ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/sm_geom.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_geom.c
9 */
10
11 #include "standard.h"
12 #include "sm_geom.h"
13
14 tri_centroid(v0,v1,v2,c)
15 FVECT v0,v1,v2,c;
16 {
17 /* Average three triangle vertices to give centroid: return in c */
18 c[0] = (v0[0] + v1[0] + v2[0])/3.0;
19 c[1] = (v0[1] + v1[1] + v2[1])/3.0;
20 c[2] = (v0[2] + v1[2] + v2[2])/3.0;
21 }
22
23
24 int
25 vec3_equal(v1,v2)
26 FVECT v1,v2;
27 {
28 return(EQUAL(v1[0],v2[0]) && EQUAL(v1[1],v2[1])&& EQUAL(v1[2],v2[2]));
29 }
30
31
32 int
33 convex_angle(v0,v1,v2)
34 FVECT v0,v1,v2;
35 {
36 FVECT cp01,cp12,cp;
37
38 /* test sign of (v0Xv1)X(v1Xv2). v1 */
39 VCROSS(cp01,v0,v1);
40 VCROSS(cp12,v1,v2);
41 VCROSS(cp,cp01,cp12);
42 if(DOT(cp,v1) < 0)
43 return(FALSE);
44 return(TRUE);
45 }
46
47 /* calculates the normal of a face contour using Newell's formula. e
48
49 a = SUMi (yi - yi+1)(zi + zi+1)
50 b = SUMi (zi - zi+1)(xi + xi+1)
51 c = SUMi (xi - xi+1)(yi + yi+1)
52 */
53 double
54 tri_normal(v0,v1,v2,n,norm)
55 FVECT v0,v1,v2,n;
56 char norm;
57 {
58 double mag;
59
60 n[0] = (v0[2] + v1[2]) * (v0[1] - v1[1]) +
61 (v1[2] + v2[2]) * (v1[1] - v2[1]) +
62 (v2[2] + v0[2]) * (v2[1] - v0[1]);
63
64 n[1] = (v0[2] - v1[2]) * (v0[0] + v1[0]) +
65 (v1[2] - v2[2]) * (v1[0] + v2[0]) +
66 (v2[2] - v0[2]) * (v2[0] + v0[0]);
67
68
69 n[2] = (v0[1] + v1[1]) * (v0[0] - v1[0]) +
70 (v1[1] + v2[1]) * (v1[0] - v2[0]) +
71 (v2[1] + v0[1]) * (v2[0] - v0[0]);
72
73 if(!norm)
74 return(0);
75
76
77 mag = normalize(n);
78
79 return(mag);
80 }
81
82
83 tri_plane_equation(v0,v1,v2,n,nd,norm)
84 FVECT v0,v1,v2,n;
85 double *nd;
86 char norm;
87 {
88 tri_normal(v0,v1,v2,n,norm);
89
90 *nd = -(DOT(n,v0));
91 }
92
93 int
94 point_relative_to_plane(p,n,nd)
95 FVECT p,n;
96 double nd;
97 {
98 double d;
99
100 d = p[0]*n[0] + p[1]*n[1] + p[2]*n[2] + nd;
101 if(d < 0)
102 return(-1);
103 if(ZERO(d))
104 return(0);
105 else
106 return(1);
107 }
108
109 /* From quad_edge-code */
110 int
111 point_in_circle_thru_origin(p,p0,p1)
112 FVECT p;
113 FVECT p0,p1;
114 {
115
116 double dp0,dp1;
117 double dp,det;
118
119 dp0 = DOT_VEC2(p0,p0);
120 dp1 = DOT_VEC2(p1,p1);
121 dp = DOT_VEC2(p,p);
122
123 det = -dp0*CROSS_VEC2(p1,p) + dp1*CROSS_VEC2(p0,p) - dp*CROSS_VEC2(p0,p1);
124
125 return (det > 0);
126 }
127
128
129
130 point_on_sphere(ps,p,c)
131 FVECT ps,p,c;
132 {
133 VSUB(ps,p,c);
134 normalize(ps);
135 }
136
137
138 int
139 intersect_vector_plane(v,plane_n,plane_d,pd,r)
140 FVECT v,plane_n;
141 double plane_d;
142 double *pd;
143 FVECT r;
144 {
145 double t;
146 int hit;
147 /*
148 Plane is Ax + By + Cz +D = 0:
149 plane[0] = A,plane[1] = B,plane[2] = C,plane[3] = D
150 */
151
152 /* line is l = p1 + (p2-p1)t, p1=origin */
153
154 /* Solve for t: */
155 t = plane_d/-(DOT(plane_n,v));
156 if(t >0 || ZERO(t))
157 hit = 1;
158 else
159 hit = 0;
160 r[0] = v[0]*t;
161 r[1] = v[1]*t;
162 r[2] = v[2]*t;
163 if(pd)
164 *pd = t;
165 return(hit);
166 }
167
168 int
169 intersect_ray_plane(orig,dir,plane_n,plane_d,pd,r)
170 FVECT orig,dir;
171 FVECT plane_n;
172 double plane_d;
173 double *pd;
174 FVECT r;
175 {
176 double t;
177 int hit;
178 /*
179 Plane is Ax + By + Cz +D = 0:
180 plane[0] = A,plane[1] = B,plane[2] = C,plane[3] = D
181 */
182 /* A(orig[0] + dxt) + B(orig[1] + dyt) + C(orig[2] + dzt) + pd = 0 */
183 /* t = -(DOT(plane_n,orig)+ plane_d)/(DOT(plane_n,d))
184 /* line is l = p1 + (p2-p1)t */
185 /* Solve for t: */
186 t = -(DOT(plane_n,orig) + plane_d)/(DOT(plane_n,dir));
187 if(ZERO(t) || t >0)
188 hit = 1;
189 else
190 hit = 0;
191
192 VSUM(r,orig,dir,t);
193
194 if(pd)
195 *pd = t;
196 return(hit);
197 }
198
199
200 int
201 point_in_cone(p,p0,p1,p2)
202 FVECT p;
203 FVECT p0,p1,p2;
204 {
205 FVECT n;
206 FVECT np,x_axis,y_axis;
207 double d1,d2,d;
208
209 /* Find the equation of the circle defined by the intersection
210 of the cone with the plane defined by p1,p2,p3- project p into
211 that plane and do an in-circle test in the plane
212 */
213
214 /* find the equation of the plane defined by p1-p3 */
215 tri_plane_equation(p0,p1,p2,n,&d,FALSE);
216
217 /* define a coordinate system on the plane: the x axis is in
218 the direction of np2-np1, and the y axis is calculated from
219 n cross x-axis
220 */
221 /* Project p onto the plane */
222 if(!intersect_vector_plane(p,n,d,NULL,np))
223 return(FALSE);
224
225 /* create coordinate system on plane: p2-p1 defines the x_axis*/
226 VSUB(x_axis,p1,p0);
227 normalize(x_axis);
228 /* The y axis is */
229 VCROSS(y_axis,n,x_axis);
230 normalize(y_axis);
231
232 VSUB(p1,p1,p0);
233 VSUB(p2,p2,p0);
234 VSUB(np,np,p0);
235
236 p1[0] = VLEN(p1);
237 p1[1] = 0;
238
239 d1 = DOT(p2,x_axis);
240 d2 = DOT(p2,y_axis);
241 p2[0] = d1;
242 p2[1] = d2;
243
244 d1 = DOT(np,x_axis);
245 d2 = DOT(np,y_axis);
246 np[0] = d1;
247 np[1] = d2;
248
249 /* perform the in-circle test in the new coordinate system */
250 return(point_in_circle_thru_origin(np,p1,p2));
251 }
252
253 int
254 test_point_against_spherical_tri(v0,v1,v2,p,n,nset,which,sides)
255 FVECT v0,v1,v2,p;
256 FVECT n[3];
257 char *nset;
258 char *which;
259 char sides[3];
260
261 {
262 float d;
263
264 /* Find the normal to the triangle ORIGIN:v0:v1 */
265 if(!NTH_BIT(*nset,0))
266 {
267 VCROSS(n[0],v1,v0);
268 SET_NTH_BIT(*nset,0);
269 }
270 /* Test the point for sidedness */
271 d = DOT(n[0],p);
272
273 if(ZERO(d))
274 sides[0] = GT_EDGE;
275 else
276 if(d > 0)
277 {
278 sides[0] = GT_OUT;
279 sides[1] = sides[2] = GT_INVALID;
280 return(FALSE);
281 }
282 else
283 sides[0] = GT_INTERIOR;
284
285 /* Test next edge */
286 if(!NTH_BIT(*nset,1))
287 {
288 VCROSS(n[1],v2,v1);
289 SET_NTH_BIT(*nset,1);
290 }
291 /* Test the point for sidedness */
292 d = DOT(n[1],p);
293 if(ZERO(d))
294 {
295 sides[1] = GT_EDGE;
296 /* If on plane 0-and on plane 1: lies on edge */
297 if(sides[0] == GT_EDGE)
298 {
299 *which = 1;
300 sides[2] = GT_INVALID;
301 return(GT_EDGE);
302 }
303 }
304 else if(d > 0)
305 {
306 sides[1] = GT_OUT;
307 sides[2] = GT_INVALID;
308 return(FALSE);
309 }
310 else
311 sides[1] = GT_INTERIOR;
312 /* Test next edge */
313 if(!NTH_BIT(*nset,2))
314 {
315
316 VCROSS(n[2],v0,v2);
317 SET_NTH_BIT(*nset,2);
318 }
319 /* Test the point for sidedness */
320 d = DOT(n[2],p);
321 if(ZERO(d))
322 {
323 sides[2] = GT_EDGE;
324
325 /* If on plane 0 and 2: lies on edge 0*/
326 if(sides[0] == GT_EDGE)
327 {
328 *which = 0;
329 return(GT_EDGE);
330 }
331 /* If on plane 1 and 2: lies on edge 2*/
332 if(sides[1] == GT_EDGE)
333 {
334 *which = 2;
335 return(GT_EDGE);
336 }
337 /* otherwise: on face 2 */
338 else
339 {
340 *which = 2;
341 return(GT_FACE);
342 }
343 }
344 else if(d > 0)
345 {
346 sides[2] = GT_OUT;
347 return(FALSE);
348 }
349 /* If on edge */
350 else
351 sides[2] = GT_INTERIOR;
352
353 /* If on plane 0 only: on face 0 */
354 if(sides[0] == GT_EDGE)
355 {
356 *which = 0;
357 return(GT_FACE);
358 }
359 /* If on plane 1 only: on face 1 */
360 if(sides[1] == GT_EDGE)
361 {
362 *which = 1;
363 return(GT_FACE);
364 }
365 /* Must be interior to the pyramid */
366 return(GT_INTERIOR);
367 }
368
369
370
371
372 int
373 test_single_point_against_spherical_tri(v0,v1,v2,p,which)
374 FVECT v0,v1,v2,p;
375 char *which;
376 {
377 float d;
378 FVECT n;
379 char sides[3];
380
381 /* First test if point coincides with any of the vertices */
382 if(EQUAL_VEC3(p,v0))
383 {
384 *which = 0;
385 return(GT_VERTEX);
386 }
387 if(EQUAL_VEC3(p,v1))
388 {
389 *which = 1;
390 return(GT_VERTEX);
391 }
392 if(EQUAL_VEC3(p,v2))
393 {
394 *which = 2;
395 return(GT_VERTEX);
396 }
397 VCROSS(n,v1,v0);
398 /* Test the point for sidedness */
399 d = DOT(n,p);
400 if(ZERO(d))
401 sides[0] = GT_EDGE;
402 else
403 if(d > 0)
404 return(FALSE);
405 else
406 sides[0] = GT_INTERIOR;
407 /* Test next edge */
408 VCROSS(n,v2,v1);
409 /* Test the point for sidedness */
410 d = DOT(n,p);
411 if(ZERO(d))
412 {
413 sides[1] = GT_EDGE;
414 /* If on plane 0-and on plane 1: lies on edge */
415 if(sides[0] == GT_EDGE)
416 {
417 *which = 1;
418 return(GT_VERTEX);
419 }
420 }
421 else if(d > 0)
422 return(FALSE);
423 else
424 sides[1] = GT_INTERIOR;
425
426 /* Test next edge */
427 VCROSS(n,v0,v2);
428 /* Test the point for sidedness */
429 d = DOT(n,p);
430 if(ZERO(d))
431 {
432 sides[2] = GT_EDGE;
433
434 /* If on plane 0 and 2: lies on edge 0*/
435 if(sides[0] == GT_EDGE)
436 {
437 *which = 0;
438 return(GT_VERTEX);
439 }
440 /* If on plane 1 and 2: lies on edge 2*/
441 if(sides[1] == GT_EDGE)
442 {
443 *which = 2;
444 return(GT_VERTEX);
445 }
446 /* otherwise: on face 2 */
447 else
448 {
449 return(GT_FACE);
450 }
451 }
452 else if(d > 0)
453 return(FALSE);
454 /* Must be interior to the pyramid */
455 return(GT_FACE);
456 }
457
458 int
459 test_vertices_for_tri_inclusion(t0,t1,t2,p0,p1,p2,nset,n,avg,pt_sides)
460 FVECT t0,t1,t2,p0,p1,p2;
461 char *nset;
462 FVECT n[3];
463 FVECT avg;
464 char pt_sides[3][3];
465
466 {
467 char below_plane[3],on_edge,test;
468 char which;
469
470 SUM_3VEC3(avg,t0,t1,t2);
471 on_edge = 0;
472 *nset = 0;
473 /* Test vertex v[i] against triangle j*/
474 /* Check if v[i] lies below plane defined by avg of 3 vectors
475 defining triangle
476 */
477
478 /* test point 0 */
479 if(DOT(avg,p0) < 0)
480 below_plane[0] = 1;
481 else
482 below_plane[0]=0;
483 /* Test if b[i] lies in or on triangle a */
484 test = test_point_against_spherical_tri(t0,t1,t2,p0,
485 n,nset,&which,pt_sides[0]);
486 /* If pts[i] is interior: done */
487 if(!below_plane[0])
488 {
489 if(test == GT_INTERIOR)
490 return(TRUE);
491 /* Remember if b[i] fell on one of the 3 defining planes */
492 if(test)
493 on_edge++;
494 }
495 /* Now test point 1*/
496
497 if(DOT(avg,p1) < 0)
498 below_plane[1] = 1;
499 else
500 below_plane[1]=0;
501 /* Test if b[i] lies in or on triangle a */
502 test = test_point_against_spherical_tri(t0,t1,t2,p1,
503 n,nset,&which,pt_sides[1]);
504 /* If pts[i] is interior: done */
505 if(!below_plane[1])
506 {
507 if(test == GT_INTERIOR)
508 return(TRUE);
509 /* Remember if b[i] fell on one of the 3 defining planes */
510 if(test)
511 on_edge++;
512 }
513
514 /* Now test point 2 */
515 if(DOT(avg,p2) < 0)
516 below_plane[2] = 1;
517 else
518 below_plane[2]=0;
519 /* Test if b[i] lies in or on triangle a */
520 test = test_point_against_spherical_tri(t0,t1,t2,p2,
521 n,nset,&which,pt_sides[2]);
522
523 /* If pts[i] is interior: done */
524 if(!below_plane[2])
525 {
526 if(test == GT_INTERIOR)
527 return(TRUE);
528 /* Remember if b[i] fell on one of the 3 defining planes */
529 if(test)
530 on_edge++;
531 }
532
533 /* If all three points below separating plane: trivial reject */
534 if(below_plane[0] && below_plane[1] && below_plane[2])
535 return(FALSE);
536 /* Accept if all points lie on a triangle vertex/edge edge- accept*/
537 if(on_edge == 3)
538 return(TRUE);
539 /* Now check vertices in a against triangle b */
540 return(FALSE);
541 }
542
543
544 set_sidedness_tests(t0,t1,t2,p0,p1,p2,test,sides,nset,n)
545 FVECT t0,t1,t2,p0,p1,p2;
546 char test[3];
547 char sides[3][3];
548 char nset;
549 FVECT n[3];
550 {
551 char t;
552 double d;
553
554
555 /* p=0 */
556 test[0] = 0;
557 if(sides[0][0] == GT_INVALID)
558 {
559 if(!NTH_BIT(nset,0))
560 VCROSS(n[0],t1,t0);
561 /* Test the point for sidedness */
562 d = DOT(n[0],p0);
563 if(d >= 0)
564 SET_NTH_BIT(test[0],0);
565 }
566 else
567 if(sides[0][0] != GT_INTERIOR)
568 SET_NTH_BIT(test[0],0);
569
570 if(sides[0][1] == GT_INVALID)
571 {
572 if(!NTH_BIT(nset,1))
573 VCROSS(n[1],t2,t1);
574 /* Test the point for sidedness */
575 d = DOT(n[1],p0);
576 if(d >= 0)
577 SET_NTH_BIT(test[0],1);
578 }
579 else
580 if(sides[0][1] != GT_INTERIOR)
581 SET_NTH_BIT(test[0],1);
582
583 if(sides[0][2] == GT_INVALID)
584 {
585 if(!NTH_BIT(nset,2))
586 VCROSS(n[2],t0,t2);
587 /* Test the point for sidedness */
588 d = DOT(n[2],p0);
589 if(d >= 0)
590 SET_NTH_BIT(test[0],2);
591 }
592 else
593 if(sides[0][2] != GT_INTERIOR)
594 SET_NTH_BIT(test[0],2);
595
596 /* p=1 */
597 test[1] = 0;
598 /* t=0*/
599 if(sides[1][0] == GT_INVALID)
600 {
601 if(!NTH_BIT(nset,0))
602 VCROSS(n[0],t1,t0);
603 /* Test the point for sidedness */
604 d = DOT(n[0],p1);
605 if(d >= 0)
606 SET_NTH_BIT(test[1],0);
607 }
608 else
609 if(sides[1][0] != GT_INTERIOR)
610 SET_NTH_BIT(test[1],0);
611
612 /* t=1 */
613 if(sides[1][1] == GT_INVALID)
614 {
615 if(!NTH_BIT(nset,1))
616 VCROSS(n[1],t2,t1);
617 /* Test the point for sidedness */
618 d = DOT(n[1],p1);
619 if(d >= 0)
620 SET_NTH_BIT(test[1],1);
621 }
622 else
623 if(sides[1][1] != GT_INTERIOR)
624 SET_NTH_BIT(test[1],1);
625
626 /* t=2 */
627 if(sides[1][2] == GT_INVALID)
628 {
629 if(!NTH_BIT(nset,2))
630 VCROSS(n[2],t0,t2);
631 /* Test the point for sidedness */
632 d = DOT(n[2],p1);
633 if(d >= 0)
634 SET_NTH_BIT(test[1],2);
635 }
636 else
637 if(sides[1][2] != GT_INTERIOR)
638 SET_NTH_BIT(test[1],2);
639
640 /* p=2 */
641 test[2] = 0;
642 /* t = 0 */
643 if(sides[2][0] == GT_INVALID)
644 {
645 if(!NTH_BIT(nset,0))
646 VCROSS(n[0],t1,t0);
647 /* Test the point for sidedness */
648 d = DOT(n[0],p2);
649 if(d >= 0)
650 SET_NTH_BIT(test[2],0);
651 }
652 else
653 if(sides[2][0] != GT_INTERIOR)
654 SET_NTH_BIT(test[2],0);
655 /* t=1 */
656 if(sides[2][1] == GT_INVALID)
657 {
658 if(!NTH_BIT(nset,1))
659 VCROSS(n[1],t2,t1);
660 /* Test the point for sidedness */
661 d = DOT(n[1],p2);
662 if(d >= 0)
663 SET_NTH_BIT(test[2],1);
664 }
665 else
666 if(sides[2][1] != GT_INTERIOR)
667 SET_NTH_BIT(test[2],1);
668 /* t=2 */
669 if(sides[2][2] == GT_INVALID)
670 {
671 if(!NTH_BIT(nset,2))
672 VCROSS(n[2],t0,t2);
673 /* Test the point for sidedness */
674 d = DOT(n[2],p2);
675 if(d >= 0)
676 SET_NTH_BIT(test[2],2);
677 }
678 else
679 if(sides[2][2] != GT_INTERIOR)
680 SET_NTH_BIT(test[2],2);
681 }
682
683
684 int
685 spherical_tri_intersect(a1,a2,a3,b1,b2,b3)
686 FVECT a1,a2,a3,b1,b2,b3;
687 {
688 char which,test,n_set[2];
689 char sides[2][3][3],i,j,inext,jnext;
690 char tests[2][3];
691 FVECT n[2][3],p,avg[2];
692
693 /* Test the vertices of triangle a against the pyramid formed by triangle
694 b and the origin. If any vertex of a is interior to triangle b, or
695 if all 3 vertices of a are ON the edges of b,return TRUE. Remember
696 the results of the edge normal and sidedness tests for later.
697 */
698 if(test_vertices_for_tri_inclusion(a1,a2,a3,b1,b2,b3,
699 &(n_set[0]),n[0],avg[0],sides[1]))
700 return(TRUE);
701
702 if(test_vertices_for_tri_inclusion(b1,b2,b3,a1,a2,a3,
703 &(n_set[1]),n[1],avg[1],sides[0]))
704 return(TRUE);
705
706
707 set_sidedness_tests(b1,b2,b3,a1,a2,a3,tests[0],sides[0],n_set[1],n[1]);
708 if(tests[0][0]&tests[0][1]&tests[0][2])
709 return(FALSE);
710
711 set_sidedness_tests(a1,a2,a3,b1,b2,b3,tests[1],sides[1],n_set[0],n[0]);
712 if(tests[1][0]&tests[1][1]&tests[1][2])
713 return(FALSE);
714
715 for(j=0; j < 3;j++)
716 {
717 jnext = (j+1)%3;
718 /* IF edge b doesnt cross any great circles of a, punt */
719 if(tests[1][j] & tests[1][jnext])
720 continue;
721 for(i=0;i<3;i++)
722 {
723 inext = (i+1)%3;
724 /* IF edge a doesnt cross any great circles of b, punt */
725 if(tests[0][i] & tests[0][inext])
726 continue;
727 /* Now find the great circles that cross and test */
728 if((NTH_BIT(tests[0][i],j)^(NTH_BIT(tests[0][inext],j)))
729 && (NTH_BIT(tests[1][j],i)^NTH_BIT(tests[1][jnext],i)))
730 {
731 VCROSS(p,n[0][i],n[1][j]);
732
733 /* If zero cp= done */
734 if(ZERO_VEC3(p))
735 continue;
736 /* check above both planes */
737 if(DOT(avg[0],p) < 0 || DOT(avg[1],p) < 0)
738 {
739 NEGATE_VEC3(p);
740 if(DOT(avg[0],p) < 0 || DOT(avg[1],p) < 0)
741 continue;
742 }
743 return(TRUE);
744 }
745 }
746 }
747 return(FALSE);
748 }
749
750 int
751 ray_intersect_tri(orig,dir,v0,v1,v2,pt,wptr)
752 FVECT orig,dir;
753 FVECT v0,v1,v2;
754 FVECT pt;
755 char *wptr;
756 {
757 FVECT p0,p1,p2,p,n;
758 char type,which;
759 double pd;
760
761 point_on_sphere(p0,v0,orig);
762 point_on_sphere(p1,v1,orig);
763 point_on_sphere(p2,v2,orig);
764 type = test_single_point_against_spherical_tri(p0,p1,p2,dir,&which);
765
766 if(type)
767 {
768 /* Intersect the ray with the triangle plane */
769 tri_plane_equation(v0,v1,v2,n,&pd,FALSE);
770 intersect_ray_plane(orig,dir,n,pd,NULL,pt);
771 }
772 if(wptr)
773 *wptr = which;
774
775 return(type);
776 }
777
778
779 calculate_view_frustum(vp,hv,vv,horiz,vert,near,far,fnear,ffar)
780 FVECT vp,hv,vv;
781 double horiz,vert,near,far;
782 FVECT fnear[4],ffar[4];
783 {
784 double height,width;
785 FVECT t,nhv,nvv,ndv;
786 double w2,h2;
787 /* Calculate the x and y dimensions of the near face */
788 /* hv and vv are the horizontal and vertical vectors in the
789 view frame-the magnitude is the dimension of the front frustum
790 face at z =1
791 */
792 VCOPY(nhv,hv);
793 VCOPY(nvv,vv);
794 w2 = normalize(nhv);
795 h2 = normalize(nvv);
796 /* Use similar triangles to calculate the dimensions at z=near */
797 width = near*0.5*w2;
798 height = near*0.5*h2;
799
800 VCROSS(ndv,nvv,nhv);
801 /* Calculate the world space points corresponding to the 4 corners
802 of the front face of the view frustum
803 */
804 fnear[0][0] = width*nhv[0] + height*nvv[0] + near*ndv[0] + vp[0] ;
805 fnear[0][1] = width*nhv[1] + height*nvv[1] + near*ndv[1] + vp[1];
806 fnear[0][2] = width*nhv[2] + height*nvv[2] + near*ndv[2] + vp[2];
807 fnear[1][0] = -width*nhv[0] + height*nvv[0] + near*ndv[0] + vp[0];
808 fnear[1][1] = -width*nhv[1] + height*nvv[1] + near*ndv[1] + vp[1];
809 fnear[1][2] = -width*nhv[2] + height*nvv[2] + near*ndv[2] + vp[2];
810 fnear[2][0] = -width*nhv[0] - height*nvv[0] + near*ndv[0] + vp[0];
811 fnear[2][1] = -width*nhv[1] - height*nvv[1] + near*ndv[1] + vp[1];
812 fnear[2][2] = -width*nhv[2] - height*nvv[2] + near*ndv[2] + vp[2];
813 fnear[3][0] = width*nhv[0] - height*nvv[0] + near*ndv[0] + vp[0];
814 fnear[3][1] = width*nhv[1] - height*nvv[1] + near*ndv[1] + vp[1];
815 fnear[3][2] = width*nhv[2] - height*nvv[2] + near*ndv[2] + vp[2];
816
817 /* Now do the far face */
818 width = far*0.5*w2;
819 height = far*0.5*h2;
820 ffar[0][0] = width*nhv[0] + height*nvv[0] + far*ndv[0] + vp[0] ;
821 ffar[0][1] = width*nhv[1] + height*nvv[1] + far*ndv[1] + vp[1] ;
822 ffar[0][2] = width*nhv[2] + height*nvv[2] + far*ndv[2] + vp[2] ;
823 ffar[1][0] = -width*nhv[0] + height*nvv[0] + far*ndv[0] + vp[0] ;
824 ffar[1][1] = -width*nhv[1] + height*nvv[1] + far*ndv[1] + vp[1] ;
825 ffar[1][2] = -width*nhv[2] + height*nvv[2] + far*ndv[2] + vp[2] ;
826 ffar[2][0] = -width*nhv[0] - height*nvv[0] + far*ndv[0] + vp[0] ;
827 ffar[2][1] = -width*nhv[1] - height*nvv[1] + far*ndv[1] + vp[1] ;
828 ffar[2][2] = -width*nhv[2] - height*nvv[2] + far*ndv[2] + vp[2] ;
829 ffar[3][0] = width*nhv[0] - height*nvv[0] + far*ndv[0] + vp[0] ;
830 ffar[3][1] = width*nhv[1] - height*nvv[1] + far*ndv[1] + vp[1] ;
831 ffar[3][2] = width*nhv[2] - height*nvv[2] + far*ndv[2] + vp[2] ;
832 }
833
834
835
836
837 int
838 spherical_polygon_edge_intersect(a0,a1,b0,b1)
839 FVECT a0,a1,b0,b1;
840 {
841 FVECT na,nb,avga,avgb,p;
842 double d;
843 int sb0,sb1,sa0,sa1;
844
845 /* First test if edge b straddles great circle of a */
846 VCROSS(na,a0,a1);
847 d = DOT(na,b0);
848 sb0 = ZERO(d)?0:(d<0)? -1: 1;
849 d = DOT(na,b1);
850 sb1 = ZERO(d)?0:(d<0)? -1: 1;
851 /* edge b entirely on one side of great circle a: edges cannot intersect*/
852 if(sb0*sb1 > 0)
853 return(FALSE);
854 /* test if edge a straddles great circle of b */
855 VCROSS(nb,b0,b1);
856 d = DOT(nb,a0);
857 sa0 = ZERO(d)?0:(d<0)? -1: 1;
858 d = DOT(nb,a1);
859 sa1 = ZERO(d)?0:(d<0)? -1: 1;
860 /* edge a entirely on one side of great circle b: edges cannot intersect*/
861 if(sa0*sa1 > 0)
862 return(FALSE);
863
864 /* Find one of intersection points of the great circles */
865 VCROSS(p,na,nb);
866 /* If they lie on same great circle: call an intersection */
867 if(ZERO_VEC3(p))
868 return(TRUE);
869
870 VADD(avga,a0,a1);
871 VADD(avgb,b0,b1);
872 if(DOT(avga,p) < 0 || DOT(avgb,p) < 0)
873 {
874 NEGATE_VEC3(p);
875 if(DOT(avga,p) < 0 || DOT(avgb,p) < 0)
876 return(FALSE);
877 }
878 if((!sb0 || !sb1) && (!sa0 || !sa1))
879 return(FALSE);
880 return(TRUE);
881 }
882