- added Repetier postprocessor file

- removed "added ability to regenerate objects (it's actually deletion followed by recreation)" because of the way Python pass parameters to functions by reference instead of copy
This commit is contained in:
Marius Stanciu 2019-02-22 16:54:58 +02:00 committed by Marius
parent 60b08dfec5
commit 7272b46dd9
7 changed files with 367 additions and 175 deletions

View File

@ -149,7 +149,7 @@ class App(QtCore.QObject):
# Emitted by new_object() and passes the new object as argument, plot flag.
# on_object_created() adds the object to the collection, plots on appropriate flag
# and emits new_object_available.
object_created = QtCore.pyqtSignal(object, bool, bool, bool)
object_created = QtCore.pyqtSignal(object, bool, bool)
# Emitted when a object has been changed (like scaled, mirrored)
object_changed = QtCore.pyqtSignal(object)
@ -2298,7 +2298,7 @@ class App(QtCore.QObject):
# Re-buid the recent items menu
self.setup_recent_items()
def new_object(self, kind, name, initialize, active=True, fit=True, plot=True, autoselected=True, overwrite=False):
def new_object(self, kind, name, initialize, active=True, fit=True, plot=True, autoselected=True):
"""
Creates a new specalized FlatCAMObj and attaches it to the application,
this is, updates the GUI accordingly, any other records and plots it.
@ -2325,7 +2325,6 @@ class App(QtCore.QObject):
App.log.debug("new_object()")
obj_plot = plot
obj_autoselected = autoselected
obj_overwrite = overwrite
t0 = time.time() # Debug
@ -2414,7 +2413,7 @@ class App(QtCore.QObject):
# Move the object to the main thread and let the app know that it is available.
obj.moveToThread(QtWidgets.QApplication.instance().thread())
self.object_created.emit(obj, obj_plot, obj_autoselected, obj_overwrite)
self.object_created.emit(obj, obj_plot, obj_autoselected)
return obj
@ -2431,7 +2430,7 @@ class App(QtCore.QObject):
self.new_object('geometry', 'new_g', initialize, plot=False)
def on_object_created(self, obj, plot, autoselect, overwrite):
def on_object_created(self, obj, plot, autoselect):
"""
Event callback for object creation.
@ -2442,7 +2441,7 @@ class App(QtCore.QObject):
self.log.debug("on_object_created()")
# The Collection might change the name if there is a collision
self.collection.append(obj, overwrite=overwrite)
self.collection.append(obj)
# after adding the object to the collection always update the list of objects that are in the collection
self.all_objects_list = self.collection.get_list()

View File

@ -5000,20 +5000,21 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
try:
for key in self.cnc_tools:
if self.cnc_tools[key]['data']['ppname_g'] == 'marlin':
ppg = self.cnc_tools[key]['data']['ppname_g']
if ppg == 'marlin' or ppg == 'Repetier':
marlin = True
break
if self.cnc_tools[key]['data']['ppname_g'] == 'hpgl':
if ppg == 'hpgl':
hpgl = True
break
if "toolchange_probe" in self.cnc_tools[key]['data']['ppname_g'].lower():
if "toolchange_probe" in ppg.lower():
probe_pp = True
break
except Exception as e:
log.debug("FlatCAMCNCJob.gcode_header() error: --> %s" % str(e))
try:
if self.options['ppname_e'] == 'marlin':
if self.options['ppname_e'] == 'marlin' or self.options['ppname_e'] == 'Repetier':
marlin = True
except Exception as e:
log.debug("FlatCAMCNCJob.gcode_header(): --> There is no such self.option: %s" % str(e))
@ -5025,7 +5026,7 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
log.debug("FlatCAMCNCJob.gcode_header(): --> There is no such self.option: %s" % str(e))
if marlin is True:
gcode = ';Marlin G-CODE GENERATED BY FLATCAM v%s - www.flatcam.org - Version Date: %s\n' % \
gcode = ';Marlin(Repetier) G-CODE GENERATED BY FLATCAM v%s - www.flatcam.org - Version Date: %s\n' % \
(str(self.app.version), str(self.app.version_date)) + '\n'
gcode += ';Name: ' + str(self.options['name']) + '\n'

View File

@ -642,7 +642,7 @@ class ObjectCollection(QtCore.QAbstractItemModel):
# return QtWidgets.QAbstractItemModel.flags(self, index)
def append(self, obj, active=False, overwrite=False):
def append(self, obj, active=False):
FlatCAMApp.App.log.debug(str(inspect.stack()[1][3]) + " --> OC.append()")
name = obj.options["name"]
@ -653,12 +653,6 @@ class ObjectCollection(QtCore.QAbstractItemModel):
# FlatCAMApp.App.log.debug("Promised object %s became available." % name)
# FlatCAMApp.App.log.debug("%d promised objects remaining." % len(self.promises))
# first delete the old object
if overwrite:
if name in self.get_names():
self.set_active(name)
self.delete_active(select_project=False)
# Prevent same name
while name in self.get_names():
## Create a new name

View File

@ -11,7 +11,9 @@ CAD program, and create G-Code for Isolation routing.
22.02.2019
-
- added Repetier postprocessor file
- removed "added ability to regenerate objects (it's actually deletion followed by recreation)" because of the way Python pass parameters to functions by reference instead of copy
-
21.02.2019

View File

@ -5723,8 +5723,8 @@ class CNCjob(Geometry):
command['Z'] = 1
else:
command['Z'] = 0
elif self.pp_solderpaste is not None:
if 'Paste' in self.pp_solderpaste:
elif self.pp_solderpaste_name is not None:
if 'Paste' in self.pp_solderpaste_name:
match_paste = re.search(r"X([\+-]?\d+.[\+-]?\d+)\s*Y([\+-]?\d+.[\+-]?\d+)", gline)
if match_paste:
command['X'] = float(match_paste.group(1).replace(" ", ""))

View File

@ -352,7 +352,7 @@ class SolderPaste(FlatCAMTool):
# self.gcode_frame.setDisabled(True)
# self.save_gcode_frame.setDisabled(True)
self.tools = {}
self.tooltable_tools = {}
self.tooluid = 0
self.options = LoudDict()
@ -363,8 +363,8 @@ class SolderPaste(FlatCAMTool):
## Signals
self.addtool_btn.clicked.connect(self.on_tool_add)
self.deltool_btn.clicked.connect(self.on_tool_delete)
self.soldergeo_btn.clicked.connect(self.on_create_geo)
self.solder_gcode_btn.clicked.connect(self.on_create_gcode)
self.soldergeo_btn.clicked.connect(self.on_create_geo_click)
self.solder_gcode_btn.clicked.connect(self.on_create_gcode_click)
self.solder_gcode_view_btn.clicked.connect(self.on_view_gcode)
self.solder_gcode_save_btn.clicked.connect(self.on_save_gcode)
@ -424,10 +424,10 @@ class SolderPaste(FlatCAMTool):
self.tooluid = 0
self.tools.clear()
self.tooltable_tools.clear()
for tool_dia in dias:
self.tooluid += 1
self.tools.update({
self.tooltable_tools.update({
int(self.tooluid): {
'tooldia': float('%.4f' % tool_dia),
'data': deepcopy(self.options),
@ -455,7 +455,7 @@ class SolderPaste(FlatCAMTool):
self.units = self.app.general_options_form.general_app_group.units_radio.get_value().upper()
sorted_tools = []
for k, v in self.tools.items():
for k, v in self.tooltable_tools.items():
sorted_tools.append(float('%.4f' % float(v['tooldia'])))
sorted_tools.sort(reverse=True)
@ -464,7 +464,7 @@ class SolderPaste(FlatCAMTool):
tool_id = 0
for tool_sorted in sorted_tools:
for tooluid_key, tooluid_value in self.tools.items():
for tooluid_key, tooluid_value in self.tooltable_tools.items():
if float('%.4f' % tooluid_value['tooldia']) == tool_sorted:
tool_id += 1
id = QtWidgets.QTableWidgetItem('%d' % int(tool_id))
@ -543,7 +543,7 @@ class SolderPaste(FlatCAMTool):
# update the form
try:
# set the form with data from the newly selected tool
for tooluid_key, tooluid_value in self.tools.items():
for tooluid_key, tooluid_value in self.tooltable_tools.items():
if int(tooluid_key) == tooluid:
self.set_form(deepcopy(tooluid_value['data']))
except Exception as e:
@ -601,7 +601,7 @@ class SolderPaste(FlatCAMTool):
current_row = self.tools_table.currentRow()
uid = tooluid if tooluid else int(self.tools_table.item(current_row, 2).text())
for key in self.form_fields:
self.tools[uid]['data'].update({
self.tooltable_tools[uid]['data'].update({
key: self.form_fields[key].get_value()
})
@ -618,7 +618,7 @@ class SolderPaste(FlatCAMTool):
"""
Will read all the parameters of Solder Paste Tool from the provided val parameter and update the UI
:param val: dictionary with values to store in the form
:param_type: dictionary
param_type: dictionary
:return:
"""
@ -656,9 +656,9 @@ class SolderPaste(FlatCAMTool):
self.app.inform.emit("[WARNING_NOTCL] Please enter a tool diameter with non-zero value, in Float format.")
return
# construct a list of all 'tooluid' in the self.tools
# construct a list of all 'tooluid' in the self.tooltable_tools
tool_uid_list = []
for tooluid_key in self.tools:
for tooluid_key in self.tooltable_tools:
tool_uid_item = int(tooluid_key)
tool_uid_list.append(tool_uid_item)
@ -670,7 +670,7 @@ class SolderPaste(FlatCAMTool):
self.tooluid = int(max_uid + 1)
tool_dias = []
for k, v in self.tools.items():
for k, v in self.tooltable_tools.items():
for tool_v in v.keys():
if tool_v == 'tooldia':
tool_dias.append(float('%.4f' % v[tool_v]))
@ -683,7 +683,7 @@ class SolderPaste(FlatCAMTool):
else:
if muted is None:
self.app.inform.emit("[success] New Nozzle tool added to Tool Table.")
self.tools.update({
self.tooltable_tools.update({
int(self.tooluid): {
'tooldia': float('%.4f' % tool_dia),
'data': deepcopy(self.options),
@ -697,7 +697,7 @@ class SolderPaste(FlatCAMTool):
self.ui_disconnect()
tool_dias = []
for k, v in self.tools.items():
for k, v in self.tooltable_tools.items():
for tool_v in v.keys():
if tool_v == 'tooldia':
tool_dias.append(float('%.4f' % v[tool_v]))
@ -719,13 +719,13 @@ class SolderPaste(FlatCAMTool):
# identify the tool that was edited and get it's tooluid
if new_tool_dia not in tool_dias:
self.tools[tooluid]['tooldia'] = new_tool_dia
self.tooltable_tools[tooluid]['tooldia'] = new_tool_dia
self.app.inform.emit("[success] Nozzle tool from Tool Table was edited.")
self.build_ui()
return
else:
# identify the old tool_dia and restore the text in tool table
for k, v in self.tools.items():
for k, v in self.tooltable_tools.items():
if k == tooluid:
old_tool_dia = v['tooldia']
break
@ -739,7 +739,7 @@ class SolderPaste(FlatCAMTool):
deleted_tools_list = []
if all:
self.tools.clear()
self.tooltable_tools.clear()
self.build_ui()
return
@ -752,7 +752,7 @@ class SolderPaste(FlatCAMTool):
deleted_tools_list.append(rows_to_delete)
for t in deleted_tools_list:
self.tools.pop(t, None)
self.tooltable_tools.pop(t, None)
self.build_ui()
return
@ -766,7 +766,7 @@ class SolderPaste(FlatCAMTool):
deleted_tools_list.append(tooluid_del)
for t in deleted_tools_list:
self.tools.pop(t, None)
self.tooltable_tools.pop(t, None)
except AttributeError:
self.app.inform.emit("[WARNING_NOTCL] Delete failed. Select a Nozzle tool to delete.")
@ -795,31 +795,34 @@ class SolderPaste(FlatCAMTool):
def distance(pt1, pt2):
return sqrt((pt1[0] - pt2[0]) ** 2 + (pt1[1] - pt2[1]) ** 2)
def on_create_geo(self):
proc = self.app.proc_container.new("Creating Solder Paste dispensing geometry.")
def on_create_geo_click(self, signal):
name = self.obj_combo.currentText()
if name == '':
self.app.inform.emit("[WARNING_NOTCL] No SolderPaste mask Gerber object loaded.")
return
obj = self.app.collection.get_by_name(name)
# update the self.options
self.read_form_to_options()
obj = self.app.collection.get_by_name(name)
self.on_create_geo(name=name, work_object=obj)
if type(obj.solid_geometry) is not list and type(obj.solid_geometry) is not MultiPolygon:
obj.solid_geometry = [obj.solid_geometry]
def on_create_geo(self, name, work_object):
proc = self.app.proc_container.new("Creating Solder Paste dispensing geometry.")
obj = work_object
# Sort tools in descending order
sorted_tools = []
for k, v in self.tools.items():
for k, v in self.tooltable_tools.items():
# make sure that the tools diameter is more than zero and not zero
if float(v['tooldia']) > 0:
sorted_tools.append(float('%.4f' % float(v['tooldia'])))
sorted_tools.sort(reverse=True)
if not sorted_tools:
self.app.inform.emit("[WARNING_NOTCL] No Nozzle tools in the tool table.")
return 'fail'
def geo_init(geo_obj, app_obj):
geo_obj.options.update(self.options)
geo_obj.solid_geometry = []
@ -830,7 +833,6 @@ class SolderPaste(FlatCAMTool):
geo_obj.special_group = 'solder_paste_tool'
def solder_line(p, offset):
xmin, ymin, xmax, ymax = p.bounds
min = [xmin, ymin]
@ -875,21 +877,16 @@ class SolderPaste(FlatCAMTool):
rest_geo = []
tooluid = 1
if not sorted_tools:
self.app.inform.emit("[WARNING_NOTCL] No Nozzle tools in the tool table.")
return 'fail'
for tool in sorted_tools:
offset = tool / 2
for uid, v in self.tools.items():
for uid, v in self.tooltable_tools.items():
if float('%.4f' % float(v['tooldia'])) == tool:
tooluid = int(uid)
break
geo_obj.tools[tooluid] = {}
geo_obj.tools[tooluid]['tooldia'] = tool
geo_obj.tools[tooluid]['data'] = self.tools[tooluid]['data']
geo_obj.tools[tooluid]['data'] = deepcopy(self.tooltable_tools[tooluid]['data'])
geo_obj.tools[tooluid]['solid_geometry'] = []
geo_obj.tools[tooluid]['offset'] = 'Path'
geo_obj.tools[tooluid]['offset_value'] = 0.0
@ -933,7 +930,7 @@ class SolderPaste(FlatCAMTool):
def job_thread(app_obj):
try:
app_obj.new_object("geometry", name + "_solderpaste", geo_init, overwrite=True)
app_obj.new_object("geometry", name + "_solderpaste", geo_init)
except Exception as e:
proc.done()
traceback.print_stack()
@ -945,9 +942,126 @@ class SolderPaste(FlatCAMTool):
self.app.collection.promise(name)
# Background
self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app.paste_tool]})
# self.app.ui.notebook.setCurrentWidget(self.app.ui.project_tab)
def on_create_gcode_click(self, signal):
name = self.geo_obj_combo.currentText()
obj = self.app.collection.get_by_name(name)
if obj.special_group != 'solder_paste_tool':
self.app.inform.emit("[WARNING_NOTCL]This Geometry can't be processed. NOT a solder_paste_tool geometry.")
return 'fail'
a = 0
for tooluid_key in obj.tools:
if obj.tools[tooluid_key]['solid_geometry'] is None:
a += 1
if a == len(obj.tools):
self.app.inform.emit('[ERROR_NOTCL]Cancelled. Empty file, it has no geometry...')
return 'fail'
# use the name of the first tool selected in self.geo_tools_table which has the diameter passed as tool_dia
originar_name = obj.options['name'].rpartition('_')[0]
outname = "%s_%s" % (originar_name, 'cnc_solderpaste')
self.on_create_gcode(name=outname, workobject=obj)
def on_create_gcode(self, name, workobject, use_thread=True):
"""
Creates a multi-tool CNCJob out of this Geometry object.
:return: None
"""
obj = workobject
try:
xmin = obj.options['xmin']
ymin = obj.options['ymin']
xmax = obj.options['xmax']
ymax = obj.options['ymax']
except Exception as e:
log.debug("FlatCAMObj.FlatCAMGeometry.mtool_gen_cncjob() --> %s\n" % str(e))
msg = "[ERROR] An internal error has ocurred. See shell.\n"
msg += 'FlatCAMObj.FlatCAMGeometry.mtool_gen_cncjob() --> %s' % str(e)
msg += traceback.format_exc()
self.app.inform.emit(msg)
return
# Object initialization function for app.new_object()
# RUNNING ON SEPARATE THREAD!
def job_init(job_obj, app_obj):
assert isinstance(job_obj, FlatCAMCNCjob), \
"Initializer expected a FlatCAMCNCjob, got %s" % type(job_obj)
tool_cnc_dict = {}
# this turn on the FlatCAMCNCJob plot for multiple tools
job_obj.multitool = True
job_obj.multigeo = True
job_obj.cnc_tools.clear()
job_obj.special_group = 'solder_paste_tool'
job_obj.options['xmin'] = xmin
job_obj.options['ymin'] = ymin
job_obj.options['xmax'] = xmax
job_obj.options['ymax'] = ymax
for tooluid_key, tooluid_value in obj.tools.items():
app_obj.progress.emit(20)
# find the tool_dia associated with the tooluid_key
tool_dia = tooluid_value['tooldia']
tool_cnc_dict = deepcopy(tooluid_value)
job_obj.coords_decimals = self.app.defaults["cncjob_coords_decimals"]
job_obj.fr_decimals = self.app.defaults["cncjob_fr_decimals"]
job_obj.tool = int(tooluid_key)
# Propagate options
job_obj.options["tooldia"] = tool_dia
job_obj.options['tool_dia'] = tool_dia
### CREATE GCODE ###
res = job_obj.generate_gcode_from_solderpaste_geo(**tooluid_value)
if res == 'fail':
log.debug("FlatCAMGeometry.mtool_gen_cncjob() --> generate_from_geometry2() failed")
return 'fail'
else:
tool_cnc_dict['gcode'] = res
### PARSE GCODE ###
tool_cnc_dict['gcode_parsed'] = job_obj.gcode_parse()
# TODO this serve for bounding box creation only; should be optimized
tool_cnc_dict['solid_geometry'] = cascaded_union([geo['geom'] for geo in tool_cnc_dict['gcode_parsed']])
# tell gcode_parse from which point to start drawing the lines depending on what kind of
# object is the source of gcode
job_obj.toolchange_xy_type = "geometry"
app_obj.progress.emit(80)
job_obj.cnc_tools.update({
tooluid_key: deepcopy(tool_cnc_dict)
})
tool_cnc_dict.clear()
if use_thread:
# To be run in separate thread
def job_thread(app_obj):
with self.app.proc_container.new("Generating CNC Code"):
if app_obj.new_object("cncjob", name, job_init) != 'fail':
app_obj.inform.emit("[success]ToolSolderPaste CNCjob created: %s" % name)
app_obj.progress.emit(100)
# Create a promise with the name
self.app.collection.promise(name)
# Send to worker
self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
else:
self.app.new_object("cncjob", name, job_init)
def on_view_gcode(self):
time_str = "{:%A, %d %B %Y at %H:%M}".format(datetime.now())
@ -1065,122 +1179,6 @@ class SolderPaste(FlatCAMTool):
self.app.file_saved.emit("gcode", filename)
self.app.inform.emit("[success] Solder paste dispenser GCode file saved to: %s" % filename)
def on_create_gcode(self, signal, use_thread=True):
"""
Creates a multi-tool CNCJob out of this Geometry object.
:return: None
"""
name = self.geo_obj_combo.currentText()
obj = self.app.collection.get_by_name(name)
if obj.special_group != 'solder_paste_tool':
self.app.inform.emit("[WARNING_NOTCL]This Geometry can't be processed. NOT a solder_paste_tool geometry.")
return
offset_str = ''
multitool_gcode = ''
# use the name of the first tool selected in self.geo_tools_table which has the diameter passed as tool_dia
originar_name = obj.options['name'].rpartition('_')[0]
outname = "%s_%s" % (originar_name, '_cnc_solderpaste')
try:
xmin = obj.options['xmin']
ymin = obj.options['ymin']
xmax = obj.options['xmax']
ymax = obj.options['ymax']
except Exception as e:
log.debug("FlatCAMObj.FlatCAMGeometry.mtool_gen_cncjob() --> %s\n" % str(e))
msg = "[ERROR] An internal error has ocurred. See shell.\n"
msg += 'FlatCAMObj.FlatCAMGeometry.mtool_gen_cncjob() --> %s' % str(e)
msg += traceback.format_exc()
self.app.inform.emit(msg)
return
# Object initialization function for app.new_object()
# RUNNING ON SEPARATE THREAD!
def job_init(job_obj, app_obj):
assert isinstance(job_obj, FlatCAMCNCjob), \
"Initializer expected a FlatCAMCNCjob, got %s" % type(job_obj)
tool_cnc_dict = {}
# this turn on the FlatCAMCNCJob plot for multiple tools
job_obj.multitool = True
job_obj.multigeo = True
job_obj.cnc_tools.clear()
job_obj.special_group = 'solder_paste_tool'
job_obj.options['xmin'] = xmin
job_obj.options['ymin'] = ymin
job_obj.options['xmax'] = xmax
job_obj.options['ymax'] = ymax
a = 0
for tooluid_key in obj.tools:
if obj.tools[tooluid_key]['solid_geometry'] is None:
a += 1
if a == len(obj.tools):
self.app.inform.emit('[ERROR_NOTCL]Cancelled. Empty file, it has no geometry...')
return 'fail'
for tooluid_key, tooluid_value in obj.tools.items():
app_obj.progress.emit(20)
# find the tool_dia associated with the tooluid_key
tool_dia = tooluid_value['tooldia']
tool_cnc_dict = deepcopy(tooluid_value)
job_obj.coords_decimals = self.app.defaults["cncjob_coords_decimals"]
job_obj.fr_decimals = self.app.defaults["cncjob_fr_decimals"]
job_obj.tool = int(tooluid_key)
# Propagate options
job_obj.options["tooldia"] = tool_dia
job_obj.options['tool_dia'] = tool_dia
### CREATE GCODE ###
res = job_obj.generate_gcode_from_solderpaste_geo(**tooluid_value)
if res == 'fail':
log.debug("FlatCAMGeometry.mtool_gen_cncjob() --> generate_from_geometry2() failed")
return 'fail'
else:
tool_cnc_dict['gcode'] = res
### PARSE GCODE ###
tool_cnc_dict['gcode_parsed'] = job_obj.gcode_parse()
# TODO this serve for bounding box creation only; should be optimized
tool_cnc_dict['solid_geometry'] = cascaded_union([geo['geom'] for geo in tool_cnc_dict['gcode_parsed']])
# tell gcode_parse from which point to start drawing the lines depending on what kind of
# object is the source of gcode
job_obj.toolchange_xy_type = "geometry"
app_obj.progress.emit(80)
job_obj.cnc_tools.update({
tooluid_key: deepcopy(tool_cnc_dict)
})
tool_cnc_dict.clear()
if use_thread:
# To be run in separate thread
def job_thread(app_obj):
with self.app.proc_container.new("Generating CNC Code"):
if app_obj.new_object("cncjob", outname, job_init, overwrite=True) != 'fail':
app_obj.inform.emit("[success]ToolSolderPaste CNCjob created: %s" % outname)
app_obj.progress.emit(100)
# Create a promise with the name
self.app.collection.promise(outname)
# Send to worker
self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
else:
self.app.new_object("cncjob", outname, job_init, overwrite=True)
def reset_fields(self):
self.obj_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
self.geo_obj_combo.setRootModelIndex(self.app.collection.index(2, 0, QtCore.QModelIndex()))

198
postprocessors/Repetier.py Normal file
View File

@ -0,0 +1,198 @@
from FlatCAMPostProc import *
class Repetier(FlatCAMPostProc):
coordinate_format = "%.*f"
feedrate_format = '%.*f'
feedrate_rapid_format = feedrate_format
def start_code(self, p):
units = ' ' + str(p['units']).lower()
coords_xy = p['toolchange_xy']
gcode = ''
xmin = '%.*f' % (p.coords_decimals, p['options']['xmin'])
xmax = '%.*f' % (p.coords_decimals, p['options']['xmax'])
ymin = '%.*f' % (p.coords_decimals, p['options']['ymin'])
ymax = '%.*f' % (p.coords_decimals, p['options']['ymax'])
if str(p['options']['type']) == 'Geometry':
gcode += ';TOOL DIAMETER: ' + str(p['options']['tool_dia']) + units + '\n' + '\n'
gcode += ';Feedrate: ' + str(p['feedrate']) + units + '/min' + '\n'
if str(p['options']['type']) == 'Geometry':
gcode += ';Feedrate_Z: ' + str(p['feedrate_z']) + units + '/min' + '\n'
gcode += ';Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + '\n' + '\n'
gcode += ';Z_Cut: ' + str(p['z_cut']) + units + '\n'
if str(p['options']['type']) == 'Geometry':
if p['multidepth'] is True:
gcode += ';DepthPerCut: ' + str(p['depthpercut']) + units + ' <=>' + \
str(math.ceil(abs(p['z_cut']) / p['depthpercut'])) + ' passes' + '\n'
gcode += ';Z_Move: ' + str(p['z_move']) + units + '\n'
gcode += ';Z Toolchange: ' + str(p['toolchangez']) + units + '\n'
if coords_xy is not None:
gcode += ';X,Y Toolchange: ' + "%.4f, %.4f" % (coords_xy[0], coords_xy[1]) + units + '\n'
else:
gcode += ';X,Y Toolchange: ' + "None" + units + '\n'
gcode += ';Z Start: ' + str(p['startz']) + units + '\n'
gcode += ';Z End: ' + str(p['endz']) + units + '\n'
gcode += ';Steps per circle: ' + str(p['steps_per_circle']) + '\n'
if str(p['options']['type']) == 'Excellon' or str(p['options']['type']) == 'Excellon Geometry':
gcode += ';Postprocessor Excellon: ' + str(p['pp_excellon_name']) + '\n'
else:
gcode += ';Postprocessor Geometry: ' + str(p['pp_geometry_name']) + '\n' + '\n'
gcode += ';X range: ' + '{: >9s}'.format(xmin) + ' ... ' + '{: >9s}'.format(xmax) + ' ' + units + '\n'
gcode += ';Y range: ' + '{: >9s}'.format(ymin) + ' ... ' + '{: >9s}'.format(ymax) + ' ' + units + '\n\n'
gcode += ';Spindle Speed: ' + str(p['spindlespeed']) + ' RPM' + '\n' + '\n'
gcode += ('G20' if p.units.upper() == 'IN' else 'G21') + "\n"
gcode += 'G90\n'
return gcode
def startz_code(self, p):
if p.startz is not None:
return 'G0 Z' + self.coordinate_format % (p.coords_decimals, p.startz)
else:
return ''
def lift_code(self, p):
return 'G0 Z' + self.coordinate_format%(p.coords_decimals, p.z_move) + " " + self.feedrate_rapid_code(p)
def down_code(self, p):
return 'G1 Z' + self.coordinate_format%(p.coords_decimals, p.z_cut) + " " + self.end_feedrate_code(p)
def toolchange_code(self, p):
toolchangez = p.toolchangez
toolchangexy = p.toolchange_xy
f_plunge = p.f_plunge
gcode = ''
if toolchangexy is not None:
toolchangex = toolchangexy[0]
toolchangey = toolchangexy[1]
no_drills = 1
if int(p.tool) == 1 and p.startz is not None:
toolchangez = p.startz
if p.units.upper() == 'MM':
toolC_formatted = format(p.toolC, '.2f')
else:
toolC_formatted = format(p.toolC, '.4f')
if str(p['options']['type']) == 'Excellon':
for i in p['options']['Tools_in_use']:
if i[0] == p.tool:
no_drills = i[2]
if toolchangexy is not None:
gcode = """
G0 Z{toolchangez}
G0 X{toolchangex} Y{toolchangey}
M84
@pause Change to Tool Dia = {toolC}, Total drills for tool T{tool} = {t_drills}
""".format(toolchangex=self.coordinate_format % (p.coords_decimals, toolchangex),
toolchangey=self.coordinate_format % (p.coords_decimals, toolchangey),
toolchangez=self.coordinate_format % (p.coords_decimals, toolchangez),
tool=int(p.tool),
t_drills=no_drills,
toolC=toolC_formatted)
else:
gcode = """
G0 Z{toolchangez}
M84
@pause Change to Tool Dia = {toolC}, Total drills for tool T{tool} = {t_drills}
""".format(toolchangez=self.coordinate_format % (p.coords_decimals, toolchangez),
tool=int(p.tool),
t_drills=no_drills,
toolC=toolC_formatted)
if f_plunge is True:
gcode += '\nG0 Z%.*f' % (p.coords_decimals, p.z_move)
return gcode
else:
if toolchangexy is not None:
gcode = """
G0 Z{toolchangez}
G0 X{toolchangex} Y{toolchangey}
M84
@pause Change to tool T{tool} with Tool Dia = {toolC}
""".format(toolchangex=self.coordinate_format % (p.coords_decimals, toolchangex),
toolchangey=self.coordinate_format % (p.coords_decimals, toolchangey),
toolchangez=self.coordinate_format % (p.coords_decimals, toolchangez),
tool=int(p.tool),
toolC=toolC_formatted)
else:
gcode = """
G0 Z{toolchangez}
M84
@pause Change to tool T{tool} with Tool Dia = {toolC}
""".format(toolchangez=self.coordinate_format%(p.coords_decimals, toolchangez),
tool=int(p.tool),
toolC=toolC_formatted)
if f_plunge is True:
gcode += '\nG0 Z%.*f' % (p.coords_decimals, p.z_move)
return gcode
def up_to_zero_code(self, p):
return 'G1 Z0' + " " + self.feedrate_code(p)
def position_code(self, p):
return ('X' + self.coordinate_format + ' Y' + self.coordinate_format) % \
(p.coords_decimals, p.x, p.coords_decimals, p.y)
def rapid_code(self, p):
return ('G0 ' + self.position_code(p)).format(**p) + " " + self.feedrate_rapid_code(p)
def linear_code(self, p):
return ('G1 ' + self.position_code(p)).format(**p) + " " + self.end_feedrate_code(p)
def end_code(self, p):
coords_xy = p['toolchange_xy']
gcode = ('G0 Z' + self.feedrate_format %(p.fr_decimals, p.endz) + " " + self.feedrate_rapid_code(p) + "\n")
if coords_xy is not None:
gcode += 'G0 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + " " + self.feedrate_rapid_code(p) + "\n"
return gcode
def feedrate_code(self, p):
return 'G1 F' + str(self.feedrate_format %(p.fr_decimals, p.feedrate))
def end_feedrate_code(self, p):
return 'F' + self.feedrate_format %(p.fr_decimals, p.feedrate)
def feedrate_z_code(self, p):
return 'G1 F' + str(self.feedrate_format %(p.fr_decimals, p.feedrate_z))
def feedrate_rapid_code(self, p):
return 'F' + self.feedrate_rapid_format % (p.fr_decimals, p.feedrate_rapid)
def spindle_code(self,p):
if p.spindlespeed:
return 'M106 S%d' % p.spindlespeed
else:
return 'M106'
def dwell_code(self, p):
if p.dwelltime:
return 'G4 P' + str(p.dwelltime)
def spindle_stop_code(self,p):
return 'M107'