kopia lustrzana https://github.com/inkstitch/inkstitch
Improve satin guided ripple stitch and add stitch grid first option (#3436)
* ripple stitch: add stitch grid first option * introduce an anchor line to fine tune satin guided rippleslexelby/development-extensions
rodzic
c08e17b1f8
commit
160ef32d43
|
@ -236,16 +236,23 @@ class Stroke(EmbroideryElement):
|
|||
return
|
||||
return max(min_dist, 0.01)
|
||||
|
||||
_satin_guided_pattern_options = [
|
||||
ParamOption('default', _('Line count / Minimum line distance')),
|
||||
ParamOption('render_at_rungs', _('Render at rungs')),
|
||||
ParamOption('adaptive', _('Adaptive + minimum line distance')),
|
||||
]
|
||||
|
||||
@property
|
||||
@param('render_at_rungs',
|
||||
_('Render at rungs'),
|
||||
tooltip=_('Position satin guided pattern at rungs.'),
|
||||
type='boolean',
|
||||
@param('satin_guide_pattern_position',
|
||||
_('Pattern position'),
|
||||
tooltip=_('Pattern position for satin guided ripples.'),
|
||||
type='combo',
|
||||
options=_satin_guided_pattern_options,
|
||||
default='default',
|
||||
select_items=[('stroke_method', 'ripple_stitch')],
|
||||
default=False,
|
||||
sort_index=9)
|
||||
def render_at_rungs(self):
|
||||
return self.get_boolean_param('render_at_rungs', False)
|
||||
def satin_guide_pattern_position(self):
|
||||
return self.get_param('satin_guide_pattern_position', 'line_count')
|
||||
|
||||
@property
|
||||
@param('staggers',
|
||||
|
@ -257,7 +264,7 @@ class Stroke(EmbroideryElement):
|
|||
type='int',
|
||||
select_items=[('stroke_method', 'ripple_stitch')],
|
||||
default=0,
|
||||
sort_index=9)
|
||||
sort_index=15)
|
||||
def staggers(self):
|
||||
return self.get_float_param("staggers", 1)
|
||||
|
||||
|
@ -268,7 +275,7 @@ class Stroke(EmbroideryElement):
|
|||
type='int',
|
||||
default=0,
|
||||
select_items=[('stroke_method', 'ripple_stitch')],
|
||||
sort_index=10)
|
||||
sort_index=16)
|
||||
@cache
|
||||
def skip_start(self):
|
||||
return abs(self.get_int_param("skip_start", 0))
|
||||
|
@ -280,7 +287,7 @@ class Stroke(EmbroideryElement):
|
|||
type='int',
|
||||
default=0,
|
||||
select_items=[('stroke_method', 'ripple_stitch')],
|
||||
sort_index=11)
|
||||
sort_index=17)
|
||||
@cache
|
||||
def skip_end(self):
|
||||
return abs(self.get_int_param("skip_end", 0))
|
||||
|
@ -292,7 +299,7 @@ class Stroke(EmbroideryElement):
|
|||
type='boolean',
|
||||
select_items=[('stroke_method', 'ripple_stitch')],
|
||||
default=True,
|
||||
sort_index=12)
|
||||
sort_index=18)
|
||||
def flip_copies(self):
|
||||
return self.get_boolean_param('flip_copies', True)
|
||||
|
||||
|
@ -303,7 +310,7 @@ class Stroke(EmbroideryElement):
|
|||
type='float',
|
||||
default=1,
|
||||
select_items=[('stroke_method', 'ripple_stitch')],
|
||||
sort_index=13)
|
||||
sort_index=19)
|
||||
@cache
|
||||
def exponent(self):
|
||||
return max(self.get_float_param("exponent", 1), 0.1)
|
||||
|
@ -315,7 +322,7 @@ class Stroke(EmbroideryElement):
|
|||
type='boolean',
|
||||
default=False,
|
||||
select_items=[('stroke_method', 'ripple_stitch')],
|
||||
sort_index=14)
|
||||
sort_index=20)
|
||||
@cache
|
||||
def flip_exponent(self):
|
||||
return self.get_boolean_param("flip_exponent", False)
|
||||
|
@ -327,7 +334,7 @@ class Stroke(EmbroideryElement):
|
|||
type='boolean',
|
||||
default=False,
|
||||
select_items=[('stroke_method', 'ripple_stitch')],
|
||||
sort_index=15)
|
||||
sort_index=21)
|
||||
@cache
|
||||
def reverse(self):
|
||||
return self.get_boolean_param("reverse", False)
|
||||
|
@ -349,7 +356,7 @@ class Stroke(EmbroideryElement):
|
|||
options=_reverse_rails_options,
|
||||
default='automatic',
|
||||
select_items=[('stroke_method', 'ripple_stitch')],
|
||||
sort_index=16)
|
||||
sort_index=22)
|
||||
def reverse_rails(self):
|
||||
return self.get_param('reverse_rails', 'automatic')
|
||||
|
||||
|
@ -361,11 +368,23 @@ class Stroke(EmbroideryElement):
|
|||
default=0,
|
||||
unit='mm',
|
||||
select_items=[('stroke_method', 'ripple_stitch')],
|
||||
sort_index=16)
|
||||
sort_index=23)
|
||||
@cache
|
||||
def grid_size(self):
|
||||
return abs(self.get_float_param("grid_size_mm", 0))
|
||||
|
||||
@property
|
||||
@param('grid_first',
|
||||
_('Stitch grid first'),
|
||||
tooltip=_('Reverse the stitch paths, so that the grid will be stitched first'),
|
||||
type='boolean',
|
||||
default=False,
|
||||
select_items=[('stroke_method', 'ripple_stitch')],
|
||||
sort_index=24)
|
||||
@cache
|
||||
def grid_first(self):
|
||||
return self.get_boolean_param("grid_first", False)
|
||||
|
||||
@property
|
||||
@param('scale_axis',
|
||||
_('Scale axis'),
|
||||
|
@ -375,7 +394,7 @@ class Stroke(EmbroideryElement):
|
|||
# 0: xy, 1: x, 2: y, 3: none
|
||||
options=["X Y", "X", "Y", _("None")],
|
||||
select_items=[('stroke_method', 'ripple_stitch')],
|
||||
sort_index=18)
|
||||
sort_index=25)
|
||||
def scale_axis(self):
|
||||
return self.get_int_param('scale_axis', 0)
|
||||
|
||||
|
@ -387,7 +406,7 @@ class Stroke(EmbroideryElement):
|
|||
unit='%',
|
||||
default=100,
|
||||
select_items=[('stroke_method', 'ripple_stitch')],
|
||||
sort_index=18)
|
||||
sort_index=26)
|
||||
def scale_start(self):
|
||||
return self.get_float_param('scale_start', 100.0)
|
||||
|
||||
|
@ -399,7 +418,7 @@ class Stroke(EmbroideryElement):
|
|||
unit='%',
|
||||
default=0.0,
|
||||
select_items=[('stroke_method', 'ripple_stitch')],
|
||||
sort_index=19)
|
||||
sort_index=27)
|
||||
def scale_end(self):
|
||||
return self.get_float_param('scale_end', 0.0)
|
||||
|
||||
|
@ -410,7 +429,7 @@ class Stroke(EmbroideryElement):
|
|||
type='boolean',
|
||||
default=True,
|
||||
select_items=[('stroke_method', 'ripple_stitch')],
|
||||
sort_index=20)
|
||||
sort_index=30)
|
||||
@cache
|
||||
def rotate_ripples(self):
|
||||
return self.get_boolean_param("rotate_ripples", True)
|
||||
|
@ -423,7 +442,7 @@ class Stroke(EmbroideryElement):
|
|||
default=0,
|
||||
options=(_("flat"), _("point")),
|
||||
select_items=[('stroke_method', 'ripple_stitch')],
|
||||
sort_index=21)
|
||||
sort_index=31)
|
||||
@cache
|
||||
def join_style(self):
|
||||
return self.get_int_param('join_style', 0)
|
||||
|
@ -651,6 +670,16 @@ class Stroke(EmbroideryElement):
|
|||
return guide_lines['satin'][0]
|
||||
return guide_lines['stroke'][0]
|
||||
|
||||
@cache
|
||||
def get_anchor_line(self):
|
||||
anchor_lines = get_marker_elements(self.node, "anchor-line", False, True, False)
|
||||
# No or empty guide line
|
||||
if not anchor_lines or not anchor_lines['stroke']:
|
||||
return None
|
||||
|
||||
# ignore multiple anchor lines
|
||||
return anchor_lines['stroke'][0].geoms[0]
|
||||
|
||||
def _representative_point(self):
|
||||
# if we just take the center of a line string we could end up on some point far away from the actual line
|
||||
try:
|
||||
|
|
|
@ -58,6 +58,7 @@ from .remove_embroidery_settings import RemoveEmbroiderySettings
|
|||
from .reorder import Reorder
|
||||
from .satin_multicolor import SatinMulticolor
|
||||
from .select_elements import SelectElements
|
||||
from .selection_to_anchor_line import SelectionToAnchorLine
|
||||
from .selection_to_guide_line import SelectionToGuideLine
|
||||
from .selection_to_pattern import SelectionToPattern
|
||||
from .simulator import Simulator
|
||||
|
@ -128,6 +129,7 @@ __all__ = extensions = [About,
|
|||
Reorder,
|
||||
SatinMulticolor,
|
||||
SelectElements,
|
||||
SelectionToAnchorLine,
|
||||
SelectionToGuideLine,
|
||||
SelectionToPattern,
|
||||
Simulator,
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
# 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 ..i18n import _
|
||||
from ..marker import set_marker
|
||||
from ..svg.tags import EMBROIDERABLE_TAGS
|
||||
from .base import InkstitchExtension
|
||||
|
||||
|
||||
class SelectionToAnchorLine(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 anchor line."))
|
||||
return
|
||||
|
||||
for pattern in self.get_nodes():
|
||||
if pattern.tag in EMBROIDERABLE_TAGS:
|
||||
set_marker(pattern, 'start', 'anchor-line')
|
|
@ -12,7 +12,7 @@ from shapely import geometry as shgeo
|
|||
from .svg.tags import EMBROIDERABLE_TAGS
|
||||
from .utils import cache, get_bundled_dir
|
||||
|
||||
MARKER = ['pattern', 'guide-line']
|
||||
MARKER = ['anchor-line', 'pattern', 'guide-line']
|
||||
|
||||
|
||||
def ensure_marker(svg, marker):
|
||||
|
|
|
@ -41,6 +41,8 @@ def ripple_stitch(stroke):
|
|||
|
||||
if stitches and stroke.grid_size != 0:
|
||||
stitches.extend(_do_grid(stroke, helper_lines, skip_start, skip_end, is_linear, stitches[-1]))
|
||||
if stroke.grid_first:
|
||||
stitches = stitches[::-1]
|
||||
|
||||
return _repeat_coords(stitches, stroke.repeats)
|
||||
|
||||
|
@ -306,7 +308,7 @@ def _get_guided_helper_lines(stroke, outline, max_distance):
|
|||
guide_line = stroke.get_guide_line()
|
||||
if isinstance(guide_line, SatinColumn):
|
||||
# satin type guide line
|
||||
return _generate_satin_guide_helper_lines(stroke, outline, guide_line)
|
||||
return generate_satin_guide_helper_lines(stroke, outline, guide_line)
|
||||
else:
|
||||
# simple guide line
|
||||
return _generate_guided_helper_lines(stroke, outline, max_distance, guide_line.geoms[0])
|
||||
|
@ -325,7 +327,7 @@ def _generate_guided_helper_lines(stroke, outline, max_distance, guide_line):
|
|||
center = outline.centroid
|
||||
center = InkstitchPoint(center.x, center.y)
|
||||
|
||||
if stroke.render_at_rungs:
|
||||
if stroke.satin_guide_pattern_position == "render_at_rungs":
|
||||
count = len(guide_line.coords)
|
||||
else:
|
||||
count = _get_guided_line_count(stroke, guide_line)
|
||||
|
@ -340,7 +342,7 @@ def _generate_guided_helper_lines(stroke, outline, max_distance, guide_line):
|
|||
for i in range(count):
|
||||
check_stop_flag()
|
||||
|
||||
if stroke.render_at_rungs:
|
||||
if stroke.satin_guide_pattern_position == "render_at_rungs":
|
||||
# Requires the guide line to be defined as manual stitch
|
||||
guide_point = InkstitchPoint(*guide_line.coords[i])
|
||||
else:
|
||||
|
@ -369,11 +371,38 @@ def _get_start_rotation(line):
|
|||
return atan2(point1.y - point0.y, point1.x - point0.x)
|
||||
|
||||
|
||||
def _generate_satin_guide_helper_lines(stroke, outline, guide_line):
|
||||
def generate_satin_guide_helper_lines(stroke, outline, guide_line):
|
||||
anchor_line = stroke.get_anchor_line()
|
||||
if anchor_line:
|
||||
# position, rotation and scale defined by anchor line
|
||||
outline0 = InkstitchPoint(*anchor_line.coords[0])
|
||||
outline1 = InkstitchPoint(*anchor_line.coords[-1])
|
||||
else:
|
||||
# position rotation and scale defined by line end points
|
||||
outline_coords = outline.coords
|
||||
outline0 = InkstitchPoint(*outline_coords[0])
|
||||
outline1 = InkstitchPoint(*outline_coords[-1])
|
||||
if outline0 == outline1:
|
||||
return _generate_simple_satin_guide_helper_lines(stroke, outline, guide_line)
|
||||
|
||||
outline_width = (outline1 - outline0).length()
|
||||
outline_rotation = atan2(outline1.y - outline0.y, outline1.x - outline0.x)
|
||||
|
||||
if stroke.satin_guide_pattern_position == "adaptive":
|
||||
return _generate_satin_guide_helper_lines_with_varying_pattern_distance(
|
||||
stroke, guide_line, outline, outline0, outline_width, outline_rotation
|
||||
)
|
||||
else:
|
||||
return _generate_satin_guide_helper_lines_with_constant_pattern_distance(
|
||||
stroke, guide_line, outline, outline0, outline_width, outline_rotation
|
||||
)
|
||||
|
||||
|
||||
def _generate_simple_satin_guide_helper_lines(stroke, outline, guide_line):
|
||||
count = _get_guided_line_count(stroke, guide_line.center_line)
|
||||
|
||||
spacing = guide_line.center_line.length / max(1, count - 1)
|
||||
if stroke.render_at_rungs:
|
||||
if stroke.satin_guide_pattern_position == "render_at_rungs":
|
||||
sections = guide_line.flattened_sections
|
||||
pairs = []
|
||||
for (rail0, rail1) in sections:
|
||||
|
@ -413,6 +442,70 @@ def _generate_satin_guide_helper_lines(stroke, outline, guide_line):
|
|||
return _point_dict_to_helper_lines(len(outline.coords), line_point_dict)
|
||||
|
||||
|
||||
def _generate_satin_guide_helper_lines_with_constant_pattern_distance(stroke, guide_line, outline, outline0, outline_width, outline_rotation):
|
||||
# add scaled and rotated outlines along the satin column guide line
|
||||
if stroke.satin_guide_pattern_position == "render_at_rungs":
|
||||
sections = guide_line.flattened_sections
|
||||
pairs = []
|
||||
for (rail0, rail1) in sections:
|
||||
pairs.append((rail0[-1], rail1[-1]))
|
||||
else:
|
||||
count = _get_guided_line_count(stroke, guide_line.center_line)
|
||||
spacing = guide_line.center_line.length / max(1, count - 1)
|
||||
pairs = guide_line.plot_points_on_rails(spacing)
|
||||
|
||||
if pairs[0] == pairs[-1]:
|
||||
pairs = pairs[:-1]
|
||||
|
||||
line_point_dict = defaultdict(list)
|
||||
for i, (point0, point1) in enumerate(pairs):
|
||||
check_stop_flag()
|
||||
|
||||
# move to point0, rotate and scale so the other point hits point1
|
||||
scaling = (point1 - point0).length() / outline_width
|
||||
rotation = atan2(point1.y - point0.y, point1.x - point0.x)
|
||||
rotation = rotation - outline_rotation
|
||||
translation = point0 - outline0
|
||||
transformed_outline = _transform_outline(translation, rotation, scaling, outline, Point(point0), 0)
|
||||
|
||||
# outline to helper line points
|
||||
for j, point in enumerate(transformed_outline.coords):
|
||||
line_point_dict[j].append(InkstitchPoint(point[0], point[1]))
|
||||
|
||||
return _point_dict_to_helper_lines(len(outline.coords), line_point_dict)
|
||||
|
||||
|
||||
def _generate_satin_guide_helper_lines_with_varying_pattern_distance(stroke, guide_line, outline, outline0, outline_width, outline_rotation):
|
||||
# rotate pattern and get the pattern width
|
||||
minx, miny, maxx, maxy = _transform_outline(Point([0, 0]), outline_rotation, 1, outline, Point(outline0), 0).bounds
|
||||
pattern_width = maxx - minx
|
||||
|
||||
distance = 0
|
||||
line_point_dict = defaultdict(list)
|
||||
while True:
|
||||
if distance > guide_line.center_line.length:
|
||||
break
|
||||
check_stop_flag()
|
||||
cut_point = guide_line.center_line.interpolate(distance)
|
||||
point0, point1 = guide_line.find_cut_points(*cut_point.coords)
|
||||
|
||||
# move to point0, rotate and scale so the other point hits point1
|
||||
scaling = (point1 - point0).length() / outline_width
|
||||
rotation = atan2(point1.y - point0.y, point1.x - point0.x)
|
||||
rotation = rotation - outline_rotation
|
||||
translation = point0 - outline0
|
||||
transformed_outline = _transform_outline(translation, rotation, scaling, outline, Point(point0), 0)
|
||||
|
||||
min_distance = stroke.min_line_dist or 0
|
||||
distance += max(1, (pattern_width * scaling) + min_distance)
|
||||
|
||||
# outline to helper line points
|
||||
for j, point in enumerate(transformed_outline.coords):
|
||||
line_point_dict[j].append(InkstitchPoint(point[0], point[1]))
|
||||
|
||||
return _point_dict_to_helper_lines(len(outline.coords), line_point_dict)
|
||||
|
||||
|
||||
def _transform_outline(translation, rotation, scaling, outline, origin, scale_axis):
|
||||
# transform
|
||||
transformed_outline = translate(outline, translation.x, translation.y)
|
||||
|
|
|
@ -122,7 +122,7 @@ inkstitch_attribs = [
|
|||
'flip_copies',
|
||||
'line_count',
|
||||
'min_line_dist_mm',
|
||||
'render_at_rungs',
|
||||
'satin_guide_pattern_position',
|
||||
'exponent',
|
||||
'flip_exponent',
|
||||
'skip_start',
|
||||
|
@ -132,6 +132,7 @@ inkstitch_attribs = [
|
|||
'scale_end',
|
||||
'rotate_ripples',
|
||||
'grid_size_mm',
|
||||
'grid_first',
|
||||
# satin column
|
||||
'satin_column',
|
||||
'satin_method',
|
||||
|
|
|
@ -16,6 +16,25 @@
|
|||
xmlns:inkstitch="http://inkstitch.org/namespace">
|
||||
<defs
|
||||
id="defs1">
|
||||
<marker
|
||||
refX="10"
|
||||
refY="5"
|
||||
orient="auto"
|
||||
id="inkstitch-anchor-line-marker"
|
||||
markerUnits="userSpaceOnUse"
|
||||
markerWidth="0.5"
|
||||
viewBox="0 0 1 1">
|
||||
<g
|
||||
id="inkstitch-anchor-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-anchor-marker-circle" />
|
||||
<path
|
||||
id="inkstitch-anchor-marker-anchor"
|
||||
d="M 5.2906995,1.4202597 C 4.8679006,1.4083964 4.4823552,1.8090635 4.5397442,2.2343062 4.568792,2.5148029 4.7793023,2.7587002 5.0437779,2.8466079 5.0437779,2.9192332 5.0437779,2.9918586 5.0437779,3.0644837 4.757712,3.0652868 4.4715658,3.0628316 4.1855481,3.0656999 3.983847,3.0756357 3.8853404,3.3543656 4.0348752,3.489474 4.1478426,3.6002592 4.31397,3.5512227 4.4554139,3.5621911 4.6515344,3.5621911 4.8476573,3.5621911 5.0437779,3.5621911 5.0437779,5.0224311 5.0437779,6.4826482 5.0437779,7.9428881 5.0096543,8.024302 4.9683829,8.1027557 4.9314507,8.1830222 4.5485281,8.0564269 4.1615026,7.9023189 3.8538855,7.6348557 3.7475473,7.5519503 3.6239924,7.3164515 3.6794837,7.2402006 3.7811339,7.2804256 3.8827819,7.3206736 3.9844344,7.3609216 3.7194356,6.8548158 3.4544369,6.34871 3.1894404,5.8425813 3.018173,6.3946946 2.9111692,6.9738617 2.9541363,7.5536254 3.0251487,7.4780859 3.0961587,7.4025463 3.1671686,7.3270297 3.210932,7.7306569 3.5076174,8.0547518 3.8487157,8.2481441 4.2154106,8.4697145 4.6368556,8.6024135 4.9665311,8.8827497 5.0675274,8.9663434 5.0899483,9.1360779 5.2401555,9.1568903 5.3638962,9.1876385 5.4871069,9.1042742 5.5285504,8.9923876 5.6758342,8.77302 5.9336002,8.6689352 6.1579449,8.546149 6.558449,8.3439683 7.0105734,8.1629441 7.2590462,7.7657878 7.3472866,7.6408676 7.3925713,7.4561491 7.4223649,7.3336154 7.4913096,7.406952 7.5602521,7.4802887 7.6291968,7.5536254 7.6721663,6.9738617 7.5651626,6.3946946 7.3938953,5.8425813 7.1288988,6.34871 6.8639,6.8548158 6.5989012,7.3609216 6.7089682,7.3173464 6.8190352,7.2737711 6.9290999,7.2301959 6.9168144,7.4798528 6.728156,7.6694589 6.5254544,7.7910518 6.2545561,7.9625073 5.9565673,8.0857983 5.6518827,8.1830222 5.6172818,8.0962619 5.5584541,8.0156053 5.5395578,7.9247834 5.5395578,6.4705783 5.5395578,5.0163962 5.5395578,3.5621911 5.8256237,3.561365 6.1117698,3.5638203 6.3977852,3.560952 6.5994887,3.5510392 6.6979976,3.2723093 6.5484582,3.1372009 6.4354885,3.0263929 6.2693634,3.0754521 6.1279195,3.0644837 5.9318012,3.0644837 5.7356784,3.0644837 5.5395578,3.0644837 5.5395578,2.9918586 5.5395578,2.9192332 5.5395578,2.8466079 5.8943848,2.7361898 6.1301614,2.3326085 6.023401,1.9714093 5.9391303,1.6494025 5.6214856,1.4158999 5.2906995,1.4202597 Z M 5.2906995,1.9179901 C 5.457747,1.9056908 5.6057444,2.0890325 5.5308427,2.247202 5.4408929,2.4597086 5.0701226,2.4287081 5.036871,2.1916259 5.0098769,2.043025 5.1461509,1.9119093 5.2906995,1.9179901 Z" />
|
||||
</g>
|
||||
</marker>
|
||||
<marker
|
||||
refX="10"
|
||||
refY="5"
|
||||
|
|
Przed Szerokość: | Wysokość: | Rozmiar: 3.8 KiB Po Szerokość: | Wysokość: | Rozmiar: 7.0 KiB |
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<inkscape-extension translationdomain="inkstitch" xmlns="http://www.inkscape.org/namespace/inkscape/extension">
|
||||
<name>Selection to anchor line</name>
|
||||
<id>org.{{ id_inkstitch }}.selection_to_anchor_line</id>
|
||||
<param name="extension" type="string" gui-hidden="true">selection_to_anchor_line</param>
|
||||
<effect>
|
||||
<object-type>all</object-type>
|
||||
<icon>{{ icon_path }}inx/anchor_line.svg</icon>
|
||||
<menu-tip>Marks selected elements as anchor lines</menu-tip>
|
||||
<effects-menu>
|
||||
<submenu name="{{ menu_inkstitch }}" translatable="no">
|
||||
<submenu name="Edit" />
|
||||
</submenu>
|
||||
</effects-menu>
|
||||
</effect>
|
||||
<script>
|
||||
{{ command_tag | safe }}
|
||||
</script>
|
||||
</inkscape-extension>
|
Ładowanie…
Reference in New Issue