- fixed the Tcl Command Delete to have an argument -f that will force deletion evading the popup (if the popup is enabled). The sme command without a name now will delete all objects

- fixed the Tcl Command JoinExcellons
- fixed the Tcl Command JoinGeometry
- fixed the Tcl Command Mirror
- updated the Tcl Command Mirror to use a (X,Y) origin parameter. Works if the -box parameter is not used.
- updated the Tcl Command Offset. Now it can use only -x or -y parameter no longer is mandatory to have both. The one that is not present will be assumed 0.0
- updated the Tcl Command Panelize. The -rows and -columns parameters are no longer both required. If one is not present then it is assumed to be zero.
- updated the Tcl Command Scale. THe -origin parameter can now be a tuple of (x,y) coordinates.
- updated the Tcl Command Skew. Now it can use only -x or -y parameter no longer is mandatory to have both. The one that is not present will be assumed 0.0
- updated the help for all the Tcl Commands
This commit is contained in:
Marius Stanciu 2020-04-09 04:13:04 +03:00 committed by Marius
parent ecba1a9232
commit 42949021b1
53 changed files with 322 additions and 178 deletions

View File

@ -1033,7 +1033,7 @@ class App(QtCore.QObject):
'Toolchange_manual, Users, all, angle_x, angle_y, axis, auto, axisoffset, '
'box, center_x, center_y, columns, combine, connect, contour, default, '
'depthperpass, dia, diatol, dist, drilled_dias, drillz, dwelltime, '
'extracut_length, '
'extracut_length, f, '
'feedrate_z, grbl_11, GRBL_laser, gridoffsety, gridx, gridy, has_offset, '
'holes, hpgl, iso_type, line_xyz, margin, marlin, method, milled_dias, '
'minoffset, name, offset, opt_type, order, outname, overlap, '
@ -2305,7 +2305,8 @@ class App(QtCore.QObject):
# #####################################################################################
self.tcl_commands_list = ['add_circle', 'add_poly', 'add_polygon', 'add_polyline', 'add_rectangle',
'aligndrill', 'aligndrillgrid', 'bbox', 'bounding_box', 'clear', 'cncjob', 'cutout',
'delete', 'drillcncjob', 'export_dxf', 'edxf', 'export_excellon', 'ee', 'export_exc',
'del', 'delete', 'drillcncjob', 'export_dxf', 'edxf', 'export_excellon', 'ee',
'export_exc',
'export_gcode', 'export_gerber', 'egr', 'export_svg', 'ext', 'exteriors', 'follow',
'geo_union', 'geocutout', 'get_names', 'get_sys', 'getsys', 'help', 'import_svg',
'interiors', 'isolate', 'join_excellon', 'join_excellons', 'join_geometries',
@ -2326,7 +2327,7 @@ class App(QtCore.QObject):
'axisoffset',
'box', 'center_x', 'center_y', 'columns', 'combine', 'connect', 'contour', 'default',
'depthperpass', 'dia', 'diatol', 'dist', 'drilled_dias', 'drillz',
'dwelltime', 'extracut_length',
'dwelltime', 'extracut_length', 'f',
'feedrate_z', 'grbl_11', 'GRBL_laser', 'gridoffsety', 'gridx', 'gridy',
'has_offset', 'holes', 'hpgl', 'iso_type', 'line_xyz', 'margin', 'marlin', 'method',
'milled_dias', 'minoffset', 'name', 'offset', 'opt_type', 'order',
@ -7201,10 +7202,11 @@ class App(QtCore.QObject):
# Hovering over Selected tab, if the selected tab is a Geometry it will delete tools in tool table. But even if
# there is a Selected tab in focus with a Geometry inside, if you hover over canvas it will delete an object.
# Complicated, I know :)
def on_delete(self):
def on_delete(self, force_deletion=False):
"""
Delete the currently selected FlatCAMObjs.
:param force_deletion: used by Tcl command
:return: None
"""
self.report_usage("on_delete()")
@ -7216,7 +7218,7 @@ class App(QtCore.QObject):
# a geometry object before we update it.
if self.geo_editor.editor_active is False and self.exc_editor.editor_active is False \
and self.grb_editor.editor_active is False:
if self.defaults["global_delete_confirmation"] is True:
if self.defaults["global_delete_confirmation"] is True and force_deletion is False:
msgbox = QtWidgets.QMessageBox()
msgbox.setWindowTitle(_("Delete objects"))
msgbox.setWindowIcon(QtGui.QIcon(self.resource_location + '/deleteshape32.png'))
@ -7230,7 +7232,10 @@ class App(QtCore.QObject):
msgbox.exec_()
response = msgbox.clickedButton()
if response == bt_ok or self.defaults["global_delete_confirmation"] is False:
if self.defaults["global_delete_confirmation"] is False or force_deletion is True:
response = bt_ok
if response == bt_ok:
if self.collection.get_active():
self.log.debug("App.on_delete()")
@ -9539,6 +9544,7 @@ class App(QtCore.QObject):
File menu callback for opening a Gerber.
:param signal: required because clicking the entry will generate a checked signal which needs a container
:param name:
:return: None
"""
@ -9585,6 +9591,7 @@ class App(QtCore.QObject):
File menu callback for opening an Excellon file.
:param signal: required because clicking the entry will generate a checked signal which needs a container
:param name:
:return: None
"""
@ -9619,10 +9626,12 @@ class App(QtCore.QObject):
def on_fileopengcode(self, signal: bool = None, name=None):
"""
File menu call back for opening gcode.
:param signal: required because clicking the entry will generate a checked signal which needs a container
:return: None
:param name:
:return:
"""
self.report_usage("on_fileopengcode")

View File

@ -9,6 +9,19 @@ CAD program, and create G-Code for Isolation routing.
=================================================
9.4.2020
- fixed the Tcl Command Delete to have an argument -f that will force deletion evading the popup (if the popup is enabled). The sme command without a name now will delete all objects
- fixed the Tcl Command JoinExcellons
- fixed the Tcl Command JoinGeometry
- fixed the Tcl Command Mirror
- updated the Tcl Command Mirror to use a (X,Y) origin parameter. Works if the -box parameter is not used.
- updated the Tcl Command Offset. Now it can use only -x or -y parameter no longer is mandatory to have both. The one that is not present will be assumed 0.0
- updated the Tcl Command Panelize. The -rows and -columns parameters are no longer both required. If one is not present then it is assumed to be zero.
- updated the Tcl Command Scale. THe -origin parameter can now be a tuple of (x,y) coordinates.
- updated the Tcl Command Skew. Now it can use only -x or -y parameter no longer is mandatory to have both. The one that is not present will be assumed 0.0
- updated the help for all the Tcl Commands
6.04.2020
- added key shortcuts (arrow up/down) that will select the objects in the Project tab if the focus is in that tab

View File

@ -38,7 +38,7 @@ class TclCommandAddCircle(TclCommand):
('center_y', 'Y coordinates of the center of the circle.'),
('radius', 'Radius of the circle.')
]),
'examples': []
'examples': ['add_circle geo_name 1.0 2.0 3']
}
def execute(self, args, unnamed_args):

View File

@ -37,7 +37,7 @@ class TclCommandAddRectangle(TclCommandSignaled):
('x0 y0', 'Bottom left corner coordinates.'),
('x1 y1', 'Top right corner coordinates.')
]),
'examples': []
'examples': ["add_rectangle geo_name 0 0 10 10"]
}
def execute(self, args, unnamed_args):

View File

@ -41,7 +41,7 @@ class TclCommandAlignDrill(TclCommandSignaled):
# structured help for current command, args needs to be ordered
help = {
'main': "Create excellon with drills for aligment.",
'main': "Create an Excellon object with drills for alignment.",
'args': collections.OrderedDict([
('name', 'Name of the object (Gerber or Excellon) to mirror.'),
('dia', 'Tool diameter'),

View File

@ -39,7 +39,7 @@ class TclCommandAlignDrillGrid(TclCommandSignaled):
# structured help for current command, args needs to be ordered
help = {
'main': "Create excellon with drills for aligment grid.",
'main': "Create an Excellon object with drills for alignment arranged in a grid.",
'args': collections.OrderedDict([
('outname', 'Name of the object to create.'),
('dia', 'Tool diameter.'),

View File

@ -38,7 +38,7 @@ class TclCommandBbox(TclCommand):
# structured help for current command, args needs to be ordered
help = {
'main': "Creates a Geometry object that surrounds the object.",
'main': "Creates a rectangular Geometry object that surrounds the object.",
'args': collections.OrderedDict([
('name', 'Object name for which to create bounding box. String'),
('outname', 'Name of the resulting Geometry object. String.'),

View File

@ -12,6 +12,7 @@ if '_' not in builtins.__dict__:
log = logging.getLogger('base')
class TclCommandBounds(TclCommand):
"""
Tcl shell command to return the bounds values for a supplied list of objects (identified by their names).

View File

@ -38,7 +38,7 @@ class TclCommandClearShell(TclCommand):
'main': "Clear the text in the Tcl Shell browser.",
'args': collections.OrderedDict([
]),
'examples': []
'examples': ['clear']
}
def execute(self, args, unnamed_args):

View File

@ -48,7 +48,7 @@ class TclCommandCutout(TclCommand):
('gapsize', 'Size of gap. Default = 0.1'),
('gaps', "Type of gaps. Can be: 'tb' = top-bottom, 'lr' = left-right and '4' = one each side. Default = 4"),
]),
'examples': []
'examples': ['cutout new_geo -dia 1.2 -margin 0.1 -gapsize 1 -gaps "tb" ']
}
def execute(self, args, unnamed_args):

View File

@ -12,7 +12,7 @@ class TclCommandDelete(TclCommand):
"""
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['delete']
aliases = ['delete', 'del']
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
@ -21,19 +21,23 @@ class TclCommandDelete(TclCommand):
# Dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
option_types = collections.OrderedDict([
('f', bool)
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
required = ['name']
required = []
# structured help for current command, args needs to be ordered
help = {
'main': 'Deletes the given object.',
'main': 'Deletes the given object. If no name is given will delete all objects.',
'args': collections.OrderedDict([
('name', 'Name of the Object.'),
('f', 'Use this parameter to force deletion.')
]),
'examples': []
'examples': ['del new_geo -f True\n'
'delete new_geo -f 1\n'
'del new_geo -f\n'
'del new_geo']
}
def execute(self, args, unnamed_args):
@ -43,13 +47,35 @@ class TclCommandDelete(TclCommand):
:param unnamed_args:
:return:
"""
obj_name = args['name']
obj_name = None
try:
# deselect all to avoid delete selected object when run delete from shell
self.app.collection.set_all_inactive()
self.app.collection.set_active(str(obj_name))
self.app.on_delete() # Todo: This is an event handler for the GUI... bad?
except Exception as e:
return "Command failed: %s" % str(e)
obj_name = args['name']
delete_all = False
except KeyError:
delete_all = True
is_forced = False
if 'f' in args:
try:
if args['f'] is None:
is_forced = True
else:
is_forced = True if eval(str(args['f'])) else False
except KeyError:
is_forced = True
if delete_all is False:
try:
# deselect all to avoid delete selected object when run delete from shell
self.app.collection.set_all_inactive()
self.app.collection.set_active(str(obj_name))
self.app.on_delete(force_deletion=is_forced)
except Exception as e:
return "Command failed: %s" % str(e)
else:
try:
self.app.collection.set_all_active()
self.app.on_delete(force_deletion=is_forced)
except Exception as e:
return "Command failed: %s" % str(e)

View File

@ -48,11 +48,11 @@ class TclCommandExportGcode(TclCommandSignaled):
help = {
'main': "Export gcode into console output.",
'args': collections.OrderedDict([
('name', 'Name of the source Geometry object.'),
('name', 'Name of the source Geometry object. Required.'),
('preamble', 'Prepend GCODE.'),
('postamble', 'Append GCODE.')
]),
'examples': []
'examples': ['export_gcode geo_name -preamble "G01 X10 Y10" -postamble "G00 X20 Y20\nM04"']
}
def execute(self, args, unnamed_args):

View File

@ -31,7 +31,7 @@ class TclCommandExportGerber(TclCommand):
help = {
'main': "Export a Gerber Object as a Gerber File.",
'args': collections.OrderedDict([
('obj_name', 'Name of the object to export.'),
('obj_name', 'Name of the object to export. Required.'),
('filename', 'Path to the file to export.')
]),
'examples': ['export_gerber my_gerber path/my_file.gbr']

View File

@ -33,7 +33,7 @@ class TclCommandExportSVG(TclCommand):
help = {
'main': "Export a Geometry Object as a SVG File.",
'args': collections.OrderedDict([
('name', 'Name of the object export.'),
('name', 'Name of the object export. Required.'),
('filename', 'Path to the file to export.'),
('scale_factor', 'Multiplication factor used for scaling line widths during export.')
]),

View File

@ -29,10 +29,10 @@ class TclCommandExteriors(TclCommandSignaled):
help = {
'main': "Get exteriors of polygons.",
'args': collections.OrderedDict([
('name', 'Name of the source Geometry object.'),
('name', 'Name of the source Geometry object. Required.'),
('outname', 'Name of the resulting Geometry object.')
]),
'examples': []
'examples': ['ext geo_source_name -outname "final_geo"']
}
def execute(self, args, unnamed_args):

View File

@ -29,10 +29,10 @@ class TclCommandFollow(TclCommandSignaled):
help = {
'main': "Creates a geometry object following gerber paths.",
'args': collections.OrderedDict([
('name', 'Object name to follow.'),
('name', 'Object name to follow. Required.'),
('outname', 'Name of the resulting Geometry object.')
]),
'examples': ['follow name -outname name_follow']
'examples': ['follow name -outname "name_follow"']
}
def execute(self, args, unnamed_args):

View File

@ -45,14 +45,14 @@ class TclCommandGeoCutout(TclCommandSignaled):
help = {
'main': 'Creates board cutout from an object (Gerber or Geometry) of any shape',
'args': collections.OrderedDict([
('name', 'Name of the object.'),
('name', 'Name of the object to be cutout. Required'),
('dia', 'Tool diameter.'),
('margin', 'Margin over bounds.'),
('gapsize', 'size of gap.'),
('gaps', "type of gaps. Can be: 'tb' = top-bottom, 'lr' = left-right, '2tb' = 2top-2bottom, "
"'2lr' = 2left-2right, '4' = 4 cuts, '8' = 8 cuts")
]),
'examples': [" #isolate margin for example from fritzing arduino shield or any svg etc\n" +
'examples': [" #isolate margin for example from Fritzing arduino shield or any svg etc\n" +
" isolate BCu_margin -dia 3 -overlap 1\n" +
"\n" +
" #create exteriors from isolated object\n" +

View File

@ -32,12 +32,12 @@ class TclCommandGeoUnion(TclCommand):
help = {
'main': ('Runs a union operation (addition) on the components '
'of the geometry object. For example, if it contains '
'2 intersecting polygons, this opperation adds them into'
'2 intersecting polygons, this operation adds them into'
'a single larger polygon.'),
'args': collections.OrderedDict([
('name', 'Name of the Geometry Object.'),
('name', 'Name of the Geometry Object that contain the components to be joined. Required.'),
]),
'examples': []
'examples': ['geo_union target_geo']
}
def execute(self, args, unnamed_args):

View File

@ -29,11 +29,11 @@ class TclCommandGetNames(TclCommand):
# structured help for current command, args needs to be ordered
help = {
'main': 'Lists the names of objects in the project.',
'main': 'Lists the names of objects in the project. It returns a string with names separated by \n',
'args': collections.OrderedDict([
]),
'examples': []
'examples': ['get_names']
}
def execute(self, args, unnamed_args):

View File

@ -36,9 +36,9 @@ class TclCommandGetSys(TclCommand):
# structured help for current command, args needs to be ordered
help = {
'main': "Returns the value of the system variable.",
'main': "Returns the value of the targeted system variable.",
'args': collections.OrderedDict([
('name', 'Name of the system variable.'),
('name', 'Name of the system variable. Required.'),
]),
'examples': ['get_sys excellon_zeros']
}

View File

@ -30,11 +30,11 @@ class TclCommandImportSvg(TclCommandSignaled):
help = {
'main': "Import an SVG file as a Geometry Object..",
'args': collections.OrderedDict([
('filename', 'Path to file to open.'),
('filename', 'Absolute path to file to open. Required.'),
('type', 'Import as gerber or geometry(default).'),
('outname', 'Name of the resulting Geometry object.')
]),
'examples': []
'examples': ['import_svg D:\\my_beautiful_svg_file.SVG']
}
def execute(self, args, unnamed_args):

View File

@ -27,12 +27,12 @@ class TclCommandInteriors(TclCommandSignaled):
# structured help for current command, args needs to be ordered
help = {
'main': "Get interiors of polygons.",
'main': "Return the interiors of polygons as a list of Shapely geometry elements.",
'args': collections.OrderedDict([
('name', 'Name of the source Geometry object.'),
('name', 'Name of the source Geometry object. Required.'),
('outname', 'Name of the resulting Geometry object.')
]),
'examples': []
'examples': ['interiors my_geo_name -outname "outputed_geo"']
}
def execute(self, args, unnamed_args):

View File

@ -29,7 +29,7 @@ class TclCommandIsolate(TclCommandSignaled):
('dia', float),
('passes', int),
('overlap', float),
('combine', int),
('combine', bool),
('outname', str),
('follow', str),
('iso_type', int)
@ -43,18 +43,18 @@ class TclCommandIsolate(TclCommandSignaled):
help = {
'main': "Creates isolation routing geometry for the given Gerber.",
'args': collections.OrderedDict([
('name', 'Name of the source object.'),
('name', 'Name of the source object. Required.'),
('dia', 'Tool diameter.'),
('passes', 'Passes of tool width.'),
('overlap', 'Percentage of tool diameter to overlap current pass over previous pass. Float [0, 99.9999]\n'
'E.g: for a 25% from tool diameter overlap use -overlap 25'),
('combine', 'Combine all passes into one geometry.'),
('combine', 'Combine all passes into one geometry. Can be True or False, 1 or 0'),
('outname', 'Name of the resulting Geometry object.'),
('follow', 'Create a Geometry that follows the Gerber path.'),
('iso_type', 'A value of 0 will isolate exteriors, a value of 1 will isolate interiors '
'and a value of 2 will do full isolation.')
]),
'examples': []
'examples': ['isolate my_geo -dia 0.1 -passes 2 -overlap 10 -combine True -iso_type 2 -outname out_geo']
}
def execute(self, args, unnamed_args):
@ -80,6 +80,10 @@ class TclCommandIsolate(TclCommandSignaled):
if 'follow' not in args:
args['follow'] = None
# evaluate this parameter so True, False, 0 and 1 works
if "combine" in args:
args['combine'] = eval(args['combine'])
obj = self.app.collection.get_by_name(name)
if obj is None:
self.raise_tcl_error("Object not found: %s" % name)

View File

@ -22,7 +22,6 @@ class TclCommandJoinExcellon(TclCommand):
# 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'}
@ -30,14 +29,14 @@ class TclCommandJoinExcellon(TclCommand):
# structured help for current command, args needs to be ordered
help = {
'main': "Runs a merge operation (join) on the Excellon objects.",
'main': "Runs a merge operation (join) on the Excellon objects.\n"
"The names of the Excellon objects to be merged will be entered after the outname,\n"
"separated by spaces. See the example bellow.\n"
"WARNING: if the name of an Excellon objects has spaces, enclose the name with quotes.",
'args': collections.OrderedDict([
('name', 'Name of the new Excellon Object.'),
('obj_name_0', 'Name of the first object'),
('obj_name_1', 'Name of the second object.'),
('obj_name_2...', 'Additional object names')
('outname', 'Name of the new Excellon Object made by joining of other Excellon objects. Required'),
]),
'examples': []
'examples': ['join_excellons merged_new_excellon exc_name_1 "exc name_2"']
}
def execute(self, args, unnamed_args):
@ -48,7 +47,7 @@ class TclCommandJoinExcellon(TclCommand):
:return:
"""
outname = args['name']
outname = args['outname']
obj_names = unnamed_args
objs = []
@ -60,7 +59,9 @@ class TclCommandJoinExcellon(TclCommand):
objs.append(obj)
def initialize(obj_, app):
FlatCAMExcellon.merge(objs, obj_)
FlatCAMExcellon.merge(self, objs, obj_)
if objs is not None:
if objs:
self.app.new_object("excellon", outname, initialize, plot=False)
else:
return "No Excellon objects to be joined."

View File

@ -30,14 +30,14 @@ class TclCommandJoinGeometry(TclCommand):
# structured help for current command, args needs to be ordered
help = {
'main': "Runs a merge operation (join) on the Excellon objects.",
'main': "Runs a merge operation (join) on the Geometry objects.\n"
"The names of the Geometry objects to be merged will be entered after the outname,\n"
"separated by spaces. See the example bellow.\n"
"WARNING: if the name of an Geometry objects has spaces, enclose the name with quotes.",
'args': collections.OrderedDict([
('outname', 'Name of the new Geometry Object.'),
('obj_name_0', 'Name of the first object'),
('obj_name_1', 'Name of the second object.'),
('obj_name_2...', 'Additional object names')
('outname', 'Name of the new Geometry Object made by joining of other Geometry objects. Required'),
]),
'examples': []
'examples': ['join_geometry merged_new_geo geo_name_1 "geo name_2"']
}
def execute(self, args, unnamed_args):
@ -60,7 +60,9 @@ class TclCommandJoinGeometry(TclCommand):
objs.append(obj)
def initialize(obj_, app):
FlatCAMGeometry.merge(objs, obj_)
FlatCAMGeometry.merge(self, objs, obj_)
if objs is not None:
if objs:
self.app.new_object("geometry", outname, initialize, plot=False)
else:
return "No Geometry objects to be joined."

View File

@ -40,7 +40,7 @@ class TclCommandListSys(TclCommand):
"of the system variable.\n"
"In that case it will list only the system variables that starts with that string.\n"
"Main categories start with: gerber or excellon or geometry or cncjob or global.\n"
"Note: Use get_sys TclCommand to get the value and set_sys TclCommand to set it.\n",
"Note: Use 'get_sys system variable' to get the value and 'set_sys system variable value' to set it.\n",
'args': collections.OrderedDict([
]),
'examples': ['list_sys',

View File

@ -34,7 +34,7 @@ class TclCommandMillDrills(TclCommandSignaled):
('milled_dias', str),
('outname', str),
('tooldia', float),
('use_threads', bool),
('use_thread', bool),
('diatol', float)
])
@ -45,10 +45,13 @@ class TclCommandMillDrills(TclCommandSignaled):
help = {
'main': "Create Geometry Object for milling drill holes from Excellon.",
'args': collections.OrderedDict([
('name', 'Name of the Excellon Object.'),
('milled_dias', 'Comma separated tool diameters of the drills to be milled (example: 0.6, 1.0 or 3.125).'),
('name', 'Name of the Excellon Object. Required.'),
('milled_dias', 'Comma separated tool diameters of the drills to be milled (example: 0.6, 1.0 or 3.125).\n'
'Exception: if you enter "all" then the drills for all tools will be milled.\n'
'WARNING: no spaces are allowed in the list of tools.\n'
'As a precaution you can enclose them with quotes.'),
('tooldia', 'Diameter of the milling tool (example: 0.1).'),
('outname', 'Name of object to create.'),
('outname', 'Name of object to be created holding the milled geometries.'),
('use_thread', 'If to use multithreading: True or False.'),
('diatol', 'Tolerance. Percentange (0.0 ... 100.0) within which dias in milled_dias will be judged to be '
'the same as the ones in the tools from the Excellon object. E.g: if in milled_dias we have a '
@ -56,7 +59,8 @@ class TclCommandMillDrills(TclCommandSignaled):
'diatol = 5.0 then the drills with the dia = (0.95 ... 1.05) '
'in Excellon will be processed. Float number.')
]),
'examples': ['milldrills mydrills', 'milld my_excellon.drl']
'examples': ['milldrills mydrills -milled_dias "0.6,0.8" -tooldia 0.1 -diatol 10 -outname milled_holes',
'milld my_excellon.drl']
}
def execute(self, args, unnamed_args):
@ -85,8 +89,6 @@ class TclCommandMillDrills(TclCommandSignaled):
if not obj.drills:
self.raise_tcl_error("The Excellon object has no drills: %s" % name)
units = self.app.defaults['units'].upper()
try:
if 'milled_dias' in args and args['milled_dias'] != 'all':
diameters = [x.strip() for x in args['milled_dias'].split(",") if x != '']

View File

@ -34,7 +34,7 @@ class TclCommandMillSlots(TclCommandSignaled):
('milled_dias', str),
('outname', str),
('tooldia', float),
('use_threads', bool),
('use_thread', bool),
('diatol', float)
])
@ -45,10 +45,13 @@ class TclCommandMillSlots(TclCommandSignaled):
help = {
'main': "Create Geometry Object for milling slot holes from Excellon.",
'args': collections.OrderedDict([
('name', 'Name of the Excellon Object.'),
('milled_dias', 'Comma separated tool diameters of the slots to be milled (example: 0.6, 1.0 or 3.125).'),
('name', 'Name of the Excellon Object. Required.'),
('milled_dias', 'Comma separated tool diameters of the slots to be milled (example: 0.6, 1.0 or 3.125).\n'
'Exception: if you enter "all" then the slots for all tools will be milled.\n'
'WARNING: no spaces are allowed in the list of tools.\n'
'As a precaution you can enclose them with quotes.'),
('tooldia', 'Diameter of the milling tool (example: 0.1).'),
('outname', 'Name of object to create.'),
('outname', 'Name of object to be created holding the milled geometries.'),
('use_thread', 'If to use multithreading: True or False.'),
('diatol', 'Tolerance. Percentange (0.0 ... 100.0) within which dias in milled_dias will be judged to be '
'the same as the ones in the tools from the Excellon object. E.g: if in milled_dias we have a '
@ -56,7 +59,8 @@ class TclCommandMillSlots(TclCommandSignaled):
'diatol = 5.0 then the slots with the dia = (0.95 ... 1.05) '
'in Excellon will be processed. Float number.')
]),
'examples': ['millslots mydrills', 'mills my_excellon.drl']
'examples': ['millslots myslots -milled_dias "0.6,0.8" -tooldia 0.1 -diatol 10 -outname milled_slots',
'mills my_excellon.drl']
}
def execute(self, args, unnamed_args):

View File

@ -24,22 +24,25 @@ class TclCommandMirror(TclCommandSignaled):
option_types = collections.OrderedDict([
('axis', str),
('box', str),
('dist', float)
('origin', str)
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
required = ['name', 'axis']
required = ['name']
# structured help for current command, args needs to be ordered
help = {
'main': "Opens an Excellon file.",
'main': "Will mirror an named object.",
'args': collections.OrderedDict([
('name', 'Name of the object (Gerber or Excellon) to mirror.'),
('box', 'Name of object which act as box (cutout for example.)'),
('name', 'Name of the object (Gerber, Geometry or Excellon) to be mirrored. Required.'),
('axis', 'Mirror axis parallel to the X or Y axis.'),
('dist', 'Distance of the mirror axis to the X or Y axis.')
('box', 'Name of object which act as box (cutout for example.)'),
('origin', 'Reference point . It is used only if the box is not used. Format (x,y).\n'
'Comma will separate the X and Y coordinates.\n'
'WARNING: no spaces are allowed. If uncertain enclose the two values inside parenthesis.\n'
'See the example.')
]),
'examples': []
'examples': ['mirror obj_name -box box_geo -axis X -origin 3.2,4.7']
}
def execute(self, args, unnamed_args):
@ -69,10 +72,13 @@ class TclCommandMirror(TclCommandSignaled):
return "ERROR: Only Gerber, Excellon and Geometry objects can be mirrored."
# Axis
try:
axis = args['axis'].upper()
except KeyError:
return "ERROR: Specify -axis X or -axis Y"
if 'axis' in args:
try:
axis = args['axis'].upper()
except KeyError:
axis = 'Y'
else:
axis = 'Y'
# Box
if 'box' in args:
@ -91,19 +97,22 @@ class TclCommandMirror(TclCommandSignaled):
obj.mirror(axis, [px, py])
obj.plot()
return
except Exception as e:
return "Operation failed: %s" % str(e)
else:
# Origin
if 'origin' in args:
try:
dist = float(args['dist'])
origin_val = eval(args['origin'])
x = float(origin_val[0])
y = float(origin_val[1])
except KeyError:
dist = 0.0
x, y = (0, 0)
except ValueError:
return "Invalid distance: %s" % args['dist']
return "Invalid distance: %s" % str(args['origin'])
try:
obj.mirror(axis, [dist, dist])
obj.mirror(axis, [x, y])
except Exception as e:
return "Operation failed: %s" % str(e)

View File

@ -24,7 +24,7 @@ class TclCommandNew(TclCommand):
help = {
'main': "Starts a new project. Clears objects from memory.",
'args': collections.OrderedDict(),
'examples': []
'examples': ['new']
}
def execute(self, args, unnamed_args):

View File

@ -39,7 +39,7 @@ class TclCommandNewExcellon(TclCommandSignaled):
'args': collections.OrderedDict([
('name', 'New object name.'),
]),
'examples': []
'examples': ['new_excellon my_excellon', 'new_excellon']
}
def execute(self, args, unnamed_args):

View File

@ -28,11 +28,12 @@ class TclCommandNewGeometry(TclCommandSignaled):
# structured help for current command, args needs to be ordered
help = {
'main': "Creates a new empty geometry object.",
'main': "Creates a new empty Geometry object.",
'args': collections.OrderedDict([
('name', 'New object name.'),
]),
'examples': []
'examples': ['new_geometry\n'
'new_geometry my_new_geo']
}
def execute(self, args, unnamed_args):

View File

@ -39,7 +39,7 @@ class TclCommandNewGerber(TclCommandSignaled):
'args': collections.OrderedDict([
('name', 'New object name.'),
]),
'examples': []
'examples': ['new_gerber', 'new_gerber my_new_gerber_name']
}
def execute(self, args, unnamed_args):

View File

@ -41,13 +41,13 @@ class TclCommandNregions(TclCommand):
help = {
'main': "Creates a geometry object with the non-copper regions.",
'args': collections.OrderedDict([
('name', 'Object name for which to create non-copper regions. String'),
('name', 'Object name for which to create non-copper regions. String. Required.'),
('outname', 'Name of the resulting Geometry object. String.'),
('margin', "Specify the edge of the PCB by drawing a box around all objects with this minimum distance. "
"Float number."),
('rounded', "Resulting geometry will have rounded corners. True or False.")
]),
'examples': ['ncr name -outname name_ncr']
'examples': ['ncr name -margin 0.1 -rounded True -outname name_ncr']
}
def execute(self, args, unnamed_args):

View File

@ -23,21 +23,22 @@ class TclCommandOffset(TclCommand):
# Dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
option_types = collections.OrderedDict([
('x', float),
('y', float)
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
required = ['name', 'x', 'y']
required = ['name']
# structured help for current command, args needs to be ordered
help = {
'main': "Changes the position of the object.",
'main': "Changes the position of the object on X and/or Y axis.",
'args': collections.OrderedDict([
('name', 'Name of the object to offset.'),
('x', 'Offset distance in the X axis.'),
('y', 'Offset distance in the Y axis')
('name', 'Name of the object to offset. Required.'),
('x', 'Offset distance in the X axis. If it is not used it will be assumed to be 0.0'),
('y', 'Offset distance in the Y axis. If it is not used it will be assumed to be 0.0')
]),
'examples': ['offset my_geometry 1.2 -0.3']
'examples': ['offset my_geometry -x 1.2 -y -0.3', 'offset my_geometry -x 1.0']
}
def execute(self, args, unnamed_args):
@ -49,6 +50,12 @@ class TclCommandOffset(TclCommand):
"""
name = args['name']
x, y = float(args['x']), float(args['y'])
off_x = args['x'] if 'x' in args else 0.0
off_y = args['y'] if 'y' in args else 0.0
x, y = float(off_x), float(off_y)
if (x, y) == (0.0, 0.0):
return
self.app.collection.get_by_name(name).offset((x, y))

View File

@ -30,10 +30,13 @@ class TclCommandOpenExcellon(TclCommandSignaled):
help = {
'main': "Opens an Excellon file.",
'args': collections.OrderedDict([
('filename', 'Path to file to open.'),
('filename', 'Absolute path to file to open. Required.\n'
'WARNING: no spaces are allowed. If unsure enclose the entire path with quotes.'),
('outname', 'Name of the resulting Excellon object.')
]),
'examples': []
'examples': ['open_excellon D:\\my_excellon_file.DRL',
'open_excellon "D:\\my_excellon_file with spaces in the name.DRL"',
'open_excellon path_to_file']
}
def execute(self, args, unnamed_args):
@ -48,6 +51,9 @@ class TclCommandOpenExcellon(TclCommandSignaled):
filename = args.pop('filename')
# filename = filename.replace(' ', '')
if ' ' in filename:
return "The absolute path to the project file contain spaces which is not allowed.\n" \
"Please enclose the path within quotes."
args['plot'] = False
self.app.open_excellon(filename, **args)

View File

@ -31,10 +31,12 @@ class TclCommandOpenGCode(TclCommandSignaled):
help = {
'main': "Opens a G-Code file.",
'args': collections.OrderedDict([
('filename', 'Path to file to open.'),
('filename', 'Absolute path to file to open. Required.\n'
'WARNING: no spaces are allowed. If unsure enclose the entire path with quotes.'),
('outname', 'Name of the resulting CNCJob object.')
]),
'examples': []
'examples': ['open_gcode D:\\my_gcode_file.NC',
'open_gcode "D:\\my_gcode_file with spaces in the name.TXT"']
}
def execute(self, args, unnamed_args):
@ -48,6 +50,8 @@ class TclCommandOpenGCode(TclCommandSignaled):
"""
args['plot'] = False
filename = args["filename"]
# filename = filename.replace(' ', '')
if ' ' in filename:
return "The absolute path to the project file contain spaces which is not allowed.\n" \
"Please enclose the path within quotes."
self.app.open_gcode(filename, **args)

View File

@ -30,10 +30,12 @@ class TclCommandOpenGerber(TclCommandSignaled):
help = {
'main': "Opens a Gerber file.",
'args': collections.OrderedDict([
('filename', 'Path to file to open.'),
('filename', 'Absolute path to file to open. Required.\n'
'WARNING: no spaces are allowed. If unsure enclose the entire path with quotes.'),
('outname', 'Name of the resulting Gerber object.')
]),
'examples': ["open_gerber gerber_object_path -outname bla"]
'examples': ["open_gerber gerber_object_path -outname bla",
'open_gerber "D:\\my_gerber_file with spaces in the name.GRB"']
}
def execute(self, args, unnamed_args):
@ -65,7 +67,10 @@ class TclCommandOpenGerber(TclCommandSignaled):
return
filename = args['filename']
# filename = filename.replace(' ', '')
if ' ' in filename:
return "The absolute path to the project file contain spaces which is not allowed.\n" \
"Please enclose the path within quotes."
if 'outname' in args:
outname = args['outname']

View File

@ -30,9 +30,11 @@ class TclCommandOpenProject(TclCommandSignaled):
help = {
'main': "Opens a FlatCAM project.",
'args': collections.OrderedDict([
('filename', 'Path to file to open.'),
('filename', 'Absolute path to file to open. Required.\n'
'WARNING: no spaces are allowed. If unsure enclose the entire path with quotes.'),
]),
'examples': []
'examples': ['open_project D:\\my_project_file.FlatPrj',
'open_project "D:\\my_project_file with spaces in the name.FlatPrj"']
}
def execute(self, args, unnamed_args):
@ -45,6 +47,8 @@ class TclCommandOpenProject(TclCommandSignaled):
:return: None or exception
"""
filename = args['filename']
filename = filename.replace(' ', '')
if ' ' in filename:
return "The absolute path to the project file contain spaces which is not allowed.\n" \
"Please enclose the path within quotes."
self.app.open_project(filename, cli=True, plot=False)

View File

@ -28,11 +28,11 @@ class TclCommandOptions(TclCommandSignaled):
# structured help for current command, args needs to be ordered
help = {
'main': "Shows the settings for an object.",
'main': "Will return the options (settings) for an object as a string with values separated by \\n.",
'args': collections.OrderedDict([
('name', 'Object name.'),
('name', 'Object name for which to return the options. Required.'),
]),
'examples': []
'examples': ['options obj_name']
}
def execute(self, args, unnamed_args):

View File

@ -38,7 +38,7 @@ class TclCommandPanelize(TclCommand):
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
required = ['name', 'rows', 'columns']
required = ['name']
# structured help for current command, args needs to be ordered
help = {
@ -54,7 +54,14 @@ class TclCommandPanelize(TclCommand):
('outname', 'Name of the new geometry object.'),
('run_threaded', 'False = non-threaded || True = threaded')
]),
'examples': []
'examples': [
'panelize obj_name',
'panel obj_name -rows 2 -columns 2 -spacing_columns 0.4 -spacing_rows 1.3 -box box_obj_name '
'-outname panelized_name',
'panel obj_name -columns 2 -box box_obj_name -outname panelized_name',
]
}
def execute(self, args, unnamed_args):
@ -85,8 +92,18 @@ class TclCommandPanelize(TclCommand):
else:
box = obj
if 'columns' not in args or 'rows' not in args:
return "ERROR: Specify -columns and -rows"
if 'columns' in args:
columns = int(args['columns'])
else:
columns = int(0)
if 'rows' in args:
rows = int(args['rows'])
else:
rows = int(0)
if 'columns' not in args and 'rows' not in args:
return "ERROR: Specify either -columns or -rows. The one not specified it will assumed to be 0"
if 'outname' in args:
outname = args['outname']
@ -108,9 +125,6 @@ class TclCommandPanelize(TclCommand):
else:
spacing_rows = 5
rows = int(args['rows'])
columns = int(args['columns'])
xmin, ymin, xmax, ymax = box.bounds()
lenghtx = xmax - xmin + spacing_columns
lenghty = ymax - ymin + spacing_rows

View File

@ -33,7 +33,7 @@ class TclCommandPlotAll(TclCommand):
'args': collections.OrderedDict([
]),
'examples': []
'examples': ['plot_all']
}
def execute(self, args, unnamed_args):

View File

@ -32,15 +32,15 @@ class TclCommandPlotObjects(TclCommand):
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
required = []
required = ['names']
# structured help for current command, args needs to be ordered
help = {
'main': "Plot a list of objects.",
'args': collections.OrderedDict([
('names', "UA list of object names to be plotted.")
('names', "A list of object names to be plotted separated by comma. Required.")
]),
'examples': ["plot_objects"]
'examples': ["plot_objects gerber_obj.GRB, excellon_obj.DRL"]
}
def execute(self, args, unnamed_args):
@ -51,7 +51,7 @@ class TclCommandPlotObjects(TclCommand):
:return:
"""
if self.app.cmd_line_headless != 1:
names = [x.strip() for x in args['names'].split(",")]
names = [x.strip() for x in args['names'].split(",") if x != '']
objs = []
for name in names:
objs.append(self.app.collection.get_by_name(name))

View File

@ -30,9 +30,12 @@ class TclCommandSaveProject(TclCommandSignaled):
help = {
'main': "Saves the FlatCAM project to file.",
'args': collections.OrderedDict([
('filename', 'Path to file.'),
('filename', 'Absolute path to file to open. Required.\n'
'WARNING: no spaces are allowed. If unsure enclose the entire path with quotes.'),
]),
'examples': []
'examples': ['save_project D:\\my_project_file.FlatPrj',
'save_project "D:\\my_project_file with spaces in the name.FlatPrj"',
'save_project path_to_where_the_file_is_stored']
}
def execute(self, args, unnamed_args):

View File

@ -33,9 +33,9 @@ class TclCommandSaveSys(TclCommandSignaled):
# structured help for current command, args needs to be ordered
help = {
'main': "Saves the FlatCAM system paramaters to defaults file.",
'main': "Saves the FlatCAM system parameters to defaults file.",
'args': collections.OrderedDict([]),
'examples': []
'examples': ['save_sys']
}
def execute(self, args, unnamed_args):

View File

@ -45,18 +45,22 @@ class TclCommandScale(TclCommand):
help = {
'main': "Resizes the object by a factor on X axis and a factor on Y axis, having as scale origin the point ",
'args': collections.OrderedDict([
('name', 'Name of the object to resize.'),
('factor', 'Fraction by which to scale on both axis. '),
('name', 'Name of the object (Gerber, Geometry or Excellon) to be resized. Required.'),
('factor', 'Fraction by which to scale on both axis.'),
('x', 'Fraction by which to scale on X axis. If "factor" is used then this parameter is ignored'),
('y', 'Fraction by which to scale on Y axis. If "factor" is used then this parameter is ignored'),
('origin', 'Reference used for scale. It can be: "origin" which means point (0, 0) or "min_bounds" which '
'means the lower left point of the bounding box or it can be "center" which means the center '
'of the bounding box.')
('origin', 'Reference used for scale.\n'
'The reference point can be:\n'
'- "origin" which means point (0, 0)\n'
'- "min_bounds" which means the lower left point of the bounding box\n'
'- "center" which means the center point of the bounding box of the object.\n'
'- a tuple in format (x,y) with the X and Y coordinates separated by a comma. NO SPACES ALLOWED')
]),
'examples': ['scale my_geometry 4.2',
'scale my_geo -x 3.1 -y 2.8',
'scale my_geo 1.2 -origin min_bounds']
'scale my_geo 1.2 -origin min_bounds',
'scale my_geometry -x 2 -origin 3.0,2.1']
}
def execute(self, args, unnamed_args):
@ -92,8 +96,17 @@ class TclCommandScale(TclCommand):
c_y = ymin + (ymax - ymin) / 2
point = (c_x, c_y)
else:
self.raise_tcl_error('%s' % _("Expected -origin <origin> or -origin <min_bounds> or -origin <center>."))
return 'fail'
try:
point = eval(args['origin'])
if not isinstance(point, tuple):
raise Exception
except Exception as e:
self.raise_tcl_error('%s\n%s' % (_("Expected -origin <origin> or "
"-origin <min_bounds> or "
"-origin <center> or "
"- origin 3.0,4.2."), str(e))
)
return 'fail'
if 'factor' in args:
factor = float(args['factor'])

View File

@ -31,9 +31,9 @@ class TclCommandSetActive(TclCommand):
help = {
'main': 'Sets an object as active.',
'args': collections.OrderedDict([
('name', 'Name of the Object.'),
('name', 'Name of the FlatCAM object to be set as active (selected). Required.'),
]),
'examples': []
'examples': ['set_active object_name']
}
def execute(self, args, unnamed_args):

View File

@ -49,13 +49,15 @@ class TclCommandSetOrigin(TclCommand):
# structured help for current command, args needs to be ordered
help = {
'main': "Will set the origin at the specified x,y location.",
'main': "Will set the origin at the specified x,y location.\n"
"If it is called without arguments it will set origin at (0, 0)",
'args': collections.OrderedDict([
('loc', 'Location to offset all the selected objects. No spaces between x and y pair. Use like this: 2,3'),
('loc', 'Location to offset all the selected objects. NO SPACES ALLOWED in X and Y pair.\n'
'Use like this: 2,3'),
('auto', 'If set to True it will set the origin to the minimum x, y of the object selection bounding box.'
'-auto=True is not correct but -auto 1 or -auto True is correct.')
]),
'examples': ['set_origin 3,2', 'set_origin -auto 1']
'examples': ['set_origin 3,2', 'set_origin -auto 1', 'origin']
}
def execute(self, args, unnamed_args):

View File

@ -32,10 +32,10 @@ class TclCommandSetSys(TclCommand):
help = {
'main': "Sets the value of the system variable.",
'args': collections.OrderedDict([
('name', 'Name of the system variable.'),
('name', 'Name of the system variable. Required.'),
('value', 'Value to set.')
]),
'examples': []
'examples': ['set_sys global_gridx 1.0']
}
def execute(self, args, unnamed_args):

View File

@ -17,28 +17,27 @@ class TclCommandSkew(TclCommand):
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str),
('angle_x', float),
('angle_y', float)
])
# Dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
option_types = collections.OrderedDict([
('x', float),
('y', float)
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
required = ['name', 'angle_x', 'angle_y']
required = ['name']
# structured help for current command, args needs to be ordered
help = {
'main': "Shear/Skew an object by angles along x and y dimensions. The reference point is the left corner of "
"the bounding box of the object.",
'args': collections.OrderedDict([
('name', 'Name of the object to skew.'),
('angle_x', 'Angle in degrees by which to skew on the X axis.'),
('angle_y', 'Angle in degrees by which to skew on the Y axis.')
('name', 'Name of the object (Gerber, Geometry or Excellon) to be deformed (skewed). Required.'),
('x', 'Angle in degrees by which to skew on the X axis. If it is not used it will be assumed to be 0.0'),
('y', 'Angle in degrees by which to skew on the Y axis. If it is not used it will be assumed to be 0.0')
]),
'examples': ['skew my_geometry 10.2 3.5']
'examples': ['skew my_geometry -x 10.2 -y 3.5', 'skew my_geo -x 3.0']
}
def execute(self, args, unnamed_args):
@ -50,8 +49,20 @@ class TclCommandSkew(TclCommand):
"""
name = args['name']
angle_x = float(args['angle_x'])
angle_y = float(args['angle_y'])
if 'x' in args:
angle_x = float(args['x'])
else:
angle_x = 0.0
if 'y' in args:
angle_y = float(args['y'])
else:
angle_y = 0.0
if angle_x == 0.0 and angle_y == 0.0:
# nothing to be done
return
obj_to_skew = self.app.collection.get_by_name(name)
xmin, ymin, xmax, ymax = obj_to_skew.bounds()

View File

@ -28,12 +28,14 @@ class TclCommandSubtractPoly(TclCommandSignaled):
# structured help for current command, args needs to be ordered
help = {
'main': "Subtract polygon from the given Geometry object.",
'main': "Subtract polygon from the given Geometry object. The coordinates are provided in X Y pairs.\n"
"If the number of coordinates is not even then the 'Incomplete coordinate' error is raised.\n"
"If last coordinates are not the same as the first ones, the polygon will be completed automatically.",
'args': collections.OrderedDict([
('name', 'Name of the Geometry object from which to subtract.'),
('name', 'Name of the Geometry object from which to subtract. Required.'),
('x0 y0 x1 y1 x2 y2 ...', 'Points defining the polygon.')
]),
'examples': []
'examples': ['subtract_poly my_geo 0 0 2 1 3 3 4 4 0 0']
}
def execute(self, args, unnamed_args):

View File

@ -36,9 +36,10 @@ class TclCommandSubtractRectangle(TclCommandSignaled):
# structured help for current command, args needs to be ordered
help = {
'main': "Subtract rectange from the given Geometry object.",
'main': "Subtract a rectangle from the given Geometry object. The coordinates are provided in X Y pairs.\n"
"If the number of coordinates is not even then the 'Incomplete coordinates' error is raised.",
'args': collections.OrderedDict([
('name', 'Name of the Geometry object from which to subtract.'),
('name', 'Name of the Geometry object from which to subtract. Required.'),
('x0 y0', 'Bottom left corner coordinates.'),
('x1 y1', 'Top right corner coordinates.')
]),

View File

@ -34,8 +34,8 @@ class TclCommandWriteGCode(TclCommandSignaled):
help = {
'main': "Saves G-code of a CNC Job object to file.",
'args': collections.OrderedDict([
('name', 'Source CNC Job object.'),
('filename', 'Output filename.'),
('name', 'Source CNC Job object. Required.'),
('filename', 'Output filename. Required.'),
('preamble', 'Text to append at the beginning.'),
('postamble', 'Text to append at the end.'),
('muted', 'It will not put errors in the Shell or status bar.')