50#include "DGtal/base/Common.h"
51#include "DGtal/base/Exceptions.h"
52#include "DGtal/kernel/SpaceND.h"
53#include "DGtal/kernel/domains/HyperRectDomain.h"
54#include "DGtal/kernel/BasicPointPredicates.h"
55#include "DGtal/math/linalg/EigenDecomposition.h"
56#include "DGtal/topology/KhalimskySpaceND.h"
57#include "DGtal/geometry/curves/GridCurve.h"
58#include "DGtal/geometry/curves/Naive3DDSSComputer.h"
59#include "DGtal/geometry/curves/StandardDSS6Computer.h"
60#include "DGtal/geometry/curves/SaturatedSegmentation.h"
61#include "DGtal/geometry/volumes/distance/ExactPredicateLpSeparableMetric.h"
62#include "DGtal/geometry/volumes/estimation/VoronoiCovarianceMeasure.h"
63#include "DGtal/geometry/curves/estimation/LambdaMST3D.h"
64#include "DGtal/geometry/curves/estimation/FunctorsLambdaMST.h"
65#include "DGtal/io/viewers/PolyscopeViewer.h"
66#include "DGtal/io/readers/PointListReader.h"
67#include "DGtal/io/colormaps/HueShadeColorMap.h"
140const Color AXIS_COLOR( 0, 0, 0, 255 );
141const Color XY_COLOR( 0, 0, 255, 50 );
142const Color XZ_COLOR( 0, 255, 0, 50 );
143const Color YZ_COLOR( 255, 0, 0, 50 );
144const Color CURVE3D_COLOR( 100, 100, 140, 128 );
145const Color CURVE2D_COLOR( 200, 200, 200, 100 );
146const double MS3D_LINESIZE = 0.05;
151template <
typename Po
int,
typename RealPo
int,
typename space,
typename kspace >
152void displayAxes( PolyscopeViewer<space, kspace> & viewer,
153 const Point & lowerBound,
const Point & upperBound,
154 const std::string & mode )
156 RealPoint p0( (
double)lowerBound[ 0 ]-0.5,
157 (
double)lowerBound[ 1 ]-0.5,
158 (
double)lowerBound[ 2 ]-0.5 );
159 RealPoint p1( (
double)upperBound[ 0 ]-0.5,
160 (
double)upperBound[ 1 ]-0.5,
161 (
double)upperBound[ 2 ]-0.5 );
162 if ( ( mode ==
"WIRED" ) || ( mode ==
"COLORED" ) )
164 viewer.drawColor(AXIS_COLOR);
165 viewer.drawLine( DGtal::Z3i::RealPoint(p0[ 0 ], p0[ 1 ], p0[ 2 ]),
166 DGtal::Z3i::RealPoint(p1[ 0 ], p0[ 1 ], p0[ 2 ]) );
167 viewer.drawLine( DGtal::Z3i::RealPoint(p0[ 0 ], p0[ 1 ], p0[ 2 ]),
168 DGtal::Z3i::RealPoint(p0[ 0 ], p1[ 1 ], p0[ 2 ]) );
169 viewer.drawLine( DGtal::Z3i::RealPoint(p0[ 0 ], p0[ 1 ], p0[ 2 ]),
170 DGtal::Z3i::RealPoint(p0[ 0 ], p0[ 1 ], p1[ 2 ]) );
171 viewer.drawLine( DGtal::Z3i::RealPoint(p1[ 0 ], p0[ 1 ], p0[ 2 ]),
172 DGtal::Z3i::RealPoint(p1[ 0 ], p1[ 1 ], p0[ 2 ]) );
173 viewer.drawLine( DGtal::Z3i::RealPoint(p1[ 0 ], p0[ 1 ], p0[ 2 ]),
174 DGtal::Z3i::RealPoint(p1[ 0 ], p0[ 1 ], p1[ 2 ]) );
175 viewer.drawLine( DGtal::Z3i::RealPoint(p0[ 0 ], p1[ 1 ], p0[ 2 ]),
176 DGtal::Z3i::RealPoint(p1[ 0 ], p1[ 1 ], p0[ 2 ]) );
177 viewer.drawLine( DGtal::Z3i::RealPoint(p0[ 0 ], p1[ 1 ], p0[ 2 ]),
178 DGtal::Z3i::RealPoint(p0[ 0 ], p1[ 1 ], p1[ 2 ]) );
179 viewer.drawLine( DGtal::Z3i::RealPoint(p0[ 0 ], p0[ 1 ], p1[ 2 ]),
180 DGtal::Z3i::RealPoint(p1[ 0 ], p0[ 1 ], p1[ 2 ]) );
181 viewer.drawLine( DGtal::Z3i::RealPoint(p0[ 0 ], p0[ 1 ], p1[ 2 ]),
182 DGtal::Z3i::RealPoint(p0[ 0 ], p1[ 1 ], p1[ 2 ]) );
183 viewer.drawLine( DGtal::Z3i::RealPoint(p1[ 0 ], p1[ 1 ], p0[ 2 ]),
184 DGtal::Z3i::RealPoint(p1[ 0 ], p1[ 1 ], p1[ 2 ]) );
185 viewer.drawLine( DGtal::Z3i::RealPoint(p1[ 0 ], p0[ 1 ], p1[ 2 ]),
186 DGtal::Z3i::RealPoint(p1[ 0 ], p1[ 1 ], p1[ 2 ]) );
187 viewer.drawLine( DGtal::Z3i::RealPoint(p0[ 0 ], p1[ 1 ], p1[ 2 ]),
188 DGtal::Z3i::RealPoint(p1[ 0 ], p1[ 1 ], p1[ 2 ]) );
190 if ( mode ==
"COLORED" )
192 viewer.drawColor(XY_COLOR);
193 viewer.drawQuad(DGtal::Z3i::RealPoint(p1[ 0 ], p1[ 1 ], p1[ 2 ]),
194 DGtal::Z3i::RealPoint(p1[ 0 ], p0[ 1 ], p1[ 2 ]),
195 DGtal::Z3i::RealPoint(p0[ 0 ], p0[ 1 ], p1[ 2 ]),
196 DGtal::Z3i::RealPoint(p0[ 0 ], p1[ 1 ], p1[ 2 ]) );
197 viewer.drawColor(XZ_COLOR);
198 viewer.drawQuad(DGtal::Z3i::RealPoint(p1[ 0 ], p1[ 1 ], p1[ 2 ]),
199 DGtal::Z3i::RealPoint(p0[ 0 ], p1[ 1 ], p1[ 2 ]),
200 DGtal::Z3i::RealPoint(p0[ 0 ], p1[ 1 ], p0[ 2 ]),
201 DGtal::Z3i::RealPoint(p1[ 0 ], p1[ 1 ], p0[ 2 ]));
202 viewer.drawColor(YZ_COLOR);
203 viewer.drawQuad(DGtal::Z3i::RealPoint(p1[ 0 ], p1[ 1 ], p1[ 2 ]),
204 DGtal::Z3i::RealPoint(p1[ 0 ], p0[ 1 ], p1[ 2 ]),
205 DGtal::Z3i::RealPoint(p1[ 0 ], p0[ 1 ], p0[ 2 ]),
206 DGtal::Z3i::RealPoint(p1[ 0 ], p1[ 1 ], p0[ 2 ]));
210template <
typename KSpace,
typename Naive3DDSSComputer,
typename space,
typename kspace >
211void displayDSS3d( PolyscopeViewer<space, kspace> & viewer,
212 const KSpace & ks,
const Naive3DDSSComputer & dss3d,
213 const DGtal::Color & color3d )
215 viewer << color3d << dss3d;
218template <
typename Po
int1,
typename Po
int2>
219void assign( Point1 & p1,
const Point2 & p2 )
226template <
typename KSpace,
typename Naive3DDSSComputer,
typename space,
typename kspace >
227void displayDSS3dTangent( PolyscopeViewer<space, kspace> & viewer,
228 const KSpace & ks,
const Naive3DDSSComputer & dss3d,
229 const DGtal::Color & color3d )
231 typedef typename Naive3DDSSComputer::Point3d Point;
232 typedef typename Naive3DDSSComputer::Integer Integer;
233 typedef typename Naive3DDSSComputer::PointR3d PointR3d;
235 PointR3d interceptR, thicknessR;
236 Z3i::RealPoint P1, P2, direction, intercept, thickness;
237 dss3d.getParameters( directionZ3, interceptR, thicknessR );
239 intercept[0] = (double) NumberTraits<Integer>::castToDouble ( interceptR[0].first ) / (double) NumberTraits<Integer>::castToDouble ( interceptR[0].second );
240 intercept[1] = (double) NumberTraits<Integer>::castToDouble ( interceptR[1].first ) / (double) NumberTraits<Integer>::castToDouble ( interceptR[1].second );
241 intercept[2] = (double) NumberTraits<Integer>::castToDouble ( interceptR[2].first ) / (double) NumberTraits<Integer>::castToDouble ( interceptR[2].second );
242 thickness[0] = (double) NumberTraits<Integer>::castToDouble ( thicknessR[0].first ) / (double) NumberTraits<Integer>::castToDouble ( thicknessR[0].second );
243 thickness[1] = (double) NumberTraits<Integer>::castToDouble ( thicknessR[1].first ) / (double) NumberTraits<Integer>::castToDouble ( thicknessR[1].second );
244 thickness[2] = (double) NumberTraits<Integer>::castToDouble ( thicknessR[2].first ) / (double) NumberTraits<Integer>::castToDouble ( thicknessR[2].second );
246 assign( direction, directionZ3 );
247 direction /= direction.norm();
248 assign( P1, *dss3d.begin() );
249 assign( P2, *(dss3d.end()-1) );
250 double t1 = (P1 - intercept).dot( direction );
251 double t2 = (P2 - intercept).dot( direction );
253 Z3i::RealPoint Q1 = intercept + t1 * direction;
254 Z3i::RealPoint Q2 = intercept + t2 * direction;
255 viewer.drawColor(color3d);
256 viewer.drawLine( Z3i::RealPoint(Q1[ 0 ]-0.5, Q1[ 1 ]-0.5, Q1[ 2 ]-0.5),
257 Z3i::RealPoint(Q2[ 0 ]-0.5, Q2[ 1 ]-0.5, Q2[ 2 ]-0.5));
260template <
typename KSpace,
typename StandardDSS6Computer,
typename space,
typename kspace >
261void displayProj2d6( PolyscopeViewer<space, kspace> & viewer,
262 const KSpace & ks,
const StandardDSS6Computer & dss3d,
263 const DGtal::Color & color2d )
265 typedef typename StandardDSS6Computer::ArithmeticalDSSComputer2d ArithmeticalDSSComputer2d;
266 typedef typename ArithmeticalDSSComputer2d::ConstIterator ConstIterator2d;
267 typedef typename ArithmeticalDSSComputer2d::Point Point2d;
268 typedef typename KSpace::Cell Cell;
269 typedef typename KSpace::Point Point3d;
270 Point3d b = ks.lowerBound();
271 for ( DGtal::Dimension i = 0; i < 3; ++i )
273 const ArithmeticalDSSComputer2d & dss2d = dss3d.arithmeticalDSS2d( i );
274 for ( ConstIterator2d itP = dss2d.begin(), itPEnd = dss2d.end(); itP != itPEnd; ++itP )
280 case 0: q = Point3d( 2*b[ i ] , 2*p[ 0 ]+1, 2*p[ 1 ]+1 );
break;
281 case 1: q = Point3d( 2*p[ 0 ]+1, 2*b[ i ] , 2*p[ 1 ]+1 );
break;
282 case 2: q = Point3d( 2*p[ 0 ]+1, 2*p[ 1 ]+1, 2*b[ i ] );
break;
284 Cell c = ks.uCell( q );
285 viewer << color2d << c;
290template <
typename KSpace,
typename StandardDSS6Computer,
typename space,
typename kspace >
291void displayDSS2d6( PolyscopeViewer<space, kspace> & viewer,
292 const KSpace & ks,
const StandardDSS6Computer & dss3d,
293 const DGtal::Color & color2d )
295 typedef typename StandardDSS6Computer::ConstIterator ConstIterator3d;
296 typedef typename StandardDSS6Computer::ArithmeticalDSSComputer2d ArithmeticalDSSComputer2d;
297 typedef typename ArithmeticalDSSComputer2d::ConstIterator ConstIterator2d;
298 typedef typename ArithmeticalDSSComputer2d::Point Point2d;
299 typedef typename KSpace::Cell Cell;
300 typedef typename KSpace::Point Point3d;
301 typedef DGtal::PointVector<2,double> PointD2d;
302 typedef typename DGtal::PointVector<3,double> PointD3D;
303 Point3d b = ks.lowerBound();
304 for ( DGtal::Dimension i = 0; i < 3; ++i )
306 const typename ArithmeticalDSSComputer2d::Primitive & dss2d
307 = dss3d.arithmeticalDSS2d( i ).primitive();
309 std::vector<PointD2d> pts2d;
310 pts2d.push_back( dss2d.project(dss2d.back(), dss2d.Uf()) );
311 pts2d.push_back( dss2d.project(dss2d.back(), dss2d.Lf()) );
312 pts2d.push_back( dss2d.project(dss2d.front(), dss2d.Lf()) );
313 pts2d.push_back( dss2d.project(dss2d.front(), dss2d.Uf()) );
314 std::vector<PointD3D> bb;
316 for (
unsigned int j = 0; j < pts2d.size(); ++j )
320 case 0: p3[0] = (double) b[ i ]-0.5; p3[1] = pts2d[ j ][ 0 ]; p3[2] = pts2d[ j ][ 1 ];
break;
321 case 1: p3[0] = pts2d[ j ][ 0 ]; p3[1] = (double) b[ i ]-0.5; p3[2] = pts2d[ j ][ 1 ];
break;
322 case 2: p3[0] = pts2d[ j ][ 0 ]; p3[1] = pts2d[ j ][ 1 ]; p3[2] = (double) b[ i ]-0.5;
break;
326 for (
unsigned int j = 0; j < pts2d.size(); ++j ){
327 viewer.drawColor(color2d);
328 viewer.drawLine( DGtal::Z3i::RealPoint(bb[ j ][0], bb[ j ][1], bb[ j ][2]),
329 DGtal::Z3i::RealPoint(bb[ (j+1)%4 ][0], bb[ (j+1)%4 ][1], bb[ (j+1)%4 ][2]));
336template <
typename KSpace,
typename Naive3DDSSComputer,
typename space,
typename kspace >
337void displayProj2d26( PolyscopeViewer<space, kspace> & viewer,
338 const KSpace & ks,
const Naive3DDSSComputer & dss3d,
339 const DGtal::Color & color2d )
341 typedef typename Naive3DDSSComputer::ArithmeticalDSSComputer2d ArithmeticalDSSComputer2d;
342 typedef typename ArithmeticalDSSComputer2d::ConstIterator ConstIterator2d;
343 typedef typename ArithmeticalDSSComputer2d::Point Point2d;
344 typedef typename KSpace::Cell Cell;
345 typedef typename KSpace::Point Point3d;
346 Point3d b = ks.lowerBound();
348 const ArithmeticalDSSComputer2d & dssXY = dss3d.arithmeticalDSS2dXY();
349 const ArithmeticalDSSComputer2d & dssXZ = dss3d.arithmeticalDSS2dXZ();
350 const ArithmeticalDSSComputer2d & dssYZ = dss3d.arithmeticalDSS2dYZ();
352 bool validXY = dss3d.validArithmeticalDSS2d ( 2 );
353 bool validXZ = dss3d.validArithmeticalDSS2d ( 1 );
354 bool validYZ = dss3d.validArithmeticalDSS2d ( 0 );
356 if ( validXY && validXZ )
358 for ( ConstIterator2d itXY = dssXY.begin(), itXZ = dssXZ.begin(), itPEnd = dssXY.end(); itXY != itPEnd; ++itXY, ++itXZ )
360 Point2d p1 = *itXY, p2 = *itXZ;
362 q1 = Point3d ( 2*b[ 0 ], 2*p1[ 1 ]+1, 2*p2[ 1 ]+1 );
363 q2 = Point3d ( 2*p2[ 0 ]+1, 2*b[ 1 ], 2*p2[ 1 ]+1 );
364 q3 = Point3d ( 2*p1[ 0 ]+1, 2*p1[ 1 ]+1, 2*b[ 2 ] );
365 Cell c1 = ks.uCell( q1 ); Cell c2 = ks.uCell( q2 ); Cell c3 = ks.uCell( q3 );
366 viewer << color2d << c1;
367 viewer << color2d << c2;
368 viewer << color2d << c3;
373 if ( validYZ && validXY )
375 for ( ConstIterator2d itYZ = dssYZ.begin(), itXY = dssXY.begin(), itPEnd = dssXY.end(); itXY != itPEnd; ++itXY, ++itYZ )
377 Point2d p1 = *itYZ, p2 = *itXY;
379 q1 = Point3d ( 2*b[ 0 ], 2*p1[ 0 ]+1, 2*p1[ 1 ]+1 );
380 q2 = Point3d ( 2*p2[ 0 ]+1, 2*b[ 1 ], 2*p1[ 1 ]+1 );
381 q3 = Point3d ( 2*p2[ 0 ]+1, 2*p2[ 1 ]+1, 2*b[ 2 ] );
382 Cell c1 = ks.uCell( q1 ); Cell c2 = ks.uCell( q2 ); Cell c3 = ks.uCell( q3 );
383 viewer << color2d << c1;
384 viewer << color2d << c2;
385 viewer << color2d << c3;
390 for ( ConstIterator2d itYZ = dssYZ.begin(), itXZ = dssXZ.begin(), itPEnd = dssXZ.end(); itXZ != itPEnd; ++itXZ, ++itYZ )
392 Point2d p1 = *itYZ, p2 = *itXZ;
394 q1 = Point3d ( 2*b[ 0 ], 2*p1[ 0 ]+1, 2*p1[ 1 ]+1 );
395 q2 = Point3d ( 2*p2[ 0 ]+1, 2*b[ 1 ], 2*p2[ 1 ]+1 );
396 q3 = Point3d ( 2*p2[ 0 ]+1, 2*p1[ 0 ]+1, 2*b[ 2 ] );
397 Cell c1 = ks.uCell( q1 ); Cell c2 = ks.uCell( q2 );Cell c3 = ks.uCell( q3 );
398 viewer << color2d << c1;
399 viewer << color2d << c2;
400 viewer << color2d << c3;
407template <
typename KSpace,
typename Naive3DDSSComputer,
typename space,
typename kspace >
408void displayDSS2d26( PolyscopeViewer<space, kspace> & viewer,
409 const KSpace & ks,
const Naive3DDSSComputer & dss3d,
410 const DGtal::Color & color2d )
412 typedef typename Naive3DDSSComputer::ConstIterator ConstIterator3d;
413 typedef typename Naive3DDSSComputer::ArithmeticalDSSComputer2d ArithmeticalDSSComputer2d;
414 typedef typename ArithmeticalDSSComputer2d::ConstIterator ConstIterator2d;
415 typedef typename ArithmeticalDSSComputer2d::Point Point2d;
416 typedef typename KSpace::Cell Cell;
417 typedef typename KSpace::Point Point3d;
418 typedef DGtal::PointVector<2,double> PointD2d;
419 typedef DGtal::PointVector<2,double> PointD3D;
420 Point3d b = ks.lowerBound();
421 for ( DGtal::Dimension i = 0; i < 3; ++i )
423 if ( !dss3d.validArithmeticalDSS2d ( i ) )
426 const typename ArithmeticalDSSComputer2d::Primitive & dss2d
427 = dss3d.arithmeticalDSS2d( i ).primitive();
429 std::vector<PointD2d> pts2d;
430 pts2d.push_back( dss2d.project(dss2d.back(), dss2d.Uf()) );
431 pts2d.push_back( dss2d.project(dss2d.back(), dss2d.Lf()) );
432 pts2d.push_back( dss2d.project(dss2d.front(), dss2d.Lf()) );
433 pts2d.push_back( dss2d.project(dss2d.front(), dss2d.Uf()) );
434 std::vector<PointD3D> bb;
436 for (
unsigned int j = 0; j < pts2d.size(); ++j )
440 case 0: p3[0] = (double) b[ i ]-0.5; p3[1] = pts2d[ j ][ 0 ]; p3[2] = pts2d[ j ][ 1 ];
break;
441 case 1: p3[0] = pts2d[ j ][ 0 ]; p3[1] = (double) b[ i ]-0.5; p3[2] = pts2d[ j ][ 1 ];
break;
442 case 2: p3[0] = pts2d[ j ][ 0 ]; p3[1] = pts2d[ j ][ 1 ]; p3[2] = (double) b[ i ]-0.5;
break;
446 for (
unsigned int j = 0; j < pts2d.size(); ++j ){
447 viewer.drawColor(color2d);
448 viewer.drawLine( DGtal::Z3i::RealPoint(bb[ j ][0], bb[ j ][1], bb[ j ][2]),
449 DGtal::Z3i::RealPoint(bb[ (j+1)%4 ][0], bb[ (j+1)%4 ][1], bb[ (j+1)%4 ][2])
458template <
typename KSpace,
typename Po
intIterator,
typename space,
typename kspace >
459bool displayCover6( PolyscopeViewer<space, kspace> & viewer,
460 const KSpace & ks, PointIterator b, PointIterator e,
461 bool dss3d,
bool proj2d,
bool dss2d,
bool tangent,
464 typedef typename PointIterator::value_type Point;
465 typedef StandardDSS6Computer<PointIterator,int,4> SegmentComputer;
466 typedef SaturatedSegmentation<SegmentComputer> Decomposition;
467 typedef typename Decomposition::SegmentComputerIterator SegmentComputerIterator;
468 typedef typename SegmentComputer::ArithmeticalDSSComputer2d ArithmeticalDSSComputer2d;
469 SegmentComputer algo;
470 Decomposition theDecomposition(b, e, algo);
472 HueShadeColorMap<int> cmap_hue( 0, nbColors, 1 );
475 for ( SegmentComputerIterator i = theDecomposition.begin();
476 i != theDecomposition.end(); ++i)
478 SegmentComputer ms3d(*i);
479 const ArithmeticalDSSComputer2d & dssXY = ms3d.arithmeticalDSS2dXY();
480 const ArithmeticalDSSComputer2d & dssXZ = ms3d.arithmeticalDSS2dXZ();
481 const ArithmeticalDSSComputer2d & dssYZ = ms3d.arithmeticalDSS2dYZ();
482 Point f = *ms3d.begin();
483 Point l = *(ms3d.end() - 1);
484 trace.info() <<
"- " << c
486 <<
" [" << f[ 0 ] <<
"," << f[ 1 ] <<
","<< f[ 2 ] <<
"]"
487 <<
"->[" << l[ 0 ] <<
"," << l[ 1 ] <<
","<< l[ 2 ] <<
"]"
489 << dssXY.a() <<
"," << dssXY.b() <<
"," << dssXY.mu()
491 << dssXZ.a() <<
"," << dssXZ.b() <<
"," << dssXZ.mu()
493 << dssYZ.a() <<
"," << dssYZ.b() <<
"," << dssYZ.mu()
495 Color color = cmap_hue( c );
496 if ( tangent ) displayDSS3dTangent( viewer, ks, ms3d, color );
497 if ( dss3d ) displayDSS3d( viewer, ks, ms3d, color );
498 if ( dss2d ) displayDSS2d6( viewer, ks, ms3d, color );
499 if ( proj2d ) displayProj2d6( viewer, ks, ms3d, CURVE2D_COLOR );
509template <
typename KSpace,
typename Po
intIterator,
typename space,
typename kspace >
510bool displayCover26( PolyscopeViewer<space, kspace> & viewer,
511 const KSpace & ks, PointIterator b, PointIterator e,
512 bool dss3d,
bool proj2d,
bool dss2d,
bool tangent,
515 typedef typename PointIterator::value_type Point;
516 typedef Naive3DDSSComputer<PointIterator,int, 8 > SegmentComputer;
517 typedef SaturatedSegmentation<SegmentComputer> Decomposition;
518 typedef typename Decomposition::SegmentComputerIterator SegmentComputerIterator;
519 typedef typename SegmentComputer::ArithmeticalDSSComputer2d ArithmeticalDSSComputer2d;
520 SegmentComputer algo;
521 Decomposition theDecomposition(b, e, algo);
523 HueShadeColorMap<int> cmap_hue( 0, nbColors, 1 );
526 for ( SegmentComputerIterator i = theDecomposition.begin();
527 i != theDecomposition.end(); ++i)
529 SegmentComputer ms3d(*i);
530 const ArithmeticalDSSComputer2d & dssXY = ms3d.arithmeticalDSS2dXY();
531 const ArithmeticalDSSComputer2d & dssXZ = ms3d.arithmeticalDSS2dXZ();
532 const ArithmeticalDSSComputer2d & dssYZ = ms3d.arithmeticalDSS2dYZ();
533 Point f = *ms3d.begin();
534 Point l = *(ms3d.end() - 1);
535 trace.info() <<
"- " << c
537 <<
" [" << f[ 0 ] <<
"," << f[ 1 ] <<
","<< f[ 2 ] <<
"]"
538 <<
"->[" << l[ 0 ] <<
"," << l[ 1 ] <<
","<< l[ 2 ] <<
"]"
540 << dssXY.a() <<
"," << dssXY.b() <<
"," << dssXY.mu()
542 << dssXZ.a() <<
"," << dssXZ.b() <<
"," << dssXZ.mu()
544 << dssYZ.a() <<
"," << dssYZ.b() <<
"," << dssYZ.mu()
548 Color color = cmap_hue( c );
549 if ( tangent ) displayDSS3dTangent( viewer, ks, ms3d, color );
550 if ( dss3d ) displayDSS3d( viewer, ks, ms3d, color );
551 if ( dss2d ) displayDSS2d26( viewer, ks, ms3d, color );
552 if ( proj2d ) displayProj2d26( viewer, ks, ms3d, CURVE2D_COLOR );
558template <
typename Po
intIterator,
typename Space,
typename TangentSequence >
559void ComputeVCM (
const double & R,
const double & r,
560 const PointIterator & begin,
const PointIterator & end, TangentSequence & tangents,
const std::string & output )
562 using namespace DGtal;
563 typedef ExactPredicateLpSeparableMetric < Space, 2 > Metric;
564 typedef VoronoiCovarianceMeasure < Space, Metric > VCM;
565 typedef HyperRectDomain < Space > Domain;
566 typedef functors::HatPointFunction < typename Space::Point, double > KernelFunction;
567 typedef EigenDecomposition < 3, double > LinearAlgebraTool;
568 typedef LinearAlgebraTool::Matrix Matrix;
570 fstream outputStream;
571 outputStream.open ( ( output +
".vcm" ).c_str(), std::ios::out );
572 outputStream <<
"# VCM estimation R=" << R <<
" r=" << r <<
" chi=hat" << endl;
575 VCM vcm ( R, ceil( r ), l2,
true );
576 vcm.init( begin, end );
577 KernelFunction chi( 1.0, r );
579 typename Space::RealVector eval;
580 for ( PointIterator it = begin; it != end; ++it )
583 vcm_r = vcm.measure( chi, *it );
584 LinearAlgebraTool::getEigenDecomposition ( vcm_r, evec, eval );
585 typename Space::RealVector tangent = evec.column( 0 );
586 tangents.push_back ( tangent );
587 outputStream << (*it)[0] <<
" " << (*it)[1] <<
" " << (*it)[2] <<
" "
588 << tangent[0] <<
" " << tangent[1] <<
" " << tangent[2] << endl;
590 outputStream.close();
593template <
typename Po
intIterator,
typename Space,
typename TangentSequence >
594void ComputeLMST6 (
const PointIterator & begin,
const PointIterator & end, TangentSequence & tangents,
const std::string & output )
596 typedef typename PointIterator::value_type Point;
597 typedef StandardDSS6Computer<PointIterator,int, 4 > SegmentComputer;
598 typedef SaturatedSegmentation<SegmentComputer> Decomposition;
599 typedef typename Decomposition::SegmentComputerIterator SegmentComputerIterator;
600 typedef typename SegmentComputer::ArithmeticalDSSComputer2d ArithmeticalDSSComputer2d;
601 SegmentComputer algo;
602 Decomposition theDecomposition ( begin, end, algo );
604 fstream outputStream;
605 outputStream.open ( ( output +
".lmst" ).c_str(), std::ios::out );
606 outputStream <<
"X Y Z X Y Z" << endl;
608 LambdaMST3D < Decomposition > lmst64;
609 lmst64.attach ( theDecomposition );
610 lmst64.init ( begin, end );
611 lmst64.eval ( begin, end, std::back_inserter ( tangents ) );
612 typename TangentSequence::iterator itt = tangents.begin();
613 for ( PointIterator it = begin; it != end; ++it, ++itt )
615 typename Space::RealVector & tangent = (*itt);
616 if ( tangent.norm() != 0. )
617 tangent = tangent.getNormalized();
618 outputStream << (*it)[0] <<
" " << (*it)[1] <<
" " << (*it)[2] <<
" "
619 << tangent[0] <<
" " << tangent[1] <<
" " << tangent[2] << endl;
623template <
typename Po
intIterator,
typename Space,
typename TangentSequence >
624void ComputeLMST26 (
const PointIterator & begin,
const PointIterator & end, TangentSequence & tangents,
const std::string & output )
626 typedef typename PointIterator::value_type Point;
627 typedef Naive3DDSSComputer<PointIterator,int, 8 > SegmentComputer;
628 typedef SaturatedSegmentation<SegmentComputer> Decomposition;
629 typedef typename Decomposition::SegmentComputerIterator SegmentComputerIterator;
630 typedef typename SegmentComputer::ArithmeticalDSSComputer2d ArithmeticalDSSComputer2d;
631 SegmentComputer algo;
632 Decomposition theDecomposition ( begin, end, algo );
634 fstream outputStream;
635 outputStream.open ( ( output +
".lmst" ).c_str(), std::ios::out );
636 outputStream <<
"X Y Z X Y Z" << endl;
638 LambdaMST3D < Decomposition > lmst64;
639 lmst64.attach ( theDecomposition );
640 lmst64.init ( begin, end );
641 lmst64.eval ( begin, end, std::back_inserter ( tangents ) );
642 typename TangentSequence::iterator itt = tangents.begin();
643 for ( PointIterator it = begin; it != end; ++it, ++itt )
645 typename Space::RealVector & tangent = (*itt);
646 if ( tangent.norm() != 0. )
647 tangent = tangent.getNormalized();
648 outputStream << (*it)[0] <<
" " << (*it)[1] <<
" " << (*it)[2] <<
" "
649 << tangent[0] <<
" " << tangent[1] <<
" " << tangent[2] << endl;
653template <
typename Po
intIterator,
typename Space,
int CONNECT = 8 >
654void find_main_axes ( PointIterator begin, PointIterator end, multimap < typename Space::Point, string > & axes )
656 typedef Naive3DDSSComputer < PointIterator, int, CONNECT > SegmentComputer;
657 typedef SaturatedSegmentation < SegmentComputer > Segmentation;
659 Segmentation segmenter ( begin, end, SegmentComputer ( ) );
661 for (
auto it = begin; it != end; ++it )
663 unsigned int cX = 0, cY = 0, cZ = 0;
664 for (
typename Segmentation::SegmentComputerIterator idss = segmenter.begin ( ); idss != segmenter.end ( ); ++idss )
666 if ( idss->isInDSS ( *it ) )
668 const typename SegmentComputer::ArithmeticalDSSComputer2d & dssXY = (*idss).arithmeticalDSS2dXY();
669 const typename SegmentComputer::ArithmeticalDSSComputer2d & dssXZ = (*idss).arithmeticalDSS2dXZ();
670 const typename SegmentComputer::ArithmeticalDSSComputer2d & dssYZ = (*idss).arithmeticalDSS2dYZ();
671 unsigned int lenXY = distance ( dssXY.begin(), dssXY.end() );
672 unsigned int lenXZ = distance ( dssXZ.begin(), dssXZ.end() );
673 unsigned int lenYZ = distance ( dssYZ.begin(), dssYZ.end() );
675 if ( lenXY >= lenYZ && lenXZ >= lenYZ )
677 else if ( lenXY >= lenXZ && lenYZ >= lenXZ )
684 axes.insert ( pair <typename Space::Point, string > ( *it,
string (
"X" ) ) );
686 axes.insert ( pair <typename Space::Point, string > ( *it,
string (
"Y" ) ) );
688 axes.insert ( pair <typename Space::Point, string > ( *it,
string (
"Z" ) ) );
693template <
typename Po
intIterator,
typename Space >
694void print_main_axes ( PointIterator begin, PointIterator end, multimap < typename Space::Point, string > & axes )
696 for ( PointIterator itt = begin; itt != end; ++itt )
698 typename std::multimap<typename Space::Point, string>::const_iterator it = axes.lower_bound(*itt);
699 typename std::multimap<typename Space::Point, string>::const_iterator it2 = axes.upper_bound(*itt);
700 cout <<
"(" << it->first[0] <<
", " << it->first[1] <<
", " << it->first[2] <<
"); MAIN_AXES = (";
701 for (; it != it2; it++ )
703 if ( distance( it, it2 ) > 1 )
704 cout << it->second <<
", ";
706 cout << it->second <<
")";
720int main(
int argc,
char **argv)
723 using namespace DGtal;
724 typedef SpaceND<3,int> Z3;
725 typedef KhalimskySpaceND<3,int> K3;
726 typedef Z3::Point Point;
727 typedef Z3::RealPoint RealPoint;
728 typedef Z3::RealVector RealVector;
729 typedef HyperRectDomain<Z3> Domain;
730 typedef typename vector<Point>::const_iterator PointIterator;
734 std::string inputFileName;
735 std::string viewFlag {
"OFF"};
736 std::string viewBox {
"WIRED"};
737 std::string connectivity {
"6"};
738 std::string method {
"VCM"};
739 std::string axesFlag {
"OFF"};
740 std::string outputFileName {
"3d-curve-tangent-estimations"};
741 bool curve3d {
false};
742 bool curve2d {
false};
743 bool cover3d {
false};
744 bool cover2d {
false};
745 bool displayTangent {
false};
746 double bigRad {10.0};
747 double smallRad {3.0};
749 unsigned int nbColors {3};
750 app.description(
"This program estimates the tangent vector to a set of 3D integer points, which are supposed to approximate a 3D curve. This set of points is given as a list of points in file <input>.\n The tangent estimator uses either the digital Voronoi Covariance Measure (VCM) or the 3D lambda-Maximal Segment Tangent (L-MST).\n This program can also displays the curve and tangent estimations, and it can also extract maximal digital straight segments (2D and 3D).\n Note: It is not compulsory for the points to be ordered in sequence, except if you wish to compute maximal digital straight segments. In this case, you can select the connectivity of your curve between 6 (standard) or 26 (naive).\n Example:\n 3dCurveTangentEstimator -i ${DGtal}/examples/samples/sinus.dat -V ON -c -R 20 -r 3 -T 6\n" );
751 app.add_option(
"-i,--input,1", inputFileName,
"the name of the text file containing the list of 3D points: (x y z) per line." )
753 ->check(CLI::ExistingFile);
755 app.add_option(
"--view,-V", viewFlag,
"toggles display ON/OFF");
756 app.add_option(
"--box,-b", box,
"specifies the tightness of the bounding box around the curve with a given integer displacement <arg> to enlarge it (0 is tight)");
757 app.add_option(
"--viewBox,-v", viewBox,
"displays the bounding box, <arg>=WIRED means that only edges are displayed, <arg>=COLORED adds colors for planes (XY is red, XZ green, YZ, blue).")
758 -> check(CLI::IsMember({
"WIRED" ,
"COLORED"}));
759 app.add_option(
"--connectivity,-T",connectivity,
"specifies whether it is a 6-connected curve or a 26-connected curve: arg=6 | 26." )
760 -> check(CLI::IsMember({
"6",
"26"}));
761 app.add_flag(
"--curve3d,-C", curve3d,
"displays the 3D curve" );
762 app.add_flag(
"--curve2d,-c", curve2d,
"displays the 2D projections of the 3D curve on the bounding box" );
763 app.add_flag(
"--cover3d,-3", cover3d,
"displays the 3D tangential cover of the curve");
764 app.add_flag(
"--cover2d,-2", cover2d,
"displays the 2D projections of the 3D tangential cover of the curve");
765 app.add_flag(
"--tangent,-t", displayTangent,
"displays the tangents to the curve.");
766 app.add_option(
"--nbColors,-n", nbColors,
"sets the number of successive colors used for displaying 2d and 3d maximal segments (default is 3: red, green, blue)");
768 app.add_option(
"--big-radius,-R",bigRad,
"the radius parameter R in the VCM estimator.");
769 app.add_option(
"--small-radius,-r",smallRad,
"the radius parameter r in the VCM estimator.");
770 app.add_option(
"--method,-m", method,
"the method of tangent computation: VCM (default), L-MST.")
771 -> check(CLI::IsMember({
"VCM",
"L-MST"}));
772 app.add_option(
"--axes,-a", axesFlag,
"show main axes - prints list of axes for each point and color points color = (if X => 255, if Y => 255, if Z => 255)")
773 -> check(CLI::IsMember({
"ON",
"OFF"}));
774 app.add_option(
"--output,-o",outputFileName,
"the basename of the output text file which will contain points and tangent vectors: (x y z tx ty tz) per line");
778 app.get_formatter()->column_width(40);
779 CLI11_PARSE(app, argc, argv);
785 vector<Point> sequence;
787 inputStream.open ( inputFileName.c_str(), ios::in);
790 sequence = PointListReader<Point>::getPointsFromInputStream( inputStream );
791 if ( sequence.size() == 0)
throw IOException();
793 catch (DGtal::IOException & ioe)
795 trace.error() <<
"Size is null." << endl;
800 bool view = viewFlag ==
"ON";
803 bool axes = axesFlag ==
"ON";
804 multimap < Z3i::Point, string > mainAxes;
806 if ( axes && connectivity ==
"26" )
808 find_main_axes<PointIterator, Z3i::Space>(sequence.begin(), sequence.end(), mainAxes);
809 print_main_axes<PointIterator, Z3i::Space>(sequence.begin(), sequence.end(), mainAxes);
811 else if ( axes && connectivity ==
"6" )
813 find_main_axes < PointIterator, Z3i::Space, 4 > ( sequence.begin ( ), sequence.end ( ), mainAxes );
814 print_main_axes<PointIterator, Z3i::Space>(sequence.begin(), sequence.end(), mainAxes);
819 Point lowerBound = sequence[ 0 ];
820 Point upperBound = sequence[ 0 ];
821 for (
unsigned int j = 1; j < sequence.size(); ++j )
823 lowerBound = lowerBound.inf( sequence[ j ] );
824 upperBound = upperBound.sup( sequence[ j ] );
826 lowerBound -= Point::diagonal( box );
827 upperBound += Point::diagonal( box + 1 );
828 K3 ks; ks.init( lowerBound, upperBound,
true );
830 polyscope::options::programName =
"3dCurveTangentEstimator - DGtalTools";
831 polyscope::view::setNavigateStyle(polyscope::NavigateStyle::Free);
832 PolyscopeViewer<Z3,K3> viewer( ks );
833 viewer.allowReuseList =
true;
834 trace.beginBlock (
"Tool 3dCurveTangentEstimator" );
836 std::vector< RealVector > tangents;
838 if ( method ==
"VCM" )
841 const double R = bigRad;
842 trace.info() <<
"Big radius R = " << R << endl;
843 const double r = smallRad;
844 trace.info() <<
"Small radius r = " << r << endl;
846 ComputeVCM < PointIterator, Z3, std::vector< RealVector > > ( R, r, sequence.begin(), sequence.end(), tangents, outputFileName );
848 else if ( method ==
"L-MST" )
850 if (connectivity ==
"6")
851 ComputeLMST6 < PointIterator, Z3, std::vector< RealVector > > ( sequence.begin(), sequence.end(), tangents, outputFileName );
853 ComputeLMST26 < PointIterator, Z3, std::vector< RealVector > > ( sequence.begin(), sequence.end(), tangents, outputFileName );
857 trace.info() <<
"Wrong method! Try: VCM or L-MST" << endl;
863 for (
unsigned int i = 0; i < tangents.size(); i++ )
866 RealPoint p = sequence[i];
867 RealVector tangent = tangents[i];
868 viewer.drawColor( Color ( 255, 0, 0, 255 ) );
869 viewer.drawLine( p + 2.0 * tangent, p - 2.0 * tangent);
870 viewer.drawColor( Color ( 100, 100, 140, 255 ) );
878 GridCurve<K3> gc( ks );
881 gc.initFromPointsVector( sequence );
883 catch (DGtal::ConnectivityException& )
886 trace.warning() <<
"[ConnectivityException] GridCurve only accepts a sequence of face adjacent points. Try connectivity=6 instead." << endl;
896 displayAxes<Point,RealPoint, Z3i::Space, Z3i::KSpace>( viewer, lowerBound, upperBound, viewBox );
898 res = connectivity ==
"6"
899 ? displayCover6( viewer, ks, sequence.begin(), sequence.end(),
905 : displayCover26( viewer, ks, sequence.begin(), sequence.end(),
912 if ( curve3d && ! axes )
914 viewer << CURVE3D_COLOR;
915 for ( vector<Point>::const_iterator it = sequence.begin(); it != sequence.end(); ++it )
918 else if ( curve3d && axes )
920 for ( vector<Point>::const_iterator itt = sequence.begin(); itt != sequence.end(); ++itt ) {
922 typename std::multimap<typename Z3i::Point, string>::const_iterator it = mainAxes.lower_bound(*itt);
923 typename std::multimap<typename Z3i::Point, string>::const_iterator it2 = mainAxes.upper_bound(*itt);
925 for (; it != it2; it++ )
927 if (it->second ==
"X")
929 if (it->second ==
"Y")
931 if (it->second ==
"Z")
935 Color c ( pColor[0], pColor[1], pColor[2], 255 );
944 trace.emphase() << ( res ?
"Passed." :
"Error." ) << endl;