core/vgl/vgl_homg_point_3d.h
Go to the documentation of this file.
00001 // This is core/vgl/vgl_homg_point_3d.h
00002 #ifndef vgl_homg_point_3d_h_
00003 #define vgl_homg_point_3d_h_
00004 //:
00005 // \file
00006 // \brief point in projective 3D space
00007 // \author Don HAMILTON, Peter TU
00008 //
00009 // \verbatim
00010 //  Modifications
00011 //   Peter Vanroose -  4 July 2001 - Added geometric interface like vgl_point_3d
00012 //   Peter Vanroose -  2 July 2001 - Added constructor from 3 planes
00013 //   Peter Vanroose -  1 July 2001 - Renamed data to x_ y_ z_ w_ and inlined constructors
00014 //   Peter Vanroose - 27 June 2001 - Implemented operator==
00015 //   Peter Vanroose - 15 July 2002 - Added coplanar()
00016 //   Guillaume Mersch- 10 Feb 2009 - bug fix in coplanar()
00017 // \endverbatim
00018 
00019 #include <vgl/vgl_point_3d.h>
00020 #include <vgl/vgl_fwd.h> // forward declare vgl_homg_plane_3d
00021 #include <vcl_iosfwd.h>
00022 #include <vcl_cassert.h>
00023 
00024 //: Represents a homogeneous 3D point
00025 template <class Type>
00026 class vgl_homg_point_3d
00027 {
00028   // the data associated with this point
00029   Type x_;
00030   Type y_;
00031   Type z_;
00032   Type w_;
00033 
00034  public:
00035 
00036   // Constructors/Initializers/Destructor------------------------------------
00037 
00038   //: Default constructor with (0,0,0,1)
00039   inline vgl_homg_point_3d() : x_(0), y_(0), z_(0), w_((Type)1) {}
00040 
00041   //: Construct from three (nonhomogeneous) or four (homogeneous) Types.
00042   inline vgl_homg_point_3d(Type px, Type py, Type pz, Type pw = (Type)1)
00043     : x_(px), y_(py), z_(pz), w_(pw) {}
00044 
00045   //: Construct from homogeneous 4-array.
00046   inline vgl_homg_point_3d(const Type v[4]) : x_(v[0]), y_(v[1]), z_(v[2]), w_(v[3]) {}
00047 
00048   //: Construct point at infinity from direction vector.
00049   inline vgl_homg_point_3d(vgl_vector_3d<Type>const& v) : x_(v.x()), y_(v.y()), z_(v.z()), w_(0) {}
00050 
00051   //: Construct from (non-homogeneous) vgl_point_3d<Type>
00052   inline explicit vgl_homg_point_3d(vgl_point_3d<Type> const& p)
00053     : x_(p.x()), y_(p.y()), z_(p.z()), w_((Type)1) {}
00054 
00055   //: Construct from 3 planes (intersection).
00056   vgl_homg_point_3d(vgl_homg_plane_3d<Type> const& l1,
00057                     vgl_homg_plane_3d<Type> const& l2,
00058                     vgl_homg_plane_3d<Type> const& l3);
00059 
00060 #if 0
00061   // Default copy constructor
00062   inline vgl_homg_point_3d(const vgl_homg_point_3d<Type>& that)
00063     : x_(that.x()), y_(that.y()), z_(that.z()), w_(that.w()) {}
00064 
00065   // Destructor
00066   inline ~vgl_homg_point_3d() {}
00067 
00068   // Default assignment operator
00069   inline vgl_homg_point_3d<Type>& operator=(const vgl_homg_point_3d<Type>& that)
00070   {
00071     set(that.x(),that.y(),that.z(),that.w());
00072     return *this;
00073   }
00074 #endif
00075 
00076   //: the comparison operator
00077   bool operator==(vgl_homg_point_3d<Type> const& other) const;
00078   inline bool operator!=(vgl_homg_point_3d<Type>const& other)const{return !operator==(other);}
00079 
00080   // Data Access-------------------------------------------------------------
00081 
00082   inline Type x() const { return x_; }
00083   inline Type y() const { return y_; }
00084   inline Type z() const { return z_; }
00085   inline Type w() const { return w_; }
00086 
00087   //: Set \a x,y,z,w
00088   // Note that it does not make sense to set \a x, \a y, \a z or \a w individually.
00089   inline void set(Type px, Type py, Type pz, Type pw = (Type)1)
00090   { x_=px; y_=py; z_=pz; w_=pw; }
00091 
00092   inline void set(Type const p[4]) { x_=p[0]; y_=p[1]; z_=p[2]; w_=p[3]; }
00093 
00094   //: Return true iff the point is at infinity (an ideal point).
00095   // The method checks whether |w| <= tol * max(|x|,|y|,|z|)
00096   inline bool ideal(Type tol = (Type)0) const
00097   {
00098 #define vgl_Abs(x) (x<0?-x:x) // avoid #include of vcl_cmath.h AND vcl_cstdlib.h
00099     return vgl_Abs(w()) <= tol * vgl_Abs(x()) ||
00100            vgl_Abs(w()) <= tol * vgl_Abs(y()) ||
00101            vgl_Abs(w()) <= tol * vgl_Abs(z());
00102 #undef vgl_Abs
00103   }
00104 
00105   inline bool get_nonhomogeneous(double& vx, double& vy, double& vz) const
00106   {
00107     if (w() == 0)
00108     {
00109 #ifdef DEBUG
00110       vcl_cerr << "vgl_homg_point_3d::get_nonhomogeneous - point at infinity\n";
00111 #endif
00112       return false;
00113     }
00114 
00115     double hw = 1.0/w();
00116 
00117     vx = x() * hw;
00118     vy = y() * hw;
00119     vz = z() * hw;
00120 
00121     return true;
00122   }
00123 
00124   inline bool rescale_w(Type new_w = Type(1))
00125   {
00126     if (w() == 0)
00127       return false;
00128 
00129     x_ = x() * new_w / w();
00130     y_ = y() * new_w / w();
00131     z_ = z() * new_w / w();
00132     w_ = new_w;
00133 
00134     return true;
00135   }
00136 };
00137 
00138 //  +-+-+ point_3d simple I/O +-+-+
00139 
00140 //: Write "<vgl_homg_point_3d (x,y,z,w) >" to stream
00141 // \relatesalso vgl_homg_point_3d
00142 template <class Type>
00143 vcl_ostream& operator<<(vcl_ostream& s, vgl_homg_point_3d<Type> const& p);
00144 
00145 //: Read x y z w from stream
00146 // \relatesalso vgl_homg_point_3d
00147 template <class Type>
00148 vcl_istream& operator>>(vcl_istream& s, vgl_homg_point_3d<Type>& p);
00149 
00150 //  +-+-+ homg_point_3d arithmetic +-+-+
00151 
00152 //: Return true iff the point is at infinity (an ideal point).
00153 // The method checks whether |w| <= tol * max(|x|,|y|,|z|)
00154 // \relatesalso vgl_homg_point_3d
00155 template <class Type> inline
00156 bool is_ideal(vgl_homg_point_3d<Type> const& p, Type tol = (Type)0) { return p.ideal(tol); }
00157 
00158 //: Return true iff the 4 points are coplanar, i.e., they belong to a common plane
00159 // \relatesalso vgl_homg_point_3d
00160 template <class Type> inline
00161 bool coplanar(vgl_homg_point_3d<Type> const& p1,
00162               vgl_homg_point_3d<Type> const& p2,
00163               vgl_homg_point_3d<Type> const& p3,
00164               vgl_homg_point_3d<Type> const& p4)
00165 {
00166   return ((p1.x()*p2.y()-p1.y()*p2.x())*p3.z()
00167          +(p3.x()*p1.y()-p3.y()*p1.x())*p2.z()
00168          +(p2.x()*p3.y()-p2.y()*p3.x())*p1.z())*p4.w()
00169         -((p4.x()*p1.y()-p4.y()*p1.x())*p2.z()
00170          +(p2.x()*p4.y()-p2.y()*p4.x())*p1.z()
00171          +(p1.x()*p2.y()-p1.y()*p2.x())*p4.z())*p3.w()
00172         +((p3.x()*p4.y()-p3.y()*p4.x())*p1.z()
00173          +(p1.x()*p3.y()-p1.y()*p3.x())*p4.z()
00174          +(p4.x()*p1.y()-p4.y()*p1.x())*p3.z())*p2.w()
00175         -((p2.x()*p3.y()-p2.y()*p3.x())*p4.z()
00176          +(p4.x()*p2.y()-p4.y()*p2.x())*p3.z()
00177          +(p3.x()*p4.y()-p3.y()*p4.x())*p2.z())*p1.w() == 0;
00178 }
00179 
00180 //: The difference of two points is the vector from second to first point
00181 // This function is only valid if the points are not at infinity.
00182 // \relatesalso vgl_homg_point_3d
00183 template <class Type> inline
00184 vgl_vector_3d<Type> operator-(vgl_homg_point_3d<Type> const& p1,
00185                               vgl_homg_point_3d<Type> const& p2)
00186 {
00187   assert(p1.w() && p2.w());
00188   return vgl_vector_3d<Type>(p1.x()/p1.w()-p2.x()/p2.w(),
00189                              p1.y()/p1.w()-p2.y()/p2.w(),
00190                              p1.z()/p1.w()-p2.z()/p2.w());
00191 }
00192 
00193 //: Adding a vector to a point gives a new point at the end of that vector
00194 // If the point is at infinity, nothing happens.
00195 // Note that vector + point is not defined!  It's always point + vector.
00196 // \relatesalso vgl_homg_point_3d
00197 template <class Type> inline
00198 vgl_homg_point_3d<Type> operator+(vgl_homg_point_3d<Type> const& p,
00199                                   vgl_vector_3d<Type> const& v)
00200 {
00201   return vgl_homg_point_3d<Type>(p.x()+v.x()*p.w(),
00202                                  p.y()+v.y()*p.w(),
00203                                  p.z()+v.z()*p.w(), p.w());
00204 }
00205 
00206 //: Adding a vector to a point gives the point at the end of that vector
00207 // If the point is at infinity, nothing happens.
00208 // \relatesalso vgl_homg_point_3d
00209 template <class Type> inline
00210 vgl_homg_point_3d<Type>& operator+=(vgl_homg_point_3d<Type>& p,
00211                                     vgl_vector_3d<Type> const& v)
00212 {
00213   p.set(p.x()+v.x()*p.w(),p.y()+v.y()*p.w(),p.z()+v.z()*p.w(),p.w()); return p;
00214 }
00215 
00216 //: Subtracting a vector from a point is the same as adding the inverse vector
00217 // \relatesalso vgl_homg_point_3d
00218 template <class Type> inline
00219 vgl_homg_point_3d<Type> operator-(vgl_homg_point_3d<Type> const& p,
00220                                   vgl_vector_3d<Type> const& v)
00221 { return p + (-v); }
00222 
00223 //: Subtracting a vector from a point is the same as adding the inverse vector
00224 // \relatesalso vgl_homg_point_3d
00225 template <class Type> inline
00226 vgl_homg_point_3d<Type>& operator-=(vgl_homg_point_3d<Type>& p,
00227                                     vgl_vector_3d<Type> const& v)
00228 { return p += (-v); }
00229 
00230 //  +-+-+ homg_point_3d geometry +-+-+
00231 
00232 //: cross ratio of four collinear points
00233 // This number is projectively invariant, and it is the coordinate of p4
00234 // in the reference frame where p2 is the origin (coordinate 0), p3 is
00235 // the unity (coordinate 1) and p1 is the point at infinity.
00236 // This cross ratio is often denoted as ((p1, p2; p3, p4)) (which also
00237 // equals ((p3, p4; p1, p2)) or ((p2, p1; p4, p3)) or ((p4, p3; p2, p1)) )
00238 // and is calculated as
00239 //  \verbatim
00240 //                      p1 - p3   p2 - p3      (p1-p3)(p2-p4)
00241 //                      ------- : --------  =  --------------
00242 //                      p1 - p4   p2 - p4      (p1-p4)(p2-p3)
00243 // \endverbatim
00244 // If three of the given points coincide, the cross ratio is not defined.
00245 //
00246 // In this implementation, a least-squares result is calculated when the
00247 // points are not exactly collinear.
00248 //
00249 // \relatesalso vgl_homg_point_3d
00250 template <class T>
00251 double cross_ratio(vgl_homg_point_3d<T>const& p1, vgl_homg_point_3d<T>const& p2,
00252                    vgl_homg_point_3d<T>const& p3, vgl_homg_point_3d<T>const& p4);
00253 
00254 //: Are three points collinear, i.e., do they lie on a common line?
00255 // \relatesalso vgl_homg_point_3d
00256 template <class Type>
00257 bool collinear(vgl_homg_point_3d<Type> const& p1,
00258                vgl_homg_point_3d<Type> const& p2,
00259                vgl_homg_point_3d<Type> const& p3);
00260 
00261 //: Return the relative distance to p1 wrt p1-p2 of p3.
00262 //  The three points should be collinear and p2 should not equal p1.
00263 //  This is the coordinate of p3 in the affine 1D reference frame (p1,p2).
00264 //  If p3=p1, the ratio is 0; if p1=p3, the ratio is 1.
00265 //  The mid point of p1 and p2 has ratio 0.5.
00266 //  Note that the return type is double, not Type, since the ratio of e.g.
00267 //  two vgl_vector_3d<int> need not be an int.
00268 // \relatesalso vgl_homg_point_3d
00269 template <class Type> inline
00270 double ratio(vgl_homg_point_3d<Type> const& p1,
00271              vgl_homg_point_3d<Type> const& p2,
00272              vgl_homg_point_3d<Type> const& p3)
00273 { return (p3-p1)/(p2-p1); }
00274 
00275 //: Return the point at a given ratio wrt two other points.
00276 //  By default, the mid point (ratio=0.5) is returned.
00277 //  Note that the third argument is Type, not double, so the midpoint of e.g.
00278 //  two vgl_homg_point_3d<int> is not a valid concept.  But the reflection point
00279 //  of p2 wrt p1 is: in that case f=-1.
00280 // \relatesalso vgl_homg_point_3d
00281 template <class Type> inline
00282 vgl_homg_point_3d<Type> midpoint(vgl_homg_point_3d<Type> const& p1,
00283                                  vgl_homg_point_3d<Type> const& p2,
00284                                  Type f = (Type)0.5)
00285 { return p1 + f*(p2-p1); }
00286 
00287 
00288 //: Return the point at the centre of gravity of two given points.
00289 // Identical to midpoint(p1,p2).
00290 // Invalid when both points are at infinity.
00291 // If only one point is at infinity, that point is returned. inline
00292 // \relatesalso vgl_homg_point_3d
00293 template <class Type> inline
00294 vgl_homg_point_3d<Type> centre(vgl_homg_point_3d<Type> const& p1,
00295                                vgl_homg_point_3d<Type> const& p2)
00296 {
00297   return vgl_homg_point_3d<Type>(p1.x()*p2.w() + p2.x()*p1.w() ,
00298                                  p1.y()*p2.w() + p2.y()*p1.w() ,
00299                                  p1.z()*p2.w() + p2.z()*p1.w() ,
00300                                  p1.w()*p2.w()*2 );
00301 }
00302 
00303 //: Return the point at the centre of gravity of a set of given points.
00304 // There are no rounding errors when Type is e.g. int, if all w() are 1.
00305 // \relatesalso vgl_homg_point_3d
00306 template <class Type> inline
00307 vgl_homg_point_3d<Type> centre(vcl_vector<vgl_homg_point_3d<Type> > const& v)
00308 {
00309   int n=v.size();
00310   assert(n>0); // it is *not* correct to return the point (0,0) when n==0.
00311   Type x = 0, y = 0, z = 0;
00312   for (int i=0; i<n; ++i)
00313     x+=v[i].x()/v[i].w(), y+=v[i].y()/v[i].w(), z+=v[i].z()/v[i].w();
00314   return vgl_homg_point_3d<Type>(x,y,z,(Type)n);
00315 }
00316 
00317 #define VGL_HOMG_POINT_3D_INSTANTIATE(T) extern "please include vgl/vgl_homg_point_3d.txx first"
00318 
00319 #endif // vgl_homg_point_3d_h_