Parallel Plane Sweep  0.1
Shared memory multithreaded version of the plane sweep algorithm
parPlaneSweep.cpp
Go to the documentation of this file.
1 /*
2  * The MIT License (MIT)
3  * Copyright (c) <2016> <Mark McKenney>
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6  *
7  * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10  * */
11 
12 #include "parPlaneSweep.h"
13 #include <iomanip>
14 
22 int avlHsegCompare( const void* first, const void* second, void* param )
23 {
24  const halfsegment* h1 = static_cast<const halfsegment*>(first);
25  const halfsegment* h2 = static_cast<const halfsegment*>(second);
26  if( *h1 == *h2 )
27  return 0;
28  else if( *h1 < *h2 )
29  return -1;
30  return 1;
31 }
32 
42 int avlHsegActiveListCompare( const void* first, const void* second, void* param )
43 {
44  // first is always the item being added/found
45  const halfsegment* h1 = static_cast<const halfsegment*>(first);
46  const halfsegment* h2 = static_cast<const halfsegment*>(second);
47  double xVal = *static_cast<double*>( param );
48 
49  // if equal, indicate
50  if( *h1 == *h2 )
51  return 0;
52  // if colinear, then 'first' is greater (due to hseg ordering)
53  // the only time we will have overlapping colinear is when inserting left hsegs
54  // so this shouldn't ever come up when removing based on right segs
55  if( h1->colinear( *h2 ) )
56  return 1;
57 
58  double h1Y = h1->getYvalAtX( xVal );
59  double h2Y = h2->getYvalAtX( xVal );
60  // at this point, we simply construct hsegs using the sweep line intersect and xval as the dominating point
61  halfsegment newH1;
62  halfsegment newH2;
63  newH1.dx = newH2.dx = xVal;
64  newH1.dy = h1Y;
65  newH2.dy = h2Y;
66  if( newH1.dx == h1->sx && newH1.dy == h1->sy ) {
67  newH1.sx = h1->dx;
68  newH1.sy = h1->dy;
69  }
70  else {
71  newH1.sx = h1->sx;
72  newH1.sy = h1->sy;
73  }
74 if( newH2.dx == h2->sx && newH2.dy == h2->sy ) {
75  newH2.sx = h2->dx;
76  newH2.sy = h2->dy;
77  }
78  else {
79  newH2.sx = h2->sx;
80  newH2.sy = h2->sy;
81  }
82 //cerr << "newh1, newh2: " << newH1 << ", " << newH2 << (newH1 < newH2)<<endl;
83  // if Y vals are different
84  if( h1Y < h2Y ) return -1;
85  else if( h1Y > h2Y ) return 1;
86  // otherwise, the dom point is the same
87  // now we just use the halfsgment < operator
88  // for the active list, we want the seg that is above the other one.
89  // special case: when they are both right hsegs, they always share a dom point. reverse <
90  if( !newH1.isLeft() && !newH2.isLeft( ) ) {
91  if( newH1 < newH2 ) return 1;
92  return -1;
93  }
94  else if( newH1.isLeft() && newH2.isLeft( ) ) {
95  if( newH1 < newH2 ) return -1;
96  return 1;
97  }
98  else {
99 
100  // we have a left one and a right one. the right hseg is less
101  if( !newH1.isLeft() ) return -1;
102  return 1;
103  // we should never get 1 left and 1 right hseg
104 
105  cerr<< "AL comp. got a left and right" << endl;
106  cerr<< "xval: " << std::setprecision(100)<< xVal << endl;
107  cerr << std::setprecision(100) << *h1 << endl << *h2 << endl << newH1 << endl << newH2 << endl;
108  exit( -1 );
109  }
110  return 1;
111 }
112 
113 
117 int binarySearchExists( vector< halfsegment > &region, double x, int hi=-1, int lo=0 )
118 {
119  if( hi < 0 )
120  hi = region.size();
121  while( lo < hi ) {
122  int mid = (lo+hi)/2;
123  if( region[mid].dx < x ) lo = mid+1;
124  else if( region[mid].dx > x ) hi = mid;
125  else return mid;
126  }
127  return -1;
128 }
129 
133 int binarySearchSmallestGreater( vector< halfsegment > &region, double x, int hi=-1, int lo=-1 )
134 {
135  if( hi < 0 )
136  hi = region.size();
137  while( lo < hi ) {
138  int mid = (lo+hi)/2;
139  if( region[mid].dx <= x ) lo = mid+1;
140  else if( region[mid].dx > x ) {
141  if( mid > 0 && region[mid-1].dx <= x ) return mid;
142  hi = mid-1;
143  }
144  //else return mid;
145  }
146  return hi;
147 }
148 
152 bool binarySearchHalfsegment(vector< halfsegment > &region,
153  const halfsegment &h, int & mid, int hi=-1, int lo=0 )
154 {
155  if( hi < 0 )
156  hi = region.size();
157  while( lo < hi ) {
158  mid = (lo+hi)/2;
159  if( region[mid] < h ) lo = mid+1;
160  else if( region[mid] == h ) return true;
161  else hi = mid;
162  }
163  mid = lo;
164  return false;
165 }
166 
167 
178 void findIsoBoundaries( vector<halfsegment> &r1, vector<halfsegment> &r2,
179  vector< double> & isoBounds );
180 
189 void createStrips( vector< halfsegment> & region, vector<double> &isoBounds,
190  vector<halfsegment> & rStrips, vector< int > &stripStopIndex );
191 
192 
202 void partialOverlay( const vector<halfsegment> & r1Strips, const vector<halfsegment> & r2Strips,
203  vector<halfsegment> & result,
204  vector< int > &r1StripStopIndex, vector< int > &r2StripStopIndex,
205  const int stripID );
206 
207 
211 bool findIntersectionPoint( const halfsegment & h1, const halfsegment & h2,
212  double & X, double & Y, bool & colinear );
213 
217 bool breakHsegs( const halfsegment &alSeg, halfsegment & origCurr,
218  vector< halfsegment> & brokenSegs, bool & colinear,
219  const bool includeCurrSegInBrokenSegs );
220 
221 
228 void createFinalOverlay( vector<halfsegment> & finalResult,
229  vector< vector<halfsegment> > &resultStrips,
230  const vector<double> &isoBounds );
231 
232 
238 void insertBrokenSegsToActiveListAndDiscoveredQueue( const vector<halfsegment> & brokenSegs,
239  vector<halfsegment> & result,
240  avl_table * discoveredSegs,
241  avl_table * activeList,
242  const double eventX,
243  const double eventY );
247 void parallelOverlay( vector<halfsegment> &r1, vector<halfsegment> &r2, vector<halfsegment> &result,
248  int numStrips, int numWorkerThreads )
249 {
250  vector<halfsegment> r1Strips, r2Strips;
251  vector< double > isoBounds;
252  vector< vector< halfsegment> > resultStrips;
253  vector< int > r1StripStopIndex, r2StripStopIndex;
254  result.clear(); // make sure the result vec is clear
255 
256  // set default parallel values
257  if( numStrips < 0 ) {
258  numStrips = omp_get_num_procs();
259  }
260  if( numWorkerThreads > 0 ) {
261  omp_set_num_threads( numWorkerThreads );
262  }
263 
264 
265  int numIsoBounds = numStrips+1;
266 
267  // set up vectors for split points, return strips
268  for( int i = 0; i < numStrips; i++ ) {
269  resultStrips.push_back( vector<halfsegment>() );
270  }
271  for( int i = 0; i < numIsoBounds; i++ ) {
272  isoBounds.push_back( 0 );
273  }
274 
275  // find split points
276  findIsoBoundaries( r1, r2, isoBounds );
277 
278  // split up the regions at the iso boundaries
279  #pragma omp parallel for
280  for( int i = 0; i < 2; i++ ){
281  if( i == 0 ) createStrips( r1, isoBounds, r1Strips, r1StripStopIndex );
282  else createStrips( r2, isoBounds, r2Strips, r2StripStopIndex );
283  }
284  {
285  int count, total = 0;
286  cout << "Number of segmenents in each strip (r1): , ";
287  for( int i = 0; i < r1StripStopIndex.size( ); i++ ) {
288  count = r1StripStopIndex[i];
289  if( i > 0 ) count -= r1StripStopIndex[i-1];
290  total += count;
291  cout << count << ",";
292  }
293  cout << "\ntotal segments in all strips:, "<< total << endl;
294  total = 0;
295  cout << "Number of segmenents in each strip (r2): , ";
296  for( int i = 0; i < r2StripStopIndex.size( ); i++ ) {
297  count = r2StripStopIndex[i];
298  if( i > 0 ) count -= r2StripStopIndex[i-1];
299  total += count;
300  cout << count << ",";
301  }
302  cout << "\ntotal segments in all strips:, "<< total << endl;
303  }
304 
305  // do the actual plane sweeps
306 #pragma omp parallel for schedule(dynamic,1)
307  for( int i = 0; i < numStrips; i++ ) {
308  partialOverlay( r1Strips, r2Strips, resultStrips[i], r1StripStopIndex, r2StripStopIndex, i );
309  }
310 
311  // create the final overlay
312  createFinalOverlay( result,
313  resultStrips,
314  isoBounds );
315 }
316 
317 // call the individual overlay functions.
318 // this function just sets up the function calls to overlayPlaneSweep
322  void partialOverlay( const vector<halfsegment> & r1Strips, const vector<halfsegment> & r2Strips,
323  vector<halfsegment> & result,
324  vector< int > &r1StripStopIndex, vector< int > &r2StripStopIndex,
325  const int stripID )
326 {
327 
328  int r1Start, r2Start, r1Stop, r2Stop;
329  if( stripID == 0 ) {
330  r1Start = r2Start = 0;
331  }
332  else {
333  r1Start = r1StripStopIndex[stripID-1];
334  r2Start = r2StripStopIndex[stripID-1];
335  }
336  r1Stop = r1StripStopIndex[stripID];
337  r2Stop = r2StripStopIndex[stripID];
338 
339  overlayPlaneSweep( &(r1Strips[r1Start]), r1Stop-r1Start,
340  &(r2Strips[r2Start]), r2Stop-r2Start,
341  result);
342 }
343 
347 void overlayPlaneSweep( const halfsegment r1[], int r1Size,
348  const halfsegment r2[], int r2Size,
349  vector<halfsegment>& result )
350 {
351  halfsegment currSeg, maxSeg, tmpSeg, *tmpSegPtr;
352  maxSeg.dx = maxSeg.dy = maxSeg.sx = maxSeg.sy = std::numeric_limits<double>::max();
353  double eventX, eventY;
354  avl_table* activeList = avl_create( avlHsegActiveListCompare, &eventX, NULL );// active list avl tree
355  avl_table* discoveredSegs = avl_create( avlHsegCompare, NULL, NULL ); // discovered segs
356  avl_traverser discoveredTraverser;
357  avl_traverser alTraverser, alAboveTraverser, alBelowTraverser;
358  halfsegment* alHsegPtr = NULL, *alInsertPtr = NULL, *alHsegAbovePtr = NULL, *alHsegBelowPtr = NULL;
359  vector< halfsegment > brokenSegs;
360  bool colinearIntersection;
361  avl_t_init( &discoveredTraverser, discoveredSegs );
362  avl_t_init( &alTraverser, activeList );
363  avl_t_init( &alAboveTraverser, activeList );
364  avl_t_init( &alBelowTraverser, activeList );
365 
366  int r1Pos = 0;
367  int r2Pos = 0;
368  int segSource;
369  while( discoveredSegs->avl_count > 0 || r1Pos < r1Size || r2Pos < r2Size ) {
370  // get the next seg
371  // next seg is the least seg from r1, r2, and the discoveredSeg tree (event queue)
372  currSeg = maxSeg;
373  if( r1Pos < r1Size ) {
374  currSeg = r1[r1Pos];
375  segSource = 1;
376  }
377  if( r2Pos < r2Size && r2[r2Pos]< currSeg ) {
378  currSeg = r2[r2Pos];
379  segSource = 2;
380  }
381  tmpSegPtr = static_cast<halfsegment*>(avl_t_first( &discoveredTraverser, discoveredSegs ) );
382  if( tmpSegPtr != NULL ) {
383  tmpSeg = *tmpSegPtr;
384  if( tmpSeg < currSeg || tmpSeg == currSeg ){
385  currSeg = tmpSeg;
386  segSource = 3;
387  }
388  }
389  // remove the next seg from its source
390  if( segSource == 3 ) {
391  avl_delete( discoveredSegs, &currSeg );
392  delete tmpSegPtr;
393  tmpSegPtr = NULL;
394  }
395  else if( segSource == 2 ){
396  r2Pos++;
397  }
398  else {
399  r1Pos++;
400  }
401 
402  // set current event point.
403  // the activeList compare function uses eventX as its |param| argument
404  eventX = currSeg.dx;
405  eventY = currSeg.dy;
406 
407  // If curr is a left seg, insert it and check for intersections with neighbors
408  // Else it is a right seg, remove it and check its neighbors for intersections
409  if( currSeg.isLeft( ) ) {
410  // initialize the overlap labels
411  currSeg.ola = currSeg.olb = -1;
412  // insert the left seg
413  // use avl_t_insert so we can get its neighbors.
414  alInsertPtr = new halfsegment( currSeg );
415  alHsegPtr = static_cast<halfsegment*>( avl_t_insert( &alTraverser, activeList, alInsertPtr ));
416  // if a duplicate is in the active list, we get a pointer to the duplicate. So we need to update labels
417  // if insert is successful, we get a pointer to the inserted item
418  if( alHsegPtr != alInsertPtr ) {
419  // We found a duplicate in active list. update labels
420  delete alInsertPtr;
421  alInsertPtr = NULL;
422  // NOTE: overlapping segs are a special case for labels.
423  // NOTE: overlap labels are altered in the |breakHsegs()| as well,
424  // but that function is not called here (no need to break up segs
425  // if they are equal)
426  alHsegPtr->ola = currSeg.la;
427  alHsegPtr->olb = currSeg.lb;
428  }
429  else {
430  bool needToRemoveCurr = false;
431  // inserted successfully. Need to get neighbors
432  avl_t_copy( &alAboveTraverser, &alTraverser );
433  avl_t_copy( &alBelowTraverser, &alTraverser );
434  alHsegBelowPtr = static_cast<halfsegment*>( avl_t_prev( &alBelowTraverser));
435  alHsegAbovePtr = static_cast<halfsegment*>( avl_t_next( &alAboveTraverser));
436 
437  // do intersections with above and below. Update currSeg along the way
438  brokenSegs.clear();
439 
440  // We have to deal with the below seg first because currSegs labels get changed
441  // based on the below seg. Once we begin dealing with the above seg, the labels
442  // for the currSeg are already computed and will carry over into those calaculations
443  if( alHsegBelowPtr != NULL ) {
444  halfsegment belowSegCopy(*alHsegBelowPtr);
445 
446  // update labels:
447  // NOTE: overlapping segs are a special case for labels.
448  // NOTE: overlap labels are altered in the |breakHsegs()| as well,
449  if( currSeg.regionID != belowSegCopy.regionID ) {
450  // if below seg is from opposing region, set overlap labels
451  if( belowSegCopy.dx != belowSegCopy.sx ) { // if seg is not vertical, use la (label above)
452  currSeg.ola = currSeg.olb = belowSegCopy.la;
453  } else { // if below seg is vertical, use lb (the label to the right)
454  currSeg.ola = currSeg.olb = belowSegCopy.lb;
455  }
456  }
457  else if(currSeg.regionID == belowSegCopy.regionID ) { // if below seg is from same region, just extend overlap labels
458  currSeg.ola = currSeg.olb = belowSegCopy.ola;
459  // commented code is for checking against vertical seg below from same regions
460  // this should never happen for well formed regions based on hseg order
461  // if( belowSegCopy.dx != belowSegCopy.sx ) { // if seg is not vertical, use ola (label above)
462  // currSeg.ola = currSeg.olb = belowSegCopy.ola;
463  // } else { // if below seg is vertical, use lb (the label to the right)
464  // currSeg.ola = currSeg.olb = belowSegCopy.olb;
465  // }
466  }
467 
468  // Labels are now computed
469  // Compute the segment intersections:
470  if(breakHsegs( *alHsegBelowPtr, currSeg, brokenSegs, colinearIntersection, false ) ){
471  needToRemoveCurr = true;
472  // remove below seg
473  alHsegBelowPtr = static_cast<halfsegment*>( avl_delete( activeList, alHsegBelowPtr ) );
474  delete alHsegBelowPtr;
475  alHsegBelowPtr = NULL;
476  }
477 
478  }
479  // compute intersections with above seg:
480  if( alHsegAbovePtr != NULL ) {
481  if( breakHsegs( *alHsegAbovePtr, currSeg, brokenSegs, colinearIntersection, false ) ) {
482  needToRemoveCurr = true;
483  // remove above seg
484  alHsegAbovePtr = static_cast<halfsegment*>( avl_delete( activeList, alHsegAbovePtr ) );
485  delete alHsegAbovePtr;
486  alHsegAbovePtr = NULL;
487  }
488  }
489 
490  // Update the seg inserted into the active list this round
491  // currSeg is the result of intersecting that seg with its neighbors
492  *alHsegPtr = currSeg;
493 
494  // Insert all the broken up segs into thier various data structures
496  discoveredSegs, activeList,
497  eventX, eventY );
498 
499  }
500  }
501  else {
502  // This is a right halfsegment.
503  // find its brother (left halfsegment) in the active list,
504  // remove it, and check its neighbors for intersections.
505  currSeg = currSeg.getBrother();
506  alHsegPtr = static_cast<halfsegment*>( avl_t_find( &alTraverser, activeList, &currSeg ));
507  if( alHsegPtr != NULL ) {
508  // We found the halfsegment in the active list.
509  // Its possible we don't find one, since a right halfsegment may be in r1 or r2
510  // whose brother (left halfsegment) was broken due to an intersection
511  result.push_back( *alHsegPtr );
512  result.push_back( alHsegPtr->getBrother( ) );
513  // The copy of the seg in the active list has the appropriate labels, so copy it over
514  currSeg = *alHsegPtr;
515  // find the neighbors
516  avl_t_copy( &alAboveTraverser, &alTraverser );
517  avl_t_copy( &alBelowTraverser, &alTraverser );
518  alHsegBelowPtr = static_cast<halfsegment*>( avl_t_prev( &alBelowTraverser));
519  alHsegAbovePtr = static_cast<halfsegment*>( avl_t_next( &alAboveTraverser));
520  // delete the segment
521  alHsegPtr = static_cast<halfsegment*>(avl_delete( activeList, alHsegPtr ));
522  delete alHsegPtr;
523  alHsegPtr = NULL;
524  // if both neighbors are not null, then there is an above and below neighbor,
525  // check them for an intersection
526  if( alHsegBelowPtr != NULL && alHsegAbovePtr != NULL ) {
527  tmpSeg = *alHsegAbovePtr;
528  brokenSegs.clear();
529  if(breakHsegs( *alHsegBelowPtr, tmpSeg, brokenSegs, colinearIntersection, true ) ){
530  // remove below seg and above seg
531  alHsegBelowPtr = static_cast<halfsegment*>( avl_delete( activeList, alHsegBelowPtr ) );
532  delete alHsegBelowPtr;
533  alHsegBelowPtr = NULL;
534  alHsegAbovePtr = static_cast<halfsegment*>( avl_delete( activeList, alHsegAbovePtr ) );
535  delete alHsegAbovePtr;
536  alHsegAbovePtr = NULL;
537  // add broken segs to output and discovered list
539  discoveredSegs, activeList,
540  eventX, eventY );
541  }
542  }
543 
544  }
545  }
546 
547  }
548  // sort the result
549 
550  std::sort( result.begin(), result.end() );
551  // cerr << "ps result: " <<endl;
552  //for( int i = 0; i <result.size(); i++ )
553  // if( result[i].isLeft() )
554  // cerr << result[i]<<endl;
555 
556 }
557 
558 void insertBrokenSegsToActiveListAndDiscoveredQueue( const vector<halfsegment> & brokenSegs,
559  vector<halfsegment> & result,
560  avl_table * discoveredSegs,
561  avl_table * activeList,
562  const double eventX,
563  const double eventY )
564 {
565  for( int i = 0; i < brokenSegs.size(); i++ ){
566  if( (brokenSegs[i].dx != brokenSegs[i].sx && ( brokenSegs[i].dx <= eventX && brokenSegs[i].sx <= eventX))
567  || (brokenSegs[i].dx == brokenSegs[i].sx && ( brokenSegs[i].dy <= eventY && brokenSegs[i].sy <= eventY)) ){
568  // If the seg is behind sweep line, just put it in the output.
569  // The seg is behind teh sweep line if it is not vertical and dx,sx <= eventX
570  // OR the seg is vertical and dy,sy <= eventY
571  result.push_back( brokenSegs[i] );
572  }
573  else if ( !brokenSegs[i].isLeft()
574  || brokenSegs[i].dx > eventX
575  || ( brokenSegs[i].dx == eventX && brokenSegs[i].dy > eventY ) ) {
576  // If the seg is ahead of the sweep line, or a right halfegment,
577  // it goes in the event queue (discovered list)
578  // The seg is ahead of the sweep line if dx > eventX or dx = eventx and dy > eventY
579  avl_insert( discoveredSegs, new halfsegment( brokenSegs[i] ) );
580  }
581  else {
582  // If we get here, the seg spans the sweep line and is a left halfsegment
583  // The seg goes back into the active list.
584  avl_insert( activeList, new halfsegment( brokenSegs[i] ) );
585  }
586  }
587 }
588 
589 bool breakHsegs( const halfsegment &alSeg, halfsegment & origCurr,
590  vector< halfsegment> & brokenSegs, bool & colinear,
591  const bool includeCurrSegInBrokenSegs)
592 {
593  halfsegment tmpSeg;
594  halfsegment curr = origCurr; // copy
595  const halfsegment h2 = alSeg; // rename
596  bool foundIntersection;
597  // get the intersecion point
598  double X,Y;
599  if( foundIntersection = findIntersectionPoint( h2, curr, X, Y, colinear ) ) {
600  if( colinear ) {
601  // If the segs are colinear, their intersection can have at most 3 components
602  // 1) one seg begins to the left (or below) the other. (non overlapping part)
603  // 2) the portion of the segs that overlap
604  // 3) one seg ends to the right (or above) the other. (non overlapping part)
605  // at most, all three portions exist. At the least, portion (2) will exist
606  if( h2.dx < curr.dx || h2.dy < curr.dy ) { // build the first part (1)
607  tmpSeg = h2;
608  tmpSeg.sx = curr.dx;
609  tmpSeg.sy = curr.dy;
610  brokenSegs.push_back( tmpSeg ); // THIS IS NEW Neighbor SEG from AVL tree
611  brokenSegs.push_back( tmpSeg.getBrother() );
612  }
613  // build the middle part (2)
614  tmpSeg = curr;
615  if( curr.sx > h2.sx || (curr.sx == h2.sx && curr.sy > h2.sy )) {
616  // curr extends beyond h2
617  tmpSeg.sx = h2.sx;
618  tmpSeg.sy = h2.sy;
619  }
620  tmpSeg.ola = h2.la; // Set the overlapping labels.
621  tmpSeg.olb = h2.lb;
622  brokenSegs.push_back( tmpSeg.getBrother() );
623  if( includeCurrSegInBrokenSegs ) { // don't need to return currSeg for inserting left hseg
624  brokenSegs.push_back( tmpSeg );
625  }
626  origCurr = tmpSeg; // UPDATE |origCurr| so that the overlap labels get updated
627  // it is pass by reference
628  // build last part (3)
629  if( curr.sx != h2.sx || curr.sy != h2.sy ) {
630  // h2 extends past curr
631  tmpSeg = h2;
632  tmpSeg.dx = curr.sx;
633  tmpSeg.dy = curr.sy;
634  if( curr.sx > h2.sx || (curr.sx == h2.sx && curr.sy > h2.sy )) {
635  // curr extends past h2
636  tmpSeg = curr;
637  tmpSeg.dx = h2.sx;
638  tmpSeg.dy = h2.sy;
639  }
640  brokenSegs.push_back( tmpSeg ); // some future seg
641  brokenSegs.push_back( tmpSeg.getBrother() );
642  }
643  }
644  else {
645  // regular intersection
646  // split up curr
647  if( (X == curr.dx && Y == curr.dy ) ||
648  (X == curr.sx && Y == curr.sy ) ) {
649  // If this is an end point intersection, do not break the seg
650  // we do not remove the curr seg from the active list, so no need
651  // to add to broken segs to get reinserted. Active list curr seg
652  // gets updated in the plane sweep function after all intersections
653  // with currSegs neighbors have been computed
654  }
655  else {
656  // If the intersection is on the interior of this seg, break it up
657  tmpSeg = curr;
658  tmpSeg.sx = X;
659  tmpSeg.sy = Y;
660  brokenSegs.push_back( tmpSeg.getBrother() );
661  if( includeCurrSegInBrokenSegs ) { // don't need to return currSeg for inserting left hseg
662  brokenSegs.push_back( tmpSeg );
663  }
664  origCurr = tmpSeg; // UPDATE |origCurr|. it is passed by reference
665  tmpSeg = curr;
666  tmpSeg.dx = X;
667  tmpSeg.dy = Y;
668  brokenSegs.push_back( tmpSeg );
669  brokenSegs.push_back( tmpSeg.getBrother() );
670  }
671  // split up h2. Identical code to above. see those comments
672  if( (X == h2.dx && Y == h2.dy ) ||
673  (X == h2.sx && Y == h2.sy ) ) {
674  // If this is an end point intersection, do not break the seg
675  // we will reinsert this seg, but its brother remains the same,
676  // so we don't need to put the brother in
677  // reinsertion is just for convienience
678  // we remove the seg in the plane sweep function so
679  // we don't have to keep track of the aboves belows.
680  // In the case of colinears, seg must be removed anyway, so we just
681  // always remove the above/below segs and reinsert them if needed.
682  brokenSegs.push_back( h2 );
683  }
684  else {
685  // interior intersection, split
686  tmpSeg = h2;
687  tmpSeg.sx = X;
688  tmpSeg.sy = Y;
689  brokenSegs.push_back( tmpSeg ); // THIS IS THE UPDATED H2
690  brokenSegs.push_back( tmpSeg.getBrother() );
691  tmpSeg = h2;
692  tmpSeg.dx = X;
693  tmpSeg.dy = Y;
694  brokenSegs.push_back( tmpSeg );
695  brokenSegs.push_back( tmpSeg.getBrother() );
696  }
697  }
698  }
699  return foundIntersection;
700 }
701 
702 bool findIntersectionPoint( const halfsegment & h1, const halfsegment & h2, double & X, double & Y, bool & colinear )
703 {
704  // if colinear, intersection point is h2 dominating (since h2 will be curr seg from overlay)
705  colinear = false;
706  if( h1.colinear( h2 ) ) {
707  X = h2.dx;
708  Y = h2.dy;
709  colinear = true;
710  return true;
711  }
712  // if they share an end point, there is nothing to do
713  if( (h1.dx == h2.dx && h1.dy == h2.dy ) ||
714  (h1.sx == h2.sx && h1.sy == h2.sy ) ) {
715  X = std::numeric_limits<double>::max();
716  Y = std::numeric_limits<double>::max();
717  return false;
718  }
719 
720  // find intersection point
721  double x1 = h1.dx;
722  double y1 = h1.dy;
723  double x2 = h1.sx;
724  double y2 = h1.sy;
725  double x3 = h2.dx;
726  double y3 = h2.dy;
727  double x4 = h2.sx;
728  double y4 = h2.sy;
729 
730  double denom = ((y4-y3)*(x2-x1)) - ((x4-x3)*(y2-y1));
731  double ua = ((x4-x3)*(y1-y3)) - ((y4-y3)*(x1-x3));
732  double ub = ((x2-x1)*(y1-y3)) - ((y2-y1)*(x1-x3));
733 
734  ua = ua/denom;
735  ub = ub/denom;
736  // if ua and ub are between 0 and 1 inclusive, we have an intersection
737  // in at least 1 interior.
738  // end point intersections are handled above
739  if( 0.0 <= ua && ua <= 1.0 && 0.0 <= ub && ub <= 1.0 ) {
740  X = x1 + ( ua*(x2-x1) );
741  Y = y1 + ( ua*(y2-y1) );
742  return true;
743  }
744  else {
745  X = std::numeric_limits<double>::max();
746  Y = std::numeric_limits<double>::max();
747  }
748  return false;
749 }
750 
751 bool hsegIDSort( const halfsegment & h1, const halfsegment & h2 )
752 {
753  return h1.stripID < h2.stripID || (h1.stripID == h2.stripID && h1 < h2 );
754 }
755 
756 void createStrips( vector< halfsegment> & region, vector<double> &isoBounds,
757  vector<halfsegment> & rStrips, vector< int > &stripStopIndex )
758 {
759  halfsegment workSeg;
760  int startBound = 0;
761  // grab a seg, break it on each strip that it crosses, put it in the strips
762  for( int i = 0; i< region.size(); i++ ) {
763  // only need to worry about lefties
764  if( region[i].isLeft( ) ) {
765  workSeg = region[i];
766  for( int j = startBound; j < isoBounds.size()-1; j++ ){
767  if( workSeg.dx > isoBounds[j+1] ) {
768  // we are done with this strip (hseg ordering)
769  startBound++;
770  continue;
771  }
772  // check if we cross the boundary.
773  // remember, we won't have any seg end on a boundary unless we split it
774  else if( workSeg.dx >= isoBounds[j] && workSeg.sx < isoBounds[j+1] ) {
775  workSeg.stripID = j;
776  rStrips.push_back( workSeg );
777  rStrips.push_back( workSeg.getBrother( ) );
778  break; // done with this seg
779  }
780  // otherwise, we cross a boundary
781  else {
782  // get the y value at iso bound
783  halfsegment lhs = workSeg;
784  // make the segs split at isoBounds[j]
785  lhs.sy = workSeg.dy = workSeg.getYvalAtX( isoBounds[j+1] );
786  lhs.sx = workSeg.dx = isoBounds[j+1];
787  lhs.stripID = j;
788  rStrips.push_back( lhs );
789  rStrips.push_back( lhs.getBrother() );
790  }
791  }
792  }
793  }
794  // deallocate input segments (to save memory!)
795  // use the swap to local var trick!
796  //{
797  // vector< halfsegment > localOne;
798  // region.swap(localOne);
799  //}
800 
801  // sort the strips by stripID, then by hseg order
802 
803  std::sort( rStrips.begin(), rStrips.end(), hsegIDSort);
804  // find the startIndex for each strip
805  for( int i = 0; i < isoBounds.size()-1; i++ )
806  stripStopIndex.push_back( std::numeric_limits<int>::min() );
807  for( int i = 0; i < rStrips.size(); i++ ){
808  if( i >= stripStopIndex[ rStrips[i].stripID ] )
809  stripStopIndex[ rStrips[i].stripID ] = i+1;
810  }
811  // remove any remaining min vals
812  int prevVal = 0;
813  for( int i = 0; i < stripStopIndex.size(); i++ ) {
814  if( stripStopIndex[i] == std::numeric_limits<int>::min() ) {
815  stripStopIndex[i] = prevVal;
816  }
817  prevVal = stripStopIndex[i];
818  }
819 
820 #ifdef DEBUG_PRINT
821 #pragma omp critical
822  {
823  /* cerr << "strips: "<<endl;
824  for( int i = 0; i < rStrips.size(); i++ ) {
825  cerr <<"[(" << rStrips[i].dx << "," << rStrips[i].dy << ")(" << rStrips[i].sx << "," << rStrips[i].sy << ") " << rStrips[i].stripID << ", " << rStrips[i].la << ", " << rStrips[i].lb << "]" << endl;
826  }*/
827  cerr<< "stopIndex: " ;
828  for( int i = 0; i < stripStopIndex.size(); i++ )
829  cerr << stripStopIndex[i] << " ";
830  cerr << endl;
831  }
832 #endif
833 }
834 
835 void findIsoBoundaries( vector<halfsegment> &r1, vector<halfsegment> &r2,
836  vector< double> & isoBounds )
837 {
838 
839  // set extrema for isobounds
840  isoBounds[0] = std::numeric_limits<double>::max() *-1;
841  isoBounds[ isoBounds.size()-1 ] = std::numeric_limits<double>::max();
842 
843  // find min/max X
844  double minX = std::numeric_limits<double>::max();
845  double maxX = std::numeric_limits<double>::max()*-1;
846  if( isoBounds.size() == 2){
847  return;
848  }
849  for( int i = 0; i < r1.size(); i++ ){
850  if( r1[i].dx < minX ) minX = r1[i].dx;
851  if( r1[i].dx > maxX ) maxX = r1[i].dx;
852  if( r1[i].sx < minX ) minX = r1[i].sx;
853  if( r1[i].sx > maxX ) maxX = r1[i].sx;
854  }
855  for( int i = 0; i < r2.size(); i++ ){
856  if( r2[i].dx < minX ) minX = r2[i].dx;
857  if( r2[i].dx > maxX ) maxX = r2[i].dx;
858  if( r2[i].sx < minX ) minX = r2[i].sx;
859  if( r2[i].sx > maxX ) maxX = r2[i].sx;
860  }
861  // calc the middle iso bounds (not the extrema).
862  // need numIsoBounds-2 values spaced evenly between minX and maxX
863  double prevIsoVal = minX;
864  double stripWidth = (maxX-minX) / (isoBounds.size()-1);
865  for( int i = 1; i < isoBounds.size()-1; i++ ) {
866  prevIsoVal += stripWidth;
867  isoBounds[i] = prevIsoVal;
868  }
869 
870 #ifdef DEBUG_PRINT
871  cerr<< "iso Bounds: " << endl;
872  cerr << minX <<","<< maxX<<","<< r1.size() << ","<<r2.size() <<endl;
873  for( int i= 0; i < isoBounds.size(); i++ ){
874  cerr << isoBounds[i] << ", ";
875  }
876  cerr << endl;
877 #endif
878 
879  // make sure we don't have an iso boundary on an endpoint
880  for( int i = 1; i < isoBounds.size()-1; i++ ) {
881  int r1Index, r2Index;
882  r1Index = binarySearchExists( r1, isoBounds[i] );
883  r2Index = binarySearchExists( r2, isoBounds[i] );
884  // move forward to find highest segwith same domX
885  if( r1Index >= 0 || r2Index >= 0 ){
886  // get smallest greater
887  r1Index = binarySearchSmallestGreater( r1, isoBounds[i] );
888  r2Index = binarySearchSmallestGreater( r2, isoBounds[i] );
889  cerr << "riInd, r2Ind " << r1Index << ", " << r2Index << endl;
890  double xVal = isoBounds[i+1];
891  if( r1Index < r1.size() && r1[r1Index].dx < xVal ) {
892  xVal = r1[r1Index].dx;
893  }
894  if( r2Index < r2.size() && r2[r2Index].dx < xVal ) {
895  xVal = r2[r2Index].dx;
896  }
897  if( xVal == std::numeric_limits<double>::max() ){
898  cerr << "Did not find xVal in splits" << endl;
899  exit(-1 );
900  }
901  // find point between isoX and xVal
902  isoBounds[i] = (isoBounds[i]+xVal)/2.0;
903  }
904  }
905 
906 #ifdef DEBUG_PRINT
907  cerr<< "iso Bounds: " << endl;
908  for( int i= 0; i < isoBounds.size(); i++ ){
909  cerr << isoBounds[i] << ", ";
910  }
911  cerr << endl;
912 #endif
913 
914 
915 }
916 
917 
918 void createFinalOverlay( vector<halfsegment> & finalResult,
919  vector< vector<halfsegment> > &resultStrips,
920  const vector<double> &isoBounds )
921 {
922  halfsegment curr;
923  int broIndex;
924  int currBound;
925  int currStrip;
926  int currIndex;
927  // each strip is sorted. Join segs with artifical breaks
928  // easiest way: for each isobound
929  // 1) grab a non-invalidated seg
930  // 2) if it ends on an iso bound, check if it is the only one at that point
931  // 3) if so, find the seg and its brother from the next strip, join, invalidate all others
932  // keep the earliest left seg as the valid one
933  // 4) if the new seg ends on the next iso bound, repeat, building the seg across all bounds.
934  // 5) once seg is finished, put it and its brother in results
935  for( int i = 0; i <resultStrips.size(); i++ ) {
936  for( int j = 0; j < resultStrips[i].size(); j++ ) {
937  curr = resultStrips[i][j];
938  // only process left hsegs that are valid;
939  if( curr.isLeft() && curr.la != curr.lb ) {
940  // if the left end point ends on an iso boundary, merge it
941  currIndex = j;
942  currBound = i+1;
943  currStrip = i;
944  if( curr.sx == isoBounds[currBound] ) {
945  // find its brother
946  if( ! binarySearchHalfsegment(resultStrips[ currStrip ], curr.getBrother(), broIndex ) ) {
947  cerr << "did not find brother 1" <<endl; exit( -1 );
948  }
949  }
950  bool invalidateLast=false;
951  while( curr.sx == isoBounds[currBound] ) {
952  // check the brother's neighbors
953  if( (broIndex+1 < resultStrips[currStrip].size()
954  && resultStrips[currStrip][broIndex+1].dx == curr.sx
955  && resultStrips[currStrip][broIndex+1].dy == curr.sy )
956  || (broIndex > 0
957  && resultStrips[currStrip][broIndex-1].dx == curr.sx
958  && resultStrips[currStrip][broIndex-1].dy == curr.sy ) ) {
959  // multiple segs cross here. We are done with this seg
960  break;
961  } else {
962  invalidateLast = true; // record that we need to invalidate the last part
963  // we have to join this seg with its counterpart in the next strip
964  // invalidate the brother
965  resultStrips[currStrip][broIndex].la = resultStrips[currStrip][broIndex].lb = -1;
966  // invalidate the curr
967  resultStrips[currStrip][currIndex].la = resultStrips[currStrip][currIndex].lb = -1;
968  // find the seg in the next strip
969  binarySearchHalfsegment(resultStrips[ currStrip+1 ], resultStrips[currStrip][broIndex], currIndex );
970  // find its brother
971  binarySearchHalfsegment(resultStrips[ currStrip+1 ], resultStrips[currStrip+1][currIndex].getBrother(), broIndex );
972  // update curr with that segs sub point
973  curr.sx = resultStrips[ currStrip+1 ][currIndex].sx;
974  curr.sy = resultStrips[ currStrip+1 ][currIndex].sy;
975  currStrip++; // we are now in the next strip
976  currBound++; // we are now looking at the next bound
977  }
978  }
979  if( invalidateLast ) {
980  // invalidate the brother
981  resultStrips[currStrip][broIndex].la = resultStrips[currStrip][broIndex].lb = -1;
982  // invalidate the curr
983  resultStrips[currStrip][currIndex].la = resultStrips[currStrip][currIndex].lb = -1;
984 
985  }
986  // add the seg and its brother to the output
987  finalResult.push_back( curr );
988  finalResult.push_back( curr.getBrother() );
989  }
990  }
991  }
992 
993 }
994 
995 
int ola
overlap labels.
Definition: parPlaneSweep.h:87
bool colinear(const halfsegment &rhs) const
holds a single halfsegment, along with labeling information and information indicating if the opposin...
Definition: parPlaneSweep.h:76
void * avl_delete(struct avl_table *tree, const void *item)
Definition: avl.c:237
void * avl_t_next(struct avl_traverser *trav)
Definition: avl.c:590
bool hsegIDSort(const halfsegment &h1, const halfsegment &h2)
int avlHsegActiveListCompare(const void *first, const void *second, void *param)
int binarySearchExists(vector< halfsegment > &region, double x, int hi=-1, int lo=0)
size_t avl_count
Definition: avl.h:72
int regionID
The region the seg belongs to.
Definition: parPlaneSweep.h:85
void createStrips(vector< halfsegment > &region, vector< double > &isoBounds, vector< halfsegment > &rStrips, vector< int > &stripStopIndex)
struct avl_table * avl_create(avl_comparison_func *compare, void *param, struct libavl_allocator *allocator)
Definition: avl.c:46
bool findIntersectionPoint(const halfsegment &h1, const halfsegment &h2, double &X, double &Y, bool &colinear)
void * avl_t_insert(struct avl_traverser *trav, struct avl_table *tree, void *item)
Definition: avl.c:541
void partialOverlay(const vector< halfsegment > &r1Strips, const vector< halfsegment > &r2Strips, vector< halfsegment > &result, vector< int > &r1StripStopIndex, vector< int > &r2StripStopIndex, const int stripID)
void parallelOverlay(vector< halfsegment > &r1, vector< halfsegment > &r2, vector< halfsegment > &result, int numStrips, int numWorkerThreads)
double getYvalAtX(const double x) const
void * avl_insert(struct avl_table *table, void *item)
Definition: avl.c:210
void * avl_t_find(struct avl_traverser *trav, struct avl_table *tree, void *item)
Definition: avl.c:502
void * avl_t_prev(struct avl_traverser *trav)
Definition: avl.c:643
void insertBrokenSegsToActiveListAndDiscoveredQueue(const vector< halfsegment > &brokenSegs, vector< halfsegment > &result, avl_table *discoveredSegs, avl_table *activeList, const double eventX, const double eventY)
void createFinalOverlay(vector< halfsegment > &finalResult, vector< vector< halfsegment > > &resultStrips, const vector< double > &isoBounds)
int binarySearchSmallestGreater(vector< halfsegment > &region, double x, int hi=-1, int lo=-1)
int stripID
strip ID
Definition: parPlaneSweep.h:83
bool isLeft() const
double dx
dominating and submissive points
Definition: parPlaneSweep.h:79
void overlayPlaneSweep(const halfsegment r1[], int r1Size, const halfsegment r2[], int r2Size, vector< halfsegment > &result)
bool binarySearchHalfsegment(vector< halfsegment > &region, const halfsegment &h, int &mid, int hi=-1, int lo=0)
Definition: avl.h:66
int la
label above, label below
Definition: parPlaneSweep.h:81
int avlHsegCompare(const void *first, const void *second, void *param)
void * avl_t_copy(struct avl_traverser *trav, const struct avl_traverser *src)
Definition: avl.c:566
void * avl_t_first(struct avl_traverser *trav, struct avl_table *tree)
Definition: avl.c:446
void findIsoBoundaries(vector< halfsegment > &r1, vector< halfsegment > &r2, vector< double > &isoBounds)
bool breakHsegs(const halfsegment &alSeg, halfsegment &origCurr, vector< halfsegment > &brokenSegs, bool &colinear, const bool includeCurrSegInBrokenSegs)
halfsegment getBrother() const
void avl_t_init(struct avl_traverser *trav, struct avl_table *tree)
Definition: avl.c:434