buffer non planar, merge paths with zip
This commit is contained in:
parent
af96629b76
commit
c57f843092
2 changed files with 67 additions and 8 deletions
65
__init__.py
65
__init__.py
|
|
@ -13,10 +13,12 @@ bl_info = {
|
|||
}
|
||||
|
||||
from math import floor
|
||||
from itertools import zip_longest
|
||||
from typing import TYPE_CHECKING, Any
|
||||
import bpy
|
||||
import os
|
||||
import numpy as np
|
||||
from mathutils import Euler, Matrix
|
||||
|
||||
from bpy.types import NodeTree, Operator, Menu
|
||||
from bpy.props import PointerProperty, StringProperty, FloatProperty, IntProperty
|
||||
|
|
@ -110,6 +112,13 @@ class SLICESOCK_String(InputNodeSocket):
|
|||
value: StringProperty(name="String", default="") # pyright: ignore[reportInvalidTypeForm]
|
||||
color = (0.4, 0.7, 1.0, 1.0)
|
||||
|
||||
@register_class
|
||||
class SLICESOCK_Vector(InputNodeSocket):
|
||||
bl_label = "Vector"
|
||||
|
||||
value: bpy.props.FloatVectorProperty(name="Vector", size=3, default=(0.0, 0.0, 0.0), subtype='EULER') # pyright: ignore[reportInvalidTypeForm]
|
||||
color = (0.39, 0.39, 0.78, 1.0)
|
||||
|
||||
@register_class
|
||||
class SLICESOCK_Mesh(LabelNodeSocket):
|
||||
bl_label = "Mesh"
|
||||
|
|
@ -310,6 +319,7 @@ class SLICENODE_BufferShells(SliceNode):
|
|||
def init(self, context):
|
||||
self.add_input("SLICESOCK_Slices")
|
||||
self.add_input("SLICESOCK_Float", "Distance").value = 0
|
||||
self.add_input("SLICESOCK_Vector", "Rotation")
|
||||
self.add_output("SLICESOCK_Slices")
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
|
|
@ -320,7 +330,25 @@ class SLICENODE_BufferShells(SliceNode):
|
|||
if socket_name != "Slices": return []
|
||||
|
||||
slices: list[np.ndarray] = resolve_input(self.inputs.get("Slices"))
|
||||
distance: float = resolve_input(self.inputs.get("Distance"))
|
||||
distance: float = resolve_input(self.inputs.get("Distance")) or 0.0
|
||||
rotation: Any = resolve_input(self.inputs.get("Rotation")) or (0.0, 0.0, 0.0)
|
||||
|
||||
if not slices: return []
|
||||
|
||||
if any(rotation):
|
||||
# De-rotate shells to Z-perpendicular plane
|
||||
mat = Euler(rotation).to_matrix().inverted()
|
||||
mat_np = np.array(mat)
|
||||
de_rotated_slices = [s @ mat_np.T for s in slices]
|
||||
|
||||
# Buffer
|
||||
buffered_slices = slice.buffer_slice(de_rotated_slices, distance, miter=self.shape_option)
|
||||
|
||||
# Re-rotate shells back
|
||||
mat_inv = Euler(rotation).to_matrix()
|
||||
mat_inv_np = np.array(mat_inv)
|
||||
re_rotated_slices = [s @ mat_inv_np.T for s in buffered_slices]
|
||||
return re_rotated_slices
|
||||
|
||||
buffered_slices = slice.buffer_slice(slices, distance, miter=self.shape_option)
|
||||
|
||||
|
|
@ -466,16 +494,45 @@ class SLICENODE_JoinPaths(SliceNodeJoiner):
|
|||
bl_label = "Join Paths"
|
||||
socket_type = "SLICESOCK_Paths"
|
||||
|
||||
def evaluate_output(self, socket_name: str, **_kwargs) -> list[np.ndarray]:
|
||||
merged_paths = []
|
||||
mode: bpy.props.EnumProperty(
|
||||
name="Mode",
|
||||
items=[
|
||||
('EXTEND', "Extend", "Append paths sequentially"),
|
||||
('ZIP', "Zip", "Interleave paths from all inputs"),
|
||||
],
|
||||
default='EXTEND'
|
||||
) # pyright: ignore[reportInvalidTypeForm]
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
assert layout
|
||||
layout.prop(self, "mode", text="")
|
||||
|
||||
def evaluate_output(self, socket_name: str, **_kwargs) -> list[np.ndarray]:
|
||||
inputs_data: list[list[np.ndarray]] = []
|
||||
for input in self.inputs:
|
||||
paths = resolve_input(input)
|
||||
if paths:
|
||||
merged_paths.extend(paths)
|
||||
inputs_data.append(paths)
|
||||
|
||||
if not inputs_data:
|
||||
return []
|
||||
|
||||
if self.mode == 'EXTEND':
|
||||
merged_paths = []
|
||||
for paths in inputs_data:
|
||||
merged_paths.extend(paths)
|
||||
return merged_paths
|
||||
|
||||
elif self.mode == 'ZIP':
|
||||
merged_paths = []
|
||||
for group in zip_longest(*inputs_data):
|
||||
for path in group:
|
||||
if path is not None:
|
||||
merged_paths.append(path)
|
||||
return merged_paths
|
||||
|
||||
return []
|
||||
|
||||
### I/O
|
||||
|
||||
@register_class
|
||||
|
|
|
|||
|
|
@ -68,8 +68,10 @@ def resolve_input(
|
|||
assert socket.node
|
||||
|
||||
if not socket.is_linked:
|
||||
if v := getattr(socket, "value", None): return v
|
||||
else: return socket.default
|
||||
val = getattr(socket, "value", None)
|
||||
if val is not None:
|
||||
return val
|
||||
return socket.default
|
||||
|
||||
assert socket.is_linked
|
||||
assert socket.links
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue