diff options
Diffstat (limited to 'lib/elements')
| -rw-r--r-- | lib/elements/auto_fill.py | 4 | ||||
| -rw-r--r-- | lib/elements/element.py | 12 | ||||
| -rw-r--r-- | lib/elements/fill.py | 4 | ||||
| -rw-r--r-- | lib/elements/pattern.py | 33 | ||||
| -rw-r--r-- | lib/elements/polyline.py | 4 | ||||
| -rw-r--r-- | lib/elements/satin_column.py | 54 | ||||
| -rw-r--r-- | lib/elements/stroke.py | 6 | ||||
| -rw-r--r-- | lib/elements/utils.py | 5 |
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) |
