diff options
| author | Kaalleen <36401965+kaalleen@users.noreply.github.com> | 2025-08-31 11:25:46 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-08-31 11:25:46 +0200 |
| commit | 612f18dc711c6a0fbf554465174b449604abb374 (patch) | |
| tree | 3ad9bab29ae6f453c7f0406bfe8ee5bcbceabfb2 /lib/elements/utils/stroke_to_satin.py | |
| parent | 3b2f2973f3977bba5838e48c85ba4c8e3a41c71d (diff) | |
stroke to satin: ensure a good starting point for closed paths (#3944)
starting point for the conversion, not necessarily the resulting column
Diffstat (limited to 'lib/elements/utils/stroke_to_satin.py')
| -rw-r--r-- | lib/elements/utils/stroke_to_satin.py | 47 |
1 files changed, 39 insertions, 8 deletions
diff --git a/lib/elements/utils/stroke_to_satin.py b/lib/elements/utils/stroke_to_satin.py index e75ca5d3..0b8ec819 100644 --- a/lib/elements/utils/stroke_to_satin.py +++ b/lib/elements/utils/stroke_to_satin.py @@ -3,18 +3,19 @@ # Copyright (c) 2025 Authors # Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details. -from numpy import zeros, convolve, int32, diff, setdiff1d, sign -from math import degrees, acos -from ...svg import PIXELS_PER_MM +import sys +from math import acos, degrees -from ...utils import Point -from shapely import geometry as shgeo from inkex import errormsg -from ...utils.geometry import remove_duplicate_points +from numpy import convolve, diff, int32, setdiff1d, sign, zeros +from shapely import geometry as shgeo +from shapely.affinity import rotate, scale from shapely.ops import substring -from shapely.affinity import scale + from ...i18n import _ -import sys +from ...svg import PIXELS_PER_MM +from ...utils import Point, roll_linear_ring +from ...utils.geometry import remove_duplicate_points class SelfIntersectionError(Exception): @@ -305,3 +306,33 @@ def _merge(section, other_section): rungs.extend(other_rungs) return (rails, rungs) + + +def set_first_node(paths, stroke_width): + """ + Rolls the first path in paths to a starting node which has no intersections and is not within a sharp corner + + paths is expected to be a list with only one closed path. + """ + path = paths[0] + + ring = shgeo.LinearRing(path) + buffered_ring = ring.buffer(stroke_width / 2).boundary + + for point1, point2 in zip(path[:-1], path[1:]): + line = shgeo.LineString([point1, point2]) + if line.length == 0: + continue + + # create a rung at the center of the line + # we know that the line (and therefore it's center) is always straight + scale_factor = (stroke_width + 0.001) / line.length + rung = rotate(line, 90) + rung = scale(rung, xfact=scale_factor, yfact=scale_factor) + + # when the rung intersects twice with the buffered ring, we assume a good starting point + intersection = rung.intersection(buffered_ring) + if isinstance(intersection, shgeo.MultiPoint) and len(intersection.geoms) == 2: + distance = ring.project(line.centroid) + paths[0] = list(roll_linear_ring(ring, distance).coords) + break |
