knit-graphs 0.0.11__py3-none-any.whl → 0.0.12__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- knit_graphs/Course.py +63 -42
- knit_graphs/Knit_Graph.py +62 -160
- knit_graphs/Knit_Graph_Visualizer.py +51 -63
- knit_graphs/Loop.py +122 -116
- knit_graphs/Pull_Direction.py +3 -2
- knit_graphs/Yarn.py +246 -233
- knit_graphs/artin_wale_braids/Loop_Braid_Graph.py +42 -62
- knit_graphs/artin_wale_braids/Wale.py +61 -82
- knit_graphs/artin_wale_braids/Wale_Braid.py +7 -2
- knit_graphs/artin_wale_braids/Wale_Braid_Word.py +35 -22
- knit_graphs/artin_wale_braids/Wale_Group.py +46 -39
- knit_graphs/basic_knit_graph_generators.py +89 -168
- knit_graphs/directed_loop_graph.py +454 -0
- knit_graphs/knit_graph_builder.py +187 -0
- knit_graphs/knit_graph_errors/__init__.py +0 -0
- knit_graphs/knit_graph_errors/knit_graph_error.py +30 -0
- {knit_graphs-0.0.11.dist-info → knit_graphs-0.0.12.dist-info}/METADATA +1 -1
- {knit_graphs-0.0.11.dist-info → knit_graphs-0.0.12.dist-info}/RECORD +20 -16
- {knit_graphs-0.0.11.dist-info → knit_graphs-0.0.12.dist-info}/LICENSE +0 -0
- {knit_graphs-0.0.11.dist-info → knit_graphs-0.0.12.dist-info}/WHEEL +0 -0
|
@@ -5,18 +5,22 @@ This module provides the Wale_Group class which represents a collection of inter
|
|
|
5
5
|
|
|
6
6
|
from __future__ import annotations
|
|
7
7
|
|
|
8
|
-
from typing import TYPE_CHECKING,
|
|
8
|
+
from typing import TYPE_CHECKING, TypeVar
|
|
9
9
|
|
|
10
10
|
from networkx import DiGraph, dfs_preorder_nodes
|
|
11
11
|
|
|
12
12
|
from knit_graphs.artin_wale_braids.Wale import Wale
|
|
13
|
+
from knit_graphs.directed_loop_graph import Directed_Loop_Graph
|
|
13
14
|
from knit_graphs.Loop import Loop
|
|
15
|
+
from knit_graphs.Pull_Direction import Pull_Direction
|
|
14
16
|
|
|
15
17
|
if TYPE_CHECKING:
|
|
16
18
|
from knit_graphs.Knit_Graph import Knit_Graph
|
|
17
19
|
|
|
20
|
+
LoopT = TypeVar("LoopT", bound=Loop)
|
|
18
21
|
|
|
19
|
-
|
|
22
|
+
|
|
23
|
+
class Wale_Group(Directed_Loop_Graph[LoopT, Pull_Direction]):
|
|
20
24
|
"""A graph structure maintaining relationships between connected wales through decrease operations.
|
|
21
25
|
|
|
22
26
|
This class represents a collection of wales that are connected through decrease stitches, where multiple wales merge into fewer wales as the knitting progresses upward.
|
|
@@ -24,47 +28,68 @@ class Wale_Group:
|
|
|
24
28
|
|
|
25
29
|
Attributes:
|
|
26
30
|
wale_graph (DiGraph): A directed graph representing the relationships between wales in this group.
|
|
27
|
-
stitch_graph (DiGraph): A directed graph of all individual stitch connections within this wale group.
|
|
28
31
|
top_loops (dict[Loop, Wale]): Mapping from the last (top) loop of each wale to the wale itself.
|
|
29
32
|
bottom_loops (dict[Loop, Wale]): Mapping from the first (bottom) loop of each wale to the wale itself.
|
|
30
33
|
"""
|
|
31
34
|
|
|
32
|
-
def __init__(self, terminal_loop:
|
|
35
|
+
def __init__(self, terminal_loop: LoopT, knit_graph: Knit_Graph[LoopT]):
|
|
33
36
|
"""Initialize a wale group starting from a terminal wale and building downward.
|
|
34
37
|
|
|
35
38
|
Args:
|
|
36
39
|
terminal_loop (Loop): The terminal loop of this wale-group. All the wales in the group connect up to this loop.
|
|
37
40
|
knit_graph (Knit_Graph): The parent knit graph that contains this wale group.
|
|
38
41
|
"""
|
|
42
|
+
super().__init__()
|
|
39
43
|
self.wale_graph: DiGraph = DiGraph()
|
|
40
|
-
self.
|
|
41
|
-
self.
|
|
42
|
-
self.
|
|
43
|
-
self.
|
|
44
|
-
self.bottom_loops: dict[Loop, Wale] = {}
|
|
44
|
+
self._knit_graph: Knit_Graph[LoopT] = knit_graph
|
|
45
|
+
self._terminal_loop: LoopT = terminal_loop
|
|
46
|
+
self.top_loops: dict[LoopT, Wale] = {}
|
|
47
|
+
self.bottom_loops: dict[LoopT, Wale] = {}
|
|
45
48
|
self._build_wale_group()
|
|
46
49
|
|
|
47
50
|
@property
|
|
48
|
-
def terminal_loop(self) ->
|
|
51
|
+
def terminal_loop(self) -> LoopT:
|
|
49
52
|
"""
|
|
50
53
|
Returns:
|
|
51
|
-
|
|
54
|
+
LoopT: The loop that terminates all wales in this group.
|
|
52
55
|
"""
|
|
53
56
|
return self._terminal_loop
|
|
54
57
|
|
|
58
|
+
def get_loops_over_courses(self) -> list[list[LoopT]]:
|
|
59
|
+
"""Get loops organized by their course (horizontal row) within this wale group.
|
|
60
|
+
|
|
61
|
+
This method traces through the stitch connections starting from the terminal wale's top loop and groups loops by their vertical position (course) in the knitted structure.
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
list[list[LoopT]]: A list where each inner list contains all loops that belong to the same course, ordered from top to bottom courses. Returns empty list if there is no terminal wale.
|
|
65
|
+
"""
|
|
66
|
+
courses: list[list[LoopT]] = []
|
|
67
|
+
cur_course: list[LoopT] = [self._terminal_loop]
|
|
68
|
+
while len(cur_course) > 0:
|
|
69
|
+
courses.append(cur_course)
|
|
70
|
+
next_course: list[LoopT] = []
|
|
71
|
+
for loop in cur_course:
|
|
72
|
+
next_course.extend(self.predecessors(loop))
|
|
73
|
+
cur_course = next_course
|
|
74
|
+
return courses
|
|
75
|
+
|
|
55
76
|
def _build_wale_group(self) -> None:
|
|
56
77
|
full_wales = self._knit_graph.get_wales_ending_with_loop(self._terminal_loop)
|
|
57
78
|
# Build up the stitch graph.
|
|
58
79
|
for wale in full_wales:
|
|
59
|
-
u_loops
|
|
60
|
-
v_loops
|
|
80
|
+
u_loops = wale[:-1]
|
|
81
|
+
v_loops = wale[1:]
|
|
61
82
|
for u, v in zip(u_loops, v_loops, strict=False):
|
|
62
|
-
|
|
83
|
+
if u not in self:
|
|
84
|
+
self.add_loop(u)
|
|
85
|
+
if v not in self:
|
|
86
|
+
self.add_loop(v)
|
|
87
|
+
self.add_edge(u, v, self._knit_graph.get_pull_direction(u, v))
|
|
63
88
|
wales_to_split = full_wales
|
|
64
89
|
while len(wales_to_split) > 0:
|
|
65
90
|
wale_to_split = wales_to_split.pop()
|
|
66
91
|
split = False
|
|
67
|
-
upper_loops =
|
|
92
|
+
upper_loops = wale_to_split[1:]
|
|
68
93
|
for (
|
|
69
94
|
loop
|
|
70
95
|
) in upper_loops: # skip first loop in each wale as it may be already connected to a discovered decrease.
|
|
@@ -87,24 +112,6 @@ class Wale_Group:
|
|
|
87
112
|
self.top_loops[wale.last_loop] = wale
|
|
88
113
|
self.bottom_loops[wale.first_loop] = wale
|
|
89
114
|
|
|
90
|
-
def get_loops_over_courses(self) -> list[list[Loop]]:
|
|
91
|
-
"""Get loops organized by their course (horizontal row) within this wale group.
|
|
92
|
-
|
|
93
|
-
This method traces through the stitch connections starting from the terminal wale's top loop and groups loops by their vertical position (course) in the knitted structure.
|
|
94
|
-
|
|
95
|
-
Returns:
|
|
96
|
-
list[list[Loop]]: A list where each inner list contains all loops that belong to the same course, ordered from top to bottom courses. Returns empty list if there is no terminal wale.
|
|
97
|
-
"""
|
|
98
|
-
courses: list[list[Loop]] = []
|
|
99
|
-
cur_course: list[Loop] = [self._terminal_loop]
|
|
100
|
-
while len(cur_course) > 0:
|
|
101
|
-
courses.append(cur_course)
|
|
102
|
-
next_course = []
|
|
103
|
-
for loop in cur_course:
|
|
104
|
-
next_course.extend(self.stitch_graph.predecessors(loop))
|
|
105
|
-
cur_course = next_course
|
|
106
|
-
return courses
|
|
107
|
-
|
|
108
115
|
def __len__(self) -> int:
|
|
109
116
|
"""Get the height of the wale group measured as the maximum number of loops from base to terminal.
|
|
110
117
|
|
|
@@ -126,18 +133,18 @@ class Wale_Group:
|
|
|
126
133
|
"""
|
|
127
134
|
return hash(self._terminal_loop)
|
|
128
135
|
|
|
129
|
-
def __contains__(self, item:
|
|
136
|
+
def __contains__(self, item: LoopT | int | tuple[LoopT | int, LoopT | int] | Wale) -> bool:
|
|
130
137
|
"""
|
|
131
138
|
Args:
|
|
132
|
-
item (
|
|
139
|
+
item (LoopT | int | tuple[LoopT | int, LoopT | int] | Wale): The item to check for in the wale group.
|
|
133
140
|
|
|
134
141
|
Returns:
|
|
135
|
-
bool: True if the given loop, loop_id (int), or wale is in this group.
|
|
142
|
+
bool: True if the given loop, loop_id (int), pair of loops, or wale is in this group.
|
|
136
143
|
"""
|
|
137
|
-
if isinstance(item,
|
|
138
|
-
return item in self.stitch_graph.nodes
|
|
139
|
-
else: # isinstance(item, Wale):
|
|
144
|
+
if isinstance(item, Wale):
|
|
140
145
|
return item in self.wale_graph
|
|
146
|
+
else:
|
|
147
|
+
return super().__contains__(item)
|
|
141
148
|
|
|
142
149
|
def __str__(self) -> str:
|
|
143
150
|
"""
|
|
@@ -4,30 +4,34 @@ This module provides utility functions for creating common knitting patterns and
|
|
|
4
4
|
These functions serve as building blocks for testing and demonstration purposes.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
from
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from collections.abc import Sequence
|
|
10
|
+
|
|
8
11
|
from knit_graphs.Knit_Graph import Knit_Graph
|
|
12
|
+
from knit_graphs.knit_graph_builder import Knit_Graph_Builder
|
|
9
13
|
from knit_graphs.Loop import Loop
|
|
10
14
|
from knit_graphs.Pull_Direction import Pull_Direction
|
|
11
15
|
from knit_graphs.Yarn import Yarn
|
|
12
16
|
|
|
13
17
|
|
|
14
|
-
def co_loops(width: int) -> tuple[Knit_Graph, Yarn]:
|
|
18
|
+
def co_loops(width: int) -> tuple[Knit_Graph_Builder[Loop], Knit_Graph[Loop], Yarn[Loop]]:
|
|
15
19
|
"""Create a cast-on row of loops forming the foundation for knitting patterns.
|
|
16
20
|
|
|
17
21
|
Args:
|
|
18
22
|
width (int): The number of loops to create in the cast-on row.
|
|
19
23
|
|
|
20
24
|
Returns:
|
|
21
|
-
tuple[Knit_Graph, Yarn]: A tuple containing the knit graph with one course of the specified width and the yarn used to create it.
|
|
25
|
+
tuple[Knit_Graph_Builder[Loop], Knit_Graph[Loop], Yarn[Loop]: A tuple containing the knit graph builder and its knitgraph with one course of the specified width and the yarn used to create it.
|
|
22
26
|
"""
|
|
23
|
-
|
|
24
|
-
yarn =
|
|
27
|
+
builder = Knit_Graph_Builder[Loop]()
|
|
28
|
+
yarn = builder.add_yarn()
|
|
25
29
|
for _ in range(0, width):
|
|
26
|
-
_loop =
|
|
27
|
-
return knit_graph, yarn
|
|
30
|
+
_loop = builder.tuck(yarn)
|
|
31
|
+
return builder, builder.knit_graph, yarn
|
|
28
32
|
|
|
29
33
|
|
|
30
|
-
def jersey_swatch(width: int, height: int) -> Knit_Graph:
|
|
34
|
+
def jersey_swatch(width: int, height: int) -> Knit_Graph[Loop]:
|
|
31
35
|
"""Generate a rectangular knit swatch with all knit stitches in a flat sheet structure.
|
|
32
36
|
|
|
33
37
|
This creates a basic stockinette/jersey pattern where all stitches are worked as knit stitches from back to front.
|
|
@@ -39,19 +43,14 @@ def jersey_swatch(width: int, height: int) -> Knit_Graph:
|
|
|
39
43
|
Returns:
|
|
40
44
|
Knit_Graph: A knit graph representing a flat rectangular swatch with all knit stitches.
|
|
41
45
|
"""
|
|
42
|
-
knit_graph, yarn = co_loops(width)
|
|
43
|
-
last_course =
|
|
46
|
+
builder, knit_graph, yarn = co_loops(width)
|
|
47
|
+
last_course: Sequence[Loop] = knit_graph.get_courses()[0]
|
|
44
48
|
for _ in range(0, height):
|
|
45
|
-
|
|
46
|
-
for parent_loop in reversed(last_course):
|
|
47
|
-
child_loop = yarn.make_loop_on_end()
|
|
48
|
-
knit_graph.connect_loops(parent_loop, child_loop, pull_direction=Pull_Direction.BtF)
|
|
49
|
-
next_course.append(child_loop)
|
|
50
|
-
last_course = next_course
|
|
49
|
+
last_course = [builder.knit(yarn, [parent_loop]) for parent_loop in reversed(last_course)]
|
|
51
50
|
return knit_graph
|
|
52
51
|
|
|
53
52
|
|
|
54
|
-
def jersey_tube(tube_width: int, height: int) -> Knit_Graph:
|
|
53
|
+
def jersey_tube(tube_width: int, height: int) -> Knit_Graph[Loop]:
|
|
55
54
|
"""Generate a tubular knit structure with all knit stitches worked in the round.
|
|
56
55
|
|
|
57
56
|
This creates a seamless tube by knitting in the round, where the front and back sections are connected by floats to maintain the circular structure.
|
|
@@ -63,33 +62,22 @@ def jersey_tube(tube_width: int, height: int) -> Knit_Graph:
|
|
|
63
62
|
Returns:
|
|
64
63
|
Knit_Graph: A knit graph representing a seamless tube with all knit stitches.
|
|
65
64
|
"""
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
"""Internal helper function to set up float connections between front and back of tube."""
|
|
71
|
-
front_loops = last_course[0:tube_width]
|
|
72
|
-
back_loops = last_course[tube_width:]
|
|
73
|
-
for first_front, second_front, back in zip(
|
|
74
|
-
front_loops[0:-1], front_loops[1:], reversed(back_loops), strict=False
|
|
75
|
-
):
|
|
76
|
-
yarn.add_loop_behind_float(back, first_front, second_front)
|
|
77
|
-
for first_back, second_back, front in zip(
|
|
78
|
-
back_loops[0:-1], back_loops[1:], reversed(front_loops), strict=False
|
|
79
|
-
):
|
|
80
|
-
yarn.add_loop_in_front_of_float(front, first_back, second_back)
|
|
81
|
-
|
|
82
|
-
_set_tube_floats()
|
|
65
|
+
builder = Knit_Graph_Builder[Loop]()
|
|
66
|
+
yarn = builder.add_yarn()
|
|
67
|
+
front_of_tube = [builder.tuck(yarn) for _ in range(0, tube_width)]
|
|
68
|
+
back_of_tube = [builder.tuck(yarn) for _ in reversed(front_of_tube)]
|
|
83
69
|
for _ in range(0, height):
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
70
|
+
for fl, bl in zip(front_of_tube[:-1], reversed(back_of_tube[1:]), strict=False):
|
|
71
|
+
builder.position_float(fl, loops_behind_float=[bl])
|
|
72
|
+
for fl, bl in zip(reversed(front_of_tube[1:]), back_of_tube[:-1], strict=False):
|
|
73
|
+
builder.position_float(bl, loops_in_front_of_float=[fl])
|
|
74
|
+
front_of_tube = [builder.knit(yarn, [fl], Pull_Direction.BtF) for fl in front_of_tube]
|
|
75
|
+
back_of_tube = [builder.knit(yarn, [bl], Pull_Direction.FtB) for bl in back_of_tube]
|
|
90
76
|
|
|
77
|
+
return builder.knit_graph
|
|
91
78
|
|
|
92
|
-
|
|
79
|
+
|
|
80
|
+
def kp_rib_swatch(width: int, height: int) -> Knit_Graph[Loop]:
|
|
93
81
|
"""Generate a knit-purl ribbing swatch with alternating wales of knit and purl stitches.
|
|
94
82
|
|
|
95
83
|
This creates a 1x1 ribbing pattern where knit and purl wales alternate, maintaining their stitch type throughout the height of the swatch for a stretchy, textured fabric.
|
|
@@ -101,30 +89,19 @@ def kp_rib_swatch(width: int, height: int) -> Knit_Graph:
|
|
|
101
89
|
Returns:
|
|
102
90
|
Knit_Graph: A knit graph representing a ribbed swatch with alternating knit and purl wales.
|
|
103
91
|
"""
|
|
104
|
-
knit_graph, yarn = co_loops(width)
|
|
105
|
-
last_course = knit_graph.get_courses()[0]
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
last_course = next_course
|
|
114
|
-
for _ in range(1, height):
|
|
115
|
-
next_course = []
|
|
116
|
-
for parent_loop in reversed(last_course):
|
|
117
|
-
grand_parent = parent_loop.parent_loops[0]
|
|
118
|
-
parent_pull = knit_graph.get_pull_direction(grand_parent, parent_loop)
|
|
119
|
-
assert isinstance(parent_pull, Pull_Direction)
|
|
120
|
-
child_loop = yarn.make_loop_on_end()
|
|
121
|
-
knit_graph.connect_loops(parent_loop, child_loop, pull_direction=parent_pull)
|
|
122
|
-
next_course.append(child_loop)
|
|
123
|
-
last_course = next_course
|
|
92
|
+
builder, knit_graph, yarn = co_loops(width)
|
|
93
|
+
last_course: Sequence[Loop] = knit_graph.get_courses()[0]
|
|
94
|
+
for _ in range(0, height):
|
|
95
|
+
assert yarn.last_loop is not None
|
|
96
|
+
pull_direction = yarn.last_loop.pull_directions[0] if yarn.last_loop.has_parent_loops else Pull_Direction.BtF
|
|
97
|
+
last_course = [
|
|
98
|
+
builder.knit(yarn, [parent_loop], pull_direction=pull_direction if i % 2 == 0 else pull_direction.opposite)
|
|
99
|
+
for i, parent_loop in enumerate(reversed(last_course))
|
|
100
|
+
]
|
|
124
101
|
return knit_graph
|
|
125
102
|
|
|
126
103
|
|
|
127
|
-
def seed_swatch(width: int, height: int) -> Knit_Graph:
|
|
104
|
+
def seed_swatch(width: int, height: int) -> Knit_Graph[Loop]:
|
|
128
105
|
"""Generate a seed stitch swatch with a checkerboard pattern of knit and purl stitches.
|
|
129
106
|
|
|
130
107
|
This creates a textured fabric where each stitch alternates between knit and purl both horizontally and vertically, creating a bumpy, non-curling fabric texture.
|
|
@@ -136,30 +113,19 @@ def seed_swatch(width: int, height: int) -> Knit_Graph:
|
|
|
136
113
|
Returns:
|
|
137
114
|
Knit_Graph: A knit graph representing a seed stitch swatch with checkerboard knit-purl pattern.
|
|
138
115
|
"""
|
|
139
|
-
knit_graph, yarn = co_loops(width)
|
|
140
|
-
last_course = knit_graph.get_courses()[0]
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
last_course = next_course
|
|
149
|
-
for _ in range(1, height):
|
|
150
|
-
next_course = []
|
|
151
|
-
for parent_loop in reversed(last_course):
|
|
152
|
-
grand_parent = parent_loop.parent_loops[0]
|
|
153
|
-
parent_pull = knit_graph.get_pull_direction(grand_parent, parent_loop)
|
|
154
|
-
assert isinstance(parent_pull, Pull_Direction)
|
|
155
|
-
child_loop = yarn.make_loop_on_end()
|
|
156
|
-
knit_graph.connect_loops(parent_loop, child_loop, pull_direction=parent_pull.opposite())
|
|
157
|
-
next_course.append(child_loop)
|
|
158
|
-
last_course = next_course
|
|
116
|
+
builder, knit_graph, yarn = co_loops(width)
|
|
117
|
+
last_course: Sequence[Loop] = knit_graph.get_courses()[0]
|
|
118
|
+
for _ in range(0, height):
|
|
119
|
+
assert yarn.last_loop is not None
|
|
120
|
+
pull_direction = yarn.last_loop.pull_directions[0] if yarn.last_loop.has_parent_loops else Pull_Direction.BtF
|
|
121
|
+
last_course = [
|
|
122
|
+
builder.knit(yarn, [parent_loop], pull_direction=pull_direction.opposite if i % 2 == 0 else pull_direction)
|
|
123
|
+
for i, parent_loop in enumerate(reversed(last_course))
|
|
124
|
+
]
|
|
159
125
|
return knit_graph
|
|
160
126
|
|
|
161
127
|
|
|
162
|
-
def lace_mesh(width: int, height: int) -> Knit_Graph:
|
|
128
|
+
def lace_mesh(width: int, height: int) -> Knit_Graph[Loop]:
|
|
163
129
|
"""Generate a mesh pattern with alternating left and right leaning decrease paired to yarn-overs.
|
|
164
130
|
These pairings create a basic lace pattern with eyelets formed around the increases.
|
|
165
131
|
|
|
@@ -170,73 +136,31 @@ def lace_mesh(width: int, height: int) -> Knit_Graph:
|
|
|
170
136
|
Returns:
|
|
171
137
|
Knit_Graph: A knit graph representing a mesh swatch.
|
|
172
138
|
"""
|
|
173
|
-
knit_graph, yarn = co_loops(width)
|
|
174
|
-
last_course = knit_graph.get_courses()[0]
|
|
175
|
-
next_course = []
|
|
176
|
-
for parent_loop in reversed(last_course):
|
|
177
|
-
child_loop = yarn.make_loop_on_end()
|
|
178
|
-
knit_graph.connect_loops(parent_loop, child_loop, pull_direction=Pull_Direction.BtF)
|
|
179
|
-
next_course.append(child_loop)
|
|
180
|
-
last_course = next_course
|
|
139
|
+
builder, knit_graph, yarn = co_loops(width)
|
|
140
|
+
last_course = [builder.knit(yarn, [p]) for p in reversed(knit_graph.get_courses()[0])]
|
|
181
141
|
for _ in range(1, height):
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
knit_graph.connect_loops(
|
|
190
|
-
parent_loop,
|
|
191
|
-
child_loop,
|
|
192
|
-
pull_direction=Pull_Direction.BtF,
|
|
193
|
-
stack_position=0,
|
|
194
|
-
)
|
|
195
|
-
elif i % 6 == 1: # Second of every 6 stitches (0 indexed) is yarn over before a decrease.
|
|
196
|
-
yo_parent = parent_loop
|
|
197
|
-
elif i % 6 == 2: # Third of every 6 stitches is bottom of decrease with prior yarn-over's parent
|
|
198
|
-
knit_graph.connect_loops(
|
|
199
|
-
parent_loop,
|
|
200
|
-
child_loop,
|
|
201
|
-
pull_direction=Pull_Direction.BtF,
|
|
202
|
-
stack_position=0,
|
|
203
|
-
)
|
|
204
|
-
assert isinstance(yo_parent, Loop)
|
|
205
|
-
knit_graph.connect_loops(
|
|
206
|
-
yo_parent,
|
|
207
|
-
child_loop,
|
|
208
|
-
pull_direction=Pull_Direction.BtF,
|
|
209
|
-
stack_position=1,
|
|
210
|
-
)
|
|
211
|
-
elif i % 6 == 4: # Fifth of every six stitches is bottom of decrease with next yarn-over's parent
|
|
212
|
-
knit_graph.connect_loops(
|
|
213
|
-
parent_loop,
|
|
214
|
-
child_loop,
|
|
215
|
-
pull_direction=Pull_Direction.BtF,
|
|
216
|
-
stack_position=0,
|
|
217
|
-
)
|
|
218
|
-
prior_child = child_loop
|
|
219
|
-
elif i % 6 == 5: # The last of six stitches is the top of the prior decrease and new yarn-over
|
|
220
|
-
assert isinstance(prior_child, Loop)
|
|
221
|
-
knit_graph.connect_loops(
|
|
222
|
-
parent_loop,
|
|
223
|
-
prior_child,
|
|
224
|
-
pull_direction=Pull_Direction.BtF,
|
|
225
|
-
stack_position=1,
|
|
226
|
-
)
|
|
227
|
-
next_course.append(child_loop)
|
|
228
|
-
last_course = next_course
|
|
229
|
-
# Make a basic jersey course
|
|
142
|
+
dec1 = last_course[1::3]
|
|
143
|
+
dec2 = last_course[2::3]
|
|
144
|
+
decs = [
|
|
145
|
+
dec_parents if i % 2 == 0 else (dec_parents[1], dec_parents[0])
|
|
146
|
+
for i, dec_parents in enumerate(zip(reversed(dec1), reversed(dec2), strict=False))
|
|
147
|
+
]
|
|
148
|
+
knits = last_course[0::3]
|
|
230
149
|
next_course = []
|
|
231
|
-
for parent_loop in reversed(
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
150
|
+
for i, parent_loop in enumerate(reversed(knits)):
|
|
151
|
+
next_course.append(builder.knit(yarn, [parent_loop]))
|
|
152
|
+
if len(decs) > 0:
|
|
153
|
+
if i % 2 == 0:
|
|
154
|
+
next_course.append(builder.tuck(yarn))
|
|
155
|
+
next_course.append(builder.knit(yarn, decs.pop(0)))
|
|
156
|
+
else:
|
|
157
|
+
next_course.append(builder.knit(yarn, decs.pop(0)))
|
|
158
|
+
next_course.append(builder.tuck(yarn))
|
|
159
|
+
last_course = [builder.knit(yarn, [p]) for p in reversed(next_course)]
|
|
236
160
|
return knit_graph
|
|
237
161
|
|
|
238
162
|
|
|
239
|
-
def twist_cable(width: int, height: int) -> Knit_Graph:
|
|
163
|
+
def twist_cable(width: int, height: int) -> Knit_Graph[Loop]:
|
|
240
164
|
"""Generate a twisted cable pattern with alternating crossing directions and purl separators.
|
|
241
165
|
|
|
242
166
|
This creates a cable pattern with 1x1 twists that alternate direction every two rows, separated by purl wales to make the cable structure more prominent.
|
|
@@ -253,34 +177,31 @@ def twist_cable(width: int, height: int) -> Knit_Graph:
|
|
|
253
177
|
# p k/k p ->: 1-2
|
|
254
178
|
# p k k p <-: 0-1
|
|
255
179
|
# 0 1 2 3
|
|
256
|
-
knit_graph, yarn = co_loops(width)
|
|
257
|
-
last_course = knit_graph.get_courses()[0]
|
|
258
|
-
next_course = []
|
|
180
|
+
builder, knit_graph, yarn = co_loops(width)
|
|
259
181
|
pull_directions = [
|
|
260
182
|
Pull_Direction.FtB,
|
|
261
183
|
Pull_Direction.BtF,
|
|
262
184
|
Pull_Direction.BtF,
|
|
263
185
|
Pull_Direction.FtB,
|
|
264
186
|
]
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
187
|
+
last_course = [
|
|
188
|
+
builder.knit(yarn, [p], pull_directions[i % 4]) for i, p in enumerate(reversed(knit_graph.get_courses()[0]))
|
|
189
|
+
]
|
|
190
|
+
for r in range(1, height, 2):
|
|
191
|
+
crossed_course: list[Loop] = []
|
|
192
|
+
for i, parent_loop in enumerate(last_course):
|
|
193
|
+
if i % 4 == 2:
|
|
194
|
+
crossed_course.insert(-1, parent_loop)
|
|
195
|
+
else:
|
|
196
|
+
crossed_course.append(parent_loop)
|
|
197
|
+
last_course = [builder.knit(yarn, [p]) for p in reversed(crossed_course)]
|
|
198
|
+
left_cable_loops = last_course[-2:0:-4]
|
|
199
|
+
right_cable_loops = last_course[-3:0:-4]
|
|
200
|
+
for left_loop, right_loop in zip(left_cable_loops, right_cable_loops, strict=False):
|
|
201
|
+
if r % 4 == 1:
|
|
202
|
+
builder.xfer(left_loop, over_loops_to_right=[right_loop])
|
|
278
203
|
else:
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
for left_loop, right_loop in zip(next_course[1::4], next_course[2::4], strict=False):
|
|
283
|
-
knit_graph.add_crossing(left_loop, right_loop, crossing)
|
|
284
|
-
crossing = ~crossing
|
|
285
|
-
last_course = next_course
|
|
204
|
+
builder.xfer(left_loop, under_loops_to_right=[right_loop])
|
|
205
|
+
last_course = [builder.knit(yarn, [p]) for p in reversed(last_course)]
|
|
206
|
+
|
|
286
207
|
return knit_graph
|