diff --git a/src/Mod/Part/App/AppPartPy.cpp b/src/Mod/Part/App/AppPartPy.cpp index dbe8270cdc..b63fda3689 100644 --- a/src/Mod/Part/App/AppPartPy.cpp +++ b/src/Mod/Part/App/AppPartPy.cpp @@ -857,6 +857,29 @@ static PyObject * makeHelix(PyObject *self, PyObject *args) } } +static PyObject * makeLongHelix(PyObject *self, PyObject *args) +{ + double pitch, height, radius, angle=-1.0; + PyObject *pleft=Py_False; + if (!PyArg_ParseTuple(args, "ddd|dO!", &pitch, &height, &radius, &angle, + &(PyBool_Type), &pleft)) { + Base::Console().Message("Part.makeLongHelix fails on parms\n"); + return 0; + } + + try { + TopoShape helix; + Standard_Boolean anIsLeft = PyObject_IsTrue(pleft) ? Standard_True : Standard_False; + TopoDS_Shape wire = helix.makeLongHelix(pitch, height, radius, angle, anIsLeft); + return new TopoShapeWirePy(new TopoShape(wire)); + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + PyErr_SetString(PyExc_Exception, e->GetMessageString()); + return 0; + } +} + static PyObject * makeThread(PyObject *self, PyObject *args) { double pitch, depth, height, radius; @@ -1650,6 +1673,11 @@ struct PyMethodDef Part_methods[] = { "By default a cylindrical surface is used to create the helix. If the fourth parameter is set\n" "(the apex given in degree) a conical surface is used instead"}, + {"makeLongHelix" ,makeLongHelix,METH_VARARGS, + "makeLongHelix(pitch,height,radius,[angle],[hand]) -- Make a (multi-edge) helix with a given pitch, height and radius\n" + "By default a cylindrical surface is used to create the helix. If the fourth parameter is set\n" + "(the apex given in degree) a conical surface is used instead."}, + {"makeThread" ,makeThread,METH_VARARGS, "makeThread(pitch,depth,height,radius) -- Make a thread with a given pitch, depth, height and radius"}, diff --git a/src/Mod/Part/App/TopoShape.cpp b/src/Mod/Part/App/TopoShape.cpp index 5fac6d70a8..a10ddbc661 100644 --- a/src/Mod/Part/App/TopoShape.cpp +++ b/src/Mod/Part/App/TopoShape.cpp @@ -1582,14 +1582,14 @@ TopoDS_Shape TopoShape::makeHelix(Standard_Real pitch, Standard_Real height, if (newStyle) { // See discussion at 0001247: Part Conical Helix Height/Pitch Incorrect - if (angle >= Precision::Confusion()) { - // calculate end point for conical helix - Standard_Real v = height / cos(angle); - Standard_Real u = (height/pitch) * 2.0 * M_PI; - gp_Pnt2d cend(u, v); - end = cend; - } - } + if (angle >= Precision::Confusion()) { + // calculate end point for conical helix + Standard_Real v = height / cos(angle); + Standard_Real u = (height/pitch) * 2.0 * M_PI; + gp_Pnt2d cend(u, v); + end = cend; + } + } Handle(Geom2d_TrimmedCurve) segm = GCE2d_MakeSegment(beg , end); @@ -1599,6 +1599,91 @@ TopoDS_Shape TopoShape::makeHelix(Standard_Real pitch, Standard_Real height, return wire; } +//*********** +// makeLongHelix is a workaround for an OCC problem found in helices with more than +// some magic number of turns. See Mantis #0954. +//*********** +TopoDS_Shape TopoShape::makeLongHelix(Standard_Real pitch, Standard_Real height, + Standard_Real radius, Standard_Real angle, + Standard_Boolean leftHanded) const +{ + if (pitch < Precision::Confusion()) + Standard_Failure::Raise("Pitch of helix too small"); + + if (height < Precision::Confusion()) + Standard_Failure::Raise("Height of helix too small"); + + gp_Ax2 cylAx2(gp_Pnt(0.0,0.0,0.0) , gp::DZ()); + Handle_Geom_Surface surf; + Standard_Boolean isCylinder; + + if (angle < Precision::Confusion()) { // Cylindrical helix + if (radius < Precision::Confusion()) + Standard_Failure::Raise("Radius of helix too small"); + surf= new Geom_CylindricalSurface(cylAx2, radius); + isCylinder = true; + } + else { // Conical helix + angle = Base::toRadians(angle); + if (angle < Precision::Confusion()) + Standard_Failure::Raise("Angle of helix too small"); + surf = new Geom_ConicalSurface(gp_Ax3(cylAx2), angle, radius); + isCylinder = false; + } + + Standard_Real turns = height/pitch; + unsigned long wholeTurns = trunc(turns); + Standard_Real partTurn = turns - wholeTurns; + + gp_Pnt2d aPnt(0, 0); + gp_Dir2d aDir(2. * M_PI, pitch); + Standard_Real coneDir = 1.0; + if (leftHanded) { + aPnt.SetCoord(2. * M_PI, 0.0); + aDir.SetCoord(-2. * M_PI, pitch); + coneDir = -1.0; + } + gp_Ax2d aAx2d(aPnt, aDir); + Handle(Geom2d_Line) line = new Geom2d_Line(aAx2d); + gp_Pnt2d beg = line->Value(0); + gp_Pnt2d end; + Standard_Real u,v; + BRepBuilderAPI_MakeWire mkWire; + Handle(Geom2d_TrimmedCurve) segm; + TopoDS_Edge edgeOnSurf; + + for (unsigned long i = 0; i < wholeTurns; i++) { + if (isCylinder) + end = line->Value(sqrt(4.0*M_PI*M_PI+pitch*pitch)*(i+1)); + else { + u = coneDir * (i+1) * 2.0 * M_PI; + v = ((i+1) * pitch) / cos(angle); + end = gp_Pnt2d(u, v); + } + segm = GCE2d_MakeSegment(beg , end); + edgeOnSurf = BRepBuilderAPI_MakeEdge(segm , surf); + mkWire.Add(edgeOnSurf); + beg = end; + } + + if (partTurn > Precision::Confusion()) { + if (isCylinder) + end = line->Value(sqrt(4.0*M_PI*M_PI+pitch*pitch)*turns); + else { + u = coneDir * turns * 2.0 * M_PI; + v = height / cos(angle); + end = gp_Pnt2d(u, v); + } + segm = GCE2d_MakeSegment(beg , end); + edgeOnSurf = BRepBuilderAPI_MakeEdge(segm , surf); + mkWire.Add(edgeOnSurf); + } + + TopoDS_Wire wire = mkWire.Wire(); + BRepLib::BuildCurves3d(wire); + return wire; +} + TopoDS_Shape TopoShape::makeThread(Standard_Real pitch, Standard_Real depth, Standard_Real height, diff --git a/src/Mod/Part/App/TopoShape.h b/src/Mod/Part/App/TopoShape.h index 86cd4b2692..4fcece5727 100644 --- a/src/Mod/Part/App/TopoShape.h +++ b/src/Mod/Part/App/TopoShape.h @@ -163,6 +163,9 @@ public: TopoDS_Shape makeHelix(Standard_Real pitch, Standard_Real height, Standard_Real radius, Standard_Real angle=0, Standard_Boolean left=Standard_False, Standard_Boolean style=Standard_False) const; + TopoDS_Shape makeLongHelix(Standard_Real pitch, Standard_Real height, + Standard_Real radius, Standard_Real angle=0, + Standard_Boolean left=Standard_False) const; TopoDS_Shape makeThread(Standard_Real pitch, Standard_Real depth, Standard_Real height, Standard_Real radius) const; TopoDS_Shape makeLoft(const TopTools_ListOfShape& profiles, Standard_Boolean isSolid,