Fréchet View  1.6.0
A Tool for Exploring Fréchet Distance Algorithms
structure.cpp
Go to the documentation of this file.
1 
2 #include <structure.h>
3 #include <iostream>
4 #include <tbb/tbb.h>
5 #include <app/workerthread.h>
6 
7 using namespace frechet;
8 using namespace data;
9 using namespace reach;
10 
11 Structure::Structure(int concurrency, volatile bool* the_cancelFlag)
12  : Structure(FreeSpace::ptr(nullptr),concurrency,the_cancelFlag)
13 
14 { }
15 
16 Structure::Structure(const FreeSpace::ptr afs, int aconcurrency, volatile bool* the_cancelFlag)
17  : fs(afs),
18  _boundary{{BoundaryList(),BoundaryList()},
20  concurrency(aconcurrency),
21  cancelFlag(the_cancelFlag)
22 { }
23 
25  : Structure()
26 {
27  copy(that);
28 }
29 
31  : Structure()
32 {
33  swap(that);
34 }
35 
44 void Structure::copy(const Structure& that)
45 {
46 
47  // TODO parallelize ?
48  // create and keep cloned segments
49  for(Orientation ori=HORIZONTAL; ori <= VERTICAL; ++ori)
50  for(Direction dir=FIRST; dir <= SECOND; ++dir)
51  for(Pointer p=that.boundary(ori,dir).first(); p; p=p->next())
52  p->createClone();
53 
54  // adjust h/l pointers
55  for(Orientation ori=HORIZONTAL; ori <= VERTICAL; ++ori)
56  for(Direction dir=FIRST; dir <= SECOND; ++dir)
57  for(Pointer p=that.boundary(ori,dir).first(); p; p=p->next())
58  {
59  if (p->l) {
60  Q_ASSERT(p->l==p->clone()->l);
61  p->clone()->l = p->l->clone();
62  Q_ASSERT(p->l!=p->clone()->l);
63  }
64  if (p->h) {
65  Q_ASSERT(p->h==p->clone()->h);
66  p->clone()->h = p->h->clone();
67  Q_ASSERT(p->h!=p->clone()->h);
68  }
69  }
70 
71  // move cloned segments to 'this'
72  for(Orientation ori=HORIZONTAL; ori <= VERTICAL; ++ori)
73  for(Direction dir=FIRST; dir <= SECOND; ++dir)
74  {
75  BoundaryList& dest = this->boundary(ori,dir);
76  for(Pointer p=that.boundary(ori,dir).first(); p; p=p->next())
77  {
78  dest.insert_last(p->clone());
79 #ifdef QT_DEBUG
80  p->clone()->setOwner(this);
81 #endif
82  //p->clearClone();
83  }
84  }
85 }
86 
88 {
89  swap(that);
90  return *this;
91 }
92 
94 {
95  copy(that);
96  return *this;
97 }
98 
100 {
101  const_cast<FreeSpace::ptr&>(this->fs).swap( const_cast<FreeSpace::ptr&>(that.fs));
102 
103  for (Orientation ori = HORIZONTAL; ori <= VERTICAL; ++ori)
104  for (Direction dir = FIRST; dir <= SECOND; ++dir)
105  this->boundary(ori, dir).swap(that.boundary(ori, dir));
106 }
107 
108 
109 
110 
112 {
113  // TODO parallelize ?
114  for(Direction dir=FIRST; dir <= SECOND; ++dir)
115  {
116  if (shift.x() != 0)
117  for(Pointer p = boundary(HORIZONTAL,dir).first(); p; p = p->next())
118  *p += shift.x();
119 
120  if (shift.y() != 0)
121  for(Pointer p = boundary(VERTICAL,dir).first(); p; p = p->next())
122  *p += shift.y();
123  }
124  // most likely, the Free-Space is now ill-adjusted. Better not use it.
125 }
126 
128 { }
129 
131 {
132  if (fs->wrapRight() || fs->wrapTop()) {
133  // Closed Curve (P)
134  return calculateDouble();
135  }
136  else {
137  // open curve
138  return calculateSingle();
139  }
140 }
141 
143 {
144  calcRecursive(Rect(0,0,fs->n-1,fs->m-1));
145 
146  // is [n-1,m-1] reachable from [0,0] ?
147 
148  for(Orientation o1=HORIZONTAL; o1 <= VERTICAL; ++o1)
149  for(Orientation o2=HORIZONTAL; o2 <= VERTICAL; ++o2)
150  {
151  Pointer u = first(o1).first();
152  Pointer v = second(o2).last();
153 
154  Q_ASSERT(u->contains(0.0));
155  Q_ASSERT(v->contains(o2==HORIZONTAL ? (fs->n-1) : (fs->m-1)));
156 
157  if (u->type==NON_ACCESSIBLE || v->type==NON_ACCESSIBLE)
158  continue;
159 
160  if ((!u->l || compare_interval(u->l,v) <= 0)
161  && (!u->h || compare_interval(v,u->h) <=0))
162  return u;
163  }
164  return nullptr;
165 }
166 
168 {
169  if (fs->wrapRight()) {
172  }
173  else if (fs->wrapTop()) {
175  return findStartingPoint(VERTICAL);
176  }
177  Q_ASSERT(false); // at least one closed curve expected !
178 }
179 
180 void Structure::calculateColumns(int i, int j)
181 {
182  Q_ASSERT(i < fs->n-1);
183  Q_ASSERT(i < j);
184 
185  if (j <= fs->n-1) {
186  // calculate one part
187  Rect r (i,0, j,fs->m-1);
188  calcRecursive(r);
189  }
190  else {
191  // calculate two parts
192  Rect r1 (i,0, fs->n-1,fs->m-1);
193  Rect r2 (0,0, j-(fs->n-1),fs->m-1);
194  Rect s2 (fs->n-1,0, j,fs->m-1);
195 
196  calcRecursive(r1);
197 
198  Structure buddy(fs);
199  buddy.calcRecursive(r2);
200  buddy.shift(Point(fs->n-1,0));
201 
202  merge(VERTICAL, buddy, r1,s2);
203  }
204 }
205 
206 
212 {
213  Rect r1 (0,0,fs->n-1,fs->m-1);
214  calcRecursive(r1);
215 
216  Rect r2;
217  if (fringe==VERTICAL)
218  r2 = Rect(r1.i1, 0, 2*r1.i1, r1.j1);
219  else
220  r2 = Rect(0, r1.j1, r1.i1, 2*r1.j1);
221 
222  // TODO copy & shift in parallel ?
223  Structure buddy(*this);
224  buddy.shift(Point(r2.i0,r2.j0));
225  // Free-Space does not fit shifted structure
226  // it is not needed, anyway
227  // TODO merge in parallel ?
228  merge(fringe,buddy, r1,r2);
229 }
249 {
250  // iterate bottom and top edge
251  int offset = (edge==HORIZONTAL) ? (fs->n-1) : (fs->m-1);
252  Pointer u = first(edge).first();
253  Pointer v = second(edge).first()->clone();
254 
255  for( ; u && v; u = u->next(), v = v->next())
256  {
257  if (u->type==NON_ACCESSIBLE ||
258  v->type==NON_ACCESSIBLE)
259  continue;
260 
261  Q_ASSERT(u->dir!=v->dir);
262  Q_ASSERT(u->lower()+offset==v->lower());
263  Q_ASSERT(u->upper()+offset==v->upper());
264 
265  if ((!u->l || compare_interval(u->l,v) <= 0)
266  && (!u->h || compare_interval(v,u->h) <=0))
267  return u;
268  }
269 
270  return nullptr;
271 }
272 
274  Q_ASSERT(r.i0 >= 0 && r.i1 < fs->n);
275  Q_ASSERT(r.j0 >= 0 && r.j1 < fs->m);
276  Q_ASSERT(r.i0 < r.i1);
277  Q_ASSERT(r.j0 < r.j1);
278 
279  Q_ASSERT(r.i0 < r.i1);
280  Q_ASSERT(r.j0 < r.j1);
281 
282  if (concurrency==1 || (r.width()==1 && r.height()==1)) {
283  doCalcRecursive(r);
284  }
285  else {
286  // set up a TBB dependency graph
287  tbb::flow::graph g;
288  StructureTask* root_task = StructureTask::createTask(this,r,g,concurrency);
289  root_task->start();
290  g.wait_for_all();
291  delete root_task;
292  }
293 }
294 
295 //Structure* owner;
297 : owner(the_owner), node(nullptr)
298 { }
299 
301  delete node;
302 }
303 
304 StructureTask* StructureTask::createTask(Structure* owner, const frechet::Rect& r, tbb::flow::graph& graph, int concurrency)
305 {
306  if (concurrency <= 1 || (r.width()==1 && r.height()==1))
307  return new CalculateTask(owner,r,graph);
308  else
309  return new MergeTask(owner,r,graph,concurrency);
310 }
311 
312 //frechet::Rect r;
313 CalculateTask::CalculateTask(Structure* the_owner, frechet::Rect r, tbb::flow::graph& graph)
314 : StructureTask(the_owner)
315 {
316  node = new node_t(graph, [this,r] (msg_t) {
317  this->owner->doCalcRecursive(r);
318  });
319 }
320 
322  Q_ASSERT(node);
323  node->try_put(msg_t());
324 }
325 
326 
327 MergeTask::MergeTask(Structure* owner, frechet::Rect r, tbb::flow::graph& graph, int concurrency)
328 : StructureTask(owner),
329  buddy(owner->fs),
330  child1(), child2()
331 {
332  Rect r1,r2;
333  Orientation ori;
334 
335  if ((r.i1-r.i0) > (r.j1-r.j0)){
336  // split along the vertical fringe
337  r1 = Rect(r.i0, r.j0, (r.i0+r.i1)/2, r.j1);
338  r2 = Rect((r.i0+r.i1)/2, r.j0, r.i1, r.j1);
339  ori = VERTICAL;
340  }
341  else {
342  // split along the horizonal fringe
343  r1 = Rect(r.i0,r.j0, r.i1, (r.j0+r.j1)/2);
344  r2 = Rect(r.i0, (r.j0+r.j1)/2, r.i1, r.j1);
345  ori = HORIZONTAL;
346  }
347 
348  child1 = createTask(owner,r1,graph, concurrency/2);
349  child2 = createTask(&buddy,r2,graph, concurrency/2);
350 
351  node = new node_t(graph, [this,ori,r1,r2](msg_t) {
352  this->owner->merge(ori,this->buddy,r1,r2);
353  });
354 
355  tbb::flow::make_edge(*child1->node,*node);
356  tbb::flow::make_edge(*child2->node,*node);
357 }
358 
360  Q_ASSERT(child1 && child2);
361  child1->start();
362  child2->start();
363 }
364 
366 {
367  delete child1;
368  delete child2;
369 }
370 
372 {
373  testCancelFlag();
374  if (r.width()==1 && r.height()==1) {
375  // single cell, recursion ends here
376  singleCell(r.i0,r.j0);
377  }
378  else if ((r.i1-r.i0) > (r.j1-r.j0)){
379  // split along the vertical fringe
380  Rect r1 (r.i0, r.j0, (r.i0+r.i1)/2, r.j1);
381  Rect r2 ((r.i0+r.i1)/2, r.j0, r.i1, r.j1);
382  Structure buddy(fs);
383  this->doCalcRecursive(r1);
384  buddy.doCalcRecursive(r2);
385  merge(VERTICAL,buddy, r1,r2);
386  }
387  else {
388  // split along the horizonal fringe
389  Rect r1 (r.i0,r.j0, r.i1, (r.j0+r.j1)/2);
390  Rect r2 (r.i0, (r.j0+r.j1)/2, r.i1, r.j1);
391  Structure buddy(fs);
392  this->doCalcRecursive(r1);
393  buddy.doCalcRecursive(r2);
394  merge(HORIZONTAL,buddy, r1, r2);
395  }
396 }
397 
399 {
400  Pointer i1 = this->first(fringe).first();
401  Pointer i2 = this->second(fringe).first();
402  Pointer j1 = that.first(fringe).first();
403  Pointer j2 = that.second(fringe).first();
404 
405  Q_ASSERT(this->first(fringe).size()==this->second(fringe).size());
406  Q_ASSERT(that.first(fringe).size()==that.second(fringe).size());
407 
408  for( ; i1 && j1; i1=i1->next(), i2=i2->next(), j1=j1->next(), j2=j2->next())
409  {
410  Q_ASSERT(i1->lower()==i2->lower()); // lower bounds are alreay in synch
411  Q_ASSERT(i1->lower()==j1->lower());
412  Q_ASSERT(i1->lower()==j2->lower());
413 
414  Q_ASSERT(i1->upper()==i2->upper()); // i1 and i2 are already in synch
415  Q_ASSERT(j1->upper()==j2->upper()); // j1 and j2 are already in synch
416 
417  if (i1->upper() < j1->upper())
418  { // split 'that'
419  that.split2(j1, i1->upper(), j2);
420  }
421  else if (i1->upper() > j1->upper())
422  { // split 'this'
423  this->split2(i1, j1->upper(), i2);
424  }
425 
426  // connect inner intervals temporarily (needed during merge process)
427  // "brezel" shaped ring pointer
428  crossLink(i1,i2,j1,j2);
429  }
430 
431  if (i1)
432  {
433  // single-point interval at the top of this
434  for ( ; i1; i1=i1->next(), i2=i2->next(), j1=j1->next(), j2=j2->next())
435  {
436  Q_ASSERT(i1->lower()==i1->upper());
437 
438  j1 = that.first(fringe).last();
439  j2 = that.second(fringe).last();
440 
441  that.split2(j1, i1->upper(), j2);
442 
443  crossLink(i1->prev(),i2->prev(), j1,j2);
444  crossLink(i1,i2, j1->next(),j2->next());
445  }
446  }
447  else if (j1)
448  {
449  // single-point interval at the top of that
450  for ( ; j1; i1=i1->next(), i2=i2->next(), j1=j1->next(), j2=j2->next())
451  {
452  Q_ASSERT(j1->lower()==j1->upper());
453 
454  i1 = this->first(fringe).last();
455  i2 = this->second(fringe).last();
456 
457  this->split2(i1, j1->upper(), i2);
458 
459  crossLink(i1,i2, j1->prev(),j2->prev());
460  crossLink(i1->next(),i2->next(), j1,j2);
461  }
462  }
463 
464  Q_ASSERT(this->first(fringe).size()==this->second(fringe).size());
465  Q_ASSERT(this->first(fringe).size()==that.first(fringe).size());
466  Q_ASSERT(this->first(fringe).size()==that.second(fringe).size());
467 }
479 void Structure::split2(Pointer& a, double x, Pointer& b)
480 {
481  a = split(a,x,b);
482  b = split(b,x,a);
483 }
497 {
498  i2->temp._twin = j2; // R1 -> R2
499  j2->temp._twin = j1; // R2 -> L2
500  j1->temp._twin = i1; // L2 -> L1
501  i1->temp._twin = i2; // L1 -> R1
502 }
503 
507 
508 //int iteration=0;
509 
510 void Structure::merge(Orientation fringe, Structure& that,
511  const frechet::Rect& r1, const frechet::Rect& r2)
512 {
513  //Q_ASSERT(++iteration);
514  testCancelFlag();
515 
516  Q_ASSERT(!before_merge || (before_merge(this,&r1, &that,&r2, fringe),true));
517 
518  // adjust intervals
519  synchIntervals(fringe, that);
520 
521  // assumes that all intervals are already adjusted
522  Q_ASSERT(assertSynchedIntervals(
523  first(fringe).first(), second(fringe).first(),
524  that.first(fringe).first(), that.second(fringe).first()));
525 
526  //TODO move to test classes
527  // synching must not affect the integrity of both structures:
528  Q_ASSERT(!before_merge || (before_merge(this,&r1, &that,&r2, fringe),true));
529 
530  // perform merge along the middle fringe
531  markNonAccesible(fringe, that);
532 
533  Q_ASSERT(!before_merge || (before_merge(this,&r1, &that,&r2, fringe),true));
534 
535  // Next we scan through B1 u L1
536  this->scanAndMerge(bottom().first(), fringe);
537  this->scanAndMerge(left().first(), fringe);
538  // analogous for T2 u R2
539  that.scanAndMerge(that.right().first(), fringe);
540  that.scanAndMerge(that.top().first(), fringe);
541 
542  // swap R1 with R2
543  this->second(fringe).swap( that.second(fringe) );
544  // concat top and bottom (that.bottomAndTop becomes empty)
545  this->first(opposite(fringe)).concat(
546  that.first(opposite(fringe)));
547  this->second(opposite(fringe)).concat(
548  that.second(opposite(fringe)));
549 #ifdef QT_DEBUG
550  takeOwnership();
551 #endif
552 
553  Q_ASSERT(!after_merge || (after_merge(this,&r1, &that,&r2, fringe),true));
554 
555 /*
556  mergeConsecutive(HORIZONTAL);
557  mergeConsecutive(VERTICAL);
558 
559  Q_ASSERT(!after_merge || after_merge(this,r1, &that,r2, fringe));
560 */
561 }
562 
564 {
565  // TODO merge consecutive equal intervals to reduce fragmentation
566  // Or, maybe, don't. Reachability Graphs rely on "refined" intervals.
567  // at least equal N intervals
568  Pointer i1=first(ori).first();
569  Pointer i2=second(ori).first();
570 
571  Pointer i1n = i1->next();
572  Pointer i2n = i2->next();
573 
574  while(i1 && i1n)
575  {
576  Q_ASSERT(i2 && i2n);
577  if ((*i1 == *i1n) && (*i2 == *i2n))
578  {
579  merge(first(ori), i1,i1n);
580  merge(second(ori), i2,i2n);
581  }
582  else
583  {
584  i1 = i1n;
585  i2 = i2n;
586  }
587  i1n = i1->next();
588  i2n = i2->next();
589  }
590 }
591 
593 {
594 #ifdef QT_DEBUG
595  for(Orientation ori=HORIZONTAL; ori <= VERTICAL; ++ori)
596  for(Direction dir=FIRST; dir <= SECOND; ++dir)
597  for(Pointer p=boundary(ori,dir).first(); p; p=p->next())
598  p->setOwner(this);
599 #endif
600 }
601 
603 {
604  p = prev(p);
605  while(p && p->type==NON_ACCESSIBLE)
606  p = prev(p);
607  return p;
608 }
609 
611 {
612  p = next(p);
613  while(p && p->type==NON_ACCESSIBLE)
614  p = next(p);
615  return p;
616 }
617 
619 {
620  // iterate all segments that point to K
621  // iterate from K.l to K.h
622  StructureIterator L (*this, *K, K1);
623  for( ; L; ++L) {
624  // update l,h pointers that point to K
625  if ((L->l != K) && (L->h != K)) continue;
626 
627  if (L->h==K) L->h = h;
628  if (L->l==K) L->l = l;
629 
630  switch(L->type)
631  {
632  case REACHABLE:
633  if ((!L->l || !L->h) || empty_interval(*L)) {
634  // segment becomes empty (n)
635  L->clear();
636  }
637  else {
638  Q_ASSERT(!empty_interval(*L));
639  Q_ASSERT(assertPointerInterval((Pointer)L,*L));
640  }
641  break;
642  case SEE_THROUGH:
643  // l,h pointers must point UP, resp. DOWN
644  if ((!L->l && !L->h) || empty_see_through_interval((Pointer)L))
645  {
646  L->clear();
647  // TODO simplify
648  }
649  else {
650  Q_ASSERT(assertPointerInterval((Pointer)L,*L));
651  }
652  break;
653  }
654  }
655 }
672 {
673 
674  Pointer K1 = this->first(fringe).first();
675  Pointer K = this->second(fringe).first();
676  Pointer I = that.first(fringe).first();
677  Pointer I2 = that.second(fringe).first();
678 
679  for( ; K && I; K=K->next(), I=I->next(), K1=K1->next(), I2=I2->next())
680  {
681  // see [alt95]
682  if (K->type!=NON_ACCESSIBLE && I->type==NON_ACCESSIBLE) {
683  // R1 becomes n
684  this->markNonAccesible(K,K1);
685  }
686  else if (I->type!=NON_ACCESSIBLE && K->type==NON_ACCESSIBLE) {
687  // L2 becomes n
688  that.markNonAccesible(I,I2);
689  }
690  }
691 }
692 
694 {
695  Q_ASSERT(K->type!=NON_ACCESSIBLE);
696  K->type = NON_ACCESSIBLE;
697  // all h-pointers into that segment are lowered
698  Pointer h2 = this->prevReachable(K);
699  // all l-pointers into that segment are increased
700  Pointer l2 = this->nextReachable(K);
701 
702  Q_ASSERT(!l2 || (l2->type!=NON_ACCESSIBLE));
703  Q_ASSERT(!h2 || (h2->type!=NON_ACCESSIBLE));
704 
705  // update all segments pointing to K
706  updatePointers(K, l2, h2, K1);
707 
708  if (K1->type==SEE_THROUGH)
709  {
710  // s-n becomes r-n
711  K1->type = REACHABLE;
712  if (!K1->l) K1->l = l2;
713  if (!K1->h) K1->h = h2;
714 
715  if (!K1->l || !K1->h || empty_interval(*K1)) {
716  // segment becomes empty (n)
717  K1->type = NON_ACCESSIBLE;
718  K1->clear();
719  }
720  else {
721  Q_ASSERT(! empty_interval(*K1));
722  Q_ASSERT(assertPointerInterval(K1,*K1));
723  }
724 
725  }
726 
727  K->clear(); // clear l and h
728 }
748 {
749  // TODO parallelize? or better not touch ...
750  for( ; K; K=K->next())
751  {
752  if (K->type==NON_ACCESSIBLE) continue;
753  Q_ASSERT(K->type==REACHABLE || K->type==SEE_THROUGH);
754 
755  // 1. if h(K) exists ...
756  if (K->h && K->h->ori==fringe)
757  { // ... and points into some r- or s- interval I of L2
758  Pointer I = K->h->twin(2);
759  Q_ASSERT(I->ori==K->h->ori);
760  Q_ASSERT(I->dir!=K->h->dir);
761  Q_ASSERT(((Interval)*I)==((Interval)*K->h));
762 
763  switch(I->type)
764  {
765  case REACHABLE:
766  Q_ASSERT(! empty_interval(*I));
767  Q_ASSERT(I->h);
768  K->h = I->h;
769  break;
770  case SEE_THROUGH:
771  if (I->h) {
772  K->h = I->h;
773  }
774  else {
775  Q_ASSERT(K->h->twin(1)==I->twin(3));
776  K->h = I->twin(3);
777  }
778  break;
779  }
780  Q_ASSERT(K->h);
781  }
782  // 2. if l(K) exists and points into some interval I in L2
783  if (K->l && K->l->ori==fringe)
784  {
785  Pointer I = K->l->twin(2);
786  Q_ASSERT(I->ori==K->l->ori);
787  Q_ASSERT(I->dir!=K->l->dir);
788  Q_ASSERT(((Interval)*I)==((Interval)*K->l));
789 
790  switch(I->type)
791  {
792  case REACHABLE:
793  // 2.1 if I is type r, then l(K) := l(I)
794  Q_ASSERT(! empty_interval(*I));
795  Q_ASSERT(I->l);
796  K->l = I->l;
797  break;
798  case SEE_THROUGH:
799  if (I->l) {
800  K->l = I->l;
801  }
802  else {
803  // 2.2 if I is type s then set l(K) to the lower endpoint of R2
804  Q_ASSERT(K->l->twin(1)==I->twin(3));
805  K->l = I->twin(3);
806  }
807  break;
808  }
809  }
810  // 3. if K is type s and K' is the corresponding interval at L2
811  if (K->type==SEE_THROUGH && K->ori==fringe)
812  {
813  // 3.1 if K' is type r then set K to type r and and l(K) := l(K')
814  //Q_ASSERT(K->twin(3)==K2->twin(2));
815  Pointer K3 = K->twin(3);
816  Q_ASSERT(K3->dir==K->dir);
817  Q_ASSERT(K3->ori==K->ori);
818  if (K3->type==REACHABLE) {
819  K->type = REACHABLE;
820  //Q_ASSERT(!K->l);
821  //Q_ASSERT(K3->l);
822  if (!K->l) K->l = K3->l;
823  if (!K->h) K->h = K3->h;
824  Q_ASSERT(K->l && K->h);
825  }
826  }
827 
828  Q_ASSERT(!K->l || K->type!=NON_ACCESSIBLE);
829  Q_ASSERT(!K->h || K->type!=NON_ACCESSIBLE);
830  Q_ASSERT(K->type==SEE_THROUGH || ! empty_interval(*K));
831  Q_ASSERT(assertPointerInterval(K,*K));
832  }
833 }
834 
847 {
848  Q_ASSERT(seg->contains(y));
849  // split interval at 'y'
850  BoundaryList& list = boundary(seg->ori,seg->dir);
851 
852  Pointer copy = new BoundarySegment(*seg);
853  copy->upper() = seg->lower() = y;
854 
855  list.insert_before(copy,seg);
856 
857  Q_ASSERT(copy->next()==seg);
858  Q_ASSERT(seg->prev()==copy);
859 
860  if (seg->type!=NON_ACCESSIBLE)
861  { // update pointers that can see 'seg'
862 /*
863  * PointerInterval ival = *seg;
864  if (!ival.l) {
865  // missing "see-through" pointer
866  Q_ASSERT(seg->type==SEE_THROUGH);
867  Q_ASSERT((seg->ori==VERTICAL && seg->dir==FIRST)
868  || (seg->ori==HORIZONTAL && seg->dir==SECOND));
869  ival.l = twin;
870  }
871  if (!ival.h) {
872  Q_ASSERT(seg->type==SEE_THROUGH);
873  Q_ASSERT((seg->ori==VERTICAL && seg->dir==SECOND)
874  || (seg->ori==HORIZONTAL && seg->dir==FIRST));
875  ival.h = twin;
876  }
877 
878  Q_ASSERT(ival.l && ival.h);
879 */
880  StructureIterator i (*this, *seg, twin);
881  if (seg->ori==VERTICAL)
882  {
883  // l-pointers into vertical 'seg' are adjusted to 'copy'
884  for( ; i; ++i)
885  if (i->l == seg) {
886  i->l = copy;
887  Q_ASSERT(assertPointerInterval((Pointer)i,*i));
888  }
889  }
890  else
891  {
892  // h-pointers into horizontal 'seg' are adjusted to 'copy'
893  // EXCEPT h-pointers of S intervals
894  Q_ASSERT(seg->ori==HORIZONTAL);
895  for( ; i; ++i)
896  if (i->h == seg) {
897  i->h = copy;
898  Q_ASSERT(assertPointerInterval((Pointer)i,*i));
899  }
900  }
901  }
902 
903  return copy;
904 }
905 
907 {
908  b->lower() = a->lower();
909  list.remove(a);
910  // TODO correct all pointers into a
911  // see split()
912 
913  delete a;
914 }
915 
917 {
918  Pointer result = p->next(p->ori);
919  // HORIZONTAL = 0 = p->prev()
920  // VERTICAL = 1 = p->next()
921  if (!result)
922  {
923  // bottom-left corner
924  if (p->ori==HORIZONTAL && p->dir==BOTTOM_LEFT)
925  result = left().first();
926  // right-top corner
927  if (p->ori==VERTICAL && p->dir==RIGHT_TOP)
928  result = top().last();
929  }
930  return result;
931 }
932 
934 {
935  Pointer result = p->next(1 - p->ori);
936  // HORIZONTAL = 0 = p->next()
937  // VERTICAL = 1 = p->prev()
938  if (!result)
939  {
940  // left-bottom corner
941  if (p->ori==VERTICAL && p->dir==BOTTOM_LEFT)
942  result = bottom().first();
943  // top-right corner
944  if (p->ori==HORIZONTAL && p->dir==RIGHT_TOP)
945  result = right().last();
946  }
947  return result;
948 }
949 
950 
952  if (cancelFlag && *cancelFlag) {
954  }
955 }
956 
957 
959 {
960  if (p->dir==FIRST) {
961  if (p->type==SEE_THROUGH) {
962  // l and h-pointers must point UP
963  Q_ASSERT(ival.l || ival.h);
964  Q_ASSERT(! ival.h || (compare_pointers(p,ival.h) <= 0) );
965  Q_ASSERT(! ival.l || (compare_pointers(p,ival.l) <= 0) );
966  }
967  else {
968  // l and h-pointers must point UP (strictly, otherwise it would be a see-through)
969  Q_ASSERT(ival.l && ival.h);
970  Q_ASSERT( (compare_pointers(p,ival.h) <= 0) && (p!=ival.h) );
971  Q_ASSERT( (compare_pointers(p,ival.l) <= 0) && (p!=ival.l) );
972  }
973  }
974  else
975  {
976  if (p->type==SEE_THROUGH) {
977  // l and h-pointers must point DOWN
978  Q_ASSERT(ival.l || ival.h);
979  Q_ASSERT(! ival.h || (compare_pointers(p,ival.h) >= 0) );
980  Q_ASSERT(! ival.l || (compare_pointers(p,ival.l) >= 0) );
981  }
982  else {
983  // l and h-pointers must point DOWN (strictly, otherwise it would be a see-through)
984  Q_ASSERT(ival.l && ival.h);
985  Q_ASSERT( (compare_pointers(p,ival.h) >= 0) && (p!=ival.h) );
986  Q_ASSERT( (compare_pointers(p,ival.l) >= 0) && (p!=ival.l) );
987  }
988  }
989  return true;
990 }
991 
993 {
994  for( ; i1; i1=i1->next(), i2=i2->next(), i3=i3->next(), i4=i4->next()) {
995  Q_ASSERT(i1->lower()==i2->lower());
996  Q_ASSERT(i1->upper()==i2->upper());
997 
998  Q_ASSERT(i1->lower()==i3->lower());
999  Q_ASSERT(i1->upper()==i3->upper());
1000 
1001  Q_ASSERT(i1->lower()==i4->lower());
1002  Q_ASSERT(i1->upper()==i4->upper());
1003 
1004  // Brezel-shaped ring pointer
1005  Q_ASSERT(i2->twin(1)==i4);
1006  Q_ASSERT(i2->twin(2)==i3);
1007  Q_ASSERT(i2->twin(3)==i1);
1008  Q_ASSERT(i2->twin(4)==i2);
1009 
1010  Q_ASSERT(i3->twin(1)==i1);
1011  Q_ASSERT(i3->twin(2)==i2);
1012  Q_ASSERT(i3->twin(3)==i4);
1013  Q_ASSERT(i3->twin(4)==i3);
1014  }
1015 
1016  Q_ASSERT(!i1 && !i2 && !i3 && !i4);
1017  return true;
1018 }
1019 
1020 
1022  const PointerInterval& ival,
1023  Pointer ifnull)
1024  : str(astr), current(ival.l), last(ival.h)
1025 {
1026  if (!current) current = ifnull;
1027  if (!last) last = ifnull;
1028 
1029  Q_ASSERT(current && last);
1030  Q_ASSERT(current->dir == last->dir);
1031  Q_ASSERT(!empty_interval(current,last));
1032 }
1033 
1034 StructureIterator::StructureIterator(const Structure& astr, Pointer a, Pointer b)
1035  : str(astr), current(a), last(b)
1036 {
1037  Q_ASSERT(current && last);
1038  Q_ASSERT(current->dir == last->dir);
1039  Q_ASSERT(!empty_interval(current,last));
1040 }
1041 
1043 {
1044  if (current==last)
1045  current = NULL; // EOF
1046  else
1047  current = str.next(current);
1048  return *this;
1049 }
1050 
1051 std::ostream& frechet::reach::operator<<(std::ostream &out, const Structure &str)
1052 {
1053  return out << "{" << str.bottom() << std::endl
1054  << " "<<str.top() << std::endl
1055  << " "<<str.left() << std::endl
1056  << " "<<str.right() << "}" << std::endl;
1057 }
void testCancelFlag()
check for user interrupion The canceFlag should be polled in regular intervals. If the user requested...
Definition: structure.cpp:951
void calculateColumns(int i, int j)
compute a region of the reachability structure. may span the double free-space!.
Definition: structure.cpp:180
StructureTask(Structure *owner)
constructor with Structure
Definition: structure.cpp:296
BoundaryList & first(Orientation ori)
Definition: structure.h:129
bool empty_see_through_interval(Pointer p)
test intersection of intervals. Assumes a SEE_THROUGH segment.
Definition: boundary.cpp:203
BoundaryList & left()
Definition: structure.h:161
StructureIterator & operator++()
pre-increment; advance the iterator
Definition: structure.cpp:1042
static assert_hook after_single_cell
Definition: structure.h:473
void insert_last(BLinkedListElement *el)
insert a new element at the end of the list; the list takes ownership of the element....
Definition: linkedlist.cpp:52
void singleCell(int i, int j)
create a BoundarySegment from one cell of the free-space-diagram
reachable: other intervals are reachable
Definition: boundary.h:21
int j1
top bound, exclusive
Definition: types.h:39
bottom and left part of the reachability structure
Definition: boundary.h:121
void split2(Pointer &a, double x, Pointer &b)
split a reachabiliy segment and its opposite segment
Definition: structure.cpp:479
BoundaryList & second(Orientation ori)
Definition: structure.h:134
virtual ~MergeTask()
destructor; releases memory
Definition: structure.cpp:365
a sub-task, computing a region of the reachability structure
Definition: structure.h:594
task object for parallel execution. When the reachability structur is computed in parallel threads,...
Definition: structure.h:553
static StructureTask * createTask(Structure *owner, const frechet::Rect &r, tbb::flow::graph &graph, int concurrency)
static constructor
Definition: structure.cpp:304
see-through: other interals are visible with a straight line
Definition: boundary.h:23
global definitions for all algorithms.
StructureTask * child2
prerquisite task; only after child1 and child2 are finished, start the merging task
Definition: structure.h:619
void calcRecursive(const Rect &r)
Divide & Conquer algorithm. Merge regions recursively. Makes use of paralel threads.
Definition: structure.cpp:273
tbb::flow::continue_msg msg_t
used to connect nodes in the dependency graph
Definition: structure.h:581
const Orientation ori
horizontal or vertical
Definition: boundary.h:318
non-accesible. no interval is reachable from this one
Definition: boundary.h:19
static assert_hook before_merge
Definition: structure.h:473
data::LinkedList< BoundarySegment > BoundaryList
a double-linked list of reachability segments. makes up one of the four edges of a reachability struc...
Definition: boundary.h:461
int concat(BLinkedList &that)
append all elements of another list, taking ownership of the new elements
Definition: linkedlist.cpp:145
int width() const
Definition: types.h:63
Direction
direction of a Pointer inside the reachability structure.
Definition: boundary.h:115
Pointer current
current location of the iterator
Definition: structure.h:494
static assert_hook after_merge
Definition: structure.h:473
The StructureIterator class.
Definition: structure.h:488
void(* assert_hook)(Structure *, const Rect *, Structure *, const Rect *, Orientation)
hooks for Unit Tests. Only used in debug mode.
Definition: structure.h:468
thrown by long-runner tasks
Definition: workerthread.h:27
Pointer nextReachable(Pointer p)
find next reachable segment
Definition: structure.cpp:610
struct frechet::reach::BoundarySegment::@4 temp
temporary data used during merge and split operations
boundary interval in the reachability structure. Represents an interval on the boundary of the FreeSp...
Definition: boundary.h:285
Pointer prevReachable(Pointer p)
find previous reachable segment
Definition: structure.cpp:602
virtual ~StructureTask()
destructor
Definition: structure.cpp:300
void mergeConsecutive(Orientation ori)
could be used to merge indentical intervals. Reduces the number of intervals (and thus the complexity...
Definition: structure.cpp:563
describes l,h pointers. Both pointers are assumed to point into the same rectangle section (right-top...
Definition: boundary.h:160
Structure * owner
the underlying reachability structure
Definition: structure.h:586
Pointer twin(int hops)
Definition: boundary.h:309
void copy(const Structure &that)
assigment function
Definition: structure.cpp:44
double upper() const
Definition: interval.h:96
int compare_pointers(Pointer a, Pointer b)
compare two pointers on opposite parts of a reachability structure (eitehr left->right-top,...
Definition: boundary.cpp:214
BoundaryList & right()
Definition: structure.h:163
void swap(Structure &that)
swap content with another object
Definition: structure.cpp:99
BoundaryList & boundary(Orientation ori, Direction dir)
Definition: structure.h:113
StructureIterator(const Structure &str, Pointer first, Pointer last)
constructor with two segments
void merge(Orientation fringe, Structure &that, const Rect &r1, const Rect &r2)
merge this structure with another structure
volatile bool * cancelFlag
used when running ia a background thread to indicate cancellation by the user
Definition: structure.h:42
MergeTask(Structure *owner, frechet::Rect r, tbb::flow::graph &graph, int concurrency)
default constructor
Definition: structure.cpp:327
Structure & operator=(const Structure &that)
assigment operator
Definition: structure.cpp:93
int height() const
Definition: types.h:67
virtual ~Structure()
destructor; releases all memory
Definition: structure.cpp:127
Structure(int concurrency=1, volatile bool *cancelFlag=nullptr)
empty constructor
void shift(Point offset)
shift the reachability structure by a given offset. The shifted second copy is then merged to compute...
Definition: structure.cpp:111
BoundarySegment * Pointer
(dumb) pointer to a BoundarySegment object
Definition: boundary.h:55
BoundaryList & top()
Definition: structure.h:167
static bool assertPointerInterval(Pointer p, const PointerInterval &ival)
for debugging and unit tests, check if reachability intervals are consistent
Definition: structure.cpp:958
int i1
right bound, exclusive
Definition: types.h:38
Pointer last
last segment
Definition: structure.h:496
Type type
reachability label
Definition: boundary.h:317
QPointF Point
a point in the plane; with double floating point precision. This type is heavily used throughout all ...
Definition: types.h:14
void synchIntervals(Orientation fringe, Structure &that)
before mergin two reachabiliry structures, its intervals must be synchronized
Definition: structure.cpp:398
a very simple Rectangle structure, with integer boundaries.
Definition: types.h:35
int j0
top bound, inclusive
Definition: types.h:37
Pointer split(Pointer seg, double y, Pointer twin)
split a reachabiliy segment Adjust l,h pointers into that segment.
Definition: structure.cpp:846
void crossLink(Pointer i1, Pointer i2, Pointer j1, Pointer j2)
set up links between four opposite segments. This pointer chain will be used to traverse a reachabili...
Definition: structure.cpp:496
std::ostream & operator<<(std::ostream &out, const BoundaryList &list)
print operator for debugging
Definition: boundary.cpp:272
void updatePointers(Pointer K, Pointer l, Pointer h, Pointer K1)
update all l,h, pointers that point into a segment
Definition: structure.cpp:618
bool contains(double x) const
containment test
Definition: boundary.h:369
Pointer calculateSingle()
compute the reachability structure for an open curve, based on a single free-space-diagram.
Definition: structure.cpp:142
right and top part of the reachability structure
Definition: boundary.h:122
void clear()
clears pointers, keep interval bounds
Definition: boundary.h:359
Orientation
Segment Orientation.
Definition: boundary.h:31
tbb::flow::continue_node< msg_t > node_t
a node in the dependency graph
Definition: structure.h:583
void swap(LinkedList< T > &that)
exchange all elements with another list, taking ownership of the new elements
Definition: linkedlist.h:312
double lower() const
Definition: interval.h:92
void takeOwnership()
for debugging: fill in owner pointers
Definition: structure.cpp:592
const FreeSpace::ptr fs
the underlying free-space; may be nullptr
Definition: structure.h:36
CalculateTask(Structure *owner, frechet::Rect r, tbb::flow::graph &graph)
default constructor
Definition: structure.cpp:313
Pointer calculate()
compute the reachability structure from the underlying free-space diagram. Uses a divide-and-conquere...
Definition: structure.cpp:130
second segment = right and top edge
Definition: boundary.h:118
const Direction dir
left/right or bottom/top
Definition: boundary.h:319
void doCalcRecursive(const Rect &r)
Merge regions recursively. Uses only one thread.
Definition: structure.cpp:371
const Structure & str
the associated reachability structure
Definition: structure.h:492
Pointer l
points to the lowest segment of the interval
Definition: boundary.h:161
int compare_interval(Pointer a, Pointer b)
compare two pointers in the same part of a reachability structure (either right-top,...
Definition: boundary.cpp:148
StructureTask * child1
prerquisite task; only after child1 and child2 are finished, start the merging task
Definition: structure.h:617
int i0
left bound, inclusive
Definition: types.h:36
Pointer next(Pointer p) const
used when traversing reachability segments. Traversal direction is discussed in frechet::reach::Direc...
Definition: structure.cpp:916
#define str(S)
void markNonAccesible(Orientation fringe, Structure &that)
mark non-accesible segments
Definition: structure.cpp:671
virtual void start() override
computes the reachability structure for the given region
Definition: structure.cpp:321
Orientation opposite(Orientation ori)
Definition: boundary.h:39
The FreeSpace class models the Free-Space Diagram calculated from two curves.
Definition: freespace.h:83
virtual void start() override
perform the merging
Definition: structure.cpp:359
int concurrency
number of parallel threads to use
Definition: structure.h:40
Structure buddy
structure to merge with
Definition: structure.h:615
The Reachability Structure; maintains a list of intervals on the border of Free Space,...
Definition: structure.h:32
Pointer prev(Pointer p) const
used when traversing reachability segments. Traversal direction is discussed in frechet::reach::Direc...
Definition: structure.cpp:933
Pointer h
points to the highest segment of the interval
Definition: boundary.h:162
Pointer findStartingPoint(Orientation edge)
after the reachability structure is computed, find the starting interval of a feasible path....
Definition: structure.cpp:248
first segment = bottom and left edge
Definition: boundary.h:117
virtual void start()=0
abstract method for starting a task
an interval of two double values.
Definition: interval.h:31
node_t * node
a node in the dependency graph
Definition: structure.h:588
BoundaryList & bottom()
Definition: structure.h:165
Pointer _twin
points to a segment on the opposite edge of the reachability structure. twins have the same boundary ...
Definition: boundary.h:298
void scanAndMerge(Pointer K, Orientation fringe)
scan and merge one segment
Definition: structure.cpp:747
boost::shared_ptr< FreeSpace > ptr
smart pointer to FreeSpace object
Definition: freespace.h:92
bool empty_interval(Pointer a, Pointer b)
test intersection of intervals
Definition: boundary.cpp:191
static bool assertSynchedIntervals(Pointer i1, Pointer i2, Pointer i3, Pointer i4)
for debugging and unit tests, check if reachability intervals are consistent
Definition: structure.cpp:992
a sub-taks, performing the merging of two reachability structures
Definition: structure.h:612
Pointer calculateDouble()
compute the reachability structure for a closed curve, based on a double-free-space-diagram.
Definition: structure.cpp:167