feat: Various features (some very prototype).
It's very prototype-y. Cleanup pending.blender-plugin-mvp
parent
74d5a5daf8
commit
d95210dc34
|
@ -97,6 +97,7 @@ class SocketType(BlenderTypeEnum):
|
|||
Complex3DVector = enum.auto()
|
||||
|
||||
# Physical
|
||||
PhysicalUnitSystem = enum.auto()
|
||||
PhysicalTime = enum.auto()
|
||||
|
||||
PhysicalAngle = enum.auto()
|
||||
|
@ -122,6 +123,7 @@ class SocketType(BlenderTypeEnum):
|
|||
PhysicalPol = enum.auto()
|
||||
|
||||
PhysicalFreq = enum.auto()
|
||||
PhysicalVacWL = enum.auto()
|
||||
PhysicalSpecPowerDist = enum.auto()
|
||||
PhysicalSpecRelPermDist = enum.auto()
|
||||
|
||||
|
@ -135,6 +137,8 @@ class SocketType(BlenderTypeEnum):
|
|||
BlenderGeoNodes = enum.auto()
|
||||
BlenderText = enum.auto()
|
||||
|
||||
BlenderPreviewTarget = enum.auto()
|
||||
|
||||
# Maxwell
|
||||
MaxwellSource = enum.auto()
|
||||
MaxwellTemporalShape = enum.auto()
|
||||
|
@ -376,14 +380,19 @@ SocketType_to_units = {
|
|||
"GHZ": spuex.gigahertz,
|
||||
"THZ": spuex.terahertz,
|
||||
"PHZ": spuex.petahertz,
|
||||
#"EHZ": spu.exahertz,
|
||||
"VAC_PM": spu.picometer, ## c(vac) = wl*freq
|
||||
"VAC_A": spu.angstrom,
|
||||
"VAC_NM": spu.nanometer,
|
||||
"VAC_UM": spu.micrometer,
|
||||
"VAC_MM": spu.millimeter,
|
||||
"VAC_CM": spu.centimeter,
|
||||
"VAC_M": spu.meter,
|
||||
"EHZ": spuex.exahertz,
|
||||
},
|
||||
},
|
||||
SocketType.PhysicalVacWL: {
|
||||
"default": "NM",
|
||||
"values": {
|
||||
"PM": spu.picometer, ## c(vac) = wl*freq
|
||||
"A": spu.angstrom,
|
||||
"NM": spu.nanometer,
|
||||
"UM": spu.micrometer,
|
||||
"MM": spu.millimeter,
|
||||
"CM": spu.centimeter,
|
||||
"M": spu.meter,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -408,6 +417,7 @@ SocketType_to_color = {
|
|||
SocketType.Complex3DVector: (0.2, 0.7, 0.2, 1.0), # Dark Green
|
||||
|
||||
# Physical
|
||||
SocketType.PhysicalUnitSystem: (1.0, 0.5, 0.5, 1.0), # Light Red
|
||||
SocketType.PhysicalTime: (1.0, 0.5, 0.5, 1.0), # Light Red
|
||||
SocketType.PhysicalAngle: (0.9, 0.45, 0.45, 1.0), # Medium Light Red
|
||||
SocketType.PhysicalLength: (0.8, 0.4, 0.4, 1.0), # Medium Red
|
||||
|
@ -425,6 +435,7 @@ SocketType_to_color = {
|
|||
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.PhysicalFreq: (1.0, 0.7, 0.5, 1.0), # Light Peach
|
||||
SocketType.PhysicalVacWL: (1.0, 0.7, 0.5, 1.0), # Light Peach
|
||||
SocketType.PhysicalSpecPowerDist: (0.9, 0.65, 0.45, 1.0), # Medium Light Peach
|
||||
SocketType.PhysicalSpecRelPermDist: (0.8, 0.6, 0.4, 1.0), # Medium Peach
|
||||
|
||||
|
@ -435,6 +446,7 @@ SocketType_to_color = {
|
|||
SocketType.BlenderVolume: (0.4, 0.35, 0.7, 1.0), # Medium Dark Purple
|
||||
SocketType.BlenderGeoNodes: (0.3, 0.3, 0.6, 1.0), # Dark Purple
|
||||
SocketType.BlenderText: (0.5, 0.5, 0.75, 1.0), # Light Lavender
|
||||
SocketType.BlenderPreviewTarget: (0.5, 0.5, 0.75, 1.0), # Light Lavender
|
||||
|
||||
# Maxwell
|
||||
SocketType.MaxwellSource: (1.0, 1.0, 0.5, 1.0), # Light Yellow
|
||||
|
@ -451,40 +463,104 @@ SocketType_to_color = {
|
|||
}
|
||||
|
||||
BLNodeSocket_to_SocketType = {
|
||||
"NodeSocketBool": SocketType.Bool,
|
||||
"NodeSocketCollection": SocketType.BlenderCollection,
|
||||
"NodeSocketColor": SocketType.Real3DVector,
|
||||
"NodeSocketFloat": SocketType.RealNumber,
|
||||
"NodeSocketFloatAngle": SocketType.RealNumber,
|
||||
"NodeSocketFloatDistance": SocketType.RealNumber,
|
||||
"NodeSocketFloatFactor": SocketType.RealNumber,
|
||||
"NodeSocketFloatPercentage": SocketType.RealNumber,
|
||||
"NodeSocketFloatTime": SocketType.RealNumber,
|
||||
"NodeSocketFloatTimeAbsolute": SocketType.RealNumber,
|
||||
"NodeSocketFloatUnsigned": SocketType.RealNumber,
|
||||
"NodeSocketGeometry": SocketType.Any,
|
||||
"NodeSocketImage": SocketType.BlenderImage,
|
||||
"NodeSocketInt": SocketType.IntegerNumber,
|
||||
"NodeSocketIntFactor": SocketType.IntegerNumber,
|
||||
"NodeSocketIntPercentage": SocketType.IntegerNumber,
|
||||
"NodeSocketIntUnsigned": SocketType.IntegerNumber,
|
||||
"NodeSocketMaterial": SocketType.Any,
|
||||
"NodeSocketObject": SocketType.BlenderObject,
|
||||
"NodeSocketRotation": SocketType.Real3DVector,
|
||||
"NodeSocketShader": SocketType.Any,
|
||||
"NodeSocketStandard": SocketType.Any,
|
||||
"NodeSocketString": SocketType.Text,
|
||||
"NodeSocketTexture": SocketType.Any,
|
||||
"NodeSocketVector": SocketType.Real3DVector,
|
||||
"NodeSocketVectorAcceleration": SocketType.Real3DVector,
|
||||
"NodeSocketVectorDirection": SocketType.Real3DVector,
|
||||
"NodeSocketVectorEuler": SocketType.Real3DVector,
|
||||
"NodeSocketVectorTranslation": SocketType.Real3DVector,
|
||||
"NodeSocketVectorVelocity": SocketType.Real3DVector,
|
||||
"NodeSocketVectorXYZ": SocketType.Real3DVector,
|
||||
"NodeSocketVirtual": SocketType.Any,
|
||||
1: {
|
||||
"NodeSocketStandard": SocketType.Any,
|
||||
"NodeSocketVirtual": SocketType.Any,
|
||||
"NodeSocketGeometry": SocketType.Any,
|
||||
"NodeSocketTexture": SocketType.Any,
|
||||
"NodeSocketShader": SocketType.Any,
|
||||
"NodeSocketMaterial": SocketType.Any,
|
||||
|
||||
"NodeSocketString": SocketType.Text,
|
||||
"NodeSocketBool": SocketType.Bool,
|
||||
"NodeSocketCollection": SocketType.BlenderCollection,
|
||||
"NodeSocketImage": SocketType.BlenderImage,
|
||||
"NodeSocketObject": SocketType.BlenderObject,
|
||||
|
||||
"NodeSocketFloat": SocketType.RealNumber,
|
||||
"NodeSocketFloatAngle": SocketType.PhysicalAngle,
|
||||
"NodeSocketFloatDistance": SocketType.PhysicalLength,
|
||||
"NodeSocketFloatFactor": SocketType.RealNumber,
|
||||
"NodeSocketFloatPercentage": SocketType.RealNumber,
|
||||
"NodeSocketFloatTime": SocketType.PhysicalTime,
|
||||
"NodeSocketFloatTimeAbsolute": SocketType.RealNumber,
|
||||
"NodeSocketFloatUnsigned": SocketType.RealNumber,
|
||||
|
||||
"NodeSocketInt": SocketType.IntegerNumber,
|
||||
"NodeSocketIntFactor": SocketType.IntegerNumber,
|
||||
"NodeSocketIntPercentage": SocketType.IntegerNumber,
|
||||
"NodeSocketIntUnsigned": SocketType.IntegerNumber,
|
||||
},
|
||||
2: {
|
||||
"NodeSocketVector": SocketType.Real3DVector,
|
||||
"NodeSocketVectorAcceleration": SocketType.Real3DVector,
|
||||
"NodeSocketVectorDirection": SocketType.Real3DVector,
|
||||
"NodeSocketVectorEuler": SocketType.Real3DVector,
|
||||
"NodeSocketVectorTranslation": SocketType.Real3DVector,
|
||||
"NodeSocketVectorVelocity": SocketType.Real3DVector,
|
||||
"NodeSocketVectorXYZ": SocketType.Real3DVector,
|
||||
#"NodeSocketVector": SocketType.Real2DVector,
|
||||
#"NodeSocketVectorAcceleration": SocketType.PhysicalAccel2D,
|
||||
#"NodeSocketVectorDirection": SocketType.PhysicalDir2D,
|
||||
#"NodeSocketVectorEuler": SocketType.PhysicalEuler2D,
|
||||
#"NodeSocketVectorTranslation": SocketType.PhysicalDispl2D,
|
||||
#"NodeSocketVectorVelocity": SocketType.PhysicalVel2D,
|
||||
#"NodeSocketVectorXYZ": SocketType.Real2DPoint,
|
||||
},
|
||||
3: {
|
||||
"NodeSocketRotation": SocketType.Real3DVector,
|
||||
|
||||
"NodeSocketColor": SocketType.Any,
|
||||
|
||||
"NodeSocketVector": SocketType.Real3DVector,
|
||||
#"NodeSocketVectorAcceleration": SocketType.PhysicalAccel3D,
|
||||
#"NodeSocketVectorDirection": SocketType.PhysicalDir3D,
|
||||
#"NodeSocketVectorEuler": SocketType.PhysicalEuler3D,
|
||||
#"NodeSocketVectorTranslation": SocketType.PhysicalDispl3D,
|
||||
"NodeSocketVectorTranslation": SocketType.PhysicalPoint3D,
|
||||
#"NodeSocketVectorVelocity": SocketType.PhysicalVel3D,
|
||||
"NodeSocketVectorXYZ": SocketType.PhysicalPoint3D,
|
||||
},
|
||||
}
|
||||
|
||||
BLNodeSocket_to_SocketType_by_desc = {
|
||||
1: {
|
||||
"Angle": SocketType.PhysicalAngle,
|
||||
|
||||
"Length": SocketType.PhysicalLength,
|
||||
"Area": SocketType.PhysicalArea,
|
||||
"Volume": SocketType.PhysicalVolume,
|
||||
|
||||
"Mass": SocketType.PhysicalMass,
|
||||
|
||||
"Speed": SocketType.PhysicalSpeed,
|
||||
"Accel": SocketType.PhysicalAccelScalar,
|
||||
"Force": SocketType.PhysicalForceScalar,
|
||||
|
||||
"Freq": SocketType.PhysicalFreq,
|
||||
},
|
||||
2: {
|
||||
#"2DCount": SocketType.Int2DVector,
|
||||
|
||||
#"2DPoint": SocketType.PhysicalPoint2D,
|
||||
#"2DSize": SocketType.PhysicalSize2D,
|
||||
#"2DPol": SocketType.PhysicalPol,
|
||||
"2DPoint": SocketType.PhysicalPoint3D,
|
||||
"2DSize": SocketType.PhysicalSize3D,
|
||||
},
|
||||
3: {
|
||||
#"Count": SocketType.Int3DVector,
|
||||
|
||||
"Point": SocketType.PhysicalPoint3D,
|
||||
"Size": SocketType.PhysicalSize3D,
|
||||
|
||||
#"Force": SocketType.PhysicalForce3D,
|
||||
|
||||
"Freq": SocketType.PhysicalSize3D,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
####################
|
||||
# - Node Types
|
||||
####################
|
||||
|
@ -493,15 +569,17 @@ class NodeType(BlenderTypeEnum):
|
|||
KitchenSink = enum.auto()
|
||||
|
||||
# Inputs
|
||||
UnitSystem = enum.auto()
|
||||
|
||||
## Inputs / Scene
|
||||
Time = enum.auto()
|
||||
UnitSystem = enum.auto()
|
||||
|
||||
## Inputs / Parameters
|
||||
NumberParameter = enum.auto()
|
||||
PhysicalParameter = enum.auto()
|
||||
|
||||
## Inputs / Constants
|
||||
WaveConstant = enum.auto()
|
||||
ScientificConstant = enum.auto()
|
||||
NumberConstant = enum.auto()
|
||||
PhysicalConstant = enum.auto()
|
||||
|
@ -517,6 +595,7 @@ class NodeType(BlenderTypeEnum):
|
|||
|
||||
# Outputs
|
||||
## Outputs / Viewers
|
||||
Viewer3D = enum.auto()
|
||||
ValueViewer = enum.auto()
|
||||
ConsoleViewer = enum.auto()
|
||||
|
||||
|
@ -612,8 +691,13 @@ class NodeType(BlenderTypeEnum):
|
|||
|
||||
|
||||
# Utilities
|
||||
Combine = enum.auto()
|
||||
Separate = enum.auto()
|
||||
Math = enum.auto()
|
||||
|
||||
## Utilities / Converters
|
||||
WaveConverter = enum.auto()
|
||||
|
||||
## Utilities / Operations
|
||||
ArrayOperation = enum.auto()
|
||||
|
||||
|
@ -663,6 +747,7 @@ class NodeCategory(BlenderTypeEnum):
|
|||
|
||||
# Utilities/
|
||||
MAXWELLSIM_UTILITIES = enum.auto()
|
||||
MAXWELLSIM_UTILITIES_CONVERTERS = enum.auto()
|
||||
MAXWELLSIM_UTILITIES_OPERATIONS = enum.auto()
|
||||
|
||||
@classmethod
|
||||
|
@ -727,6 +812,7 @@ NodeCategory_to_category_label = {
|
|||
|
||||
# Utilities/
|
||||
NodeCategory.MAXWELLSIM_UTILITIES: "Utilities",
|
||||
NodeCategory.MAXWELLSIM_UTILITIES_CONVERTERS: "Converters",
|
||||
NodeCategory.MAXWELLSIM_UTILITIES_OPERATIONS: "Operations",
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,25 @@ from . import contracts
|
|||
|
||||
ICON_SIM_TREE = 'MOD_SIMPLEDEFORM'
|
||||
|
||||
|
||||
class BLENDER_MAXWELL_PT_MaxwellSimTreePanel(bpy.types.Panel):
|
||||
bl_label = "Node Tree Custom Prop"
|
||||
bl_idname = "NODE_PT_custom_prop"
|
||||
bl_space_type = 'NODE_EDITOR'
|
||||
bl_region_type = 'UI'
|
||||
bl_category = 'Item'
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.space_data.tree_type == contracts.TreeType.MaxwellSim.value
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
node_tree = context.space_data.node_tree
|
||||
|
||||
layout.prop(node_tree, "preview_collection")
|
||||
layout.prop(node_tree, "non_preview_collection")
|
||||
|
||||
####################
|
||||
# - Node Tree Definition
|
||||
####################
|
||||
|
@ -12,6 +31,22 @@ class MaxwellSimTree(bpy.types.NodeTree):
|
|||
bl_label = "Maxwell Sim Editor"
|
||||
bl_icon = contracts.Icon.MaxwellSimTree
|
||||
|
||||
preview_collection: bpy.props.PointerProperty(
|
||||
name="Preview Collection",
|
||||
description="Collection of Blender objects that will be previewed",
|
||||
type=bpy.types.Collection,
|
||||
update=(lambda self, context: self.trigger_updates())
|
||||
)
|
||||
non_preview_collection: bpy.props.PointerProperty(
|
||||
name="Non-Preview Collection",
|
||||
description="Collection of Blender objects that will NOT be previewed",
|
||||
type=bpy.types.Collection,
|
||||
update=(lambda self, context: self.trigger_updates())
|
||||
)
|
||||
|
||||
def trigger_updates(self):
|
||||
pass
|
||||
|
||||
####################
|
||||
# - Blender Registration
|
||||
####################
|
||||
|
|
|
@ -165,14 +165,19 @@ class MaxwellSimTreeNode(bpy.types.Node):
|
|||
if output_socket_set_key not in socket_set_keys
|
||||
]
|
||||
|
||||
def labeller(socket_set_key):
|
||||
return " ".join(
|
||||
word.capitalize()
|
||||
for word in socket_set_key.split("_")
|
||||
)
|
||||
cls.__annotations__["socket_set"] = bpy.props.EnumProperty(
|
||||
name="",
|
||||
description="Select a node socket configuration",
|
||||
items=[
|
||||
(
|
||||
socket_set_key,
|
||||
socket_set_key.capitalize(),
|
||||
socket_set_key.capitalize(),
|
||||
labeller(socket_set_key),
|
||||
labeller(socket_set_key),
|
||||
)
|
||||
for socket_set_key in socket_set_keys
|
||||
],
|
||||
|
@ -217,32 +222,28 @@ class MaxwellSimTreeNode(bpy.types.Node):
|
|||
`NodeTypeProtocol` specification, and initializes each as described
|
||||
by user-provided `SocketDefProtocol`s.
|
||||
"""
|
||||
# Initialize Input Sockets
|
||||
# Create Input Sockets
|
||||
for socket_name, socket_def in self.input_sockets.items():
|
||||
self.inputs.new(
|
||||
socket_def.socket_type.value, ## strenum.value => a real str
|
||||
socket_def.socket_type.value,
|
||||
socket_def.label,
|
||||
)
|
||||
|
||||
# Retrieve the Blender Socket (bpy.types.NodeSocket)
|
||||
## We could use self.g_input_bl_socket()...
|
||||
## ...but that would rely on implicit semi-initialized state.
|
||||
bl_socket = self.inputs[
|
||||
self.input_sockets[socket_name].label
|
||||
]
|
||||
|
||||
# Initialize the Socket from the Socket Definition
|
||||
## `bl_socket` knows whether it's an input or output socket...
|
||||
## ...via its `.is_output` attribute.
|
||||
socket_def.init(bl_socket)
|
||||
|
||||
# Initialize Output Sockets
|
||||
# Create Output Sockets
|
||||
for socket_name, socket_def in self.output_sockets.items():
|
||||
self.outputs.new(
|
||||
socket_def.socket_type.value,
|
||||
socket_def.label,
|
||||
)
|
||||
|
||||
# Initialize Sockets
|
||||
for socket_name, socket_def in self.input_sockets.items():
|
||||
bl_socket = self.inputs[
|
||||
self.input_sockets[socket_name].label
|
||||
]
|
||||
socket_def.init(bl_socket)
|
||||
|
||||
for socket_name, socket_def in self.output_sockets.items():
|
||||
bl_socket = self.outputs[
|
||||
self.output_sockets[socket_name].label
|
||||
]
|
||||
|
@ -274,6 +275,9 @@ class MaxwellSimTreeNode(bpy.types.Node):
|
|||
if self.preset is not None:
|
||||
sync_selected_preset(self)
|
||||
|
||||
if hasattr(self, "init_cb"):
|
||||
self.init_cb()
|
||||
|
||||
@classmethod
|
||||
def poll(cls, ntree: bpy.types.NodeTree) -> bool:
|
||||
"""This class method controls whether a node can be instantiated
|
||||
|
@ -366,6 +370,12 @@ class MaxwellSimTreeNode(bpy.types.Node):
|
|||
if hasattr(self, "draw_operators"):
|
||||
self.draw_operators(context, layout)
|
||||
|
||||
if hasattr(self, "draw_props"):
|
||||
self.draw_props(context, layout)
|
||||
|
||||
if hasattr(self, "draw_info"):
|
||||
self.draw_info(context, layout)
|
||||
|
||||
####################
|
||||
# - Socket Getters
|
||||
####################
|
||||
|
@ -392,13 +402,12 @@ class MaxwellSimTreeNode(bpy.types.Node):
|
|||
return self.inputs[self.input_sockets[input_socket_name].label]
|
||||
|
||||
elif hasattr(self, "socket_set"):
|
||||
# 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
|
||||
if socket_set == self.socket_set
|
||||
)]
|
||||
|
||||
def g_output_bl_socket(
|
||||
|
@ -436,21 +445,21 @@ class MaxwellSimTreeNode(bpy.types.Node):
|
|||
self,
|
||||
output_bl_socket_name: contracts.BLSocketName,
|
||||
) -> contracts.SocketName:
|
||||
output_socket_names = [
|
||||
output_socket_name
|
||||
for output_socket_name in self.output_sockets.keys()
|
||||
if self.output_sockets[
|
||||
output_socket_name
|
||||
].label == output_bl_socket_name
|
||||
]
|
||||
if hasattr(self, "socket_set"):
|
||||
return next(
|
||||
output_socket_names += [
|
||||
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(
|
||||
output_socket_name
|
||||
for output_socket_name in self.output_sockets.keys()
|
||||
if self.output_sockets[
|
||||
output_socket_name
|
||||
].label == output_bl_socket_name
|
||||
)
|
||||
]
|
||||
return output_socket_names[0]
|
||||
|
||||
####################
|
||||
# - Socket Setters
|
||||
|
|
|
@ -1,5 +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 BoundBoxNode(base.MaxwellSimTreeNode):
|
||||
node_type = contracts.NodeType.BoundBox
|
||||
bl_label = "Bound Box"
|
||||
#bl_icon = ...
|
||||
|
||||
####################
|
||||
# - Sockets
|
||||
####################
|
||||
input_sockets = {
|
||||
"x_pos": sockets.MaxwellBoundFaceSocketDef(
|
||||
label="+x",
|
||||
),
|
||||
"x_neg": sockets.MaxwellBoundFaceSocketDef(
|
||||
label="-x",
|
||||
),
|
||||
"y_pos": sockets.MaxwellBoundFaceSocketDef(
|
||||
label="+y",
|
||||
),
|
||||
"y_neg": sockets.MaxwellBoundFaceSocketDef(
|
||||
label="-y",
|
||||
),
|
||||
"z_pos": sockets.MaxwellBoundFaceSocketDef(
|
||||
label="+z",
|
||||
),
|
||||
"z_neg": sockets.MaxwellBoundFaceSocketDef(
|
||||
label="-z",
|
||||
),
|
||||
}
|
||||
output_sockets = {
|
||||
"bound": sockets.MaxwellBoundBoxSocketDef(
|
||||
label="Bound",
|
||||
),
|
||||
}
|
||||
|
||||
####################
|
||||
# - Output Socket Computation
|
||||
####################
|
||||
@base.computes_output_socket("bound")
|
||||
def compute_simulation(self: contracts.NodeTypeProtocol) -> td.BoundarySpec:
|
||||
x_pos = self.compute_input("x_pos")
|
||||
x_neg = self.compute_input("x_neg")
|
||||
y_pos = self.compute_input("x_pos")
|
||||
y_neg = self.compute_input("x_neg")
|
||||
z_pos = self.compute_input("x_pos")
|
||||
z_neg = self.compute_input("x_neg")
|
||||
|
||||
return td.BoundarySpec(
|
||||
x=td.Boundary(
|
||||
plus=x_pos,
|
||||
minus=x_neg,
|
||||
),
|
||||
y=td.Boundary(
|
||||
plus=y_pos,
|
||||
minus=y_neg,
|
||||
),
|
||||
z=td.Boundary(
|
||||
plus=z_pos,
|
||||
minus=z_neg,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
|
||||
####################
|
||||
# - Blender Registration
|
||||
####################
|
||||
BL_REGISTER = []
|
||||
BL_NODES = {}
|
||||
BL_REGISTER = [
|
||||
BoundBoxNode,
|
||||
]
|
||||
BL_NODES = {
|
||||
contracts.NodeType.BoundBox: (
|
||||
contracts.NodeCategory.MAXWELLSIM_BOUNDS
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,17 +1,20 @@
|
|||
from . import unit_system
|
||||
|
||||
from . import constants
|
||||
from . import lists
|
||||
from . import parameters
|
||||
from . import scene
|
||||
|
||||
BL_REGISTER = [
|
||||
*unit_system.BL_REGISTER,
|
||||
|
||||
*scene.BL_REGISTER,
|
||||
*constants.BL_REGISTER,
|
||||
*parameters.BL_REGISTER,
|
||||
*lists.BL_REGISTER,
|
||||
]
|
||||
BL_NODES = {
|
||||
**unit_system.BL_NODES,
|
||||
|
||||
**scene.BL_NODES,
|
||||
**constants.BL_NODES,
|
||||
**parameters.BL_NODES,
|
||||
**lists.BL_NODES,
|
||||
}
|
||||
|
|
|
@ -1,17 +1,23 @@
|
|||
from . import number_constant
|
||||
from . import blender_constant
|
||||
from . import physical_constant
|
||||
from . import wave_constant
|
||||
from . import scientific_constant
|
||||
|
||||
from . import number_constant
|
||||
from . import physical_constant
|
||||
from . import blender_constant
|
||||
|
||||
BL_REGISTER = [
|
||||
*wave_constant.BL_REGISTER,
|
||||
*scientific_constant.BL_REGISTER,
|
||||
|
||||
*number_constant.BL_REGISTER,
|
||||
*blender_constant.BL_REGISTER,
|
||||
*physical_constant.BL_REGISTER,
|
||||
*blender_constant.BL_REGISTER,
|
||||
]
|
||||
BL_NODES = {
|
||||
**wave_constant.BL_NODES,
|
||||
**scientific_constant.BL_NODES,
|
||||
|
||||
**number_constant.BL_NODES,
|
||||
**blender_constant.BL_NODES,
|
||||
**physical_constant.BL_NODES,
|
||||
**blender_constant.BL_NODES,
|
||||
}
|
||||
|
|
|
@ -1,5 +1,68 @@
|
|||
import typing as typ
|
||||
|
||||
from .... import contracts
|
||||
from .... import sockets
|
||||
from ... import base
|
||||
|
||||
class BlenderConstantNode(base.MaxwellSimTreeNode):
|
||||
node_type = contracts.NodeType.BlenderConstant
|
||||
|
||||
bl_label = "Blender Constant"
|
||||
#bl_icon = constants.ICON_SIM_INPUT
|
||||
|
||||
input_sockets = {}
|
||||
input_socket_sets = {
|
||||
"object": {
|
||||
"value": sockets.BlenderObjectSocketDef(
|
||||
label="Object",
|
||||
),
|
||||
},
|
||||
"collection": {
|
||||
"value": sockets.BlenderCollectionSocketDef(
|
||||
label="Collection",
|
||||
),
|
||||
},
|
||||
"image": {
|
||||
"value": sockets.BlenderImageSocketDef(
|
||||
label="Image",
|
||||
),
|
||||
},
|
||||
"volume": {
|
||||
"value": sockets.BlenderVolumeSocketDef(
|
||||
label="Volume",
|
||||
),
|
||||
},
|
||||
"text": {
|
||||
"value": sockets.BlenderTextSocketDef(
|
||||
label="Text",
|
||||
),
|
||||
},
|
||||
"geonodes": {
|
||||
"value": sockets.BlenderGeoNodesSocketDef(
|
||||
label="GeoNodes",
|
||||
),
|
||||
},
|
||||
}
|
||||
output_sockets = {}
|
||||
output_socket_sets = input_socket_sets
|
||||
|
||||
####################
|
||||
# - Callbacks
|
||||
####################
|
||||
@base.computes_output_socket("value")
|
||||
def compute_value(self: contracts.NodeTypeProtocol) -> typ.Any:
|
||||
return self.compute_input("value")
|
||||
|
||||
|
||||
|
||||
####################
|
||||
# - Blender Registration
|
||||
####################
|
||||
BL_REGISTER = []
|
||||
BL_NODES = {}
|
||||
BL_REGISTER = [
|
||||
BlenderConstantNode,
|
||||
]
|
||||
BL_NODES = {
|
||||
contracts.NodeType.BlenderConstant: (
|
||||
contracts.NodeCategory.MAXWELLSIM_INPUTS_CONSTANTS
|
||||
)
|
||||
}
|
||||
|
|
|
@ -13,6 +13,11 @@ class NumberConstantNode(base.MaxwellSimTreeNode):
|
|||
|
||||
input_sockets = {}
|
||||
input_socket_sets = {
|
||||
"integer": {
|
||||
"value": sockets.IntegerNumberSocketDef(
|
||||
label="Integer",
|
||||
),
|
||||
},
|
||||
"real": {
|
||||
"value": sockets.RealNumberSocketDef(
|
||||
label="Real",
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
import bpy
|
||||
import sympy as sp
|
||||
import sympy.physics.units as spu
|
||||
import scipy as sc
|
||||
|
||||
from .... import contracts
|
||||
from .... import sockets
|
||||
from ... import base
|
||||
|
||||
vac_speed_of_light = (
|
||||
sc.constants.speed_of_light
|
||||
* spu.meter/spu.second
|
||||
)
|
||||
|
||||
class WaveConstantNode(base.MaxwellSimTreeNode):
|
||||
node_type = contracts.NodeType.WaveConstant
|
||||
|
||||
bl_label = "Wave Constant"
|
||||
|
||||
input_sockets = {}
|
||||
input_socket_sets = {
|
||||
"vac_wl": {
|
||||
"vac_wl": sockets.PhysicalVacWLSocketDef(
|
||||
label="Vac WL",
|
||||
),
|
||||
},
|
||||
"freq": {
|
||||
"freq": sockets.PhysicalFreqSocketDef(
|
||||
label="Freq",
|
||||
),
|
||||
},
|
||||
}
|
||||
output_sockets = {
|
||||
"vac_wl": sockets.PhysicalVacWLSocketDef(
|
||||
label="Vac WL",
|
||||
),
|
||||
"freq": sockets.PhysicalVacWLSocketDef(
|
||||
label="Freq",
|
||||
),
|
||||
}
|
||||
output_socket_sets = {}
|
||||
|
||||
####################
|
||||
# - Callbacks
|
||||
####################
|
||||
@base.computes_output_socket("vac_wl")
|
||||
def compute_vac_wl(self: contracts.NodeTypeProtocol) -> sp.Expr:
|
||||
if self.socket_set == "vac_wl":
|
||||
return self.compute_input("vac_wl")
|
||||
|
||||
elif self.socket_set == "freq":
|
||||
freq = self.compute_input("freq")
|
||||
return spu.convert_to(
|
||||
vac_speed_of_light / freq,
|
||||
spu.meter,
|
||||
)
|
||||
|
||||
raise ValueError("No valid socket set.")
|
||||
|
||||
@base.computes_output_socket("freq")
|
||||
def compute_freq(self: contracts.NodeTypeProtocol) -> sp.Expr:
|
||||
if self.socket_set == "vac_wl":
|
||||
vac_wl = self.compute_input("vac_wl")
|
||||
return spu.convert_to(
|
||||
vac_speed_of_light / vac_wl,
|
||||
spu.hertz,
|
||||
)
|
||||
|
||||
elif self.socket_set == "freq":
|
||||
return self.compute_input("freq")
|
||||
|
||||
raise ValueError("No valid socket set.")
|
||||
|
||||
|
||||
|
||||
####################
|
||||
# - Blender Registration
|
||||
####################
|
||||
BL_REGISTER = [
|
||||
WaveConstantNode,
|
||||
]
|
||||
BL_NODES = {
|
||||
contracts.NodeType.WaveConstant: (
|
||||
contracts.NodeCategory.MAXWELLSIM_INPUTS_CONSTANTS
|
||||
)
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
from . import number_parameter
|
||||
from . import physical_parameter
|
||||
|
||||
BL_REGISTER = [
|
||||
*number_parameter.BL_REGISTER,
|
||||
*physical_parameter.BL_REGISTER,
|
||||
]
|
||||
BL_NODES = {
|
||||
**number_parameter.BL_NODES,
|
||||
**physical_parameter.BL_NODES,
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
####################
|
||||
# - Blender Registration
|
||||
####################
|
||||
BL_REGISTER = []
|
||||
BL_NODES = {}
|
|
@ -1,5 +0,0 @@
|
|||
####################
|
||||
# - Blender Registration
|
||||
####################
|
||||
BL_REGISTER = []
|
||||
BL_NODES = {}
|
|
@ -0,0 +1,44 @@
|
|||
import bpy
|
||||
import sympy as sp
|
||||
|
||||
from ... import contracts
|
||||
from ... import sockets
|
||||
from .. import base
|
||||
|
||||
class PhysicalUnitSystemNode(base.MaxwellSimTreeNode):
|
||||
node_type = contracts.NodeType.UnitSystem
|
||||
|
||||
bl_label = "Unit System Constant"
|
||||
|
||||
input_sockets = {
|
||||
"unit_system": sockets.PhysicalUnitSystemSocketDef(
|
||||
label="Unit System",
|
||||
show_by_default=True,
|
||||
),
|
||||
}
|
||||
output_sockets = {
|
||||
"unit_system": sockets.PhysicalUnitSystemSocketDef(
|
||||
label="Unit System",
|
||||
),
|
||||
}
|
||||
|
||||
####################
|
||||
# - Callbacks
|
||||
####################
|
||||
@base.computes_output_socket("unit_system")
|
||||
def compute_value(self: contracts.NodeTypeProtocol) -> sp.Expr:
|
||||
return self.compute_input("unit_system")
|
||||
|
||||
|
||||
|
||||
####################
|
||||
# - Blender Registration
|
||||
####################
|
||||
BL_REGISTER = [
|
||||
PhysicalUnitSystemNode,
|
||||
]
|
||||
BL_NODES = {
|
||||
contracts.NodeType.UnitSystem: (
|
||||
contracts.NodeCategory.MAXWELLSIM_INPUTS
|
||||
)
|
||||
}
|
|
@ -1,6 +1,80 @@
|
|||
import tidy3d as td
|
||||
import sympy as sp
|
||||
import sympy.physics.units as spu
|
||||
|
||||
from ... import contracts
|
||||
from ... import sockets
|
||||
from .. import base
|
||||
|
||||
class DrudeLorentzMediumNode(base.MaxwellSimTreeNode):
|
||||
node_type = contracts.NodeType.DrudeLorentzMedium
|
||||
|
||||
bl_label = "Drude-Lorentz Medium"
|
||||
#bl_icon = ...
|
||||
|
||||
####################
|
||||
# - Sockets
|
||||
####################
|
||||
input_sockets = {
|
||||
"eps_inf": sockets.RealNumberSocketDef(
|
||||
label=f"εr_∞",
|
||||
),
|
||||
} | {
|
||||
f"del_eps{i}": sockets.RealNumberSocketDef(
|
||||
label=f"Δεr_{i}",
|
||||
)
|
||||
for i in [1, 2, 3]
|
||||
} | {
|
||||
f"f{i}": sockets.PhysicalFreqSocketDef(
|
||||
label=f"f_{i}",
|
||||
)
|
||||
for i in [1, 2, 3]
|
||||
} | {
|
||||
f"delta{i}": sockets.PhysicalFreqSocketDef(
|
||||
label=f"δ_{i}",
|
||||
)
|
||||
for i in [1, 2, 3]
|
||||
}
|
||||
output_sockets = {
|
||||
"medium": sockets.MaxwellMediumSocketDef(
|
||||
label="Medium"
|
||||
),
|
||||
}
|
||||
|
||||
####################
|
||||
# - Output Socket Computation
|
||||
####################
|
||||
@base.computes_output_socket("medium")
|
||||
def compute_medium(self: contracts.NodeTypeProtocol) -> td.Sellmeier:
|
||||
## Retrieval
|
||||
return td.Lorentz(
|
||||
eps_inf=self.compute_input(f"eps_inf"),
|
||||
coeffs = [
|
||||
(
|
||||
self.compute_input(f"del_eps{i}"),
|
||||
spu.convert_to(
|
||||
self.compute_input(f"f{i}"),
|
||||
spu.hertz,
|
||||
) / spu.hertz,
|
||||
spu.convert_to(
|
||||
self.compute_input(f"delta{i}"),
|
||||
spu.hertz,
|
||||
) / spu.hertz,
|
||||
)
|
||||
for i in [1, 2, 3]
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
|
||||
####################
|
||||
# - Blender Registration
|
||||
####################
|
||||
BL_REGISTER = []
|
||||
BL_NODES = {}
|
||||
|
||||
BL_REGISTER = [
|
||||
DrudeLorentzMediumNode,
|
||||
]
|
||||
BL_NODES = {
|
||||
contracts.NodeType.DrudeLorentzMedium: (
|
||||
contracts.NodeCategory.MAXWELLSIM_MEDIUMS
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,161 @@
|
|||
import bpy
|
||||
import tidy3d as td
|
||||
import sympy as sp
|
||||
import sympy.physics.units as spu
|
||||
import numpy as np
|
||||
import scipy as sc
|
||||
|
||||
from .....utils import extra_sympy_units as spuex
|
||||
from ... import contracts
|
||||
from ... import sockets
|
||||
from .. import base
|
||||
|
||||
class ExperimentOperator00(bpy.types.Operator):
|
||||
bl_idname = "blender_maxwell.experiment_operator_00"
|
||||
bl_label = "exp"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return True
|
||||
|
||||
def execute(self, context):
|
||||
node = context.node
|
||||
node.invoke_matplotlib_and_update_image()
|
||||
return {'FINISHED'}
|
||||
|
||||
class LibraryMediumNode(base.MaxwellSimTreeNode):
|
||||
node_type = contracts.NodeType.LibraryMedium
|
||||
|
||||
bl_label = "Library Medium"
|
||||
#bl_icon = ...
|
||||
|
||||
####################
|
||||
# - Sockets
|
||||
####################
|
||||
input_sockets = {}
|
||||
output_sockets = {
|
||||
"medium": sockets.MaxwellMediumSocketDef(
|
||||
label="Medium"
|
||||
),
|
||||
}
|
||||
|
||||
####################
|
||||
# - Properties
|
||||
####################
|
||||
material: bpy.props.EnumProperty(
|
||||
name="",
|
||||
description="",
|
||||
#icon="NODE_MATERIAL",
|
||||
items=[
|
||||
(
|
||||
mat_key,
|
||||
td.material_library[mat_key].name,
|
||||
", ".join([
|
||||
ref.journal
|
||||
for ref in td.material_library[mat_key].variants[
|
||||
td.material_library[mat_key].default
|
||||
].reference
|
||||
])
|
||||
)
|
||||
for mat_key in td.material_library
|
||||
if mat_key != "graphene" ## For some reason, it's unique...
|
||||
],
|
||||
default="Au",
|
||||
update=(lambda self,context: self.update()),
|
||||
)
|
||||
|
||||
####################
|
||||
# - UI
|
||||
####################
|
||||
def draw_props(self, context, layout):
|
||||
layout.prop(self, "material", text="")
|
||||
|
||||
def draw_info(self, context, layout):
|
||||
layout.operator(ExperimentOperator00.bl_idname, text="Experiment")
|
||||
vac_speed_of_light = sc.constants.speed_of_light * spu.meter/spu.second
|
||||
|
||||
mat = td.material_library[self.material]
|
||||
freq_range = [
|
||||
spu.convert_to(
|
||||
val * spu.hertz,
|
||||
spuex.terahertz,
|
||||
) / spuex.terahertz
|
||||
for val in mat.medium.frequency_range
|
||||
]
|
||||
nm_range = [
|
||||
spu.convert_to(
|
||||
vac_speed_of_light / (val * spu.hertz),
|
||||
spu.nanometer,
|
||||
) / spu.nanometer
|
||||
for val in mat.medium.frequency_range
|
||||
]
|
||||
|
||||
layout.label(text=f"nm: [{nm_range[1].n(2)}, {nm_range[0].n(2)}]")
|
||||
layout.label(text=f"THz: [{freq_range[0].n(2)}, {freq_range[1].n(2)}]")
|
||||
|
||||
####################
|
||||
# - Output Socket Computation
|
||||
####################
|
||||
@base.computes_output_socket("medium")
|
||||
def compute_medium(self: contracts.NodeTypeProtocol) -> td.AbstractMedium:
|
||||
return td.material_library[self.material].medium
|
||||
|
||||
####################
|
||||
# - Experiment
|
||||
####################
|
||||
def invoke_matplotlib_and_update_image(self):
|
||||
import matplotlib.pyplot as plt
|
||||
mat = td.material_library[self.material]
|
||||
|
||||
aspect_ratio = 1.0
|
||||
for area in bpy.context.screen.areas:
|
||||
if area.type == 'IMAGE_EDITOR':
|
||||
width = area.width
|
||||
height = area.height
|
||||
aspect_ratio = width / height
|
||||
|
||||
# Generate a plot with matplotlib
|
||||
fig_width = 6
|
||||
fig_height = fig_width / aspect_ratio
|
||||
fig, ax = plt.subplots(figsize=(fig_width, fig_height))
|
||||
ax.set_aspect(aspect_ratio)
|
||||
mat.medium.plot(
|
||||
np.linspace(*mat.medium.frequency_range[:2], 50),
|
||||
ax=ax,
|
||||
)
|
||||
|
||||
# Save the plot to a temporary file
|
||||
temp_plot_file = bpy.path.abspath('//temp_plot.png')
|
||||
fig.savefig(temp_plot_file, bbox_inches='tight')
|
||||
plt.close(fig) # Close the figure to free up memory
|
||||
|
||||
# Load or reload the image in Blender
|
||||
if "matplotlib_plot" in bpy.data.images:
|
||||
image = bpy.data.images["matplotlib_plot"]
|
||||
image.reload()
|
||||
else:
|
||||
image = bpy.data.images.load(temp_plot_file)
|
||||
image.name = "matplotlib_plot"
|
||||
|
||||
# Write the plot to an image datablock in Blender
|
||||
for area in bpy.context.screen.areas:
|
||||
if area.type == 'IMAGE_EDITOR':
|
||||
for space in area.spaces:
|
||||
if space.type == 'IMAGE_EDITOR':
|
||||
space.image = image
|
||||
return True
|
||||
|
||||
|
||||
|
||||
####################
|
||||
# - Blender Registration
|
||||
####################
|
||||
BL_REGISTER = []
|
||||
BL_NODES = {}
|
||||
BL_REGISTER = [
|
||||
ExperimentOperator00,
|
||||
LibraryMediumNode,
|
||||
]
|
||||
BL_NODES = {
|
||||
contracts.NodeType.LibraryMedium: (
|
||||
contracts.NodeCategory.MAXWELLSIM_MEDIUMS
|
||||
)
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ from pathlib import Path
|
|||
import bpy
|
||||
import sympy as sp
|
||||
import pydantic as pyd
|
||||
import tidy3d as td
|
||||
|
||||
from .... import contracts
|
||||
from .... import sockets
|
||||
|
@ -26,6 +27,19 @@ class JSONFileExporterPrintJSON(bpy.types.Operator):
|
|||
print(node.linked_data_as_json())
|
||||
return {'FINISHED'}
|
||||
|
||||
class JSONFileExporterMeshData(bpy.types.Operator):
|
||||
bl_idname = "blender_maxwell.json_file_exporter_mesh_data"
|
||||
bl_label = "Print any mesh data linked into a JSONFileExporterNode."
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return True
|
||||
|
||||
def execute(self, context):
|
||||
node = context.node
|
||||
print(node.linked_mesh_data())
|
||||
return {'FINISHED'}
|
||||
|
||||
class JSONFileExporterSaveJSON(bpy.types.Operator):
|
||||
bl_idname = "blender_maxwell.json_file_exporter_save_json"
|
||||
bl_label = "Save the JSON of what's linked into a JSONFileExporterNode."
|
||||
|
@ -69,6 +83,7 @@ class JSONFileExporterNode(base.MaxwellSimTreeNode):
|
|||
) -> None:
|
||||
layout.operator(JSONFileExporterPrintJSON.bl_idname, text="Print")
|
||||
layout.operator(JSONFileExporterSaveJSON.bl_idname, text="Save")
|
||||
layout.operator(JSONFileExporterMeshData.bl_idname, text="Mesh Info")
|
||||
|
||||
####################
|
||||
# - Methods
|
||||
|
@ -85,10 +100,16 @@ class JSONFileExporterNode(base.MaxwellSimTreeNode):
|
|||
elif isinstance(data, pyd.BaseModel):
|
||||
return data.model_dump_json()
|
||||
|
||||
# Finally: Try json.dumps (might fail)
|
||||
else:
|
||||
json.dumps(data)
|
||||
|
||||
def linked_mesh_data(self) -> str | None:
|
||||
if self.g_input_bl_socket("data").is_linked:
|
||||
data: typ.Any = self.compute_input("data")
|
||||
|
||||
if isinstance(data, td.Structure):
|
||||
return data.geometry
|
||||
|
||||
def export_data_as_json(self) -> None:
|
||||
if (data := self.linked_data_as_json()):
|
||||
data_dict = json.loads(data)
|
||||
|
@ -101,8 +122,9 @@ class JSONFileExporterNode(base.MaxwellSimTreeNode):
|
|||
####################
|
||||
BL_REGISTER = [
|
||||
JSONFileExporterPrintJSON,
|
||||
JSONFileExporterNode,
|
||||
JSONFileExporterMeshData,
|
||||
JSONFileExporterSaveJSON,
|
||||
JSONFileExporterNode,
|
||||
]
|
||||
BL_NODES = {
|
||||
contracts.NodeType.JSONFileExporter: (
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
from . import viewer_3d
|
||||
from . import value_viewer
|
||||
from . import console_viewer
|
||||
|
||||
BL_REGISTER = [
|
||||
*viewer_3d.BL_REGISTER,
|
||||
*value_viewer.BL_REGISTER,
|
||||
*console_viewer.BL_REGISTER,
|
||||
]
|
||||
BL_NODES = {
|
||||
**viewer_3d.BL_NODES,
|
||||
**value_viewer.BL_NODES,
|
||||
**console_viewer.BL_NODES,
|
||||
}
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
import typing as typ
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import bpy
|
||||
import sympy as sp
|
||||
import pydantic as pyd
|
||||
import tidy3d as td
|
||||
|
||||
from .... import contracts
|
||||
from .... import sockets
|
||||
from ... import base
|
||||
|
||||
INTERNAL_GEONODES = {
|
||||
|
||||
}
|
||||
|
||||
####################
|
||||
# - Node
|
||||
####################
|
||||
class Viewer3DNode(base.MaxwellSimTreeNode):
|
||||
node_type = contracts.NodeType.Viewer3D
|
||||
|
||||
bl_label = "3D Viewer"
|
||||
|
||||
input_sockets = {
|
||||
"data": sockets.AnySocketDef(
|
||||
label="Data",
|
||||
),
|
||||
}
|
||||
output_sockets = {}
|
||||
|
||||
####################
|
||||
# - Update
|
||||
####################
|
||||
def update_cb(self):
|
||||
pass
|
||||
|
||||
|
||||
####################
|
||||
# - Blender Registration
|
||||
####################
|
||||
BL_REGISTER = [
|
||||
Viewer3DNode,
|
||||
]
|
||||
BL_NODES = {
|
||||
contracts.NodeType.Viewer3D: (
|
||||
contracts.NodeCategory.MAXWELLSIM_OUTPUTS_VIEWERS
|
||||
)
|
||||
}
|
|
@ -19,8 +19,8 @@ class FDTDSimNode(base.MaxwellSimTreeNode):
|
|||
"run_time": sockets.PhysicalTimeSocketDef(
|
||||
label="Run Time",
|
||||
),
|
||||
"size": sockets.PhysicalSize3DSocketDef(
|
||||
label="Size",
|
||||
"domain": sockets.PhysicalSize3DSocketDef(
|
||||
label="Domain",
|
||||
),
|
||||
"ambient_medium": sockets.MaxwellMediumSocketDef(
|
||||
label="Ambient Medium",
|
||||
|
@ -37,7 +37,7 @@ class FDTDSimNode(base.MaxwellSimTreeNode):
|
|||
}
|
||||
output_sockets = {
|
||||
"fdtd_sim": sockets.MaxwellFDTDSimSocketDef(
|
||||
label="Medium",
|
||||
label="FDTD Sim",
|
||||
),
|
||||
}
|
||||
|
||||
|
@ -47,17 +47,17 @@ class FDTDSimNode(base.MaxwellSimTreeNode):
|
|||
@base.computes_output_socket("fdtd_sim")
|
||||
def compute_simulation(self: contracts.NodeTypeProtocol) -> td.Simulation:
|
||||
_run_time = self.compute_input("run_time")
|
||||
_size = self.compute_input("size")
|
||||
_domain = self.compute_input("domain")
|
||||
ambient_medium = self.compute_input("ambient_medium")
|
||||
structures = [self.compute_input("structure")]
|
||||
sources = [self.compute_input("source")]
|
||||
bound = self.compute_input("bound")
|
||||
|
||||
run_time = spu.convert_to(_run_time, spu.second) / spu.second
|
||||
size = tuple(spu.convert_to(_size, spu.um) / spu.um)
|
||||
domain = tuple(spu.convert_to(_domain, spu.um) / spu.um)
|
||||
|
||||
return td.Simulation(
|
||||
size=size,
|
||||
size=domain,
|
||||
medium=ambient_medium,
|
||||
structures=structures,
|
||||
sources=sources,
|
||||
|
|
|
@ -1,6 +1,94 @@
|
|||
import math
|
||||
|
||||
import tidy3d as td
|
||||
import sympy as sp
|
||||
import sympy.physics.units as spu
|
||||
|
||||
from ... import contracts
|
||||
from ... import sockets
|
||||
from .. import base
|
||||
|
||||
class PlaneWaveSourceNode(base.MaxwellSimTreeNode):
|
||||
node_type = contracts.NodeType.PlaneWaveSource
|
||||
|
||||
bl_label = "Plane Wave Source"
|
||||
#bl_icon = ...
|
||||
|
||||
####################
|
||||
# - Sockets
|
||||
####################
|
||||
input_sockets = {
|
||||
"temporal_shape": sockets.MaxwellTemporalShapeSocketDef(
|
||||
label="Temporal Shape",
|
||||
),
|
||||
"center": sockets.PhysicalPoint3DSocketDef(
|
||||
label="Center",
|
||||
),
|
||||
"size": sockets.PhysicalSize3DSocketDef(
|
||||
label="Size",
|
||||
),
|
||||
"direction": sockets.BoolSocketDef(
|
||||
label="+ Direction?",
|
||||
default_value=True,
|
||||
),
|
||||
"angle_theta": sockets.PhysicalAngleSocketDef(
|
||||
label="θ",
|
||||
),
|
||||
"angle_phi": sockets.PhysicalAngleSocketDef(
|
||||
label="φ",
|
||||
),
|
||||
"angle_pol": sockets.PhysicalAngleSocketDef(
|
||||
label="Pol Angle",
|
||||
),
|
||||
}
|
||||
output_sockets = {
|
||||
"source": sockets.MaxwellSourceSocketDef(
|
||||
label="Source",
|
||||
),
|
||||
}
|
||||
|
||||
####################
|
||||
# - Output Socket Computation
|
||||
####################
|
||||
@base.computes_output_socket("source")
|
||||
def compute_source(self: contracts.NodeTypeProtocol) -> td.PointDipole:
|
||||
temporal_shape = self.compute_input("temporal_shape")
|
||||
_center = self.compute_input("center")
|
||||
_size = self.compute_input("size")
|
||||
_direction = self.compute_input("direction")
|
||||
_angle_theta = self.compute_input("angle_theta")
|
||||
_angle_phi = self.compute_input("angle_phi")
|
||||
_angle_pol = self.compute_input("angle_pol")
|
||||
|
||||
center = tuple(spu.convert_to(_center, spu.um) / spu.um)
|
||||
size = tuple(
|
||||
0 if val == 1.0 else math.inf
|
||||
for val in spu.convert_to(_size, spu.um) / spu.um
|
||||
)
|
||||
angle_theta = spu.convert_to(_angle_theta, spu.rad) / spu.rad
|
||||
angle_phi = spu.convert_to(_angle_phi, spu.rad) / spu.rad
|
||||
angle_pol = spu.convert_to(_angle_pol, spu.rad) / spu.rad
|
||||
|
||||
return td.PlaneWave(
|
||||
center=center,
|
||||
size=size,
|
||||
source_time=temporal_shape,
|
||||
direction="+" if _direction else "-",
|
||||
angle_theta=angle_theta,
|
||||
angle_phi=angle_phi,
|
||||
pol_angle=angle_pol,
|
||||
)
|
||||
|
||||
|
||||
|
||||
####################
|
||||
# - Blender Registration
|
||||
####################
|
||||
BL_REGISTER = []
|
||||
BL_NODES = {}
|
||||
|
||||
BL_REGISTER = [
|
||||
PlaneWaveSourceNode,
|
||||
]
|
||||
BL_NODES = {
|
||||
contracts.NodeType.PlaneWaveSource: (
|
||||
contracts.NodeCategory.MAXWELLSIM_SOURCES
|
||||
)
|
||||
}
|
||||
|
|
|
@ -16,15 +16,19 @@ class PointDipoleSourceNode(base.MaxwellSimTreeNode):
|
|||
# - Sockets
|
||||
####################
|
||||
input_sockets = {
|
||||
#"polarization": sockets.PhysicalPolSocketDef(
|
||||
# label="Polarization",
|
||||
#), ## TODO: Exactly how to go about this...
|
||||
"polarization": sockets.PhysicalPolSocketDef(
|
||||
label="Polarization",
|
||||
),
|
||||
"temporal_shape": sockets.MaxwellTemporalShapeSocketDef(
|
||||
label="Temporal Shape",
|
||||
),
|
||||
"center": sockets.PhysicalPoint3DSocketDef(
|
||||
label="Center",
|
||||
),
|
||||
"interpolate": sockets.BoolSocketDef(
|
||||
label="Interpolate",
|
||||
default_value=True,
|
||||
),
|
||||
}
|
||||
output_sockets = {
|
||||
"source": sockets.MaxwellSourceSocketDef(
|
||||
|
@ -37,19 +41,18 @@ class PointDipoleSourceNode(base.MaxwellSimTreeNode):
|
|||
####################
|
||||
@base.computes_output_socket("source")
|
||||
def compute_source(self: contracts.NodeTypeProtocol) -> td.PointDipole:
|
||||
polarization = self.compute_input("polarization")
|
||||
temporal_shape = self.compute_input("temporal_shape")
|
||||
|
||||
_center = self.compute_input("center")
|
||||
center = tuple(spu.convert_to(_center, spu.um) / spu.um)
|
||||
interpolate = self.compute_input("interpolate")
|
||||
|
||||
cheating_pol = "Ex"
|
||||
## TODO: Fix
|
||||
center = tuple(spu.convert_to(_center, spu.um) / spu.um)
|
||||
|
||||
return td.PointDipole(
|
||||
center=center,
|
||||
source_time=temporal_shape,
|
||||
interpolate=True,
|
||||
polarization=cheating_pol,
|
||||
interpolate=interpolate,
|
||||
polarization=polarization,
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,77 @@
|
|||
import tidy3d as td
|
||||
import sympy as sp
|
||||
import sympy.physics.units as spu
|
||||
|
||||
from .... import contracts
|
||||
from .... import sockets
|
||||
from ... import base
|
||||
|
||||
class ContinuousWaveTemporalShapeNode(base.MaxwellSimTreeNode):
|
||||
node_type = contracts.NodeType.ContinuousWaveTemporalShape
|
||||
|
||||
bl_label = "Continuous Wave 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",
|
||||
default_value=5.0,
|
||||
),
|
||||
}
|
||||
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")
|
||||
|
||||
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.ContinuousWave(
|
||||
amplitude=cheating_amplitude,
|
||||
phase=phase,
|
||||
freq0=freq_center,
|
||||
fwidth=freq_std,
|
||||
offset=time_delay_rel_ang_freq,
|
||||
)
|
||||
|
||||
|
||||
|
||||
####################
|
||||
# - Blender Registration
|
||||
####################
|
||||
BL_REGISTER = []
|
||||
BL_NODES = {}
|
||||
|
||||
BL_REGISTER = [
|
||||
ContinuousWaveTemporalShapeNode,
|
||||
]
|
||||
BL_NODES = {
|
||||
contracts.NodeType.ContinuousWaveTemporalShape: (
|
||||
contracts.NodeCategory.MAXWELLSIM_SOURCES_TEMPORALSHAPES
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
####################
|
||||
# - Blender Registration
|
||||
####################
|
||||
BL_REGISTER = []
|
||||
BL_NODES = {}
|
||||
|
|
@ -30,6 +30,7 @@ class GaussianPulseTemporalShapeNode(base.MaxwellSimTreeNode):
|
|||
),
|
||||
"time_delay_rel_ang_freq": sockets.RealNumberSocketDef(
|
||||
label="Time Delay rel. Ang. Freq",
|
||||
default_value=5.0,
|
||||
),
|
||||
"remove_dc_component": sockets.BoolSocketDef(
|
||||
label="Remove DC",
|
||||
|
|
|
@ -4,6 +4,7 @@ import sympy as sp
|
|||
import sympy.physics.units as spu
|
||||
|
||||
import bpy
|
||||
from bpy_types import bpy_types
|
||||
import bmesh
|
||||
|
||||
from ... import contracts
|
||||
|
@ -12,6 +13,26 @@ from .. import base
|
|||
|
||||
GEONODES_MODIFIER_NAME = "BLMaxwell_GeoNodes"
|
||||
|
||||
# Monkey-Patch Sympy Types
|
||||
## TODO: This needs to be a more generic thing, this isn't the only place we're setting blender interface values.
|
||||
def parse_scalar(scalar):
|
||||
if isinstance(scalar, sp.Integer):
|
||||
return int(scalar)
|
||||
elif isinstance(scalar, sp.Float):
|
||||
return float(scalar)
|
||||
elif isinstance(scalar, sp.Rational):
|
||||
return float(scalar)
|
||||
elif isinstance(scalar, sp.Expr):
|
||||
return float(scalar.n())
|
||||
|
||||
return scalar
|
||||
|
||||
def parse_bl_to_sp(scalar):
|
||||
if isinstance(scalar, bpy_types.bpy_prop_array):
|
||||
return sp.Matrix(tuple(scalar))
|
||||
|
||||
return scalar
|
||||
|
||||
class GeoNodesStructureNode(base.MaxwellSimTreeNode):
|
||||
node_type = contracts.NodeType.GeoNodesStructure
|
||||
bl_label = "GeoNodes Structure"
|
||||
|
@ -21,12 +42,15 @@ class GeoNodesStructureNode(base.MaxwellSimTreeNode):
|
|||
# - Sockets
|
||||
####################
|
||||
input_sockets = {
|
||||
"preview_target": sockets.BlenderPreviewTargetSocketDef(
|
||||
label="Preview Target",
|
||||
),
|
||||
"blender_unit_system": sockets.PhysicalUnitSystemSocketDef(
|
||||
label="Blender Units",
|
||||
),
|
||||
"medium": sockets.MaxwellMediumSocketDef(
|
||||
label="Medium",
|
||||
),
|
||||
"object": sockets.BlenderObjectSocketDef(
|
||||
label="Object",
|
||||
),
|
||||
"geo_nodes": sockets.BlenderGeoNodesSocketDef(
|
||||
label="GeoNodes",
|
||||
),
|
||||
|
@ -50,7 +74,10 @@ class GeoNodesStructureNode(base.MaxwellSimTreeNode):
|
|||
|
||||
# Triangulate Object Mesh
|
||||
bmesh_mesh = bmesh.new()
|
||||
bmesh_mesh.from_mesh(bl_object.data)
|
||||
bmesh_mesh.from_object(
|
||||
bl_object,
|
||||
bpy.context.evaluated_depsgraph_get(),
|
||||
)
|
||||
bmesh.ops.triangulate(bmesh_mesh, faces=bmesh_mesh.faces)
|
||||
|
||||
mesh = bpy.data.meshes.new(name="TriangulatedMesh")
|
||||
|
@ -75,8 +102,13 @@ class GeoNodesStructureNode(base.MaxwellSimTreeNode):
|
|||
####################
|
||||
# - Update Function
|
||||
####################
|
||||
def free(self) -> None:
|
||||
bl_socket = self.g_input_bl_socket("preview_target")
|
||||
|
||||
bl_socket.free()
|
||||
|
||||
def update_cb(self) -> None:
|
||||
bl_object = self.compute_input("object")
|
||||
bl_object = self.compute_input("preview_target")
|
||||
if bl_object is None: return
|
||||
|
||||
geo_nodes = self.compute_input("geo_nodes")
|
||||
|
@ -91,9 +123,12 @@ class GeoNodesStructureNode(base.MaxwellSimTreeNode):
|
|||
):
|
||||
if idx == 0: continue ## Always-on "Geometry" Input (from Object)
|
||||
|
||||
# Retrieve Input Socket
|
||||
bl_socket = self.inputs[
|
||||
interface_item.name
|
||||
]
|
||||
|
||||
# Retrieve Linked/Unlinked Input Socket Value
|
||||
if bl_socket.is_linked:
|
||||
linked_bl_socket = bl_socket.links[0].from_socket
|
||||
linked_bl_node = bl_socket.links[0].from_node
|
||||
|
@ -103,13 +138,33 @@ class GeoNodesStructureNode(base.MaxwellSimTreeNode):
|
|||
)
|
||||
) ## What a bunch of spaghetti
|
||||
else:
|
||||
val = self.inputs[
|
||||
interface_item.name
|
||||
].default_value
|
||||
val = bl_socket.default_value
|
||||
|
||||
# Retrieve Unit-System Corrected Modifier Value
|
||||
bl_unit_system = self.compute_input("blender_unit_system")
|
||||
|
||||
socket_type = contracts.SocketType[
|
||||
bl_socket.bl_idname.removesuffix("SocketType")
|
||||
]
|
||||
if socket_type in bl_unit_system:
|
||||
unitless_val = spu.convert_to(
|
||||
val,
|
||||
bl_unit_system[socket_type],
|
||||
) / bl_unit_system[socket_type]
|
||||
else:
|
||||
unitless_val = val
|
||||
|
||||
if isinstance(unitless_val, sp.matrices.MatrixBase):
|
||||
unitless_val = tuple(
|
||||
parse_scalar(scalar)
|
||||
for scalar in unitless_val
|
||||
)
|
||||
else:
|
||||
unitless_val = parse_scalar(unitless_val)
|
||||
|
||||
# Conservatively Set Differing Values
|
||||
if bl_modifier[interface_item.identifier] != val:
|
||||
bl_modifier[interface_item.identifier] = val
|
||||
if bl_modifier[interface_item.identifier] != unitless_val:
|
||||
bl_modifier[interface_item.identifier] = unitless_val
|
||||
|
||||
# Update DepGraph
|
||||
bl_object.data.update()
|
||||
|
@ -134,23 +189,77 @@ class GeoNodesStructureNode(base.MaxwellSimTreeNode):
|
|||
self.inputs.remove(bl_socket)
|
||||
|
||||
# Query for Blender Object / Geo Nodes
|
||||
bl_object = self.compute_input("object")
|
||||
bl_object = self.compute_input("preview_target")
|
||||
if bl_object is None: return
|
||||
## TODO: Make object? Gray out geonodes if object not defined?
|
||||
|
||||
# Remove Existing GeoNodes Modifier
|
||||
if GEONODES_MODIFIER_NAME in bl_object.modifiers:
|
||||
modifier_to_remove = bl_object.modifiers[GEONODES_MODIFIER_NAME]
|
||||
bl_object.modifiers.remove(modifier_to_remove)
|
||||
|
||||
# Retrieve GeoNodes Tree
|
||||
geo_nodes = self.compute_input("geo_nodes")
|
||||
if geo_nodes is None: return
|
||||
|
||||
|
||||
# Add Non-Static Sockets from GeoNodes
|
||||
for bl_socket_name, bl_socket in geo_nodes.interface.items_tree.items():
|
||||
# For now, don't allow Geometry inputs.
|
||||
if bl_socket.socket_type == "NodeSocketGeometry": continue
|
||||
|
||||
self.inputs.new(
|
||||
contracts.BLNodeSocket_to_SocketType[bl_socket.socket_type],
|
||||
bl_socket_name,
|
||||
)
|
||||
# Establish Dimensions of GeoNodes Input Sockets
|
||||
if (
|
||||
bl_socket.description.startswith("2D")
|
||||
):
|
||||
dimensions = 2
|
||||
elif (
|
||||
bl_socket.socket_type.startswith("NodeSocketVector")
|
||||
or bl_socket.socket_type.startswith("NodeSocketColor")
|
||||
or bl_socket.socket_type.startswith("NodeSocketRotation")
|
||||
):
|
||||
dimensions = 3
|
||||
else:
|
||||
dimensions = 1
|
||||
|
||||
# Choose Socket via. Description Hint (if exists)
|
||||
if (
|
||||
":" in bl_socket.description
|
||||
and "(" in (desc_hint := bl_socket.description.split(":")[0])
|
||||
and ")" in desc_hint
|
||||
):
|
||||
for tag in contracts.BLNodeSocket_to_SocketType_by_desc[
|
||||
dimensions
|
||||
]:
|
||||
if desc_hint.startswith(tag):
|
||||
self.inputs.new(
|
||||
contracts.BLNodeSocket_to_SocketType_by_desc[
|
||||
dimensions
|
||||
][tag],
|
||||
bl_socket_name,
|
||||
)
|
||||
|
||||
if len([
|
||||
(unit := _unit)
|
||||
for _unit in contracts.SocketType_to_units[
|
||||
contracts.SocketType[
|
||||
self.inputs[bl_socket_name].bl_idname.removesuffix("SocketType")
|
||||
]
|
||||
]["values"].values()
|
||||
if desc_hint[
|
||||
desc_hint.find("(")+1 : desc_hint.find(")")
|
||||
] == str(_unit)
|
||||
]) > 0:
|
||||
self.inputs[bl_socket_name].unit = unit
|
||||
|
||||
elif bl_socket.socket_type in contracts.BLNodeSocket_to_SocketType[
|
||||
dimensions
|
||||
]:
|
||||
self.inputs.new(
|
||||
contracts.BLNodeSocket_to_SocketType[
|
||||
dimensions
|
||||
][bl_socket.socket_type],
|
||||
bl_socket_name,
|
||||
)
|
||||
|
||||
|
||||
# Create New GeoNodes Modifier
|
||||
if GEONODES_MODIFIER_NAME not in bl_object.modifiers:
|
||||
|
@ -160,7 +269,27 @@ class GeoNodesStructureNode(base.MaxwellSimTreeNode):
|
|||
)
|
||||
modifier.node_group = geo_nodes
|
||||
|
||||
self.update()
|
||||
# Set Default Values
|
||||
for interface_item in geo_nodes.interface.items_tree.values():
|
||||
if (
|
||||
interface_item.name in self.inputs
|
||||
and hasattr(interface_item, "default_value")
|
||||
):
|
||||
bl_socket = self.inputs[
|
||||
interface_item.name
|
||||
]
|
||||
if hasattr(bl_socket, "use_units"):
|
||||
bl_unit_system = self.compute_input("blender_unit_system")
|
||||
socket_type = contracts.SocketType[
|
||||
bl_socket.bl_idname.removesuffix("SocketType")
|
||||
]
|
||||
|
||||
bl_socket.default_value = (
|
||||
parse_bl_to_sp(interface_item.default_value)
|
||||
* bl_unit_system[socket_type]
|
||||
)
|
||||
else:
|
||||
bl_socket.default_value = parse_bl_to_sp(interface_item.default_value)
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -45,7 +45,10 @@ class ObjectStructureNode(base.MaxwellSimTreeNode):
|
|||
|
||||
# Triangulate Object Mesh
|
||||
bmesh_mesh = bmesh.new()
|
||||
bmesh_mesh.from_mesh(bl_object.data)
|
||||
bmesh_mesh.from_object(
|
||||
bl_object,
|
||||
bpy.context.evaluated_depsgraph_get(),
|
||||
)
|
||||
bmesh.ops.triangulate(bmesh_mesh, faces=bmesh_mesh.faces)
|
||||
|
||||
mesh = bpy.data.meshes.new(name="TriangulatedMesh")
|
||||
|
@ -62,7 +65,6 @@ class ObjectStructureNode(base.MaxwellSimTreeNode):
|
|||
# Remove Temporary Mesh
|
||||
bpy.data.meshes.remove(mesh)
|
||||
|
||||
print(vertices)
|
||||
return td.Structure(
|
||||
geometry=td.TriangleMesh.from_vertices_faces(vertices, faces),
|
||||
medium=self.compute_input("medium")
|
||||
|
|
|
@ -61,6 +61,6 @@ BL_REGISTER = [
|
|||
]
|
||||
BL_NODES = {
|
||||
contracts.NodeType.BoxStructure: (
|
||||
contracts.NodeCategory.MAXWELLSIM_STRUCTURES
|
||||
contracts.NodeCategory.MAXWELLSIM_STRUCTURES_PRIMITIVES
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,72 @@
|
|||
import tidy3d as td
|
||||
import sympy as sp
|
||||
import sympy.physics.units as spu
|
||||
|
||||
from .... import contracts
|
||||
from .... import sockets
|
||||
from ... import base
|
||||
|
||||
class CylinderStructureNode(base.MaxwellSimTreeNode):
|
||||
node_type = contracts.NodeType.CylinderStructure
|
||||
bl_label = "Cylinder Structure"
|
||||
#bl_icon = ...
|
||||
|
||||
####################
|
||||
# - Sockets
|
||||
####################
|
||||
input_sockets = {
|
||||
"medium": sockets.MaxwellMediumSocketDef(
|
||||
label="Medium",
|
||||
),
|
||||
"center": sockets.PhysicalPoint3DSocketDef(
|
||||
label="Center",
|
||||
),
|
||||
"radius": sockets.PhysicalLengthSocketDef(
|
||||
label="Radius",
|
||||
),
|
||||
"height": sockets.PhysicalLengthSocketDef(
|
||||
label="Height",
|
||||
),
|
||||
}
|
||||
output_sockets = {
|
||||
"structure": sockets.MaxwellStructureSocketDef(
|
||||
label="Structure",
|
||||
),
|
||||
}
|
||||
|
||||
####################
|
||||
# - Output Socket Computation
|
||||
####################
|
||||
@base.computes_output_socket("structure")
|
||||
def compute_simulation(self: contracts.NodeTypeProtocol) -> td.Box:
|
||||
medium = self.compute_input("medium")
|
||||
_center = self.compute_input("center")
|
||||
_radius = self.compute_input("radius")
|
||||
_height = self.compute_input("height")
|
||||
|
||||
center = tuple(spu.convert_to(_center, spu.um) / spu.um)
|
||||
radius = spu.convert_to(_radius, spu.um) / spu.um
|
||||
height = spu.convert_to(_height, spu.um) / spu.um
|
||||
|
||||
return td.Structure(
|
||||
geometry=td.Cylinder(
|
||||
radius=radius,
|
||||
center=center,
|
||||
length=height,
|
||||
),
|
||||
medium=medium,
|
||||
)
|
||||
|
||||
|
||||
|
||||
####################
|
||||
# - Blender Registration
|
||||
####################
|
||||
BL_REGISTER = []
|
||||
BL_NODES = {}
|
||||
|
||||
BL_REGISTER = [
|
||||
CylinderStructureNode,
|
||||
]
|
||||
BL_NODES = {
|
||||
contracts.NodeType.CylinderStructure: (
|
||||
contracts.NodeCategory.MAXWELLSIM_STRUCTURES_PRIMITIVES
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,66 @@
|
|||
import tidy3d as td
|
||||
import sympy as sp
|
||||
import sympy.physics.units as spu
|
||||
|
||||
from .... import contracts
|
||||
from .... import sockets
|
||||
from ... import base
|
||||
|
||||
class SphereStructureNode(base.MaxwellSimTreeNode):
|
||||
node_type = contracts.NodeType.SphereStructure
|
||||
bl_label = "Sphere Structure"
|
||||
#bl_icon = ...
|
||||
|
||||
####################
|
||||
# - Sockets
|
||||
####################
|
||||
input_sockets = {
|
||||
"medium": sockets.MaxwellMediumSocketDef(
|
||||
label="Medium",
|
||||
),
|
||||
"center": sockets.PhysicalPoint3DSocketDef(
|
||||
label="Center",
|
||||
),
|
||||
"radius": sockets.PhysicalLengthSocketDef(
|
||||
label="Radius",
|
||||
),
|
||||
}
|
||||
output_sockets = {
|
||||
"structure": sockets.MaxwellStructureSocketDef(
|
||||
label="Structure",
|
||||
),
|
||||
}
|
||||
|
||||
####################
|
||||
# - Output Socket Computation
|
||||
####################
|
||||
@base.computes_output_socket("structure")
|
||||
def compute_simulation(self: contracts.NodeTypeProtocol) -> td.Box:
|
||||
medium = self.compute_input("medium")
|
||||
_center = self.compute_input("center")
|
||||
_radius = self.compute_input("radius")
|
||||
|
||||
center = tuple(spu.convert_to(_center, spu.um) / spu.um)
|
||||
radius = spu.convert_to(_radius, spu.um) / spu.um
|
||||
|
||||
return td.Structure(
|
||||
geometry=td.Sphere(
|
||||
radius=radius,
|
||||
center=center,
|
||||
),
|
||||
medium=medium,
|
||||
)
|
||||
|
||||
|
||||
|
||||
####################
|
||||
# - Blender Registration
|
||||
####################
|
||||
BL_REGISTER = []
|
||||
BL_NODES = {}
|
||||
|
||||
BL_REGISTER = [
|
||||
SphereStructureNode,
|
||||
]
|
||||
BL_NODES = {
|
||||
contracts.NodeType.SphereStructure: (
|
||||
contracts.NodeCategory.MAXWELLSIM_STRUCTURES_PRIMITIVES
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,11 +1,23 @@
|
|||
from . import combine
|
||||
#from . import separate
|
||||
|
||||
from . import math
|
||||
from . import operations
|
||||
from . import converter
|
||||
|
||||
BL_REGISTER = [
|
||||
*combine.BL_REGISTER,
|
||||
#*separate.BL_REGISTER,
|
||||
|
||||
*converter.BL_REGISTER,
|
||||
*math.BL_REGISTER,
|
||||
*operations.BL_REGISTER,
|
||||
]
|
||||
BL_NODES = {
|
||||
**combine.BL_NODES,
|
||||
#**separate.BL_NODES,
|
||||
|
||||
**converter.BL_NODES,
|
||||
**math.BL_NODES,
|
||||
**operations.BL_NODES,
|
||||
}
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
import sympy as sp
|
||||
import sympy.physics.units as spu
|
||||
import scipy as sc
|
||||
|
||||
from ... import contracts
|
||||
from ... import sockets
|
||||
from .. import base
|
||||
|
||||
class CombineNode(base.MaxwellSimTreeNode):
|
||||
node_type = contracts.NodeType.Combine
|
||||
bl_label = "Combine"
|
||||
#bl_icon = ...
|
||||
|
||||
####################
|
||||
# - Sockets
|
||||
####################
|
||||
input_sockets = {}
|
||||
input_socket_sets = {
|
||||
"real_3d_vector": {
|
||||
f"x_{i}": sockets.RealNumberSocketDef(
|
||||
label=f"x_{i}"
|
||||
)
|
||||
for i in range(3)
|
||||
},
|
||||
"point_3d": {
|
||||
axis: sockets.PhysicalLengthSocketDef(
|
||||
label=axis
|
||||
)
|
||||
for i, axis in zip(
|
||||
range(3),
|
||||
["x", "y", "z"]
|
||||
)
|
||||
},
|
||||
"size_3d": {
|
||||
axis_key: sockets.PhysicalLengthSocketDef(
|
||||
label=axis_label
|
||||
)
|
||||
for i, axis_key, axis_label in zip(
|
||||
range(3),
|
||||
["x_size", "y_size", "z_size"],
|
||||
["X Size", "Y Size", "Z Size"],
|
||||
)
|
||||
},
|
||||
}
|
||||
output_sockets = {}
|
||||
output_socket_sets = {
|
||||
"real_3d_vector": {
|
||||
"real_3d_vector": sockets.Real3DVectorSocketDef(
|
||||
label="Real 3D Vector",
|
||||
),
|
||||
},
|
||||
"point_3d": {
|
||||
"point_3d": sockets.PhysicalPoint3DSocketDef(
|
||||
label="3D Point",
|
||||
),
|
||||
},
|
||||
"size_3d": {
|
||||
"size_3d": sockets.PhysicalSize3DSocketDef(
|
||||
label="3D Size",
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
####################
|
||||
# - Output Socket Computation
|
||||
####################
|
||||
@base.computes_output_socket("real_3d_vector")
|
||||
def compute_real_3d_vector(self: contracts.NodeTypeProtocol) -> sp.Expr:
|
||||
x1, x2, x3 = [
|
||||
self.compute_input(f"x_{i}")
|
||||
for i in range(3)
|
||||
]
|
||||
|
||||
return (x1, x2, x3)
|
||||
|
||||
@base.computes_output_socket("point_3d")
|
||||
def compute_point_3d(self: contracts.NodeTypeProtocol) -> sp.Expr:
|
||||
x, y, z = [
|
||||
self.compute_input(axis)
|
||||
#spu.convert_to(
|
||||
# self.compute_input(axis),
|
||||
# spu.meter,
|
||||
#) / spu.meter
|
||||
for axis in ["x", "y", "z"]
|
||||
]
|
||||
|
||||
return sp.Matrix([x, y, z])# * spu.meter
|
||||
|
||||
@base.computes_output_socket("size_3d")
|
||||
def compute_size_3d(self: contracts.NodeTypeProtocol) -> sp.Expr:
|
||||
x_size, y_size, z_size = [
|
||||
self.compute_input(axis)
|
||||
#spu.convert_to(
|
||||
# self.compute_input(axis),
|
||||
# spu.meter,
|
||||
#) / spu.meter
|
||||
for axis in ["x_size", "y_size", "z_size"]
|
||||
]
|
||||
|
||||
return sp.Matrix([x_size, y_size, z_size])# * spu.meter
|
||||
|
||||
|
||||
|
||||
####################
|
||||
# - Blender Registration
|
||||
####################
|
||||
BL_REGISTER = [
|
||||
CombineNode,
|
||||
]
|
||||
BL_NODES = {
|
||||
contracts.NodeType.Combine: (
|
||||
contracts.NodeCategory.MAXWELLSIM_UTILITIES
|
||||
)
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
from . import wave_converter
|
||||
|
||||
BL_REGISTER = [
|
||||
*wave_converter.BL_REGISTER,
|
||||
]
|
||||
BL_NODES = {
|
||||
**wave_converter.BL_NODES,
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
import tidy3d as td
|
||||
import sympy as sp
|
||||
import sympy.physics.units as spu
|
||||
import scipy as sc
|
||||
|
||||
from .... import contracts
|
||||
from .... import sockets
|
||||
from ... import base
|
||||
|
||||
class WaveConverterNode(base.MaxwellSimTreeNode):
|
||||
node_type = contracts.NodeType.WaveConverter
|
||||
bl_label = "Wave Converter"
|
||||
#bl_icon = ...
|
||||
|
||||
####################
|
||||
# - Sockets
|
||||
####################
|
||||
input_sockets = {}
|
||||
input_socket_sets = {
|
||||
"freq_to_vacwl": {
|
||||
"freq": sockets.PhysicalFreqSocketDef(
|
||||
label="Freq",
|
||||
),
|
||||
},
|
||||
"vacwl_to_freq": {
|
||||
"vacwl": sockets.PhysicalVacWLSocketDef(
|
||||
label="Vac WL",
|
||||
),
|
||||
},
|
||||
}
|
||||
output_sockets = {}
|
||||
output_socket_sets = {
|
||||
"freq_to_vacwl": {
|
||||
"vacwl": sockets.PhysicalVacWLSocketDef(
|
||||
label="Vac WL",
|
||||
),
|
||||
},
|
||||
"vacwl_to_freq": {
|
||||
"freq": sockets.PhysicalFreqSocketDef(
|
||||
label="Freq",
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
####################
|
||||
# - Output Socket Computation
|
||||
####################
|
||||
@base.computes_output_socket("freq")
|
||||
def compute_freq(self: contracts.NodeTypeProtocol) -> sp.Expr:
|
||||
vac_speed_of_light = sc.constants.speed_of_light * spu.meter/spu.second
|
||||
|
||||
vacwl = self.compute_input("vacwl")
|
||||
|
||||
return spu.convert_to(
|
||||
vac_speed_of_light / vacwl,
|
||||
spu.hertz,
|
||||
)
|
||||
|
||||
@base.computes_output_socket("vacwl")
|
||||
def compute_vacwl(self: contracts.NodeTypeProtocol) -> sp.Expr:
|
||||
vac_speed_of_light = sc.constants.speed_of_light * spu.meter/spu.second
|
||||
|
||||
freq = self.compute_input("freq")
|
||||
|
||||
return spu.convert_to(
|
||||
vac_speed_of_light / freq,
|
||||
spu.meter,
|
||||
)
|
||||
|
||||
|
||||
|
||||
####################
|
||||
# - Blender Registration
|
||||
####################
|
||||
BL_REGISTER = [
|
||||
WaveConverterNode,
|
||||
]
|
||||
BL_NODES = {
|
||||
contracts.NodeType.WaveConverter: (
|
||||
contracts.NodeCategory.MAXWELLSIM_UTILITIES_CONVERTERS
|
||||
)
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
import tidy3d as td
|
||||
import sympy as sp
|
||||
import sympy.physics.units as spu
|
||||
import scipy as sc
|
||||
|
||||
from .... import contracts
|
||||
from .... import sockets
|
||||
from ... import base
|
||||
|
||||
class WaveConverterNode(base.MaxwellSimTreeNode):
|
||||
node_type = contracts.NodeType.WaveConverter
|
||||
bl_label = "Wave Converter"
|
||||
#bl_icon = ...
|
||||
|
||||
####################
|
||||
# - Sockets
|
||||
####################
|
||||
input_sockets = {}
|
||||
input_socket_sets = {
|
||||
"freq_to_vacwl": {
|
||||
"freq": sockets.PhysicalFreqSocketDef(
|
||||
label="Freq",
|
||||
),
|
||||
},
|
||||
"vacwl_to_freq": {
|
||||
"vacwl": sockets.PhysicalVacWLSocketDef(
|
||||
label="Vac WL",
|
||||
),
|
||||
},
|
||||
}
|
||||
output_sockets = {}
|
||||
output_socket_sets = {
|
||||
"freq_to_vacwl": {
|
||||
"vacwl": sockets.PhysicalVacWLSocketDef(
|
||||
label="Vac WL",
|
||||
),
|
||||
},
|
||||
"vacwl_to_freq": {
|
||||
"freq": sockets.PhysicalFreqSocketDef(
|
||||
label="Freq",
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
####################
|
||||
# - Output Socket Computation
|
||||
####################
|
||||
@base.computes_output_socket("freq")
|
||||
def compute_freq(self: contracts.NodeTypeProtocol) -> sp.Expr:
|
||||
vac_speed_of_light = sc.constants.speed_of_light * spu.meter/spu.second
|
||||
|
||||
vacwl = self.compute_input("vacwl")
|
||||
|
||||
return spu.convert_to(
|
||||
vac_speed_of_light / vacwl,
|
||||
spu.hertz,
|
||||
)
|
||||
|
||||
@base.computes_output_socket("vacwl")
|
||||
def compute_vacwl(self: contracts.NodeTypeProtocol) -> sp.Expr:
|
||||
vac_speed_of_light = sc.constants.speed_of_light * spu.meter/spu.second
|
||||
|
||||
freq = self.compute_input("freq")
|
||||
|
||||
return spu.convert_to(
|
||||
vac_speed_of_light / freq,
|
||||
spu.meter,
|
||||
)
|
||||
|
||||
|
||||
|
||||
####################
|
||||
# - Blender Registration
|
||||
####################
|
||||
BL_REGISTER = [
|
||||
WaveConverterNode,
|
||||
]
|
||||
BL_NODES = {
|
||||
contracts.NodeType.WaveConverter: (
|
||||
contracts.NodeCategory.MAXWELLSIM_UTILITIES_CONVERTERS
|
||||
)
|
||||
}
|
|
@ -17,6 +17,7 @@ Real3DVectorSocketDef = vector.Real3DVectorSocketDef
|
|||
Complex3DVectorSocketDef = vector.Complex3DVectorSocketDef
|
||||
|
||||
from . import physical
|
||||
PhysicalUnitSystemSocketDef = physical.PhysicalUnitSystemSocketDef
|
||||
PhysicalTimeSocketDef = physical.PhysicalTimeSocketDef
|
||||
PhysicalAngleSocketDef = physical.PhysicalAngleSocketDef
|
||||
PhysicalLengthSocketDef = physical.PhysicalLengthSocketDef
|
||||
|
@ -30,6 +31,7 @@ PhysicalAccelScalarSocketDef = physical.PhysicalAccelScalarSocketDef
|
|||
PhysicalForceScalarSocketDef = physical.PhysicalForceScalarSocketDef
|
||||
PhysicalPolSocketDef = physical.PhysicalPolSocketDef
|
||||
PhysicalFreqSocketDef = physical.PhysicalFreqSocketDef
|
||||
PhysicalVacWLSocketDef = physical.PhysicalVacWLSocketDef
|
||||
PhysicalSpecRelPermDistSocketDef = physical.PhysicalSpecRelPermDistSocketDef
|
||||
PhysicalSpecPowerDistSocketDef = physical.PhysicalSpecPowerDistSocketDef
|
||||
|
||||
|
@ -40,6 +42,7 @@ BlenderImageSocketDef = blender.BlenderImageSocketDef
|
|||
BlenderVolumeSocketDef = blender.BlenderVolumeSocketDef
|
||||
BlenderGeoNodesSocketDef = blender.BlenderGeoNodesSocketDef
|
||||
BlenderTextSocketDef = blender.BlenderTextSocketDef
|
||||
BlenderPreviewTargetSocketDef = blender.BlenderPreviewTargetSocketDef
|
||||
|
||||
from . import maxwell
|
||||
MaxwellBoundBoxSocketDef = maxwell.MaxwellBoundBoxSocketDef
|
||||
|
|
|
@ -235,4 +235,23 @@ class BLSocket(bpy.types.NodeSocket):
|
|||
node: bpy.types.Node,
|
||||
text: str,
|
||||
) -> None:
|
||||
layout.label(text=text)
|
||||
col = layout.column()
|
||||
row_col = col.row()
|
||||
row_col.alignment = "RIGHT"
|
||||
# Row: Label & Preview Toggle
|
||||
if hasattr(self, "draw_preview"):
|
||||
row_col.prop(
|
||||
self,
|
||||
"preview_active",
|
||||
toggle=True,
|
||||
text="",
|
||||
icon="SEQ_PREVIEW",
|
||||
)
|
||||
|
||||
row_col.label(text=text)
|
||||
|
||||
# Row: Preview (in box)
|
||||
if hasattr(self, "draw_preview"):
|
||||
if self.preview_active:
|
||||
col_box = col.box()
|
||||
self.draw_preview(col_box)
|
||||
|
|
|
@ -13,6 +13,8 @@ from . import text_socket
|
|||
BlenderGeoNodesSocketDef = geonodes_socket.BlenderGeoNodesSocketDef
|
||||
BlenderTextSocketDef = text_socket.BlenderTextSocketDef
|
||||
|
||||
from . import target_socket
|
||||
BlenderPreviewTargetSocketDef = target_socket.BlenderPreviewTargetSocketDef
|
||||
|
||||
BL_REGISTER = [
|
||||
*object_socket.BL_REGISTER,
|
||||
|
@ -20,6 +22,7 @@ BL_REGISTER = [
|
|||
|
||||
*image_socket.BL_REGISTER,
|
||||
*volume_socket.BL_REGISTER,
|
||||
*target_socket.BL_REGISTER,
|
||||
|
||||
*geonodes_socket.BL_REGISTER,
|
||||
*text_socket.BL_REGISTER,
|
||||
|
|
|
@ -6,6 +6,19 @@ import pydantic as pyd
|
|||
from .. import base
|
||||
from ... import contracts
|
||||
|
||||
####################
|
||||
# - Operators
|
||||
####################
|
||||
class BlenderMaxwellResetGeoNodesSocket(bpy.types.Operator):
|
||||
bl_idname = "blender_maxwell.reset_geo_nodes_socket"
|
||||
bl_label = "Reset GeoNodes Socket"
|
||||
|
||||
def execute(self, context):
|
||||
context.socket.update_geonodes_node()
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
####################
|
||||
# - Blender Socket
|
||||
####################
|
||||
|
@ -33,6 +46,18 @@ class BlenderGeoNodesBLSocket(base.BLSocket):
|
|||
update=(lambda self, context: self.update_geonodes_node()),
|
||||
)
|
||||
|
||||
####################
|
||||
# - UI
|
||||
####################
|
||||
def draw_label_row(self, label_col_row, text):
|
||||
label_col_row.label(text=text)
|
||||
if self.raw_value:
|
||||
label_col_row.operator(
|
||||
"blender_maxwell.reset_geo_nodes_socket",
|
||||
text="",
|
||||
icon="FILE_REFRESH",
|
||||
)
|
||||
|
||||
####################
|
||||
# - Default Value
|
||||
####################
|
||||
|
@ -58,5 +83,6 @@ class BlenderGeoNodesSocketDef(pyd.BaseModel):
|
|||
# - Blender Registration
|
||||
####################
|
||||
BL_REGISTER = [
|
||||
BlenderGeoNodesBLSocket
|
||||
BlenderMaxwellResetGeoNodesSocket,
|
||||
BlenderGeoNodesBLSocket,
|
||||
]
|
||||
|
|
|
@ -6,6 +6,29 @@ import pydantic as pyd
|
|||
from .. import base
|
||||
from ... import contracts
|
||||
|
||||
####################
|
||||
# - Blender Socket
|
||||
####################
|
||||
class BlenderMaxwellCreateAndAssignBLObject(bpy.types.Operator):
|
||||
bl_idname = "blender_maxwell.create_and_assign_bl_object"
|
||||
bl_label = "Create and Assign BL Object"
|
||||
|
||||
def execute(self, context):
|
||||
mesh = bpy.data.meshes.new("GenMesh")
|
||||
new_bl_object = bpy.data.objects.new("GenObj", mesh)
|
||||
|
||||
context.collection.objects.link(new_bl_object)
|
||||
|
||||
node = context.node
|
||||
for bl_socket_name, bl_socket in node.inputs.items():
|
||||
if isinstance(bl_socket, BlenderObjectBLSocket):
|
||||
bl_socket.default_value = new_bl_object
|
||||
|
||||
if hasattr(node, "update_sockets_from_geonodes"):
|
||||
node.update_sockets_from_geonodes()
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
####################
|
||||
# - Blender Socket
|
||||
####################
|
||||
|
@ -23,6 +46,17 @@ class BlenderObjectBLSocket(base.BLSocket):
|
|||
update=(lambda self, context: self.trigger_updates()),
|
||||
)
|
||||
|
||||
####################
|
||||
# - UI
|
||||
####################
|
||||
def draw_label_row(self, label_col_row, text):
|
||||
label_col_row.label(text=text)
|
||||
label_col_row.operator(
|
||||
"blender_maxwell.create_and_assign_bl_object",
|
||||
text="",
|
||||
icon="ADD",
|
||||
)
|
||||
|
||||
####################
|
||||
# - Default Value
|
||||
####################
|
||||
|
@ -48,5 +82,6 @@ class BlenderObjectSocketDef(pyd.BaseModel):
|
|||
# - Blender Registration
|
||||
####################
|
||||
BL_REGISTER = [
|
||||
BlenderObjectBLSocket
|
||||
BlenderMaxwellCreateAndAssignBLObject,
|
||||
BlenderObjectBLSocket,
|
||||
]
|
||||
|
|
|
@ -0,0 +1,268 @@
|
|||
import typing as typ
|
||||
|
||||
import bpy
|
||||
import sympy as sp
|
||||
import pydantic as pyd
|
||||
|
||||
from .. import base
|
||||
from ... import contracts
|
||||
|
||||
def mk_and_assign_target_bl_obj(bl_socket, node, node_tree):
|
||||
# Create Mesh and Object
|
||||
mesh = bpy.data.meshes.new("Mesh" + bl_socket.node.name)
|
||||
new_bl_object = bpy.data.objects.new(bl_socket.node.name, mesh)
|
||||
|
||||
# Create Preview Collection and Object
|
||||
if bl_socket.show_preview:
|
||||
#if not node_tree.preview_collection:
|
||||
# new_collection = bpy.data.collections.new("BLMaxwellPreview")
|
||||
# node_tree.preview_collection = new_collection
|
||||
#
|
||||
# bpy.context.scene.collection.children.link(new_collection)
|
||||
|
||||
node_tree.preview_collection.objects.link(new_bl_object)
|
||||
|
||||
# Create Non-Preview Collection and Object
|
||||
else:
|
||||
#if not node_tree.non_preview_collection:
|
||||
# new_collection = bpy.data.collections.new("BLMaxwellNonPreview")
|
||||
# node_tree.non_preview_collection = new_collection
|
||||
#
|
||||
# bpy.context.scene.collection.children.link(new_collection)
|
||||
|
||||
node_tree.non_preview_collection.objects.link(new_bl_object)
|
||||
|
||||
bl_socket.local_target_object = new_bl_object
|
||||
|
||||
if hasattr(node, "update_sockets_from_geonodes"):
|
||||
node.update_sockets_from_geonodes()
|
||||
|
||||
class BlenderMaxwellCreateAndAssignTargetBLObject(bpy.types.Operator):
|
||||
bl_idname = "blender_maxwell.create_and_assign_target_bl_object"
|
||||
bl_label = "Create and Assign Target BL Object"
|
||||
|
||||
def execute(self, context):
|
||||
bl_socket = context.socket
|
||||
node = bl_socket.node
|
||||
node_tree = node.id_data
|
||||
|
||||
mk_and_assign_target_bl_obj(bl_socket, node, node_tree)
|
||||
return {'FINISHED'}
|
||||
|
||||
####################
|
||||
# - Blender Socket
|
||||
####################
|
||||
class BlenderPreviewTargetBLSocket(base.BLSocket):
|
||||
socket_type = contracts.SocketType.BlenderPreviewTarget
|
||||
bl_label = "BlenderPreviewTarget"
|
||||
|
||||
####################
|
||||
# - Properties
|
||||
####################
|
||||
show_preview: bpy.props.BoolProperty(
|
||||
name="Target Object Included in Preview",
|
||||
description="Whether or not Blender will preview the target object",
|
||||
default=True,
|
||||
update=(lambda self, context: self.update_preview()),
|
||||
)
|
||||
show_definition: bpy.props.BoolProperty(
|
||||
name="Show Unit System Definition",
|
||||
description="Toggle to show unit system definition",
|
||||
default=False,
|
||||
update=(lambda self, context: self.trigger_updates()),
|
||||
)
|
||||
|
||||
|
||||
target_object_pinned: bpy.props.BoolProperty(
|
||||
name="Target Object Pinned",
|
||||
description="Whether or not Blender will manage the target object",
|
||||
default=True,
|
||||
)
|
||||
preview_collection_pinned: bpy.props.BoolProperty(
|
||||
name="Global Preview Collection Pinned",
|
||||
description="Whether or not Blender will use the global preview collection",
|
||||
default=True,
|
||||
)
|
||||
non_preview_collection_pinned: bpy.props.BoolProperty(
|
||||
name="Global Non-Preview Collection Pinned",
|
||||
description="Whether or not Blender will use the global non-preview collection",
|
||||
default=True,
|
||||
)
|
||||
|
||||
|
||||
local_target_object: bpy.props.PointerProperty(
|
||||
name="Local Target Blender Object",
|
||||
description="Represents a Blender object to apply a preview to",
|
||||
type=bpy.types.Object,
|
||||
update=(lambda self, context: self.trigger_updates()),
|
||||
)
|
||||
local_preview_collection: bpy.props.PointerProperty(
|
||||
name="Local Preview Collection",
|
||||
description="Collection of Blender objects that will be previewed",
|
||||
type=bpy.types.Collection,
|
||||
update=(lambda self, context: self.trigger_updates())
|
||||
)
|
||||
local_non_preview_collection: bpy.props.PointerProperty(
|
||||
name="Local Non-Preview Collection",
|
||||
description="Collection of Blender objects that will NOT be previewed",
|
||||
type=bpy.types.Collection,
|
||||
update=(lambda self, context: self.trigger_updates())
|
||||
)
|
||||
|
||||
####################
|
||||
# - Methods
|
||||
####################
|
||||
def update_preview(self):
|
||||
node_tree = self.node.id_data
|
||||
|
||||
# Target Object Pinned
|
||||
if (
|
||||
self.show_preview
|
||||
and self.local_target_object
|
||||
and self.target_object_pinned
|
||||
):
|
||||
node_tree.non_preview_collection.objects.unlink(self.local_target_object)
|
||||
node_tree.preview_collection.objects.link(self.local_target_object)
|
||||
|
||||
elif (
|
||||
not self.show_preview
|
||||
and self.local_target_object
|
||||
and self.target_object_pinned
|
||||
):
|
||||
node_tree.preview_collection.objects.unlink(self.local_target_object)
|
||||
node_tree.non_preview_collection.objects.link(self.local_target_object)
|
||||
|
||||
# Target Object Not Pinned
|
||||
if (
|
||||
self.show_preview
|
||||
and self.local_target_object
|
||||
and not self.target_object_pinned
|
||||
and self.local_target_object.name in (
|
||||
node_tree.non_preview_collection.objects.keys()
|
||||
)
|
||||
):
|
||||
node_tree.non_preview_collection.objects.unlink(self.local_target_object)
|
||||
node_tree.preview_collection.objects.link(self.local_target_object)
|
||||
elif (
|
||||
not self.show_preview
|
||||
and self.local_target_object
|
||||
and not self.target_object_pinned
|
||||
and self.local_target_object.name in (
|
||||
node_tree.preview_collection.objects.keys()
|
||||
)
|
||||
):
|
||||
node_tree.preview_collection.objects.unlink(self.local_target_object)
|
||||
node_tree.non_preview_collection.objects.link(self.local_target_object)
|
||||
|
||||
self.trigger_updates()
|
||||
|
||||
####################
|
||||
# - UI
|
||||
####################
|
||||
def draw_label_row(self, label_col_row: bpy.types.UILayout, text) -> None:
|
||||
label_col_row.label(text=text)
|
||||
label_col_row.prop(self, "show_preview", toggle=True, text="", icon="SEQ_PREVIEW")
|
||||
label_col_row.prop(self, "show_definition", toggle=True, text="", icon="MOD_LENGTH")
|
||||
|
||||
def draw_value(self, col: bpy.types.UILayout) -> None:
|
||||
node_tree = self.node.id_data
|
||||
|
||||
if self.show_definition:
|
||||
col_row = col.row(align=True)
|
||||
col_row.alignment = "EXPAND"
|
||||
col_row.label(text="Target", icon="OBJECT_DATA")
|
||||
col_row.prop(
|
||||
self,
|
||||
"target_object_pinned",
|
||||
toggle=True,
|
||||
icon="EVENT_A",
|
||||
icon_only=True,
|
||||
)
|
||||
#col_row.operator(
|
||||
# "blender_maxwell.create_and_assign_target_bl_object",
|
||||
# text="",
|
||||
# icon="ADD",
|
||||
#)
|
||||
|
||||
col_row=col.row(align=True)
|
||||
col_row.alignment = "EXPAND"
|
||||
if not self.target_object_pinned:
|
||||
col_row.prop(self, "local_target_object", text="")
|
||||
|
||||
# Non-Preview Collection
|
||||
col_row=col.row(align=True)
|
||||
col_row.alignment = "EXPAND"
|
||||
col_row.label(text="Enabled", icon="COLLECTION_COLOR_04")
|
||||
col_row.prop(
|
||||
self,
|
||||
"preview_collection_pinned",
|
||||
toggle=True,
|
||||
icon="PINNED",
|
||||
icon_only=True,
|
||||
)
|
||||
|
||||
col_row=col.row(align=True)
|
||||
col_row.alignment = "EXPAND"
|
||||
if not self.preview_collection_pinned:
|
||||
col_row.prop(self, "local_preview_collection", text="")
|
||||
|
||||
# Non-Preview Collection
|
||||
col_row=col.row(align=True)
|
||||
col_row.alignment = "EXPAND"
|
||||
col_row.label(text="Disabled", icon="COLLECTION_COLOR_01")
|
||||
col_row.prop(
|
||||
self,
|
||||
"non_preview_collection_pinned",
|
||||
toggle=True,
|
||||
icon="PINNED",
|
||||
icon_only=True,
|
||||
)
|
||||
|
||||
col_row=col.row(align=True)
|
||||
col_row.alignment = "EXPAND"
|
||||
if not self.non_preview_collection_pinned:
|
||||
col_row.prop(self, "local_non_preview_collection", text="")
|
||||
|
||||
####################
|
||||
# - Default Value
|
||||
####################
|
||||
@property
|
||||
def default_value(self) -> bpy.types.Object:
|
||||
node_tree = self.node.id_data
|
||||
if not self.local_target_object and self.target_object_pinned:
|
||||
mk_and_assign_target_bl_obj(self, self.node, node_tree)
|
||||
return self.local_target_object
|
||||
|
||||
return self.local_target_object
|
||||
|
||||
@default_value.setter
|
||||
def default_value(self, value: typ.Any) -> None:
|
||||
pass
|
||||
|
||||
####################
|
||||
# - Cleanup
|
||||
####################
|
||||
def free(self) -> None:
|
||||
if self.local_target_object:
|
||||
bpy.data.meshes.remove(self.local_target_object.data, do_unlink=True)
|
||||
|
||||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class BlenderPreviewTargetSocketDef(pyd.BaseModel):
|
||||
socket_type: contracts.SocketType = contracts.SocketType.BlenderPreviewTarget
|
||||
label: str
|
||||
|
||||
show_preview: bool = True
|
||||
|
||||
def init(self, bl_socket: BlenderPreviewTargetBLSocket) -> None:
|
||||
pass
|
||||
#bl_socket.show_preview = self.show_preview
|
||||
|
||||
####################
|
||||
# - Blender Registration
|
||||
####################
|
||||
BL_REGISTER = [
|
||||
BlenderMaxwellCreateAndAssignTargetBLObject,
|
||||
BlenderPreviewTargetBLSocket,
|
||||
]
|
|
@ -7,6 +7,13 @@ import tidy3d as td
|
|||
from .. import base
|
||||
from ... import contracts
|
||||
|
||||
BOUND_FACE_ITEMS = [
|
||||
("PML", "PML", "Perfectly matched layer"),
|
||||
("PEC", "PEC", "Perfect electrical conductor"),
|
||||
("PMC", "PMC", "Perfect magnetic conductor"),
|
||||
("PERIODIC", "Periodic", "Infinitely periodic layer"),
|
||||
]
|
||||
|
||||
class MaxwellBoundBoxBLSocket(base.BLSocket):
|
||||
socket_type = contracts.SocketType.MaxwellBoundBox
|
||||
bl_label = "Maxwell Bound Box"
|
||||
|
@ -15,6 +22,72 @@ class MaxwellBoundBoxBLSocket(base.BLSocket):
|
|||
td.BoundarySpec: {}
|
||||
}
|
||||
|
||||
####################
|
||||
# - Properties
|
||||
####################
|
||||
x_pos: bpy.props.EnumProperty(
|
||||
name="+x Bound Face",
|
||||
description="+x choice of default boundary face",
|
||||
items=BOUND_FACE_ITEMS,
|
||||
default="PML",
|
||||
update=(lambda self, context: self.trigger_updates()),
|
||||
)
|
||||
x_neg: bpy.props.EnumProperty(
|
||||
name="-x Bound Face",
|
||||
description="-x choice of default boundary face",
|
||||
items=BOUND_FACE_ITEMS,
|
||||
default="PML",
|
||||
update=(lambda self, context: self.trigger_updates()),
|
||||
)
|
||||
y_pos: bpy.props.EnumProperty(
|
||||
name="+y Bound Face",
|
||||
description="+y choice of default boundary face",
|
||||
items=BOUND_FACE_ITEMS,
|
||||
default="PML",
|
||||
update=(lambda self, context: self.trigger_updates()),
|
||||
)
|
||||
y_neg: bpy.props.EnumProperty(
|
||||
name="-y Bound Face",
|
||||
description="-y choice of default boundary face",
|
||||
items=BOUND_FACE_ITEMS,
|
||||
default="PML",
|
||||
update=(lambda self, context: self.trigger_updates()),
|
||||
)
|
||||
z_pos: bpy.props.EnumProperty(
|
||||
name="+z Bound Face",
|
||||
description="+z choice of default boundary face",
|
||||
items=BOUND_FACE_ITEMS,
|
||||
default="PML",
|
||||
update=(lambda self, context: self.trigger_updates()),
|
||||
)
|
||||
z_neg: bpy.props.EnumProperty(
|
||||
name="-z Bound Face",
|
||||
description="-z choice of default boundary face",
|
||||
items=BOUND_FACE_ITEMS,
|
||||
default="PML",
|
||||
update=(lambda self, context: self.trigger_updates()),
|
||||
)
|
||||
|
||||
####################
|
||||
# - UI
|
||||
####################
|
||||
def draw_value(self, col: bpy.types.UILayout) -> None:
|
||||
col.label(text="-/+ x")
|
||||
col_row = col.row(align=True)
|
||||
col_row.prop(self, "x_neg", text="")
|
||||
col_row.prop(self, "x_pos", text="")
|
||||
|
||||
col.label(text="-/+ y")
|
||||
col_row = col.row(align=True)
|
||||
col_row.prop(self, "y_neg", text="")
|
||||
col_row.prop(self, "y_pos", text="")
|
||||
|
||||
col.label(text="-/+ z")
|
||||
col_row = col.row(align=True)
|
||||
col_row.prop(self, "z_neg", text="")
|
||||
col_row.prop(self, "z_pos", text="")
|
||||
|
||||
|
||||
####################
|
||||
# - Computation of Default Value
|
||||
####################
|
||||
|
|
|
@ -11,16 +11,40 @@ class MaxwellBoundFaceBLSocket(base.BLSocket):
|
|||
socket_type = contracts.SocketType.MaxwellBoundFace
|
||||
bl_label = "Maxwell Bound Face"
|
||||
|
||||
compatible_types = {
|
||||
td.BoundarySpec: {}
|
||||
}
|
||||
####################
|
||||
# - Properties
|
||||
####################
|
||||
default_choice: bpy.props.EnumProperty(
|
||||
name="Bound Face",
|
||||
description="A choice of default boundary face",
|
||||
items=[
|
||||
("PML", "PML", "Perfectly matched layer"),
|
||||
("PEC", "PEC", "Perfect electrical conductor"),
|
||||
("PMC", "PMC", "Perfect magnetic conductor"),
|
||||
("PERIODIC", "Periodic", "Infinitely periodic layer"),
|
||||
],
|
||||
default="PML",
|
||||
update=(lambda self, context: self.trigger_updates()),
|
||||
)
|
||||
|
||||
####################
|
||||
# - UI
|
||||
####################
|
||||
def draw_value(self, col: bpy.types.UILayout) -> None:
|
||||
col_row = col.row(align=True)
|
||||
col_row.prop(self, "default_choice", text="")
|
||||
|
||||
####################
|
||||
# - Computation of Default Value
|
||||
####################
|
||||
@property
|
||||
def default_value(self) -> td.BoundarySpec:
|
||||
return td.BoundarySpec()
|
||||
return {
|
||||
"PML": td.PML(num_layers=12),
|
||||
"PEC": td.PECBoundary(),
|
||||
"PMC": td.PMCBoundary(),
|
||||
"PERIODIC": td.Periodic(),
|
||||
}[self.default_choice]
|
||||
|
||||
@default_value.setter
|
||||
def default_value(self, value: typ.Any) -> None:
|
||||
|
@ -33,8 +57,10 @@ class MaxwellBoundFaceSocketDef(pyd.BaseModel):
|
|||
socket_type: contracts.SocketType = contracts.SocketType.MaxwellBoundFace
|
||||
label: str
|
||||
|
||||
default_choice: str = "PML"
|
||||
|
||||
def init(self, bl_socket: MaxwellBoundFaceBLSocket) -> None:
|
||||
pass
|
||||
bl_socket.default_choice = self.default_choice
|
||||
|
||||
####################
|
||||
# - Blender Registration
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import typing as typ
|
||||
|
||||
import bpy
|
||||
import pydantic as pyd
|
||||
|
||||
from .. import base
|
||||
|
@ -12,16 +13,26 @@ class IntegerNumberBLSocket(base.BLSocket):
|
|||
socket_type = contracts.SocketType.IntegerNumber
|
||||
bl_label = "IntegerNumber"
|
||||
|
||||
####################
|
||||
# - Properties
|
||||
####################
|
||||
raw_value: bpy.props.IntProperty(
|
||||
name="Integer",
|
||||
description="Represents an integer",
|
||||
default=0,
|
||||
update=(lambda self, context: self.trigger_updates()),
|
||||
)
|
||||
|
||||
####################
|
||||
# - Default Value
|
||||
####################
|
||||
@property
|
||||
def default_value(self) -> None:
|
||||
pass
|
||||
return self.raw_value
|
||||
|
||||
@default_value.setter
|
||||
def default_value(self, value: typ.Any) -> None:
|
||||
pass
|
||||
self.raw_value = int(value)
|
||||
|
||||
####################
|
||||
# - Socket Configuration
|
||||
|
@ -30,8 +41,10 @@ class IntegerNumberSocketDef(pyd.BaseModel):
|
|||
socket_type: contracts.SocketType = contracts.SocketType.IntegerNumber
|
||||
label: str
|
||||
|
||||
default_value: int = 0
|
||||
|
||||
def init(self, bl_socket: IntegerNumberBLSocket) -> None:
|
||||
pass
|
||||
bl_socket.raw_value = self.default_value
|
||||
|
||||
####################
|
||||
# - Blender Registration
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
from . import unit_system_socket
|
||||
PhysicalUnitSystemSocketDef = unit_system_socket.PhysicalUnitSystemSocketDef
|
||||
|
||||
from . import time_socket
|
||||
PhysicalTimeSocketDef = time_socket.PhysicalTimeSocketDef
|
||||
|
||||
|
@ -31,7 +34,9 @@ from . import pol_socket
|
|||
PhysicalPolSocketDef = pol_socket.PhysicalPolSocketDef
|
||||
|
||||
from . import freq_socket
|
||||
from . import vac_wl_socket
|
||||
PhysicalFreqSocketDef = freq_socket.PhysicalFreqSocketDef
|
||||
PhysicalVacWLSocketDef = vac_wl_socket.PhysicalVacWLSocketDef
|
||||
|
||||
from . import spec_rel_permit_dist_socket
|
||||
from . import spec_power_dist_socket
|
||||
|
@ -40,6 +45,8 @@ PhysicalSpecPowerDistSocketDef = spec_power_dist_socket.PhysicalSpecPowerDistSoc
|
|||
|
||||
|
||||
BL_REGISTER = [
|
||||
*unit_system_socket.BL_REGISTER,
|
||||
|
||||
*time_socket.BL_REGISTER,
|
||||
|
||||
*angle_socket.BL_REGISTER,
|
||||
|
@ -61,6 +68,7 @@ BL_REGISTER = [
|
|||
*pol_socket.BL_REGISTER,
|
||||
|
||||
*freq_socket.BL_REGISTER,
|
||||
*vac_wl_socket.BL_REGISTER,
|
||||
*spec_rel_permit_dist_socket.BL_REGISTER,
|
||||
*spec_power_dist_socket.BL_REGISTER,
|
||||
]
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import typing as typ
|
||||
|
||||
import bpy
|
||||
import pydantic as pyd
|
||||
|
||||
from .. import base
|
||||
|
@ -12,12 +13,44 @@ class PhysicalPolBLSocket(base.BLSocket):
|
|||
socket_type = contracts.SocketType.PhysicalPol
|
||||
bl_label = "PhysicalPol"
|
||||
|
||||
####################
|
||||
# - Properties
|
||||
####################
|
||||
default_choice: bpy.props.EnumProperty(
|
||||
name="Bound Face",
|
||||
description="A choice of default boundary face",
|
||||
items=[
|
||||
("EX", "Ex", "Linear x-pol of E field"),
|
||||
("EY", "Ey", "Linear y-pol of E field"),
|
||||
("EZ", "Ez", "Linear z-pol of E field"),
|
||||
("HX", "Hx", "Linear x-pol of H field"),
|
||||
("HY", "Hy", "Linear x-pol of H field"),
|
||||
("HZ", "Hz", "Linear x-pol of H field"),
|
||||
],
|
||||
default="EX",
|
||||
update=(lambda self, context: self.trigger_updates()),
|
||||
)
|
||||
|
||||
####################
|
||||
# - UI
|
||||
####################
|
||||
def draw_value(self, col: bpy.types.UILayout) -> None:
|
||||
col_row = col.row(align=True)
|
||||
col_row.prop(self, "default_choice", text="")
|
||||
|
||||
####################
|
||||
# - Default Value
|
||||
####################
|
||||
@property
|
||||
def default_value(self) -> None:
|
||||
pass
|
||||
def default_value(self) -> str:
|
||||
return {
|
||||
"EX": "Ex",
|
||||
"EY": "Ey",
|
||||
"EZ": "Ez",
|
||||
"HX": "Hx",
|
||||
"HY": "Hy",
|
||||
"HZ": "Hz",
|
||||
}[self.default_choice]
|
||||
|
||||
@default_value.setter
|
||||
def default_value(self, value: typ.Any) -> None:
|
||||
|
|
|
@ -13,17 +13,6 @@ class PhysicalSize3DBLSocket(base.BLSocket):
|
|||
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
|
||||
####################
|
||||
|
|
|
@ -0,0 +1,296 @@
|
|||
import typing as typ
|
||||
|
||||
import bpy
|
||||
import sympy as sp
|
||||
import pydantic as pyd
|
||||
|
||||
from .. import base
|
||||
from ... import contracts
|
||||
|
||||
def contract_units_to_items(socket_type):
|
||||
return [
|
||||
(
|
||||
unit_key,
|
||||
str(unit),
|
||||
f"{socket_type}-compatible unit",
|
||||
)
|
||||
for unit_key, unit in contracts.SocketType_to_units[
|
||||
socket_type
|
||||
]["values"].items()
|
||||
]
|
||||
def default_unit_key_for(socket_type):
|
||||
return contracts.SocketType_to_units[
|
||||
socket_type
|
||||
]["default"]
|
||||
|
||||
####################
|
||||
# - Blender Socket
|
||||
####################
|
||||
class PhysicalUnitSystemBLSocket(base.BLSocket):
|
||||
socket_type = contracts.SocketType.PhysicalUnitSystem
|
||||
bl_label = "PhysicalUnitSystem"
|
||||
|
||||
####################
|
||||
# - Properties
|
||||
####################
|
||||
show_definition: bpy.props.BoolProperty(
|
||||
name="Show Unit System Definition",
|
||||
description="Toggle to show unit system definition",
|
||||
default=False,
|
||||
update=(lambda self, context: self.trigger_updates()),
|
||||
)
|
||||
|
||||
unit_time: bpy.props.EnumProperty(
|
||||
name="Time Unit",
|
||||
description="Unit of time",
|
||||
items=contract_units_to_items(contracts.SocketType.PhysicalTime),
|
||||
default=default_unit_key_for(contracts.SocketType.PhysicalTime),
|
||||
update=(lambda self, context: self.trigger_updates()),
|
||||
)
|
||||
|
||||
unit_angle: bpy.props.EnumProperty(
|
||||
name="Angle Unit",
|
||||
description="Unit of angle",
|
||||
items=contract_units_to_items(contracts.SocketType.PhysicalAngle),
|
||||
default=default_unit_key_for(contracts.SocketType.PhysicalAngle),
|
||||
update=(lambda self, context: self.trigger_updates()),
|
||||
)
|
||||
|
||||
unit_length: bpy.props.EnumProperty(
|
||||
name="Length Unit",
|
||||
description="Unit of length",
|
||||
items=contract_units_to_items(contracts.SocketType.PhysicalLength),
|
||||
default=default_unit_key_for(contracts.SocketType.PhysicalLength),
|
||||
update=(lambda self, context: self.trigger_updates()),
|
||||
)
|
||||
unit_area: bpy.props.EnumProperty(
|
||||
name="Area Unit",
|
||||
description="Unit of area",
|
||||
items=contract_units_to_items(contracts.SocketType.PhysicalArea),
|
||||
default=default_unit_key_for(contracts.SocketType.PhysicalArea),
|
||||
update=(lambda self, context: self.trigger_updates()),
|
||||
)
|
||||
unit_volume: bpy.props.EnumProperty(
|
||||
name="Volume Unit",
|
||||
description="Unit of time",
|
||||
items=contract_units_to_items(contracts.SocketType.PhysicalVolume),
|
||||
default=default_unit_key_for(contracts.SocketType.PhysicalVolume),
|
||||
update=(lambda self, context: self.trigger_updates()),
|
||||
)
|
||||
|
||||
unit_point_2d: bpy.props.EnumProperty(
|
||||
name="Point2D Unit",
|
||||
description="Unit of 2D points",
|
||||
items=contract_units_to_items(contracts.SocketType.PhysicalPoint2D),
|
||||
default=default_unit_key_for(contracts.SocketType.PhysicalPoint2D),
|
||||
update=(lambda self, context: self.trigger_updates()),
|
||||
)
|
||||
unit_point_3d: bpy.props.EnumProperty(
|
||||
name="Point3D Unit",
|
||||
description="Unit of 3D points",
|
||||
items=contract_units_to_items(contracts.SocketType.PhysicalPoint3D),
|
||||
default=default_unit_key_for(contracts.SocketType.PhysicalPoint3D),
|
||||
update=(lambda self, context: self.trigger_updates()),
|
||||
)
|
||||
|
||||
unit_size_2d: bpy.props.EnumProperty(
|
||||
name="Size2D Unit",
|
||||
description="Unit of 2D sizes",
|
||||
items=contract_units_to_items(contracts.SocketType.PhysicalSize2D),
|
||||
default=default_unit_key_for(contracts.SocketType.PhysicalSize2D),
|
||||
update=(lambda self, context: self.trigger_updates()),
|
||||
)
|
||||
unit_size_3d: bpy.props.EnumProperty(
|
||||
name="Size3D Unit",
|
||||
description="Unit of 3D sizes",
|
||||
items=contract_units_to_items(contracts.SocketType.PhysicalSize3D),
|
||||
default=default_unit_key_for(contracts.SocketType.PhysicalSize3D),
|
||||
update=(lambda self, context: self.trigger_updates()),
|
||||
)
|
||||
|
||||
unit_mass: bpy.props.EnumProperty(
|
||||
name="Mass Unit",
|
||||
description="Unit of mass",
|
||||
items=contract_units_to_items(contracts.SocketType.PhysicalMass),
|
||||
default=default_unit_key_for(contracts.SocketType.PhysicalMass),
|
||||
update=(lambda self, context: self.trigger_updates()),
|
||||
)
|
||||
|
||||
unit_speed: bpy.props.EnumProperty(
|
||||
name="Speed Unit",
|
||||
description="Unit of speed",
|
||||
items=contract_units_to_items(contracts.SocketType.PhysicalSpeed),
|
||||
default=default_unit_key_for(contracts.SocketType.PhysicalSpeed),
|
||||
update=(lambda self, context: self.trigger_updates()),
|
||||
)
|
||||
unit_accel_scalar: bpy.props.EnumProperty(
|
||||
name="Accel Unit",
|
||||
description="Unit of acceleration",
|
||||
items=contract_units_to_items(contracts.SocketType.PhysicalAccelScalar),
|
||||
default=default_unit_key_for(contracts.SocketType.PhysicalAccelScalar),
|
||||
update=(lambda self, context: self.trigger_updates()),
|
||||
)
|
||||
unit_force_scalar: bpy.props.EnumProperty(
|
||||
name="Force Scalar Unit",
|
||||
description="Unit of scalar force",
|
||||
items=contract_units_to_items(contracts.SocketType.PhysicalForceScalar),
|
||||
default=default_unit_key_for(contracts.SocketType.PhysicalForceScalar),
|
||||
update=(lambda self, context: self.trigger_updates()),
|
||||
)
|
||||
unit_accel_3d_vector: bpy.props.EnumProperty(
|
||||
name="Accel3D Unit",
|
||||
description="Unit of 3D vector acceleration",
|
||||
items=contract_units_to_items(contracts.SocketType.PhysicalAccel3DVector),
|
||||
default=default_unit_key_for(contracts.SocketType.PhysicalAccel3DVector),
|
||||
update=(lambda self, context: self.trigger_updates()),
|
||||
)
|
||||
unit_force_3d_vector: bpy.props.EnumProperty(
|
||||
name="Force3D Unit",
|
||||
description="Unit of 3D vector force",
|
||||
items=contract_units_to_items(contracts.SocketType.PhysicalForce3DVector),
|
||||
default=default_unit_key_for(contracts.SocketType.PhysicalForce3DVector),
|
||||
update=(lambda self, context: self.trigger_updates()),
|
||||
)
|
||||
|
||||
unit_freq: bpy.props.EnumProperty(
|
||||
name="Freq Unit",
|
||||
description="Unit of frequency",
|
||||
items=contract_units_to_items(contracts.SocketType.PhysicalFreq),
|
||||
default=default_unit_key_for(contracts.SocketType.PhysicalFreq),
|
||||
update=(lambda self, context: self.trigger_updates()),
|
||||
)
|
||||
unit_vac_wl: bpy.props.EnumProperty(
|
||||
name="VacWL Unit",
|
||||
description="Unit of vacuum wavelength",
|
||||
items=contract_units_to_items(contracts.SocketType.PhysicalVacWL),
|
||||
default=default_unit_key_for(contracts.SocketType.PhysicalVacWL),
|
||||
update=(lambda self, context: self.trigger_updates()),
|
||||
)
|
||||
|
||||
####################
|
||||
# - UI
|
||||
####################
|
||||
def draw_label_row(self, label_col_row: bpy.types.UILayout, text) -> None:
|
||||
label_col_row.label(text=text)
|
||||
label_col_row.prop(self, "show_definition", toggle=True, text="", icon="MOD_LENGTH")
|
||||
|
||||
def draw_value(self, col: bpy.types.UILayout) -> None:
|
||||
if self.show_definition:
|
||||
col_row=col.row(align=True)
|
||||
col_row.alignment = "EXPAND"
|
||||
col_row.prop(self, "unit_time", text="")
|
||||
col_row.prop(self, "unit_angle", text="")
|
||||
|
||||
col_row=col.row(align=True)
|
||||
col_row.alignment = "EXPAND"
|
||||
col_row.prop(self, "unit_length", text="")
|
||||
col_row.prop(self, "unit_area", text="")
|
||||
col_row.prop(self, "unit_volume", text="")
|
||||
|
||||
col_row=col.row(align=True)
|
||||
col_row.alignment = "EXPAND"
|
||||
col_row.label(text="Point")
|
||||
col_row.prop(self, "unit_point_2d", text="")
|
||||
col_row.prop(self, "unit_point_3d", text="")
|
||||
|
||||
col_row=col.row(align=True)
|
||||
col_row.alignment = "EXPAND"
|
||||
col_row.label(text="Size")
|
||||
col_row.prop(self, "unit_size_2d", text="")
|
||||
col_row.prop(self, "unit_size_3d", text="")
|
||||
|
||||
col_row=col.row(align=True)
|
||||
col_row.alignment = "EXPAND"
|
||||
col_row.label(text="Mass")
|
||||
col_row.prop(self, "unit_mass", text="")
|
||||
|
||||
col_row=col.row(align=True)
|
||||
col_row.alignment = "EXPAND"
|
||||
col_row.label(text="Vel")
|
||||
col_row.prop(self, "unit_speed", text="")
|
||||
#col_row.prop(self, "unit_vel_2d_vector", text="")
|
||||
#col_row.prop(self, "unit_vel_3d_vector", text="")
|
||||
|
||||
col_row=col.row(align=True)
|
||||
col_row.label(text="Accel")
|
||||
col_row.prop(self, "unit_accel_scalar", text="")
|
||||
#col_row.prop(self, "unit_accel_2d_vector", text="")
|
||||
col_row.prop(self, "unit_accel_3d_vector", text="")
|
||||
|
||||
col_row=col.row(align=True)
|
||||
col_row.label(text="Force")
|
||||
col_row.prop(self, "unit_force_scalar", text="")
|
||||
#col_row.prop(self, "unit_force_2d_vector", text="")
|
||||
col_row.prop(self, "unit_force_3d_vector", text="")
|
||||
|
||||
col_row=col.row(align=True)
|
||||
col_row.alignment = "EXPAND"
|
||||
col_row.label(text="Freq")
|
||||
col_row.prop(self, "unit_freq", text="")
|
||||
|
||||
col_row=col.row(align=True)
|
||||
col_row.alignment = "EXPAND"
|
||||
col_row.label(text="Vac WL")
|
||||
col_row.prop(self, "unit_vac_wl", text="")
|
||||
|
||||
####################
|
||||
# - Default Value
|
||||
####################
|
||||
@property
|
||||
def default_value(self) -> sp.Expr:
|
||||
ST = contracts.SocketType
|
||||
SM = lambda socket_type: contracts.SocketType_to_units[
|
||||
socket_type
|
||||
]["values"]
|
||||
|
||||
return {
|
||||
socket_type: SM(socket_type)[socket_unit_prop]
|
||||
for socket_type, socket_unit_prop in [
|
||||
(ST.PhysicalTime, self.unit_time),
|
||||
(ST.PhysicalAngle, self.unit_angle),
|
||||
|
||||
(ST.PhysicalLength, self.unit_length),
|
||||
(ST.PhysicalArea, self.unit_area),
|
||||
(ST.PhysicalVolume, self.unit_volume),
|
||||
|
||||
(ST.PhysicalPoint2D, self.unit_point_2d),
|
||||
(ST.PhysicalPoint3D, self.unit_point_3d),
|
||||
|
||||
(ST.PhysicalSize2D, self.unit_size_2d),
|
||||
(ST.PhysicalSize3D, self.unit_size_3d),
|
||||
|
||||
(ST.PhysicalMass, self.unit_mass),
|
||||
|
||||
(ST.PhysicalSpeed, self.unit_speed),
|
||||
(ST.PhysicalAccelScalar, self.unit_accel_scalar),
|
||||
(ST.PhysicalForceScalar, self.unit_force_scalar),
|
||||
(ST.PhysicalAccel3DVector, self.unit_accel_3d_vector),
|
||||
(ST.PhysicalForce3DVector, self.unit_force_3d_vector),
|
||||
|
||||
(ST.PhysicalFreq, self.unit_freq),
|
||||
(ST.PhysicalVacWL, self.unit_vac_wl),
|
||||
]
|
||||
}
|
||||
|
||||
@default_value.setter
|
||||
def default_value(self, value: typ.Any) -> None:
|
||||
pass
|
||||
|
||||
####################
|
||||
# - Socket Configuration
|
||||
####################
|
||||
class PhysicalUnitSystemSocketDef(pyd.BaseModel):
|
||||
socket_type: contracts.SocketType = contracts.SocketType.PhysicalUnitSystem
|
||||
label: str
|
||||
|
||||
show_by_default: bool = False
|
||||
|
||||
def init(self, bl_socket: PhysicalUnitSystemBLSocket) -> None:
|
||||
bl_socket.show_definition = self.show_by_default
|
||||
|
||||
####################
|
||||
# - Blender Registration
|
||||
####################
|
||||
BL_REGISTER = [
|
||||
PhysicalUnitSystemBLSocket,
|
||||
]
|
|
@ -0,0 +1,54 @@
|
|||
import typing as typ
|
||||
|
||||
import bpy
|
||||
import pydantic as pyd
|
||||
|
||||
from .. import base
|
||||
from ... import contracts
|
||||
|
||||
####################
|
||||
# - Blender Socket
|
||||
####################
|
||||
class PhysicalVacWLBLSocket(base.BLSocket):
|
||||
socket_type = contracts.SocketType.PhysicalVacWL
|
||||
bl_label = "PhysicalVacWL"
|
||||
use_units = True
|
||||
|
||||
####################
|
||||
# - Properties
|
||||
####################
|
||||
raw_value: bpy.props.FloatProperty(
|
||||
name="Unitless Vacuum Wavelength",
|
||||
description="Represents the unitless part of the vacuum wavelength",
|
||||
default=0.0,
|
||||
precision=6,
|
||||
update=(lambda self, context: self.trigger_updates()),
|
||||
)
|
||||
|
||||
####################
|
||||
# - 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 PhysicalVacWLSocketDef(pyd.BaseModel):
|
||||
socket_type: contracts.SocketType = contracts.SocketType.PhysicalVacWL
|
||||
label: str
|
||||
|
||||
def init(self, bl_socket: PhysicalVacWLBLSocket) -> None:
|
||||
pass
|
||||
|
||||
####################
|
||||
# - Blender Registration
|
||||
####################
|
||||
BL_REGISTER = [
|
||||
PhysicalVacWLBLSocket,
|
||||
]
|
|
@ -1,5 +1,7 @@
|
|||
import typing as typ
|
||||
|
||||
import bpy
|
||||
import sympy as sp
|
||||
import pydantic as pyd
|
||||
|
||||
from .. import base
|
||||
|
@ -13,15 +15,27 @@ class Real2DVectorBLSocket(base.BLSocket):
|
|||
bl_label = "Real2DVector"
|
||||
|
||||
####################
|
||||
# - Default Value
|
||||
# - Properties
|
||||
####################
|
||||
raw_value: bpy.props.FloatVectorProperty(
|
||||
name="Unitless 2D Vector (global coordinate system)",
|
||||
description="Represents a real 2D (coordinate) vector",
|
||||
size=2,
|
||||
default=(0.0, 0.0),
|
||||
precision=4,
|
||||
update=(lambda self, context: self.trigger_updates()),
|
||||
)
|
||||
|
||||
####################
|
||||
# - Computation of Default Value
|
||||
####################
|
||||
@property
|
||||
def default_value(self) -> None:
|
||||
pass
|
||||
def default_value(self) -> sp.Expr:
|
||||
return tuple(self.raw_value)
|
||||
|
||||
@default_value.setter
|
||||
def default_value(self, value: typ.Any) -> None:
|
||||
pass
|
||||
self.raw_value = tuple(value)
|
||||
|
||||
####################
|
||||
# - Socket Configuration
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import typing as typ
|
||||
|
||||
import bpy
|
||||
import sympy as sp
|
||||
import pydantic as pyd
|
||||
|
||||
from .. import base
|
||||
|
@ -13,15 +15,27 @@ class Real3DVectorBLSocket(base.BLSocket):
|
|||
bl_label = "Real3DVector"
|
||||
|
||||
####################
|
||||
# - Default Value
|
||||
# - Properties
|
||||
####################
|
||||
raw_value: bpy.props.FloatVectorProperty(
|
||||
name="Unitless 3D Vector (global coordinate system)",
|
||||
description="Represents a real 3D (coordinate) vector",
|
||||
size=3,
|
||||
default=(0.0, 0.0, 0.0),
|
||||
precision=4,
|
||||
update=(lambda self, context: self.trigger_updates()),
|
||||
)
|
||||
|
||||
####################
|
||||
# - Computation of Default Value
|
||||
####################
|
||||
@property
|
||||
def default_value(self) -> None:
|
||||
pass
|
||||
def default_value(self) -> sp.Expr:
|
||||
return tuple(self.raw_value)
|
||||
|
||||
@default_value.setter
|
||||
def default_value(self, value: typ.Any) -> None:
|
||||
pass
|
||||
self.raw_value = tuple(value)
|
||||
|
||||
####################
|
||||
# - Socket Configuration
|
||||
|
|
BIN
code/demo.blend (Stored with Git LFS)
BIN
code/demo.blend (Stored with Git LFS)
Binary file not shown.
Loading…
Reference in New Issue