PDA

View Full Version : equation of a circle in 3D?

mcsellski
03-05-2002, 12:30 AM
Hi,

I have a requirement to map data to a cylindrical skin in 3D.

I know the datum of the base of the cylinder and the direction vector of the cylinder in 3D space. And the radius is known, of course.

What is the equation of a circle in 3D described by the origin, normal to the plane and the radius?

Any help appreciated.

Thanks

matthew

zeckensack
03-05-2002, 12:37 AM
What is the equation of a circle in 3D described by the origin, normal to the plane and the radius?
Two equations must be satisfied http://www.opengl.org/discussion_boards/ubb/smile.gif
If P is the origin, N is the normal off the plane (or in this case the direction vector of the cylinder) and the solutions in X form the circle, you'll get this

(X - P) dot (X - P)=r^2 <- equation for a sphere
(X - P) dot N=0

This is basically the intersection of a sphere around the origin and the plane -> a circle!

Hope this helps http://www.opengl.org/discussion_boards/ubb/smile.gif

mcsellski
03-05-2002, 12:54 AM
That's great. Thanks for the speedy reply. Now all I need to do is expand that and solve for x, y and z :S

Matthew

nexusone
03-05-2002, 06:19 AM
A circle is a 2D object, to draw a circle use the math function below:
Once you draw the circle, then just use glRotate to move it in 3D. The same with the texture normals apply as if a 2D object, the glrotate will adjust direction of the texture in the matrix.

This finds points on a circle:
angle is the point on the circle you are looking to find. angle is in radians
r is the radius of the circle.

x = r * cos( angle ); // X
y = r * sin( angle ); // Y

If you need information on a sphere, here is a good website on 3D math, it includes normals calculation in 3D space.
http://www.geocities.com/SiliconValley/2151/math3d.html

Originally posted by mcsellski:
Hi,

I have a requirement to map data to a cylindrical skin in 3D.

I know the datum of the base of the cylinder and the direction vector of the cylinder in 3D space. And the radius is known, of course.

What is the equation of a circle in 3D described by the origin, normal to the plane and the radius?

Any help appreciated.

Thanks

matthew

mcsellski
03-05-2002, 06:55 AM
Thanks. I think I understand. I need to create the circle then rotate it and it's texture co-ordinates to preserve the vertex normals.

Trouble is that I actually need to know the co-ordinates of the vertices that I generate. I'm mapping data as colour to a polygon. In the real-time environment I need to keep the data structure very flat for performance reasons and so all I persist is the polygon vertices. I need to get the rotated co-ordinates of those circles.

Matthew

zeckensack
03-05-2002, 11:09 AM
If we take out the origin - which is more convenient, more about that later - you need at least one vector that lies in the circle's plane (ie it's perpendicular to the normal)

So, you have two vectors, N (the normal) and P1 (perpendicular to the normal). Now you can do a cross-product to get a vector that is perpendicular to both of them.

P2 = N x P1

Normalize P1 and P2. You can now start to generate points (vertices!) along the circle. The same output can also be used as surface normals for your cylinder.
Some pseudo code might look like this:

vect3 normal=something;
vect3 perp1=something_else.normalize();
vect3 perp2=(normal.cross(perp1)).normalize();

const float pi=3.14blabla;

const int circle_vertices=100; //choose what you want
vect3 circle_vertex[circle_vertices];

for (int step=0;step<circle_vertices;++step)
{
float angle=step*pi*2/circle_vertices;
circle_vertex[step]=sin(angle)*perp1+cos(angle)*perp2;
}

There you are http://www.opengl.org/discussion_boards/ubb/smile.gif
These vertices are all centered around (0;0;0) so you can translate, rotate and scale them as you please. You should also be able to quite easily extrude the cylinder.

The remaining problem is to find perp1.

I suggest something like this

vect3 temp=normal.cross(vect3(1,0,0));
if (temp==vect3(0,0,0))
{
temp=normal.cross(vect3(0,1,0));
}
perp1=temp.normalize();
Note that this may still fail due to insufficient precision of your floating point format. Things like (float==0.0f) are extremely rare to go right on limited precision. You should try to measure if the difference falls below a small threshold instead, this is just for brevity http://www.opengl.org/discussion_boards/ubb/biggrin.gif

Thanks to Furrage for pointing out some stupid mistakes

[This message has been edited by zeckensack (edited 03-07-2002).]

mcsellski
03-06-2002, 01:40 AM
Wow, spot on, thanks. Works a treat. Now if I dig a little deeper I can even use this method for extruding convoluted pipes too. It took me all day yesterday to get precisely nowhere. This solved it in about an hour.

Thanks again.

Matthew

zeckensack
03-06-2002, 06:44 PM
Hmmm, I've just had a good idea to finding the first perpendicular vector without too much headaches http://www.opengl.org/discussion_boards/ubb/biggrin.gif

To recap, I suggested doing N x (1;0;0) because the cross product of these two vectors is another vector perpendicular to both N and (1;0;0) ... or it may be (0;0;0) which is per the mathematical definition perpendicular to all 3d vectors. But of course you can't do anything with it in graphics.

This will happen if N is of the form scalar*(1;0;0) - or very close to it, floating point only has limited precision http://www.opengl.org/discussion_boards/ubb/wink.gif. If this is the case, it'll be safe to perform a cross product with another vector that is a nice chunky 90° angle away, eg (0;1;0).

The 'winning' vector in any case will be perpendicular to the normal and large enough to be properly normalized.

Why am I blabbering then? The idea I just had was to simply calculate the length of the first dot product and see if it falls below a threshold. If the vector is very short, you might get better precision if you choose a different, longer one, and you avoid the (0,0,0) vector.

Now we're here:

vect3 perp1=normal.cross(vect3(1;0;0);
if (perp1.dot(perp1)<0.3f) perp1=normal.cross(vect3(0;1;0);
perp1.normalize();
unit length is guaranteed, orientation still undefined (at least is perpendicular to the normal) http://www.opengl.org/discussion_boards/ubb/wink.gif

[This message has been greatly improved by Furrage's corrections http://www.opengl.org/discussion_boards/ubb/wink.gif]

[This message has been edited by zeckensack (edited 03-07-2002).]

Furrage
03-07-2002, 05:13 AM
Originally posted by zeckensack:
To recap, I suggested doing N x (1;0;0) because the cross product of two unit length vectors is another unit length vector perpendicular to both N and (1;0;0) ... or it may be (0;0;0) which is per the mathematical definition perpendicular to all 3d vectors. But of course you can't do anything with it in graphics.

Not true. The cross product of two unit vectors is a unit vector only when the first two vectors are perpendicular.The result's length is always related to the sine of the angle between the two vectors. More accurately...

|AxB| = |A&#0124; &#0124;B|sin(Theta)

where |AxB| is the length of A cross B, |A| is the length of vector A, |B| is the length of vector B, and Theta is the angle between vectors A and B.

PS. For those who aren't sure a unit vector has length 1 unit.

zeckensack
03-07-2002, 05:31 AM
Yeah, you're right, Furrage! Sorry for posting this dumb stuff, silly me. I'll correct some of that nonsense right away.