core/vgl/vgl_plane_3d.txx
Go to the documentation of this file.
00001 // This is core/vgl/vgl_plane_3d.txx
00002 #ifndef vgl_plane_3d_txx_
00003 #define vgl_plane_3d_txx_
00004 //:
00005 // \file
00006 
00007 #include "vgl_plane_3d.h"
00008 #include <vgl/vgl_homg_plane_3d.h>
00009 #include <vgl/vgl_point_3d.h>
00010 #include <vgl/vgl_point_2d.h>
00011 #include <vgl/vgl_closest_point.h>
00012 #include <vgl/vgl_distance.h>
00013 //#include <vgl/vgl_tolerance.h>
00014 #include <vcl_cmath.h>
00015 #include <vcl_cassert.h>
00016 #include <vcl_iostream.h>
00017 
00018 //: Construct from homogeneous plane
00019 template <class T>
00020 vgl_plane_3d<T>::vgl_plane_3d(vgl_homg_plane_3d<T> const& p)
00021   : a_(p.a()), b_(p.b()), c_(p.c()), d_(p.d()) {assert (a_||b_||c_);}
00022 
00023 //: Construct from three points
00024 template <class T>
00025 vgl_plane_3d<T>::vgl_plane_3d (vgl_point_3d<T> const& p1,
00026                                vgl_point_3d<T> const& p2,
00027                                vgl_point_3d<T> const& p3)
00028 : a_(p2.y()*p3.z()-p2.z()*p3.y()
00029     +p3.y()*p1.z()-p3.z()*p1.y()
00030     +p1.y()*p2.z()-p1.z()*p2.y())
00031 , b_(p2.z()*p3.x()-p2.x()*p3.z()
00032     +p3.z()*p1.x()-p3.x()*p1.z()
00033     +p1.z()*p2.x()-p1.x()*p2.z())
00034 , c_(p2.x()*p3.y()-p2.y()*p3.x()
00035     +p3.x()*p1.y()-p3.y()*p1.x()
00036     +p1.x()*p2.y()-p1.y()*p2.x())
00037 , d_(p1.x()*(p2.z()*p3.y()-p2.y()*p3.z())
00038     +p2.x()*(p3.z()*p1.y()-p3.y()*p1.z())
00039     +p3.x()*(p1.z()*p2.y()-p1.y()*p2.z()))
00040 {
00041   assert(a_||b_||c_); // points should not be collinear or coinciding
00042 }
00043 
00044 //: Construct from normal and a point
00045 template <class T>
00046 vgl_plane_3d<T>::vgl_plane_3d(vgl_vector_3d<T> const& n,
00047                               vgl_point_3d<T> const& p)
00048  : a_(n.x()), b_(n.y()), c_(n.z()), d_(-(n.x()*p.x()+n.y()*p.y()+n.z()*p.z()))
00049 {
00050   assert(a_||b_||c_); // normal vector should not be the null vector
00051 }
00052 
00053 //: Return true if p is on the plane
00054 template <class T>
00055 bool vgl_plane_3d<T>::contains(vgl_point_3d<T> const& p, T tol) const
00056 {
00057   //to maintain a consistent distance metric the plane should be normalized
00058   vgl_vector_3d<T> n(a_, b_, c_), pv(p.x(), p.y(), p.z());
00059   T dist = (dot_product(n,pv) + d_) / static_cast<T>(length(n));
00060   return dist >= -tol && dist <= tol;
00061 }
00062 
00063 template <class T>
00064 bool vgl_plane_3d<T>::operator==(vgl_plane_3d<T> const& p) const
00065 {
00066   return (this==&p) ||
00067          (   (a()*p.b()==p.a()*b())
00068           && (a()*p.c()==p.a()*c())
00069           && (a()*p.d()==p.a()*d())
00070           && (b()*p.c()==p.b()*c())
00071           && (b()*p.d()==p.b()*d())
00072           && (c()*p.d()==p.c()*d()) );
00073 }
00074 
00075 #define vp(os,v,s) { os<<' '; if ((v)>0) os<<'+'; if ((v)&&!s[0]) os<<(v); else { \
00076                      if ((v)==-1) os<<'-';\
00077                      else if ((v)!=0&&(v)!=1) os<<(v);\
00078                      if ((v)!=0) os<<' '<<s; } }
00079 
00080 template <class T>
00081 vcl_ostream& operator<<(vcl_ostream& os, const vgl_plane_3d<T>& p)
00082 {
00083   os << "<vgl_plane_3d"; vp(os,p.a(),"x"); vp(os,p.b(),"y"); vp(os,p.c(),"z");
00084   vp(os,p.d(),""); return os << " = 0 >";
00085 }
00086 
00087 #undef vp
00088 
00089 template <class T>
00090 vcl_istream& operator>>(vcl_istream& is, vgl_plane_3d<T>& p)
00091 {
00092   if (! is.good()) return is; // (TODO: should throw an exception)
00093   bool paren = false;
00094   bool formatted = false;
00095   T a, b, c, d;
00096   is >> vcl_ws; // jump over any leading whitespace
00097   if (is.eof()) return is; // nothing to be set because of EOF (TODO: should throw an exception)
00098   if (is.peek() == '(') { is.ignore(); paren=true; }
00099   is >> vcl_ws >> a >> vcl_ws;
00100   if (is.eof()) return is;
00101   if (is.peek() == ',') is.ignore();
00102   else if (is.peek() == 'x') { is.ignore(); formatted=true; }
00103   is >> vcl_ws >> b >> vcl_ws;
00104   if (is.eof()) return is;
00105   if (formatted) {
00106     if (is.eof()) return is;
00107     if (is.peek() == 'y') is.ignore();
00108     else                  return is; // formatted input incorrect (TODO: throw an exception)
00109   }
00110   else if (is.peek() == ',') is.ignore();
00111   is >> vcl_ws >> c >> vcl_ws;
00112   if (is.eof()) return is;
00113   if (formatted) {
00114     if (is.eof()) return is;
00115     if (is.peek() == 'z') is.ignore();
00116     else                  return is; // formatted input incorrect (TODO: throw an exception)
00117   }
00118   else if (is.peek() == ',') is.ignore();
00119   is >> vcl_ws >> d >> vcl_ws;
00120   if (paren) {
00121     if (is.eof()) return is;
00122     if (is.peek() == ')') is.ignore();
00123     else                  return is; // closing parenthesis is missing (TODO: throw an exception)
00124   }
00125   if (formatted) {
00126     if (is.eof()) return is;
00127     if (is.peek() == '=') is.ignore();
00128     else                  return is; // closing parenthesis is missing (TODO: throw an exception)
00129     is >> vcl_ws;
00130     if (is.peek() == '0') is.ignore();
00131     else                  return is; // closing parenthesis is missing (TODO: throw an exception)
00132   }
00133   p.set(a,b,c,d);
00134   return is;
00135 }
00136 
00137 template <class T>
00138 void vgl_plane_3d<T>::
00139 plane_coord_vectors(vgl_vector_3d<T>& uvec, vgl_vector_3d<T>& vvec) const
00140 {
00141   vgl_vector_3d<T> Y((T)0, (T)1, (T)0);
00142   vgl_vector_3d<T> n = this->normal();
00143   T dp = (T)1 - vcl_fabs(dot_product(n, Y));
00144   T tol = ((T)1)/((T)10);
00145   if (dp>tol)//ok to use the Y axis to form the coordinate system
00146   {
00147     uvec = normalized(cross_product(Y, n));
00148     vvec = normalized(cross_product(n, uvec));
00149   }
00150   else { // the normal is parallel to the Y axis
00151     vgl_vector_3d<T> Z((T)0, (T)0, (T)1);
00152     uvec = normalized(cross_product(n, Z));
00153     vvec = normalized(cross_product(uvec, n));
00154   }
00155 }
00156 
00157 template <class T>
00158 bool vgl_plane_3d<T>::plane_coords(vgl_point_3d<T> const& p3d,
00159                                    vgl_point_2d<T>& p2d, T tol) const
00160 {
00161   // check if point is on the plane
00162   vgl_point_3d<T> pt_on_plane = vgl_closest_point(p3d, *this);
00163   double dist = vgl_distance(p3d, pt_on_plane), dtol = static_cast<double>(tol);
00164   if (dist>dtol)
00165    return false;
00166   // use the plane point to compute coordinates
00167   // construct the axis vectors
00168   vgl_vector_3d<T> Y((T)0, (T)1, (T)0);
00169   vgl_point_3d<T> origin_pt = vgl_closest_point_origin(*this);
00170   vgl_vector_3d<T> p = pt_on_plane - origin_pt;
00171   vgl_vector_3d<T> uvec, vvec;
00172   this->plane_coord_vectors(uvec, vvec);
00173   T u = dot_product(uvec, p), v = dot_product(vvec, p);
00174   p2d.set(u, v);
00175   return true;
00176 }
00177 
00178 template <class T>
00179 vgl_point_3d<T>
00180 vgl_plane_3d<T>::world_coords(vgl_point_2d<T> const& p2d) const
00181 {
00182   vgl_point_3d<T> origin_pt = vgl_closest_point_origin(*this);
00183   vgl_vector_3d<T> uvec, vvec;
00184   this->plane_coord_vectors(uvec, vvec);
00185   vgl_point_3d<T> p3d = origin_pt + uvec*p2d.x() + vvec*p2d.y();
00186   return p3d;
00187 }
00188 
00189 #undef VGL_PLANE_3D_INSTANTIATE
00190 #define VGL_PLANE_3D_INSTANTIATE(T) \
00191 template class vgl_plane_3d<T >; \
00192 template vcl_ostream& operator<<(vcl_ostream&, vgl_plane_3d<T >const&); \
00193 template vcl_istream& operator>>(vcl_istream&, vgl_plane_3d<T >&)
00194 
00195 #endif // vgl_plane_3d_txx_