vgl_polygon_scan_iterator.hxx
Go to the documentation of this file.
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>
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>
47 {
49  {}
50 
51  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 
58 };
59 
60 template <class T>
62 {
63  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>
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>
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>
87 {
88  delete [] crossedges;
89  delete [] yverts;
90 }
91 
92 //===============================================================
93 // Constructor - polygon & boundary flag
94 //===============================================================
95 template <class T>
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>
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>
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>
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>
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>
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>
262 static inline int irnd(T x)
263 {
264  return (int)std::floor(x + 0.5);
265 }
266 
267 template <class T>
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>
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>
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>
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>
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>
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_
int boundp
boolean indicating if boundary should be included or not
void get_next_vert(vertind v, vertind &next)
Returns the vertex following v in v's chain.
bool next() override
Moves iterator to next segment.
~vgl_polygon_scan_iterator() override
Destructor.
#define MIN(a, b)
int chainnum
which chain the vertex is part of
Describes an edge crossing the current scan line.
void get_prev_vert(vertind v, vertind &prev)
Returns the vertex preceding v in v's chain.
#define v
Definition: vgl_vector_2d.h:74
compare_vertind(typename vgl_polygon< T >::sheet_t *chs)
vertind v
edge goes from vertex v.vertnum to v.vertnum + 1
#define MAX(a, b)
bool operator()(const typename vgl_polygon_scan_iterator< T >::vertind &u, const typename vgl_polygon_scan_iterator< T >::vertind &v) const
void get_crossedge_vertices(int *&chainnum, int *&vertnum, int &numcrossedges)
Type & y()
Definition: vgl_point_2d.h:72
vgl_polygon_scan_iterator(vgl_polygon< T > const &face, bool boundaryp=true)
Construct with a polygon and bool indicating whether boundary included.
Vertex index - uniquely identifies a vertex in the array chains.
void reset() override
Resets iterator to first segment of first scan line.
T x
x coord of edge's intersection with current scanline
bool operator()(const typename vgl_polygon_scan_iterator< T >::crossedge &u, const typename vgl_polygon_scan_iterator< T >::crossedge &v) const
std::vector< point_t > sheet_t
Definition: vgl_polygon.h:43
Store a polygon.
Definition: vgl_area.h:6
vgl_polygon< T >::sheet_t * chs_
vgl_box_2d< T > win
clipping window
Type & x()
Definition: vgl_point_2d.h:71