Merge remote-tracking branch 'origin/Beta_8.994' into Beta_8.994

# Conflicts:
#	CHANGELOG.md
This commit is contained in:
Marius 2020-07-25 12:41:23 +03:00
commit e7e1d959fd
16 changed files with 687 additions and 116 deletions

View File

@ -11,6 +11,17 @@ CHANGELOG for FlatCAM beta
- Tools Tab is hidden when entering into a Editor and showed on exit (this needs to be remade such that the toolbars state should be restored to whatever it was before entering in the Editor) - Tools Tab is hidden when entering into a Editor and showed on exit (this needs to be remade such that the toolbars state should be restored to whatever it was before entering in the Editor)
22.07.2020
- working on a proper GCode Editor
- wip in the GCode Editor
- added a Laser preprocessor named 'Z_laser' which will change the Z to the Travel Z on each ToolChange event allowing therefore control of the dot size
- by default now a new blank Geometry object created by FlatCAM is of type multigeo
- made sure that optimizations of lines when importing SVG or DXF as lines will not encounter polygons but only LinesStrings or LinearRings, otherwise having crashes
- fixed the import SVG and import DXF, when importing as Geometry to be imported as multigeo tool
- fixed the import SVG and import DXF, the source files will be saved as loaded into the source_file attribute of the resulting object (be it Geometry or Gerber)
- in import SVG and import DXF methods made sure that any polygons that are imported as polygons will survive and only the lines are optimized (changed the behavior of the above made modification)
21.07.2020 21.07.2020
- updated the FCRadio class with a method that allow disabling certain options - updated the FCRadio class with a method that allow disabling certain options

View File

@ -2569,7 +2569,7 @@ class AppExcEditor(QtCore.QObject):
self.set_ui() self.set_ui()
# now that we hava data, create the appGUI interface and add it to the Tool Tab # now that we have data, create the appGUI interface and add it to the Tool Tab
self.build_ui(first_run=True) self.build_ui(first_run=True)
# we activate this after the initial build as we don't need to see the tool been populated # we activate this after the initial build as we don't need to see the tool been populated

View File

@ -3979,77 +3979,6 @@ class AppGeoEditor(QtCore.QObject):
# self.storage = AppGeoEditor.make_storage() # self.storage = AppGeoEditor.make_storage()
self.replot() self.replot()
def edit_fcgeometry(self, fcgeometry, multigeo_tool=None):
"""
Imports the geometry from the given FlatCAM Geometry object
into the editor.
:param fcgeometry: GeometryObject
:param multigeo_tool: A tool for the case of the edited geometry being of type 'multigeo'
:return: None
"""
assert isinstance(fcgeometry, Geometry), "Expected a Geometry, got %s" % type(fcgeometry)
self.deactivate()
self.activate()
self.set_ui()
# Hide original geometry
self.fcgeometry = fcgeometry
fcgeometry.visible = False
# Set selection tolerance
DrawToolShape.tolerance = fcgeometry.drawing_tolerance * 10
self.select_tool("select")
if self.app.defaults['geometry_spindledir'] == 'CW':
if self.app.defaults['geometry_editor_milling_type'] == 'cl':
milling_type = 1 # CCW motion = climb milling (spindle is rotating CW)
else:
milling_type = -1 # CW motion = conventional milling (spindle is rotating CW)
else:
if self.app.defaults['geometry_editor_milling_type'] == 'cl':
milling_type = -1 # CCW motion = climb milling (spindle is rotating CCW)
else:
milling_type = 1 # CW motion = conventional milling (spindle is rotating CCW)
# Link shapes into editor.
if multigeo_tool:
self.multigeo_tool = multigeo_tool
geo_to_edit = self.flatten(geometry=fcgeometry.tools[self.multigeo_tool]['solid_geometry'],
orient_val=milling_type)
self.app.inform.emit(
'[WARNING_NOTCL] %s: %s %s: %s' % (
_("Editing MultiGeo Geometry, tool"),
str(self.multigeo_tool),
_("with diameter"),
str(fcgeometry.tools[self.multigeo_tool]['tooldia'])
)
)
else:
geo_to_edit = self.flatten(geometry=fcgeometry.solid_geometry, orient_val=milling_type)
for shape in geo_to_edit:
if shape is not None:
if type(shape) == Polygon:
self.add_shape(DrawToolShape(shape.exterior))
for inter in shape.interiors:
self.add_shape(DrawToolShape(inter))
else:
self.add_shape(DrawToolShape(shape))
self.replot()
# updated units
self.units = self.app.defaults['units'].upper()
self.decimals = self.app.decimals
# start with GRID toolbar activated
if self.app.ui.grid_snap_btn.isChecked() is False:
self.app.ui.grid_snap_btn.trigger()
def on_buffer_tool(self): def on_buffer_tool(self):
buff_tool = BufferSelectionTool(self.app, self) buff_tool = BufferSelectionTool(self.app, self)
buff_tool.run() buff_tool.run()
@ -4700,6 +4629,77 @@ class AppGeoEditor(QtCore.QObject):
return snap_x, snap_y return snap_x, snap_y
def edit_fcgeometry(self, fcgeometry, multigeo_tool=None):
"""
Imports the geometry from the given FlatCAM Geometry object
into the editor.
:param fcgeometry: GeometryObject
:param multigeo_tool: A tool for the case of the edited geometry being of type 'multigeo'
:return: None
"""
assert isinstance(fcgeometry, Geometry), "Expected a Geometry, got %s" % type(fcgeometry)
self.deactivate()
self.activate()
self.set_ui()
# Hide original geometry
self.fcgeometry = fcgeometry
fcgeometry.visible = False
# Set selection tolerance
DrawToolShape.tolerance = fcgeometry.drawing_tolerance * 10
self.select_tool("select")
if self.app.defaults['geometry_spindledir'] == 'CW':
if self.app.defaults['geometry_editor_milling_type'] == 'cl':
milling_type = 1 # CCW motion = climb milling (spindle is rotating CW)
else:
milling_type = -1 # CW motion = conventional milling (spindle is rotating CW)
else:
if self.app.defaults['geometry_editor_milling_type'] == 'cl':
milling_type = -1 # CCW motion = climb milling (spindle is rotating CCW)
else:
milling_type = 1 # CW motion = conventional milling (spindle is rotating CCW)
# Link shapes into editor.
if multigeo_tool:
self.multigeo_tool = multigeo_tool
geo_to_edit = self.flatten(geometry=fcgeometry.tools[self.multigeo_tool]['solid_geometry'],
orient_val=milling_type)
self.app.inform.emit(
'[WARNING_NOTCL] %s: %s %s: %s' % (
_("Editing MultiGeo Geometry, tool"),
str(self.multigeo_tool),
_("with diameter"),
str(fcgeometry.tools[self.multigeo_tool]['tooldia'])
)
)
else:
geo_to_edit = self.flatten(geometry=fcgeometry.solid_geometry, orient_val=milling_type)
for shape in geo_to_edit:
if shape is not None:
if type(shape) == Polygon:
self.add_shape(DrawToolShape(shape.exterior))
for inter in shape.interiors:
self.add_shape(DrawToolShape(inter))
else:
self.add_shape(DrawToolShape(shape))
self.replot()
# updated units
self.units = self.app.defaults['units'].upper()
self.decimals = self.app.decimals
# start with GRID toolbar activated
if self.app.ui.grid_snap_btn.isChecked() is False:
self.app.ui.grid_snap_btn.trigger()
def update_fcgeometry(self, fcgeometry): def update_fcgeometry(self, fcgeometry):
""" """
Transfers the geometry tool shape buffer to the selected geometry Transfers the geometry tool shape buffer to the selected geometry

View File

@ -5,7 +5,7 @@
# MIT Licence # # MIT Licence #
# ########################################################## # ##########################################################
from appGUI.GUIElements import FCFileSaveDialog, FCEntry, FCTextAreaExtended, FCTextAreaLineNumber from appGUI.GUIElements import FCFileSaveDialog, FCEntry, FCTextAreaExtended, FCTextAreaLineNumber, FCButton
from PyQt5 import QtPrintSupport, QtWidgets, QtCore, QtGui from PyQt5 import QtPrintSupport, QtWidgets, QtCore, QtGui
from reportlab.platypus import SimpleDocTemplate, Paragraph from reportlab.platypus import SimpleDocTemplate, Paragraph
@ -30,6 +30,7 @@ class AppTextEditor(QtWidgets.QWidget):
self.app = app self.app = app
self.plain_text = plain_text self.plain_text = plain_text
self.callback = lambda x: None
self.setSizePolicy( self.setSizePolicy(
QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding,
@ -71,17 +72,17 @@ class AppTextEditor(QtWidgets.QWidget):
if text: if text:
self.code_editor.setPlainText(text) self.code_editor.setPlainText(text)
self.buttonPreview = QtWidgets.QPushButton(_('Print Preview')) self.buttonPreview = FCButton(_('Print Preview'))
self.buttonPreview.setIcon(QtGui.QIcon(self.app.resource_location + '/preview32.png')) self.buttonPreview.setIcon(QtGui.QIcon(self.app.resource_location + '/preview32.png'))
self.buttonPreview.setToolTip(_("Open a OS standard Preview Print window.")) self.buttonPreview.setToolTip(_("Open a OS standard Preview Print window."))
self.buttonPreview.setMinimumWidth(100) self.buttonPreview.setMinimumWidth(100)
self.buttonPrint = QtWidgets.QPushButton(_('Print Code')) self.buttonPrint = FCButton(_('Print Code'))
self.buttonPrint.setIcon(QtGui.QIcon(self.app.resource_location + '/printer32.png')) self.buttonPrint.setIcon(QtGui.QIcon(self.app.resource_location + '/printer32.png'))
self.buttonPrint.setToolTip(_("Open a OS standard Print window.")) self.buttonPrint.setToolTip(_("Open a OS standard Print window."))
self.buttonPrint.setMinimumWidth(100) self.buttonPrint.setMinimumWidth(100)
self.buttonFind = QtWidgets.QPushButton(_('Find in Code')) self.buttonFind = FCButton(_('Find in Code'))
self.buttonFind.setIcon(QtGui.QIcon(self.app.resource_location + '/find32.png')) self.buttonFind.setIcon(QtGui.QIcon(self.app.resource_location + '/find32.png'))
self.buttonFind.setToolTip(_("Will search and highlight in yellow the string in the Find box.")) self.buttonFind.setToolTip(_("Will search and highlight in yellow the string in the Find box."))
self.buttonFind.setMinimumWidth(100) self.buttonFind.setMinimumWidth(100)
@ -89,7 +90,7 @@ class AppTextEditor(QtWidgets.QWidget):
self.entryFind = FCEntry() self.entryFind = FCEntry()
self.entryFind.setToolTip(_("Find box. Enter here the strings to be searched in the text.")) self.entryFind.setToolTip(_("Find box. Enter here the strings to be searched in the text."))
self.buttonReplace = QtWidgets.QPushButton(_('Replace With')) self.buttonReplace = FCButton(_('Replace With'))
self.buttonReplace.setIcon(QtGui.QIcon(self.app.resource_location + '/replace32.png')) self.buttonReplace.setIcon(QtGui.QIcon(self.app.resource_location + '/replace32.png'))
self.buttonReplace.setToolTip(_("Will replace the string from the Find box with the one in the Replace box.")) self.buttonReplace.setToolTip(_("Will replace the string from the Find box with the one in the Replace box."))
self.buttonReplace.setMinimumWidth(100) self.buttonReplace.setMinimumWidth(100)
@ -101,22 +102,22 @@ class AppTextEditor(QtWidgets.QWidget):
self.sel_all_cb.setToolTip(_("When checked it will replace all instances in the 'Find' box\n" self.sel_all_cb.setToolTip(_("When checked it will replace all instances in the 'Find' box\n"
"with the text in the 'Replace' box..")) "with the text in the 'Replace' box.."))
self.button_copy_all = QtWidgets.QPushButton(_('Copy All')) self.button_copy_all = FCButton(_('Copy All'))
self.button_copy_all.setIcon(QtGui.QIcon(self.app.resource_location + '/copy_file32.png')) self.button_copy_all.setIcon(QtGui.QIcon(self.app.resource_location + '/copy_file32.png'))
self.button_copy_all.setToolTip(_("Will copy all the text in the Code Editor to the clipboard.")) self.button_copy_all.setToolTip(_("Will copy all the text in the Code Editor to the clipboard."))
self.button_copy_all.setMinimumWidth(100) self.button_copy_all.setMinimumWidth(100)
self.buttonOpen = QtWidgets.QPushButton(_('Open Code')) self.buttonOpen = FCButton(_('Open Code'))
self.buttonOpen.setIcon(QtGui.QIcon(self.app.resource_location + '/folder32_bis.png')) self.buttonOpen.setIcon(QtGui.QIcon(self.app.resource_location + '/folder32_bis.png'))
self.buttonOpen.setToolTip(_("Will open a text file in the editor.")) self.buttonOpen.setToolTip(_("Will open a text file in the editor."))
self.buttonOpen.setMinimumWidth(100) self.buttonOpen.setMinimumWidth(100)
self.buttonSave = QtWidgets.QPushButton(_('Save Code')) self.buttonSave = FCButton(_('Save Code'))
self.buttonSave.setIcon(QtGui.QIcon(self.app.resource_location + '/save_as.png')) self.buttonSave.setIcon(QtGui.QIcon(self.app.resource_location + '/save_as.png'))
self.buttonSave.setToolTip(_("Will save the text in the editor into a file.")) self.buttonSave.setToolTip(_("Will save the text in the editor into a file."))
self.buttonSave.setMinimumWidth(100) self.buttonSave.setMinimumWidth(100)
self.buttonRun = QtWidgets.QPushButton(_('Run Code')) self.buttonRun = FCButton(_('Run Code'))
self.buttonRun.setToolTip(_("Will run the TCL commands found in the text file, one by one.")) self.buttonRun.setToolTip(_("Will run the TCL commands found in the text file, one by one."))
self.buttonRun.setMinimumWidth(100) self.buttonRun.setMinimumWidth(100)
@ -162,6 +163,9 @@ class AppTextEditor(QtWidgets.QWidget):
self.code_edited = '' self.code_edited = ''
def set_callback(self, callback):
self.callback = callback
def handlePrint(self): def handlePrint(self):
self.app.defaults.report_usage("handlePrint()") self.app.defaults.report_usage("handlePrint()")

View File

@ -0,0 +1,322 @@
# ##########################################################
# FlatCAM: 2D Post-processing for Manufacturing #
# File Author: Marius Adrian Stanciu (c) #
# Date: 07/22/2020 #
# MIT Licence #
# ##########################################################
from appEditors.AppTextEditor import AppTextEditor
from appObjects.FlatCAMCNCJob import CNCJobObject
from appGUI.GUIElements import FCTextArea, FCEntry, FCButton
from PyQt5 import QtWidgets, QtCore, QtGui
# from io import StringIO
import logging
import gettext
import appTranslation as fcTranslate
import builtins
fcTranslate.apply_language('strings')
if '_' not in builtins.__dict__:
_ = gettext.gettext
log = logging.getLogger('base')
class AppGCodeEditor(QtCore.QObject):
def __init__(self, app, parent=None):
super().__init__(parent=parent)
self.app = app
self.plain_text = ''
self.callback = lambda x: None
self.ui = AppGCodeEditorUI(app=self.app)
self.gcode_obj = None
self.code_edited = ''
def set_ui(self):
"""
:return:
:rtype:
"""
# #############################################################################################################
# ############# ADD a new TAB in the PLot Tab Area
# #############################################################################################################
self.ui.gcode_editor_tab = AppTextEditor(app=self.app, plain_text=True)
# add the tab if it was closed
self.app.ui.plot_tab_area.addTab(self.ui.gcode_editor_tab, '%s' % _("Code Editor"))
self.ui.gcode_editor_tab.setObjectName('code_editor_tab')
# delete the absolute and relative position and messages in the infobar
self.app.ui.position_label.setText("")
self.app.ui.rel_position_label.setText("")
self.ui.gcode_editor_tab.code_editor.completer_enable = False
self.ui.gcode_editor_tab.buttonRun.hide()
# Switch plot_area to CNCJob tab
self.app.ui.plot_tab_area.setCurrentWidget(self.ui.gcode_editor_tab)
self.ui.gcode_editor_tab.t_frame.hide()
self.ui.gcode_editor_tab.t_frame.show()
self.app.proc_container.view.set_idle()
# #############################################################################################################
# #############################################################################################################
self.ui.append_text.set_value(self.app.defaults["cncjob_append"])
self.ui.prepend_text.set_value(self.app.defaults["cncjob_prepend"])
# #################################################################################
# ################### SIGNALS #####################################################
# #################################################################################
self.ui.update_gcode_button.clicked.connect(self.insert_gcode)
self.ui.exit_editor_button.clicked.connect(self.update_fcgcode)
def build_ui(self):
"""
:return:
:rtype:
"""
# Remove anything else in the GUI Selected Tab
self.app.ui.selected_scroll_area.takeWidget()
# Put ourselves in the GUI Selected Tab
self.app.ui.selected_scroll_area.setWidget(self.ui.edit_widget)
# Switch notebook to Selected page
self.app.ui.notebook.setCurrentWidget(self.app.ui.selected_tab)
def ui_connect(self):
"""
:return:
:rtype:
"""
pass
def ui_disconnect(self):
"""
:return:
:rtype:
"""
pass
def handleTextChanged(self):
"""
:return:
:rtype:
"""
# enable = not self.ui.code_editor.document().isEmpty()
# self.ui.buttonPrint.setEnabled(enable)
# self.ui.buttonPreview.setEnabled(enable)
self.buttonSave.setStyleSheet("QPushButton {color: red;}")
self.buttonSave.setIcon(QtGui.QIcon(self.app.resource_location + '/save_as_red.png'))
def insert_gcode(self):
"""
:return:
:rtype:
"""
pass
def edit_fcgcode(self, cnc_obj):
"""
:param cnc_obj:
:type cnc_obj:
:return:
:rtype:
"""
assert isinstance(cnc_obj, CNCJobObject)
self.gcode_obj = cnc_obj
gcode_text = self.gcode_obj.source_file
self.set_ui()
self.build_ui()
# then append the text from GCode to the text editor
self.ui.gcode_editor_tab.load_text(gcode_text, move_to_start=True, clear_text=True)
self.app.inform.emit('[success] %s...' % _('Loaded Machine Code into Code Editor'))
def update_fcgcode(self):
"""
:return:
:rtype:
"""
preamble = str(self.ui.prepend_text.get_value())
postamble = str(self.ui.append_text.get_value())
my_gcode = self.ui.gcode_editor_tab.code_editor.toPlainText()
self.gcode_obj.source_file = my_gcode
self.ui.gcode_editor_tab.buttonSave.setStyleSheet("")
self.ui.gcode_editor_tab.setIcon(QtGui.QIcon(self.app.resource_location + '/save_as.png'))
def on_open_gcode(self):
"""
:return:
:rtype:
"""
_filter_ = "G-Code Files (*.nc);; G-Code Files (*.txt);; G-Code Files (*.tap);; G-Code Files (*.cnc);; " \
"All Files (*.*)"
path, _f = QtWidgets.QFileDialog.getOpenFileName(
caption=_('Open file'), directory=self.app.get_last_folder(), filter=_filter_)
if path:
file = QtCore.QFile(path)
if file.open(QtCore.QIODevice.ReadOnly):
stream = QtCore.QTextStream(file)
self.code_edited = stream.readAll()
self.ui.gcode_editor_tab.load_text(self.code_edited, move_to_start=True, clear_text=True)
file.close()
class AppGCodeEditorUI:
def __init__(self, app):
self.app = app
# Number of decimals used by tools in this class
self.decimals = self.app.decimals
# ## Current application units in Upper Case
self.units = self.app.defaults['units'].upper()
# self.setSizePolicy(
# QtWidgets.QSizePolicy.MinimumExpanding,
# QtWidgets.QSizePolicy.MinimumExpanding
# )
self.gcode_editor_tab = None
self.edit_widget = QtWidgets.QWidget()
# ## Box for custom widgets
# This gets populated in offspring implementations.
layout = QtWidgets.QVBoxLayout()
self.edit_widget.setLayout(layout)
# add a frame and inside add a vertical box layout. Inside this vbox layout I add all the Drills widgets
# this way I can hide/show the frame
self.edit_frame = QtWidgets.QFrame()
self.edit_frame.setContentsMargins(0, 0, 0, 0)
layout.addWidget(self.edit_frame)
self.edit_box = QtWidgets.QVBoxLayout()
self.edit_box.setContentsMargins(0, 0, 0, 0)
self.edit_frame.setLayout(self.edit_box)
# ## Page Title box (spacing between children)
self.title_box = QtWidgets.QHBoxLayout()
self.edit_box.addLayout(self.title_box)
# ## Page Title icon
pixmap = QtGui.QPixmap(self.app.resource_location + '/flatcam_icon32.png')
self.icon = QtWidgets.QLabel()
self.icon.setPixmap(pixmap)
self.title_box.addWidget(self.icon, stretch=0)
# ## Title label
self.title_label = QtWidgets.QLabel("<font size=5><b>%s</b></font>" % _('GCode Editor'))
self.title_label.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
self.title_box.addWidget(self.title_label, stretch=1)
# ## Object name
self.name_box = QtWidgets.QHBoxLayout()
self.edit_box.addLayout(self.name_box)
name_label = QtWidgets.QLabel(_("Name:"))
self.name_box.addWidget(name_label)
self.name_entry = FCEntry()
self.name_box.addWidget(self.name_entry)
# Prepend text to GCode
prependlabel = QtWidgets.QLabel('%s:' % _('Prepend to CNC Code'))
prependlabel.setToolTip(
_("Type here any G-Code commands you would\n"
"like to add at the beginning of the G-Code file.")
)
self.edit_box.addWidget(prependlabel)
self.prepend_text = FCTextArea()
self.prepend_text.setPlaceholderText(
_("Type here any G-Code commands you would\n"
"like to add at the beginning of the G-Code file.")
)
self.edit_box.addWidget(self.prepend_text)
# Append text to GCode
appendlabel = QtWidgets.QLabel('%s:' % _('Append to CNC Code'))
appendlabel.setToolTip(
_("Type here any G-Code commands you would\n"
"like to append to the generated file.\n"
"I.e.: M2 (End of program)")
)
self.edit_box.addWidget(appendlabel)
self.append_text = FCTextArea()
self.append_text.setPlaceholderText(
_("Type here any G-Code commands you would\n"
"like to append to the generated file.\n"
"I.e.: M2 (End of program)")
)
self.edit_box.addWidget(self.append_text)
h_lay = QtWidgets.QHBoxLayout()
h_lay.setAlignment(QtCore.Qt.AlignVCenter)
self.edit_box.addLayout(h_lay)
# GO Button
self.update_gcode_button = FCButton(_('Update Code'))
# self.update_gcode_button.setIcon(QtGui.QIcon(self.app.resource_location + '/save_as.png'))
self.update_gcode_button.setToolTip(
_("Update the Gcode in the Editor with the values\n"
"in the 'Prepend' and 'Append' text boxes.")
)
h_lay.addWidget(self.update_gcode_button)
layout.addStretch()
# Editor
self.exit_editor_button = FCButton(_('Exit Editor'))
self.exit_editor_button.setIcon(QtGui.QIcon(self.app.resource_location + '/power16.png'))
self.exit_editor_button.setToolTip(
_("Exit from Editor.")
)
self.exit_editor_button.setStyleSheet("""
QPushButton
{
font-weight: bold;
}
""")
layout.addWidget(self.exit_editor_button)
# ############################ FINSIHED GUI ##################################################################
# #############################################################################################################
def confirmation_message(self, accepted, minval, maxval):
if accepted is False:
self.app.inform[str, bool].emit('[WARNING_NOTCL] %s: [%.*f, %.*f]' % (_("Edited value is out of range"),
self.decimals,
minval,
self.decimals,
maxval), False)
else:
self.app.inform[str, bool].emit('[success] %s' % _("Edited value is within limits."), False)
def confirmation_message_int(self, accepted, minval, maxval):
if accepted is False:
self.app.inform[str, bool].emit('[WARNING_NOTCL] %s: [%d, %d]' %
(_("Edited value is out of range"), minval, maxval), False)
else:
self.app.inform[str, bool].emit('[success] %s' % _("Edited value is within limits."), False)

View File

@ -1557,8 +1557,13 @@ class FCInputDialog(QtWidgets.QInputDialog):
class FCButton(QtWidgets.QPushButton): class FCButton(QtWidgets.QPushButton):
def __init__(self, parent=None): def __init__(self, text=None, checkable=None, click_callback=None, parent=None):
super(FCButton, self).__init__(parent) super(FCButton, self).__init__(text, parent)
if not checkable is None:
self.setCheckable(checkable)
if not click_callback is None:
self.clicked.connect(click_callback)
def get_value(self): def get_value(self):
return self.isChecked() return self.isChecked()

View File

@ -1870,7 +1870,7 @@ class CNCObjectUI(ObjectUI):
self.custom_box.addWidget(self.updateplot_button) self.custom_box.addWidget(self.updateplot_button)
# Editor # Editor
self.editor_button = QtWidgets.QPushButton(_('GCode Editor')) self.editor_button = FCButton(_('GCode Editor'))
self.editor_button.setIcon(QtGui.QIcon(self.app.resource_location + '/edit_file32.png')) self.editor_button.setIcon(QtGui.QIcon(self.app.resource_location + '/edit_file32.png'))
self.editor_button.setToolTip( self.editor_button.setToolTip(

View File

@ -223,11 +223,37 @@ class AppObject(QtCore.QObject):
:return: None :return: None
""" """
outname = 'new_geo'
def initialize(obj, app): def initialize(obj, app):
obj.multitool = False obj.multitool = True
obj.multigeo = True
# store here the default data for Geometry Data
default_data = {}
self.new_object('geometry', 'new_geo', initialize, plot=False) for opt_key, opt_val in app.options.items():
if opt_key.find('geometry' + "_") == 0:
oname = opt_key[len('geometry') + 1:]
default_data[oname] = self.app.options[opt_key]
if opt_key.find('tools_mill' + "_") == 0:
oname = opt_key[len('tools_mill') + 1:]
default_data[oname] = self.app.options[opt_key]
obj.tools = {}
obj.tools.update({
1: {
'tooldia': float(app.defaults["geometry_cnctooldia"]),
'offset': 'Path',
'offset_value': 0.0,
'type': _('Rough'),
'tool_type': 'C1',
'data': deepcopy(default_data),
'solid_geometry': []
}
})
obj.tools[1]['data']['name'] = outname
self.new_object('geometry', outname, initialize, plot=False)
def new_gerber_object(self): def new_gerber_object(self):
""" """

View File

@ -149,6 +149,7 @@ class CNCJobObject(FlatCAMObj, CNCjob):
self.gcode_editor_tab = None self.gcode_editor_tab = None
self.source_file = ''
self.units_found = self.app.defaults['units'] self.units_found = self.app.defaults['units']
def build_ui(self): def build_ui(self):
@ -538,10 +539,14 @@ class CNCJobObject(FlatCAMObj, CNCjob):
self.ui.name_entry.set_value(new_name) self.ui.name_entry.set_value(new_name)
self.on_name_activate(silent=True) self.on_name_activate(silent=True)
preamble = str(self.ui.prepend_text.get_value()) try:
postamble = str(self.ui.append_text.get_value()) preamble = str(self.ui.prepend_text.get_value())
postamble = str(self.ui.append_text.get_value())
gc = self.export_gcode(filename, preamble=preamble, postamble=postamble)
except Exception as err:
log.debug("CNCJobObject.export_gcode_handler() --> %s" % str(err))
gc = self.export_gcode(filename)
gc = self.export_gcode(filename, preamble=preamble, postamble=postamble)
if gc == 'fail': if gc == 'fail':
return return
@ -590,15 +595,19 @@ class CNCJobObject(FlatCAMObj, CNCjob):
try: try:
self.gcode_editor_tab.load_text(self.app.gcode_edited.getvalue(), move_to_start=True, clear_text=True) self.gcode_editor_tab.load_text(self.app.gcode_edited.getvalue(), move_to_start=True, clear_text=True)
except Exception as e: except Exception as e:
log.debug('FlatCAMCNNJob.on_edit_code_click() -->%s' % str(e)) log.debug('FlatCAMCNCJob.on_edit_code_click() -->%s' % str(e))
self.app.inform.emit('[ERROR] %s %s' % ('FlatCAMCNNJob.on_edit_code_click() -->', str(e)))
return return
self.gcode_editor_tab.t_frame.show() self.gcode_editor_tab.t_frame.show()
self.app.proc_container.view.set_idle() self.app.proc_container.view.set_idle()
self.gcode_editor_tab.buttonSave.clicked.connect(self.on_update_source_file)
self.app.inform.emit('[success] %s...' % _('Loaded Machine Code into Code Editor')) self.app.inform.emit('[success] %s...' % _('Loaded Machine Code into Code Editor'))
def on_update_source_file(self):
self.source_file = self.gcode_editor_tab.code_editor.toPlainText()
def gcode_header(self, comment_start_symbol=None, comment_stop_symbol=None): def gcode_header(self, comment_start_symbol=None, comment_stop_symbol=None):
""" """
Will create a header to be added to all GCode files generated by FlatCAM Will create a header to be added to all GCode files generated by FlatCAM
@ -735,6 +744,11 @@ class CNCJobObject(FlatCAMObj, CNCjob):
include_header = True include_header = True
if preamble == '':
preamble = self.app.defaults["cncjob_prepend"]
if postamble == '':
preamble = self.app.defaults["cncjob_append"]
try: try:
if self.special_group: if self.special_group:
self.app.inform.emit('[WARNING_NOTCL] %s %s %s.' % self.app.inform.emit('[WARNING_NOTCL] %s %s %s.' %

View File

@ -1881,6 +1881,7 @@ class GeometryObject(FlatCAMObj, Geometry):
job_obj.z_pdepth = float(self.app.defaults["geometry_z_pdepth"]) job_obj.z_pdepth = float(self.app.defaults["geometry_z_pdepth"])
job_obj.feedrate_probe = float(self.app.defaults["geometry_feedrate_probe"]) job_obj.feedrate_probe = float(self.app.defaults["geometry_feedrate_probe"])
total_gcode = ''
for tooluid_key in list(tools_dict.keys()): for tooluid_key in list(tools_dict.keys()):
tool_cnt += 1 tool_cnt += 1
@ -1970,6 +1971,8 @@ class GeometryObject(FlatCAMObj, Geometry):
else: else:
dia_cnc_dict['gcode'] = res dia_cnc_dict['gcode'] = res
total_gcode += res
# tell gcode_parse from which point to start drawing the lines depending on what kind of # tell gcode_parse from which point to start drawing the lines depending on what kind of
# object is the source of gcode # object is the source of gcode
job_obj.toolchange_xy_type = "geometry" job_obj.toolchange_xy_type = "geometry"
@ -1993,6 +1996,8 @@ class GeometryObject(FlatCAMObj, Geometry):
}) })
dia_cnc_dict.clear() dia_cnc_dict.clear()
job_obj.source_file = total_gcode
# Object initialization function for app.app_obj.new_object() # Object initialization function for app.app_obj.new_object()
# RUNNING ON SEPARATE THREAD! # RUNNING ON SEPARATE THREAD!
def job_init_multi_geometry(job_obj, app_obj): def job_init_multi_geometry(job_obj, app_obj):
@ -2031,6 +2036,7 @@ class GeometryObject(FlatCAMObj, Geometry):
self.app.inform.emit('[ERROR_NOTCL] %s...' % _('Cancelled. Empty file, it has no geometry')) self.app.inform.emit('[ERROR_NOTCL] %s...' % _('Cancelled. Empty file, it has no geometry'))
return 'fail' return 'fail'
total_gcode = ''
for tooluid_key in list(tools_dict.keys()): for tooluid_key in list(tools_dict.keys()):
tool_cnt += 1 tool_cnt += 1
dia_cnc_dict = deepcopy(tools_dict[tooluid_key]) dia_cnc_dict = deepcopy(tools_dict[tooluid_key])
@ -2123,6 +2129,7 @@ class GeometryObject(FlatCAMObj, Geometry):
return 'fail' return 'fail'
else: else:
dia_cnc_dict['gcode'] = res dia_cnc_dict['gcode'] = res
total_gcode += res
self.app.inform.emit('[success] %s' % _("G-Code parsing in progress...")) self.app.inform.emit('[success] %s' % _("G-Code parsing in progress..."))
dia_cnc_dict['gcode_parsed'] = job_obj.gcode_parse() dia_cnc_dict['gcode_parsed'] = job_obj.gcode_parse()
@ -2149,6 +2156,8 @@ class GeometryObject(FlatCAMObj, Geometry):
}) })
dia_cnc_dict.clear() dia_cnc_dict.clear()
job_obj.source_file = total_gcode
if use_thread: if use_thread:
# To be run in separate thread # To be run in separate thread
def job_thread(a_obj): def job_thread(a_obj):
@ -2288,17 +2297,18 @@ class GeometryObject(FlatCAMObj, Geometry):
# it seems that the tolerance needs to be a lot lower value than 0.01 and it was hardcoded initially # it seems that the tolerance needs to be a lot lower value than 0.01 and it was hardcoded initially
# to a value of 0.0005 which is 20 times less than 0.01 # to a value of 0.0005 which is 20 times less than 0.01
tol = float(self.app.defaults['global_tolerance']) / 20 tol = float(self.app.defaults['global_tolerance']) / 20
job_obj.generate_from_geometry_2( res = job_obj.generate_from_geometry_2(self, tooldia=tooldia, offset=offset, tolerance=tol,
self, tooldia=tooldia, offset=offset, tolerance=tol, z_cut=z_cut, z_move=z_move, feedrate=feedrate,
z_cut=z_cut, z_move=z_move, feedrate_z=feedrate_z, feedrate_rapid=feedrate_rapid,
feedrate=feedrate, feedrate_z=feedrate_z, feedrate_rapid=feedrate_rapid, spindlespeed=spindlespeed, dwell=dwell, dwelltime=dwelltime,
spindlespeed=spindlespeed, dwell=dwell, dwelltime=dwelltime, multidepth=multidepth, depthpercut=depthperpass,
multidepth=multidepth, depthpercut=depthperpass, toolchange=toolchange, toolchangez=toolchangez,
toolchange=toolchange, toolchangez=toolchangez, toolchangexy=toolchangexy, toolchangexy=toolchangexy,
extracut=extracut, extracut_length=extracut_length, startz=startz, endz=endz, endxy=endxy, extracut=extracut, extracut_length=extracut_length,
pp_geometry_name=ppname_g startz=startz, endz=endz, endxy=endxy,
pp_geometry_name=ppname_g
) )
job_obj.source_file = res
# tell gcode_parse from which point to start drawing the lines depending on what kind of object is the # tell gcode_parse from which point to start drawing the lines depending on what kind of object is the
# source of gcode # source of gcode
job_obj.toolchange_xy_type = "geometry" job_obj.toolchange_xy_type = "geometry"

View File

@ -1797,6 +1797,7 @@ class ToolDrilling(AppTool, Excellon):
self.total_gcode_parsed += tool_gcode_parsed self.total_gcode_parsed += tool_gcode_parsed
job_obj.gcode = self.total_gcode job_obj.gcode = self.total_gcode
job_obj.source_file = self.total_gcode
job_obj.gcode_parsed = self.total_gcode_parsed job_obj.gcode_parsed = self.total_gcode_parsed
if job_obj.gcode == 'fail': if job_obj.gcode == 'fail':
return 'fail' return 'fail'

View File

@ -913,6 +913,7 @@ class SolderPaste(AppTool):
job_obj.options['xmax'] = xmax job_obj.options['xmax'] = xmax
job_obj.options['ymax'] = ymax job_obj.options['ymax'] = ymax
total_gcode = ''
for tooluid_key, tooluid_value in obj.tools.items(): for tooluid_key, tooluid_value in obj.tools.items():
# find the tool_dia associated with the tooluid_key # find the tool_dia associated with the tooluid_key
tool_dia = tooluid_value['tooldia'] tool_dia = tooluid_value['tooldia']
@ -934,6 +935,7 @@ class SolderPaste(AppTool):
return 'fail' return 'fail'
else: else:
tool_cnc_dict['gcode'] = res tool_cnc_dict['gcode'] = res
total_gcode += res
# ## PARSE GCODE # ## # ## PARSE GCODE # ##
tool_cnc_dict['gcode_parsed'] = job_obj.gcode_parse() tool_cnc_dict['gcode_parsed'] = job_obj.gcode_parse()
@ -949,6 +951,8 @@ class SolderPaste(AppTool):
}) })
tool_cnc_dict.clear() tool_cnc_dict.clear()
job_obj.source_file = total_gcode
if use_thread: if use_thread:
# To be run in separate thread # To be run in separate thread
def job_thread(app_obj): def job_thread(app_obj):

View File

@ -83,6 +83,7 @@ from appEditors.AppGeoEditor import AppGeoEditor
from appEditors.AppExcEditor import AppExcEditor from appEditors.AppExcEditor import AppExcEditor
from appEditors.AppGerberEditor import AppGerberEditor from appEditors.AppGerberEditor import AppGerberEditor
from appEditors.AppTextEditor import AppTextEditor from appEditors.AppTextEditor import AppTextEditor
from appEditors.appGCodeEditor import AppGCodeEditor
from appParsers.ParseHPGL2 import HPGL2 from appParsers.ParseHPGL2 import HPGL2
# FlatCAM Workers # FlatCAM Workers
@ -1574,6 +1575,12 @@ class App(QtCore.QObject):
self.grb_editor = AppGerberEditor(self) self.grb_editor = AppGerberEditor(self)
except Exception as es: except Exception as es:
log.debug("app_Main.__init__() --> Gerber Editor Error: %s" % str(es)) log.debug("app_Main.__init__() --> Gerber Editor Error: %s" % str(es))
try:
self.gcode_editor = AppGCodeEditor(self)
except Exception as es:
log.debug("app_Main.__init__() --> GCode Editor Error: %s" % str(es))
self.log.debug("Finished adding FlatCAM Editor's.") self.log.debug("Finished adding FlatCAM Editor's.")
self.set_ui_title(name=_("New Project - Not saved")) self.set_ui_title(name=_("New Project - Not saved"))
@ -2186,9 +2193,10 @@ class App(QtCore.QObject):
if edited_object.tools[tool]['tooldia'] == selected_tooldia: if edited_object.tools[tool]['tooldia'] == selected_tooldia:
multi_tool = tool multi_tool = tool
break break
log.debug("Editing MultiGeo Geometry with tool diameter: %s" % str(multi_tool))
self.geo_editor.edit_fcgeometry(edited_object, multigeo_tool=multi_tool) self.geo_editor.edit_fcgeometry(edited_object, multigeo_tool=multi_tool)
else: else:
log.debug("Editing SingleGeo Geometry with tool diameter.")
self.geo_editor.edit_fcgeometry(edited_object) self.geo_editor.edit_fcgeometry(edited_object)
# set call source to the Editor we go into # set call source to the Editor we go into
@ -2226,7 +2234,10 @@ class App(QtCore.QObject):
if self.ui.splitter.sizes()[0] == 0: if self.ui.splitter.sizes()[0] == 0:
self.ui.splitter.setSizes([1, 1]) self.ui.splitter.setSizes([1, 1])
edited_object.on_edit_code_click() # set call source to the Editor we go into
self.call_source = 'gcode_editor'
self.gcode_editor.edit_fcgcode(edited_object)
return return
# make sure that we can't select another object while in Editor Mode: # make sure that we can't select another object while in Editor Mode:
@ -7762,10 +7773,7 @@ class App(QtCore.QObject):
# then append the text from GCode to the text editor # then append the text from GCode to the text editor
if obj.kind == 'cncjob': if obj.kind == 'cncjob':
try: try:
file = obj.export_gcode( file = obj.export_gcode(to_file=True)
preamble=self.defaults["cncjob_prepend"],
postamble=self.defaults["cncjob_append"],
to_file=True)
if file == 'fail': if file == 'fail':
return 'fail' return 'fail'
except AttributeError: except AttributeError:
@ -8682,14 +8690,14 @@ class App(QtCore.QObject):
def job_thread_grb(app_obj): def job_thread_grb(app_obj):
ret = make_gerber() ret = make_gerber()
if ret == 'fail': if ret == 'fail':
self.inform.emit('[ERROR_NOTCL] %s' % _('Could not export Gerber file.')) self.inform.emit('[ERROR_NOTCL] %s' % _('Could not export file.'))
return return
self.worker_task.emit({'fcn': job_thread_grb, 'params': [self]}) self.worker_task.emit({'fcn': job_thread_grb, 'params': [self]})
else: else:
gret = make_gerber() gret = make_gerber()
if gret == 'fail': if gret == 'fail':
self.inform.emit('[ERROR_NOTCL] %s' % _('Could not export Gerber file.')) self.inform.emit('[ERROR_NOTCL] %s' % _('Could not export file.'))
return 'fail' return 'fail'
if local_use is not None: if local_use is not None:
return gret return gret
@ -8790,9 +8798,15 @@ class App(QtCore.QObject):
units = self.defaults['units'].upper() units = self.defaults['units'].upper()
def obj_init(geo_obj, app_obj): def obj_init(geo_obj, app_obj):
geo_obj.import_svg(filename, obj_type, units=units) if obj_type == "geometry":
geo_obj.multigeo = False geo_obj.import_svg(filename, obj_type, units=units)
geo_obj.source_file = self.export_gerber(obj_name=name, filename=None, local_use=geo_obj, use_thread=False) elif obj_type == "gerber":
geo_obj.import_svg(filename, obj_type, units=units)
geo_obj.multigeo = True
with open(filename) as f:
file_content = f.read()
geo_obj.source_file = file_content
with self.proc_container.new(_("Importing SVG")) as proc: with self.proc_container.new(_("Importing SVG")) as proc:
@ -8843,7 +8857,11 @@ class App(QtCore.QObject):
geo_obj.import_dxf_as_gerber(filename, units=units) geo_obj.import_dxf_as_gerber(filename, units=units)
else: else:
return "fail" return "fail"
geo_obj.multigeo = True geo_obj.multigeo = True
with open(filename) as f:
file_content = f.read()
geo_obj.source_file = file_content
with self.proc_container.new(_("Importing DXF")): with self.proc_container.new(_("Importing DXF")):

View File

@ -1058,7 +1058,19 @@ class Geometry(object):
geos = [translate(scale(g, 1.0, -1.0, origin=(0, 0)), yoff=h) for g in geos] geos = [translate(scale(g, 1.0, -1.0, origin=(0, 0)), yoff=h) for g in geos]
# trying to optimize the resulting geometry by merging contiguous lines # trying to optimize the resulting geometry by merging contiguous lines
geos = linemerge(geos) geos = list(self.flatten_list(geos))
geos_polys = []
geos_lines = []
for g in geos:
if isinstance(g, Polygon):
geos_polys.append(g)
else:
geos_lines.append(g)
merged_lines = linemerge(geos_lines)
geos = geos_polys
for l in merged_lines:
geos.append(l)
# Add to object # Add to object
if self.solid_geometry is None: if self.solid_geometry is None:
@ -1081,12 +1093,31 @@ class Geometry(object):
if flip: if flip:
# Change origin to bottom left # Change origin to bottom left
for i in geos_text: for i in geos_text:
_, minimy, _, maximy = i.bounds __, minimy, __, maximy = i.bounds
h2 = (maximy - minimy) * 0.5 h2 = (maximy - minimy) * 0.5
geos_text_f.append(translate(scale(i, 1.0, -1.0, origin=(0, 0)), yoff=(h + h2))) geos_text_f.append(translate(scale(i, 1.0, -1.0, origin=(0, 0)), yoff=(h + h2)))
if geos_text_f: if geos_text_f:
self.solid_geometry = self.solid_geometry + geos_text_f self.solid_geometry = self.solid_geometry + geos_text_f
tooldia = float(self.app.defaults["geometry_cnctooldia"])
tooldia = float('%.*f' % (self.decimals, tooldia))
new_data = {k: v for k, v in self.options.items()}
self.tools.update({
1: {
'tooldia': tooldia,
'offset': 'Path',
'offset_value': 0.0,
'type': _('Rough'),
'tool_type': 'C1',
'data': deepcopy(new_data),
'solid_geometry': self.solid_geometry
}
})
self.tools[1]['data']['name'] = self.options['name']
def import_dxf_as_geo(self, filename, units='MM'): def import_dxf_as_geo(self, filename, units='MM'):
""" """
Imports shapes from an DXF file into the object's geometry. Imports shapes from an DXF file into the object's geometry.
@ -1103,7 +1134,19 @@ class Geometry(object):
geos = getdxfgeo(dxf) geos = getdxfgeo(dxf)
# trying to optimize the resulting geometry by merging contiguous lines # trying to optimize the resulting geometry by merging contiguous lines
geos = linemerge(geos) geos = list(self.flatten_list(geos))
geos_polys = []
geos_lines = []
for g in geos:
if isinstance(g, Polygon):
geos_polys.append(g)
else:
geos_lines.append(g)
merged_lines = linemerge(geos_lines)
geos = geos_polys
for l in merged_lines:
geos.append(l)
# Add to object # Add to object
if self.solid_geometry is None: if self.solid_geometry is None:
@ -5176,7 +5219,8 @@ class CNCjob(Geometry):
geo_storage = {} geo_storage = {}
for geo in temp_solid_geometry: for geo in temp_solid_geometry:
geo_storage[geo.coords[0]] = geo if not geo is None:
geo_storage[geo.coords[0]] = geo
locations = list(geo_storage.keys()) locations = list(geo_storage.keys())
if opt_type == 'M': if opt_type == 'M':

111
preprocessors/Z_laser.py Normal file
View File

@ -0,0 +1,111 @@
# ##########################################################
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# File Author: Matthieu Berthomé #
# Date: 5/26/2017 #
# MIT Licence #
# ##########################################################
from appPreProcessor import *
# This post processor is configured to output code that
# is compatible with almost any version of Grbl.
class Z_laser(PreProc):
include_header = True
coordinate_format = "%.*f"
feedrate_format = '%.*f'
def start_code(self, p):
units = ' ' + str(p['units']).lower()
gcode = '(This preprocessor is used with a motion controller loaded with GRBL firmware. )\n'
gcode += '(It is for the case when it is used together with a LASER connected on the SPINDLE connector.)\n'
gcode += '(On toolchange event the laser will move to a defined Z height to change the laser dot size.)\n\n'
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 += '(Feedrate: ' + str(p['feedrate']) + units + '/min' + ')\n'
gcode += '(Feedrate rapids: ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
gcode += '(Z Focus: ' + str(p['z_move']) + 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' + '\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 += '(Laser Power (Spindle Speed): ' + str(p['spindlespeed']) + ')\n\n'
gcode += ('G20' if p.units.upper() == 'IN' else 'G21') + "\n"
gcode += 'G90\n'
gcode += 'G17\n'
gcode += 'G94'
return gcode
def startz_code(self, p):
return ''
def lift_code(self, p):
return 'M5'
def down_code(self, p):
sdir = {'CW': 'M03', 'CCW': 'M04'}[p.spindledir]
if p.spindlespeed:
return '%s S%s' % (sdir, str(p.spindlespeed))
else:
return sdir
def toolchange_code(self, p):
return 'G00 Z' + self.coordinate_format % (p.coords_decimals, p.z_move)
def up_to_zero_code(self, p):
return 'M5'
def position_code(self, p):
return ('X' + self.coordinate_format + ' Y' + self.coordinate_format) % \
(p.coords_decimals, p.x, p.coords_decimals, p.y)
def rapid_code(self, p):
return ('G00 ' + self.position_code(p)).format(**p)
def linear_code(self, p):
return ('G01 ' + self.position_code(p)).format(**p) + \
' F' + str(self.feedrate_format % (p.fr_decimals, p.feedrate))
def end_code(self, p):
coords_xy = p['xy_end']
gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + "\n")
if coords_xy and coords_xy != '':
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))
def z_feedrate_code(self, p):
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]
if p.spindlespeed:
return '%s S%s' % (sdir, str(p.spindlespeed))
else:
return sdir
def dwell_code(self, p):
return ''
def spindle_stop_code(self, p):
return 'M5'

View File

@ -332,6 +332,7 @@ class TclCommandDrillcncjob(TclCommandSignaled):
job_obj.excellon_optimization_type = opt_type job_obj.excellon_optimization_type = opt_type
ret_val = job_obj.generate_from_excellon_by_tool(obj, tools, use_ui=False) ret_val = job_obj.generate_from_excellon_by_tool(obj, tools, use_ui=False)
job_obj.source_file = ret_val
if ret_val == 'fail': if ret_val == 'fail':
return 'fail' return 'fail'