diff options
| author | Lex Neva <github.com@lexneva.name> | 2019-02-25 19:49:38 -0500 |
|---|---|---|
| committer | Lex Neva <github.com@lexneva.name> | 2019-03-08 19:57:11 -0500 |
| commit | 53a9bd6b31ca3a1f50d41f228e0b598a7d9da8ea (patch) | |
| tree | 3a25ae8a48ef01d749d60fe071ed5509f5472fd7 | |
| parent | 4ba3cd708561870a731d9634d9cdd5c18579cac7 (diff) | |
add trims in stitches.auto_satin
| -rw-r--r-- | lib/extensions/auto_satin.py | 52 | ||||
| -rw-r--r-- | lib/stitches/auto_satin.py | 115 | ||||
| -rw-r--r-- | lib/svg/svg.py | 5 |
3 files changed, 116 insertions, 56 deletions
diff --git a/lib/extensions/auto_satin.py b/lib/extensions/auto_satin.py index 90d8fe33..12588d1e 100644 --- a/lib/extensions/auto_satin.py +++ b/lib/extensions/auto_satin.py @@ -38,22 +38,6 @@ class AutoSatin(CommandsExtension): if command is not None: return command.target_point - def effect(self): - if not self.check_selection(): - return - - if self.options.preserve_order: - # when preservering order, auto_satin() takes care of putting the - # newly-created elements into the existing group nodes in the SVG - # DOM - new_elements, trim_indices = self.auto_satin() - else: - group = self.create_group() - new_elements, trim_indices = self.auto_satin() - self.add_elements(group, new_elements) - - self.add_trims(new_elements, trim_indices) - def check_selection(self): if not self.get_elements(): return @@ -65,38 +49,10 @@ class AutoSatin(CommandsExtension): return True - def create_group(self): - first = self.elements[0].node - parent = first.getparent() - insert_index = parent.index(first) - group = inkex.etree.Element(SVG_GROUP_TAG, { - "transform": get_correction_transform(parent, child=True) - }) - parent.insert(insert_index, group) - - return group + def effect(self): + if not self.check_selection(): + return - def auto_satin(self): starting_point = self.get_starting_point() ending_point = self.get_ending_point() - return auto_satin(self.elements, self.options.preserve_order, starting_point, ending_point) - - def add_elements(self, group, new_elements): - for i, element in enumerate(new_elements): - if isinstance(element, SatinColumn): - element.node.set("id", self.uniqueId("autosatin")) - - # L10N Label for a satin column created by Auto-Route Satin Columns extension - element.node.set(INKSCAPE_LABEL, _("AutoSatin %d") % (i + 1)) - else: - element.node.set("id", self.uniqueId("autosatinrun")) - - # L10N Label for running stitch (underpathing) created by Auto-Route Satin Columns extension - element.node.set(INKSCAPE_LABEL, _("AutoSatin Running Stitch %d") % (i + 1)) - - group.append(element.node) - - def add_trims(self, new_elements, trim_indices): - if self.options.trim and trim_indices: - for i in trim_indices: - add_commands(new_elements[i], ["trim"]) + auto_satin(self.elements, self.options.preserve_order, starting_point, ending_point, self.options.trim) diff --git a/lib/stitches/auto_satin.py b/lib/stitches/auto_satin.py index e204a445..aea26427 100644 --- a/lib/stitches/auto_satin.py +++ b/lib/stitches/auto_satin.py @@ -9,9 +9,11 @@ import simplestyle import networkx as nx +from ..commands import add_commands from ..elements import Stroke, SatinColumn -from ..svg import PIXELS_PER_MM, line_strings_to_csp, get_correction_transform -from ..svg.tags import SVG_PATH_TAG +from ..i18n import _ +from ..svg import PIXELS_PER_MM, line_strings_to_csp, get_correction_transform, generate_unique_id +from ..svg.tags import SVG_PATH_TAG, SVG_GROUP_TAG, INKSCAPE_LABEL from ..utils import Point as InkstitchPoint, cut, cache @@ -258,7 +260,7 @@ class RunningStitch(object): return RunningStitch(new_path, self.original_element) -def auto_satin(elements, preserve_order=False, starting_point=None, ending_point=None): +def auto_satin(elements, preserve_order=False, starting_point=None, ending_point=None, trim=False): """Find an optimal order to stitch a list of SatinColumns. Add running stitch and jump stitches as necessary to construct a stitch @@ -294,14 +296,20 @@ def auto_satin(elements, preserve_order=False, starting_point=None, ending_point If preserve_order is True, then the elements and any newly-created elements will be in the same position in the SVG DOM. If preserve_order is False, then - the elements will be removed from the SVG DOM and it's up to the caller to - decide where to put the returned SVG path nodes. + the elements will be removed from their current position in SVG DOM and added + to a newly-created group node. - Returns: a list of SVG path nodes making up the selected stitch order. + If trim is True, then Trim commands will be added to avoid jump stitches. + + Returns: a list of Element instances making up the stitching order chosen. Jumps between objects are implied if they are not right next to each other. """ + # save these for create_new_group() call below + parent = elements[0].node.getparent() + index = parent.index(elements[0].node) + graph = build_graph(elements, preserve_order) add_jumps(graph, elements, preserve_order) starting_node, ending_node = get_starting_and_ending_nodes( @@ -310,12 +318,21 @@ def auto_satin(elements, preserve_order=False, starting_point=None, ending_point operations = path_to_operations(graph, path) operations = collapse_sequential_segments(operations) new_elements, trims, original_parents = operations_to_elements_and_trims(operations, preserve_order) + remove_original_elements(elements) if preserve_order: preserve_original_groups(new_elements, original_parents) + else: + group = create_new_group(parent, index) + add_elements_to_group(new_elements, group) + + name_elements(new_elements, preserve_order) - return new_elements, trims + if trim: + new_elements = add_trims(new_elements, trims) + + return new_elements def build_graph(elements, preserve_order=False): @@ -628,3 +645,87 @@ def preserve_original_groups(elements, original_parent_nodes): if parent is not None: parent.append(element.node) element.node.set('transform', get_correction_transform(parent, child=True)) + + +def create_new_group(parent, insert_index): + group = inkex.etree.Element(SVG_GROUP_TAG, { + INKSCAPE_LABEL: _("Auto-Satin"), + "transform": get_correction_transform(parent, child=True) + }) + parent.insert(insert_index, group) + + return group + + +def add_elements_to_group(elements, group): + for element in elements: + group.append(element.node) + + +def name_elements(new_elements, preserve_order): + """Give the newly-created SVG objects useful names. + + Objects will be named like this: + + * AutoSatin 1 + * AutoSatin 2 + * AutoSatin Running Stitch 3 + * AutoSatin 4 + * AutoSatin Running Stitch 5 + ... + + Objects are numbered starting with 1. Satins are named "AutoSatin #", and + running stitches are named "AutoSatin Running Stitch #". + + If preserve_order is true and the element already has an INKSCAPE_LABEL, + we'll leave it alone. That way users can see which original satin the new + satin(s) came from. + + SVG element IDs are also set. Since these need to be unique across the + document, the numbers will likely not match up with the numbers in the + name we set. + """ + + index = 1 + for element in new_elements: + if isinstance(element, SatinColumn): + element.node.set("id", generate_unique_id(element.node, "autosatin")) + else: + element.node.set("id", generate_unique_id(element.node, "autosatinrun")) + + if not (preserve_order and INKSCAPE_LABEL in element.node.attrib): + if isinstance(element, SatinColumn): + # L10N Label for a satin column created by Auto-Route Satin Columns and Lettering extensions + element.node.set(INKSCAPE_LABEL, _("AutoSatin %d") % index) + else: + # L10N Label for running stitch (underpathing) created by Auto-Route Satin Columns amd Lettering extensions + element.node.set(INKSCAPE_LABEL, _("AutoSatin Running Stitch %d") % index) + + index += 1 + + +def add_trims(elements, trim_indices): + """Add trim commands on the specified elements. + + If any running stitches immediately follow a trim, they are eliminated. + When we're trimming, there's no need to try to reduce the jump length, + so the running stitch would be a waste of time (and thread). + """ + + trim_indices = set(trim_indices) + new_elements = [] + just_trimmed = False + for i, element in enumerate(elements): + if just_trimmed and isinstance(element, Stroke): + element.node.getparent().remove(element.node) + continue + + if i in trim_indices: + add_commands(element, ["trim"]) + just_trimmed = True + else: + just_trimmed = False + + new_elements.append(element) + + return new_elements diff --git a/lib/svg/svg.py b/lib/svg/svg.py index 0ec43f75..3715def8 100644 --- a/lib/svg/svg.py +++ b/lib/svg/svg.py @@ -1,3 +1,5 @@ +from inkex import etree + from ..utils import cache @@ -6,7 +8,8 @@ def get_document(node): return node.getroottree().getroot() -def generate_unique_id(document, prefix="path"): +def generate_unique_id(document_or_element, prefix="path"): + document = get_document(document_or_element) doc_ids = {node.get('id') for node in document.iterdescendants() if 'id' in node.attrib} i = 1 |
