diff --git a/src/Mod/Part/App/PartFeature.cpp b/src/Mod/Part/App/PartFeature.cpp index b24a74854..660146282 100644 --- a/src/Mod/Part/App/PartFeature.cpp +++ b/src/Mod/Part/App/PartFeature.cpp @@ -27,14 +27,16 @@ # include # include # include +# include # include # include # include # include -// includes for findAllFacesCutBy() # include # include # include // for Precision::Confusion() +# include +# include #endif @@ -333,3 +335,34 @@ std::vector Part::findAllFacesCutBy( return result; } + +const bool Part::checkIntersection(const TopoDS_Shape& first, const TopoDS_Shape& second, const bool quick) { + 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! + 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; + + TopExp_Explorer xp; + xp.Init(mkCommon.Shape(),TopAbs_SOLID); + if (xp.More()) + return true; + + return false; +} diff --git a/src/Mod/Part/App/PartFeature.h b/src/Mod/Part/App/PartFeature.h index bd7beac3b..d44272b65 100644 --- a/src/Mod/Part/App/PartFeature.h +++ b/src/Mod/Part/App/PartFeature.h @@ -135,6 +135,16 @@ PartExport std::vector findAllFacesCutBy(const TopoDS_Shape& shape, const TopoDS_Shape& face, const gp_Dir& dir); +/** + * Check for intersection between the two shapes. Only solids are guaranteed to work properly + * There are two modes: + * 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 + */ +PartExport +const bool checkIntersection(const TopoDS_Shape& first, const TopoDS_Shape& second, const bool quick = true); + } //namespace Part diff --git a/src/Mod/PartDesign/App/FeatureTransformed.cpp b/src/Mod/PartDesign/App/FeatureTransformed.cpp index f871f89a0..574974a7a 100644 --- a/src/Mod/PartDesign/App/FeatureTransformed.cpp +++ b/src/Mod/PartDesign/App/FeatureTransformed.cpp @@ -30,8 +30,6 @@ # include # include # include -# include -# include # include # include #endif @@ -114,10 +112,6 @@ App::DocumentObjectExecReturn *Transformed::execute(void) supportShape.setTransform(Base::Matrix4D()); TopoDS_Shape support = supportShape._Shape; - // Prepare a bounding box for intersection tests - Bnd_Box support_bb; - BRepBndLib::Add(support, support_bb); - // NOTE: It would be possible to build a compound from all original addShapes/subShapes and then // transform the compounds as a whole. But we choose to apply the transformations to each // Original separately. This way it is easier to discover what feature causes a fuse/cut @@ -162,9 +156,7 @@ App::DocumentObjectExecReturn *Transformed::execute(void) return new App::DocumentObjectExecReturn("Transformation failed", (*o)); // Check for intersection with support - Bnd_Box transformed_bb; - BRepBndLib::Add(mkTrf.Shape(), transformed_bb); - if (support_bb.Distance(transformed_bb) > Precision::Confusion()) { + if (!Part::checkIntersection(support, mkTrf.Shape(), false)) { Base::Console().Warning("Transformed shape does not intersect support %s: Removed\n", (*o)->getNameInDocument()); // Note: The removal happens in getSolid() after the fuse. If we remove here, // the histories get messed up and we get a crash @@ -193,11 +185,6 @@ App::DocumentObjectExecReturn *Transformed::execute(void) } // Check for intersection of the original and the transformed shape - // Note: For performance reasons, we only check for intersection of bounding boxes - Bnd_Box original_bb; - BRepBndLib::Add(shape, original_bb); - original_bb.SetGap(0); - for (std::vector::const_iterator s = v_transformedShapes.begin(); s != v_transformedShapes.end(); s++) { // If there is only one transformed feature, this check is not necessary (though it might seem @@ -205,12 +192,7 @@ App::DocumentObjectExecReturn *Transformed::execute(void) if (v_transformedShapes.size() == 1) break; - Bnd_Box transformed_bb; - BRepBndLib::Add(*s, transformed_bb); - transformed_bb.SetGap(0); - if (!original_bb.IsOut(transformed_bb)) - // if (original_bb.Distance(transformed_bb) < Precision::Confusion()) - // FIXME: Both tests fail if the objects are touching one another at zero distance + if (Part::checkIntersection(shape, *s, 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 @@ -220,6 +202,14 @@ App::DocumentObjectExecReturn *Transformed::execute(void) // features might overlap, even if the original and the first shape don't overlap! if (this->getTypeId() != PartDesign::MultiTransform::getClassTypeId()) break; + else { + // Check intersection with all other transformed shapes as well + std::vector::const_iterator s2 = s; + s2++; + for (; s2 != v_transformedShapes.end(); s2++) + if (Part::checkIntersection(*s, *s2, false)) + return new App::DocumentObjectExecReturn("Transformed objects are overlapping, try using a higher length or reducing the number of occurrences", (*o)); + } } // Fuse/Cut the compounded transformed shapes with the support