nodebpy 0.3.1__tar.gz → 0.4.0__tar.gz
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.
- {nodebpy-0.3.1 → nodebpy-0.4.0}/PKG-INFO +6 -56
- {nodebpy-0.3.1 → nodebpy-0.4.0}/README.md +4 -54
- {nodebpy-0.3.1 → nodebpy-0.4.0}/pyproject.toml +2 -2
- {nodebpy-0.3.1 → nodebpy-0.4.0}/src/nodebpy/builder.py +17 -13
- nodebpy-0.4.0/src/nodebpy/lib/nodearrange/__init__.py +2 -0
- nodebpy-0.4.0/src/nodebpy/lib/nodearrange/arrange/graph.py +583 -0
- nodebpy-0.4.0/src/nodebpy/lib/nodearrange/arrange/ordering.py +512 -0
- nodebpy-0.4.0/src/nodebpy/lib/nodearrange/arrange/ranking.py +256 -0
- nodebpy-0.4.0/src/nodebpy/lib/nodearrange/arrange/realize.py +231 -0
- nodebpy-0.4.0/src/nodebpy/lib/nodearrange/arrange/stacking.py +313 -0
- nodebpy-0.4.0/src/nodebpy/lib/nodearrange/arrange/structs.py +132 -0
- nodebpy-0.4.0/src/nodebpy/lib/nodearrange/arrange/sugiyama.py +256 -0
- nodebpy-0.4.0/src/nodebpy/lib/nodearrange/arrange/x_coords.py +211 -0
- nodebpy-0.4.0/src/nodebpy/lib/nodearrange/arrange/y_coords.py +339 -0
- nodebpy-0.4.0/src/nodebpy/lib/nodearrange/config.py +45 -0
- nodebpy-0.4.0/src/nodebpy/lib/nodearrange/utils.py +109 -0
- {nodebpy-0.3.1 → nodebpy-0.4.0}/src/nodebpy/nodes/color.py +0 -1
- {nodebpy-0.3.1 → nodebpy-0.4.0}/src/nodebpy/nodes/group.py +0 -1
- {nodebpy-0.3.1 → nodebpy-0.4.0}/src/nodebpy/__init__.py +0 -0
- {nodebpy-0.3.1 → nodebpy-0.4.0}/src/nodebpy/arrange.py +0 -0
- {nodebpy-0.3.1 → nodebpy-0.4.0}/src/nodebpy/nodes/__init__.py +0 -0
- {nodebpy-0.3.1 → nodebpy-0.4.0}/src/nodebpy/nodes/attribute.py +0 -0
- {nodebpy-0.3.1 → nodebpy-0.4.0}/src/nodebpy/nodes/converter.py +0 -0
- {nodebpy-0.3.1 → nodebpy-0.4.0}/src/nodebpy/nodes/experimental.py +0 -0
- {nodebpy-0.3.1 → nodebpy-0.4.0}/src/nodebpy/nodes/geometry.py +0 -0
- {nodebpy-0.3.1 → nodebpy-0.4.0}/src/nodebpy/nodes/grid.py +0 -0
- {nodebpy-0.3.1 → nodebpy-0.4.0}/src/nodebpy/nodes/input.py +0 -0
- {nodebpy-0.3.1 → nodebpy-0.4.0}/src/nodebpy/nodes/interface.py +0 -0
- {nodebpy-0.3.1 → nodebpy-0.4.0}/src/nodebpy/nodes/manual.py +0 -0
- {nodebpy-0.3.1 → nodebpy-0.4.0}/src/nodebpy/nodes/output.py +0 -0
- {nodebpy-0.3.1 → nodebpy-0.4.0}/src/nodebpy/nodes/texture.py +0 -0
- {nodebpy-0.3.1 → nodebpy-0.4.0}/src/nodebpy/nodes/vector.py +0 -0
- {nodebpy-0.3.1 → nodebpy-0.4.0}/src/nodebpy/nodes/zone.py +0 -0
- {nodebpy-0.3.1 → nodebpy-0.4.0}/src/nodebpy/screenshot.py +0 -0
- {nodebpy-0.3.1 → nodebpy-0.4.0}/src/nodebpy/screenshot_subprocess.py +0 -0
- {nodebpy-0.3.1 → nodebpy-0.4.0}/src/nodebpy/sockets.py +0 -0
- {nodebpy-0.3.1 → nodebpy-0.4.0}/src/nodebpy/types.py +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: nodebpy
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Build nodes in Blender with code
|
|
5
5
|
Author: Brady Johnston
|
|
6
6
|
Author-email: Brady Johnston <brady.johnston@me.com>
|
|
7
|
-
Requires-Dist:
|
|
7
|
+
Requires-Dist: networkx>=3.6.1
|
|
8
8
|
Requires-Dist: bpy>=5.0.0 ; extra == 'bpy'
|
|
9
9
|
Requires-Dist: fake-bpy-module>=20260113 ; extra == 'dev'
|
|
10
10
|
Requires-Dist: jsondiff>=2.2.1 ; extra == 'dev'
|
|
@@ -60,18 +60,16 @@ be linked to the previous node via the inferred or specified socket.
|
|
|
60
60
|
``` python
|
|
61
61
|
from nodebpy import TreeBuilder, nodes as n, sockets as s
|
|
62
62
|
|
|
63
|
-
with TreeBuilder("AnotherTree") as tree:
|
|
63
|
+
with TreeBuilder("AnotherTree", collapse=True) as tree:
|
|
64
64
|
with tree.inputs:
|
|
65
65
|
count = s.SocketInt("Count", 10)
|
|
66
66
|
with tree.outputs:
|
|
67
67
|
instances = s.SocketGeometry("Instances")
|
|
68
68
|
|
|
69
69
|
rotation = (
|
|
70
|
-
n.RandomValue.vector(min
|
|
70
|
+
n.RandomValue.vector(min=-1, seed=2)
|
|
71
71
|
>> n.AlignRotationToVector()
|
|
72
|
-
>> n.RotateRotation(
|
|
73
|
-
rotate_by=n.AxisAngleToRotation(angle=0.3), rotation_space="LOCAL"
|
|
74
|
-
)
|
|
72
|
+
>> n.RotateRotation(rotate_by=n.AxisAngleToRotation(angle=0.3))
|
|
75
73
|
)
|
|
76
74
|
|
|
77
75
|
_ = (
|
|
@@ -86,57 +84,9 @@ with TreeBuilder("AnotherTree") as tree:
|
|
|
86
84
|
>> n.InstanceOnPoints(n.Cube(), instance=...)
|
|
87
85
|
>> instances
|
|
88
86
|
)
|
|
89
|
-
|
|
90
|
-
tree
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
``` mermaid
|
|
94
|
-
graph LR
|
|
95
|
-
N0("NodeGroupInput"):::default-node
|
|
96
|
-
N1("RandomValue<br/><small>(-1,-1,-1) seed:2</small>"):::converter-node
|
|
97
|
-
N2("RandomValue<br/><small>(-1,-1,-1)</small>"):::converter-node
|
|
98
|
-
N3("AlignRotationToVector"):::converter-node
|
|
99
|
-
N4("AxisAngleToRotation<br/><small>(0,0,1)</small>"):::converter-node
|
|
100
|
-
N5("InputPosition"):::input-node
|
|
101
|
-
N6("Points"):::geometry-node
|
|
102
|
-
N7("MeshCube"):::geometry-node
|
|
103
|
-
N8("RotateRotation"):::converter-node
|
|
104
|
-
N9("VectorMath<br/><small>×2</small>"):::vector-node
|
|
105
|
-
N10("InstanceOnPoints"):::geometry-node
|
|
106
|
-
N11("VectorMath<br/><small>(0,0.2,0.3)</small>"):::vector-node
|
|
107
|
-
N12("SetPosition<br/><small>+(0,0,0.1)</small>"):::geometry-node
|
|
108
|
-
N13("MeshCube"):::geometry-node
|
|
109
|
-
N14("RealizeInstances"):::geometry-node
|
|
110
|
-
N15("InstanceOnPoints"):::geometry-node
|
|
111
|
-
N16("NodeGroupOutput"):::default-node
|
|
112
|
-
N1 -->|"Value>>Vector"| N3
|
|
113
|
-
N4 -->|"Rotation>>Rotate By"| N8
|
|
114
|
-
N3 -->|"Rotation>>Rotation"| N8
|
|
115
|
-
N2 -->|"Value>>Position"| N6
|
|
116
|
-
N0 -->|"Count>>Count"| N6
|
|
117
|
-
N7 -->|"Mesh>>Instance"| N10
|
|
118
|
-
N8 -->|"Rotation>>Rotation"| N10
|
|
119
|
-
N6 -->|"Points>>Points"| N10
|
|
120
|
-
N5 -->|"Position>>Vector"| N9
|
|
121
|
-
N9 -->|"Vector>>Vector"| N11
|
|
122
|
-
N11 -->|"Vector>>Position"| N12
|
|
123
|
-
N10 -->|"Instances>>Geometry"| N12
|
|
124
|
-
N12 -->|"Geometry>>Geometry"| N14
|
|
125
|
-
N13 -->|"Mesh>>Points"| N15
|
|
126
|
-
N14 -->|"Geometry>>Instance"| N15
|
|
127
|
-
N15 -->|"Instances>>Instances"| N16
|
|
128
|
-
|
|
129
|
-
classDef geometry-node fill:#e8f5f1,stroke:#3a7c49,stroke-width:2px
|
|
130
|
-
classDef converter-node fill:#e6f1f7,stroke:#246283,stroke-width:2px
|
|
131
|
-
classDef vector-node fill:#e9e9f5,stroke:#3C3C83,stroke-width:2px
|
|
132
|
-
classDef texture-node fill:#fef3e6,stroke:#E66800,stroke-width:2px
|
|
133
|
-
classDef shader-node fill:#fef0eb,stroke:#e67c52,stroke-width:2px
|
|
134
|
-
classDef input-node fill:#f1f8ed,stroke:#7fb069,stroke-width:2px
|
|
135
|
-
classDef output-node fill:#faf0ed,stroke:#c97659,stroke-width:2px
|
|
136
|
-
classDef default-node fill:#f0f0f0,stroke:#5a5a5a,stroke-width:2px
|
|
137
87
|
```
|
|
138
88
|
|
|
139
|
-

|
|
140
90
|
|
|
141
91
|
# Design Considerations
|
|
142
92
|
|
|
@@ -36,18 +36,16 @@ be linked to the previous node via the inferred or specified socket.
|
|
|
36
36
|
``` python
|
|
37
37
|
from nodebpy import TreeBuilder, nodes as n, sockets as s
|
|
38
38
|
|
|
39
|
-
with TreeBuilder("AnotherTree") as tree:
|
|
39
|
+
with TreeBuilder("AnotherTree", collapse=True) as tree:
|
|
40
40
|
with tree.inputs:
|
|
41
41
|
count = s.SocketInt("Count", 10)
|
|
42
42
|
with tree.outputs:
|
|
43
43
|
instances = s.SocketGeometry("Instances")
|
|
44
44
|
|
|
45
45
|
rotation = (
|
|
46
|
-
n.RandomValue.vector(min
|
|
46
|
+
n.RandomValue.vector(min=-1, seed=2)
|
|
47
47
|
>> n.AlignRotationToVector()
|
|
48
|
-
>> n.RotateRotation(
|
|
49
|
-
rotate_by=n.AxisAngleToRotation(angle=0.3), rotation_space="LOCAL"
|
|
50
|
-
)
|
|
48
|
+
>> n.RotateRotation(rotate_by=n.AxisAngleToRotation(angle=0.3))
|
|
51
49
|
)
|
|
52
50
|
|
|
53
51
|
_ = (
|
|
@@ -62,57 +60,9 @@ with TreeBuilder("AnotherTree") as tree:
|
|
|
62
60
|
>> n.InstanceOnPoints(n.Cube(), instance=...)
|
|
63
61
|
>> instances
|
|
64
62
|
)
|
|
65
|
-
|
|
66
|
-
tree
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
``` mermaid
|
|
70
|
-
graph LR
|
|
71
|
-
N0("NodeGroupInput"):::default-node
|
|
72
|
-
N1("RandomValue<br/><small>(-1,-1,-1) seed:2</small>"):::converter-node
|
|
73
|
-
N2("RandomValue<br/><small>(-1,-1,-1)</small>"):::converter-node
|
|
74
|
-
N3("AlignRotationToVector"):::converter-node
|
|
75
|
-
N4("AxisAngleToRotation<br/><small>(0,0,1)</small>"):::converter-node
|
|
76
|
-
N5("InputPosition"):::input-node
|
|
77
|
-
N6("Points"):::geometry-node
|
|
78
|
-
N7("MeshCube"):::geometry-node
|
|
79
|
-
N8("RotateRotation"):::converter-node
|
|
80
|
-
N9("VectorMath<br/><small>×2</small>"):::vector-node
|
|
81
|
-
N10("InstanceOnPoints"):::geometry-node
|
|
82
|
-
N11("VectorMath<br/><small>(0,0.2,0.3)</small>"):::vector-node
|
|
83
|
-
N12("SetPosition<br/><small>+(0,0,0.1)</small>"):::geometry-node
|
|
84
|
-
N13("MeshCube"):::geometry-node
|
|
85
|
-
N14("RealizeInstances"):::geometry-node
|
|
86
|
-
N15("InstanceOnPoints"):::geometry-node
|
|
87
|
-
N16("NodeGroupOutput"):::default-node
|
|
88
|
-
N1 -->|"Value>>Vector"| N3
|
|
89
|
-
N4 -->|"Rotation>>Rotate By"| N8
|
|
90
|
-
N3 -->|"Rotation>>Rotation"| N8
|
|
91
|
-
N2 -->|"Value>>Position"| N6
|
|
92
|
-
N0 -->|"Count>>Count"| N6
|
|
93
|
-
N7 -->|"Mesh>>Instance"| N10
|
|
94
|
-
N8 -->|"Rotation>>Rotation"| N10
|
|
95
|
-
N6 -->|"Points>>Points"| N10
|
|
96
|
-
N5 -->|"Position>>Vector"| N9
|
|
97
|
-
N9 -->|"Vector>>Vector"| N11
|
|
98
|
-
N11 -->|"Vector>>Position"| N12
|
|
99
|
-
N10 -->|"Instances>>Geometry"| N12
|
|
100
|
-
N12 -->|"Geometry>>Geometry"| N14
|
|
101
|
-
N13 -->|"Mesh>>Points"| N15
|
|
102
|
-
N14 -->|"Geometry>>Instance"| N15
|
|
103
|
-
N15 -->|"Instances>>Instances"| N16
|
|
104
|
-
|
|
105
|
-
classDef geometry-node fill:#e8f5f1,stroke:#3a7c49,stroke-width:2px
|
|
106
|
-
classDef converter-node fill:#e6f1f7,stroke:#246283,stroke-width:2px
|
|
107
|
-
classDef vector-node fill:#e9e9f5,stroke:#3C3C83,stroke-width:2px
|
|
108
|
-
classDef texture-node fill:#fef3e6,stroke:#E66800,stroke-width:2px
|
|
109
|
-
classDef shader-node fill:#fef0eb,stroke:#e67c52,stroke-width:2px
|
|
110
|
-
classDef input-node fill:#f1f8ed,stroke:#7fb069,stroke-width:2px
|
|
111
|
-
classDef output-node fill:#faf0ed,stroke:#c97659,stroke-width:2px
|
|
112
|
-
classDef default-node fill:#f0f0f0,stroke:#5a5a5a,stroke-width:2px
|
|
113
63
|
```
|
|
114
64
|
|
|
115
|
-

|
|
116
66
|
|
|
117
67
|
# Design Considerations
|
|
118
68
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "nodebpy"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.4.0"
|
|
4
4
|
description = "Build nodes in Blender with code"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [
|
|
@@ -8,7 +8,7 @@ authors = [
|
|
|
8
8
|
]
|
|
9
9
|
requires-python = ">=3.11"
|
|
10
10
|
dependencies = [
|
|
11
|
-
"
|
|
11
|
+
"networkx>=3.6.1",
|
|
12
12
|
]
|
|
13
13
|
|
|
14
14
|
[project.scripts]
|
|
@@ -5,7 +5,6 @@ from typing import TYPE_CHECKING, Any, ClassVar, Iterable, Literal
|
|
|
5
5
|
if TYPE_CHECKING:
|
|
6
6
|
from .nodes import Math, VectorMath
|
|
7
7
|
|
|
8
|
-
import arrangebpy
|
|
9
8
|
import bpy
|
|
10
9
|
from bpy.types import (
|
|
11
10
|
GeometryNodeTree,
|
|
@@ -14,6 +13,7 @@ from bpy.types import (
|
|
|
14
13
|
NodeSocket,
|
|
15
14
|
)
|
|
16
15
|
|
|
16
|
+
from .lib.nodearrange import arrange
|
|
17
17
|
from .types import (
|
|
18
18
|
LINKABLE,
|
|
19
19
|
SOCKET_COMPATIBILITY,
|
|
@@ -117,12 +117,15 @@ class TreeBuilder:
|
|
|
117
117
|
"""Builder for creating Blender geometry node trees with a clean Python API."""
|
|
118
118
|
|
|
119
119
|
_tree_contexts: ClassVar["list[TreeBuilder]"] = []
|
|
120
|
-
# _active_tree: ClassVar["TreeBuilder | None"] = None
|
|
121
|
-
# _previous_tree: ClassVar["list[TreeBuilder]"] = list()
|
|
122
120
|
just_added: "Node | None" = None
|
|
121
|
+
collapse: bool = False
|
|
123
122
|
|
|
124
123
|
def __init__(
|
|
125
|
-
self,
|
|
124
|
+
self,
|
|
125
|
+
tree: GeometryNodeTree | str = "Geometry Nodes",
|
|
126
|
+
*,
|
|
127
|
+
collapse: bool = False,
|
|
128
|
+
arrange: bool = True,
|
|
126
129
|
):
|
|
127
130
|
if isinstance(tree, str):
|
|
128
131
|
self.tree = bpy.data.node_groups.new(tree, "GeometryNodeTree")
|
|
@@ -134,6 +137,11 @@ class TreeBuilder:
|
|
|
134
137
|
self.inputs = InputInterfaceContext(self)
|
|
135
138
|
self.outputs = OutputInterfaceContext(self)
|
|
136
139
|
self._arrange = arrange
|
|
140
|
+
self.collapse = collapse
|
|
141
|
+
|
|
142
|
+
@property
|
|
143
|
+
def nodes(self) -> Nodes:
|
|
144
|
+
return self.tree.nodes
|
|
137
145
|
|
|
138
146
|
def activate_tree(self) -> None:
|
|
139
147
|
"""Make this tree the active tree for all new node creation."""
|
|
@@ -152,18 +160,12 @@ class TreeBuilder:
|
|
|
152
160
|
self.arrange()
|
|
153
161
|
self.deactivate_tree()
|
|
154
162
|
|
|
155
|
-
@property
|
|
156
|
-
def nodes(self) -> Nodes:
|
|
157
|
-
return self.tree.nodes
|
|
158
|
-
|
|
159
163
|
def __len__(self) -> int:
|
|
160
164
|
return len(self.nodes)
|
|
161
165
|
|
|
162
166
|
def arrange(self):
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
)
|
|
166
|
-
arrangebpy.sugiyama_layout(self.tree, settings)
|
|
167
|
+
arrange.sugiyama.sugiyama_layout(self.tree)
|
|
168
|
+
arrange.sugiyama.config.reset()
|
|
167
169
|
|
|
168
170
|
def _repr_markdown_(self) -> str | None:
|
|
169
171
|
"""
|
|
@@ -230,7 +232,9 @@ class TreeBuilder:
|
|
|
230
232
|
return link
|
|
231
233
|
|
|
232
234
|
def add(self, name: str) -> Node:
|
|
233
|
-
|
|
235
|
+
node = self.tree.nodes.new(name)
|
|
236
|
+
node.hide = self.collapse
|
|
237
|
+
return node
|
|
234
238
|
|
|
235
239
|
|
|
236
240
|
class NodeBuilder:
|