DGtal  0.6.devel
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
FrechetShortcut.ih
1 
29 
30 // IMPLEMENTATION of inline methods.
32 
34 #include <cstdlib>
36 
37 
39 // Class backpath
41 
42 
43 //creation of a backPath
44 // Default constructor
45 template <typename TIterator, typename TInteger>
46 inline
48 {
49  myQuad = 0;
50  myFlag = false;
51 }
52 
53 
54 //creation of a backPath
55 template <typename TIterator, typename TInteger>
56 inline
58 {
59 }
60 
61 template <typename TIterator, typename TInteger>
62 inline
63 DGtal::FrechetShortcut<TIterator, TInteger>::Backpath::Backpath(const Backpath & other): myS(other.myS),myQuad(other.myQuad),myFlag(other.myFlag),myOcculters(other.myOcculters),myForbiddenIntervals(other.myForbiddenIntervals)
64 {
65 }
66 
67 
68 
69 template <typename TIterator, typename TInteger>
70 inline
72 {
73  myFlag = false;
74  myOcculters.clear();
75  myForbiddenIntervals.clear();
76 }
77 
78 
79 //destruction of a backPath
80 template <typename TIterator, typename TInteger>
81 inline
83 { }
84 
85 template <typename TIterator, typename TInteger>
86 inline
88 {
89 
90  myIt = it;
91 
92  switch(d)
93  {
94  case 0:
95  case 1:
96  case 2:
97  case 7:
98  {
99  addPositivePoint();
100  break;
101  }
102  case 3:
103  case 4:
104  case 5:
105  case 6:
106  {
107  addNegativePoint();
108  break;
109  }
110  }
111 }
112 
113 // update the list of active occulters
114 template <typename TIterator, typename TInteger>
115 inline
117 {
118 
119  // The potential new occulter is the last-but-one point
120  Point p = Point(*(myIt-1));
121 
122 
123  Point pi,v;
124  Vector dir = Tools::chainCode2Vect(myQuad);
125  Vector dir_ortho = Tools::chainCode2Vect((myQuad+6)%8);
126 
127 
128  Point u1,u2;
129  u1 = dir;
130  u2 = Tools::chainCode2Vect((myQuad+1)%8);;
131 
132  double angle_min=0;
133  double angle_max=M_PI_4;
134  bool ok = true;
135  bool occ = false;
136 
138 
139  if(myOcculters.size()==0)
140  {
141  occ =true;
142  angle_min=0;
143  angle_max=M_PI_4;
144  }
145  else
146  {
147  typename occulter_list::iterator iter;
148 
149  for(iter = myOcculters.begin();ok && iter!=myOcculters.end() ;++iter)
150  {
151  pi = Point(*(iter->first));
152  v = p-pi;
153 
154  // pi is after p for all directions -> p is not an occulter
155  if(ic.dotProduct(v,u1) < 0 && ic.dotProduct(v,u2) <0)
156  {
157  ok = false;
158  occ = false;
159  }
160  else
161  // p is after pi for all directions -> pi is not an occulter
162  // anymore, p is a new occulter.
163  if(ic.dotProduct(v,u1) > 0 && ic.dotProduct(v,u2) > 0)
164  {
165  myOcculters.erase(iter);
166  occ = true;
167  angle_min = 0;
168  angle_max = M_PI_4;
169  }
170  else
171  // p is after pi on [0,alpha], before pi on [alpha,pi/4]
172  if(ic.dotProduct(v,u1) > 0 && ic.dotProduct(v,u2) <= 0)
173  {
174  double alpha = Tools::angleVectVect(v,dir_ortho);
175 
176  if(alpha >= iter->second.angle_min && alpha <=
177  iter->second.angle_max)
178  {
179  // p is a new occulter
180  occ = true;
181  angle_min = 0;
182  angle_max = alpha;
183  // pi's angle_min is updated
184  iter->second.angle_min = alpha;
185  }
186  else
187  if(alpha > iter->second.angle_max)
188  {
189  //pi is not an occulter anymore
190  myOcculters.erase(iter);
191  occ=true;
192  angle_min = 0;
193  angle_max = M_PI_4;
194  }
195  // if alpha < iter->second.angle_min, pi does not
196  // change, p may be an occulter -> do nothing
197  }
198  else // scalar_product(v,u1) < 0 && scalar_product(v,u2) > 0
199  // p is after pi on [alpha,pi/4], before pi on [0,alpha]
200  {
201  double alpha = Tools::angleVectVect(v,dir_ortho);
202  alpha = M_PI - alpha;
203 
204  if(alpha >= iter->second.angle_min && alpha <=
205  iter->second.angle_max)
206  {
207  occ = true;
208  angle_min = alpha;
209  angle_max = M_PI_4;
210  // pi's angle_max is updated
211  iter->second.angle_max = alpha;
212  }
213  else
214  if(alpha < iter->second.angle_min)
215  {
216  //pi is not an occulter anymore
217  myOcculters.erase(iter);
218  occ=true;
219  angle_min = 0;
220  angle_max = M_PI_4;
221  }
222  // if(alpha > iter->second.angle_max), pi does not
223  // change, p may be an occulter -> do nothing
224 
225  }
226  }
227  }
228 
229  if(occ)
230  {
231  occulter_attributes new_occ;
232  new_occ.angle_min = angle_min;
233  new_occ.angle_max = angle_max;
234  myOcculters.insert(myOcculters.end(),pair<const ConstIterator,occulter_attributes>(myIt-1,new_occ));
235 
236  }
237 
238 
239 }
240 
241 
242 
243 // update the set of intervals
244 template <typename TIterator, typename TInteger>
245 inline
247 {
248  Point p = Point(*myIt);
249 
250  Point pi,v;
251  Vector dir,dir1;
252 
254 
255  for(typename occulter_list::iterator iter =
256  myOcculters.begin(); iter!=myOcculters.end() ;++iter)
257  {
258  pi = Point(*(iter->first));
259 
260  v = p-pi;
261 
262  dir = Tools::chainCode2Vect(myQuad);
263  dir1 = Tools::chainCode2Vect((myQuad+1)%8);
264 
265  if(ic.dotProduct(v,dir)<0 || ic.dotProduct(v,dir1)<0)
266  {
267  if(v.norm()>=myS->myError/sqrt(2.0F))
268  {
269  if(ic.crossProduct(dir,v)<=0)
270  {
271  v[0] = -v[0];
272  v[1] = -v[1];
273  }
274  double angle_v = Tools::angleVectVect(v,dir);
275 
276  double tmp = acos((double) myS->myError/(sqrt(2.0F)*v.norm()));
277  double angle1 = -tmp+angle_v;
278  double angle2 = tmp+angle_v;
279  if(angle1 < 0)
280  angle1 = 0;
281  if(angle2 > M_PI_4)
282  angle2 = M_PI_4;
283 
284  // Define a new interval of forbidden angles and insert it in the list.
285  boost::icl::interval<double>::type s = boost::icl::interval<double>::closed(angle1,angle2);
286  myForbiddenIntervals.insert(s);
287 
288  }
289  }
290  }
291 
292 }
293 
294 
295 // update the length of the longest backpath on a curve part
296 template <typename TIterator, typename TInteger>
297 inline
299 {
300  // if we were on a monotone backpath, the point is an end of backpath
301  // otherwise, do nothing
302  if(myFlag)
303  {
304  myFlag=false;
305  }
306 }
307 
308 
309 
310 /************************************************************/
311 
312 
313 template <typename TIterator, typename TInteger>
314 inline
316 {
317 
318  // if we were on a monotone backpath, do nothing, the backpath
319  // continues
320  // otherwise it is the beggining of a new monotone backpath,
321  // possibly a locally maximal occulting point
322 
323  //trace.info() << "add negative point" << std::endl;
324 
325  if(!myFlag)
326  {
327  myFlag=true;
328  updateOcculters();
329  updateIntervals();
330  }
331  else
332  {
333  updateIntervals();
334  }
335 
336 
337 }
339 // End of class backpath
341 
343 // Class cone
345 
346 
347 //creation of a cone
348 
349 template <typename TIterator, typename TInteger>
350 inline
352 {
353  myInf = true;
354  myMin = 0;
355  myMax = 0;
356 }
357 
358 
359 
360 template <typename TIterator, typename TInteger>
361 inline
363 {
364 
365  // angle0 and angle1 are ordered in direct orientation such that the angle between made by the two directions is lower than PI.
366 
367 
368  // case angle0-angle1 = PI -> infinite cone
369  if(fabs(fabs(angle0-angle1)-M_PI) < 0.00001)
370  {
371  // the orientation is supposed to be ok (depends on the points involved)
372  myMin = angle0;
373  myMax = angle1;
374  }
375  else
376  if(fabs(angle0-angle1)<M_PI)
377  {
378  if(angle0-angle1>0)
379  {
380  myMin = angle1;
381  myMax = angle0;
382  }
383  else
384  {
385  myMin = angle0;
386  myMax = angle1;
387  }
388  }
389  else
390  {
391  // the cone includes the direction of angle=0
392  if(angle0>angle1)
393  {
394  myMin = angle0;
395  myMax = angle1;
396  }
397  else
398  {
399  myMin = angle1;
400  myMax = angle0;
401  }
402  }
403  myInf = false;
404 }
405 
406 template <typename TIterator, typename TInteger>
407 inline
408 DGtal::FrechetShortcut<TIterator,TInteger>::Cone::Cone(double x, double y, double x0, double y0, double x1, double y1)
409 {
410  double angle0 = Tools::computeAngle(x, y, x0, y0);
411  double angle1 = Tools::computeAngle(x, y, x1, y1);
412 
413  assert(angle0 != -1 && angle1 != -1);
414 
415  *this = Cone(angle0,angle1);
416  myInf = false;
417 }
418 
419 template <typename TIterator, typename TInteger>
420 inline
422 {
423  if(myInf)
424  return false;
425  else
426  if(myMin==myMax)
427  return true;
428  else
429  return false;
430 }
431 
432 template <typename TIterator, typename TInteger>
433 inline
435 {
436  myMin =c.myMin;
437  myMax=c.myMax;
438  myInf = c.myInf;
439  return *this;
440 }
441 
442 // // Computes the symmetrical cone
443 template <typename TIterator, typename TInteger>
444 inline
446 {
447  Cone cnew(myMin+M_PI,myMax+M_PI);
448  return cnew;
449 }
450 
451 // Computes the intersection between the self Cone and another one.
452 template <typename TIterator, typename TInteger>
453 inline
455 {
456  Cone res;
457 
458  // computes the intersection between the self cone and one half of another cone
459  res = intersectConesSimple(c);
460 
461  // if they are disjoint, try the intersection with the other half
462  if(res.isEmpty())
463  {
464  Cone sym = c.symmetricalCone();
465  res = intersectConesSimple(sym);
466  }
467 
468  *this = res;
469 }
470 
471 
472 //intersection of the self cone with another cone: considers only one half of the cone
473 template <typename TIterator, typename TInteger>
474 inline
476 {
477  Cone res;
478 
479  // if the cone is infinite, the new cone is c
480  if(myInf)
481  {
482  res = c;
483  res.myInf = false;
484  }
485  else
486  // the directions of the new cone are not included in the old one
487  if(!Tools::isBetween(c.myMin, myMin, myMax, 2*M_PI) && !Tools::isBetween(c.myMax, myMin,
488  myMax,
489  2*M_PI))
490  {
491  // first possibility: the cones are disjoint
492  if(!Tools::isBetween(myMin, c.myMin, c.myMax, 2*M_PI) && !Tools::isBetween(myMax, c.myMin,
493  c.myMax, 2*M_PI))
494  res = Cone(0,0);
495  else
496  // or the new cone includes the old one, nothing changes, the cone remains the same.
497  res = *this;
498  }
499  else
500  // the old cone is "cut" by the new one
501  if(Tools::isBetween(c.myMin, myMin, myMax, 2*M_PI))
502  if(Tools::isBetween(c.myMax, myMin, myMax, 2*M_PI))
503  res = c;
504  else
505  res = Cone(c.myMin, myMax);
506  else
507  res = Cone(myMin,c.myMax);
508 
509  return res;
510 }
511 
512 template <typename TIterator, typename TInteger>
513 inline
515 {
516  out << "[Cone]" << endl;
517  if(myInf)
518  out << "Infinite" << endl;
519  else
520  out << "[Cone min = " << myMin << " max = " << myMax << "]" << endl;
521  out << "[End Cone]" << endl;
522 }
523 
524 
528 
530 // Implementation of inline methods //
531 
532 template <typename TIterator, typename TInteger>
533 inline
535 {
536  myError = 0;
537  myCone = Cone();
538 
539  for(int i=0;i<8;i++)
540  {
541  //backpath b(i,0);
542  Backpath b(this,i);
543  myBackpath.push_back(b);
544  }
545 
546 }
547 
548 
549 template <typename TIterator, typename TInteger>
550 inline
552 {
553  myError = error;
554  myCone = Cone();
555 
556  for(int i=0;i<8;i++)
557  {
558  //backpath b(i,error);
559  Backpath b(this,i);
560  myBackpath.push_back(b);
561  }
562 }
563 
564 
565 
566 
567 template <typename TIterator, typename TInteger>
568 inline
570 {
571  myBegin = it;
572  myEnd = it;
573  resetCone();
574  resetBackpath();
575 }
576 
577 
578 template <typename TIterator, typename TInteger>
579 inline
581 {
583  return other;
584 }
585 
586 
587 template <typename TIterator, typename TInteger>
588 inline
590  resetBackpath();
591  resetCone();
592 
593 }
594 
595 template <typename TIterator, typename TInteger>
596 inline
598 {
599 
600  if(this != &other)
601  {
602  myError = other.myError;
603  myBackpath = other.myBackpath;
604  myCone = other.myCone;
605  myBegin = other.myBegin;
606  myEnd = other.myEnd;
607  }
608  return *this;
609 }
610 
611 template <typename TIterator, typename TInteger>
612 inline
616 {
617  return Reverse(myError);
618 }
619 
620 template <typename TIterator, typename TInteger>
621 inline
622 bool
624  const DGtal::FrechetShortcut<TIterator,TInteger>& other) const {
625  return ((myBegin == other.myBegin) && (myEnd == other.myEnd) && (myError == other.myError));
626 }
627 
628 
629 
630 template <typename TIterator, typename TInteger>
631 inline
632 bool
634  const DGtal::FrechetShortcut<TIterator,TInteger>& other) const {
635  return (!(*this == other));
636 }
637 
638 
639 template <typename TIterator, typename TInteger>
640 inline
641 bool
643 {
644  bool flag = (updateWidth() && updateBackpath());
645 
646  if(flag)
647  ++myEnd;
648 
649  return flag;
650 }
651 
652 
653 template <typename TIterator, typename TInteger>
654 inline
655 bool
657 {
658 
659  return (testUpdateWidth() && testUpdateBackpath());
660 
661 }
662 
663 template <typename TIterator, typename TInteger>
664 inline
666 {
667  double x0, y0,x1,y1;
668 
669  Point firstP = Point(*myBegin);
670  Point newP = Point(*(myEnd+1));
671 
672 
673  Cone newCone=myCone;
674 
675  // compute the tangent points defined by the first point and the
676  // circle C(newP,error)
677  bool intersect = Tools::circleTangentPoints(firstP[0],firstP[1], newP[0], newP[1], myError/(sqrt(2.0F)), &x0, &y0,
678  &x1, &y1);
679 
680  if(intersect)
681  {
682  // define a cone according to the new tangent points
683  Cone c;
684  // case where there is one single tangent point
685  if(fabs(x0-x1) < 0.00001 && fabs(y0-y1) < 0.00001)
686  {
687  double angle = Tools::computeAngle(firstP[0],firstP[1],newP[0],newP[1]);
688  assert(angle != -1);
689  double angle0 = angle - M_PI_2;
690  if(angle0<0)
691  angle0 = angle0+2*M_PI;
692  double angle1 = angle + M_PI_2;
693  if(angle1>2*M_PI)
694  angle1 = angle1-2*M_PI;
695  c = Cone(angle0,angle1);
696  }
697  else
698  c = Cone(firstP[0],firstP[1],x0,y0,x1,y1);
699 
700  newCone.intersectCones(c);
701  }
702 
703  return newCone;
704 
705 }
706 
707 // Test if the new direction belongs to the new cone, but does not
708 // modify myCone
709 template <typename TIterator, typename TInteger>
710 inline
712 {
713  Cone c = computeNewCone();
714 
715  Point firstP = Point(*myBegin);
716  Point newP = Point(*(myEnd+1));
717 
718  if(!(c.isEmpty()))
719  if(c.myInf)
720  return true;
721  else
722  {
723  double angle = Tools::computeAngle(firstP[0], firstP[1], newP[0], newP[1]);
724  assert(angle != -1);
725  return Tools::isBetween(angle,c.myMin,c.myMax,2*M_PI);
726  }
727  else
728  return false;
729 
730 }
731 
732 
733 template <typename TIterator, typename TInteger>
734 inline
736 {
737  // Save the current value of the backpath
738  vector <typename FrechetShortcut<TIterator,TInteger>::Backpath> BackpathSave;
739 
740  for(unsigned int i=0;i<8;i++)
741  {
742  Backpath b(myBackpath[i]);
743  BackpathSave.push_back(b);
744  }
745 
746  // Check whether the next point could be added or not with respect to the backpath
747  bool flag = updateBackpath();
748 
749  // Copy back the values of backpath before the test.
750  for(unsigned int i=0;i<8;i++)
751  myBackpath[i] = Backpath(BackpathSave[i]);
752 
753  return flag;
754 
755 }
756 
757 
758 // Same as testUpdateWidth() but myCone is modified.
759 template <typename TIterator, typename TInteger>
760 inline
762 {
763  Cone c = computeNewCone();
764 
765  myCone = c;
766 
767  Point firstP = Point(*myBegin);
768  Point newP = Point(*(myEnd+1));
769 
770  bool flag = true;
771 
772  if(!(c.isEmpty()))
773  if(c.myInf)
774  flag = true;
775  else
776  {
777  double angle = Tools::computeAngle
778 (firstP[0], firstP[1], newP[0],
779  newP[1]);
780  assert(angle != -1);
781  flag = Tools::isBetween(angle,c.myMin,c.myMax,2*M_PI);
782  }
783  else
784  flag = false;
785 
786  return flag;
787 }
788 
789 template <typename TIterator, typename TInteger>
790 inline
792 {
793  Point prevP = Point(*myEnd);
794  Point P = Point(*(myEnd+1));
795 
796  int d = Tools::computeChainCode(prevP,P);
797 
798  for(unsigned int j=0;j<8;j++)
799  myBackpath[j].updateBackPathFirstQuad(Tools::rot(d,j),myEnd+1);
800 
801 
802  return isBackpathOk();
803 
804 }
805 
806 template <typename TIterator, typename TInteger>
807 inline
809 {
810  // compute the quadrant of the direction of P(i,j)
811 
812  Point firstP = Point(*myBegin);
813  Point P = Point(*(myEnd+1));
814 
815  int q = Tools::computeQuadrant(firstP,P);
816 
817 
818  // to handle non simple curves (a point is visited twice)
819  if(firstP==P)
820  return true;
821 
822  // compute the direction vector pipj
823  Point v;
824  v[0] = P[0]-firstP[0];
825  v[1] = P[1]-firstP[1];
826 
827  // compute the angle between the direction vector and the elementary
828  // direction (defined by the quadrant)
829  Point dir_elem = Tools::chainCode2Vect(q);
830 
831  double angle = Tools::angleVectVect(v,dir_elem);
832 
833  boost::icl::interval_set<double> intervals = myBackpath[q].myForbiddenIntervals;
834 
835  if(contains(intervals,angle))
836  return false;
837 
838  return true;
839 
840 }
841 
842 
843 template <typename TIterator, typename TInteger>
844 inline
846 {
847  for(unsigned int i=0;i<8;i++)
848  {
849  myBackpath[i].reset();
850  }
851 }
852 
853 template <typename TIterator, typename TInteger>
854 inline
856 {
857  myCone.myMin = 0;
858  myCone.myMax = 0;
859  myCone.myInf = true;
860 }
861 
862 
863 template <typename TIterator, typename TInteger>
864 inline
865 TIterator
867  return myBegin;
868 }
869 
870 template <typename TIterator, typename TInteger>
871 inline
872 TIterator
874  ConstIterator i(myEnd); ++i;
875  return i;
876 }
877 
878 
879 
880 template <typename TIterator, typename TInteger>
881 inline
882 std::string
884 {
885  return "FrechetShortcut";
886 }
887 
888 
889 
895 template <typename TIterator, typename TInteger>
896 inline
897 void
899 {
900 
901  out << "[FrechetShortcut]" << endl;
902  out << "(Begin, End)=";
903  out << "("<< Point(*myBegin) << ", " << Point(*myEnd) << ")\n";
904  out << "[End FrechetShortcut]" << endl;
905 
906 }
907 
908 // Implementation of inline functions //
909 
910 template <typename TIterator, typename TInteger>
911 inline
912 std::ostream&
913 DGtal::operator<< ( std::ostream & out,
914  const FrechetShortcut<TIterator,TInteger> & object )
915 {
916  object.selfDisplay( out );
917  return out;
918 }
919 
920 
921 
922 
923 // //
925 
926