From 18da371546f40e93b184fd391d7ec4ddd3c1a8fc Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Fri, 18 Jan 2013 16:43:41 +0430 Subject: [PATCH] Re-worked Part::checkIntersection to give less false positives for pattern features --- src/Mod/Part/App/PartFeature.cpp | 48 +++++++++++++------ src/Mod/Part/App/PartFeature.h | 12 ++++- src/Mod/PartDesign/App/FeatureTransformed.cpp | 6 +-- 3 files changed, 46 insertions(+), 20 deletions(-) diff --git a/src/Mod/Part/App/PartFeature.cpp b/src/Mod/Part/App/PartFeature.cpp index 660146282..7c133ba79 100644 --- a/src/Mod/Part/App/PartFeature.cpp +++ b/src/Mod/Part/App/PartFeature.cpp @@ -27,6 +27,7 @@ # include # include # include +# include # include # include # include @@ -336,33 +337,50 @@ std::vector Part::findAllFacesCutBy( return result; } -const bool Part::checkIntersection(const TopoDS_Shape& first, const TopoDS_Shape& second, const bool quick) { +const bool Part::checkIntersection(const TopoDS_Shape& first, const TopoDS_Shape& second, + const bool quick, const bool touch_is_intersection) { Bnd_Box first_bb, second_bb; BRepBndLib::Add(first, first_bb); first_bb.SetGap(0); BRepBndLib::Add(second, second_bb); second_bb.SetGap(0); - // Note: Both tests fail if the objects are touching one another at zero distance! + // Note: This test fails if the objects are touching one another at zero distance if (first_bb.IsOut(second_bb)) return false; // no intersection - //if (first_bb.Distance(second_bb) > Precision::Confusion()) - // return false; if (quick) return true; // assumed intersection // Try harder - BRepAlgoAPI_Common mkCommon(first, second); - // FIXME: Error in boolean operation, return true by default - if (!mkCommon.IsDone()) - return true; - if (mkCommon.Shape().IsNull()) - return true; + if (touch_is_intersection) { + // If both shapes fuse to a single solid, then they intersect + BRepAlgoAPI_Fuse mkFuse(first, second); + if (!mkFuse.IsDone()) + return false; + if (mkFuse.Shape().IsNull()) + return false; - TopExp_Explorer xp; - xp.Init(mkCommon.Shape(),TopAbs_SOLID); - if (xp.More()) - return true; + // Did we get one or two solids? + TopExp_Explorer xp; + xp.Init(mkFuse.Shape(),TopAbs_SOLID); + if (xp.More()) { + // At least one solid + xp.Next(); + return (xp.More() == Standard_False); + } else { + return false; + } + } else { + // If both shapes have common material, then they intersect + BRepAlgoAPI_Common mkCommon(first, second); + if (!mkCommon.IsDone()) + return false; + if (mkCommon.Shape().IsNull()) + return false; - return false; + // Did we get a solid? + TopExp_Explorer xp; + xp.Init(mkCommon.Shape(),TopAbs_SOLID); + return (xp.More() == Standard_True); + } } diff --git a/src/Mod/Part/App/PartFeature.h b/src/Mod/Part/App/PartFeature.h index d44272b65..68520186d 100644 --- a/src/Mod/Part/App/PartFeature.h +++ b/src/Mod/Part/App/PartFeature.h @@ -141,10 +141,18 @@ std::vector findAllFacesCutBy(const TopoDS_Shape& shape, * 1. Bounding box check only - quick but inaccurate * 2. Bounding box check plus (if necessary) boolean operation - costly but accurate * Return true if the shapes intersect, false if they don't + * The flag touch_is_intersection decides whether shapes touching at distance zero are regarded + * as intersecting or not + * 1. If set to true, a true check result means that a boolean fuse operation between the two shapes + * will return a single solid + * 2. If set to false, a true check result means that a boolean common operation will return a + * valid solid + * If there is any error in the boolean operations, the check always returns false */ PartExport -const bool checkIntersection(const TopoDS_Shape& first, const TopoDS_Shape& second, const bool quick = true); - +const bool checkIntersection(const TopoDS_Shape& first, const TopoDS_Shape& second, + const bool quick, const bool touch_is_intersection); + } //namespace Part diff --git a/src/Mod/PartDesign/App/FeatureTransformed.cpp b/src/Mod/PartDesign/App/FeatureTransformed.cpp index 3cc80f173..571e02f26 100644 --- a/src/Mod/PartDesign/App/FeatureTransformed.cpp +++ b/src/Mod/PartDesign/App/FeatureTransformed.cpp @@ -170,7 +170,7 @@ App::DocumentObjectExecReturn *Transformed::execute(void) return new App::DocumentObjectExecReturn("Transformation failed", (*o)); // Check for intersection with support - if (!Part::checkIntersection(support, mkTrf.Shape(), false)) { + if (!Part::checkIntersection(support, mkTrf.Shape(), false, true)) { Base::Console().Warning("Transformed shape does not intersect support %s: Removed\n", (*o)->getNameInDocument()); // Note: The removal happens in getSolid() after the fuse rejected.push_back(*t); @@ -203,7 +203,7 @@ App::DocumentObjectExecReturn *Transformed::execute(void) if (v_transformedShapes.size() == 1) break; - if (Part::checkIntersection(shape, *s, false)) + if (Part::checkIntersection(shape, *s, false, false)) return new App::DocumentObjectExecReturn("Transformed objects are overlapping, try using a higher length or reducing the number of occurrences", (*o)); // Note: This limitation could be overcome by fusing the transformed features instead of // compounding them, probably at the expense of quite a bit of performance and complexity @@ -218,7 +218,7 @@ App::DocumentObjectExecReturn *Transformed::execute(void) std::vector::const_iterator s2 = s; s2++; for (; s2 != v_transformedShapes.end(); s2++) - if (Part::checkIntersection(*s, *s2, false)) + if (Part::checkIntersection(*s, *s2, false, false)) return new App::DocumentObjectExecReturn("Transformed objects are overlapping, try using a higher length or reducing the number of occurrences", (*o)); } }