diff options
Diffstat (limited to 'lib/stitches/ripple_stitch.py')
| -rw-r--r-- | lib/stitches/ripple_stitch.py | 127 |
1 files changed, 83 insertions, 44 deletions
diff --git a/lib/stitches/ripple_stitch.py b/lib/stitches/ripple_stitch.py index e150945e..5ebd531b 100644 --- a/lib/stitches/ripple_stitch.py +++ b/lib/stitches/ripple_stitch.py @@ -33,20 +33,30 @@ def ripple_stitch(stroke): skip_start = _adjust_skip(stroke, num_lines, stroke.skip_start) skip_end = _adjust_skip(stroke, num_lines, stroke.skip_end) - lines = _get_ripple_lines(stroke, helper_lines, is_linear, skip_start, skip_end) + lines = _get_ripple_lines(helper_lines, is_linear, skip_start, skip_end) stitches = _get_stitches(stroke, is_linear, lines, skip_start) if stroke.reverse: stitches.reverse() - if stroke.grid_size != 0: - stitches.extend(_do_grid(stroke, helper_lines, skip_start, skip_end, is_linear)) + if stitches and stroke.grid_size != 0: + stitches.extend(_do_grid(stroke, helper_lines, skip_start, skip_end, is_linear, stitches[-1])) return _repeat_coords(stitches, stroke.repeats) def _get_stitches(stroke, is_linear, lines, skip_start): - if is_linear: + if stroke.manual_pattern_placement: + if stroke.flip_copies: + stitches = [] + for i, line in enumerate(lines): + if i % 2 == 0: + stitches.extend(line[::-1]) + else: + stitches.extend(line) + return stitches + return [point for line in lines for point in line] + if is_linear and stroke.flip_copies: return _get_staggered_stitches(stroke, lines, skip_start) else: points = [point for line in lines for point in line] @@ -69,7 +79,7 @@ def _get_staggered_stitches(stroke, lines, skip_start): for i, line in enumerate(lines): connector = [] if i != 0 and stroke.join_style == 0: - if i % 2 == 0: + if i % 2 == 0 or not stroke.flip_copies: first_point = line[0] else: first_point = line[-1] @@ -81,7 +91,7 @@ def _get_staggered_stitches(stroke, lines, skip_start): should_reverse = (i + skip_start) % 2 == 1 if enable_random_stitch_length or stroke.staggers == 0: - if should_reverse: + if should_reverse and stroke.flip_copies: line.reverse() points = running_stitch(line, stitch_length, tolerance, enable_random_stitch_length, length_sigma, prng.join_args(random_seed, i)) stitched_line = connector + points @@ -89,7 +99,7 @@ def _get_staggered_stitches(stroke, lines, skip_start): # uses the guided fill alforithm to stagger rows of stitches points = list(apply_stitches(LineString(line), stitch_length, stroke.staggers, 0.5, i, tolerance).coords) stitched_line = [InkstitchPoint(*point) for point in points] - if should_reverse: + if should_reverse and stroke.flip_copies: stitched_line.reverse() stitched_line = connector + stitched_line @@ -104,7 +114,7 @@ def _adjust_skip(stroke, num_lines, skip): return skip -def _get_ripple_lines(stroke, helper_lines, is_linear, skip_start, skip_end): +def _get_ripple_lines(helper_lines, is_linear, skip_start, skip_end): lines = [] for point_num in range(skip_start, len(helper_lines[0]) - skip_end): row = [] @@ -158,9 +168,16 @@ def _get_helper_lines(stroke): if len(lines) > 1: return True, _get_satin_ripple_helper_lines(stroke) else: - outline = LineString(even_running_stitch(line_string_to_point_list(lines[0]), - stroke.grid_size or stroke.running_stitch_length, - stroke.running_stitch_tolerance)) + if stroke.manual_pattern_placement: + path = stroke.parse_path() + path = [stroke.strip_control_points(subpath) for subpath in path][0] + outline = LineString(path) + else: + outline = LineString(even_running_stitch( + line_string_to_point_list(lines[0]), + stroke.grid_size or stroke.running_stitch_length, + stroke.running_stitch_tolerance) + ) if stroke.is_closed: return False, _get_circular_ripple_helper_lines(stroke, outline) @@ -189,13 +206,13 @@ def _get_satin_ripple_helper_lines(stroke): for step in steps: helper_lines[-1].append(InkstitchPoint.from_shapely_point(helper_line.interpolate(step, normalized=True))) - if stroke.join_style == 1: - helper_lines = _converge_helper_line_points(helper_lines, True) + if stroke.join_style == 1 or not stroke.flip_copies: + helper_lines = _converge_helper_line_points(helper_lines, True, stroke.flip_copies) return helper_lines -def _converge_helper_line_points(helper_lines, point_edge=False): +def _converge_helper_line_points(helper_lines, point_edge=False, flip_copies=True): num_lines = len(helper_lines) steps = _get_steps(num_lines) for i, line in enumerate(helper_lines): @@ -203,7 +220,7 @@ def _converge_helper_line_points(helper_lines, point_edge=False): points = [] for j in range(len(line) - 1): - if point_edge and j % 2 == 1: + if point_edge and j % 2 == 1 and flip_copies: k = num_lines - 1 - i points.append(line[j] * (1 - steps[k]) + line[j + 1] * steps[k]) else: @@ -250,37 +267,36 @@ def _target_point_helper_lines(stroke, outline): return helper_lines -def _adjust_helper_lines_for_grid(stroke, helper_lines, skip_start, skip_end, is_linear): - num_lines = len(helper_lines[0]) - count = num_lines - skip_start - skip_end - - if stroke.join_style == 0 and (stroke.reverse and count % 2 != 0): - count += 1 - elif (stroke.join_style == 1 and ((stroke.reverse and (count + skip_start) % 2 != 0) or - (not stroke.reverse and skip_start % 2 != 0))): - count += 1 - - if not is_linear: - count = 1 - if stroke.reverse: - count = 0 - - if count % 2 != 0: - helper_lines.reverse() - return helper_lines +def _adjust_helper_lines_for_grid(grid, last_stitch): + # check which end of the grid is nearest to the last stitch + # and adjust grid accordingly + last_stitch = Point(last_stitch) + distances = [ + Point(grid[0][0]).distance(last_stitch), + Point(grid[0][-1]).distance(last_stitch), + Point(grid[-1][0]).distance(last_stitch), + Point(grid[-1][-1]).distance(last_stitch) + ] + nearest = distances.index(min(distances)) + if nearest in [1, 3]: + adjusted_grid = [] + for line in grid: + adjusted_grid.append(line[::-1]) + grid = adjusted_grid + if nearest in [2, 3]: + grid.reverse() + return grid -def _do_grid(stroke, helper_lines, skip_start, skip_end, is_linear): - helper_lines = _adjust_helper_lines_for_grid(stroke, helper_lines, skip_start, skip_end, is_linear) +def _do_grid(stroke, helper_lines, skip_start, skip_end, is_linear, last_stitch): grid = [] for i, helper in enumerate(helper_lines): end = len(helper) - skip_end points = helper[skip_start:end] - if stroke.reverse: - points.reverse() - if len(helper_lines) - skip_start - skip_end % 2 != 0: + if i % 2 != 0 and is_linear and not stroke.flip_copies and stroke.join_style == 0: points.reverse() grid.append(points) + grid = _adjust_helper_lines_for_grid(grid, last_stitch) grid = _get_staggered_stitches(stroke, grid, 0) return grid @@ -299,14 +315,22 @@ def _get_guided_helper_lines(stroke, outline, max_distance): def _generate_guided_helper_lines(stroke, outline, max_distance, guide_line): # helper lines are generated by making copies of the outline along the guide line line_point_dict = defaultdict(list) - outline = LineString(even_running_stitch(line_string_to_point_list(outline), max_distance, stroke.running_stitch_tolerance)) + if not stroke.manual_pattern_placement: + outline = LineString(even_running_stitch( + line_string_to_point_list(outline), + max_distance, + stroke.running_stitch_tolerance + )) center = outline.centroid center = InkstitchPoint(center.x, center.y) - count = _get_guided_line_count(stroke, guide_line) + if stroke.render_at_rungs: + count = len(guide_line.coords) + else: + count = _get_guided_line_count(stroke, guide_line) + outline_steps = _get_steps(count, exponent=stroke.exponent, flip=stroke.flip_exponent) - outline_steps = _get_steps(count, exponent=stroke.exponent, flip=stroke.flip_exponent) scale_steps = _get_steps(count, start=stroke.scale_start / 100.0, end=stroke.scale_end / 100.0) start_point = InkstitchPoint(*(guide_line.coords[0])) @@ -316,7 +340,11 @@ def _generate_guided_helper_lines(stroke, outline, max_distance, guide_line): for i in range(count): check_stop_flag() - guide_point = InkstitchPoint.from_shapely_point(guide_line.interpolate(outline_steps[i], normalized=True)) + if stroke.render_at_rungs: + # Requires the guide line to be defined as manual stitch + guide_point = InkstitchPoint(*guide_line.coords[i]) + else: + guide_point = InkstitchPoint.from_shapely_point(guide_line.interpolate(outline_steps[i], normalized=True)) translation = guide_point - start_point scaling = scale_steps[i] if stroke.rotate_ripples and previous_guide_point: @@ -343,11 +371,20 @@ def _get_start_rotation(line): def _generate_satin_guide_helper_lines(stroke, outline, guide_line): count = _get_guided_line_count(stroke, guide_line.center_line) - spacing = guide_line.center_line.length / (count - 1) - pairs = guide_line.plot_points_on_rails(spacing) + + spacing = guide_line.center_line.length / max(1, count - 1) + if stroke.render_at_rungs: + sections = guide_line.flattened_sections + pairs = [] + for (rail0, rail1) in sections: + pairs.append((rail0[-1], rail1[-1])) + pairs = pairs[:-1] + else: + pairs = guide_line.plot_points_on_rails(spacing) point0 = pairs[0][0] point1 = pairs[0][1] + start_rotation = atan2(point1.y - point0.y, point1.x - point0.x) start_scale = (point1 - point0).length() outline_center = InkstitchPoint.from_shapely_point(outline.centroid) @@ -411,6 +448,8 @@ def _get_steps(num_steps, start=0.0, end=1.0, exponent=1, flip=False): def _repeat_coords(coords, repeats): + if not coords: + return coords final_coords = [] for i in range(repeats): if i % 2 == 1: |
