-clean-up before merge
This commit is contained in:
431
tclCommands/TclCommand.py
Normal file
431
tclCommands/TclCommand.py
Normal 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)
|
||||
65
tclCommands/TclCommandAddCircle.py
Normal file
65
tclCommands/TclCommandAddCircle.py
Normal 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))
|
||||
|
||||
61
tclCommands/TclCommandAddPolygon.py
Normal file
61
tclCommands/TclCommandAddPolygon.py
Normal 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()
|
||||
61
tclCommands/TclCommandAddPolyline.py
Normal file
61
tclCommands/TclCommandAddPolyline.py
Normal 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()
|
||||
66
tclCommands/TclCommandAddRectangle.py
Normal file
66
tclCommands/TclCommandAddRectangle.py
Normal 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)])
|
||||
201
tclCommands/TclCommandAlignDrill.py
Normal file
201
tclCommands/TclCommandAlignDrill.py
Normal 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'
|
||||
105
tclCommands/TclCommandAlignDrillGrid.py
Normal file
105
tclCommands/TclCommandAlignDrillGrid.py
Normal 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)
|
||||
46
tclCommands/TclCommandClearShell.py
Normal file
46
tclCommands/TclCommandClearShell.py
Normal 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
|
||||
105
tclCommands/TclCommandCncjob.py
Normal file
105
tclCommands/TclCommandCncjob.py
Normal 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)
|
||||
99
tclCommands/TclCommandCutout.py
Normal file
99
tclCommands/TclCommandCutout.py
Normal 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)
|
||||
54
tclCommands/TclCommandDelete.py
Normal file
54
tclCommands/TclCommandDelete.py
Normal 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)
|
||||
107
tclCommands/TclCommandDrillcncjob.py
Normal file
107
tclCommands/TclCommandDrillcncjob.py
Normal 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)
|
||||
79
tclCommands/TclCommandExportGcode.py
Normal file
79
tclCommands/TclCommandExportGcode.py
Normal 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)
|
||||
52
tclCommands/TclCommandExportSVG.py
Normal file
52
tclCommands/TclCommandExportSVG.py
Normal 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)
|
||||
64
tclCommands/TclCommandExteriors.py
Normal file
64
tclCommands/TclCommandExteriors.py
Normal 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)
|
||||
65
tclCommands/TclCommandFollow.py
Normal file
65
tclCommands/TclCommandFollow.py
Normal 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()
|
||||
128
tclCommands/TclCommandGeoCutout.py
Normal file
128
tclCommands/TclCommandGeoCutout.py
Normal 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)
|
||||
59
tclCommands/TclCommandGeoUnion.py
Normal file
59
tclCommands/TclCommandGeoUnion.py
Normal 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()
|
||||
46
tclCommands/TclCommandGetNames.py
Normal file
46
tclCommands/TclCommandGetNames.py
Normal 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())
|
||||
50
tclCommands/TclCommandGetSys.py
Normal file
50
tclCommands/TclCommandGetSys.py
Normal 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]
|
||||
|
||||
81
tclCommands/TclCommandImportSvg.py
Normal file
81
tclCommands/TclCommandImportSvg.py
Normal 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)
|
||||
|
||||
64
tclCommands/TclCommandInteriors.py
Normal file
64
tclCommands/TclCommandInteriors.py
Normal 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)
|
||||
79
tclCommands/TclCommandIsolate.py
Normal file
79
tclCommands/TclCommandIsolate.py
Normal 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)
|
||||
64
tclCommands/TclCommandJoinExcellon.py
Normal file
64
tclCommands/TclCommandJoinExcellon.py
Normal 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)
|
||||
64
tclCommands/TclCommandJoinGeometry.py
Normal file
64
tclCommands/TclCommandJoinGeometry.py
Normal 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)
|
||||
56
tclCommands/TclCommandListSys.py
Normal file
56
tclCommands/TclCommandListSys.py
Normal 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])
|
||||
91
tclCommands/TclCommandMillHoles.py
Normal file
91
tclCommands/TclCommandMillHoles.py
Normal 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)
|
||||
108
tclCommands/TclCommandMirror.py
Normal file
108
tclCommands/TclCommandMirror.py
Normal 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)
|
||||
39
tclCommands/TclCommandNew.py
Normal file
39
tclCommands/TclCommandNew.py
Normal 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()
|
||||
49
tclCommands/TclCommandNewGeometry.py
Normal file
49
tclCommands/TclCommandNewGeometry.py
Normal 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)
|
||||
53
tclCommands/TclCommandOffset.py
Normal file
53
tclCommands/TclCommandOffset.py
Normal 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))
|
||||
50
tclCommands/TclCommandOpenExcellon.py
Normal file
50
tclCommands/TclCommandOpenExcellon.py
Normal 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)
|
||||
49
tclCommands/TclCommandOpenGCode.py
Normal file
49
tclCommands/TclCommandOpenGCode.py
Normal 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)
|
||||
95
tclCommands/TclCommandOpenGerber.py
Normal file
95
tclCommands/TclCommandOpenGerber.py
Normal 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)
|
||||
47
tclCommands/TclCommandOpenProject.py
Normal file
47
tclCommands/TclCommandOpenProject.py
Normal 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'])
|
||||
50
tclCommands/TclCommandOptions.py
Normal file
50
tclCommands/TclCommandOptions.py
Normal 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])
|
||||
84
tclCommands/TclCommandPaint.py
Normal file
84
tclCommands/TclCommandPaint.py
Normal 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)
|
||||
|
||||
|
||||
154
tclCommands/TclCommandPanelize.py
Normal file
154
tclCommands/TclCommandPanelize.py
Normal 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"
|
||||
46
tclCommands/TclCommandPlot.py
Normal file
46
tclCommands/TclCommandPlot.py
Normal 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()
|
||||
47
tclCommands/TclCommandSaveProject.py
Normal file
47
tclCommands/TclCommandSaveProject.py
Normal 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'])
|
||||
44
tclCommands/TclCommandSaveSys.py
Normal file
44
tclCommands/TclCommandSaveSys.py
Normal 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)
|
||||
51
tclCommands/TclCommandScale.py
Normal file
51
tclCommands/TclCommandScale.py
Normal 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)
|
||||
51
tclCommands/TclCommandSetActive.py
Normal file
51
tclCommands/TclCommandSetActive.py
Normal 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)
|
||||
88
tclCommands/TclCommandSetSys.py
Normal file
88
tclCommands/TclCommandSetSys.py
Normal 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))
|
||||
|
||||
54
tclCommands/TclCommandSkew.py
Normal file
54
tclCommands/TclCommandSkew.py
Normal 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)
|
||||
62
tclCommands/TclCommandSubtractPoly.py
Normal file
62
tclCommands/TclCommandSubtractPoly.py
Normal 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)
|
||||
66
tclCommands/TclCommandSubtractRectangle.py
Normal file
66
tclCommands/TclCommandSubtractRectangle.py
Normal 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)])
|
||||
47
tclCommands/TclCommandVersion.py
Normal file
47
tclCommands/TclCommandVersion.py
Normal 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()
|
||||
|
||||
90
tclCommands/TclCommandWriteGCode.py
Normal file
90
tclCommands/TclCommandWriteGCode.py
Normal 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
92
tclCommands/__init__.py
Normal 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()
|
||||
}
|
||||
Reference in New Issue
Block a user