#include <math.h>
#include "GraphicsGems.h"
/* ---- inttor - Intersect a ray with a torus. ------------------------ */
/* */
/* */
/* Description: */
/* Inttor determines the intersection of a ray with a torus. */
/* */
/* On entry: */
/* raybase = The coordinate defining the base of the */
/* intersecting ray. */
/* raycos = The direction cosines of the above ray. */
/* center = The center location of the torus. */
/* radius = The major radius of the torus. */
/* rplane = The minor radius in the plane of the torus. */
/* rnorm = The minor radius normal to the plane of the torus.*/
/* tran = A 4x4 transformation matrix that will position */
/* the torus at the origin and orient it such that */
/* the plane of the torus lyes in the x-z plane. */
/* */
/* On return: */
/* nhits = The number of intersections the ray makes with */
/* the torus. */
/* rhits = The entering/leaving distances of the */
/* intersections. */
/* */
/* Returns: True if the ray intersects the torus. */
/* */
/* -------------------------------------------------------------------- */
int inttor (raybase,raycos,center,radius,rplane,rnorm,tran,nhits,rhits)
Point3 raybase; /* Base of the intersection ray */
Vector3 raycos; /* Direction cosines of the ray */
Point3 center; /* Center of the torus */
double radius; /* Major radius of the torus */
double rplane; /* Minor planer radius */
double rnorm; /* Minor normal radius */
Matrix4 tran; /* Transformation matrix */
int * nhits; /* Number of intersections */
double rhits[4]; /* Intersection distances */
{
int hit; /* True if ray intersects torus */
double rsphere; /* Bounding sphere radius */
Vector3 Base, Dcos; /* Transformed intersection ray */
double rmin, rmax; /* Root bounds */
double yin, yout;
double rho, a0, b0; /* Related constants */
double f, l, t, g, q, m, u; /* Ray dependent terms */
double C[5]; /* Quartic coefficients */
extern int intsph (); /* Intersect ray with sphere */
extern int SolveQuartic (); /* Solve quartic equation */
*nhits = 0;
/* Compute the intersection of the ray with a bounding sphere. */
rsphere = radius + MAX (rplane,rnorm);
hit = intsph (raybase,raycos,center,rsphere,&rmin,&rmax);
if (!hit) return (hit); /* If ray misses bounding sphere*/
/* Transform the intersection ray */
Base = raybase;
Dcos = raycos;
V3MulPointByMatrix (&Base,&tran);
V3MulVectorByMatrix (&Dcos,&tran);
/* Bound the torus by two parallel planes rnorm from the x-z plane.*/
yin = Base.y + rmin * Dcos.y;
yout = Base.y + rmax * Dcos.y;
hit = !( (yin > rnorm && yout > rnorm) ||
(yin < -rnorm && yout < -rnorm) );
if (!hit) return (hit); /* If ray is above/below torus. */
/* Compute constants related to the torus. */
rho = rplane*rplane / (rnorm*rnorm);
a0 = 4. * radius*radius;
b0 = radius*radius - rplane*rplane;
/* Compute ray dependent terms. */
f = 1. - Dcos.y*Dcos.y;
l = 2. * (Base.x*Dcos.x + Base.z*Dcos.z);
t = Base.x*Base.x + Base.z*Base.z;
g = f + rho * Dcos.y*Dcos.y;
q = a0 / (g*g);
m = (l + 2.*rho*Dcos.y*Base.y) / g;
u = (t + rho*Base.y*Base.y + b0) / g;
/* Compute the coefficients of the quartic. */
C[4] = 1.0;
C[3] = 2. * m;
C[2] = m*m + 2.*u - q*f;
C[1] = 2.*m*u - q*l;
C[0] = u*u - q*t;
/* Use quartic root solver found in "Graphics Gems" by Jochen */
/* Schwarze. */
*nhits = SolveQuartic (C,rhits);
/* SolveQuartic returns root pairs in reversed order. */
m = rhits[0]; u = rhits[1]; rhits[0] = u; rhits[1] = m;
m = rhits[2]; u = rhits[3]; rhits[2] = u; rhits[3] = m;
return (*nhits != 0);
}
Personally, I get a lot of satisfaction building one myself. However, the enormous amount of time it takes certainly would justify a command. How you could actually implement it with less complexity than piloting a fighter jet, I don't know.
<FCB2> trevbev94: who made the perimid out of saind cause that is ausom
<FCB2> Pemalite+: druffin. 'cmere big boy for some lovin'
The user places two blocks just like cuboid, and the command does this:
1. uses ellipsoid command to make a circle along the xy-plane from x1,y1,(z1+z2)/2 to x2,y2,(z1+z2)/2
2. draws spheres from EVERY point on the circle with radius z1-[(z1+z2)/2]
3. This should approximate a torus pretty well, I'm going to test it
EDIT: And Bloody_Llama, I would love to build a torus myself using this method, but the lame builders spamming spheres took sphere away from all builders.
Last edited by M1_Abrams on September 1st, 2011, 3:07 am, edited 1 time in total.
"A ship in a harbor is safe, but that’s not what ships are for."
--William Shedd
Good luck making a hollow one like that
Also, don't you have to define how big the center is, and how steep (I'm sure there is a better word for that)?
And if we're going to call it a torus, shouldn't it allow more irregular shapes? Torus's aren't all perfectly circular. (LOL @ circles in a game made of cubes)
edit: M1_Abrams if you want to test out this shit, download fCraft and start up a local server on your machine, where you can use any command to your hearts content.
Last edited by Bloody_Llama on September 1st, 2011, 3:11 am, edited 1 time in total.
<FCB2> trevbev94: who made the perimid out of saind cause that is ausom
<FCB2> Pemalite+: druffin. 'cmere big boy for some lovin'
Rotating a sphere around an axis would work, BUT there are a couple performance constraints to overcome before this will be practical:
All draw operations are applied incrementally, and must preserve their state between batches. This is optimally solved with a state machine such as the current /ehx implementation. If that ends up being too difficult (as it very well might), I'd have to fall back to creating an iterator block. That adds some overhead though.
All draw operations must touch any given coordinate at least once. If a block is touched twice, /undo information will be lost for that coordinate. It would also be extremely inefficient to revisit each block dozens or even hundreds of times with consecutive sphere commands. I've dealt with this limitation so far by making all drawing operations work linearly. Another solution would be to keep a list of modified coordinates, like a HashSet of resolved block array indices. But that would add a lot of memory and CPU overhead, and would not scale well - checking for duplicate coordinates will become O(n^2).
Well another method would be to draw that axis in the picture above, then draw two perpendicular rings around it, and then draw a bunch of circles (not as many as the sphere idea!) parallel to the axis that contain the points on the two rings.
EDIT: Nevermind, I failed.
"A ship in a harbor is safe, but that’s not what ships are for."
--William Shedd
I would suggest an implementation that goes in slices along the z axis (top-down) like so:
Each slice will have blocks between two circles - inner and outer. The radius of those circles can be figured out with a simple equation. Now all you have to do is go through each voxel within a slice and check if it's contained between those circles. Tada.
Like I said earlier, I don't plan on implementing this myself. But if someone else wants to volunteer, go ahead, I'll include your code when you're done.
Now I just have to finish making the callback and figure out where the user should set the blocks and it's good to go! (Hopefully)
Also I have to program the Logger and the undo-er thing. Woohoo!
"A ship in a harbor is safe, but that’s not what ships are for."
--William Shedd
doberman411: I now know that I feel a bit of relief every time the landing gear of my plane lifts off of the runway knowing that I'm one step closer to freedom.