Add tests and implement boundary smoothing and cutout functionality
- Introduced tests for boundary smoothing in `test_boundary_smoothing.py`, verifying that smoothing reduces stair-step artifacts while preserving boundary integrity. - Added tests for cutout boundary behavior in `test_cutout_boundary.py`, ensuring proper handling of boundary triangles and normal blending. - Created `test_temporary_attributes.py` to check the cleanup of temporary attributes across depth modifier branches, ensuring no warnings are raised. - Implemented point culling functionality in `test_validity.py`, confirming that invalid points are removed without affecting adjacent geometry. - Developed boundary smoothing logic in `boundary_smoothing.py`, allowing for depth smoothing while maintaining edge integrity. - Added cutout boundary management in `cutout_boundary.py`, including functions for removing boundary triangles and tapering thickness profiles. - Implemented validity checks in `validity.py` to ensure proper deletion of invalid vertices and associated wire edges.
This commit is contained in:
@@ -114,13 +114,45 @@ def evaluate_field(group, value, data_type, domain):
|
||||
return node.outputs["Value"]
|
||||
|
||||
|
||||
def capture_fields(group, geometry, domain, **fields):
|
||||
"""Keep source fields attached to geometry through later changes."""
|
||||
node = group.nodes.new("GeometryNodeCaptureAttribute")
|
||||
node.domain = domain
|
||||
node.capture_items.clear()
|
||||
def sample_field(group, geometry, value, data_type, domain="POINT", index=None):
|
||||
"""Evaluate a field on an explicit source geometry and index domain."""
|
||||
node = group.nodes.new("GeometryNodeSampleIndex")
|
||||
node.data_type, node.domain = data_type, domain
|
||||
node.clamp = False
|
||||
if index is None:
|
||||
index = group.nodes.new("GeometryNodeInputIndex").outputs["Index"]
|
||||
group.links.new(geometry, node.inputs["Geometry"])
|
||||
for name, (data_type, value) in fields.items():
|
||||
node.capture_items.new(data_type, name)
|
||||
group.links.new(value, node.inputs[name])
|
||||
return node.outputs["Geometry"], {name: node.outputs[name] for name in fields}
|
||||
group.links.new(value, node.inputs["Value"])
|
||||
group.links.new(index, node.inputs["Index"])
|
||||
return node.outputs["Value"]
|
||||
|
||||
|
||||
def store_boolean_attribute(group, geometry, name, value, domain="POINT"):
|
||||
"""Store a topology marker needed after destructive mesh operations."""
|
||||
node = group.nodes.new("GeometryNodeStoreNamedAttribute")
|
||||
node.domain, node.data_type = domain, "BOOLEAN"
|
||||
node.inputs["Name"].default_value = name
|
||||
group.links.new(geometry, node.inputs["Geometry"])
|
||||
group.links.new(value, node.inputs["Value"])
|
||||
read = group.nodes.new("GeometryNodeInputNamedAttribute")
|
||||
read.data_type = "BOOLEAN"
|
||||
read.inputs["Name"].default_value = name
|
||||
return node.outputs["Geometry"], read.outputs["Attribute"]
|
||||
|
||||
|
||||
def remove_attributes(group, geometry, *names, enabled=None):
|
||||
"""Remove only the explicitly owned temporary attributes."""
|
||||
original = geometry
|
||||
for name in names:
|
||||
node = group.nodes.new("GeometryNodeRemoveAttribute")
|
||||
node.inputs["Name"].default_value = name
|
||||
group.links.new(geometry, node.inputs["Geometry"])
|
||||
geometry = node.outputs["Geometry"]
|
||||
if enabled is not None:
|
||||
choose = group.nodes.new("GeometryNodeSwitch")
|
||||
choose.input_type = "GEOMETRY"
|
||||
group.links.new(enabled, choose.inputs["Switch"])
|
||||
group.links.new(original, choose.inputs["False"])
|
||||
group.links.new(geometry, choose.inputs["True"])
|
||||
geometry = choose.outputs["Output"]
|
||||
return geometry
|
||||
|
||||
Reference in New Issue
Block a user