Fix #142494: Manifold Boolean Subtraction causes crash.

The case of subtracing a plane is handled specially as the
plane is not manifold, but the library has a TrimByPlane function.
The special handling code did not deal with the empty result case
properly.
Also, there was no error return checking from Manifold in this special
case, so that was added.
Also, the general error handling just assumed that any Manifold error
on the inputs was a "not manifold" error, which while probably true,
should not be assumed, so that was fixed too.
This commit is contained in:
Howard Trickey
2025-07-20 08:36:53 -04:00
parent f8c0d504f4
commit 248529d6e0

View File

@@ -1689,24 +1689,41 @@ static bool is_plane(const Mesh *mesh,
* Handle special case of one manifold mesh, which has been converted to
* \a manifold 0, and one plane, which has normalized normal \a normal
* and distance from origin \a origin_offset.
* If there is an error, set *r_error appropriately.
*/
static MeshGL mesh_trim_manifold(Manifold &manifold0,
float3 normal,
float origin_offset,
const MeshOffsets &mesh_offsets)
const MeshOffsets &mesh_offsets,
BooleanError *r_error)
{
Manifold man_result = manifold0.TrimByPlane(manifold::vec3(normal[0], normal[1], normal[2]),
double(origin_offset));
MeshGL meshgl = man_result.GetMeshGL();
if (man_result.Status() != Manifold::Error::NoError) {
if (man_result.Status() == Manifold::Error::ResultTooLarge) {
*r_error = BooleanError::ResultTooBig;
}
else if (man_result.Status() == Manifold::Error::NotManifold) {
*r_error = BooleanError::NonManifold;
}
else {
*r_error = BooleanError::UnknownError;
}
return meshgl;
}
/* This meshgl_result has a non-standard (but non-zero) original ID for the
* plane faces, and faceIDs that make no sense for them. Fix this. */
BLI_assert(meshgl.runOriginalID.size() == 2 && meshgl.runOriginalID[1] > 0);
meshgl.runOriginalID[1] = 1;
BLI_assert(meshgl.runIndex.size() == 3);
int plane_face_start = meshgl.runIndex[1] / 3;
int plane_face_end = meshgl.runIndex[2] / 3;
for (int i = plane_face_start; i < plane_face_end; i++) {
meshgl.faceID[i] = mesh_offsets.face_offsets[1][0];
* plane faces, and faceIDs that make no sense for them. Fix this.
* But only do this if the result is not empty. */
if (meshgl.vertProperties.size() > 0) {
BLI_assert(meshgl.runOriginalID.size() == 2 && meshgl.runOriginalID[1] > 0);
meshgl.runOriginalID[1] = 1;
BLI_assert(meshgl.runIndex.size() == 3);
int plane_face_start = meshgl.runIndex[1] / 3;
int plane_face_end = meshgl.runIndex[2] / 3;
for (int i = plane_face_start; i < plane_face_end; i++) {
meshgl.faceID[i] = mesh_offsets.face_offsets[1][0];
}
}
return meshgl;
}
@@ -1957,10 +1974,22 @@ Mesh *mesh_boolean_manifold(Span<const Mesh *> meshes,
# ifdef DEBUG_TIME
timeit::ScopedTimer timer_trim("DOING BOOLEAN SLICE, GETTING MESH_GL RESULT");
# endif
meshgl_result = mesh_trim_manifold(manifolds[0], normal, origin_offset, mesh_offsets);
meshgl_result = mesh_trim_manifold(
manifolds[0], normal, origin_offset, mesh_offsets, r_error);
if (*r_error != BooleanError::NoError) {
return nullptr;
}
}
else {
*r_error = BooleanError::NonManifold;
if (std::any_of(manifolds.begin(), manifolds.end(), [](const Manifold &m) {
return m.Status() == Manifold::Error::NotManifold;
}))
{
*r_error = BooleanError::NonManifold;
}
else {
*r_error = BooleanError::UnknownError;
}
return nullptr;
}
}