home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
RISC DISC 3
/
RISC_DISC_3.iso
/
resources
/
etexts
/
gems
/
gemsv
/
ch5_5
/
voronoi.cxx
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-04
|
9KB
|
181 lines
#include <iostream.h>
#include <math.h>
#include "global.h"
#include "voronoi.h" // D-DIM. VORONOI TEMPLATE
struct cell : public VECTOR<3> { // 3-DIMENSIONAL VORONOI-CELL
vector p; // POSITION OF PARTICLE
list<cell*> ln; // CONTIGUOUS CELLS
list<object*> lh; // HOST OBJECT(S)
list<object*> lo; // LIST OF INTERSECTING OBJECTS
long t; // LOCAL TRAVERSE CODE (WORK)
cell *b; // BACK (voronoi::disperse)
cell() {t=0L;}
cell(vector& v, object *o=(object*)0) {
double x[3]; x[0]=v[0]; x[1]=v[1]; x[2]=v[2];
*((VECTOR<3>*)this)=VECTOR<3>(x); p=v; {if(o)lh+=o;} t=0L;
}
int operator&(vector& p) { // CELL CONTAINS POINT p
for(cell*n=ln.first();n;n=ln.next())
if(!(halfspace(this->p,n->p)&p)) return 0;
return 1;
}
int operator&(object& o) { // CELL INTERSECTS OBJECT o
for(cell*n=ln.first();n;n=ln.next())
if(!(o&halfspace(this->p,n->p))) return 0;
return 1;
}
};
// GLOBAL METHODS (NOT REALLY AN OBJECT ORIENTED APPROACH!)
static void initcells(VERTEX<3>*v) { // VORONOI-CELLS FROM VORONOI<3>
for(register int i=0; i<3; i++) {
cell *ci=(cell*)(v->p[i]);
for(register int j=i+1; j<4; j++) {
cell *cj=(cell*)(v->p[j]);
if(!ci->ln[cj]) ci->ln+=cj;
if(!cj->ln[ci]) cj->ln+=ci;
}
}
}
static int lexcmp(const void *v1, const void *v2) {
cell *c1=*(cell**)v1; cell *c2=*(cell**)v2;
const double EPS=1e-6;
for(register int i=0; i<3; i++) {
double d=(*c1)[i]-(*c2)[i];
if(d<-EPS) return -1;
if(d>EPS) return 1;
}
return 0;
}
// METHODS OF class voronoi
void voronoi::disperse(object *o, cell *C) {
traverse++;
if(traverse==-1L) { // OVERFLOW
traverse=-3L; disperse((object*)0,C); // REINITIALIZE
traverse=0L;
}
cell *c=C; c->b=(cell*)0; // PARTICULAR CASE
cell *n=c->ln.first(); // ACTUAL NEIGHBOR
register int back=0; // DON'T STEP BACK YET
for(;;) { // ITERATIVE TRAVERSE
c->t=traverse; // MARK AS TRAVERSED
register int go=0; // DON'T GO YET
do { // ACTION ON ACTUAL c
if(back) { // STEP BACKWARDS
cell *b=c->b; // FROM WHERE WE CAME
if(o) c->lo+=o; // PERFORM ACTION
c=b; back=0; continue; // TAKE BACK CELL
}
if(n==c->b) continue; // DON'T STEP BACK YET
if(n->t==traverse) continue; // ALREADY TRAVERSED
if(o && !(*n&(*o))) continue; // PARTIAL TRAVERSE
go=1; break; // GO ON
} while(n=c->ln.next()); // UNTIL NOT ALL DONE
if(go) { // STEP FORWARDS
n->b=c; // ESTABLISH BACK LINK
c=n; n=c->ln.first(); continue; // LET'S GO AHEAD
}
if(c==C) break; // RETURNED
back=1; // GO BACK IF NO BETTER
}
if(o) C->lo+=o; C->t=traverse; // C IS THE LAST ONE
}
void voronoi::preprocess(list<object*> *lo) { // PREPROCESSING
list<cell*> *lc=new list<cell*>;
register int n=0;
for(object* o=lo->first(); o; o=lo->next()) { // OBJECTS
list<vector*> *lp=o->particles();
for(vector* p=lp->first(); p; p=lp->next())
{(*lc)+=new cell(*p,o); n++; delete p;}
delete lp;
}
for(o=lightsources.first(); o; o=lightsources.next()) { // LIGHTSRC.S
list<vector*> *lp=o->particles();
for(vector* p=lp->first(); p; p=lp->next())
{(*lc)+=new cell(*p); n++; delete p;}
delete lp;
}
(*lc)+=new cell(actcamera.getray(0.,0.).o); n++; // EYE
cell **C=new cell*[n];
n=0;
for(cell* c=lc->first(); c; c=lc->next()) C[n++]=c;
delete lc;
qsort((void*)C, (size_t)n, sizeof(cell*), lexcmp); // LEXICOGRAPHIC
list<VECTOR<3>*> *lv=new list<VECTOR<3>*>;
(*lv)+=C[0]; cell* p=C[0];
vector cm=C[0]->p; // CENTER OF MASS
for(register int i=1; i<n; i++) {
cm=cm+C[i]->p;
if(lexcmp((const void**)&C[i], // MULTIPLE PARTICLE
(const void**)&p)==0) {
for(o=C[i]->lh.first(); o; o=C[i]->lh.next())
p->lh+=o;
delete C[i];
} else {(*lv)+=C[i]; p=C[i];} // SINGLE (YET)
}
cm=cm/(double)n; // CENTER OF MASS
delete C;
VECTOR<3>*b[4]; for(i=0;i<4;i++) b[i]=new cell; // BOUNDARY CELLS
VORONOI<3> V(lv,b); // VERTEX STRUCTURE
for(i=0;i<4;i++) { // BOUNDARY CELLS
cell* c=(cell*)b[i];
c->p=vector((*c)[0],(*c)[1],(*c)[2]); // UPDATE
}
V(initcells); // 3D VORONOI-CELLS
traverse=0L; // INITIALIZE disperse
double ddmin; register int first=1; // INITIALIZE SEARCH
for(c=(cell*)lv->first();c;c=(cell*)lv->next()) {
for(o=c->lh.first();o;o=c->lh.next()) // BUILD OBJECT LISTS
disperse(o,c); // PARTIAL TRAVERSE
vector u=c->p-cm; double dd=u%u; // DISTANCE^2 FROM cm
if(first || dd<ddmin) // FIND CLOSEST TO cm
{ddmin=dd;this->C=c;}
first=0;
}
n=1<<(lmax+1);
s=new cell*[n]; for(i=0;i<n;i++) s[i]=this->C; // START FOR firstlist
delete lv; // ???
}
void voronoi::step() { // ONE STEP ALONG RAY r
double tmin=0.; cell* nmin=(cell*)0; // INITIALIZE SEARCH
for(cell*n=a->ln.first(); n; n=a->ln.next()) { // NEIGHBORING CELLS
vector u=n->p-a->p; // NORMAL OF BISECTOR
double d=r->d%u; // DENOMINATOR
if(fabs(d)<EPS) continue; // PARALLEL FACE
vector v=(n->p+a->p)*.5-r->o;
double t=(v%u)/d; // t AT INTERSECTION
if(t<=this->t) continue; // WOULD BE A BACK STEP
if(t<EPS) // r->o ON BISECTOR PL.
if(u%r->d>0.) {tmin=EPS; nmin=n; continue;}
else continue;
if(!tmin || t<tmin) {tmin=t; nmin=n;} // CLOSER INTERSECTION
}
this->t=tmin; a=nmin;
}
list<object*>* voronoi::firstlist(ray& r) {
register int i=r.c>=0?r.c:(1<<(lmax+1))-1; // INDEX INTO s
a=s[i]; // INITIALIZE step()
if(!((*a)&r.o)) { // COHERENCE FAILED
ray R(a->p,norm(r.o-a->p),0,0); // PATH OF WALK
this->r=&R; t=0.; // INITIALIZE step()
for(step(); a; step()) // WALK
if((*a)&r.o) {s[i]=a; break;} // SUCCESS
}
this->r=&r; t=0.; // INITIALIZE step()
return a?&a->lo:(list<object*>*)0;
}
list<object*>* voronoi::nextlist() {
step(); // ONE STEP
return a?&a->lo:(list<object*>*)0; // SUCCESS OR FAIL
}