Finish error propagation for Minkowski, SplitByPlane, Mirror (#1474) (#1659)

Finish error propagation for Minkowski, SplitByPlane, Mirror

Three methods silently dropped errored-input status:

- MinkowskiSum / MinkowskiDifference: no status check before
  Impl::Minkowski.
- SplitByPlane: if (IsEmpty()) early-return returned default
  Manifold() pair; errored manifolds are empty, so error was lost.
- Mirror: zero-length normal path returned empty Manifold() without
  honoring input error.

All use the standard PropagateStatus pattern before the early return.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Zach Loafman
2026-04-17 12:46:47 +08:00
committed by GitHub
co-authored by Claude Opus 4.6
parent 97df55ba1d
commit c5f72130b9
2 changed files with 50 additions and 0 deletions
+12
View File
@@ -493,6 +493,9 @@ Manifold Manifold::Transform(const mat3x4& m) const {
* @param normal The normal vector of the plane to be mirrored over
*/
Manifold Manifold::Mirror(vec3 normal) const {
auto leafImpl = GetCsgLeafNode().GetImpl();
if (leafImpl->status_ != Error::NoError)
return PropagateStatus(leafImpl->status_);
if (la::length(normal) == 0.) {
return Manifold();
}
@@ -893,6 +896,11 @@ std::pair<Manifold, Manifold> Manifold::Split(const Manifold& cutter) const {
*/
std::pair<Manifold, Manifold> Manifold::SplitByPlane(
vec3 normal, double originOffset) const {
auto leafImpl = GetCsgLeafNode().GetImpl();
if (leafImpl->status_ != Error::NoError) {
Manifold err = PropagateStatus(leafImpl->status_);
return {err, err};
}
if (IsEmpty()) return {Manifold(), Manifold()};
return Split(Halfspace(BoundingBox(), normal, originOffset));
}
@@ -921,7 +929,9 @@ Manifold Manifold::TrimByPlane(vec3 normal, double originOffset) const {
*/
Manifold Manifold::MinkowskiSum(const Manifold& other) const {
auto aImpl = GetCsgLeafNode().GetImpl();
if (aImpl->status_ != Error::NoError) return PropagateStatus(aImpl->status_);
auto bImpl = other.GetCsgLeafNode().GetImpl();
if (bImpl->status_ != Error::NoError) return PropagateStatus(bImpl->status_);
return aImpl->Minkowski(*bImpl, false);
}
@@ -936,7 +946,9 @@ Manifold Manifold::MinkowskiSum(const Manifold& other) const {
*/
Manifold Manifold::MinkowskiDifference(const Manifold& other) const {
auto aImpl = GetCsgLeafNode().GetImpl();
if (aImpl->status_ != Error::NoError) return PropagateStatus(aImpl->status_);
auto bImpl = other.GetCsgLeafNode().GetImpl();
if (bImpl->status_ != Error::NoError) return PropagateStatus(bImpl->status_);
return aImpl->Minkowski(*bImpl, true);
}
+38
View File
@@ -283,6 +283,44 @@ TEST(Manifold, ErrorPropagationWarp) {
Manifold::Error::NonFiniteVertex);
}
TEST(Manifold, ErrorPropagationMinkowski) {
MeshGL in = TetGL();
in.vertProperties[2 * 3 + 1] = NAN;
Manifold errored(in);
ASSERT_EQ(errored.Status(), Manifold::Error::NonFiniteVertex);
Manifold good = Manifold::Cube();
EXPECT_EQ(errored.MinkowskiSum(good).Status(),
Manifold::Error::NonFiniteVertex);
EXPECT_EQ(good.MinkowskiSum(errored).Status(),
Manifold::Error::NonFiniteVertex);
EXPECT_EQ(errored.MinkowskiDifference(good).Status(),
Manifold::Error::NonFiniteVertex);
EXPECT_EQ(good.MinkowskiDifference(errored).Status(),
Manifold::Error::NonFiniteVertex);
}
TEST(Manifold, ErrorPropagationSplitByPlane) {
MeshGL in = TetGL();
in.vertProperties[2 * 3 + 1] = NAN;
Manifold errored(in);
ASSERT_EQ(errored.Status(), Manifold::Error::NonFiniteVertex);
auto parts = errored.SplitByPlane(vec3(0, 0, 1), 0);
EXPECT_EQ(parts.first.Status(), Manifold::Error::NonFiniteVertex);
EXPECT_EQ(parts.second.Status(), Manifold::Error::NonFiniteVertex);
}
TEST(Manifold, ErrorPropagationMirror) {
MeshGL in = TetGL();
in.vertProperties[2 * 3 + 1] = NAN;
Manifold errored(in);
ASSERT_EQ(errored.Status(), Manifold::Error::NonFiniteVertex);
EXPECT_EQ(errored.Mirror(vec3(1, 0, 0)).Status(),
Manifold::Error::NonFiniteVertex);
// Degenerate normal (zero vector) on errored input should still propagate.
EXPECT_EQ(errored.Mirror(vec3(0, 0, 0)).Status(),
Manifold::Error::NonFiniteVertex);
}
TEST(Manifold, ErrorPropagationSimplify) {
MeshGL in = TetGL();
in.vertProperties[2 * 3 + 1] = NAN;