apply clip to stroke (#2283)

pull/2293/head
Kaalleen 2023-05-10 09:02:47 +02:00 zatwierdzone przez GitHub
rodzic 9d5cc6013e
commit c799b798bc
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
3 zmienionych plików z 52 dodań i 9 usunięć

Wyświetl plik

@ -23,6 +23,7 @@ from ..stitches import (auto_fill, circular_fill, contour_fill, guided_fill,
legacy_fill) legacy_fill)
from ..stitches.meander_fill import meander_fill from ..stitches.meander_fill import meander_fill
from ..svg import PIXELS_PER_MM, get_node_transform from ..svg import PIXELS_PER_MM, get_node_transform
from ..svg.clip import get_clip_path
from ..svg.tags import INKSCAPE_LABEL from ..svg.tags import INKSCAPE_LABEL
from ..utils import cache, version from ..utils import cache, version
from ..utils.param import ParamOption from ..utils.param import ParamOption
@ -571,12 +572,9 @@ class FillStitch(EmbroideryElement):
if self.node.clip is None: if self.node.clip is None:
return self.original_shape return self.original_shape
from .element import EmbroideryElement clip_path = get_clip_path(self.node)
clip_element = EmbroideryElement(self.node.clip)
clip_element.paths.sort(key=lambda point_list: shgeo.Polygon(point_list).area, reverse=True)
polygon = shgeo.MultiPolygon([(clip_element.paths[0], clip_element.paths[1:])])
try: try:
intersection = polygon.intersection(self.original_shape) intersection = clip_path.intersection(self.original_shape)
except TopologicalError: except TopologicalError:
return self.original_shape return self.original_shape

Wyświetl plik

@ -5,7 +5,7 @@
from math import ceil from math import ceil
import shapely.geometry import shapely.geometry as shgeo
from inkex import Transform from inkex import Transform
from ..i18n import _ from ..i18n import _
@ -18,7 +18,9 @@ from ..threads import ThreadColor
from ..utils import Point, cache from ..utils import Point, cache
from ..utils.param import ParamOption from ..utils.param import ParamOption
from .element import EmbroideryElement, param from .element import EmbroideryElement, param
from ..svg.clip import get_clip_path
from .validation import ValidationWarning from .validation import ValidationWarning
from shapely.errors import TopologicalError
class MultipleGuideLineWarning(ValidationWarning): class MultipleGuideLineWarning(ValidationWarning):
@ -349,6 +351,7 @@ class Stroke(EmbroideryElement):
def paths(self): def paths(self):
path = self.parse_path() path = self.parse_path()
flattened = self.flatten(path) flattened = self.flatten(path)
flattened = self._get_clipped_path(flattened)
# manipulate invalid path # manipulate invalid path
if len(flattened[0]) == 1: if len(flattened[0]) == 1:
@ -366,8 +369,32 @@ class Stroke(EmbroideryElement):
@cache @cache
def as_multi_line_string(self): def as_multi_line_string(self):
line_strings = [shapely.geometry.LineString(path) for path in self.paths] line_strings = [shgeo.LineString(path) for path in self.paths]
return shapely.geometry.MultiLineString(line_strings) return shgeo.MultiLineString(line_strings)
def _get_clipped_path(self, paths):
if self.node.clip is None:
return paths
clip_path = get_clip_path(self.node)
# path to linestrings
line_strings = [shgeo.LineString(path) for path in paths]
try:
intersection = clip_path.intersection(shgeo.MultiLineString(line_strings))
except TopologicalError:
return paths
coords = []
if intersection.is_empty:
return paths
elif isinstance(intersection, shgeo.MultiLineString):
for c in [intersection for intersection in intersection.geoms if isinstance(intersection, shgeo.LineString)]:
coords.append(c.coords)
elif isinstance(intersection, shgeo.LineString):
coords.append(intersection.coords)
else:
return paths
return coords
def get_ripple_target(self): def get_ripple_target(self):
command = self.get_command('ripple_target') command = self.get_command('ripple_target')
@ -431,7 +458,7 @@ class Stroke(EmbroideryElement):
# apply max distances # apply max distances
max_len_path = [path[0]] max_len_path = [path[0]]
for points in zip(path[:-1], path[1:]): for points in zip(path[:-1], path[1:]):
line = shapely.geometry.LineString(points) line = shgeo.LineString(points)
dist = line.length dist = line.length
if dist > self.max_stitch_length: if dist > self.max_stitch_length:
num_subsections = ceil(dist / self.max_stitch_length) num_subsections = ceil(dist / self.max_stitch_length)

18
lib/svg/clip.py 100644
Wyświetl plik

@ -0,0 +1,18 @@
# Authors: see git history
#
# Copyright (c) 2023 Authors
# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
from shapely.geometry import MultiPolygon, Polygon
from ..elements import EmbroideryElement
def get_clip_path(node):
# get clip and apply node transform
clip = node.clip
transform = node.composed_transform()
clip.transform = transform
clip_element = EmbroideryElement(clip)
clip_element.paths.sort(key=lambda point_list: Polygon(point_list).area, reverse=True)
return MultiPolygon([(clip_element.paths[0], clip_element.paths[1:])])