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 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
return True
# 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
adjacency_cache[key] = False
return False
# Normals are parallel — also verify the elements share a face plane.
# Project all vertices onto n_a to get the 1-D depth range of each
# element along the normal axis. Side-by-side elements span the same
# depth range (overlap > tol). Elements stacked end-to-end only touch
# at a single interface point (overlap ≈ 0) and must not be joined.
projs_a = [v.dot(n_a) for v in verts_a]
projs_b = [v.dot(n_a) for v in verts_b]
# Check whether both elements are at the same depth relative to the
# camera. Project vertices onto the camera look direction: elements
# at the same camera depth have overlapping ranges; depth-stacked
# elements (one in front of the other) have separated ranges.
# Using the camera direction rather than n_a is critical — n_a may
# be perpendicular to the camera (e.g. X-normal boxes in plan view)
# 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_b = (min(projs_b), max(projs_b))
overlap = min(range_a[1], range_b[1]) - max(range_a[0], range_b[0])