| 1 | greg | 1.1 | /* Copyright (c) 1986 Regents of the University of California */ | 
| 2 |  |  |  | 
| 3 |  |  | #ifndef lint | 
| 4 |  |  | static char SCCSid[] = "$SunId$ LBL"; | 
| 5 |  |  | #endif | 
| 6 |  |  |  | 
| 7 |  |  | /* | 
| 8 |  |  | *  sphere.c - routines for creating octrees for spheres. | 
| 9 |  |  | * | 
| 10 |  |  | *     7/28/85 | 
| 11 |  |  | */ | 
| 12 |  |  |  | 
| 13 |  |  | #include  "standard.h" | 
| 14 |  |  |  | 
| 15 |  |  | #include  "octree.h" | 
| 16 |  |  |  | 
| 17 |  |  | #include  "object.h" | 
| 18 |  |  |  | 
| 19 |  |  | #include  "otypes.h" | 
| 20 |  |  |  | 
| 21 |  |  | #define  ROOT3          1.732050808 | 
| 22 |  |  |  | 
| 23 |  |  | /* | 
| 24 |  |  | *      Regrettably, the algorithm for determining a cube's location | 
| 25 |  |  | *  with respect to a sphere is not simple.  First, a quick test is | 
| 26 |  |  | *  made to determine if the sphere and the bounding sphere of the cube | 
| 27 |  |  | *  are disjoint.  This of course means no intersection.  Failing this, | 
| 28 |  |  | *  we determine if the cube lies inside the sphere.  The cube is | 
| 29 |  |  | *  entirely inside if the bounding sphere on the cube is | 
| 30 |  |  | *  contained within our sphere.  This means no intersection.  Otherwise, | 
| 31 |  |  | *  if the cube radius is smaller than the sphere's and the cube center is | 
| 32 |  |  | *  inside the sphere, we assume intersection.  If these tests fail, | 
| 33 |  |  | *  we proceed as follows. | 
| 34 |  |  | *      The sphere center is located in relation to the 6 cube faces, | 
| 35 |  |  | *  and one of four things is done depending on the number of | 
| 36 |  |  | *  planes the center lies between: | 
| 37 |  |  | * | 
| 38 |  |  | *      0:  The sphere is closest to a cube corner, find the | 
| 39 |  |  | *              distance to that corner. | 
| 40 |  |  | * | 
| 41 |  |  | *      1:  The sphere is closest to a cube edge, find this | 
| 42 |  |  | *              distance. | 
| 43 |  |  | * | 
| 44 |  |  | *      2:  The sphere is closest to a cube face, find the distance. | 
| 45 |  |  | * | 
| 46 |  |  | *      3:  The sphere has its center inside the cube. | 
| 47 |  |  | * | 
| 48 |  |  | *      In cases 0-2, if the closest part of the cube is within | 
| 49 |  |  | *  the radius distance from the sphere center, we have intersection. | 
| 50 |  |  | *  If it is not, the cube must be outside the sphere. | 
| 51 |  |  | *      In case 3, there must be intersection, and no further | 
| 52 |  |  | *  tests are necessary. | 
| 53 |  |  | */ | 
| 54 |  |  |  | 
| 55 |  |  |  | 
| 56 |  |  | o_sphere(o, cu)                 /* determine if sphere intersects cube */ | 
| 57 |  |  | OBJREC  *o; | 
| 58 |  |  | register CUBE  *cu; | 
| 59 |  |  | { | 
| 60 |  |  | FVECT  v1; | 
| 61 |  |  | double  d1, d2; | 
| 62 | greg | 1.4 | register FLOAT  *fa; | 
| 63 | greg | 1.1 | register int  i; | 
| 64 |  |  | #define  cent           fa | 
| 65 |  |  | #define  rad            fa[3] | 
| 66 |  |  | /* get arguments */ | 
| 67 | greg | 1.3 | if (o->oargs.nfargs != 4) | 
| 68 |  |  | objerror(o, USER, "bad # arguments"); | 
| 69 | greg | 1.1 | fa = o->oargs.farg; | 
| 70 | greg | 1.3 | if (rad < -FTINY) { | 
| 71 |  |  | objerror(o, WARNING, "negative radius"); | 
| 72 |  |  | o->otype = o->otype == OBJ_SPHERE ? | 
| 73 |  |  | OBJ_BUBBLE : OBJ_SPHERE; | 
| 74 |  |  | rad = -rad; | 
| 75 |  |  | } else if (rad <= FTINY) | 
| 76 |  |  | objerror(o, USER, "zero radius"); | 
| 77 | greg | 1.1 |  | 
| 78 |  |  | d1 = ROOT3/2.0 * cu->cusize;    /* bounding radius for cube */ | 
| 79 |  |  |  | 
| 80 |  |  | d2 = cu->cusize * 0.5;          /* get distance between centers */ | 
| 81 |  |  | for (i = 0; i < 3; i++) | 
| 82 |  |  | v1[i] = cu->cuorg[i] + d2 - cent[i]; | 
| 83 |  |  | d2 = DOT(v1,v1); | 
| 84 |  |  |  | 
| 85 |  |  | if (d2 > (rad+d1+FTINY)*(rad+d1+FTINY)) /* quick test */ | 
| 86 | greg | 1.2 | return(O_MISS);                 /* cube outside */ | 
| 87 | greg | 1.1 |  | 
| 88 |  |  | /* check sphere interior */ | 
| 89 |  |  | if (d1 < rad) { | 
| 90 |  |  | if (d2 < (rad-d1-FTINY)*(rad-d1-FTINY)) | 
| 91 | greg | 1.2 | return(O_MISS);         /* cube inside sphere */ | 
| 92 | greg | 1.1 | if (d2 < (rad+FTINY)*(rad+FTINY)) | 
| 93 | greg | 1.2 | return(O_HIT);          /* cube center inside */ | 
| 94 | greg | 1.1 | } | 
| 95 |  |  | /* find closest distance */ | 
| 96 |  |  | for (i = 0; i < 3; i++) | 
| 97 |  |  | if (cent[i] < cu->cuorg[i]) | 
| 98 |  |  | v1[i] = cu->cuorg[i] - cent[i]; | 
| 99 |  |  | else if (cent[i] > cu->cuorg[i] + cu->cusize) | 
| 100 |  |  | v1[i] = cent[i] - (cu->cuorg[i] + cu->cusize); | 
| 101 |  |  | else | 
| 102 |  |  | v1[i] = 0; | 
| 103 |  |  | /* final intersection check */ | 
| 104 |  |  | if (DOT(v1,v1) <= (rad+FTINY)*(rad+FTINY)) | 
| 105 | greg | 1.2 | return(O_HIT); | 
| 106 | greg | 1.1 | else | 
| 107 | greg | 1.2 | return(O_MISS); | 
| 108 | greg | 1.1 | } |