44 #include <Cleaver/Cleaver.h>    45 #include <Cleaver/CleaverMesher.h>    46 #include <Cleaver/InverseField.h>    47 #include <Cleaver/SizingFieldCreator.h>    48 #include <Cleaver/Timer.h>    49 #include <NRRDTools.h>    51 #include <boost/program_options.hpp>    66 const std::string scirun = 
"scirun";
    67 const std::string tetgen = 
"tetgen";
    68 const std::string matlab = 
"matlab";
    69 const std::string vtkPoly = 
"vtkPoly";
    70 const std::string vtkUSG = 
"vtkUSG";
    71 const std::string ply = 
"ply";
    73 const std::string kDefaultOutputPath = 
"./";
    74 const std::string kDefaultOutputName = 
"output";
    75 const cleaver::MeshFormat kDefaultOutputFormat = cleaver::Tetgen;
    78 const double kDefaultAlpha = 0.4;
    79 const double kDefaultAlphaLong = 0.357;
    80 const double kDefaultAlphaShort = 0.203;
    81 const double kDefaultScale = 1.0;
    82 const double kDefaultLipschitz = 0.2;
    83 const double kDefaultMultiplier = 1.0;
    84 const int    kDefaultPadding = 0;
    85 const int    kDefaultMaxIterations = 1000;
    86 const double kDefaultSigma = 1.;
    88 namespace po = boost::program_options;
    91 int main(
int argc, 
char* argv[])
    94   bool fix_tets = 
false;
    95   bool segmentation = 
false;
    96   std::vector<std::string> material_fields;
    97   std::string sizing_field;
    98   std::string background_mesh;
    99   std::string output_path = kDefaultOutputPath;
   100   std::string output_name = kDefaultOutputName;
   101   double alpha = kDefaultAlpha;
   102   double alpha_long = kDefaultAlphaLong;
   103   double alpha_short = kDefaultAlphaShort;
   104   double lipschitz = kDefaultLipschitz;
   105   double multiplier = kDefaultMultiplier;
   106   double scaling = kDefaultScale;
   107   int padding = kDefaultPadding;
   108   bool have_sizing_field = 
false;
   109   bool have_background_mesh = 
false;
   110   bool write_background_mesh = 
false;
   112   bool strip_exterior = 
false;
   113   enum cleaver::MeshType mesh_mode = cleaver::Structured;
   114   cleaver::MeshFormat output_format = kDefaultOutputFormat;
   115   double sigma = kDefaultSigma;
   117   double sizing_field_time = 0;
   118   double   background_time = 0;
   119   double     cleaving_time = 0;
   126     po::options_description description(
"Command line flags");
   127     description.add_options()
   128       (
"help,h", 
"display help message")
   129       (
"verbose,v", 
"enable verbose output")
   130       (
"version,V", 
"display version information")
   131       (
"input_files,i", po::value<std::vector<std::string> >()->multitoken(), 
"material field paths or segmentation path")
   132       (
"background_mesh,b", po::value<std::string>(), 
"input background mesh")
   133       (
"mesh_mode,m", po::value<std::string>(), 
"background mesh mode (adaptive [default], constant)")
   134       (
"alpha,a", po::value<double>(), 
"initial alpha value")
   135       (
"alpha_short,s", po::value<double>(), 
"alpha short value for regular mesh_mode")
   136       (
"alpha_long,l", po::value<double>(), 
"alpha long value for regular mesh_mode")
   137       (
"sizing_field,z", po::value<std::string>(), 
"sizing field path")
   138       (
"grading,g", po::value<double>(), 
"sizing field grading")
   139       (
"scale,c", po::value<double>(), 
"sizing field scale factor")
   140       (
"multiplier,x", po::value<double>(), 
"sizing field multiplier")
   141       (
"padding,p", po::value<int>(), 
"volume padding")
   142       (
"write_background_mesh,w", 
"write background mesh")
   143       (
"fix_tet_windup,j", 
"Ensure positive Jacobians with proper vertex wind-up.")
   144       (
"strip_exterior,e", 
"strip exterior tetrahedra")
   145       (
"output_path,o", po::value<std::string>(), 
"output path prefix")
   146       (
"output_name,n", po::value<std::string>(), 
"output mesh name [default 'output']")
   147       (
"output_format,f", po::value<std::string>(), 
"output mesh format (tetgen [default], scirun, matlab, vtkUSG, vtkPoly, ply [Surface mesh only])")
   148       (
"strict,t", 
"warnings become errors")
   149       (
"segmentation,S", 
"The input file is a segmentation file.")
   150       (
"blend_sigma,B", po::value<double>(), 
"blending sigma for input(s) to remove alias artifacts.")
   153     boost::program_options::variables_map variables_map;
   154     boost::program_options::store(boost::program_options::parse_command_line(argc, argv, description), variables_map);
   155     boost::program_options::notify(variables_map);
   158     if (variables_map.count(
"help") || (argc == 1)) {
   159       std::cout << description << std::endl;
   164     if (variables_map.count(
"version")) {
   165       std::cout << cleaver::Version << std::endl;
   170     if (variables_map.count(
"verbose")) {
   175     if (variables_map.count(
"segmentation")) {
   178     if (variables_map.count(
"strict")) {
   183     if (variables_map.count(
"input_files")) {
   184       material_fields = variables_map[
"input_files"].as<std::vector<std::string> >();
   186       std::cerr << 
"Error: At least one material field file must be specified." << std::endl;
   194     if (variables_map.count(
"sizing_field")) {
   195       have_sizing_field = 
true;
   196       sizing_field = variables_map[
"sizing_field"].as<std::string>();
   198       if (variables_map.count(
"grading")) {
   200           std::cerr << 
"Warning: sizing field provided, grading will be ignored." << std::endl;
   202           std::cerr << 
"Error: both sizing field and grading parameter provided." << std::endl;
   206       if (variables_map.count(
"multiplier")) {
   208           std::cerr << 
"Warning: sizing field provided, multiplier will be ignored." << std::endl;
   210           std::cerr << 
"Error: both sizing field and multiplier parameter provided." << std::endl;
   214       if (variables_map.count(
"scale")) {
   216           std::cerr << 
"Warning: sizing field provided, scale will be ignored." << std::endl;
   218           std::cerr << 
"Error: both sizing field and scale parameter provided." << std::endl;
   225     if (variables_map.count(
"grading")) {
   226       lipschitz = variables_map[
"grading"].as<
double>();
   228     if (variables_map.count(
"scaling")) {
   229       scaling = variables_map[
"scaling"].as<
double>();
   231     if (variables_map.count(
"multiplier")) {
   232       multiplier = variables_map[
"multiplier"].as<
double>();
   234     if (variables_map.count(
"padding")) {
   235       padding = variables_map[
"padding"].as<
int>();
   237     fix_tets = variables_map.count(
"fix_tet_windup") == 0 ? 
false : 
true;
   239     if (variables_map.count(
"alpha")) {
   240       alpha = variables_map[
"alpha"].as<
double>();
   242     if (variables_map.count(
"alpha_short")) {
   243       alpha_short = variables_map[
"alpha_short"].as<
double>();
   245     if (variables_map.count(
"alpha_long")) {
   246       alpha_long = variables_map[
"alpha_long"].as<
double>();
   248     if (variables_map.count(
"blend_sigma")) {
   249       sigma = variables_map[
"blend_sigma"].as<
double>();
   252     if (variables_map.count(
"background_mesh")) {
   253       have_background_mesh = 
true;
   254       background_mesh = variables_map[
"background_mesh"].as<std::string>();
   256       if (variables_map.count(
"sizing_field")) {
   258           std::cerr << 
"Warning: background mesh provided, sizing field will be ignored." << std::endl;
   260           std::cerr << 
"Error: both background mesh and sizing field provided." << std::endl;
   268     if (variables_map.count(
"mesh_mode")) {
   269       std::string mesh_mode_string = variables_map[
"mesh_mode"].as<std::string>();
   270       if (mesh_mode_string.compare(
"adaptive") == 0) {
   271         mesh_mode = cleaver::Regular;
   272       } 
else if (mesh_mode_string.compare(
"constant") == 0) {
   273         mesh_mode = cleaver::Structured;
   275         std::cerr << 
"Error: invalid background mesh mode: " << mesh_mode_string << std::endl;
   276         std::cerr << 
"Valid Modes: [regular] [structured] " << std::endl;
   287     if (variables_map.count(
"strip_exterior")) {
   288       strip_exterior = 
true;
   292     if (variables_map.count(
"write_background_mesh")) {
   293       write_background_mesh = 
true;
   297     if (variables_map.count(
"output_format")) {
   298       std::string format_string = variables_map[
"output_format"].as<std::string>();
   299       if (format_string.compare(tetgen) == 0) {
   300         output_format = cleaver::Tetgen;
   301       } 
else if (format_string.compare(scirun) == 0) {
   302         output_format = cleaver::Scirun;
   303       } 
else if (format_string.compare(matlab) == 0) {
   304         output_format = cleaver::Matlab;
   305       } 
else if (format_string.compare(vtkPoly) == 0) {
   306         output_format = cleaver::VtkPoly;
   307       } 
else if (format_string.compare(vtkUSG) == 0) {
   308         output_format = cleaver::VtkUSG;
   309       } 
else if (format_string.compare(ply) == 0) {
   310         output_format = cleaver::PLY;
   312         std::cerr << 
"Error: unsupported output format: " << format_string << std::endl;
   318     if (variables_map.count(
"output_path")) {
   319       output_path = variables_map[
"output_path"].as<std::string>();
   323     if (variables_map.count(
"output_name")) {
   324       output_name = variables_map[
"output_name"].as<std::string>();
   327   } 
catch (std::exception& e) {
   328     std::cerr << 
"Error: " << e.what() << std::endl;
   331     std::cerr << 
"Unhandled exception caught. Terminating." << std::endl;
   340   bool add_inverse = 
false;
   341   std::vector<cleaver::AbstractScalarField*> fields;
   342   if (material_fields.empty()) {
   343     std::cerr << 
"No material fields or segmentation files provided. Terminating."   347   if (segmentation && material_fields.size() == 1) {
   348     NRRDTools::segmentationToIndicatorFunctions(material_fields[0], sigma);
   350     if (material_fields.size() > 1) {
   351       std::cerr << 
"WARNING: More than 1 input provided for segmentation." <<
   352         " This will be assumed to be indicator functions." << std::endl;
   354     if (material_fields.size() == 1) {
   358       std::cout << 
" Loading input fields:" << std::endl;
   359       for (
size_t i = 0; i < material_fields.size(); i++) {
   360         std::cout << 
" - " << material_fields[i] << std::endl;
   363     fields = NRRDTools::loadNRRDFiles(material_fields);
   364     if (fields.empty()) {
   365       std::cerr << 
"Failed to load image data. Terminating." << std::endl;
   367     } 
else if (add_inverse)
   372   mesher.setVolume(volume);
   373   mesher.setAlphaInit(alpha);
   379   if (have_background_mesh) {
   380     std::string nodeFileName = background_mesh + 
".node";
   381     std::string eleFileName = background_mesh + 
".ele";
   383       std::cout << 
"Loading background mesh: \n\t" << nodeFileName
   384         << 
"\n\t" << eleFileName << std::endl;
   386     bgMesh = cleaver::TetMesh::createFromNodeElePair(nodeFileName, eleFileName);
   387     mesher.setBackgroundMesh(bgMesh);
   397     std::vector<cleaver::AbstractScalarField *> sizingField;
   398     if (have_sizing_field) {
   399       std::cout << 
"Loading sizing field: " << sizing_field << std::endl;
   400       std::vector<std::string> tmp(1,sizing_field);
   401       sizingField = NRRDTools::loadNRRDFiles(tmp);
   405       sizing_field_timer.start();
   406       sizingField.push_back(cleaver::SizingFieldCreator::createSizingFieldFromVolume(
   408         (
float)(1.0 / lipschitz),
   412         (mesh_mode == cleaver::Regular ? 
false : 
true),
   414       sizing_field_timer.stop();
   415       sizing_field_time = sizing_field_timer.time();
   421     volume->setSizingField(sizingField[0]);
   428     background_timer.start();
   430       std::cout << 
"Creating Octree Mesh..." << std::endl;
   433     case cleaver::Regular:
   434       mesher.setAlphas(alpha_long, alpha_short);
   435       mesher.setRegular(
true);
   436       bgMesh = mesher.createBackgroundMesh(verbose);
   439     case cleaver::Structured:
   440       mesher.setRegular(
false);
   441       bgMesh = mesher.createBackgroundMesh(verbose);
   444     background_timer.stop();
   445     background_time = background_timer.time();
   446     mesher.setBackgroundTime(background_time);
   453   if (bgMesh && write_background_mesh) {
   454     bgMesh->writeNodeEle(output_path + 
"bgmesh", 
false, 
false, 
false);
   461   cleaving_timer.start();
   462   mesher.buildAdjacency(verbose);
   463   mesher.sampleVolume(verbose);
   464   mesher.computeAlphas(verbose);
   465   mesher.computeInterfaces(verbose);
   466   mesher.generalizeTets(verbose);
   467   mesher.snapsAndWarp(verbose);
   468   mesher.stencilTets(verbose);
   469   cleaving_timer.stop();
   470   cleaving_time = cleaving_timer.time();
   477   if (strip_exterior) {
   478     cleaver::stripExteriorTets(mesh, volume, verbose);
   484   mesh->computeAngles();
   488   if (fix_tets) mesh->fixVertexWindup(verbose);
   493   mesh->writeMesh(output_path + output_name, output_format, verbose);
   494   mesh->writeInfo(output_path + output_name, verbose);
   499   double total_time = total_timer.time();
   502     std::cout << 
"Output Info" << std::endl;
   503     std::cout << 
"Size: " << volume->size().toString() << std::endl;
   504     std::cout << 
"Materials: " << volume->numberOfMaterials() << std::endl;
   505     std::cout << 
"Min Dihedral: " << mesh->min_angle << std::endl;
   506     std::cout << 
"Max Dihedral: " << mesh->max_angle << std::endl;
   507     std::cout << 
"Total Time: " << total_time << 
" seconds" << std::endl;
   508     std::cout << 
"Sizing Field Time: " << sizing_field_time << 
" seconds" << std::endl;
   509     std::cout << 
"Backound Mesh Time: " << background_time << 
" seconds" << std::endl;
   510     std::cout << 
"Cleaving Time: " << cleaving_time << 
" seconds" << std::endl;