summaryrefslogtreecommitdiff
path: root/lib/elements
diff options
context:
space:
mode:
Diffstat (limited to 'lib/elements')
-rw-r--r--lib/elements/auto_fill.py4
-rw-r--r--lib/elements/element.py12
-rw-r--r--lib/elements/fill.py4
-rw-r--r--lib/elements/pattern.py33
-rw-r--r--lib/elements/polyline.py4
-rw-r--r--lib/elements/satin_column.py54
-rw-r--r--lib/elements/stroke.py6
-rw-r--r--lib/elements/utils.py5
8 files changed, 101 insertions, 21 deletions
diff --git a/lib/elements/auto_fill.py b/lib/elements/auto_fill.py
index cf7a44a7..3c13a081 100644
--- a/lib/elements/auto_fill.py
+++ b/lib/elements/auto_fill.py
@@ -13,7 +13,7 @@ from ..i18n import _
from ..stitches import auto_fill
from ..svg.tags import INKSCAPE_LABEL
from ..utils import cache, version
-from .element import Patch, param
+from .element import StitchGroup, param
from .fill import Fill
from .validation import ValidationWarning
@@ -261,7 +261,7 @@ class AutoFill(Fill):
self.fatal(message)
- return [Patch(stitches=stitches, color=self.color)]
+ return [StitchGroup(stitches=stitches, color=self.color)]
def validation_warnings(self):
if self.shape.area < 20:
diff --git a/lib/elements/element.py b/lib/elements/element.py
index 0b001f0b..17ed9167 100644
--- a/lib/elements/element.py
+++ b/lib/elements/element.py
@@ -11,13 +11,14 @@ from inkex import bezier
from ..commands import find_commands
from ..i18n import _
+from ..patterns import apply_patterns
from ..svg import (PIXELS_PER_MM, apply_transforms, convert_length,
get_node_transform)
from ..svg.tags import INKSCAPE_LABEL, INKSTITCH_ATTRIBS
from ..utils import Point, cache
-class Patch:
+class StitchGroup:
"""A raw collection of stitches with attached instructions."""
def __init__(self, color=None, stitches=None, trim_after=False, stop_after=False, tie_modus=0, stitch_as_is=False):
@@ -29,10 +30,10 @@ class Patch:
self.stitch_as_is = stitch_as_is
def __add__(self, other):
- if isinstance(other, Patch):
- return Patch(self.color, self.stitches + other.stitches)
+ if isinstance(other, StitchGroup):
+ return StitchGroup(self.color, self.stitches + other.stitches)
else:
- raise TypeError("Patch can only be added to another Patch")
+ raise TypeError("StitchGroup can only be added to another StitchGroup")
def __len__(self):
# This method allows `len(patch)` and `if patch:
@@ -42,7 +43,7 @@ class Patch:
self.stitches.append(stitch)
def reverse(self):
- return Patch(self.color, self.stitches[::-1])
+ return StitchGroup(self.color, self.stitches[::-1])
class Param(object):
@@ -335,6 +336,7 @@ class EmbroideryElement(object):
self.validate()
patches = self.to_patches(last_patch)
+ apply_patterns(patches, self.node)
for patch in patches:
patch.tie_modus = self.ties
diff --git a/lib/elements/fill.py b/lib/elements/fill.py
index b6799165..75a86ffd 100644
--- a/lib/elements/fill.py
+++ b/lib/elements/fill.py
@@ -14,7 +14,7 @@ from ..i18n import _
from ..stitches import legacy_fill
from ..svg import PIXELS_PER_MM
from ..utils import cache
-from .element import EmbroideryElement, Patch, param
+from .element import EmbroideryElement, StitchGroup, param
from .validation import ValidationError
@@ -198,4 +198,4 @@ class Fill(EmbroideryElement):
self.flip,
self.staggers,
self.skip_last)
- return [Patch(stitches=stitch_list, color=self.color) for stitch_list in stitch_lists]
+ return [StitchGroup(stitches=stitch_list, color=self.color) for stitch_list in stitch_lists]
diff --git a/lib/elements/pattern.py b/lib/elements/pattern.py
new file mode 100644
index 00000000..95ce81a1
--- /dev/null
+++ b/lib/elements/pattern.py
@@ -0,0 +1,33 @@
+# 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 ..i18n import _
+from .element import EmbroideryElement
+from .validation import ObjectTypeWarning
+
+
+class PatternWarning(ObjectTypeWarning):
+ name = _("Pattern Element")
+ description = _("This element will not be embroidered. "
+ "It will appear as a pattern applied to objects in the same group as it. "
+ "Objects in sub-groups will be ignored.")
+ steps_to_solve = [
+ _("To disable pattern mode, remove the pattern marker:"),
+ _('* Open the Fill and Stroke panel (Objects > Fill and Stroke)'),
+ _('* Go to the Stroke style tab'),
+ _('* Under "Markers" choose the first (empty) option in the first dropdown list.')
+ ]
+
+
+class PatternObject(EmbroideryElement):
+
+ def validation_warnings(self):
+ repr_point = next(inkex.Path(self.parse_path()).end_points)
+ yield PatternWarning(repr_point)
+
+ def to_patches(self, last_patch):
+ return []
diff --git a/lib/elements/polyline.py b/lib/elements/polyline.py
index 5ea00508..f63dfc3b 100644
--- a/lib/elements/polyline.py
+++ b/lib/elements/polyline.py
@@ -9,7 +9,7 @@ from shapely import geometry as shgeo
from ..i18n import _
from ..utils import cache
from ..utils.geometry import Point
-from .element import EmbroideryElement, Patch, param
+from .element import EmbroideryElement, StitchGroup, param
from .validation import ValidationWarning
@@ -101,7 +101,7 @@ class Polyline(EmbroideryElement):
yield PolylineWarning(self.points[0])
def to_patches(self, last_patch):
- patch = Patch(color=self.color)
+ patch = StitchGroup(color=self.color)
for stitch in self.stitches:
patch.add_stitch(Point(*stitch))
diff --git a/lib/elements/satin_column.py b/lib/elements/satin_column.py
index d72680b7..1f28cb45 100644
--- a/lib/elements/satin_column.py
+++ b/lib/elements/satin_column.py
@@ -14,7 +14,7 @@ from shapely.ops import nearest_points
from ..i18n import _
from ..svg import line_strings_to_csp, point_lists_to_csp
from ..utils import Point, cache, collapse_duplicate_point, cut
-from .element import EmbroideryElement, Patch, param
+from .element import EmbroideryElement, StitchGroup, param
from .validation import ValidationError, ValidationWarning
@@ -81,6 +81,14 @@ class SatinColumn(EmbroideryElement):
return self.get_boolean_param("e_stitch")
@property
+ @param('max_stitch_length_mm',
+ _('Maximum stitch length'),
+ tooltip=_('Maximum stitch length for split stitches.'),
+ type='float', unit="mm")
+ def max_stitch_length(self):
+ return self.get_float_param("max_stitch_length_mm") or None
+
+ @property
def color(self):
return self.get_style("stroke")
@@ -708,7 +716,7 @@ class SatinColumn(EmbroideryElement):
# other.
forward, back = self.plot_points_on_rails(self.contour_underlay_stitch_length,
-self.contour_underlay_inset)
- return Patch(color=self.color, stitches=(forward + list(reversed(back))))
+ return StitchGroup(color=self.color, stitches=(forward + list(reversed(back))))
def do_center_walk(self):
# Center walk underlay is just a running stitch down and back on the
@@ -717,7 +725,7 @@ class SatinColumn(EmbroideryElement):
# Do it like contour underlay, but inset all the way to the center.
forward, back = self.plot_points_on_rails(self.center_walk_underlay_stitch_length,
-100000)
- return Patch(color=self.color, stitches=(forward + list(reversed(back))))
+ return StitchGroup(color=self.color, stitches=(forward + list(reversed(back))))
def do_zigzag_underlay(self):
# zigzag underlay, usually done at a much lower density than the
@@ -730,7 +738,7 @@ class SatinColumn(EmbroideryElement):
# "German underlay" described here:
# http://www.mrxstitch.com/underlay-what-lies-beneath-machine-embroidery/
- patch = Patch(color=self.color)
+ patch = StitchGroup(color=self.color)
sides = self.plot_points_on_rails(self.zigzag_underlay_spacing / 2.0,
-self.zigzag_underlay_inset)
@@ -756,7 +764,10 @@ class SatinColumn(EmbroideryElement):
# print >> dbg, "satin", self.zigzag_spacing, self.pull_compensation
- patch = Patch(color=self.color)
+ if self.max_stitch_length:
+ return self.do_split_stitch()
+
+ patch = StitchGroup(color=self.color)
sides = self.plot_points_on_rails(self.zigzag_spacing, self.pull_compensation)
@@ -774,7 +785,7 @@ class SatinColumn(EmbroideryElement):
# print >> dbg, "satin", self.zigzag_spacing, self.pull_compensation
- patch = Patch(color=self.color)
+ patch = StitchGroup(color=self.color)
sides = self.plot_points_on_rails(self.zigzag_spacing, self.pull_compensation)
@@ -787,6 +798,35 @@ class SatinColumn(EmbroideryElement):
return patch
+ def do_split_stitch(self):
+ # stitches exceeding the maximum stitch length will be divided into equal parts through additional stitches
+ patch = StitchGroup(color=self.color)
+ sides = self.plot_points_on_rails(self.zigzag_spacing, self.pull_compensation)
+ for i, (left, right) in enumerate(zip(*sides)):
+ patch.add_stitch(left)
+ points, count = self._get_split_points(left, right)
+ for point in points:
+ patch.add_stitch(point)
+ patch.add_stitch(right)
+ # it is possible that the way back has a different length from the first
+ # but it looks ugly if the points differ too much
+ # so let's make sure they have at least the same amount of divisions
+ if not i+1 >= len(sides[0]):
+ points, count = self._get_split_points(right, sides[0][i+1], count)
+ for point in points:
+ patch.add_stitch(point)
+ return patch
+
+ def _get_split_points(self, left, right, count=None):
+ points = []
+ distance = left.distance(right)
+ split_count = count or int(-(-distance // self.max_stitch_length))
+ for i in range(split_count):
+ line = shgeo.LineString((left, right))
+ split_point = line.interpolate((i+1)/split_count, normalized=True)
+ points.append(Point(split_point.x, split_point.y))
+ return [points, split_count]
+
def to_patches(self, last_patch):
# Stitch a variable-width satin column, zig-zagging between two paths.
@@ -794,7 +834,7 @@ class SatinColumn(EmbroideryElement):
# beziers. The boundary points between beziers serve as "checkpoints",
# allowing the user to control how the zigzags flow around corners.
- patch = Patch(color=self.color)
+ patch = StitchGroup(color=self.color)
if self.center_walk_underlay:
patch += self.do_center_walk()
diff --git a/lib/elements/stroke.py b/lib/elements/stroke.py
index 39a8f6e3..76e80688 100644
--- a/lib/elements/stroke.py
+++ b/lib/elements/stroke.py
@@ -11,7 +11,7 @@ from ..i18n import _
from ..stitches import bean_stitch, running_stitch
from ..svg import parse_length_with_units
from ..utils import Point, cache
-from .element import EmbroideryElement, Patch, param
+from .element import EmbroideryElement, StitchGroup, param
warned_about_legacy_running_stitch = False
@@ -190,7 +190,7 @@ class Stroke(EmbroideryElement):
stitches = running_stitch(repeated_path, stitch_length)
- return Patch(self.color, stitches)
+ return StitchGroup(self.color, stitches)
def to_patches(self, last_patch):
patches = []
@@ -198,7 +198,7 @@ class Stroke(EmbroideryElement):
for path in self.paths:
path = [Point(x, y) for x, y in path]
if self.manual_stitch_mode:
- patch = Patch(color=self.color, stitches=path, stitch_as_is=True)
+ patch = StitchGroup(color=self.color, stitches=path, stitch_as_is=True)
elif self.is_running_stitch():
patch = self.running_stitch(path, self.running_stitch_length)
diff --git a/lib/elements/utils.py b/lib/elements/utils.py
index aceab485..99df7002 100644
--- a/lib/elements/utils.py
+++ b/lib/elements/utils.py
@@ -4,6 +4,7 @@
# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
from ..commands import is_command
+from ..patterns import is_pattern
from ..svg.tags import (EMBROIDERABLE_TAGS, SVG_IMAGE_TAG, SVG_PATH_TAG,
SVG_POLYLINE_TAG, SVG_TEXT_TAG)
from .auto_fill import AutoFill
@@ -12,6 +13,7 @@ from .element import EmbroideryElement
from .empty_d_object import EmptyDObject
from .fill import Fill
from .image import ImageObject
+from .pattern import PatternObject
from .polyline import Polyline
from .satin_column import SatinColumn
from .stroke import Stroke
@@ -28,6 +30,9 @@ def node_to_elements(node): # noqa: C901
elif node.tag == SVG_PATH_TAG and not node.get('d', ''):
return [EmptyDObject(node)]
+ elif is_pattern(node):
+ return [PatternObject(node)]
+
elif node.tag in EMBROIDERABLE_TAGS:
element = EmbroideryElement(node)