mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 09:21:46 +00:00
Warn when a face inner boundary intersects another boundary (#527)
A face whose inner boundary crosses the outer boundary (or another inner boundary) is invalid per the schema. Open Cascade silently heals or drops such a face, so the intended hole is lost or the face is corrupted with no diagnostic at all (the 2018 report saw a dropped face; on the current line the face survives as wrong geometry, still silently). After the wires are collected, if a face has inner boundaries, measure the BRepExtrema distance between each inner wire and every earlier wire. Two non intersecting loops have strictly positive distance, so a distance at or below the modelling precision means the boundaries touch or cross; emit a warning (GEO 402) naming the offending face. This is diagnostic only, no geometry change. The message is emitted via the kernel logger() rather than Logger::Root(): IfcConvert configures a local Logger and worker logs merge into it, while Logger::Root() is a separate unconfigured singleton whose messages are discarded (a latent issue affecting some existing GEO messages too). Verified on OCC 7.9.2 with synthesized IFC4 faces: an inner triangle crossing the outer edge, and one straddling the bottom edge, each emit one GEO 402; a valid 4x4 hole emits none and triangulates identically (area 84.0), in both sequential and multithreaded runs. Pure inner self intersection and full containment are distinct classes and intentionally left untouched. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
committed by
Thomas Krijnen
parent
a8d0ef3437
commit
061bb90d50
@@ -31,6 +31,7 @@
|
||||
#include <ShapeFix_Shape.hxx>
|
||||
#include <ShapeFix_ShapeTolerance.hxx>
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <BRepExtrema_DistShapeShape.hxx>
|
||||
|
||||
#include <Standard_Macro.hxx>
|
||||
#include <TopoDS_Shape.hxx>
|
||||
@@ -356,6 +357,27 @@ bool OpenCascadeKernel::convert(const taxonomy::face::ptr face, TopoDS_Shape& re
|
||||
return false;
|
||||
}
|
||||
|
||||
// #527: A face whose inner boundary intersects the outer boundary (or
|
||||
// another inner boundary) is invalid per the schema. Open Cascade heals or
|
||||
// drops such a face silently, so the intended hole is lost with no
|
||||
// diagnostic. The distance between two non-intersecting loops is strictly
|
||||
// positive; a distance at (or below) the modelling precision means the
|
||||
// boundaries touch or cross. Emit a clear warning so the invalid input is
|
||||
// not silently lost. wires() is ordered outer-first, inner-bounds after.
|
||||
if (fd.wires().size() > 1) {
|
||||
const auto& fwires = fd.wires();
|
||||
bool reported = false;
|
||||
for (size_t i = 1; i < fwires.size() && !reported; ++i) {
|
||||
for (size_t j = 0; j < i && !reported; ++j) {
|
||||
BRepExtrema_DistShapeShape dss(fwires[i], fwires[j]);
|
||||
if (dss.IsDone() && dss.Value() < precision_) {
|
||||
logger().Warning("GEO", 402, "Face inner boundary intersects another face boundary", face->instance);
|
||||
reported = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fd.surface().IsNull()) {
|
||||
// Use the first wire to find a plane manually for polygonal wires
|
||||
const TopoDS_Wire& wire = fd.wires().front();
|
||||
|
||||
Reference in New Issue
Block a user