ifcgeom: fall back to unopened geometry when convert_openings() cleanly fails

Converter::create_brep_for_representation() called kernel_->convert_openings()
without checking its return value. When every candidate kernel rejects the
boolean operands (e.g. CgalKernel's Nef conversion refuses self-intersecting
geometry and returns false without throwing), opened_shapes stays empty and
the guard below, which exists to preserve the product's unopened geometry on
failure, only looked at caught_error from a thrown exception. A clean `false`
return slipped past it, so the empty opened_shapes silently replaced the
product's valid solid and the element vanished instead of degrading to its
unclipped shape, the way every other failure path in this code already does.

Reproduced with the IfcWindow from #5880's attached file: `--kernel cgal` and
`--kernel hybrid-cgal-opencascade` produced 0 vertices (window disappears)
even though OpenCASCADE alone converts it fine (152 vertices). With this fix
both now log the self-intersection error and still emit the window's
unopened geometry (268 vertices) instead of nothing.

Bonsai's actual default, hybrid-cgal-simple-opencascade, isn't affected by
this particular file: HybridKernel already skips the non-boolean CGAL-simple
kernel for elements with openings and goes straight to OpenCASCADE. Verified
byte-identical output (0 diffs) on that path and on plain opencascade for
both the reported window and a second reporter-attached roof file. Full
regression pass over all 258 test/input/*.ifc fixtures: 244 byte-identical
between the unpatched and patched binary, the remaining 14 fail identically
before and after (pre-existing crash/timeout repro fixtures, e.g.
outOfMemory/segfault/infiniteLoop/invalid.ifc), 0 new failures.

Fixes #5880.

This commit contains AI-generated code, generated with the assistance of an AI coding tool.
This commit is contained in:
Petru Conduraru
2026-07-20 16:37:33 +03:00
parent 55a2430d71
commit bd27cf38aa
+4 -2
View File
@@ -205,8 +205,10 @@ IfcGeom::BRepElement* ifcopenshell::geometry::Converter::create_brep_for_represe
if (opening_items.empty()) {
opened_shapes = shapes;
} else {
kernel_->convert_openings(product, opening_items, shapes, *place, opened_shapes);
} else if (!kernel_->convert_openings(product, opening_items, shapes, *place, opened_shapes)) {
// A clean `false` return is a failure just like a thrown exception.
logger_.Message(Logger::LOG_ERROR, "GEO", 34, "Error processing openings for:", product);
caught_error = true;
}
} catch (const std::exception& e) {
logger_.Message(Logger::LOG_ERROR, "GEO", 33, std::string("Error processing openings for: ") + e.what() + ":", product);