summaryrefslogtreecommitdiff
path: root/lib/patterns.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/patterns.py')
-rw-r--r--lib/patterns.py106
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