summaryrefslogtreecommitdiff
path: root/lib/stitches
diff options
context:
space:
mode:
authorAndreas <v.andreas.1@web.de>2022-03-21 20:39:06 +0100
committerKaalleen <reni@allenka.de>2022-05-04 19:18:33 +0200
commitf75c812aba081f3d8d3a6fde799cc2e9fbc9b757 (patch)
treed04badbb01987c25c2b1a5a69707d1d66d07abac /lib/stitches
parent6916a3371695205ca388daa37e3b9a0cc8d51de6 (diff)
replacing shapely parallel_offset by buffer
Diffstat (limited to 'lib/stitches')
-rw-r--r--lib/stitches/tangential_fill_stitch_line_creator.py165
1 files changed, 90 insertions, 75 deletions
diff --git a/lib/stitches/tangential_fill_stitch_line_creator.py b/lib/stitches/tangential_fill_stitch_line_creator.py
index 4d4377f0..01124478 100644
--- a/lib/stitches/tangential_fill_stitch_line_creator.py
+++ b/lib/stitches/tangential_fill_stitch_line_creator.py
@@ -2,7 +2,7 @@ from shapely.geometry.polygon import LinearRing, LineString
from shapely.geometry import Polygon, MultiLineString
from shapely.ops import polygonize
from shapely.geometry import MultiPolygon
-from anytree import AnyNode, PreOrderIter, LevelOrderGroupIter
+from anytree import AnyNode, PreOrderIter, LevelOrderGroupIter, RenderTree
from shapely.geometry.polygon import orient
from depq import DEPQ
from enum import IntEnum
@@ -10,79 +10,94 @@ from ..stitches import tangential_fill_stitch_pattern_creator
from ..stitches import constants
-def offset_linear_ring(ring, offset, side, resolution, join_style, mitre_limit):
- """
- Solves following problem: When shapely offsets a LinearRing the
- start/end point might be handled wrongly since they
- are only treated as LineString.
- (See e.g. https://i.stack.imgur.com/vVh56.png as a problematic example)
- This method checks first whether the start/end point form a problematic
- edge with respect to the offset side. If it is not a problematic
- edge we can use the normal offset_routine. Otherwise we need to
- perform two offsets:
- -offset the ring
- -offset the start/end point + its two neighbors left and right
- Finally both offsets are merged together to get the correct
- offset of a LinearRing
- """
+def offset_linear_ring(ring, offset, resolution, join_style, mitre_limit):
+ result = Polygon(ring).buffer(offset, resolution, cap_style=2, join_style=join_style, mitre_limit=mitre_limit, single_sided=True)
- coords = ring.coords[:]
- # check whether edge at index 0 is concave or convex. Only for
- # concave edges we need to spend additional effort
- dx_seg1 = dy_seg1 = 0
- if coords[0] != coords[-1]:
- dx_seg1 = coords[0][0] - coords[-1][0]
- dy_seg1 = coords[0][1] - coords[-1][1]
+ if result.geom_type == 'Polygon':
+ return result.exterior
else:
- dx_seg1 = coords[0][0] - coords[-2][0]
- dy_seg1 = coords[0][1] - coords[-2][1]
- dx_seg2 = coords[1][0] - coords[0][0]
- dy_seg2 = coords[1][1] - coords[0][1]
- # use cross product:
- crossvalue = dx_seg1 * dy_seg2 - dy_seg1 * dx_seg2
- sidesign = 1
- if side == "left":
- sidesign = -1
-
- # We do not need to take care of the joint n-0 since we
- # offset along a concave edge:
- if sidesign * offset * crossvalue <= 0:
- return ring.parallel_offset(offset, side, resolution, join_style, mitre_limit)
-
- # We offset along a convex edge so we offset the joint n-0 separately:
- if coords[0] != coords[-1]:
- coords.append(coords[0])
- offset_ring1 = ring.parallel_offset(
- offset, side, resolution, join_style, mitre_limit
- )
- offset_ring2 = LineString((coords[-2], coords[0], coords[1])).parallel_offset(
- offset, side, resolution, join_style, mitre_limit
- )
-
- # Next we need to merge the results:
- if offset_ring1.geom_type == "LineString":
- return LinearRing(offset_ring2.coords[:] + offset_ring1.coords[1:-1])
- else:
- # We have more than one resulting LineString for offset of
- # the geometry (ring) = offset_ring1.
- # Hence we need to find the LineString which belongs to the
- # offset of element 0 in coords =offset_ring2
- # in order to add offset_ring2 geometry to it:
result_list = []
- thresh = constants.offset_factor_for_adjacent_geometry * abs(offset)
- for offsets in offset_ring1:
- if (
- abs(offsets.coords[0][0] - coords[0][0]) < thresh
- and abs(offsets.coords[0][1] - coords[0][1]) < thresh
- ):
- result_list.append(
- LinearRing(offset_ring2.coords[:] + offsets.coords[1:-1])
- )
- else:
- result_list.append(LinearRing(offsets))
+ for poly in result:
+ result_list.append(poly.exterior)
return MultiLineString(result_list)
+# """
+# Solves following problem: When shapely offsets a LinearRing the
+# start/end point might be handled wrongly since they
+# are only treated as LineString.
+# (See e.g. https://i.stack.imgur.com/vVh56.png as a problematic example)
+# This method checks first whether the start/end point form a problematic
+# edge with respect to the offset side. If it is not a problematic
+# edge we can use the normal offset_routine. Otherwise we need to
+# perform two offsets:
+# -offset the ring
+# -offset the start/end point + its two neighbors left and right
+# Finally both offsets are merged together to get the correct
+# offset of a LinearRing
+# """
+
+#PROBLEM: Did not work in rare cases since it expects the point order be maintained after offsetting the curve
+#(e.g. the first point in the offsetted curve shall belong to the first point in the original curve). However, this
+#assumption seems to be not always true that is why this code was replaced by the buffer routine.
+
+# coords = ring.coords[:]
+# # check whether edge at index 0 is concave or convex. Only for
+# # concave edges we need to spend additional effort
+# dx_seg1 = dy_seg1 = 0
+# if coords[0] != coords[-1]:
+# dx_seg1 = coords[0][0] - coords[-1][0]
+# dy_seg1 = coords[0][1] - coords[-1][1]
+# else:
+# dx_seg1 = coords[0][0] - coords[-2][0]
+# dy_seg1 = coords[0][1] - coords[-2][1]
+# dx_seg2 = coords[1][0] - coords[0][0]
+# dy_seg2 = coords[1][1] - coords[0][1]
+# # use cross product:
+# crossvalue = dx_seg1 * dy_seg2 - dy_seg1 * dx_seg2
+# sidesign = 1
+# if side == "left":
+# sidesign = -1
+
+# # We do not need to take care of the joint n-0 since we
+# # offset along a concave edge:
+# if sidesign * offset * crossvalue <= 0:
+# return ring.parallel_offset(offset, side, resolution, join_style, mitre_limit)
+
+# # We offset along a convex edge so we offset the joint n-0 separately:
+# if coords[0] != coords[-1]:
+# coords.append(coords[0])
+# offset_ring1 = ring.parallel_offset(
+# offset, side, resolution, join_style, mitre_limit
+# )
+# offset_ring2 = LineString((coords[-2], coords[0], coords[1])).parallel_offset(
+# offset, side, resolution, join_style, mitre_limit
+# )
+
+# # Next we need to merge the results:
+# if offset_ring1.geom_type == "LineString":
+# return LinearRing(offset_ring2.coords[:] + offset_ring1.coords[1:-1])
+# else:
+# # We have more than one resulting LineString for offset of
+# # the geometry (ring) = offset_ring1.
+# # Hence we need to find the LineString which belongs to the
+# # offset of element 0 in coords =offset_ring2
+# # in order to add offset_ring2 geometry to it:
+# result_list = []
+# thresh = constants.offset_factor_for_adjacent_geometry * abs(offset)
+# for offsets in offset_ring1:
+# if (
+# abs(offsets.coords[0][0] - coords[0][0]) < thresh
+# and abs(offsets.coords[0][1] - coords[0][1]) < thresh
+# ):
+# result_list.append(
+# LinearRing(offset_ring2.coords[:] + offsets.coords[1:-1])
+# )
+# else:
+# result_list.append(LinearRing(offsets))
+# return MultiLineString(result_list)
+
+
def take_only_valid_linear_rings(rings):
"""
Removes all geometries which do not form a "valid" LinearRing
@@ -99,13 +114,15 @@ def take_only_valid_linear_rings(rings):
return LinearRing(new_list[0])
else:
return MultiLineString(new_list)
- else:
+ elif rings.geom_type == "LineString" or rings.geom_type == "LinearRing":
if len(rings.coords) <= 2:
return LinearRing()
elif len(rings.coords) == 3 and rings.coords[0] == rings.coords[-1]:
return LinearRing()
else:
return rings
+ else:
+ return LinearRing()
def make_tree_uniform_ccw(root):
@@ -223,7 +240,6 @@ def offset_poly(poly, offset, join_style, stitch_distance, min_stitch_distance,
outer = offset_linear_ring(
current_poly.val,
offset,
- "left",
resolution=5,
join_style=join_style,
mitre_limit=10,
@@ -234,8 +250,7 @@ def offset_poly(poly, offset, join_style, stitch_distance, min_stitch_distance,
for j in range(len(current_holes)):
inner = offset_linear_ring(
current_holes[j].val,
- offset,
- "left",
+ -offset, #take negative offset for holes
resolution=5,
join_style=join_style,
mitre_limit=10,
@@ -246,12 +261,12 @@ def offset_poly(poly, offset, join_style, stitch_distance, min_stitch_distance,
poly_inners.append(Polygon(inner))
if not outer.is_empty:
if len(poly_inners) == 0:
- if outer.geom_type == "LineString":
+ if outer.geom_type == "LineString" or outer.geom_type == "LinearRing":
result = Polygon(outer)
else:
result = MultiPolygon(polygonize(outer))
else:
- if outer.geom_type == "LineString":
+ if outer.geom_type == "LineString" or outer.geom_type == "LinearRing":
result = Polygon(outer).difference(
MultiPolygon(poly_inners))
else:
@@ -312,7 +327,7 @@ def offset_poly(poly, offset, join_style, stitch_distance, min_stitch_distance,
if previous_hole.parent is None:
previous_hole.parent = current_poly
-
+ #print(RenderTree(root))
make_tree_uniform_ccw(root)
if strategy == StitchingStrategy.CLOSEST_POINT: