- in Tool Follow made sure that the resulting geometry elements are all valid and not empty and also do not contain Points as those are irrelevant in the Follow Tool

- in Geometry Editor fixed the selection on the Geometry Table
- in Geometry Editor - made sure that the edited Geometry do not contain Shapely Points and that when adding shapes, that the geometry of that shapes is valid and non empty and it is not a Shapely Point
- in Geometry Editor - added new information's (length, coordinates and vertex points number) for the geometric element selected in the Geometry Table
This commit is contained in:
Marius Stanciu
2020-11-27 01:09:43 +02:00
committed by Marius
parent 9ecc2dc9ac
commit d34b1f1c71
3 changed files with 131 additions and 25 deletions

View File

@@ -7,6 +7,12 @@ CHANGELOG for FlatCAM beta
================================================= =================================================
27.11.2020
- in Geometry Editor fixed the selection on the Geometry Table
- in Geometry Editor - made sure that the edited Geometry do not contain Shapely Points and that when adding shapes, that the geometry of that shapes is valid and non empty and it is not a Shapely Point
- in Geometry Editor - added new information's (length, coordinates and vertex points number) for the geometric element selected in the Geometry Table
26.11.2020 26.11.2020
- fixed error in Tools Database when deleting first tool; remade the tool deletion method - fixed error in Tools Database when deleting first tool; remade the tool deletion method
@@ -14,6 +20,7 @@ CHANGELOG for FlatCAM beta
- in Tools Database made sure that editing the Target and Tool diameter in the right side section will update the values in the left TreeWidget - in Tools Database made sure that editing the Target and Tool diameter in the right side section will update the values in the left TreeWidget
- in Tools Database added a Sort by Target context menu entry and functionality; fixed the Sort by Dia functionality - in Tools Database added a Sort by Target context menu entry and functionality; fixed the Sort by Dia functionality
- in Tools Database - clicking the header sections of the TreeWidget for columns Target and Diameter will sort the tools by that criteria - in Tools Database - clicking the header sections of the TreeWidget for columns Target and Diameter will sort the tools by that criteria
- in Tool Follow made sure that the resulting geometry elements are all valid and not empty and also do not contain Points as those are irrelevant in the Follow Tool
25.11.2020 25.11.2020

View File

@@ -17,7 +17,7 @@ from PyQt5.QtCore import Qt
from camlib import distance, arc, three_point_circle, Geometry, FlatCAMRTreeStorage from camlib import distance, arc, three_point_circle, Geometry, FlatCAMRTreeStorage
from appTool import AppTool from appTool import AppTool
from appGUI.GUIElements import OptionalInputSection, FCCheckBox, FCLabel, FCComboBox, FCTextAreaRich, \ from appGUI.GUIElements import OptionalInputSection, FCCheckBox, FCLabel, FCComboBox, FCTextAreaRich, \
FCDoubleSpinner, FCButton, FCInputDoubleSpinner, FCTree, NumericalEvalTupleEntry FCDoubleSpinner, FCButton, FCInputDoubleSpinner, FCTree, NumericalEvalTupleEntry, FCEntry, FCTextEdit
from appParsers.ParseFont import * from appParsers.ParseFont import *
from shapely.geometry import LineString, LinearRing, MultiLineString, Polygon, MultiPolygon, Point from shapely.geometry import LineString, LinearRing, MultiLineString, Polygon, MultiPolygon, Point
@@ -2637,7 +2637,7 @@ class FCSelect(DrawTool):
except Exception as e: except Exception as e:
log.error("[ERROR] AppGeoEditor.FCSelect.click_release() -> Something went bad. %s" % str(e)) log.error("[ERROR] AppGeoEditor.FCSelect.click_release() -> Something went bad. %s" % str(e))
# if selection is done on canvas update the Tree in Selected Tab with the selection # if selection is done on canvas update the Tree in Properties Tab with the selection
try: try:
self.draw_app.tw.itemSelectionChanged.disconnect(self.draw_app.on_tree_selection_change) self.draw_app.tw.itemSelectionChanged.disconnect(self.draw_app.on_tree_selection_change)
except (AttributeError, TypeError): except (AttributeError, TypeError):
@@ -2649,7 +2649,7 @@ class FCSelect(DrawTool):
while iterator.value(): while iterator.value():
item = iterator.value() item = iterator.value()
try: try:
if int(item.text(1)) == id(sel_shape): if int(item.text(0)) == id(sel_shape):
item.setSelected(True) item.setSelected(True)
except ValueError: except ValueError:
pass pass
@@ -3368,18 +3368,59 @@ class AppGeoEditor(QtCore.QObject):
self.title_box.addWidget(self.title_label, stretch=1) self.title_box.addWidget(self.title_label, stretch=1)
self.title_box.addWidget(FCLabel('')) self.title_box.addWidget(FCLabel(''))
grid0 = QtWidgets.QGridLayout()
grid0.setColumnStretch(0, 0)
grid0.setColumnStretch(1, 1)
self.tools_box.addLayout(grid0)
# Tree Widget Title
tw_label = FCLabel('<b>%s</b>:' % _("Geometry Table"))
tw_label.setToolTip(
_("The list of geometry elements inside the edited object.")
)
grid0.addWidget(tw_label, 0, 0, 1, 2)
# Tree Widget
self.tw = FCTree(columns=3, header_hidden=False, protected_column=[0, 1], extended_sel=True) self.tw = FCTree(columns=3, header_hidden=False, protected_column=[0, 1], extended_sel=True)
self.tw.setHeaderLabels(["ID", _("Type"), _("Name")]) self.tw.setHeaderLabels(["ID", _("Type"), _("Name")])
self.tw.setIndentation(0) self.tw.setIndentation(0)
self.tw.header().setStretchLastSection(True) self.tw.header().setStretchLastSection(True)
self.tw.header().setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents) self.tw.header().setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
self.tools_box.addWidget(self.tw) grid0.addWidget(self.tw, 2, 0, 1, 2)
self.geo_font = QtGui.QFont() self.geo_font = QtGui.QFont()
self.geo_font.setBold(True) self.geo_font.setBold(True)
self.geo_parent = self.tw.invisibleRootItem() self.geo_parent = self.tw.invisibleRootItem()
# Length
len_lbl = FCLabel('<b>%s</b>:' % _("Length"))
len_lbl.setToolTip(
_("The length of the geometry element.")
)
self.geo_len_entry = FCEntry(decimals=self.decimals)
grid0.addWidget(len_lbl, 4, 0)
grid0.addWidget(self.geo_len_entry, 4, 1)
# Coordinates
coords_lbl = FCLabel('<b>%s</b>:' % _("Coordinates"))
coords_lbl.setToolTip(
_("The coordinates of the selected geometry element.")
)
grid0.addWidget(coords_lbl, 6, 0, 1, 2)
self.geo_coords_entry = FCTextEdit()
grid0.addWidget(self.geo_coords_entry, 8, 0, 1, 2)
# Vertex Points Number
vertex_lbl = FCLabel('<b>%s</b>:' % _("Vertex Points"))
vertex_lbl.setToolTip(
_("The number of vertex points in the selected geometry element.")
)
self.geo_vertex_entry = FCEntry(decimals=self.decimals)
grid0.addWidget(vertex_lbl, 10, 0)
grid0.addWidget(self.geo_vertex_entry, 10, 1)
layout.addStretch() layout.addStretch()
# Editor # Editor
@@ -3690,14 +3731,37 @@ class AppGeoEditor(QtCore.QObject):
def on_tree_selection_change(self): def on_tree_selection_change(self):
self.selected = [] self.selected = []
last_obj_shape = None
selected_tree_items = self.tw.selectedItems() selected_tree_items = self.tw.selectedItems()
for sel in selected_tree_items: for sel in selected_tree_items:
for obj_shape in self.storage.get_objects(): for obj_shape in self.storage.get_objects():
try: try:
if id(obj_shape) == int(sel.text(0)): if id(obj_shape) == int(sel.text(0)):
self.selected.append(obj_shape) self.selected.append(obj_shape)
last_obj_shape = obj_shape
except ValueError: except ValueError:
pass pass
if last_obj_shape:
last_sel_geo = last_obj_shape.geo
if last_sel_geo.geom_type in ['LinearRing', 'LineString', 'MultiLineString']:
length = last_sel_geo.length
coords = list(last_sel_geo.coords)
vertex_nr = len(coords)
elif last_sel_geo.geom_type == 'Polygon':
length = last_sel_geo.exterior.length
coords = list(last_sel_geo.exterior.coords)
vertex_nr = len(coords)
else:
length = 0.0
coords = 'None'
vertex_nr = 0
self.geo_len_entry.set_value(length, decimals=self.decimals)
self.geo_coords_entry.setText(str(coords))
self.geo_vertex_entry.set_value(vertex_nr)
self.replot() self.replot()
def activate(self): def activate(self):
@@ -4029,10 +4093,17 @@ class AppGeoEditor(QtCore.QObject):
return return
# List of DrawToolShape? # List of DrawToolShape?
if isinstance(shape, list): # if isinstance(shape, list):
# for subshape in shape:
# self.add_shape(subshape)
# return
try:
for subshape in shape: for subshape in shape:
self.add_shape(subshape) self.add_shape(subshape)
return return
except TypeError:
pass
assert isinstance(shape, DrawToolShape), "Expected a DrawToolShape, got %s" % type(shape) assert isinstance(shape, DrawToolShape), "Expected a DrawToolShape, got %s" % type(shape)
assert shape.geo is not None, "Shape object has empty geometry (None)" assert shape.geo is not None, "Shape object has empty geometry (None)"
@@ -4042,12 +4113,14 @@ class AppGeoEditor(QtCore.QObject):
if isinstance(shape, DrawToolUtilityShape): if isinstance(shape, DrawToolUtilityShape):
self.utility.append(shape) self.utility.append(shape)
else: else:
try: geometry = shape.geo
self.storage.insert(shape) if geometry and geometry.is_valid and not geometry.is_empty and geometry.geom_type != 'Point':
except Exception as err: try:
self.app.inform_shell.emit('%s\n%s' % ( _("Error on inserting shapes into storage."), str(err))) self.storage.insert(shape)
if build_ui is True: except Exception as err:
self.build_ui_sig.emit() # Build UI self.app.inform_shell.emit('%s\n%s' % ( _("Error on inserting shapes into storage."), str(err)))
if build_ui is True:
self.build_ui_sig.emit() # Build UI
def delete_utility_geometry(self): def delete_utility_geometry(self):
""" """
@@ -4416,7 +4489,7 @@ class AppGeoEditor(QtCore.QObject):
while iterator.value(): while iterator.value():
item = iterator.value() item = iterator.value()
try: try:
if int(item.text(1)) == id(sel_shape): if int(item.text(0)) == id(sel_shape):
item.setSelected(True) item.setSelected(True)
except ValueError: except ValueError:
pass pass
@@ -4801,14 +4874,22 @@ class AppGeoEditor(QtCore.QObject):
else: else:
geo_to_edit = editor_obj.flatten(geometry=fcgeometry.solid_geometry, orient_val=milling_type) geo_to_edit = editor_obj.flatten(geometry=fcgeometry.solid_geometry, orient_val=milling_type)
for shape in geo_to_edit: # ####################################################################################################
if shape is not None: # remove the invalid geometry and also the Points as those are not relevant for the Editor
if type(shape) == Polygon: # ####################################################################################################
editor_obj.add_shape(DrawToolShape(shape.exterior), build_ui=False) try:
for inter in shape.interiors: __ = iter(geo_to_edit)
editor_obj.add_shape(DrawToolShape(inter), build_ui=False) except TypeError:
else: geo_to_edit = [geo_to_edit]
editor_obj.add_shape(DrawToolShape(shape), build_ui=False) cleaned_geo = [g for g in geo_to_edit if g and not g.is_empty and g.is_valid and g.geom_type != 'Point']
for shape in cleaned_geo:
if shape.geom_type == 'Polygon':
editor_obj.add_shape(DrawToolShape(shape.exterior), build_ui=False)
for inter in shape.interiors:
editor_obj.add_shape(DrawToolShape(inter), build_ui=False)
else:
editor_obj.add_shape(DrawToolShape(shape), build_ui=False)
editor_obj.replot() editor_obj.replot()
@@ -5007,8 +5088,9 @@ class AppGeoEditor(QtCore.QObject):
tools = selected[1:] tools = selected[1:]
toolgeo = unary_union([deepcopy(shp.geo) for shp in tools]).buffer(0.0000001) toolgeo = unary_union([deepcopy(shp.geo) for shp in tools]).buffer(0.0000001)
target = deepcopy(selected[0].geo) target = deepcopy(selected[0].geo)
result = DrawToolShape(target.difference(toolgeo))
self.add_shape(result) result = target.difference(toolgeo)
self.add_shape(DrawToolShape(result))
for_deletion = [s for s in self.get_selected()] for_deletion = [s for s in self.get_selected()]
for shape in for_deletion: for shape in for_deletion:

View File

@@ -238,9 +238,19 @@ class ToolFollow(AppTool, Gerber):
oname = opt_key[len('tools_mill') + 1:] oname = opt_key[len('tools_mill') + 1:]
new_data[oname] = app_obj.options[opt_key] new_data[oname] = app_obj.options[opt_key]
try:
__ = iter(followed_obj.follow_geometry)
except TypeError:
followed_obj.follow_geometry = [followed_obj.follow_geometry]
follow_geo = [
g for g in followed_obj.follow_geometry if g and not g.is_empty and g.is_valid and
g.geom_type != 'Point'
]
# Propagate options # Propagate options
new_obj.options["cnctooldia"] = app_obj.defaults["geometry_cnctooldia"] new_obj.options["cnctooldia"] = app_obj.defaults["geometry_cnctooldia"]
new_obj.solid_geometry = deepcopy(followed_obj.follow_geometry) new_obj.solid_geometry = follow_geo
new_obj.tools = { new_obj.tools = {
1: { 1: {
'tooldia': app_obj.dec_format(float(tools_list[0]), self.decimals), 'tooldia': app_obj.dec_format(float(tools_list[0]), self.decimals),
@@ -304,7 +314,14 @@ class ToolFollow(AppTool, Gerber):
self.sel_rect[:] = [] self.sel_rect[:] = []
self.points = [] self.points = []
new_obj.solid_geometry = deepcopy(area_follow) try:
__ = iter(area_follow)
except TypeError:
area_follow = [area_follow]
cleaned_area_follow = [g for g in area_follow if not g.is_empty and g.is_valid and g.geom_type != 'Point']
new_obj.solid_geometry = deepcopy(cleaned_area_follow)
new_obj.tools = { new_obj.tools = {
1: { 1: {
'tooldia': app_obj.dec_format(float(tools_list[0]), self.decimals), 'tooldia': app_obj.dec_format(float(tools_list[0]), self.decimals),