kopia lustrzana https://github.com/inkstitch/inkstitch
gray out randomize stitch length param when random stitch length is disabled (#3002)
rodzic
c030e32835
commit
c017cae01a
|
@ -27,7 +27,7 @@ from ..utils.cache import get_stitch_plan_cache, is_cache_disabled, CacheKeyGene
|
|||
|
||||
class Param(object):
|
||||
def __init__(self, name, description, unit=None, values=[], type=None, group=None, inverse=False,
|
||||
options=[], default=None, tooltip=None, sort_index=0, select_items=None):
|
||||
options=[], default=None, tooltip=None, sort_index=0, select_items=None, enables=None):
|
||||
self.name = name
|
||||
self.description = description
|
||||
self.unit = unit
|
||||
|
@ -40,6 +40,7 @@ class Param(object):
|
|||
self.tooltip = tooltip
|
||||
self.sort_index = sort_index
|
||||
self.select_items = select_items
|
||||
self.enables = enables
|
||||
|
||||
def __repr__(self):
|
||||
return "Param(%s)" % vars(self)
|
||||
|
|
|
@ -487,19 +487,20 @@ class FillStitch(EmbroideryElement):
|
|||
return max(self.get_float_param("running_stitch_tolerance_mm", 0.2), 0.01)
|
||||
|
||||
@property
|
||||
@param('enable_random_stitches',
|
||||
_('Randomize stitches'),
|
||||
@param('enable_random_stitch_length',
|
||||
_('Randomize stitch length'),
|
||||
tooltip=_('Randomize stitch length and phase instead of dividing evenly or staggering. '
|
||||
'This is recommended for closely-spaced curved fills to avoid Moiré artefacts.'),
|
||||
type='boolean',
|
||||
enables=['random_stitch_length_jitter_percent'],
|
||||
select_items=[('fill_method', 'auto_fill'),
|
||||
('fill_method', 'contour_fill'),
|
||||
('fill_method', 'guided_fill'),
|
||||
('fill_method', 'circular_fill')],
|
||||
default=False,
|
||||
sort_index=44)
|
||||
def enable_random_stitches(self):
|
||||
return self.get_boolean_param('enable_random_stitches', False)
|
||||
def enable_random_stitch_length(self):
|
||||
return self.get_boolean_param('enable_random_stitch_length', False)
|
||||
|
||||
@property
|
||||
@param('random_stitch_length_jitter_percent',
|
||||
|
@ -1023,7 +1024,7 @@ class FillStitch(EmbroideryElement):
|
|||
ending_point,
|
||||
self.underpath,
|
||||
self.gap_fill_rows,
|
||||
self.enable_random_stitches,
|
||||
self.enable_random_stitch_length,
|
||||
self.random_stitch_length_jitter,
|
||||
self.random_seed,
|
||||
)
|
||||
|
@ -1049,7 +1050,7 @@ class FillStitch(EmbroideryElement):
|
|||
self.smoothness,
|
||||
starting_point,
|
||||
self.avoid_self_crossing,
|
||||
self.enable_random_stitches,
|
||||
self.enable_random_stitch_length,
|
||||
self.random_stitch_length_jitter,
|
||||
self.random_seed
|
||||
)
|
||||
|
@ -1059,7 +1060,7 @@ class FillStitch(EmbroideryElement):
|
|||
self.max_stitch_length,
|
||||
self.running_stitch_tolerance,
|
||||
starting_point,
|
||||
self.enable_random_stitches,
|
||||
self.enable_random_stitch_length,
|
||||
self.random_stitch_length_jitter,
|
||||
self.random_seed
|
||||
)
|
||||
|
@ -1069,7 +1070,7 @@ class FillStitch(EmbroideryElement):
|
|||
self.max_stitch_length,
|
||||
self.running_stitch_tolerance,
|
||||
starting_point,
|
||||
self.enable_random_stitches,
|
||||
self.enable_random_stitch_length,
|
||||
self.random_stitch_length_jitter,
|
||||
self.random_seed
|
||||
)
|
||||
|
@ -1110,7 +1111,7 @@ class FillStitch(EmbroideryElement):
|
|||
ending_point,
|
||||
self.underpath,
|
||||
self.guided_fill_strategy,
|
||||
self.enable_random_stitches,
|
||||
self.enable_random_stitch_length,
|
||||
self.random_stitch_length_jitter,
|
||||
self.random_seed,
|
||||
)
|
||||
|
@ -1164,7 +1165,7 @@ class FillStitch(EmbroideryElement):
|
|||
ending_point,
|
||||
self.underpath,
|
||||
target,
|
||||
self.enable_random_stitches,
|
||||
self.enable_random_stitch_length,
|
||||
self.random_stitch_length_jitter,
|
||||
self.random_seed,
|
||||
)
|
||||
|
|
|
@ -130,16 +130,17 @@ class Stroke(EmbroideryElement):
|
|||
return max(self.get_float_param("running_stitch_tolerance_mm", 0.2), 0.01)
|
||||
|
||||
@property
|
||||
@param('enable_random_stitches',
|
||||
_('Randomize stitches'),
|
||||
@param('enable_random_stitch_length',
|
||||
_('Randomized stitch length'),
|
||||
tooltip=_('Randomize stitch length and phase instead of dividing evenly or staggering. '
|
||||
'This is recommended for closely-spaced curved fills to avoid Moiré artefacts.'),
|
||||
type='boolean',
|
||||
select_items=[('stroke_method', 'running_stitch'), ('stroke_method', 'ripple_stitch')],
|
||||
enables=['random_stitch_length_jitter_percent'],
|
||||
default=False,
|
||||
sort_index=5)
|
||||
def enable_random_stitches(self):
|
||||
return self.get_boolean_param('enable_random_stitches', False)
|
||||
def enable_random_stitch_length(self):
|
||||
return self.get_boolean_param('enable_random_stitch_length', False)
|
||||
|
||||
@property
|
||||
@param('random_stitch_length_jitter_percent',
|
||||
|
@ -490,9 +491,9 @@ class Stroke(EmbroideryElement):
|
|||
|
||||
return stitch_group
|
||||
|
||||
def running_stitch(self, path, stitch_length, tolerance, enable_random, random_sigma, random_seed):
|
||||
def running_stitch(self, path, stitch_length, tolerance, enable_random_stitch_length, random_sigma, random_seed):
|
||||
# running stitch with repeats
|
||||
stitches = running_stitch(path, stitch_length, tolerance, enable_random, random_sigma, random_seed)
|
||||
stitches = running_stitch(path, stitch_length, tolerance, enable_random_stitch_length, random_sigma, random_seed)
|
||||
|
||||
repeated_stitches = []
|
||||
# go back and forth along the path as specified by self.repeats
|
||||
|
@ -573,7 +574,7 @@ class Stroke(EmbroideryElement):
|
|||
# running stitch
|
||||
else:
|
||||
stitch_group = self.running_stitch(path, self.running_stitch_length, self.running_stitch_tolerance,
|
||||
self.enable_random_stitches, self.random_stitch_length_jitter, self.random_seed)
|
||||
self.enable_random_stitch_length, self.random_stitch_length_jitter, self.random_seed)
|
||||
# bean stitch
|
||||
if any(self.bean_stitch_repeats):
|
||||
stitch_group.stitches = self.do_bean_repeats(stitch_group.stitches)
|
||||
|
|
|
@ -97,7 +97,8 @@ class ParamsTab(ScrolledPanel):
|
|||
|
||||
if self.toggle:
|
||||
self.update_toggle_state()
|
||||
# end wxGlade
|
||||
|
||||
self.update_enable_widgets()
|
||||
|
||||
def pair(self, tab):
|
||||
self.paired_tab = tab
|
||||
|
@ -349,6 +350,28 @@ class ParamsTab(ScrolledPanel):
|
|||
widgets[3].Show(True)
|
||||
choice["last_initialized_choice"] = current_selection
|
||||
|
||||
def update_enable_widgets(self, event=None):
|
||||
if event is None:
|
||||
for param in self.params:
|
||||
if param.enables is not None:
|
||||
value = self.param_inputs[param.name].GetValue()
|
||||
for item in param.enables:
|
||||
enable_input = self.param_inputs[item]
|
||||
enable_input.Enable(value)
|
||||
enable_input.GetPrevSibling().Enable(value)
|
||||
else:
|
||||
input = event.GetEventObject()
|
||||
param = [param for param in self.params if param.name == input.Name]
|
||||
if not param:
|
||||
return
|
||||
param = param[0]
|
||||
if param.enables is not None:
|
||||
value = input.GetValue()
|
||||
for item in param.enables:
|
||||
enable_input = self.param_inputs[item]
|
||||
enable_input.Enable(value)
|
||||
enable_input.GetPrevSibling().Enable(value)
|
||||
|
||||
def __do_layout(self, only_settings_grid=False): # noqa: C901
|
||||
|
||||
# just to add space around the settings
|
||||
|
@ -393,7 +416,8 @@ class ParamsTab(ScrolledPanel):
|
|||
input = wx.CheckBox(self)
|
||||
if param.values:
|
||||
input.SetValue(param.values[0])
|
||||
|
||||
input.SetName(param.name)
|
||||
input.Bind(wx.EVT_CHECKBOX, self.update_enable_widgets)
|
||||
input.Bind(wx.EVT_CHECKBOX, self.changed)
|
||||
elif param.type == 'dropdown':
|
||||
input = wx.Choice(self, wx.ID_ANY, choices=param.options)
|
||||
|
|
|
@ -80,7 +80,7 @@ def auto_fill(shape,
|
|||
ending_point=None,
|
||||
underpath=True,
|
||||
gap_fill_rows=0,
|
||||
enable_random=False,
|
||||
enable_random_stitch_length=False,
|
||||
random_sigma=0.0,
|
||||
random_seed=""):
|
||||
rows = intersect_region_with_grating(shape, angle, row_spacing, end_row_spacing)
|
||||
|
@ -108,7 +108,7 @@ def auto_fill(shape,
|
|||
path = fill_gaps(path, round_to_multiple_of_2(gap_fill_rows))
|
||||
result = path_to_stitches(shape, path, travel_graph, fill_stitch_graph, angle, row_spacing,
|
||||
max_stitch_length, running_stitch_length, running_stitch_tolerance,
|
||||
staggers, skip_last, underpath, enable_random, random_sigma, random_seed)
|
||||
staggers, skip_last, underpath, enable_random_stitch_length, random_sigma, random_seed)
|
||||
|
||||
return result
|
||||
|
||||
|
@ -852,7 +852,7 @@ def travel(shape, travel_graph, edge, running_stitch_length, running_stitch_tole
|
|||
|
||||
@debug.time
|
||||
def path_to_stitches(shape, path, travel_graph, fill_stitch_graph, angle, row_spacing, max_stitch_length, running_stitch_length,
|
||||
running_stitch_tolerance, staggers, skip_last, underpath, enable_random, random_sigma, random_seed):
|
||||
running_stitch_tolerance, staggers, skip_last, underpath, enable_random_stitch_length, random_sigma, random_seed):
|
||||
path = collapse_sequential_outline_edges(path, fill_stitch_graph)
|
||||
|
||||
stitches = []
|
||||
|
@ -864,7 +864,7 @@ def path_to_stitches(shape, path, travel_graph, fill_stitch_graph, angle, row_sp
|
|||
for i, edge in enumerate(path):
|
||||
if edge.is_segment():
|
||||
stitch_row(stitches, edge[0], edge[1], angle, row_spacing, max_stitch_length, staggers, skip_last,
|
||||
enable_random, random_sigma, join_args(random_seed, i))
|
||||
enable_random_stitch_length, random_sigma, join_args(random_seed, i))
|
||||
|
||||
# note: gap fill segments won't be in the graph
|
||||
if fill_stitch_graph.has_edge(edge[0], edge[1], key='segment'):
|
||||
|
|
|
@ -27,7 +27,7 @@ def circular_fill(shape,
|
|||
ending_point,
|
||||
underpath,
|
||||
target,
|
||||
use_random,
|
||||
enable_random_stitch_length,
|
||||
running_stitch_length_jitter,
|
||||
random_seed,
|
||||
):
|
||||
|
@ -69,7 +69,7 @@ def circular_fill(shape,
|
|||
stitches = running_stitch([Stitch(*point) for point in path],
|
||||
running_stitch_length,
|
||||
running_stitch_tolerance,
|
||||
use_random,
|
||||
enable_random_stitch_length,
|
||||
running_stitch_length_jitter,
|
||||
random_seed)
|
||||
return _apply_bean_stitch_and_repeats(stitches, repeats, bean_stitch_repeats)
|
||||
|
@ -81,7 +81,7 @@ def circular_fill(shape,
|
|||
coords = running_stitch([Point(*point) for point in line.coords],
|
||||
running_stitch_length,
|
||||
running_stitch_tolerance,
|
||||
use_random,
|
||||
enable_random_stitch_length,
|
||||
running_stitch_length_jitter,
|
||||
prng.join_args(random_seed, n))
|
||||
segments.append([(point.x, point.y) for point in coords])
|
||||
|
|
|
@ -412,7 +412,7 @@ def _find_path_inner_to_outer(tree, node, offset, starting_point, avoid_self_cro
|
|||
def inner_to_outer(tree, polygon, offset,
|
||||
stitch_length, tolerance, smoothness,
|
||||
starting_point, avoid_self_crossing,
|
||||
enable_random, random_sigma, random_seed):
|
||||
enable_random_stitch_length, random_sigma, random_seed):
|
||||
"""Fill a shape with spirals, from innermost to outermost."""
|
||||
|
||||
stitch_path = _find_path_inner_to_outer(tree, 'root', offset, starting_point, avoid_self_crossing)
|
||||
|
@ -422,7 +422,7 @@ def inner_to_outer(tree, polygon, offset,
|
|||
smoothed = smooth_path(points, smoothness)
|
||||
points = clamp_path_to_polygon(smoothed, polygon)
|
||||
|
||||
stitches = running_stitch(points, stitch_length, tolerance, enable_random, random_sigma, random_seed)
|
||||
stitches = running_stitch(points, stitch_length, tolerance, enable_random_stitch_length, random_sigma, random_seed)
|
||||
|
||||
return stitches
|
||||
|
||||
|
@ -518,24 +518,24 @@ def _check_and_prepare_tree_for_valid_spiral(tree):
|
|||
return process_node('root')
|
||||
|
||||
|
||||
def single_spiral(tree, stitch_length, tolerance, starting_point, enable_random, random_sigma, random_seed):
|
||||
def single_spiral(tree, stitch_length, tolerance, starting_point, enable_random_stitch_length, random_sigma, random_seed):
|
||||
"""Fill a shape with a single spiral going from outside to center."""
|
||||
return _spiral_fill(tree, stitch_length, tolerance, starting_point, enable_random, random_sigma, random_seed, _make_spiral)
|
||||
return _spiral_fill(tree, stitch_length, tolerance, starting_point, enable_random_stitch_length, random_sigma, random_seed, _make_spiral)
|
||||
|
||||
|
||||
def double_spiral(tree, stitch_length, tolerance, starting_point, enable_random, random_sigma, random_seed):
|
||||
def double_spiral(tree, stitch_length, tolerance, starting_point, enable_random_stitch_length, random_sigma, random_seed):
|
||||
"""Fill a shape with a double spiral going from outside to center and back to outside. """
|
||||
return _spiral_fill(tree, stitch_length, tolerance, starting_point, enable_random, random_sigma, random_seed, _make_fermat_spiral)
|
||||
return _spiral_fill(tree, stitch_length, tolerance, starting_point, enable_random_stitch_length, random_sigma, random_seed, _make_fermat_spiral)
|
||||
|
||||
|
||||
def _spiral_fill(tree, stitch_length, tolerance, close_point, enable_random, random_sigma, random_seed, spiral_maker):
|
||||
def _spiral_fill(tree, stitch_length, tolerance, close_point, enable_random_stitch_length, random_sigma, random_seed, spiral_maker):
|
||||
starting_point = close_point.coords[0]
|
||||
|
||||
rings = _get_spiral_rings(tree)
|
||||
path = spiral_maker(rings, stitch_length, starting_point)
|
||||
path = [Stitch(*stitch) for stitch in path]
|
||||
|
||||
return running_stitch(path, stitch_length, tolerance, enable_random, random_sigma, random_seed)
|
||||
return running_stitch(path, stitch_length, tolerance, enable_random_stitch_length, random_sigma, random_seed)
|
||||
|
||||
|
||||
def _get_spiral_rings(tree):
|
||||
|
|
|
@ -52,12 +52,13 @@ def adjust_stagger(stitch, angle, row_spacing, max_stitch_length, staggers):
|
|||
return stitch - offset * east(angle)
|
||||
|
||||
|
||||
def stitch_row(stitches, beg, end, angle, row_spacing, max_stitch_length, staggers, skip_last, enable_random, random_sigma, random_seed):
|
||||
def stitch_row(stitches, beg, end, angle, row_spacing, max_stitch_length, staggers, skip_last,
|
||||
enable_random_stitch_length, random_sigma, random_seed):
|
||||
beg = Stitch(*beg, tags=('fill_row_start',))
|
||||
end = Stitch(*end, tags=('fill_row_start',))
|
||||
stitches.append(beg)
|
||||
|
||||
if enable_random:
|
||||
if enable_random_stitch_length:
|
||||
stitches += split_segment_random_phase(beg, end, max_stitch_length, random_sigma, random_seed)
|
||||
else:
|
||||
# We want our stitches to look like this:
|
||||
|
|
|
@ -35,12 +35,12 @@ def guided_fill(shape,
|
|||
ending_point,
|
||||
underpath,
|
||||
strategy,
|
||||
enable_random,
|
||||
enable_random_stitch_length,
|
||||
random_sigma,
|
||||
random_seed,
|
||||
):
|
||||
segments = intersect_region_with_grating_guideline(shape, guideline, row_spacing, num_staggers, max_stitch_length, strategy,
|
||||
enable_random, running_stitch_tolerance, random_sigma, random_seed,)
|
||||
enable_random_stitch_length, running_stitch_tolerance, random_sigma, random_seed,)
|
||||
if not segments:
|
||||
return fallback(shape, guideline, row_spacing, max_stitch_length, running_stitch_length, running_stitch_tolerance,
|
||||
num_staggers, skip_last, starting_point, ending_point, underpath)
|
||||
|
@ -239,7 +239,7 @@ def _get_start_row(line, shape, row_spacing, line_direction):
|
|||
|
||||
|
||||
def intersect_region_with_grating_guideline(shape, line, row_spacing, num_staggers, max_stitch_length, strategy,
|
||||
enable_random, tolerance, random_sigma, random_seed):
|
||||
enable_random_stitch_length, tolerance, random_sigma, random_seed):
|
||||
line = prepare_guide_line(line, shape)
|
||||
|
||||
debug.log_line_string(shape.exterior, "guided fill shape")
|
||||
|
@ -271,7 +271,7 @@ def intersect_region_with_grating_guideline(shape, line, row_spacing, num_stagge
|
|||
|
||||
debug.log_line_string(offset_line, f"offset {row}")
|
||||
|
||||
if enable_random:
|
||||
if enable_random_stitch_length:
|
||||
points = [InkstitchPoint(*x) for x in offset_line.coords]
|
||||
stitched_line = shgeo.LineString(random_running_stitch(
|
||||
points, max_stitch_length, tolerance, random_sigma, prng.join_args(random_seed, row)))
|
||||
|
|
|
@ -50,7 +50,7 @@ def _get_stitches(stroke, is_linear, lines, skip_start):
|
|||
return running_stitch(points,
|
||||
stroke.running_stitch_length,
|
||||
stroke.running_stitch_tolerance,
|
||||
stroke.enable_random_stitches,
|
||||
stroke.enable_random_stitch_length,
|
||||
stroke.random_stitch_length_jitter,
|
||||
stroke.random_seed)
|
||||
|
||||
|
@ -59,7 +59,7 @@ def _get_staggered_stitches(stroke, lines, skip_start):
|
|||
stitches = []
|
||||
stitch_length = stroke.running_stitch_length
|
||||
tolerance = stroke.running_stitch_tolerance
|
||||
enable_random = stroke.enable_random_stitches
|
||||
enable_random_stitch_length = stroke.enable_random_stitch_length
|
||||
length_sigma = stroke.random_stitch_length_jitter
|
||||
random_seed = stroke.random_seed
|
||||
last_point = None
|
||||
|
@ -77,10 +77,10 @@ def _get_staggered_stitches(stroke, lines, skip_start):
|
|||
elif stroke.join_style == 1:
|
||||
should_reverse = (i + skip_start) % 2 == 1
|
||||
|
||||
if enable_random or stroke.staggers == 0:
|
||||
if enable_random_stitch_length or stroke.staggers == 0:
|
||||
if should_reverse:
|
||||
line.reverse()
|
||||
points = running_stitch(line, stitch_length, tolerance, enable_random, length_sigma, prng.join_args(random_seed, i))
|
||||
points = running_stitch(line, stitch_length, tolerance, enable_random_stitch_length, length_sigma, prng.join_args(random_seed, i))
|
||||
stitched_line = connector + points
|
||||
else:
|
||||
# uses the guided fill alforithm to stagger rows of stitches
|
||||
|
|
|
@ -56,11 +56,12 @@ stitch_path = (
|
|||
"l-0.55,-0.1,0.55,0.1" # Bottom-left whisker
|
||||
"z") # return to start
|
||||
|
||||
|
||||
def generate_realistic_filter() -> inkex.BaseElement:
|
||||
"""
|
||||
Return a copy of the realistic stitch filter, ready to add to svg defs.
|
||||
"""
|
||||
filter = inkex.Filter(attrib = {
|
||||
filter = inkex.Filter(attrib={
|
||||
"style": "color-interpolation-filters:sRGB",
|
||||
"id": "realistic-stitch-filter",
|
||||
"x": "0",
|
||||
|
@ -71,27 +72,27 @@ def generate_realistic_filter() -> inkex.BaseElement:
|
|||
})
|
||||
|
||||
filter.add(
|
||||
inkex.Filter.GaussianBlur(attrib = {
|
||||
inkex.Filter.GaussianBlur(attrib={
|
||||
"edgeMode": "none",
|
||||
"stdDeviation": "0.9",
|
||||
"in": "SourceAlpha",
|
||||
}),
|
||||
inkex.Filter.SpecularLighting(
|
||||
inkex.Filter.DistantLight(attrib = {
|
||||
inkex.Filter.DistantLight(attrib={
|
||||
"azimuth": "-125",
|
||||
"elevation": "20",
|
||||
}), attrib = {
|
||||
}), attrib={
|
||||
"result": "result2",
|
||||
"surfaceScale": "1.5",
|
||||
"specularConstant": "0.78",
|
||||
"specularExponent": "2.5",
|
||||
}
|
||||
),
|
||||
inkex.Filter.Composite(attrib = {
|
||||
inkex.Filter.Composite(attrib={
|
||||
"in2": "SourceAlpha",
|
||||
"operator": "atop",
|
||||
}),
|
||||
inkex.Filter.Composite(attrib = {
|
||||
inkex.Filter.Composite(attrib={
|
||||
"in2": "SourceGraphic",
|
||||
"operator": "arithmetic",
|
||||
"result": "result3",
|
||||
|
|
|
@ -106,7 +106,7 @@ inkstitch_attribs = [
|
|||
'rows_per_thread',
|
||||
'herringbone_width_mm',
|
||||
'tartan_angle',
|
||||
'enable_random_stitches',
|
||||
'enable_random_stitch_length',
|
||||
'random_stitch_length_jitter_percent',
|
||||
'gap_fill_rows',
|
||||
# stroke
|
||||
|
|
Ładowanie…
Reference in New Issue