34 #include <boost/program_options/options_description.hpp>
35 #include <boost/program_options/parsers.hpp>
36 #include <boost/program_options/variables_map.hpp>
38 #include "DGtal/base/Common.h"
39 #include "DGtal/base/CountedPtr.h"
40 #include "DGtal/helpers/StdDefs.h"
41 #include "DGtal/math/MPolynomial.h"
42 #include "DGtal/io/readers/MPolynomialReader.h"
43 #include "DGtal/io/DrawWithDisplay3DModifier.h"
44 #include "DGtal/io/viewers/Viewer3D.h"
45 #include "DGtal/topology/KhalimskySpaceND.h"
46 #include "DGtal/topology/CubicalComplex.h"
47 #include "DGtal/topology/CubicalComplexFunctions.h"
48 #include "DGtal/topology/SetOfSurfels.h"
49 #include "DGtal/topology/DigitalSurface.h"
50 #include "DGtal/topology/helpers/Surfaces.h"
51 #include "DGtal/shapes/GaussDigitizer.h"
52 #include "DGtal/shapes/Mesh.h"
53 #include "DGtal/shapes/implicit/ImplicitPolynomial3Shape.h"
58 using namespace DGtal;
131 template <
typename CellOutputIterator,
typename DigitalSurface>
133 analyzeSurface( CellOutputIterator itSure, CellOutputIterator itUnsure,
DigitalSurface surface )
143 const Container& C = surface.
container();
144 const KSpace& K = surface.
container().space();
146 for ( ConstIterator it = surface.
begin(), itE = surface.
end(); it != itE; ++it )
150 Integer s_xt = K.
sKCoord( s, t );
151 if ( s_xt == 0 ) *itUnsure++ = is;
152 else if ( s_xt == -1 )
155 if ( tracker->adjacent( s2, t,
true ) != 0 )
157 Integer s2_xt = K.
sKCoord( s2, t );
159 if ( s2_xt > 0 ) *itSure++ = ic;
160 else *itUnsure++ = ic;
163 else if ( s_xt == 1 )
166 if ( tracker->adjacent( s2, t,
false ) != 0 )
168 Integer s2_xt = K.
sKCoord( s2, t );
170 if ( s2_xt < 0 ) *itSure++ = ic;
171 else *itUnsure++ = ic;
174 else cout <<
" " << s_xt;
186 template <
typename ImplicitSurface,
typename RealPo
int>
187 RealPoint projectNewton(
const ImplicitSurface & is,
190 unsigned int max_iter )
195 Scalar eps2 = epsilon * epsilon;
196 while ( max_iter-- != 0 )
199 if (
abs( f ) < epsilon )
return x;
200 gx = is.gradient( x );
202 if ( g2 < eps2 )
return x;
209 template <
typename CubicalComplex3,
typename ImplicitShape3,
210 typename ImplicitDigitalShape3>
211 void projectComplex( std::vector< typename ImplicitShape3::RealPoint >& points,
212 const CubicalComplex3& complex3,
213 const ImplicitShape3& shape,
214 const ImplicitDigitalShape3& dshape,
216 unsigned int max_iter,
217 double max_distance )
219 typedef typename CubicalComplex3::Cell Cell3;
220 typedef typename CubicalComplex3::Point Point3;
221 typedef typename CubicalComplex3::CellMapConstIterator CellMapConstIterator;
222 typedef typename ImplicitShape3::RealPoint RealPoint3;
223 typedef typename ImplicitShape3::Ring Ring;
225 for ( CellMapConstIterator it = complex3.begin( 0 ), itE = complex3.end( 0 ); it != itE; ++it )
227 Cell3 cell = it->first;
228 Point3 dp = complex3.space().uKCoords( cell ) - Point3::diagonal( 1 );
229 RealPoint3 p = dshape->embed( dp ) / 2.0;
230 RealPoint3 q = projectNewton( shape, p, epsilon, max_iter );
231 double d = (p-q).norm();
232 if ( d > max_distance ) q = p + (q-p)*( max_distance / d );
233 points.push_back( q );
237 template <
typename CubicalComplex3,
typename ImplicitShape3,
238 typename ImplicitDigitalShape3>
239 typename ImplicitShape3::Ring
240 getValue(
const CubicalComplex3& complex3,
241 const typename CubicalComplex3::Cell& cell,
242 const ImplicitShape3& shape,
243 const ImplicitDigitalShape3& dshape )
245 typedef typename CubicalComplex3::Cell Cell3;
246 typedef typename CubicalComplex3::Cells Cells3;
247 typedef typename CubicalComplex3::Point Point3;
248 typedef typename ImplicitShape3::RealPoint RealPoint3;
249 typedef typename ImplicitShape3::Ring Ring;
251 Point3 dp = complex3.space().uKCoords( cell ) - Point3::diagonal( 1 );
252 RealPoint3 p = dshape->embed( dp ) / 2.0;
258 template <
typename CubicalComplex3,
typename ImplicitShape3,
259 typename ImplicitDigitalShape3>
260 void doNotProjectComplex( std::vector< typename ImplicitShape3::RealPoint >& points,
261 const CubicalComplex3& complex3,
262 const ImplicitShape3& shape,
263 const ImplicitDigitalShape3& dshape )
265 typedef typename CubicalComplex3::Cell Cell3;
266 typedef typename CubicalComplex3::Point Point3;
267 typedef typename CubicalComplex3::CellMapConstIterator CellMapConstIterator;
268 typedef typename ImplicitShape3::RealPoint RealPoint3;
269 typedef typename ImplicitShape3::Ring Ring;
271 for ( CellMapConstIterator it = complex3.begin( 0 ), itE = complex3.end( 0 ); it != itE; ++it )
273 Cell3 cell = it->first;
274 Point3 dp = complex3.space().uKCoords( cell );
275 RealPoint3 p = dshape->embed( dp ) / 2.0;
276 points.push_back( p );
282 int main(
int argc,
char** argv )
287 typedef KSpace3::Cell Cell3;
288 typedef std::map<Cell3, CubicalCellData> Map3;
291 typedef Space3::Point Point3;
292 typedef Space3::RealPoint RealPoint3;
293 typedef Space3::RealVector RealVector3;
294 typedef RealPoint3::Coordinate Ring;
300 ImplicitDigitalShape3;
301 typedef ImplicitDigitalShape3::Domain Domain3;
302 typedef CC3::CellMapIterator CellMapIterator;
303 typedef CC3::CellMapConstIterator CellMapConstIterator;
304 typedef CC3::Cells Cells3;
307 namespace po = boost::program_options;
308 po::options_description general_opt(
"Allowed options are: ");
309 general_opt.add_options()
310 (
"help,h",
"display this message")
311 (
"polynomial,p", po::value<string>(),
"the implicit polynomial whose zero-level defines the shape of interest." )
312 (
"minAABB,a", po::value<double>()->default_value( -10.0 ),
"the min value of the AABB bounding box (domain)" )
313 (
"maxAABB,A", po::value<double>()->default_value( 10.0 ),
"the max value of the AABB bounding box (domain)" )
314 (
"gridstep,g", po::value< double >()->default_value( 1.0 ),
"the gridstep that defines the digitization (often called h). " )
315 (
"thickness,t", po::value< double >()->default_value( 1e-2 ),
"the thickening parameter for the implicit surface." )
316 (
"project,P", po::value< std::string >()->default_value(
"Newton" ),
"defines the projection: either No or Newton." )
317 (
"epsilon,e", po::value< double >()->default_value( 1e-6 ),
"the maximum precision relative to the implicit surface in the Newton approximation of F=0." )
318 (
"max_iter,n", po::value< unsigned int >()->default_value( 500 ),
"the maximum number of iteration in the Newton approximation of F=0." )
319 (
"view,v", po::value< std::string >()->default_value(
"Normal" ),
"specifies if the surface is viewed as is (Normal) or if places close to singularities are highlighted (Singular), or if unsure places should not be displayed (Hide)." )
323 po::variables_map vm;
325 po::store(po::parse_command_line(argc, argv, general_opt), vm);
326 }
catch (
const exception& ex ) {
328 cerr <<
"Error checking program options: "<< ex.what()<< endl;
331 if( ! parseOK || vm.count(
"help") || ! vm.count(
"polynomial" ) )
333 if ( ! vm.count(
"polynomial" ) )
334 cerr <<
"Need parameter --polynomial / -p" << endl;
336 cerr <<
"Usage: " << argv[0] <<
" -p <polynomial> [options]\n"
337 <<
"Computes the zero level set of the given polynomial."
339 << general_opt <<
"\n";
340 cerr <<
"Example:\n" << endl
341 << argv[0] <<
" -p \"x^2-y*z^2\" -g 0.1 -a -2 -A 2 -v Singular" << endl
342 <<
" - whitney : x^2-y*z^2" << endl
343 <<
" - 4lines : x*y*(y-x)*(y-z*x)" << endl
344 <<
" - cone : z^2-x^2-y^2" << endl
345 <<
" - simonU : x^2-z*y^2+x^4+y^4" << endl
346 <<
" - cayley3 : 4*(x^2 + y^2 + z^2) + 16*x*y*z - 1" << endl
347 <<
" - crixxi : -0.9*(y^2+z^2-1)^2-(x^2+y^2-1)^3" << endl << endl;
348 cerr <<
"Some other examples (more difficult):" << endl
349 << argv[0] <<
" -a -2 -A 2 -p \"((y^2+z^2-1)^2-(x^2+y^2-1)^3)*(y*(x-1)^2-z*(x+1))^2\" -g 0.025 -e 1e-6 -n 50000 -v Singular -t 0.5 -P Newton" << endl
350 << argv[0] <<
" -a -2 -A 2 -p \"(x^5-4*z^3*y^2)*((x+y)^2-(z-x)^3)\" -g 0.025 -e 1e-6 -n 50000 -v Singular -t 0.05 -P Newton" << endl;
355 trace.
beginBlock(
"Reading polynomial and creating 3D implicit function" );
356 string poly_str = vm[
"polynomial" ].as<
string>();
358 Polynomial3Reader reader;
359 string::const_iterator iter = reader.read( poly, poly_str.begin(), poly_str.end() );
360 if ( iter != poly_str.end() )
362 trace.
error() <<
"ERROR reading polynomial: I read only <" << poly_str.substr( 0, iter - poly_str.begin() )
363 <<
">, and I built P=" << poly << std::endl;
369 Ring min_x = vm[
"minAABB" ].as<
double>();
370 Ring max_x = vm[
"maxAABB" ].as<
double>();
371 Ring h = vm[
"gridstep" ].as<
double>();
372 RealPoint3 p1( min_x, min_x, min_x );
373 RealPoint3 p2( max_x, max_x, max_x );
376 dshape->attach( *shape );
377 dshape->init( p1, p2, RealVector3( h, h, h ) );
378 Domain3 domain3 = dshape->getDomain();
380 K3.
init( domain3.lowerBound(), domain3.upperBound(), true );
381 trace.
info() <<
"- domain is " << domain3 << std::endl;
385 trace.
beginBlock(
"Extracting thickened isosurface [-t,+t] of 3D polynomial. " );
388 Ring t = vm[
"thickness" ].as<
double>();
390 for ( Domain3::ConstIterator it = domain3.begin(), itE = domain3.end(); it != itE; ++it )
392 Cell3 spel = K3.uSpel( *it );
394 RealPoint3 px = dshape->embed( K3.uKCoords( spel ) - Point3::diagonal( 1 ) ) / 2.0;
395 Ring s = (*shape)( px );
396 if ( (-t <= s ) && ( s <= t ) ) complex3.insertCell( spel, unsure_data );
398 trace.
info() <<
"- K[-t,+t] = " << complex3 << endl;
400 trace.
info() <<
"- Cl K[-t,+t] = " << complex3 << endl;
401 std::vector<Cell3> separating_cells;
402 std::back_insert_iterator< std::vector<Cell3> > outItSurface( separating_cells );
404 K3, *dshape, domain3.lowerBound(), domain3.upperBound() );
405 trace.
info() <<
"- separating S = " << separating_cells.size() <<
" 2-cells." << endl;
406 complex3.insertCells( separating_cells.begin(), separating_cells.end(), sure_data );
407 for ( std::vector<Cell3>::const_iterator it = separating_cells.begin(), itE = separating_cells.end(); it != itE; ++it )
409 Cells3 bdry = K3.uFaces( *it );
410 for ( Cells3::const_iterator itBdry = bdry.begin(), itBdryE = bdry.end(); itBdry != itBdryE; ++itBdry )
411 complex3.insertCell( *itBdry, sure_data );
413 separating_cells.clear();
414 trace.
info() <<
"- Cl K[-t,+t] + Cl S = " << complex3 << endl;
419 std::vector<Cell3> inner;
420 std::vector<Cell3> bdry;
421 functions::filterCellsWithinBounds
422 ( complex3, K3.uKCoords( K3.lowerCell() ), K3.uKCoords( K3.upperCell() ),
423 std::back_inserter( bdry ), std::back_inserter( inner ) );
424 trace.
info() <<
"- there are " << inner.size() <<
" inner cells." << endl;
425 trace.
info() <<
"- there are " << bdry.size() <<
" boundary cells." << endl;
433 for ( CellMapIterator it = complex3.begin( i ), itE = complex3.end( i ); it != itE; ++it )
435 Cell3 cell = it->first;
436 Ring v = getValue( complex3, cell, *shape, dshape );
437 v =
abs( 10000.0*v );
438 if ( v > 10000000.0 ) v = 10000000.0;
439 it->second.data &= ~CC3::VALUE;
448 typename CC3::DefaultCellMapIteratorPriority priority;
449 CC3 bdry_complex3( K3 );
450 for ( std::vector<Cell3>::const_iterator it = bdry.begin(), itE = bdry.end(); it != itE; ++it )
454 CellMapConstIterator cmIt = complex3.findCell( d, cell );
455 bdry_complex3.insertCell( d, cell, cmIt->second );
457 trace.
info() <<
"- [before collapse] K_bdry =" << bdry_complex3 << endl;
458 functions::collapse( bdry_complex3, bdry.begin(), bdry.end(), priority,
true,
true, false );
459 trace.
info() <<
"- [after collapse] K_bdry =" << bdry_complex3 << endl;
460 for ( std::vector<Cell3>::const_iterator it = bdry.begin(), itE = bdry.end(); it != itE; ++it )
464 CellMapConstIterator cmIt = bdry_complex3.findCell( d, cell );
465 if ( cmIt != bdry_complex3.end( d ) ) {
466 CellMapIterator cmIt2 = complex3.findCell( d, cell );
467 cmIt2->second = sure_data;
474 std::copy( bdry.begin(), bdry.end(), std::back_inserter( inner ) );
475 functions::collapse( complex3, inner.begin(), inner.end(), priority,
true,
true, true );
476 trace.
info() <<
"- K = " << complex3 << endl;
481 std::string project = vm[
"project" ].as<std::string>();
482 double epsilon = vm[
"epsilon" ].as<
double>();
483 unsigned int max_iter = vm[
"max_iter" ].as<
unsigned int>();
484 std::vector<RealPoint3> points;
485 if ( project ==
"Newton" )
486 projectComplex( points, complex3, *shape, dshape, epsilon, max_iter, h * sqrt(3.0));
488 doNotProjectComplex( points, complex3, *shape, dshape );
493 std::string view = vm[
"view" ].as<std::string>();
494 bool highlight = ( view ==
"Singular" );
495 bool hide = ( view ==
"Hide" );
497 std::map<Cell3,unsigned int> indices;
499 for ( CellMapConstIterator it = complex3.begin( 0 ), itE = complex3.end( 0 ); it != itE; ++it, ++idx )
501 Cell3 cell = it->first;
502 indices[ cell ] = idx;
503 mesh.addVertex( points[ idx ] );
505 for ( CellMapConstIterator it = complex3.begin( 2 ), itE = complex3.end( 2 ); it != itE; ++it )
507 Cell3 cell = it->first;
508 bool fixed = it->second.data & CC3::FIXED;
509 Cells3 bdry = complex3.cellBoundary( cell,
true );
510 std::vector<unsigned int> face_idx;
511 for ( Cells3::const_iterator itC = bdry.begin(), itCE = bdry.end(); itC != itCE; ++itC )
513 if ( complex3.dim( *itC ) == 0 )
514 face_idx.push_back( indices[ *itC ] );
516 if ( ( ! fixed ) && hide )
continue;
517 Color color = highlight
518 ? ( fixed ? Color::White :
Color(128,255,128) )
520 RealVector3 diag03 = points[ face_idx[ 0 ] ] - points[ face_idx[ 3 ] ];
521 RealVector3 diag12 = points[ face_idx[ 1 ] ] - points[ face_idx[ 2 ] ];
522 if ( diag03.dot( diag03 ) <= diag12.dot( diag12 ) )
524 mesh.addTriangularFace( face_idx[ 0 ], face_idx[ 1 ], face_idx[ 3 ], color );
525 mesh.addTriangularFace( face_idx[ 0 ], face_idx[ 3 ], face_idx[ 2 ], color );
529 mesh.addTriangularFace( face_idx[ 0 ], face_idx[ 1 ], face_idx[ 2 ], color );
530 mesh.addTriangularFace( face_idx[ 1 ], face_idx[ 3 ], face_idx[ 2 ], color );
537 QApplication application(argc,argv);
539 viewer.setWindowTitle(
"Implicit surface viewer by thickening");
543 for ( CellMapConstIterator it = complex3.begin( 1 ), itE = complex3.end( 1 ); it != itE; ++it )
545 Cell3 cell = it->first;
546 bool fixed = it->second.data & CC3::FIXED;
547 std::vector<Cell3> dummy;
548 std::back_insert_iterator< std::vector<Cell3> > outIt( dummy );
549 complex3.directCoFaces( outIt, cell );
550 if ( ! dummy.empty() )
continue;
552 Cells3 bdry = complex3.cellBoundary( cell,
true );
553 Cell3 v0 = *(bdry.begin() );
554 Cell3 v1 = *(bdry.begin() + 1);
555 if ( ( ! fixed ) && hide )
continue;
556 Color color = highlight
557 ? ( fixed ? Color::White :
Color(128,255,128) )
559 viewer.setLineColor( color );
560 viewer.addLine( points[ indices[ v0 ] ], points[ indices[ v1 ] ], h/2.0 );
562 viewer << Viewer3D<Space3,KSpace3>::updateDisplay;
563 return application.exec();
void beginBlock(const std::string &keyword="")
DigitalSurfaceContainer::SurfelConstIterator ConstIterator
DGtal::uint32_t Dimension
DigitalSurfaceContainer::DigitalSurfaceTracker DigitalSurfaceTracker
TDigitalSurfaceContainer DigitalSurfaceContainer
bool init(const Point &lower, const Point &upper, bool isClosed)
Cell uIncident(const Cell &c, Dimension k, bool up) const
DigitalSurfaceContainer::KSpace KSpace
Trace trace(traceWriterTerm)
Integer sKCoord(const SCell &c, Dimension k) const
const DigitalSurfaceContainer & container() const
Cell unsigns(const SCell &p) const
static const constexpr Dimension dimension
Component dot(const Self &v) const
ConstIterator begin() const
DigitalSurfaceContainer::Surfel Surfel
ConstIterator end() const