core/vgl/vgl_ellipse_scan_iterator.txx
Go to the documentation of this file.
00001 // This is core/vgl/vgl_ellipse_scan_iterator.txx
00002 #ifndef vgl_ellipse_scan_iterator_txx_
00003 #define vgl_ellipse_scan_iterator_txx_
00004 
00005 #include "vgl_ellipse_scan_iterator.h"
00006 #include <vcl_cmath.h>
00007 
00008 // Helper functions
00009 namespace {
00010   template <class T> inline T my_max( T x, T y ) { return x<y ? y : x; }
00011 }
00012 
00013 template <class T>
00014 vgl_ellipse_scan_iterator<T>::vgl_ellipse_scan_iterator( T xc, T yc, T rx, T ry, T theta )
00015   : xc_( xc ),
00016     yc_( yc ),
00017     rx_( rx*rx ),
00018     ry_( ry*ry ),
00019     theta_( theta ),
00020     y_( 0 ),
00021     min_y_( 0 )
00022 {
00023 }
00024 
00025 template <class T>
00026 vgl_ellipse_scan_iterator<T>::~vgl_ellipse_scan_iterator()
00027 {
00028 }
00029 
00030 template <class T>
00031 void vgl_ellipse_scan_iterator<T>::reset()
00032 {
00033   // The max value.
00034   T y0;
00035   if ( vcl_sin( theta_ ) == 0.0 ) {
00036     y0 = vcl_sqrt(ry_);
00037   }
00038   else {
00039     T t = vcl_atan2( vcl_sqrt(ry_) , vcl_sqrt(rx_) * vcl_tan( theta_ ) );
00040     y0 = vcl_sqrt(rx_) * vcl_cos( t ) * vcl_sin( theta_ ) + vcl_sqrt(ry_) * vcl_sin( t ) * vcl_cos( theta_ );
00041   }
00042   if ( y0 < 0 ) y0 = -y0;
00043 
00044   y_ = int( vcl_floor( yc_ + y0 ) ) + 1;
00045   min_y_ = int( vcl_ceil( yc_ - y0 ) );
00046 }
00047 
00048 template <class T>
00049 bool vgl_ellipse_scan_iterator<T>::next()
00050 {
00051   --y_;
00052   if ( y_ < min_y_ ) return false;
00053 
00054   T st = vcl_sin( -theta_ );
00055   T ct = vcl_cos( -theta_ );
00056   T A = rx_ * st * st + ry_ * ct * ct;
00057 
00058   T x0, x1; // the intersection points of the scan line; x0 >= x1
00059 
00060   if ( A > 0 ) {
00061     // not a degenerate horizontal line
00062     //
00063     T B = (rx_ - ry_) * (y_-yc_) * ct*st;
00064 //  T C = - rx_*ry_ + (rx_*ct*ct + ry_*st*st)*(y_-yc_)*(y_-yc_);
00065     T D = rx_*ry_*(rx_*st*st + ry_*ct*ct - (y_-yc_)*(y_-yc_)); // = B*B-A*C
00066     if (D < 0) D=0; // could be slightly < 0 due to rounding errors
00067 
00068     x0 = (-B + vcl_sqrt( D )) / A;
00069     x1 = (-B - vcl_sqrt( D )) / A;
00070   }
00071   else {
00072     // "ellipse" is a horizontal line or a point
00073     //
00074     x0 = vcl_sqrt( my_max(rx_,ry_) );
00075     x1 = -x0;
00076   }
00077 
00078   start_x_= int( vcl_ceil( xc_ + x1 - 1e-9 ) ); // avoid problems with rounding
00079   end_x_ = int( vcl_floor( xc_ + x0 + 1e-9 ) ); // by slightly shifting.
00080 
00081   if ( start_x_ > end_x_ ) {
00082     // Could happen with very thin ellipses, near the end points
00083     return next();
00084   }
00085   else {
00086     return true;
00087   }
00088 }
00089 
00090 #undef VGL_ELLIPSE_SCAN_ITERATOR_INSTANTIATE
00091 #define VGL_ELLIPSE_SCAN_ITERATOR_INSTANTIATE(T) \
00092 template class vgl_ellipse_scan_iterator<T >
00093 
00094 #endif // vgl_ellipse_scan_iterator_txx_