- 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:
Marius Stanciu
2020-11-28 23:42:30 +02:00
committed by Marius
parent eb6621f5ca
commit 6a3631a401
3 changed files with 276 additions and 130 deletions

View File

@@ -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

View File

@@ -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):
""" """

View File

@@ -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(