core/vgl/algo/vgl_intersection.txx
Go to the documentation of this file.
00001 // This is core/vgl/algo/vgl_intersection.txx
00002 #ifndef vgl_algo_intersection_txx_
00003 #define vgl_algo_intersection_txx_
00004 //:
00005 // \file
00006 // \author Gamze Tunali
00007 
00008 #include "vgl_intersection.h"
00009 
00010 #include <vgl/algo/vgl_homg_operators_3d.h>
00011 #include <vgl/vgl_plane_3d.h>
00012 #include <vgl/vgl_homg_plane_3d.h>
00013 #include <vgl/vgl_box_3d.h>
00014 #include <vgl/vgl_point_3d.h>
00015 #include <vgl/vgl_intersection.h>
00016 #include <vgl/vgl_polygon.h>
00017 
00018 #include <vnl/vnl_matrix.h>
00019 #include <vnl/vnl_vector.h>
00020 #include <vnl/algo/vnl_matrix_inverse.h>
00021 #include <vnl/algo/vnl_svd.h>
00022 
00023 #include <vcl_cassert.h>
00024 
00025 template <class T>
00026 vgl_point_3d<T> vgl_intersection(vcl_vector<vgl_plane_3d<T> > const& p)
00027 {
00028   vcl_vector<vgl_homg_plane_3d<T> > planes;
00029   for (unsigned i=0; i<p.size(); ++i) {
00030     planes.push_back(vgl_homg_plane_3d<T> (p[i]));
00031   }
00032 
00033   return vgl_homg_operators_3d<T>::intersection(planes);
00034 }
00035 
00036 
00037 template <class T>
00038 vgl_infinite_line_3d<T>
00039 vgl_intersection(const vcl_list<vgl_plane_3d<T> >& planes)
00040 {
00041   if (planes.size() == 0)
00042     return vgl_infinite_line_3d<T>(vgl_vector_2d<T>(0,0),vgl_vector_3d<T>(0,0,0));
00043 
00044   // form the matrix of plane normal monomials
00045   vnl_matrix<double> Q(3,3,0.0);
00046   vnl_vector<double> vd(3,0.0);
00047   unsigned n = planes.size();
00048   for (typename vcl_list<vgl_plane_3d<T> >::const_iterator pit = planes.begin();
00049        pit != planes.end(); ++pit)
00050   {
00051     double a = (*pit).a(), b = (*pit).b(), c = (*pit).c(),d = (*pit).d();
00052     Q[0][0] += a*a; Q[0][1] += a*b; Q[0][2] += a*c;
00053     Q[1][1] += b*b; Q[1][2] += b*c;
00054     Q[2][2] += c*c;
00055     vd[0]-=a*d; vd[1]-=b*d; vd[2]-=c*d;
00056   }
00057   Q[1][0]=  Q[0][1];   Q[2][0]= Q[0][2];   Q[2][1]=  Q[1][2];
00058   Q/=n;
00059   vd/=n;
00060   vnl_svd<double> svd(Q);
00061 
00062   // the direction of the resulting line
00063   vnl_vector<double> t = svd.nullvector();
00064 
00065   double tx = t[0], ty = t[1], tz = t[2];
00066 
00067   // determine maximum component of t
00068   char component = 'x';
00069   if (ty>tx&&ty>tz)
00070     component = 'y';
00071   if (tz>tx&&tz>ty)
00072     component = 'z';
00073   vgl_point_3d<double> p0d;
00074   switch (component)
00075   {
00076     case 'x':
00077     {
00078       double det = Q[1][1]*Q[2][2] - Q[1][2]*Q[2][1];
00079       double neuy = vd[1]*Q[2][2]  - Q[1][2]*vd[2];
00080       double neuz = Q[1][1]*vd[2]  - vd[1]*Q[2][1];
00081       p0d.set(0.0, neuy/det, neuz/det);
00082       break;
00083     }
00084     case 'y':
00085     {
00086       double det = Q[0][0]*Q[2][2] - Q[0][2]*Q[2][0];
00087       double neux = vd[0]*Q[2][2]  - Q[0][2]*vd[2];
00088       double neuz = Q[0][0]*vd[2]  - vd[0]*Q[2][0];
00089       p0d.set(neux/det, 0.0, neuz/det);
00090       break;
00091     }
00092     case 'z':
00093     default:
00094     {
00095       double det = Q[0][0]*Q[1][1] - Q[0][1]*Q[1][0];
00096       double neux = vd[0]*Q[1][1]  - Q[0][1]*vd[1];
00097       double neuy = Q[0][0]*vd[1]  - vd[0]*Q[1][0];
00098       p0d.set(neux/det, neuy/det, 0.0);
00099       break;
00100     }
00101   }
00102   vgl_point_3d<T> pt(static_cast<T>(p0d.x()),
00103                      static_cast<T>(p0d.y()),
00104                      static_cast<T>(p0d.z()));
00105 
00106   vgl_vector_3d<T> tv(static_cast<T>(tx),
00107                       static_cast<T>(ty),
00108                       static_cast<T>(tz));
00109 
00110   return vgl_infinite_line_3d<T>(pt, tv);
00111 }
00112 
00113 template <class T>
00114 bool
00115 vgl_intersection(const vcl_list<vgl_plane_3d<T> >& planes, vcl_vector<T> ws,
00116                  vgl_infinite_line_3d<T>& line, T &residual)
00117 {
00118   if (planes.size() < 2)
00119     return false;
00120   // form the matrix of plane normal monomials
00121   vnl_matrix<double> Q(3,3,0.0);
00122   vnl_vector<double> vd(3,0.0);
00123   unsigned cnt=0;
00124   T sum_ws=0;
00125   for (typename vcl_list<vgl_plane_3d<T> >::const_iterator pit = planes.begin();
00126        pit != planes.end(); ++pit)
00127   {
00128     double a = (*pit).a(), b = (*pit).b(), c = (*pit).c(), d = (*pit).d();
00129     T w=ws[cnt++];
00130     Q[0][0] += w*a*a;
00131     Q[0][1] += w*a*b; Q[1][1] += w*b*b;
00132     Q[0][2] += w*a*c; Q[1][2] += w*b*c; Q[2][2] += w*c*c;
00133     vd[0]-=w*a*d; vd[1]-=w*b*d; vd[2]-=w*c*d;
00134     sum_ws+=w;
00135   }
00136   Q[1][0]=  Q[0][1];   Q[2][0]= Q[0][2];   Q[2][1]=  Q[1][2];
00137   Q/=sum_ws;
00138   vd/=sum_ws;
00139   vnl_svd<double> svd(Q);
00140   // the direction of the resulting line
00141   vnl_vector<double> t = svd.nullvector();
00142   double tx = t[0], ty = t[1], tz = t[2];
00143   // determine maximum component of t
00144   char component = 'x';
00145   if (ty>tx&&ty>tz)
00146     component = 'y';
00147   if (tz>tx&&tz>ty)
00148     component = 'z';
00149   vgl_point_3d<double> p0d;
00150   switch (component)
00151   {
00152     case 'x':
00153     {
00154       double det = Q[1][1]*Q[2][2] - Q[1][2]*Q[2][1];
00155       double neuy = vd[1]*Q[2][2]  - Q[1][2]*vd[2];
00156       double neuz = Q[1][1]*vd[2]  - vd[1]*Q[2][1];
00157       p0d.set(0.0, neuy/det, neuz/det);
00158       break;
00159     }
00160     case 'y':
00161     {
00162       double det = Q[0][0]*Q[2][2] - Q[0][2]*Q[2][0];
00163       double neux = vd[0]*Q[2][2]  - Q[0][2]*vd[2];
00164       double neuz = Q[0][0]*vd[2]  - vd[0]*Q[2][0];
00165       p0d.set(neux/det, 0.0, neuz/det);
00166       break;
00167     }
00168     case 'z':
00169     default:
00170     {
00171       double det = Q[0][0]*Q[1][1] - Q[0][1]*Q[1][0];
00172       double neux = vd[0]*Q[1][1]  - Q[0][1]*vd[1];
00173       double neuy = Q[0][0]*vd[1]  - vd[0]*Q[1][0];
00174       p0d.set(neux/det, neuy/det, 0.0);
00175       break;
00176     }
00177   }
00178   vgl_point_3d<T> pt(static_cast<T>(p0d.x()),
00179                      static_cast<T>(p0d.y()),
00180                      static_cast<T>(p0d.z()));
00181 
00182   vgl_vector_3d<T> tv(static_cast<T>(tx),
00183                       static_cast<T>(ty),
00184                       static_cast<T>(tz));
00185   residual=T(0);
00186   sum_ws=0;
00187   cnt=0;
00188   for (typename vcl_list<vgl_plane_3d<T> >::const_iterator pit = planes.begin();
00189        pit != planes.end(); ++pit)
00190   {
00191     double a = pit->normal().x(), b = pit->normal().y(), c = pit->normal().z();
00192     residual+=ws[cnt]*ws[cnt]*T(a*tx+b*ty+c*tz)*T(a*tx+b*ty+c*tz);
00193     sum_ws+=ws[cnt]*ws[cnt];
00194     cnt++;
00195   }
00196 
00197   if (cnt>0)
00198   {
00199     residual/=sum_ws;
00200     residual=vcl_sqrt(residual);
00201   }
00202   line=vgl_infinite_line_3d<T>(pt, tv);
00203   return true;
00204 }
00205 
00206 
00207 template <class T>
00208 bool vgl_intersection(vgl_box_3d<T> const& b, vcl_list<vgl_point_3d<T> >& poly)
00209 {
00210   // check if two bounding boxes intersect
00211   // find the bounding box of the polygon
00212   assert(poly.size() >= 3);
00213 
00214   vgl_box_3d<T> bb;
00215   typename vcl_list<vgl_point_3d<T> >::iterator it=poly.begin();
00216   for (; it != poly.end(); ++it)
00217     bb.add(*it);
00218 
00219   vgl_box_3d<T> inters = vgl_intersection(b, bb);
00220   if (inters.is_empty())
00221     return false;
00222 
00223   // check if the polygon corners inside the box
00224   for (it=poly.begin(); it != poly.end(); ++it) {
00225     if (b.contains(*it))
00226       return true;
00227   }
00228 
00229   it=poly.begin();
00230   // get the first 3 points to create a plane
00231   vgl_point_3d<T> p0=*it; ++it;
00232   vgl_point_3d<T> p1=*it; ++it;
00233   vgl_point_3d<T> p2=*it; ++it;
00234   // create a plane from polygon
00235   vgl_plane_3d<T> poly_plane(p0,p1,p2);
00236   if (!vgl_intersection<T>(b, poly_plane))
00237     return false;
00238 
00239   // now we do a 3D transformation of the polygon and the box center to the plane
00240   // where polygon resides, so that we can do 2D poly-point test
00241   vgl_vector_3d<T> n = poly_plane.normal();
00242   n=normalize(n);
00243   vgl_vector_3d<T> u(p1-p0);
00244   u=normalize(u);
00245   vgl_vector_3d<T> v = cross_product(n,u);
00246 
00247   vnl_matrix<T> M(3,3);
00248   M.put(0,0,u.x());
00249   M.put(1,0,u.y());
00250   M.put(2,0,u.z());
00251   M.put(0,1,v.x());
00252   M.put(1,1,v.y());
00253   M.put(2,1,v.z());
00254   M.put(0,2,n.x());
00255   M.put(1,2,n.y());
00256   M.put(2,2,n.z());
00257 
00258   vnl_matrix_inverse<T> R(M);
00259 
00260   // transform the polygon
00261   vgl_polygon<T> poly2d(1);  // with one sheet
00262   for (it=poly.begin(); it != poly.end(); ++it) {
00263     vgl_vector_3d<T> temp(*it-p0);
00264     vnl_matrix<T> tv(3,1);
00265     tv.put(0,0,temp.x());
00266     tv.put(1,0,temp.y());
00267     tv.put(2,0,temp.z());
00268     vnl_matrix<T> pi = R*tv;
00269     poly2d.push_back(pi.get(0,0), pi.get(1,0));
00270   }
00271 
00272   vgl_point_3d<T> c=b.centroid();
00273   vnl_matrix<T> tv(3,1);
00274   tv.put(0,0,c.x()-p0.x());
00275   tv.put(1,0,c.y()-p0.y());
00276   tv.put(2,0,c.z()-p0.z());
00277   vnl_matrix<T> ci(R*tv);
00278   return poly2d.contains(ci.get(0,0),ci.get(1,0));
00279 }
00280 
00281 #undef VGL_ALGO_INTERSECTION_INSTANTIATE
00282 #define VGL_ALGO_INTERSECTION_INSTANTIATE(T) \
00283 template vgl_point_3d<T > vgl_intersection(const vcl_vector<vgl_plane_3d<T > >&); \
00284 template bool vgl_intersection(vgl_box_3d<T > const&, vcl_list<vgl_point_3d<T > >&); \
00285 template vgl_infinite_line_3d<T > vgl_intersection(const vcl_list<vgl_plane_3d<T > >& planes); \
00286 template bool vgl_intersection(const vcl_list<vgl_plane_3d<T > >& planes, vcl_vector<T > ws,vgl_infinite_line_3d<T >&,T& residual)
00287 
00288 #endif // vgl_algo_intersection_txx_