91 #include <boost/program_options/options_description.hpp> 92 #include <boost/program_options/parsers.hpp> 93 #include <boost/program_options/variables_map.hpp> 95 #include "DGtal/base/Common.h" 96 #include "DGtal/base/Exceptions.h" 97 #include "DGtal/kernel/SpaceND.h" 98 #include "DGtal/kernel/domains/HyperRectDomain.h" 99 #include "DGtal/topology/KhalimskySpaceND.h" 100 #include "DGtal/geometry/curves/GridCurve.h" 101 #include "DGtal/geometry/curves/StandardDSS6Computer.h" 102 #include "DGtal/geometry/curves/SaturatedSegmentation.h" 103 #include "DGtal/io/viewers/Viewer3D.h" 104 #include "DGtal/io/readers/PointListReader.h" 105 #include "DGtal/io/DrawWithDisplay3DModifier.h" 108 using namespace DGtal;
111 const Color AXIS_COLOR( 0, 0, 0, 255 );
112 const double AXIS_LINESIZE = 0.1;
113 const Color XY_COLOR( 0, 0, 255, 50 );
114 const Color XZ_COLOR( 0, 255, 0, 50 );
115 const Color YZ_COLOR( 255, 0, 0, 50 );
116 const Color CURVE3D_COLOR( 100, 100, 140, 128 );
117 const Color CURVE2D_COLOR( 200, 200, 200, 100 );
118 const double MS3D_LINESIZE = 0.05;
123 template <
typename Po
int,
typename RealPo
int,
typename space,
typename kspace >
124 void displayAxes( Viewer3D<space, kspace> & viewer,
125 const Point & lowerBound,
const Point & upperBound,
126 const std::string & mode )
128 RealPoint p0( (
double)lowerBound[ 0 ]-0.5,
129 (
double)lowerBound[ 1 ]-0.5,
130 (
double)lowerBound[ 2 ]-0.5 );
131 RealPoint p1( (
double)upperBound[ 0 ]-0.5,
132 (
double)upperBound[ 1 ]-0.5,
133 (
double)upperBound[ 2 ]-0.5 );
134 if ( ( mode ==
"WIRED" ) || ( mode ==
"COLORED" ) )
136 viewer.setLineColor(AXIS_COLOR);
137 viewer.addLine( DGtal::Z3i::RealPoint(p0[ 0 ], p0[ 1 ], p0[ 2 ]),
138 DGtal::Z3i::RealPoint(p1[ 0 ], p0[ 1 ], p0[ 2 ]), AXIS_LINESIZE );
139 viewer.addLine( DGtal::Z3i::RealPoint(p0[ 0 ], p0[ 1 ], p0[ 2 ]),
140 DGtal::Z3i::RealPoint(p0[ 0 ], p1[ 1 ], p0[ 2 ]), AXIS_LINESIZE );
141 viewer.addLine( DGtal::Z3i::RealPoint(p0[ 0 ], p0[ 1 ], p0[ 2 ]),
142 DGtal::Z3i::RealPoint(p0[ 0 ], p0[ 1 ], p1[ 2 ]), AXIS_LINESIZE );
143 viewer.addLine( DGtal::Z3i::RealPoint(p1[ 0 ], p0[ 1 ], p0[ 2 ]),
144 DGtal::Z3i::RealPoint(p1[ 0 ], p1[ 1 ], p0[ 2 ]), AXIS_LINESIZE );
145 viewer.addLine( DGtal::Z3i::RealPoint(p1[ 0 ], p0[ 1 ], p0[ 2 ]),
146 DGtal::Z3i::RealPoint(p1[ 0 ], p0[ 1 ], p1[ 2 ]), AXIS_LINESIZE );
147 viewer.addLine( DGtal::Z3i::RealPoint(p0[ 0 ], p1[ 1 ], p0[ 2 ]),
148 DGtal::Z3i::RealPoint(p1[ 0 ], p1[ 1 ], p0[ 2 ]), AXIS_LINESIZE );
149 viewer.addLine( DGtal::Z3i::RealPoint(p0[ 0 ], p1[ 1 ], p0[ 2 ]),
150 DGtal::Z3i::RealPoint(p0[ 0 ], p1[ 1 ], p1[ 2 ]), AXIS_LINESIZE );
151 viewer.addLine( DGtal::Z3i::RealPoint(p0[ 0 ], p0[ 1 ], p1[ 2 ]),
152 DGtal::Z3i::RealPoint(p1[ 0 ], p0[ 1 ], p1[ 2 ]), AXIS_LINESIZE );
153 viewer.addLine( DGtal::Z3i::RealPoint(p0[ 0 ], p0[ 1 ], p1[ 2 ]),
154 DGtal::Z3i::RealPoint(p0[ 0 ], p1[ 1 ], p1[ 2 ]), AXIS_LINESIZE );
155 viewer.addLine( DGtal::Z3i::RealPoint(p1[ 0 ], p1[ 1 ], p0[ 2 ]),
156 DGtal::Z3i::RealPoint(p1[ 0 ], p1[ 1 ], p1[ 2 ]), AXIS_LINESIZE );
157 viewer.addLine( DGtal::Z3i::RealPoint(p1[ 0 ], p0[ 1 ], p1[ 2 ]),
158 DGtal::Z3i::RealPoint(p1[ 0 ], p1[ 1 ], p1[ 2 ]), AXIS_LINESIZE );
159 viewer.addLine( DGtal::Z3i::RealPoint(p0[ 0 ], p1[ 1 ], p1[ 2 ]),
160 DGtal::Z3i::RealPoint(p1[ 0 ], p1[ 1 ], p1[ 2 ]), AXIS_LINESIZE );
162 if ( mode ==
"COLORED" )
164 viewer.setFillColor(XY_COLOR);
165 viewer.addQuad(DGtal::Z3i::RealPoint(p1[ 0 ], p1[ 1 ], p1[ 2 ]),
166 DGtal::Z3i::RealPoint(p1[ 0 ], p0[ 1 ], p1[ 2 ]),
167 DGtal::Z3i::RealPoint(p0[ 0 ], p0[ 1 ], p1[ 2 ]),
168 DGtal::Z3i::RealPoint(p0[ 0 ], p1[ 1 ], p1[ 2 ]) );
169 viewer.setFillColor(XZ_COLOR);
170 viewer.addQuad(DGtal::Z3i::RealPoint(p1[ 0 ], p1[ 1 ], p1[ 2 ]),
171 DGtal::Z3i::RealPoint(p0[ 0 ], p1[ 1 ], p1[ 2 ]),
172 DGtal::Z3i::RealPoint(p0[ 0 ], p1[ 1 ], p0[ 2 ]),
173 DGtal::Z3i::RealPoint(p1[ 0 ], p1[ 1 ], p0[ 2 ]));
174 viewer.setFillColor(YZ_COLOR);
175 viewer.addQuad(DGtal::Z3i::RealPoint(p1[ 0 ], p1[ 1 ], p1[ 2 ]),
176 DGtal::Z3i::RealPoint(p1[ 0 ], p0[ 1 ], p1[ 2 ]),
177 DGtal::Z3i::RealPoint(p1[ 0 ], p0[ 1 ], p0[ 2 ]),
178 DGtal::Z3i::RealPoint(p1[ 0 ], p1[ 1 ], p0[ 2 ]));
182 template <
typename KSpace,
typename StandardDSS6Computer,
typename space,
typename kspace >
183 void displayDSS3d( Viewer3D<space, kspace> & viewer,
184 const KSpace & ks,
const StandardDSS6Computer & dss3d,
185 const DGtal::Color & color3d )
187 viewer << CustomColors3D( color3d, color3d ) << dss3d;
190 template <
typename Po
int1,
typename Po
int2>
191 void assign( Point1 & p1,
const Point2 & p2 )
198 template <
typename KSpace,
typename StandardDSS6Computer,
typename space,
typename kspace >
199 void displayDSS3dTangent( Viewer3D<space, kspace> & viewer,
200 const KSpace & ks,
const StandardDSS6Computer & dss3d,
201 const DGtal::Color & color3d )
203 typedef typename StandardDSS6Computer::Point3d Point;
204 typedef typename StandardDSS6Computer::PointR3d PointR3d;
205 typedef DGtal::PointVector<3,double> PointD3d;
206 typedef typename Display3D<>::BallD3D PointD3D;
208 PointR3d interceptR, thicknessR;
209 PointD3d P1, P2, direction;
210 dss3d.getParameters( directionZ3, interceptR, thicknessR );
213 intercept[0] = (double) NumberTraits<int>::castToInt64_t ( interceptR[0].first ) / (double) NumberTraits<int>::castToInt64_t ( interceptR[0].second );
214 intercept[1] = (double) NumberTraits<int>::castToInt64_t ( interceptR[1].first ) / (double) NumberTraits<int>::castToInt64_t ( interceptR[1].second );
215 intercept[2] = (double) NumberTraits<int>::castToInt64_t ( interceptR[2].first ) / (double) NumberTraits<int>::castToInt64_t ( interceptR[2].second );
218 thickness[0] = (double) NumberTraits<int>::castToInt64_t ( thicknessR[0].first ) / (double) NumberTraits<int>::castToInt64_t ( thicknessR[0].second );
219 thickness[1] = (double) NumberTraits<int>::castToInt64_t ( thicknessR[1].first ) / (double) NumberTraits<int>::castToInt64_t ( thicknessR[1].second );
220 thickness[2] = (double) NumberTraits<int>::castToInt64_t ( thicknessR[2].first ) / (double) NumberTraits<int>::castToInt64_t ( thicknessR[2].second );
222 assign( direction, directionZ3 );
223 direction /= direction.norm();
224 assign( P1, *dss3d.begin() );
225 assign( P2, *(dss3d.end()-1) );
226 double t1 = (P1 - intercept).dot( direction );
227 double t2 = (P2 - intercept).dot( direction );
229 PointD3d Q1 = intercept + t1 * direction;
230 PointD3d Q2 = intercept + t2 * direction;
231 viewer.setLineColor(color3d);
232 viewer.addLine( DGtal::Z3i::RealPoint(Q1[ 0 ]-0.5, Q1[ 1 ]-0.5, Q1[ 2 ]-0.5),
233 DGtal::Z3i::RealPoint(Q2[ 0 ]-0.5, Q2[ 1 ]-0.5, Q2[ 2 ]-0.5),
237 template <
typename KSpace,
typename StandardDSS6Computer,
typename space,
typename kspace >
238 void displayProj2d( Viewer3D<space, kspace> & viewer,
239 const KSpace & ks,
const StandardDSS6Computer & dss3d,
240 const DGtal::Color & color2d )
242 typedef typename StandardDSS6Computer::ArithmeticalDSSComputer2d ArithmeticalDSSComputer2d;
243 typedef typename ArithmeticalDSSComputer2d::ConstIterator ConstIterator2d;
244 typedef typename ArithmeticalDSSComputer2d::Point Point2d;
245 typedef typename KSpace::Cell Cell;
246 typedef typename KSpace::Point Point3d;
247 Point3d b = ks.lowerBound();
248 for ( DGtal::Dimension i = 0; i < 3; ++i )
250 const ArithmeticalDSSComputer2d & dss2d = dss3d.arithmeticalDSS2d( i );
251 for ( ConstIterator2d itP = dss2d.begin(), itPEnd = dss2d.end(); itP != itPEnd; ++itP )
256 case 0: q = Point3d( 2*b[ i ] , 2*p[ 0 ]+1, 2*p[ 1 ]+1 );
break;
257 case 1: q = Point3d( 2*p[ 0 ]+1, 2*b[ i ] , 2*p[ 1 ]+1 );
break;
258 case 2: q = Point3d( 2*p[ 0 ]+1, 2*p[ 1 ]+1, 2*b[ i ] );
break;
260 Cell c = ks.uCell( q );
261 viewer << CustomColors3D( color2d, color2d ) << c;
266 template <
typename KSpace,
typename StandardDSS6Computer,
typename space,
typename kspace >
267 void displayDSS2d( Viewer3D<space, kspace> & viewer,
268 const KSpace & ks,
const StandardDSS6Computer & dss3d,
269 const DGtal::Color & color2d )
271 typedef typename StandardDSS6Computer::ConstIterator ConstIterator3d;
272 typedef typename StandardDSS6Computer::ArithmeticalDSSComputer2d ArithmeticalDSSComputer2d;
273 typedef typename ArithmeticalDSSComputer2d::ConstIterator ConstIterator2d;
274 typedef typename ArithmeticalDSSComputer2d::Point Point2d;
275 typedef typename KSpace::Cell Cell;
276 typedef typename KSpace::Point Point3d;
277 typedef DGtal::PointVector<2,double> PointD2d;
278 typedef typename Display3D<>::BallD3D PointD3D;
279 Point3d b = ks.lowerBound();
280 for ( DGtal::Dimension i = 0; i < 3; ++i )
282 const typename ArithmeticalDSSComputer2d::Primitive & dss2d
283 = dss3d.arithmeticalDSS2d( i ).primitive();
285 std::vector<PointD2d> pts2d;
286 pts2d.push_back( dss2d.project(dss2d.back(), dss2d.Uf()) );
287 pts2d.push_back( dss2d.project(dss2d.back(), dss2d.Lf()) );
288 pts2d.push_back( dss2d.project(dss2d.front(), dss2d.Lf()) );
289 pts2d.push_back( dss2d.project(dss2d.front(), dss2d.Uf()) );
290 std::vector<PointD3D> bb;
292 for (
unsigned int j = 0; j < pts2d.size(); ++j )
295 case 0: p3.center[0] = (double) b[ i ]-0.5; p3.center[1] = pts2d[ j ][ 0 ]; p3.center[2] = pts2d[ j ][ 1 ];
break;
296 case 1: p3.center[0] = pts2d[ j ][ 0 ]; p3.center[1] = (double) b[ i ]-0.5; p3.center[2] = pts2d[ j ][ 1 ];
break;
297 case 2: p3.center[0] = pts2d[ j ][ 0 ]; p3.center[1] = pts2d[ j ][ 1 ]; p3.center[2] = (double) b[ i ]-0.5;
break;
301 for (
unsigned int j = 0; j < pts2d.size(); ++j ){
302 viewer.setLineColor(color2d);
303 viewer.addLine( DGtal::Z3i::RealPoint(bb[ j ].center[0], bb[ j ].center[1], bb[ j ].center[2]),
304 DGtal::Z3i::RealPoint(bb[ (j+1)%4 ].center[0], bb[ (j+1)%4 ].center[1], bb[ (j+1)%4 ].center[2]),
314 template <
typename KSpace,
typename Po
intIterator,
typename space,
typename kspace >
315 bool displayCover( Viewer3D<space, kspace> & viewer,
316 const KSpace & ks, PointIterator b, PointIterator e,
317 bool dss3d,
bool proj2d,
bool dss2d,
bool tangent,
320 typedef typename PointIterator::value_type Point;
321 typedef StandardDSS6Computer<PointIterator,int,4> SegmentComputer;
322 typedef SaturatedSegmentation<SegmentComputer> Decomposition;
323 typedef typename Decomposition::SegmentComputerIterator SegmentComputerIterator;
324 typedef typename SegmentComputer::ArithmeticalDSSComputer2d ArithmeticalDSSComputer2d;
325 SegmentComputer algo;
326 Decomposition theDecomposition(b, e, algo);
328 viewer << SetMode3D( algo.className(),
"BoundingBox" );
329 HueShadeColorMap<int> cmap_hue( 0, nbColors, 1 );
332 for ( SegmentComputerIterator i = theDecomposition.begin();
333 i != theDecomposition.end(); ++i)
335 SegmentComputer ms3d(*i);
336 const ArithmeticalDSSComputer2d & dssXY = ms3d.arithmeticalDSS2dXY();
337 const ArithmeticalDSSComputer2d & dssXZ = ms3d.arithmeticalDSS2dXZ();
338 const ArithmeticalDSSComputer2d & dssYZ = ms3d.arithmeticalDSS2dYZ();
339 Point f = *ms3d.begin();
340 Point l = *(ms3d.end() - 1);
341 trace.info() <<
"- " << c
343 <<
" [" << f[ 0 ] <<
"," << f[ 1 ] <<
","<< f[ 2 ] <<
"]" 344 <<
"->[" << l[ 0 ] <<
"," << l[ 1 ] <<
","<< l[ 2 ] <<
"]" 346 << dssXY.a() <<
"," << dssXY.b() <<
"," << dssXY.mu()
348 << dssXZ.a() <<
"," << dssXZ.b() <<
"," << dssXZ.mu()
350 << dssYZ.a() <<
"," << dssYZ.b() <<
"," << dssYZ.mu()
354 Color color = cmap_hue( c );
355 if ( tangent ) displayDSS3dTangent( viewer, ks, ms3d, color );
356 if ( dss3d ) displayDSS3d( viewer, ks, ms3d, color );
357 if ( dss2d ) displayDSS2d( viewer, ks, ms3d, color );
358 if ( proj2d ) displayProj2d( viewer, ks, ms3d, CURVE2D_COLOR );
366 namespace po = boost::program_options;
376 int main(
int argc,
char **argv)
378 typedef SpaceND<3,int> Z3;
379 typedef KhalimskySpaceND<3,int> K3;
380 typedef Z3::Point Point;
381 typedef Z3::RealPoint RealPoint;
384 QApplication application(argc,argv);
385 po::options_description general_opt(
"Specific allowed options (for Qt options, see Qt official site) are");
386 general_opt.add_options()
387 (
"help,h",
"display this message")
388 (
"input,i", po::value<std::string>(),
"the name of the text file containing the list of 3D points (x y z per line)" )
389 (
"box,b", po::value<int>()->default_value( 0 ),
"specifies the the tightness of the bounding box around the curve with a given integer displacement <arg> to enlarge it (0 is tight)" )
390 (
"viewBox,v", po::value<string>()->default_value(
"WIRED" ),
"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)." )
391 (
"curve3d,C",
"displays the 3D curve")
392 (
"curve2d,c",
"displays the 2D projections of the 3D curve on the bounding box")
393 (
"cover3d,3",
"displays the 3D tangential cover of the curve" )
394 (
"cover2d,2",
"displays the 2D projections of the 3D tangential cover of the curve" )
395 (
"nbColors,n", po::value<int>()->default_value( 3 ),
"sets the number of successive colors used for displaying 2d and 3d maximal segments (default is 3: red, green, blue)" )
396 (
"tangent,t",
"displays the tangents to the curve" )
398 po::positional_options_description pos_opt;
399 pos_opt.add(
"input", 1);
403 po::variables_map vm;
405 po::command_line_parser clp( argc, argv );
406 clp.options( general_opt ).positional( pos_opt );
407 po::store( clp.run(), vm );
408 }
catch(
const std::exception& ex ) {
410 trace.info() <<
"Error checking program options: "<< ex.what() << endl;
413 if( !parseOK || vm.count(
"help")||argc<=1)
415 std::cout <<
"Usage: " << argv[0] <<
" [options] input\n" 416 <<
"Display a 3D curve given as the <input> filename (with possibly projections and/or tangent information) by using QGLviewer.\n" 417 << general_opt <<
"\n\n";
418 std::cout <<
"Example:\n" 419 <<
"3dCurveViewer -C -b 1 -3 -2 -c ${DGtal}/examples/samples/sinus.dat\n";
424 string input = vm[
"input"].as<std::string>();
425 int b = vm[
"box"].as<
int>();
427 vector<Point> sequence;
429 inputStream.open ( input.c_str(), ios::in);
431 sequence = PointListReader<Point>::getPointsFromInputStream( inputStream );
432 if ( sequence.size() == 0)
throw IOException();
434 catch (DGtal::IOException & ioe) {
435 trace.error() <<
"Size is null." << std::endl;
441 trace.beginBlock (
"Tool 3dCurveViewer" );
445 Point lowerBound = sequence[ 0 ];
446 Point upperBound = sequence[ 0 ];
447 for (
unsigned int j = 1; j < sequence.size(); ++j )
449 lowerBound = lowerBound.inf( sequence[ j ] );
450 upperBound = upperBound.sup( sequence[ j ] );
452 lowerBound -= Point::diagonal( b );
453 upperBound += Point::diagonal( b+1 );
454 K3 ks; ks.init( lowerBound, upperBound,
true );
455 GridCurve<K3> gc( ks );
457 gc.initFromPointsVector( sequence );
458 }
catch (DGtal::ConnectivityException& ) {
459 throw ConnectivityException();
467 if ( vm.count(
"viewBox" ) )
468 displayAxes<Point,RealPoint, Z3i::Space, Z3i::KSpace>( viewer, lowerBound, upperBound, vm[
"viewBox" ].as<std::string>() );
470 bool res = displayCover( viewer, ks, sequence.begin(), sequence.end(),
471 vm.count(
"cover3d" ),
472 vm.count(
"curve2d" ),
473 vm.count(
"cover2d" ),
474 vm.count(
"tangent" ),
475 vm[
"nbColors"].as<
int>() );
477 if ( vm.count(
"curve3d" ) )
478 viewer << CustomColors3D( CURVE3D_COLOR, CURVE3D_COLOR )
479 << gc.getPointsRange()
484 viewer << Viewer3D<>::updateDisplay;
486 trace.emphase() << ( res ?
"Passed." :
"Error." ) << endl;