kopia lustrzana https://github.com/inkstitch/inkstitch
apply clip to stroke (#2283)
rodzic
9d5cc6013e
commit
c799b798bc
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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:])])
|
Ładowanie…
Reference in New Issue