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;