Add ripple stitch feature (#1667)

pull/1685/head
Kaalleen 2022-05-24 19:40:30 +02:00 zatwierdzone przez GitHub
rodzic ca07b1b267
commit e968f814f7
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
12 zmienionych plików z 412 dodań i 58 usunięć

Wyświetl plik

@ -171,7 +171,7 @@ jobs:
# with --no-binary argument may fix notary issues as well shapely speedups error issue
pip install -U lxml --no-binary lxml
pip uninstall --yes shapely
pip install -v -U Shapely --no-binary Shapely
pip install -v -U Shapely==1.8.1 --no-binary Shapely
pip install pyinstaller
echo "${{ env.pythonLocation }}/bin" >> $GITHUB_PATH

Wyświetl plik

@ -26,6 +26,9 @@ COMMANDS = {
# L10N command attached to an object
"fill_end": N_("Fill stitch ending position"),
# L10N command attached to an object
"ripple_target": N_("Ripple stitch target position"),
# L10N command attached to an object
"run_start": N_("Auto-route running stitch starting position"),
@ -60,7 +63,8 @@ COMMANDS = {
"stop_position": N_("Jump destination for Stop commands (a.k.a. \"Frame Out position\")."),
}
OBJECT_COMMANDS = ["fill_start", "fill_end", "run_start", "run_end", "satin_start", "satin_end", "stop", "trim", "ignore_object", "satin_cut_point"]
OBJECT_COMMANDS = ["fill_start", "fill_end", "ripple_target", "run_start", "run_end", "satin_start", "satin_end",
"stop", "trim", "ignore_object", "satin_cut_point"]
FREE_MOVEMENT_OBJECT_COMMANDS = ["run_start", "run_end", "satin_start", "satin_end"]
LAYER_COMMANDS = ["ignore_layer"]
GLOBAL_COMMANDS = ["origin", "stop_position"]

Wyświetl plik

@ -7,16 +7,30 @@ import sys
import shapely.geometry
from .element import EmbroideryElement, param
from inkex import Transform
from ..i18n import _
from ..stitch_plan import StitchGroup
from ..stitches import bean_stitch, running_stitch
from ..svg import parse_length_with_units
from ..stitches.ripple_stitch import ripple_stitch
from ..svg import get_node_transform, parse_length_with_units
from ..utils import Point, cache
from .element import EmbroideryElement, param
from .satin_column import SatinColumn
from .validation import ValidationWarning
warned_about_legacy_running_stitch = False
class IgnoreSkipValues(ValidationWarning):
name = _("Ignore skip")
description = _("Skip values are ignored, because there was no line left to embroider.")
steps_to_solve = [
_('* Reduce values of Skip first and last lines or'),
_('* Increase number of lines accordinly in the params dialog.'),
]
class Stroke(EmbroideryElement):
element_name = _("Stroke")
@ -34,15 +48,36 @@ class Stroke(EmbroideryElement):
return self.get_style("stroke-dasharray") is not None
@property
@param('running_stitch_length_mm',
_('Running stitch length'),
tooltip=_('Length of stitches in running stitch mode.'),
unit='mm',
type='float',
default=1.5,
sort_index=3)
def running_stitch_length(self):
return max(self.get_float_param("running_stitch_length_mm", 1.5), 0.01)
@param('stroke_method',
_('Method'),
type='dropdown',
default=0,
# 0: run/simple satin, 1: manual, 2: ripple
options=[_("Running Stitch"), _("Ripple")],
sort_index=0)
def stroke_method(self):
return self.get_int_param('stroke_method', 0)
@property
@param('manual_stitch',
_('Manual stitch placement'),
tooltip=_("Stitch every node in the path. All other options are ignored."),
type='boolean',
default=False,
select_items=[('stroke_method', 0)],
sort_index=1)
def manual_stitch_mode(self):
return self.get_boolean_param('manual_stitch')
@property
@param('repeats',
_('Repeats'),
tooltip=_('Defines how many times to run down and back along the path.'),
type='int',
default="1",
sort_index=2)
def repeats(self):
return max(1, self.get_int_param("repeats", 1))
@property
@param(
@ -53,10 +88,93 @@ class Stroke(EmbroideryElement):
'A value of 2 would quintuple each stitch, etc. Only applies to running stitch.'),
type='int',
default=0,
sort_index=2)
sort_index=3)
def bean_stitch_repeats(self):
return self.get_int_param("bean_stitch_repeats", 0)
@property
@param('running_stitch_length_mm',
_('Running stitch length'),
tooltip=_('Length of stitches in running stitch mode.'),
unit='mm',
type='float',
default=1.5,
sort_index=4)
def running_stitch_length(self):
return max(self.get_float_param("running_stitch_length_mm", 1.5), 0.01)
@property
@param('line_count',
_('Number of lines'),
tooltip=_('Number of lines from start to finish'),
type='int',
default=10,
select_items=[('stroke_method', 1)],
sort_index=5)
@cache
def line_count(self):
return max(self.get_int_param("line_count", 10), 1)
@property
@param('skip_start',
_('Skip first lines'),
tooltip=_('Skip this number of lines at the beginning.'),
type='int',
default=0,
select_items=[('stroke_method', 1)],
sort_index=6)
@cache
def skip_start(self):
return abs(self.get_int_param("skip_start", 0))
@property
@param('skip_end',
_('Skip last lines'),
tooltip=_('Skip this number of lines at the end'),
type='int',
default=0,
select_items=[('stroke_method', 1)],
sort_index=7)
@cache
def skip_end(self):
return abs(self.get_int_param("skip_end", 0))
@property
@param('flip',
_('Flip'),
tooltip=_('Flip outer to inner'),
type='boolean',
default=False,
select_items=[('stroke_method', 1)],
sort_index=8)
@cache
def flip(self):
return self.get_boolean_param("flip", False)
@property
@param('render_grid',
_('Grid distance'),
tooltip=_('Render as grid. Works only with satin type ripple stitches.'),
type='float',
default=0,
select_items=[('stroke_method', 1)],
sort_index=8)
@cache
def render_grid(self):
return abs(self.get_float_param("render_grid", 0))
@property
@param('exponent',
_('Line distance exponent'),
tooltip=_('Increse density towards one side.'),
type='float',
default=1,
select_items=[('stroke_method', 1)],
sort_index=9)
@cache
def exponent(self):
return max(self.get_float_param("exponent", 1), 0.1)
@property
@param('zigzag_spacing_mm',
_('Zig-zag spacing (peak-to-peak)'),
@ -64,22 +182,12 @@ class Stroke(EmbroideryElement):
unit='mm',
type='float',
default=0.4,
sort_index=3)
select_items=[('stroke_method', 0)],
sort_index=5)
@cache
def zigzag_spacing(self):
return max(self.get_float_param("zigzag_spacing_mm", 0.4), 0.01)
@property
@param('repeats',
_('Repeats'),
tooltip=_('Defines how many times to run down and back along the path.'),
type='int',
default="1",
sort_index=1)
def repeats(self):
repeats = self.get_int_param("repeats", 1)
return max(1, repeats)
@property
def paths(self):
path = self.parse_path()
@ -102,18 +210,17 @@ class Stroke(EmbroideryElement):
@cache
def as_multi_line_string(self):
line_strings = [shapely.geometry.LineString(path) for path in self.paths]
return shapely.geometry.MultiLineString(line_strings)
@property
@param('manual_stitch',
_('Manual stitch placement'),
tooltip=_("Stitch every node in the path. Stitch length and zig-zag spacing are ignored."),
type='boolean',
default=False,
sort_index=0)
def manual_stitch_mode(self):
return self.get_boolean_param('manual_stitch')
def get_ripple_target(self):
command = self.get_command('ripple_target')
if command:
pos = [float(command.use.get("x", 0)), float(command.use.get("y", 0))]
transform = get_node_transform(command.use)
pos = Transform(transform).apply_to_point(pos)
return Point(*pos)
else:
return self.shape.centroid
def is_running_stitch(self):
# using stroke width <= 0.5 pixels to indicate running stitch is deprecated in favor of dashed lines
@ -199,23 +306,61 @@ class Stroke(EmbroideryElement):
return StitchGroup(self.color, stitches)
def do_bean_repeats(self, stitches):
return bean_stitch(stitches, self.bean_stitch_repeats)
def to_stitch_groups(self, last_patch):
patches = []
for path in self.paths:
path = [Point(x, y) for x, y in path]
if self.manual_stitch_mode:
patch = StitchGroup(color=self.color, stitches=path, stitch_as_is=True)
elif self.is_running_stitch():
patch = self.running_stitch(path, self.running_stitch_length)
if self.bean_stitch_repeats > 0:
patch.stitches = bean_stitch(patch.stitches, self.bean_stitch_repeats)
else:
patch = self.simple_satin(path, self.zigzag_spacing, self.stroke_width)
# ripple stitch
if self.stroke_method == 1:
lines = self.as_multi_line_string()
points = []
if len(lines.geoms) > 1:
# if render_grid has a number use this, otherwise use running_stitch_length
length = self.render_grid or self.running_stitch_length
# use satin column points for satin like build ripple stitches
points = SatinColumn(self.node).plot_points_on_rails(length, 0)
point_target = self.get_ripple_target()
patch = StitchGroup(
color=self.color,
tags=["ripple_stitch"],
stitches=ripple_stitch(
self.as_multi_line_string(),
point_target,
self.line_count,
points,
self.running_stitch_length,
self.repeats,
self.flip,
self.skip_start,
self.skip_end,
self.render_grid,
self.exponent))
if patch:
if self.bean_stitch_repeats > 0:
patch.stitches = self.do_bean_repeats(patch.stitches)
patches.append(patch)
else:
for path in self.paths:
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)
# running stitch
elif self.is_running_stitch():
patch = self.running_stitch(path, self.running_stitch_length)
if self.bean_stitch_repeats > 0:
patch.stitches = self.do_bean_repeats(patch.stitches)
# simple satin
else:
patch = self.simple_satin(path, self.zigzag_spacing, self.stroke_width)
if patch:
patches.append(patch)
return patches
def validation_warnings(self):
if self.stroke_method == 1 and self.skip_start + self.skip_end >= self.line_count:
yield IgnoreSkipValues(self.shape.centroid)

Wyświetl plik

@ -129,6 +129,7 @@ class ParamsTab(ScrolledPanel):
self.update_choice_widgets((param, selection))
self.settings_grid.Layout()
self.Fit()
self.Layout()
if event:

Wyświetl plik

@ -9,4 +9,5 @@ from .guided_fill import guided_fill
from .running_stitch import *
# Can't put this here because we get a circular import :(
#from auto_satin import auto_satin
# from .auto_satin import auto_satin
# from .ripple_stitch import ripple_stitch

Wyświetl plik

@ -132,7 +132,7 @@ def autorun(elements, preserve_order=False, break_up=None, starting_point=None,
else:
parent = elements[0].node.getparent()
insert_index = parent.index(elements[0].node)
group = create_new_group(parent, insert_index, _("Auto-Run"))
group = create_new_group(parent, insert_index, _("Auto-Route"))
add_elements_to_group(new_elements, group)
if trim:

Wyświetl plik

@ -0,0 +1,173 @@
from collections import defaultdict
from shapely.geometry import LineString, Point
from ..utils.geometry import line_string_to_point_list
from .running_stitch import running_stitch
def ripple_stitch(lines, target, line_count, points, max_stitch_length, repeats, flip, skip_start, skip_end, render_grid, exponent):
'''
Ripple stitch is allowed to cross itself and doesn't care about an equal distance of lines
It is meant to be used with light (not dense) stitching
It will ignore holes in a closed shape. Closed shapes will be filled with a spiral
Open shapes will be stitched back and forth.
If there is only one (open) line or a closed shape the target point will be used.
If more sublines are present interpolation will take place between the first two.
'''
# sort geoms by size
lines = sorted(lines.geoms, key=lambda linestring: linestring.length, reverse=True)
outline = lines[0]
# ignore skip_start and skip_end if both toghether are greater or equal to line_count
if skip_start + skip_end >= line_count:
skip_start = skip_end = 0
if is_closed(outline):
rippled_line = do_circular_ripple(outline, target, line_count, repeats, flip, max_stitch_length, skip_start, skip_end, exponent)
else:
rippled_line = do_linear_ripple(lines, points, target, line_count - 1, repeats, flip, skip_start, skip_end, render_grid, exponent)
return running_stitch(line_string_to_point_list(rippled_line), max_stitch_length)
def do_circular_ripple(outline, target, line_count, repeats, flip, max_stitch_length, skip_start, skip_end, exponent):
# for each point generate a line going to the target point
lines = target_point_lines_normalized_distances(outline, target, flip, max_stitch_length)
# create a list of points for each line
points = get_interpolation_points(lines, line_count, exponent, "circular")
# connect the lines to a spiral towards the target
coords = []
for i in range(skip_start, line_count - skip_end):
for j in range(len(lines)):
coords.append(Point(points[j][i].x, points[j][i].y))
coords = repeat_coords(coords, repeats)
return LineString(coords)
def do_linear_ripple(lines, points, target, line_count, repeats, flip, skip_start, skip_end, render_grid, exponent):
if len(lines) == 1:
helper_lines = target_point_lines(lines[0], target, flip)
else:
helper_lines = []
for start, end in zip(points[0], points[1]):
if flip:
helper_lines.append(LineString([end, start]))
else:
helper_lines.append(LineString([start, end]))
# get linear points along the lines
points = get_interpolation_points(helper_lines, line_count, exponent)
# go back and forth along the lines - flip direction of every second line
coords = []
for i in range(skip_start, len(points[0]) - skip_end):
for j in range(len(helper_lines)):
k = j
if i % 2 != 0:
k = len(helper_lines) - j - 1
coords.append(Point(points[k][i].x, points[k][i].y))
# add helper lines as a grid
# for now only add this to satin type ripples, otherwise it could become to dense at the target point
if len(lines) > 1 and render_grid:
coords.extend(do_grid(helper_lines, line_count - skip_end))
coords = repeat_coords(coords, repeats)
return LineString(coords)
def do_grid(lines, num_lines):
coords = []
if num_lines % 2 == 0:
lines = reversed(lines)
for i, line in enumerate(lines):
line_coords = list(line.coords)
if (i % 2 == 0 and num_lines % 2 == 0) or (i % 2 != 0 and num_lines % 2 != 0):
coords.extend(reversed(line_coords))
else:
coords.extend(line_coords)
return coords
def line_length(line):
return line.length
def is_closed(line):
coords = line.coords
return Point(*coords[0]).distance(Point(*coords[-1])) < 0.05
def target_point_lines(outline, target, flip):
lines = []
for point in outline.coords:
if flip:
lines.append(LineString([point, target]))
else:
lines.append(LineString([target, point]))
return lines
def target_point_lines_normalized_distances(outline, target, flip, max_stitch_length):
lines = []
outline = running_stitch(line_string_to_point_list(outline), max_stitch_length)
for point in outline:
if flip:
lines.append(LineString([target, point]))
else:
lines.append(LineString([point, target]))
return lines
def get_interpolation_points(lines, line_count, exponent, method="linear"):
new_points = defaultdict(list)
count = len(lines) - 1
for i, line in enumerate(lines):
steps = get_steps(line, line_count, exponent)
distance = -1
points = []
for j in range(line_count):
length = line.length * steps[j]
if method == "circular":
if distance == -1:
# the first line makes sure, it is going to be a spiral
distance = (line.length * steps[j+1]) * (i / count)
else:
distance += length - (line.length * steps[j-1])
else:
distance = line.length * steps[j]
points.append(line.interpolate(distance))
if method == "linear":
points.append(Point(*line.coords[-1]))
new_points[i] = points
return new_points
def get_steps(line, total_lines, exponent):
# get_steps is scribbled from the inkscape interpolate extension
# (https://gitlab.com/inkscape/extensions/-/blob/master/interp.py)
steps = [
((i + 1) / (total_lines)) ** exponent
for i in range(total_lines - 1)
]
return [0] + steps + [1]
def repeat_coords(coords, repeats):
final_coords = []
for i in range(repeats):
if i % 2 == 1:
# reverse every other pass
this_coords = coords[::-1]
else:
this_coords = coords[:]
final_coords.extend(this_coords)
return final_coords

Wyświetl plik

@ -63,6 +63,11 @@ inkstitch_attribs = [
'join_style',
'avoid_self_crossing',
'clockwise',
'line_count',
'skip_start',
'skip_end',
'render_grid',
'exponent',
'expand_mm',
'fill_underlay',
'fill_underlay_angle',
@ -80,7 +85,7 @@ inkstitch_attribs = [
'flip',
'expand_mm',
# stroke
'manual_stitch',
'stroke_method',
'bean_stitch_repeats',
'repeats',
'running_stitch_length_mm',
@ -102,7 +107,8 @@ inkstitch_attribs = [
'stroke_first',
# Legacy
'trim_after',
'stop_after'
'stop_after',
'manual_stitch',
]
for attrib in inkstitch_attribs:
INKSTITCH_ATTRIBS[attrib] = inkex.addNS(attrib, 'inkstitch')

Wyświetl plik

@ -8,7 +8,7 @@
backports.functools_lru_cache
wxPython
networkx
shapely==1.8.0
shapely==1.8.2
lxml
appdirs
numpy<=1.17.4

Wyświetl plik

@ -324,6 +324,22 @@
id="inkstitch-autorun_end-path"
d="M -1.5977169,-4.8605484 c -0.00319,1.523e-4 -0.00643,6.284e-4 -0.00955,0.00139 l -1.738218,0.6114515 c -0.044131,0.013274 -0.04771,0.07406 -0.00546,0.092381 l 1.7286718,0.6522048 c 0.042543,0.011464 0.077832,-0.033916 0.055977,-0.072004 -0.075631,-0.1076723 -0.1279528,-0.2256474 -0.1583813,-0.3478501 l 5.3580083,0.0693 C 3.7283489,-3.6574881 3.9289854,-3.5209456 4.163113,-3.51807 4.4929661,-3.51396 4.7679522,-3.7755203 4.7721242,-4.1036793 4.7763142,-4.4318766 4.5079699,-4.70559 4.178155,-4.7096844 3.9431472,-4.7126044 3.7385104,-4.5784741 3.6388043,-4.38223 l -5.3566689,-0.065225 c 0.033509,-0.1204507 0.089391,-0.2361787 0.1679695,-0.3396805 0.019712,-0.034678 -0.00793,-0.077126 -0.047786,-0.073375 z m -2.6203001,0.2119742 c -0.3227531,0.0041 -0.5844387,0.2625539 -0.5884958,0.5856093 -0.00295,0.2329983 0.129063,0.4383262 0.3236143,0.5394287 l -0.065546,5.2964025 c -0.1188053,-0.03344 -0.233209,-0.088553 -0.3359005,-0.1657553 -0.018028,-0.014169 -0.043442,-0.014169 -0.061451,0 -0.016535,0.013426 -0.022582,0.035878 -0.015004,0.055721 l 0.6130875,1.7310434 c 0.013338,0.043896 0.074426,0.047476 0.092855,0.00543 l 0.6608737,-1.7201931 c 0.021243,-0.048142 -0.037912,-0.091505 -0.077832,-0.057054 -0.1085476,0.075489 -0.2269701,0.1273635 -0.3495646,0.1576047 l 0.069641,-5.2950505 c 0.1995845,-0.095713 0.3397855,-0.2989653 0.3427327,-0.5326301 0.00412,-0.3281781 -0.2641734,-0.5964641 -0.5939692,-0.6005585 -0.00519,-7.62e-5 -0.00991,-7.62e-5 -0.015023,0 z m 8.4425639,1.3302136 c -0.020458,-1.333e-4 -0.038925,0.012283 -0.046428,0.03125 l -0.6608735,1.714742 c -0.021243,0.04818 0.037931,0.091524 0.077851,0.057054 0.1072273,-0.074556 0.2244441,-0.1271727 0.3454502,-0.1576044 L 3.8750009,3.6234841 C 3.6760287,3.7194257 3.5366315,3.9202022 3.5336461,4.15341 3.529436,4.4816071 3.7964416,4.7512453 4.1262565,4.7553397 4.4560331,4.759449 4.726962,4.4979085 4.731134,4.1697112 4.7341354,3.934523 4.5996979,3.7276145 4.4020654,3.6275594 L 4.4703294,-1.66612 c 0.1197239,0.033383 0.2338597,0.08802 0.3372785,0.1657745 0.039309,0.032355 0.096166,-0.00834 0.077832,-0.055721 L 4.2709744,-3.2871101 c -0.00748,-0.018949 -0.02595,-0.031384 -0.046428,-0.031251 z M 1.5114302,3.6180947 c -0.037451,6.856e-4 -0.060627,0.040868 -0.042351,0.073356 0.075823,0.1079391 0.1280103,0.2267139 0.1584006,0.3492023 L -3.7305473,3.971372 c -0.096108,-0.1988532 -0.2989079,-0.338138 -0.5338966,-0.3410517 -0.3297958,-0.0041 -0.5994042,0.2615256 -0.6035188,0.5896847 -0.00413,0.3281972 0.2627956,0.6019488 0.5926104,0.6060241 0.2345678,0.00292 0.4394534,-0.1304295 0.5393508,-0.3261024 l 5.3580084,0.063873 C 1.5885549,4.684593 1.5314859,4.7996924 1.4526979,4.90348 1.4299049,4.942272 1.4668789,4.9887 1.5100529,4.975503 L 3.2496085,4.3640511 c 0.043002,-0.015959 0.043002,-0.076441 0,-0.0924 L 1.5250561,3.6194659 c -0.00446,-0.00112 -0.00905,-0.00154 -0.013665,-0.00139 Z" />
</symbol>
<symbol
id="inkstitch_ripple_target"
style="display:inline">
<title
id="inkstitch_title9427-9">Ripple stitch target point</title>
<path
id="inkstitch_circle13166-9"
d="m 9.220113,0.07922893 c -1.9e-6,5.10672897 -4.1398241,9.24654997 -9.24655297,9.24654997 -5.10672933,0 -9.24655213,-4.139821 -9.24655403,-9.24654997 1e-7,-2.45233803 0.9741879,-4.80423503 2.7082531,-6.53830103 1.7340653,-1.734065 4.0859624,-2.708252 6.53830093,-2.708252 5.10673007,0 9.24655277,4.139823 9.24655297,9.24655303 0,0 0,0 0,0"
style="opacity:1;vector-effect:none;fill:#fafafa;fill-opacity:1;fill-rule:evenodd;stroke:#003399;stroke-width:1.06500006;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:3.19500017, 3.19500017;stroke-dashoffset:0;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
style="opacity:1;fill:none;stroke:#000000;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;"
d="m -4.1361006,-3.9974292 8.224564,8.224564 m 0,-8.224564 -8.224564,8.224564 m 9.927927,-4.112282 h -11.63129 m 5.81564501,-5.815645 v 11.63129"
id="inkstitch_rect5371-2-9"
inkscape:connector-curvature="0" />
</symbol>
</defs>
<metadata
id="metadata8380">
@ -458,5 +474,13 @@
width="100%"
height="100%"
transform="translate(37.830849,113.28861)" />
<use
xlink:href="#inkstitch_ripple_target"
id="use37099"
x="0"
y="0"
width="100%"
height="100%"
transform="translate(151.1811,112.79208)" />
</g>
</svg>

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 50 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 51 KiB

Wyświetl plik

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension translationdomain="inkstitch" xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>Autoroute Running Stitch</name>
<name>Auto-Route Running Stitch</name>
<id>org.inkstitch.auto_run</id>
<param name="extension" type="string" gui-hidden="true">auto_run</param>
<effect>
@ -12,7 +12,7 @@
</effects-menu>
</effect>
<param name="options" type="notebook">
<page name="options" gui-text="Autoroute Running Stitch Options">
<page name="options" gui-text="Auto-Route Running Stitch Options">
<spacer />
<param name="break_up" type="boolean" gui-text="Add nodes at intersections">true</param>
<spacer />
@ -21,7 +21,7 @@
<param name="trim" type="boolean" gui-text="Trim jump stitches">false</param>
</page>
<page name="help" gui-text="Help">
<label appearance="header">Autoroute Running Stitch</label>
<label appearance="header">Auto-Route Running Stitch</label>
<label>Add nodes at intersections:</label>
<spacer />
<label indent="1">- Enabled (automatic). Ink/Stitch will add some nodes for better routing. This is the default setting.</label>

Wyświetl plik

@ -6,7 +6,7 @@
<effect>
<object-type>all</object-type>
<effects-menu>
<submenu name="Ink/Stitch">
<submenu name="Ink/Stitch" translatable="no">
<submenu name="Edit" />
</submenu>
</effects-menu>