CNA-BUG-070: BoundingSphere::Contains(Vector3) and Contains(BoundingSphere) return different ContainmentType values from XNA 4.0

CNA snapshot 009d40f5  ·  Known Issues › Current bugs  ·  source links pinned to 009d40f5

✓

Evidence basis: source-verified at the pinned commit; tests exist (not executed for this page). Claims on this page were checked by reading the CNA source at commit 009d40f5; unless a sentence says otherwise, nothing here was built or executed. Nothing on this page was executed unless the Evidence section says so.

A point exactly on the surface is Intersects in CNA (XNA: Disjoint), and Contains(BoundingSphere) tests d^2 <= (R - r)^2, losing the sign of R - r, so a small sphere reports that it Contains a larger concentric sphere (XNA: Intersects).

Identifier
CNA-BUG-070
Category
Bug
Subsystem
Math & geometry
Status
Open
Verified against
CNA 009d40f5 (009d40f5dd085c4e674d3479675fac84b12b3e0a)
Severity
Medium (a triage suggestion, not a project priority)
Evidence basis
Source-verified: read at TARGET, not executed
Tests touching this area
Yes: see Current tests
Affected contract
Microsoft::Xna::Framework::BoundingSphere::Contains(Vector3), Contains(BoundingSphere) and their out-parameter overloads

Expected behaviour

XNA 4.0 (IL): Contains(Vector3) returns Contains when DistanceSquared(point, Center) < Radius*Radius and Disjoint otherwise - never Intersects. Contains(BoundingSphere) computes d = Distance(Center, sphere.Center); Disjoint if R + r < d, Contains if R - r >= d, otherwise Intersects.

Actual behaviour at TARGET

BoundingSphere.cpp returns Intersects for sqDistance == sqRadius in the point overload, where XNA 4.0 answers Disjoint (it returns Contains only for DistanceSquared < Radius*Radius). The sphere overload's Contains test is sqDistance <= (Radius - sphere.Radius) * (Radius - sphere.Radius): squaring discards the sign, so a radius-1 sphere asked about a concentric radius-5 sphere answers Contains. BoundingSphere::Contains(BoundingBox) and Contains(const BoundingFrustum&) use the point overload only as a “corner is not Disjoint” test, which counts a corner lying exactly on the surface as inside; XNA's own corner test (outside only when the squared distance exceeds Radius*Radius) does the same, so the surface difference does not change those two overloads' answers.

Source locations

Evidence

Checked by reading the named sources at 009d40f5; nothing was built or executed for this entry. XNA behaviour from the genuine XNA 4.0 IL (ContainmentType Disjoint=0, Contains=1, Intersects=2). The sphere overload's formula came from FNA.

Focused reproduction

// Illustrative; not compiled or run for this entry.
BoundingSphere small(Vector3::Zero, 1.0f), big(Vector3::Zero, 5.0f);
auto a = small.Contains(big);                   // XNA: Intersects   CNA: Contains
auto b = small.Contains(Vector3(1, 0, 0));      // XNA: Disjoint     CNA: Intersects

Current tests

BoundingSphereTests.cpp pins the non-XNA surface answer in ContainsPointOnBoundaryIsIntersects; no test checks a larger argument sphere.

Regression test

Change ContainsPointOnBoundaryIsIntersects to expect Disjoint, and add a test that a sphere does not Contain a larger concentric sphere.

Blast radius

Culling, trigger volumes and spatial partitioning that nest spheres; the enclosing-sphere case can make a container claim ownership of a larger object.

Workaround

Compare radii before calling Contains(BoundingSphere).

The same subject is explained at several altitudes. These are the neighbouring pages at each one.

Known issues
Bug index