diff options
| author | Kaalleen <36401965+kaalleen@users.noreply.github.com> | 2024-12-26 16:19:35 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-12-26 16:19:35 +0100 |
| commit | ef7d056173cc6d7782d6120c031dae9276725a3d (patch) | |
| tree | 75d2ef67976336a93424b504e42bbf1a394b9a49 /lib/elements | |
| parent | e20161a4ec9a69cb0f1bdfdd16bcd27a8601fde7 (diff) | |
End points (#3370)
* end at nearest point to next element (if requested and possible)
Diffstat (limited to 'lib/elements')
| -rw-r--r-- | lib/elements/clone.py | 44 | ||||
| -rw-r--r-- | lib/elements/element.py | 71 | ||||
| -rw-r--r-- | lib/elements/empty_d_object.py | 6 | ||||
| -rw-r--r-- | lib/elements/fill_stitch.py | 25 | ||||
| -rw-r--r-- | lib/elements/marker.py | 2 | ||||
| -rw-r--r-- | lib/elements/satin_column.py | 104 | ||||
| -rw-r--r-- | lib/elements/stroke.py | 13 | ||||
| -rw-r--r-- | lib/elements/text.py | 4 |
8 files changed, 196 insertions, 73 deletions
diff --git a/lib/elements/clone.py b/lib/elements/clone.py index 770fcc0c..0db8bf4c 100644 --- a/lib/elements/clone.py +++ b/lib/elements/clone.py @@ -35,7 +35,8 @@ class CloneWarning(ValidationWarning): class Clone(EmbroideryElement): - element_name = "Clone" + name = "Clone" + element_name = _("Clone") def __init__(self, *args, **kwargs): super(Clone, self).__init__(*args, **kwargs) @@ -66,10 +67,10 @@ class Clone(EmbroideryElement): def flip_angle(self): return self.get_boolean_param('flip_angle', False) - def get_cache_key_data(self, previous_stitch): + def get_cache_key_data(self, previous_stitch, next_element): source_node = self.node.href source_elements = self.clone_to_elements(source_node) - return [element.get_cache_key(previous_stitch) for element in source_elements] + return [element.get_cache_key(previous_stitch, next_element) for element in source_elements] def clone_to_elements(self, node) -> List[EmbroideryElement]: # Only used in get_cache_key_data, actual embroidery uses nodes_to_elements+iterate_nodes @@ -82,22 +83,53 @@ class Clone(EmbroideryElement): elements.extend(node_to_elements(child, True)) return elements - def to_stitch_groups(self, last_stitch_group=None) -> List[StitchGroup]: + def to_stitch_groups(self, last_stitch_group=None, next_element=None) -> List[StitchGroup]: if not self.clone: return [] with self.clone_elements() as elements: + if not elements: + return [] stitch_groups = [] - for element in elements: + next_elements = [next_element] + if len(elements) > 1: + next_elements = elements[1:] + next_elements + for element, next_element in zip(elements, next_elements): # Using `embroider` here to get trim/stop after commands, etc. - element_stitch_groups = element.embroider(last_stitch_group) + element_stitch_groups = element.embroider(last_stitch_group, next_element) if len(element_stitch_groups): last_stitch_group = element_stitch_groups[-1] stitch_groups.extend(element_stitch_groups) return stitch_groups + @property + def first_stitch(self): + first, last = self.first_and_last_element() + if first: + return first.first_stitch + return None + + def uses_previous_stitch(self): + first, last = self.first_and_last_element() + if first: + return first.uses_previous_stitch() + return None + + def uses_next_element(self): + first, last = self.first_and_last_element() + if last: + return last.uses_next_element() + return None + + @cache + def first_and_last_element(self): + with self.clone_elements() as elements: + if len(elements): + return elements[0], elements[-1] + return None, None + @contextmanager def clone_elements(self) -> Generator[List[EmbroideryElement], None, None]: """ diff --git a/lib/elements/element.py b/lib/elements/element.py index ac5cf51f..0846b7ab 100644 --- a/lib/elements/element.py +++ b/lib/elements/element.py @@ -5,26 +5,29 @@ import sys from contextlib import contextmanager from copy import deepcopy +from typing import List, Optional import inkex import numpy as np -from inkex import bezier, BaseElement -from typing import List, Optional +from inkex import BaseElement, bezier +from shapely import Point as ShapelyPoint +from shapely.ops import nearest_points from ..commands import Command, find_commands -from ..stitch_plan import StitchGroup from ..debug.debug import debug from ..exceptions import InkstitchException, format_uncaught_exception 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 import StitchGroup 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 from ..utils import Point, cache -from ..utils.cache import get_stitch_plan_cache, is_cache_disabled, CacheKeyGenerator +from ..utils.cache import (CacheKeyGenerator, get_stitch_plan_cache, + is_cache_disabled) class Param(object): @@ -437,6 +440,12 @@ class EmbroideryElement(object): raise NotImplementedError("INTERNAL ERROR: %s must implement shape()", self.__class__) @property + def first_stitch(self): + # first stitch is an approximation to where the first stitch may possibly be + # if not defined through commands or repositioned by the previous element + raise NotImplementedError("INTERNAL ERROR: %s must implement first_stitch()", self.__class__) + + @property @cache def commands(self) -> List[Command]: return find_commands(self.node) @@ -497,11 +506,11 @@ class EmbroideryElement(object): return lock_start, lock_end - def to_stitch_groups(self, last_stitch_group: Optional[StitchGroup]) -> List[StitchGroup]: + def to_stitch_groups(self, last_stitch_group: Optional[StitchGroup], next_element: Optional[ShapelyPoint] = None) -> List[StitchGroup]: raise NotImplementedError("%s must implement to_stitch_groups()" % self.__class__.__name__) @debug.time - def _load_cached_stitch_groups(self, previous_stitch): + def _load_cached_stitch_groups(self, previous_stitch, next_element): if is_cache_disabled(): return None @@ -509,7 +518,7 @@ class EmbroideryElement(object): # we don't care about the previous stitch previous_stitch = None - cache_key = self.get_cache_key(previous_stitch) + cache_key = self.get_cache_key(previous_stitch, next_element) stitch_groups = get_stitch_plan_cache().get(cache_key) if stitch_groups: @@ -526,20 +535,27 @@ class EmbroideryElement(object): """ return False + def uses_next_element(self) -> bool: + """Returns True if the shape of the next element can affect this Element's stitches. + + This function may be overridden in a subclass. + """ + return False + @debug.time - def _save_cached_stitch_groups(self, stitch_groups, previous_stitch): + def _save_cached_stitch_groups(self, stitch_groups, previous_stitch, next_element): if is_cache_disabled(): return stitch_plan_cache = get_stitch_plan_cache() - cache_key = self.get_cache_key(previous_stitch) + cache_key = self.get_cache_key(previous_stitch, next_element) if cache_key not in stitch_plan_cache: stitch_plan_cache[cache_key] = stitch_groups if previous_stitch is not None: # Also store it with None as the previous stitch, so that it can be used next time # if we don't care about the previous stitch - cache_key = self.get_cache_key(None) + cache_key = self.get_cache_key(None, None) if cache_key not in stitch_plan_cache: stitch_plan_cache[cache_key] = stitch_groups @@ -569,10 +585,10 @@ class EmbroideryElement(object): def _get_tartan_key_data(self): return (self.node.get('inkstitch:tartan', None)) - def get_cache_key_data(self, previous_stitch): + def get_cache_key_data(self, previous_stitch, next_element): return [] - def get_cache_key(self, previous_stitch): + def get_cache_key(self, previous_stitch, next_element): cache_key_generator = CacheKeyGenerator() cache_key_generator.update(self.__class__.__name__) cache_key_generator.update(self.get_params_and_values()) @@ -580,18 +596,20 @@ class EmbroideryElement(object): cache_key_generator.update(list(self._get_specified_style().items())) cache_key_generator.update(self._get_gradient_cache_key_data()) cache_key_generator.update(previous_stitch) + if next_element is not None: + cache_key_generator.update(next_element.get_cache_key(None, None)) cache_key_generator.update([(c.command, c.target_point) for c in self.commands]) cache_key_generator.update(self._get_patterns_cache_key_data()) cache_key_generator.update(self._get_guides_cache_key_data()) - cache_key_generator.update(self.get_cache_key_data(previous_stitch)) + cache_key_generator.update(self.get_cache_key_data(previous_stitch, next_element)) cache_key_generator.update(self._get_tartan_key_data()) cache_key = cache_key_generator.get_cache_key() - debug.log(f"cache key for {self.node.get('id')} {self.node.get(INKSCAPE_LABEL)} {previous_stitch}: {cache_key}") + debug.log(f"cache key for {self.node.get('id')} {self.node.get(INKSCAPE_LABEL)} {previous_stitch} {next_element}: {cache_key}") return cache_key - def embroider(self, last_stitch_group: Optional[StitchGroup]) -> List[StitchGroup]: + def embroider(self, last_stitch_group: Optional[StitchGroup], next_element=None) -> List[StitchGroup]: debug.log(f"starting {self.node.get('id')} {self.node.get(INKSCAPE_LABEL)}") with self.handle_unexpected_exceptions(): @@ -599,12 +617,13 @@ class EmbroideryElement(object): previous_stitch = last_stitch_group.stitches[-1] else: previous_stitch = None - stitch_groups = self._load_cached_stitch_groups(previous_stitch) + + stitch_groups = self._load_cached_stitch_groups(previous_stitch, next_element) if not stitch_groups: self.validate() - stitch_groups = self.to_stitch_groups(last_stitch_group) + stitch_groups = self.to_stitch_groups(last_stitch_group, next_element) apply_patterns(stitch_groups, self.node) if stitch_groups: @@ -617,11 +636,27 @@ class EmbroideryElement(object): stitch_group.min_jump_stitch_length = self.min_jump_stitch_length stitch_group.set_minimum_stitch_length(self.min_stitch_length) - self._save_cached_stitch_groups(stitch_groups, previous_stitch) + self._save_cached_stitch_groups(stitch_groups, previous_stitch, next_element) debug.log(f"ending {self.node.get('id')} {self.node.get(INKSCAPE_LABEL)}") return stitch_groups + def next_stitch(self, next_element): + next_stitch = None + if next_element is not None and self.uses_next_element(): + # in fact we really only try an approximation to the next stitch + if next_element.uses_previous_stitch(): + try: + next_stitch = nearest_points(next_element.shape, self.shape)[1] + except (ValueError, AttributeError): + pass + else: + try: + next_stitch = nearest_points(next_element.first_stitch, self.shape)[1] + except (ValueError, AttributeError): + pass + return next_stitch + def fatal(self, message, point_to_troubleshoot=False): label = self.node.get(INKSCAPE_LABEL) id = self.node.get("id") diff --git a/lib/elements/empty_d_object.py b/lib/elements/empty_d_object.py index c2e56eac..ca31a35c 100644 --- a/lib/elements/empty_d_object.py +++ b/lib/elements/empty_d_object.py @@ -27,5 +27,9 @@ class EmptyDObject(EmbroideryElement): def shape(self): return - def to_stitch_groups(self, last_stitch_group): + @property + def first_stitch(self): + return + + def to_stitch_groups(self, last_stitch_group, next_element=None): return [] diff --git a/lib/elements/fill_stitch.py b/lib/elements/fill_stitch.py index 9b330947..07466303 100644 --- a/lib/elements/fill_stitch.py +++ b/lib/elements/fill_stitch.py @@ -143,6 +143,7 @@ class InvalidShapeError(ValidationError): class FillStitch(EmbroideryElement): + name = "FillStitch" element_name = _("FillStitch") @property @@ -890,6 +891,12 @@ class FillStitch(EmbroideryElement): def fill_shape(self, shape): return self.shrink_or_grow_shape(shape, self.expand) + @property + def first_stitch(self): + # Serves as a reverence point for the end point of the previous element + # This isn't really used for fill stitches as they always make their first stitch point dependent on the previous element itself + return None + def get_starting_point(self, previous_stitch_group): # If there is a "starting_point" Command, then use that; otherwise pick # the point closest to the end of the last stitch_group. @@ -901,19 +908,27 @@ class FillStitch(EmbroideryElement): else: return None + def get_ending_point(self, next_stitch): + if self.get_command('ending_point'): + return self.get_command('ending_point').target_point + elif next_stitch: + return next_stitch.coords + else: + return None + def uses_previous_stitch(self): if self.get_command('starting_point'): return False else: return True - def get_ending_point(self): + def uses_next_element(self): if self.get_command('ending_point'): - return self.get_command('ending_point').target_point + return False else: - return None + return True - def to_stitch_groups(self, previous_stitch_group): # noqa: C901 + def to_stitch_groups(self, previous_stitch_group, next_element=None): # noqa: C901 # backwards compatibility: legacy_fill used to be inkstitch:auto_fill == False if not self.auto_fill or self.fill_method == 'legacy_fill': return self.do_legacy_fill() @@ -922,7 +937,7 @@ class FillStitch(EmbroideryElement): # start and end points start = self.get_starting_point(previous_stitch_group) - final_end = self.get_ending_point() + final_end = self.get_ending_point(self.next_stitch(next_element)) # sort shapes to get a nicer routing shapes = list(self.shape.geoms) diff --git a/lib/elements/marker.py b/lib/elements/marker.py index 7085d31f..49f9110e 100644 --- a/lib/elements/marker.py +++ b/lib/elements/marker.py @@ -28,5 +28,5 @@ class MarkerObject(EmbroideryElement): repr_point = next(inkex.Path(self.parse_path()).end_points) yield MarkerWarning(repr_point) - def to_stitch_groups(self, last_stitch_group): + def to_stitch_groups(self, last_stitch_group, next_element=None): return [] diff --git a/lib/elements/satin_column.py b/lib/elements/satin_column.py index 71beba6a..597b7dc6 100644 --- a/lib/elements/satin_column.py +++ b/lib/elements/satin_column.py @@ -98,6 +98,7 @@ class UnequalPointsWarning(ValidationWarning): class SatinColumn(EmbroideryElement): + name = "SatinColumn" element_name = _("Satin Column") def __init__(self, *args, **kwargs): @@ -399,6 +400,14 @@ class SatinColumn(EmbroideryElement): return self.get_boolean_param('start_at_nearest_point') @property + @param('end_at_nearest_point', + _('End at nearest point'), + tooltip=_('End at nearest point to the next element. An end position command will overwrite this setting.'), + default=False, type='boolean', sort_index=24) + def end_at_nearest_point(self): + return self.get_boolean_param('end_at_nearest_point') + + @property @param('contour_underlay', _('Contour underlay'), type='toggle', group=_('Contour Underlay')) def contour_underlay(self): # "Contour underlay" is stitching just inside the rectangular shape @@ -1282,23 +1291,23 @@ class SatinColumn(EmbroideryElement): stitch_group.add_tags(("satin_column", "satin_column_underlay")) return stitch_group - def do_end_path(self): + def do_end_path(self, end_point): return StitchGroup( color=self.color, tags=("satin_column",), - stitches=[Point(*self.end_point)] + stitches=[Point(*end_point)] ) - def _do_underlay_stitch_groups(self): + def _do_underlay_stitch_groups(self, end_point): stitch_groups = [] if self.center_walk_underlay: - stitch_groups.extend(self.do_center_walk()) + stitch_groups.extend(self.do_center_walk(end_point)) if self.contour_underlay: - stitch_groups.extend(self.do_contour_underlay()) + stitch_groups.extend(self.do_contour_underlay(end_point)) if self.zigzag_underlay: - stitch_groups.extend(self.do_zigzag_underlay()) + stitch_groups.extend(self.do_zigzag_underlay(end_point)) return stitch_groups @@ -1311,7 +1320,7 @@ class SatinColumn(EmbroideryElement): stitches=[Stitch(*coord) for coord in linestring.coords] ) - def do_contour_underlay(self): + def do_contour_underlay(self, end_point): # "contour walk" underlay: do stitches up one side and down the # other. if the two sides are far away, adding a running stitch to travel # in between avoids a long jump or a trim. @@ -1336,7 +1345,7 @@ class SatinColumn(EmbroideryElement): else: second_side.reverse() - if self.end_point: + if end_point: stitch_groups = [] tags = ("satin_column", "satin_column_underlay", "satin_contour_underlay") first_linestring = shgeo.LineString(first_side) @@ -1359,14 +1368,14 @@ class SatinColumn(EmbroideryElement): stitch_group.stitches += second_side return [stitch_group] - def do_center_walk(self): + def do_center_walk(self, end_point): # Center walk underlay is just a running stitch down and back on the # center line between the bezier curves. repeats = self.center_walk_underlay_repeats stitch_groups = [] stitches = self._get_center_line_stitches(self.center_walk_underlay_position) - if self.end_point: + if end_point: tags = ("satin_column", "satin_column_underlay", "satin_center_walk") stitches = shgeo.LineString(stitches) start, end = self._split_linestring_at_end_point(stitches) @@ -1391,7 +1400,7 @@ class SatinColumn(EmbroideryElement): stitch_group.stitches += stitch_group.stitches[:stitch_count] return stitch_groups - def do_zigzag_underlay(self): + def do_zigzag_underlay(self, end_point): # zigzag underlay, usually done at a much lower density than the # satin itself. It looks like this: # @@ -1418,7 +1427,7 @@ class SatinColumn(EmbroideryElement): start_groups = [] end_groups = [] for points in point_groups: - if not self.end_point: + if not end_point: stitch_groups.append(self._generate_zigzag_stitch_group(points)) continue zigzag_line = shgeo.LineString(points) @@ -1456,21 +1465,19 @@ class SatinColumn(EmbroideryElement): else: stitch_group = self.do_satin() - if self.end_point: - return self._split_top_layer(stitch_group) - return [stitch_group] + return stitch_group - def _split_linestring_at_end_point(self, linestring): - split_line = shgeo.LineString(self.find_cut_points(self.end_point)) + def _split_linestring_at_end_point(self, linestring, end_point): + split_line = shgeo.LineString(self.find_cut_points(end_point)) split_point = nearest_points(linestring, split_line)[0] project = linestring.project(split_point) start = substring(linestring, 0, project) end = substring(linestring, project, linestring.length) return start, end - def _split_top_layer(self, stitch_group): + def _split_top_layer(self, stitch_group, end_point): top_layer = shgeo.LineString(stitch_group.stitches) - start, end = self._split_linestring_at_end_point(top_layer) + start, end = self._split_linestring_at_end_point(top_layer, end_point) stitch_group2 = deepcopy(stitch_group) stitch_group2.stitches = [Stitch(*point) for point in end.reverse().coords] stitch_group1 = stitch_group @@ -1793,12 +1800,34 @@ class SatinColumn(EmbroideryElement): return stitch_group @property - def start_point(self): - return self._get_command_point('starting_point') + def first_stitch(self): + return shgeo.Point(self.flattened_rails[0].coords[0]) - @property - def end_point(self): - return self._get_command_point('ending_point') + def start_point(self, last_stitch_group): + start_point = self._get_command_point('starting_point') + if start_point is None and self.start_at_nearest_point and last_stitch_group is not None: + start_point = nearest_points(shgeo.Point(*last_stitch_group.stitches[-1]), self.center_line)[1] + start_point = Point(*list(start_point.coords[0])) + return start_point + + def end_point(self, next_stitch): + end_point = self._get_command_point('ending_point') + if end_point is None and self.end_at_nearest_point and next_stitch is not None: + end_point = nearest_points(next_stitch, self.center_line)[1] + end_point = Point(*list(end_point.coords[0])) + return end_point + + def uses_previous_stitch(self): + if not self.start_at_nearest_point or self.get_command('starting_point'): + return False + else: + return True + + def uses_next_element(self): + if not self.end_at_nearest_point or self.get_command('ending_point'): + return False + else: + return True def _get_command_point(self, command): point = self.get_command(command) @@ -1806,8 +1835,8 @@ class SatinColumn(EmbroideryElement): point = point.target_point return point - def _sort_stitch_groups(self, stitch_groups): - if self.end_point: + def _sort_stitch_groups(self, stitch_groups, end_point): + if end_point: ordered_stitch_groups = [] ordered_stitch_groups.extend(stitch_groups[::2]) ordered_stitch_groups.append(self._connect_stitch_group_with_point(stitch_groups[1], ordered_stitch_groups[-1].stitches[-1], True)) @@ -1815,33 +1844,34 @@ class SatinColumn(EmbroideryElement): return ordered_stitch_groups return stitch_groups - def to_stitch_groups(self, last_stitch_group=None): + def to_stitch_groups(self, last_stitch_group=None, next_element=None): # Stitch a variable-width satin column, zig-zagging between two paths. # The algorithm will draw zigzags between each consecutive pair of # beziers. The boundary points between beziers serve as "checkpoints", # allowing the user to control how the zigzags flow around corners. + start_point = self.start_point(last_stitch_group) + end_point = self.end_point(self.next_stitch(next_element)) stitch_groups = [] - start_point = self.start_point - if start_point is None and last_stitch_group is not None and self.start_at_nearest_point: - start_point = nearest_points(shgeo.Point(*last_stitch_group.stitches[-1]), self.center_line)[1] - start_point = Point(*list(start_point.coords[0])) - # underlays - stitch_groups.extend(self._do_underlay_stitch_groups()) + stitch_groups.extend(self._do_underlay_stitch_groups(end_point)) # top layer - stitch_groups.extend(self._do_top_layer_stitch_group()) + top_layer_group = self._do_top_layer_stitch_group() + if end_point: + stitch_groups.extend(self._split_top_layer(top_layer_group, end_point)) + else: + stitch_groups.append(top_layer_group) # order stitch groups - stitch_groups = self._sort_stitch_groups(stitch_groups) + stitch_groups = self._sort_stitch_groups(stitch_groups, end_point) # start and end if start_point is not None: stitch_groups = [self._connect_stitch_group_with_point(stitch_groups[0], start_point)] + stitch_groups - if self.end_point: - stitch_groups.append(self.do_end_path()) + if end_point: + stitch_groups.append(self.do_end_path(end_point)) # assemble stitch groups stitch_group = StitchGroup( diff --git a/lib/elements/stroke.py b/lib/elements/stroke.py index ff9718c5..5c6a0b08 100644 --- a/lib/elements/stroke.py +++ b/lib/elements/stroke.py @@ -13,11 +13,13 @@ from ..i18n import _ from ..marker import get_marker_elements from ..stitch_plan import StitchGroup from ..stitches.ripple_stitch import ripple_stitch -from ..stitches.running_stitch import (bean_stitch, running_stitch, zigzag_stitch) +from ..stitches.running_stitch import (bean_stitch, running_stitch, + zigzag_stitch) from ..svg import get_node_transform, parse_length_with_units from ..svg.clip import get_clip_path from ..threads import ThreadColor from ..utils import Point, cache +from ..utils.geometry import ensure_multi_line_string from ..utils.param import ParamOption from .element import EmbroideryElement, param from .validation import ValidationWarning @@ -41,6 +43,7 @@ class TooFewSubpathsWarning(ValidationWarning): class Stroke(EmbroideryElement): + name = "Stroke" element_name = _("Stroke") @property @@ -483,13 +486,17 @@ class Stroke(EmbroideryElement): @property @cache def shape(self): - return self.as_multi_line_string().convex_hull + return ensure_multi_line_string(self.as_multi_line_string().convex_hull) @cache def as_multi_line_string(self): line_strings = [shgeo.LineString(path) for path in self.paths] return shgeo.MultiLineString(line_strings) + @property + def first_stitch(self): + return shgeo.Point(self.as_multi_line_string().geoms[0].coords[0]) + def _get_clipped_path(self, paths): clip_path = get_clip_path(self.node) if clip_path is None: @@ -583,7 +590,7 @@ class Stroke(EmbroideryElement): def do_bean_repeats(self, stitches): return bean_stitch(stitches, self.bean_stitch_repeats) - def to_stitch_groups(self, last_stitch_group): # noqa: C901 + def to_stitch_groups(self, last_stitch_group, next_element=None): # noqa: C901 stitch_groups = [] # ripple stitch diff --git a/lib/elements/text.py b/lib/elements/text.py index 4203c8f9..37a38bc8 100644 --- a/lib/elements/text.py +++ b/lib/elements/text.py @@ -4,9 +4,9 @@ # Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details. from ..i18n import _ +from ..svg.path import get_node_transform from .element import EmbroideryElement from .validation import ObjectTypeWarning -from ..svg.path import get_node_transform class TextTypeWarning(ObjectTypeWarning): @@ -29,5 +29,5 @@ class TextObject(EmbroideryElement): def validation_warnings(self): yield TextTypeWarning(self.pointer()) - def to_stitch_groups(self, last_stitch_group): + def to_stitch_groups(self, last_stitch_group, next_element=None): return [] |
