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.
@@ -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, cast
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
- class Wale_Group:
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: Loop, knit_graph: Knit_Graph):
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.stitch_graph: DiGraph = DiGraph()
41
- self._knit_graph: Knit_Graph = knit_graph
42
- self._terminal_loop: Loop = terminal_loop
43
- self.top_loops: dict[Loop, Wale] = {}
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) -> Loop:
51
+ def terminal_loop(self) -> LoopT:
49
52
  """
50
53
  Returns:
51
- Loop: The loop that terminates all wales in this group.
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: list[Loop] = cast(list[Loop], wale[:-1])
60
- v_loops: list[Loop] = cast(list[Loop], wale[1:])
80
+ u_loops = wale[:-1]
81
+ v_loops = wale[1:]
61
82
  for u, v in zip(u_loops, v_loops, strict=False):
62
- self.stitch_graph.add_edge(u, v, pull_direction=self._knit_graph.get_pull_direction(u, v))
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 = cast(list[Loop], wale_to_split[1:])
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: Loop | int | Wale) -> bool:
136
+ def __contains__(self, item: LoopT | int | tuple[LoopT | int, LoopT | int] | Wale) -> bool:
130
137
  """
131
138
  Args:
132
- item (Loop | int | Wale): The item to check for in the wale group.
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, (Loop, int)):
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 knit_graphs.artin_wale_braids.Crossing_Direction import Crossing_Direction
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
- knit_graph = Knit_Graph()
24
- yarn = Yarn(knit_graph=knit_graph)
27
+ builder = Knit_Graph_Builder[Loop]()
28
+ yarn = builder.add_yarn()
25
29
  for _ in range(0, width):
26
- _loop = yarn.make_loop_on_end()
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 = list(knit_graph.get_courses()[0])
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
- next_course = []
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
- knit_graph, yarn = co_loops(tube_width * 2)
67
- last_course = [*knit_graph.get_courses()[0]]
68
-
69
- def _set_tube_floats() -> None:
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
- next_course = [yarn.make_loop_on_end() for _p in last_course]
85
- for parent_loop, child_loop in zip(last_course, next_course, strict=False):
86
- knit_graph.connect_loops(parent_loop, child_loop, pull_direction=Pull_Direction.BtF)
87
- last_course = next_course
88
- _set_tube_floats()
89
- return knit_graph
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
- def kp_rib_swatch(width: int, height: int) -> Knit_Graph:
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
- next_course = []
107
- next_pull = Pull_Direction.BtF
108
- for parent_loop in reversed(last_course):
109
- child_loop = yarn.make_loop_on_end()
110
- knit_graph.connect_loops(parent_loop, child_loop, pull_direction=next_pull)
111
- next_pull = next_pull.opposite()
112
- next_course.append(child_loop)
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
- next_course = []
142
- next_pull = Pull_Direction.BtF
143
- for parent_loop in reversed(last_course):
144
- child_loop = yarn.make_loop_on_end()
145
- knit_graph.connect_loops(parent_loop, child_loop, pull_direction=next_pull)
146
- next_pull = next_pull.opposite()
147
- next_course.append(child_loop)
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
- # Make the lace course
183
- next_course = []
184
- yo_parent = None
185
- prior_child = None
186
- for i, parent_loop in enumerate(reversed(last_course)):
187
- child_loop = yarn.make_loop_on_end()
188
- if i % 3 == 0: # Just knit every third stitch
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(last_course):
232
- child_loop = yarn.make_loop_on_end()
233
- knit_graph.connect_loops(parent_loop, child_loop, pull_direction=Pull_Direction.BtF)
234
- next_course.append(child_loop)
235
- last_course = next_course
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
- for i, parent_loop in enumerate(reversed(last_course)):
266
- child_loop = yarn.make_loop_on_end()
267
- knit_graph.connect_loops(parent_loop, child_loop, pull_direction=pull_directions[i % 4])
268
- next_course.append(child_loop)
269
- last_course = next_course
270
- crossing = Crossing_Direction.Over_Right
271
- for r in range(1, height):
272
- next_course = [yarn.make_loop_on_end() for _ in last_course]
273
- for i, parent_loop in enumerate(reversed(last_course)):
274
- if r % 2 == 0 or i % 4 == 0 or i % 4 == 3: # not cable row (even) or in purl wale
275
- child_loop = next_course[i]
276
- elif i % 4 == 1:
277
- child_loop = next_course[i + 1]
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
- child_loop = next_course[i - 1]
280
- knit_graph.connect_loops(parent_loop, child_loop, pull_direction=pull_directions[i % 4])
281
- if r % 2 == 1: # cable row
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