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