summaryrefslogtreecommitdiff
path: root/lib/stitches/running_stitch.py
blob: 0bb8fc7d734122202ba6d8c25e1d3178eb171817 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
from copy import copy

""" Utility functions to produce running stitches. """


def running_stitch(points, stitch_length):
    """Generate running stitch along a path.

    Given a path and a stitch length, walk along the path in increments of the
    stitch length.  If sharp corners are encountered, an extra stitch will be
    added at the corner to avoid rounding the corner.  The starting and ending
    point are always stitched.

    The path is described by a set of line segments, each connected to the next.
    The line segments are described by a sequence of points.
    """

    if len(points) < 2:
        return []

    output = []
    segment_start = points[0]
    last_segment_direction = None

    # This tracks the distance we've traveled along the current segment so
    # far.  Each time we make a stitch, we add the stitch_length to this
    # value.  If we fall off the end of the current segment, we carry over
    # the remainder to the next segment.
    distance = 0.0

    for segment_end in points[1:]:
        segment = segment_end - segment_start
        segment_length = segment.length()

        if segment_length == 0:
            continue

        segment_direction = segment.unit()

        # corner detection
        if last_segment_direction:
            cos_angle_between = segment_direction * last_segment_direction

            # This checks whether the corner is sharper than 45 degrees.
            if cos_angle_between < 0.5:
                # Only add the corner point if it's more than 0.1mm away to
                # avoid a double-stitch.
                if (segment_start - output[-1]).length() > 0.1:
                    # add a stitch at the corner
                    output.append(segment_start)

                    # next stitch needs to be stitch_length along this segment
                    distance = stitch_length

        while distance < segment_length:
            output.append(segment_start + distance * segment_direction)
            distance += stitch_length

        # prepare for the next segment
        segment_start = segment_end
        last_segment_direction = segment_direction
        distance -= segment_length

    # stitch a single point if the path has a length of zero
    if not output:
        output.append(segment_start)

    # stitch the last point unless we're already almost there
    if (segment_start - output[-1]).length() > 0.1 or len(output) == 0:
        output.append(segment_start)

    return output


def bean_stitch(stitches, repeats):
    """Generate bean stitch from a set of stitches.

    "Bean" stitch is made by backtracking each stitch to make it heaver.  A
    simple bean stitch would be two stitches forward, one stitch back, two
    stitches forward, etc.  This would result in each stitch being tripled.

    We'll say that the above counts as 1 repeat.  Backtracking each stitch
    repeatedly will result in a heavier bean stitch.  There will always be
    an odd number of threads piled up for each stitch.
    """

    if len(stitches) < 2:
        return stitches

    new_stitches = [stitches[0]]

    for stitch in stitches:
        new_stitches.append(stitch)

        for i in xrange(repeats):
            new_stitches.extend(copy(new_stitches[-2:]))

    return new_stitches