From 9c2fae672ce91e924e9f207d7908ebb2f102b823 Mon Sep 17 00:00:00 2001 From: Peter Boin Date: Thu, 27 Jul 2017 16:11:56 +1000 Subject: [PATCH] added normalization func' --- scripts/pygcode-norm | 133 +++++++++++++++++++++++++++++++++-------- src/pygcode/machine.py | 24 ++++---- 2 files changed, 121 insertions(+), 36 deletions(-) diff --git a/scripts/pygcode-norm b/scripts/pygcode-norm index 94ad14c..1c967da 100755 --- a/scripts/pygcode-norm +++ b/scripts/pygcode-norm @@ -23,7 +23,7 @@ for pygcode_lib_type in ('installed_lib', 'relative_lib'): from pygcode.transform import linearize_arc, simplify_canned_cycle from pygcode.transform import ArcLinearizeInside, ArcLinearizeOutside, ArcLinearizeMid from pygcode.gcodes import _subclasses - from pygcode.utils import omit_redundant_modes + from pygcode import utils except ImportError: import sys, os, inspect @@ -63,7 +63,7 @@ def arc_lin_method_type(value): return value_dict -def canned_codes_type(value): +def word_list_type(value): """ :return: [Word('G73'), Word('G89'), ... ] """ @@ -88,9 +88,15 @@ parser.add_argument( ) parser.add_argument( - '--precision', '-p', dest='precision', type=float, default=DEFAULT_PRECISION, - help="maximum positional error when generating gcodes (eg: arcs to lines) " - "(default: %g)" % DEFAULT_PRECISION, + '--singles', '-s', dest='singles', + action='store_const', const=True, default=False, + help="only output one command per gcode line", +) +parser.add_argument( + '--full', '-f', dest='full', + action='store_const', const=True, default=False, + help="output full commands, any modal parameters will be acompanied with " + "the fully qualified gcode command", ) # Machine @@ -104,7 +110,7 @@ group = parser.add_argument_group( "Arc Linearizing", "Converting arcs (G2/G3 codes) into linear interpolations (G1 codes) to " "aproximate the original arc. Indistinguishable from an original arc when " - "--precision is set low enough." + "--arc_precision is set low enough." ) group.add_argument( '--arc_linearize', '-al', dest='arc_linearize', @@ -119,6 +125,18 @@ group.add_argument( "(default: '%s')" % DEFAULT_ARC_LIN_METHOD, metavar='{i,o,m}[,{i,o,m}]', ) +group.add_argument( + '--arc_precision', '-alp', dest='arc_precision', type=float, default=DEFAULT_PRECISION, + help="maximum positional error when creating linear interpolation codes " + "(default: %g)" % DEFAULT_PRECISION, +) + +#parser.add_argument( +# '--arc_alignment', '-aa', dest='arc_alignment', type=str, choices=('XYZ','IJK','R'), +# default=None, +# help="enforce precision on arcs, if XYZ the destination is altered to match the radius" +# "if IJK or R then the arc'c centre point is moved to assure precision", +#) # Canned Cycles group = parser.add_argument_group( @@ -133,16 +151,37 @@ group.add_argument( ) group.add_argument( '--canned_codes', '-cc', dest='canned_codes', - type=canned_codes_type, default=DEFAULT_CANNED_CODES, + type=word_list_type, default=DEFAULT_CANNED_CODES, help="List of canned gcodes to expand, (default is '%s')" % DEFAULT_CANNED_CODES, ) -#parser.add_argument( -# '--arc_alignment', '-aa', dest='arc_alignment', type=str, choices=('XYZ','IJK','R'), -# default=None, -# help="enforce precision on arcs, if XYZ the destination is altered to match the radius" -# "if IJK or R then the arc'c centre point is moved to assure precision", -#) +# Removing non-functional content +group = parser.add_argument_group( + "Removing Content", + "options for the removal of content" +) +group.add_argument( + '--rm_comments', '-rc', dest='rm_comments', + action='store_const', const=True, default=False, + help="remove all comments (non-functional)", +) +group.add_argument( + '--rm_blanks', '-rb', dest='rm_blanks', + action='store_const', const=True, default=False, + help="remove all empty lines (non-functional)", +) +group.add_argument( + '--rm_whitespace', '-rws', dest='rm_whitespace', + action='store_const', const=True, default=False, + help="remove all whitespace from gcode blocks (non-functional)", +) +group.add_argument( + '--rm_gcodes', '-rmg', dest='rm_gcodes', + type=word_list_type, default=[], + help="remove gcode (and it's parameters) with words in the given list " + "(eg: M6,G43) (note: only works for modal params with --full)", +) + # --- Parse Arguments args = parser.parse_args() @@ -158,6 +197,46 @@ class MyMachine(Machine): machine = MyMachine() # =================== Utility Functions =================== +omit_redundant_modes = utils.omit_redundant_modes +if args.full: + omit_redundant_modes = lambda gcode_iter: gcode_iter # bypass + +def write(gcodes, modal_params=tuple(), comment=None): + """ + Write to output, while enforcing the flags: + args.singles + args.rm_comments + args.rm_blanks + args.rm_whitespace + :param obj: Line, Block, GCode or Comment instance + """ + assert not(args.full and modal_params), "with full specified, this should never be called with modal_params" + if args.singles and len(gcodes) > 1: + for g in sorted(gcodes): + write([g], comment=comment) + else: + # remove comments + if args.rm_comments: + comment = None + # remove particular gcodes + if args.rm_gcodes: + gcodes = [g for g in gcodes if g.word not in args.rm_gcodes] + + # Convert to string & write to file (or stdout) + block_str = ' '.join(str(x) for x in (list(gcodes) + list(modal_params))) + if args.rm_whitespace: + block_str = re.sub(r'\s', '', block_str) + + line_list = [] + if block_str: + line_list.append(block_str) + if comment: + line_list.append(str(comment)) + line_str = ' '.join(line_list) + if line_str or not args.rm_blanks: + print(line_str) + + def gcodes2str(gcodes): return ' '.join("%s" % g for g in gcodes) @@ -171,20 +250,21 @@ def split_and_process(gcode_list, gcode_class, comment): :param comment: Comment instance, or None """ (befores, (g,), afters) = split_gcodes(gcode_list, gcode_class) - # print & process those before gcode_class instance + # write & process those before gcode_class instance if befores: - print(gcodes2str(befores)) + write(befores) machine.process_gcodes(*befores) # yield, then process gcode_class instance yield g machine.process_gcodes(g) - # print & process those after gcode_class instance + # write & process those after gcode_class instance if afters: - print(gcodes2str(afters)) + write(afters) machine.process_gcodes(*afters) - # print comment (if given) + # write comment (if given) if comment: - print(str(line.comment)) + write([], comment=line.comment) + # =================== Process File =================== @@ -198,7 +278,7 @@ for line_str in args.infile.readlines(): if args.arc_linearize and any(isinstance(g, GCodeArcMove) for g in effective_gcodes): with split_and_process(effective_gcodes, GCodeArcMove, line.comment) as arc: - print(Comment("linearized arc: %r" % arc)) + write([], comment=Comment("linearized arc: %r" % arc)) linearize_params = { 'arc_gcode': arc, 'start_pos': machine.pos, @@ -206,15 +286,15 @@ for line_str in args.infile.readlines(): 'method_class': args.arc_lin_method[arc.word], 'dist_mode': machine.mode.distance, 'arc_dist_mode': machine.mode.arc_ijk_distance, - 'max_error': args.precision, + 'max_error': args.arc_precision, 'decimal_places': 3, } for linear_gcode in omit_redundant_modes(linearize_arc(**linearize_params)): - print(linear_gcode) + write([linear_gcode]) elif args.canned_expand and any((g.word in args.canned_codes) for g in effective_gcodes): with split_and_process(effective_gcodes, GCodeCannedCycle, line.comment) as canned: - print(Comment("expanded: %r" % canned)) + write([], comment=Comment("expanded: %r" % canned)) simplify_canned_params = { 'canned_gcode': canned, 'start_pos': machine.pos, @@ -223,8 +303,11 @@ for line_str in args.infile.readlines(): 'axes': machine.axes, } for simplified_gcode in omit_redundant_modes(simplify_canned_cycle(**simplify_canned_params)): - print(simplified_gcode) + write([simplified_gcode]) else: - print(str(line)) + if args.full: + write(effective_gcodes, comment=line.comment) + else: + write(line.block.gcodes, modal_params=line.block.modal_params, comment=line.comment) machine.process_block(line.block) diff --git a/src/pygcode/machine.py b/src/pygcode/machine.py index 7cf412d..42c2f15 100644 --- a/src/pygcode/machine.py +++ b/src/pygcode/machine.py @@ -87,7 +87,7 @@ class Position(object): return self._value == other._value else: x = copy(other) - x.set_unit(self._unit) + x.unit = self._unit return self._value == x._value def __ne__(self, other): @@ -125,13 +125,17 @@ class Position(object): __truediv__ = __div__ # Python 3 division # Conversion - def set_unit(self, unit): - if unit == self._unit: - return - factor = UNIT_MAP[self._unit]['conversion_factor'][unit] - for k in [k for (k, v) in self._value.items() if v is not None]: - self._value[k] *= factor - self._unit = unit + @property + def unit(self): + return self._unit + + @unit.setter + def unit(self, value): + if value != self._unit: + factor = UNIT_MAP[self._unit]['conversion_factor'][value] + for k in [k for (k, v) in self._value.items() if v is not None]: + self._value[k] *= factor + self._unit = value @property def words(self): @@ -202,8 +206,6 @@ class State(object): # Coordinate System selection: # - G54-G59: select coordinate system (offsets from machine coordinates set by G10 L2) - # TODO: Move this class into MachineState - @property def coord_sys(self): """Current equivalent coordinate system, including all """ @@ -328,7 +330,7 @@ class Machine(object): units_mode = getattr(self.mode, 'units', None) self.Position = type('Position', (Position,), { 'default_axes': self.axes, - 'default_unit': units_mode.unit_id if units_mode else UNIT_METRIC, + 'default_unit': units_mode.unit_id if units_mode else Position.default_unit, }) # Absolute machine position