Merged in test_beta_8.909 (pull request #133)

Test beta 8.909
This commit is contained in:
Marius Stanciu 2019-02-16 14:26:12 +00:00
commit a7398961c7
30 changed files with 2168 additions and 985 deletions

File diff suppressed because it is too large Load Diff

View File

@ -2079,9 +2079,15 @@ class FlatCAMGeoEditor(QtCore.QObject):
log.debug("FlatCAMGeoEditor.__init__().entry2option() --> %s" % str(e))
return
def gridx_changed(goption, gentry):
entry2option(option=goption, entry=gentry)
# if the grid link is checked copy the value in the GridX field to GridY
if self.app.ui.grid_gap_link_cb.isChecked():
self.app.ui.grid_gap_y_entry.set_value(self.app.ui.grid_gap_x_entry.get_value())
self.app.ui.grid_gap_x_entry.setValidator(QtGui.QDoubleValidator())
self.app.ui.grid_gap_x_entry.textChanged.connect(
lambda: entry2option("global_gridx", self.app.ui.grid_gap_x_entry))
lambda: gridx_changed("global_gridx", self.app.ui.grid_gap_x_entry))
self.app.ui.grid_gap_y_entry.setValidator(QtGui.QDoubleValidator())
self.app.ui.grid_gap_y_entry.textChanged.connect(
@ -3532,6 +3538,7 @@ class FlatCAMExcEditor(QtCore.QObject):
self.new_drills = []
self.new_tools = {}
self.new_slots = {}
self.new_tool_offset = {}
# dictionary to store the tool_row and diameters in Tool_table
# it will be updated everytime self.build_ui() is called
@ -3872,7 +3879,7 @@ class FlatCAMExcEditor(QtCore.QObject):
horizontal_header.setSectionResizeMode(3, QtWidgets.QHeaderView.ResizeToContents)
# horizontal_header.setStretchLastSection(True)
self.tools_table_exc.setSortingEnabled(True)
# self.tools_table_exc.setSortingEnabled(True)
# sort by tool diameter
self.tools_table_exc.sortItems(1)
@ -3949,6 +3956,7 @@ class FlatCAMExcEditor(QtCore.QObject):
def on_tool_delete(self, dia=None):
self.is_modified = True
deleted_tool_dia_list = []
deleted_tool_offset_list = []
try:
if dia is None or dia is False:
@ -3968,6 +3976,9 @@ class FlatCAMExcEditor(QtCore.QObject):
for deleted_tool_dia in deleted_tool_dia_list:
# delete de tool offset
self.exc_obj.tool_offset.pop(float(deleted_tool_dia), None)
# delete the storage used for that tool
storage_elem = FlatCAMGeoEditor.make_storage()
self.storage_dict[deleted_tool_dia] = storage_elem
@ -3983,7 +3994,9 @@ class FlatCAMExcEditor(QtCore.QObject):
if flag_del:
for tool_to_be_deleted in flag_del:
# delete the tool
self.tool2tooldia.pop(tool_to_be_deleted, None)
# delete also the drills from points_edit dict just in case we add the tool again, we don't want to show the
# number of drills from before was deleter
self.points_edit[deleted_tool_dia] = []
@ -4023,6 +4036,11 @@ class FlatCAMExcEditor(QtCore.QObject):
self.olddia_newdia[dia_changed] = current_table_dia_edited
# update the dict that holds tool_no as key and tool_dia as value
self.tool2tooldia[key_in_tool2tooldia] = current_table_dia_edited
# update the tool offset
modified_offset = self.exc_obj.tool_offset.pop(dia_changed)
self.exc_obj.tool_offset[current_table_dia_edited] = modified_offset
self.replot()
else:
# tool diameter is already in use so we move the drills from the prior tool to the new tool
@ -4036,6 +4054,9 @@ class FlatCAMExcEditor(QtCore.QObject):
self.on_tool_delete(dia=dia_changed)
# delete the tool offset
self.exc_obj.tool_offset.pop(dia_changed, None)
# we reactivate the signals after the after the tool editing
self.tools_table_exc.itemChanged.connect(self.on_tool_edit)
# self.tools_table_exc.selectionModel().currentChanged.connect(self.on_row_selected)
@ -4222,8 +4243,9 @@ class FlatCAMExcEditor(QtCore.QObject):
self.replot()
# add a first tool in the Tool Table
self.on_tool_add(tooldia=1.00)
# add a first tool in the Tool Table but only if the Excellon Object is empty
if not self.tool2tooldia:
self.on_tool_add(tooldia=1.00)
def update_fcexcellon(self, exc_obj):
"""
@ -4290,6 +4312,9 @@ class FlatCAMExcEditor(QtCore.QObject):
spec = {"C": float(tool_dia[0])}
self.new_tools[name] = spec
# add in self.tools the 'solid_geometry' key, the value (a list) is populated bellow
self.new_tools[name]['solid_geometry'] = []
# create the self.drills for the new Excellon object (the one with edited content)
for point in tool_dia[1]:
self.new_drills.append(
@ -4298,6 +4323,9 @@ class FlatCAMExcEditor(QtCore.QObject):
'tool': str(current_tool)
}
)
# repopulate the 'solid_geometry' for each tool
poly = Point(point).buffer(float(tool_dia[0]) / 2.0, int(int(exc_obj.geo_steps_per_circle) / 4))
self.new_tools[name]['solid_geometry'].append(poly)
if self.is_modified is True:
if "_edit" in self.edited_obj_name:
@ -4315,6 +4343,8 @@ class FlatCAMExcEditor(QtCore.QObject):
if self.exc_obj.slots:
self.new_slots = self.exc_obj.slots
self.new_tool_offset = self.exc_obj.tool_offset
# reset the tool table
self.tools_table_exc.clear()
self.tools_table_exc.setHorizontalHeaderLabels(['#', 'Diameter', 'D', 'S'])
@ -4364,6 +4394,7 @@ class FlatCAMExcEditor(QtCore.QObject):
excellon_obj.drills = self.new_drills
excellon_obj.tools = self.new_tools
excellon_obj.slots = self.new_slots
excellon_obj.tool_offset = self.new_tool_offset
excellon_obj.options['name'] = outname
try:

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -642,8 +642,8 @@ class FCDetachableTab(QtWidgets.QTabWidget):
self.old_index = index
# Get the tab content
name = self.tabText(index)
# Get the tab content and add name FlatCAM to the tab so we know on which app is this tab linked
name = "FlatCAM " + self.tabText(index)
icon = self.tabIcon(index)
if icon.isNull():
icon = self.window().windowIcon()
@ -684,6 +684,8 @@ class FCDetachableTab(QtWidgets.QTabWidget):
# Remove the reference
del self.detachedTabs[name]
# make sure that we strip the 'FlatCAM' part of the detached name otherwise the tab name will be too long
name = name.partition(' ')[2]
# helps in restoring the tab to the same index that it was before was detached
insert_index = self.old_index if self.use_old_index is True else insertAt
@ -1210,7 +1212,7 @@ class FCDoubleSpinner(QtWidgets.QDoubleSpinBox):
class Dialog_box(QtWidgets.QWidget):
def __init__(self, title=None, label=None):
def __init__(self, title=None, label=None, icon=None):
"""
:param title: string with the window title
@ -1221,7 +1223,8 @@ class Dialog_box(QtWidgets.QWidget):
self.ok = False
dialog_box = QtWidgets.QInputDialog()
dialog_box.setFixedWidth(270)
dialog_box.setFixedWidth(290)
self.setWindowIcon(icon)
self.location, self.ok = dialog_box.getText(self, title, label)

View File

@ -507,17 +507,21 @@ class ObjectCollection(QtCore.QAbstractItemModel):
self.app.ui.menuprojectcopy.setEnabled(sel)
self.app.ui.menuprojectedit.setEnabled(sel)
self.app.ui.menuprojectdelete.setEnabled(sel)
self.app.ui.menuprojectsave.setEnabled(sel)
self.app.ui.menuprojectproperties.setEnabled(sel)
if sel:
self.app.ui.menuprojectgeneratecnc.setVisible(True)
self.app.ui.menuprojectedit.setVisible(True)
self.app.ui.menuprojectsave.setVisible(True)
for obj in self.get_selected():
if type(obj) != FlatCAMGeometry:
self.app.ui.menuprojectgeneratecnc.setVisible(False)
if type(obj) != FlatCAMGeometry and type(obj) != FlatCAMExcellon:
self.app.ui.menuprojectedit.setVisible(False)
if type(obj) != FlatCAMGeometry and type(obj) != FlatCAMExcellon and type(obj) != FlatCAMCNCjob:
self.app.ui.menuprojectsave.setVisible(False)
else:
self.app.ui.menuprojectgeneratecnc.setVisible(False)
@ -676,6 +680,13 @@ class ObjectCollection(QtCore.QAbstractItemModel):
if group.child_count() is 1:
self.view.setExpanded(group_index, True)
self.app.should_we_save = True
# decide if to show or hide the Notebook side of the screen
if self.app.defaults["global_project_autohide"] is True:
# always open the notebook on object added to collection
self.app.ui.splitter.setSizes([1, 1])
def get_names(self):
"""
Gets a list of the names of all objects in the collection.
@ -768,6 +779,14 @@ class ObjectCollection(QtCore.QAbstractItemModel):
# always go to the Project Tab after object deletion as it may be done with a shortcut key
self.app.ui.notebook.setCurrentWidget(self.app.ui.project_tab)
self.app.should_we_save = True
# decide if to show or hide the Notebook side of the screen
if self.app.defaults["global_project_autohide"] is True:
# hide the notebook if there are no objects in the collection
if not self.get_list():
self.app.ui.splitter.setSizes([0, 1])
def delete_all(self):
FlatCAMApp.App.log.debug(str(inspect.stack()[1][3]) + "--> OC.delete_all()")
@ -883,6 +902,20 @@ class ObjectCollection(QtCore.QAbstractItemModel):
try:
obj = current.indexes()[0].internalPointer().obj
if obj.kind == 'gerber':
self.app.inform.emit('[selected]<span style="color:%s;">%s</span> selected' %
('green', str(obj.options['name'])))
elif obj.kind == 'excellon':
self.app.inform.emit('[selected]<span style="color:%s;">%s</span> selected' %
('brown', str(obj.options['name'])))
elif obj.kind == 'cncjob':
self.app.inform.emit('[selected]<span style="color:%s;">%s</span> selected' %
('blue', str(obj.options['name'])))
elif obj.kind == 'geometry':
self.app.inform.emit('[selected]<span style="color:%s;">%s</span> selected' %
('red', str(obj.options['name'])))
except IndexError:
FlatCAMApp.App.log.debug("on_list_selection_change(): Index Error (Nothing selected?)")

View File

@ -4,6 +4,7 @@ from GUIElements import FCEntry, FloatEntry, EvalEntry, FCCheckBox, FCTable, \
LengthEntry, FCTextArea, IntEntry, RadioSet, OptionalInputSection, FCComboBox, FloatEntry2, EvalEntry2
from camlib import Excellon
class ObjectUI(QtWidgets.QWidget):
"""
Base class for the UI of FlatCAM objects. Deriving classes should
@ -31,14 +32,6 @@ class ObjectUI(QtWidgets.QWidget):
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()
layout.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)
## Box box for custom widgets
# This gets populated in offspring implementations.
self.custom_box = QtWidgets.QVBoxLayout()
@ -116,20 +109,12 @@ class GerberObjectUI(ObjectUI):
ObjectUI.__init__(self, title='Gerber Object', parent=parent)
# Plot options
self.plot_options_label = QtWidgets.QLabel("<b>Plot Options:</b>")
self.custom_box.addWidget(self.plot_options_label)
grid0 = QtWidgets.QGridLayout()
grid0.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
self.custom_box.addLayout(grid0)
# Plot CB
self.plot_cb = FCCheckBox(label='Plot ')
self.plot_options_label.setToolTip(
"Plot (show) this object."
)
self.plot_cb.setFixedWidth(50)
grid0.addWidget(self.plot_cb, 0, 0)
self.plot_options_label = QtWidgets.QLabel("<b>Plot Options:</b>")
grid0.addWidget(self.plot_options_label, 0, 0)
# Solid CB
self.solid_cb = FCCheckBox(label='Solid ')
@ -147,6 +132,69 @@ class GerberObjectUI(ObjectUI):
self.multicolored_cb.setFixedWidth(55)
grid0.addWidget(self.multicolored_cb, 0, 2)
## Object name
self.name_hlay = QtWidgets.QHBoxLayout()
self.custom_box.addLayout(self.name_hlay)
name_label = QtWidgets.QLabel("<b>Name:</b>")
self.name_entry = FCEntry()
self.name_entry.setFocusPolicy(QtCore.Qt.StrongFocus)
self.name_hlay.addWidget(name_label)
self.name_hlay.addWidget(self.name_entry)
hlay_plot = QtWidgets.QHBoxLayout()
self.custom_box.addLayout(hlay_plot)
#### Gerber Apertures ####
self.apertures_table_label = QtWidgets.QLabel('<b>Apertures Table</b>')
self.apertures_table_label.setToolTip(
"Apertures in this Gerber object."
)
hlay_plot.addWidget(self.apertures_table_label)
# Aperture Table Visibility CB
self.aperture_table_visibility_cb = FCCheckBox()
hlay_plot.addWidget(self.aperture_table_visibility_cb)
# Plot CB
self.plot_cb = FCCheckBox('Plot Object')
self.plot_cb.setToolTip(
"Plot (show) this object."
)
self.plot_cb.setLayoutDirection(QtCore.Qt.RightToLeft)
hlay_plot.addStretch()
hlay_plot.addWidget(self.plot_cb)
self.apertures_table = FCTable()
self.custom_box.addWidget(self.apertures_table)
self.apertures_table.setColumnCount(6)
self.apertures_table.setHorizontalHeaderLabels(['#', 'Code', 'Type', 'Size', 'Dim', 'P'])
self.apertures_table.setSortingEnabled(False)
self.apertures_table.horizontalHeaderItem(0).setToolTip(
"Index")
self.apertures_table.horizontalHeaderItem(1).setToolTip(
"Aperture Code")
self.apertures_table.horizontalHeaderItem(2).setToolTip(
"Type of aperture: circular, rectangle, macros etc")
self.apertures_table.horizontalHeaderItem(4).setToolTip(
"Aperture Size:")
self.apertures_table.horizontalHeaderItem(4).setToolTip(
"Aperture Dimensions:\n"
" - (width, height) for R, O type.\n"
" - (dia, nVertices) for P type")
self.apertures_table.horizontalHeaderItem(5).setToolTip(
"Toggle display of the aperture instances.")
# start with apertures table hidden
self.apertures_table.setVisible(False)
# hide the plot column. for now I can't plot individually the apertures without making the plot really ugly
self.apertures_table.setColumnHidden(5, True)
#
# self.empty_label = QtWidgets.QLabel('')
# self.custom_box.addWidget(self.empty_label)
# Isolation Routing
self.isolation_routing_label = QtWidgets.QLabel("<b>Isolation Routing:</b>")
self.isolation_routing_label.setToolTip(
@ -269,20 +317,23 @@ class GerberObjectUI(ObjectUI):
self.ois_iso = OptionalInputSection(self.follow_cb,
[self.generate_int_iso_button, self.generate_ext_iso_button], logic=False)
grid2 = QtWidgets.QGridLayout()
self.custom_box.addLayout(grid2)
## Clear non-copper regions
self.clearcopper_label = QtWidgets.QLabel("<b>Clear non-copper:</b>")
self.clearcopper_label.setToolTip(
"Create a Geometry object with\n"
"toolpaths to cut all non-copper regions."
)
self.custom_box.addWidget(self.clearcopper_label)
grid2.addWidget(self.clearcopper_label, 0, 0)
self.generate_ncc_button = QtWidgets.QPushButton('Non-Copper Clear Tool')
self.generate_ncc_button = QtWidgets.QPushButton('NCC Tool')
self.generate_ncc_button.setToolTip(
"Create the Geometry Object\n"
"for non-copper routing."
)
self.custom_box.addWidget(self.generate_ncc_button)
grid2.addWidget(self.generate_ncc_button, 0, 1)
## Board cutout
self.board_cutout_label = QtWidgets.QLabel("<b>Board cutout:</b>")
@ -291,14 +342,14 @@ class GerberObjectUI(ObjectUI):
"the PCB and separate it from\n"
"the original board."
)
self.custom_box.addWidget(self.board_cutout_label)
grid2.addWidget(self.board_cutout_label, 1, 0)
self.generate_cutout_button = QtWidgets.QPushButton('Cutout Tool')
self.generate_cutout_button.setToolTip(
"Generate the geometry for\n"
"the board cutout."
)
self.custom_box.addWidget(self.generate_cutout_button)
grid2.addWidget(self.generate_cutout_button, 1, 1)
## Non-copper regions
self.noncopper_label = QtWidgets.QLabel("<b>Non-copper regions:</b>")
@ -380,22 +431,26 @@ class ExcellonObjectUI(ObjectUI):
parent=parent)
#### Plot options ####
hlay_plot = QtWidgets.QHBoxLayout()
self.custom_box.addLayout(hlay_plot)
self.plot_options_label = QtWidgets.QLabel("<b>Plot Options:</b>")
self.custom_box.addWidget(self.plot_options_label)
grid0 = QtWidgets.QGridLayout()
self.custom_box.addLayout(grid0)
self.plot_cb = FCCheckBox(label='Plot')
self.plot_cb.setToolTip(
"Plot (show) this object."
)
grid0.addWidget(self.plot_cb, 0, 0)
self.solid_cb = FCCheckBox(label='Solid')
self.solid_cb.setToolTip(
"Solid circles."
)
grid0.addWidget(self.solid_cb, 0, 1)
hlay_plot.addWidget(self.plot_options_label)
hlay_plot.addStretch()
hlay_plot.addWidget(self.solid_cb)
## Object name
self.name_hlay = QtWidgets.QHBoxLayout()
self.custom_box.addLayout(self.name_hlay)
name_label = QtWidgets.QLabel("<b>Name:</b>")
self.name_entry = FCEntry()
self.name_entry.setFocusPolicy(QtCore.Qt.StrongFocus)
self.name_hlay.addWidget(name_label)
self.name_hlay.addWidget(self.name_entry)
# 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
@ -406,19 +461,31 @@ class ExcellonObjectUI(ObjectUI):
self.tools_box.setContentsMargins(0, 0, 0, 0)
self.drills_frame.setLayout(self.tools_box)
hlay_plot = QtWidgets.QHBoxLayout()
self.tools_box.addLayout(hlay_plot)
#### Tools Drills ####
self.tools_table_label = QtWidgets.QLabel('<b>Tools Table</b>')
self.tools_table_label.setToolTip(
"Tools in this Excellon object\n"
"when are used for drilling."
)
self.tools_box.addWidget(self.tools_table_label)
hlay_plot.addWidget(self.tools_table_label)
# Plot CB
self.plot_cb = FCCheckBox('Plot Object')
self.plot_cb.setToolTip(
"Plot (show) this object."
)
self.plot_cb.setLayoutDirection(QtCore.Qt.RightToLeft)
hlay_plot.addStretch()
hlay_plot.addWidget(self.plot_cb)
self.tools_table = FCTable()
self.tools_box.addWidget(self.tools_table)
self.tools_table.setColumnCount(4)
self.tools_table.setHorizontalHeaderLabels(['#', 'Diameter', 'D', 'S'])
self.tools_table.setColumnCount(6)
self.tools_table.setHorizontalHeaderLabels(['#', 'Diameter', 'Drills', 'Slots', 'Offset', 'P'])
self.tools_table.setSortingEnabled(False)
self.tools_table.horizontalHeaderItem(0).setToolTip(
@ -434,6 +501,12 @@ class ExcellonObjectUI(ObjectUI):
self.tools_table.horizontalHeaderItem(3).setToolTip(
"The number of Slot holes. Holes that are created by\n"
"milling them with an endmill bit.")
self.tools_table.horizontalHeaderItem(4).setToolTip(
"Some drill bits (the larger ones) need to drill deeper\n"
"to create the desired exit hole diameter due of the tip shape.\n"
"The value here can compensate the Cut Z parameter.")
self.tools_table.horizontalHeaderItem(5).setToolTip(
"Toggle display of the drills for the current tool.")
self.empty_label = QtWidgets.QLabel('')
self.tools_box.addWidget(self.empty_label)
@ -681,8 +754,17 @@ class GeometryObjectUI(ObjectUI):
super(GeometryObjectUI, self).__init__(title='Geometry Object', icon_file='share/geometry32.png', parent=parent)
# Plot options
# self.plot_options_label = QtWidgets.QLabel("<b>Plot Options:</b>")
# self.custom_box.addWidget(self.plot_options_label)
self.plot_options_label = QtWidgets.QLabel("<b>Plot Options:</b>")
self.custom_box.addWidget(self.plot_options_label)
## Object name
self.name_hlay = QtWidgets.QHBoxLayout()
self.custom_box.addLayout(self.name_hlay)
name_label = QtWidgets.QLabel("<b>Name:</b>")
self.name_entry = FCEntry()
self.name_entry.setFocusPolicy(QtCore.Qt.StrongFocus)
self.name_hlay.addWidget(name_label)
self.name_hlay.addWidget(self.name_entry)
# add a frame and inside add a vertical box layout. Inside this vbox layout I add all the Tools widgets
# this way I can hide/show the frame
@ -1117,7 +1199,7 @@ class CNCObjectUI(ObjectUI):
self.plot_options_label = QtWidgets.QLabel("<b>Plot Options:</b>")
self.custom_box.addWidget(self.plot_options_label)
self.cncplot_method_label = QtWidgets.QLabel("Plot kind:")
self.cncplot_method_label = QtWidgets.QLabel("<b>Plot kind:</b>")
self.cncplot_method_label.setToolTip(
"This selects the kind of geometries on the canvas to plot.\n"
"Those can be either of type 'Travel' which means the moves\n"
@ -1131,6 +1213,27 @@ class CNCObjectUI(ObjectUI):
{"label": "Cut", "value": "cut"}
], stretch=False)
## Object name
self.name_hlay = QtWidgets.QHBoxLayout()
self.custom_box.addLayout(self.name_hlay)
name_label = QtWidgets.QLabel("<b>Name:</b>")
self.name_entry = FCEntry()
self.name_entry.setFocusPolicy(QtCore.Qt.StrongFocus)
self.name_hlay.addWidget(name_label)
self.name_hlay.addWidget(self.name_entry)
self.t_distance_label = QtWidgets.QLabel("<b>Travelled dist.:</b>")
self.t_distance_label.setToolTip(
"This is the total travelled distance on X-Y plane.\n"
"In current units."
)
self.t_distance_entry = FCEntry()
self.t_distance_entry.setToolTip(
"This is the total travelled distance on X-Y plane.\n"
"In current units."
)
self.units_label = QtWidgets.QLabel()
f_lay = QtWidgets.QGridLayout()
f_lay.setColumnStretch(1, 1)
f_lay.setColumnStretch(2, 1)
@ -1139,6 +1242,12 @@ class CNCObjectUI(ObjectUI):
f_lay.addWidget(self.cncplot_method_label, 0, 0)
f_lay.addWidget(self.cncplot_method_combo, 0, 1)
f_lay.addWidget(QtWidgets.QLabel(''), 0, 2)
f_lay.addWidget(self.t_distance_label, 1, 0)
f_lay.addWidget(self.t_distance_entry, 1, 1)
f_lay.addWidget(self.units_label, 1, 2)
self.t_distance_label.hide()
self.t_distance_entry.setVisible(False)
e1_lbl = QtWidgets.QLabel('')
self.custom_box.addWidget(e1_lbl)

View File

@ -9,6 +9,85 @@ CAD program, and create G-Code for Isolation routing.
=================================================
16.02.2019
- added the 'Save' menu entry to the Project context menu, for CNCJob: it will export the GCode.
- added messages in info bar when selecting objects in the Project View list
- fixed DblSided Tool so it correctly creates the Alignment Drills Excellon file using the new structure
- fixed DblSided Tool so it will not crash the app if the user tries to make a mirror using no coordinates
- added some relevant status bar messages in DblSided Tool
- fixed DblSided Tool to correctly use the Box object (until now it used as reference only Gerber object in spite of Excellon or Geometry objects being available)
- fixed DblSided Tool crash when trying to create Alignment Drills object without a Tool diameter specified
- fixed DblSided Tool issue when entering Tool diameter values with comma decimal separator instead of decimal dot separator
- fixed Cutout Tool Freeform to generate cutouts with options: LR, TB. 2LR, 2TB which didn't worked previously
- fixed Excellon parser to detect correctly the units and zeros for Excellon's generated by Eagle 9.3.0
- modified the initial size of the canvas on startup
- modified the build file (make_win.py) to solve the issue with suddenly not accepting the version as Beta
- changed the initial layout to 'compact'
- updated the install scripts to uninstall a previously installed FlatCAM Beta (that has the same GUID)
15.02.2019
- rearranged the File and Edit menu's and added some explanatory tooltips on certain menu items that could be seen as cryptic
- added Excellon Export Options in Edit -> Preferences
- started to work in using the Excellon Export parameters
- remade the Excellon export function to work with parameters entered in Edit -> Preferences -> Excellon Export
- added a new entry in the Project Context Menu named 'Save'. It will actually work for Geometry and it will do Export DXF and for Excellon and it will do Export Excellon
- reworked the offer to save a project so it is done only if there are objects in the project but those objects are new and/or are modified since last project load (if an old project was loaded.)
- updated the Excellon plot function so it can plot the Excellon's from old projects
- removed the message boxes that popup on Excellon Export errors and replaced them with status bar messages
- small change in tab width so the tabs looks good in Linux, too.
14.02.2019
- added total travel distance for CNCJob object created from Excellon Object in the CNCJob Selected tab
- added 'FlatCAM ' prefix to any detached tab, for easy identification
- remade the Grids context menu (right mouse button click on canvas). Now it has values linked to the units type (inch or mm). Added ability to add or delete grid values and they are persistent.
- updated the function for the project context menu 'Generate CNC' menu entry (Action) to use the modernized function FlatCAMObj.FlatCAMGeometry.on_generatecnc_button_click()
- when linked, the grid snap on Y will copy the value in grid snap on X in real time
- in Gerber aperture table now the values are displayed in the current units set in FlatCAM
- added shortcut key 'J' (jump to location) in Editors and added an icon to the dialog popup window
- the notebook is automatically collapsed when there are no objects in the collection and it is showed when adding an object
- added new options in Edit -> Preferences -> General -> App Preferences to control if the Notebook is showed at startup and if the notebook is closed when there are no objects in the collection and showed when the collection has objects.
13.02.2019
- added new parameter for Excellon Object in Preferences: Fast Retract. If the checkbox is checked then after reaching the drill depth, the drill bit will be raised out of the hole asap.
- started to work on GUI forms simplification
- changed the Preferences GUI for Geometry and Excellon Objects to make a difference between parameters that are changed often and those that are not.
- changed the layout in the Selected Tab UI
- started to add apertures table support
- finished Gerber aperture table display
- made the Gerber aperture table not visible as default and added a checkbox that can toggle the visibility
- fixed issue with plotting in CNCJob; with Plot kind set to something else than 'all' when toggling Plot, it was defaulting to kind = 'all'
- added (and commented) an experimental FlatCAMObj.FlatCAMGerber.plot_apertures()
12.02.2019
- whenever a FlatCAM tool is activated, if the notebook side is hidden it will be unhidden
- reactivated the Voronoi classes
- added a new parameter named Offset in the Excellon tool table - work in progress
- finished work on Offset parameter in Excellon Object (Excellon Editor, camlib, FlatCAMObj updated to take this param in consideration)
- fixed a bug where in Excellon editor when editing a file, a tool was automatically added. That is supposed to happen only for empty newly created Excellon Objects.
- starting to work on storing the solid_geometry for each tool in part in Excellon Object
- stored solid_geometry of Excellon object in the self.tools dictionary
- finished the solid_geometry restore after edit in Excellon Editor
- finished plotting selection for each tool in the Excellon Tool Table
- fixed the camlib.Excellon.bounds() function for the new type of Excellon geometry therefore fixed the canvas selection, too
10.02.2019
- the SELECTED type of messages are no longer printed to shell from 2 reasons: first, too much spam and second, issue with displaying html
- on set_zero function and creation of new geometry or new excellon there is no longer a zoom fit
- repurposed shortcut key 'Delete' to delete tools in tooltable when the mouse is over the Seleted tab (with Geometry inside) or in Tools tab (when NCC Tool or Paint Tool is inside). Or in Excellon Editor when mouse is hovering the Selected tab selecting a tool, 'Delete' key will delete that tool, if on canvas 'Delete' key will delete a selected shape (drill). In rest, will delete selected objects.
- adjusted the postprocessor files so the Spindle Off command (M5) is done before the move to Toolchange Z
- adjusted the Toolchange Manual postprocessor file to have more descriptive messages on the toolchange event
- added a strong focus to the object_name entry in the Selected tab
- the keypad keyPressed are now detected correctly
- added a pause and message/warning to do a rough zero for the Z axis, in case of Toolchange_Probe_MACH3 postprocessor file
- changes in Toolchange_Probe_MACH3 postprocessor file
9.02.2019
- added a protection for when saving a file first time, it require a saved path and if none then it use the current working directory
@ -20,7 +99,7 @@ CAD program, and create G-Code for Isolation routing.
8.02.2019
- when shortcut keys 1, 2, 3 (tab selection) are activated, if the splitter left side (the notebook) is hidden it will be mae visible
- when shortcut keys 1, 2, 3 (tab selection) are activated, if the splitter left side (the notebook) is hidden it will be made visible
- changed the menu entry Toggle Grid name to Toggle Grid Snap
- fixed errors in Toggle Axis
- fixed error with shortcut key triggering twice the keyPressEvent when in the Project List View

View File

@ -40,7 +40,7 @@ class VisPyCanvas(scene.SceneCanvas):
right_padding.width_max = 0
view = self.grid_widget.add_view(row=1, col=1, border_color='black', bgcolor='white')
view.camera = Camera(aspect=1, rect=(-100,-100,500,500))
view.camera = Camera(aspect=1, rect=(-25,-25,150,150))
# Following function was removed from 'prepare_draw()' of 'Grid' class by patch,
# it is necessary to call manually

117
camlib.py
View File

@ -43,6 +43,8 @@ from rasterio.features import shapes
from xml.dom.minidom import parseString as parse_xml_string
# from scipy.spatial import KDTree, Delaunay
from ParseSVG import *
from ParseDXF import *
@ -96,6 +98,9 @@ class Geometry(object):
# Flattened geometry (list of paths only)
self.flat_geometry = []
# this is the calculated conversion factor when the file units are different than the ones in the app
self.file_units_factor = 1
# Index
self.index = None
@ -1262,6 +1267,7 @@ class Geometry(object):
self.units = units
self.scale(factor)
self.file_units_factor = factor
return factor
def to_dict(self):
@ -1843,7 +1849,7 @@ class Gerber (Geometry):
+-----------+-----------------------------------+
* ``aperture_macros`` (dictionary): Are predefined geometrical structures
that can be instanciated with different parameters in an aperture
that can be instantiated with different parameters in an aperture
definition. See ``apertures`` above. The key is the name of the macro,
and the macro itself, the value, is a ``Aperture_Macro`` object.
@ -1897,7 +1903,7 @@ class Gerber (Geometry):
self.gerber_zeros = 'L'
"""Zeros in Gerber numbers. If 'L' then remove leading zeros, if 'T' remove trailing zeros. Used during parsing.
"""
## Gerber elements ##
# Apertures {'id':{'type':chr,
# ['size':float], ['width':float],
@ -3342,7 +3348,7 @@ class Excellon(Geometry):
# Number format and units
# INCH uses 6 digits
# METRIC uses 5/6
self.units_re = re.compile(r'^(INCH|METRIC)(?:,([TL])Z)?$')
self.units_re = re.compile(r'^(INCH|METRIC)(?:,([TL])Z)?.*$')
# Tool definition/parameters (?= is look-ahead
# NOTE: This might be an overkill!
@ -3508,6 +3514,7 @@ class Excellon(Geometry):
spec = {"C": float(match.group(2))}
self.tools[str(name_tool)] = spec
log.debug(" Tool definition: %s %s" % (name_tool, spec))
spec['solid_geometry'] = []
continue
else:
log.warning("Line ignored, it's a comment: %s" % eline)
@ -3567,6 +3574,7 @@ class Excellon(Geometry):
spec = {
"C": float(match.group(2)),
}
spec['solid_geometry'] = []
self.tools[name] = spec
log.debug(" Tool definition out of header: %s %s" % (name, spec))
@ -3912,6 +3920,7 @@ class Excellon(Geometry):
# "H": float(match.group(6)),
# "Z": float(match.group(7))
}
spec['solid_geometry'] = []
self.tools[name] = spec
log.debug(" Tool definition: %s %s" % (name, spec))
continue
@ -3959,7 +3968,6 @@ class Excellon(Geometry):
#FlatCAMApp.App.inform.emit("Detected INLINE: %s" % str(eline))
continue
# Search for zeros type again because it might be alone on the line
match = re.search(r'[LT]Z',eline)
if match:
@ -4068,7 +4076,12 @@ class Excellon(Geometry):
:return: None
"""
self.solid_geometry = []
try:
# clear the solid_geometry in self.tools
for tool in self.tools:
self.tools[tool]['solid_geometry'][:] = []
for drill in self.drills:
# poly = drill['point'].buffer(self.tools[drill['tool']]["C"]/2.0)
if drill['tool'] is '':
@ -4080,7 +4093,8 @@ class Excellon(Geometry):
continue
tooldia = self.tools[drill['tool']]['C']
poly = drill['point'].buffer(tooldia / 2.0, int(int(self.geo_steps_per_circle) / 4))
self.solid_geometry.append(poly)
# self.solid_geometry.append(poly)
self.tools[drill['tool']]['solid_geometry'].append(poly)
for slot in self.slots:
slot_tooldia = self.tools[slot['tool']]['C']
@ -4089,7 +4103,9 @@ class Excellon(Geometry):
lines_string = LineString([start, stop])
poly = lines_string.buffer(slot_tooldia / 2.0, int(int(self.geo_steps_per_circle) / 4))
self.solid_geometry.append(poly)
# self.solid_geometry.append(poly)
self.tools[slot['tool']]['solid_geometry'].append(poly)
except Exception as e:
log.debug("Excellon geometry creation failed due of ERROR: %s" % str(e))
return "fail"
@ -4131,9 +4147,9 @@ class Excellon(Geometry):
# now it can get bounds for nested lists of objects
log.debug("Excellon() -> bounds()")
if self.solid_geometry is None:
log.debug("solid_geometry is None")
return 0, 0, 0, 0
# if self.solid_geometry is None:
# log.debug("solid_geometry is None")
# return 0, 0, 0, 0
def bounds_rec(obj):
if type(obj) is list:
@ -4161,8 +4177,19 @@ class Excellon(Geometry):
# it's a Shapely object, return it's bounds
return obj.bounds
bounds_coords = bounds_rec(self.solid_geometry)
return bounds_coords
minx_list = []
miny_list = []
maxx_list = []
maxy_list = []
for tool in self.tools:
minx, miny, maxx, maxy = bounds_rec(self.tools[tool]['solid_geometry'])
minx_list.append(minx)
miny_list.append(miny)
maxx_list.append(maxx)
maxy_list.append(maxy)
return (min(minx_list), min(miny_list), max(maxx_list), max(maxy_list))
def convert_units(self, units):
"""
@ -4397,6 +4424,8 @@ class CNCjob(Geometry):
self.units = units
self.z_cut = z_cut
self.tool_offset = {}
self.z_move = z_move
self.feedrate = feedrate
@ -4428,6 +4457,9 @@ class CNCjob(Geometry):
# Controls if the move from Z_Toolchange to Z_Move is done fast with G0 or normally with G1
self.f_plunge = None
# Controls if the move from Z_Cutto Z_Move is done fast with G0 or G1 until zero and then G0 to Z_move
self.f_retract = None
# how much depth the probe can probe before error
self.z_pdepth = z_pdepth if z_pdepth else None
@ -4618,6 +4650,7 @@ class CNCjob(Geometry):
self.gcode = []
self.f_plunge = self.app.defaults["excellon_f_plunge"]
self.f_retract = self.app.defaults["excellon_f_retract"]
# Initialization
gcode = self.doformat(p.start_code)
@ -4744,6 +4777,13 @@ class CNCjob(Geometry):
if self.dwell is True:
gcode += self.doformat(p.dwell_code) # Dwell time
if self.units == 'MM':
current_tooldia = float('%.2f' % float(exobj.tools[tool]["C"]))
else:
current_tooldia = float('%.3f' % float(exobj.tools[tool]["C"]))
z_offset = float(self.tool_offset[current_tooldia]) * (-1)
self.z_cut += z_offset
# Drillling!
for k in node_list:
locx = locations[k][0]
@ -4751,7 +4791,8 @@ class CNCjob(Geometry):
gcode += self.doformat(p.rapid_code, x=locx, y=locy)
gcode += self.doformat(p.down_code, x=locx, y=locy)
gcode += self.doformat(p.up_to_zero_code, x=locx, y=locy)
if self.f_retract is False:
gcode += self.doformat(p.up_to_zero_code, x=locx, y=locy)
gcode += self.doformat(p.lift_code, x=locx, y=locy)
measured_distance += abs(distance_euclidian(locx, locy, self.oldx, self.oldy))
self.oldx = locx
@ -4825,13 +4866,22 @@ class CNCjob(Geometry):
if self.dwell is True:
gcode += self.doformat(p.dwell_code) # Dwell time
if self.units == 'MM':
current_tooldia = float('%.2f' % float(exobj.tools[tool]["C"]))
else:
current_tooldia = float('%.3f' % float(exobj.tools[tool]["C"]))
z_offset = float(self.tool_offset[current_tooldia]) * (-1)
self.z_cut += z_offset
# Drillling!
for k in node_list:
locx = locations[k][0]
locy = locations[k][1]
gcode += self.doformat(p.rapid_code, x=locx, y=locy)
gcode += self.doformat(p.down_code, x=locx, y=locy)
gcode += self.doformat(p.up_to_zero_code, x=locx, y=locy)
if self.f_retract is False:
gcode += self.doformat(p.up_to_zero_code, x=locx, y=locy)
gcode += self.doformat(p.lift_code, x=locx, y=locy)
measured_distance += abs(distance_euclidian(locx, locy, self.oldx, self.oldy))
self.oldx = locx
@ -4866,6 +4916,12 @@ class CNCjob(Geometry):
if self.dwell is True:
gcode += self.doformat(p.dwell_code) # Dwell time
if self.units == 'MM':
current_tooldia = float('%.2f' % float(exobj.tools[tool]["C"]))
else:
current_tooldia = float('%.3f' % float(exobj.tools[tool]["C"]))
z_offset = float(self.tool_offset[current_tooldia]) * (-1)
self.z_cut += z_offset
# Drillling!
altPoints = []
for point in points[tool]:
@ -4874,7 +4930,8 @@ class CNCjob(Geometry):
for point in self.optimized_travelling_salesman(altPoints):
gcode += self.doformat(p.rapid_code, x=point[0], y=point[1])
gcode += self.doformat(p.down_code, x=point[0], y=point[1])
gcode += self.doformat(p.up_to_zero_code, x=point[0], y=point[1])
if self.f_retract is False:
gcode += self.doformat(p.up_to_zero_code, x=point[0], y=point[1])
gcode += self.doformat(p.lift_code, x=point[0], y=point[1])
measured_distance += abs(distance_euclidian(point[0], point[1], self.oldx, self.oldy))
self.oldx = point[0]
@ -4892,6 +4949,8 @@ class CNCjob(Geometry):
measured_distance += abs(distance_euclidian(self.oldx, self.oldy, 0, 0))
log.debug("The total travel distance including travel to end position is: %s" %
str(measured_distance) + '\n')
self.travel_distance = measured_distance
self.gcode = gcode
return 'OK'
@ -6581,19 +6640,25 @@ def parse_gerber_number(strnumber, int_digits, frac_digits, zeros):
# for pIdx, lineIndices_ in cells.items():
# dangling_lines = []
# for i1, i2 in lineIndices_:
# connections = filter(lambda (i1_, i2_): (i1, i2) != (i1_, i2_) and (i1 == i1_ or i1 == i2_ or i2 == i1_ or i2 == i2_), lineIndices_)
# p = (i1, i2)
# connections = filter(lambda k: p != k and (p[0] == k[0] or p[0] == k[1] or p[1] == k[0] or p[1] == k[1]), lineIndices_)
# # connections = filter(lambda (i1_, i2_): (i1, i2) != (i1_, i2_) and (i1 == i1_ or i1 == i2_ or i2 == i1_ or i2 == i2_), lineIndices_)
# assert 1 <= len(connections) <= 2
# if len(connections) == 1:
# dangling_lines.append((i1, i2))
# assert len(dangling_lines) in [0, 2]
# if len(dangling_lines) == 2:
# (i11, i12), (i21, i22) = dangling_lines
# s = (i11, i12)
# t = (i21, i22)
#
# # determine which line ends are unconnected
# connected = filter(lambda (i1,i2): (i1,i2) != (i11,i12) and (i1 == i11 or i2 == i11), lineIndices_)
# connected = filter(lambda k: k != s and (k[0] == s[0] or k[1] == s[0]), lineIndices_)
# # connected = filter(lambda (i1,i2): (i1,i2) != (i11,i12) and (i1 == i11 or i2 == i11), lineIndices_)
# i11Unconnected = len(connected) == 0
#
# connected = filter(lambda (i1,i2): (i1,i2) != (i21,i22) and (i1 == i21 or i2 == i21), lineIndices_)
# connected = filter(lambda k: k != t and (k[0] == t[0] or k[1] == t[0]), lineIndices_)
# # connected = filter(lambda (i1,i2): (i1,i2) != (i21,i22) and (i1 == i21 or i2 == i21), lineIndices_)
# i21Unconnected = len(connected) == 0
#
# startIdx = i11 if i11Unconnected else i12
@ -6634,7 +6699,7 @@ def parse_gerber_number(strnumber, int_digits, frac_digits, zeros):
# cells = voronoi_cell_lines(points, vertices, lineIndices)
# polys = voronoi_edges2polygons(cells)
# polylist = []
# for i in xrange(len(points)):
# for i in range(len(points)):
# poly = vertices[np.asarray(polys[i])]
# polylist.append(poly)
# return polylist
@ -6650,14 +6715,14 @@ def parse_gerber_number(strnumber, int_digits, frac_digits, zeros):
# self.polygons = []
# pass
#
# def plot_polygons(self):
# axes = plt.subplot(1, 1, 1)
#
# plt.axis([-0.05, 1.05, -0.05, 1.05])
#
# for poly in self.polygons:
# p = PolygonPatch(poly, facecolor=np.random.rand(3, 1), alpha=0.3)
# axes.add_patch(p)
# # def plot_polygons(self):
# # axes = plt.subplot(1, 1, 1)
# #
# # plt.axis([-0.05, 1.05, -0.05, 1.05])
# #
# # for poly in self.polygons:
# # p = PolygonPatch(poly, facecolor=np.random.rand(3, 1), alpha=0.3)
# # axes.add_patch(p)
#
# def init_from_csv(self, filename):
# pass

View File

@ -220,6 +220,11 @@ class ToolCalculator(FlatCAMTool):
FlatCAMTool.run(self)
self.set_tool_ui()
# if the splitter us hidden, display it
if self.app.ui.splitter.sizes()[0] == 0:
self.app.ui.splitter.setSizes([1, 1])
self.app.ui.notebook.setTabText(2, "Calc. Tool")
def install(self, icon=None, separator=None, **kwargs):

View File

@ -153,8 +153,8 @@ class ToolCutOut(FlatCAMTool):
"- one gap Left / one gap Right\n"
"- one gap on each of the 4 sides."
)
self.gaps_rect_radio = RadioSet([{'label': '2(T/B)', 'value': 'tb'},
{'label': '2(L/R)', 'value': 'lr'},
self.gaps_rect_radio = RadioSet([{'label': '2(T/B)', 'value': 'TB'},
{'label': '2(L/R)', 'value': 'LR'},
{'label': '4', 'value': '4'}])
form_layout_3.addRow(gapslabel_rect, self.gaps_rect_radio)
@ -196,6 +196,11 @@ class ToolCutOut(FlatCAMTool):
FlatCAMTool.run(self)
self.set_tool_ui()
# if the splitter us hidden, display it
if self.app.ui.splitter.sizes()[0] == 0:
self.app.ui.splitter.setSizes([1, 1])
self.app.ui.notebook.setTabText(2, "Cutout Tool")
def install(self, icon=None, separator=None, **kwargs):
@ -272,7 +277,7 @@ class ToolCutOut(FlatCAMTool):
self.app.inform.emit("[WARNING_NOTCL]Tool Diameter is zero value. Change it to a positive integer.")
return "Tool Diameter is zero value. Change it to a positive integer."
if gaps not in ['lr', 'tb', '2lr', '2tb', '4', '8']:
if gaps not in ['LR', 'TB', '2LR', '2TB', '4', '8']:
self.app.inform.emit("[WARNING_NOTCL] Gaps value can be only one of: 'lr', 'tb', '2lr', '2tb', 4 or 8. "
"Fill in a correct value and retry. ")
return
@ -313,7 +318,7 @@ class ToolCutOut(FlatCAMTool):
cutout_obj = self.app.collection.get_by_name(outname)
if int(gaps) == 8 or gaps == '2lr':
if gaps == '8' or gaps == '2LR':
subtract_rectangle(cutout_obj,
xmin - gapsize, # botleft_x
py - gapsize + lenghty / 4, # botleft_y
@ -325,7 +330,7 @@ class ToolCutOut(FlatCAMTool):
xmax + gapsize,
py + gapsize - lenghty / 4)
if int(gaps) == 8 or gaps == '2tb':
if gaps == '8' or gaps == '2TB':
subtract_rectangle(cutout_obj,
px - gapsize + lenghtx / 4,
ymin - gapsize,
@ -337,14 +342,14 @@ class ToolCutOut(FlatCAMTool):
px + gapsize - lenghtx / 4,
ymax + gapsize)
if int(gaps) == 4 or gaps == 'lr':
if gaps == '4' or gaps == 'LR':
subtract_rectangle(cutout_obj,
xmin - gapsize,
py - gapsize,
xmax + gapsize,
py + gapsize)
if int(gaps) == 4 or gaps == 'tb':
if gaps == '4' or gaps == 'TB':
subtract_rectangle(cutout_obj,
px - gapsize,
ymin - gapsize,
@ -354,6 +359,7 @@ class ToolCutOut(FlatCAMTool):
cutout_obj.plot()
self.app.inform.emit("[success] Any form CutOut operation finished.")
self.app.ui.notebook.setCurrentWidget(self.app.ui.project_tab)
self.app.should_we_save = True
def on_rectangular_cutout(self):
name = self.obj_combo.currentText()
@ -441,9 +447,9 @@ class ToolCutOut(FlatCAMTool):
[maxx, midy + hgap],
[maxx, maxy],
[midx + hgap, maxy]]
cases = {"tb": [[pts[0], pts[1], pts[4], pts[5]],
cases = {"TB": [[pts[0], pts[1], pts[4], pts[5]],
[pts[6], pts[7], pts[10], pts[11]]],
"lr": [[pts[9], pts[10], pts[1], pts[2]],
"LR": [[pts[9], pts[10], pts[1], pts[2]],
[pts[3], pts[4], pts[7], pts[8]]],
"4": [[pts[0], pts[1], pts[2]],
[pts[3], pts[4], pts[5]],

View File

@ -128,7 +128,7 @@ class DblSidedTool(FlatCAMTool):
## Point/Box
self.point_box_container = QtWidgets.QVBoxLayout()
self.pb_label = QtWidgets.QLabel("<b>Point/Box:</b>")
self.pb_label = QtWidgets.QLabel("<b>Point/Box Reference:</b>")
self.pb_label.setToolTip(
"If 'Point' is selected above it store the coordinates (x, y) through which\n"
"the mirroring axis passes.\n"
@ -210,7 +210,7 @@ class DblSidedTool(FlatCAMTool):
grid_lay2 = QtWidgets.QGridLayout()
self.layout.addLayout(grid_lay2)
self.drill_dia = LengthEntry()
self.drill_dia = FCEntry()
self.dd_label = QtWidgets.QLabel("Drill diam.:")
self.dd_label.setToolTip(
"Diameter of the drill for the "
@ -259,6 +259,11 @@ class DblSidedTool(FlatCAMTool):
FlatCAMTool.run(self)
self.set_tool_ui()
# if the splitter us hidden, display it
if self.app.ui.splitter.sizes()[0] == 0:
self.app.ui.splitter.setSizes([1, 1])
self.app.ui.notebook.setTabText(2, "2-Sided Tool")
def set_tool_ui(self):
@ -290,15 +295,41 @@ class DblSidedTool(FlatCAMTool):
else:
selection_index = self.box_combo.currentIndex()
model_index = self.app.collection.index(selection_index, 0, self.gerber_object_combo.rootModelIndex())
bb_obj = model_index.internalPointer().obj
try:
bb_obj = model_index.internalPointer().obj
except AttributeError:
model_index = self.app.collection.index(selection_index, 0, self.exc_object_combo.rootModelIndex())
try:
bb_obj = model_index.internalPointer().obj
except AttributeError:
model_index = self.app.collection.index(selection_index, 0,
self.geo_object_combo.rootModelIndex())
try:
bb_obj = model_index.internalPointer().obj
except AttributeError:
self.app.inform.emit(
"[WARNING_NOTCL] There is no Box reference object loaded. Load one and retry.")
return
xmin, ymin, xmax, ymax = bb_obj.bounds()
px = 0.5 * (xmin + xmax)
py = 0.5 * (ymin + ymax)
xscale, yscale = {"X": (1.0, -1.0), "Y": (-1.0, 1.0)}[axis]
dia = self.drill_dia.get_value()
if dia is None:
try:
dia = float(self.drill_dia.get_value())
except ValueError:
# try to convert comma to decimal point. if it's still not working error message and return
try:
dia = float(self.drill_dia.get_value().replace(',', '.'))
self.drill_dia.set_value(dia)
except ValueError:
self.app.inform.emit("[WARNING_NOTCL] Tool diameter value is missing or wrong format. "
"Add it and retry.")
return
if dia is '':
self.app.inform.emit("[WARNING_NOTCL]No value or wrong format in Drill Dia entry. Add it and retry.")
return
tools = {"1": {"C": dia}}
@ -316,6 +347,10 @@ class DblSidedTool(FlatCAMTool):
point_mirror = affinity.scale(point, xscale, yscale, origin=(px, py))
drills.append({"point": point, "tool": "1"})
drills.append({"point": point_mirror, "tool": "1"})
if 'solid_geometry' not in tools:
tools["1"]['solid_geometry'] = []
else:
tools["1"]['solid_geometry'].append(point_mirror)
def obj_init(obj_inst, app_inst):
obj_inst.tools = tools
@ -324,6 +359,7 @@ class DblSidedTool(FlatCAMTool):
self.app.new_object("excellon", "Alignment Drills", obj_init)
self.drill_values = ''
self.app.inform.emit("[success] Excellon object with alignment drills created...")
def on_mirror_gerber(self):
selection_index = self.gerber_object_combo.currentIndex()
@ -366,6 +402,7 @@ class DblSidedTool(FlatCAMTool):
fcobj.mirror(axis, [px, py])
self.app.object_changed.emit(fcobj)
fcobj.plot()
self.app.inform.emit("[success] Gerber %s was mirrored..." % str(fcobj.options['name']))
def on_mirror_exc(self):
selection_index = self.exc_object_combo.currentIndex()
@ -385,13 +422,20 @@ class DblSidedTool(FlatCAMTool):
mode = self.axis_location.get_value()
if mode == "point":
px, py = self.point_entry.get_value()
try:
px, py = self.point_entry.get_value()
except Exception as e:
log.debug("DblSidedTool.on_mirror_geo() --> %s" % str(e))
self.app.inform.emit("[WARNING_NOTCL] There are no Point coordinates in the Point field. "
"Add coords and try again ...")
return
else:
selection_index_box = self.box_combo.currentIndex()
model_index_box = self.app.collection.index(selection_index_box, 0, self.box_combo.rootModelIndex())
try:
bb_obj = model_index_box.internalPointer().obj
except Exception as e:
log.debug("DblSidedTool.on_mirror_geo() --> %s" % str(e))
self.app.inform.emit("[WARNING_NOTCL] There is no Box object loaded ...")
return
@ -402,6 +446,7 @@ class DblSidedTool(FlatCAMTool):
fcobj.mirror(axis, [px, py])
self.app.object_changed.emit(fcobj)
fcobj.plot()
self.app.inform.emit("[success] Excellon %s was mirrored..." % str(fcobj.options['name']))
def on_mirror_geo(self):
selection_index = self.geo_object_combo.currentIndex()
@ -438,6 +483,7 @@ class DblSidedTool(FlatCAMTool):
fcobj.mirror(axis, [px, py])
self.app.object_changed.emit(fcobj)
fcobj.plot()
self.app.inform.emit("[success] Geometry %s was mirrored..." % str(fcobj.options['name']))
def on_point_add(self):
val = self.app.defaults["global_point_clipboard_format"] % (self.app.pos[0], self.app.pos[1])

View File

@ -161,6 +161,11 @@ class Film(FlatCAMTool):
FlatCAMTool.run(self)
self.set_tool_ui()
# if the splitter us hidden, display it
if self.app.ui.splitter.sizes()[0] == 0:
self.app.ui.splitter.setSizes([1, 1])
self.app.ui.notebook.setTabText(2, "Film Tool")
def install(self, icon=None, separator=None, **kwargs):

View File

@ -129,6 +129,11 @@ class ToolImage(FlatCAMTool):
FlatCAMTool.run(self)
self.set_tool_ui()
# if the splitter us hidden, display it
if self.app.ui.splitter.sizes()[0] == 0:
self.app.ui.splitter.setSizes([1, 1])
self.app.ui.notebook.setTabText(2, "Image Tool")
def install(self, icon=None, separator=None, **kwargs):

View File

@ -243,6 +243,11 @@ class NonCopperClear(FlatCAMTool, Gerber):
FlatCAMTool.run(self)
self.set_tool_ui()
# if the splitter us hidden, display it
if self.app.ui.splitter.sizes()[0] == 0:
self.app.ui.splitter.setSizes([1, 1])
self.build_ui()
self.app.ui.notebook.setTabText(2, "NCC Tool")

View File

@ -299,6 +299,11 @@ class ToolPaint(FlatCAMTool, Gerber):
FlatCAMTool.run(self)
self.set_tool_ui()
# if the splitter us hidden, display it
if self.app.ui.splitter.sizes()[0] == 0:
self.app.ui.splitter.setSizes([1, 1])
self.app.ui.notebook.setTabText(2, "Paint Tool")
def on_radio_selection(self):

View File

@ -184,6 +184,11 @@ class Panelize(FlatCAMTool):
FlatCAMTool.run(self)
self.set_tool_ui()
# if the splitter us hidden, display it
if self.app.ui.splitter.sizes()[0] == 0:
self.app.ui.splitter.setSizes([1, 1])
self.app.ui.notebook.setTabText(2, "Panel. Tool")
def install(self, icon=None, separator=None, **kwargs):

View File

@ -47,6 +47,11 @@ class Properties(FlatCAMTool):
if self.app.tool_tab_locked is True:
return
self.set_tool_ui()
# if the splitter us hidden, display it
if self.app.ui.splitter.sizes()[0] == 0:
self.app.ui.splitter.setSizes([1, 1])
FlatCAMTool.run(self)
self.properties()

View File

@ -91,11 +91,11 @@ class TermWidget(QWidget):
elif style == 'err':
text = '<span style="font-weight: bold; color: red;">%s</span>' % text
elif style == 'warning':
text = '<span style="font-weight: bold; color: rgb(244, 182, 66);">%s</span>' % text
text = '<span style="font-weight: bold; color: #f4b642;">%s</span>' % text
elif style == 'success':
text = '<span style="font-weight: bold; color: rgb(8, 68, 0);">%s</span>' % text
text = '<span style="font-weight: bold; color: #084400;">%s</span>' % text
elif style == 'selected':
text = '<span style="font-weight: bold; color: rgb(0, 8, 255);">%s</span>' % text
text = ''
else:
text = '<span>%s</span>' % text # without span <br/> is ignored!!!

View File

@ -360,6 +360,11 @@ class ToolTransform(FlatCAMTool):
FlatCAMTool.run(self)
self.set_tool_ui()
# if the splitter us hidden, display it
if self.app.ui.splitter.sizes()[0] == 0:
self.app.ui.splitter.setSizes([1, 1])
self.app.ui.notebook.setTabText(2, "Transform Tool")
def install(self, icon=None, separator=None, **kwargs):

View File

@ -63,8 +63,8 @@ if platform.architecture()[0] == '64bit':
include_files=include_files,
excludes=['scipy','pytz'],
# packages=['OpenGL','numpy','vispy','ortools','google']
packages=['numpy','google', 'rasterio'] # works for Python 3.7
# packages = ['opengl', 'numpy', 'google', 'rasterio'] # works for Python 3.6.5
# packages=['numpy','google', 'rasterio'] # works for Python 3.7
packages = ['opengl', 'numpy', 'google', 'rasterio'] # works for Python 3.6.5 and Python 3.7.1
)
else:
@ -72,19 +72,19 @@ else:
include_files=include_files,
excludes=['scipy', 'pytz'],
# packages=['OpenGL','numpy','vispy','ortools','google']
packages=['numpy', 'rasterio'] # works for Python 3.7
# packages = ['opengl', 'numpy', 'google', 'rasterio'] # works for Python 3.6.5
# packages=['numpy', 'rasterio'] # works for Python 3.7
packages = ['opengl', 'numpy', 'google', 'rasterio'] # works for Python 3.6.5 and Python 3.7.1
)
print("INCLUDE_FILES", include_files)
#execfile('clean.py')
# execfile('clean.py')
setup(
name="FlatCAM",
author="Juan Pablo Caram",
version="3000",
version="8.9",
description="FlatCAM: 2D Computer Aided PCB Manufacturing",
options=dict(build_exe=buildOptions),
executables=[Executable("FlatCAM.py", icon='share/flatcam_icon48.ico', base=base)]

View File

@ -60,6 +60,9 @@ 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.)'
gcode += 'M0'
return gcode
@ -76,6 +79,7 @@ class Toolchange_Probe_MACH3(FlatCAMPostProc):
toolchangez = p.toolchangez
toolchangexy = p.toolchange_xy
f_plunge = p.f_plunge
gcode = ''
if toolchangexy is not None:
@ -98,29 +102,29 @@ class Toolchange_Probe_MACH3(FlatCAMPostProc):
no_drills = i[2]
if toolchangexy is not None:
gcode = """
gcode = """
M5
T{tool}
M5
M6
G00 Z{toolchangez}
G00 X{toolchangex} Y{toolchangey}
(MSG, Change to Tool Dia = {toolC} ||| Drills for this tool = {t_drills} ||| Tool Probing MACH3)
(MSG, Change to Tool Dia = {toolC} ||| CONNECT THE PROBE ||| Drills for this tool = {t_drills})
M0
G00 Z{z_move}
F{feedrate_probe}
G31 Z{z_pdepth}
G92 Z0
G00 Z{z_move}
G00 Z{z_in_between}
F{feedrate_probe_slow}
G31 Z{z_pdepth}
G92 Z0
G00 Z{z_move}
(MSG, Remove any clips or other devices used for probing. CNC work is resuming ...)
M0
G00 Z{z_move}
""".format(toolchangex=self.coordinate_format % (p.coords_decimals, toolchangex),
toolchangey=self.coordinate_format % (p.coords_decimals, toolchangey),
toolchangez=self.coordinate_format % (p.coords_decimals, toolchangez),
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_slow=str(self.feedrate_format % (p.fr_decimals, (p.feedrate_probe / 2))),
z_pdepth=self.coordinate_format % (p.coords_decimals, p.z_pdepth),
@ -129,25 +133,25 @@ G00 Z{z_move}
toolC=toolC_formatted)
else:
gcode = """
T{tool}
M5
T{tool}
M6
G00 Z{toolchangez}
(MSG, Change to Tool Dia = {toolC} ||| Drills for this tool = {t_drills} ||| Tool Probing MACH3)
(MSG, Change to Tool Dia = {toolC} ||| CONNECT THE PROBE ||| Drills for this tool = {t_drills})
M0
G00 Z{z_move}
F{feedrate_probe}
G31 Z{z_pdepth}
G92 Z0
G00 Z{z_move}
G00 Z{z_in_between}
F{feedrate_probe_slow}
G31 Z{z_pdepth}
G92 Z0
G00 Z{z_move}
(MSG, Remove any clips or other devices used for probing. CNC work is resuming ...)
M0
G00 Z{z_move}
""".format(toolchangez=self.coordinate_format % (p.coords_decimals, toolchangez),
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_slow=str(self.feedrate_format % (p.fr_decimals, (p.feedrate_probe / 2))),
z_pdepth=self.coordinate_format % (p.coords_decimals, p.z_pdepth),
@ -162,28 +166,28 @@ G00 Z{z_move}
else:
if toolchangexy is not None:
gcode = """
T{tool}
M5
T{tool}
M6
G00 Z{toolchangez}
G00 X{toolchangex} Y{toolchangey}
(MSG, Change to Tool Dia = {toolC} ||| Tool Probing MACH3)
(MSG, Change to Tool Dia = {toolC} ||| CONNECT THE PROBE)
M0
G00 Z{z_move}
F{feedrate_probe}
G31 Z{z_pdepth}
G92 Z0
G00 Z{z_move}
G00 Z{z_in_between}
F{feedrate_probe_slow}
G31 Z{z_pdepth}
G92 Z0
G00 Z{z_move}
(MSG, Remove any clips or other devices used for probing. CNC work is resuming ...)
M0
G00 Z{z_move}
""".format(toolchangex=self.coordinate_format % (p.coords_decimals, toolchangex),
toolchangey=self.coordinate_format % (p.coords_decimals, toolchangey),
toolchangez=self.coordinate_format % (p.coords_decimals, toolchangez),
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_slow=str(self.feedrate_format % (p.fr_decimals, (p.feedrate_probe / 2))),
z_pdepth=self.coordinate_format % (p.coords_decimals, p.z_pdepth),
@ -191,25 +195,25 @@ G00 Z{z_move}
toolC=toolC_formatted)
else:
gcode = """
T{tool}
M5
T{tool}
M6
G00 Z{toolchangez}
(MSG, Change to Tool Dia = {toolC} ||| Tool Probing MACH3)
(MSG, Change to Tool Dia = {toolC} ||| CONNECT THE PROBE)
M0
G00 Z{z_move}
F{feedrate_probe}
G31 Z{z_pdepth}
G92 Z0
G00 Z{z_move}
G00 Z{z_in_between}
F{feedrate_probe_slow}
G31 Z{z_pdepth}
G92 Z0
G00 Z{z_move}
(MSG, Remove any clips or other devices used for probing. CNC work is resuming ...)
M0
G00 Z{z_move}
""".format(toolchangez=self.coordinate_format % (p.coords_decimals, toolchangez),
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_slow=str(self.feedrate_format % (p.fr_decimals, (p.feedrate_probe / 2))),
z_pdepth=self.coordinate_format % (p.coords_decimals, p.z_pdepth),

View File

@ -97,9 +97,9 @@ class Toolchange_Probe_general(FlatCAMPostProc):
if toolchangexy is not None:
gcode = """
M5
G00 X{toolchangex} Y{toolchangey}
T{tool}
M5
M6
(MSG, Change to Tool Dia = {toolC} ||| Total drills for tool T{tool} = {t_drills})
M0
@ -111,8 +111,8 @@ M0
else:
gcode = """
T{tool}
M5
T{tool}
M6
(MSG, Change to Tool Dia = {toolC} ||| Total drills for tool T{tool} = {t_drills})
M0
@ -127,9 +127,9 @@ M0
else:
if toolchangexy is not None:
gcode = """
M5
G00 X{toolchangex} Y{toolchangey}
T{tool}
M5
M6
(MSG, Change to Tool Dia = {toolC})
M0
@ -139,8 +139,8 @@ M0
toolC=toolC_formatted)
else:
gcode = """
T{tool}
M5
T{tool}
M6
(MSG, Change to Tool Dia = {toolC})
M0""".format(tool=int(p.tool),

View File

@ -100,15 +100,18 @@ class Toolchange_manual(FlatCAMPostProc):
no_drills = i[2]
if toolchangexy is not None:
gcode = """G00 Z{toolchangez}
T{tool}
M5
gcode = """
M5
G00 Z{toolchangez}
T{tool}
G00 X{toolchangex} Y{toolchangey}
(MSG, Change to Tool Dia = {toolC} ||| Total drills for tool T{tool} = {t_drills})
M0
G01 Z0
(MSG, Adjust the tool T{tool} to touch the material and then tighten it slightly.)
M0
G00 Z{toolchangez}
(MSG, Now the tool can be tightened more securely.)
M0
""".format(toolchangex=self.coordinate_format%(p.coords_decimals, toolchangex),
toolchangey=self.coordinate_format%(p.coords_decimals, toolchangey),
@ -118,14 +121,17 @@ M0
toolC=toolC_formatted)
else:
gcode = """G00 Z{toolchangez}
T{tool}
M5
gcode = """
M5
G00 Z{toolchangez}
T{tool}
(MSG, Change to Tool Dia = {toolC} ||| Total drills for tool T{tool} = {t_drills})
M0
G01 Z0
(MSG, Adjust the tool T{tool} to touch the material and then tighten it slightly.)
M0
G00 Z{toolchangez}
(MSG, Now the tool can be tightened more securely.)
M0
""".format(
toolchangez=self.coordinate_format%(p.coords_decimals, toolchangez),
@ -139,15 +145,18 @@ M0
else:
if toolchangexy is not None:
gcode = """G00 Z{toolchangez}
T{tool}
gcode = """
M5
G00 Z{toolchangez}
T{tool}
G00 X{toolchangex}Y{toolchangey}
(MSG, Change to Tool Dia = {toolC})
M0
G01 Z0
(MSG, Adjust the tool T{tool} to touch the material and then tighten it slightly.)
M0
G00 Z{toolchangez}
(MSG, Now the tool can be tightened more securely.)
M0
""".format(toolchangex=self.coordinate_format%(p.coords_decimals, toolchangex),
toolchangey=self.coordinate_format%(p.coords_decimals, toolchangey),
@ -155,14 +164,17 @@ M0
tool=int(p.tool),
toolC=toolC_formatted)
else:
gcode = """G00 Z{toolchangez}
T{tool}
gcode = """
M5
G00 Z{toolchangez}
T{tool}
(MSG, Change to Tool Dia = {toolC})
M0
G01 Z0
(MSG, Adjust the tool T{tool} to touch the material and then tighten it slightly.)
M0
G00 Z{toolchangez}
(MSG, Now the tool can be tightened more securely.)
M0
""".format(toolchangez=self.coordinate_format%(p.coords_decimals, toolchangez),
tool=int(p.tool),

View File

@ -98,10 +98,11 @@ class default(FlatCAMPostProc):
no_drills = i[2]
if toolchangexy is not None:
gcode = """G00 Z{toolchangez}
gcode = """
M5
G00 Z{toolchangez}
G00 X{toolchangex} Y{toolchangey}
T{tool}
M5
M6
(MSG, Change to Tool Dia = {toolC} ||| Total drills for tool T{tool} = {t_drills})
M0""".format(toolchangex=self.coordinate_format % (p.coords_decimals, toolchangex),
@ -111,9 +112,10 @@ M0""".format(toolchangex=self.coordinate_format % (p.coords_decimals, toolchange
t_drills=no_drills,
toolC=toolC_formatted)
else:
gcode = """G00 Z{toolchangez}
gcode = """
M5
G00 Z{toolchangez}
T{tool}
M5
M6
(MSG, Change to Tool Dia = {toolC} ||| Total drills for tool T{tool} = {t_drills})
M0""".format(toolchangez=self.coordinate_format % (p.coords_decimals, toolchangez),
@ -126,10 +128,11 @@ M0""".format(toolchangez=self.coordinate_format % (p.coords_decimals, toolchange
else:
if toolchangexy is not None:
gcode = """G00 Z{toolchangez}
gcode = """
M5
G00 Z{toolchangez}
G00 X{toolchangex} Y{toolchangey}
T{tool}
M5
M6
(MSG, Change to Tool Dia = {toolC})
M0""".format(toolchangex=self.coordinate_format % (p.coords_decimals, toolchangex),
@ -138,9 +141,10 @@ M0""".format(toolchangex=self.coordinate_format % (p.coords_decimals, toolchange
tool=int(p.tool),
toolC=toolC_formatted)
else:
gcode = """G00 Z{toolchangez}
T{tool}
gcode = """
M5
G00 Z{toolchangez}
T{tool}
M6
(MSG, Change to Tool Dia = {toolC})
M0""".format(toolchangez=self.coordinate_format%(p.coords_decimals, toolchangez),

View File

@ -97,10 +97,11 @@ class grbl_11(FlatCAMPostProc):
no_drills = i[2]
if toolchangexy is not None:
gcode = """G00 Z{toolchangez}
gcode = """
M5
G00 Z{toolchangez}
G00 X{toolchangex} Y{toolchangey}
T{tool}
M5
M6
(MSG, Change to Tool Dia = {toolC} ||| Total drills for tool T{tool} = {t_drills})
M0""".format(toolchangex=self.coordinate_format % (p.coords_decimals, toolchangex),
@ -110,9 +111,10 @@ M0""".format(toolchangex=self.coordinate_format % (p.coords_decimals, toolchange
t_drills=no_drills,
toolC=toolC_formatted)
else:
gcode = """G00 Z{toolchangez}
gcode = """
M5
G00 Z{toolchangez}
T{tool}
M5
M6
(MSG, Change to Tool Dia = {toolC} ||| Total drills for tool T{tool} = {t_drills})
M0""".format(toolchangez=self.coordinate_format % (p.coords_decimals, toolchangez),
@ -126,11 +128,12 @@ M0""".format(toolchangez=self.coordinate_format % (p.coords_decimals, toolchange
else:
if toolchangexy is not None:
gcode = """G00 Z{toolchangez}
G00 X{toolchangex} Y{toolchangey}
gcode = """
M5
G00 Z{toolchangez}
G00 X{toolchangex} Y{toolchangey}
T{tool}
M5
M6
M6
(MSG, Change to Tool Dia = {toolC})
M0""".format(toolchangex=self.coordinate_format % (p.coords_decimals, toolchangex),
toolchangey=self.coordinate_format % (p.coords_decimals, toolchangey),
@ -138,10 +141,11 @@ M0""".format(toolchangex=self.coordinate_format % (p.coords_decimals, toolchange
tool=int(p.tool),
toolC=toolC_formatted)
else:
gcode = """G00 Z{toolchangez}
gcode = """
M5
G00 Z{toolchangez}
T{tool}
M5
M6
M6
(MSG, Change to Tool Dia = {toolC})
M0""".format(toolchangez=self.coordinate_format%(p.coords_decimals, toolchangez),
tool=int(p.tool),

View File

@ -110,9 +110,10 @@ class line_xyz(FlatCAMPostProc):
for i in p['options']['Tools_in_use']:
if i[0] == p.tool:
no_drills = i[2]
gcode = """G00 X{toolchangex} Y{toolchangey} Z{toolchangez}
gcode = """
M5
G00 X{toolchangex} Y{toolchangey} Z{toolchangez}
T{tool}
M5
M6
(MSG, Change to Tool Dia = {toolC} ||| Total drills for tool T{tool} = {t_drills})
M0""".format(toolchangex=self.coordinate_format%(p.coords_decimals, toolchangex),
@ -129,9 +130,10 @@ M0""".format(toolchangex=self.coordinate_format%(p.coords_decimals, toolchangex)
z_move=self.coordinate_format % (p.coords_decimals, p.z_move))
return gcode
else:
gcode = """G00 X{toolchangex} Y{toolchangey} Z{toolchangez}
T{tool}
gcode = """
M5
G00 X{toolchangex} Y{toolchangey} Z{toolchangez}
T{tool}
M6
(MSG, Change to Tool Dia = {toolC})
M0""".format(toolchangex=self.coordinate_format%(p.coords_decimals, toolchangex),

View File

@ -98,10 +98,11 @@ class marlin(FlatCAMPostProc):
no_drills = i[2]
if toolchangexy is not None:
gcode = """G0 Z{toolchangez}
gcode = """
M5
G0 Z{toolchangez}
G0 X{toolchangex} Y{toolchangey}
T{tool}
M5
M6
;MSG, Change to Tool Dia = {toolC}, Total drills for tool T{tool} = {t_drills}
M0""".format(toolchangex=self.coordinate_format % (p.coords_decimals, toolchangex),
@ -111,9 +112,10 @@ M0""".format(toolchangex=self.coordinate_format % (p.coords_decimals, toolchange
t_drills=no_drills,
toolC=toolC_formatted)
else:
gcode = """G0 Z{toolchangez}
T{tool}
gcode = """
M5
G0 Z{toolchangez}
T{tool}
M6
;MSG, Change to Tool Dia = {toolC}, Total drills for tool T{tool} = {t_drills}
M0""".format(toolchangez=self.coordinate_format % (p.coords_decimals, toolchangez),
@ -127,10 +129,11 @@ M0""".format(toolchangez=self.coordinate_format % (p.coords_decimals, toolchange
else:
if toolchangexy is not None:
gcode = """G0 Z{toolchangez}
gcode = """
M5
G0 Z{toolchangez}
G0 X{toolchangex} Y{toolchangey}
T{tool}
M5
M6
;MSG, Change to Tool Dia = {toolC}
M0""".format(toolchangex=self.coordinate_format % (p.coords_decimals, toolchangex),
@ -139,9 +142,10 @@ M0""".format(toolchangex=self.coordinate_format % (p.coords_decimals, toolchange
tool=int(p.tool),
toolC=toolC_formatted)
else:
gcode = """G0 Z{toolchangez}
T{tool}
gcode = """
M5
G0 Z{toolchangez}
T{tool}
M6
;MSG, Change to Tool Dia = {toolC}
M0""".format(toolchangez=self.coordinate_format%(p.coords_decimals, toolchangez),

BIN
share/notebook32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 B