contrib/brl/bbas/bvgl/bvgl_intersection.txx
Go to the documentation of this file.
00001 // This is brl/bbas/bvgl/bvgl_intersection.txx
00002 #ifndef bvgl_intersection_txx_
00003 #define bvgl_intersection_txx_
00004 //:
00005 // \file
00006 // \author Andrew Miller
00007 //
00008 //  implementation based on code from Tomas Akenine-Moller
00009 //  http://jgt.akpeters.com/papers/AkenineMoller01/tribox.html
00010 
00011 #include "bvgl_intersection.h"
00012 #include <vcl_limits.h>
00013 #include <vcl_cassert.h>
00014 #include <vcl_cmath.h>
00015 #include <vcl_algorithm.h>
00016 #include <vcl_vector.h>
00017 
00018 //helper functions
00019 namespace bvgl_intersection_helpers
00020 {
00021   //label axes (for iterating)
00022   enum Axes { X=0, Y=1, Z=2 };
00023 
00024   template <typename T>
00025   inline void cross(T dest[3], T a[3], T b[3]) {
00026     dest[0]=a[1]*b[2]-a[2]*b[1];
00027     dest[1]=a[2]*b[0]-a[0]*b[2];
00028     dest[2]=a[0]*b[1]-a[1]*b[0];
00029   }
00030 
00031   template <typename T>
00032   inline T dot(T a[3], T b[3]) { return a[0]*b[0]+a[1]*b[1]+a[2]*b[2]; }
00033 
00034   template <typename T>
00035   inline void subtract(T dest[3], T a[3], T b[3]) {
00036     dest[0] = a[0]-b[0];
00037     dest[1] = a[1]-b[1];
00038     dest[2] = a[2]-b[2];
00039   }
00040 
00041   template <typename T>
00042   inline void findMinMax(T x0, T x1, T x2, T& min, T&max) {
00043     min = max = x0;
00044     if (x1 < min) min = x1;
00045     if (x1 > max) max = x1;
00046     if (x2 < min) min = x2;
00047     if (x2 > max) max = x2;
00048   }
00049 
00050   template <typename T>
00051   bool planeBoxIntersect(T normal[3], T d, T maxbox[3]) {
00052     T vmin[3],vmax[3];
00053     for (int q=X;q<=Z;q++) {
00054       if (normal[q]>0.0f) {
00055         vmin[q]=-maxbox[q];
00056         vmax[q]=maxbox[q];
00057       }
00058       else {
00059         vmin[q]=maxbox[q];
00060         vmax[q]=-maxbox[q];
00061       }
00062     }
00063     return dot(normal,vmin)+d <= 0.0f
00064        &&  dot(normal,vmax)+d >= 0.0f;
00065   }
00066 
00067   template<int Axis0, int Axis1, typename T>
00068   inline bool axisTest(T edge[3], T fedge[3], T v0[3], T v1[3], T boxhalfsize[3]) {
00069     T p0 = edge[Axis1]*v0[Axis0] - edge[Axis0]*v0[Axis1];
00070     T p1 = edge[Axis1]*v1[Axis0] - edge[Axis0]*v1[Axis1];
00071     T min = vcl_min(p0, p1);
00072     T max = vcl_max(p0, p1);
00073     T rad = fedge[Axis1]*boxhalfsize[Axis0] + fedge[Axis0]*boxhalfsize[Axis1];
00074     return min <= rad && max >= -rad;
00075   }
00076 }
00077 
00078 
00079 //: calculate the volume of intersection between these two spheres
00080 template <typename T>
00081 bool bvgl_intersection(vgl_box_3d<T> const& A, bvgl_triangle_3d<T> const& B)
00082 {
00083   // use separating axis theorem to intersect triangle and box */
00084   using namespace bvgl_intersection_helpers;
00085 
00086   //check to see if the triangle slices the box
00087   T boxcenter[3] = { A.centroid_x(), A.centroid_y(), A.centroid_z() };
00088   T boxhalfsize[3] = { A.width()/2.0, A.height()/2.0, A.depth()/2.0 };
00089   T triverts[3][3] = { { B[0].x(), B[0].y(), B[0].z() },
00090                        { B[1].x(), B[1].y(), B[1].z() },
00091                        { B[2].x(), B[2].y(), B[2].z() } };
00092 
00093   //translate box to origin (tri verts subtracted)
00094   T v0[3],v1[3],v2[3];
00095   subtract(v0,triverts[0],boxcenter);
00096   subtract(v1,triverts[1],boxcenter);
00097   subtract(v2,triverts[2],boxcenter);
00098 
00099   // compute triangle edges
00100   T e0[3],e1[3],e2[3];
00101   subtract(e0,v1,v0);
00102   subtract(e1,v2,v1);
00103   subtract(e2,v0,v2);
00104 
00105   //Test 1: test AABB collision (Box to tri AABB)
00106   T min, max;
00107   findMinMax(v0[X],v1[X],v2[X],min,max);
00108   if (min>boxhalfsize[X] || max<-boxhalfsize[X])
00109     return false;
00110   findMinMax(v0[Y],v1[Y],v2[Y],min,max);
00111   if (min>boxhalfsize[Y] || max<-boxhalfsize[Y])
00112     return false;
00113   findMinMax(v0[Z],v1[Z],v2[Z],min,max);
00114   if (min>boxhalfsize[Z] || max<-boxhalfsize[Z])
00115     return false;
00116 
00117   //Test 2: test box/plane intersection
00118   T normal[3];
00119   cross(normal,e0,e1);
00120   T d = -dot(normal,v0);  /* plane eq: normal.x+d=0 */
00121   if (!planeBoxIntersect(normal,d,boxhalfsize))
00122     return false;
00123 
00124   //test 3: if plane/box do intersect, test bounds
00125   T fe[3] = { vcl_fabs(e0[X]), vcl_fabs(e0[Y]), vcl_fabs(e0[Z]) };
00126   if (!axisTest<Y,Z>(e0, fe, v0, v2, boxhalfsize) ||
00127       !axisTest<X,Z>(e0, fe, v0, v2, boxhalfsize) ||
00128       !axisTest<X,Y>(e0, fe, v1, v2, boxhalfsize) )
00129     return false;
00130 
00131   fe[X]=vcl_fabs(e1[X]); fe[Y]=vcl_fabs(e1[Y]); fe[Z]=vcl_fabs(e1[Z]);
00132   if (!axisTest<Y,Z>(e1, fe, v0, v2, boxhalfsize) ||
00133       !axisTest<X,Z>(e1, fe, v0, v2, boxhalfsize) ||
00134       !axisTest<X,Y>(e1, fe, v0, v1, boxhalfsize) )
00135     return false;
00136 
00137   fe[X]=vcl_fabs(e2[X]); fe[Y]=vcl_fabs(e2[Y]); fe[Z]=vcl_fabs(e2[Z]);
00138   if (!axisTest<Y,Z>(e2, fe, v0, v1, boxhalfsize) ||
00139       !axisTest<X,Z>(e2, fe, v0, v1, boxhalfsize) ||
00140       !axisTest<X,Y>(e2, fe, v1, v2, boxhalfsize) )
00141     return false;
00142 
00143   //otherwise box and tri overlap
00144   return true;
00145 }
00146 
00147 
00148 //---------------------------------------------------------------------------
00149 //Template instantiation
00150 #undef BVGL_INTERSECTION_INSTANTIATE
00151 #define BVGL_INTERSECTION_INSTANTIATE(T) \
00152 template bool bvgl_intersection(vgl_box_3d<T > const& A, bvgl_triangle_3d<T > const& B)
00153 
00154 #endif // bvgl_intersection_txx_