Refactor Cutout Tool to Use World Space Edge Length

- Replaced the Mesh Detail parameter with a new Edge Length property to define cutout sampling in physical units.
- Introduced Minimum Relative Edge Length preference to control effective spacing based on the bounding box of the cutout content.
- Updated tests to validate the new edge length functionality and ensure consistent behavior across different resolutions and canvas sizes.
- Removed deprecated parameters and adjusted related properties to align with the new edge length implementation.
- Enhanced geometry sampling logic to utilize effective world spacing for both standard and fine outline modes.
This commit is contained in:
2026-09-12 23:03:24 +08:00
parent 938d95db0f
commit 18799e8828
28 changed files with 505 additions and 279 deletions

View File

@@ -67,7 +67,7 @@ def test_saved_parameter_descriptions_match_definitions():
assert len(thickness) == 2 and len(set(thickness)) == 2
if group.name == "O Image Depth Cutout":
inflation = next(item for item in sockets if item.name == "Front Inflation")
assert inflation.default_value == 0.5
assert inflation.default_value == 0.0
result[group.name] = [
(item.identifier, item.name, item.description) for item in sockets
]
@@ -82,6 +82,35 @@ def test_saved_parameter_descriptions_match_definitions():
assert descriptions(target.node_groups) == expected
@pytest.mark.parametrize("source", ["definition", "asset"])
def test_geometry_nodes_contribute_to_output(source):
from tools.nodes.build import build_node_groups
bpy.ops.wm.read_factory_settings(use_empty=True)
if source == "definition":
groups = build_node_groups()
else:
with bpy.data.libraries.load(str(node_asset_path())) as (library, target):
target.node_groups = list(library.node_groups)
groups = target.node_groups
for group in groups:
if group.bl_idname != "GeometryNodeTree":
continue
pending = [node for node in group.nodes if node.bl_idname == "NodeGroupOutput"]
used = set()
while pending:
node = pending.pop()
if node in used:
continue
used.add(node)
pending.extend(link.from_node for socket in node.inputs for link in socket.links)
pending.extend(candidate for candidate in group.nodes
if getattr(candidate, "paired_output", None) == node)
unused = [node.name for node in group.nodes
if node not in used and node.bl_idname != "NodeFrame"]
assert not unused, (group.name, unused)
@pytest.mark.parametrize("source", ["definition", "asset"])
def test_geometry_attribute_contract_includes_nested_groups(source):
from tools.nodes.build import build_node_groups