diff --git a/camlib.py b/camlib.py index f576ed98..5a8487a3 100644 --- a/camlib.py +++ b/camlib.py @@ -136,6 +136,27 @@ class Geometry(object): log.error("Failed to run union on polygons.") raise + def add_polyline(self, points): + """ + Adds a polyline to the object (by union) + + :param points: The vertices of the polyline. + :return: None + """ + if self.solid_geometry is None: + self.solid_geometry = [] + + if type(self.solid_geometry) is list: + self.solid_geometry.append(LineString(points)) + return + + try: + self.solid_geometry = self.solid_geometry.union(LineString(points)) + except: + #print "Failed to run union on polygons." + log.error("Failed to run union on polylines.") + raise + def subtract_polygon(self, points): """ Subtract polygon from the given object. This only operates on the paths in the original geometry, i.e. it converts polygons into paths. diff --git a/tclCommands/TclCommand.py b/tclCommands/TclCommand.py index ccc29eb2..eb8e222a 100644 --- a/tclCommands/TclCommand.py +++ b/tclCommands/TclCommand.py @@ -1,31 +1,33 @@ import sys, inspect, pkgutil import re import FlatCAMApp - +import collections class TclCommand(object): app=None # array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon) - aliases = None + aliases = [] - # dictionary of types from Tcl command: args = {'name': str}, this is for value without optionname - arg_names = {'name': str} + # dictionary of types from Tcl command, needs to be ordered + arg_names = collections.OrderedDict([ + ('name', str) + ]) - # dictionary of types from Tcl command: types = {'outname': str} , this is for options like -optionname value - option_types = {} + # dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value + option_types = collections.OrderedDict([]) # array of mandatory options for current Tcl command: required = {'name','outname'} required = ['name'] - # structured help for current command + # structured help for current command, args needs to be ordered help = { 'main': "undefined help.", - 'args': { - 'argumentname': 'undefined help.', - 'optionname': 'undefined help.' - }, + 'args': collections.OrderedDict([ + ('argumentname', 'undefined help.'), + ('optionname', 'undefined help.') + ]), 'examples' : [] } @@ -41,7 +43,7 @@ class TclCommand(object): def get_decorated_command(alias): command_string = [] - for key, value in reversed(self.help['args'].items()): + for key, value in self.help['args'].items(): command_string.append(get_decorated_argument(key, value, True)) return "> " + alias + " " + " ".join(command_string) @@ -49,11 +51,18 @@ class TclCommand(object): option_symbol = '' if key in self.arg_names: type=self.arg_names[key] - in_command_name = "<" + str(type.__name__) + ">" - else: + type_name=str(type.__name__) + in_command_name = "<" + type_name + ">" + elif key in self.option_types: option_symbol = '-' type=self.option_types[key] - in_command_name = option_symbol + key + " <" + str(type.__name__) + ">" + type_name=str(type.__name__) + in_command_name = option_symbol + key + " <" + type_name + ">" + else: + option_symbol = '' + type_name='?' + in_command_name = option_symbol + key + " <" + type_name + ">" + if in_command: if key in self.required: return in_command_name @@ -61,19 +70,18 @@ class TclCommand(object): return '[' + in_command_name + "]" else: if key in self.required: - return "\t" + option_symbol + key + " <" + str(type.__name__) + ">: " + value + return "\t" + option_symbol + key + " <" + type_name + ">: " + value else: - return "\t[" + option_symbol + key + " <" + str(type.__name__) + ">: " + value+"]" + return "\t[" + option_symbol + key + " <" + type_name + ">: " + value+"]" def get_decorated_example(example): - example_string = '' - return "todo" + example_string + return "> "+example help_string=[self.help['main']] for alias in self.aliases: help_string.append(get_decorated_command(alias)) - for key, value in reversed(self.help['args'].items()): + for key, value in self.help['args'].items(): help_string.append(get_decorated_argument(key, value)) for example in self.help['examples']: @@ -123,10 +131,10 @@ class TclCommand(object): # check arguments idx=0 - arg_names_reversed=self.arg_names.items() + arg_names_items=self.arg_names.items() for argument in arguments: if len(self.arg_names) > idx: - key, type = arg_names_reversed[len(self.arg_names)-idx-1] + key, type = arg_names_items[idx] try: named_args[key] = type(argument) except Exception, e: diff --git a/tclCommands/TclCommandAddPolygon.py b/tclCommands/TclCommandAddPolygon.py new file mode 100644 index 00000000..b5effcd8 --- /dev/null +++ b/tclCommands/TclCommandAddPolygon.py @@ -0,0 +1,65 @@ +from ObjectCollection import * +import TclCommand + + +class TclCommandAddPolygon(TclCommand.TclCommand): + """ + Tcl shell command to create a polygon in the given Geometry object + """ + + # array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon) + aliases = ['add_polygon','add_poly'] + + # dictionary of types from Tcl command, needs to be ordered + arg_names = collections.OrderedDict([ + ('name', str) + ]) + + # dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value + option_types = collections.OrderedDict([]) + + # array of mandatory options for current Tcl command: required = {'name','outname'} + required = ['name'] + + # structured help for current command, args needs to be ordered + help = { + 'main': "Creates a polygon in the given Geometry object.", + 'args': collections.OrderedDict([ + ('name', 'Name of the Geometry object to which to append the polygon.'), + ('xi, yi', 'Coordinates of points in the polygon.') + ]), + 'examples':[ + 'add_polygon [x3 y3 [...]]' + ] + } + + def execute(self, args, unnamed_args): + """ + execute current TCL shell command + + :param args: array of known named arguments and options + :param unnamed_args: array of other values which were passed into command + without -somename and we do not have them in known arg_names + :return: None or exception + """ + + name = args['name'] + + try: + obj = self.app.collection.get_by_name(name) + except: + self.app.raiseTclError("Could not retrieve object: %s" % name) + + if obj is None: + self.app.raiseTclError("Object not found: %s" % name) + + if not isinstance(obj, Geometry): + self.app.raiseTclError('Expected Geometry, got %s %s.' % (name, type(obj))) + + if len(unnamed_args) % 2 != 0: + self.app.raiseTclError("Incomplete coordinates.") + + points = [[float(unnamed_args[2*i]), float(unnamed_args[2*i+1])] for i in range(len(unnamed_args)/2)] + + obj.add_polygon(points) + obj.plot() \ No newline at end of file diff --git a/tclCommands/TclCommandAddPolyline.py b/tclCommands/TclCommandAddPolyline.py new file mode 100644 index 00000000..157f6e1f --- /dev/null +++ b/tclCommands/TclCommandAddPolyline.py @@ -0,0 +1,65 @@ +from ObjectCollection import * +import TclCommand + + +class TclCommandAddPolyline(TclCommand.TclCommand): + """ + Tcl shell command to create a polyline in the given Geometry object + """ + + # array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon) + aliases = ['add_polyline'] + + # dictionary of types from Tcl command, needs to be ordered + arg_names = collections.OrderedDict([ + ('name', str) + ]) + + # dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value + option_types = collections.OrderedDict([]) + + # array of mandatory options for current Tcl command: required = {'name','outname'} + required = ['name'] + + # structured help for current command, args needs to be ordered + help = { + 'main': "Creates a polyline in the given Geometry object.", + 'args': collections.OrderedDict([ + ('name', 'Name of the Geometry object to which to append the polyline.'), + ('xi, yi', 'Coordinates of points in the polyline.') + ]), + 'examples':[ + 'add_polyline [x3 y3 [...]]' + ] + } + + def execute(self, args, unnamed_args): + """ + execute current TCL shell command + + :param args: array of known named arguments and options + :param unnamed_args: array of other values which were passed into command + without -somename and we do not have them in known arg_names + :return: None or exception + """ + + name = args['name'] + + try: + obj = self.app.collection.get_by_name(name) + except: + self.app.raiseTclError("Could not retrieve object: %s" % name) + + if obj is None: + self.app.raiseTclError("Object not found: %s" % name) + + if not isinstance(obj, Geometry): + self.app.raiseTclError('Expected Geometry, got %s %s.' % (name, type(obj))) + + if len(unnamed_args) % 2 != 0: + self.app.raiseTclError("Incomplete coordinates.") + + points = [[float(unnamed_args[2*i]), float(unnamed_args[2*i+1])] for i in range(len(unnamed_args)/2)] + + obj.add_polyline(points) + obj.plot() \ No newline at end of file diff --git a/tclCommands/TclCommandExteriors.py b/tclCommands/TclCommandExteriors.py index aad0fa2a..d445cd5c 100644 --- a/tclCommands/TclCommandExteriors.py +++ b/tclCommands/TclCommandExteriors.py @@ -10,22 +10,26 @@ class TclCommandExteriors(TclCommand.TclCommand): # array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon) aliases = ['exteriors','ext'] - # dictionary of types from Tcl command: args = {'name': str}, this is for value without optionname - arg_names = {'name': str,'name2': str} + # dictionary of types from Tcl command, needs to be ordered + arg_names = collections.OrderedDict([ + ('name', str) + ]) - # dictionary of types from Tcl command: types = {'outname': str} , this is for options like -optionname value - option_types = {'outname': str} + # dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value + option_types = collections.OrderedDict([ + ('outname', str) + ]) # array of mandatory options for current Tcl command: required = {'name','outname'} required = ['name'] - # structured help for current command + # structured help for current command, args needs to be ordered help = { 'main': "Get exteriors of polygons.", - 'args': { - 'name': 'Name of the source Geometry object.', - 'outname': 'Name of the resulting Geometry object.' - }, + 'args': collections.OrderedDict([ + ('name', 'Name of the source Geometry object.'), + ('outname', 'Name of the resulting Geometry object.') + ]), 'examples':[] } diff --git a/tclCommands/TclCommandInteriors.py b/tclCommands/TclCommandInteriors.py index f1c65590..ef67ce9c 100644 --- a/tclCommands/TclCommandInteriors.py +++ b/tclCommands/TclCommandInteriors.py @@ -9,22 +9,26 @@ class TclCommandInteriors(TclCommand.TclCommand): # array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon) aliases = ['interiors'] - # dictionary of types from Tcl command: args = {'name': str}, this is for value without optionname - arg_names = {'name': str} + # dictionary of types from Tcl command, needs to be ordered + arg_names = collections.OrderedDict([ + ('name', str) + ]) - # dictionary of types from Tcl command: types = {'outname': str} , this is for options like -optionname value - option_types = {'outname': str} + # dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value + option_types = collections.OrderedDict([ + ('outname', str) + ]) # array of mandatory options for current Tcl command: required = {'name','outname'} required = ['name'] - # structured help for current command + # structured help for current command, args needs to be ordered help = { 'main': "Get interiors of polygons.", - 'args': { - 'name': 'Name of the source Geometry object.', - 'outname': 'Name of the resulting Geometry object.' - }, + 'args': collections.OrderedDict([ + ('name', 'Name of the source Geometry object.'), + ('outname', 'Name of the resulting Geometry object.') + ]), 'examples':[] } diff --git a/tclCommands/__init__.py b/tclCommands/__init__.py index 43cb0a6b..45d0ffcf 100644 --- a/tclCommands/__init__.py +++ b/tclCommands/__init__.py @@ -5,6 +5,8 @@ import sys # allowed command modules import tclCommands.TclCommandExteriors import tclCommands.TclCommandInteriors +import tclCommands.TclCommandAddPolygon +import tclCommands.TclCommandAddPolyline __all__=[]