diff --git a/src/Mod/PartDesign/App/FeatureHelix.cpp b/src/Mod/PartDesign/App/FeatureHelix.cpp index 3aa6e0c9e9..85144d2324 100644 --- a/src/Mod/PartDesign/App/FeatureHelix.cpp +++ b/src/Mod/PartDesign/App/FeatureHelix.cpp @@ -215,41 +215,36 @@ App::DocumentObjectExecReturn* Helix::execute() base.move(invObjLoc); - - std::vector wires; - try { - // Iterate over wires in sketch shape. - for (TopExp_Explorer explorer(sketchshape, TopAbs_WIRE); explorer.More(); explorer.Next()) - { - const TopoDS_Wire& aWire = TopoDS::Wire(explorer.Current()); - wires.push_back(aWire); - } - } - catch (const Base::Exception& e) { - return new App::DocumentObjectExecReturn(e.what()); - } TopoDS_Shape result; // generate the helix path - TopoDS_Shape path = generateHelixPath(); + TopoDS_Shape path; + if (Angle.getValue()==0.){ + // breaking the path at each turn prevents an OCC issue + path = generateHelixPath(); + } else { + // don't break the path or the generated solid is invalid + path = generateHelixPath(1000.); + } - TopoDS_Shape face = Part::FaceMakerCheese::makeFace(wires); + TopoDS_Shape face = sketchshape; face.Move(invObjLoc); BRepOffsetAPI_MakePipe mkPS(TopoDS::Wire(path), face, GeomFill_Trihedron::GeomFill_IsFrenet, Standard_False); - mkPS.Build(); result = mkPS.Shape(); BRepClass3d_SolidClassifier SC(result); SC.PerformInfinitePoint(Precision::Confusion()); - if (SC.State() == TopAbs_IN) + if (SC.State() == TopAbs_IN) { result.Reverse(); + } AddSubShape.setValue(result); if (base.isNull()) { - if (getAddSubType() == FeatureAddSub::Subtractive) + if (getAddSubType() == FeatureAddSub::Subtractive){ return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Error: There is nothing to subtract")); + } if (!isSingleSolidRuleSatisfied(result)) { return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Error: Result has multiple solids")); @@ -262,15 +257,16 @@ App::DocumentObjectExecReturn* Helix::execute() if (getAddSubType() == FeatureAddSub::Additive) { BRepAlgoAPI_Fuse mkFuse(base.getShape(), result); - if (!mkFuse.IsDone()) + if (!mkFuse.IsDone()){ return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Error: Adding the helix failed")); + } // we have to get the solids (fuse sometimes creates compounds) TopoShape boolOp = this->getSolid(mkFuse.Shape()); // lets check if the result is a solid - if (boolOp.isNull()) + if (boolOp.isNull()){ return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Error: Result is not a solid")); - + } if (!isSingleSolidRuleSatisfied(boolOp.getShape())) { return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Error: Result has multiple solids")); @@ -335,7 +331,7 @@ void Helix::updateAxis() Axis.setValue(dir.x, dir.y, dir.z); } -TopoDS_Shape Helix::generateHelixPath() +TopoDS_Shape Helix::generateHelixPath(double breakAtTurn) { double turns = Turns.getValue(); double height = Height.getValue(); @@ -398,7 +394,7 @@ TopoDS_Shape Helix::generateHelixPath() radiusTop = radius + height * tan(Base::toRadians(angle)); //build the helix path - TopoDS_Shape path = TopoShape().makeSpiralHelix(radius, radiusTop, height, turns, 1000, leftHanded); + TopoDS_Shape path = TopoShape().makeSpiralHelix(radius, radiusTop, height, turns, breakAtTurn, leftHanded); /* * The helix wire is created with the axis coinciding with z-axis and the start point at (radius, 0, 0) diff --git a/src/Mod/PartDesign/App/FeatureHelix.h b/src/Mod/PartDesign/App/FeatureHelix.h index 3a4a3a7cb7..3b01150b05 100644 --- a/src/Mod/PartDesign/App/FeatureHelix.h +++ b/src/Mod/PartDesign/App/FeatureHelix.h @@ -80,7 +80,7 @@ protected: void updateAxis(); /// generate helix and move it to the right location. - TopoDS_Shape generateHelixPath(); + TopoDS_Shape generateHelixPath(double breakAtTurn = 1.); // project shape on plane. Used for detecting self intersection. TopoDS_Shape projectShape(const TopoDS_Shape& input, const gp_Ax2& plane); diff --git a/src/Mod/PartDesign/PartDesignTests/TestTopologicalNamingProblem.py b/src/Mod/PartDesign/PartDesignTests/TestTopologicalNamingProblem.py index ec87ea61ed..82e189ce6c 100644 --- a/src/Mod/PartDesign/PartDesignTests/TestTopologicalNamingProblem.py +++ b/src/Mod/PartDesign/PartDesignTests/TestTopologicalNamingProblem.py @@ -674,7 +674,7 @@ class TestTopologicalNamingProblem(unittest.TestCase): self.assertEqual(len(body.Shape.childShapes()), 1) self.assertGreaterEqual(body.Shape.childShapes()[0].ElementMapSize, 26) revMap = body.Shape.childShapes()[0].ElementReverseMap - self.assertEqual(self.countFacesEdgesVertexes(revMap), (6, 12, 8)) + self.assertEqual(self.countFacesEdgesVertexes(revMap), (14, 28, 16)) Radius = 0 # Rectangle is on the axis, but wouldn't matter regardless here Area = Part.Face(sketch.Shape).Area # General helix formula; not actually used here since devolves to just the @@ -685,7 +685,7 @@ class TestTopologicalNamingProblem(unittest.TestCase): self.assertAlmostEqual(Area, 1) self.assertAlmostEqual(helixLength, helix.Height.Value) self.assertAlmostEqual(helix.Shape.Volume, Volume, 2) - self.assertEqual(body.Shape.ElementMapSize,26) + self.assertEqual(body.Shape.ElementMapSize, 58) def testPartDesignElementMapPocket(self): # Arrange @@ -856,8 +856,8 @@ class TestTopologicalNamingProblem(unittest.TestCase): self.assertEqual(body.Shape.childShapes()[0].ElementMapSize, 50) revMap = body.Shape.childShapes()[0].ElementReverseMap self.assertEqual(self.countFacesEdgesVertexes(revMap), (10, 24, 16)) - volume = 991.3606270276762 # TODO: math formula to calc this. - self.assertAlmostEqual(helix.Shape.Volume, volume) + volume = 991.3606 # TODO: math formula to calc this. + self.assertAlmostEqual(helix.Shape.Volume, volume, 4) def testPartDesignElementMapChamfer(self): """ Test Chamfer ( and FeatureDressup )"""