168int main( 
int argc, 
char* argv[] )
 
  176  using namespace DGtal;
 
  183  std::string  poly = argv[ 1 ]; 
 
  184  const double    B = argc > 2 ? atof( argv[ 2 ] ) : 1.0; 
 
  185  const double    h = argc > 3 ? atof( argv[ 3 ] ) : 1.0; 
 
  186  const double    R = argc > 4 ? atof( argv[ 4 ] ) : 2.0; 
 
  187  std::string  mode = argc > 5 ? argv[ 5 ] : 
"Const"; 
 
  188  bool interpolated = mode == 
"Interp";
 
  190    std::cout << 
"Using vertex-*Interpolated* Corrected Normal Current" << std::endl;
 
  192    std::cout << 
"Using face-*Constant* Corrected Normal Current" << std::endl;
 
  195  auto params = SH::defaultParameters() | SHG::defaultParameters();
 
  196  params( 
"t-ring", 3 )( 
"surfaceTraversal", 
"Default" );
 
  197  params( 
"polynomial", poly )( 
"gridstep", h ); 
 
  198  params( 
"minAABB", -
B )( 
"maxAABB", 
B );
 
  199  params( 
"offset", 3.0 );
 
  200  auto shape       = SH::makeImplicitShape3D( params );
 
  201  auto K           = SH::getKSpace( params );
 
  202  auto dshape      = SH::makeDigitizedImplicitShape3D( shape, params );
 
  203  auto bimage      = SH::makeBinaryImage( dshape, params );
 
  204  if ( bimage == 
nullptr ) 
 
  206      trace.error() <<  
"Unable to read polynomial <" 
  207                    << poly.c_str() << 
">" << std::endl;
 
  210  auto sembedder   = SH::getSCellEmbedder( 
K );
 
  211  auto embedder    = SH::getCellEmbedder( 
K );
 
  212  auto surface     = SH::makeDigitalSurface( bimage, 
K, params );
 
  213  auto surfels     = SH::getSurfelRange( 
surface, params );
 
  214  trace.info() << 
"- surface has " << surfels.size()<< 
" surfels." << std::endl;
 
  219  std::vector< SM::Vertices > faces;
 
  221  auto pointels = SH::getPointelRange( c2i, 
surface );
 
  222  auto vertices = SH::RealPoints( pointels.size() );
 
  223  std::transform( pointels.cbegin(), pointels.cend(), vertices.begin(),
 
  224                  [&] (
const SH::Cell& c) { return h * embedder( c ); } ); 
 
  225  for ( 
auto&& surfel : *
surface )
 
  227      const auto primal_surfel_vtcs = SH::getPointelRange( 
K, surfel );
 
  229      for ( 
auto&& primal_vtx : primal_surfel_vtcs )
 
  230        face.push_back( c2i[ primal_vtx ] );
 
  231      faces.push_back( face );
 
  233  smesh.init( vertices.cbegin(), vertices.cend(),
 
  234              faces.cbegin(),    faces.cend() );
 
  235  trace.info() << smesh << std::endl;
 
  239  auto exp_H = SHG::getMeanCurvatures( shape, 
K, surfels, params );
 
  240  auto exp_G = SHG::getGaussianCurvatures( shape, 
K, surfels, params );
 
  247  auto face_normals = SHG::getCTrivialNormalVectors( 
surface, surfels, params );
 
  250  smesh.setFaceNormals( face_normals.cbegin(), face_normals.cend() ); 
 
  253  if ( interpolated ) smesh.computeVertexNormalsFromFaceNormals();    
 
  255  auto mu0 = cnc.computeMu0();
 
  256  auto mu1 = cnc.computeMu1();
 
  257  auto mu2 = cnc.computeMu2();
 
  262  std::vector< double > 
H( smesh.nbFaces() );
 
  263  std::vector< double > G( smesh.nbFaces() );
 
  264  for ( 
auto f = 0; f < smesh.nbFaces(); ++f )
 
  266      const auto b    = smesh.faceCentroid( f );
 
  267      const auto area = mu0.measure( b, R, f );
 
  268      H[ f ] = cnc.meanCurvature    ( area, mu1.measure( b, R, f ) );
 
  269      G[ f ] = cnc.GaussianCurvature( area, mu2.measure( b, R, f ) );
 
  274  auto H_min_max = std::minmax_element( 
H.cbegin(), 
H.cend() );
 
  275  auto G_min_max = std::minmax_element( G.cbegin(), G.cend() );
 
  276  auto exp_H_min_max = std::minmax_element( exp_H.cbegin(), exp_H.cend() );
 
  277  auto exp_G_min_max = std::minmax_element( exp_G.cbegin(), exp_G.cend() );
 
  278  std::cout << 
"Expected mean curvatures:" 
  279            << 
" min=" << *exp_H_min_max.first << 
" max=" << *exp_H_min_max.second
 
  281  std::cout << 
"Computed mean curvatures:" 
  282            << 
" min=" << *H_min_max.first << 
" max=" << *H_min_max.second
 
  284  std::cout << 
"Expected Gaussian curvatures:" 
  285            << 
" min=" << *exp_G_min_max.first << 
" max=" << *exp_G_min_max.second
 
  287  std::cout << 
"Computed Gaussian curvatures:" 
  288            << 
" min=" << *G_min_max.first << 
" max=" << *G_min_max.second
 
  290  const auto      error_H = SHG::getScalarsAbsoluteDifference( 
H, exp_H );
 
  291  const auto stat_error_H = SHG::getStatistic( error_H );
 
  292  const auto   error_H_l2 = SHG::getScalarsNormL2( 
H, exp_H );
 
  293  trace.info() << 
"|H-H_CNC|_oo = " << stat_error_H.max() << std::endl;
 
  294  trace.info() << 
"|H-H_CNC|_2  = " << error_H_l2 << std::endl;
 
  295  const auto      error_G = SHG::getScalarsAbsoluteDifference( G, exp_G );
 
  296  const auto stat_error_G = SHG::getStatistic( error_G );
 
  297  const auto   error_G_l2 = SHG::getScalarsNormL2( G, exp_G );
 
  298  trace.info() << 
"|G-G_CNC|_oo = " << stat_error_G.max() << std::endl;
 
  299  trace.info() << 
"|G-G_CNC|_2  = " << error_G_l2 << std::endl;
 
  304  smesh.vertexNormals() = SH::RealVectors();
 
  305  smesh.faceNormals()   = SH::RealVectors();
 
  307  const double    Hmax = std::max( fabs( *exp_H_min_max.first ),
 
  308                                   fabs( *exp_H_min_max.second ) );
 
  309  const double    Gmax = std::max( fabs( *exp_G_min_max.first ),
 
  310                                   fabs( *exp_G_min_max.second ) );
 
  313  auto colorsH = SMW::Colors( smesh.nbFaces() );
 
  314  auto colorsG = SMW::Colors( smesh.nbFaces() );
 
  315  for ( 
auto i = 0; i < smesh.nbFaces(); i++ )
 
  317      colorsH[ i ] = colormapH( 
H[ i ] );
 
  318      colorsG[ i ] = colormapG( G[ i ] );
 
  320  SMW::writeOBJ( 
"example-cnc-H", smesh, colorsH );
 
  321  SMW::writeOBJ( 
"example-cnc-G", smesh, colorsG );