diff options
| author | Kaalleen <36401965+kaalleen@users.noreply.github.com> | 2023-03-15 20:41:54 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-03-15 20:41:54 +0100 |
| commit | 0b0704c300efedd88fb4691b3d3cffc341fa3476 (patch) | |
| tree | ba5fafdc377011644cab9ed004c42e3ba5cfb344 | |
| parent | c92b4959179da8e030599e00250dcee728b392af (diff) | |
Zigzag line to satin (#2131)
| -rw-r--r-- | lib/extensions/__init__.py | 2 | ||||
| -rw-r--r-- | lib/extensions/zigzag_line_to_satin.py | 145 | ||||
| -rw-r--r-- | templates/zigzag_line_to_satin.xml | 43 |
3 files changed, 190 insertions, 0 deletions
diff --git a/lib/extensions/__init__.py b/lib/extensions/__init__.py index fc70fcef..cc47f151 100644 --- a/lib/extensions/__init__.py +++ b/lib/extensions/__init__.py @@ -33,6 +33,7 @@ from .lettering_force_lock_stitches import LetteringForceLockStitches from .lettering_generate_json import LetteringGenerateJson from .lettering_remove_kerning import LetteringRemoveKerning from .letters_to_font import LettersToFont +from .zigzag_line_to_satin import ZigzagLineToSatin from .object_commands import ObjectCommands from .object_commands_toggle_visibility import ObjectCommandsToggleVisibility from .output import Output @@ -73,6 +74,7 @@ __all__ = extensions = [StitchPlanPreview, CommandsScaleSymbols, ConvertToSatin, StrokeToLpeSatin, + ZigzagLineToSatin, ConvertToStroke, JumpToStroke, FillToStroke, diff --git a/lib/extensions/zigzag_line_to_satin.py b/lib/extensions/zigzag_line_to_satin.py new file mode 100644 index 00000000..94a901c0 --- /dev/null +++ b/lib/extensions/zigzag_line_to_satin.py @@ -0,0 +1,145 @@ +# 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 ..elements import Stroke +from ..i18n import _ +from .base import InkstitchExtension + + +class ZigzagLineToSatin(InkstitchExtension): + """Convert a satin column into a running stitch.""" + def __init__(self, *args, **kwargs): + InkstitchExtension.__init__(self, *args, **kwargs) + self.arg_parser.add_argument("--zigzag_to_satin", type=str, default=None) + self.arg_parser.add_argument("--options", type=str, default=None) + self.arg_parser.add_argument("--info", type=str, default=None) + + self.arg_parser.add_argument("-s", "--smoothing", type=inkex.Boolean, default=True, dest="smoothing") + self.arg_parser.add_argument("-p", "--pattern", type=str, default="square", dest="pattern") + self.arg_parser.add_argument("-r", "--rungs", type=inkex.Boolean, default=True, dest="rungs") + self.arg_parser.add_argument("-l", "--reduce-rungs", type=inkex.Boolean, default=False, dest="reduce_rungs") + + def effect(self): + if not self.svg.selection or not self.get_elements(): + inkex.errormsg(_("Please select at least one stroke.")) + return + + if not any(isinstance(item, Stroke) for item in self.elements): + # L10N: Convert To Satin extension, user selected one or more objects that were not lines. + inkex.errormsg(_("Please select at least one stroke to convert to a satin column.")) + return + + for element in self.elements: + d = [] + point_list = list(element.node.get_path().end_points) + rails, rungs = self._get_rails_and_rungs(point_list) + + if self.options.rungs: + if self.options.reduce_rungs and len(rungs) > 2: + rungs = rungs[0::2] + d.extend(self._rung_path(rungs)) + if not self.options.smoothing: + for rail in rails: + d.append('M ' + ' '.join([str(point) for point in rail])) + else: + d.append(self._smooth_path(rails)) + + element.node.set('d', " ".join(d)) + element.set_param('satin_column', True) + # remove dashes + element.update_dash(False) + + def _get_rails_and_rungs(self, point_list): + if self.options.pattern == "sawtooth": + # sawtooth pattern: |/|/|/| + rails = [point_list[0::2], point_list[1::2]] + rungs = list(zip(point_list[1::2], point_list[:-1:2])) + return rails, rungs + elif self.options.pattern == "zigzag": + # zigzag pattern: VVVVV + rails = [point_list[0::2], point_list[1::2]] + rail_points = [[], []] + for i, rail in enumerate(rails): + for j, point in enumerate(rail): + if j == 0 or point in point_list[2::len(point_list)-3]: + rail_points[i].append(point) + continue + p0 = rail[j-1] + rail_points[i].append(inkex.DirectedLineSegment(p0, point).point_at_ratio(0.5)) + rail_points[i].append(point) + rungs = list(zip(*rail_points)) + return rail_points, rungs + else: + # square pattern: |_|▔|_|▔| + point_list = [point_list[i:i+4] for i in range(0, len(point_list), 4)] + + rungs = [] + rails = [[], []] + for i, points in enumerate(point_list): + if len(points) <= 1: + break + + elif len(points) < 4 and len(points) > 1: + rails[0].append(points[0]) + rails[1].append(points[1]) + rungs.append([points[0], points[1]]) + break + + rails[0].extend([points[0], points[3]]) + rails[1].extend([points[1], points[2]]) + rungs.extend([[points[0], points[1]], [points[2], points[3]]]) + return rails, rungs + + def _smooth_path(self, rails): + path_commands = [] + smoothing = 0.2 + for rail in rails: + for i, point in enumerate(rail): + if i == 0: + path_commands.append(inkex.paths.Move(*point)) + else: + # get the two previous points and the next point for handle calculation + if i < 2: + prev_prev = rail[i - 1] + else: + prev_prev = rail[i-2] + prev = rail[i-1] + if i > len(rail) - 2: + next = point + else: + next = rail[i+1] + + # get length of handles + length = inkex.DirectedLineSegment(point, prev).length * smoothing + + # get handle positions + start = inkex.DirectedLineSegment(prev_prev, point) + end = inkex.DirectedLineSegment(next, prev) + if not start.length == 0: + start = start.parallel(*prev).point_at_length(start.length - length) + else: + start = start.start + if not end.length == 0: + end = end.parallel(*point).point_at_length(end.length - length) + else: + end = end.start + + # generate curves + path_commands.append(inkex.paths.Curve(*start, *end, *point)) + return str(inkex.Path(path_commands)) + + def _rung_path(self, rungs): + if len(rungs) < 3: + return [] + d = [] + rungs = rungs[1:-1] + for point0, point1 in rungs: + line = inkex.DirectedLineSegment(point0, point1) + point0 = line.point_at_length(-0.3) + point1 = line.point_at_length(line.length + 0.3) + d.append(f'M {point0[0]}, {point0[1]} {point1[0]}, {point1[1]}') + return d diff --git a/templates/zigzag_line_to_satin.xml b/templates/zigzag_line_to_satin.xml new file mode 100644 index 00000000..b57baabb --- /dev/null +++ b/templates/zigzag_line_to_satin.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="UTF-8"?> +<inkscape-extension translationdomain="inkstitch" xmlns="http://www.inkscape.org/namespace/inkscape/extension"> + <name>Zig-Zag Line to Satin</name> + <id>org.inkstitch.zigzag_line_to_satin</id> + <param name="extension" type="string" gui-hidden="true">zigzag_line_to_satin</param> + <param name="zigzag_to_satin" type="notebook"> + <page name="options" gui-text="Options"> + <label>Converts a zigzag line into a satin column.</label> + <param name="pattern" type="optiongroup" appearance="combo" gui-text="Line Pattern"> + <option value="square">Square</option> + <option value="sawtooth">Sawtooth</option> + <option value="zigzag">Zigzag</option> + </param> + <param name="smoothing" type="boolean" gui-text="Smoothing">true</param> + <param name="rungs" type="boolean" gui-text="Add rungs">true</param> + <param indent="1" name="reduce-rungs" type="boolean" gui-text="Reduce number of rungs">false</param> + </page> + <page name="info" gui-text="Help"> + <label appearance="header">This extension converts a zigzag line into a satin column.</label> + <spacer /> + <label appearance="header">Line Pattern</label> + <label>▻ Always start and end with a rung.</label> + <spacer /> + <label>Square: |_|▔|_|▔|</label> + <label>Sawtooth: |\|\|\|</label> + <label>Zigzag: |\/\/\/|</label> + <spacer /> + <label>Get more information on our website</label> + <label appearance="url">https://inkstitch.org/docs/satin-tools/#zigzag-line-to-satin</label> + </page> + </param> + <effect> + <object-type>all</object-type> + <effects-menu> + <submenu name="Ink/Stitch" translatable="no"> + <submenu name="Tools: Satin" /> + </submenu> + </effects-menu> + </effect> + <script> + {{ command_tag | safe }} + </script> +</inkscape-extension> |
