feat: More sockets, nodes, fixes.

We're starting to have a very advanced socket-based language
for defining nodes. It's very practical already.

The priorities are
1. All the nodes!
2. Sockets, including default values, as needed.
3. Library constants, mediums.
4. Output socket previews w/geonodes, geonodes structures.
5. Utilities including arrays (and selected array multi-input)

The code is still very spaghetti. This is very much still the
"first, make it run" part of the system design.
blender-plugin-mvp
Sofus Albert Høgsbro Rose 2024-02-19 18:36:16 +01:00
parent 586d6fa74b
commit 7344913c0e
Signed by: so-rose
GPG Key ID: AD901CB0F3701434
31 changed files with 753 additions and 206 deletions

View File

@ -79,6 +79,7 @@ class TreeType(BlenderTypeEnum):
class SocketType(BlenderTypeEnum): class SocketType(BlenderTypeEnum):
# Base # Base
Any = enum.auto() Any = enum.auto()
Bool = enum.auto()
Text = enum.auto() Text = enum.auto()
FilePath = enum.auto() FilePath = enum.auto()
@ -104,11 +105,19 @@ class SocketType(BlenderTypeEnum):
PhysicalArea = enum.auto() PhysicalArea = enum.auto()
PhysicalVolume = enum.auto() PhysicalVolume = enum.auto()
PhysicalPoint2D = enum.auto()
PhysicalPoint3D = enum.auto()
PhysicalSize2D = enum.auto()
PhysicalSize3D = enum.auto()
PhysicalMass = enum.auto() PhysicalMass = enum.auto()
PhysicalSpeed = enum.auto() PhysicalSpeed = enum.auto()
PhysicalAccel = enum.auto() PhysicalAccelScalar = enum.auto()
PhysicalForce = enum.auto() PhysicalForceScalar = enum.auto()
PhysicalAccel3DVector = enum.auto()
PhysicalForce3DVector = enum.auto()
PhysicalPol = enum.auto() PhysicalPol = enum.auto()
@ -220,6 +229,72 @@ SocketType_to_units = {
}, },
}, },
SocketType.PhysicalPoint2D: {
"default": "UM",
"values": {
"PM": spu.picometer,
"A": spu.angstrom,
"NM": spu.nanometer,
"UM": spu.micrometer,
"MM": spu.millimeter,
"CM": spu.centimeter,
"M": spu.meter,
"INCH": spu.inch,
"FOOT": spu.foot,
"YARD": spu.yard,
"MILE": spu.mile,
},
},
SocketType.PhysicalPoint3D: {
"default": "UM",
"values": {
"PM": spu.picometer,
"A": spu.angstrom,
"NM": spu.nanometer,
"UM": spu.micrometer,
"MM": spu.millimeter,
"CM": spu.centimeter,
"M": spu.meter,
"INCH": spu.inch,
"FOOT": spu.foot,
"YARD": spu.yard,
"MILE": spu.mile,
},
},
SocketType.PhysicalSize2D: {
"default": "UM",
"values": {
"PM": spu.picometer,
"A": spu.angstrom,
"NM": spu.nanometer,
"UM": spu.micrometer,
"MM": spu.millimeter,
"CM": spu.centimeter,
"M": spu.meter,
"INCH": spu.inch,
"FOOT": spu.foot,
"YARD": spu.yard,
"MILE": spu.mile,
},
},
SocketType.PhysicalSize3D: {
"default": "UM",
"values": {
"PM": spu.picometer,
"A": spu.angstrom,
"NM": spu.nanometer,
"UM": spu.micrometer,
"MM": spu.millimeter,
"CM": spu.centimeter,
"M": spu.meter,
"INCH": spu.inch,
"FOOT": spu.foot,
"YARD": spu.yard,
"MILE": spu.mile,
},
},
SocketType.PhysicalMass: { SocketType.PhysicalMass: {
"default": "UG", "default": "UG",
"values": { "values": {
@ -247,7 +322,7 @@ SocketType_to_units = {
"MI_H": spu.mile / spu.hour, "MI_H": spu.mile / spu.hour,
}, },
}, },
SocketType.PhysicalAccel: { SocketType.PhysicalAccelScalar: {
"default": "UM_S_SQ", "default": "UM_S_SQ",
"values": { "values": {
"PM_S_SQ": spu.picometer / spu.second**2, "PM_S_SQ": spu.picometer / spu.second**2,
@ -259,7 +334,29 @@ SocketType_to_units = {
"FT_S_SQ": spu.feet / spu.second**2, "FT_S_SQ": spu.feet / spu.second**2,
}, },
}, },
SocketType.PhysicalForce: { SocketType.PhysicalForceScalar: {
"default": "UNEWT",
"values": {
"KG_M_S_SQ": spu.kg * spu.m/spu.second**2,
"NNEWT": spuex.nanonewton,
"UNEWT": spuex.micronewton,
"MNEWT": spuex.millinewton,
"NEWT": spu.newton,
},
},
SocketType.PhysicalAccel3DVector: {
"default": "UM_S_SQ",
"values": {
"PM_S_SQ": spu.picometer / spu.second**2,
"NM_S_SQ": spu.nanometer / spu.second**2,
"UM_S_SQ": spu.micrometer / spu.second**2,
"MM_S_SQ": spu.millimeter / spu.second**2,
"M_S_SQ": spu.meter / spu.second**2,
"KM_S_SQ": spu.kilometer / spu.second**2,
"FT_S_SQ": spu.feet / spu.second**2,
},
},
SocketType.PhysicalForce3DVector: {
"default": "UNEWT", "default": "UNEWT",
"values": { "values": {
"KG_M_S_SQ": spu.kg * spu.m/spu.second**2, "KG_M_S_SQ": spu.kg * spu.m/spu.second**2,
@ -294,6 +391,7 @@ SocketType_to_units = {
SocketType_to_color = { SocketType_to_color = {
# Basic # Basic
SocketType.Any: (0.8, 0.8, 0.8, 1.0), # Light Grey SocketType.Any: (0.8, 0.8, 0.8, 1.0), # Light Grey
SocketType.Bool: (0.7, 0.7, 0.7, 1.0), # Medium Light Grey
SocketType.Text: (0.7, 0.7, 0.7, 1.0), # Medium Light Grey SocketType.Text: (0.7, 0.7, 0.7, 1.0), # Medium Light Grey
SocketType.FilePath: (0.6, 0.6, 0.6, 1.0), # Medium Grey SocketType.FilePath: (0.6, 0.6, 0.6, 1.0), # Medium Grey
@ -315,10 +413,16 @@ SocketType_to_color = {
SocketType.PhysicalLength: (0.8, 0.4, 0.4, 1.0), # Medium Red SocketType.PhysicalLength: (0.8, 0.4, 0.4, 1.0), # Medium Red
SocketType.PhysicalArea: (0.7, 0.35, 0.35, 1.0), # Medium Dark Red SocketType.PhysicalArea: (0.7, 0.35, 0.35, 1.0), # Medium Dark Red
SocketType.PhysicalVolume: (0.6, 0.3, 0.3, 1.0), # Dark Red SocketType.PhysicalVolume: (0.6, 0.3, 0.3, 1.0), # Dark Red
SocketType.PhysicalPoint2D: (0.7, 0.35, 0.35, 1.0), # Medium Dark Red
SocketType.PhysicalPoint3D: (0.6, 0.3, 0.3, 1.0), # Dark Red
SocketType.PhysicalSize2D: (0.7, 0.35, 0.35, 1.0), # Medium Dark Red
SocketType.PhysicalSize3D: (0.6, 0.3, 0.3, 1.0), # Dark Red
SocketType.PhysicalMass: (0.9, 0.6, 0.4, 1.0), # Light Orange SocketType.PhysicalMass: (0.9, 0.6, 0.4, 1.0), # Light Orange
SocketType.PhysicalSpeed: (0.8, 0.55, 0.35, 1.0), # Medium Light Orange SocketType.PhysicalSpeed: (0.8, 0.55, 0.35, 1.0), # Medium Light Orange
SocketType.PhysicalAccel: (0.7, 0.5, 0.3, 1.0), # Medium Orange SocketType.PhysicalAccelScalar: (0.7, 0.5, 0.3, 1.0), # Medium Orange
SocketType.PhysicalForce: (0.6, 0.45, 0.25, 1.0), # Medium Dark Orange SocketType.PhysicalForceScalar: (0.6, 0.45, 0.25, 1.0), # Medium Dark Orange
SocketType.PhysicalAccel3DVector: (0.7, 0.5, 0.3, 1.0), # Medium Orange
SocketType.PhysicalForce3DVector: (0.6, 0.45, 0.25, 1.0), # Medium Dark Orange
SocketType.PhysicalPol: (0.5, 0.4, 0.2, 1.0), # Dark Orange SocketType.PhysicalPol: (0.5, 0.4, 0.2, 1.0), # Dark Orange
SocketType.PhysicalFreq: (1.0, 0.7, 0.5, 1.0), # Light Peach SocketType.PhysicalFreq: (1.0, 0.7, 0.5, 1.0), # Light Peach
SocketType.PhysicalSpecPowerDist: (0.9, 0.65, 0.45, 1.0), # Medium Light Peach SocketType.PhysicalSpecPowerDist: (0.9, 0.65, 0.45, 1.0), # Medium Light Peach

View File

@ -371,12 +371,23 @@ class MaxwellSimTreeNode(bpy.types.Node):
Blender's own node socket object. Blender's own node socket object.
""" """
# (Guard) Socket Exists if input_socket_name in self.input_sockets:
if input_socket_name not in self.input_sockets: # Check Nicely that it Exists
msg = f"Input socket with name {input_socket_name} does not exist" if input_socket_name not in self.input_sockets:
raise ValueError(msg) msg = f"Input socket with name {input_socket_name} does not exist"
raise ValueError(msg)
return self.inputs[self.input_sockets[input_socket_name].label]
return self.inputs[self.input_sockets[input_socket_name].label] elif hasattr(self, "input_socket_sets"):
# You're on your own, chump
return self.inputs[next(
socket_def.label
for socket_set, socket_dict in self.input_socket_sets.items()
for socket_name, socket_def in socket_dict.items()
if socket_name == input_socket_name
)]
def g_output_bl_socket( def g_output_bl_socket(
self, self,
@ -392,17 +403,35 @@ class MaxwellSimTreeNode(bpy.types.Node):
Blender's own node socket object. Blender's own node socket object.
""" """
# (Guard) Socket Exists
if output_socket_name not in self.output_sockets:
msg = f"Input socket with name {output_socket_name} does not exist"
raise ValueError(msg)
return self.outputs[self.output_sockets[output_socket_name].label] if output_socket_name in self.output_sockets:
# (Guard) Socket Exists
if output_socket_name not in self.output_sockets:
msg = f"Input socket with name {output_socket_name} does not exist"
raise ValueError(msg)
return self.outputs[self.output_sockets[output_socket_name].label]
elif hasattr(self, "input_socket_sets"):
return self.outputs[next(
socket_def.label
for socket_set, socket_dict in self.input_socket_sets.items()
for socket_name, socket_def in socket_dict.items()
if socket_name == output_socket_name
)]
def g_output_socket_name( def g_output_socket_name(
self, self,
output_bl_socket_name: contracts.BLSocketName, output_bl_socket_name: contracts.BLSocketName,
) -> contracts.SocketName: ) -> contracts.SocketName:
if hasattr(self, "output_socket_sets"):
return next(
socket_name
for socket_set, socket_dict in self.output_socket_sets.items()
for socket_name, socket_def in socket_dict.items()
if socket_def.label == output_bl_socket_name
)
else:
return next( return next(
output_socket_name output_socket_name
for output_socket_name in self.output_sockets.keys() for output_socket_name in self.output_sockets.keys()

View File

@ -11,16 +11,21 @@ class NumberConstantNode(base.MaxwellSimTreeNode):
bl_label = "Numerical Constant" bl_label = "Numerical Constant"
#bl_icon = constants.ICON_SIM_INPUT #bl_icon = constants.ICON_SIM_INPUT
input_sockets = { input_sockets = {}
"value": sockets.ComplexNumberSocketDef( input_socket_sets = {
label="Complex", "real": {
), ## TODO: Dynamic number socket! "value": sockets.RealNumberSocketDef(
} label="Real",
output_sockets = { ),
"value": sockets.ComplexNumberSocketDef( },
label="Complex", "complex": {
), ## TODO: Dynamic number socket! "value": sockets.ComplexNumberSocketDef(
label="Complex",
),
},
} }
output_sockets = {}
output_socket_sets = input_socket_sets
#################### ####################
# - Callbacks # - Callbacks

View File

@ -1,5 +1,75 @@
import bpy
import sympy as sp
from .... import contracts
from .... import sockets
from ... import base
class PhysicalConstantNode(base.MaxwellSimTreeNode):
node_type = contracts.NodeType.PhysicalConstant
bl_label = "Physical Constant"
#bl_icon = constants.ICON_SIM_INPUT
input_sockets = {}
input_socket_sets = {
"time": {
"value": sockets.PhysicalTimeSocketDef(
label="Time",
),
},
"angle": {
"value": sockets.PhysicalAngleSocketDef(
label="Angle",
),
},
"length": {
"value": sockets.PhysicalLengthSocketDef(
label="Length",
),
},
"area": {
"value": sockets.PhysicalAreaSocketDef(
label="Area",
),
},
"volume": {
"value": sockets.PhysicalVolumeSocketDef(
label="Volume",
),
},
"point_3d": {
"value": sockets.PhysicalPoint3DSocketDef(
label="3D Point",
),
},
"size_3d": {
"value": sockets.PhysicalSize3DSocketDef(
label="3D Size",
),
},
## I got bored so maybe the rest later
}
output_sockets = {}
output_socket_sets = input_socket_sets
####################
# - Callbacks
####################
@base.computes_output_socket("value")
def compute_value(self: contracts.NodeTypeProtocol) -> sp.Expr:
return self.compute_input("value")
#################### ####################
# - Blender Registration # - Blender Registration
#################### ####################
BL_REGISTER = [] BL_REGISTER = [
BL_NODES = {} PhysicalConstantNode,
]
BL_NODES = {
contracts.NodeType.PhysicalConstant: (
contracts.NodeCategory.MAXWELLSIM_INPUTS_CONSTANTS
)
}

View File

@ -19,6 +19,7 @@ class KitchenSinkNode(base.MaxwellSimTreeNode):
input_socket_sets = { input_socket_sets = {
"basic": { "basic": {
"basic_any": sockets.AnySocketDef(label="Any"), "basic_any": sockets.AnySocketDef(label="Any"),
"basic_bool": sockets.BoolSocketDef(label="Bool"),
"basic_filepath": sockets.FilePathSocketDef(label="FilePath"), "basic_filepath": sockets.FilePathSocketDef(label="FilePath"),
"basic_text": sockets.TextSocketDef(label="Text"), "basic_text": sockets.TextSocketDef(label="Text"),
}, },
@ -36,14 +37,20 @@ class KitchenSinkNode(base.MaxwellSimTreeNode):
}, },
"physical": { "physical": {
"physical_time": sockets.PhysicalTimeSocketDef(label="PhysicalTime"), "physical_time": sockets.PhysicalTimeSocketDef(label="PhysicalTime"),
#"physical_point_2d": sockets.PhysicalPoint2DSocketDef(label="PhysicalPoint2D"),
"physical_angle": sockets.PhysicalAngleSocketDef(label="PhysicalAngle"), "physical_angle": sockets.PhysicalAngleSocketDef(label="PhysicalAngle"),
"physical_length": sockets.PhysicalLengthSocketDef(label="PhysicalLength"), "physical_length": sockets.PhysicalLengthSocketDef(label="PhysicalLength"),
"physical_area": sockets.PhysicalAreaSocketDef(label="PhysicalArea"), "physical_area": sockets.PhysicalAreaSocketDef(label="PhysicalArea"),
"physical_volume": sockets.PhysicalVolumeSocketDef(label="PhysicalVolume"), "physical_volume": sockets.PhysicalVolumeSocketDef(label="PhysicalVolume"),
"physical_point_3d": sockets.PhysicalPoint3DSocketDef(label="PhysicalPoint3D"),
#"physical_size_2d": sockets.PhysicalSize2DSocketDef(label="PhysicalSize2D"),
"physical_size_3d": sockets.PhysicalSize3DSocketDef(label="PhysicalSize3D"),
"physical_mass": sockets.PhysicalMassSocketDef(label="PhysicalMass"), "physical_mass": sockets.PhysicalMassSocketDef(label="PhysicalMass"),
"physical_speed": sockets.PhysicalSpeedSocketDef(label="PhysicalSpeed"), "physical_speed": sockets.PhysicalSpeedSocketDef(label="PhysicalSpeed"),
"physical_accel": sockets.PhysicalAccelSocketDef(label="PhysicalAccel"), "physical_accel_scalar": sockets.PhysicalAccelScalarSocketDef(label="PhysicalAccelScalar"),
"physical_force": sockets.PhysicalForceSocketDef(label="PhysicalForce"), "physical_force_scalar": sockets.PhysicalForceScalarSocketDef(label="PhysicalForceScalar"),
#"physical_accel_3dvector": sockets.PhysicalAccel3DVectorSocketDef(label="PhysicalAccel3DVector"),
#"physical_force_3dvector": sockets.PhysicalForce3DVectorSocketDef(label="PhysicalForce3DVector"),
"physical_pol": sockets.PhysicalPolSocketDef(label="PhysicalPol"), "physical_pol": sockets.PhysicalPolSocketDef(label="PhysicalPol"),
"physical_freq": sockets.PhysicalFreqSocketDef(label="PhysicalFreq"), "physical_freq": sockets.PhysicalFreqSocketDef(label="PhysicalFreq"),
"physical_spec_power_dist": sockets.PhysicalSpecPowerDistSocketDef(label="PhysicalSpecPowerDist"), "physical_spec_power_dist": sockets.PhysicalSpecPowerDistSocketDef(label="PhysicalSpecPowerDist"),
@ -62,18 +69,21 @@ class KitchenSinkNode(base.MaxwellSimTreeNode):
"maxwell_temporal_shape": sockets.MaxwellTemporalShapeSocketDef(label="MaxwellTemporalShape"), "maxwell_temporal_shape": sockets.MaxwellTemporalShapeSocketDef(label="MaxwellTemporalShape"),
"maxwell_medium": sockets.MaxwellMediumSocketDef(label="MaxwellMedium"), "maxwell_medium": sockets.MaxwellMediumSocketDef(label="MaxwellMedium"),
#"maxwell_medium_nonlinearity": sockets.MaxwellMediumNonLinearitySocketDef(label="MaxwellMediumNonLinearity"), #"maxwell_medium_nonlinearity": sockets.MaxwellMediumNonLinearitySocketDef(label="MaxwellMediumNonLinearity"),
"maxwell_structure": sockets.MaxwellMediumSocketDef(label="MaxwellMedium"), "maxwell_structure": sockets.MaxwellStructureSocketDef(label="MaxwellMedium"),
"maxwell_bound_box": sockets.MaxwellBoundBoxSocketDef(label="MaxwellBoundBox"), "maxwell_bound_box": sockets.MaxwellBoundBoxSocketDef(label="MaxwellBoundBox"),
"maxwell_bound_face": sockets.MaxwellBoundFaceSocketDef(label="MaxwellBoundFace"), "maxwell_bound_face": sockets.MaxwellBoundFaceSocketDef(label="MaxwellBoundFace"),
"maxwell_monitor": sockets.MaxwellMonitorSocketDef(label="MaxwellMonitor"), "maxwell_monitor": sockets.MaxwellMonitorSocketDef(label="MaxwellMonitor"),
"maxwell_monitor": sockets.MaxwellFDTDSimSocketDef(label="MaxwellFDTDSim"), "maxwell_fdtd_sim": sockets.MaxwellFDTDSimSocketDef(label="MaxwellFDTDSim"),
"maxwell_monitor": sockets.MaxwellSimGridSocketDef(label="MaxwellSimGrid"), "maxwell_sim_grid": sockets.MaxwellSimGridSocketDef(label="MaxwellSimGrid"),
"maxwell_monitor": sockets.MaxwellSimGridAxisSocketDef(label="MaxwellSimGridAxis"), "maxwell_sim_grid_axis": sockets.MaxwellSimGridAxisSocketDef(label="MaxwellSimGridAxis"),
}, },
} }
output_sockets = {} output_sockets = {}
output_socket_sets = input_socket_sets output_socket_sets = {
k + " Output": v
for k, v in input_socket_sets.items()
}

View File

@ -16,21 +16,11 @@ class FDTDSimNode(base.MaxwellSimTreeNode):
# - Sockets # - Sockets
#################### ####################
input_sockets = { input_sockets = {
"run_time": sockets.RealNumberSocketDef( "run_time": sockets.PhysicalTimeSocketDef(
label="Run Time", label="Run Time",
default_value=1.0,
), ),
"size_x": sockets.RealNumberSocketDef( "size": sockets.PhysicalSize3DSocketDef(
label="Size X", label="Size",
default_value=1.0,
),
"size_y": sockets.RealNumberSocketDef(
label="Size Y",
default_value=1.0,
),
"size_z": sockets.RealNumberSocketDef(
label="Size Z",
default_value=1.0,
), ),
"ambient_medium": sockets.MaxwellMediumSocketDef( "ambient_medium": sockets.MaxwellMediumSocketDef(
label="Ambient Medium", label="Ambient Medium",
@ -56,17 +46,15 @@ class FDTDSimNode(base.MaxwellSimTreeNode):
#################### ####################
@base.computes_output_socket("fdtd_sim") @base.computes_output_socket("fdtd_sim")
def compute_simulation(self: contracts.NodeTypeProtocol) -> td.Simulation: def compute_simulation(self: contracts.NodeTypeProtocol) -> td.Simulation:
run_time = self.compute_input("run_time") _run_time = self.compute_input("run_time")
_size = self.compute_input("size")
ambient_medium = self.compute_input("ambient_medium") ambient_medium = self.compute_input("ambient_medium")
structures = [self.compute_input("structure")] structures = [self.compute_input("structure")]
sources = [self.compute_input("source")] sources = [self.compute_input("source")]
bound = self.compute_input("bound") bound = self.compute_input("bound")
size = ( run_time = spu.convert_to(_run_time, spu.second) / spu.second
self.compute_input("size_x"), size = tuple(spu.convert_to(_size, spu.um) / spu.um)
self.compute_input("size_y"),
self.compute_input("size_z"),
)
return td.Simulation( return td.Simulation(
size=size, size=size,

View File

@ -16,17 +16,14 @@ class PointDipoleSourceNode(base.MaxwellSimTreeNode):
# - Sockets # - Sockets
#################### ####################
input_sockets = { input_sockets = {
"center_x": sockets.RealNumberSocketDef( #"polarization": sockets.PhysicalPolSocketDef(
label="Center X", # label="Polarization",
default_value=0.0, #), ## TODO: Exactly how to go about this...
"temporal_shape": sockets.MaxwellTemporalShapeSocketDef(
label="Temporal Shape",
), ),
"center_y": sockets.RealNumberSocketDef( "center": sockets.PhysicalPoint3DSocketDef(
label="Center Y", label="Center",
default_value=0.0,
),
"center_z": sockets.RealNumberSocketDef(
label="Center Z",
default_value=0.0,
), ),
} }
output_sockets = { output_sockets = {
@ -40,19 +37,19 @@ class PointDipoleSourceNode(base.MaxwellSimTreeNode):
#################### ####################
@base.computes_output_socket("source") @base.computes_output_socket("source")
def compute_source(self: contracts.NodeTypeProtocol) -> td.PointDipole: def compute_source(self: contracts.NodeTypeProtocol) -> td.PointDipole:
center = ( temporal_shape = self.compute_input("temporal_shape")
self.compute_input("center_x"),
self.compute_input("center_y"),
self.compute_input("center_z"),
)
cheating_pulse = td.GaussianPulse(freq0=200e12, fwidth=20e12) _center = self.compute_input("center")
center = tuple(spu.convert_to(_center, spu.um) / spu.um)
cheating_pol = "Ex"
## TODO: Fix
return td.PointDipole( return td.PointDipole(
center=center, center=center,
source_time=cheating_pulse, source_time=temporal_shape,
interpolate=True, interpolate=True,
polarization="Ex", polarization=cheating_pol,
) )

View File

@ -1,6 +1,82 @@
import tidy3d as td
import sympy as sp
import sympy.physics.units as spu
from .... import contracts
from .... import sockets
from ... import base
class GaussianPulseTemporalShapeNode(base.MaxwellSimTreeNode):
node_type = contracts.NodeType.GaussianPulseTemporalShape
bl_label = "Gaussian Pulse Temporal Shape"
#bl_icon = ...
####################
# - Sockets
####################
input_sockets = {
#"amplitude": sockets.RealNumberSocketDef(
# label="Temporal Shape",
#), ## Should have a unit of some kind...
"phase": sockets.PhysicalAngleSocketDef(
label="Phase",
),
"freq_center": sockets.PhysicalFreqSocketDef(
label="Freq Center",
),
"freq_std": sockets.PhysicalFreqSocketDef(
label="Freq STD",
),
"time_delay_rel_ang_freq": sockets.RealNumberSocketDef(
label="Time Delay rel. Ang. Freq",
),
"remove_dc_component": sockets.BoolSocketDef(
label="Remove DC",
default_value=True,
),
}
output_sockets = {
"temporal_shape": sockets.MaxwellTemporalShapeSocketDef(
label="Temporal Shape",
),
}
####################
# - Output Socket Computation
####################
@base.computes_output_socket("temporal_shape")
def compute_source(self: contracts.NodeTypeProtocol) -> td.PointDipole:
_phase = self.compute_input("phase")
_freq_center = self.compute_input("freq_center")
_freq_std = self.compute_input("freq_std")
time_delay_rel_ang_freq = self.compute_input("time_delay_rel_ang_freq")
remove_dc_component = self.compute_input("remove_dc_component")
cheating_amplitude = 1.0
phase = spu.convert_to(_phase, spu.radian) / spu.radian
freq_center = spu.convert_to(_freq_center, spu.hertz) / spu.hertz
freq_std = spu.convert_to(_freq_std, spu.hertz) / spu.hertz
return td.GaussianPulse(
amplitude=cheating_amplitude,
phase=phase,
freq0=freq_center,
fwidth=freq_std,
offset=time_delay_rel_ang_freq,
remove_dc_component=remove_dc_component,
)
#################### ####################
# - Blender Registration # - Blender Registration
#################### ####################
BL_REGISTER = [] BL_REGISTER = [
BL_NODES = {} GaussianPulseTemporalShapeNode,
]
BL_NODES = {
contracts.NodeType.GaussianPulseTemporalShape: (
contracts.NodeCategory.MAXWELLSIM_SOURCES_TEMPORALSHAPES
)
}

View File

@ -18,29 +18,11 @@ class BoxStructureNode(base.MaxwellSimTreeNode):
"medium": sockets.MaxwellMediumSocketDef( "medium": sockets.MaxwellMediumSocketDef(
label="Medium", label="Medium",
), ),
"center_x": sockets.RealNumberSocketDef( "center": sockets.PhysicalPoint3DSocketDef(
label="Center X", label="Center",
default_value=0.0,
), ),
"center_y": sockets.RealNumberSocketDef( "size": sockets.PhysicalSize3DSocketDef(
label="Center Y", label="Size",
default_value=0.0,
),
"center_z": sockets.RealNumberSocketDef(
label="Center Z",
default_value=0.0,
),
"size_x": sockets.RealNumberSocketDef(
label="Size X",
default_value=1.0,
),
"size_y": sockets.RealNumberSocketDef(
label="Size Y",
default_value=1.0,
),
"size_z": sockets.RealNumberSocketDef(
label="Size Z",
default_value=1.0,
), ),
} }
output_sockets = { output_sockets = {
@ -55,16 +37,11 @@ class BoxStructureNode(base.MaxwellSimTreeNode):
@base.computes_output_socket("structure") @base.computes_output_socket("structure")
def compute_simulation(self: contracts.NodeTypeProtocol) -> td.Box: def compute_simulation(self: contracts.NodeTypeProtocol) -> td.Box:
medium = self.compute_input("medium") medium = self.compute_input("medium")
center = ( _center = self.compute_input("center")
self.compute_input("center_x"), _size = self.compute_input("size")
self.compute_input("center_y"),
self.compute_input("center_z"), center = tuple(spu.convert_to(_center, spu.um) / spu.um)
) size = tuple(spu.convert_to(_size, spu.um) / spu.um)
size = (
self.compute_input("size_x"),
self.compute_input("size_y"),
self.compute_input("size_z"),
)
return td.Structure( return td.Structure(
geometry=td.Box( geometry=td.Box(

View File

@ -1,5 +1,6 @@
from . import basic from . import basic
AnySocketDef = basic.AnySocketDef AnySocketDef = basic.AnySocketDef
BoolSocketDef = basic.BoolSocketDef
TextSocketDef = basic.TextSocketDef TextSocketDef = basic.TextSocketDef
FilePathSocketDef = basic.FilePathSocketDef FilePathSocketDef = basic.FilePathSocketDef
@ -21,10 +22,12 @@ PhysicalAngleSocketDef = physical.PhysicalAngleSocketDef
PhysicalLengthSocketDef = physical.PhysicalLengthSocketDef PhysicalLengthSocketDef = physical.PhysicalLengthSocketDef
PhysicalAreaSocketDef = physical.PhysicalAreaSocketDef PhysicalAreaSocketDef = physical.PhysicalAreaSocketDef
PhysicalVolumeSocketDef = physical.PhysicalVolumeSocketDef PhysicalVolumeSocketDef = physical.PhysicalVolumeSocketDef
PhysicalPoint3DSocketDef = physical.PhysicalPoint3DSocketDef
PhysicalSize3DSocketDef = physical.PhysicalSize3DSocketDef
PhysicalMassSocketDef = physical.PhysicalMassSocketDef PhysicalMassSocketDef = physical.PhysicalMassSocketDef
PhysicalSpeedSocketDef = physical.PhysicalSpeedSocketDef PhysicalSpeedSocketDef = physical.PhysicalSpeedSocketDef
PhysicalAccelSocketDef = physical.PhysicalAccelSocketDef PhysicalAccelScalarSocketDef = physical.PhysicalAccelScalarSocketDef
PhysicalForceSocketDef = physical.PhysicalForceSocketDef PhysicalForceScalarSocketDef = physical.PhysicalForceScalarSocketDef
PhysicalPolSocketDef = physical.PhysicalPolSocketDef PhysicalPolSocketDef = physical.PhysicalPolSocketDef
PhysicalFreqSocketDef = physical.PhysicalFreqSocketDef PhysicalFreqSocketDef = physical.PhysicalFreqSocketDef
PhysicalSpecRelPermDistSocketDef = physical.PhysicalSpecRelPermDistSocketDef PhysicalSpecRelPermDistSocketDef = physical.PhysicalSpecRelPermDistSocketDef

View File

@ -127,10 +127,16 @@ class BLSocket(bpy.types.NodeSocket):
the value with the new unit. the value with the new unit.
""" """
if hasattr(self, "raw_value") and hasattr(self, "unit"): if hasattr(self, "raw_value") and hasattr(self, "unit"):
self.raw_value = spu.convert_to( if hasattr(self.raw_value, "__getitem__"):
self.raw_value * self._unit_previous, self.raw_value = tuple(spu.convert_to(
self.unit, sp.Matrix(tuple(self.raw_value)) * self._unit_previous,
) / self.unit self.unit,
) / self.unit)
else:
self.raw_value = spu.convert_to(
self.raw_value * self._unit_previous,
self.unit,
) / self.unit
self._unit_previous = self.unit self._unit_previous = self.unit
@ -187,6 +193,9 @@ class BLSocket(bpy.types.NodeSocket):
label_col_row = col.row(align=True) label_col_row = col.row(align=True)
if hasattr(self, "draw_label_row"): if hasattr(self, "draw_label_row"):
self.draw_label_row(label_col_row, text) self.draw_label_row(label_col_row, text)
elif hasattr(self, "raw_unit"):
label_col_row.label(text=text)
label_col_row.prop(self, "raw_unit", text="")
else: else:
label_col_row.label(text=text) label_col_row.label(text=text)
@ -208,6 +217,9 @@ class BLSocket(bpy.types.NodeSocket):
# Row(s): Value # Row(s): Value
if hasattr(self, "draw_value"): if hasattr(self, "draw_value"):
self.draw_value(col) self.draw_value(col)
elif hasattr(self, "raw_value"):
#col_row = col.row(align=True)
col.prop(self, "raw_value", text="")
def draw_output( def draw_output(
self, self,

View File

@ -1,6 +1,9 @@
from . import any_socket from . import any_socket
AnySocketDef = any_socket.AnySocketDef AnySocketDef = any_socket.AnySocketDef
from . import bool_socket
BoolSocketDef = bool_socket.BoolSocketDef
from . import text_socket from . import text_socket
TextSocketDef = text_socket.TextSocketDef TextSocketDef = text_socket.TextSocketDef
@ -10,6 +13,7 @@ FilePathSocketDef = file_path_socket.FilePathSocketDef
BL_REGISTER = [ BL_REGISTER = [
*any_socket.BL_REGISTER, *any_socket.BL_REGISTER,
*bool_socket.BL_REGISTER,
*text_socket.BL_REGISTER, *text_socket.BL_REGISTER,
*file_path_socket.BL_REGISTER, *file_path_socket.BL_REGISTER,
] ]

View File

@ -0,0 +1,73 @@
import typing as typ
import bpy
import sympy as sp
import pydantic as pyd
from .. import base
from ... import contracts
####################
# - Blender Socket
####################
class BoolBLSocket(base.BLSocket):
socket_type = contracts.SocketType.Bool
bl_label = "Bool"
compatible_types = {
bool: {},
}
####################
# - Properties
####################
raw_value: bpy.props.BoolProperty(
name="Boolean",
description="Represents a boolean",
default=False,
)
####################
# - Socket UI
####################
def draw_label_row(self, label_col_row: bpy.types.UILayout, text: str) -> None:
label_col_row.label(text=text)
label_col_row.prop(self, "raw_value", text="")
def draw_value(self, label_col_row: bpy.types.UILayout) -> None:
pass
####################
# - Computation of Default Value
####################
@property
def default_value(self) -> str:
return self.raw_value
@default_value.setter
def default_value(self, value: typ.Any) -> None:
# (Guard) Value Compatibility
if not self.is_compatible(value):
msg = f"Tried setting socket ({self}) to incompatible value ({value}) of type {type(value)}"
raise ValueError(msg)
self.raw_value = bool(value)
####################
# - Socket Configuration
####################
class BoolSocketDef(pyd.BaseModel):
socket_type: contracts.SocketType = contracts.SocketType.Bool
label: str
default_value: bool = False
def init(self, bl_socket: BoolBLSocket) -> None:
bl_socket.raw_value = self.default_value
####################
# - Blender Registration
####################
BL_REGISTER = [
BoolBLSocket,
]

View File

@ -37,6 +37,9 @@ class TextBLSocket(base.BLSocket):
""" """
label_col_row.prop(self, "raw_value", text=text) label_col_row.prop(self, "raw_value", text=text)
def draw_value(self, label_col_row: bpy.types.UILayout) -> None:
pass
#################### ####################
# - Computation of Default Value # - Computation of Default Value
#################### ####################

View File

@ -32,6 +32,7 @@ BL_REGISTER = [
*source_socket.BL_REGISTER, *source_socket.BL_REGISTER,
*temporal_shape_socket.BL_REGISTER, *temporal_shape_socket.BL_REGISTER,
*structure_socket.BL_REGISTER, *structure_socket.BL_REGISTER,
*monitor_socket.BL_REGISTER,
*fdtd_sim_socket.BL_REGISTER, *fdtd_sim_socket.BL_REGISTER,
*sim_grid_socket.BL_REGISTER, *sim_grid_socket.BL_REGISTER,
*sim_grid_axis_socket.BL_REGISTER, *sim_grid_axis_socket.BL_REGISTER,

View File

@ -22,7 +22,7 @@ class MaxwellMediumBLSocket(base.BLSocket):
name="Permittivity", name="Permittivity",
description="Represents a simple, real permittivity.", description="Represents a simple, real permittivity.",
default=0.0, default=0.0,
precision=6, precision=4,
) )
#################### ####################
@ -33,7 +33,7 @@ class MaxwellMediumBLSocket(base.BLSocket):
specifying the active unit. specifying the active unit.
""" """
col_row = col.row(align=True) col_row = col.row(align=True)
col_row.prop(self, "rel_permittivity", text="Re(eps_r)") col_row.prop(self, "rel_permittivity", text="ϵr")
#################### ####################
# - Computation of Default Value # - Computation of Default Value

View File

@ -32,14 +32,6 @@ class RealNumberBLSocket(base.BLSocket):
precision=6, precision=6,
) )
####################
# - Socket UI
####################
def draw_label_row(self, label_col_row: bpy.types.UILayout, text: str) -> None:
"""Draw the value of the real number.
"""
label_col_row.prop(self, "raw_value", text=text)
#################### ####################
# - Computation of Default Value # - Computation of Default Value
#################### ####################

View File

@ -11,15 +11,21 @@ PhysicalLengthSocketDef = length_socket.PhysicalLengthSocketDef
PhysicalAreaSocketDef = area_socket.PhysicalAreaSocketDef PhysicalAreaSocketDef = area_socket.PhysicalAreaSocketDef
PhysicalVolumeSocketDef = volume_socket.PhysicalVolumeSocketDef PhysicalVolumeSocketDef = volume_socket.PhysicalVolumeSocketDef
from . import point_3d_socket
PhysicalPoint3DSocketDef = point_3d_socket.PhysicalPoint3DSocketDef
from . import size_3d_socket
PhysicalSize3DSocketDef = size_3d_socket.PhysicalSize3DSocketDef
from . import mass_socket from . import mass_socket
PhysicalMassSocketDef = mass_socket.PhysicalMassSocketDef PhysicalMassSocketDef = mass_socket.PhysicalMassSocketDef
from . import speed_socket from . import speed_socket
from . import accel_socket from . import accel_scalar_socket
from . import force_socket from . import force_scalar_socket
PhysicalSpeedSocketDef = speed_socket.PhysicalSpeedSocketDef PhysicalSpeedSocketDef = speed_socket.PhysicalSpeedSocketDef
PhysicalAccelSocketDef = accel_socket.PhysicalAccelSocketDef PhysicalAccelScalarSocketDef = accel_scalar_socket.PhysicalAccelScalarSocketDef
PhysicalForceSocketDef = force_socket.PhysicalForceSocketDef PhysicalForceScalarSocketDef = force_scalar_socket.PhysicalForceScalarSocketDef
from . import pol_socket from . import pol_socket
PhysicalPolSocketDef = pol_socket.PhysicalPolSocketDef PhysicalPolSocketDef = pol_socket.PhysicalPolSocketDef
@ -42,11 +48,15 @@ BL_REGISTER = [
*area_socket.BL_REGISTER, *area_socket.BL_REGISTER,
*volume_socket.BL_REGISTER, *volume_socket.BL_REGISTER,
*point_3d_socket.BL_REGISTER,
*size_3d_socket.BL_REGISTER,
*mass_socket.BL_REGISTER, *mass_socket.BL_REGISTER,
*speed_socket.BL_REGISTER, *speed_socket.BL_REGISTER,
*accel_socket.BL_REGISTER, *accel_scalar_socket.BL_REGISTER,
*force_socket.BL_REGISTER, *force_scalar_socket.BL_REGISTER,
*pol_socket.BL_REGISTER, *pol_socket.BL_REGISTER,

View File

@ -9,8 +9,8 @@ from ... import contracts
#################### ####################
# - Blender Socket # - Blender Socket
#################### ####################
class PhysicalAccelBLSocket(base.BLSocket): class PhysicalAccelScalarBLSocket(base.BLSocket):
socket_type = contracts.SocketType.PhysicalAccel socket_type = contracts.SocketType.PhysicalAccelScalar
bl_label = "PhysicalAccel" bl_label = "PhysicalAccel"
use_units = True use_units = True
@ -24,17 +24,6 @@ class PhysicalAccelBLSocket(base.BLSocket):
precision=6, precision=6,
) )
####################
# - Socket UI
####################
def draw_label_row(self, label_col_row: bpy.types.UILayout, text: str) -> None:
label_col_row.label(text=text)
label_col_row.prop(self, "raw_unit", text="")
def draw_value(self, col: bpy.types.UILayout) -> None:
col_row = col.row(align=True)
col_row.prop(self, "raw_value", text="")
#################### ####################
# - Default Value # - Default Value
#################### ####################
@ -49,16 +38,19 @@ class PhysicalAccelBLSocket(base.BLSocket):
#################### ####################
# - Socket Configuration # - Socket Configuration
#################### ####################
class PhysicalAccelSocketDef(pyd.BaseModel): class PhysicalAccelScalarSocketDef(pyd.BaseModel):
socket_type: contracts.SocketType = contracts.SocketType.PhysicalAccel socket_type: contracts.SocketType = contracts.SocketType.PhysicalAccelScalar
label: str label: str
def init(self, bl_socket: PhysicalAccelBLSocket) -> None: default_unit: typ.Any | None = None
pass
def init(self, bl_socket: PhysicalAccelScalarBLSocket) -> None:
if self.default_unit:
bl_socket.unit = self.default_unit
#################### ####################
# - Blender Registration # - Blender Registration
#################### ####################
BL_REGISTER = [ BL_REGISTER = [
PhysicalAccelBLSocket, PhysicalAccelScalarBLSocket,
] ]

View File

@ -1,5 +1,6 @@
import typing as typ import typing as typ
import bpy
import pydantic as pyd import pydantic as pyd
from .. import base from .. import base
@ -11,17 +12,28 @@ from ... import contracts
class PhysicalAngleBLSocket(base.BLSocket): class PhysicalAngleBLSocket(base.BLSocket):
socket_type = contracts.SocketType.PhysicalAngle socket_type = contracts.SocketType.PhysicalAngle
bl_label = "PhysicalAngle" bl_label = "PhysicalAngle"
use_units = True
####################
# - Properties
####################
raw_value: bpy.props.FloatProperty(
name="Unitless Acceleration",
description="Represents the unitless part of the acceleration",
default=0.0,
precision=4,
)
#################### ####################
# - Default Value # - Default Value
#################### ####################
@property @property
def default_value(self) -> None: def default_value(self) -> None:
pass return self.raw_value * self.unit
@default_value.setter @default_value.setter
def default_value(self, value: typ.Any) -> None: def default_value(self, value: typ.Any) -> None:
pass self.raw_value = self.value_as_unit(value)
#################### ####################
# - Socket Configuration # - Socket Configuration
@ -30,8 +42,11 @@ class PhysicalAngleSocketDef(pyd.BaseModel):
socket_type: contracts.SocketType = contracts.SocketType.PhysicalAngle socket_type: contracts.SocketType = contracts.SocketType.PhysicalAngle
label: str label: str
default_unit: typ.Any | None = None
def init(self, bl_socket: PhysicalAngleBLSocket) -> None: def init(self, bl_socket: PhysicalAngleBLSocket) -> None:
pass if self.default_unit:
bl_socket.unit = self.default_unit
#################### ####################
# - Blender Registration # - Blender Registration

View File

@ -38,9 +38,6 @@ class PhysicalAreaBLSocket(base.BLSocket):
# - Socket UI # - Socket UI
#################### ####################
def draw_label_row(self, label_col_row: bpy.types.UILayout, text: str) -> None: def draw_label_row(self, label_col_row: bpy.types.UILayout, text: str) -> None:
"""Draw the value of the area, including a toggle for
specifying the active unit.
"""
label_col_row.label(text=text) label_col_row.label(text=text)
label_col_row.prop(self, "raw_unit", text="") label_col_row.prop(self, "raw_unit", text="")

View File

@ -0,0 +1,56 @@
import typing as typ
import bpy
import pydantic as pyd
from .. import base
from ... import contracts
####################
# - Blender Socket
####################
class PhysicalForceScalarBLSocket(base.BLSocket):
socket_type = contracts.SocketType.PhysicalForceScalar
bl_label = "PhysicalForceScalar"
use_units = True
####################
# - Properties
####################
raw_value: bpy.props.FloatProperty(
name="Unitless Force",
description="Represents the unitless part of the force",
default=0.0,
precision=6,
)
####################
# - Default Value
####################
@property
def default_value(self) -> None:
return self.raw_value * self.unit
@default_value.setter
def default_value(self, value: typ.Any) -> None:
self.raw_value = self.value_as_unit(value)
####################
# - Socket Configuration
####################
class PhysicalForceScalarSocketDef(pyd.BaseModel):
socket_type: contracts.SocketType = contracts.SocketType.PhysicalForceScalar
label: str
default_unit: typ.Any | None = None
def init(self, bl_socket: PhysicalForceScalarBLSocket) -> None:
if self.default_unit:
bl_socket.unit = self.default_unit
####################
# - Blender Registration
####################
BL_REGISTER = [
PhysicalForceScalarBLSocket,
]

View File

@ -1,41 +0,0 @@
import typing as typ
import pydantic as pyd
from .. import base
from ... import contracts
####################
# - Blender Socket
####################
class PhysicalForceBLSocket(base.BLSocket):
socket_type = contracts.SocketType.PhysicalForce
bl_label = "PhysicalForce"
####################
# - Default Value
####################
@property
def default_value(self) -> None:
pass
@default_value.setter
def default_value(self, value: typ.Any) -> None:
pass
####################
# - Socket Configuration
####################
class PhysicalForceSocketDef(pyd.BaseModel):
socket_type: contracts.SocketType = contracts.SocketType.PhysicalForce
label: str
def init(self, bl_socket: PhysicalForceBLSocket) -> None:
pass
####################
# - Blender Registration
####################
BL_REGISTER = [
PhysicalForceBLSocket,
]

View File

@ -1,5 +1,6 @@
import typing as typ import typing as typ
import bpy
import pydantic as pyd import pydantic as pyd
from .. import base from .. import base
@ -11,17 +12,28 @@ from ... import contracts
class PhysicalFreqBLSocket(base.BLSocket): class PhysicalFreqBLSocket(base.BLSocket):
socket_type = contracts.SocketType.PhysicalFreq socket_type = contracts.SocketType.PhysicalFreq
bl_label = "PhysicalFreq" bl_label = "PhysicalFreq"
use_units = True
####################
# - Properties
####################
raw_value: bpy.props.FloatProperty(
name="Unitless Frequency",
description="Represents the unitless part of the frequency",
default=0.0,
precision=6,
)
#################### ####################
# - Default Value # - Default Value
#################### ####################
@property @property
def default_value(self) -> None: def default_value(self) -> None:
pass return self.raw_value * self.unit
@default_value.setter @default_value.setter
def default_value(self, value: typ.Any) -> None: def default_value(self, value: typ.Any) -> None:
pass self.raw_value = self.value_as_unit(value)
#################### ####################
# - Socket Configuration # - Socket Configuration

View File

@ -1,5 +1,6 @@
import typing as typ import typing as typ
import bpy
import pydantic as pyd import pydantic as pyd
from .. import base from .. import base
@ -11,17 +12,28 @@ from ... import contracts
class PhysicalLengthBLSocket(base.BLSocket): class PhysicalLengthBLSocket(base.BLSocket):
socket_type = contracts.SocketType.PhysicalLength socket_type = contracts.SocketType.PhysicalLength
bl_label = "PhysicalLength" bl_label = "PhysicalLength"
use_units = True
####################
# - Properties
####################
raw_value: bpy.props.FloatProperty(
name="Unitless Force",
description="Represents the unitless part of the force",
default=0.0,
precision=6,
)
#################### ####################
# - Default Value # - Default Value
#################### ####################
@property @property
def default_value(self) -> None: def default_value(self) -> None:
pass return self.raw_value * self.unit
@default_value.setter @default_value.setter
def default_value(self, value: typ.Any) -> None: def default_value(self, value: typ.Any) -> None:
pass self.raw_value = self.value_as_unit(value)
#################### ####################
# - Socket Configuration # - Socket Configuration
@ -30,8 +42,11 @@ class PhysicalLengthSocketDef(pyd.BaseModel):
socket_type: contracts.SocketType = contracts.SocketType.PhysicalLength socket_type: contracts.SocketType = contracts.SocketType.PhysicalLength
label: str label: str
default_unit: typ.Any | None = None
def init(self, bl_socket: PhysicalLengthBLSocket) -> None: def init(self, bl_socket: PhysicalLengthBLSocket) -> None:
pass if self.default_unit:
bl_socket.unit = self.default_unit
#################### ####################
# - Blender Registration # - Blender Registration

View File

@ -0,0 +1,67 @@
import typing as typ
import bpy
import sympy as sp
import sympy.physics.units as spu
import pydantic as pyd
from .. import base
from ... import contracts
class PhysicalPoint3DBLSocket(base.BLSocket):
socket_type = contracts.SocketType.PhysicalPoint3D
bl_label = "Physical Volume"
use_units = True
compatible_types = {
sp.Expr: {
lambda self, v: v.is_real,
lambda self, v: len(v.free_symbols) == 0,
lambda self, v: any(
contracts.is_exactly_expressed_as_unit(v, unit)
for unit in self.units.values()
)
},
}
####################
# - Properties
####################
raw_value: bpy.props.FloatVectorProperty(
name="Unitless 3D Point (global coordinate system)",
description="Represents the unitless part of the 3D point",
size=3,
default=(0.0, 0.0, 0.0),
precision=4,
)
####################
# - Computation of Default Value
####################
@property
def default_value(self) -> sp.Expr:
return sp.Matrix(tuple(self.raw_value)) * self.unit
@default_value.setter
def default_value(self, value: typ.Any) -> None:
self.raw_value = self.value_as_unit(value)
####################
# - Socket Configuration
####################
class PhysicalPoint3DSocketDef(pyd.BaseModel):
socket_type: contracts.SocketType = contracts.SocketType.PhysicalPoint3D
label: str
default_unit: typ.Any | None = None
def init(self, bl_socket: PhysicalPoint3DBLSocket) -> None:
if self.default_unit:
bl_socket.unit = self.default_unit
####################
# - Blender Registration
####################
BL_REGISTER = [
PhysicalPoint3DBLSocket,
]

View File

@ -0,0 +1,67 @@
import typing as typ
import bpy
import sympy as sp
import sympy.physics.units as spu
import pydantic as pyd
from .. import base
from ... import contracts
class PhysicalSize3DBLSocket(base.BLSocket):
socket_type = contracts.SocketType.PhysicalSize3D
bl_label = "Physical Volume"
use_units = True
compatible_types = {
sp.Expr: {
lambda self, v: v.is_real,
lambda self, v: len(v.free_symbols) == 0,
lambda self, v: any(
contracts.is_exactly_expressed_as_unit(v, unit)
for unit in self.units.values()
)
},
}
####################
# - Properties
####################
raw_value: bpy.props.FloatVectorProperty(
name="Unitless 3D Size",
description="Represents the unitless part of the 3D size",
size=3,
default=(1.0, 1.0, 1.0),
precision=4,
)
####################
# - Computation of Default Value
####################
@property
def default_value(self) -> sp.Expr:
return sp.Matrix(tuple(self.raw_value)) * self.unit
@default_value.setter
def default_value(self, value: typ.Any) -> None:
self.raw_value = self.value_as_unit(value)
####################
# - Socket Configuration
####################
class PhysicalSize3DSocketDef(pyd.BaseModel):
socket_type: contracts.SocketType = contracts.SocketType.PhysicalSize3D
label: str
default_unit: typ.Any | None = None
def init(self, bl_socket: PhysicalSize3DBLSocket) -> None:
if self.default_unit:
bl_socket.unit = self.default_unit
####################
# - Blender Registration
####################
BL_REGISTER = [
PhysicalSize3DBLSocket,
]

View File

@ -1,5 +1,6 @@
import typing as typ import typing as typ
import bpy
import pydantic as pyd import pydantic as pyd
from .. import base from .. import base
@ -11,17 +12,28 @@ from ... import contracts
class PhysicalTimeBLSocket(base.BLSocket): class PhysicalTimeBLSocket(base.BLSocket):
socket_type = contracts.SocketType.PhysicalTime socket_type = contracts.SocketType.PhysicalTime
bl_label = "PhysicalTime" bl_label = "PhysicalTime"
use_units = True
####################
# - Properties
####################
raw_value: bpy.props.FloatProperty(
name="Unitless Force",
description="Represents the unitless part of the force",
default=0.0,
precision=6,
)
#################### ####################
# - Default Value # - Default Value
#################### ####################
@property @property
def default_value(self) -> None: def default_value(self) -> None:
pass return self.raw_value * self.unit
@default_value.setter @default_value.setter
def default_value(self, value: typ.Any) -> None: def default_value(self, value: typ.Any) -> None:
pass self.raw_value = self.value_as_unit(value)
#################### ####################
# - Socket Configuration # - Socket Configuration
@ -30,8 +42,11 @@ class PhysicalTimeSocketDef(pyd.BaseModel):
socket_type: contracts.SocketType = contracts.SocketType.PhysicalTime socket_type: contracts.SocketType = contracts.SocketType.PhysicalTime
label: str label: str
default_unit: typ.Any | None = None
def init(self, bl_socket: PhysicalTimeBLSocket) -> None: def init(self, bl_socket: PhysicalTimeBLSocket) -> None:
pass if self.default_unit:
bl_socket.unit = self.default_unit
#################### ####################
# - Blender Registration # - Blender Registration

View File

@ -5,9 +5,6 @@ import sympy as sp
import sympy.physics.units as spu import sympy.physics.units as spu
import pydantic as pyd import pydantic as pyd
sp.printing.str.StrPrinter._default_settings['abbrev'] = True
## When we str() a unit expression, use abbrevied units.
from .. import base from .. import base
from ... import contracts from ... import contracts

View File

@ -1,3 +1,4 @@
tidy3d==2.5.2 tidy3d==2.5.2
pydantic==2.6.0 pydantic==2.6.0
sympy==1.12 sympy==1.12
scipy==1.12.0

BIN
code/demo.blend (Stored with Git LFS)

Binary file not shown.