core/vgl/vgl_line_2d.txx
Go to the documentation of this file.
00001 // This is core/vgl/vgl_line_2d.txx
00002 #ifndef vgl_line_2d_txx_
00003 #define vgl_line_2d_txx_
00004 //:
00005 // \file
00006 
00007 #include "vgl_line_2d.h"
00008 #include <vcl_cmath.h>     // vcl_sqrt()
00009 #include <vcl_cassert.h>
00010 #include <vcl_iostream.h>
00011 #include <vgl/vgl_point_2d.h>
00012 #include <vgl/vgl_homg_line_2d.h>
00013 
00014 //: line through two given points
00015 template <class Type>
00016 vgl_line_2d<Type>::vgl_line_2d (vgl_point_2d<Type> const& p1, vgl_point_2d<Type> const& p2)
00017 : a_ ( p1.y() - p2.y() )
00018 , b_ ( p2.x() - p1.x() )
00019 , c_ ( p1.x() * p2.y() - p1.y() * p2.x() )
00020 {
00021   assert(a_||b_); // two points were distinct
00022 }
00023 
00024 //: line defined by one point and one vector
00025 template <class Type>
00026 vgl_line_2d<Type>::vgl_line_2d (vgl_point_2d<Type> const& p, vgl_vector_2d<Type> const& v)
00027 : a_ ( -v.y() )
00028 , b_ ( v.x() )
00029 , c_ ( -a_*p.x() - b_*p.y() )
00030 {
00031 }
00032 
00033 template <class Type>
00034 vgl_line_2d<Type>::vgl_line_2d (vgl_homg_line_2d<Type> const& l)
00035  : a_(l.a()) , b_(l.b()) , c_(l.c())
00036 {
00037   //JLM I see no reason to prohibit lines through the origin
00038   //  assert(c_);
00039 }
00040 
00041 //: Get two points on the line.
00042 // These two points are normally the intersections
00043 // with the Y axis and X axis, respectively.  When the line is parallel to one
00044 // of these, the point with \a y=1 or \a x=1, resp. are taken.
00045 // When the line goes through the origin, the second point is \a (b,-a).
00046 template <class Type>
00047 void vgl_line_2d<Type>::get_two_points(vgl_point_2d<Type> &p1, vgl_point_2d<Type> &p2) const
00048 {
00049   if (b() == 0)       p1.set(-c()/a(), 1);
00050   else                p1.set(0, -c()/b());
00051   if (a() == 0)       p2.set(1, -c()/b());
00052   else if ( c() == 0) p2.set(b(), -a());
00053   else                p2.set(-c()/a(), 0);
00054 }
00055 
00056 template <class Type>
00057 double vgl_line_2d<Type>::slope_degrees() const
00058 {
00059   static const double deg_per_rad = 45.0/vcl_atan2(1.0,1.0);
00060   // do special cases separately, to avoid rounding errors:
00061   if (a() == 0) return b()<0 ? 0.0 : 180.0;
00062   if (b() == 0) return a()<0 ? -90.0 : 90.0;
00063   if (a() == b()) return a()<0 ? -45.0 : 135.0;
00064   if (a()+b() == 0) return a()<0 ? -135.0 : 45.0;
00065   // general case:
00066   return deg_per_rad * vcl_atan2(double(a()),-double(b()));
00067 }
00068 
00069 template <class Type>
00070 double vgl_line_2d<Type>::slope_radians() const
00071 {
00072   return vcl_atan2(double(a()),-double(b()));
00073 }
00074 
00075 template <class Type>
00076 bool vgl_line_2d<Type>::normalize()
00077 {
00078   double mag = a_*a_ + b_*b_;
00079   if (mag==1.0) return true;
00080   if (mag==0.0) return false;
00081   mag = 1.0/vcl_sqrt(mag);
00082   a_ = Type(a_*mag);
00083   b_ = Type(b_*mag);
00084   c_ = Type(c_*mag);
00085   mag = a_*a_ + b_*b_;
00086   // return false when normalisation did not succeed, e.g. when Type == int:
00087   return mag>0.99 && mag<1.01;
00088 }
00089 
00090 #define vp(os,v,s) { os<<' '; if ((v)>0) os<<'+'; if ((v)&&!s[0]) os<<(v); else { \
00091                      if ((v)==-1) os<<'-';\
00092                      else if ((v)!=0&&(v)!=1) os<<(v);\
00093                      if ((v)!=0) os<<' '<<s; } }
00094 
00095 //: Write line description to stream: "<vgl_line_2d ax+by+c=0>"
00096 template <class Type>
00097 vcl_ostream&  operator<<(vcl_ostream& os, vgl_line_2d<Type> const& l)
00098 {
00099   os << "<vgl_line_2d"; vp(os,l.a(),"x"); vp(os,l.b(),"y"); vp(os,l.c(),"");
00100   return os << " = 0 >";
00101 }
00102 
00103 #undef vp
00104 
00105 //: Read in three line parameters from stream
00106 //  Either just reads three blank-separated numbers,
00107 //  or reads three comma-separated numbers,
00108 //  or reads three numbers in parenthesized form "(123, 321, 567)"
00109 //  or reads the formatted form "123x+321y+567=0"
00110 template <class Type>
00111 vcl_istream&  operator>>(vcl_istream& is, vgl_line_2d<Type>& line)
00112 {
00113   if (! is.good()) return is; // (TODO: should throw an exception)
00114   bool paren = false;
00115   bool formatted = false;
00116   Type a, b, c;
00117   is >> vcl_ws; // jump over any leading whitespace
00118   if (is.eof()) return is; // nothing to be set because of EOF (TODO: should throw an exception)
00119   if (is.peek() == '(') { is.ignore(); paren=true; }
00120   is >> vcl_ws >> a >> vcl_ws;
00121   if (is.eof()) return is;
00122   if (is.peek() == ',') is.ignore();
00123   else if (is.peek() == 'x') { is.ignore(); formatted=true; }
00124   is >> vcl_ws >> b >> vcl_ws;
00125   if (is.eof()) return is;
00126   if (formatted) {
00127     if (is.eof()) return is;
00128     if (is.peek() == 'y') is.ignore();
00129     else                  return is; // formatted input incorrect (TODO: throw an exception)
00130   }
00131   else if (is.peek() == ',') is.ignore();
00132   is >> vcl_ws >> c >> vcl_ws;
00133   if (paren) {
00134     if (is.eof()) return is;
00135     if (is.peek() == ')') is.ignore();
00136     else                  return is; // closing parenthesis is missing (TODO: throw an exception)
00137   }
00138   if (formatted) {
00139     if (is.eof()) return is;
00140     if (is.peek() == '=') is.ignore();
00141     else                  return is; // closing parenthesis is missing (TODO: throw an exception)
00142     is >> vcl_ws;
00143     if (is.peek() == '0') is.ignore();
00144     else                  return is; // closing parenthesis is missing (TODO: throw an exception)
00145   }
00146   line.set(a,b,c);
00147   return is;
00148 }
00149 
00150 #undef VGL_LINE_2D_INSTANTIATE
00151 #define VGL_LINE_2D_INSTANTIATE(T) \
00152 template class vgl_line_2d<T >; \
00153 template vcl_ostream& operator<<(vcl_ostream&, vgl_line_2d<T >const&); \
00154 template vcl_istream& operator>>(vcl_istream&, vgl_line_2d<T >&)
00155 
00156 #endif // vgl_line_2d_txx_