#ifndef lint static const char RCSid[] = "$Id: sm_qtree.c,v 3.17 2003/06/30 14:59:12 schorsch Exp $"; #endif /* * sm_qtree.c: adapted from octree.c from radiance code */ /* * octree.c - routines dealing with octrees and cubes. * * 7/28/85 */ #include #include "standard.h" #include "sm_flag.h" #include "sm_geom.h" #include "object.h" #include "sm_qtree.h" QUADTREE *quad_block[QT_MAX_BLK]; /* our quadtree */ static QUADTREE quad_free_list = EMPTY; /* freed octree nodes */ static QUADTREE treetop = 0; /* next free node */ int32 *quad_flag= NULL; /* quadtree flags */ qtremovelast(qt,id) QUADTREE qt; OBJECT id; { #ifdef DEBUG if(qtqueryset(qt)[(*(qtqueryset(qt)))] != id) error(CONSISTENCY,"not removed\n"); #endif ((*(qtqueryset(qt)))--); } QUADTREE qtAlloc() /* allocate a quadtree */ { register QUADTREE freet; if ((freet = quad_free_list) != EMPTY) { quad_free_list = QT_NTH_CHILD(freet, 0); return(freet); } freet = treetop; if (QT_BLOCK_INDEX(freet) == 0) { if (QT_BLOCK(freet) >= QT_MAX_BLK) return(EMPTY); if ((quad_block[QT_BLOCK(freet)] = (QUADTREE *)malloc( QT_BLOCK_SIZE*4*sizeof(QUADTREE))) == NULL) error(SYSTEM,"qtAlloc(): Unable to allocate memory\n"); /* Realloc the per/node flags */ quad_flag = (int32 *)realloc((void *)quad_flag, (QT_BLOCK(freet)+1)*((QT_BLOCK_SIZE+7)>>3)); if (quad_flag == NULL) error(SYSTEM,"qtAlloc(): Unable to allocate memory\n"); } treetop += 4; return(freet); } qtClearAllFlags() /* clear all quadtree branch flags */ { if (!treetop) return; /* Clear the node flags*/ memset((char *)quad_flag, '\0', (QT_BLOCK(treetop-4)+1)*((QT_BLOCK_SIZE+7)>>3)); /* Clear set flags */ qtclearsetflags(); } qtFree(qt) /* free a quadtree */ register QUADTREE qt; { register int i; if (!QT_IS_TREE(qt)) { qtfreeleaf(qt); return; } for (i = 0; i < 4; i++) qtFree(QT_NTH_CHILD(qt, i)); QT_NTH_CHILD(qt, 0) = quad_free_list; quad_free_list = qt; } qtDone() /* free EVERYTHING */ { register int i; qtfreeleaves(); for (i = 0; i < QT_MAX_BLK; i++) { if (quad_block[i] == NULL) break; free((void *)quad_block[i]); quad_block[i] = NULL; } /* Free the flags */ if (i) free((void *)quad_flag); quad_flag = NULL; quad_free_list = EMPTY; treetop = 0; } /* * bary_parent(coord,i) : Set coord to be value of pt at one level up in * quadtree, given it was the ith child * BCOORD coord[3]; :barycentric coordinates of point, also will hold * result as side effect * int i; :designates which child coord was */ bary_parent(coord,i) BCOORD coord[3]; int i; { switch(i) { case 0: /* update bary for child */ coord[0] = (coord[0] >> 1) + MAXBCOORD4; coord[1] >>= 1; coord[2] >>= 1; break; case 1: coord[0] >>= 1; coord[1] = (coord[1] >> 1) + MAXBCOORD4; coord[2] >>= 1; break; case 2: coord[0] >>= 1; coord[1] >>= 1; coord[2] = (coord[2] >> 1) + MAXBCOORD4; break; case 3: coord[0] = MAXBCOORD4 - (coord[0] >> 1); coord[1] = MAXBCOORD4 - (coord[1] >> 1); coord[2] = MAXBCOORD4 - (coord[2] >> 1); break; #ifdef DEBUG default: eputs("bary_parent():Invalid child\n"); break; #endif } } /* * bary_from_child(coord,child,next): Given that coord was the (child) child * of the quadtree node, calculate what the (next) child * is at the same level. * BCOORD coord[3]; :At current level (child)th child of node,will also hold * result as side effect * int child,next; :Which child coord was (child), and which one * is now desired(next) */ bary_from_child(coord,child,next) BCOORD coord[3]; int child,next; { #ifdef DEBUG if(child <0 || child > 3) { eputs("bary_from_child():Invalid child\n"); return; } if(next <0 || next > 3) { eputs("bary_from_child():Invalid next\n"); return; } #endif if(next == child) return; switch(child){ case 0: coord[0] = 0; coord[1] = MAXBCOORD2 - coord[1]; coord[2] = MAXBCOORD2 - coord[2]; break; case 1: coord[0] = MAXBCOORD2 - coord[0]; coord[1] = 0; coord[2] = MAXBCOORD2 - coord[2]; break; case 2: coord[0] = MAXBCOORD2 - coord[0]; coord[1] = MAXBCOORD2 - coord[1]; coord[2] = 0; break; case 3: switch(next){ case 0: coord[0] = 0; coord[1] = MAXBCOORD2 - coord[1]; coord[2] = MAXBCOORD2 - coord[2]; break; case 1: coord[0] = MAXBCOORD2 - coord[0]; coord[1] = 0; coord[2] = MAXBCOORD2 - coord[2]; break; case 2: coord[0] = MAXBCOORD2 - coord[0]; coord[1] = MAXBCOORD2 - coord[1]; coord[2] = 0; break; } break; } } /* * int * bary_child(coord): Return which child coord is of node at current level * As side effect recalculate coord at next level * BCOORD coord[3]; :At current level coordinates of point, will also set * to coords at next level as side effect */ int bary_child(coord) BCOORD coord[3]; { int i; if(coord[0] > MAXBCOORD4) { /* update bary for child */ coord[0] = (coord[0]<< 1) - MAXBCOORD2; coord[1] <<= 1; coord[2] <<= 1; return(0); } else if(coord[1] > MAXBCOORD4) { coord[0] <<= 1; coord[1] = (coord[1] << 1) - MAXBCOORD2; coord[2] <<= 1; return(1); } else if(coord[2] > MAXBCOORD4) { coord[0] <<= 1; coord[1] <<= 1; coord[2] = (coord[2] << 1) - MAXBCOORD2; return(2); } else { coord[0] = MAXBCOORD2 - (coord[0] << 1); coord[1] = MAXBCOORD2 - (coord[1] << 1); coord[2] = MAXBCOORD2 - (coord[2] << 1); return(3); } } QUADTREE qtLocate(qt,bcoord) QUADTREE qt; BCOORD bcoord[3]; { int i; if(QT_IS_TREE(qt)) { i = bary_child(bcoord); return(qtLocate(QT_NTH_CHILD(qt,i),bcoord)); } else return(qt); } int move_to_nbr(b,db0,db1,db2,tptr) BCOORD b[3]; BDIR db0,db1,db2; double *tptr; { double t,dt; BCOORD bc; int nbr; nbr = -1; *tptr = 0.0; /* Advance to next node */ if(b[0]==0 && db0 < 0) return(0); if(b[1]==0 && db1 < 0) return(1); if(b[2]==0 && db2 < 0) return(2); if(db0 < 0) { t = ((double)b[0])/-db0; nbr = 0; } else t = MAXFLOAT; if(db1 < 0) { dt = ((double)b[1])/-db1; if( dt < t) { t = dt; nbr = 1; } } if(db2 < 0) { dt = ((double)b[2])/-db2; if( dt < t) { t = dt; nbr = 2; } } *tptr = t; return(nbr); } qtTrace_ray(qt,b,db0,db1,db2,nextptr,sign,sfactor,func,f) QUADTREE qt; BCOORD b[3]; BDIR db0,db1,db2; int *nextptr; int sign,sfactor; FUNC func; int *f; { int i,found; QUADTREE child; int nbr,next,w; double t; if(QT_IS_TREE(qt)) { /* Find the appropriate child and reset the coord */ i = bary_child(b); for(;;) { child = QT_NTH_CHILD(qt,i); if(i != 3) qtTrace_ray(child,b,db0,db1,db2,nextptr,sign,sfactor+1,func,f); else /* If the center cell- must flip direction signs */ qtTrace_ray(child,b,-db0,-db1,-db2,nextptr,1-sign,sfactor+1,func,f); if(QT_FLAG_IS_DONE(*f)) return; /* If in same block: traverse */ if(i==3) next = *nextptr; else if(*nextptr == i) next = 3; else { /* reset the barycentric coordinates in the parents*/ bary_parent(b,i); /* Else pop up to parent and traverse from there */ return(qt); } bary_from_child(b,i,next); i = next; } } else { #ifdef TEST_DRIVER if(Pick_cnt < 500) Pick_q[Pick_cnt++]=qt; #endif; F_FUNC(func)(qt,F_ARGS(func),f); if(QT_FLAG_IS_DONE(*f)) return; /* Advance to next node */ nbr = move_to_nbr(b,db0,db1,db2,&t); if(nbr==-1) { QT_FLAG_SET_DONE(*f); return; } b[0] += (BCOORD)(t *db0); b[1] += (BCOORD)(t *db1); b[2] += (BCOORD)(t *db2); *nextptr = nbr; return; } } #define TEST_INT(tl,th,d,q0,q1,h,l) \ tl=d>q0;th=d> 1) | (s0 << 2 & 4))); /* See if edge can be trivially rejected from intersetion testing */ test_t0t1 = !(((s0 & 6)==0) || ((s1 & 6)==0)|| ((s2 & 6)==0) || ((sq0 & 6)==6) ||((sq1 & 6)==6)|| ((sq2 & 6)==6)); bl=bh=0; if(test_t0t1 && (e0 & 2) ) { /* Must do double calculation to avoid overflow */ db = t0[1] + dt10[1]*((double)(a-t0[0]))/dt10[0]; TEST_INT(testl,testh,db,b,q1[1],bl,bh) } test_t1t2= !(((s0 & 3)==0) || ((s1 & 3)==0)|| ((s2 & 3)==0) || ((sq0 & 3)==3) ||((sq1 & 3)==3)|| ((sq2 & 3)==3)); if(test_t1t2 && (e0 & 1)) { /* test t1t2 against a */ db = t1[1] + dt21[1]*((double)(a - t1[0]))/dt21[0]; TEST_INT(testl,testh,db,b,q1[1],bl,bh) } test_t2t0 = !(((s0 & 5)==0) || ((s1 & 5)==0)|| ((s2 & 5)==0) || ((sq0 & 5)==5) ||((sq1 & 5)==5)|| ((sq2 & 5)==5)); if(test_t2t0 && (e0 & 4)) { db = t2[1] + dt02[1]*((double)(a - t2[0]))/dt02[0]; TEST_INT(testl,testh,db,b,q1[1],bl,bh) } e1 = (s1 ^ ((s1 >> 1) | (s1 << 2 & 4))); cl = ch = 0; if(test_t0t1 && (e1 & 2)) {/* test t0t1 against b */ db = t0[2] + dt10[2]*((double)(b-t0[1]))/dt10[1]; TEST_INT(testl,testh,db,c,q2[2],cl,ch) } if(test_t1t2 && (e1 & 1)) {/* test t1t2 against b */ db = t1[2] + dt21[2]*((double)(q0[1] - t1[1]))/dt21[1]; TEST_INT(testl,testh,db,c,q2[2],cl,ch) } if(test_t2t0 && (e1 & 4)) {/* test t2t0 against b */ db = t2[2] + dt02[2]*((double)(q0[1] - t2[1]))/dt02[1]; TEST_INT(testl,testh,db,c,q2[2],cl,ch) } /* test edges against c */ e2 = (s2 ^ ((s2 >> 1) | (s2 << 2 & 4))); al = ah = 0; if(test_t0t1 && (e2 & 2)) { /* test t0t1 against c */ db = t0[0] + dt10[0]*((double)(c-t0[2]))/dt10[2]; TEST_INT(testl,testh,db,a,q0[0],al,ah) } if(test_t1t2 && (e2 & 1)) { db = t1[0] + dt21[0]*((double)(c - t1[2]))/dt21[2]; TEST_INT(testl,testh,db,a,q0[0],al,ah) } if(test_t2t0 && (e2 & 4)) { /* test t2t0 against c */ db = t2[0] + dt02[0]*((double)(c - t2[2]))/dt02[2]; TEST_INT(testl,testh,db,a,q0[0],al,ah) } /* Only remaining case is if some edge trivially rejected */ if(!e0 || !e1 || !e2) return(qt); /* Only one/none got tested - pick either of other two/any two */ /* Only need to test one edge */ if(!test_t0t1 && (e0 & 2)) { db = t0[1] + dt10[1]*((double)(a-t0[0]))/dt10[0]; TEST_INT(testl,testh,db,b,q1[1],bl,bh) } if(!test_t1t2 && (e0 & 1)) {/* test t1t2 against a */ db = t1[1] + dt21[1]*((double)(a - t1[0]))/dt21[0]; TEST_INT(testl,testh,db,b,q1[1],bl,bh) } if(!test_t2t0 && (e0 & 4)) { db = t2[1] + dt02[1]*((double)(a - t2[0]))/dt02[0]; TEST_INT(testl,testh,db,b,q1[1],bl,bh) } return(qt); Lfunc_call: qt = f.func(f.argptr,root,qt,q0,q1,q2,t0,t1,t2,dt10,dt21,dt02,scale, s0,s1,s2,sq0,sq1,sq2,0,f,n); return(qt); } /* Leaf node: Do definitive test */ QUADTREE qtLeaf_insert_tri_rev(root,qt,q0,q1,q2,t0,t1,t2,dt10,dt21,dt02, scale, s0,s1,s2,sq0,sq1,sq2,f,n) int root; QUADTREE qt; BCOORD q0[3],q1[3],q2[3]; BCOORD t0[3],t1[3],t2[3]; BCOORD dt10[3],dt21[3],dt02[3]; unsigned int scale,s0,s1,s2,sq0,sq1,sq2; FUNC f; int n; { double db; unsigned int e0,e1,e2; BCOORD a,b,c; double p0[2], p1[2],cp; char al,ah,bl,bh,cl,ch; char testl,testh,test_t0t1,test_t1t2,test_t2t0; unsigned int ls0,ls1,ls2; /* May have gotten passed trivial reject if one/two vertices are ON */ a = q1[0];b= q0[1]; c= q0[2]; SIDES_LESS(t0,t1,t2,ls0,ls1,ls2,a,b,c); /* First check if can trivial accept: if vertex in cell */ if(ls0 & ls1 & ls2) { goto Lfunc_call; } if(ls0==0 || ls1 == 0 || ls2 ==0) return(qt); /* Assumption: Could not trivial reject*/ /* IF any coords lie on edge- must be in if couldnt reject */ if(t0[0]== a || t0[1] == b || t0[2] == c) { goto Lfunc_call; } if(t1[0]== a || t1[1] == b || t1[2] == c) { goto Lfunc_call; } if(t2[0]== a || t2[1] == b || t2[2] == c) { goto Lfunc_call; } /* Test for edge crossings */ /* Test t0t1 against a,b,c */ /* First test if t0t1 can be trivially rejected */ /* If both edges are outside bounds- dont need to test */ /* Test t0t1,t1t2,t2t0 against a */ test_t0t1 = !(((ls0 & 6)==0) || ((ls1 & 6)==0)|| ((ls2 & 6)==0) || ((sq0 & 6)==0) ||((sq1 & 6)==0)|| ((sq2 & 6)==0)); e0 = (ls0 ^ ((ls0 >> 1) | (ls0 << 2 & 4))); bl=bh=0; /* Test t0t1,t1t2,t2t0 against a */ if(test_t0t1 && (e0 & 2) ) { db = t0[1] + dt10[1]*((double)(a-t0[0])/dt10[0]); TEST_INT(testl,testh,db,q1[1],b,bl,bh) } test_t1t2= !(((ls0 & 3)==0) || ((ls1 & 3)==0)|| ((ls2 & 3)==0) || ((sq0 & 3)==0) ||((sq1 & 3)==0)|| ((sq2 & 3)==0)); if(test_t1t2 && (e0 & 1)) { /* test t1t2 against a */ db = t1[1] + dt21[1]*((double)(a - t1[0]))/dt21[0]; TEST_INT(testl,testh,db,q1[1],b,bl,bh) } test_t2t0 = !(((ls0 & 5)==0) || ((ls1 & 5)==0)|| ((ls2 & 5)==0) || ((sq0 & 5)==0) ||((sq1 & 5)==0)|| ((sq2 & 5)==0)); if(test_t2t0 && (e0 & 4)) { db = t2[1] + dt02[1]*((double)(a - t2[0]))/dt02[0]; TEST_INT(testl,testh,db,q1[1],b,bl,bh) } cl = ch = 0; e1 = (ls1 ^ ((ls1 >> 1) | (ls1 << 2 & 4))); if(test_t0t1 && (e1 & 2)) {/* test t0t1 against b */ db = t0[2] + dt10[2]*(((double)(b-t0[1]))/dt10[1]); TEST_INT(testl,testh,db,q1[2],c,cl,ch) } if(test_t1t2 && (e1 & 1)) {/* test t1t2 against b */ db = t1[2] + dt21[2]*((double)(b - t1[1]))/dt21[1]; TEST_INT(testl,testh,db,q1[2],c,cl,ch) } if(test_t2t0 && (e1 & 4)) {/* test t2t0 against b */ db = t2[2] + dt02[2]*((double)(b - t2[1]))/dt02[1]; TEST_INT(testl,testh,db,q1[2],c,cl,ch) } al = ah = 0; e2 = (ls2 ^ ((ls2 >> 1) | (ls2 << 2 & 4))); if(test_t0t1 && (e2 & 2)) { /* test t0t1 against c */ db = t0[0] + dt10[0]*(((double)(c-t0[2]))/dt10[2]); TEST_INT(testl,testh,db,q0[0],a,al,ah) } if(test_t1t2 && (e2 & 1)) { db = t1[0] + dt21[0]*((double)(c - t1[2]))/dt21[2]; TEST_INT(testl,testh,db,q0[0],a,al,ah) } if(test_t2t0 && (e2 & 4)) { /* test t2t0 against c */ db = t2[0] + dt02[0]*((double)(c - t2[2]))/dt02[2]; TEST_INT(testl,testh,db,q0[0],a,al,ah) } /* Only remaining case is if some edge trivially rejected */ if(!e0 || !e1 || !e2) return(qt); /* Only one/none got tested - pick either of other two/any two */ /* Only need to test one edge */ if(!test_t0t1 && (e0 & 2)) { db = t0[1] + dt10[1]*((double)(a-t0[0]))/dt10[0]; TEST_INT(testl,testh,db,q1[1],b,bl,bh) } if(!test_t1t2 && (e0 & 1)) {/* test t1t2 against a */ db = t1[1] + dt21[1]*((double)(a - t1[0]))/dt21[0]; TEST_INT(testl,testh,db,q1[1],b,bl,bh) } if(!test_t2t0 && (e0 & 4)) { db = t2[1] + dt02[1]*((double)(a - t2[0]))/dt02[0]; TEST_INT(testl,testh,db,q1[1],b,bl,bh) } return(qt); Lfunc_call: qt = f.func(f.argptr,root,qt,q0,q1,q2,t0,t1,t2,dt10,dt21,dt02,scale, s0,s1,s2,sq0,sq1,sq2,1,f,n); return(qt); } /* ASSUMPTION: that triangle t0,t1,t2 intersects quad cell q0,q1,q2 */ /*-------q2--------- sq2 / \ s1 /sc \ s0 qb_____qa / \ / \ \sq0/sa \ /sb \ /sq1 \ q0____qc____q1/ \ / \ s2 / */ int Find_id=0; QUADTREE qtInsert_tri(root,qt,q0,q1,q2,t0,t1,t2,dt10,dt21,dt02,scale, s0,s1,s2,sq0,sq1,sq2,f,n) int root; QUADTREE qt; BCOORD q0[3],q1[3],q2[3]; BCOORD t0[3],t1[3],t2[3]; BCOORD dt10[3],dt21[3],dt02[3]; BCOORD scale; unsigned int s0,s1,s2,sq0,sq1,sq2; FUNC f; int n; { BCOORD a,b,c; BCOORD va[3],vb[3],vc[3]; unsigned int sa,sb,sc; /* If a tree: trivial reject and recurse on potential children */ if(QT_IS_TREE(qt)) { /* Test against new a edge: if entirely to left: only need to visit child 0 */ a = q1[0] + scale; b = q0[1] + scale; c = q0[2] + scale; SIDES_GTR(t0,t1,t2,sa,sb,sc,a,b,c); if(sa==7) { vb[1] = q0[1]; vc[2] = q0[2]; vc[1] = b; vb[2] = c; vb[0] = vc[0] = a; QT_NTH_CHILD(qt,0) = qtInsert_tri(root,QT_NTH_CHILD(qt,0),q0,vc, vb,t0,t1,t2,dt10,dt21,dt02, scale>>1,sa,s1,s2,sq0,sb,sc,f,n+1); return(qt); } if(sb==7) { va[0] = q1[0]; vc[2] = q0[2]; va[1] = vc[1] = b; va[2] = c; vc[0] = a; QT_NTH_CHILD(qt,1) = qtInsert_tri(root,QT_NTH_CHILD(qt,1),vc,q1,va, t0,t1,t2,dt10,dt21,dt02,scale>>1,s0,sb,s2,sa,sq1,sc,f,n+1); return(qt); } if(sc==7) { va[0] = q1[0]; vb[1] = q0[1]; va[1] = b; va[2] = vb[2] = c; vb[0] = a; QT_NTH_CHILD(qt,2) = qtInsert_tri(root,QT_NTH_CHILD(qt,2),vb,va, q2,t0,t1,t2,dt10,dt21,dt02,scale>>1,s0,s1,sc,sa,sb,sq2,f,n+1); return(qt); } va[0] = q1[0]; vb[1] = q0[1]; vc[2] = q0[2]; va[1] = vc[1] = b; va[2] = vb[2] = c; vb[0] = vc[0] = a; /* If outside of all edges: only need to Visit 3 */ if(sa==0 && sb==0 && sc==0) { QT_NTH_CHILD(qt,3) = qtInsert_tri_rev(root,QT_NTH_CHILD(qt,3),va,vb, vc,t0,t1,t2,dt10,dt21,dt02, scale>>1,sa,sb,sc,s0,s1,s2,f,n+1); return(qt); } if(sa) QT_NTH_CHILD(qt,0) = qtInsert_tri(root,QT_NTH_CHILD(qt,0),q0,vc,vb,t0, t1,t2,dt10,dt21,dt02,scale>>1,sa,s1,s2,sq0,sb,sc,f,n+1); if(sb) QT_NTH_CHILD(qt,1) = qtInsert_tri(root,QT_NTH_CHILD(qt,1),vc,q1,va,t0, t1,t2,dt10,dt21,dt02,scale>>1,s0,sb,s2,sa,sq1,sc,f,n+1); if(sc) QT_NTH_CHILD(qt,2) = qtInsert_tri(root,QT_NTH_CHILD(qt,2),vb,va,q2,t0, t1,t2,dt10,dt21,dt02,scale>>1,s0,s1,sc,sa,sb,sq2,f,n+1); QT_NTH_CHILD(qt,3) = qtInsert_tri_rev(root,QT_NTH_CHILD(qt,3),va,vb,vc,t0, t1,t2,dt10,dt21,dt02,scale>>1,sa,sb,sc,s0,s1,s2,f,n+1); return(qt); } /* Leaf node: Do definitive test */ else return(qt = qtLeaf_insert_tri(root,qt,q0,q1,q2,t0,t1,t2,dt10,dt21,dt02, scale,s0,s1,s2,sq0,sq1,sq2,f,n)); } QUADTREE qtInsert_tri_rev(root,qt,q0,q1,q2,t0,t1,t2,dt10,dt21,dt02,scale, s0,s1,s2,sq0,sq1,sq2,f,n) int root; QUADTREE qt; BCOORD q0[3],q1[3],q2[3]; BCOORD t0[3],t1[3],t2[3]; BCOORD dt10[3],dt21[3],dt02[3]; BCOORD scale; unsigned int s0,s1,s2,sq0,sq1,sq2; FUNC f; int n; { BCOORD a,b,c; BCOORD va[3],vb[3],vc[3]; unsigned int sa,sb,sc; /* If a tree: trivial reject and recurse on potential children */ if(QT_IS_TREE(qt)) { /* Test against new a edge: if entirely to left: only need to visit child 0 */ a = q1[0] - scale; b = q0[1] - scale; c = q0[2] - scale; SIDES_GTR(t0,t1,t2,sa,sb,sc,a,b,c); if(sa==0) { vb[1] = q0[1]; vc[2] = q0[2]; vc[1] = b; vb[2] = c; vb[0] = vc[0] = a; QT_NTH_CHILD(qt,0) = qtInsert_tri_rev(root,QT_NTH_CHILD(qt,0),q0,vc, vb,t0,t1,t2,dt10,dt21,dt02, scale>>1,sa,s1,s2,sq0,sb,sc,f,n+1); return(qt); } if(sb==0) { va[0] = q1[0]; vc[2] = q0[2]; va[1] = vc[1] = b; va[2] = c; vc[0] = a; QT_NTH_CHILD(qt,1) = qtInsert_tri_rev(root,QT_NTH_CHILD(qt,1),vc,q1,va, t0,t1,t2,dt10,dt21,dt02,scale>>1,s0,sb,s2,sa,sq1,sc,f,n+1); return(qt); } if(sc==0) { va[0] = q1[0]; vb[1] = q0[1]; va[1] = b; va[2] = vb[2] = c; vb[0] = a; QT_NTH_CHILD(qt,2) = qtInsert_tri_rev(root,QT_NTH_CHILD(qt,2),vb,va, q2,t0,t1,t2,dt10,dt21,dt02,scale>>1,s0,s1,sc,sa,sb,sq2,f,n+1); return(qt); } va[0] = q1[0]; vb[1] = q0[1]; vc[2] = q0[2]; va[1] = vc[1] = b; va[2] = vb[2] = c; vb[0] = vc[0] = a; /* If outside of all edges: only need to Visit 3 */ if(sa==7 && sb==7 && sc==7) { QT_NTH_CHILD(qt,3) = qtInsert_tri(root,QT_NTH_CHILD(qt,3),va,vb, vc,t0,t1,t2,dt10,dt21,dt02, scale>>1,sa,sb,sc,s0,s1,s2,f,n+1); return(qt); } if(sa!=7) QT_NTH_CHILD(qt,0) = qtInsert_tri_rev(root,QT_NTH_CHILD(qt,0),q0,vc,vb, t0,t1,t2,dt10,dt21,dt02,scale>>1,sa,s1,s2,sq0,sb,sc,f,n+1); if(sb!=7) QT_NTH_CHILD(qt,1) = qtInsert_tri_rev(root,QT_NTH_CHILD(qt,1),vc,q1,va, t0,t1,t2,dt10,dt21,dt02,scale>>1,s0,sb,s2,sa,sq1,sc,f,n+1); if(sc!=7) QT_NTH_CHILD(qt,2) = qtInsert_tri_rev(root,QT_NTH_CHILD(qt,2),vb,va,q2, t0,t1,t2,dt10,dt21,dt02,scale>>1,s0,s1,sc,sa,sb,sq2,f,n+1); QT_NTH_CHILD(qt,3) = qtInsert_tri(root,QT_NTH_CHILD(qt,3),va,vb,vc,t0,t1, t2,dt10,dt21,dt02,scale>>1,sa,sb,sc,s0,s1,s2,f,n+1); return(qt); } /* Leaf node: Do definitive test */ else return(qt = qtLeaf_insert_tri_rev(root,qt,q0,q1,q2,t0,t1,t2,dt10,dt21,dt02, scale,s0,s1,s2,sq0,sq1,sq2,f,n)); } /*************************************************************************/ /* Visit code for applying functions: NOTE THIS IS THE SAME AS INSERT CODE: except sets flags: wanted insert to be as efficient as possible: so broke into two sets of routines. Also traverses only to n levels. */ qtVisit_tri(root,qt,q0,q1,q2,t0,t1,t2,dt10,dt21,dt02,scale, s0,s1,s2,sq0,sq1,sq2,f,n) int root; QUADTREE qt; BCOORD q0[3],q1[3],q2[3]; BCOORD t0[3],t1[3],t2[3]; BCOORD dt10[3],dt21[3],dt02[3]; BCOORD scale; unsigned int s0,s1,s2,sq0,sq1,sq2; FUNC f; int n; { BCOORD a,b,c; BCOORD va[3],vb[3],vc[3]; unsigned int sa,sb,sc; if(n == 0) return; /* If a tree: trivial reject and recurse on potential children */ if(QT_IS_TREE(qt)) { QT_SET_FLAG(qt); /* Test against new a edge: if entirely to left: only need to visit child 0 */ a = q1[0] + scale; b = q0[1] + scale; c = q0[2] + scale; SIDES_GTR(t0,t1,t2,sa,sb,sc,a,b,c); if(sa==7) { vb[1] = q0[1]; vc[2] = q0[2]; vc[1] = b; vb[2] = c; vb[0] = vc[0] = a; qtVisit_tri(root,QT_NTH_CHILD(qt,0),q0,vc, vb,t0,t1,t2,dt10,dt21,dt02, scale>>1,sa,s1,s2,sq0,sb,sc,f,n-1); return; } if(sb==7) { va[0] = q1[0]; vc[2] = q0[2]; va[1] = vc[1] = b; va[2] = c; vc[0] = a; qtVisit_tri(root,QT_NTH_CHILD(qt,1),vc,q1,va, t0,t1,t2,dt10,dt21,dt02,scale>>1,s0,sb,s2,sa,sq1,sc,f,n-1); return; } if(sc==7) { va[0] = q1[0]; vb[1] = q0[1]; va[1] = b; va[2] = vb[2] = c; vb[0] = a; qtVisit_tri(root,QT_NTH_CHILD(qt,2),vb,va, q2,t0,t1,t2,dt10,dt21,dt02,scale>>1,s0,s1,sc,sa,sb,sq2,f,n-1); return; } va[0] = q1[0]; vb[1] = q0[1]; vc[2] = q0[2]; va[1] = vc[1] = b; va[2] = vb[2] = c; vb[0] = vc[0] = a; /* If outside of all edges: only need to Visit 3 */ if(sa==0 && sb==0 && sc==0) { qtVisit_tri_rev(root,QT_NTH_CHILD(qt,3),va,vb, vc,t0,t1,t2,dt10,dt21,dt02, scale>>1,sa,sb,sc,s0,s1,s2,f,n-1); return; } if(sa) qtVisit_tri(root,QT_NTH_CHILD(qt,0),q0,vc,vb,t0, t1,t2,dt10,dt21,dt02,scale>>1,sa,s1,s2,sq0,sb,sc,f,n-1); if(sb) qtVisit_tri(root,QT_NTH_CHILD(qt,1),vc,q1,va,t0, t1,t2,dt10,dt21,dt02,scale>>1,s0,sb,s2,sa,sq1,sc,f,n-1); if(sc) qtVisit_tri(root,QT_NTH_CHILD(qt,2),vb,va,q2,t0, t1,t2,dt10,dt21,dt02,scale>>1,s0,s1,sc,sa,sb,sq2,f,n-1); qtVisit_tri_rev(root,QT_NTH_CHILD(qt,3),va,vb,vc,t0, t1,t2,dt10,dt21,dt02,scale>>1,sa,sb,sc,s0,s1,s2,f,n-1); } /* Leaf node: Do definitive test */ else qtLeaf_visit_tri(root,qt,q0,q1,q2,t0,t1,t2,dt10,dt21,dt02, scale,s0,s1,s2,sq0,sq1,sq2,f,n); } qtVisit_tri_rev(root,qt,q0,q1,q2,t0,t1,t2,dt10,dt21,dt02,scale, s0,s1,s2,sq0,sq1,sq2,f,n) int root; QUADTREE qt; BCOORD q0[3],q1[3],q2[3]; BCOORD t0[3],t1[3],t2[3]; BCOORD dt10[3],dt21[3],dt02[3]; BCOORD scale; unsigned int s0,s1,s2,sq0,sq1,sq2; FUNC f; int n; { BCOORD a,b,c; BCOORD va[3],vb[3],vc[3]; unsigned int sa,sb,sc; if(n==0) return; /* If a tree: trivial reject and recurse on potential children */ if(QT_IS_TREE(qt)) { QT_SET_FLAG(qt); /* Test against new a edge: if entirely to left: only need to visit child 0 */ a = q1[0] - scale; b = q0[1] - scale; c = q0[2] - scale; SIDES_GTR(t0,t1,t2,sa,sb,sc,a,b,c); if(sa==0) { vb[1] = q0[1]; vc[2] = q0[2]; vc[1] = b; vb[2] = c; vb[0] = vc[0] = a; qtVisit_tri_rev(root,QT_NTH_CHILD(qt,0),q0,vc, vb,t0,t1,t2,dt10,dt21,dt02, scale>>1,sa,s1,s2,sq0,sb,sc,f,n-1); return; } if(sb==0) { va[0] = q1[0]; vc[2] = q0[2]; va[1] = vc[1] = b; va[2] = c; vc[0] = a; qtVisit_tri_rev(root,QT_NTH_CHILD(qt,1),vc,q1,va, t0,t1,t2,dt10,dt21,dt02,scale>>1,s0,sb,s2,sa,sq1,sc,f,n-1); return; } if(sc==0) { va[0] = q1[0]; vb[1] = q0[1]; va[1] = b; va[2] = vb[2] = c; vb[0] = a; qtVisit_tri_rev(root,QT_NTH_CHILD(qt,2),vb,va, q2,t0,t1,t2,dt10,dt21,dt02,scale>>1,s0,s1,sc,sa,sb,sq2,f,n-1); return; } va[0] = q1[0]; vb[1] = q0[1]; vc[2] = q0[2]; va[1] = vc[1] = b; va[2] = vb[2] = c; vb[0] = vc[0] = a; /* If outside of all edges: only need to Visit 3 */ if(sa==7 && sb==7 && sc==7) { qtVisit_tri(root,QT_NTH_CHILD(qt,3),va,vb, vc,t0,t1,t2,dt10,dt21,dt02, scale>>1,sa,sb,sc,s0,s1,s2,f,n-1); return; } if(sa!=7) qtVisit_tri_rev(root,QT_NTH_CHILD(qt,0),q0,vc,vb, t0,t1,t2,dt10,dt21,dt02,scale>>1,sa,s1,s2,sq0,sb,sc,f,n-1); if(sb!=7) qtVisit_tri_rev(root,QT_NTH_CHILD(qt,1),vc,q1,va, t0,t1,t2,dt10,dt21,dt02,scale>>1,s0,sb,s2,sa,sq1,sc,f,n-1); if(sc!=7) qtVisit_tri_rev(root,QT_NTH_CHILD(qt,2),vb,va,q2, t0,t1,t2,dt10,dt21,dt02,scale>>1,s0,s1,sc,sa,sb,sq2,f,n-1); qtVisit_tri(root,QT_NTH_CHILD(qt,3),va,vb,vc,t0,t1, t2,dt10,dt21,dt02,scale>>1,sa,sb,sc,s0,s1,s2,f,n-1); return; } /* Leaf node: Do definitive test */ else qtLeaf_visit_tri_rev(root,qt,q0,q1,q2,t0,t1,t2,dt10,dt21,dt02, scale,s0,s1,s2,sq0,sq1,sq2,f,n); } qtLeaf_visit_tri(root,qt,q0,q1,q2,t0,t1,t2,dt10,dt21,dt02, scale, s0,s1,s2,sq0,sq1,sq2,f,n) int root; QUADTREE qt; BCOORD q0[3],q1[3],q2[3]; BCOORD t0[3],t1[3],t2[3]; BCOORD dt10[3],dt21[3],dt02[3]; unsigned int scale,s0,s1,s2,sq0,sq1,sq2; FUNC f; int n; { double db; unsigned int e0,e1,e2; char al,ah,bl,bh,cl,ch,testl,testh; char test_t0t1,test_t1t2,test_t2t0; BCOORD a,b,c; /* First check if can trivial accept: if vertex in cell */ if(s0 & s1 & s2) goto Lfunc_call; /* Assumption: Could not trivial reject*/ /* IF any coords lie on edge- must be in if couldnt reject */ a = q1[0];b= q0[1]; c= q0[2]; if(t0[0]== a || t0[1] == b || t0[2] == c) goto Lfunc_call; if(t1[0]== a || t1[1] == b || t1[2] == c) goto Lfunc_call; if(t2[0]== a || t2[1] == b || t2[2] == c) goto Lfunc_call; /* Test for edge crossings */ /* Test t0t1,t1t2,t2t0 against a */ /* Calculate edge crossings */ e0 = (s0 ^ ((s0 >> 1) | (s0 << 2 & 4))); /* See if edge can be trivially rejected from intersetion testing */ test_t0t1 = !(((s0 & 6)==0) || ((s1 & 6)==0)|| ((s2 & 6)==0) || ((sq0 & 6)==6) ||((sq1 & 6)==6)|| ((sq2 & 6)==6)); bl=bh=0; if(test_t0t1 && (e0 & 2) ) { /* Must do double calculation to avoid overflow */ db = t0[1] + dt10[1]*((double)(a-t0[0]))/dt10[0]; TEST_INT(testl,testh,db,b,q1[1],bl,bh) } test_t1t2= !(((s0 & 3)==0) || ((s1 & 3)==0)|| ((s2 & 3)==0) || ((sq0 & 3)==3) ||((sq1 & 3)==3)|| ((sq2 & 3)==3)); if(test_t1t2 && (e0 & 1)) { /* test t1t2 against a */ db = t1[1] + dt21[1]*((double)(a - t1[0]))/dt21[0]; TEST_INT(testl,testh,db,b,q1[1],bl,bh) } test_t2t0 = !(((s0 & 5)==0) || ((s1 & 5)==0)|| ((s2 & 5)==0) || ((sq0 & 5)==5) ||((sq1 & 5)==5)|| ((sq2 & 5)==5)); if(test_t2t0 && (e0 & 4)) { db = t2[1] + dt02[1]*((double)(a - t2[0]))/dt02[0]; TEST_INT(testl,testh,db,b,q1[1],bl,bh) } e1 = (s1 ^ ((s1 >> 1) | (s1 << 2 & 4))); cl = ch = 0; if(test_t0t1 && (e1 & 2)) {/* test t0t1 against b */ db = t0[2] + dt10[2]*((double)(b-t0[1]))/dt10[1]; TEST_INT(testl,testh,db,c,q2[2],cl,ch) } if(test_t1t2 && (e1 & 1)) {/* test t1t2 against b */ db = t1[2] + dt21[2]*((double)(q0[1] - t1[1]))/dt21[1]; TEST_INT(testl,testh,db,c,q2[2],cl,ch) } if(test_t2t0 && (e1 & 4)) {/* test t2t0 against b */ db = t2[2] + dt02[2]*((double)(q0[1] - t2[1]))/dt02[1]; TEST_INT(testl,testh,db,c,q2[2],cl,ch) } /* test edges against c */ e2 = (s2 ^ ((s2 >> 1) | (s2 << 2 & 4))); al = ah = 0; if(test_t0t1 && (e2 & 2)) { /* test t0t1 against c */ db = t0[0] + dt10[0]*((double)(c-t0[2]))/dt10[2]; TEST_INT(testl,testh,db,a,q0[0],al,ah) } if(test_t1t2 && (e2 & 1)) { db = t1[0] + dt21[0]*((double)(c - t1[2]))/dt21[2]; TEST_INT(testl,testh,db,a,q0[0],al,ah) } if(test_t2t0 && (e2 & 4)) { /* test t2t0 against c */ db = t2[0] + dt02[0]*((double)(c - t2[2]))/dt02[2]; TEST_INT(testl,testh,db,a,q0[0],al,ah) } /* Only remaining case is if some edge trivially rejected */ if(!e0 || !e1 || !e2) return; /* Only one/none got tested - pick either of other two/any two */ /* Only need to test one edge */ if(!test_t0t1 && (e0 & 2)) { db = t0[1] + dt10[1]*((double)(a-t0[0]))/dt10[0]; TEST_INT(testl,testh,db,b,q1[1],bl,bh) } if(!test_t1t2 && (e0 & 1)) {/* test t1t2 against a */ db = t1[1] + dt21[1]*((double)(a - t1[0]))/dt21[0]; TEST_INT(testl,testh,db,b,q1[1],bl,bh) } if(!test_t2t0 && (e0 & 4)) { db = t2[1] + dt02[1]*((double)(a - t2[0]))/dt02[0]; TEST_INT(testl,testh,db,b,q1[1],bl,bh) } return; Lfunc_call: f.func(f.argptr,root,qt,n); if(!QT_IS_EMPTY(qt)) QT_LEAF_SET_FLAG(qt); } /* Leaf node: Do definitive test */ QUADTREE qtLeaf_visit_tri_rev(root,qt,q0,q1,q2,t0,t1,t2,dt10,dt21,dt02, scale, s0,s1,s2,sq0,sq1,sq2,f,n) int root; QUADTREE qt; BCOORD q0[3],q1[3],q2[3]; BCOORD t0[3],t1[3],t2[3]; BCOORD dt10[3],dt21[3],dt02[3]; unsigned int scale,s0,s1,s2,sq0,sq1,sq2; FUNC f; int n; { double db; unsigned int e0,e1,e2; BCOORD a,b,c; double p0[2], p1[2],cp; char al,ah,bl,bh,cl,ch; char testl,testh,test_t0t1,test_t1t2,test_t2t0; unsigned int ls0,ls1,ls2; /* May have gotten passed trivial reject if one/two vertices are ON */ a = q1[0];b= q0[1]; c= q0[2]; SIDES_LESS(t0,t1,t2,ls0,ls1,ls2,a,b,c); /* First check if can trivial accept: if vertex in cell */ if(ls0 & ls1 & ls2) goto Lfunc_call; if(ls0==0 || ls1 == 0 || ls2 ==0) return; /* Assumption: Could not trivial reject*/ /* IF any coords lie on edge- must be in if couldnt reject */ if(t0[0]== a || t0[1] == b || t0[2] == c) goto Lfunc_call; if(t1[0]== a || t1[1] == b || t1[2] == c) goto Lfunc_call; if(t2[0]== a || t2[1] == b || t2[2] == c) goto Lfunc_call; /* Test for edge crossings */ /* Test t0t1 against a,b,c */ /* First test if t0t1 can be trivially rejected */ /* If both edges are outside bounds- dont need to test */ /* Test t0t1,t1t2,t2t0 against a */ test_t0t1 = !(((ls0 & 6)==0) || ((ls1 & 6)==0)|| ((ls2 & 6)==0) || ((sq0 & 6)==0) ||((sq1 & 6)==0)|| ((sq2 & 6)==0)); e0 = (ls0 ^ ((ls0 >> 1) | (ls0 << 2 & 4))); bl=bh=0; /* Test t0t1,t1t2,t2t0 against a */ if(test_t0t1 && (e0 & 2) ) { db = t0[1] + dt10[1]*((double)(a-t0[0])/dt10[0]); TEST_INT(testl,testh,db,q1[1],b,bl,bh) } test_t1t2= !(((ls0 & 3)==0) || ((ls1 & 3)==0)|| ((ls2 & 3)==0) || ((sq0 & 3)==0) ||((sq1 & 3)==0)|| ((sq2 & 3)==0)); if(test_t1t2 && (e0 & 1)) { /* test t1t2 against a */ db = t1[1] + dt21[1]*((double)(a - t1[0]))/dt21[0]; TEST_INT(testl,testh,db,q1[1],b,bl,bh) } test_t2t0 = !(((ls0 & 5)==0) || ((ls1 & 5)==0)|| ((ls2 & 5)==0) || ((sq0 & 5)==0) ||((sq1 & 5)==0)|| ((sq2 & 5)==0)); if(test_t2t0 && (e0 & 4)) { db = t2[1] + dt02[1]*((double)(a - t2[0]))/dt02[0]; TEST_INT(testl,testh,db,q1[1],b,bl,bh) } cl = ch = 0; e1 = (ls1 ^ ((ls1 >> 1) | (ls1 << 2 & 4))); if(test_t0t1 && (e1 & 2)) {/* test t0t1 against b */ db = t0[2] + dt10[2]*(((double)(b-t0[1]))/dt10[1]); TEST_INT(testl,testh,db,q1[2],c,cl,ch) } if(test_t1t2 && (e1 & 1)) {/* test t1t2 against b */ db = t1[2] + dt21[2]*((double)(b - t1[1]))/dt21[1]; TEST_INT(testl,testh,db,q1[2],c,cl,ch) } if(test_t2t0 && (e1 & 4)) {/* test t2t0 against b */ db = t2[2] + dt02[2]*((double)(b - t2[1]))/dt02[1]; TEST_INT(testl,testh,db,q1[2],c,cl,ch) } al = ah = 0; e2 = (ls2 ^ ((ls2 >> 1) | (ls2 << 2 & 4))); if(test_t0t1 && (e2 & 2)) { /* test t0t1 against c */ db = t0[0] + dt10[0]*(((double)(c-t0[2]))/dt10[2]); TEST_INT(testl,testh,db,q0[0],a,al,ah) } if(test_t1t2 && (e2 & 1)) { db = t1[0] + dt21[0]*((double)(c - t1[2]))/dt21[2]; TEST_INT(testl,testh,db,q0[0],a,al,ah) } if(test_t2t0 && (e2 & 4)) { /* test t2t0 against c */ db = t2[0] + dt02[0]*((double)(c - t2[2]))/dt02[2]; TEST_INT(testl,testh,db,q0[0],a,al,ah) } /* Only remaining case is if some edge trivially rejected */ if(!e0 || !e1 || !e2) return; /* Only one/none got tested - pick either of other two/any two */ /* Only need to test one edge */ if(!test_t0t1 && (e0 & 2)) { db = t0[1] + dt10[1]*((double)(a-t0[0]))/dt10[0]; TEST_INT(testl,testh,db,q1[1],b,bl,bh) } if(!test_t1t2 && (e0 & 1)) {/* test t1t2 against a */ db = t1[1] + dt21[1]*((double)(a - t1[0]))/dt21[0]; TEST_INT(testl,testh,db,q1[1],b,bl,bh) } if(!test_t2t0 && (e0 & 4)) { db = t2[1] + dt02[1]*((double)(a - t2[0]))/dt02[0]; TEST_INT(testl,testh,db,q1[1],b,bl,bh) } return; Lfunc_call: f.func(f.argptr,root,qt,n); if(!QT_IS_EMPTY(qt)) QT_LEAF_SET_FLAG(qt); } QUADTREE qtInsert_point(root,qt,parent,q0,q1,q2,bc,scale,f,n,doneptr) int root; QUADTREE qt,parent; BCOORD q0[3],q1[3],q2[3],bc[3],scale; FUNC f; int n,*doneptr; { BCOORD a,b,c; BCOORD va[3],vb[3],vc[3]; if(QT_IS_TREE(qt)) { a = q1[0] + scale; b = q0[1] + scale; c = q0[2] + scale; if(bc[0] > a) { vc[0] = a; vc[1] = b; vc[2] = q0[2]; vb[0] = a; vb[1] = q0[1]; vb[2] = c; QT_NTH_CHILD(qt,0) = qtInsert_point(root,QT_NTH_CHILD(qt,0), qt,q0,vc,vb,bc,scale>>1,f,n+1,doneptr); if(!*doneptr) { f.func_after(f.argptr,QT_NTH_CHILD(qt,1),f,doneptr); if(!*doneptr) f.func_after(f.argptr,QT_NTH_CHILD(qt,2),f,doneptr); if(!*doneptr) f.func_after(f.argptr,QT_NTH_CHILD(qt,3),f,doneptr); } return(qt); } if(bc[1] > b) { vc[0] = a; vc[1] = b; vc[2] = q0[2]; va[0] = q1[0]; va[1] = b; va[2] = c; QT_NTH_CHILD(qt,1) =qtInsert_point(root,QT_NTH_CHILD(qt,1), qt,vc,q1,va,bc,scale >>1,f,n+1,doneptr); if(!*doneptr) { f.func_after(f.argptr,QT_NTH_CHILD(qt,0),f,doneptr); if(!*doneptr) f.func_after(f.argptr,QT_NTH_CHILD(qt,2),f,doneptr); if(!*doneptr) f.func_after(f.argptr,QT_NTH_CHILD(qt,3),f,doneptr); } return(qt); } if(bc[2] > c) { va[0] = q1[0]; va[1] = b; va[2] = c; vb[0] = a; vb[1] = q0[1]; vb[2] = c; QT_NTH_CHILD(qt,2) = qtInsert_point(root,QT_NTH_CHILD(qt,2), qt,vb,va,q2,bc,scale>>1,f,n+1,doneptr); if(!*doneptr) { f.func_after(f.argptr,QT_NTH_CHILD(qt,0),f,doneptr); if(!*doneptr) f.func_after(f.argptr,QT_NTH_CHILD(qt,1),f,doneptr); if(!*doneptr) f.func_after(f.argptr,QT_NTH_CHILD(qt,3),f,doneptr); } return(qt); } else { va[0] = q1[0]; va[1] = b; va[2] = c; vb[0] = a; vb[1] = q0[1]; vb[2] = c; vc[0] = a; vc[1] = b; vc[2] = q0[2]; QT_NTH_CHILD(qt,3) = qtInsert_point_rev(root,QT_NTH_CHILD(qt,3), qt,va,vb,vc,bc,scale>>1,f,n+1,doneptr); if(!*doneptr) { f.func_after(f.argptr,QT_NTH_CHILD(qt,0),f,doneptr); if(!*doneptr) f.func_after(f.argptr,QT_NTH_CHILD(qt,1),f,doneptr); if(!*doneptr) f.func_after(f.argptr,QT_NTH_CHILD(qt,2),f,doneptr); } return(qt); } } else { qt = f.func(f.argptr,root,qt,parent,q0,q1,q2,bc,scale,0,f,n,doneptr); return(qt); } } QUADTREE qtInsert_point_rev(root,qt,parent,q0,q1,q2,bc,scale,f,n,doneptr) int root; QUADTREE qt,parent; BCOORD q0[3],q1[3],q2[3],bc[3]; BCOORD scale; FUNC f; int n,*doneptr; { BCOORD a,b,c; BCOORD va[3],vb[3],vc[3]; if(QT_IS_TREE(qt)) { a = q1[0] - scale; b = q0[1] - scale; c = q0[2] - scale; if(bc[0] < a) { vc[0] = a; vc[1] = b; vc[2] = q0[2]; vb[0] = a; vb[1] = q0[1]; vb[2] = c; QT_NTH_CHILD(qt,0) = qtInsert_point_rev(root,QT_NTH_CHILD(qt,0), qt,q0,vc,vb,bc,scale>>1,f,n+1,doneptr); if(!*doneptr) { f.func_after(f.argptr,QT_NTH_CHILD(qt,1),f,doneptr); if(!*doneptr) f.func_after(f.argptr,QT_NTH_CHILD(qt,2),f,doneptr); if(!*doneptr) f.func_after(f.argptr,QT_NTH_CHILD(qt,3),f,doneptr); } return(qt); } if(bc[1] < b) { vc[0] = a; vc[1] = b; vc[2] = q0[2]; va[0] = q1[0]; va[1] = b; va[2] = c; QT_NTH_CHILD(qt,1) = qtInsert_point_rev(root,QT_NTH_CHILD(qt,1), qt,vc,q1,va,bc,scale>>1,f,n+1,doneptr); if(!*doneptr) { f.func_after(f.argptr,QT_NTH_CHILD(qt,0),f,doneptr); if(!*doneptr) f.func_after(f.argptr,QT_NTH_CHILD(qt,2),f,doneptr); if(!*doneptr) f.func_after(f.argptr,QT_NTH_CHILD(qt,3),f,doneptr); } return(qt); } if(bc[2] < c) { va[0] = q1[0]; va[1] = b; va[2] = c; vb[0] = a; vb[1] = q0[1]; vb[2] = c; QT_NTH_CHILD(qt,2) = qtInsert_point_rev(root,QT_NTH_CHILD(qt,2), qt,vb,va,q2,bc,scale>>1,f,n+1,doneptr); if(!*doneptr) { f.func_after(f.argptr,QT_NTH_CHILD(qt,0),f,doneptr); if(!*doneptr) f.func_after(f.argptr,QT_NTH_CHILD(qt,1),f,doneptr); if(!*doneptr) f.func_after(f.argptr,QT_NTH_CHILD(qt,3),f,doneptr); } return(qt); } else { va[0] = q1[0]; va[1] = b; va[2] = c; vb[0] = a; vb[1] = q0[1]; vb[2] = c; vc[0] = a; vc[1] = b; vc[2] = q0[2]; QT_NTH_CHILD(qt,3) = qtInsert_point(root,QT_NTH_CHILD(qt,3), qt,va,vb,vc,bc,scale>>1,f,n+1,doneptr); if(!*doneptr) { f.func_after(f.argptr,QT_NTH_CHILD(qt,0),f,doneptr); if(!*doneptr) f.func_after(f.argptr,QT_NTH_CHILD(qt,1),f,doneptr); if(!*doneptr) f.func_after(f.argptr,QT_NTH_CHILD(qt,2),f,doneptr); } return(qt); } } else { qt = f.func(f.argptr,root,qt,parent,q0,q1,q2,bc,scale,1,f,n,doneptr); return(qt); } }