- in Geometry Editor - reverted to using non-threaded move
- in Geometry Editor - made sure that polygons are displayed as such in order to not create confusion (the plotted shapes now have 'content') - in Geometry Editor - in Polygon tool solved issues with adding a double point at the last position - in Geometry Editor - the Rectangle and Polygon tools are now the result stored as LinearRing instead of Polygon - in Geometry Editor - upgraded the Intersection and Subtraction tools to work correctly using as inputs LinearRing's - in Geometry Editor - fixed the display of coordinates for MultiLineString's - in Geometry Editor - fixed the Explode tool to work in the new conditions - in Geometry Editor - fixed the Buffer tool to work in the new conditions
This commit is contained in:
@@ -12,6 +12,14 @@ CHANGELOG for FlatCAM beta
|
|||||||
- updated the Italian translation (by Massimiliano Golfetto)
|
- updated the Italian translation (by Massimiliano Golfetto)
|
||||||
- added the mechanism to create an error log in the data path where to write debug data for the crashes of FlatCAM
|
- added the mechanism to create an error log in the data path where to write debug data for the crashes of FlatCAM
|
||||||
- Turkish language strings updated (by Mehmet Kaya)
|
- Turkish language strings updated (by Mehmet Kaya)
|
||||||
|
- in Geometry Editor - reverted to using non-threaded move
|
||||||
|
- in Geometry Editor - made sure that polygons are displayed as such in order to not create confusion (the plotted shapes now have 'content')
|
||||||
|
- in Geometry Editor - in Polygon tool solved issues with adding a double point at the last position
|
||||||
|
- in Geometry Editor - the Rectangle and Polygon tools are now the result stored as LinearRing instead of Polygon
|
||||||
|
- in Geometry Editor - upgraded the Intersection and Subtraction tools to work correctly using as inputs LinearRing's
|
||||||
|
- in Geometry Editor - fixed the display of coordinates for MultiLineString's
|
||||||
|
- in Geometry Editor - fixed the Explode tool to work in the new conditions
|
||||||
|
- in Geometry Editor - fixed the Buffer tool to work in the new conditions
|
||||||
|
|
||||||
27.11.2020
|
27.11.2020
|
||||||
|
|
||||||
|
|||||||
@@ -2388,7 +2388,9 @@ class FCRectangle(FCShapeTool):
|
|||||||
p1 = self.points[0]
|
p1 = self.points[0]
|
||||||
p2 = self.points[1]
|
p2 = self.points[1]
|
||||||
# self.geometry = LinearRing([p1, (p2[0], p1[1]), p2, (p1[0], p2[1])])
|
# self.geometry = LinearRing([p1, (p2[0], p1[1]), p2, (p1[0], p2[1])])
|
||||||
self.geometry = DrawToolShape(Polygon([p1, (p2[0], p1[1]), p2, (p1[0], p2[1])]))
|
geo = LinearRing([p1, (p2[0], p1[1]), p2, (p1[0], p2[1])])
|
||||||
|
|
||||||
|
self.geometry = DrawToolShape(geo)
|
||||||
self.complete = True
|
self.complete = True
|
||||||
|
|
||||||
self.draw_app.app.jump_signal.disconnect()
|
self.draw_app.app.jump_signal.disconnect()
|
||||||
@@ -2433,7 +2435,8 @@ class FCPolygon(FCShapeTool):
|
|||||||
self.draw_app.app.jump_signal.connect(lambda x: self.draw_app.update_utility_geometry(data=x))
|
self.draw_app.app.jump_signal.connect(lambda x: self.draw_app.update_utility_geometry(data=x))
|
||||||
|
|
||||||
self.draw_app.in_action = True
|
self.draw_app.in_action = True
|
||||||
self.points.append(point)
|
if point != self.points[-1:]:
|
||||||
|
self.points.append(point)
|
||||||
|
|
||||||
if len(self.points) > 0:
|
if len(self.points) > 0:
|
||||||
self.draw_app.app.inform.emit(_("Click on next Point or click right mouse button to complete ..."))
|
self.draw_app.app.inform.emit(_("Click on next Point or click right mouse button to complete ..."))
|
||||||
@@ -2460,8 +2463,11 @@ class FCPolygon(FCShapeTool):
|
|||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
if self.points[-1] == self.points[-2]:
|
||||||
|
self.points.pop(-1)
|
||||||
|
|
||||||
# self.geometry = LinearRing(self.points)
|
# self.geometry = LinearRing(self.points)
|
||||||
self.geometry = DrawToolShape(Polygon(self.points))
|
self.geometry = DrawToolShape(LinearRing(self.points))
|
||||||
self.draw_app.in_action = False
|
self.draw_app.in_action = False
|
||||||
self.complete = True
|
self.complete = True
|
||||||
|
|
||||||
@@ -2694,17 +2700,23 @@ class FCExplode(FCShapeTool):
|
|||||||
for shape in self.draw_app.get_selected():
|
for shape in self.draw_app.get_selected():
|
||||||
to_be_deleted_list.append(shape)
|
to_be_deleted_list.append(shape)
|
||||||
geo = shape.geo
|
geo = shape.geo
|
||||||
ext_coords = list(geo.exterior.coords)
|
|
||||||
|
|
||||||
for c in range(len(ext_coords)):
|
if geo.geom_type == 'MultiLineString':
|
||||||
if c < len(ext_coords) - 1:
|
lines = [line for line in geo]
|
||||||
lines.append(LineString([ext_coords[c], ext_coords[c + 1]]))
|
|
||||||
|
|
||||||
for int_geo in geo.interiors:
|
elif geo.is_ring:
|
||||||
int_coords = list(int_geo.coords)
|
geo = Polygon(geo)
|
||||||
for c in range(len(int_coords)):
|
ext_coords = list(geo.exterior.coords)
|
||||||
if c < len(int_coords):
|
|
||||||
lines.append(LineString([int_coords[c], int_coords[c + 1]]))
|
for c in range(len(ext_coords)):
|
||||||
|
if c < len(ext_coords) - 1:
|
||||||
|
lines.append(LineString([ext_coords[c], ext_coords[c + 1]]))
|
||||||
|
|
||||||
|
for int_geo in geo.interiors:
|
||||||
|
int_coords = list(int_geo.coords)
|
||||||
|
for c in range(len(int_coords)):
|
||||||
|
if c < len(int_coords):
|
||||||
|
lines.append(LineString([int_coords[c], int_coords[c + 1]]))
|
||||||
|
|
||||||
for shape in to_be_deleted_list:
|
for shape in to_be_deleted_list:
|
||||||
self.draw_app.storage.remove(shape)
|
self.draw_app.storage.remove(shape)
|
||||||
@@ -2714,6 +2726,7 @@ class FCExplode(FCShapeTool):
|
|||||||
geo_list = []
|
geo_list = []
|
||||||
for line in lines:
|
for line in lines:
|
||||||
geo_list.append(DrawToolShape(line))
|
geo_list.append(DrawToolShape(line))
|
||||||
|
|
||||||
self.geometry = geo_list
|
self.geometry = geo_list
|
||||||
self.draw_app.on_shape_complete()
|
self.draw_app.on_shape_complete()
|
||||||
self.draw_app.app.inform.emit('[success] %s...' % _("Done."))
|
self.draw_app.app.inform.emit('[success] %s...' % _("Done."))
|
||||||
@@ -2785,24 +2798,21 @@ class FCMove(FCShapeTool):
|
|||||||
return "Done."
|
return "Done."
|
||||||
|
|
||||||
def make(self):
|
def make(self):
|
||||||
def worker_task():
|
with self.draw_app.app.proc_container.new('%s...' % _("Moving")):
|
||||||
with self.draw_app.app.proc_container.new('%s...' % _("Moving")):
|
# Create new geometry
|
||||||
# Create new geometry
|
dx = self.destination[0] - self.origin[0]
|
||||||
dx = self.destination[0] - self.origin[0]
|
dy = self.destination[1] - self.origin[1]
|
||||||
dy = self.destination[1] - self.origin[1]
|
self.geometry = [DrawToolShape(affinity.translate(geom.geo, xoff=dx, yoff=dy))
|
||||||
self.geometry = [DrawToolShape(affinity.translate(geom.geo, xoff=dx, yoff=dy))
|
for geom in self.draw_app.get_selected()]
|
||||||
for geom in self.draw_app.get_selected()]
|
|
||||||
|
|
||||||
# Delete old
|
# Delete old
|
||||||
self.draw_app.delete_selected()
|
self.draw_app.delete_selected()
|
||||||
self.complete = True
|
self.complete = True
|
||||||
self.draw_app.app.inform.emit('[success] %s' % _("Done."))
|
self.draw_app.app.inform.emit('[success] %s' % _("Done."))
|
||||||
try:
|
try:
|
||||||
self.draw_app.app.jump_signal.disconnect()
|
self.draw_app.app.jump_signal.disconnect()
|
||||||
except TypeError:
|
except TypeError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
self.draw_app.app.worker_task.emit({'fcn': worker_task, 'params': []})
|
|
||||||
|
|
||||||
def selection_bbox(self):
|
def selection_bbox(self):
|
||||||
geo_list = []
|
geo_list = []
|
||||||
@@ -3873,7 +3883,21 @@ class AppGeoEditor(QtCore.QObject):
|
|||||||
self.is_valid_entry.set_value(last_sel_geo.is_valid)
|
self.is_valid_entry.set_value(last_sel_geo.is_valid)
|
||||||
self.is_empty_entry.set_value(last_sel_geo.is_empty)
|
self.is_empty_entry.set_value(last_sel_geo.is_empty)
|
||||||
|
|
||||||
if last_sel_geo.geom_type in ['LinearRing', 'LineString', 'MultiLineString']:
|
if last_sel_geo.geom_type == 'MultiLineString':
|
||||||
|
length = last_sel_geo.length
|
||||||
|
self.is_simple_entry.set_value(last_sel_geo.is_simple)
|
||||||
|
self.is_ring_entry.set_value(last_sel_geo.is_ring)
|
||||||
|
self.is_ccw_entry.set_value('None')
|
||||||
|
|
||||||
|
coords = ''
|
||||||
|
vertex_nr = 0
|
||||||
|
for idx, line in enumerate(last_sel_geo):
|
||||||
|
line_coords = list(line.coords)
|
||||||
|
vertex_nr += len(line_coords)
|
||||||
|
coords += 'Line %s\n' % str(idx)
|
||||||
|
coords += str(line_coords) + '\n'
|
||||||
|
|
||||||
|
elif last_sel_geo.geom_type in ['LinearRing', 'LineString']:
|
||||||
length = last_sel_geo.length
|
length = last_sel_geo.length
|
||||||
coords = list(last_sel_geo.coords)
|
coords = list(last_sel_geo.coords)
|
||||||
vertex_nr = len(coords)
|
vertex_nr = len(coords)
|
||||||
@@ -4879,7 +4903,6 @@ class AppGeoEditor(QtCore.QObject):
|
|||||||
:return: List of plotted elements.
|
:return: List of plotted elements.
|
||||||
"""
|
"""
|
||||||
plot_elements = []
|
plot_elements = []
|
||||||
|
|
||||||
if geometry is None:
|
if geometry is None:
|
||||||
geometry = self.active_tool.geometry
|
geometry = self.active_tool.geometry
|
||||||
|
|
||||||
@@ -4894,10 +4917,14 @@ class AppGeoEditor(QtCore.QObject):
|
|||||||
plot_elements += self.plot_shape(geometry=geometry.geo, color=color, linewidth=linewidth)
|
plot_elements += self.plot_shape(geometry=geometry.geo, color=color, linewidth=linewidth)
|
||||||
|
|
||||||
# Polygon: Descend into exterior and each interior.
|
# Polygon: Descend into exterior and each interior.
|
||||||
if isinstance(geometry, Polygon):
|
# if isinstance(geometry, Polygon):
|
||||||
plot_elements += self.plot_shape(geometry=geometry.exterior, color=color, linewidth=linewidth)
|
# plot_elements += self.plot_shape(geometry=geometry.exterior, color=color, linewidth=linewidth)
|
||||||
plot_elements += self.plot_shape(geometry=geometry.interiors, color=color, linewidth=linewidth)
|
# plot_elements += self.plot_shape(geometry=geometry.interiors, color=color, linewidth=linewidth)
|
||||||
|
|
||||||
|
if isinstance(geometry, Polygon):
|
||||||
|
plot_elements.append(self.shapes.add(shape=geometry, color=color, face_color=color[:-2]+'50', layer=0,
|
||||||
|
tolerance=self.fcgeometry.drawing_tolerance,
|
||||||
|
linewidth=linewidth))
|
||||||
if isinstance(geometry, (LineString, LinearRing)):
|
if isinstance(geometry, (LineString, LinearRing)):
|
||||||
plot_elements.append(self.shapes.add(shape=geometry, color=color, layer=0,
|
plot_elements.append(self.shapes.add(shape=geometry, color=color, layer=0,
|
||||||
tolerance=self.fcgeometry.drawing_tolerance,
|
tolerance=self.fcgeometry.drawing_tolerance,
|
||||||
@@ -4961,7 +4988,7 @@ class AppGeoEditor(QtCore.QObject):
|
|||||||
if isinstance(p, Polygon):
|
if isinstance(p, Polygon):
|
||||||
pl.append(Polygon(p.exterior.coords[::-1], p.interiors))
|
pl.append(Polygon(p.exterior.coords[::-1], p.interiors))
|
||||||
elif isinstance(p, LinearRing):
|
elif isinstance(p, LinearRing):
|
||||||
pl.append(Polygon(p.coords[::-1]))
|
pl.append(LinearRing(p.coords[::-1]))
|
||||||
elif isinstance(p, LineString):
|
elif isinstance(p, LineString):
|
||||||
pl.append(LineString(p.coords[::-1]))
|
pl.append(LineString(p.coords[::-1]))
|
||||||
elif isinstance(p, MultiPolygon):
|
elif isinstance(p, MultiPolygon):
|
||||||
@@ -4978,7 +5005,7 @@ class AppGeoEditor(QtCore.QObject):
|
|||||||
if isinstance(geom, Polygon) and geom is not None:
|
if isinstance(geom, Polygon) and geom is not None:
|
||||||
geom = Polygon(geom.exterior.coords[::-1], geom.interiors)
|
geom = Polygon(geom.exterior.coords[::-1], geom.interiors)
|
||||||
elif isinstance(geom, LinearRing) and geom is not None:
|
elif isinstance(geom, LinearRing) and geom is not None:
|
||||||
geom = Polygon(geom.coords[::-1])
|
geom = LinearRing(geom.coords[::-1])
|
||||||
elif isinstance(geom, LineString) and geom is not None:
|
elif isinstance(geom, LineString) and geom is not None:
|
||||||
geom = LineString(geom.coords[::-1])
|
geom = LineString(geom.coords[::-1])
|
||||||
else:
|
else:
|
||||||
@@ -5253,9 +5280,11 @@ class AppGeoEditor(QtCore.QObject):
|
|||||||
:return: None.
|
:return: None.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def work_task():
|
def work_task(self):
|
||||||
with self.app.proc_container.new(_("Working...")):
|
with self.app.proc_container.new(_("Working...")):
|
||||||
results = unary_union([t.geo for t in self.get_selected()])
|
results = unary_union([t.geo for t in self.get_selected()])
|
||||||
|
if results.geom_type == 'MultiLineString':
|
||||||
|
results = linemerge(results)
|
||||||
|
|
||||||
# Delete originals.
|
# Delete originals.
|
||||||
for_deletion = [s for s in self.get_selected()]
|
for_deletion = [s for s in self.get_selected()]
|
||||||
@@ -5266,10 +5295,11 @@ class AppGeoEditor(QtCore.QObject):
|
|||||||
self.selected = []
|
self.selected = []
|
||||||
|
|
||||||
self.add_shape(DrawToolShape(results))
|
self.add_shape(DrawToolShape(results))
|
||||||
|
|
||||||
self.replot()
|
self.replot()
|
||||||
|
self.build_ui_sig.emit()
|
||||||
|
self.app.inform.emit('[success] %s' % _("Done."))
|
||||||
|
|
||||||
self.app.worker_task.emit({'fcn': work_task, 'params': []})
|
self.app.worker_task.emit({'fcn': work_task, 'params': [self]})
|
||||||
|
|
||||||
def intersection_2(self):
|
def intersection_2(self):
|
||||||
"""
|
"""
|
||||||
@@ -5277,21 +5307,37 @@ class AppGeoEditor(QtCore.QObject):
|
|||||||
|
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
def work_task():
|
def work_task(self):
|
||||||
with self.app.proc_container.new(_("Working...")):
|
self.app.log.debug("AppGeoEditor.intersection_2()")
|
||||||
geo_shapes = self.get_selected()
|
|
||||||
|
|
||||||
try:
|
with self.app.proc_container.new(_("Working...")):
|
||||||
results = geo_shapes[0].geo
|
selected = self.get_selected()
|
||||||
except Exception as e:
|
|
||||||
self.app.log.debug("AppGeoEditor.intersection() --> %s" % str(e))
|
if len(selected) < 2:
|
||||||
self.app.inform.emit('[WARNING_NOTCL] %s' %
|
self.app.inform.emit('[WARNING_NOTCL] %s' %
|
||||||
_("A selection of minimum two items is required to do Intersection."))
|
_("A selection of minimum two items is required to do Intersection."))
|
||||||
self.select_tool('select')
|
self.select_tool('select')
|
||||||
return
|
return
|
||||||
|
|
||||||
for shape_el in geo_shapes[1:]:
|
target = deepcopy(selected[0].geo)
|
||||||
results = results.intersection(shape_el.geo)
|
if target.is_ring:
|
||||||
|
target = Polygon(target)
|
||||||
|
tools = selected[1:]
|
||||||
|
# toolgeo = unary_union([deepcopy(shp.geo) for shp in tools]).buffer(0.0000001)
|
||||||
|
# result = DrawToolShape(target.difference(toolgeo))
|
||||||
|
for tool in tools:
|
||||||
|
if tool.geo.is_ring:
|
||||||
|
intersector_geo = Polygon(tool.geo)
|
||||||
|
target = target.difference(intersector_geo)
|
||||||
|
|
||||||
|
if target.geom_type in ['LineString', 'MultiLineString']:
|
||||||
|
target = linemerge(target)
|
||||||
|
|
||||||
|
if target.geom_type == 'Polygon':
|
||||||
|
target = target.exterior
|
||||||
|
|
||||||
|
result = DrawToolShape(target)
|
||||||
|
self.add_shape(deepcopy(result))
|
||||||
|
|
||||||
# Delete originals.
|
# Delete originals.
|
||||||
for_deletion = [s for s in self.get_selected()]
|
for_deletion = [s for s in self.get_selected()]
|
||||||
@@ -5301,11 +5347,11 @@ class AppGeoEditor(QtCore.QObject):
|
|||||||
# Selected geometry is now gone!
|
# Selected geometry is now gone!
|
||||||
self.selected = []
|
self.selected = []
|
||||||
|
|
||||||
self.add_shape(DrawToolShape(results))
|
|
||||||
|
|
||||||
self.replot()
|
self.replot()
|
||||||
|
self.build_ui_sig.emit()
|
||||||
|
self.app.inform.emit('[success] %s' % _("Done."))
|
||||||
|
|
||||||
self.app.worker_task.emit({'fcn': work_task, 'params': []})
|
self.app.worker_task.emit({'fcn': work_task, 'params': [self]})
|
||||||
|
|
||||||
def intersection(self):
|
def intersection(self):
|
||||||
"""
|
"""
|
||||||
@@ -5314,28 +5360,35 @@ class AppGeoEditor(QtCore.QObject):
|
|||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def work_task():
|
def work_task(self):
|
||||||
|
self.app.log.debug("AppGeoEditor.intersection()")
|
||||||
|
|
||||||
with self.app.proc_container.new(_("Working...")):
|
with self.app.proc_container.new(_("Working...")):
|
||||||
geo_shapes = self.get_selected()
|
selected = self.get_selected()
|
||||||
results = []
|
results = []
|
||||||
intact = []
|
intact = []
|
||||||
|
|
||||||
try:
|
if len(selected) < 2:
|
||||||
intersector = geo_shapes[0].geo
|
|
||||||
except Exception as e:
|
|
||||||
self.app.log.debug("AppGeoEditor.intersection() --> %s" % str(e))
|
|
||||||
self.app.inform.emit('[WARNING_NOTCL] %s' %
|
self.app.inform.emit('[WARNING_NOTCL] %s' %
|
||||||
_("A selection of minimum two items is required to do Intersection."))
|
_("A selection of minimum two items is required to do Intersection."))
|
||||||
self.select_tool('select')
|
self.select_tool('select')
|
||||||
return
|
return
|
||||||
|
|
||||||
for shape_el in geo_shapes[1:]:
|
intersector = selected[0].geo
|
||||||
if intersector.intersects(shape_el.geo):
|
if intersector.is_ring:
|
||||||
results.append(intersector.intersection(shape_el.geo))
|
intersector = Polygon(intersector)
|
||||||
|
tools = selected[1:]
|
||||||
|
for tool in tools:
|
||||||
|
if tool.geo.is_ring:
|
||||||
|
intersected = Polygon(tool.geo)
|
||||||
else:
|
else:
|
||||||
intact.append(shape_el)
|
intersected = tool.geo
|
||||||
|
if intersector.intersects(intersected):
|
||||||
|
results.append(intersector.intersection(intersected))
|
||||||
|
else:
|
||||||
|
intact.append(tool)
|
||||||
|
|
||||||
if len(results) != 0:
|
if results:
|
||||||
# Delete originals.
|
# Delete originals.
|
||||||
for_deletion = [s for s in self.get_selected()]
|
for_deletion = [s for s in self.get_selected()]
|
||||||
for shape_el in for_deletion:
|
for shape_el in for_deletion:
|
||||||
@@ -5343,57 +5396,81 @@ class AppGeoEditor(QtCore.QObject):
|
|||||||
self.delete_shape(shape_el)
|
self.delete_shape(shape_el)
|
||||||
|
|
||||||
for geo in results:
|
for geo in results:
|
||||||
self.add_shape(DrawToolShape(geo))
|
if geo.geom_type == 'MultiPolygon':
|
||||||
|
for poly in geo.geoms:
|
||||||
|
p_geo = [poly.exterior] + [ints for ints in poly.interiors]
|
||||||
|
for g in p_geo:
|
||||||
|
self.add_shape(DrawToolShape(g))
|
||||||
|
elif geo.geom_type == 'Polygon':
|
||||||
|
p_geo = [geo.exterior] + [ints for ints in geo.interiors]
|
||||||
|
for g in p_geo:
|
||||||
|
self.add_shape(DrawToolShape(g))
|
||||||
|
else:
|
||||||
|
self.add_shape(DrawToolShape(geo))
|
||||||
|
|
||||||
# Selected geometry is now gone!
|
# Selected geometry is now gone!
|
||||||
self.selected = []
|
self.selected = []
|
||||||
self.replot()
|
self.replot()
|
||||||
|
self.build_ui_sig.emit()
|
||||||
|
self.app.inform.emit('[success] %s' % _("Done."))
|
||||||
|
|
||||||
self.app.worker_task.emit({'fcn': work_task, 'params': []})
|
self.app.worker_task.emit({'fcn': work_task, 'params': [self]})
|
||||||
|
|
||||||
def subtract(self):
|
def subtract(self):
|
||||||
def work_task():
|
def work_task(self):
|
||||||
with self.app.proc_container.new(_("Working...")):
|
with self.app.proc_container.new(_("Working...")):
|
||||||
selected = self.get_selected()
|
selected = self.get_selected()
|
||||||
try:
|
try:
|
||||||
tools = selected[1:]
|
|
||||||
toolgeo = unary_union([deepcopy(shp.geo) for shp in tools]).buffer(0.0000001)
|
|
||||||
target = deepcopy(selected[0].geo)
|
target = deepcopy(selected[0].geo)
|
||||||
|
tools = selected[1:]
|
||||||
result = target.difference(toolgeo)
|
# toolgeo = unary_union([deepcopy(shp.geo) for shp in tools]).buffer(0.0000001)
|
||||||
self.add_shape(DrawToolShape(result))
|
# result = DrawToolShape(target.difference(toolgeo))
|
||||||
|
for tool in tools:
|
||||||
|
if tool.geo.is_ring:
|
||||||
|
sub_geo = Polygon(tool.geo)
|
||||||
|
target = target.difference(sub_geo)
|
||||||
|
result = DrawToolShape(target)
|
||||||
|
self.add_shape(deepcopy(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:
|
||||||
self.delete_shape(shape)
|
self.delete_shape(shape)
|
||||||
|
|
||||||
self.replot()
|
self.replot()
|
||||||
|
self.build_ui_sig.emit()
|
||||||
|
self.app.inform.emit('[success] %s' % _("Done."))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.app.log.debug(str(e))
|
self.app.log.debug(str(e))
|
||||||
|
|
||||||
self.app.worker_task.emit({'fcn': work_task, 'params': []})
|
self.app.worker_task.emit({'fcn': work_task, 'params': [self]})
|
||||||
|
|
||||||
def subtract_2(self):
|
def subtract_2(self):
|
||||||
def work_task():
|
def work_task(self):
|
||||||
with self.app.proc_container.new(_("Working...")):
|
with self.app.proc_container.new(_("Working...")):
|
||||||
selected = self.get_selected()
|
selected = self.get_selected()
|
||||||
try:
|
try:
|
||||||
tools = selected[1:]
|
|
||||||
toolgeo = unary_union([shp.geo for shp in tools]).buffer(0.0000001)
|
|
||||||
target = deepcopy(selected[0].geo)
|
target = deepcopy(selected[0].geo)
|
||||||
result = DrawToolShape(target.difference(toolgeo))
|
tools = selected[1:]
|
||||||
self.add_shape(result)
|
# toolgeo = unary_union([shp.geo for shp in tools]).buffer(0.0000001)
|
||||||
|
for tool in tools:
|
||||||
|
if tool.geo.is_ring:
|
||||||
|
sub_geo = Polygon(tool.geo)
|
||||||
|
target = target.difference(sub_geo)
|
||||||
|
result = DrawToolShape(target)
|
||||||
|
self.add_shape(deepcopy(result))
|
||||||
|
|
||||||
self.delete_shape(selected[0])
|
self.delete_shape(selected[0])
|
||||||
|
|
||||||
self.replot()
|
self.replot()
|
||||||
|
self.build_ui_sig.emit()
|
||||||
|
self.app.inform.emit('[success] %s' % _("Done."))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.app.log.debug(str(e))
|
self.app.log.debug(str(e))
|
||||||
|
|
||||||
self.app.worker_task.emit({'fcn': work_task, 'params': []})
|
self.app.worker_task.emit({'fcn': work_task, 'params': [self]})
|
||||||
|
|
||||||
def cutpath(self):
|
def cutpath(self):
|
||||||
def work_task():
|
def work_task(self):
|
||||||
with self.app.proc_container.new(_("Working...")):
|
with self.app.proc_container.new(_("Working...")):
|
||||||
selected = self.get_selected()
|
selected = self.get_selected()
|
||||||
tools = selected[1:]
|
tools = selected[1:]
|
||||||
@@ -5417,11 +5494,13 @@ class AppGeoEditor(QtCore.QObject):
|
|||||||
|
|
||||||
self.delete_shape(target)
|
self.delete_shape(target)
|
||||||
self.replot()
|
self.replot()
|
||||||
|
self.build_ui_sig.emit()
|
||||||
|
self.app.inform.emit('[success] %s' % _("Done."))
|
||||||
|
|
||||||
self.app.worker_task.emit({'fcn': work_task, 'params': []})
|
self.app.worker_task.emit({'fcn': work_task, 'params': [self]})
|
||||||
|
|
||||||
def buffer(self, buf_distance, join_style):
|
def buffer(self, buf_distance, join_style):
|
||||||
def work_task():
|
def work_task(self):
|
||||||
with self.app.proc_container.new(_("Working...")):
|
with self.app.proc_container.new(_("Working...")):
|
||||||
selected = self.get_selected()
|
selected = self.get_selected()
|
||||||
|
|
||||||
@@ -5449,22 +5528,43 @@ class AppGeoEditor(QtCore.QObject):
|
|||||||
|
|
||||||
results = []
|
results = []
|
||||||
for t in selected:
|
for t in selected:
|
||||||
if isinstance(t.geo, Polygon) and not t.geo.is_empty:
|
if not t.geo.is_empty and t.geo.is_valid:
|
||||||
results.append(t.geo.exterior.buffer(
|
if t.geo.geom_type == 'Polygon':
|
||||||
buf_distance - 1e-10,
|
results.append(t.geo.exterior.buffer(
|
||||||
resolution=int(int(self.app.defaults["geometry_circle_steps"]) / 4),
|
buf_distance - 1e-10,
|
||||||
join_style=join_style)
|
resolution=int(int(self.app.defaults["geometry_circle_steps"]) / 4),
|
||||||
)
|
join_style=join_style)
|
||||||
else:
|
)
|
||||||
results.append(t.geo.buffer(
|
elif t.geo.geom_type == 'MultiLineString':
|
||||||
buf_distance - 1e-10,
|
for line in t.geo:
|
||||||
resolution=int(int(self.app.defaults["geometry_circle_steps"]) / 4),
|
if line.is_ring:
|
||||||
join_style=join_style)
|
b_geo = Polygon(line)
|
||||||
)
|
results.append(b_geo.buffer(
|
||||||
|
buf_distance - 1e-10,
|
||||||
|
resolution=int(int(self.app.defaults["geometry_circle_steps"]) / 4),
|
||||||
|
join_style=join_style).exterior
|
||||||
|
)
|
||||||
|
results.append(b_geo.buffer(
|
||||||
|
-buf_distance + 1e-10,
|
||||||
|
resolution=int(int(self.app.defaults["geometry_circle_steps"]) / 4),
|
||||||
|
join_style=join_style).exterior
|
||||||
|
)
|
||||||
|
elif t.geo.geom_type in ['LineString', 'LinearRing']:
|
||||||
|
if t.geo.is_ring:
|
||||||
|
b_geo = Polygon(t.geo)
|
||||||
|
results.append(b_geo.buffer(
|
||||||
|
buf_distance - 1e-10,
|
||||||
|
resolution=int(int(self.app.defaults["geometry_circle_steps"]) / 4),
|
||||||
|
join_style=join_style).exterior
|
||||||
|
)
|
||||||
|
results.append(b_geo.buffer(
|
||||||
|
-buf_distance + 1e-10,
|
||||||
|
resolution=int(int(self.app.defaults["geometry_circle_steps"]) / 4),
|
||||||
|
join_style=join_style).exterior
|
||||||
|
)
|
||||||
|
|
||||||
if not results:
|
if not results:
|
||||||
self.app.inform.emit('[ERROR_NOTCL] %s' %
|
self.app.inform.emit('[ERROR_NOTCL] %s' % _("Failed, the result is empty."))
|
||||||
_("Failed, the result is empty. Choose a different buffer value."))
|
|
||||||
# deselect everything
|
# deselect everything
|
||||||
self.selected = []
|
self.selected = []
|
||||||
self.replot()
|
self.replot()
|
||||||
@@ -5474,12 +5574,13 @@ class AppGeoEditor(QtCore.QObject):
|
|||||||
self.add_shape(DrawToolShape(sha))
|
self.add_shape(DrawToolShape(sha))
|
||||||
|
|
||||||
self.replot()
|
self.replot()
|
||||||
self.app.inform.emit('[success] %s' % _("Full buffer geometry created."))
|
self.build_ui_sig.emit()
|
||||||
|
self.app.inform.emit('[success] %s' % _("Done."))
|
||||||
|
|
||||||
self.app.worker_task.emit({'fcn': work_task, 'params': []})
|
self.app.worker_task.emit({'fcn': work_task, 'params': [self]})
|
||||||
|
|
||||||
def buffer_int(self, buf_distance, join_style):
|
def buffer_int(self, buf_distance, join_style):
|
||||||
def work_task():
|
def work_task(self):
|
||||||
with self.app.proc_container.new(_("Working...")):
|
with self.app.proc_container.new(_("Working...")):
|
||||||
selected = self.get_selected()
|
selected = self.get_selected()
|
||||||
|
|
||||||
@@ -5503,19 +5604,33 @@ class AppGeoEditor(QtCore.QObject):
|
|||||||
|
|
||||||
results = []
|
results = []
|
||||||
for t in selected:
|
for t in selected:
|
||||||
if isinstance(t.geo, LinearRing):
|
if not t.geo.is_empty and t.geo.is_valid:
|
||||||
t.geo = Polygon(t.geo)
|
if t.geo.geom_type == 'Polygon':
|
||||||
|
results.append(t.geo.exterior.buffer(
|
||||||
if isinstance(t.geo, Polygon) and not t.geo.is_empty:
|
-buf_distance + 1e-10,
|
||||||
results.append(t.geo.buffer(
|
resolution=int(int(self.app.defaults["geometry_circle_steps"]) / 4),
|
||||||
-buf_distance + 1e-10,
|
join_style=join_style).exterior
|
||||||
resolution=int(int(self.app.defaults["geometry_circle_steps"]) / 4),
|
)
|
||||||
join_style=join_style)
|
elif t.geo.geom_type == 'MultiLineString':
|
||||||
)
|
for line in t.geo:
|
||||||
|
if line.is_ring:
|
||||||
|
b_geo = Polygon(line)
|
||||||
|
results.append(b_geo.buffer(
|
||||||
|
-buf_distance + 1e-10,
|
||||||
|
resolution=int(int(self.app.defaults["geometry_circle_steps"]) / 4),
|
||||||
|
join_style=join_style).exterior
|
||||||
|
)
|
||||||
|
elif t.geo.geom_type in ['LineString', 'LinearRing']:
|
||||||
|
if t.geo.is_ring:
|
||||||
|
b_geo = Polygon(t.geo)
|
||||||
|
results.append(b_geo.buffer(
|
||||||
|
-buf_distance + 1e-10,
|
||||||
|
resolution=int(int(self.app.defaults["geometry_circle_steps"]) / 4),
|
||||||
|
join_style=join_style).exterior
|
||||||
|
)
|
||||||
|
|
||||||
if not results:
|
if not results:
|
||||||
self.app.inform.emit('[ERROR_NOTCL] %s' %
|
self.app.inform.emit('[ERROR_NOTCL] %s' % _("Failed, the result is empty."))
|
||||||
_("Failed, the result is empty. Choose a different buffer value."))
|
|
||||||
# deselect everything
|
# deselect everything
|
||||||
self.selected = []
|
self.selected = []
|
||||||
self.replot()
|
self.replot()
|
||||||
@@ -5525,12 +5640,13 @@ class AppGeoEditor(QtCore.QObject):
|
|||||||
self.add_shape(DrawToolShape(sha))
|
self.add_shape(DrawToolShape(sha))
|
||||||
|
|
||||||
self.replot()
|
self.replot()
|
||||||
self.app.inform.emit('[success] %s' % _("Interior buffer geometry created."))
|
self.build_ui_sig.emit()
|
||||||
|
self.app.inform.emit('[success] %s' % _("Done."))
|
||||||
|
|
||||||
self.app.worker_task.emit({'fcn': work_task, 'params': []})
|
self.app.worker_task.emit({'fcn': work_task, 'params': [self]})
|
||||||
|
|
||||||
def buffer_ext(self, buf_distance, join_style):
|
def buffer_ext(self, buf_distance, join_style):
|
||||||
def work_task():
|
def work_task(self):
|
||||||
with self.app.proc_container.new(_("Working...")):
|
with self.app.proc_container.new(_("Working...")):
|
||||||
selected = self.get_selected()
|
selected = self.get_selected()
|
||||||
|
|
||||||
@@ -5556,34 +5672,49 @@ class AppGeoEditor(QtCore.QObject):
|
|||||||
|
|
||||||
results = []
|
results = []
|
||||||
for t in selected:
|
for t in selected:
|
||||||
if isinstance(t.geo, LinearRing):
|
if not t.geo.is_empty and t.geo.is_valid:
|
||||||
t.geo = Polygon(t.geo)
|
if t.geo.geom_type == 'Polygon':
|
||||||
|
results.append(t.geo.exterior.buffer(
|
||||||
if isinstance(t.geo, Polygon) and not t.geo.is_empty:
|
buf_distance - 1e-10,
|
||||||
results.append(t.geo.buffer(
|
resolution=int(int(self.app.defaults["geometry_circle_steps"]) / 4),
|
||||||
buf_distance,
|
join_style=join_style).exterior
|
||||||
resolution=int(int(self.app.defaults["geometry_circle_steps"]) / 4),
|
)
|
||||||
join_style=join_style)
|
elif t.geo.geom_type == 'MultiLineString':
|
||||||
)
|
for line in t.geo:
|
||||||
|
if line.is_ring:
|
||||||
|
b_geo = Polygon(line)
|
||||||
|
results.append(b_geo.buffer(
|
||||||
|
buf_distance - 1e-10,
|
||||||
|
resolution=int(int(self.app.defaults["geometry_circle_steps"]) / 4),
|
||||||
|
join_style=join_style).exterior
|
||||||
|
)
|
||||||
|
elif t.geo.geom_type in ['LineString', 'LinearRing']:
|
||||||
|
if t.geo.is_ring:
|
||||||
|
b_geo = Polygon(t.geo)
|
||||||
|
results.append(b_geo.buffer(
|
||||||
|
buf_distance - 1e-10,
|
||||||
|
resolution=int(int(self.app.defaults["geometry_circle_steps"]) / 4),
|
||||||
|
join_style=join_style).exterior
|
||||||
|
)
|
||||||
|
|
||||||
if not results:
|
if not results:
|
||||||
self.app.inform.emit('[ERROR_NOTCL] %s' %
|
self.app.inform.emit('[ERROR_NOTCL] %s' % _("Failed, the result is empty."))
|
||||||
_("Failed, the result is empty. Choose a different buffer value."))
|
|
||||||
# deselect everything
|
# deselect everything
|
||||||
self.selected = []
|
self.selected = []
|
||||||
self.replot()
|
self.replot()
|
||||||
return
|
return 'fail'
|
||||||
|
|
||||||
for sha in results:
|
for sha in results:
|
||||||
self.add_shape(DrawToolShape(sha))
|
self.add_shape(DrawToolShape(sha))
|
||||||
|
|
||||||
self.replot()
|
self.replot()
|
||||||
self.app.inform.emit('[success] %s' % _("Exterior buffer geometry created."))
|
self.build_ui_sig.emit()
|
||||||
|
self.app.inform.emit('[success] %s' % _("Done."))
|
||||||
|
|
||||||
self.app.worker_task.emit({'fcn': work_task, 'params': []})
|
self.app.worker_task.emit({'fcn': work_task, 'params': [self]})
|
||||||
|
|
||||||
def paint(self, tooldia, overlap, margin, connect, contour, method):
|
def paint(self, tooldia, overlap, margin, connect, contour, method):
|
||||||
def work_task():
|
def work_task(self):
|
||||||
with self.app.proc_container.new(_("Working...")):
|
with self.app.proc_container.new(_("Working...")):
|
||||||
if overlap >= 100:
|
if overlap >= 100:
|
||||||
self.app.inform.emit('[ERROR_NOTCL] %s' %
|
self.app.inform.emit('[ERROR_NOTCL] %s' %
|
||||||
@@ -5673,10 +5804,11 @@ class AppGeoEditor(QtCore.QObject):
|
|||||||
# This is a dirty patch:
|
# This is a dirty patch:
|
||||||
for r in results:
|
for r in results:
|
||||||
self.add_shape(DrawToolShape(r))
|
self.add_shape(DrawToolShape(r))
|
||||||
self.app.inform.emit('[success] %s' % _("Done."))
|
|
||||||
self.replot()
|
self.replot()
|
||||||
|
self.build_ui_sig.emit()
|
||||||
|
self.app.inform.emit('[success] %s' % _("Done."))
|
||||||
|
|
||||||
self.app.worker_task.emit({'fcn': work_task, 'params': []})
|
self.app.worker_task.emit({'fcn': work_task, 'params': [self]})
|
||||||
|
|
||||||
def flatten(self, geometry, orient_val=1, reset=True, pathonly=False):
|
def flatten(self, geometry, orient_val=1, reset=True, pathonly=False):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -1186,9 +1186,15 @@ class MainGUI(QtWidgets.QMainWindow):
|
|||||||
self.geo_intersection_btn = self.geo_edit_toolbar.addAction(
|
self.geo_intersection_btn = self.geo_edit_toolbar.addAction(
|
||||||
QtGui.QIcon(self.app.resource_location + '/intersection32.png'), _('Polygon Intersection'))
|
QtGui.QIcon(self.app.resource_location + '/intersection32.png'), _('Polygon Intersection'))
|
||||||
self.geo_subtract_btn = self.geo_edit_toolbar.addAction(
|
self.geo_subtract_btn = self.geo_edit_toolbar.addAction(
|
||||||
QtGui.QIcon(self.app.resource_location + '/subtract32.png'), _('Polygon Subtraction'))
|
QtGui.QIcon(self.app.resource_location + '/subtract32.png'),
|
||||||
|
_('Polygon Subtraction. First selected is the target.\n'
|
||||||
|
'The rest of the selected is subtracted from the first.\n'
|
||||||
|
'First selected is replaced by the result.'))
|
||||||
self.geo_alt_subtract_btn = self.geo_edit_toolbar.addAction(
|
self.geo_alt_subtract_btn = self.geo_edit_toolbar.addAction(
|
||||||
QtGui.QIcon(self.app.resource_location + '/subtract_alt32.png'), _('Alt Subtraction'))
|
QtGui.QIcon(self.app.resource_location + '/subtract_alt32.png'),
|
||||||
|
_('Alt Subtraction. First selected is the target.\n'
|
||||||
|
'The rest of the selected is subtracted from the first.\n'
|
||||||
|
'First selected is kept besides the result.'))
|
||||||
|
|
||||||
self.geo_edit_toolbar.addSeparator()
|
self.geo_edit_toolbar.addSeparator()
|
||||||
self.geo_cutpath_btn = self.geo_edit_toolbar.addAction(
|
self.geo_cutpath_btn = self.geo_edit_toolbar.addAction(
|
||||||
|
|||||||
Reference in New Issue
Block a user