149 lines
5.9 KiB
Python
149 lines
5.9 KiB
Python
from __future__ import annotations
|
|
from typing import Any, TypeAlias
|
|
import bpy
|
|
import numpy as np
|
|
|
|
from ..bpy_ns_types import NfIntProperty, NfStringProperty, NfEnumProperty, NfBoolProperty, notify_tree_changed
|
|
|
|
from ....registry import register_class
|
|
from ... import slice
|
|
from ...slice import Pather, slice_at_range, SlicePaths
|
|
from ....infra.blender.blender_mesh_capture import SlicingCollection, SlicingObject, capture_mesh_edges, SlicingGroup
|
|
from ....infra.blender.blender_bridge import get_all_children
|
|
from ....infra.blender.blender_slice_nodes_generic import SliceNode, resolve_input
|
|
|
|
class SliceIntrinsics:
|
|
bed_x: float
|
|
bed_y: float
|
|
feedrate: float
|
|
travel_feedrate: float
|
|
extrusion_rate: float
|
|
retraction: float
|
|
lift: float
|
|
retraction_feedrate: float
|
|
|
|
def __init__(self, bed_x: float = 250.0, bed_y: float = 250.0, feedrate: float = 1200.0, travel_feedrate: float = 2400.0, extrusion_rate: float = 0.017, retraction: float = 0.0, lift: float = 0.0, retraction_feedrate: float = 0.0):
|
|
self.bed_x = bed_x
|
|
self.bed_y = bed_y
|
|
self.feedrate = feedrate
|
|
self.travel_feedrate = travel_feedrate
|
|
self.extrusion_rate = extrusion_rate
|
|
self.retraction = retraction
|
|
self.lift = lift
|
|
self.retraction_feedrate = retraction_feedrate
|
|
|
|
class InputNode(SliceNode):
|
|
input_type: str = ""
|
|
socket_type: str = ""
|
|
|
|
def __init_subclass__(cls, **kwargs):
|
|
super().__init_subclass__(**kwargs)
|
|
if "bl_label" not in cls.__dict__: cls.bl_label = cls.input_type
|
|
|
|
def init(self, context) -> None:
|
|
stype = self.socket_type or (f"NodeSocket{self.bl_label}" if not self.bl_label.startswith("NodeSocket") else self.bl_label)
|
|
self.add_output(stype)
|
|
|
|
def draw_buttons(self, context, layout):
|
|
assert layout
|
|
if self.outputs:
|
|
sock = self.outputs[0]
|
|
if hasattr(sock, "default_value"):
|
|
layout.prop(sock, "default_value", text="")
|
|
elif hasattr(sock, "value"):
|
|
layout.prop(sock, "value", text="")
|
|
|
|
def evaluate_output(self, socket_name: str, **_kwargs):
|
|
out = self.outputs.get(socket_name) or (self.outputs[0] if self.outputs else None)
|
|
if out is None: return None
|
|
return getattr(out, "value", getattr(out, "default_value", None))
|
|
|
|
class MathNode(SliceNode):
|
|
bl_label = "Float Math"
|
|
|
|
operation: NfEnumProperty(
|
|
name="Operation",
|
|
items=[
|
|
('ADD', "Add", "Add the two values"),
|
|
('SUBTRACT', "Subtract", "Subtract the second value from the first"),
|
|
('MULTIPLY', "Multiply", "Multiply the two values"),
|
|
('DIVIDE', "Divide", "Division"),
|
|
('ABS', "Absolute", "Absolute value of the first value"),
|
|
('NEGATE', "Negate", "Negate the first value"),
|
|
('POWER', "Power", "First value raised to the power of the second"),
|
|
('MIN', "Minimum", "The smaller of the two values"),
|
|
('MAX', "Maximum", "The larger of the two values"),
|
|
('SIGN', "Sign", "The sign of the first value (-1, 0, or 1)"),
|
|
('DIVIDE_ROUND', "Divide Round", "Division rounded to the nearest integer"),
|
|
('DIVIDE_FLOOR', "Divide Floor", "Division rounded down"),
|
|
('DIVIDE_TRUNCATE', "Divide Truncate", "Division rounded towards zero"),
|
|
('MODULO_FLOORED', "Floored Modulo", "Modulo using floor division"),
|
|
('MODULO_TRUNCATED', "Truncated Modulo", "Modulo using truncated division"),
|
|
],
|
|
default='ADD'
|
|
) # pyright: ignore[reportInvalidTypeForm]
|
|
|
|
math_type: TypeAlias = float
|
|
socket_label: str = "Float"
|
|
socket_type: str = "NodeSocketFloat"
|
|
|
|
def init(self, context):
|
|
self.add_output(self.socket_type, "Value")
|
|
|
|
self.add_input(self.socket_type, "Value")
|
|
self.add_input(self.socket_type, "Value")
|
|
|
|
def draw_buttons(self, context, layout):
|
|
assert layout
|
|
layout.prop(self, "operation", text="")
|
|
|
|
def evaluate_output(self, socket_name: str, **_kwargs) -> math_type:
|
|
t = self.math_type
|
|
|
|
a: t = resolve_input(self.inputs[0]) or 0
|
|
b: t = resolve_input(self.inputs[1]) or 0
|
|
|
|
op = self.operation
|
|
try:
|
|
if op == 'ADD': return a + b
|
|
if op == 'SUBTRACT': return a - b
|
|
if op == 'MULTIPLY': return a * b
|
|
if op == 'DIVIDE': return a // b if b != 0 else 0
|
|
if op == 'ABS': return abs(a)
|
|
if op == 'NEGATE': return -a
|
|
if op == 'POWER': return t(a ** b) if not (a == 0 and b < 0) else 0
|
|
if op == 'MIN': return min(a, b)
|
|
if op == 'MAX': return max(a, b)
|
|
if op == 'SIGN': return (a > 0) - (a < 0)
|
|
if op == 'DIVIDE_ROUND': return t(round(a / b)) if b != 0 else 0
|
|
if op == 'DIVIDE_FLOOR': return a // b if b != 0 else 0
|
|
if op == 'DIVIDE_TRUNCATE': return t(a / b) if b != 0 else 0
|
|
if op == 'MODULO_FLOORED': return a % b if b != 0 else 0
|
|
if op == 'MODULO_TRUNCATED': return a - (b * t(a / b)) if b != 0 else 0
|
|
except Exception:
|
|
return 0
|
|
return 0
|
|
|
|
class SliceNodeJoiner(SliceNode):
|
|
socket_type: str = ""
|
|
output_socket_type: str = ""
|
|
socket_label: str = ""
|
|
|
|
def init(self, context):
|
|
self.add_output(self.output_socket_type or self.socket_type, name=self.socket_label)
|
|
self.add_multi_socket_group(self.socket_type, name=self.socket_label)
|
|
|
|
class ExecSliceNode(SliceNode):
|
|
button_label: str = 'Execute'
|
|
|
|
def _init_exec(self):
|
|
self.add_output("SLICESOCK_ExecutionLink")
|
|
|
|
def draw_buttons(self, context, layout):
|
|
assert layout
|
|
layout.operator("slicenode.execute", text=self.button_label).node_name = self.name
|
|
|
|
def evaluate_output(self, socket_name: str, **_kwargs) -> Any:
|
|
if socket_name == "Execution Link":
|
|
return self
|
|
return None
|