From 1adfa87a68be6bcc92d9521b97ab59dc022ab3be Mon Sep 17 00:00:00 2001 From: Kaalleen Date: Tue, 22 Jun 2021 20:04:39 +0200 Subject: satin pattern and split stitch --- templates/apply_satin_pattern.xml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 templates/apply_satin_pattern.xml (limited to 'templates') diff --git a/templates/apply_satin_pattern.xml b/templates/apply_satin_pattern.xml new file mode 100644 index 00000000..e52fb1a4 --- /dev/null +++ b/templates/apply_satin_pattern.xml @@ -0,0 +1,17 @@ + + + {% trans %}Apply Satin Pattern{% endtrans %} + org.inkstitch.apply_satin_pattern.{{ locale }} + apply_satin_pattern + + all + + + + + + + + -- cgit v1.3.1 From c602c4c517cab40dfc2dc7dbc5c29c037cccafae Mon Sep 17 00:00:00 2001 From: Kaalleen Date: Sun, 27 Jun 2021 22:29:57 +0200 Subject: group patterns --- lib/commands.py | 11 ++++- lib/elements/satin_column.py | 10 +++-- lib/elements/utils.py | 4 +- lib/extensions/__init__.py | 2 - lib/extensions/apply_satin_pattern.py | 79 ----------------------------------- lib/extensions/base.py | 9 ++-- symbols/inkstitch.svg | 23 ++++++++++ templates/apply_satin_pattern.xml | 17 -------- 8 files changed, 49 insertions(+), 106 deletions(-) delete mode 100644 lib/extensions/apply_satin_pattern.py delete mode 100644 templates/apply_satin_pattern.xml (limited to 'templates') diff --git a/lib/commands.py b/lib/commands.py index f2ab8c3e..ea6d3509 100644 --- a/lib/commands.py +++ b/lib/commands.py @@ -46,10 +46,12 @@ COMMANDS = { # L10N command attached to an object "satin_cut_point": N_("Satin cut point (use with Cut Satin Column)"), - # L10N command that affects a layer "ignore_layer": N_("Ignore layer (do not stitch any objects in this layer)"), + # L10N command that affects a group + "pattern_group": N_("Strokes in this group will be interpretet as a pattern"), + # L10N command that affects entire document "origin": N_("Origin for exported embroidery files"), @@ -58,6 +60,7 @@ COMMANDS = { } OBJECT_COMMANDS = ["fill_start", "fill_end", "satin_start", "satin_end", "stop", "trim", "ignore_object", "satin_cut_point"] +GROUP_COMMANDS = ["pattern_group"] LAYER_COMMANDS = ["ignore_layer"] GLOBAL_COMMANDS = ["origin", "stop_position"] @@ -184,6 +187,12 @@ def find_commands(node): return commands +def group_commands(node, command): + xpath = "./ancestor::svg:g/svg:use[@xlink:href='#inkstitch_%(command)s']" % dict(id=node.get('id'), command=command) + group_command = node.xpath(xpath, namespaces=inkex.NSS) + return group_command + + def layer_commands(layer, command): """Find standalone (unconnected) command symbols in this layer.""" diff --git a/lib/elements/satin_column.py b/lib/elements/satin_column.py index 3f5f05e5..43948e42 100644 --- a/lib/elements/satin_column.py +++ b/lib/elements/satin_column.py @@ -6,7 +6,7 @@ from copy import deepcopy from itertools import chain -from inkex import paths +from inkex import paths, NSS from shapely import affinity as shaffinity from shapely import geometry as shgeo from shapely.ops import nearest_points @@ -14,6 +14,7 @@ from shapely.ops import nearest_points from ..i18n import _ from ..svg import (PIXELS_PER_MM, apply_transforms, line_strings_to_csp, point_lists_to_csp) +from ..svg.tags import EMBROIDERABLE_TAGS from ..utils import Point, cache, collapse_duplicate_point, cut from .element import EmbroideryElement, Patch, param from .validation import ValidationError, ValidationWarning @@ -577,10 +578,13 @@ class SatinColumn(EmbroideryElement): return SatinColumn(node) def get_patterns(self): - xpath = ".//*[@inkstitch:pattern='%(id)s']" % dict(id=self.node.get('id')) - patterns = self.node.getroottree().getroot().xpath(xpath) + xpath = "./ancestor::svg:g[svg:use[@xlink:href='#inkstitch_pattern_group']]//*[not(@inkstitch:satin_column='true')]" + patterns = self.node.xpath(xpath, namespaces=NSS) line_strings = [] for pattern in patterns: + # TODO: exclude fills in case we will want to use them with the pattern too + if pattern.tag not in EMBROIDERABLE_TAGS: + continue d = pattern.get_path() path = paths.Path(d).to_superpath() path = apply_transforms(path, pattern) diff --git a/lib/elements/utils.py b/lib/elements/utils.py index 03ea48d4..cbac3d40 100644 --- a/lib/elements/utils.py +++ b/lib/elements/utils.py @@ -17,6 +17,7 @@ from .polyline import Polyline from .satin_column import SatinColumn from .stroke import Stroke from .text import TextObject +from ..commands import group_commands def node_to_elements(node): # noqa: C901 @@ -29,7 +30,8 @@ def node_to_elements(node): # noqa: C901 elif node.tag == SVG_PATH_TAG and not node.get('d', ''): return [EmptyDObject(node)] - elif node.get(INKSTITCH_ATTRIBS['pattern']): + # TODO: exclude fills + elif group_commands(node, 'pattern_group') and not node.get(INKSTITCH_ATTRIBS['satin_column']): return [PatternObject(node)] elif node.tag in EMBROIDERABLE_TAGS: diff --git a/lib/extensions/__init__.py b/lib/extensions/__init__.py index 70df7c37..25f835c3 100644 --- a/lib/extensions/__init__.py +++ b/lib/extensions/__init__.py @@ -5,7 +5,6 @@ from lib.extensions.troubleshoot import Troubleshoot -from .apply_satin_pattern import ApplySatinPattern from .auto_satin import AutoSatin from .break_apart import BreakApart from .cleanup import Cleanup @@ -46,7 +45,6 @@ __all__ = extensions = [StitchPlanPreview, GlobalCommands, ConvertToSatin, CutSatin, - ApplySatinPattern, AutoSatin, Lettering, LetteringGenerateJson, diff --git a/lib/extensions/apply_satin_pattern.py b/lib/extensions/apply_satin_pattern.py deleted file mode 100644 index 47eb4d83..00000000 --- a/lib/extensions/apply_satin_pattern.py +++ /dev/null @@ -1,79 +0,0 @@ -# Authors: see git history -# -# Copyright (c) 2021 Authors -# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details. - -import inkex -from lxml import etree - -from ..elements import SatinColumn -from ..i18n import _ -from ..svg.tags import INKSTITCH_ATTRIBS, SVG_DEFS_TAG -from .base import InkstitchExtension - - -class ApplySatinPattern(InkstitchExtension): - # Add inkstitch:pattern attribute to selected patterns. The patterns will be projected on a satin column, which must be in the selection too - - def effect(self): - if not self.get_elements(): - return - - if not self.svg.selected or not any(isinstance(item, SatinColumn) for item in self.elements) or len(self.svg.selected) < 2: - inkex.errormsg(_("Please select at least one satin column and a pattern.")) - return - - if sum(isinstance(item, SatinColumn) for item in self.elements) > 1: - inkex.errormsg(_("Please select only one satin column.")) - return - - satin_id = self.get_satin_column().node.get('id', None) - patterns = self.get_patterns() - - for pattern in patterns: - pattern.node.set(INKSTITCH_ATTRIBS['pattern'], satin_id) - self.set_marker(pattern.node) - - def get_satin_column(self): - return list(filter(lambda satin: isinstance(satin, SatinColumn), self.elements))[0] - - def get_patterns(self): - return list(filter(lambda satin: not isinstance(satin, SatinColumn), self.elements)) - - def set_marker(self, node): - document = node.getroottree().getroot() - xpath = ".//marker[@id='inkstitch-pattern-marker']" - pattern_marker = document.xpath(xpath) - if not pattern_marker: - # get or create def element - defs = document.find(SVG_DEFS_TAG) - if defs is None: - defs = etree.SubElement(document, SVG_DEFS_TAG) - - # insert marker - marker = """ - - - - - """ # noqa: E501 - defs.append(etree.fromstring(marker)) - - # attach marker to node - style = node.get('style', '').split(";") - import sys - print(style, file=sys.stderr) - style = [i for i in style if not i.startswith('marker-start')] - style.append('marker-start:url(#inkstitch-pattern-marker)') - node.set('style', ";".join(style)) diff --git a/lib/extensions/base.py b/lib/extensions/base.py index 00d4a00d..ce5f8b1d 100644 --- a/lib/extensions/base.py +++ b/lib/extensions/base.py @@ -12,7 +12,7 @@ import inkex from lxml import etree from stringcase import snakecase -from ..commands import is_command, layer_commands +from ..commands import is_command, layer_commands, group_commands from ..elements import EmbroideryElement, nodes_to_elements from ..elements.clone import is_clone from ..i18n import _ @@ -171,9 +171,12 @@ class InkstitchExtension(inkex.Effect): if selected: if node.tag == SVG_GROUP_TAG: pass - elif (node.tag in EMBROIDERABLE_TAGS or is_clone(node)) and not node.get(INKSTITCH_ATTRIBS['pattern']): + elif ((node.tag in EMBROIDERABLE_TAGS or is_clone(node)) and not + (len(list(group_commands(node, 'pattern_group'))) and not node.get(INKSTITCH_ATTRIBS['satin_column']))): nodes.append(node) - elif troubleshoot and (node.tag in NOT_EMBROIDERABLE_TAGS or node.get(INKSTITCH_ATTRIBS['pattern'])): + # add images, text and patterns for the troubleshoot extension + elif (troubleshoot and (node.tag in NOT_EMBROIDERABLE_TAGS or + (len(list(group_commands(node, 'pattern_group'))) and not node.get(INKSTITCH_ATTRIBS['satin_column'])))): nodes.append(node) return nodes diff --git a/symbols/inkstitch.svg b/symbols/inkstitch.svg index 4a67ae1c..f380d106 100644 --- a/symbols/inkstitch.svg +++ b/symbols/inkstitch.svg @@ -58,6 +58,21 @@ id="title9425">Ink/Stitch Commands + + Pattern group + + + + <use + xlink:href="#inkstitch_pattern_group" + id="use9462" + x="0" + y="0" + width="100%" + height="100%" + transform="translate(189.0002,37.680421)" /> <use xlink:href="#inkstitch_trim" id="use9461" diff --git a/templates/apply_satin_pattern.xml b/templates/apply_satin_pattern.xml deleted file mode 100644 index e52fb1a4..00000000 --- a/templates/apply_satin_pattern.xml +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <name>{% trans %}Apply Satin Pattern{% endtrans %}</name> - <id>org.inkstitch.apply_satin_pattern.{{ locale }}</id> - <param name="extension" type="string" gui-hidden="true">apply_satin_pattern</param> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu name="Ink/Stitch"> - <submenu name="{% trans %}Satin Tools{% endtrans %}" /> - </submenu> - </effects-menu> - </effect> - <script> - {{ command_tag | safe }} - </script> -</inkscape-extension> -- cgit v1.3.1 From 2f54ff2a436f2774bfdc730b6e95c43f18ed81ac Mon Sep 17 00:00:00 2001 From: Kaalleen <reni@allenka.de> Date: Sun, 27 Jun 2021 22:47:43 +0200 Subject: group command extension --- lib/elements/satin_column.py | 2 +- lib/elements/utils.py | 3 +-- lib/extensions/__init__.py | 2 ++ lib/extensions/base.py | 2 +- lib/extensions/group_commands.py | 41 ++++++++++++++++++++++++++++++++++++++++ lib/inx/extensions.py | 9 +++++++-- templates/group_commands.xml | 21 ++++++++++++++++++++ 7 files changed, 74 insertions(+), 6 deletions(-) create mode 100644 lib/extensions/group_commands.py create mode 100644 templates/group_commands.xml (limited to 'templates') diff --git a/lib/elements/satin_column.py b/lib/elements/satin_column.py index 43948e42..65e523d4 100644 --- a/lib/elements/satin_column.py +++ b/lib/elements/satin_column.py @@ -6,7 +6,7 @@ from copy import deepcopy from itertools import chain -from inkex import paths, NSS +from inkex import NSS, paths from shapely import affinity as shaffinity from shapely import geometry as shgeo from shapely.ops import nearest_points diff --git a/lib/elements/utils.py b/lib/elements/utils.py index cbac3d40..78dace6a 100644 --- a/lib/elements/utils.py +++ b/lib/elements/utils.py @@ -3,7 +3,7 @@ # Copyright (c) 2010 Authors # Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details. -from ..commands import is_command +from ..commands import group_commands, is_command from ..svg.tags import (EMBROIDERABLE_TAGS, INKSTITCH_ATTRIBS, SVG_IMAGE_TAG, SVG_PATH_TAG, SVG_POLYLINE_TAG, SVG_TEXT_TAG) from .auto_fill import AutoFill @@ -17,7 +17,6 @@ from .polyline import Polyline from .satin_column import SatinColumn from .stroke import Stroke from .text import TextObject -from ..commands import group_commands def node_to_elements(node): # noqa: C901 diff --git a/lib/extensions/__init__.py b/lib/extensions/__init__.py index 25f835c3..a6d25d2c 100644 --- a/lib/extensions/__init__.py +++ b/lib/extensions/__init__.py @@ -14,6 +14,7 @@ from .duplicate_params import DuplicateParams from .embroider_settings import EmbroiderSettings from .flip import Flip from .global_commands import GlobalCommands +from .group_commands import GroupCommands from .import_threadlist import ImportThreadlist from .input import Input from .install import Install @@ -41,6 +42,7 @@ __all__ = extensions = [StitchPlanPreview, Zip, Flip, ObjectCommands, + GroupCommands, LayerCommands, GlobalCommands, ConvertToSatin, diff --git a/lib/extensions/base.py b/lib/extensions/base.py index ce5f8b1d..353e433c 100644 --- a/lib/extensions/base.py +++ b/lib/extensions/base.py @@ -12,7 +12,7 @@ import inkex from lxml import etree from stringcase import snakecase -from ..commands import is_command, layer_commands, group_commands +from ..commands import group_commands, is_command, layer_commands from ..elements import EmbroideryElement, nodes_to_elements from ..elements.clone import is_clone from ..i18n import _ diff --git a/lib/extensions/group_commands.py b/lib/extensions/group_commands.py new file mode 100644 index 00000000..af1f9fb1 --- /dev/null +++ b/lib/extensions/group_commands.py @@ -0,0 +1,41 @@ +# 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 lxml import etree + +from ..commands import GROUP_COMMANDS, ensure_symbol, get_command_description +from ..i18n import _ +from ..svg import get_correction_transform +from ..svg.tags import INKSCAPE_LABEL, SVG_USE_TAG, XLINK_HREF +from .commands import CommandsExtension + + +class GroupCommands(CommandsExtension): + COMMANDS = GROUP_COMMANDS + + def effect(self): + commands = [command for command in self.COMMANDS if getattr(self.options, command)] + + if not commands: + inkex.errormsg(_("Please choose one or more commands to add.")) + return + + correction_transform = get_correction_transform(self.svg.get_current_layer(), child=True) + + for i, command in enumerate(commands): + ensure_symbol(self.document, command) + + etree.SubElement(self.svg.get_current_layer(), SVG_USE_TAG, + { + "id": self.uniqueId("use"), + INKSCAPE_LABEL: _("Ink/Stitch Command") + ": %s" % get_command_description(command), + XLINK_HREF: "#inkstitch_%s" % command, + "height": "100%", + "width": "100%", + "x": str(i * 20), + "y": "-10", + "transform": correction_transform + }) diff --git a/lib/inx/extensions.py b/lib/inx/extensions.py index 9a197c5d..8ca0addc 100755 --- a/lib/inx/extensions.py +++ b/lib/inx/extensions.py @@ -5,8 +5,8 @@ import pyembroidery -from ..commands import (COMMANDS, GLOBAL_COMMANDS, LAYER_COMMANDS, - OBJECT_COMMANDS) +from ..commands import (COMMANDS, GLOBAL_COMMANDS, GROUP_COMMANDS, + LAYER_COMMANDS, OBJECT_COMMANDS) from ..extensions import Input, Output, extensions from ..threads import ThreadCatalog from .outputs import pyembroidery_output_formats @@ -24,6 +24,10 @@ def global_commands(): return [(command, COMMANDS[command]) for command in GLOBAL_COMMANDS] +def group_commands(): + return [(command, COMMANDS[command]) for command in GROUP_COMMANDS] + + def object_commands(): return [(command, COMMANDS[command]) for command in OBJECT_COMMANDS] @@ -51,6 +55,7 @@ def generate_extension_inx_files(): write_inx_file(name, template.render(formats=pyembroidery_output_formats(), debug_formats=pyembroidery_debug_formats(), threadcatalog=threadcatalog(), + group_commands=group_commands(), layer_commands=layer_commands(), object_commands=object_commands(), global_commands=global_commands())) diff --git a/templates/group_commands.xml b/templates/group_commands.xml new file mode 100644 index 00000000..2a67c5b7 --- /dev/null +++ b/templates/group_commands.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> + <name>{% trans %}Add Group Commands{% endtrans %}</name> + <id>org.inkstitch.group_commands.{{ locale }}</id> + <param name="description" type="description">{% trans %}Commands will be added to the currently-selected group.{% endtrans %}</param> + {% for command, description in group_commands %} + <param name="{{ command }}" type="boolean" _gui-text="{{ _(description) }}">false</param> + {% endfor %} + <param name="extension" type="string" gui-hidden="true">group_commands</param> + <effect> + <object-type>all</object-type> + <effects-menu> + <submenu name="Ink/Stitch"> + <submenu name="{% trans %}Commands{% endtrans %}" /> + </submenu> + </effects-menu> + </effect> + <script> + {{ command_tag | safe }} + </script> +</inkscape-extension> -- cgit v1.3.1 From ecacb9829e9c2b7050486707211f9d176aafdf75 Mon Sep 17 00:00:00 2001 From: Kaalleen <reni@allenka.de> Date: Mon, 28 Jun 2021 20:05:50 +0200 Subject: pattern markers --- lib/commands.py | 7 ----- lib/elements/pattern.py | 4 +++ lib/elements/satin_column.py | 7 +++-- lib/elements/utils.py | 11 ++++--- lib/extensions/__init__.py | 4 +-- lib/extensions/apply_pattern.py | 62 ++++++++++++++++++++++++++++++++++++++++ lib/extensions/base.py | 12 ++++---- lib/extensions/group_commands.py | 41 -------------------------- lib/inx/extensions.py | 9 ++---- templates/apply_pattern.xml | 15 ++++++++++ templates/group_commands.xml | 21 -------------- 11 files changed, 100 insertions(+), 93 deletions(-) create mode 100644 lib/extensions/apply_pattern.py delete mode 100644 lib/extensions/group_commands.py create mode 100644 templates/apply_pattern.xml delete mode 100644 templates/group_commands.xml (limited to 'templates') diff --git a/lib/commands.py b/lib/commands.py index ea6d3509..cb2a74d5 100644 --- a/lib/commands.py +++ b/lib/commands.py @@ -60,7 +60,6 @@ COMMANDS = { } OBJECT_COMMANDS = ["fill_start", "fill_end", "satin_start", "satin_end", "stop", "trim", "ignore_object", "satin_cut_point"] -GROUP_COMMANDS = ["pattern_group"] LAYER_COMMANDS = ["ignore_layer"] GLOBAL_COMMANDS = ["origin", "stop_position"] @@ -187,12 +186,6 @@ def find_commands(node): return commands -def group_commands(node, command): - xpath = "./ancestor::svg:g/svg:use[@xlink:href='#inkstitch_%(command)s']" % dict(id=node.get('id'), command=command) - group_command = node.xpath(xpath, namespaces=inkex.NSS) - return group_command - - def layer_commands(layer, command): """Find standalone (unconnected) command symbols in this layer.""" diff --git a/lib/elements/pattern.py b/lib/elements/pattern.py index 98f29456..c66ffbdc 100644 --- a/lib/elements/pattern.py +++ b/lib/elements/pattern.py @@ -30,3 +30,7 @@ class PatternObject(EmbroideryElement): def to_patches(self, last_patch): return [] + + +def is_pattern(node): + return "marker-start:url(#inkstitch-pattern-marker)" in node.get('style', '') diff --git a/lib/elements/satin_column.py b/lib/elements/satin_column.py index 65e523d4..77cb7d22 100644 --- a/lib/elements/satin_column.py +++ b/lib/elements/satin_column.py @@ -578,11 +578,14 @@ class SatinColumn(EmbroideryElement): return SatinColumn(node) def get_patterns(self): - xpath = "./ancestor::svg:g[svg:use[@xlink:href='#inkstitch_pattern_group']]//*[not(@inkstitch:satin_column='true')]" + # TODO: which one is better?!? + # All child groups of pattern + # xpath = "./ancestor::svg:g//*[contains(@style, 'marker-start:url(#inkstitch-pattern-marker)')]" + # Only direct siblings of pattern + xpath = "./parent::svg:g/*[contains(@style, 'marker-start:url(#inkstitch-pattern-marker)')]" patterns = self.node.xpath(xpath, namespaces=NSS) line_strings = [] for pattern in patterns: - # TODO: exclude fills in case we will want to use them with the pattern too if pattern.tag not in EMBROIDERABLE_TAGS: continue d = pattern.get_path() diff --git a/lib/elements/utils.py b/lib/elements/utils.py index 78dace6a..cd87cec8 100644 --- a/lib/elements/utils.py +++ b/lib/elements/utils.py @@ -3,16 +3,16 @@ # Copyright (c) 2010 Authors # Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details. -from ..commands import group_commands, is_command -from ..svg.tags import (EMBROIDERABLE_TAGS, INKSTITCH_ATTRIBS, SVG_IMAGE_TAG, - SVG_PATH_TAG, SVG_POLYLINE_TAG, SVG_TEXT_TAG) +from ..commands import is_command +from ..svg.tags import (EMBROIDERABLE_TAGS, SVG_IMAGE_TAG, SVG_PATH_TAG, + SVG_POLYLINE_TAG, SVG_TEXT_TAG) from .auto_fill import AutoFill from .clone import Clone, is_clone from .element import EmbroideryElement from .empty_d_object import EmptyDObject from .fill import Fill from .image import ImageObject -from .pattern import PatternObject +from .pattern import PatternObject, is_pattern from .polyline import Polyline from .satin_column import SatinColumn from .stroke import Stroke @@ -29,8 +29,7 @@ def node_to_elements(node): # noqa: C901 elif node.tag == SVG_PATH_TAG and not node.get('d', ''): return [EmptyDObject(node)] - # TODO: exclude fills - elif group_commands(node, 'pattern_group') and not node.get(INKSTITCH_ATTRIBS['satin_column']): + elif is_pattern(node): return [PatternObject(node)] elif node.tag in EMBROIDERABLE_TAGS: diff --git a/lib/extensions/__init__.py b/lib/extensions/__init__.py index a6d25d2c..3bd2fef6 100644 --- a/lib/extensions/__init__.py +++ b/lib/extensions/__init__.py @@ -5,6 +5,7 @@ from lib.extensions.troubleshoot import Troubleshoot +from .apply_pattern import ApplyPattern from .auto_satin import AutoSatin from .break_apart import BreakApart from .cleanup import Cleanup @@ -14,7 +15,6 @@ from .duplicate_params import DuplicateParams from .embroider_settings import EmbroiderSettings from .flip import Flip from .global_commands import GlobalCommands -from .group_commands import GroupCommands from .import_threadlist import ImportThreadlist from .input import Input from .install import Install @@ -41,8 +41,8 @@ __all__ = extensions = [StitchPlanPreview, Output, Zip, Flip, + ApplyPattern, ObjectCommands, - GroupCommands, LayerCommands, GlobalCommands, ConvertToSatin, diff --git a/lib/extensions/apply_pattern.py b/lib/extensions/apply_pattern.py new file mode 100644 index 00000000..ad881604 --- /dev/null +++ b/lib/extensions/apply_pattern.py @@ -0,0 +1,62 @@ +# Authors: see git history +# +# Copyright (c) 2021 Authors +# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details. + +import inkex +from lxml import etree + +from ..i18n import _ +from ..svg.tags import SVG_DEFS_TAG +from .base import InkstitchExtension + + +class ApplyPattern(InkstitchExtension): + # This extension will mark selected + + def effect(self): + if not self.get_elements(): + return + + if not self.svg.selected: + inkex.errormsg(_("Please select at least one object to be marked as a pattern.")) + return + + for pattern in self.svg.selected.values(): + self.set_marker(pattern) + + def set_marker(self, node): + xpath = ".//marker[@id='inkstitch-pattern-marker']" + pattern_marker = self.document.xpath(xpath) + + if not pattern_marker: + # get or create def element + defs = self.document.find(SVG_DEFS_TAG) + if defs is None: + defs = etree.SubElement(self.document, SVG_DEFS_TAG) + + # insert marker + marker = """<marker + refX="10" + refY="5" + orient="auto" + id="inkstitch-pattern-marker"> + <g + id="inkstitch-pattern-group"> + <path + style="fill:#fafafa;stroke:#ff5500;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1, 1;stroke-dashoffset:0;stroke-opacity:1;fill-opacity:0.8;" + d="M 10.12911,5.2916678 A 4.8374424,4.8374426 0 0 1 5.2916656,10.12911 4.8374424,4.8374426 0 0 1 0.45422399,5.2916678 4.8374424,4.8374426 0 0 1 5.2916656,0.45422399 4.8374424,4.8374426 0 0 1 10.12911,5.2916678 Z" + id="inkstitch-pattern-marker-circle" /> + <path + style="fill:none;stroke:#000000;stroke-width:0.4;stroke-linecap:round;stroke-miterlimit:4;" + id="inkstitch-pattern-marker-spiral" + d="M 4.9673651,5.7245662 C 4.7549848,5.7646159 4.6247356,5.522384 4.6430021,5.3419847 4.6765851,5.0103151 5.036231,4.835347 5.3381858,4.8987426 5.7863901,4.9928495 6.0126802,5.4853625 5.9002872,5.9065088 5.7495249,6.4714237 5.1195537,6.7504036 4.5799191,6.5874894 3.898118,6.3816539 3.5659013,5.6122905 3.7800789,4.9545192 4.0402258,4.1556558 4.9498996,3.7699484 5.7256318,4.035839 6.6416744,4.3498087 7.0810483,5.4003986 6.7631909,6.2939744 6.395633,7.3272552 5.2038143,7.8204128 4.1924535,7.4503931 3.0418762,7.0294421 2.4948761,5.6961604 2.9171752,4.567073 3.3914021,3.2991406 4.8663228,2.6982592 6.1130974,3.1729158 7.4983851,3.7003207 8.1531869,5.3169977 7.6260947,6.6814205 7.0456093,8.1841025 5.2870784,8.8928844 3.8050073,8.3132966 2.1849115,7.6797506 1.4221671,5.7793073 2.0542715,4.1796074 2.7408201,2.4420977 4.7832541,1.6253548 6.5005435,2.310012 8.3554869,3.0495434 9.2262638,5.2339874 8.4890181,7.0688861 8.4256397,7.2266036 8.3515789,7.379984 8.2675333,7.5277183" /> + </g> + </marker>""" # noqa: E501 + defs.append(etree.fromstring(marker)) + + # attach marker to node + style = node.get('style', '').split(";") + style = [i for i in style if not i.startswith('marker-start')] + style.append('marker-start:url(#inkstitch-pattern-marker)') + node.set('style', ";".join(style)) diff --git a/lib/extensions/base.py b/lib/extensions/base.py index 353e433c..1c10cd4a 100644 --- a/lib/extensions/base.py +++ b/lib/extensions/base.py @@ -12,14 +12,14 @@ import inkex from lxml import etree from stringcase import snakecase -from ..commands import group_commands, is_command, layer_commands +from ..commands import is_command, layer_commands from ..elements import EmbroideryElement, nodes_to_elements from ..elements.clone import is_clone +from ..elements.pattern import is_pattern from ..i18n import _ from ..svg import generate_unique_id from ..svg.tags import (CONNECTOR_TYPE, EMBROIDERABLE_TAGS, INKSCAPE_GROUPMODE, - INKSTITCH_ATTRIBS, NOT_EMBROIDERABLE_TAGS, - SVG_DEFS_TAG, SVG_GROUP_TAG) + NOT_EMBROIDERABLE_TAGS, SVG_DEFS_TAG, SVG_GROUP_TAG) SVG_METADATA_TAG = inkex.addNS("metadata", "svg") @@ -171,12 +171,10 @@ class InkstitchExtension(inkex.Effect): if selected: if node.tag == SVG_GROUP_TAG: pass - elif ((node.tag in EMBROIDERABLE_TAGS or is_clone(node)) and not - (len(list(group_commands(node, 'pattern_group'))) and not node.get(INKSTITCH_ATTRIBS['satin_column']))): + elif (node.tag in EMBROIDERABLE_TAGS or is_clone(node)) and not is_pattern(node): nodes.append(node) # add images, text and patterns for the troubleshoot extension - elif (troubleshoot and (node.tag in NOT_EMBROIDERABLE_TAGS or - (len(list(group_commands(node, 'pattern_group'))) and not node.get(INKSTITCH_ATTRIBS['satin_column'])))): + elif troubleshoot and (node.tag in NOT_EMBROIDERABLE_TAGS or is_pattern(node)): nodes.append(node) return nodes diff --git a/lib/extensions/group_commands.py b/lib/extensions/group_commands.py deleted file mode 100644 index af1f9fb1..00000000 --- a/lib/extensions/group_commands.py +++ /dev/null @@ -1,41 +0,0 @@ -# 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 lxml import etree - -from ..commands import GROUP_COMMANDS, ensure_symbol, get_command_description -from ..i18n import _ -from ..svg import get_correction_transform -from ..svg.tags import INKSCAPE_LABEL, SVG_USE_TAG, XLINK_HREF -from .commands import CommandsExtension - - -class GroupCommands(CommandsExtension): - COMMANDS = GROUP_COMMANDS - - def effect(self): - commands = [command for command in self.COMMANDS if getattr(self.options, command)] - - if not commands: - inkex.errormsg(_("Please choose one or more commands to add.")) - return - - correction_transform = get_correction_transform(self.svg.get_current_layer(), child=True) - - for i, command in enumerate(commands): - ensure_symbol(self.document, command) - - etree.SubElement(self.svg.get_current_layer(), SVG_USE_TAG, - { - "id": self.uniqueId("use"), - INKSCAPE_LABEL: _("Ink/Stitch Command") + ": %s" % get_command_description(command), - XLINK_HREF: "#inkstitch_%s" % command, - "height": "100%", - "width": "100%", - "x": str(i * 20), - "y": "-10", - "transform": correction_transform - }) diff --git a/lib/inx/extensions.py b/lib/inx/extensions.py index 8ca0addc..9a197c5d 100755 --- a/lib/inx/extensions.py +++ b/lib/inx/extensions.py @@ -5,8 +5,8 @@ import pyembroidery -from ..commands import (COMMANDS, GLOBAL_COMMANDS, GROUP_COMMANDS, - LAYER_COMMANDS, OBJECT_COMMANDS) +from ..commands import (COMMANDS, GLOBAL_COMMANDS, LAYER_COMMANDS, + OBJECT_COMMANDS) from ..extensions import Input, Output, extensions from ..threads import ThreadCatalog from .outputs import pyembroidery_output_formats @@ -24,10 +24,6 @@ def global_commands(): return [(command, COMMANDS[command]) for command in GLOBAL_COMMANDS] -def group_commands(): - return [(command, COMMANDS[command]) for command in GROUP_COMMANDS] - - def object_commands(): return [(command, COMMANDS[command]) for command in OBJECT_COMMANDS] @@ -55,7 +51,6 @@ def generate_extension_inx_files(): write_inx_file(name, template.render(formats=pyembroidery_output_formats(), debug_formats=pyembroidery_debug_formats(), threadcatalog=threadcatalog(), - group_commands=group_commands(), layer_commands=layer_commands(), object_commands=object_commands(), global_commands=global_commands())) diff --git a/templates/apply_pattern.xml b/templates/apply_pattern.xml new file mode 100644 index 00000000..cbd83dbc --- /dev/null +++ b/templates/apply_pattern.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> + <name>{% trans %}Apply Pattern{% endtrans %}</name> + <id>org.inkstitch.apply_pattern.{{ locale }}</id> + <param name="extension" type="string" gui-hidden="true">apply_pattern</param> + <effect> + <object-type>all</object-type> + <effects-menu> + <submenu name="Ink/Stitch" /> + </effects-menu> + </effect> + <script> + {{ command_tag | safe }} + </script> +</inkscape-extension> diff --git a/templates/group_commands.xml b/templates/group_commands.xml deleted file mode 100644 index 2a67c5b7..00000000 --- a/templates/group_commands.xml +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <name>{% trans %}Add Group Commands{% endtrans %}</name> - <id>org.inkstitch.group_commands.{{ locale }}</id> - <param name="description" type="description">{% trans %}Commands will be added to the currently-selected group.{% endtrans %}</param> - {% for command, description in group_commands %} - <param name="{{ command }}" type="boolean" _gui-text="{{ _(description) }}">false</param> - {% endfor %} - <param name="extension" type="string" gui-hidden="true">group_commands</param> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu name="Ink/Stitch"> - <submenu name="{% trans %}Commands{% endtrans %}" /> - </submenu> - </effects-menu> - </effect> - <script> - {{ command_tag | safe }} - </script> -</inkscape-extension> -- cgit v1.3.1 From 52d9ee6a6d97b2ea752f5fdd3080a160a3574f82 Mon Sep 17 00:00:00 2001 From: Kaalleen <reni@allenka.de> Date: Wed, 30 Jun 2021 14:05:13 +0200 Subject: structuring --- lib/elements/element.py | 50 ++------------------------ lib/elements/pattern.py | 7 ---- lib/elements/utils.py | 3 +- lib/extensions/__init__.py | 4 +-- lib/extensions/apply_pattern.py | 62 -------------------------------- lib/extensions/base.py | 2 +- lib/extensions/selection_to_pattern.py | 61 +++++++++++++++++++++++++++++++ lib/patterns.py | 66 ++++++++++++++++++++++++++++++++++ templates/apply_pattern.xml | 15 -------- templates/selection_to_pattern.xml | 17 +++++++++ 10 files changed, 151 insertions(+), 136 deletions(-) delete mode 100644 lib/extensions/apply_pattern.py create mode 100644 lib/extensions/selection_to_pattern.py create mode 100644 lib/patterns.py delete mode 100644 templates/apply_pattern.xml create mode 100644 templates/selection_to_pattern.xml (limited to 'templates') diff --git a/lib/elements/element.py b/lib/elements/element.py index aa0c4795..dc466fbf 100644 --- a/lib/elements/element.py +++ b/lib/elements/element.py @@ -9,10 +9,10 @@ from copy import deepcopy import inkex import tinycss2 from inkex import bezier -from shapely import geometry as shgeo 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 (EMBROIDERABLE_TAGS, INKSCAPE_LABEL, INKSTITCH_ATTRIBS, @@ -331,52 +331,6 @@ class EmbroideryElement(object): else: return None - @cache - def get_patterns(self): - xpath = "./parent::svg:g/*[contains(@style, 'marker-start:url(#inkstitch-pattern-marker)')]" - patterns = self.node.xpath(xpath, namespaces=inkex.NSS) - line_strings = [] - for pattern in patterns: - if pattern.tag not in EMBROIDERABLE_TAGS: - continue - d = pattern.get_path() - path = inkex.paths.Path(d).to_superpath() - path = apply_transforms(path, pattern) - path = self.flatten(path) - lines = [shgeo.LineString(p) for p in path] - for line in lines: - line_strings.append(line) - return shgeo.MultiLineString(line_strings) - - def _apply_patterns(self, patches): - patterns = self.get_patterns() - if not patterns: - return patches - - patch_points = [] - for patch in patches: - for i, stitch in enumerate(patch.stitches): - patch_points.append(stitch) - if i == len(patch.stitches) - 1: - continue - intersection_points = self._get_pattern_points(stitch, patch.stitches[i+1], patterns) - for point in intersection_points: - patch_points.append(point) - patch.stitches = patch_points - - def _get_pattern_points(self, first, second, patterns): - points = [] - for pattern in patterns: - intersection = shgeo.LineString([first, second]).intersection(pattern) - if isinstance(intersection, shgeo.Point): - points.append(Point(intersection.x, intersection.y)) - if isinstance(intersection, shgeo.MultiPoint): - for point in intersection: - points.append(Point(point.x, point.y)) - # sort points after their distance to left - points.sort(key=lambda point: point.distance(first)) - return points - def strip_control_points(self, subpath): return [point for control_before, point, control_after in subpath] @@ -409,7 +363,7 @@ class EmbroideryElement(object): self.validate() patches = self.to_patches(last_patch) - self._apply_patterns(patches) + apply_patterns(patches, self.node) for patch in patches: patch.tie_modus = self.ties diff --git a/lib/elements/pattern.py b/lib/elements/pattern.py index fa54b7ba..98f29456 100644 --- a/lib/elements/pattern.py +++ b/lib/elements/pattern.py @@ -6,7 +6,6 @@ import inkex from ..i18n import _ -from ..svg.tags import EMBROIDERABLE_TAGS from .element import EmbroideryElement from .validation import ObjectTypeWarning @@ -31,9 +30,3 @@ class PatternObject(EmbroideryElement): def to_patches(self, last_patch): return [] - - -def is_pattern(node): - if node.tag not in EMBROIDERABLE_TAGS: - return False - return "marker-start:url(#inkstitch-pattern-marker)" in node.get('style', '') diff --git a/lib/elements/utils.py b/lib/elements/utils.py index cd87cec8..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,7 +13,7 @@ from .element import EmbroideryElement from .empty_d_object import EmptyDObject from .fill import Fill from .image import ImageObject -from .pattern import PatternObject, is_pattern +from .pattern import PatternObject from .polyline import Polyline from .satin_column import SatinColumn from .stroke import Stroke diff --git a/lib/extensions/__init__.py b/lib/extensions/__init__.py index 3bd2fef6..7996770d 100644 --- a/lib/extensions/__init__.py +++ b/lib/extensions/__init__.py @@ -5,7 +5,6 @@ from lib.extensions.troubleshoot import Troubleshoot -from .apply_pattern import ApplyPattern from .auto_satin import AutoSatin from .break_apart import BreakApart from .cleanup import Cleanup @@ -29,6 +28,7 @@ from .params import Params from .print_pdf import Print from .remove_embroidery_settings import RemoveEmbroiderySettings from .reorder import Reorder +from .selection_to_pattern import SelectionToPattern from .simulator import Simulator from .stitch_plan_preview import StitchPlanPreview from .zip import Zip @@ -41,7 +41,7 @@ __all__ = extensions = [StitchPlanPreview, Output, Zip, Flip, - ApplyPattern, + SelectionToPattern, ObjectCommands, LayerCommands, GlobalCommands, diff --git a/lib/extensions/apply_pattern.py b/lib/extensions/apply_pattern.py deleted file mode 100644 index ad881604..00000000 --- a/lib/extensions/apply_pattern.py +++ /dev/null @@ -1,62 +0,0 @@ -# Authors: see git history -# -# Copyright (c) 2021 Authors -# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details. - -import inkex -from lxml import etree - -from ..i18n import _ -from ..svg.tags import SVG_DEFS_TAG -from .base import InkstitchExtension - - -class ApplyPattern(InkstitchExtension): - # This extension will mark selected - - def effect(self): - if not self.get_elements(): - return - - if not self.svg.selected: - inkex.errormsg(_("Please select at least one object to be marked as a pattern.")) - return - - for pattern in self.svg.selected.values(): - self.set_marker(pattern) - - def set_marker(self, node): - xpath = ".//marker[@id='inkstitch-pattern-marker']" - pattern_marker = self.document.xpath(xpath) - - if not pattern_marker: - # get or create def element - defs = self.document.find(SVG_DEFS_TAG) - if defs is None: - defs = etree.SubElement(self.document, SVG_DEFS_TAG) - - # insert marker - marker = """<marker - refX="10" - refY="5" - orient="auto" - id="inkstitch-pattern-marker"> - <g - id="inkstitch-pattern-group"> - <path - style="fill:#fafafa;stroke:#ff5500;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1, 1;stroke-dashoffset:0;stroke-opacity:1;fill-opacity:0.8;" - d="M 10.12911,5.2916678 A 4.8374424,4.8374426 0 0 1 5.2916656,10.12911 4.8374424,4.8374426 0 0 1 0.45422399,5.2916678 4.8374424,4.8374426 0 0 1 5.2916656,0.45422399 4.8374424,4.8374426 0 0 1 10.12911,5.2916678 Z" - id="inkstitch-pattern-marker-circle" /> - <path - style="fill:none;stroke:#000000;stroke-width:0.4;stroke-linecap:round;stroke-miterlimit:4;" - id="inkstitch-pattern-marker-spiral" - d="M 4.9673651,5.7245662 C 4.7549848,5.7646159 4.6247356,5.522384 4.6430021,5.3419847 4.6765851,5.0103151 5.036231,4.835347 5.3381858,4.8987426 5.7863901,4.9928495 6.0126802,5.4853625 5.9002872,5.9065088 5.7495249,6.4714237 5.1195537,6.7504036 4.5799191,6.5874894 3.898118,6.3816539 3.5659013,5.6122905 3.7800789,4.9545192 4.0402258,4.1556558 4.9498996,3.7699484 5.7256318,4.035839 6.6416744,4.3498087 7.0810483,5.4003986 6.7631909,6.2939744 6.395633,7.3272552 5.2038143,7.8204128 4.1924535,7.4503931 3.0418762,7.0294421 2.4948761,5.6961604 2.9171752,4.567073 3.3914021,3.2991406 4.8663228,2.6982592 6.1130974,3.1729158 7.4983851,3.7003207 8.1531869,5.3169977 7.6260947,6.6814205 7.0456093,8.1841025 5.2870784,8.8928844 3.8050073,8.3132966 2.1849115,7.6797506 1.4221671,5.7793073 2.0542715,4.1796074 2.7408201,2.4420977 4.7832541,1.6253548 6.5005435,2.310012 8.3554869,3.0495434 9.2262638,5.2339874 8.4890181,7.0688861 8.4256397,7.2266036 8.3515789,7.379984 8.2675333,7.5277183" /> - </g> - </marker>""" # noqa: E501 - defs.append(etree.fromstring(marker)) - - # attach marker to node - style = node.get('style', '').split(";") - style = [i for i in style if not i.startswith('marker-start')] - style.append('marker-start:url(#inkstitch-pattern-marker)') - node.set('style', ";".join(style)) diff --git a/lib/extensions/base.py b/lib/extensions/base.py index 1c10cd4a..862d031e 100644 --- a/lib/extensions/base.py +++ b/lib/extensions/base.py @@ -15,8 +15,8 @@ from stringcase import snakecase from ..commands import is_command, layer_commands from ..elements import EmbroideryElement, nodes_to_elements from ..elements.clone import is_clone -from ..elements.pattern import is_pattern from ..i18n import _ +from ..patterns import is_pattern from ..svg import generate_unique_id from ..svg.tags import (CONNECTOR_TYPE, EMBROIDERABLE_TAGS, INKSCAPE_GROUPMODE, NOT_EMBROIDERABLE_TAGS, SVG_DEFS_TAG, SVG_GROUP_TAG) diff --git a/lib/extensions/selection_to_pattern.py b/lib/extensions/selection_to_pattern.py new file mode 100644 index 00000000..3527cc5e --- /dev/null +++ b/lib/extensions/selection_to_pattern.py @@ -0,0 +1,61 @@ +# Authors: see git history +# +# Copyright (c) 2021 Authors +# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details. + +import inkex +from lxml import etree + +from ..i18n import _ +from ..svg.tags import SVG_DEFS_TAG +from .base import InkstitchExtension + + +class SelectionToPattern(InkstitchExtension): + + def effect(self): + if not self.get_elements(): + return + + if not self.svg.selected: + inkex.errormsg(_("Please select at least one object to be marked as a pattern.")) + return + + for pattern in self.svg.selected.values(): + self.set_marker(pattern) + + def set_marker(self, node): + xpath = ".//marker[@id='inkstitch-pattern-marker']" + pattern_marker = self.document.xpath(xpath) + + if not pattern_marker: + # get or create def element + defs = self.document.find(SVG_DEFS_TAG) + if defs is None: + defs = etree.SubElement(self.document, SVG_DEFS_TAG) + + # insert marker + marker = """<marker + refX="10" + refY="5" + orient="auto" + id="inkstitch-pattern-marker"> + <g + id="inkstitch-pattern-group"> + <path + style="fill:#fafafa;stroke:#ff5500;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1, 1;stroke-dashoffset:0;stroke-opacity:1;fill-opacity:0.8;" + d="M 10.12911,5.2916678 A 4.8374424,4.8374426 0 0 1 5.2916656,10.12911 4.8374424,4.8374426 0 0 1 0.45422399,5.2916678 4.8374424,4.8374426 0 0 1 5.2916656,0.45422399 4.8374424,4.8374426 0 0 1 10.12911,5.2916678 Z" + id="inkstitch-pattern-marker-circle" /> + <path + style="fill:none;stroke:#000000;stroke-width:0.4;stroke-linecap:round;stroke-miterlimit:4;" + id="inkstitch-pattern-marker-spiral" + d="M 4.9673651,5.7245662 C 4.7549848,5.7646159 4.6247356,5.522384 4.6430021,5.3419847 4.6765851,5.0103151 5.036231,4.835347 5.3381858,4.8987426 5.7863901,4.9928495 6.0126802,5.4853625 5.9002872,5.9065088 5.7495249,6.4714237 5.1195537,6.7504036 4.5799191,6.5874894 3.898118,6.3816539 3.5659013,5.6122905 3.7800789,4.9545192 4.0402258,4.1556558 4.9498996,3.7699484 5.7256318,4.035839 6.6416744,4.3498087 7.0810483,5.4003986 6.7631909,6.2939744 6.395633,7.3272552 5.2038143,7.8204128 4.1924535,7.4503931 3.0418762,7.0294421 2.4948761,5.6961604 2.9171752,4.567073 3.3914021,3.2991406 4.8663228,2.6982592 6.1130974,3.1729158 7.4983851,3.7003207 8.1531869,5.3169977 7.6260947,6.6814205 7.0456093,8.1841025 5.2870784,8.8928844 3.8050073,8.3132966 2.1849115,7.6797506 1.4221671,5.7793073 2.0542715,4.1796074 2.7408201,2.4420977 4.7832541,1.6253548 6.5005435,2.310012 8.3554869,3.0495434 9.2262638,5.2339874 8.4890181,7.0688861 8.4256397,7.2266036 8.3515789,7.379984 8.2675333,7.5277183" /> + </g> + </marker>""" # noqa: E501 + defs.append(etree.fromstring(marker)) + + # attach marker to node + style = node.get('style', '').split(";") + style = [i for i in style if not i.startswith('marker-start')] + style.append('marker-start:url(#inkstitch-pattern-marker)') + node.set('style', ";".join(style)) diff --git a/lib/patterns.py b/lib/patterns.py new file mode 100644 index 00000000..8872a8ce --- /dev/null +++ b/lib/patterns.py @@ -0,0 +1,66 @@ +# 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 shapely import geometry as shgeo + +from .svg import apply_transforms +from .svg.tags import EMBROIDERABLE_TAGS +from .utils import Point + + +def is_pattern(node): + if node.tag not in EMBROIDERABLE_TAGS: + return False + return "marker-start:url(#inkstitch-pattern-marker)" in node.get('style', '') + + +def apply_patterns(patches, node): + patterns = _get_patterns(node) + if not patterns: + return patches + + patch_points = [] + for patch in patches: + for i, stitch in enumerate(patch.stitches): + patch_points.append(stitch) + if i == len(patch.stitches) - 1: + continue + intersection_points = _get_pattern_points(stitch, patch.stitches[i+1], patterns) + for point in intersection_points: + patch_points.append(point) + patch.stitches = patch_points + + +def _get_patterns(node): + xpath = "./parent::svg:g/*[contains(@style, 'marker-start:url(#inkstitch-pattern-marker)')]" + patterns = node.xpath(xpath, namespaces=inkex.NSS) + line_strings = [] + for pattern in patterns: + if pattern.tag not in EMBROIDERABLE_TAGS: + continue + d = pattern.get_path() + path = inkex.paths.Path(d).to_superpath() + path = apply_transforms(path, pattern) + inkex.bezier.cspsubdiv(path, 0.1) + path = [[point for control_before, point, control_after in subpath] for subpath in path] + lines = [shgeo.LineString(p) for p in path] + for line in lines: + line_strings.append(line) + return shgeo.MultiLineString(line_strings) + + +def _get_pattern_points(first, second, patterns): + points = [] + for pattern in patterns: + intersection = shgeo.LineString([first, second]).intersection(pattern) + if isinstance(intersection, shgeo.Point): + points.append(Point(intersection.x, intersection.y)) + if isinstance(intersection, shgeo.MultiPoint): + for point in intersection: + points.append(Point(point.x, point.y)) + # sort points after their distance to left + points.sort(key=lambda point: point.distance(first)) + return points diff --git a/templates/apply_pattern.xml b/templates/apply_pattern.xml deleted file mode 100644 index cbd83dbc..00000000 --- a/templates/apply_pattern.xml +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> - <name>{% trans %}Apply Pattern{% endtrans %}</name> - <id>org.inkstitch.apply_pattern.{{ locale }}</id> - <param name="extension" type="string" gui-hidden="true">apply_pattern</param> - <effect> - <object-type>all</object-type> - <effects-menu> - <submenu name="Ink/Stitch" /> - </effects-menu> - </effect> - <script> - {{ command_tag | safe }} - </script> -</inkscape-extension> diff --git a/templates/selection_to_pattern.xml b/templates/selection_to_pattern.xml new file mode 100644 index 00000000..859a51ed --- /dev/null +++ b/templates/selection_to_pattern.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension"> + <name>{% trans %}Selection to pattern{% endtrans %}</name> + <id>org.inkstitch.selection_to_pattern.{{ locale }}</id> + <param name="extension" type="string" gui-hidden="true">selection_to_pattern</param> + <effect> + <object-type>all</object-type> + <effects-menu> + <submenu name="Ink/Stitch"> + <submenu name="{% trans %}Edit{% endtrans %}" /> + </submenu> + </effects-menu> + </effect> + <script> + {{ command_tag | safe }} + </script> +</inkscape-extension> -- cgit v1.3.1