diff --git a/FlatCAMApp.py b/FlatCAMApp.py index 568afe3a..5e130435 100644 --- a/FlatCAMApp.py +++ b/FlatCAMApp.py @@ -834,6 +834,12 @@ class App(QtCore.QObject): "tools_copper_thieving_box_type": 'rect', "tools_copper_thieving_circle_steps": 128, "tools_copper_thieving_fill_type": 'solid', + "tools_copper_thieving_dots_dia": 0.0393701, + "tools_copper_thieving_dots_spacing": 0.0787402, + "tools_copper_thieving_squares_size": 0.0393701, + "tools_copper_thieving_squares_spacing": 0.0787402, + "tools_copper_thieving_lines_size": 0.01, + "tools_copper_thieving_lines_spacing": 0.0787402, # Utilities # file associations @@ -1371,6 +1377,13 @@ class App(QtCore.QObject): "tools_copper_thieving_box_type": self.ui.tools2_defaults_form.tools2_cfill_group.bbox_type_radio, "tools_copper_thieving_circle_steps": self.ui.tools2_defaults_form.tools2_cfill_group.circlesteps_entry, "tools_copper_thieving_fill_type": self.ui.tools2_defaults_form.tools2_cfill_group.fill_type_radio, + "tools_copper_thieving_dots_dia": self.ui.tools2_defaults_form.tools2_cfill_group.dot_dia_entry, + "tools_copper_thieving_dots_spacing": self.ui.tools2_defaults_form.tools2_cfill_group.dot_spacing_entry, + "tools_copper_thieving_squares_size": self.ui.tools2_defaults_form.tools2_cfill_group.square_size_entry, + "tools_copper_thieving_squares_spacing": + self.ui.tools2_defaults_form.tools2_cfill_group.squares_spacing_entry, + "tools_copper_thieving_lines_size": self.ui.tools2_defaults_form.tools2_cfill_group.line_size_entry, + "tools_copper_thieving_lines_spacing": self.ui.tools2_defaults_form.tools2_cfill_group.lines_spacing_entry, # Utilities # File associations diff --git a/README.md b/README.md index f66b0b83..09d8b8a4 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,8 @@ CAD program, and create G-Code for Isolation routing. - renamed the Copper Fill Tool to Copper Thieving Tool as this is a more appropriate name; started to add ability for more types of copper thieving besides solid - fixed some issues recently introduced in ParseSVG - updated POT file +- fixed GUI in 2Sided Tool +- extending the Copper Thieving Tool - wip 9.11.2019 diff --git a/flatcamGUI/FlatCAMGUI.py b/flatcamGUI/FlatCAMGUI.py index f477c983..d4fd03ba 100644 --- a/flatcamGUI/FlatCAMGUI.py +++ b/flatcamGUI/FlatCAMGUI.py @@ -2515,7 +2515,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow): # Copper Thieving Tool if key == QtCore.Qt.Key_F: - self.app.copperfill_tool.run(toggle=True) + self.app.copper_thieving_tool.run(toggle=True) return # Toggle Grid lines diff --git a/flatcamGUI/PreferencesUI.py b/flatcamGUI/PreferencesUI.py index aa56f137..778600b3 100644 --- a/flatcamGUI/PreferencesUI.py +++ b/flatcamGUI/PreferencesUI.py @@ -5830,6 +5830,93 @@ class Tools2CFillPrefGroupUI(OptionsGroupUI): grid_lay.addWidget(self.fill_type_label, 7, 0) grid_lay.addWidget(self.fill_type_radio, 7, 1) + self.dots_label = QtWidgets.QLabel('%s:' % _("Dots Grid Parameters")) + grid_lay.addWidget(self.dots_label, 8, 0, 1, 2) + + # Dot diameter # + self.dotdia_label = QtWidgets.QLabel('%s:' % _("Dia")) + self.dotdia_label.setToolTip( + _("Dot diameter in Dots Grid.") + ) + self.dot_dia_entry = FCDoubleSpinner() + 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) + + grid_lay.addWidget(self.dotdia_label, 9, 0) + grid_lay.addWidget(self.dot_dia_entry, 9, 1) + + # Dot spacing # + self.dotspacing_label = QtWidgets.QLabel('%s:' % _("Spacing")) + self.dotspacing_label.setToolTip( + _("Distance between each two dots in Dots Grid.") + ) + self.dot_spacing_entry = FCDoubleSpinner() + 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) + + grid_lay.addWidget(self.dotspacing_label, 10, 0) + grid_lay.addWidget(self.dot_spacing_entry, 10, 1) + + self.squares_label = QtWidgets.QLabel('%s:' % _("Squares Grid Parameters")) + grid_lay.addWidget(self.squares_label, 11, 0, 1, 2) + + # Square Size # + self.square_size_label = QtWidgets.QLabel('%s:' % _("Size")) + self.square_size_label.setToolTip( + _("Square side size in Squares Grid.") + ) + self.square_size_entry = FCDoubleSpinner() + 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) + + grid_lay.addWidget(self.square_size_label, 12, 0) + grid_lay.addWidget(self.square_size_entry, 12, 1) + + # Squares spacing # + self.squares_spacing_label = QtWidgets.QLabel('%s:' % _("Spacing")) + self.squares_spacing_label.setToolTip( + _("Distance between each two squares in Squares Grid.") + ) + self.squares_spacing_entry = FCDoubleSpinner() + 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) + + grid_lay.addWidget(self.squares_spacing_label, 13, 0) + grid_lay.addWidget(self.squares_spacing_entry, 13, 1) + + self.lines_label = QtWidgets.QLabel('%s:' % _("Lines Grid Parameters")) + grid_lay.addWidget(self.lines_label, 14, 0, 1, 2) + + # Square Size # + self.line_size_label = QtWidgets.QLabel('%s:' % _("Size")) + self.line_size_label.setToolTip( + _("Line thickness size in Lines Grid.") + ) + self.line_size_entry = FCDoubleSpinner() + 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) + + grid_lay.addWidget(self.line_size_label, 15, 0) + grid_lay.addWidget(self.line_size_entry, 15, 1) + + # Lines spacing # + self.lines_spacing_label = QtWidgets.QLabel('%s:' % _("Spacing")) + self.lines_spacing_label.setToolTip( + _("Distance between each two lines in Lines Grid.") + ) + self.lines_spacing_entry = FCDoubleSpinner() + 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) + + grid_lay.addWidget(self.lines_spacing_label, 16, 0) + grid_lay.addWidget(self.lines_spacing_entry, 16, 1) + self.layout.addStretch() diff --git a/flatcamTools/ToolCopperThieving.py b/flatcamTools/ToolCopperThieving.py index 44c18a8f..b560f4fb 100644 --- a/flatcamTools/ToolCopperThieving.py +++ b/flatcamTools/ToolCopperThieving.py @@ -14,7 +14,7 @@ from FlatCAMObj import FlatCAMGerber, FlatCAMGeometry, FlatCAMExcellon import shapely.geometry.base as base from shapely.ops import cascaded_union, unary_union -from shapely.geometry import Polygon, MultiPolygon +from shapely.geometry import Polygon, MultiPolygon, Point from shapely.geometry import box as box import logging @@ -98,7 +98,7 @@ class ToolCopperThieving(FlatCAMTool): "and the copper traces in the Gerber file.") ) self.clearance_entry = FCDoubleSpinner() - self.clearance_entry.setMinimum(0.00001) + self.clearance_entry.set_range(0.00001, 9999.9999) self.clearance_entry.set_precision(self.decimals) self.clearance_entry.setSingleStep(0.1) @@ -111,7 +111,7 @@ class ToolCopperThieving(FlatCAMTool): _("Bounding box margin.") ) self.margin_entry = FCDoubleSpinner() - self.margin_entry.setMinimum(0.0) + self.margin_entry.set_range(0.0, 9999.9999) self.margin_entry.set_precision(self.decimals) self.margin_entry.setSingleStep(0.1) @@ -200,6 +200,126 @@ class ToolCopperThieving(FlatCAMTool): grid_lay.addWidget(self.fill_type_label, 8, 0) grid_lay.addWidget(self.fill_type_radio, 8, 1) + # DOTS FRAME + self.dots_frame = QtWidgets.QFrame() + self.dots_frame.setContentsMargins(0, 0, 0, 0) + self.layout.addWidget(self.dots_frame) + dots_grid = QtWidgets.QGridLayout() + dots_grid.setColumnStretch(0, 0) + dots_grid.setColumnStretch(1, 1) + dots_grid.setContentsMargins(0, 0, 0, 0) + self.dots_frame.setLayout(dots_grid) + self.dots_frame.hide() + + self.dots_label = QtWidgets.QLabel('%s:' % _("Dots Grid Parameters")) + dots_grid.addWidget(self.dots_label, 0, 0, 1, 2) + + # Dot diameter # + self.dotdia_label = QtWidgets.QLabel('%s:' % _("Dia")) + self.dotdia_label.setToolTip( + _("Dot diameter in Dots Grid.") + ) + self.dot_dia_entry = FCDoubleSpinner() + 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) + + dots_grid.addWidget(self.dotdia_label, 1, 0) + dots_grid.addWidget(self.dot_dia_entry, 1, 1) + + # Dot spacing # + self.dotspacing_label = QtWidgets.QLabel('%s:' % _("Spacing")) + self.dotspacing_label.setToolTip( + _("Distance between each two dots in Dots Grid.") + ) + self.dot_spacing_entry = FCDoubleSpinner() + 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) + + dots_grid.addWidget(self.dotspacing_label, 2, 0) + dots_grid.addWidget(self.dot_spacing_entry, 2, 1) + + # SQUARES FRAME + self.squares_frame = QtWidgets.QFrame() + self.squares_frame.setContentsMargins(0, 0, 0, 0) + self.layout.addWidget(self.squares_frame) + squares_grid = QtWidgets.QGridLayout() + squares_grid.setColumnStretch(0, 0) + squares_grid.setColumnStretch(1, 1) + squares_grid.setContentsMargins(0, 0, 0, 0) + self.squares_frame.setLayout(squares_grid) + self.squares_frame.hide() + + self.squares_label = QtWidgets.QLabel('%s:' % _("Squares Grid Parameters")) + squares_grid.addWidget(self.squares_label, 0, 0, 1, 2) + + # Square Size # + self.square_size_label = QtWidgets.QLabel('%s:' % _("Size")) + self.square_size_label.setToolTip( + _("Square side size in Squares Grid.") + ) + self.square_size_entry = FCDoubleSpinner() + 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) + + squares_grid.addWidget(self.square_size_label, 1, 0) + squares_grid.addWidget(self.square_size_entry, 1, 1) + + # Squares spacing # + self.squares_spacing_label = QtWidgets.QLabel('%s:' % _("Spacing")) + self.squares_spacing_label.setToolTip( + _("Distance between each two squares in Squares Grid.") + ) + self.squares_spacing_entry = FCDoubleSpinner() + 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) + + squares_grid.addWidget(self.squares_spacing_label, 2, 0) + squares_grid.addWidget(self.squares_spacing_entry, 2, 1) + + # LINES FRAME + self.lines_frame = QtWidgets.QFrame() + self.lines_frame.setContentsMargins(0, 0, 0, 0) + self.layout.addWidget(self.lines_frame) + lines_grid = QtWidgets.QGridLayout() + lines_grid.setColumnStretch(0, 0) + lines_grid.setColumnStretch(1, 1) + lines_grid.setContentsMargins(0, 0, 0, 0) + self.lines_frame.setLayout(lines_grid) + self.lines_frame.hide() + + self.lines_label = QtWidgets.QLabel('%s:' % _("Lines Grid Parameters")) + lines_grid.addWidget(self.lines_label, 0, 0, 1, 2) + + # Square Size # + self.line_size_label = QtWidgets.QLabel('%s:' % _("Size")) + self.line_size_label.setToolTip( + _("Line thickness size in Lines Grid.") + ) + self.line_size_entry = FCDoubleSpinner() + 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) + + lines_grid.addWidget(self.line_size_label, 1, 0) + lines_grid.addWidget(self.line_size_entry, 1, 1) + + # Lines spacing # + self.lines_spacing_label = QtWidgets.QLabel('%s:' % _("Spacing")) + self.lines_spacing_label.setToolTip( + _("Distance between each two lines in Lines Grid.") + ) + self.lines_spacing_entry = FCDoubleSpinner() + 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) + + lines_grid.addWidget(self.lines_spacing_label, 2, 0) + lines_grid.addWidget(self.lines_spacing_entry, 2, 1) + # ## Insert Copper Thieving self.fill_button = QtWidgets.QPushButton(_("Insert Copper thieving")) self.fill_button.setToolTip( @@ -235,6 +355,7 @@ class ToolCopperThieving(FlatCAMTool): self.fill_button.clicked.connect(self.execute) self.box_combo_type.currentIndexChanged.connect(self.on_combo_box_type) self.reference_radio.group_toggle_fn = self.on_toggle_reference + self.fill_type_radio.activated_custom.connect(self.on_thieving_type) def run(self, toggle=True): self.app.report_usage("ToolCopperThieving()") @@ -276,6 +397,13 @@ class ToolCopperThieving(FlatCAMTool): self.fill_type_radio.set_value(self.app.defaults["tools_copper_thieving_fill_type"]) self.geo_steps_per_circle = int(self.app.defaults["tools_copper_thieving_circle_steps"]) + self.dot_dia_entry.set_value(self.app.defaults["tools_copper_thieving_dots_dia"]) + self.dot_spacing_entry.set_value(self.app.defaults["tools_copper_thieving_dots_spacing"]) + self.square_size_entry.set_value(self.app.defaults["tools_copper_thieving_squares_size"]) + self.squares_spacing_entry.set_value(self.app.defaults["tools_copper_thieving_squares_spacing"]) + self.line_size_entry.set_value(self.app.defaults["tools_copper_thieving_lines_size"]) + self.lines_spacing_entry.set_value(self.app.defaults["tools_copper_thieving_lines_spacing"]) + self.area_method = False def on_combo_box_type(self): @@ -302,6 +430,24 @@ class ToolCopperThieving(FlatCAMTool): self.bbox_type_label.hide() self.bbox_type_radio.hide() + def on_thieving_type(self, choice): + if choice == 'solid': + self.dots_frame.hide() + self.squares_frame.hide() + self.lines_frame.hide() + elif choice == 'dot': + self.dots_frame.show() + self.squares_frame.hide() + self.lines_frame.hide() + elif choice == 'square': + self.dots_frame.hide() + self.squares_frame.show() + self.lines_frame.hide() + else: + self.dots_frame.hide() + self.squares_frame.hide() + self.lines_frame.show() + def execute(self): self.app.call_source = "copper_thieving_tool" @@ -330,8 +476,8 @@ class ToolCopperThieving(FlatCAMTool): self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Could not retrieve object"), str(e))) return "Could not retrieve object: %s" % self.obj_name - self.on_copper_fill( - fill_obj=self.grb_object, + self.on_copper_thieving( + thieving_obj=self.grb_object, c_val=self.clearance_val, margin=self.margin_val ) @@ -363,8 +509,8 @@ class ToolCopperThieving(FlatCAMTool): self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Could not retrieve object"), bound_obj_name)) return "Could not retrieve object: %s. Error: %s" % (bound_obj_name, str(e)) - self.on_copper_fill( - fill_obj=self.grb_object, + self.on_copper_thieving( + thieving_obj=self.grb_object, ref_obj=self.ref_obj, c_val=self.clearance_val, margin=self.margin_val @@ -445,8 +591,8 @@ class ToolCopperThieving(FlatCAMTool): if not isinstance(self.sel_rect, Iterable): self.sel_rect = [self.sel_rect] - self.on_copper_fill( - fill_obj=self.grb_object, + self.on_copper_thieving( + thieving_obj=self.grb_object, ref_obj=self.sel_rect, c_val=self.clearance_val, margin=self.margin_val @@ -497,10 +643,10 @@ class ToolCopperThieving(FlatCAMTool): self.app.draw_moving_selection_shape(old_coords=(self.cursor_pos[0], self.cursor_pos[1]), coords=(curr_pos[0], curr_pos[1])) - def on_copper_fill(self, fill_obj, ref_obj=None, c_val=None, margin=None, run_threaded=True): + def on_copper_thieving(self, thieving_obj, ref_obj=None, c_val=None, margin=None, run_threaded=True): """ - :param fill_obj: + :param thieving_obj: :param ref_obj: :param c_val: :param margin: @@ -527,6 +673,14 @@ class ToolCopperThieving(FlatCAMTool): if margin is None: margin = float(self.app.defaults["tools_copperfill_margin"]) + fill_type = self.fill_type_radio.get_value() + dot_dia = self.dot_dia_entry.get_value() + dot_spacing = self.dot_spacing_entry.get_value() + square_size = self.square_size_entry.get_value() + square_spacing = self.squares_spacing_entry.get_value() + line_size = self.line_size_entry.get_value() + line_spacing = self.lines_spacing_entry.get_value() + # make sure that the source object solid geometry is an Iterable if not isinstance(self.grb_object.solid_geometry, Iterable): self.grb_object.solid_geometry = [self.grb_object.solid_geometry] @@ -584,11 +738,11 @@ class ToolCopperThieving(FlatCAMTool): try: if ref_obj is None or ref_obj == 'itself': - working_obj = fill_obj + working_obj = thieving_obj else: working_obj = ref_obj except Exception as e: - log.debug("ToolCopperThieving.on_copper_fill() --> %s" % str(e)) + log.debug("ToolCopperThieving.on_copper_thieving() --> %s" % str(e)) return 'fail' bounding_box = None @@ -622,7 +776,7 @@ class ToolCopperThieving(FlatCAMTool): bounding_box = env_obj.buffer(distance=margin, join_style=base.JOIN_STYLE.mitre) except Exception as e: - log.debug("ToolCopperFIll.on_copper_fill() 'itself' --> %s" % str(e)) + log.debug("ToolCopperFIll.on_copper_thieving() 'itself' --> %s" % str(e)) self.app.inform.emit('[ERROR_NOTCL] %s' % _("No object available.")) return 'fail' @@ -631,7 +785,7 @@ class ToolCopperThieving(FlatCAMTool): try: __ = iter(geo_n) except Exception as e: - log.debug("ToolCopperFIll.on_copper_fill() 'area' --> %s" % str(e)) + log.debug("ToolCopperFIll.on_copper_thieving() 'area' --> %s" % str(e)) geo_n = [geo_n] geo_buff_list = [] @@ -650,7 +804,7 @@ class ToolCopperThieving(FlatCAMTool): try: __ = iter(geo_n) except Exception as e: - log.debug("ToolCopperFIll.on_copper_fill() 'box' --> %s" % str(e)) + log.debug("ToolCopperFIll.on_copper_thieving() 'box' --> %s" % str(e)) geo_n = [geo_n] geo_buff_list = [] @@ -672,7 +826,20 @@ class ToolCopperThieving(FlatCAMTool): log.debug("Copper Thieving Tool. Finished creating areas to fill with copper.") self.app.inform.emit(_("Copper Thieving Tool. Appending new geometry and buffering.")) - new_solid_geometry = bounding_box.difference(clearance_geometry) + + # ######################################################################################### + # ########## Generate filling geometry. ################################################### + # ######################################################################################### + + if fill_type == 'solid': + new_solid_geometry = bounding_box.difference(clearance_geometry) + elif fill_type == 'dots': + dot_geo = Point((0, 0)).buffer(dot_dia / 2.0) + try: + for bb in bounding_box: + pass + except TypeError: + pass geo_list = self.grb_object.solid_geometry if isinstance(self.grb_object.solid_geometry, MultiPolygon): diff --git a/flatcamTools/ToolDblSided.py b/flatcamTools/ToolDblSided.py index 96ca7c2b..cbb683cd 100644 --- a/flatcamTools/ToolDblSided.py +++ b/flatcamTools/ToolDblSided.py @@ -45,6 +45,8 @@ class DblSidedTool(FlatCAMTool): # ## Grid Layout grid_lay = QtWidgets.QGridLayout() self.layout.addLayout(grid_lay) + grid_lay.setColumnStretch(0, 1) + grid_lay.setColumnStretch(1, 0) # ## Gerber Object to mirror self.gerber_object_combo = QtWidgets.QComboBox() @@ -53,9 +55,7 @@ class DblSidedTool(FlatCAMTool): self.gerber_object_combo.setCurrentIndex(1) self.botlay_label = QtWidgets.QLabel("%s:" % _("GERBER")) - self.botlay_label.setToolTip( - "Gerber to be mirrored." - ) + self.botlay_label.setToolTip('%s.' % _("Gerber to be mirrored")) self.mirror_gerber_button = QtWidgets.QPushButton(_("Mirror")) self.mirror_gerber_button.setToolTip( @@ -77,9 +77,7 @@ class DblSidedTool(FlatCAMTool): self.exc_object_combo.setCurrentIndex(1) self.excobj_label = QtWidgets.QLabel("%s:" % _("EXCELLON")) - self.excobj_label.setToolTip( - _("Excellon Object to be mirrored.") - ) + self.excobj_label.setToolTip(_("Excellon Object to be mirrored.")) self.mirror_exc_button = QtWidgets.QPushButton(_("Mirror")) self.mirror_exc_button.setToolTip( @@ -126,9 +124,8 @@ class DblSidedTool(FlatCAMTool): 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).") - ) + 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) @@ -154,6 +151,8 @@ class DblSidedTool(FlatCAMTool): # ## Grid Layout grid_lay2 = QtWidgets.QGridLayout() self.layout.addLayout(grid_lay2) + grid_lay2.setColumnStretch(0, 1) + grid_lay2.setColumnStretch(1, 0) # ## Point/Box self.point_box_container = QtWidgets.QVBoxLayout()