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

@@ -43,13 +43,13 @@ def test_cutout_depth_axis_is_adjusted_only_in_modifier(shape, gesture):
positive_x = _create_cutout_shape(
source,
shape,
8,
0.1,
gesture=gesture,
)
negative_z = _create_cutout_shape(
source,
shape,
8,
0.1,
gesture=gesture,
)
@@ -160,7 +160,7 @@ def test_balloon_build_starts_from_the_unified_single_sheet():
result = _create_cutout_shape(
source,
"SOLID",
8,
0.1,
)
assert all(abs(vertex.co.z) < 1e-8 for vertex in result.data.vertices)
@@ -211,7 +211,7 @@ def test_teddy_preference_writes_the_shared_balloon_attribute():
result = _create_cutout_shape(
source,
"FLAT",
8,
0.1,
)
attribute = result.data.attributes[cutout_shape.BALLOON_ATTRIBUTE_NAME]
@@ -251,7 +251,7 @@ def test_depth_surface_protected_smooth_evaluates(gesture):
result = _create_cutout_shape(
source,
"DEPTH_SOLID",
8,
0.25,
depth_image=depth_image,
depth_metadata=depth_metadata,
gesture=gesture,
@@ -270,7 +270,7 @@ def test_depth_surface_protected_smooth_evaluates(gesture):
0.0,
)
expected_cleanup = cutout_geometry.cutout_cleanup_value(
cutout_geometry.cutout_sampling_spacing(source, 8),
0.25,
cutout_geometry.world_plane_metric(source.matrix_world)[0],
)
assert np.isclose(
@@ -374,7 +374,7 @@ def test_depth_surface_keeps_continuous_points_across_zero_validity_edge():
result = _create_cutout_shape(
source,
"DEPTH_SOLID",
8,
0.1,
depth_image=_depth_image(points, validity),
depth_metadata=_depth_metadata(intrinsics, (size, size), 1.0),
)
@@ -621,7 +621,7 @@ def test_depth_balloon_uses_metric_plane_inputs():
result = _create_cutout_shape(
source,
"DEPTH_BALLOON",
8,
0.1,
depth_image=depth_image,
depth_metadata=depth_metadata,
bounds=crop_bounds,
@@ -869,7 +869,7 @@ def test_local_cutout_builds_from_blender_image_pixels_without_a_job():
bpy.context,
source,
"FLAT",
16,
0.1,
content_values,
selection_mask.bounds,
alpha_threshold=0.5,
@@ -885,7 +885,7 @@ def test_local_cutout_builds_from_blender_image_pixels_without_a_job():
modifier = result.modifiers[0]
assert modifier.node_group.name == cutout_shape.CUTOUT_NODE_GROUP_NAMES["FLAT"]
expected_cleanup = cutout_geometry.cutout_cleanup_value(
cutout_geometry.cutout_sampling_spacing(source, 16),
0.1,
cutout_geometry.world_plane_metric(source.matrix_world)[0],
)
assert np.isclose(