Fix depth check to use camera direction instead of face normal

The same-plane check projected vertices onto the dominant face
normal (n_a) to determine if two elements span the same depth
range. This correctly rejected slabs stacked along their normal
axis but broke for elements whose largest face is perpendicular
to the camera (e.g. X-normal boxes in plan view) — projection
onto X produces zero overlap for legitimate side-by-side pairs.

Replace n_a projection with projection onto _cam_look. Elements
at the same camera depth produce overlapping ranges and are joined;
elements separated in camera depth produce disjoint ranges and are
correctly rejected regardless of the orientation of their faces.

Generated with the assistance of an AI coding tool.
This commit is contained in:
Ryan Schultz
2026-04-07 13:28:08 -05:00
parent 16d2ec64b4
commit 6c993ba919
@@ -1729,7 +1729,8 @@ class CreateDrawing(bpy.types.Operator):
return False return False
return True return True
if aabb_contains(corners_a, corners_b) or aabb_contains(corners_b, corners_a): contained = aabb_contains(corners_a, corners_b) or aabb_contains(corners_b, corners_a)
if contained:
adjacency_cache[key] = True adjacency_cache[key] = True
return True return True
# Coplanarity check: use the largest-face normal for each object. # Coplanarity check: use the largest-face normal for each object.
@@ -1750,13 +1751,15 @@ class CreateDrawing(bpy.types.Operator):
if dot <= 1.0 - 3.8e-5: # ~0.5° tolerance if dot <= 1.0 - 3.8e-5: # ~0.5° tolerance
adjacency_cache[key] = False adjacency_cache[key] = False
return False return False
# Normals are parallel — also verify the elements share a face plane. # Check whether both elements are at the same depth relative to the
# Project all vertices onto n_a to get the 1-D depth range of each # camera. Project vertices onto the camera look direction: elements
# element along the normal axis. Side-by-side elements span the same # at the same camera depth have overlapping ranges; depth-stacked
# depth range (overlap > tol). Elements stacked end-to-end only touch # elements (one in front of the other) have separated ranges.
# at a single interface point (overlap ≈ 0) and must not be joined. # Using the camera direction rather than n_a is critical — n_a may
projs_a = [v.dot(n_a) for v in verts_a] # be perpendicular to the camera (e.g. X-normal boxes in plan view)
projs_b = [v.dot(n_a) for v in verts_b] # which would produce zero overlap for legitimate side-by-side pairs.
projs_a = [v.dot(_cam_look) for v in verts_a]
projs_b = [v.dot(_cam_look) for v in verts_b]
range_a = (min(projs_a), max(projs_a)) range_a = (min(projs_a), max(projs_a))
range_b = (min(projs_b), max(projs_b)) range_b = (min(projs_b), max(projs_b))
overlap = min(range_a[1], range_b[1]) - max(range_a[0], range_b[0]) overlap = min(range_a[1], range_b[1]) - max(range_a[0], range_b[0])