mirror of
https://git.mirrors.martin98.com/https://github.com/petaflot/pygcode
synced 2025-04-22 22:00:30 +08:00
first working crop script
This commit is contained in:
parent
a82becb61d
commit
53de97d9b0
@ -14,7 +14,9 @@ for pygcode_lib_type in ('installed_lib', 'relative_lib'):
|
||||
try:
|
||||
# pygcode
|
||||
from pygcode import Machine, Mode
|
||||
from pygcode import Line
|
||||
from pygcode import Line, Comment
|
||||
from pygcode import GCodePlaneSelect, GCodeSelectXYPlane
|
||||
from pygcode import GCodeRapidMove
|
||||
|
||||
except ImportError:
|
||||
import sys, os, inspect
|
||||
@ -131,9 +133,11 @@ def range_type(value):
|
||||
|
||||
|
||||
# --- Create Parser
|
||||
parser = argparse.ArgumentParser(description='Crop a gcode file down to the')
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Remove gcode before and after given 'from' and 'to' events"
|
||||
)
|
||||
parser.add_argument(
|
||||
'infile', type=argparse.FileType('r'), nargs=1,
|
||||
'infile', type=argparse.FileType('r'),
|
||||
help="gcode file to normalize",
|
||||
)
|
||||
parser.add_argument(
|
||||
@ -159,35 +163,52 @@ post_crop = False
|
||||
|
||||
(is_first, is_last) = args.range
|
||||
|
||||
|
||||
for (i, line_str) in enumerate(args.infile.readlines()):
|
||||
line = Line(line_str)
|
||||
|
||||
# TODO: remember machine's maximum values for each axis
|
||||
# TODO: based on machine.abs_pos
|
||||
|
||||
# remember machine's (relevant) state before processing
|
||||
# TODO: create machine.__copy__ to copy position & state
|
||||
# remember machine's state before processing the current line
|
||||
old_machine = copy(machine)
|
||||
machine.process_block(line.block)
|
||||
|
||||
if pre_crop:
|
||||
if is_first(i + 1, old_machine.pos):
|
||||
if is_first(i + 1, machine.pos):
|
||||
# First line inside cropping range
|
||||
pre_crop = False
|
||||
|
||||
# TODO: print mode
|
||||
print(old_machine.mode)
|
||||
# TODO: position machine before first cropped line
|
||||
# TODO: rapid move to Z (maximum Z)
|
||||
# TODO: rapid move to X,Y
|
||||
# TODO: rapid move to Z (machine.pos.Z)
|
||||
# Set machine's accumulated mode (from everything that's been cut)
|
||||
mode_str = str(old_machine.mode)
|
||||
if mode_str:
|
||||
print(Comment("machine mode before cropping"))
|
||||
print(mode_str)
|
||||
|
||||
# Getting machine's current (modal) selected plane
|
||||
plane = old_machine.mode.plane_selection
|
||||
if not isinstance(plane, GCodePlaneSelect):
|
||||
plane = GCodeSelectXYPlane() # default to XY plane
|
||||
|
||||
# --- position machine before first cropped line
|
||||
print(Comment("traverse into position, up, over, and down"))
|
||||
# rapid move to Z (maximum Z the machine has experienced thus far)
|
||||
print(GCodeRapidMove(**{
|
||||
plane.normal_axis: getattr(old_machine.abs_range_max, plane.normal_axis),
|
||||
}))
|
||||
# rapid move to X,Y
|
||||
print(GCodeRapidMove(**dict(
|
||||
(k, v) for (k, v) in old_machine.pos.values.items()
|
||||
if k in plane.plane_axes
|
||||
)))
|
||||
# rapid move to Z (machine.pos.Z)
|
||||
print(GCodeRapidMove(**{
|
||||
plane.normal_axis: getattr(old_machine.pos, plane.normal_axis),
|
||||
}))
|
||||
print('')
|
||||
|
||||
if (pre_crop, post_crop) == (False, False):
|
||||
|
||||
if is_last(i + 1, machine.pos):
|
||||
# First line **outside** the area being cropped
|
||||
# (ie: this line won't be output)
|
||||
post_crop = True # although, irrelevant because...
|
||||
break
|
||||
else:
|
||||
# inside cropping area
|
||||
print(line)
|
||||
|
||||
if is_last(i + 1, old_machine.pos):
|
||||
# Last line in cropping range
|
||||
post_crop = True
|
||||
|
@ -824,9 +824,11 @@ class GCodePlaneSelect(GCode):
|
||||
# vectorYZ = GCodeSelectYZPlane.quat * (GCodeSelectZXPlane.quat.conjugate() * vectorZX)
|
||||
quat = None # Quaternion
|
||||
|
||||
# -- Plane Normal
|
||||
# -- Plane Axis Information
|
||||
# Vector normal to plane (such that XYZ axes follow the right-hand rule)
|
||||
normal_axis = None # Letter of normal axis (upper case)
|
||||
# Axes of plane
|
||||
plane_axes = set()
|
||||
normal = None # Vector3
|
||||
|
||||
|
||||
@ -835,6 +837,7 @@ class GCodeSelectXYPlane(GCodePlaneSelect):
|
||||
word_key = Word('G', 17)
|
||||
quat = Quaternion() # no effect
|
||||
normal_axis = 'Z'
|
||||
plane_axes = set('XY')
|
||||
normal = Vector3(0., 0., 1.)
|
||||
|
||||
|
||||
@ -846,6 +849,7 @@ class GCodeSelectZXPlane(GCodePlaneSelect):
|
||||
Vector3(0., 0., 1.), Vector3(1., 0., 0.)
|
||||
)
|
||||
normal_axis = 'Y'
|
||||
plane_axes = set('ZX')
|
||||
normal = Vector3(0., 1., 0.)
|
||||
|
||||
|
||||
@ -857,6 +861,7 @@ class GCodeSelectYZPlane(GCodePlaneSelect):
|
||||
Vector3(0., 1., 0.), Vector3(0., 0., 1.)
|
||||
)
|
||||
normal_axis = 'X'
|
||||
plane_axes = set('YZ')
|
||||
normal = Vector3(1., 0., 0.)
|
||||
|
||||
|
||||
|
@ -52,6 +52,9 @@ class Position(object):
|
||||
self._value = defaultdict(lambda: 0.0, dict((k, 0.0) for k in self.axes))
|
||||
self._value.update(kwargs)
|
||||
|
||||
def __copy__(self):
|
||||
return self.__class__(axes=copy(self.axes), unit=self._unit, **self.values)
|
||||
|
||||
def update(self, **coords):
|
||||
for (k, v) in coords.items():
|
||||
setattr(self, k, v)
|
||||
@ -74,10 +77,6 @@ class Position(object):
|
||||
else:
|
||||
self.__dict__[key] = value
|
||||
|
||||
# Copy
|
||||
def __copy__(self):
|
||||
return self.__class__(axes=copy(self.axes), unit=self._unit, **self.values)
|
||||
|
||||
# Equality
|
||||
def __eq__(self, other):
|
||||
if self.axes ^ other.axes:
|
||||
@ -137,6 +136,36 @@ class Position(object):
|
||||
self._value[k] *= factor
|
||||
self._unit = value
|
||||
|
||||
# Min/Max
|
||||
@classmethod
|
||||
def _cmp(cls, p1, p2, key):
|
||||
"""
|
||||
Returns a position of the combined min/max values for each axis
|
||||
(eg: key=min for)
|
||||
note: the result is not necessarily equal to either p1 or p2.
|
||||
:param p1: Position instance
|
||||
:param p2: Position instance
|
||||
:return: Position instance with the highest/lowest value per axis
|
||||
"""
|
||||
if p2.unit != p1.unit:
|
||||
p2 = copy(p2)
|
||||
p2.unit = p1.unit
|
||||
return cls(
|
||||
unit=p1.unit,
|
||||
**dict(
|
||||
(k, key(getattr(p1, k), getattr(p2, k))) for k in p1.values
|
||||
)
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def min(cls, a, b):
|
||||
return cls._cmp(a, b, key=min)
|
||||
|
||||
@classmethod
|
||||
def max(cls, a, b):
|
||||
return cls._cmp(a, b, key=max)
|
||||
|
||||
# Words & Values
|
||||
@property
|
||||
def words(self):
|
||||
return sorted(Word(k, self._value[k]) for k in self.axes)
|
||||
@ -149,6 +178,7 @@ class Position(object):
|
||||
def vector(self):
|
||||
return Vector3(self._value['X'], self._value['Y'], self._value['Z'])
|
||||
|
||||
# String representation(s)
|
||||
def __repr__(self):
|
||||
return "<{class_name}: {coordinates}>".format(
|
||||
class_name=self.__class__.__name__,
|
||||
@ -157,12 +187,13 @@ class Position(object):
|
||||
|
||||
|
||||
class CoordinateSystem(object):
|
||||
def __init__(self, axes):
|
||||
self.offset = Position(axes)
|
||||
def __init__(self, axes=None):
|
||||
self.offset = Position(axes=axes)
|
||||
|
||||
def __add__(self, other):
|
||||
if isinstance(other, CoordinateSystem):
|
||||
pass
|
||||
def __copy__(self):
|
||||
obj = self.__class__()
|
||||
obj.offset = copy(self.offset)
|
||||
return obj
|
||||
|
||||
def __repr__(self):
|
||||
return "<{class_name}: offset={offset}>".format(
|
||||
@ -178,6 +209,7 @@ class State(object):
|
||||
# AFAIK: this is everything needed to remember a machine's state that isn't
|
||||
# handled by modal gcodes.
|
||||
def __init__(self, axes=None):
|
||||
self._axes = axes
|
||||
# Coordinate Systems
|
||||
self.coord_systems = {}
|
||||
for i in range(1, 10): # G54-G59.3
|
||||
@ -206,6 +238,12 @@ class State(object):
|
||||
# Coordinate System selection:
|
||||
# - G54-G59: select coordinate system (offsets from machine coordinates set by G10 L2)
|
||||
|
||||
def __copy__(self):
|
||||
obj = self.__class__(axes=self._axes)
|
||||
obj.coord_systems = [copy(cs) for cs in self.coord_systems]
|
||||
obj.offset = copy(self.offset)
|
||||
return obj
|
||||
|
||||
@property
|
||||
def coord_sys(self):
|
||||
"""Current equivalent coordinate system, including all """
|
||||
@ -249,12 +287,18 @@ class Mode(object):
|
||||
|
||||
# Mode is defined by gcodes set by processed blocks:
|
||||
# see modal_group in gcode.py module for details
|
||||
def __init__(self):
|
||||
def __init__(self, set_default=True):
|
||||
self.modal_groups = defaultdict(lambda: None)
|
||||
|
||||
# Initialize
|
||||
if set_default:
|
||||
self.set_mode(*Line(self.default_mode).block.gcodes)
|
||||
|
||||
def __copy__(self):
|
||||
obj = self.__class__(set_default=False)
|
||||
obj.modal_groups = deepcopy(self.modal_groups)
|
||||
return obj
|
||||
|
||||
def set_mode(self, *gcode_list):
|
||||
"""
|
||||
Set machine mode from given gcodes (will not be processed)
|
||||
@ -335,6 +379,18 @@ class Machine(object):
|
||||
|
||||
# Absolute machine position
|
||||
self.abs_pos = self.Position()
|
||||
# Machine's motion range (min/max corners of a bounding box)
|
||||
self.abs_range_min = copy(self.abs_pos)
|
||||
self.abs_range_max = copy(self.abs_pos)
|
||||
|
||||
def __copy__(self):
|
||||
obj = self.__class__()
|
||||
obj.mode = copy(self.mode)
|
||||
obj.state = copy(self.state)
|
||||
obj.abs_pos = copy(self.abs_pos)
|
||||
obj.abs_range_min = copy(self.abs_range_min)
|
||||
obj.abs_range_max = copy(self.abs_range_max)
|
||||
return obj
|
||||
|
||||
def set_mode(self, *gcode_list):
|
||||
self.mode.set_mode(*gcode_list) # passthrough
|
||||
@ -425,6 +481,11 @@ class Machine(object):
|
||||
coord_sys_offset = getattr(self.state.coord_sys, 'offset', Position(axes=self.axes))
|
||||
temp_offset = self.state.offset
|
||||
self.abs_pos = (value + temp_offset) + coord_sys_offset
|
||||
self._update_abs_range(self.abs_pos)
|
||||
|
||||
def _update_abs_range(self, pos):
|
||||
self.abs_range_min = Position.min(pos, self.abs_range_min)
|
||||
self.abs_range_max = Position.max(pos, self.abs_range_max)
|
||||
|
||||
# =================== Machine Actions ===================
|
||||
def move_to(self, rapid=False, **coords):
|
||||
|
Loading…
x
Reference in New Issue
Block a user