Add Part.makeLongHelix to work around Mantis #0954

This commit is contained in:
WandererFan
2013-12-28 09:44:54 -05:00
committed by wmayer
parent a018b50ac2
commit acb8210c96
3 changed files with 124 additions and 8 deletions

View File

@@ -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"},

View File

@@ -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,

View File

@@ -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,