diff --git a/src/Mod/PartDesign/App/FeatureGroove.cpp b/src/Mod/PartDesign/App/FeatureGroove.cpp index 763016932..006abdeea 100644 --- a/src/Mod/PartDesign/App/FeatureGroove.cpp +++ b/src/Mod/PartDesign/App/FeatureGroove.cpp @@ -33,6 +33,7 @@ # include # include # include +# include #endif #include @@ -76,12 +77,12 @@ App::DocumentObjectExecReturn *Groove::execute(void) return new App::DocumentObjectExecReturn("Angle of groove too small"); if (angle > 360.0) return new App::DocumentObjectExecReturn("Angle of groove too large"); - + angle = Base::toRadians(angle); // Reverse angle if selected if (Reversed.getValue() && !Midplane.getValue()) angle *= (-1.0); - + Part::Part2DObject* sketch = 0; std::vector wires; TopoDS_Shape support; @@ -152,6 +153,10 @@ App::DocumentObjectExecReturn *Groove::execute(void) support.Move(invObjLoc); sketchshape.Move(invObjLoc); + // Check distance between sketchshape and axis - to avoid failures and crashes + if (checkLineCrossesFace(gp_Lin(pnt, dir), TopoDS::Face(sketchshape))) + return new App::DocumentObjectExecReturn("Revolve axis intersects the sketch"); + // revolve the face to a solid BRepPrimAPI_MakeRevol RevolMaker(sketchshape, gp_Ax1(pnt, dir), angle); @@ -159,7 +164,7 @@ App::DocumentObjectExecReturn *Groove::execute(void) TopoDS_Shape result = RevolMaker.Shape(); // set the subtractive shape property for later usage in e.g. pattern this->SubShape.setValue(result); - + // cut out groove to get one result object BRepAlgoAPI_Cut mkCut(support, result); // Let's check if the fusion has been successful @@ -181,7 +186,7 @@ App::DocumentObjectExecReturn *Groove::execute(void) catch (Standard_Failure) { Handle_Standard_Failure e = Standard_Failure::Caught(); if (std::string(e->GetMessageString()) == "TopoDS::Face") - return new App::DocumentObjectExecReturn("Could not create face from sketch.\n" + return new App::DocumentObjectExecReturn("Could not create face from sketch.\n" "Intersecting sketch entities or multiple faces in a sketch are not allowed."); else return new App::DocumentObjectExecReturn(e->GetMessageString()); diff --git a/src/Mod/PartDesign/App/FeatureRevolution.cpp b/src/Mod/PartDesign/App/FeatureRevolution.cpp index 463c32970..c5018588f 100644 --- a/src/Mod/PartDesign/App/FeatureRevolution.cpp +++ b/src/Mod/PartDesign/App/FeatureRevolution.cpp @@ -33,6 +33,7 @@ # include # include # include +# include #endif #include @@ -40,6 +41,7 @@ #include #include "FeatureRevolution.h" +#include using namespace PartDesign; @@ -76,12 +78,12 @@ App::DocumentObjectExecReturn *Revolution::execute(void) return new App::DocumentObjectExecReturn("Angle of groove too small"); if (angle > 360.0) return new App::DocumentObjectExecReturn("Angle of groove too large"); - + angle = Base::toRadians(angle); // Reverse angle if selected if (Reversed.getValue() && !Midplane.getValue()) angle *= (-1.0); - + Part::Part2DObject* sketch = 0; std::vector wires; try { @@ -90,7 +92,7 @@ App::DocumentObjectExecReturn *Revolution::execute(void) } catch (const Base::Exception& e) { return new App::DocumentObjectExecReturn(e.what()); } - + TopoDS_Shape support; try { support = getSupportShape(); @@ -158,6 +160,10 @@ App::DocumentObjectExecReturn *Revolution::execute(void) support.Move(invObjLoc); sketchshape.Move(invObjLoc); + // Check distance between sketchshape and axis - to avoid failures and crashes + if (checkLineCrossesFace(gp_Lin(pnt, dir), TopoDS::Face(sketchshape))) + return new App::DocumentObjectExecReturn("Revolve axis intersects the sketch"); + // revolve the face to a solid BRepPrimAPI_MakeRevol RevolMaker(sketchshape, gp_Ax1(pnt, dir), angle); @@ -186,7 +192,7 @@ App::DocumentObjectExecReturn *Revolution::execute(void) catch (Standard_Failure) { Handle_Standard_Failure e = Standard_Failure::Caught(); if (std::string(e->GetMessageString()) == "TopoDS::Face") - return new App::DocumentObjectExecReturn("Could not create face from sketch.\n" + return new App::DocumentObjectExecReturn("Could not create face from sketch.\n" "Intersecting sketch entities or multiple faces in a sketch are not allowed."); else return new App::DocumentObjectExecReturn(e->GetMessageString()); diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.cpp b/src/Mod/PartDesign/App/FeatureSketchBased.cpp index 3f5bac665..5a9aaa41c 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.cpp +++ b/src/Mod/PartDesign/App/FeatureSketchBased.cpp @@ -52,6 +52,11 @@ # include # include # include +# include +# include +# include +# include +# include #endif @@ -532,6 +537,61 @@ const bool SketchBased::checkWireInsideFace(const TopoDS_Wire& wire, const TopoD return (proj.More() && proj.Current().Closed()); } +const bool SketchBased::checkLineCrossesFace(const gp_Lin &line, const TopoDS_Face &face) { + // This is not as easy as it looks, because a distance of zero might be OK if + // the axis touches the sketchshape in in a linear edge or a vertex + // Note: This algorithm does not catch cases where the sketchshape touches the + // axis in two or more points + // Note: And it only works on closed outer wires + TopoDS_Wire outerWire = ShapeAnalysis::OuterWire(face); + BRepBuilderAPI_MakeEdge mkEdge(line); + if (!mkEdge.IsDone()) + throw Base::Exception("Revolve: Unexpected OCE failure"); + BRepAdaptor_Curve axis(TopoDS::Edge(mkEdge.Shape())); + + TopExp_Explorer ex; + int intersections = 0; + std::vector intersectionpoints; + + // Note: We need to look at evey edge separately to catch coincident lines + for (ex.Init(outerWire, TopAbs_EDGE); ex.More(); ex.Next()) { + BRepAdaptor_Curve edge(TopoDS::Edge(ex.Current())); + Extrema_ExtCC intersector(axis, edge); + + if (intersector.IsDone()) { + for (int i = 1; i <= intersector.NbExt(); i++) { + + + if (intersector.SquareDistance(i) < Precision::Confusion()) { + if (intersector.IsParallel()) { + // A line that is coincident with the axis produces three intersections + // 1 with the line itself and 2 with the adjacent edges + intersections -= 2; + } else { + Extrema_POnCurv p1, p2; + intersector.Points(i, p1, p2); + intersectionpoints.push_back(p1.Value()); + intersections++; + } + } + } + } + } + + // Note: We might check this inside the loop but then we have to rely on TopExp_Explorer + // returning the wire's edges in adjacent order (because of the coincident line checking) + if (intersections > 1) { + // Check that we don't touch the sketchface just in two identical vertices + if ((intersectionpoints.size() == 2) && + (intersectionpoints[0].IsEqual(intersectionpoints[1], Precision::Confusion()))) + return false; + else + return true; + } + + return false; +} + void SketchBased::remapSupportShape(const TopoDS_Shape& newShape) { TopTools_IndexedMapOfShape faceMap; diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.h b/src/Mod/PartDesign/App/FeatureSketchBased.h index 4163ffe86..995a2e112 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.h +++ b/src/Mod/PartDesign/App/FeatureSketchBased.h @@ -32,6 +32,7 @@ class TopoDS_Shape; class TopoDS_Face; class TopoDS_Wire; class gp_Dir; +class gp_Lin; namespace PartDesign { @@ -102,7 +103,7 @@ protected: const std::string& method, const gp_Dir& direction, const double L, - const double L2, + const double L2, const bool midplane, const bool reversed); @@ -110,6 +111,10 @@ protected: static const bool checkWireInsideFace(const TopoDS_Wire& wire, const TopoDS_Face& face, const gp_Dir& dir); + + /// Check whether the line crosses the face (line and face must be on the same plane) + static const bool checkLineCrossesFace(const gp_Lin& line, const TopoDS_Face& face); + }; } //namespace PartDesign