cleanups
implement TclCommand.TclCommandSignaled as proof of concept (not usefull) bypass using threads within obj.generatecncjob(use_thread = False, **args) reimplement some more shell commands to OOP style
This commit is contained in:
parent
0f463a1fc2
commit
980638630d
102
FlatCAMApp.py
102
FlatCAMApp.py
@ -651,7 +651,7 @@ class App(QtCore.QObject):
|
|||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def raiseTclUnknownError(self, unknownException):
|
def raise_tcl_unknown_error(self, unknownException):
|
||||||
"""
|
"""
|
||||||
raise Exception if is different type than TclErrorException
|
raise Exception if is different type than TclErrorException
|
||||||
:param unknownException:
|
:param unknownException:
|
||||||
@ -659,11 +659,11 @@ class App(QtCore.QObject):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
if not isinstance(unknownException, self.TclErrorException):
|
if not isinstance(unknownException, self.TclErrorException):
|
||||||
self.raiseTclError("Unknown error: %s" % str(unknownException))
|
self.raise_tcl_error("Unknown error: %s" % str(unknownException))
|
||||||
else:
|
else:
|
||||||
raise unknownException
|
raise unknownException
|
||||||
|
|
||||||
def raiseTclError(self, text):
|
def raise_tcl_error(self, text):
|
||||||
"""
|
"""
|
||||||
this method pass exception from python into TCL as error, so we get stacktrace and reason
|
this method pass exception from python into TCL as error, so we get stacktrace and reason
|
||||||
:param text: text of error
|
:param text: text of error
|
||||||
@ -2274,20 +2274,20 @@ class App(QtCore.QObject):
|
|||||||
# 8 - 2*left + 2*right +2*top + 2*bottom
|
# 8 - 2*left + 2*right +2*top + 2*bottom
|
||||||
|
|
||||||
if name is None:
|
if name is None:
|
||||||
self.raiseTclError('Argument name is missing.')
|
self.raise_tcl_error('Argument name is missing.')
|
||||||
|
|
||||||
for key in kwa:
|
for key in kwa:
|
||||||
if key not in types:
|
if key not in types:
|
||||||
self.raiseTclError('Unknown parameter: %s' % key)
|
self.raise_tcl_error('Unknown parameter: %s' % key)
|
||||||
try:
|
try:
|
||||||
kwa[key] = types[key](kwa[key])
|
kwa[key] = types[key](kwa[key])
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
self.raiseTclError("Cannot cast argument '%s' to type %s." % (key, str(types[key])))
|
self.raise_tcl_error("Cannot cast argument '%s' to type %s." % (key, str(types[key])))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
obj = self.collection.get_by_name(str(name))
|
obj = self.collection.get_by_name(str(name))
|
||||||
except:
|
except:
|
||||||
self.raiseTclError("Could not retrieve object: %s" % name)
|
self.raise_tcl_error("Could not retrieve object: %s" % name)
|
||||||
|
|
||||||
# Get min and max data for each object as we just cut rectangles across X or Y
|
# Get min and max data for each object as we just cut rectangles across X or Y
|
||||||
xmin, ymin, xmax, ymax = obj.bounds()
|
xmin, ymin, xmax, ymax = obj.bounds()
|
||||||
@ -2337,7 +2337,7 @@ class App(QtCore.QObject):
|
|||||||
ymax + gapsize)
|
ymax + gapsize)
|
||||||
|
|
||||||
except Exception as unknown:
|
except Exception as unknown:
|
||||||
self.raiseTclUnknownError(unknown)
|
self.raise_tcl_unknown_error(unknown)
|
||||||
|
|
||||||
def mirror(name, *args):
|
def mirror(name, *args):
|
||||||
a, kwa = h(*args)
|
a, kwa = h(*args)
|
||||||
@ -2624,26 +2624,26 @@ class App(QtCore.QObject):
|
|||||||
}
|
}
|
||||||
|
|
||||||
if name is None:
|
if name is None:
|
||||||
self.raiseTclError('Argument name is missing.')
|
self.raise_tcl_error('Argument name is missing.')
|
||||||
|
|
||||||
for key in kwa:
|
for key in kwa:
|
||||||
if key not in types:
|
if key not in types:
|
||||||
self.raiseTclError('Unknown parameter: %s' % key)
|
self.raise_tcl_error('Unknown parameter: %s' % key)
|
||||||
try:
|
try:
|
||||||
kwa[key] = types[key](kwa[key])
|
kwa[key] = types[key](kwa[key])
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
self.raiseTclError("Cannot cast argument '%s' to type %s." % (key, str(types[key])))
|
self.raise_tcl_error("Cannot cast argument '%s' to type %s." % (key, str(types[key])))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
obj = self.collection.get_by_name(str(name))
|
obj = self.collection.get_by_name(str(name))
|
||||||
except:
|
except:
|
||||||
self.raiseTclError("Could not retrieve object: %s" % name)
|
self.raise_tcl_error("Could not retrieve object: %s" % name)
|
||||||
|
|
||||||
if obj is None:
|
if obj is None:
|
||||||
self.raiseTclError('Object not found: %s' % name)
|
self.raise_tcl_error('Object not found: %s' % name)
|
||||||
|
|
||||||
if not isinstance(obj, FlatCAMExcellon):
|
if not isinstance(obj, FlatCAMExcellon):
|
||||||
self.raiseTclError('Only Excellon objects can be drilled, got %s %s.' % (name, type(obj)))
|
self.raise_tcl_error('Only Excellon objects can be drilled, got %s %s.' % (name, type(obj)))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Get the tools from the list
|
# Get the tools from the list
|
||||||
@ -2663,10 +2663,10 @@ class App(QtCore.QObject):
|
|||||||
obj.app.new_object("cncjob", job_name, job_init)
|
obj.app.new_object("cncjob", job_name, job_init)
|
||||||
|
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
self.raiseTclError("Operation failed: %s" % str(e))
|
self.raise_tcl_error("Operation failed: %s" % str(e))
|
||||||
|
|
||||||
except Exception as unknown:
|
except Exception as unknown:
|
||||||
self.raiseTclUnknownError(unknown)
|
self.raise_tcl_unknown_error(unknown)
|
||||||
|
|
||||||
|
|
||||||
def millholes(name=None, *args):
|
def millholes(name=None, *args):
|
||||||
@ -2684,43 +2684,43 @@ class App(QtCore.QObject):
|
|||||||
'outname': str}
|
'outname': str}
|
||||||
|
|
||||||
if name is None:
|
if name is None:
|
||||||
self.raiseTclError('Argument name is missing.')
|
self.raise_tcl_error('Argument name is missing.')
|
||||||
|
|
||||||
for key in kwa:
|
for key in kwa:
|
||||||
if key not in types:
|
if key not in types:
|
||||||
self.raiseTclError('Unknown parameter: %s' % key)
|
self.raise_tcl_error('Unknown parameter: %s' % key)
|
||||||
try:
|
try:
|
||||||
kwa[key] = types[key](kwa[key])
|
kwa[key] = types[key](kwa[key])
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
self.raiseTclError("Cannot cast argument '%s' to type %s." % (key, types[key]))
|
self.raise_tcl_error("Cannot cast argument '%s' to type %s." % (key, types[key]))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if 'tools' in kwa:
|
if 'tools' in kwa:
|
||||||
kwa['tools'] = [x.strip() for x in kwa['tools'].split(",")]
|
kwa['tools'] = [x.strip() for x in kwa['tools'].split(",")]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.raiseTclError("Bad tools: %s" % str(e))
|
self.raise_tcl_error("Bad tools: %s" % str(e))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
obj = self.collection.get_by_name(str(name))
|
obj = self.collection.get_by_name(str(name))
|
||||||
except:
|
except:
|
||||||
self.raiseTclError("Could not retrieve object: %s" % name)
|
self.raise_tcl_error("Could not retrieve object: %s" % name)
|
||||||
|
|
||||||
if obj is None:
|
if obj is None:
|
||||||
self.raiseTclError("Object not found: %s" % name)
|
self.raise_tcl_error("Object not found: %s" % name)
|
||||||
|
|
||||||
if not isinstance(obj, FlatCAMExcellon):
|
if not isinstance(obj, FlatCAMExcellon):
|
||||||
self.raiseTclError('Only Excellon objects can be mill drilled, got %s %s.' % (name, type(obj)))
|
self.raise_tcl_error('Only Excellon objects can be mill drilled, got %s %s.' % (name, type(obj)))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
success, msg = obj.generate_milling(**kwa)
|
success, msg = obj.generate_milling(**kwa)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.raiseTclError("Operation failed: %s" % str(e))
|
self.raise_tcl_error("Operation failed: %s" % str(e))
|
||||||
|
|
||||||
if not success:
|
if not success:
|
||||||
self.raiseTclError(msg)
|
self.raise_tcl_error(msg)
|
||||||
|
|
||||||
except Exception as unknown:
|
except Exception as unknown:
|
||||||
self.raiseTclUnknownError(unknown)
|
self.raise_tcl_unknown_error(unknown)
|
||||||
|
|
||||||
def exteriors(name=None, *args):
|
def exteriors(name=None, *args):
|
||||||
'''
|
'''
|
||||||
@ -2735,26 +2735,26 @@ class App(QtCore.QObject):
|
|||||||
types = {'outname': str}
|
types = {'outname': str}
|
||||||
|
|
||||||
if name is None:
|
if name is None:
|
||||||
self.raiseTclError('Argument name is missing.')
|
self.raise_tcl_error('Argument name is missing.')
|
||||||
|
|
||||||
for key in kwa:
|
for key in kwa:
|
||||||
if key not in types:
|
if key not in types:
|
||||||
self.raiseTclError('Unknown parameter: %s' % key)
|
self.raise_tcl_error('Unknown parameter: %s' % key)
|
||||||
try:
|
try:
|
||||||
kwa[key] = types[key](kwa[key])
|
kwa[key] = types[key](kwa[key])
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
self.raiseTclError("Cannot cast argument '%s' to type %s." % (key, types[key]))
|
self.raise_tcl_error("Cannot cast argument '%s' to type %s." % (key, types[key]))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
obj = self.collection.get_by_name(str(name))
|
obj = self.collection.get_by_name(str(name))
|
||||||
except:
|
except:
|
||||||
self.raiseTclError("Could not retrieve object: %s" % name)
|
self.raise_tcl_error("Could not retrieve object: %s" % name)
|
||||||
|
|
||||||
if obj is None:
|
if obj is None:
|
||||||
self.raiseTclError("Object not found: %s" % name)
|
self.raise_tcl_error("Object not found: %s" % name)
|
||||||
|
|
||||||
if not isinstance(obj, Geometry):
|
if not isinstance(obj, Geometry):
|
||||||
self.raiseTclError('Expected Geometry, got %s %s.' % (name, type(obj)))
|
self.raise_tcl_error('Expected Geometry, got %s %s.' % (name, type(obj)))
|
||||||
|
|
||||||
def geo_init(geo_obj, app_obj):
|
def geo_init(geo_obj, app_obj):
|
||||||
geo_obj.solid_geometry = obj_exteriors
|
geo_obj.solid_geometry = obj_exteriors
|
||||||
@ -2768,10 +2768,10 @@ class App(QtCore.QObject):
|
|||||||
obj_exteriors = obj.get_exteriors()
|
obj_exteriors = obj.get_exteriors()
|
||||||
self.new_object('geometry', outname, geo_init)
|
self.new_object('geometry', outname, geo_init)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.raiseTclError("Failed: %s" % str(e))
|
self.raise_tcl_error("Failed: %s" % str(e))
|
||||||
|
|
||||||
except Exception as unknown:
|
except Exception as unknown:
|
||||||
self.raiseTclUnknownError(unknown)
|
self.raise_tcl_unknown_error(unknown)
|
||||||
|
|
||||||
def interiors(name=None, *args):
|
def interiors(name=None, *args):
|
||||||
'''
|
'''
|
||||||
@ -2787,25 +2787,25 @@ class App(QtCore.QObject):
|
|||||||
|
|
||||||
for key in kwa:
|
for key in kwa:
|
||||||
if key not in types:
|
if key not in types:
|
||||||
self.raiseTclError('Unknown parameter: %s' % key)
|
self.raise_tcl_error('Unknown parameter: %s' % key)
|
||||||
try:
|
try:
|
||||||
kwa[key] = types[key](kwa[key])
|
kwa[key] = types[key](kwa[key])
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
self.raiseTclError("Cannot cast argument '%s' to type %s." % (key, types[key]))
|
self.raise_tcl_error("Cannot cast argument '%s' to type %s." % (key, types[key]))
|
||||||
|
|
||||||
if name is None:
|
if name is None:
|
||||||
self.raiseTclError('Argument name is missing.')
|
self.raise_tcl_error('Argument name is missing.')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
obj = self.collection.get_by_name(str(name))
|
obj = self.collection.get_by_name(str(name))
|
||||||
except:
|
except:
|
||||||
self.raiseTclError("Could not retrieve object: %s" % name)
|
self.raise_tcl_error("Could not retrieve object: %s" % name)
|
||||||
|
|
||||||
if obj is None:
|
if obj is None:
|
||||||
self.raiseTclError("Object not found: %s" % name)
|
self.raise_tcl_error("Object not found: %s" % name)
|
||||||
|
|
||||||
if not isinstance(obj, Geometry):
|
if not isinstance(obj, Geometry):
|
||||||
self.raiseTclError('Expected Geometry, got %s %s.' % (name, type(obj)))
|
self.raise_tcl_error('Expected Geometry, got %s %s.' % (name, type(obj)))
|
||||||
|
|
||||||
def geo_init(geo_obj, app_obj):
|
def geo_init(geo_obj, app_obj):
|
||||||
geo_obj.solid_geometry = obj_interiors
|
geo_obj.solid_geometry = obj_interiors
|
||||||
@ -2819,10 +2819,10 @@ class App(QtCore.QObject):
|
|||||||
obj_interiors = obj.get_interiors()
|
obj_interiors = obj.get_interiors()
|
||||||
self.new_object('geometry', outname, geo_init)
|
self.new_object('geometry', outname, geo_init)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.raiseTclError("Failed: %s" % str(e))
|
self.raise_tcl_error("Failed: %s" % str(e))
|
||||||
|
|
||||||
except Exception as unknown:
|
except Exception as unknown:
|
||||||
self.raiseTclUnknownError(unknown)
|
self.raise_tcl_unknown_error(unknown)
|
||||||
|
|
||||||
def isolate(name=None, *args):
|
def isolate(name=None, *args):
|
||||||
'''
|
'''
|
||||||
@ -2840,29 +2840,29 @@ class App(QtCore.QObject):
|
|||||||
|
|
||||||
for key in kwa:
|
for key in kwa:
|
||||||
if key not in types:
|
if key not in types:
|
||||||
self.raiseTclError('Unknown parameter: %s' % key)
|
self.raise_tcl_error('Unknown parameter: %s' % key)
|
||||||
try:
|
try:
|
||||||
kwa[key] = types[key](kwa[key])
|
kwa[key] = types[key](kwa[key])
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
self.raiseTclError("Cannot cast argument '%s' to type %s." % (key, types[key]))
|
self.raise_tcl_error("Cannot cast argument '%s' to type %s." % (key, types[key]))
|
||||||
try:
|
try:
|
||||||
obj = self.collection.get_by_name(str(name))
|
obj = self.collection.get_by_name(str(name))
|
||||||
except:
|
except:
|
||||||
self.raiseTclError("Could not retrieve object: %s" % name)
|
self.raise_tcl_error("Could not retrieve object: %s" % name)
|
||||||
|
|
||||||
if obj is None:
|
if obj is None:
|
||||||
self.raiseTclError("Object not found: %s" % name)
|
self.raise_tcl_error("Object not found: %s" % name)
|
||||||
|
|
||||||
assert isinstance(obj, FlatCAMGerber), \
|
assert isinstance(obj, FlatCAMGerber), \
|
||||||
"Expected a FlatCAMGerber, got %s" % type(obj)
|
"Expected a FlatCAMGerber, got %s" % type(obj)
|
||||||
|
|
||||||
if not isinstance(obj, FlatCAMGerber):
|
if not isinstance(obj, FlatCAMGerber):
|
||||||
self.raiseTclError('Expected FlatCAMGerber, got %s %s.' % (name, type(obj)))
|
self.raise_tcl_error('Expected FlatCAMGerber, got %s %s.' % (name, type(obj)))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
obj.isolate(**kwa)
|
obj.isolate(**kwa)
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
self.raiseTclError("Operation failed: %s" % str(e))
|
self.raise_tcl_error("Operation failed: %s" % str(e))
|
||||||
|
|
||||||
return 'Ok'
|
return 'Ok'
|
||||||
|
|
||||||
@ -3253,11 +3253,11 @@ class App(QtCore.QObject):
|
|||||||
Test it like this:
|
Test it like this:
|
||||||
if name is None:
|
if name is None:
|
||||||
|
|
||||||
self.raiseTclError('Argument name is missing.')
|
self.raise_tcl_error('Argument name is missing.')
|
||||||
|
|
||||||
When error ocurre, always use raiseTclError, never return "sometext" on error,
|
When error ocurre, always use raise_tcl_error, never return "sometext" on error,
|
||||||
otherwise we will miss it and processing will silently continue.
|
otherwise we will miss it and processing will silently continue.
|
||||||
Method raiseTclError pass error into TCL interpreter, then raise python exception,
|
Method raise_tcl_error pass error into TCL interpreter, then raise python exception,
|
||||||
which is catched in exec_command and displayed in TCL shell console with red background.
|
which is catched in exec_command and displayed in TCL shell console with red background.
|
||||||
Error in console is displayed with TCL trace.
|
Error in console is displayed with TCL trace.
|
||||||
|
|
||||||
|
@ -1040,6 +1040,10 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
|
|||||||
|
|
||||||
self.app.inform.emit("Saved to: " + filename)
|
self.app.inform.emit("Saved to: " + filename)
|
||||||
|
|
||||||
|
def get_gcode(self, preamble='', postamble=''):
|
||||||
|
#we need this to beable get_gcode separatelly for shell command export_code
|
||||||
|
return preamble + '\n' + self.gcode + "\n" + postamble
|
||||||
|
|
||||||
def on_plot_cb_click(self, *args):
|
def on_plot_cb_click(self, *args):
|
||||||
if self.muted_ui:
|
if self.muted_ui:
|
||||||
return
|
return
|
||||||
@ -1243,7 +1247,8 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
|
|||||||
outname=None,
|
outname=None,
|
||||||
spindlespeed=None,
|
spindlespeed=None,
|
||||||
multidepth=None,
|
multidepth=None,
|
||||||
depthperpass=None):
|
depthperpass=None,
|
||||||
|
use_thread=True):
|
||||||
"""
|
"""
|
||||||
Creates a CNCJob out of this Geometry object. The actual
|
Creates a CNCJob out of this Geometry object. The actual
|
||||||
work is done by the target FlatCAMCNCjob object's
|
work is done by the target FlatCAMCNCjob object's
|
||||||
@ -1304,18 +1309,22 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
|
|||||||
|
|
||||||
app_obj.progress.emit(80)
|
app_obj.progress.emit(80)
|
||||||
|
|
||||||
# To be run in separate thread
|
|
||||||
def job_thread(app_obj):
|
|
||||||
with self.app.proc_container.new("Generating CNC Job."):
|
|
||||||
app_obj.new_object("cncjob", outname, job_init)
|
|
||||||
app_obj.inform.emit("CNCjob created: %s" % outname)
|
|
||||||
app_obj.progress.emit(100)
|
|
||||||
|
|
||||||
# Create a promise with the name
|
if use_thread:
|
||||||
self.app.collection.promise(outname)
|
# To be run in separate thread
|
||||||
|
def job_thread(app_obj):
|
||||||
|
with self.app.proc_container.new("Generating CNC Job."):
|
||||||
|
app_obj.new_object("cncjob", outname, job_init)
|
||||||
|
app_obj.inform.emit("CNCjob created: %s" % outname)
|
||||||
|
app_obj.progress.emit(100)
|
||||||
|
|
||||||
# Send to worker
|
# Create a promise with the name
|
||||||
self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
|
self.app.collection.promise(outname)
|
||||||
|
|
||||||
|
# Send to worker
|
||||||
|
self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
|
||||||
|
else:
|
||||||
|
self.app.new_object("cncjob", outname, job_init)
|
||||||
|
|
||||||
def on_plot_cb_click(self, *args): # TODO: args not needed
|
def on_plot_cb_click(self, *args): # TODO: args not needed
|
||||||
if self.muted_ui:
|
if self.muted_ui:
|
||||||
|
@ -1,83 +1,108 @@
|
|||||||
import sys, inspect, pkgutil
|
|
||||||
import re
|
import re
|
||||||
import FlatCAMApp
|
import FlatCAMApp
|
||||||
|
import abc
|
||||||
import collections
|
import collections
|
||||||
|
from PyQt4 import QtCore
|
||||||
|
from contextlib import contextmanager
|
||||||
|
|
||||||
|
|
||||||
class TclCommand(object):
|
class TclCommand(object):
|
||||||
|
|
||||||
app=None
|
# FlatCAMApp
|
||||||
|
app = None
|
||||||
|
|
||||||
|
# logger
|
||||||
|
log = None
|
||||||
|
|
||||||
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||||
aliases = []
|
aliases = []
|
||||||
|
|
||||||
# dictionary of types from Tcl command, needs to be ordered
|
# dictionary of types from Tcl command, needs to be ordered
|
||||||
|
# OrderedDict should be like collections.OrderedDict([(key,value),(key2,value2)])
|
||||||
arg_names = collections.OrderedDict([
|
arg_names = collections.OrderedDict([
|
||||||
('name', str)
|
('name', str)
|
||||||
])
|
])
|
||||||
|
|
||||||
# dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
|
# dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
|
||||||
option_types = collections.OrderedDict([])
|
# OrderedDict should be like collections.OrderedDict([(key,value),(key2,value2)])
|
||||||
|
option_types = collections.OrderedDict()
|
||||||
|
|
||||||
# array of mandatory options for current Tcl command: required = {'name','outname'}
|
# array of mandatory options for current Tcl command: required = {'name','outname'}
|
||||||
required = ['name']
|
required = ['name']
|
||||||
|
|
||||||
# structured help for current command, args needs to be ordered
|
# structured help for current command, args needs to be ordered
|
||||||
|
# OrderedDict should be like collections.OrderedDict([(key,value),(key2,value2)])
|
||||||
help = {
|
help = {
|
||||||
'main': "undefined help.",
|
'main': "undefined help.",
|
||||||
'args': collections.OrderedDict([
|
'args': collections.OrderedDict([
|
||||||
('argumentname', 'undefined help.'),
|
('argumentname', 'undefined help.'),
|
||||||
('optionname', 'undefined help.')
|
('optionname', 'undefined help.')
|
||||||
]),
|
]),
|
||||||
'examples' : []
|
'examples': []
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, app):
|
def __init__(self, app):
|
||||||
self.app=app
|
self.app = app
|
||||||
|
if self.app is None:
|
||||||
|
raise TypeError('Expected app to be FlatCAMApp instance.')
|
||||||
|
if not isinstance(self.app, FlatCAMApp.App):
|
||||||
|
raise TypeError('Expected FlatCAMApp, got %s.' % type(app))
|
||||||
|
self.log = self.app.log
|
||||||
|
|
||||||
|
def raise_tcl_error(self, text):
|
||||||
|
"""
|
||||||
|
this method pass exception from python into TCL as error, so we get stacktrace and reason
|
||||||
|
this is only redirect to self.app.raise_tcl_error
|
||||||
|
:param text: text of error
|
||||||
|
:return: none
|
||||||
|
"""
|
||||||
|
|
||||||
|
self.app.raise_tcl_error(text)
|
||||||
|
|
||||||
def get_decorated_help(self):
|
def get_decorated_help(self):
|
||||||
"""
|
"""
|
||||||
Decorate help for TCL console output.
|
Decorate help for TCL console output.
|
||||||
|
|
||||||
:return: decorated help from structue
|
:return: decorated help from structure
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def get_decorated_command(alias):
|
def get_decorated_command(alias_name):
|
||||||
command_string = []
|
command_string = []
|
||||||
for key, value in self.help['args'].items():
|
for arg_key, arg_type in self.help['args'].items():
|
||||||
command_string.append(get_decorated_argument(key, value, True))
|
command_string.append(get_decorated_argument(arg_key, arg_type, True))
|
||||||
return "> " + alias + " " + " ".join(command_string)
|
return "> " + alias_name + " " + " ".join(command_string)
|
||||||
|
|
||||||
def get_decorated_argument(key, value, in_command=False):
|
def get_decorated_argument(help_key, help_text, in_command=False):
|
||||||
option_symbol = ''
|
option_symbol = ''
|
||||||
if key in self.arg_names:
|
if help_key in self.arg_names:
|
||||||
type=self.arg_names[key]
|
arg_type = self.arg_names[help_key]
|
||||||
type_name=str(type.__name__)
|
type_name = str(arg_type.__name__)
|
||||||
in_command_name = "<" + type_name + ">"
|
in_command_name = "<" + type_name + ">"
|
||||||
elif key in self.option_types:
|
elif help_key in self.option_types:
|
||||||
option_symbol = '-'
|
option_symbol = '-'
|
||||||
type=self.option_types[key]
|
arg_type = self.option_types[help_key]
|
||||||
type_name=str(type.__name__)
|
type_name = str(arg_type.__name__)
|
||||||
in_command_name = option_symbol + key + " <" + type_name + ">"
|
in_command_name = option_symbol + help_key + " <" + type_name + ">"
|
||||||
else:
|
else:
|
||||||
option_symbol = ''
|
option_symbol = ''
|
||||||
type_name='?'
|
type_name = '?'
|
||||||
in_command_name = option_symbol + key + " <" + type_name + ">"
|
in_command_name = option_symbol + help_key + " <" + type_name + ">"
|
||||||
|
|
||||||
if in_command:
|
if in_command:
|
||||||
if key in self.required:
|
if help_key in self.required:
|
||||||
return in_command_name
|
return in_command_name
|
||||||
else:
|
else:
|
||||||
return '[' + in_command_name + "]"
|
return '[' + in_command_name + "]"
|
||||||
else:
|
else:
|
||||||
if key in self.required:
|
if help_key in self.required:
|
||||||
return "\t" + option_symbol + key + " <" + type_name + ">: " + value
|
return "\t" + option_symbol + help_key + " <" + type_name + ">: " + help_text
|
||||||
else:
|
else:
|
||||||
return "\t[" + option_symbol + key + " <" + type_name + ">: " + value+"]"
|
return "\t[" + option_symbol + help_key + " <" + type_name + ">: " + help_text + "]"
|
||||||
|
|
||||||
def get_decorated_example(example):
|
def get_decorated_example(example_item):
|
||||||
return "> "+example
|
return "> "+example_item
|
||||||
|
|
||||||
help_string=[self.help['main']]
|
help_string = [self.help['main']]
|
||||||
for alias in self.aliases:
|
for alias in self.aliases:
|
||||||
help_string.append(get_decorated_command(alias))
|
help_string.append(get_decorated_command(alias))
|
||||||
|
|
||||||
@ -89,12 +114,17 @@ class TclCommand(object):
|
|||||||
|
|
||||||
return "\n".join(help_string)
|
return "\n".join(help_string)
|
||||||
|
|
||||||
def parse_arguments(self, args):
|
@staticmethod
|
||||||
|
def parse_arguments(args):
|
||||||
"""
|
"""
|
||||||
Pre-processes arguments to detect '-keyword value' pairs into dictionary
|
Pre-processes arguments to detect '-keyword value' pairs into dictionary
|
||||||
and standalone parameters into list.
|
and standalone parameters into list.
|
||||||
|
|
||||||
This is copy from FlatCAMApp.setup_shell().h() just for accesibility, original should be removed after all commands will be converted
|
This is copy from FlatCAMApp.setup_shell().h() just for accessibility,
|
||||||
|
original should be removed after all commands will be converted
|
||||||
|
|
||||||
|
:param args: arguments from tcl to parse
|
||||||
|
:return: arguments, options
|
||||||
"""
|
"""
|
||||||
|
|
||||||
options = {}
|
options = {}
|
||||||
@ -121,41 +151,43 @@ class TclCommand(object):
|
|||||||
Check arguments and options for right types
|
Check arguments and options for right types
|
||||||
|
|
||||||
:param args: arguments from tcl to check
|
:param args: arguments from tcl to check
|
||||||
:return:
|
:return: named_args, unnamed_args
|
||||||
"""
|
"""
|
||||||
|
|
||||||
arguments, options = self.parse_arguments(args)
|
arguments, options = self.parse_arguments(args)
|
||||||
|
|
||||||
named_args={}
|
named_args = {}
|
||||||
unnamed_args=[]
|
unnamed_args = []
|
||||||
|
|
||||||
# check arguments
|
# check arguments
|
||||||
idx=0
|
idx = 0
|
||||||
arg_names_items=self.arg_names.items()
|
arg_names_items = self.arg_names.items()
|
||||||
for argument in arguments:
|
for argument in arguments:
|
||||||
if len(self.arg_names) > idx:
|
if len(self.arg_names) > idx:
|
||||||
key, type = arg_names_items[idx]
|
key, arg_type = arg_names_items[idx]
|
||||||
try:
|
try:
|
||||||
named_args[key] = type(argument)
|
named_args[key] = arg_type(argument)
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
self.app.raiseTclError("Cannot cast named argument '%s' to type %s." % (key, type))
|
self.raise_tcl_error("Cannot cast named argument '%s' to type %s with exception '%s'."
|
||||||
|
% (key, arg_type, str(e)))
|
||||||
else:
|
else:
|
||||||
unnamed_args.append(argument)
|
unnamed_args.append(argument)
|
||||||
idx += 1
|
idx += 1
|
||||||
|
|
||||||
# check otions
|
# check options
|
||||||
for key in options:
|
for key in options:
|
||||||
if key not in self.option_types:
|
if key not in self.option_types:
|
||||||
self.app.raiseTclError('Unknown parameter: %s' % key)
|
self.raise_tcl_error('Unknown parameter: %s' % key)
|
||||||
try:
|
try:
|
||||||
named_args[key] = self.option_types[key](options[key])
|
named_args[key] = self.option_types[key](options[key])
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
self.app.raiseTclError("Cannot cast argument '-%s' to type %s." % (key, self.option_types[key]))
|
self.raise_tcl_error("Cannot cast argument '-%s' to type '%s' with exception '%s'."
|
||||||
|
% (key, self.option_types[key], str(e)))
|
||||||
|
|
||||||
# check required arguments
|
# check required arguments
|
||||||
for key in self.required:
|
for key in self.required:
|
||||||
if key not in named_args:
|
if key not in named_args:
|
||||||
self.app.raiseTclError("Missing required argument '%s'." % (key))
|
self.raise_tcl_error("Missing required argument '%s'." % key)
|
||||||
|
|
||||||
return named_args, unnamed_args
|
return named_args, unnamed_args
|
||||||
|
|
||||||
@ -168,12 +200,16 @@ class TclCommand(object):
|
|||||||
:param args: arguments passed from tcl command console
|
:param args: arguments passed from tcl command console
|
||||||
:return: None, output text or exception
|
:return: None, output text or exception
|
||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
self.log.debug("TCL command '%s' executed." % str(self.__class__))
|
||||||
args, unnamed_args = self.check_args(args)
|
args, unnamed_args = self.check_args(args)
|
||||||
return self.execute(args, unnamed_args)
|
return self.execute(args, unnamed_args)
|
||||||
except Exception as unknown:
|
except Exception as unknown:
|
||||||
self.app.raiseTclUnknownError(unknown)
|
self.log.error("TCL command '%s' failed." % str(self))
|
||||||
|
self.app.raise_tcl_unknown_error(unknown)
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
def execute(self, args, unnamed_args):
|
def execute(self, args, unnamed_args):
|
||||||
"""
|
"""
|
||||||
Direct execute of command, this method should be implemented in each descendant.
|
Direct execute of command, this method should be implemented in each descendant.
|
||||||
@ -186,3 +222,73 @@ class TclCommand(object):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
raise NotImplementedError("Please Implement this method")
|
raise NotImplementedError("Please Implement this method")
|
||||||
|
|
||||||
|
|
||||||
|
class TclCommandSignaled(TclCommand):
|
||||||
|
"""
|
||||||
|
!!! I left it here only for demonstration !!!
|
||||||
|
Go to TclCommandCncjob and into class definition put
|
||||||
|
class TclCommandCncjob(TclCommand.TclCommandSignaled):
|
||||||
|
also change
|
||||||
|
obj.generatecncjob(use_thread = False, **args)
|
||||||
|
to
|
||||||
|
obj.generatecncjob(use_thread = True, **args)
|
||||||
|
|
||||||
|
|
||||||
|
This class is child of TclCommand and is used for commands which create new objects
|
||||||
|
it handles all neccessary stuff about blocking and passing exeptions
|
||||||
|
"""
|
||||||
|
|
||||||
|
# default timeout for operation is 30 sec, but it can be much more
|
||||||
|
default_timeout = 30000
|
||||||
|
|
||||||
|
|
||||||
|
def execute_wrapper(self, *args):
|
||||||
|
"""
|
||||||
|
Command which is called by tcl console when current commands aliases are hit.
|
||||||
|
Main catch(except) is implemented here.
|
||||||
|
This method should be reimplemented only when initial checking sequence differs
|
||||||
|
|
||||||
|
:param args: arguments passed from tcl command console
|
||||||
|
:return: None, output text or exception
|
||||||
|
"""
|
||||||
|
|
||||||
|
@contextmanager
|
||||||
|
def wait_signal(signal, timeout=30000):
|
||||||
|
"""Block loop until signal emitted, or timeout (ms) elapses."""
|
||||||
|
loop = QtCore.QEventLoop()
|
||||||
|
signal.connect(loop.quit)
|
||||||
|
|
||||||
|
status = {'timed_out': False}
|
||||||
|
|
||||||
|
def report_quit():
|
||||||
|
status['timed_out'] = True
|
||||||
|
loop.quit()
|
||||||
|
|
||||||
|
yield
|
||||||
|
|
||||||
|
if timeout is not None:
|
||||||
|
QtCore.QTimer.singleShot(timeout, report_quit)
|
||||||
|
|
||||||
|
loop.exec_()
|
||||||
|
|
||||||
|
if status['timed_out']:
|
||||||
|
self.app.raise_tcl_unknown_error('Operation timed out!')
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.log.debug("TCL command '%s' executed." % str(self.__class__))
|
||||||
|
args, unnamed_args = self.check_args(args)
|
||||||
|
if 'timeout' in args:
|
||||||
|
passed_timeout=args['timeout']
|
||||||
|
del args['timeout']
|
||||||
|
else:
|
||||||
|
passed_timeout=self.default_timeout
|
||||||
|
with wait_signal(self.app.new_object_available, passed_timeout):
|
||||||
|
# every TclCommandNewObject ancestor support timeout as parameter,
|
||||||
|
# but it does not mean anything for child itself
|
||||||
|
# when operation will be really long is good to set it higher then defqault 30s
|
||||||
|
return self.execute(args, unnamed_args)
|
||||||
|
|
||||||
|
except Exception as unknown:
|
||||||
|
self.log.error("TCL command '%s' failed." % str(self))
|
||||||
|
self.app.raise_tcl_unknown_error(unknown)
|
@ -8,7 +8,7 @@ class TclCommandAddPolygon(TclCommand.TclCommand):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||||
aliases = ['add_polygon','add_poly']
|
aliases = ['add_polygon', 'add_poly']
|
||||||
|
|
||||||
# dictionary of types from Tcl command, needs to be ordered
|
# dictionary of types from Tcl command, needs to be ordered
|
||||||
arg_names = collections.OrderedDict([
|
arg_names = collections.OrderedDict([
|
||||||
@ -16,7 +16,7 @@ class TclCommandAddPolygon(TclCommand.TclCommand):
|
|||||||
])
|
])
|
||||||
|
|
||||||
# dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
|
# dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
|
||||||
option_types = collections.OrderedDict([])
|
option_types = collections.OrderedDict()
|
||||||
|
|
||||||
# array of mandatory options for current Tcl command: required = {'name','outname'}
|
# array of mandatory options for current Tcl command: required = {'name','outname'}
|
||||||
required = ['name']
|
required = ['name']
|
||||||
@ -28,7 +28,7 @@ class TclCommandAddPolygon(TclCommand.TclCommand):
|
|||||||
('name', 'Name of the Geometry object to which to append the polygon.'),
|
('name', 'Name of the Geometry object to which to append the polygon.'),
|
||||||
('xi, yi', 'Coordinates of points in the polygon.')
|
('xi, yi', 'Coordinates of points in the polygon.')
|
||||||
]),
|
]),
|
||||||
'examples':[
|
'examples': [
|
||||||
'add_polygon <name> <x0> <y0> <x1> <y1> <x2> <y2> [x3 y3 [...]]'
|
'add_polygon <name> <x0> <y0> <x1> <y1> <x2> <y2> [x3 y3 [...]]'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -45,21 +45,17 @@ class TclCommandAddPolygon(TclCommand.TclCommand):
|
|||||||
|
|
||||||
name = args['name']
|
name = args['name']
|
||||||
|
|
||||||
try:
|
obj = self.app.collection.get_by_name(name)
|
||||||
obj = self.app.collection.get_by_name(name)
|
|
||||||
except:
|
|
||||||
self.app.raiseTclError("Could not retrieve object: %s" % name)
|
|
||||||
|
|
||||||
if obj is None:
|
if obj is None:
|
||||||
self.app.raiseTclError("Object not found: %s" % name)
|
self.raise_tcl_error("Object not found: %s" % name)
|
||||||
|
|
||||||
if not isinstance(obj, Geometry):
|
if not isinstance(obj, Geometry):
|
||||||
self.app.raiseTclError('Expected Geometry, got %s %s.' % (name, type(obj)))
|
self.raise_tcl_error('Expected Geometry, got %s %s.' % (name, type(obj)))
|
||||||
|
|
||||||
if len(unnamed_args) % 2 != 0:
|
if len(unnamed_args) % 2 != 0:
|
||||||
self.app.raiseTclError("Incomplete coordinates.")
|
self.raise_tcl_error("Incomplete coordinates.")
|
||||||
|
|
||||||
points = [[float(unnamed_args[2*i]), float(unnamed_args[2*i+1])] for i in range(len(unnamed_args)/2)]
|
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.add_polygon(points)
|
||||||
obj.plot()
|
obj.plot()
|
||||||
|
@ -16,7 +16,7 @@ class TclCommandAddPolyline(TclCommand.TclCommand):
|
|||||||
])
|
])
|
||||||
|
|
||||||
# dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
|
# dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
|
||||||
option_types = collections.OrderedDict([])
|
option_types = collections.OrderedDict()
|
||||||
|
|
||||||
# array of mandatory options for current Tcl command: required = {'name','outname'}
|
# array of mandatory options for current Tcl command: required = {'name','outname'}
|
||||||
required = ['name']
|
required = ['name']
|
||||||
@ -28,7 +28,7 @@ class TclCommandAddPolyline(TclCommand.TclCommand):
|
|||||||
('name', 'Name of the Geometry object to which to append the polyline.'),
|
('name', 'Name of the Geometry object to which to append the polyline.'),
|
||||||
('xi, yi', 'Coordinates of points in the polyline.')
|
('xi, yi', 'Coordinates of points in the polyline.')
|
||||||
]),
|
]),
|
||||||
'examples':[
|
'examples': [
|
||||||
'add_polyline <name> <x0> <y0> <x1> <y1> <x2> <y2> [x3 y3 [...]]'
|
'add_polyline <name> <x0> <y0> <x1> <y1> <x2> <y2> [x3 y3 [...]]'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -45,21 +45,17 @@ class TclCommandAddPolyline(TclCommand.TclCommand):
|
|||||||
|
|
||||||
name = args['name']
|
name = args['name']
|
||||||
|
|
||||||
try:
|
obj = self.app.collection.get_by_name(name)
|
||||||
obj = self.app.collection.get_by_name(name)
|
|
||||||
except:
|
|
||||||
self.app.raiseTclError("Could not retrieve object: %s" % name)
|
|
||||||
|
|
||||||
if obj is None:
|
if obj is None:
|
||||||
self.app.raiseTclError("Object not found: %s" % name)
|
self.raise_tcl_error("Object not found: %s" % name)
|
||||||
|
|
||||||
if not isinstance(obj, Geometry):
|
if not isinstance(obj, Geometry):
|
||||||
self.app.raiseTclError('Expected Geometry, got %s %s.' % (name, type(obj)))
|
self.raise_tcl_error('Expected Geometry, got %s %s.' % (name, type(obj)))
|
||||||
|
|
||||||
if len(unnamed_args) % 2 != 0:
|
if len(unnamed_args) % 2 != 0:
|
||||||
self.app.raiseTclError("Incomplete coordinates.")
|
self.raise_tcl_error("Incomplete coordinates.")
|
||||||
|
|
||||||
points = [[float(unnamed_args[2*i]), float(unnamed_args[2*i+1])] for i in range(len(unnamed_args)/2)]
|
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.add_polyline(points)
|
||||||
obj.plot()
|
obj.plot()
|
||||||
|
86
tclCommands/TclCommandCncjob.py
Normal file
86
tclCommands/TclCommandCncjob.py
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
from ObjectCollection import *
|
||||||
|
import TclCommand
|
||||||
|
|
||||||
|
|
||||||
|
class TclCommandCncjob(TclCommand.TclCommand):
|
||||||
|
"""
|
||||||
|
Tcl shell command to Generates a CNC Job from a Geometry Object.
|
||||||
|
|
||||||
|
example:
|
||||||
|
set_sys units MM
|
||||||
|
new
|
||||||
|
open_gerber tests/gerber_files/simple1.gbr -outname margin
|
||||||
|
isolate margin -dia 3
|
||||||
|
cncjob margin_iso
|
||||||
|
"""
|
||||||
|
|
||||||
|
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||||
|
aliases = ['cncjob']
|
||||||
|
|
||||||
|
# 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([
|
||||||
|
('z_cut',float),
|
||||||
|
('z_move',float),
|
||||||
|
('feedrate',float),
|
||||||
|
('tooldia',float),
|
||||||
|
('spindlespeed',int),
|
||||||
|
('multidepth',bool),
|
||||||
|
('depthperpass',float),
|
||||||
|
('outname',str)
|
||||||
|
])
|
||||||
|
|
||||||
|
# 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': "Generates a CNC Job from a Geometry Object.",
|
||||||
|
'args': collections.OrderedDict([
|
||||||
|
('name', 'Name of the source object.'),
|
||||||
|
('z_cut', 'Z-axis cutting position.'),
|
||||||
|
('z_move', 'Z-axis moving position.'),
|
||||||
|
('feedrate', 'Moving speed when cutting.'),
|
||||||
|
('tooldia', 'Tool diameter to show on screen.'),
|
||||||
|
('spindlespeed', 'Speed of the spindle in rpm (example: 4000).'),
|
||||||
|
('multidepth', 'Use or not multidepth cnccut.'),
|
||||||
|
('depthperpass', 'Height of one layer for multidepth.'),
|
||||||
|
('outname', 'Name of the resulting Geometry object.'),
|
||||||
|
('timeout', 'Max wait for job timeout before error.')
|
||||||
|
]),
|
||||||
|
'examples': []
|
||||||
|
}
|
||||||
|
|
||||||
|
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']
|
||||||
|
|
||||||
|
if 'outname' not in args:
|
||||||
|
args['outname'] = name + "_cnc"
|
||||||
|
|
||||||
|
if 'timeout' in args:
|
||||||
|
timeout = args['timeout']
|
||||||
|
else:
|
||||||
|
timeout = 10000
|
||||||
|
|
||||||
|
obj = self.app.collection.get_by_name(name)
|
||||||
|
if obj is None:
|
||||||
|
self.raise_tcl_error("Object not found: %s" % name)
|
||||||
|
|
||||||
|
if not isinstance(obj, FlatCAMGeometry):
|
||||||
|
self.raise_tcl_error('Expected FlatCAMGeometry, got %s %s.' % (name, type(obj)))
|
||||||
|
|
||||||
|
del args['name']
|
||||||
|
obj.generatecncjob(use_thread = False, **args)
|
79
tclCommands/TclCommandExportGcode.py
Normal file
79
tclCommands/TclCommandExportGcode.py
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
from ObjectCollection import *
|
||||||
|
import TclCommand
|
||||||
|
|
||||||
|
|
||||||
|
class TclCommandExportGcode(TclCommand.TclCommand):
|
||||||
|
"""
|
||||||
|
Tcl shell command to export gcode as tcl output for "set X [export_gcode ...]"
|
||||||
|
|
||||||
|
Requires name to be available. It might still be in the
|
||||||
|
making at the time this function is called, so check for
|
||||||
|
promises and send to background if there are promises.
|
||||||
|
|
||||||
|
|
||||||
|
this export may be catched by tcl and past as preable to another export_gcode or write_gcode
|
||||||
|
this can be used to join GCODES
|
||||||
|
|
||||||
|
example:
|
||||||
|
set_sys units MM
|
||||||
|
new
|
||||||
|
open_gerber tests/gerber_files/simple1.gbr -outname margin
|
||||||
|
isolate margin -dia 3
|
||||||
|
cncjob margin_iso
|
||||||
|
cncjob margin_iso
|
||||||
|
set EXPORT [export_gcode margin_iso_cnc]
|
||||||
|
write_gcode margin_iso_cnc_1 /tmp/file.gcode ${EXPORT}
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||||
|
aliases = ['export_gcode']
|
||||||
|
|
||||||
|
# dictionary of types from Tcl command, needs to be ordered
|
||||||
|
arg_names = collections.OrderedDict([
|
||||||
|
('name', str),
|
||||||
|
('preamble', str),
|
||||||
|
('postamble', 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': "Export gcode into console output.",
|
||||||
|
'args': collections.OrderedDict([
|
||||||
|
('name', 'Name of the source Geometry object.'),
|
||||||
|
('preamble', 'Prepend GCODE.'),
|
||||||
|
('postamble', 'Append GCODE.')
|
||||||
|
]),
|
||||||
|
'examples': []
|
||||||
|
}
|
||||||
|
|
||||||
|
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']
|
||||||
|
|
||||||
|
obj = self.app.collection.get_by_name(name)
|
||||||
|
if obj is None:
|
||||||
|
self.raise_tcl_error("Object not found: %s" % name)
|
||||||
|
|
||||||
|
if not isinstance(obj, CNCjob):
|
||||||
|
self.raise_tcl_error('Expected CNCjob, got %s %s.' % (name, type(obj)))
|
||||||
|
|
||||||
|
if self.app.collection.has_promises():
|
||||||
|
self.raise_tcl_error('!!!Promises exists, but should not here!!!')
|
||||||
|
|
||||||
|
del args['name']
|
||||||
|
return obj.get_gcode(**args)
|
@ -8,7 +8,7 @@ class TclCommandExteriors(TclCommand.TclCommand):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||||
aliases = ['exteriors','ext']
|
aliases = ['exteriors', 'ext']
|
||||||
|
|
||||||
# dictionary of types from Tcl command, needs to be ordered
|
# dictionary of types from Tcl command, needs to be ordered
|
||||||
arg_names = collections.OrderedDict([
|
arg_names = collections.OrderedDict([
|
||||||
@ -30,7 +30,7 @@ class TclCommandExteriors(TclCommand.TclCommand):
|
|||||||
('name', 'Name of the source Geometry object.'),
|
('name', 'Name of the source Geometry object.'),
|
||||||
('outname', 'Name of the resulting Geometry object.')
|
('outname', 'Name of the resulting Geometry object.')
|
||||||
]),
|
]),
|
||||||
'examples':[]
|
'examples': []
|
||||||
}
|
}
|
||||||
|
|
||||||
def execute(self, args, unnamed_args):
|
def execute(self, args, unnamed_args):
|
||||||
@ -50,19 +50,15 @@ class TclCommandExteriors(TclCommand.TclCommand):
|
|||||||
else:
|
else:
|
||||||
outname = name + "_exteriors"
|
outname = name + "_exteriors"
|
||||||
|
|
||||||
try:
|
obj = self.app.collection.get_by_name(name)
|
||||||
obj = self.app.collection.get_by_name(name)
|
|
||||||
except:
|
|
||||||
self.app.raiseTclError("Could not retrieve object: %s" % name)
|
|
||||||
|
|
||||||
if obj is None:
|
if obj is None:
|
||||||
self.app.raiseTclError("Object not found: %s" % name)
|
self.raise_tcl_error("Object not found: %s" % name)
|
||||||
|
|
||||||
if not isinstance(obj, Geometry):
|
if not isinstance(obj, Geometry):
|
||||||
self.app.raiseTclError('Expected Geometry, got %s %s.' % (name, type(obj)))
|
self.raise_tcl_error('Expected Geometry, got %s %s.' % (name, type(obj)))
|
||||||
|
|
||||||
def geo_init(geo_obj, app_obj):
|
def geo_init(geo_obj):
|
||||||
geo_obj.solid_geometry = obj_exteriors
|
geo_obj.solid_geometry = obj_exteriors
|
||||||
|
|
||||||
obj_exteriors = obj.get_exteriors()
|
obj_exteriors = obj.get_exteriors()
|
||||||
self.app.new_object('geometry', outname, geo_init)
|
self.app.new_object('geometry', outname, geo_init)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
from ObjectCollection import *
|
from ObjectCollection import *
|
||||||
import TclCommand
|
import TclCommand
|
||||||
|
|
||||||
|
|
||||||
class TclCommandInteriors(TclCommand.TclCommand):
|
class TclCommandInteriors(TclCommand.TclCommand):
|
||||||
"""
|
"""
|
||||||
Tcl shell command to get interiors of polygons
|
Tcl shell command to get interiors of polygons
|
||||||
@ -29,7 +30,7 @@ class TclCommandInteriors(TclCommand.TclCommand):
|
|||||||
('name', 'Name of the source Geometry object.'),
|
('name', 'Name of the source Geometry object.'),
|
||||||
('outname', 'Name of the resulting Geometry object.')
|
('outname', 'Name of the resulting Geometry object.')
|
||||||
]),
|
]),
|
||||||
'examples':[]
|
'examples': []
|
||||||
}
|
}
|
||||||
|
|
||||||
def execute(self, args, unnamed_args):
|
def execute(self, args, unnamed_args):
|
||||||
@ -49,19 +50,15 @@ class TclCommandInteriors(TclCommand.TclCommand):
|
|||||||
else:
|
else:
|
||||||
outname = name + "_interiors"
|
outname = name + "_interiors"
|
||||||
|
|
||||||
try:
|
obj = self.app.collection.get_by_name(name)
|
||||||
obj = self.app.collection.get_by_name(name)
|
|
||||||
except:
|
|
||||||
self.app.raiseTclError("Could not retrieve object: %s" % name)
|
|
||||||
|
|
||||||
if obj is None:
|
if obj is None:
|
||||||
self.app.raiseTclError("Object not found: %s" % name)
|
self.raise_tcl_error("Object not found: %s" % name)
|
||||||
|
|
||||||
if not isinstance(obj, Geometry):
|
if not isinstance(obj, Geometry):
|
||||||
self.app.raiseTclError('Expected Geometry, got %s %s.' % (name, type(obj)))
|
self.raise_tcl_error('Expected Geometry, got %s %s.' % (name, type(obj)))
|
||||||
|
|
||||||
def geo_init(geo_obj, app_obj):
|
def geo_init(geo_obj):
|
||||||
geo_obj.solid_geometry = obj_exteriors
|
geo_obj.solid_geometry = obj_exteriors
|
||||||
|
|
||||||
obj_exteriors = obj.get_interiors()
|
obj_exteriors = obj.get_interiors()
|
||||||
self.app.new_object('geometry', outname, geo_init)
|
self.app.new_object('geometry', outname, geo_init)
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import pkgutil
|
import pkgutil
|
||||||
import inspect
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
# allowed command modules
|
# allowed command modules
|
||||||
@ -7,9 +6,10 @@ import tclCommands.TclCommandExteriors
|
|||||||
import tclCommands.TclCommandInteriors
|
import tclCommands.TclCommandInteriors
|
||||||
import tclCommands.TclCommandAddPolygon
|
import tclCommands.TclCommandAddPolygon
|
||||||
import tclCommands.TclCommandAddPolyline
|
import tclCommands.TclCommandAddPolyline
|
||||||
|
import tclCommands.TclCommandExportGcode
|
||||||
|
import tclCommands.TclCommandCncjob
|
||||||
|
|
||||||
|
__all__ = []
|
||||||
__all__=[]
|
|
||||||
|
|
||||||
for loader, name, is_pkg in pkgutil.walk_packages(__path__):
|
for loader, name, is_pkg in pkgutil.walk_packages(__path__):
|
||||||
module = loader.find_module(name).load_module(name)
|
module = loader.find_module(name).load_module(name)
|
||||||
@ -25,8 +25,8 @@ def register_all_commands(app, commands):
|
|||||||
|
|
||||||
we need import all modules in top section:
|
we need import all modules in top section:
|
||||||
import tclCommands.TclCommandExteriors
|
import tclCommands.TclCommandExteriors
|
||||||
at this stage we can include only wanted commands with this, autoloading may be implemented in future
|
at this stage we can include only wanted commands with this, auto loading may be implemented in future
|
||||||
I have no enought knowledge about python's anatomy. Would be nice to include all classes which are descendant etc.
|
I have no enough knowledge about python's anatomy. Would be nice to include all classes which are descendant etc.
|
||||||
|
|
||||||
:param app: FlatCAMApp
|
:param app: FlatCAMApp
|
||||||
:param commands: array of commands which should be modified
|
:param commands: array of commands which should be modified
|
||||||
@ -35,14 +35,14 @@ def register_all_commands(app, commands):
|
|||||||
|
|
||||||
tcl_modules = {k: v for k, v in sys.modules.items() if k.startswith('tclCommands.TclCommand')}
|
tcl_modules = {k: v for k, v in sys.modules.items() if k.startswith('tclCommands.TclCommand')}
|
||||||
|
|
||||||
for key, module in tcl_modules.items():
|
for key, mod in tcl_modules.items():
|
||||||
if key != 'tclCommands.TclCommand':
|
if key != 'tclCommands.TclCommand':
|
||||||
classname = key.split('.')[1]
|
class_name = key.split('.')[1]
|
||||||
class_ = getattr(module, classname)
|
class_type = getattr(mod, class_name)
|
||||||
commandInstance=class_(app)
|
command_instance = class_type(app)
|
||||||
|
|
||||||
for alias in commandInstance.aliases:
|
for alias in command_instance.aliases:
|
||||||
commands[alias]={
|
commands[alias] = {
|
||||||
'fcn': commandInstance.execute_wrapper,
|
'fcn': command_instance.execute_wrapper,
|
||||||
'help': commandInstance.get_decorated_help()
|
'help': command_instance.get_decorated_help()
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user