Skip to content

Fix Box VolumeBelow/CenterOfVolumeBelow#724

Merged
caguero merged 1 commit intomainfrom
fix/box-volume-below-centroid-sphere-float
Mar 16, 2026
Merged

Fix Box VolumeBelow/CenterOfVolumeBelow#724
caguero merged 1 commit intomainfrom
fix/box-volume-below-centroid-sphere-float

Conversation

@caguero
Copy link
Copy Markdown
Contributor

@caguero caguero commented Mar 15, 2026

🦟 Bug fix

Summary

This patch fixes some functions used to compute graded buoyancy.

  • Replace Box::VolumeBelow and Box::CenterOfVolumeBelow with analytic inclusion-exclusion formulas (Scardovelli-Zaleski / Lehmann-Gekle), fixing two bugs:
    • VolumeBelow used TrianglesInPlane which relied on exact float comparison (Plane::Side() == NO_SIDE) and produced wrong volumes for non-axis-aligned planes
    • CenterOfVolumeBelow returned arithmetic mean of vertex positions instead of volumetric centroid, only correct for axis-aligned cuts
  • Delete TrianglesInPlane free function and remove Triangle3.hh include (no longer needed)
  • Fix Sphere<float> compilation by replacing hardcoded Vector3d with Vector3<T>::Zero in VolumeBelow and CenterOfVolumeBelow

Bugs fixed

  1. Box::VolumeBelow wrong for non-axis-aligned planes: The old mesh-based implementation used TrianglesInPlane, which classified vertices with exact float comparison (Plane::Side() == NO_SIDE, requiring Distance == 0.0). Vertices with any FP error were silently dropped, producing incorrect polygon decompositions. Example: box 4x2x6 with plane n=(2,1,3) gave 26.22 instead of the correct 26.67.

  2. Box::CenterOfVolumeBelow fundamentally wrong formula: The old code computed sum(vertices) / count(vertices) — the arithmetic mean of polygon vertices, not the volumetric centroid. This is only correct for axis-aligned cuts. For any diagonal plane, the conservation law CoV_below * V_below + CoV_above * V_above = (0,0,0) was violated.

  3. Sphere<float> compilation failure: VolumeBelow and CenterOfVolumeBelow hardcoded Vector3d(0,0,0) instead of Vector3<T>::Zero. Instantiating Sphere<float> failed because Plane<float>::Distance() has no overload accepting Vector3d.

Improvements

Old New
VolumeBelow O(n) mesh reconstruction: 7 planes, vertex classification, angle sorting, divergence theorem over triangles O(1) closed-form: 8 max(0,x)^3 terms, one division
CenterOfVolumeBelow Same O(n) mesh reconstruction + vertex averaging O(1) closed-form: at most 32 max(0,x)^k evaluations
Heap allocations std::vector and std::set per call Zero — only stack std::arrays
Dependencies Triangle3.hh, <vector>, <utility>, <set> <array>, <cmath>
Numerical robustness Fragile: exact float equality, WellOrderedVectors 1e-3 tolerance (broke for boxes < ~0.002), triangle winding Robust: only abs, max(0,x), and arithmetic; no tolerance parameters

Test plan

  • New BoxTest.VolumeBelowDiagonalPlanes: tetrahedron corner cut, non-unit normals, asymmetric box, tangent plane, very small box (exposes old 1e-3 tolerance bug), complementary planes
  • New BoxTest.CenterOfVolumeBelowDiagonal: direction check, tetrahedron centroid, symmetry, weighted-sum conservation, 2D normal (k=2 path), flipped 3D normal (sign transform)
  • New SphereTest.VolumeBelowFloat: Sphere<float> VolumeBelow + CenterOfVolumeBelow compile and produce correct results
  • All 193 existing tests continue to pass
  • Verified new tests fail against old implementation

Checklist

  • Signed all commits for DCO
  • Added a screen capture or video to the PR description that demonstrates the fix (as needed)
  • Added tests
  • Updated documentation (as needed)
  • Updated migration guide (as needed)
  • Consider updating Python bindings (if the library has them)
  • codecheck passed (See contributing)
  • All tests passed (See test coverage)
  • Updated Bazel files (if adding new files). Created an issue otherwise.
  • While waiting for a review on your PR, please help review another open pull request to support the maintainers
  • Was GenAI used to generate this PR? If so, make sure to add "Generated-by" to your commits. (See this policy for more info.)

Generated-by: Opus 4.6

Note to maintainers: Remember to use Squash-Merge and edit the commit message to match the pull request summary while retaining Signed-off-by and Generated-by messages.

Backports: If this is a backport, please use Rebase and Merge instead.

@caguero caguero force-pushed the fix/box-volume-below-centroid-sphere-float branch 2 times, most recently from 90cd8d6 to 8be3c41 Compare March 15, 2026 23:41
@caguero caguero changed the title Fix Box VolumeBelow/CenterOfVolumeBelow and Sphere<float> type error Fix Box VolumeBelow/CenterOfVolumeBelow Mar 15, 2026
@caguero caguero requested a review from arjo129 March 15, 2026 23:51
Copy link
Copy Markdown
Contributor

@ahcorde ahcorde left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you update the Python binding too ? Adding the new tests

@github-project-automation github-project-automation Bot moved this from Inbox to In review in Core development Mar 16, 2026
Replace the surface-mesh + divergence theorem implementation of
Box::VolumeBelow and Box::CenterOfVolumeBelow with an analytic
inclusion-exclusion formula (Scardovelli-Zaleski / Lehmann-Gekle).

The old VolumeBelow used TrianglesInPlane which relied on exact float
comparison (Plane::Side() == NO_SIDE) and produced wrong volumes for
non-axis-aligned planes. The old CenterOfVolumeBelow returned the
arithmetic mean of vertex positions instead of the volumetric centroid,
which was only correct for axis-aligned cuts.

The new implementation:
- Computes volume analytically via IE3/IE2/IE1 formulas with proper
  dimensional reduction (handles 3D, 2D, 1D, and degenerate cases)
- Computes centroid via first-moment IE formula with F_k functions
  matched to the effective dimensionality
- Removes TrianglesInPlane and its Triangle3.hh dependency
- Fixes Sphere<float> compilation by replacing hardcoded Vector3d
  with Vector3<T>::Zero in VolumeBelow and CenterOfVolumeBelow

Signed-off-by: Carlos Agüero <caguero@osrfoundation.org>
generated-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@caguero caguero force-pushed the fix/box-volume-below-centroid-sphere-float branch from 8be3c41 to c1226d2 Compare March 16, 2026 10:33
@caguero
Copy link
Copy Markdown
Contributor Author

caguero commented Mar 16, 2026

Can you update the Python binding too ? Adding the new tests

Added

@caguero caguero requested a review from ahcorde March 16, 2026 13:50
@caguero caguero merged commit c7f441d into main Mar 16, 2026
12 checks passed
@caguero caguero deleted the fix/box-volume-below-centroid-sphere-float branch March 16, 2026 14:27
@github-project-automation github-project-automation Bot moved this from In review to Done in Core development Mar 16, 2026
@caguero
Copy link
Copy Markdown
Contributor Author

caguero commented Mar 16, 2026

@Mergifyio backport gz-math9 gz-math8 gz-math7 ign-math6

@mergify
Copy link
Copy Markdown
Contributor

mergify Bot commented Mar 16, 2026

backport gz-math9 gz-math8 gz-math7 ign-math6

✅ Backports have been created

Details

Cherry-pick of c7f441d has failed:

On branch mergify/bp/gz-math7/pr-724
Your branch is up to date with 'origin/gz-math7'.

You are currently cherry-picking commit c7f441d.
  (fix conflicts and run "git cherry-pick --continue")
  (use "git cherry-pick --skip" to skip this patch)
  (use "git cherry-pick --abort" to cancel the cherry-pick operation)

Changes to be committed:
	modified:   include/gz/math/detail/Sphere.hh
	modified:   src/Box_TEST.cc
	modified:   src/Sphere_TEST.cc
	modified:   src/python_pybind11/test/Box_TEST.py

Unmerged paths:
  (use "git add <file>..." to mark resolution)
	both modified:   include/gz/math/detail/Box.hh

To fix up this pull request, you can check it out locally. See documentation: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/checking-out-pull-requests-locally

Cherry-pick of c7f441d has failed:

On branch mergify/bp/ign-math6/pr-724
Your branch is up to date with 'origin/ign-math6'.

You are currently cherry-picking commit c7f441d.
  (fix conflicts and run "git cherry-pick --continue")
  (use "git cherry-pick --skip" to skip this patch)
  (use "git cherry-pick --abort" to cancel the cherry-pick operation)

Changes to be committed:
	modified:   include/gz/math/detail/Sphere.hh
	modified:   src/Box_TEST.cc
	modified:   src/Sphere_TEST.cc
	modified:   src/python_pybind11/test/Box_TEST.py

Unmerged paths:
  (use "git add <file>..." to mark resolution)
	both modified:   include/gz/math/detail/Box.hh

To fix up this pull request, you can check it out locally. See documentation: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/checking-out-pull-requests-locally

mergify Bot pushed a commit that referenced this pull request Mar 16, 2026
…724)

Replace the surface-mesh + divergence theorem implementation of
Box::VolumeBelow and Box::CenterOfVolumeBelow with an analytic
inclusion-exclusion formula (Scardovelli-Zaleski / Lehmann-Gekle).

The old VolumeBelow used TrianglesInPlane which relied on exact float
comparison (Plane::Side() == NO_SIDE) and produced wrong volumes for
non-axis-aligned planes. The old CenterOfVolumeBelow returned the
arithmetic mean of vertex positions instead of the volumetric centroid,
which was only correct for axis-aligned cuts.

The new implementation:
- Computes volume analytically via IE3/IE2/IE1 formulas with proper
  dimensional reduction (handles 3D, 2D, 1D, and degenerate cases)
- Computes centroid via first-moment IE formula with F_k functions
  matched to the effective dimensionality
- Removes TrianglesInPlane and its Triangle3.hh dependency
- Fixes Sphere<float> compilation by replacing hardcoded Vector3d
  with Vector3<T>::Zero in VolumeBelow and CenterOfVolumeBelow

generated-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

Signed-off-by: Carlos Agüero <caguero@osrfoundation.org>
(cherry picked from commit c7f441d)
mergify Bot pushed a commit that referenced this pull request Mar 16, 2026
…724)

Replace the surface-mesh + divergence theorem implementation of
Box::VolumeBelow and Box::CenterOfVolumeBelow with an analytic
inclusion-exclusion formula (Scardovelli-Zaleski / Lehmann-Gekle).

The old VolumeBelow used TrianglesInPlane which relied on exact float
comparison (Plane::Side() == NO_SIDE) and produced wrong volumes for
non-axis-aligned planes. The old CenterOfVolumeBelow returned the
arithmetic mean of vertex positions instead of the volumetric centroid,
which was only correct for axis-aligned cuts.

The new implementation:
- Computes volume analytically via IE3/IE2/IE1 formulas with proper
  dimensional reduction (handles 3D, 2D, 1D, and degenerate cases)
- Computes centroid via first-moment IE formula with F_k functions
  matched to the effective dimensionality
- Removes TrianglesInPlane and its Triangle3.hh dependency
- Fixes Sphere<float> compilation by replacing hardcoded Vector3d
  with Vector3<T>::Zero in VolumeBelow and CenterOfVolumeBelow

generated-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

Signed-off-by: Carlos Agüero <caguero@osrfoundation.org>
(cherry picked from commit c7f441d)
mergify Bot pushed a commit that referenced this pull request Mar 16, 2026
…724)

Replace the surface-mesh + divergence theorem implementation of
Box::VolumeBelow and Box::CenterOfVolumeBelow with an analytic
inclusion-exclusion formula (Scardovelli-Zaleski / Lehmann-Gekle).

The old VolumeBelow used TrianglesInPlane which relied on exact float
comparison (Plane::Side() == NO_SIDE) and produced wrong volumes for
non-axis-aligned planes. The old CenterOfVolumeBelow returned the
arithmetic mean of vertex positions instead of the volumetric centroid,
which was only correct for axis-aligned cuts.

The new implementation:
- Computes volume analytically via IE3/IE2/IE1 formulas with proper
  dimensional reduction (handles 3D, 2D, 1D, and degenerate cases)
- Computes centroid via first-moment IE formula with F_k functions
  matched to the effective dimensionality
- Removes TrianglesInPlane and its Triangle3.hh dependency
- Fixes Sphere<float> compilation by replacing hardcoded Vector3d
  with Vector3<T>::Zero in VolumeBelow and CenterOfVolumeBelow

generated-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

Signed-off-by: Carlos Agüero <caguero@osrfoundation.org>
(cherry picked from commit c7f441d)

# Conflicts:
#	include/gz/math/detail/Box.hh
mergify Bot pushed a commit that referenced this pull request Mar 16, 2026
…724)

Replace the surface-mesh + divergence theorem implementation of
Box::VolumeBelow and Box::CenterOfVolumeBelow with an analytic
inclusion-exclusion formula (Scardovelli-Zaleski / Lehmann-Gekle).

The old VolumeBelow used TrianglesInPlane which relied on exact float
comparison (Plane::Side() == NO_SIDE) and produced wrong volumes for
non-axis-aligned planes. The old CenterOfVolumeBelow returned the
arithmetic mean of vertex positions instead of the volumetric centroid,
which was only correct for axis-aligned cuts.

The new implementation:
- Computes volume analytically via IE3/IE2/IE1 formulas with proper
  dimensional reduction (handles 3D, 2D, 1D, and degenerate cases)
- Computes centroid via first-moment IE formula with F_k functions
  matched to the effective dimensionality
- Removes TrianglesInPlane and its Triangle3.hh dependency
- Fixes Sphere<float> compilation by replacing hardcoded Vector3d
  with Vector3<T>::Zero in VolumeBelow and CenterOfVolumeBelow

generated-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

Signed-off-by: Carlos Agüero <caguero@osrfoundation.org>
(cherry picked from commit c7f441d)

# Conflicts:
#	include/gz/math/detail/Box.hh
caguero added a commit that referenced this pull request Mar 16, 2026
…724)

Replace the surface-mesh + divergence theorem implementation of
Box::VolumeBelow and Box::CenterOfVolumeBelow with an analytic
inclusion-exclusion formula (Scardovelli-Zaleski / Lehmann-Gekle).

The old VolumeBelow used TrianglesInPlane which relied on exact float
comparison (Plane::Side() == NO_SIDE) and produced wrong volumes for
non-axis-aligned planes. The old CenterOfVolumeBelow returned the
arithmetic mean of vertex positions instead of the volumetric centroid,
which was only correct for axis-aligned cuts.

The new implementation:
- Computes volume analytically via IE3/IE2/IE1 formulas with proper
  dimensional reduction (handles 3D, 2D, 1D, and degenerate cases)
- Computes centroid via first-moment IE formula with F_k functions
  matched to the effective dimensionality
- Deprecates TrianglesInPlane (kept for source compatibility)
- Fixes Sphere<float> compilation by replacing hardcoded Vector3d
  with Vector3<T>::Zero in VolumeBelow and CenterOfVolumeBelow

Generated-by: Claude Opus 4.6 (1M context)
Signed-off-by: Carlos Agüero <caguero@osrfoundation.org>
caguero added a commit that referenced this pull request Mar 16, 2026
…724)

Replace the surface-mesh + divergence theorem implementation of
Box::VolumeBelow and Box::CenterOfVolumeBelow with an analytic
inclusion-exclusion formula (Scardovelli-Zaleski / Lehmann-Gekle).

The old VolumeBelow used TrianglesInPlane which relied on exact float
comparison (Plane::Side() == NO_SIDE) and produced wrong volumes for
non-axis-aligned planes. The old CenterOfVolumeBelow returned the
arithmetic mean of vertex positions instead of the volumetric centroid,
which was only correct for axis-aligned cuts.

The new implementation:
- Computes volume analytically via IE3/IE2/IE1 formulas with proper
  dimensional reduction (handles 3D, 2D, 1D, and degenerate cases)
- Computes centroid via first-moment IE formula with F_k functions
  matched to the effective dimensionality
- Keeps TrianglesInPlane for source compatibility (with bug note)
- Fixes Sphere<float> compilation by replacing hardcoded Vector3d
  with Vector3<T>::Zero in VolumeBelow and CenterOfVolumeBelow

Generated-by: Claude Opus 4.6 (1M context)
Signed-off-by: Carlos Agüero <caguero@osrfoundation.org>
caguero added a commit that referenced this pull request Mar 16, 2026
…724)

Replace the surface-mesh + divergence theorem implementation of
Box::VolumeBelow and Box::CenterOfVolumeBelow with an analytic
inclusion-exclusion formula (Scardovelli-Zaleski / Lehmann-Gekle).

The old VolumeBelow used TrianglesInPlane which relied on exact float
comparison (Plane::Side() == NO_SIDE) and produced wrong volumes for
non-axis-aligned planes. The old CenterOfVolumeBelow returned the
arithmetic mean of vertex positions instead of the volumetric centroid,
which was only correct for axis-aligned cuts.

The new implementation:
- Computes volume analytically via IE3/IE2/IE1 formulas with proper
  dimensional reduction (handles 3D, 2D, 1D, and degenerate cases)
- Computes centroid via first-moment IE formula with F_k functions
  matched to the effective dimensionality
- Keeps TrianglesInPlane for source compatibility (with bug note)
- Fixes Sphere<float> compilation by replacing hardcoded Vector3d
  with Vector3<T>::Zero in VolumeBelow and CenterOfVolumeBelow

Generated-by: Claude Opus 4.6 (1M context)
Signed-off-by: Carlos Agüero <caguero@osrfoundation.org>
caguero added a commit that referenced this pull request Mar 16, 2026
…724)

Replace the surface-mesh + divergence theorem implementation of
Box::VolumeBelow and Box::CenterOfVolumeBelow with an analytic
inclusion-exclusion formula (Scardovelli-Zaleski / Lehmann-Gekle).

The old VolumeBelow used TrianglesInPlane which relied on exact float
comparison (Plane::Side() == NO_SIDE) and produced wrong volumes for
non-axis-aligned planes. The old CenterOfVolumeBelow returned the
arithmetic mean of vertex positions instead of the volumetric centroid,
which was only correct for axis-aligned cuts.

The new implementation:
- Computes volume analytically via IE3/IE2/IE1 formulas with proper
  dimensional reduction (handles 3D, 2D, 1D, and degenerate cases)
- Computes centroid via first-moment IE formula with F_k functions
  matched to the effective dimensionality
- Keeps TrianglesInPlane for source compatibility (with bug note)
- Fixes Sphere<float> compilation by replacing hardcoded Vector3d
  with Vector3<T>::Zero in VolumeBelow and CenterOfVolumeBelow

Generated-by: Claude Opus 4.6 (1M context)
Signed-off-by: Carlos Agüero <caguero@osrfoundation.org>
caguero added a commit that referenced this pull request Mar 16, 2026
…724)

Replace the surface-mesh + divergence theorem implementation of
Box::VolumeBelow and Box::CenterOfVolumeBelow with an analytic
inclusion-exclusion formula (Scardovelli-Zaleski / Lehmann-Gekle).

The old VolumeBelow used TrianglesInPlane which relied on exact float
comparison (Plane::Side() == NO_SIDE) and produced wrong volumes for
non-axis-aligned planes. The old CenterOfVolumeBelow returned the
arithmetic mean of vertex positions instead of the volumetric centroid,
which was only correct for axis-aligned cuts.

The new implementation:
- Computes volume analytically via IE3/IE2/IE1 formulas with proper
  dimensional reduction (handles 3D, 2D, 1D, and degenerate cases)
- Computes centroid via first-moment IE formula with F_k functions
  matched to the effective dimensionality
- Keeps TrianglesInPlane for source compatibility (with bug note)
- Fixes Sphere<float> compilation by replacing hardcoded Vector3d
  with Vector3<T>::Zero in VolumeBelow and CenterOfVolumeBelow

Generated-by: Claude Opus 4.6 (1M context)
Signed-off-by: Carlos Agüero <caguero@osrfoundation.org>
caguero added a commit that referenced this pull request Mar 16, 2026
…724)

Replace the surface-mesh + divergence theorem implementation of
Box::VolumeBelow and Box::CenterOfVolumeBelow with an analytic
inclusion-exclusion formula (Scardovelli-Zaleski / Lehmann-Gekle).

The old VolumeBelow used TrianglesInPlane which relied on exact float
comparison (Plane::Side() == NO_SIDE) and produced wrong volumes for
non-axis-aligned planes. The old CenterOfVolumeBelow returned the
arithmetic mean of vertex positions instead of the volumetric centroid,
which was only correct for axis-aligned cuts.

The new implementation:
- Computes volume analytically via IE3/IE2/IE1 formulas with proper
  dimensional reduction (handles 3D, 2D, 1D, and degenerate cases)
- Computes centroid via first-moment IE formula with F_k functions
  matched to the effective dimensionality
- Keeps TrianglesInPlane for source compatibility (with bug note)
- Fixes Sphere<float> compilation by replacing hardcoded Vector3d
  with Vector3<T>::Zero in VolumeBelow and CenterOfVolumeBelow

Generated-by: Claude Opus 4.6 (1M context)
Signed-off-by: Carlos Agüero <caguero@osrfoundation.org>
caguero added a commit that referenced this pull request Mar 16, 2026
…724)

Replace the surface-mesh + divergence theorem implementation of
Box::VolumeBelow and Box::CenterOfVolumeBelow with an analytic
inclusion-exclusion formula (Scardovelli-Zaleski / Lehmann-Gekle).

The old VolumeBelow used TrianglesInPlane which relied on exact float
comparison (Plane::Side() == NO_SIDE) and produced wrong volumes for
non-axis-aligned planes. The old CenterOfVolumeBelow returned the
arithmetic mean of vertex positions instead of the volumetric centroid,
which was only correct for axis-aligned cuts.

The new implementation:
- Computes volume analytically via IE3/IE2/IE1 formulas with proper
  dimensional reduction (handles 3D, 2D, 1D, and degenerate cases)
- Computes centroid via first-moment IE formula with F_k functions
  matched to the effective dimensionality
- Keeps TrianglesInPlane for source compatibility (with bug note)
- Fixes Sphere<float> compilation by replacing hardcoded Vector3d
  with Vector3<T>::Zero in VolumeBelow and CenterOfVolumeBelow

Generated-by: Claude Opus 4.6 (1M context)
Signed-off-by: Carlos Agüero <caguero@osrfoundation.org>
caguero added a commit that referenced this pull request Mar 16, 2026
…724)

Replace the surface-mesh + divergence theorem implementation of
Box::VolumeBelow and Box::CenterOfVolumeBelow with an analytic
inclusion-exclusion formula (Scardovelli-Zaleski / Lehmann-Gekle).

The old VolumeBelow used TrianglesInPlane which relied on exact float
comparison (Plane::Side() == NO_SIDE) and produced wrong volumes for
non-axis-aligned planes. The old CenterOfVolumeBelow returned the
arithmetic mean of vertex positions instead of the volumetric centroid,
which was only correct for axis-aligned cuts.

The new implementation:
- Computes volume analytically via IE3/IE2/IE1 formulas with proper
  dimensional reduction (handles 3D, 2D, 1D, and degenerate cases)
- Computes centroid via first-moment IE formula with F_k functions
  matched to the effective dimensionality
- Deprecates TrianglesInPlane (kept for source compatibility)
- Fixes Sphere<float> compilation by replacing hardcoded Vector3d
  with Vector3<T>::Zero in VolumeBelow and CenterOfVolumeBelow

Generated-by: Claude Opus 4.6 (1M context)
Signed-off-by: Carlos Agüero <caguero@osrfoundation.org>
@scpeters scpeters mentioned this pull request Mar 26, 2026
7 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

3 participants