kopia lustrzana https://github.com/inkstitch/inkstitch
Add object based min stitch length (#2792)
* add object based min stitch length (overwrites global) * add object based minimum jump stitch (overwrites global) * rename patches to stitch_groupspull/2803/head dev-build-claudine-improve_fonts_7
rodzic
ea394f6d3b
commit
8e70f3d2fe
|
@ -20,8 +20,8 @@ def get_stitch_plan():
|
|||
metadata = g.extension.get_inkstitch_metadata()
|
||||
collapse_len = metadata['collapse_len_mm']
|
||||
min_stitch_len = metadata['min_stitch_len_mm']
|
||||
patches = g.extension.elements_to_stitch_groups(g.extension.elements)
|
||||
stitch_plan = stitch_groups_to_stitch_plan(patches, collapse_len=collapse_len, min_stitch_len=min_stitch_len)
|
||||
stitch_groups = g.extension.elements_to_stitch_groups(g.extension.elements)
|
||||
stitch_plan = stitch_groups_to_stitch_plan(stitch_groups, collapse_len=collapse_len, min_stitch_len=min_stitch_len)
|
||||
return jsonify(stitch_plan)
|
||||
except InkstitchException as exc:
|
||||
return jsonify({"error_message": str(exc)}), 500
|
||||
|
|
|
@ -218,6 +218,28 @@ class EmbroideryElement(object):
|
|||
width = convert_length(width)
|
||||
return width * self.stroke_scale
|
||||
|
||||
@property
|
||||
@param('min_stitch_length_mm',
|
||||
_('Minimum stitch length'),
|
||||
tooltip=_('Overwrite global minimum stitch length setting. Shorter stitches than that will be removed.'),
|
||||
type='float',
|
||||
default=None,
|
||||
sort_index=48)
|
||||
@cache
|
||||
def min_stitch_length(self):
|
||||
return self.get_float_param("min_stitch_length_mm")
|
||||
|
||||
@property
|
||||
@param('min_jump_stitch_length_mm',
|
||||
_('Minimum jump stitch length'),
|
||||
tooltip=_('Overwrite global minimum jump stitch length setting. Shorter distances to the next object will have no lock stitches.'),
|
||||
type='float',
|
||||
default=None,
|
||||
sort_index=49)
|
||||
@cache
|
||||
def min_jump_stitch_length(self):
|
||||
return self.get_float_param("min_jump_stitch_length_mm")
|
||||
|
||||
@property
|
||||
@param('ties',
|
||||
_('Allow lock stitches'),
|
||||
|
@ -472,7 +494,7 @@ class EmbroideryElement(object):
|
|||
|
||||
return lock_start, lock_end
|
||||
|
||||
def to_stitch_groups(self, last_patch):
|
||||
def to_stitch_groups(self, last_stitch_group):
|
||||
raise NotImplementedError("%s must implement to_stitch_groups()" % self.__class__.__name__)
|
||||
|
||||
@debug.time
|
||||
|
@ -576,6 +598,10 @@ class EmbroideryElement(object):
|
|||
stitch_groups[-1].trim_after = self.has_command("trim") or self.trim_after
|
||||
stitch_groups[-1].stop_after = self.has_command("stop") or self.stop_after
|
||||
|
||||
for stitch_group in stitch_groups:
|
||||
stitch_group.min_jump_stitch_length = self.min_jump_stitch_length
|
||||
stitch_group.set_minimum_stitch_length(self.min_stitch_length)
|
||||
|
||||
self._save_cached_stitch_groups(stitch_groups, previous_stitch)
|
||||
|
||||
debug.log(f"ending {self.node.get('id')} {self.node.get(INKSCAPE_LABEL)}")
|
||||
|
|
|
@ -27,5 +27,5 @@ class EmptyDObject(EmbroideryElement):
|
|||
def shape(self):
|
||||
return
|
||||
|
||||
def to_stitch_groups(self, last_patch):
|
||||
def to_stitch_groups(self, last_stitch_group):
|
||||
return []
|
||||
|
|
|
@ -714,7 +714,7 @@ class FillStitch(EmbroideryElement):
|
|||
|
||||
def get_starting_point(self, previous_stitch_group):
|
||||
# If there is a "fill_start" Command, then use that; otherwise pick
|
||||
# the point closest to the end of the last patch.
|
||||
# the point closest to the end of the last stitch_group.
|
||||
|
||||
if self.get_command('fill_start'):
|
||||
return self.get_command('fill_start').target_point
|
||||
|
@ -792,18 +792,23 @@ class FillStitch(EmbroideryElement):
|
|||
return stitch_groups
|
||||
|
||||
def do_legacy_fill(self):
|
||||
stitch_lists = legacy_fill(self.shape,
|
||||
self.angle,
|
||||
self.row_spacing,
|
||||
self.end_row_spacing,
|
||||
self.max_stitch_length,
|
||||
self.flip,
|
||||
self.staggers,
|
||||
self.skip_last)
|
||||
return [StitchGroup(stitches=stitch_list,
|
||||
color=self.color,
|
||||
force_lock_stitches=self.force_lock_stitches,
|
||||
lock_stitches=self.lock_stitches) for stitch_list in stitch_lists]
|
||||
stitch_lists = legacy_fill(
|
||||
self.shape,
|
||||
self.angle,
|
||||
self.row_spacing,
|
||||
self.end_row_spacing,
|
||||
self.max_stitch_length,
|
||||
self.flip,
|
||||
self.staggers,
|
||||
self.skip_last
|
||||
)
|
||||
|
||||
return [StitchGroup(
|
||||
stitches=stitch_list,
|
||||
color=self.color,
|
||||
force_lock_stitches=self.force_lock_stitches,
|
||||
lock_stitches=self.lock_stitches
|
||||
) for stitch_list in stitch_lists]
|
||||
|
||||
def do_underlay(self, shape, starting_point):
|
||||
color = self.color
|
||||
|
@ -833,7 +838,7 @@ class FillStitch(EmbroideryElement):
|
|||
starting_point = underlay.stitches[-1]
|
||||
return [stitch_groups, starting_point]
|
||||
|
||||
def do_auto_fill(self, shape, last_patch, starting_point, ending_point):
|
||||
def do_auto_fill(self, shape, last_stitch_group, starting_point, ending_point):
|
||||
stitch_group = StitchGroup(
|
||||
color=self.color,
|
||||
tags=("auto_fill", "auto_fill_top"),
|
||||
|
@ -851,10 +856,12 @@ class FillStitch(EmbroideryElement):
|
|||
self.skip_last,
|
||||
starting_point,
|
||||
ending_point,
|
||||
self.underpath))
|
||||
self.underpath
|
||||
)
|
||||
)
|
||||
return [stitch_group]
|
||||
|
||||
def do_contour_fill(self, polygon, last_patch, starting_point):
|
||||
def do_contour_fill(self, polygon, last_stitch_group, starting_point):
|
||||
if not starting_point:
|
||||
starting_point = (0, 0)
|
||||
starting_point = shgeo.Point(starting_point)
|
||||
|
@ -894,17 +901,17 @@ class FillStitch(EmbroideryElement):
|
|||
tags=("auto_fill", "auto_fill_top"),
|
||||
stitches=stitches,
|
||||
force_lock_stitches=self.force_lock_stitches,
|
||||
lock_stitches=self.lock_stitches,)
|
||||
lock_stitches=self.lock_stitches)
|
||||
stitch_groups.append(stitch_group)
|
||||
|
||||
return stitch_groups
|
||||
|
||||
def do_guided_fill(self, shape, last_patch, starting_point, ending_point):
|
||||
def do_guided_fill(self, shape, last_stitch_group, starting_point, ending_point):
|
||||
guide_line = self._get_guide_lines()
|
||||
|
||||
# No guide line: fallback to normal autofill
|
||||
if not guide_line:
|
||||
return self.do_auto_fill(shape, last_patch, starting_point, ending_point)
|
||||
return self.do_auto_fill(shape, last_stitch_group, starting_point, ending_point)
|
||||
|
||||
stitch_group = StitchGroup(
|
||||
color=self.color,
|
||||
|
@ -947,11 +954,11 @@ class FillStitch(EmbroideryElement):
|
|||
tags=("meander_fill", "meander_fill_top"),
|
||||
stitches=meander_fill(self, shape, original_shape, i, starting_point, ending_point),
|
||||
force_lock_stitches=self.force_lock_stitches,
|
||||
lock_stitches=self.lock_stitches,
|
||||
lock_stitches=self.lock_stitches
|
||||
)
|
||||
return [stitch_group]
|
||||
|
||||
def do_circular_fill(self, shape, last_patch, starting_point, ending_point):
|
||||
def do_circular_fill(self, shape, last_stitch_group, starting_point, ending_point):
|
||||
# get target position
|
||||
command = self.get_command('ripple_target')
|
||||
if command:
|
||||
|
@ -983,8 +990,9 @@ class FillStitch(EmbroideryElement):
|
|||
tags=("circular_fill", "auto_fill_top"),
|
||||
stitches=stitches,
|
||||
force_lock_stitches=self.force_lock_stitches,
|
||||
lock_stitches=self.lock_stitches,)
|
||||
lock_stitches=self.lock_stitches
|
||||
)
|
||||
return [stitch_group]
|
||||
|
||||
def do_linear_gradient_fill(self, shape, last_patch, start, end):
|
||||
def do_linear_gradient_fill(self, shape, last_stitch_group, start, end):
|
||||
return linear_gradient_fill(self, shape, start, end)
|
||||
|
|
|
@ -29,5 +29,5 @@ class ImageObject(EmbroideryElement):
|
|||
def validation_warnings(self):
|
||||
yield ImageTypeWarning(self.center())
|
||||
|
||||
def to_stitch_groups(self, last_patch):
|
||||
def to_stitch_groups(self, last_stitch_group):
|
||||
return []
|
||||
|
|
|
@ -28,5 +28,5 @@ class MarkerObject(EmbroideryElement):
|
|||
repr_point = next(inkex.Path(self.parse_path()).end_points)
|
||||
yield MarkerWarning(repr_point)
|
||||
|
||||
def to_stitch_groups(self, last_patch):
|
||||
def to_stitch_groups(self, last_stitch_group):
|
||||
return []
|
||||
|
|
|
@ -94,10 +94,10 @@ class Polyline(EmbroideryElement):
|
|||
def validation_warnings(self):
|
||||
yield PolylineWarning(self.path[0][0][0])
|
||||
|
||||
def to_stitch_groups(self, last_patch):
|
||||
patch = StitchGroup(color=self.color, lock_stitches=(None, None))
|
||||
def to_stitch_groups(self, last_stitch_group):
|
||||
stitch_group = StitchGroup(color=self.color, lock_stitches=(None, None))
|
||||
|
||||
for stitch in self.stitches:
|
||||
patch.add_stitch(Point(*stitch))
|
||||
stitch_group.add_stitch(Point(*stitch))
|
||||
|
||||
return [patch]
|
||||
return [stitch_group]
|
||||
|
|
|
@ -1145,7 +1145,8 @@ class SatinColumn(EmbroideryElement):
|
|||
stitch_group = StitchGroup(
|
||||
color=self.color,
|
||||
tags=("satin_column", "satin_column_underlay", "satin_contour_underlay"),
|
||||
stitches=first_side)
|
||||
stitches=first_side
|
||||
)
|
||||
|
||||
self.add_running_stitches(first_side[-1], second_side[0], stitch_group)
|
||||
stitch_group.stitches += second_side
|
||||
|
@ -1172,7 +1173,8 @@ class SatinColumn(EmbroideryElement):
|
|||
return StitchGroup(
|
||||
color=self.color,
|
||||
tags=("satin_column", "satin_column_underlay", "satin_center_walk"),
|
||||
stitches=stitches)
|
||||
stitches=stitches
|
||||
)
|
||||
|
||||
def do_zigzag_underlay(self):
|
||||
# zigzag underlay, usually done at a much lower density than the
|
||||
|
@ -1185,7 +1187,7 @@ class SatinColumn(EmbroideryElement):
|
|||
# "German underlay" described here:
|
||||
# http://www.mrxstitch.com/underlay-what-lies-beneath-machine-embroidery/
|
||||
|
||||
patch = StitchGroup(color=self.color)
|
||||
stitch_group = StitchGroup(color=self.color)
|
||||
|
||||
pairs = self.plot_points_on_rails(self.zigzag_underlay_spacing / 2.0,
|
||||
-self.zigzag_underlay_inset_px,
|
||||
|
@ -1206,12 +1208,12 @@ class SatinColumn(EmbroideryElement):
|
|||
if last_point.distance(point) > max_len:
|
||||
split_points = running_stitch.split_segment_even_dist(last_point, point, max_len)
|
||||
for p in split_points:
|
||||
patch.add_stitch(p)
|
||||
stitch_group.add_stitch(p)
|
||||
last_point = point
|
||||
patch.add_stitch(point)
|
||||
stitch_group.add_stitch(point)
|
||||
|
||||
patch.add_tags(("satin_column", "satin_column_underlay", "satin_zigzag_underlay"))
|
||||
return patch
|
||||
stitch_group.add_tags(("satin_column", "satin_column_underlay", "satin_zigzag_underlay"))
|
||||
return stitch_group
|
||||
|
||||
def do_satin(self):
|
||||
# satin: do a zigzag pattern, alternating between the paths. The
|
||||
|
@ -1222,7 +1224,7 @@ class SatinColumn(EmbroideryElement):
|
|||
|
||||
# print >> dbg, "satin", self.zigzag_spacing, self.pull_compensation
|
||||
|
||||
patch = StitchGroup(color=self.color)
|
||||
stitch_group = StitchGroup(color=self.color)
|
||||
|
||||
# pull compensation is automatically converted from mm to pixels by get_float_param
|
||||
pairs = self.plot_points_on_rails(
|
||||
|
@ -1248,25 +1250,25 @@ class SatinColumn(EmbroideryElement):
|
|||
split_points, _ = self.get_split_points(
|
||||
last_point, a, last_short_point, a_short, max_stitch_length, last_count,
|
||||
length_sigma, random_phase, min_split_length, prng.join_args(seed, 'satin-split', 2 * i), row_num=2 * i, from_end=True)
|
||||
patch.add_stitches(split_points, ("satin_column", "satin_split_stitch"))
|
||||
stitch_group.add_stitches(split_points, ("satin_column", "satin_split_stitch"))
|
||||
|
||||
patch.add_stitch(a_short)
|
||||
patch.stitches[-1].add_tags(("satin_column", "satin_column_edge"))
|
||||
stitch_group.add_stitch(a_short)
|
||||
stitch_group.stitches[-1].add_tags(("satin_column", "satin_column_edge"))
|
||||
|
||||
split_points, last_count = self.get_split_points(
|
||||
a, b, a_short, b_short, max_stitch_length, None,
|
||||
length_sigma, random_phase, min_split_length, prng.join_args(seed, 'satin-split', 2 * i + 1), row_num=2 * i + 1)
|
||||
patch.add_stitches(split_points, ("satin_column", "satin_split_stitch"))
|
||||
stitch_group.add_stitches(split_points, ("satin_column", "satin_split_stitch"))
|
||||
|
||||
patch.add_stitch(b_short)
|
||||
patch.stitches[-1].add_tags(("satin_column", "satin_column_edge"))
|
||||
stitch_group.add_stitch(b_short)
|
||||
stitch_group.stitches[-1].add_tags(("satin_column", "satin_column_edge"))
|
||||
last_point = b
|
||||
last_short_point = b_short
|
||||
|
||||
if self._center_walk_is_odd():
|
||||
patch.stitches = list(reversed(patch.stitches))
|
||||
stitch_group.stitches = list(reversed(stitch_group.stitches))
|
||||
|
||||
return patch
|
||||
return stitch_group
|
||||
|
||||
def do_e_stitch(self):
|
||||
# e stitch: do a pattern that looks like the letter "E". It looks like
|
||||
|
@ -1274,7 +1276,7 @@ class SatinColumn(EmbroideryElement):
|
|||
#
|
||||
# _|_|_|_|_|_|_|_|_|_|_|_|
|
||||
|
||||
patch = StitchGroup(color=self.color)
|
||||
stitch_group = StitchGroup(color=self.color)
|
||||
|
||||
pairs = self.plot_points_on_rails(
|
||||
self.zigzag_spacing,
|
||||
|
@ -1302,21 +1304,21 @@ class SatinColumn(EmbroideryElement):
|
|||
# zigzag spacing is wider than stitch length, subdivide
|
||||
if last_point is not None and max_stitch_length is not None and self.zigzag_spacing > max_stitch_length:
|
||||
points, _ = self.get_split_points(last_point, left, last_point, left, max_stitch_length)
|
||||
patch.add_stitches(points)
|
||||
stitch_group.add_stitches(points)
|
||||
|
||||
patch.add_stitch(a_short, ("edge", "left"))
|
||||
patch.add_stitches(split_points, ("split_stitch",))
|
||||
patch.add_stitch(b_short, ("edge",))
|
||||
patch.add_stitches(split_points[::-1], ("split_stitch",))
|
||||
patch.add_stitch(a_short, ("edge",))
|
||||
stitch_group.add_stitch(a_short, ("edge", "left"))
|
||||
stitch_group.add_stitches(split_points, ("split_stitch",))
|
||||
stitch_group.add_stitch(b_short, ("edge",))
|
||||
stitch_group.add_stitches(split_points[::-1], ("split_stitch",))
|
||||
stitch_group.add_stitch(a_short, ("edge",))
|
||||
|
||||
last_point = a_short
|
||||
|
||||
if self._center_walk_is_odd():
|
||||
patch.stitches = list(reversed(patch.stitches))
|
||||
stitch_group.stitches = list(reversed(stitch_group.stitches))
|
||||
|
||||
patch.add_tags(("satin_column", "e_stitch"))
|
||||
return patch
|
||||
stitch_group.add_tags(("satin_column", "e_stitch"))
|
||||
return stitch_group
|
||||
|
||||
def do_s_stitch(self):
|
||||
# S stitch: do a pattern that looks like the letter "S". It looks like
|
||||
|
@ -1324,7 +1326,7 @@ class SatinColumn(EmbroideryElement):
|
|||
# _ _ _ _ _ _
|
||||
# _| |_| |_| |_| |_| |_| |
|
||||
|
||||
patch = StitchGroup(color=self.color)
|
||||
stitch_group = StitchGroup(color=self.color)
|
||||
|
||||
pairs = self.plot_points_on_rails(
|
||||
self.zigzag_spacing,
|
||||
|
@ -1357,17 +1359,17 @@ class SatinColumn(EmbroideryElement):
|
|||
if last_point is not None and max_stitch_length is not None and self.zigzag_spacing > max_stitch_length:
|
||||
initial_points, _ = self.get_split_points(last_point, points[0], last_point, points[0], max_stitch_length)
|
||||
|
||||
patch.add_stitches(points)
|
||||
stitch_group.add_stitches(points)
|
||||
last_point = points[-1]
|
||||
|
||||
if self._center_walk_is_odd():
|
||||
patch.stitches = list(reversed(patch.stitches))
|
||||
stitch_group.stitches = list(reversed(stitch_group.stitches))
|
||||
|
||||
patch.add_tags(("satin", "s_stitch"))
|
||||
return patch
|
||||
stitch_group.add_tags(("satin", "s_stitch"))
|
||||
return stitch_group
|
||||
|
||||
def do_zigzag(self):
|
||||
patch = StitchGroup(color=self.color)
|
||||
stitch_group = StitchGroup(color=self.color)
|
||||
|
||||
# calculate pairs at double the requested density
|
||||
pairs = self.plot_points_on_rails(
|
||||
|
@ -1401,24 +1403,24 @@ class SatinColumn(EmbroideryElement):
|
|||
split_points, _ = self.get_split_points(
|
||||
last_point, a, last_point_short, a_short, max_stitch_length, None,
|
||||
length_sigma, random_phase, min_split_length, prng.join_args(seed, 'satin-split', 2 * i), row_num=2 * i, from_end=True)
|
||||
patch.add_stitches(split_points, ("satin_column", "zigzag_split_stitch"))
|
||||
stitch_group.add_stitches(split_points, ("satin_column", "zigzag_split_stitch"))
|
||||
|
||||
patch.add_stitch(a_short)
|
||||
stitch_group.add_stitch(a_short)
|
||||
|
||||
split_points, _ = self.get_split_points(
|
||||
a, b, a_short, b_short, max_stitch_length, None,
|
||||
length_sigma, random_phase, min_split_length, prng.join_args(seed, 'satin-split', 2 * i + 1), row_num=2 * i + 1)
|
||||
patch.add_stitches(split_points, ("satin_column", "zigzag_split_stitch"))
|
||||
stitch_group.add_stitches(split_points, ("satin_column", "zigzag_split_stitch"))
|
||||
|
||||
patch.add_stitch(b_short)
|
||||
stitch_group.add_stitch(b_short)
|
||||
|
||||
last_point = b
|
||||
last_point_short = b_short
|
||||
|
||||
if self._center_walk_is_odd():
|
||||
patch.stitches = list(reversed(patch.stitches))
|
||||
stitch_group.stitches = list(reversed(stitch_group.stitches))
|
||||
|
||||
return patch
|
||||
return stitch_group
|
||||
|
||||
def get_split_points(self, *args, **kwargs):
|
||||
if self.split_method == "default":
|
||||
|
@ -1526,15 +1528,17 @@ class SatinColumn(EmbroideryElement):
|
|||
stitch_group += next_stitch_group
|
||||
return stitch_group
|
||||
|
||||
def to_stitch_groups(self, last_patch=None):
|
||||
def to_stitch_groups(self, last_stitch_group=None):
|
||||
# Stitch a variable-width satin column, zig-zagging between two paths.
|
||||
# The algorithm will draw zigzags between each consecutive pair of
|
||||
# beziers. The boundary points between beziers serve as "checkpoints",
|
||||
# allowing the user to control how the zigzags flow around corners.
|
||||
|
||||
stitch_group = StitchGroup(color=self.color,
|
||||
force_lock_stitches=self.force_lock_stitches,
|
||||
lock_stitches=self.lock_stitches)
|
||||
stitch_group = StitchGroup(
|
||||
color=self.color,
|
||||
force_lock_stitches=self.force_lock_stitches,
|
||||
lock_stitches=self.lock_stitches
|
||||
)
|
||||
|
||||
if self.center_walk_underlay:
|
||||
stitch_group += self.do_center_walk()
|
||||
|
|
|
@ -443,11 +443,10 @@ class Stroke(EmbroideryElement):
|
|||
# `self.zigzag_spacing` is the length for a zig and a zag
|
||||
# together (a V shape). Start with running stitch at half
|
||||
# that length:
|
||||
patch = self.running_stitch(path, zigzag_spacing / 2.0, self.running_stitch_tolerance)
|
||||
stitch_group = self.running_stitch(path, zigzag_spacing / 2.0, self.running_stitch_tolerance)
|
||||
stitch_group.stitches = zigzag_stitch(stitch_group.stitches, zigzag_spacing, stroke_width, pull_compensation)
|
||||
|
||||
patch.stitches = zigzag_stitch(patch.stitches, zigzag_spacing, stroke_width, pull_compensation)
|
||||
|
||||
return patch
|
||||
return stitch_group
|
||||
|
||||
def running_stitch(self, path, stitch_length, tolerance):
|
||||
stitches = running_stitch(path, stitch_length, tolerance)
|
||||
|
@ -463,7 +462,12 @@ class Stroke(EmbroideryElement):
|
|||
|
||||
repeated_stitches.extend(this_path)
|
||||
|
||||
return StitchGroup(self.color, repeated_stitches, lock_stitches=self.lock_stitches, force_lock_stitches=self.force_lock_stitches)
|
||||
return StitchGroup(
|
||||
self.color,
|
||||
stitches=repeated_stitches,
|
||||
lock_stitches=self.lock_stitches,
|
||||
force_lock_stitches=self.force_lock_stitches
|
||||
)
|
||||
|
||||
def apply_max_stitch_length(self, path):
|
||||
# apply max distances
|
||||
|
@ -491,16 +495,16 @@ class Stroke(EmbroideryElement):
|
|||
def do_bean_repeats(self, stitches):
|
||||
return bean_stitch(stitches, self.bean_stitch_repeats)
|
||||
|
||||
def to_stitch_groups(self, last_patch): # noqa: C901
|
||||
patches = []
|
||||
def to_stitch_groups(self, last_stitch_group): # noqa: C901
|
||||
stitch_groups = []
|
||||
|
||||
# ripple stitch
|
||||
if self.stroke_method == 'ripple_stitch':
|
||||
patch = self.ripple_stitch()
|
||||
if patch:
|
||||
stitch_group = self.ripple_stitch()
|
||||
if stitch_group:
|
||||
if any(self.bean_stitch_repeats):
|
||||
patch.stitches = self.do_bean_repeats(patch.stitches)
|
||||
patches.append(patch)
|
||||
stitch_group.stitches = self.do_bean_repeats(stitch_group.stitches)
|
||||
stitch_groups.append(stitch_group)
|
||||
else:
|
||||
for path in self.paths:
|
||||
path = [Point(x, y) for x, y in path]
|
||||
|
@ -514,24 +518,26 @@ class Stroke(EmbroideryElement):
|
|||
else:
|
||||
# manual stitch disables lock stitches unless they force them
|
||||
lock_stitches = (None, None)
|
||||
patch = StitchGroup(color=self.color,
|
||||
stitches=path,
|
||||
lock_stitches=lock_stitches,
|
||||
force_lock_stitches=self.force_lock_stitches)
|
||||
stitch_group = StitchGroup(
|
||||
color=self.color,
|
||||
stitches=path,
|
||||
lock_stitches=lock_stitches,
|
||||
force_lock_stitches=self.force_lock_stitches
|
||||
)
|
||||
# simple satin
|
||||
elif self.stroke_method == 'zigzag_stitch':
|
||||
patch = self.simple_satin(path, self.zigzag_spacing, self.stroke_width, self.pull_compensation)
|
||||
stitch_group = self.simple_satin(path, self.zigzag_spacing, self.stroke_width, self.pull_compensation)
|
||||
# running stitch
|
||||
else:
|
||||
patch = self.running_stitch(path, self.running_stitch_length, self.running_stitch_tolerance)
|
||||
stitch_group = self.running_stitch(path, self.running_stitch_length, self.running_stitch_tolerance)
|
||||
# bean stitch
|
||||
if any(self.bean_stitch_repeats):
|
||||
patch.stitches = self.do_bean_repeats(patch.stitches)
|
||||
stitch_group.stitches = self.do_bean_repeats(stitch_group.stitches)
|
||||
|
||||
if patch:
|
||||
patches.append(patch)
|
||||
if stitch_group:
|
||||
stitch_groups.append(stitch_group)
|
||||
|
||||
return patches
|
||||
return stitch_groups
|
||||
|
||||
@cache
|
||||
def get_guide_line(self):
|
||||
|
|
|
@ -29,5 +29,5 @@ class TextObject(EmbroideryElement):
|
|||
def validation_warnings(self):
|
||||
yield TextTypeWarning(self.pointer())
|
||||
|
||||
def to_stitch_groups(self, last_patch):
|
||||
def to_stitch_groups(self, last_stitch_group):
|
||||
return []
|
||||
|
|
|
@ -124,16 +124,16 @@ class InkstitchExtension(inkex.EffectExtension):
|
|||
return False
|
||||
|
||||
def elements_to_stitch_groups(self, elements):
|
||||
patches = []
|
||||
stitch_groups = []
|
||||
for element in elements:
|
||||
if patches:
|
||||
last_patch = patches[-1]
|
||||
if stitch_groups:
|
||||
last_stitch_group = stitch_groups[-1]
|
||||
else:
|
||||
last_patch = None
|
||||
last_stitch_group = None
|
||||
|
||||
patches.extend(element.embroider(last_patch))
|
||||
stitch_groups.extend(element.embroider(last_stitch_group))
|
||||
|
||||
return patches
|
||||
return stitch_groups
|
||||
|
||||
def get_inkstitch_metadata(self):
|
||||
return InkStitchMetadata(self.svg)
|
||||
|
|
|
@ -39,8 +39,8 @@ class DensityMap(InkstitchExtension):
|
|||
self.metadata = self.get_inkstitch_metadata()
|
||||
collapse_len = self.metadata['collapse_len_mm']
|
||||
min_stitch_len = self.metadata['min_stitch_len_mm']
|
||||
patches = self.elements_to_stitch_groups(self.elements)
|
||||
stitch_plan = stitch_groups_to_stitch_plan(patches, collapse_len=collapse_len, min_stitch_len=min_stitch_len)
|
||||
stitch_groups = self.elements_to_stitch_groups(self.elements)
|
||||
stitch_plan = stitch_groups_to_stitch_plan(stitch_groups, collapse_len=collapse_len, min_stitch_len=min_stitch_len)
|
||||
|
||||
layer = svg.find(".//*[@id='__inkstitch_density_plan__']")
|
||||
color_groups = create_color_groups(layer)
|
||||
|
|
|
@ -54,8 +54,8 @@ class Output(InkstitchExtension):
|
|||
self.metadata = self.get_inkstitch_metadata()
|
||||
collapse_len = self.metadata['collapse_len_mm']
|
||||
min_stitch_len = self.metadata['min_stitch_len_mm']
|
||||
patches = self.elements_to_stitch_groups(self.elements)
|
||||
stitch_plan = stitch_groups_to_stitch_plan(patches, collapse_len=collapse_len, disable_ties=self.settings.get('laser_mode', False),
|
||||
stitch_groups = self.elements_to_stitch_groups(self.elements)
|
||||
stitch_plan = stitch_groups_to_stitch_plan(stitch_groups, collapse_len=collapse_len, disable_ties=self.settings.get('laser_mode', False),
|
||||
min_stitch_len=min_stitch_len)
|
||||
ThreadCatalog().match_and_apply_palette(stitch_plan, self.metadata['thread-palette'])
|
||||
|
||||
|
|
|
@ -310,8 +310,8 @@ class Print(InkstitchExtension):
|
|||
self.metadata = self.get_inkstitch_metadata()
|
||||
collapse_len = self.metadata['collapse_len_mm']
|
||||
min_stitch_len = self.metadata['min_stitch_len_mm']
|
||||
patches = self.elements_to_stitch_groups(self.elements)
|
||||
stitch_plan = stitch_groups_to_stitch_plan(patches, collapse_len=collapse_len, min_stitch_len=min_stitch_len)
|
||||
stitch_groups = self.elements_to_stitch_groups(self.elements)
|
||||
stitch_plan = stitch_groups_to_stitch_plan(stitch_groups, collapse_len=collapse_len, min_stitch_len=min_stitch_len)
|
||||
palette = ThreadCatalog().match_and_apply_palette(stitch_plan, self.get_inkstitch_metadata()['thread-palette'])
|
||||
|
||||
overview_svg, color_block_svgs = self.render_svgs(stitch_plan, realistic=False)
|
||||
|
|
|
@ -38,8 +38,8 @@ class StitchPlanPreview(InkstitchExtension):
|
|||
self.metadata = self.get_inkstitch_metadata()
|
||||
collapse_len = self.metadata['collapse_len_mm']
|
||||
min_stitch_len = self.metadata['min_stitch_len_mm']
|
||||
patches = self.elements_to_stitch_groups(self.elements)
|
||||
stitch_plan = stitch_groups_to_stitch_plan(patches, collapse_len=collapse_len, min_stitch_len=min_stitch_len)
|
||||
stitch_groups = self.elements_to_stitch_groups(self.elements)
|
||||
stitch_plan = stitch_groups_to_stitch_plan(stitch_groups, collapse_len=collapse_len, min_stitch_len=min_stitch_len)
|
||||
render_stitch_plan(svg, stitch_plan, realistic, visual_commands)
|
||||
|
||||
# apply options
|
||||
|
|
|
@ -54,8 +54,8 @@ class Zip(InkstitchExtension):
|
|||
self.metadata = self.get_inkstitch_metadata()
|
||||
collapse_len = self.metadata['collapse_len_mm']
|
||||
min_stitch_len = self.metadata['min_stitch_len_mm']
|
||||
patches = self.elements_to_stitch_groups(self.elements)
|
||||
stitch_plan = stitch_groups_to_stitch_plan(patches, collapse_len=collapse_len, min_stitch_len=min_stitch_len)
|
||||
stitch_groups = self.elements_to_stitch_groups(self.elements)
|
||||
stitch_plan = stitch_groups_to_stitch_plan(stitch_groups, collapse_len=collapse_len, min_stitch_len=min_stitch_len)
|
||||
ThreadCatalog().match_and_apply_palette(stitch_plan, self.get_inkstitch_metadata()['thread-palette'])
|
||||
|
||||
if self.options.x_repeats != 1 or self.options.y_repeats != 1:
|
||||
|
|
|
@ -112,6 +112,7 @@ class ColorBlock(object):
|
|||
|
||||
if min_stitch_len is None:
|
||||
min_stitch_len = 0.1
|
||||
min_stitch_len *= PIXELS_PER_MM
|
||||
|
||||
stitches = [self.stitches[0]]
|
||||
for stitch in self.stitches[1:]:
|
||||
|
@ -123,7 +124,8 @@ class ColorBlock(object):
|
|||
pass
|
||||
else:
|
||||
length = (stitch - stitches[-1]).length()
|
||||
if length <= min_stitch_len * PIXELS_PER_MM:
|
||||
min_length = stitch.min_stitch_length or min_stitch_len
|
||||
if length <= min_length:
|
||||
# duplicate stitch, skip this one
|
||||
continue
|
||||
|
||||
|
|
|
@ -11,7 +11,17 @@ from ..utils.geometry import Point
|
|||
class Stitch(Point):
|
||||
"""A stitch is a Point with extra information telling how to sew it."""
|
||||
|
||||
def __init__(self, x, y=None, color=None, jump=False, stop=False, trim=False, color_change=False, tags=None):
|
||||
def __init__(
|
||||
self,
|
||||
x, y=None,
|
||||
color=None,
|
||||
jump=False,
|
||||
stop=False,
|
||||
trim=False,
|
||||
color_change=False,
|
||||
min_stitch_length=None,
|
||||
tags=None
|
||||
):
|
||||
# DANGER: if you add new attributes, you MUST also set their default
|
||||
# values in __new__() below. Otherwise, cached stitch plans can be
|
||||
# loaded and create objects without those properties defined, because
|
||||
|
@ -37,6 +47,7 @@ class Stitch(Point):
|
|||
self._set('trim', trim, base_stitch)
|
||||
self._set('stop', stop, base_stitch)
|
||||
self._set('color_change', color_change, base_stitch)
|
||||
self._set('min_stitch_length', min_stitch_length, base_stitch)
|
||||
|
||||
self.tags = set()
|
||||
self.add_tags(tags or [])
|
||||
|
@ -52,13 +63,16 @@ class Stitch(Point):
|
|||
return instance
|
||||
|
||||
def __repr__(self):
|
||||
return "Stitch(%s, %s, %s, %s, %s, %s, %s)" % (self.x,
|
||||
self.y,
|
||||
self.color,
|
||||
"JUMP" if self.jump else " ",
|
||||
"TRIM" if self.trim else " ",
|
||||
"STOP" if self.stop else " ",
|
||||
"COLOR CHANGE" if self.color_change else " ")
|
||||
return "Stitch(%s, %s, %s, %s, %s, %s, %s, %s)" % (
|
||||
self.x,
|
||||
self.y,
|
||||
self.color,
|
||||
self.min_stitch_length,
|
||||
"JUMP" if self.jump else " ",
|
||||
"TRIM" if self.trim else " ",
|
||||
"STOP" if self.stop else " ",
|
||||
"COLOR CHANGE" if self.color_change else " "
|
||||
)
|
||||
|
||||
def _set(self, attribute, value, base_stitch):
|
||||
# Set an attribute. If the caller passed a Stitch object, use its value, unless
|
||||
|
@ -95,7 +109,17 @@ class Stitch(Point):
|
|||
return tag in self.tags
|
||||
|
||||
def copy(self):
|
||||
return Stitch(self.x, self.y, self.color, self.jump, self.stop, self.trim, self.color_change, self.tags)
|
||||
return Stitch(
|
||||
self.x,
|
||||
self.y,
|
||||
self.color,
|
||||
self.jump,
|
||||
self.stop,
|
||||
self.trim,
|
||||
self.color_change,
|
||||
self.min_stitch_length,
|
||||
self.tags
|
||||
)
|
||||
|
||||
def offset(self, offset: Point):
|
||||
out = self.copy()
|
||||
|
|
|
@ -17,8 +17,17 @@ class StitchGroup:
|
|||
between them by the stitch plan generation code.
|
||||
"""
|
||||
|
||||
def __init__(self, color=None, stitches=None, trim_after=False, stop_after=False,
|
||||
lock_stitches=(None, None), force_lock_stitches=False, tags=None):
|
||||
def __init__(
|
||||
self,
|
||||
color=None,
|
||||
stitches=None,
|
||||
min_jump_stitch_length=False,
|
||||
trim_after=False,
|
||||
stop_after=False,
|
||||
lock_stitches=(None, None),
|
||||
force_lock_stitches=False,
|
||||
tags=None
|
||||
):
|
||||
# DANGER: if you add new attributes, you MUST also set their default
|
||||
# values in __new__() below. Otherwise, cached stitch plans can be
|
||||
# loaded and create objects without those properties defined, because
|
||||
|
@ -29,6 +38,7 @@ class StitchGroup:
|
|||
self.stop_after = stop_after
|
||||
self.lock_stitches = lock_stitches
|
||||
self.force_lock_stitches = force_lock_stitches
|
||||
self.min_jump_stitch_length = min_jump_stitch_length
|
||||
self.stitches = []
|
||||
|
||||
if stitches:
|
||||
|
@ -55,9 +65,13 @@ class StitchGroup:
|
|||
raise TypeError("StitchGroup can only be added to another StitchGroup")
|
||||
|
||||
def __len__(self):
|
||||
# This method allows `len(patch)` and `if patch:
|
||||
# This method allows `len(stitch_group)` and `if stitch_group:
|
||||
return len(self.stitches)
|
||||
|
||||
def set_minimum_stitch_length(self, min_stitch_length):
|
||||
for stitch in self.stitches:
|
||||
stitch.min_stitch_length = min_stitch_length
|
||||
|
||||
def add_stitches(self, stitches, tags=None):
|
||||
for stitch in stitches:
|
||||
self.add_stitch(stitch, tags=tags)
|
||||
|
@ -66,7 +80,6 @@ class StitchGroup:
|
|||
if not isinstance(stitch, Stitch):
|
||||
# probably a Point
|
||||
stitch = Stitch(stitch, tags=tags)
|
||||
|
||||
self.stitches.append(stitch)
|
||||
|
||||
def reverse(self):
|
||||
|
|
|
@ -59,13 +59,23 @@ def stitch_groups_to_stitch_plan(stitch_groups, collapse_len=None, min_stitch_le
|
|||
# make a new block of our color
|
||||
color_block = stitch_plan.new_color_block(color=stitch_group.color)
|
||||
else:
|
||||
if (len(color_block) and not need_tie_in and
|
||||
((stitch_group.stitches[0] - color_block.stitches[-1]).length() > collapse_len or
|
||||
previous_stitch_group.force_lock_stitches)):
|
||||
lock_stitches = previous_stitch_group.get_lock_stitches("end", disable_ties)
|
||||
if lock_stitches:
|
||||
color_block.add_stitches(stitches=lock_stitches)
|
||||
need_tie_in = True
|
||||
add_lock = False
|
||||
if len(color_block) and not need_tie_in:
|
||||
distance_to_previous_stitch = (stitch_group.stitches[0] - color_block.stitches[-1]).length()
|
||||
if previous_stitch_group.force_lock_stitches:
|
||||
add_lock = True
|
||||
elif previous_stitch_group.min_jump_stitch_length:
|
||||
# object based minimum jump stitch length overrides the global collapse_len setting
|
||||
if distance_to_previous_stitch > previous_stitch_group.min_jump_stitch_length:
|
||||
add_lock = True
|
||||
elif distance_to_previous_stitch > collapse_len:
|
||||
add_lock = True
|
||||
|
||||
if add_lock:
|
||||
lock_stitches = previous_stitch_group.get_lock_stitches("end", disable_ties)
|
||||
need_tie_in = True
|
||||
if lock_stitches:
|
||||
color_block.add_stitches(stitches=lock_stitches)
|
||||
|
||||
if need_tie_in is True:
|
||||
lock_stitches = stitch_group.get_lock_stitches("start", disable_ties)
|
||||
|
|
|
@ -54,6 +54,8 @@ SVG_OBJECT_TAGS = (SVG_ELLIPSE_TAG, SVG_CIRCLE_TAG, SVG_RECT_TAG)
|
|||
|
||||
INKSTITCH_ATTRIBS = {}
|
||||
inkstitch_attribs = [
|
||||
'min_stitch_length_mm',
|
||||
'min_jump_stitch_length_mm',
|
||||
'ties',
|
||||
'force_lock_stitches',
|
||||
'lock_start',
|
||||
|
|
Ładowanie…
Reference in New Issue