609
FlatCAMApp.py
1482
FlatCAMCommon.py
1251
FlatCAMObj.py
116
FlatCAMTool.py
|
@ -9,7 +9,15 @@
|
|||
from PyQt5 import QtGui, QtCore, QtWidgets, QtWidgets
|
||||
from PyQt5.QtCore import Qt
|
||||
|
||||
from shapely.geometry import Polygon
|
||||
from shapely.geometry import Polygon, LineString
|
||||
|
||||
import gettext
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
|
||||
class FlatCAMTool(QtWidgets.QWidget):
|
||||
|
@ -98,6 +106,7 @@ class FlatCAMTool(QtWidgets.QWidget):
|
|||
|
||||
:param old_coords: old coordinates
|
||||
:param coords: new coordinates
|
||||
:param kwargs:
|
||||
:return:
|
||||
"""
|
||||
|
||||
|
@ -135,6 +144,111 @@ class FlatCAMTool(QtWidgets.QWidget):
|
|||
if self.app.is_legacy is True:
|
||||
self.app.tool_shapes.redraw()
|
||||
|
||||
def draw_selection_shape_polygon(self, points, **kwargs):
|
||||
"""
|
||||
|
||||
:param points: a list of points from which to create a Polygon
|
||||
:param kwargs:
|
||||
:return:
|
||||
"""
|
||||
if 'color' in kwargs:
|
||||
color = kwargs['color']
|
||||
else:
|
||||
color = self.app.defaults['global_sel_line']
|
||||
|
||||
if 'face_color' in kwargs:
|
||||
face_color = kwargs['face_color']
|
||||
else:
|
||||
face_color = self.app.defaults['global_sel_fill']
|
||||
|
||||
if 'face_alpha' in kwargs:
|
||||
face_alpha = kwargs['face_alpha']
|
||||
else:
|
||||
face_alpha = 0.3
|
||||
if len(points) < 3:
|
||||
sel_rect = LineString(points)
|
||||
else:
|
||||
sel_rect = Polygon(points)
|
||||
|
||||
# color_t = Color(face_color)
|
||||
# color_t.alpha = face_alpha
|
||||
|
||||
color_t = face_color[:-2] + str(hex(int(face_alpha * 255)))[2:]
|
||||
|
||||
self.app.tool_shapes.add(sel_rect, color=color, face_color=color_t, update=True,
|
||||
layer=0, tolerance=None)
|
||||
if self.app.is_legacy is True:
|
||||
self.app.tool_shapes.redraw()
|
||||
|
||||
def delete_tool_selection_shape(self):
|
||||
self.app.tool_shapes.clear()
|
||||
self.app.tool_shapes.redraw()
|
||||
|
||||
def draw_moving_selection_shape_poly(self, points, data, **kwargs):
|
||||
"""
|
||||
|
||||
:param points:
|
||||
:param data:
|
||||
:param kwargs:
|
||||
:return:
|
||||
"""
|
||||
if 'color' in kwargs:
|
||||
color = kwargs['color']
|
||||
else:
|
||||
color = self.app.defaults['global_sel_line']
|
||||
|
||||
if 'face_color' in kwargs:
|
||||
face_color = kwargs['face_color']
|
||||
else:
|
||||
face_color = self.app.defaults['global_sel_fill']
|
||||
|
||||
if 'face_alpha' in kwargs:
|
||||
face_alpha = kwargs['face_alpha']
|
||||
else:
|
||||
face_alpha = 0.3
|
||||
|
||||
temp_points = [x for x in points]
|
||||
try:
|
||||
if data != temp_points[-1]:
|
||||
temp_points.append(data)
|
||||
except IndexError:
|
||||
return
|
||||
|
||||
l_points = len(temp_points)
|
||||
if l_points == 2:
|
||||
geo = LineString(temp_points)
|
||||
elif l_points > 2:
|
||||
geo = Polygon(temp_points)
|
||||
else:
|
||||
return
|
||||
|
||||
color_t = face_color[:-2] + str(hex(int(face_alpha * 255)))[2:]
|
||||
color_t_error = "#00000000"
|
||||
|
||||
if geo.is_valid and not geo.is_empty:
|
||||
self.app.move_tool.sel_shapes.add(geo, color=color, face_color=color_t, update=True,
|
||||
layer=0, tolerance=None)
|
||||
elif not geo.is_valid:
|
||||
self.app.move_tool.sel_shapes.add(geo, color="red", face_color=color_t_error, update=True,
|
||||
layer=0, tolerance=None)
|
||||
|
||||
if self.app.is_legacy is True:
|
||||
self.app.move_tool.sel_shapes.redraw()
|
||||
|
||||
def delete_moving_selection_shape(self):
|
||||
self.app.move_tool.sel_shapes.clear()
|
||||
self.app.move_tool.sel_shapes.redraw()
|
||||
|
||||
def confirmation_message(self, accepted, minval, maxval):
|
||||
if accepted is False:
|
||||
self.app.inform.emit('[WARNING_NOTCL] %s: [%.*f, %.*f]' %
|
||||
(_("Edited value is out of range"), self.decimals, minval, self.decimals, maxval))
|
||||
else:
|
||||
self.app.inform.emit('[success] %s' % _("Edited value is within limits."))
|
||||
|
||||
def confirmation_message_int(self, accepted, minval, maxval):
|
||||
if accepted is False:
|
||||
self.app.inform.emit('[WARNING_NOTCL] %s: [%d, %d]' %
|
||||
(_("Edited value is out of range"), minval, maxval))
|
||||
else:
|
||||
self.app.inform.emit('[success] %s' % _("Edited value is within limits."))
|
||||
|
|
|
@ -338,7 +338,7 @@ class ObjectCollection(QtCore.QAbstractItemModel):
|
|||
self.app.ui.menuprojectcolor.setEnabled(False)
|
||||
|
||||
for obj in self.get_selected():
|
||||
if type(obj) == FlatCAMGerber:
|
||||
if type(obj) == FlatCAMGerber or type(obj) == FlatCAMExcellon:
|
||||
self.app.ui.menuprojectcolor.setEnabled(True)
|
||||
|
||||
if type(obj) != FlatCAMGeometry:
|
||||
|
@ -504,7 +504,7 @@ class ObjectCollection(QtCore.QAbstractItemModel):
|
|||
name += "_1"
|
||||
obj.options["name"] = name
|
||||
|
||||
obj.set_ui(obj.ui_type(decimals=self.app.decimals))
|
||||
obj.set_ui(obj.ui_type(app=self.app))
|
||||
|
||||
# Required before appending (Qt MVC)
|
||||
group = self.group_items[obj.kind]
|
||||
|
@ -645,6 +645,59 @@ class ObjectCollection(QtCore.QAbstractItemModel):
|
|||
if not self.get_list():
|
||||
self.app.ui.splitter.setSizes([0, 1])
|
||||
|
||||
def delete_by_name(self, name, select_project=True):
|
||||
obj = self.get_by_name(name=name)
|
||||
item = obj.item
|
||||
group = self.group_items[obj.kind]
|
||||
|
||||
group_index = self.index(group.row(), 0, QtCore.QModelIndex())
|
||||
item_index = self.index(item.row(), 0, group_index)
|
||||
|
||||
deleted = item_index.internalPointer()
|
||||
group = deleted.parent_item
|
||||
|
||||
# some objects add a Tab on creation, close it here
|
||||
for idx in range(self.app.ui.plot_tab_area.count()):
|
||||
if self.app.ui.plot_tab_area.widget(idx).objectName() == deleted.obj.options['name']:
|
||||
self.app.ui.plot_tab_area.removeTab(idx)
|
||||
break
|
||||
|
||||
# update the SHELL auto-completer model data
|
||||
name = deleted.obj.options['name']
|
||||
try:
|
||||
self.app.myKeywords.remove(name)
|
||||
self.app.shell._edit.set_model_data(self.app.myKeywords)
|
||||
# this is not needed any more because now the code editor is created on demand
|
||||
# self.app.ui.code_editor.set_model_data(self.app.myKeywords)
|
||||
except Exception as e:
|
||||
log.debug(
|
||||
"delete_active() --> Could not remove the old object name from auto-completer model list. %s" % str(e))
|
||||
|
||||
self.app.object_status_changed.emit(deleted.obj, 'delete', name)
|
||||
|
||||
# ############ OBJECT DELETION FROM MODEL STARTS HERE ####################
|
||||
self.beginRemoveRows(self.index(group.row(), 0, QtCore.QModelIndex()), deleted.row(), deleted.row())
|
||||
group.remove_child(deleted)
|
||||
# after deletion of object store the current list of objects into the self.app.all_objects_list
|
||||
self.app.all_objects_list = self.get_list()
|
||||
self.endRemoveRows()
|
||||
# ############ OBJECT DELETION FROM MODEL STOPS HERE ####################
|
||||
|
||||
if self.app.is_legacy is False:
|
||||
self.app.plotcanvas.redraw()
|
||||
|
||||
if select_project:
|
||||
# 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()")
|
||||
|
||||
|
|
377
README.md
|
@ -9,15 +9,262 @@ CAD program, and create G-Code for Isolation routing.
|
|||
|
||||
=================================================
|
||||
|
||||
1.04.2020
|
||||
|
||||
- updated the SVG parser to take into consideration the 'Close' svg element and paths that are made from a single line (we may need to switch to svgpathtools module)
|
||||
|
||||
30.03.2020
|
||||
|
||||
- working to update the Paint Tool
|
||||
- fixed some issues in Paint Tool
|
||||
|
||||
29.03.2020
|
||||
|
||||
- modified the new database to accept data from NCC and Paint Tools
|
||||
- fixed issues in the new database when adding the tool in a Geometry object
|
||||
- fixed a bug in Geometry object that generated a change of dictionary while iterating over it
|
||||
- started to add the new database links in the NCC and Paint Tools
|
||||
- in the new Tools DB added ability to double click on the ID in the tree widget to execute adding a tool from DB
|
||||
- working in updating NCC Tool
|
||||
|
||||
28.03.2020
|
||||
|
||||
- finished the new database based on a QTreeWidget
|
||||
|
||||
21.03.2020
|
||||
|
||||
- fixed Cutout Tool to work with negative values for Margin parameter
|
||||
|
||||
20.03.2020
|
||||
|
||||
- updated the "re-cut" feature in Geometry object; now if the re-cut parameter is non zero it will cut half of the entered distance before the isolation end and half of it after the isolation end
|
||||
- added to Paint and NCC Tool a feature that allow polygon area selection when the reference is selected as Area Selection
|
||||
- in Paint Tool and NCC Tool added ability to use Escape Tool to cancel Area Selection and for Paint Tool to cancel Polygon Selection
|
||||
- fixed issue in "re-cut" feature when combined with multi-depth feature
|
||||
- fixed bugs in cncjob TclCommand
|
||||
|
||||
13.03.2020
|
||||
|
||||
- fixed a bug in CNCJob generation out of a Excellon object; the plot failed in case some of the geometry of the CNCJob was invalid
|
||||
- fixed Properties Tool due of recent changes to the FCTree widget
|
||||
|
||||
12.03.2020
|
||||
|
||||
- working on the new database
|
||||
- fix a bug in the TextInputTool in FlatCAM Geometry Editor that crashed the sw when some fonts are not loaded correctly
|
||||
|
||||
4.03.2020
|
||||
|
||||
- updated all the FlatCAM Tools and the Gerber UI FCComboBoxes to update the box value with the latest object loaded in the App
|
||||
- some fixes in the NCC Tool
|
||||
- modified some strings
|
||||
|
||||
02.03.2020
|
||||
|
||||
- added property that allow the FCComboBox to update the view with the last item loaded; updated the app to use this property
|
||||
|
||||
01.03.2020
|
||||
|
||||
- updated the CutOut Tool such that while adding manual gaps, the cutting geometry is updated on-the-fly if the gap size or tool diameter parameters are adjusted
|
||||
- updated the UI in Geometry Editor
|
||||
|
||||
29.02.2020
|
||||
|
||||
- compacted the NCC Tool UI by replacing some Radio buttons with Combo boxes due of too many elements
|
||||
- fixed error in CutOut Tool when trying to create a FreeFrom Cutout out of a Gerber object with the Convex Shape checked
|
||||
- working on a new type of database
|
||||
|
||||
28.02.2020
|
||||
|
||||
- some small changes in preprocessors
|
||||
- solved issue #381 where there was an error when trying to generate CNCJob out of an Excellon file that have a tool with only slots and no drills
|
||||
- solved some issues in the preprocessors regarding the newly introduced feature that allow control of the final move X,Y positions
|
||||
|
||||
25.02.2020
|
||||
|
||||
- fixed bug in Gerber parser: it tried to calculate a len() for a single element and not a list - a Gerber generated by Eagle exhibited this
|
||||
- added a new parameter named 'End Move X,Y' for the Geometry and Excellon objects. Adding a tuple of coordinates in this field will control the X,Y position of the final move; not entering a value there will cause not to make an end move
|
||||
|
||||
20.02.2020
|
||||
|
||||
- in Paint Tool replaced the Selection radio with a combobox GUI element that is more compact
|
||||
- in NCC Tool modified the UI
|
||||
|
||||
19.02.2020
|
||||
|
||||
- fixed some issues in the Geometry Editor; the jump signal disconnect was failing for repeated Editor tool operation
|
||||
- fixed an issue in Gerber Editor where the multiprocessing pool was reported as closed and an ValueError exception was raised in a certain scneraio
|
||||
- on Set Origin, Move to Origin and Move actions for Gerber and Excellon objects the source file will be also updated (the export functions will export an updated object)
|
||||
- in FlatCAMObj.export_gerber() method took into account the possibility of polygons of type 'clear' (the ones found in the Gerber files under the LPC command)
|
||||
|
||||
17.02.2020
|
||||
|
||||
- updated the Excellon UI to hold data for each tool
|
||||
- in Excellon UI removed the tools table column for Offset Z and used the UI form parameter
|
||||
- updated the Excellon Editor to add for each tool a 'data' dictionary
|
||||
- updated all FlatCAM tools to use the new confirmation message that show if the entered value is within range or outside
|
||||
- updated all FlatCAM tools to use the new confirmation message for QSpinBoxes, too
|
||||
- in Excellon UI protected the values that are common parameters from change on tool selection change
|
||||
- fixed some issues related to the usage of the new confirmation message in FlatCAM Tools
|
||||
- made sure that the FlatCAM Tools UI initialization is done only in set_tool_ui() method and not in the constructor
|
||||
- adapted the GCode generation from Excellon to work with multiple tools data and modified the preprocessors header
|
||||
- when multiple tools are selected in Excellon UI and parameters are modified it will applied to all selected
|
||||
- in Excellon UI, Paint Tool and NCC Tool finished the "Apply parameters to all tools" functionality
|
||||
- updated Paint Tool and NCC Tool in the UI functionality
|
||||
- fixed the Offset spinbox not being controller by offset checkbox in NCC Tool
|
||||
|
||||
16.02.2020
|
||||
|
||||
- small update to NCC Tool UI
|
||||
|
||||
15.02.2020
|
||||
|
||||
- in Paint Tool added a new method of painting named Combo who will pass through all the methods until the polygon is cleared
|
||||
- in Paint Tool attempting to add a new mode suitable for Laser usage
|
||||
- more work in the new Laser Mode in the Paint Tool
|
||||
- modified the Paint Tool UI
|
||||
|
||||
14.02.2020
|
||||
|
||||
- adjusted the UI for Excellon and Geometry objects
|
||||
- added a new FlatCAM Tool: Gerber Invert Tool. It will invert the copper features in a Gerber file: where is copper there will be empty and where is empty it will be copper
|
||||
- added the Preferences entries for the Gerber Invert Tool
|
||||
|
||||
13.02.2020
|
||||
|
||||
- finished Punch Gerber Tool
|
||||
- minor changes in the Tool Transform and Tool Calculators UI to bring them up2date with the other tools
|
||||
|
||||
12.02.2020
|
||||
|
||||
- working on fixing a bug in FlatCAMGeometry.merge() - FIXED issue #380
|
||||
- fixed bug: when deleting a FlatCAMCNCJob with annotations enabled, the annotations are not deleted from canvas; fixed issue #379
|
||||
- fixed bug: creating a new project while a project is open and it contain CNCJob annotations and/or Gerber mark shapes, did not delete them from canvas
|
||||
|
||||
11.02.2020
|
||||
|
||||
- working on Tool Punch; finished the geometry update with the clear geometry for the case of Excellon method
|
||||
- working on Tool Punch; finished the geometry update with the clear geometry for the case of Fixed Diameter method
|
||||
|
||||
10.02.2020
|
||||
|
||||
- optimized the Paint and NCC Tools. When the Lines type of painting/clearing is used, the lines will try to arrange themselves on the direction that the lines length clearing the polygon are bigger
|
||||
- solved bug that made drilling with Marlin preprocessor very slow
|
||||
- applied the fix for above bug to the TclCommand Drillcncjob too
|
||||
- started a new way to clear the Gerber polygons based on the 'follow' lines
|
||||
- some cleanup and bug fixes for the Paint Tool
|
||||
|
||||
|
||||
8.02.2020
|
||||
|
||||
- added a new preprocessor for using laser on a Marlin 3D printer named 'Marlin_laser_use_Spindle_pin'
|
||||
- modified the Geometry UI when using laser preprocessors
|
||||
- added a new preprocessor file for using laser on a Marlin motion controller but with the laser connected to one of the FAN pins, named 'Marlin_laser_use_FAN_pin'
|
||||
- modified the Excellon GCode generation so now it can use multi depth drilling; modified the preprocessors to show the number of passes
|
||||
|
||||
5.02.2020
|
||||
|
||||
- Modified the Distance Tool such that the Measure button can't be clicked while measuring is in progress
|
||||
- optimized selection of drills in the Excellon Editor
|
||||
- fixed bugs in multiple selection in Excellon Editor
|
||||
- fixed selection problems in Gerber Editor
|
||||
- in Distance Tool, when run in the Excellon or Gerber Editor, added a new option to snap to center of the geometry (drill for Excellon, pad for Gerber)
|
||||
|
||||
3.02.2020
|
||||
|
||||
- modified Spinbox and DoubleSpinbox Custom UI elements such that they issue a warning status message when the typed value is out of range
|
||||
- fixed the preprocessors with 'laser' in the name to use the spindle direction set in the Preferences
|
||||
- increased the upper limit for feedrates by an order of magnitude
|
||||
|
||||
2.02.2020
|
||||
|
||||
- fixed issue #376 where the V-Shape parameters from Gerber UI are not transferred to the resulting Geometry object if the 'combine' checkbox is not checked in the Gerber UI
|
||||
- in Excellon UI, if Basic application mode is selected in Preferences, the Plot column 'P' is hidden now because some inexperienced users mistake this column checkboxes for tool selection
|
||||
- fixed an error in Gerber Parser; the initial values for current_x, current_y were None but should have been 0.0
|
||||
- limited the lower limit of angle of V-tip to a value of 1 because 0 makes no sense
|
||||
- small changes in Gerber UI
|
||||
- in Geometry Editor make sure that after an edit is finished (correctly or forced) the QTree in the Editor UI is cleared of items
|
||||
|
||||
31.01.2020
|
||||
|
||||
- added a new functionality, a variation of Set Origin named Move to Origin. It will move a selection of objects to origin such as the bottom left corner of the bounding box that fit them all is in origin.
|
||||
- fixed some bugs
|
||||
- fixed a division by zero error: fixed #377
|
||||
|
||||
30.01.2020
|
||||
|
||||
- remade GUI in Tool Cutout, Tool Align Objects, Tool Panelize
|
||||
- some changed in the Excellon UI
|
||||
- some UI changes in the common object UI
|
||||
|
||||
29.01.2020
|
||||
|
||||
- changes in how the Editor exit is handled
|
||||
- small fix in some pywin32 imports
|
||||
- remade the GUI + small fixes in 2Sided Tool
|
||||
- updated 2Sided Tool
|
||||
|
||||
28.01.2020
|
||||
|
||||
- some changes in Excellon Editor
|
||||
|
||||
27.01.2020
|
||||
|
||||
- in Geometry Editor made sure that on final save, for MultiLineString geometry all the connected lines are merged into one LineString to minimize the number of vertical movements in GCode
|
||||
- more work in Punch Gerber Tool
|
||||
- the Jump To popup window will now autoselect the LineEdit therefore no more need for an extra click after launching the function
|
||||
- made some structural changes in Properties Tool
|
||||
- started to make some changes in Geometry Editor
|
||||
- finished adding in Geometry Editor a TreeWidget with the geometry shapes found in the edited object
|
||||
|
||||
24.02.2020
|
||||
|
||||
- small changes to the Toolchange manual preprocessor
|
||||
- fix for plotting Excellon objects if the color is changed and then the object is moved
|
||||
- laying the GUI for a new Tool: Punch Gerber Tool which will add holes in the Gerber apertures
|
||||
- fixed bugs in Minimum Distance Tool
|
||||
- update in the GUI for the Punch Gerber Tool
|
||||
|
||||
22.01.2020
|
||||
|
||||
- fixed a bug in the bounding box generation
|
||||
|
||||
19.01.2020
|
||||
|
||||
- fixed some bugs that are visible in Linux regarding the ArgsThread class: on app close we need to quit the QThread running the ArgsThread class and also close the opened Socket
|
||||
- make sure that the fixes above apply when rebooting app for theme change or for language change
|
||||
- fixed and issue that made setting colors for the Gerber file not possible if using a translation
|
||||
- made possible to set the colors for Excellon objects too
|
||||
- added to the possible colors the fundamentals: black and white
|
||||
- in the project context menu for setting colors added the option to set the transparency and also a default option which revert the color to the default value set in the Preferences
|
||||
|
||||
17.01.2020
|
||||
|
||||
- more changes to Excellon UI
|
||||
- changes to Geometry UI
|
||||
- more work in NCC Tool upgrade; each tool now work with it's own set of parameters
|
||||
- some updates in NCC Tool
|
||||
- optimized the object envelope generation in the redesigned NCC Tool
|
||||
|
||||
16.01.2020
|
||||
|
||||
- updated/optimized the GUI in Preferences for Paint Tool and for NCC Tool
|
||||
- work in Paint Tool to bring it up to date with NCC Tool
|
||||
- updated the GUI in preferences for Calculator Tool
|
||||
- a small change in the Excellon UI
|
||||
- updated the Excellon and Geometry UI to be similar
|
||||
- put bases for future changes to Excellon Object UI such that each tool will hold it's own parameters
|
||||
- in ParseExcellon.Excellon the self.tools dict has now a key 'data' which holds a dict with all the default values for Excellon and Geometry
|
||||
- Excellon and Geometry objects, when started with multiple tools selected, the parameters tool name reflect this situation
|
||||
- moved default_data data update from Excellon parser to the Excellon object constructor
|
||||
|
||||
15.01.2020
|
||||
|
||||
- added key shortcuts and toolbar icons for the new tools: Align Object Tool (ALT+A) and Extract Drills (ALT+I)
|
||||
- added new functionality (key shortcut SHIFT+J) to locate the corners of the bounding box (and center) in a selected object
|
||||
- modified the NCC Tool GUI to prepare for accepting a tool from a tool database
|
||||
- started to modify the Paint Tool to be similar to NCC Tool and to accept a tool from a database
|
||||
- work in Paint Tool GUI functionality
|
||||
|
||||
14.01.2020
|
||||
|
||||
|
@ -350,7 +597,7 @@ CAD program, and create G-Code for Isolation routing.
|
|||
- in Excellon UI fixed bug that did not allow editing of the Offset Z parameter from the Tool table
|
||||
- in Properties Tool added new information's for the tools in the CNCjob objects
|
||||
- few bugs solved regarding the newly created empty objects
|
||||
- changed everywhere the name "postprocessor" with "preprocessor"
|
||||
- changed everywhere the name "preprocessor" with "preprocessor"
|
||||
- updated the preprocessor files in the toolchange section in order to avoid a graphical representation of travel lines glitch
|
||||
- fixed a GUI glitch in the Excellon tool table
|
||||
- added units to some of the parameters in the Properties Tool
|
||||
|
@ -489,7 +736,7 @@ CAD program, and create G-Code for Isolation routing.
|
|||
|
||||
16.11.2019
|
||||
|
||||
- fixed issue #341 that affected both postprocessors that have inlined feedrate: marlin and repetier. THe used feedrate was the Feedrate X-Y and instead had to be Feedrate Z.
|
||||
- fixed issue #341 that affected both preprocessors that have inlined feedrate: marlin and repetier. The used feedrate was the Feedrate X-Y and instead had to be Feedrate Z.
|
||||
|
||||
15.11.2019
|
||||
|
||||
|
@ -499,7 +746,7 @@ CAD program, and create G-Code for Isolation routing.
|
|||
|
||||
14.11.2019
|
||||
|
||||
- made sure that the 'default' postprocessor file is always loaded first such that this name is always first in the GUI comboboxes
|
||||
- made sure that the 'default' preprocessor file is always loaded first such that this name is always first in the GUI comboboxes
|
||||
- added a class in GUIElements for a TextEdit box with line numbers and highlight
|
||||
|
||||
13.11.2019
|
||||
|
@ -511,7 +758,7 @@ CAD program, and create G-Code for Isolation routing.
|
|||
|
||||
12.11.2019
|
||||
|
||||
- added two new postprocessor files for ISEL CNC and for BERTA CNC
|
||||
- added two new preprocessor files for ISEL CNC and for BERTA CNC
|
||||
- clicking on a FCTable GUI element empty space will also clear the focus now
|
||||
|
||||
11.11.2019
|
||||
|
@ -1041,7 +1288,7 @@ CAD program, and create G-Code for Isolation routing.
|
|||
- more GUI optimizations related to being part of the Advanced category or not
|
||||
- added possibility to change the positive SVG exported file color in Tool Film
|
||||
- fixed some issues recently introduced in the TclCommands CNCJob, DrillCNCJob and write_gcode; changed some parameters names
|
||||
- fixed issue in the Laser postprocessor where the laser was turned on as soon as the GCode started creating an unwanted cut up until the job start
|
||||
- fixed issue in the Laser preprocessor where the laser was turned on as soon as the GCode started creating an unwanted cut up until the job start
|
||||
- added new links in Menu -> Help (Excellon, Gerber specifications and a Report Bug)
|
||||
- made the splashscreen to be showed on the current monitor on systems with multiple monitors
|
||||
- added a new entry in Menu -> View -> Redraw All which is doing what the name says: redraw all loaded objects
|
||||
|
@ -1254,7 +1501,7 @@ CAD program, and create G-Code for Isolation routing.
|
|||
- remade the NCC Tool in preparation for the newly added TclCommand CopperClear
|
||||
- finished adding the TclCommandCopperClear that can be called with alias: 'ncc'
|
||||
- added new capability in NCC Tool when the reference object is of Gerber type and fixed some newly introduced errors
|
||||
- fixed issue #298. The changes in postprocessors done in Preferences dis not update the object UI layout as it was supposed to. The selection of Marlin postproc. did not unhidden the Feedrate Rapids entry.
|
||||
- fixed issue #298. The changes in preprocessors done in Preferences dis not update the object UI layout as it was supposed to. The selection of Marlin postproc. did not unhidden the Feedrate Rapids entry.
|
||||
- fixed minor issues
|
||||
- fixed Tcl Command AddPolygon, AddPolyline
|
||||
- fixed Tcl Command CncJob
|
||||
|
@ -1780,7 +2027,7 @@ CAD program, and create G-Code for Isolation routing.
|
|||
11.05.2019
|
||||
|
||||
- fixed issue in camlib.CNCjob.generate_from_excellon_by_tool() in the drill path optimization algorithm selection when selecting the MH algorithm. The new API's for Google OR-tools required some changes and also the time parameter can be now just an integer therefore I modified the GUI
|
||||
- made the Feedrate Rapids parameter to depend on the type of postprocessor choosed. It will be showed only for a postprocessor which the name contain 'marlin' and for any postprocessor's that have 'custom' in the name
|
||||
- made the Feedrate Rapids parameter to depend on the type of preprocessor choosed. It will be showed only for a preprocessor which the name contain 'marlin' and for any preprocessor's that have 'custom' in the name
|
||||
- fixed the camlib.Gerber functions of mirror, scale, offset, skew and rotate to work with the new data structure for apertures geometry
|
||||
- fixed Gerber Editor selection to work with the new Gerber data structure in self.apertures
|
||||
- fixed Gerber Editor FCPad class to work with the new Gerber data structure in self.apertures
|
||||
|
@ -2210,7 +2457,7 @@ CAD program, and create G-Code for Isolation routing.
|
|||
|
||||
- added a fix in the Gerber parser when adding the geometry in the self.apertures dict for the case that the current aperture is None (Allegro does that)
|
||||
- finished support for internationalization by adding a set of .po/.mo files for the English language. Unfortunately the final action can be done only when Beta will be out of Beta (no more changes) or when I will decide to stop working on this app.
|
||||
- changed the tooltip for 'feedrate_rapids' parameter to point out that this parameter is useful only for the Marlin postprocessor
|
||||
- changed the tooltip for 'feedrate_rapids' parameter to point out that this parameter is useful only for the Marlin preprocessor
|
||||
- fix app crash for the case that there are no translation files
|
||||
- fixed some forgotten strings to be prepared for internationalization in ToolCalculators
|
||||
- fixed Tools menu no longer working due of changes
|
||||
|
@ -2249,7 +2496,7 @@ CAD program, and create G-Code for Isolation routing.
|
|||
|
||||
5.03.2019
|
||||
|
||||
- modified the grbl-laser postprocessor lift_code()
|
||||
- modified the grbl-laser preprocessor lift_code()
|
||||
- treated an error created by Z_Cut parameter being None
|
||||
- changed the hover and selection box transparency
|
||||
|
||||
|
@ -2302,7 +2549,7 @@ CAD program, and create G-Code for Isolation routing.
|
|||
- because adding shapes to the shapes collection (when doing Mark or Mark All) is time consuming I made the plot_aperture() threaded.
|
||||
- made the polygon fusing in modified Gerber creation, a list comprehension in an attempt for optimization
|
||||
- when right clicking the files in Project tab, the Save option for Excellon no longer export it but really save the original.
|
||||
- in ToolChange Custom Code replacement, the Text Box in the CNCJob Selected tab will be active only if there is a 'toolchange_custom' in the name of the postprocessor file. This assume that it is, or was created having as template the Toolchange Custom postprocessor file.
|
||||
- in ToolChange Custom Code replacement, the Text Box in the CNCJob Selected tab will be active only if there is a 'toolchange_custom' in the name of the preprocessor file. This assume that it is, or was created having as template the Toolchange Custom preprocessor file.
|
||||
|
||||
|
||||
25.02.2019
|
||||
|
@ -2329,7 +2576,7 @@ CAD program, and create G-Code for Isolation routing.
|
|||
- added all the Tools in a new ToolBar
|
||||
- fixed bug that after changing the layout all the toolbar actions are no longer working
|
||||
- fixed bug in Set Origin function
|
||||
- fixed a typo in Toolchange_Probe_MACH3 postprocessor
|
||||
- fixed a typo in Toolchange_Probe_MACH3 preprocessor
|
||||
|
||||
23.02.2019
|
||||
|
||||
|
@ -2340,7 +2587,7 @@ CAD program, and create G-Code for Isolation routing.
|
|||
|
||||
22.02.2019
|
||||
|
||||
- added Repetier postprocessor file
|
||||
- added Repetier preprocessor file
|
||||
- removed "added ability to regenerate objects (it's actually deletion followed by recreation)" because of the way Python pass parameters to functions by reference instead of copy
|
||||
- added ability to toggle globally the display of ToolTips. Edit -> Preferences -> General -> Enable ToolTips checkbox.
|
||||
- added true fullscreen support (for Windows OS)
|
||||
|
@ -2369,7 +2616,7 @@ CAD program, and create G-Code for Isolation routing.
|
|||
- finished added a Tool Table for Tool SolderPaste
|
||||
- working on multi tool solder paste dispensing
|
||||
- finished the Edit -> Preferences defaults section
|
||||
- finished the UI, created the postprocessor file template
|
||||
- finished the UI, created the preprocessor file template
|
||||
- finished the multi-tool solder paste dispensing: it will start using the biggest nozzle, fill the pads it can, and then go to the next smaller nozzle until there are no pads without solder.
|
||||
|
||||
19.02.2019
|
||||
|
@ -2492,12 +2739,12 @@ CAD program, and create G-Code for Isolation routing.
|
|||
- 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
|
||||
- adjusted the preprocessor files so the Spindle Off command (M5) is done before the move to Toolchange Z
|
||||
- adjusted the Toolchange Manual preprocessor 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
|
||||
- added a pause and message/warning to do a rough zero for the Z axis, in case of Toolchange_Probe_MACH3 preprocessor file
|
||||
- changes in Toolchange_Probe_MACH3 preprocessor file
|
||||
|
||||
9.02.2019
|
||||
|
||||
|
@ -2563,16 +2810,16 @@ CAD program, and create G-Code for Isolation routing.
|
|||
- added a text in the Selected Tab which is showed whenever the Selected Tab is selected but without having an object selected to display it's properties
|
||||
- added an initial text in the Tools tab
|
||||
- added possibility to use the shortcut key for shortcut list in the Notebook tabs
|
||||
- added a way to set the Probe depth if Toolchange_Probe postprocessors are selected
|
||||
- finished the postprocessor file for MACH3 tool probing on toolchange event
|
||||
- added a new parameter to set the feedrate of the probing in case the used postprocessor does probing (has toolchange_probe in it's name)
|
||||
- fixed bug in Marlin postprocessor for the Excellon files; the header and toolchange event always used the parenthesis witch is not compatible with GCode for Marlin
|
||||
- added a way to set the Probe depth if Toolchange_Probe preprocessors are selected
|
||||
- finished the preprocessor file for MACH3 tool probing on toolchange event
|
||||
- added a new parameter to set the feedrate of the probing in case the used preprocessor does probing (has toolchange_probe in it's name)
|
||||
- fixed bug in Marlin preprocessor for the Excellon files; the header and toolchange event always used the parenthesis witch is not compatible with GCode for Marlin
|
||||
- fixed a issue with a move to Z_move before any toolchange
|
||||
|
||||
4.02.2019
|
||||
|
||||
- modified the Toolchange_Probe_general postprocessor file to remove any Z moves before the actual toolchange event
|
||||
- created a prototype postprocessor file for usage with tool probing in MACH3
|
||||
- modified the Toolchange_Probe_general preprocessor file to remove any Z moves before the actual toolchange event
|
||||
- created a prototype preprocessor file for usage with tool probing in MACH3
|
||||
- added the default values for Tool Film and Tool Panelize to the Edit -> Preferences
|
||||
- added a new parameter in the Tool Film which control the thickness of the stroke width in the resulting SVG. It's a scale parameter.
|
||||
- whatever was the visibility of the corresponding toolbar when we enter in the Editor, it will be set after exit from the Editor (either Geometry Editor or Excellon Editor).
|
||||
|
@ -2599,14 +2846,14 @@ CAD program, and create G-Code for Isolation routing.
|
|||
- some GUI structure optimization's
|
||||
- added protection against entering float numbers with comma separator instead of decimal dot separator in key points of FlatCAM (not everywhere)
|
||||
- added a choice of plotting the kind of geometry for the CNC plot (all, travel and cut kind of geometries) in CNCJob Selected Tab
|
||||
- added a new postprocessor file named: 'probe_from_zmove' which allow probing to be done from z_move position on toolchange event
|
||||
- added a new preprocessor file named: 'probe_from_zmove' which allow probing to be done from z_move position on toolchange event
|
||||
- fixed the snap magnet button in Geometry Editor, restored the checkable property to True
|
||||
- some more changes in the Editors GUI in deactivate() function
|
||||
- a fix for saving as empty an edited new and empty Excellon Object
|
||||
|
||||
1.02.2019
|
||||
|
||||
- fixed postprocessor files so now the bounds values are right aligned (assuming max string length of 9 chars which means 4 digits and 4 decimals)
|
||||
- fixed preprocessor files so now the bounds values are right aligned (assuming max string length of 9 chars which means 4 digits and 4 decimals)
|
||||
- corrected small type in list_sys Tcl command; added a protection of the Plot Area Tab after a successful edit.
|
||||
- remade the way FlatCAM saves the GUI position data from a file (previously) to use PyQt QSettings
|
||||
- added a 'theme' combo selection in Edit -> Preferences. Two themes are available: standard and compact.
|
||||
|
@ -2630,7 +2877,7 @@ CAD program, and create G-Code for Isolation routing.
|
|||
|
||||
30.01.2019
|
||||
|
||||
- added a space before Y coordinate in end_code() function in some of the postprocessor files
|
||||
- added a space before Y coordinate in end_code() function in some of the preprocessor files
|
||||
- added in Calculators Tool an Electroplating Calculator.
|
||||
- remade the App Menu for Editors: now they will be showed only when the respective Editor is active and hidden when the Editor is closed.
|
||||
- added a traceback report in the TCL Shell for the errors that don't allow creation of an object; useful to trace exceptions/errors
|
||||
|
@ -2638,9 +2885,9 @@ CAD program, and create G-Code for Isolation routing.
|
|||
- fixed an issue in camlib.CNCJob where tha variable self.toolchange_xy was used for 2 different purposes which created loss of information.
|
||||
- fixed unit conversion functions in case the toolchange_xy parameter is None
|
||||
- more fixes in camlib.CNCJob regarding usage of toolchange (in case it is None)
|
||||
- fixed postprocessor files to work with toolchange_xy parameter value = None (no values in Edit - Preferences fields)
|
||||
- fixed preprocessor files to work with toolchange_xy parameter value = None (no values in Edit - Preferences fields)
|
||||
- fixed Tcl commands CncJob and DrillCncJob to work with toolchange
|
||||
- added to the postprocessor files the command after toolchange to go with G00 (fastest) to "Z Move" value of Z pozition.
|
||||
- added to the preprocessor files the command after toolchange to go with G00 (fastest) to "Z Move" value of Z pozition.
|
||||
|
||||
29.01.2019
|
||||
|
||||
|
@ -2673,15 +2920,15 @@ CAD program, and create G-Code for Isolation routing.
|
|||
- added options for trace segmentation that can be useful for auto-levelling (code snippet from Lei Zheng from a rejected pull request on FlatCAM https://bitbucket.org/realthunder/ )
|
||||
- added shortcut key 'L' for creating 'New Excellon'
|
||||
- added shortcut key combo 'SHIFT+S' for Running a Script.
|
||||
- modified grbl_laser postprocessor file so it includes a Sxxxx command on the line with M03 (laser active) whenever a value is enter in the Spindlespeed entry field
|
||||
- modified GRBL_laser preprocessor file so it includes a Sxxxx command on the line with M03 (laser active) whenever a value is enter in the Spindlespeed entry field
|
||||
- remade the EDIT -> PREFERENCES window, the Excellon and Gerber sections. Created a new section named TOOLS
|
||||
|
||||
26.01.2019
|
||||
|
||||
- fixed grbl_11 postprocessor in linear_code() function
|
||||
- fixed grbl_11 preprocessor in linear_code() function
|
||||
- added icons to the Project Tab context menu
|
||||
- added new entries to the Canvas context menu (Copy, Delete, Edit/Save, Move, New Excellon, New Geometry, New Project)
|
||||
- fixed grbl_laser postprocessor file
|
||||
- fixed GRBL_laser preprocessor file
|
||||
- updated function for copy of an Excellon object for the case when the object has slots
|
||||
- updated FlatCAMExcellon.merge() function to work in case some (or all) of the merged objects have slots
|
||||
|
||||
|
@ -2701,14 +2948,14 @@ CAD program, and create G-Code for Isolation routing.
|
|||
- added the Copy entry to the Project context menu
|
||||
- made the functions behind Disable and Enable project context menu entries, non-threaded to fix a possible issue
|
||||
- added multiple object selection on Open ... and Import ... (idea and code snippet came from Travers Carter, BitBucket user https://bitbucket.org/travc/)
|
||||
- fixed 'grbl_laser' postprocessor bugs (missing functions)
|
||||
- fixed display geometry for 'grbl_laser' postprocessor
|
||||
- fixed 'GRBL_laser' preprocessor bugs (missing functions)
|
||||
- fixed display geometry for 'GRBL_laser' preprocessor
|
||||
- Excellon Editor - added possibility to create an linear drill array rotated at an custom angle
|
||||
- added the Edit and Properties entries to the Project context menu
|
||||
|
||||
23.01.2019
|
||||
|
||||
- added a new postprocessor file named 'line_xyz' which have x, y, z values on the same GCode line
|
||||
- added a new preprocessor file named 'line_xyz' which have x, y, z values on the same GCode line
|
||||
- fixed calculation of total path for Excellon Gcode file
|
||||
- modified the way FlatCAM preferences are saved. Now they can be saved as new files with .FlatConfig extension by the user and shared.
|
||||
- added possibility to open the folder where FlatCAM is saving the preferences files
|
||||
|
@ -2725,19 +2972,19 @@ CAD program, and create G-Code for Isolation routing.
|
|||
|
||||
- fixed the HPGL code geometry rendering when travel
|
||||
- fixed the message box layout when asking to save the current work
|
||||
- made sure that whenever the HPGL postprocessor is selected the Toolchange is always ON and the MultiDepth is OFF
|
||||
- the HPGL postprocessor entry is not allowed in Excellon Object postprocessor selection combobox as it is only applicable for Geometry
|
||||
- made sure that whenever the HPGL preprocessor is selected the Toolchange is always ON and the MultiDepth is OFF
|
||||
- the HPGL preprocessor entry is not allowed in Excellon Object preprocessor selection combobox as it is only applicable for Geometry
|
||||
- when saving HPGL code it will be saved as a file with extension .plt
|
||||
- the units mentioned in HPGL format are only METRIC therefore if FlatCAM units are in INCH they will be transform to METRIC
|
||||
- the minimum unit in HPGL is 0.025mm therefore the coordinates are rounded to a multiple of 0.025mm
|
||||
- removed the raise statement in do_worker_task() function as this is fatal in conjunction with PyQt5
|
||||
- added a try - except clause for the situations when for a font can't be determined the family and name
|
||||
- moved font parsing to the Geometry Editor: it is done everytime the Text tool is invoked
|
||||
- made sure that the HPGL postprocessor is not populated in the Excellon postprocessors in Preferences as it make no sense (HPGL is useful only for Geometries)
|
||||
- made sure that the HPGL preprocessor is not populated in the Excellon preprocessors in Preferences as it make no sense (HPGL is useful only for Geometries)
|
||||
|
||||
19.01.2019
|
||||
|
||||
- added initial implementation of HPGL postprocessor
|
||||
- added initial implementation of HPGL preprocessor
|
||||
- fixed display HPGL code geometry on canvas
|
||||
|
||||
11.01.2019
|
||||
|
@ -2761,9 +3008,9 @@ CAD program, and create G-Code for Isolation routing.
|
|||
|
||||
6.01.2019
|
||||
|
||||
- fixed the Marlin postprocessor detection in GCode header
|
||||
- fixed the Marlin preprocessor detection in GCode header
|
||||
- the version date in GCode header is now the one set in FlatCAMApp.App.version_date
|
||||
- fixed bug in postprocessor files: number of drills is now calculated only for the Excellon objects in toolchange function (only Excellon objects have drills)
|
||||
- fixed bug in preprocessor files: number of drills is now calculated only for the Excellon objects in toolchange function (only Excellon objects have drills)
|
||||
|
||||
5.01.2019
|
||||
|
||||
|
@ -2927,8 +3174,8 @@ now there is a Tool Table in CNC Object UI and each tool GCode can be enabled or
|
|||
- Geometry Tool Table: new tool added copy all the form fields (data) from the last tool
|
||||
- finished work on generation of a single CNC Job file (therefore a single GCODE file) even for multiple tools in Geo Tool Table
|
||||
- GCode header is added only on saving the file therefore the time generation will be reflected in the file
|
||||
- modified postprocessors to accommodate the new CNC Job file with multiple tools
|
||||
- modified postprocessors so the last X,Y move will be to the toolchange X,Y pos (set in Preferences)
|
||||
- modified preprocessors to accommodate the new CNC Job file with multiple tools
|
||||
- modified preprocessors so the last X,Y move will be to the toolchange X,Y pos (set in Preferences)
|
||||
- save_project and load_project now work with the new type of multitool geometry and cncjob objects
|
||||
|
||||
10.12.2018
|
||||
|
@ -2997,7 +3244,7 @@ now there is a Tool Table in CNC Object UI and each tool GCode can be enabled or
|
|||
|
||||
- added checks for using a Z Cut with positive value. The Z Cut parameter has to be negative so if the app will detect a positive value it will automatically convert it to negative
|
||||
- started to implement rest-machining for Non Copper clearing Tool - for now the results are not great
|
||||
- added Toolchange X,Y position parameters and modified the default and manual_toolchange postprocessor file to use them
|
||||
- added Toolchange X,Y position parameters and modified the default and manual_toolchange preprocessor file to use them
|
||||
For now they are used only for Excellon objects who do have toolchange events
|
||||
- added Toolchange event selection for Geometry objects; for now it is as before, single tool on each file
|
||||
- remade the GUI for objects and in Preferences to have uniformity
|
||||
|
@ -3005,14 +3252,14 @@ For now they are used only for Excellon objects who do have toolchange events
|
|||
- fixed some bugs in Tool Add feature of the new Non Copper Clear Tool
|
||||
- added some messages in the Non Copper Clear Tool
|
||||
- added parameters for coordinates no of decimals and for feedrate no of decimals used in the resulting GCODE. They are in EDIT -> Preferences -> CNC Job Options
|
||||
- modified the postprocessors to use the "decimals" parameters
|
||||
- modified the preprocessors to use the "decimals" parameters
|
||||
|
||||
28.11.2018
|
||||
|
||||
- added different methods of copper clearing (standard, seed, line_based) and "connect", "contour" options found in Paint function
|
||||
- remake of the non-copper clearing tool as a separate tool
|
||||
- modified the "About" menu entry to mention the main contributors to FlatCAM 3000
|
||||
- modified Marlin postprocessor according to modifications made by @redbull0174 user from FlatCAM.org forum
|
||||
- modified Marlin preprocessor according to modifications made by @redbull0174 user from FlatCAM.org forum
|
||||
- modified Move Tool so it will detect if there is no object to move and issue a message
|
||||
|
||||
27.11.2018
|
||||
|
@ -3031,7 +3278,7 @@ For now they are used only for Excellon objects who do have toolchange events
|
|||
|
||||
- restored the selection method in Geometry Editor to the original one found in FlatCAM 8.5
|
||||
- minor changes in Clear Copper function
|
||||
- minor changes in some postprocessors
|
||||
- minor changes in some preprocessors
|
||||
- change Join Geometry menu entry to Join Geo/Gerber
|
||||
- added menu entry for Toggle Axis in Menu -> View
|
||||
- added menu entry for Toggle Workspace in Menu -> View
|
||||
|
@ -3047,7 +3294,7 @@ For now they are used only for Excellon objects who do have toolchange events
|
|||
|
||||
19.11.2018
|
||||
|
||||
- fixed issue with nested comment in postprocessors
|
||||
- fixed issue with nested comment in preprocessors
|
||||
- fixed issue in Paint All; reverted changes
|
||||
|
||||
18.11.2018
|
||||
|
@ -3064,13 +3311,13 @@ For now they are used only for Excellon objects who do have toolchange events
|
|||
12.11.2018
|
||||
|
||||
- fixed bug in Paint Single Polygon
|
||||
- added spindle speed in laser postprocessor
|
||||
- added spindle speed in laser preprocessor
|
||||
- added Z start move parameter. It controls the height at which the tool travel on the fist move in the job. Leave it blank if you don't need it.
|
||||
|
||||
9.11.2018
|
||||
|
||||
- fixed a reported bug generated by a typo for feedrate_z object in camlib.py. Because of that, the project could not be saved.
|
||||
- fixed a G01 usage (should be G1) in Marlin postprocessor.
|
||||
- fixed a G01 usage (should be G1) in Marlin preprocessor.
|
||||
- changed the position of the Tool Dia entry in the Object UI and in FlatCAMGUI
|
||||
- fixed issues in the installer
|
||||
|
||||
|
@ -3289,9 +3536,9 @@ the setting in the Preferences) and drag the rectangle across the objects you wa
|
|||
- work on Excellon Editor. Excellon editor working functions are: loading an Excellon object into Editor,
|
||||
saving an Excellon object from editor to FlatCAM, selecting drills by left click, selection of drills by dragging rectangle, deletion of drills.
|
||||
- fixed Excellon merge
|
||||
- added more Gcode details (depthperpass parameter in Gcode header) in postprocessors
|
||||
- deleted the Tool informations from header in postprocessors due to Mach3 not liking the lot of square brackets
|
||||
- more corrections in postprocessors
|
||||
- added more Gcode details (depthperpass parameter in Gcode header) in preprocessors
|
||||
- deleted the Tool informations from header in preprocessors due to Mach3 not liking the lot of square brackets
|
||||
- more corrections in preprocessors
|
||||
|
||||
|
||||
28.09.2018
|
||||
|
@ -3366,7 +3613,7 @@ an Excellon file, a G-Code file or a SVG file.
|
|||
|
||||
- added new information's in the object properties: all used Tool-Table items
|
||||
are included in a new entry in self.options dictionary
|
||||
- modified the postprocessor files so they now include information's about
|
||||
- modified the preprocessor files so they now include information's about
|
||||
how many drills (or slots) are for each tool. The Gcode will have this
|
||||
information displayed on the message from ToolChange.
|
||||
- removed some log.debug and add new log.debug especially for moments when some process is finished
|
||||
|
@ -3404,7 +3651,7 @@ is faster
|
|||
17.09.2018
|
||||
|
||||
- fixed Measuring Tool not working when grid is turned OFF
|
||||
- fixed Roland MDX20 postprocessor
|
||||
- fixed Roland MDX20 preprocessor
|
||||
- added a .GBR extension in the open_gerber filter
|
||||
- added ability to Scale and Offset (for all types of objects) to just
|
||||
press Enter after entering a value in the Entry just like in Tool Transform
|
||||
|
@ -3418,8 +3665,8 @@ to FlatCAM.py
|
|||
|
||||
15.09.2018
|
||||
|
||||
- removed dwell line generator and included dwell generation in the postprocessor files
|
||||
- added a proposed RML1 Roland_MDX20 postprocessor file.
|
||||
- removed dwell line generator and included dwell generation in the preprocessor files
|
||||
- added a proposed RML1 Roland_MDX20 preprocessor file.
|
||||
- added a limit of 15mm/sec (900mm/min) to the feedrate and to the feedrate_rapid. Anything faster than this
|
||||
will be capped to 900mm/min regardless what is entered in the program GUI. This is because Roland MDX-20 has
|
||||
a mechanical limit of the speed to 15mm/sec (900mm/min in GUI)
|
||||
|
@ -3800,7 +4047,7 @@ total number of drills
|
|||
- modified generate_milling method which had issues from the Python3 port
|
||||
(it could not sort the tools due of dict to dict comparison no longer
|
||||
possible).
|
||||
- modified the 'default' postprocessor in order to include a space
|
||||
- modified the 'default' preprocessor in order to include a space
|
||||
between the value of Xcoord and the following Y
|
||||
- made optional the using of threads for the milling command; by default
|
||||
it is OFF (False) because in the current configuration it creates issues
|
||||
|
@ -3820,7 +4067,7 @@ clicked and Options Combo was in Project Options
|
|||
- fixed issue with Tcl Shell loosing focus after each command, therefore
|
||||
needing to click in the edit line before we type a new command (borrowed
|
||||
from @brainstorm
|
||||
- added a header in the postprocessor files mentioning that the GCODE
|
||||
- added a header in the preprocessor files mentioning that the GCODE
|
||||
files were generated by FlatCAM.
|
||||
- modified the number of decimals in some of the line entries to 4.
|
||||
- added an alias for the millholes Tcl Command: 'mill'
|
||||
|
@ -3923,14 +4170,14 @@ Delete: Delete Obj
|
|||
|
||||
22.05.2018
|
||||
|
||||
- Added Marlin postprocessor
|
||||
- Added Marlin preprocessor
|
||||
- Added a new entry into the Geometry and Excellon Object's UI:
|
||||
Feedrate rapid: the purpose is to set a feedrate for the G0
|
||||
command that some firmwares like Marlin don't intepret as
|
||||
'move with highest speed'
|
||||
- FlatCAM was not making the conversion from one type of units to
|
||||
another for a lot of parameters. Corrected that.
|
||||
- Modified the Marlin Postprocessor so it will generate the required
|
||||
- Modified the Marlin preprocessor so it will generate the required
|
||||
GCODE.
|
||||
|
||||
21.05.2018
|
||||
|
@ -4010,7 +4257,7 @@ make a board cutout from a "any shape" Gerber or Geometry file
|
|||
parameter value as the toolchangez parameter value and for the endz value
|
||||
used a default value = 1
|
||||
|
||||
- added postprocessor name into the TCL command "drillcncjob" parameters
|
||||
- added preprocessor name into the TCL command "drillcncjob" parameters
|
||||
|
||||
- when adding a new geometry the default name is now: "New_Geometry" instead
|
||||
of "New Geometry". TCL commands don't handle the spaces inside the name and
|
||||
|
@ -4097,19 +4344,19 @@ is less than 6 then the software will multiply by 10 the coordinates
|
|||
|
||||
- fixed bug in Geometry CNCJob generation that prevented generating
|
||||
the object
|
||||
- added GRBL 1.1 postprocessor and Laser postprocessor (adapted from
|
||||
- added GRBL 1.1 preprocessor and Laser preprocessor (adapted from
|
||||
the work of MARCO A QUEZADA)
|
||||
|
||||
|
||||
13.05.2018
|
||||
|
||||
- added postprocessing in correct form
|
||||
- added the possibility to select an postprocessor for Excellon Object
|
||||
- added a new postprocessor, manual_toolchange.py. It allows to change
|
||||
- added the possibility to select an preprocessor for Excellon Object
|
||||
- added a new preprocessor, manual_toolchange.py. It allows to change
|
||||
the tools and adjust the drill tip to touch the surface manually, always
|
||||
in the X=0, Y=0, Z = toolchangeZ coordinates.
|
||||
- fixed drillcncjob TCL command by adding toolchangeZ parameter
|
||||
- fixed the posprocessor file template 'default.py' in the toolchange
|
||||
- fixed the preprocessor file template 'default.py' in the toolchange
|
||||
command section
|
||||
- after I created a feature that the message in infobar is cleared by
|
||||
moving mouse on canvas, it generated a bug in TCL shell: everytime
|
||||
|
|
|
@ -124,7 +124,7 @@ class FCDrillAdd(FCShapeTool):
|
|||
self.draw_app.app.jump_signal.disconnect()
|
||||
|
||||
def clean_up(self):
|
||||
self.draw_app.selected = list()
|
||||
self.draw_app.selected = []
|
||||
self.draw_app.tools_table_exc.clearSelection()
|
||||
self.draw_app.plot_all()
|
||||
|
||||
|
@ -359,7 +359,7 @@ class FCDrillArray(FCShapeTool):
|
|||
self.draw_app.app.jump_signal.disconnect()
|
||||
|
||||
def clean_up(self):
|
||||
self.draw_app.selected = list()
|
||||
self.draw_app.selected = []
|
||||
self.draw_app.tools_table_exc.clearSelection()
|
||||
self.draw_app.plot_all()
|
||||
|
||||
|
@ -562,7 +562,7 @@ class FCSlot(FCShapeTool):
|
|||
self.draw_app.app.jump_signal.disconnect()
|
||||
|
||||
def clean_up(self):
|
||||
self.draw_app.selected = list()
|
||||
self.draw_app.selected = []
|
||||
self.draw_app.tools_table_exc.clearSelection()
|
||||
self.draw_app.plot_all()
|
||||
|
||||
|
@ -888,7 +888,7 @@ class FCSlotArray(FCShapeTool):
|
|||
self.draw_app.app.jump_signal.disconnect()
|
||||
|
||||
def clean_up(self):
|
||||
self.draw_app.selected = list()
|
||||
self.draw_app.selected = []
|
||||
self.draw_app.tools_table_exc.clearSelection()
|
||||
self.draw_app.plot_all()
|
||||
|
||||
|
@ -1128,7 +1128,7 @@ class FCDrillResize(FCShapeTool):
|
|||
self.draw_app.select_tool("drill_select")
|
||||
|
||||
def clean_up(self):
|
||||
self.draw_app.selected = list()
|
||||
self.draw_app.selected = []
|
||||
self.draw_app.tools_table_exc.clearSelection()
|
||||
self.draw_app.plot_all()
|
||||
|
||||
|
@ -1268,7 +1268,7 @@ class FCDrillMove(FCShapeTool):
|
|||
return DrawToolUtilityShape(ss_el)
|
||||
|
||||
def clean_up(self):
|
||||
self.draw_app.selected = list()
|
||||
self.draw_app.selected = []
|
||||
self.draw_app.tools_table_exc.clearSelection()
|
||||
self.draw_app.plot_all()
|
||||
|
||||
|
@ -1323,7 +1323,7 @@ class FCDrillCopy(FCDrillMove):
|
|||
self.draw_app.app.jump_signal.disconnect()
|
||||
|
||||
def clean_up(self):
|
||||
self.draw_app.selected = list()
|
||||
self.draw_app.selected = []
|
||||
self.draw_app.tools_table_exc.clearSelection()
|
||||
self.draw_app.plot_all()
|
||||
|
||||
|
@ -1334,8 +1334,8 @@ class FCDrillCopy(FCDrillMove):
|
|||
|
||||
|
||||
class FCDrillSelect(DrawTool):
|
||||
def __init__(self, exc_editor_app):
|
||||
DrawTool.__init__(self, exc_editor_app)
|
||||
def __init__(self, draw_app):
|
||||
DrawTool.__init__(self, draw_app)
|
||||
self.name = 'drill_select'
|
||||
|
||||
try:
|
||||
|
@ -1343,7 +1343,7 @@ class FCDrillSelect(DrawTool):
|
|||
except Exception as e:
|
||||
pass
|
||||
|
||||
self.exc_editor_app = exc_editor_app
|
||||
self.exc_editor_app = draw_app
|
||||
self.storage = self.exc_editor_app.storage_dict
|
||||
# self.selected = self.exc_editor_app.selected
|
||||
|
||||
|
@ -1368,7 +1368,7 @@ class FCDrillSelect(DrawTool):
|
|||
else:
|
||||
mod_key = None
|
||||
|
||||
if mod_key == self.draw_app.app.defaults["global_mselect_key"]:
|
||||
if mod_key == self.exc_editor_app.app.defaults["global_mselect_key"]:
|
||||
pass
|
||||
else:
|
||||
self.exc_editor_app.selected = []
|
||||
|
@ -1379,8 +1379,10 @@ class FCDrillSelect(DrawTool):
|
|||
|
||||
try:
|
||||
for storage in self.exc_editor_app.storage_dict:
|
||||
for sh in self.exc_editor_app.storage_dict[storage].get_objects():
|
||||
self.sel_storage.insert(sh)
|
||||
# for sh in self.exc_editor_app.storage_dict[storage].get_objects():
|
||||
# self.sel_storage.insert(sh)
|
||||
_, st_closest_shape = self.exc_editor_app.storage_dict[storage].nearest(pos)
|
||||
self.sel_storage.insert(st_closest_shape)
|
||||
|
||||
_, closest_shape = self.sel_storage.nearest(pos)
|
||||
|
||||
|
@ -1417,37 +1419,41 @@ class FCDrillSelect(DrawTool):
|
|||
else:
|
||||
mod_key = None
|
||||
|
||||
if mod_key == self.draw_app.app.defaults["global_mselect_key"]:
|
||||
if mod_key == self.exc_editor_app.app.defaults["global_mselect_key"]:
|
||||
if closest_shape in self.exc_editor_app.selected:
|
||||
self.exc_editor_app.selected.remove(closest_shape)
|
||||
else:
|
||||
self.exc_editor_app.selected.append(closest_shape)
|
||||
else:
|
||||
self.draw_app.selected = []
|
||||
self.draw_app.selected.append(closest_shape)
|
||||
self.exc_editor_app.selected = []
|
||||
self.exc_editor_app.selected.append(closest_shape)
|
||||
|
||||
# select the diameter of the selected shape in the tool table
|
||||
try:
|
||||
self.draw_app.tools_table_exc.cellPressed.disconnect()
|
||||
self.exc_editor_app.tools_table_exc.cellPressed.disconnect()
|
||||
except (TypeError, AttributeError):
|
||||
pass
|
||||
|
||||
self.exc_editor_app.tools_table_exc.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
|
||||
# if mod_key == self.exc_editor_app.app.defaults["global_mselect_key"]:
|
||||
# self.exc_editor_app.tools_table_exc.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
|
||||
self.sel_tools.clear()
|
||||
|
||||
for shape_s in self.exc_editor_app.selected:
|
||||
for storage in self.exc_editor_app.storage_dict:
|
||||
if shape_s in self.exc_editor_app.storage_dict[storage].get_objects():
|
||||
self.sel_tools.add(storage)
|
||||
|
||||
self.exc_editor_app.tools_table_exc.clearSelection()
|
||||
for storage in self.sel_tools:
|
||||
for k, v in self.draw_app.tool2tooldia.items():
|
||||
for k, v in self.exc_editor_app.tool2tooldia.items():
|
||||
if v == storage:
|
||||
self.exc_editor_app.tools_table_exc.selectRow(int(k) - 1)
|
||||
self.draw_app.last_tool_selected = int(k)
|
||||
self.exc_editor_app.last_tool_selected = int(k)
|
||||
break
|
||||
|
||||
self.exc_editor_app.tools_table_exc.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
|
||||
# self.exc_editor_app.tools_table_exc.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
|
||||
|
||||
self.draw_app.tools_table_exc.cellPressed.connect(self.draw_app.on_row_selected)
|
||||
self.exc_editor_app.tools_table_exc.cellPressed.connect(self.exc_editor_app.on_row_selected)
|
||||
|
||||
# delete whatever is in selection storage, there is no longer need for those shapes
|
||||
self.sel_storage = FlatCAMExcEditor.make_storage()
|
||||
|
@ -2068,7 +2074,6 @@ 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
|
||||
|
@ -2180,6 +2185,43 @@ class FlatCAMExcEditor(QtCore.QObject):
|
|||
if option in self.app.options:
|
||||
self.options[option] = self.app.options[option]
|
||||
|
||||
self.data_defaults = {
|
||||
"plot": self.app.defaults["excellon_plot"],
|
||||
"solid": self.app.defaults["excellon_solid"],
|
||||
|
||||
"operation": self.app.defaults["excellon_operation"],
|
||||
"milling_type": self.app.defaults["excellon_milling_type"],
|
||||
|
||||
"milling_dia":self.app.defaults["excellon_milling_dia"],
|
||||
|
||||
"cutz": self.app.defaults["excellon_cutz"],
|
||||
"multidepth": self.app.defaults["excellon_multidepth"],
|
||||
"depthperpass": self.app.defaults["excellon_depthperpass"],
|
||||
"travelz": self.app.defaults["excellon_travelz"],
|
||||
"feedrate": self.app.defaults["geometry_feedrate"],
|
||||
"feedrate_z": self.app.defaults["excellon_feedrate_z"],
|
||||
"feedrate_rapid": self.app.defaults["excellon_feedrate_rapid"],
|
||||
"tooldia": self.app.defaults["excellon_tooldia"],
|
||||
"slot_tooldia": self.app.defaults["excellon_slot_tooldia"],
|
||||
"toolchange": self.app.defaults["excellon_toolchange"],
|
||||
"toolchangez": self.app.defaults["excellon_toolchangez"],
|
||||
"toolchangexy": self.app.defaults["excellon_toolchangexy"],
|
||||
"extracut": self.app.defaults["geometry_extracut"],
|
||||
"extracut_length": self.app.defaults["geometry_extracut_length"],
|
||||
"endz": self.app.defaults["excellon_endz"],
|
||||
"endxy": self.app.defaults["excellon_endxy"],
|
||||
"startz": self.app.defaults["excellon_startz"],
|
||||
"offset": self.app.defaults["excellon_offset"],
|
||||
"spindlespeed": self.app.defaults["excellon_spindlespeed"],
|
||||
"dwell": self.app.defaults["excellon_dwell"],
|
||||
"dwelltime": self.app.defaults["excellon_dwelltime"],
|
||||
"ppname_e": self.app.defaults["excellon_ppname_e"],
|
||||
"ppname_g": self.app.defaults["geometry_ppname_g"],
|
||||
"z_pdepth": self.app.defaults["excellon_z_pdepth"],
|
||||
"feedrate_probe": self.app.defaults["excellon_feedrate_probe"],
|
||||
"optimization_type": self.app.defaults["excellon_optimization_type"]
|
||||
}
|
||||
|
||||
self.rtree_exc_index = rtindex.Index()
|
||||
# flag to show if the object was modified
|
||||
self.is_modified = False
|
||||
|
@ -2586,9 +2628,6 @@ 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
|
||||
|
@ -2789,7 +2828,7 @@ class FlatCAMExcEditor(QtCore.QObject):
|
|||
self.new_drills = []
|
||||
self.new_tools = {}
|
||||
self.new_slots = []
|
||||
self.new_tool_offset = {}
|
||||
|
||||
self.olddia_newdia = {}
|
||||
|
||||
self.shapes.enabled = True
|
||||
|
@ -2974,7 +3013,7 @@ class FlatCAMExcEditor(QtCore.QObject):
|
|||
except (TypeError, AttributeError):
|
||||
pass
|
||||
|
||||
self.app.ui.popmenu_copy.triggered.connect(self.app.on_copy_object)
|
||||
self.app.ui.popmenu_copy.triggered.connect(self.app.on_copy_command)
|
||||
self.app.ui.popmenu_delete.triggered.connect(self.app.on_delete)
|
||||
self.app.ui.popmenu_move.triggered.connect(self.app.obj_move)
|
||||
|
||||
|
@ -3262,7 +3301,6 @@ class FlatCAMExcEditor(QtCore.QObject):
|
|||
self.edited_obj_name += "_1"
|
||||
else:
|
||||
self.edited_obj_name += "_edit"
|
||||
self.new_tool_offset = self.exc_obj.tool_offset
|
||||
|
||||
self.app.worker_task.emit({'fcn': self.new_edited_excellon,
|
||||
'params': [self.edited_obj_name,
|
||||
|
@ -3270,6 +3308,8 @@ class FlatCAMExcEditor(QtCore.QObject):
|
|||
self.new_slots,
|
||||
self.new_tools]})
|
||||
|
||||
return self.edited_obj_name
|
||||
|
||||
def update_options(self, obj):
|
||||
try:
|
||||
if not obj.options:
|
||||
|
@ -3308,9 +3348,14 @@ class FlatCAMExcEditor(QtCore.QObject):
|
|||
excellon_obj.drills = deepcopy(new_drills)
|
||||
excellon_obj.tools = deepcopy(new_tools)
|
||||
excellon_obj.slots = deepcopy(new_slots)
|
||||
excellon_obj.tool_offset = self.new_tool_offset
|
||||
|
||||
excellon_obj.options['name'] = outname
|
||||
|
||||
# add a 'data' dict for each tool with the default values
|
||||
for tool in excellon_obj.tools:
|
||||
excellon_obj.tools[tool]['data'] = {}
|
||||
excellon_obj.tools[tool]['data'].update(deepcopy(self.data_defaults))
|
||||
|
||||
try:
|
||||
excellon_obj.create_geometry()
|
||||
except KeyError:
|
||||
|
|
|
@ -18,12 +18,12 @@ from camlib import distance, arc, three_point_circle, Geometry, FlatCAMRTreeStor
|
|||
from FlatCAMTool import FlatCAMTool
|
||||
from flatcamGUI.ObjectUI import RadioSet
|
||||
from flatcamGUI.GUIElements import OptionalInputSection, FCCheckBox, FCEntry, FCComboBox, FCTextAreaRich, \
|
||||
FCTable, FCDoubleSpinner, FCButton, EvalEntry2, FCInputDialog
|
||||
FCTable, FCDoubleSpinner, FCButton, EvalEntry2, FCInputDialog, FCTree
|
||||
from flatcamParsers.ParseFont import *
|
||||
import FlatCAMApp
|
||||
|
||||
from shapely.geometry import LineString, LinearRing, MultiLineString, Polygon, MultiPolygon
|
||||
from shapely.ops import cascaded_union, unary_union
|
||||
from shapely.ops import cascaded_union, unary_union, linemerge
|
||||
import shapely.affinity as affinity
|
||||
from shapely.geometry.polygon import orient
|
||||
|
||||
|
@ -202,7 +202,7 @@ class TextInputTool(FlatCAMTool):
|
|||
self.text_path = []
|
||||
self.decimals = self.app.decimals
|
||||
|
||||
self.f_parse = ParseFont(self)
|
||||
self.f_parse = ParseFont(self.app)
|
||||
self.f_parse.get_fonts_by_types()
|
||||
|
||||
# this way I can hide/show the frame
|
||||
|
@ -364,12 +364,10 @@ class TextInputTool(FlatCAMTool):
|
|||
string_to_geo = self.text_input_entry.get_value()
|
||||
font_to_geo_size = self.font_size_cb.get_value()
|
||||
|
||||
self.text_path = self.f_parse.font_to_geometry(
|
||||
char_string=string_to_geo,
|
||||
font_name=self.font_name,
|
||||
font_size=font_to_geo_size,
|
||||
font_type=font_to_geo_type,
|
||||
units=self.app.defaults['units'].upper())
|
||||
self.text_path = self.f_parse.font_to_geometry(char_string=string_to_geo, font_name=self.font_name,
|
||||
font_size=font_to_geo_size,
|
||||
font_type=font_to_geo_type,
|
||||
units=self.app.defaults['units'].upper())
|
||||
|
||||
def font_family(self, font):
|
||||
self.text_input_entry.selectAll()
|
||||
|
@ -403,8 +401,8 @@ class TextInputTool(FlatCAMTool):
|
|||
|
||||
def hide_tool(self):
|
||||
self.text_tool_frame.hide()
|
||||
self.app.ui.notebook.setCurrentWidget(self.app.ui.project_tab)
|
||||
self.app.ui.splitter.setSizes([0, 1])
|
||||
self.app.ui.notebook.setCurrentWidget(self.app.ui.selected_tab)
|
||||
# self.app.ui.splitter.setSizes([0, 1])
|
||||
self.app.ui.notebook.setTabText(2, _("Tool"))
|
||||
|
||||
|
||||
|
@ -451,7 +449,7 @@ class PaintOptionsTool(FlatCAMTool):
|
|||
grid.addWidget(self.painttooldia_entry, 0, 1)
|
||||
|
||||
# Overlap
|
||||
ovlabel = QtWidgets.QLabel('%s:' % _('Overlap Rate'))
|
||||
ovlabel = QtWidgets.QLabel('%s:' % _('Overlap'))
|
||||
ovlabel.setToolTip(
|
||||
_("How much (percentage) of the tool width to overlap each tool pass.\n"
|
||||
"Adjust the value starting with lower values\n"
|
||||
|
@ -487,15 +485,20 @@ class PaintOptionsTool(FlatCAMTool):
|
|||
# Method
|
||||
methodlabel = QtWidgets.QLabel('%s:' % _('Method'))
|
||||
methodlabel.setToolTip(
|
||||
_("Algorithm to paint the polygon:<BR>"
|
||||
"<B>Standard</B>: Fixed step inwards.<BR>"
|
||||
"<B>Seed-based</B>: Outwards from seed.")
|
||||
_("Algorithm to paint the polygons:\n"
|
||||
"- Standard: Fixed step inwards.\n"
|
||||
"- Seed-based: Outwards from seed.\n"
|
||||
"- Line-based: Parallel lines.")
|
||||
)
|
||||
# self.paintmethod_combo = RadioSet([
|
||||
# {"label": _("Standard"), "value": "standard"},
|
||||
# {"label": _("Seed-based"), "value": "seed"},
|
||||
# {"label": _("Straight lines"), "value": "lines"}
|
||||
# ], orientation='vertical', stretch=False)
|
||||
self.paintmethod_combo = FCComboBox()
|
||||
self.paintmethod_combo.addItems(
|
||||
[_("Standard"), _("Seed"), _("Lines")]
|
||||
)
|
||||
self.paintmethod_combo = RadioSet([
|
||||
{"label": _("Standard"), "value": "standard"},
|
||||
{"label": _("Seed-based"), "value": "seed"},
|
||||
{"label": _("Straight lines"), "value": "lines"}
|
||||
], orientation='vertical', stretch=False)
|
||||
|
||||
grid.addWidget(methodlabel, 3, 0)
|
||||
grid.addWidget(self.paintmethod_combo, 3, 1)
|
||||
|
@ -564,7 +567,7 @@ class PaintOptionsTool(FlatCAMTool):
|
|||
if self.app.defaults["tools_paintmethod"]:
|
||||
self.paintmethod_combo.set_value(self.app.defaults["tools_paintmethod"])
|
||||
else:
|
||||
self.paintmethod_combo.set_value("seed")
|
||||
self.paintmethod_combo.set_value(_("Seed"))
|
||||
|
||||
if self.app.defaults["tools_pathconnect"]:
|
||||
self.pathconnect_cb.set_value(self.app.defaults["tools_pathconnect"])
|
||||
|
@ -578,8 +581,7 @@ class PaintOptionsTool(FlatCAMTool):
|
|||
|
||||
def on_paint(self):
|
||||
if not self.fcdraw.selected:
|
||||
self.app.inform.emit('[WARNING_NOTCL] %s' %
|
||||
_("Paint cancelled. No shape selected."))
|
||||
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Paint cancelled. No shape selected."))
|
||||
return
|
||||
|
||||
tooldia = self.painttooldia_entry.get_value()
|
||||
|
@ -1751,7 +1753,7 @@ class DrawToolShape(object):
|
|||
|
||||
def translate_recursion(geom):
|
||||
if type(geom) == list:
|
||||
geoms = list()
|
||||
geoms = []
|
||||
for local_geom in geom:
|
||||
geoms.append(translate_recursion(local_geom))
|
||||
return geoms
|
||||
|
@ -1798,7 +1800,7 @@ class DrawToolShape(object):
|
|||
|
||||
def scale_recursion(geom):
|
||||
if type(geom) == list:
|
||||
geoms = list()
|
||||
geoms = []
|
||||
for local_geom in geom:
|
||||
geoms.append(scale_recursion(local_geom))
|
||||
return geoms
|
||||
|
@ -1924,6 +1926,12 @@ class FCCircle(FCShapeTool):
|
|||
self.steps_per_circ = self.draw_app.app.defaults["geometry_circle_steps"]
|
||||
|
||||
def click(self, point):
|
||||
try:
|
||||
self.draw_app.app.jump_signal.disconnect()
|
||||
except (TypeError, AttributeError):
|
||||
pass
|
||||
self.draw_app.app.jump_signal.connect(lambda x: self.draw_app.update_utility_geometry(data=x))
|
||||
|
||||
self.points.append(point)
|
||||
|
||||
if len(self.points) == 1:
|
||||
|
@ -1962,7 +1970,7 @@ class FCCircle(FCShapeTool):
|
|||
self.draw_app.app.inform.emit('[success] %s' % _("Done. Adding Circle completed."))
|
||||
|
||||
def clean_up(self):
|
||||
self.draw_app.selected = list()
|
||||
self.draw_app.selected = []
|
||||
self.draw_app.plot_all()
|
||||
|
||||
try:
|
||||
|
@ -2003,6 +2011,12 @@ class FCArc(FCShapeTool):
|
|||
self.steps_per_circ = self.draw_app.app.defaults["geometry_circle_steps"]
|
||||
|
||||
def click(self, point):
|
||||
try:
|
||||
self.draw_app.app.jump_signal.disconnect()
|
||||
except (TypeError, AttributeError):
|
||||
pass
|
||||
self.draw_app.app.jump_signal.connect(lambda x: self.draw_app.update_utility_geometry(data=x))
|
||||
|
||||
self.points.append(point)
|
||||
|
||||
if len(self.points) == 1:
|
||||
|
@ -2196,7 +2210,7 @@ class FCArc(FCShapeTool):
|
|||
self.draw_app.app.inform.emit('[success] %s' % _("Done. Arc completed."))
|
||||
|
||||
def clean_up(self):
|
||||
self.draw_app.selected = list()
|
||||
self.draw_app.selected = []
|
||||
self.draw_app.plot_all()
|
||||
|
||||
try:
|
||||
|
@ -2227,6 +2241,12 @@ class FCRectangle(FCShapeTool):
|
|||
self.draw_app.app.inform.emit(_("Click on 1st corner ..."))
|
||||
|
||||
def click(self, point):
|
||||
try:
|
||||
self.draw_app.app.jump_signal.disconnect()
|
||||
except (TypeError, AttributeError):
|
||||
pass
|
||||
self.draw_app.app.jump_signal.connect(lambda x: self.draw_app.update_utility_geometry(data=x))
|
||||
|
||||
self.points.append(point)
|
||||
|
||||
if len(self.points) == 1:
|
||||
|
@ -2263,7 +2283,7 @@ class FCRectangle(FCShapeTool):
|
|||
self.draw_app.app.inform.emit('[success] %s' % _("Done. Rectangle completed."))
|
||||
|
||||
def clean_up(self):
|
||||
self.draw_app.selected = list()
|
||||
self.draw_app.selected = []
|
||||
self.draw_app.plot_all()
|
||||
|
||||
try:
|
||||
|
@ -2294,6 +2314,12 @@ class FCPolygon(FCShapeTool):
|
|||
self.draw_app.app.inform.emit(_("Click on 1st corner ..."))
|
||||
|
||||
def click(self, point):
|
||||
try:
|
||||
self.draw_app.app.jump_signal.disconnect()
|
||||
except (TypeError, AttributeError):
|
||||
pass
|
||||
self.draw_app.app.jump_signal.connect(lambda x: self.draw_app.update_utility_geometry(data=x))
|
||||
|
||||
self.draw_app.in_action = True
|
||||
self.points.append(point)
|
||||
|
||||
|
@ -2346,7 +2372,7 @@ class FCPolygon(FCShapeTool):
|
|||
return _("Backtracked one point ...")
|
||||
|
||||
def clean_up(self):
|
||||
self.draw_app.selected = list()
|
||||
self.draw_app.selected = []
|
||||
self.draw_app.plot_all()
|
||||
|
||||
try:
|
||||
|
@ -2411,7 +2437,7 @@ class FCPath(FCPolygon):
|
|||
return _("Backtracked one point ...")
|
||||
|
||||
def clean_up(self):
|
||||
self.draw_app.selected = list()
|
||||
self.draw_app.selected = []
|
||||
self.draw_app.plot_all()
|
||||
|
||||
try:
|
||||
|
@ -2494,10 +2520,34 @@ class FCSelect(DrawTool):
|
|||
self.draw_app.selected = []
|
||||
self.draw_app.selected.append(obj_to_add)
|
||||
except Exception as e:
|
||||
log.error("[ERROR] Something went bad. %s" % str(e))
|
||||
raise
|
||||
log.error("[ERROR] FlatCAMGeoEditor.FCSelect.click_release() -> Something went bad. %s" % str(e))
|
||||
|
||||
# if selection is done on canvas update the Tree in Selected Tab with the selection
|
||||
try:
|
||||
self.draw_app.tw.itemSelectionChanged.disconnect(self.draw_app.on_tree_selection_change)
|
||||
except (AttributeError, TypeError):
|
||||
pass
|
||||
|
||||
self.draw_app.tw.selectionModel().clearSelection()
|
||||
for sel_shape in self.draw_app.selected:
|
||||
iterator = QtWidgets.QTreeWidgetItemIterator(self.draw_app.tw)
|
||||
while iterator.value():
|
||||
item = iterator.value()
|
||||
try:
|
||||
if int(item.text(1)) == id(sel_shape):
|
||||
item.setSelected(True)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
iterator += 1
|
||||
|
||||
self.draw_app.tw.itemSelectionChanged.connect(self.draw_app.on_tree_selection_change)
|
||||
|
||||
return ""
|
||||
|
||||
def clean_up(self):
|
||||
pass
|
||||
|
||||
|
||||
class FCExplode(FCShapeTool):
|
||||
def __init__(self, draw_app):
|
||||
|
@ -2521,8 +2571,8 @@ class FCExplode(FCShapeTool):
|
|||
self.make()
|
||||
|
||||
def make(self):
|
||||
to_be_deleted_list = list()
|
||||
lines = list()
|
||||
to_be_deleted_list = []
|
||||
lines = []
|
||||
|
||||
for shape in self.draw_app.get_selected():
|
||||
to_be_deleted_list.append(shape)
|
||||
|
@ -2544,7 +2594,7 @@ class FCExplode(FCShapeTool):
|
|||
if shape in self.draw_app.selected:
|
||||
self.draw_app.selected.remove(shape)
|
||||
|
||||
geo_list = list()
|
||||
geo_list = []
|
||||
for line in lines:
|
||||
geo_list.append(DrawToolShape(line))
|
||||
self.geometry = geo_list
|
||||
|
@ -2552,7 +2602,7 @@ class FCExplode(FCShapeTool):
|
|||
self.draw_app.app.inform.emit('[success] %s...' % _("Done. Polygons exploded into lines."))
|
||||
|
||||
def clean_up(self):
|
||||
self.draw_app.selected = list()
|
||||
self.draw_app.selected = []
|
||||
self.draw_app.plot_all()
|
||||
|
||||
try:
|
||||
|
@ -2585,6 +2635,7 @@ class FCMove(FCShapeTool):
|
|||
return
|
||||
else:
|
||||
self.draw_app.app.inform.emit(_(" MOVE: Click on reference point ..."))
|
||||
|
||||
self.draw_app.app.jump_signal.connect(lambda x: self.draw_app.update_utility_geometry(data=x))
|
||||
|
||||
def set_origin(self, origin):
|
||||
|
@ -2592,6 +2643,12 @@ class FCMove(FCShapeTool):
|
|||
self.origin = origin
|
||||
|
||||
def click(self, point):
|
||||
try:
|
||||
self.draw_app.app.jump_signal.disconnect()
|
||||
except (TypeError, AttributeError):
|
||||
pass
|
||||
self.draw_app.app.jump_signal.connect(lambda x: self.draw_app.update_utility_geometry(data=x))
|
||||
|
||||
if len(self.draw_app.get_selected()) == 0:
|
||||
# self.complete = True
|
||||
# self.draw_app.app.inform.emit(_("[WARNING_NOTCL] Move cancelled. No shape selected."))
|
||||
|
@ -2623,7 +2680,10 @@ class FCMove(FCShapeTool):
|
|||
self.draw_app.delete_selected()
|
||||
self.complete = True
|
||||
self.draw_app.app.inform.emit('[success] %s' % _("Done. Geometry(s) Move completed."))
|
||||
self.draw_app.app.jump_signal.disconnect()
|
||||
try:
|
||||
self.draw_app.app.jump_signal.disconnect()
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
def selection_bbox(self):
|
||||
geo_list = []
|
||||
|
@ -2731,7 +2791,7 @@ class FCMove(FCShapeTool):
|
|||
raise
|
||||
|
||||
def clean_up(self):
|
||||
self.draw_app.selected = list()
|
||||
self.draw_app.selected = []
|
||||
self.draw_app.plot_all()
|
||||
|
||||
try:
|
||||
|
@ -2753,10 +2813,13 @@ class FCCopy(FCMove):
|
|||
for geom in self.draw_app.get_selected()]
|
||||
self.complete = True
|
||||
self.draw_app.app.inform.emit('[success] %s' % _("Done. Geometry(s) Copy completed."))
|
||||
self.draw_app.app.jump_signal.disconnect()
|
||||
try:
|
||||
self.draw_app.app.jump_signal.disconnect()
|
||||
except (TypeError, AttributeError):
|
||||
pass
|
||||
|
||||
def clean_up(self):
|
||||
self.draw_app.selected = list()
|
||||
self.draw_app.selected = []
|
||||
self.draw_app.plot_all()
|
||||
|
||||
try:
|
||||
|
@ -2783,11 +2846,17 @@ class FCText(FCShapeTool):
|
|||
self.draw_app.app.inform.emit(_("Click on 1st point ..."))
|
||||
self.origin = (0, 0)
|
||||
|
||||
self.text_gui = TextInputTool(self.app)
|
||||
self.text_gui = TextInputTool(app=self.app)
|
||||
self.text_gui.run()
|
||||
self.draw_app.app.jump_signal.connect(lambda x: self.draw_app.update_utility_geometry(data=x))
|
||||
|
||||
def click(self, point):
|
||||
try:
|
||||
self.draw_app.app.jump_signal.disconnect()
|
||||
except (TypeError, AttributeError):
|
||||
pass
|
||||
self.draw_app.app.jump_signal.connect(lambda x: self.draw_app.update_utility_geometry(data=x))
|
||||
|
||||
# Create new geometry
|
||||
dx = point[0]
|
||||
dy = point[1]
|
||||
|
@ -2807,7 +2876,10 @@ class FCText(FCShapeTool):
|
|||
return
|
||||
else:
|
||||
self.draw_app.app.inform.emit('[WARNING_NOTCL] %s' % _("No text to add."))
|
||||
self.draw_app.app.jump_signal.disconnect()
|
||||
try:
|
||||
self.draw_app.app.jump_signal.disconnect()
|
||||
except (TypeError, AttributeError):
|
||||
pass
|
||||
return
|
||||
|
||||
self.text_gui.text_path = []
|
||||
|
@ -2832,7 +2904,7 @@ class FCText(FCShapeTool):
|
|||
return
|
||||
|
||||
def clean_up(self):
|
||||
self.draw_app.selected = list()
|
||||
self.draw_app.selected = []
|
||||
self.draw_app.plot_all()
|
||||
|
||||
try:
|
||||
|
@ -2885,13 +2957,11 @@ class FCBuffer(FCShapeTool):
|
|||
self.disactivate()
|
||||
if ret_val == 'fail':
|
||||
return
|
||||
self.draw_app.app.inform.emit('[success] %s' %
|
||||
_("Done. Buffer Tool completed."))
|
||||
self.draw_app.app.inform.emit('[success] %s' % _("Done. Buffer Tool completed."))
|
||||
|
||||
def on_buffer_int(self):
|
||||
if not self.draw_app.selected:
|
||||
self.app.inform.emit('[WARNING_NOTCL] %s' %
|
||||
_("Buffer cancelled. No shape selected."))
|
||||
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Buffer cancelled. No shape selected."))
|
||||
return
|
||||
|
||||
try:
|
||||
|
@ -2915,13 +2985,11 @@ class FCBuffer(FCShapeTool):
|
|||
self.disactivate()
|
||||
if ret_val == 'fail':
|
||||
return
|
||||
self.draw_app.app.inform.emit('[success] %s' %
|
||||
_("Done. Buffer Int Tool completed."))
|
||||
self.draw_app.app.inform.emit('[success] %s' % _("Done. Buffer Int Tool completed."))
|
||||
|
||||
def on_buffer_ext(self):
|
||||
if not self.draw_app.selected:
|
||||
self.app.inform.emit('[WARNING_NOTCL] %s' %
|
||||
_("Buffer cancelled. No shape selected."))
|
||||
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Buffer cancelled. No shape selected."))
|
||||
return
|
||||
|
||||
try:
|
||||
|
@ -2945,8 +3013,7 @@ class FCBuffer(FCShapeTool):
|
|||
self.disactivate()
|
||||
if ret_val == 'fail':
|
||||
return
|
||||
self.draw_app.app.inform.emit('[success] %s' %
|
||||
_("Done. Buffer Ext Tool completed."))
|
||||
self.draw_app.app.inform.emit('[success] %s' % _("Done. Buffer Ext Tool completed."))
|
||||
|
||||
def activate(self):
|
||||
self.buff_tool.buffer_button.clicked.disconnect()
|
||||
|
@ -2968,9 +3035,13 @@ class FCBuffer(FCShapeTool):
|
|||
self.complete = True
|
||||
self.draw_app.select_tool("select")
|
||||
self.buff_tool.hide_tool()
|
||||
try:
|
||||
self.draw_app.app.jump_signal.disconnect()
|
||||
except (TypeError, AttributeError):
|
||||
pass
|
||||
|
||||
def clean_up(self):
|
||||
self.draw_app.selected = list()
|
||||
self.draw_app.selected = []
|
||||
self.draw_app.plot_all()
|
||||
|
||||
try:
|
||||
|
@ -2979,7 +3050,6 @@ class FCBuffer(FCShapeTool):
|
|||
pass
|
||||
|
||||
|
||||
|
||||
class FCEraser(FCShapeTool):
|
||||
def __init__(self, draw_app):
|
||||
DrawTool.__init__(self, draw_app)
|
||||
|
@ -3007,6 +3077,12 @@ class FCEraser(FCShapeTool):
|
|||
self.origin = origin
|
||||
|
||||
def click(self, point):
|
||||
try:
|
||||
self.draw_app.app.jump_signal.disconnect()
|
||||
except (TypeError, AttributeError):
|
||||
pass
|
||||
self.draw_app.app.jump_signal.connect(lambda x: self.draw_app.update_utility_geometry(data=x))
|
||||
|
||||
if len(self.draw_app.get_selected()) == 0:
|
||||
for obj_shape in self.storage.get_objects():
|
||||
try:
|
||||
|
@ -3054,7 +3130,10 @@ class FCEraser(FCShapeTool):
|
|||
self.draw_app.delete_utility_geometry()
|
||||
self.draw_app.plot_all()
|
||||
self.draw_app.app.inform.emit('[success] %s' % _("Done. Eraser tool action completed."))
|
||||
self.draw_app.app.jump_signal.disconnect()
|
||||
try:
|
||||
self.draw_app.app.jump_signal.disconnect()
|
||||
except (TypeError, AttributeError):
|
||||
pass
|
||||
|
||||
def utility_geometry(self, data=None):
|
||||
"""
|
||||
|
@ -3084,7 +3163,7 @@ class FCEraser(FCShapeTool):
|
|||
return DrawToolUtilityShape(geo_list)
|
||||
|
||||
def clean_up(self):
|
||||
self.draw_app.selected = list()
|
||||
self.draw_app.selected = []
|
||||
self.draw_app.plot_all()
|
||||
|
||||
try:
|
||||
|
@ -3123,6 +3202,9 @@ class FCTransform(FCShapeTool):
|
|||
# ###############################################
|
||||
class FlatCAMGeoEditor(QtCore.QObject):
|
||||
|
||||
# will emit the name of the object that was just selected
|
||||
item_selected = QtCore.pyqtSignal(str)
|
||||
|
||||
transform_complete = QtCore.pyqtSignal()
|
||||
|
||||
draw_shape_idx = -1
|
||||
|
@ -3137,6 +3219,49 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
self.canvas = app.plotcanvas
|
||||
self.decimals = app.decimals
|
||||
|
||||
self.geo_edit_widget = QtWidgets.QWidget()
|
||||
# ## Box for custom widgets
|
||||
# This gets populated in offspring implementations.
|
||||
layout = QtWidgets.QVBoxLayout()
|
||||
self.geo_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.geo_frame = QtWidgets.QFrame()
|
||||
self.geo_frame.setContentsMargins(0, 0, 0, 0)
|
||||
layout.addWidget(self.geo_frame)
|
||||
self.tools_box = QtWidgets.QVBoxLayout()
|
||||
self.tools_box.setContentsMargins(0, 0, 0, 0)
|
||||
self.geo_frame.setLayout(self.tools_box)
|
||||
|
||||
# ## Page Title box (spacing between children)
|
||||
self.title_box = QtWidgets.QHBoxLayout()
|
||||
self.tools_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>" % _('Geometry Editor'))
|
||||
self.title_label.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
|
||||
self.title_box.addWidget(self.title_label, stretch=1)
|
||||
self.title_box.addWidget(QtWidgets.QLabel(''))
|
||||
|
||||
self.tw = FCTree(columns=3, header_hidden=False, protected_column=[0, 1], extended_sel=True)
|
||||
self.tw.setHeaderLabels(["ID", _("Type"), _("Name")])
|
||||
self.tw.setIndentation(0)
|
||||
self.tw.header().setStretchLastSection(True)
|
||||
self.tw.header().setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
|
||||
self.tools_box.addWidget(self.tw)
|
||||
|
||||
self.geo_font = QtGui.QFont()
|
||||
self.geo_font.setBold(True)
|
||||
|
||||
self.geo_parent = self.tw.invisibleRootItem()
|
||||
|
||||
# ## Toolbar events and properties
|
||||
self.tools = {
|
||||
"select": {"button": self.app.ui.geo_select_btn,
|
||||
|
@ -3338,10 +3463,84 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
self.delete_selected()
|
||||
self.replot()
|
||||
|
||||
def set_ui(self):
|
||||
# updated units
|
||||
self.units = self.app.defaults['units'].upper()
|
||||
self.decimals = self.app.decimals
|
||||
|
||||
# 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.geo_edit_widget)
|
||||
# Switch notebook to Selected page
|
||||
self.app.ui.notebook.setCurrentWidget(self.app.ui.selected_tab)
|
||||
|
||||
def build_ui(self, first_run=None):
|
||||
|
||||
# try:
|
||||
# # if connected, disconnect the signal from the slot on item_changed as it creates issues
|
||||
# self.apertures_table.itemChanged.disconnect()
|
||||
# except (TypeError, AttributeError):
|
||||
# pass
|
||||
|
||||
iterator = QtWidgets.QTreeWidgetItemIterator(self.geo_parent)
|
||||
to_delete = []
|
||||
while iterator.value():
|
||||
item = iterator.value()
|
||||
to_delete.append(item)
|
||||
iterator += 1
|
||||
for it in to_delete:
|
||||
self.geo_parent.removeChild(it)
|
||||
|
||||
for elem in self.storage.get_objects():
|
||||
geo_type = type(elem.geo)
|
||||
el_type = None
|
||||
if geo_type is LinearRing:
|
||||
el_type = _('Ring')
|
||||
elif geo_type is LineString:
|
||||
el_type = _('Line')
|
||||
elif geo_type is Polygon:
|
||||
el_type = _('Polygon')
|
||||
elif geo_type is MultiLineString:
|
||||
el_type = _('Multi-Line')
|
||||
elif geo_type is MultiPolygon:
|
||||
el_type = _('Multi-Polygon')
|
||||
|
||||
self.tw.addParentEditable(
|
||||
self.geo_parent,
|
||||
[
|
||||
str(id(elem)),
|
||||
'%s' % el_type,
|
||||
_("Geo Elem")
|
||||
],
|
||||
font=self.geo_font,
|
||||
font_items=2,
|
||||
# color=QtGui.QColor("#FF0000"),
|
||||
editable=True
|
||||
)
|
||||
|
||||
self.tw.resize_sig.emit()
|
||||
|
||||
def on_geo_elem_selected(self):
|
||||
pass
|
||||
|
||||
def on_tree_selection_change(self):
|
||||
self.selected = []
|
||||
selected_tree_items = self.tw.selectedItems()
|
||||
for sel in selected_tree_items:
|
||||
for obj_shape in self.storage.get_objects():
|
||||
try:
|
||||
if id(obj_shape) == int(sel.text(0)):
|
||||
self.selected.append(obj_shape)
|
||||
except ValueError:
|
||||
pass
|
||||
self.replot()
|
||||
|
||||
def activate(self):
|
||||
# adjust the status of the menu entries related to the editor
|
||||
self.app.ui.menueditedit.setDisabled(True)
|
||||
self.app.ui.menueditok.setDisabled(False)
|
||||
|
||||
# adjust the visibility of some of the canvas context menu
|
||||
self.app.ui.popmenu_edit.setVisible(False)
|
||||
self.app.ui.popmenu_save.setVisible(True)
|
||||
|
@ -3379,23 +3578,34 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
self.app.ui.g_editor_cmenu.menuAction().setVisible(True)
|
||||
|
||||
# prevent the user to change anything in the Selected Tab while the Geo Editor is active
|
||||
sel_tab_widget_list = self.app.ui.selected_tab.findChildren(QtWidgets.QWidget)
|
||||
for w in sel_tab_widget_list:
|
||||
w.setEnabled(False)
|
||||
# sel_tab_widget_list = self.app.ui.selected_tab.findChildren(QtWidgets.QWidget)
|
||||
# for w in sel_tab_widget_list:
|
||||
# w.setEnabled(False)
|
||||
|
||||
# Tell the App that the editor is active
|
||||
self.editor_active = True
|
||||
|
||||
self.item_selected.connect(self.on_geo_elem_selected)
|
||||
|
||||
# ## GUI Events
|
||||
self.tw.itemSelectionChanged.connect(self.on_tree_selection_change)
|
||||
# self.tw.keyPressed.connect(self.app.ui.keyPressEvent)
|
||||
# self.tw.customContextMenuRequested.connect(self.on_menu_request)
|
||||
|
||||
self.geo_frame.show()
|
||||
|
||||
log.debug("Finished activating the Geometry Editor...")
|
||||
|
||||
def deactivate(self):
|
||||
try:
|
||||
QtGui.QGuiApplication.restoreOverrideCursor()
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# adjust the status of the menu entries related to the editor
|
||||
self.app.ui.menueditedit.setDisabled(False)
|
||||
self.app.ui.menueditok.setDisabled(True)
|
||||
|
||||
# adjust the visibility of some of the canvas context menu
|
||||
self.app.ui.popmenu_edit.setVisible(True)
|
||||
self.app.ui.popmenu_save.setVisible(False)
|
||||
|
@ -3454,16 +3664,37 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
self.app.ui.g_editor_cmenu.menuAction().setVisible(False)
|
||||
|
||||
try:
|
||||
# re-enable all the widgets in the Selected Tab that were disabled after entering in Edit Geometry Mode
|
||||
sel_tab_widget_list = self.app.ui.selected_tab.findChildren(QtWidgets.QWidget)
|
||||
for w in sel_tab_widget_list:
|
||||
w.setEnabled(True)
|
||||
except Exception as e:
|
||||
log.debug("FlatCAMGeoEditor.deactivate() --> %s" % str(e))
|
||||
self.item_selected.disconnect()
|
||||
except (AttributeError, TypeError):
|
||||
pass
|
||||
|
||||
try:
|
||||
# ## GUI Events
|
||||
self.tw.itemSelectionChanged.disconnect(self.on_tree_selection_change)
|
||||
# self.tw.keyPressed.connect(self.app.ui.keyPressEvent)
|
||||
# self.tw.customContextMenuRequested.connect(self.on_menu_request)
|
||||
except (AttributeError, TypeError):
|
||||
pass
|
||||
|
||||
# try:
|
||||
# # re-enable all the widgets in the Selected Tab that were disabled after entering in Edit Geometry Mode
|
||||
# sel_tab_widget_list = self.app.ui.selected_tab.findChildren(QtWidgets.QWidget)
|
||||
# for w in sel_tab_widget_list:
|
||||
# w.setEnabled(True)
|
||||
# except Exception as e:
|
||||
# log.debug("FlatCAMGeoEditor.deactivate() --> %s" % str(e))
|
||||
|
||||
# Show original geometry
|
||||
if self.fcgeometry:
|
||||
self.fcgeometry.visible = True
|
||||
|
||||
# clear the Tree
|
||||
self.tw.clear()
|
||||
self.geo_parent = self.tw.invisibleRootItem()
|
||||
|
||||
# hide the UI
|
||||
self.geo_frame.hide()
|
||||
|
||||
log.debug("Finished deactivating the Geometry Editor...")
|
||||
|
||||
def connect_canvas_event_handlers(self):
|
||||
|
@ -3553,7 +3784,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
except (TypeError, AttributeError):
|
||||
pass
|
||||
|
||||
self.app.ui.popmenu_copy.triggered.connect(self.app.on_copy_object)
|
||||
self.app.ui.popmenu_copy.triggered.connect(self.app.on_copy_command)
|
||||
self.app.ui.popmenu_delete.triggered.connect(self.app.on_delete)
|
||||
self.app.ui.popmenu_move.triggered.connect(self.app.obj_move)
|
||||
|
||||
|
@ -3665,6 +3896,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
self.utility.append(shape)
|
||||
else:
|
||||
self.storage.insert(shape) # TODO: Check performance
|
||||
self.build_ui()
|
||||
|
||||
def delete_utility_geometry(self):
|
||||
# for_deletion = [shape for shape in self.shape_buffer if shape.utility]
|
||||
|
@ -3705,6 +3937,8 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
self.deactivate()
|
||||
self.activate()
|
||||
|
||||
self.set_ui()
|
||||
|
||||
# Hide original geometry
|
||||
self.fcgeometry = fcgeometry
|
||||
fcgeometry.visible = False
|
||||
|
@ -3739,8 +3973,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
)
|
||||
)
|
||||
else:
|
||||
geo_to_edit = self.flatten(geometry=fcgeometry.solid_geometry,
|
||||
orient_val=milling_type)
|
||||
geo_to_edit = self.flatten(geometry=fcgeometry.solid_geometry, orient_val=milling_type)
|
||||
|
||||
for shape in geo_to_edit:
|
||||
if shape is not None: # TODO: Make flatten never create a None
|
||||
|
@ -3827,7 +4060,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
|
||||
self.pos = self.canvas.translate_coords(event_pos)
|
||||
|
||||
if self.app.grid_status() == True:
|
||||
if self.app.grid_status():
|
||||
self.pos = self.app.geo_editor.snap(self.pos[0], self.pos[1])
|
||||
else:
|
||||
self.pos = (self.pos[0], self.pos[1])
|
||||
|
@ -3840,7 +4073,9 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
# If the SHIFT key is pressed when LMB is clicked then the coordinates are copied to clipboard
|
||||
if modifiers == QtCore.Qt.ShiftModifier:
|
||||
self.app.clipboard.setText(
|
||||
self.app.defaults["global_point_clipboard_format"] % (self.pos[0], self.pos[1]))
|
||||
self.app.defaults["global_point_clipboard_format"] %
|
||||
(self.decimals, self.pos[0], self.decimals, self.pos[1])
|
||||
)
|
||||
return
|
||||
|
||||
# Selection with left mouse button
|
||||
|
@ -3907,7 +4142,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
return
|
||||
|
||||
# ### Snap coordinates ###
|
||||
if self.app.grid_status() == True:
|
||||
if self.app.grid_status():
|
||||
x, y = self.snap(x, y)
|
||||
|
||||
# Update cursor
|
||||
|
@ -3921,7 +4156,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
|
||||
# update the position label in the infobar since the APP mouse event handlers are disconnected
|
||||
self.app.ui.position_label.setText(" <b>X</b>: %.4f "
|
||||
"<b>Y</b>: %.4f" % (x, y))
|
||||
"<b>Y</b>: %.4f" % (x, y))
|
||||
|
||||
if self.pos is None:
|
||||
self.pos = (0, 0)
|
||||
|
@ -3930,7 +4165,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
|
||||
# update the reference position label in the infobar since the APP mouse event handlers are disconnected
|
||||
self.app.ui.rel_position_label.setText("<b>Dx</b>: %.4f <b>Dy</b>: "
|
||||
"%.4f " % (dx, dy))
|
||||
"%.4f " % (dx, dy))
|
||||
|
||||
if event.button == 1 and event_is_dragging and isinstance(self.active_tool, FCEraser):
|
||||
pass
|
||||
|
@ -3943,8 +4178,8 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
self.app.delete_selection_shape()
|
||||
if dx < 0:
|
||||
self.app.draw_moving_selection_shape((self.pos[0], self.pos[1]), (x, y),
|
||||
color=self.app.defaults["global_alt_sel_line"],
|
||||
face_color=self.app.defaults['global_alt_sel_fill'])
|
||||
color=self.app.defaults["global_alt_sel_line"],
|
||||
face_color=self.app.defaults['global_alt_sel_fill'])
|
||||
self.app.selection_type = False
|
||||
else:
|
||||
self.app.draw_moving_selection_shape((self.pos[0], self.pos[1]), (x, y))
|
||||
|
@ -3993,19 +4228,18 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
# self.app.inform.emit(msg)
|
||||
self.replot()
|
||||
elif event.button == right_button: # right click
|
||||
if self.app.ui.popMenu.mouse_is_panning == False:
|
||||
if self.app.ui.popMenu.mouse_is_panning is False:
|
||||
if self.in_action is False:
|
||||
try:
|
||||
QtGui.QGuiApplication.restoreOverrideCursor()
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if self.active_tool.complete is False and not isinstance(self.active_tool, FCSelect):
|
||||
self.active_tool.complete = True
|
||||
self.in_action = False
|
||||
self.delete_utility_geometry()
|
||||
self.app.inform.emit('[success] %s' %
|
||||
_("Done."))
|
||||
self.app.inform.emit('[success] %s' % _("Done."))
|
||||
self.select_tool('select')
|
||||
else:
|
||||
self.app.cursor = QtGui.QCursor()
|
||||
|
@ -4019,8 +4253,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
self.active_tool.make()
|
||||
if self.active_tool.complete:
|
||||
self.on_shape_complete()
|
||||
self.app.inform.emit('[success] %s' %
|
||||
_("Done."))
|
||||
self.app.inform.emit('[success] %s' % _("Done."))
|
||||
self.select_tool(self.active_tool.name)
|
||||
except Exception as e:
|
||||
log.warning("FLatCAMGeoEditor.on_geo_click_release() --> Error: %s" % str(e))
|
||||
|
@ -4064,6 +4297,27 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
self.selected = []
|
||||
self.selected = sel_objects_list
|
||||
|
||||
# if selection is done on canvas update the Tree in Selected Tab with the selection
|
||||
try:
|
||||
self.tw.itemSelectionChanged.disconnect(self.on_tree_selection_change)
|
||||
except (AttributeError, TypeError):
|
||||
pass
|
||||
|
||||
self.tw.selectionModel().clearSelection()
|
||||
for sel_shape in self.selected:
|
||||
iterator = QtWidgets.QTreeWidgetItemIterator(self.tw)
|
||||
while iterator.value():
|
||||
item = iterator.value()
|
||||
try:
|
||||
if int(item.text(1)) == id(sel_shape):
|
||||
item.setSelected(True)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
iterator += 1
|
||||
|
||||
self.tw.itemSelectionChanged.connect(self.on_tree_selection_change)
|
||||
|
||||
self.replot()
|
||||
|
||||
def draw_utility_geometry(self, geo):
|
||||
|
@ -4113,6 +4367,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
for shape in tempref:
|
||||
self.delete_shape(shape)
|
||||
self.selected = []
|
||||
self.build_ui()
|
||||
|
||||
def delete_shape(self, shape):
|
||||
|
||||
|
@ -4275,7 +4530,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
log.debug("FlatCAMGeoEditor.on_shape_complete() Error --> %s" % str(e))
|
||||
return 'fail'
|
||||
|
||||
shape_list = list()
|
||||
shape_list = []
|
||||
try:
|
||||
for geo in geom:
|
||||
shape_list.append(DrawToolShape(geo))
|
||||
|
@ -4396,13 +4651,24 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
fcgeometry.tools[self.multigeo_tool]['solid_geometry'] = []
|
||||
# for shape in self.shape_buffer:
|
||||
for shape in self.storage.get_objects():
|
||||
fcgeometry.tools[self.multigeo_tool]['solid_geometry'].append(shape.geo)
|
||||
new_geo = shape.geo
|
||||
|
||||
# simplify the MultiLineString
|
||||
if isinstance(new_geo, MultiLineString):
|
||||
new_geo = linemerge(new_geo)
|
||||
|
||||
fcgeometry.tools[self.multigeo_tool]['solid_geometry'].append(new_geo)
|
||||
self.multigeo_tool = None
|
||||
|
||||
fcgeometry.solid_geometry = []
|
||||
# for shape in self.shape_buffer:
|
||||
for shape in self.storage.get_objects():
|
||||
fcgeometry.solid_geometry.append(shape.geo)
|
||||
new_geo = shape.geo
|
||||
|
||||
# simplify the MultiLineString
|
||||
if isinstance(new_geo, MultiLineString):
|
||||
new_geo = linemerge(new_geo)
|
||||
fcgeometry.solid_geometry.append(new_geo)
|
||||
|
||||
def update_options(self, obj):
|
||||
if self.paint_tooldia:
|
||||
|
@ -4777,11 +5043,11 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
else:
|
||||
poly_buf = Polygon(geo_obj).buffer(-margin)
|
||||
|
||||
if method == "seed":
|
||||
if method == _("Seed"):
|
||||
cp = Geometry.clear_polygon2(self, polygon_to_clear=poly_buf, tooldia=tooldia,
|
||||
steps_per_circle=self.app.defaults["geometry_circle_steps"],
|
||||
overlap=overlap, contour=contour, connect=connect)
|
||||
elif method == "lines":
|
||||
elif method == _("Lines"):
|
||||
cp = Geometry.clear_polygon3(self, polygon=poly_buf, tooldia=tooldia,
|
||||
steps_per_circle=self.app.defaults["geometry_circle_steps"],
|
||||
overlap=overlap, contour=contour, connect=connect)
|
||||
|
@ -4794,12 +5060,10 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
local_results += list(cp.get_objects())
|
||||
except Exception as e:
|
||||
log.debug("Could not Paint the polygons. %s" % str(e))
|
||||
self.app.inform.emit('[ERROR] %s\n%s' %
|
||||
(_("Could not do Paint. Try a different combination of"
|
||||
" parameters. Or a different method of Paint"),
|
||||
str(e)
|
||||
)
|
||||
)
|
||||
self.app.inform.emit(
|
||||
'[ERROR] %s\n%s' % (_("Could not do Paint. Try a different combination of parameters. "
|
||||
"Or a different method of Paint"), str(e))
|
||||
)
|
||||
return
|
||||
|
||||
# add the result to the results list
|
||||
|
@ -4808,8 +5072,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
# This is a dirty patch:
|
||||
for r in results:
|
||||
self.add_shape(DrawToolShape(r))
|
||||
self.app.inform.emit(
|
||||
'[success] %s' % _("Paint done."))
|
||||
self.app.inform.emit('[success] %s' % _("Paint done."))
|
||||
self.replot()
|
||||
|
||||
def flatten(self, geometry, orient_val=1, reset=True, pathonly=False):
|
||||
|
|
|
@ -288,14 +288,14 @@ class FCPad(FCShapeTool):
|
|||
|
||||
ap_type = self.draw_app.storage_dict[self.draw_app.last_aperture_selected]['type']
|
||||
if ap_type == 'C':
|
||||
new_geo_el = dict()
|
||||
new_geo_el = {}
|
||||
|
||||
center = Point([point_x, point_y])
|
||||
new_geo_el['solid'] = center.buffer(self.radius)
|
||||
new_geo_el['follow'] = center
|
||||
return new_geo_el
|
||||
elif ap_type == 'R':
|
||||
new_geo_el = dict()
|
||||
new_geo_el = {}
|
||||
|
||||
p1 = (point_x - self.half_width, point_y - self.half_height)
|
||||
p2 = (point_x + self.half_width, point_y - self.half_height)
|
||||
|
@ -307,7 +307,7 @@ class FCPad(FCShapeTool):
|
|||
return new_geo_el
|
||||
elif ap_type == 'O':
|
||||
geo = []
|
||||
new_geo_el = dict()
|
||||
new_geo_el = {}
|
||||
|
||||
if self.half_height > self.half_width:
|
||||
p1 = (point_x - self.half_width, point_y - self.half_height + self.half_width)
|
||||
|
@ -545,7 +545,7 @@ class FCPadArray(FCShapeTool):
|
|||
)
|
||||
|
||||
if static is None or static is False:
|
||||
new_geo_el = dict()
|
||||
new_geo_el = {}
|
||||
|
||||
if 'solid' in geo_el:
|
||||
new_geo_el['solid'] = affinity.translate(
|
||||
|
@ -602,14 +602,14 @@ class FCPadArray(FCShapeTool):
|
|||
|
||||
ap_type = self.draw_app.storage_dict[self.draw_app.last_aperture_selected]['type']
|
||||
if ap_type == 'C':
|
||||
new_geo_el = dict()
|
||||
new_geo_el = {}
|
||||
|
||||
center = Point([point_x, point_y])
|
||||
new_geo_el['solid'] = center.buffer(self.radius)
|
||||
new_geo_el['follow'] = center
|
||||
return new_geo_el
|
||||
elif ap_type == 'R':
|
||||
new_geo_el = dict()
|
||||
new_geo_el = {}
|
||||
|
||||
p1 = (point_x - self.half_width, point_y - self.half_height)
|
||||
p2 = (point_x + self.half_width, point_y - self.half_height)
|
||||
|
@ -620,7 +620,7 @@ class FCPadArray(FCShapeTool):
|
|||
return new_geo_el
|
||||
elif ap_type == 'O':
|
||||
geo = []
|
||||
new_geo_el = dict()
|
||||
new_geo_el = {}
|
||||
|
||||
if self.half_height > self.half_width:
|
||||
p1 = (point_x - self.half_width, point_y - self.half_height + self.half_width)
|
||||
|
@ -812,7 +812,7 @@ class FCPoligonize(FCShapeTool):
|
|||
except KeyError:
|
||||
self.draw_app.on_aperture_add(apid='0')
|
||||
current_storage = self.draw_app.storage_dict['0']['geometry']
|
||||
new_el = dict()
|
||||
new_el = {}
|
||||
new_el['solid'] = geo
|
||||
new_el['follow'] = geo.exterior
|
||||
self.draw_app.on_grb_shape_complete(current_storage, specific_shape=DrawToolShape(deepcopy(new_el)))
|
||||
|
@ -827,7 +827,7 @@ class FCPoligonize(FCShapeTool):
|
|||
self.draw_app.on_aperture_add(apid='0')
|
||||
current_storage = self.draw_app.storage_dict['0']['geometry']
|
||||
|
||||
new_el = dict()
|
||||
new_el = {}
|
||||
new_el['solid'] = fused_geo
|
||||
new_el['follow'] = fused_geo.exterior
|
||||
self.draw_app.on_grb_shape_complete(current_storage, specific_shape=DrawToolShape(deepcopy(new_el)))
|
||||
|
@ -915,7 +915,7 @@ class FCRegion(FCShapeTool):
|
|||
self.gridy_size = float(self.draw_app.app.ui.grid_gap_y_entry.get_value())
|
||||
|
||||
def utility_geometry(self, data=None):
|
||||
new_geo_el = dict()
|
||||
new_geo_el = {}
|
||||
|
||||
x = data[0]
|
||||
y = data[1]
|
||||
|
@ -983,7 +983,7 @@ class FCRegion(FCShapeTool):
|
|||
self.inter_point = data
|
||||
|
||||
self.temp_points.append(data)
|
||||
new_geo_el = dict()
|
||||
new_geo_el = {}
|
||||
|
||||
if len(self.temp_points) > 1:
|
||||
try:
|
||||
|
@ -1049,7 +1049,7 @@ class FCRegion(FCShapeTool):
|
|||
|
||||
self.temp_points.append(self.inter_point)
|
||||
self.temp_points.append(data)
|
||||
new_geo_el = dict()
|
||||
new_geo_el = {}
|
||||
|
||||
new_geo_el['solid'] = LinearRing(self.temp_points).buffer(self.buf_val,
|
||||
resolution=int(self.steps_per_circle / 4),
|
||||
|
@ -1070,7 +1070,7 @@ class FCRegion(FCShapeTool):
|
|||
else:
|
||||
self.draw_app.last_aperture_selected = '0'
|
||||
|
||||
new_geo_el = dict()
|
||||
new_geo_el = {}
|
||||
|
||||
new_geo_el['solid'] = Polygon(self.points).buffer(self.buf_val,
|
||||
resolution=int(self.steps_per_circle / 4),
|
||||
|
@ -1183,7 +1183,7 @@ class FCTrack(FCRegion):
|
|||
self.draw_app.app.inform.emit(_('Track Mode 1: 45 degrees ...'))
|
||||
|
||||
def make(self):
|
||||
new_geo_el = dict()
|
||||
new_geo_el = {}
|
||||
if len(self.temp_points) == 1:
|
||||
new_geo_el['solid'] = Point(self.temp_points).buffer(self.buf_val,
|
||||
resolution=int(self.steps_per_circle / 4))
|
||||
|
@ -1219,7 +1219,7 @@ class FCTrack(FCRegion):
|
|||
except IndexError:
|
||||
self.points.append(point)
|
||||
|
||||
new_geo_el = dict()
|
||||
new_geo_el = {}
|
||||
|
||||
if len(self.temp_points) == 1:
|
||||
new_geo_el['solid'] = Point(self.temp_points).buffer(self.buf_val,
|
||||
|
@ -1242,7 +1242,7 @@ class FCTrack(FCRegion):
|
|||
|
||||
def utility_geometry(self, data=None):
|
||||
self.update_grid_info()
|
||||
new_geo_el = dict()
|
||||
new_geo_el = {}
|
||||
|
||||
if len(self.points) == 0:
|
||||
new_geo_el['solid'] = Point(data).buffer(self.buf_val,
|
||||
|
@ -1427,10 +1427,10 @@ class FCDisc(FCShapeTool):
|
|||
if '0' in self.draw_app.storage_dict:
|
||||
self.storage_obj = self.draw_app.storage_dict['0']['geometry']
|
||||
else:
|
||||
self.draw_app.storage_dict['0'] = dict()
|
||||
self.draw_app.storage_dict['0'] = {}
|
||||
self.draw_app.storage_dict['0']['type'] = 'C'
|
||||
self.draw_app.storage_dict['0']['size'] = 0.0
|
||||
self.draw_app.storage_dict['0']['geometry'] = list()
|
||||
self.draw_app.storage_dict['0']['geometry'] = []
|
||||
self.storage_obj = self.draw_app.storage_dict['0']['geometry']
|
||||
|
||||
self.draw_app.app.inform.emit(_("Click on Center point ..."))
|
||||
|
@ -1453,7 +1453,7 @@ class FCDisc(FCShapeTool):
|
|||
return ""
|
||||
|
||||
def utility_geometry(self, data=None):
|
||||
new_geo_el = dict()
|
||||
new_geo_el = {}
|
||||
if len(self.points) == 1:
|
||||
p1 = self.points[0]
|
||||
p2 = data
|
||||
|
@ -1464,7 +1464,7 @@ class FCDisc(FCShapeTool):
|
|||
return None
|
||||
|
||||
def make(self):
|
||||
new_geo_el = dict()
|
||||
new_geo_el = {}
|
||||
|
||||
try:
|
||||
QtGui.QGuiApplication.restoreOverrideCursor()
|
||||
|
@ -1530,10 +1530,10 @@ class FCSemiDisc(FCShapeTool):
|
|||
if '0' in self.draw_app.storage_dict:
|
||||
self.storage_obj = self.draw_app.storage_dict['0']['geometry']
|
||||
else:
|
||||
self.draw_app.storage_dict['0'] = dict()
|
||||
self.draw_app.storage_dict['0'] = {}
|
||||
self.draw_app.storage_dict['0']['type'] = 'C'
|
||||
self.draw_app.storage_dict['0']['size'] = 0.0
|
||||
self.draw_app.storage_dict['0']['geometry'] = list()
|
||||
self.draw_app.storage_dict['0']['geometry'] = []
|
||||
self.storage_obj = self.draw_app.storage_dict['0']['geometry']
|
||||
|
||||
self.steps_per_circ = self.draw_app.app.defaults["gerber_circle_steps"]
|
||||
|
@ -1592,10 +1592,10 @@ class FCSemiDisc(FCShapeTool):
|
|||
return _('Mode: Center -> Start -> Stop. Click on Center point ...')
|
||||
|
||||
def utility_geometry(self, data=None):
|
||||
new_geo_el = dict()
|
||||
new_geo_el_pt1 = dict()
|
||||
new_geo_el_pt2 = dict()
|
||||
new_geo_el_pt3 = dict()
|
||||
new_geo_el = {}
|
||||
new_geo_el_pt1 = {}
|
||||
new_geo_el_pt2 = {}
|
||||
new_geo_el_pt3 = {}
|
||||
|
||||
if len(self.points) == 1: # Show the radius
|
||||
center = self.points[0]
|
||||
|
@ -1681,7 +1681,7 @@ class FCSemiDisc(FCShapeTool):
|
|||
|
||||
def make(self):
|
||||
self.draw_app.current_storage = self.storage_obj
|
||||
new_geo_el = dict()
|
||||
new_geo_el = {}
|
||||
|
||||
if self.mode == 'c12':
|
||||
center = self.points[0]
|
||||
|
@ -2031,7 +2031,7 @@ class FCApertureMove(FCShapeTool):
|
|||
for select_shape in self.draw_app.get_selected():
|
||||
if select_shape in self.current_storage:
|
||||
geometric_data = select_shape.geo
|
||||
new_geo_el = dict()
|
||||
new_geo_el = {}
|
||||
if 'solid' in geometric_data:
|
||||
new_geo_el['solid'] = affinity.translate(geometric_data['solid'], xoff=dx, yoff=dy)
|
||||
if 'follow' in geometric_data:
|
||||
|
@ -2084,7 +2084,7 @@ class FCApertureMove(FCShapeTool):
|
|||
|
||||
if len(self.draw_app.get_selected()) <= self.sel_limit:
|
||||
for geom in self.draw_app.get_selected():
|
||||
new_geo_el = dict()
|
||||
new_geo_el = {}
|
||||
if 'solid' in geom.geo:
|
||||
new_geo_el['solid'] = affinity.translate(geom.geo['solid'], xoff=dx, yoff=dy)
|
||||
if 'follow' in geom.geo:
|
||||
|
@ -2094,7 +2094,7 @@ class FCApertureMove(FCShapeTool):
|
|||
geo_list.append(deepcopy(new_geo_el))
|
||||
return DrawToolUtilityShape(geo_list)
|
||||
else:
|
||||
ss_el = dict()
|
||||
ss_el = {}
|
||||
ss_el['solid'] = affinity.translate(self.selection_shape, xoff=dx, yoff=dy)
|
||||
return DrawToolUtilityShape(ss_el)
|
||||
|
||||
|
@ -2115,7 +2115,7 @@ class FCApertureCopy(FCApertureMove):
|
|||
for select_shape in self.draw_app.get_selected():
|
||||
if select_shape in self.current_storage:
|
||||
geometric_data = select_shape.geo
|
||||
new_geo_el = dict()
|
||||
new_geo_el = {}
|
||||
if 'solid' in geometric_data:
|
||||
new_geo_el['solid'] = affinity.translate(geometric_data['solid'], xoff=dx, yoff=dy)
|
||||
if 'follow' in geometric_data:
|
||||
|
@ -2274,7 +2274,7 @@ class FCEraser(FCShapeTool):
|
|||
dy = data[1] - self.origin[1]
|
||||
|
||||
for geom in self.draw_app.get_selected():
|
||||
new_geo_el = dict()
|
||||
new_geo_el = {}
|
||||
if 'solid' in geom.geo:
|
||||
new_geo_el['solid'] = affinity.translate(geom.geo['solid'], xoff=dx, yoff=dy)
|
||||
if 'follow' in geom.geo:
|
||||
|
@ -2300,10 +2300,10 @@ class FCApertureSelect(DrawTool):
|
|||
|
||||
# since FCApertureSelect tool is activated whenever a tool is exited I place here the reinitialization of the
|
||||
# bending modes using in FCRegion and FCTrack
|
||||
self.draw_app.bend_mode = 1
|
||||
self.grb_editor_app.bend_mode = 1
|
||||
|
||||
# here store the selected apertures
|
||||
self.sel_aperture = set()
|
||||
self.sel_aperture = []
|
||||
|
||||
try:
|
||||
self.grb_editor_app.apertures_table.clearSelection()
|
||||
|
@ -2332,7 +2332,7 @@ class FCApertureSelect(DrawTool):
|
|||
else:
|
||||
mod_key = None
|
||||
|
||||
if mod_key == self.draw_app.app.defaults["global_mselect_key"]:
|
||||
if mod_key == self.grb_editor_app.app.defaults["global_mselect_key"]:
|
||||
pass
|
||||
else:
|
||||
self.grb_editor_app.selected = []
|
||||
|
@ -2348,46 +2348,53 @@ class FCApertureSelect(DrawTool):
|
|||
else:
|
||||
mod_key = None
|
||||
|
||||
if mod_key != self.grb_editor_app.app.defaults["global_mselect_key"]:
|
||||
self.grb_editor_app.selected.clear()
|
||||
self.sel_aperture.clear()
|
||||
|
||||
for storage in self.grb_editor_app.storage_dict:
|
||||
try:
|
||||
for geo_el in self.grb_editor_app.storage_dict[storage]['geometry']:
|
||||
if 'solid' in geo_el.geo:
|
||||
geometric_data = geo_el.geo['solid']
|
||||
for shape_stored in self.grb_editor_app.storage_dict[storage]['geometry']:
|
||||
if 'solid' in shape_stored.geo:
|
||||
geometric_data = shape_stored.geo['solid']
|
||||
if Point(point).within(geometric_data):
|
||||
if mod_key == self.grb_editor_app.app.defaults["global_mselect_key"]:
|
||||
if geo_el in self.draw_app.selected:
|
||||
self.draw_app.selected.remove(geo_el)
|
||||
self.sel_aperture.remove(storage)
|
||||
else:
|
||||
# add the object to the selected shapes
|
||||
self.draw_app.selected.append(geo_el)
|
||||
self.sel_aperture.add(storage)
|
||||
if shape_stored in self.grb_editor_app.selected:
|
||||
self.grb_editor_app.selected.remove(shape_stored)
|
||||
else:
|
||||
self.draw_app.selected.append(geo_el)
|
||||
self.sel_aperture.add(storage)
|
||||
# add the object to the selected shapes
|
||||
self.grb_editor_app.selected.append(shape_stored)
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
# select the aperture in the Apertures Table that is associated with the selected shape
|
||||
self.sel_aperture.clear()
|
||||
|
||||
self.grb_editor_app.apertures_table.clearSelection()
|
||||
try:
|
||||
self.draw_app.apertures_table.cellPressed.disconnect()
|
||||
self.grb_editor_app.apertures_table.cellPressed.disconnect()
|
||||
except Exception as e:
|
||||
log.debug("FlatCAMGrbEditor.FCApertureSelect.click_release() --> %s" % str(e))
|
||||
|
||||
self.grb_editor_app.apertures_table.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
|
||||
for shape_s in self.grb_editor_app.selected:
|
||||
for storage in self.grb_editor_app.storage_dict:
|
||||
if shape_s in self.grb_editor_app.storage_dict[storage]['geometry']:
|
||||
self.sel_aperture.append(storage)
|
||||
|
||||
# self.grb_editor_app.apertures_table.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
|
||||
for aper in self.sel_aperture:
|
||||
for row in range(self.grb_editor_app.apertures_table.rowCount()):
|
||||
if str(aper) == self.grb_editor_app.apertures_table.item(row, 1).text():
|
||||
self.grb_editor_app.apertures_table.selectRow(row)
|
||||
self.draw_app.last_aperture_selected = aper
|
||||
self.grb_editor_app.apertures_table.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
|
||||
if not self.grb_editor_app.apertures_table.item(row, 0).isSelected():
|
||||
self.grb_editor_app.apertures_table.selectRow(row)
|
||||
self.grb_editor_app.last_aperture_selected = aper
|
||||
# self.grb_editor_app.apertures_table.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
|
||||
|
||||
self.draw_app.apertures_table.cellPressed.connect(self.draw_app.on_row_selected)
|
||||
self.grb_editor_app.apertures_table.cellPressed.connect(self.grb_editor_app.on_row_selected)
|
||||
|
||||
return ""
|
||||
|
||||
def clean_up(self):
|
||||
self.draw_app.plot_all()
|
||||
self.grb_editor_app.plot_all()
|
||||
|
||||
|
||||
class FCTransform(FCShapeTool):
|
||||
|
@ -2915,30 +2922,30 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
# # ## Data
|
||||
self.active_tool = None
|
||||
|
||||
self.storage_dict = dict()
|
||||
self.current_storage = list()
|
||||
self.storage_dict = {}
|
||||
self.current_storage = []
|
||||
|
||||
self.sorted_apid = list()
|
||||
self.sorted_apid = []
|
||||
|
||||
self.new_apertures = dict()
|
||||
self.new_aperture_macros = dict()
|
||||
self.new_apertures = {}
|
||||
self.new_aperture_macros = {}
|
||||
|
||||
# store here the plot promises, if empty the delayed plot will be activated
|
||||
self.grb_plot_promises = list()
|
||||
self.grb_plot_promises = []
|
||||
|
||||
# dictionary to store the tool_row and aperture codes in Tool_table
|
||||
# it will be updated everytime self.build_ui() is called
|
||||
self.olddia_newdia = dict()
|
||||
self.olddia_newdia = {}
|
||||
|
||||
self.tool2tooldia = dict()
|
||||
self.tool2tooldia = {}
|
||||
|
||||
# this will store the value for the last selected tool, for use after clicking on canvas when the selection
|
||||
# is cleared but as a side effect also the selected tool is cleared
|
||||
self.last_aperture_selected = None
|
||||
self.utility = list()
|
||||
self.utility = []
|
||||
|
||||
# this will store the polygons marked by mark are to be perhaps deleted
|
||||
self.geo_to_delete = list()
|
||||
self.geo_to_delete = []
|
||||
|
||||
# this will flag if the Editor "tools" are launched from key shortcuts (True) or from menu toolbar (False)
|
||||
self.launched_from_shortcuts = False
|
||||
|
@ -2950,7 +2957,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
self.apdim_lbl.hide()
|
||||
self.apdim_entry.hide()
|
||||
self.gerber_obj = None
|
||||
self.gerber_obj_options = dict()
|
||||
self.gerber_obj_options = {}
|
||||
|
||||
# VisPy Visuals
|
||||
if self.app.is_legacy is False:
|
||||
|
@ -3033,11 +3040,14 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
self.pool = self.app.pool
|
||||
|
||||
# Multiprocessing results
|
||||
self.results = list()
|
||||
self.results = []
|
||||
|
||||
# A QTimer
|
||||
self.plot_thread = None
|
||||
|
||||
# a QThread for the edit process
|
||||
self.thread = QtCore.QThread()
|
||||
|
||||
# store the status of the editor so the Delete at object level will not work until the edit is finished
|
||||
self.editor_active = False
|
||||
|
||||
|
@ -3099,6 +3109,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
def pool_recreated(self, pool):
|
||||
self.shapes.pool = pool
|
||||
self.tool_shape.pool = pool
|
||||
self.pool = pool
|
||||
|
||||
def set_ui(self):
|
||||
# updated units
|
||||
|
@ -3423,7 +3434,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
|
||||
# I've added this flag_del variable because dictionary don't like
|
||||
# having keys deleted while iterating through them
|
||||
flag_del = list()
|
||||
flag_del = []
|
||||
for deleted_tool in self.tool2tooldia:
|
||||
if self.tool2tooldia[deleted_tool] == deleted_aperture:
|
||||
flag_del.append(deleted_tool)
|
||||
|
@ -3493,7 +3504,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
geometry = []
|
||||
for geo_el in self.storage_dict[dia_changed]:
|
||||
geometric_data = geo_el.geo
|
||||
new_geo_el = dict()
|
||||
new_geo_el = {}
|
||||
if 'solid' in geometric_data:
|
||||
new_geo_el['solid'] = deepcopy(affinity.scale(geometric_data['solid'],
|
||||
xfact=factor, yfact=factor))
|
||||
|
@ -3742,7 +3753,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
except (TypeError, AttributeError):
|
||||
pass
|
||||
|
||||
self.app.ui.popmenu_copy.triggered.connect(self.app.on_copy_object)
|
||||
self.app.ui.popmenu_copy.triggered.connect(self.app.on_copy_command)
|
||||
self.app.ui.popmenu_delete.triggered.connect(self.app.on_delete)
|
||||
self.app.ui.popmenu_move.triggered.connect(self.app.obj_move)
|
||||
|
||||
|
@ -3920,101 +3931,130 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
# # and add the first aperture to have something to play with
|
||||
# self.on_aperture_add('10')
|
||||
|
||||
def worker_job(app_obj):
|
||||
with app_obj.app.proc_container.new('%s ...' % _("Loading Gerber into Editor")):
|
||||
# ############################################################# ##
|
||||
# APPLY CLEAR_GEOMETRY on the SOLID_GEOMETRY
|
||||
# ############################################################# ##
|
||||
# self.app.worker_task.emit({'fcn': worker_job, 'params': [self]})
|
||||
|
||||
# list of clear geos that are to be applied to the entire file
|
||||
global_clear_geo = []
|
||||
class Execute_Edit(QtCore.QObject):
|
||||
|
||||
# create one big geometry made out of all 'negative' (clear) polygons
|
||||
for apid in app_obj.gerber_obj.apertures:
|
||||
# first check if we have any clear_geometry (LPC) and if yes added it to the global_clear_geo
|
||||
if 'geometry' in app_obj.gerber_obj.apertures[apid]:
|
||||
for elem in app_obj.gerber_obj.apertures[apid]['geometry']:
|
||||
if 'clear' in elem:
|
||||
global_clear_geo.append(elem['clear'])
|
||||
log.warning("Found %d clear polygons." % len(global_clear_geo))
|
||||
start = QtCore.pyqtSignal(str)
|
||||
|
||||
global_clear_geo = MultiPolygon(global_clear_geo)
|
||||
if isinstance(global_clear_geo, Polygon):
|
||||
global_clear_geo = list(global_clear_geo)
|
||||
def __init__(self, app):
|
||||
super(Execute_Edit, self).__init__()
|
||||
self.app = app
|
||||
self.start.connect(self.run)
|
||||
|
||||
# we subtract the big "negative" (clear) geometry from each solid polygon but only the part of
|
||||
# clear geometry that fits inside the solid. otherwise we may loose the solid
|
||||
for apid in app_obj.gerber_obj.apertures:
|
||||
temp_solid_geometry = []
|
||||
if 'geometry' in app_obj.gerber_obj.apertures[apid]:
|
||||
# for elem in self.gerber_obj.apertures[apid]['geometry']:
|
||||
# if 'solid' in elem:
|
||||
# solid_geo = elem['solid']
|
||||
# for clear_geo in global_clear_geo:
|
||||
# # Make sure that the clear_geo is within the solid_geo otherwise we loose
|
||||
# # the solid_geometry. We want for clear_geometry just to cut into solid_geometry not to
|
||||
# # delete it
|
||||
# if clear_geo.within(solid_geo):
|
||||
# solid_geo = solid_geo.difference(clear_geo)
|
||||
# try:
|
||||
# for poly in solid_geo:
|
||||
# new_elem = dict()
|
||||
#
|
||||
# new_elem['solid'] = poly
|
||||
# if 'clear' in elem:
|
||||
# new_elem['clear'] = poly
|
||||
# if 'follow' in elem:
|
||||
# new_elem['follow'] = poly
|
||||
# temp_elem.append(deepcopy(new_elem))
|
||||
# except TypeError:
|
||||
# new_elem = dict()
|
||||
# new_elem['solid'] = solid_geo
|
||||
# if 'clear' in elem:
|
||||
# new_elem['clear'] = solid_geo
|
||||
# if 'follow' in elem:
|
||||
# new_elem['follow'] = solid_geo
|
||||
# temp_elem.append(deepcopy(new_elem))
|
||||
for elem in app_obj.gerber_obj.apertures[apid]['geometry']:
|
||||
new_elem = dict()
|
||||
if 'solid' in elem:
|
||||
solid_geo = elem['solid']
|
||||
@staticmethod
|
||||
def worker_job(app_obj):
|
||||
with app_obj.app.proc_container.new('%s ...' % _("Loading Gerber into Editor")):
|
||||
# ############################################################# ##
|
||||
# APPLY CLEAR_GEOMETRY on the SOLID_GEOMETRY
|
||||
# ############################################################# ##
|
||||
|
||||
for clear_geo in global_clear_geo:
|
||||
# Make sure that the clear_geo is within the solid_geo otherwise we loose
|
||||
# the solid_geometry. We want for clear_geometry just to cut into solid_geometry
|
||||
# not to delete it
|
||||
if clear_geo.within(solid_geo):
|
||||
solid_geo = solid_geo.difference(clear_geo)
|
||||
# list of clear geos that are to be applied to the entire file
|
||||
global_clear_geo = []
|
||||
|
||||
new_elem['solid'] = solid_geo
|
||||
if 'clear' in elem:
|
||||
new_elem['clear'] = elem['clear']
|
||||
if 'follow' in elem:
|
||||
new_elem['follow'] = elem['follow']
|
||||
temp_solid_geometry.append(deepcopy(new_elem))
|
||||
# create one big geometry made out of all 'negative' (clear) polygons
|
||||
for apid in app_obj.gerber_obj.apertures:
|
||||
# first check if we have any clear_geometry (LPC) and if yes added it to the global_clear_geo
|
||||
if 'geometry' in app_obj.gerber_obj.apertures[apid]:
|
||||
for elem in app_obj.gerber_obj.apertures[apid]['geometry']:
|
||||
if 'clear' in elem:
|
||||
global_clear_geo.append(elem['clear'])
|
||||
log.warning("Found %d clear polygons." % len(global_clear_geo))
|
||||
|
||||
app_obj.gerber_obj.apertures[apid]['geometry'] = deepcopy(temp_solid_geometry)
|
||||
log.warning("Polygon difference done for %d apertures." % len(app_obj.gerber_obj.apertures))
|
||||
if global_clear_geo:
|
||||
global_clear_geo = MultiPolygon(global_clear_geo)
|
||||
if isinstance(global_clear_geo, Polygon):
|
||||
global_clear_geo = list(global_clear_geo)
|
||||
|
||||
# Loading the Geometry into Editor Storage
|
||||
for ap_id, ap_dict in app_obj.gerber_obj.apertures.items():
|
||||
app_obj.results.append(app_obj.pool.apply_async(app_obj.add_apertures, args=(ap_id, ap_dict)))
|
||||
# we subtract the big "negative" (clear) geometry from each solid polygon but only the part of
|
||||
# clear geometry that fits inside the solid. otherwise we may loose the solid
|
||||
for apid in app_obj.gerber_obj.apertures:
|
||||
temp_solid_geometry = []
|
||||
if 'geometry' in app_obj.gerber_obj.apertures[apid]:
|
||||
# for elem in self.gerber_obj.apertures[apid]['geometry']:
|
||||
# if 'solid' in elem:
|
||||
# solid_geo = elem['solid']
|
||||
# for clear_geo in global_clear_geo:
|
||||
# # Make sure that the clear_geo is within the solid_geo otherwise we loose
|
||||
# # the solid_geometry. We want for clear_geometry just to cut into solid_geometry not to
|
||||
# # delete it
|
||||
# if clear_geo.within(solid_geo):
|
||||
# solid_geo = solid_geo.difference(clear_geo)
|
||||
# try:
|
||||
# for poly in solid_geo:
|
||||
# new_elem = {}
|
||||
#
|
||||
# new_elem['solid'] = poly
|
||||
# if 'clear' in elem:
|
||||
# new_elem['clear'] = poly
|
||||
# if 'follow' in elem:
|
||||
# new_elem['follow'] = poly
|
||||
# temp_elem.append(deepcopy(new_elem))
|
||||
# except TypeError:
|
||||
# new_elem = {}
|
||||
# new_elem['solid'] = solid_geo
|
||||
# if 'clear' in elem:
|
||||
# new_elem['clear'] = solid_geo
|
||||
# if 'follow' in elem:
|
||||
# new_elem['follow'] = solid_geo
|
||||
# temp_elem.append(deepcopy(new_elem))
|
||||
for elem in app_obj.gerber_obj.apertures[apid]['geometry']:
|
||||
new_elem = {}
|
||||
if 'solid' in elem:
|
||||
solid_geo = elem['solid']
|
||||
if not global_clear_geo or global_clear_geo.is_empty:
|
||||
pass
|
||||
else:
|
||||
for clear_geo in global_clear_geo:
|
||||
# Make sure that the clear_geo is within the solid_geo otherwise we loose
|
||||
# the solid_geometry. We want for clear_geometry just to cut into
|
||||
# solid_geometry not to delete it
|
||||
if clear_geo.within(solid_geo):
|
||||
solid_geo = solid_geo.difference(clear_geo)
|
||||
|
||||
output = list()
|
||||
for p in app_obj.results:
|
||||
output.append(p.get())
|
||||
new_elem['solid'] = solid_geo
|
||||
if 'clear' in elem:
|
||||
new_elem['clear'] = elem['clear']
|
||||
if 'follow' in elem:
|
||||
new_elem['follow'] = elem['follow']
|
||||
temp_solid_geometry.append(deepcopy(new_elem))
|
||||
|
||||
for elem in output:
|
||||
app_obj.storage_dict[elem[0]] = deepcopy(elem[1])
|
||||
app_obj.gerber_obj.apertures[apid]['geometry'] = deepcopy(temp_solid_geometry)
|
||||
log.warning("Polygon difference done for %d apertures." % len(app_obj.gerber_obj.apertures))
|
||||
|
||||
app_obj.mp_finished.emit(output)
|
||||
try:
|
||||
# Loading the Geometry into Editor Storage
|
||||
for ap_id, ap_dict in app_obj.gerber_obj.apertures.items():
|
||||
app_obj.results.append(
|
||||
app_obj.pool.apply_async(app_obj.add_apertures, args=(ap_id, ap_dict))
|
||||
)
|
||||
except Exception as e:
|
||||
log.debug(
|
||||
"FlatCAMGrbEditor.edit_fcgerber.worker_job() Adding processes to pool --> %s" % str(e))
|
||||
traceback.print_exc()
|
||||
|
||||
self.app.worker_task.emit({'fcn': worker_job, 'params': [self]})
|
||||
output = []
|
||||
for p in app_obj.results:
|
||||
output.append(p.get())
|
||||
|
||||
for elem in output:
|
||||
app_obj.storage_dict[elem[0]] = deepcopy(elem[1])
|
||||
|
||||
app_obj.mp_finished.emit(output)
|
||||
|
||||
def run(self):
|
||||
self.worker_job(self.app)
|
||||
|
||||
self.thread.start(QtCore.QThread.NormalPriority)
|
||||
|
||||
executable_edit = Execute_Edit(app=self)
|
||||
executable_edit.moveToThread(self.thread)
|
||||
executable_edit.start.emit("Started")
|
||||
|
||||
@staticmethod
|
||||
def add_apertures(aperture_id, aperture_dict):
|
||||
storage_elem = list()
|
||||
storage_dict = dict()
|
||||
storage_elem = []
|
||||
storage_dict = {}
|
||||
|
||||
for k, v in list(aperture_dict.items()):
|
||||
try:
|
||||
|
@ -4073,7 +4113,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
def update_options(obj):
|
||||
try:
|
||||
if not obj.options:
|
||||
obj.options = dict()
|
||||
obj.options = {}
|
||||
obj.options['xmin'] = 0
|
||||
obj.options['ymin'] = 0
|
||||
obj.options['xmax'] = 0
|
||||
|
@ -4082,7 +4122,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
else:
|
||||
return False
|
||||
except AttributeError:
|
||||
obj.options = dict()
|
||||
obj.options = {}
|
||||
return True
|
||||
|
||||
def new_edited_gerber(self, outname, aperture_storage):
|
||||
|
@ -4101,7 +4141,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
out_name = outname
|
||||
storage_dict = aperture_storage
|
||||
|
||||
local_storage_dict = dict()
|
||||
local_storage_dict = {}
|
||||
for aperture in storage_dict:
|
||||
if 'geometry' in storage_dict[aperture]:
|
||||
# add aperture only if it has geometry
|
||||
|
@ -4122,7 +4162,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
grb_obj.apertures[storage_apid][k] = []
|
||||
for geo_el in val:
|
||||
geometric_data = geo_el.geo
|
||||
new_geo_el = dict()
|
||||
new_geo_el = {}
|
||||
if 'solid' in geometric_data:
|
||||
new_geo_el['solid'] = geometric_data['solid']
|
||||
poly_buffer.append(deepcopy(new_geo_el['solid']))
|
||||
|
@ -4197,12 +4237,12 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
except Exception as e:
|
||||
log.error("Error on Edited object creation: %s" % str(e))
|
||||
# make sure to clean the previous results
|
||||
self.results = list()
|
||||
self.results = []
|
||||
return
|
||||
|
||||
self.app.inform.emit('[success] %s' % _("Done. Gerber editing finished."))
|
||||
# make sure to clean the previous results
|
||||
self.results = list()
|
||||
self.results = []
|
||||
|
||||
def on_tool_select(self, tool):
|
||||
"""
|
||||
|
@ -4371,7 +4411,8 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
# If the SHIFT key is pressed when LMB is clicked then the coordinates are copied to clipboard
|
||||
if modifiers == QtCore.Qt.ShiftModifier:
|
||||
self.app.clipboard.setText(
|
||||
self.app.defaults["global_point_clipboard_format"] % (self.pos[0], self.pos[1])
|
||||
self.app.defaults["global_point_clipboard_format"] %
|
||||
(self.decimals, self.pos[0], self.decimals, self.pos[1])
|
||||
)
|
||||
self.app.inform.emit('[success] %s' %
|
||||
_("Coordinates copied to clipboard."))
|
||||
|
@ -4911,14 +4952,14 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
|
||||
def buffer_recursion(geom_el, selection):
|
||||
if type(geom_el) == list:
|
||||
geoms = list()
|
||||
geoms = []
|
||||
for local_geom in geom_el:
|
||||
geoms.append(buffer_recursion(local_geom, selection=selection))
|
||||
return geoms
|
||||
else:
|
||||
if geom_el in selection:
|
||||
geometric_data = geom_el.geo
|
||||
buffered_geom_el = dict()
|
||||
buffered_geom_el = {}
|
||||
if 'solid' in geometric_data:
|
||||
buffered_geom_el['solid'] = geometric_data['solid'].buffer(buff_value, join_style=join_style)
|
||||
if 'follow' in geometric_data:
|
||||
|
@ -4967,14 +5008,14 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
|
||||
def scale_recursion(geom_el, selection):
|
||||
if type(geom_el) == list:
|
||||
geoms = list()
|
||||
geoms = []
|
||||
for local_geom in geom_el:
|
||||
geoms.append(scale_recursion(local_geom, selection=selection))
|
||||
return geoms
|
||||
else:
|
||||
if geom_el in selection:
|
||||
geometric_data = geom_el.geo
|
||||
scaled_geom_el = dict()
|
||||
scaled_geom_el = {}
|
||||
if 'solid' in geometric_data:
|
||||
scaled_geom_el['solid'] = affinity.scale(
|
||||
geometric_data['solid'], scale_factor, scale_factor, origin='center'
|
||||
|
|
|
@ -29,6 +29,8 @@ class TextEditor(QtWidgets.QWidget):
|
|||
super().__init__()
|
||||
|
||||
self.app = app
|
||||
self.plain_text = plain_text
|
||||
|
||||
self.setSizePolicy(
|
||||
QtWidgets.QSizePolicy.MinimumExpanding,
|
||||
QtWidgets.QSizePolicy.MinimumExpanding
|
||||
|
@ -45,7 +47,7 @@ class TextEditor(QtWidgets.QWidget):
|
|||
self.work_editor_layout.setContentsMargins(2, 2, 2, 2)
|
||||
self.t_frame.setLayout(self.work_editor_layout)
|
||||
|
||||
if plain_text:
|
||||
if self.plain_text:
|
||||
self.editor_class = FCTextAreaLineNumber()
|
||||
self.code_editor = self.editor_class.edit
|
||||
|
||||
|
@ -313,7 +315,7 @@ class TextEditor(QtWidgets.QWidget):
|
|||
if qc.hasSelection():
|
||||
qc.insertText(new)
|
||||
else:
|
||||
self.ui.code_editor.moveCursor(QtGui.QTextCursor.Start)
|
||||
self.code_editor.moveCursor(QtGui.QTextCursor.Start)
|
||||
break
|
||||
# Mark end of undo block
|
||||
cursor.endEditBlock()
|
||||
|
|
|
@ -371,6 +371,9 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
|
|||
self.menuedit.addSeparator()
|
||||
self.menueditorigin = self.menuedit.addAction(
|
||||
QtGui.QIcon(self.app.resource_location + '/origin16.png'), _('Se&t Origin\tO'))
|
||||
self.menuedit_move2origin = self.menuedit.addAction(
|
||||
QtGui.QIcon(self.app.resource_location + '/origin2_16.png'), _('Move to Origin\tSHIFT+O'))
|
||||
|
||||
self.menueditjump = self.menuedit.addAction(
|
||||
QtGui.QIcon(self.app.resource_location + '/jump_to16.png'), _('Jump to Location\tJ'))
|
||||
self.menueditlocate = self.menuedit.addAction(
|
||||
|
@ -686,9 +689,25 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
|
|||
self.menuproject_brown = self.menuprojectcolor.addAction(
|
||||
QtGui.QIcon(self.app.resource_location + '/brown32.png'), _('Brown'))
|
||||
|
||||
self.menuproject_brown = self.menuprojectcolor.addAction(
|
||||
QtGui.QIcon(self.app.resource_location + '/white32.png'), _('White'))
|
||||
|
||||
self.menuproject_brown = self.menuprojectcolor.addAction(
|
||||
QtGui.QIcon(self.app.resource_location + '/black32.png'), _('Black'))
|
||||
|
||||
self.menuprojectcolor.addSeparator()
|
||||
|
||||
self.menuproject_custom = self.menuprojectcolor.addAction(
|
||||
QtGui.QIcon(self.app.resource_location + '/set_color32.png'), _('Custom'))
|
||||
|
||||
self.menuprojectcolor.addSeparator()
|
||||
|
||||
self.menuproject_custom = self.menuprojectcolor.addAction(
|
||||
QtGui.QIcon(self.app.resource_location + '/set_color32.png'), _('Opacity'))
|
||||
|
||||
self.menuproject_custom = self.menuprojectcolor.addAction(
|
||||
QtGui.QIcon(self.app.resource_location + '/set_color32.png'), _('Default'))
|
||||
|
||||
self.menuproject.addSeparator()
|
||||
|
||||
self.menuprojectgeneratecnc = self.menuproject.addAction(
|
||||
|
@ -825,6 +844,9 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
|
|||
QtGui.QIcon(self.app.resource_location + '/distance_min32.png'), _("Distance Min Tool"))
|
||||
self.origin_btn = self.toolbargeo.addAction(
|
||||
QtGui.QIcon(self.app.resource_location + '/origin32.png'), _('Set Origin'))
|
||||
self.move2origin_btn = self.toolbargeo.addAction(
|
||||
QtGui.QIcon(self.app.resource_location + '/origin2_32.png'), _('Move to Origin'))
|
||||
|
||||
self.jmp_btn = self.toolbargeo.addAction(
|
||||
QtGui.QIcon(self.app.resource_location + '/jump_to16.png'), _('Jump to Location'))
|
||||
self.locate_btn = self.toolbargeo.addAction(
|
||||
|
@ -904,6 +926,10 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
|
|||
QtGui.QIcon(self.app.resource_location + '/fiducials_32.png'), _("Fiducials Tool"))
|
||||
self.cal_btn = self.toolbartools.addAction(
|
||||
QtGui.QIcon(self.app.resource_location + '/calibrate_32.png'), _("Calibration Tool"))
|
||||
self.punch_btn = self.toolbartools.addAction(
|
||||
QtGui.QIcon(self.app.resource_location + '/punch32.png'), _("Punch Gerber Tool"))
|
||||
self.invert_btn = self.toolbartools.addAction(
|
||||
QtGui.QIcon(self.app.resource_location + '/invert32.png'), _("Invert Gerber Tool"))
|
||||
|
||||
# ########################################################################
|
||||
# ########################## Excellon Editor Toolbar# ####################
|
||||
|
@ -1535,6 +1561,10 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
|
|||
<td height="20"><strong>ALT+E</strong></td>
|
||||
<td> %s</td>
|
||||
</tr>
|
||||
<tr height="20">
|
||||
<td height="20"><strong>ALT+H</strong></td>
|
||||
<td> %s</td>
|
||||
</tr>
|
||||
<tr height="20">
|
||||
<td height="20"><strong>ALT+I</strong></td>
|
||||
<td> %s</td>
|
||||
|
@ -1664,7 +1694,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
|
|||
_("Skew on Y axis"),
|
||||
# ALT section
|
||||
_("Align Objects Tool"), _("Calculators Tool"), _("2-Sided PCB Tool"), _("Transformations Tool"),
|
||||
_("Extract Drills Tool"), _("Fiducials Tool"),
|
||||
_("Punch Gerber Tool"), _("Extract Drills Tool"), _("Fiducials Tool"),
|
||||
_("Solder Paste Dispensing Tool"),
|
||||
_("Film PCB Tool"), _("Non-Copper Clearing Tool"), _("Optimal Tool"),
|
||||
_("Paint Area Tool"), _("QRCode Tool"), _("Rules Check Tool"),
|
||||
|
@ -2797,7 +2827,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
|
|||
self.app.tools_db_tab.on_tool_copy()
|
||||
return
|
||||
|
||||
self.app.on_copy_object()
|
||||
self.app.on_copy_command()
|
||||
|
||||
# Copy an FlatCAM object
|
||||
if key == QtCore.Qt.Key_D:
|
||||
|
@ -2950,6 +2980,10 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
|
|||
return
|
||||
|
||||
# Align in Object Tool
|
||||
if key == QtCore.Qt.Key_H:
|
||||
self.app.punch_tool.run(toggle=True)
|
||||
|
||||
# Extract Drills Tool
|
||||
if key == QtCore.Qt.Key_I:
|
||||
self.app.edrills_tool.run(toggle=True)
|
||||
|
||||
|
|
|
@ -152,6 +152,124 @@ class RadioSet(QtWidgets.QWidget):
|
|||
# wgt.show()
|
||||
|
||||
|
||||
class FCTree(QtWidgets.QTreeWidget):
|
||||
resize_sig = QtCore.pyqtSignal()
|
||||
|
||||
def __init__(self, parent=None, columns=2, header_hidden=True, extended_sel=False, protected_column=None):
|
||||
super(FCTree, self).__init__(parent)
|
||||
|
||||
self.setColumnCount(columns)
|
||||
self.setHeaderHidden(header_hidden)
|
||||
self.header().setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
|
||||
self.setSizePolicy(QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Expanding)
|
||||
|
||||
palette = QtGui.QPalette()
|
||||
palette.setColor(QtGui.QPalette.Inactive, QtGui.QPalette.Highlight,
|
||||
palette.color(QtGui.QPalette.Active, QtGui.QPalette.Highlight))
|
||||
|
||||
# make inactive rows text some color as active; may be useful in the future
|
||||
# palette.setColor(QtGui.QPalette.Inactive, QtGui.QPalette.HighlightedText,
|
||||
# palette.color(QtGui.QPalette.Active, QtGui.QPalette.HighlightedText))
|
||||
self.setPalette(palette)
|
||||
|
||||
if extended_sel:
|
||||
self.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
|
||||
|
||||
self.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
|
||||
|
||||
self.protected_column = protected_column
|
||||
self.itemDoubleClicked.connect(self.on_double_click)
|
||||
self.header().sectionDoubleClicked.connect(self.on_header_double_click)
|
||||
self.resize_sig.connect(self.on_resize)
|
||||
|
||||
def on_double_click(self, item, column):
|
||||
# from here: https://stackoverflow.com/questions/2801959/making-only-one-column-of-a-qtreewidgetitem-editable
|
||||
tmp_flags = item.flags()
|
||||
if self.is_editable(column):
|
||||
item.setFlags(tmp_flags | QtCore.Qt.ItemIsEditable)
|
||||
elif tmp_flags & QtCore.Qt.ItemIsEditable:
|
||||
item.setFlags(tmp_flags ^ QtCore.Qt.ItemIsEditable)
|
||||
|
||||
def on_header_double_click(self, column):
|
||||
header = self.header()
|
||||
header.setSectionResizeMode(column, QtWidgets.QHeaderView.ResizeToContents)
|
||||
width = header.sectionSize(column)
|
||||
header.setSectionResizeMode(column, QtWidgets.QHeaderView.Interactive)
|
||||
header.resizeSection(column, width)
|
||||
|
||||
def is_editable(self, tested_col):
|
||||
try:
|
||||
ret_val = False if tested_col in self.protected_column else True
|
||||
except TypeError:
|
||||
ret_val = False
|
||||
return ret_val
|
||||
|
||||
def addParent(self, parent, title, expanded=False, color=None, font=None):
|
||||
item = QtWidgets.QTreeWidgetItem(parent, [title])
|
||||
item.setChildIndicatorPolicy(QtWidgets.QTreeWidgetItem.ShowIndicator)
|
||||
item.setExpanded(expanded)
|
||||
if color is not None:
|
||||
# item.setTextColor(0, color) # PyQt4
|
||||
item.setForeground(0, QtGui.QBrush(color))
|
||||
if font is not None:
|
||||
item.setFont(0, font)
|
||||
return item
|
||||
|
||||
def addParentEditable(self, parent, title, color=None, font=None, font_items=None, editable=False):
|
||||
item = QtWidgets.QTreeWidgetItem(parent)
|
||||
item.setChildIndicatorPolicy(QtWidgets.QTreeWidgetItem.DontShowIndicator)
|
||||
if editable:
|
||||
item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
|
||||
|
||||
item.setFlags(item.flags() | QtCore.Qt.ItemIsSelectable)
|
||||
|
||||
for t in range(len(title)):
|
||||
item.setText(t, title[t])
|
||||
|
||||
if color is not None:
|
||||
# item.setTextColor(0, color) # PyQt4
|
||||
item.setForeground(0, QtGui.QBrush(color))
|
||||
|
||||
if font and font_items:
|
||||
try:
|
||||
for fi in font_items:
|
||||
item.setFont(fi, font)
|
||||
except TypeError:
|
||||
item.setFont(font_items, font)
|
||||
elif font:
|
||||
item.setFont(0, font)
|
||||
return item
|
||||
|
||||
def addChild(self, parent, title, column1=None, font=None, font_items=None, editable=False):
|
||||
item = QtWidgets.QTreeWidgetItem(parent)
|
||||
if editable:
|
||||
item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
|
||||
|
||||
item.setText(0, str(title[0]))
|
||||
if column1 is not None:
|
||||
item.setText(1, str(title[1]))
|
||||
if font and font_items:
|
||||
try:
|
||||
for fi in font_items:
|
||||
item.setFont(fi, font)
|
||||
except TypeError:
|
||||
item.setFont(font_items, font)
|
||||
|
||||
def resizeEvent(self, event):
|
||||
""" Resize all sections to content and user interactive """
|
||||
|
||||
super(FCTree, self).resizeEvent(event)
|
||||
self.on_resize()
|
||||
|
||||
def on_resize(self):
|
||||
header = self.header()
|
||||
for column in range(header.count()):
|
||||
header.setSectionResizeMode(column, QtWidgets.QHeaderView.ResizeToContents)
|
||||
width = header.sectionSize(column)
|
||||
header.setSectionResizeMode(column, QtWidgets.QHeaderView.Interactive)
|
||||
header.resizeSection(column, width)
|
||||
|
||||
|
||||
class LengthEntry(QtWidgets.QLineEdit):
|
||||
def __init__(self, output_units='IN', decimals=None, parent=None):
|
||||
super(LengthEntry, self).__init__(parent)
|
||||
|
@ -201,7 +319,7 @@ class LengthEntry(QtWidgets.QLineEdit):
|
|||
units = raw[-2:]
|
||||
units = self.scales[self.output_units][units.upper()]
|
||||
value = raw[:-2]
|
||||
return float(eval(value))* units
|
||||
return float(eval(value)) * units
|
||||
except IndexError:
|
||||
value = raw
|
||||
return float(eval(value))
|
||||
|
@ -233,7 +351,7 @@ class FloatEntry(QtWidgets.QLineEdit):
|
|||
|
||||
def mousePressEvent(self, e, Parent=None):
|
||||
super(FloatEntry, self).mousePressEvent(e) # required to deselect on 2e click
|
||||
if self.readyToEdit == True:
|
||||
if self.readyToEdit is True:
|
||||
self.selectAll()
|
||||
self.readyToEdit = False
|
||||
|
||||
|
@ -407,6 +525,8 @@ class FCEntry(QtWidgets.QLineEdit):
|
|||
decimal_digits = decimals if decimals is not None else self.decimals
|
||||
if type(val) is float:
|
||||
self.setText('%.*f' % (decimal_digits, val))
|
||||
elif val is None:
|
||||
self.setText('')
|
||||
else:
|
||||
self.setText(str(val))
|
||||
|
||||
|
@ -538,12 +658,16 @@ class EvalEntry2(QtWidgets.QLineEdit):
|
|||
class FCSpinner(QtWidgets.QSpinBox):
|
||||
|
||||
returnPressed = QtCore.pyqtSignal()
|
||||
confirmation_signal = QtCore.pyqtSignal(bool, float, float)
|
||||
|
||||
def __init__(self, suffix=None, alignment=None, parent=None):
|
||||
def __init__(self, suffix=None, alignment=None, parent=None, callback=None):
|
||||
super(FCSpinner, self).__init__(parent)
|
||||
self.readyToEdit = True
|
||||
|
||||
self.editingFinished.connect(self.on_edit_finished)
|
||||
if callback:
|
||||
self.confirmation_signal.connect(callback)
|
||||
|
||||
self.lineEdit().installEventFilter(self)
|
||||
|
||||
if suffix:
|
||||
|
@ -613,8 +737,30 @@ class FCSpinner(QtWidgets.QSpinBox):
|
|||
return
|
||||
self.setValue(k)
|
||||
|
||||
def validate(self, p_str, p_int):
|
||||
text = p_str
|
||||
|
||||
min_val = self.minimum()
|
||||
max_val = self.maximum()
|
||||
try:
|
||||
if int(text) < min_val or int(text) > max_val:
|
||||
self.confirmation_signal.emit(False, min_val, max_val)
|
||||
return QtGui.QValidator.Intermediate, text, p_int
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
self.confirmation_signal.emit(True, min_val, max_val)
|
||||
return QtGui.QValidator.Acceptable, p_str, p_int
|
||||
|
||||
def set_range(self, min_val, max_val):
|
||||
self.blockSignals(True)
|
||||
self.setRange(min_val, max_val)
|
||||
self.blockSignals(False)
|
||||
|
||||
def set_step(self, p_int):
|
||||
self.blockSignals(True)
|
||||
self.setSingleStep(p_int)
|
||||
self.blockSignals(False)
|
||||
|
||||
# def sizeHint(self):
|
||||
# default_hint_size = super(FCSpinner, self).sizeHint()
|
||||
|
@ -624,12 +770,23 @@ class FCSpinner(QtWidgets.QSpinBox):
|
|||
class FCDoubleSpinner(QtWidgets.QDoubleSpinBox):
|
||||
|
||||
returnPressed = QtCore.pyqtSignal()
|
||||
confirmation_signal = QtCore.pyqtSignal(bool, float, float)
|
||||
|
||||
def __init__(self, suffix=None, alignment=None, parent=None):
|
||||
def __init__(self, suffix=None, alignment=None, parent=None, callback=None):
|
||||
"""
|
||||
|
||||
:param suffix: a char added to the end of the value in the LineEdit; like a '%' or '$' etc
|
||||
:param alignment: the value is aligned to left or right
|
||||
:param parent:
|
||||
:param callback: called when the entered value is outside limits; the min and max value will be passed to it
|
||||
"""
|
||||
super(FCDoubleSpinner, self).__init__(parent)
|
||||
self.readyToEdit = True
|
||||
|
||||
self.editingFinished.connect(self.on_edit_finished)
|
||||
if callback:
|
||||
self.confirmation_signal.connect(callback)
|
||||
|
||||
self.lineEdit().installEventFilter(self)
|
||||
|
||||
# by default don't allow the minus sign to be entered as the default for QDoubleSpinBox is the positive range
|
||||
|
@ -699,11 +856,17 @@ class FCDoubleSpinner(QtWidgets.QDoubleSpinBox):
|
|||
|
||||
def validate(self, p_str, p_int):
|
||||
text = p_str.replace(',', '.')
|
||||
|
||||
min_val = self.minimum()
|
||||
max_val = self.maximum()
|
||||
try:
|
||||
if float(text) < self.minimum() or float(text) > self.maximum():
|
||||
if float(text) < min_val or float(text) > max_val:
|
||||
self.confirmation_signal.emit(False, min_val, max_val)
|
||||
return QtGui.QValidator.Intermediate, text, p_int
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
self.confirmation_signal.emit(True, min_val, max_val)
|
||||
return QtGui.QValidator.Acceptable, p_str, p_int
|
||||
|
||||
def get_value(self):
|
||||
|
@ -1139,6 +1302,9 @@ class FCComboBox(QtWidgets.QComboBox):
|
|||
self.view.viewport().installEventFilter(self)
|
||||
self.view.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||
|
||||
self._set_last = False
|
||||
self._obj_type = None
|
||||
|
||||
# the callback() will be called on customcontextmenu event and will be be passed 2 parameters:
|
||||
# pos = mouse right click click position
|
||||
# self = is the combobox object itself
|
||||
|
@ -1160,6 +1326,29 @@ class FCComboBox(QtWidgets.QComboBox):
|
|||
def set_value(self, val):
|
||||
self.setCurrentIndex(self.findText(str(val)))
|
||||
|
||||
@property
|
||||
def is_last(self):
|
||||
return self._set_last
|
||||
|
||||
@is_last.setter
|
||||
def is_last(self, val):
|
||||
self._set_last = val
|
||||
if self._set_last is True:
|
||||
self.model().rowsInserted.connect(self.on_model_changed)
|
||||
self.setCurrentIndex(1)
|
||||
|
||||
@property
|
||||
def obj_type(self):
|
||||
return self._obj_type
|
||||
|
||||
@obj_type.setter
|
||||
def obj_type(self, val):
|
||||
self._obj_type = val
|
||||
|
||||
def on_model_changed(self, parent, first, last):
|
||||
if self.model().data(parent, QtCore.Qt.DisplayRole) == self.obj_type:
|
||||
self.setCurrentIndex(first)
|
||||
|
||||
|
||||
class FCInputDialog(QtWidgets.QInputDialog):
|
||||
def __init__(self, parent=None, ok=False, val=None, title=None, text=None, min=None, max=None, decimals=None,
|
||||
|
@ -1290,7 +1479,7 @@ class FCDetachableTab(QtWidgets.QTabWidget):
|
|||
self.protect_by_name = protect_by_name if isinstance(protect_by_name, list) else None
|
||||
|
||||
# Close all detached tabs if the application is closed explicitly
|
||||
QtWidgets.qApp.aboutToQuit.connect(self.closeDetachedTabs) # @UndefinedVariable
|
||||
QtWidgets.qApp.aboutToQuit.connect(self.closeDetachedTabs) # @UndefinedVariable
|
||||
|
||||
# used by the property self.useOldIndex(param)
|
||||
self.use_old_index = None
|
||||
|
@ -1770,7 +1959,7 @@ class FCDetachableTab(QtWidgets.QTabWidget):
|
|||
self.dragInitiated = True
|
||||
|
||||
# If the current movement is a drag initiated by the left button
|
||||
if ((event.buttons() & QtCore.Qt.LeftButton)) and self.dragInitiated and self.can_be_dragged:
|
||||
if (event.buttons() & QtCore.Qt.LeftButton) and self.dragInitiated and self.can_be_dragged:
|
||||
|
||||
# Stop the move event
|
||||
finishMoveEvent = QtGui.QMouseEvent(
|
||||
|
@ -2026,7 +2215,7 @@ class FCTable(QtWidgets.QTableWidget):
|
|||
self.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
|
||||
self.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove)
|
||||
|
||||
self.rows_not_for_drag_and_drop = list()
|
||||
self.rows_not_for_drag_and_drop = []
|
||||
if protected_rows:
|
||||
try:
|
||||
for r in protected_rows:
|
||||
|
@ -2034,7 +2223,7 @@ class FCTable(QtWidgets.QTableWidget):
|
|||
except TypeError:
|
||||
self.rows_not_for_drag_and_drop = [protected_rows]
|
||||
|
||||
self.rows_to_move = list()
|
||||
self.rows_to_move = []
|
||||
|
||||
def sizeHint(self):
|
||||
default_hint_size = super(FCTable, self).sizeHint()
|
||||
|
@ -2090,7 +2279,7 @@ class FCTable(QtWidgets.QTableWidget):
|
|||
# # ]
|
||||
# self.rows_to_move[:] = []
|
||||
# for row_index in rows:
|
||||
# row_items = list()
|
||||
# row_items = []
|
||||
# for column_index in range(self.columnCount()):
|
||||
# r_item = self.item(row_index, column_index)
|
||||
# w_item = self.cellWidget(row_index, column_index)
|
||||
|
@ -2171,7 +2360,7 @@ class FCTable(QtWidgets.QTableWidget):
|
|||
for _ in range(len(rows)):
|
||||
self.insertRow(targetRow)
|
||||
|
||||
rowMapping = dict() # Src row to target row.
|
||||
rowMapping = {} # Src row to target row.
|
||||
for idx, row in enumerate(rows):
|
||||
if row < targetRow:
|
||||
rowMapping[row] = targetRow + idx
|
||||
|
@ -2278,7 +2467,7 @@ class Dialog_box(QtWidgets.QWidget):
|
|||
|
||||
|
||||
class DialogBoxRadio(QtWidgets.QDialog):
|
||||
def __init__(self, title=None, label=None, icon=None, initial_text=None, reference='abs'):
|
||||
def __init__(self, title=None, label=None, icon=None, initial_text=None, reference='abs', parent=None):
|
||||
"""
|
||||
|
||||
:param title: string with the window title
|
||||
|
@ -2322,8 +2511,10 @@ class DialogBoxRadio(QtWidgets.QDialog):
|
|||
"If the reference is Relative then the Jump will be at the (x,y) distance\n"
|
||||
"from the current mouse location point.")
|
||||
)
|
||||
self.lineEdit = EvalEntry()
|
||||
self.lineEdit = EvalEntry(self)
|
||||
self.lineEdit.setText(str(self.location).replace('(', '').replace(')', ''))
|
||||
self.lineEdit.selectAll()
|
||||
self.lineEdit.setFocus()
|
||||
self.form.addRow(self.loc_label, self.lineEdit)
|
||||
|
||||
self.button_box = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel,
|
||||
|
|
|
@ -62,7 +62,7 @@ class PlotCanvas(QtCore.QObject, VisPyCanvas):
|
|||
# self.b_line, self.r_line, self.t_line, self.l_line = None, None, None, None
|
||||
self.workspace_line = None
|
||||
|
||||
self.pagesize_dict = dict()
|
||||
self.pagesize_dict = {}
|
||||
self.pagesize_dict.update(
|
||||
{
|
||||
'A0': (841, 1189),
|
||||
|
|
|
@ -158,7 +158,7 @@ class PlotCanvasLegacy(QtCore.QObject):
|
|||
# self.b_line, self.r_line, self.t_line, self.l_line = None, None, None, None
|
||||
self.workspace_line = None
|
||||
|
||||
self.pagesize_dict = dict()
|
||||
self.pagesize_dict = {}
|
||||
self.pagesize_dict.update(
|
||||
{
|
||||
'A0': (841, 1189),
|
||||
|
@ -959,8 +959,8 @@ class ShapeCollectionLegacy:
|
|||
self.app = app
|
||||
self.annotation_job = annotation_job
|
||||
|
||||
self._shapes = dict()
|
||||
self.shape_dict = dict()
|
||||
self._shapes = {}
|
||||
self.shape_dict = {}
|
||||
self.shape_id = 0
|
||||
|
||||
self._color = None
|
||||
|
|
|
@ -43,6 +43,7 @@ class Excellon(Geometry):
|
|||
================ ====================================
|
||||
C Diameter of the tool
|
||||
solid_geometry Geometry list for each tool
|
||||
data dictionary which holds the options for each tool
|
||||
Others Not supported (Ignored).
|
||||
================ ====================================
|
||||
|
||||
|
@ -94,11 +95,11 @@ class Excellon(Geometry):
|
|||
Geometry.__init__(self, geo_steps_per_circle=int(geo_steps_per_circle))
|
||||
|
||||
# dictionary to store tools, see above for description
|
||||
self.tools = dict()
|
||||
self.tools = {}
|
||||
# list to store the drills, see above for description
|
||||
self.drills = list()
|
||||
self.drills = []
|
||||
# self.slots (list) to store the slots; each is a dictionary
|
||||
self.slots = list()
|
||||
self.slots = []
|
||||
|
||||
self.source_file = ''
|
||||
|
||||
|
@ -109,8 +110,8 @@ class Excellon(Geometry):
|
|||
self.match_routing_start = None
|
||||
self.match_routing_stop = None
|
||||
|
||||
self.num_tools = list() # List for keeping the tools sorted
|
||||
self.index_per_tool = dict() # Dictionary to store the indexed points for each tool
|
||||
self.num_tools = [] # List for keeping the tools sorted
|
||||
self.index_per_tool = {} # Dictionary to store the indexed points for each tool
|
||||
|
||||
# ## IN|MM -> Units are inherited from Geometry
|
||||
self.units = self.app.defaults['units']
|
||||
|
@ -961,10 +962,8 @@ class Excellon(Geometry):
|
|||
try:
|
||||
# clear the solid_geometry in self.tools
|
||||
for tool in self.tools:
|
||||
try:
|
||||
self.tools[tool]['solid_geometry'][:] = []
|
||||
except KeyError:
|
||||
self.tools[tool]['solid_geometry'] = []
|
||||
self.tools[tool]['solid_geometry'] = []
|
||||
self.tools[tool]['data'] = {}
|
||||
|
||||
for drill in self.drills:
|
||||
# poly = drill['point'].buffer(self.tools[drill['tool']]["C"]/2.0)
|
||||
|
@ -979,7 +978,10 @@ class Excellon(Geometry):
|
|||
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.tools[drill['tool']]['solid_geometry'].append(poly)
|
||||
|
||||
tool_in_drills = drill['tool']
|
||||
self.tools[tool_in_drills]['solid_geometry'].append(poly)
|
||||
self.tools[tool_in_drills]['data'] = deepcopy(self.default_data)
|
||||
|
||||
for slot in self.slots:
|
||||
slot_tooldia = self.tools[slot['tool']]['C']
|
||||
|
@ -989,8 +991,10 @@ 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.tools[slot['tool']]['solid_geometry'].append(poly)
|
||||
|
||||
tool_in_slots = slot['tool']
|
||||
self.tools[tool_in_slots]['solid_geometry'].append(poly)
|
||||
self.tools[tool_in_slots]['data'] = deepcopy(self.default_data)
|
||||
except Exception as e:
|
||||
log.debug("flatcamParsers.ParseExcellon.Excellon.create_geometry() -> "
|
||||
"Excellon geometry creation failed due of ERROR: %s" % str(e))
|
||||
|
|
|
@ -394,10 +394,10 @@ class Gerber(Geometry):
|
|||
current_operation_code = None
|
||||
|
||||
# Current coordinates
|
||||
current_x = None
|
||||
current_y = None
|
||||
previous_x = None
|
||||
previous_y = None
|
||||
current_x = 0
|
||||
current_y = 0
|
||||
previous_x = 0
|
||||
previous_y = 0
|
||||
|
||||
current_d = None
|
||||
|
||||
|
@ -456,13 +456,18 @@ class Gerber(Geometry):
|
|||
new_polarity = match.group(1)
|
||||
# log.info("Polarity CHANGE, LPC = %s, poly_buff = %s" % (self.is_lpc, poly_buffer))
|
||||
self.is_lpc = True if new_polarity == 'C' else False
|
||||
if len(path) > 1 and current_polarity != new_polarity:
|
||||
try:
|
||||
path_length = len(path)
|
||||
except TypeError:
|
||||
path_length = 1
|
||||
|
||||
if path_length > 1 and current_polarity != new_polarity:
|
||||
|
||||
# finish the current path and add it to the storage
|
||||
# --- Buffered ----
|
||||
width = self.apertures[last_path_aperture]["size"]
|
||||
|
||||
geo_dict = dict()
|
||||
geo_dict = {}
|
||||
geo_f = LineString(path)
|
||||
if not geo_f.is_empty:
|
||||
follow_buffer.append(geo_f)
|
||||
|
@ -481,7 +486,7 @@ class Gerber(Geometry):
|
|||
geo_dict['solid'] = geo_s
|
||||
|
||||
if last_path_aperture not in self.apertures:
|
||||
self.apertures[last_path_aperture] = dict()
|
||||
self.apertures[last_path_aperture] = {}
|
||||
if 'geometry' not in self.apertures[last_path_aperture]:
|
||||
self.apertures[last_path_aperture]['geometry'] = []
|
||||
self.apertures[last_path_aperture]['geometry'].append(deepcopy(geo_dict))
|
||||
|
@ -491,7 +496,12 @@ class Gerber(Geometry):
|
|||
# --- Apply buffer ---
|
||||
# If added for testing of bug #83
|
||||
# TODO: Remove when bug fixed
|
||||
if len(poly_buffer) > 0:
|
||||
try:
|
||||
buff_length = len(poly_buffer)
|
||||
except TypeError:
|
||||
buff_length = 1
|
||||
|
||||
if buff_length > 0:
|
||||
if current_polarity == 'D':
|
||||
self.solid_geometry = self.solid_geometry.union(cascaded_union(poly_buffer))
|
||||
|
||||
|
@ -667,7 +677,7 @@ class Gerber(Geometry):
|
|||
# --- Buffered ---
|
||||
try:
|
||||
# log.debug("Bare op-code %d." % current_operation_code)
|
||||
geo_dict = dict()
|
||||
geo_dict = {}
|
||||
flash = self.create_flash_geometry(
|
||||
Point(current_x, current_y), self.apertures[current_aperture],
|
||||
self.steps_per_circle)
|
||||
|
@ -685,7 +695,7 @@ class Gerber(Geometry):
|
|||
geo_dict['solid'] = flash
|
||||
|
||||
if current_aperture not in self.apertures:
|
||||
self.apertures[current_aperture] = dict()
|
||||
self.apertures[current_aperture] = {}
|
||||
if 'geometry' not in self.apertures[current_aperture]:
|
||||
self.apertures[current_aperture]['geometry'] = []
|
||||
self.apertures[current_aperture]['geometry'].append(deepcopy(geo_dict))
|
||||
|
@ -714,12 +724,17 @@ class Gerber(Geometry):
|
|||
# log.debug(self.apertures[current_aperture])
|
||||
|
||||
# Take care of the current path with the previous tool
|
||||
if len(path) > 1:
|
||||
try:
|
||||
path_length = len(path)
|
||||
except TypeError:
|
||||
path_length = 1
|
||||
|
||||
if path_length > 1:
|
||||
if self.apertures[last_path_aperture]["type"] == 'R':
|
||||
# do nothing because 'R' type moving aperture is none at once
|
||||
pass
|
||||
else:
|
||||
geo_dict = dict()
|
||||
geo_dict = {}
|
||||
geo_f = LineString(path)
|
||||
if not geo_f.is_empty:
|
||||
follow_buffer.append(geo_f)
|
||||
|
@ -739,7 +754,7 @@ class Gerber(Geometry):
|
|||
geo_dict['solid'] = geo_s
|
||||
|
||||
if last_path_aperture not in self.apertures:
|
||||
self.apertures[last_path_aperture] = dict()
|
||||
self.apertures[last_path_aperture] = {}
|
||||
if 'geometry' not in self.apertures[last_path_aperture]:
|
||||
self.apertures[last_path_aperture]['geometry'] = []
|
||||
self.apertures[last_path_aperture]['geometry'].append(deepcopy(geo_dict))
|
||||
|
@ -751,10 +766,15 @@ class Gerber(Geometry):
|
|||
# ################ G36* - Begin region ########################
|
||||
# ################################################################
|
||||
if self.regionon_re.search(gline):
|
||||
if len(path) > 1:
|
||||
try:
|
||||
path_length = len(path)
|
||||
except TypeError:
|
||||
path_length = 1
|
||||
|
||||
if path_length > 1:
|
||||
# Take care of what is left in the path
|
||||
|
||||
geo_dict = dict()
|
||||
geo_dict = {}
|
||||
geo_f = LineString(path)
|
||||
if not geo_f.is_empty:
|
||||
follow_buffer.append(geo_f)
|
||||
|
@ -774,7 +794,7 @@ class Gerber(Geometry):
|
|||
geo_dict['solid'] = geo_s
|
||||
|
||||
if last_path_aperture not in self.apertures:
|
||||
self.apertures[last_path_aperture] = dict()
|
||||
self.apertures[last_path_aperture] = {}
|
||||
if 'geometry' not in self.apertures[last_path_aperture]:
|
||||
self.apertures[last_path_aperture]['geometry'] = []
|
||||
self.apertures[last_path_aperture]['geometry'].append(deepcopy(geo_dict))
|
||||
|
@ -794,14 +814,19 @@ class Gerber(Geometry):
|
|||
self.apertures['0'] = {}
|
||||
self.apertures['0']['type'] = 'REG'
|
||||
self.apertures['0']['size'] = 0.0
|
||||
self.apertures['0']['geometry'] = list()
|
||||
self.apertures['0']['geometry'] = []
|
||||
|
||||
# if D02 happened before G37 we now have a path with 1 element only; we have to add the current
|
||||
# geo to the poly_buffer otherwise we loose it
|
||||
if current_operation_code == 2:
|
||||
if len(path) == 1:
|
||||
try:
|
||||
path_length = len(path)
|
||||
except TypeError:
|
||||
path_length = 1
|
||||
|
||||
if path_length == 1:
|
||||
# this means that the geometry was prepared previously and we just need to add it
|
||||
geo_dict = dict()
|
||||
geo_dict = {}
|
||||
if geo_f:
|
||||
if not geo_f.is_empty:
|
||||
follow_buffer.append(geo_f)
|
||||
|
@ -825,7 +850,12 @@ class Gerber(Geometry):
|
|||
# Only one path defines region?
|
||||
# This can happen if D02 happened before G37 and
|
||||
# is not and error.
|
||||
if len(path) < 3:
|
||||
try:
|
||||
path_length = len(path)
|
||||
except TypeError:
|
||||
path_length = 1
|
||||
|
||||
if path_length < 3:
|
||||
# print "ERROR: Path contains less than 3 points:"
|
||||
# path = [[current_x, current_y]]
|
||||
continue
|
||||
|
@ -833,7 +863,7 @@ class Gerber(Geometry):
|
|||
# For regions we may ignore an aperture that is None
|
||||
|
||||
# --- Buffered ---
|
||||
geo_dict = dict()
|
||||
geo_dict = {}
|
||||
if current_aperture in self.apertures:
|
||||
# the following line breaks loading of Circuit Studio Gerber files
|
||||
# buff_value = float(self.apertures[current_aperture]['size']) / 2.0
|
||||
|
@ -935,7 +965,7 @@ class Gerber(Geometry):
|
|||
maxy = max(path[0][1], path[1][1]) + height / 2
|
||||
log.debug("Coords: %s - %s - %s - %s" % (minx, miny, maxx, maxy))
|
||||
|
||||
geo_dict = dict()
|
||||
geo_dict = {}
|
||||
geo_f = Point([current_x, current_y])
|
||||
follow_buffer.append(geo_f)
|
||||
geo_dict['follow'] = geo_f
|
||||
|
@ -952,7 +982,7 @@ class Gerber(Geometry):
|
|||
geo_dict['solid'] = geo_s
|
||||
|
||||
if current_aperture not in self.apertures:
|
||||
self.apertures[current_aperture] = dict()
|
||||
self.apertures[current_aperture] = {}
|
||||
if 'geometry' not in self.apertures[current_aperture]:
|
||||
self.apertures[current_aperture]['geometry'] = []
|
||||
self.apertures[current_aperture]['geometry'].append(deepcopy(geo_dict))
|
||||
|
@ -974,10 +1004,15 @@ class Gerber(Geometry):
|
|||
_("GERBER file might be CORRUPT. Check the file !!!"))
|
||||
|
||||
elif current_operation_code == 2:
|
||||
if len(path) > 1:
|
||||
try:
|
||||
path_length = len(path)
|
||||
except TypeError:
|
||||
path_length = 1
|
||||
|
||||
if path_length > 1:
|
||||
geo_s = None
|
||||
|
||||
geo_dict = dict()
|
||||
geo_dict = {}
|
||||
# --- BUFFERED ---
|
||||
# this treats the case when we are storing geometry as paths only
|
||||
if making_region:
|
||||
|
@ -1054,7 +1089,7 @@ class Gerber(Geometry):
|
|||
geo_dict['solid'] = geo_s
|
||||
|
||||
if last_path_aperture not in self.apertures:
|
||||
self.apertures[last_path_aperture] = dict()
|
||||
self.apertures[last_path_aperture] = {}
|
||||
if 'geometry' not in self.apertures[last_path_aperture]:
|
||||
self.apertures[last_path_aperture]['geometry'] = []
|
||||
self.apertures[last_path_aperture]['geometry'].append(deepcopy(geo_dict))
|
||||
|
@ -1073,9 +1108,14 @@ class Gerber(Geometry):
|
|||
elif current_operation_code == 3:
|
||||
|
||||
# Create path draw so far.
|
||||
if len(path) > 1:
|
||||
try:
|
||||
path_length = len(path)
|
||||
except TypeError:
|
||||
path_length = 1
|
||||
|
||||
if path_length > 1:
|
||||
# --- Buffered ----
|
||||
geo_dict = dict()
|
||||
geo_dict = {}
|
||||
|
||||
# this treats the case when we are storing geometry as paths
|
||||
geo_f = LineString(path)
|
||||
|
@ -1116,7 +1156,7 @@ class Gerber(Geometry):
|
|||
geo_dict['solid'] = geo_s
|
||||
|
||||
if last_path_aperture not in self.apertures:
|
||||
self.apertures[last_path_aperture] = dict()
|
||||
self.apertures[last_path_aperture] = {}
|
||||
if 'geometry' not in self.apertures[last_path_aperture]:
|
||||
self.apertures[last_path_aperture]['geometry'] = []
|
||||
self.apertures[last_path_aperture]['geometry'].append(deepcopy(geo_dict))
|
||||
|
@ -1127,7 +1167,7 @@ class Gerber(Geometry):
|
|||
# --- BUFFERED ---
|
||||
# Draw the flash
|
||||
# this treats the case when we are storing geometry as paths
|
||||
geo_dict = dict()
|
||||
geo_dict = {}
|
||||
geo_flash = Point([linear_x, linear_y])
|
||||
follow_buffer.append(geo_flash)
|
||||
geo_dict['follow'] = geo_flash
|
||||
|
@ -1150,7 +1190,7 @@ class Gerber(Geometry):
|
|||
geo_dict['solid'] = flash
|
||||
|
||||
if current_aperture not in self.apertures:
|
||||
self.apertures[current_aperture] = dict()
|
||||
self.apertures[current_aperture] = {}
|
||||
if 'geometry' not in self.apertures[current_aperture]:
|
||||
self.apertures[current_aperture]['geometry'] = []
|
||||
self.apertures[current_aperture]['geometry'].append(deepcopy(geo_dict))
|
||||
|
@ -1229,8 +1269,13 @@ class Gerber(Geometry):
|
|||
# Nothing created! Pen Up.
|
||||
if current_operation_code == 2:
|
||||
log.warning("Arc with D2. (%d)" % line_num)
|
||||
if len(path) > 1:
|
||||
geo_dict = dict()
|
||||
try:
|
||||
path_length = len(path)
|
||||
except TypeError:
|
||||
path_length = 1
|
||||
|
||||
if path_length > 1:
|
||||
geo_dict = {}
|
||||
|
||||
if last_path_aperture is None:
|
||||
log.warning("No aperture defined for curent path. (%d)" % line_num)
|
||||
|
@ -1258,7 +1303,7 @@ class Gerber(Geometry):
|
|||
geo_dict['solid'] = buffered
|
||||
|
||||
if last_path_aperture not in self.apertures:
|
||||
self.apertures[last_path_aperture] = dict()
|
||||
self.apertures[last_path_aperture] = {}
|
||||
if 'geometry' not in self.apertures[last_path_aperture]:
|
||||
self.apertures[last_path_aperture]['geometry'] = []
|
||||
self.apertures[last_path_aperture]['geometry'].append(deepcopy(geo_dict))
|
||||
|
@ -1372,7 +1417,12 @@ class Gerber(Geometry):
|
|||
# ################################################################
|
||||
log.warning("Line ignored (%d): %s" % (line_num, gline))
|
||||
|
||||
if len(path) > 1:
|
||||
try:
|
||||
path_length = len(path)
|
||||
except TypeError:
|
||||
path_length = 1
|
||||
|
||||
if path_length > 1:
|
||||
# In case that G01 (moving) aperture is rectangular, there is no need to still create
|
||||
# another geo since we already created a shapely box using the start and end coordinates found in
|
||||
# path variable. We do it only for other apertures than 'R' type
|
||||
|
@ -1382,7 +1432,7 @@ class Gerber(Geometry):
|
|||
# EOF, create shapely LineString if something still in path
|
||||
# ## --- Buffered ---
|
||||
|
||||
geo_dict = dict()
|
||||
geo_dict = {}
|
||||
# this treats the case when we are storing geometry as paths
|
||||
geo_f = LineString(path)
|
||||
if not geo_f.is_empty:
|
||||
|
@ -1404,7 +1454,7 @@ class Gerber(Geometry):
|
|||
geo_dict['solid'] = geo_s
|
||||
|
||||
if last_path_aperture not in self.apertures:
|
||||
self.apertures[last_path_aperture] = dict()
|
||||
self.apertures[last_path_aperture] = {}
|
||||
if 'geometry' not in self.apertures[last_path_aperture]:
|
||||
self.apertures[last_path_aperture]['geometry'] = []
|
||||
self.apertures[last_path_aperture]['geometry'].append(deepcopy(geo_dict))
|
||||
|
@ -1414,13 +1464,26 @@ class Gerber(Geometry):
|
|||
self.follow_geometry = follow_buffer
|
||||
|
||||
# this treats the case when we are storing geometry as solids
|
||||
try:
|
||||
buff_length = len(poly_buffer)
|
||||
except TypeError:
|
||||
buff_length = 1
|
||||
|
||||
if len(poly_buffer) == 0 and len(self.solid_geometry) == 0:
|
||||
log.error("Object is not Gerber file or empty. Aborting Object creation.")
|
||||
try:
|
||||
sol_geo_length = len(self.solid_geometry)
|
||||
except TypeError:
|
||||
sol_geo_length = 1
|
||||
|
||||
try:
|
||||
if buff_length == 0 and sol_geo_length == 0:
|
||||
log.error("Object is not Gerber file or empty. Aborting Object creation.")
|
||||
return 'fail'
|
||||
except TypeError as e:
|
||||
log.error("Object is not Gerber file or empty. Aborting Object creation. %s" % str(e))
|
||||
return 'fail'
|
||||
|
||||
log.warning("Joining %d polygons." % len(poly_buffer))
|
||||
self.app.inform.emit('%s: %d.' % (_("Gerber processing. Joining polygons"), len(poly_buffer)))
|
||||
log.warning("Joining %d polygons." % buff_length)
|
||||
self.app.inform.emit('%s: %d.' % (_("Gerber processing. Joining polygons"), buff_length))
|
||||
|
||||
if self.use_buffer_for_union:
|
||||
log.debug("Union by buffer...")
|
||||
|
@ -1462,7 +1525,7 @@ class Gerber(Geometry):
|
|||
# it use a filled bounding box polygon to which add clear polygons (negative) to isolate the copper
|
||||
# features
|
||||
if self.app.defaults['gerber_extra_buffering']:
|
||||
candidate_geo = list()
|
||||
candidate_geo = []
|
||||
try:
|
||||
for p in self.solid_geometry:
|
||||
candidate_geo.append(p.buffer(-0.0000001))
|
||||
|
@ -1714,7 +1777,7 @@ class Gerber(Geometry):
|
|||
|
||||
# Add to object
|
||||
if self.solid_geometry is None:
|
||||
self.solid_geometry = list()
|
||||
self.solid_geometry = []
|
||||
|
||||
# if type(self.solid_geometry) == list:
|
||||
# if type(geos) == list:
|
||||
|
@ -1726,8 +1789,13 @@ class Gerber(Geometry):
|
|||
|
||||
if type(geos) == list:
|
||||
# HACK for importing QRCODE exported by FlatCAM
|
||||
if len(geos) == 1:
|
||||
geo_qrcode = list()
|
||||
try:
|
||||
geos_length = len(geos)
|
||||
except TypeError:
|
||||
geos_length = 1
|
||||
|
||||
if geos_length == 1:
|
||||
geo_qrcode = []
|
||||
geo_qrcode.append(Polygon(geos[0].exterior))
|
||||
for i_el in geos[0].interiors:
|
||||
geo_qrcode.append(Polygon(i_el).buffer(0))
|
||||
|
@ -1754,13 +1822,13 @@ class Gerber(Geometry):
|
|||
self.solid_geometry = [self.solid_geometry]
|
||||
|
||||
if '0' not in self.apertures:
|
||||
self.apertures['0'] = dict()
|
||||
self.apertures['0'] = {}
|
||||
self.apertures['0']['type'] = 'REG'
|
||||
self.apertures['0']['size'] = 0.0
|
||||
self.apertures['0']['geometry'] = list()
|
||||
self.apertures['0']['geometry'] = []
|
||||
|
||||
for pol in self.solid_geometry:
|
||||
new_el = dict()
|
||||
new_el = {}
|
||||
new_el['solid'] = pol
|
||||
new_el['follow'] = pol.exterior
|
||||
self.apertures['0']['geometry'].append(deepcopy(new_el))
|
||||
|
@ -1849,10 +1917,10 @@ class Gerber(Geometry):
|
|||
# we need to scale the geometry stored in the Gerber apertures, too
|
||||
try:
|
||||
for apid in self.apertures:
|
||||
new_geometry = list()
|
||||
new_geometry = []
|
||||
if 'geometry' in self.apertures[apid]:
|
||||
for geo_el in self.apertures[apid]['geometry']:
|
||||
new_geo_el = dict()
|
||||
new_geo_el = {}
|
||||
if 'solid' in geo_el:
|
||||
new_geo_el['solid'] = scale_geom(geo_el['solid'])
|
||||
if 'follow' in geo_el:
|
||||
|
@ -2245,10 +2313,10 @@ class Gerber(Geometry):
|
|||
# we need to buffer the geometry stored in the Gerber apertures, too
|
||||
try:
|
||||
for apid in self.apertures:
|
||||
new_geometry = list()
|
||||
new_geometry = []
|
||||
if 'geometry' in self.apertures[apid]:
|
||||
for geo_el in self.apertures[apid]['geometry']:
|
||||
new_geo_el = dict()
|
||||
new_geo_el = {}
|
||||
if 'solid' in geo_el:
|
||||
new_geo_el['solid'] = buffer_geom(geo_el['solid'])
|
||||
if 'follow' in geo_el:
|
||||
|
@ -2296,10 +2364,10 @@ class Gerber(Geometry):
|
|||
except KeyError:
|
||||
pass
|
||||
|
||||
new_geometry = list()
|
||||
new_geometry = []
|
||||
if 'geometry' in self.apertures[apid]:
|
||||
for geo_el in self.apertures[apid]['geometry']:
|
||||
new_geo_el = dict()
|
||||
new_geo_el = {}
|
||||
if 'follow' in geo_el:
|
||||
new_geo_el['follow'] = geo_el['follow']
|
||||
size = float(self.apertures[apid]['size'])
|
||||
|
@ -2337,7 +2405,7 @@ class Gerber(Geometry):
|
|||
return 'fail'
|
||||
|
||||
# make the new solid_geometry
|
||||
new_solid_geo = list()
|
||||
new_solid_geo = []
|
||||
for apid in self.apertures:
|
||||
if 'geometry' in self.apertures[apid]:
|
||||
new_solid_geo += [geo_el['solid'] for geo_el in self.apertures[apid]['geometry']]
|
||||
|
|
|
@ -49,9 +49,9 @@ class HPGL2:
|
|||
self.units = 'MM'
|
||||
|
||||
# storage for the tools
|
||||
self.tools = dict()
|
||||
self.tools = {}
|
||||
|
||||
self.default_data = dict()
|
||||
self.default_data = {}
|
||||
self.default_data.update({
|
||||
"name": '_ncc',
|
||||
"plot": self.app.defaults["geometry_plot"],
|
||||
|
@ -72,6 +72,8 @@ class HPGL2:
|
|||
"toolchange": self.app.defaults["geometry_toolchange"],
|
||||
"toolchangez": self.app.defaults["geometry_toolchangez"],
|
||||
"endz": self.app.defaults["geometry_endz"],
|
||||
"endxy": self.app.defaults["geometry_endxy"],
|
||||
|
||||
"spindlespeed": self.app.defaults["geometry_spindlespeed"],
|
||||
"toolchangexy": self.app.defaults["geometry_toolchangexy"],
|
||||
"startz": self.app.defaults["geometry_startz"],
|
||||
|
@ -151,7 +153,7 @@ class HPGL2:
|
|||
"""
|
||||
|
||||
# Coordinates of the current path, each is [x, y]
|
||||
path = list()
|
||||
path = []
|
||||
|
||||
geo_buffer = []
|
||||
|
||||
|
@ -207,7 +209,7 @@ class HPGL2:
|
|||
match = self.sp_re.search(gline)
|
||||
if match:
|
||||
tool = match.group(1)
|
||||
# self.tools[tool] = dict()
|
||||
# self.tools[tool] = {}
|
||||
self.tools.update({
|
||||
tool: {
|
||||
'tooldia': float('%.*f' %
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
# import xml.etree.ElementTree as ET
|
||||
from svg.path import Line, Arc, CubicBezier, QuadraticBezier, parse_path
|
||||
from svg.path.path import Move
|
||||
from svg.path.path import Move, Close
|
||||
from shapely.geometry import LineString, LinearRing, MultiLineString
|
||||
from shapely.affinity import skew, affine_transform, rotate
|
||||
import numpy as np
|
||||
|
@ -69,6 +69,7 @@ def path2shapely(path, object_type, res=1.0):
|
|||
geometry = []
|
||||
geo_element = None
|
||||
rings = []
|
||||
closed = False
|
||||
|
||||
for component in path:
|
||||
# Line
|
||||
|
@ -88,7 +89,8 @@ def path2shapely(path, object_type, res=1.0):
|
|||
|
||||
# How many points to use in the discrete representation.
|
||||
length = component.length(res / 10.0)
|
||||
steps = int(length / res + 0.5)
|
||||
# steps = int(length / res + 0.5)
|
||||
steps = int(length) * 2
|
||||
|
||||
# solve error when step is below 1,
|
||||
# it may cause other problems, but LineString needs at least two points
|
||||
|
@ -109,11 +111,29 @@ def path2shapely(path, object_type, res=1.0):
|
|||
|
||||
# Move
|
||||
if isinstance(component, Move):
|
||||
if not points:
|
||||
continue
|
||||
else:
|
||||
rings.append(points)
|
||||
if closed is False:
|
||||
points = []
|
||||
else:
|
||||
closed = False
|
||||
start = component.start
|
||||
x, y = start.real, start.imag
|
||||
points = [(x, y)]
|
||||
continue
|
||||
|
||||
closed = False
|
||||
|
||||
# Close
|
||||
if isinstance(component, Close):
|
||||
if not points:
|
||||
continue
|
||||
else:
|
||||
rings.append(points)
|
||||
points = []
|
||||
closed = True
|
||||
continue
|
||||
log.warning("I don't know what this is: %s" % str(component))
|
||||
continue
|
||||
|
@ -122,8 +142,12 @@ def path2shapely(path, object_type, res=1.0):
|
|||
|
||||
if points:
|
||||
rings.append(points)
|
||||
try:
|
||||
rings = MultiLineString(rings)
|
||||
except Exception as e:
|
||||
log.debug("ParseSVG.path2shapely() MString --> %s" % str(e))
|
||||
return None
|
||||
|
||||
rings = MultiLineString(rings)
|
||||
if len(rings) > 0:
|
||||
if len(rings) == 1 and not isinstance(rings, MultiLineString):
|
||||
# Polygons are closed and require more than 2 points
|
||||
|
@ -135,11 +159,14 @@ def path2shapely(path, object_type, res=1.0):
|
|||
try:
|
||||
geo_element = Polygon(rings[0], rings[1:])
|
||||
except Exception:
|
||||
coords = list()
|
||||
coords = []
|
||||
for line in rings:
|
||||
coords.append(line.coords[0])
|
||||
coords.append(line.coords[1])
|
||||
geo_element = Polygon(coords)
|
||||
try:
|
||||
geo_element = Polygon(coords)
|
||||
except Exception:
|
||||
geo_element = LineString(coords)
|
||||
geometry.append(geo_element)
|
||||
return geometry
|
||||
|
||||
|
@ -305,7 +332,7 @@ def getsvggeo(node, object_type, root=None):
|
|||
root = node
|
||||
|
||||
kind = re.search('(?:\{.*\})?(.*)$', node.tag).group(1)
|
||||
geo = list()
|
||||
geo = []
|
||||
|
||||
# Recurse
|
||||
if len(node) > 0:
|
||||
|
|
|
@ -50,94 +50,86 @@ class AlignObjects(FlatCAMTool):
|
|||
""")
|
||||
self.layout.addWidget(title_label)
|
||||
|
||||
self.layout.addWidget(QtWidgets.QLabel(''))
|
||||
|
||||
# Form Layout
|
||||
grid0 = QtWidgets.QGridLayout()
|
||||
grid0.setColumnStretch(0, 0)
|
||||
grid0.setColumnStretch(1, 1)
|
||||
self.layout.addLayout(grid0)
|
||||
|
||||
self.aligned_label = QtWidgets.QLabel('<b>%s</b>' % _("Selection of the WORKING object"))
|
||||
self.aligned_label = QtWidgets.QLabel('<b>%s:</b>' % _("MOVING object"))
|
||||
grid0.addWidget(self.aligned_label, 0, 0, 1, 2)
|
||||
|
||||
# Type of object to be aligned
|
||||
self.type_obj_combo = FCComboBox()
|
||||
self.type_obj_combo.addItem("Gerber")
|
||||
self.type_obj_combo.addItem("Excellon")
|
||||
|
||||
self.type_obj_combo.setItemIcon(0, QtGui.QIcon(self.app.resource_location + "/flatcam_icon16.png"))
|
||||
self.type_obj_combo.setItemIcon(1, QtGui.QIcon(self.app.resource_location + "/drill16.png"))
|
||||
|
||||
self.type_obj_combo_label = QtWidgets.QLabel('%s:' % _("Object Type"))
|
||||
self.type_obj_combo_label.setToolTip(
|
||||
self.aligned_label.setToolTip(
|
||||
_("Specify the type of object to be aligned.\n"
|
||||
"It can be of type: Gerber or Excellon.\n"
|
||||
"The selection here decide the type of objects that will be\n"
|
||||
"in the Object combobox.")
|
||||
)
|
||||
grid0.addWidget(self.type_obj_combo_label, 2, 0)
|
||||
grid0.addWidget(self.type_obj_combo, 2, 1)
|
||||
|
||||
# Type of object to be aligned
|
||||
self.type_obj_radio = RadioSet([
|
||||
{"label": _("Gerber"), "value": "grb"},
|
||||
{"label": _("Excellon"), "value": "exc"},
|
||||
], orientation='vertical', stretch=False)
|
||||
|
||||
grid0.addWidget(self.type_obj_radio, 3, 0, 1, 2)
|
||||
|
||||
# Object to be aligned
|
||||
self.object_combo = FCComboBox()
|
||||
self.object_combo.setModel(self.app.collection)
|
||||
self.object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.object_combo.setCurrentIndex(1)
|
||||
self.object_combo.is_last = True
|
||||
|
||||
self.object_label = QtWidgets.QLabel('%s:' % _("Object"))
|
||||
self.object_label.setToolTip(
|
||||
self.object_combo.setToolTip(
|
||||
_("Object to be aligned.")
|
||||
)
|
||||
|
||||
grid0.addWidget(self.object_label, 3, 0)
|
||||
grid0.addWidget(self.object_combo, 3, 1)
|
||||
grid0.addWidget(self.object_combo, 4, 0, 1, 2)
|
||||
|
||||
separator_line = QtWidgets.QFrame()
|
||||
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
grid0.addWidget(separator_line, 4, 0, 1, 2)
|
||||
grid0.addWidget(separator_line, 5, 0, 1, 2)
|
||||
|
||||
self.aligned_label = QtWidgets.QLabel('<b>%s</b>' % _("Selection of the TARGET object"))
|
||||
grid0.addWidget(QtWidgets.QLabel(''), 6, 0, 1, 2)
|
||||
|
||||
self.aligned_label = QtWidgets.QLabel('<b>%s:</b>' % _("TARGET object"))
|
||||
self.aligned_label.setToolTip(
|
||||
_("Object to which the other objects will be aligned to (moved to).")
|
||||
)
|
||||
grid0.addWidget(self.aligned_label, 6, 0, 1, 2)
|
||||
|
||||
# Type of object to be aligned to = aligner
|
||||
self.type_aligner_obj_combo = FCComboBox()
|
||||
self.type_aligner_obj_combo.addItem("Gerber")
|
||||
self.type_aligner_obj_combo.addItem("Excellon")
|
||||
|
||||
self.type_aligner_obj_combo.setItemIcon(0, QtGui.QIcon(self.app.resource_location + "/flatcam_icon16.png"))
|
||||
self.type_aligner_obj_combo.setItemIcon(1, QtGui.QIcon(self.app.resource_location + "/drill16.png"))
|
||||
|
||||
self.type_aligner_obj_combo_label = QtWidgets.QLabel('%s:' % _("Object Type"))
|
||||
self.type_aligner_obj_combo_label.setToolTip(
|
||||
_("Specify the type of object to be aligned to.\n"
|
||||
"It can be of type: Gerber or Excellon.\n"
|
||||
"The selection here decide the type of objects that will be\n"
|
||||
"in the Object combobox.")
|
||||
)
|
||||
grid0.addWidget(self.type_aligner_obj_combo_label, 7, 0)
|
||||
grid0.addWidget(self.type_aligner_obj_combo, 7, 1)
|
||||
grid0.addWidget(self.aligned_label, 7, 0, 1, 2)
|
||||
|
||||
# Type of object to be aligned to = aligner
|
||||
self.type_aligner_obj_radio = RadioSet([
|
||||
{"label": _("Gerber"), "value": "grb"},
|
||||
{"label": _("Excellon"), "value": "exc"},
|
||||
], orientation='vertical', stretch=False)
|
||||
|
||||
grid0.addWidget(self.type_aligner_obj_radio, 8, 0, 1, 2)
|
||||
|
||||
# Object to be aligned to = aligner
|
||||
self.aligner_object_combo = FCComboBox()
|
||||
self.aligner_object_combo.setModel(self.app.collection)
|
||||
self.aligner_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.aligner_object_combo.setCurrentIndex(1)
|
||||
self.aligner_object_combo.is_last = True
|
||||
|
||||
self.aligner_object_label = QtWidgets.QLabel('%s:' % _("Object"))
|
||||
self.aligner_object_label.setToolTip(
|
||||
self.aligner_object_combo.setToolTip(
|
||||
_("Object to be aligned to. Aligner.")
|
||||
)
|
||||
|
||||
grid0.addWidget(self.aligner_object_label, 8, 0)
|
||||
grid0.addWidget(self.aligner_object_combo, 8, 1)
|
||||
grid0.addWidget(self.aligner_object_combo, 9, 0, 1, 2)
|
||||
|
||||
separator_line = QtWidgets.QFrame()
|
||||
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
grid0.addWidget(separator_line, 9, 0, 1, 2)
|
||||
grid0.addWidget(separator_line, 10, 0, 1, 2)
|
||||
|
||||
grid0.addWidget(QtWidgets.QLabel(''), 11, 0, 1, 2)
|
||||
|
||||
# Alignment Type
|
||||
self.a_type_lbl = QtWidgets.QLabel('<b>%s:</b>' % _("Alignment Type"))
|
||||
|
@ -151,17 +143,17 @@ class AlignObjects(FlatCAMTool):
|
|||
{'label': _('Single Point'), 'value': 'sp'},
|
||||
{'label': _('Dual Point'), 'value': 'dp'}
|
||||
],
|
||||
orientation='horizontal',
|
||||
orientation='vertical',
|
||||
stretch=False
|
||||
)
|
||||
|
||||
grid0.addWidget(self.a_type_lbl, 10, 0, 1, 2)
|
||||
grid0.addWidget(self.a_type_radio, 11, 0, 1, 2)
|
||||
grid0.addWidget(self.a_type_lbl, 12, 0, 1, 2)
|
||||
grid0.addWidget(self.a_type_radio, 13, 0, 1, 2)
|
||||
|
||||
separator_line = QtWidgets.QFrame()
|
||||
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
grid0.addWidget(separator_line, 12, 0, 1, 2)
|
||||
grid0.addWidget(separator_line, 14, 0, 1, 2)
|
||||
|
||||
# Buttons
|
||||
self.align_object_button = QtWidgets.QPushButton(_("Align Object"))
|
||||
|
@ -195,8 +187,8 @@ class AlignObjects(FlatCAMTool):
|
|||
|
||||
# Signals
|
||||
self.align_object_button.clicked.connect(self.on_align)
|
||||
self.type_obj_combo.currentIndexChanged.connect(self.on_type_obj_index_changed)
|
||||
self.type_aligner_obj_combo.currentIndexChanged.connect(self.on_type_aligner_index_changed)
|
||||
self.type_obj_radio.activated_custom.connect(self.on_type_obj_changed)
|
||||
self.type_aligner_obj_radio.activated_custom.connect(self.on_type_aligner_changed)
|
||||
self.reset_button.clicked.connect(self.set_tool_ui)
|
||||
|
||||
self.mr = None
|
||||
|
@ -214,7 +206,7 @@ class AlignObjects(FlatCAMTool):
|
|||
self.target_obj = None
|
||||
|
||||
# here store the alignment points
|
||||
self.clicked_points = list()
|
||||
self.clicked_points = []
|
||||
|
||||
self.align_type = None
|
||||
|
||||
|
@ -257,7 +249,7 @@ class AlignObjects(FlatCAMTool):
|
|||
def set_tool_ui(self):
|
||||
self.reset_fields()
|
||||
|
||||
self.clicked_points = list()
|
||||
self.clicked_points = []
|
||||
self.target_obj = None
|
||||
self.aligned_obj = None
|
||||
self.aligner_obj = None
|
||||
|
@ -268,19 +260,23 @@ class AlignObjects(FlatCAMTool):
|
|||
self.aligned_old_line_color = None
|
||||
|
||||
self.a_type_radio.set_value(self.app.defaults["tools_align_objects_align_type"])
|
||||
self.type_obj_radio.set_value('grb')
|
||||
self.type_aligner_obj_radio.set_value('grb')
|
||||
|
||||
if self.local_connected is True:
|
||||
self.disconnect_cal_events()
|
||||
|
||||
def on_type_obj_index_changed(self):
|
||||
obj_type = self.type_obj_combo.currentIndex()
|
||||
def on_type_obj_changed(self, val):
|
||||
obj_type = {'grb': 0, 'exc': 1}[val]
|
||||
self.object_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
|
||||
self.object_combo.setCurrentIndex(0)
|
||||
self.object_combo.obj_type = {'grb': "Gerber", 'exc': "Excellon"}[val]
|
||||
|
||||
def on_type_aligner_index_changed(self):
|
||||
obj_type = self.type_aligner_obj_combo.currentIndex()
|
||||
def on_type_aligner_changed(self, val):
|
||||
obj_type = {'grb': 0, 'exc': 1}[val]
|
||||
self.aligner_object_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
|
||||
self.aligner_object_combo.setCurrentIndex(0)
|
||||
self.aligner_object_combo.obj_type = {'grb': "Gerber", 'exc': "Excellon"}[val]
|
||||
|
||||
def on_align(self):
|
||||
self.app.delete_selection_shape()
|
||||
|
@ -379,7 +375,7 @@ class AlignObjects(FlatCAMTool):
|
|||
|
||||
elif event.button == right_button and self.app.event_is_dragging is False:
|
||||
self.reset_color()
|
||||
self.clicked_points = list()
|
||||
self.clicked_points = []
|
||||
self.disconnect_cal_events()
|
||||
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Cancelled by user request."))
|
||||
|
||||
|
|
|
@ -92,7 +92,7 @@ class ToolCalculator(FlatCAMTool):
|
|||
self.layout.addLayout(form_layout)
|
||||
|
||||
self.tipDia_label = QtWidgets.QLabel('%s:' % _("Tip Diameter"))
|
||||
self.tipDia_entry = FCDoubleSpinner()
|
||||
self.tipDia_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.tipDia_entry.set_precision(self.decimals)
|
||||
self.tipDia_entry.set_range(0.0, 9999.9999)
|
||||
self.tipDia_entry.setSingleStep(0.1)
|
||||
|
@ -103,16 +103,16 @@ class ToolCalculator(FlatCAMTool):
|
|||
"It is specified by manufacturer.")
|
||||
)
|
||||
self.tipAngle_label = QtWidgets.QLabel('%s:' % _("Tip Angle"))
|
||||
self.tipAngle_entry = FCSpinner()
|
||||
self.tipAngle_entry = FCSpinner(callback=self.confirmation_message_int)
|
||||
self.tipAngle_entry.set_range(0,180)
|
||||
self.tipAngle_entry.setSingleStep(5)
|
||||
self.tipAngle_entry.set_step(5)
|
||||
|
||||
# self.tipAngle_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
|
||||
self.tipAngle_label.setToolTip(_("This is the angle of the tip of the tool.\n"
|
||||
"It is specified by manufacturer."))
|
||||
|
||||
self.cutDepth_label = QtWidgets.QLabel('%s:' % _("Cut Z"))
|
||||
self.cutDepth_entry = FCDoubleSpinner()
|
||||
self.cutDepth_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.cutDepth_entry.set_range(-9999.9999, 9999.9999)
|
||||
self.cutDepth_entry.set_precision(self.decimals)
|
||||
|
||||
|
@ -121,7 +121,7 @@ class ToolCalculator(FlatCAMTool):
|
|||
"In the CNCJob is the CutZ parameter."))
|
||||
|
||||
self.effectiveToolDia_label = QtWidgets.QLabel('%s:' % _("Tool Diameter"))
|
||||
self.effectiveToolDia_entry = FCDoubleSpinner()
|
||||
self.effectiveToolDia_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.effectiveToolDia_entry.set_precision(self.decimals)
|
||||
|
||||
# self.effectiveToolDia_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
|
||||
|
@ -165,7 +165,7 @@ class ToolCalculator(FlatCAMTool):
|
|||
self.layout.addLayout(plate_form_layout)
|
||||
|
||||
self.pcblengthlabel = QtWidgets.QLabel('%s:' % _("Board Length"))
|
||||
self.pcblength_entry = FCDoubleSpinner()
|
||||
self.pcblength_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.pcblength_entry.set_precision(self.decimals)
|
||||
self.pcblength_entry.set_range(0.0, 9999.9999)
|
||||
|
||||
|
@ -173,7 +173,7 @@ class ToolCalculator(FlatCAMTool):
|
|||
self.pcblengthlabel.setToolTip(_('This is the board length. In centimeters.'))
|
||||
|
||||
self.pcbwidthlabel = QtWidgets.QLabel('%s:' % _("Board Width"))
|
||||
self.pcbwidth_entry = FCDoubleSpinner()
|
||||
self.pcbwidth_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.pcbwidth_entry.set_precision(self.decimals)
|
||||
self.pcbwidth_entry.set_range(0.0, 9999.9999)
|
||||
|
||||
|
@ -181,7 +181,7 @@ class ToolCalculator(FlatCAMTool):
|
|||
self.pcbwidthlabel.setToolTip(_('This is the board width.In centimeters.'))
|
||||
|
||||
self.cdensity_label = QtWidgets.QLabel('%s:' % _("Current Density"))
|
||||
self.cdensity_entry = FCDoubleSpinner()
|
||||
self.cdensity_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.cdensity_entry.set_precision(self.decimals)
|
||||
self.cdensity_entry.set_range(0.0, 9999.9999)
|
||||
self.cdensity_entry.setSingleStep(0.1)
|
||||
|
@ -191,7 +191,7 @@ class ToolCalculator(FlatCAMTool):
|
|||
"In Amps per Square Feet ASF."))
|
||||
|
||||
self.growth_label = QtWidgets.QLabel('%s:' % _("Copper Growth"))
|
||||
self.growth_entry = FCDoubleSpinner()
|
||||
self.growth_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.growth_entry.set_precision(self.decimals)
|
||||
self.growth_entry.set_range(0.0, 9999.9999)
|
||||
self.growth_entry.setSingleStep(0.01)
|
||||
|
@ -203,7 +203,7 @@ class ToolCalculator(FlatCAMTool):
|
|||
# self.growth_entry.setEnabled(False)
|
||||
|
||||
self.cvaluelabel = QtWidgets.QLabel('%s:' % _("Current Value"))
|
||||
self.cvalue_entry = FCDoubleSpinner()
|
||||
self.cvalue_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.cvalue_entry.set_precision(self.decimals)
|
||||
self.cvalue_entry.set_range(0.0, 9999.9999)
|
||||
self.cvalue_entry.setSingleStep(0.1)
|
||||
|
@ -214,7 +214,7 @@ class ToolCalculator(FlatCAMTool):
|
|||
self.cvalue_entry.setReadOnly(True)
|
||||
|
||||
self.timelabel = QtWidgets.QLabel('%s:' % _("Time"))
|
||||
self.time_entry = FCDoubleSpinner()
|
||||
self.time_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.time_entry.set_precision(self.decimals)
|
||||
self.time_entry.set_range(0.0, 9999.9999)
|
||||
self.time_entry.setSingleStep(0.1)
|
||||
|
@ -242,6 +242,19 @@ class ToolCalculator(FlatCAMTool):
|
|||
|
||||
self.layout.addStretch()
|
||||
|
||||
# ## Reset Tool
|
||||
self.reset_button = QtWidgets.QPushButton(_("Reset Tool"))
|
||||
self.reset_button.setToolTip(
|
||||
_("Will reset the tool parameters.")
|
||||
)
|
||||
self.reset_button.setStyleSheet("""
|
||||
QPushButton
|
||||
{
|
||||
font-weight: bold;
|
||||
}
|
||||
""")
|
||||
self.layout.addWidget(self.reset_button)
|
||||
|
||||
self.units = ''
|
||||
|
||||
# ## Signals
|
||||
|
@ -255,6 +268,7 @@ class ToolCalculator(FlatCAMTool):
|
|||
self.inch_entry.editingFinished.connect(self.on_calculate_mm_units)
|
||||
|
||||
self.calculate_plate_button.clicked.connect(self.on_calculate_eplate)
|
||||
self.reset_button.clicked.connect(self.set_tool_ui)
|
||||
|
||||
def run(self, toggle=True):
|
||||
self.app.report_usage("ToolCalculators()")
|
||||
|
|
|
@ -76,7 +76,7 @@ class ToolCalibration(FlatCAMTool):
|
|||
_("Height (Z) for travelling between the points.")
|
||||
)
|
||||
|
||||
self.travelz_entry = FCDoubleSpinner()
|
||||
self.travelz_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.travelz_entry.set_range(-9999.9999, 9999.9999)
|
||||
self.travelz_entry.set_precision(self.decimals)
|
||||
self.travelz_entry.setSingleStep(0.1)
|
||||
|
@ -90,7 +90,7 @@ class ToolCalibration(FlatCAMTool):
|
|||
_("Height (Z) for checking the point.")
|
||||
)
|
||||
|
||||
self.verz_entry = FCDoubleSpinner()
|
||||
self.verz_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.verz_entry.set_range(-9999.9999, 9999.9999)
|
||||
self.verz_entry.set_precision(self.decimals)
|
||||
self.verz_entry.setSingleStep(0.1)
|
||||
|
@ -113,7 +113,7 @@ class ToolCalibration(FlatCAMTool):
|
|||
_("Height (Z) for mounting the verification probe.")
|
||||
)
|
||||
|
||||
self.toolchangez_entry = FCDoubleSpinner()
|
||||
self.toolchangez_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.toolchangez_entry.set_range(0.0000, 9999.9999)
|
||||
self.toolchangez_entry.set_precision(self.decimals)
|
||||
self.toolchangez_entry.setSingleStep(0.1)
|
||||
|
@ -195,7 +195,6 @@ class ToolCalibration(FlatCAMTool):
|
|||
self.obj_type_combo = FCComboBox()
|
||||
self.obj_type_combo.addItem(_("Gerber"))
|
||||
self.obj_type_combo.addItem(_("Excellon"))
|
||||
self.obj_type_combo.setCurrentIndex(1)
|
||||
|
||||
self.obj_type_combo.setItemIcon(0, QtGui.QIcon(self.app.resource_location + "/flatcam_icon16.png"))
|
||||
self.obj_type_combo.setItemIcon(1, QtGui.QIcon(self.app.resource_location + "/drill16.png"))
|
||||
|
@ -206,7 +205,7 @@ class ToolCalibration(FlatCAMTool):
|
|||
self.object_combo = FCComboBox()
|
||||
self.object_combo.setModel(self.app.collection)
|
||||
self.object_combo.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
|
||||
self.object_combo.setCurrentIndex(1)
|
||||
self.object_combo.is_last = True
|
||||
|
||||
self.object_label = QtWidgets.QLabel("%s:" % _("Source object selection"))
|
||||
self.object_label.setToolTip(
|
||||
|
@ -263,8 +262,6 @@ class ToolCalibration(FlatCAMTool):
|
|||
self.bottom_left_coordy_found = EvalEntry()
|
||||
self.points_table.setCellWidget(row, 3, self.bottom_left_coordy_found)
|
||||
|
||||
self.bottom_left_coordx_found.set_value(_("Origin"))
|
||||
self.bottom_left_coordy_found.set_value(_("Origin"))
|
||||
self.bottom_left_coordx_found.setDisabled(True)
|
||||
self.bottom_left_coordy_found.setDisabled(True)
|
||||
row += 1
|
||||
|
@ -471,7 +468,7 @@ class ToolCalibration(FlatCAMTool):
|
|||
self.scalex_label.setToolTip(
|
||||
_("Factor for Scale action over X axis.")
|
||||
)
|
||||
self.scalex_entry = FCDoubleSpinner()
|
||||
self.scalex_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.scalex_entry.set_range(0, 9999.9999)
|
||||
self.scalex_entry.set_precision(self.decimals)
|
||||
self.scalex_entry.setSingleStep(0.1)
|
||||
|
@ -483,7 +480,7 @@ class ToolCalibration(FlatCAMTool):
|
|||
self.scaley_label.setToolTip(
|
||||
_("Factor for Scale action over Y axis.")
|
||||
)
|
||||
self.scaley_entry = FCDoubleSpinner()
|
||||
self.scaley_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.scaley_entry.set_range(0, 9999.9999)
|
||||
self.scaley_entry.set_precision(self.decimals)
|
||||
self.scaley_entry.setSingleStep(0.1)
|
||||
|
@ -508,7 +505,7 @@ class ToolCalibration(FlatCAMTool):
|
|||
_("Angle for Skew action, in degrees.\n"
|
||||
"Float number between -360 and 359.")
|
||||
)
|
||||
self.skewx_entry = FCDoubleSpinner()
|
||||
self.skewx_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.skewx_entry.set_range(-360, 360)
|
||||
self.skewx_entry.set_precision(self.decimals)
|
||||
self.skewx_entry.setSingleStep(0.1)
|
||||
|
@ -521,7 +518,7 @@ class ToolCalibration(FlatCAMTool):
|
|||
_("Angle for Skew action, in degrees.\n"
|
||||
"Float number between -360 and 359.")
|
||||
)
|
||||
self.skewy_entry = FCDoubleSpinner()
|
||||
self.skewy_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.skewy_entry.set_range(-360, 360)
|
||||
self.skewy_entry.set_precision(self.decimals)
|
||||
self.skewy_entry.setSingleStep(0.1)
|
||||
|
@ -552,7 +549,7 @@ class ToolCalibration(FlatCAMTool):
|
|||
# self.fin_scalex_label.setToolTip(
|
||||
# _("Final factor for Scale action over X axis.")
|
||||
# )
|
||||
# self.fin_scalex_entry = FCDoubleSpinner()
|
||||
# self.fin_scalex_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
# self.fin_scalex_entry.set_range(0, 9999.9999)
|
||||
# self.fin_scalex_entry.set_precision(self.decimals)
|
||||
# self.fin_scalex_entry.setSingleStep(0.1)
|
||||
|
@ -564,7 +561,7 @@ class ToolCalibration(FlatCAMTool):
|
|||
# self.fin_scaley_label.setToolTip(
|
||||
# _("Final factor for Scale action over Y axis.")
|
||||
# )
|
||||
# self.fin_scaley_entry = FCDoubleSpinner()
|
||||
# self.fin_scaley_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
# self.fin_scaley_entry.set_range(0, 9999.9999)
|
||||
# self.fin_scaley_entry.set_precision(self.decimals)
|
||||
# self.fin_scaley_entry.setSingleStep(0.1)
|
||||
|
@ -577,7 +574,7 @@ class ToolCalibration(FlatCAMTool):
|
|||
# _("Final value for angle for Skew action, in degrees.\n"
|
||||
# "Float number between -360 and 359.")
|
||||
# )
|
||||
# self.fin_skewx_entry = FCDoubleSpinner()
|
||||
# self.fin_skewx_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
# self.fin_skewx_entry.set_range(-360, 360)
|
||||
# self.fin_skewx_entry.set_precision(self.decimals)
|
||||
# self.fin_skewx_entry.setSingleStep(0.1)
|
||||
|
@ -590,7 +587,7 @@ class ToolCalibration(FlatCAMTool):
|
|||
# _("Final value for angle for Skew action, in degrees.\n"
|
||||
# "Float number between -360 and 359.")
|
||||
# )
|
||||
# self.fin_skewy_entry = FCDoubleSpinner()
|
||||
# self.fin_skewy_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
# self.fin_skewy_entry.set_range(-360, 360)
|
||||
# self.fin_skewy_entry.set_precision(self.decimals)
|
||||
# self.fin_skewy_entry.setSingleStep(0.1)
|
||||
|
@ -630,18 +627,15 @@ class ToolCalibration(FlatCAMTool):
|
|||
)
|
||||
grid_lay.addWidget(step_5, 45, 0, 1, 3)
|
||||
|
||||
self.adj_object_type_combo = QtWidgets.QComboBox()
|
||||
self.adj_object_type_combo = FCComboBox()
|
||||
self.adj_object_type_combo.addItems([_("Gerber"), _("Excellon"), _("Geometry")])
|
||||
self.adj_object_type_combo.setCurrentIndex(0)
|
||||
|
||||
self.adj_object_type_combo.setItemIcon(0, QtGui.QIcon(self.app.resource_location + "/flatcam_icon16.png"))
|
||||
self.adj_object_type_combo.setItemIcon(1, QtGui.QIcon(self.app.resource_location + "/drill16.png"))
|
||||
self.adj_object_type_combo.setItemIcon(2, QtGui.QIcon(self.app.resource_location + "/geometry16.png"))
|
||||
|
||||
self.adj_object_type_label = QtWidgets.QLabel("%s:" % _("Adjusted object type"))
|
||||
self.adj_object_type_label.setToolTip(
|
||||
_("Type of the FlatCAM Object to be adjusted.")
|
||||
)
|
||||
self.adj_object_type_label.setToolTip(_("Type of the FlatCAM Object to be adjusted."))
|
||||
|
||||
grid_lay.addWidget(self.adj_object_type_label, 46, 0, 1, 3)
|
||||
grid_lay.addWidget(self.adj_object_type_combo, 47, 0, 1, 3)
|
||||
|
@ -649,7 +643,10 @@ class ToolCalibration(FlatCAMTool):
|
|||
self.adj_object_combo = FCComboBox()
|
||||
self.adj_object_combo.setModel(self.app.collection)
|
||||
self.adj_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.adj_object_combo.setCurrentIndex(0)
|
||||
self.adj_object_combo.is_last = True
|
||||
self.adj_object_combo.obj_type = {
|
||||
_("Gerber"): "Gerber", _("Excellon"): "Excellon", _("Geometry"): "Geometry"
|
||||
}[self.adj_object_type_combo.get_value()]
|
||||
|
||||
self.adj_object_label = QtWidgets.QLabel("%s:" % _("Adjusted object selection"))
|
||||
self.adj_object_label.setToolTip(
|
||||
|
@ -770,6 +767,9 @@ class ToolCalibration(FlatCAMTool):
|
|||
if self.local_connected is True:
|
||||
self.disconnect_cal_events()
|
||||
|
||||
self.bottom_left_coordx_found.set_value(_("Origin"))
|
||||
self.bottom_left_coordy_found.set_value(_("Origin"))
|
||||
|
||||
self.reset_calibration_points()
|
||||
|
||||
self.cal_source_radio.set_value(self.app.defaults['tools_cal_calsource'])
|
||||
|
@ -786,6 +786,14 @@ class ToolCalibration(FlatCAMTool):
|
|||
self.skewx_entry.set_value(0.0)
|
||||
self.skewy_entry.set_value(0.0)
|
||||
|
||||
# default object selection is Excellon = index_1
|
||||
self.obj_type_combo.setCurrentIndex(1)
|
||||
self.on_obj_type_combo()
|
||||
|
||||
self.adj_object_type_combo.setCurrentIndex(0)
|
||||
self.on_adj_obj_type_combo()
|
||||
# self.adj_object_combo.setCurrentIndex(0)
|
||||
|
||||
# calibrated object
|
||||
self.cal_object = None
|
||||
|
||||
|
@ -794,12 +802,18 @@ class ToolCalibration(FlatCAMTool):
|
|||
def on_obj_type_combo(self):
|
||||
obj_type = self.obj_type_combo.currentIndex()
|
||||
self.object_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
|
||||
self.object_combo.setCurrentIndex(0)
|
||||
# self.object_combo.setCurrentIndex(0)
|
||||
self.object_combo.obj_type = {
|
||||
_("Gerber"): "Gerber", _("Excellon"): "Excellon"
|
||||
}[self.obj_type_combo.get_value()]
|
||||
|
||||
def on_adj_obj_type_combo(self):
|
||||
obj_type = self.adj_object_type_combo.currentIndex()
|
||||
self.adj_object_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
|
||||
self.adj_object_combo.setCurrentIndex(0)
|
||||
# self.adj_object_combo.setCurrentIndex(0)
|
||||
self.adj_object_combo.obj_type = {
|
||||
_("Gerber"): "Gerber", _("Excellon"): "Excellon", _("Geometry"): "Geometry"
|
||||
}[self.adj_object_type_combo.get_value()]
|
||||
|
||||
def on_cal_source_radio(self, val):
|
||||
if val == 'object':
|
||||
|
@ -925,7 +939,7 @@ class ToolCalibration(FlatCAMTool):
|
|||
self.disconnect_cal_events()
|
||||
|
||||
def reset_calibration_points(self):
|
||||
self.click_points = list()
|
||||
self.click_points = []
|
||||
|
||||
self.bottom_left_coordx_tgt.set_value('')
|
||||
self.bottom_left_coordy_tgt.set_value('')
|
||||
|
@ -1275,7 +1289,7 @@ class ToolCalibration(FlatCAMTool):
|
|||
if obj.tools:
|
||||
obj_init.tools = deepcopy(obj.tools)
|
||||
except Exception as ee:
|
||||
log.debug("App.on_copy_object() --> %s" % str(ee))
|
||||
log.debug("ToolCalibration.new_calibrated_object.initialize_geometry() --> %s" % str(ee))
|
||||
|
||||
obj_init.scale(xfactor=scalex, yfactor=scaley, point=(origin_x, origin_y))
|
||||
obj_init.skew(angle_x=skewx, angle_y=skewy, point=(origin_x, origin_y))
|
||||
|
@ -1301,7 +1315,7 @@ class ToolCalibration(FlatCAMTool):
|
|||
if obj.tools:
|
||||
obj_init.tools = deepcopy(obj.tools)
|
||||
except Exception as err:
|
||||
log.debug("App.on_copy_object() --> %s" % str(err))
|
||||
log.debug("ToolCalibration.new_calibrated_object.initialize_gerber() --> %s" % str(err))
|
||||
|
||||
obj_init.scale(xfactor=scalex, yfactor=scaley, point=(origin_x, origin_y))
|
||||
obj_init.skew(angle_x=skewx, angle_y=skewy, point=(origin_x, origin_y))
|
||||
|
|
|
@ -9,7 +9,7 @@ from PyQt5 import QtWidgets, QtCore
|
|||
|
||||
import FlatCAMApp
|
||||
from FlatCAMTool import FlatCAMTool
|
||||
from flatcamGUI.GUIElements import FCDoubleSpinner, RadioSet, FCEntry
|
||||
from flatcamGUI.GUIElements import FCDoubleSpinner, RadioSet, FCEntry, FCComboBox
|
||||
from FlatCAMObj import FlatCAMGerber, FlatCAMGeometry, FlatCAMExcellon
|
||||
|
||||
import shapely.geometry.base as base
|
||||
|
@ -66,10 +66,11 @@ class ToolCopperThieving(FlatCAMTool):
|
|||
i_grid_lay.setColumnStretch(0, 0)
|
||||
i_grid_lay.setColumnStretch(1, 1)
|
||||
|
||||
self.grb_object_combo = QtWidgets.QComboBox()
|
||||
self.grb_object_combo = FCComboBox()
|
||||
self.grb_object_combo.setModel(self.app.collection)
|
||||
self.grb_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.grb_object_combo.setCurrentIndex(1)
|
||||
self.grb_object_combo.is_last = True
|
||||
self.grb_object_combo.obj_type = 'Gerber'
|
||||
|
||||
self.grbobj_label = QtWidgets.QLabel("<b>%s:</b>" % _("GERBER"))
|
||||
self.grbobj_label.setToolTip(
|
||||
|
@ -99,7 +100,7 @@ class ToolCopperThieving(FlatCAMTool):
|
|||
"(the polygon fill may be split in multiple polygons)\n"
|
||||
"and the copper traces in the Gerber file.")
|
||||
)
|
||||
self.clearance_entry = FCDoubleSpinner()
|
||||
self.clearance_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.clearance_entry.set_range(0.00001, 9999.9999)
|
||||
self.clearance_entry.set_precision(self.decimals)
|
||||
self.clearance_entry.setSingleStep(0.1)
|
||||
|
@ -112,7 +113,7 @@ class ToolCopperThieving(FlatCAMTool):
|
|||
self.margin_label.setToolTip(
|
||||
_("Bounding box margin.")
|
||||
)
|
||||
self.margin_entry = FCDoubleSpinner()
|
||||
self.margin_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.margin_entry.set_range(0.0, 9999.9999)
|
||||
self.margin_entry.set_precision(self.decimals)
|
||||
self.margin_entry.setSingleStep(0.1)
|
||||
|
@ -135,35 +136,36 @@ class ToolCopperThieving(FlatCAMTool):
|
|||
grid_lay.addWidget(self.reference_label, 3, 0)
|
||||
grid_lay.addWidget(self.reference_radio, 3, 1)
|
||||
|
||||
self.box_combo_type_label = QtWidgets.QLabel('%s:' % _("Ref. Type"))
|
||||
self.box_combo_type_label.setToolTip(
|
||||
self.ref_combo_type_label = QtWidgets.QLabel('%s:' % _("Ref. Type"))
|
||||
self.ref_combo_type_label.setToolTip(
|
||||
_("The type of FlatCAM object to be used as copper thieving reference.\n"
|
||||
"It can be Gerber, Excellon or Geometry.")
|
||||
)
|
||||
self.box_combo_type = QtWidgets.QComboBox()
|
||||
self.box_combo_type.addItem(_("Reference Gerber"))
|
||||
self.box_combo_type.addItem(_("Reference Excellon"))
|
||||
self.box_combo_type.addItem(_("Reference Geometry"))
|
||||
self.ref_combo_type = FCComboBox()
|
||||
self.ref_combo_type.addItems([_("Gerber"), _("Excellon"), _("Geometry")])
|
||||
|
||||
grid_lay.addWidget(self.box_combo_type_label, 4, 0)
|
||||
grid_lay.addWidget(self.box_combo_type, 4, 1)
|
||||
grid_lay.addWidget(self.ref_combo_type_label, 4, 0)
|
||||
grid_lay.addWidget(self.ref_combo_type, 4, 1)
|
||||
|
||||
self.box_combo_label = QtWidgets.QLabel('%s:' % _("Ref. Object"))
|
||||
self.box_combo_label.setToolTip(
|
||||
self.ref_combo_label = QtWidgets.QLabel('%s:' % _("Ref. Object"))
|
||||
self.ref_combo_label.setToolTip(
|
||||
_("The FlatCAM object to be used as non copper clearing reference.")
|
||||
)
|
||||
self.box_combo = QtWidgets.QComboBox()
|
||||
self.box_combo.setModel(self.app.collection)
|
||||
self.box_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.box_combo.setCurrentIndex(1)
|
||||
self.ref_combo = FCComboBox()
|
||||
self.ref_combo.setModel(self.app.collection)
|
||||
self.ref_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.ref_combo.is_last = True
|
||||
self.ref_combo.obj_type = {
|
||||
_("Gerber"): "Gerber", _("Excellon"): "Excellon", _("Geometry"): "Geometry"
|
||||
}[self.ref_combo_type.get_value()]
|
||||
|
||||
grid_lay.addWidget(self.box_combo_label, 5, 0)
|
||||
grid_lay.addWidget(self.box_combo, 5, 1)
|
||||
grid_lay.addWidget(self.ref_combo_label, 5, 0)
|
||||
grid_lay.addWidget(self.ref_combo, 5, 1)
|
||||
|
||||
self.box_combo.hide()
|
||||
self.box_combo_label.hide()
|
||||
self.box_combo_type.hide()
|
||||
self.box_combo_type_label.hide()
|
||||
self.ref_combo.hide()
|
||||
self.ref_combo_label.hide()
|
||||
self.ref_combo_type.hide()
|
||||
self.ref_combo_type_label.hide()
|
||||
|
||||
# Bounding Box Type #
|
||||
self.bbox_type_radio = RadioSet([
|
||||
|
@ -221,7 +223,7 @@ class ToolCopperThieving(FlatCAMTool):
|
|||
self.dotdia_label.setToolTip(
|
||||
_("Dot diameter in Dots Grid.")
|
||||
)
|
||||
self.dot_dia_entry = FCDoubleSpinner()
|
||||
self.dot_dia_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.dot_dia_entry.set_range(0.0, 9999.9999)
|
||||
self.dot_dia_entry.set_precision(self.decimals)
|
||||
self.dot_dia_entry.setSingleStep(0.1)
|
||||
|
@ -234,7 +236,7 @@ class ToolCopperThieving(FlatCAMTool):
|
|||
self.dotspacing_label.setToolTip(
|
||||
_("Distance between each two dots in Dots Grid.")
|
||||
)
|
||||
self.dot_spacing_entry = FCDoubleSpinner()
|
||||
self.dot_spacing_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.dot_spacing_entry.set_range(0.0, 9999.9999)
|
||||
self.dot_spacing_entry.set_precision(self.decimals)
|
||||
self.dot_spacing_entry.setSingleStep(0.1)
|
||||
|
@ -261,7 +263,7 @@ class ToolCopperThieving(FlatCAMTool):
|
|||
self.square_size_label.setToolTip(
|
||||
_("Square side size in Squares Grid.")
|
||||
)
|
||||
self.square_size_entry = FCDoubleSpinner()
|
||||
self.square_size_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.square_size_entry.set_range(0.0, 9999.9999)
|
||||
self.square_size_entry.set_precision(self.decimals)
|
||||
self.square_size_entry.setSingleStep(0.1)
|
||||
|
@ -274,7 +276,7 @@ class ToolCopperThieving(FlatCAMTool):
|
|||
self.squares_spacing_label.setToolTip(
|
||||
_("Distance between each two squares in Squares Grid.")
|
||||
)
|
||||
self.squares_spacing_entry = FCDoubleSpinner()
|
||||
self.squares_spacing_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.squares_spacing_entry.set_range(0.0, 9999.9999)
|
||||
self.squares_spacing_entry.set_precision(self.decimals)
|
||||
self.squares_spacing_entry.setSingleStep(0.1)
|
||||
|
@ -301,7 +303,7 @@ class ToolCopperThieving(FlatCAMTool):
|
|||
self.line_size_label.setToolTip(
|
||||
_("Line thickness size in Lines Grid.")
|
||||
)
|
||||
self.line_size_entry = FCDoubleSpinner()
|
||||
self.line_size_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.line_size_entry.set_range(0.0, 9999.9999)
|
||||
self.line_size_entry.set_precision(self.decimals)
|
||||
self.line_size_entry.setSingleStep(0.1)
|
||||
|
@ -314,7 +316,7 @@ class ToolCopperThieving(FlatCAMTool):
|
|||
self.lines_spacing_label.setToolTip(
|
||||
_("Distance between each two lines in Lines Grid.")
|
||||
)
|
||||
self.lines_spacing_entry = FCDoubleSpinner()
|
||||
self.lines_spacing_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.lines_spacing_entry.set_range(0.0, 9999.9999)
|
||||
self.lines_spacing_entry.set_precision(self.decimals)
|
||||
self.lines_spacing_entry.setSingleStep(0.1)
|
||||
|
@ -362,7 +364,7 @@ class ToolCopperThieving(FlatCAMTool):
|
|||
self.rb_margin_label.setToolTip(
|
||||
_("Bounding box margin for robber bar.")
|
||||
)
|
||||
self.rb_margin_entry = FCDoubleSpinner()
|
||||
self.rb_margin_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.rb_margin_entry.set_range(-9999.9999, 9999.9999)
|
||||
self.rb_margin_entry.set_precision(self.decimals)
|
||||
self.rb_margin_entry.setSingleStep(0.1)
|
||||
|
@ -375,7 +377,7 @@ class ToolCopperThieving(FlatCAMTool):
|
|||
self.rb_thickness_label.setToolTip(
|
||||
_("The robber bar thickness.")
|
||||
)
|
||||
self.rb_thickness_entry = FCDoubleSpinner()
|
||||
self.rb_thickness_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.rb_thickness_entry.set_range(0.0000, 9999.9999)
|
||||
self.rb_thickness_entry.set_precision(self.decimals)
|
||||
self.rb_thickness_entry.setSingleStep(0.1)
|
||||
|
@ -417,10 +419,11 @@ class ToolCopperThieving(FlatCAMTool):
|
|||
"the pattern plating mask.")
|
||||
)
|
||||
|
||||
self.sm_object_combo = QtWidgets.QComboBox()
|
||||
self.sm_object_combo = FCComboBox()
|
||||
self.sm_object_combo.setModel(self.app.collection)
|
||||
self.sm_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.sm_object_combo.setCurrentIndex(1)
|
||||
self.sm_object_combo.is_last = True
|
||||
self.sm_object_combo.obj_type = 'Gerber'
|
||||
|
||||
grid_lay_1.addWidget(self.sm_obj_label, 7, 0, 1, 3)
|
||||
grid_lay_1.addWidget(self.sm_object_combo, 8, 0, 1, 3)
|
||||
|
@ -431,7 +434,7 @@ class ToolCopperThieving(FlatCAMTool):
|
|||
_("The distance between the possible copper thieving elements\n"
|
||||
"and/or robber bar and the actual openings in the mask.")
|
||||
)
|
||||
self.clearance_ppm_entry = FCDoubleSpinner()
|
||||
self.clearance_ppm_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.clearance_ppm_entry.set_range(-9999.9999, 9999.9999)
|
||||
self.clearance_ppm_entry.set_precision(self.decimals)
|
||||
self.clearance_ppm_entry.setSingleStep(0.1)
|
||||
|
@ -494,11 +497,11 @@ class ToolCopperThieving(FlatCAMTool):
|
|||
# Objects involved in Copper thieving
|
||||
self.grb_object = None
|
||||
self.ref_obj = None
|
||||
self.sel_rect = list()
|
||||
self.sel_rect = []
|
||||
self.sm_object = None
|
||||
|
||||
# store the flattened geometry here:
|
||||
self.flat_geometry = list()
|
||||
self.flat_geometry = []
|
||||
|
||||
# Events ID
|
||||
self.mr = None
|
||||
|
@ -517,7 +520,7 @@ class ToolCopperThieving(FlatCAMTool):
|
|||
self.geo_steps_per_circle = 128
|
||||
|
||||
# Thieving geometry storage
|
||||
self.new_solid_geometry = list()
|
||||
self.new_solid_geometry = []
|
||||
|
||||
# Robber bar geometry storage
|
||||
self.robber_geo = None
|
||||
|
@ -526,7 +529,7 @@ class ToolCopperThieving(FlatCAMTool):
|
|||
self.rb_thickness = None
|
||||
|
||||
# SIGNALS
|
||||
self.box_combo_type.currentIndexChanged.connect(self.on_combo_box_type)
|
||||
self.ref_combo_type.currentIndexChanged.connect(self.on_ref_combo_type_change)
|
||||
self.reference_radio.group_toggle_fn = self.on_toggle_reference
|
||||
self.fill_type_radio.activated_custom.connect(self.on_thieving_type)
|
||||
|
||||
|
@ -594,22 +597,25 @@ class ToolCopperThieving(FlatCAMTool):
|
|||
self.robber_line = None
|
||||
self.new_solid_geometry = None
|
||||
|
||||
def on_combo_box_type(self):
|
||||
obj_type = self.box_combo_type.currentIndex()
|
||||
self.box_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
|
||||
self.box_combo.setCurrentIndex(0)
|
||||
def on_ref_combo_type_change(self):
|
||||
obj_type = self.ref_combo_type.currentIndex()
|
||||
self.ref_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
|
||||
self.ref_combo.setCurrentIndex(0)
|
||||
self.ref_combo.obj_type = {
|
||||
_("Gerber"): "Gerber", _("Excellon"): "Excellon", _("Geometry"): "Geometry"
|
||||
}[self.ref_combo_type.get_value()]
|
||||
|
||||
def on_toggle_reference(self):
|
||||
if self.reference_radio.get_value() == "itself" or self.reference_radio.get_value() == "area":
|
||||
self.box_combo.hide()
|
||||
self.box_combo_label.hide()
|
||||
self.box_combo_type.hide()
|
||||
self.box_combo_type_label.hide()
|
||||
self.ref_combo.hide()
|
||||
self.ref_combo_label.hide()
|
||||
self.ref_combo_type.hide()
|
||||
self.ref_combo_type_label.hide()
|
||||
else:
|
||||
self.box_combo.show()
|
||||
self.box_combo_label.show()
|
||||
self.box_combo_type.show()
|
||||
self.box_combo_type_label.show()
|
||||
self.ref_combo.show()
|
||||
self.ref_combo_label.show()
|
||||
self.ref_combo_type.show()
|
||||
self.ref_combo_type_label.show()
|
||||
|
||||
if self.reference_radio.get_value() == "itself":
|
||||
self.bbox_type_label.show()
|
||||
|
@ -681,7 +687,7 @@ class ToolCopperThieving(FlatCAMTool):
|
|||
break
|
||||
|
||||
if aperture_found:
|
||||
geo_elem = dict()
|
||||
geo_elem = {}
|
||||
geo_elem['solid'] = self.robber_geo
|
||||
geo_elem['follow'] = self.robber_line
|
||||
self.grb_object.apertures[aperture_found]['geometry'].append(deepcopy(geo_elem))
|
||||
|
@ -692,19 +698,19 @@ class ToolCopperThieving(FlatCAMTool):
|
|||
else:
|
||||
new_apid = '10'
|
||||
|
||||
self.grb_object.apertures[new_apid] = dict()
|
||||
self.grb_object.apertures[new_apid] = {}
|
||||
self.grb_object.apertures[new_apid]['type'] = 'C'
|
||||
self.grb_object.apertures[new_apid]['size'] = self.rb_thickness
|
||||
self.grb_object.apertures[new_apid]['geometry'] = list()
|
||||
self.grb_object.apertures[new_apid]['geometry'] = []
|
||||
|
||||
geo_elem = dict()
|
||||
geo_elem = {}
|
||||
geo_elem['solid'] = self.robber_geo
|
||||
geo_elem['follow'] = self.robber_line
|
||||
self.grb_object.apertures[new_apid]['geometry'].append(deepcopy(geo_elem))
|
||||
|
||||
geo_obj = self.grb_object.solid_geometry
|
||||
if isinstance(geo_obj, MultiPolygon):
|
||||
s_list = list()
|
||||
s_list = []
|
||||
for pol in geo_obj.geoms:
|
||||
s_list.append(pol)
|
||||
s_list.append(self.robber_geo)
|
||||
|
@ -778,7 +784,7 @@ class ToolCopperThieving(FlatCAMTool):
|
|||
self.mm = self.app.plotcanvas.graph_event_connect('mouse_move', self.on_mouse_move)
|
||||
|
||||
elif reference_method == 'box':
|
||||
bound_obj_name = self.box_combo.currentText()
|
||||
bound_obj_name = self.ref_combo.currentText()
|
||||
|
||||
# Get reference object.
|
||||
try:
|
||||
|
@ -1127,7 +1133,7 @@ class ToolCopperThieving(FlatCAMTool):
|
|||
|
||||
if fill_type == 'dot' or fill_type == 'square':
|
||||
# build the MultiPolygon of dots/squares that will fill the entire bounding box
|
||||
thieving_list = list()
|
||||
thieving_list = []
|
||||
|
||||
if fill_type == 'dot':
|
||||
radius = dot_dia / 2.0
|
||||
|
@ -1169,7 +1175,7 @@ class ToolCopperThieving(FlatCAMTool):
|
|||
except TypeError:
|
||||
thieving_box_geo = [thieving_box_geo]
|
||||
|
||||
thieving_geo = list()
|
||||
thieving_geo = []
|
||||
for dot_geo in thieving_box_geo:
|
||||
for geo_t in app_obj.new_solid_geometry:
|
||||
if dot_geo.within(geo_t):
|
||||
|
@ -1212,7 +1218,7 @@ class ToolCopperThieving(FlatCAMTool):
|
|||
app_obj.app.proc_container.update_view_text(' %s' % _("Buffering"))
|
||||
outline_geometry = unary_union(outline_geometry)
|
||||
|
||||
outline_line = list()
|
||||
outline_line = []
|
||||
try:
|
||||
for geo_o in outline_geometry:
|
||||
outline_line.append(
|
||||
|
@ -1238,7 +1244,7 @@ class ToolCopperThieving(FlatCAMTool):
|
|||
)
|
||||
|
||||
bx0, by0, bx1, by1 = box_outline_geo.bounds
|
||||
thieving_lines_geo = list()
|
||||
thieving_lines_geo = []
|
||||
new_x = bx0
|
||||
new_y = by0
|
||||
while new_x <= x1 - half_thick_line:
|
||||
|
@ -1258,7 +1264,7 @@ class ToolCopperThieving(FlatCAMTool):
|
|||
new_y += line_size + line_spacing
|
||||
|
||||
# merge everything together
|
||||
diff_lines_geo = list()
|
||||
diff_lines_geo = []
|
||||
for line_poly in thieving_lines_geo:
|
||||
rest_line = line_poly.difference(clearance_geometry)
|
||||
diff_lines_geo.append(rest_line)
|
||||
|
@ -1271,8 +1277,8 @@ class ToolCopperThieving(FlatCAMTool):
|
|||
geo_list = list(app_obj.grb_object.solid_geometry.geoms)
|
||||
|
||||
if '0' not in app_obj.grb_object.apertures:
|
||||
app_obj.grb_object.apertures['0'] = dict()
|
||||
app_obj.grb_object.apertures['0']['geometry'] = list()
|
||||
app_obj.grb_object.apertures['0'] = {}
|
||||
app_obj.grb_object.apertures['0']['geometry'] = []
|
||||
app_obj.grb_object.apertures['0']['type'] = 'REG'
|
||||
app_obj.grb_object.apertures['0']['size'] = 0.0
|
||||
|
||||
|
@ -1282,7 +1288,7 @@ class ToolCopperThieving(FlatCAMTool):
|
|||
geo_list.append(poly)
|
||||
|
||||
# append into the '0' aperture
|
||||
geo_elem = dict()
|
||||
geo_elem = {}
|
||||
geo_elem['solid'] = poly
|
||||
geo_elem['follow'] = poly.exterior
|
||||
app_obj.grb_object.apertures['0']['geometry'].append(deepcopy(geo_elem))
|
||||
|
@ -1291,7 +1297,7 @@ class ToolCopperThieving(FlatCAMTool):
|
|||
geo_list.append(app_obj.new_solid_geometry)
|
||||
|
||||
# append into the '0' aperture
|
||||
geo_elem = dict()
|
||||
geo_elem = {}
|
||||
geo_elem['solid'] = app_obj.new_solid_geometry
|
||||
geo_elem['follow'] = app_obj.new_solid_geometry.exterior
|
||||
app_obj.grb_object.apertures['0']['geometry'].append(deepcopy(geo_elem))
|
||||
|
@ -1350,7 +1356,7 @@ class ToolCopperThieving(FlatCAMTool):
|
|||
|
||||
# if the clearance is negative apply it to the original soldermask too
|
||||
if ppm_clearance < 0:
|
||||
temp_geo_list = list()
|
||||
temp_geo_list = []
|
||||
for geo in geo_list:
|
||||
temp_geo_list.append(geo.buffer(ppm_clearance))
|
||||
geo_list = temp_geo_list
|
||||
|
@ -1372,11 +1378,11 @@ class ToolCopperThieving(FlatCAMTool):
|
|||
|
||||
def obj_init(grb_obj, app_obj):
|
||||
grb_obj.multitool = False
|
||||
grb_obj.source_file = list()
|
||||
grb_obj.source_file = []
|
||||
grb_obj.multigeo = False
|
||||
grb_obj.follow = False
|
||||
grb_obj.apertures = dict()
|
||||
grb_obj.solid_geometry = list()
|
||||
grb_obj.apertures = {}
|
||||
grb_obj.solid_geometry = []
|
||||
|
||||
# try:
|
||||
# grb_obj.options['xmin'] = 0
|
||||
|
@ -1389,8 +1395,8 @@ class ToolCopperThieving(FlatCAMTool):
|
|||
# if we have copper thieving geometry, add it
|
||||
if thieving_solid_geo:
|
||||
if '0' not in grb_obj.apertures:
|
||||
grb_obj.apertures['0'] = dict()
|
||||
grb_obj.apertures['0']['geometry'] = list()
|
||||
grb_obj.apertures['0'] = {}
|
||||
grb_obj.apertures['0']['geometry'] = []
|
||||
grb_obj.apertures['0']['type'] = 'REG'
|
||||
grb_obj.apertures['0']['size'] = 0.0
|
||||
|
||||
|
@ -1402,7 +1408,7 @@ class ToolCopperThieving(FlatCAMTool):
|
|||
geo_list.append(poly_b)
|
||||
|
||||
# append into the '0' aperture
|
||||
geo_elem = dict()
|
||||
geo_elem = {}
|
||||
geo_elem['solid'] = poly_b
|
||||
geo_elem['follow'] = poly_b.exterior
|
||||
grb_obj.apertures['0']['geometry'].append(deepcopy(geo_elem))
|
||||
|
@ -1411,7 +1417,7 @@ class ToolCopperThieving(FlatCAMTool):
|
|||
geo_list.append(thieving_solid_geo.buffer(ppm_clearance))
|
||||
|
||||
# append into the '0' aperture
|
||||
geo_elem = dict()
|
||||
geo_elem = {}
|
||||
geo_elem['solid'] = thieving_solid_geo.buffer(ppm_clearance)
|
||||
geo_elem['follow'] = thieving_solid_geo.buffer(ppm_clearance).exterior
|
||||
grb_obj.apertures['0']['geometry'].append(deepcopy(geo_elem))
|
||||
|
@ -1425,7 +1431,7 @@ class ToolCopperThieving(FlatCAMTool):
|
|||
break
|
||||
|
||||
if aperture_found:
|
||||
geo_elem = dict()
|
||||
geo_elem = {}
|
||||
geo_elem['solid'] = robber_solid_geo
|
||||
geo_elem['follow'] = robber_line
|
||||
grb_obj.apertures[aperture_found]['geometry'].append(deepcopy(geo_elem))
|
||||
|
@ -1437,12 +1443,12 @@ class ToolCopperThieving(FlatCAMTool):
|
|||
else:
|
||||
new_apid = '10'
|
||||
|
||||
grb_obj.apertures[new_apid] = dict()
|
||||
grb_obj.apertures[new_apid] = {}
|
||||
grb_obj.apertures[new_apid]['type'] = 'C'
|
||||
grb_obj.apertures[new_apid]['size'] = rb_thickness + ppm_clearance
|
||||
grb_obj.apertures[new_apid]['geometry'] = list()
|
||||
grb_obj.apertures[new_apid]['geometry'] = []
|
||||
|
||||
geo_elem = dict()
|
||||
geo_elem = {}
|
||||
geo_elem['solid'] = robber_solid_geo.buffer(ppm_clearance)
|
||||
geo_elem['follow'] = Polygon(robber_line).buffer(ppm_clearance / 2.0).exterior
|
||||
grb_obj.apertures[new_apid]['geometry'].append(deepcopy(geo_elem))
|
||||
|
@ -1510,7 +1516,7 @@ class ToolCopperThieving(FlatCAMTool):
|
|||
self.grb_object = None
|
||||
self.sm_object = None
|
||||
self.ref_obj = None
|
||||
self.sel_rect = list()
|
||||
self.sel_rect = []
|
||||
|
||||
# Events ID
|
||||
self.mr = None
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
from PyQt5 import QtWidgets, QtGui, QtCore
|
||||
from FlatCAMTool import FlatCAMTool
|
||||
from flatcamGUI.GUIElements import FCDoubleSpinner, FCCheckBox, RadioSet, FCComboBox, OptionalInputSection
|
||||
from flatcamGUI.GUIElements import FCDoubleSpinner, FCCheckBox, RadioSet, FCComboBox, OptionalInputSection, FCButton
|
||||
from FlatCAMObj import FlatCAMGerber
|
||||
|
||||
from shapely.geometry import box, MultiPolygon, Polygon, LineString, LinearRing
|
||||
|
@ -59,49 +59,21 @@ class CutOut(FlatCAMTool):
|
|||
""")
|
||||
self.layout.addWidget(title_label)
|
||||
|
||||
self.layout.addWidget(QtWidgets.QLabel(''))
|
||||
|
||||
# Form Layout
|
||||
grid0 = QtWidgets.QGridLayout()
|
||||
grid0.setColumnStretch(0, 0)
|
||||
grid0.setColumnStretch(1, 1)
|
||||
self.layout.addLayout(grid0)
|
||||
|
||||
# Type of object to be cutout
|
||||
self.type_obj_combo = QtWidgets.QComboBox()
|
||||
self.type_obj_combo.addItem("Gerber")
|
||||
self.type_obj_combo.addItem("Excellon")
|
||||
self.type_obj_combo.addItem("Geometry")
|
||||
|
||||
# we get rid of item1 ("Excellon") as it is not suitable for creating film
|
||||
self.type_obj_combo.view().setRowHidden(1, True)
|
||||
self.type_obj_combo.setItemIcon(0, QtGui.QIcon(self.app.resource_location + "/flatcam_icon16.png"))
|
||||
# self.type_obj_combo.setItemIcon(1, QtGui.QIcon(self.app.resource_location + "/drill16.png"))
|
||||
self.type_obj_combo.setItemIcon(2, QtGui.QIcon(self.app.resource_location + "/geometry16.png"))
|
||||
|
||||
self.type_obj_combo_label = QtWidgets.QLabel('%s:' % _("Object Type"))
|
||||
self.type_obj_combo_label.setToolTip(
|
||||
_("Specify the type of object to be cutout.\n"
|
||||
"It can be of type: Gerber or Geometry.\n"
|
||||
"What is selected here will dictate the kind\n"
|
||||
"of objects that will populate the 'Object' combobox.")
|
||||
)
|
||||
self.type_obj_combo_label.setMinimumWidth(60)
|
||||
grid0.addWidget(self.type_obj_combo_label, 0, 0)
|
||||
grid0.addWidget(self.type_obj_combo, 0, 1)
|
||||
|
||||
self.object_label = QtWidgets.QLabel('<b>%s:</b>' % _("Object to be cutout"))
|
||||
self.object_label = QtWidgets.QLabel('<b>%s:</b>' % _("Source Object"))
|
||||
self.object_label.setToolTip('%s.' % _("Object to be cutout"))
|
||||
|
||||
# Object to be cutout
|
||||
self.obj_combo = QtWidgets.QComboBox()
|
||||
self.obj_combo.setModel(self.app.collection)
|
||||
self.obj_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.obj_combo.setCurrentIndex(1)
|
||||
|
||||
grid0.addWidget(self.object_label, 1, 0, 1, 2)
|
||||
grid0.addWidget(self.obj_combo, 2, 0, 1, 2)
|
||||
grid0.addWidget(self.object_label, 0, 0, 1, 2)
|
||||
|
||||
# Object kind
|
||||
self.kindlabel = QtWidgets.QLabel('%s:' % _('Object kind'))
|
||||
self.kindlabel = QtWidgets.QLabel('%s:' % _('Kind'))
|
||||
self.kindlabel.setToolTip(
|
||||
_("Choice of what kind the object we want to cutout is.<BR>"
|
||||
"- <B>Single</B>: contain a single PCB Gerber outline object.<BR>"
|
||||
|
@ -112,11 +84,46 @@ class CutOut(FlatCAMTool):
|
|||
{"label": _("Single"), "value": "single"},
|
||||
{"label": _("Panel"), "value": "panel"},
|
||||
])
|
||||
grid0.addWidget(self.kindlabel, 3, 0)
|
||||
grid0.addWidget(self.obj_kind_combo, 3, 1)
|
||||
grid0.addWidget(self.kindlabel, 1, 0)
|
||||
grid0.addWidget(self.obj_kind_combo, 1, 1)
|
||||
|
||||
# Type of object to be cutout
|
||||
self.type_obj_radio = RadioSet([
|
||||
{"label": _("Gerber"), "value": "grb"},
|
||||
{"label": _("Geometry"), "value": "geo"},
|
||||
])
|
||||
|
||||
self.type_obj_combo_label = QtWidgets.QLabel('%s:' % _("Type"))
|
||||
self.type_obj_combo_label.setToolTip(
|
||||
_("Specify the type of object to be cutout.\n"
|
||||
"It can be of type: Gerber or Geometry.\n"
|
||||
"What is selected here will dictate the kind\n"
|
||||
"of objects that will populate the 'Object' combobox.")
|
||||
)
|
||||
|
||||
grid0.addWidget(self.type_obj_combo_label, 2, 0)
|
||||
grid0.addWidget(self.type_obj_radio, 2, 1)
|
||||
|
||||
# Object to be cutout
|
||||
self.obj_combo = FCComboBox()
|
||||
self.obj_combo.setModel(self.app.collection)
|
||||
self.obj_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.obj_combo.is_last = True
|
||||
|
||||
grid0.addWidget(self.obj_combo, 3, 0, 1, 2)
|
||||
|
||||
separator_line = QtWidgets.QFrame()
|
||||
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
grid0.addWidget(separator_line, 4, 0, 1, 2)
|
||||
|
||||
grid0.addWidget(QtWidgets.QLabel(''), 5, 0, 1, 2)
|
||||
|
||||
self.param_label = QtWidgets.QLabel('<b>%s:</b>' % _("Tool Parameters"))
|
||||
grid0.addWidget(self.param_label, 6, 0, 1, 2)
|
||||
|
||||
# Tool Diameter
|
||||
self.dia = FCDoubleSpinner()
|
||||
self.dia = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.dia.set_precision(self.decimals)
|
||||
self.dia.set_range(0.0000, 9999.9999)
|
||||
|
||||
|
@ -125,8 +132,8 @@ class CutOut(FlatCAMTool):
|
|||
_("Diameter of the tool used to cutout\n"
|
||||
"the PCB shape out of the surrounding material.")
|
||||
)
|
||||
grid0.addWidget(self.dia_label, 4, 0)
|
||||
grid0.addWidget(self.dia, 4, 1)
|
||||
grid0.addWidget(self.dia_label, 8, 0)
|
||||
grid0.addWidget(self.dia, 8, 1)
|
||||
|
||||
# Cut Z
|
||||
cutzlabel = QtWidgets.QLabel('%s:' % _('Cut Z'))
|
||||
|
@ -136,7 +143,7 @@ class CutOut(FlatCAMTool):
|
|||
"below the copper surface."
|
||||
)
|
||||
)
|
||||
self.cutz_entry = FCDoubleSpinner()
|
||||
self.cutz_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.cutz_entry.set_precision(self.decimals)
|
||||
|
||||
if machinist_setting == 0:
|
||||
|
@ -146,8 +153,8 @@ class CutOut(FlatCAMTool):
|
|||
|
||||
self.cutz_entry.setSingleStep(0.1)
|
||||
|
||||
grid0.addWidget(cutzlabel, 5, 0)
|
||||
grid0.addWidget(self.cutz_entry, 5, 1)
|
||||
grid0.addWidget(cutzlabel, 9, 0)
|
||||
grid0.addWidget(self.cutz_entry, 9, 1)
|
||||
|
||||
# Multi-pass
|
||||
self.mpass_cb = FCCheckBox('%s:' % _("Multi-Depth"))
|
||||
|
@ -160,7 +167,7 @@ class CutOut(FlatCAMTool):
|
|||
)
|
||||
)
|
||||
|
||||
self.maxdepth_entry = FCDoubleSpinner()
|
||||
self.maxdepth_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.maxdepth_entry.set_precision(self.decimals)
|
||||
self.maxdepth_entry.setRange(0, 9999.9999)
|
||||
self.maxdepth_entry.setSingleStep(0.1)
|
||||
|
@ -172,11 +179,11 @@ class CutOut(FlatCAMTool):
|
|||
)
|
||||
self.ois_mpass_geo = OptionalInputSection(self.mpass_cb, [self.maxdepth_entry])
|
||||
|
||||
grid0.addWidget(self.mpass_cb, 6, 0)
|
||||
grid0.addWidget(self.maxdepth_entry, 6, 1)
|
||||
grid0.addWidget(self.mpass_cb, 10, 0)
|
||||
grid0.addWidget(self.maxdepth_entry, 10, 1)
|
||||
|
||||
# Margin
|
||||
self.margin = FCDoubleSpinner()
|
||||
self.margin = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.margin.set_range(-9999.9999, 9999.9999)
|
||||
self.margin.setSingleStep(0.1)
|
||||
self.margin.set_precision(self.decimals)
|
||||
|
@ -187,11 +194,11 @@ class CutOut(FlatCAMTool):
|
|||
"will make the cutout of the PCB further from\n"
|
||||
"the actual PCB border")
|
||||
)
|
||||
grid0.addWidget(self.margin_label, 7, 0)
|
||||
grid0.addWidget(self.margin, 7, 1)
|
||||
grid0.addWidget(self.margin_label, 11, 0)
|
||||
grid0.addWidget(self.margin, 11, 1)
|
||||
|
||||
# Gapsize
|
||||
self.gapsize = FCDoubleSpinner()
|
||||
self.gapsize = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.gapsize.set_precision(self.decimals)
|
||||
|
||||
self.gapsize_label = QtWidgets.QLabel('%s:' % _("Gap size"))
|
||||
|
@ -201,8 +208,8 @@ class CutOut(FlatCAMTool):
|
|||
"the surrounding material (the one \n"
|
||||
"from which the PCB is cutout).")
|
||||
)
|
||||
grid0.addWidget(self.gapsize_label, 8, 0)
|
||||
grid0.addWidget(self.gapsize, 8, 1)
|
||||
grid0.addWidget(self.gapsize_label, 13, 0)
|
||||
grid0.addWidget(self.gapsize, 13, 1)
|
||||
|
||||
# How gaps wil be rendered:
|
||||
# lr - left + right
|
||||
|
@ -219,12 +226,14 @@ class CutOut(FlatCAMTool):
|
|||
_("Create a convex shape surrounding the entire PCB.\n"
|
||||
"Used only if the source object type is Gerber.")
|
||||
)
|
||||
grid0.addWidget(self.convex_box, 9, 0, 1, 2)
|
||||
grid0.addWidget(self.convex_box, 15, 0, 1, 2)
|
||||
|
||||
separator_line = QtWidgets.QFrame()
|
||||
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
grid0.addWidget(separator_line, 10, 0, 1, 2)
|
||||
grid0.addWidget(separator_line, 16, 0, 1, 2)
|
||||
|
||||
grid0.addWidget(QtWidgets.QLabel(''), 17, 0, 1, 2)
|
||||
|
||||
# Title2
|
||||
title_param_label = QtWidgets.QLabel("<font size=4><b>%s</b></font>" % _('A. Automatic Bridge Gaps'))
|
||||
|
@ -309,10 +318,11 @@ class CutOut(FlatCAMTool):
|
|||
self.layout.addLayout(form_layout_3)
|
||||
|
||||
# Manual Geo Object
|
||||
self.man_object_combo = QtWidgets.QComboBox()
|
||||
self.man_object_combo = FCComboBox()
|
||||
self.man_object_combo.setModel(self.app.collection)
|
||||
self.man_object_combo.setRootModelIndex(self.app.collection.index(2, 0, QtCore.QModelIndex()))
|
||||
self.man_object_combo.setCurrentIndex(1)
|
||||
self.man_object_combo.is_last = True
|
||||
self.man_object_combo.obj_type = "Geometry"
|
||||
|
||||
self.man_object_label = QtWidgets.QLabel('%s:' % _("Geometry Object"))
|
||||
self.man_object_label.setToolTip(
|
||||
|
@ -398,15 +408,16 @@ class CutOut(FlatCAMTool):
|
|||
self.ff_cutout_object_btn.clicked.connect(self.on_freeform_cutout)
|
||||
self.rect_cutout_object_btn.clicked.connect(self.on_rectangular_cutout)
|
||||
|
||||
self.type_obj_combo.currentIndexChanged.connect(self.on_type_obj_index_changed)
|
||||
self.type_obj_radio.activated_custom.connect(self.on_type_obj_changed)
|
||||
self.man_geo_creation_btn.clicked.connect(self.on_manual_geo)
|
||||
self.man_gaps_creation_btn.clicked.connect(self.on_manual_gap_click)
|
||||
self.reset_button.clicked.connect(self.set_tool_ui)
|
||||
|
||||
def on_type_obj_index_changed(self, index):
|
||||
obj_type = self.type_obj_combo.currentIndex()
|
||||
def on_type_obj_changed(self, val):
|
||||
obj_type = {'grb': 0, 'geo': 2}[val]
|
||||
self.obj_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
|
||||
self.obj_combo.setCurrentIndex(0)
|
||||
self.obj_combo.obj_type = {"grb": "Gerber", "geo": "Geometry"}[val]
|
||||
|
||||
def run(self, toggle=True):
|
||||
self.app.report_usage("ToolCutOut()")
|
||||
|
@ -451,6 +462,7 @@ class CutOut(FlatCAMTool):
|
|||
self.gapsize.set_value(float(self.app.defaults["tools_cutoutgapsize"]))
|
||||
self.gaps.set_value(self.app.defaults["tools_gaps_ff"])
|
||||
self.convex_box.set_value(self.app.defaults['tools_cutout_convexshape'])
|
||||
self.type_obj_radio.set_value('grb')
|
||||
|
||||
def on_freeform_cutout(self):
|
||||
|
||||
|
@ -514,9 +526,16 @@ class CutOut(FlatCAMTool):
|
|||
solid_geo = []
|
||||
|
||||
if isinstance(cutout_obj, FlatCAMGerber):
|
||||
if convex_box:
|
||||
object_geo = cutout_obj.solid_geometry.convex_hull
|
||||
else:
|
||||
if isinstance(cutout_obj.solid_geometry, list):
|
||||
cutout_obj.solid_geometry = MultiPolygon(cutout_obj.solid_geometry)
|
||||
|
||||
try:
|
||||
if convex_box:
|
||||
object_geo = cutout_obj.solid_geometry.convex_hull
|
||||
else:
|
||||
object_geo = cutout_obj.solid_geometry
|
||||
except Exception as err:
|
||||
log.debug("CutOut.on_freeform_cutout().geo_init() --> %s" % str(err))
|
||||
object_geo = cutout_obj.solid_geometry
|
||||
else:
|
||||
object_geo = cutout_obj.solid_geometry
|
||||
|
@ -588,12 +607,14 @@ class CutOut(FlatCAMTool):
|
|||
if isinstance(object_geo, MultiPolygon):
|
||||
x0, y0, x1, y1 = object_geo.bounds
|
||||
object_geo = box(x0, y0, x1, y1)
|
||||
if margin >= 0:
|
||||
geo_buf = object_geo.buffer(margin + abs(dia / 2))
|
||||
else:
|
||||
geo_buf = object_geo.buffer(margin - abs(dia / 2))
|
||||
|
||||
geo_buf = object_geo.buffer(margin + abs(dia / 2))
|
||||
geo = geo_buf.exterior
|
||||
else:
|
||||
geo = object_geo
|
||||
|
||||
solid_geo = cutout_handler(geom=geo)
|
||||
else:
|
||||
try:
|
||||
|
@ -603,7 +624,11 @@ class CutOut(FlatCAMTool):
|
|||
|
||||
for geom_struct in object_geo:
|
||||
if isinstance(cutout_obj, FlatCAMGerber):
|
||||
geom_struct = (geom_struct.buffer(margin + abs(dia / 2))).exterior
|
||||
if margin >= 0:
|
||||
geom_struct = (geom_struct.buffer(margin + abs(dia / 2))).exterior
|
||||
else:
|
||||
geom_struct_buff = geom_struct.buffer(-margin + abs(dia / 2))
|
||||
geom_struct = geom_struct_buff.interiors
|
||||
|
||||
solid_geo += cutout_handler(geom=geom_struct)
|
||||
|
||||
|
@ -623,7 +648,7 @@ class CutOut(FlatCAMTool):
|
|||
|
||||
cutout_obj.plot()
|
||||
self.app.inform.emit('[success] %s' % _("Any form CutOut operation finished."))
|
||||
self.app.ui.notebook.setCurrentWidget(self.app.ui.project_tab)
|
||||
# self.app.ui.notebook.setCurrentWidget(self.app.ui.project_tab)
|
||||
self.app.should_we_save = True
|
||||
|
||||
def on_rectangular_cutout(self):
|
||||
|
@ -751,24 +776,43 @@ class CutOut(FlatCAMTool):
|
|||
# if Gerber create a buffer at a distance
|
||||
# if Geometry then cut through the geometry
|
||||
if isinstance(cutout_obj, FlatCAMGerber):
|
||||
geo = geo.buffer(margin + abs(dia / 2))
|
||||
if margin >= 0:
|
||||
geo = geo.buffer(margin + abs(dia / 2))
|
||||
else:
|
||||
geo = geo.buffer(margin - abs(dia / 2))
|
||||
|
||||
solid_geo = cutout_rect_handler(geom=geo)
|
||||
else:
|
||||
try:
|
||||
__ = iter(object_geo)
|
||||
except TypeError:
|
||||
object_geo = [object_geo]
|
||||
if cutout_obj.kind == 'geometry':
|
||||
try:
|
||||
__ = iter(object_geo)
|
||||
except TypeError:
|
||||
object_geo = [object_geo]
|
||||
|
||||
for geom_struct in object_geo:
|
||||
geom_struct = unary_union(geom_struct)
|
||||
xmin, ymin, xmax, ymax = geom_struct.bounds
|
||||
geom_struct = box(xmin, ymin, xmax, ymax)
|
||||
for geom_struct in object_geo:
|
||||
geom_struct = unary_union(geom_struct)
|
||||
xmin, ymin, xmax, ymax = geom_struct.bounds
|
||||
geom_struct = box(xmin, ymin, xmax, ymax)
|
||||
|
||||
solid_geo += cutout_rect_handler(geom=geom_struct)
|
||||
elif cutout_obj.kind == 'gerber' and margin >= 0:
|
||||
try:
|
||||
__ = iter(object_geo)
|
||||
except TypeError:
|
||||
object_geo = [object_geo]
|
||||
|
||||
for geom_struct in object_geo:
|
||||
geom_struct = unary_union(geom_struct)
|
||||
xmin, ymin, xmax, ymax = geom_struct.bounds
|
||||
geom_struct = box(xmin, ymin, xmax, ymax)
|
||||
|
||||
if isinstance(cutout_obj, FlatCAMGerber):
|
||||
geom_struct = geom_struct.buffer(margin + abs(dia / 2))
|
||||
|
||||
solid_geo += cutout_rect_handler(geom=geom_struct)
|
||||
solid_geo += cutout_rect_handler(geom=geom_struct)
|
||||
elif cutout_obj.kind == 'gerber' and margin < 0:
|
||||
self.app.inform.emit('[WARNING_NOTCL] %s' %
|
||||
_("Rectangular cutout with negative margin is not possible."))
|
||||
return "fail"
|
||||
|
||||
geo_obj.solid_geometry = deepcopy(solid_geo)
|
||||
geo_obj.options['cnctooldia'] = str(dia)
|
||||
|
@ -777,12 +821,12 @@ class CutOut(FlatCAMTool):
|
|||
geo_obj.options['depthperpass'] = self.maxdepth_entry.get_value()
|
||||
|
||||
outname = cutout_obj.options["name"] + "_cutout"
|
||||
self.app.new_object('geometry', outname, geo_init)
|
||||
ret = self.app.new_object('geometry', outname, geo_init)
|
||||
|
||||
# cutout_obj.plot()
|
||||
self.app.inform.emit('[success] %s' %
|
||||
_("Any form CutOut operation finished."))
|
||||
self.app.ui.notebook.setCurrentWidget(self.app.ui.project_tab)
|
||||
if ret != 'fail':
|
||||
# cutout_obj.plot()
|
||||
self.app.inform.emit('[success] %s' % _("Any form CutOut operation finished."))
|
||||
# self.app.ui.notebook.setCurrentWidget(self.app.ui.project_tab)
|
||||
self.app.should_we_save = True
|
||||
|
||||
def on_manual_gap_click(self):
|
||||
|
@ -923,6 +967,9 @@ class CutOut(FlatCAMTool):
|
|||
self.app.new_object('geometry', outname, geo_init)
|
||||
|
||||
def cutting_geo(self, pos):
|
||||
self.cutting_dia = float(self.dia.get_value())
|
||||
self.cutting_gapsize = float(self.gapsize.get_value())
|
||||
|
||||
offset = self.cutting_dia / 2 + self.cutting_gapsize / 2
|
||||
|
||||
# cutting area definition
|
||||
|
@ -1018,7 +1065,7 @@ class CutOut(FlatCAMTool):
|
|||
except TypeError:
|
||||
return
|
||||
|
||||
if self.app.grid_status() == True:
|
||||
if self.app.grid_status():
|
||||
snap_x, snap_y = self.app.geo_editor.snap(x, y)
|
||||
else:
|
||||
snap_x, snap_y = x, y
|
||||
|
@ -1048,7 +1095,7 @@ class CutOut(FlatCAMTool):
|
|||
else:
|
||||
radian = math.atan(dx / dy)
|
||||
angle = radian * 180 / math.pi
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
angle = 0
|
||||
return angle
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
from PyQt5 import QtWidgets, QtCore
|
||||
|
||||
from FlatCAMTool import FlatCAMTool
|
||||
from flatcamGUI.GUIElements import RadioSet, FCDoubleSpinner, EvalEntry, FCEntry
|
||||
from flatcamGUI.GUIElements import RadioSet, FCDoubleSpinner, EvalEntry, FCEntry, FCButton, FCComboBox
|
||||
from FlatCAMObj import FlatCAMGerber, FlatCAMExcellon, FlatCAMGeometry
|
||||
|
||||
from numpy import Inf
|
||||
|
@ -41,22 +41,28 @@ class DblSidedTool(FlatCAMTool):
|
|||
""")
|
||||
self.layout.addWidget(title_label)
|
||||
|
||||
self.empty_lb = QtWidgets.QLabel("")
|
||||
self.layout.addWidget(self.empty_lb)
|
||||
self.layout.addWidget(QtWidgets.QLabel(""))
|
||||
|
||||
# ## Grid Layout
|
||||
grid_lay = QtWidgets.QGridLayout()
|
||||
self.layout.addLayout(grid_lay)
|
||||
grid_lay.setColumnStretch(0, 1)
|
||||
grid_lay.setColumnStretch(1, 0)
|
||||
self.layout.addLayout(grid_lay)
|
||||
|
||||
# Objects to be mirrored
|
||||
self.m_objects_label = QtWidgets.QLabel("<b>%s:</b>" % _("Mirror Operation"))
|
||||
self.m_objects_label.setToolTip('%s.' % _("Objects to be mirrored"))
|
||||
|
||||
grid_lay.addWidget(self.m_objects_label, 0, 0, 1, 2)
|
||||
|
||||
# ## Gerber Object to mirror
|
||||
self.gerber_object_combo = QtWidgets.QComboBox()
|
||||
self.gerber_object_combo = FCComboBox()
|
||||
self.gerber_object_combo.setModel(self.app.collection)
|
||||
self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.gerber_object_combo.setCurrentIndex(1)
|
||||
self.gerber_object_combo.is_last = True
|
||||
self.gerber_object_combo.obj_type = "Gerber"
|
||||
|
||||
self.botlay_label = QtWidgets.QLabel("<b>%s:</b>" % _("GERBER"))
|
||||
self.botlay_label = QtWidgets.QLabel("%s:" % _("GERBER"))
|
||||
self.botlay_label.setToolTip('%s.' % _("Gerber to be mirrored"))
|
||||
|
||||
self.mirror_gerber_button = QtWidgets.QPushButton(_("Mirror"))
|
||||
|
@ -73,18 +79,18 @@ class DblSidedTool(FlatCAMTool):
|
|||
""")
|
||||
self.mirror_gerber_button.setMinimumWidth(60)
|
||||
|
||||
# grid_lay.addRow("Bottom Layer:", self.object_combo)
|
||||
grid_lay.addWidget(self.botlay_label, 0, 0)
|
||||
grid_lay.addWidget(self.gerber_object_combo, 1, 0)
|
||||
grid_lay.addWidget(self.mirror_gerber_button, 1, 1)
|
||||
grid_lay.addWidget(self.botlay_label, 1, 0)
|
||||
grid_lay.addWidget(self.gerber_object_combo, 2, 0)
|
||||
grid_lay.addWidget(self.mirror_gerber_button, 2, 1)
|
||||
|
||||
# ## Excellon Object to mirror
|
||||
self.exc_object_combo = QtWidgets.QComboBox()
|
||||
self.exc_object_combo = FCComboBox()
|
||||
self.exc_object_combo.setModel(self.app.collection)
|
||||
self.exc_object_combo.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
|
||||
self.exc_object_combo.setCurrentIndex(1)
|
||||
self.exc_object_combo.is_last = True
|
||||
self.exc_object_combo.obj_type = "Excellon"
|
||||
|
||||
self.excobj_label = QtWidgets.QLabel("<b>%s:</b>" % _("EXCELLON"))
|
||||
self.excobj_label = QtWidgets.QLabel("%s:" % _("EXCELLON"))
|
||||
self.excobj_label.setToolTip(_("Excellon Object to be mirrored."))
|
||||
|
||||
self.mirror_exc_button = QtWidgets.QPushButton(_("Mirror"))
|
||||
|
@ -101,18 +107,18 @@ class DblSidedTool(FlatCAMTool):
|
|||
""")
|
||||
self.mirror_exc_button.setMinimumWidth(60)
|
||||
|
||||
# grid_lay.addRow("Bottom Layer:", self.object_combo)
|
||||
grid_lay.addWidget(self.excobj_label, 2, 0)
|
||||
grid_lay.addWidget(self.exc_object_combo, 3, 0)
|
||||
grid_lay.addWidget(self.mirror_exc_button, 3, 1)
|
||||
grid_lay.addWidget(self.excobj_label, 3, 0)
|
||||
grid_lay.addWidget(self.exc_object_combo, 4, 0)
|
||||
grid_lay.addWidget(self.mirror_exc_button, 4, 1)
|
||||
|
||||
# ## Geometry Object to mirror
|
||||
self.geo_object_combo = QtWidgets.QComboBox()
|
||||
self.geo_object_combo = FCComboBox()
|
||||
self.geo_object_combo.setModel(self.app.collection)
|
||||
self.geo_object_combo.setRootModelIndex(self.app.collection.index(2, 0, QtCore.QModelIndex()))
|
||||
self.geo_object_combo.setCurrentIndex(1)
|
||||
self.geo_object_combo.is_last = True
|
||||
self.geo_object_combo.obj_type = "Geometry"
|
||||
|
||||
self.geoobj_label = QtWidgets.QLabel("<b>%s</b>:" % _("GEOMETRY"))
|
||||
self.geoobj_label = QtWidgets.QLabel("%s:" % _("GEOMETRY"))
|
||||
self.geoobj_label.setToolTip(
|
||||
_("Geometry Obj to be mirrored.")
|
||||
)
|
||||
|
@ -132,161 +138,315 @@ class DblSidedTool(FlatCAMTool):
|
|||
self.mirror_geo_button.setMinimumWidth(60)
|
||||
|
||||
# grid_lay.addRow("Bottom Layer:", self.object_combo)
|
||||
grid_lay.addWidget(self.geoobj_label, 4, 0)
|
||||
grid_lay.addWidget(self.geo_object_combo, 5, 0)
|
||||
grid_lay.addWidget(self.mirror_geo_button, 5, 1)
|
||||
grid_lay.addWidget(self.geoobj_label, 5, 0)
|
||||
grid_lay.addWidget(self.geo_object_combo, 6, 0)
|
||||
grid_lay.addWidget(self.mirror_geo_button, 6, 1)
|
||||
|
||||
separator_line = QtWidgets.QFrame()
|
||||
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
grid_lay.addWidget(separator_line, 7, 0, 1, 2)
|
||||
|
||||
self.layout.addWidget(QtWidgets.QLabel(""))
|
||||
|
||||
# ## Grid Layout
|
||||
grid_lay1 = QtWidgets.QGridLayout()
|
||||
grid_lay1.setColumnStretch(0, 0)
|
||||
grid_lay1.setColumnStretch(1, 1)
|
||||
self.layout.addLayout(grid_lay1)
|
||||
|
||||
# Objects to be mirrored
|
||||
self.param_label = QtWidgets.QLabel("<b>%s:</b>" % _("Mirror Parameters"))
|
||||
self.param_label.setToolTip('%s.' % _("Parameters for the mirror operation"))
|
||||
|
||||
grid_lay1.addWidget(self.param_label, 0, 0, 1, 3)
|
||||
|
||||
# ## Axis
|
||||
self.mirax_label = QtWidgets.QLabel('%s:' % _("Mirror Axis"))
|
||||
self.mirax_label.setToolTip(_("Mirror vertically (X) or horizontally (Y)."))
|
||||
self.mirror_axis = RadioSet([{'label': 'X', 'value': 'X'},
|
||||
{'label': 'Y', 'value': 'Y'}])
|
||||
self.mirax_label = QtWidgets.QLabel(_("Mirror Axis:"))
|
||||
self.mirax_label.setToolTip(_("Mirror vertically (X) or horizontally (Y)."))
|
||||
|
||||
# grid_lay.addRow("Mirror Axis:", self.mirror_axis)
|
||||
self.empty_lb1 = QtWidgets.QLabel("")
|
||||
grid_lay1.addWidget(self.empty_lb1, 6, 0)
|
||||
grid_lay1.addWidget(self.mirax_label, 7, 0)
|
||||
grid_lay1.addWidget(self.mirror_axis, 7, 1)
|
||||
grid_lay1.addWidget(self.mirax_label, 2, 0)
|
||||
grid_lay1.addWidget(self.mirror_axis, 2, 1, 1, 2)
|
||||
|
||||
# ## Axis Location
|
||||
self.axloc_label = QtWidgets.QLabel('%s:' % _("Reference"))
|
||||
self.axloc_label.setToolTip(
|
||||
_("The coordinates used as reference for the mirror operation.\n"
|
||||
"Can be:\n"
|
||||
"- Point -> a set of coordinates (x,y) around which the object is mirrored\n"
|
||||
"- Box -> a set of coordinates (x, y) obtained from the center of the\n"
|
||||
"bounding box of another object selected below")
|
||||
)
|
||||
self.axis_location = RadioSet([{'label': _('Point'), 'value': 'point'},
|
||||
{'label': _('Box'), 'value': 'box'}])
|
||||
self.axloc_label = QtWidgets.QLabel('%s:' % _("Axis Ref"))
|
||||
self.axloc_label.setToolTip(
|
||||
_("The axis should pass through a <b>point</b> or cut\n "
|
||||
"a specified <b>box</b> (in a FlatCAM object) through \n"
|
||||
"the center.")
|
||||
)
|
||||
# grid_lay.addRow("Axis Location:", self.axis_location)
|
||||
grid_lay1.addWidget(self.axloc_label, 8, 0)
|
||||
grid_lay1.addWidget(self.axis_location, 8, 1)
|
||||
|
||||
self.empty_lb2 = QtWidgets.QLabel("")
|
||||
grid_lay1.addWidget(self.empty_lb2, 9, 0)
|
||||
|
||||
# ## Grid Layout
|
||||
grid_lay2 = QtWidgets.QGridLayout()
|
||||
self.layout.addLayout(grid_lay2)
|
||||
grid_lay2.setColumnStretch(0, 1)
|
||||
grid_lay2.setColumnStretch(1, 0)
|
||||
grid_lay1.addWidget(self.axloc_label, 4, 0)
|
||||
grid_lay1.addWidget(self.axis_location, 4, 1, 1, 2)
|
||||
|
||||
# ## Point/Box
|
||||
self.point_box_container = QtWidgets.QVBoxLayout()
|
||||
self.pb_label = QtWidgets.QLabel("<b>%s:</b>" % _('Point/Box Reference'))
|
||||
self.pb_label.setToolTip(
|
||||
_("If 'Point' is selected above it store the coordinates (x, y) through which\n"
|
||||
"the mirroring axis passes.\n"
|
||||
"If 'Box' is selected above, select here a FlatCAM object (Gerber, Exc or Geo).\n"
|
||||
"Through the center of this object pass the mirroring axis selected above.")
|
||||
)
|
||||
self.point_entry = EvalEntry()
|
||||
|
||||
# Add a reference
|
||||
self.add_point_button = QtWidgets.QPushButton(_("Add"))
|
||||
self.add_point_button.setToolTip(
|
||||
_("Add the coordinates in format <b>(x, y)</b> through which the mirroring axis \n "
|
||||
"selected in 'MIRROR AXIS' pass.\n"
|
||||
"The (x, y) coordinates are captured by pressing SHIFT key\n"
|
||||
"and left mouse button click on canvas or you can enter the coords manually.")
|
||||
"and left mouse button click on canvas or you can enter the coordinates manually.")
|
||||
)
|
||||
self.add_point_button.setStyleSheet("""
|
||||
QPushButton
|
||||
{
|
||||
font-weight: bold;
|
||||
}
|
||||
""")
|
||||
QPushButton
|
||||
{
|
||||
font-weight: bold;
|
||||
}
|
||||
""")
|
||||
self.add_point_button.setMinimumWidth(60)
|
||||
|
||||
grid_lay2.addWidget(self.pb_label, 10, 0)
|
||||
grid_lay2.addLayout(self.point_box_container, 11, 0)
|
||||
grid_lay2.addWidget(self.add_point_button, 11, 1)
|
||||
grid_lay1.addWidget(self.point_entry, 7, 0, 1, 2)
|
||||
grid_lay1.addWidget(self.add_point_button, 7, 2)
|
||||
|
||||
self.point_entry = EvalEntry()
|
||||
self.point_box_container.addWidget(self.point_entry)
|
||||
# ## Grid Layout
|
||||
grid_lay2 = QtWidgets.QGridLayout()
|
||||
grid_lay2.setColumnStretch(0, 0)
|
||||
grid_lay2.setColumnStretch(1, 1)
|
||||
self.layout.addLayout(grid_lay2)
|
||||
|
||||
self.box_combo = QtWidgets.QComboBox()
|
||||
self.box_type_label = QtWidgets.QLabel('%s:' % _("Reference Object"))
|
||||
self.box_type_label.setToolTip(
|
||||
_("It can be of type: Gerber or Excellon or Geometry.\n"
|
||||
"The coordinates of the center of the bounding box are used\n"
|
||||
"as reference for mirror operation.")
|
||||
)
|
||||
|
||||
# Type of object used as BOX reference
|
||||
self.box_type_radio = RadioSet([{'label': _('Gerber'), 'value': 'grb'},
|
||||
{'label': _('Excellon'), 'value': 'exc'},
|
||||
{'label': _('Geometry'), 'value': 'geo'}])
|
||||
|
||||
self.box_type_label.hide()
|
||||
self.box_type_radio.hide()
|
||||
|
||||
grid_lay2.addWidget(self.box_type_label, 0, 0, 1, 2)
|
||||
grid_lay2.addWidget(self.box_type_radio, 1, 0, 1, 2)
|
||||
|
||||
# Object used as BOX reference
|
||||
self.box_combo = FCComboBox()
|
||||
self.box_combo.setModel(self.app.collection)
|
||||
self.box_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.box_combo.setCurrentIndex(1)
|
||||
self.box_combo.is_last = True
|
||||
|
||||
self.box_combo_type = QtWidgets.QComboBox()
|
||||
self.box_combo_type.addItem(_("Reference Gerber"))
|
||||
self.box_combo_type.addItem(_("Reference Excellon"))
|
||||
self.box_combo_type.addItem(_("Reference Geometry"))
|
||||
|
||||
self.point_box_container.addWidget(self.box_combo_type)
|
||||
self.point_box_container.addWidget(self.box_combo)
|
||||
self.box_combo.hide()
|
||||
self.box_combo_type.hide()
|
||||
|
||||
grid_lay2.addWidget(self.box_combo, 3, 0, 1, 2)
|
||||
|
||||
separator_line = QtWidgets.QFrame()
|
||||
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
grid_lay2.addWidget(separator_line, 12, 0, 1, 2)
|
||||
grid_lay2.addWidget(separator_line, 4, 0, 1, 2)
|
||||
|
||||
grid_lay2.addWidget(QtWidgets.QLabel(""), 5, 0, 1, 2)
|
||||
|
||||
# ## Title Bounds Values
|
||||
self.bv_label = QtWidgets.QLabel("<b>%s:</b>" % _('Bounds Values'))
|
||||
self.bv_label.setToolTip(
|
||||
_("Select on canvas the object(s)\n"
|
||||
"for which to calculate bounds values.")
|
||||
)
|
||||
grid_lay2.addWidget(self.bv_label, 6, 0, 1, 2)
|
||||
|
||||
# Xmin value
|
||||
self.xmin_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.xmin_entry.set_precision(self.decimals)
|
||||
self.xmin_entry.set_range(-9999.9999, 9999.9999)
|
||||
|
||||
self.xmin_btn = FCButton('%s:' % _("X min"))
|
||||
self.xmin_btn.setToolTip(
|
||||
_("Minimum location.")
|
||||
)
|
||||
self.xmin_entry.setReadOnly(True)
|
||||
|
||||
grid_lay2.addWidget(self.xmin_btn, 7, 0)
|
||||
grid_lay2.addWidget(self.xmin_entry, 7, 1)
|
||||
|
||||
# Ymin value
|
||||
self.ymin_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.ymin_entry.set_precision(self.decimals)
|
||||
self.ymin_entry.set_range(-9999.9999, 9999.9999)
|
||||
|
||||
self.ymin_btn = FCButton('%s:' % _("Y min"))
|
||||
self.ymin_btn.setToolTip(
|
||||
_("Minimum location.")
|
||||
)
|
||||
self.ymin_entry.setReadOnly(True)
|
||||
|
||||
grid_lay2.addWidget(self.ymin_btn, 8, 0)
|
||||
grid_lay2.addWidget(self.ymin_entry, 8, 1)
|
||||
|
||||
# Xmax value
|
||||
self.xmax_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.xmax_entry.set_precision(self.decimals)
|
||||
self.xmax_entry.set_range(-9999.9999, 9999.9999)
|
||||
|
||||
self.xmax_btn = FCButton('%s:' % _("X max"))
|
||||
self.xmax_btn.setToolTip(
|
||||
_("Maximum location.")
|
||||
)
|
||||
self.xmax_entry.setReadOnly(True)
|
||||
|
||||
grid_lay2.addWidget(self.xmax_btn, 9, 0)
|
||||
grid_lay2.addWidget(self.xmax_entry, 9, 1)
|
||||
|
||||
# Ymax value
|
||||
self.ymax_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.ymax_entry.set_precision(self.decimals)
|
||||
self.ymax_entry.set_range(-9999.9999, 9999.9999)
|
||||
|
||||
self.ymax_btn = FCButton('%s:' % _("Y max"))
|
||||
self.ymax_btn.setToolTip(
|
||||
_("Maximum location.")
|
||||
)
|
||||
self.ymax_entry.setReadOnly(True)
|
||||
|
||||
grid_lay2.addWidget(self.ymax_btn, 10, 0)
|
||||
grid_lay2.addWidget(self.ymax_entry, 10, 1)
|
||||
|
||||
# Center point value
|
||||
self.center_entry = FCEntry()
|
||||
|
||||
self.center_btn = FCButton('%s:' % _("Centroid"))
|
||||
self.center_btn.setToolTip(
|
||||
_("The center point location for the rectangular\n"
|
||||
"bounding shape. Centroid. Format is (x, y).")
|
||||
)
|
||||
self.center_entry.setReadOnly(True)
|
||||
|
||||
grid_lay2.addWidget(self.center_btn, 12, 0)
|
||||
grid_lay2.addWidget(self.center_entry, 12, 1)
|
||||
|
||||
# Calculate Bounding box
|
||||
self.calculate_bb_button = QtWidgets.QPushButton(_("Calculate Bounds Values"))
|
||||
self.calculate_bb_button.setToolTip(
|
||||
_("Calculate the enveloping rectangular shape coordinates,\n"
|
||||
"for the selection of objects.\n"
|
||||
"The envelope shape is parallel with the X, Y axis.")
|
||||
)
|
||||
self.calculate_bb_button.setStyleSheet("""
|
||||
QPushButton
|
||||
{
|
||||
font-weight: bold;
|
||||
}
|
||||
""")
|
||||
grid_lay2.addWidget(self.calculate_bb_button, 13, 0, 1, 2)
|
||||
|
||||
separator_line = QtWidgets.QFrame()
|
||||
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
grid_lay2.addWidget(separator_line, 14, 0, 1, 2)
|
||||
|
||||
grid_lay2.addWidget(QtWidgets.QLabel(""), 15, 0, 1, 2)
|
||||
|
||||
# ## Alignment holes
|
||||
self.ah_label = QtWidgets.QLabel("<b>%s:</b>" % _('Alignment Drill Coordinates'))
|
||||
self.alignment_label = QtWidgets.QLabel("<b>%s:</b>" % _('PCB Alignment'))
|
||||
self.alignment_label.setToolTip(
|
||||
_("Creates an Excellon Object containing the\n"
|
||||
"specified alignment holes and their mirror\n"
|
||||
"images.")
|
||||
)
|
||||
grid_lay2.addWidget(self.alignment_label, 25, 0, 1, 2)
|
||||
|
||||
# ## Drill diameter for alignment holes
|
||||
self.dt_label = QtWidgets.QLabel("%s:" % _('Drill Diameter'))
|
||||
self.dt_label.setToolTip(
|
||||
_("Diameter of the drill for the alignment holes.")
|
||||
)
|
||||
|
||||
self.drill_dia = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.drill_dia.setToolTip(
|
||||
_("Diameter of the drill for the alignment holes.")
|
||||
)
|
||||
self.drill_dia.set_precision(self.decimals)
|
||||
self.drill_dia.set_range(0.0000, 9999.9999)
|
||||
|
||||
grid_lay2.addWidget(self.dt_label, 26, 0)
|
||||
grid_lay2.addWidget(self.drill_dia, 26, 1)
|
||||
|
||||
# ## Alignment Axis
|
||||
self.align_ax_label = QtWidgets.QLabel('%s:' % _("Align Axis"))
|
||||
self.align_ax_label.setToolTip(
|
||||
_("Mirror vertically (X) or horizontally (Y).")
|
||||
)
|
||||
self.align_axis_radio = RadioSet([{'label': 'X', 'value': 'X'},
|
||||
{'label': 'Y', 'value': 'Y'}])
|
||||
|
||||
grid_lay2.addWidget(self.align_ax_label, 27, 0)
|
||||
grid_lay2.addWidget(self.align_axis_radio, 27, 1)
|
||||
|
||||
# ## Alignment Reference Point
|
||||
self.align_ref_label = QtWidgets.QLabel('%s:' % _("Reference"))
|
||||
self.align_ref_label.setToolTip(
|
||||
_("The reference point used to create the second alignment drill\n"
|
||||
"from the first alignment drill, by doing mirror.\n"
|
||||
"It can be modified in the Mirror Parameters -> Reference section")
|
||||
)
|
||||
|
||||
self.align_ref_label_val = EvalEntry()
|
||||
self.align_ref_label_val.setToolTip(
|
||||
_("The reference point used to create the second alignment drill\n"
|
||||
"from the first alignment drill, by doing mirror.\n"
|
||||
"It can be modified in the Mirror Parameters -> Reference section")
|
||||
)
|
||||
self.align_ref_label_val.setDisabled(True)
|
||||
|
||||
grid_lay2.addWidget(self.align_ref_label, 28, 0)
|
||||
grid_lay2.addWidget(self.align_ref_label_val, 28, 1)
|
||||
|
||||
grid_lay4 = QtWidgets.QGridLayout()
|
||||
self.layout.addLayout(grid_lay4)
|
||||
|
||||
# ## Alignment holes
|
||||
self.ah_label = QtWidgets.QLabel("%s:" % _('Alignment Drill Coordinates'))
|
||||
self.ah_label.setToolTip(
|
||||
_("Alignment holes (x1, y1), (x2, y2), ... "
|
||||
"on one side of the mirror axis. For each set of (x, y) coordinates\n"
|
||||
"entered here, a pair of drills will be created:\n\n"
|
||||
"- one drill at the coordinates from the field\n"
|
||||
"- one drill in mirror position over the axis selected above in the 'Mirror Axis'.")
|
||||
"- one drill in mirror position over the axis selected above in the 'Align Axis'.")
|
||||
)
|
||||
self.layout.addWidget(self.ah_label)
|
||||
|
||||
grid_lay3 = QtWidgets.QGridLayout()
|
||||
self.layout.addLayout(grid_lay3)
|
||||
|
||||
self.alignment_holes = EvalEntry()
|
||||
|
||||
self.add_drill_point_button = QtWidgets.QPushButton(_("Add"))
|
||||
grid_lay4.addWidget(self.ah_label, 0, 0, 1, 2)
|
||||
grid_lay4.addWidget(self.alignment_holes, 1, 0, 1, 2)
|
||||
|
||||
self.add_drill_point_button = FCButton(_("Add"))
|
||||
self.add_drill_point_button.setToolTip(
|
||||
_("Add alignment drill holes coords in the format: (x1, y1), (x2, y2), ... \n"
|
||||
"on one side of the mirror axis.\n\n"
|
||||
_("Add alignment drill holes coordinates in the format: (x1, y1), (x2, y2), ... \n"
|
||||
"on one side of the alignment axis.\n\n"
|
||||
"The coordinates set can be obtained:\n"
|
||||
"- press SHIFT key and left mouse clicking on canvas. Then click Add.\n"
|
||||
"- press SHIFT key and left mouse clicking on canvas. Then CTRL+V in the field.\n"
|
||||
"- press SHIFT key and left mouse clicking on canvas. Then RMB click in the field and click Paste.\n"
|
||||
"- by entering the coords manually in the format: (x1, y1), (x2, y2), ...")
|
||||
)
|
||||
self.add_drill_point_button.setStyleSheet("""
|
||||
QPushButton
|
||||
{
|
||||
font-weight: bold;
|
||||
}
|
||||
""")
|
||||
self.add_drill_point_button.setMinimumWidth(60)
|
||||
# self.add_drill_point_button.setStyleSheet("""
|
||||
# QPushButton
|
||||
# {
|
||||
# font-weight: bold;
|
||||
# }
|
||||
# """)
|
||||
|
||||
grid_lay3.addWidget(self.alignment_holes, 0, 0)
|
||||
grid_lay3.addWidget(self.add_drill_point_button, 0, 1)
|
||||
|
||||
grid0 = QtWidgets.QGridLayout()
|
||||
self.layout.addLayout(grid0)
|
||||
grid0.setColumnStretch(0, 0)
|
||||
grid0.setColumnStretch(1, 1)
|
||||
|
||||
# ## Drill diameter for alignment holes
|
||||
self.dt_label = QtWidgets.QLabel("<b>%s:</b>" % _('Alignment Drill Diameter'))
|
||||
self.dt_label.setToolTip(
|
||||
_("Diameter of the drill for the "
|
||||
"alignment holes.")
|
||||
self.delete_drill_point_button = FCButton(_("Delete Last"))
|
||||
self.delete_drill_point_button.setToolTip(
|
||||
_("Delete the last coordinates tuple in the list.")
|
||||
)
|
||||
grid0.addWidget(self.dt_label, 0, 0, 1, 2)
|
||||
drill_hlay = QtWidgets.QHBoxLayout()
|
||||
|
||||
# Drill diameter value
|
||||
self.drill_dia = FCDoubleSpinner()
|
||||
self.drill_dia.set_precision(self.decimals)
|
||||
self.drill_dia.set_range(0.0000, 9999.9999)
|
||||
drill_hlay.addWidget(self.add_drill_point_button)
|
||||
drill_hlay.addWidget(self.delete_drill_point_button)
|
||||
|
||||
self.drill_dia.setToolTip(
|
||||
_("Diameter of the drill for the "
|
||||
"alignment holes.")
|
||||
)
|
||||
|
||||
grid0.addWidget(self.drill_dia, 1, 0, 1, 2)
|
||||
grid_lay4.addLayout(drill_hlay, 2, 0, 1, 2)
|
||||
|
||||
# ## Buttons
|
||||
self.create_alignment_hole_button = QtWidgets.QPushButton(_("Create Excellon Object"))
|
||||
|
@ -303,102 +463,6 @@ class DblSidedTool(FlatCAMTool):
|
|||
""")
|
||||
self.layout.addWidget(self.create_alignment_hole_button)
|
||||
|
||||
separator_line = QtWidgets.QFrame()
|
||||
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
self.layout.addWidget(separator_line)
|
||||
|
||||
self.layout.addWidget(QtWidgets.QLabel(''))
|
||||
|
||||
grid1 = QtWidgets.QGridLayout()
|
||||
self.layout.addLayout(grid1)
|
||||
grid1.setColumnStretch(0, 0)
|
||||
grid1.setColumnStretch(1, 1)
|
||||
|
||||
# Xmin value
|
||||
self.xmin_entry = FCDoubleSpinner()
|
||||
self.xmin_entry.set_precision(self.decimals)
|
||||
self.xmin_entry.set_range(-9999.9999, 9999.9999)
|
||||
|
||||
self.xmin_label = QtWidgets.QLabel('%s:' % _("X min"))
|
||||
self.xmin_label.setToolTip(
|
||||
_("Minimum location.")
|
||||
)
|
||||
self.xmin_entry.setReadOnly(True)
|
||||
|
||||
grid1.addWidget(self.xmin_label, 1, 0)
|
||||
grid1.addWidget(self.xmin_entry, 1, 1)
|
||||
|
||||
# Ymin value
|
||||
self.ymin_entry = FCDoubleSpinner()
|
||||
self.ymin_entry.set_precision(self.decimals)
|
||||
self.ymin_entry.set_range(-9999.9999, 9999.9999)
|
||||
|
||||
self.ymin_label = QtWidgets.QLabel('%s:' % _("Y min"))
|
||||
self.ymin_label.setToolTip(
|
||||
_("Minimum location.")
|
||||
)
|
||||
self.ymin_entry.setReadOnly(True)
|
||||
|
||||
grid1.addWidget(self.ymin_label, 2, 0)
|
||||
grid1.addWidget(self.ymin_entry, 2, 1)
|
||||
|
||||
# Xmax value
|
||||
self.xmax_entry = FCDoubleSpinner()
|
||||
self.xmax_entry.set_precision(self.decimals)
|
||||
self.xmax_entry.set_range(-9999.9999, 9999.9999)
|
||||
|
||||
self.xmax_label = QtWidgets.QLabel('%s:' % _("X max"))
|
||||
self.xmax_label.setToolTip(
|
||||
_("Maximum location.")
|
||||
)
|
||||
self.xmax_entry.setReadOnly(True)
|
||||
|
||||
grid1.addWidget(self.xmax_label, 3, 0)
|
||||
grid1.addWidget(self.xmax_entry, 3, 1)
|
||||
|
||||
# Ymax value
|
||||
self.ymax_entry = FCDoubleSpinner()
|
||||
self.ymax_entry.set_precision(self.decimals)
|
||||
self.ymax_entry.set_range(-9999.9999, 9999.9999)
|
||||
|
||||
self.ymax_label = QtWidgets.QLabel('%s:' % _("Y max"))
|
||||
self.ymax_label.setToolTip(
|
||||
_("Maximum location.")
|
||||
)
|
||||
self.ymax_entry.setReadOnly(True)
|
||||
|
||||
grid1.addWidget(self.ymax_label, 4, 0)
|
||||
grid1.addWidget(self.ymax_entry, 4, 1)
|
||||
|
||||
# Center point value
|
||||
self.center_entry = FCEntry()
|
||||
|
||||
self.center_label = QtWidgets.QLabel('%s:' % _("Centroid"))
|
||||
self.center_label.setToolTip(
|
||||
_("The center point location for the rectangular\n"
|
||||
"bounding shape. Centroid. Format is (x, y).")
|
||||
)
|
||||
self.center_entry.setReadOnly(True)
|
||||
|
||||
grid1.addWidget(self.center_label, 5, 0)
|
||||
grid1.addWidget(self.center_entry, 5, 1)
|
||||
|
||||
# Calculate Bounding box
|
||||
self.calculate_bb_button = QtWidgets.QPushButton(_("Calculate Bounds Values"))
|
||||
self.calculate_bb_button.setToolTip(
|
||||
_("Calculate the enveloping rectangular shape coordinates,\n"
|
||||
"for the selection of objects.\n"
|
||||
"The envelope shape is parallel with the X, Y axis.")
|
||||
)
|
||||
self.calculate_bb_button.setStyleSheet("""
|
||||
QPushButton
|
||||
{
|
||||
font-weight: bold;
|
||||
}
|
||||
""")
|
||||
self.layout.addWidget(self.calculate_bb_button)
|
||||
|
||||
self.layout.addStretch()
|
||||
|
||||
# ## Reset Tool
|
||||
|
@ -418,12 +482,26 @@ class DblSidedTool(FlatCAMTool):
|
|||
self.mirror_gerber_button.clicked.connect(self.on_mirror_gerber)
|
||||
self.mirror_exc_button.clicked.connect(self.on_mirror_exc)
|
||||
self.mirror_geo_button.clicked.connect(self.on_mirror_geo)
|
||||
|
||||
self.add_point_button.clicked.connect(self.on_point_add)
|
||||
self.add_drill_point_button.clicked.connect(self.on_drill_add)
|
||||
self.box_combo_type.currentIndexChanged.connect(self.on_combo_box_type)
|
||||
self.delete_drill_point_button.clicked.connect(self.on_drill_delete_last)
|
||||
self.box_type_radio.activated_custom.connect(self.on_combo_box_type)
|
||||
|
||||
self.axis_location.group_toggle_fn = self.on_toggle_pointbox
|
||||
|
||||
self.point_entry.textChanged.connect(lambda val: self.align_ref_label_val.set_value(val))
|
||||
|
||||
self.xmin_btn.clicked.connect(self.on_xmin_clicked)
|
||||
self.ymin_btn.clicked.connect(self.on_ymin_clicked)
|
||||
self.xmax_btn.clicked.connect(self.on_xmax_clicked)
|
||||
self.ymax_btn.clicked.connect(self.on_ymax_clicked)
|
||||
|
||||
self.center_btn.clicked.connect(
|
||||
lambda: self.point_entry.set_value(self.center_entry.get_value())
|
||||
)
|
||||
|
||||
|
||||
self.create_alignment_hole_button.clicked.connect(self.on_create_alignment_holes)
|
||||
self.calculate_bb_button.clicked.connect(self.on_bbox_coordinates)
|
||||
|
||||
|
@ -470,6 +548,7 @@ class DblSidedTool(FlatCAMTool):
|
|||
self.mirror_axis.set_value(self.app.defaults["tools_2sided_mirror_axis"])
|
||||
self.axis_location.set_value(self.app.defaults["tools_2sided_axis_loc"])
|
||||
self.drill_dia.set_value(self.app.defaults["tools_2sided_drilldia"])
|
||||
self.align_axis_radio.set_value(self.app.defaults["tools_2sided_allign_axis"])
|
||||
|
||||
self.xmin_entry.set_value(0.0)
|
||||
self.ymin_entry.set_value(0.0)
|
||||
|
@ -477,13 +556,21 @@ class DblSidedTool(FlatCAMTool):
|
|||
self.ymax_entry.set_value(0.0)
|
||||
self.center_entry.set_value('')
|
||||
|
||||
def on_combo_box_type(self):
|
||||
obj_type = self.box_combo_type.currentIndex()
|
||||
self.align_ref_label_val.set_value('%.*f' % (self.decimals, 0.0))
|
||||
|
||||
# run once to make sure that the obj_type attribute is updated in the FCComboBox
|
||||
self.box_type_radio.set_value('grb')
|
||||
self.on_combo_box_type('grb')
|
||||
|
||||
def on_combo_box_type(self, val):
|
||||
obj_type = {'grb': 0, 'exc': 1, 'geo': 2}[val]
|
||||
self.box_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
|
||||
self.box_combo.setCurrentIndex(0)
|
||||
self.box_combo.obj_type = {
|
||||
"grb": "Gerber", "exc": "Excellon", "geo": "Geometry"}[val]
|
||||
|
||||
def on_create_alignment_holes(self):
|
||||
axis = self.mirror_axis.get_value()
|
||||
axis = self.align_axis_radio.get_value()
|
||||
mode = self.axis_location.get_value()
|
||||
|
||||
if mode == "point":
|
||||
|
@ -524,7 +611,10 @@ class DblSidedTool(FlatCAMTool):
|
|||
_("No value or wrong format in Drill Dia entry. Add it and retry."))
|
||||
return
|
||||
|
||||
tools = {"1": {"C": dia}}
|
||||
tools = {}
|
||||
tools["1"] = {}
|
||||
tools["1"]["C"] = dia
|
||||
tools["1"]['solid_geometry'] = []
|
||||
|
||||
# holes = self.alignment_holes.get_value()
|
||||
holes = eval('[{}]'.format(self.alignment_holes.text()))
|
||||
|
@ -533,23 +623,24 @@ class DblSidedTool(FlatCAMTool):
|
|||
"Add them and retry."))
|
||||
return
|
||||
|
||||
drills = list()
|
||||
drills = []
|
||||
|
||||
for hole in holes:
|
||||
point = Point(hole)
|
||||
point_mirror = affinity.scale(point, xscale, yscale, origin=(px, py))
|
||||
|
||||
drills.append({"point": point, "tool": "1"})
|
||||
drills.append({"point": point_mirror, "tool": "1"})
|
||||
if 'solid_geometry' not in tools["1"]:
|
||||
tools["1"]['solid_geometry'] = list()
|
||||
else:
|
||||
tools["1"]['solid_geometry'].append(point)
|
||||
tools["1"]['solid_geometry'].append(point_mirror)
|
||||
|
||||
tools["1"]['solid_geometry'].append(point)
|
||||
tools["1"]['solid_geometry'].append(point_mirror)
|
||||
|
||||
def obj_init(obj_inst, app_inst):
|
||||
obj_inst.tools = tools
|
||||
obj_inst.drills = drills
|
||||
obj_inst.create_geometry()
|
||||
obj_inst.source_file = app_inst.export_excellon(obj_name=obj_inst.options['name'], local_use=obj_inst,
|
||||
filename=None, use_thread=False)
|
||||
|
||||
self.app.new_object("excellon", "Alignment Drills", obj_init)
|
||||
self.drill_values = ''
|
||||
|
@ -561,7 +652,7 @@ class DblSidedTool(FlatCAMTool):
|
|||
model_index = self.app.collection.index(selection_index, 0, self.gerber_object_combo.rootModelIndex())
|
||||
try:
|
||||
fcobj = model_index.internalPointer().obj
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Gerber object loaded ..."))
|
||||
return
|
||||
|
||||
|
@ -585,7 +676,7 @@ class DblSidedTool(FlatCAMTool):
|
|||
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:
|
||||
except Exception:
|
||||
self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Box object loaded ..."))
|
||||
return
|
||||
|
||||
|
@ -604,7 +695,7 @@ class DblSidedTool(FlatCAMTool):
|
|||
model_index = self.app.collection.index(selection_index, 0, self.exc_object_combo.rootModelIndex())
|
||||
try:
|
||||
fcobj = model_index.internalPointer().obj
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Excellon object loaded ..."))
|
||||
return
|
||||
|
||||
|
@ -648,7 +739,7 @@ class DblSidedTool(FlatCAMTool):
|
|||
model_index = self.app.collection.index(selection_index, 0, self.geo_object_combo.rootModelIndex())
|
||||
try:
|
||||
fcobj = model_index.internalPointer().obj
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Geometry object loaded ..."))
|
||||
return
|
||||
|
||||
|
@ -666,7 +757,7 @@ class DblSidedTool(FlatCAMTool):
|
|||
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:
|
||||
except Exception:
|
||||
self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Box object loaded ..."))
|
||||
return
|
||||
|
||||
|
@ -679,27 +770,39 @@ class DblSidedTool(FlatCAMTool):
|
|||
fcobj.plot()
|
||||
self.app.inform.emit('[success] Geometry %s %s...' % (str(fcobj.options['name']), _("was mirrored")))
|
||||
|
||||
|
||||
def on_point_add(self):
|
||||
val = self.app.defaults["global_point_clipboard_format"] % (self.app.pos[0], self.app.pos[1])
|
||||
val = self.app.defaults["global_point_clipboard_format"] % \
|
||||
(self.decimals, self.app.pos[0], self.decimals, self.app.pos[1])
|
||||
self.point_entry.set_value(val)
|
||||
|
||||
def on_drill_add(self):
|
||||
self.drill_values += (self.app.defaults["global_point_clipboard_format"] %
|
||||
(self.app.pos[0], self.app.pos[1])) + ','
|
||||
(self.decimals, self.app.pos[0], self.decimals, self.app.pos[1])) + ','
|
||||
self.alignment_holes.set_value(self.drill_values)
|
||||
|
||||
def on_drill_delete_last(self):
|
||||
drill_values_without_last_tupple = self.drill_values.rpartition('(')[0]
|
||||
self.drill_values = drill_values_without_last_tupple
|
||||
self.alignment_holes.set_value(self.drill_values)
|
||||
|
||||
def on_toggle_pointbox(self):
|
||||
if self.axis_location.get_value() == "point":
|
||||
self.point_entry.show()
|
||||
self.add_point_button.show()
|
||||
self.box_type_label.hide()
|
||||
self.box_type_radio.hide()
|
||||
self.box_combo.hide()
|
||||
self.box_combo_type.hide()
|
||||
self.add_point_button.setDisabled(False)
|
||||
|
||||
self.align_ref_label_val.set_value(self.point_entry.get_value())
|
||||
else:
|
||||
self.point_entry.hide()
|
||||
self.add_point_button.hide()
|
||||
|
||||
self.box_type_label.show()
|
||||
self.box_type_radio.show()
|
||||
self.box_combo.show()
|
||||
self.box_combo_type.show()
|
||||
self.add_point_button.setDisabled(True)
|
||||
|
||||
self.align_ref_label_val.set_value("Box centroid")
|
||||
|
||||
def on_bbox_coordinates(self):
|
||||
|
||||
|
@ -735,6 +838,51 @@ class DblSidedTool(FlatCAMTool):
|
|||
self.center_entry.set_value(val_txt)
|
||||
self.axis_location.set_value('point')
|
||||
self.point_entry.set_value(val_txt)
|
||||
self.app.delete_selection_shape()
|
||||
|
||||
def on_xmin_clicked(self):
|
||||
xmin = self.xmin_entry.get_value()
|
||||
self.axis_location.set_value('point')
|
||||
|
||||
try:
|
||||
px, py = self.point_entry.get_value()
|
||||
val = self.app.defaults["global_point_clipboard_format"] % (self.decimals, xmin, self.decimals, py)
|
||||
except TypeError:
|
||||
val = self.app.defaults["global_point_clipboard_format"] % (self.decimals, xmin, self.decimals, 0.0)
|
||||
self.point_entry.set_value(val)
|
||||
|
||||
def on_ymin_clicked(self):
|
||||
ymin = self.ymin_entry.get_value()
|
||||
self.axis_location.set_value('point')
|
||||
|
||||
try:
|
||||
px, py = self.point_entry.get_value()
|
||||
val = self.app.defaults["global_point_clipboard_format"] % (self.decimals, px, self.decimals, ymin)
|
||||
except TypeError:
|
||||
val = self.app.defaults["global_point_clipboard_format"] % (self.decimals, 0.0, self.decimals, ymin)
|
||||
self.point_entry.set_value(val)
|
||||
|
||||
def on_xmax_clicked(self):
|
||||
xmax = self.xmax_entry.get_value()
|
||||
self.axis_location.set_value('point')
|
||||
|
||||
try:
|
||||
px, py = self.point_entry.get_value()
|
||||
val = self.app.defaults["global_point_clipboard_format"] % (self.decimals, xmax, self.decimals, py)
|
||||
except TypeError:
|
||||
val = self.app.defaults["global_point_clipboard_format"] % (self.decimals, xmax, self.decimals, 0.0)
|
||||
self.point_entry.set_value(val)
|
||||
|
||||
def on_ymax_clicked(self):
|
||||
ymax = self.ymax_entry.get_value()
|
||||
self.axis_location.set_value('point')
|
||||
|
||||
try:
|
||||
px, py = self.point_entry.get_value()
|
||||
val = self.app.defaults["global_point_clipboard_format"] % (self.decimals, px, self.decimals, ymax)
|
||||
except TypeError:
|
||||
val = self.app.defaults["global_point_clipboard_format"] % (self.decimals, 0.0, self.decimals, ymax)
|
||||
self.point_entry.set_value(val)
|
||||
|
||||
def reset_fields(self):
|
||||
self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
|
@ -746,6 +894,7 @@ class DblSidedTool(FlatCAMTool):
|
|||
self.exc_object_combo.setCurrentIndex(0)
|
||||
self.geo_object_combo.setCurrentIndex(0)
|
||||
self.box_combo.setCurrentIndex(0)
|
||||
self.box_combo_type.setCurrentIndex(0)
|
||||
self.box_type_radio.set_value('grb')
|
||||
|
||||
self.drill_values = ""
|
||||
self.align_ref_label_val.set_value('')
|
||||
|
|
|
@ -9,13 +9,18 @@ from PyQt5 import QtWidgets, QtCore
|
|||
|
||||
from FlatCAMTool import FlatCAMTool
|
||||
from flatcamGUI.VisPyVisuals import *
|
||||
from flatcamGUI.GUIElements import FCEntry
|
||||
from flatcamGUI.GUIElements import FCEntry, FCButton, FCCheckBox
|
||||
|
||||
from shapely.geometry import Point, MultiLineString, Polygon
|
||||
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
from camlib import FlatCAMRTreeStorage
|
||||
from flatcamEditors.FlatCAMGeoEditor import DrawToolShape
|
||||
|
||||
from copy import copy
|
||||
import math
|
||||
import logging
|
||||
import gettext
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
|
@ -43,82 +48,101 @@ class Distance(FlatCAMTool):
|
|||
self.layout.addWidget(title_label)
|
||||
|
||||
# ## Form Layout
|
||||
form_layout = QtWidgets.QFormLayout()
|
||||
self.layout.addLayout(form_layout)
|
||||
grid0 = QtWidgets.QGridLayout()
|
||||
grid0.setColumnStretch(0, 0)
|
||||
grid0.setColumnStretch(1, 1)
|
||||
self.layout.addLayout(grid0)
|
||||
|
||||
self.units_label = QtWidgets.QLabel('%s:' % _("Units"))
|
||||
self.units_label.setToolTip(_("Those are the units in which the distance is measured."))
|
||||
self.units_value = QtWidgets.QLabel("%s" % str({'mm': _("METRIC (mm)"), 'in': _("INCH (in)")}[self.units]))
|
||||
self.units_value.setDisabled(True)
|
||||
|
||||
grid0.addWidget(self.units_label, 0, 0)
|
||||
grid0.addWidget(self.units_value, 0, 1)
|
||||
|
||||
self.snap_center_cb = FCCheckBox(_("Snap to center"))
|
||||
self.snap_center_cb.setToolTip(
|
||||
_("Mouse cursor will snap to the center of the pad/drill\n"
|
||||
"when it is hovering over the geometry of the pad/drill.")
|
||||
)
|
||||
grid0.addWidget(self.snap_center_cb, 1, 0, 1, 2)
|
||||
|
||||
separator_line = QtWidgets.QFrame()
|
||||
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
grid0.addWidget(separator_line, 2, 0, 1, 2)
|
||||
|
||||
self.start_label = QtWidgets.QLabel("%s:" % _('Start Coords'))
|
||||
self.start_label.setToolTip(_("This is measuring Start point coordinates."))
|
||||
|
||||
self.stop_label = QtWidgets.QLabel("%s:" % _('Stop Coords'))
|
||||
self.stop_label.setToolTip(_("This is the measuring Stop point coordinates."))
|
||||
|
||||
self.distance_x_label = QtWidgets.QLabel('%s:' % _("Dx"))
|
||||
self.distance_x_label.setToolTip(_("This is the distance measured over the X axis."))
|
||||
|
||||
self.distance_y_label = QtWidgets.QLabel('%s:' % _("Dy"))
|
||||
self.distance_y_label.setToolTip(_("This is the distance measured over the Y axis."))
|
||||
|
||||
self.angle_label = QtWidgets.QLabel('%s:' % _("Angle"))
|
||||
self.angle_label.setToolTip(_("This is orientation angle of the measuring line."))
|
||||
|
||||
self.total_distance_label = QtWidgets.QLabel("<b>%s:</b>" % _('DISTANCE'))
|
||||
self.total_distance_label.setToolTip(_("This is the point to point Euclidian distance."))
|
||||
|
||||
self.start_entry = FCEntry()
|
||||
self.start_entry.setReadOnly(True)
|
||||
self.start_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
|
||||
self.start_entry.setToolTip(_("This is measuring Start point coordinates."))
|
||||
|
||||
grid0.addWidget(self.start_label, 3, 0)
|
||||
grid0.addWidget(self.start_entry, 3, 1)
|
||||
|
||||
self.stop_label = QtWidgets.QLabel("%s:" % _('Stop Coords'))
|
||||
self.stop_label.setToolTip(_("This is the measuring Stop point coordinates."))
|
||||
|
||||
self.stop_entry = FCEntry()
|
||||
self.stop_entry.setReadOnly(True)
|
||||
self.stop_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
|
||||
self.stop_entry.setToolTip(_("This is the measuring Stop point coordinates."))
|
||||
|
||||
grid0.addWidget(self.stop_label, 4, 0)
|
||||
grid0.addWidget(self.stop_entry, 4, 1)
|
||||
|
||||
self.distance_x_label = QtWidgets.QLabel('%s:' % _("Dx"))
|
||||
self.distance_x_label.setToolTip(_("This is the distance measured over the X axis."))
|
||||
|
||||
self.distance_x_entry = FCEntry()
|
||||
self.distance_x_entry.setReadOnly(True)
|
||||
self.distance_x_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
|
||||
self.distance_x_entry.setToolTip(_("This is the distance measured over the X axis."))
|
||||
|
||||
grid0.addWidget(self.distance_x_label, 5, 0)
|
||||
grid0.addWidget(self.distance_x_entry, 5, 1)
|
||||
|
||||
self.distance_y_label = QtWidgets.QLabel('%s:' % _("Dy"))
|
||||
self.distance_y_label.setToolTip(_("This is the distance measured over the Y axis."))
|
||||
|
||||
self.distance_y_entry = FCEntry()
|
||||
self.distance_y_entry.setReadOnly(True)
|
||||
self.distance_y_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
|
||||
self.distance_y_entry.setToolTip(_("This is the distance measured over the Y axis."))
|
||||
|
||||
grid0.addWidget(self.distance_y_label, 6, 0)
|
||||
grid0.addWidget(self.distance_y_entry, 6, 1)
|
||||
|
||||
self.angle_label = QtWidgets.QLabel('%s:' % _("Angle"))
|
||||
self.angle_label.setToolTip(_("This is orientation angle of the measuring line."))
|
||||
|
||||
self.angle_entry = FCEntry()
|
||||
self.angle_entry.setReadOnly(True)
|
||||
self.angle_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
|
||||
self.angle_entry.setToolTip(_("This is orientation angle of the measuring line."))
|
||||
|
||||
grid0.addWidget(self.angle_label, 7, 0)
|
||||
grid0.addWidget(self.angle_entry, 7, 1)
|
||||
|
||||
self.total_distance_label = QtWidgets.QLabel("<b>%s:</b>" % _('DISTANCE'))
|
||||
self.total_distance_label.setToolTip(_("This is the point to point Euclidian distance."))
|
||||
|
||||
self.total_distance_entry = FCEntry()
|
||||
self.total_distance_entry.setReadOnly(True)
|
||||
self.total_distance_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
|
||||
self.total_distance_entry.setToolTip(_("This is the point to point Euclidian distance."))
|
||||
|
||||
self.measure_btn = QtWidgets.QPushButton(_("Measure"))
|
||||
grid0.addWidget(self.total_distance_label, 8, 0)
|
||||
grid0.addWidget(self.total_distance_entry, 8, 1)
|
||||
|
||||
self.measure_btn = FCButton(_("Measure"))
|
||||
# self.measure_btn.setFixedWidth(70)
|
||||
self.layout.addWidget(self.measure_btn)
|
||||
|
||||
form_layout.addRow(self.units_label, self.units_value)
|
||||
form_layout.addRow(self.start_label, self.start_entry)
|
||||
form_layout.addRow(self.stop_label, self.stop_entry)
|
||||
form_layout.addRow(self.distance_x_label, self.distance_x_entry)
|
||||
form_layout.addRow(self.distance_y_label, self.distance_y_entry)
|
||||
form_layout.addRow(self.angle_label, self.angle_entry)
|
||||
form_layout.addRow(self.total_distance_label, self.total_distance_entry)
|
||||
|
||||
# initial view of the layout
|
||||
self.start_entry.set_value('(0, 0)')
|
||||
self.stop_entry.set_value('(0, 0)')
|
||||
self.distance_x_entry.set_value('0.0')
|
||||
self.distance_y_entry.set_value('0.0')
|
||||
self.angle_entry.set_value('0.0')
|
||||
self.total_distance_entry.set_value('0.0')
|
||||
|
||||
self.layout.addStretch()
|
||||
|
||||
# store here the first click and second click of the measurement process
|
||||
|
@ -137,6 +161,15 @@ class Distance(FlatCAMTool):
|
|||
self.mm = None
|
||||
self.mr = None
|
||||
|
||||
# monitor if the tool was used
|
||||
self.tool_done = False
|
||||
|
||||
# store the grid status here
|
||||
self.grid_status_memory = False
|
||||
|
||||
# store here if the snap button was clicked
|
||||
self.snap_toggled = None
|
||||
|
||||
# VisPy visuals
|
||||
if self.app.is_legacy is False:
|
||||
self.sel_shapes = ShapeCollection(parent=self.app.plotcanvas.view.scene, layers=1)
|
||||
|
@ -145,6 +178,7 @@ class Distance(FlatCAMTool):
|
|||
self.sel_shapes = ShapeCollectionLegacy(obj=self, app=self.app, name='measurement')
|
||||
|
||||
self.measure_btn.clicked.connect(self.activate_measure_tool)
|
||||
self.snap_center_cb.toggled.connect(self.on_snap_toggled)
|
||||
|
||||
def run(self, toggle=False):
|
||||
self.app.report_usage("ToolDistance()")
|
||||
|
@ -154,6 +188,8 @@ class Distance(FlatCAMTool):
|
|||
self.rel_point1 = None
|
||||
self.rel_point2 = None
|
||||
|
||||
self.tool_done = False
|
||||
|
||||
if self.app.tool_tab_locked is True:
|
||||
return
|
||||
|
||||
|
@ -177,7 +213,7 @@ class Distance(FlatCAMTool):
|
|||
# Remove anything else in the GUI
|
||||
self.app.ui.tool_scroll_area.takeWidget()
|
||||
|
||||
# Put ourself in the GUI
|
||||
# Put ourselves in the GUI
|
||||
self.app.ui.tool_scroll_area.setWidget(self)
|
||||
|
||||
# Switch notebook to tool page
|
||||
|
@ -195,20 +231,45 @@ class Distance(FlatCAMTool):
|
|||
self.angle_entry.set_value('0.0')
|
||||
self.total_distance_entry.set_value('0.0')
|
||||
|
||||
self.snap_center_cb.set_value(self.app.defaults['tools_dist_snap_center'])
|
||||
|
||||
# snap center works only for Gerber and Execellon Editor's
|
||||
if self.original_call_source == 'exc_editor' or self.original_call_source == 'grb_editor':
|
||||
self.snap_center_cb.show()
|
||||
else:
|
||||
self.snap_center_cb.hide()
|
||||
|
||||
# this is a hack; seems that triggering the grid will make the visuals better
|
||||
# trigger it twice to return to the original state
|
||||
self.app.ui.grid_snap_btn.trigger()
|
||||
self.app.ui.grid_snap_btn.trigger()
|
||||
|
||||
if self.app.ui.grid_snap_btn.isChecked():
|
||||
self.grid_status_memory = True
|
||||
|
||||
log.debug("Distance Tool --> tool initialized")
|
||||
|
||||
def on_snap_toggled(self, state):
|
||||
self.app.defaults['tools_dist_snap_center'] = state
|
||||
if state:
|
||||
# disengage the grid snapping since it will be hard to find the drills or pads on grid
|
||||
if self.app.ui.grid_snap_btn.isChecked():
|
||||
self.app.ui.grid_snap_btn.trigger()
|
||||
|
||||
def activate_measure_tool(self):
|
||||
# ENABLE the Measuring TOOL
|
||||
self.active = True
|
||||
|
||||
# disable the measuring button
|
||||
self.measure_btn.setDisabled(True)
|
||||
self.measure_btn.setText('%s...' % _("Working"))
|
||||
|
||||
self.clicked_meas = 0
|
||||
self.original_call_source = copy(self.app.call_source)
|
||||
|
||||
snap_center = self.app.defaults['tools_dist_snap_center']
|
||||
self.on_snap_toggled(snap_center)
|
||||
|
||||
self.app.inform.emit(_("MEASURING: Click on the Start point ..."))
|
||||
self.units = self.app.defaults['units'].lower()
|
||||
|
||||
|
@ -267,6 +328,10 @@ class Distance(FlatCAMTool):
|
|||
self.active = False
|
||||
self.points = []
|
||||
|
||||
# disable the measuring button
|
||||
self.measure_btn.setDisabled(False)
|
||||
self.measure_btn.setText(_("Measure"))
|
||||
|
||||
self.app.call_source = copy(self.original_call_source)
|
||||
if self.original_call_source == 'app':
|
||||
self.app.mm = self.canvas.graph_event_connect('mouse_move', self.app.on_mouse_move_over_plot)
|
||||
|
@ -307,8 +372,16 @@ class Distance(FlatCAMTool):
|
|||
# delete the measuring line
|
||||
self.delete_shape()
|
||||
|
||||
# restore the grid status
|
||||
if (self.app.ui.grid_snap_btn.isChecked() and self.grid_status_memory is False) or \
|
||||
(not self.app.ui.grid_snap_btn.isChecked() and self.grid_status_memory is True):
|
||||
self.app.ui.grid_snap_btn.trigger()
|
||||
|
||||
log.debug("Distance Tool --> exit tool")
|
||||
|
||||
if self.tool_done is False:
|
||||
self.app.inform.emit('%s' % _("Distance Tool finished."))
|
||||
|
||||
def on_mouse_click_release(self, event):
|
||||
# mouse click releases will be accepted only if the left button is clicked
|
||||
# this is necessary because right mouse click or middle mouse click
|
||||
|
@ -323,11 +396,71 @@ class Distance(FlatCAMTool):
|
|||
|
||||
pos_canvas = self.canvas.translate_coords(event_pos)
|
||||
|
||||
# if GRID is active we need to get the snapped positions
|
||||
if self.app.grid_status() == True:
|
||||
pos = self.app.geo_editor.snap(pos_canvas[0], pos_canvas[1])
|
||||
if self.snap_center_cb.get_value() is False:
|
||||
# if GRID is active we need to get the snapped positions
|
||||
if self.app.grid_status():
|
||||
pos = self.app.geo_editor.snap(pos_canvas[0], pos_canvas[1])
|
||||
else:
|
||||
pos = pos_canvas[0], pos_canvas[1]
|
||||
else:
|
||||
pos = pos_canvas[0], pos_canvas[1]
|
||||
pos = (pos_canvas[0], pos_canvas[1])
|
||||
current_pt = Point(pos)
|
||||
shapes_storage = self.make_storage()
|
||||
|
||||
if self.original_call_source == 'exc_editor':
|
||||
for storage in self.app.exc_editor.storage_dict:
|
||||
__, st_closest_shape = self.app.exc_editor.storage_dict[storage].nearest(pos)
|
||||
shapes_storage.insert(st_closest_shape)
|
||||
|
||||
__, closest_shape = shapes_storage.nearest(pos)
|
||||
|
||||
# if it's a drill
|
||||
if isinstance(closest_shape.geo, MultiLineString):
|
||||
radius = closest_shape.geo[0].length / 2.0
|
||||
center_pt = closest_shape.geo.centroid
|
||||
|
||||
geo_buffered = center_pt.buffer(radius)
|
||||
|
||||
if current_pt.within(geo_buffered):
|
||||
pos = (center_pt.x, center_pt.y)
|
||||
|
||||
# if it's a slot
|
||||
elif isinstance(closest_shape.geo, Polygon):
|
||||
geo_buffered = closest_shape.geo.buffer(0)
|
||||
center_pt = geo_buffered.centroid
|
||||
|
||||
if current_pt.within(geo_buffered):
|
||||
pos = (center_pt.x, center_pt.y)
|
||||
|
||||
elif self.original_call_source == 'grb_editor':
|
||||
clicked_pads = []
|
||||
for storage in self.app.grb_editor.storage_dict:
|
||||
try:
|
||||
for shape_stored in self.app.grb_editor.storage_dict[storage]['geometry']:
|
||||
if 'solid' in shape_stored.geo:
|
||||
geometric_data = shape_stored.geo['solid']
|
||||
if Point(current_pt).within(geometric_data):
|
||||
if isinstance(shape_stored.geo['follow'], Point):
|
||||
clicked_pads.append(shape_stored.geo['follow'])
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
if len(clicked_pads) > 1:
|
||||
self.tool_done = True
|
||||
self.deactivate_measure_tool()
|
||||
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Pads overlapped. Aborting."))
|
||||
return
|
||||
|
||||
pos = (clicked_pads[0].x, clicked_pads[0].y)
|
||||
|
||||
self.app.on_jump_to(custom_location=pos, fit_center=False)
|
||||
# Update cursor
|
||||
self.app.app_cursor.enabled = True
|
||||
self.app.app_cursor.set_data(np.asarray([(pos[0], pos[1])]),
|
||||
symbol='++', edge_color='#000000',
|
||||
edge_width=self.app.defaults["global_cursor_width"],
|
||||
size=self.app.defaults["global_cursor_size"])
|
||||
|
||||
self.points.append(pos)
|
||||
|
||||
# Reset here the relative coordinates so there is a new reference on the click position
|
||||
|
@ -340,41 +473,46 @@ class Distance(FlatCAMTool):
|
|||
self.rel_point2 = copy(self.rel_point1)
|
||||
self.rel_point1 = pos
|
||||
|
||||
if len(self.points) == 1:
|
||||
self.start_entry.set_value("(%.*f, %.*f)" % (self.decimals, pos[0], self.decimals, pos[1]))
|
||||
self.app.inform.emit(_("MEASURING: Click on the Destination point ..."))
|
||||
elif len(self.points) == 2:
|
||||
dx = self.points[1][0] - self.points[0][0]
|
||||
dy = self.points[1][1] - self.points[0][1]
|
||||
d = math.sqrt(dx ** 2 + dy ** 2)
|
||||
self.stop_entry.set_value("(%.*f, %.*f)" % (self.decimals, pos[0], self.decimals, pos[1]))
|
||||
self.calculate_distance(pos=pos)
|
||||
|
||||
self.app.inform.emit("{tx1}: {tx2} D(x) = {d_x} | D(y) = {d_y} | {tx3} = {d_z}".format(
|
||||
tx1=_("MEASURING"),
|
||||
tx2=_("Result"),
|
||||
tx3=_("Distance"),
|
||||
d_x='%*f' % (self.decimals, abs(dx)),
|
||||
d_y='%*f' % (self.decimals, abs(dy)),
|
||||
d_z='%*f' % (self.decimals, abs(d)))
|
||||
def calculate_distance(self, pos):
|
||||
if len(self.points) == 1:
|
||||
self.start_entry.set_value("(%.*f, %.*f)" % (self.decimals, pos[0], self.decimals, pos[1]))
|
||||
self.app.inform.emit(_("MEASURING: Click on the Destination point ..."))
|
||||
elif len(self.points) == 2:
|
||||
self.app.app_cursor.enabled = False
|
||||
dx = self.points[1][0] - self.points[0][0]
|
||||
dy = self.points[1][1] - self.points[0][1]
|
||||
d = math.sqrt(dx ** 2 + dy ** 2)
|
||||
self.stop_entry.set_value("(%.*f, %.*f)" % (self.decimals, pos[0], self.decimals, pos[1]))
|
||||
|
||||
self.app.inform.emit("{tx1}: {tx2} D(x) = {d_x} | D(y) = {d_y} | {tx3} = {d_z}".format(
|
||||
tx1=_("MEASURING"),
|
||||
tx2=_("Result"),
|
||||
tx3=_("Distance"),
|
||||
d_x='%*f' % (self.decimals, abs(dx)),
|
||||
d_y='%*f' % (self.decimals, abs(dy)),
|
||||
d_z='%*f' % (self.decimals, abs(d)))
|
||||
)
|
||||
|
||||
self.distance_x_entry.set_value('%.*f' % (self.decimals, abs(dx)))
|
||||
self.distance_y_entry.set_value('%.*f' % (self.decimals, abs(dy)))
|
||||
|
||||
if dx != 0.0:
|
||||
try:
|
||||
angle = math.degrees(math.atan(dy / dx))
|
||||
self.angle_entry.set_value('%.*f' % (self.decimals, angle))
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
self.total_distance_entry.set_value('%.*f' % (self.decimals, abs(d)))
|
||||
self.app.ui.rel_position_label.setText(
|
||||
"<b>Dx</b>: {} <b>Dy</b>: {} ".format(
|
||||
'%.*f' % (self.decimals, pos[0]), '%.*f' % (self.decimals, pos[1])
|
||||
)
|
||||
|
||||
self.distance_x_entry.set_value('%.*f' % (self.decimals, abs(dx)))
|
||||
self.distance_y_entry.set_value('%.*f' % (self.decimals, abs(dy)))
|
||||
|
||||
if dx != 0.0:
|
||||
try:
|
||||
angle = math.degrees(math.atan(dy / dx))
|
||||
self.angle_entry.set_value('%.*f' % (self.decimals, angle))
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
self.total_distance_entry.set_value('%.*f' % (self.decimals, abs(d)))
|
||||
self.app.ui.rel_position_label.setText(
|
||||
"<b>Dx</b>: {} <b>Dy</b>: {} ".format(
|
||||
'%.*f' % (self.decimals, pos[0]), '%.*f' % (self.decimals, pos[1])
|
||||
)
|
||||
)
|
||||
self.deactivate_measure_tool()
|
||||
)
|
||||
self.tool_done = True
|
||||
self.deactivate_measure_tool()
|
||||
|
||||
def on_mouse_move_meas(self, event):
|
||||
try: # May fail in case mouse not within axes
|
||||
|
@ -391,7 +529,7 @@ class Distance(FlatCAMTool):
|
|||
|
||||
pos_canvas = self.app.plotcanvas.translate_coords((x, y))
|
||||
|
||||
if self.app.grid_status() == True:
|
||||
if self.app.grid_status():
|
||||
pos = self.app.geo_editor.snap(pos_canvas[0], pos_canvas[1])
|
||||
|
||||
# Update cursor
|
||||
|
@ -465,7 +603,15 @@ class Distance(FlatCAMTool):
|
|||
self.sel_shapes.clear()
|
||||
self.sel_shapes.redraw()
|
||||
|
||||
def set_meas_units(self, units):
|
||||
self.meas.units_label.setText("[" + self.app.options["units"].lower() + "]")
|
||||
@staticmethod
|
||||
def make_storage():
|
||||
# ## Shape storage.
|
||||
storage = FlatCAMRTreeStorage()
|
||||
storage.get_points = DrawToolShape.get_pts
|
||||
|
||||
return storage
|
||||
|
||||
# def set_meas_units(self, units):
|
||||
# self.meas.units_label.setText("[" + self.app.options["units"].lower() + "]")
|
||||
|
||||
# end of file
|
||||
|
|
|
@ -11,7 +11,8 @@ from flatcamGUI.VisPyVisuals import *
|
|||
from flatcamGUI.GUIElements import FCEntry
|
||||
|
||||
from shapely.ops import nearest_points
|
||||
from shapely.geometry import Point
|
||||
from shapely.geometry import Point, MultiPolygon
|
||||
from shapely.ops import cascaded_union
|
||||
|
||||
import math
|
||||
import logging
|
||||
|
@ -127,15 +128,6 @@ class DistanceMin(FlatCAMTool):
|
|||
form_layout.addRow(self.total_distance_label, self.total_distance_entry)
|
||||
form_layout.addRow(self.half_point_label, self.half_point_entry)
|
||||
|
||||
# initial view of the layout
|
||||
self.start_entry.set_value('(0, 0)')
|
||||
self.stop_entry.set_value('(0, 0)')
|
||||
self.distance_x_entry.set_value('0.0')
|
||||
self.distance_y_entry.set_value('0.0')
|
||||
self.angle_entry.set_value('0.0')
|
||||
self.total_distance_entry.set_value('0.0')
|
||||
self.half_point_entry.set_value('(0, 0)')
|
||||
|
||||
self.layout.addStretch()
|
||||
|
||||
self.h_point = (0, 0)
|
||||
|
@ -205,6 +197,17 @@ class DistanceMin(FlatCAMTool):
|
|||
str(len(selected_objs))))
|
||||
return
|
||||
else:
|
||||
if isinstance(selected_objs[0].solid_geometry, list):
|
||||
try:
|
||||
selected_objs[0].solid_geometry = MultiPolygon(selected_objs[0].solid_geometry)
|
||||
except Exception:
|
||||
selected_objs[0].solid_geometry = cascaded_union(selected_objs[0].solid_geometry)
|
||||
|
||||
try:
|
||||
selected_objs[1].solid_geometry = MultiPolygon(selected_objs[1].solid_geometry)
|
||||
except Exception:
|
||||
selected_objs[1].solid_geometry = cascaded_union(selected_objs[1].solid_geometry)
|
||||
|
||||
first_pos, last_pos = nearest_points(selected_objs[0].solid_geometry, selected_objs[1].solid_geometry)
|
||||
|
||||
elif self.app.call_source == 'geo_editor':
|
||||
|
@ -278,7 +281,7 @@ class DistanceMin(FlatCAMTool):
|
|||
)
|
||||
|
||||
if d != 0:
|
||||
self.app.inform.emit("{tx1}: {tx2} D(x) = {d_x} | D(y) = {d_y} | (tx3} = {d_z}".format(
|
||||
self.app.inform.emit("{tx1}: {tx2} D(x) = {d_x} | D(y) = {d_y} | {tx3} = {d_z}".format(
|
||||
tx1=_("MEASURING"),
|
||||
tx2=_("Result"),
|
||||
tx3=_("Distance"),
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
from PyQt5 import QtWidgets, QtCore
|
||||
|
||||
from FlatCAMTool import FlatCAMTool
|
||||
from flatcamGUI.GUIElements import RadioSet, FCDoubleSpinner, FCCheckBox
|
||||
from flatcamGUI.GUIElements import RadioSet, FCDoubleSpinner, FCCheckBox, FCComboBox
|
||||
|
||||
from shapely.geometry import Point
|
||||
|
||||
|
@ -43,8 +43,7 @@ class ToolExtractDrills(FlatCAMTool):
|
|||
""")
|
||||
self.layout.addWidget(title_label)
|
||||
|
||||
self.empty_lb = QtWidgets.QLabel("")
|
||||
self.layout.addWidget(self.empty_lb)
|
||||
self.layout.addWidget(QtWidgets.QLabel(""))
|
||||
|
||||
# ## Grid Layout
|
||||
grid_lay = QtWidgets.QGridLayout()
|
||||
|
@ -53,10 +52,11 @@ class ToolExtractDrills(FlatCAMTool):
|
|||
grid_lay.setColumnStretch(1, 0)
|
||||
|
||||
# ## Gerber Object
|
||||
self.gerber_object_combo = QtWidgets.QComboBox()
|
||||
self.gerber_object_combo = FCComboBox()
|
||||
self.gerber_object_combo.setModel(self.app.collection)
|
||||
self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.gerber_object_combo.setCurrentIndex(1)
|
||||
self.gerber_object_combo.is_last = True
|
||||
self.gerber_object_combo.obj_type = "Gerber"
|
||||
|
||||
self.grb_label = QtWidgets.QLabel("<b>%s:</b>" % _("GERBER"))
|
||||
self.grb_label.setToolTip('%s.' % _("Gerber from which to extract drill holes"))
|
||||
|
@ -77,7 +77,7 @@ class ToolExtractDrills(FlatCAMTool):
|
|||
# Circular Aperture Selection
|
||||
self.circular_cb = FCCheckBox('%s' % _("Circular"))
|
||||
self.circular_cb.setToolTip(
|
||||
_("Create drills from circular pads.")
|
||||
_("Process Circular Pads.")
|
||||
)
|
||||
|
||||
grid_lay.addWidget(self.circular_cb, 3, 0, 1, 2)
|
||||
|
@ -85,7 +85,7 @@ class ToolExtractDrills(FlatCAMTool):
|
|||
# Oblong Aperture Selection
|
||||
self.oblong_cb = FCCheckBox('%s' % _("Oblong"))
|
||||
self.oblong_cb.setToolTip(
|
||||
_("Create drills from oblong pads.")
|
||||
_("Process Oblong Pads.")
|
||||
)
|
||||
|
||||
grid_lay.addWidget(self.oblong_cb, 4, 0, 1, 2)
|
||||
|
@ -93,7 +93,7 @@ class ToolExtractDrills(FlatCAMTool):
|
|||
# Square Aperture Selection
|
||||
self.square_cb = FCCheckBox('%s' % _("Square"))
|
||||
self.square_cb.setToolTip(
|
||||
_("Create drills from square pads.")
|
||||
_("Process Square Pads.")
|
||||
)
|
||||
|
||||
grid_lay.addWidget(self.square_cb, 5, 0, 1, 2)
|
||||
|
@ -101,7 +101,7 @@ class ToolExtractDrills(FlatCAMTool):
|
|||
# Rectangular Aperture Selection
|
||||
self.rectangular_cb = FCCheckBox('%s' % _("Rectangular"))
|
||||
self.rectangular_cb.setToolTip(
|
||||
_("Create drills from rectangular pads.")
|
||||
_("Process Rectangular Pads.")
|
||||
)
|
||||
|
||||
grid_lay.addWidget(self.rectangular_cb, 6, 0, 1, 2)
|
||||
|
@ -109,7 +109,7 @@ class ToolExtractDrills(FlatCAMTool):
|
|||
# Others type of Apertures Selection
|
||||
self.other_cb = FCCheckBox('%s' % _("Others"))
|
||||
self.other_cb.setToolTip(
|
||||
_("Create drills from other types of pad shape.")
|
||||
_("Process pads not in the categories above.")
|
||||
)
|
||||
|
||||
grid_lay.addWidget(self.other_cb, 7, 0, 1, 2)
|
||||
|
@ -126,9 +126,14 @@ class ToolExtractDrills(FlatCAMTool):
|
|||
grid1.setColumnStretch(1, 1)
|
||||
|
||||
self.method_label = QtWidgets.QLabel('<b>%s</b>' % _("Method"))
|
||||
self.method_label.setToolTip(
|
||||
_("The method for processing pads. Can be:\n"
|
||||
"- Fixed Diameter -> all holes will have a set size\n"
|
||||
"- Fixed Annular Ring -> all holes will have a set annular ring\n"
|
||||
"- Proportional -> each hole size will be a fraction of the pad size"))
|
||||
grid1.addWidget(self.method_label, 2, 0, 1, 2)
|
||||
|
||||
# ## Axis
|
||||
# ## Holes Size
|
||||
self.hole_size_radio = RadioSet(
|
||||
[
|
||||
{'label': _("Fixed Diameter"), 'value': 'fixed'},
|
||||
|
@ -138,15 +143,7 @@ class ToolExtractDrills(FlatCAMTool):
|
|||
orientation='vertical',
|
||||
stretch=False)
|
||||
|
||||
self.hole_size_label = QtWidgets.QLabel('%s:' % _("Hole Size"))
|
||||
self.hole_size_label.setToolTip(
|
||||
_("The selected method of extracting the drills. Can be:\n"
|
||||
"- Fixed Diameter -> all holes will have a set size\n"
|
||||
"- Fixed Annular Ring -> all holes will have a set annular ring\n"
|
||||
"- Proportional -> each hole size will be a fraction of the pad size"))
|
||||
|
||||
grid1.addWidget(self.hole_size_label, 3, 0)
|
||||
grid1.addWidget(self.hole_size_radio, 3, 1)
|
||||
grid1.addWidget(self.hole_size_radio, 3, 0, 1, 2)
|
||||
|
||||
# grid_lay1.addWidget(QtWidgets.QLabel(''))
|
||||
|
||||
|
@ -160,7 +157,7 @@ class ToolExtractDrills(FlatCAMTool):
|
|||
grid1.addWidget(self.fixed_label, 6, 0, 1, 2)
|
||||
|
||||
# Diameter value
|
||||
self.dia_entry = FCDoubleSpinner()
|
||||
self.dia_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.dia_entry.set_precision(self.decimals)
|
||||
self.dia_entry.set_range(0.0000, 9999.9999)
|
||||
|
||||
|
@ -195,7 +192,7 @@ class ToolExtractDrills(FlatCAMTool):
|
|||
self.ring_label = QtWidgets.QLabel('<b>%s</b>' % _("Fixed Annular Ring"))
|
||||
self.ring_label.setToolTip(
|
||||
_("The size of annular ring.\n"
|
||||
"The copper sliver between the drill hole exterior\n"
|
||||
"The copper sliver between the hole exterior\n"
|
||||
"and the margin of the copper pad.")
|
||||
)
|
||||
grid2.addWidget(self.ring_label, 0, 0, 1, 2)
|
||||
|
@ -206,7 +203,7 @@ class ToolExtractDrills(FlatCAMTool):
|
|||
_("The size of annular ring for circular pads.")
|
||||
)
|
||||
|
||||
self.circular_ring_entry = FCDoubleSpinner()
|
||||
self.circular_ring_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.circular_ring_entry.set_precision(self.decimals)
|
||||
self.circular_ring_entry.set_range(0.0000, 9999.9999)
|
||||
|
||||
|
@ -219,7 +216,7 @@ class ToolExtractDrills(FlatCAMTool):
|
|||
_("The size of annular ring for oblong pads.")
|
||||
)
|
||||
|
||||
self.oblong_ring_entry = FCDoubleSpinner()
|
||||
self.oblong_ring_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.oblong_ring_entry.set_precision(self.decimals)
|
||||
self.oblong_ring_entry.set_range(0.0000, 9999.9999)
|
||||
|
||||
|
@ -232,7 +229,7 @@ class ToolExtractDrills(FlatCAMTool):
|
|||
_("The size of annular ring for square pads.")
|
||||
)
|
||||
|
||||
self.square_ring_entry = FCDoubleSpinner()
|
||||
self.square_ring_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.square_ring_entry.set_precision(self.decimals)
|
||||
self.square_ring_entry.set_range(0.0000, 9999.9999)
|
||||
|
||||
|
@ -245,7 +242,7 @@ class ToolExtractDrills(FlatCAMTool):
|
|||
_("The size of annular ring for rectangular pads.")
|
||||
)
|
||||
|
||||
self.rectangular_ring_entry = FCDoubleSpinner()
|
||||
self.rectangular_ring_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.rectangular_ring_entry.set_precision(self.decimals)
|
||||
self.rectangular_ring_entry.set_range(0.0000, 9999.9999)
|
||||
|
||||
|
@ -258,7 +255,7 @@ class ToolExtractDrills(FlatCAMTool):
|
|||
_("The size of annular ring for other pads.")
|
||||
)
|
||||
|
||||
self.other_ring_entry = FCDoubleSpinner()
|
||||
self.other_ring_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.other_ring_entry.set_precision(self.decimals)
|
||||
self.other_ring_entry.set_range(0.0000, 9999.9999)
|
||||
|
||||
|
@ -280,7 +277,7 @@ class ToolExtractDrills(FlatCAMTool):
|
|||
grid3.addWidget(self.prop_label, 2, 0, 1, 2)
|
||||
|
||||
# Diameter value
|
||||
self.factor_entry = FCDoubleSpinner(suffix='%')
|
||||
self.factor_entry = FCDoubleSpinner(callback=self.confirmation_message, suffix='%')
|
||||
self.factor_entry.set_precision(self.decimals)
|
||||
self.factor_entry.set_range(0.0000, 100.0000)
|
||||
self.factor_entry.setSingleStep(0.1)
|
||||
|
@ -288,7 +285,7 @@ class ToolExtractDrills(FlatCAMTool):
|
|||
self.factor_label = QtWidgets.QLabel('%s:' % _("Value"))
|
||||
self.factor_label.setToolTip(
|
||||
_("Proportional Diameter.\n"
|
||||
"The drill diameter will be a fraction of the pad size.")
|
||||
"The hole diameter will be a fraction of the pad size.")
|
||||
)
|
||||
|
||||
grid3.addWidget(self.factor_label, 3, 0)
|
||||
|
@ -427,8 +424,8 @@ class ToolExtractDrills(FlatCAMTool):
|
|||
|
||||
prop_factor = self.factor_entry.get_value() / 100.0
|
||||
|
||||
drills = list()
|
||||
tools = dict()
|
||||
drills = []
|
||||
tools = {}
|
||||
|
||||
selection_index = self.gerber_object_combo.currentIndex()
|
||||
model_index = self.app.collection.index(selection_index, 0, self.gerber_object_combo.rootModelIndex())
|
||||
|
@ -473,7 +470,7 @@ class ToolExtractDrills(FlatCAMTool):
|
|||
if 'follow' in geo_el and isinstance(geo_el['follow'], Point):
|
||||
drills.append({"point": geo_el['follow'], "tool": "1"})
|
||||
if 'solid_geometry' not in tools["1"]:
|
||||
tools["1"]['solid_geometry'] = list()
|
||||
tools["1"]['solid_geometry'] = []
|
||||
else:
|
||||
tools["1"]['solid_geometry'].append(geo_el['follow'])
|
||||
|
||||
|
@ -552,7 +549,7 @@ class ToolExtractDrills(FlatCAMTool):
|
|||
drills.append({"point": geo_el['follow'], "tool": tool_in_drills})
|
||||
|
||||
if 'solid_geometry' not in tools[tool_in_drills]:
|
||||
tools[tool_in_drills]['solid_geometry'] = list()
|
||||
tools[tool_in_drills]['solid_geometry'] = []
|
||||
else:
|
||||
tools[tool_in_drills]['solid_geometry'].append(geo_el['follow'])
|
||||
|
||||
|
@ -637,7 +634,7 @@ class ToolExtractDrills(FlatCAMTool):
|
|||
drills.append({"point": geo_el['follow'], "tool": tool_in_drills})
|
||||
|
||||
if 'solid_geometry' not in tools[tool_in_drills]:
|
||||
tools[tool_in_drills]['solid_geometry'] = list()
|
||||
tools[tool_in_drills]['solid_geometry'] = []
|
||||
else:
|
||||
tools[tool_in_drills]['solid_geometry'].append(geo_el['follow'])
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
from PyQt5 import QtWidgets, QtCore
|
||||
|
||||
from FlatCAMTool import FlatCAMTool
|
||||
from flatcamGUI.GUIElements import FCDoubleSpinner, RadioSet, EvalEntry, FCTable
|
||||
from flatcamGUI.GUIElements import FCDoubleSpinner, RadioSet, EvalEntry, FCTable, FCComboBox
|
||||
|
||||
from shapely.geometry import Point, Polygon, MultiPolygon, LineString
|
||||
from shapely.geometry import box as box
|
||||
|
@ -159,7 +159,7 @@ class ToolFiducials(FlatCAMTool):
|
|||
"otherwise is the size of the fiducial.\n"
|
||||
"The soldermask opening is double than that.")
|
||||
)
|
||||
self.fid_size_entry = FCDoubleSpinner()
|
||||
self.fid_size_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.fid_size_entry.set_range(1.0000, 3.0000)
|
||||
self.fid_size_entry.set_precision(self.decimals)
|
||||
self.fid_size_entry.setWrapping(True)
|
||||
|
@ -173,7 +173,7 @@ class ToolFiducials(FlatCAMTool):
|
|||
self.margin_label.setToolTip(
|
||||
_("Bounding box margin.")
|
||||
)
|
||||
self.margin_entry = FCDoubleSpinner()
|
||||
self.margin_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.margin_entry.set_range(-9999.9999, 9999.9999)
|
||||
self.margin_entry.set_precision(self.decimals)
|
||||
self.margin_entry.setSingleStep(0.1)
|
||||
|
@ -236,7 +236,7 @@ class ToolFiducials(FlatCAMTool):
|
|||
self.line_thickness_label.setToolTip(
|
||||
_("Bounding box margin.")
|
||||
)
|
||||
self.line_thickness_entry = FCDoubleSpinner()
|
||||
self.line_thickness_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.line_thickness_entry.set_range(0.00001, 9999.9999)
|
||||
self.line_thickness_entry.set_precision(self.decimals)
|
||||
self.line_thickness_entry.setSingleStep(0.1)
|
||||
|
@ -250,10 +250,11 @@ class ToolFiducials(FlatCAMTool):
|
|||
grid_lay.addWidget(separator_line_1, 8, 0, 1, 2)
|
||||
|
||||
# Copper Gerber object
|
||||
self.grb_object_combo = QtWidgets.QComboBox()
|
||||
self.grb_object_combo = FCComboBox()
|
||||
self.grb_object_combo.setModel(self.app.collection)
|
||||
self.grb_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.grb_object_combo.setCurrentIndex(1)
|
||||
self.grb_object_combo.is_last = True
|
||||
self.grb_object_combo.obj_type = "Gerber"
|
||||
|
||||
self.grbobj_label = QtWidgets.QLabel("<b>%s:</b>" % _("Copper Gerber"))
|
||||
self.grbobj_label.setToolTip(
|
||||
|
@ -286,10 +287,11 @@ class ToolFiducials(FlatCAMTool):
|
|||
self.sm_object_label.setToolTip(
|
||||
_("The Soldermask Gerber object.")
|
||||
)
|
||||
self.sm_object_combo = QtWidgets.QComboBox()
|
||||
self.sm_object_combo = FCComboBox()
|
||||
self.sm_object_combo.setModel(self.app.collection)
|
||||
self.sm_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.sm_object_combo.setCurrentIndex(1)
|
||||
self.sm_object_combo.is_last = True
|
||||
self.sm_object_combo.obj_type = "Gerber"
|
||||
|
||||
grid_lay.addWidget(self.sm_object_label, 13, 0, 1, 2)
|
||||
grid_lay.addWidget(self.sm_object_combo, 14, 0, 1, 2)
|
||||
|
@ -333,7 +335,7 @@ class ToolFiducials(FlatCAMTool):
|
|||
self.sm_obj_set = set()
|
||||
|
||||
# store the flattened geometry here:
|
||||
self.flat_geometry = list()
|
||||
self.flat_geometry = []
|
||||
|
||||
# Events ID
|
||||
self.mr = None
|
||||
|
@ -353,7 +355,7 @@ class ToolFiducials(FlatCAMTool):
|
|||
self.sec_position = None
|
||||
self.geo_steps_per_circle = 128
|
||||
|
||||
self.click_points = list()
|
||||
self.click_points = []
|
||||
|
||||
# SIGNALS
|
||||
self.add_cfid_button.clicked.connect(self.add_fiducials)
|
||||
|
@ -404,7 +406,7 @@ class ToolFiducials(FlatCAMTool):
|
|||
self.fid_type_radio.set_value(self.app.defaults["tools_fiducials_type"])
|
||||
self.line_thickness_entry.set_value(float(self.app.defaults["tools_fiducials_line_thickness"]))
|
||||
|
||||
self.click_points = list()
|
||||
self.click_points = []
|
||||
self.bottom_left_coords_entry.set_value('')
|
||||
self.top_right_coords_entry.set_value('')
|
||||
self.sec_points_coords_entry.set_value('')
|
||||
|
@ -429,7 +431,7 @@ class ToolFiducials(FlatCAMTool):
|
|||
:return: None
|
||||
"""
|
||||
if val == 'auto':
|
||||
self.click_points = list()
|
||||
self.click_points = []
|
||||
|
||||
try:
|
||||
self.disconnect_event_handlers()
|
||||
|
@ -451,7 +453,7 @@ class ToolFiducials(FlatCAMTool):
|
|||
self.sec_position = self.pos_radio.get_value()
|
||||
fid_type = self.fid_type_radio.get_value()
|
||||
|
||||
self.click_points = list()
|
||||
self.click_points = []
|
||||
|
||||
# get the Gerber object on which the Fiducial will be inserted
|
||||
selection_index = self.grb_object_combo.currentIndex()
|
||||
|
@ -547,7 +549,7 @@ class ToolFiducials(FlatCAMTool):
|
|||
|
||||
if aperture_found:
|
||||
for geo in geo_list:
|
||||
dict_el = dict()
|
||||
dict_el = {}
|
||||
dict_el['follow'] = geo.centroid
|
||||
dict_el['solid'] = geo
|
||||
g_obj.apertures[aperture_found]['geometry'].append(deepcopy(dict_el))
|
||||
|
@ -558,18 +560,18 @@ class ToolFiducials(FlatCAMTool):
|
|||
else:
|
||||
new_apid = '10'
|
||||
|
||||
g_obj.apertures[new_apid] = dict()
|
||||
g_obj.apertures[new_apid] = {}
|
||||
g_obj.apertures[new_apid]['type'] = 'C'
|
||||
g_obj.apertures[new_apid]['size'] = fid_size
|
||||
g_obj.apertures[new_apid]['geometry'] = list()
|
||||
g_obj.apertures[new_apid]['geometry'] = []
|
||||
|
||||
for geo in geo_list:
|
||||
dict_el = dict()
|
||||
dict_el = {}
|
||||
dict_el['follow'] = geo.centroid
|
||||
dict_el['solid'] = geo
|
||||
g_obj.apertures[new_apid]['geometry'].append(deepcopy(dict_el))
|
||||
|
||||
s_list = list()
|
||||
s_list = []
|
||||
if g_obj.solid_geometry:
|
||||
try:
|
||||
for poly in g_obj.solid_geometry:
|
||||
|
@ -580,7 +582,7 @@ class ToolFiducials(FlatCAMTool):
|
|||
s_list += geo_list
|
||||
g_obj.solid_geometry = MultiPolygon(s_list)
|
||||
elif fid_type == 'cross':
|
||||
geo_list = list()
|
||||
geo_list = []
|
||||
|
||||
for pt in points_list:
|
||||
x = pt[0]
|
||||
|
@ -599,7 +601,7 @@ class ToolFiducials(FlatCAMTool):
|
|||
aperture_found = ap_id
|
||||
break
|
||||
|
||||
geo_buff_list = list()
|
||||
geo_buff_list = []
|
||||
if aperture_found:
|
||||
for geo in geo_list:
|
||||
geo_buff_h = geo[0].buffer(line_thickness / 2.0)
|
||||
|
@ -607,7 +609,7 @@ class ToolFiducials(FlatCAMTool):
|
|||
geo_buff_list.append(geo_buff_h)
|
||||
geo_buff_list.append(geo_buff_v)
|
||||
|
||||
dict_el = dict()
|
||||
dict_el = {}
|
||||
dict_el['follow'] = geo_buff_h.centroid
|
||||
dict_el['solid'] = geo_buff_h
|
||||
g_obj.apertures[aperture_found]['geometry'].append(deepcopy(dict_el))
|
||||
|
@ -621,10 +623,10 @@ class ToolFiducials(FlatCAMTool):
|
|||
else:
|
||||
new_apid = '10'
|
||||
|
||||
g_obj.apertures[new_apid] = dict()
|
||||
g_obj.apertures[new_apid] = {}
|
||||
g_obj.apertures[new_apid]['type'] = 'C'
|
||||
g_obj.apertures[new_apid]['size'] = line_thickness
|
||||
g_obj.apertures[new_apid]['geometry'] = list()
|
||||
g_obj.apertures[new_apid]['geometry'] = []
|
||||
|
||||
for geo in geo_list:
|
||||
geo_buff_h = geo[0].buffer(line_thickness / 2.0)
|
||||
|
@ -632,7 +634,7 @@ class ToolFiducials(FlatCAMTool):
|
|||
geo_buff_list.append(geo_buff_h)
|
||||
geo_buff_list.append(geo_buff_v)
|
||||
|
||||
dict_el = dict()
|
||||
dict_el = {}
|
||||
dict_el['follow'] = geo_buff_h.centroid
|
||||
dict_el['solid'] = geo_buff_h
|
||||
g_obj.apertures[new_apid]['geometry'].append(deepcopy(dict_el))
|
||||
|
@ -640,7 +642,7 @@ class ToolFiducials(FlatCAMTool):
|
|||
dict_el['solid'] = geo_buff_v
|
||||
g_obj.apertures[new_apid]['geometry'].append(deepcopy(dict_el))
|
||||
|
||||
s_list = list()
|
||||
s_list = []
|
||||
if g_obj.solid_geometry:
|
||||
try:
|
||||
for poly in g_obj.solid_geometry:
|
||||
|
@ -655,7 +657,7 @@ class ToolFiducials(FlatCAMTool):
|
|||
g_obj.solid_geometry = MultiPolygon(s_list)
|
||||
else:
|
||||
# chess pattern fiducial type
|
||||
geo_list = list()
|
||||
geo_list = []
|
||||
|
||||
def make_square_poly(center_pt, side_size):
|
||||
half_s = side_size / 2
|
||||
|
@ -684,12 +686,12 @@ class ToolFiducials(FlatCAMTool):
|
|||
aperture_found = ap_id
|
||||
break
|
||||
|
||||
geo_buff_list = list()
|
||||
geo_buff_list = []
|
||||
if aperture_found:
|
||||
for geo in geo_list:
|
||||
geo_buff_list.append(geo)
|
||||
|
||||
dict_el = dict()
|
||||
dict_el = {}
|
||||
dict_el['follow'] = geo.centroid
|
||||
dict_el['solid'] = geo
|
||||
g_obj.apertures[aperture_found]['geometry'].append(deepcopy(dict_el))
|
||||
|
@ -700,22 +702,22 @@ class ToolFiducials(FlatCAMTool):
|
|||
else:
|
||||
new_apid = '10'
|
||||
|
||||
g_obj.apertures[new_apid] = dict()
|
||||
g_obj.apertures[new_apid] = {}
|
||||
g_obj.apertures[new_apid]['type'] = 'R'
|
||||
g_obj.apertures[new_apid]['size'] = new_ap_size
|
||||
g_obj.apertures[new_apid]['width'] = fid_size
|
||||
g_obj.apertures[new_apid]['height'] = fid_size
|
||||
g_obj.apertures[new_apid]['geometry'] = list()
|
||||
g_obj.apertures[new_apid]['geometry'] = []
|
||||
|
||||
for geo in geo_list:
|
||||
geo_buff_list.append(geo)
|
||||
|
||||
dict_el = dict()
|
||||
dict_el = {}
|
||||
dict_el['follow'] = geo.centroid
|
||||
dict_el['solid'] = geo
|
||||
g_obj.apertures[new_apid]['geometry'].append(deepcopy(dict_el))
|
||||
|
||||
s_list = list()
|
||||
s_list = []
|
||||
if g_obj.solid_geometry:
|
||||
try:
|
||||
for poly in g_obj.solid_geometry:
|
||||
|
|
|
@ -65,15 +65,13 @@ class Film(FlatCAMTool):
|
|||
grid0.setColumnStretch(1, 1)
|
||||
|
||||
# Type of object for which to create the film
|
||||
self.tf_type_obj_combo = QtWidgets.QComboBox()
|
||||
self.tf_type_obj_combo.addItem("Gerber")
|
||||
self.tf_type_obj_combo.addItem("Excellon")
|
||||
self.tf_type_obj_combo.addItem("Geometry")
|
||||
self.tf_type_obj_combo = FCComboBox()
|
||||
self.tf_type_obj_combo.addItems([_("Gerber"), _("Geometry")])
|
||||
|
||||
# we get rid of item1 ("Excellon") as it is not suitable for creating film
|
||||
self.tf_type_obj_combo.view().setRowHidden(1, True)
|
||||
# self.tf_type_obj_combo.view().setRowHidden(1, True)
|
||||
self.tf_type_obj_combo.setItemIcon(0, QtGui.QIcon(self.app.resource_location + "/flatcam_icon16.png"))
|
||||
self.tf_type_obj_combo.setItemIcon(2, QtGui.QIcon(self.app.resource_location + "/geometry16.png"))
|
||||
self.tf_type_obj_combo.setItemIcon(1, QtGui.QIcon(self.app.resource_location + "/geometry16.png"))
|
||||
|
||||
self.tf_type_obj_combo_label = QtWidgets.QLabel('%s:' % _("Object Type"))
|
||||
self.tf_type_obj_combo_label.setToolTip(
|
||||
|
@ -86,10 +84,10 @@ class Film(FlatCAMTool):
|
|||
grid0.addWidget(self.tf_type_obj_combo, 0, 1)
|
||||
|
||||
# List of objects for which we can create the film
|
||||
self.tf_object_combo = QtWidgets.QComboBox()
|
||||
self.tf_object_combo = FCComboBox()
|
||||
self.tf_object_combo.setModel(self.app.collection)
|
||||
self.tf_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.tf_object_combo.setCurrentIndex(1)
|
||||
self.tf_object_combo.is_last = True
|
||||
|
||||
self.tf_object_label = QtWidgets.QLabel('%s:' % _("Film Object"))
|
||||
self.tf_object_label.setToolTip(
|
||||
|
@ -100,15 +98,17 @@ class Film(FlatCAMTool):
|
|||
|
||||
# Type of Box Object to be used as an envelope for film creation
|
||||
# Within this we can create negative
|
||||
self.tf_type_box_combo = QtWidgets.QComboBox()
|
||||
self.tf_type_box_combo.addItem("Gerber")
|
||||
self.tf_type_box_combo.addItem("Excellon")
|
||||
self.tf_type_box_combo.addItem("Geometry")
|
||||
self.tf_type_box_combo = FCComboBox()
|
||||
self.tf_type_box_combo.addItems([_("Gerber"), _("Geometry")])
|
||||
|
||||
# self.tf_type_box_combo.addItem("Gerber")
|
||||
# self.tf_type_box_combo.addItem("Excellon")
|
||||
# self.tf_type_box_combo.addItem("Geometry")
|
||||
|
||||
# we get rid of item1 ("Excellon") as it is not suitable for box when creating film
|
||||
self.tf_type_box_combo.view().setRowHidden(1, True)
|
||||
# self.tf_type_box_combo.view().setRowHidden(1, True)
|
||||
self.tf_type_box_combo.setItemIcon(0, QtGui.QIcon(self.app.resource_location + "/flatcam_icon16.png"))
|
||||
self.tf_type_box_combo.setItemIcon(2, QtGui.QIcon(self.app.resource_location + "/geometry16.png"))
|
||||
self.tf_type_box_combo.setItemIcon(1, QtGui.QIcon(self.app.resource_location + "/geometry16.png"))
|
||||
|
||||
self.tf_type_box_combo_label = QtWidgets.QLabel(_("Box Type:"))
|
||||
self.tf_type_box_combo_label.setToolTip(
|
||||
|
@ -121,10 +121,10 @@ class Film(FlatCAMTool):
|
|||
grid0.addWidget(self.tf_type_box_combo, 2, 1)
|
||||
|
||||
# Box
|
||||
self.tf_box_combo = QtWidgets.QComboBox()
|
||||
self.tf_box_combo = FCComboBox()
|
||||
self.tf_box_combo.setModel(self.app.collection)
|
||||
self.tf_box_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.tf_box_combo.setCurrentIndex(1)
|
||||
self.tf_box_combo.is_last = True
|
||||
|
||||
self.tf_box_combo_label = QtWidgets.QLabel('%s:' % _("Box Object"))
|
||||
self.tf_box_combo_label.setToolTip(
|
||||
|
@ -160,7 +160,7 @@ class Film(FlatCAMTool):
|
|||
grid0.addWidget(self.film_scale_cb, 6, 0, 1, 2)
|
||||
|
||||
self.film_scalex_label = QtWidgets.QLabel('%s:' % _("X factor"))
|
||||
self.film_scalex_entry = FCDoubleSpinner()
|
||||
self.film_scalex_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.film_scalex_entry.set_range(-999.9999, 999.9999)
|
||||
self.film_scalex_entry.set_precision(self.decimals)
|
||||
self.film_scalex_entry.setSingleStep(0.01)
|
||||
|
@ -169,7 +169,7 @@ class Film(FlatCAMTool):
|
|||
grid0.addWidget(self.film_scalex_entry, 7, 1)
|
||||
|
||||
self.film_scaley_label = QtWidgets.QLabel('%s:' % _("Y factor"))
|
||||
self.film_scaley_entry = FCDoubleSpinner()
|
||||
self.film_scaley_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.film_scaley_entry.set_range(-999.9999, 999.9999)
|
||||
self.film_scaley_entry.set_precision(self.decimals)
|
||||
self.film_scaley_entry.setSingleStep(0.01)
|
||||
|
@ -199,7 +199,7 @@ class Film(FlatCAMTool):
|
|||
grid0.addWidget(self.film_skew_cb, 10, 0, 1, 2)
|
||||
|
||||
self.film_skewx_label = QtWidgets.QLabel('%s:' % _("X angle"))
|
||||
self.film_skewx_entry = FCDoubleSpinner()
|
||||
self.film_skewx_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.film_skewx_entry.set_range(-999.9999, 999.9999)
|
||||
self.film_skewx_entry.set_precision(self.decimals)
|
||||
self.film_skewx_entry.setSingleStep(0.01)
|
||||
|
@ -208,7 +208,7 @@ class Film(FlatCAMTool):
|
|||
grid0.addWidget(self.film_skewx_entry, 11, 1)
|
||||
|
||||
self.film_skewy_label = QtWidgets.QLabel('%s:' % _("Y angle"))
|
||||
self.film_skewy_entry = FCDoubleSpinner()
|
||||
self.film_skewy_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.film_skewy_entry.set_range(-999.9999, 999.9999)
|
||||
self.film_skewy_entry.set_precision(self.decimals)
|
||||
self.film_skewy_entry.setSingleStep(0.01)
|
||||
|
@ -275,7 +275,7 @@ class Film(FlatCAMTool):
|
|||
grid0.addWidget(self.film_param_label, 18, 0, 1, 2)
|
||||
|
||||
# Scale Stroke size
|
||||
self.film_scale_stroke_entry = FCDoubleSpinner()
|
||||
self.film_scale_stroke_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.film_scale_stroke_entry.set_range(-999.9999, 999.9999)
|
||||
self.film_scale_stroke_entry.setSingleStep(0.01)
|
||||
self.film_scale_stroke_entry.set_precision(self.decimals)
|
||||
|
@ -308,7 +308,7 @@ class Film(FlatCAMTool):
|
|||
grid0.addWidget(self.film_type, 21, 1)
|
||||
|
||||
# Boundary for negative film generation
|
||||
self.boundary_entry = FCDoubleSpinner()
|
||||
self.boundary_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.boundary_entry.set_range(-999.9999, 999.9999)
|
||||
self.boundary_entry.setSingleStep(0.01)
|
||||
self.boundary_entry.set_precision(self.decimals)
|
||||
|
@ -366,10 +366,12 @@ class Film(FlatCAMTool):
|
|||
self.exc_label.setToolTip(
|
||||
_("Remove the geometry of Excellon from the Film to create the holes in pads.")
|
||||
)
|
||||
self.exc_combo = QtWidgets.QComboBox()
|
||||
self.exc_combo = FCComboBox()
|
||||
self.exc_combo.setModel(self.app.collection)
|
||||
self.exc_combo.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
|
||||
self.exc_combo.setCurrentIndex(1)
|
||||
self.exc_combo.is_last = True
|
||||
self.exc_combo.obj_type = "Excellon"
|
||||
|
||||
punch_grid.addWidget(self.exc_label, 1, 0)
|
||||
punch_grid.addWidget(self.exc_combo, 1, 1)
|
||||
|
||||
|
@ -378,7 +380,7 @@ class Film(FlatCAMTool):
|
|||
|
||||
self.punch_size_label = QtWidgets.QLabel('%s:' % _("Punch Size"))
|
||||
self.punch_size_label.setToolTip(_("The value here will control how big is the punch hole in the pads."))
|
||||
self.punch_size_spinner = FCDoubleSpinner()
|
||||
self.punch_size_spinner = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.punch_size_spinner.set_range(0, 999.9999)
|
||||
self.punch_size_spinner.setSingleStep(0.1)
|
||||
self.punch_size_spinner.set_precision(self.decimals)
|
||||
|
@ -434,7 +436,7 @@ class Film(FlatCAMTool):
|
|||
|
||||
self.pagesize_combo = FCComboBox()
|
||||
|
||||
self.pagesize = dict()
|
||||
self.pagesize = {}
|
||||
self.pagesize.update(
|
||||
{
|
||||
'Bounds': None,
|
||||
|
@ -539,15 +541,21 @@ class Film(FlatCAMTool):
|
|||
self.file_type_radio.activated_custom.connect(self.on_file_type)
|
||||
self.reset_button.clicked.connect(self.set_tool_ui)
|
||||
|
||||
def on_type_obj_index_changed(self, index):
|
||||
def on_type_obj_index_changed(self):
|
||||
obj_type = self.tf_type_obj_combo.currentIndex()
|
||||
self.tf_object_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
|
||||
self.tf_object_combo.setCurrentIndex(0)
|
||||
self.tf_object_combo.obj_type = {
|
||||
_("Gerber"): "Gerber", _("Geometry"): "Geometry"
|
||||
}[self.tf_type_obj_combo.get_value()]
|
||||
|
||||
def on_type_box_index_changed(self, index):
|
||||
def on_type_box_index_changed(self):
|
||||
obj_type = self.tf_type_box_combo.currentIndex()
|
||||
self.tf_box_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
|
||||
self.tf_box_combo.setCurrentIndex(0)
|
||||
self.tf_box_combo.obj_type = {
|
||||
_("Gerber"): "Gerber", _("Geometry"): "Geometry"
|
||||
}[self.tf_type_obj_combo.get_value()]
|
||||
|
||||
def run(self, toggle=True):
|
||||
self.app.report_usage("ToolFilm()")
|
||||
|
@ -610,6 +618,10 @@ class Film(FlatCAMTool):
|
|||
self.orientation_radio.set_value(self.app.defaults["tools_film_orientation"])
|
||||
self.pagesize_combo.set_value(self.app.defaults["tools_film_pagesize"])
|
||||
|
||||
# run once to update the obj_type attribute in the FCCombobox so the last object is showed in cb
|
||||
self.on_type_obj_index_changed()
|
||||
self.on_type_box_index_changed()
|
||||
|
||||
def on_film_type(self, val):
|
||||
type_of_film = val
|
||||
|
||||
|
@ -786,7 +798,7 @@ class Film(FlatCAMTool):
|
|||
|
||||
punch_size = float(self.punch_size_spinner.get_value())
|
||||
|
||||
punching_geo = list()
|
||||
punching_geo = []
|
||||
for apid in film_obj.apertures:
|
||||
if film_obj.apertures[apid]['type'] == 'C':
|
||||
if punch_size >= float(film_obj.apertures[apid]['size']):
|
||||
|
|
|
@ -46,8 +46,7 @@ class ToolImage(FlatCAMTool):
|
|||
|
||||
# Type of object to create for the image
|
||||
self.tf_type_obj_combo = FCComboBox()
|
||||
self.tf_type_obj_combo.addItem("Gerber")
|
||||
self.tf_type_obj_combo.addItem("Geometry")
|
||||
self.tf_type_obj_combo.addItems([_("Gerber"), _("Geometry")])
|
||||
|
||||
self.tf_type_obj_combo.setItemIcon(0, QtGui.QIcon(self.app.resource_location + "/flatcam_icon16.png"))
|
||||
self.tf_type_obj_combo.setItemIcon(1, QtGui.QIcon(self.app.resource_location + "/geometry16.png"))
|
||||
|
@ -61,7 +60,7 @@ class ToolImage(FlatCAMTool):
|
|||
ti_form_layout.addRow(self.tf_type_obj_combo_label, self.tf_type_obj_combo)
|
||||
|
||||
# DPI value of the imported image
|
||||
self.dpi_entry = FCSpinner()
|
||||
self.dpi_entry = FCSpinner(callback=self.confirmation_message_int)
|
||||
self.dpi_entry.set_range(0, 99999)
|
||||
self.dpi_label = QtWidgets.QLabel('%s:' % _("DPI value"))
|
||||
self.dpi_label.setToolTip(_("Specify a DPI value for the image.") )
|
||||
|
@ -87,7 +86,7 @@ class ToolImage(FlatCAMTool):
|
|||
ti2_form_layout.addRow(self.image_type_label, self.image_type)
|
||||
|
||||
# Mask value of the imported image when image monochrome
|
||||
self.mask_bw_entry = FCSpinner()
|
||||
self.mask_bw_entry = FCSpinner(callback=self.confirmation_message_int)
|
||||
self.mask_bw_entry.set_range(0, 255)
|
||||
|
||||
self.mask_bw_label = QtWidgets.QLabel("%s <b>B/W</b>:" % _('Mask value'))
|
||||
|
@ -102,7 +101,7 @@ class ToolImage(FlatCAMTool):
|
|||
ti2_form_layout.addRow(self.mask_bw_label, self.mask_bw_entry)
|
||||
|
||||
# Mask value of the imported image for RED color when image color
|
||||
self.mask_r_entry = FCSpinner()
|
||||
self.mask_r_entry = FCSpinner(callback=self.confirmation_message_int)
|
||||
self.mask_r_entry.set_range(0, 255)
|
||||
|
||||
self.mask_r_label = QtWidgets.QLabel("%s <b>R:</b>" % _('Mask value'))
|
||||
|
@ -115,7 +114,7 @@ class ToolImage(FlatCAMTool):
|
|||
ti2_form_layout.addRow(self.mask_r_label, self.mask_r_entry)
|
||||
|
||||
# Mask value of the imported image for GREEN color when image color
|
||||
self.mask_g_entry = FCSpinner()
|
||||
self.mask_g_entry = FCSpinner(callback=self.confirmation_message_int)
|
||||
self.mask_g_entry.set_range(0, 255)
|
||||
|
||||
self.mask_g_label = QtWidgets.QLabel("%s <b>G:</b>" % _('Mask value'))
|
||||
|
@ -128,7 +127,7 @@ class ToolImage(FlatCAMTool):
|
|||
ti2_form_layout.addRow(self.mask_g_label, self.mask_g_entry)
|
||||
|
||||
# Mask value of the imported image for BLUE color when image color
|
||||
self.mask_b_entry = FCSpinner()
|
||||
self.mask_b_entry = FCSpinner(callback=self.confirmation_message_int)
|
||||
self.mask_b_entry.set_range(0, 255)
|
||||
|
||||
self.mask_b_label = QtWidgets.QLabel("%s <b>B:</b>" % _('Mask value'))
|
||||
|
@ -223,7 +222,7 @@ class ToolImage(FlatCAMTool):
|
|||
:type type_of_obj: str
|
||||
:return: None
|
||||
"""
|
||||
mask = list()
|
||||
mask = []
|
||||
self.app.log.debug("on_file_importimage()")
|
||||
|
||||
_filter = "Image Files(*.BMP *.PNG *.JPG *.JPEG);;" \
|
||||
|
@ -238,7 +237,7 @@ class ToolImage(FlatCAMTool):
|
|||
filename, _f = QtWidgets.QFileDialog.getOpenFileName(caption=_("Import IMAGE"), filter=filter)
|
||||
|
||||
filename = str(filename)
|
||||
type_obj = self.tf_type_obj_combo.get_value().lower()
|
||||
type_obj = self.tf_type_obj_combo.get_value()
|
||||
dpi = self.dpi_entry.get_value()
|
||||
mode = self.image_type.get_value()
|
||||
mask = [self.mask_bw_entry.get_value(), self.mask_r_entry.get_value(), self.mask_g_entry.get_value(),
|
||||
|
@ -250,7 +249,7 @@ class ToolImage(FlatCAMTool):
|
|||
self.app.worker_task.emit({'fcn': self.import_image,
|
||||
'params': [filename, type_obj, dpi, mode, mask]})
|
||||
|
||||
def import_image(self, filename, o_type='gerber', dpi=96, mode='black', mask=None, outname=None):
|
||||
def import_image(self, filename, o_type=_("Gerber"), dpi=96, mode='black', mask=None, outname=None):
|
||||
"""
|
||||
Adds a new Geometry Object to the projects and populates
|
||||
it with shapes extracted from the SVG file.
|
||||
|
@ -269,10 +268,10 @@ class ToolImage(FlatCAMTool):
|
|||
if mask is None:
|
||||
mask = [250, 250, 250, 250]
|
||||
|
||||
if o_type is None or o_type == "geometry":
|
||||
if o_type is None or o_type == _("Geometry"):
|
||||
obj_type = "geometry"
|
||||
elif o_type == "gerber":
|
||||
obj_type = o_type
|
||||
elif o_type == _("Gerber"):
|
||||
obj_type = "gerber"
|
||||
else:
|
||||
self.app.inform.emit('[ERROR_NOTCL] %s' %
|
||||
_("Not supported type is picked as parameter. "
|
||||
|
|
|
@ -0,0 +1,304 @@
|
|||
# ##########################################################
|
||||
# FlatCAM: 2D Post-processing for Manufacturing #
|
||||
# File Author: Marius Adrian Stanciu (c) #
|
||||
# Date: 2/14/2020 #
|
||||
# MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
from PyQt5 import QtWidgets, QtCore
|
||||
|
||||
from FlatCAMTool import FlatCAMTool
|
||||
from flatcamGUI.GUIElements import FCButton, FCDoubleSpinner, RadioSet, FCComboBox
|
||||
|
||||
from shapely.geometry import box
|
||||
|
||||
from copy import deepcopy
|
||||
|
||||
import logging
|
||||
import gettext
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
log = logging.getLogger('base')
|
||||
|
||||
|
||||
class ToolInvertGerber(FlatCAMTool):
|
||||
|
||||
toolName = _("Invert Gerber Tool")
|
||||
|
||||
def __init__(self, app):
|
||||
self.app = app
|
||||
self.decimals = self.app.decimals
|
||||
|
||||
FlatCAMTool.__init__(self, app)
|
||||
|
||||
self.tools_frame = QtWidgets.QFrame()
|
||||
self.tools_frame.setContentsMargins(0, 0, 0, 0)
|
||||
self.layout.addWidget(self.tools_frame)
|
||||
self.tools_box = QtWidgets.QVBoxLayout()
|
||||
self.tools_box.setContentsMargins(0, 0, 0, 0)
|
||||
self.tools_frame.setLayout(self.tools_box)
|
||||
|
||||
# Title
|
||||
title_label = QtWidgets.QLabel("%s" % self.toolName)
|
||||
title_label.setStyleSheet("""
|
||||
QLabel
|
||||
{
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
""")
|
||||
self.tools_box.addWidget(title_label)
|
||||
|
||||
# Grid Layout
|
||||
grid0 = QtWidgets.QGridLayout()
|
||||
grid0.setColumnStretch(0, 0)
|
||||
grid0.setColumnStretch(1, 1)
|
||||
self.tools_box.addLayout(grid0)
|
||||
|
||||
grid0.addWidget(QtWidgets.QLabel(''), 0, 0, 1, 2)
|
||||
|
||||
# Target Gerber Object
|
||||
self.gerber_combo = FCComboBox()
|
||||
self.gerber_combo.setModel(self.app.collection)
|
||||
self.gerber_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.gerber_combo.is_last = True
|
||||
self.gerber_combo.obj_type = "Gerber"
|
||||
|
||||
self.gerber_label = QtWidgets.QLabel('<b>%s:</b>' % _("GERBER"))
|
||||
self.gerber_label.setToolTip(
|
||||
_("Gerber object that will be inverted.")
|
||||
)
|
||||
|
||||
grid0.addWidget(self.gerber_label, 1, 0, 1, 2)
|
||||
grid0.addWidget(self.gerber_combo, 2, 0, 1, 2)
|
||||
|
||||
grid0.addWidget(QtWidgets.QLabel(""), 3, 0, 1, 2)
|
||||
|
||||
self.param_label = QtWidgets.QLabel("<b>%s:</b>" % _("Parameters"))
|
||||
self.param_label.setToolTip('%s.' % _("Parameters for this tool"))
|
||||
|
||||
grid0.addWidget(self.param_label, 4, 0, 1, 2)
|
||||
|
||||
# Margin
|
||||
self.margin_label = QtWidgets.QLabel('%s:' % _('Margin'))
|
||||
self.margin_label.setToolTip(
|
||||
_("Distance by which to avoid\n"
|
||||
"the edges of the Gerber object.")
|
||||
)
|
||||
self.margin_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.margin_entry.set_precision(self.decimals)
|
||||
self.margin_entry.set_range(0.0000, 9999.9999)
|
||||
self.margin_entry.setObjectName(_("Margin"))
|
||||
|
||||
grid0.addWidget(self.margin_label, 5, 0, 1, 2)
|
||||
grid0.addWidget(self.margin_entry, 6, 0, 1, 2)
|
||||
|
||||
self.join_label = QtWidgets.QLabel('%s:' % _("Lines Join Style"))
|
||||
self.join_label.setToolTip(
|
||||
_("The way that the lines in the object outline will be joined.\n"
|
||||
"Can be:\n"
|
||||
"- rounded -> an arc is added between two joining lines\n"
|
||||
"- square -> the lines meet in 90 degrees angle\n"
|
||||
"- bevel -> the lines are joined by a third line")
|
||||
)
|
||||
self.join_radio = RadioSet([
|
||||
{'label': 'Rounded', 'value': 'r'},
|
||||
{'label': 'Square', 'value': 's'},
|
||||
{'label': 'Bevel', 'value': 'b'}
|
||||
], orientation='vertical', stretch=False)
|
||||
|
||||
grid0.addWidget(self.join_label, 7, 0, 1, 2)
|
||||
grid0.addWidget(self.join_radio, 8, 0, 1, 2)
|
||||
|
||||
separator_line = QtWidgets.QFrame()
|
||||
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
grid0.addWidget(separator_line, 9, 0, 1, 2)
|
||||
|
||||
self.invert_btn = FCButton(_('Invert Gerber'))
|
||||
self.invert_btn.setToolTip(
|
||||
_("Will invert the Gerber object: areas that have copper\n"
|
||||
"will be empty of copper and previous empty area will be\n"
|
||||
"filled with copper.")
|
||||
)
|
||||
self.invert_btn.setStyleSheet("""
|
||||
QPushButton
|
||||
{
|
||||
font-weight: bold;
|
||||
}
|
||||
""")
|
||||
grid0.addWidget(self.invert_btn, 10, 0, 1, 2)
|
||||
|
||||
self.tools_box.addStretch()
|
||||
|
||||
# ## Reset Tool
|
||||
self.reset_button = QtWidgets.QPushButton(_("Reset Tool"))
|
||||
self.reset_button.setToolTip(
|
||||
_("Will reset the tool parameters.")
|
||||
)
|
||||
self.reset_button.setStyleSheet("""
|
||||
QPushButton
|
||||
{
|
||||
font-weight: bold;
|
||||
}
|
||||
""")
|
||||
self.tools_box.addWidget(self.reset_button)
|
||||
|
||||
self.invert_btn.clicked.connect(self.on_grb_invert)
|
||||
self.reset_button.clicked.connect(self.set_tool_ui)
|
||||
|
||||
def install(self, icon=None, separator=None, **kwargs):
|
||||
FlatCAMTool.install(self, icon, separator, shortcut='', **kwargs)
|
||||
|
||||
def run(self, toggle=True):
|
||||
self.app.report_usage("ToolInvertGerber()")
|
||||
log.debug("ToolInvertGerber() is running ...")
|
||||
|
||||
if toggle:
|
||||
# if the splitter is hidden, display it, else hide it but only if the current widget is the same
|
||||
if self.app.ui.splitter.sizes()[0] == 0:
|
||||
self.app.ui.splitter.setSizes([1, 1])
|
||||
else:
|
||||
try:
|
||||
if self.app.ui.tool_scroll_area.widget().objectName() == self.toolName:
|
||||
# if tab is populated with the tool but it does not have the focus, focus on it
|
||||
if not self.app.ui.notebook.currentWidget() is self.app.ui.tool_tab:
|
||||
# focus on Tool Tab
|
||||
self.app.ui.notebook.setCurrentWidget(self.app.ui.tool_tab)
|
||||
else:
|
||||
self.app.ui.splitter.setSizes([0, 1])
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
if self.app.ui.splitter.sizes()[0] == 0:
|
||||
self.app.ui.splitter.setSizes([1, 1])
|
||||
|
||||
FlatCAMTool.run(self)
|
||||
self.set_tool_ui()
|
||||
|
||||
self.app.ui.notebook.setTabText(2, _("Invert Tool"))
|
||||
|
||||
def set_tool_ui(self):
|
||||
self.margin_entry.set_value(float(self.app.defaults["tools_invert_margin"]))
|
||||
self.join_radio.set_value(self.app.defaults["tools_invert_join_style"])
|
||||
|
||||
def on_grb_invert(self):
|
||||
margin = self.margin_entry.get_value()
|
||||
if round(margin, self.decimals) == 0.0:
|
||||
margin = 1E-10
|
||||
|
||||
join_style = {'r': 1, 'b': 3, 's': 2}[self.join_radio.get_value()]
|
||||
if join_style is None:
|
||||
join_style = 'r'
|
||||
|
||||
grb_circle_steps = int(self.app.defaults["gerber_circle_steps"])
|
||||
obj_name = self.gerber_combo.currentText()
|
||||
|
||||
outname = obj_name + "_inverted"
|
||||
|
||||
# Get source object.
|
||||
try:
|
||||
grb_obj = self.app.collection.get_by_name(obj_name)
|
||||
except Exception as e:
|
||||
self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Could not retrieve object"), str(obj_name)))
|
||||
return "Could not retrieve object: %s with error: %s" % (obj_name, str(e))
|
||||
|
||||
if grb_obj is None:
|
||||
if obj_name == '':
|
||||
obj_name = 'None'
|
||||
self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Object not found"), str(obj_name)))
|
||||
return
|
||||
|
||||
xmin, ymin, xmax, ymax = grb_obj.bounds()
|
||||
|
||||
grb_box = box(xmin, ymin, xmax, ymax).buffer(margin, resolution=grb_circle_steps, join_style=join_style)
|
||||
|
||||
try:
|
||||
__ = iter(grb_obj.solid_geometry)
|
||||
except TypeError:
|
||||
grb_obj.solid_geometry = list(grb_obj.solid_geometry)
|
||||
|
||||
new_solid_geometry = deepcopy(grb_box)
|
||||
|
||||
for poly in grb_obj.solid_geometry:
|
||||
new_solid_geometry = new_solid_geometry.difference(poly)
|
||||
|
||||
new_options = {}
|
||||
for opt in grb_obj.options:
|
||||
new_options[opt] = deepcopy(grb_obj.options[opt])
|
||||
|
||||
new_apertures = {}
|
||||
|
||||
# for apid, val in grb_obj.apertures.items():
|
||||
# new_apertures[apid] = {}
|
||||
# for key in val:
|
||||
# if key == 'geometry':
|
||||
# new_apertures[apid]['geometry'] = []
|
||||
# for elem in val['geometry']:
|
||||
# geo_elem = {}
|
||||
# if 'follow' in elem:
|
||||
# try:
|
||||
# geo_elem['clear'] = elem['follow'].buffer(val['size'] / 2.0).exterior
|
||||
# except AttributeError:
|
||||
# # TODO should test if width or height is bigger
|
||||
# geo_elem['clear'] = elem['follow'].buffer(val['width'] / 2.0).exterior
|
||||
# if 'clear' in elem:
|
||||
# if isinstance(elem['clear'], Polygon):
|
||||
# try:
|
||||
# geo_elem['solid'] = elem['clear'].buffer(val['size'] / 2.0, grb_circle_steps)
|
||||
# except AttributeError:
|
||||
# # TODO should test if width or height is bigger
|
||||
# geo_elem['solid'] = elem['clear'].buffer(val['width'] / 2.0, grb_circle_steps)
|
||||
# else:
|
||||
# geo_elem['follow'] = elem['clear']
|
||||
# new_apertures[apid]['geometry'].append(deepcopy(geo_elem))
|
||||
# else:
|
||||
# new_apertures[apid][key] = deepcopy(val[key])
|
||||
|
||||
if '0' not in new_apertures:
|
||||
new_apertures['0'] = {}
|
||||
new_apertures['0']['type'] = 'C'
|
||||
new_apertures['0']['size'] = 0.0
|
||||
new_apertures['0']['geometry'] = []
|
||||
|
||||
try:
|
||||
for poly in new_solid_geometry:
|
||||
new_el = {}
|
||||
new_el['solid'] = poly
|
||||
new_el['follow'] = poly.exterior
|
||||
new_apertures['0']['geometry'].append(new_el)
|
||||
except TypeError:
|
||||
new_el = {}
|
||||
new_el['solid'] = new_solid_geometry
|
||||
new_el['follow'] = new_solid_geometry.exterior
|
||||
new_apertures['0']['geometry'].append(new_el)
|
||||
|
||||
for td in new_apertures:
|
||||
print(td, new_apertures[td])
|
||||
|
||||
def init_func(new_obj, app_obj):
|
||||
new_obj.options.update(new_options)
|
||||
new_obj.options['name'] = outname
|
||||
new_obj.fill_color = deepcopy(grb_obj.fill_color)
|
||||
new_obj.outline_color = deepcopy(grb_obj.outline_color)
|
||||
|
||||
new_obj.apertures = deepcopy(new_apertures)
|
||||
|
||||
new_obj.solid_geometry = deepcopy(new_solid_geometry)
|
||||
new_obj.source_file = self.app.export_gerber(obj_name=outname, filename=None,
|
||||
local_use=new_obj, use_thread=False)
|
||||
|
||||
self.app.new_object('gerber', outname, init_func)
|
||||
|
||||
def reset_fields(self):
|
||||
self.gerber_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
|
||||
@staticmethod
|
||||
def poly2rings(poly):
|
||||
return [poly.exterior] + [interior for interior in poly.interiors]
|
||||
# end of file
|
|
@ -188,6 +188,16 @@ class ToolMove(FlatCAMTool):
|
|||
sel_obj.options['ymin'] = b
|
||||
sel_obj.options['xmax'] = c
|
||||
sel_obj.options['ymax'] = d
|
||||
|
||||
# update the source_file with the new positions
|
||||
for sel_obj in obj_list:
|
||||
out_name = sel_obj.options["name"]
|
||||
if sel_obj.kind == 'gerber':
|
||||
sel_obj.source_file = self.app.export_gerber(
|
||||
obj_name=out_name, filename=None, local_use=sel_obj, use_thread=False)
|
||||
elif sel_obj.kind == 'excellon':
|
||||
sel_obj.source_file = self.app.export_excellon(
|
||||
obj_name=out_name, filename=None, local_use=sel_obj, use_thread=False)
|
||||
except Exception as e:
|
||||
log.debug('[ERROR_NOTCL] %s --> %s' % ('ToolMove.on_left_click()', str(e)))
|
||||
return "fail"
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
from PyQt5 import QtWidgets, QtCore, QtGui
|
||||
|
||||
from FlatCAMTool import FlatCAMTool
|
||||
from flatcamGUI.GUIElements import OptionalHideInputSection, FCTextArea, FCEntry, FCSpinner, FCCheckBox
|
||||
from flatcamGUI.GUIElements import OptionalHideInputSection, FCTextArea, FCEntry, FCSpinner, FCCheckBox, FCComboBox
|
||||
from FlatCAMObj import FlatCAMGerber
|
||||
import FlatCAMApp
|
||||
|
||||
|
@ -63,10 +63,11 @@ class ToolOptimal(FlatCAMTool):
|
|||
form_lay.addRow(QtWidgets.QLabel(""))
|
||||
|
||||
# ## Gerber Object to mirror
|
||||
self.gerber_object_combo = QtWidgets.QComboBox()
|
||||
self.gerber_object_combo = FCComboBox()
|
||||
self.gerber_object_combo.setModel(self.app.collection)
|
||||
self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.gerber_object_combo.setCurrentIndex(1)
|
||||
self.gerber_object_combo.is_last = True
|
||||
self.gerber_object_combo.obj_type = "Gerber"
|
||||
|
||||
self.gerber_object_label = QtWidgets.QLabel("<b>%s:</b>" % _("GERBER"))
|
||||
self.gerber_object_label.setToolTip(
|
||||
|
@ -78,7 +79,7 @@ class ToolOptimal(FlatCAMTool):
|
|||
self.precision_label = QtWidgets.QLabel('%s:' % _("Precision"))
|
||||
self.precision_label.setToolTip(_("Number of decimals kept for found distances."))
|
||||
|
||||
self.precision_spinner = FCSpinner()
|
||||
self.precision_spinner = FCSpinner(callback=self.confirmation_message_int)
|
||||
self.precision_spinner.set_range(2, 10)
|
||||
self.precision_spinner.setWrapping(True)
|
||||
form_lay.addRow(self.precision_label, self.precision_spinner)
|
||||
|
@ -259,7 +260,7 @@ class ToolOptimal(FlatCAMTool):
|
|||
|
||||
# dict to hold the distances between every two elements in Gerber as keys and the actual locations where that
|
||||
# distances happen as values
|
||||
self.min_dict = dict()
|
||||
self.min_dict = {}
|
||||
|
||||
# ############################################################################
|
||||
# ############################ Signals #######################################
|
||||
|
@ -282,9 +283,6 @@ class ToolOptimal(FlatCAMTool):
|
|||
def run(self, toggle=True):
|
||||
self.app.report_usage("ToolOptimal()")
|
||||
|
||||
self.result_entry.set_value(0.0)
|
||||
self.freq_entry.set_value('0')
|
||||
|
||||
if toggle:
|
||||
# if the splitter is hidden, display it, else hide it but only if the current widget is the same
|
||||
if self.app.ui.splitter.sizes()[0] == 0:
|
||||
|
@ -310,6 +308,9 @@ class ToolOptimal(FlatCAMTool):
|
|||
self.app.ui.notebook.setTabText(2, _("Optimal Tool"))
|
||||
|
||||
def set_tool_ui(self):
|
||||
self.result_entry.set_value(0.0)
|
||||
self.freq_entry.set_value('0')
|
||||
|
||||
self.precision_spinner.set_value(int(self.app.defaults["tools_opt_precision"]))
|
||||
self.locations_textb.clear()
|
||||
# new cursor - select all document
|
||||
|
@ -354,7 +355,7 @@ class ToolOptimal(FlatCAMTool):
|
|||
old_disp_number = 0
|
||||
pol_nr = 0
|
||||
app_obj.proc_container.update_view_text(' %d%%' % 0)
|
||||
total_geo = list()
|
||||
total_geo = []
|
||||
|
||||
for ap in list(fcobj.apertures.keys()):
|
||||
if 'geometry' in fcobj.apertures[ap]:
|
||||
|
@ -388,7 +389,7 @@ class ToolOptimal(FlatCAMTool):
|
|||
'%s: %s' % (_("Optimal Tool. Finding the distances between each two elements. Iterations"),
|
||||
str(geo_len)))
|
||||
|
||||
self.min_dict = dict()
|
||||
self.min_dict = {}
|
||||
idx = 1
|
||||
for geo in total_geo:
|
||||
for s_geo in total_geo[idx:]:
|
||||
|
|
|
@ -105,7 +105,7 @@ class ToolPDF(FlatCAMTool):
|
|||
self.restore_gs_re = re.compile(r'^.*Q.*$')
|
||||
|
||||
# graphic stack where we save parameters like transformation, line_width
|
||||
self.gs = dict()
|
||||
self.gs = {}
|
||||
# each element is a list composed of sublist elements
|
||||
# (each sublist has 2 lists each having 2 elements: first is offset like:
|
||||
# offset_geo = [off_x, off_y], second element is scale list with 2 elements, like: scale_geo = [sc_x, sc_yy])
|
||||
|
@ -434,12 +434,12 @@ class ToolPDF(FlatCAMTool):
|
|||
traceback.print_exc()
|
||||
|
||||
def parse_pdf(self, pdf_content):
|
||||
path = dict()
|
||||
path = {}
|
||||
path['lines'] = [] # it's a list of lines subpaths
|
||||
path['bezier'] = [] # it's a list of bezier arcs subpaths
|
||||
path['rectangle'] = [] # it's a list of rectangle subpaths
|
||||
|
||||
subpath = dict()
|
||||
subpath = {}
|
||||
subpath['lines'] = [] # it's a list of points
|
||||
subpath['bezier'] = [] # it's a list of sublists each like this [start, c1, c2, stop]
|
||||
subpath['rectangle'] = [] # it's a list of sublists of points
|
||||
|
@ -473,9 +473,9 @@ class ToolPDF(FlatCAMTool):
|
|||
|
||||
# store the apertures with clear geometry here
|
||||
# we are interested only in the circular geometry (drill holes) therefore we target only Bezier subpaths
|
||||
clear_apertures_dict = dict()
|
||||
clear_apertures_dict = {}
|
||||
# everything will be stored in the '0' aperture since we are dealing with clear polygons not strokes
|
||||
clear_apertures_dict['0'] = dict()
|
||||
clear_apertures_dict['0'] = {}
|
||||
clear_apertures_dict['0']['size'] = 0.0
|
||||
clear_apertures_dict['0']['type'] = 'C'
|
||||
clear_apertures_dict['0']['geometry'] = []
|
||||
|
@ -515,7 +515,7 @@ class ToolPDF(FlatCAMTool):
|
|||
apertures_dict.clear()
|
||||
layer_nr += 1
|
||||
|
||||
object_dict[layer_nr] = dict()
|
||||
object_dict[layer_nr] = {}
|
||||
old_color = copy(color)
|
||||
# we make sure that the following geometry is added to the right storage
|
||||
flag_clear_geo = False
|
||||
|
@ -778,7 +778,7 @@ class ToolPDF(FlatCAMTool):
|
|||
if match:
|
||||
# scale the size here; some PDF printers apply transformation after the size is declared
|
||||
applied_size = size * scale_geo[0] * self.point_to_unit_factor
|
||||
path_geo = list()
|
||||
path_geo = []
|
||||
if current_subpath == 'lines':
|
||||
if path['lines']:
|
||||
for subp in path['lines']:
|
||||
|
@ -859,12 +859,12 @@ class ToolPDF(FlatCAMTool):
|
|||
for pdf_geo in path_geo:
|
||||
if isinstance(pdf_geo, MultiPolygon):
|
||||
for poly in pdf_geo:
|
||||
new_el = dict()
|
||||
new_el = {}
|
||||
new_el['solid'] = poly
|
||||
new_el['follow'] = poly.exterior
|
||||
apertures_dict[copy(found_aperture)]['geometry'].append(deepcopy(new_el))
|
||||
else:
|
||||
new_el = dict()
|
||||
new_el = {}
|
||||
new_el['solid'] = pdf_geo
|
||||
new_el['follow'] = pdf_geo.exterior
|
||||
apertures_dict[copy(found_aperture)]['geometry'].append(deepcopy(new_el))
|
||||
|
@ -879,12 +879,12 @@ class ToolPDF(FlatCAMTool):
|
|||
for pdf_geo in path_geo:
|
||||
if isinstance(pdf_geo, MultiPolygon):
|
||||
for poly in pdf_geo:
|
||||
new_el = dict()
|
||||
new_el = {}
|
||||
new_el['solid'] = poly
|
||||
new_el['follow'] = poly.exterior
|
||||
apertures_dict[str(aperture)]['geometry'].append(deepcopy(new_el))
|
||||
else:
|
||||
new_el = dict()
|
||||
new_el = {}
|
||||
new_el['solid'] = pdf_geo
|
||||
new_el['follow'] = pdf_geo.exterior
|
||||
apertures_dict[str(aperture)]['geometry'].append(deepcopy(new_el))
|
||||
|
@ -896,12 +896,12 @@ class ToolPDF(FlatCAMTool):
|
|||
for pdf_geo in path_geo:
|
||||
if isinstance(pdf_geo, MultiPolygon):
|
||||
for poly in pdf_geo:
|
||||
new_el = dict()
|
||||
new_el = {}
|
||||
new_el['solid'] = poly
|
||||
new_el['follow'] = poly.exterior
|
||||
apertures_dict[str(aperture)]['geometry'].append(deepcopy(new_el))
|
||||
else:
|
||||
new_el = dict()
|
||||
new_el = {}
|
||||
new_el['solid'] = pdf_geo
|
||||
new_el['follow'] = pdf_geo.exterior
|
||||
apertures_dict[str(aperture)]['geometry'].append(deepcopy(new_el))
|
||||
|
@ -913,7 +913,7 @@ class ToolPDF(FlatCAMTool):
|
|||
if match:
|
||||
# scale the size here; some PDF printers apply transformation after the size is declared
|
||||
applied_size = size * scale_geo[0] * self.point_to_unit_factor
|
||||
path_geo = list()
|
||||
path_geo = []
|
||||
|
||||
if current_subpath == 'lines':
|
||||
if path['lines']:
|
||||
|
@ -1007,11 +1007,11 @@ class ToolPDF(FlatCAMTool):
|
|||
if path_geo:
|
||||
try:
|
||||
for g in path_geo:
|
||||
new_el = dict()
|
||||
new_el = {}
|
||||
new_el['clear'] = g
|
||||
clear_apertures_dict['0']['geometry'].append(new_el)
|
||||
except TypeError:
|
||||
new_el = dict()
|
||||
new_el = {}
|
||||
new_el['clear'] = path_geo
|
||||
clear_apertures_dict['0']['geometry'].append(new_el)
|
||||
|
||||
|
@ -1022,11 +1022,11 @@ class ToolPDF(FlatCAMTool):
|
|||
for pdf_geo in path_geo:
|
||||
if isinstance(pdf_geo, MultiPolygon):
|
||||
for poly in pdf_geo:
|
||||
new_el = dict()
|
||||
new_el = {}
|
||||
new_el['clear'] = poly
|
||||
apertures_dict['0']['geometry'].append(deepcopy(new_el))
|
||||
else:
|
||||
new_el = dict()
|
||||
new_el = {}
|
||||
new_el['clear'] = pdf_geo
|
||||
apertures_dict['0']['geometry'].append(deepcopy(new_el))
|
||||
except KeyError:
|
||||
|
@ -1038,11 +1038,11 @@ class ToolPDF(FlatCAMTool):
|
|||
for pdf_geo in path_geo:
|
||||
if isinstance(pdf_geo, MultiPolygon):
|
||||
for poly in pdf_geo:
|
||||
new_el = dict()
|
||||
new_el = {}
|
||||
new_el['clear'] = poly
|
||||
apertures_dict['0']['geometry'].append(deepcopy(new_el))
|
||||
else:
|
||||
new_el = dict()
|
||||
new_el = {}
|
||||
new_el['clear'] = pdf_geo
|
||||
apertures_dict['0']['geometry'].append(deepcopy(new_el))
|
||||
else:
|
||||
|
@ -1051,12 +1051,12 @@ class ToolPDF(FlatCAMTool):
|
|||
for pdf_geo in path_geo:
|
||||
if isinstance(pdf_geo, MultiPolygon):
|
||||
for poly in pdf_geo:
|
||||
new_el = dict()
|
||||
new_el = {}
|
||||
new_el['solid'] = poly
|
||||
new_el['follow'] = poly.exterior
|
||||
apertures_dict['0']['geometry'].append(deepcopy(new_el))
|
||||
else:
|
||||
new_el = dict()
|
||||
new_el = {}
|
||||
new_el['solid'] = pdf_geo
|
||||
new_el['follow'] = pdf_geo.exterior
|
||||
apertures_dict['0']['geometry'].append(deepcopy(new_el))
|
||||
|
@ -1069,12 +1069,12 @@ class ToolPDF(FlatCAMTool):
|
|||
for pdf_geo in path_geo:
|
||||
if isinstance(pdf_geo, MultiPolygon):
|
||||
for poly in pdf_geo:
|
||||
new_el = dict()
|
||||
new_el = {}
|
||||
new_el['solid'] = poly
|
||||
new_el['follow'] = poly.exterior
|
||||
apertures_dict['0']['geometry'].append(deepcopy(new_el))
|
||||
else:
|
||||
new_el = dict()
|
||||
new_el = {}
|
||||
new_el['solid'] = pdf_geo
|
||||
new_el['follow'] = pdf_geo.exterior
|
||||
apertures_dict['0']['geometry'].append(deepcopy(new_el))
|
||||
|
@ -1085,8 +1085,8 @@ class ToolPDF(FlatCAMTool):
|
|||
if match:
|
||||
# scale the size here; some PDF printers apply transformation after the size is declared
|
||||
applied_size = size * scale_geo[0] * self.point_to_unit_factor
|
||||
path_geo = list()
|
||||
fill_geo = list()
|
||||
path_geo = []
|
||||
fill_geo = []
|
||||
|
||||
if current_subpath == 'lines':
|
||||
if path['lines']:
|
||||
|
@ -1222,12 +1222,12 @@ class ToolPDF(FlatCAMTool):
|
|||
for pdf_geo in path_geo:
|
||||
if isinstance(pdf_geo, MultiPolygon):
|
||||
for poly in pdf_geo:
|
||||
new_el = dict()
|
||||
new_el = {}
|
||||
new_el['solid'] = poly
|
||||
new_el['follow'] = poly.exterior
|
||||
apertures_dict[copy(found_aperture)]['geometry'].append(deepcopy(new_el))
|
||||
else:
|
||||
new_el = dict()
|
||||
new_el = {}
|
||||
new_el['solid'] = pdf_geo
|
||||
new_el['follow'] = pdf_geo.exterior
|
||||
apertures_dict[copy(found_aperture)]['geometry'].append(deepcopy(new_el))
|
||||
|
@ -1242,12 +1242,12 @@ class ToolPDF(FlatCAMTool):
|
|||
for pdf_geo in path_geo:
|
||||
if isinstance(pdf_geo, MultiPolygon):
|
||||
for poly in pdf_geo:
|
||||
new_el = dict()
|
||||
new_el = {}
|
||||
new_el['solid'] = poly
|
||||
new_el['follow'] = poly.exterior
|
||||
apertures_dict[str(aperture)]['geometry'].append(deepcopy(new_el))
|
||||
else:
|
||||
new_el = dict()
|
||||
new_el = {}
|
||||
new_el['solid'] = pdf_geo
|
||||
new_el['follow'] = pdf_geo.exterior
|
||||
apertures_dict[str(aperture)]['geometry'].append(deepcopy(new_el))
|
||||
|
@ -1259,12 +1259,12 @@ class ToolPDF(FlatCAMTool):
|
|||
for pdf_geo in path_geo:
|
||||
if isinstance(pdf_geo, MultiPolygon):
|
||||
for poly in pdf_geo:
|
||||
new_el = dict()
|
||||
new_el = {}
|
||||
new_el['solid'] = poly
|
||||
new_el['follow'] = poly.exterior
|
||||
apertures_dict[str(aperture)]['geometry'].append(deepcopy(new_el))
|
||||
else:
|
||||
new_el = dict()
|
||||
new_el = {}
|
||||
new_el['solid'] = pdf_geo
|
||||
new_el['follow'] = pdf_geo.exterior
|
||||
apertures_dict[str(aperture)]['geometry'].append(deepcopy(new_el))
|
||||
|
@ -1279,11 +1279,11 @@ class ToolPDF(FlatCAMTool):
|
|||
for pdf_geo in path_geo:
|
||||
if isinstance(pdf_geo, MultiPolygon):
|
||||
for poly in fill_geo:
|
||||
new_el = dict()
|
||||
new_el = {}
|
||||
new_el['clear'] = poly
|
||||
apertures_dict['0']['geometry'].append(deepcopy(new_el))
|
||||
else:
|
||||
new_el = dict()
|
||||
new_el = {}
|
||||
new_el['clear'] = pdf_geo
|
||||
apertures_dict['0']['geometry'].append(deepcopy(new_el))
|
||||
except KeyError:
|
||||
|
@ -1295,11 +1295,11 @@ class ToolPDF(FlatCAMTool):
|
|||
for pdf_geo in fill_geo:
|
||||
if isinstance(pdf_geo, MultiPolygon):
|
||||
for poly in pdf_geo:
|
||||
new_el = dict()
|
||||
new_el = {}
|
||||
new_el['clear'] = poly
|
||||
apertures_dict['0']['geometry'].append(deepcopy(new_el))
|
||||
else:
|
||||
new_el = dict()
|
||||
new_el = {}
|
||||
new_el['clear'] = pdf_geo
|
||||
apertures_dict['0']['geometry'].append(deepcopy(new_el))
|
||||
else:
|
||||
|
@ -1307,12 +1307,12 @@ class ToolPDF(FlatCAMTool):
|
|||
for pdf_geo in path_geo:
|
||||
if isinstance(pdf_geo, MultiPolygon):
|
||||
for poly in fill_geo:
|
||||
new_el = dict()
|
||||
new_el = {}
|
||||
new_el['solid'] = poly
|
||||
new_el['follow'] = poly.exterior
|
||||
apertures_dict['0']['geometry'].append(deepcopy(new_el))
|
||||
else:
|
||||
new_el = dict()
|
||||
new_el = {}
|
||||
new_el['solid'] = pdf_geo
|
||||
new_el['follow'] = pdf_geo.exterior
|
||||
apertures_dict['0']['geometry'].append(deepcopy(new_el))
|
||||
|
@ -1325,12 +1325,12 @@ class ToolPDF(FlatCAMTool):
|
|||
for pdf_geo in fill_geo:
|
||||
if isinstance(pdf_geo, MultiPolygon):
|
||||
for poly in pdf_geo:
|
||||
new_el = dict()
|
||||
new_el = {}
|
||||
new_el['solid'] = poly
|
||||
new_el['follow'] = poly.exterior
|
||||
apertures_dict['0']['geometry'].append(deepcopy(new_el))
|
||||
else:
|
||||
new_el = dict()
|
||||
new_el = {}
|
||||
new_el['solid'] = pdf_geo
|
||||
new_el['follow'] = pdf_geo.exterior
|
||||
apertures_dict['0']['geometry'].append(deepcopy(new_el))
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
from PyQt5 import QtWidgets, QtGui, QtCore
|
||||
from FlatCAMTool import FlatCAMTool
|
||||
|
||||
from flatcamGUI.GUIElements import FCSpinner, FCDoubleSpinner, RadioSet, FCCheckBox, OptionalInputSection
|
||||
from flatcamGUI.GUIElements import FCSpinner, FCDoubleSpinner, RadioSet, FCCheckBox, OptionalInputSection, FCComboBox
|
||||
from FlatCAMObj import FlatCAMGeometry, FlatCAMGerber, FlatCAMExcellon
|
||||
import FlatCAMApp
|
||||
from copy import deepcopy
|
||||
|
@ -49,12 +49,24 @@ class Panelize(FlatCAMTool):
|
|||
""")
|
||||
self.layout.addWidget(title_label)
|
||||
|
||||
self.layout.addWidget(QtWidgets.QLabel(''))
|
||||
|
||||
self.object_label = QtWidgets.QLabel('<b>%s:</b>' % _("Source Object"))
|
||||
self.object_label.setToolTip(
|
||||
_("Specify the type of object to be panelized\n"
|
||||
"It can be of type: Gerber, Excellon or Geometry.\n"
|
||||
"The selection here decide the type of objects that will be\n"
|
||||
"in the Object combobox.")
|
||||
)
|
||||
|
||||
self.layout.addWidget(self.object_label)
|
||||
|
||||
# Form Layout
|
||||
form_layout_0 = QtWidgets.QFormLayout()
|
||||
self.layout.addLayout(form_layout_0)
|
||||
|
||||
# Type of object to be panelized
|
||||
self.type_obj_combo = QtWidgets.QComboBox()
|
||||
self.type_obj_combo = FCComboBox()
|
||||
self.type_obj_combo.addItem("Gerber")
|
||||
self.type_obj_combo.addItem("Excellon")
|
||||
self.type_obj_combo.addItem("Geometry")
|
||||
|
@ -63,27 +75,21 @@ class Panelize(FlatCAMTool):
|
|||
self.type_obj_combo.setItemIcon(1, QtGui.QIcon(self.app.resource_location + "/drill16.png"))
|
||||
self.type_obj_combo.setItemIcon(2, QtGui.QIcon(self.app.resource_location + "/geometry16.png"))
|
||||
|
||||
self.type_obj_combo_label = QtWidgets.QLabel('%s:' % _("Object Type"))
|
||||
self.type_obj_combo_label.setToolTip(
|
||||
_("Specify the type of object to be panelized\n"
|
||||
"It can be of type: Gerber, Excellon or Geometry.\n"
|
||||
"The selection here decide the type of objects that will be\n"
|
||||
"in the Object combobox.")
|
||||
)
|
||||
form_layout_0.addRow(self.type_obj_combo_label, self.type_obj_combo)
|
||||
self.type_object_label = QtWidgets.QLabel('%s:' % _("Object Type"))
|
||||
|
||||
form_layout_0.addRow(self.type_object_label, self.type_obj_combo)
|
||||
|
||||
# Object to be panelized
|
||||
self.object_combo = QtWidgets.QComboBox()
|
||||
self.object_combo = FCComboBox()
|
||||
self.object_combo.setModel(self.app.collection)
|
||||
self.object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.object_combo.setCurrentIndex(1)
|
||||
self.object_combo.is_last = True
|
||||
|
||||
self.object_label = QtWidgets.QLabel('%s:' % _("Object"))
|
||||
self.object_label.setToolTip(
|
||||
self.object_combo.setToolTip(
|
||||
_("Object to be panelized. This means that it will\n"
|
||||
"be duplicated in an array of rows and columns.")
|
||||
)
|
||||
form_layout_0.addRow(self.object_label, self.object_combo)
|
||||
form_layout_0.addRow(self.object_combo)
|
||||
form_layout_0.addRow(QtWidgets.QLabel(""))
|
||||
|
||||
# Form Layout
|
||||
|
@ -108,15 +114,13 @@ class Panelize(FlatCAMTool):
|
|||
form_layout.addRow(self.reference_radio)
|
||||
|
||||
# Type of Box Object to be used as an envelope for panelization
|
||||
self.type_box_combo = QtWidgets.QComboBox()
|
||||
self.type_box_combo.addItem("Gerber")
|
||||
self.type_box_combo.addItem("Excellon")
|
||||
self.type_box_combo.addItem("Geometry")
|
||||
self.type_box_combo = FCComboBox()
|
||||
self.type_box_combo.addItems([_("Gerber"), _("Geometry")])
|
||||
|
||||
# we get rid of item1 ("Excellon") as it is not suitable for use as a "box" for panelizing
|
||||
self.type_box_combo.view().setRowHidden(1, True)
|
||||
# self.type_box_combo.view().setRowHidden(1, True)
|
||||
self.type_box_combo.setItemIcon(0, QtGui.QIcon(self.app.resource_location + "/flatcam_icon16.png"))
|
||||
self.type_box_combo.setItemIcon(2, QtGui.QIcon(self.app.resource_location + "/geometry16.png"))
|
||||
self.type_box_combo.setItemIcon(1, QtGui.QIcon(self.app.resource_location + "/geometry16.png"))
|
||||
|
||||
self.type_box_combo_label = QtWidgets.QLabel('%s:' % _("Box Type"))
|
||||
self.type_box_combo_label.setToolTip(
|
||||
|
@ -128,17 +132,16 @@ class Panelize(FlatCAMTool):
|
|||
form_layout.addRow(self.type_box_combo_label, self.type_box_combo)
|
||||
|
||||
# Box
|
||||
self.box_combo = QtWidgets.QComboBox()
|
||||
self.box_combo = FCComboBox()
|
||||
self.box_combo.setModel(self.app.collection)
|
||||
self.box_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.box_combo.setCurrentIndex(1)
|
||||
self.box_combo.is_last = True
|
||||
|
||||
self.box_combo_label = QtWidgets.QLabel('%s:' % _("Box Object"))
|
||||
self.box_combo_label.setToolTip(
|
||||
self.box_combo.setToolTip(
|
||||
_("The actual object that is used a container for the\n "
|
||||
"selected object that is to be panelized.")
|
||||
)
|
||||
form_layout.addRow(self.box_combo_label, self.box_combo)
|
||||
form_layout.addRow(self.box_combo)
|
||||
form_layout.addRow(QtWidgets.QLabel(""))
|
||||
|
||||
panel_data_label = QtWidgets.QLabel("<b>%s:</b>" % _("Panel Data"))
|
||||
|
@ -153,7 +156,7 @@ class Panelize(FlatCAMTool):
|
|||
form_layout.addRow(panel_data_label)
|
||||
|
||||
# Spacing Columns
|
||||
self.spacing_columns = FCDoubleSpinner()
|
||||
self.spacing_columns = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.spacing_columns.set_range(0, 9999)
|
||||
self.spacing_columns.set_precision(4)
|
||||
|
||||
|
@ -165,7 +168,7 @@ class Panelize(FlatCAMTool):
|
|||
form_layout.addRow(self.spacing_columns_label, self.spacing_columns)
|
||||
|
||||
# Spacing Rows
|
||||
self.spacing_rows = FCDoubleSpinner()
|
||||
self.spacing_rows = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.spacing_rows.set_range(0, 9999)
|
||||
self.spacing_rows.set_precision(4)
|
||||
|
||||
|
@ -177,7 +180,7 @@ class Panelize(FlatCAMTool):
|
|||
form_layout.addRow(self.spacing_rows_label, self.spacing_rows)
|
||||
|
||||
# Columns
|
||||
self.columns = FCSpinner()
|
||||
self.columns = FCSpinner(callback=self.confirmation_message_int)
|
||||
self.columns.set_range(0, 9999)
|
||||
|
||||
self.columns_label = QtWidgets.QLabel('%s:' % _("Columns"))
|
||||
|
@ -187,7 +190,7 @@ class Panelize(FlatCAMTool):
|
|||
form_layout.addRow(self.columns_label, self.columns)
|
||||
|
||||
# Rows
|
||||
self.rows = FCSpinner()
|
||||
self.rows = FCSpinner(callback=self.confirmation_message_int)
|
||||
self.rows.set_range(0, 9999)
|
||||
|
||||
self.rows_label = QtWidgets.QLabel('%s:' % _("Rows"))
|
||||
|
@ -220,7 +223,7 @@ class Panelize(FlatCAMTool):
|
|||
)
|
||||
form_layout.addRow(self.constrain_cb)
|
||||
|
||||
self.x_width_entry = FCDoubleSpinner()
|
||||
self.x_width_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.x_width_entry.set_precision(4)
|
||||
self.x_width_entry.set_range(0, 9999)
|
||||
|
||||
|
@ -231,7 +234,7 @@ class Panelize(FlatCAMTool):
|
|||
)
|
||||
form_layout.addRow(self.x_width_lbl, self.x_width_entry)
|
||||
|
||||
self.y_height_entry = FCDoubleSpinner()
|
||||
self.y_height_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.y_height_entry.set_range(0, 9999)
|
||||
self.y_height_entry.set_precision(4)
|
||||
|
||||
|
@ -358,10 +361,18 @@ class Panelize(FlatCAMTool):
|
|||
self.app.defaults["tools_panelize_panel_type"] else 'gerber'
|
||||
self.panel_type_radio.set_value(panel_type)
|
||||
|
||||
# run once the following so the obj_type attribute is updated in the FCComboBoxes
|
||||
# such that the last loaded object is populated in the combo boxes
|
||||
self.on_type_obj_index_changed()
|
||||
self.on_type_box_index_changed()
|
||||
|
||||
def on_type_obj_index_changed(self):
|
||||
obj_type = self.type_obj_combo.currentIndex()
|
||||
self.object_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
|
||||
self.object_combo.setCurrentIndex(0)
|
||||
self.object_combo.obj_type = {
|
||||
_("Gerber"): "Gerber", _("Excellon"): "Excellon", _("Geometry"): "Geometry"
|
||||
}[self.type_obj_combo.get_value()]
|
||||
|
||||
# hide the panel type for Excellons, the panel can be only of type Geometry
|
||||
if self.type_obj_combo.currentText() != 'Excellon':
|
||||
|
@ -376,18 +387,19 @@ class Panelize(FlatCAMTool):
|
|||
obj_type = self.type_box_combo.currentIndex()
|
||||
self.box_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
|
||||
self.box_combo.setCurrentIndex(0)
|
||||
self.box_combo.obj_type = {
|
||||
_("Gerber"): "Gerber", _("Geometry"): "Geometry"
|
||||
}[self.type_box_combo.get_value()]
|
||||
|
||||
def on_reference_radio_changed(self, current_val):
|
||||
if current_val == 'object':
|
||||
self.type_box_combo.setDisabled(False)
|
||||
self.type_box_combo_label.setDisabled(False)
|
||||
self.box_combo.setDisabled(False)
|
||||
self.box_combo_label.setDisabled(False)
|
||||
else:
|
||||
self.type_box_combo.setDisabled(True)
|
||||
self.type_box_combo_label.setDisabled(True)
|
||||
self.box_combo.setDisabled(True)
|
||||
self.box_combo_label.setDisabled(True)
|
||||
|
||||
def on_panelize(self):
|
||||
name = self.object_combo.currentText()
|
||||
|
@ -470,13 +482,13 @@ class Panelize(FlatCAMTool):
|
|||
|
||||
if isinstance(panel_obj, FlatCAMExcellon) or isinstance(panel_obj, FlatCAMGeometry):
|
||||
# make a copy of the panelized Excellon or Geometry tools
|
||||
copied_tools = dict()
|
||||
copied_tools = {}
|
||||
for tt, tt_val in list(panel_obj.tools.items()):
|
||||
copied_tools[tt] = deepcopy(tt_val)
|
||||
|
||||
if isinstance(panel_obj, FlatCAMGerber):
|
||||
# make a copy of the panelized Gerber apertures
|
||||
copied_apertures = dict()
|
||||
copied_apertures = {}
|
||||
for tt, tt_val in list(panel_obj.apertures.items()):
|
||||
copied_apertures[tt] = deepcopy(tt_val)
|
||||
|
||||
|
@ -574,7 +586,7 @@ class Panelize(FlatCAMTool):
|
|||
|
||||
def translate_recursion(geom):
|
||||
if type(geom) == list:
|
||||
geoms = list()
|
||||
geoms = []
|
||||
for local_geom in geom:
|
||||
res_geo = translate_recursion(local_geom)
|
||||
try:
|
||||
|
@ -597,7 +609,7 @@ class Panelize(FlatCAMTool):
|
|||
elif isinstance(panel_obj, FlatCAMGerber):
|
||||
obj_fin.apertures = copied_apertures
|
||||
for ap in obj_fin.apertures:
|
||||
obj_fin.apertures[ap]['geometry'] = list()
|
||||
obj_fin.apertures[ap]['geometry'] = []
|
||||
|
||||
# find the number of polygons in the source solid_geometry
|
||||
geo_len = 0
|
||||
|
@ -733,7 +745,7 @@ class Panelize(FlatCAMTool):
|
|||
# graceful abort requested by the user
|
||||
raise FlatCAMApp.GracefulException
|
||||
|
||||
new_el = dict()
|
||||
new_el = {}
|
||||
if 'solid' in el:
|
||||
geo_aper = translate_recursion(el['solid'])
|
||||
new_el['solid'] = geo_aper
|
||||
|
|
|
@ -90,7 +90,7 @@ class PcbWizard(FlatCAMTool):
|
|||
self.layout.addLayout(form_layout1)
|
||||
|
||||
# Integral part of the coordinates
|
||||
self.int_entry = FCSpinner()
|
||||
self.int_entry = FCSpinner(callback=self.confirmation_message_int)
|
||||
self.int_entry.set_range(1, 10)
|
||||
self.int_label = QtWidgets.QLabel('%s:' % _("Int. digits"))
|
||||
self.int_label.setToolTip(
|
||||
|
@ -99,7 +99,7 @@ class PcbWizard(FlatCAMTool):
|
|||
form_layout1.addRow(self.int_label, self.int_entry)
|
||||
|
||||
# Fractional part of the coordinates
|
||||
self.frac_entry = FCSpinner()
|
||||
self.frac_entry = FCSpinner(callback=self.confirmation_message_int)
|
||||
self.frac_entry.set_range(1, 10)
|
||||
self.frac_label = QtWidgets.QLabel('%s:' % _("Frac. digits"))
|
||||
self.frac_label.setToolTip(
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
from PyQt5 import QtGui, QtCore, QtWidgets
|
||||
from FlatCAMTool import FlatCAMTool
|
||||
from flatcamGUI.GUIElements import FCTree
|
||||
|
||||
from shapely.geometry import MultiPolygon, Polygon
|
||||
from shapely.ops import cascaded_union
|
||||
|
@ -64,11 +65,7 @@ class Properties(FlatCAMTool):
|
|||
|
||||
self.properties_box.addLayout(self.vlay)
|
||||
|
||||
self.treeWidget = QtWidgets.QTreeWidget()
|
||||
self.treeWidget.setColumnCount(2)
|
||||
self.treeWidget.setHeaderHidden(True)
|
||||
self.treeWidget.header().setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
|
||||
self.treeWidget.setSizePolicy(QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Expanding)
|
||||
self.treeWidget = FCTree(columns=2)
|
||||
|
||||
self.vlay.addWidget(self.treeWidget)
|
||||
self.vlay.setStretch(0, 0)
|
||||
|
@ -132,6 +129,10 @@ class Properties(FlatCAMTool):
|
|||
for obj in obj_list:
|
||||
self.addItems(obj)
|
||||
self.app.inform.emit('[success] %s' % _("Object Properties are displayed."))
|
||||
|
||||
# make sure that the FCTree widget columns are resized to content
|
||||
self.treeWidget.resize_sig.emit()
|
||||
|
||||
self.app.ui.notebook.setTabText(2, _("Properties Tool"))
|
||||
|
||||
def addItems(self, obj):
|
||||
|
@ -146,36 +147,50 @@ class Properties(FlatCAMTool):
|
|||
font.setBold(True)
|
||||
|
||||
# main Items categories
|
||||
obj_type = self.addParent(parent, _('TYPE'), expanded=True, color=QtGui.QColor("#000000"), font=font)
|
||||
obj_name = self.addParent(parent, _('NAME'), expanded=True, color=QtGui.QColor("#000000"), font=font)
|
||||
dims = self.addParent(parent, _('Dimensions'), expanded=True, color=QtGui.QColor("#000000"), font=font)
|
||||
units = self.addParent(parent, _('Units'), expanded=True, color=QtGui.QColor("#000000"), font=font)
|
||||
options = self.addParent(parent, _('Options'), color=QtGui.QColor("#000000"), font=font)
|
||||
obj_type = self.treeWidget.addParent(parent, _('TYPE'), expanded=True, color=QtGui.QColor("#000000"), font=font)
|
||||
obj_name = self.treeWidget.addParent(parent, _('NAME'), expanded=True, color=QtGui.QColor("#000000"), font=font)
|
||||
dims = self.treeWidget.addParent(
|
||||
parent, _('Dimensions'), expanded=True, color=QtGui.QColor("#000000"), font=font)
|
||||
units = self.treeWidget.addParent(parent, _('Units'), expanded=True, color=QtGui.QColor("#000000"), font=font)
|
||||
options = self.treeWidget.addParent(parent, _('Options'), color=QtGui.QColor("#000000"), font=font)
|
||||
|
||||
if obj.kind.lower() == 'gerber':
|
||||
apertures = self.addParent(parent, _('Apertures'), expanded=True, color=QtGui.QColor("#000000"), font=font)
|
||||
apertures = self.treeWidget.addParent(
|
||||
parent, _('Apertures'), expanded=True, color=QtGui.QColor("#000000"), font=font)
|
||||
else:
|
||||
tools = self.addParent(parent, _('Tools'), expanded=True, color=QtGui.QColor("#000000"), font=font)
|
||||
tools = self.treeWidget.addParent(
|
||||
parent, _('Tools'), expanded=True, color=QtGui.QColor("#000000"), font=font)
|
||||
|
||||
if obj.kind.lower() == 'excellon':
|
||||
drills = self.addParent(parent, _('Drills'), expanded=True, color=QtGui.QColor("#000000"), font=font)
|
||||
slots = self.addParent(parent, _('Slots'), expanded=True, color=QtGui.QColor("#000000"), font=font)
|
||||
drills = self.treeWidget.addParent(
|
||||
parent, _('Drills'), expanded=True, color=QtGui.QColor("#000000"), font=font)
|
||||
slots = self.treeWidget.addParent(
|
||||
parent, _('Slots'), expanded=True, color=QtGui.QColor("#000000"), font=font)
|
||||
|
||||
if obj.kind.lower() == 'cncjob':
|
||||
others = self.addParent(parent, _('Others'), expanded=True, color=QtGui.QColor("#000000"), font=font)
|
||||
others = self.treeWidget.addParent(
|
||||
parent, _('Others'), expanded=True, color=QtGui.QColor("#000000"), font=font)
|
||||
|
||||
separator = self.addParent(parent, '')
|
||||
separator = self.treeWidget.addParent(parent, '')
|
||||
|
||||
self.addChild(obj_type, ['%s:' % _('Object Type'), ('%s' % (obj.kind.upper()))], True, font=font, font_items=1)
|
||||
self.treeWidget.addChild(
|
||||
obj_type, ['%s:' % _('Object Type'), ('%s' % (obj.kind.upper()))], True, font=font, font_items=1)
|
||||
try:
|
||||
self.addChild(obj_type,
|
||||
['%s:' % _('Geo Type'),
|
||||
('%s' % ({False: _("Single-Geo"), True: _("Multi-Geo")}[obj.multigeo]))],
|
||||
True)
|
||||
self.treeWidget.addChild(obj_type,
|
||||
[
|
||||
'%s:' % _('Geo Type'),
|
||||
('%s' % (
|
||||
{
|
||||
False: _("Single-Geo"),
|
||||
True: _("Multi-Geo")
|
||||
}[obj.multigeo])
|
||||
)
|
||||
],
|
||||
True)
|
||||
except Exception as e:
|
||||
log.debug("Properties.addItems() --> %s" % str(e))
|
||||
|
||||
self.addChild(obj_name, [obj.options['name']])
|
||||
self.treeWidget.addChild(obj_name, [obj.options['name']])
|
||||
|
||||
def job_thread(obj_prop):
|
||||
proc = self.app.proc_container.new(_("Calculating dimensions ... Please wait."))
|
||||
|
@ -193,8 +208,8 @@ class Properties(FlatCAMTool):
|
|||
|
||||
length = abs(xmax - xmin)
|
||||
width = abs(ymax - ymin)
|
||||
except Exception as e:
|
||||
log.debug("PropertiesTool.addItems() -> calculate dimensions --> %s" % str(e))
|
||||
except Exception as ee:
|
||||
log.debug("PropertiesTool.addItems() -> calculate dimensions --> %s" % str(ee))
|
||||
|
||||
# calculate box area
|
||||
if self.app.defaults['units'].lower() == 'mm':
|
||||
|
@ -266,7 +281,7 @@ class Properties(FlatCAMTool):
|
|||
# calculate copper area
|
||||
|
||||
# create a complete solid_geometry from the tools
|
||||
geo_tools = list()
|
||||
geo_tools = []
|
||||
for tool_k in obj_prop.tools:
|
||||
if 'solid_geometry' in obj_prop.tools[tool_k]:
|
||||
for geo_el in obj_prop.tools[tool_k]['solid_geometry']:
|
||||
|
@ -278,24 +293,27 @@ class Properties(FlatCAMTool):
|
|||
except TypeError:
|
||||
copper_area += geo_tools.area
|
||||
copper_area /= 100
|
||||
except Exception as e:
|
||||
log.debug("Properties.addItems() --> %s" % str(e))
|
||||
except Exception as err:
|
||||
log.debug("Properties.addItems() --> %s" % str(err))
|
||||
|
||||
area_chull = 0.0
|
||||
if obj_prop.kind.lower() != 'cncjob':
|
||||
# calculate and add convex hull area
|
||||
if geo:
|
||||
if isinstance(geo, MultiPolygon):
|
||||
env_obj = geo.convex_hull
|
||||
elif (isinstance(geo, MultiPolygon) and len(geo) == 1) or \
|
||||
(isinstance(geo, list) and len(geo) == 1) and isinstance(geo[0], Polygon):
|
||||
env_obj = cascaded_union(obj_prop.solid_geometry)
|
||||
env_obj = env_obj.convex_hull
|
||||
else:
|
||||
env_obj = cascaded_union(obj_prop.solid_geometry)
|
||||
env_obj = env_obj.convex_hull
|
||||
if isinstance(geo, list) and geo[0] is not None:
|
||||
if isinstance(geo, MultiPolygon):
|
||||
env_obj = geo.convex_hull
|
||||
elif (isinstance(geo, MultiPolygon) and len(geo) == 1) or \
|
||||
(isinstance(geo, list) and len(geo) == 1) and isinstance(geo[0], Polygon):
|
||||
env_obj = cascaded_union(geo)
|
||||
env_obj = env_obj.convex_hull
|
||||
else:
|
||||
env_obj = cascaded_union(geo)
|
||||
env_obj = env_obj.convex_hull
|
||||
|
||||
area_chull = env_obj.area
|
||||
area_chull = env_obj.area
|
||||
else:
|
||||
area_chull = 0
|
||||
else:
|
||||
try:
|
||||
area_chull = []
|
||||
|
@ -303,9 +321,9 @@ class Properties(FlatCAMTool):
|
|||
area_el = cascaded_union(obj_prop.tools[tool_k]['solid_geometry']).convex_hull
|
||||
area_chull.append(area_el.area)
|
||||
area_chull = max(area_chull)
|
||||
except Exception as e:
|
||||
except Exception as er:
|
||||
area_chull = None
|
||||
log.debug("Properties.addItems() --> %s" % str(e))
|
||||
log.debug("Properties.addItems() --> %s" % str(er))
|
||||
|
||||
if self.app.defaults['units'].lower() == 'mm' and area_chull:
|
||||
area_chull = area_chull / 100
|
||||
|
@ -319,7 +337,7 @@ class Properties(FlatCAMTool):
|
|||
|
||||
# Units items
|
||||
f_unit = {'in': _('Inch'), 'mm': _('Metric')}[str(self.app.defaults['units'].lower())]
|
||||
self.addChild(units, ['FlatCAM units:', f_unit], True)
|
||||
self.treeWidget.addChild(units, ['FlatCAM units:', f_unit], True)
|
||||
|
||||
o_unit = {
|
||||
'in': _('Inch'),
|
||||
|
@ -327,17 +345,17 @@ class Properties(FlatCAMTool):
|
|||
'inch': _('Inch'),
|
||||
'metric': _('Metric')
|
||||
}[str(obj.units_found.lower())]
|
||||
self.addChild(units, ['Object units:', o_unit], True)
|
||||
self.treeWidget.addChild(units, ['Object units:', o_unit], True)
|
||||
|
||||
# Options items
|
||||
for option in obj.options:
|
||||
if option is 'name':
|
||||
continue
|
||||
self.addChild(options, [str(option), str(obj.options[option])], True)
|
||||
self.treeWidget.addChild(options, [str(option), str(obj.options[option])], True)
|
||||
|
||||
# Items that depend on the object type
|
||||
if obj.kind.lower() == 'gerber':
|
||||
temp_ap = dict()
|
||||
temp_ap = {}
|
||||
for ap in obj.apertures:
|
||||
temp_ap.clear()
|
||||
temp_ap = deepcopy(obj.apertures[ap])
|
||||
|
@ -363,15 +381,17 @@ class Properties(FlatCAMTool):
|
|||
temp_ap['Follow_Geo'] = '%s LineStrings' % str(follow_nr)
|
||||
temp_ap['Clear_Geo'] = '%s Polygons' % str(clear_nr)
|
||||
|
||||
apid = self.addParent(apertures, str(ap), expanded=False, color=QtGui.QColor("#000000"), font=font)
|
||||
apid = self.treeWidget.addParent(
|
||||
apertures, str(ap), expanded=False, color=QtGui.QColor("#000000"), font=font)
|
||||
for key in temp_ap:
|
||||
self.addChild(apid, [str(key), str(temp_ap[key])], True)
|
||||
self.treeWidget.addChild(apid, [str(key), str(temp_ap[key])], True)
|
||||
elif obj.kind.lower() == 'excellon':
|
||||
tot_drill_cnt = 0
|
||||
tot_slot_cnt = 0
|
||||
|
||||
for tool, value in obj.tools.items():
|
||||
toolid = self.addParent(tools, str(tool), expanded=False, color=QtGui.QColor("#000000"), font=font)
|
||||
toolid = self.treeWidget.addParent(
|
||||
tools, str(tool), expanded=False, color=QtGui.QColor("#000000"), font=font)
|
||||
|
||||
drill_cnt = 0 # variable to store the nr of drills per tool
|
||||
slot_cnt = 0 # variable to store the nr of slots per tool
|
||||
|
@ -390,7 +410,7 @@ class Properties(FlatCAMTool):
|
|||
|
||||
tot_slot_cnt += slot_cnt
|
||||
|
||||
self.addChild(
|
||||
self.treeWidget.addChild(
|
||||
toolid,
|
||||
[
|
||||
_('Diameter'),
|
||||
|
@ -398,52 +418,59 @@ class Properties(FlatCAMTool):
|
|||
],
|
||||
True
|
||||
)
|
||||
self.addChild(toolid, [_('Drills number'), str(drill_cnt)], True)
|
||||
self.addChild(toolid, [_('Slots number'), str(slot_cnt)], True)
|
||||
self.treeWidget.addChild(toolid, [_('Drills number'), str(drill_cnt)], True)
|
||||
self.treeWidget.addChild(toolid, [_('Slots number'), str(slot_cnt)], True)
|
||||
|
||||
self.addChild(drills, [_('Drills total number:'), str(tot_drill_cnt)], True)
|
||||
self.addChild(slots, [_('Slots total number:'), str(tot_slot_cnt)], True)
|
||||
self.treeWidget.addChild(drills, [_('Drills total number:'), str(tot_drill_cnt)], True)
|
||||
self.treeWidget.addChild(slots, [_('Slots total number:'), str(tot_slot_cnt)], True)
|
||||
elif obj.kind.lower() == 'geometry':
|
||||
for tool, value in obj.tools.items():
|
||||
geo_tool = self.addParent(tools, str(tool), expanded=True, color=QtGui.QColor("#000000"), font=font)
|
||||
geo_tool = self.treeWidget.addParent(
|
||||
tools, str(tool), expanded=True, color=QtGui.QColor("#000000"), font=font)
|
||||
for k, v in value.items():
|
||||
if k == 'solid_geometry':
|
||||
printed_value = _('Present') if v else _('None')
|
||||
self.addChild(geo_tool, [str(k), printed_value], True)
|
||||
# printed_value = _('Present') if v else _('None')
|
||||
try:
|
||||
printed_value = str(len(v))
|
||||
except (TypeError, AttributeError):
|
||||
printed_value = '1'
|
||||
self.treeWidget.addChild(geo_tool, [str(k), printed_value], True)
|
||||
elif k == 'data':
|
||||
tool_data = self.addParent(geo_tool, str(k).capitalize(),
|
||||
color=QtGui.QColor("#000000"), font=font)
|
||||
tool_data = self.treeWidget.addParent(
|
||||
geo_tool, str(k).capitalize(), color=QtGui.QColor("#000000"), font=font)
|
||||
for data_k, data_v in v.items():
|
||||
self.addChild(tool_data, [str(data_k), str(data_v)], True)
|
||||
self.treeWidget.addChild(tool_data, [str(data_k), str(data_v)], True)
|
||||
else:
|
||||
self.addChild(geo_tool, [str(k), str(v)], True)
|
||||
self.treeWidget.addChild(geo_tool, [str(k), str(v)], True)
|
||||
elif obj.kind.lower() == 'cncjob':
|
||||
# for cncjob objects made from gerber or geometry
|
||||
for tool, value in obj.cnc_tools.items():
|
||||
geo_tool = self.addParent(tools, str(tool), expanded=True, color=QtGui.QColor("#000000"), font=font)
|
||||
geo_tool = self.treeWidget.addParent(
|
||||
tools, str(tool), expanded=True, color=QtGui.QColor("#000000"), font=font)
|
||||
for k, v in value.items():
|
||||
if k == 'solid_geometry':
|
||||
printed_value = _('Present') if v else _('None')
|
||||
self.addChild(geo_tool, [_("Solid Geometry"), printed_value], True)
|
||||
self.treeWidget.addChild(geo_tool, [_("Solid Geometry"), printed_value], True)
|
||||
elif k == 'gcode':
|
||||
printed_value = _('Present') if v != '' else _('None')
|
||||
self.addChild(geo_tool, [_("GCode Text"), printed_value], True)
|
||||
self.treeWidget.addChild(geo_tool, [_("GCode Text"), printed_value], True)
|
||||
elif k == 'gcode_parsed':
|
||||
printed_value = _('Present') if v else _('None')
|
||||
self.addChild(geo_tool, [_("GCode Geometry"), printed_value], True)
|
||||
self.treeWidget.addChild(geo_tool, [_("GCode Geometry"), printed_value], True)
|
||||
elif k == 'data':
|
||||
tool_data = self.addParent(geo_tool, _("Data"), color=QtGui.QColor("#000000"), font=font)
|
||||
tool_data = self.treeWidget.addParent(
|
||||
geo_tool, _("Data"), color=QtGui.QColor("#000000"), font=font)
|
||||
for data_k, data_v in v.items():
|
||||
self.addChild(tool_data, [str(data_k).capitalize(), str(data_v)], True)
|
||||
self.treeWidget.addChild(tool_data, [str(data_k).capitalize(), str(data_v)], True)
|
||||
else:
|
||||
self.addChild(geo_tool, [str(k), str(v)], True)
|
||||
self.treeWidget.addChild(geo_tool, [str(k), str(v)], True)
|
||||
|
||||
# for cncjob objects made from excellon
|
||||
for tool_dia, value in obj.exc_cnc_tools.items():
|
||||
exc_tool = self.addParent(
|
||||
exc_tool = self.treeWidget.addParent(
|
||||
tools, str(value['tool']), expanded=False, color=QtGui.QColor("#000000"), font=font
|
||||
)
|
||||
self.addChild(
|
||||
self.treeWidget.addChild(
|
||||
exc_tool,
|
||||
[
|
||||
_('Diameter'),
|
||||
|
@ -454,15 +481,15 @@ class Properties(FlatCAMTool):
|
|||
for k, v in value.items():
|
||||
if k == 'solid_geometry':
|
||||
printed_value = _('Present') if v else _('None')
|
||||
self.addChild(exc_tool, [_("Solid Geometry"), printed_value], True)
|
||||
self.treeWidget.addChild(exc_tool, [_("Solid Geometry"), printed_value], True)
|
||||
elif k == 'nr_drills':
|
||||
self.addChild(exc_tool, [_("Drills number"), str(v)], True)
|
||||
self.treeWidget.addChild(exc_tool, [_("Drills number"), str(v)], True)
|
||||
elif k == 'nr_slots':
|
||||
self.addChild(exc_tool, [_("Slots number"), str(v)], True)
|
||||
self.treeWidget.addChild(exc_tool, [_("Slots number"), str(v)], True)
|
||||
else:
|
||||
pass
|
||||
|
||||
self.addChild(
|
||||
self.treeWidget.addChild(
|
||||
exc_tool,
|
||||
[
|
||||
_("Depth of Cut"),
|
||||
|
@ -474,7 +501,7 @@ class Properties(FlatCAMTool):
|
|||
],
|
||||
True
|
||||
)
|
||||
self.addChild(
|
||||
self.treeWidget.addChild(
|
||||
exc_tool,
|
||||
[
|
||||
_("Clearance Height"),
|
||||
|
@ -486,7 +513,7 @@ class Properties(FlatCAMTool):
|
|||
],
|
||||
True
|
||||
)
|
||||
self.addChild(
|
||||
self.treeWidget.addChild(
|
||||
exc_tool,
|
||||
[
|
||||
_("Feedrate"),
|
||||
|
@ -506,14 +533,14 @@ class Properties(FlatCAMTool):
|
|||
r_time *= 60
|
||||
units_lbl = 'sec'
|
||||
r_time = math.ceil(float(r_time))
|
||||
self.addChild(
|
||||
self.treeWidget.addChild(
|
||||
others,
|
||||
[
|
||||
'%s:' % _('Routing time'),
|
||||
'%.*f %s' % (self.decimals, r_time, units_lbl)],
|
||||
True
|
||||
)
|
||||
self.addChild(
|
||||
self.treeWidget.addChild(
|
||||
others,
|
||||
[
|
||||
'%s:' % _('Travelled distance'),
|
||||
|
@ -522,40 +549,17 @@ class Properties(FlatCAMTool):
|
|||
True
|
||||
)
|
||||
|
||||
self.addChild(separator, [''])
|
||||
|
||||
def addParent(self, parent, title, expanded=False, color=None, font=None):
|
||||
item = QtWidgets.QTreeWidgetItem(parent, [title])
|
||||
item.setChildIndicatorPolicy(QtWidgets.QTreeWidgetItem.ShowIndicator)
|
||||
item.setExpanded(expanded)
|
||||
if color is not None:
|
||||
# item.setTextColor(0, color) # PyQt4
|
||||
item.setForeground(0, QtGui.QBrush(color))
|
||||
if font is not None:
|
||||
item.setFont(0, font)
|
||||
return item
|
||||
|
||||
def addChild(self, parent, title, column1=None, font=None, font_items=None):
|
||||
item = QtWidgets.QTreeWidgetItem(parent)
|
||||
item.setText(0, str(title[0]))
|
||||
if column1 is not None:
|
||||
item.setText(1, str(title[1]))
|
||||
if font and font_items:
|
||||
try:
|
||||
for fi in font_items:
|
||||
item.setFont(fi, font)
|
||||
except TypeError:
|
||||
item.setFont(font_items, font)
|
||||
self.treeWidget.addChild(separator, [''])
|
||||
|
||||
def show_area_chull(self, area, length, width, chull_area, copper_area, location):
|
||||
|
||||
# add dimensions
|
||||
self.addChild(
|
||||
self.treeWidget.addChild(
|
||||
location,
|
||||
['%s:' % _('Length'), '%.*f %s' % (self.decimals, length, self.app.defaults['units'].lower())],
|
||||
True
|
||||
)
|
||||
self.addChild(
|
||||
self.treeWidget.addChild(
|
||||
location,
|
||||
['%s:' % _('Width'), '%.*f %s' % (self.decimals, width, self.app.defaults['units'].lower())],
|
||||
True
|
||||
|
@ -563,16 +567,16 @@ class Properties(FlatCAMTool):
|
|||
|
||||
# add box area
|
||||
if self.app.defaults['units'].lower() == 'mm':
|
||||
self.addChild(location, ['%s:' % _('Box Area'), '%.*f %s' % (self.decimals, area, 'cm2')], True)
|
||||
self.addChild(
|
||||
self.treeWidget.addChild(location, ['%s:' % _('Box Area'), '%.*f %s' % (self.decimals, area, 'cm2')], True)
|
||||
self.treeWidget.addChild(
|
||||
location,
|
||||
['%s:' % _('Convex_Hull Area'), '%.*f %s' % (self.decimals, chull_area, 'cm2')],
|
||||
True
|
||||
)
|
||||
|
||||
else:
|
||||
self.addChild(location, ['%s:' % _('Box Area'), '%.*f %s' % (self.decimals, area, 'in2')], True)
|
||||
self.addChild(
|
||||
self.treeWidget.addChild(location, ['%s:' % _('Box Area'), '%.*f %s' % (self.decimals, area, 'in2')], True)
|
||||
self.treeWidget.addChild(
|
||||
location,
|
||||
['%s:' % _('Convex_Hull Area'), '%.*f %s' % (self.decimals, chull_area, 'in2')],
|
||||
True
|
||||
|
@ -580,8 +584,10 @@ class Properties(FlatCAMTool):
|
|||
|
||||
# add copper area
|
||||
if self.app.defaults['units'].lower() == 'mm':
|
||||
self.addChild(location, ['%s:' % _('Copper Area'), '%.*f %s' % (self.decimals, copper_area, 'cm2')], True)
|
||||
self.treeWidget.addChild(
|
||||
location, ['%s:' % _('Copper Area'), '%.*f %s' % (self.decimals, copper_area, 'cm2')], True)
|
||||
else:
|
||||
self.addChild(location, ['%s:' % _('Copper Area'), '%.*f %s' % (self.decimals, copper_area, 'in2')], True)
|
||||
self.treeWidget.addChild(
|
||||
location, ['%s:' % _('Copper Area'), '%.*f %s' % (self.decimals, copper_area, 'in2')], True)
|
||||
|
||||
# end of file
|
||||
|
|
|
@ -0,0 +1,994 @@
|
|||
# ##########################################################
|
||||
# FlatCAM: 2D Post-processing for Manufacturing #
|
||||
# File Author: Marius Adrian Stanciu (c) #
|
||||
# Date: 1/24/2020 #
|
||||
# MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
from PyQt5 import QtCore, QtWidgets
|
||||
|
||||
from FlatCAMTool import FlatCAMTool
|
||||
from flatcamGUI.GUIElements import RadioSet, FCDoubleSpinner, FCCheckBox, FCComboBox
|
||||
|
||||
from copy import deepcopy
|
||||
import logging
|
||||
from shapely.geometry import MultiPolygon, Point
|
||||
|
||||
import gettext
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
log = logging.getLogger('base')
|
||||
|
||||
|
||||
class ToolPunchGerber(FlatCAMTool):
|
||||
|
||||
toolName = _("Punch Gerber")
|
||||
|
||||
def __init__(self, app):
|
||||
FlatCAMTool.__init__(self, app)
|
||||
|
||||
self.decimals = self.app.decimals
|
||||
|
||||
# Title
|
||||
title_label = QtWidgets.QLabel("%s" % self.toolName)
|
||||
title_label.setStyleSheet("""
|
||||
QLabel
|
||||
{
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
""")
|
||||
self.layout.addWidget(title_label)
|
||||
|
||||
# Punch Drill holes
|
||||
self.layout.addWidget(QtWidgets.QLabel(""))
|
||||
|
||||
# ## Grid Layout
|
||||
grid_lay = QtWidgets.QGridLayout()
|
||||
self.layout.addLayout(grid_lay)
|
||||
grid_lay.setColumnStretch(0, 1)
|
||||
grid_lay.setColumnStretch(1, 0)
|
||||
|
||||
# ## Gerber Object
|
||||
self.gerber_object_combo = FCComboBox()
|
||||
self.gerber_object_combo.setModel(self.app.collection)
|
||||
self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.gerber_object_combo.is_last = True
|
||||
self.gerber_object_combo.obj_type = "Gerber"
|
||||
|
||||
self.grb_label = QtWidgets.QLabel("<b>%s:</b>" % _("GERBER"))
|
||||
self.grb_label.setToolTip('%s.' % _("Gerber into which to punch holes"))
|
||||
|
||||
grid_lay.addWidget(self.grb_label, 0, 0, 1, 2)
|
||||
grid_lay.addWidget(self.gerber_object_combo, 1, 0, 1, 2)
|
||||
|
||||
separator_line = QtWidgets.QFrame()
|
||||
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
grid_lay.addWidget(separator_line, 2, 0, 1, 2)
|
||||
|
||||
self.padt_label = QtWidgets.QLabel("<b>%s</b>" % _("Processed Pads Type"))
|
||||
self.padt_label.setToolTip(
|
||||
_("The type of pads shape to be processed.\n"
|
||||
"If the PCB has many SMD pads with rectangular pads,\n"
|
||||
"disable the Rectangular aperture.")
|
||||
)
|
||||
|
||||
grid_lay.addWidget(self.padt_label, 3, 0, 1, 2)
|
||||
|
||||
# Select all
|
||||
self.select_all_cb = FCCheckBox('%s' % _("ALL"))
|
||||
grid_lay.addWidget(self.select_all_cb)
|
||||
|
||||
# Circular Aperture Selection
|
||||
self.circular_cb = FCCheckBox('%s' % _("Circular"))
|
||||
self.circular_cb.setToolTip(
|
||||
_("Process Circular Pads.")
|
||||
)
|
||||
|
||||
grid_lay.addWidget(self.circular_cb, 5, 0, 1, 2)
|
||||
|
||||
# Oblong Aperture Selection
|
||||
self.oblong_cb = FCCheckBox('%s' % _("Oblong"))
|
||||
self.oblong_cb.setToolTip(
|
||||
_("Process Oblong Pads.")
|
||||
)
|
||||
|
||||
grid_lay.addWidget(self.oblong_cb, 6, 0, 1, 2)
|
||||
|
||||
# Square Aperture Selection
|
||||
self.square_cb = FCCheckBox('%s' % _("Square"))
|
||||
self.square_cb.setToolTip(
|
||||
_("Process Square Pads.")
|
||||
)
|
||||
|
||||
grid_lay.addWidget(self.square_cb, 7, 0, 1, 2)
|
||||
|
||||
# Rectangular Aperture Selection
|
||||
self.rectangular_cb = FCCheckBox('%s' % _("Rectangular"))
|
||||
self.rectangular_cb.setToolTip(
|
||||
_("Process Rectangular Pads.")
|
||||
)
|
||||
|
||||
grid_lay.addWidget(self.rectangular_cb, 8, 0, 1, 2)
|
||||
|
||||
# Others type of Apertures Selection
|
||||
self.other_cb = FCCheckBox('%s' % _("Others"))
|
||||
self.other_cb.setToolTip(
|
||||
_("Process pads not in the categories above.")
|
||||
)
|
||||
|
||||
grid_lay.addWidget(self.other_cb, 9, 0, 1, 2)
|
||||
|
||||
separator_line = QtWidgets.QFrame()
|
||||
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
grid_lay.addWidget(separator_line, 10, 0, 1, 2)
|
||||
|
||||
# Grid Layout
|
||||
grid0 = QtWidgets.QGridLayout()
|
||||
self.layout.addLayout(grid0)
|
||||
grid0.setColumnStretch(0, 0)
|
||||
grid0.setColumnStretch(1, 1)
|
||||
|
||||
self.method_label = QtWidgets.QLabel('<b>%s:</b>' % _("Method"))
|
||||
self.method_label.setToolTip(
|
||||
_("The punch hole source can be:\n"
|
||||
"- Excellon Object-> the Excellon object drills center will serve as reference.\n"
|
||||
"- Fixed Diameter -> will try to use the pads center as reference adding fixed diameter holes.\n"
|
||||
"- Fixed Annular Ring -> will try to keep a set annular ring.\n"
|
||||
"- Proportional -> will make a Gerber punch hole having the diameter a percentage of the pad diameter.\n")
|
||||
)
|
||||
self.method_punch = RadioSet(
|
||||
[
|
||||
{'label': _('Excellon'), 'value': 'exc'},
|
||||
{'label': _("Fixed Diameter"), 'value': 'fixed'},
|
||||
{'label': _("Fixed Annular Ring"), 'value': 'ring'},
|
||||
{'label': _("Proportional"), 'value': 'prop'}
|
||||
],
|
||||
orientation='vertical',
|
||||
stretch=False)
|
||||
grid0.addWidget(self.method_label, 0, 0, 1, 2)
|
||||
grid0.addWidget(self.method_punch, 1, 0, 1, 2)
|
||||
|
||||
separator_line = QtWidgets.QFrame()
|
||||
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
grid0.addWidget(separator_line, 2, 0, 1, 2)
|
||||
|
||||
self.exc_label = QtWidgets.QLabel('<b>%s</b>' % _("Excellon"))
|
||||
self.exc_label.setToolTip(
|
||||
_("Remove the geometry of Excellon from the Gerber to create the holes in pads.")
|
||||
)
|
||||
|
||||
self.exc_combo = FCComboBox()
|
||||
self.exc_combo.setModel(self.app.collection)
|
||||
self.exc_combo.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
|
||||
self.exc_combo.is_last = True
|
||||
self.exc_combo.obj_type = "Excellon"
|
||||
|
||||
grid0.addWidget(self.exc_label, 3, 0, 1, 2)
|
||||
grid0.addWidget(self.exc_combo, 4, 0, 1, 2)
|
||||
|
||||
separator_line = QtWidgets.QFrame()
|
||||
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
grid0.addWidget(separator_line, 5, 0, 1, 2)
|
||||
|
||||
# Fixed Dia
|
||||
self.fixed_label = QtWidgets.QLabel('<b>%s</b>' % _("Fixed Diameter"))
|
||||
grid0.addWidget(self.fixed_label, 6, 0, 1, 2)
|
||||
|
||||
# Diameter value
|
||||
self.dia_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.dia_entry.set_precision(self.decimals)
|
||||
self.dia_entry.set_range(0.0000, 9999.9999)
|
||||
|
||||
self.dia_label = QtWidgets.QLabel('%s:' % _("Value"))
|
||||
self.dia_label.setToolTip(
|
||||
_("Fixed hole diameter.")
|
||||
)
|
||||
|
||||
grid0.addWidget(self.dia_label, 8, 0)
|
||||
grid0.addWidget(self.dia_entry, 8, 1)
|
||||
|
||||
separator_line = QtWidgets.QFrame()
|
||||
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
grid0.addWidget(separator_line, 9, 0, 1, 2)
|
||||
|
||||
self.ring_frame = QtWidgets.QFrame()
|
||||
self.ring_frame.setContentsMargins(0, 0, 0, 0)
|
||||
grid0.addWidget(self.ring_frame, 10, 0, 1, 2)
|
||||
|
||||
self.ring_box = QtWidgets.QVBoxLayout()
|
||||
self.ring_box.setContentsMargins(0, 0, 0, 0)
|
||||
self.ring_frame.setLayout(self.ring_box)
|
||||
|
||||
# Annular Ring value
|
||||
self.ring_label = QtWidgets.QLabel('<b>%s</b>' % _("Fixed Annular Ring"))
|
||||
self.ring_label.setToolTip(
|
||||
_("The size of annular ring.\n"
|
||||
"The copper sliver between the hole exterior\n"
|
||||
"and the margin of the copper pad.")
|
||||
)
|
||||
self.ring_box.addWidget(self.ring_label)
|
||||
|
||||
# ## Grid Layout
|
||||
self.grid1 = QtWidgets.QGridLayout()
|
||||
self.grid1.setColumnStretch(0, 0)
|
||||
self.grid1.setColumnStretch(1, 1)
|
||||
self.ring_box.addLayout(self.grid1)
|
||||
|
||||
# Circular Annular Ring Value
|
||||
self.circular_ring_label = QtWidgets.QLabel('%s:' % _("Circular"))
|
||||
self.circular_ring_label.setToolTip(
|
||||
_("The size of annular ring for circular pads.")
|
||||
)
|
||||
|
||||
self.circular_ring_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.circular_ring_entry.set_precision(self.decimals)
|
||||
self.circular_ring_entry.set_range(0.0000, 9999.9999)
|
||||
|
||||
self.grid1.addWidget(self.circular_ring_label, 3, 0)
|
||||
self.grid1.addWidget(self.circular_ring_entry, 3, 1)
|
||||
|
||||
# Oblong Annular Ring Value
|
||||
self.oblong_ring_label = QtWidgets.QLabel('%s:' % _("Oblong"))
|
||||
self.oblong_ring_label.setToolTip(
|
||||
_("The size of annular ring for oblong pads.")
|
||||
)
|
||||
|
||||
self.oblong_ring_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.oblong_ring_entry.set_precision(self.decimals)
|
||||
self.oblong_ring_entry.set_range(0.0000, 9999.9999)
|
||||
|
||||
self.grid1.addWidget(self.oblong_ring_label, 4, 0)
|
||||
self.grid1.addWidget(self.oblong_ring_entry, 4, 1)
|
||||
|
||||
# Square Annular Ring Value
|
||||
self.square_ring_label = QtWidgets.QLabel('%s:' % _("Square"))
|
||||
self.square_ring_label.setToolTip(
|
||||
_("The size of annular ring for square pads.")
|
||||
)
|
||||
|
||||
self.square_ring_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.square_ring_entry.set_precision(self.decimals)
|
||||
self.square_ring_entry.set_range(0.0000, 9999.9999)
|
||||
|
||||
self.grid1.addWidget(self.square_ring_label, 5, 0)
|
||||
self.grid1.addWidget(self.square_ring_entry, 5, 1)
|
||||
|
||||
# Rectangular Annular Ring Value
|
||||
self.rectangular_ring_label = QtWidgets.QLabel('%s:' % _("Rectangular"))
|
||||
self.rectangular_ring_label.setToolTip(
|
||||
_("The size of annular ring for rectangular pads.")
|
||||
)
|
||||
|
||||
self.rectangular_ring_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.rectangular_ring_entry.set_precision(self.decimals)
|
||||
self.rectangular_ring_entry.set_range(0.0000, 9999.9999)
|
||||
|
||||
self.grid1.addWidget(self.rectangular_ring_label, 6, 0)
|
||||
self.grid1.addWidget(self.rectangular_ring_entry, 6, 1)
|
||||
|
||||
# Others Annular Ring Value
|
||||
self.other_ring_label = QtWidgets.QLabel('%s:' % _("Others"))
|
||||
self.other_ring_label.setToolTip(
|
||||
_("The size of annular ring for other pads.")
|
||||
)
|
||||
|
||||
self.other_ring_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.other_ring_entry.set_precision(self.decimals)
|
||||
self.other_ring_entry.set_range(0.0000, 9999.9999)
|
||||
|
||||
self.grid1.addWidget(self.other_ring_label, 7, 0)
|
||||
self.grid1.addWidget(self.other_ring_entry, 7, 1)
|
||||
|
||||
separator_line = QtWidgets.QFrame()
|
||||
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
grid0.addWidget(separator_line, 11, 0, 1, 2)
|
||||
|
||||
# Proportional value
|
||||
self.prop_label = QtWidgets.QLabel('<b>%s</b>' % _("Proportional Diameter"))
|
||||
grid0.addWidget(self.prop_label, 12, 0, 1, 2)
|
||||
|
||||
# Diameter value
|
||||
self.factor_entry = FCDoubleSpinner(callback=self.confirmation_message, suffix='%')
|
||||
self.factor_entry.set_precision(self.decimals)
|
||||
self.factor_entry.set_range(0.0000, 100.0000)
|
||||
self.factor_entry.setSingleStep(0.1)
|
||||
|
||||
self.factor_label = QtWidgets.QLabel('%s:' % _("Value"))
|
||||
self.factor_label.setToolTip(
|
||||
_("Proportional Diameter.\n"
|
||||
"The hole diameter will be a fraction of the pad size.")
|
||||
)
|
||||
|
||||
grid0.addWidget(self.factor_label, 13, 0)
|
||||
grid0.addWidget(self.factor_entry, 13, 1)
|
||||
|
||||
separator_line3 = QtWidgets.QFrame()
|
||||
separator_line3.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
separator_line3.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
grid0.addWidget(separator_line3, 14, 0, 1, 2)
|
||||
|
||||
# Buttons
|
||||
self.punch_object_button = QtWidgets.QPushButton(_("Punch Gerber"))
|
||||
self.punch_object_button.setToolTip(
|
||||
_("Create a Gerber object from the selected object, within\n"
|
||||
"the specified box.")
|
||||
)
|
||||
self.punch_object_button.setStyleSheet("""
|
||||
QPushButton
|
||||
{
|
||||
font-weight: bold;
|
||||
}
|
||||
""")
|
||||
self.layout.addWidget(self.punch_object_button)
|
||||
|
||||
self.layout.addStretch()
|
||||
|
||||
# ## Reset Tool
|
||||
self.reset_button = QtWidgets.QPushButton(_("Reset Tool"))
|
||||
self.reset_button.setToolTip(
|
||||
_("Will reset the tool parameters.")
|
||||
)
|
||||
self.reset_button.setStyleSheet("""
|
||||
QPushButton
|
||||
{
|
||||
font-weight: bold;
|
||||
}
|
||||
""")
|
||||
self.layout.addWidget(self.reset_button)
|
||||
|
||||
self.units = self.app.defaults['units']
|
||||
|
||||
# self.cb_items = [
|
||||
# self.grid1.itemAt(w).widget() for w in range(self.grid1.count())
|
||||
# if isinstance(self.grid1.itemAt(w).widget(), FCCheckBox)
|
||||
# ]
|
||||
|
||||
self.circular_ring_entry.setEnabled(False)
|
||||
self.oblong_ring_entry.setEnabled(False)
|
||||
self.square_ring_entry.setEnabled(False)
|
||||
self.rectangular_ring_entry.setEnabled(False)
|
||||
self.other_ring_entry.setEnabled(False)
|
||||
|
||||
self.dia_entry.setDisabled(True)
|
||||
self.dia_label.setDisabled(True)
|
||||
self.factor_label.setDisabled(True)
|
||||
self.factor_entry.setDisabled(True)
|
||||
|
||||
# ## Signals
|
||||
self.method_punch.activated_custom.connect(self.on_method)
|
||||
self.reset_button.clicked.connect(self.set_tool_ui)
|
||||
self.punch_object_button.clicked.connect(self.on_generate_object)
|
||||
|
||||
self.circular_cb.stateChanged.connect(
|
||||
lambda state:
|
||||
self.circular_ring_entry.setDisabled(False) if state else self.circular_ring_entry.setDisabled(True)
|
||||
)
|
||||
|
||||
self.oblong_cb.stateChanged.connect(
|
||||
lambda state:
|
||||
self.oblong_ring_entry.setDisabled(False) if state else self.oblong_ring_entry.setDisabled(True)
|
||||
)
|
||||
|
||||
self.square_cb.stateChanged.connect(
|
||||
lambda state:
|
||||
self.square_ring_entry.setDisabled(False) if state else self.square_ring_entry.setDisabled(True)
|
||||
)
|
||||
|
||||
self.rectangular_cb.stateChanged.connect(
|
||||
lambda state:
|
||||
self.rectangular_ring_entry.setDisabled(False) if state else self.rectangular_ring_entry.setDisabled(True)
|
||||
)
|
||||
|
||||
self.other_cb.stateChanged.connect(
|
||||
lambda state:
|
||||
self.other_ring_entry.setDisabled(False) if state else self.other_ring_entry.setDisabled(True)
|
||||
)
|
||||
|
||||
def run(self, toggle=True):
|
||||
self.app.report_usage("ToolPunchGerber()")
|
||||
|
||||
if toggle:
|
||||
# if the splitter is hidden, display it, else hide it but only if the current widget is the same
|
||||
if self.app.ui.splitter.sizes()[0] == 0:
|
||||
self.app.ui.splitter.setSizes([1, 1])
|
||||
else:
|
||||
try:
|
||||
if self.app.ui.tool_scroll_area.widget().objectName() == self.toolName:
|
||||
# if tab is populated with the tool but it does not have the focus, focus on it
|
||||
if not self.app.ui.notebook.currentWidget() is self.app.ui.tool_tab:
|
||||
# focus on Tool Tab
|
||||
self.app.ui.notebook.setCurrentWidget(self.app.ui.tool_tab)
|
||||
else:
|
||||
self.app.ui.splitter.setSizes([0, 1])
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
if self.app.ui.splitter.sizes()[0] == 0:
|
||||
self.app.ui.splitter.setSizes([1, 1])
|
||||
|
||||
FlatCAMTool.run(self)
|
||||
|
||||
self.set_tool_ui()
|
||||
|
||||
self.app.ui.notebook.setTabText(2, _("Punch Tool"))
|
||||
|
||||
def install(self, icon=None, separator=None, **kwargs):
|
||||
FlatCAMTool.install(self, icon, separator, shortcut='ALT+H', **kwargs)
|
||||
|
||||
def set_tool_ui(self):
|
||||
self.reset_fields()
|
||||
|
||||
self.ui_connect()
|
||||
self.method_punch.set_value(self.app.defaults["tools_punch_hole_type"])
|
||||
self.select_all_cb.set_value(False)
|
||||
|
||||
self.dia_entry.set_value(float(self.app.defaults["tools_punch_hole_fixed_dia"]))
|
||||
|
||||
self.circular_ring_entry.set_value(float(self.app.defaults["tools_punch_circular_ring"]))
|
||||
self.oblong_ring_entry.set_value(float(self.app.defaults["tools_punch_oblong_ring"]))
|
||||
self.square_ring_entry.set_value(float(self.app.defaults["tools_punch_square_ring"]))
|
||||
self.rectangular_ring_entry.set_value(float(self.app.defaults["tools_punch_rectangular_ring"]))
|
||||
self.other_ring_entry.set_value(float(self.app.defaults["tools_punch_others_ring"]))
|
||||
|
||||
self.circular_cb.set_value(self.app.defaults["tools_punch_circular"])
|
||||
self.oblong_cb.set_value(self.app.defaults["tools_punch_oblong"])
|
||||
self.square_cb.set_value(self.app.defaults["tools_punch_square"])
|
||||
self.rectangular_cb.set_value(self.app.defaults["tools_punch_rectangular"])
|
||||
self.other_cb.set_value(self.app.defaults["tools_punch_others"])
|
||||
|
||||
self.factor_entry.set_value(float(self.app.defaults["tools_punch_hole_prop_factor"]))
|
||||
|
||||
def on_select_all(self, state):
|
||||
self.ui_disconnect()
|
||||
if state:
|
||||
self.circular_cb.setChecked(True)
|
||||
self.oblong_cb.setChecked(True)
|
||||
self.square_cb.setChecked(True)
|
||||
self.rectangular_cb.setChecked(True)
|
||||
self.other_cb.setChecked(True)
|
||||
else:
|
||||
self.circular_cb.setChecked(False)
|
||||
self.oblong_cb.setChecked(False)
|
||||
self.square_cb.setChecked(False)
|
||||
self.rectangular_cb.setChecked(False)
|
||||
self.other_cb.setChecked(False)
|
||||
self.ui_connect()
|
||||
|
||||
def on_method(self, val):
|
||||
self.exc_label.setEnabled(False)
|
||||
self.exc_combo.setEnabled(False)
|
||||
self.fixed_label.setEnabled(False)
|
||||
self.dia_label.setEnabled(False)
|
||||
self.dia_entry.setEnabled(False)
|
||||
self.ring_frame.setEnabled(False)
|
||||
self.prop_label.setEnabled(False)
|
||||
self.factor_label.setEnabled(False)
|
||||
self.factor_entry.setEnabled(False)
|
||||
|
||||
if val == 'exc':
|
||||
self.exc_label.setEnabled(True)
|
||||
self.exc_combo.setEnabled(True)
|
||||
elif val == 'fixed':
|
||||
self.fixed_label.setEnabled(True)
|
||||
self.dia_label.setEnabled(True)
|
||||
self.dia_entry.setEnabled(True)
|
||||
elif val == 'ring':
|
||||
self.ring_frame.setEnabled(True)
|
||||
elif val == 'prop':
|
||||
self.prop_label.setEnabled(True)
|
||||
self.factor_label.setEnabled(True)
|
||||
self.factor_entry.setEnabled(True)
|
||||
|
||||
def ui_connect(self):
|
||||
self.select_all_cb.stateChanged.connect(self.on_select_all)
|
||||
|
||||
def ui_disconnect(self):
|
||||
try:
|
||||
self.select_all_cb.stateChanged.disconnect()
|
||||
except (AttributeError, TypeError):
|
||||
pass
|
||||
|
||||
def on_generate_object(self):
|
||||
|
||||
# get the Gerber file who is the source of the punched Gerber
|
||||
selection_index = self.gerber_object_combo.currentIndex()
|
||||
model_index = self.app.collection.index(selection_index, 0, self.gerber_object_combo.rootModelIndex())
|
||||
|
||||
try:
|
||||
grb_obj = model_index.internalPointer().obj
|
||||
except Exception:
|
||||
self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Gerber object loaded ..."))
|
||||
return
|
||||
|
||||
name = grb_obj.options['name'].rpartition('.')[0]
|
||||
outname = name + "_punched"
|
||||
|
||||
punch_method = self.method_punch.get_value()
|
||||
|
||||
new_options = {}
|
||||
for opt in grb_obj.options:
|
||||
new_options[opt] = deepcopy(grb_obj.options[opt])
|
||||
|
||||
if punch_method == 'exc':
|
||||
|
||||
# get the Excellon file whose geometry will create the punch holes
|
||||
selection_index = self.exc_combo.currentIndex()
|
||||
model_index = self.app.collection.index(selection_index, 0, self.exc_combo.rootModelIndex())
|
||||
|
||||
try:
|
||||
exc_obj = model_index.internalPointer().obj
|
||||
except Exception:
|
||||
self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Excellon object loaded ..."))
|
||||
return
|
||||
|
||||
# this is the punching geometry
|
||||
exc_solid_geometry = MultiPolygon(exc_obj.solid_geometry)
|
||||
if isinstance(grb_obj.solid_geometry, list):
|
||||
grb_solid_geometry = MultiPolygon(grb_obj.solid_geometry)
|
||||
else:
|
||||
grb_solid_geometry = grb_obj.solid_geometry
|
||||
|
||||
# create the punched Gerber solid_geometry
|
||||
punched_solid_geometry = grb_solid_geometry.difference(exc_solid_geometry)
|
||||
|
||||
# update the gerber apertures to include the clear geometry so it can be exported successfully
|
||||
new_apertures = deepcopy(grb_obj.apertures)
|
||||
new_apertures_items = new_apertures.items()
|
||||
|
||||
# find maximum aperture id
|
||||
new_apid = max([int(x) for x, __ in new_apertures_items])
|
||||
|
||||
# store here the clear geometry, the key is the drill size
|
||||
holes_apertures = {}
|
||||
|
||||
for apid, val in new_apertures_items:
|
||||
for elem in val['geometry']:
|
||||
# make it work only for Gerber Flashes who are Points in 'follow'
|
||||
if 'solid' in elem and isinstance(elem['follow'], Point):
|
||||
for drill in exc_obj.drills:
|
||||
clear_apid_size = exc_obj.tools[drill['tool']]['C']
|
||||
|
||||
# since there may be drills that do not drill into a pad we test only for drills in a pad
|
||||
if drill['point'].within(elem['solid']):
|
||||
geo_elem = {}
|
||||
geo_elem['clear'] = drill['point']
|
||||
|
||||
if clear_apid_size not in holes_apertures:
|
||||
holes_apertures[clear_apid_size] = {}
|
||||
holes_apertures[clear_apid_size]['type'] = 'C'
|
||||
holes_apertures[clear_apid_size]['size'] = clear_apid_size
|
||||
holes_apertures[clear_apid_size]['geometry'] = []
|
||||
|
||||
holes_apertures[clear_apid_size]['geometry'].append(deepcopy(geo_elem))
|
||||
|
||||
# add the clear geometry to new apertures; it's easier than to test if there are apertures with the same
|
||||
# size and add there the clear geometry
|
||||
for hole_size, ap_val in holes_apertures.items():
|
||||
new_apid += 1
|
||||
new_apertures[str(new_apid)] = deepcopy(ap_val)
|
||||
|
||||
def init_func(new_obj, app_obj):
|
||||
new_obj.options.update(new_options)
|
||||
new_obj.options['name'] = outname
|
||||
new_obj.fill_color = deepcopy(grb_obj.fill_color)
|
||||
new_obj.outline_color = deepcopy(grb_obj.outline_color)
|
||||
|
||||
new_obj.apertures = deepcopy(new_apertures)
|
||||
|
||||
new_obj.solid_geometry = deepcopy(punched_solid_geometry)
|
||||
new_obj.source_file = self.app.export_gerber(obj_name=outname, filename=None,
|
||||
local_use=new_obj, use_thread=False)
|
||||
|
||||
self.app.new_object('gerber', outname, init_func)
|
||||
elif punch_method == 'fixed':
|
||||
punch_size = float(self.dia_entry.get_value())
|
||||
|
||||
if punch_size == 0.0:
|
||||
self.app.inform.emit('[WARNING_NOTCL] %s' % _("The value of the fixed diameter is 0.0. Aborting."))
|
||||
return 'fail'
|
||||
|
||||
punching_geo = []
|
||||
for apid in grb_obj.apertures:
|
||||
if grb_obj.apertures[apid]['type'] == 'C' and self.circular_cb.get_value():
|
||||
if punch_size >= float(grb_obj.apertures[apid]['size']):
|
||||
self.app.inform.emit('[ERROR_NOTCL] %s' %
|
||||
_(" Could not generate punched hole Gerber because the punch hole size"
|
||||
"is bigger than some of the apertures in the Gerber object."))
|
||||
return 'fail'
|
||||
else:
|
||||
for elem in grb_obj.apertures[apid]['geometry']:
|
||||
if 'follow' in elem:
|
||||
if isinstance(elem['follow'], Point):
|
||||
punching_geo.append(elem['follow'].buffer(punch_size / 2))
|
||||
elif grb_obj.apertures[apid]['type'] == 'R':
|
||||
if punch_size >= float(grb_obj.apertures[apid]['width']) or \
|
||||
punch_size >= float(grb_obj.apertures[apid]['height']):
|
||||
self.app.inform.emit('[ERROR_NOTCL] %s' %
|
||||
_("Could not generate punched hole Gerber because the punch hole size"
|
||||
"is bigger than some of the apertures in the Gerber object."))
|
||||
return 'fail'
|
||||
elif round(float(grb_obj.apertures[apid]['width']), self.decimals) == \
|
||||
round(float(grb_obj.apertures[apid]['height']), self.decimals) and \
|
||||
self.square_cb.get_value():
|
||||
for elem in grb_obj.apertures[apid]['geometry']:
|
||||
if 'follow' in elem:
|
||||
if isinstance(elem['follow'], Point):
|
||||
punching_geo.append(elem['follow'].buffer(punch_size / 2))
|
||||
elif round(float(grb_obj.apertures[apid]['width']), self.decimals) != \
|
||||
round(float(grb_obj.apertures[apid]['height']), self.decimals) and \
|
||||
self.rectangular_cb.get_value():
|
||||
for elem in grb_obj.apertures[apid]['geometry']:
|
||||
if 'follow' in elem:
|
||||
if isinstance(elem['follow'], Point):
|
||||
punching_geo.append(elem['follow'].buffer(punch_size / 2))
|
||||
elif grb_obj.apertures[apid]['type'] == 'O' and self.oblong_cb.get_value():
|
||||
for elem in grb_obj.apertures[apid]['geometry']:
|
||||
if 'follow' in elem:
|
||||
if isinstance(elem['follow'], Point):
|
||||
punching_geo.append(elem['follow'].buffer(punch_size / 2))
|
||||
elif grb_obj.apertures[apid]['type'] not in ['C', 'R', 'O'] and self.other_cb.get_value():
|
||||
for elem in grb_obj.apertures[apid]['geometry']:
|
||||
if 'follow' in elem:
|
||||
if isinstance(elem['follow'], Point):
|
||||
punching_geo.append(elem['follow'].buffer(punch_size / 2))
|
||||
|
||||
punching_geo = MultiPolygon(punching_geo)
|
||||
if isinstance(grb_obj.solid_geometry, list):
|
||||
temp_solid_geometry = MultiPolygon(grb_obj.solid_geometry)
|
||||
else:
|
||||
temp_solid_geometry = grb_obj.solid_geometry
|
||||
punched_solid_geometry = temp_solid_geometry.difference(punching_geo)
|
||||
|
||||
if punched_solid_geometry == temp_solid_geometry:
|
||||
self.app.inform.emit('[WARNING_NOTCL] %s' %
|
||||
_("Could not generate punched hole Gerber because the newly created object "
|
||||
"geometry is the same as the one in the source object geometry..."))
|
||||
return 'fail'
|
||||
|
||||
# update the gerber apertures to include the clear geometry so it can be exported successfully
|
||||
new_apertures = deepcopy(grb_obj.apertures)
|
||||
new_apertures_items = new_apertures.items()
|
||||
|
||||
# find maximum aperture id
|
||||
new_apid = max([int(x) for x, __ in new_apertures_items])
|
||||
|
||||
# store here the clear geometry, the key is the drill size
|
||||
holes_apertures = {}
|
||||
|
||||
for apid, val in new_apertures_items:
|
||||
for elem in val['geometry']:
|
||||
# make it work only for Gerber Flashes who are Points in 'follow'
|
||||
if 'solid' in elem and isinstance(elem['follow'], Point):
|
||||
for geo in punching_geo:
|
||||
clear_apid_size = punch_size
|
||||
|
||||
# since there may be drills that do not drill into a pad we test only for drills in a pad
|
||||
if geo.within(elem['solid']):
|
||||
geo_elem = {}
|
||||
geo_elem['clear'] = geo.centroid
|
||||
|
||||
if clear_apid_size not in holes_apertures:
|
||||
holes_apertures[clear_apid_size] = {}
|
||||
holes_apertures[clear_apid_size]['type'] = 'C'
|
||||
holes_apertures[clear_apid_size]['size'] = clear_apid_size
|
||||
holes_apertures[clear_apid_size]['geometry'] = []
|
||||
|
||||
holes_apertures[clear_apid_size]['geometry'].append(deepcopy(geo_elem))
|
||||
|
||||
# add the clear geometry to new apertures; it's easier than to test if there are apertures with the same
|
||||
# size and add there the clear geometry
|
||||
for hole_size, ap_val in holes_apertures.items():
|
||||
new_apid += 1
|
||||
new_apertures[str(new_apid)] = deepcopy(ap_val)
|
||||
|
||||
def init_func(new_obj, app_obj):
|
||||
new_obj.options.update(new_options)
|
||||
new_obj.options['name'] = outname
|
||||
new_obj.fill_color = deepcopy(grb_obj.fill_color)
|
||||
new_obj.outline_color = deepcopy(grb_obj.outline_color)
|
||||
|
||||
new_obj.apertures = deepcopy(new_apertures)
|
||||
|
||||
new_obj.solid_geometry = deepcopy(punched_solid_geometry)
|
||||
new_obj.source_file = self.app.export_gerber(obj_name=outname, filename=None,
|
||||
local_use=new_obj, use_thread=False)
|
||||
|
||||
self.app.new_object('gerber', outname, init_func)
|
||||
elif punch_method == 'ring':
|
||||
circ_r_val = self.circular_ring_entry.get_value()
|
||||
oblong_r_val = self.oblong_ring_entry.get_value()
|
||||
square_r_val = self.square_ring_entry.get_value()
|
||||
rect_r_val = self.rectangular_ring_entry.get_value()
|
||||
other_r_val = self.other_ring_entry.get_value()
|
||||
|
||||
dia = None
|
||||
|
||||
if isinstance(grb_obj.solid_geometry, list):
|
||||
temp_solid_geometry = MultiPolygon(grb_obj.solid_geometry)
|
||||
else:
|
||||
temp_solid_geometry = grb_obj.solid_geometry
|
||||
|
||||
punched_solid_geometry = temp_solid_geometry
|
||||
|
||||
new_apertures = deepcopy(grb_obj.apertures)
|
||||
new_apertures_items = new_apertures.items()
|
||||
|
||||
# find maximum aperture id
|
||||
new_apid = max([int(x) for x, __ in new_apertures_items])
|
||||
|
||||
# store here the clear geometry, the key is the new aperture size
|
||||
holes_apertures = {}
|
||||
|
||||
for apid, apid_value in grb_obj.apertures.items():
|
||||
ap_type = apid_value['type']
|
||||
punching_geo = []
|
||||
|
||||
if ap_type == 'C' and self.circular_cb.get_value():
|
||||
dia = float(apid_value['size']) - (2 * circ_r_val)
|
||||
for elem in apid_value['geometry']:
|
||||
if 'follow' in elem and isinstance(elem['follow'], Point):
|
||||
punching_geo.append(elem['follow'].buffer(dia / 2))
|
||||
|
||||
elif ap_type == 'O' and self.oblong_cb.get_value():
|
||||
width = float(apid_value['width'])
|
||||
height = float(apid_value['height'])
|
||||
|
||||
if width > height:
|
||||
dia = float(apid_value['height']) - (2 * oblong_r_val)
|
||||
else:
|
||||
dia = float(apid_value['width']) - (2 * oblong_r_val)
|
||||
|
||||
for elem in grb_obj.apertures[apid]['geometry']:
|
||||
if 'follow' in elem:
|
||||
if isinstance(elem['follow'], Point):
|
||||
punching_geo.append(elem['follow'].buffer(dia / 2))
|
||||
|
||||
elif ap_type == 'R':
|
||||
width = float(apid_value['width'])
|
||||
height = float(apid_value['height'])
|
||||
|
||||
# if the height == width (float numbers so the reason for the following)
|
||||
if round(width, self.decimals) == round(height, self.decimals):
|
||||
if self.square_cb.get_value():
|
||||
dia = float(apid_value['height']) - (2 * square_r_val)
|
||||
|
||||
for elem in grb_obj.apertures[apid]['geometry']:
|
||||
if 'follow' in elem:
|
||||
if isinstance(elem['follow'], Point):
|
||||
punching_geo.append(elem['follow'].buffer(dia / 2))
|
||||
elif self.rectangular_cb.get_value():
|
||||
if width > height:
|
||||
dia = float(apid_value['height']) - (2 * rect_r_val)
|
||||
else:
|
||||
dia = float(apid_value['width']) - (2 * rect_r_val)
|
||||
|
||||
for elem in grb_obj.apertures[apid]['geometry']:
|
||||
if 'follow' in elem:
|
||||
if isinstance(elem['follow'], Point):
|
||||
punching_geo.append(elem['follow'].buffer(dia / 2))
|
||||
|
||||
elif self.other_cb.get_value():
|
||||
try:
|
||||
dia = float(apid_value['size']) - (2 * other_r_val)
|
||||
except KeyError:
|
||||
if ap_type == 'AM':
|
||||
pol = apid_value['geometry'][0]['solid']
|
||||
x0, y0, x1, y1 = pol.bounds
|
||||
dx = x1 - x0
|
||||
dy = y1 - y0
|
||||
if dx <= dy:
|
||||
dia = dx - (2 * other_r_val)
|
||||
else:
|
||||
dia = dy - (2 * other_r_val)
|
||||
|
||||
for elem in grb_obj.apertures[apid]['geometry']:
|
||||
if 'follow' in elem:
|
||||
if isinstance(elem['follow'], Point):
|
||||
punching_geo.append(elem['follow'].buffer(dia / 2))
|
||||
|
||||
# if dia is None then none of the above applied so we skip the following
|
||||
if dia is None:
|
||||
continue
|
||||
|
||||
punching_geo = MultiPolygon(punching_geo)
|
||||
|
||||
if punching_geo is None or punching_geo.is_empty:
|
||||
continue
|
||||
|
||||
punched_solid_geometry = punched_solid_geometry.difference(punching_geo)
|
||||
|
||||
# update the gerber apertures to include the clear geometry so it can be exported successfully
|
||||
for elem in apid_value['geometry']:
|
||||
# make it work only for Gerber Flashes who are Points in 'follow'
|
||||
if 'solid' in elem and isinstance(elem['follow'], Point):
|
||||
clear_apid_size = dia
|
||||
for geo in punching_geo:
|
||||
|
||||
# since there may be drills that do not drill into a pad we test only for geos in a pad
|
||||
if geo.within(elem['solid']):
|
||||
geo_elem = {}
|
||||
geo_elem['clear'] = geo.centroid
|
||||
|
||||
if clear_apid_size not in holes_apertures:
|
||||
holes_apertures[clear_apid_size] = {}
|
||||
holes_apertures[clear_apid_size]['type'] = 'C'
|
||||
holes_apertures[clear_apid_size]['size'] = clear_apid_size
|
||||
holes_apertures[clear_apid_size]['geometry'] = []
|
||||
|
||||
holes_apertures[clear_apid_size]['geometry'].append(deepcopy(geo_elem))
|
||||
|
||||
# add the clear geometry to new apertures; it's easier than to test if there are apertures with the same
|
||||
# size and add there the clear geometry
|
||||
for hole_size, ap_val in holes_apertures.items():
|
||||
new_apid += 1
|
||||
new_apertures[str(new_apid)] = deepcopy(ap_val)
|
||||
|
||||
def init_func(new_obj, app_obj):
|
||||
new_obj.options.update(new_options)
|
||||
new_obj.options['name'] = outname
|
||||
new_obj.fill_color = deepcopy(grb_obj.fill_color)
|
||||
new_obj.outline_color = deepcopy(grb_obj.outline_color)
|
||||
|
||||
new_obj.apertures = deepcopy(new_apertures)
|
||||
|
||||
new_obj.solid_geometry = deepcopy(punched_solid_geometry)
|
||||
new_obj.source_file = self.app.export_gerber(obj_name=outname, filename=None,
|
||||
local_use=new_obj, use_thread=False)
|
||||
|
||||
self.app.new_object('gerber', outname, init_func)
|
||||
|
||||
elif punch_method == 'prop':
|
||||
prop_factor = self.factor_entry.get_value() / 100.0
|
||||
|
||||
dia = None
|
||||
|
||||
if isinstance(grb_obj.solid_geometry, list):
|
||||
temp_solid_geometry = MultiPolygon(grb_obj.solid_geometry)
|
||||
else:
|
||||
temp_solid_geometry = grb_obj.solid_geometry
|
||||
|
||||
punched_solid_geometry = temp_solid_geometry
|
||||
|
||||
new_apertures = deepcopy(grb_obj.apertures)
|
||||
new_apertures_items = new_apertures.items()
|
||||
|
||||
# find maximum aperture id
|
||||
new_apid = max([int(x) for x, __ in new_apertures_items])
|
||||
|
||||
# store here the clear geometry, the key is the new aperture size
|
||||
holes_apertures = {}
|
||||
|
||||
for apid, apid_value in grb_obj.apertures.items():
|
||||
ap_type = apid_value['type']
|
||||
punching_geo = []
|
||||
|
||||
if ap_type == 'C' and self.circular_cb.get_value():
|
||||
dia = float(apid_value['size']) * prop_factor
|
||||
for elem in apid_value['geometry']:
|
||||
if 'follow' in elem and isinstance(elem['follow'], Point):
|
||||
punching_geo.append(elem['follow'].buffer(dia / 2))
|
||||
|
||||
elif ap_type == 'O' and self.oblong_cb.get_value():
|
||||
width = float(apid_value['width'])
|
||||
height = float(apid_value['height'])
|
||||
|
||||
if width > height:
|
||||
dia = float(apid_value['height']) * prop_factor
|
||||
else:
|
||||
dia = float(apid_value['width']) * prop_factor
|
||||
|
||||
for elem in grb_obj.apertures[apid]['geometry']:
|
||||
if 'follow' in elem:
|
||||
if isinstance(elem['follow'], Point):
|
||||
punching_geo.append(elem['follow'].buffer(dia / 2))
|
||||
|
||||
elif ap_type == 'R':
|
||||
width = float(apid_value['width'])
|
||||
height = float(apid_value['height'])
|
||||
|
||||
# if the height == width (float numbers so the reason for the following)
|
||||
if round(width, self.decimals) == round(height, self.decimals):
|
||||
if self.square_cb.get_value():
|
||||
dia = float(apid_value['height']) * prop_factor
|
||||
|
||||
for elem in grb_obj.apertures[apid]['geometry']:
|
||||
if 'follow' in elem:
|
||||
if isinstance(elem['follow'], Point):
|
||||
punching_geo.append(elem['follow'].buffer(dia / 2))
|
||||
elif self.rectangular_cb.get_value():
|
||||
if width > height:
|
||||
dia = float(apid_value['height']) * prop_factor
|
||||
else:
|
||||
dia = float(apid_value['width']) * prop_factor
|
||||
|
||||
for elem in grb_obj.apertures[apid]['geometry']:
|
||||
if 'follow' in elem:
|
||||
if isinstance(elem['follow'], Point):
|
||||
punching_geo.append(elem['follow'].buffer(dia / 2))
|
||||
|
||||
elif self.other_cb.get_value():
|
||||
try:
|
||||
dia = float(apid_value['size']) * prop_factor
|
||||
except KeyError:
|
||||
if ap_type == 'AM':
|
||||
pol = apid_value['geometry'][0]['solid']
|
||||
x0, y0, x1, y1 = pol.bounds
|
||||
dx = x1 - x0
|
||||
dy = y1 - y0
|
||||
if dx <= dy:
|
||||
dia = dx * prop_factor
|
||||
else:
|
||||
dia = dy * prop_factor
|
||||
|
||||
for elem in grb_obj.apertures[apid]['geometry']:
|
||||
if 'follow' in elem:
|
||||
if isinstance(elem['follow'], Point):
|
||||
punching_geo.append(elem['follow'].buffer(dia / 2))
|
||||
|
||||
# if dia is None then none of the above applied so we skip the following
|
||||
if dia is None:
|
||||
continue
|
||||
|
||||
punching_geo = MultiPolygon(punching_geo)
|
||||
|
||||
if punching_geo is None or punching_geo.is_empty:
|
||||
continue
|
||||
|
||||
punched_solid_geometry = punched_solid_geometry.difference(punching_geo)
|
||||
|
||||
# update the gerber apertures to include the clear geometry so it can be exported successfully
|
||||
for elem in apid_value['geometry']:
|
||||
# make it work only for Gerber Flashes who are Points in 'follow'
|
||||
if 'solid' in elem and isinstance(elem['follow'], Point):
|
||||
clear_apid_size = dia
|
||||
for geo in punching_geo:
|
||||
|
||||
# since there may be drills that do not drill into a pad we test only for geos in a pad
|
||||
if geo.within(elem['solid']):
|
||||
geo_elem = {}
|
||||
geo_elem['clear'] = geo.centroid
|
||||
|
||||
if clear_apid_size not in holes_apertures:
|
||||
holes_apertures[clear_apid_size] = {}
|
||||
holes_apertures[clear_apid_size]['type'] = 'C'
|
||||
holes_apertures[clear_apid_size]['size'] = clear_apid_size
|
||||
holes_apertures[clear_apid_size]['geometry'] = []
|
||||
|
||||
holes_apertures[clear_apid_size]['geometry'].append(deepcopy(geo_elem))
|
||||
|
||||
# add the clear geometry to new apertures; it's easier than to test if there are apertures with the same
|
||||
# size and add there the clear geometry
|
||||
for hole_size, ap_val in holes_apertures.items():
|
||||
new_apid += 1
|
||||
new_apertures[str(new_apid)] = deepcopy(ap_val)
|
||||
|
||||
def init_func(new_obj, app_obj):
|
||||
new_obj.options.update(new_options)
|
||||
new_obj.options['name'] = outname
|
||||
new_obj.fill_color = deepcopy(grb_obj.fill_color)
|
||||
new_obj.outline_color = deepcopy(grb_obj.outline_color)
|
||||
|
||||
new_obj.apertures = deepcopy(new_apertures)
|
||||
|
||||
new_obj.solid_geometry = deepcopy(punched_solid_geometry)
|
||||
new_obj.source_file = self.app.export_gerber(obj_name=outname, filename=None,
|
||||
local_use=new_obj, use_thread=False)
|
||||
|
||||
self.app.new_object('gerber', outname, init_func)
|
||||
|
||||
def reset_fields(self):
|
||||
self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.exc_combo.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
|
||||
self.ui_disconnect()
|
|
@ -9,7 +9,7 @@ from PyQt5 import QtWidgets, QtCore, QtGui
|
|||
from PyQt5.QtCore import Qt
|
||||
|
||||
from FlatCAMTool import FlatCAMTool
|
||||
from flatcamGUI.GUIElements import RadioSet, FCTextArea, FCSpinner, FCEntry, FCCheckBox
|
||||
from flatcamGUI.GUIElements import RadioSet, FCTextArea, FCSpinner, FCEntry, FCCheckBox, FCComboBox
|
||||
from flatcamParsers.ParseSVG import *
|
||||
|
||||
from shapely.geometry.base import *
|
||||
|
@ -69,12 +69,13 @@ class QRCode(FlatCAMTool):
|
|||
i_grid_lay.setColumnStretch(0, 0)
|
||||
i_grid_lay.setColumnStretch(1, 1)
|
||||
|
||||
self.grb_object_combo = QtWidgets.QComboBox()
|
||||
self.grb_object_combo = FCComboBox()
|
||||
self.grb_object_combo.setModel(self.app.collection)
|
||||
self.grb_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.grb_object_combo.setCurrentIndex(1)
|
||||
self.grb_object_combo.is_last = True
|
||||
self.grb_object_combo.obj_type = "Gerber"
|
||||
|
||||
self.grbobj_label = QtWidgets.QLabel("<b>%s:</b>" % _("GERBER"))
|
||||
self.grbobj_label = QtWidgets.QLabel("<b>%s:</b>" % _("Object"))
|
||||
self.grbobj_label.setToolTip(
|
||||
_("Gerber Object to which the QRCode will be added.")
|
||||
)
|
||||
|
@ -101,7 +102,7 @@ class QRCode(FlatCAMTool):
|
|||
_("QRCode version can have values from 1 (21x21 boxes)\n"
|
||||
"to 40 (177x177 boxes).")
|
||||
)
|
||||
self.version_entry = FCSpinner()
|
||||
self.version_entry = FCSpinner(callback=self.confirmation_message_int)
|
||||
self.version_entry.set_range(1, 40)
|
||||
self.version_entry.setWrapping(True)
|
||||
|
||||
|
@ -137,7 +138,7 @@ class QRCode(FlatCAMTool):
|
|||
_("Box size control the overall size of the QRcode\n"
|
||||
"by adjusting the size of each box in the code.")
|
||||
)
|
||||
self.bsize_entry = FCSpinner()
|
||||
self.bsize_entry = FCSpinner(callback=self.confirmation_message_int)
|
||||
self.bsize_entry.set_range(1, 9999)
|
||||
self.bsize_entry.setWrapping(True)
|
||||
|
||||
|
@ -150,10 +151,9 @@ class QRCode(FlatCAMTool):
|
|||
_("Size of the QRCode border. How many boxes thick is the border.\n"
|
||||
"Default value is 4. The width of the clearance around the QRCode.")
|
||||
)
|
||||
self.border_size_entry = FCSpinner()
|
||||
self.border_size_entry = FCSpinner(callback=self.confirmation_message_int)
|
||||
self.border_size_entry.set_range(1, 9999)
|
||||
self.border_size_entry.setWrapping(True)
|
||||
self.border_size_entry.set_value(4)
|
||||
|
||||
grid_lay.addWidget(self.border_size_label, 4, 0)
|
||||
grid_lay.addWidget(self.border_size_entry, 4, 1)
|
||||
|
@ -386,6 +386,8 @@ class QRCode(FlatCAMTool):
|
|||
|
||||
def set_tool_ui(self):
|
||||
self.units = self.app.defaults['units']
|
||||
self.border_size_entry.set_value(4)
|
||||
|
||||
self.version_entry.set_value(int(self.app.defaults["tools_qrcode_version"]))
|
||||
self.error_radio.set_value(self.app.defaults["tools_qrcode_error"])
|
||||
self.bsize_entry.set_value(int(self.app.defaults["tools_qrcode_box_size"]))
|
||||
|
@ -495,7 +497,7 @@ class QRCode(FlatCAMTool):
|
|||
mask_geo = box(a, b, c, d).buffer(buff_val, join_style=2)
|
||||
|
||||
# update the solid geometry with the cutout (if it is the case)
|
||||
new_solid_geometry = list()
|
||||
new_solid_geometry = []
|
||||
offset_mask_geo = translate(mask_geo, xoff=pos[0], yoff=pos[1])
|
||||
for poly in geo_list:
|
||||
if poly.contains(offset_mask_geo):
|
||||
|
@ -522,7 +524,7 @@ class QRCode(FlatCAMTool):
|
|||
|
||||
box_size = float(self.bsize_entry.get_value()) / 10.0
|
||||
|
||||
sort_apid = list()
|
||||
sort_apid = []
|
||||
new_apid = '10'
|
||||
if self.grb_object.apertures:
|
||||
for k, v in list(self.grb_object.apertures.items()):
|
||||
|
@ -536,8 +538,8 @@ class QRCode(FlatCAMTool):
|
|||
|
||||
# don't know if the condition is required since I already made sure above that the new_apid is a new one
|
||||
if new_apid not in self.grb_object.apertures:
|
||||
self.grb_object.apertures[new_apid] = dict()
|
||||
self.grb_object.apertures[new_apid]['geometry'] = list()
|
||||
self.grb_object.apertures[new_apid] = {}
|
||||
self.grb_object.apertures[new_apid]['geometry'] = []
|
||||
self.grb_object.apertures[new_apid]['type'] = 'R'
|
||||
# TODO: HACK
|
||||
# I've artificially added 1% to the height and width because otherwise after loading the
|
||||
|
@ -548,14 +550,14 @@ class QRCode(FlatCAMTool):
|
|||
self.grb_object.apertures[new_apid]['size'] = deepcopy(math.sqrt(box_size ** 2 + box_size ** 2))
|
||||
|
||||
if '0' not in self.grb_object.apertures:
|
||||
self.grb_object.apertures['0'] = dict()
|
||||
self.grb_object.apertures['0']['geometry'] = list()
|
||||
self.grb_object.apertures['0'] = {}
|
||||
self.grb_object.apertures['0']['geometry'] = []
|
||||
self.grb_object.apertures['0']['type'] = 'REG'
|
||||
self.grb_object.apertures['0']['size'] = 0.0
|
||||
|
||||
# in case that the QRCode geometry is dropped onto a copper region (found in the '0' aperture)
|
||||
# make sure that I place a cutout there
|
||||
zero_elem = dict()
|
||||
zero_elem = {}
|
||||
zero_elem['clear'] = offset_mask_geo
|
||||
self.grb_object.apertures['0']['geometry'].append(deepcopy(zero_elem))
|
||||
|
||||
|
@ -570,12 +572,12 @@ class QRCode(FlatCAMTool):
|
|||
|
||||
try:
|
||||
for geo in self.qrcode_geometry:
|
||||
geo_elem = dict()
|
||||
geo_elem = {}
|
||||
geo_elem['solid'] = translate(geo, xoff=pos[0], yoff=pos[1])
|
||||
geo_elem['follow'] = translate(geo.centroid, xoff=pos[0], yoff=pos[1])
|
||||
self.grb_object.apertures[new_apid]['geometry'].append(deepcopy(geo_elem))
|
||||
except TypeError:
|
||||
geo_elem = dict()
|
||||
geo_elem = {}
|
||||
geo_elem['solid'] = self.qrcode_geometry
|
||||
self.grb_object.apertures[new_apid]['geometry'].append(deepcopy(geo_elem))
|
||||
|
||||
|
@ -591,7 +593,7 @@ class QRCode(FlatCAMTool):
|
|||
# face = '#0000FF' + str(hex(int(0.2 * 255)))[2:]
|
||||
outline = '#0000FFAF'
|
||||
|
||||
offset_geo = list()
|
||||
offset_geo = []
|
||||
|
||||
# I use the len of self.qrcode_geometry instead of the utility one because the complexity of the polygons is
|
||||
# better seen in this (bit what if the sel.qrcode_geometry is just one geo element? len will fail ...
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
from PyQt5 import QtWidgets
|
||||
|
||||
from FlatCAMTool import FlatCAMTool
|
||||
from flatcamGUI.GUIElements import FCDoubleSpinner, FCCheckBox, OptionalInputSection
|
||||
from flatcamGUI.GUIElements import FCDoubleSpinner, FCCheckBox, OptionalInputSection, FCComboBox
|
||||
from copy import deepcopy
|
||||
|
||||
from FlatCAMPool import *
|
||||
|
@ -69,10 +69,11 @@ class RulesCheck(FlatCAMTool):
|
|||
self.grid_layout.addWidget(self.all_obj_cb, 0, 2)
|
||||
|
||||
# Copper Top object
|
||||
self.copper_t_object = QtWidgets.QComboBox()
|
||||
self.copper_t_object = FCComboBox()
|
||||
self.copper_t_object.setModel(self.app.collection)
|
||||
self.copper_t_object.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.copper_t_object.setCurrentIndex(1)
|
||||
self.copper_t_object.is_last = True
|
||||
self.copper_t_object.obj_type = "Gerber"
|
||||
|
||||
self.copper_t_object_lbl = QtWidgets.QLabel('%s:' % _("Top"))
|
||||
self.copper_t_object_lbl.setToolTip(
|
||||
|
@ -86,10 +87,11 @@ class RulesCheck(FlatCAMTool):
|
|||
self.grid_layout.addWidget(self.copper_t_cb, 1, 2)
|
||||
|
||||
# Copper Bottom object
|
||||
self.copper_b_object = QtWidgets.QComboBox()
|
||||
self.copper_b_object = FCComboBox()
|
||||
self.copper_b_object.setModel(self.app.collection)
|
||||
self.copper_b_object.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.copper_b_object.setCurrentIndex(1)
|
||||
self.copper_b_object.is_last = True
|
||||
self.copper_b_object.obj_type = "Gerber"
|
||||
|
||||
self.copper_b_object_lbl = QtWidgets.QLabel('%s:' % _("Bottom"))
|
||||
self.copper_b_object_lbl.setToolTip(
|
||||
|
@ -103,10 +105,11 @@ class RulesCheck(FlatCAMTool):
|
|||
self.grid_layout.addWidget(self.copper_b_cb, 2, 2)
|
||||
|
||||
# SolderMask Top object
|
||||
self.sm_t_object = QtWidgets.QComboBox()
|
||||
self.sm_t_object = FCComboBox()
|
||||
self.sm_t_object.setModel(self.app.collection)
|
||||
self.sm_t_object.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.sm_t_object.setCurrentIndex(1)
|
||||
self.sm_t_object.is_last = True
|
||||
self.sm_t_object.obj_type = "Gerber"
|
||||
|
||||
self.sm_t_object_lbl = QtWidgets.QLabel('%s:' % _("SM Top"))
|
||||
self.sm_t_object_lbl.setToolTip(
|
||||
|
@ -120,10 +123,11 @@ class RulesCheck(FlatCAMTool):
|
|||
self.grid_layout.addWidget(self.sm_t_cb, 3, 2)
|
||||
|
||||
# SolderMask Bottom object
|
||||
self.sm_b_object = QtWidgets.QComboBox()
|
||||
self.sm_b_object = FCComboBox()
|
||||
self.sm_b_object.setModel(self.app.collection)
|
||||
self.sm_b_object.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.sm_b_object.setCurrentIndex(1)
|
||||
self.sm_b_object.is_last = True
|
||||
self.sm_b_object.obj_type = "Gerber"
|
||||
|
||||
self.sm_b_object_lbl = QtWidgets.QLabel('%s:' % _("SM Bottom"))
|
||||
self.sm_b_object_lbl.setToolTip(
|
||||
|
@ -137,10 +141,11 @@ class RulesCheck(FlatCAMTool):
|
|||
self.grid_layout.addWidget(self.sm_b_cb, 4, 2)
|
||||
|
||||
# SilkScreen Top object
|
||||
self.ss_t_object = QtWidgets.QComboBox()
|
||||
self.ss_t_object = FCComboBox()
|
||||
self.ss_t_object.setModel(self.app.collection)
|
||||
self.ss_t_object.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.ss_t_object.setCurrentIndex(1)
|
||||
self.ss_t_object.is_last = True
|
||||
self.ss_t_object.obj_type = "Gerber"
|
||||
|
||||
self.ss_t_object_lbl = QtWidgets.QLabel('%s:' % _("Silk Top"))
|
||||
self.ss_t_object_lbl.setToolTip(
|
||||
|
@ -154,10 +159,11 @@ class RulesCheck(FlatCAMTool):
|
|||
self.grid_layout.addWidget(self.ss_t_cb, 5, 2)
|
||||
|
||||
# SilkScreen Bottom object
|
||||
self.ss_b_object = QtWidgets.QComboBox()
|
||||
self.ss_b_object = FCComboBox()
|
||||
self.ss_b_object.setModel(self.app.collection)
|
||||
self.ss_b_object.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.ss_b_object.setCurrentIndex(1)
|
||||
self.ss_b_object.is_last = True
|
||||
self.ss_b_object.obj_type = "Gerber"
|
||||
|
||||
self.ss_b_object_lbl = QtWidgets.QLabel('%s:' % _("Silk Bottom"))
|
||||
self.ss_b_object_lbl.setToolTip(
|
||||
|
@ -171,10 +177,11 @@ class RulesCheck(FlatCAMTool):
|
|||
self.grid_layout.addWidget(self.ss_b_cb, 6, 2)
|
||||
|
||||
# Outline object
|
||||
self.outline_object = QtWidgets.QComboBox()
|
||||
self.outline_object = FCComboBox()
|
||||
self.outline_object.setModel(self.app.collection)
|
||||
self.outline_object.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.outline_object.setCurrentIndex(1)
|
||||
self.outline_object.is_last = True
|
||||
self.outline_object.obj_type = "Gerber"
|
||||
|
||||
self.outline_object_lbl = QtWidgets.QLabel('%s:' % _("Outline"))
|
||||
self.outline_object_lbl.setToolTip(
|
||||
|
@ -197,10 +204,11 @@ class RulesCheck(FlatCAMTool):
|
|||
self.grid_layout.addWidget(self.excellon_title_lbl, 9, 0, 1, 3)
|
||||
|
||||
# Excellon 1 object
|
||||
self.e1_object = QtWidgets.QComboBox()
|
||||
self.e1_object = FCComboBox()
|
||||
self.e1_object.setModel(self.app.collection)
|
||||
self.e1_object.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
|
||||
self.e1_object.setCurrentIndex(1)
|
||||
self.e1_object.is_last = True
|
||||
self.e1_object.obj_type = "Excellon"
|
||||
|
||||
self.e1_object_lbl = QtWidgets.QLabel('%s:' % _("Excellon 1"))
|
||||
self.e1_object_lbl.setToolTip(
|
||||
|
@ -215,10 +223,11 @@ class RulesCheck(FlatCAMTool):
|
|||
self.grid_layout.addWidget(self.e1_cb, 10, 2)
|
||||
|
||||
# Excellon 2 object
|
||||
self.e2_object = QtWidgets.QComboBox()
|
||||
self.e2_object = FCComboBox()
|
||||
self.e2_object.setModel(self.app.collection)
|
||||
self.e2_object.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
|
||||
self.e2_object.setCurrentIndex(1)
|
||||
self.e2_object.is_last = True
|
||||
self.e2_object.obj_type = "Excellon"
|
||||
|
||||
self.e2_object_lbl = QtWidgets.QLabel('%s:' % _("Excellon 2"))
|
||||
self.e2_object_lbl.setToolTip(
|
||||
|
@ -260,7 +269,7 @@ class RulesCheck(FlatCAMTool):
|
|||
self.form_layout_1.addRow(self.trace_size_cb)
|
||||
|
||||
# Trace size value
|
||||
self.trace_size_entry = FCDoubleSpinner()
|
||||
self.trace_size_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.trace_size_entry.set_range(0.00001, 999.99999)
|
||||
self.trace_size_entry.set_precision(self.decimals)
|
||||
self.trace_size_entry.setSingleStep(0.1)
|
||||
|
@ -282,7 +291,7 @@ class RulesCheck(FlatCAMTool):
|
|||
self.form_layout_1.addRow(self.clearance_copper2copper_cb)
|
||||
|
||||
# Copper2copper clearance value
|
||||
self.clearance_copper2copper_entry = FCDoubleSpinner()
|
||||
self.clearance_copper2copper_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.clearance_copper2copper_entry.set_range(0.00001, 999.99999)
|
||||
self.clearance_copper2copper_entry.set_precision(self.decimals)
|
||||
self.clearance_copper2copper_entry.setSingleStep(0.1)
|
||||
|
@ -305,7 +314,7 @@ class RulesCheck(FlatCAMTool):
|
|||
self.form_layout_1.addRow(self.clearance_copper2ol_cb)
|
||||
|
||||
# Copper2outline clearance value
|
||||
self.clearance_copper2ol_entry = FCDoubleSpinner()
|
||||
self.clearance_copper2ol_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.clearance_copper2ol_entry.set_range(0.00001, 999.99999)
|
||||
self.clearance_copper2ol_entry.set_precision(self.decimals)
|
||||
self.clearance_copper2ol_entry.setSingleStep(0.1)
|
||||
|
@ -328,7 +337,7 @@ class RulesCheck(FlatCAMTool):
|
|||
self.form_layout_1.addRow(self.clearance_silk2silk_cb)
|
||||
|
||||
# Copper2silkscreen clearance value
|
||||
self.clearance_silk2silk_entry = FCDoubleSpinner()
|
||||
self.clearance_silk2silk_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.clearance_silk2silk_entry.set_range(0.00001, 999.99999)
|
||||
self.clearance_silk2silk_entry.set_precision(self.decimals)
|
||||
self.clearance_silk2silk_entry.setSingleStep(0.1)
|
||||
|
@ -351,7 +360,7 @@ class RulesCheck(FlatCAMTool):
|
|||
self.form_layout_1.addRow(self.clearance_silk2sm_cb)
|
||||
|
||||
# Silkscreen2soldermask clearance value
|
||||
self.clearance_silk2sm_entry = FCDoubleSpinner()
|
||||
self.clearance_silk2sm_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.clearance_silk2sm_entry.set_range(0.00001, 999.99999)
|
||||
self.clearance_silk2sm_entry.set_precision(self.decimals)
|
||||
self.clearance_silk2sm_entry.setSingleStep(0.1)
|
||||
|
@ -374,7 +383,7 @@ class RulesCheck(FlatCAMTool):
|
|||
self.form_layout_1.addRow(self.clearance_silk2ol_cb)
|
||||
|
||||
# Silk2outline clearance value
|
||||
self.clearance_silk2ol_entry = FCDoubleSpinner()
|
||||
self.clearance_silk2ol_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.clearance_silk2ol_entry.set_range(0.00001, 999.99999)
|
||||
self.clearance_silk2ol_entry.set_precision(self.decimals)
|
||||
self.clearance_silk2ol_entry.setSingleStep(0.1)
|
||||
|
@ -397,7 +406,7 @@ class RulesCheck(FlatCAMTool):
|
|||
self.form_layout_1.addRow(self.clearance_sm2sm_cb)
|
||||
|
||||
# Soldermask2soldermask clearance value
|
||||
self.clearance_sm2sm_entry = FCDoubleSpinner()
|
||||
self.clearance_sm2sm_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.clearance_sm2sm_entry.set_range(0.00001, 999.99999)
|
||||
self.clearance_sm2sm_entry.set_precision(self.decimals)
|
||||
self.clearance_sm2sm_entry.setSingleStep(0.1)
|
||||
|
@ -420,7 +429,7 @@ class RulesCheck(FlatCAMTool):
|
|||
self.form_layout_1.addRow(self.ring_integrity_cb)
|
||||
|
||||
# Ring integrity value
|
||||
self.ring_integrity_entry = FCDoubleSpinner()
|
||||
self.ring_integrity_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.ring_integrity_entry.set_range(0.00001, 999.99999)
|
||||
self.ring_integrity_entry.set_precision(self.decimals)
|
||||
self.ring_integrity_entry.setSingleStep(0.1)
|
||||
|
@ -445,7 +454,7 @@ class RulesCheck(FlatCAMTool):
|
|||
self.form_layout_1.addRow(self.clearance_d2d_cb)
|
||||
|
||||
# Hole2Hole clearance value
|
||||
self.clearance_d2d_entry = FCDoubleSpinner()
|
||||
self.clearance_d2d_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.clearance_d2d_entry.set_range(0.00001, 999.99999)
|
||||
self.clearance_d2d_entry.set_precision(self.decimals)
|
||||
self.clearance_d2d_entry.setSingleStep(0.1)
|
||||
|
@ -468,7 +477,7 @@ class RulesCheck(FlatCAMTool):
|
|||
self.form_layout_1.addRow(self.drill_size_cb)
|
||||
|
||||
# Drile holes value
|
||||
self.drill_size_entry = FCDoubleSpinner()
|
||||
self.drill_size_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.drill_size_entry.set_range(0.00001, 999.99999)
|
||||
self.drill_size_entry.set_precision(self.decimals)
|
||||
self.drill_size_entry.setSingleStep(0.1)
|
||||
|
@ -655,8 +664,8 @@ class RulesCheck(FlatCAMTool):
|
|||
|
||||
rule_title = rule
|
||||
|
||||
violations = list()
|
||||
obj_violations = dict()
|
||||
violations = []
|
||||
obj_violations = {}
|
||||
obj_violations.update({
|
||||
'name': '',
|
||||
'points': list()
|
||||
|
@ -667,8 +676,8 @@ class RulesCheck(FlatCAMTool):
|
|||
|
||||
obj_violations['name'] = gerber_obj['name']
|
||||
|
||||
solid_geo = list()
|
||||
clear_geo = list()
|
||||
solid_geo = []
|
||||
clear_geo = []
|
||||
for apid in gerber_obj['apertures']:
|
||||
if 'geometry' in gerber_obj['apertures'][apid]:
|
||||
geometry = gerber_obj['apertures'][apid]['geometry']
|
||||
|
@ -679,7 +688,7 @@ class RulesCheck(FlatCAMTool):
|
|||
clear_geo.append(geo_el['clear'])
|
||||
|
||||
if clear_geo:
|
||||
total_geo = list()
|
||||
total_geo = []
|
||||
for geo_c in clear_geo:
|
||||
for geo_s in solid_geo:
|
||||
if geo_c.within(geo_s):
|
||||
|
@ -696,7 +705,7 @@ class RulesCheck(FlatCAMTool):
|
|||
iterations = (iterations * (iterations - 1)) / 2
|
||||
log.debug("RulesCheck.check_gerber_clearance(). Iterations: %s" % str(iterations))
|
||||
|
||||
min_dict = dict()
|
||||
min_dict = {}
|
||||
idx = 1
|
||||
for geo in total_geo:
|
||||
for s_geo in total_geo[idx:]:
|
||||
|
@ -729,8 +738,8 @@ class RulesCheck(FlatCAMTool):
|
|||
log.debug("RulesCheck.check_gerber_clearance()")
|
||||
rule_title = rule
|
||||
|
||||
violations = list()
|
||||
obj_violations = dict()
|
||||
violations = []
|
||||
obj_violations = {}
|
||||
obj_violations.update({
|
||||
'name': '',
|
||||
'points': list()
|
||||
|
@ -739,7 +748,7 @@ class RulesCheck(FlatCAMTool):
|
|||
if len(gerber_list) == 2:
|
||||
gerber_1 = gerber_list[0]
|
||||
# added it so I won't have errors of using before declaring
|
||||
gerber_2 = dict()
|
||||
gerber_2 = {}
|
||||
|
||||
gerber_3 = gerber_list[1]
|
||||
elif len(gerber_list) == 3:
|
||||
|
@ -749,7 +758,7 @@ class RulesCheck(FlatCAMTool):
|
|||
else:
|
||||
return 'Fail. Not enough Gerber objects to check Gerber 2 Gerber clearance'
|
||||
|
||||
total_geo_grb_1 = list()
|
||||
total_geo_grb_1 = []
|
||||
for apid in gerber_1['apertures']:
|
||||
if 'geometry' in gerber_1['apertures'][apid]:
|
||||
geometry = gerber_1['apertures'][apid]['geometry']
|
||||
|
@ -766,7 +775,7 @@ class RulesCheck(FlatCAMTool):
|
|||
if 'solid' in geo_el and geo_el['solid'] is not None:
|
||||
total_geo_grb_1.append(geo_el['solid'])
|
||||
|
||||
total_geo_grb_3 = list()
|
||||
total_geo_grb_3 = []
|
||||
for apid in gerber_3['apertures']:
|
||||
if 'geometry' in gerber_3['apertures'][apid]:
|
||||
geometry = gerber_3['apertures'][apid]['geometry']
|
||||
|
@ -795,7 +804,7 @@ class RulesCheck(FlatCAMTool):
|
|||
iterations = len_1 * len_3
|
||||
log.debug("RulesCheck.check_gerber_clearance(). Iterations: %s" % str(iterations))
|
||||
|
||||
min_dict = dict()
|
||||
min_dict = {}
|
||||
for geo in total_geo_grb_1:
|
||||
for s_geo in total_geo_grb_3:
|
||||
# minimize the number of distances by not taking into considerations those that are too small
|
||||
|
@ -817,7 +826,7 @@ class RulesCheck(FlatCAMTool):
|
|||
for location in min_dict[dist]:
|
||||
points_list.add(location)
|
||||
|
||||
name_list = list()
|
||||
name_list = []
|
||||
if gerber_1:
|
||||
name_list.append(gerber_1['name'])
|
||||
if gerber_2:
|
||||
|
@ -837,8 +846,8 @@ class RulesCheck(FlatCAMTool):
|
|||
|
||||
rule = _("Hole Size")
|
||||
|
||||
violations = list()
|
||||
obj_violations = dict()
|
||||
violations = []
|
||||
obj_violations = {}
|
||||
obj_violations.update({
|
||||
'name': '',
|
||||
'dia': list()
|
||||
|
@ -863,14 +872,14 @@ class RulesCheck(FlatCAMTool):
|
|||
log.debug("RulesCheck.check_holes_clearance()")
|
||||
rule = _("Hole to Hole Clearance")
|
||||
|
||||
violations = list()
|
||||
obj_violations = dict()
|
||||
violations = []
|
||||
obj_violations = {}
|
||||
obj_violations.update({
|
||||
'name': '',
|
||||
'points': list()
|
||||
})
|
||||
|
||||
total_geo = list()
|
||||
total_geo = []
|
||||
for elem in elements:
|
||||
for tool in elem['tools']:
|
||||
if 'solid_geometry' in elem['tools'][tool]:
|
||||
|
@ -878,7 +887,7 @@ class RulesCheck(FlatCAMTool):
|
|||
for geo in geometry:
|
||||
total_geo.append(geo)
|
||||
|
||||
min_dict = dict()
|
||||
min_dict = {}
|
||||
idx = 1
|
||||
for geo in total_geo:
|
||||
for s_geo in total_geo[idx:]:
|
||||
|
@ -903,7 +912,7 @@ class RulesCheck(FlatCAMTool):
|
|||
for location in min_dict[dist]:
|
||||
points_list.add(location)
|
||||
|
||||
name_list = list()
|
||||
name_list = []
|
||||
for elem in elements:
|
||||
name_list.append(elem['name'])
|
||||
|
||||
|
@ -919,8 +928,8 @@ class RulesCheck(FlatCAMTool):
|
|||
|
||||
rule = _("Trace Size")
|
||||
|
||||
violations = list()
|
||||
obj_violations = dict()
|
||||
violations = []
|
||||
obj_violations = {}
|
||||
obj_violations.update({
|
||||
'name': '',
|
||||
'size': list(),
|
||||
|
@ -957,18 +966,18 @@ class RulesCheck(FlatCAMTool):
|
|||
def check_gerber_annular_ring(obj_list, size, rule):
|
||||
rule_title = rule
|
||||
|
||||
violations = list()
|
||||
obj_violations = dict()
|
||||
violations = []
|
||||
obj_violations = {}
|
||||
obj_violations.update({
|
||||
'name': '',
|
||||
'points': list()
|
||||
})
|
||||
|
||||
# added it so I won't have errors of using before declaring
|
||||
gerber_obj = dict()
|
||||
gerber_extra_obj = dict()
|
||||
exc_obj = dict()
|
||||
exc_extra_obj = dict()
|
||||
gerber_obj = {}
|
||||
gerber_extra_obj = {}
|
||||
exc_obj = {}
|
||||
exc_extra_obj = {}
|
||||
|
||||
if len(obj_list) == 2:
|
||||
gerber_obj = obj_list[0]
|
||||
|
@ -997,7 +1006,7 @@ class RulesCheck(FlatCAMTool):
|
|||
else:
|
||||
return 'Fail. Not enough objects to check Minimum Annular Ring'
|
||||
|
||||
total_geo_grb = list()
|
||||
total_geo_grb = []
|
||||
for apid in gerber_obj['apertures']:
|
||||
if 'geometry' in gerber_obj['apertures'][apid]:
|
||||
geometry = gerber_obj['apertures'][apid]['geometry']
|
||||
|
@ -1017,7 +1026,7 @@ class RulesCheck(FlatCAMTool):
|
|||
total_geo_grb = MultiPolygon(total_geo_grb)
|
||||
total_geo_grb = total_geo_grb.buffer(0)
|
||||
|
||||
total_geo_exc = list()
|
||||
total_geo_exc = []
|
||||
for tool in exc_obj['tools']:
|
||||
if 'solid_geometry' in exc_obj['tools'][tool]:
|
||||
geometry = exc_obj['tools'][tool]['solid_geometry']
|
||||
|
@ -1047,7 +1056,7 @@ class RulesCheck(FlatCAMTool):
|
|||
iterations = len_1 * len_2
|
||||
log.debug("RulesCheck.check_gerber_annular_ring(). Iterations: %s" % str(iterations))
|
||||
|
||||
min_dict = dict()
|
||||
min_dict = {}
|
||||
dist = None
|
||||
for geo in total_geo_grb:
|
||||
for s_geo in total_geo_exc:
|
||||
|
@ -1075,12 +1084,12 @@ class RulesCheck(FlatCAMTool):
|
|||
else:
|
||||
min_dict[dist] = [s_geo.representative_point()]
|
||||
|
||||
points_list = list()
|
||||
points_list = []
|
||||
for dist in min_dict.keys():
|
||||
for location in min_dict[dist]:
|
||||
points_list.append(location)
|
||||
|
||||
name_list = list()
|
||||
name_list = []
|
||||
try:
|
||||
if gerber_obj:
|
||||
name_list.append(gerber_obj['name'])
|
||||
|
@ -1110,7 +1119,7 @@ class RulesCheck(FlatCAMTool):
|
|||
return rule_title, violations
|
||||
|
||||
def execute(self):
|
||||
self.results = list()
|
||||
self.results = []
|
||||
|
||||
log.debug("RuleCheck() executing")
|
||||
|
||||
|
@ -1119,17 +1128,17 @@ class RulesCheck(FlatCAMTool):
|
|||
|
||||
# RULE: Check Trace Size
|
||||
if self.trace_size_cb.get_value():
|
||||
copper_list = list()
|
||||
copper_list = []
|
||||
copper_name_1 = self.copper_t_object.currentText()
|
||||
if copper_name_1 is not '' and self.copper_t_cb.get_value():
|
||||
elem_dict = dict()
|
||||
elem_dict = {}
|
||||
elem_dict['name'] = deepcopy(copper_name_1)
|
||||
elem_dict['apertures'] = deepcopy(self.app.collection.get_by_name(copper_name_1).apertures)
|
||||
copper_list.append(elem_dict)
|
||||
|
||||
copper_name_2 = self.copper_b_object.currentText()
|
||||
if copper_name_2 is not '' and self.copper_b_cb.get_value():
|
||||
elem_dict = dict()
|
||||
elem_dict = {}
|
||||
elem_dict['name'] = deepcopy(copper_name_2)
|
||||
elem_dict['apertures'] = deepcopy(self.app.collection.get_by_name(copper_name_2).apertures)
|
||||
copper_list.append(elem_dict)
|
||||
|
@ -1151,7 +1160,7 @@ class RulesCheck(FlatCAMTool):
|
|||
|
||||
if self.copper_t_cb.get_value():
|
||||
copper_t_obj = self.copper_t_object.currentText()
|
||||
copper_t_dict = dict()
|
||||
copper_t_dict = {}
|
||||
|
||||
if copper_t_obj is not '':
|
||||
copper_t_dict['name'] = deepcopy(copper_t_obj)
|
||||
|
@ -1163,7 +1172,7 @@ class RulesCheck(FlatCAMTool):
|
|||
_("TOP -> Copper to Copper clearance"))))
|
||||
if self.copper_b_cb.get_value():
|
||||
copper_b_obj = self.copper_b_object.currentText()
|
||||
copper_b_dict = dict()
|
||||
copper_b_dict = {}
|
||||
if copper_b_obj is not '':
|
||||
copper_b_dict['name'] = deepcopy(copper_b_obj)
|
||||
copper_b_dict['apertures'] = deepcopy(self.app.collection.get_by_name(copper_b_obj).apertures)
|
||||
|
@ -1181,9 +1190,9 @@ class RulesCheck(FlatCAMTool):
|
|||
|
||||
# RULE: Check Copper to Outline Clearance
|
||||
if self.clearance_copper2ol_cb.get_value() and self.out_cb.get_value():
|
||||
top_dict = dict()
|
||||
bottom_dict = dict()
|
||||
outline_dict = dict()
|
||||
top_dict = {}
|
||||
bottom_dict = {}
|
||||
outline_dict = {}
|
||||
|
||||
copper_top = self.copper_t_object.currentText()
|
||||
if copper_top is not '' and self.copper_t_cb.get_value():
|
||||
|
@ -1235,7 +1244,7 @@ class RulesCheck(FlatCAMTool):
|
|||
|
||||
# RULE: Check Silk to Silk Clearance
|
||||
if self.clearance_silk2silk_cb.get_value():
|
||||
silk_dict = dict()
|
||||
silk_dict = {}
|
||||
|
||||
try:
|
||||
silk_silk_clearance = float(self.clearance_silk2silk_entry.get_value())
|
||||
|
@ -1275,10 +1284,10 @@ class RulesCheck(FlatCAMTool):
|
|||
|
||||
# RULE: Check Silk to Solder Mask Clearance
|
||||
if self.clearance_silk2sm_cb.get_value():
|
||||
silk_t_dict = dict()
|
||||
sm_t_dict = dict()
|
||||
silk_b_dict = dict()
|
||||
sm_b_dict = dict()
|
||||
silk_t_dict = {}
|
||||
sm_t_dict = {}
|
||||
silk_b_dict = {}
|
||||
sm_b_dict = {}
|
||||
|
||||
top_ss = False
|
||||
bottom_ss = False
|
||||
|
@ -1344,9 +1353,9 @@ class RulesCheck(FlatCAMTool):
|
|||
|
||||
# RULE: Check Silk to Outline Clearance
|
||||
if self.clearance_silk2ol_cb.get_value():
|
||||
top_dict = dict()
|
||||
bottom_dict = dict()
|
||||
outline_dict = dict()
|
||||
top_dict = {}
|
||||
bottom_dict = {}
|
||||
outline_dict = {}
|
||||
|
||||
silk_top = self.ss_t_object.currentText()
|
||||
if silk_top is not '' and self.ss_t_cb.get_value():
|
||||
|
@ -1399,7 +1408,7 @@ class RulesCheck(FlatCAMTool):
|
|||
|
||||
# RULE: Check Minimum Solder Mask Sliver
|
||||
if self.clearance_silk2silk_cb.get_value():
|
||||
sm_dict = dict()
|
||||
sm_dict = {}
|
||||
|
||||
try:
|
||||
sm_sm_clearance = float(self.clearance_sm2sm_entry.get_value())
|
||||
|
@ -1439,10 +1448,10 @@ class RulesCheck(FlatCAMTool):
|
|||
|
||||
# RULE: Check Minimum Annular Ring
|
||||
if self.ring_integrity_cb.get_value():
|
||||
top_dict = dict()
|
||||
bottom_dict = dict()
|
||||
exc_1_dict = dict()
|
||||
exc_2_dict = dict()
|
||||
top_dict = {}
|
||||
bottom_dict = {}
|
||||
exc_1_dict = {}
|
||||
exc_2_dict = {}
|
||||
|
||||
copper_top = self.copper_t_object.currentText()
|
||||
if copper_top is not '' and self.copper_t_cb.get_value():
|
||||
|
@ -1504,17 +1513,17 @@ class RulesCheck(FlatCAMTool):
|
|||
|
||||
# RULE: Check Hole to Hole Clearance
|
||||
if self.clearance_d2d_cb.get_value():
|
||||
exc_list = list()
|
||||
exc_list = []
|
||||
exc_name_1 = self.e1_object.currentText()
|
||||
if exc_name_1 is not '' and self.e1_cb.get_value():
|
||||
elem_dict = dict()
|
||||
elem_dict = {}
|
||||
elem_dict['name'] = deepcopy(exc_name_1)
|
||||
elem_dict['tools'] = deepcopy(self.app.collection.get_by_name(exc_name_1).tools)
|
||||
exc_list.append(elem_dict)
|
||||
|
||||
exc_name_2 = self.e2_object.currentText()
|
||||
if exc_name_2 is not '' and self.e2_cb.get_value():
|
||||
elem_dict = dict()
|
||||
elem_dict = {}
|
||||
elem_dict['name'] = deepcopy(exc_name_2)
|
||||
elem_dict['tools'] = deepcopy(self.app.collection.get_by_name(exc_name_2).tools)
|
||||
exc_list.append(elem_dict)
|
||||
|
@ -1524,17 +1533,17 @@ class RulesCheck(FlatCAMTool):
|
|||
|
||||
# RULE: Check Holes Size
|
||||
if self.drill_size_cb.get_value():
|
||||
exc_list = list()
|
||||
exc_list = []
|
||||
exc_name_1 = self.e1_object.currentText()
|
||||
if exc_name_1 is not '' and self.e1_cb.get_value():
|
||||
elem_dict = dict()
|
||||
elem_dict = {}
|
||||
elem_dict['name'] = deepcopy(exc_name_1)
|
||||
elem_dict['tools'] = deepcopy(self.app.collection.get_by_name(exc_name_1).tools)
|
||||
exc_list.append(elem_dict)
|
||||
|
||||
exc_name_2 = self.e2_object.currentText()
|
||||
if exc_name_2 is not '' and self.e2_cb.get_value():
|
||||
elem_dict = dict()
|
||||
elem_dict = {}
|
||||
elem_dict['name'] = deepcopy(exc_name_2)
|
||||
elem_dict['tools'] = deepcopy(self.app.collection.get_by_name(exc_name_2).tools)
|
||||
exc_list.append(elem_dict)
|
||||
|
@ -1542,7 +1551,7 @@ class RulesCheck(FlatCAMTool):
|
|||
drill_size = float(self.drill_size_entry.get_value())
|
||||
self.results.append(self.pool.apply_async(self.check_holes_size, args=(exc_list, drill_size)))
|
||||
|
||||
output = list()
|
||||
output = []
|
||||
for p in self.results:
|
||||
output.append(p.get())
|
||||
|
||||
|
|
|
@ -61,7 +61,8 @@ class SolderPaste(FlatCAMTool):
|
|||
self.obj_combo = FCComboBox(callback=self.on_rmb_combo)
|
||||
self.obj_combo.setModel(self.app.collection)
|
||||
self.obj_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.obj_combo.setCurrentIndex(1)
|
||||
self.obj_combo.is_last = True
|
||||
self.obj_combo.obj_type = "Gerber"
|
||||
|
||||
self.object_label = QtWidgets.QLabel("Gerber: ")
|
||||
self.object_label.setToolTip(
|
||||
|
@ -105,7 +106,7 @@ class SolderPaste(FlatCAMTool):
|
|||
self.addtool_entry_lbl.setToolTip(
|
||||
_("Diameter for the new Nozzle tool to add in the Tool Table")
|
||||
)
|
||||
self.addtool_entry = FCDoubleSpinner()
|
||||
self.addtool_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.addtool_entry.set_range(0.0000001, 9999.9999)
|
||||
self.addtool_entry.set_precision(self.decimals)
|
||||
self.addtool_entry.setSingleStep(0.1)
|
||||
|
@ -174,7 +175,7 @@ class SolderPaste(FlatCAMTool):
|
|||
self.gcode_box.addLayout(self.gcode_form_layout)
|
||||
|
||||
# Z dispense start
|
||||
self.z_start_entry = FCDoubleSpinner()
|
||||
self.z_start_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.z_start_entry.set_range(0.0000001, 9999.9999)
|
||||
self.z_start_entry.set_precision(self.decimals)
|
||||
self.z_start_entry.setSingleStep(0.1)
|
||||
|
@ -186,7 +187,7 @@ class SolderPaste(FlatCAMTool):
|
|||
self.gcode_form_layout.addRow(self.z_start_label, self.z_start_entry)
|
||||
|
||||
# Z dispense
|
||||
self.z_dispense_entry = FCDoubleSpinner()
|
||||
self.z_dispense_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.z_dispense_entry.set_range(0.0000001, 9999.9999)
|
||||
self.z_dispense_entry.set_precision(self.decimals)
|
||||
self.z_dispense_entry.setSingleStep(0.1)
|
||||
|
@ -198,7 +199,7 @@ class SolderPaste(FlatCAMTool):
|
|||
self.gcode_form_layout.addRow(self.z_dispense_label, self.z_dispense_entry)
|
||||
|
||||
# Z dispense stop
|
||||
self.z_stop_entry = FCDoubleSpinner()
|
||||
self.z_stop_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.z_stop_entry.set_range(0.0000001, 9999.9999)
|
||||
self.z_stop_entry.set_precision(self.decimals)
|
||||
self.z_stop_entry.setSingleStep(0.1)
|
||||
|
@ -210,7 +211,7 @@ class SolderPaste(FlatCAMTool):
|
|||
self.gcode_form_layout.addRow(self.z_stop_label, self.z_stop_entry)
|
||||
|
||||
# Z travel
|
||||
self.z_travel_entry = FCDoubleSpinner()
|
||||
self.z_travel_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.z_travel_entry.set_range(0.0000001, 9999.9999)
|
||||
self.z_travel_entry.set_precision(self.decimals)
|
||||
self.z_travel_entry.setSingleStep(0.1)
|
||||
|
@ -223,7 +224,7 @@ class SolderPaste(FlatCAMTool):
|
|||
self.gcode_form_layout.addRow(self.z_travel_label, self.z_travel_entry)
|
||||
|
||||
# Z toolchange location
|
||||
self.z_toolchange_entry = FCDoubleSpinner()
|
||||
self.z_toolchange_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.z_toolchange_entry.set_range(0.0000001, 9999.9999)
|
||||
self.z_toolchange_entry.set_precision(self.decimals)
|
||||
self.z_toolchange_entry.setSingleStep(0.1)
|
||||
|
@ -244,8 +245,8 @@ class SolderPaste(FlatCAMTool):
|
|||
self.gcode_form_layout.addRow(self.xy_toolchange_label, self.xy_toolchange_entry)
|
||||
|
||||
# Feedrate X-Y
|
||||
self.frxy_entry = FCDoubleSpinner()
|
||||
self.frxy_entry.set_range(0.0000001, 9999.9999)
|
||||
self.frxy_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.frxy_entry.set_range(0.0000, 99999.9999)
|
||||
self.frxy_entry.set_precision(self.decimals)
|
||||
self.frxy_entry.setSingleStep(0.1)
|
||||
|
||||
|
@ -256,8 +257,8 @@ class SolderPaste(FlatCAMTool):
|
|||
self.gcode_form_layout.addRow(self.frxy_label, self.frxy_entry)
|
||||
|
||||
# Feedrate Z
|
||||
self.frz_entry = FCDoubleSpinner()
|
||||
self.frz_entry.set_range(0.0000001, 9999.9999)
|
||||
self.frz_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.frz_entry.set_range(0.0000, 99999.9999)
|
||||
self.frz_entry.set_precision(self.decimals)
|
||||
self.frz_entry.setSingleStep(0.1)
|
||||
|
||||
|
@ -269,8 +270,8 @@ class SolderPaste(FlatCAMTool):
|
|||
self.gcode_form_layout.addRow(self.frz_label, self.frz_entry)
|
||||
|
||||
# Feedrate Z Dispense
|
||||
self.frz_dispense_entry = FCDoubleSpinner()
|
||||
self.frz_dispense_entry.set_range(0.0000001, 9999.9999)
|
||||
self.frz_dispense_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.frz_dispense_entry.set_range(0.0000, 99999.9999)
|
||||
self.frz_dispense_entry.set_precision(self.decimals)
|
||||
self.frz_dispense_entry.setSingleStep(0.1)
|
||||
|
||||
|
@ -282,9 +283,9 @@ class SolderPaste(FlatCAMTool):
|
|||
self.gcode_form_layout.addRow(self.frz_dispense_label, self.frz_dispense_entry)
|
||||
|
||||
# Spindle Speed Forward
|
||||
self.speedfwd_entry = FCSpinner()
|
||||
self.speedfwd_entry = FCSpinner(callback=self.confirmation_message_int)
|
||||
self.speedfwd_entry.set_range(0, 999999)
|
||||
self.speedfwd_entry.setSingleStep(1000)
|
||||
self.speedfwd_entry.set_step(1000)
|
||||
|
||||
self.speedfwd_label = QtWidgets.QLabel('%s:' % _("Spindle Speed FWD"))
|
||||
self.speedfwd_label.setToolTip(
|
||||
|
@ -294,7 +295,7 @@ class SolderPaste(FlatCAMTool):
|
|||
self.gcode_form_layout.addRow(self.speedfwd_label, self.speedfwd_entry)
|
||||
|
||||
# Dwell Forward
|
||||
self.dwellfwd_entry = FCDoubleSpinner()
|
||||
self.dwellfwd_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.dwellfwd_entry.set_range(0.0000001, 9999.9999)
|
||||
self.dwellfwd_entry.set_precision(self.decimals)
|
||||
self.dwellfwd_entry.setSingleStep(0.1)
|
||||
|
@ -306,9 +307,9 @@ class SolderPaste(FlatCAMTool):
|
|||
self.gcode_form_layout.addRow(self.dwellfwd_label, self.dwellfwd_entry)
|
||||
|
||||
# Spindle Speed Reverse
|
||||
self.speedrev_entry = FCSpinner()
|
||||
self.speedrev_entry = FCSpinner(callback=self.confirmation_message_int)
|
||||
self.speedrev_entry.set_range(0, 999999)
|
||||
self.speedrev_entry.setSingleStep(1000)
|
||||
self.speedrev_entry.set_step(1000)
|
||||
|
||||
self.speedrev_label = QtWidgets.QLabel('%s:' % _("Spindle Speed REV"))
|
||||
self.speedrev_label.setToolTip(
|
||||
|
@ -318,7 +319,7 @@ class SolderPaste(FlatCAMTool):
|
|||
self.gcode_form_layout.addRow(self.speedrev_label, self.speedrev_entry)
|
||||
|
||||
# Dwell Reverse
|
||||
self.dwellrev_entry = FCDoubleSpinner()
|
||||
self.dwellrev_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.dwellrev_entry.set_range(0.0000001, 9999.9999)
|
||||
self.dwellrev_entry.set_precision(self.decimals)
|
||||
self.dwellrev_entry.setSingleStep(0.1)
|
||||
|
@ -383,7 +384,8 @@ class SolderPaste(FlatCAMTool):
|
|||
self.geo_obj_combo = FCComboBox(callback=self.on_rmb_combo)
|
||||
self.geo_obj_combo.setModel(self.app.collection)
|
||||
self.geo_obj_combo.setRootModelIndex(self.app.collection.index(2, 0, QtCore.QModelIndex()))
|
||||
self.geo_obj_combo.setCurrentIndex(1)
|
||||
self.geo_obj_combo.is_last = True
|
||||
self.geo_obj_combo.obj_type = "Geometry"
|
||||
|
||||
self.geo_object_label = QtWidgets.QLabel('%s:' % _("Geo Result"))
|
||||
self.geo_object_label.setToolTip(
|
||||
|
@ -416,7 +418,8 @@ class SolderPaste(FlatCAMTool):
|
|||
self.cnc_obj_combo = FCComboBox(callback=self.on_rmb_combo)
|
||||
self.cnc_obj_combo.setModel(self.app.collection)
|
||||
self.cnc_obj_combo.setRootModelIndex(self.app.collection.index(3, 0, QtCore.QModelIndex()))
|
||||
self.cnc_obj_combo.setCurrentIndex(1)
|
||||
self.cnc_obj_combo.is_last = True
|
||||
self.geo_obj_combo.obj_type = "CNCJob"
|
||||
|
||||
self.cnc_object_label = QtWidgets.QLabel('%s:' % _("CNC Result"))
|
||||
self.cnc_object_label.setToolTip(
|
||||
|
@ -491,6 +494,8 @@ class SolderPaste(FlatCAMTool):
|
|||
self.units = ''
|
||||
self.name = ""
|
||||
|
||||
self.obj = None
|
||||
|
||||
self.text_editor_tab = None
|
||||
|
||||
# this will be used in the combobox context menu, for delete entry
|
||||
|
@ -652,10 +657,10 @@ class SolderPaste(FlatCAMTool):
|
|||
for tooluid_key, tooluid_value in self.tooltable_tools.items():
|
||||
if float('%.*f' % (self.decimals, tooluid_value['tooldia'])) == tool_sorted:
|
||||
tool_id += 1
|
||||
id = QtWidgets.QTableWidgetItem('%d' % int(tool_id))
|
||||
id.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
|
||||
id_item = QtWidgets.QTableWidgetItem('%d' % int(tool_id))
|
||||
id_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
|
||||
row_no = tool_id - 1
|
||||
self.tools_table.setItem(row_no, 0, id) # Tool name/id
|
||||
self.tools_table.setItem(row_no, 0, id_item) # Tool name/id
|
||||
|
||||
# Make sure that the drill diameter when in MM is with no more than 2 decimals
|
||||
# There are no drill bits in MM with more than 2 decimals diameter
|
||||
|
@ -1295,7 +1300,7 @@ class SolderPaste(FlatCAMTool):
|
|||
if obj.tools[tooluid_key]['solid_geometry'] is None:
|
||||
a += 1
|
||||
if a == len(obj.tools):
|
||||
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'
|
||||
|
||||
# use the name of the first tool selected in self.geo_tools_table which has the diameter passed as tool_dia
|
||||
|
@ -1334,8 +1339,6 @@ class SolderPaste(FlatCAMTool):
|
|||
assert isinstance(job_obj, FlatCAMCNCjob), \
|
||||
"Initializer expected a FlatCAMCNCjob, got %s" % type(job_obj)
|
||||
|
||||
tool_cnc_dict = {}
|
||||
|
||||
# this turn on the FlatCAMCNCJob plot for multiple tools
|
||||
job_obj.multitool = True
|
||||
job_obj.multigeo = True
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
from PyQt5 import QtWidgets, QtCore
|
||||
|
||||
from FlatCAMTool import FlatCAMTool
|
||||
from flatcamGUI.GUIElements import FCCheckBox, FCButton
|
||||
from flatcamGUI.GUIElements import FCCheckBox, FCButton, FCComboBox
|
||||
|
||||
from shapely.geometry import Polygon, MultiPolygon, MultiLineString, LineString
|
||||
from shapely.ops import cascaded_union
|
||||
|
@ -66,10 +66,12 @@ class ToolSub(FlatCAMTool):
|
|||
form_layout.addRow(self.gerber_title)
|
||||
|
||||
# Target Gerber Object
|
||||
self.target_gerber_combo = QtWidgets.QComboBox()
|
||||
self.target_gerber_combo = FCComboBox()
|
||||
self.target_gerber_combo.setModel(self.app.collection)
|
||||
self.target_gerber_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.target_gerber_combo.setCurrentIndex(1)
|
||||
# self.target_gerber_combo.setCurrentIndex(1)
|
||||
self.target_gerber_combo.is_last = True
|
||||
self.target_gerber_combo.obj_type = "Gerber"
|
||||
|
||||
self.target_gerber_label = QtWidgets.QLabel('%s:' % _("Target"))
|
||||
self.target_gerber_label.setToolTip(
|
||||
|
@ -80,10 +82,11 @@ class ToolSub(FlatCAMTool):
|
|||
form_layout.addRow(self.target_gerber_label, self.target_gerber_combo)
|
||||
|
||||
# Substractor Gerber Object
|
||||
self.sub_gerber_combo = QtWidgets.QComboBox()
|
||||
self.sub_gerber_combo = FCComboBox()
|
||||
self.sub_gerber_combo.setModel(self.app.collection)
|
||||
self.sub_gerber_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.sub_gerber_combo.setCurrentIndex(1)
|
||||
self.sub_gerber_combo.is_last = True
|
||||
self.sub_gerber_combo.obj_type = "Gerber"
|
||||
|
||||
self.sub_gerber_label = QtWidgets.QLabel('%s:' % _("Subtractor"))
|
||||
self.sub_gerber_label.setToolTip(
|
||||
|
@ -118,10 +121,12 @@ class ToolSub(FlatCAMTool):
|
|||
form_geo_layout.addRow(self.geo_title)
|
||||
|
||||
# Target Geometry Object
|
||||
self.target_geo_combo = QtWidgets.QComboBox()
|
||||
self.target_geo_combo = FCComboBox()
|
||||
self.target_geo_combo.setModel(self.app.collection)
|
||||
self.target_geo_combo.setRootModelIndex(self.app.collection.index(2, 0, QtCore.QModelIndex()))
|
||||
self.target_geo_combo.setCurrentIndex(1)
|
||||
# self.target_geo_combo.setCurrentIndex(1)
|
||||
self.target_geo_combo.is_last = True
|
||||
self.target_geo_combo.obj_type = "Geometry"
|
||||
|
||||
self.target_geo_label = QtWidgets.QLabel('%s:' % _("Target"))
|
||||
self.target_geo_label.setToolTip(
|
||||
|
@ -132,10 +137,11 @@ class ToolSub(FlatCAMTool):
|
|||
form_geo_layout.addRow(self.target_geo_label, self.target_geo_combo)
|
||||
|
||||
# Substractor Geometry Object
|
||||
self.sub_geo_combo = QtWidgets.QComboBox()
|
||||
self.sub_geo_combo = FCComboBox()
|
||||
self.sub_geo_combo.setModel(self.app.collection)
|
||||
self.sub_geo_combo.setRootModelIndex(self.app.collection.index(2, 0, QtCore.QModelIndex()))
|
||||
self.sub_geo_combo.setCurrentIndex(1)
|
||||
self.sub_geo_combo.is_last = True
|
||||
self.sub_geo_combo.obj_type = "Geometry"
|
||||
|
||||
self.sub_geo_label = QtWidgets.QLabel('%s:' % _("Subtractor"))
|
||||
self.sub_geo_label.setToolTip(
|
||||
|
@ -254,14 +260,14 @@ class ToolSub(FlatCAMTool):
|
|||
FlatCAMTool.run(self)
|
||||
self.set_tool_ui()
|
||||
|
||||
self.app.ui.notebook.setTabText(2, _("Sub Tool"))
|
||||
|
||||
def set_tool_ui(self):
|
||||
self.new_apertures.clear()
|
||||
self.new_tools.clear()
|
||||
self.new_solid_geometry = []
|
||||
self.target_options.clear()
|
||||
|
||||
self.app.ui.notebook.setTabText(2, _("Sub Tool"))
|
||||
|
||||
def set_tool_ui(self):
|
||||
self.tools_frame.show()
|
||||
self.close_paths_cb.setChecked(self.app.defaults["tools_sub_close_paths"])
|
||||
|
||||
|
@ -303,14 +309,14 @@ class ToolSub(FlatCAMTool):
|
|||
|
||||
# crate the new_apertures dict structure
|
||||
for apid in self.target_grb_obj.apertures:
|
||||
self.new_apertures[apid] = dict()
|
||||
self.new_apertures[apid] = {}
|
||||
self.new_apertures[apid]['type'] = 'C'
|
||||
self.new_apertures[apid]['size'] = self.target_grb_obj.apertures[apid]['size']
|
||||
self.new_apertures[apid]['geometry'] = list()
|
||||
self.new_apertures[apid]['geometry'] = []
|
||||
|
||||
geo_solid_union_list = list()
|
||||
geo_follow_union_list = list()
|
||||
geo_clear_union_list = list()
|
||||
geo_solid_union_list = []
|
||||
geo_follow_union_list = []
|
||||
geo_clear_union_list = []
|
||||
|
||||
for apid1 in self.sub_grb_obj.apertures:
|
||||
if 'geometry' in self.sub_grb_obj.apertures[apid1]:
|
||||
|
@ -339,14 +345,14 @@ class ToolSub(FlatCAMTool):
|
|||
self.app.worker_task.emit({'fcn': self.aperture_intersection, 'params': [apid, geo]})
|
||||
|
||||
def aperture_intersection(self, apid, geo):
|
||||
new_geometry = list()
|
||||
new_geometry = []
|
||||
|
||||
log.debug("Working on promise: %s" % str(apid))
|
||||
|
||||
with self.app.proc_container.new('%s: %s...' % (_("Parsing geometry for aperture"), str(apid))):
|
||||
|
||||
for geo_el in geo:
|
||||
new_el = dict()
|
||||
new_el = {}
|
||||
|
||||
if 'solid' in geo_el:
|
||||
work_geo = geo_el['solid']
|
||||
|
@ -513,14 +519,14 @@ class ToolSub(FlatCAMTool):
|
|||
return
|
||||
|
||||
# create the target_options obj
|
||||
# self.target_options = dict()
|
||||
# self.target_options = {}
|
||||
# for k, v in self.target_geo_obj.options.items():
|
||||
# if k != 'name':
|
||||
# self.target_options[k] = v
|
||||
|
||||
# crate the new_tools dict structure
|
||||
for tool in self.target_geo_obj.tools:
|
||||
self.new_tools[tool] = dict()
|
||||
self.new_tools[tool] = {}
|
||||
for key in self.target_geo_obj.tools[tool]:
|
||||
if key == 'solid_geometry':
|
||||
self.new_tools[tool][key] = []
|
||||
|
|
|
@ -68,7 +68,7 @@ class ToolTransform(FlatCAMTool):
|
|||
"Negative numbers for CCW motion.")
|
||||
)
|
||||
|
||||
self.rotate_entry = FCDoubleSpinner()
|
||||
self.rotate_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.rotate_entry.set_precision(self.decimals)
|
||||
self.rotate_entry.setSingleStep(45)
|
||||
self.rotate_entry.setWrapping(True)
|
||||
|
@ -77,7 +77,6 @@ class ToolTransform(FlatCAMTool):
|
|||
# self.rotate_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
|
||||
|
||||
self.rotate_button = FCButton()
|
||||
self.rotate_button.set_value(_("Rotate"))
|
||||
self.rotate_button.setToolTip(
|
||||
_("Rotate the selected object(s).\n"
|
||||
"The point of reference is the middle of\n"
|
||||
|
@ -103,13 +102,12 @@ class ToolTransform(FlatCAMTool):
|
|||
_("Angle for Skew action, in degrees.\n"
|
||||
"Float number between -360 and 360.")
|
||||
)
|
||||
self.skewx_entry = FCDoubleSpinner()
|
||||
self.skewx_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
# self.skewx_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
|
||||
self.skewx_entry.set_precision(self.decimals)
|
||||
self.skewx_entry.set_range(-360, 360)
|
||||
|
||||
self.skewx_button = FCButton()
|
||||
self.skewx_button.set_value(_("Skew X"))
|
||||
self.skewx_button.setToolTip(
|
||||
_("Skew/shear the selected object(s).\n"
|
||||
"The point of reference is the middle of\n"
|
||||
|
@ -125,13 +123,12 @@ class ToolTransform(FlatCAMTool):
|
|||
_("Angle for Skew action, in degrees.\n"
|
||||
"Float number between -360 and 360.")
|
||||
)
|
||||
self.skewy_entry = FCDoubleSpinner()
|
||||
self.skewy_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
# self.skewy_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
|
||||
self.skewy_entry.set_precision(self.decimals)
|
||||
self.skewy_entry.set_range(-360, 360)
|
||||
|
||||
self.skewy_button = FCButton()
|
||||
self.skewy_button.set_value(_("Skew Y"))
|
||||
self.skewy_button.setToolTip(
|
||||
_("Skew/shear the selected object(s).\n"
|
||||
"The point of reference is the middle of\n"
|
||||
|
@ -155,13 +152,12 @@ class ToolTransform(FlatCAMTool):
|
|||
self.scalex_label.setToolTip(
|
||||
_("Factor for scaling on X axis.")
|
||||
)
|
||||
self.scalex_entry = FCDoubleSpinner()
|
||||
self.scalex_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
# self.scalex_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
|
||||
self.scalex_entry.set_precision(self.decimals)
|
||||
self.scalex_entry.setMinimum(-1e6)
|
||||
|
||||
self.scalex_button = FCButton()
|
||||
self.scalex_button.set_value(_("Scale X"))
|
||||
self.scalex_button.setToolTip(
|
||||
_("Scale the selected object(s).\n"
|
||||
"The point of reference depends on \n"
|
||||
|
@ -176,13 +172,12 @@ class ToolTransform(FlatCAMTool):
|
|||
self.scaley_label.setToolTip(
|
||||
_("Factor for scaling on Y axis.")
|
||||
)
|
||||
self.scaley_entry = FCDoubleSpinner()
|
||||
self.scaley_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
# self.scaley_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
|
||||
self.scaley_entry.set_precision(self.decimals)
|
||||
self.scaley_entry.setMinimum(-1e6)
|
||||
|
||||
self.scaley_button = FCButton()
|
||||
self.scaley_button.set_value(_("Scale Y"))
|
||||
self.scaley_button.setToolTip(
|
||||
_("Scale the selected object(s).\n"
|
||||
"The point of reference depends on \n"
|
||||
|
@ -194,7 +189,6 @@ class ToolTransform(FlatCAMTool):
|
|||
grid0.addWidget(self.scaley_button, 9, 2)
|
||||
|
||||
self.scale_link_cb = FCCheckBox()
|
||||
self.scale_link_cb.set_value(True)
|
||||
self.scale_link_cb.setText(_("Link"))
|
||||
self.scale_link_cb.setToolTip(
|
||||
_("Scale the selected object(s)\n"
|
||||
|
@ -202,7 +196,6 @@ class ToolTransform(FlatCAMTool):
|
|||
)
|
||||
|
||||
self.scale_zero_ref_cb = FCCheckBox()
|
||||
self.scale_zero_ref_cb.set_value(True)
|
||||
self.scale_zero_ref_cb.setText('%s' % _("Scale Reference"))
|
||||
self.scale_zero_ref_cb.setToolTip(
|
||||
_("Scale the selected object(s)\n"
|
||||
|
@ -228,13 +221,12 @@ class ToolTransform(FlatCAMTool):
|
|||
self.offx_label.setToolTip(
|
||||
_("Distance to offset on X axis. In current units.")
|
||||
)
|
||||
self.offx_entry = FCDoubleSpinner()
|
||||
self.offx_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
# self.offx_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
|
||||
self.offx_entry.set_precision(self.decimals)
|
||||
self.offx_entry.setMinimum(-1e6)
|
||||
|
||||
self.offx_button = FCButton()
|
||||
self.offx_button.set_value(_("Offset X"))
|
||||
self.offx_button.setToolTip(
|
||||
_("Offset the selected object(s).\n"
|
||||
"The point of reference is the middle of\n"
|
||||
|
@ -249,13 +241,12 @@ class ToolTransform(FlatCAMTool):
|
|||
self.offy_label.setToolTip(
|
||||
_("Distance to offset on Y axis. In current units.")
|
||||
)
|
||||
self.offy_entry = FCDoubleSpinner()
|
||||
self.offy_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
# self.offy_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
|
||||
self.offy_entry.set_precision(self.decimals)
|
||||
self.offy_entry.setMinimum(-1e6)
|
||||
|
||||
self.offy_button = FCButton()
|
||||
self.offy_button.set_value(_("Offset Y"))
|
||||
self.offy_button.setToolTip(
|
||||
_("Offset the selected object(s).\n"
|
||||
"The point of reference is the middle of\n"
|
||||
|
@ -276,13 +267,11 @@ class ToolTransform(FlatCAMTool):
|
|||
grid0.addWidget(flip_title_label, 16, 0, 1, 3)
|
||||
|
||||
self.flipx_button = FCButton()
|
||||
self.flipx_button.set_value(_("Flip on X"))
|
||||
self.flipx_button.setToolTip(
|
||||
_("Flip the selected object(s) over the X axis.")
|
||||
)
|
||||
|
||||
self.flipy_button = FCButton()
|
||||
self.flipy_button.set_value(_("Flip on Y"))
|
||||
self.flipy_button.setToolTip(
|
||||
_("Flip the selected object(s) over the X axis.")
|
||||
)
|
||||
|
@ -294,7 +283,6 @@ class ToolTransform(FlatCAMTool):
|
|||
hlay0.addWidget(self.flipy_button)
|
||||
|
||||
self.flip_ref_cb = FCCheckBox()
|
||||
self.flip_ref_cb.set_value(True)
|
||||
self.flip_ref_cb.setText('%s' % _("Mirror Reference"))
|
||||
self.flip_ref_cb.setToolTip(
|
||||
_("Flip the selected object(s)\n"
|
||||
|
@ -320,7 +308,6 @@ class ToolTransform(FlatCAMTool):
|
|||
# self.flip_ref_entry.setFixedWidth(70)
|
||||
|
||||
self.flip_ref_button = FCButton()
|
||||
self.flip_ref_button.set_value(_("Add"))
|
||||
self.flip_ref_button.setToolTip(
|
||||
_("The point coordinates can be captured by\n"
|
||||
"left click on canvas together with pressing\n"
|
||||
|
@ -353,14 +340,13 @@ class ToolTransform(FlatCAMTool):
|
|||
"or decreased with the 'distance'.")
|
||||
)
|
||||
|
||||
self.buffer_entry = FCDoubleSpinner()
|
||||
self.buffer_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.buffer_entry.set_precision(self.decimals)
|
||||
self.buffer_entry.setSingleStep(0.1)
|
||||
self.buffer_entry.setWrapping(True)
|
||||
self.buffer_entry.set_range(-9999.9999, 9999.9999)
|
||||
|
||||
self.buffer_button = FCButton()
|
||||
self.buffer_button.set_value(_("Buffer D"))
|
||||
self.buffer_button.setToolTip(
|
||||
_("Create the buffer effect on each geometry,\n"
|
||||
"element from the selected object, using the distance.")
|
||||
|
@ -380,14 +366,13 @@ class ToolTransform(FlatCAMTool):
|
|||
"of the initial dimension.")
|
||||
)
|
||||
|
||||
self.buffer_factor_entry = FCDoubleSpinner(suffix='%')
|
||||
self.buffer_factor_entry = FCDoubleSpinner(callback=self.confirmation_message, suffix='%')
|
||||
self.buffer_factor_entry.set_range(-100.0000, 1000.0000)
|
||||
self.buffer_factor_entry.set_precision(self.decimals)
|
||||
self.buffer_factor_entry.setWrapping(True)
|
||||
self.buffer_factor_entry.setSingleStep(1)
|
||||
|
||||
self.buffer_factor_button = FCButton()
|
||||
self.buffer_factor_button.set_value(_("Buffer F"))
|
||||
self.buffer_factor_button.setToolTip(
|
||||
_("Create the buffer effect on each geometry,\n"
|
||||
"element from the selected object, using the factor.")
|
||||
|
@ -412,6 +397,19 @@ class ToolTransform(FlatCAMTool):
|
|||
|
||||
self.transform_lay.addStretch()
|
||||
|
||||
# ## Reset Tool
|
||||
self.reset_button = QtWidgets.QPushButton(_("Reset Tool"))
|
||||
self.reset_button.setToolTip(
|
||||
_("Will reset the tool parameters.")
|
||||
)
|
||||
self.reset_button.setStyleSheet("""
|
||||
QPushButton
|
||||
{
|
||||
font-weight: bold;
|
||||
}
|
||||
""")
|
||||
self.transform_lay.addWidget(self.reset_button)
|
||||
|
||||
# ## Signals
|
||||
self.rotate_button.clicked.connect(self.on_rotate)
|
||||
self.skewx_button.clicked.connect(self.on_skewx)
|
||||
|
@ -426,6 +424,8 @@ class ToolTransform(FlatCAMTool):
|
|||
self.buffer_button.clicked.connect(self.on_buffer_by_distance)
|
||||
self.buffer_factor_button.clicked.connect(self.on_buffer_by_factor)
|
||||
|
||||
self.reset_button.clicked.connect(self.set_tool_ui)
|
||||
|
||||
# self.rotate_entry.returnPressed.connect(self.on_rotate)
|
||||
# self.skewx_entry.returnPressed.connect(self.on_skewx)
|
||||
# self.skewy_entry.returnPressed.connect(self.on_skewy)
|
||||
|
@ -466,6 +466,22 @@ class ToolTransform(FlatCAMTool):
|
|||
FlatCAMTool.install(self, icon, separator, shortcut='ALT+T', **kwargs)
|
||||
|
||||
def set_tool_ui(self):
|
||||
self.rotate_button.set_value(_("Rotate"))
|
||||
self.skewx_button.set_value(_("Skew X"))
|
||||
self.skewy_button.set_value(_("Skew Y"))
|
||||
self.scalex_button.set_value(_("Scale X"))
|
||||
self.scaley_button.set_value(_("Scale Y"))
|
||||
self.scale_link_cb.set_value(True)
|
||||
self.scale_zero_ref_cb.set_value(True)
|
||||
self.offx_button.set_value(_("Offset X"))
|
||||
self.offy_button.set_value(_("Offset Y"))
|
||||
self.flipx_button.set_value(_("Flip on X"))
|
||||
self.flipy_button.set_value(_("Flip on Y"))
|
||||
self.flip_ref_cb.set_value(True)
|
||||
self.flip_ref_button.set_value(_("Add"))
|
||||
self.buffer_button.set_value(_("Buffer D"))
|
||||
self.buffer_factor_button.set_value(_("Buffer F"))
|
||||
|
||||
# ## Initialize form
|
||||
if self.app.defaults["tools_transform_rotate"]:
|
||||
self.rotate_entry.set_value(self.app.defaults["tools_transform_rotate"])
|
||||
|
|
|
@ -17,7 +17,7 @@ from flatcamTools.ToolDistanceMin import DistanceMin
|
|||
|
||||
from flatcamTools.ToolMove import ToolMove
|
||||
|
||||
from flatcamTools.ToolNonCopperClear import NonCopperClear
|
||||
from flatcamTools.ToolNCC import NonCopperClear
|
||||
from flatcamTools.ToolPaint import ToolPaint
|
||||
|
||||
from flatcamTools.ToolOptimal import ToolOptimal
|
||||
|
@ -38,3 +38,6 @@ from flatcamTools.ToolSolderPaste import SolderPaste
|
|||
from flatcamTools.ToolSub import ToolSub
|
||||
|
||||
from flatcamTools.ToolTransform import ToolTransform
|
||||
from flatcamTools.ToolPunchGerber import ToolPunchGerber
|
||||
|
||||
from flatcamTools.ToolInvertGerber import ToolInvertGerber
|
||||
|
|
|
@ -22,7 +22,7 @@ class Berta_CNC(FlatCAMPostProc):
|
|||
def start_code(self, p):
|
||||
units = ' ' + str(p['units']).lower()
|
||||
coords_xy = p['xy_toolchange']
|
||||
gcode = ''
|
||||
gcode = '(This preprocessor is used with a BERTA CNC router.)\n\n'
|
||||
|
||||
xmin = '%.*f' % (p.coords_decimals, p['options']['xmin'])
|
||||
xmax = '%.*f' % (p.coords_decimals, p['options']['xmax'])
|
||||
|
@ -35,24 +35,57 @@ class Berta_CNC(FlatCAMPostProc):
|
|||
gcode += '(Feedrate: ' + str(p['feedrate']) + units + '/min' + ')\n'
|
||||
|
||||
if str(p['options']['type']) == 'Geometry':
|
||||
gcode += '(TOOL DIAMETER: ' + str(p['options']['tool_dia']) + units + ')\n'
|
||||
gcode += '(Feedrate_XY: ' + str(p['feedrate']) + units + '/min' + ')\n'
|
||||
gcode += '(Feedrate_Z: ' + str(p['z_feedrate']) + units + '/min' + ')\n'
|
||||
|
||||
gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
|
||||
gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
|
||||
|
||||
if str(p['options']['type']) == 'Geometry':
|
||||
gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
|
||||
gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
|
||||
if p['multidepth'] is True:
|
||||
gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
|
||||
str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'
|
||||
gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
|
||||
|
||||
gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
|
||||
gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
|
||||
elif str(p['options']['type']) == 'Excellon' and p['use_ui'] is True:
|
||||
gcode += '\n(TOOLS DIAMETER: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Dia: %s' % str(val["C"]) + ')\n'
|
||||
|
||||
if coords_xy is not None:
|
||||
gcode += '(X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
|
||||
p.decimals, coords_xy[1]) + units + ')\n'
|
||||
else:
|
||||
gcode += '(X,Y Toolchange: ' + "None" + units + ')\n'
|
||||
gcode += '\n(FEEDRATE Z: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate: %s' % str(val['data']["feedrate_z"]) + ')\n'
|
||||
|
||||
gcode += '\n(FEEDRATE RAPIDS: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate Rapids: %s' % \
|
||||
str(val['data']["feedrate_rapid"]) + ')\n'
|
||||
|
||||
gcode += '\n(Z_CUT: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Z_Cut: %s' % str(val['data']["cutz"]) + ')\n'
|
||||
|
||||
gcode += '\n(Tools Offset: )\n'
|
||||
for tool, val in p['exc_cnc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(val['tool']) + 'Offset Z: %s' % str(val['offset_z']) + ')\n'
|
||||
|
||||
if p['multidepth'] is True:
|
||||
gcode += '\n(DEPTH_PER_CUT: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'DeptPerCut: %s' % \
|
||||
str(val['data']["depthperpass"]) + ')\n'
|
||||
|
||||
gcode += '\n(Z_MOVE: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Z_Move: %s' % str(val['data']["travelz"]) + ')\n'
|
||||
gcode += '\n'
|
||||
|
||||
if p['toolchange'] is True:
|
||||
gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
|
||||
|
||||
if coords_xy is not None:
|
||||
gcode += '(X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
|
||||
p.decimals, coords_xy[1]) + units + ')\n'
|
||||
else:
|
||||
gcode += '(X,Y Toolchange: ' + "None" + units + ')\n'
|
||||
|
||||
gcode += '(Z Start: ' + str(p['startz']) + units + ')\n'
|
||||
gcode += '(Z End: ' + str(p['z_end']) + units + ')\n'
|
||||
|
@ -80,7 +113,7 @@ class Berta_CNC(FlatCAMPostProc):
|
|||
gcode += 'G54\n'
|
||||
gcode += 'G0\n'
|
||||
gcode += '(Berta)\n'
|
||||
gcode += 'G94\n'
|
||||
gcode += 'G94'
|
||||
|
||||
return gcode
|
||||
|
||||
|
@ -194,10 +227,10 @@ M0""".format(z_toolchange=self.coordinate_format % (p.coords_decimals, z_toolcha
|
|||
return ('G01 ' + self.position_code(p)).format(**p)
|
||||
|
||||
def end_code(self, p):
|
||||
coords_xy = p['xy_toolchange']
|
||||
coords_xy = p['xy_end']
|
||||
gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + "\n")
|
||||
|
||||
if coords_xy is not None:
|
||||
if coords_xy and coords_xy != '':
|
||||
gcode += 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n"
|
||||
|
||||
gcode += '(Berta)\n'
|
||||
|
|
|
@ -12,7 +12,7 @@ from FlatCAMPostProc import *
|
|||
# is compatible with almost any version of Grbl.
|
||||
|
||||
|
||||
class grbl_laser(FlatCAMPostProc):
|
||||
class GRBL_laser(FlatCAMPostProc):
|
||||
|
||||
include_header = True
|
||||
coordinate_format = "%.*f"
|
||||
|
@ -20,7 +20,8 @@ class grbl_laser(FlatCAMPostProc):
|
|||
|
||||
def start_code(self, p):
|
||||
units = ' ' + str(p['units']).lower()
|
||||
gcode = ''
|
||||
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\n'
|
||||
|
||||
xmin = '%.*f' % (p.coords_decimals, p['options']['xmin'])
|
||||
xmax = '%.*f' % (p.coords_decimals, p['options']['xmax'])
|
||||
|
@ -28,7 +29,9 @@ class grbl_laser(FlatCAMPostProc):
|
|||
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 += '(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'
|
||||
|
||||
|
@ -40,10 +43,12 @@ class grbl_laser(FlatCAMPostProc):
|
|||
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\n'
|
||||
gcode += 'G94'
|
||||
|
||||
return gcode
|
||||
|
||||
|
@ -51,19 +56,20 @@ class grbl_laser(FlatCAMPostProc):
|
|||
return ''
|
||||
|
||||
def lift_code(self, p):
|
||||
return 'M05 S0'
|
||||
return 'M5'
|
||||
|
||||
def down_code(self, p):
|
||||
sdir = {'CW': 'M03', 'CCW': 'M04'}[p.spindledir]
|
||||
if p.spindlespeed:
|
||||
return 'M03 S%d' % p.spindlespeed
|
||||
return '%s S%s' % (sdir, str(p.spindlespeed))
|
||||
else:
|
||||
return 'M03'
|
||||
return sdir
|
||||
|
||||
def toolchange_code(self, p):
|
||||
return ''
|
||||
|
||||
def up_to_zero_code(self, p):
|
||||
return 'M05'
|
||||
return 'M5'
|
||||
|
||||
def position_code(self, p):
|
||||
return ('X' + self.coordinate_format + ' Y' + self.coordinate_format) % \
|
||||
|
@ -77,10 +83,10 @@ class grbl_laser(FlatCAMPostProc):
|
|||
' F' + str(self.feedrate_format % (p.fr_decimals, p.feedrate))
|
||||
|
||||
def end_code(self, p):
|
||||
coords_xy = p['xy_toolchange']
|
||||
coords_xy = p['xy_end']
|
||||
gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + "\n")
|
||||
|
||||
if coords_xy is not None:
|
||||
if coords_xy and coords_xy != '':
|
||||
gcode += 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n"
|
||||
return gcode
|
||||
|
||||
|
@ -101,4 +107,4 @@ class grbl_laser(FlatCAMPostProc):
|
|||
return ''
|
||||
|
||||
def spindle_stop_code(self, p):
|
||||
return 'M05'
|
||||
return 'M5'
|
|
@ -17,7 +17,7 @@ class ISEL_CNC(FlatCAMPostProc):
|
|||
def start_code(self, p):
|
||||
units = ' ' + str(p['units']).lower()
|
||||
coords_xy = p['xy_toolchange']
|
||||
gcode = ''
|
||||
gcode = '(This preprocessor is used with a ISEL CNC router.)\n\n'
|
||||
|
||||
xmin = '%.*f' % (p.coords_decimals, p['options']['xmin'])
|
||||
xmax = '%.*f' % (p.coords_decimals, p['options']['xmax'])
|
||||
|
@ -26,28 +26,56 @@ class ISEL_CNC(FlatCAMPostProc):
|
|||
|
||||
if str(p['options']['type']) == 'Geometry':
|
||||
gcode += '(TOOL DIAMETER: ' + str(p['options']['tool_dia']) + units + ')\n'
|
||||
|
||||
gcode += '(Feedrate: ' + str(p['feedrate']) + units + '/min' + ')\n'
|
||||
|
||||
if str(p['options']['type']) == 'Geometry':
|
||||
gcode += '(Feedrate_XY: ' + str(p['feedrate']) + units + '/min' + ')\n'
|
||||
gcode += '(Feedrate_Z: ' + str(p['z_feedrate']) + units + '/min' + ')\n'
|
||||
|
||||
gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
|
||||
gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
|
||||
|
||||
if str(p['options']['type']) == 'Geometry':
|
||||
gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
|
||||
gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
|
||||
if p['multidepth'] is True:
|
||||
gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
|
||||
str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'
|
||||
gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
|
||||
|
||||
gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
|
||||
gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
|
||||
elif str(p['options']['type']) == 'Excellon' and p['use_ui'] is True:
|
||||
gcode += '\n(TOOLS DIAMETER: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Dia: %s' % str(val["C"]) + ')\n'
|
||||
|
||||
if coords_xy is not None:
|
||||
gcode += '(X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
|
||||
p.decimals, coords_xy[1]) + units + ')\n'
|
||||
else:
|
||||
gcode += '(X,Y Toolchange: ' + "None" + units + ')\n'
|
||||
gcode += '\n(FEEDRATE Z: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate: %s' % str(val['data']["feedrate_z"]) + ')\n'
|
||||
|
||||
gcode += '\n(FEEDRATE RAPIDS: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate Rapids: %s' % \
|
||||
str(val['data']["feedrate_rapid"]) + ')\n'
|
||||
|
||||
gcode += '\n(Z_CUT: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Z_Cut: %s' % str(val['data']["cutz"]) + ')\n'
|
||||
|
||||
gcode += '\n(Tools Offset: )\n'
|
||||
for tool, val in p['exc_cnc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(val['tool']) + 'Offset Z: %s' % str(val['offset_z']) + ')\n'
|
||||
|
||||
if p['multidepth'] is True:
|
||||
gcode += '\n(DEPTH_PER_CUT: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'DeptPerCut: %s' % \
|
||||
str(val['data']["depthperpass"]) + ')\n'
|
||||
|
||||
gcode += '\n(Z_MOVE: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Z_Move: %s' % str(val['data']["travelz"]) + ')\n'
|
||||
gcode += '\n'
|
||||
|
||||
if p['toolchange'] is True:
|
||||
gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
|
||||
|
||||
if coords_xy is not None:
|
||||
gcode += '(X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
|
||||
p.decimals, coords_xy[1]) + units + ')\n'
|
||||
else:
|
||||
gcode += '(X,Y Toolchange: ' + "None" + units + ')\n'
|
||||
|
||||
gcode += '(Z Start: ' + str(p['startz']) + units + ')\n'
|
||||
gcode += '(Z End: ' + str(p['z_end']) + units + ')\n'
|
||||
|
@ -129,10 +157,10 @@ M01""".format(tool=int(p.tool), toolC=toolC_formatted)
|
|||
return ('G01 ' + self.position_code(p)).format(**p)
|
||||
|
||||
def end_code(self, p):
|
||||
coords_xy = p['xy_toolchange']
|
||||
coords_xy = p['xy_end']
|
||||
gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + "\n")
|
||||
|
||||
if coords_xy is not None:
|
||||
if coords_xy and coords_xy != '':
|
||||
gcode += 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n"
|
||||
return gcode
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ class ISEL_ICP_CNC(FlatCAMPostProc):
|
|||
def start_code(self, p):
|
||||
units = ' ' + str(p['units']).lower()
|
||||
coords_xy = p['xy_toolchange']
|
||||
gcode = ''
|
||||
gcode = '; This preprocessor is used with a ISEL ICP CNC router.\n\n'
|
||||
|
||||
xmin = '%.*f' % (p.coords_decimals, p['options']['xmin'])
|
||||
xmax = '%.*f' % (p.coords_decimals, p['options']['xmax'])
|
||||
|
@ -25,36 +25,71 @@ class ISEL_ICP_CNC(FlatCAMPostProc):
|
|||
gcode += 'IMF_PBL flatcam\n\n'
|
||||
|
||||
if str(p['options']['type']) == 'Geometry':
|
||||
gcode += '; TOOL DIAMETER: ' + str(p['options']['tool_dia']) + units + '\n'
|
||||
gcode += '; Spindle Speed: %s RPM\n' % str(p['spindlespeed'])
|
||||
gcode += '; Feedrate: ' + str(p['feedrate']) + units + '/min' + '\n'
|
||||
if str(p['options']['type']) == 'Geometry':
|
||||
gcode += '; Feedrate_Z: ' + str(p['z_feedrate']) + units + '/min' + '\n'
|
||||
gcode += '\n'
|
||||
gcode += '; Z_Cut: ' + str(p['z_cut']) + units + '\n'
|
||||
|
||||
if str(p['options']['type']) == 'Geometry':
|
||||
gcode += ';TOOL DIAMETER: ' + str(p['options']['tool_dia']) + units + '\n'
|
||||
gcode += ';Feedrate_XY: ' + str(p['feedrate']) + units + '/min' + '\n'
|
||||
gcode += ';Feedrate_Z: ' + str(p['z_feedrate']) + units + '/min' + '\n'
|
||||
gcode += ';Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + '\n' + '\n'
|
||||
gcode += ';Z_Cut: ' + str(p['z_cut']) + units + '\n'
|
||||
if p['multidepth'] is True:
|
||||
gcode += '; DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
|
||||
gcode += ';DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
|
||||
str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + '\n'
|
||||
gcode += '; Z_Move: ' + str(p['z_move']) + units + '\n'
|
||||
gcode += '; Z Toolchange: ' + str(p['z_toolchange']) + units + '\n'
|
||||
if coords_xy is not None:
|
||||
gcode += '; X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
|
||||
p.decimals, coords_xy[1]) + units + '\n'
|
||||
else:
|
||||
gcode += '; X,Y Toolchange: ' + "None" + units + '\n'
|
||||
gcode += '; Z Start: ' + str(p['startz']) + units + '\n'
|
||||
gcode += '; Z End: ' + str(p['z_end']) + units + '\n'
|
||||
gcode += '; Steps per circle: ' + str(p['steps_per_circle']) + '\n'
|
||||
if str(p['options']['type']) == 'Excellon' or str(p['options']['type']) == 'Excellon Geometry':
|
||||
gcode += '; Preprocessor Excellon: ' + str(p['pp_excellon_name']) + '\n'
|
||||
else:
|
||||
gcode += '; Preprocessor Geometry: ' + str(p['pp_geometry_name']) + '\n'
|
||||
gcode += '\n'
|
||||
gcode += ';Z_Move: ' + str(p['z_move']) + units + '\n'
|
||||
|
||||
gcode += '; X range: ' + '{: >9s}'.format(xmin) + ' ... ' + '{: >9s}'.format(xmax) + ' ' + units + '\n'
|
||||
gcode += '; Y range: ' + '{: >9s}'.format(ymin) + ' ... ' + '{: >9s}'.format(ymax) + ' ' + units + '\n'
|
||||
elif str(p['options']['type']) == 'Excellon' and p['use_ui'] is True:
|
||||
gcode += '\n;TOOLS DIAMETER: \n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += ';Tool: %s -> ' % str(tool) + 'Dia: %s' % str(val["C"]) + '\n'
|
||||
|
||||
gcode += '\n;FEEDRATE Z: \n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += ';Tool: %s -> ' % str(tool) + 'Feedrate: %s' % str(val['data']["feedrate_z"]) + '\n'
|
||||
|
||||
gcode += '\n;FEEDRATE RAPIDS: \n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += ';Tool: %s -> ' % str(tool) + 'Feedrate Rapids: %s' % \
|
||||
str(val['data']["feedrate_rapid"]) + '\n'
|
||||
|
||||
gcode += '\n;Z_CUT: \n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += ';Tool: %s -> ' % str(tool) + 'Z_Cut: %s' % str(val['data']["cutz"]) + '\n'
|
||||
|
||||
gcode += '\n;Tools Offset: \n'
|
||||
for tool, val in p['exc_cnc_tools'].items():
|
||||
gcode += ';Tool: %s -> ' % str(val['tool']) + 'Offset Z: %s' % str(val['offset_z']) + '\n'
|
||||
|
||||
if p['multidepth'] is True:
|
||||
gcode += '\n;DEPTH_PER_CUT: \n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += ';Tool: %s -> ' % str(tool) + 'DeptPerCut: %s' % \
|
||||
str(val['data']["depthperpass"]) + '\n'
|
||||
|
||||
gcode += '\n;Z_MOVE: \n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += ';Tool: %s -> ' % str(tool) + 'Z_Move: %s' % str(val['data']["travelz"]) + '\n'
|
||||
gcode += '\n'
|
||||
|
||||
if p['toolchange'] is True:
|
||||
gcode += ';Z Toolchange: ' + str(p['z_toolchange']) + units + '\n'
|
||||
|
||||
if coords_xy is not None:
|
||||
gcode += ';X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
|
||||
p.decimals, coords_xy[1]) + units + '\n'
|
||||
else:
|
||||
gcode += ';X,Y Toolchange: ' + "None" + units + '\n'
|
||||
|
||||
gcode += ';Z Start: ' + str(p['startz']) + units + '\n'
|
||||
gcode += ';Z End: ' + str(p['z_end']) + units + '\n'
|
||||
gcode += ';Steps per circle: ' + str(p['steps_per_circle']) + '\n'
|
||||
|
||||
if str(p['options']['type']) == 'Excellon' or str(p['options']['type']) == 'Excellon Geometry':
|
||||
gcode += ';Preprocessor Excellon: ' + str(p['pp_excellon_name']) + '\n' + '\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 += ';Spindle Speed: %s RPM)\n' % str(p['spindlespeed'])
|
||||
|
||||
return gcode
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
from FlatCAMPostProc import *
|
||||
|
||||
|
||||
class marlin(FlatCAMPostProc):
|
||||
class Marlin(FlatCAMPostProc):
|
||||
|
||||
include_header = True
|
||||
coordinate_format = "%.*f"
|
||||
|
@ -27,47 +27,74 @@ class marlin(FlatCAMPostProc):
|
|||
ymax = '%.*f' % (p.coords_decimals, p['options']['ymax'])
|
||||
|
||||
if str(p['options']['type']) == 'Geometry':
|
||||
gcode += ';TOOL DIAMETER: ' + str(p['options']['tool_dia']) + units + '\n' + '\n'
|
||||
|
||||
gcode += ';Feedrate: ' + str(p['feedrate']) + units + '/min' + '\n'
|
||||
|
||||
if str(p['options']['type']) == 'Geometry':
|
||||
gcode += ';TOOL DIAMETER: ' + str(p['options']['tool_dia']) + units + '\n'
|
||||
gcode += ';Feedrate_XY: ' + str(p['feedrate']) + units + '/min' + '\n'
|
||||
gcode += ';Feedrate_Z: ' + str(p['z_feedrate']) + units + '/min' + '\n'
|
||||
|
||||
gcode += ';Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + '\n' + '\n'
|
||||
gcode += ';Z_Cut: ' + str(p['z_cut']) + units + '\n'
|
||||
|
||||
if str(p['options']['type']) == 'Geometry':
|
||||
gcode += ';Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + '\n' + '\n'
|
||||
gcode += ';Z_Cut: ' + str(p['z_cut']) + units + '\n'
|
||||
if p['multidepth'] is True:
|
||||
gcode += ';DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
|
||||
str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + '\n'
|
||||
gcode += ';Z_Move: ' + str(p['z_move']) + units + '\n'
|
||||
|
||||
gcode += ';Z_Move: ' + str(p['z_move']) + units + '\n'
|
||||
gcode += ';Z Toolchange: ' + str(p['z_toolchange']) + units + '\n'
|
||||
elif str(p['options']['type']) == 'Excellon' and p['use_ui'] is True:
|
||||
gcode += '\n;TOOLS DIAMETER: \n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += ';Tool: %s -> ' % str(tool) + 'Dia: %s' % str(val["C"]) + '\n'
|
||||
|
||||
if coords_xy is not None:
|
||||
gcode += ';X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
|
||||
p.decimals, coords_xy[1]) + units + '\n'
|
||||
else:
|
||||
gcode += ';X,Y Toolchange: ' + "None" + units + '\n'
|
||||
gcode += '\n;FEEDRATE Z: \n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += ';Tool: %s -> ' % str(tool) + 'Feedrate: %s' % str(val['data']["feedrate_z"]) + '\n'
|
||||
|
||||
gcode += '\n;FEEDRATE RAPIDS: \n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += ';Tool: %s -> ' % str(tool) + 'Feedrate Rapids: %s' % \
|
||||
str(val['data']["feedrate_rapid"]) + '\n'
|
||||
|
||||
gcode += '\n;Z_CUT: \n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += ';Tool: %s -> ' % str(tool) + 'Z_Cut: %s' % str(val['data']["cutz"]) + '\n'
|
||||
|
||||
gcode += '\n;Tools Offset: \n'
|
||||
for tool, val in p['exc_cnc_tools'].items():
|
||||
gcode += ';Tool: %s -> ' % str(val['tool']) + 'Offset Z: %s' % str(val['offset_z']) + '\n'
|
||||
|
||||
if p['multidepth'] is True:
|
||||
gcode += '\n;DEPTH_PER_CUT: \n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += ';Tool: %s -> ' % str(tool) + 'DeptPerCut: %s' % \
|
||||
str(val['data']["depthperpass"]) + '\n'
|
||||
|
||||
gcode += '\n;Z_MOVE: \n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += ';Tool: %s -> ' % str(tool) + 'Z_Move: %s' % str(val['data']["travelz"]) + '\n'
|
||||
gcode += '\n'
|
||||
|
||||
if p['toolchange'] is True:
|
||||
gcode += ';Z Toolchange: ' + str(p['z_toolchange']) + units + '\n'
|
||||
|
||||
if coords_xy is not None:
|
||||
gcode += ';X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
|
||||
p.decimals, coords_xy[1]) + units + '\n'
|
||||
else:
|
||||
gcode += ';X,Y Toolchange: ' + "None" + units + '\n'
|
||||
|
||||
gcode += ';Z Start: ' + str(p['startz']) + units + '\n'
|
||||
gcode += ';Z End: ' + str(p['z_end']) + units + '\n'
|
||||
gcode += ';Steps per circle: ' + str(p['steps_per_circle']) + '\n'
|
||||
|
||||
if str(p['options']['type']) == 'Excellon' or str(p['options']['type']) == 'Excellon Geometry':
|
||||
gcode += ';Preprocessor Excellon: ' + str(p['pp_excellon_name']) + '\n'
|
||||
gcode += ';Preprocessor Excellon: ' + str(p['pp_excellon_name']) + '\n' + '\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 += ';Spindle Speed: ' + str(p['spindlespeed']) + ' RPM' + '\n' + '\n'
|
||||
gcode += ';Spindle Speed: %s RPM)\n' % str(p['spindlespeed'])
|
||||
|
||||
gcode += ('G20' if p.units.upper() == 'IN' else 'G21') + "\n"
|
||||
gcode += 'G90\n'
|
||||
gcode += 'G94\n'
|
||||
gcode += 'G90'
|
||||
|
||||
return gcode
|
||||
|
||||
|
@ -188,10 +215,10 @@ G0 Z{z_toolchange}
|
|||
return ('G1 ' + self.position_code(p)).format(**p) + " " + self.inline_feedrate_code(p)
|
||||
|
||||
def end_code(self, p):
|
||||
coords_xy = p['xy_toolchange']
|
||||
coords_xy = p['xy_end']
|
||||
gcode = ('G0 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + " " + self.feedrate_rapid_code(p) + "\n")
|
||||
|
||||
if coords_xy is not None:
|
||||
if coords_xy and coords_xy != '':
|
||||
gcode += 'G0 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + " " + self.feedrate_rapid_code(p) + "\n"
|
||||
|
||||
return gcode
|
||||
|
@ -219,8 +246,11 @@ G0 Z{z_toolchange}
|
|||
return sdir
|
||||
|
||||
def dwell_code(self, p):
|
||||
gcode = 'G4 P' + str(p.dwelltime)
|
||||
if p.dwelltime:
|
||||
return 'G4 P' + str(p.dwelltime)
|
||||
return gcode
|
||||
|
||||
def spindle_stop_code(self, p):
|
||||
return 'M5'
|
||||
gcode = 'M400\n'
|
||||
gcode += 'M5'
|
||||
return gcode
|
|
@ -0,0 +1,120 @@
|
|||
# ##########################################################
|
||||
# FlatCAM: 2D Post-processing for Manufacturing #
|
||||
# Website: http://flatcam.org #
|
||||
# File Author: Marius Adrian Stanciu (c) #
|
||||
# Date: 8-Feb-2020 #
|
||||
# License: MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
from FlatCAMPostProc import *
|
||||
|
||||
|
||||
class Marlin_laser_FAN_pin(FlatCAMPostProc):
|
||||
|
||||
include_header = True
|
||||
coordinate_format = "%.*f"
|
||||
feedrate_format = '%.*f'
|
||||
feedrate_rapid_format = feedrate_format
|
||||
|
||||
def start_code(self, p):
|
||||
units = ' ' + str(p['units']).lower()
|
||||
coords_xy = p['xy_toolchange']
|
||||
gcode = ';This preprocessor is used with a motion controller loaded with MARLIN firmware.\n'
|
||||
gcode += ';It is for the case when it is used together with a LASER connected on one of the FAN pins.\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'
|
||||
|
||||
return gcode
|
||||
|
||||
def startz_code(self, p):
|
||||
if p.startz is not None:
|
||||
return 'G0 Z' + self.coordinate_format % (p.coords_decimals, p.z_move)
|
||||
else:
|
||||
return ''
|
||||
|
||||
def lift_code(self, p):
|
||||
gcode = 'M400\n'
|
||||
gcode += 'M107'
|
||||
return gcode
|
||||
|
||||
def down_code(self, p):
|
||||
if p.spindlespeed:
|
||||
return '%s S%s' % ('M106', str(p.spindlespeed))
|
||||
else:
|
||||
return 'M106'
|
||||
|
||||
def toolchange_code(self, p):
|
||||
return ''
|
||||
|
||||
def up_to_zero_code(self, p):
|
||||
gcode = 'M400\n'
|
||||
gcode += 'M107'
|
||||
return gcode
|
||||
|
||||
def position_code(self, p):
|
||||
return ('X' + self.coordinate_format + ' Y' + self.coordinate_format) % \
|
||||
(p.coords_decimals, p.x, p.coords_decimals, p.y)
|
||||
|
||||
def rapid_code(self, p):
|
||||
return ('G0 ' + self.position_code(p)).format(**p) + " " + self.feedrate_rapid_code(p)
|
||||
|
||||
def linear_code(self, p):
|
||||
return ('G1 ' + self.position_code(p)).format(**p) + " " + self.inline_feedrate_code(p)
|
||||
|
||||
def end_code(self, p):
|
||||
coords_xy = p['xy_end']
|
||||
gcode = ('G0 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + " " + self.feedrate_rapid_code(p) + "\n")
|
||||
|
||||
if coords_xy and coords_xy != '':
|
||||
gcode += 'G0 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + " " + self.feedrate_rapid_code(p) + "\n"
|
||||
|
||||
return gcode
|
||||
|
||||
def feedrate_code(self, p):
|
||||
return 'G1 F' + str(self.feedrate_format % (p.fr_decimals, p.feedrate))
|
||||
|
||||
def z_feedrate_code(self, p):
|
||||
return 'G1 F' + str(self.feedrate_format % (p.fr_decimals, p.z_feedrate))
|
||||
|
||||
def inline_feedrate_code(self, p):
|
||||
return 'F' + self.feedrate_format % (p.fr_decimals, p.feedrate)
|
||||
|
||||
def feedrate_rapid_code(self, p):
|
||||
return 'F' + self.feedrate_rapid_format % (p.fr_decimals, p.feedrate_rapid)
|
||||
|
||||
def spindle_code(self, p):
|
||||
if p.spindlespeed:
|
||||
return 'M106 S%s' % str(p.spindlespeed)
|
||||
else:
|
||||
return 'M106'
|
||||
|
||||
def dwell_code(self, p):
|
||||
return ''
|
||||
|
||||
def spindle_stop_code(self, p):
|
||||
gcode = 'M400\n'
|
||||
gcode += 'M106 S0'
|
||||
return gcode
|
|
@ -0,0 +1,122 @@
|
|||
# ##########################################################
|
||||
# FlatCAM: 2D Post-processing for Manufacturing #
|
||||
# Website: http://flatcam.org #
|
||||
# File Author: Marius Adrian Stanciu (c) #
|
||||
# Date: 8-Feb-2020 #
|
||||
# License: MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
from FlatCAMPostProc import *
|
||||
|
||||
|
||||
class Marlin_laser_Spindle_pin(FlatCAMPostProc):
|
||||
|
||||
include_header = True
|
||||
coordinate_format = "%.*f"
|
||||
feedrate_format = '%.*f'
|
||||
feedrate_rapid_format = feedrate_format
|
||||
|
||||
def start_code(self, p):
|
||||
units = ' ' + str(p['units']).lower()
|
||||
coords_xy = p['xy_toolchange']
|
||||
gcode = ';This preprocessor is used with a motion controller loaded with MARLIN firmware.\n'
|
||||
gcode += ';It is for the case when it is used together with a LASER connected on the SPINDLE connector.\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'
|
||||
|
||||
return gcode
|
||||
|
||||
def startz_code(self, p):
|
||||
if p.startz is not None:
|
||||
return 'G0 Z' + self.coordinate_format % (p.coords_decimals, p.z_move)
|
||||
else:
|
||||
return ''
|
||||
|
||||
def lift_code(self, p):
|
||||
gcode = 'M400\n'
|
||||
gcode += 'M5'
|
||||
return gcode
|
||||
|
||||
def down_code(self, p):
|
||||
sdir = {'CW': 'M3', 'CCW': 'M4'}[p.spindledir]
|
||||
if p.spindlespeed:
|
||||
return '%s S%s' % (sdir, str(p.spindlespeed))
|
||||
else:
|
||||
return sdir
|
||||
|
||||
def toolchange_code(self, p):
|
||||
return ''
|
||||
|
||||
def up_to_zero_code(self, p):
|
||||
gcode = 'M400\n'
|
||||
gcode += 'M5'
|
||||
return gcode
|
||||
|
||||
def position_code(self, p):
|
||||
return ('X' + self.coordinate_format + ' Y' + self.coordinate_format) % \
|
||||
(p.coords_decimals, p.x, p.coords_decimals, p.y)
|
||||
|
||||
def rapid_code(self, p):
|
||||
return ('G0 ' + self.position_code(p)).format(**p) + " " + self.feedrate_rapid_code(p)
|
||||
|
||||
def linear_code(self, p):
|
||||
return ('G1 ' + self.position_code(p)).format(**p) + " " + self.inline_feedrate_code(p)
|
||||
|
||||
def end_code(self, p):
|
||||
coords_xy = p['xy_end']
|
||||
gcode = ('G0 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + " " + self.feedrate_rapid_code(p) + "\n")
|
||||
|
||||
if coords_xy and coords_xy != '':
|
||||
gcode += 'G0 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + " " + self.feedrate_rapid_code(p) + "\n"
|
||||
|
||||
return gcode
|
||||
|
||||
def feedrate_code(self, p):
|
||||
return 'G1 F' + str(self.feedrate_format % (p.fr_decimals, p.feedrate))
|
||||
|
||||
def z_feedrate_code(self, p):
|
||||
return 'G1 F' + str(self.feedrate_format % (p.fr_decimals, p.z_feedrate))
|
||||
|
||||
def inline_feedrate_code(self, p):
|
||||
return 'F' + self.feedrate_format % (p.fr_decimals, p.feedrate)
|
||||
|
||||
def feedrate_rapid_code(self, p):
|
||||
return 'F' + self.feedrate_rapid_format % (p.fr_decimals, p.feedrate_rapid)
|
||||
|
||||
def spindle_code(self, p):
|
||||
sdir = {'CW': 'M3', 'CCW': 'M4'}[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):
|
||||
gcode = 'M400\n'
|
||||
gcode += 'M5'
|
||||
return gcode
|
|
@ -122,10 +122,10 @@ G00 Z{z_toolchange}
|
|||
return ('G01 ' + self.position_code(p)).format(**p)
|
||||
|
||||
def end_code(self, p):
|
||||
coords_xy = [float(eval(a)) for a in p['xy_toolchange'].split(",") if a != '']
|
||||
coords_xy = [float(eval(a)) for a in p['xy_end'].split(",") if a != '']
|
||||
gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, float(p['z_toolchange'])) + "\n")
|
||||
|
||||
if coords_xy is not None:
|
||||
if coords_xy and coords_xy != '':
|
||||
gcode += 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n"
|
||||
return gcode
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ class Repetier(FlatCAMPostProc):
|
|||
def start_code(self, p):
|
||||
units = ' ' + str(p['units']).lower()
|
||||
coords_xy = p['xy_toolchange']
|
||||
gcode = ''
|
||||
gcode = ';This preprocessor is used with a motion controller loaded with REPETIER firmware.\n\n'
|
||||
|
||||
xmin = '%.*f' % (p.coords_decimals, p['options']['xmin'])
|
||||
xmax = '%.*f' % (p.coords_decimals, p['options']['xmax'])
|
||||
|
@ -27,43 +27,71 @@ class Repetier(FlatCAMPostProc):
|
|||
ymax = '%.*f' % (p.coords_decimals, p['options']['ymax'])
|
||||
|
||||
if str(p['options']['type']) == 'Geometry':
|
||||
gcode += ';TOOL DIAMETER: ' + str(p['options']['tool_dia']) + units + '\n' + '\n'
|
||||
|
||||
gcode += ';Feedrate: ' + str(p['feedrate']) + units + '/min' + '\n'
|
||||
|
||||
if str(p['options']['type']) == 'Geometry':
|
||||
gcode += ';TOOL DIAMETER: ' + str(p['options']['tool_dia']) + units + '\n'
|
||||
gcode += ';Feedrate_XY: ' + str(p['feedrate']) + units + '/min' + '\n'
|
||||
gcode += ';Feedrate_Z: ' + str(p['z_feedrate']) + units + '/min' + '\n'
|
||||
|
||||
gcode += ';Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + '\n' + '\n'
|
||||
gcode += ';Z_Cut: ' + str(p['z_cut']) + units + '\n'
|
||||
|
||||
if str(p['options']['type']) == 'Geometry':
|
||||
gcode += ';Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + '\n' + '\n'
|
||||
gcode += ';Z_Cut: ' + str(p['z_cut']) + units + '\n'
|
||||
if p['multidepth'] is True:
|
||||
gcode += ';DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
|
||||
str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + '\n'
|
||||
gcode += ';Z_Move: ' + str(p['z_move']) + units + '\n'
|
||||
|
||||
gcode += ';Z_Move: ' + str(p['z_move']) + units + '\n'
|
||||
gcode += ';Z Toolchange: ' + str(p['z_toolchange']) + units + '\n'
|
||||
elif str(p['options']['type']) == 'Excellon' and p['use_ui'] is True:
|
||||
gcode += '\n;TOOLS DIAMETER: \n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += ';Tool: %s -> ' % str(tool) + 'Dia: %s' % str(val["C"]) + '\n'
|
||||
|
||||
if coords_xy is not None:
|
||||
gcode += ';X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
|
||||
p.decimals, coords_xy[1]) + units + '\n'
|
||||
else:
|
||||
gcode += ';X,Y Toolchange: ' + "None" + units + '\n'
|
||||
gcode += '\n;FEEDRATE Z: \n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += ';Tool: %s -> ' % str(tool) + 'Feedrate: %s' % str(val['data']["feedrate_z"]) + '\n'
|
||||
|
||||
gcode += '\n;FEEDRATE RAPIDS: \n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += ';Tool: %s -> ' % str(tool) + 'Feedrate Rapids: %s' % \
|
||||
str(val['data']["feedrate_rapid"]) + '\n'
|
||||
|
||||
gcode += '\n;Z_CUT: \n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += ';Tool: %s -> ' % str(tool) + 'Z_Cut: %s' % str(val['data']["cutz"]) + '\n'
|
||||
|
||||
gcode += '\n;Tools Offset: \n'
|
||||
for tool, val in p['exc_cnc_tools'].items():
|
||||
gcode += ';Tool: %s -> ' % str(val['tool']) + 'Offset Z: %s' % str(val['offset_z']) + '\n'
|
||||
|
||||
if p['multidepth'] is True:
|
||||
gcode += '\n;DEPTH_PER_CUT: \n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += ';Tool: %s -> ' % str(tool) + 'DeptPerCut: %s' % \
|
||||
str(val['data']["depthperpass"]) + '\n'
|
||||
|
||||
gcode += '\n;Z_MOVE: \n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += ';Tool: %s -> ' % str(tool) + 'Z_Move: %s' % str(val['data']["travelz"]) + '\n'
|
||||
gcode += '\n'
|
||||
|
||||
if p['toolchange'] is True:
|
||||
gcode += ';Z Toolchange: ' + str(p['z_toolchange']) + units + '\n'
|
||||
|
||||
if coords_xy is not None:
|
||||
gcode += ';X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
|
||||
p.decimals, coords_xy[1]) + units + '\n'
|
||||
else:
|
||||
gcode += ';X,Y Toolchange: ' + "None" + units + '\n'
|
||||
|
||||
gcode += ';Z Start: ' + str(p['startz']) + units + '\n'
|
||||
gcode += ';Z End: ' + str(p['z_end']) + units + '\n'
|
||||
gcode += ';Steps per circle: ' + str(p['steps_per_circle']) + '\n'
|
||||
|
||||
if str(p['options']['type']) == 'Excellon' or str(p['options']['type']) == 'Excellon Geometry':
|
||||
gcode += ';Preprocessor Excellon: ' + str(p['pp_excellon_name']) + '\n'
|
||||
gcode += ';Preprocessor Excellon: ' + str(p['pp_excellon_name']) + '\n' + '\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 += ';Spindle Speed: ' + str(p['spindlespeed']) + ' RPM' + '\n' + '\n'
|
||||
gcode += ';Spindle Speed: %s RPM)\n' % str(p['spindlespeed'])
|
||||
|
||||
gcode += ('G20' if p.units.upper() == 'IN' else 'G21') + "\n"
|
||||
gcode += 'G90\n'
|
||||
|
@ -178,10 +206,10 @@ G0 Z{z_toolchange}
|
|||
return ('G1 ' + self.position_code(p)).format(**p) + " " + self.inline_feedrate_code(p)
|
||||
|
||||
def end_code(self, p):
|
||||
coords_xy = p['xy_toolchange']
|
||||
coords_xy = p['xy_end']
|
||||
gcode = ('G0 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + " " + self.feedrate_rapid_code(p) + "\n")
|
||||
|
||||
if coords_xy is not None:
|
||||
if coords_xy and coords_xy != '':
|
||||
gcode += 'G0 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + " " + self.feedrate_rapid_code(p) + "\n"
|
||||
|
||||
return gcode
|
||||
|
|
|
@ -27,35 +27,63 @@ class Toolchange_Custom(FlatCAMPostProc):
|
|||
|
||||
if str(p['options']['type']) == 'Geometry':
|
||||
gcode += '(TOOL DIAMETER: ' + str(p['options']['tool_dia']) + units + ')\n'
|
||||
|
||||
gcode += '(Feedrate: ' + str(p['feedrate']) + units + '/min' + ')\n'
|
||||
|
||||
if str(p['options']['type']) == 'Geometry':
|
||||
gcode += '(Feedrate_XY: ' + str(p['feedrate']) + units + '/min' + ')\n'
|
||||
gcode += '(Feedrate_Z: ' + str(p['z_feedrate']) + units + '/min' + ')\n'
|
||||
|
||||
gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
|
||||
gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
|
||||
|
||||
if str(p['options']['type']) == 'Geometry':
|
||||
gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
|
||||
gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
|
||||
if p['multidepth'] is True:
|
||||
gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
|
||||
str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'
|
||||
gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
|
||||
|
||||
gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
|
||||
gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
|
||||
elif str(p['options']['type']) == 'Excellon' and p['use_ui'] is True:
|
||||
gcode += '\n(TOOLS DIAMETER: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Dia: %s' % str(val["C"]) + ')\n'
|
||||
|
||||
if coords_xy is not None:
|
||||
gcode += '(X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
|
||||
p.decimals, coords_xy[1]) + units + ')\n'
|
||||
else:
|
||||
gcode += '(X,Y Toolchange: ' + "None" + units + ')\n'
|
||||
gcode += '\n(FEEDRATE Z: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate: %s' % str(val['data']["feedrate_z"]) + ')\n'
|
||||
|
||||
gcode += '\n(FEEDRATE RAPIDS: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate Rapids: %s' % \
|
||||
str(val['data']["feedrate_rapid"]) + ')\n'
|
||||
|
||||
gcode += '\n(Z_CUT: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Z_Cut: %s' % str(val['data']["cutz"]) + ')\n'
|
||||
|
||||
gcode += '\n(Tools Offset: )\n'
|
||||
for tool, val in p['exc_cnc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(val['tool']) + 'Offset Z: %s' % str(val['offset_z']) + ')\n'
|
||||
|
||||
if p['multidepth'] is True:
|
||||
gcode += '\n(DEPTH_PER_CUT: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'DeptPerCut: %s' % \
|
||||
str(val['data']["depthperpass"]) + ')\n'
|
||||
|
||||
gcode += '\n(Z_MOVE: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Z_Move: %s' % str(val['data']["travelz"]) + ')\n'
|
||||
gcode += '\n'
|
||||
|
||||
if p['toolchange'] is True:
|
||||
gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
|
||||
|
||||
if coords_xy is not None:
|
||||
gcode += '(X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
|
||||
p.decimals, coords_xy[1]) + units + ')\n'
|
||||
else:
|
||||
gcode += '(X,Y Toolchange: ' + "None" + units + ')\n'
|
||||
|
||||
gcode += '(Z Start: ' + str(p['startz']) + units + ')\n'
|
||||
gcode += '(Z End: ' + str(p['z_end']) + units + ')\n'
|
||||
gcode += '(Steps per circle: ' + str(p['steps_per_circle']) + ')\n'
|
||||
|
||||
if str(p['options']['type']) == 'Excellon' or str(p['options']['type']) == 'Excellon Geometry':
|
||||
gcode += '(Preprocessor Excellon: ' + str(p['pp_excellon_name']) + ')\n'
|
||||
gcode += '(Preprocessor Excellon: ' + str(p['pp_excellon_name']) + ')\n' + '\n'
|
||||
else:
|
||||
gcode += '(Preprocessor Geometry: ' + str(p['pp_geometry_name']) + ')\n' + '\n'
|
||||
|
||||
|
@ -145,10 +173,10 @@ M6
|
|||
return ('G01 ' + self.position_code(p)).format(**p)
|
||||
|
||||
def end_code(self, p):
|
||||
coords_xy = p['xy_toolchange']
|
||||
coords_xy = p['xy_end']
|
||||
gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + "\n")
|
||||
|
||||
if coords_xy is not None:
|
||||
if coords_xy and coords_xy != '':
|
||||
gcode += 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n"
|
||||
return gcode
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
from FlatCAMPostProc import *
|
||||
|
||||
|
||||
class Toolchange_manual(FlatCAMPostProc):
|
||||
class Toolchange_Manual(FlatCAMPostProc):
|
||||
|
||||
include_header = True
|
||||
coordinate_format = "%.*f"
|
||||
|
@ -27,27 +27,57 @@ class Toolchange_manual(FlatCAMPostProc):
|
|||
|
||||
if str(p['options']['type']) == 'Geometry':
|
||||
gcode += '(TOOL DIAMETER: ' + str(p['options']['tool_dia']) + units + ')\n'
|
||||
|
||||
gcode += '(Feedrate: ' + str(p['feedrate']) + units + '/min' + ')\n'
|
||||
|
||||
if str(p['options']['type']) == 'Geometry':
|
||||
gcode += '(Feedrate_XY: ' + str(p['feedrate']) + units + '/min' + ')\n'
|
||||
gcode += '(Feedrate_Z: ' + str(p['z_feedrate']) + units + '/min' + ')\n'
|
||||
|
||||
gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
|
||||
gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
|
||||
|
||||
if str(p['options']['type']) == 'Geometry':
|
||||
gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
|
||||
gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
|
||||
if p['multidepth'] is True:
|
||||
gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
|
||||
str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'
|
||||
gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
|
||||
|
||||
elif str(p['options']['type']) == 'Excellon' and p['use_ui'] is True:
|
||||
gcode += '\n(TOOLS DIAMETER: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Dia: %s' % str(val["C"]) + ')\n'
|
||||
|
||||
gcode += '\n(FEEDRATE Z: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate: %s' % str(val['data']["feedrate_z"]) + ')\n'
|
||||
|
||||
gcode += '\n(FEEDRATE RAPIDS: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate Rapids: %s' % \
|
||||
str(val['data']["feedrate_rapid"]) + ')\n'
|
||||
|
||||
gcode += '\n(Z_CUT: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Z_Cut: %s' % str(val['data']["cutz"]) + ')\n'
|
||||
|
||||
gcode += '\n(Tools Offset: )\n'
|
||||
for tool, val in p['exc_cnc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(val['tool']) + 'Offset Z: %s' % str(val['offset_z']) + ')\n'
|
||||
|
||||
if p['multidepth'] is True:
|
||||
gcode += '\n(DEPTH_PER_CUT: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'DeptPerCut: %s' % \
|
||||
str(val['data']["depthperpass"]) + ')\n'
|
||||
|
||||
gcode += '\n(Z_MOVE: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Z_Move: %s' % str(val['data']["travelz"]) + ')\n'
|
||||
gcode += '\n'
|
||||
|
||||
if p['toolchange'] is True:
|
||||
gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
|
||||
|
||||
if coords_xy is not None:
|
||||
gcode += '(X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
|
||||
p.decimals, coords_xy[1]) + units + ')\n'
|
||||
else:
|
||||
gcode += '(X,Y Toolchange: ' + "None" + units + ')\n'
|
||||
|
||||
gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
|
||||
gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
|
||||
if coords_xy is not None:
|
||||
gcode += '(X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
|
||||
p.decimals, coords_xy[1]) + units + ')\n'
|
||||
else:
|
||||
gcode += '(X,Y Toolchange: ' + "None" + units + ')\n'
|
||||
gcode += '(Z Start: ' + str(p['startz']) + units + ')\n'
|
||||
gcode += '(Z End: ' + str(p['z_end']) + units + ')\n'
|
||||
gcode += '(Steps per circle: ' + str(p['steps_per_circle']) + ')\n'
|
||||
|
@ -119,6 +149,7 @@ M0
|
|||
G00 Z{z_toolchange}
|
||||
(MSG, Now the tool can be tightened more securely.)
|
||||
M0
|
||||
(MSG, Drilling with Tool Dia = {toolC} ||| Total drills for tool T{tool} = {t_drills})
|
||||
""".format(x_toolchange=self.coordinate_format % (p.coords_decimals, x_toolchange),
|
||||
y_toolchange=self.coordinate_format % (p.coords_decimals, y_toolchange),
|
||||
z_toolchange=self.coordinate_format % (p.coords_decimals, z_toolchange),
|
||||
|
@ -139,6 +170,7 @@ M0
|
|||
G00 Z{z_toolchange}
|
||||
(MSG, Now the tool can be tightened more securely.)
|
||||
M0
|
||||
(MSG, Milling with Tool Dia = {toolC} ||| Total drills for tool T{tool} = {t_drills})
|
||||
""".format(
|
||||
z_toolchange=self.coordinate_format % (p.coords_decimals, z_toolchange),
|
||||
tool=int(p.tool),
|
||||
|
@ -203,12 +235,11 @@ M0
|
|||
return ('G01 ' + self.position_code(p)).format(**p)
|
||||
|
||||
def end_code(self, p):
|
||||
coords_xy = p['xy_toolchange']
|
||||
coords_xy = p['xy_end']
|
||||
gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + "\n")
|
||||
if coords_xy is not None:
|
||||
|
||||
if coords_xy and coords_xy != '':
|
||||
gcode += 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n"
|
||||
else:
|
||||
gcode += 'G00 X0 Y0' + "\n"
|
||||
return gcode
|
||||
|
||||
def feedrate_code(self, p):
|
|
@ -18,7 +18,7 @@ class Toolchange_Probe_MACH3(FlatCAMPostProc):
|
|||
def start_code(self, p):
|
||||
units = ' ' + str(p['units']).lower()
|
||||
coords_xy = p['xy_toolchange']
|
||||
gcode = ''
|
||||
gcode = '(This preprocessor is used with MACH3 with probing height.)\n\n'
|
||||
|
||||
xmin = '%.*f' % (p.coords_decimals, p['options']['xmin'])
|
||||
xmax = '%.*f' % (p.coords_decimals, p['options']['xmax'])
|
||||
|
@ -27,37 +27,63 @@ class Toolchange_Probe_MACH3(FlatCAMPostProc):
|
|||
|
||||
if str(p['options']['type']) == 'Geometry':
|
||||
gcode += '(TOOL DIAMETER: ' + str(p['options']['tool_dia']) + units + ')\n'
|
||||
|
||||
gcode += '(Feedrate: ' + str(p['feedrate']) + units + '/min' + ')\n'
|
||||
|
||||
if str(p['options']['type']) == 'Geometry':
|
||||
gcode += '(Feedrate_XY: ' + str(p['feedrate']) + units + '/min' + ')\n'
|
||||
gcode += '(Feedrate_Z: ' + str(p['z_feedrate']) + units + '/min' + ')\n'
|
||||
|
||||
gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
|
||||
gcode += '(Feedrate Probe ' + str(p['feedrate_probe']) + units + '/min' + ')\n' + '\n'
|
||||
gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
|
||||
|
||||
if str(p['options']['type']) == 'Geometry':
|
||||
gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
|
||||
gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
|
||||
if p['multidepth'] is True:
|
||||
gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
|
||||
str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'
|
||||
gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
|
||||
|
||||
gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
|
||||
gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
|
||||
elif str(p['options']['type']) == 'Excellon' and p['use_ui'] is True:
|
||||
gcode += '\n(TOOLS DIAMETER: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Dia: %s' % str(val["C"]) + ')\n'
|
||||
|
||||
if coords_xy is not None:
|
||||
gcode += '(X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
|
||||
p.decimals, coords_xy[1]) + units + ')\n'
|
||||
else:
|
||||
gcode += '(X,Y Toolchange: ' + "None" + units + ')\n'
|
||||
gcode += '\n(FEEDRATE Z: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate: %s' % str(val['data']["feedrate_z"]) + ')\n'
|
||||
|
||||
gcode += '\n(FEEDRATE RAPIDS: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate Rapids: %s' % \
|
||||
str(val['data']["feedrate_rapid"]) + ')\n'
|
||||
|
||||
gcode += '\n(Z_CUT: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Z_Cut: %s' % str(val['data']["cutz"]) + ')\n'
|
||||
|
||||
gcode += '\n(Tools Offset: )\n'
|
||||
for tool, val in p['exc_cnc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(val['tool']) + 'Offset Z: %s' % str(val['offset_z']) + ')\n'
|
||||
|
||||
if p['multidepth'] is True:
|
||||
gcode += '\n(DEPTH_PER_CUT: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'DeptPerCut: %s' % \
|
||||
str(val['data']["depthperpass"]) + ')\n'
|
||||
|
||||
gcode += '\n(Z_MOVE: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Z_Move: %s' % str(val['data']["travelz"]) + ')\n'
|
||||
gcode += '\n'
|
||||
|
||||
if p['toolchange'] is True:
|
||||
gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
|
||||
|
||||
if coords_xy is not None:
|
||||
gcode += '(X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
|
||||
p.decimals, coords_xy[1]) + units + ')\n'
|
||||
else:
|
||||
gcode += '(X,Y Toolchange: ' + "None" + units + ')\n'
|
||||
|
||||
gcode += '(Z Start: ' + str(p['startz']) + units + ')\n'
|
||||
gcode += '(Z End: ' + str(p['z_end']) + units + ')\n'
|
||||
gcode += '(Z Probe Depth: ' + str(p['z_pdepth']) + 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'
|
||||
gcode += '(Preprocessor Excellon: ' + str(p['pp_excellon_name']) + ')\n' + '\n'
|
||||
else:
|
||||
gcode += '(Preprocessor Geometry: ' + str(p['pp_geometry_name']) + ')\n' + '\n'
|
||||
|
||||
|
@ -246,10 +272,10 @@ M0
|
|||
return ('G01 ' + self.position_code(p)).format(**p)
|
||||
|
||||
def end_code(self, p):
|
||||
coords_xy = p['xy_toolchange']
|
||||
coords_xy = p['xy_end']
|
||||
gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + "\n")
|
||||
|
||||
if coords_xy is not None:
|
||||
if coords_xy and coords_xy != '':
|
||||
gcode += 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n"
|
||||
return gcode
|
||||
|
||||
|
|
|
@ -18,7 +18,8 @@ class default(FlatCAMPostProc):
|
|||
def start_code(self, p):
|
||||
units = ' ' + str(p['units']).lower()
|
||||
coords_xy = p['xy_toolchange']
|
||||
gcode = ''
|
||||
gcode = '(This preprocessor is the default preprocessor used by FlatCAM.)\n'
|
||||
gcode += '(It is made to work with MACH3 compatible motion controllers.)\n\n'
|
||||
|
||||
xmin = '%.*f' % (p.coords_decimals, p['options']['xmin'])
|
||||
xmax = '%.*f' % (p.coords_decimals, p['options']['xmax'])
|
||||
|
@ -27,28 +28,56 @@ class default(FlatCAMPostProc):
|
|||
|
||||
if str(p['options']['type']) == 'Geometry':
|
||||
gcode += '(TOOL DIAMETER: ' + str(p['options']['tool_dia']) + units + ')\n'
|
||||
|
||||
gcode += '(Feedrate: ' + str(p['feedrate']) + units + '/min' + ')\n'
|
||||
|
||||
if str(p['options']['type']) == 'Geometry':
|
||||
gcode += '(Feedrate_XY: ' + str(p['feedrate']) + units + '/min' + ')\n'
|
||||
gcode += '(Feedrate_Z: ' + str(p['z_feedrate']) + units + '/min' + ')\n'
|
||||
|
||||
gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
|
||||
gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
|
||||
|
||||
if str(p['options']['type']) == 'Geometry':
|
||||
gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
|
||||
gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
|
||||
if p['multidepth'] is True:
|
||||
gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
|
||||
str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'
|
||||
gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
|
||||
|
||||
gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
|
||||
gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
|
||||
elif str(p['options']['type']) == 'Excellon' and p['use_ui'] is True:
|
||||
gcode += '\n(TOOLS DIAMETER: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Dia: %s' % str(val["C"]) + ')\n'
|
||||
|
||||
if coords_xy is not None:
|
||||
gcode += '(X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
|
||||
p.decimals, coords_xy[1]) + units + ')\n'
|
||||
else:
|
||||
gcode += '(X,Y Toolchange: ' + "None" + units + ')\n'
|
||||
gcode += '\n(FEEDRATE Z: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate: %s' % str(val['data']["feedrate_z"]) + ')\n'
|
||||
|
||||
gcode += '\n(FEEDRATE RAPIDS: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate Rapids: %s' % \
|
||||
str(val['data']["feedrate_rapid"]) + ')\n'
|
||||
|
||||
gcode += '\n(Z_CUT: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Z_Cut: %s' % str(val['data']["cutz"]) + ')\n'
|
||||
|
||||
gcode += '\n(Tools Offset: )\n'
|
||||
for tool, val in p['exc_cnc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(val['tool']) + 'Offset Z: %s' % str(val['offset_z']) + ')\n'
|
||||
|
||||
if p['multidepth'] is True:
|
||||
gcode += '\n(DEPTH_PER_CUT: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'DeptPerCut: %s' % \
|
||||
str(val['data']["depthperpass"]) + ')\n'
|
||||
|
||||
gcode += '\n(Z_MOVE: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Z_Move: %s' % str(val['data']["travelz"]) + ')\n'
|
||||
gcode += '\n'
|
||||
|
||||
if p['toolchange'] is True:
|
||||
gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
|
||||
|
||||
if coords_xy is not None:
|
||||
gcode += '(X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
|
||||
p.decimals, coords_xy[1]) + units + ')\n'
|
||||
else:
|
||||
gcode += '(X,Y Toolchange: ' + "None" + units + ')\n'
|
||||
|
||||
gcode += '(Z Start: ' + str(p['startz']) + units + ')\n'
|
||||
gcode += '(Z End: ' + str(p['z_end']) + units + ')\n'
|
||||
|
@ -66,7 +95,7 @@ class default(FlatCAMPostProc):
|
|||
|
||||
gcode += ('G20\n' if p.units.upper() == 'IN' else 'G21\n')
|
||||
gcode += 'G90\n'
|
||||
gcode += 'G94\n'
|
||||
gcode += 'G94'
|
||||
|
||||
return gcode
|
||||
|
||||
|
@ -117,11 +146,11 @@ M6
|
|||
M0
|
||||
G00 Z{z_toolchange}
|
||||
""".format(x_toolchange=self.coordinate_format % (p.coords_decimals, x_toolchange),
|
||||
y_toolchange=self.coordinate_format % (p.coords_decimals, y_toolchange),
|
||||
z_toolchange=self.coordinate_format % (p.coords_decimals, z_toolchange),
|
||||
tool=int(p.tool),
|
||||
t_drills=no_drills,
|
||||
toolC=toolC_formatted)
|
||||
y_toolchange=self.coordinate_format % (p.coords_decimals, y_toolchange),
|
||||
z_toolchange=self.coordinate_format % (p.coords_decimals, z_toolchange),
|
||||
tool=int(p.tool),
|
||||
t_drills=no_drills,
|
||||
toolC=toolC_formatted)
|
||||
else:
|
||||
gcode = """
|
||||
M5
|
||||
|
@ -188,11 +217,11 @@ G00 Z{z_toolchange}
|
|||
return ('G01 ' + self.position_code(p)).format(**p)
|
||||
|
||||
def end_code(self, p):
|
||||
coords_xy = p['xy_toolchange']
|
||||
end_coords_xy = p['xy_end']
|
||||
gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + "\n")
|
||||
|
||||
if coords_xy is not None:
|
||||
gcode += 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n"
|
||||
if end_coords_xy and end_coords_xy != '':
|
||||
gcode += 'G00 X{x} Y{y}'.format(x=end_coords_xy[0], y=end_coords_xy[1]) + "\n"
|
||||
return gcode
|
||||
|
||||
def feedrate_code(self, p):
|
||||
|
|
|
@ -18,7 +18,8 @@ class grbl_11(FlatCAMPostProc):
|
|||
def start_code(self, p):
|
||||
units = ' ' + str(p['units']).lower()
|
||||
coords_xy = p['xy_toolchange']
|
||||
gcode = ''
|
||||
gcode = '(This preprocessor is used with a motion controller loaded with GRBL firmware.)\n'
|
||||
gcode += '(It is configured to be compatible with almost any version of GRBL firmware.)\n\n'
|
||||
|
||||
xmin = '%.*f' % (p.coords_decimals, p['options']['xmin'])
|
||||
xmax = '%.*f' % (p.coords_decimals, p['options']['xmax'])
|
||||
|
@ -26,41 +27,71 @@ class grbl_11(FlatCAMPostProc):
|
|||
ymax = '%.*f' % (p.coords_decimals, p['options']['ymax'])
|
||||
|
||||
if str(p['options']['type']) == 'Geometry':
|
||||
gcode += '(TOOL DIAMETER: ' + str(p['options']['tool_dia']) + units + ')\n' + '\n'
|
||||
|
||||
gcode += '(Feedrate: ' + str(p['feedrate']) + units + '/min' + ')\n'
|
||||
|
||||
if str(p['options']['type']) == 'Geometry':
|
||||
gcode += '(TOOL DIAMETER: ' + str(p['options']['tool_dia']) + units + ')\n'
|
||||
gcode += '(Feedrate_XY: ' + str(p['feedrate']) + units + '/min' + ')\n'
|
||||
gcode += '(Feedrate_Z: ' + str(p['z_feedrate']) + units + '/min' + ')\n'
|
||||
|
||||
gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
|
||||
gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
|
||||
|
||||
if str(p['options']['type']) == 'Geometry':
|
||||
gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
|
||||
gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
|
||||
if p['multidepth'] is True:
|
||||
gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
|
||||
str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'
|
||||
gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
|
||||
|
||||
elif str(p['options']['type']) == 'Excellon' and p['use_ui'] is True:
|
||||
gcode += '\n(TOOLS DIAMETER: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Dia: %s' % str(val["C"]) + ')\n'
|
||||
|
||||
gcode += '\n(FEEDRATE Z: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate: %s' % str(val['data']["feedrate_z"]) + ')\n'
|
||||
|
||||
gcode += '\n(FEEDRATE RAPIDS: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate Rapids: %s' % \
|
||||
str(val['data']["feedrate_rapid"]) + ')\n'
|
||||
|
||||
gcode += '\n(Z_CUT: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Z_Cut: %s' % str(val['data']["cutz"]) + ')\n'
|
||||
|
||||
gcode += '\n(Tools Offset: )\n'
|
||||
for tool, val in p['exc_cnc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(val['tool']) + 'Offset Z: %s' % str(val['offset_z']) + ')\n'
|
||||
|
||||
if p['multidepth'] is True:
|
||||
gcode += '\n(DEPTH_PER_CUT: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'DeptPerCut: %s' % \
|
||||
str(val['data']["depthperpass"]) + ')\n'
|
||||
|
||||
gcode += '\n(Z_MOVE: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Z_Move: %s' % str(val['data']["travelz"]) + ')\n'
|
||||
gcode += '\n'
|
||||
|
||||
if p['toolchange'] is True:
|
||||
gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
|
||||
|
||||
if coords_xy is not None:
|
||||
gcode += '(X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
|
||||
p.decimals, coords_xy[1]) + units + ')\n'
|
||||
else:
|
||||
gcode += '(X,Y Toolchange: ' + "None" + units + ')\n'
|
||||
|
||||
gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
|
||||
gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
|
||||
if coords_xy is not None:
|
||||
gcode += '(X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
|
||||
p.decimals, coords_xy[1]) + units + ')\n'
|
||||
else:
|
||||
gcode += '(X,Y Toolchange: ' + "None" + units + ')\n'
|
||||
gcode += '(Z Start: ' + str(p['startz']) + units + ')\n'
|
||||
gcode += '(Z End: ' + str(p['z_end']) + units + ')\n'
|
||||
gcode += '(Steps per circle: ' + str(p['steps_per_circle']) + ')\n'
|
||||
|
||||
if str(p['options']['type']) == 'Excellon' or str(p['options']['type']) == 'Excellon Geometry':
|
||||
gcode += '(Preprocessor Excellon: ' + str(p['pp_excellon_name']) + ')\n'
|
||||
gcode += '(Preprocessor Excellon: ' + str(p['pp_excellon_name']) + ')\n' + '\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 += '(Spindle Speed: ' + str(p['spindlespeed']) + ' RPM' + ')\n' + '\n'
|
||||
gcode += '(Spindle Speed: %s RPM)\n' % str(p['spindlespeed'])
|
||||
|
||||
gcode += ('G20' if p.units.upper() == 'IN' else 'G21') + "\n"
|
||||
gcode += 'G90\n'
|
||||
|
@ -187,10 +218,10 @@ G00 Z{z_toolchange}
|
|||
' F' + str(self.feedrate_format % (p.fr_decimals, p.feedrate))
|
||||
|
||||
def end_code(self, p):
|
||||
coords_xy = p['xy_toolchange']
|
||||
coords_xy = p['xy_end']
|
||||
gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + "\n")
|
||||
|
||||
if coords_xy is not None:
|
||||
if coords_xy and coords_xy != '':
|
||||
gcode += 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n"
|
||||
return gcode
|
||||
|
||||
|
|
|
@ -27,33 +27,63 @@ class line_xyz(FlatCAMPostProc):
|
|||
|
||||
if str(p['options']['type']) == 'Geometry':
|
||||
gcode += '(TOOL DIAMETER: ' + str(p['options']['tool_dia']) + units + ')\n'
|
||||
|
||||
gcode += '(Feedrate: ' + str(p['feedrate']) + units + '/min' + ')\n'
|
||||
|
||||
if str(p['options']['type']) == 'Geometry':
|
||||
gcode += '(Feedrate_XY: ' + str(p['feedrate']) + units + '/min' + ')\n'
|
||||
gcode += '(Feedrate_Z: ' + str(p['z_feedrate']) + units + '/min' + ')\n'
|
||||
|
||||
gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
|
||||
gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
|
||||
|
||||
if str(p['options']['type']) == 'Geometry':
|
||||
gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n'
|
||||
gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n'
|
||||
if p['multidepth'] is True:
|
||||
gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \
|
||||
str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n'
|
||||
gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
|
||||
|
||||
elif str(p['options']['type']) == 'Excellon' and p['use_ui'] is True:
|
||||
gcode += '\n(TOOLS DIAMETER: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Dia: %s' % str(val["C"]) + ')\n'
|
||||
|
||||
gcode += '\n(FEEDRATE Z: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate: %s' % str(val['data']["feedrate_z"]) + ')\n'
|
||||
|
||||
gcode += '\n(FEEDRATE RAPIDS: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Feedrate Rapids: %s' % \
|
||||
str(val['data']["feedrate_rapid"]) + ')\n'
|
||||
|
||||
gcode += '\n(Z_CUT: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Z_Cut: %s' % str(val['data']["cutz"]) + ')\n'
|
||||
|
||||
gcode += '\n(Tools Offset: )\n'
|
||||
for tool, val in p['exc_cnc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(val['tool']) + 'Offset Z: %s' % str(val['offset_z']) + ')\n'
|
||||
|
||||
if p['multidepth'] is True:
|
||||
gcode += '\n(DEPTH_PER_CUT: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'DeptPerCut: %s' % \
|
||||
str(val['data']["depthperpass"]) + ')\n'
|
||||
|
||||
gcode += '\n(Z_MOVE: )\n'
|
||||
for tool, val in p['exc_tools'].items():
|
||||
gcode += '(Tool: %s -> ' % str(tool) + 'Z_Move: %s' % str(val['data']["travelz"]) + ')\n'
|
||||
gcode += '\n'
|
||||
|
||||
if p['toolchange'] is True:
|
||||
gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
|
||||
|
||||
if coords_xy is not None:
|
||||
gcode += '(X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
|
||||
p.decimals, coords_xy[1]) + units + ')\n'
|
||||
else:
|
||||
gcode += '(X,Y Toolchange: ' + "None" + units + ')\n'
|
||||
|
||||
gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n'
|
||||
gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n'
|
||||
if coords_xy is not None:
|
||||
gcode += '(X,Y Toolchange: ' + "%.*f, %.*f" % (p.decimals, coords_xy[0],
|
||||
p.decimals, coords_xy[1]) + units + ')\n'
|
||||
else:
|
||||
gcode += '(X,Y Toolchange: ' + "None" + units + ')\n'
|
||||
gcode += '(Z Start: ' + str(p['startz']) + units + ')\n'
|
||||
gcode += '(Z End: ' + str(p['z_end']) + units + ')\n'
|
||||
gcode += '(Steps per circle: ' + str(p['steps_per_circle']) + ')\n'
|
||||
|
||||
if str(p['options']['type']) == 'Excellon' or str(p['options']['type']) == 'Excellon Geometry':
|
||||
gcode += '(Preprocessor Excellon: ' + str(p['pp_excellon_name']) + ')\n'
|
||||
gcode += '(Preprocessor Excellon: ' + str(p['pp_excellon_name']) + ')\n' + '\n'
|
||||
else:
|
||||
gcode += '(Preprocessor Geometry: ' + str(p['pp_geometry_name']) + ')\n' + '\n'
|
||||
|
||||
|
@ -176,8 +206,8 @@ M0""".format(x_toolchange=self.coordinate_format % (p.coords_decimals, x_toolcha
|
|||
return g
|
||||
|
||||
def end_code(self, p):
|
||||
coords_xy = p['xy_toolchange']
|
||||
if coords_xy is not None:
|
||||
coords_xy = p['xy_end']
|
||||
if coords_xy and coords_xy != '':
|
||||
g = 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n"
|
||||
else:
|
||||
g = ('G00 ' + self.position_code(p)).format(**p)
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
# This file contains python only requirements to be installed with pip
|
||||
# Python packages that cannot be installed with pip (e.g. PyQt5, GDAL) are not included.
|
||||
# Usage: pip3 install -r requirements.txt
|
||||
numpy >=1.16
|
||||
pyqt5==5.12.1
|
||||
numpy>=1.16
|
||||
matplotlib>=3.1
|
||||
cycler>=0.10
|
||||
python-dateutil>=2.1
|
||||
|
|
|
@ -3,6 +3,7 @@ sudo apt install --reinstall libpng-dev libfreetype6 libfreetype6-dev libgeos-de
|
|||
sudo apt install --reinstall python3-dev python3-pyqt5 python3-pyqt5.qtopengl python3-gdal python3-simplejson
|
||||
sudo apt install --reinstall python3-pip python3-tk python3-imaging
|
||||
|
||||
sudo python3 -m pip install --upgrade pyqt5==5.12
|
||||
sudo python3 -m pip install --upgrade pip numpy scipy shapely rtree tk lxml cycler python-dateutil kiwisolver dill
|
||||
sudo python3 -m pip install --upgrade vispy pyopengl setuptools svg.path ortools freetype-py fontTools rasterio ezdxf
|
||||
sudo python3 -m pip install --upgrade matplotlib qrcode reportlab svglib
|
After Width: | Height: | Size: 183 B |
After Width: | Height: | Size: 245 B |
After Width: | Height: | Size: 374 B |
Before Width: | Height: | Size: 563 B After Width: | Height: | Size: 523 B |
After Width: | Height: | Size: 516 B |
After Width: | Height: | Size: 763 B |
Before Width: | Height: | Size: 750 B After Width: | Height: | Size: 808 B |
After Width: | Height: | Size: 514 B |
After Width: | Height: | Size: 726 B |
After Width: | Height: | Size: 189 B |
|
@ -78,7 +78,7 @@ class TclCommand(object):
|
|||
|
||||
:return: current command
|
||||
"""
|
||||
command_string = list()
|
||||
command_string = []
|
||||
command_string.append(self.aliases[0])
|
||||
|
||||
if self.original_args is not None:
|
||||
|
|
|
@ -52,7 +52,7 @@ class TclCommandBounds(TclCommand):
|
|||
:return:
|
||||
"""
|
||||
|
||||
obj_list = list()
|
||||
obj_list = []
|
||||
if 'objects' in args:
|
||||
try:
|
||||
obj_list = [str(obj_name) for obj_name in str(args['objects']).split(",") if obj_name != '']
|
||||
|
@ -68,7 +68,7 @@ class TclCommandBounds(TclCommand):
|
|||
_("Expected a list of objects names separated by comma. Got"), str(args['objects'])))
|
||||
return 'fail'
|
||||
|
||||
result_list = list()
|
||||
result_list = []
|
||||
for name in obj_list:
|
||||
obj = self.app.collection.get_by_name(name)
|
||||
|
||||
|
|
|
@ -213,7 +213,12 @@ class TclCommandCncjob(TclCommandSignaled):
|
|||
local_tools_dict[tool_uid]['data']['feedrate_rapid'] = args["feedrate_rapid"]
|
||||
local_tools_dict[tool_uid]['data']['multidepth'] = args["multidepth"]
|
||||
local_tools_dict[tool_uid]['data']['extracut'] = args["extracut"]
|
||||
local_tools_dict[tool_uid]['data']['extracut_length'] = args["extracut_length"]
|
||||
|
||||
if args["extracut"] is True:
|
||||
local_tools_dict[tool_uid]['data']['extracut_length'] = args["extracut_length"]
|
||||
else:
|
||||
local_tools_dict[tool_uid]['data']['extracut_length'] = None
|
||||
|
||||
local_tools_dict[tool_uid]['data']['depthperpass'] = args["depthperpass"]
|
||||
local_tools_dict[tool_uid]['data']['toolchange'] = args["toolchange"]
|
||||
local_tools_dict[tool_uid]['data']['toolchangez'] = args["toolchangez"]
|
||||
|
|
|
@ -175,6 +175,7 @@ class TclCommandCopperClear(TclCommand):
|
|||
"toolchange": self.app.defaults["geometry_toolchange"],
|
||||
"toolchangez": self.app.defaults["geometry_toolchangez"],
|
||||
"endz": self.app.defaults["geometry_endz"],
|
||||
"endxy": self.app.defaults["geometry_endxy"],
|
||||
"spindlespeed": self.app.defaults["geometry_spindlespeed"],
|
||||
"toolchangexy": self.app.defaults["geometry_toolchangexy"],
|
||||
"startz": self.app.defaults["geometry_startz"],
|
||||
|
@ -187,7 +188,7 @@ class TclCommandCopperClear(TclCommand):
|
|||
"paintcontour": self.app.defaults["tools_paintcontour"],
|
||||
"paintoverlap": self.app.defaults["tools_paintoverlap"]
|
||||
})
|
||||
ncc_tools = dict()
|
||||
ncc_tools = {}
|
||||
|
||||
tooluid = 0
|
||||
for tool in tools:
|
||||
|
|
|
@ -169,7 +169,7 @@ class TclCommandDrillcncjob(TclCommandSignaled):
|
|||
else:
|
||||
return "fail"
|
||||
|
||||
drillz = args["drillz"] if "drillz" in args and args["drillz"] is not None else obj.options["drillz"]
|
||||
drillz = args["drillz"] if "drillz" in args and args["drillz"] is not None else obj.options["cutz"]
|
||||
|
||||
if "toolchangez" in args:
|
||||
toolchange = True
|
||||
|
@ -185,7 +185,10 @@ class TclCommandDrillcncjob(TclCommandSignaled):
|
|||
opt_type = args["opt_type"] if "opt_type" in args and args["opt_type"] else 'B'
|
||||
|
||||
job_obj.z_move = args["travelz"] if "travelz" in args and args["travelz"] else obj.options["travelz"]
|
||||
|
||||
job_obj.feedrate = args["feedrate"] if "feedrate" in args and args["feedrate"] else obj.options["feedrate"]
|
||||
job_obj.z_feedrate = args["feedrate"] if "feedrate" in args and args["feedrate"] else \
|
||||
obj.options["feedrate"]
|
||||
job_obj.feedrate_rapid = args["feedrate_rapid"] \
|
||||
if "feedrate_rapid" in args and args["feedrate_rapid"] else obj.options["feedrate_rapid"]
|
||||
|
||||
|
@ -226,9 +229,6 @@ class TclCommandDrillcncjob(TclCommandSignaled):
|
|||
float(job_obj.exc_cnc_tools[t_item]['offset_z']) + float(drillz)
|
||||
job_obj.exc_cnc_tools[t_item]['data']['ppname_e'] = obj.options['ppname_e']
|
||||
|
||||
# for now there is no tool offset support in this Tcl Command so we write the 0.0 value here
|
||||
job_obj.tool_offset[t_item] = 0.0
|
||||
|
||||
job_obj.origin_kind = 'excellon'
|
||||
|
||||
job_obj.gcode_parse()
|
||||
|
|
|
@ -164,6 +164,8 @@ class TclCommandPaint(TclCommand):
|
|||
"toolchange": self.app.defaults["geometry_toolchange"],
|
||||
"toolchangez": self.app.defaults["geometry_toolchangez"],
|
||||
"endz": self.app.defaults["geometry_endz"],
|
||||
"endxy": self.app.defaults["geometry_endxy"],
|
||||
|
||||
"spindlespeed": self.app.defaults["geometry_spindlespeed"],
|
||||
"toolchangexy": self.app.defaults["geometry_toolchangexy"],
|
||||
"startz": self.app.defaults["geometry_startz"],
|
||||
|
@ -176,7 +178,7 @@ class TclCommandPaint(TclCommand):
|
|||
"paintcontour": self.app.defaults["tools_paintcontour"],
|
||||
"paintoverlap": self.app.defaults["tools_paintoverlap"]
|
||||
})
|
||||
paint_tools = dict()
|
||||
paint_tools = {}
|
||||
|
||||
tooluid = 0
|
||||
for tool in tools:
|
||||
|
|
|
@ -228,7 +228,7 @@ class TclCommandPanelize(TclCommand):
|
|||
|
||||
def translate_recursion(geom):
|
||||
if type(geom) == list:
|
||||
geoms = list()
|
||||
geoms = []
|
||||
for local_geom in geom:
|
||||
geoms.append(translate_recursion(local_geom))
|
||||
return geoms
|
||||
|
|
|
@ -66,7 +66,7 @@ class TclCommandSetOrigin(TclCommand):
|
|||
:return:
|
||||
"""
|
||||
|
||||
loc = list()
|
||||
loc = []
|
||||
if 'auto' in args:
|
||||
if bool(args['auto']) is True:
|
||||
objs = self.app.collection.get_list()
|
||||
|
|