diff options
Diffstat (limited to 'lib/patterns.py')
| -rw-r--r-- | lib/patterns.py | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/lib/patterns.py b/lib/patterns.py new file mode 100644 index 00000000..8a0c8449 --- /dev/null +++ b/lib/patterns.py @@ -0,0 +1,106 @@ +# Authors: see git history +# +# Copyright (c) 2010 Authors +# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details. + +import inkex +from shapely import geometry as shgeo + +from .stitch_plan import Stitch +from .svg.tags import EMBROIDERABLE_TAGS +from .utils import Point + + +def is_pattern(node): + if node.tag not in EMBROIDERABLE_TAGS: + return False + style = node.get('style') or '' + return "marker-start:url(#inkstitch-pattern-marker)" in style + + +def apply_patterns(patches, node): + patterns = _get_patterns(node) + _apply_stroke_patterns(patterns['stroke_patterns'], patches) + _apply_fill_patterns(patterns['fill_patterns'], patches) + + +def _apply_stroke_patterns(patterns, patches): + for pattern in patterns: + for patch in patches: + patch_points = [] + for i, stitch in enumerate(patch.stitches): + patch_points.append(stitch) + if i == len(patch.stitches) - 1: + continue + intersection_points = _get_pattern_points(stitch, patch.stitches[i+1], pattern) + for point in intersection_points: + patch_points.append(Stitch(point, tags=('pattern_point',))) + patch.stitches = patch_points + + +def _apply_fill_patterns(patterns, patches): + for pattern in patterns: + for patch in patches: + patch_points = [] + for i, stitch in enumerate(patch.stitches): + if not shgeo.Point(stitch).within(pattern): + # keep points outside the fill pattern + patch_points.append(stitch) + elif i - 1 < 0 or i >= len(patch.stitches) - 1: + # keep start and end points + patch_points.append(stitch) + elif stitch.has_tag('fill_row_start') or stitch.has_tag('fill_row_end'): + # keep points if they are the start or end of a fill stitch row + patch_points.append(stitch) + elif stitch.has_tag('auto_fill') and not stitch.has_tag('auto_fill_top'): + # keep auto-fill underlay + patch_points.append(stitch) + elif stitch.has_tag('auto_fill_travel'): + # keep travel stitches (underpath or travel around the border) + patch_points.append(stitch) + elif stitch.has_tag('satin_column') and not stitch.has_tag('satin_split_stitch'): + # keep satin column stitches unless they are split stitches + patch_points.append(stitch) + patch.stitches = patch_points + + +def _get_patterns(node): + from .elements import EmbroideryElement + from .elements.fill import Fill + from .elements.stroke import Stroke + + fills = [] + strokes = [] + xpath = "./parent::svg:g/*[contains(@style, 'marker-start:url(#inkstitch-pattern-marker)')]" + patterns = node.xpath(xpath, namespaces=inkex.NSS) + for pattern in patterns: + if pattern.tag not in EMBROIDERABLE_TAGS: + continue + + element = EmbroideryElement(pattern) + fill = element.get_style('fill') + stroke = element.get_style('stroke') + + if fill is not None: + fill_pattern = Fill(pattern).shape + fills.append(fill_pattern) + + if stroke is not None: + stroke_pattern = Stroke(pattern).paths + line_strings = [shgeo.LineString(path) for path in stroke_pattern] + strokes.append(shgeo.MultiLineString(line_strings)) + + return {'fill_patterns': fills, 'stroke_patterns': strokes} + + +def _get_pattern_points(first, second, pattern): + points = [] + intersection = shgeo.LineString([first, second]).intersection(pattern) + if isinstance(intersection, shgeo.Point): + points.append(Point(intersection.x, intersection.y)) + if isinstance(intersection, shgeo.MultiPoint): + for point in intersection: + points.append(Point(point.x, point.y)) + # sort points after their distance to first + points.sort(key=lambda point: point.distance(first)) + return points |
