170int main( 
int argc, 
char* argv[] )
 
  178  using namespace DGtal;
 
  185  std::string  poly = argv[ 1 ]; 
 
  186  const double    B = argc > 2 ? atof( argv[ 2 ] ) : 1.0; 
 
  187  const double    h = argc > 3 ? atof( argv[ 3 ] ) : 1.0; 
 
  188  const double    R = argc > 4 ? atof( argv[ 4 ] ) : 2.0; 
 
  189  std::string  mode = argc > 5 ? argv[ 5 ] : 
"Const"; 
 
  190  bool interpolated = mode == 
"Interp";
 
  192    std::cout << 
"Using vertex-*Interpolated* Corrected Normal Current" << std::endl;
 
  194    std::cout << 
"Using face-*Constant* Corrected Normal Current" << std::endl;
 
  197  auto params = SH::defaultParameters() | SHG::defaultParameters();
 
  198  params( 
"t-ring", 3 )( 
"surfaceTraversal", 
"Default" );
 
  199  params( 
"polynomial", poly )( 
"gridstep", h ); 
 
  200  params( 
"minAABB", -
B )( 
"maxAABB", 
B );
 
  201  params( 
"offset", 3.0 );
 
  202  auto shape       = SH::makeImplicitShape3D( params );
 
  203  auto K           = SH::getKSpace( params );
 
  204  auto dshape      = SH::makeDigitizedImplicitShape3D( shape, params );
 
  205  auto bimage      = SH::makeBinaryImage( dshape, params );
 
  206  if ( bimage == 
nullptr ) 
 
  208      trace.error() <<  
"Unable to read polynomial <" 
  209                    << poly.c_str() << 
">" << std::endl;
 
  212  auto sembedder   = SH::getSCellEmbedder( 
K );
 
  213  auto embedder    = SH::getCellEmbedder( 
K );
 
  214  auto surface     = SH::makeDigitalSurface( bimage, 
K, params );
 
  215  auto surfels     = SH::getSurfelRange( 
surface, params );
 
  216  trace.info() << 
"- surface has " << surfels.size()<< 
" surfels." << std::endl;
 
  221  std::vector< SM::Vertices > faces;
 
  223  auto pointels = SH::getPointelRange( c2i, 
surface );
 
  224  auto vertices = SH::RealPoints( pointels.size() );
 
  225  std::transform( pointels.cbegin(), pointels.cend(), vertices.begin(),
 
  226                  [&] (
const SH::Cell& c) { return h * embedder( c ); } ); 
 
  227  for ( 
auto&& surfel : *
surface )
 
  229      const auto primal_surfel_vtcs = SH::getPointelRange( 
K, surfel );
 
  231      for ( 
auto&& primal_vtx : primal_surfel_vtcs )
 
  232        face.push_back( c2i[ primal_vtx ] );
 
  233      faces.push_back( face );
 
  235  smesh.init( vertices.cbegin(), vertices.cend(),
 
  236              faces.cbegin(),    faces.cend() );
 
  237  trace.info() << smesh << std::endl;
 
  241  auto exp_K1 = SHG::getFirstPrincipalCurvatures ( shape, 
K, surfels, params );
 
  242  auto exp_K2 = SHG::getSecondPrincipalCurvatures( shape, 
K, surfels, params );
 
  243  auto exp_D1 = SHG::getFirstPrincipalDirections ( shape, 
K, surfels, params );
 
  244  auto exp_D2 = SHG::getSecondPrincipalDirections( shape, 
K, surfels, params );
 
  251  auto face_normals = SHG::getCTrivialNormalVectors( 
surface, surfels, params );
 
  254  smesh.setFaceNormals( face_normals.cbegin(), face_normals.cend() ); 
 
  257  if ( interpolated ) smesh.computeVertexNormalsFromFaceNormals();    
 
  259  auto mu0  = cnc.computeMu0();
 
  260  auto muXY = cnc.computeMuXY();
 
  266  std::vector< double > K1( smesh.nbFaces() );
 
  267  std::vector< double > K2( smesh.nbFaces() );
 
  268  std::vector< RealVector > D1( smesh.nbFaces() );
 
  269  std::vector< RealVector > D2( smesh.nbFaces() );
 
  270  for ( 
auto f = 0; f < smesh.nbFaces(); ++f )
 
  272      const auto b    = smesh.faceCentroid( f );
 
  273      const auto N    = smesh.faceNormals()[ f ];
 
  274      const auto area = mu0 .measure( b, R, f );
 
  275      const auto M    = muXY.measure( b, R, f );
 
  276      std::tie( K1[ f ], K2[ f ], D1[ f ], D2[ f ] )
 
  277        = cnc.principalCurvatures( area, M, N );
 
  282  auto exp_K1_min_max = std::minmax_element( exp_K1.cbegin(), exp_K1.cend() );
 
  283  auto exp_K2_min_max = std::minmax_element( exp_K2.cbegin(), exp_K2.cend() );
 
  284  auto K1_min_max = std::minmax_element( K1.cbegin(), K1.cend() );
 
  285  auto K2_min_max = std::minmax_element( K2.cbegin(), K2.cend() );
 
  286  std::cout << 
"Expected K1 curvatures:" 
  287            << 
" min=" << *exp_K1_min_max.first << 
" max=" << *exp_K1_min_max.second
 
  289  std::cout << 
"Computed k1 curvatures:" 
  290            << 
" min=" << *K1_min_max.first << 
" max=" << *K1_min_max.second
 
  292  std::cout << 
"Expected k2 curvatures:" 
  293            << 
" min=" << *exp_K2_min_max.first << 
" max=" << *exp_K2_min_max.second
 
  295  std::cout << 
"Computed k2 curvatures:" 
  296            << 
" min=" << *K2_min_max.first << 
" max=" << *K2_min_max.second
 
  298  const auto      error_K1 = SHG::getScalarsAbsoluteDifference( K1, exp_K1 );
 
  299  const auto stat_error_K1 = SHG::getStatistic( error_K1 );
 
  300  const auto   error_K1_l2 = SHG::getScalarsNormL2( K1, exp_K1 );
 
  301  trace.info() << 
"|K1-K1_CNC|_oo = " << stat_error_K1.max() << std::endl;
 
  302  trace.info() << 
"|K1-K1_CNC|_2  = " << error_K1_l2 << std::endl;
 
  303  const auto      error_K2 = SHG::getScalarsAbsoluteDifference( K2, exp_K2 );
 
  304  const auto stat_error_K2 = SHG::getStatistic( error_K2 );
 
  305  const auto   error_K2_l2 = SHG::getScalarsNormL2( K2, exp_K2 );
 
  306  trace.info() << 
"|K2-K2_CNC|_oo = " << stat_error_K2.max() << std::endl;
 
  307  trace.info() << 
"|K2-K2_CNC|_2  = " << error_K2_l2 << std::endl;
 
  312  smesh.vertexNormals() = SH::RealVectors();
 
  313  smesh.faceNormals()   = SH::RealVectors();
 
  315  const double    Kmax = std::max( fabs( *exp_K1_min_max.first ),
 
  316                                   fabs( *exp_K2_min_max.second ) );
 
  319  auto colorsK1 = SMW::Colors( smesh.nbFaces() );
 
  320  auto colorsK2 = SMW::Colors( smesh.nbFaces() );
 
  321  for ( 
auto i = 0; i < smesh.nbFaces(); i++ )
 
  323      colorsK1[ i ] = colormapK1( K1[ i ] );
 
  324      colorsK2[ i ] = colormapK2( K2[ i ] );
 
  326  SMW::writeOBJ( 
"example-cnc-K1", smesh, colorsK1 );
 
  327  SMW::writeOBJ( 
"example-cnc-K2", smesh, colorsK2 );
 
  328  const auto avg_e = smesh.averageEdgeLength();
 
  329  SH::RealPoints positions( smesh.nbFaces() );
 
  330  for ( 
auto f = 0; f < positions.size(); ++f )
 
  332      D1[ f ] *= smesh.localWindow( f );
 
  333      positions[ f ] = smesh.faceCentroid( f ) - 0.5 * D1[ f ];
 
  335  SH::saveVectorFieldOBJ( positions, D1, 0.05 * avg_e, SH::Colors(),
 
  337                          SH::Color::Black, SH::Color( 0, 128, 0 ) );
 
  338  for ( 
auto f = 0; f < positions.size(); ++f )
 
  340      D2[ f ] *= smesh.localWindow( f );
 
  341      positions[ f ] = smesh.faceCentroid( f ) - 0.5 * D2[ f ];
 
  343  SH::saveVectorFieldOBJ( positions, D2, 0.05 * avg_e, SH::Colors(),
 
  345                          SH::Color::Black, SH::Color(128, 0,128 ) );