ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/sm_qtree.c
Revision: 3.1
Committed: Wed Aug 19 17:45:24 1998 UTC (25 years, 8 months ago) by gwlarson
Content type: text/plain
Branch: MAIN
Log Message:
Initial revision

File Contents

# Content
1 /* Copyright (c) 1998 Silicon Graphics, Inc. */
2
3 #ifndef lint
4 static char SCCSid[] = "$SunId$ SGI";
5 #endif
6
7 /*
8 * sm_qtree.c: adapted from octree.c from radiance code
9 */
10 /*
11 * octree.c - routines dealing with octrees and cubes.
12 *
13 * 7/28/85
14 */
15
16 #include "standard.h"
17
18 #include "sm_geom.h"
19 #include "sm_qtree.h"
20 #include "object.h"
21
22 QUADTREE *quad_block[QT_MAX_BLK]; /* our quadtree */
23 static QUADTREE quad_free_list = EMPTY; /* freed octree nodes */
24 static QUADTREE treetop = 0; /* next free node */
25
26
27
28 QUADTREE
29 qtAlloc() /* allocate a quadtree */
30 {
31 register QUADTREE freet;
32
33 if ((freet = quad_free_list) != EMPTY)
34 {
35 quad_free_list = QT_NTH_CHILD(freet, 0);
36 return(freet);
37 }
38 freet = treetop;
39 if (QT_BLOCK_INDEX(freet) == 0)
40 {
41 if (QT_BLOCK(freet) >= QT_MAX_BLK)
42 return(EMPTY);
43 if ((quad_block[QT_BLOCK(freet)] = (QUADTREE *)malloc(
44 (unsigned)QT_BLOCK_SIZE*4*sizeof(QUADTREE))) == NULL)
45 return(EMPTY);
46 }
47 treetop += 4;
48 return(freet);
49 }
50
51
52 qtFree(qt) /* free a quadtree */
53 register QUADTREE qt;
54 {
55 register int i;
56
57 if (!QT_IS_TREE(qt))
58 {
59 qtfreeleaf(qt);
60 return;
61 }
62 for (i = 0; i < 4; i++)
63 qtFree(QT_NTH_CHILD(qt, i));
64 QT_NTH_CHILD(qt, 0) = quad_free_list;
65 quad_free_list = qt;
66 }
67
68
69 qtDone() /* free EVERYTHING */
70 {
71 register int i;
72
73 for (i = 0; i < QT_MAX_BLK; i++)
74 {
75 free((char *)quad_block[i],
76 (unsigned)QT_BLOCK_SIZE*4*sizeof(QUADTREE));
77 quad_block[i] = NULL;
78 }
79 quad_free_list = EMPTY;
80 treetop = 0;
81 }
82
83 QUADTREE
84 qtCompress(qt) /* recursively combine nodes */
85 register QUADTREE qt;
86 {
87 register int i;
88 register QUADTREE qres;
89
90 if (!QT_IS_TREE(qt)) /* not a tree */
91 return(qt);
92 qres = QT_NTH_CHILD(qt,0) = qtCompress(QT_NTH_CHILD(qt,0));
93 for (i = 1; i < 4; i++)
94 if((QT_NTH_CHILD(qt,i) = qtCompress(QT_NTH_CHILD(qt,i))) != qres)
95 qres = qt;
96 if(!QT_IS_TREE(qres))
97 { /* all were identical leaves */
98 QT_NTH_CHILD(qt,0) = quad_free_list;
99 quad_free_list = qt;
100 }
101 return(qres);
102 }
103
104 QUADTREE
105 qtPoint_locate(qtptr,v1,v2,v3,pt,type,which,p0,p1,p2)
106 QUADTREE *qtptr;
107 FVECT v1,v2,v3;
108 FVECT pt;
109 char *type,*which;
110 FVECT p0,p1,p2;
111 {
112 char d,w;
113 int i;
114 QUADTREE *child;
115 QUADTREE qt;
116 FVECT a,b,c;
117 FVECT t1,t2,t3;
118
119 /* Determine if point lies within pyramid (and therefore
120 inside a spherical quadtree cell):GT_INTERIOR, on one of the
121 pyramid sides (and on cell edge):GT_EDGE(1,2 or 3),
122 or on pyramid vertex (and on cell vertex):GT_VERTEX(1,2, or 3).
123 For each triangle edge: compare the
124 point against the plane formed by the edge and the view center
125 */
126 d = test_single_point_against_spherical_tri(v1,v2,v3,pt,&w);
127
128 /* Not in this triangle */
129 if(!d)
130 {
131 if(which)
132 *which = 0;
133 return(EMPTY);
134 }
135
136 /* Will return lowest level triangle containing point: It the
137 point is on an edge or vertex: will return first associated
138 triangle encountered in the child traversal- the others can
139 be derived using triangle adjacency information
140 */
141
142 if(QT_IS_TREE(*qtptr))
143 {
144 qtSubdivide_tri(v1,v2,v3,a,b,c);
145 child = QT_NTH_CHILD_PTR(*qtptr,0);
146 if(!QT_IS_EMPTY(*child))
147 {
148 qt = qtPoint_locate(child,v1,a,c,pt,type,which,p0,p1,p2);
149 if(!QT_IS_EMPTY(qt))
150 return(qt);
151 }
152 child = QT_NTH_CHILD_PTR(*qtptr,1);
153 if(!QT_IS_EMPTY(*child))
154 {
155 qt = qtPoint_locate(child,a,b,c,pt,type,which,p0,p1,p2);
156 if(!QT_IS_EMPTY(qt))
157 return(qt);
158 }
159 child = QT_NTH_CHILD_PTR(*qtptr,2);
160 if(!QT_IS_EMPTY(*child))
161 {
162 qt = qtPoint_locate(child,a,v2,b,pt,type,which,p0,p1,p2);
163 if(!QT_IS_EMPTY(qt))
164 return(qt);
165 }
166 child = QT_NTH_CHILD_PTR(*qtptr,3);
167 if(!QT_IS_EMPTY(*child))
168 {
169 qt = qtPoint_locate(child,c,b,v3,pt,type,which,p0,p1,p2);
170 if(!QT_IS_EMPTY(qt))
171 return(qt);
172 }
173 }
174 else
175 if(!QT_IS_EMPTY(*qtptr))
176 {
177 /* map GT_VERTEX,GT_EDGE,GT_FACE GT_INTERIOR of pyramid to
178 spherical triangle primitives
179 */
180 if(type)
181 *type = d;
182 if(which)
183 *which = w;
184 VCOPY(p0,v1);
185 VCOPY(p1,v2);
186 VCOPY(p2,v3);
187 return(*qtptr);
188 }
189 return(EMPTY);
190 }
191
192 int
193 qtPoint_in_tri(qtptr,v0,v1,v2,pt,type,which)
194 QUADTREE *qtptr;
195 FVECT v0,v1,v2;
196 FVECT pt;
197 char *type,*which;
198 {
199 QUADTREE qt;
200 OBJECT os[MAXSET+1],*optr;
201 char d,w;
202 int i,id;
203 FVECT p0,p1,p2;
204
205 qt = qtPoint_locate(qtptr,v0,v1,v2,pt,type,which,p0,p1,p2);
206 if(QT_IS_EMPTY(qt))
207 return(EMPTY);
208
209 /* Get the set */
210 qtgetset(os,qt);
211 for (i = QT_SET_CNT(os),optr = QT_SET_PTR(os); i > 0; i--)
212 {
213 /* Find the triangle that pt falls in (NOTE:FOR now return first 1) */
214 id = QT_SET_NEXT_ELEM(optr);
215 qtTri_verts_from_id(id,p0,p1,p2);
216 d = test_single_point_against_spherical_tri(p0,p1,p2,pt,&w);
217 if(d)
218 {
219 if(type)
220 *type = d;
221 if(which)
222 *which = w;
223 return(id);
224 }
225 }
226 return(EMPTY);
227 }
228
229 QUADTREE
230 qtSubdivide(qtptr)
231 QUADTREE *qtptr;
232 {
233 QUADTREE node;
234 node = qtAlloc();
235 QT_CLEAR_CHILDREN(node);
236 *qtptr = node;
237 return(node);
238 }
239
240
241 QUADTREE
242 qtSubdivide_nth_child(qt,n)
243 QUADTREE qt;
244 int n;
245 {
246 QUADTREE node;
247
248 node = qtSubdivide(&(QT_NTH_CHILD(qt,n)));
249
250 return(node);
251 }
252
253 /* for triangle v1-v2-v3- returns a,b,c: children are:
254
255 v3 0: v1,a,c
256 /\ 1: a,b,c
257 /3 \ 2: a,v2,b
258 c/____\b 3: c,b,v3
259 /\ /\
260 /0 \1 /2 \
261 v1/____\/____\v2
262 a
263 */
264
265 qtSubdivide_tri(v1,v2,v3,a,b,c)
266 FVECT v1,v2,v3;
267 FVECT a,b,c;
268 {
269 EDGE_MIDPOINT_VEC3(a,v1,v2);
270 normalize(a);
271 EDGE_MIDPOINT_VEC3(b,v2,v3);
272 normalize(b);
273 EDGE_MIDPOINT_VEC3(c,v3,v1);
274 normalize(c);
275 }
276
277 qtNth_child_tri(v1,v2,v3,a,b,c,i,r1,r2,r3)
278 FVECT v1,v2,v3;
279 FVECT a,b,c;
280 int i;
281 FVECT r1,r2,r3;
282 {
283 VCOPY(r1,a); VCOPY(r2,b); VCOPY(r3,c);
284 switch(i){
285 case 0:
286 VCOPY(r2,r1);
287 VCOPY(r1,v1);
288 break;
289 case 1:
290 break;
291 case 2:
292 VCOPY(r3,r2);
293 VCOPY(r2,v2);
294 break;
295 case 3:
296 VCOPY(r1,r3);
297 VCOPY(r3,v3);
298 break;
299 }
300 }
301
302 /* Add triangle "id" to all leaf level cells that are children of
303 quadtree pointed to by "qtptr" with cell vertices "t1,t2,t3"
304 that it overlaps (vertex and edge adjacencies do not count
305 as overlapping). If the addition of the triangle causes the cell to go over
306 threshold- the cell is split- and the triangle must be recursively inserted
307 into the new child cells: it is assumed that "v1,v2,v3" are normalized
308 */
309
310 int
311 qtAdd_tri(qtptr,id,t1,t2,t3,v1,v2,v3,n)
312 QUADTREE *qtptr;
313 int id;
314 FVECT t1,t2,t3;
315 FVECT v1,v2,v3;
316 int n;
317 {
318
319 char test;
320 int i,index;
321 FVECT a,b,c;
322 OBJECT os[MAXSET+1],*optr;
323 QUADTREE qt;
324 int found;
325 FVECT r1,r2,r3;
326
327 /* test if triangle (t1,t2,t3) overlaps cell triangle (v1,v2,v3) */
328 test = spherical_tri_intersect(t1,t2,t3,v1,v2,v3);
329
330 /* If triangles do not overlap: done */
331 if(!test)
332 return(FALSE);
333 found = 0;
334
335 /* if this is tree: recurse */
336 if(QT_IS_TREE(*qtptr))
337 {
338 n++;
339 qtSubdivide_tri(v1,v2,v3,a,b,c);
340 found |= qtAdd_tri(QT_NTH_CHILD_PTR(*qtptr,0),id,t1,t2,t3,v1,a,c,n);
341 found |= qtAdd_tri(QT_NTH_CHILD_PTR(*qtptr,1),id,t1,t2,t3,a,b,c,n);
342 found |= qtAdd_tri(QT_NTH_CHILD_PTR(*qtptr,2),id,t1,t2,t3,a,v2,b,n);
343 found |= qtAdd_tri(QT_NTH_CHILD_PTR(*qtptr,3),id,t1,t2,t3,c,b,v3,n);
344
345 #if 0
346 if(!found)
347 {
348 #ifdef TEST_DRIVER
349 HANDLE_ERROR("qtAdd_tri():Found in parent but not children\n");
350 #else
351 eputs("qtAdd_tri():Found in parent but not children\n");
352 #endif
353 }
354 #endif
355 }
356 else
357 {
358 /* If this leave node emptry- create a new set */
359 if(QT_IS_EMPTY(*qtptr))
360 {
361 *qtptr = qtaddelem(*qtptr,id);
362 #if 0
363 {
364 int k;
365 qtgetset(os,*qtptr);
366 printf("\n%d:\n",os[0]);
367 for(k=1; k <= os[0];k++)
368 printf("%d ",os[k]);
369 printf("\n");
370 }
371 #endif
372 /*
373 os[0] = 0;
374 insertelem(os,id);
375 qt = fullnode(os);
376 *qtptr = qt;
377 */
378 }
379 else
380 {
381 qtgetset(os,*qtptr);
382 /* If the set is too large: subdivide */
383 if(QT_SET_CNT(os) < QT_SET_THRESHOLD)
384 {
385 *qtptr = qtaddelem(*qtptr,id);
386 #if 0
387 {
388 int k;
389 qtgetset(os,*qtptr);
390 printf("\n%d:\n",os[0]);
391 for(k=1; k <= os[0];k++)
392 printf("%d ",os[k]);
393 printf("\n");
394 }
395 #endif
396 /*
397 insertelem(os,id);
398 *qtptr = fullnode(os);
399 */
400 }
401 else
402 {
403 if (n < QT_MAX_LEVELS)
404 {
405 /* If set size exceeds threshold: subdivide cell and
406 reinsert set tris into cell
407 */
408 n++;
409 qtfreeleaf(*qtptr);
410 qtSubdivide(qtptr);
411 found = qtAdd_tri(qtptr,id,t1,t2,t3,v1,v2,v3,n);
412 #if 0
413 if(!found)
414 {
415 #ifdef TEST_DRIVER
416 HANDLE_ERROR("qtAdd_tri():Found in parent but not children\n");
417 #else
418 eputs("qtAdd_tri():Found in parent but not children\n");
419 #endif
420 }
421 #endif
422 for(optr = &(os[1]),i = QT_SET_CNT(os); i > 0; i--)
423 {
424 id = QT_SET_NEXT_ELEM(optr);
425 qtTri_verts_from_id(id,r1,r2,r3);
426 found=qtAdd_tri(qtptr,id,r1,r2,r3,v1,v2,v3,n);
427 #ifdef DEBUG
428 if(!found)
429 eputs("qtAdd_tri():Reinsert-in parent but not children\n");
430 #endif
431 }
432 }
433 else
434 if(QT_SET_CNT(os) < QT_MAX_SET)
435 {
436 *qtptr = qtaddelem(*qtptr,id);
437 #if 0
438 {
439 int k;
440 qtgetset(os,*qtptr);
441 printf("\n%d:\n",os[0]);
442 for(k=1; k <= os[0];k++)
443 printf("%d ",os[k]);
444 printf("\n");
445 }
446 #endif
447 /*
448 insertelem(os,id);
449 *qtptr = fullnode(os);
450 */
451 }
452 else
453 {
454 #ifdef DEBUG
455 eputs("qtAdd_tri():two many levels\n");
456 #endif
457 return(FALSE);
458 }
459 }
460 }
461 }
462 return(TRUE);
463 }
464
465
466 int
467 qtApply_to_tri_cells(qtptr,t1,t2,t3,v1,v2,v3,func,arg)
468 QUADTREE *qtptr;
469 FVECT t1,t2,t3;
470 FVECT v1,v2,v3;
471 int (*func)();
472 char *arg;
473 {
474 char test;
475 FVECT a,b,c;
476
477 /* test if triangle (t1,t2,t3) overlaps cell triangle (v1,v2,v3) */
478 test = spherical_tri_intersect(t1,t2,t3,v1,v2,v3);
479
480 /* If triangles do not overlap: done */
481 if(!test)
482 return(FALSE);
483
484 /* if this is tree: recurse */
485 if(QT_IS_TREE(*qtptr))
486 {
487 qtSubdivide_tri(v1,v2,v3,a,b,c);
488 qtApply_to_tri_cells(QT_NTH_CHILD_PTR(*qtptr,0),t1,t2,t3,v1,a,c,func,arg);
489 qtApply_to_tri_cells(QT_NTH_CHILD_PTR(*qtptr,1),t1,t2,t3,a,b,c,func,arg);
490 qtApply_to_tri_cells(QT_NTH_CHILD_PTR(*qtptr,2),t1,t2,t3,a,v2,b,func,arg);
491 qtApply_to_tri_cells(QT_NTH_CHILD_PTR(*qtptr,3),t1,t2,t3,c,b,v3,func,arg);
492 }
493 else
494 return(func(qtptr,arg));
495 }
496
497
498 int
499 qtRemove_tri(qtptr,id,t1,t2,t3,v1,v2,v3)
500 QUADTREE *qtptr;
501 int id;
502 FVECT t1,t2,t3;
503 FVECT v1,v2,v3;
504 {
505
506 char test;
507 int i;
508 FVECT a,b,c;
509 OBJECT os[MAXSET+1];
510
511 /* test if triangle (t1,t2,t3) overlaps cell triangle (v1,v2,v3) */
512 test = spherical_tri_intersect(t1,t2,t3,v1,v2,v3);
513
514 /* If triangles do not overlap: done */
515 if(!test)
516 return(FALSE);
517
518 /* if this is tree: recurse */
519 if(QT_IS_TREE(*qtptr))
520 {
521 qtSubdivide_tri(v1,v2,v3,a,b,c);
522 qtRemove_tri(QT_NTH_CHILD_PTR(*qtptr,0),id,t1,t2,t3,v1,a,c);
523 qtRemove_tri(QT_NTH_CHILD_PTR(*qtptr,1),id,t1,t2,t3,a,b,c);
524 qtRemove_tri(QT_NTH_CHILD_PTR(*qtptr,2),id,t1,t2,t3,a,v2,b);
525 qtRemove_tri(QT_NTH_CHILD_PTR(*qtptr,3),id,t1,t2,t3,c,b,v3);
526 }
527 else
528 {
529 if(QT_IS_EMPTY(*qtptr))
530 {
531 #ifdef DEBUG
532 eputs("qtRemove_tri(): triangle not found\n");
533 #endif
534 }
535 /* remove id from set */
536 else
537 {
538 qtgetset(os,*qtptr);
539 if(!inset(os,id))
540 {
541 #ifdef DEBUG
542 eputs("qtRemove_tri(): tri not in set\n");
543 #endif
544 }
545 else
546 {
547 *qtptr = qtdelelem(*qtptr,id);
548 #if 0
549 {
550 int k;
551 if(!QT_IS_EMPTY(*qtptr))
552 {qtgetset(os,*qtptr);
553 printf("\n%d:\n",os[0]);
554 for(k=1; k <= os[0];k++)
555 printf("%d ",os[k]);
556 printf("\n");
557 }
558
559 }
560 #endif
561 }
562 }
563 }
564 return(TRUE);
565 }