Merge remote-tracking branch 'remotes/jpcgt/flatcam/Beta' into Beta

This commit is contained in:
camellan 2019-12-17 19:23:56 +04:00
commit 762e460614
42 changed files with 9383 additions and 8692 deletions

View File

@ -140,8 +140,8 @@ class App(QtCore.QObject):
# ##########################################################################
# ################## Version and VERSION DATE ##############################
# ##########################################################################
version = 8.99
version_date = "2019/12/15"
version = 8.991
version_date = "2019/12/30"
beta = True
engine = '3D'
@ -237,6 +237,9 @@ class App(QtCore.QObject):
# should be disconnected after use so it can be reused
replot_signal = pyqtSignal(list)
# signal emitted when jumping
jump_signal = pyqtSignal(tuple)
def __init__(self, user_defaults=True):
"""
Starts the application.
@ -3810,7 +3813,7 @@ class App(QtCore.QObject):
if 'version' not in defaults or defaults['version'] != self.defaults['version']:
for k, v in defaults.items():
if k in self.defaults:
if k in self.defaults and k != 'version':
self.defaults[k] = v
# delete old factory defaults
@ -7355,10 +7358,6 @@ class App(QtCore.QObject):
"""
self.report_usage("on_jump_to()")
# if self.is_legacy is True:
# self.inform.emit(_("Not available with the current Graphic Engine Legacy(2D)."))
# return
if not custom_location:
dia_box_location = None
@ -7372,17 +7371,29 @@ class App(QtCore.QObject):
else:
dia_box_location = None
dia_box = Dialog_box(title=_("Jump to ..."),
label=_("Enter the coordinates in format X,Y:"),
icon=QtGui.QIcon(self.resource_location + '/jump_to16.png'),
initial_text=dia_box_location)
# dia_box = Dialog_box(title=_("Jump to ..."),
# label=_("Enter the coordinates in format X,Y:"),
# icon=QtGui.QIcon(self.resource_location + '/jump_to16.png'),
# initial_text=dia_box_location)
dia_box = DialogBoxRadio(title=_("Jump to ..."),
label=_("Enter the coordinates in format X,Y:"),
icon=QtGui.QIcon(self.resource_location + '/jump_to16.png'),
initial_text=dia_box_location)
if dia_box.ok is True:
try:
location = eval(dia_box.location)
if not isinstance(location, tuple):
self.inform.emit(_("Wrong coordinates. Enter coordinates in format: X,Y"))
return
if dia_box.reference == 'rel':
rel_x = self.mouse[0] + location[0]
rel_y = self.mouse[1] + location[1]
location = (rel_x, rel_y)
except Exception:
return
else:
@ -7390,6 +7401,8 @@ class App(QtCore.QObject):
else:
location = custom_location
self.jump_signal.emit(location)
units = self.defaults['units'].upper()
if fit_center:
@ -9962,11 +9975,11 @@ class App(QtCore.QObject):
flt = "All Files (*.*)"
if obj.kind == 'gerber':
flt = "Gerber Files (*.GBR);;All Files (*.*)"
flt = "Gerber Files (*.GBR);;PDF Files (*.PDF);;All Files (*.*)"
elif obj.kind == 'excellon':
flt = "Excellon Files (*.DRL);;All Files (*.*)"
flt = "Excellon Files (*.DRL);;PDF Files (*.PDF);;All Files (*.*)"
elif obj.kind == 'cncjob':
"GCode Files (*.NC);;All Files (*.*)"
flt = "GCode Files (*.NC);;PDF Files (*.PDF);;All Files (*.*)"
self.source_editor_tab = TextEditor(app=self, plain_text=True)
@ -10241,13 +10254,6 @@ class App(QtCore.QObject):
self.inform.emit('[WARNING_NOTCL] %s' % _("Save Project cancelled."))
return
try:
f = open(filename, 'r')
f.close()
except IOError:
self.inform.emit('[ERROR_NOTCL] %s' % _("The object is used by another application."))
return
if use_thread is True:
self.worker_task.emit({'fcn': self.save_project,
'params': [filename, quit_action]})
@ -12154,14 +12160,14 @@ class App(QtCore.QObject):
g = json.dumps(d, default=to_dict, indent=2, sort_keys=True).encode('utf-8')
# # Write
f.write(g)
self.inform.emit('[success] %s: %s' %
(_("Project saved to"), filename))
self.inform.emit('[success] %s: %s' % (_("Project saved to"), filename))
else:
# Open file
try:
f = open(filename, 'w')
except IOError:
App.log.error("Failed to open file for saving: %s", filename)
self.inform.emit('[ERROR_NOTCL] %s' % _("The object is used by another application."))
return
# Write
@ -12175,8 +12181,7 @@ class App(QtCore.QObject):
except IOError:
if silent is False:
self.inform.emit('[ERROR_NOTCL] %s: %s %s' %
(_("Failed to verify project file"), filename, _("Retry to save it."))
)
(_("Failed to verify project file"), filename, _("Retry to save it.")))
return
try:
@ -12184,8 +12189,7 @@ class App(QtCore.QObject):
except Exception:
if silent is False:
self.inform.emit('[ERROR_NOTCL] %s: %s %s' %
(_("Failed to parse saved project file"), filename, _("Retry to save it."))
)
(_("Failed to parse saved project file"), filename, _("Retry to save it.")))
f.close()
return
saved_f.close()
@ -12196,8 +12200,7 @@ class App(QtCore.QObject):
(_("Project saved to"), filename))
else:
self.inform.emit('[ERROR_NOTCL] %s: %s %s' %
(_("Failed to parse saved project file"), filename, _("Retry to save it."))
)
(_("Failed to parse saved project file"), filename, _("Retry to save it.")))
tb_settings = QSettings("Open Source", "FlatCAM")
lock_state = self.ui.lock_action.isChecked()

View File

@ -1288,6 +1288,8 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
def iso_init(geo_obj, app_obj):
# Propagate options
geo_obj.options["cnctooldia"] = str(self.options["isotooldia"])
geo_obj.tool_type = self.ui.tool_type_radio.get_value().upper()
geo_obj.solid_geometry = []
for i in range(passes):
iso_offset = dia * ((2 * i + 1) / 2.0) - (i * (overlap / 100) * dia)
@ -1417,6 +1419,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
def iso_init(geo_obj, app_obj):
# Propagate options
geo_obj.options["cnctooldia"] = str(self.options["isotooldia"])
geo_obj.tool_type = self.ui.tool_type_radio.get_value().upper()
# if milling type is climb then the move is counter-clockwise around features
mill_t = 1 if milling_type == 'cl' else 0
@ -3603,6 +3606,9 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.old_toolchangeg_state = self.app.defaults["geometry_toolchange"]
self.units_found = self.app.defaults['units']
# this variable can be updated by the Object that generates the geometry
self.tool_type = 'C1'
# Attributes to be included in serialization
# Always append to it because it carries contents
# from predecessors.
@ -3745,11 +3751,11 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.ui.geo_tools_table.setColumnHidden(6, False)
self.set_tool_offset_visibility(selected_row)
self.ui_connect()
# HACK: for whatever reasons the name in Selected tab is reverted to the original one after a successful rename
# done in the collection view but only for Geometry objects. Perhaps some references remains. Should be fixed.
self.ui.name_entry.set_value(self.options['name'])
self.ui_connect()
def set_ui(self, ui):
FlatCAMObj.set_ui(self, ui)
@ -3859,7 +3865,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
'offset': 'Path',
'offset_value': 0.0,
'type': _('Rough'),
'tool_type': 'C1',
'tool_type': self.tool_type,
'data': new_data,
'solid_geometry': self.solid_geometry
}
@ -3883,7 +3889,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.ui.tool_offset_entry.hide()
self.ui.tool_offset_lbl.hide()
# used to store the state of the mpass_cb if the selected postproc for geometry is hpgl
# used to store the state of the mpass_cb if the selected preprocessor for geometry is hpgl
self.old_pp_state = self.default_data['multidepth']
self.old_toolchangeg_state = self.default_data['toolchange']
@ -3934,7 +3940,6 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.ui.paint_tool_button.clicked.connect(lambda: self.app.paint_tool.run(toggle=False))
self.ui.generate_ncc_button.clicked.connect(lambda: self.app.ncclear_tool.run(toggle=False))
self.ui.pp_geometry_name_cb.activated.connect(self.on_pp_changed)
self.ui.addtool_entry.returnPressed.connect(lambda: self.on_tool_add())
self.ui.tipdia_entry.valueChanged.connect(self.update_cutz)
self.ui.tipangle_entry.valueChanged.connect(self.update_cutz)
@ -4010,6 +4015,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
# I use lambda's because the connected functions have parameters that could be used in certain scenarios
self.ui.addtool_btn.clicked.connect(lambda: self.on_tool_add())
self.ui.addtool_entry.returnPressed.connect(self.on_tool_add)
self.ui.copytool_btn.clicked.connect(lambda: self.on_tool_copy())
self.ui.deltool_btn.clicked.connect(lambda: self.on_tool_delete())
@ -4062,6 +4068,11 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
except (TypeError, AttributeError):
pass
try:
self.ui.addtool_entry.returnPressed.disconnect()
except (TypeError, AttributeError):
pass
try:
self.ui.copytool_btn.clicked.disconnect()
except (TypeError, AttributeError):
@ -4103,59 +4114,26 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.units = self.app.defaults['units'].upper()
# if a Tool diameter entered is a char instead a number the final message of Tool adding is changed
# because the Default value for Tool is used.
change_message = False
if dia is not None:
tooldia = dia
else:
try:
tooldia = float(self.ui.addtool_entry.get_value())
except ValueError:
# try to convert comma to decimal point. if it's still not working error message and return
try:
tooldia = float(self.ui.addtool_entry.get_value().replace(',', '.'))
except ValueError:
change_message = True
tooldia = float(self.options["cnctooldia"][0])
if tooldia is None:
self.build_ui()
self.app.inform.emit('[ERROR_NOTCL] %s' %
_("Please enter the desired tool diameter in Float format."))
return
tooldia = float(self.ui.addtool_entry.get_value())
# construct a list of all 'tooluid' in the self.tools
tool_uid_list = []
for tooluid_key in self.tools:
tool_uid_item = int(tooluid_key)
tool_uid_list.append(tool_uid_item)
# tool_uid_list = list()
# for tooluid_key in self.tools:
# tool_uid_list.append(int(tooluid_key))
tool_uid_list = [int(tooluid_key) for tooluid_key in self.tools]
# find maximum from the temp_uid, add 1 and this is the new 'tooluid'
if not tool_uid_list:
max_uid = 0
else:
max_uid = max(tool_uid_list)
max_uid = max(tool_uid_list) if tool_uid_list else 0
self.tooluid = max_uid + 1
tooldia = float('%.*f' % (self.decimals, tooldia))
# here we actually add the new tool; if there is no tool in the tool table we add a tool with default data
# otherwise we add a tool with data copied from last tool
if not self.tools:
self.tools.update({
self.tooluid: {
'tooldia': tooldia,
'offset': 'Path',
'offset_value': 0.0,
'type': _('Rough'),
'tool_type': 'C1',
'data': deepcopy(self.default_data),
'solid_geometry': self.solid_geometry
}
})
else:
if self.tools:
last_data = self.tools[max_uid]['data']
last_offset = self.tools[max_uid]['offset']
last_offset_value = self.tools[max_uid]['offset_value']
@ -4179,6 +4157,18 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
'solid_geometry': deepcopy(last_solid_geometry)
}
})
else:
self.tools.update({
self.tooluid: {
'tooldia': tooldia,
'offset': 'Path',
'offset_value': 0.0,
'type': _('Rough'),
'tool_type': 'C1',
'data': deepcopy(self.default_data),
'solid_geometry': self.solid_geometry
}
})
self.tools[self.tooluid]['data']['name'] = self.options['name']
@ -4192,12 +4182,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
pass
self.ser_attrs.append('tools')
if change_message is False:
self.app.inform.emit('[success] %s' % _("Tool added in Tool Table."))
else:
change_message = False
self.app.inform.emit('[WARNING_NOTCL] %s' %
_("Default Tool added. Wrong value format entered."))
self.app.inform.emit('[success] %s' % _("Tool added in Tool Table."))
self.build_ui()
# if there is no tool left in the Tools Table, enable the parameters GUI
@ -5735,12 +5720,17 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.tools = deepcopy(temp_tools_dict)
# if there is a value in the new tool field then convert that one too
try:
self.ui.addtool_entry.returnPressed.disconnect()
except TypeError:
pass
tooldia = self.ui.addtool_entry.get_value()
if tooldia:
tooldia *= factor
tooldia = float('%.*f' % (self.decimals, tooldia))
self.ui.addtool_entry.set_value(tooldia)
self.ui.addtool_entry.returnPressed.connect(self.on_tool_add)
return factor
@ -6621,9 +6611,12 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
:param to_file: if False then no actual file is saved but the app will know that a file was created
:return: None
"""
gcode = ''
roland = False
hpgl = False
# gcode = ''
# roland = False
# hpgl = False
# isel_icp = False
include_header = True
try:
if self.special_group:
@ -6635,58 +6628,184 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
except AttributeError:
pass
# detect if using Roland preprocessor
try:
for key in self.cnc_tools:
if self.cnc_tools[key]['data']['ppname_g'] == 'Roland_MDX_20':
roland = True
break
if self.cnc_tools[key]['data']['ppname_g'] == 'hpgl':
hpgl = True
break
except Exception as e:
try:
for key in self.cnc_tools:
if self.cnc_tools[key]['data']['ppname_e'] == 'Roland_MDX_20':
roland = True
break
except Exception as e:
pass
# if this dict is not empty then the object is a Geometry object
if self.cnc_tools:
first_key = next(iter(self.cnc_tools))
include_header = self.app.preprocessors[self.cnc_tools[first_key]['data']['ppname_g']].include_header
# if this dict is not empty then the object is an Excellon object
if self.exc_cnc_tools:
first_key = next(iter(self.exc_cnc_tools))
include_header = self.app.preprocessors[self.exc_cnc_tools[first_key]['data']['ppname_e']].include_header
# # detect if using Roland preprocessor
# try:
# for key in self.cnc_tools:
# if self.cnc_tools[key]['data']['ppname_g'] == 'Roland_MDX_20':
# roland = True
# break
# except Exception:
# try:
# for key in self.cnc_tools:
# if self.cnc_tools[key]['data']['ppname_e'] == 'Roland_MDX_20':
# roland = True
# break
# except Exception:
# pass
#
# # detect if using HPGL preprocessor
# try:
# for key in self.cnc_tools:
# if self.cnc_tools[key]['data']['ppname_g'] == 'hpgl':
# hpgl = True
# break
# except Exception:
# try:
# for key in self.cnc_tools:
# if self.cnc_tools[key]['data']['ppname_e'] == 'hpgl':
# hpgl = True
# break
# except Exception:
# pass
#
# # detect if using ISEL_ICP_CNC preprocessor
# try:
# for key in self.cnc_tools:
# if 'ISEL_ICP' in self.cnc_tools[key]['data']['ppname_g'].upper():
# isel_icp = True
# break
# except Exception:
# try:
# for key in self.cnc_tools:
# if 'ISEL_ICP' in self.cnc_tools[key]['data']['ppname_e'].upper():
# isel_icp = True
# break
# except Exception:
# pass
# do not add gcode_header when using the Roland preprocessor, add it for every other preprocessor
if roland is False and hpgl is False:
gcode = self.gcode_header()
# if roland is False and hpgl is False and isel_icp is False:
# gcode = self.gcode_header()
# detect if using multi-tool and make the Gcode summation correctly for each case
if self.multitool is True:
for tooluid_key in self.cnc_tools:
for key, value in self.cnc_tools[tooluid_key].items():
if key == 'gcode':
gcode += value
break
else:
gcode += self.gcode
# do not add gcode_header when using the Roland, HPGL or ISEP_ICP_CNC preprocessor (or any other preprocessor
# that has the include_header attribute set as False, add it for every other preprocessor
# if include_header:
# gcode = self.gcode_header()
# else:
# gcode = ''
if roland is True:
g = preamble + gcode + postamble
elif hpgl is True:
g = self.gcode_header() + preamble + gcode + postamble
# # detect if using multi-tool and make the Gcode summation correctly for each case
# if self.multitool is True:
# for tooluid_key in self.cnc_tools:
# for key, value in self.cnc_tools[tooluid_key].items():
# if key == 'gcode':
# gcode += value
# break
# else:
# gcode += self.gcode
# if roland is True:
# g = preamble + gcode + postamble
# elif hpgl is True:
# g = self.gcode_header() + preamble + gcode + postamble
# else:
# # fix so the preamble gets inserted in between the comments header and the actual start of GCODE
# g_idx = gcode.rfind('G20')
#
# # if it did not find 'G20' then search for 'G21'
# if g_idx == -1:
# g_idx = gcode.rfind('G21')
#
# # if it did not find 'G20' and it did not find 'G21' then there is an error and return
# # but only when the preprocessor is not ISEL_ICP who is allowed not to have the G20/G21 command
# if g_idx == -1 and isel_icp is False:
# self.app.inform.emit('[ERROR_NOTCL] %s' % _("G-code does not have a units code: either G20 or G21"))
# return
#
# footer = self.app.defaults['cncjob_footer']
# end_gcode = self.gcode_footer() if footer is True else ''
# g = gcode[:g_idx] + preamble + '\n' + gcode[g_idx:] + postamble + end_gcode
gcode = ''
if include_header is False:
g = preamble
# detect if using multi-tool and make the Gcode summation correctly for each case
if self.multitool is True:
for tooluid_key in self.cnc_tools:
for key, value in self.cnc_tools[tooluid_key].items():
if key == 'gcode':
gcode += value
break
else:
gcode += self.gcode
g = g + gcode + postamble
else:
# search for the GCode beginning which is usually a G20 or G21
# fix so the preamble gets inserted in between the comments header and the actual start of GCODE
g_idx = gcode.rfind('G20')
# g_idx = gcode.rfind('G20')
#
# # if it did not find 'G20' then search for 'G21'
# if g_idx == -1:
# g_idx = gcode.rfind('G21')
#
# # if it did not find 'G20' and it did not find 'G21' then there is an error and return
# if g_idx == -1:
# self.app.inform.emit('[ERROR_NOTCL] %s' % _("G-code does not have a units code: either G20 or G21"))
# return
# if it did not find 'G20' then search for 'G21'
if g_idx == -1:
g_idx = gcode.rfind('G21')
# detect if using multi-tool and make the Gcode summation correctly for each case
if self.multitool is True:
for tooluid_key in self.cnc_tools:
for key, value in self.cnc_tools[tooluid_key].items():
if key == 'gcode':
gcode += value
break
else:
gcode += self.gcode
# if it did not find 'G20' and it did not find 'G21' then there is an error and return
if g_idx == -1:
self.app.inform.emit('[ERROR_NOTCL] %s' % _("G-code does not have a units code: either G20 or G21"))
return
end_gcode = self.gcode_footer() if self.app.defaults['cncjob_footer'] is True else ''
footer = self.app.defaults['cncjob_footer']
end_gcode = self.gcode_footer() if footer is True else ''
g = gcode[:g_idx] + preamble + '\n' + gcode[g_idx:] + postamble + end_gcode
# detect if using a HPGL preprocessor
hpgl = False
if self.cnc_tools:
for key in self.cnc_tools:
if 'ppname_g' in self.cnc_tools[key]['data']:
if 'hpgl' in self.cnc_tools[key]['data']['ppname_g']:
hpgl = True
break
elif self.exc_cnc_tools:
for key in self.cnc_tools:
if 'ppname_e' in self.cnc_tools[key]['data']:
if 'hpgl' in self.cnc_tools[key]['data']['ppname_e']:
hpgl = True
break
if hpgl:
processed_gcode = ''
pa_re = re.compile(r"^PA\s*(-?\d+\.\d*),?\s*(-?\d+\.\d*)*;?$")
for gline in gcode.splitlines():
match = pa_re.search(gline)
if match:
x_int = int(float(match.group(1)))
y_int = int(float(match.group(2)))
new_line = 'PA%d,%d;\n' % (x_int, y_int)
processed_gcode += new_line
else:
processed_gcode += gline + '\n'
gcode = processed_gcode
g = self.gcode_header() + '\n' + preamble + '\n' + gcode + postamble + end_gcode
else:
try:
g_idx = gcode.index('G94')
g = self.gcode_header() + gcode[:g_idx + 3] + '\n\n' + preamble + '\n' + \
gcode[(g_idx + 3):] + postamble + end_gcode
except ValueError:
self.app.inform.emit('[ERROR_NOTCL] %s' %
_("G-code does not have a G94 code and we will not include the code in the "
"'Prepend to GCode' text box"))
g = self.gcode_header() + '\n' + gcode + postamble + end_gcode
# if toolchange custom is used, replace M6 code with the code from the Toolchange Custom Text box
if self.ui.toolchange_cb.get_value() is True:

View File

@ -9,6 +9,34 @@ CAD program, and create G-Code for Isolation routing.
=================================================
17.12.2019
- more optimizations in NCC Tool
- optimizations in Paint Tool
- maximum range for Cut Z is now zero to deal with the situation when using V-shape with tip-dia same value with cut width
- modified QValidator in FCDoubleSpinner() GUI element to allow entering the minus sign when the range maximum is set as 0.0; also for positive numbers allowed entering the symbol plus
- made sure that if in Gerber UI the isolation is made with a V-Shape tool then the tool type is automatically updated on the generated Geometry Object
- added ability to save the Source File as PDF (still have to adjust the page size)
- fixed the generate_from_geometry_2() method to use the default values in case the parameters are None
- added ability to save the Source File as PDF - fixed page size and added line breaks
- more mods to generate_from_geometry_2() method
- fixed bug saving the FlatCAM project saying the file is used by another application
16.12.2019
- in Geometry Editor added support for Jump To function such as that it works within the Editor Tools themselves. For now it works only in absolute jumps
- modified the Jump To method such that now allows relative jump from the current mouse location
- fixed the Defaults upgrade overwriting the new version number with the old one
- fixed issue with clear_polygon3() - the one who makes 'lines' and fixed the NCC Tool
- some small changes in the FlatCAMGeometry.on_tool_add() method
- made sure that in Geometry Editor the self.app.mouse attribute is updated with the current mouse position (x, y)
- updated the preprocessor files
- fixed the HPGL preprocessor
- fixed the CNCJob geometry created with HPGL preprocessor
- fixed GCode generated with HPGL preprocessor to output only integer coordinates
- fixed the HPGL2 import parsing for absolute linear movements
- fixed the line endings for setup_ubuntu.sh
15.12.2019
- fixed a bug that created a crash in special conditions; it's related to the QSettings in FlatCAMGui.py
@ -17,6 +45,10 @@ CAD program, and create G-Code for Isolation routing.
- updated the languages
- fixed a typo
- fixed layout on first launch of the app
- fixed some issues with the recent preparation for dark icons resource usage
- added a new preprocessor file contributed by Daniel Friderich and added fixes for it
- modified the export_gcode() method and the preprocessors such that the preprocessors now have the information if to include the gcode header
- updated all the translation PO files and the POT file
- RELEASE 8.99
14.12.2019

176
camlib.py
View File

@ -1381,9 +1381,10 @@ class Geometry(object):
inner_edges.append(y)
# geoms += outer_edges + inner_edges
for g in outer_edges + inner_edges:
geoms.insert(g)
if prog_plot:
self.plot_temp_shapes(g)
if g and not g.is_empty:
geoms.insert(g)
if prog_plot:
self.plot_temp_shapes(g)
if prog_plot:
self.temp_shapes.redraw()
@ -1395,7 +1396,9 @@ class Geometry(object):
# Optimization: Reduce lifts
if connect:
# log.debug("Reducing tool lifts...")
geoms = Geometry.paint_connect(geoms, polygon_to_clear, tooldia, steps_per_circle)
geoms_conn = Geometry.paint_connect(geoms, polygon_to_clear, tooldia, steps_per_circle)
if geoms_conn:
return geoms_conn
return geoms
@ -1419,6 +1422,9 @@ class Geometry(object):
"""
# log.debug("camlib.clear_polygon3()")
if not isinstance(polygon, Polygon):
log.debug("camlib.Geometry.clear_polygon3() --> Not a Polygon but %s" % str(type(polygon)))
return None
# ## The toolpaths
# Index first and last points in paths
@ -1433,41 +1439,43 @@ class Geometry(object):
# Bounding box
left, bot, right, top = polygon.bounds
margin_poly = polygon.buffer(-tooldia / 1.99999999, (int(steps_per_circle)))
try:
margin_poly = polygon.buffer(-tooldia / 1.99999999, (int(steps_per_circle)))
except Exception as e:
log.debug("camlib.Geometry.clear_polygon3() --> Could not buffer the Polygon")
return None
# First line
y = top - tooldia / 1.99999999
while y > bot + tooldia / 1.999999999:
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
try:
y = top - tooldia / 1.99999999
while y > bot + tooldia / 1.999999999:
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
# provide the app with a way to process the GUI events when in a blocking loop
QtWidgets.QApplication.processEvents()
# provide the app with a way to process the GUI events when in a blocking loop
QtWidgets.QApplication.processEvents()
line = LineString([(left, y), (right, y)])
line = line.intersection(margin_poly)
lines_trimmed.append(line)
y -= tooldia * (1 - overlap)
if prog_plot:
self.plot_temp_shapes(line)
self.temp_shapes.redraw()
# Last line
y = bot + tooldia / 2
line = LineString([(left, y), (right, y)])
line = line.intersection(margin_poly)
lines_trimmed.append(line)
y -= tooldia * (1 - overlap)
if prog_plot:
self.plot_temp_shapes(line)
self.temp_shapes.redraw()
# Last line
y = bot + tooldia / 2
line = LineString([(left, y), (right, y)])
line = line.intersection(margin_poly)
for ll in line:
lines_trimmed.append(ll)
if prog_plot:
self.plot_temp_shapes(line)
# Combine
# linesgeo = unary_union(lines)
# Trim to the polygon
# margin_poly = polygon.buffer(-tooldia / 1.99999999, (int(steps_per_circle)))
# lines_trimmed = linesgeo.intersection(margin_poly)
for ll in line:
lines_trimmed.append(ll)
if prog_plot:
self.plot_temp_shapes(line)
except Exception as e:
log.debug('camlib.Geometry.clear_polygon3() Processing poly --> %s' % str(e))
return None
if prog_plot:
self.temp_shapes.redraw()
@ -1477,27 +1485,33 @@ class Geometry(object):
# Add lines to storage
try:
for line in lines_trimmed:
geoms.insert(line)
if isinstance(line, LineString) or isinstance(line, LinearRing):
geoms.insert(line)
else:
log.debug("camlib.Geometry.clear_polygon3(). Not a line: %s" % str(type(line)))
except TypeError:
# in case lines_trimmed are not iterable (Linestring, LinearRing)
geoms.insert(lines_trimmed)
# Add margin (contour) to storage
if contour:
if isinstance(margin_poly, Polygon):
geoms.insert(margin_poly.exterior)
if prog_plot:
self.plot_temp_shapes(margin_poly.exterior)
for ints in margin_poly.interiors:
geoms.insert(ints)
if prog_plot:
self.plot_temp_shapes(ints)
elif isinstance(margin_poly, MultiPolygon):
try:
for poly in margin_poly:
geoms.insert(poly.exterior)
if isinstance(poly, Polygon) and not poly.is_empty:
geoms.insert(poly.exterior)
if prog_plot:
self.plot_temp_shapes(poly.exterior)
for ints in poly.interiors:
geoms.insert(ints)
if prog_plot:
self.plot_temp_shapes(ints)
except TypeError:
if isinstance(margin_poly, Polygon) and not margin_poly.is_empty:
marg_ext = margin_poly.exterior
geoms.insert(marg_ext)
if prog_plot:
self.plot_temp_shapes(poly.exterior)
for ints in poly.interiors:
self.plot_temp_shapes(margin_poly.exterior)
for ints in margin_poly.interiors:
geoms.insert(ints)
if prog_plot:
self.plot_temp_shapes(ints)
@ -1508,7 +1522,9 @@ class Geometry(object):
# Optimization: Reduce lifts
if connect:
# log.debug("Reducing tool lifts...")
geoms = Geometry.paint_connect(geoms, polygon, tooldia, steps_per_circle)
geoms_conn = Geometry.paint_connect(geoms, polygon, tooldia, steps_per_circle)
if geoms_conn:
return geoms_conn
return geoms
@ -1581,8 +1597,14 @@ class Geometry(object):
optimized_paths.get_points = get_pts
path_count = 0
current_pt = (0, 0)
pt, geo = storage.nearest(current_pt)
try:
pt, geo = storage.nearest(current_pt)
except StopIteration:
log.debug("camlib.Geometry.paint_connect(). Storage empty")
return None
storage.remove(geo)
geo = LineString(geo)
current_pt = geo.coords[-1]
try:
@ -1592,6 +1614,7 @@ class Geometry(object):
pt, candidate = storage.nearest(current_pt)
storage.remove(candidate)
candidate = LineString(candidate)
# If last point in geometry is the nearest
@ -2448,11 +2471,17 @@ class CNCjob(Geometry):
except KeyError:
z_off = 0
default_data = dict()
for k, v in list(self.options.items()):
default_data[k] = deepcopy(v)
self.exc_cnc_tools[it[1]] = dict()
self.exc_cnc_tools[it[1]]['tool'] = it[0]
self.exc_cnc_tools[it[1]]['nr_drills'] = drill_no
self.exc_cnc_tools[it[1]]['nr_slots'] = slot_no
self.exc_cnc_tools[it[1]]['offset_z'] = z_off
self.exc_cnc_tools[it[1]]['data'] = default_data
self.exc_cnc_tools[it[1]]['solid_geometry'] = deepcopy(sol_geo)
self.app.inform.emit(_("Creating a list of points to drill..."))
@ -3275,14 +3304,12 @@ class CNCjob(Geometry):
return self.gcode
def generate_from_geometry_2(
self, geometry, append=True,
tooldia=None, offset=0.0, tolerance=0,
z_cut=1.0, z_move=2.0,
feedrate=2.0, feedrate_z=2.0, feedrate_rapid=30,
spindlespeed=None, spindledir='CW', dwell=False, dwelltime=1.0,
self, geometry, append=True, tooldia=None, offset=0.0, tolerance=0, z_cut=None, z_move=None,
feedrate=None, feedrate_z=None, feedrate_rapid=None,
spindlespeed=None, spindledir='CW', dwell=False, dwelltime=None,
multidepth=False, depthpercut=None,
toolchange=False, toolchangez=1.0, toolchangexy="0.0, 0.0",
extracut=False, extracut_length=0.1, startz=None, endz=2.0,
toolchange=False, toolchangez=None, toolchangexy="0.0, 0.0",
extracut=False, extracut_length=None, startz=None, endz=None,
pp_geometry_name=None, tool_no=1):
"""
Second algorithm to generate from Geometry.
@ -3377,27 +3404,31 @@ class CNCjob(Geometry):
log.debug("%d paths" % len(flat_geometry))
try:
self.tooldia = float(tooldia) if tooldia else None
self.tooldia = float(tooldia) if tooldia else self.app.defaults["geometry_cnctooldia"]
except ValueError:
self.tooldia = [float(el) for el in tooldia.split(',') if el != ''] if tooldia else None
self.tooldia = [float(el) for el in tooldia.split(',') if el != ''] if tooldia is not None else \
self.app.defaults["geometry_cnctooldia"]
self.z_cut = float(z_cut) if z_cut is not None else None
self.z_move = float(z_move) if z_move is not None else None
self.z_cut = float(z_cut) if z_cut is not None else self.app.defaults["geometry_cutz"]
self.z_move = float(z_move) if z_move is not None else self.app.defaults["geometry_travelz"]
self.feedrate = float(feedrate) if feedrate else None
self.z_feedrate = float(feedrate_z) if feedrate_z is not None else None
self.feedrate_rapid = float(feedrate_rapid) if feedrate_rapid else None
self.feedrate = float(feedrate) if feedrate is not None else self.app.defaults["geometry_feedrate"]
self.z_feedrate = float(feedrate_z) if feedrate_z is not None else self.app.defaults["geometry_feedrate_z"]
self.feedrate_rapid = float(feedrate_rapid) if feedrate_rapid is not None else \
self.app.defaults["geometry_feedrate_rapid"]
self.spindlespeed = int(spindlespeed) if spindlespeed != 0 else None
self.spindledir = spindledir
self.dwell = dwell
self.dwelltime = float(dwelltime) if dwelltime else None
self.dwelltime = float(dwelltime) if dwelltime is not None else self.app.defaults["geometry_dwelltime"]
self.startz = float(startz) if startz is not None else None
self.z_end = float(endz) if endz is not None else None
self.z_depthpercut = float(depthpercut) if depthpercut else None
self.startz = float(startz) if startz is not None else self.app.defaults["geometry_startz"]
self.z_end = float(endz) if endz is not None else self.app.defaults["geometry_endz"]
self.z_depthpercut = float(depthpercut) if depthpercut is not None else 0.0
self.multidepth = multidepth
self.z_toolchange = float(toolchangez) if toolchangez is not None else None
self.z_toolchange = float(toolchangez) if toolchangez is not None else self.app.defaults["geometry_toolchangez"]
self.extracut_length = float(extracut_length) if extracut_length is not None else \
self.app.defaults["geometry_extracut_length"]
try:
if toolchangexy == '':
@ -3457,7 +3488,10 @@ class CNCjob(Geometry):
return 'fail'
# made sure that depth_per_cut is no more then the z_cut
if abs(self.z_cut) < self.z_depthpercut:
try:
if abs(self.z_cut) < self.z_depthpercut:
self.z_depthpercut = abs(self.z_cut)
except TypeError:
self.z_depthpercut = abs(self.z_cut)
# ## Index first and last points in paths
@ -3572,7 +3606,7 @@ class CNCjob(Geometry):
if not multidepth:
# calculate the cut distance
total_cut += geo.length
self.gcode += self.create_gcode_single_pass(geo, extracut, extracut_length, tolerance,
self.gcode += self.create_gcode_single_pass(geo, extracut, self.extracut_length, tolerance,
old_point=current_pt)
# --------- Multi-pass ---------
@ -3587,7 +3621,7 @@ class CNCjob(Geometry):
total_cut += (geo.length * nr_cuts)
self.gcode += self.create_gcode_multi_pass(geo, extracut, extracut_length, tolerance,
self.gcode += self.create_gcode_multi_pass(geo, extracut, self.extracut_length, tolerance,
postproc=p, old_point=current_pt)
# calculate the travel distance
@ -3916,8 +3950,8 @@ class CNCjob(Geometry):
match_pa = re.search(r"^PA(\s*-?\d+\.\d+?),(\s*\s*-?\d+\.\d+?)*;$", gline)
if match_pa:
command['G'] = 0
command['X'] = float(match_pa.group(1).replace(" ", ""))
command['Y'] = float(match_pa.group(2).replace(" ", ""))
command['X'] = float(match_pa.group(1).replace(" ", "")) / 40
command['Y'] = float(match_pa.group(2).replace(" ", "")) / 40
match_pen = re.search(r"^(P[U|D])", gline)
if match_pen:
if match_pen.group(1) == 'PU':

View File

@ -1880,7 +1880,10 @@ class DrawTool(object):
return ""
def on_key(self, key):
return None
# Jump to coords
if key == QtCore.Qt.Key_J or key == 'J':
self.draw_app.app.on_jump_to()
def utility_geometry(self, data=None):
return None
@ -1934,13 +1937,17 @@ class FCCircle(FCShapeTool):
DrawTool.__init__(self, draw_app)
self.name = 'circle'
self.draw_app = draw_app
try:
QtGui.QGuiApplication.restoreOverrideCursor()
except Exception:
pass
self.cursor = QtGui.QCursor(QtGui.QPixmap(self.app.resource_location + '/aero_circle_geo.png'))
self.cursor = QtGui.QCursor(QtGui.QPixmap(self.draw_app.app.resource_location + '/aero_circle_geo.png'))
QtGui.QGuiApplication.setOverrideCursor(self.cursor)
self.draw_app.app.jump_signal.connect(lambda x: self.draw_app.update_utility_geometry(data=x))
self.draw_app.app.inform.emit(_("Click on Center point ..."))
self.steps_per_circ = self.draw_app.app.defaults["geometry_circle_steps"]
@ -1977,8 +1984,10 @@ class FCCircle(FCShapeTool):
radius = distance(p1, p2)
self.geometry = DrawToolShape(Point(p1).buffer(radius, int(self.steps_per_circ / 4)))
self.complete = True
self.draw_app.app.inform.emit('[success] %s' %
_("Done. Adding Circle completed."))
self.draw_app.app.jump_signal.disconnect()
self.draw_app.app.inform.emit('[success] %s' % _("Done. Adding Circle completed."))
class FCArc(FCShapeTool):
@ -1986,11 +1995,13 @@ class FCArc(FCShapeTool):
DrawTool.__init__(self, draw_app)
self.name = 'arc'
self.draw_app = draw_app
try:
QtGui.QGuiApplication.restoreOverrideCursor()
except Exception:
pass
self.cursor = QtGui.QCursor(QtGui.QPixmap(self.app.resource_location + '/aero_arc.png'))
self.cursor = QtGui.QCursor(QtGui.QPixmap(self.draw_app.app.resource_location + '/aero_arc.png'))
QtGui.QGuiApplication.setOverrideCursor(self.cursor)
self.draw_app.app.inform.emit(_("Click on Center point ..."))
@ -2006,6 +2017,8 @@ class FCArc(FCShapeTool):
# 132 = p1, p3, p2
self.mode = "c12" # Center, p1, p2
self.draw_app.app.jump_signal.connect(lambda x: self.draw_app.update_utility_geometry(data=x))
self.steps_per_circ = self.draw_app.app.defaults["geometry_circle_steps"]
def click(self, point):
@ -2040,6 +2053,10 @@ class FCArc(FCShapeTool):
self.direction = 'cw' if self.direction == 'ccw' else 'ccw'
return _('Direction: %s') % self.direction.upper()
# Jump to coords
if key == QtCore.Qt.Key_J or key == 'J':
self.draw_app.app.on_jump_to()
if key == 'M' or key == QtCore.Qt.Key_M:
# delete the possible points made before this action; we want to start anew
self.points[:] = []
@ -2192,8 +2209,10 @@ class FCArc(FCShapeTool):
self.geometry = DrawToolShape(LineString(arc(center, radius, startangle, stopangle,
self.direction, self.steps_per_circ)))
self.complete = True
self.draw_app.app.inform.emit('[success] %s' %
_("Done. Arc completed."))
self.draw_app.app.jump_signal.disconnect()
self.draw_app.app.inform.emit('[success] %s' % _("Done. Arc completed."))
class FCRectangle(FCShapeTool):
@ -2204,14 +2223,17 @@ class FCRectangle(FCShapeTool):
def __init__(self, draw_app):
DrawTool.__init__(self, draw_app)
self.name = 'rectangle'
self.draw_app = draw_app
try:
QtGui.QGuiApplication.restoreOverrideCursor()
except Exception:
pass
self.cursor = QtGui.QCursor(QtGui.QPixmap(self.app.resource_location + '/aero.png'))
self.cursor = QtGui.QCursor(QtGui.QPixmap(self.draw_app.app.resource_location + '/aero.png'))
QtGui.QGuiApplication.setOverrideCursor(self.cursor)
self.draw_app.app.jump_signal.connect(lambda x: self.draw_app.update_utility_geometry(data=x))
self.draw_app.app.inform.emit(_("Click on 1st corner ..."))
def click(self, point):
@ -2246,8 +2268,9 @@ class FCRectangle(FCShapeTool):
# self.geometry = LinearRing([p1, (p2[0], p1[1]), p2, (p1[0], p2[1])])
self.geometry = DrawToolShape(Polygon([p1, (p2[0], p1[1]), p2, (p1[0], p2[1])]))
self.complete = True
self.draw_app.app.inform.emit('[success] %s' %
_("Done. Rectangle completed."))
self.draw_app.app.jump_signal.disconnect()
self.draw_app.app.inform.emit('[success] %s' % _("Done. Rectangle completed."))
class FCPolygon(FCShapeTool):
@ -2258,14 +2281,17 @@ class FCPolygon(FCShapeTool):
def __init__(self, draw_app):
DrawTool.__init__(self, draw_app)
self.name = 'polygon'
self.draw_app = draw_app
try:
QtGui.QGuiApplication.restoreOverrideCursor()
except Exception:
pass
self.cursor = QtGui.QCursor(QtGui.QPixmap(self.app.resource_location + '/aero.png'))
self.cursor = QtGui.QCursor(QtGui.QPixmap(self.draw_app.app.resource_location + '/aero.png'))
QtGui.QGuiApplication.setOverrideCursor(self.cursor)
self.draw_app.app.jump_signal.connect(lambda x: self.draw_app.update_utility_geometry(data=x))
self.draw_app.app.inform.emit(_("Click on 1st corner ..."))
def click(self, point):
@ -2301,10 +2327,16 @@ class FCPolygon(FCShapeTool):
self.geometry = DrawToolShape(Polygon(self.points))
self.draw_app.in_action = False
self.complete = True
self.draw_app.app.inform.emit('[success] %s' %
_("Done. Polygon completed."))
self.draw_app.app.jump_signal.disconnect()
self.draw_app.app.inform.emit('[success] %s' % _("Done. Polygon completed."))
def on_key(self, key):
# Jump to coords
if key == QtCore.Qt.Key_J or key == 'J':
self.draw_app.app.on_jump_to()
if key == 'Backspace' or key == QtCore.Qt.Key_Backspace:
if len(self.points) > 0:
self.points = self.points[0:-1]
@ -2321,14 +2353,17 @@ class FCPath(FCPolygon):
"""
def __init__(self, draw_app):
FCPolygon.__init__(self, draw_app)
self.draw_app = draw_app
try:
QtGui.QGuiApplication.restoreOverrideCursor()
except Exception:
pass
self.cursor = QtGui.QCursor(QtGui.QPixmap(self.app.resource_location + '/aero_path5.png'))
self.cursor = QtGui.QCursor(QtGui.QPixmap(self.draw_app.app.resource_location + '/aero_path5.png'))
QtGui.QGuiApplication.setOverrideCursor(self.cursor)
self.draw_app.app.jump_signal.connect(lambda x: self.draw_app.update_utility_geometry(data=x))
def make(self):
self.geometry = DrawToolShape(LineString(self.points))
self.name = 'path'
@ -2340,6 +2375,9 @@ class FCPath(FCPolygon):
self.draw_app.in_action = False
self.complete = True
self.draw_app.app.jump_signal.disconnect()
self.draw_app.app.inform.emit('[success] %s' % _("Done. Path completed."))
def utility_geometry(self, data=None):
@ -2351,6 +2389,10 @@ class FCPath(FCPolygon):
return None
def on_key(self, key):
# Jump to coords
if key == QtCore.Qt.Key_J or key == 'J':
self.draw_app.app.on_jump_to()
if key == 'Backspace' or key == QtCore.Qt.Key_Backspace:
if len(self.points) > 0:
self.points = self.points[0:-1]
@ -2365,6 +2407,7 @@ class FCSelect(DrawTool):
def __init__(self, draw_app):
DrawTool.__init__(self, draw_app)
self.name = 'select'
self.draw_app = draw_app
try:
QtGui.QGuiApplication.restoreOverrideCursor()
@ -2443,12 +2486,11 @@ class FCExplode(FCShapeTool):
def __init__(self, draw_app):
FCShapeTool.__init__(self, draw_app)
self.name = 'explode'
self.draw_app = draw_app
try:
QtGui.QGuiApplication.restoreOverrideCursor()
except Exception as e:
except Exception:
pass
self.storage = self.draw_app.storage
@ -2457,8 +2499,7 @@ class FCExplode(FCShapeTool):
self.draw_app.active_tool = self
if len(self.draw_app.get_selected()) == 0:
self.draw_app.app.inform.emit('[WARNING_NOTCL] %s...' %
_("No shape selected. Select a shape to explode"))
self.draw_app.app.inform.emit('[WARNING_NOTCL] %s...' % ("No shape selected. Select a shape to explode"))
else:
self.make()
@ -2498,6 +2539,7 @@ class FCMove(FCShapeTool):
def __init__(self, draw_app):
FCShapeTool.__init__(self, draw_app)
self.name = 'move'
self.draw_app = draw_app
try:
QtGui.QGuiApplication.restoreOverrideCursor()
@ -2673,24 +2715,22 @@ class FCCopy(FCMove):
self.geometry = [DrawToolShape(affinity.translate(geom.geo, xoff=dx, yoff=dy))
for geom in self.draw_app.get_selected()]
self.complete = True
self.draw_app.app.inform.emit('[success] %s' %
_("Done. Geometry(s) Copy completed."))
self.draw_app.app.inform.emit('[success] %s' % _("Done. Geometry(s) Copy completed."))
class FCText(FCShapeTool):
def __init__(self, draw_app):
FCShapeTool.__init__(self, draw_app)
self.name = 'text'
self.draw_app = draw_app
try:
QtGui.QGuiApplication.restoreOverrideCursor()
except Exception:
pass
self.cursor = QtGui.QCursor(QtGui.QPixmap(self.app.resource_location + '/aero_text.png'))
self.cursor = QtGui.QCursor(QtGui.QPixmap(self.draw_app.app.resource_location + '/aero_text.png'))
QtGui.QGuiApplication.setOverrideCursor(self.cursor)
# self.shape_buffer = self.draw_app.shape_buffer
self.draw_app = draw_app
self.app = draw_app.app
self.draw_app.app.inform.emit(_("Click on 1st corner ..."))
@ -2762,8 +2802,7 @@ class FCBuffer(FCShapeTool):
def on_buffer(self):
if not self.draw_app.selected:
self.app.inform.emit('[WARNING_NOTCL] %s' %
_("Buffer cancelled. No shape selected."))
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Buffer cancelled. No shape selected."))
return
try:
@ -2876,6 +2915,7 @@ class FCEraser(FCShapeTool):
def __init__(self, draw_app):
DrawTool.__init__(self, draw_app)
self.name = 'eraser'
self.draw_app = draw_app
self.origin = None
self.destination = None
@ -2982,8 +3022,6 @@ class FCPaint(FCShapeTool):
def __init__(self, draw_app):
FCShapeTool.__init__(self, draw_app)
self.name = 'paint'
# self.shape_buffer = self.draw_app.shape_buffer
self.draw_app = draw_app
self.app = draw_app.app
@ -2997,7 +3035,6 @@ class FCTransform(FCShapeTool):
FCShapeTool.__init__(self, draw_app)
self.name = 'transformation'
# self.shape_buffer = self.draw_app.shape_buffer
self.draw_app = draw_app
self.app = draw_app.app
@ -3798,6 +3835,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
self.snap_x = x
self.snap_y = y
self.app.mouse = [x, y]
# update the position label in the infobar since the APP mouse event handlers are disconnected
self.app.ui.position_label.setText("&nbsp;&nbsp;&nbsp;&nbsp;<b>X</b>: %.4f&nbsp;&nbsp; "
@ -3815,12 +3853,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
if event.button == 1 and event_is_dragging and isinstance(self.active_tool, FCEraser):
pass
else:
# ### Utility geometry (animated) ###
geo = self.active_tool.utility_geometry(data=(x, y))
if isinstance(geo, DrawToolShape) and geo.geo is not None:
# Remove any previous utility shape
self.tool_shape.clear(update=True)
self.draw_utility_geometry(geo=geo)
self.update_utility_geometry(data=(x, y))
# ### Selection area on canvas section ###
dx = pos[0] - self.pos[0]
@ -3837,6 +3870,14 @@ class FlatCAMGeoEditor(QtCore.QObject):
else:
self.app.selection_type = None
def update_utility_geometry(self, data):
# ### Utility geometry (animated) ###
geo = self.active_tool.utility_geometry(data=data)
if isinstance(geo, DrawToolShape) and geo.geo is not None:
# Remove any previous utility shape
self.tool_shape.clear(update=True)
self.draw_utility_geometry(geo=geo)
def on_geo_click_release(self, event):
if self.app.is_legacy is False:
event_pos = event.pos

View File

@ -4530,13 +4530,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
self.app.ui.rel_position_label.setText("<b>Dx</b>: %.4f&nbsp;&nbsp; <b>Dy</b>: "
"%.4f&nbsp;&nbsp;&nbsp;&nbsp;" % (dx, dy))
# # ## Utility geometry (animated)
geo = self.active_tool.utility_geometry(data=(x, y))
if isinstance(geo, DrawToolShape) and geo.geo is not None:
# Remove any previous utility shape
self.tool_shape.clear(update=True)
self.draw_utility_geometry(geo=geo)
self.update_utility_geometry(data=(x, y))
# # ## Selection area on canvas section # ##
if event_is_dragging == 1 and event.button == 1:
@ -4558,6 +4552,15 @@ class FlatCAMGrbEditor(QtCore.QObject):
else:
self.app.selection_type = None
def update_utility_geometry(self, data):
# # ## Utility geometry (animated)
geo = self.active_tool.utility_geometry(data=data)
if isinstance(geo, DrawToolShape) and geo.geo is not None:
# Remove any previous utility shape
self.tool_shape.clear(update=True)
self.draw_utility_geometry(geo=geo)
def draw_utility_geometry(self, geo):
if type(geo.geo) == list:
for el in geo.geo:

View File

@ -8,6 +8,12 @@
from flatcamGUI.GUIElements import *
from PyQt5 import QtPrintSupport
from reportlab.platypus import SimpleDocTemplate, Paragraph
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.units import inch, mm
from io import StringIO
import gettext
import FlatCAMTranslation as fcTranslate
import builtins
@ -217,9 +223,38 @@ class TextEditor(QtWidgets.QWidget):
else:
try:
my_gcode = self.code_editor.toPlainText()
with open(filename, 'w') as f:
for line in my_gcode:
f.write(line)
if filename.rpartition('.')[2].lower() == 'pdf':
page_size = (
self.app.plotcanvas.pagesize_dict[self.app.defaults['global_workspaceT']][0] * mm,
self.app.plotcanvas.pagesize_dict[self.app.defaults['global_workspaceT']][1] * mm
)
# add new line after each line
lined_gcode = my_gcode.replace("\n", "<br />")
styles = getSampleStyleSheet()
styleN = styles['Normal']
styleH = styles['Heading1']
story = []
doc = SimpleDocTemplate(
filename,
pagesize=page_size,
bottomMargin=0.4 * inch,
topMargin=0.6 * inch,
rightMargin=0.8 * inch,
leftMargin=0.8 * inch)
P = Paragraph(lined_gcode, styleN)
story.append(P)
doc.build(
story,
)
else:
with open(filename, 'w') as f:
for line in my_gcode:
f.write(line)
except FileNotFoundError:
self.app.inform.emit('[WARNING] %s' % _("No such file or directory"))
return

View File

@ -21,8 +21,16 @@ import re
import logging
import html
import gettext
import FlatCAMTranslation as fcTranslate
import builtins
log = logging.getLogger('base')
fcTranslate.apply_language('strings')
if '_' not in builtins.__dict__:
_ = gettext.gettext
EDIT_SIZE_HINT = 70
@ -624,7 +632,7 @@ class FCDoubleSpinner(QtWidgets.QDoubleSpinBox):
# by default don't allow the minus sign to be entered as the default for QDoubleSpinBox is the positive range
# between 0.00 and 99.00 (2 decimals)
self.lineEdit().setValidator(
QtGui.QRegExpValidator(QtCore.QRegExp("[0-9]*[.,]?[0-9]{%d}" % self.decimals()), self))
QtGui.QRegExpValidator(QtCore.QRegExp("\+?[0-9]*[.,]?[0-9]{%d}" % self.decimals()), self))
if suffix:
self.setSuffix(' %s' % str(suffix))
@ -710,15 +718,15 @@ class FCDoubleSpinner(QtWidgets.QDoubleSpinBox):
self.setDecimals(val)
# make sure that the user can't type more decimals than the set precision
if self.minimum() < 0 or self.maximum() < 0:
if self.minimum() < 0 or self.maximum() <= 0:
self.lineEdit().setValidator(
QtGui.QRegExpValidator(QtCore.QRegExp("-?[0-9]*[.,]?[0-9]{%d}" % self.decimals()), self))
else:
self.lineEdit().setValidator(
QtGui.QRegExpValidator(QtCore.QRegExp("[0-9]*[.,]?[0-9]{%d}" % self.decimals()), self))
QtGui.QRegExpValidator(QtCore.QRegExp("\+?[0-9]*[.,]?[0-9]{%d}" % self.decimals()), self))
def set_range(self, min_val, max_val):
if min_val < 0 or max_val < 0:
if min_val < 0 or max_val <= 0:
self.lineEdit().setValidator(
QtGui.QRegExpValidator(QtCore.QRegExp("-?[0-9]*[.,]?[0-9]{%d}" % self.decimals()), self))
@ -2230,6 +2238,72 @@ class Dialog_box(QtWidgets.QWidget):
self.readyToEdit = True
class DialogBoxRadio(QtWidgets.QDialog):
def __init__(self, title=None, label=None, icon=None, initial_text=None):
"""
:param title: string with the window title
:param label: string with the message inside the dialog box
"""
super(DialogBoxRadio, self).__init__()
if initial_text is None:
self.location = str((0, 0))
else:
self.location = initial_text
self.ok = False
self.setWindowIcon(icon)
self.setWindowTitle(str(title))
self.form = QtWidgets.QFormLayout(self)
self.form.addRow(QtWidgets.QLabel(''))
self.wdg_label = QtWidgets.QLabel('<b>%s</b>' % str(label))
self.form.addRow(self.wdg_label)
self.ref_label = QtWidgets.QLabel('%s:' % _("Reference"))
self.ref_label.setToolTip(
_("The reference can be:\n"
"- Absolute -> the reference point is point (0,0)\n"
"- Relative -> the reference point is the mouse position before Jump")
)
self.ref_radio = RadioSet([
{"label": _("Abs"), "value": "abs"},
{"label": _("Relative"), "value": "rel"}
], orientation='horizontal', stretch=False)
self.ref_radio.set_value('abs')
self.form.addRow(self.ref_label, self.ref_radio)
self.loc_label = QtWidgets.QLabel('<b>%s:</b>' % _("Location"))
self.loc_label.setToolTip(
_("The Location value is a tuple (x,y).\n"
"If the reference is Absolute then the Jump will be at the position (x,y).\n"
"If the reference is Relative then the Jump will be at the (x,y) distance\n"
"from the current mouse location point.")
)
self.lineEdit = EvalEntry()
self.lineEdit.setText(str(self.location).replace('(', '').replace(')', ''))
self.form.addRow(self.loc_label, self.lineEdit)
self.button_box = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel,
Qt.Horizontal, parent=self)
self.form.addRow(self.button_box)
self.button_box.accepted.connect(self.accept)
self.button_box.rejected.connect(self.reject)
self.readyToEdit = True
if self.exec_() == QtWidgets.QDialog.Accepted:
self.ok = True
self.location = self.lineEdit.text()
self.reference = self.ref_radio.get_value()
else:
self.ok = False
class _BrowserTextEdit(QTextEdit):
def __init__(self, version):

View File

@ -348,7 +348,7 @@ class GerberObjectUI(ObjectUI):
"below the copper surface.")
)
self.cutz_spinner = FCDoubleSpinner()
self.cutz_spinner.set_range(-9999.9999, -0.0001)
self.cutz_spinner.set_range(-9999.9999, 0.0000)
self.cutz_spinner.set_precision(self.decimals)
self.cutz_spinner.setSingleStep(0.1)
self.cutz_spinner.setWrapping(True)
@ -381,7 +381,7 @@ class GerberObjectUI(ObjectUI):
)
passlabel.setMinimumWidth(90)
self.iso_width_entry = FCSpinner()
self.iso_width_entry.setRange(1, 999)
self.iso_width_entry.set_range(1, 999)
grid1.addWidget(passlabel, 5, 0)
grid1.addWidget(self.iso_width_entry, 5, 1, 1, 2)
@ -394,7 +394,7 @@ class GerberObjectUI(ObjectUI):
self.iso_overlap_entry = FCDoubleSpinner(suffix='%')
self.iso_overlap_entry.set_precision(self.decimals)
self.iso_overlap_entry.setWrapping(True)
self.iso_overlap_entry.setRange(0.0000, 99.9999)
self.iso_overlap_entry.set_range(0.0000, 99.9999)
self.iso_overlap_entry.setSingleStep(0.1)
grid1.addWidget(overlabel, 6, 0)
grid1.addWidget(self.iso_overlap_entry, 6, 1, 1, 2)
@ -827,9 +827,9 @@ class ExcellonObjectUI(ObjectUI):
self.cutz_entry.set_precision(self.decimals)
if machinist_setting == 0:
self.cutz_entry.setRange(-9999.9999, -0.000001)
self.cutz_entry.set_range(-9999.9999, 0.0000)
else:
self.cutz_entry.setRange(-9999.9999, 9999.9999)
self.cutz_entry.set_range(-9999.9999, 9999.9999)
self.cutz_entry.setSingleStep(0.1)
@ -846,9 +846,9 @@ class ExcellonObjectUI(ObjectUI):
self.travelz_entry.set_precision(self.decimals)
if machinist_setting == 0:
self.travelz_entry.setRange(0.00001, 9999.9999)
self.travelz_entry.set_range(0.00001, 9999.9999)
else:
self.travelz_entry.setRange(-9999.9999, 9999.9999)
self.travelz_entry.set_range(-9999.9999, 9999.9999)
self.travelz_entry.setSingleStep(0.1)
@ -873,9 +873,9 @@ class ExcellonObjectUI(ObjectUI):
self.toolchangez_entry.set_precision(self.decimals)
if machinist_setting == 0:
self.toolchangez_entry.setRange(0.0, 9999.9999)
self.toolchangez_entry.set_range(0.0, 9999.9999)
else:
self.toolchangez_entry.setRange(-9999.9999, 9999.9999)
self.toolchangez_entry.set_range(-9999.9999, 9999.9999)
self.toolchangez_entry.setSingleStep(0.1)
@ -883,7 +883,7 @@ class ExcellonObjectUI(ObjectUI):
self.ois_tcz_e = OptionalInputSection(self.toolchange_cb, [self.toolchangez_entry])
# Start move Z:
self.estartz_label = QtWidgets.QLabel('%s:' % _("Start move Z"))
self.estartz_label = QtWidgets.QLabel('%s:' % _("Start Z"))
self.estartz_label.setToolTip(
_("Height of the tool just after start.\n"
"Delete the value if you don't need this feature.")
@ -903,9 +903,9 @@ class ExcellonObjectUI(ObjectUI):
self.eendz_entry.set_precision(self.decimals)
if machinist_setting == 0:
self.eendz_entry.setRange(0.0, 9999.9999)
self.eendz_entry.set_range(0.0, 9999.9999)
else:
self.eendz_entry.setRange(-9999.9999, 9999.9999)
self.eendz_entry.set_range(-9999.9999, 9999.9999)
self.eendz_entry.setSingleStep(0.1)
@ -922,7 +922,7 @@ class ExcellonObjectUI(ObjectUI):
grid1.addWidget(frlabel, 6, 0)
self.feedrate_entry = FCDoubleSpinner()
self.feedrate_entry.set_precision(self.decimals)
self.feedrate_entry.setRange(0.0, 9999.9999)
self.feedrate_entry.set_range(0.0, 9999.9999)
self.feedrate_entry.setSingleStep(0.1)
grid1.addWidget(self.feedrate_entry, 6, 1)
@ -939,7 +939,7 @@ class ExcellonObjectUI(ObjectUI):
grid1.addWidget(self.feedrate_rapid_label, 7, 0)
self.feedrate_rapid_entry = FCDoubleSpinner()
self.feedrate_rapid_entry.set_precision(self.decimals)
self.feedrate_rapid_entry.setRange(0.0, 9999.9999)
self.feedrate_rapid_entry.set_range(0.0, 9999.9999)
self.feedrate_rapid_entry.setSingleStep(0.1)
grid1.addWidget(self.feedrate_rapid_entry, 7, 1)
@ -967,7 +967,7 @@ class ExcellonObjectUI(ObjectUI):
)
self.dwelltime_entry = FCDoubleSpinner()
self.dwelltime_entry.set_precision(self.decimals)
self.dwelltime_entry.setRange(0.0, 9999.9999)
self.dwelltime_entry.set_range(0.0, 9999.9999)
self.dwelltime_entry.setSingleStep(0.1)
self.dwelltime_entry.setToolTip(
@ -998,7 +998,7 @@ class ExcellonObjectUI(ObjectUI):
grid1.addWidget(self.pdepth_label, 11, 0)
self.pdepth_entry = FCDoubleSpinner()
self.pdepth_entry.set_precision(self.decimals)
self.pdepth_entry.setRange(-9999.9999, 9999.9999)
self.pdepth_entry.set_range(-9999.9999, 9999.9999)
self.pdepth_entry.setSingleStep(0.1)
grid1.addWidget(self.pdepth_entry, 11, 1)
@ -1013,7 +1013,7 @@ class ExcellonObjectUI(ObjectUI):
self.feedrate_probe_entry = FCDoubleSpinner()
self.feedrate_probe_entry.set_precision(self.decimals)
self.feedrate_probe_entry.setRange(0.0, 9999.9999)
self.feedrate_probe_entry.set_range(0.0, 9999.9999)
self.feedrate_probe_entry.setSingleStep(0.1)
grid1.addWidget(self.feedrate_probe_label, 12, 0)
@ -1077,7 +1077,7 @@ class ExcellonObjectUI(ObjectUI):
)
self.tooldia_entry = FCDoubleSpinner()
self.tooldia_entry.set_precision(self.decimals)
self.tooldia_entry.setRange(0.0, 9999.9999)
self.tooldia_entry.set_range(0.0, 9999.9999)
self.tooldia_entry.setSingleStep(0.1)
self.generate_milling_button = QtWidgets.QPushButton(_('Mill Drills Geo'))
@ -1104,7 +1104,7 @@ class ExcellonObjectUI(ObjectUI):
self.slot_tooldia_entry = FCDoubleSpinner()
self.slot_tooldia_entry.set_precision(self.decimals)
self.slot_tooldia_entry.setRange(0.0, 9999.9999)
self.slot_tooldia_entry.set_range(0.0, 9999.9999)
self.slot_tooldia_entry.setSingleStep(0.1)
self.generate_milling_slots_button = QtWidgets.QPushButton(_('Mill Slots Geo'))
@ -1286,7 +1286,7 @@ class GeometryObjectUI(ObjectUI):
)
self.tool_offset_entry = FCDoubleSpinner()
self.tool_offset_entry.set_precision(self.decimals)
self.tool_offset_entry.setRange(-9999.9999, 9999.9999)
self.tool_offset_entry.set_range(-9999.9999, 9999.9999)
self.tool_offset_entry.setSingleStep(0.1)
self.grid1.addWidget(self.tool_offset_lbl, 0, 0)
@ -1298,7 +1298,7 @@ class GeometryObjectUI(ObjectUI):
)
self.addtool_entry = FCDoubleSpinner()
self.addtool_entry.set_precision(self.decimals)
self.addtool_entry.setRange(0.00001, 9999.9999)
self.addtool_entry.set_range(0.00001, 9999.9999)
self.addtool_entry.setSingleStep(0.1)
self.addtool_btn = QtWidgets.QPushButton(_('Add'))
@ -1379,7 +1379,7 @@ class GeometryObjectUI(ObjectUI):
)
self.tipdia_entry = FCDoubleSpinner()
self.tipdia_entry.set_precision(self.decimals)
self.tipdia_entry.setRange(0.00001, 9999.9999)
self.tipdia_entry.set_range(0.00001, 9999.9999)
self.tipdia_entry.setSingleStep(0.1)
self.grid3.addWidget(self.tipdialabel, 1, 0)
@ -1395,7 +1395,7 @@ class GeometryObjectUI(ObjectUI):
)
self.tipangle_entry = FCDoubleSpinner()
self.tipangle_entry.set_precision(self.decimals)
self.tipangle_entry.setRange(0.0, 180.0)
self.tipangle_entry.set_range(0.0, 180.0)
self.tipangle_entry.setSingleStep(1)
self.grid3.addWidget(self.tipanglelabel, 2, 0)
@ -1413,9 +1413,9 @@ class GeometryObjectUI(ObjectUI):
self.cutz_entry.set_precision(self.decimals)
if machinist_setting == 0:
self.cutz_entry.setRange(-9999.9999, -0.00001)
self.cutz_entry.set_range(-9999.9999, 0.0000)
else:
self.cutz_entry.setRange(-9999.9999, 9999.9999)
self.cutz_entry.set_range(-9999.9999, 9999.9999)
self.cutz_entry.setSingleStep(0.1)
@ -1435,7 +1435,7 @@ class GeometryObjectUI(ObjectUI):
self.maxdepth_entry = FCDoubleSpinner()
self.maxdepth_entry.set_precision(self.decimals)
self.maxdepth_entry.setRange(0, 9999.9999)
self.maxdepth_entry.set_range(0, 9999.9999)
self.maxdepth_entry.setSingleStep(0.1)
self.maxdepth_entry.setToolTip(
@ -1458,9 +1458,9 @@ class GeometryObjectUI(ObjectUI):
self.travelz_entry.set_precision(self.decimals)
if machinist_setting == 0:
self.travelz_entry.setRange(0.00001, 9999.9999)
self.travelz_entry.set_range(0.00001, 9999.9999)
else:
self.travelz_entry.setRange(-9999.9999, 9999.9999)
self.travelz_entry.set_range(-9999.9999, 9999.9999)
self.travelz_entry.setSingleStep(0.1)
@ -1486,9 +1486,9 @@ class GeometryObjectUI(ObjectUI):
self.toolchangez_entry.set_precision(self.decimals)
if machinist_setting == 0:
self.toolchangez_entry.setRange(0, 9999.9999)
self.toolchangez_entry.set_range(0, 9999.9999)
else:
self.toolchangez_entry.setRange(-9999.9999, 9999.9999)
self.toolchangez_entry.set_range(-9999.9999, 9999.9999)
self.toolchangez_entry.setSingleStep(0.1)
@ -1518,9 +1518,9 @@ class GeometryObjectUI(ObjectUI):
self.gendz_entry.set_precision(self.decimals)
if machinist_setting == 0:
self.gendz_entry.setRange(0, 9999.9999)
self.gendz_entry.set_range(0, 9999.9999)
else:
self.gendz_entry.setRange(-9999.9999, 9999.9999)
self.gendz_entry.set_range(-9999.9999, 9999.9999)
self.gendz_entry.setSingleStep(0.1)
@ -1535,7 +1535,7 @@ class GeometryObjectUI(ObjectUI):
)
self.cncfeedrate_entry = FCDoubleSpinner()
self.cncfeedrate_entry.set_precision(self.decimals)
self.cncfeedrate_entry.setRange(0, 9999.9999)
self.cncfeedrate_entry.set_range(0, 9999.9999)
self.cncfeedrate_entry.setSingleStep(0.1)
self.grid3.addWidget(frlabel, 10, 0)
@ -1550,7 +1550,7 @@ class GeometryObjectUI(ObjectUI):
)
self.cncplunge_entry = FCDoubleSpinner()
self.cncplunge_entry.set_precision(self.decimals)
self.cncplunge_entry.setRange(0, 9999.9999)
self.cncplunge_entry.set_range(0, 9999.9999)
self.cncplunge_entry.setSingleStep(0.1)
self.grid3.addWidget(frzlabel, 11, 0)
@ -1567,7 +1567,7 @@ class GeometryObjectUI(ObjectUI):
)
self.cncfeedrate_rapid_entry = FCDoubleSpinner()
self.cncfeedrate_rapid_entry.set_precision(self.decimals)
self.cncfeedrate_rapid_entry.setRange(0, 9999.9999)
self.cncfeedrate_rapid_entry.set_range(0, 9999.9999)
self.cncfeedrate_rapid_entry.setSingleStep(0.1)
self.grid3.addWidget(self.fr_rapidlabel, 12, 0)
@ -1627,7 +1627,7 @@ class GeometryObjectUI(ObjectUI):
)
self.dwelltime_entry = FCDoubleSpinner()
self.dwelltime_entry.set_precision(self.decimals)
self.dwelltime_entry.setRange(0, 9999.9999)
self.dwelltime_entry.set_range(0, 9999.9999)
self.dwelltime_entry.setSingleStep(0.1)
self.dwelltime_entry.setToolTip(
@ -1658,7 +1658,7 @@ class GeometryObjectUI(ObjectUI):
)
self.pdepth_entry = FCDoubleSpinner()
self.pdepth_entry.set_precision(self.decimals)
self.pdepth_entry.setRange(-9999.9999, 9999.9999)
self.pdepth_entry.set_range(-9999.9999, 9999.9999)
self.pdepth_entry.setSingleStep(0.1)
self.grid3.addWidget(self.pdepth_label, 17, 0)
@ -1674,7 +1674,7 @@ class GeometryObjectUI(ObjectUI):
)
self.feedrate_probe_entry = FCDoubleSpinner()
self.feedrate_probe_entry.set_precision(self.decimals)
self.feedrate_probe_entry.setRange(0.0, 9999.9999)
self.feedrate_probe_entry.set_range(0.0, 9999.9999)
self.feedrate_probe_entry.setSingleStep(0.1)
self.grid3.addWidget(self.feedrate_probe_label, 18, 0)

View File

@ -1682,7 +1682,7 @@ class GerberAdvOptPrefGroupUI(OptionsGroupUI):
)
self.cutz_spinner = FCDoubleSpinner()
self.cutz_spinner.set_precision(self.decimals)
self.cutz_spinner.set_range(-99.9999, -0.0001)
self.cutz_spinner.set_range(-99.9999, 0.0000)
self.cutz_spinner.setSingleStep(0.1)
self.cutz_spinner.setWrapping(True)
@ -2352,7 +2352,7 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
self.cutz_entry = FCDoubleSpinner()
if machinist_setting == 0:
self.cutz_entry.set_range(-9999.9999, -0.000001)
self.cutz_entry.set_range(-9999.9999, 0.0000)
else:
self.cutz_entry.set_range(-9999.9999, 9999.9999)
@ -2584,7 +2584,7 @@ class ExcellonAdvOptPrefGroupUI(OptionsGroupUI):
self.toolchangexy_entry = FCEntry()
grid1.addWidget(self.toolchangexy_entry, 1, 1)
startzlabel = QtWidgets.QLabel('%s:' % _('Start move Z'))
startzlabel = QtWidgets.QLabel('%s:' % _('Start Z'))
startzlabel.setToolTip(
_("Height of the tool just after start.\n"
"Delete the value if you don't need this feature.")
@ -2617,7 +2617,7 @@ class ExcellonAdvOptPrefGroupUI(OptionsGroupUI):
)
self.pdepth_entry = FCDoubleSpinner()
self.pdepth_entry.set_precision(self.decimals)
self.pdepth_entry.set_range(-99999, -0.000001)
self.pdepth_entry.set_range(-99999.9999, 0.0000)
grid1.addWidget(self.pdepth_label, 4, 0)
grid1.addWidget(self.pdepth_entry, 4, 1)
@ -3196,7 +3196,7 @@ class GeometryOptPrefGroupUI(OptionsGroupUI):
self.cutz_entry = FCDoubleSpinner()
if machinist_setting == 0:
self.cutz_entry.set_range(-9999.9999, -0.000001)
self.cutz_entry.set_range(-9999.9999, 0.0000)
else:
self.cutz_entry.set_range(-9999.9999, 9999.9999)
@ -3429,7 +3429,7 @@ class GeometryAdvOptPrefGroupUI(OptionsGroupUI):
grid1.addWidget(self.toolchangexy_entry, 1, 1)
# Start move Z
startzlabel = QtWidgets.QLabel('%s:' % _('Start move Z'))
startzlabel = QtWidgets.QLabel('%s:' % _('Start Z'))
startzlabel.setToolTip(
_("Height of the tool just after starting the work.\n"
"Delete the value if you don't need this feature.")
@ -3486,7 +3486,7 @@ class GeometryAdvOptPrefGroupUI(OptionsGroupUI):
"to probe. Negative value, in current units.")
)
self.pdepth_entry = FCDoubleSpinner()
self.pdepth_entry.set_range(-99999, -0.000001)
self.pdepth_entry.set_range(-99999, 0.0000)
self.pdepth_entry.set_precision(self.decimals)
self.pdepth_entry.setSingleStep(0.1)
self.pdepth_entry.setWrapping(True)
@ -4052,7 +4052,7 @@ class ToolsNCCPrefGroupUI(OptionsGroupUI):
)
self.cutz_entry = FCDoubleSpinner()
self.cutz_entry.set_precision(self.decimals)
self.cutz_entry.set_range(-9999.9999, -0.000001)
self.cutz_entry.set_range(-9999.9999, 0.0000)
self.cutz_entry.setSingleStep(0.1)
self.cutz_entry.setToolTip(
@ -4310,7 +4310,7 @@ class ToolsCutoutPrefGroupUI(OptionsGroupUI):
self.cutz_entry.set_precision(self.decimals)
if machinist_setting == 0:
self.cutz_entry.setRange(-9999.9999, -0.00001)
self.cutz_entry.setRange(-9999.9999, 0.0000)
else:
self.cutz_entry.setRange(-9999.9999, 9999.9999)
@ -5119,7 +5119,7 @@ class ToolsCalculatorsPrefGroupUI(OptionsGroupUI):
# ## Depth-of-cut Cut Z
self.cut_z_entry = FCDoubleSpinner()
self.cut_z_entry.set_range(-9999.9999, -0.00001)
self.cut_z_entry.set_range(-9999.9999, 0.0000)
self.cut_z_entry.set_precision(self.decimals)
self.cut_z_entry.setSingleStep(0.01)

View File

@ -111,9 +111,9 @@ class HPGL2:
self.initialize_re = re.compile(r'^(IN);?$')
# Absolute linear interpolation
self.abs_move_re = re.compile(r"^PA\s*(-?\d+\.?\d+?),?\s*(-?\d+\.?\d+?)*;?$")
self.abs_move_re = re.compile(r"^PA\s*(-?\d+\.?\d*),?\s*(-?\d+\.?\d*)*;?$")
# Relative linear interpolation
self.rel_move_re = re.compile(r"^PR\s*(-?\d+\.\d+?),?\s*(-?\d+\.\d+?)*;?$")
self.rel_move_re = re.compile(r"^PR\s*(-?\d+\.?\d*),?\s*(-?\d+\.?\d*)*;?$")
# Circular interpolation with radius
self.circ_re = re.compile(r"^CI\s*(\+?\d+\.?\d+?)?\s*;?\s*$")

View File

@ -258,7 +258,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
)
self.cutz_entry = FCDoubleSpinner()
self.cutz_entry.set_precision(self.decimals)
self.cutz_entry.set_range(-99999, -0.00000000000001)
self.cutz_entry.set_range(-99999.9999, 0.0000)
self.cutz_entry.setToolTip(
_("Depth of cut into material. Negative value.\n"
@ -1810,8 +1810,43 @@ class NonCopperClear(FlatCAMTool, Gerber):
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
if p is not None:
# clean the polygon
p = p.buffer(0)
if p is not None and p.is_valid:
poly_processed = list()
try:
for pol in p:
if pol is not None and isinstance(pol, Polygon):
if ncc_method == 'standard':
cp = self.clear_polygon(pol, tool,
self.grb_circle_steps,
overlap=overlap, contour=contour,
connect=connect,
prog_plot=prog_plot)
elif ncc_method == 'seed':
cp = self.clear_polygon2(pol, tool,
self.grb_circle_steps,
overlap=overlap, contour=contour,
connect=connect,
prog_plot=prog_plot)
else:
cp = self.clear_polygon3(pol, tool,
self.grb_circle_steps,
overlap=overlap, contour=contour,
connect=connect,
prog_plot=prog_plot)
if cp:
cleared_geo += list(cp.get_objects())
poly_processed.append(True)
else:
poly_processed.append(False)
log.warning("Polygon in MultiPolygon can not be cleared.")
else:
log.warning("Geo in Iterable can not be cleared beacuse it is not Polygon. "
"It is: %s" % str(type(pol)))
except TypeError:
if isinstance(p, Polygon):
if ncc_method == 'standard':
cp = self.clear_polygon(p, tool, self.grb_circle_steps,
@ -1827,32 +1862,20 @@ class NonCopperClear(FlatCAMTool, Gerber):
prog_plot=prog_plot)
if cp:
cleared_geo += list(cp.get_objects())
elif isinstance(p, MultiPolygon):
for pol in p:
if pol is not None:
if ncc_method == 'standard':
cp = self.clear_polygon(pol, tool,
self.grb_circle_steps,
overlap=overlap, contour=contour,
connect=connect,
prog_plot=prog_plot)
elif ncc_method == 'seed':
cp = self.clear_polygon2(pol, tool,
self.grb_circle_steps,
overlap=overlap, contour=contour,
connect=connect,
prog_plot=prog_plot)
else:
cp = self.clear_polygon3(pol, tool,
self.grb_circle_steps,
overlap=overlap, contour=contour,
connect=connect,
prog_plot=prog_plot)
if cp:
cleared_geo += list(cp.get_objects())
except Exception as e:
log.warning("Polygon can not be cleared. %s" % str(e))
poly_processed.append(True)
else:
poly_processed.append(False)
log.warning("Polygon can not be cleared.")
else:
log.warning("Geo can not be cleared because it is: %s" % str(type(p)))
p_cleared = poly_processed.count(True)
p_not_cleared = poly_processed.count(False)
if p_not_cleared:
app_obj.poly_not_cleared = True
if p_cleared == 0:
continue
pol_nr += 1
@ -2182,7 +2205,10 @@ class NonCopperClear(FlatCAMTool, Gerber):
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
if p is not None:
# clean the polygon
p = p.buffer(0)
if p is not None and p.is_valid:
# provide the app with a way to process the GUI events when in a blocking loop
QtWidgets.QApplication.processEvents()

View File

@ -1450,8 +1450,7 @@ class ToolPaint(FlatCAMTool, Gerber):
geo_obj.solid_geometry += list(cpoly.get_objects())
return cpoly
else:
app_obj.inform.emit('[ERROR_NOTCL] %s' %
_('Geometry could not be painted completely'))
app_obj.inform.emit('[ERROR_NOTCL] %s' % _('Geometry could not be painted completely'))
return None
current_uid = int(1)
@ -1769,62 +1768,162 @@ class ToolPaint(FlatCAMTool, Gerber):
pol_nr = 0
for geo in painted_area:
try:
# Polygons are the only really paintable geometries, lines in theory have no area to be painted
if not isinstance(geo, Polygon):
# provide the app with a way to process the GUI events when in a blocking loop
QtWidgets.QApplication.processEvents()
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
# try to clean the Polygon but it may result into a MultiPolygon
geo = geo.buffer(0)
poly_buf = geo.buffer(-paint_margin)
if geo is not None and geo.is_valid:
poly_processed = list()
try:
for pol in poly_buf:
if pol is not None and isinstance(pol, Polygon):
if paint_method == 'standard':
cp = self.clear_polygon(pol,
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
"geometry_circle_steps"],
overlap=over,
contour=cont,
connect=conn,
prog_plot=prog_plot)
elif paint_method == 'seed':
cp = self.clear_polygon2(pol,
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
"geometry_circle_steps"],
overlap=over,
contour=cont,
connect=conn,
prog_plot=prog_plot)
else:
cp = self.clear_polygon3(pol,
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
"geometry_circle_steps"],
overlap=over,
contour=cont,
connect=conn,
prog_plot=prog_plot)
if cp:
total_geometry += list(cp.get_objects())
poly_processed.append(True)
else:
poly_processed.append(False)
log.warning("Polygon in MultiPolygon can not be cleared.")
else:
log.warning("Geo in Iterable can not be cleared because it is not Polygon. "
"It is: %s" % str(type(pol)))
except TypeError:
if isinstance(poly_buf, Polygon):
if paint_method == 'standard':
cp = self.clear_polygon(poly_buf,
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
"geometry_circle_steps"],
overlap=over,
contour=cont,
connect=conn,
prog_plot=prog_plot)
elif paint_method == 'seed':
cp = self.clear_polygon2(poly_buf,
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
"geometry_circle_steps"],
overlap=over,
contour=cont,
connect=conn,
prog_plot=prog_plot)
else:
cp = self.clear_polygon3(poly_buf,
tooldia=tool_dia,
steps_per_circle=self.app.defaults[
"geometry_circle_steps"],
overlap=over,
contour=cont,
connect=conn,
prog_plot=prog_plot)
if cp:
total_geometry += list(cp.get_objects())
poly_processed.append(True)
else:
poly_processed.append(False)
log.warning("Polygon can not be cleared.")
else:
log.warning("Geo can not be cleared because it is: %s" % str(type(poly_buf)))
p_cleared = poly_processed.count(True)
p_not_cleared = poly_processed.count(False)
if p_not_cleared:
app_obj.poly_not_cleared = True
if p_cleared == 0:
continue
poly_buf = geo.buffer(-paint_margin)
if paint_method == "seed":
# Type(cp) == FlatCAMRTreeStorage | None
cp = self.clear_polygon2(poly_buf,
tooldia=tool_dia,
steps_per_circle=self.app.defaults["geometry_circle_steps"],
overlap=over,
contour=cont,
connect=conn,
prog_plot=prog_plot)
# try:
# # Polygons are the only really paintable geometries, lines in theory have no area to be painted
# if not isinstance(geo, Polygon):
# continue
# poly_buf = geo.buffer(-paint_margin)
#
# if paint_method == "seed":
# # Type(cp) == FlatCAMRTreeStorage | None
# cp = self.clear_polygon2(poly_buf,
# tooldia=tool_dia,
# steps_per_circle=self.app.defaults["geometry_circle_steps"],
# overlap=over,
# contour=cont,
# connect=conn,
# prog_plot=prog_plot)
#
# elif paint_method == "lines":
# # Type(cp) == FlatCAMRTreeStorage | None
# cp = self.clear_polygon3(poly_buf,
# tooldia=tool_dia,
# steps_per_circle=self.app.defaults["geometry_circle_steps"],
# overlap=over,
# contour=cont,
# connect=conn,
# prog_plot=prog_plot)
#
# else:
# # Type(cp) == FlatCAMRTreeStorage | None
# cp = self.clear_polygon(poly_buf,
# tooldia=tool_dia,
# steps_per_circle=self.app.defaults["geometry_circle_steps"],
# overlap=over,
# contour=cont,
# connect=conn,
# prog_plot=prog_plot)
#
# if cp is not None:
# total_geometry += list(cp.get_objects())
# except FlatCAMApp.GracefulException:
# return "fail"
# except Exception as e:
# log.debug("Could not Paint the polygons. %s" % str(e))
# self.app.inform.emit('[ERROR] %s\n%s' %
# (_("Could not do Paint All. Try a different combination of parameters. "
# "Or a different Method of paint"),
# str(e)))
# return "fail"
elif paint_method == "lines":
# Type(cp) == FlatCAMRTreeStorage | None
cp = self.clear_polygon3(poly_buf,
tooldia=tool_dia,
steps_per_circle=self.app.defaults["geometry_circle_steps"],
overlap=over,
contour=cont,
connect=conn,
prog_plot=prog_plot)
pol_nr += 1
disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 100]))
# log.debug("Polygons cleared: %d" % pol_nr)
else:
# Type(cp) == FlatCAMRTreeStorage | None
cp = self.clear_polygon(poly_buf,
tooldia=tool_dia,
steps_per_circle=self.app.defaults["geometry_circle_steps"],
overlap=over,
contour=cont,
connect=conn,
prog_plot=prog_plot)
if cp is not None:
total_geometry += list(cp.get_objects())
except FlatCAMApp.GracefulException:
return "fail"
except Exception as e:
log.debug("Could not Paint the polygons. %s" % str(e))
self.app.inform.emit('[ERROR] %s\n%s' %
(_("Could not do Paint All. Try a different combination of parameters. "
"Or a different Method of paint"),
str(e)))
return "fail"
pol_nr += 1
disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 100]))
# log.debug("Polygons cleared: %d" % pol_nr)
if old_disp_number < disp_number <= 100:
app_obj.proc_container.update_view_text(' %d%%' % disp_number)
old_disp_number = disp_number
# log.debug("Polygons cleared: %d. Percentage done: %d%%" % (pol_nr, disp_number))
if old_disp_number < disp_number <= 100:
app_obj.proc_container.update_view_text(' %d%%' % disp_number)
old_disp_number = disp_number
# log.debug("Polygons cleared: %d. Percentage done: %d%%" % (pol_nr, disp_number))
# add the solid_geometry to the current too in self.paint_tools (tools_storage)
# dictionary and then reset the temporary list that stored that solid_geometry
@ -1837,17 +1936,24 @@ class ToolPaint(FlatCAMTool, Gerber):
if self.app.defaults["tools_paint_plotting"] == 'progressive':
self.temp_shapes.clear(update=True)
# # delete tools with empty geometry
# keys_to_delete = []
# # look for keys in the tools_storage dict that have 'solid_geometry' values empty
# for uid in tools_storage:
# # if the solid_geometry (type=list) is empty
# if not tools_storage[uid]['solid_geometry']:
# keys_to_delete.append(uid)
#
# # actual delete of keys from the tools_storage dict
# for k in keys_to_delete:
# tools_storage.pop(k, None)
# delete tools with empty geometry
keys_to_delete = []
# look for keys in the tools_storage dict that have 'solid_geometry' values empty
for uid in tools_storage:
for uid in list(tools_storage.keys()):
# if the solid_geometry (type=list) is empty
if not tools_storage[uid]['solid_geometry']:
keys_to_delete.append(uid)
# actual delete of keys from the tools_storage dict
for k in keys_to_delete:
tools_storage.pop(k, None)
tools_storage.pop(uid, None)
geo_obj.options["cnctooldia"] = str(tool_dia)
# this turn on the FlatCAMCNCJob plot for multiple tools

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -14,6 +14,8 @@ from FlatCAMPostProc import *
class Berta_CNC(FlatCAMPostProc):
include_header = True
coordinate_format = "%.*f"
feedrate_format = '%.*f'
@ -66,18 +68,19 @@ class Berta_CNC(FlatCAMPostProc):
gcode += '(Spindle Speed: %s RPM)\n' % str(p['spindlespeed'])
gcode += '(Berta)\n'
gcode += 'G90 G94 G17 G91.1'
gcode += (
# This line allow you to sets the machine to METRIC / INCH in the GUI
'G20\n' if p.units.upper() == 'IN' else 'G21\n')
'G20\n' if p.units.upper() == 'IN' else 'G21\n') + '\n'
# gcode += 'G21\n' # This line sets the machine to METRIC ONLY
# gcode += 'G20\n' # This line sets the machine to INCH ONLY
gcode += 'G90 G17 G91.1\n'
gcode += 'G64 P0.03\n'
gcode += 'M110\n'
gcode += 'G54\n'
gcode += 'G0\n'
gcode += '(Berta)\n'
gcode += 'G94\n'
return gcode
@ -97,7 +100,6 @@ class Berta_CNC(FlatCAMPostProc):
z_toolchange = p.z_toolchange
toolchangexy = p.xy_toolchange
f_plunge = p.f_plunge
gcode = ''
if toolchangexy is not None:
x_toolchange = toolchangexy[0]

View File

@ -1,16 +1,16 @@
# ########################################################## ##
# ##########################################################
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# File Author: Matthieu Berthomé #
# Date: 5/26/2017 #
# MIT Licence #
# ########################################################## ##
# ##########################################################
from FlatCAMPostProc import *
class ISEL_CNC(FlatCAMPostProc):
include_header = True
coordinate_format = "%.*f"
feedrate_format = '%.*f'
@ -71,15 +71,15 @@ class ISEL_CNC(FlatCAMPostProc):
def startz_code(self, p):
if p.startz is not None:
return 'G00 Z' + self.coordinate_format%(p.coords_decimals, p.startz)
return 'G00 Z' + self.coordinate_format % (p.coords_decimals, p.startz)
else:
return ''
def lift_code(self, p):
return 'G00 Z' + self.coordinate_format%(p.coords_decimals, p.z_move)
return 'G00 Z' + self.coordinate_format % (p.coords_decimals, p.z_move)
def down_code(self, p):
return 'G01 Z' + self.coordinate_format%(p.coords_decimals, p.z_cut)
return 'G01 Z' + self.coordinate_format % (p.coords_decimals, p.z_cut)
def toolchange_code(self, p):
f_plunge = p.f_plunge
@ -130,17 +130,17 @@ M01""".format(tool=int(p.tool), toolC=toolC_formatted)
def end_code(self, p):
coords_xy = p['xy_toolchange']
gcode = ('G00 Z' + self.feedrate_format %(p.fr_decimals, p.z_end) + "\n")
gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + "\n")
if coords_xy is not None:
gcode += 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n"
return gcode
def feedrate_code(self, p):
return 'G01 F' + str(self.feedrate_format %(p.fr_decimals, p.feedrate))
return 'G01 F' + str(self.feedrate_format % (p.fr_decimals, p.feedrate))
def z_feedrate_code(self, p):
return 'G01 F' + str(self.feedrate_format %(p.fr_decimals, p.z_feedrate))
return 'G01 F' + str(self.feedrate_format % (p.fr_decimals, p.z_feedrate))
def spindle_code(self, p):
sdir = {'CW': 'M03', 'CCW': 'M04'}[p.spindledir]
@ -153,5 +153,5 @@ M01""".format(tool=int(p.tool), toolC=toolC_formatted)
if p.dwelltime:
return 'G4 P' + str(p.dwelltime)
def spindle_stop_code(self,p):
def spindle_stop_code(self, p):
return 'M05'

View File

@ -0,0 +1,136 @@
# ##########################################################
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# File Author: Matthieu Berthomé, Daniel Friderich #
# Date: 12/15/2019 #
# MIT Licence #
# ##########################################################
from FlatCAMPostProc import *
class ISEL_ICP_CNC(FlatCAMPostProc):
include_header = False
def start_code(self, p):
units = ' ' + str(p['units']).lower()
coords_xy = p['xy_toolchange']
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'])
gcode += 'IMF_PBL flatcam\n\n'
if str(p['options']['type']) == 'Geometry':
gcode += '; TOOL DIAMETER: ' + str(p['options']['tool_dia']) + units + '\n'
gcode += '; Spindle Speed: %s RPM\n' % str(p['spindlespeed'])
gcode += '; Feedrate: ' + str(p['feedrate']) + units + '/min' + '\n'
if str(p['options']['type']) == 'Geometry':
gcode += '; Feedrate_Z: ' + str(p['z_feedrate']) + units + '/min' + '\n'
gcode += '\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['z_depthpercut']) + units + ' <=>' + \
str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + '\n'
gcode += '; Z_Move: ' + str(p['z_move']) + units + '\n'
gcode += '; Z Toolchange: ' + str(p['z_toolchange']) + units + '\n'
if coords_xy is not None:
gcode += '; X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
p.decimals, 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['z_end']) + 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 += '; Preprocessor Excellon: ' + str(p['pp_excellon_name']) + '\n'
else:
gcode += '; Preprocessor Geometry: ' + str(p['pp_geometry_name']) + '\n'
gcode += '\n'
gcode += '; X range: ' + '{: >9s}'.format(xmin) + ' ... ' + '{: >9s}'.format(xmax) + ' ' + units + '\n'
gcode += '; Y range: ' + '{: >9s}'.format(ymin) + ' ... ' + '{: >9s}'.format(ymax) + ' ' + units + '\n'
return gcode
def startz_code(self, p):
if p.startz is not None:
return 'FASTABS Z' + str(int(p.startz * 1000))
else:
return ''
def lift_code(self, p):
return 'FASTABS Z' + str(int(p.z_move * 1000))
def down_code(self, p):
return 'MOVEABS Z' + str(int(p.z_cut * 1000))
def toolchange_code(self, p):
f_plunge = p.f_plunge
no_drills = 1
toolC_formatted = '%.*f' % (p.decimals, p.toolC)
if str(p['options']['type']) == 'Excellon':
for i in p['options']['Tools_in_use']:
if i[0] == p.tool:
no_drills = i[2]
gcode = "GETTOOL {tool}\n; Changed to Tool Dia = {toolC}".format(tool=int(p.tool), t_drills=no_drills,
toolC=toolC_formatted)
if f_plunge is True:
gcode += '\nFASTABS Z' + str(int(p.z_move * 1000))
return gcode
else:
gcode = "GETTOOL {tool}\n; Changed to Tool Dia = {toolC}".format(tool=int(p.tool), toolC=toolC_formatted)
if f_plunge is True:
gcode += '\nFASTABS Z' + str(int(p.z_move * 1000))
return gcode
def up_to_zero_code(self, p):
return 'MOVEABS Z0'
def position_code(self, p):
return 'X' + str(int(p.x * 1000)) + ' Y' + str(int(p.y * 1000))
def rapid_code(self, p):
return ('FASTABS ' + self.position_code(p)).format(**p)
def linear_code(self, p):
return ('MOVEABS ' + self.position_code(p)).format(**p)
def end_code(self, p):
gcode = ''
gcode += 'WPCLEAR\n'
gcode += 'FASTABS Z0\n'
gcode += 'FASTABS X0 Y0\n'
gcode += 'PROGEND'
return gcode
def feedrate_code(self, p):
return 'VEL ' + str(int(p.feedrate / 60 * 1000))
def z_feedrate_code(self, p):
return 'VEL ' + str(int(p.z_feedrate / 60 * 1000))
def spindle_code(self, p):
sdir = {'CW': 'SPINDLE CW', 'CCW': 'SPINDLE CCW'}[p.spindledir]
if p.spindlespeed:
return '%s RPM%s' % (sdir, str(int(p.spindlespeed)))
else:
return sdir
def dwell_code(self, p):
if p.dwelltime:
return 'WAIT ' + str(int(p.dwelltime * 1000))
def spindle_stop_code(self, p):
return 'SPINDLE OFF'

View File

@ -1,16 +1,17 @@
# ########################################################## ##
# ##########################################################
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# File Author: Marius Adrian Stanciu (c) #
# Date: 3/10/2019 #
# MIT Licence #
# ########################################################## ##
# ##########################################################
from FlatCAMPostProc import *
class Paste_1(FlatCAMPostProc_Tools):
include_header = True
coordinate_format = "%.*f"
feedrate_format = '%.*f'
@ -56,21 +57,20 @@ class Paste_1(FlatCAMPostProc_Tools):
return gcode
def lift_code(self, p):
return 'G00 Z' + self.coordinate_format%(p.coords_decimals, float(p['z_travel']))
return 'G00 Z' + self.coordinate_format % (p.coords_decimals, float(p['z_travel']))
def down_z_start_code(self, p):
return 'G01 Z' + self.coordinate_format%(p.coords_decimals, float(p['z_start']))
return 'G01 Z' + self.coordinate_format % (p.coords_decimals, float(p['z_start']))
def lift_z_dispense_code(self, p):
return 'G01 Z' + self.coordinate_format%(p.coords_decimals, float(p['z_dispense']))
return 'G01 Z' + self.coordinate_format % (p.coords_decimals, float(p['z_dispense']))
def down_z_stop_code(self, p):
return 'G01 Z' + self.coordinate_format%(p.coords_decimals, float(p['z_stop']))
return 'G01 Z' + self.coordinate_format % (p.coords_decimals, float(p['z_stop']))
def toolchange_code(self, p):
z_toolchange = float(p['z_toolchange'])
toolchangexy = [float(eval(a)) for a in p['xy_toolchange'].split(",") if a != '']
gcode = ''
if toolchangexy is not None:
x_toolchange = toolchangexy[0]
@ -116,27 +116,27 @@ G00 Z{z_toolchange}
def rapid_code(self, p):
return ('G00 ' + self.position_code(p)).format(**p) + '\nG00 Z' + \
self.coordinate_format%(p.coords_decimals, float(p['z_travel']))
self.coordinate_format % (p.coords_decimals, float(p['z_travel']))
def linear_code(self, p):
return ('G01 ' + self.position_code(p)).format(**p)
def end_code(self, p):
coords_xy = [float(eval(a)) for a in p['xy_toolchange'].split(",") if a != '']
gcode = ('G00 Z' + self.feedrate_format %(p.fr_decimals, float(p['z_toolchange'])) + "\n")
gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, float(p['z_toolchange'])) + "\n")
if coords_xy is not None:
gcode += 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n"
return gcode
def feedrate_xy_code(self, p):
return 'G01 F' + str(self.feedrate_format %(p.fr_decimals, float(p['frxy'])))
return 'G01 F' + str(self.feedrate_format % (p.fr_decimals, float(p['frxy'])))
def z_feedrate_code(self, p):
return 'G01 F' + str(self.feedrate_format %(p.fr_decimals, float(p['frz'])))
return 'G01 F' + str(self.feedrate_format % (p.fr_decimals, float(p['frz'])))
def feedrate_z_dispense_code(self, p):
return 'G01 F' + str(self.feedrate_format %(p.fr_decimals, float(p['frz_dispense'])))
return 'G01 F' + str(self.feedrate_format % (p.fr_decimals, float(p['frz_dispense'])))
def spindle_fwd_code(self, p):
if p.spindlespeed:
@ -150,7 +150,7 @@ G00 Z{z_toolchange}
else:
return 'M04'
def spindle_off_code(self,p):
def spindle_off_code(self, p):
return 'M05'
def dwell_fwd_code(self, p):

View File

@ -1,16 +1,17 @@
# ########################################################## ##
# ##########################################################
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# File Author: Marius Adrian Stanciu (c) #
# Date: 3/10/2019 #
# MIT Licence #
# ########################################################## ##
# ##########################################################
from FlatCAMPostProc import *
class Repetier(FlatCAMPostProc):
include_header = True
coordinate_format = "%.*f"
feedrate_format = '%.*f'
feedrate_rapid_format = feedrate_format
@ -66,6 +67,7 @@ class Repetier(FlatCAMPostProc):
gcode += ('G20' if p.units.upper() == 'IN' else 'G21') + "\n"
gcode += 'G90\n'
gcode += 'G94\n'
return gcode
@ -76,20 +78,22 @@ class Repetier(FlatCAMPostProc):
return ''
def lift_code(self, p):
return 'G0 Z' + self.coordinate_format%(p.coords_decimals, p.z_move) + " " + self.feedrate_rapid_code(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.inline_z_feedrate_code(p)
return 'G1 Z' + self.coordinate_format % (p.coords_decimals, p.z_cut) + " " + self.inline_z_feedrate_code(p)
def toolchange_code(self, p):
z_toolchange = p.z_toolchange
toolchangexy = p.xy_toolchange
f_plunge = p.f_plunge
gcode = ''
if toolchangexy is not None:
x_toolchange = toolchangexy[0]
y_toolchange = toolchangexy[1]
else:
x_toolchange = 0.0
y_toolchange = 0.0
no_drills = 1
@ -151,7 +155,7 @@ G0 Z{z_toolchange}
M84
@pause Change to tool T{tool} with Tool Dia = {toolC}
G0 Z{z_toolchange}
""".format(z_toolchange=self.coordinate_format%(p.coords_decimals, z_toolchange),
""".format(z_toolchange=self.coordinate_format % (p.coords_decimals, z_toolchange),
tool=int(p.tool),
toolC=toolC_formatted)
@ -175,7 +179,7 @@ G0 Z{z_toolchange}
def end_code(self, p):
coords_xy = p['xy_toolchange']
gcode = ('G0 Z' + self.feedrate_format %(p.fr_decimals, p.z_end) + " " + self.feedrate_rapid_code(p) + "\n")
gcode = ('G0 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + " " + 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"
@ -183,21 +187,21 @@ G0 Z{z_toolchange}
return gcode
def feedrate_code(self, p):
return 'G1 F' + str(self.feedrate_format %(p.fr_decimals, p.feedrate))
return 'G1 F' + str(self.feedrate_format % (p.fr_decimals, p.feedrate))
def inline_feedrate_code(self, p):
return 'F' + self.feedrate_format %(p.fr_decimals, p.feedrate)
return 'F' + self.feedrate_format % (p.fr_decimals, p.feedrate)
def inline_z_feedrate_code(self, p):
return 'F' + self.feedrate_format %(p.fr_decimals, p.z_feedrate)
return 'F' + self.feedrate_format % (p.fr_decimals, p.z_feedrate)
def z_feedrate_code(self, p):
return 'G1 F' + str(self.feedrate_format %(p.fr_decimals, p.z_feedrate))
return 'G1 F' + str(self.feedrate_format % (p.fr_decimals, p.z_feedrate))
def feedrate_rapid_code(self, p):
return 'F' + self.feedrate_rapid_format % (p.fr_decimals, p.feedrate_rapid)
def spindle_code(self,p):
def spindle_code(self, p):
if p.spindlespeed:
return 'M106 S%d' % p.spindlespeed
else:
@ -207,5 +211,5 @@ G0 Z{z_toolchange}
if p.dwelltime:
return 'G4 P' + str(p.dwelltime)
def spindle_stop_code(self,p):
def spindle_stop_code(self, p):
return 'M107'

View File

@ -1,10 +1,10 @@
# ########################################################## ##
# ##########################################################
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# File Author: Marius Adrian Stanciu (c) #
# Date: 3/10/2019 #
# MIT Licence #
# ########################################################## ##
# ##########################################################
from FlatCAMPostProc import *
@ -13,6 +13,7 @@ from FlatCAMPostProc import *
# the same) to contain the following keyword, case-sensitive: 'Roland' without the quotes.
class Roland_MDX_20(FlatCAMPostProc):
include_header = False
coordinate_format = "%.1f"
feedrate_format = '%.1f'
feedrate_rapid_format = '%.1f'
@ -123,5 +124,5 @@ class Roland_MDX_20(FlatCAMPostProc):
def dwell_code(self, p):
return''
def spindle_stop_code(self,p):
def spindle_stop_code(self, p):
return '!MC0'

View File

@ -1,16 +1,17 @@
# ########################################################## ##
# ##########################################################
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# File Author: Marius Adrian Stanciu (c) #
# Date: 3/10/2019 #
# MIT Licence #
# ########################################################## ##
# ##########################################################
from FlatCAMPostProc import *
class Toolchange_Custom(FlatCAMPostProc):
include_header = True
coordinate_format = "%.*f"
feedrate_format = '%.*f'
@ -74,10 +75,10 @@ class Toolchange_Custom(FlatCAMPostProc):
return ''
def lift_code(self, p):
return 'G00 Z' + self.coordinate_format%(p.coords_decimals, p.z_move)
return 'G00 Z' + self.coordinate_format % (p.coords_decimals, p.z_move)
def down_code(self, p):
return 'G01 Z' + self.coordinate_format%(p.coords_decimals, p.z_cut)
return 'G01 Z' + self.coordinate_format % (p.coords_decimals, p.z_cut)
def toolchange_code(self, p):
z_toolchange = p.z_toolchange
@ -88,6 +89,9 @@ class Toolchange_Custom(FlatCAMPostProc):
if toolchangexy is not None:
x_toolchange = toolchangexy[0]
y_toolchange = toolchangexy[1]
else:
x_toolchange = 0.0
y_toolchange = 0.0
no_drills = 1
@ -142,17 +146,17 @@ M6
def end_code(self, p):
coords_xy = p['xy_toolchange']
gcode = ('G00 Z' + self.feedrate_format %(p.fr_decimals, p.z_end) + "\n")
gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + "\n")
if coords_xy is not None:
gcode += 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n"
return gcode
def feedrate_code(self, p):
return 'G01 F' + str(self.feedrate_format %(p.fr_decimals, p.feedrate))
return 'G01 F' + str(self.feedrate_format % (p.fr_decimals, p.feedrate))
def z_feedrate_code(self, p):
return 'G01 F' + str(self.feedrate_format %(p.fr_decimals, p.z_feedrate))
return 'G01 F' + str(self.feedrate_format % (p.fr_decimals, p.z_feedrate))
def spindle_code(self, p):
sdir = {'CW': 'M03', 'CCW': 'M04'}[p.spindledir]
@ -165,5 +169,5 @@ M6
if p.dwelltime:
return 'G4 P' + str(p.dwelltime)
def spindle_stop_code(self,p):
def spindle_stop_code(self, p):
return 'M05'

View File

@ -1,16 +1,17 @@
# ########################################################## ##
# ##########################################################
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# File Author: Marius Adrian Stanciu (c) #
# Date: 3/10/2019 #
# MIT Licence #
# ########################################################## ##
# ##########################################################
from FlatCAMPostProc import *
class Toolchange_Probe_MACH3(FlatCAMPostProc):
include_header = True
coordinate_format = "%.*f"
feedrate_format = '%.*f'
@ -69,14 +70,14 @@ class Toolchange_Probe_MACH3(FlatCAMPostProc):
gcode += 'G90\n'
gcode += 'G17\n'
gcode += 'G94\n'
gcode += '(MSG, WARNING: Make sure you do zero on all axis. ' \
'For Z axis, since it will be probed, make a rough estimate and do a zero.)\n'
gcode += 'M0'
return gcode
def startz_code(self, p):
return ''
g = '(MSG, WARNING: Make sure you do zero on all axis. ' \
'For Z axis, since it will be probed, make a rough estimate and do a zero.)\n'
g += 'M0'
return g
def lift_code(self, p):
return 'G00 Z' + self.coordinate_format%(p.coords_decimals, p.z_move)
@ -89,11 +90,12 @@ class Toolchange_Probe_MACH3(FlatCAMPostProc):
toolchangexy = p.xy_toolchange
f_plunge = p.f_plunge
gcode = ''
if toolchangexy is not None:
x_toolchange = toolchangexy[0]
y_toolchange = toolchangexy[1]
else:
x_toolchange = 0.0
y_toolchange = 0.0
no_drills = 1
@ -131,7 +133,7 @@ M0
z_toolchange=self.coordinate_format % (p.coords_decimals, z_toolchange),
z_move=self.coordinate_format % (p.coords_decimals, p.z_move),
z_in_between=self.coordinate_format % (p.coords_decimals, p.z_move / 2),
feedrate_probe=str(self.feedrate_format %(p.fr_decimals, p.feedrate_probe)),
feedrate_probe=str(self.feedrate_format % (p.fr_decimals, p.feedrate_probe)),
feedrate_probe_slow=str(self.feedrate_format % (p.fr_decimals, (p.feedrate_probe / 2))),
z_pdepth=self.coordinate_format % (p.coords_decimals, p.z_pdepth),
tool=int(p.tool),
@ -158,7 +160,7 @@ M0
""".format(z_toolchange=self.coordinate_format % (p.coords_decimals, z_toolchange),
z_move=self.coordinate_format % (p.coords_decimals, p.z_move),
z_in_between=self.coordinate_format % (p.coords_decimals, p.z_move / 2),
feedrate_probe=str(self.feedrate_format %(p.fr_decimals, p.feedrate_probe)),
feedrate_probe=str(self.feedrate_format % (p.fr_decimals, p.feedrate_probe)),
feedrate_probe_slow=str(self.feedrate_format % (p.fr_decimals, (p.feedrate_probe / 2))),
z_pdepth=self.coordinate_format % (p.coords_decimals, p.z_pdepth),
tool=int(p.tool),
@ -194,7 +196,7 @@ M0
z_toolchange=self.coordinate_format % (p.coords_decimals, z_toolchange),
z_move=self.coordinate_format % (p.coords_decimals, p.z_move),
z_in_between=self.coordinate_format % (p.coords_decimals, p.z_move / 2),
feedrate_probe=str(self.feedrate_format %(p.fr_decimals, p.feedrate_probe)),
feedrate_probe=str(self.feedrate_format % (p.fr_decimals, p.feedrate_probe)),
feedrate_probe_slow=str(self.feedrate_format % (p.fr_decimals, (p.feedrate_probe / 2))),
z_pdepth=self.coordinate_format % (p.coords_decimals, p.z_pdepth),
tool=int(p.tool),
@ -220,7 +222,7 @@ M0
""".format(z_toolchange=self.coordinate_format % (p.coords_decimals, z_toolchange),
z_move=self.coordinate_format % (p.coords_decimals, p.z_move),
z_in_between=self.coordinate_format % (p.coords_decimals, p.z_move / 2),
feedrate_probe=str(self.feedrate_format %(p.fr_decimals, p.feedrate_probe)),
feedrate_probe=str(self.feedrate_format % (p.fr_decimals, p.feedrate_probe)),
feedrate_probe_slow=str(self.feedrate_format % (p.fr_decimals, (p.feedrate_probe / 2))),
z_pdepth=self.coordinate_format % (p.coords_decimals, p.z_pdepth),
tool=int(p.tool),
@ -245,17 +247,17 @@ M0
def end_code(self, p):
coords_xy = p['xy_toolchange']
gcode = ('G00 Z' + self.feedrate_format %(p.fr_decimals, p.z_end) + "\n")
gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + "\n")
if coords_xy is not None:
gcode += 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n"
return gcode
def feedrate_code(self, p):
return 'G01 F' + str(self.feedrate_format %(p.fr_decimals, p.feedrate))
return 'G01 F' + str(self.feedrate_format % (p.fr_decimals, p.feedrate))
def z_feedrate_code(self, p):
return 'G01 F' + str(self.feedrate_format %(p.fr_decimals, p.z_feedrate))
return 'G01 F' + str(self.feedrate_format % (p.fr_decimals, p.z_feedrate))
def spindle_code(self, p):
sdir = {'CW': 'M03', 'CCW': 'M04'}[p.spindledir]
@ -268,5 +270,5 @@ M0
if p.dwelltime:
return 'G4 P' + str(p.dwelltime)
def spindle_stop_code(self,p):
def spindle_stop_code(self, p):
return 'M05'

View File

@ -1,16 +1,17 @@
# ########################################################## ##
# ##########################################################
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# File Author: Marius Adrian Stanciu (c) #
# Date: 3/10/2019 #
# MIT Licence #
# ########################################################## ##
# ##########################################################
from FlatCAMPostProc import *
class Toolchange_manual(FlatCAMPostProc):
include_header = True
coordinate_format = "%.*f"
feedrate_format = '%.*f'
@ -84,11 +85,13 @@ class Toolchange_manual(FlatCAMPostProc):
z_toolchange = p.z_toolchange
toolchangexy = p.xy_toolchange
f_plunge = p.f_plunge
gcode = ''
if toolchangexy is not None:
x_toolchange = toolchangexy[0]
y_toolchange = toolchangexy[1]
else:
x_toolchange = 0.0
y_toolchange = 0.0
no_drills = 1
@ -116,9 +119,9 @@ M0
G00 Z{z_toolchange}
(MSG, Now the tool can be tightened more securely.)
M0
""".format(x_toolchange=self.coordinate_format%(p.coords_decimals, x_toolchange),
y_toolchange=self.coordinate_format%(p.coords_decimals, y_toolchange),
z_toolchange=self.coordinate_format%(p.coords_decimals, z_toolchange),
""".format(x_toolchange=self.coordinate_format % (p.coords_decimals, x_toolchange),
y_toolchange=self.coordinate_format % (p.coords_decimals, y_toolchange),
z_toolchange=self.coordinate_format % (p.coords_decimals, z_toolchange),
tool=int(p.tool),
t_drills=no_drills,
toolC=toolC_formatted)
@ -137,7 +140,7 @@ G00 Z{z_toolchange}
(MSG, Now the tool can be tightened more securely.)
M0
""".format(
z_toolchange=self.coordinate_format%(p.coords_decimals, z_toolchange),
z_toolchange=self.coordinate_format % (p.coords_decimals, z_toolchange),
tool=int(p.tool),
t_drills=no_drills,
toolC=toolC_formatted)
@ -161,9 +164,9 @@ M0
G00 Z{z_toolchange}
(MSG, Now the tool can be tightened more securely.)
M0
""".format(x_toolchange=self.coordinate_format%(p.coords_decimals, x_toolchange),
y_toolchange=self.coordinate_format%(p.coords_decimals, y_toolchange),
z_toolchange=self.coordinate_format%(p.coords_decimals, z_toolchange),
""".format(x_toolchange=self.coordinate_format % (p.coords_decimals, x_toolchange),
y_toolchange=self.coordinate_format % (p.coords_decimals, y_toolchange),
z_toolchange=self.coordinate_format % (p.coords_decimals, z_toolchange),
tool=int(p.tool),
toolC=toolC_formatted)
else:
@ -179,8 +182,7 @@ M0
G00 Z{z_toolchange}
(MSG, Now the tool can be tightened more securely.)
M0
""".format(z_toolchange=self.coordinate_format%(p.coords_decimals, z_toolchange),
tool=int(p.tool),
""".format(z_toolchange=self.coordinate_format % (p.coords_decimals, z_toolchange), tool=int(p.tool),
toolC=toolC_formatted)
if f_plunge is True:
@ -202,7 +204,7 @@ M0
def end_code(self, p):
coords_xy = p['xy_toolchange']
gcode = ('G00 Z' + self.feedrate_format %(p.fr_decimals, p.z_end) + "\n")
gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + "\n")
if coords_xy is not None:
gcode += 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n"
else:
@ -210,10 +212,10 @@ M0
return gcode
def feedrate_code(self, p):
return 'G01 F' + str(self.feedrate_format %(p.fr_decimals, p.feedrate))
return 'G01 F' + str(self.feedrate_format % (p.fr_decimals, p.feedrate))
def z_feedrate_code(self, p):
return 'G01 F' + str(self.feedrate_format %(p.fr_decimals, p.z_feedrate))
return 'G01 F' + str(self.feedrate_format % (p.fr_decimals, p.z_feedrate))
def spindle_code(self, p):
sdir = {'CW': 'M03', 'CCW': 'M04'}[p.spindledir]
@ -226,5 +228,5 @@ M0
if p.dwelltime:
return 'G4 P' + str(p.dwelltime)
def spindle_stop_code(self,p):
def spindle_stop_code(self, p):
return 'M05'

View File

@ -1,16 +1,17 @@
# ########################################################## ##
# ##########################################################
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# File Author: Matthieu Berthomé #
# Date: 5/26/2017 #
# MIT Licence #
# ########################################################## ##
# ##########################################################
from FlatCAMPostProc import *
class default(FlatCAMPostProc):
include_header = True
coordinate_format = "%.*f"
feedrate_format = '%.*f'
@ -71,25 +72,27 @@ class default(FlatCAMPostProc):
def startz_code(self, p):
if p.startz is not None:
return 'G00 Z' + self.coordinate_format%(p.coords_decimals, p.startz)
return 'G00 Z' + self.coordinate_format % (p.coords_decimals, p.startz)
else:
return ''
def lift_code(self, p):
return 'G00 Z' + self.coordinate_format%(p.coords_decimals, p.z_move)
return 'G00 Z' + self.coordinate_format % (p.coords_decimals, p.z_move)
def down_code(self, p):
return 'G01 Z' + self.coordinate_format%(p.coords_decimals, p.z_cut)
return 'G01 Z' + self.coordinate_format % (p.coords_decimals, p.z_cut)
def toolchange_code(self, p):
z_toolchange = p.z_toolchange
toolchangexy = p.xy_toolchange
f_plunge = p.f_plunge
gcode = ''
if toolchangexy is not None:
x_toolchange = toolchangexy[0]
y_toolchange = toolchangexy[1]
else:
x_toolchange = 0.0
y_toolchange = 0.0
no_drills = 1
@ -163,7 +166,7 @@ M6
(MSG, Change to Tool Dia = {toolC})
M0
G00 Z{z_toolchange}
""".format(z_toolchange=self.coordinate_format%(p.coords_decimals, z_toolchange),
""".format(z_toolchange=self.coordinate_format % (p.coords_decimals, z_toolchange),
tool=int(p.tool),
toolC=toolC_formatted)
@ -186,17 +189,17 @@ G00 Z{z_toolchange}
def end_code(self, p):
coords_xy = p['xy_toolchange']
gcode = ('G00 Z' + self.feedrate_format %(p.fr_decimals, p.z_end) + "\n")
gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + "\n")
if coords_xy is not None:
gcode += 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n"
return gcode
def feedrate_code(self, p):
return 'G01 F' + str(self.feedrate_format %(p.fr_decimals, p.feedrate))
return 'G01 F' + str(self.feedrate_format % (p.fr_decimals, p.feedrate))
def z_feedrate_code(self, p):
return 'G01 F' + str(self.feedrate_format %(p.fr_decimals, p.z_feedrate))
return 'G01 F' + str(self.feedrate_format % (p.fr_decimals, p.z_feedrate))
def spindle_code(self, p):
sdir = {'CW': 'M03', 'CCW': 'M04'}[p.spindledir]
@ -209,5 +212,5 @@ G00 Z{z_toolchange}
if p.dwelltime:
return 'G4 P' + str(p.dwelltime)
def spindle_stop_code(self,p):
def spindle_stop_code(self, p):
return 'M05'

View File

@ -1,16 +1,17 @@
# ########################################################## ##
# ##########################################################
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# File Author: Matthieu Berthomé #
# Date: 5/26/2017 #
# MIT Licence #
# ########################################################## ##
# ##########################################################
from FlatCAMPostProc import *
class grbl_11(FlatCAMPostProc):
include_header = True
coordinate_format = "%.*f"
feedrate_format = '%.*f'
@ -63,32 +64,34 @@ class grbl_11(FlatCAMPostProc):
gcode += ('G20' if p.units.upper() == 'IN' else 'G21') + "\n"
gcode += 'G90\n'
gcode += 'G94\n'
gcode += 'G17\n'
gcode += 'G94\n'
return gcode
def startz_code(self, p):
if p.startz is not None:
return 'G00 Z' + self.coordinate_format%(p.coords_decimals, p.startz)
return 'G00 Z' + self.coordinate_format % (p.coords_decimals, p.startz)
else:
return ''
def lift_code(self, p):
return 'G00 Z' + self.coordinate_format%(p.coords_decimals, p.z_move)
return 'G00 Z' + self.coordinate_format % (p.coords_decimals, p.z_move)
def down_code(self, p):
return 'G01 Z' + self.coordinate_format%(p.coords_decimals, p.z_cut)
return 'G01 Z' + self.coordinate_format % (p.coords_decimals, p.z_cut)
def toolchange_code(self, p):
z_toolchange = p.z_toolchange
toolchangexy = p.xy_toolchange
f_plunge = p.f_plunge
gcode = ''
if toolchangexy is not None:
x_toolchange = toolchangexy[0]
y_toolchange = toolchangexy[1]
else:
x_toolchange = 0.0
y_toolchange = 0.0
no_drills = 1
@ -161,7 +164,7 @@ M6
(MSG, Change to Tool Dia = {toolC})
M0
G00 Z{z_toolchange}
""".format(z_toolchange=self.coordinate_format%(p.coords_decimals, z_toolchange),
""".format(z_toolchange=self.coordinate_format % (p.coords_decimals, z_toolchange),
tool=int(p.tool),
toolC=toolC_formatted)
@ -181,21 +184,21 @@ G00 Z{z_toolchange}
def linear_code(self, p):
return ('G01 ' + self.position_code(p)).format(**p) + \
' F' + str(self.feedrate_format %(p.fr_decimals, p.feedrate))
' F' + str(self.feedrate_format % (p.fr_decimals, p.feedrate))
def end_code(self, p):
coords_xy = p['xy_toolchange']
gcode = ('G00 Z' + self.feedrate_format %(p.fr_decimals, p.z_end) + "\n")
gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + "\n")
if coords_xy is not None:
gcode += 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n"
return gcode
def feedrate_code(self, p):
return 'G01 F' + str(self.feedrate_format %(p.fr_decimals, p.feedrate))
return 'G01 F' + str(self.feedrate_format % (p.fr_decimals, p.feedrate))
def z_feedrate_code(self, p):
return 'G01 F' + str(self.feedrate_format %(p.fr_decimals, p.z_feedrate))
return 'G01 F' + str(self.feedrate_format % (p.fr_decimals, p.z_feedrate))
def spindle_code(self, p):
sdir = {'CW': 'M03', 'CCW': 'M04'}[p.spindledir]
@ -208,5 +211,5 @@ G00 Z{z_toolchange}
if p.dwelltime:
return 'G4 P' + str(p.dwelltime)
def spindle_stop_code(self,p):
def spindle_stop_code(self, p):
return 'M05'

View File

@ -1,10 +1,10 @@
# ########################################################## ##
# ##########################################################
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# File Author: Matthieu Berthomé #
# Date: 5/26/2017 #
# MIT Licence #
# ########################################################## ##
# ##########################################################
from FlatCAMPostProc import *
@ -14,6 +14,7 @@ from FlatCAMPostProc import *
class grbl_laser(FlatCAMPostProc):
include_header = True
coordinate_format = "%.*f"
feedrate_format = '%.*f'
@ -34,15 +35,15 @@ class grbl_laser(FlatCAMPostProc):
if str(p['options']['type']) == 'Excellon' or str(p['options']['type']) == 'Excellon Geometry':
gcode += '(Preprocessor Excellon: ' + str(p['pp_excellon_name']) + ')\n'
else:
gcode += '(Preprocessor Geometry: ' + str(p['pp_geometry_name']) + ')\n'
gcode += ('G20' if p.units.upper() == 'IN' else 'G21') + "\n" + '\n'
gcode += '(Preprocessor 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 += ('G20' if p.units.upper() == 'IN' else 'G21') + "\n"
gcode += 'G90\n'
gcode += 'G94\n'
gcode += 'G17\n'
gcode += 'G94\n'
return gcode
@ -73,21 +74,21 @@ class grbl_laser(FlatCAMPostProc):
def linear_code(self, p):
return ('G01 ' + self.position_code(p)).format(**p) + \
' F' + str(self.feedrate_format %(p.fr_decimals, p.feedrate))
' F' + str(self.feedrate_format % (p.fr_decimals, p.feedrate))
def end_code(self, p):
coords_xy = p['xy_toolchange']
gcode = ('G00 Z' + self.feedrate_format %(p.fr_decimals, p.z_end) + "\n")
gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + "\n")
if coords_xy is not None:
gcode += 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n"
return gcode
def feedrate_code(self, p):
return 'G01 F' + str(self.feedrate_format %(p.fr_decimals, p.feedrate))
return 'G01 F' + str(self.feedrate_format % (p.fr_decimals, p.feedrate))
def z_feedrate_code(self, p):
return 'G01 F' + str(self.feedrate_format %(p.fr_decimals, p.z_feedrate))
return 'G01 F' + str(self.feedrate_format % (p.fr_decimals, p.z_feedrate))
def spindle_code(self, p):
sdir = {'CW': 'M03', 'CCW': 'M04'}[p.spindledir]
@ -99,5 +100,5 @@ class grbl_laser(FlatCAMPostProc):
def dwell_code(self, p):
return ''
def spindle_stop_code(self,p):
def spindle_stop_code(self, p):
return 'M05'

View File

@ -1,10 +1,10 @@
# ########################################################## ##
# ##########################################################
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# File Author: Marius Adrian Stanciu (c) #
# Date: 3/10/2019 #
# MIT Licence #
# ########################################################## ##
# ##########################################################
from FlatCAMPostProc import *
@ -12,11 +12,12 @@ from FlatCAMPostProc import *
# for Roland Preprocessors it is mandatory for the preprocessor name (python file and class name, both of them must be
# the same) to contain the following keyword, case-sensitive: 'Roland' without the quotes.
class hpgl(FlatCAMPostProc):
include_header = True
coordinate_format = "%.*f"
def start_code(self, p):
gcode = 'IN;'
gcode = 'IN;\n'
gcode += 'PU;'
return gcode
def startz_code(self, p):
@ -49,8 +50,19 @@ class hpgl(FlatCAMPostProc):
y = p.y
# we need to have the coordinates as multiples of 0.025mm
x = round(x / 0.025) * 25 / 1000
y = round(y / 0.025) * 25 / 1000
x = round(x * 40)
y = round(y * 40)
# constrain the x and y values within the domain of valid values: [-32767 ... 32768]
if x <= -32767:
x = -32767
if x >= 32768:
x = 32768
if y <= -32767:
y = -32767
if y >= 32768:
y = 32768
return ('PA' + self.coordinate_format + ',' + self.coordinate_format + ';') % \
(p.coords_decimals, x, p.coords_decimals, y)
@ -80,5 +92,5 @@ class hpgl(FlatCAMPostProc):
def dwell_code(self, p):
return ''
def spindle_stop_code(self,p):
def spindle_stop_code(self, p):
return ''

View File

@ -1,16 +1,17 @@
# ########################################################## ##
# ##########################################################
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# File Author: Marius Adrian Stanciu (c) #
# Date: 3/10/2019 #
# MIT Licence #
# ########################################################## ##
# ##########################################################
from FlatCAMPostProc import *
class line_xyz(FlatCAMPostProc):
include_header = True
coordinate_format = "%.*f"
feedrate_format = '%.*f'
@ -69,9 +70,9 @@ class line_xyz(FlatCAMPostProc):
def startz_code(self, p):
if p.startz is not None:
g = 'G00 ' + 'X' + self.coordinate_format%(p.coords_decimals, p.x) + \
' Y' + self.coordinate_format%(p.coords_decimals, p.y) + \
' Z' + self.coordinate_format%(p.coords_decimals, p.startz)
g = 'G00 ' + 'X' + self.coordinate_format % (p.coords_decimals, p.x) + \
' Y' + self.coordinate_format % (p.coords_decimals, p.y) + \
' Z' + self.coordinate_format % (p.coords_decimals, p.startz)
return g
else:
return ''
@ -92,7 +93,6 @@ class line_xyz(FlatCAMPostProc):
z_toolchange = p.z_toolchange
xy_toolchange = p.xy_toolchange
f_plunge = p.f_plunge
gcode = ''
if xy_toolchange is not None:
x_toolchange = xy_toolchange[0]
@ -122,7 +122,7 @@ G00 X{x_toolchange} Y{x_toolchange} Z{z_toolchange}
T{tool}
M6
(MSG, Change to Tool Dia = {toolC} ||| Total drills for tool T{tool} = {t_drills})
M0""".format(x_toolchange=self.coordinate_format%(p.coords_decimals, x_toolchange),
M0""".format(x_toolchange=self.coordinate_format % (p.coords_decimals, x_toolchange),
y_toolchange=self.coordinate_format % (p.coords_decimals, y_toolchange),
z_toolchange=self.coordinate_format % (p.coords_decimals, z_toolchange),
tool=int(p.tool),
@ -131,7 +131,7 @@ M0""".format(x_toolchange=self.coordinate_format%(p.coords_decimals, x_toolchang
if f_plunge is True:
gcode += """\nG00 X{x_toolchange} Y{x_toolchange} Z{z_move}""".format(
x_toolchange=self.coordinate_format%(p.coords_decimals, x_toolchange),
x_toolchange=self.coordinate_format % (p.coords_decimals, x_toolchange),
y_toolchange=self.coordinate_format % (p.coords_decimals, y_toolchange),
z_move=self.coordinate_format % (p.coords_decimals, p.z_move))
return gcode
@ -142,7 +142,7 @@ G00 X{x_toolchange} Y{x_toolchange} Z{z_toolchange}
T{tool}
M6
(MSG, Change to Tool Dia = {toolC})
M0""".format(x_toolchange=self.coordinate_format%(p.coords_decimals, x_toolchange),
M0""".format(x_toolchange=self.coordinate_format % (p.coords_decimals, x_toolchange),
y_toolchange=self.coordinate_format % (p.coords_decimals, y_toolchange),
z_toolchange=self.coordinate_format % (p.coords_decimals, z_toolchange),
tool=int(p.tool),
@ -185,10 +185,10 @@ M0""".format(x_toolchange=self.coordinate_format%(p.coords_decimals, x_toolchang
return g
def feedrate_code(self, p):
return 'G01 F' + str(self.feedrate_format %(p.fr_decimals, p.feedrate))
return 'G01 F' + str(self.feedrate_format % (p.fr_decimals, p.feedrate))
def z_feedrate_code(self, p):
return 'G01 F' + str(self.feedrate_format %(p.fr_decimals, p.z_feedrate))
return 'G01 F' + str(self.feedrate_format % (p.fr_decimals, p.z_feedrate))
def spindle_code(self, p):
sdir = {'CW': 'M03', 'CCW': 'M04'}[p.spindledir]
@ -201,5 +201,5 @@ M0""".format(x_toolchange=self.coordinate_format%(p.coords_decimals, x_toolchang
if p.dwelltime:
return 'G4 P' + str(p.dwelltime)
def spindle_stop_code(self,p):
def spindle_stop_code(self, p):
return 'M05'

View File

@ -11,6 +11,7 @@ from FlatCAMPostProc import *
class marlin(FlatCAMPostProc):
include_header = True
coordinate_format = "%.*f"
feedrate_format = '%.*f'
feedrate_rapid_format = feedrate_format
@ -66,6 +67,7 @@ class marlin(FlatCAMPostProc):
gcode += ('G20' if p.units.upper() == 'IN' else 'G21') + "\n"
gcode += 'G90\n'
gcode += 'G94\n'
return gcode
@ -76,20 +78,22 @@ class marlin(FlatCAMPostProc):
return ''
def lift_code(self, p):
return 'G0 Z' + self.coordinate_format%(p.coords_decimals, p.z_move) + " " + self.feedrate_rapid_code(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.inline_z_feedrate_code(p)
return 'G1 Z' + self.coordinate_format % (p.coords_decimals, p.z_cut) + " " + self.inline_z_feedrate_code(p)
def toolchange_code(self, p):
z_toolchange = p.z_toolchange
toolchangexy = p.xy_toolchange
f_plunge = p.f_plunge
gcode = ''
if toolchangexy is not None:
x_toolchange = toolchangexy[0]
y_toolchange = toolchangexy[1]
else:
x_toolchange = 0.0
y_toolchange = 0.0
no_drills = 1
@ -162,7 +166,7 @@ M6
;MSG, Change to Tool Dia = {toolC}
M0
G0 Z{z_toolchange}
""".format(z_toolchange=self.coordinate_format%(p.coords_decimals, z_toolchange),
""".format(z_toolchange=self.coordinate_format % (p.coords_decimals, z_toolchange),
tool=int(p.tool),
toolC=toolC_formatted)
@ -185,7 +189,7 @@ G0 Z{z_toolchange}
def end_code(self, p):
coords_xy = p['xy_toolchange']
gcode = ('G0 Z' + self.feedrate_format %(p.fr_decimals, p.z_end) + " " + self.feedrate_rapid_code(p) + "\n")
gcode = ('G0 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + " " + 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"
@ -193,16 +197,16 @@ G0 Z{z_toolchange}
return gcode
def feedrate_code(self, p):
return 'G1 F' + str(self.feedrate_format %(p.fr_decimals, p.feedrate))
return 'G1 F' + str(self.feedrate_format % (p.fr_decimals, p.feedrate))
def inline_feedrate_code(self, p):
return 'F' + self.feedrate_format %(p.fr_decimals, p.feedrate)
return 'F' + self.feedrate_format % (p.fr_decimals, p.feedrate)
def inline_z_feedrate_code(self, p):
return 'F' + self.feedrate_format %(p.fr_decimals, p.z_feedrate)
return 'F' + self.feedrate_format % (p.fr_decimals, p.z_feedrate)
def z_feedrate_code(self, p):
return 'G1 F' + str(self.feedrate_format %(p.fr_decimals, p.z_feedrate))
return 'G1 F' + str(self.feedrate_format % (p.fr_decimals, p.z_feedrate))
def feedrate_rapid_code(self, p):
return 'F' + self.feedrate_rapid_format % (p.fr_decimals, p.feedrate_rapid)
@ -218,5 +222,5 @@ G0 Z{z_toolchange}
if p.dwelltime:
return 'G4 P' + str(p.dwelltime)
def spindle_stop_code(self,p):
def spindle_stop_code(self, p):
return 'M5'