*(continued...)*

**Pipe with constant radius**

A particular case of a pipe with a constant section is a pipe with a constant radius. In ACIS such surfaces are called tubes.

Here is a sample screenshot:

Here is an example of creation:

GeomFill_Pipe aTube (thePath, theRadius);

aTube.Perform (aTol, Standard_False, (GeomAbs_Shape)Min (GeomAbs_C1, thePath->Continuity()), aMaxDeg, aMaxSeg);

**Pipe with constant radius and two rail curves**

As a convenience, the pipe algorithm allows to specify two rail curves. Rails are those which limit the cross section.

This algorithm flavor can be used to model so-called rolling ball surfaces. ACIS defines rolling-ball surfaces as if you have a ball of a constant radius that rolls along the path and always touches two limiting faces. The traces that the ball makes on those boundary faces are called spring or rail curves.

Open CASCADE algorithm accepts the radius, the path and two rail curves and creates a surface with limited circular sections. Each section is constructed by intersecting a plane at every path point and perpendicular to it with rail curves.

Here are sample screenshots of rolling ball surfaces:

On both images the pipes are shown in red and rail curves in blue. The 2nd screenshot also contains a full tube of which a fragment is constructed using 2 rail curves. This tube is a trace that a full rolling ball would make.

Important note to make is that Open CASCADE requires that rail curves follow the path parametrization. This means that the rail curves' ranges must be at least as big as the path's and be consistent between each other.

**Pipe with variable radius**

In addition to constant radius, you might want to create tubes (i.e. pipes with circular sections) with variable radii. For instance, like this:

Open CASCADE does not offer direct API to construct such surfaces but you can do these using lower level API it offers. For instance, here is my code excerpt:

/*! Set radius evolution function with SetEvol() before calling this method.

If \a theIsPolynomial is true tries to create polynomial B-Spline, otherwise - rational.

\sa Surface(), Error().

*/

void ACISGGeom_Pipe::Perform (const Standard_Real theTol,

const Standard_Boolean theIsPolynomial,

const GeomAbs_Shape theContinuity,

const Standard_Integer theMaxDegree,

const Standard_Integer theMaxSegment)

{

mySurface.Nullify();

myError = -1.;

if (myEvol.IsNull())

return;

//circular profile

Handle(Geom_Circle) aCirc = new Geom_Circle (gp::XOY(), 1.);

aCirc->Rotate (gp::OZ(), PI / 2.);

//code inspired by GeomFile_Pipe when using for constant radius and corrected

//trihedron orientation

//perpendicular section

Handle(GeomFill_SectionLaw) aSec = new GeomFill_EvolvedSection (aCirc, myEvol);

Handle(GeomFill_LocationLaw) aLoc = new GeomFill_CurveAndTrihedron (

new GeomFill_CorrectedFrenet);

aLoc->SetCurve (myPath);

GeomFill_Sweep Sweep (aLoc, myIsElem);

Sweep.SetTolerance (theTol);

Sweep.Build (aSec, GeomFill_Location, theContinuity, theMaxDegree, theMaxSegment);

if (Sweep.IsDone()) {

mySurface = Sweep.Surface();

myError = Sweep.ErrorOnSurface();

}

}

In this case myEval is Handle_Law_BSpFunc object constructed from 2D B-Spline which defines radius evolution:

/*! Creates an internal Law_BSpFunc object which represents an evolution function. Uses X

coordinates of the \a theEvol B-Spline curve.

\a theFirst and \a theLast are boundaries of the path curve.

*/

static Handle(Law_BSpFunc) CreateBsFunction (const Handle(Geom2d_BSplineCurve)& theEvol,

const Standard_Real theFirst,

const Standard_Real theLast)

{

//knots are recalculated from theEvol prorate to [theFirst, theLast] range

Standard_Integer i;

const Standard_Integer aNbP = theEvol->NbPoles();

TColgp_Array1OfPnt2d aPArrE (1, aNbP);

theEvol->Poles (aPArrE);

TColStd_Array1OfReal aPArr (1, aNbP);

for (i = 1; i <= aNbP; i++)

aPArr(i) = aPArrE(i).X();

const Standard_Integer aNbK = theEvol->NbKnots();

TColStd_Array1OfReal aKArrE (1, aNbK), aKArr (1, aNbK);

theEvol->Knots (aKArrE);

TColStd_Array1OfInteger aMArr (1, aNbK);

theEvol->Multiplicities (aMArr);

const Standard_Real aKF = aKArrE(1), aKL = aKArrE (aNbK);

const Standard_Real aKRatio = (theLast - theFirst) / (aKL - aKF);

for (i = 1; i <= aNbK; i++) {

aKArr(i) = theFirst + (aKArrE(i) - aKF) * aKRatio;

}

Handle(Law_BSpline) aBs;

if (theEvol->IsRational()) {

TColStd_Array1OfReal aWArrE (1, aNbP);

theEvol->Weights (aWArrE);

aBs = new Law_BSpline (aPArr, aWArrE, aKArr, aMArr, theEvol->Degree(),

theEvol->IsPeriodic());

} else {

aBs = new Law_BSpline (aPArr, aKArr, aMArr, theEvol->Degree(), theEvol->IsPeriodic());

}

Handle(Law_BSpFunc) aFunc = new Law_BSpFunc (aBs, theFirst, theLast);

return aFunc;

}

/*! Uses X coordinates of the \a theEvol B-Spline curve to set evolution function.

*/

void ACISGGeom_Pipe::SetEvol (const Handle(Geom2d_BSplineCurve)& theEvol)

{

myEvol = ::CreateBsFunction (theEvol, myPath->FirstParameter(), myPath->LastParameter());

}

Below are examples of radius function (as 2D B-Spline) and resulting surface:

**Common comments**

Pipe surfaces are parametrized in U along the cross section and in V along the path. Surface parametrization inherits the path range and adjusts U to a section range. For instance, tubes are parametrized from 0 to 2*PI in U.

*To be continued...*