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
|
||||||
return max(min_dist, 0.01)
|
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
|
@property
|
||||||
@param('render_at_rungs',
|
@param('satin_guide_pattern_position',
|
||||||
_('Render at rungs'),
|
_('Pattern position'),
|
||||||
tooltip=_('Position satin guided pattern at rungs.'),
|
tooltip=_('Pattern position for satin guided ripples.'),
|
||||||
type='boolean',
|
type='combo',
|
||||||
|
options=_satin_guided_pattern_options,
|
||||||
|
default='default',
|
||||||
select_items=[('stroke_method', 'ripple_stitch')],
|
select_items=[('stroke_method', 'ripple_stitch')],
|
||||||
default=False,
|
|
||||||
sort_index=9)
|
sort_index=9)
|
||||||
def render_at_rungs(self):
|
def satin_guide_pattern_position(self):
|
||||||
return self.get_boolean_param('render_at_rungs', False)
|
return self.get_param('satin_guide_pattern_position', 'line_count')
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@param('staggers',
|
@param('staggers',
|
||||||
|
@ -257,7 +264,7 @@ class Stroke(EmbroideryElement):
|
||||||
type='int',
|
type='int',
|
||||||
select_items=[('stroke_method', 'ripple_stitch')],
|
select_items=[('stroke_method', 'ripple_stitch')],
|
||||||
default=0,
|
default=0,
|
||||||
sort_index=9)
|
sort_index=15)
|
||||||
def staggers(self):
|
def staggers(self):
|
||||||
return self.get_float_param("staggers", 1)
|
return self.get_float_param("staggers", 1)
|
||||||
|
|
||||||
|
@ -268,7 +275,7 @@ class Stroke(EmbroideryElement):
|
||||||
type='int',
|
type='int',
|
||||||
default=0,
|
default=0,
|
||||||
select_items=[('stroke_method', 'ripple_stitch')],
|
select_items=[('stroke_method', 'ripple_stitch')],
|
||||||
sort_index=10)
|
sort_index=16)
|
||||||
@cache
|
@cache
|
||||||
def skip_start(self):
|
def skip_start(self):
|
||||||
return abs(self.get_int_param("skip_start", 0))
|
return abs(self.get_int_param("skip_start", 0))
|
||||||
|
@ -280,7 +287,7 @@ class Stroke(EmbroideryElement):
|
||||||
type='int',
|
type='int',
|
||||||
default=0,
|
default=0,
|
||||||
select_items=[('stroke_method', 'ripple_stitch')],
|
select_items=[('stroke_method', 'ripple_stitch')],
|
||||||
sort_index=11)
|
sort_index=17)
|
||||||
@cache
|
@cache
|
||||||
def skip_end(self):
|
def skip_end(self):
|
||||||
return abs(self.get_int_param("skip_end", 0))
|
return abs(self.get_int_param("skip_end", 0))
|
||||||
|
@ -292,7 +299,7 @@ class Stroke(EmbroideryElement):
|
||||||
type='boolean',
|
type='boolean',
|
||||||
select_items=[('stroke_method', 'ripple_stitch')],
|
select_items=[('stroke_method', 'ripple_stitch')],
|
||||||
default=True,
|
default=True,
|
||||||
sort_index=12)
|
sort_index=18)
|
||||||
def flip_copies(self):
|
def flip_copies(self):
|
||||||
return self.get_boolean_param('flip_copies', True)
|
return self.get_boolean_param('flip_copies', True)
|
||||||
|
|
||||||
|
@ -303,7 +310,7 @@ class Stroke(EmbroideryElement):
|
||||||
type='float',
|
type='float',
|
||||||
default=1,
|
default=1,
|
||||||
select_items=[('stroke_method', 'ripple_stitch')],
|
select_items=[('stroke_method', 'ripple_stitch')],
|
||||||
sort_index=13)
|
sort_index=19)
|
||||||
@cache
|
@cache
|
||||||
def exponent(self):
|
def exponent(self):
|
||||||
return max(self.get_float_param("exponent", 1), 0.1)
|
return max(self.get_float_param("exponent", 1), 0.1)
|
||||||
|
@ -315,7 +322,7 @@ class Stroke(EmbroideryElement):
|
||||||
type='boolean',
|
type='boolean',
|
||||||
default=False,
|
default=False,
|
||||||
select_items=[('stroke_method', 'ripple_stitch')],
|
select_items=[('stroke_method', 'ripple_stitch')],
|
||||||
sort_index=14)
|
sort_index=20)
|
||||||
@cache
|
@cache
|
||||||
def flip_exponent(self):
|
def flip_exponent(self):
|
||||||
return self.get_boolean_param("flip_exponent", False)
|
return self.get_boolean_param("flip_exponent", False)
|
||||||
|
@ -327,7 +334,7 @@ class Stroke(EmbroideryElement):
|
||||||
type='boolean',
|
type='boolean',
|
||||||
default=False,
|
default=False,
|
||||||
select_items=[('stroke_method', 'ripple_stitch')],
|
select_items=[('stroke_method', 'ripple_stitch')],
|
||||||
sort_index=15)
|
sort_index=21)
|
||||||
@cache
|
@cache
|
||||||
def reverse(self):
|
def reverse(self):
|
||||||
return self.get_boolean_param("reverse", False)
|
return self.get_boolean_param("reverse", False)
|
||||||
|
@ -349,7 +356,7 @@ class Stroke(EmbroideryElement):
|
||||||
options=_reverse_rails_options,
|
options=_reverse_rails_options,
|
||||||
default='automatic',
|
default='automatic',
|
||||||
select_items=[('stroke_method', 'ripple_stitch')],
|
select_items=[('stroke_method', 'ripple_stitch')],
|
||||||
sort_index=16)
|
sort_index=22)
|
||||||
def reverse_rails(self):
|
def reverse_rails(self):
|
||||||
return self.get_param('reverse_rails', 'automatic')
|
return self.get_param('reverse_rails', 'automatic')
|
||||||
|
|
||||||
|
@ -361,11 +368,23 @@ class Stroke(EmbroideryElement):
|
||||||
default=0,
|
default=0,
|
||||||
unit='mm',
|
unit='mm',
|
||||||
select_items=[('stroke_method', 'ripple_stitch')],
|
select_items=[('stroke_method', 'ripple_stitch')],
|
||||||
sort_index=16)
|
sort_index=23)
|
||||||
@cache
|
@cache
|
||||||
def grid_size(self):
|
def grid_size(self):
|
||||||
return abs(self.get_float_param("grid_size_mm", 0))
|
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
|
@property
|
||||||
@param('scale_axis',
|
@param('scale_axis',
|
||||||
_('Scale axis'),
|
_('Scale axis'),
|
||||||
|
@ -375,7 +394,7 @@ class Stroke(EmbroideryElement):
|
||||||
# 0: xy, 1: x, 2: y, 3: none
|
# 0: xy, 1: x, 2: y, 3: none
|
||||||
options=["X Y", "X", "Y", _("None")],
|
options=["X Y", "X", "Y", _("None")],
|
||||||
select_items=[('stroke_method', 'ripple_stitch')],
|
select_items=[('stroke_method', 'ripple_stitch')],
|
||||||
sort_index=18)
|
sort_index=25)
|
||||||
def scale_axis(self):
|
def scale_axis(self):
|
||||||
return self.get_int_param('scale_axis', 0)
|
return self.get_int_param('scale_axis', 0)
|
||||||
|
|
||||||
|
@ -387,7 +406,7 @@ class Stroke(EmbroideryElement):
|
||||||
unit='%',
|
unit='%',
|
||||||
default=100,
|
default=100,
|
||||||
select_items=[('stroke_method', 'ripple_stitch')],
|
select_items=[('stroke_method', 'ripple_stitch')],
|
||||||
sort_index=18)
|
sort_index=26)
|
||||||
def scale_start(self):
|
def scale_start(self):
|
||||||
return self.get_float_param('scale_start', 100.0)
|
return self.get_float_param('scale_start', 100.0)
|
||||||
|
|
||||||
|
@ -399,7 +418,7 @@ class Stroke(EmbroideryElement):
|
||||||
unit='%',
|
unit='%',
|
||||||
default=0.0,
|
default=0.0,
|
||||||
select_items=[('stroke_method', 'ripple_stitch')],
|
select_items=[('stroke_method', 'ripple_stitch')],
|
||||||
sort_index=19)
|
sort_index=27)
|
||||||
def scale_end(self):
|
def scale_end(self):
|
||||||
return self.get_float_param('scale_end', 0.0)
|
return self.get_float_param('scale_end', 0.0)
|
||||||
|
|
||||||
|
@ -410,7 +429,7 @@ class Stroke(EmbroideryElement):
|
||||||
type='boolean',
|
type='boolean',
|
||||||
default=True,
|
default=True,
|
||||||
select_items=[('stroke_method', 'ripple_stitch')],
|
select_items=[('stroke_method', 'ripple_stitch')],
|
||||||
sort_index=20)
|
sort_index=30)
|
||||||
@cache
|
@cache
|
||||||
def rotate_ripples(self):
|
def rotate_ripples(self):
|
||||||
return self.get_boolean_param("rotate_ripples", True)
|
return self.get_boolean_param("rotate_ripples", True)
|
||||||
|
@ -423,7 +442,7 @@ class Stroke(EmbroideryElement):
|
||||||
default=0,
|
default=0,
|
||||||
options=(_("flat"), _("point")),
|
options=(_("flat"), _("point")),
|
||||||
select_items=[('stroke_method', 'ripple_stitch')],
|
select_items=[('stroke_method', 'ripple_stitch')],
|
||||||
sort_index=21)
|
sort_index=31)
|
||||||
@cache
|
@cache
|
||||||
def join_style(self):
|
def join_style(self):
|
||||||
return self.get_int_param('join_style', 0)
|
return self.get_int_param('join_style', 0)
|
||||||
|
@ -651,6 +670,16 @@ class Stroke(EmbroideryElement):
|
||||||
return guide_lines['satin'][0]
|
return guide_lines['satin'][0]
|
||||||
return guide_lines['stroke'][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):
|
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
|
# if we just take the center of a line string we could end up on some point far away from the actual line
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -58,6 +58,7 @@ from .remove_embroidery_settings import RemoveEmbroiderySettings
|
||||||
from .reorder import Reorder
|
from .reorder import Reorder
|
||||||
from .satin_multicolor import SatinMulticolor
|
from .satin_multicolor import SatinMulticolor
|
||||||
from .select_elements import SelectElements
|
from .select_elements import SelectElements
|
||||||
|
from .selection_to_anchor_line import SelectionToAnchorLine
|
||||||
from .selection_to_guide_line import SelectionToGuideLine
|
from .selection_to_guide_line import SelectionToGuideLine
|
||||||
from .selection_to_pattern import SelectionToPattern
|
from .selection_to_pattern import SelectionToPattern
|
||||||
from .simulator import Simulator
|
from .simulator import Simulator
|
||||||
|
@ -128,6 +129,7 @@ __all__ = extensions = [About,
|
||||||
Reorder,
|
Reorder,
|
||||||
SatinMulticolor,
|
SatinMulticolor,
|
||||||
SelectElements,
|
SelectElements,
|
||||||
|
SelectionToAnchorLine,
|
||||||
SelectionToGuideLine,
|
SelectionToGuideLine,
|
||||||
SelectionToPattern,
|
SelectionToPattern,
|
||||||
Simulator,
|
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 .svg.tags import EMBROIDERABLE_TAGS
|
||||||
from .utils import cache, get_bundled_dir
|
from .utils import cache, get_bundled_dir
|
||||||
|
|
||||||
MARKER = ['pattern', 'guide-line']
|
MARKER = ['anchor-line', 'pattern', 'guide-line']
|
||||||
|
|
||||||
|
|
||||||
def ensure_marker(svg, marker):
|
def ensure_marker(svg, marker):
|
||||||
|
|
|
@ -41,6 +41,8 @@ def ripple_stitch(stroke):
|
||||||
|
|
||||||
if stitches and stroke.grid_size != 0:
|
if stitches and stroke.grid_size != 0:
|
||||||
stitches.extend(_do_grid(stroke, helper_lines, skip_start, skip_end, is_linear, stitches[-1]))
|
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)
|
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()
|
guide_line = stroke.get_guide_line()
|
||||||
if isinstance(guide_line, SatinColumn):
|
if isinstance(guide_line, SatinColumn):
|
||||||
# satin type guide line
|
# 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:
|
else:
|
||||||
# simple guide line
|
# simple guide line
|
||||||
return _generate_guided_helper_lines(stroke, outline, max_distance, guide_line.geoms[0])
|
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 = outline.centroid
|
||||||
center = InkstitchPoint(center.x, center.y)
|
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)
|
count = len(guide_line.coords)
|
||||||
else:
|
else:
|
||||||
count = _get_guided_line_count(stroke, guide_line)
|
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):
|
for i in range(count):
|
||||||
check_stop_flag()
|
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
|
# Requires the guide line to be defined as manual stitch
|
||||||
guide_point = InkstitchPoint(*guide_line.coords[i])
|
guide_point = InkstitchPoint(*guide_line.coords[i])
|
||||||
else:
|
else:
|
||||||
|
@ -369,11 +371,38 @@ def _get_start_rotation(line):
|
||||||
return atan2(point1.y - point0.y, point1.x - point0.x)
|
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)
|
count = _get_guided_line_count(stroke, guide_line.center_line)
|
||||||
|
|
||||||
spacing = guide_line.center_line.length / max(1, count - 1)
|
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
|
sections = guide_line.flattened_sections
|
||||||
pairs = []
|
pairs = []
|
||||||
for (rail0, rail1) in sections:
|
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)
|
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):
|
def _transform_outline(translation, rotation, scaling, outline, origin, scale_axis):
|
||||||
# transform
|
# transform
|
||||||
transformed_outline = translate(outline, translation.x, translation.y)
|
transformed_outline = translate(outline, translation.x, translation.y)
|
||||||
|
|
|
@ -122,7 +122,7 @@ inkstitch_attribs = [
|
||||||
'flip_copies',
|
'flip_copies',
|
||||||
'line_count',
|
'line_count',
|
||||||
'min_line_dist_mm',
|
'min_line_dist_mm',
|
||||||
'render_at_rungs',
|
'satin_guide_pattern_position',
|
||||||
'exponent',
|
'exponent',
|
||||||
'flip_exponent',
|
'flip_exponent',
|
||||||
'skip_start',
|
'skip_start',
|
||||||
|
@ -132,6 +132,7 @@ inkstitch_attribs = [
|
||||||
'scale_end',
|
'scale_end',
|
||||||
'rotate_ripples',
|
'rotate_ripples',
|
||||||
'grid_size_mm',
|
'grid_size_mm',
|
||||||
|
'grid_first',
|
||||||
# satin column
|
# satin column
|
||||||
'satin_column',
|
'satin_column',
|
||||||
'satin_method',
|
'satin_method',
|
||||||
|
|
|
@ -16,6 +16,25 @@
|
||||||
xmlns:inkstitch="http://inkstitch.org/namespace">
|
xmlns:inkstitch="http://inkstitch.org/namespace">
|
||||||
<defs
|
<defs
|
||||||
id="defs1">
|
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
|
<marker
|
||||||
refX="10"
|
refX="10"
|
||||||
refY="5"
|
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