knit-graphs 0.0.6__py3-none-any.whl → 0.0.7__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-0.0.6.dist-info/licenses/LICENSE → LICENSE +21 -21
- README.md +75 -0
- docs/Makefile +20 -0
- docs/make.bat +35 -0
- docs/source/api/knit_graphs.artin_wale_braids.rst +58 -0
- docs/source/api/knit_graphs.rst +74 -0
- docs/source/conf.py +335 -0
- docs/source/index.rst +71 -0
- docs/source/installation.rst +67 -0
- knit_graphs/Course.py +156 -104
- knit_graphs/Knit_Graph.py +249 -186
- knit_graphs/Knit_Graph_Visualizer.py +680 -0
- knit_graphs/Loop.py +141 -155
- knit_graphs/Pull_Direction.py +68 -23
- knit_graphs/Yarn.py +424 -267
- knit_graphs/__init__.py +3 -3
- knit_graphs/_base_classes.py +173 -0
- knit_graphs/artin_wale_braids/Crossing_Direction.py +74 -15
- knit_graphs/artin_wale_braids/Loop_Braid_Graph.py +95 -62
- knit_graphs/artin_wale_braids/Wale.py +169 -93
- knit_graphs/artin_wale_braids/Wale_Braid.py +50 -30
- knit_graphs/artin_wale_braids/Wale_Braid_Word.py +99 -54
- knit_graphs/artin_wale_braids/Wale_Group.py +136 -88
- knit_graphs/{knit_graph_generators/basic_knit_graph_generators.py → basic_knit_graph_generators.py} +302 -248
- knit_graphs-0.0.7.dist-info/LICENSE +21 -0
- {knit_graphs-0.0.6.dist-info → knit_graphs-0.0.7.dist-info}/METADATA +33 -24
- knit_graphs-0.0.7.dist-info/RECORD +29 -0
- {knit_graphs-0.0.6.dist-info → knit_graphs-0.0.7.dist-info}/WHEEL +1 -1
- knit_graphs/__about__.py +0 -4
- knit_graphs/knit_graph_generators/__init__.py +0 -0
- knit_graphs/knit_graph_visualizer/Stitch_Visualizer.py +0 -427
- knit_graphs/knit_graph_visualizer/__init__.py +0 -0
- knit_graphs-0.0.6.dist-info/RECORD +0 -22
|
@@ -1,23 +1,29 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
2
|
Name: knit-graphs
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.7
|
|
4
4
|
Summary: A graph representation of knitted structures where each loop is a node and edges represent yarn and stitch relationships.
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
Author
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
5
|
+
Home-page: https://mhofmann-Khoury.github.io/knit-graphs/
|
|
6
|
+
License: MIT
|
|
7
|
+
Keywords: ACT Lab,Northeastern University,knit,machine knit,fabrication,textile
|
|
8
|
+
Author: Megan Hofmann
|
|
9
|
+
Author-email: m.hofmann@northeastern.edu
|
|
10
|
+
Maintainer: Megan Hofmann
|
|
11
|
+
Maintainer-email: m.hofmann@northeastern.edu
|
|
12
|
+
Requires-Python: >=3.11,<3.14
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
16
|
Classifier: Natural Language :: English
|
|
13
|
-
Classifier:
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
19
|
Classifier: Programming Language :: Python :: 3.11
|
|
15
20
|
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
-
Classifier: Programming Language :: Python ::
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
22
|
Classifier: Topic :: Scientific/Engineering
|
|
18
|
-
Requires-
|
|
19
|
-
Requires-Dist:
|
|
20
|
-
|
|
23
|
+
Requires-Dist: networkx (>=3.5)
|
|
24
|
+
Requires-Dist: plotly (>=6.3.0)
|
|
25
|
+
Project-URL: Documentation, https://mhofmann-Khoury.github.io/knit-graphs/
|
|
26
|
+
Project-URL: Repository, https://github.com/mhofmann-Khoury/knit-graphs
|
|
21
27
|
Description-Content-Type: text/markdown
|
|
22
28
|
|
|
23
29
|
# knit_graphs
|
|
@@ -27,9 +33,9 @@ Description-Content-Type: text/markdown
|
|
|
27
33
|
|
|
28
34
|
-----
|
|
29
35
|
## Description
|
|
30
|
-
The knit-graphs packaged provides a data structure for representing knitted structures formed of loops of yarn (nodes) connected by various edge structures. Loops are connected by: floats (yarn-edges) in a yarn graph structure, stitch edges (loops pulled through loops), and crossed over each other in a wale-braid structure.
|
|
36
|
+
The knit-graphs packaged provides a data structure for representing knitted structures formed of loops of yarn (nodes) connected by various edge structures. Loops are connected by: floats (yarn-edges) in a yarn graph structure, stitch edges (loops pulled through loops), and crossed over each other in a wale-braid structure.
|
|
31
37
|
|
|
32
|
-
Knit graphs provide a powerful tool for representing knitted structures for digital fabrication systems such as knitting machine programming languages and design tools.
|
|
38
|
+
Knit graphs provide a powerful tool for representing knitted structures for digital fabrication systems such as knitting machine programming languages and design tools.
|
|
33
39
|
|
|
34
40
|
Additional details about this knit-graph construction are available in the ACM publication:
|
|
35
41
|
["KnitPicking Texture: Programming and Modifying Complex Knitted Textures for Machine and Hand Knitting"](https://doi.org/10.1145/3332165.3347886)
|
|
@@ -54,25 +60,27 @@ pip install knit-graphs
|
|
|
54
60
|
## Usage
|
|
55
61
|
|
|
56
62
|
### Knit Graph Generators
|
|
57
|
-
The [knit-graph-generators subpackage](https://github.com/mhofmann-Khoury/knit_graph/tree/main/src/knit_graphs/knit_graph_generators) provides a library of basic knit graphs to generate such as casting on loops of a knitted structure, creating Jersey (aka Stockinette) tubes and swatches, and other basic textures.
|
|
63
|
+
The [knit-graph-generators subpackage](https://github.com/mhofmann-Khoury/knit_graph/tree/main/src/knit_graphs/knit_graph_generators) provides a library of basic knit graphs to generate such as casting on loops of a knitted structure, creating Jersey (aka Stockinette) tubes and swatches, and other basic textures.
|
|
58
64
|
For example, to generate a swatch of knit-purl ribbing use the following:
|
|
65
|
+
|
|
59
66
|
```python
|
|
60
|
-
from knit_graphs.
|
|
67
|
+
from knit_graphs.basic_knit_graph_generators import kp_rib_swatch
|
|
68
|
+
|
|
61
69
|
width = 10
|
|
62
70
|
height = 10
|
|
63
71
|
kp_rib_swatch = kp_rib_swatch(width, height)
|
|
64
72
|
```
|
|
65
73
|
Additional examples of knitgraph generator usage can be found in the [Knit_Graph test module](https://github.com/mhofmann-Khoury/knit_graph/blob/main/tests/test_Knit_Graph.py).
|
|
66
74
|
|
|
67
|
-
Knitgraphs can be created without generators. We encourage users to review the generators as simple examples on creating a knit graph programmatically.
|
|
75
|
+
Knitgraphs can be created without generators. We encourage users to review the generators as simple examples on creating a knit graph programmatically.
|
|
68
76
|
|
|
69
77
|
### Visualizing Knit Graphs
|
|
70
|
-
We provide simple support for visualizing knit graphs. This is primarily used to debugging simple knit graph programs.
|
|
78
|
+
We provide simple support for visualizing knit graphs. This is primarily used to debugging simple knit graph programs.
|
|
71
79
|
|
|
72
80
|
For example, we can visualize a swatch of seed stitch (checkered knit and purl stitches) with the following code.
|
|
73
81
|
|
|
74
82
|
```python
|
|
75
|
-
from knit_graphs.
|
|
83
|
+
from knit_graphs.basic_knit_graph_generators import seed_swatch
|
|
76
84
|
from knit_graphs.knit_graph_visualizer.Stitch_Visualizer import visualize_stitches
|
|
77
85
|
|
|
78
86
|
width = 4
|
|
@@ -80,16 +88,17 @@ height = 4
|
|
|
80
88
|
swatch = seed_swatch(width, height)
|
|
81
89
|
visualize_stitches(swatch)
|
|
82
90
|
```
|
|
83
|
-
The visualizer shows knit stitches (loops pulled from the back of the fabric to the front) as blue edges and purl stitches (loops pulled from the front to back) (aka back-knits) as red edges. Loop nodes are circles labeled with their time-ordered index and colored to match their yarn (defaults to dark green). The yarn edges (aka floats) connecting them are made of thin edges the same color as the loop nodes.
|
|
91
|
+
The visualizer shows knit stitches (loops pulled from the back of the fabric to the front) as blue edges and purl stitches (loops pulled from the front to back) (aka back-knits) as red edges. Loop nodes are circles labeled with their time-ordered index and colored to match their yarn (defaults to dark green). The yarn edges (aka floats) connecting them are made of thin edges the same color as the loop nodes.
|
|
84
92
|
|
|
85
93
|
Additional examples of using the visualizer are available in the [Stitch Visualizer Tests Module](https://github.com/mhofmann-Khoury/knit_graph/blob/main/tests/test_Stitch_Visualizer.py)
|
|
86
94
|
|
|
87
95
|
## Credits
|
|
88
|
-
The design of this data scructure was completed by the authors of
|
|
96
|
+
The design of this data scructure was completed by the authors of
|
|
89
97
|
["KnitPicking Texture: Programming and Modifying Complex Knitted Textures for Machine and Hand Knitting"](https://doi.org/10.1145/3332165.3347886).
|
|
90
98
|
|
|
91
99
|
The inclusion of the Artin-Braide wale crossing construction was inspired by ["An Artin Braid Group Representation of Knitting Machine State with Applications to Validation and Optimization of Fabrication Plans"](https://doi.org/10.1109/ICRA48506.2021.9562113) by Jenny Lin and James McCann.
|
|
92
100
|
|
|
93
101
|
## License
|
|
94
102
|
|
|
95
|
-
`knit-graphs` is distributed under the terms of the [MIT](https://spdx.org/licenses/MIT.html) license.
|
|
103
|
+
`knit-graphs` is distributed under the terms of the [MIT](https://spdx.org/licenses/MIT.html) license.
|
|
104
|
+
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
LICENSE,sha256=Oazk3oiRu5ZN7b-EdYNYh0vu-I3Av2uIPQ-9L_cZ6Oo,1070
|
|
2
|
+
README.md,sha256=Hrs3kN8A7hxyel-WhEkzZYY89456vAh3KWbupcOAHsI,3963
|
|
3
|
+
docs/Makefile,sha256=4zv3TVkTACm6JBaKgTES3ZI9cETXgM6ULbZkXZP1as8,638
|
|
4
|
+
docs/make.bat,sha256=0qjrzODegavKd7LLwmr9ADhaYftiTnBgqOVAL9kApyo,769
|
|
5
|
+
docs/source/api/knit_graphs.artin_wale_braids.rst,sha256=_KUBZld6fAS5OP0k4gd5yKamNGXEqH12XjakmWeJIII,1549
|
|
6
|
+
docs/source/api/knit_graphs.rst,sha256=zdmnXipviweW0ZGQsQCZtfOOc_6Fj0yWdg_TwOMafLI,1398
|
|
7
|
+
docs/source/conf.py,sha256=TZK8Rz0JNgQs2J_cUhVX5_4tmMBvRdGtILJsnAnAFWo,13350
|
|
8
|
+
docs/source/index.rst,sha256=D4KmCX1_d2-WrPgxSeggHHsc9-TeQwSUGYOkehRQWrw,1462
|
|
9
|
+
docs/source/installation.rst,sha256=GyNRk_oXKVgOZ4KFLAgkXLwjHYzDYsx8gcokLRrS0ZI,1247
|
|
10
|
+
knit_graphs/Course.py,sha256=oT-YghPdAg7A51GI_StdfF8oxYGWGkoad72woEkRKeY,5818
|
|
11
|
+
knit_graphs/Knit_Graph.py,sha256=KgcWQPzZJ-Iif7g3zWq6hBy4fdJXkJXnFxGOSMYOn-g,10795
|
|
12
|
+
knit_graphs/Knit_Graph_Visualizer.py,sha256=bbWl9iPQR93MtpWMPji4RTFR3Rgon0vzBlS11e2R8Zg,37925
|
|
13
|
+
knit_graphs/Loop.py,sha256=zp1ZiVRFSCPL2CnXNxgwNPv7WrcuqFRe3S_ZATxEBAo,5781
|
|
14
|
+
knit_graphs/Pull_Direction.py,sha256=8xRLN-j7V1mExgmt3YjcJcTDa5rLedA2bF4wI8gd-DE,2334
|
|
15
|
+
knit_graphs/Yarn.py,sha256=wNOmj15dnSA56Qw2D5ksgbmQqug-u5kPPxKGuitQ_qI,15901
|
|
16
|
+
knit_graphs/__init__.py,sha256=qzZAOxTqjgLkhoGnKNZwOkuYbKEyzfWKkKpKkV6lVfk,111
|
|
17
|
+
knit_graphs/_base_classes.py,sha256=ZEv_jkUglHzkfg-0TD6oonBq7QQmA4G7jrC_A6OubpY,6401
|
|
18
|
+
knit_graphs/artin_wale_braids/Crossing_Direction.py,sha256=71ckmEFfL0s25NJb8lfYwH2zku0uM1C5X9gGM7PYC5A,2820
|
|
19
|
+
knit_graphs/artin_wale_braids/Loop_Braid_Graph.py,sha256=2tsE16IzcvgsIKij1JNHWah6hLOgrpXCcjb6eocbfFs,4575
|
|
20
|
+
knit_graphs/artin_wale_braids/Wale.py,sha256=PK8IQDnTFXk5924QZYiGCqfckS62laG9_XhK7xH2zAo,7171
|
|
21
|
+
knit_graphs/artin_wale_braids/Wale_Braid.py,sha256=Ws0QmU7s63nrBKe69acDza-r-LozDyyaKVDNxQMy10Y,2662
|
|
22
|
+
knit_graphs/artin_wale_braids/Wale_Braid_Word.py,sha256=4YBlVMUZkqp85r46ETQSbFVS_WrT4PsWthHmFv5Ny9M,4587
|
|
23
|
+
knit_graphs/artin_wale_braids/Wale_Group.py,sha256=HTl01PHzFhInhFJuB30OScWx7pIejmo3-HwHN4RB4V4,6868
|
|
24
|
+
knit_graphs/artin_wale_braids/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
25
|
+
knit_graphs/basic_knit_graph_generators.py,sha256=_8CbtZ4M5NRp0mXXNdCNDPtIaCKEzmpAJQVNlmV5l8c,13893
|
|
26
|
+
knit_graphs-0.0.7.dist-info/LICENSE,sha256=Oazk3oiRu5ZN7b-EdYNYh0vu-I3Av2uIPQ-9L_cZ6Oo,1070
|
|
27
|
+
knit_graphs-0.0.7.dist-info/METADATA,sha256=YuT2TGLdupJYXAKbbC-pXi-z0fKbOelNz31STuy7tks,5188
|
|
28
|
+
knit_graphs-0.0.7.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
|
29
|
+
knit_graphs-0.0.7.dist-info/RECORD,,
|
knit_graphs/__about__.py
DELETED
|
File without changes
|
|
@@ -1,427 +0,0 @@
|
|
|
1
|
-
import networkx
|
|
2
|
-
import plotly.graph_objects as go
|
|
3
|
-
|
|
4
|
-
from knit_graphs.Course import Course
|
|
5
|
-
from knit_graphs.Knit_Graph import Knit_Graph
|
|
6
|
-
from knit_graphs.Loop import Loop
|
|
7
|
-
from knit_graphs.Pull_Direction import Pull_Direction
|
|
8
|
-
from knit_graphs.artin_wale_braids.Crossing_Direction import Crossing_Direction
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
def get_base_row_course_positions(course: Course, start_on_left: bool, loop_space: float = 1.0) -> tuple[dict[Loop, float], float, float]:
|
|
12
|
-
"""
|
|
13
|
-
:param course: course assumed to be base of knit graph for visualization
|
|
14
|
-
:param start_on_left: If True, loops will start on left side of plot
|
|
15
|
-
:param loop_space: spacing between loops
|
|
16
|
-
:return: dictionary of loops in course keyed to x position. The minimum loop position. The maximum loop position.
|
|
17
|
-
"""
|
|
18
|
-
loops = course
|
|
19
|
-
if not start_on_left:
|
|
20
|
-
loops = reversed(course)
|
|
21
|
-
positions = {l: x * loop_space for x, l in enumerate(loops)}
|
|
22
|
-
return positions, min(positions.values()), max(positions.values())
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
def get_base_round_course_positions(course: Course, start_on_left: bool,
|
|
26
|
-
loop_space: float = 1.0, back_shift: float = 0.5) -> tuple[dict[Loop, float], dict[Loop, float], float, float]:
|
|
27
|
-
"""
|
|
28
|
-
:param back_shift: Shift in x position for back bed loop s that can't be placed by float inference.
|
|
29
|
-
:param course: Course assumed to be base of knit graph for visualization.
|
|
30
|
-
:param start_on_left: If True, loops will start on the left side of plot.
|
|
31
|
-
:param loop_space: Spacing between loops.
|
|
32
|
-
:return: Dictionary of loops in front of the course keyed to x position.
|
|
33
|
-
Dictionary of loops in the back of the course keyed to x position.
|
|
34
|
-
Min loop position. Max loop position
|
|
35
|
-
"""
|
|
36
|
-
split_index = int(len(course) / 2)
|
|
37
|
-
front_loops = course[:split_index]
|
|
38
|
-
back_loops = course[split_index:]
|
|
39
|
-
if start_on_left:
|
|
40
|
-
back_loops = reversed(back_loops)
|
|
41
|
-
else:
|
|
42
|
-
front_loops = reversed(back_loops)
|
|
43
|
-
front_positions = {l: x * loop_space for x, l in enumerate(front_loops)}
|
|
44
|
-
back_positions = {l: x * loop_space + back_shift for x, l in enumerate(back_loops)}
|
|
45
|
-
for back_loop in back_loops:
|
|
46
|
-
float_positions = [front_positions[fl] for fl in back_loop.front_floats if fl in front_positions]
|
|
47
|
-
if len(float_positions) > 0:
|
|
48
|
-
back_positions[back_loop] = sum(float_positions) / len(float_positions)
|
|
49
|
-
min_front = min(front_positions.values())
|
|
50
|
-
max_front = max(front_positions.values())
|
|
51
|
-
min_back = min(back_positions.values())
|
|
52
|
-
max_back = max(back_positions.values())
|
|
53
|
-
return front_positions, back_positions, min(min_front, min_back), max(max_front, max_back)
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
def get_loop_x_by_parent_average(data_graph: networkx.DiGraph, loop: Loop) -> float | None:
|
|
57
|
-
"""
|
|
58
|
-
:param data_graph: Collection of loop nodes to assigned locations.
|
|
59
|
-
:param loop: Loop to derive location for.
|
|
60
|
-
:return: X position derived from parent_loop locations for loop.
|
|
61
|
-
"""
|
|
62
|
-
|
|
63
|
-
def _parent_weight(stack_position):
|
|
64
|
-
return len(loop.parent_loops) - stack_position
|
|
65
|
-
|
|
66
|
-
parent_positions = {data_graph.nodes[p]['x'] * _parent_weight(sp): _parent_weight(sp)
|
|
67
|
-
for sp, p in enumerate(loop.parent_loops)
|
|
68
|
-
if p in data_graph.nodes}
|
|
69
|
-
if len(parent_positions) == 0:
|
|
70
|
-
return None
|
|
71
|
-
return sum(parent_positions.keys()) / sum(parent_positions.values())
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
def get_loop_x_by_yarn_neighbor_average(data_graph: networkx.DiGraph, loop: Loop, prior_space=1, next_space=-1) -> float | None:
|
|
75
|
-
"""
|
|
76
|
-
:param data_graph: Collection of loop nodes to assigned locations.
|
|
77
|
-
:param loop: Loop to place.
|
|
78
|
-
:param prior_space: Spacing from this loop to prior on yarn.
|
|
79
|
-
:param next_space: Spacing from this loop to next on yarn.
|
|
80
|
-
:return: None if no neighbors are placed or assign x position by neighbors on yarn.
|
|
81
|
-
"""
|
|
82
|
-
x_neighbors = []
|
|
83
|
-
prior_loop = loop.prior_loop_on_yarn()
|
|
84
|
-
next_loop = loop.next_loop_on_yarn()
|
|
85
|
-
if prior_loop is not None and prior_loop in data_graph.nodes:
|
|
86
|
-
x_neighbors.append(data_graph.nodes[prior_loop]['x'] + prior_space)
|
|
87
|
-
if next_loop is not None and next_loop in data_graph.nodes:
|
|
88
|
-
x_neighbors.append(data_graph.nodes[next_loop]['x'] + next_space)
|
|
89
|
-
return sum(x_neighbors) / len(x_neighbors)
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
def re_balance_course(data_graph: networkx.DiGraph, course: Course, target_width: float | None,
|
|
93
|
-
left_side: float = 0, right_side: float | None = None) -> dict[Loop, float]:
|
|
94
|
-
"""
|
|
95
|
-
:param target_width: Width to retarget to. Defaults to definition from right side value.
|
|
96
|
-
:param data_graph: Collection of loop nodes to assign locations.
|
|
97
|
-
:param course: The course to re-balance.
|
|
98
|
-
:param left_side: The minimum left position of the course.
|
|
99
|
-
:param right_side: The maximum right position of the course. Defaults to right most loop position.
|
|
100
|
-
:return: Dictionary of loops to rebalanced positions.
|
|
101
|
-
Maintains original float proportions of each loop but assigns positions between left and right side values.
|
|
102
|
-
"""
|
|
103
|
-
min_x, min_loop = min_x_in_course(course, data_graph)
|
|
104
|
-
max_x, max_loop = max_x_in_course(course, data_graph)
|
|
105
|
-
course_width = max_x - min_x
|
|
106
|
-
if target_width is None:
|
|
107
|
-
if right_side is None:
|
|
108
|
-
right_side = max_x
|
|
109
|
-
target_width = right_side - left_side
|
|
110
|
-
|
|
111
|
-
def _target_float_size(u, v) -> float:
|
|
112
|
-
current_size = abs(data_graph.nodes[u]['x'] - data_graph.nodes[v]['x'])
|
|
113
|
-
return (current_size * target_width) / course_width
|
|
114
|
-
|
|
115
|
-
return {l: _target_float_size(min_loop, l) + left_side for l in course}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
def max_x_in_course(course, data_graph) -> tuple[float, Loop]:
|
|
119
|
-
"""
|
|
120
|
-
:param course:
|
|
121
|
-
:param data_graph:
|
|
122
|
-
:return: right most x position in course, loop with right most x position
|
|
123
|
-
"""
|
|
124
|
-
return max([(data_graph.nodes[l]['x'], l) for l in course], key=lambda tup: tup[0])
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
def min_x_in_course(course, data_graph) -> tuple[float, Loop]:
|
|
128
|
-
"""
|
|
129
|
-
:param course:
|
|
130
|
-
:param data_graph:
|
|
131
|
-
:return: left most x position in course, loop with left most x position
|
|
132
|
-
"""
|
|
133
|
-
return min([(data_graph.nodes[l]['x'], l) for l in course], key=lambda tup: tup[0])
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
def get_loop_y_by_neighbor_floats(data_graph: networkx.DiGraph, loop: Loop, float_buffer: float = 0.25) -> float | None:
|
|
137
|
-
"""
|
|
138
|
-
:param data_graph: Collection of loop nodes to assign locations.
|
|
139
|
-
:param loop: Loop to assign y location by neighboring floats.
|
|
140
|
-
:param float_buffer: Spacing between loop and its neighboring floats.
|
|
141
|
-
:return: Y position of loop or None if loop has no neighboring floats.
|
|
142
|
-
"""
|
|
143
|
-
positions = [data_graph.nodes[fl]['y'] + float_buffer for fl in loop.front_floats if fl in data_graph.nodes]
|
|
144
|
-
positions.extend([data_graph.nodes[bl]['y'] - float_buffer for bl in loop.back_floats if bl in data_graph.nodes])
|
|
145
|
-
if len(positions) == 0:
|
|
146
|
-
return None
|
|
147
|
-
return sum(positions) / len(positions)
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
def shift_purls(knit_graph: Knit_Graph, data_graph: networkx.DiGraph, purl_shift: float = 0.25):
|
|
151
|
-
shifted = set()
|
|
152
|
-
for u, v in knit_graph.stitch_graph.edges:
|
|
153
|
-
if v not in shifted:
|
|
154
|
-
pull_direction = knit_graph.stitch_graph[u][v]['pull_direction']
|
|
155
|
-
if pull_direction is Pull_Direction.FtB:
|
|
156
|
-
data_graph.nodes[v]['x'] += purl_shift
|
|
157
|
-
shifted.add(v)
|
|
158
|
-
if len(u.parent_loops) == 0: # purl coming from yarn over
|
|
159
|
-
data_graph.nodes[u]['x'] += purl_shift
|
|
160
|
-
shifted.add(u)
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
def visualize_stitches(knit_graph: Knit_Graph,
|
|
164
|
-
first_course_index: int = 0, top_course_index: int | None = None,
|
|
165
|
-
start_on_left: bool = True,
|
|
166
|
-
re_balance_to_course_width=False,
|
|
167
|
-
re_balance_to_base_width=False,
|
|
168
|
-
left_zero_align=True,
|
|
169
|
-
graph_title: str = "knit_graph"):
|
|
170
|
-
data_graph = position_loops(first_course_index, knit_graph, left_zero_align, re_balance_to_base_width, re_balance_to_course_width, start_on_left, top_course_index)
|
|
171
|
-
|
|
172
|
-
yarn_loop_traces = collect_yarn_loop_traces(data_graph, knit_graph)
|
|
173
|
-
|
|
174
|
-
yarn_float_traces = collect_yarn_float_traces(data_graph, knit_graph)
|
|
175
|
-
|
|
176
|
-
def _new_edge_data():
|
|
177
|
-
return {'x': [], 'y': [], 'edge': [], 'is_start': []}
|
|
178
|
-
|
|
179
|
-
def _add_edge_data(edge_data: dict[str, list], u_loop: Loop, v_loop: Loop):
|
|
180
|
-
data_graph.add_edge(u_loop, v_loop, pull_direction=pull_direction)
|
|
181
|
-
edge_data['x'].append(data_graph.nodes[u_loop]['x'])
|
|
182
|
-
edge_data['y'].append(data_graph.nodes[u_loop]['y'])
|
|
183
|
-
edge_data['edge'].append((u_loop, v_loop))
|
|
184
|
-
edge_data['is_start'].append(True)
|
|
185
|
-
edge_data['x'].append(data_graph.nodes[v_loop]['x'])
|
|
186
|
-
edge_data['y'].append(data_graph.nodes[v_loop]['y'])
|
|
187
|
-
edge_data['edge'].append((u_loop, v_loop))
|
|
188
|
-
edge_data['is_start'].append(False)
|
|
189
|
-
edge_data['x'].append(None)
|
|
190
|
-
edge_data['y'].append(None)
|
|
191
|
-
|
|
192
|
-
top_knit_data = _new_edge_data()
|
|
193
|
-
bot_knit_data = _new_edge_data()
|
|
194
|
-
top_purl_data = _new_edge_data()
|
|
195
|
-
bot_purl_data = _new_edge_data()
|
|
196
|
-
no_cross_knit_data = _new_edge_data()
|
|
197
|
-
no_cross_purl_data = _new_edge_data()
|
|
198
|
-
|
|
199
|
-
for left_loop, right_loop in knit_graph.braid_graph.loop_crossing_graph.edges:
|
|
200
|
-
crossing_direction = knit_graph.braid_graph.get_crossing(left_loop, right_loop)
|
|
201
|
-
for left_parent in left_loop.parent_loops:
|
|
202
|
-
pull_direction: Pull_Direction = knit_graph.stitch_graph[left_parent][left_loop]['pull_direction']
|
|
203
|
-
data_graph.add_edge(left_parent, left_loop, pull_direction=pull_direction)
|
|
204
|
-
if pull_direction is Pull_Direction.BtF: # knit
|
|
205
|
-
if crossing_direction is Crossing_Direction.Over_Right:
|
|
206
|
-
data = top_knit_data
|
|
207
|
-
elif crossing_direction is Crossing_Direction.Under_Right:
|
|
208
|
-
data = bot_knit_data
|
|
209
|
-
else:
|
|
210
|
-
data = no_cross_knit_data
|
|
211
|
-
else:
|
|
212
|
-
if crossing_direction is Crossing_Direction.Over_Right:
|
|
213
|
-
data = top_purl_data
|
|
214
|
-
elif crossing_direction is Crossing_Direction.Under_Right:
|
|
215
|
-
data = bot_purl_data
|
|
216
|
-
else:
|
|
217
|
-
data = no_cross_knit_data
|
|
218
|
-
_add_edge_data(data, left_parent, left_loop)
|
|
219
|
-
for right_parent in right_loop.parent_loops:
|
|
220
|
-
pull_direction: Pull_Direction = knit_graph.stitch_graph[right_parent][right_loop]['pull_direction']
|
|
221
|
-
data_graph.add_edge(right_parent, right_loop, pull_direction=pull_direction)
|
|
222
|
-
if pull_direction is Pull_Direction.BtF: # knit
|
|
223
|
-
if crossing_direction is Crossing_Direction.Under_Right:
|
|
224
|
-
data = top_knit_data
|
|
225
|
-
elif crossing_direction is Crossing_Direction.Over_Right:
|
|
226
|
-
data = bot_knit_data
|
|
227
|
-
else:
|
|
228
|
-
data = no_cross_knit_data
|
|
229
|
-
else:
|
|
230
|
-
if crossing_direction is Crossing_Direction.Under_Right:
|
|
231
|
-
data = top_purl_data
|
|
232
|
-
elif crossing_direction is Crossing_Direction.Over_Right:
|
|
233
|
-
data = bot_purl_data
|
|
234
|
-
else:
|
|
235
|
-
data = no_cross_purl_data
|
|
236
|
-
_add_edge_data(data, right_parent, right_loop)
|
|
237
|
-
|
|
238
|
-
for u, v in knit_graph.stitch_graph.edges:
|
|
239
|
-
if not data_graph.has_edge(u, v):
|
|
240
|
-
pull_direction: Pull_Direction = knit_graph.stitch_graph[u][v]['pull_direction']
|
|
241
|
-
if pull_direction is Pull_Direction.BtF: # knit
|
|
242
|
-
_add_edge_data(no_cross_knit_data, u, v)
|
|
243
|
-
else:
|
|
244
|
-
_add_edge_data(no_cross_purl_data, u, v)
|
|
245
|
-
|
|
246
|
-
no_cross_knit_trace = go.Scatter(name="Knit Stitches (No Crossing)",
|
|
247
|
-
x=no_cross_knit_data['x'], y=no_cross_knit_data['y'],
|
|
248
|
-
line=dict(width=4, color='blue', dash='solid'),
|
|
249
|
-
opacity=0.8,
|
|
250
|
-
mode='lines')
|
|
251
|
-
top_knit_trace = go.Scatter(name="Knit Stitches (Crossing Over)",
|
|
252
|
-
x=top_knit_data['x'], y=top_knit_data['y'],
|
|
253
|
-
line=dict(width=5, color='blue', dash='solid'),
|
|
254
|
-
opacity=1,
|
|
255
|
-
mode='lines')
|
|
256
|
-
bot_knit_trace = go.Scatter(name="Knit Stitches (Crossing Under)",
|
|
257
|
-
x=bot_knit_data['x'], y=bot_knit_data['y'],
|
|
258
|
-
line=dict(width=3, color='blue', dash='dash'),
|
|
259
|
-
opacity=.5,
|
|
260
|
-
mode='lines')
|
|
261
|
-
no_cross_purl_trace = go.Scatter(name="Purl Stitches",
|
|
262
|
-
x=no_cross_purl_data['x'], y=no_cross_purl_data['y'],
|
|
263
|
-
line=dict(width=4, color='red', dash='solid'),
|
|
264
|
-
opacity=0.8,
|
|
265
|
-
mode='lines')
|
|
266
|
-
top_purl_trace = go.Scatter(name="Purl Stitches (Crossing Over)",
|
|
267
|
-
x=top_purl_data['x'], y=top_knit_data['y'],
|
|
268
|
-
line=dict(width=5, color='red', dash='solid'),
|
|
269
|
-
opacity=1,
|
|
270
|
-
mode='lines')
|
|
271
|
-
bot_purl_trace = go.Scatter(name="Purl Stitches (Crossing Under)",
|
|
272
|
-
x=bot_purl_data['x'], y=bot_purl_data['y'],
|
|
273
|
-
line=dict(width=3, color='red', dash='dash'),
|
|
274
|
-
opacity=.5,
|
|
275
|
-
mode='lines')
|
|
276
|
-
|
|
277
|
-
go_layout = go.Layout(title=graph_title,
|
|
278
|
-
showlegend=True,
|
|
279
|
-
hovermode='closest',
|
|
280
|
-
margin=dict(b=20, l=5, r=5, t=40)
|
|
281
|
-
)
|
|
282
|
-
figure_data = [top_knit_trace, top_purl_trace,
|
|
283
|
-
no_cross_knit_trace, no_cross_purl_trace,
|
|
284
|
-
bot_knit_trace, bot_purl_trace]
|
|
285
|
-
figure_data.extend(yarn_float_traces)
|
|
286
|
-
figure_data.extend(yarn_loop_traces)
|
|
287
|
-
fig = go.Figure(data=figure_data,
|
|
288
|
-
layout=go_layout
|
|
289
|
-
)
|
|
290
|
-
fig.show()
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
def position_loops(first_course_index, knit_graph, left_zero_align, re_balance_to_base_width, re_balance_to_course_width,
|
|
294
|
-
start_on_left, top_course_index):
|
|
295
|
-
data_graph = networkx.DiGraph()
|
|
296
|
-
courses = knit_graph.get_courses()
|
|
297
|
-
loops_to_course = {}
|
|
298
|
-
if top_course_index is not None:
|
|
299
|
-
courses = courses[:top_course_index]
|
|
300
|
-
base_course = courses[first_course_index]
|
|
301
|
-
for loop in base_course:
|
|
302
|
-
loops_to_course[loop] = base_course
|
|
303
|
-
if len(courses) > first_course_index + 1 and base_course.in_round_with(courses[first_course_index + 1]):
|
|
304
|
-
front_positions, back_positions, min_x, max_x = get_base_round_course_positions(base_course, start_on_left)
|
|
305
|
-
for loop, x in front_positions.items():
|
|
306
|
-
data_graph.add_node(loop, x=x, y=0)
|
|
307
|
-
for loop, x in back_positions.items():
|
|
308
|
-
# y = get_loop_y_by_neighbor_floats(data_graph, loop)
|
|
309
|
-
# if y is None:
|
|
310
|
-
# y = .25
|
|
311
|
-
data_graph.add_node(loop, x=x, y=0)
|
|
312
|
-
else:
|
|
313
|
-
positions, min_x, max_x = get_base_row_course_positions(base_course, start_on_left)
|
|
314
|
-
for loop, x in positions.items():
|
|
315
|
-
data_graph.add_node(loop, x=x, y=0)
|
|
316
|
-
base_width = max_x - min_x
|
|
317
|
-
y = 1
|
|
318
|
-
for course in courses[first_course_index + 1:]:
|
|
319
|
-
need_x_placement = {}
|
|
320
|
-
for x, loop in enumerate(course):
|
|
321
|
-
loops_to_course[loop] = course
|
|
322
|
-
parent_average_x = get_loop_x_by_parent_average(data_graph, loop)
|
|
323
|
-
if parent_average_x is None:
|
|
324
|
-
need_x_placement[loop] = x
|
|
325
|
-
else:
|
|
326
|
-
x = parent_average_x
|
|
327
|
-
# float_placed_y = get_loop_y_by_neighbor_floats(data_graph, loop)
|
|
328
|
-
# if float_placed_y is not None:
|
|
329
|
-
# y = float_placed_y
|
|
330
|
-
data_graph.add_node(loop, x=x, y=y)
|
|
331
|
-
for loop in need_x_placement.keys():
|
|
332
|
-
neighbor_based_x = get_loop_x_by_yarn_neighbor_average(data_graph, loop)
|
|
333
|
-
if neighbor_based_x is not None:
|
|
334
|
-
data_graph.nodes[loop]['x'] = neighbor_based_x
|
|
335
|
-
# swap x positions based on cable crossings
|
|
336
|
-
for left_loop in course:
|
|
337
|
-
for right_loop in knit_graph.braid_graph.left_crossing_loops(left_loop):
|
|
338
|
-
crossing_direction = knit_graph.braid_graph.get_crossing(left_loop, right_loop)
|
|
339
|
-
if crossing_direction is not Crossing_Direction.No_Cross:
|
|
340
|
-
left_x = data_graph.nodes[left_loop]['x']
|
|
341
|
-
data_graph.nodes[left_loop]['x'] = data_graph.nodes[right_loop]['x']
|
|
342
|
-
data_graph.nodes[right_loop]['x'] = left_x
|
|
343
|
-
new_positions = {}
|
|
344
|
-
left_side = 0
|
|
345
|
-
if not left_zero_align:
|
|
346
|
-
left_side, left_loop = min_x_in_course(course, data_graph)
|
|
347
|
-
if re_balance_to_course_width:
|
|
348
|
-
new_positions = re_balance_course(data_graph, course, len(course) - 1, left_side)
|
|
349
|
-
elif re_balance_to_base_width:
|
|
350
|
-
new_positions = re_balance_course(data_graph, course, base_width, left_side)
|
|
351
|
-
for l, x in new_positions.items():
|
|
352
|
-
data_graph.nodes[l]['x'] = x
|
|
353
|
-
y += 1
|
|
354
|
-
adjust_y_positions_by_float_alignment(data_graph, knit_graph, loops_to_course)
|
|
355
|
-
shift_purls(knit_graph, data_graph)
|
|
356
|
-
return data_graph
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
def adjust_y_positions_by_float_alignment(data_graph, knit_graph, loops_to_course, float_increment: float = 0.25):
|
|
360
|
-
for yarn in knit_graph.yarns:
|
|
361
|
-
for u, v, front_loops in yarn.loops_in_front_of_floats():
|
|
362
|
-
for fl in front_loops:
|
|
363
|
-
fl_course = loops_to_course[fl]
|
|
364
|
-
if u in fl_course and v in fl_course: # same course, adjust float position
|
|
365
|
-
data_graph.nodes[fl]['y'] -= float_increment
|
|
366
|
-
for u, v, back_loops in yarn.loops_behind_floats():
|
|
367
|
-
for bl in back_loops:
|
|
368
|
-
bl_course = loops_to_course[bl]
|
|
369
|
-
if u in bl_course and v in bl_course: # same course, adjust float position
|
|
370
|
-
data_graph.nodes[bl]['y'] += float_increment
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
def collect_yarn_float_traces(data_graph, knit_graph):
|
|
374
|
-
"""
|
|
375
|
-
:param data_graph: Collection of loop nodes to assign locations.
|
|
376
|
-
:param knit_graph: The knit graph to derive loop data from.
|
|
377
|
-
:return: The traces of the yarns-loop nodes for the graph
|
|
378
|
-
"""
|
|
379
|
-
yarns_to_float_data = {}
|
|
380
|
-
for y in knit_graph.yarns.values():
|
|
381
|
-
float_data = {'x': [], 'y': []}
|
|
382
|
-
for u, v in y.loop_graph.edges:
|
|
383
|
-
float_data['x'].append(data_graph.nodes[u]['x'])
|
|
384
|
-
float_data['y'].append(data_graph.nodes[u]['y'])
|
|
385
|
-
float_data['x'].append(data_graph.nodes[v]['x'])
|
|
386
|
-
float_data['y'].append(data_graph.nodes[v]['y'])
|
|
387
|
-
yarns_to_float_data[y] = float_data
|
|
388
|
-
for y in knit_graph.yarns.values():
|
|
389
|
-
float_data = {'x': [], 'y': []}
|
|
390
|
-
for u in y.loop_graph.nodes:
|
|
391
|
-
float_data['x'].append(data_graph.nodes[u]['x'])
|
|
392
|
-
float_data['y'].append(data_graph.nodes[u]['y'])
|
|
393
|
-
yarns_to_float_data[y] = float_data
|
|
394
|
-
yarn_float_traces = [go.Scatter(name=y.yarn_id,
|
|
395
|
-
x=fd['x'], y=fd['y'],
|
|
396
|
-
line=dict(width=1,
|
|
397
|
-
color=y.properties.color,
|
|
398
|
-
shape='spline',
|
|
399
|
-
smoothing=1.3),
|
|
400
|
-
mode='lines')
|
|
401
|
-
for y, fd in yarns_to_float_data.items()]
|
|
402
|
-
return yarn_float_traces
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
def collect_yarn_loop_traces(data_graph, knit_graph):
|
|
406
|
-
"""
|
|
407
|
-
:param data_graph: Collection of loop nodes to assign locations.
|
|
408
|
-
:param knit_graph: The knit graph to derive loop data from.
|
|
409
|
-
:return: The traces of the yarns-float edges for the graph
|
|
410
|
-
"""
|
|
411
|
-
yarns_to_loop_data = {y: {'x': [data_graph.nodes[l]['x'] for l in y],
|
|
412
|
-
'y': [data_graph.nodes[l]['y'] for l in y],
|
|
413
|
-
'loop_id': [l.loop_id for l in y]
|
|
414
|
-
}
|
|
415
|
-
for y in knit_graph.yarns
|
|
416
|
-
}
|
|
417
|
-
yarn_loop_traces = [go.Scatter(name=f"Loops on {y.yarn_id}", x=yd['x'], y=yd['y'], text=yd['loop_id'],
|
|
418
|
-
textposition='middle center',
|
|
419
|
-
mode='markers+text',
|
|
420
|
-
marker=dict(
|
|
421
|
-
reversescale=True,
|
|
422
|
-
color=y.properties.color,
|
|
423
|
-
size=30,
|
|
424
|
-
line_width=2, ))
|
|
425
|
-
for y, yd in yarns_to_loop_data.items()
|
|
426
|
-
]
|
|
427
|
-
return yarn_loop_traces
|
|
File without changes
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
knit_graphs/Course.py,sha256=gEIl9EXXCx3NfEQclhK_7WGVOK_rxF5hB0jqGeAyH_w,3437
|
|
2
|
-
knit_graphs/Knit_Graph.py,sha256=arRNaxUaV3uwgNJ_UKxS7zViHl46y5QErPM_vTA_q8Y,7753
|
|
3
|
-
knit_graphs/Loop.py,sha256=S2YGS8f_CtbFzy-OJsY6_JzGaHiiVMXrROO6P-wByTo,5236
|
|
4
|
-
knit_graphs/Pull_Direction.py,sha256=G2JLbUT8x-ZfLNX3yjslv61FaoZiODUOPyYeDqj3pqQ,596
|
|
5
|
-
knit_graphs/Yarn.py,sha256=9FOEBnWbtI8VJ-b1-NL0e8bsXuT0Jg0HG90jWEflUxw,9230
|
|
6
|
-
knit_graphs/__about__.py,sha256=f6QbNB-h7iIziTm9pqa987kBoY_CelBN7KwRBZHwZck,137
|
|
7
|
-
knit_graphs/__init__.py,sha256=bPQ_U3Sf5VvF36ywW6v79_J51b7DdZPvXuaHAtlbmg4,114
|
|
8
|
-
knit_graphs/artin_wale_braids/Crossing_Direction.py,sha256=YVYfv11V-mB9WmQzNuOjbEQQI-b07gl9KF31vwujb1g,430
|
|
9
|
-
knit_graphs/artin_wale_braids/Loop_Braid_Graph.py,sha256=z9_VyQA5U9y-XjyaZ67kSmOr0Bg_N1932ghV3YzNrP0,2742
|
|
10
|
-
knit_graphs/artin_wale_braids/Wale.py,sha256=ldXVbb8cAe5QSoZNRxmdyrncnMYp6S0NnRpdJU6QQM4,3597
|
|
11
|
-
knit_graphs/artin_wale_braids/Wale_Braid.py,sha256=9xCE0i0FoHN9J4CA_PZOoVIeLDHhIY3vC7LyK8OVkfk,1348
|
|
12
|
-
knit_graphs/artin_wale_braids/Wale_Braid_Word.py,sha256=K17E-oRRsKYDrSWqwP1WMqR2MnK8nTNoSqaD73gtX6Y,1844
|
|
13
|
-
knit_graphs/artin_wale_braids/Wale_Group.py,sha256=e5YTNiHditg4sSq-1lMAdmeIwIEHX4JKEiEx5X4nwZg,3718
|
|
14
|
-
knit_graphs/artin_wale_braids/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
|
-
knit_graphs/knit_graph_generators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
|
-
knit_graphs/knit_graph_generators/basic_knit_graph_generators.py,sha256=eRmoqIhjymKERJhjnwuQll3psAf9HHwnHWDkTcZX6Uk,11330
|
|
17
|
-
knit_graphs/knit_graph_visualizer/Stitch_Visualizer.py,sha256=l90bdaucCDzSmua7iILoNmpVQuQsuMKHq5r0DkakoL0,21411
|
|
18
|
-
knit_graphs/knit_graph_visualizer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
|
-
knit_graphs-0.0.6.dist-info/METADATA,sha256=Mn0jZgvr2WWltpSizNu3mJS-7SPTehGQ6vlXM3I9UNY,5039
|
|
20
|
-
knit_graphs-0.0.6.dist-info/WHEEL,sha256=zEMcRr9Kr03x1ozGwg5v9NQBKn3kndp6LSoSlVg-jhU,87
|
|
21
|
-
knit_graphs-0.0.6.dist-info/licenses/LICENSE,sha256=M4U6L5axKj_93OoQXCm4RUIsUwHqEVzf7hsOVmyFPp0,1091
|
|
22
|
-
knit_graphs-0.0.6.dist-info/RECORD,,
|