knit-graphs 0.0.1__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 +104 -0
- knit_graphs/Knit_Graph.py +187 -0
- knit_graphs/Loop.py +155 -0
- knit_graphs/Pull_Direction.py +23 -0
- knit_graphs/Yarn.py +279 -0
- knit_graphs/__about__.py +4 -0
- knit_graphs/__init__.py +3 -0
- knit_graphs/artin_wale_braids/Crossing_Direction.py +15 -0
- knit_graphs/artin_wale_braids/Loop_Braid_Graph.py +62 -0
- knit_graphs/artin_wale_braids/Wale.py +93 -0
- knit_graphs/artin_wale_braids/Wale_Braid.py +30 -0
- knit_graphs/artin_wale_braids/Wale_Braid_Word.py +54 -0
- knit_graphs/artin_wale_braids/Wale_Group.py +88 -0
- knit_graphs/artin_wale_braids/__init__.py +0 -0
- knit_graphs/knit_graph_generators/__init__.py +0 -0
- knit_graphs/knit_graph_generators/basic_knit_graph_generators.py +248 -0
- knit_graphs/knit_graph_visualizer/Stitch_Visualizer.py +427 -0
- knit_graphs/knit_graph_visualizer/__init__.py +0 -0
- knit_graphs-0.0.1.dist-info/METADATA +96 -0
- knit_graphs-0.0.1.dist-info/RECORD +22 -0
- knit_graphs-0.0.1.dist-info/WHEEL +4 -0
- knit_graphs-0.0.1.dist-info/licenses/LICENSE +21 -0
knit_graphs/Course.py
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""Course representation of a section of knitting with no parent loops."""
|
|
2
|
+
from knit_graphs.Loop import Loop
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Course:
|
|
6
|
+
"""
|
|
7
|
+
Course object for organizing loops into knitting rows
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
def __init__(self):
|
|
11
|
+
self.loops_in_order: list[Loop] = []
|
|
12
|
+
self._loop_set: dict[Loop, Loop] = {}
|
|
13
|
+
|
|
14
|
+
def add_loop(self, loop: Loop, index: int | None = None):
|
|
15
|
+
"""
|
|
16
|
+
Add the loop at the given index or to the end of the course
|
|
17
|
+
:param loop: loop to add
|
|
18
|
+
:param index: index to insert at or None if adding to end
|
|
19
|
+
"""
|
|
20
|
+
for parent_loop in loop.parent_loops:
|
|
21
|
+
assert parent_loop not in self, f"{loop} has parent {parent_loop}, cannot be added to same course"
|
|
22
|
+
self._loop_set[loop] = loop
|
|
23
|
+
if index is None:
|
|
24
|
+
self.loops_in_order.append(loop)
|
|
25
|
+
else:
|
|
26
|
+
self.loops_in_order.insert(index, loop)
|
|
27
|
+
|
|
28
|
+
def has_increase(self) -> bool:
|
|
29
|
+
"""
|
|
30
|
+
:return: True if course has at least one yarn over to start new wales.
|
|
31
|
+
"""
|
|
32
|
+
for loop in self:
|
|
33
|
+
if not loop.has_parent_loops(): # Yarn over
|
|
34
|
+
return True
|
|
35
|
+
return False
|
|
36
|
+
|
|
37
|
+
def has_decrease(self) -> bool:
|
|
38
|
+
"""
|
|
39
|
+
:return: True if course has at least one decrease, merging two wales
|
|
40
|
+
"""
|
|
41
|
+
for loop in self:
|
|
42
|
+
if len(loop.parent_loops) > 1:
|
|
43
|
+
return True
|
|
44
|
+
return False
|
|
45
|
+
|
|
46
|
+
def has_terminal_loop(self, knit_graph) -> bool:
|
|
47
|
+
"""\
|
|
48
|
+
:param knit_graph: Knit graph to get child loop data from
|
|
49
|
+
:return: True if this course contains a terminal loop with no child
|
|
50
|
+
"""
|
|
51
|
+
for loop in self:
|
|
52
|
+
if knit_graph.get_child_loop(loop) is None:
|
|
53
|
+
return True
|
|
54
|
+
return False
|
|
55
|
+
|
|
56
|
+
def __getitem__(self, index: int | slice) -> Loop | list[Loop]:
|
|
57
|
+
return self.loops_in_order[index]
|
|
58
|
+
|
|
59
|
+
def index(self, loop: Loop) -> int:
|
|
60
|
+
"""
|
|
61
|
+
Searches for index of given loop_id
|
|
62
|
+
:param loop: loop_id or loop to find
|
|
63
|
+
:return: index of the loop_id
|
|
64
|
+
"""
|
|
65
|
+
return self.loops_in_order.index(loop)
|
|
66
|
+
|
|
67
|
+
def in_round_with(self, next_course) -> bool:
|
|
68
|
+
"""
|
|
69
|
+
:param next_course: another course who should follow this course
|
|
70
|
+
:return: True if the next course starts at the beginning of this course
|
|
71
|
+
"""
|
|
72
|
+
next_start = next_course[0]
|
|
73
|
+
i = 1
|
|
74
|
+
while not next_start.has_parent_loops():
|
|
75
|
+
next_start = next_course[i]
|
|
76
|
+
i += 1
|
|
77
|
+
return self[0] in next_start.parent_loops
|
|
78
|
+
|
|
79
|
+
def in_row_with(self, next_course) -> bool:
|
|
80
|
+
"""
|
|
81
|
+
:param next_course: another course that should follow this course.
|
|
82
|
+
:return: True if the next course starts at the end of this course.
|
|
83
|
+
"""
|
|
84
|
+
next_start = next_course[0]
|
|
85
|
+
i = 1
|
|
86
|
+
while not next_start.has_parent_loops():
|
|
87
|
+
next_start = next_course[i]
|
|
88
|
+
i += 1
|
|
89
|
+
return self[-1] in next_start.parent_loops
|
|
90
|
+
|
|
91
|
+
def __contains__(self, loop: Loop) -> bool:
|
|
92
|
+
return loop in self._loop_set
|
|
93
|
+
|
|
94
|
+
def __iter__(self):
|
|
95
|
+
return self.loops_in_order.__iter__()
|
|
96
|
+
|
|
97
|
+
def __len__(self):
|
|
98
|
+
return len(self.loops_in_order)
|
|
99
|
+
|
|
100
|
+
def __str__(self):
|
|
101
|
+
return str(self.loops_in_order)
|
|
102
|
+
|
|
103
|
+
def __repr__(self):
|
|
104
|
+
return str(self)
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"""The graph structure used to represent knitted objects"""
|
|
2
|
+
import networkx
|
|
3
|
+
|
|
4
|
+
from knit_graphs.Course import Course
|
|
5
|
+
from knit_graphs.Loop import Loop
|
|
6
|
+
from knit_graphs.Pull_Direction import Pull_Direction
|
|
7
|
+
from knit_graphs.Yarn import Yarn
|
|
8
|
+
from knit_graphs.artin_wale_braids.Crossing_Direction import Crossing_Direction
|
|
9
|
+
from knit_graphs.artin_wale_braids.Loop_Braid_Graph import Loop_Braid_Graph
|
|
10
|
+
from knit_graphs.artin_wale_braids.Wale import Wale
|
|
11
|
+
from knit_graphs.artin_wale_braids.Wale_Group import Wale_Group
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Knit_Graph:
|
|
15
|
+
"""
|
|
16
|
+
A representation of knitted structures as connections between loops on yarns
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def __init__(self):
|
|
20
|
+
self.stitch_graph: networkx.DiGraph = networkx.DiGraph()
|
|
21
|
+
self.braid_graph: Loop_Braid_Graph = Loop_Braid_Graph()
|
|
22
|
+
self._last_loop: None | Loop = None
|
|
23
|
+
self.yarns: dict[Yarn, Yarn] = {}
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def last_loop(self) -> None | Loop:
|
|
27
|
+
"""
|
|
28
|
+
:return: Last loop added to graph
|
|
29
|
+
"""
|
|
30
|
+
return self._last_loop
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def has_loop(self) -> bool:
|
|
34
|
+
"""
|
|
35
|
+
:return: True if graph has loops
|
|
36
|
+
"""
|
|
37
|
+
return self._last_loop is not None
|
|
38
|
+
|
|
39
|
+
def add_crossing(self, left_loop: Loop, right_loop: Loop, crossing_direction: Crossing_Direction):
|
|
40
|
+
"""
|
|
41
|
+
Adds edge between loops with attribute of the crossing direction.
|
|
42
|
+
:param left_loop: Loop on the left side of the crossing.
|
|
43
|
+
:param right_loop: Loop on the right side of the crossing.
|
|
44
|
+
:param crossing_direction: The crossing direction is (over, under, none) between loops.
|
|
45
|
+
"""
|
|
46
|
+
self.braid_graph.add_crossing(left_loop, right_loop, crossing_direction)
|
|
47
|
+
|
|
48
|
+
def add_loop(self, loop: Loop):
|
|
49
|
+
"""
|
|
50
|
+
Adds a loop to the graph
|
|
51
|
+
:param loop: the loop to be added in as a node in the graph
|
|
52
|
+
"""
|
|
53
|
+
self.stitch_graph.add_node(loop)
|
|
54
|
+
if loop.yarn not in self.yarns:
|
|
55
|
+
self.add_yarn(loop.yarn)
|
|
56
|
+
if self._last_loop is None or loop > self._last_loop:
|
|
57
|
+
self._last_loop = loop
|
|
58
|
+
|
|
59
|
+
def add_yarn(self, yarn: Yarn):
|
|
60
|
+
"""
|
|
61
|
+
Adds a yarn to the graph. Assumes that loops do not need to be added
|
|
62
|
+
:param yarn: the yarn to be added to the graph structure
|
|
63
|
+
"""
|
|
64
|
+
self.yarns[yarn] = yarn
|
|
65
|
+
|
|
66
|
+
def connect_loops(self, parent_loop: Loop, child_loop: Loop,
|
|
67
|
+
pull_direction: Pull_Direction = Pull_Direction.BtF,
|
|
68
|
+
stack_position: int | None = None):
|
|
69
|
+
"""
|
|
70
|
+
Creates a stitch-edge by connecting a parent and child loop
|
|
71
|
+
:param parent_loop: the id of the parent loop to connect to this child
|
|
72
|
+
:param child_loop: the id of the child loop to connect to the parent
|
|
73
|
+
:param pull_direction: the direction the child is pulled through the parent
|
|
74
|
+
:param stack_position: The position to insert the parent into, by default add on top of the stack
|
|
75
|
+
"""
|
|
76
|
+
if parent_loop not in self:
|
|
77
|
+
raise KeyError(f"parent loop {parent_loop} not in Knit Graph")
|
|
78
|
+
if child_loop not in self:
|
|
79
|
+
raise KeyError(f"child loop {parent_loop} not in Knit Graph")
|
|
80
|
+
self.stitch_graph.add_edge(parent_loop, child_loop, pull_direction=pull_direction)
|
|
81
|
+
child_loop.add_parent_loop(parent_loop, stack_position)
|
|
82
|
+
|
|
83
|
+
def get_wale_starting_with_loop(self, first_loop: Loop) -> Wale:
|
|
84
|
+
"""
|
|
85
|
+
:param first_loop:
|
|
86
|
+
:return: A wale starting from given loop in knit graph.
|
|
87
|
+
"""
|
|
88
|
+
wale = Wale(first_loop)
|
|
89
|
+
cur_loop = first_loop
|
|
90
|
+
while len(self.stitch_graph.successors(cur_loop)) == 1:
|
|
91
|
+
cur_loop = [*self.stitch_graph.successors(cur_loop)][0]
|
|
92
|
+
wale.add_loop_to_end(cur_loop, self.stitch_graph.edges[wale.last_loop, cur_loop]['pull_direction'])
|
|
93
|
+
return wale
|
|
94
|
+
|
|
95
|
+
def get_wales_ending_with_loop(self, last_loop: Loop) -> list[Wale]:
|
|
96
|
+
"""
|
|
97
|
+
:param last_loop: last loop of joined set of wales
|
|
98
|
+
:return: the set of wales that end at this loop, only multiple wales if this is a child of a decrease.
|
|
99
|
+
"""
|
|
100
|
+
wales = []
|
|
101
|
+
for top_stitch_parent in self.stitch_graph.predecessors(last_loop):
|
|
102
|
+
wale = Wale(last_loop)
|
|
103
|
+
wale.add_loop_to_beginning(top_stitch_parent, self.stitch_graph.edges[top_stitch_parent, last_loop]['pull_direction'])
|
|
104
|
+
cur_loop = top_stitch_parent
|
|
105
|
+
while len(cur_loop.parent_loops) == 1: # stop at split for decrease or start of wale
|
|
106
|
+
cur_loop = [*self.stitch_graph.predecessors(cur_loop)][0]
|
|
107
|
+
wale.add_loop_to_beginning(cur_loop, self.stitch_graph.edges[cur_loop, wale.first_loop]['pull_direction'])
|
|
108
|
+
wales.append(wale)
|
|
109
|
+
return wales
|
|
110
|
+
|
|
111
|
+
def get_courses(self) -> list[Course]:
|
|
112
|
+
"""
|
|
113
|
+
:return: A dictionary of loop_ids to the course they are on,
|
|
114
|
+
a dictionary or course ids to the loops on that course in the order of creation.
|
|
115
|
+
The first set of loops in the graph is on course 0.
|
|
116
|
+
A course change occurs when a loop has a parent loop in the last course.
|
|
117
|
+
"""
|
|
118
|
+
courses = []
|
|
119
|
+
course = Course()
|
|
120
|
+
for loop in sorted([*self.stitch_graph.nodes]):
|
|
121
|
+
for parent in self.stitch_graph.predecessors(loop):
|
|
122
|
+
if parent in course: # start a new course
|
|
123
|
+
courses.append(course)
|
|
124
|
+
course = Course()
|
|
125
|
+
break
|
|
126
|
+
course.add_loop(loop)
|
|
127
|
+
courses.append(course)
|
|
128
|
+
return courses
|
|
129
|
+
|
|
130
|
+
def get_wale_groups(self) -> dict[Loop, Wale_Group]:
|
|
131
|
+
"""
|
|
132
|
+
:return: Dictionary of terminal loops to the wale group they terminate
|
|
133
|
+
"""
|
|
134
|
+
wale_groups = {}
|
|
135
|
+
for loop in self.stitch_graph.nodes:
|
|
136
|
+
if self.is_terminal_loop(loop):
|
|
137
|
+
wale_groups.update({loop: Wale_Group(wale, self) for wale in self.get_wales_ending_with_loop(loop)})
|
|
138
|
+
return wale_groups
|
|
139
|
+
|
|
140
|
+
def __contains__(self, item: Loop):
|
|
141
|
+
"""
|
|
142
|
+
Returns true if the item is in the graph
|
|
143
|
+
:param item: the loop being checked for in the graph
|
|
144
|
+
:return: true if the loop_id of item or the loop is in the graph
|
|
145
|
+
"""
|
|
146
|
+
return self.stitch_graph.has_node(item)
|
|
147
|
+
|
|
148
|
+
def get_stitch_edge(self, parent: Loop, child: Loop, stitch_property: str | None = None):
|
|
149
|
+
"""
|
|
150
|
+
Shortcut to get stitch-edge data from loops or ids
|
|
151
|
+
:param stitch_property: property of edge to return
|
|
152
|
+
:param parent: parent loop or id of parent loop
|
|
153
|
+
:param child: child loop or id of child loop
|
|
154
|
+
:return: the edge data for this stitch edge
|
|
155
|
+
"""
|
|
156
|
+
if self.stitch_graph.has_edge(parent, child):
|
|
157
|
+
edge = self.stitch_graph.get_edge_data(parent, child)
|
|
158
|
+
if stitch_property is not None:
|
|
159
|
+
return edge[stitch_property]
|
|
160
|
+
else:
|
|
161
|
+
return edge
|
|
162
|
+
else:
|
|
163
|
+
return None
|
|
164
|
+
|
|
165
|
+
def get_child_loop(self, loop: Loop) -> Loop | None:
|
|
166
|
+
"""
|
|
167
|
+
:param loop: loop_id to look for child from.
|
|
168
|
+
:return: child loop_id or None if no child loop
|
|
169
|
+
"""
|
|
170
|
+
successors = [*self.stitch_graph.successors(loop)]
|
|
171
|
+
if len(successors) == 0:
|
|
172
|
+
return None
|
|
173
|
+
return successors[0]
|
|
174
|
+
|
|
175
|
+
def has_child_loop(self, loop: Loop) -> bool:
|
|
176
|
+
"""
|
|
177
|
+
:param loop:
|
|
178
|
+
:return: True if loop has a child loop
|
|
179
|
+
"""
|
|
180
|
+
return self.get_child_loop(loop) is not None
|
|
181
|
+
|
|
182
|
+
def is_terminal_loop(self, loop: Loop) -> bool:
|
|
183
|
+
"""
|
|
184
|
+
:param loop:
|
|
185
|
+
:return: True if loop has no child
|
|
186
|
+
"""
|
|
187
|
+
return not self.has_child_loop(loop)
|
knit_graphs/Loop.py
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"""Module containing the Loop Class"""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Loop:
|
|
5
|
+
"""
|
|
6
|
+
A class to represent a single loop structure for modeling a single loop in a knitting pattern.
|
|
7
|
+
|
|
8
|
+
Attributes:
|
|
9
|
+
-----------
|
|
10
|
+
_loop_id : int
|
|
11
|
+
a unique identifier for the loop
|
|
12
|
+
yarn : Yarn
|
|
13
|
+
the Yarn variable that creates and holds this loop
|
|
14
|
+
parent_loops : list
|
|
15
|
+
the list of parent loops
|
|
16
|
+
front_floats : dict
|
|
17
|
+
a dictionary of loops in front of the float
|
|
18
|
+
back_floats : dict
|
|
19
|
+
a dictionary of loops behind the float
|
|
20
|
+
|
|
21
|
+
Methods:
|
|
22
|
+
-----------
|
|
23
|
+
add_loop_in_front_of_float(u, v)
|
|
24
|
+
Set this loop to be in front of the float between u and v
|
|
25
|
+
add_loop_behind_float(u, v)
|
|
26
|
+
Set this loop to be behind the float between u and v
|
|
27
|
+
is_in_front_of_float(u, v)
|
|
28
|
+
Check if the float between u and v is in front of this loop
|
|
29
|
+
is_behind_float(u, v)
|
|
30
|
+
Check if the float between u and v is behind this loop
|
|
31
|
+
prior_loop_on_yarn()
|
|
32
|
+
Return the prior loop on yarn or None if first loop on yarn
|
|
33
|
+
next_loop_on_yarn()
|
|
34
|
+
Return the next loop on yarn or None if last loop on yarn
|
|
35
|
+
has_parent_loops()
|
|
36
|
+
Check if loop has stitch-edge parents
|
|
37
|
+
add_parent_loop(parent, stack_position)
|
|
38
|
+
Add the parent Loop onto the stack of parent_loops
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
def __init__(self, loop_id: int, yarn):
|
|
42
|
+
"""
|
|
43
|
+
Constructs the Loop object.
|
|
44
|
+
|
|
45
|
+
Parameters:
|
|
46
|
+
-----------
|
|
47
|
+
loop_id : int
|
|
48
|
+
a unique identifier for the loop, must be non-negative
|
|
49
|
+
yarn : Yarn
|
|
50
|
+
the Yarn variable that creates and holds this loop
|
|
51
|
+
"""
|
|
52
|
+
assert loop_id >= 0, f"{loop_id}: Loop_id must be non-negative"
|
|
53
|
+
self._loop_id: int = loop_id
|
|
54
|
+
self.yarn = yarn
|
|
55
|
+
self.parent_loops: list[Loop] = []
|
|
56
|
+
self.front_floats: dict[Loop, set[Loop]] = {}
|
|
57
|
+
self.back_floats: dict[Loop, set[Loop]] = {}
|
|
58
|
+
|
|
59
|
+
def add_loop_in_front_of_float(self, u, v):
|
|
60
|
+
"""
|
|
61
|
+
Set this loop to be in front of the float between u and v
|
|
62
|
+
:param u: First loop in float
|
|
63
|
+
:param v: Second loop in float
|
|
64
|
+
"""
|
|
65
|
+
if u not in self.back_floats:
|
|
66
|
+
self.back_floats[u] = set()
|
|
67
|
+
if v not in self.back_floats:
|
|
68
|
+
self.back_floats[v] = set()
|
|
69
|
+
self.back_floats[u].add(v)
|
|
70
|
+
self.back_floats[v].add(u)
|
|
71
|
+
|
|
72
|
+
def add_loop_behind_float(self, u, v):
|
|
73
|
+
"""
|
|
74
|
+
Set this loop to be behind the float between u and v
|
|
75
|
+
:param u: First loop in float
|
|
76
|
+
:param v: Second loop in float
|
|
77
|
+
"""
|
|
78
|
+
if u not in self.front_floats:
|
|
79
|
+
self.front_floats[u] = set()
|
|
80
|
+
if v not in self.front_floats:
|
|
81
|
+
self.front_floats[v] = set()
|
|
82
|
+
self.front_floats[u].add(v)
|
|
83
|
+
self.front_floats[v].add(u)
|
|
84
|
+
|
|
85
|
+
def is_in_front_of_float(self, u, v) -> bool:
|
|
86
|
+
"""
|
|
87
|
+
:param u: First loop in float.
|
|
88
|
+
:param v: Second loop in float.
|
|
89
|
+
:return: True if the float between u and v is in front of this loop.
|
|
90
|
+
"""
|
|
91
|
+
return u in self.back_floats and v in self.back_floats and v in self.back_floats[u]
|
|
92
|
+
|
|
93
|
+
def is_behind_float(self, u, v) -> bool:
|
|
94
|
+
"""
|
|
95
|
+
:param u: First loop in float.
|
|
96
|
+
:param v: Second loop in float.
|
|
97
|
+
:return: True if the float between u and v is behind this loop.
|
|
98
|
+
"""
|
|
99
|
+
return u in self.front_floats and v in self.front_floats and v in self.front_floats[u]
|
|
100
|
+
|
|
101
|
+
def prior_loop_on_yarn(self):
|
|
102
|
+
"""
|
|
103
|
+
:return: Prior loop on yarn or None if first loop on yarn
|
|
104
|
+
"""
|
|
105
|
+
return self.yarn.prior_loop(self)
|
|
106
|
+
|
|
107
|
+
def next_loop_on_yarn(self):
|
|
108
|
+
"""
|
|
109
|
+
:return: Next loop on yarn or Non if last loop on yarn
|
|
110
|
+
"""
|
|
111
|
+
return self.yarn.next_loop(self)
|
|
112
|
+
|
|
113
|
+
def has_parent_loops(self) -> bool:
|
|
114
|
+
"""
|
|
115
|
+
:return: True if loop has stitch-edge parents
|
|
116
|
+
"""
|
|
117
|
+
return len(self.parent_loops) > 0
|
|
118
|
+
|
|
119
|
+
def add_parent_loop(self, parent, stack_position: int | None = None):
|
|
120
|
+
"""
|
|
121
|
+
Adds the parent Loop onto the stack of parent_loops
|
|
122
|
+
:param parent: the Loop to be added onto the stack
|
|
123
|
+
:param stack_position: The position to insert the parent into, by default add on top of the stack
|
|
124
|
+
"""
|
|
125
|
+
if stack_position is not None:
|
|
126
|
+
self.parent_loops.insert(stack_position, parent)
|
|
127
|
+
else:
|
|
128
|
+
self.parent_loops.append(parent)
|
|
129
|
+
|
|
130
|
+
@property
|
|
131
|
+
def loop_id(self) -> int:
|
|
132
|
+
"""
|
|
133
|
+
:return: the id of the loop
|
|
134
|
+
"""
|
|
135
|
+
return self._loop_id
|
|
136
|
+
|
|
137
|
+
def __hash__(self):
|
|
138
|
+
return self.loop_id
|
|
139
|
+
|
|
140
|
+
def __eq__(self, other):
|
|
141
|
+
return isinstance(other, Loop) and self.loop_id == other.loop_id and self.yarn == other.yarn
|
|
142
|
+
|
|
143
|
+
def __lt__(self, other):
|
|
144
|
+
assert isinstance(other, Loop)
|
|
145
|
+
return self.loop_id < other.loop_id
|
|
146
|
+
|
|
147
|
+
def __gt__(self, other):
|
|
148
|
+
assert isinstance(other, Loop)
|
|
149
|
+
return self.loop_id > other.loop_id
|
|
150
|
+
|
|
151
|
+
def __str__(self):
|
|
152
|
+
return f"{self.loop_id} on yarn {self.yarn}"
|
|
153
|
+
|
|
154
|
+
def __repr__(self):
|
|
155
|
+
return str(self.loop_id)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Enumerator used to define the two pull-direction of a loop through other loops"""
|
|
2
|
+
from enum import Enum
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Pull_Direction(Enum):
|
|
6
|
+
"""An enumerator of the two pull-directions of a loop."""
|
|
7
|
+
BtF = "Knit"
|
|
8
|
+
FtB = "Purl"
|
|
9
|
+
|
|
10
|
+
def opposite(self):
|
|
11
|
+
"""
|
|
12
|
+
:return: returns the opposite pull direction of self
|
|
13
|
+
"""
|
|
14
|
+
if self is Pull_Direction.BtF:
|
|
15
|
+
return Pull_Direction.FtB
|
|
16
|
+
else:
|
|
17
|
+
return Pull_Direction.BtF
|
|
18
|
+
|
|
19
|
+
def __str__(self):
|
|
20
|
+
return self.value
|
|
21
|
+
|
|
22
|
+
def __repr__(self):
|
|
23
|
+
return self.value
|