- Copper Fill Tool: added possibility to select between a bounding box rectangular or convex hull when the reference is the geometry of the source Gerber object
- Copper Fill Tool: cleanup on not regular tool exit
This commit is contained in:
@@ -22,6 +22,8 @@ CAD program, and create G-Code for Isolation routing.
|
|||||||
- QRCode Tool: added GUI category in Preferences window
|
- QRCode Tool: added GUI category in Preferences window
|
||||||
- QRCode Tool: shortcut key for this tool is now ALT+Q while PDF import Tool was relegated to CTRL+Q combo key shortcut
|
- QRCode Tool: shortcut key for this tool is now ALT+Q while PDF import Tool was relegated to CTRL+Q combo key shortcut
|
||||||
- added a new FlatCAM Tool: Copper Fill Tool. It will pour copper into a Gerber filling all empty space with copper, at a clearance distance of the Gerber features
|
- added a new FlatCAM Tool: Copper Fill Tool. It will pour copper into a Gerber filling all empty space with copper, at a clearance distance of the Gerber features
|
||||||
|
- Copper Fill Tool: added possibility to select between a bounding box rectangular or convex hull when the reference is the geometry of the source Gerber object
|
||||||
|
- Copper Fill Tool: cleanup on not regular tool exit
|
||||||
|
|
||||||
24.10.2019
|
24.10.2019
|
||||||
|
|
||||||
|
|||||||
@@ -3512,6 +3512,30 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
|
|||||||
# Jump to coords
|
# Jump to coords
|
||||||
if key == QtCore.Qt.Key_J:
|
if key == QtCore.Qt.Key_J:
|
||||||
self.app.on_jump_to()
|
self.app.on_jump_to()
|
||||||
|
elif self.app.call_source == 'copperfill_tool':
|
||||||
|
if modifiers == QtCore.Qt.ControlModifier | QtCore.Qt.AltModifier:
|
||||||
|
if key == QtCore.Qt.Key_X:
|
||||||
|
self.app.abort_all_tasks()
|
||||||
|
return
|
||||||
|
|
||||||
|
elif modifiers == QtCore.Qt.ControlModifier:
|
||||||
|
pass
|
||||||
|
elif modifiers == QtCore.Qt.ShiftModifier:
|
||||||
|
pass
|
||||||
|
elif modifiers == QtCore.Qt.AltModifier:
|
||||||
|
pass
|
||||||
|
elif modifiers == QtCore.Qt.NoModifier:
|
||||||
|
# Escape = Deselect All
|
||||||
|
if key == QtCore.Qt.Key_Escape or key == 'Escape':
|
||||||
|
self.app.copperfill_tool.on_exit()
|
||||||
|
|
||||||
|
# Grid toggle
|
||||||
|
if key == QtCore.Qt.Key_G:
|
||||||
|
self.app.ui.grid_snap_btn.trigger()
|
||||||
|
|
||||||
|
# Jump to coords
|
||||||
|
if key == QtCore.Qt.Key_J:
|
||||||
|
self.app.on_jump_to()
|
||||||
|
|
||||||
def createPopupMenu(self):
|
def createPopupMenu(self):
|
||||||
menu = super().createPopupMenu()
|
menu = super().createPopupMenu()
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ from FlatCAMObj import FlatCAMGerber, FlatCAMGeometry, FlatCAMExcellon
|
|||||||
import shapely.geometry.base as base
|
import shapely.geometry.base as base
|
||||||
from shapely.ops import cascaded_union, unary_union
|
from shapely.ops import cascaded_union, unary_union
|
||||||
from shapely.geometry import Polygon, MultiPolygon
|
from shapely.geometry import Polygon, MultiPolygon
|
||||||
|
from shapely.geometry import box as box
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
@@ -138,9 +139,9 @@ class ToolCopperFill(FlatCAMTool):
|
|||||||
"It can be Gerber, Excellon or Geometry.")
|
"It can be Gerber, Excellon or Geometry.")
|
||||||
)
|
)
|
||||||
self.box_combo_type = QtWidgets.QComboBox()
|
self.box_combo_type = QtWidgets.QComboBox()
|
||||||
self.box_combo_type.addItem(_("Gerber Reference Box Object"))
|
self.box_combo_type.addItem(_("Reference Gerber"))
|
||||||
self.box_combo_type.addItem(_("Excellon Reference Box Object"))
|
self.box_combo_type.addItem(_("Reference Excellon"))
|
||||||
self.box_combo_type.addItem(_("Geometry Reference Box Object"))
|
self.box_combo_type.addItem(_("Reference Geometry"))
|
||||||
|
|
||||||
grid_lay.addWidget(self.box_combo_type_label, 4, 0)
|
grid_lay.addWidget(self.box_combo_type_label, 4, 0)
|
||||||
grid_lay.addWidget(self.box_combo_type, 4, 1)
|
grid_lay.addWidget(self.box_combo_type, 4, 1)
|
||||||
@@ -162,6 +163,21 @@ class ToolCopperFill(FlatCAMTool):
|
|||||||
self.box_combo_type.hide()
|
self.box_combo_type.hide()
|
||||||
self.box_combo_type_label.hide()
|
self.box_combo_type_label.hide()
|
||||||
|
|
||||||
|
# Bounding Box Type #
|
||||||
|
self.bbox_type_radio = RadioSet([
|
||||||
|
{'label': _('Rectangular'), 'value': 'rect'},
|
||||||
|
{"label": _("Minimal"), "value": "min"}
|
||||||
|
], stretch=False)
|
||||||
|
self.bbox_type_label = QtWidgets.QLabel(_("Box Type:"))
|
||||||
|
self.bbox_type_label.setToolTip(
|
||||||
|
_("- 'Rectangular' - the bounding box will be of rectangular shape.\n "
|
||||||
|
"- 'Minimal' - the bounding box will be the convex hull shape.")
|
||||||
|
)
|
||||||
|
grid_lay.addWidget(self.bbox_type_label, 6, 0)
|
||||||
|
grid_lay.addWidget(self.bbox_type_radio, 6, 1)
|
||||||
|
self.bbox_type_label.hide()
|
||||||
|
self.bbox_type_radio.hide()
|
||||||
|
|
||||||
# ## Insert Copper Fill
|
# ## Insert Copper Fill
|
||||||
self.fill_button = QtWidgets.QPushButton(_("Insert Copper Fill"))
|
self.fill_button = QtWidgets.QPushButton(_("Insert Copper Fill"))
|
||||||
self.fill_button.setToolTip(
|
self.fill_button.setToolTip(
|
||||||
@@ -186,6 +202,8 @@ class ToolCopperFill(FlatCAMTool):
|
|||||||
self.cursor_pos = (0, 0)
|
self.cursor_pos = (0, 0)
|
||||||
self.first_click = False
|
self.first_click = False
|
||||||
|
|
||||||
|
self.area_method = False
|
||||||
|
|
||||||
# Tool properties
|
# Tool properties
|
||||||
self.clearance_val = None
|
self.clearance_val = None
|
||||||
self.margin_val = None
|
self.margin_val = None
|
||||||
@@ -233,10 +251,14 @@ class ToolCopperFill(FlatCAMTool):
|
|||||||
# self.margin_entry.set_value(float(self.app.defaults["tools_copperfill_margin"]))
|
# self.margin_entry.set_value(float(self.app.defaults["tools_copperfill_margin"]))
|
||||||
# self.reference_radio.set_value(self.app.defaults["tools_copperfill_reference"])
|
# self.reference_radio.set_value(self.app.defaults["tools_copperfill_reference"])
|
||||||
# self.geo_steps_per_circle = int(self.app.defaults["tools_copperfill_circle_steps"])
|
# self.geo_steps_per_circle = int(self.app.defaults["tools_copperfill_circle_steps"])
|
||||||
|
# self.bbox_type_radio.set_value(self.app.defaults["tools_copperfill_box_type"])
|
||||||
|
|
||||||
self.clearance_entry.set_value(0.5)
|
self.clearance_entry.set_value(0.5)
|
||||||
self.margin_entry.set_value(1.0)
|
self.margin_entry.set_value(1.0)
|
||||||
self.reference_radio.set_value('itself')
|
self.reference_radio.set_value('itself')
|
||||||
|
self.bbox_type_radio.set_value('rect')
|
||||||
|
|
||||||
|
self.area_method = False
|
||||||
|
|
||||||
def on_combo_box_type(self):
|
def on_combo_box_type(self):
|
||||||
obj_type = self.box_combo_type.currentIndex()
|
obj_type = self.box_combo_type.currentIndex()
|
||||||
@@ -255,7 +277,16 @@ class ToolCopperFill(FlatCAMTool):
|
|||||||
self.box_combo_type.show()
|
self.box_combo_type.show()
|
||||||
self.box_combo_type_label.show()
|
self.box_combo_type_label.show()
|
||||||
|
|
||||||
|
if self.reference_radio.get_value() == "itself":
|
||||||
|
self.bbox_type_label.show()
|
||||||
|
self.bbox_type_radio.show()
|
||||||
|
else:
|
||||||
|
self.bbox_type_label.hide()
|
||||||
|
self.bbox_type_radio.hide()
|
||||||
|
|
||||||
def execute(self):
|
def execute(self):
|
||||||
|
self.app.call_source = "copperfill_tool"
|
||||||
|
|
||||||
self.clearance_val = self.clearance_entry.get_value()
|
self.clearance_val = self.clearance_entry.get_value()
|
||||||
self.margin_val = self.margin_entry.get_value()
|
self.margin_val = self.margin_entry.get_value()
|
||||||
reference_method = self.reference_radio.get_value()
|
reference_method = self.reference_radio.get_value()
|
||||||
@@ -290,6 +321,8 @@ class ToolCopperFill(FlatCAMTool):
|
|||||||
elif reference_method == 'area':
|
elif reference_method == 'area':
|
||||||
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Click the start point of the area."))
|
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Click the start point of the area."))
|
||||||
|
|
||||||
|
self.area_method = True
|
||||||
|
|
||||||
if self.app.is_legacy is False:
|
if self.app.is_legacy is False:
|
||||||
self.app.plotcanvas.graph_event_disconnect('mouse_press', self.app.on_mouse_click_over_plot)
|
self.app.plotcanvas.graph_event_disconnect('mouse_press', self.app.on_mouse_click_over_plot)
|
||||||
self.app.plotcanvas.graph_event_disconnect('mouse_move', self.app.on_mouse_move_over_plot)
|
self.app.plotcanvas.graph_event_disconnect('mouse_move', self.app.on_mouse_move_over_plot)
|
||||||
@@ -363,7 +396,7 @@ class ToolCopperFill(FlatCAMTool):
|
|||||||
|
|
||||||
elif event.button == right_button and self.mouse_is_dragging == False:
|
elif event.button == right_button and self.mouse_is_dragging == False:
|
||||||
self.app.delete_selection_shape()
|
self.app.delete_selection_shape()
|
||||||
|
self.area_method = False
|
||||||
self.first_click = False
|
self.first_click = False
|
||||||
|
|
||||||
if self.app.is_legacy is False:
|
if self.app.is_legacy is False:
|
||||||
@@ -464,7 +497,6 @@ class ToolCopperFill(FlatCAMTool):
|
|||||||
log.debug("Copper Filling Tool started. Reading parameters.")
|
log.debug("Copper Filling Tool started. Reading parameters.")
|
||||||
self.app.inform.emit(_("Copper Filling Tool started. Reading parameters."))
|
self.app.inform.emit(_("Copper Filling Tool started. Reading parameters."))
|
||||||
|
|
||||||
units = self.app.ui.general_defaults_form.general_app_group.units_radio.get_value()
|
|
||||||
ref_selected = self.reference_radio.get_value()
|
ref_selected = self.reference_radio.get_value()
|
||||||
if c_val is None:
|
if c_val is None:
|
||||||
c_val = float(self.app.defaults["tools_copperfill_clearance"])
|
c_val = float(self.app.defaults["tools_copperfill_clearance"])
|
||||||
@@ -540,6 +572,7 @@ class ToolCopperFill(FlatCAMTool):
|
|||||||
geo_n = working_obj.solid_geometry
|
geo_n = working_obj.solid_geometry
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
if self.bbox_type_radio.get_value() == 'min':
|
||||||
if isinstance(geo_n, MultiPolygon):
|
if isinstance(geo_n, MultiPolygon):
|
||||||
env_obj = geo_n.convex_hull
|
env_obj = geo_n.convex_hull
|
||||||
elif (isinstance(geo_n, MultiPolygon) and len(geo_n) == 1) or \
|
elif (isinstance(geo_n, MultiPolygon) and len(geo_n) == 1) or \
|
||||||
@@ -548,6 +581,20 @@ class ToolCopperFill(FlatCAMTool):
|
|||||||
else:
|
else:
|
||||||
env_obj = cascaded_union(geo_n)
|
env_obj = cascaded_union(geo_n)
|
||||||
env_obj = env_obj.convex_hull
|
env_obj = env_obj.convex_hull
|
||||||
|
else:
|
||||||
|
if isinstance(geo_n, Polygon) or \
|
||||||
|
(isinstance(geo_n, list) and len(geo_n) == 1) or \
|
||||||
|
(isinstance(geo_n, MultiPolygon) and len(geo_n) == 1):
|
||||||
|
env_obj = geo_n.buffer(0, join_style=base.JOIN_STYLE.mitre).exterior
|
||||||
|
elif isinstance(geo_n, MultiPolygon):
|
||||||
|
x0, y0, x1, y1 = geo_n.bounds
|
||||||
|
geo = box(x0, y0, x1, y1)
|
||||||
|
env_obj = geo.buffer(0, join_style=base.JOIN_STYLE.mitre)
|
||||||
|
else:
|
||||||
|
self.app.inform.emit(
|
||||||
|
'[ERROR_NOTCL] %s: %s' % (_("Geometry not supported for bounding box"), type(geo_n))
|
||||||
|
)
|
||||||
|
return 'fail'
|
||||||
|
|
||||||
bounding_box = env_obj.buffer(distance=margin, join_style=base.JOIN_STYLE.mitre)
|
bounding_box = env_obj.buffer(distance=margin, join_style=base.JOIN_STYLE.mitre)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -568,7 +615,7 @@ class ToolCopperFill(FlatCAMTool):
|
|||||||
if self.app.abort_flag:
|
if self.app.abort_flag:
|
||||||
# graceful abort requested by the user
|
# graceful abort requested by the user
|
||||||
raise FlatCAMApp.GracefulException
|
raise FlatCAMApp.GracefulException
|
||||||
geo_buff_list.append(poly.buffer(distance=0.0, join_style=base.JOIN_STYLE.mitre))
|
geo_buff_list.append(poly.buffer(distance=margin, join_style=base.JOIN_STYLE.mitre))
|
||||||
|
|
||||||
bounding_box = cascaded_union(geo_buff_list)
|
bounding_box = cascaded_union(geo_buff_list)
|
||||||
|
|
||||||
@@ -676,3 +723,26 @@ class ToolCopperFill(FlatCAMTool):
|
|||||||
self.mouse_is_dragging = False
|
self.mouse_is_dragging = False
|
||||||
self.cursor_pos = (0, 0)
|
self.cursor_pos = (0, 0)
|
||||||
self.first_click = False
|
self.first_click = False
|
||||||
|
|
||||||
|
# if True it means we exited from tool in the middle of area adding therefore disconnect the events
|
||||||
|
if self.area_method is True:
|
||||||
|
self.app.delete_selection_shape()
|
||||||
|
self.area_method = False
|
||||||
|
|
||||||
|
if self.app.is_legacy is False:
|
||||||
|
self.app.plotcanvas.graph_event_disconnect('mouse_release', self.on_mouse_release)
|
||||||
|
self.app.plotcanvas.graph_event_disconnect('mouse_move', self.on_mouse_move)
|
||||||
|
else:
|
||||||
|
self.app.plotcanvas.graph_event_disconnect(self.mr)
|
||||||
|
self.app.plotcanvas.graph_event_disconnect(self.mm)
|
||||||
|
|
||||||
|
self.app.mp = self.app.plotcanvas.graph_event_connect('mouse_press',
|
||||||
|
self.app.on_mouse_click_over_plot)
|
||||||
|
self.app.mm = self.app.plotcanvas.graph_event_connect('mouse_move',
|
||||||
|
self.app.on_mouse_move_over_plot)
|
||||||
|
self.app.mr = self.app.plotcanvas.graph_event_connect('mouse_release',
|
||||||
|
self.app.on_mouse_click_release_over_plot)
|
||||||
|
|
||||||
|
self.app.call_source = "app"
|
||||||
|
self.app.inform.emit('[success] %s' % _("Copper Fill Tool exit."))
|
||||||
|
|
||||||
|
|||||||
@@ -187,9 +187,9 @@ class DblSidedTool(FlatCAMTool):
|
|||||||
self.box_combo.setCurrentIndex(1)
|
self.box_combo.setCurrentIndex(1)
|
||||||
|
|
||||||
self.box_combo_type = QtWidgets.QComboBox()
|
self.box_combo_type = QtWidgets.QComboBox()
|
||||||
self.box_combo_type.addItem(_("Gerber Reference Box Object"))
|
self.box_combo_type.addItem(_("Reference Gerber"))
|
||||||
self.box_combo_type.addItem(_("Excellon Reference Box Object"))
|
self.box_combo_type.addItem(_("Reference Excellon"))
|
||||||
self.box_combo_type.addItem(_("Geometry Reference Box Object"))
|
self.box_combo_type.addItem(_("Reference Geometry"))
|
||||||
|
|
||||||
self.point_box_container.addWidget(self.box_combo_type)
|
self.point_box_container.addWidget(self.box_combo_type)
|
||||||
self.point_box_container.addWidget(self.box_combo)
|
self.point_box_container.addWidget(self.box_combo)
|
||||||
|
|||||||
@@ -445,9 +445,9 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
|||||||
"It can be Gerber, Excellon or Geometry.")
|
"It can be Gerber, Excellon or Geometry.")
|
||||||
)
|
)
|
||||||
self.box_combo_type = QtWidgets.QComboBox()
|
self.box_combo_type = QtWidgets.QComboBox()
|
||||||
self.box_combo_type.addItem(_("Gerber Reference Box Object"))
|
self.box_combo_type.addItem(_("Reference Gerber"))
|
||||||
self.box_combo_type.addItem(_("Excellon Reference Box Object"))
|
self.box_combo_type.addItem(_("Reference Excellon"))
|
||||||
self.box_combo_type.addItem(_("Geometry Reference Box Object"))
|
self.box_combo_type.addItem(_("Reference Geometry"))
|
||||||
form1.addRow(self.box_combo_type_label, self.box_combo_type)
|
form1.addRow(self.box_combo_type_label, self.box_combo_type)
|
||||||
|
|
||||||
self.box_combo_label = QtWidgets.QLabel('%s:' % _("Ref. Object"))
|
self.box_combo_label = QtWidgets.QLabel('%s:' % _("Ref. Object"))
|
||||||
|
|||||||
@@ -335,9 +335,9 @@ class ToolPaint(FlatCAMTool, Gerber):
|
|||||||
"It can be Gerber, Excellon or Geometry.")
|
"It can be Gerber, Excellon or Geometry.")
|
||||||
)
|
)
|
||||||
self.box_combo_type = QtWidgets.QComboBox()
|
self.box_combo_type = QtWidgets.QComboBox()
|
||||||
self.box_combo_type.addItem(_("Gerber Reference Box Object"))
|
self.box_combo_type.addItem(_("Reference Gerber"))
|
||||||
self.box_combo_type.addItem(_("Excellon Reference Box Object"))
|
self.box_combo_type.addItem(_("Reference Excellon"))
|
||||||
self.box_combo_type.addItem(_("Geometry Reference Box Object"))
|
self.box_combo_type.addItem(_("Reference Geometry"))
|
||||||
form1.addRow(self.box_combo_type_label, self.box_combo_type)
|
form1.addRow(self.box_combo_type_label, self.box_combo_type)
|
||||||
|
|
||||||
self.box_combo_label = QtWidgets.QLabel('%s:' % _("Ref. Object"))
|
self.box_combo_label = QtWidgets.QLabel('%s:' % _("Ref. Object"))
|
||||||
|
|||||||
Reference in New Issue
Block a user