nodebpy 0.16.0__tar.gz → 0.17.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.16.0 → nodebpy-0.17.0}/PKG-INFO +1 -1
- {nodebpy-0.16.0 → nodebpy-0.17.0}/pyproject.toml +1 -1
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/builder/accessor.py +2 -2
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/builder/mixins.py +1 -1
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/builder/socket.py +517 -46
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/geometry/groups.py +12 -12
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/geometry/manual.py +32 -31
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/types.py +1 -1
- {nodebpy-0.16.0 → nodebpy-0.17.0}/README.md +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/__init__.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/arrange.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/builder/__init__.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/builder/_registry.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/builder/_utils.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/builder/node.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/builder/tree.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/diagram.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/lib/nodearrange/__init__.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/lib/nodearrange/arrange/graph.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/lib/nodearrange/arrange/ordering.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/lib/nodearrange/arrange/ranking.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/lib/nodearrange/arrange/realize.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/lib/nodearrange/arrange/stacking.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/lib/nodearrange/arrange/structs.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/lib/nodearrange/arrange/sugiyama.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/lib/nodearrange/arrange/x_coords.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/lib/nodearrange/arrange/y_coords.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/lib/nodearrange/config.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/lib/nodearrange/utils.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/__init__.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/compositor/__init__.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/compositor/color.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/compositor/converter.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/compositor/distort.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/compositor/filter.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/compositor/group.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/compositor/input.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/compositor/interface.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/compositor/manual.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/compositor/matte.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/compositor/output.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/compositor/vector.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/geometry/__init__.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/geometry/attribute.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/geometry/color.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/geometry/converter.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/geometry/geometry.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/geometry/grid.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/geometry/group.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/geometry/input.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/geometry/interface.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/geometry/output.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/geometry/texture.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/geometry/utilities.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/geometry/vector.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/geometry/zone.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/shader/__init__.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/shader/color.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/shader/converter.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/shader/grid.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/shader/group.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/shader/input.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/shader/manual.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/shader/output.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/shader/script.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/shader/shader.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/shader/texture.py +0 -0
- {nodebpy-0.16.0 → nodebpy-0.17.0}/src/nodebpy/nodes/shader/vector.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import TYPE_CHECKING, Literal, overload
|
|
3
|
+
from typing import TYPE_CHECKING, Iterator, Literal, overload
|
|
4
4
|
|
|
5
5
|
import bpy
|
|
6
6
|
from bpy.types import NodeSocket
|
|
@@ -200,7 +200,7 @@ class SocketAccessor:
|
|
|
200
200
|
def __len__(self) -> int:
|
|
201
201
|
return len(self._items())
|
|
202
202
|
|
|
203
|
-
def __iter__(self):
|
|
203
|
+
def __iter__(self) -> Iterator["Socket"]:
|
|
204
204
|
return iter(self._values())
|
|
205
205
|
|
|
206
206
|
def __getattr__(self, name: str) -> "Socket":
|
|
@@ -11,7 +11,7 @@ from ._utils import SocketError, _resolve_promotion, _SocketLike
|
|
|
11
11
|
_RShiftT = TypeVar("_RShiftT")
|
|
12
12
|
|
|
13
13
|
if TYPE_CHECKING:
|
|
14
|
-
from ..nodes.geometry import Compare
|
|
14
|
+
from ..nodes.geometry import Compare
|
|
15
15
|
from ..types import InputLinkable
|
|
16
16
|
from .node import BaseNode
|
|
17
17
|
from .socket import (
|
|
@@ -3,9 +3,13 @@ from __future__ import annotations
|
|
|
3
3
|
from typing import (
|
|
4
4
|
TYPE_CHECKING,
|
|
5
5
|
Any,
|
|
6
|
+
Generic,
|
|
6
7
|
Iterable,
|
|
7
8
|
Iterator,
|
|
9
|
+
Literal,
|
|
8
10
|
Mapping,
|
|
11
|
+
NamedTuple,
|
|
12
|
+
TypeVar,
|
|
9
13
|
cast,
|
|
10
14
|
overload,
|
|
11
15
|
)
|
|
@@ -68,14 +72,45 @@ if TYPE_CHECKING:
|
|
|
68
72
|
IntegerMath,
|
|
69
73
|
MatchString,
|
|
70
74
|
Math,
|
|
71
|
-
MultiplyMatrices,
|
|
72
|
-
TransformPoint,
|
|
73
75
|
)
|
|
74
76
|
from ..nodes.geometry.manual import Compare
|
|
75
77
|
from ..nodes.geometry.vector import VectorMath
|
|
76
78
|
from .node import BaseNode
|
|
77
79
|
from .tree import TreeBuilder
|
|
78
80
|
|
|
81
|
+
_T = TypeVar("_T")
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class QuaternionComponents(NamedTuple):
|
|
85
|
+
"""Quaternion components returned by `RotationSocket.to_quaternion()`."""
|
|
86
|
+
|
|
87
|
+
w: "FloatSocket"
|
|
88
|
+
x: "FloatSocket"
|
|
89
|
+
y: "FloatSocket"
|
|
90
|
+
z: "FloatSocket"
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class AxisAngle(NamedTuple):
|
|
94
|
+
"""Axis-angle components returned by `RotationSocket.to_axis_angle()`."""
|
|
95
|
+
|
|
96
|
+
axis: "VectorSocket"
|
|
97
|
+
angle: "FloatSocket"
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class FindResult(NamedTuple):
|
|
101
|
+
"""Result of `StringSocket.find()`."""
|
|
102
|
+
|
|
103
|
+
first_found: "IntegerSocket"
|
|
104
|
+
count: "IntegerSocket"
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class SVDResult(NamedTuple):
|
|
108
|
+
"""SVD components returned by `MatrixSocket.svd()`."""
|
|
109
|
+
|
|
110
|
+
u: "MatrixSocket"
|
|
111
|
+
s: "VectorSocket"
|
|
112
|
+
v: "MatrixSocket"
|
|
113
|
+
|
|
79
114
|
|
|
80
115
|
class BaseSocket:
|
|
81
116
|
def __init__(self, socket: NodeSocket):
|
|
@@ -243,6 +278,89 @@ class Socket(BaseSocket, _SocketLike, OperatorMixin, LinkingMixin):
|
|
|
243
278
|
# ---------------------------------------------------------------------------
|
|
244
279
|
|
|
245
280
|
|
|
281
|
+
class _FieldDomain(Generic[_T]):
|
|
282
|
+
"""Domain-bound factory available on all socket types.
|
|
283
|
+
|
|
284
|
+
Access via a domain property (e.g. ``socket.point``). Provides field
|
|
285
|
+
evaluation methods; subclasses add statistics for numeric socket types.
|
|
286
|
+
"""
|
|
287
|
+
|
|
288
|
+
def __init__(self, socket: NodeSocket, dtype: str, domain: str) -> None:
|
|
289
|
+
self._socket = socket
|
|
290
|
+
self._dtype = dtype
|
|
291
|
+
self._domain = domain
|
|
292
|
+
|
|
293
|
+
def evaluate(self) -> "_T":
|
|
294
|
+
"""Force evaluation of this field on the bound domain via ``EvaluateOnDomain``."""
|
|
295
|
+
from ..nodes.geometry import EvaluateOnDomain
|
|
296
|
+
|
|
297
|
+
return getattr(getattr(EvaluateOnDomain, self._domain), self._dtype)(
|
|
298
|
+
self._socket
|
|
299
|
+
).o.value
|
|
300
|
+
|
|
301
|
+
def at(self, index: InputInteger = 0) -> "_T":
|
|
302
|
+
"""Evaluate this field's value at *index* on the bound domain via ``EvaluateAtIndex``."""
|
|
303
|
+
from ..nodes.geometry import EvaluateAtIndex
|
|
304
|
+
|
|
305
|
+
return getattr(getattr(EvaluateAtIndex, self._domain), self._dtype)(
|
|
306
|
+
self._socket, index
|
|
307
|
+
).o.value
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
class _MinMaxDomain(_FieldDomain[_T]):
|
|
311
|
+
"""Extends ``_FieldDomain`` with min/max aggregation for Integer sockets."""
|
|
312
|
+
|
|
313
|
+
def _minmax(self, field: str, group_index: InputInteger) -> "_T":
|
|
314
|
+
from ..nodes.geometry import FieldMinAndMax
|
|
315
|
+
|
|
316
|
+
node = getattr(getattr(FieldMinAndMax, self._domain), self._dtype)(
|
|
317
|
+
self._socket, group_index
|
|
318
|
+
)
|
|
319
|
+
return getattr(node.o, field)
|
|
320
|
+
|
|
321
|
+
def min(self, group_index: InputInteger = None) -> "_T":
|
|
322
|
+
return self._minmax("min", group_index)
|
|
323
|
+
|
|
324
|
+
def max(self, group_index: InputInteger = None) -> "_T":
|
|
325
|
+
return self._minmax("max", group_index)
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
class _StatsDomain(_MinMaxDomain[_T]):
|
|
329
|
+
"""Extends ``_MinMaxDomain`` with full statistics for Float and Vector sockets."""
|
|
330
|
+
|
|
331
|
+
def mean(self, group_index: InputInteger = None) -> "_T":
|
|
332
|
+
from ..nodes.geometry import FieldAverage
|
|
333
|
+
|
|
334
|
+
node = getattr(getattr(FieldAverage, self._domain), self._dtype)(
|
|
335
|
+
self._socket, group_index
|
|
336
|
+
)
|
|
337
|
+
return node.o.mean
|
|
338
|
+
|
|
339
|
+
def median(self, group_index: InputInteger = None) -> "_T":
|
|
340
|
+
from ..nodes.geometry import FieldAverage
|
|
341
|
+
|
|
342
|
+
node = getattr(getattr(FieldAverage, self._domain), self._dtype)(
|
|
343
|
+
self._socket, group_index
|
|
344
|
+
)
|
|
345
|
+
return node.o.median
|
|
346
|
+
|
|
347
|
+
def std_dev(self, group_index: InputInteger = None) -> "_T":
|
|
348
|
+
from ..nodes.geometry import FieldVariance
|
|
349
|
+
|
|
350
|
+
node = getattr(getattr(FieldVariance, self._domain), self._dtype)(
|
|
351
|
+
self._socket, group_index
|
|
352
|
+
)
|
|
353
|
+
return node.o.standard_deviation
|
|
354
|
+
|
|
355
|
+
def variance(self, group_index: InputInteger = None) -> "_T":
|
|
356
|
+
from ..nodes.geometry import FieldVariance
|
|
357
|
+
|
|
358
|
+
node = getattr(getattr(FieldVariance, self._domain), self._dtype)(
|
|
359
|
+
self._socket, group_index
|
|
360
|
+
)
|
|
361
|
+
return node.o.variance
|
|
362
|
+
|
|
363
|
+
|
|
246
364
|
class _VectorMixin(BaseSocket):
|
|
247
365
|
"""Vector-specific properties (.x, .y, .z) and dispatch."""
|
|
248
366
|
|
|
@@ -286,6 +404,34 @@ class _VectorMixin(BaseSocket):
|
|
|
286
404
|
else:
|
|
287
405
|
return self._combine().i.z
|
|
288
406
|
|
|
407
|
+
@property
|
|
408
|
+
def point(self) -> "_StatsDomain[VectorSocket]":
|
|
409
|
+
return _StatsDomain(self.socket, "vector", "point")
|
|
410
|
+
|
|
411
|
+
@property
|
|
412
|
+
def edge(self) -> "_StatsDomain[VectorSocket]":
|
|
413
|
+
return _StatsDomain(self.socket, "vector", "edge")
|
|
414
|
+
|
|
415
|
+
@property
|
|
416
|
+
def face(self) -> "_StatsDomain[VectorSocket]":
|
|
417
|
+
return _StatsDomain(self.socket, "vector", "face")
|
|
418
|
+
|
|
419
|
+
@property
|
|
420
|
+
def corner(self) -> "_StatsDomain[VectorSocket]":
|
|
421
|
+
return _StatsDomain(self.socket, "vector", "corner")
|
|
422
|
+
|
|
423
|
+
@property
|
|
424
|
+
def spline(self) -> "_StatsDomain[VectorSocket]":
|
|
425
|
+
return _StatsDomain(self.socket, "vector", "spline")
|
|
426
|
+
|
|
427
|
+
@property
|
|
428
|
+
def instance(self) -> "_StatsDomain[VectorSocket]":
|
|
429
|
+
return _StatsDomain(self.socket, "vector", "instance")
|
|
430
|
+
|
|
431
|
+
@property
|
|
432
|
+
def layer(self) -> "_StatsDomain[VectorSocket]":
|
|
433
|
+
return _StatsDomain(self.socket, "vector", "layer")
|
|
434
|
+
|
|
289
435
|
def dot(self, vector: InputVector) -> "FloatSocket":
|
|
290
436
|
"""Dot product with another vector. The other vector can be a Socket, a NodeSocket, or a 3-tuple of floats.
|
|
291
437
|
|
|
@@ -307,6 +453,61 @@ class _VectorMixin(BaseSocket):
|
|
|
307
453
|
"""
|
|
308
454
|
return self._vmath.normalize(self.socket).o.vector
|
|
309
455
|
|
|
456
|
+
def cross(self, other: InputVector) -> "VectorSocket":
|
|
457
|
+
"""Cross product of this vector with *other*. Returns a vector perpendicular to both."""
|
|
458
|
+
return self._vmath.cross_product(self.socket, other).o.vector
|
|
459
|
+
|
|
460
|
+
def distance(self, other: InputVector) -> "FloatSocket":
|
|
461
|
+
"""Euclidean distance between this vector and *other*."""
|
|
462
|
+
return self._vmath.distance(self.socket, other).o.value
|
|
463
|
+
|
|
464
|
+
def project(self, other: InputVector) -> "VectorSocket":
|
|
465
|
+
"""Project this vector onto *other*."""
|
|
466
|
+
return self._vmath.project(self.socket, other).o.vector
|
|
467
|
+
|
|
468
|
+
def reflect(self, normal: InputVector) -> "VectorSocket":
|
|
469
|
+
"""Reflect this vector around *normal*. *normal* does not need to be normalised."""
|
|
470
|
+
return self._vmath.reflect(self.socket, normal).o.vector
|
|
471
|
+
|
|
472
|
+
def map_range(
|
|
473
|
+
self,
|
|
474
|
+
from_min: InputVector = (0.0, 0.0, 0.0),
|
|
475
|
+
from_max: InputVector = (1.0, 1.0, 1.0),
|
|
476
|
+
to_min: InputVector = (0.0, 0.0, 0.0),
|
|
477
|
+
to_max: InputVector = (1.0, 1.0, 1.0),
|
|
478
|
+
*,
|
|
479
|
+
clamp: bool = True,
|
|
480
|
+
interpolation_type: Literal[
|
|
481
|
+
"LINEAR", "STEPPED", "SMOOTHSTEP", "SMOOTHERSTEP"
|
|
482
|
+
] = "LINEAR",
|
|
483
|
+
steps: InputVector = (4.0, 4.0, 4.0),
|
|
484
|
+
) -> "VectorSocket":
|
|
485
|
+
"""Convenience method to remap a vector socket using the `MapRange.vector()` node with this socket as input"""
|
|
486
|
+
from ..nodes.geometry import MapRange
|
|
487
|
+
|
|
488
|
+
node = MapRange.vector(self.socket, from_min, from_max, to_min, to_max)
|
|
489
|
+
node.clamp = clamp
|
|
490
|
+
node.interpolation_type = interpolation_type
|
|
491
|
+
if interpolation_type == "STEPPED":
|
|
492
|
+
kwargs = {"Steps_FLOAT3": steps}
|
|
493
|
+
node._establish_links(**kwargs)
|
|
494
|
+
return node.o.vector
|
|
495
|
+
|
|
496
|
+
def rotate(
|
|
497
|
+
self,
|
|
498
|
+
rotation: InputRotation,
|
|
499
|
+
) -> "VectorSocket":
|
|
500
|
+
"Rotate this vector by the given rotation."
|
|
501
|
+
from ..nodes.geometry import RotateVector
|
|
502
|
+
|
|
503
|
+
return RotateVector(self.socket, rotation).o.vector
|
|
504
|
+
|
|
505
|
+
def transform(self, matrix: InputMatrix) -> "VectorSocket":
|
|
506
|
+
"Transform this vector by the given matrix."
|
|
507
|
+
from ..nodes.geometry import TransformPoint
|
|
508
|
+
|
|
509
|
+
return TransformPoint(self.socket, matrix).o.vector
|
|
510
|
+
|
|
310
511
|
@property
|
|
311
512
|
def default_value(self) -> list[float]:
|
|
312
513
|
return list(self.socket.default_value)
|
|
@@ -428,10 +629,10 @@ class _VectorMixin(BaseSocket):
|
|
|
428
629
|
def __rfloordiv__(self, other: Any) -> "VectorSocket": ...
|
|
429
630
|
def __neg__(self) -> "VectorSocket": ...
|
|
430
631
|
def __abs__(self) -> "VectorSocket": ...
|
|
431
|
-
def __lt__(self, other: Any) -> "Compare[
|
|
432
|
-
def __gt__(self, other: Any) -> "Compare[
|
|
433
|
-
def __le__(self, other: Any) -> "Compare[
|
|
434
|
-
def __ge__(self, other: Any) -> "Compare[
|
|
632
|
+
def __lt__(self, other: Any) -> "Compare[VectorSocket]": ...
|
|
633
|
+
def __gt__(self, other: Any) -> "Compare[VectorSocket]": ...
|
|
634
|
+
def __le__(self, other: Any) -> "Compare[VectorSocket]": ...
|
|
635
|
+
def __ge__(self, other: Any) -> "Compare[VectorSocket]": ...
|
|
435
636
|
|
|
436
637
|
|
|
437
638
|
_SEPARATE_COLOR_IDNAMES = (
|
|
@@ -710,9 +911,37 @@ class _BooleanMixin(BaseSocket):
|
|
|
710
911
|
|
|
711
912
|
return _BooleanSwitchSocketFactory(self.socket)
|
|
712
913
|
|
|
914
|
+
@property
|
|
915
|
+
def point(self) -> "_FieldDomain[BooleanSocket]":
|
|
916
|
+
return _FieldDomain(self.socket, "boolean", "point")
|
|
917
|
+
|
|
918
|
+
@property
|
|
919
|
+
def edge(self) -> "_FieldDomain[BooleanSocket]":
|
|
920
|
+
return _FieldDomain(self.socket, "boolean", "edge")
|
|
921
|
+
|
|
922
|
+
@property
|
|
923
|
+
def face(self) -> "_FieldDomain[BooleanSocket]":
|
|
924
|
+
return _FieldDomain(self.socket, "boolean", "face")
|
|
925
|
+
|
|
926
|
+
@property
|
|
927
|
+
def corner(self) -> "_FieldDomain[BooleanSocket]":
|
|
928
|
+
return _FieldDomain(self.socket, "boolean", "corner")
|
|
929
|
+
|
|
930
|
+
@property
|
|
931
|
+
def spline(self) -> "_FieldDomain[BooleanSocket]":
|
|
932
|
+
return _FieldDomain(self.socket, "boolean", "spline")
|
|
933
|
+
|
|
934
|
+
@property
|
|
935
|
+
def instance(self) -> "_FieldDomain[BooleanSocket]":
|
|
936
|
+
return _FieldDomain(self.socket, "boolean", "instance")
|
|
937
|
+
|
|
938
|
+
@property
|
|
939
|
+
def layer(self) -> "_FieldDomain[BooleanSocket]":
|
|
940
|
+
return _FieldDomain(self.socket, "boolean", "layer")
|
|
941
|
+
|
|
713
942
|
|
|
714
943
|
class _RotationMixin(BaseSocket):
|
|
715
|
-
"""Rotation-specific
|
|
944
|
+
"""Rotation-specific methods."""
|
|
716
945
|
|
|
717
946
|
socket: NodeSocketRotation
|
|
718
947
|
|
|
@@ -724,43 +953,101 @@ class _RotationMixin(BaseSocket):
|
|
|
724
953
|
def default_value(self, value: Euler) -> None:
|
|
725
954
|
self.socket.default_value = value
|
|
726
955
|
|
|
727
|
-
|
|
728
|
-
|
|
956
|
+
def invert(self) -> "RotationSocket":
|
|
957
|
+
"Invert the rotation of the socket."
|
|
958
|
+
from ..nodes.geometry import InvertRotation
|
|
959
|
+
|
|
960
|
+
return InvertRotation._find_or_create_linked(self.socket).o.rotation
|
|
961
|
+
|
|
962
|
+
def rotate(
|
|
963
|
+
self,
|
|
964
|
+
rotation: InputRotation,
|
|
965
|
+
rotation_space: Literal["GLOBAL", "LOCAL"] = "GLOBAL",
|
|
966
|
+
) -> "RotationSocket":
|
|
967
|
+
"Rotate this rotation by the given rotation in the specified rotation space."
|
|
968
|
+
from ..nodes.geometry import RotateRotation
|
|
969
|
+
|
|
970
|
+
return RotateRotation(
|
|
971
|
+
self.socket, rotation, rotation_space=rotation_space
|
|
972
|
+
).o.rotation
|
|
973
|
+
|
|
974
|
+
def to_euler(self) -> "VectorSocket":
|
|
975
|
+
"Convert the rotation to an XYZ euler rotation and return `VectorSocket`."
|
|
976
|
+
from ..nodes.geometry.converter import RotationToEuler
|
|
977
|
+
|
|
978
|
+
return RotationToEuler._find_or_create_linked(self.socket).o.euler
|
|
979
|
+
|
|
980
|
+
def to_quaternion(self) -> QuaternionComponents:
|
|
981
|
+
"Decompose the rotation into quaternion components `(w, x, y, z)`."
|
|
729
982
|
from ..nodes.geometry import RotationToQuaternion
|
|
730
983
|
|
|
731
|
-
|
|
984
|
+
o = RotationToQuaternion._find_or_create_linked(self.socket).o
|
|
985
|
+
return QuaternionComponents(o.w, o.x, o.y, o.z)
|
|
986
|
+
|
|
987
|
+
def to_axis_angle(self) -> AxisAngle:
|
|
988
|
+
"Decompose the rotation into axis-angle components `(axis, angle)`."
|
|
989
|
+
from ..nodes.geometry import RotationToAxisAngle
|
|
990
|
+
|
|
991
|
+
o = RotationToAxisAngle(self.socket).o
|
|
992
|
+
return AxisAngle(o.axis, o.angle)
|
|
732
993
|
|
|
733
994
|
@property
|
|
734
|
-
def
|
|
735
|
-
|
|
736
|
-
return self._quaternion.o.w
|
|
995
|
+
def point(self) -> "_FieldDomain[RotationSocket]":
|
|
996
|
+
return _FieldDomain(self.socket, "quaternion", "point")
|
|
737
997
|
|
|
738
998
|
@property
|
|
739
|
-
def
|
|
740
|
-
|
|
741
|
-
return self._quaternion.o.x
|
|
999
|
+
def edge(self) -> "_FieldDomain[RotationSocket]":
|
|
1000
|
+
return _FieldDomain(self.socket, "quaternion", "edge")
|
|
742
1001
|
|
|
743
1002
|
@property
|
|
744
|
-
def
|
|
745
|
-
|
|
746
|
-
return self._quaternion.o.y
|
|
1003
|
+
def face(self) -> "_FieldDomain[RotationSocket]":
|
|
1004
|
+
return _FieldDomain(self.socket, "quaternion", "face")
|
|
747
1005
|
|
|
748
1006
|
@property
|
|
749
|
-
def
|
|
750
|
-
|
|
751
|
-
return self._quaternion.o.z
|
|
1007
|
+
def corner(self) -> "_FieldDomain[RotationSocket]":
|
|
1008
|
+
return _FieldDomain(self.socket, "quaternion", "corner")
|
|
752
1009
|
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
1010
|
+
@property
|
|
1011
|
+
def spline(self) -> "_FieldDomain[RotationSocket]":
|
|
1012
|
+
return _FieldDomain(self.socket, "quaternion", "spline")
|
|
756
1013
|
|
|
757
|
-
|
|
1014
|
+
@property
|
|
1015
|
+
def instance(self) -> "_FieldDomain[RotationSocket]":
|
|
1016
|
+
return _FieldDomain(self.socket, "quaternion", "instance")
|
|
758
1017
|
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
1018
|
+
@property
|
|
1019
|
+
def layer(self) -> "_FieldDomain[RotationSocket]":
|
|
1020
|
+
return _FieldDomain(self.socket, "quaternion", "layer")
|
|
762
1021
|
|
|
763
|
-
|
|
1022
|
+
|
|
1023
|
+
class _FloatMixDataTypeFactory:
|
|
1024
|
+
"""Factory for typed Mix nodes driven by a float factor socket.
|
|
1025
|
+
|
|
1026
|
+
Access via ``FloatSocket.mix``. Each method creates a ``Mix`` node using
|
|
1027
|
+
this socket as the factor and returns the corresponding output socket.
|
|
1028
|
+
"""
|
|
1029
|
+
|
|
1030
|
+
def __init__(self, socket: NodeSocket):
|
|
1031
|
+
self._socket = socket
|
|
1032
|
+
from ..nodes.geometry import Mix
|
|
1033
|
+
|
|
1034
|
+
self._mix = Mix
|
|
1035
|
+
|
|
1036
|
+
def float(self, a: InputFloat, b: InputFloat) -> "FloatSocket":
|
|
1037
|
+
"Mix two float values, returning a ``FloatSocket``."
|
|
1038
|
+
return self._mix.float(self._socket, a, b).o.result_float
|
|
1039
|
+
|
|
1040
|
+
def vector(self, a: InputVector, b: InputVector) -> "VectorSocket":
|
|
1041
|
+
"Mix two vectors, returning a ``VectorSocket``."
|
|
1042
|
+
return self._mix.vector(self._socket, a, b).o.result_vector
|
|
1043
|
+
|
|
1044
|
+
def color(self, a: InputColor, b: InputColor) -> "ColorSocket":
|
|
1045
|
+
"Mix two colors, returning a ``ColorSocket``."
|
|
1046
|
+
return self._mix.color(self._socket, a, b).o.result_color
|
|
1047
|
+
|
|
1048
|
+
def rotation(self, a: InputRotation, b: InputRotation) -> "RotationSocket":
|
|
1049
|
+
"Mix two rotations, returning a ``RotationSocket``."
|
|
1050
|
+
return self._mix.rotation(self._socket, a, b).o.result_rotation
|
|
764
1051
|
|
|
765
1052
|
|
|
766
1053
|
class _FloatMixin(BaseSocket):
|
|
@@ -782,6 +1069,106 @@ class _FloatMixin(BaseSocket):
|
|
|
782
1069
|
|
|
783
1070
|
return Math
|
|
784
1071
|
|
|
1072
|
+
@property
|
|
1073
|
+
def mix(self) -> _FloatMixDataTypeFactory:
|
|
1074
|
+
"Create a ``Mix`` node using this socket as the factor."
|
|
1075
|
+
return _FloatMixDataTypeFactory(self.socket)
|
|
1076
|
+
|
|
1077
|
+
@property
|
|
1078
|
+
def point(self) -> "_StatsDomain[FloatSocket]":
|
|
1079
|
+
return _StatsDomain(self.socket, "float", "point")
|
|
1080
|
+
|
|
1081
|
+
@property
|
|
1082
|
+
def edge(self) -> "_StatsDomain[FloatSocket]":
|
|
1083
|
+
return _StatsDomain(self.socket, "float", "edge")
|
|
1084
|
+
|
|
1085
|
+
@property
|
|
1086
|
+
def face(self) -> "_StatsDomain[FloatSocket]":
|
|
1087
|
+
return _StatsDomain(self.socket, "float", "face")
|
|
1088
|
+
|
|
1089
|
+
@property
|
|
1090
|
+
def corner(self) -> "_StatsDomain[FloatSocket]":
|
|
1091
|
+
return _StatsDomain(self.socket, "float", "corner")
|
|
1092
|
+
|
|
1093
|
+
@property
|
|
1094
|
+
def spline(self) -> "_StatsDomain[FloatSocket]":
|
|
1095
|
+
return _StatsDomain(self.socket, "float", "spline")
|
|
1096
|
+
|
|
1097
|
+
@property
|
|
1098
|
+
def instance(self) -> "_StatsDomain[FloatSocket]":
|
|
1099
|
+
return _StatsDomain(self.socket, "float", "instance")
|
|
1100
|
+
|
|
1101
|
+
@property
|
|
1102
|
+
def layer(self) -> "_StatsDomain[FloatSocket]":
|
|
1103
|
+
return _StatsDomain(self.socket, "float", "layer")
|
|
1104
|
+
|
|
1105
|
+
def map_range(
|
|
1106
|
+
self,
|
|
1107
|
+
from_min: InputFloat = 0.0,
|
|
1108
|
+
from_max: InputFloat = 1.0,
|
|
1109
|
+
to_min: InputFloat = 0.0,
|
|
1110
|
+
to_max: InputFloat = 1.0,
|
|
1111
|
+
*,
|
|
1112
|
+
clamp=True,
|
|
1113
|
+
interpolation_type: Literal[
|
|
1114
|
+
"LINEAR", "STEPPED", "SMOOTHSTEP", "SMOOTHERSTEP"
|
|
1115
|
+
] = "LINEAR",
|
|
1116
|
+
steps: InputFloat = 4.0,
|
|
1117
|
+
) -> "FloatSocket":
|
|
1118
|
+
"""Remap the values on the float socket using the MapRange node."""
|
|
1119
|
+
from ..nodes.geometry import MapRange
|
|
1120
|
+
|
|
1121
|
+
node = MapRange.float(self.socket, from_min, from_max, to_min, to_max)
|
|
1122
|
+
node.clamp = clamp
|
|
1123
|
+
node.interpolation_type = interpolation_type
|
|
1124
|
+
if interpolation_type == "STEPPED":
|
|
1125
|
+
node._establish_links(steps=steps)
|
|
1126
|
+
return node.o.result
|
|
1127
|
+
|
|
1128
|
+
def clamp(self, min: InputFloat = 0.0, max: InputFloat = 1.0) -> "FloatSocket":
|
|
1129
|
+
"""Clamp the value to *[min, max]*. Defaults to the unit interval ``[0, 1]``."""
|
|
1130
|
+
from ..nodes.geometry import Clamp
|
|
1131
|
+
|
|
1132
|
+
return Clamp.min_max(self.socket, min, max).o.result
|
|
1133
|
+
|
|
1134
|
+
def sqrt(self) -> "FloatSocket":
|
|
1135
|
+
"""Return the square root of this value."""
|
|
1136
|
+
return self._math.square_root(self.socket).o.value
|
|
1137
|
+
|
|
1138
|
+
def power(self, exponent: InputFloat) -> "FloatSocket":
|
|
1139
|
+
"""Raise this value to *exponent*."""
|
|
1140
|
+
return self._math.power(self.socket, exponent).o.value
|
|
1141
|
+
|
|
1142
|
+
def floor(self) -> "FloatSocket":
|
|
1143
|
+
"""Round down to the nearest integer."""
|
|
1144
|
+
return self._math.floor(self.socket).o.value
|
|
1145
|
+
|
|
1146
|
+
def ceil(self) -> "FloatSocket":
|
|
1147
|
+
"""Round up to the nearest integer."""
|
|
1148
|
+
return self._math.ceil(self.socket).o.value
|
|
1149
|
+
|
|
1150
|
+
def round(self) -> "FloatSocket":
|
|
1151
|
+
"""Round to the nearest integer."""
|
|
1152
|
+
return self._math.round(self.socket).o.value
|
|
1153
|
+
|
|
1154
|
+
def modulo(self, divisor: InputFloat) -> "FloatSocket":
|
|
1155
|
+
"""Floored modulo — remainder after dividing by *divisor*, always non-negative."""
|
|
1156
|
+
return self._math.floored_modulo(self.socket, divisor).o.value
|
|
1157
|
+
|
|
1158
|
+
def wrap(self, min: InputFloat, max: InputFloat) -> "FloatSocket":
|
|
1159
|
+
"""Wrap the value into the *[min, max]* range, repeating cyclically."""
|
|
1160
|
+
# the wrap method has different order of arguments with max being first
|
|
1161
|
+
# compared to other nodes that are defined.
|
|
1162
|
+
return self._math.wrap(self.socket, value_001=max, value_002=min).o.value
|
|
1163
|
+
|
|
1164
|
+
def to_radians(self) -> "FloatSocket":
|
|
1165
|
+
"""Convert degrees to radians."""
|
|
1166
|
+
return self._math.to_radians(self.socket).o.value
|
|
1167
|
+
|
|
1168
|
+
def to_degrees(self) -> "FloatSocket":
|
|
1169
|
+
"""Convert radians to degrees."""
|
|
1170
|
+
return self._math.to_degrees(self.socket).o.value
|
|
1171
|
+
|
|
785
1172
|
def sign(self) -> "FloatSocket":
|
|
786
1173
|
"Return the sign of the FloatSocket, eithe `-1`, `0` or `1`."
|
|
787
1174
|
return self._math.sign(self.socket).o.value
|
|
@@ -796,6 +1183,14 @@ class _FloatMixin(BaseSocket):
|
|
|
796
1183
|
|
|
797
1184
|
return ValueToString.float(self.socket, decimals).o.string
|
|
798
1185
|
|
|
1186
|
+
def to_integer(
|
|
1187
|
+
self, rounding_mode: Literal["ROUND", "FLOOR", "CEILING", "TRUNCATE"] = "ROUND"
|
|
1188
|
+
) -> "IntegerSocket":
|
|
1189
|
+
"Convert the `FloatSocket` to an `IntegerSocket` by truncating the decimal part."
|
|
1190
|
+
from ..nodes.geometry import FloatToInteger
|
|
1191
|
+
|
|
1192
|
+
return FloatToInteger(self.socket, rounding_mode=rounding_mode).o.integer
|
|
1193
|
+
|
|
799
1194
|
|
|
800
1195
|
class _IntegerMixin(BaseSocket):
|
|
801
1196
|
"""Integer-specific dispatch — uses IntegerMath in geometry trees."""
|
|
@@ -812,6 +1207,34 @@ class _IntegerMixin(BaseSocket):
|
|
|
812
1207
|
def default_value(self, value: int) -> None:
|
|
813
1208
|
self.socket.default_value = value
|
|
814
1209
|
|
|
1210
|
+
@property
|
|
1211
|
+
def point(self) -> "_MinMaxDomain[IntegerSocket]":
|
|
1212
|
+
return _MinMaxDomain(self.socket, "integer", "point")
|
|
1213
|
+
|
|
1214
|
+
@property
|
|
1215
|
+
def edge(self) -> "_MinMaxDomain[IntegerSocket]":
|
|
1216
|
+
return _MinMaxDomain(self.socket, "integer", "edge")
|
|
1217
|
+
|
|
1218
|
+
@property
|
|
1219
|
+
def face(self) -> "_MinMaxDomain[IntegerSocket]":
|
|
1220
|
+
return _MinMaxDomain(self.socket, "integer", "face")
|
|
1221
|
+
|
|
1222
|
+
@property
|
|
1223
|
+
def corner(self) -> "_MinMaxDomain[IntegerSocket]":
|
|
1224
|
+
return _MinMaxDomain(self.socket, "integer", "corner")
|
|
1225
|
+
|
|
1226
|
+
@property
|
|
1227
|
+
def spline(self) -> "_MinMaxDomain[IntegerSocket]":
|
|
1228
|
+
return _MinMaxDomain(self.socket, "integer", "spline")
|
|
1229
|
+
|
|
1230
|
+
@property
|
|
1231
|
+
def instance(self) -> "_MinMaxDomain[IntegerSocket]":
|
|
1232
|
+
return _MinMaxDomain(self.socket, "integer", "instance")
|
|
1233
|
+
|
|
1234
|
+
@property
|
|
1235
|
+
def layer(self) -> "_MinMaxDomain[IntegerSocket]":
|
|
1236
|
+
return _MinMaxDomain(self.socket, "integer", "layer")
|
|
1237
|
+
|
|
815
1238
|
@property
|
|
816
1239
|
def _imath(self) -> "type[IntegerMath]":
|
|
817
1240
|
from ..nodes.geometry import IntegerMath
|
|
@@ -824,6 +1247,16 @@ class _IntegerMixin(BaseSocket):
|
|
|
824
1247
|
|
|
825
1248
|
return ValueToString.integer(self.socket).o.string
|
|
826
1249
|
|
|
1250
|
+
def clamp(self, min: InputInteger = 0, max: InputInteger = 1) -> "IntegerSocket":
|
|
1251
|
+
"""Clamp the value to *[min, max]*."""
|
|
1252
|
+
return self._imath.minimum(
|
|
1253
|
+
self._imath.maximum(self.socket, min).o.value, max
|
|
1254
|
+
).o.value
|
|
1255
|
+
|
|
1256
|
+
def modulo(self, divisor: InputInteger) -> "IntegerSocket":
|
|
1257
|
+
"""Remainder after dividing by *divisor* (always non-negative)."""
|
|
1258
|
+
return self._imath.modulo(self.socket, divisor).o.value
|
|
1259
|
+
|
|
827
1260
|
def sign(self) -> "IntegerSocket":
|
|
828
1261
|
"Return the sign of the IntegerSocket, either `-1`, `0`, or `1`."
|
|
829
1262
|
return self._imath.sign(self.socket).o.value
|
|
@@ -894,10 +1327,10 @@ class _IntegerMixin(BaseSocket):
|
|
|
894
1327
|
def __rfloordiv__(self, other: Any) -> "IntegerSocket": ...
|
|
895
1328
|
def __neg__(self) -> "IntegerSocket": ...
|
|
896
1329
|
def __abs__(self) -> "IntegerSocket": ...
|
|
897
|
-
def __lt__(self, other: Any) -> "Compare[
|
|
898
|
-
def __gt__(self, other: Any) -> "Compare[
|
|
899
|
-
def __le__(self, other: Any) -> "Compare[
|
|
900
|
-
def __ge__(self, other: Any) -> "Compare[
|
|
1330
|
+
def __lt__(self, other: Any) -> "Compare[IntegerSocket]": ...
|
|
1331
|
+
def __gt__(self, other: Any) -> "Compare[IntegerSocket]": ...
|
|
1332
|
+
def __le__(self, other: Any) -> "Compare[IntegerSocket]": ...
|
|
1333
|
+
def __ge__(self, other: Any) -> "Compare[IntegerSocket]": ...
|
|
901
1334
|
|
|
902
1335
|
|
|
903
1336
|
class _StringMixin(BaseSocket):
|
|
@@ -959,15 +1392,12 @@ class _StringMixin(BaseSocket):
|
|
|
959
1392
|
|
|
960
1393
|
return StringLength(self.socket).o.length
|
|
961
1394
|
|
|
962
|
-
def find(self, search: InputString) ->
|
|
963
|
-
"
|
|
964
|
-
|
|
965
|
-
Returns a tuple(IntegerSocket, IntegerSocket), corresponding to (index_of_first_match, count_of_matches)."""
|
|
1395
|
+
def find(self, search: InputString) -> FindResult:
|
|
1396
|
+
"Find where in a string a pattern occurs. Returns `(first_found, count)`."
|
|
966
1397
|
from ..nodes.geometry import FindInString
|
|
967
1398
|
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
return (node.o.first_found, node.o.count)
|
|
1399
|
+
o = FindInString(self.socket, search).o
|
|
1400
|
+
return FindResult(o.first_found, o.count)
|
|
971
1401
|
|
|
972
1402
|
def join(
|
|
973
1403
|
self, strings: Iterable[str | "StringSocket" | NodeSocketString | BaseNode]
|
|
@@ -1035,11 +1465,50 @@ class _MatrixMixin(BaseSocket):
|
|
|
1035
1465
|
|
|
1036
1466
|
return TransposeMatrix._find_or_create_linked(self.socket).o.matrix
|
|
1037
1467
|
|
|
1038
|
-
def svd(self) ->
|
|
1039
|
-
"
|
|
1468
|
+
def svd(self) -> SVDResult:
|
|
1469
|
+
"Decompose the matrix via SVD. Returns `(u, s, v)`."
|
|
1040
1470
|
from ..nodes.geometry import MatrixSVD
|
|
1041
1471
|
|
|
1042
|
-
|
|
1472
|
+
o = MatrixSVD(self.socket).o
|
|
1473
|
+
return SVDResult(o.u, o.s, o.v)
|
|
1474
|
+
|
|
1475
|
+
def transform_direction(self, direction: InputVector) -> "VectorSocket":
|
|
1476
|
+
"""Apply this matrix to *direction*, ignoring translation.
|
|
1477
|
+
|
|
1478
|
+
Use this instead of ``transform()`` when transforming a direction vector
|
|
1479
|
+
(e.g. a normal) where translation must not affect the result.
|
|
1480
|
+
"""
|
|
1481
|
+
from ..nodes.geometry import TransformDirection
|
|
1482
|
+
|
|
1483
|
+
return TransformDirection(direction, self.socket).o.direction
|
|
1484
|
+
|
|
1485
|
+
@property
|
|
1486
|
+
def point(self) -> "_FieldDomain[MatrixSocket]":
|
|
1487
|
+
return _FieldDomain(self.socket, "matrix", "point")
|
|
1488
|
+
|
|
1489
|
+
@property
|
|
1490
|
+
def edge(self) -> "_FieldDomain[MatrixSocket]":
|
|
1491
|
+
return _FieldDomain(self.socket, "matrix", "edge")
|
|
1492
|
+
|
|
1493
|
+
@property
|
|
1494
|
+
def face(self) -> "_FieldDomain[MatrixSocket]":
|
|
1495
|
+
return _FieldDomain(self.socket, "matrix", "face")
|
|
1496
|
+
|
|
1497
|
+
@property
|
|
1498
|
+
def corner(self) -> "_FieldDomain[MatrixSocket]":
|
|
1499
|
+
return _FieldDomain(self.socket, "matrix", "corner")
|
|
1500
|
+
|
|
1501
|
+
@property
|
|
1502
|
+
def spline(self) -> "_FieldDomain[MatrixSocket]":
|
|
1503
|
+
return _FieldDomain(self.socket, "matrix", "spline")
|
|
1504
|
+
|
|
1505
|
+
@property
|
|
1506
|
+
def instance(self) -> "_FieldDomain[MatrixSocket]":
|
|
1507
|
+
return _FieldDomain(self.socket, "matrix", "instance")
|
|
1508
|
+
|
|
1509
|
+
@property
|
|
1510
|
+
def layer(self) -> "_FieldDomain[MatrixSocket]":
|
|
1511
|
+
return _FieldDomain(self.socket, "matrix", "layer")
|
|
1043
1512
|
|
|
1044
1513
|
@overload
|
|
1045
1514
|
def __getitem__(self, key: slice) -> "list[FloatSocket]": ...
|
|
@@ -1071,10 +1540,12 @@ class _MatrixMixin(BaseSocket):
|
|
|
1071
1540
|
|
|
1072
1541
|
if self.socket.is_output:
|
|
1073
1542
|
node = SeparateMatrix._find_or_create_linked(self.socket)
|
|
1074
|
-
|
|
1543
|
+
for i in node.o:
|
|
1544
|
+
yield cast(FloatSocket, i)
|
|
1075
1545
|
else:
|
|
1076
1546
|
node = CombineMatrix._find_or_create_linked(self.socket)
|
|
1077
|
-
|
|
1547
|
+
for i in node.i:
|
|
1548
|
+
yield cast(FloatSocket, i)
|
|
1078
1549
|
|
|
1079
1550
|
def __len__(self) -> int:
|
|
1080
1551
|
return 16
|
|
@@ -14,12 +14,10 @@ from ...builder import (
|
|
|
14
14
|
from . import (
|
|
15
15
|
AxesToRotation,
|
|
16
16
|
CombineMatrix,
|
|
17
|
+
Compare,
|
|
17
18
|
EdgesOfVertex,
|
|
18
19
|
EdgeVertices,
|
|
19
|
-
EvaluateAtIndex,
|
|
20
|
-
FieldAverage,
|
|
21
20
|
Frame,
|
|
22
|
-
Switch,
|
|
23
21
|
)
|
|
24
22
|
|
|
25
23
|
|
|
@@ -60,13 +58,15 @@ class OtherVertex(CustomGeometryGroup):
|
|
|
60
58
|
vertex_index = tree.inputs.integer("Vertex Index", default_input="INDEX")
|
|
61
59
|
edge_number = tree.inputs.integer("Edge Number")
|
|
62
60
|
|
|
63
|
-
eov = EdgesOfVertex(vertex_index, sort_index=edge_number)
|
|
61
|
+
eov = EdgesOfVertex(vertex_index, sort_index=edge_number).o.edge_index
|
|
64
62
|
ev = EdgeVertices()
|
|
65
|
-
vert_1 =
|
|
66
|
-
vert_2 =
|
|
67
|
-
|
|
63
|
+
vert_1 = ev.o.vertex_index_1.edge.at(eov)
|
|
64
|
+
vert_2 = ev.o.vertex_index_2.edge.at(eov)
|
|
65
|
+
index = Compare.integer.not_equal(vert_1, vertex_index).o.result.switch.integer(
|
|
66
|
+
vert_1, vert_2
|
|
67
|
+
)
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
index >> tree.outputs.integer("Other Vertex")
|
|
70
70
|
|
|
71
71
|
|
|
72
72
|
class OffsetVector(CustomGeometryGroup):
|
|
@@ -110,7 +110,7 @@ class OffsetVector(CustomGeometryGroup):
|
|
|
110
110
|
vector = tree.inputs.vector("Vector", default_input="POSITION")
|
|
111
111
|
offset = tree.inputs.integer("Offset")
|
|
112
112
|
|
|
113
|
-
value =
|
|
113
|
+
value = vector.point.at(index + offset)
|
|
114
114
|
|
|
115
115
|
_ = value >> tree.outputs.vector("Vector")
|
|
116
116
|
|
|
@@ -177,7 +177,7 @@ class PrincipalComponents(CustomGeometryGroup):
|
|
|
177
177
|
out_short = tree.outputs.vector("Shortest Axis")
|
|
178
178
|
|
|
179
179
|
with Frame("Centroid"):
|
|
180
|
-
centroid =
|
|
180
|
+
centroid = position.point.mean(group_id)
|
|
181
181
|
centroid >> out_centroid
|
|
182
182
|
|
|
183
183
|
with Frame("Covariance Matrix"):
|
|
@@ -185,8 +185,8 @@ class PrincipalComponents(CustomGeometryGroup):
|
|
|
185
185
|
matrix = CombineMatrix()
|
|
186
186
|
|
|
187
187
|
for i, axis1 in enumerate(diff):
|
|
188
|
-
mean =
|
|
189
|
-
for j, axis2 in enumerate(mean
|
|
188
|
+
mean = (diff * axis1).point.mean(group_id)
|
|
189
|
+
for j, axis2 in enumerate(mean):
|
|
190
190
|
axis2 >> matrix.i[int(i * 4 + j)]
|
|
191
191
|
|
|
192
192
|
with Frame("SVD"):
|
|
@@ -14,6 +14,7 @@ from bpy.types import (
|
|
|
14
14
|
)
|
|
15
15
|
|
|
16
16
|
from nodebpy.builder._registry import _get_socket_linker
|
|
17
|
+
from nodebpy.builder.socket import BaseSocket
|
|
17
18
|
|
|
18
19
|
from ...builder import (
|
|
19
20
|
BaseNode,
|
|
@@ -88,7 +89,7 @@ from .zone import (
|
|
|
88
89
|
_sync_closure_items,
|
|
89
90
|
)
|
|
90
91
|
|
|
91
|
-
_T = TypeVar("_T")
|
|
92
|
+
_T = TypeVar("_T", bound=BaseSocket)
|
|
92
93
|
_S = TypeVar("_S")
|
|
93
94
|
|
|
94
95
|
__all__ = (
|
|
@@ -1441,7 +1442,7 @@ class JoinGeometry(BaseNode):
|
|
|
1441
1442
|
|
|
1442
1443
|
def __init__(self, geometry: Iterable[InputGeometry] = ()):
|
|
1443
1444
|
super().__init__()
|
|
1444
|
-
for source in reversed(geometry):
|
|
1445
|
+
for source in reversed(list(geometry)):
|
|
1445
1446
|
assert source
|
|
1446
1447
|
self._link(*self._find_best_socket_pair(source, self))
|
|
1447
1448
|
|
|
@@ -2493,20 +2494,6 @@ class FieldAverage(BaseNode, Generic[_T]):
|
|
|
2493
2494
|
instance = _FieldAverageDomainFactory("INSTANCE")
|
|
2494
2495
|
layer = _FieldAverageDomainFactory("LAYER")
|
|
2495
2496
|
|
|
2496
|
-
def __init__(
|
|
2497
|
-
self,
|
|
2498
|
-
value: InputFloat | InputVector = None,
|
|
2499
|
-
group_index: InputFloat | InputVector = 0,
|
|
2500
|
-
*,
|
|
2501
|
-
data_type: Literal["FLOAT", "FLOAT_VECTOR"] = "FLOAT",
|
|
2502
|
-
domain: _AttributeDomains = "POINT",
|
|
2503
|
-
):
|
|
2504
|
-
super().__init__()
|
|
2505
|
-
key_args = {"Value": value, "Group Index": group_index}
|
|
2506
|
-
self.data_type = data_type
|
|
2507
|
-
self.domain = domain
|
|
2508
|
-
self._establish_links(**key_args)
|
|
2509
|
-
|
|
2510
2497
|
class _Inputs(SocketAccessor, Generic[_S]):
|
|
2511
2498
|
value: _S
|
|
2512
2499
|
"""The field value to average."""
|
|
@@ -2527,6 +2514,20 @@ class FieldAverage(BaseNode, Generic[_T]):
|
|
|
2527
2514
|
@property
|
|
2528
2515
|
def o(self) -> "_Outputs[_T]": ...
|
|
2529
2516
|
|
|
2517
|
+
def __init__(
|
|
2518
|
+
self,
|
|
2519
|
+
value: InputFloat | InputVector = None,
|
|
2520
|
+
group_index: InputFloat | InputVector = 0,
|
|
2521
|
+
*,
|
|
2522
|
+
data_type: Literal["FLOAT", "FLOAT_VECTOR"] = "FLOAT",
|
|
2523
|
+
domain: _AttributeDomains = "POINT",
|
|
2524
|
+
):
|
|
2525
|
+
super().__init__()
|
|
2526
|
+
key_args = {"Value": value, "Group Index": group_index}
|
|
2527
|
+
self.data_type = data_type
|
|
2528
|
+
self.domain = domain
|
|
2529
|
+
self._establish_links(**key_args)
|
|
2530
|
+
|
|
2530
2531
|
@property
|
|
2531
2532
|
def data_type(self) -> Literal["FLOAT", "FLOAT_VECTOR"]:
|
|
2532
2533
|
return self.node.data_type
|
|
@@ -2597,20 +2598,6 @@ class FieldMinAndMax(BaseNode, Generic[_T]):
|
|
|
2597
2598
|
instance = _FieldMinAndMaxDomainFactory("INSTANCE")
|
|
2598
2599
|
layer = _FieldMinAndMaxDomainFactory("LAYER")
|
|
2599
2600
|
|
|
2600
|
-
def __init__(
|
|
2601
|
-
self,
|
|
2602
|
-
value: InputFloat | InputVector | InputInteger = 1.0,
|
|
2603
|
-
group_index: InputInteger = 0,
|
|
2604
|
-
*,
|
|
2605
|
-
data_type: Literal["FLOAT", "INT", "FLOAT_VECTOR"] = "FLOAT",
|
|
2606
|
-
domain: _AttributeDomains = "POINT",
|
|
2607
|
-
):
|
|
2608
|
-
super().__init__()
|
|
2609
|
-
key_args = {"Value": value, "Group Index": group_index}
|
|
2610
|
-
self.data_type = data_type
|
|
2611
|
-
self.domain = domain
|
|
2612
|
-
self._establish_links(**key_args)
|
|
2613
|
-
|
|
2614
2601
|
class _Inputs(SocketAccessor, Generic[_S]):
|
|
2615
2602
|
value: _S
|
|
2616
2603
|
"""The field value to find the min/max of."""
|
|
@@ -2631,6 +2618,20 @@ class FieldMinAndMax(BaseNode, Generic[_T]):
|
|
|
2631
2618
|
@property
|
|
2632
2619
|
def o(self) -> "_Outputs[_T]": ...
|
|
2633
2620
|
|
|
2621
|
+
def __init__(
|
|
2622
|
+
self,
|
|
2623
|
+
value: InputFloat | InputVector | InputInteger = 1.0,
|
|
2624
|
+
group_index: InputInteger = 0,
|
|
2625
|
+
*,
|
|
2626
|
+
data_type: Literal["FLOAT", "INT", "FLOAT_VECTOR"] = "FLOAT",
|
|
2627
|
+
domain: _AttributeDomains = "POINT",
|
|
2628
|
+
):
|
|
2629
|
+
super().__init__()
|
|
2630
|
+
key_args = {"Value": value, "Group Index": group_index}
|
|
2631
|
+
self.data_type = data_type
|
|
2632
|
+
self.domain = domain
|
|
2633
|
+
self._establish_links(**key_args)
|
|
2634
|
+
|
|
2634
2635
|
@property
|
|
2635
2636
|
def data_type(self) -> Literal["FLOAT", "INT", "FLOAT_VECTOR"]:
|
|
2636
2637
|
return self.node.data_type
|
|
@@ -2681,7 +2682,7 @@ class EvaluateOnDomain(BaseNode, Generic[_T]):
|
|
|
2681
2682
|
value, domain=self._domain, data_type="FLOAT_VECTOR"
|
|
2682
2683
|
)
|
|
2683
2684
|
|
|
2684
|
-
def
|
|
2685
|
+
def quaternion(
|
|
2685
2686
|
self, value: InputRotation = None
|
|
2686
2687
|
) -> "EvaluateOnDomain[RotationSocket]":
|
|
2687
2688
|
return EvaluateOnDomain(value, domain=self._domain, data_type="QUATERNION")
|
|
@@ -100,7 +100,7 @@ InputColor = typing.Union[
|
|
|
100
100
|
InputLinkable,
|
|
101
101
|
"ColorSocket",
|
|
102
102
|
]
|
|
103
|
-
InputString = typing.Union[str, NodeSocketString, EllipsisType, "StringSocket"]
|
|
103
|
+
InputString = typing.Union[None, str, NodeSocketString, EllipsisType, "StringSocket"]
|
|
104
104
|
InputGeometry = typing.Union[NodeSocketGeometry, InputLinkable, "GeometrySocket"]
|
|
105
105
|
InputObject = typing.Union[NodeSocketObject, Object, InputLinkable, "ObjectSocket"]
|
|
106
106
|
InputMaterial = typing.Union[
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|