3D Pipe

Started by
9 comments, last by fear4ever 17 years, 1 month ago
Any ideas on implemneting a smooth 3d Pipe when 3D points that the pipe will follow are present (say generated from a bezier curve)? I thought about drawing cylinders at each point in direction of next point with height equal to the distance between these two points, but that's a lot of calculation. Anyne got a better idea? edit: I guess there is no simple solution for this. Also my solution leaves empty areas at curving intersection points...Still hoping someone got some ideas..
Advertisement
You have a decent idea, just generate a ring of points offset from the points on the curve, and then connect them using triangle strips or something similar.

You might want quite a few divisions on the curve to get a good curve going in the final tube.

If ya want I could go a bit more in-depth into the method.

I seek knowledge and to help others whom seek it
Assuming there are no particular constraints on the curve (that is, it can go in 'any direction'), then your best bet is probably to use a 'parallel transport frame'.

A Google search for this term might turn up some good references. If not, I can help further, but be aware that implementing this technique requires a reasonable degree of comfort with vector and matrix math.
Thanks for the replies.

jyk, i had a glance at parallel transport frame method. Its a bit overkill for my application since the tube generation part is just a small part of it (i'm not very good at linear algebra am i:) ).

AlgorithmX2, if I understand you correctly you are proposing i find equadistance points around all original curve points. That will give me circle points around curve points. Then I can triangulate the points of circles to get a pipe. The circles will be on planes that are perpendicular to the tangent of the curve at that point.

That is what I had in mind. If that's not what you are suggesting please correct me.

Now assuming that is the method, can you please elaborate on how to find the circle points based on the direction vector of a curve point. (The points of the red circle P1 and P2 given)


[Edited by - fear4ever on March 8, 2007 2:25:12 AM]
What I would do is find two orthogonal directions to the vector P1->P2. These two directions can define a new co-ordinate system which you can use to create the circle.

1) To find the first you can cross product the vector with any arbitaty non-parallel vector. This must give one vector perpendicular to the original one.

2) The second is then a cross product of original one, and the new one. This will give you two axes around which you can produce a circle of points.

The arbitary direction in stage 1 can probably be manipulated to help you with connectivity. If it's completely random then your starting rotation on your circle will be different each time. An idea might be to use the previous vector as your arbitary vector. I'd suggest having a play around.

I've not done this before, I'm just saying how I'd start of going about it. This method might be disgustingly flawed in some way, or there may be a far better way. Yell if you want me to elaborate.
TGA your approach seems correct. Only a minor flow as far as i can see is even if i take the same random vector each time, because the direction vector changes my first point will be on a diffrent part of circles each time. Am i correct?

Now my algebra is a bit weak so i'll request your help here. This is my example

P1(1,1,1)
P2(3,5,4)

PDirection=P2-P1= (2,4,3)
PRandom= (1,1,1)

axis1= PDirection X PRandom = (4*1-3*1)i+(3*1-2*1)j+(2*1-4*1)k
= (1,1,-2)

axis2= axis1 X PDirection = (1,1,-2) X (5,3,4)
= (1*4-(-2)*3)i+((-2)*5-1*4)j+(1*3-1*5)k
= (10, -14, -2)

so
axis1= (1,1,-2)
axis1= (10, -14, -2)

Assuming what i have done is correct, how can i find circle points using these two axis? (at radius r )
Quote:Original post by fear4ever
TGA your approach seems correct. Only a minor flow as far as i can see is even if i take the same random vector each time, because the direction vector changes my first point will be on a diffrent part of circles each time. Am i correct?

Now my algebra is a bit weak so i'll request your help here. This is my example

P1(1,1,1)
P2(3,5,4)

PDirection=P2-P1= (2,4,3)
PRandom= (1,1,1)

axis1= PDirection X PRandom = (4*1-3*1)i+(3*1-2*1)j+(2*1-4*1)k
= (1,1,-2)

axis2= axis1 X PDirection = (1,1,-2) X (5,3,4)
= (1*4-(-2)*3)i+((-2)*5-1*4)j+(1*3-1*5)k
= (10, -14, -2)

so
axis1= (1,1,-2)
axis1= (10, -14, -2)

Assuming what i have done is correct, how can i find circle points using these two axis? (at radius r )
Let me put in one more plug for the PTF :)

Use of either a fixed-reference or Frenet frame can be problematic when generating meshes for generalized cylinders. Issues include degeneracies, discontinuities, and improper alignment of vertices. These methods certainly can work given certain constraints (and are to be preferred in some cases), but the parallel transport frame is more general and will produce acceptable results in almost all cases.

Here's a screenshot of a generalized cylinder generated using this method:



Fixed-reference and Frenet frames are easier to implement, so if you can get one of these methods to work for your purposes that'd probably be the easiest way to go. If however you run into problems or need to support arbitrarily oriented curves, you might take another look at the parallel transport frame.
If you were to take a slightly more systematic approach, like taking the cross product of the previous and current vector then the first points should connect fairly well.

As for maths, your second cross product seems odd:

axis2 = axis1 X PDirection = (1,1,-2) X (2,4,3), which gives axis2 = (-11, 7, -2)

You then have to normalize these axes:
axis1N = (1, 1, -2) / sqrt(6)
axis2N = (-11, 7, -2) / sqrt(174)

To find the points on the circle at each angle relative to the centre point you should be able to just multiply one axis by sin(angle), the other by cos(angle), sum the results, and multiply by the radius. If you think about it this is the same as what you do working in the x-y plane with axes (0,0,1), and (0,1,0).
I have written a simple program to implement this. Here is a link to MSVS 6 workspace (10kb)
Source

I am using a bezier curve. You can play with resetControl() function to specify diffrent control points and get diffrent curves.

The pipe is generated with some weird looking parts especially at curving regions. I could not figure out if this is due to the 3D structure of it or not. (I think something is definetely wrong though).

If you have time to download and have a look at it please check the "circlesFromCurve" function and let me know if there is any problem there.

For those who dont have time to download the source, this is the function.

double PI = acos(-1);const float DEG2RAD=PI/180;typedef struct{	double x;	double y;	double z;}Point3D;typedef struct{	Point3D* points;	int n;}Circle;



/*This func generates a circle for each point on curve *cn is numner of curve points that i will generate circles for *res is resolution of circles(number of points per circle)*/Circle* circlesFromCurve(Point3D* curvePoints,int cn, int res, double radius){	Circle* circles=(Circle*)malloc(sizeof(Circle)*cn);     Point3D pRandom;    pRandom.x=1;    pRandom.y=1;    pRandom.z=1;	for(int i=0;i<cn-1;i++)	{		Point3D pDirection;		Point3D axis1,axis2; 		pDirection.x=curvePoints[i+1].x-curvePoints.x;        pDirection.y=curvePoints[i+1].y-curvePoints.y;        pDirection.z=curvePoints[i+1].z-curvePoints.z;                          		axis1.x=pDirection.y*pRandom.z - pDirection.z*pRandom.y;        axis1.y=pDirection.z*pRandom.x - pDirection.x*pRandom.z;        axis1.z=pDirection.x-pRandom.y - pDirection.y*pRandom.x;         axis2.x=axis1.y*pDirection.z - axis1.z*pDirection.y;        axis2.y=axis1.z*pDirection.x - axis1.x*pDirection.z;        axis2.z=axis1.x-pDirection.y - axis1.y*pDirection.x;         double l=axis1.x*axis1.x+axis1.y*axis1.y+axis1.z*axis1.z;        axis1.x=axis1.x/sqrt(l);        axis1.y=axis1.y/sqrt(l);        axis1.z=axis1.z/sqrt(l);         l=axis2.x*axis1.x+axis2.y*axis2.y+axis2.z*axis2.z;		axis2.x=axis2.x/sqrt(l);        axis2.y=axis2.y/sqrt(l);        axis2.z=axis2.z/sqrt(l);  		circles.n=res;        circles.points=(Point3D*)malloc(sizeof(Point3D)*res);         double step=360/res;        for(int j=0;j<res;j++)        {			double degree=j*step*DEG2RAD;            double vcos=sin(degree)*radius;            double vsin=cos(degree)*radius;            circles.points[j].x=curvePoints.x+axis1.x*vcos+axis2.x*vsin;            circles.points[j].y=curvePoints.y+axis1.y*vcos+axis2.y*vsin;            circles.points[j].z=curvePoints.z+axis1.z*vcos+axis2.z*vsin;                    }         pRandom.x=pDirection.x;        pRandom.y=pDirection.y;        pRandom.z=pDirection.z;	} 	return circles;}
There were a few typos in there (magnetude of 2nd axis, and both cross product z-axes). This should work:

/*This func generates a circle for each point on curve *cn is numner of curve points that i will generate circles for *res is resolution of circles(number of points per circle)*/Circle* circlesFromCurve(Point3D* curvePoints,int cn, int res, double radius){	Circle* circles=(Circle*)malloc(sizeof(Circle)*cn);     Point3D pRandom;    pRandom.x=1;    pRandom.y=1;    pRandom.z=1;	for(int i=0;i<cn-1;i++)	{		Point3D pDirection;		Point3D axis1,axis2; 		pDirection.x=curvePoints[i+1].x-curvePoints.x;        pDirection.y=curvePoints[i+1].y-curvePoints.y;        pDirection.z=curvePoints[i+1].z-curvePoints.z; //Bug squashed                    		axis1.x=pDirection.y*pRandom.z - pDirection.z*pRandom.y;        axis1.y=pDirection.z*pRandom.x - pDirection.x*pRandom.z;        axis1.z=pDirection.x*pRandom.y - pDirection.y*pRandom.x; //Bug squashed         axis2.x=axis1.y*pDirection.z - axis1.z*pDirection.y;        axis2.y=axis1.z*pDirection.x - axis1.x*pDirection.z;        axis2.z=axis1.x*pDirection.y - axis1.y*pDirection.x; //Bug squashed         double l=axis1.x*axis1.x+axis1.y*axis1.y+axis1.z*axis1.z;        axis1.x=axis1.x/sqrt(l);        axis1.y=axis1.y/sqrt(l);        axis1.z=axis1.z/sqrt(l);         l=axis2.x*axis2.x+axis2.y*axis2.y+axis2.z*axis2.z; //Bug squashed		axis2.x=axis2.x/sqrt(l);        axis2.y=axis2.y/sqrt(l);        axis2.z=axis2.z/sqrt(l);  		circles.n=res;        circles.points=(Point3D*)malloc(sizeof(Point3D)*res);         double step=360/res;        for(int j=0;j<res;j++)        {			double degree=j*step*DEG2RAD;            double vcos=sin(degree)*radius;            double vsin=cos(degree)*radius;            circles.points[j].x=curvePoints.x+axis1.x*vcos+axis2.x*vsin;            circles.points[j].y=curvePoints.y+axis1.y*vcos+axis2.y*vsin;            circles.points[j].z=curvePoints.z+axis1.z*vcos+axis2.z*vsin;                    }         pRandom.x=pDirection.x;        pRandom.y=pDirection.y;        pRandom.z=pDirection.z;	} 	return circles;}

This topic is closed to new replies.

Advertisement