use offset curve for convert satin extension (#2775)

filter invalid rungs when merging satin sections
pull/2803/head
Kaalleen 2024-03-23 09:00:40 +01:00 zatwierdzone przez GitHub
rodzic 3bf30f6f26
commit 1112959da1
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
2 zmienionych plików z 20 dodań i 15 usunięć

Wyświetl plik

@ -941,8 +941,20 @@ class SatinColumn(EmbroideryElement):
# add on the other satin's rungs # add on the other satin's rungs
rungs.extend(other_rungs) rungs.extend(other_rungs)
rungs = self._get_filtered_rungs(rails, rungs)
return self._csp_to_satin(point_lists_to_csp(rails + rungs)) return self._csp_to_satin(point_lists_to_csp(rails + rungs))
def _get_filtered_rungs(self, rails, rungs):
# returns a filtered list of rungs which do intersect the rails exactly twice
rails = shgeo.MultiLineString(rails)
filtered_rungs = []
for rung in shgeo.MultiLineString(rungs).geoms:
intersection = rung.intersection(rails)
if intersection.geom_type == "MultiPoint" and len(intersection.geoms) == 2:
filtered_rungs.append(list(rung.coords))
return filtered_rungs
@property @property
@cache @cache
def center_line(self): def center_line(self):

Wyświetl plik

@ -12,12 +12,12 @@ import numpy
from numpy import diff, setdiff1d, sign from numpy import diff, setdiff1d, sign
from shapely import geometry as shgeo from shapely import geometry as shgeo
from .base import InkstitchExtension
from ..elements import SatinColumn, Stroke from ..elements import SatinColumn, Stroke
from ..i18n import _ from ..i18n import _
from ..svg import PIXELS_PER_MM, get_correction_transform from ..svg import PIXELS_PER_MM, get_correction_transform
from ..svg.tags import INKSTITCH_ATTRIBS from ..svg.tags import INKSTITCH_ATTRIBS
from ..utils import Point from ..utils import Point
from .base import InkstitchExtension
class SelfIntersectionError(Exception): class SelfIntersectionError(Exception):
@ -119,7 +119,7 @@ class ConvertToSatin(InkstitchExtension):
return [point for point, repeats in groupby(path)] return [point for point, repeats in groupby(path)]
def join_style_args(self, element): def join_style_args(self, element):
"""Convert svg line join style to shapely parallel offset arguments.""" """Convert svg line join style to shapely offset_curve arguments."""
args = { args = {
# mitre is the default per SVG spec # mitre is the default per SVG spec
@ -146,16 +146,12 @@ class ConvertToSatin(InkstitchExtension):
if Point(*path[0]).distance(Point(*path[-1])) < 1: if Point(*path[0]).distance(Point(*path[-1])) < 1:
raise SelfIntersectionError() raise SelfIntersectionError()
# Shapely is supposed to return right sided offsets in reversed direction, which it does, except for macOS.
# To avoid direction checking, we are going to rely on left side offsets only.
# Therefore we need to reverse the original path.
reversed_path = shgeo.LineString(reversed(path))
path = shgeo.LineString(path) path = shgeo.LineString(path)
distance = stroke_width / 2.0 distance = stroke_width / 2.0
try: try:
left_rail = path.parallel_offset(distance, 'left', **style_args) left_rail = path.offset_curve(-distance, **style_args)
right_rail = reversed_path.parallel_offset(distance, 'left', **style_args) right_rail = path.offset_curve(distance, **style_args)
except ValueError: except ValueError:
# TODO: fix this error automatically # TODO: fix this error automatically
# Error reference: https://github.com/inkstitch/inkstitch/issues/964 # Error reference: https://github.com/inkstitch/inkstitch/issues/964
@ -163,16 +159,13 @@ class ConvertToSatin(InkstitchExtension):
"Please break up your path and try again.") + '\n') "Please break up your path and try again.") + '\n')
sys.exit(1) sys.exit(1)
if not isinstance(left_rail, shgeo.LineString) or \ if left_rail.geom_type != 'LineString' or right_rail.geom_type != 'LineString':
not isinstance(right_rail, shgeo.LineString): # If the offset curve come out as anything but a LineString, that means the
# If the parallel offsets come out as anything but a LineString, that means the # path intersects itself, when taking its stroke width into consideration.
# path intersects itself, when taking its stroke width into consideration. See
# the last example for parallel_offset() in the Shapely documentation:
# https://shapely.readthedocs.io/en/latest/manual.html#object.parallel_offset
raise SelfIntersectionError() raise SelfIntersectionError()
left_rail = list(left_rail.coords) left_rail = list(left_rail.coords)
right_rail = list(reversed(right_rail.coords)) right_rail = list(right_rail.coords)
rungs = self.generate_rungs(path, stroke_width) rungs = self.generate_rungs(path, stroke_width)