1 // This is core/vgl/vgl_polygon_scan_iterator.hxx
2 #ifndef vgl_polygon_scan_iterator_hxx_
3 #define vgl_polygon_scan_iterator_hxx_
4 //:
5 // \file
6 
7 #include <cstring>
8 #include <cmath>
9 #include <iostream>
10 #include <algorithm>
11 #include "vgl_polygon_scan_iterator.h"
12 #ifdef _MSC_VER
13 #  include <vcl_msvc_warnings.h>
14 #endif
15 
16 // It used to be necessary to add 0.5 to the scanline coordinates
17 // obtained from a vgl_polygon_scan_iterator. Presumably this had
18 // something to do with pixels and rendering them, but that issue is
19 // irrelevant to a polygon_scan_iterator.
20 //
21 // I think it is clear what a vgl_polygon_scan_iterator should do: tell
22 // me which points inside my polygon have integer coordinates.
23 //
24 // If you cannot live without a polygon_scan_iterator which offsets
25 // things by 0.5, make a new class called something like
26 // \code
27 //   vgl_polygon_scan_iterator_which_adds_one_half
28 // \endcode
29 // and change the value of vgl_polygon_scan_iterator_offset back to 0.5
30 // for that class.
31 //
32 // fsm
33 //
34 
35 static const float vgl_polygon_scan_iterator_offset = 0.0f; // was 0.5f;
36 
37 // find minimum of a and b
38 #undef MIN
39 #define MIN(a,b) (((a)<(b))?(a):(b))
40 
41 // find maximum of a and b
42 #undef MAX
43 #define MAX(a,b) (((a)>(b))?(a):(b))
44 
45 template <class T>
46 struct compare_vertind
47 {
compare_vertindcompare_vertind48   compare_vertind(typename vgl_polygon<T>::sheet_t* chs) : chs_(chs)
49   {}
50 
operator ()compare_vertind51   inline bool operator()(const typename vgl_polygon_scan_iterator<T>::vertind &u,
52                          const typename vgl_polygon_scan_iterator<T>::vertind &v) const
53   {
54     return chs_[u.chainnum][u.vertnum].y() < chs_[v.chainnum][v.vertnum].y();
55   }
56 
57   typename vgl_polygon<T>::sheet_t* chs_;
58 };
59 
60 template <class T>
61 struct compare_crossedges
62 {
operator ()compare_crossedges63   inline bool operator()(const typename vgl_polygon_scan_iterator<T>::crossedge &u,
64                          const typename vgl_polygon_scan_iterator<T>::crossedge &v) const
65   {
66     return u.x < v.x;
67   }
68 };
69 
70 template <class T>
local_qsort(typename vgl_polygon_scan_iterator<T>::vertind * yverts,int numverts,vgl_polygon<T> & p)71 inline static void local_qsort(typename vgl_polygon_scan_iterator<T>::vertind* yverts, int numverts, vgl_polygon<T>& p)
72 {
73   std::sort(yverts, yverts + numverts, compare_vertind<T>(&p[0]));
74 }
75 
76 template <class T>
local_qsort(typename vgl_polygon_scan_iterator<T>::crossedge * crossedges,int numcrossedges)77 inline static void local_qsort(typename vgl_polygon_scan_iterator<T>::crossedge* crossedges, int numcrossedges)
78 {
79   std::sort(crossedges, crossedges + numcrossedges, compare_crossedges<T>());
80 }
81 
82 //===============================================================
83 // Destructor
84 //===============================================================
85 template <class T>
~vgl_polygon_scan_iterator()86 vgl_polygon_scan_iterator<T>::~vgl_polygon_scan_iterator()
87 {
88   delete [] crossedges;
89   delete [] yverts;
90 }
91 
92 //===============================================================
93 // Constructor - polygon & boundary flag
94 //===============================================================
95 template <class T>
vgl_polygon_scan_iterator(vgl_polygon<T> const & face,bool boundaryp)96 vgl_polygon_scan_iterator<T>::vgl_polygon_scan_iterator(vgl_polygon<T> const& face,
97                                                         bool boundaryp):
98   poly_(face)
99 {
100   boundp = boundaryp;
101   have_window = false;
102   init();
103 }
104 
105 //===============================================================
106 // Constructor - polygon, boundary flag and viewing area
107 //===============================================================
108 template <class T>
vgl_polygon_scan_iterator(vgl_polygon<T> const & face,bool boundaryp,vgl_box_2d<T> const & window)109 vgl_polygon_scan_iterator<T>::vgl_polygon_scan_iterator(vgl_polygon<T> const& face, bool boundaryp, vgl_box_2d<T> const& window):
110   poly_(face)
111 {
112   boundp = boundaryp;
113   have_window = true;
114   win = window;
115   init();
116 }
117 
118 //===============================================================
119 // Init - data structures necessary for the scan line
120 //    conversion.  These initializations are common to all 3
121 //    constructors.
122 //===============================================================
123 template <class T>
init()124 void vgl_polygon_scan_iterator<T>::init()
125 {
126   // count total numverts
127   numverts = 0;
128   for (unsigned int s = 0; s < poly_.num_sheets(); ++s)
129     numverts += int(poly_[s].size());
130 
131   unsigned int numchains = poly_.num_sheets();
132   // return if no vertices in face
133   if ( numverts == 0 ) {
134     // Make a call to next() return false.
135     y0 = 0;
136     y1 = -1;
137     crossedges = nullptr;
138     yverts = nullptr;
139     return;
140   }
141 
142   // create array for storing edges crossing current scan line
143   crossedges = new crossedge[ numverts ];
144 
145   // create y-sorted array of vertices
146   yverts = new vertind[ numverts ];
147   int i = 0;
148   for (unsigned int j = 0; j < numchains; j++ )
149     for (unsigned int h = 0; h < poly_[ j ].size(); h++ )
150     {
151       yverts[ i ].chainnum = j;
152       yverts[ i ].vertnum = h;
153       i++;
154     }
155   if ( i != numverts )
156     std::cout << "Error:  i does not equal numverts!\n";
157 
158   // sort vertices by y coordinate
159   local_qsort<T>(yverts, numverts, poly_);
160 
161   T miny, maxy;   // min and max y coordinate of vertices
162   miny = get_y( yverts[ 0 ] );
163   maxy = get_y( yverts[ numverts - 1 ] );
164 
165   // set y0 and y1 to bottommost and topmost scan lines
166   if (have_window)
167   {
168     if (boundp)
169       y0 = (int)MAX(win.min_y(), std::floor( miny - vgl_polygon_scan_iterator_offset));
170     else
171       y0 = (int)MAX(win.min_y(), std::ceil( miny - vgl_polygon_scan_iterator_offset));
172 
173     if (boundp)
174       y1 = (int)MIN(win.max_y()-1, std::ceil( maxy - vgl_polygon_scan_iterator_offset));
175     else
176       y1 = (int)MIN(win.max_y()-1, std::floor( maxy - vgl_polygon_scan_iterator_offset));
177   }
178   else
179   {
180     if (boundp)
181       y0 = (int)std::floor( miny - vgl_polygon_scan_iterator_offset);
182     else
183       y0 = (int)std::ceil( miny - vgl_polygon_scan_iterator_offset);
184 
185     if (boundp)
186       y1 = (int)std::ceil( maxy - vgl_polygon_scan_iterator_offset);
187     else
188       y1 = (int)std::floor(  maxy - vgl_polygon_scan_iterator_offset);
189   }
190 }
191 
192 //===============================================================
193 // Deletes edge (v,get_next_vert(v)) from the crossedge array
194 //===============================================================
195 template <class T>
delete_edge(vertind v)196 void vgl_polygon_scan_iterator<T>::delete_edge( vertind v )
197 {
198     int j;
199     for ( j = 0; j < numcrossedges &&
200                  !( crossedges[j].v.chainnum == v.chainnum &&
201                     crossedges[j].v.vertnum  == v.vertnum ); ++j )
202       /*nothing*/;
203 
204     // edge not in cross edge list; happens at win->y0
205     if ( j >= numcrossedges ) return;
206 
207     numcrossedges--;
208     std::memmove(&crossedges[j], &crossedges[j+1],
209                 (numcrossedges-j)*sizeof( crossedges[0] ));
210 }
211 
212 //===============================================================
213 // Inserts edge (v,get_next_vert(v)) into the crossedge array
214 //===============================================================
215 template <class T>
insert_edge(vertind v)216 void vgl_polygon_scan_iterator<T>::insert_edge( vertind v )
217 {
218   vertind nextvert;
219   T dx;
220   Point2 p, q;
221 
222   get_next_vert( v, nextvert );
223   if ( get_y( v ) < get_y( nextvert ) )
224   {
225     p = get_pt( v );
226     q = get_pt( nextvert );
227   }
228   else
229   {
230     p = get_pt( nextvert );
231     q = get_pt( v );
232   }
233 
234   // initialize x position at intersection of edge with scanline y
235   crossedges[numcrossedges].dx = dx = (q.x() - p.x()) / (q.y() - p.y());
236   crossedges[numcrossedges].x = dx * ( fy + vgl_polygon_scan_iterator_offset - p.y() ) + p.x();
237   crossedges[numcrossedges].v = v;
238   numcrossedges++;
239 }
240 
241 //===============================================================
242 // Resets the iterator so that when next() is called, it will
243 //    store the first scan segment
244 //===============================================================
245 template <class T>
reset()246 void vgl_polygon_scan_iterator<T>::reset()
247 {
248   y = y0;               // first interior scan line
249   numcrossedges = 0;    // start with empty crossingedges list
250   curcrossedge = 0;     // crossedge marking first scan segment
251   k = 0;                // yverts[k] is next vertex to process
252   xl = 0;               // Arbitrary values
253   xr = 0;
254   fxl = 0;
255   fxr = 0;
256 }
257 
258 //===============================================================
259 // Round the double to the nearest int
260 //===============================================================
261 template <class T>
irnd(T x)262 static inline int irnd(T x)
263 {
264   return (int)std::floor(x + 0.5);
265 }
266 
267 template <class T>
get_crossedge_vertices(int * & chainnum,int * & vertnum,int & num_crossedges)268 void vgl_polygon_scan_iterator<T>::get_crossedge_vertices(int * &chainnum, int * &vertnum, int & num_crossedges)
269 {
270   num_crossedges=numcrossedges;
271   int current=0;
272   chainnum=new int[num_crossedges];
273   vertnum=new int[num_crossedges];
274   while ( current < numcrossedges )
275   {
276     chainnum[current] = crossedges[current].v.chainnum;
277     vertnum[current] = crossedges[current].v.vertnum;
278     current++;
279   }
280 }
281 //===============================================================
282 // Moves iterator to the next scan segment.
283 // Scanline y is at y+vgl_polygon_scan_iterator_offset.
284 //
285 //??? Check vertices between previous scanline and current one, if any to simplify.
286 //??? If pt.y=y+0.5,  pretend it's above invariant: y-0.5 < pt[i].y <= y+.5.
287 //===============================================================
288 template <class T>
next()289 bool vgl_polygon_scan_iterator<T>::next( )
290 {
291   do {
292     // Find next segment on current scan line
293     while ( curcrossedge < numcrossedges )
294     {
295       fxl = crossedges[curcrossedge].x;
296       fxr = crossedges[curcrossedge+1].x;
297       if (boundp)
298         // left end of span with boundary
299         xl = (int)std::floor( crossedges[curcrossedge].x - vgl_polygon_scan_iterator_offset);
300       else
301         // left end of span without boundary
302         xl = (int)std::ceil( crossedges[curcrossedge].x - vgl_polygon_scan_iterator_offset);
303 
304       if ( have_window && xl < irnd(win.min_x()) )
305       {
306         fxl = win.min_x();
307         xl = irnd(fxl);
308       }
309 
310       if ( boundp )
311         //right end of span with boundary
312         xr = (int)std::ceil( crossedges[curcrossedge+1].x - vgl_polygon_scan_iterator_offset);
313       else
314         // right end of span without boundary
315         xr = (int)std::floor( crossedges[curcrossedge+1].x - vgl_polygon_scan_iterator_offset);
316 
317       if ( have_window && xr >= irnd(win.max_x()) )
318       {
319         fxr = win.max_x() -1;
320         xr =  irnd(fxr);
321       }
322 #if 0 // TODO: added by Vishal Jain (Brown U) but breaks the tests - please fix!
323       if (xr==crossedges[curcrossedge+1].x)
324         --xr;
325 #endif // 0
326       // adjust the x coord so that it is the intersection of
327       // the edge with the scan line one above current
328       crossedges[curcrossedge].x += crossedges[curcrossedge].dx;
329       crossedges[curcrossedge+1].x += crossedges[curcrossedge+1].dx;
330       curcrossedge+=2;
331       if ( xl <= xr )
332         return true;
333     }
334 
335     // All segments on current scan line have been exhausted.  Start
336     // processing next scan line.
337     vertind curvert, prevvert, nextvert;
338     if ( y > y1 )
339       return false;
340     else
341     {
342       // Current scan line is not the last one.
343       bool not_last = true;
344 
345       // If boundary included and processing first or last scan line
346       // floating point scan line must be taken as a min/max y coordinate
347       // of the polygon. Otherwise these scan lines are not included because
348       // of the earlier rounding (ceil/floor).
349       if ( boundp ) {
350         if ( y == y0 )
351           fy = std::floor(get_y( yverts[ 0 ] ));
352         else if ( y == y1 ) {
353           fy = std::ceil(get_y( yverts[ numverts - 1 ] ));
354           not_last = false;
355         }
356         else
357           fy = T(y);
358       }
359       else
360         fy = T(y);
361 
362       for (; k<numverts && get_y(yverts[k]) <= fy+vgl_polygon_scan_iterator_offset && not_last; k++)
363       {
364         curvert = yverts[ k ];
365 
366         // insert or delete edges (curvert, nextvert) and (prevvert, curvert)
367         // from crossedges list if they cross scanline y
368         get_prev_vert( curvert, prevvert );
369 
370         if ( get_y( prevvert ) <= fy-vgl_polygon_scan_iterator_offset)  // old edge, remove from active list
371           delete_edge( prevvert );
372         else if ( get_y( prevvert ) > fy+vgl_polygon_scan_iterator_offset)  // new edge, add to active list
373           insert_edge( prevvert );
374 
375         get_next_vert( curvert, nextvert );
376 
377         if ( get_y( nextvert ) <= fy-vgl_polygon_scan_iterator_offset)  // old edge, remove from active list
378           delete_edge( curvert );
379         else if ( get_y( nextvert ) > fy+vgl_polygon_scan_iterator_offset)  // new edge, add to active list
380           insert_edge( curvert );
381       }
382 
383       // sort edges crossing scan line by their intersection with scan line
384       local_qsort<T>(crossedges, numcrossedges);
385 
386       curcrossedge = 0; // Process the next set of horizontal spans
387       y++;
388     }
389   } while ( true );
390 }
391 
392 //===============================================================
393 //: Returns the vertex following v in v's chain.
394 //  The vertex is returned through the parameter nextvert.
395 //  I get a syntax error when I tried to return an object of type vertind.
396 //  Compiler error says the default return type is int???
397 template <class T>
get_next_vert(vertind v,vertind & nextvert)398 void vgl_polygon_scan_iterator<T>::get_next_vert( vertind v, vertind & nextvert )
399 {
400         nextvert = v;
401         nextvert.vertnum += 1;
402         if ( nextvert.vertnum == int(poly_[nextvert.chainnum].size()) )
403             nextvert.vertnum = 0; // wrap around to first vertex
404 }
405 
406 //: Returns the vertex preceding v in v's chain.
407 //  The vertex is returned through the parameter prevvert.
408 //  I get a syntax error when I tried to return an object of type vertind.
409 //  Compiler error says the default return type is int???
410 template <class T>
get_prev_vert(vertind v,vertind & prevvert)411 void vgl_polygon_scan_iterator<T>::get_prev_vert( vertind v, vertind & prevvert )
412 {
413         prevvert = v;
414         prevvert.vertnum = prevvert.vertnum - 1;
415         if ( prevvert.vertnum == -1 )  // wrap around to last vertex
416             prevvert.vertnum = int(poly_[prevvert.chainnum].size() - 1);
417 }
418 
419 //===============================================================
420 // For debugging purposes.
421 //===============================================================
422 template <class T>
display_chains()423 void vgl_polygon_scan_iterator<T>::display_chains()
424 {
425     std::cout << "Number of Chains: " << poly_.num_sheets() << std::endl
426              << "Number of Vertices: " << numverts << std::endl;
427     for (unsigned int c = 0; c < poly_.num_sheets(); ++c )
428     {
429         std::cout << "---- Chain # " << c << " ----\n"
430                  << "  Length: " << poly_[ c ].size() << std::endl;
431         for (unsigned int v = 0; v < poly_[ c ].size(); v++ )
432         {
433             std::cout << "  [ " << poly_[ c ][ v ].x()
434                      << ' ' << poly_[ c ][ v ].y() << " ]\n";
435         }
436     }
437     std::cout << std::flush;
438 }
439 
440 //===============================================================
441 // For debugging purposes.
442 //===============================================================
443 template <class T>
display_crossedges()444 void vgl_polygon_scan_iterator<T>::display_crossedges()
445 {
446     std::cout << "----- CROSSEDGES -----\n"
447              << "numcrossedges: " << numcrossedges << std::endl;
448     for (int i = 0; i< numcrossedges; i++ )
449     {
450         std::cout << "x = " << crossedges[i].x << '\n'
451                  << "y = " << crossedges[i].dx << '\n'
452                  << "v: chainnum=" << crossedges[i].v.chainnum
453                  << ", vertnum=" << crossedges[i].v.vertnum << '\n';
454     }
455     std::cout << "---------------------\n" << std::flush;
456 }
457 
458 #undef VGL_POLYGON_SCAN_ITERATOR_INSTANTIATE
459 #define VGL_POLYGON_SCAN_ITERATOR_INSTANTIATE(T) \
460 template class vgl_polygon_scan_iterator<T >
461 
462 #endif // vgl_polygon_scan_iterator_hxx_
463