diff --git a/src/geometry.cpp b/src/geometry.cpp index 3ecbed6..260b5a3 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -333,16 +334,10 @@ intersect_result classify_solid_intersection( TopExp_Explorer ex; ex.Init(op.Shape(), TopAbs_SOLID); if (ex.More()) { - // we expect the common volume to occasionally come back negative. - // OCCT appears to do this when the two solids have faces that are - // within the given tolerance/fuzzy value + // OCCT (version 7.5) appears to occasionally come back with a + // negative volume. it appears to do this when the two solids have + // non-trivial faces that are within the given tolerance/fuzzy value result.vol_common = volume_of_shape_maybe_neg(op.Shape()); - if (result.vol_common < 0) { - // returning failed here should cause the overlap checker will - // retry with a stricter tolerance, which tends to cause this - // error to disappear! - return result; - } op.SetOperation(BOPAlgo_CUT); op.Build(); @@ -358,7 +353,25 @@ intersect_result classify_solid_intersection( } result.vol_cut12 = volume_of_shape(op.Shape()); - result.status = intersect_status::overlap; + if (result.vol_common < 0) { + // ensure the this negative volume is "small", relative to the + // input shapes, as we only expect this to happen along the + // boundary of shapes + const double limit = std::min(result.vol_cut, result.vol_cut12) * 0.1; + if (limit < -result.vol_common) { + throw std::runtime_error("negative volume too large"); + } + + // until this is fixed upstream in OCCT, recording them as + // touching seems to be best. an alternative would be to fail, and + // let the caller retry with stricter tolerance (which tends to + // succeed). touching seems best as we later steps want to know + // which solids are close to each other and therefore need to + // considered during merging + result.status = intersect_status::touching; + } else { + result.status = intersect_status::overlap; + } return result; }