22#include " MRMesh/MRMeshLoad.h"
33#include " MRMesh/MRMeshSave.h"
44#include " MREAlgorithms/MREMeshDecimate.h"
5+ #include " MREAlgorithms/MREMeshBoolean.h"
56#include < boost/program_options.hpp>
67#include < boost/exception/diagnostic_information.hpp>
78#include < iostream>
89
10+ bool doCommand ( const boost::program_options::option& option, MR::Mesh& mesh )
11+ {
12+ namespace po = boost::program_options;
13+ if ( option.string_key == " remesh" )
14+ {
15+ float targetEdgeLen{ 0 .f };
16+ if ( !option.value .empty () )
17+ targetEdgeLen = std::stof ( option.value [0 ] );
18+ if ( targetEdgeLen <= 0 )
19+ targetEdgeLen = mesh.averageEdgeLength ();
20+
21+ MRE::RemeshSettings rems;
22+ rems.targetEdgeLen = targetEdgeLen;
23+ rems.maxDeviation = targetEdgeLen / 100 ;
24+ MRE::remesh ( mesh, rems );
25+
26+ std::cout << " re-meshed successfully to target edge length " << targetEdgeLen << " \n " ;
27+ }
28+ else if ( option.string_key == " unite" || option.string_key == " subtract" || option.string_key == " intersect" )
29+ {
30+ std::filesystem::path meshPath = option.value [0 ];
31+
32+ auto loadRes = MR::MeshLoad::fromAnySupportedFormat ( meshPath );
33+ if ( !loadRes.has_value () )
34+ {
35+ std::cerr << " Mesh load error: " << loadRes.error () << " \n " ;
36+ return false ;
37+ }
38+ auto meshB = std::move ( loadRes.value () );
39+ std::cout << meshPath << " loaded successfully\n " ;
40+
41+ MRE::BooleanOperation bo{ MRE::BooleanOperation::Union };
42+ if ( option.string_key == " subtract" )
43+ bo = MRE::BooleanOperation::OutsideA;
44+ if ( option.string_key == " intersect" )
45+ bo = MRE::BooleanOperation::Intersection;
46+ auto booleanRes = MRE::boolean ( mesh, meshB, bo );
47+
48+ if ( !booleanRes )
49+ {
50+ std::cerr << booleanRes.errorString << " \n " ;
51+ return false ;
52+ }
53+ else
54+ {
55+ std::cout << option.string_key << " success!\n " ;
56+ mesh = std::move ( booleanRes.mesh );
57+ }
58+ }
59+ return true ;
60+ }
61+
962// can throw
1063static int mainInternal ( int argc, char **argv )
1164{
1265 std::filesystem::path inFilePath;
1366 std::filesystem::path outFilePath;
14- float targetEdgeLen = 0 ;
1567
1668 namespace po = boost::program_options;
17- po::options_description desc ( " Available options" );
18- desc .add_options ()
69+ po::options_description generalOptions ( " General options" );
70+ generalOptions .add_options ()
1971 (" help" , " produce help message" )
2072 (" input-file" , po::value<std::filesystem::path>( &inFilePath ), " filename of input mesh" )
2173 (" output-file" , po::value<std::filesystem::path>( &outFilePath ), " filename of output mesh" )
22- (" remesh" , po::value<float >( &targetEdgeLen )->implicit_value ( targetEdgeLen ), " optional argument if positive is target edge length after remeshing" )
2374 ;
2475
76+ po::options_description commands ( " Commands" );
77+ commands.add_options ()
78+ ( " remesh" , po::value<float >()->implicit_value ( 0 ), " optional argument if positive is target edge length after remeshing" )
79+ ( " unite" , po::value<std::filesystem::path>(), " unite mesh from input file and given mesh" )
80+ ( " subtract" , po::value<std::filesystem::path>(), " subtract given mesh from input file mesh given mesh" )
81+ ( " intersect" , po::value<std::filesystem::path>(), " intersect mesh from input file and given mesh" )
82+ ;
83+
84+ po::options_description allCommands ( " Available options" );
85+ allCommands.add ( generalOptions ).add ( commands );
86+
2587 po::positional_options_description p;
2688 p.add (" input-file" , 1 );
2789 p.add (" output-file" , 1 );
2890
91+ po::parsed_options parsedGeneral = po::command_line_parser ( argc, argv )
92+ .options ( generalOptions )
93+ .positional ( p )
94+ .allow_unregistered ()
95+ .run ();
96+
97+ std::vector<std::string> unregisteredOptions;
98+ for ( const auto & o : parsedGeneral.options )
99+ {
100+ if ( o.unregistered )
101+ unregisteredOptions.insert ( unregisteredOptions.end (), o.original_tokens .begin (), o.original_tokens .end () );
102+ }
103+
29104 po::variables_map vm;
30- po::store (po::command_line_parser (argc, argv). options (desc). positional (p). run () , vm);
105+ po::store (parsedGeneral , vm);
31106 po::notify (vm);
32107
108+ po::parsed_options parsedCommands = po::command_line_parser ( unregisteredOptions )
109+ .options ( commands )
110+ .allow_unregistered ()
111+ .run ();
112+
33113 if ( vm.count (" help" ) || !vm.count (" input-file" ) || !vm.count (" output-file" ) )
34114 {
35115 std::cerr <<
36116 " meshconv is mesh file conversion utility based on MeshInspector/MeshLib\n "
37117 " Usage: meshconv input-file output-file [options]\n "
38- << desc << " \n " ;
118+ << allCommands << " \n " ;
39119 return 1 ;
40120 }
41121
@@ -48,19 +128,17 @@ static int mainInternal( int argc, char **argv )
48128 auto mesh = std::move ( loadRes.value () );
49129 std::cout << inFilePath << " loaded successfully\n " ;
50130
51- if ( vm.count (" remesh" ) )
131+ std::vector<std::vector<std::string>> lists;
132+ for ( const po::option& o : parsedCommands.options )
52133 {
53- if ( targetEdgeLen <= 0 )
54- targetEdgeLen = mesh.averageEdgeLength ();
55-
56- MRE::RemeshSettings rems;
57- rems.targetEdgeLen = targetEdgeLen;
58- rems.maxDeviation = targetEdgeLen / 100 ;
59- MRE::remesh ( mesh, rems );
60-
61- std::cout << " re-meshed successfully to target edge length " << targetEdgeLen << " \n " ;
134+ if ( !doCommand ( o, mesh ) )
135+ {
136+ std::cerr << " Error in command : \" " << o.string_key << " " << o.value [0 ] << " \"\n Break\n " ;
137+ return 1 ;
138+ }
62139 }
63140
141+
64142 auto saveRes = MR::MeshSave::toAnySupportedFormat ( mesh, outFilePath );
65143 if ( !saveRes.has_value () )
66144 {
0 commit comments