-clean-up before merge

This commit is contained in:
Marius Stanciu
2019-01-03 21:25:08 +02:00
committed by Marius S
parent 421e9766ea
commit e48d2d2f49
266 changed files with 42425 additions and 0 deletions

431
tclCommands/TclCommand.py Normal file
View File

@@ -0,0 +1,431 @@
import sys
import re
import FlatCAMApp
import abc
import collections
from PyQt5 import QtCore, QtGui
from PyQt5.QtCore import Qt
from contextlib import contextmanager
class TclCommand(object):
# FlatCAMApp
app = None
# Logger
log = None
# List of all command aliases, to be able use old names
# for backward compatibility (add_poly, add_polygon)
aliases = []
# Dictionary of types from Tcl command, needs to be ordered
# OrderedDict should be like collections.OrderedDict([(key,value),(key2,value2)])
arg_names = collections.OrderedDict([
('name', str)
])
# dictionary of types from Tcl command, needs to be ordered.
# This is for options like -optionname value.
# OrderedDict should be like collections.OrderedDict([(key,value),(key2,value2)])
option_types = collections.OrderedDict()
# List of mandatory options for current Tcl command: required = {'name','outname'}
required = ['name']
# Structured help for current command, args needs to be ordered
# OrderedDict should be like collections.OrderedDict([(key,value),(key2,value2)])
help = {
'main': "undefined help.",
'args': collections.OrderedDict([
('argumentname', 'undefined help.'),
('optionname', 'undefined help.')
]),
'examples': []
}
# Original incoming arguments into command
original_args = None
def __init__(self, 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_current_command(self):
"""
Get current command, we are not able to get it from TCL we have to reconstruct it.
:return: current command
"""
command_string = []
command_string.append(self.aliases[0])
if self.original_args is not None:
for arg in self.original_args:
command_string.append(arg)
return " ".join(command_string)
def get_decorated_help(self):
"""
Decorate help for TCL console output.
:return: decorated help from structure
"""
def get_decorated_command(alias_name):
command_string = []
for arg_key, arg_type in list(self.help['args'].items()):
command_string.append(get_decorated_argument(arg_key, arg_type, True))
return "> " + alias_name + " " + " ".join(command_string)
def get_decorated_argument(help_key, help_text, in_command=False):
"""
:param help_key: Name of the argument.
:param help_text:
:param in_command:
:return:
"""
option_symbol = ''
if help_key in self.arg_names:
arg_type = self.arg_names[help_key]
type_name = str(arg_type.__name__)
#in_command_name = help_key + "<" + type_name + ">"
in_command_name = help_key
elif help_key in self.option_types:
option_symbol = '-'
arg_type = self.option_types[help_key]
type_name = str(arg_type.__name__)
in_command_name = option_symbol + help_key + " <" + type_name + ">"
else:
option_symbol = ''
type_name = '?'
in_command_name = option_symbol + help_key + " <" + type_name + ">"
if in_command:
if help_key in self.required:
return in_command_name
else:
return '[' + in_command_name + "]"
else:
if help_key in self.required:
return "\t" + option_symbol + help_key + " <" + type_name + ">: " + help_text
else:
return "\t[" + option_symbol + help_key + " <" + type_name + ">: " + help_text + "]"
def get_decorated_example(example_item):
return "> " + example_item
help_string = [self.help['main']]
for alias in self.aliases:
help_string.append(get_decorated_command(alias))
for key, value in list(self.help['args'].items()):
help_string.append(get_decorated_argument(key, value))
# timeout is unique for signaled commands (this is not best oop practice, but much easier for now)
if isinstance(self, TclCommandSignaled):
help_string.append("\t[-timeout <int>: Max wait for job timeout before error.]")
for example in self.help['examples']:
help_string.append(get_decorated_example(example))
return "\n".join(help_string)
@staticmethod
def parse_arguments(args):
"""
Pre-processes arguments to detect '-keyword value' pairs into dictionary
and standalone parameters into list.
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 = {}
arguments = []
n = len(args)
name = None
for i in range(n):
match = re.search(r'^-([a-zA-Z].*)', args[i])
if match:
assert name is None
name = match.group(1)
continue
if name is None:
arguments.append(args[i])
else:
options[name] = args[i]
name = None
return arguments, options
def check_args(self, args):
"""
Check arguments and options for right types
:param args: arguments from tcl to check
:return: named_args, unnamed_args
"""
arguments, options = self.parse_arguments(args)
named_args = {}
unnamed_args = []
# check arguments
idx = 0
arg_names_items = list(self.arg_names.items())
for argument in arguments:
if len(self.arg_names) > idx:
key, arg_type = arg_names_items[idx]
try:
named_args[key] = arg_type(argument)
except Exception as e:
self.raise_tcl_error("Cannot cast named argument '%s' to type %s with exception '%s'."
% (key, arg_type, str(e)))
else:
unnamed_args.append(argument)
idx += 1
# check options
for key in options:
if key not in self.option_types and key != 'timeout':
self.raise_tcl_error('Unknown parameter: %s' % key)
try:
if key != 'timeout':
named_args[key] = self.option_types[key](options[key])
else:
named_args[key] = int(options[key])
except Exception as e:
self.raise_tcl_error("Cannot cast argument '-%s' to type '%s' with exception '%s'."
% (key, self.option_types[key], str(e)))
# check required arguments
for key in self.required:
if key not in named_args:
self.raise_tcl_error("Missing required argument '%s'." % key)
return named_args, unnamed_args
def raise_tcl_unknown_error(self, unknown_exception):
"""
raise Exception if is different type than TclErrorException
this is here mainly to show unknown errors inside TCL shell console
:param unknown_exception:
:return:
"""
raise unknown_exception
def raise_tcl_error(self, text):
"""
this method pass exception from python into TCL as error, so we get stacktrace and reason
:param text: text of error
:return: raise exception
"""
# becouse of signaling we cannot call error to TCL from here but when task
# is finished also nonsignaled are handled here to better exception
# handling and displayed after command is finished
raise self.app.TclErrorException(text)
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
"""
#self.worker_task.emit({'fcn': self.exec_command_test, 'params': [text, False]})
try:
self.log.debug("TCL command '%s' executed." % str(self.__class__))
self.original_args = args
args, unnamed_args = self.check_args(args)
return self.execute(args, unnamed_args)
except Exception as unknown:
error_info = sys.exc_info()
self.log.error("TCL command '%s' failed." % str(self))
self.app.display_tcl_error(unknown, error_info)
self.raise_tcl_unknown_error(unknown)
@abc.abstractmethod
def execute(self, args, unnamed_args):
"""
Direct execute of command, this method should be implemented in each descendant.
No main catch should be implemented here.
: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, output text or exception
"""
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(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
"""
@abc.abstractmethod
def execute(self, args, unnamed_args):
raise NotImplementedError("Please Implement this method")
output = None
def execute_call(self, args, unnamed_args):
try:
self.output = None
self.error = None
self.error_info = None
self.output = self.execute(args, unnamed_args)
except Exception as unknown:
self.error_info = sys.exc_info()
self.error = unknown
finally:
self.app.shell_command_finished.emit(self)
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=300000):
"""Block loop until signal emitted, or timeout (ms) elapses."""
loop = QtCore.QEventLoop()
# Normal termination
signal.connect(loop.quit)
# Termination by exception in thread
self.app.thread_exception.connect(loop.quit)
status = {'timed_out': False}
def report_quit():
status['timed_out'] = True
loop.quit()
yield
# Temporarily change how exceptions are managed.
oeh = sys.excepthook
ex = []
def except_hook(type_, value, traceback_):
ex.append(value)
oeh(type_, value, traceback_)
sys.excepthook = except_hook
# Terminate on timeout
if timeout is not None:
QtCore.QTimer.singleShot(timeout, report_quit)
# Block
loop.exec_()
# Restore exception management
sys.excepthook = oeh
if ex:
raise ex[0]
if status['timed_out']:
self.app.raise_tcl_unknown_error("Operation timed outed! Consider increasing option "
"'-timeout <miliseconds>' for command or "
"'set_sys global_background_timeout <miliseconds>'.")
try:
self.log.debug("TCL command '%s' executed." % str(self.__class__))
self.original_args = args
args, unnamed_args = self.check_args(args)
if 'timeout' in args:
passed_timeout = args['timeout']
del args['timeout']
else:
passed_timeout = self.app.defaults['global_background_timeout']
# set detail for processing, it will be there until next open or close
self.app.shell.open_proccessing(self.get_current_command())
def handle_finished(obj):
self.app.shell_command_finished.disconnect(handle_finished)
if self.error is not None:
self.raise_tcl_unknown_error(self.error)
self.app.shell_command_finished.connect(handle_finished)
with wait_signal(self.app.shell_command_finished, 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
self.app.worker_task.emit({'fcn': self.execute_call, 'params': [args, unnamed_args]})
return self.output
except Exception as unknown:
# if error happens inside thread execution, then pass correct error_info to display
if self.error_info is not None:
error_info = self.error_info
else:
error_info = sys.exc_info()
self.log.error("TCL command '%s' failed." % str(self))
self.app.display_tcl_error(unknown, error_info)
self.raise_tcl_unknown_error(unknown)

View File

@@ -0,0 +1,65 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommand
class TclCommandAddCircle(TclCommand):
"""
Tcl shell command to creates a circle in the given Geometry object.
example:
"""
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['add_circle']
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str),
('center_x', float),
('center_y', float),
('radius', float)
])
# 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', 'center_x', 'center_y', 'radius']
# structured help for current command, args needs to be ordered
help = {
'main': "Creates a circle in the given Geometry object.",
'args': collections.OrderedDict([
('name', 'Name of the geometry object to which to append the circle.'),
('center_x', 'X coordinate of the center of the circle.'),
('center_y', 'Y coordinates of the center of the circle.'),
('radius', 'Radius of the circle.')
]),
'examples': []
}
def execute(self, args, unnamed_args):
"""
:param args:
:param unnamed_args:
:return:
"""
obj_name = args['name']
center_x = args['center_x']
center_y = args['center_y']
radius = args['radius']
try:
obj = self.app.collection.get_by_name(str(obj_name))
except:
return "Could not retrieve object: %s" % obj_name
if obj is None:
return "Object not found: %s" % obj_name
obj.add_circle([float(center_x), float(center_y)], float(radius))

View File

@@ -0,0 +1,61 @@
from ObjectCollection import *
from tclCommands.TclCommand import *
class TclCommandAddPolygon(TclCommandSignaled):
"""
Tcl shell command to create a polygon in the given Geometry object
"""
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['add_polygon', 'add_poly']
# dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str)
])
# dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
option_types = collections.OrderedDict()
# array of mandatory options for current Tcl command: required = {'name','outname'}
required = ['name']
# structured help for current command, args needs to be ordered
help = {
'main': "Creates a polygon in the given Geometry object.",
'args': collections.OrderedDict([
('name', 'Name of the Geometry object to which to append the polygon.'),
('xi, yi', 'Coordinates of points in the polygon.')
]),
'examples': [
'add_polygon <name> <x0> <y0> <x1> <y1> <x2> <y2> [x3 y3 [...]]'
]
}
def execute(self, args, unnamed_args):
"""
execute current TCL shell command
:param args: array of known named arguments and options
:param unnamed_args: array of other values which were passed into command
without -somename and we do not have them in known arg_names
:return: None or exception
"""
name = args['name']
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, Geometry):
self.raise_tcl_error('Expected Geometry, got %s %s.' % (name, type(obj)))
if len(unnamed_args) % 2 != 0:
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)]
obj.add_polygon(points)
obj.plot()

View File

@@ -0,0 +1,61 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommandSignaled
class TclCommandAddPolyline(TclCommandSignaled):
"""
Tcl shell command to create a polyline in the given Geometry object
"""
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['add_polyline']
# dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str)
])
# dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
option_types = collections.OrderedDict()
# array of mandatory options for current Tcl command: required = {'name','outname'}
required = ['name']
# structured help for current command, args needs to be ordered
help = {
'main': "Creates a polyline in the given Geometry object.",
'args': collections.OrderedDict([
('name', 'Name of the Geometry object to which to append the polyline.'),
('xi, yi', 'Coordinates of points in the polyline.')
]),
'examples': [
'add_polyline <name> <x0> <y0> <x1> <y1> <x2> <y2> [x3 y3 [...]]'
]
}
def execute(self, args, unnamed_args):
"""
execute current TCL shell command
:param args: array of known named arguments and options
:param unnamed_args: array of other values which were passed into command
without -somename and we do not have them in known arg_names
:return: None or exception
"""
name = args['name']
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, Geometry):
self.raise_tcl_error('Expected Geometry, got %s %s.' % (name, type(obj)))
if len(unnamed_args) % 2 != 0:
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)]
obj.add_polyline(points)
obj.plot()

View File

@@ -0,0 +1,66 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommandSignaled
class TclCommandAddRectangle(TclCommandSignaled):
"""
Tcl shell command to add a rectange to the given Geometry object.
"""
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['add_rectangle']
# Dictionary of types from Tcl command, needs to be ordered.
# For positional arguments
arg_names = collections.OrderedDict([
('name', str),
('x0', float),
('y0', float),
('x1', float),
('y1', float)
])
# Dictionary of types from Tcl command, needs to be ordered.
# For options like -optionname value
option_types = collections.OrderedDict([
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
required = ['name', 'x0', 'y0', 'x1', 'y1']
# structured help for current command, args needs to be ordered
help = {
'main': "Add a rectange to the given Geometry object.",
'args': collections.OrderedDict([
('name', 'Name of the Geometry object in which to add the rectangle.'),
('x0 y0', 'Bottom left corner coordinates.'),
('x1 y1', 'Top right corner coordinates.')
]),
'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
"""
obj_name = args['name']
x0 = args['x0']
y0 = args['y0']
x1 = args['x1']
y1 = args['y1']
try:
obj = self.app.collection.get_by_name(str(obj_name))
except:
return "Could not retrieve object: %s" % obj_name
if obj is None:
return "Object not found: %s" % obj_name
obj.add_polygon([(x0, y0), (x1, y0), (x1, y1), (x0, y1)])

View File

@@ -0,0 +1,201 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommandSignaled
class TclCommandAlignDrill(TclCommandSignaled):
"""
Tcl shell command to create excellon with drills for aligment.
"""
# array of all command aliases, to be able use old names for
# backward compatibility (add_poly, add_polygon)
aliases = ['aligndrill']
# Dictionary of types from Tcl command, needs to be ordered.
# For positional arguments
arg_names = collections.OrderedDict([
('name', str)
])
# Dictionary of types from Tcl command, needs to be ordered.
# For options like -optionname value
option_types = collections.OrderedDict([
('box', str),
('axis', str),
('holes', str),
('grid', float),
('minoffset', float),
('gridoffset', float),
('axisoffset', float),
('dia', float),
('dist', float),
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
required = ['name', 'axis']
# structured help for current command, args needs to be ordered
help = {
'main': "Create excellon with drills for aligment.",
'args': collections.OrderedDict([
('name', 'Name of the object (Gerber or Excellon) to mirror.'),
('dia', 'Tool diameter'),
('box', 'Name of object which act as box (cutout for example.)'),
('grid', 'Aligning to grid, for those, who have aligning pins'
'inside table in grid (-5,0),(5,0),(15,0)...'),
('gridoffset', 'offset of grid from 0 position.'),
('minoffset', 'min and max distance between align hole and pcb.'),
('axisoffset', 'Offset on second axis before aligment holes'),
('axis', 'Mirror axis parallel to the X or Y axis.'),
('dist', 'Distance of the mirror axis to the X or Y axis.')
]),
'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']
# Get source object.
try:
obj = self.app.collection.get_by_name(str(name))
except:
return "Could not retrieve object: %s" % name
if obj is None:
return "Object not found: %s" % name
if not isinstance(obj, FlatCAMGeometry) and \
not isinstance(obj, FlatCAMGerber) and \
not isinstance(obj, FlatCAMExcellon):
return "ERROR: Only Gerber, Geometry and Excellon objects can be used."
# Axis
try:
axis = args['axis'].upper()
except KeyError:
return "ERROR: Specify -axis X or -axis Y"
if not ('holes' in args or ('grid' in args and 'gridoffset' in args)):
return "ERROR: Specify -holes or -grid with -gridoffset "
if 'holes' in args:
try:
holes = eval("[" + args['holes'] + "]")
except KeyError:
return "ERROR: Wrong -holes format (X1,Y1),(X2,Y2)"
xscale, yscale = {"X": (1.0, -1.0), "Y": (-1.0, 1.0)}[axis]
# Tools
tools = {"1": {"C": args['dia']}}
def alligndrill_init_me(init_obj, app_obj):
"""
This function is used to initialize the new
object once it's created.
:param init_obj: The new object.
:param app_obj: The application (FlatCAMApp)
:return: None
"""
drills = []
if 'holes' in args:
for hole in holes:
point = Point(hole)
point_mirror = affinity.scale(point, xscale, yscale, origin=(px, py))
drills.append({"point": point, "tool": "1"})
drills.append({"point": point_mirror, "tool": "1"})
else:
if 'box' not in args:
return "ERROR: -grid can be used only for -box"
if 'axisoffset' in args:
axisoffset = args['axisoffset']
else:
axisoffset = 0
# This will align hole to given aligngridoffset and minimal offset from pcb, based on selected axis
if axis == "X":
firstpoint = args['gridoffset']
while (xmin - args['minoffset']) < firstpoint:
firstpoint = firstpoint - args['grid']
lastpoint = args['gridoffset']
while (xmax + args['minoffset']) > lastpoint:
lastpoint = lastpoint + args['grid']
localholes = (firstpoint, axisoffset), (lastpoint, axisoffset)
else:
firstpoint = args['gridoffset']
while (ymin - args['minoffset']) < firstpoint:
firstpoint = firstpoint - args['grid']
lastpoint = args['gridoffset']
while (ymax + args['minoffset']) > lastpoint:
lastpoint = lastpoint + args['grid']
localholes = (axisoffset, firstpoint), (axisoffset, lastpoint)
for hole in localholes:
point = Point(hole)
point_mirror = affinity.scale(point, xscale, yscale, origin=(px, py))
drills.append({"point": point, "tool": "1"})
drills.append({"point": point_mirror, "tool": "1"})
init_obj.tools = tools
init_obj.drills = drills
init_obj.create_geometry()
# Box
if 'box' in args:
try:
box = self.app.collection.get_by_name(args['box'])
except:
return "Could not retrieve object box: %s" % args['box']
if box is None:
return "Object box not found: %s" % args['box']
try:
xmin, ymin, xmax, ymax = box.bounds()
px = 0.5 * (xmin + xmax)
py = 0.5 * (ymin + ymax)
obj.app.new_object("excellon",
name + "_aligndrill",
alligndrill_init_me)
except Exception as e:
return "Operation failed: %s" % str(e)
else:
try:
dist = float(args['dist'])
except KeyError:
dist = 0.0
except ValueError:
return "Invalid distance: %s" % args['dist']
try:
px = dist
py = dist
obj.app.new_object("excellon", name + "_alligndrill", alligndrill_init_me)
except Exception as e:
return "Operation failed: %s" % str(e)
return 'Ok'

View File

@@ -0,0 +1,105 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommandSignaled
class TclCommandAlignDrillGrid(TclCommandSignaled):
"""
Tcl shell command to create an Excellon object
with drills for aligment grid.
Todo: What is an alignment grid?
"""
# array of all command aliases, to be able use old names for
# backward compatibility (add_poly, add_polygon)
aliases = ['aligndrillgrid']
# Dictionary of types from Tcl command, needs to be ordered.
# For positional arguments
arg_names = collections.OrderedDict([
('outname', str)
])
# Dictionary of types from Tcl command, needs to be ordered.
# For options like -optionname value
option_types = collections.OrderedDict([
('dia', float),
('gridx', float),
('gridoffsetx', float),
('gridy', float),
('gridoffsety', float),
('columns', int),
('rows', int)
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
required = ['outname', 'gridx', 'gridy', 'columns', 'rows']
# structured help for current command, args needs to be ordered
help = {
'main': "Create excellon with drills for aligment grid.",
'args': collections.OrderedDict([
('outname', 'Name of the object to create.'),
('dia', 'Tool diameter.'),
('gridx', 'Grid size in X axis.'),
('gridoffsetx', 'Move grid from origin.'),
('gridy', 'Grid size in Y axis.'),
('gridoffsety', 'Move grid from origin.'),
('colums', 'Number of grid holes on X axis.'),
('rows', 'Number of grid holes on Y axis.'),
]),
'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
"""
if 'gridoffsetx' not in args:
gridoffsetx = 0
else:
gridoffsetx = args['gridoffsetx']
if 'gridoffsety' not in args:
gridoffsety = 0
else:
gridoffsety = args['gridoffsety']
# Tools
tools = {"1": {"C": args['dia']}}
def aligndrillgrid_init_me(init_obj, app_obj):
"""
This function is used to initialize the new
object once it's created.
:param init_obj: The new object.
:param app_obj: The application (FlatCAMApp)
:return: None
"""
drills = []
currenty = 0
for row in range(args['rows']):
currentx = 0
for col in range(args['columns']):
point = Point(currentx + gridoffsetx, currenty + gridoffsety)
drills.append({"point": point, "tool": "1"})
currentx = currentx + args['gridx']
currenty = currenty + args['gridy']
init_obj.tools = tools
init_obj.drills = drills
init_obj.create_geometry()
# Create the new object
self.app.new_object("excellon", args['outname'], aligndrillgrid_init_me)

View File

@@ -0,0 +1,46 @@
from tclCommands.TclCommand import TclCommand
from ObjectCollection import *
class TclCommandClearShell(TclCommand):
"""
Tcl shell command to creates a circle in the given Geometry object.
example:
"""
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['clear']
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
])
# 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 = []
# structured help for current command, args needs to be ordered
help = {
'main': "Clear the text in the Tcl Shell browser.",
'args': collections.OrderedDict([
]),
'examples': []
}
def execute(self, args, unnamed_args):
"""
:param args:
:param unnamed_args:
:return:
"""
self.app.inform.emit("Tcl Shell Editor cleared ...")
self.app.shell._browser.clear()
pass

View File

@@ -0,0 +1,105 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommandSignaled
class TclCommandCncjob(TclCommandSignaled):
"""
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),
('feedrate_rapid', float),
('tooldia', float),
('spindlespeed', int),
('multidepth', bool),
('extracut', bool),
('depthperpass', float),
('endz', float),
('ppname_g', str),
('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.'),
('tooldia', 'Tool diameter to show on screen.'),
('z_cut', 'Z-axis cutting position.'),
('z_move', 'Z-axis moving position.'),
('feedrate', 'Moving speed when cutting.'),
('feedrate_rapid', 'Rapid moving at speed when cutting.'),
('spindlespeed', 'Speed of the spindle in rpm (example: 4000).'),
('multidepth', 'Use or not multidepth cnccut. (True or False)'),
('depthperpass', 'Height of one layer for multidepth.'),
('extracut', 'Use or not an extra cnccut over the first point in path,in the job end (example: True)'),
('endz', 'Height where the last move will park.'),
('outname', 'Name of the resulting Geometry object.'),
('ppname_g', 'Name of the Geometry postprocessor. No quotes, case sensitive')
]),
'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'] = str(name) + "_cnc"
obj = self.app.collection.get_by_name(str(name), isCaseSensitive=False)
if obj is None:
self.raise_tcl_error("Object not found: %s" % str(name))
if not isinstance(obj, FlatCAMGeometry):
self.raise_tcl_error('Expected FlatCAMGeometry, got %s %s.' % (str(name), type(obj)))
args["z_cut"] = args["z_cut"] if "z_cut" in args else obj.options["cutz"]
args["z_move"] = args["z_move"] if "z_move" in args else obj.options["travelz"]
args["feedrate"] = args["feedrate"] if "feedrate" in args else obj.options["feedrate"]
args["feedrate_rapid"] = args["feedrate_rapid"] if "feedrate_rapid" in args else obj.options["feedrate_rapid"]
args["spindlespeed"] = args["spindlespeed"] if "spindlespeed" in args else None
args["tooldia"] = args["tooldia"] if "tooldia" in args else obj.options["cnctooldia"]
args["multidepth"] = args["multidepth"] if "multidepth" in args else obj.options["multidepth"]
args["depthperpass"] = args["depthperpass"] if "depthperpass" in args else obj.options["depthperpass"]
args["extracut"] = args["extracut"] if "extracut" in args else obj.options["extracut"]
args["endz"]= args["endz"] if "endz" in args else obj.options["endz"]
args["ppname_g"] = args["ppname_g"] if "ppname_g" in args else obj.options["ppname_g"]
del args['name']
# HACK !!! Should be solved elsewhere!!!
# default option for multidepth is False
obj.options['multidepth'] = False
obj.generatecncjob(use_thread=False, **args)

View File

@@ -0,0 +1,99 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommand
class TclCommandCutout(TclCommand):
"""
Tcl shell command to create a board cutout geometry.
example:
"""
# List of all command aliases, to be able use old
# names for backward compatibility (add_poly, add_polygon)
aliases = ['cutout']
# 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([
('dia', float),
('margin', float),
('gapsize', float),
('gaps', 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': 'Creates board cutout.',
'args': collections.OrderedDict([
('name', 'Name of the object.'),
('dia', 'Tool diameter.'),
('margin', 'Margin over bounds.'),
('gapsize', 'size of gap.'),
('gaps', 'type of gaps.'),
]),
'examples': []
}
def execute(self, args, unnamed_args):
"""
:param args:
:param unnamed_args:
:return:
"""
name = args['name']
try:
obj = self.app.collection.get_by_name(str(name))
except:
return "Could not retrieve object: %s" % name
def geo_init_me(geo_obj, app_obj):
margin = args['margin'] + args['dia'] / 2
gap_size = args['dia'] + args['gapsize']
minx, miny, maxx, maxy = obj.bounds()
minx -= margin
maxx += margin
miny -= margin
maxy += margin
midx = 0.5 * (minx + maxx)
midy = 0.5 * (miny + maxy)
hgap = 0.5 * gap_size
pts = [[midx - hgap, maxy],
[minx, maxy],
[minx, midy + hgap],
[minx, midy - hgap],
[minx, miny],
[midx - hgap, miny],
[midx + hgap, miny],
[maxx, miny],
[maxx, midy - hgap],
[maxx, midy + hgap],
[maxx, maxy],
[midx + hgap, maxy]]
cases = {"tb": [[pts[0], pts[1], pts[4], pts[5]],
[pts[6], pts[7], pts[10], pts[11]]],
"lr": [[pts[9], pts[10], pts[1], pts[2]],
[pts[3], pts[4], pts[7], pts[8]]],
"4": [[pts[0], pts[1], pts[2]],
[pts[3], pts[4], pts[5]],
[pts[6], pts[7], pts[8]],
[pts[9], pts[10], pts[11]]]}
cuts = cases[args['gaps']]
geo_obj.solid_geometry = cascaded_union([LineString(segment) for segment in cuts])
try:
obj.app.new_object("geometry", name + "_cutout", geo_init_me)
except Exception as e:
return "Operation failed: %s" % str(e)

View File

@@ -0,0 +1,54 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommand
class TclCommandDelete(TclCommand):
"""
Tcl shell command to delete an object.
example:
"""
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['delete']
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str),
])
# Dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
option_types = collections.OrderedDict([
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
required = ['name']
# structured help for current command, args needs to be ordered
help = {
'main': 'Deletes the given object.',
'args': collections.OrderedDict([
('name', 'Name of the Object.'),
]),
'examples': []
}
def execute(self, args, unnamed_args):
"""
:param args:
:param unnamed_args:
:return:
"""
obj_name = args['name']
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)

View File

@@ -0,0 +1,107 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommandSignaled
class TclCommandDrillcncjob(TclCommandSignaled):
"""
Tcl shell command to Generates a Drill CNC Job from a Excellon Object.
"""
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['drillcncjob']
# 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([
('tools', str),
('drillz', float),
('travelz', float),
('feedrate', float),
('feedrate_rapid', float),
('spindlespeed', int),
('toolchange', bool),
('toolchangez', float),
('endz', float),
('ppname_e', str),
('outname', str),
('opt_type', 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 Drill CNC Job from a Excellon Object.",
'args': collections.OrderedDict([
('name', 'Name of the source object.'),
('tools', 'Comma separated indexes of tools (example: 1,3 or 2) or select all if not specified.'),
('drillz', 'Drill depth into material (example: -2.0).'),
('travelz', 'Travel distance above material (example: 2.0).'),
('feedrate', 'Drilling feed rate.'),
('feedrate_rapid', 'Rapid drilling feed rate.'),
('spindlespeed', 'Speed of the spindle in rpm (example: 4000).'),
('toolchange', 'Enable tool changes (example: True).'),
('toolchangez', 'Z distance for toolchange (example: 30.0).'),
('endz', 'Z distance at job end (example: 30.0).'),
('ppname_e', 'This is the Excellon postprocessor name: case_sensitive, no_quotes'),
('outname', 'Name of the resulting Geometry object.'),
('opt_type', 'Name of move optimization type. R by default from Rtree or '
'T from Travelling Salesman Algorithm')
]),
'examples': ['drillcncjob test.TXT -drillz -1.5 -travelz 14 -feedrate 222 -feedrate_rapid 456 -spindlespeed 777'
' -toolchange True -toolchangez 33 -endz 22 -ppname_e default\n'
'Usage of -feedrate_rapid matter only when the posptocessor is using it, like -marlin-.']
}
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"
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, FlatCAMExcellon):
self.raise_tcl_error('Expected FlatCAMExcellon, got %s %s.' % (name, type(obj)))
def job_init(job_obj, app_obj):
drillz = args["drillz"] if "drillz" in args else obj.options["drillz"]
job_obj.z_move = args["travelz"] if "travelz" in args else obj.options["travelz"]
job_obj.feedrate = args["feedrate"] if "feedrate" in args else obj.options["feedrate"]
job_obj.feedrate_rapid = args["feedrate_rapid"] if "feedrate_rapid" in args else obj.options["feedrate_rapid"]
job_obj.spindlespeed = args["spindlespeed"] if "spindlespeed" in args else None
job_obj.pp_excellon_name = args["ppname_e"] if "ppname_e" in args \
else obj.options["ppname_e"]
toolchange = True if "toolchange" in args and args["toolchange"] == 1 else False
toolchangez = args["toolchangez"] if "toolchangez" in args else obj.options["toolchangez"]
endz = args["endz"] if "endz" in args else obj.options["endz"]
tools = args["tools"] if "tools" in args else 'all'
opt_type = args["opt_type"] if "opt_type" in args else 'B'
job_obj.generate_from_excellon_by_tool(obj, tools, drillz=drillz, toolchangez=toolchangez, endz=endz,
toolchange=toolchange, excellon_optimization_type=opt_type)
job_obj.gcode_parse()
job_obj.create_geometry()
self.app.new_object("cncjob", args['outname'], job_init)

View File

@@ -0,0 +1,79 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommandSignaled
class TclCommandExportGcode(TclCommandSignaled):
"""
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 captured and passed as preable
to another "export_gcode" or "write_gcode" call to join G-Code.
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)

View File

@@ -0,0 +1,52 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommand
class TclCommandExportSVG(TclCommand):
"""
Tcl shell command to export a Geometry Object as an SVG File.
example:
export_svg my_geometry filename
"""
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['export_svg']
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str),
('filename', str),
('scale_factor', float)
])
# Dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
option_types = collections.OrderedDict([
('scale_factor', float)
])
# 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 a Geometry Object as a SVG File.",
'args': collections.OrderedDict([
('name', 'Name of the object export.'),
('filename', 'Path to the file to export.'),
('scale_factor', 'Multiplication factor used for scaling line widths during export.')
]),
'examples': ['export_svg my_geometry my_file.svg']
}
def execute(self, args, unnamed_args):
"""
:param args:
:param unnamed_args:
:return:
"""
name = args['name']
self.app.export_svg(**args)

View File

@@ -0,0 +1,64 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommandSignaled
class TclCommandExteriors(TclCommandSignaled):
"""
Tcl shell command to get exteriors of polygons
"""
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['exteriors', 'ext']
# dictionary of types from Tcl command, 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([
('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': "Get exteriors of polygons.",
'args': collections.OrderedDict([
('name', 'Name of the source Geometry object.'),
('outname', 'Name of the resulting Geometry object.')
]),
'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' in args:
outname = args['outname']
else:
outname = name + "_exteriors"
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, Geometry):
self.raise_tcl_error('Expected Geometry, got %s %s.' % (name, type(obj)))
def geo_init(geo_obj, app_obj):
geo_obj.solid_geometry = obj_exteriors
obj_exteriors = obj.get_exteriors()
self.app.new_object('geometry', outname, geo_init)

View File

@@ -0,0 +1,65 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommandSignaled
class TclCommandFollow(TclCommandSignaled):
"""
Tcl shell command to follow a Gerber file
"""
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['follow']
# 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([
('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': "Creates a geometry object following gerber paths.",
'args': collections.OrderedDict([
('name', 'Object name to follow.'),
('outname', 'Name of the resulting Geometry object.')
]),
'examples': ['follow name -outname name_follow']
}
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 + "_follow"
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, FlatCAMGerber):
self.raise_tcl_error('Expected FlatCAMGerber, got %s %s.' % (name, type(obj)))
del args['name']
try:
obj.follow(**args)
except Exception as e:
return "Operation failed: %s" % str(e)
# in the end toggle the visibility of the origin object so we can see the generated Geometry
self.app.collection.get_by_name(name).ui.plot_cb.toggle()

View File

@@ -0,0 +1,128 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommandSignaled
class TclCommandGeoCutout(TclCommandSignaled):
"""
Tcl shell command to cut holding gaps from geometry.
"""
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['geocutout']
# Dictionary of types from Tcl command, needs to be ordered.
# For positional arguments
arg_names = collections.OrderedDict([
('name', str)
])
# Dictionary of types from Tcl command, needs to be ordered.
# For options like -optionname value
option_types = collections.OrderedDict([
('dia', float),
('margin', float),
('gapsize', float),
('gaps', 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': "Cut holding gaps from geometry.",
'args': collections.OrderedDict([
('name', 'Name of the geometry object.'),
('dia', 'Tool diameter.'),
('margin', 'Margin over bounds.'),
('gapsize', 'Size of gap.'),
('gaps', 'Type of gaps.'),
]),
'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" +
" exteriors BCu_margin_iso -outname BCu_margin_iso_exterior\n" +
"\n" +
" #delete isolated object if you dond need id anymore\n" +
" delete BCu_margin_iso\n" +
"\n" +
" #finally cut holding gaps\n" +
" geocutout BCu_margin_iso_exterior -dia 3 -gapsize 0.6 -gaps 4\n"]
}
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
"""
# How gaps wil be rendered:
# lr - left + right
# tb - top + bottom
# 4 - left + right +top + bottom
# 2lr - 2*left + 2*right
# 2tb - 2*top + 2*bottom
# 8 - 2*left + 2*right +2*top + 2*bottom
name = args['name']
obj = None
def subtract_rectangle(obj_, x0, y0, x1, y1):
pts = [(x0, y0), (x1, y0), (x1, y1), (x0, y1)]
obj_.subtract_polygon(pts)
try:
obj = self.app.collection.get_by_name(str(name))
except:
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
xmin, ymin, xmax, ymax = obj.bounds()
px = 0.5 * (xmin + xmax)
py = 0.5 * (ymin + ymax)
lenghtx = (xmax - xmin)
lenghty = (ymax - ymin)
gapsize = args['gapsize'] + (args['dia'] / 2)
if args['gaps'] == '8' or args['gaps'] == '2lr':
subtract_rectangle(obj,
xmin - gapsize, # botleft_x
py - gapsize + lenghty / 4, # botleft_y
xmax + gapsize, # topright_x
py + gapsize + lenghty / 4) # topright_y
subtract_rectangle(obj,
xmin - gapsize,
py - gapsize - lenghty / 4,
xmax + gapsize,
py + gapsize - lenghty / 4)
if args['gaps'] == '8' or args['gaps'] == '2tb':
subtract_rectangle(obj,
px - gapsize + lenghtx / 4,
ymin - gapsize,
px + gapsize + lenghtx / 4,
ymax + gapsize)
subtract_rectangle(obj,
px - gapsize - lenghtx / 4,
ymin - gapsize,
px + gapsize - lenghtx / 4,
ymax + gapsize)
if args['gaps'] == '4' or args['gaps'] == 'lr':
subtract_rectangle(obj,
xmin - gapsize,
py - gapsize,
xmax + gapsize,
py + gapsize)
if args['gaps'] == '4' or args['gaps'] == 'tb':
subtract_rectangle(obj,
px - gapsize,
ymin - gapsize,
px + gapsize,
ymax + gapsize)

View File

@@ -0,0 +1,59 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommand
class TclCommandGeoUnion(TclCommand):
"""
Tcl shell command to run a union (addition) operation on the
components of a geometry object.
example:
"""
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['geo_union']
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str),
])
# Dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
option_types = collections.OrderedDict([
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
required = ['name']
# structured help for current command, args needs to be ordered
help = {
'main': ('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'
'a single larger polygon.'),
'args': collections.OrderedDict([
('name', 'Name of the Geometry Object.'),
]),
'examples': []
}
def execute(self, args, unnamed_args):
"""
:param args:
:param unnamed_args:
:return:
"""
obj_name = args['name']
try:
obj = self.collection.get_by_name(str(obj_name))
except:
return "Could not retrieve object: %s" % obj_name
if obj is None:
return "Object not found: %s" % obj_name
obj.union()

View File

@@ -0,0 +1,46 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommand
class TclCommandGetNames(TclCommand):
"""
Tcl shell command to set an object as active in the GUI.
example:
"""
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['get_names']
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
])
# 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 = []
# structured help for current command, args needs to be ordered
help = {
'main': 'Lists the names of objects in the project.',
'args': collections.OrderedDict([
]),
'examples': []
}
def execute(self, args, unnamed_args):
"""
:param args:
:param unnamed_args:
:return:
"""
return '\n'.join(self.app.collection.get_names())

View File

@@ -0,0 +1,50 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommand
class TclCommandGetSys(TclCommand):
"""
Tcl shell command to get the value of a system variable
example:
get_sys excellon_zeros
"""
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['get_sys', 'getsys']
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str)
])
# Dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
option_types = collections.OrderedDict([
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
required = ['name']
# structured help for current command, args needs to be ordered
help = {
'main': "Returns the value of the system variable.",
'args': collections.OrderedDict([
('name', 'Name of the system variable.'),
]),
'examples': ['get_sys excellon_zeros']
}
def execute(self, args, unnamed_args):
"""
:param args:
:param unnamed_args:
:return:
"""
name = args['name']
if name in self.app.defaults:
return self.app.defaults[name]

View File

@@ -0,0 +1,81 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommandSignaled
class TclCommandImportSvg(TclCommandSignaled):
"""
Tcl shell command to import an SVG file as a Geometry Object.
"""
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['import_svg']
# dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('filename', str)
])
# dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
option_types = collections.OrderedDict([
('type', str),
('outname', str)
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
required = ['filename']
# structured help for current command, args needs to be ordered
help = {
'main': "Import an SVG file as a Geometry Object..",
'args': collections.OrderedDict([
('filename', 'Path to file to open.'),
('type', 'Import as gerber or geometry(default).'),
('outname', 'Name of the resulting Geometry object.')
]),
'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
"""
# How the object should be initialized
def obj_init(geo_obj, app_obj):
if not isinstance(geo_obj, Geometry):
self.raise_tcl_error('Expected Geometry or Gerber, got %s %s.' % (outname, type(geo_obj)))
geo_obj.import_svg(filename)
filename = args['filename']
if 'outname' in args:
outname = args['outname']
else:
outname = filename.split('/')[-1].split('\\')[-1]
if 'type' in args:
obj_type = args['type']
else:
obj_type = 'geometry'
if obj_type != "geometry" and obj_type != "gerber":
self.raise_tcl_error("Option type can be 'geopmetry' or 'gerber' only, got '%s'." % obj_type)
with self.app.proc_container.new("Import SVG"):
# Object creation
self.app.new_object(obj_type, outname, obj_init)
# Register recent file
self.app.file_opened.emit("svg", filename)
# GUI feedback
self.app.inform.emit("Opened: " + filename)

View File

@@ -0,0 +1,64 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommandSignaled
class TclCommandInteriors(TclCommandSignaled):
"""
Tcl shell command to get interiors of polygons
"""
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['interiors']
# dictionary of types from Tcl command, 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([
('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': "Get interiors of polygons.",
'args': collections.OrderedDict([
('name', 'Name of the source Geometry object.'),
('outname', 'Name of the resulting Geometry object.')
]),
'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' in args:
outname = args['outname']
else:
outname = name + "_interiors"
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, Geometry):
self.raise_tcl_error('Expected Geometry, got %s %s.' % (name, type(obj)))
def geo_init(geo_obj, app_obj):
geo_obj.solid_geometry = obj_interiors
obj_interiors = obj.get_interiors()
self.app.new_object('geometry', outname, geo_init)

View File

@@ -0,0 +1,79 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommandSignaled
class TclCommandIsolate(TclCommandSignaled):
"""
Tcl shell command to Creates isolation routing geometry for the given Gerber.
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 = ['isolate']
# 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([
('dia', float),
('passes', int),
('overlap', float),
('combine', int),
('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': "Creates isolation routing geometry for the given Gerber.",
'args': collections.OrderedDict([
('name', 'Name of the source object.'),
('dia', 'Tool diameter.'),
('passes', 'Passes of tool width.'),
('overlap', 'Fraction of tool diameter to overlap passes.'),
('combine', 'Combine all passes into one geometry.'),
('outname', 'Name of the resulting Geometry object.')
]),
'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 + "_iso"
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, FlatCAMGerber):
self.raise_tcl_error('Expected FlatCAMGerber, got %s %s.' % (name, type(obj)))
del args['name']
obj.isolate(**args)

View File

@@ -0,0 +1,64 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommand
class TclCommandJoinExcellon(TclCommand):
"""
Tcl shell command to merge Excellon objects.
example:
"""
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['join_excellon', 'join_excellons']
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('outname', 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 = ['outname']
# structured help for current command, args needs to be ordered
help = {
'main': "Runs a merge operation (join) on the Excellon objects.",
'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')
]),
'examples': []
}
def execute(self, args, unnamed_args):
"""
:param args:
:param unnamed_args:
:return:
"""
outname = args['name']
obj_names = unnamed_args
objs = []
for obj_n in obj_names:
obj = self.app.collection.get_by_name(str(obj_n))
if obj is None:
return "Object not found: %s" % obj_n
else:
objs.append(obj)
def initialize(obj_, app):
FlatCAMExcellon.merge(objs, obj_)
if objs is not None:
self.app.new_object("excellon", outname, initialize)

View File

@@ -0,0 +1,64 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommand
class TclCommandJoinGeometry(TclCommand):
"""
Tcl shell command to merge Excellon objects.
example:
"""
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['join_geometries', 'join_geometry']
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('outname', 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 = ['outname']
# structured help for current command, args needs to be ordered
help = {
'main': "Runs a merge operation (join) on the Excellon objects.",
'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')
]),
'examples': []
}
def execute(self, args, unnamed_args):
"""
:param args:
:param unnamed_args:
:return:
"""
outname = args['outname']
obj_names = unnamed_args
objs = []
for obj_n in obj_names:
obj = self.app.collection.get_by_name(str(obj_n))
if obj is None:
return "Object not found: %s" % obj_n
else:
objs.append(obj)
def initialize(obj_, app):
FlatCAMGeometry.merge(objs, obj_)
if objs is not None:
self.app.new_object("geometry", outname, initialize)

View File

@@ -0,0 +1,56 @@
from tclCommands.TclCommand import *
class TclCommandListSys(TclCommand):
"""
Tcl shell command to get the list of system variables
example:
list_sys
"""
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['list_sys', 'listsys']
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('selection', 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 = []
# structured help for current command, args needs to be ordered
help = {
'main': "Returns the list of the names of system variables.\n"
"Without an argument it will list all the system parameters. "
"As an argument use first letter or first letters from the name "
"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",
'args': collections.OrderedDict([
]),
'examples': ['list_sys',
'list_sys ser'
'list_sys gerber',
'list_sys cncj']
}
def execute(self, args, unnamed_args):
"""
:param args:
:param unnamed_args:
:return:
"""
if 'selection' in args:
argument = args['selection']
return str([k for k in self.app.defaults.keys() if str(k).startswith(str(argument))])
else:
return str([*self.app.defaults])

View File

@@ -0,0 +1,91 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommandSignaled
class TclCommandMillHoles(TclCommandSignaled):
"""
Tcl shell command to Create Geometry Object for milling holes from Excellon.
example:
millholes my_drill -tools 1,2,3 -tooldia 0.1 -outname mill_holes_geo
"""
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['millholes', 'mill']
# 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([
('tools', str),
('outname', str),
('tooldia', float),
('use_threads', bool)
])
# 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': "Create Geometry Object for milling holes from Excellon.",
'args': collections.OrderedDict([
('name', 'Name of the Excellon Object.'),
('tools', 'Comma separated indexes of tools (example: 1,3 or 2).'),
('tooldia', 'Diameter of the milling tool (example: 0.1).'),
('outname', 'Name of object to create.'),
('use_thread', 'If to use multithreading: True or False.')
]),
'examples': ['millholes mydrills']
}
def execute(self, args, unnamed_args):
"""
: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 + "_mill"
try:
if 'tools' in args and args['tools'] != 'all':
# Split and put back. We are passing the whole dictionary later.
args['tools'] = [x.strip() for x in args['tools'].split(",")]
else:
args['tools'] = 'all'
except Exception as e:
self.raise_tcl_error("Bad tools: %s" % str(e))
try:
obj = self.app.collection.get_by_name(str(name))
except:
self.raise_tcl_error("Could not retrieve object: %s" % name)
if not isinstance(obj, FlatCAMExcellon):
self.raise_tcl_error('Only Excellon objects can be mill-drilled, got %s %s.' % (name, type(obj)))
if self.app.collection.has_promises():
self.raise_tcl_error('!!!Promises exists, but should not here!!!')
try:
# 'name' is not an argument of obj.generate_milling()
del args['name']
# This runs in the background... Is blocking handled?
success, msg = obj.generate_milling(**args)
except Exception as e:
self.raise_tcl_error("Operation failed: %s" % str(e))
if not success:
self.raise_tcl_error(msg)

View File

@@ -0,0 +1,108 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommandSignaled
class TclCommandMirror(TclCommandSignaled):
"""
Tcl shell command to mirror an object.
"""
# array of all command aliases, to be able use
# old names for backward compatibility (add_poly, add_polygon)
aliases = ['mirror']
# Dictionary of types from Tcl command, needs to be ordered.
# For positional arguments
arg_names = collections.OrderedDict([
('name', str)
])
# Dictionary of types from Tcl command, needs to be ordered.
# For options like -optionname value
option_types = collections.OrderedDict([
('axis', str),
('box', str),
('dist', float)
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
required = ['name', 'axis']
# structured help for current command, args needs to be ordered
help = {
'main': "Opens an Excellon file.",
'args': collections.OrderedDict([
('name', 'Name of the object (Gerber or Excellon) to mirror.'),
('box', 'Name of object which act as box (cutout for example.)'),
('axis', 'Mirror axis parallel to the X or Y axis.'),
('dist', 'Distance of the mirror axis to the X or Y axis.')
]),
'examples': []
}
def execute(self, args, unnamed_args):
"""
Execute this 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']
# Get source object.
try:
obj = self.app.collection.get_by_name(str(name))
except:
return "Could not retrieve object: %s" % name
if obj is None:
return "Object not found: %s" % name
if not isinstance(obj, FlatCAMGerber) and \
not isinstance(obj, FlatCAMExcellon) and \
not isinstance(obj, FlatCAMGeometry):
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"
# Box
if 'box' in args:
try:
box = self.app.collection.get_by_name(args['box'])
except:
return "Could not retrieve object box: %s" % args['box']
if box is None:
return "Object box not found: %s" % args['box']
try:
xmin, ymin, xmax, ymax = box.bounds()
px = 0.5 * (xmin + xmax)
py = 0.5 * (ymin + ymax)
obj.mirror(axis, [px, py])
obj.plot()
except Exception as e:
return "Operation failed: %s" % str(e)
else:
try:
dist = float(args['dist'])
except KeyError:
dist = 0.0
except ValueError:
return "Invalid distance: %s" % args['dist']
try:
obj.mirror(axis, [dist, dist])
obj.plot()
except Exception as e:
return "Operation failed: %s" % str(e)

View File

@@ -0,0 +1,39 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommand
class TclCommandNew(TclCommand):
"""
Tcl shell command to starts a new project. Clears objects from memory
"""
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['new']
# dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict()
# 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 = []
# structured help for current command, args needs to be ordered
help = {
'main': "Starts a new project. Clears objects from memory.",
'args': collections.OrderedDict(),
'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
"""
self.app.on_file_new()

View File

@@ -0,0 +1,49 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommandSignaled
class TclCommandNewGeometry(TclCommandSignaled):
"""
Tcl shell command to subtract polygon from the given Geometry object.
"""
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['new_geometry']
# Dictionary of types from Tcl command, needs to be ordered.
# For positional arguments
arg_names = collections.OrderedDict([
('name', str)
])
# Dictionary of types from Tcl command, needs to be ordered.
# For options like -optionname value
option_types = collections.OrderedDict([
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
required = ['name']
# structured help for current command, args needs to be ordered
help = {
'main': "Creates a new empty geometry object.",
'args': collections.OrderedDict([
('name', 'New object name.'),
]),
'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']
self.app.new_object('geometry', str(name), lambda x, y: None)

View File

@@ -0,0 +1,53 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommand
class TclCommandOffset(TclCommand):
"""
Tcl shell command to change the position of the object.
example:
offset my_geometry 1.2 -0.3
"""
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['offset']
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str),
('x', float),
('y', float)
])
# 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', 'x', 'y']
# structured help for current command, args needs to be ordered
help = {
'main': "Changes the position of the object.",
'args': collections.OrderedDict([
('name', 'Name of the object to offset.'),
('x', 'Offset distance in the X axis.'),
('y', 'Offset distance in the Y axis')
]),
'examples': ['offset my_geometry 1.2 -0.3']
}
def execute(self, args, unnamed_args):
"""
:param args:
:param unnamed_args:
:return:
"""
name = args['name']
x, y = args['x'], args['y']
self.app.collection.get_by_name(name).offset((x, y))

View File

@@ -0,0 +1,50 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommandSignaled
class TclCommandOpenExcellon(TclCommandSignaled):
"""
Tcl shell command to open an Excellon file.
"""
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['open_excellon']
# Dictionary of types from Tcl command, needs to be ordered.
# For positional arguments
arg_names = collections.OrderedDict([
('filename', str)
])
# Dictionary of types from Tcl command, needs to be ordered.
# For options like -optionname value
option_types = collections.OrderedDict([
('outname', str)
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
required = ['filename']
# structured help for current command, args needs to be ordered
help = {
'main': "Opens an Excellon file.",
'args': collections.OrderedDict([
('filename', 'Path to file to open.'),
('outname', 'Name of the resulting Excellon object.')
]),
'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
"""
filename = args.pop('filename')
self.app.open_excellon(filename, **args)

View File

@@ -0,0 +1,49 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommandSignaled
class TclCommandOpenGCode(TclCommandSignaled):
"""
Tcl shell command to open a G-Code file.
"""
# array of all command aliases, to be able use old names for
# backward compatibility (add_poly, add_polygon)
aliases = ['open_gcode']
# Dictionary of types from Tcl command, needs to be ordered.
# For positional arguments
arg_names = collections.OrderedDict([
('filename', str)
])
# Dictionary of types from Tcl command, needs to be ordered.
# For options like -optionname value
option_types = collections.OrderedDict([
('outname', str)
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
required = ['filename']
# structured help for current command, args needs to be ordered
help = {
'main': "Opens a G-Code file.",
'args': collections.OrderedDict([
('filename', 'Path to file to open.'),
('outname', 'Name of the resulting CNCJob object.')
]),
'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
"""
self.app.open_gcode(args['filename'], **args)

View File

@@ -0,0 +1,95 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommandSignaled
class TclCommandOpenGerber(TclCommandSignaled):
"""
Tcl shell command to opens a Gerber file
"""
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['open_gerber']
# dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('filename', str)
])
# dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
option_types = collections.OrderedDict([
('follow', str),
('outname', str)
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
required = ['filename']
# structured help for current command, args needs to be ordered
help = {
'main': "Opens a Gerber file.",
'args': collections.OrderedDict([
('filename', 'Path to file to open.'),
('follow', 'N If 1, does not create polygons, just follows the gerber path.'),
('outname', 'Name of the resulting Gerber object.')
]),
'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
"""
# How the object should be initialized
def obj_init(gerber_obj, app_obj):
if not isinstance(gerber_obj, Geometry):
self.raise_tcl_error('Expected FlatCAMGerber, got %s %s.' % (outname, type(gerber_obj)))
# Opening the file happens here
self.app.progress.emit(30)
try:
gerber_obj.parse_file(filename, follow=follow)
except IOError:
app_obj.inform.emit("[error_notcl] Failed to open file: %s " % filename)
app_obj.progress.emit(0)
self.raise_tcl_error('Failed to open file: %s' % filename)
except ParseError as e:
app_obj.inform.emit("[error_notcl] Failed to parse file: %s, %s " % (filename, str(e)))
app_obj.progress.emit(0)
self.log.error(str(e))
return
# Further parsing
app_obj.progress.emit(70)
filename = args['filename']
if 'outname' in args:
outname = args['outname']
else:
outname = filename.split('/')[-1].split('\\')[-1]
follow = None
if 'follow' in args:
follow = args['follow']
with self.app.proc_container.new("Opening Gerber"):
# Object creation
self.app.new_object("gerber", outname, obj_init)
# Register recent file
self.app.file_opened.emit("gerber", filename)
self.app.progress.emit(100)
# GUI feedback
self.app.inform.emit("[success]Opened: " + filename)

View File

@@ -0,0 +1,47 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommandSignaled
class TclCommandOpenProject(TclCommandSignaled):
"""
Tcl shell command to open a FlatCAM project.
"""
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['open_project']
# Dictionary of types from Tcl command, needs to be ordered.
# For positional arguments
arg_names = collections.OrderedDict([
('filename', str)
])
# Dictionary of types from Tcl command, needs to be ordered.
# For options like -optionname value
option_types = collections.OrderedDict([
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
required = ['filename']
# structured help for current command, args needs to be ordered
help = {
'main': "Opens a FlatCAM project.",
'args': collections.OrderedDict([
('filename', 'Path to file to open.'),
]),
'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
"""
self.app.open_project(args['filename'])

View File

@@ -0,0 +1,50 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommandSignaled
class TclCommandOptions(TclCommandSignaled):
"""
Tcl shell command to open an Excellon file.
"""
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['options']
# Dictionary of types from Tcl command, needs to be ordered.
# For positional arguments
arg_names = collections.OrderedDict([
('name', str)
])
# Dictionary of types from Tcl command, needs to be ordered.
# 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': "Shows the settings for an object.",
'args': collections.OrderedDict([
('name', 'Object name.'),
]),
'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']
ops = self.app.collection.get_by_name(str(name)).options
return '\n'.join(["%s: %s" % (o, ops[o]) for o in ops])

View File

@@ -0,0 +1,84 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommandSignaled
class TclCommandPaint(TclCommandSignaled):
"""
Paint the interior of polygons
"""
# Array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['paint']
# dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str),
('tooldia', float),
('overlap', float)
])
# dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
option_types = collections.OrderedDict([
('outname', str),
('all', bool),
('x', float),
('y', float)
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
required = ['name', 'tooldia', 'overlap']
# structured help for current command, args needs to be ordered
help = {
'main': "Paint polygons",
'args': collections.OrderedDict([
('name', 'Name of the source Geometry object.'),
('tooldia', 'Diameter of the tool to be used.'),
('overlap', 'Fraction of the tool diameter to overlap cuts.'),
('outname', 'Name of the resulting Geometry object.'),
('all', 'Paint all polygons in the object.'),
('x', 'X value of coordinate for the selection of a single polygon.'),
('y', 'Y value of coordinate for the selection of a single polygon.')
]),
'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']
tooldia = args['tooldia']
overlap = args['overlap']
if 'outname' in args:
outname = args['outname']
else:
outname = name + "_paint"
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, Geometry):
self.raise_tcl_error('Expected Geometry, got %s %s.' % (name, type(obj)))
if 'all' in args and args['all']:
obj.paint_poly_all(tooldia, overlap, outname)
return
if 'x' not in args or 'y' not in args:
self.raise_tcl_error('Expected -all 1 or -x <value> and -y <value>.')
x = args['x']
y = args['y']
obj.paint_poly_single_click([x, y], tooldia, overlap, outname)

View File

@@ -0,0 +1,154 @@
from ObjectCollection import *
from copy import copy,deepcopy
from tclCommands.TclCommand import TclCommand
class TclCommandPanelize(TclCommand):
"""
Tcl shell command to panelize an object.
example:
"""
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['panelize','pan', 'panel']
# 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([
('rows', int),
('columns', int),
('spacing_columns', float),
('spacing_rows', float),
('box', str),
('outname', str)
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
required = ['name', 'rows', 'columns']
# structured help for current command, args needs to be ordered
help = {
'main': 'Rectangular panelizing.',
'args': collections.OrderedDict([
('name', 'Name of the object to panelize.'),
('box', 'Name of object which acts as box (cutout for example.)'
'for cutout boundary. Object from name is used if not specified.'),
('spacing_columns', 'Spacing between columns.'),
('spacing_rows', 'Spacing between rows.'),
('columns', 'Number of columns.'),
('rows', 'Number of rows;'),
('outname', 'Name of the new geometry object.')
]),
'examples': []
}
def execute(self, args, unnamed_args):
"""
:param args:
:param unnamed_args:
:return:
"""
name = args['name']
# Get source object.
try:
obj = self.app.collection.get_by_name(str(name))
except:
return "Could not retrieve object: %s" % name
if obj is None:
return "Object not found: %s" % name
if 'box' in args:
boxname = args['box']
try:
box = self.app.collection.get_by_name(boxname)
except:
return "Could not retrieve object: %s" % name
else:
box = obj
if 'columns' not in args or 'rows' not in args:
return "ERROR: Specify -columns and -rows"
if 'outname' in args:
outname = args['outname']
else:
outname = name + '_panelized'
if 'spacing_columns' in args:
spacing_columns = args['spacing_columns']
else:
spacing_columns = 5
if 'spacing_rows' in args:
spacing_rows = args['spacing_rows']
else:
spacing_rows = 5
xmin, ymin, xmax, ymax = box.bounds()
lenghtx = xmax - xmin + spacing_columns
lenghty = ymax - ymin + spacing_rows
currenty = 0
def initialize_local(obj_init, app):
obj_init.solid_geometry = obj.solid_geometry
obj_init.offset([float(currentx), float(currenty)])
objs.append(obj_init)
def initialize_local_excellon(obj_init, app):
obj_init.tools = obj.tools
# drills are offset, so they need to be deep copied
obj_init.drills = deepcopy(obj.drills)
obj_init.offset([float(currentx), float(currenty)])
obj_init.create_geometry()
objs.append(obj_init)
def initialize_geometry(obj_init, app):
FlatCAMGeometry.merge(objs, obj_init)
def initialize_excellon(obj_init, app):
# merge expects tools to exist in the target object
obj_init.tools = obj.tools.copy()
FlatCAMExcellon.merge(objs, obj_init)
objs = []
if obj is not None:
for row in range(args['rows']):
currentx = 0
for col in range(args['columns']):
local_outname = outname + ".tmp." + str(col) + "." + str(row)
if isinstance(obj, FlatCAMExcellon):
self.app.new_object("excellon", local_outname, initialize_local_excellon, plot=False,
autoselected=False)
else:
self.app.new_object("geometry", local_outname, initialize_local, plot=False, autoselected=False)
currentx += lenghtx
currenty += lenghty
if isinstance(obj, FlatCAMExcellon):
self.app.new_object("excellon", outname, initialize_excellon)
else:
self.app.new_object("geometry", outname, initialize_geometry)
# deselect all to avoid delete selected object when run delete from shell
self.app.collection.set_all_inactive()
for delobj in objs:
self.app.collection.set_active(delobj.options['name'])
self.app.on_delete()
else:
return "ERROR: obj is None"
return "Ok"

View File

@@ -0,0 +1,46 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommand
class TclCommandPlot(TclCommand):
"""
Tcl shell command to update the plot on the user interface.
example:
plot
"""
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['plot']
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
])
# 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 = []
# structured help for current command, args needs to be ordered
help = {
'main': "Updates the plot on the user interface.",
'args': collections.OrderedDict([
]),
'examples': []
}
def execute(self, args, unnamed_args):
"""
:param args:
:param unnamed_args:
:return:
"""
self.app.plot_all()

View File

@@ -0,0 +1,47 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommandSignaled
class TclCommandSaveProject(TclCommandSignaled):
"""
Tcl shell command to save the FlatCAM project to file.
"""
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['save_project']
# Dictionary of types from Tcl command, needs to be ordered.
# For positional arguments
arg_names = collections.OrderedDict([
('filename', str)
])
# Dictionary of types from Tcl command, needs to be ordered.
# For options like -optionname value
option_types = collections.OrderedDict([
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
required = ['filename']
# structured help for current command, args needs to be ordered
help = {
'main': "Saves the FlatCAM project to file.",
'args': collections.OrderedDict([
('filename', 'Path to file.'),
]),
'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
"""
self.app.save_project(args['filename'])

View File

@@ -0,0 +1,44 @@
from tclCommands.TclCommand import *
class TclCommandSaveSys(TclCommandSignaled):
"""
Tcl shell command to save the FlatCAM defaults settings to file.
"""
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['save_sys', 'save']
# Dictionary of types from Tcl command, needs to be ordered.
# For positional arguments
arg_names = collections.OrderedDict([
])
# Dictionary of types from Tcl command, needs to be ordered.
# For options like -optionname value
option_types = collections.OrderedDict([
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
required = []
# structured help for current command, args needs to be ordered
help = {
'main': "Saves the FlatCAM system paramaters to defaults file.",
'args': collections.OrderedDict([]),
'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
"""
self.app.save_defaults(args)

View File

@@ -0,0 +1,51 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommand
class TclCommandScale(TclCommand):
"""
Tcl shell command to resizes the object by a factor.
example:
scale my_geometry 4.2
"""
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['scale']
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str),
('factor', float)
])
# 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', 'factor']
# structured help for current command, args needs to be ordered
help = {
'main': "Resizes the object by a factor.",
'args': collections.OrderedDict([
('name', 'Name of the object to resize.'),
('factor', 'Fraction by which to scale.')
]),
'examples': ['scale my_geometry 4.2']
}
def execute(self, args, unnamed_args):
"""
:param args:
:param unnamed_args:
:return:
"""
name = args['name']
factor = args['factor']
self.app.collection.get_by_name(name).scale(factor)

View File

@@ -0,0 +1,51 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommand
class TclCommandSetActive(TclCommand):
"""
Tcl shell command to set an object as active in the GUI.
example:
"""
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['set_active']
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str),
])
# Dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
option_types = collections.OrderedDict([
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
required = ['name']
# structured help for current command, args needs to be ordered
help = {
'main': 'Sets an object as active.',
'args': collections.OrderedDict([
('name', 'Name of the Object.'),
]),
'examples': []
}
def execute(self, args, unnamed_args):
"""
:param args:
:param unnamed_args:
:return:
"""
obj_name = args['name']
try:
self.app.collection.set_active(str(obj_name))
except Exception as e:
return "Command failed: %s" % str(e)

View File

@@ -0,0 +1,88 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommand
class TclCommandSetSys(TclCommand):
"""
Tcl shell command to set the value of a system variable
example:
"""
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['set_sys', 'setsys']
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str),
('value', 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', 'value']
# structured help for current command, args needs to be ordered
help = {
'main': "Sets the value of the system variable.",
'args': collections.OrderedDict([
('name', 'Name of the system variable.'),
('value', 'Value to set.')
]),
'examples': []
}
def execute(self, args, unnamed_args):
"""
:param args:
:param unnamed_args:
:return:
"""
param = args['name']
value = args['value']
# TCL string to python keywords:
tcl2py = {
"None": None,
"none": None,
"false": False,
"False": False,
"true": True,
"True": True,
"l": "L",
"L": "L",
"T": "T",
"t": "T",
"0": "0",
"1": "1",
"2": "2",
"3": "3",
"4": "4",
"5": "5",
"in": "IN",
"IN": "IN",
"mm": "MM",
"MM": "MM"
}
if param in self.app.defaults:
try:
value = tcl2py[value]
except KeyError:
pass
self.app.defaults[param] = value
self.app.propagate_defaults(silent=True)
else:
self.raise_tcl_error("No such system parameter \"{}\".".format(param))

View File

@@ -0,0 +1,54 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommand
class TclCommandSkew(TclCommand):
"""
Tcl shell command to skew the object by a an angle over X axis and an angle over Y axes.
example:
skew my_geometry 10.2 3.5
"""
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['skew']
# 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([
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
required = ['name', 'angle_x', 'angle_y']
# structured help for current command, args needs to be ordered
help = {
'main': "Shear/Skew an object by angles along x and y dimensions.",
'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.')
]),
'examples': ['skew my_geometry 10.2 3.5']
}
def execute(self, args, unnamed_args):
"""
:param args:
:param unnamed_args:
:return:
"""
name = args['name']
angle_x = args['angle_x']
angle_y = args['angle_y']
self.app.collection.get_by_name(name).skew(angle_x, angle_y)

View File

@@ -0,0 +1,62 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommandSignaled
class TclCommandSubtractPoly(TclCommandSignaled):
"""
Tcl shell command to create a new empty Geometry object.
"""
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['subtract_poly']
# Dictionary of types from Tcl command, needs to be ordered.
# For positional arguments
arg_names = collections.OrderedDict([
('name', str)
])
# Dictionary of types from Tcl command, needs to be ordered.
# 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': "Subtract polygon from the given Geometry object.",
'args': collections.OrderedDict([
('name', 'Name of the Geometry object from which to subtract.'),
('x0 y0 x1 y1 x2 y2 ...', 'Points defining the polygon.')
]),
'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
"""
obj_name = args['name']
if len(unnamed_args) % 2 != 0:
return "Incomplete coordinate."
points = [[float(unnamed_args[2 * i]), float(unnamed_args[2 * i + 1])] for i in range(len(unnamed_args) / 2)]
try:
obj = self.app.collection.get_by_name(str(obj_name))
except:
return "Could not retrieve object: %s" % obj_name
if obj is None:
return "Object not found: %s" % obj_name
obj.subtract_polygon(points)

View File

@@ -0,0 +1,66 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommandSignaled
class TclCommandSubtractRectangle(TclCommandSignaled):
"""
Tcl shell command to subtract a rectange from the given Geometry object.
"""
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['subtract_rectangle']
# Dictionary of types from Tcl command, needs to be ordered.
# For positional arguments
arg_names = collections.OrderedDict([
('name', str),
('x0', float),
('y0', float),
('x1', float),
('y1', float)
])
# Dictionary of types from Tcl command, needs to be ordered.
# For options like -optionname value
option_types = collections.OrderedDict([
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
required = ['name', 'x0', 'y0', 'x1', 'y1']
# structured help for current command, args needs to be ordered
help = {
'main': "Subtract rectange from the given Geometry object.",
'args': collections.OrderedDict([
('name', 'Name of the Geometry object from which to subtract.'),
('x0 y0', 'Bottom left corner coordinates.'),
('x1 y1', 'Top right corner coordinates.')
]),
'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
"""
obj_name = args['name']
x0 = args['x0']
y0 = args['y0']
x1 = args['x1']
y1 = args['y1']
try:
obj = self.app.collection.get_by_name(str(obj_name))
except:
return "Could not retrieve object: %s" % obj_name
if obj is None:
return "Object not found: %s" % obj_name
obj.subtract_polygon([(x0, y0), (x1, y0), (x1, y1), (x0, y1)])

View File

@@ -0,0 +1,47 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommand
class TclCommandVersion(TclCommand):
"""
Tcl shell command to check the program version.
example:
"""
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['version']
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
])
# 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 = []
# structured help for current command, args needs to be ordered
help = {
'main': "Checks the program version.",
'args': collections.OrderedDict([
]),
'examples': []
}
def execute(self, args, unnamed_args):
"""
:param args:
:param unnamed_args:
:return:
"""
self.app.version_check()

View File

@@ -0,0 +1,90 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommandSignaled
class TclCommandWriteGCode(TclCommandSignaled):
"""
Tcl shell command to save the G-code of a CNC Job object to file.
"""
# array of all command aliases, to be able use
# old names for backward compatibility (add_poly, add_polygon)
aliases = ['write_gcode']
# Dictionary of types from Tcl command, needs to be ordered.
# For positional arguments
arg_names = collections.OrderedDict([
('name', str),
('filename', str)
])
# Dictionary of types from Tcl command, needs to be ordered.
# For options like -optionname value
option_types = collections.OrderedDict([
('preamble', str),
('postamble', str)
])
# array of mandatory options for current Tcl command: required = {'name','outname'}
required = ['name', 'filename']
# structured help for current command, args needs to be ordered
help = {
'main': "Saves G-code of a CNC Job object to file.",
'args': collections.OrderedDict([
('name', 'Source CNC Job object.'),
('filename', 'Output filename.'),
('preamble', 'Text to append at the beginning.'),
('postamble', 'Text to append at the end.')
]),
'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
"""
"""
Requires obj_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.
"""
obj_name = args['name']
filename = args['filename']
preamble = args['preamble'] if 'preamble' in args else ''
postamble = args['postamble'] if 'postamble' in args else ''
# TODO: This is not needed any more? All targets should be present.
# If there are promised objects, wait until all promises have been fulfilled.
# if self.collection.has_promises():
# def write_gcode_on_object(new_object):
# self.log.debug("write_gcode_on_object(): Disconnecting %s" % write_gcode_on_object)
# self.new_object_available.disconnect(write_gcode_on_object)
# write_gcode(obj_name, filename, preamble, postamble)
#
# # Try again when a new object becomes available.
# self.log.debug("write_gcode(): Collection has promises. Queued for %s." % obj_name)
# self.log.debug("write_gcode(): Queued function: %s" % write_gcode_on_object)
# self.new_object_available.connect(write_gcode_on_object)
#
# return
# self.log.debug("write_gcode(): No promises. Continuing for %s." % obj_name)
try:
obj = self.app.collection.get_by_name(str(obj_name))
except:
return "Could not retrieve object: %s" % obj_name
try:
obj.export_gcode(str(filename), str(preamble), str(postamble))
except Exception as e:
return "Operation failed: %s" % str(e)

92
tclCommands/__init__.py Normal file
View File

@@ -0,0 +1,92 @@
import pkgutil
import sys
# Todo: I think these imports are not needed.
# allowed command modules (please append them alphabetically ordered)
import tclCommands.TclCommandAddCircle
import tclCommands.TclCommandAddPolygon
import tclCommands.TclCommandAddPolyline
import tclCommands.TclCommandAddRectangle
import tclCommands.TclCommandAlignDrill
import tclCommands.TclCommandAlignDrillGrid
import tclCommands.TclCommandClearShell
import tclCommands.TclCommandCncjob
import tclCommands.TclCommandCutout
import tclCommands.TclCommandDelete
import tclCommands.TclCommandDrillcncjob
import tclCommands.TclCommandExportGcode
import tclCommands.TclCommandExportSVG
import tclCommands.TclCommandExteriors
import tclCommands.TclCommandGeoCutout
import tclCommands.TclCommandGeoUnion
import tclCommands.TclCommandGetNames
import tclCommands.TclCommandGetSys
import tclCommands.TclCommandImportSvg
import tclCommands.TclCommandInteriors
import tclCommands.TclCommandIsolate
import tclCommands.TclCommandFollow
import tclCommands.TclCommandJoinExcellon
import tclCommands.TclCommandJoinGeometry
import tclCommands.TclCommandListSys
import tclCommands.TclCommandMillHoles
import tclCommands.TclCommandMirror
import tclCommands.TclCommandNew
import tclCommands.TclCommandNewGeometry
import tclCommands.TclCommandOffset
import tclCommands.TclCommandOpenExcellon
import tclCommands.TclCommandOpenGCode
import tclCommands.TclCommandOpenGerber
import tclCommands.TclCommandOpenProject
import tclCommands.TclCommandOptions
import tclCommands.TclCommandPaint
import tclCommands.TclCommandPanelize
import tclCommands.TclCommandPlot
import tclCommands.TclCommandSaveProject
import tclCommands.TclCommandSaveSys
import tclCommands.TclCommandScale
import tclCommands.TclCommandSetActive
import tclCommands.TclCommandSetSys
import tclCommands.TclCommandSkew
import tclCommands.TclCommandSubtractPoly
import tclCommands.TclCommandSubtractRectangle
import tclCommands.TclCommandVersion
import tclCommands.TclCommandWriteGCode
__all__ = []
for loader, name, is_pkg in pkgutil.walk_packages(__path__):
module = loader.find_module(name).load_module(name)
__all__.append(name)
def register_all_commands(app, commands):
"""
Static method which registers all known commands.
Command should be for now in directory tclCommands and module should start with TCLCommand
Class have to follow same name as module.
we need import all modules in top section:
import tclCommands.TclCommandExteriors
at this stage we can include only wanted commands with this, auto loading may be implemented in future
I have no enough knowledge about python's anatomy. Would be nice to include all classes which are descendant etc.
:param app: FlatCAMApp
:param commands: List of commands being updated
:return: None
"""
tcl_modules = {k: v for k, v in list(sys.modules.items()) if k.startswith('tclCommands.TclCommand')}
for key, mod in list(tcl_modules.items()):
if key != 'tclCommands.TclCommand':
class_name = key.split('.')[1]
class_type = getattr(mod, class_name)
command_instance = class_type(app)
for alias in command_instance.aliases:
commands[alias] = {
'fcn': command_instance.execute_wrapper,
'help': command_instance.get_decorated_help()
}