Retrieving Cylindrical Surface from BSpline Surface

Short introduction:
For some reason CATIAV.5 converts during STEP-write-process some cylindrical surfaces to BSpline-surfaces. But my program relies on primitive surfaces (cones, cylinders, spheres, tori and of course planes).

Question:
Is there a way to retrieve the cylindrical surface from the BSpline-surface (which actually IS a cylindrical surface).

Thanks for any help/hint

Greetings,

Dennis

Gerhard Hofmann's picture
Denis Teissandier's picture

In such case, I retrieve the properties of a cylindrical surface like that :

TopoDS_Shape sh1= ....; // Your shape built by the STEP reader of OCC
TopoDS_Face aFace1= TopoDS::Face(sh1);

BRepAdaptor_Surface FaceElementAdaptor1(aFace1, Standard_True);
GeomAbs_SurfaceType theTypeElement1=FaceElementAdaptor1.GetType();

Standard_Real theDiameter; // Diameter of the cylindrical surface
gp_Ax1 theAxis; // Axis of the cylindrical surface

if(theTypeElement1==GeomAbs_Cylinder)
{
theAxis= FaceElementAdaptor1.AxeOfRevolution();

gp_Pnt aPnt1= FaceElementAdaptor1.Value(FaceElementAdaptor1.FirstUParameter(), FaceElementAdaptor1.FirstVParameter());
gp_Pnt aPnt2= FaceElementAdaptor1.Value(FaceElementAdaptor1.LastUParameter(), FaceElementAdaptor1.LastVParameter());

Handle(Geom_Line) aGeomAxis= new Geom_Line(theAxis);
GeomAPI_ProjectPointOnCurve aProj1(aPnt1, aGeomAxis);
GeomAPI_ProjectPointOnCurve aProj2(aPnt2, aGeomAxis);
theDiameter= 2*(aProj1.Distance(1));
}

Regards,

Denis

Pawel's picture

Hi Dennis,

you can try the following approach:
Iterate through the uv-parametric space of your surface and make sure that:
- at each point one curvature value is 0 the other is not 0
- all the "not 0" curvature values are equal (choosing a tolerance may be an issue here)
- the direction of the "0-curvature" is the same at each point (those must be parallel)
- the angle between the "0" nad the "not 0" curvature direction is 90 degree

If you choose the tolerances properly it should work. It worked for me.

Cheers
Pawel

Dennis G.'s picture

Thank you for the answers. By now I realized that I also have to implement quadric surfaces in general. So I decided to handle any B-Spline surface as a general quadric. Therefor I spread some sample points over the surface in question and fit the general quadric to these points by solving the linear equations A.x=b by using OpenCASCADES implementation of the Singular Value Decomposition algorithm in math_SVD.

This works well.

Thanks again,

Dennis

Hesham Nasif's picture

Hello Dennis
I am facing same problem. I have one surface
Geom_Adaptor gives me the surface type BSpline, while BRep_Adaptor is give it to me as a cylinder, but when i am trying to handle the cylinder it is give me runtime error. So now i would like to use it as a BSpline and create points and using SVD to get general Quadric coefficients. Would you help me to do that
Thanks
Hesham

Hesham Nasif's picture

I am facing same problem. I have one surface
Geom_Adaptor gives me the surface type BSpline, while BRep_Adaptor is give it to me as a cylinder, but when i am trying to handle the cylinder it is give me runtime error. So now i would like to use it as a BSpline and create points and using SVD to get general Quadric coefficients. Would you help me to do that
Thanks
Hesham

Dennis G.'s picture

Hi Hesham,

this is basically the code I used for the calculation of the coefficients for a general quadric:

Standard_Boolean myAppCSGTool_CellBuilder::ComputeGQ(const TopoDS_Face& theFace, math_Vector& pVec)
{
/*
* Compute General Quadric (GQ) for given Face
*
* GQ is defined by: A x**2 + B y**2 + C z**2 + D xy + E yz + F zx + G x + H y + I z = -1
*
* Best fitting parameter vector (A,B,C,D,E,F,G,H,I) is found by solving the set of linear equations
* A x = b for x by using a singular value decomposition algorithm, implemented by OCC
* 'A' herewith is the design matrix given by A_ij = X_j(x_i), with X_j \in {x**2, y**2, ... , y, z}
* b_j = -1 for all j=1..N, N=Number of Sample points. So A is a NxM matrix (N sample points, M parameters).
* Solving the above equation for x leads to the best fitting parameter vector in the chisquare sense.
*/

//Get Sample Points on surface
Standard_Integer sp=2, N=0;
Handle(TColgp_HSequenceOfPnt) theSamplePoints;

while(true)//collect sample points
{
theSamplePoints = myApp_GTOOL::FaceSamplePoints(theFace,sp+1,sp);
N = theSamplePoints->Length();

if(N >= 30)
break;

theSamplePoints->Clear();

if(sp>5)
{
cout << "_#_myAppCSGTool_CellBuilder.cxx :: Can't create sufficient sample points for fit!!!" << endl;
return Standard_False;
}
sp++;
}

//Fill design matrix A
Standard_Integer i,j;

math_Vector b(1,N); // =-1
math_Matrix A(1,N,1,9); //design matrix
b.Init(-1); // A.a=b, where a='parameter vector', b='residual vector'

for(i=1; i<=N; i++)
{
gp_Pnt pnt = theSamplePoints->Value(i);

for(j=1;j<=9;j++)
{
Standard_Real eval = DjFunc(pnt,j);
if(Abs(eval)<1.0e-9)
eval = 0.0;

A(i,j) = eval;
}
}

math_SVD singVD(A); // perform singular value decomposition and solve herewith the least square problem
singVD.Solve(b, pVec, 1e-7);

//set small values to cero
for(j=1; j<=9; j++)
if(Abs(pVec(j))<1e-7)
pVec(j)=0.0;

//compute Chi-Square
Standard_Real chiSqu(0.0);
for(i=1;i<=N;i++)
{
Standard_Real val(0.0);
for(j=1;j<=9;j++)
{
val += (A(i,j)*pVec(j));
}
val+=1;

chiSqu += val*val;
}

cout << "\n\n\nCHISQU = " << chiSqu << "\n\n\n";

return Standard_True;
}

This code was sufficient for my purposes so far. I didn't have time to implement a further check if Chi-Square is small enough.

Good Luck,

Dennis

Hesham Nasif's picture

Dear Dennis
Would like to thank you so much about your help and i will start reading it
Best

Hesham Nasif's picture

Hi Dennis
I have read your code and i thank you again but there are three points i would like to know
1- FaceSamplePoints Function(theFace, sp+1,sp)
2- DjFunc(pnt, j)
3- pVect
Thanks for your considerations
Hesham

Dennis G.'s picture

Hello Hesham,

I'm sorry, I didn't read my code before I posted and I forgot to include external functions.

1. This function simply generates sample points lying on the surface. I suggest you do this part on your own. The code we use seems a little bit to much specialized for our purposes, plus it's a lot of code which my antecessor wrote and I don't have enough time right now to go through it and give support on it.

2. DjFunc(...) returns the evaluation for a given point 'pnt' of the derived d/d_j F(x1,x2,...,x9)[pnt], with j \in {1,...,9} (the nine free parameters of the function).

Standard_Real myAppCSGTool_CellBuilder::DjFunc(const gp_Pnt& pnt, const Standard_Integer& indx)
{
switch(indx)
{
case 1: return (pnt.X() * pnt.X()); // x**2
case 2: return (pnt.Y() * pnt.Y()); // y**2
case 3: return (pnt.Z() * pnt.Z()); // z**2
case 4: return (pnt.X() * pnt.Y()); // xy
case 5: return (pnt.Y() * pnt.Z()); // yz
case 6: return (pnt.Z() * pnt.X()); // zx
case 7: return (pnt.X()); // x
case 8: return (pnt.Y()); // y
case 9: return (pnt.Z()); // z
case 10:return (1); // 1
default: return 0;
}
return 0;
}

3. pVec is the vector which contains in the end the nine free parameters which we are looking for. Initially all entries are set to zero.

Hope this helps,

Dennis