TriangleCube.cc
上传用户:kellyonhid
上传日期:2013-10-12
资源大小:932k
文件大小:10k
源码类别:

3D图形编程

开发平台:

Visual C++

  1. //###############################################################
  2. // TriangleCube.cc
  3. // Kari Pulli
  4. // Mon Nov 23 14:41:10 CET 1998
  5. // 
  6. // Detect an intersection of a cube and a triangle
  7. // Based on code from Graphics Gems III, Douglas Voorhies
  8. //###############################################################
  9. #include "Pnt3.h"
  10. #define SIGN3( A ) (((A)[0]<0)?4:0 | ((A)[1]<0)?2:0 | ((A)[2]<0)?1:0)
  11. #define MIN3(a,b,c) ((((a)<(b))&&((a)<(c))) ? (a) : (((b)<(c)) ? (b) : (c)))
  12. #define MAX3(a,b,c) ((((a)>(b))&&((a)>(c))) ? (a) : (((b)>(c)) ? (b) : (c)))
  13. /*___________________________________________________________________________*/
  14. /* Which of the six face-plane(s) is point P outside of? */
  15. static long 
  16. face_plane(const Pnt3 &p)
  17. {
  18.   long outcode = 0;
  19.   if (p[0] >  .5) outcode |= 0x01;
  20.   if (p[0] < -.5) outcode |= 0x02;
  21.   if (p[1] >  .5) outcode |= 0x04;
  22.   if (p[1] < -.5) outcode |= 0x08;
  23.   if (p[2] >  .5) outcode |= 0x10;
  24.   if (p[2] < -.5) outcode |= 0x20;
  25.   return outcode;
  26. }
  27. /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  28. /* Which of the twelve edge plane(s) is point P outside of? */
  29. static long 
  30. bevel_2d(const Pnt3 &p)
  31. {
  32.   long outcode = 0;
  33.   if ( p[0] + p[1] > 1.0) outcode |= 0x001;
  34.   if ( p[0] - p[1] > 1.0) outcode |= 0x002;
  35.   if (-p[0] + p[1] > 1.0) outcode |= 0x004;
  36.   if (-p[0] - p[1] > 1.0) outcode |= 0x008;
  37.   if ( p[0] + p[2] > 1.0) outcode |= 0x010;
  38.   if ( p[0] - p[2] > 1.0) outcode |= 0x020;
  39.   if (-p[0] + p[2] > 1.0) outcode |= 0x040;
  40.   if (-p[0] - p[2] > 1.0) outcode |= 0x080;
  41.   if ( p[1] + p[2] > 1.0) outcode |= 0x100;
  42.   if ( p[1] - p[2] > 1.0) outcode |= 0x200;
  43.   if (-p[1] + p[2] > 1.0) outcode |= 0x400;
  44.   if (-p[1] - p[2] > 1.0) outcode |= 0x800;
  45.   return outcode;
  46. }
  47. /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  48. /* Which of the eight corner plane(s) is point P outside of? */
  49. static long 
  50. bevel_3d(const Pnt3 &p)
  51. {
  52.   long outcode = 0;
  53.   if (( p[0] + p[1] + p[2]) > 1.5) outcode |= 0x01;
  54.   if (( p[0] + p[1] - p[2]) > 1.5) outcode |= 0x02;
  55.   if (( p[0] - p[1] + p[2]) > 1.5) outcode |= 0x04;
  56.   if (( p[0] - p[1] - p[2]) > 1.5) outcode |= 0x08;
  57.   if ((-p[0] + p[1] + p[2]) > 1.5) outcode |= 0x10;
  58.   if ((-p[0] + p[1] - p[2]) > 1.5) outcode |= 0x20;
  59.   if ((-p[0] - p[1] + p[2]) > 1.5) outcode |= 0x40;
  60.   if ((-p[0] - p[1] - p[2]) > 1.5) outcode |= 0x80;
  61.   return outcode;
  62. }
  63. /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  64. /* Test the point "alpha" of the way from P1 to P2 */
  65. /* See if it is on a face of the cube              */
  66. /* Consider only faces in "mask"                   */
  67. static bool
  68. point_on_face(const Pnt3 &p1, const Pnt3 &p2, float alpha, long mask)
  69. {
  70.   Pnt3 plane_point;
  71.   plane_point.lerp(alpha, p1, p2);
  72.   return (face_plane(plane_point) & mask);
  73. }
  74. /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  75. /* Compute intersection of P1 --> P2 line segment with face planes */
  76. /* Then test intersection point to see if it is on cube face       */
  77. /* Consider only face planes in "outcode_diff"                     */
  78. /* Note: Zero bits in "outcode_diff" means face line is outside of */
  79. static bool
  80. line_on_face(const Pnt3 &p1, const Pnt3 &p2, long outcode_diff)
  81. {
  82.   if (0x01 & outcode_diff)
  83.     if (point_on_face(p1,p2,( .5-p1[0])/(p2[0]-p1[0]),0x3e)) return true;
  84.   if (0x02 & outcode_diff)
  85.     if (point_on_face(p1,p2,(-.5-p1[0])/(p2[0]-p1[0]),0x3d)) return true;
  86.   if (0x04 & outcode_diff)
  87.     if (point_on_face(p1,p2,( .5-p1[1])/(p2[1]-p1[1]),0x3b)) return true;
  88.   if (0x08 & outcode_diff)
  89.     if (point_on_face(p1,p2,(-.5-p1[1])/(p2[1]-p1[1]),0x37)) return true;
  90.   if (0x10 & outcode_diff)
  91.     if (point_on_face(p1,p2,( .5-p1[2])/(p2[2]-p1[2]),0x2f)) return true;
  92.   if (0x20 & outcode_diff)
  93.     if (point_on_face(p1,p2,(-.5-p1[2])/(p2[2]-p1[2]),0x1f)) return true;
  94.   return false;
  95. }
  96. /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  97. /* Test if 3D point is inside 3D triangle */
  98. static bool
  99. point_triangle_intersection(const Pnt3 &p, 
  100.     const Pnt3 &v1, const Pnt3 &v2, const Pnt3 &v3)
  101. {
  102.   /* First, a quick bounding-box test:                               */
  103.   /* If P is outside triangle bbox, there cannot be an intersection. */
  104.   if (p[0] > MAX3(v1[0], v2[0], v3[0])) return true;  
  105.   if (p[1] > MAX3(v1[1], v2[1], v3[1])) return true;
  106.   if (p[2] > MAX3(v1[2], v2[2], v3[2])) return true;
  107.   if (p[0] < MIN3(v1[0], v2[0], v3[0])) return true;
  108.   if (p[1] < MIN3(v1[1], v2[1], v3[1])) return true;
  109.   if (p[2] < MIN3(v1[2], v2[2], v3[2])) return true;
  110.   /* For each triangle side, make a vector out of it by subtracting vertexes; */
  111.   /* make another vector from one vertex to point P.                          */
  112.   /* The crossproduct of these two vectors is orthogonal to both and the      */
  113.   /* signs of its X,Y,Z components indicate whether P was to the inside or    */
  114.   /* to the outside of this triangle side.                                    */
  115.   long sign12 = SIGN3(cross(v2,p,v1)); // Extract X,Y,Z signs as 0...7 integer
  116.   long sign23 = SIGN3(cross(v3,p,v2));
  117.   long sign31 = SIGN3(cross(v1,p,v3));
  118.   /* If all three crossproduct vectors agree in their component signs,  */
  119.   /* then the point must be inside all three.                           */
  120.   /* P cannot be OUTSIDE all three sides simultaneously.                */
  121.   return ((sign12 != sign23) || (sign23 != sign31));
  122. }
  123. /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
  124. //
  125. // the main routine
  126. // true if triangle t1,t2,t3 is outside a cube 
  127. // centered at c with length of a side s,
  128. // false if the triangle intersects cube
  129. //
  130. bool
  131. tri_outside_of_cube(const Pnt3 &c, float s,
  132.     const Pnt3 &t1, const Pnt3 &t2, const Pnt3 &t3)
  133. {
  134.   long v1_test,v2_test,v3_test;
  135.   /* First compare all three vertexes with all six face-planes */
  136.   /* If any vertex is inside the cube, return immediately!     */
  137.   Pnt3 v1((t1[0]-c[0])/s, (t1[1]-c[1])/s, (t1[2]-c[2])/s);
  138.   if (!(v1_test = face_plane(v1))) return false;
  139.   Pnt3 v2((t2[0]-c[0])/s, (t2[1]-c[1])/s, (t2[2]-c[2])/s);
  140.   if (!(v2_test = face_plane(v2))) return false;
  141.   Pnt3 v3((t3[0]-c[0])/s, (t3[1]-c[1])/s, (t3[2]-c[2])/s);
  142.   if (!(v3_test = face_plane(v3))) return false;
  143.   /* If all three vertexes were outside of one or more face-planes, */
  144.   /* return immediately with a trivial rejection!                   */
  145.   if ((v1_test & v2_test & v3_test) != 0) return true;
  146.   /* Now do the same trivial rejection test for the 12 edge planes */
  147.   v1_test |= bevel_2d(v1) << 8; 
  148.   v2_test |= bevel_2d(v2) << 8; 
  149.   v3_test |= bevel_2d(v3) << 8;
  150.   if ((v1_test & v2_test & v3_test) != 0) return true;  
  151.   /* Now do the same trivial rejection test for the 8 corner planes */
  152.   v1_test |= bevel_3d(v1) << 24; 
  153.   v2_test |= bevel_3d(v2) << 24; 
  154.   v3_test |= bevel_3d(v3) << 24; 
  155.   if ((v1_test & v2_test & v3_test) != 0) return true;   
  156.   /* If vertex 1 and 2, as a pair, cannot be trivially rejected */
  157.   /* by the above tests, then see if the v1-->v2 triangle edge  */
  158.   /* intersects the cube.  Do the same for v1-->v3 and v2-->v3. */
  159.   /* Pass to the intersection algorithm the "OR" of the outcode */
  160.   /* bits, so that only those cube faces which are spanned by   */
  161.   /* each triangle edge need be tested.                         */
  162.   if ((v1_test & v2_test) == 0)
  163.     if (line_on_face(v1,v2,v1_test|v2_test)) return false;
  164.   if ((v1_test & v3_test) == 0)
  165.     if (line_on_face(v1,v3,v1_test|v3_test)) return false;
  166.   if ((v2_test & v3_test) == 0)
  167.     if (line_on_face(v2,v3,v2_test|v3_test)) return false;
  168.   /* By now, we know that the triangle is not off to any side,     */
  169.   /* and that its sides do not penetrate the cube.  We must now    */
  170.   /* test for the cube intersecting the interior of the triangle.  */
  171.   /* We do this by looking for intersections between the cube      */
  172.   /* diagonals and the triangle...first finding the intersection   */
  173.   /* of the four diagonals with the plane of the triangle, and     */
  174.   /* then if that intersection is inside the cube, pursuing        */
  175.   /* whether the intersection point is inside the triangle itself. */
  176.   /* To find plane of the triangle, first perform crossproduct on  */
  177.   /* two triangle side vectors to compute the normal vector.       */  
  178.                                 
  179.   Pnt3 norm = cross(v2,v3,v1);
  180.   /* The normal vector "norm" X,Y,Z components are the coefficients */
  181.   /* of the triangles AX + BY + CZ + D = 0 plane equation.  If we   */
  182.   /* solve the plane equation for X=Y=Z (a diagonal), we get        */
  183.   /* -D/(A+B+C) as a metric of the distance from cube center to the */
  184.   /* diagonal/plane intersection.  If this is between -0.5 and 0.5, */
  185.   /* the intersection is inside the cube.  If so, we continue by    */
  186.   /* doing a point/triangle intersection.                           */
  187.   /* Do this for all four diagonals.                                */
  188.   
  189.   float d = dot(norm, v1);
  190.   Pnt3 hit;
  191.   hit[0] = hit[1] = hit[2] = d / (norm[0] + norm[1] + norm[2]);
  192.   if (fabsf(hit[0]) <= 0.5)
  193.     if (point_triangle_intersection(hit,v1,v2,v3) == false) 
  194.       return false;
  195.   hit[2] = -(hit[0] = hit[1] = d / (norm[0] + norm[1] - norm[2]));
  196.   if (fabsf(hit[0]) <= 0.5)
  197.     if (point_triangle_intersection(hit,v1,v2,v3) == false) 
  198.       return false;
  199.   hit[1] = -(hit[0] = hit[2] = d / (norm[0] - norm[1] + norm[2]));
  200.   if (fabsf(hit[0]) <= 0.5)
  201.     if (point_triangle_intersection(hit,v1,v2,v3) == false) 
  202.       return false;
  203.   hit[1] = hit[2] = -(hit[0] = d / (norm[0] - norm[1] - norm[2]));
  204.   if (fabsf(hit[0]) <= 0.5)
  205.     if (point_triangle_intersection(hit,v1,v2,v3) == false) 
  206.       return false;
  207.   /* No edge touched the cube; no cube diagonal touched the triangle. */
  208.   /* We're done...there was no intersection.                          */
  209.   return true;
  210. }
  211. #ifdef TRICUBEMAIN
  212. void
  213. main(void)
  214. {
  215.   Pnt3 ctr(10,10,10);
  216.   float s = 2;
  217.   SHOW(ctr);
  218.   SHOW(s);
  219.   Pnt3 a(10.95, 10.95, 10.95);
  220.   Pnt3 b;
  221.   Pnt3 c(1,3,5);
  222.   Pnt3 d(13.0001,10,10);
  223.   Pnt3 e(10,13.0001,10);
  224.   Pnt3 f(10,10,13.0001);
  225.   Pnt3 g(10,10,12.99);
  226.   SHOW(a);
  227.   SHOW(b);
  228.   SHOW(c);
  229.   SHOW(d);
  230.   SHOW(e);
  231.   SHOW(f);
  232.   SHOW(g);
  233.   SHOW(tri_outside_of_cube(ctr,s,a,b,c));
  234.   SHOW(tri_outside_of_cube(ctr,s,d,b,c));
  235.   SHOW(tri_outside_of_cube(ctr,s,d,e,c));
  236.   SHOW(tri_outside_of_cube(ctr,s,d,e,f));
  237.   SHOW(tri_outside_of_cube(ctr,s,d,e,g));
  238.   SHOW(tri_outside_of_cube(ctr,s,Pnt3(), Pnt3(4,5,6), Pnt3(6,7,8)));
  239. }
  240. #endif