summaryrefslogtreecommitdiff
path: root/lib/elements
diff options
context:
space:
mode:
Diffstat (limited to 'lib/elements')
-rw-r--r--lib/elements/element.py159
-rw-r--r--lib/elements/fill_stitch.py14
-rw-r--r--lib/elements/polyline.py6
-rw-r--r--lib/elements/satin_column.py12
-rw-r--r--lib/elements/stroke.py13
5 files changed, 165 insertions, 39 deletions
diff --git a/lib/elements/element.py b/lib/elements/element.py
index 3a9f331c..ba15d943 100644
--- a/lib/elements/element.py
+++ b/lib/elements/element.py
@@ -4,9 +4,9 @@
# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
import sys
from copy import deepcopy
-import numpy as np
import inkex
+import numpy as np
from inkex import bezier
from ..commands import find_commands
@@ -14,6 +14,8 @@ from ..debug import debug
from ..i18n import _
from ..marker import get_marker_elements_cache_key_data
from ..patterns import apply_patterns, get_patterns_cache_key_data
+from ..stitch_plan.lock_stitch import (LOCK_DEFAULTS, AbsoluteLock, CustomLock,
+ LockStitch, SVGLock)
from ..svg import (PIXELS_PER_MM, apply_transforms, convert_length,
get_node_transform)
from ..svg.tags import INKSCAPE_LABEL, INKSTITCH_ATTRIBS
@@ -262,6 +264,119 @@ class EmbroideryElement(object):
return self.get_boolean_param('force_lock_stitches', False)
@property
+ @param('lock_start',
+ _('Tack stitch'),
+ tooltip=_('Tack down stitch type'),
+ type='combo',
+ default='half_stitch',
+ options=LOCK_DEFAULTS['start'],
+ sort_index=52)
+ def lock_start(self):
+ return self.get_param('lock_start', "half_stitch")
+
+ @property
+ @param('lock_custom_start',
+ _('Custom path'),
+ tooltip=_("Enter a custom path. For svg paths The last node will not be embroidered, but represents the first stitch of the element."),
+ type="string",
+ default="",
+ select_items=[('lock_start', 'custom')],
+ sort_index=53)
+ def lock_custom_start(self):
+ return self.get_param('lock_custom_start', '')
+
+ @property
+ @param('lock_start_scale_mm',
+ _('Scale tack stitch'),
+ tooltip=_('Set stitch length. A 1 in a custom path equals this values.'),
+ type='float',
+ unit="mm",
+ default=0.7,
+ select_items=[('lock_start', lock.id) for lock in LOCK_DEFAULTS['start'] if isinstance(lock, (AbsoluteLock, CustomLock))],
+ sort_index=54)
+ def lock_start_scale_mm(self):
+ return self.get_float_param('lock_start_scale_mm', 0.7)
+
+ @property
+ @param('lock_start_scale_percent',
+ _('Scale tack stitch'),
+ tooltip=_('Scale tack stitch by this percentage.'),
+ type='float',
+ unit="%",
+ default=100,
+ select_items=[('lock_start', lock.id) for lock in LOCK_DEFAULTS['start'] if isinstance(lock, (SVGLock, CustomLock))],
+ sort_index=54)
+ def lock_start_scale_percent(self):
+ return self.get_float_param('lock_start_scale_percent', 100)
+
+ @property
+ @param('lock_end',
+ _('Lock stitch'),
+ tooltip=_('Lock stitch type'),
+ type='combo',
+ default='half_stitch',
+ options=LOCK_DEFAULTS['end'],
+ sort_index=55)
+ def lock_end(self):
+ return self.get_param('lock_end', "half_stitch")
+
+ @property
+ @param('lock_custom_end',
+ _('Custom path'),
+ tooltip=_("Enter a custom path. For svg paths the first node will not be embroidered, but represents the last stitch of the element."),
+ type="string",
+ default="",
+ select_items=[('lock_end', 'custom')],
+ sort_index=56)
+ def lock_custom_end(self):
+ return self.get_param('lock_custom_end', '')
+
+ @property
+ @param('lock_end_scale_mm',
+ _('Scale lock stitch'),
+ tooltip=_('Set length of lock stitches (mm).'),
+ type='float',
+ unit="mm",
+ default=0.7,
+ select_items=[('lock_end', lock.id) for lock in LOCK_DEFAULTS['end'] if isinstance(lock, (AbsoluteLock, CustomLock))],
+ sort_index=57)
+ def lock_end_scale_mm(self):
+ return self.get_float_param('lock_end_scale_mm', 0.7)
+
+ @property
+ @param('lock_end_scale_percent',
+ _('Scale lock stitch'),
+ tooltip=_('Scale lock stitch by this percentage.'),
+ type='float',
+ unit="%",
+ default=100,
+ select_items=[('lock_end', lock.id) for lock in LOCK_DEFAULTS['end'] if isinstance(lock, (SVGLock, CustomLock))],
+ sort_index=57)
+ @cache
+ def lock_end_scale_percent(self):
+ return self.get_float_param('lock_end_scale_percent', 100)
+
+ @property
+ @param('trim_after',
+ _('Trim After'),
+ tooltip=_('Add a TRIM command after stitching this object.'),
+ type='boolean',
+ default=False,
+ sort_index=60)
+ def trim_after(self):
+ return self.get_boolean_param('trim_after', False)
+
+ @property
+ @param('stop_after',
+ _('Stop After'),
+ tooltip=_('Add a STOP command after stitching this object.'),
+ type='boolean',
+ default=False,
+ sort_index=60)
+ def stop_after(self):
+ return self.get_boolean_param('stop_after', False)
+
+ @property
@param('random_seed',
_('Random seed'),
tooltip=_('Use a specific seed for randomized attributes. Uses the element ID if empty.'),
@@ -314,7 +429,7 @@ class EmbroideryElement(object):
if not d:
self.fatal(_("Object %(id)s has an empty 'd' attribute. Please delete this object from your document.") % dict(id=self.node.get("id")))
- return inkex.paths.Path(d).to_superpath()
+ return inkex.Path(d).to_superpath()
@cache
def parse_path(self):
@@ -369,24 +484,26 @@ class EmbroideryElement(object):
return self.strip_control_points(path[0])
@property
- @param('trim_after',
- _('Trim After'),
- tooltip=_('Add a TRIM command after stitching this object.'),
- type='boolean',
- default=False,
- sort_index=52)
- def trim_after(self):
- return self.get_boolean_param('trim_after', False)
+ @cache
+ def lock_stitches(self):
+ lock_start = None
+ lock_end = None
- @property
- @param('stop_after',
- _('Stop After'),
- tooltip=_('Add a STOP command after stitching this object.'),
- type='boolean',
- default=False,
- sort_index=53)
- def stop_after(self):
- return self.get_boolean_param('stop_after', False)
+ # Ties: 0 = Both | 1 = Before | 2 = After | 3 = Neither
+ tie_modus = self.ties
+ force = self.force_lock_stitches
+
+ if tie_modus in [0, 1]:
+ lock_start = LockStitch('start', self.lock_start, scale_percent=self.lock_start_scale_percent, scale_absolute=self.lock_start_scale_mm)
+ if self.lock_start == "custom":
+ lock_start.path = self.lock_custom_start
+
+ if tie_modus in [0, 2] or force:
+ lock_end = LockStitch('end', self.lock_end, scale_percent=self.lock_end_scale_percent, scale_absolute=self.lock_end_scale_mm)
+ if self.lock_end == "custom":
+ lock_end.path = self.lock_custom_end
+
+ return lock_start, lock_end
def to_stitch_groups(self, last_patch):
raise NotImplementedError("%s must implement to_stitch_groups()" % self.__class__.__name__)
@@ -477,10 +594,6 @@ class EmbroideryElement(object):
stitch_groups = self.to_stitch_groups(last_stitch_group)
apply_patterns(stitch_groups, self.node)
- for stitch_group in stitch_groups:
- stitch_group.tie_modus = self.ties
- stitch_group.force_lock_stitches = self.force_lock_stitches
-
if stitch_groups:
stitch_groups[-1].trim_after = self.has_command("trim") or self.trim_after
stitch_groups[-1].stop_after = self.has_command("stop") or self.stop_after
diff --git a/lib/elements/fill_stitch.py b/lib/elements/fill_stitch.py
index 1897c8bf..8eb12af2 100644
--- a/lib/elements/fill_stitch.py
+++ b/lib/elements/fill_stitch.py
@@ -673,7 +673,10 @@ class FillStitch(EmbroideryElement):
self.flip,
self.staggers,
self.skip_last)
- return [StitchGroup(stitches=stitch_list, color=self.color) for stitch_list in stitch_lists]
+ return [StitchGroup(stitches=stitch_list,
+ color=self.color,
+ force_lock_stitches=self.force_lock_stitches,
+ lock_stitches=self.lock_stitches) for stitch_list in stitch_lists]
def do_underlay(self, shape, starting_point):
stitch_groups = []
@@ -681,6 +684,7 @@ class FillStitch(EmbroideryElement):
underlay = StitchGroup(
color=self.color,
tags=("auto_fill", "auto_fill_underlay"),
+ lock_stitches=self.lock_stitches,
stitches=auto_fill(
shape,
self.fill_underlay_angle[i],
@@ -702,6 +706,8 @@ class FillStitch(EmbroideryElement):
stitch_group = StitchGroup(
color=self.color,
tags=("auto_fill", "auto_fill_top"),
+ force_lock_stitches=self.force_lock_stitches,
+ lock_stitches=self.lock_stitches,
stitches=auto_fill(
shape,
self.angle,
@@ -755,7 +761,9 @@ class FillStitch(EmbroideryElement):
stitch_group = StitchGroup(
color=self.color,
tags=("auto_fill", "auto_fill_top"),
- stitches=stitches)
+ stitches=stitches,
+ force_lock_stitches=self.force_lock_stitches,
+ lock_stitches=self.lock_stitches,)
stitch_groups.append(stitch_group)
return stitch_groups
@@ -770,6 +778,8 @@ class FillStitch(EmbroideryElement):
stitch_group = StitchGroup(
color=self.color,
tags=("guided_fill", "auto_fill_top"),
+ force_lock_stitches=self.force_lock_stitches,
+ lock_stitches=self.lock_stitches,
stitches=guided_fill(
shape,
guide_line.geoms[0],
diff --git a/lib/elements/polyline.py b/lib/elements/polyline.py
index 5086c705..a33b75de 100644
--- a/lib/elements/polyline.py
+++ b/lib/elements/polyline.py
@@ -6,12 +6,12 @@
from inkex import Path
from shapely import geometry as shgeo
-from .element import EmbroideryElement, param
-from .validation import ValidationWarning
from ..i18n import _
from ..stitch_plan import StitchGroup
from ..utils import cache
from ..utils.geometry import Point
+from .element import EmbroideryElement, param
+from .validation import ValidationWarning
class PolylineWarning(ValidationWarning):
@@ -95,7 +95,7 @@ class Polyline(EmbroideryElement):
yield PolylineWarning(self.path[0][0][0])
def to_stitch_groups(self, last_patch):
- patch = StitchGroup(color=self.color)
+ patch = StitchGroup(color=self.color, lock_stitches=(None, None))
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 eba63c6c..b5086171 100644
--- a/lib/elements/satin_column.py
+++ b/lib/elements/satin_column.py
@@ -3,10 +3,10 @@
# Copyright (c) 2010 Authors
# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
-from copy import deepcopy
import itertools
-from itertools import chain
import typing
+from copy import deepcopy
+from itertools import chain
import numpy as np
from inkex import paths
@@ -16,10 +16,10 @@ from shapely.ops import nearest_points
from ..i18n import _
from ..stitch_plan import StitchGroup
+from ..stitches import running_stitch
from ..svg import line_strings_to_csp, point_lists_to_csp
from ..utils import Point, cache, cut, cut_multiple, prng
-from ..stitches import running_stitch
-from .element import EmbroideryElement, param, PIXELS_PER_MM
+from .element import PIXELS_PER_MM, EmbroideryElement, param
from .validation import ValidationError, ValidationWarning
from ..utils.threading import check_stop_flag
@@ -1092,7 +1092,9 @@ class SatinColumn(EmbroideryElement):
# beziers. The boundary points between beziers serve as "checkpoints",
# allowing the user to control how the zigzags flow around corners.
- patch = StitchGroup(color=self.color)
+ patch = StitchGroup(color=self.color,
+ force_lock_stitches=self.force_lock_stitches,
+ lock_stitches=self.lock_stitches)
if self.center_walk_underlay:
patch += self.do_center_walk()
diff --git a/lib/elements/stroke.py b/lib/elements/stroke.py
index 6aca3847..c633a2c6 100644
--- a/lib/elements/stroke.py
+++ b/lib/elements/stroke.py
@@ -6,19 +6,18 @@
import sys
import shapely.geometry
-
from inkex import Transform
from ..i18n import _
from ..marker import get_marker_elements
from ..stitch_plan import StitchGroup
-from ..stitches.running_stitch import bean_stitch, running_stitch
from ..stitches.ripple_stitch import ripple_stitch
+from ..stitches.running_stitch import bean_stitch, running_stitch
from ..svg import get_node_transform, parse_length_with_units
+from ..threads import ThreadColor
from ..utils import Point, cache
from .element import EmbroideryElement, param
from .validation import ValidationWarning
-from ..threads import ThreadColor
warned_about_legacy_running_stitch = False
@@ -445,13 +444,15 @@ class Stroke(EmbroideryElement):
repeated_stitches.extend(this_path)
- return StitchGroup(self.color, repeated_stitches)
+ return StitchGroup(self.color, repeated_stitches, lock_stitches=self.lock_stitches, force_lock_stitches=self.force_lock_stitches)
def ripple_stitch(self):
return StitchGroup(
color=self.color,
tags=["ripple_stitch"],
- stitches=ripple_stitch(self))
+ stitches=ripple_stitch(self),
+ lock_stitches=self.lock_stitches,
+ force_lock_stitches=self.force_lock_stitches)
def do_bean_repeats(self, stitches):
return bean_stitch(stitches, self.bean_stitch_repeats)
@@ -471,7 +472,7 @@ class Stroke(EmbroideryElement):
path = [Point(x, y) for x, y in path]
# manual stitch
if self.manual_stitch_mode:
- patch = StitchGroup(color=self.color, stitches=path, stitch_as_is=True)
+ patch = StitchGroup(color=self.color, stitches=path, lock_stitches=(None, None))
# running stitch
elif self.is_running_stitch():
patch = self.running_stitch(path, self.running_stitch_length, self.running_stitch_tolerance)