Merge remote-tracking branch 'upstream/Beta' into Beta
This commit is contained in:
@@ -1,10 +1,9 @@
|
||||
import sys
|
||||
import re
|
||||
import FlatCAMApp
|
||||
import app_Main
|
||||
import abc
|
||||
import collections
|
||||
from PyQt5 import QtCore, QtGui
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5 import QtCore
|
||||
from contextlib import contextmanager
|
||||
|
||||
|
||||
@@ -54,10 +53,12 @@ class TclCommand(object):
|
||||
if self.app is None:
|
||||
raise TypeError('Expected app to be FlatCAMApp instance.')
|
||||
|
||||
if not isinstance(self.app, FlatCAMApp.App):
|
||||
if not isinstance(self.app, app_Main.App):
|
||||
raise TypeError('Expected FlatCAMApp, got %s.' % type(app))
|
||||
|
||||
self.log = self.app.log
|
||||
self.error_info = None
|
||||
self.error = None
|
||||
|
||||
def raise_tcl_error(self, text):
|
||||
"""
|
||||
@@ -70,7 +71,7 @@ class TclCommand(object):
|
||||
:return: none
|
||||
"""
|
||||
|
||||
self.app.raise_tcl_error(text)
|
||||
self.app.shell.raise_tcl_error(text)
|
||||
|
||||
def get_current_command(self):
|
||||
"""
|
||||
@@ -78,9 +79,7 @@ class TclCommand(object):
|
||||
|
||||
:return: current command
|
||||
"""
|
||||
|
||||
command_string = []
|
||||
command_string.append(self.aliases[0])
|
||||
command_string = [self.aliases[0]]
|
||||
|
||||
if self.original_args is not None:
|
||||
for arg in self.original_args:
|
||||
@@ -117,7 +116,7 @@ class TclCommand(object):
|
||||
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 + "<" + type_name + ">"
|
||||
in_command_name = help_key
|
||||
|
||||
elif help_key in self.option_types:
|
||||
@@ -163,35 +162,43 @@ class TclCommand(object):
|
||||
|
||||
@staticmethod
|
||||
def parse_arguments(args):
|
||||
"""
|
||||
Pre-processes arguments to detect '-keyword value' pairs into dictionary
|
||||
and standalone parameters into list.
|
||||
"""
|
||||
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
|
||||
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
|
||||
"""
|
||||
: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
|
||||
options = {}
|
||||
arguments = []
|
||||
n = len(args)
|
||||
|
||||
if name is None:
|
||||
arguments.append(args[i])
|
||||
else:
|
||||
options[name] = args[i]
|
||||
name = None
|
||||
option_name = None
|
||||
|
||||
return arguments, options
|
||||
for i in range(n):
|
||||
match = re.search(r'^-([a-zA-Z].*)', args[i])
|
||||
if match:
|
||||
# assert option_name is None
|
||||
if option_name is not None:
|
||||
options[option_name] = None
|
||||
|
||||
option_name = match.group(1)
|
||||
continue
|
||||
|
||||
if option_name is None:
|
||||
arguments.append(args[i])
|
||||
else:
|
||||
options[option_name] = args[i]
|
||||
option_name = None
|
||||
|
||||
if option_name is not None:
|
||||
options[option_name] = None
|
||||
|
||||
return arguments, options
|
||||
|
||||
def check_args(self, args):
|
||||
"""
|
||||
@@ -202,7 +209,6 @@ class TclCommand(object):
|
||||
"""
|
||||
|
||||
arguments, options = self.parse_arguments(args)
|
||||
|
||||
named_args = {}
|
||||
unnamed_args = []
|
||||
|
||||
@@ -212,6 +218,7 @@ class TclCommand(object):
|
||||
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:
|
||||
@@ -227,7 +234,12 @@ class TclCommand(object):
|
||||
self.raise_tcl_error('Unknown parameter: %s' % key)
|
||||
try:
|
||||
if key != 'timeout':
|
||||
named_args[key] = self.option_types[key](options[key])
|
||||
# None options are allowed; if None then the defaults are used
|
||||
# - must be implemented in the Tcl commands
|
||||
if options[key] is not None:
|
||||
named_args[key] = self.option_types[key](options[key])
|
||||
else:
|
||||
named_args[key] = options[key]
|
||||
else:
|
||||
named_args[key] = int(options[key])
|
||||
except Exception as e:
|
||||
@@ -259,10 +271,10 @@ class TclCommand(object):
|
||||
: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
|
||||
# because of signaling we cannot call error to TCL from here but when task
|
||||
# is finished also non-signaled are handled here to better exception
|
||||
# handling and displayed after command is finished
|
||||
raise self.app.TclErrorException(text)
|
||||
raise self.app.shell.TclErrorException(text)
|
||||
|
||||
def execute_wrapper(self, *args):
|
||||
"""
|
||||
@@ -274,17 +286,16 @@ class TclCommand(object):
|
||||
:return: None, output text or exception
|
||||
"""
|
||||
|
||||
#self.worker_task.emit({'fcn': self.exec_command_test, 'params': [text, False]})
|
||||
|
||||
# self.worker_task.emit({'fcn': self.exec_command_test, 'params': [text, False]})
|
||||
try:
|
||||
self.log.debug("TCL command '%s' executed." % str(self.__class__))
|
||||
self.log.debug("TCL command '%s' executed." % str(type(self).__name__))
|
||||
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.log.error("TCL command '%s' failed. Error text: %s" % (str(self), str(unknown)))
|
||||
self.app.shell.display_tcl_error(unknown, error_info)
|
||||
self.raise_tcl_unknown_error(unknown)
|
||||
|
||||
@abc.abstractmethod
|
||||
@@ -376,7 +387,8 @@ class TclCommandSignaled(TclCommand):
|
||||
|
||||
# Terminate on timeout
|
||||
if timeout is not None:
|
||||
QtCore.QTimer.singleShot(timeout, report_quit)
|
||||
time_val = int(timeout)
|
||||
QtCore.QTimer.singleShot(time_val, report_quit)
|
||||
|
||||
# Block
|
||||
loop.exec_()
|
||||
@@ -387,12 +399,12 @@ class TclCommandSignaled(TclCommand):
|
||||
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>'.")
|
||||
self.app.shell.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.log.debug("TCL command '%s' executed." % str(type(self).__name__))
|
||||
self.original_args = args
|
||||
args, unnamed_args = self.check_args(args)
|
||||
if 'timeout' in args:
|
||||
@@ -402,9 +414,9 @@ class TclCommandSignaled(TclCommand):
|
||||
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())
|
||||
self.app.shell.open_processing(self.get_current_command())
|
||||
|
||||
def handle_finished(obj):
|
||||
def handle_finished():
|
||||
self.app.shell_command_finished.disconnect(handle_finished)
|
||||
if self.error is not None:
|
||||
self.raise_tcl_unknown_error(self.error)
|
||||
@@ -417,7 +429,6 @@ class TclCommandSignaled(TclCommand):
|
||||
# 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:
|
||||
@@ -427,5 +438,5 @@ class TclCommandSignaled(TclCommand):
|
||||
else:
|
||||
error_info = sys.exc_info()
|
||||
self.log.error("TCL command '%s' failed." % str(self))
|
||||
self.app.display_tcl_error(unknown, error_info)
|
||||
self.app.shell.display_tcl_error(unknown, error_info)
|
||||
self.raise_tcl_unknown_error(unknown)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from ObjectCollection import *
|
||||
import collections
|
||||
from tclCommands.TclCommand import TclCommand
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@ class TclCommandAddCircle(TclCommand):
|
||||
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['add_circle']
|
||||
|
||||
description = '%s %s' % ("--", "Creates a circle in the given Geometry object.")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict([
|
||||
('name', str),
|
||||
@@ -38,7 +40,7 @@ class TclCommandAddCircle(TclCommand):
|
||||
('center_y', 'Y coordinates of the center of the circle.'),
|
||||
('radius', 'Radius of the circle.')
|
||||
]),
|
||||
'examples': []
|
||||
'examples': ['add_circle geo_name 1.0 2.0 3']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
@@ -49,17 +51,18 @@ class TclCommandAddCircle(TclCommand):
|
||||
:return:
|
||||
"""
|
||||
|
||||
obj_name = args['name']
|
||||
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
|
||||
obj = self.app.collection.get_by_name(str(name))
|
||||
except Exception:
|
||||
return "Could not retrieve object: %s" % name
|
||||
if obj is None:
|
||||
return "Object not found: %s" % obj_name
|
||||
return "Object not found: %s" % name
|
||||
if obj.kind != 'geometry':
|
||||
self.raise_tcl_error('Expected Geometry, got %s %s.' % (name, type(obj)))
|
||||
|
||||
obj.add_circle([float(center_x), float(center_y)], float(radius))
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
from ObjectCollection import *
|
||||
from tclCommands.TclCommand import *
|
||||
|
||||
|
||||
@@ -10,6 +9,8 @@ class TclCommandAddPolygon(TclCommandSignaled):
|
||||
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['add_polygon', 'add_poly']
|
||||
|
||||
description = '%s %s' % ("--", "Creates a polygon in the given Geometry object.")
|
||||
|
||||
# dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict([
|
||||
('name', str)
|
||||
@@ -49,13 +50,13 @@ class TclCommandAddPolygon(TclCommandSignaled):
|
||||
if obj is None:
|
||||
self.raise_tcl_error("Object not found: %s" % name)
|
||||
|
||||
if not isinstance(obj, Geometry):
|
||||
if obj.kind != '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)]
|
||||
nr_points = int(len(unnamed_args) / 2)
|
||||
points = [[float(unnamed_args[2*i]), float(unnamed_args[2*i+1])] for i in range(nr_points)]
|
||||
|
||||
obj.add_polygon(points)
|
||||
obj.plot()
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from ObjectCollection import *
|
||||
from tclCommands.TclCommand import TclCommandSignaled
|
||||
from tclCommands.TclCommand import *
|
||||
|
||||
|
||||
class TclCommandAddPolyline(TclCommandSignaled):
|
||||
@@ -10,6 +9,8 @@ class TclCommandAddPolyline(TclCommandSignaled):
|
||||
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['add_polyline']
|
||||
|
||||
description = '%s %s' % ("--", "Creates a polyline in the given Geometry object.")
|
||||
|
||||
# dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict([
|
||||
('name', str)
|
||||
@@ -49,13 +50,13 @@ class TclCommandAddPolyline(TclCommandSignaled):
|
||||
if obj is None:
|
||||
self.raise_tcl_error("Object not found: %s" % name)
|
||||
|
||||
if not isinstance(obj, Geometry):
|
||||
if obj.kind != '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)]
|
||||
nr_points = int(len(unnamed_args) / 2)
|
||||
points = [[float(unnamed_args[2*i]), float(unnamed_args[2*i+1])] for i in range(nr_points)]
|
||||
|
||||
obj.add_polyline(points)
|
||||
obj.plot()
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from ObjectCollection import *
|
||||
from tclCommands.TclCommand import TclCommandSignaled
|
||||
from tclCommands.TclCommand import *
|
||||
|
||||
|
||||
class TclCommandAddRectangle(TclCommandSignaled):
|
||||
@@ -10,6 +9,8 @@ class TclCommandAddRectangle(TclCommandSignaled):
|
||||
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['add_rectangle']
|
||||
|
||||
description = '%s %s' % ("--", "Creates a rectangle in the given Geometry object.")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered.
|
||||
# For positional arguments
|
||||
arg_names = collections.OrderedDict([
|
||||
@@ -31,13 +32,13 @@ class TclCommandAddRectangle(TclCommandSignaled):
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': "Add a rectange to the given Geometry object.",
|
||||
'main': "Creates a rectangle in 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': []
|
||||
'examples': ["add_rectangle geo_name 0 0 10 10"]
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
@@ -50,17 +51,23 @@ class TclCommandAddRectangle(TclCommandSignaled):
|
||||
:return: None or exception
|
||||
"""
|
||||
|
||||
obj_name = args['name']
|
||||
name = args['name']
|
||||
x0 = args['x0']
|
||||
y0 = args['y0']
|
||||
x1 = args['x1']
|
||||
y1 = args['y1']
|
||||
|
||||
if unnamed_args:
|
||||
self.raise_tcl_error(
|
||||
"Too many arguments. Correct format: %s" % '["add_rectangle geo_name xmin ymin xmax ymax"]')
|
||||
|
||||
try:
|
||||
obj = self.app.collection.get_by_name(str(obj_name))
|
||||
except:
|
||||
return "Could not retrieve object: %s" % obj_name
|
||||
obj = self.app.collection.get_by_name(str(name))
|
||||
except Exception:
|
||||
return "Could not retrieve object: %s" % name
|
||||
if obj is None:
|
||||
return "Object not found: %s" % obj_name
|
||||
return "Object not found: %s" % name
|
||||
if obj.kind != 'geometry':
|
||||
self.raise_tcl_error('Expected Geometry, got %s %s.' % (name, type(obj)))
|
||||
|
||||
obj.add_polygon([(x0, y0), (x1, y0), (x1, y1), (x0, y1)])
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
from ObjectCollection import *
|
||||
import collections
|
||||
from tclCommands.TclCommand import TclCommandSignaled
|
||||
|
||||
from shapely.geometry import Point
|
||||
import shapely.affinity as affinity
|
||||
|
||||
|
||||
class TclCommandAlignDrill(TclCommandSignaled):
|
||||
"""
|
||||
@@ -11,6 +14,8 @@ class TclCommandAlignDrill(TclCommandSignaled):
|
||||
# backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['aligndrill']
|
||||
|
||||
description = '%s %s' % ("--", "Create an Excellon object with drills for alignment.")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered.
|
||||
# For positional arguments
|
||||
arg_names = collections.OrderedDict([
|
||||
@@ -29,6 +34,7 @@ class TclCommandAlignDrill(TclCommandSignaled):
|
||||
('axisoffset', float),
|
||||
('dia', float),
|
||||
('dist', float),
|
||||
('outname', str),
|
||||
])
|
||||
|
||||
# array of mandatory options for current Tcl command: required = {'name','outname'}
|
||||
@@ -36,20 +42,24 @@ class TclCommandAlignDrill(TclCommandSignaled):
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': "Create excellon with drills for aligment.",
|
||||
'main': "Create an Excellon object with drills for alignment.",
|
||||
'args': collections.OrderedDict([
|
||||
('name', 'Name of the object (Gerber or Excellon) to mirror.'),
|
||||
('dia', 'Tool diameter'),
|
||||
('box', 'Name of object which act as box (cutout for example.)'),
|
||||
('holes', 'Tuple of tuples where each tuple it is a set of x, y coordinates. '
|
||||
'E.g: (x0, y0), (x1, y1), ... '),
|
||||
('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.')
|
||||
('dist', 'Distance of the mirror axis to the X or Y axis.'),
|
||||
('outname', 'Name of the resulting Excellon object.'),
|
||||
]),
|
||||
'examples': []
|
||||
'examples': ['aligndrill my_object -axis X -box my_object -dia 3.125 -grid 1 '
|
||||
'-gridoffset 0 -minoffset 2 -axisoffset 2']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
@@ -64,18 +74,21 @@ class TclCommandAlignDrill(TclCommandSignaled):
|
||||
|
||||
name = args['name']
|
||||
|
||||
if 'outname' in args:
|
||||
outname = args['outname']
|
||||
else:
|
||||
outname = name + "_aligndrill"
|
||||
|
||||
# Get source object.
|
||||
try:
|
||||
obj = self.app.collection.get_by_name(str(name))
|
||||
except:
|
||||
except Exception:
|
||||
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):
|
||||
if obj.kind != "geometry" and obj.kind != 'gerber' and obj.kind != 'excellon':
|
||||
return "ERROR: Only Gerber, Geometry and Excellon objects can be used."
|
||||
|
||||
# Axis
|
||||
@@ -95,8 +108,10 @@ class TclCommandAlignDrill(TclCommandSignaled):
|
||||
|
||||
xscale, yscale = {"X": (1.0, -1.0), "Y": (-1.0, 1.0)}[axis]
|
||||
|
||||
tooldia = args['dia']
|
||||
|
||||
# Tools
|
||||
tools = {"1": {"C": args['dia']}}
|
||||
# tools = {"1": {"C": args['dia']}}
|
||||
|
||||
def alligndrill_init_me(init_obj, app_obj):
|
||||
"""
|
||||
@@ -113,8 +128,8 @@ class TclCommandAlignDrill(TclCommandSignaled):
|
||||
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"})
|
||||
drills.append(point)
|
||||
drills.append(point_mirror)
|
||||
else:
|
||||
if 'box' not in args:
|
||||
return "ERROR: -grid can be used only for -box"
|
||||
@@ -154,18 +169,24 @@ class TclCommandAlignDrill(TclCommandSignaled):
|
||||
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"})
|
||||
drills.append(point)
|
||||
drills.append(point_mirror)
|
||||
|
||||
init_obj.tools = {
|
||||
'1': {
|
||||
'tooldia': tooldia,
|
||||
'drills': drills,
|
||||
'solid_geometry': []
|
||||
}
|
||||
}
|
||||
|
||||
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:
|
||||
except Exception:
|
||||
return "Could not retrieve object box: %s" % args['box']
|
||||
|
||||
if box is None:
|
||||
@@ -176,9 +197,7 @@ class TclCommandAlignDrill(TclCommandSignaled):
|
||||
px = 0.5 * (xmin + xmax)
|
||||
py = 0.5 * (ymin + ymax)
|
||||
|
||||
obj.app.new_object("excellon",
|
||||
name + "_aligndrill",
|
||||
alligndrill_init_me)
|
||||
obj.app.app_obj.new_object("excellon", outname, alligndrill_init_me, plot=False)
|
||||
|
||||
except Exception as e:
|
||||
return "Operation failed: %s" % str(e)
|
||||
@@ -194,8 +213,8 @@ class TclCommandAlignDrill(TclCommandSignaled):
|
||||
try:
|
||||
px = dist
|
||||
py = dist
|
||||
obj.app.new_object("excellon", name + "_alligndrill", alligndrill_init_me)
|
||||
obj.app.app_obj.new_object("excellon", outname, alligndrill_init_me, plot=False)
|
||||
except Exception as e:
|
||||
return "Operation failed: %s" % str(e)
|
||||
|
||||
return 'Ok'
|
||||
return 'Ok. Align Drills Excellon object created'
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from ObjectCollection import *
|
||||
import collections
|
||||
from tclCommands.TclCommand import TclCommandSignaled
|
||||
|
||||
from shapely.geometry import Point
|
||||
|
||||
class TclCommandAlignDrillGrid(TclCommandSignaled):
|
||||
"""
|
||||
@@ -14,10 +15,12 @@ class TclCommandAlignDrillGrid(TclCommandSignaled):
|
||||
# backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['aligndrillgrid']
|
||||
|
||||
description = '%s %s' % ("--", "Create an Excellon object with drills for alignment arranged in a grid.")
|
||||
|
||||
# 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.
|
||||
@@ -29,17 +32,17 @@ class TclCommandAlignDrillGrid(TclCommandSignaled):
|
||||
('gridy', float),
|
||||
('gridoffsety', float),
|
||||
('columns', int),
|
||||
('rows', int)
|
||||
('rows', int),
|
||||
('outname', str)
|
||||
])
|
||||
|
||||
# array of mandatory options for current Tcl command: required = {'name','outname'}
|
||||
required = ['outname', 'gridx', 'gridy', 'columns', 'rows']
|
||||
required = ['gridx', 'gridy', 'columns', 'rows']
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': "Create excellon with drills for aligment grid.",
|
||||
'main': "Create an Excellon object with drills for alignment arranged in a grid.",
|
||||
'args': collections.OrderedDict([
|
||||
('outname', 'Name of the object to create.'),
|
||||
('dia', 'Tool diameter.'),
|
||||
('gridx', 'Grid size in X axis.'),
|
||||
('gridoffsetx', 'Move grid from origin.'),
|
||||
@@ -47,8 +50,9 @@ class TclCommandAlignDrillGrid(TclCommandSignaled):
|
||||
('gridoffsety', 'Move grid from origin.'),
|
||||
('colums', 'Number of grid holes on X axis.'),
|
||||
('rows', 'Number of grid holes on Y axis.'),
|
||||
('outname', 'Name of the object to create.')
|
||||
]),
|
||||
'examples': []
|
||||
'examples': ['aligndrillgrid -rows 2 -columns 2 -gridoffsetx 10 -gridoffsety 10 -gridx 2.54 -gridy 5.08']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
@@ -61,6 +65,11 @@ class TclCommandAlignDrillGrid(TclCommandSignaled):
|
||||
:return: None or exception
|
||||
"""
|
||||
|
||||
if 'outname' in args:
|
||||
outname = args['outname']
|
||||
else:
|
||||
outname = "new_aligndrill_grid"
|
||||
|
||||
if 'gridoffsetx' not in args:
|
||||
gridoffsetx = 0
|
||||
else:
|
||||
@@ -71,8 +80,9 @@ class TclCommandAlignDrillGrid(TclCommandSignaled):
|
||||
else:
|
||||
gridoffsety = args['gridoffsety']
|
||||
|
||||
tooldia = args['dia']
|
||||
# Tools
|
||||
tools = {"1": {"C": args['dia']}}
|
||||
# tools = {"1": {"C": args['dia']}}
|
||||
|
||||
def aligndrillgrid_init_me(init_obj, app_obj):
|
||||
"""
|
||||
@@ -92,14 +102,19 @@ class TclCommandAlignDrillGrid(TclCommandSignaled):
|
||||
|
||||
for col in range(args['columns']):
|
||||
point = Point(currentx + gridoffsetx, currenty + gridoffsety)
|
||||
drills.append({"point": point, "tool": "1"})
|
||||
drills.append(point)
|
||||
currentx = currentx + args['gridx']
|
||||
|
||||
currenty = currenty + args['gridy']
|
||||
|
||||
init_obj.tools = tools
|
||||
init_obj.drills = drills
|
||||
init_obj.tools = {
|
||||
'1': {
|
||||
'tooldia': tooldia,
|
||||
'drills': drills,
|
||||
'solid_geometry': []
|
||||
}
|
||||
}
|
||||
init_obj.create_geometry()
|
||||
|
||||
# Create the new object
|
||||
self.app.new_object("excellon", args['outname'], aligndrillgrid_init_me)
|
||||
self.app.app_obj.new_object("excellon", outname, aligndrillgrid_init_me, plot=False)
|
||||
|
||||
105
tclCommands/TclCommandBbox.py
Normal file
105
tclCommands/TclCommandBbox.py
Normal file
@@ -0,0 +1,105 @@
|
||||
import collections
|
||||
from tclCommands.TclCommand import TclCommand
|
||||
|
||||
from shapely.ops import unary_union
|
||||
|
||||
import gettext
|
||||
import appTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
|
||||
class TclCommandBbox(TclCommand):
|
||||
"""
|
||||
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 = ['bounding_box', 'bbox']
|
||||
|
||||
description = '%s %s' % ("--", "Creates a rectangular Geometry object that surrounds the object.")
|
||||
|
||||
# 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),
|
||||
('margin', float),
|
||||
('rounded', 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 rectangular Geometry object that surrounds the object.",
|
||||
'args': collections.OrderedDict([
|
||||
('name', 'Object name for which to create bounding box. String'),
|
||||
('margin', "Distance of the edges of the box to the nearest polygon."
|
||||
"Float number."),
|
||||
('rounded', "If the bounding box has to have rounded corners their radius is equal to the margin. "
|
||||
"True (1) or False (0)."),
|
||||
('outname', 'Name of the resulting Geometry object. String.')
|
||||
]),
|
||||
'examples': ['bbox name -outname name_bbox']
|
||||
}
|
||||
|
||||
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 + "_bbox"
|
||||
|
||||
obj = self.app.collection.get_by_name(name)
|
||||
if obj is None:
|
||||
self.raise_tcl_error("%s: %s" % (_("Object not found"), name))
|
||||
|
||||
if obj.kind != 'gerber' and obj.kind != 'geometry':
|
||||
self.raise_tcl_error('%s %s: %s.' % (
|
||||
_("Expected GerberObject or GeometryObject, got"), name, type(obj)))
|
||||
|
||||
if 'margin' not in args:
|
||||
args['margin'] = float(self.app.defaults["gerber_bboxmargin"])
|
||||
margin = args['margin']
|
||||
|
||||
if 'rounded' in args:
|
||||
try:
|
||||
par = args['rounded'].capitalize()
|
||||
except AttributeError:
|
||||
par = args['rounded']
|
||||
rounded = bool(eval(par))
|
||||
else:
|
||||
rounded = bool(eval(self.app.defaults["gerber_bboxrounded"]))
|
||||
|
||||
del args['name']
|
||||
|
||||
try:
|
||||
def geo_init(geo_obj, app_obj):
|
||||
# assert geo_obj.kind == 'geometry'
|
||||
|
||||
# Bounding box with rounded corners
|
||||
geo = unary_union(obj.solid_geometry)
|
||||
bounding_box = geo.envelope.buffer(float(margin))
|
||||
if not rounded: # Remove rounded corners
|
||||
bounding_box = bounding_box.envelope
|
||||
geo_obj.solid_geometry = bounding_box
|
||||
|
||||
self.app.app_obj.new_object("geometry", args['outname'], geo_init, plot=False)
|
||||
except Exception as e:
|
||||
return "Operation failed: %s" % str(e)
|
||||
83
tclCommands/TclCommandBounds.py
Normal file
83
tclCommands/TclCommandBounds.py
Normal file
@@ -0,0 +1,83 @@
|
||||
from tclCommands.TclCommand import TclCommand
|
||||
import collections
|
||||
import logging
|
||||
|
||||
import gettext
|
||||
import appTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
log = logging.getLogger('base')
|
||||
|
||||
|
||||
class TclCommandBounds(TclCommand):
|
||||
"""
|
||||
Tcl shell command to return the bounds values for a supplied list of objects (identified by their names).
|
||||
example:
|
||||
|
||||
"""
|
||||
|
||||
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['get_bounds', 'bounds']
|
||||
|
||||
description = '%s %s' % ("--", "Return in the console a list of bounds values for a list of objects.")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict([
|
||||
('objects', 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': "Will return a list of bounds values, each set of bound values is "
|
||||
"a list itself: [xmin, ymin, xmax, ymax] corresponding to each of the provided objects.",
|
||||
'args': collections.OrderedDict([
|
||||
('objects', 'A list of object names separated by comma without spaces.'),
|
||||
]),
|
||||
'examples': ['bounds a_obj.GTL,b_obj.DRL']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
"""
|
||||
|
||||
:param args:
|
||||
:param unnamed_args:
|
||||
:return:
|
||||
"""
|
||||
|
||||
obj_list = []
|
||||
if 'objects' in args:
|
||||
try:
|
||||
obj_list = [str(obj_name) for obj_name in str(args['objects']).split(",") if obj_name != '']
|
||||
except AttributeError as e:
|
||||
log.debug("TclCommandBounds.execute --> %s" % str(e))
|
||||
|
||||
if not obj_list:
|
||||
self.raise_tcl_error('%s: %s:' % (
|
||||
_("Expected a list of objects names separated by comma. Got"), str(args['objects'])))
|
||||
return 'fail'
|
||||
else:
|
||||
self.raise_tcl_error('%s: %s:' % (
|
||||
_("Expected a list of objects names separated by comma. Got"), str(args['objects'])))
|
||||
return 'fail'
|
||||
|
||||
result_list = []
|
||||
for name in obj_list:
|
||||
obj = self.app.collection.get_by_name(name)
|
||||
|
||||
xmin, ymin, xmax, ymax = obj.bounds()
|
||||
result_list.append([xmin, ymin, xmax, ymax])
|
||||
|
||||
self.app.inform.emit('[success] %s ...' % _('TclCommand Bounds done.'))
|
||||
|
||||
return result_list
|
||||
@@ -1,10 +1,17 @@
|
||||
# ##########################################################
|
||||
# FlatCAM: 2D Post-processing for Manufacturing #
|
||||
# File Author: Marius Adrian Stanciu (c) #
|
||||
# Date: 8/17/2019 #
|
||||
# MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
from tclCommands.TclCommand import TclCommand
|
||||
from ObjectCollection import *
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandClearShell(TclCommand):
|
||||
"""
|
||||
Tcl shell command to creates a circle in the given Geometry object.
|
||||
Tcl shell command to clear the text in the Tcl Shell browser.
|
||||
|
||||
example:
|
||||
|
||||
@@ -13,6 +20,8 @@ class TclCommandClearShell(TclCommand):
|
||||
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['clear']
|
||||
|
||||
description = '%s %s' % ("--", "Clear the text in the Tcl Shell.")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict([
|
||||
|
||||
@@ -28,10 +37,10 @@ class TclCommandClearShell(TclCommand):
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': "Clear the text in the Tcl Shell browser.",
|
||||
'main': "Clear the text in the Tcl Shell.",
|
||||
'args': collections.OrderedDict([
|
||||
]),
|
||||
'examples': []
|
||||
'examples': ['clear']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
from ObjectCollection import *
|
||||
from tclCommands.TclCommand import TclCommandSignaled
|
||||
|
||||
import collections
|
||||
from copy import deepcopy
|
||||
|
||||
|
||||
class TclCommandCncjob(TclCommandSignaled):
|
||||
"""
|
||||
@@ -17,6 +19,8 @@ class TclCommandCncjob(TclCommandSignaled):
|
||||
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['cncjob']
|
||||
|
||||
description = '%s %s' % ("--", "Generates a CNC Job object from a Geometry Object.")
|
||||
|
||||
# dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict([
|
||||
('name', str)
|
||||
@@ -24,45 +28,58 @@ class TclCommandCncjob(TclCommandSignaled):
|
||||
|
||||
# dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
|
||||
option_types = collections.OrderedDict([
|
||||
('dia', float),
|
||||
('z_cut', float),
|
||||
('z_move', float),
|
||||
('feedrate', float),
|
||||
('feedrate_z', float),
|
||||
('feedrate_rapid', float),
|
||||
('tooldia', float),
|
||||
('spindlespeed', int),
|
||||
('multidepth', bool),
|
||||
('extracut', bool),
|
||||
('depthperpass', float),
|
||||
('extracut_length', float),
|
||||
('dpp', float),
|
||||
('toolchangez', float),
|
||||
('toolchangexy', str),
|
||||
('startz', float),
|
||||
('endz', float),
|
||||
('ppname_g', str),
|
||||
('endxy', str),
|
||||
('spindlespeed', int),
|
||||
('dwelltime', float),
|
||||
('pp', str),
|
||||
('muted', str),
|
||||
('outname', str)
|
||||
])
|
||||
|
||||
# array of mandatory options for current Tcl command: required = {'name','outname'}
|
||||
required = ['name']
|
||||
required = []
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': "Generates a CNC Job from a Geometry Object.",
|
||||
'main': "Generates a CNC Job object from a Geometry Object.",
|
||||
'args': collections.OrderedDict([
|
||||
('name', 'Name of the source object.'),
|
||||
('tooldia', 'Tool diameter to show on screen.'),
|
||||
('dia', 'Tool diameter to show on screen.'),
|
||||
('z_cut', 'Z-axis cutting position.'),
|
||||
('z_move', 'Z-axis moving position.'),
|
||||
('feedrate', 'Moving speed when cutting.'),
|
||||
('feedrate', 'Moving speed on X-Y plane when cutting.'),
|
||||
('feedrate_z', 'Moving speed on Z plane 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)'),
|
||||
('toolchange', 'Enable tool changes (example: True).'),
|
||||
('toolchangez', 'Z distance for toolchange (example: 30.0).'),
|
||||
('toolchangexy', 'X, Y coordonates for toolchange in format (x, y) (example: (2.0, 3.1) ).'),
|
||||
('extracut_length', 'The value for extra cnccut over the first point in path,in the job end; float'),
|
||||
('dpp', 'If present then use multidepth cnc cut. Height of one layer for multidepth.'),
|
||||
('toolchangez', 'Z distance for toolchange (example: 30.0).\n'
|
||||
'If used in the command then a toolchange event will be included in gcode'),
|
||||
('toolchangexy', 'The X,Y coordinates at Toolchange event in format (x, y) (example: (30.0, 15.2) or '
|
||||
'without parenthesis like: 0.3,1.0). WARNING: no spaces allowed in the value.'),
|
||||
('startz', 'Height before the first move.'),
|
||||
('endz', 'Height where the last move will park.'),
|
||||
('endxy', 'The X,Y coordinates at job end in format (x, y) (example: (2.0, 1.2) or without parenthesis'
|
||||
'like: 0.3,1.0). WARNING: no spaces allowed in the value.'),
|
||||
('spindlespeed', 'Speed of the spindle in rpm (example: 4000).'),
|
||||
('dwelltime', 'Time to pause to allow the spindle to reach the full speed.\n'
|
||||
'If it is not used in command then it will not be included'),
|
||||
('outname', 'Name of the resulting Geometry object.'),
|
||||
('ppname_g', 'Name of the Geometry postprocessor. No quotes, case sensitive')
|
||||
('pp', 'Name of the Geometry preprocessor. No quotes, case sensitive'),
|
||||
('muted', 'It will not put errors in the Shell. Can be True (1) or False (0)')
|
||||
]),
|
||||
'examples': []
|
||||
'examples': ['cncjob geo_name -dia 0.5 -z_cut -1.7 -z_move 2 -feedrate 120 -pp default']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
@@ -75,38 +92,180 @@ class TclCommandCncjob(TclCommandSignaled):
|
||||
:return: None or exception
|
||||
"""
|
||||
|
||||
name = args['name']
|
||||
name = ''
|
||||
|
||||
if 'muted' in args:
|
||||
try:
|
||||
par = args['muted'].capitalize()
|
||||
except AttributeError:
|
||||
par = args['muted']
|
||||
muted = bool(eval(par))
|
||||
else:
|
||||
muted = False
|
||||
|
||||
try:
|
||||
name = args['name']
|
||||
except KeyError:
|
||||
if muted is False:
|
||||
self.raise_tcl_error("Object name is missing")
|
||||
else:
|
||||
return "fail"
|
||||
|
||||
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 muted is False:
|
||||
self.raise_tcl_error("Object not found: %s" % str(name))
|
||||
else:
|
||||
return "fail"
|
||||
|
||||
if not isinstance(obj, FlatCAMGeometry):
|
||||
self.raise_tcl_error('Expected FlatCAMGeometry, got %s %s.' % (str(name), type(obj)))
|
||||
if obj.kind != 'geometry':
|
||||
if muted is False:
|
||||
self.raise_tcl_error('Expected GeometryObject, got %s %s.' % (str(name), type(obj)))
|
||||
else:
|
||||
return
|
||||
|
||||
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"]
|
||||
args["dia"] = args["dia"] if "dia" in args and args["dia"] else self.app.defaults["geometry_cnctooldia"]
|
||||
|
||||
args["toolchange"] = True if "toolchange" in args and args["toolchange"] == 1 else False
|
||||
args["toolchangez"] = args["toolchangez"] if "toolchangez" in args else obj.options["toolchangez"]
|
||||
args["toolchangexy"] = args["toolchangexy"] if "toolchangexy" in args else obj.options["toolchangexy"]
|
||||
args["z_cut"] = args["z_cut"] if "z_cut" in args and args["z_cut"] else self.app.defaults["geometry_cutz"]
|
||||
args["z_move"] = args["z_move"] if "z_move" in args and args["z_move"] else \
|
||||
self.app.defaults["geometry_travelz"]
|
||||
|
||||
args["feedrate"] = args["feedrate"] if "feedrate" in args and args["feedrate"] else \
|
||||
self.app.defaults["geometry_feedrate"]
|
||||
args["feedrate_z"] = args["feedrate_z"] if "feedrate_z" in args and args["feedrate_z"] else \
|
||||
self.app.defaults["geometry_feedrate_z"]
|
||||
args["feedrate_rapid"] = args["feedrate_rapid"] if "feedrate_rapid" in args and args["feedrate_rapid"] else \
|
||||
self.app.defaults["geometry_feedrate_rapid"]
|
||||
|
||||
if "extracut_length" in args:
|
||||
args["extracut"] = True
|
||||
if args["extracut_length"] is None:
|
||||
args["extracut_length"] = 0.0
|
||||
else:
|
||||
args["extracut_length"] = float(args["extracut_length"])
|
||||
else:
|
||||
args["extracut"] = self.app.defaults["geometry_extracut"]
|
||||
args["extracut_length"] = self.app.defaults["geometry_extracut_length"]
|
||||
|
||||
if "dpp" in args:
|
||||
args["multidepth"] = True
|
||||
if args["dpp"] is None:
|
||||
args["dpp"] = self.app.defaults["geometry_depthperpass"]
|
||||
else:
|
||||
args["dpp"] = float(args["dpp"])
|
||||
else:
|
||||
args["multidepth"] = self.app.defaults["geometry_multidepth"]
|
||||
args["dpp"] = self.app.defaults["geometry_depthperpass"]
|
||||
|
||||
args["startz"] = args["startz"] if "startz" in args and args["startz"] else \
|
||||
self.app.defaults["geometry_startz"]
|
||||
args["endz"] = args["endz"] if "endz" in args and args["endz"] else self.app.defaults["geometry_endz"]
|
||||
|
||||
if "endxy" in args and args["endxy"]:
|
||||
args["endxy"] = args["endxy"]
|
||||
else:
|
||||
if self.app.defaults["geometry_endxy"]:
|
||||
args["endxy"] = str(self.app.defaults["geometry_endxy"])
|
||||
else:
|
||||
args["endxy"] = '0, 0'
|
||||
if len(eval(args["endxy"])) != 2:
|
||||
self.raise_tcl_error("The entered value for 'endxy' needs to have the format x,y or "
|
||||
"in format (x, y) - no spaces allowed. But always two comma separated values.")
|
||||
|
||||
args["spindlespeed"] = args["spindlespeed"] if "spindlespeed" in args and args["spindlespeed"] != 0 else None
|
||||
|
||||
if 'dwelltime' in args:
|
||||
args["dwell"] = True
|
||||
if args['dwelltime'] is None:
|
||||
args["dwelltime"] = float(obj.options["dwelltime"])
|
||||
else:
|
||||
args["dwelltime"] = float(args['dwelltime'])
|
||||
else:
|
||||
args["dwell"] = self.app.defaults["geometry_dwell"]
|
||||
args["dwelltime"] = self.app.defaults["geometry_dwelltime"]
|
||||
|
||||
args["pp"] = args["pp"] if "pp" in args and args["pp"] else self.app.defaults["geometry_ppname_g"]
|
||||
|
||||
if "toolchangez" in args:
|
||||
args["toolchange"] = True
|
||||
if args["toolchangez"] is not None:
|
||||
args["toolchangez"] = args["toolchangez"]
|
||||
else:
|
||||
args["toolchangez"] = self.app.defaults["geometry_toolchangez"]
|
||||
else:
|
||||
args["toolchange"] = self.app.defaults["geometry_toolchange"]
|
||||
args["toolchangez"] = self.app.defaults["geometry_toolchangez"]
|
||||
|
||||
if "toolchangexy" in args and args["toolchangexy"]:
|
||||
args["toolchangexy"] = args["toolchangexy"]
|
||||
else:
|
||||
if self.app.defaults["geometry_toolchangexy"]:
|
||||
args["toolchangexy"] = str(self.app.defaults["geometry_toolchangexy"])
|
||||
else:
|
||||
args["toolchangexy"] = '0, 0'
|
||||
if len(eval(args["toolchangexy"])) != 2:
|
||||
self.raise_tcl_error("The entered value for 'toolchangexy' needs to have the format x,y or "
|
||||
"in format (x, y) - no spaces allowed. But always two comma separated values.")
|
||||
|
||||
del args['name']
|
||||
|
||||
for arg in args:
|
||||
if arg == "toolchange_xy" or arg == "spindlespeed" or arg == "startz":
|
||||
continue
|
||||
else:
|
||||
if args[arg] is None:
|
||||
print("None parameters: %s is None" % arg)
|
||||
if muted is False:
|
||||
self.raise_tcl_error('One of the command parameters that have to be not None, is None.\n'
|
||||
'The parameter that is None is in the default values found in the list \n'
|
||||
'generated by the TclCommand "list_sys geom". or in the arguments.')
|
||||
else:
|
||||
return
|
||||
|
||||
# HACK !!! Should be solved elsewhere!!!
|
||||
# default option for multidepth is False
|
||||
obj.options['multidepth'] = False
|
||||
# obj.options['multidepth'] = False
|
||||
|
||||
obj.generatecncjob(use_thread=False, **args)
|
||||
if not obj.multigeo:
|
||||
obj.generatecncjob(use_thread=False, plot=False, **args)
|
||||
else:
|
||||
# Update the local_tools_dict values with the args value
|
||||
local_tools_dict = deepcopy(obj.tools)
|
||||
|
||||
for tool_uid in list(local_tools_dict.keys()):
|
||||
if 'data' in local_tools_dict[tool_uid]:
|
||||
local_tools_dict[tool_uid]['data']['cutz'] = args["z_cut"]
|
||||
local_tools_dict[tool_uid]['data']['travelz'] = args["z_move"]
|
||||
local_tools_dict[tool_uid]['data']['feedrate'] = args["feedrate"]
|
||||
local_tools_dict[tool_uid]['data']['feedrate_z'] = args["feedrate_z"]
|
||||
local_tools_dict[tool_uid]['data']['feedrate_rapid'] = args["feedrate_rapid"]
|
||||
local_tools_dict[tool_uid]['data']['multidepth'] = args["multidepth"]
|
||||
local_tools_dict[tool_uid]['data']['extracut'] = args["extracut"]
|
||||
|
||||
if args["extracut"] is True:
|
||||
local_tools_dict[tool_uid]['data']['extracut_length'] = args["extracut_length"]
|
||||
else:
|
||||
local_tools_dict[tool_uid]['data']['extracut_length'] = None
|
||||
|
||||
local_tools_dict[tool_uid]['data']['depthperpass'] = args["dpp"]
|
||||
local_tools_dict[tool_uid]['data']['toolchange'] = args["toolchange"]
|
||||
local_tools_dict[tool_uid]['data']['toolchangez'] = args["toolchangez"]
|
||||
local_tools_dict[tool_uid]['data']['toolchangexy'] = args["toolchangexy"]
|
||||
local_tools_dict[tool_uid]['data']['startz'] = args["startz"]
|
||||
local_tools_dict[tool_uid]['data']['endz'] = args["endz"]
|
||||
local_tools_dict[tool_uid]['data']['endxy'] = args["endxy"]
|
||||
local_tools_dict[tool_uid]['data']['spindlespeed'] = args["spindlespeed"]
|
||||
local_tools_dict[tool_uid]['data']['dwell'] = args["dwell"]
|
||||
local_tools_dict[tool_uid]['data']['dwelltime'] = args["dwelltime"]
|
||||
local_tools_dict[tool_uid]['data']['ppname_g'] = args["pp"]
|
||||
obj.mtool_gen_cncjob(
|
||||
outname=args['outname'],
|
||||
tools_dict=local_tools_dict,
|
||||
tools_in_use=[],
|
||||
use_thread=False,
|
||||
plot=False)
|
||||
# self.raise_tcl_error('The object is a multi-geo geometry which is not supported in cncjob Tcl Command')
|
||||
|
||||
305
tclCommands/TclCommandCopperClear.py
Normal file
305
tclCommands/TclCommandCopperClear.py
Normal file
@@ -0,0 +1,305 @@
|
||||
from tclCommands.TclCommand import TclCommand
|
||||
|
||||
import collections
|
||||
import logging
|
||||
|
||||
import gettext
|
||||
import appTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
log = logging.getLogger('base')
|
||||
|
||||
|
||||
class TclCommandCopperClear(TclCommand):
|
||||
"""
|
||||
Clear the non-copper areas.
|
||||
"""
|
||||
|
||||
# Array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['ncc_clear', 'ncc']
|
||||
|
||||
description = '%s %s' % ("--", "Clear excess copper.")
|
||||
|
||||
# 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([
|
||||
('tooldia', str),
|
||||
('overlap', float),
|
||||
('order', str),
|
||||
('margin', float),
|
||||
('method', str),
|
||||
('connect', str),
|
||||
('contour', str),
|
||||
('offset', float),
|
||||
('rest', str),
|
||||
('all', int),
|
||||
('ref', str),
|
||||
('box', 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': "Clear excess copper in polygons. Basically it's a negative Paint.",
|
||||
'args': collections.OrderedDict([
|
||||
('name', 'Name of the source Geometry object. String.'),
|
||||
('tooldia', 'Diameter of the tool to be used. Can be a comma separated list of diameters.\n'
|
||||
'WARNING: No space is allowed between tool diameters. E.g: correct: 0.5,1 / incorrect: 0.5, 1'),
|
||||
('overlap', 'Percentage of tool diameter to overlap current pass over previous pass. Float [0, 99.9999]\n'
|
||||
'E.g: for a 25% from tool diameter overlap use -overlap 25'),
|
||||
('margin', 'Bounding box margin. Float number.'),
|
||||
('order', 'Can have the values: "no", "fwd" and "rev". String.'
|
||||
'It is useful when there are multiple tools in tooldia parameter.'
|
||||
'"no" -> the order used is the one provided.'
|
||||
'"fwd" -> tools are ordered from smallest to biggest.'
|
||||
'"rev" -> tools are ordered from biggest to smallest.'),
|
||||
('method', 'Algorithm for copper clearing. Can be: "standard", "seed" or "lines".'),
|
||||
('connect', 'Draw lines to minimize tool lifts. True (1) or False (0)'),
|
||||
('contour', 'Cut around the perimeter of the painting. True (1) or False (0)'),
|
||||
('rest', 'Use rest-machining. True (1) or False (0)'),
|
||||
('offset', 'If used, the copper clearing will finish to a distance from copper features. Float number.'),
|
||||
('all', 'If used will copper clear the whole object. Either "-all" or "-box <value>" has to be used.'),
|
||||
('box', 'Name of the object to be used as reference. Either "-all" or "-box <value>" has to be used. '
|
||||
'String.'),
|
||||
('outname', 'Name of the resulting Geometry object. String. No spaces.'),
|
||||
]),
|
||||
'examples': ["ncc obj_name -tooldia 0.3,1 -overlap 10 -margin 1.0 -method 'lines' -all"]
|
||||
}
|
||||
|
||||
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 Exception as e:
|
||||
log.debug("TclCommandCopperClear.execute() --> %s" % str(e))
|
||||
self.raise_tcl_error("%s: %s" % (_("Could not retrieve object"), name))
|
||||
return "Could not retrieve object: %s" % name
|
||||
|
||||
if obj is None:
|
||||
return "Object not found: %s" % name
|
||||
|
||||
if 'tooldia' in args:
|
||||
tooldia = str(args['tooldia'])
|
||||
else:
|
||||
tooldia = str(self.app.defaults["tools_ncc_tools"])
|
||||
|
||||
if 'overlap' in args:
|
||||
overlap = float(args['overlap']) / 100.0
|
||||
else:
|
||||
overlap = float(self.app.defaults["tools_ncc_overlap"]) / 100.0
|
||||
|
||||
if 'order' in args:
|
||||
order = args['order']
|
||||
else:
|
||||
order = str(self.app.defaults["tools_ncc_order"])
|
||||
|
||||
if 'margin' in args:
|
||||
margin = float(args['margin'])
|
||||
else:
|
||||
margin = float(self.app.defaults["tools_ncc_margin"])
|
||||
|
||||
if 'method' in args:
|
||||
method = args['method']
|
||||
if method == "standard":
|
||||
method_data = 0
|
||||
elif method == "seed":
|
||||
method_data = 1
|
||||
else:
|
||||
method_data = 2
|
||||
else:
|
||||
method = str(self.app.defaults["tools_ncc_method"])
|
||||
method_data = method
|
||||
|
||||
if 'connect' in args:
|
||||
try:
|
||||
par = args['connect'].capitalize()
|
||||
except AttributeError:
|
||||
par = args['connect']
|
||||
connect = bool(eval(par))
|
||||
else:
|
||||
connect = bool(eval(str(self.app.defaults["tools_ncc_connect"])))
|
||||
|
||||
if 'contour' in args:
|
||||
try:
|
||||
par = args['contour'].capitalize()
|
||||
except AttributeError:
|
||||
par = args['contour']
|
||||
contour = bool(eval(par))
|
||||
else:
|
||||
contour = bool(eval(str(self.app.defaults["tools_ncc_contour"])))
|
||||
|
||||
offset = 0.0
|
||||
if 'offset' in args:
|
||||
offset = float(args['offset'])
|
||||
has_offset = True
|
||||
else:
|
||||
has_offset = False
|
||||
|
||||
try:
|
||||
tools = [float(eval(dia)) for dia in tooldia.split(",") if dia != '']
|
||||
except AttributeError:
|
||||
tools = [float(tooldia)]
|
||||
|
||||
if 'rest' in args:
|
||||
try:
|
||||
par = args['rest'].capitalize()
|
||||
except AttributeError:
|
||||
par = args['rest']
|
||||
rest = bool(eval(par))
|
||||
else:
|
||||
rest = bool(eval(str(self.app.defaults["tools_ncc_rest"])))
|
||||
|
||||
if 'outname' in args:
|
||||
outname = args['outname']
|
||||
else:
|
||||
if rest is True:
|
||||
outname = name + "_ncc"
|
||||
else:
|
||||
outname = name + "_ncc_rm"
|
||||
|
||||
# used only to have correct information's in the obj.tools[tool]['data'] dict
|
||||
if "all" in args:
|
||||
select = 0 # 'ITSELF
|
||||
else:
|
||||
select = 2 # 'REFERENCE Object'
|
||||
|
||||
# store here the default data for Geometry Data
|
||||
default_data = {}
|
||||
default_data.update({
|
||||
"name": outname,
|
||||
"plot": False,
|
||||
"cutz": self.app.defaults["geometry_cutz"],
|
||||
"vtipdia": float(self.app.defaults["geometry_vtipdia"]),
|
||||
"vtipangle": float(self.app.defaults["geometry_vtipangle"]),
|
||||
"travelz": self.app.defaults["geometry_travelz"],
|
||||
"feedrate": self.app.defaults["geometry_feedrate"],
|
||||
"feedrate_z": self.app.defaults["geometry_feedrate_z"],
|
||||
"feedrate_rapid": self.app.defaults["geometry_feedrate_rapid"],
|
||||
"dwell": self.app.defaults["geometry_dwell"],
|
||||
"dwelltime": self.app.defaults["geometry_dwelltime"],
|
||||
"multidepth": self.app.defaults["geometry_multidepth"],
|
||||
"ppname_g": self.app.defaults["geometry_ppname_g"],
|
||||
"depthperpass": self.app.defaults["geometry_depthperpass"],
|
||||
"extracut": self.app.defaults["geometry_extracut"],
|
||||
"extracut_length": self.app.defaults["geometry_extracut_length"],
|
||||
"toolchange": self.app.defaults["geometry_toolchange"],
|
||||
"toolchangez": self.app.defaults["geometry_toolchangez"],
|
||||
"endz": self.app.defaults["geometry_endz"],
|
||||
"endxy": self.app.defaults["geometry_endxy"],
|
||||
"spindlespeed": self.app.defaults["geometry_spindlespeed"],
|
||||
"toolchangexy": self.app.defaults["geometry_toolchangexy"],
|
||||
"startz": self.app.defaults["geometry_startz"],
|
||||
|
||||
"area_exclusion": self.app.defaults["geometry_area_exclusion"],
|
||||
"area_shape": self.app.defaults["geometry_area_shape"],
|
||||
"area_strategy": self.app.defaults["geometry_area_strategy"],
|
||||
"area_overz": float(self.app.defaults["geometry_area_overz"]),
|
||||
|
||||
"tooldia": tooldia,
|
||||
"tools_ncc_operation": self.app.defaults["tools_ncc_operation"],
|
||||
|
||||
"tools_ncc_margin": margin,
|
||||
"tools_ncc_method": method_data,
|
||||
"tools_ncc_ref": select,
|
||||
"tools_ncc_connect": connect,
|
||||
"tools_ncc_contour": contour,
|
||||
"tools_ncc_overlap": overlap,
|
||||
|
||||
"tools_ncc_offset_choice": self.app.defaults["tools_ncc_offset_choice"],
|
||||
"tools_ncc_offset_value": self.app.defaults["tools_ncc_offset_value"],
|
||||
"tools_ncc_milling_type": self.app.defaults["tools_ncc_milling_type"]
|
||||
})
|
||||
ncc_tools = {}
|
||||
|
||||
tooluid = 0
|
||||
for tool in tools:
|
||||
tooluid += 1
|
||||
ncc_tools.update({
|
||||
int(tooluid): {
|
||||
'tooldia': float('%.*f' % (obj.decimals, tool)),
|
||||
'offset': 'Path',
|
||||
'offset_value': 0.0,
|
||||
'type': 'Iso',
|
||||
'tool_type': 'C1',
|
||||
'data': dict(default_data),
|
||||
'solid_geometry': []
|
||||
}
|
||||
})
|
||||
ncc_tools[int(tooluid)]['data']['tooldia'] = self.app.dec_format(tool, obj.decimals)
|
||||
|
||||
# Non-Copper clear all polygons in the non-copper clear object
|
||||
if 'all' in args:
|
||||
self.app.ncclear_tool.clear_copper_tcl(ncc_obj=obj,
|
||||
select_method=0, # ITSELF
|
||||
ncctooldia=tooldia,
|
||||
overlap=overlap,
|
||||
order=order,
|
||||
margin=margin,
|
||||
has_offset=has_offset,
|
||||
offset=offset,
|
||||
method=method,
|
||||
outname=outname,
|
||||
connect=connect,
|
||||
contour=contour,
|
||||
rest=rest,
|
||||
tools_storage=ncc_tools,
|
||||
plot=False,
|
||||
run_threaded=False)
|
||||
return
|
||||
|
||||
# Non-Copper clear all polygons found within the box object from the the non_copper cleared object
|
||||
if 'box' in args: # Reference Object
|
||||
box_name = args['box']
|
||||
|
||||
# Get box source object.
|
||||
try:
|
||||
box_obj = self.app.collection.get_by_name(str(box_name))
|
||||
except Exception as e:
|
||||
log.debug("TclCommandCopperClear.execute() --> %s" % str(e))
|
||||
self.raise_tcl_error("%s: %s" % (_("Could not retrieve object"), name))
|
||||
return "Could not retrieve object: %s" % name
|
||||
|
||||
self.app.ncclear_tool.clear_copper_tcl(ncc_obj=obj,
|
||||
sel_obj=box_obj,
|
||||
select_method=2, # REFERENCE OBJECT
|
||||
ncctooldia=tooldia,
|
||||
overlap=overlap,
|
||||
order=order,
|
||||
margin=margin,
|
||||
has_offset=has_offset,
|
||||
offset=offset,
|
||||
method=method,
|
||||
outname=outname,
|
||||
connect=connect,
|
||||
contour=contour,
|
||||
rest=rest,
|
||||
tools_storage=ncc_tools,
|
||||
plot=False,
|
||||
run_threaded=False)
|
||||
return
|
||||
|
||||
# if the program reached this then it's an error because neither -all or -box <value> was used.
|
||||
self.raise_tcl_error('%s' % _("Expected either -box <value> or -all."))
|
||||
return "Expected either -box <value> or -all. Copper clearing failed."
|
||||
@@ -1,8 +1,13 @@
|
||||
from ObjectCollection import *
|
||||
from tclCommands.TclCommand import TclCommand
|
||||
from shapely.ops import cascaded_union
|
||||
|
||||
import collections
|
||||
import logging
|
||||
|
||||
from shapely.ops import unary_union
|
||||
from shapely.geometry import LineString
|
||||
|
||||
log = logging.getLogger('base')
|
||||
|
||||
|
||||
class TclCommandCutout(TclCommand):
|
||||
"""
|
||||
@@ -16,6 +21,8 @@ class TclCommandCutout(TclCommand):
|
||||
# names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['cutout']
|
||||
|
||||
description = '%s %s' % ("--", "Creates board cutout from an object (Gerber or Geometry) with a rectangular shape.")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict([
|
||||
('name', str),
|
||||
@@ -27,7 +34,8 @@ class TclCommandCutout(TclCommand):
|
||||
('dia', float),
|
||||
('margin', float),
|
||||
('gapsize', float),
|
||||
('gaps', str)
|
||||
('gaps', str),
|
||||
('outname', str)
|
||||
])
|
||||
|
||||
# array of mandatory options for current Tcl command: required = {'name','outname'}
|
||||
@@ -35,15 +43,16 @@ class TclCommandCutout(TclCommand):
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': 'Creates board cutout from an object (Gerber or Geometry) with a rectangular shape',
|
||||
'main': 'Creates board cutout from an object (Gerber or Geometry) with a rectangular shape.',
|
||||
'args': collections.OrderedDict([
|
||||
('name', 'Name of the object.'),
|
||||
('dia', 'Tool diameter. Default = 0.1'),
|
||||
('margin', 'Margin over bounds. Default = 0.001'),
|
||||
('gapsize', 'Size of gap. Default = 0.1'),
|
||||
('gaps', "Type of gaps. Can be: 'tb' = top-bottom, 'lr' = left-right and '4' = one each side. Default = 4"),
|
||||
('dia', 'Tool diameter.'),
|
||||
('margin', 'Margin over bounds.'),
|
||||
('gapsize', 'Size of gap.'),
|
||||
('gaps', "Type of gaps. Can be: 'tb' = top-bottom, 'lr' = left-right and '4' = one each side."),
|
||||
('outname', 'Name of the object to create.')
|
||||
]),
|
||||
'examples': []
|
||||
'examples': ['cutout new_geo -dia 1.2 -margin 0.1 -gapsize 1 -gaps "tb" -outname cut_geo']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
@@ -62,24 +71,29 @@ class TclCommandCutout(TclCommand):
|
||||
return
|
||||
|
||||
if 'margin' in args:
|
||||
margin_par = args['margin']
|
||||
margin_par = float(args['margin'])
|
||||
else:
|
||||
margin_par = 0.001
|
||||
margin_par = float(self.app.defaults["tools_cutout_margin"])
|
||||
|
||||
if 'dia' in args:
|
||||
dia_par = args['dia']
|
||||
dia_par = float(args['dia'])
|
||||
else:
|
||||
dia_par = 0.1
|
||||
dia_par = float(self.app.defaults["tools_cutout_tooldia"])
|
||||
|
||||
if 'gaps' in args:
|
||||
gaps_par = args['gaps']
|
||||
else:
|
||||
gaps_par = 4
|
||||
gaps_par = str(self.app.defaults["tools_cutout_gaps_ff"])
|
||||
|
||||
if 'gapsize' in args:
|
||||
gapsize_par = args['gapsize']
|
||||
gapsize_par = float(args['gapsize'])
|
||||
else:
|
||||
gapsize_par = 0.1
|
||||
gapsize_par = float(self.app.defaults["tools_cutout_gapsize"])
|
||||
|
||||
if 'outname' in args:
|
||||
outname = args['outname']
|
||||
else:
|
||||
outname = name + "_cutout"
|
||||
|
||||
try:
|
||||
obj = self.app.collection.get_by_name(str(name))
|
||||
@@ -120,10 +134,10 @@ class TclCommandCutout(TclCommand):
|
||||
[pts[6], pts[7], pts[8]],
|
||||
[pts[9], pts[10], pts[11]]]}
|
||||
cuts = cases[gaps_par]
|
||||
geo_obj.solid_geometry = cascaded_union([LineString(segment) for segment in cuts])
|
||||
geo_obj.solid_geometry = unary_union([LineString(segment) for segment in cuts])
|
||||
|
||||
try:
|
||||
self.app.new_object("geometry", name + "_cutout", geo_init_me)
|
||||
self.app.app_obj.new_object("geometry", outname, geo_init_me, plot=False)
|
||||
self.app.inform.emit("[success] Rectangular-form Cutout operation finished.")
|
||||
except Exception as e:
|
||||
return "Operation failed: %s" % str(e)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from ObjectCollection import *
|
||||
from tclCommands.TclCommand import TclCommand
|
||||
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandDelete(TclCommand):
|
||||
"""
|
||||
@@ -11,7 +12,9 @@ class TclCommandDelete(TclCommand):
|
||||
"""
|
||||
|
||||
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['delete']
|
||||
aliases = ['delete', 'del']
|
||||
|
||||
description = '%s %s' % ("--", "Deletes the given object. If no name is given will delete all objects.")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict([
|
||||
@@ -20,19 +23,25 @@ class TclCommandDelete(TclCommand):
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
|
||||
option_types = collections.OrderedDict([
|
||||
|
||||
('f', str)
|
||||
])
|
||||
|
||||
# array of mandatory options for current Tcl command: required = {'name','outname'}
|
||||
required = ['name']
|
||||
required = []
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': 'Deletes the given object.',
|
||||
'main': 'Deletes the given object. If no name is given will delete all objects.',
|
||||
'args': collections.OrderedDict([
|
||||
('name', 'Name of the Object.'),
|
||||
('f', 'Use this parameter to force deletion.\n'
|
||||
'Can be used without value which will be auto assumed to be True.\n'
|
||||
'Or it can have a value: True (1) or False (0).')
|
||||
]),
|
||||
'examples': []
|
||||
'examples': ['del new_geo -f True\n'
|
||||
'delete new_geo -f 1\n'
|
||||
'del new_geo -f\n'
|
||||
'del new_geo']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
@@ -42,13 +51,39 @@ class TclCommandDelete(TclCommand):
|
||||
:param unnamed_args:
|
||||
:return:
|
||||
"""
|
||||
|
||||
obj_name = args['name']
|
||||
obj_name = None
|
||||
|
||||
try:
|
||||
# deselect all to avoid delete selected object when run delete from shell
|
||||
self.app.collection.set_all_inactive()
|
||||
self.app.collection.set_active(str(obj_name))
|
||||
self.app.on_delete() # Todo: This is an event handler for the GUI... bad?
|
||||
except Exception as e:
|
||||
return "Command failed: %s" % str(e)
|
||||
obj_name = args['name']
|
||||
delete_all = False
|
||||
except KeyError:
|
||||
delete_all = True
|
||||
|
||||
is_forced = False
|
||||
if 'f' in args:
|
||||
try:
|
||||
if args['f'] is None:
|
||||
is_forced = True
|
||||
else:
|
||||
try:
|
||||
par = args['f'].capitalize()
|
||||
except AttributeError:
|
||||
par = args['f']
|
||||
is_forced = bool(eval(par))
|
||||
except KeyError:
|
||||
is_forced = True
|
||||
|
||||
if delete_all is False:
|
||||
try:
|
||||
# deselect all to avoid delete selected object when run delete from shell
|
||||
self.app.collection.set_all_inactive()
|
||||
self.app.collection.set_active(str(obj_name))
|
||||
self.app.on_delete(force_deletion=is_forced)
|
||||
except Exception as e:
|
||||
return "Command failed: %s" % str(e)
|
||||
else:
|
||||
try:
|
||||
self.app.collection.set_all_active()
|
||||
self.app.on_delete(force_deletion=is_forced)
|
||||
except Exception as e:
|
||||
return "Command failed: %s" % str(e)
|
||||
|
||||
@@ -1,6 +1,16 @@
|
||||
from ObjectCollection import *
|
||||
from tclCommands.TclCommand import TclCommandSignaled
|
||||
|
||||
import collections
|
||||
import math
|
||||
|
||||
import gettext
|
||||
import appTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
|
||||
class TclCommandDrillcncjob(TclCommandSignaled):
|
||||
"""
|
||||
@@ -10,6 +20,8 @@ class TclCommandDrillcncjob(TclCommandSignaled):
|
||||
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['drillcncjob']
|
||||
|
||||
description = '%s %s' % ("--", "Generates a Drill CNC Job object from a Excellon Object.")
|
||||
|
||||
# dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict([
|
||||
('name', str)
|
||||
@@ -17,18 +29,24 @@ class TclCommandDrillcncjob(TclCommandSignaled):
|
||||
|
||||
# dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
|
||||
option_types = collections.OrderedDict([
|
||||
('tools', str),
|
||||
('drilled_dias', str),
|
||||
('drillz', float),
|
||||
('dpp', float),
|
||||
('travelz', float),
|
||||
('feedrate', float),
|
||||
('feedrate_z', float),
|
||||
('feedrate_rapid', float),
|
||||
('spindlespeed', int),
|
||||
('toolchange', bool),
|
||||
('toolchangez', float),
|
||||
('toolchangexy', str),
|
||||
('startz', float),
|
||||
('endz', float),
|
||||
('ppname_e', str),
|
||||
('outname', str),
|
||||
('opt_type', str)
|
||||
('endxy', str),
|
||||
('dwelltime', float),
|
||||
('pp', str),
|
||||
('opt_type', str),
|
||||
('diatol', float),
|
||||
('muted', str),
|
||||
('outname', str)
|
||||
])
|
||||
|
||||
# array of mandatory options for current Tcl command: required = {'name','outname'}
|
||||
@@ -39,24 +57,41 @@ class TclCommandDrillcncjob(TclCommandSignaled):
|
||||
'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).'),
|
||||
('drilled_dias',
|
||||
'Comma separated tool diameters of the drills to be drilled (example: 0.6,1.0 or 3.125). '
|
||||
'WARNING: No space allowed'),
|
||||
('drillz', 'Drill depth into material (example: -2.0). Negative value.'),
|
||||
('dpp', 'Progressive drilling into material with a specified step (example: 0.7). Positive value.'),
|
||||
('travelz', 'Travel distance above material (example: 2.0).'),
|
||||
('feedrate', 'Drilling feed rate.'),
|
||||
('feedrate_z', 'Drilling feed rate. It is the speed on the Z axis.'),
|
||||
('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).'),
|
||||
('toolchangexy', 'X, Y coordonates for toolchange in format (x, y) (example: (2.0, 3.1) ).'),
|
||||
('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')
|
||||
('toolchangez', 'Z distance for toolchange (example: 30.0).\n'
|
||||
'If used in the command then a toolchange event will be included in gcode'),
|
||||
('toolchangexy', 'The X,Y coordinates at Toolchange event in format (x, y) (example: (30.0, 15.2) or '
|
||||
'without parenthesis like: 0.3,1.0). WARNING: no spaces allowed in the value.'),
|
||||
('startz', 'The Z coordinate at job start (example: 30.0).'),
|
||||
('endz', 'The Z coordinate at job end (example: 30.0).'),
|
||||
('endxy', 'The X,Y coordinates at job end in format (x, y) (example: (2.0, 1.2) or without parenthesis'
|
||||
'like: 0.3,1.0). WARNING: no spaces allowed in the value.'),
|
||||
('dwelltime', 'Time to pause to allow the spindle to reach the full speed.\n'
|
||||
'If it is not used in command then it will not be included'),
|
||||
('pp', 'This is the Excellon preprocessor name: case_sensitive, no_quotes'),
|
||||
('opt_type', 'Name of move optimization type. B by default for Basic OR-Tools, M for Metaheuristic OR-Tools'
|
||||
'T from Travelling Salesman Algorithm. B and M works only for 64bit version of FlatCAM and '
|
||||
'T works only for 32bit version of FlatCAM'),
|
||||
('diatol', 'Tolerance. Percentange (0.0 ... 100.0) within which dias in drilled_dias will be judged to be '
|
||||
'the same as the ones in the tools from the Excellon object. E.g: if in drill_dias we have a '
|
||||
'diameter with value 1.0, in the Excellon we have a tool with dia = 1.05 and we set a tolerance '
|
||||
'diatol = 5.0 then the drills with the dia = (0.95 ... 1.05) '
|
||||
'in Excellon will be processed. Float number.'),
|
||||
('muted', 'It will not put errors in the Shell or status bar. Can be True (1) or False (0).'),
|
||||
('outname', 'Name of the resulting Geometry object.')
|
||||
]),
|
||||
'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-.']
|
||||
'examples': ['drillcncjob test.TXT -drillz -1.5 -travelz 14 -feedrate_z 222 -feedrate_rapid 456 '
|
||||
'-spindlespeed 777 -toolchangez 33 -endz 22 -pp default\n'
|
||||
'Usage of -feedrate_rapid matter only when the preprocessor is using it, like -marlin-.',
|
||||
'drillcncjob test.DRL -drillz -1.7 -dpp 0.5 -travelz 2 -feedrate_z 800 -endxy 3,3']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
@@ -71,15 +106,31 @@ class TclCommandDrillcncjob(TclCommandSignaled):
|
||||
|
||||
name = args['name']
|
||||
|
||||
obj = self.app.collection.get_by_name(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 'muted' in args:
|
||||
try:
|
||||
par = args['muted'].capitalize()
|
||||
except AttributeError:
|
||||
par = args['muted']
|
||||
muted = bool(eval(par))
|
||||
else:
|
||||
muted = False
|
||||
|
||||
if not isinstance(obj, FlatCAMExcellon):
|
||||
self.raise_tcl_error('Expected FlatCAMExcellon, got %s %s.' % (name, type(obj)))
|
||||
if obj is None:
|
||||
if muted is False:
|
||||
self.raise_tcl_error("Object not found: %s" % name)
|
||||
else:
|
||||
return "fail"
|
||||
|
||||
if obj.kind != 'excellon':
|
||||
if muted is False:
|
||||
self.raise_tcl_error('Expected ExcellonObject, got %s %s.' % (name, type(obj)))
|
||||
else:
|
||||
return "fail"
|
||||
|
||||
xmin = obj.options['xmin']
|
||||
ymin = obj.options['ymin']
|
||||
@@ -87,42 +138,213 @@ class TclCommandDrillcncjob(TclCommandSignaled):
|
||||
ymax = obj.options['ymax']
|
||||
|
||||
def job_init(job_obj, app_obj):
|
||||
# tools = args["tools"] if "tools" in args else 'all'
|
||||
|
||||
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"]
|
||||
try:
|
||||
if 'drilled_dias' in args and args['drilled_dias'] != 'all':
|
||||
diameters = [x.strip() for x in args['drilled_dias'].split(",") if x != '']
|
||||
nr_diameters = len(diameters)
|
||||
|
||||
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"]
|
||||
req_tools = set()
|
||||
for tool in obj.tools:
|
||||
for req_dia in diameters:
|
||||
obj_dia_form = float('%.*f' % (obj.decimals, float(obj.tools[tool]["C"])))
|
||||
req_dia_form = float('%.*f' % (obj.decimals, float(req_dia)))
|
||||
|
||||
job_obj.coords_decimals = int(self.app.defaults["cncjob_coords_decimals"])
|
||||
job_obj.fr_decimals = int(self.app.defaults["cncjob_fr_decimals"])
|
||||
if 'diatol' in args:
|
||||
tolerance = args['diatol'] / 100
|
||||
|
||||
tolerance = 0.0 if tolerance < 0.0 else tolerance
|
||||
tolerance = 1.0 if tolerance > 1.0 else tolerance
|
||||
if math.isclose(obj_dia_form, req_dia_form, rel_tol=tolerance):
|
||||
req_tools.add(tool)
|
||||
nr_diameters -= 1
|
||||
else:
|
||||
if obj_dia_form == req_dia_form:
|
||||
req_tools.add(tool)
|
||||
nr_diameters -= 1
|
||||
|
||||
if nr_diameters > 0:
|
||||
if muted is False:
|
||||
self.raise_tcl_error("One or more tool diameters of the drills to be drilled passed to the "
|
||||
"TclCommand are not actual tool diameters in the Excellon object.")
|
||||
else:
|
||||
return "fail"
|
||||
|
||||
# make a string of diameters separated by comma; this is what generate_from_excellon_by_tool() is
|
||||
# expecting as tools parameter
|
||||
tools = ','.join(req_tools)
|
||||
|
||||
# no longer needed
|
||||
del args['drilled_dias']
|
||||
del args['diatol']
|
||||
|
||||
# Split and put back. We are passing the whole dictionary later.
|
||||
# args['milled_dias'] = [x.strip() for x in args['tools'].split(",")]
|
||||
else:
|
||||
tools = 'all'
|
||||
except Exception as e:
|
||||
tools = 'all'
|
||||
|
||||
if muted is False:
|
||||
self.raise_tcl_error("Bad tools: %s" % str(e))
|
||||
else:
|
||||
return "fail"
|
||||
|
||||
used_tools_info = []
|
||||
used_tools_info.insert(0, [_("Tool_nr"), _("Diameter"), _("Drills_Nr"), _("Slots_Nr")])
|
||||
|
||||
# populate the information's list for used tools
|
||||
if tools == 'all':
|
||||
sort = []
|
||||
for k, v in list(obj.tools.items()):
|
||||
sort.append((k, v.get('tooldia')))
|
||||
sorted_tools = sorted(sort, key=lambda t1: t1[1])
|
||||
use_tools = [i[0] for i in sorted_tools]
|
||||
|
||||
for tool_no in use_tools:
|
||||
tool_dia_used = obj.tools[tool_no]['tooldia']
|
||||
|
||||
drill_cnt = 0 # variable to store the nr of drills per tool
|
||||
slot_cnt = 0 # variable to store the nr of slots per tool
|
||||
|
||||
# Find no of drills for the current tool
|
||||
if 'drills' in obj.tools[tool_no] and obj.tools[tool_no]['drills']:
|
||||
drill_cnt = len(obj.tools[tool_no]['drills'])
|
||||
|
||||
# Find no of slots for the current tool
|
||||
if 'slots' in obj.tools[tool_no] and obj.tools[tool_no]['slots']:
|
||||
slot_cnt = len(obj.tools[tool_no]['slots'])
|
||||
|
||||
used_tools_info.append([str(tool_no), str(tool_dia_used), str(drill_cnt), str(slot_cnt)])
|
||||
|
||||
drillz = args["drillz"] if "drillz" in args and args["drillz"] is not None else \
|
||||
obj.options["tools_drill_cutz"]
|
||||
|
||||
if "toolchangez" in args:
|
||||
toolchange = True
|
||||
if args["toolchangez"] is not None:
|
||||
toolchangez = args["toolchangez"]
|
||||
else:
|
||||
toolchangez = obj.options["tools_drill_toolchangez"]
|
||||
else:
|
||||
toolchange = self.app.defaults["tools_drill_toolchange"]
|
||||
toolchangez = float(self.app.defaults["tools_drill_toolchangez"])
|
||||
|
||||
if "toolchangexy" in args and args["tools_drill_toolchangexy"]:
|
||||
xy_toolchange = args["toolchangexy"]
|
||||
else:
|
||||
if self.app.defaults["tools_drill_toolchangexy"]:
|
||||
xy_toolchange = str(self.app.defaults["tools_drill_toolchangexy"])
|
||||
else:
|
||||
xy_toolchange = '0, 0'
|
||||
if len(eval(xy_toolchange)) != 2:
|
||||
self.raise_tcl_error("The entered value for 'toolchangexy' needs to have the format x,y or "
|
||||
"in format (x, y) - no spaces allowed. But always two comma separated values.")
|
||||
|
||||
endz = args["endz"] if "endz" in args and args["endz"] is not None else \
|
||||
self.app.defaults["tools_drill_endz"]
|
||||
|
||||
if "endxy" in args and args["endxy"]:
|
||||
xy_end = args["endxy"]
|
||||
else:
|
||||
if self.app.defaults["tools_drill_endxy"]:
|
||||
xy_end = str(self.app.defaults["tools_drill_endxy"])
|
||||
else:
|
||||
xy_end = '0, 0'
|
||||
|
||||
if len(eval(xy_end)) != 2:
|
||||
self.raise_tcl_error("The entered value for 'xy_end' needs to have the format x,y or "
|
||||
"in format (x, y) - no spaces allowed. But always two comma separated values.")
|
||||
|
||||
opt_type = args["opt_type"] if "opt_type" in args and args["opt_type"] else 'B'
|
||||
|
||||
# ##########################################################################################
|
||||
# ################# Set parameters #########################################################
|
||||
# ##########################################################################################
|
||||
job_obj.origin_kind = 'excellon'
|
||||
|
||||
job_obj.options['Tools_in_use'] = used_tools_info
|
||||
job_obj.options['type'] = 'Excellon'
|
||||
|
||||
toolchange = True if "toolchange" in args and args["toolchange"] == 1 else False
|
||||
toolchangez = args["toolchangez"] if "toolchangez" in args else obj.options["toolchangez"]
|
||||
job_obj.toolchangexy = args["toolchangexy"] if "toolchangexy" in args else obj.options["toolchangexy"]
|
||||
pp_excellon_name = args["pp"] if "pp" in args and args["pp"] else self.app.defaults["tools_drill_ppname_e"]
|
||||
job_obj.pp_excellon_name = pp_excellon_name
|
||||
job_obj.options['ppname_e'] = pp_excellon_name
|
||||
|
||||
if 'dpp' in args:
|
||||
job_obj.multidepth = True
|
||||
if args['dpp'] is not None:
|
||||
job_obj.z_depthpercut = float(args['dpp'])
|
||||
else:
|
||||
job_obj.z_depthpercut = float(obj.options["dpp"])
|
||||
else:
|
||||
job_obj.multidepth = self.app.defaults["tools_drill_multidepth"]
|
||||
job_obj.z_depthpercut = self.app.defaults["tools_drill_depthperpass"]
|
||||
|
||||
job_obj.z_move = float(args["travelz"]) if "travelz" in args and args["travelz"] else \
|
||||
self.app.defaults["tools_drill_travelz"]
|
||||
|
||||
job_obj.feedrate = float(args["feedrate_z"]) if "feedrate_z" in args and args["feedrate_z"] else \
|
||||
self.app.defaults["tools_drill_feedrate_z"]
|
||||
job_obj.z_feedrate = float(args["feedrate_z"]) if "feedrate_z" in args and args["feedrate_z"] else \
|
||||
self.app.defaults["tools_drill_feedrate_z"]
|
||||
|
||||
job_obj.feedrate_rapid = float(args["feedrate_rapid"]) \
|
||||
if "feedrate_rapid" in args and args["feedrate_rapid"] else \
|
||||
self.app.defaults["tools_drill_feedrate_rapid"]
|
||||
|
||||
job_obj.spindlespeed = float(args["spindlespeed"]) if "spindlespeed" in args else None
|
||||
job_obj.spindledir = self.app.defaults['tools_drill_spindlespeed']
|
||||
if 'dwelltime' in args:
|
||||
job_obj.dwell = True
|
||||
if args['dwelltime'] is not None:
|
||||
job_obj.dwelltime = float(args['dwelltime'])
|
||||
else:
|
||||
job_obj.dwelltime = float(self.app.defaults["tools_drill_dwelltime"])
|
||||
else:
|
||||
job_obj.dwell = self.app.defaults["tools_drill_dwell"]
|
||||
job_obj.dwelltime = self.app.defaults["tools_drill_dwelltime"]
|
||||
|
||||
job_obj.toolchange_xy_type = "excellon"
|
||||
job_obj.coords_decimals = int(self.app.defaults["cncjob_coords_decimals"])
|
||||
job_obj.fr_decimals = int(self.app.defaults["cncjob_fr_decimals"])
|
||||
|
||||
job_obj.options['xmin'] = xmin
|
||||
job_obj.options['ymin'] = ymin
|
||||
job_obj.options['xmax'] = xmax
|
||||
job_obj.options['ymax'] = ymax
|
||||
|
||||
endz = args["endz"] if "endz" in args else obj.options["endz"]
|
||||
job_obj.z_cut = float(drillz)
|
||||
job_obj.toolchange = toolchange
|
||||
job_obj.xy_toolchange = xy_toolchange
|
||||
job_obj.z_toolchange = float(toolchangez)
|
||||
|
||||
tools = args["tools"] if "tools" in args else 'all'
|
||||
opt_type = args["opt_type"] if "opt_type" in args else 'B'
|
||||
if "startz" in args and args["startz"] is not None:
|
||||
job_obj.startz = float(args["startz"])
|
||||
else:
|
||||
if self.app.defaults["tools_drill_startz"]:
|
||||
job_obj.startz = self.app.defaults["tools_drill_startz"]
|
||||
else:
|
||||
job_obj.startz = self.app.defaults["tools_drill_travelz"]
|
||||
|
||||
job_obj.endz = float(endz)
|
||||
job_obj.xy_end = xy_end
|
||||
job_obj.excellon_optimization_type = opt_type
|
||||
job_obj.spindledir = self.app.defaults["tools_drill_spindledir"]
|
||||
|
||||
ret_val = job_obj.generate_from_excellon_by_tool(obj, tools, use_ui=False)
|
||||
job_obj.source_file = ret_val
|
||||
|
||||
if ret_val == 'fail':
|
||||
return 'fail'
|
||||
job_obj.gc_start = ret_val[1]
|
||||
|
||||
for t_item in job_obj.exc_cnc_tools:
|
||||
job_obj.exc_cnc_tools[t_item]['data']['tools_drill_offset'] = \
|
||||
float(job_obj.exc_cnc_tools[t_item]['offset_z']) + float(drillz)
|
||||
job_obj.exc_cnc_tools[t_item]['data']['tools_drill_ppname_e'] = job_obj.options['ppname_e']
|
||||
|
||||
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)
|
||||
self.app.app_obj.new_object("cncjob", args['outname'], job_init, plot=False)
|
||||
|
||||
52
tclCommands/TclCommandExportDXF.py
Normal file
52
tclCommands/TclCommandExportDXF.py
Normal file
@@ -0,0 +1,52 @@
|
||||
from tclCommands.TclCommand import TclCommand
|
||||
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandExportDXF(TclCommand):
|
||||
"""
|
||||
Tcl shell command to export a Geometry Object as an DXF File.
|
||||
|
||||
example:
|
||||
export_dxf path/my_geometry filename
|
||||
"""
|
||||
|
||||
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['export_dxf', 'edxf']
|
||||
|
||||
description = '%s %s' % ("--", "Export a Geometry object as a DXF File.")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict([
|
||||
('name', str),
|
||||
('filename', 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 = ['obj_name']
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': "Export a Geometry object as a DXF File.",
|
||||
'args': collections.OrderedDict([
|
||||
('name', 'Name of the Geometry object to export.'),
|
||||
('filename', 'Absolute path to file to export.\n'
|
||||
'WARNING: no spaces are allowed. If unsure enclose the entire path with quotes.'),
|
||||
]),
|
||||
'examples': ['export_dxf my_geo path/my_file.dxf', 'export_dxf my_geo D:/my_file.dxf']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
"""
|
||||
|
||||
:param args:
|
||||
:param unnamed_args:
|
||||
:return:
|
||||
"""
|
||||
if 'filename' not in args:
|
||||
args['filename'] = self.app.defaults["global_last_save_folder"] + '/' + args['name']
|
||||
self.app.f_handlers.export_dxf(use_thread=False, local_use=None, **args)
|
||||
52
tclCommands/TclCommandExportExcellon.py
Normal file
52
tclCommands/TclCommandExportExcellon.py
Normal file
@@ -0,0 +1,52 @@
|
||||
from tclCommands.TclCommand import TclCommand
|
||||
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandExportExcellon(TclCommand):
|
||||
"""
|
||||
Tcl shell command to export a Excellon Object as an Excellon File.
|
||||
|
||||
example:
|
||||
export_exc path/my_excellon filename
|
||||
"""
|
||||
|
||||
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['export_exc', 'ee', 'export_excellon']
|
||||
|
||||
description = '%s %s' % ("--", "Export a Excellon object as a Excellon File.")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict([
|
||||
('name', str),
|
||||
('filename', 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 a Excellon object as a Excellon File.",
|
||||
'args': collections.OrderedDict([
|
||||
('name', 'Name of the Excellon object to export.'),
|
||||
('filename', 'Absolute path to file to export.\n'
|
||||
'WARNING: no spaces are allowed. If unsure enclose the entire path with quotes.'),
|
||||
]),
|
||||
'examples': ['export_excellon my_excellon path/my_file.drl', 'export_excellon My_Excellon D:/drill_file.DRL']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
"""
|
||||
|
||||
:param args:
|
||||
:param unnamed_args:
|
||||
:return:
|
||||
"""
|
||||
if 'filename' not in args:
|
||||
args['filename'] = self.app.defaults["global_last_save_folder"] + '/' + args['name']
|
||||
self.app.f_handlers.export_excellon(use_thread=False, **args)
|
||||
@@ -1,5 +1,7 @@
|
||||
from ObjectCollection import *
|
||||
from tclCommands.TclCommand import TclCommandSignaled
|
||||
from camlib import CNCjob
|
||||
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandExportGcode(TclCommandSignaled):
|
||||
@@ -11,7 +13,7 @@ class TclCommandExportGcode(TclCommandSignaled):
|
||||
promises and send to background if there are promises.
|
||||
|
||||
|
||||
This export may be captured and passed as preable
|
||||
This export may be captured and passed as preamble
|
||||
to another "export_gcode" or "write_gcode" call to join G-Code.
|
||||
|
||||
example:
|
||||
@@ -29,11 +31,13 @@ class TclCommandExportGcode(TclCommandSignaled):
|
||||
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['export_gcode']
|
||||
|
||||
description = '%s %s' % ("--", "Return Gcode into console output.")
|
||||
|
||||
# dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict([
|
||||
('name', str),
|
||||
('preamble', str),
|
||||
('postamble', str)
|
||||
('postamble', str),
|
||||
])
|
||||
|
||||
# dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
|
||||
@@ -46,11 +50,11 @@ class TclCommandExportGcode(TclCommandSignaled):
|
||||
help = {
|
||||
'main': "Export gcode into console output.",
|
||||
'args': collections.OrderedDict([
|
||||
('name', 'Name of the source Geometry object.'),
|
||||
('preamble', 'Prepend GCODE.'),
|
||||
('postamble', 'Append GCODE.')
|
||||
('name', 'Name of the source Geometry object. Required.'),
|
||||
('preamble', 'Prepend GCode to the original GCode.'),
|
||||
('postamble', 'Append GCode o the original GCode.'),
|
||||
]),
|
||||
'examples': []
|
||||
'examples': ['export_gcode geo_name -preamble "G01 X10 Y10" -postamble "G00 X20 Y20\nM04"']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
@@ -76,4 +80,5 @@ class TclCommandExportGcode(TclCommandSignaled):
|
||||
self.raise_tcl_error('!!!Promises exists, but should not here!!!')
|
||||
|
||||
del args['name']
|
||||
return obj.get_gcode(**args)
|
||||
obj.get_gcode(**args)
|
||||
return
|
||||
|
||||
52
tclCommands/TclCommandExportGerber.py
Normal file
52
tclCommands/TclCommandExportGerber.py
Normal file
@@ -0,0 +1,52 @@
|
||||
from tclCommands.TclCommand import TclCommand
|
||||
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandExportGerber(TclCommand):
|
||||
"""
|
||||
Tcl shell command to export a Gerber Object as an Gerber File.
|
||||
|
||||
example:
|
||||
export_exc path/my_excellon filename
|
||||
"""
|
||||
|
||||
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['export_grb', 'egr', 'export_gerber']
|
||||
|
||||
description = '%s %s' % ("--", "Export a Gerber object as a Gerber File.")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict([
|
||||
('name', str),
|
||||
('filename', 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 = ['obj_name']
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': "Export a Gerber Object as a Gerber File.",
|
||||
'args': collections.OrderedDict([
|
||||
('name', 'Name of the object to export. Required.'),
|
||||
('filename', 'Absolute path to file to export.\n'
|
||||
'WARNING: no spaces are allowed. If unsure enclose the entire path with quotes.'),
|
||||
]),
|
||||
'examples': ['export_gerber my_gerber path/my_file.gbr']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
"""
|
||||
|
||||
:param args:
|
||||
:param unnamed_args:
|
||||
:return:
|
||||
"""
|
||||
if 'filename' not in args:
|
||||
args['filename'] = self.app.defaults["global_last_save_folder"] + '/' + args['name']
|
||||
self.app.f_handlers.export_gerber(use_thread=False, **args)
|
||||
@@ -1,6 +1,7 @@
|
||||
from ObjectCollection import *
|
||||
from tclCommands.TclCommand import TclCommand
|
||||
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandExportSVG(TclCommand):
|
||||
"""
|
||||
@@ -13,16 +14,18 @@ class TclCommandExportSVG(TclCommand):
|
||||
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['export_svg']
|
||||
|
||||
description = '%s %s' % ("--", "Export a Geometry object as a SVG File.")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict([
|
||||
('name', str),
|
||||
('filename', str),
|
||||
('scale_factor', float)
|
||||
('scale_stroke_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)
|
||||
('scale_stroke_factor', float)
|
||||
])
|
||||
|
||||
# array of mandatory options for current Tcl command: required = {'name','outname'}
|
||||
@@ -30,11 +33,12 @@ class TclCommandExportSVG(TclCommand):
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': "Export a Geometry Object as a SVG File.",
|
||||
'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.')
|
||||
('name', 'Name of the object export. Required.'),
|
||||
('filename', 'Absolute path to file to export.\n'
|
||||
'WARNING: no spaces are allowed. If unsure enclose the entire path with quotes.'),
|
||||
('scale_stroke_factor', 'Multiplication factor used for scaling line widths during export.')
|
||||
]),
|
||||
'examples': ['export_svg my_geometry my_file.svg']
|
||||
}
|
||||
@@ -47,6 +51,4 @@ class TclCommandExportSVG(TclCommand):
|
||||
:return:
|
||||
"""
|
||||
|
||||
name = args['name']
|
||||
|
||||
self.app.export_svg(**args)
|
||||
self.app.f_handlers.export_svg(**args)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
from ObjectCollection import *
|
||||
from tclCommands.TclCommand import TclCommandSignaled
|
||||
from camlib import Geometry
|
||||
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandExteriors(TclCommandSignaled):
|
||||
@@ -10,6 +12,9 @@ class TclCommandExteriors(TclCommandSignaled):
|
||||
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['exteriors', 'ext']
|
||||
|
||||
description = '%s %s' % ("--", "Get exteriors of polygons from a Geometry object and "
|
||||
"from them create a new Geometry object.")
|
||||
|
||||
# dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict([
|
||||
('name', str)
|
||||
@@ -25,12 +30,12 @@ class TclCommandExteriors(TclCommandSignaled):
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': "Get exteriors of polygons.",
|
||||
'main': "Get exteriors of polygons from a Geometry object and from them create a new Geometry object.",
|
||||
'args': collections.OrderedDict([
|
||||
('name', 'Name of the source Geometry object.'),
|
||||
('name', 'Name of the source Geometry object. Required.'),
|
||||
('outname', 'Name of the resulting Geometry object.')
|
||||
]),
|
||||
'examples': []
|
||||
'examples': ['ext geo_source_name -outname "final_geo"']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
@@ -61,4 +66,4 @@ class TclCommandExteriors(TclCommandSignaled):
|
||||
geo_obj.solid_geometry = obj_exteriors
|
||||
|
||||
obj_exteriors = obj.get_exteriors()
|
||||
self.app.new_object('geometry', outname, geo_init)
|
||||
self.app.app_obj.new_object('geometry', outname, geo_init, plot=False)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from ObjectCollection import *
|
||||
from tclCommands.TclCommand import TclCommandSignaled
|
||||
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandFollow(TclCommandSignaled):
|
||||
"""
|
||||
@@ -10,6 +11,8 @@ class TclCommandFollow(TclCommandSignaled):
|
||||
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['follow']
|
||||
|
||||
description = '%s %s' % ("--", "Creates a Geometry object following Gerber paths.")
|
||||
|
||||
# dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict([
|
||||
('name', str)
|
||||
@@ -25,12 +28,12 @@ class TclCommandFollow(TclCommandSignaled):
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': "Creates a geometry object following gerber paths.",
|
||||
'main': "Creates a Geometry object following Gerber paths.",
|
||||
'args': collections.OrderedDict([
|
||||
('name', 'Object name to follow.'),
|
||||
('name', 'Object name to follow. Required.'),
|
||||
('outname', 'Name of the resulting Geometry object.')
|
||||
]),
|
||||
'examples': ['follow name -outname name_follow']
|
||||
'examples': ['follow name -outname "name_follow"']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
@@ -52,14 +55,14 @@ class TclCommandFollow(TclCommandSignaled):
|
||||
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)))
|
||||
if obj.kind != 'gerber':
|
||||
self.raise_tcl_error('Expected GerberObject, got %s %s.' % (name, type(obj)))
|
||||
|
||||
del args['name']
|
||||
try:
|
||||
obj.follow(**args)
|
||||
obj.follow_geo(**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()
|
||||
# self.app.collection.get_by_name(name).ui.plot_cb.toggle()
|
||||
|
||||
@@ -1,9 +1,21 @@
|
||||
from ObjectCollection import *
|
||||
from tclCommands.TclCommand import TclCommandSignaled
|
||||
|
||||
import logging
|
||||
import collections
|
||||
from copy import deepcopy
|
||||
from shapely.ops import cascaded_union
|
||||
from shapely.ops import unary_union
|
||||
from shapely.geometry import Polygon, LineString, LinearRing
|
||||
|
||||
import gettext
|
||||
import appTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
log = logging.getLogger('base')
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
|
||||
class TclCommandGeoCutout(TclCommandSignaled):
|
||||
"""
|
||||
@@ -19,6 +31,8 @@ class TclCommandGeoCutout(TclCommandSignaled):
|
||||
# names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['geocutout', 'geoc']
|
||||
|
||||
description = '%s %s' % ("--", "Creates board cutout from an object (Gerber or Geometry) of any shape.")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict([
|
||||
('name', str),
|
||||
@@ -30,7 +44,8 @@ class TclCommandGeoCutout(TclCommandSignaled):
|
||||
('dia', float),
|
||||
('margin', float),
|
||||
('gapsize', float),
|
||||
('gaps', str)
|
||||
('gaps', str),
|
||||
('outname', str)
|
||||
])
|
||||
|
||||
# array of mandatory options for current Tcl command: required = {'name','outname'}
|
||||
@@ -38,16 +53,17 @@ class TclCommandGeoCutout(TclCommandSignaled):
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': 'Creates board cutout from an object (Gerber or Geometry) of any shape',
|
||||
'main': 'Creates board cutout from an object (Gerber or Geometry) of any shape.',
|
||||
'args': collections.OrderedDict([
|
||||
('name', 'Name of the object.'),
|
||||
('name', 'Name of the object to be cutout. Required'),
|
||||
('dia', 'Tool diameter.'),
|
||||
('margin', 'Margin over bounds.'),
|
||||
('gapsize', 'size of gap.'),
|
||||
('gaps', "type of gaps. Can be: 'tb' = top-bottom, 'lr' = left-right, '2tb' = 2top-2bottom, "
|
||||
"'2lr' = 2left-2right, '4' = 4 cuts, '8' = 8 cuts")
|
||||
"'2lr' = 2left-2right, '4' = 4 cuts, '8' = 8 cuts"),
|
||||
('outname', 'Name of the resulting Geometry object.'),
|
||||
]),
|
||||
'examples': [" #isolate margin for example from fritzing arduino shield or any svg etc\n" +
|
||||
'examples': [" #isolate margin for example from Fritzing arduino shield or any svg etc\n" +
|
||||
" isolate BCu_margin -dia 3 -overlap 1\n" +
|
||||
"\n" +
|
||||
" #create exteriors from isolated object\n" +
|
||||
@@ -57,7 +73,7 @@ class TclCommandGeoCutout(TclCommandSignaled):
|
||||
" delete BCu_margin_iso\n" +
|
||||
"\n" +
|
||||
" #finally cut holding gaps\n" +
|
||||
" geocutout BCu_margin_iso_exterior -dia 3 -gapsize 0.6 -gaps 4\n"]
|
||||
" geocutout BCu_margin_iso_exterior -dia 3 -gapsize 0.6 -gaps 4 -outname cutout_geo\n"]
|
||||
}
|
||||
|
||||
flat_geometry = []
|
||||
@@ -115,41 +131,46 @@ class TclCommandGeoCutout(TclCommandSignaled):
|
||||
flat_geometry = flatten(geo, pathonly=True)
|
||||
|
||||
polygon = Polygon(pts)
|
||||
toolgeo = cascaded_union(polygon)
|
||||
toolgeo = unary_union(polygon)
|
||||
diffs = []
|
||||
for target in flat_geometry:
|
||||
if type(target) == LineString or type(target) == LinearRing:
|
||||
diffs.append(target.difference(toolgeo))
|
||||
else:
|
||||
log.warning("Not implemented.")
|
||||
return cascaded_union(diffs)
|
||||
return unary_union(diffs)
|
||||
|
||||
if 'name' in args:
|
||||
name = args['name']
|
||||
else:
|
||||
self.app.inform.emit(
|
||||
"[WARNING]The name of the object for which cutout is done is missing. Add it and retry.")
|
||||
"[WARNING] %s" % _("The name of the object for which cutout is done is missing. Add it and retry."))
|
||||
return
|
||||
|
||||
if 'margin' in args:
|
||||
margin = args['margin']
|
||||
margin = float(args['margin'])
|
||||
else:
|
||||
margin = 0.001
|
||||
margin = float(self.app.defaults["tools_cutout_margin"])
|
||||
|
||||
if 'dia' in args:
|
||||
dia = args['dia']
|
||||
dia = float(args['dia'])
|
||||
else:
|
||||
dia = 0.1
|
||||
dia = float(self.app.defaults["tools_cutout_tooldia"])
|
||||
|
||||
if 'gaps' in args:
|
||||
gaps = args['gaps']
|
||||
else:
|
||||
gaps = 4
|
||||
gaps = str(self.app.defaults["tools_cutout_gaps_ff"])
|
||||
|
||||
if 'gapsize' in args:
|
||||
gapsize = args['gapsize']
|
||||
gapsize = float(args['gapsize'])
|
||||
else:
|
||||
gapsize = 0.1
|
||||
gapsize = float(self.app.defaults["tools_cutout_gapsize"])
|
||||
|
||||
if 'outname' in args:
|
||||
outname = args['outname']
|
||||
else:
|
||||
outname = str(name) + "_cutout"
|
||||
|
||||
# Get source object.
|
||||
try:
|
||||
@@ -159,12 +180,13 @@ class TclCommandGeoCutout(TclCommandSignaled):
|
||||
return "Could not retrieve object: %s" % name
|
||||
|
||||
if 0 in {dia}:
|
||||
self.app.inform.emit("[WARNING]Tool Diameter is zero value. Change it to a positive real number.")
|
||||
self.app.inform.emit(
|
||||
"[WARNING] %s" % _("Tool Diameter is zero value. Change it to a positive real number."))
|
||||
return "Tool Diameter is zero value. Change it to a positive real number."
|
||||
|
||||
if gaps not in ['lr', 'tb', '2lr', '2tb', '4', '8']:
|
||||
self.app.inform.emit("[WARNING]Gaps value can be only one of: 'lr', 'tb', '2lr', '2tb', 4 or 8. "
|
||||
"Fill in a correct value and retry. ")
|
||||
self.app.inform.emit(
|
||||
"[WARNING] %s" % _("Gaps value can be only one of: 'lr', 'tb', '2lr', '2tb', 4 or 8."))
|
||||
return
|
||||
|
||||
# Get min and max data for each object as we just cut rectangles across X or Y
|
||||
@@ -186,7 +208,7 @@ class TclCommandGeoCutout(TclCommandSignaled):
|
||||
except ValueError:
|
||||
gaps_u = gaps
|
||||
|
||||
if isinstance(cutout_obj, FlatCAMGeometry):
|
||||
if cutout_obj.kind == 'geometry':
|
||||
# rename the obj name so it can be identified as cutout
|
||||
# cutout_obj.options["name"] += "_cutout"
|
||||
|
||||
@@ -276,15 +298,11 @@ class TclCommandGeoCutout(TclCommandSignaled):
|
||||
|
||||
app_obj.disable_plots(objects=[cutout_obj])
|
||||
|
||||
app_obj.inform.emit("[success] Any-form Cutout operation finished.")
|
||||
app_obj.inform.emit("[success] %s" % _("Any-form Cutout operation finished."))
|
||||
|
||||
outname = cutout_obj.options["name"] + "_cutout"
|
||||
self.app.new_object('geometry', outname, geo_init)
|
||||
self.app.app_obj.new_object('geometry', outname, geo_init, plot=False)
|
||||
|
||||
# cutout_obj.plot()
|
||||
# self.app.inform.emit("[success] Any-form Cutout operation finished.")
|
||||
# self.app.plots_updated.emit()
|
||||
elif isinstance(cutout_obj, FlatCAMGerber):
|
||||
elif cutout_obj.kind == 'gerber':
|
||||
|
||||
def geo_init(geo_obj, app_obj):
|
||||
try:
|
||||
@@ -335,12 +353,11 @@ class TclCommandGeoCutout(TclCommandSignaled):
|
||||
geo_obj.options['ymin'] = cutout_obj.options['ymin']
|
||||
geo_obj.options['xmax'] = cutout_obj.options['xmax']
|
||||
geo_obj.options['ymax'] = cutout_obj.options['ymax']
|
||||
app_obj.inform.emit("[success] Any-form Cutout operation finished.")
|
||||
app_obj.inform.emit("[success] %s" % _("Any-form Cutout operation finished."))
|
||||
|
||||
outname = cutout_obj.options["name"] + "_cutout"
|
||||
self.app.new_object('geometry', outname, geo_init)
|
||||
self.app.app_obj.new_object('geometry', outname, geo_init, plot=False)
|
||||
|
||||
cutout_obj = self.app.collection.get_by_name(outname)
|
||||
else:
|
||||
self.app.inform.emit("[ERROR]Cancelled. Object type is not supported.")
|
||||
self.app.inform.emit("[ERROR] %s" % _("Cancelled. Object type is not supported."))
|
||||
return
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from ObjectCollection import *
|
||||
from tclCommands.TclCommand import TclCommand
|
||||
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandGeoUnion(TclCommand):
|
||||
"""
|
||||
@@ -14,6 +15,8 @@ class TclCommandGeoUnion(TclCommand):
|
||||
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['geo_union']
|
||||
|
||||
description = '%s %s' % ("--", "Run the Union (join) geometry operation on the elements of a Geometry object.")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict([
|
||||
('name', str),
|
||||
@@ -31,12 +34,12 @@ class TclCommandGeoUnion(TclCommand):
|
||||
help = {
|
||||
'main': ('Runs a union operation (addition) on the components '
|
||||
'of the geometry object. For example, if it contains '
|
||||
'2 intersecting polygons, this opperation adds them into'
|
||||
'2 intersecting polygons, this operation adds them into'
|
||||
'a single larger polygon.'),
|
||||
'args': collections.OrderedDict([
|
||||
('name', 'Name of the Geometry Object.'),
|
||||
('name', 'Name of the Geometry Object that contain the components to be joined. Required.'),
|
||||
]),
|
||||
'examples': []
|
||||
'examples': ['geo_union target_geo']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
@@ -50,8 +53,8 @@ class TclCommandGeoUnion(TclCommand):
|
||||
obj_name = args['name']
|
||||
|
||||
try:
|
||||
obj = self.collection.get_by_name(str(obj_name))
|
||||
except:
|
||||
obj = self.app.collection.get_by_name(str(obj_name))
|
||||
except Exception:
|
||||
return "Could not retrieve object: %s" % obj_name
|
||||
if obj is None:
|
||||
return "Object not found: %s" % obj_name
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
from ObjectCollection import *
|
||||
from tclCommands.TclCommand import TclCommand
|
||||
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandGetNames(TclCommand):
|
||||
"""
|
||||
Tcl shell command to set an object as active in the GUI.
|
||||
Tcl shell command to set an object as active in the appGUI.
|
||||
|
||||
example:
|
||||
|
||||
@@ -13,6 +14,9 @@ class TclCommandGetNames(TclCommand):
|
||||
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['get_names']
|
||||
|
||||
description = '%s %s' % ("--", "Return to TCL the list of the project objects names "
|
||||
"as a string with names separated by the '\\n' char.")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict([
|
||||
|
||||
@@ -28,11 +32,12 @@ class TclCommandGetNames(TclCommand):
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': 'Lists the names of objects in the project.',
|
||||
'main': 'Lists the names of objects in the project. '
|
||||
'It returns a string with names separated by "\\n" character',
|
||||
'args': collections.OrderedDict([
|
||||
|
||||
]),
|
||||
'examples': []
|
||||
'examples': ['get_names']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
|
||||
65
tclCommands/TclCommandGetPath.py
Normal file
65
tclCommands/TclCommandGetPath.py
Normal file
@@ -0,0 +1,65 @@
|
||||
# ##########################################################
|
||||
# FlatCAM: 2D Post-processing for Manufacturing #
|
||||
# File Author: Marius Adrian Stanciu (c) #
|
||||
# Date: 4/28/2020 #
|
||||
# MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
from tclCommands.TclCommand import TclCommand
|
||||
|
||||
import collections
|
||||
import logging
|
||||
import gettext
|
||||
import appTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
log = logging.getLogger('base')
|
||||
|
||||
|
||||
class TclCommandGetPath(TclCommand):
|
||||
"""
|
||||
Tcl shell command to get the current default path set for Tcl.
|
||||
|
||||
example:
|
||||
|
||||
"""
|
||||
|
||||
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['get_path']
|
||||
|
||||
description = '%s %s' % ("--", "Get the default Tcl Shell folder path.")
|
||||
|
||||
# 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': "Will get the folder path used as a fallback path for opening files.",
|
||||
'args': collections.OrderedDict([
|
||||
]),
|
||||
'examples': ['get_path']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
"""
|
||||
|
||||
:param args:
|
||||
:param unnamed_args:
|
||||
:return:
|
||||
"""
|
||||
|
||||
self.app.shell.append_output("Current default Tcl Shell path is: ")
|
||||
path = self.app.defaults["global_tcl_path"]
|
||||
return path
|
||||
@@ -1,6 +1,14 @@
|
||||
from ObjectCollection import *
|
||||
# ##########################################################
|
||||
# FlatCAM: 2D Post-processing for Manufacturing #
|
||||
# File Author: Marius Adrian Stanciu (c) #
|
||||
# Date: 8/17/2019 #
|
||||
# MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
from tclCommands.TclCommand import TclCommand
|
||||
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandGetSys(TclCommand):
|
||||
"""
|
||||
@@ -13,6 +21,8 @@ class TclCommandGetSys(TclCommand):
|
||||
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['get_sys', 'getsys']
|
||||
|
||||
description = '%s %s' % ("--", "Returns to TCL the value for the entered system variable.")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict([
|
||||
('name', str)
|
||||
@@ -28,9 +38,9 @@ class TclCommandGetSys(TclCommand):
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': "Returns the value of the system variable.",
|
||||
'main': "Returns to TCL the value for the entered system variable.",
|
||||
'args': collections.OrderedDict([
|
||||
('name', 'Name of the system variable.'),
|
||||
('name', 'Name of the system variable. Required.'),
|
||||
]),
|
||||
'examples': ['get_sys excellon_zeros']
|
||||
}
|
||||
@@ -47,4 +57,5 @@ class TclCommandGetSys(TclCommand):
|
||||
|
||||
if name in self.app.defaults:
|
||||
return self.app.defaults[name]
|
||||
|
||||
else:
|
||||
return "The keyword: %s does not exist as a parameter" % str(name)
|
||||
|
||||
117
tclCommands/TclCommandHelp.py
Normal file
117
tclCommands/TclCommandHelp.py
Normal file
@@ -0,0 +1,117 @@
|
||||
# ##########################################################
|
||||
# FlatCAM: 2D Post-processing for Manufacturing #
|
||||
# File Author: Marius Adrian Stanciu (c) #
|
||||
# Content was borrowed from FlatCAM proper #
|
||||
# Date: 4/22/2020 #
|
||||
# MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
from tclCommands.TclCommand import TclCommand
|
||||
|
||||
import collections
|
||||
|
||||
import gettext
|
||||
import appTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
|
||||
class TclCommandHelp(TclCommand):
|
||||
"""
|
||||
Tcl shell command to show Help
|
||||
|
||||
example:
|
||||
help add_circle
|
||||
"""
|
||||
|
||||
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['help']
|
||||
|
||||
description = '%s %s' % ("--", "PRINTS to TCL the HELP.")
|
||||
|
||||
# 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 = []
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': "Returns to TCL the value for the entered system variable.",
|
||||
'args': collections.OrderedDict([
|
||||
('name', 'Name of a Tcl Command for which to display the Help.'),
|
||||
]),
|
||||
'examples': ['help add_circle']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
"""
|
||||
|
||||
:param args: Without any argument will display the list of commands. Can have as a argument
|
||||
a tcl command name to display the help for that command.
|
||||
:param unnamed_args:
|
||||
:return:
|
||||
"""
|
||||
|
||||
if 'name' in args:
|
||||
name = args['name']
|
||||
if name not in self.app.shell.tcl_commands_storage:
|
||||
return "Unknown command: %s" % name
|
||||
|
||||
help_for_command = self.app.shell.tcl_commands_storage[name]["help"] + '\n\n'
|
||||
self.app.shell.append_output(help_for_command)
|
||||
else:
|
||||
if not args:
|
||||
cmd_enum = '%s\n' % _("Available commands:")
|
||||
|
||||
displayed_text = []
|
||||
try:
|
||||
# find the maximum length of a command name
|
||||
max_len = 0
|
||||
for cmd_name in self.app.shell.tcl_commands_storage:
|
||||
curr_len = len(cmd_name)
|
||||
if curr_len > max_len:
|
||||
max_len = curr_len
|
||||
|
||||
h_space = " "
|
||||
cnt = 0
|
||||
for cmd_name in sorted(self.app.shell.tcl_commands_storage):
|
||||
cmd_description = "<span>%s</span>" % \
|
||||
self.app.shell.tcl_commands_storage[cmd_name]['description']
|
||||
|
||||
curr_len = len(cmd_name)
|
||||
|
||||
cmd_name_colored = "> <span style=\" font-weight: bold; color: red;\" >%s</span>" % \
|
||||
str(cmd_name)
|
||||
|
||||
nr_chars = max_len - curr_len
|
||||
|
||||
cmd_line_txt = '%s%s %s' % (cmd_name_colored, nr_chars * h_space, cmd_description)
|
||||
|
||||
displayed_text.append(cmd_line_txt)
|
||||
|
||||
# group commands by 4 adding a line break after 4 commands
|
||||
if cnt == 3:
|
||||
cnt = 0
|
||||
displayed_text.append(' ')
|
||||
else:
|
||||
cnt += 1
|
||||
except Exception as err:
|
||||
self.app.log.debug("tclCommands.TclCommandHelp() when run as 'help' --> %s" % str(err))
|
||||
displayed_text = ['> %s' % cmd for cmd in sorted(self.app.shell.tcl_commands_storage)]
|
||||
|
||||
cmd_enum += '<br>'.join(displayed_text)
|
||||
cmd_enum += '<br><br>%s<br>%s<br><br>' % (
|
||||
_("Type help <command_name> for usage."), _("Example: help open_gerber"))
|
||||
|
||||
self.app.shell.append_raw(cmd_enum)
|
||||
@@ -1,6 +1,8 @@
|
||||
from ObjectCollection import *
|
||||
from tclCommands.TclCommand import TclCommandSignaled
|
||||
|
||||
import collections
|
||||
from camlib import Geometry
|
||||
|
||||
|
||||
class TclCommandImportSvg(TclCommandSignaled):
|
||||
"""
|
||||
@@ -10,6 +12,8 @@ class TclCommandImportSvg(TclCommandSignaled):
|
||||
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['import_svg']
|
||||
|
||||
description = '%s %s' % ("--", "Import a SVG file as a Geometry (or Gerber) Object.")
|
||||
|
||||
# dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict([
|
||||
('filename', str)
|
||||
@@ -26,13 +30,14 @@ class TclCommandImportSvg(TclCommandSignaled):
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': "Import an SVG file as a Geometry Object..",
|
||||
'main': "Import a SVG file as a Geometry (or Gerber) Object.",
|
||||
'args': collections.OrderedDict([
|
||||
('filename', 'Path to file to open.'),
|
||||
('type', 'Import as gerber or geometry(default).'),
|
||||
('filename', 'Absolute path to file to open. Required.\n'
|
||||
'WARNING: no spaces are allowed. If unsure enclose the entire path with quotes.'),
|
||||
('type', 'Import as a Gerber or Geometry (default) object. Values can be: "geometry" or "gerber"'),
|
||||
('outname', 'Name of the resulting Geometry object.')
|
||||
]),
|
||||
'examples': []
|
||||
'examples': ['import_svg D:\\my_beautiful_svg_file.SVG']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
@@ -61,21 +66,20 @@ class TclCommandImportSvg(TclCommandSignaled):
|
||||
outname = filename.split('/')[-1].split('\\')[-1]
|
||||
|
||||
if 'type' in args:
|
||||
obj_type = args['type']
|
||||
obj_type = args['type'].lower()
|
||||
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)
|
||||
self.raise_tcl_error("Option type can be 'geometry' or 'gerber' only, got '%s'." % obj_type)
|
||||
|
||||
with self.app.proc_container.new("Import SVG"):
|
||||
with self.app.proc_container.new('%s ...' % _("Importing")):
|
||||
|
||||
# Object creation
|
||||
self.app.new_object(obj_type, outname, obj_init)
|
||||
self.app.app_obj.new_object(obj_type, outname, obj_init, plot=False)
|
||||
|
||||
# Register recent file
|
||||
self.app.file_opened.emit("svg", filename)
|
||||
|
||||
# GUI feedback
|
||||
self.app.inform.emit("Opened: " + filename)
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
from ObjectCollection import *
|
||||
from tclCommands.TclCommand import TclCommandSignaled
|
||||
from camlib import Geometry
|
||||
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandInteriors(TclCommandSignaled):
|
||||
@@ -10,6 +12,9 @@ class TclCommandInteriors(TclCommandSignaled):
|
||||
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['interiors']
|
||||
|
||||
description = '%s %s' % ("--", "Create a new Geometry object with the 'interiors' geo "
|
||||
"elements of the source object.")
|
||||
|
||||
# dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict([
|
||||
('name', str)
|
||||
@@ -25,12 +30,13 @@ class TclCommandInteriors(TclCommandSignaled):
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': "Get interiors of polygons.",
|
||||
'main': "Create a new Geometry object with the 'interiors' geometric elements of "
|
||||
"the specified source Geometry object.",
|
||||
'args': collections.OrderedDict([
|
||||
('name', 'Name of the source Geometry object.'),
|
||||
('name', 'Name of the source Geometry object. Required.'),
|
||||
('outname', 'Name of the resulting Geometry object.')
|
||||
]),
|
||||
'examples': []
|
||||
'examples': ['interiors my_geo_name -outname "outputed_geo"']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
@@ -61,4 +67,4 @@ class TclCommandInteriors(TclCommandSignaled):
|
||||
geo_obj.solid_geometry = obj_interiors
|
||||
|
||||
obj_interiors = obj.get_interiors()
|
||||
self.app.new_object('geometry', outname, geo_init)
|
||||
self.app.app_obj.new_object('geometry', outname, geo_init)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from ObjectCollection import *
|
||||
from tclCommands.TclCommand import TclCommandSignaled
|
||||
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandIsolate(TclCommandSignaled):
|
||||
"""
|
||||
@@ -17,6 +18,8 @@ class TclCommandIsolate(TclCommandSignaled):
|
||||
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['isolate']
|
||||
|
||||
description = '%s %s' % ("--", "Creates isolation routing Geometry for the specified Gerber object.")
|
||||
|
||||
# dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict([
|
||||
('name', str)
|
||||
@@ -27,9 +30,10 @@ class TclCommandIsolate(TclCommandSignaled):
|
||||
('dia', float),
|
||||
('passes', int),
|
||||
('overlap', float),
|
||||
('combine', int),
|
||||
('combine', str),
|
||||
('outname', str),
|
||||
('follow', str)
|
||||
('follow', str),
|
||||
('iso_type', int)
|
||||
|
||||
])
|
||||
|
||||
@@ -38,17 +42,20 @@ class TclCommandIsolate(TclCommandSignaled):
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': "Creates isolation routing geometry for the given Gerber.",
|
||||
'main': "Creates isolation routing Geometry for the specified Gerber object.",
|
||||
'args': collections.OrderedDict([
|
||||
('name', 'Name of the source object.'),
|
||||
('name', 'Name of the Gerber source object to be isolated. Required.'),
|
||||
('dia', 'Tool diameter.'),
|
||||
('passes', 'Passes of tool width.'),
|
||||
('overlap', 'Fraction of tool diameter to overlap passes.'),
|
||||
('combine', 'Combine all passes into one geometry.'),
|
||||
('overlap', 'Percentage of tool diameter to overlap current pass over previous pass. Float [0, 99.9999]\n'
|
||||
'E.g: for a 25% from tool diameter overlap use -overlap 25'),
|
||||
('combine', 'Combine all passes into one geometry. Can be True (1) or False (0)'),
|
||||
('outname', 'Name of the resulting Geometry object.'),
|
||||
('follow', 'Create a Geometry that follows the Gerber path.')
|
||||
('follow', 'Create a Geometry that follows the Gerber path. Can be True (1) or False (0).'),
|
||||
('iso_type', 'A value of 0 will isolate exteriors, a value of 1 will isolate interiors '
|
||||
'and a value of 2 will do full isolation.')
|
||||
]),
|
||||
'examples': []
|
||||
'examples': ['isolate my_gerber -dia 0.1 -passes 2 -overlap 10 -combine True -iso_type 2 -outname out_geo']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
@@ -66,20 +73,30 @@ class TclCommandIsolate(TclCommandSignaled):
|
||||
if 'outname' not in args:
|
||||
args['outname'] = name + "_iso"
|
||||
|
||||
if 'timeout' in args:
|
||||
timeout = args['timeout']
|
||||
else:
|
||||
timeout = 10000
|
||||
# if 'timeout' in args:
|
||||
# timeout = args['timeout']
|
||||
# else:
|
||||
# timeout = 10000
|
||||
|
||||
if 'follow' not in args:
|
||||
args['follow'] = None
|
||||
|
||||
# evaluate this parameter so True, False, 0 and 1 works
|
||||
if 'combine' in args:
|
||||
try:
|
||||
par = args['combine'].capitalize()
|
||||
except AttributeError:
|
||||
par = args['combine']
|
||||
args['combine'] = bool(eval(par))
|
||||
else:
|
||||
args['combine'] = bool(eval(self.app.defaults["tools_iso_combine_passes"]))
|
||||
|
||||
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)))
|
||||
if obj.kind != 'gerber':
|
||||
self.raise_tcl_error('Expected GerberObject, got %s %s.' % (name, type(obj)))
|
||||
|
||||
del args['name']
|
||||
obj.isolate(**args)
|
||||
obj.isolate(plot=False, **args)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
from ObjectCollection import *
|
||||
from tclCommands.TclCommand import TclCommand
|
||||
from appObjects.FlatCAMExcellon import ExcellonObject
|
||||
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandJoinExcellon(TclCommand):
|
||||
@@ -13,6 +15,9 @@ class TclCommandJoinExcellon(TclCommand):
|
||||
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['join_excellon', 'join_excellons']
|
||||
|
||||
description = '%s %s' % ("--", "Merge two or more Excellon objects drills and create "
|
||||
"a new Excellon object with them.")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict([
|
||||
('outname', str),
|
||||
@@ -20,7 +25,6 @@ class TclCommandJoinExcellon(TclCommand):
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
|
||||
option_types = collections.OrderedDict([
|
||||
|
||||
])
|
||||
|
||||
# array of mandatory options for current Tcl command: required = {'name','outname'}
|
||||
@@ -28,14 +32,14 @@ class TclCommandJoinExcellon(TclCommand):
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': "Runs a merge operation (join) on the Excellon objects.",
|
||||
'main': "Runs a merge operation (join) on the Excellon objects.\n"
|
||||
"The names of the Excellon objects to be merged will be entered after the outname,\n"
|
||||
"separated by spaces. See the example below.\n"
|
||||
"WARNING: if the name of an Excellon objects has spaces, enclose the name with quotes.",
|
||||
'args': collections.OrderedDict([
|
||||
('name', 'Name of the new Excellon Object.'),
|
||||
('obj_name_0', 'Name of the first object'),
|
||||
('obj_name_1', 'Name of the second object.'),
|
||||
('obj_name_2...', 'Additional object names')
|
||||
('outname', 'Name of the new Excellon Object made by joining of other Excellon objects. Required'),
|
||||
]),
|
||||
'examples': []
|
||||
'examples': ['join_excellons merged_new_excellon exc_name_1 "exc name_2"']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
@@ -46,7 +50,7 @@ class TclCommandJoinExcellon(TclCommand):
|
||||
:return:
|
||||
"""
|
||||
|
||||
outname = args['name']
|
||||
outname = args['outname']
|
||||
obj_names = unnamed_args
|
||||
|
||||
objs = []
|
||||
@@ -58,7 +62,9 @@ class TclCommandJoinExcellon(TclCommand):
|
||||
objs.append(obj)
|
||||
|
||||
def initialize(obj_, app):
|
||||
FlatCAMExcellon.merge(objs, obj_)
|
||||
ExcellonObject.merge(objs, obj_, decimals=self.app.decimals)
|
||||
|
||||
if objs is not None:
|
||||
self.app.new_object("excellon", outname, initialize)
|
||||
if objs and len(objs) >= 2:
|
||||
self.app.app_obj.new_object("excellon", outname, initialize, plot=False)
|
||||
else:
|
||||
return "No Excellon objects to be joined or less than two Excellon objects specified for merging."
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
from ObjectCollection import *
|
||||
from tclCommands.TclCommand import TclCommand
|
||||
from appObjects.FlatCAMGeometry import GeometryObject
|
||||
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandJoinGeometry(TclCommand):
|
||||
@@ -13,6 +15,8 @@ class TclCommandJoinGeometry(TclCommand):
|
||||
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['join_geometries', 'join_geometry']
|
||||
|
||||
description = '%s %s' % ("--", "Merge two or more Geometry objects and create a new Geometry object.")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict([
|
||||
('outname', str),
|
||||
@@ -28,14 +32,14 @@ class TclCommandJoinGeometry(TclCommand):
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': "Runs a merge operation (join) on the Excellon objects.",
|
||||
'main': "Runs a merge operation (join) on the Geometry objects.\n"
|
||||
"The names of the Geometry objects to be merged will be entered after the outname,\n"
|
||||
"separated by spaces. See the example below.\n"
|
||||
"WARNING: if the name of an Geometry objects has spaces, enclose the name with quotes.",
|
||||
'args': collections.OrderedDict([
|
||||
('outname', 'Name of the new Geometry Object.'),
|
||||
('obj_name_0', 'Name of the first object'),
|
||||
('obj_name_1', 'Name of the second object.'),
|
||||
('obj_name_2...', 'Additional object names')
|
||||
('outname', 'Name of the new Geometry Object made by joining of other Geometry objects. Required'),
|
||||
]),
|
||||
'examples': []
|
||||
'examples': ['join_geometry merged_new_geo geo_name_1 "geo name_2"']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
@@ -58,7 +62,9 @@ class TclCommandJoinGeometry(TclCommand):
|
||||
objs.append(obj)
|
||||
|
||||
def initialize(obj_, app):
|
||||
FlatCAMGeometry.merge(objs, obj_)
|
||||
GeometryObject.merge(objs, obj_)
|
||||
|
||||
if objs is not None:
|
||||
self.app.new_object("geometry", outname, initialize)
|
||||
if objs and len(objs) >= 2:
|
||||
self.app.app_obj.new_object("geometry", outname, initialize, plot=False)
|
||||
else:
|
||||
return "No Geometry objects to be joined or less than two Geometry objects specified for merging."
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
# ##########################################################
|
||||
# FlatCAM: 2D Post-processing for Manufacturing #
|
||||
# File Author: Marius Adrian Stanciu (c) #
|
||||
# Date: 8/17/2019 #
|
||||
# MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
from tclCommands.TclCommand import *
|
||||
|
||||
|
||||
@@ -12,6 +19,8 @@ class TclCommandListSys(TclCommand):
|
||||
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['list_sys', 'listsys']
|
||||
|
||||
description = '%s %s' % ("--", "Outputs in Tcl Shell the list with the names of system variables.")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict([
|
||||
('selection', str),
|
||||
@@ -33,7 +42,7 @@ class TclCommandListSys(TclCommand):
|
||||
"of the system variable.\n"
|
||||
"In that case it will list only the system variables that starts with that string.\n"
|
||||
"Main categories start with: gerber or excellon or geometry or cncjob or global.\n"
|
||||
"Note: Use get_sys TclCommand to get the value and set_sys TclCommand to set it.\n",
|
||||
"Note: Use 'get_sys system variable' to get the value and 'set_sys system variable value' to set it.\n",
|
||||
'args': collections.OrderedDict([
|
||||
]),
|
||||
'examples': ['list_sys',
|
||||
@@ -53,4 +62,6 @@ class TclCommandListSys(TclCommand):
|
||||
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])
|
||||
ret_val = list(self.app.defaults.keys())
|
||||
return str(ret_val)
|
||||
# return str([*self.app.defaults])
|
||||
|
||||
158
tclCommands/TclCommandMillDrills.py
Normal file
158
tclCommands/TclCommandMillDrills.py
Normal file
@@ -0,0 +1,158 @@
|
||||
# ##########################################################
|
||||
# FlatCAM: 2D Post-processing for Manufacturing #
|
||||
# File Author: Marius Adrian Stanciu (c) #
|
||||
# Date: 8/17/2019 #
|
||||
# MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
from tclCommands.TclCommand import TclCommandSignaled
|
||||
|
||||
import math
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandMillDrills(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 = ['milldrills', 'milld']
|
||||
|
||||
description = '%s %s' % ("--", "Create a Geometry Object for milling drill holes from Excellon.")
|
||||
|
||||
# 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([
|
||||
('milled_dias', str),
|
||||
('outname', str),
|
||||
('tooldia', float),
|
||||
('use_thread', str),
|
||||
('diatol', 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': "Create a Geometry Object for milling drill holes from Excellon.",
|
||||
'args': collections.OrderedDict([
|
||||
('name', 'Name of the Excellon Object. Required.'),
|
||||
('milled_dias', 'Comma separated tool diameters of the drills to be milled (example: 0.6, 1.0 or 3.125).\n'
|
||||
'Exception: if you enter "all" then the drills for all tools will be milled.\n'
|
||||
'WARNING: no spaces are allowed in the list of tools.\n'
|
||||
'As a precaution you can enclose them with quotes.'),
|
||||
('tooldia', 'Diameter of the milling tool (example: 0.1).'),
|
||||
('outname', 'Name of Geometry object to be created holding the milled geometries.'),
|
||||
('use_thread', 'If to use multithreading: True (1) or False (0).'),
|
||||
('diatol', 'Tolerance. Percentange (0.0 ... 100.0) within which dias in milled_dias will be judged to be '
|
||||
'the same as the ones in the tools from the Excellon object. E.g: if in milled_dias we have a '
|
||||
'diameter with value 1.0, in the Excellon we have a tool with dia = 1.05 and we set a tolerance '
|
||||
'diatol = 5.0 then the drills with the dia = (0.95 ... 1.05) '
|
||||
'in Excellon will be processed. Float number.')
|
||||
]),
|
||||
'examples': ['milldrills mydrills -milled_dias "0.6,0.8" -tooldia 0.1 -diatol 10 -outname milled_holes',
|
||||
'milld my_excellon.drl']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
"""
|
||||
|
||||
:param args: array of known named arguments and options
|
||||
:param unnamed_args: array of other values which were passed into command
|
||||
without -somename and we do not have them in known arg_names
|
||||
:return: None or exception
|
||||
"""
|
||||
|
||||
name = args['name']
|
||||
|
||||
try:
|
||||
obj = self.app.collection.get_by_name(str(name))
|
||||
except Exception:
|
||||
obj = None
|
||||
self.raise_tcl_error("Could not retrieve object: %s" % name)
|
||||
|
||||
if 'outname' not in args:
|
||||
args['outname'] = name + "_mill_drills"
|
||||
|
||||
if 'use_thread' in args:
|
||||
try:
|
||||
par = args['use_thread'].capitalize()
|
||||
except AttributeError:
|
||||
par = args['use_thread']
|
||||
args['use_thread'] = bool(eval(par))
|
||||
else:
|
||||
args['use_thread'] = False
|
||||
|
||||
if not obj.drills:
|
||||
self.raise_tcl_error("The Excellon object has no drills: %s" % name)
|
||||
|
||||
try:
|
||||
if 'milled_dias' in args and args['milled_dias'] != 'all':
|
||||
diameters = [x.strip() for x in args['milled_dias'].split(",") if x != '']
|
||||
nr_diameters = len(diameters)
|
||||
|
||||
req_tools = set()
|
||||
for tool in obj.tools:
|
||||
for req_dia in diameters:
|
||||
obj_dia_form = float('%.*f' % (obj.decimals, float(obj.tools[tool]["C"])))
|
||||
req_dia_form = float('%.*f' % (obj.decimals, float(req_dia)))
|
||||
|
||||
if 'diatol' in args:
|
||||
tolerance = float(args['diatol']) / 100
|
||||
|
||||
tolerance = 0.0 if tolerance < 0.0 else tolerance
|
||||
tolerance = 1.0 if tolerance > 1.0 else tolerance
|
||||
if math.isclose(obj_dia_form, req_dia_form, rel_tol=tolerance):
|
||||
req_tools.add(tool)
|
||||
nr_diameters -= 1
|
||||
else:
|
||||
if obj_dia_form == req_dia_form:
|
||||
req_tools.add(tool)
|
||||
nr_diameters -= 1
|
||||
|
||||
if nr_diameters > 0:
|
||||
self.raise_tcl_error("One or more tool diameters of the drills to be milled passed to the "
|
||||
"TclCommand are not actual tool diameters in the Excellon object.")
|
||||
|
||||
args['tools'] = req_tools
|
||||
|
||||
# no longer needed
|
||||
del args['milled_dias']
|
||||
del args['diatol']
|
||||
|
||||
# Split and put back. We are passing the whole dictionary later.
|
||||
# args['milled_dias'] = [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))
|
||||
|
||||
if obj.kind != 'excellon':
|
||||
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_drills(plot=False, **args)
|
||||
except Exception as e:
|
||||
success = None
|
||||
msg = None
|
||||
self.raise_tcl_error("Operation failed: %s" % str(e))
|
||||
|
||||
if not success:
|
||||
self.raise_tcl_error(msg)
|
||||
@@ -1,91 +0,0 @@
|
||||
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_drills(**args)
|
||||
|
||||
except Exception as e:
|
||||
self.raise_tcl_error("Operation failed: %s" % str(e))
|
||||
|
||||
if not success:
|
||||
self.raise_tcl_error(msg)
|
||||
160
tclCommands/TclCommandMillSlots.py
Normal file
160
tclCommands/TclCommandMillSlots.py
Normal file
@@ -0,0 +1,160 @@
|
||||
# ##########################################################
|
||||
# FlatCAM: 2D Post-processing for Manufacturing #
|
||||
# File Author: Marius Adrian Stanciu (c) #
|
||||
# Date: 8/17/2019 #
|
||||
# MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
from tclCommands.TclCommand import TclCommandSignaled
|
||||
|
||||
import collections
|
||||
import math
|
||||
|
||||
|
||||
class TclCommandMillSlots(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 = ['millslots', 'mills']
|
||||
|
||||
description = '%s %s' % ("--", "Create a Geometry Object for milling slot holes from Excellon.")
|
||||
|
||||
# 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([
|
||||
('milled_dias', str),
|
||||
('outname', str),
|
||||
('tooldia', float),
|
||||
('use_thread', str),
|
||||
('diatol', 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': "Create a Geometry Object for milling slot holes from Excellon.",
|
||||
'args': collections.OrderedDict([
|
||||
('name', 'Name of the Excellon Object. Required.'),
|
||||
('milled_dias', 'Comma separated tool diameters of the slots to be milled (example: 0.6, 1.0 or 3.125).\n'
|
||||
'Exception: if you enter "all" then the slots for all tools will be milled.\n'
|
||||
'WARNING: no spaces are allowed in the list of tools.\n'
|
||||
'As a precaution you can enclose them with quotes.'),
|
||||
('tooldia', 'Diameter of the milling tool (example: 0.1).'),
|
||||
('outname', 'Name of object to be created holding the milled geometries.'),
|
||||
('use_thread', 'If to use multithreading: True (1) or False (0).'),
|
||||
('diatol', 'Tolerance. Percentange (0.0 ... 100.0) within which dias in milled_dias will be judged to be '
|
||||
'the same as the ones in the tools from the Excellon object. E.g: if in milled_dias we have a '
|
||||
'diameter with value 1.0, in the Excellon we have a tool with dia = 1.05 and we set a tolerance '
|
||||
'diatol = 5.0 then the slots with the dia = (0.95 ... 1.05) '
|
||||
'in Excellon will be processed. Float number.')
|
||||
]),
|
||||
'examples': ['millslots myslots -milled_dias "0.6,0.8" -tooldia 0.1 -diatol 10 -outname milled_slots',
|
||||
'mills my_excellon.drl']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
"""
|
||||
|
||||
:param args: array of known named arguments and options
|
||||
:param unnamed_args: array of other values which were passed into command
|
||||
without -somename and we do not have them in known arg_names
|
||||
:return: None or exception
|
||||
"""
|
||||
|
||||
name = args['name']
|
||||
|
||||
try:
|
||||
obj = self.app.collection.get_by_name(str(name))
|
||||
except Exception:
|
||||
obj = None
|
||||
self.raise_tcl_error("Could not retrieve object: %s" % name)
|
||||
|
||||
if 'outname' not in args:
|
||||
args['outname'] = name + "_mill_slots"
|
||||
|
||||
if 'use_thread' in args:
|
||||
try:
|
||||
par = args['use_thread'].capitalize()
|
||||
except AttributeError:
|
||||
par = args['use_thread']
|
||||
args['use_thread'] = bool(eval(par))
|
||||
else:
|
||||
args['use_thread'] = False
|
||||
|
||||
if not obj.slots:
|
||||
self.raise_tcl_error("The Excellon object has no slots: %s" % name)
|
||||
|
||||
# units = self.app.defaults['units'].upper()
|
||||
try:
|
||||
if 'milled_dias' in args and args['milled_dias'] != 'all':
|
||||
diameters = [x.strip() for x in args['milled_dias'].split(",")]
|
||||
nr_diameters = len(diameters)
|
||||
|
||||
req_tools = set()
|
||||
for tool in obj.tools:
|
||||
for req_dia in diameters:
|
||||
obj_dia_form = float('%.*f' % (obj.decimals, float(obj.tools[tool]["C"])))
|
||||
req_dia_form = float('%.*f' % (obj.decimals, float(req_dia)))
|
||||
|
||||
if 'diatol' in args:
|
||||
tolerance = args['diatol'] / 100
|
||||
|
||||
tolerance = 0.0 if tolerance < 0.0 else tolerance
|
||||
tolerance = 1.0 if tolerance > 1.0 else tolerance
|
||||
if math.isclose(obj_dia_form, req_dia_form, rel_tol=tolerance):
|
||||
req_tools.add(tool)
|
||||
nr_diameters -= 1
|
||||
else:
|
||||
if obj_dia_form == req_dia_form:
|
||||
req_tools.add(tool)
|
||||
nr_diameters -= 1
|
||||
|
||||
if nr_diameters > 0:
|
||||
self.raise_tcl_error("One or more tool diameters of the slots to be milled passed to the "
|
||||
"TclCommand are not actual tool diameters in the Excellon object.")
|
||||
|
||||
args['tools'] = req_tools
|
||||
|
||||
# no longer needed
|
||||
del args['milled_dias']
|
||||
del args['diatol']
|
||||
|
||||
# Split and put back. We are passing the whole dictionary later.
|
||||
# args['milled_dias'] = [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))
|
||||
|
||||
if obj.kind != 'excellon':
|
||||
self.raise_tcl_error('Only Excellon objects can have mill-slots, 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_slots(plot=False, **args)
|
||||
|
||||
except Exception as e:
|
||||
success = None
|
||||
msg = None
|
||||
self.raise_tcl_error("Operation failed: %s" % str(e))
|
||||
|
||||
if not success:
|
||||
self.raise_tcl_error(msg)
|
||||
@@ -1,6 +1,7 @@
|
||||
from ObjectCollection import *
|
||||
from tclCommands.TclCommand import TclCommandSignaled
|
||||
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandMirror(TclCommandSignaled):
|
||||
"""
|
||||
@@ -11,6 +12,8 @@ class TclCommandMirror(TclCommandSignaled):
|
||||
# old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['mirror']
|
||||
|
||||
description = '%s %s' % ("--", "Will mirror the geometry of a named object. Does not create a new object.")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered.
|
||||
# For positional arguments
|
||||
arg_names = collections.OrderedDict([
|
||||
@@ -22,22 +25,25 @@ class TclCommandMirror(TclCommandSignaled):
|
||||
option_types = collections.OrderedDict([
|
||||
('axis', str),
|
||||
('box', str),
|
||||
('dist', float)
|
||||
('origin', str)
|
||||
])
|
||||
|
||||
# array of mandatory options for current Tcl command: required = {'name','outname'}
|
||||
required = ['name', 'axis']
|
||||
required = ['name']
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': "Opens an Excellon file.",
|
||||
'main': "Will mirror the geometry of a named object. Does not create a new object.",
|
||||
'args': collections.OrderedDict([
|
||||
('name', 'Name of the object (Gerber or Excellon) to mirror.'),
|
||||
('box', 'Name of object which act as box (cutout for example.)'),
|
||||
('name', 'Name of the object (Gerber, Geometry or Excellon) to be mirrored. Required.'),
|
||||
('axis', 'Mirror axis parallel to the X or Y axis.'),
|
||||
('dist', 'Distance of the mirror axis to the X or Y axis.')
|
||||
('box', 'Name of object which act as box (cutout for example.)'),
|
||||
('origin', 'Reference point . It is used only if the box is not used. Format (x,y).\n'
|
||||
'Comma will separate the X and Y coordinates.\n'
|
||||
'WARNING: no spaces are allowed. If uncertain enclose the two values inside parenthesis.\n'
|
||||
'See the example.')
|
||||
]),
|
||||
'examples': []
|
||||
'examples': ['mirror obj_name -box box_geo -axis X -origin 3.2,4.7']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
@@ -55,29 +61,30 @@ class TclCommandMirror(TclCommandSignaled):
|
||||
# Get source object.
|
||||
try:
|
||||
obj = self.app.collection.get_by_name(str(name))
|
||||
except:
|
||||
except Exception:
|
||||
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):
|
||||
if obj.kind != 'gerber' and obj.kind != 'geometry' and obj.kind != 'excellon':
|
||||
return "ERROR: Only Gerber, Excellon and Geometry objects can be mirrored."
|
||||
|
||||
# Axis
|
||||
try:
|
||||
axis = args['axis'].upper()
|
||||
except KeyError:
|
||||
return "ERROR: Specify -axis X or -axis Y"
|
||||
if 'axis' in args:
|
||||
try:
|
||||
axis = args['axis'].upper()
|
||||
except KeyError:
|
||||
axis = 'Y'
|
||||
else:
|
||||
axis = 'Y'
|
||||
|
||||
# Box
|
||||
if 'box' in args:
|
||||
try:
|
||||
box = self.app.collection.get_by_name(args['box'])
|
||||
except:
|
||||
return "Could not retrieve object box: %s" % args['box']
|
||||
except Exception:
|
||||
return "Could not retrieve object: %s" % args['box']
|
||||
|
||||
if box is None:
|
||||
return "Object box not found: %s" % args['box']
|
||||
@@ -89,20 +96,22 @@ class TclCommandMirror(TclCommandSignaled):
|
||||
|
||||
obj.mirror(axis, [px, py])
|
||||
obj.plot()
|
||||
|
||||
return
|
||||
except Exception as e:
|
||||
return "Operation failed: %s" % str(e)
|
||||
|
||||
else:
|
||||
# Origin
|
||||
if 'origin' in args:
|
||||
try:
|
||||
dist = float(args['dist'])
|
||||
origin_val = eval(args['origin'])
|
||||
x = float(origin_val[0])
|
||||
y = float(origin_val[1])
|
||||
except KeyError:
|
||||
dist = 0.0
|
||||
x, y = (0, 0)
|
||||
except ValueError:
|
||||
return "Invalid distance: %s" % args['dist']
|
||||
return "Invalid distance: %s" % str(args['origin'])
|
||||
|
||||
try:
|
||||
obj.mirror(axis, [dist, dist])
|
||||
obj.plot()
|
||||
obj.mirror(axis, [x, y])
|
||||
except Exception as e:
|
||||
return "Operation failed: %s" % str(e)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from ObjectCollection import *
|
||||
from tclCommands.TclCommand import TclCommand
|
||||
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandNew(TclCommand):
|
||||
"""
|
||||
@@ -10,6 +11,8 @@ class TclCommandNew(TclCommand):
|
||||
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['new']
|
||||
|
||||
description = '%s %s' % ("--", "Starts a new project. Clears objects from memory.")
|
||||
|
||||
# dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict()
|
||||
|
||||
@@ -23,7 +26,7 @@ class TclCommandNew(TclCommand):
|
||||
help = {
|
||||
'main': "Starts a new project. Clears objects from memory.",
|
||||
'args': collections.OrderedDict(),
|
||||
'examples': []
|
||||
'examples': ['new']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
@@ -36,4 +39,4 @@ class TclCommandNew(TclCommand):
|
||||
:return: None or exception
|
||||
"""
|
||||
|
||||
self.app.on_file_new()
|
||||
self.app.on_file_new(cli=True)
|
||||
|
||||
61
tclCommands/TclCommandNewExcellon.py
Normal file
61
tclCommands/TclCommandNewExcellon.py
Normal file
@@ -0,0 +1,61 @@
|
||||
# ##########################################################
|
||||
# FlatCAM: 2D Post-processing for Manufacturing #
|
||||
# File Author: Marius Adrian Stanciu (c) #
|
||||
# Date: 8/17/2019 #
|
||||
# MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
from tclCommands.TclCommand import TclCommandSignaled
|
||||
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandNewExcellon(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_excellon']
|
||||
|
||||
description = '%s %s' % ("--", "Creates a new empty Excellon object.")
|
||||
|
||||
# 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 = []
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': "Creates a new empty Excellon object.",
|
||||
'args': collections.OrderedDict([
|
||||
('name', 'New object name.'),
|
||||
]),
|
||||
'examples': ['new_excellon my_excellon', 'new_excellon']
|
||||
}
|
||||
|
||||
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 'name' in args:
|
||||
name = args['name']
|
||||
else:
|
||||
name = 'new_exc'
|
||||
self.app.app_obj.new_object('excellon', name, lambda x, y: None, plot=False)
|
||||
@@ -1,6 +1,7 @@
|
||||
from ObjectCollection import *
|
||||
from tclCommands.TclCommand import TclCommandSignaled
|
||||
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandNewGeometry(TclCommandSignaled):
|
||||
"""
|
||||
@@ -10,6 +11,8 @@ class TclCommandNewGeometry(TclCommandSignaled):
|
||||
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['new_geometry']
|
||||
|
||||
description = '%s %s' % ("--", "Creates a new empty Geometry object.")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered.
|
||||
# For positional arguments
|
||||
arg_names = collections.OrderedDict([
|
||||
@@ -23,15 +26,16 @@ class TclCommandNewGeometry(TclCommandSignaled):
|
||||
])
|
||||
|
||||
# array of mandatory options for current Tcl command: required = {'name','outname'}
|
||||
required = ['name']
|
||||
required = []
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': "Creates a new empty geometry object.",
|
||||
'main': "Creates a new empty Geometry object.",
|
||||
'args': collections.OrderedDict([
|
||||
('name', 'New object name.'),
|
||||
]),
|
||||
'examples': []
|
||||
'examples': ['new_geometry\n'
|
||||
'new_geometry my_new_geo']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
@@ -43,7 +47,9 @@ class TclCommandNewGeometry(TclCommandSignaled):
|
||||
without -somename and we do not have them in known arg_names
|
||||
:return: None or exception
|
||||
"""
|
||||
if 'name' in args:
|
||||
name = args['name']
|
||||
else:
|
||||
name = 'new_geo'
|
||||
|
||||
name = args['name']
|
||||
|
||||
self.app.new_object('geometry', str(name), lambda x, y: None)
|
||||
self.app.app_obj.new_object('geometry', str(name), lambda x, y: None, plot=False)
|
||||
|
||||
78
tclCommands/TclCommandNewGerber.py
Normal file
78
tclCommands/TclCommandNewGerber.py
Normal file
@@ -0,0 +1,78 @@
|
||||
# ##########################################################
|
||||
# FlatCAM: 2D Post-processing for Manufacturing #
|
||||
# File Author: Marius Adrian Stanciu (c) #
|
||||
# Date: 8/17/2019 #
|
||||
# MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
from tclCommands.TclCommand import TclCommandSignaled
|
||||
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandNewGerber(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_gerber']
|
||||
|
||||
description = '%s %s' % ("--", "Creates a new empty Gerber object.")
|
||||
|
||||
# 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 = []
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': "Creates a new empty Gerber object.",
|
||||
'args': collections.OrderedDict([
|
||||
('name', 'New object name.'),
|
||||
]),
|
||||
'examples': ['new_gerber', 'new_gerber my_new_gerber_name']
|
||||
}
|
||||
|
||||
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 'name' in args:
|
||||
name = args['name']
|
||||
else:
|
||||
name = 'new_grb'
|
||||
|
||||
def initialize(grb_obj, app_obj):
|
||||
grb_obj.multitool = False
|
||||
grb_obj.source_file = []
|
||||
grb_obj.multigeo = False
|
||||
grb_obj.follow = False
|
||||
grb_obj.apertures = {}
|
||||
grb_obj.solid_geometry = []
|
||||
|
||||
try:
|
||||
grb_obj.options['xmin'] = 0
|
||||
grb_obj.options['ymin'] = 0
|
||||
grb_obj.options['xmax'] = 0
|
||||
grb_obj.options['ymax'] = 0
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
self.app.app_obj.new_object('gerber', name, initialize, plot=False)
|
||||
108
tclCommands/TclCommandNregions.py
Normal file
108
tclCommands/TclCommandNregions.py
Normal file
@@ -0,0 +1,108 @@
|
||||
from tclCommands.TclCommand import TclCommand
|
||||
|
||||
from shapely.ops import unary_union
|
||||
|
||||
import collections
|
||||
|
||||
import gettext
|
||||
import appTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
|
||||
class TclCommandNregions(TclCommand):
|
||||
"""
|
||||
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 = ['non_copper_regions', 'ncr']
|
||||
|
||||
description = '%s %s' % ("--", "Creates a Geometry object with the non-copper regions.")
|
||||
|
||||
# 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),
|
||||
('margin', float),
|
||||
('rounded', 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 with the non-copper regions.",
|
||||
'args': collections.OrderedDict([
|
||||
('name', 'Object name for which to create non-copper regions. String. Required.'),
|
||||
('outname', 'Name of the resulting Geometry object. String.'),
|
||||
('margin', "Specify the edge of the PCB by drawing a box around all objects with this minimum distance. "
|
||||
"Float number."),
|
||||
('rounded', "Resulting geometry will have rounded corners. True (1) or False (0).")
|
||||
]),
|
||||
'examples': ['ncr name -margin 0.1 -rounded True -outname name_ncr']
|
||||
}
|
||||
|
||||
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 + "_noncopper"
|
||||
|
||||
obj = self.app.collection.get_by_name(name)
|
||||
if obj is None:
|
||||
self.raise_tcl_error("%s: %s" % (_("Object not found"), name))
|
||||
|
||||
if obj.kind != 'gerber' and obj.kind != 'geometry':
|
||||
self.raise_tcl_error('%s %s: %s.' % (_("Expected GerberObject or GeometryObject, got"), name, type(obj)))
|
||||
|
||||
if 'margin' not in args:
|
||||
args['margin'] = float(self.app.defaults["gerber_noncoppermargin"])
|
||||
margin = float(args['margin'])
|
||||
|
||||
if 'rounded' in args:
|
||||
try:
|
||||
par = args['rounded'].capitalize()
|
||||
except AttributeError:
|
||||
par = args['rounded']
|
||||
rounded = bool(eval(par))
|
||||
else:
|
||||
rounded = bool(eval(self.app.defaults["gerber_noncopperrounded"]))
|
||||
|
||||
del args['name']
|
||||
|
||||
try:
|
||||
def geo_init(geo_obj, app_obj):
|
||||
assert geo_obj.kind == 'geometry'
|
||||
|
||||
geo = unary_union(obj.solid_geometry)
|
||||
bounding_box = geo.envelope.buffer(float(margin))
|
||||
if not rounded:
|
||||
bounding_box = bounding_box.envelope
|
||||
|
||||
non_copper = bounding_box.difference(geo)
|
||||
geo_obj.solid_geometry = non_copper
|
||||
|
||||
self.app.app_obj.new_object("geometry", args['outname'], geo_init, plot=False)
|
||||
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()
|
||||
@@ -1,6 +1,7 @@
|
||||
from ObjectCollection import *
|
||||
from tclCommands.TclCommand import TclCommand
|
||||
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandOffset(TclCommand):
|
||||
"""
|
||||
@@ -13,6 +14,8 @@ class TclCommandOffset(TclCommand):
|
||||
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['offset']
|
||||
|
||||
description = '%s %s' % ("--", "Will offset the geometry of a named object. Does not create a new object.")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict([
|
||||
('name', str),
|
||||
@@ -22,21 +25,22 @@ class TclCommandOffset(TclCommand):
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
|
||||
option_types = collections.OrderedDict([
|
||||
|
||||
('x', float),
|
||||
('y', float)
|
||||
])
|
||||
|
||||
# array of mandatory options for current Tcl command: required = {'name','outname'}
|
||||
required = ['name', 'x', 'y']
|
||||
required = ['name']
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': "Changes the position of the object.",
|
||||
'main': "Changes the position of the object on X and/or Y axis.",
|
||||
'args': collections.OrderedDict([
|
||||
('name', 'Name of the object to offset.'),
|
||||
('x', 'Offset distance in the X axis.'),
|
||||
('y', 'Offset distance in the Y axis')
|
||||
('name', 'Name of the object to offset. Required.'),
|
||||
('x', 'Offset distance in the X axis. If it is not used it will be assumed to be 0.0'),
|
||||
('y', 'Offset distance in the Y axis. If it is not used it will be assumed to be 0.0')
|
||||
]),
|
||||
'examples': ['offset my_geometry 1.2 -0.3']
|
||||
'examples': ['offset my_geometry -x 1.2 -y -0.3', 'offset my_geometry -x 1.0']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
@@ -48,6 +52,12 @@ class TclCommandOffset(TclCommand):
|
||||
"""
|
||||
|
||||
name = args['name']
|
||||
x, y = args['x'], args['y']
|
||||
off_x = args['x'] if 'x' in args else 0.0
|
||||
off_y = args['y'] if 'y' in args else 0.0
|
||||
|
||||
x, y = float(off_x), float(off_y)
|
||||
|
||||
if (x, y) == (0.0, 0.0):
|
||||
return
|
||||
|
||||
self.app.collection.get_by_name(name).offset((x, y))
|
||||
|
||||
98
tclCommands/TclCommandOpenDXF.py
Normal file
98
tclCommands/TclCommandOpenDXF.py
Normal file
@@ -0,0 +1,98 @@
|
||||
from tclCommands.TclCommand import TclCommandSignaled
|
||||
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandOpenDXF(TclCommandSignaled):
|
||||
"""
|
||||
Tcl shell command to open an DXF file as a Geometry/Gerber Object.
|
||||
"""
|
||||
|
||||
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['open_dxf']
|
||||
|
||||
description = '%s %s' % ("--", "Open a DXF file as a Geometry (or Gerber) Object.")
|
||||
|
||||
# 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': "Open a DXF file as a Geometry (or Gerber) Object.",
|
||||
'args': collections.OrderedDict([
|
||||
('filename', 'Absolute path to file to open. Required.\n'
|
||||
'WARNING: no spaces are allowed. If unsure enclose the entire path with quotes.'),
|
||||
('type', 'Open as a Gerber or Geometry (default) object. Values can be: "geometry" or "gerber"'),
|
||||
('outname', 'Name of the resulting Geometry object.')
|
||||
]),
|
||||
'examples': ['open_dxf D:\\my_beautiful_svg_file.SVG']
|
||||
}
|
||||
|
||||
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 geo_obj.kind != 'geometry' and geo_obj.kind != 'gerber':
|
||||
# self.raise_tcl_error('Expected Geometry or Gerber, got %s %s.' % (outname, type(geo_obj)))
|
||||
if obj_type == "geometry":
|
||||
geo_obj.import_dxf_as_geo(filename, units=units)
|
||||
elif obj_type == "gerber":
|
||||
geo_obj.import_dxf_as_gerber(filename, units=units)
|
||||
else:
|
||||
return "fail"
|
||||
|
||||
filename = args['filename']
|
||||
|
||||
if 'outname' in args:
|
||||
outname = args['outname']
|
||||
else:
|
||||
outname = filename.split('/')[-1].split('\\')[-1]
|
||||
|
||||
if 'type' in args:
|
||||
obj_type = str(args['type']).lower()
|
||||
else:
|
||||
obj_type = 'geometry'
|
||||
|
||||
if obj_type != "geometry" and obj_type != "gerber":
|
||||
self.raise_tcl_error("Option type can be 'geometry' or 'gerber' only, got '%s'." % obj_type)
|
||||
|
||||
units = self.app.defaults['units'].upper()
|
||||
|
||||
with self.app.proc_container.new('%s' % _("Opening ...")):
|
||||
|
||||
# Object creation
|
||||
ret_val = self.app.app_obj.new_object(obj_type, outname, obj_init, plot=False)
|
||||
if ret_val == 'fail':
|
||||
filename = self.app.defaults['global_tcl_path'] + '/' + outname
|
||||
ret_val = self.app.app_obj.new_object(obj_type, outname, obj_init, plot=False)
|
||||
self.app.shell.append_output(
|
||||
"No path provided or path is wrong. Using the default Path... \n")
|
||||
|
||||
if ret_val == 'fail':
|
||||
return "Failed. The OpenDXF command was used but could not open the DXF file"
|
||||
|
||||
# Register recent file
|
||||
self.app.file_opened.emit("dxf", filename)
|
||||
|
||||
# GUI feedback
|
||||
self.app.inform.emit("Opened: " + filename)
|
||||
@@ -1,6 +1,7 @@
|
||||
from ObjectCollection import *
|
||||
from tclCommands.TclCommand import TclCommandSignaled
|
||||
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandOpenExcellon(TclCommandSignaled):
|
||||
"""
|
||||
@@ -10,6 +11,8 @@ class TclCommandOpenExcellon(TclCommandSignaled):
|
||||
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['open_excellon']
|
||||
|
||||
description = '%s %s' % ("--", "Opens an Excellon file, parse it and create a Excellon object from it.")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered.
|
||||
# For positional arguments
|
||||
arg_names = collections.OrderedDict([
|
||||
@@ -27,12 +30,15 @@ class TclCommandOpenExcellon(TclCommandSignaled):
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': "Opens an Excellon file.",
|
||||
'main': "Opens an Excellon file, parse it and create a Excellon object from it.",
|
||||
'args': collections.OrderedDict([
|
||||
('filename', 'Path to file to open.'),
|
||||
('filename', 'Absolute path to file to open. Required.\n'
|
||||
'WARNING: no spaces are allowed. If unsure enclose the entire path with quotes.'),
|
||||
('outname', 'Name of the resulting Excellon object.')
|
||||
]),
|
||||
'examples': []
|
||||
'examples': ['open_excellon D:\\my_excellon_file.DRL',
|
||||
'open_excellon "D:\\my_excellon_file with spaces in the name.DRL"',
|
||||
'open_excellon path_to_file']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
@@ -47,4 +53,10 @@ class TclCommandOpenExcellon(TclCommandSignaled):
|
||||
|
||||
filename = args.pop('filename')
|
||||
|
||||
self.app.open_excellon(filename, **args)
|
||||
# if ' ' in filename:
|
||||
# return "The absolute path to the project file contain spaces which is not allowed.\n" \
|
||||
# "Please enclose the path within quotes."
|
||||
|
||||
args['plot'] = False
|
||||
args['from_tcl'] = True
|
||||
self.app.f_handlers.open_excellon(filename, **args)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from ObjectCollection import *
|
||||
from tclCommands.TclCommand import TclCommandSignaled
|
||||
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandOpenGCode(TclCommandSignaled):
|
||||
"""
|
||||
@@ -11,6 +12,8 @@ class TclCommandOpenGCode(TclCommandSignaled):
|
||||
# backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['open_gcode']
|
||||
|
||||
description = '%s %s' % ("--", "Opens an GCode file, parse it and create a GCode object from it.")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered.
|
||||
# For positional arguments
|
||||
arg_names = collections.OrderedDict([
|
||||
@@ -28,12 +31,14 @@ class TclCommandOpenGCode(TclCommandSignaled):
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': "Opens a G-Code file.",
|
||||
'main': "Opens an GCode file, parse it and create a GCode object from it.",
|
||||
'args': collections.OrderedDict([
|
||||
('filename', 'Path to file to open.'),
|
||||
('filename', 'Absolute path to file to open. Required.\n'
|
||||
'WARNING: no spaces are allowed. If unsure enclose the entire path with quotes.'),
|
||||
('outname', 'Name of the resulting CNCJob object.')
|
||||
]),
|
||||
'examples': []
|
||||
'examples': ['open_gcode D:\\my_gcode_file.NC',
|
||||
'open_gcode "D:\\my_gcode_file with spaces in the name.TXT"']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
@@ -45,5 +50,12 @@ class TclCommandOpenGCode(TclCommandSignaled):
|
||||
without -somename and we do not have them in known arg_names
|
||||
:return: None or exception
|
||||
"""
|
||||
args['plot'] = False
|
||||
args['from_tcl'] = True
|
||||
filename = args.pop("filename")
|
||||
|
||||
self.app.open_gcode(args['filename'], **args)
|
||||
# if ' ' in filename:
|
||||
# return "The absolute path to the project file contain spaces which is not allowed.\n" \
|
||||
# "Please enclose the path within quotes."
|
||||
|
||||
self.app.f_handlers.open_gcode(filename, **args)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
from ObjectCollection import *
|
||||
from tclCommands.TclCommand import TclCommandSignaled
|
||||
from camlib import ParseError
|
||||
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandOpenGerber(TclCommandSignaled):
|
||||
@@ -10,6 +12,8 @@ class TclCommandOpenGerber(TclCommandSignaled):
|
||||
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['open_gerber']
|
||||
|
||||
description = '%s %s' % ("--", "Opens an Gerber file, parse it and create a Gerber object from it.")
|
||||
|
||||
# dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict([
|
||||
('filename', str)
|
||||
@@ -27,10 +31,12 @@ class TclCommandOpenGerber(TclCommandSignaled):
|
||||
help = {
|
||||
'main': "Opens a Gerber file.",
|
||||
'args': collections.OrderedDict([
|
||||
('filename', 'Path to file to open.'),
|
||||
('filename', 'Absolute path to file to open. Required.\n'
|
||||
'WARNING: no spaces are allowed. If unsure enclose the entire path with quotes.'),
|
||||
('outname', 'Name of the resulting Gerber object.')
|
||||
]),
|
||||
'examples': []
|
||||
'examples': ["open_gerber gerber_object_path -outname bla",
|
||||
'open_gerber "D:\\my_gerber_file with spaces in the name.GRB"']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
@@ -43,50 +49,17 @@ class TclCommandOpenGerber(TclCommandSignaled):
|
||||
:return: None or exception
|
||||
"""
|
||||
|
||||
# How the object should be initialized
|
||||
def obj_init(gerber_obj, app_obj):
|
||||
if 'follow' in args:
|
||||
self.raise_tcl_error("The 'follow' parameter is obsolete. To create 'follow' geometry use the 'follow' "
|
||||
"parameter for the Tcl Command isolate()")
|
||||
|
||||
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)
|
||||
|
||||
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']
|
||||
filename = args.pop('filename')
|
||||
|
||||
if 'outname' in args:
|
||||
outname = args['outname']
|
||||
outname = args.pop('outname')
|
||||
else:
|
||||
outname = filename.split('/')[-1].split('\\')[-1]
|
||||
|
||||
if 'follow' in args:
|
||||
self.raise_tcl_error("The 'follow' parameter is obsolete. To create 'follow' geometry use the 'follow' parameter for the Tcl Command isolate()")
|
||||
|
||||
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)
|
||||
args['plot'] = False
|
||||
args['from_tcl'] = True
|
||||
self.app.f_handlers.open_gerber(filename, outname, **args)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from ObjectCollection import *
|
||||
from tclCommands.TclCommand import TclCommandSignaled
|
||||
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandOpenProject(TclCommandSignaled):
|
||||
"""
|
||||
@@ -10,6 +11,8 @@ class TclCommandOpenProject(TclCommandSignaled):
|
||||
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['open_project']
|
||||
|
||||
description = '%s %s' % ("--", "Opens an FlatCAm project file, parse it and recreate all the objects.")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered.
|
||||
# For positional arguments
|
||||
arg_names = collections.OrderedDict([
|
||||
@@ -27,11 +30,13 @@ class TclCommandOpenProject(TclCommandSignaled):
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': "Opens a FlatCAM project.",
|
||||
'main': "Opens an FlatCAm project file, parse it and recreate all the objects.",
|
||||
'args': collections.OrderedDict([
|
||||
('filename', 'Path to file to open.'),
|
||||
('filename', 'Absolute path to file to open. Required.\n'
|
||||
'WARNING: no spaces are allowed. If unsure enclose the entire path with quotes.'),
|
||||
]),
|
||||
'examples': []
|
||||
'examples': ['open_project D:\\my_project_file.FlatPrj',
|
||||
'open_project "D:\\my_project_file with spaces in the name.FlatPrj"']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
@@ -43,5 +48,9 @@ class TclCommandOpenProject(TclCommandSignaled):
|
||||
without -somename and we do not have them in known arg_names
|
||||
:return: None or exception
|
||||
"""
|
||||
filename = args['filename']
|
||||
# if ' ' in filename:
|
||||
# return "The absolute path to the project file contain spaces which is not allowed.\n" \
|
||||
# "Please enclose the path within quotes."
|
||||
|
||||
self.app.open_project(args['filename'])
|
||||
self.app.f_handlers.open_project(filename, cli=True, plot=False, from_tcl=True)
|
||||
|
||||
93
tclCommands/TclCommandOpenSVG.py
Normal file
93
tclCommands/TclCommandOpenSVG.py
Normal file
@@ -0,0 +1,93 @@
|
||||
from tclCommands.TclCommand import TclCommandSignaled
|
||||
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandOpenSVG(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 = ['open_svg']
|
||||
|
||||
description = '%s %s' % ("--", "Open a SVG file as a Geometry (or Gerber) Object.")
|
||||
|
||||
# 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': "Open a SVG file as a Geometry (or Gerber) Object.",
|
||||
'args': collections.OrderedDict([
|
||||
('filename', 'Absolute path to file to open. Required.\n'
|
||||
'WARNING: no spaces are allowed. If unsure enclose the entire path with quotes.'),
|
||||
('type', 'Open as a Gerber or Geometry (default) object. Values can be: "geometry" or "gerber"'),
|
||||
('outname', 'Name of the resulting Geometry object.')
|
||||
]),
|
||||
'examples': ['open_svg D:\\my_beautiful_svg_file.SVG']
|
||||
}
|
||||
|
||||
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 geo_obj.kind != 'geometry' or geo_obj.kind != 'gerber':
|
||||
# self.raise_tcl_error('Expected Geometry or Gerber, got %s %s.' % (outname, type(geo_obj)))
|
||||
|
||||
geo_obj.import_svg(filename, obj_type, units=units)
|
||||
|
||||
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'].lower()
|
||||
else:
|
||||
obj_type = 'geometry'
|
||||
|
||||
if obj_type != "geometry" and obj_type != "gerber":
|
||||
self.raise_tcl_error("Option type can be 'geometry' or 'gerber' only, got '%s'." % obj_type)
|
||||
|
||||
units = self.app.defaults['units'].upper()
|
||||
|
||||
with self.app.proc_container.new(_("Working ...")):
|
||||
|
||||
# Object creation
|
||||
ret_val = self.app.app_obj.new_object(obj_type, outname, obj_init, plot=False)
|
||||
if ret_val == 'fail':
|
||||
filename = self.app.defaults['global_tcl_path'] + '/' + outname
|
||||
ret_val = self.app.app_obj.new_object(obj_type, outname, obj_init, plot=False)
|
||||
self.app.shell.append_output(
|
||||
"No path provided or path is wrong. Using the default Path... \n")
|
||||
if ret_val == 'fail':
|
||||
return "Failed. The OpenSVG command was used but could not open the SVG file"
|
||||
|
||||
# Register recent file
|
||||
self.app.file_opened.emit("svg", filename)
|
||||
|
||||
# GUI feedback
|
||||
self.app.inform.emit("Opened: " + filename)
|
||||
@@ -1,6 +1,7 @@
|
||||
from ObjectCollection import *
|
||||
from tclCommands.TclCommand import TclCommandSignaled
|
||||
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandOptions(TclCommandSignaled):
|
||||
"""
|
||||
@@ -10,6 +11,9 @@ class TclCommandOptions(TclCommandSignaled):
|
||||
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['options']
|
||||
|
||||
description = '%s %s' % ("--", "Will return the options (settings) for an object as a string "
|
||||
"with values separated by \\n.")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered.
|
||||
# For positional arguments
|
||||
arg_names = collections.OrderedDict([
|
||||
@@ -27,11 +31,11 @@ class TclCommandOptions(TclCommandSignaled):
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': "Shows the settings for an object.",
|
||||
'main': "Will return the options (settings) for an object as a string with values separated by \\n.",
|
||||
'args': collections.OrderedDict([
|
||||
('name', 'Object name.'),
|
||||
('name', 'Object name for which to return the options. Required.'),
|
||||
]),
|
||||
'examples': []
|
||||
'examples': ['options obj_name']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
|
||||
@@ -1,8 +1,20 @@
|
||||
from ObjectCollection import *
|
||||
from tclCommands.TclCommand import TclCommandSignaled
|
||||
from tclCommands.TclCommand import TclCommand
|
||||
|
||||
import collections
|
||||
import logging
|
||||
|
||||
import gettext
|
||||
import appTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
log = logging.getLogger('base')
|
||||
|
||||
|
||||
class TclCommandPaint(TclCommandSignaled):
|
||||
class TclCommandPaint(TclCommand):
|
||||
"""
|
||||
Paint the interior of polygons
|
||||
"""
|
||||
@@ -10,37 +22,61 @@ class TclCommandPaint(TclCommandSignaled):
|
||||
# Array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['paint']
|
||||
|
||||
description = '%s %s' % ("--", "Paint polygons in the specified object by covering them with toolpaths.")
|
||||
|
||||
# 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([
|
||||
('tooldia', str),
|
||||
('overlap', float),
|
||||
('order', str),
|
||||
('offset', float),
|
||||
('method', str),
|
||||
('connect', str),
|
||||
('contour', str),
|
||||
|
||||
('all', str),
|
||||
('single', str),
|
||||
('ref', str),
|
||||
('box', str),
|
||||
('outname', str),
|
||||
('all', bool),
|
||||
('x', float),
|
||||
('y', float)
|
||||
])
|
||||
|
||||
# array of mandatory options for current Tcl command: required = {'name','outname'}
|
||||
required = ['name', 'tooldia', 'overlap']
|
||||
required = ['name']
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': "Paint polygons",
|
||||
'main': "Paint polygons in the specified object by covering them with toolpaths.\n"
|
||||
"Can use only one of the parameters: 'all', 'box', 'single'.",
|
||||
'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.')
|
||||
('name', 'Name of the source Geometry object. String.'),
|
||||
('tooldia', 'Diameter of the tools to be used. Can be a comma separated list of diameters.\n'
|
||||
'WARNING: No space is allowed between tool diameters. E.g: correct: 0.5,1 / incorrect: 0.5, 1'),
|
||||
('overlap', 'Percentage of tool diameter to overlap current pass over previous pass. Float [0, 99.9999]\n'
|
||||
'E.g: for a 25% from tool diameter overlap use -overlap 25'),
|
||||
('offset', 'Distance from the polygon border where painting starts. Float number.'),
|
||||
('order', 'Can have the values: "no", "fwd" and "rev". String.\n'
|
||||
'It is useful when there are multiple tools in tooldia parameter.\n'
|
||||
'"no" -> the order used is the one provided.\n'
|
||||
'"fwd" -> tools are ordered from smallest to biggest.\n'
|
||||
'"rev" -> tools are ordered from biggest to smallest.'),
|
||||
('method', 'Algorithm for painting. Can be: "standard", "seed", "lines", "laser_lines", "combo".'),
|
||||
('connect', 'Draw lines to minimize tool lifts. True (1) or False (0)'),
|
||||
('contour', 'Cut around the perimeter of the painting. True (1) or False (0)'),
|
||||
('all', 'If used, paint all polygons in the object.'),
|
||||
('box', 'name of the object to be used as paint reference. String.'),
|
||||
('single', 'Value is in format x,y or (x,y). Example: 2.0,1.1\n'
|
||||
'If used will paint a single polygon specified by "x" and "y" values.\n'
|
||||
'WARNING: No spaces allowed in the value. Use dot decimals separator.'),
|
||||
('outname', 'Name of the resulting Geometry object. String. No spaces.'),
|
||||
]),
|
||||
'examples': []
|
||||
'examples': ["paint obj_name -tooldia 0.3 -offset 0.1 -method 'seed' -all",
|
||||
"paint obj_name -tooldia 0.3 -offset 0.1 -method 'seed' -single 3.3,2.0"]
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
@@ -54,31 +90,212 @@ class TclCommandPaint(TclCommandSignaled):
|
||||
"""
|
||||
|
||||
name = args['name']
|
||||
tooldia = args['tooldia']
|
||||
overlap = args['overlap']
|
||||
|
||||
# Get source object.
|
||||
try:
|
||||
obj = self.app.collection.get_by_name(str(name))
|
||||
except Exception as e:
|
||||
log.debug("TclCommandPaint.execute() --> %s" % str(e))
|
||||
self.raise_tcl_error("%s: %s" % (_("Could not retrieve object"), name))
|
||||
return "Could not retrieve object: %s" % name
|
||||
|
||||
if 'tooldia' in args:
|
||||
tooldia = str(args['tooldia'])
|
||||
else:
|
||||
tooldia = str(self.app.defaults["tools_paint_tooldia"])
|
||||
|
||||
if 'overlap' in args:
|
||||
overlap = float(args['overlap']) / 100.0
|
||||
else:
|
||||
overlap = float(self.app.defaults["tools_paint_overlap"]) / 100.0
|
||||
|
||||
if 'order' in args:
|
||||
order = args['order']
|
||||
else:
|
||||
order = str(self.app.defaults["tools_paint_order"])
|
||||
|
||||
if 'offset' in args:
|
||||
offset = float(args['offset'])
|
||||
else:
|
||||
offset = float(self.app.defaults["tools_paint_offset"])
|
||||
|
||||
if 'method' in args:
|
||||
method = args['method']
|
||||
if method == "standard":
|
||||
method = _("Standard")
|
||||
elif method == "seed":
|
||||
method = _("Seed")
|
||||
elif method == "lines":
|
||||
method = _("Lines")
|
||||
elif method == "laser_lines":
|
||||
method = _("Laser_lines")
|
||||
else:
|
||||
method = _("Combo")
|
||||
else:
|
||||
method = str(self.app.defaults["tools_paint_method"])
|
||||
|
||||
if 'connect' in args:
|
||||
try:
|
||||
par = args['connect'].capitalize()
|
||||
except AttributeError:
|
||||
par = args['connect']
|
||||
connect = bool(eval(par))
|
||||
else:
|
||||
connect = bool(eval(str(self.app.defaults["tools_paint_connect"])))
|
||||
|
||||
if 'contour' in args:
|
||||
try:
|
||||
par = args['contour'].capitalize()
|
||||
except AttributeError:
|
||||
par = args['contour']
|
||||
contour = bool(eval(par))
|
||||
else:
|
||||
contour = bool(eval(str(self.app.defaults["tools_paint_contour"])))
|
||||
|
||||
if 'outname' in args:
|
||||
outname = args['outname']
|
||||
else:
|
||||
outname = name + "_paint"
|
||||
|
||||
obj = self.app.collection.get_by_name(name)
|
||||
# used only to have correct information's in the obj.tools[tool]['data'] dict
|
||||
if "all" in args:
|
||||
select = _("All")
|
||||
elif "single" in args:
|
||||
select = _("Polygon Selection")
|
||||
else:
|
||||
select = _("Reference Object")
|
||||
|
||||
try:
|
||||
tools = [float(eval(dia)) for dia in tooldia.split(",") if dia != '']
|
||||
except AttributeError:
|
||||
tools = [float(tooldia)]
|
||||
# store here the default data for Geometry Data
|
||||
default_data = {}
|
||||
default_data.update({
|
||||
"name": outname,
|
||||
"plot": False,
|
||||
"cutz": self.app.defaults["geometry_cutz"],
|
||||
"vtipdia": float(self.app.defaults["tools_paint_tipdia"]),
|
||||
"vtipangle": float(self.app.defaults["tools_paint_tipangle"]),
|
||||
"travelz": self.app.defaults["geometry_travelz"],
|
||||
"feedrate": self.app.defaults["geometry_feedrate"],
|
||||
"feedrate_z": self.app.defaults["geometry_feedrate_z"],
|
||||
"feedrate_rapid": self.app.defaults["geometry_feedrate_rapid"],
|
||||
"dwell": self.app.defaults["geometry_dwell"],
|
||||
"dwelltime": self.app.defaults["geometry_dwelltime"],
|
||||
"multidepth": self.app.defaults["geometry_multidepth"],
|
||||
"ppname_g": self.app.defaults["geometry_ppname_g"],
|
||||
"depthperpass": self.app.defaults["geometry_depthperpass"],
|
||||
"extracut": self.app.defaults["geometry_extracut"],
|
||||
"extracut_length": self.app.defaults["geometry_extracut_length"],
|
||||
"toolchange": self.app.defaults["geometry_toolchange"],
|
||||
"toolchangez": self.app.defaults["geometry_toolchangez"],
|
||||
"endz": self.app.defaults["geometry_endz"],
|
||||
"endxy": self.app.defaults["geometry_endxy"],
|
||||
|
||||
"spindlespeed": self.app.defaults["geometry_spindlespeed"],
|
||||
"toolchangexy": self.app.defaults["geometry_toolchangexy"],
|
||||
"startz": self.app.defaults["geometry_startz"],
|
||||
|
||||
"area_exclusion": self.app.defaults["geometry_area_exclusion"],
|
||||
"area_shape": self.app.defaults["geometry_area_shape"],
|
||||
"area_strategy": self.app.defaults["geometry_area_strategy"],
|
||||
"area_overz": float(self.app.defaults["geometry_area_overz"]),
|
||||
|
||||
"tooldia": tooldia,
|
||||
"tools_paint_offset": offset,
|
||||
"tools_paint_method": method,
|
||||
"tools_paint_selectmethod": select,
|
||||
"tools_paint_connect": connect,
|
||||
"tools_paint_contour": contour,
|
||||
"tools_paint_overlap": overlap
|
||||
})
|
||||
paint_tools = {}
|
||||
|
||||
tooluid = 0
|
||||
for tool in tools:
|
||||
tooluid += 1
|
||||
paint_tools.update({
|
||||
int(tooluid): {
|
||||
'tooldia': self.app.dec_format(float(tool), self.app.decimals),
|
||||
'offset': 'Path',
|
||||
'offset_value': 0.0,
|
||||
'type': 'Iso',
|
||||
'tool_type': 'C1',
|
||||
'data': dict(default_data),
|
||||
'solid_geometry': []
|
||||
}
|
||||
})
|
||||
paint_tools[int(tooluid)]['data']['tooldia'] = self.app.dec_format(float(tool), self.app.decimals)
|
||||
|
||||
if obj is None:
|
||||
self.raise_tcl_error("Object not found: %s" % name)
|
||||
return "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)
|
||||
# Paint all polygons in the painted object
|
||||
if 'all' in args:
|
||||
self.app.paint_tool.paint_poly_all(obj=obj,
|
||||
tooldia=tooldia,
|
||||
order=order,
|
||||
method=method,
|
||||
outname=outname,
|
||||
tools_storage=paint_tools,
|
||||
plot=False,
|
||||
run_threaded=False)
|
||||
return
|
||||
|
||||
if 'x' not in args or 'y' not in args:
|
||||
self.raise_tcl_error('Expected -all 1 or -x <value> and -y <value>.')
|
||||
# Paint single polygon in the painted object
|
||||
if 'single' in args:
|
||||
if not args['single'] or args['single'] == '':
|
||||
self.raise_tcl_error('%s Got: %s' %
|
||||
(_("Expected a tuple value like -single 3.2,0.1."), str(args['single'])))
|
||||
else:
|
||||
coords_xy = [float(eval(a)) for a in args['single'].split(",") if a != '']
|
||||
|
||||
x = args['x']
|
||||
y = args['y']
|
||||
if coords_xy and len(coords_xy) != 2:
|
||||
self.raise_tcl_error('%s Got: %s' %
|
||||
(_("Expected a tuple value like -single 3.2,0.1."), str(coords_xy)))
|
||||
x = coords_xy[0]
|
||||
y = coords_xy[1]
|
||||
|
||||
obj.paint_poly_single_click([x, y], tooldia, overlap, outname)
|
||||
ret_val = self.app.paint_tool.paint_poly(obj=obj,
|
||||
inside_pt=[x, y],
|
||||
tooldia=tooldia,
|
||||
order=order,
|
||||
method=method,
|
||||
outname=outname,
|
||||
tools_storage=paint_tools,
|
||||
plot=False,
|
||||
run_threaded=False)
|
||||
if ret_val == 'fail':
|
||||
return "Could not find a Polygon at the specified location."
|
||||
return
|
||||
|
||||
# Paint all polygons found within the box object from the the painted object
|
||||
if 'box' in args:
|
||||
box_name = args['box']
|
||||
|
||||
if box_name is None:
|
||||
self.raise_tcl_error('%s' % _("Expected -box <value>."))
|
||||
|
||||
# Get box source object.
|
||||
try:
|
||||
box_obj = self.app.collection.get_by_name(str(box_name))
|
||||
except Exception as e:
|
||||
log.debug("TclCommandPaint.execute() --> %s" % str(e))
|
||||
self.raise_tcl_error("%s: %s" % (_("Could not retrieve object"), name))
|
||||
return "Could not retrieve object: %s" % name
|
||||
|
||||
self.app.paint_tool.paint_poly_ref(obj=obj,
|
||||
sel_obj=box_obj,
|
||||
tooldia=tooldia,
|
||||
order=order,
|
||||
method=method,
|
||||
outname=outname,
|
||||
tools_storage=paint_tools,
|
||||
plot=False,
|
||||
run_threaded=False)
|
||||
return
|
||||
|
||||
self.raise_tcl_error("%s:" % _("None of the following args: 'box', 'single', 'all' were used.\n"
|
||||
"Paint failed."))
|
||||
return "None of the following args: 'box', 'single', 'all' were used. Paint failed."
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
from ObjectCollection import *
|
||||
from copy import copy,deepcopy
|
||||
|
||||
from tclCommands.TclCommand import TclCommand
|
||||
|
||||
import shapely.affinity as affinity
|
||||
|
||||
import logging
|
||||
from copy import deepcopy
|
||||
import collections
|
||||
|
||||
log = logging.getLogger('base')
|
||||
|
||||
|
||||
class TclCommandPanelize(TclCommand):
|
||||
"""
|
||||
@@ -13,7 +18,10 @@ class TclCommandPanelize(TclCommand):
|
||||
"""
|
||||
|
||||
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['panelize','pan', 'panel']
|
||||
aliases = ['panelize', 'pan', 'panel']
|
||||
|
||||
description = '%s %s' % ("--", "Create a new object with an array of duplicates of the original geometry, "
|
||||
"arranged in a grid.")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict([
|
||||
@@ -28,15 +36,15 @@ class TclCommandPanelize(TclCommand):
|
||||
('spacing_rows', float),
|
||||
('box', str),
|
||||
('outname', str),
|
||||
('threaded', int)
|
||||
('use_thread', str)
|
||||
])
|
||||
|
||||
# array of mandatory options for current Tcl command: required = {'name','outname'}
|
||||
required = ['name', 'rows', 'columns']
|
||||
required = ['name']
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': 'Rectangular panelizing.',
|
||||
'main': 'Create a new object with an array of duplicates of the original geometry, arranged in a grid.',
|
||||
'args': collections.OrderedDict([
|
||||
('name', 'Name of the object to panelize.'),
|
||||
('box', 'Name of object which acts as box (cutout for example.)'
|
||||
@@ -46,9 +54,16 @@ class TclCommandPanelize(TclCommand):
|
||||
('columns', 'Number of columns.'),
|
||||
('rows', 'Number of rows;'),
|
||||
('outname', 'Name of the new geometry object.'),
|
||||
('threaded', '0 = non-threaded || 1 = threaded')
|
||||
('use_thread', 'False (0) = non-threaded execution or True (1) = threaded execution')
|
||||
]),
|
||||
'examples': []
|
||||
'examples': [
|
||||
'panelize obj_name',
|
||||
|
||||
'panel obj_name -rows 2 -columns 2 -spacing_columns 0.4 -spacing_rows 1.3 -box box_obj_name '
|
||||
'-outname panelized_name',
|
||||
|
||||
'panel obj_name -columns 2 -box box_obj_name -outname panelized_name',
|
||||
]
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
@@ -64,7 +79,7 @@ class TclCommandPanelize(TclCommand):
|
||||
# Get source object.
|
||||
try:
|
||||
obj = self.app.collection.get_by_name(str(name))
|
||||
except:
|
||||
except Exception:
|
||||
return "Could not retrieve object: %s" % name
|
||||
|
||||
if obj is None:
|
||||
@@ -74,37 +89,48 @@ class TclCommandPanelize(TclCommand):
|
||||
boxname = args['box']
|
||||
try:
|
||||
box = self.app.collection.get_by_name(boxname)
|
||||
except:
|
||||
except Exception:
|
||||
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 'columns' in args:
|
||||
columns = int(args['columns'])
|
||||
else:
|
||||
columns = int(0)
|
||||
|
||||
if 'rows' in args:
|
||||
rows = int(args['rows'])
|
||||
else:
|
||||
rows = int(0)
|
||||
|
||||
if 'columns' not in args and 'rows' not in args:
|
||||
return "ERROR: Specify either -columns or -rows. The one not specified it will assumed to be 0"
|
||||
|
||||
if 'outname' in args:
|
||||
outname = args['outname']
|
||||
else:
|
||||
outname = name + '_panelized'
|
||||
|
||||
if 'threaded' in args:
|
||||
threaded = args['threaded']
|
||||
if 'use_thread' in args:
|
||||
try:
|
||||
par = args['use_thread'].capitalize()
|
||||
except AttributeError:
|
||||
par = args['use_thread']
|
||||
threaded = bool(eval(par))
|
||||
else:
|
||||
threaded = 1
|
||||
threaded = False
|
||||
|
||||
if 'spacing_columns' in args:
|
||||
spacing_columns = args['spacing_columns']
|
||||
spacing_columns = int(args['spacing_columns'])
|
||||
else:
|
||||
spacing_columns = 5
|
||||
|
||||
if 'spacing_rows' in args:
|
||||
spacing_rows = args['spacing_rows']
|
||||
spacing_rows = int(args['spacing_rows'])
|
||||
else:
|
||||
spacing_rows = 5
|
||||
|
||||
rows = args['rows']
|
||||
columns = args['columns']
|
||||
|
||||
xmin, ymin, xmax, ymax = box.bounds()
|
||||
lenghtx = xmax - xmin + spacing_columns
|
||||
lenghty = ymax - ymin + spacing_rows
|
||||
@@ -126,12 +152,12 @@ class TclCommandPanelize(TclCommand):
|
||||
# objs.append(obj_init)
|
||||
#
|
||||
# def initialize_geometry(obj_init, app):
|
||||
# FlatCAMGeometry.merge(objs, obj_init)
|
||||
# GeometryObject.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)
|
||||
# ExcellonObject.merge(objs, obj_init)
|
||||
#
|
||||
# objs = []
|
||||
# if obj is not None:
|
||||
@@ -140,20 +166,21 @@ class TclCommandPanelize(TclCommand):
|
||||
# currentx = 0
|
||||
# for col in range(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,
|
||||
# if isinstance(obj, ExcellonObject):
|
||||
# self.app.app_obj.new_object("excellon", local_outname, initialize_local_excellon,
|
||||
# plot=False,
|
||||
# autoselected=False)
|
||||
# else:
|
||||
# self.app.new_object("geometry", local_outname, initialize_local, plot=False,
|
||||
# self.app.app_obj.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)
|
||||
# if isinstance(obj, ExcellonObject):
|
||||
# self.app.app_obj.new_object("excellon", outname, initialize_excellon)
|
||||
# else:
|
||||
# self.app.new_object("geometry", outname, initialize_geometry)
|
||||
# self.app.app_obj.new_object("geometry", outname, initialize_geometry)
|
||||
#
|
||||
# # deselect all to avoid delete selected object when run delete from shell
|
||||
# self.app.collection.set_all_inactive()
|
||||
@@ -171,45 +198,38 @@ class TclCommandPanelize(TclCommand):
|
||||
if obj is not None:
|
||||
self.app.inform.emit("Generating panel ... Please wait.")
|
||||
|
||||
self.app.progress.emit(0)
|
||||
|
||||
def job_init_excellon(obj_fin, app_obj):
|
||||
currenty = 0.0
|
||||
self.app.progress.emit(10)
|
||||
|
||||
obj_fin.tools = obj.tools.copy()
|
||||
obj_fin.drills = []
|
||||
obj_fin.slots = []
|
||||
obj_fin.solid_geometry = []
|
||||
if 'drills' not in obj_fin.tools:
|
||||
obj_fin.tools['drills'] = []
|
||||
if 'slots' not in obj_fin.tools:
|
||||
obj_fin.tools['slots'] = []
|
||||
if 'solid_geometry' not in obj_fin.tools:
|
||||
obj_fin.tools['solid_geometry'] = []
|
||||
|
||||
for option in obj.options:
|
||||
if option is not 'name':
|
||||
if option != 'name':
|
||||
try:
|
||||
obj_fin.options[option] = obj.options[option]
|
||||
except:
|
||||
log.warning("Failed to copy option.", option)
|
||||
except Exception as e:
|
||||
app_obj.log.warning("Failed to copy option: %s" % str(option))
|
||||
app_obj.log.debug("TclCommandPanelize.execute().panelize2() --> %s" % str(e))
|
||||
|
||||
for row in range(rows):
|
||||
currentx = 0.0
|
||||
for col in range(columns):
|
||||
if obj.drills:
|
||||
for tool_dict in obj.drills:
|
||||
point_offseted = affinity.translate(tool_dict['point'], currentx, currenty)
|
||||
obj_fin.drills.append(
|
||||
{
|
||||
"point": point_offseted,
|
||||
"tool": tool_dict['tool']
|
||||
}
|
||||
)
|
||||
if obj.slots:
|
||||
for tool_dict in obj.slots:
|
||||
start_offseted = affinity.translate(tool_dict['start'], currentx, currenty)
|
||||
stop_offseted = affinity.translate(tool_dict['stop'], currentx, currenty)
|
||||
obj_fin.slots.append(
|
||||
{
|
||||
"start": start_offseted,
|
||||
"stop": stop_offseted,
|
||||
"tool": tool_dict['tool']
|
||||
}
|
||||
if 'drills' in obj.tools:
|
||||
for drill_pt in obj.tools['drills']:
|
||||
point_offseted = affinity.translate(drill_pt, currentx, currenty)
|
||||
obj_fin.tools['drills'].append(point_offseted)
|
||||
if 'slots' in obj.tools:
|
||||
for slot_tuple in obj.tools['slots']:
|
||||
start_offseted = affinity.translate(slot_tuple[0], currentx, currenty)
|
||||
stop_offseted = affinity.translate(slot_tuple[1], currentx, currenty)
|
||||
obj_fin.tools['slots'].append(
|
||||
(start_offseted, stop_offseted)
|
||||
)
|
||||
currentx += lenghtx
|
||||
currenty += lenghty
|
||||
@@ -224,7 +244,7 @@ class TclCommandPanelize(TclCommand):
|
||||
|
||||
def translate_recursion(geom):
|
||||
if type(geom) == list:
|
||||
geoms = list()
|
||||
geoms = []
|
||||
for local_geom in geom:
|
||||
geoms.append(translate_recursion(local_geom))
|
||||
return geoms
|
||||
@@ -233,19 +253,18 @@ class TclCommandPanelize(TclCommand):
|
||||
|
||||
obj_fin.solid_geometry = []
|
||||
|
||||
if isinstance(obj, FlatCAMGeometry):
|
||||
if obj.kind == 'geometry':
|
||||
obj_fin.multigeo = obj.multigeo
|
||||
obj_fin.tools = deepcopy(obj.tools)
|
||||
if obj.multigeo is True:
|
||||
for tool in obj.tools:
|
||||
obj_fin.tools[tool]['solid_geometry'][:] = []
|
||||
|
||||
self.app.progress.emit(0)
|
||||
for row in range(rows):
|
||||
currentx = 0.0
|
||||
|
||||
for col in range(columns):
|
||||
if isinstance(obj, FlatCAMGeometry):
|
||||
if obj.kind == 'geometry':
|
||||
if obj.multigeo is True:
|
||||
for tool in obj.tools:
|
||||
obj_fin.tools[tool]['solid_geometry'].append(translate_recursion(
|
||||
@@ -263,28 +282,24 @@ class TclCommandPanelize(TclCommand):
|
||||
currentx += lenghtx
|
||||
currenty += lenghty
|
||||
|
||||
if isinstance(obj, FlatCAMExcellon):
|
||||
self.app.progress.emit(50)
|
||||
self.app.new_object("excellon", outname, job_init_excellon, plot=True, autoselected=True)
|
||||
if obj.kind == 'excellon':
|
||||
self.app.app_obj.new_object("excellon", outname, job_init_excellon, plot=False, autoselected=True)
|
||||
else:
|
||||
self.app.progress.emit(50)
|
||||
self.app.new_object("geometry", outname, job_init_geometry, plot=True, autoselected=True)
|
||||
self.app.app_obj.new_object("geometry", outname, job_init_geometry, plot=False, autoselected=True)
|
||||
|
||||
if threaded == 1:
|
||||
proc = self.app.proc_container.new("Generating panel ... Please wait.")
|
||||
if threaded is True:
|
||||
self.app.proc_container.new(_("Working ..."))
|
||||
|
||||
def job_thread(app_obj):
|
||||
try:
|
||||
panelize_2()
|
||||
self.app.inform.emit("[success] Panel created successfully.")
|
||||
except Exception as e:
|
||||
proc.done()
|
||||
log.debug(str(e))
|
||||
app_obj.inform.emit('[success]' % _("Done."))
|
||||
except Exception as ee:
|
||||
log.debug(str(ee))
|
||||
return
|
||||
proc.done()
|
||||
|
||||
self.app.collection.promise(outname)
|
||||
self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
|
||||
else:
|
||||
panelize_2()
|
||||
self.app.inform.emit("[success] Panel created successfully.")
|
||||
self.app.inform.emit('[success]' % _("Done."))
|
||||
|
||||
78
tclCommands/TclCommandPlotAll.py
Normal file
78
tclCommands/TclCommandPlotAll.py
Normal file
@@ -0,0 +1,78 @@
|
||||
from tclCommands.TclCommand import TclCommandSignaled
|
||||
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandPlotAll(TclCommandSignaled):
|
||||
"""
|
||||
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_all']
|
||||
|
||||
description = '%s %s' % ("--", "Plots all objects on appGUI.")
|
||||
|
||||
# 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([
|
||||
('plot_status', str),
|
||||
('use_thread', str)
|
||||
])
|
||||
|
||||
# array of mandatory options for current Tcl command: required = {'name','outname'}
|
||||
required = []
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': "Plots all objects on appGUI.",
|
||||
'args': collections.OrderedDict([
|
||||
('plot_status', 'If to display or not the objects: True (1) or False (0).'),
|
||||
('use_thread', 'If to use multithreading: True (1) or False (0).')
|
||||
]),
|
||||
'examples': ['plot_all', 'plot_all -plot_status False']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
"""
|
||||
|
||||
:param args:
|
||||
:param unnamed_args:
|
||||
:return:
|
||||
"""
|
||||
|
||||
if 'use_thread' in args:
|
||||
try:
|
||||
par = args['use_thread'].capitalize()
|
||||
except AttributeError:
|
||||
par = args['use_thread']
|
||||
threaded = bool(eval(par))
|
||||
else:
|
||||
threaded = False
|
||||
|
||||
plot_status = True
|
||||
if 'plot_status' in args:
|
||||
try:
|
||||
if args['plot_status'] is None:
|
||||
plot_status = True
|
||||
else:
|
||||
try:
|
||||
par = args['plot_status'].capitalize()
|
||||
except AttributeError:
|
||||
par = args['plot_status']
|
||||
plot_status = bool(eval(par))
|
||||
except KeyError:
|
||||
plot_status = True
|
||||
|
||||
for obj in self.app.collection.get_list():
|
||||
obj.options["plot"] = True if plot_status is True else False
|
||||
|
||||
if self.app.cmd_line_headless != 1:
|
||||
self.app.plot_all(use_thread=threaded)
|
||||
75
tclCommands/TclCommandPlotObjects.py
Normal file
75
tclCommands/TclCommandPlotObjects.py
Normal file
@@ -0,0 +1,75 @@
|
||||
# ##########################################################
|
||||
# FlatCAM: 2D Post-processing for Manufacturing #
|
||||
# File Author: Marius Adrian Stanciu (c) #
|
||||
# Date: 8/17/2019 #
|
||||
# MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
from tclCommands.TclCommand import TclCommand
|
||||
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandPlotObjects(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_objects']
|
||||
|
||||
description = '%s %s' % ("--", "Plot a specified list of objects in appGUI.")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict([
|
||||
('names', str)
|
||||
])
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
|
||||
option_types = collections.OrderedDict([
|
||||
('plot_status', str)
|
||||
])
|
||||
|
||||
# array of mandatory options for current Tcl command: required = {'name','outname'}
|
||||
required = ['names']
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': "Plot a specified list of objects in appGUI.",
|
||||
'args': collections.OrderedDict([
|
||||
('names', "A list of object names to be plotted separated by comma. Required.\n"
|
||||
"WARNING: no spaces are allowed. If unsure enclose the entire list with quotes."),
|
||||
('plot_status', 'If to display or not the objects: True (1) or False (0).')
|
||||
]),
|
||||
'examples': ["plot_objects gerber_obj.GRB,excellon_obj.DRL"]
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
"""
|
||||
|
||||
:param args:
|
||||
:param unnamed_args:
|
||||
:return:
|
||||
"""
|
||||
|
||||
if 'plot_status' in args:
|
||||
if args['plot_status'] is None:
|
||||
plot_status = True
|
||||
else:
|
||||
plot_status = bool(eval(args['plot_status']))
|
||||
else:
|
||||
plot_status = True
|
||||
|
||||
if self.app.cmd_line_headless != 1:
|
||||
names = [x.strip() for x in args['names'].split(",") if x != '']
|
||||
objs = []
|
||||
for name in names:
|
||||
obj = self.app.collection.get_by_name(name)
|
||||
obj.options["plot"] = True if plot_status is True else False
|
||||
objs.append(obj)
|
||||
|
||||
for obj in objs:
|
||||
obj.plot()
|
||||
@@ -1,17 +1,27 @@
|
||||
from ObjectCollection import *
|
||||
# ##########################################################
|
||||
# FlatCAM: 2D Post-processing for Manufacturing #
|
||||
# File Author: Marius Adrian Stanciu (c) #
|
||||
# Date: 8/17/2019 #
|
||||
# MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
from tclCommands.TclCommand import TclCommand
|
||||
|
||||
import collections
|
||||
|
||||
class TclCommandPlot(TclCommand):
|
||||
|
||||
class TclCommandQuit(TclCommand):
|
||||
"""
|
||||
Tcl shell command to update the plot on the user interface.
|
||||
Tcl shell command to quit FlatCAM from Tcl shell.
|
||||
|
||||
example:
|
||||
plot
|
||||
|
||||
"""
|
||||
|
||||
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['plot']
|
||||
aliases = ['quit_flatcam']
|
||||
|
||||
description = '%s %s' % ("--", "Tcl shell command to quit FlatCAM from Tcl shell.")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict([
|
||||
@@ -28,11 +38,11 @@ class TclCommandPlot(TclCommand):
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': "Updates the plot on the user interface.",
|
||||
'main': "Tcl shell command to quit FlatCAM from Tcl shell.",
|
||||
'args': collections.OrderedDict([
|
||||
|
||||
]),
|
||||
'examples': []
|
||||
'examples': ['quit_flatcam']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
@@ -43,4 +53,4 @@ class TclCommandPlot(TclCommand):
|
||||
:return:
|
||||
"""
|
||||
|
||||
self.app.plot_all()
|
||||
self.app.quit_application()
|
||||
@@ -1,6 +1,7 @@
|
||||
from ObjectCollection import *
|
||||
from tclCommands.TclCommand import TclCommandSignaled
|
||||
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandSaveProject(TclCommandSignaled):
|
||||
"""
|
||||
@@ -10,6 +11,8 @@ class TclCommandSaveProject(TclCommandSignaled):
|
||||
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['save_project']
|
||||
|
||||
description = '%s %s' % ("--", "Saves the FlatCAM project to file.")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered.
|
||||
# For positional arguments
|
||||
arg_names = collections.OrderedDict([
|
||||
@@ -29,9 +32,12 @@ class TclCommandSaveProject(TclCommandSignaled):
|
||||
help = {
|
||||
'main': "Saves the FlatCAM project to file.",
|
||||
'args': collections.OrderedDict([
|
||||
('filename', 'Path to file.'),
|
||||
('filename', 'Absolute path to file to save. Required.\n'
|
||||
'WARNING: no spaces are allowed. If unsure enclose the entire path with quotes.'),
|
||||
]),
|
||||
'examples': []
|
||||
'examples': ['save_project D:\\my_project_file.FlatPrj',
|
||||
'save_project "D:\\my_project_file with spaces in the name.FlatPrj"',
|
||||
'save_project path_to_where_the_file_is_stored']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
@@ -44,4 +50,4 @@ class TclCommandSaveProject(TclCommandSignaled):
|
||||
:return: None or exception
|
||||
"""
|
||||
|
||||
self.app.save_project(args['filename'])
|
||||
self.app.save_project(args['filename'], from_tcl=True)
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
# ##########################################################
|
||||
# FlatCAM: 2D Post-processing for Manufacturing #
|
||||
# File Author: Marius Adrian Stanciu (c) #
|
||||
# Date: 8/17/2019 #
|
||||
# MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
from tclCommands.TclCommand import *
|
||||
|
||||
|
||||
@@ -9,6 +16,8 @@ class TclCommandSaveSys(TclCommandSignaled):
|
||||
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['save_sys', 'save']
|
||||
|
||||
description = '%s %s' % ("--", "Saves the FlatCAM system parameters to defaults file.")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered.
|
||||
# For positional arguments
|
||||
arg_names = collections.OrderedDict([
|
||||
@@ -26,9 +35,9 @@ class TclCommandSaveSys(TclCommandSignaled):
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': "Saves the FlatCAM system paramaters to defaults file.",
|
||||
'main': "Saves the FlatCAM system parameters to defaults file.",
|
||||
'args': collections.OrderedDict([]),
|
||||
'examples': []
|
||||
'examples': ['save_sys']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
@@ -41,4 +50,4 @@ class TclCommandSaveSys(TclCommandSignaled):
|
||||
:return: None or exception
|
||||
"""
|
||||
|
||||
self.app.save_defaults(args)
|
||||
self.app.preferencesUiManager.save_defaults(args)
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
from ObjectCollection import *
|
||||
from tclCommands.TclCommand import TclCommand
|
||||
|
||||
import collections
|
||||
import logging
|
||||
|
||||
import gettext
|
||||
import appTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
log = logging.getLogger('base')
|
||||
|
||||
|
||||
class TclCommandScale(TclCommand):
|
||||
"""
|
||||
@@ -13,6 +25,8 @@ class TclCommandScale(TclCommand):
|
||||
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['scale']
|
||||
|
||||
description = '%s %s' % ("--", "Will scale the geometry of a named object. Does not create a new object.")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict([
|
||||
('name', str),
|
||||
@@ -21,20 +35,34 @@ class TclCommandScale(TclCommand):
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
|
||||
option_types = collections.OrderedDict([
|
||||
|
||||
('x', float),
|
||||
('y', float),
|
||||
('origin', str)
|
||||
])
|
||||
|
||||
# array of mandatory options for current Tcl command: required = {'name','outname'}
|
||||
required = ['name', 'factor']
|
||||
required = ['name']
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': "Resizes the object by a factor.",
|
||||
'main': "Resizes the object by a factor on X axis and a factor on Y axis, having as scale origin the point ",
|
||||
'args': collections.OrderedDict([
|
||||
('name', 'Name of the object to resize.'),
|
||||
('factor', 'Fraction by which to scale.')
|
||||
('name', 'Name of the object (Gerber, Geometry or Excellon) to be resized. Required.'),
|
||||
('factor', 'Fraction by which to scale on both axis.'),
|
||||
('x', 'Fraction by which to scale on X axis. If "factor" is used then this parameter is ignored'),
|
||||
('y', 'Fraction by which to scale on Y axis. If "factor" is used then this parameter is ignored'),
|
||||
('origin', 'Reference used for scale.\n'
|
||||
'The reference point can be:\n'
|
||||
'- "origin" which means point (0, 0)\n'
|
||||
'- "min_bounds" which means the lower left point of the bounding box\n'
|
||||
'- "center" which means the center point of the bounding box of the object.\n'
|
||||
'- a tuple in format (x,y) with the X and Y coordinates separated by a comma. NO SPACES ALLOWED')
|
||||
|
||||
]),
|
||||
'examples': ['scale my_geometry 4.2']
|
||||
'examples': ['scale my_geometry 4.2',
|
||||
'scale my_geo -x 3.1 -y 2.8',
|
||||
'scale my_geo 1.2 -origin min_bounds',
|
||||
'scale my_geometry -x 2 -origin 3.0,2.1']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
@@ -46,6 +74,57 @@ class TclCommandScale(TclCommand):
|
||||
"""
|
||||
|
||||
name = args['name']
|
||||
factor = args['factor']
|
||||
try:
|
||||
obj_to_scale = self.app.collection.get_by_name(name)
|
||||
except Exception as e:
|
||||
log.debug("TclCommandCopperClear.execute() --> %s" % str(e))
|
||||
self.raise_tcl_error("%s: %s" % (_("Could not retrieve object"), name))
|
||||
return "Could not retrieve object: %s" % name
|
||||
|
||||
self.app.collection.get_by_name(name).scale(factor)
|
||||
if 'origin' not in args:
|
||||
xmin, ymin, xmax, ymax = obj_to_scale.bounds()
|
||||
c_x = xmin + (xmax - xmin) / 2
|
||||
c_y = ymin + (ymax - ymin) / 2
|
||||
point = (c_x, c_y)
|
||||
else:
|
||||
if args['origin'] == 'origin':
|
||||
point = (0, 0)
|
||||
elif args['origin'] == 'min_bounds':
|
||||
xmin, ymin, xmax, ymax = obj_to_scale.bounds()
|
||||
point = (xmin, ymin)
|
||||
elif args['origin'] == 'center':
|
||||
xmin, ymin, xmax, ymax = obj_to_scale.bounds()
|
||||
c_x = xmin + (xmax - xmin) / 2
|
||||
c_y = ymin + (ymax - ymin) / 2
|
||||
point = (c_x, c_y)
|
||||
else:
|
||||
try:
|
||||
point = eval(args['origin'])
|
||||
if not isinstance(point, tuple):
|
||||
raise Exception
|
||||
except Exception as e:
|
||||
self.raise_tcl_error('%s\n%s' % (_("Expected -origin <origin> or "
|
||||
"-origin <min_bounds> or "
|
||||
"-origin <center> or "
|
||||
"- origin 3.0,4.2."), str(e)))
|
||||
return 'fail'
|
||||
|
||||
if 'factor' in args:
|
||||
factor = float(args['factor'])
|
||||
obj_to_scale.scale(factor, point=point)
|
||||
return
|
||||
|
||||
if 'x' not in args and 'y' not in args:
|
||||
self.raise_tcl_error('%s' % _("Expected -x <value> -y <value>."))
|
||||
return 'fail'
|
||||
|
||||
if 'x' in args and 'y' not in args:
|
||||
f_x = float(args['x'])
|
||||
obj_to_scale.scale(f_x, 0, point=point)
|
||||
elif 'x' not in args and 'y' in args:
|
||||
f_y = float(args['y'])
|
||||
obj_to_scale.scale(0, f_y, point=point)
|
||||
elif 'x' in args and 'y' in args:
|
||||
f_x = float(args['x'])
|
||||
f_y = float(args['y'])
|
||||
obj_to_scale.scale(f_x, f_y, point=point)
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
from ObjectCollection import *
|
||||
from tclCommands.TclCommand import TclCommand
|
||||
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandSetActive(TclCommand):
|
||||
"""
|
||||
Tcl shell command to set an object as active in the GUI.
|
||||
Tcl shell command to set an object as active in the appGUI.
|
||||
|
||||
example:
|
||||
|
||||
@@ -13,6 +14,8 @@ class TclCommandSetActive(TclCommand):
|
||||
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['set_active']
|
||||
|
||||
description = '%s %s' % ("--", "Sets a FlatCAM object as active (selected).")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict([
|
||||
('name', str),
|
||||
@@ -28,11 +31,11 @@ class TclCommandSetActive(TclCommand):
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': 'Sets an object as active.',
|
||||
'main': 'Sets a FlatCAM object as active (selected).',
|
||||
'args': collections.OrderedDict([
|
||||
('name', 'Name of the Object.'),
|
||||
('name', 'Name of the FlatCAM object to be set as active (selected). Required.'),
|
||||
]),
|
||||
'examples': []
|
||||
'examples': ['set_active object_name']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
|
||||
103
tclCommands/TclCommandSetOrigin.py
Normal file
103
tclCommands/TclCommandSetOrigin.py
Normal file
@@ -0,0 +1,103 @@
|
||||
# ##########################################################
|
||||
# FlatCAM: 2D Post-processing for Manufacturing #
|
||||
# File Author: Marius Adrian Stanciu (c) #
|
||||
# Date: 8/17/2019 #
|
||||
# MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
from tclCommands.TclCommand import TclCommand
|
||||
|
||||
import collections
|
||||
|
||||
from camlib import get_bounds
|
||||
|
||||
import logging
|
||||
import gettext
|
||||
import appTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
log = logging.getLogger('base')
|
||||
|
||||
|
||||
class TclCommandSetOrigin(TclCommand):
|
||||
"""
|
||||
Tcl shell command to set the origin to zero or to a specified location for all loaded objects in FlatCAM.
|
||||
|
||||
example:
|
||||
|
||||
"""
|
||||
|
||||
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['set_origin', 'origin']
|
||||
|
||||
description = '%s %s' % ("--", "Set the origin at the specified x,y location.")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict([
|
||||
('loc', str)
|
||||
])
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
|
||||
option_types = collections.OrderedDict([
|
||||
('auto', str)
|
||||
])
|
||||
|
||||
# array of mandatory options for current Tcl command: required = {'name','outname'}
|
||||
required = []
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': "Will set the origin at the specified x,y location.\n"
|
||||
"If it is called without arguments it will set origin at (0, 0)",
|
||||
'args': collections.OrderedDict([
|
||||
('loc', 'Location to offset all the selected objects. NO SPACES ALLOWED in X and Y pair.\n'
|
||||
'Use like this: 2,3'),
|
||||
('auto', 'If set to True it will set the origin to the minimum x, y of the object selection bounding box.'
|
||||
'-auto=True is not correct but -auto 1 or -auto True is correct. True (1) or False (0).')
|
||||
]),
|
||||
'examples': ['set_origin 3,2', 'set_origin -auto 1', 'origin']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
"""
|
||||
|
||||
:param args:
|
||||
:param unnamed_args:
|
||||
:return:
|
||||
"""
|
||||
|
||||
loc = []
|
||||
if 'auto' in args:
|
||||
if bool(args['auto']) is True:
|
||||
objs = self.app.collection.get_list()
|
||||
minx, miny, __, ___ = get_bounds(objs)
|
||||
|
||||
loc.append(0 - minx)
|
||||
loc.append(0 - miny)
|
||||
else:
|
||||
loc = [0, 0]
|
||||
elif 'loc' in args:
|
||||
try:
|
||||
location = [float(eval(coord)) for coord in str(args['loc']).split(",") if coord != '']
|
||||
except AttributeError as e:
|
||||
log.debug("TclCommandSetOrigin.execute --> %s" % str(e))
|
||||
location = (0, 0)
|
||||
|
||||
loc.append(location[0])
|
||||
loc.append(location[1])
|
||||
|
||||
if len(location) != 2:
|
||||
self.raise_tcl_error('%s: %s' % (
|
||||
_("Expected a pair of (x, y) coordinates. Got"), str(len(location))))
|
||||
return 'fail'
|
||||
else:
|
||||
loc = [0, 0]
|
||||
|
||||
self.app.on_set_zero_click(event=None, location=loc, noplot=True, use_thread=False)
|
||||
msg = '[success] Tcl %s: %s' % (_('Origin set by offsetting all loaded objects with '),
|
||||
'{0:.4f}, {0:.4f}'.format(loc[0], loc[1]))
|
||||
self.app.inform_shell.emit(msg)
|
||||
94
tclCommands/TclCommandSetPath.py
Normal file
94
tclCommands/TclCommandSetPath.py
Normal file
@@ -0,0 +1,94 @@
|
||||
# ##########################################################
|
||||
# FlatCAM: 2D Post-processing for Manufacturing #
|
||||
# File Author: Marius Adrian Stanciu (c) #
|
||||
# Date: 4/28/2020 #
|
||||
# MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
from tclCommands.TclCommand import TclCommand
|
||||
|
||||
import collections
|
||||
import os
|
||||
import logging
|
||||
import gettext
|
||||
import appTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
log = logging.getLogger('base')
|
||||
|
||||
|
||||
class TclCommandSetPath(TclCommand):
|
||||
"""
|
||||
Tcl shell command to set the default path for Tcl Shell for opening files.
|
||||
|
||||
example:
|
||||
|
||||
"""
|
||||
|
||||
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['set_path']
|
||||
|
||||
description = '%s %s' % ("--", "Set the folder path to the specified path.")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict([
|
||||
('path', 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 = ['path']
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': "Will set the folder path to the specified path.\n"
|
||||
"By using this command there is no need for usage of the absolute path to the files.",
|
||||
'args': collections.OrderedDict([
|
||||
('path', 'A folder path to where the user is supposed to have the file that he will work with.\n'
|
||||
'WARNING: No spaces allowed. Use quotes around the path if it contains spaces.'),
|
||||
]),
|
||||
'examples': ['set_path D:\\Project_storage_path']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
"""
|
||||
|
||||
:param args:
|
||||
:param unnamed_args:
|
||||
:return:
|
||||
"""
|
||||
|
||||
if 'path' not in args:
|
||||
return "Failed. The Tcl command set_path was used but no path argument was provided."
|
||||
else:
|
||||
path = str(args['path']).replace('\\', '/')
|
||||
|
||||
# check if path exists
|
||||
path_isdir = os.path.isdir(path)
|
||||
if path_isdir is False:
|
||||
path_isfile = os.path.isfile(path)
|
||||
if path_isfile:
|
||||
msg = '[ERROR] %s: %s, %s' % (
|
||||
"The provided path",
|
||||
str(path),
|
||||
"is a path to file and not a directory as expected.")
|
||||
self.app.inform_shell.emit(msg)
|
||||
return "Failed. The Tcl command set_path was used but it was not a directory."
|
||||
else:
|
||||
msg = '[ERROR] %s: %s, %s' % (
|
||||
"The provided path", str(path), "do not exist. Check for typos.")
|
||||
self.app.inform_shell.emit(msg)
|
||||
return "Failed. The Tcl command set_path was used but it does not exist."
|
||||
|
||||
cd_command = 'cd %s' % path
|
||||
self.app.shell.exec_command(cd_command, no_echo=False)
|
||||
self.app.defaults["global_tcl_path"] = str(path)
|
||||
msg = '[success] %s: %s' % ("Relative path set to", str(path))
|
||||
self.app.inform_shell.emit(msg)
|
||||
@@ -1,6 +1,7 @@
|
||||
from ObjectCollection import *
|
||||
from tclCommands.TclCommand import TclCommand
|
||||
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandSetSys(TclCommand):
|
||||
"""
|
||||
@@ -13,6 +14,8 @@ class TclCommandSetSys(TclCommand):
|
||||
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['set_sys', 'setsys']
|
||||
|
||||
description = '%s %s' % ("--", "Sets the value of the specified system variable.")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict([
|
||||
('name', str),
|
||||
@@ -29,12 +32,12 @@ class TclCommandSetSys(TclCommand):
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': "Sets the value of the system variable.",
|
||||
'main': "Sets the value of the specified system variable.",
|
||||
'args': collections.OrderedDict([
|
||||
('name', 'Name of the system variable.'),
|
||||
('name', 'Name of the system variable. Required.'),
|
||||
('value', 'Value to set.')
|
||||
]),
|
||||
'examples': []
|
||||
'examples': ['set_sys global_gridx 1.0']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
@@ -80,9 +83,7 @@ class TclCommandSetSys(TclCommand):
|
||||
pass
|
||||
|
||||
self.app.defaults[param] = value
|
||||
|
||||
self.app.propagate_defaults(silent=True)
|
||||
self.app.defaults.propagate_defaults()
|
||||
|
||||
else:
|
||||
self.raise_tcl_error("No such system parameter \"{}\".".format(param))
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from ObjectCollection import *
|
||||
from tclCommands.TclCommand import TclCommand
|
||||
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandSkew(TclCommand):
|
||||
"""
|
||||
@@ -13,30 +14,32 @@ class TclCommandSkew(TclCommand):
|
||||
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['skew']
|
||||
|
||||
description = '%s %s' % ("--", "Will deform (skew) the geometry of a named object. Does not create a new object.")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict([
|
||||
('name', str),
|
||||
('angle_x', float),
|
||||
('angle_y', float)
|
||||
])
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered , this is for options like -optionname value
|
||||
option_types = collections.OrderedDict([
|
||||
|
||||
('x', float),
|
||||
('y', float)
|
||||
])
|
||||
|
||||
# array of mandatory options for current Tcl command: required = {'name','outname'}
|
||||
required = ['name', 'angle_x', 'angle_y']
|
||||
required = ['name']
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': "Shear/Skew an object by angles along x and y dimensions.",
|
||||
'main': "Shear/Skew an object along x and y dimensions. The reference point is the left corner of "
|
||||
"the bounding box of the object.",
|
||||
'args': collections.OrderedDict([
|
||||
('name', 'Name of the object to skew.'),
|
||||
('angle_x', 'Angle in degrees by which to skew on the X axis.'),
|
||||
('angle_y', 'Angle in degrees by which to skew on the Y axis.')
|
||||
('name', 'Name of the object (Gerber, Geometry or Excellon) to be deformed (skewed). Required.'),
|
||||
('x', 'Angle in degrees by which to skew on the X axis. If it is not used it will be assumed to be 0.0'),
|
||||
('y', 'Angle in degrees by which to skew on the Y axis. If it is not used it will be assumed to be 0.0')
|
||||
]),
|
||||
'examples': ['skew my_geometry 10.2 3.5']
|
||||
'examples': ['skew my_geometry -x 10.2 -y 3.5', 'skew my_geo -x 3.0']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
@@ -48,7 +51,21 @@ class TclCommandSkew(TclCommand):
|
||||
"""
|
||||
|
||||
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)
|
||||
if 'x' in args:
|
||||
angle_x = float(args['x'])
|
||||
else:
|
||||
angle_x = 0.0
|
||||
|
||||
if 'y' in args:
|
||||
angle_y = float(args['y'])
|
||||
else:
|
||||
angle_y = 0.0
|
||||
|
||||
if angle_x == 0.0 and angle_y == 0.0:
|
||||
# nothing to be done
|
||||
return
|
||||
|
||||
obj_to_skew = self.app.collection.get_by_name(name)
|
||||
xmin, ymin, xmax, ymax = obj_to_skew.bounds()
|
||||
obj_to_skew.skew(angle_x, angle_y, point=(xmin, ymin))
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from ObjectCollection import *
|
||||
from tclCommands.TclCommand import TclCommandSignaled
|
||||
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandSubtractPoly(TclCommandSignaled):
|
||||
"""
|
||||
@@ -10,6 +11,9 @@ class TclCommandSubtractPoly(TclCommandSignaled):
|
||||
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['subtract_poly']
|
||||
|
||||
description = '%s %s' % ("--", "Subtract polygon from the given Geometry object. "
|
||||
"The coordinates are provided in X Y pairs.")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered.
|
||||
# For positional arguments
|
||||
arg_names = collections.OrderedDict([
|
||||
@@ -27,12 +31,14 @@ class TclCommandSubtractPoly(TclCommandSignaled):
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': "Subtract polygon from the given Geometry object.",
|
||||
'main': "Subtract polygon from the given Geometry object. The coordinates are provided in X Y pairs.\n"
|
||||
"If the number of coordinates is not even then the 'Incomplete coordinate' error is raised.\n"
|
||||
"If last coordinates are not the same as the first ones, the polygon will be completed automatically.",
|
||||
'args': collections.OrderedDict([
|
||||
('name', 'Name of the Geometry object from which to subtract.'),
|
||||
('name', 'Name of the Geometry object from which to subtract. Required.'),
|
||||
('x0 y0 x1 y1 x2 y2 ...', 'Points defining the polygon.')
|
||||
]),
|
||||
'examples': []
|
||||
'examples': ['subtract_poly my_geo 0 0 2 1 3 3 4 4 0 0']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
@@ -50,11 +56,13 @@ class TclCommandSubtractPoly(TclCommandSignaled):
|
||||
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)]
|
||||
points = [
|
||||
[float(unnamed_args[2 * i]), float(unnamed_args[2 * i + 1])] for i in range(int(len(unnamed_args) / 2))
|
||||
]
|
||||
|
||||
try:
|
||||
obj = self.app.collection.get_by_name(str(obj_name))
|
||||
except:
|
||||
except Exception:
|
||||
return "Could not retrieve object: %s" % obj_name
|
||||
if obj is None:
|
||||
return "Object not found: %s" % obj_name
|
||||
|
||||
@@ -1,23 +1,31 @@
|
||||
from ObjectCollection import *
|
||||
from tclCommands.TclCommand import TclCommandSignaled
|
||||
|
||||
import collections
|
||||
|
||||
import gettext
|
||||
import appTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
|
||||
class TclCommandSubtractRectangle(TclCommandSignaled):
|
||||
"""
|
||||
Tcl shell command to subtract a rectange from the given Geometry object.
|
||||
Tcl shell command to subtract a rectangle 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']
|
||||
|
||||
description = '%s %s' % ("--", "Subtract a rectangle from the given Geometry object. "
|
||||
"The coordinates are provided in X Y pairs.")
|
||||
|
||||
# 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)
|
||||
('name', str)
|
||||
])
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered.
|
||||
@@ -27,17 +35,18 @@ class TclCommandSubtractRectangle(TclCommandSignaled):
|
||||
])
|
||||
|
||||
# array of mandatory options for current Tcl command: required = {'name','outname'}
|
||||
required = ['name', 'x0', 'y0', 'x1', 'y1']
|
||||
required = ['name']
|
||||
|
||||
# structured help for current command, args needs to be ordered
|
||||
help = {
|
||||
'main': "Subtract rectange from the given Geometry object.",
|
||||
'main': "Subtract a rectangle from the given Geometry object. The coordinates are provided in X Y pairs.\n"
|
||||
"If the number of coordinates is not even then the 'Incomplete coordinates' error is raised.",
|
||||
'args': collections.OrderedDict([
|
||||
('name', 'Name of the Geometry object from which to subtract.'),
|
||||
('name', 'Name of the Geometry object from which to subtract. Required.'),
|
||||
('x0 y0', 'Bottom left corner coordinates.'),
|
||||
('x1 y1', 'Top right corner coordinates.')
|
||||
]),
|
||||
'examples': []
|
||||
'examples': ['subtract_rectangle geo_obj 8 8 15 15']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
@@ -49,17 +58,25 @@ class TclCommandSubtractRectangle(TclCommandSignaled):
|
||||
without -somename and we do not have them in known arg_names
|
||||
:return: None or exception
|
||||
"""
|
||||
|
||||
if 'name' not in args:
|
||||
self.raise_tcl_error("%s:" % _("No Geometry name in args. Provide a name and try again."))
|
||||
return 'fail'
|
||||
obj_name = args['name']
|
||||
x0 = args['x0']
|
||||
y0 = args['y0']
|
||||
x1 = args['x1']
|
||||
y1 = args['y1']
|
||||
|
||||
if len(unnamed_args) != 4:
|
||||
self.raise_tcl_error("Incomplete coordinates. There are 4 required: x0 y0 x1 y1.")
|
||||
return 'fail'
|
||||
|
||||
x0 = float(unnamed_args[0])
|
||||
y0 = float(unnamed_args[1])
|
||||
x1 = float(unnamed_args[2])
|
||||
y1 = float(unnamed_args[3])
|
||||
|
||||
try:
|
||||
obj = self.app.collection.get_by_name(str(obj_name))
|
||||
except:
|
||||
except Exception:
|
||||
return "Could not retrieve object: %s" % obj_name
|
||||
|
||||
if obj is None:
|
||||
return "Object not found: %s" % obj_name
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from ObjectCollection import *
|
||||
from tclCommands.TclCommand import TclCommand
|
||||
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandVersion(TclCommand):
|
||||
"""
|
||||
@@ -13,6 +14,8 @@ class TclCommandVersion(TclCommand):
|
||||
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['version']
|
||||
|
||||
description = '%s %s' % ("--", "Checks the program version.")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered
|
||||
arg_names = collections.OrderedDict([
|
||||
|
||||
@@ -32,7 +35,7 @@ class TclCommandVersion(TclCommand):
|
||||
'args': collections.OrderedDict([
|
||||
|
||||
]),
|
||||
'examples': []
|
||||
'examples': ['version']
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
@@ -44,4 +47,3 @@ class TclCommandVersion(TclCommand):
|
||||
"""
|
||||
|
||||
self.app.version_check()
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from ObjectCollection import *
|
||||
from tclCommands.TclCommand import TclCommandSignaled
|
||||
|
||||
import collections
|
||||
|
||||
|
||||
class TclCommandWriteGCode(TclCommandSignaled):
|
||||
"""
|
||||
@@ -11,6 +12,8 @@ class TclCommandWriteGCode(TclCommandSignaled):
|
||||
# old names for backward compatibility (add_poly, add_polygon)
|
||||
aliases = ['write_gcode']
|
||||
|
||||
description = '%s %s' % ("--", "Saves G-code of a CNC Job object to file.")
|
||||
|
||||
# Dictionary of types from Tcl command, needs to be ordered.
|
||||
# For positional arguments
|
||||
arg_names = collections.OrderedDict([
|
||||
@@ -22,7 +25,8 @@ class TclCommandWriteGCode(TclCommandSignaled):
|
||||
# For options like -optionname value
|
||||
option_types = collections.OrderedDict([
|
||||
('preamble', str),
|
||||
('postamble', str)
|
||||
('postamble', str),
|
||||
('muted', str)
|
||||
])
|
||||
|
||||
# array of mandatory options for current Tcl command: required = {'name','outname'}
|
||||
@@ -32,12 +36,14 @@ class TclCommandWriteGCode(TclCommandSignaled):
|
||||
help = {
|
||||
'main': "Saves G-code of a CNC Job object to file.",
|
||||
'args': collections.OrderedDict([
|
||||
('name', 'Source CNC Job object.'),
|
||||
('filename', 'Output filename.'),
|
||||
('name', 'Source CNC Job object. Required.'),
|
||||
('filename', 'Output filename. Required.'),
|
||||
('preamble', 'Text to append at the beginning.'),
|
||||
('postamble', 'Text to append at the end.')
|
||||
('postamble', 'Text to append at the end.'),
|
||||
('muted', 'It will not put errors in the Shell or status bar. True (1) or False (0)')
|
||||
|
||||
]),
|
||||
'examples': []
|
||||
'examples': ["write_gcode name c:\\\\gcode_repo"]
|
||||
}
|
||||
|
||||
def execute(self, args, unnamed_args):
|
||||
@@ -62,18 +68,27 @@ class TclCommandWriteGCode(TclCommandSignaled):
|
||||
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 'muted' in args:
|
||||
try:
|
||||
par = args['muted'].capitalize()
|
||||
except AttributeError:
|
||||
par = args['muted']
|
||||
muted = bool(eval(par))
|
||||
else:
|
||||
muted = False
|
||||
|
||||
# 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):
|
||||
# def write_gcode_on_object(app_obj.new_object):
|
||||
# self.log.debug("write_gcode_on_object(): Disconnecting %s" % write_gcode_on_object)
|
||||
# self.new_object_available.disconnect(write_gcode_on_object)
|
||||
# self.app_obj.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)
|
||||
# self.app_obj.new_object_available.connect(write_gcode_on_object)
|
||||
#
|
||||
# return
|
||||
|
||||
@@ -81,10 +96,16 @@ class TclCommandWriteGCode(TclCommandSignaled):
|
||||
|
||||
try:
|
||||
obj = self.app.collection.get_by_name(str(obj_name))
|
||||
except:
|
||||
return "Could not retrieve object: %s" % obj_name
|
||||
except Exception:
|
||||
if muted is False:
|
||||
return "Could not retrieve object: %s" % obj_name
|
||||
else:
|
||||
return "fail"
|
||||
|
||||
try:
|
||||
obj.export_gcode(str(filename), str(preamble), str(postamble))
|
||||
obj.export_gcode(str(filename), str(preamble), str(postamble), from_tcl=True)
|
||||
except Exception as e:
|
||||
return "Operation failed: %s" % str(e)
|
||||
if muted is False:
|
||||
return "Operation failed: %s" % str(e)
|
||||
else:
|
||||
return
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
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
|
||||
@@ -9,43 +8,60 @@ import tclCommands.TclCommandAddPolyline
|
||||
import tclCommands.TclCommandAddRectangle
|
||||
import tclCommands.TclCommandAlignDrill
|
||||
import tclCommands.TclCommandAlignDrillGrid
|
||||
import tclCommands.TclCommandBbox
|
||||
import tclCommands.TclCommandBounds
|
||||
import tclCommands.TclCommandClearShell
|
||||
import tclCommands.TclCommandCncjob
|
||||
import tclCommands.TclCommandCopperClear
|
||||
import tclCommands.TclCommandCutout
|
||||
import tclCommands.TclCommandDelete
|
||||
import tclCommands.TclCommandDrillcncjob
|
||||
import tclCommands.TclCommandExportDXF
|
||||
import tclCommands.TclCommandExportExcellon
|
||||
import tclCommands.TclCommandExportGerber
|
||||
import tclCommands.TclCommandExportGcode
|
||||
import tclCommands.TclCommandExportSVG
|
||||
import tclCommands.TclCommandExteriors
|
||||
import tclCommands.TclCommandGeoCutout
|
||||
import tclCommands.TclCommandGeoUnion
|
||||
import tclCommands.TclCommandGetNames
|
||||
import tclCommands.TclCommandGetPath
|
||||
import tclCommands.TclCommandGetSys
|
||||
import tclCommands.TclCommandImportSvg
|
||||
import tclCommands.TclCommandHelp
|
||||
import tclCommands.TclCommandInteriors
|
||||
import tclCommands.TclCommandIsolate
|
||||
import tclCommands.TclCommandFollow
|
||||
import tclCommands.TclCommandJoinExcellon
|
||||
import tclCommands.TclCommandJoinGeometry
|
||||
import tclCommands.TclCommandListSys
|
||||
import tclCommands.TclCommandMillHoles
|
||||
import tclCommands.TclCommandMillDrills
|
||||
import tclCommands.TclCommandMillSlots
|
||||
import tclCommands.TclCommandMirror
|
||||
import tclCommands.TclCommandNew
|
||||
import tclCommands.TclCommandNregions
|
||||
import tclCommands.TclCommandNewExcellon
|
||||
import tclCommands.TclCommandNewGeometry
|
||||
import tclCommands.TclCommandNewGerber
|
||||
import tclCommands.TclCommandOffset
|
||||
import tclCommands.TclCommandOpenDXF
|
||||
import tclCommands.TclCommandOpenExcellon
|
||||
import tclCommands.TclCommandOpenFolder
|
||||
import tclCommands.TclCommandOpenGCode
|
||||
import tclCommands.TclCommandOpenGerber
|
||||
import tclCommands.TclCommandOpenProject
|
||||
import tclCommands.TclCommandOpenFolder
|
||||
import tclCommands.TclCommandOpenSVG
|
||||
import tclCommands.TclCommandOptions
|
||||
import tclCommands.TclCommandPaint
|
||||
import tclCommands.TclCommandPanelize
|
||||
import tclCommands.TclCommandPlot
|
||||
import tclCommands.TclCommandPlotAll
|
||||
import tclCommands.TclCommandPlotObjects
|
||||
import tclCommands.TclCommandQuit
|
||||
import tclCommands.TclCommandSaveProject
|
||||
import tclCommands.TclCommandSaveSys
|
||||
import tclCommands.TclCommandScale
|
||||
import tclCommands.TclCommandSetActive
|
||||
import tclCommands.TclCommandSetOrigin
|
||||
import tclCommands.TclCommandSetPath
|
||||
import tclCommands.TclCommandSetSys
|
||||
import tclCommands.TclCommandSkew
|
||||
import tclCommands.TclCommandSubtractPoly
|
||||
@@ -78,7 +94,8 @@ def register_all_commands(app, commands):
|
||||
:return: None
|
||||
"""
|
||||
|
||||
tcl_modules = {k: v for k, v in list(sys.modules.items()) if k.startswith('tclCommands.TclCommand')}
|
||||
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':
|
||||
@@ -87,7 +104,12 @@ def register_all_commands(app, commands):
|
||||
command_instance = class_type(app)
|
||||
|
||||
for alias in command_instance.aliases:
|
||||
try:
|
||||
description = command_instance.description
|
||||
except AttributeError:
|
||||
description = ''
|
||||
commands[alias] = {
|
||||
'fcn': command_instance.execute_wrapper,
|
||||
'help': command_instance.get_decorated_help()
|
||||
'help': command_instance.get_decorated_help(),
|
||||
'description': description
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user