DGtal  0.9.3
testStabbingCircleComputer.cpp
Go to the documentation of this file.
1 
30 #include <iostream>
32 #include "DGtal/base/Common.h"
33 
34 //space / domain
35 #include "DGtal/kernel/SpaceND.h"
36 #include "DGtal/kernel/domains/HyperRectDomain.h"
37 #include "DGtal/topology/KhalimskySpaceND.h"
38 
39 //shape and digitizer
40 #include "DGtal/shapes/ShapeFactory.h"
41 #include "DGtal/shapes/Shapes.h"
42 #include "DGtal/topology/helpers/Surfaces.h"
43 #include "DGtal/shapes/GaussDigitizer.h"
44 #include "DGtal/geometry/curves/GridCurve.h"
45 
46 //Segment computer and DCA
47 #include "DGtal/geometry/curves/CBidirectionalSegmentComputer.h"
48 
49 #include "DGtal/geometry/curves/StabbingCircleComputer.h"
50 
51 #include "DGtal/geometry/curves/SegmentComputerUtils.h"
52 #include "DGtal/geometry/curves/GreedySegmentation.h"
53 #include "DGtal/geometry/curves/SaturatedSegmentation.h"
54 
55 //boards
56 #include "DGtal/io/boards/Board2D.h"
57 #include "DGtal/io/boards/CDrawableWithBoard2D.h"
58 
59 #include "ConfigTest.h"
60 
62 
63 using namespace std;
64 using namespace DGtal;
65 
67 // digital circle generator
68 template<typename TKSpace>
70 ballGenerator(double aCx, double aCy, double aR, bool aFlagIsCW)
71 {
72 
73  // Types
74  typedef TKSpace KSpace;
75  typedef typename KSpace::SCell SCell;
77  typedef typename KSpace::Space Space;
78  typedef Ball2D<Space> Shape;
79  typedef typename Space::Point Point;
80  typedef typename Space::RealPoint RealPoint;
82 
83  //Forme
84  Shape aShape(Point(aCx,aCy), aR);
85 
86  // Window for the estimation
87  RealPoint xLow ( -aR-1, -aR-1 );
88  RealPoint xUp( aR+1, aR+1 );
90  dig.attach( aShape ); // attaches the shape.
91  dig.init( xLow, xUp, 1 );
92  Domain domain = dig.getDomain();
93  // Create cellular space
94  KSpace K;
95  bool ok = K.init( dig.getLowerBound(), dig.getUpperBound(), true );
96  if ( ! ok )
97  {
98  std::cerr << " "
99  << " error in creating KSpace." << std::endl;
100  return GridCurve();
101  }
102  try
103  {
104 
105  // Extracts shape boundary
107  SCell bel = Surfaces<KSpace>::findABel( K, dig, 10000 );
108  // Getting the consecutive surfels of the 2D boundary
109  std::vector<Point> points, points2;
110  Surfaces<KSpace>::track2DBoundaryPoints( points, K, SAdj, dig, bel );
111  //counter-clockwise oriented by default
112  GridCurve c;
113  if (aFlagIsCW)
114  {
115  points2.assign( points.rbegin(), points.rend() );
116  c.initFromVector(points2);
117  }
118  else
119  {
120  c.initFromVector(points);
121  }
122  return c;
123  }
124  catch ( InputException e )
125  {
126  std::cerr << " "
127  << " error in finding a bel." << std::endl;
128  return GridCurve();
129  }
130 }
131 
133 // Functions for testing class StabbingCircleComputer.
135 
137 {
138  typedef std::pair<PointVector<2,int>, PointVector<2,int> > Pair;
139  typedef std::vector<Pair>::const_iterator ConstIterator;
140  typedef StabbingCircleComputer<ConstIterator> GeomDSS;
141  BOOST_CONCEPT_ASSERT(( concepts::CDrawableWithBoard2D<GeomDSS> ));
142  BOOST_CONCEPT_ASSERT(( concepts::CBidirectionalSegmentComputer<GeomDSS> ));
143 }
144 
145 /*
146 * simple drawing
147 */
148 template <typename TCurve>
149 bool drawingTestStabbingCircleComputer(const TCurve& curve, const string& suffix)
150 {
151 
152  typedef typename TCurve::IncidentPointsRange Range; //range
153  Range r = curve.getIncidentPointsRange(); //range
154 
155  {
156  typedef typename Range::ConstIterator ConstIterator; //iterator
158  longestSegment(s,r.begin(),r.end());
159 
160  Board2D board;
161  board << r << s;
162  std::stringstream ss;
163  ss << "StabbingCircleComputerDrawingTest" << suffix << ".eps";
164  board.saveEPS(ss.str().c_str());
165  }
166 
167  {
168  typedef typename Range::ConstReverseIterator ConstReverseIterator; //iterator
170  longestSegment(s,r.rbegin(),r.rend());
171 
172  Board2D board;
173  board << r << s;
174  std::stringstream ss;
175  ss << "StabbingCircleComputerDrawingTest" << suffix << "2.eps";
176  board.saveEPS(ss.str().c_str());
177  }
178 
179  return true;
180 }
181 
185 template <typename TCurve>
186 bool testStabbingCircleComputer(const TCurve& curve)
187 {
188 
189  typedef typename TCurve::IncidentPointsRange Range; //range
190  typedef typename Range::ConstIterator ConstIterator; //iterator
191  typedef typename Range::ConstReverseIterator ConstReverseIterator; //reverse iterator
192 
193  unsigned int nbok = 0;
194  unsigned int nb = 0;
195 
196  trace.beginBlock ( "Constructors, copy, assignement" );
197  {
198  Range r = curve.getIncidentPointsRange(); //range
199 
201  longestSegment(s2, r.begin(), r.end());
202  longestSegment(s3, r.begin()+1, r.end());
205  s3 = s1;
206 
207  trace.info() << s1.isValid() << s1 << endl;
208  trace.info() << s2.isValid() << s2 << endl;
209  trace.info() << s3.isValid() << s3 << endl;
210  trace.info() << s4.isValid() << s4 << endl;
211  trace.info() << s5.isValid() << s5 << endl;
212 
213  bool myFlag = (!s1.isValid())&&(!s3.isValid())
214  &&(s2.isValid())&&(s4.isValid())&&(s5.isValid())
215  &&(s2 == s4)&&(s2 != s5)&&(s2 != s1)
216  &&(s3 != s5)&&(s1 == s3);
217 
218  nbok += myFlag ? 1 : 0;
219  nb++;
220  }
221  trace.endBlock();
222 
223 
224  trace.beginBlock ( "Extension operations" );
225  {
226  Range r = curve.getIncidentPointsRange(); //range
227 
229 
230  trace.info() << "forward extension " << endl;
231 
232  ConstIterator itBegin (r.begin());
233  ConstIterator itEnd (r.end());
234 
235  s.init( itBegin );
236  while ( (s.end() != itEnd) && (s.isExtendableFront()) && (s.extendFront()) ) {}
237  trace.info() << s << endl;
238 
239  ConstIterator itLast (s.end()); --itLast;
240 
241  t.init( itLast );
242  while ( (t.begin() != itBegin) && (t.extendBack()) ) {}
243  trace.info() << t << endl;
244 
245  trace.info() << "backward extension " << endl;
246 
248  ConstReverseIterator ritBegin ( s.end() );
249  ConstReverseIterator ritEnd ( itBegin );
250 
251  rs.init( ritBegin );
252  while ( (rs.end() != ritEnd) && (rs.isExtendableFront()) && (rs.extendFront()) ) {}
253  trace.info() << rs << endl;
254 
255  ConstReverseIterator ritLast (rs.end()); --ritLast;
256 
258  rt.init( ritLast );
259  while ( (rt.begin() != ritBegin) && (rt.extendBack()) ) {}
260  trace.info() << rt << endl;
261 
262  trace.info() << "comparison... " << endl;
263  bool myFlag = (s == t)
264  &&(rs == rt);
265 
266  nbok += myFlag ? 1 : 0;
267  nb++;
268  }
269  trace.endBlock();
270 
271  trace.info() << "(" << nbok << "/" << nb << ") " << endl;
272  return nbok == nb;
273 }
274 
279 {
280 
281  typedef KhalimskySpaceND<2,int> KSpace;
283 
284  unsigned int nbok = 0;
285  unsigned int nb = 0;
286 
287  trace.beginBlock ( "Recognition" );
288 
289  for (unsigned int i = 0; i < 50; ++i)
290  {
291  //generate digital circle
292  double cx = (rand()%100 ) / 100.0;
293  double cy = (rand()%100 ) / 100.0;
294  double radius = (rand()%100 )+100;
295  c = ballGenerator<KSpace>( cx, cy, radius, ((i%2)==1) );
296  trace.info() << " #ball #" << i << " c(" << cx << "," << cy << ") r=" << radius << endl;
297 
298  //range
300  Range r = c.getIncidentPointsRange();
301 
302  //recognition
303  typedef Range::ConstIterator ConstIterator; //iterator
305  longestSegment(s,r.begin(),r.end());
306 
307  //checking if the circle is separating
308  bool flag = true;
309  typedef CircleFrom3Points<KSpace::Point> Circle;
311  FirstInCirclePred;
313  SecondInCirclePred;
314  for (ConstIterator it = s.begin(); ((it != s.end()) && flag) ; ++it)
315  {
316  FirstInCirclePred p1( s.getSeparatingCircle() );
317  SecondInCirclePred p2( s.getSeparatingCircle() );
318  flag = ( p1(it->first)&&p2(it->second) );
319  }
320 
321  //conclusion
322  nbok += flag ? 1 : 0;
323  nb++;
324  }
325 
326  trace.endBlock();
327 
328  trace.info() << "(" << nbok << "/" << nb << ") " << endl;
329  return nbok == nb;
330 }
331 
335 template <typename TCurve>
336 bool testSegmentation(const TCurve& curve)
337 {
338 
339  typedef typename TCurve::IncidentPointsRange Range; //range
340  Range r = curve.getIncidentPointsRange(); //range
341 
342  typedef typename Range::ConstIterator ConstIterator; //iterator
343  typedef StabbingCircleComputer<ConstIterator> SegmentComputer; //segment computer
344 
345  unsigned int nbok = 0;
346  unsigned int nb = 0;
347 
348  trace.beginBlock ( "Greedy segmentation" );
349  {
350  typedef GreedySegmentation<SegmentComputer> Segmentation;
351  Segmentation theSegmentation( r.begin(), r.end(), SegmentComputer() );
352 
353  Board2D board;
354  board << r;
355 
356  typename Segmentation::SegmentComputerIterator it = theSegmentation.begin();
357  typename Segmentation::SegmentComputerIterator itEnd = theSegmentation.end();
358  unsigned int n = 0;
359  unsigned int suml = 0;
360  for ( ; it != itEnd; ++it, ++n) {
361  board << SetMode(SegmentComputer().className(), "Sector")
362  << (*it);
363  for (ConstIterator i = it->begin(); i != it->end(); ++i)
364  suml += 1;
365  }
366 
367  board.saveSVG("StabbingCircleComputerGreedySegmentationTest.svg", Board2D::BoundingBox, 5000 );
368 
369  trace.info() << r.size() << ";" << n << ";" << suml << endl;
370  //comparison with the results given by another program
371  bool flag = ((r.size()==85)&&(n==6)&&(suml==90)&&((r.size()+n-1)==suml));
372  nbok += flag ? 1 : 0;
373  nb++;
374  }
375  trace.endBlock();
376 
377  trace.beginBlock ( "Saturated segmentation" );
378  {
379  typedef SaturatedSegmentation<SegmentComputer> Segmentation;
380  Segmentation theSegmentation( r.begin(), r.end(), SegmentComputer() );
381  theSegmentation.setMode("Last");
382 
383  Board2D board;
384  board << curve;
385 
386  typename Segmentation::SegmentComputerIterator it = theSegmentation.begin();
387  typename Segmentation::SegmentComputerIterator itEnd = theSegmentation.end();
388  unsigned int n = 0;
389  unsigned int suml = 0;
390  for ( ; it != itEnd; ++it, ++n) {
391  board << SetMode(SegmentComputer().className(), "Annulus")
392  << (*it);
393  for (ConstIterator i = it->begin(); i != it->end(); ++i)
394  suml += 1;
395  }
396 
397  board.saveSVG("StabbingCircleComputerSaturatedSegmentationTest.svg", Board2D::BoundingBox, 5000 );
398 
399  trace.info() << r.size() << ";" << n << ";" << suml << endl;
400  //comparison with the results given by another program
401  nbok += ((r.size()==85)&&(n==20)&&(suml==326)) ? 1 : 0;
402  nb++;
403  }
404  trace.endBlock();
405 
406  trace.info() << "(" << nbok << "/" << nb << ") " << endl;
407  return (nbok == nb);
408 }
410 // Standard services - public :
411 
412 int main( int argc, char** argv )
413 {
414  trace.beginBlock ( "Testing class StabbingCircleComputer" );
415  trace.info() << "Args:";
416  for ( int i = 0; i < argc; ++i )
417  trace.info() << " " << argv[ i ];
418  trace.info() << endl;
419 
420  bool res;
421 
422  {//concept checking
424  }
425 
426  {//basic operations
427  typedef KhalimskySpaceND<2,int> KSpace;
428 
429  GridCurve<KSpace> c, rc;
430  c = ballGenerator<KSpace>(0,0,6,false);
431  std::vector<PointVector<2,int> > rv;
432  rc = ballGenerator<KSpace>(0,0,6,true);
433 
436  && drawingTestStabbingCircleComputer(rc, "CW");
437  }
438 
439  {//recognition
440  res = res && testRecognition();
441  }
442 
443  {//segmentations
444  std::string filename = testPath + "samples/sinus2D4.dat";
445  ifstream instream; // input stream
446  instream.open (filename.c_str(), ifstream::in);
447 
448  typedef KhalimskySpaceND<2,int> KSpace;
449  GridCurve<KSpace> c; //grid curve
450  c.initFromVectorStream(instream);
451 
452  res = res && testSegmentation(c);
453  }
454 
455  trace.emphase() << ( res ? "Passed." : "Error." ) << endl;
456  trace.endBlock();
457  return res ? 0 : 1;
458 }
459 // //
void beginBlock(const std::string &keyword="")
void testStabbingCircleComputerConceptChecking()
HyperRectDomain< Space > Domain
const Domain domain(Point(1, 2), Point(6, 5))
MyDigitalSurface::ConstIterator ConstIterator
const Point & getLowerBound() const
Trace trace
Definition: Common.h:137
Aim: A utility class for constructing surfaces (i.e. set of (n-1)-cells).
Definition: Surfaces.h:78
const Point & getUpperBound() const
Circle getSeparatingCircle() const
int main(int argc, char **argv)
STL namespace.
double endBlock()
void attach(const EuclideanShape &shape)
Aim: Represents a circle uniquely defined by three 2D points and that is able to return for any given...
void saveSVG(const char *filename, PageSize size=Board::BoundingBox, double margin=10.0) const
Definition: Board.cpp:1012
void setMode(const std::string &aMode)
Aim: Computes the greedy segmentation of a range given by a pair of ConstIterators. The last element of a given segment is the first one one of the next segment.
Aim: On-line recognition of a digital circular arcs (DCA) defined as a sequence of connected grid edg...
void longestSegment(SC &s, const typename SC::ConstIterator &i, const typename SC::ConstIterator &end, IteratorType)
Aim: Predicate returning &#39;true&#39; iff a given point is in the &#39;interior&#39; of a given shape...
ConstIterator end() const
Aim: The concept CDrawableWithBoard2D specifies what are the classes that admit an export with Board2...
Aim: Model of the concept StarShaped represents any circle in the plane.
Definition: Ball2D.h:60
bool initFromVector(const std::vector< Point > &aVectorOfPoints)
void init(const RealPoint &xLow, const RealPoint &xUp, typename RealVector::Component gridStep)
bool drawingTestStabbingCircleComputer(const TCurve &curve, const string &suffix)
std::ostream & emphase()
Aim: A class for computing the Gauss digitization of some Euclidean shape, i.e. its intersection with...
bool testStabbingCircleComputer(const TCurve &curve)
std::reverse_iterator< ConstIterator > ConstReverseIterator
ConstIterator begin() const
void init(const ConstIterator &anIt)
DGtal is the top-level namespace which contains all DGtal functions and types.
MyPointD Point
Definition: testClone2.cpp:383
Aim: model of CConstBidirectionalRange that adapts any range of elements bounded by two iterators [it...
bool testSegmentation(const TCurve &curve)
bool initFromVectorStream(std::istream &in)
std::ostream & info()
Modifier class in a Board2D stream. Useful to choose your own mode for a given class. Realizes the concept CDrawableWithBoard2D.
Definition: Board2D.h:247
Aim: Computes the saturated segmentation, that is the whole set of maximal segments within a range gi...
GridCurve< TKSpace > ballGenerator(double aCx, double aCy, double aR, bool aFlagIsCW)
Aim: Defines the concept describing a bidirectional segment computer, ie. a model of concepts::CSegme...
KSpace K
IncidentPointsRange getIncidentPointsRange() const
Definition: GridCurve.h:486
Aim: describes, in a cellular space of dimension n, a closed or open sequence of signed d-cells (or d...
Definition: GridCurve.h:172
bool testRecognition()
Domain getDomain() const
Aim: This class is a model of CCellularGridSpaceND. It represents the cubical grid as a cell complex...
Aim: This class specializes a &#39;Board&#39; class so as to display DGtal objects more naturally (with <<)...
Definition: Board2D.h:70