home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
gondwana.ecr.mu.oz.au/pub/
/
Graphics.tar
/
Graphics
/
sphere.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-07-08
|
7KB
|
307 lines
/*% cc -g sphere.c -o sphere -lm
*
* sphere - generate a triangle mesh approximating a sphere by
* recursive subdivision. First approximation is an octahedron;
* each level of refinement increases the number of triangles by
* a factor of 4.
* Level 3 (128 triangles) is a good tradeoff if gouraud
* shading is used to render the database.
*
* Usage: sphere [level] [-p] [-c]
* level is an integer >= 1 setting the recursion level (default 1).
* -p causes generation of a PPHIGS format ASCII archive
* instead of the default generic output format.
* -c causes triangles to be generated with vertices in counterclockwise
* order as viewed from the outside in a RHS coordinate system.
* The default is clockwise order.
*
* The subroutines print_object() and print_triangle() should
* be changed to generate whatever the desired database format is.
*
* Jon Leech (leech@cs.unc.edu) 3/24/89
*/
#include <stdio.h>
#include <math.h>
typedef struct {
double x, y, z;
} point;
typedef struct {
point pt[3]; /* Vertices of triangle */
double area; /* Unused; might be used for adaptive subdivision */
} triangle;
typedef struct {
int npoly; /* # of triangles in object */
triangle *poly; /* Triangles */
} object;
/* Six equidistant points lying on the unit sphere */
#define XPLUS { 1, 0, 0 } /* X */
#define XMIN { -1, 0, 0 } /* -X */
#define YPLUS { 0, 1, 0 } /* Y */
#define YMIN { 0, -1, 0 } /* -Y */
#define ZPLUS { 0, 0, 1 } /* Z */
#define ZMIN { 0, 0, -1 } /* -Z */
/* Vertices of a unit octahedron */
triangle octahedron[] = {
{ { XPLUS, ZPLUS, YPLUS }, 0.0 },
{ { YPLUS, ZPLUS, XMIN }, 0.0 },
{ { XMIN , ZPLUS, YMIN }, 0.0 },
{ { YMIN , ZPLUS, XPLUS }, 0.0 },
{ { XPLUS, YPLUS, ZMIN }, 0.0 },
{ { YPLUS, XMIN , ZMIN }, 0.0 },
{ { XMIN , YMIN , ZMIN }, 0.0 },
{ { YMIN , XPLUS, ZMIN }, 0.0 }
};
/* A unit octahedron */
object oct = {
sizeof(octahedron) / sizeof(octahedron[0]),
&octahedron[0]
};
int PPHIGSflag = 0;
/* Forward declarations */
point *normalize(/* point *p */);
point *midpoint(/* point *a, point *b */);
void print_object(/* object *obj, int level */);
void print_triangle(/* triangle *t */);
void pphigs_header(/* int */);
void pphigs_trailer();
extern char *malloc(/* unsigned */);
main(ac, av)
int ac;
char *av[];
{
object *old,
*new;
int ccwflag = 0, /* Reverse vertex order if true */
i,
level, /* Current subdivision level */
maxlevel = 1; /* Maximum subdivision level */
/* Parse arguments */
for (i = 1; i < ac; i++) {
if (!strcmp(av[i], "-p"))
PPHIGSflag = 1;
else if (!strcmp(av[i], "-c"))
ccwflag = 1;
else if ((maxlevel = atoi(av[i])) < 1) {
fprintf(stderr, "%s: # of levels must be >= 1\n", av[0]);
exit(1);
}
}
if (ccwflag) {
/* Reverse order of points in each triangle */
for (i = 0; i < oct.npoly; i++) {
point tmp;
tmp = oct.poly[i].pt[0];
oct.poly[i].pt[0] = oct.poly[i].pt[2];
oct.poly[i].pt[2] = tmp;
}
}
old = &oct;
/* Subdivide each starting triangle (maxlevel - 1) times */
for (level = 1; level < maxlevel; level++) {
/* Allocate a new object */
new = (object *)malloc(sizeof(object));
if (new == NULL) {
fprintf(stderr, "%s: Out of memory on subdivision level %d\n",
av[0], level);
exit(1);
}
new->npoly = old->npoly * 4;
/* Allocate 4* the number of points in the current approximation */
new->poly = (triangle *)malloc(new->npoly * sizeof(triangle));
if (new->poly == NULL) {
fprintf(stderr, "%s: Out of memory on subdivision level %d\n",
av[0], level);
exit(1);
}
/* Subdivide each triangle in the old approximation and normalize
* the new points thus generated to lie on the surface of the unit
* sphere.
* Each input triangle with vertices labelled [0,1,2] as shown
* below will be turned into four new triangles:
*
* Make new points
* a = (0+2)/2
* b = (0+1)/2
* c = (1+2)/2
* 1
* /\ Normalize a, b, c
* / \
* b/____\ c Construct new triangles
* /\ /\ [0,b,a]
* / \ / \ [b,1,c]
* /____\/____\ [a,b,c]
* 0 a 2 [a,c,2]
*/
for (i = 0; i < old->npoly; i++) {
triangle
*oldt = &old->poly[i],
*newt = &new->poly[i*4];
point a, b, c;
a = *normalize(midpoint(&oldt->pt[0], &oldt->pt[2]));
b = *normalize(midpoint(&oldt->pt[0], &oldt->pt[1]));
c = *normalize(midpoint(&oldt->pt[1], &oldt->pt[2]));
newt->pt[0] = oldt->pt[0];
newt->pt[1] = b;
newt->pt[2] = a;
newt++;
newt->pt[0] = b;
newt->pt[1] = oldt->pt[1];
newt->pt[2] = c;
newt++;
newt->pt[0] = a;
newt->pt[1] = b;
newt->pt[2] = c;
newt++;
newt->pt[0] = a;
newt->pt[1] = c;
newt->pt[2] = oldt->pt[2];
}
if (level > 1) {
free(old->poly);
free(old);
}
/* Continue subdividing new triangles */
old = new;
}
/* Print out resulting approximation */
print_object(old, maxlevel);
}
/* Normalize a point p */
point *normalize(p)
point *p;
{
static point r;
double mag;
r = *p;
mag = r.x * r.x + r.y * r.y + r.z * r.z;
if (mag != 0.0) {
mag = 1.0 / sqrt(mag);
r.x *= mag;
r.y *= mag;
r.z *= mag;
}
return &r;
}
/* Return the midpoint on the line between two points */
point *midpoint(a, b)
point *a, *b;
{
static point r;
r.x = (a->x + b->x) * 0.5;
r.y = (a->y + b->y) * 0.5;
r.z = (a->z + b->z) * 0.5;
return &r;
}
/* Write out all triangles in an object */
void print_object(obj, level)
object *obj;
int level;
{
int i;
if (PPHIGSflag)
pphigs_header(level);
/* Spit out coordinates for each triangle */
for (i = 0; i < obj->npoly; i++)
print_triangle(&obj->poly[i]);
if (PPHIGSflag)
pphigs_trailer();
}
/* Output a triangle */
void print_triangle(t)
triangle *t;
{
int i;
if (PPHIGSflag) {
printf("\tpolygon 3 {\n");
for (i = 0; i < 3; i++)
printf("\t\t%g\t%g\t%g %g\t%g\t%g ;\n",
t->pt[i].x, t->pt[i].y, t->pt[i].z, /* Point */
t->pt[i].x, t->pt[i].y, t->pt[i].z); /* Normal */
printf("\t};\n");
} else {
/* Modify this to generate your favorite output format
* Triangle vertices are in t->pt[0..2].{x,y,z}
* A generic format is provided.
*/
printf("triangle\n");
for (i = 0; i < 3; i++)
printf("\t%g %g %g\n", t->pt[i].x, t->pt[i].y, t->pt[i].z);
}
}
/* Generate header for a PPHIGS ASCII archive */
void pphigs_header(level)
int level;
{
int dx, dy, dz;
printf("structure sphere%d posted {\n", level);
printf("\tcolor polygon {\n");
printf("\t\t200 100 50 0 50 100 200 0\n");
printf("\t};\n");
switch (level) {
case 1:
dx = -2000; dy = 2000; dz = 0;
break;
case 2:
dx = 2000; dy = 2000; dz = 0;
break;
case 3:
dx = -2000; dy = -2000; dz = 0;
break;
case 4:
dx = 2000; dy = -2000; dz = 0;
break;
case 5:
dx = 0; dy = 0; dz = 0;
break;
default:
dx = dy = dz = 0;
break;
}
printf("\tmatrix Pre scale 1000 1000 1000;\n");
printf("\tmatrix Pre translate %d %d %d ;\n", dx, dy, dz);
}
void pphigs_trailer() {
printf("};\n");
}