home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
RISC DISC 3
/
RISC_DISC_3.iso
/
resources
/
etexts
/
gems
/
gemsv
/
ch4_5
/
ellipsoid.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-04-04
|
10KB
|
291 lines
/* ellipsoid.c */
#include <stdio.h>
#include <math.h>
#include <malloc.h>
#include "ellipsoid.h"
#ifndef M_PI_2
#define M_PI_2 1.57079632679489661923
#endif
typedef struct slot { float cos, sin; enum { None, Only, Done } flag; } slot;
static int n_max = 0; /* current maximum degree of subdivision */
static slot *table = NULL; /* an array of slots */
static vertex *octant = NULL; /* the base octant of the ellipsoid */
#define SetP(p,px,py,pz) (p).x=(px), (p).y=(py), (p).z=(pz)
#define SetV(v,px,py,pz,nx,ny,nz) SetP((v)->p,px,py,pz), SetP((v)->n,nx,ny,nz)
#define SetF(f,i0,i1,i2) (f)->v0 = i0, (f)->v1 = i1, (f)->v2 = i2
/*
// Compute the necessary cosine and sine values for generating ellipsoids
// with the degree of subdivision n, and initialize the array table[].
// The largest n becomes n_max, and calls with n <= n_max return immediately.
// The memory for the base octant is allocated to cope with any n <= n_max.
*/
void ellipsoid_init (int n)
{
int n_table, i, j, k, l, m, h, d;
slot *t0, *t1, *t2;
float theta;
if (n > n_max) {
n_max = n;
if (table) free (table);
if ((n_table = ((n-1)*n)/2) == 0) table = NULL;
else table = (slot *) malloc (n_table * sizeof(slot));
if (octant) free (octant);
octant = (vertex *) malloc (((n+1)*(n+2))/2 * sizeof(vertex));
for (t0 = table, k = n_table; k > 0; k--, t0++) t0->flag = None;
for (t0 = table, k = 0, l = 1, m = 3, i = 2; i <= n_max; i++) {
l += m, m += 2, h = n_max / i - 1;
for (t1 = t0+i - 2, j = 1; j < i; j++, k++, t0++, t1--) {
if (t0->flag == None) {
theta = (M_PI_2 * j) / i;
t0->cos = t1->sin = cos (theta);
t0->sin = t1->cos = sin (theta);
t0->flag = t1->flag = Only;
}
if (t0->flag == Only) {
t0->flag = Done;
for (d = k+l, t2 = t0; h > 0; h--) {
t2 += d, d += l;
t2->cos = t0->cos;
t2->sin = t0->sin;
t2->flag = Done;
}
}
}
}
}
}
/*
// Construct the base octant of the ellipsoid whose parameters are a, b, and c,
// with the degree of subdivision n using the cosine and sine values in table[].
// It is assumed that n <= n_max.
*/
static void ellipsoid_octant (int n, float a, float b, float c)
{
int i, j;
float a_1, b_1, c_1;
float cos_ph, sin_ph, px, py, pz, nx, ny, nz, nznz, rnorm, tmp;
vertex *o = octant;
slot *table_th, *table_ph;
a_1 = 1.0 / a; b_1 = 1.0 / b; c_1 = 1.0 / c;
o = octant;
table_th = table;
table_ph = table + ((n-1)*(n-2))/2;
SetV (o, 0.0, 0.0, c, 0.0, 0.0, 1.0), o++; /* i = 0, j = 0 */
for (i = 1; i < n; i++, table_ph++) {
cos_ph = table_ph->cos;
sin_ph = table_ph->sin;
pz = cos_ph * c;
nz = cos_ph * c_1;
nznz = nz * nz;
px = sin_ph * a;
nx = sin_ph * a_1;
rnorm = 1.0 / sqrt (nx*nx + nznz); /* 0 < i < n, j = 0 */
SetV (o, px, 0.0, pz, nx*rnorm, 0.0, nz*rnorm), o++;
for (j = i; --j > 0; table_th++) {
tmp = table_th->cos * sin_ph;
px = tmp * a;
nx = tmp * a_1;
tmp = table_th->sin * sin_ph;
py = tmp * b;
ny = tmp * b_1;
rnorm = 1.0 / sqrt (nx*nx + ny*ny + nznz); /* 0 < i < n, 0 < j < i */
SetV (o, px, py, pz, nx*rnorm, ny*rnorm, nz*rnorm), o++;
}
py = sin_ph * b;
ny = sin_ph * b_1;
rnorm = 1.0 / sqrt (ny*ny + nznz); /* 0 < i < n, j = i */
SetV (o, 0.0, py, pz, 0.0, ny*rnorm, nz*rnorm), o++;
}
SetV (o, a, 0.0, 0.0, 1.0, 0.0, 0.0), o++; /* i = n, j = 0 */
for (j = i; --j > 0; table_th++) {
tmp = table_th->cos;
px = tmp * a;
nx = tmp * a_1;
tmp = table_th->sin;
py = tmp * b;
ny = tmp * b_1;
rnorm = 1.0 / sqrt (nx*nx + ny*ny); /* i = n, 0 < j < i */
SetV (o, px, py, 0.0, nx*rnorm, ny*rnorm, 0.0), o++;
}
SetV (o, 0.0, b, 0.0, 0.0, 1.0, 0.0); /* i = n, j = i */
}
/*
// Note the following conventions in ellipsoid_seq() and ellipsoid_par():
// the north pole: th = 0, ph = 0,
// the 1st octant: 0 <= th < 90, 0 < ph <= 90,
// the 2nd octant: 90 <= th < 180, 0 < ph <= 90,
// the 3rd octant: 180 <= th < 270, 0 < ph <= 90,
// the 4th octant: 270 <= th < 360, 0 < ph <= 90,
// the 5th octant: 0 <= th < 90, 90 < ph <= 180,
// the 6th octant: 90 <= th < 180, 90 < ph <= 180,
// the 7th octant: 180 <= th < 270, 90 < ph <= 180,
// the 8th octant: 270 <= th < 360, 90 < ph <= 180, and
// the south pole: th = 0, ph = 180.
*/
/*
// Generate the vertices fot the ellipsoid with parameters a, b, and c
// with the degree of subdivision n, by reflecting the base octant.
// Also generate triangular faces of the ellipsoid with vertices ordered
// counterclockwise when viewed from the outside.
*/
/* sequential version */
void ellipsoid_seq (object *ellipsoid, int n, float a, float b, float c)
{
vertex *v, *o;
face *f;
int i, j, ko, kv, kw, kv0, kw0;
/* Check parameters for validity. */
if (n <= 0 || n_max < n || a <= 0.0 || b <= 0.0 || c <= 0.0) {
ellipsoid->nv = 0; ellipsoid->v = NULL;
ellipsoid->nf = 0; ellipsoid->f = NULL;
return;
}
/* Initialize the base octant. */
ellipsoid_octant (n, a, b, c);
/* Allocate memories for vertices and faces. */
ellipsoid->nv = 4*n*n + 2;
ellipsoid->nf = 8*n*n;
ellipsoid->v = (vertex *) malloc (ellipsoid->nv * sizeof(vertex));
ellipsoid->f = (face *) malloc (ellipsoid->nf * sizeof(face));
/* Generate vertices of the ellipsoid from octant[]. */
v = ellipsoid->v;
o = octant;
#define op o->p
#define on o->n
SetV (v, op.x, op.y, op.z, on.x, on.y, on.z), v++; /* the north pole */
for (i = 0; ++i <= n;) {
o += i;
for (j = i; --j >= 0; o++, v++) /* 1st octant */
SetV (v, op.x, op.y, op.z, on.x, on.y, on.z);
for (j = i; --j >= 0; o--, v++) /* 2nd octant */
SetV (v, -op.x, op.y, op.z, -on.x, on.y, on.z);
for (j = i; --j >= 0; o++, v++) /* 3rd octant */
SetV (v, -op.x, -op.y, op.z, -on.x, -on.y, on.z);
for (j = i; --j >= 0; o--, v++) /* 4th octant */
SetV (v, op.x, -op.y, op.z, on.x, -on.y, on.z);
}
for (; --i > 1;) {
o -= i;
for (j = i; --j > 0; o++, v++) /* 5th octant */
SetV (v, op.x, op.y, -op.z, on.x, on.y, -on.z);
for (j = i; --j > 0; o--, v++) /* 6th octant */
SetV (v, -op.x, op.y, -op.z, -on.x, on.y, -on.z);
for (j = i; --j > 0; o++, v++) /* 7th octant */
SetV (v, -op.x, -op.y, -op.z, -on.x, -on.y, -on.z);
for (j = i; --j > 0; o--, v++) /* 8th octant */
SetV (v, op.x, -op.y, -op.z, on.x, -on.y, -on.z);
}
o--, SetV (v, -op.x, -op.y, -op.z, -on.x, -on.y, -on.z); /* the south pole */
#undef op
#undef on
/* Generate triangular faces of the ellipsoid. */
f = ellipsoid->f;
kv = 0, kw = 1;
for (i = 0; i < n; i++) {
kv0 = kv, kw0 = kw;
for (ko = 1; ko <= 3; ko++) /* the 1st, 2nd, 3rd octants */
for (j = i;; j--) {
SetF (f, kv, kw, ++kw), f++;
if (j == 0) break;
SetF (f, kv, kw, ++kv), f++;
}
for (j = i;; j--) { /* the 4th octant */
if (j == 0) { SetF (f, kv0, kw, kw0), kv++, kw++, f++; break; }
SetF (f, kv, kw, ++kw), f++;
if (j == 1) SetF (f, kv, kw, kv0), f++;
else SetF (f, kv, kw, ++kv), f++;
}
}
for (; --i >= 0;) {
kv0 = kv, kw0 = kw;
for (ko = 5; ko <= 7; ko++) /* the 5th, 6th, 7th octants */
for (j = i;; j--) {
SetF (f, kv, kw, ++kv), f++;
if (j == 0) break;
SetF (f, kv, kw, ++kw), f++;
}
for (j = i;; j--) { /* the 8th octant */
if (j == 0) { SetF (f, kv, kw0, kv0), kv++, kw++, f++; break; }
SetF (f, kv, kw, ++kv), f++;
if (j == 1) SetF (f, kv, kw, kw0), f++;
else SetF (f, kv, kw, ++kw), f++;
}
}
}
/* parallel version */
void ellipsoid_par (object *ellipsoid, int n, float a, float b, float c)
{
int nv, nf;
vertex *ev;
face *ef;
/* Check parameters for validity. */
if (n <= 0 || n_max < n || a <= 0.0 || b <= 0.0 || c <= 0.0) {
ellipsoid->nv = 0; ellipsoid->v = NULL;
ellipsoid->nf = 0; ellipsoid->f = NULL;
return;
}
/* Initialize the base octant. */
ellipsoid_octant (n, a, b, c);
/* Allocate memories for vertices and faces. */
nv = ellipsoid->nv = 4*n*n + 2;
nf = ellipsoid->nf = 8*n*n;
ev = ellipsoid->v = (vertex *) malloc (nv * sizeof(vertex));
ef = ellipsoid->f = (face *) malloc (nf * sizeof(face));
ellipsoid_par_help (n, nv, nf, ev, ef, octant);
}
/* A utility function that simply outputs the ellipsoid data. */
void ellipsoid_print (object *ellipsoid)
{
int i;
vertex *v;
face *f;
for (v = ellipsoid->v, i = 0; i < ellipsoid->nv; i++, v++)
printf ("v %g %g %g %g %g %g\n",
v->p.x, v->p.y, v->p.z, v->n.x, v->n.y, v->n.z);
for (f = ellipsoid->f, i = 0; i < ellipsoid->nf; i++, f++)
printf ("f %d %d %d\n", f->v0, f->v1, f->v2);
}
/* undo of ellipsoid_init () */
void ellipsoid_done (void)
{
n_max = 0;
if (table) free (table), table = NULL;
if (octant) free (octant), octant = NULL;
}
/* undo of ellipsoid_seq () */
void ellipsoid_free (object *ellipsoid)
{
free (ellipsoid->v), ellipsoid->nv = 0, ellipsoid->v = NULL;
free (ellipsoid->f), ellipsoid->nf = 0, ellipsoid->f = NULL;
}