core/vgl/vgl_polygon_scan_iterator.txx
Go to the documentation of this file.
00001 // This is core/vgl/vgl_polygon_scan_iterator.txx
00002 #ifndef vgl_polygon_scan_iterator_txx_
00003 #define vgl_polygon_scan_iterator_txx_
00004 //:
00005 // \file
00006 
00007 #include "vgl_polygon_scan_iterator.h"
00008 #include <vcl_cstring.h>
00009 #include <vcl_cmath.h>
00010 #include <vcl_iostream.h>
00011 #include <vcl_algorithm.h>
00012 
00013 // It used to be necessary to add 0.5 to the scanline coordinates
00014 // obtained from a vgl_polygon_scan_iterator. Presumably this had
00015 // something to do with pixels and rendering them, but that issue is
00016 // irrelevant to a polygon_scan_iterator.
00017 //
00018 // I think it is clear what a vgl_polygon_scan_iterator should do: tell
00019 // me which points inside my polygon have integer coordinates.
00020 //
00021 // If you cannot live without a polygon_scan_iterator which offsets
00022 // things by 0.5, make a new class called something like
00023 // \code
00024 //   vgl_polygon_scan_iterator_which_adds_one_half
00025 // \endcode
00026 // and change the value of vgl_polygon_scan_iterator_offset back to 0.5
00027 // for that class.
00028 //
00029 // fsm
00030 //
00031 
00032 static const float vgl_polygon_scan_iterator_offset = 0.0f; // was 0.5f;
00033 
00034 // find minimum of a and b
00035 #undef MIN
00036 #define MIN(a,b) (((a)<(b))?(a):(b))
00037 
00038 // find maximum of a and b
00039 #undef MAX
00040 #define MAX(a,b) (((a)>(b))?(a):(b))
00041 
00042 template <class T>
00043 struct compare_vertind
00044 {
00045   compare_vertind(typename vgl_polygon<T>::sheet_t* chs) : chs_(chs)
00046   {}
00047 
00048   inline bool operator()(const typename vgl_polygon_scan_iterator<T>::vertind &u,
00049                          const typename vgl_polygon_scan_iterator<T>::vertind &v) const
00050   {
00051     return chs_[u.chainnum][u.vertnum].y() < chs_[v.chainnum][v.vertnum].y();
00052   }
00053 
00054   typename vgl_polygon<T>::sheet_t* chs_;
00055 };
00056 
00057 template <class T>
00058 struct compare_crossedges
00059 {
00060   inline bool operator()(const typename vgl_polygon_scan_iterator<T>::crossedge &u,
00061                          const typename vgl_polygon_scan_iterator<T>::crossedge &v) const
00062   {
00063     return u.x < v.x;
00064   }
00065 };
00066 
00067 template <class T>
00068 inline static void local_qsort(typename vgl_polygon_scan_iterator<T>::vertind* yverts, int numverts, vgl_polygon<T>& p)
00069 {
00070   vcl_sort(yverts, yverts + numverts, compare_vertind<T>(&p[0]));
00071 }
00072 
00073 template <class T>
00074 inline static void local_qsort(typename vgl_polygon_scan_iterator<T>::crossedge* crossedges, int numcrossedges)
00075 {
00076   vcl_sort(crossedges, crossedges + numcrossedges, compare_crossedges<T>());
00077 }
00078 
00079 //===============================================================
00080 // Destructor
00081 //===============================================================
00082 template <class T>
00083 vgl_polygon_scan_iterator<T>::~vgl_polygon_scan_iterator()
00084 {
00085   delete [] crossedges;
00086   delete [] yverts;
00087 }
00088 
00089 //===============================================================
00090 // Constructor - polygon & boundary flag
00091 //===============================================================
00092 template <class T>
00093 vgl_polygon_scan_iterator<T>::vgl_polygon_scan_iterator(vgl_polygon<T> const& face,
00094                                                         bool boundaryp):
00095   poly_(face)
00096 {
00097   boundp = boundaryp;
00098   have_window = false;
00099   init();
00100 }
00101 
00102 //===============================================================
00103 // Constructor - polygon, boundary flag and viewing area
00104 //===============================================================
00105 template <class T>
00106 vgl_polygon_scan_iterator<T>::vgl_polygon_scan_iterator(vgl_polygon<T> const& face, bool boundaryp, vgl_box_2d<T> const& window):
00107   poly_(face)
00108 {
00109   boundp = boundaryp;
00110   have_window = true;
00111   win = window;
00112   init();
00113 }
00114 
00115 //===============================================================
00116 // Init - data structures necessary for the scan line
00117 //    conversion.  These initializations are common to all 3
00118 //    constructors.
00119 //===============================================================
00120 template <class T>
00121 void vgl_polygon_scan_iterator<T>::init()
00122 {
00123   // count total numverts
00124   numverts = 0;
00125   for (unsigned int s = 0; s < poly_.num_sheets(); ++s)
00126     numverts += int(poly_[s].size());
00127 
00128   unsigned int numchains = poly_.num_sheets();
00129   // return if no vertices in face
00130   if ( numverts == 0 ) {
00131     // Make a call to next() return false.
00132     y0 = 0;
00133     y1 = -1;
00134     crossedges = 0;
00135     yverts = 0;
00136     return;
00137   }
00138 
00139   // create array for storing edges crossing current scan line
00140   crossedges = new crossedge[ numverts ];
00141 
00142   // create y-sorted array of vertices
00143   yverts = new vertind[ numverts ];
00144   int i = 0;
00145   for (unsigned int j = 0; j < numchains; j++ )
00146     for (unsigned int h = 0; h < poly_[ j ].size(); h++ )
00147     {
00148       yverts[ i ].chainnum = j;
00149       yverts[ i ].vertnum = h;
00150       i++;
00151     }
00152   if ( i != numverts )
00153     vcl_cout << "Error:  i does not equal numverts!\n";
00154 
00155   // sort vertices by y coordinate
00156   local_qsort<T>(yverts, numverts, poly_);
00157 
00158   T miny, maxy;   // min and max y coordinate of vertices
00159   miny = get_y( yverts[ 0 ] );
00160   maxy = get_y( yverts[ numverts - 1 ] );
00161 
00162   // set y0 and y1 to bottommost and topmost scan lines
00163   if (have_window)
00164   {
00165     if (boundp)
00166       y0 = (int)MAX(win.min_y(), vcl_floor( miny - vgl_polygon_scan_iterator_offset));
00167     else
00168       y0 = (int)MAX(win.min_y(), vcl_ceil( miny - vgl_polygon_scan_iterator_offset));
00169 
00170     if (boundp)
00171       y1 = (int)MIN(win.max_y()-1, vcl_ceil( maxy - vgl_polygon_scan_iterator_offset));
00172     else
00173       y1 = (int)MIN(win.max_y()-1, vcl_floor( maxy - vgl_polygon_scan_iterator_offset));
00174   }
00175   else
00176   {
00177     if (boundp)
00178       y0 = (int)vcl_floor( miny - vgl_polygon_scan_iterator_offset);
00179     else
00180       y0 = (int)vcl_ceil( miny - vgl_polygon_scan_iterator_offset);
00181 
00182     if (boundp)
00183       y1 = (int)vcl_ceil( maxy - vgl_polygon_scan_iterator_offset);
00184     else
00185       y1 = (int)vcl_floor(  maxy - vgl_polygon_scan_iterator_offset);
00186   }
00187 }
00188 
00189 //===============================================================
00190 // Deletes edge (v,get_next_vert(v)) from the crossedge array
00191 //===============================================================
00192 template <class T>
00193 void vgl_polygon_scan_iterator<T>::delete_edge( vertind v )
00194 {
00195     int j;
00196     for ( j = 0; j < numcrossedges &&
00197                  !( crossedges[j].v.chainnum == v.chainnum &&
00198                     crossedges[j].v.vertnum  == v.vertnum ); ++j )
00199       /*nothing*/;
00200 
00201     // edge not in cross edge list; happens at win->y0
00202     if ( j >= numcrossedges ) return;
00203 
00204     numcrossedges--;
00205     vcl_memmove(&crossedges[j], &crossedges[j+1],
00206                 (numcrossedges-j)*sizeof( crossedges[0] ));
00207 }
00208 
00209 //===============================================================
00210 // Inserts edge (v,get_next_vert(v)) into the crossedge array
00211 //===============================================================
00212 template <class T>
00213 void vgl_polygon_scan_iterator<T>::insert_edge( vertind v )
00214 {
00215   vertind nextvert;
00216   T dx;
00217   Point2 p, q;
00218 
00219   get_next_vert( v, nextvert );
00220   if ( get_y( v ) < get_y( nextvert ) )
00221   {
00222     p = get_pt( v );
00223     q = get_pt( nextvert );
00224   }
00225   else
00226   {
00227     p = get_pt( nextvert );
00228     q = get_pt( v );
00229   }
00230 
00231   // initialize x position at intersection of edge with scanline y
00232   crossedges[numcrossedges].dx = dx = (q.x() - p.x()) / (q.y() - p.y());
00233   crossedges[numcrossedges].x = dx * ( fy + vgl_polygon_scan_iterator_offset - p.y() ) + p.x();
00234   crossedges[numcrossedges].v = v;
00235   numcrossedges++;
00236 }
00237 
00238 //===============================================================
00239 // Resets the iterator so that when next() is called, it will
00240 //    store the first scan segment
00241 //===============================================================
00242 template <class T>
00243 void vgl_polygon_scan_iterator<T>::reset()
00244 {
00245   y = y0;               // first interior scan line
00246   numcrossedges = 0;    // start with empty crossingedges list
00247   curcrossedge = 0;     // crossedge marking first scan segment
00248   k = 0;                // yverts[k] is next vertex to process
00249   xl = 0;               // Arbitrary values
00250   xr = 0;
00251   fxl = 0;
00252   fxr = 0;
00253 }
00254 
00255 //===============================================================
00256 // Round the double to the nearest int
00257 //===============================================================
00258 template <class T>
00259 static inline int irnd(T x)
00260 {
00261   return (int)vcl_floor(x + 0.5);
00262 }
00263 
00264 template <class T>
00265 void vgl_polygon_scan_iterator<T>::get_crossedge_vertices(int * &chainnum, int * &vertnum, int & num_crossedges)
00266 {
00267   num_crossedges=numcrossedges;
00268   int current=0;
00269   chainnum=new int[num_crossedges];
00270   vertnum=new int[num_crossedges];
00271   while ( current < numcrossedges )
00272   {
00273     chainnum[current] = crossedges[current].v.chainnum;
00274     vertnum[current] = crossedges[current].v.vertnum;
00275     current++;
00276   }
00277 }
00278 //===============================================================
00279 // Moves iterator to the next scan segment.
00280 // Scanline y is at y+vgl_polygon_scan_iterator_offset.
00281 //
00282 //??? Check vertices between previous scanline and current one, if any to simplify.
00283 //??? If pt.y=y+0.5,  pretend it's above invariant: y-0.5 < pt[i].y <= y+.5.
00284 //===============================================================
00285 template <class T>
00286 bool vgl_polygon_scan_iterator<T>::next( )
00287 {
00288   do {
00289     // Find next segment on current scan line
00290     while ( curcrossedge < numcrossedges )
00291     {
00292       fxl = crossedges[curcrossedge].x;
00293       fxr = crossedges[curcrossedge+1].x;
00294       if (boundp)
00295         // left end of span with boundary
00296         xl = (int)vcl_floor( crossedges[curcrossedge].x - vgl_polygon_scan_iterator_offset);
00297       else
00298         // left end of span without boundary
00299         xl = (int)vcl_ceil( crossedges[curcrossedge].x - vgl_polygon_scan_iterator_offset);
00300 
00301       if ( have_window && xl < irnd(win.min_x()) )
00302       {
00303         fxl = win.min_x();
00304         xl = irnd(fxl);
00305       }
00306 
00307       if ( boundp )
00308         //right end of span with boundary
00309         xr = (int)vcl_ceil( crossedges[curcrossedge+1].x - vgl_polygon_scan_iterator_offset);
00310       else
00311         // right end of span without boundary
00312         xr = (int)vcl_floor( crossedges[curcrossedge+1].x - vgl_polygon_scan_iterator_offset);
00313 
00314       if ( have_window && xr >= irnd(win.max_x()) )
00315       {
00316         fxr = win.max_x() -1;
00317         xr =  irnd(fxr);
00318       }
00319 #if 0 // TODO: added by Vishal Jain (Brown U) but breaks the tests - please fix!
00320       if (xr==crossedges[curcrossedge+1].x)
00321         --xr;
00322 #endif // 0
00323       // adjust the x coord so that it is the intersection of
00324       // the edge with the scan line one above current
00325       crossedges[curcrossedge].x += crossedges[curcrossedge].dx;
00326       crossedges[curcrossedge+1].x += crossedges[curcrossedge+1].dx;
00327       curcrossedge+=2;
00328       if ( xl <= xr )
00329         return true;
00330     }
00331 
00332     // All segments on current scan line have been exhausted.  Start
00333     // processing next scan line.
00334     vertind curvert, prevvert, nextvert;
00335     if ( y > y1 )
00336       return false;
00337     else
00338     {
00339       // Current scan line is not the last one.
00340       bool not_last = true;
00341 
00342       // If boundary included and processing first or last scan line
00343       // floating point scan line must be taken as a min/max y coordinate
00344       // of the polygon. Otherwise these scan lines are not included because
00345       // of the earlier rounding (ceil/floor).
00346       if ( boundp ) {
00347         if ( y == y0 )
00348           fy = vcl_floor(get_y( yverts[ 0 ] ));
00349         else if ( y == y1 ) {
00350           fy = vcl_ceil(get_y( yverts[ numverts - 1 ] ));
00351           not_last = false;
00352         }
00353         else
00354           fy = T(y);
00355       }
00356       else
00357         fy = T(y);
00358 
00359       for (; k<numverts && get_y(yverts[k]) <= fy+vgl_polygon_scan_iterator_offset && not_last; k++)
00360       {
00361         curvert = yverts[ k ];
00362 
00363         // insert or delete edges (curvert, nextvert) and (prevvert, curvert)
00364         // from crossedges list if they cross scanline y
00365         get_prev_vert( curvert, prevvert );
00366 
00367         if ( get_y( prevvert ) <= fy-vgl_polygon_scan_iterator_offset)  // old edge, remove from active list
00368           delete_edge( prevvert );
00369         else if ( get_y( prevvert ) > fy+vgl_polygon_scan_iterator_offset)  // new edge, add to active list
00370           insert_edge( prevvert );
00371 
00372         get_next_vert( curvert, nextvert );
00373 
00374         if ( get_y( nextvert ) <= fy-vgl_polygon_scan_iterator_offset)  // old edge, remove from active list
00375           delete_edge( curvert );
00376         else if ( get_y( nextvert ) > fy+vgl_polygon_scan_iterator_offset)  // new edge, add to active list
00377           insert_edge( curvert );
00378       }
00379 
00380       // sort edges crossing scan line by their intersection with scan line
00381       local_qsort<T>(crossedges, numcrossedges);
00382 
00383       curcrossedge = 0; // Process the next set of horizontal spans
00384       y++;
00385     }
00386   } while ( true );
00387 }
00388 
00389 //===============================================================
00390 //: Returns the vertex following v in v's chain.
00391 //  The vertex is returned through the parameter nextvert.
00392 //  I get a syntax error when I tried to return an object of type vertind.
00393 //  Compiler error says the default return type is int???
00394 template <class T>
00395 void vgl_polygon_scan_iterator<T>::get_next_vert( vertind v, vertind & nextvert )
00396 {
00397         nextvert = v;
00398         nextvert.vertnum += 1;
00399         if ( nextvert.vertnum == int(poly_[nextvert.chainnum].size()) )
00400             nextvert.vertnum = 0; // wrap around to first vertex
00401 }
00402 
00403 //: Returns the vertex preceding v in v's chain.
00404 //  The vertex is returned through the parameter prevvert.
00405 //  I get a syntax error when I tried to return an object of type vertind.
00406 //  Compiler error says the default return type is int???
00407 template <class T>
00408 void vgl_polygon_scan_iterator<T>::get_prev_vert( vertind v, vertind & prevvert )
00409 {
00410         prevvert = v;
00411         prevvert.vertnum = prevvert.vertnum - 1;
00412         if ( prevvert.vertnum == -1 )  // wrap around to last vertex
00413             prevvert.vertnum = int(poly_[prevvert.chainnum].size() - 1);
00414 }
00415 
00416 //===============================================================
00417 // For debugging purposes.
00418 //===============================================================
00419 template <class T>
00420 void vgl_polygon_scan_iterator<T>::display_chains()
00421 {
00422     vcl_cout << "Number of Chains: " << poly_.num_sheets() << vcl_endl
00423              << "Number of Vertices: " << numverts << vcl_endl;
00424     for (unsigned int c = 0; c < poly_.num_sheets(); ++c )
00425     {
00426         vcl_cout << "---- Chain # " << c << " ----\n"
00427                  << "  Length: " << poly_[ c ].size() << vcl_endl;
00428         for (unsigned int v = 0; v < poly_[ c ].size(); v++ )
00429         {
00430             vcl_cout << "  [ " << poly_[ c ][ v ].x()
00431                      << ' ' << poly_[ c ][ v ].y() << " ]\n";
00432         }
00433     }
00434     vcl_cout << vcl_flush;
00435 }
00436 
00437 //===============================================================
00438 // For debugging purposes.
00439 //===============================================================
00440 template <class T>
00441 void vgl_polygon_scan_iterator<T>::display_crossedges()
00442 {
00443     vcl_cout << "----- CROSSEDGES -----\n"
00444              << "numcrossedges: " << numcrossedges << vcl_endl;
00445     for (int i = 0; i< numcrossedges; i++ )
00446     {
00447         vcl_cout << "x = " << crossedges[i].x << '\n'
00448                  << "y = " << crossedges[i].dx << '\n'
00449                  << "v: chainnum=" << crossedges[i].v.chainnum
00450                  << ", vertnum=" << crossedges[i].v.vertnum << '\n';
00451     }
00452     vcl_cout << "---------------------\n" << vcl_flush;
00453 }
00454 
00455 #undef VGL_POLYGON_SCAN_ITERATOR_INSTANTIATE
00456 #define VGL_POLYGON_SCAN_ITERATOR_INSTANTIATE(T) \
00457 template class vgl_polygon_scan_iterator<T >
00458 
00459 #endif // vgl_polygon_scan_iterator_txx_