|
| 1 | +#include <igl/readOBJ.h> |
| 2 | +#include <igl/writeOBJ.h> |
1 | 3 | #include "common.hh" |
2 | | -#include "implicit_optimization.hh" |
3 | 4 | #include "cone_metric.hh" |
4 | 5 | #include "energy_functor.hh" |
| 6 | +#include "implicit_optimization.hh" |
| 7 | +#include "io.hh" |
5 | 8 | #include "penner_optimization_interface.hh" |
6 | 9 | #include "refinement.hh" |
7 | | -#include "io.hh" |
8 | 10 | #include "vector.hh" |
9 | | -#include <igl/readOBJ.h> |
10 | | -#include <igl/writeOBJ.h> |
| 11 | +#include "viewers.hh" |
| 12 | + |
| 13 | +#include <CLI/CLI.hpp> |
| 14 | + |
11 | 15 | using namespace CurvatureMetric; |
12 | 16 |
|
13 | | -int main(int argc, char *argv[]) |
| 17 | +int main(int argc, char* argv[]) |
14 | 18 | { |
15 | 19 | #ifdef MULTIPRECISION |
16 | | - spdlog::info("Using multiprecision"); |
17 | | - mpfr::mpreal::set_default_prec(100); |
18 | | - mpfr::mpreal::set_emax(mpfr::mpreal::get_emax_max()); |
19 | | - mpfr::mpreal::set_emin(mpfr::mpreal::get_emin_min()); |
| 20 | + spdlog::info("Using multiprecision"); |
| 21 | + mpfr::mpreal::set_default_prec(100); |
| 22 | + mpfr::mpreal::set_emax(mpfr::mpreal::get_emax_max()); |
| 23 | + mpfr::mpreal::set_emin(mpfr::mpreal::get_emin_min()); |
20 | 24 | #endif |
21 | 25 |
|
22 | | - spdlog::set_level(spdlog::level::info); |
23 | | - assert(argc > 3); |
24 | | - std::string input_filename = argv[1]; |
25 | | - std::string Th_hat_filename = argv[2]; |
26 | | - std::string output_dir = argv[3]; |
27 | | - std::filesystem::create_directories(output_dir); |
28 | | - |
29 | | - // Get input mesh |
30 | | - Eigen::MatrixXd V, uv, N; |
31 | | - Eigen::MatrixXi F, FT, FN; |
32 | | - spdlog::info("Optimizing mesh at {}", input_filename); |
33 | | - igl::readOBJ(input_filename, V, uv, N, F, FT, FN); |
34 | | - |
35 | | - // Get input angles |
36 | | - std::vector<Scalar> Th_hat_init; |
37 | | - spdlog::info("Using cone angles at {}", Th_hat_filename); |
38 | | - read_vector_from_file(Th_hat_filename, Th_hat_init); |
39 | | - std::vector<Scalar> Th_hat = correct_cone_angles(Th_hat_init); |
40 | | - |
41 | | - // Get initial mesh for optimization |
42 | | - std::vector<int> vtx_reindex; |
43 | | - std::vector<int> free_cones = {}; |
44 | | - bool fix_boundary = false; |
45 | | - std::unique_ptr<DifferentiableConeMetric> cone_metric = generate_initial_mesh(V, F, V, F, Th_hat, vtx_reindex, free_cones, fix_boundary, false); |
46 | | - std::unique_ptr<DifferentiableConeMetric> eucl_cone_metric = generate_initial_mesh(V, F, V, F, Th_hat, vtx_reindex, free_cones, fix_boundary, true); |
47 | | - DiscreteMetric discrete_metric(*eucl_cone_metric, eucl_cone_metric->get_metric_coordinates()); |
48 | | - |
49 | | - // Get energy |
50 | | - QuadraticSymmetricDirichletEnergy opt_energy(*cone_metric, discrete_metric); |
51 | | - |
52 | | - // Get initial metric from file or target |
53 | | - VectorX reduced_metric_init; |
54 | | - if (argc > 4) |
55 | | - { |
56 | | - std::string metric_filename = argv[4]; |
57 | | - std::vector<Scalar> reduced_metric_init_vec; |
58 | | - read_vector_from_file(metric_filename, reduced_metric_init_vec); |
59 | | - convert_std_to_eigen_vector(reduced_metric_init_vec, reduced_metric_init); |
60 | | - cone_metric->set_metric_coordinates(reduced_metric_init); |
61 | | - } |
62 | | - |
63 | | - // Set all cones as dof |
64 | | - //std::vector<int> cone_vertices; |
65 | | - //compute_cone_vertices(m, cone_vertices); |
66 | | - //std::vector<bool> is_cone_vertex; |
67 | | - //convert_index_vector_to_boolean_array(cone_vertices, m.n_vertices(), is_cone_vertex); |
68 | | - //m.fixed_dof = is_cone_vertex; |
69 | | - |
70 | | - // Make default parameters with specified output directory |
71 | | - auto proj_params = std::make_shared<ProjectionParameters>(); |
72 | | - auto opt_params = std::make_shared<OptimizationParameters>(); |
73 | | - opt_params->output_dir = output_dir; |
74 | | - |
75 | | - // Optimize the metric |
76 | | - std::unique_ptr<DifferentiableConeMetric> optimized_cone_metric = optimize_metric( |
77 | | - *cone_metric, |
78 | | - opt_energy, |
79 | | - proj_params, |
80 | | - opt_params); |
81 | | - VectorX optimized_metric_coords = optimized_cone_metric->get_metric_coordinates(); |
82 | | - |
83 | | - // Write the output |
84 | | - std::string output_filename = join_path(output_dir, "optimized_metric_coords"); |
85 | | - write_vector(optimized_metric_coords, output_filename, 17); |
86 | | - |
87 | | - // Generate overlay VF mesh with parametrization |
88 | | - std::vector<bool> is_cut = {}; |
89 | | - bool do_best_fit_scaling = false; |
90 | | - auto vf_res = generate_VF_mesh_from_metric( |
91 | | - V, |
92 | | - F, |
93 | | - Th_hat, |
94 | | - *cone_metric, |
95 | | - optimized_metric_coords, |
96 | | - is_cut, |
97 | | - do_best_fit_scaling |
98 | | - ); |
99 | | - OverlayMesh<Scalar> m_o = std::get<0>(vf_res); |
100 | | - Eigen::MatrixXd V_o = std::get<1>(vf_res); |
101 | | - Eigen::MatrixXi F_o = std::get<2>(vf_res); |
102 | | - Eigen::MatrixXd uv_o = std::get<3>(vf_res); |
103 | | - Eigen::MatrixXi FT_o = std::get<4>(vf_res); |
104 | | - std::vector<int> fn_to_f_o = std::get<7>(vf_res); |
105 | | - std::vector<std::pair<int,int>> endpoints_o = std::get<8>(vf_res); |
106 | | - |
107 | | - // Write the overlay output |
108 | | - output_filename = join_path(output_dir, "overlay_mesh_with_uv.obj"); |
109 | | - write_obj_with_uv(output_filename, V_o, F_o, uv_o, FT_o); |
110 | | - |
111 | | - // Get refinement mesh |
112 | | - // Build mesh |
113 | | - Eigen::MatrixXd V_r; |
114 | | - Eigen::MatrixXi F_r; |
115 | | - Eigen::MatrixXd uv_r; |
116 | | - Eigen::MatrixXi FT_r; |
117 | | - std::vector<int> fn_to_f_r; |
118 | | - std::vector<std::pair<int,int>> endpoints_r; |
119 | | - RefinementMesh refinement_mesh(V_o, F_o, uv_o, FT_o, fn_to_f_o, endpoints_o); |
120 | | - refinement_mesh.get_VF_mesh(V_r, F_r, uv_r, FT_r, fn_to_f_r, endpoints_r); |
121 | | - |
122 | | - // Write the refined output |
123 | | - output_filename = join_path(output_dir, "refined_mesh_with_uv.obj"); |
124 | | - write_obj_with_uv(output_filename, V_r, F_r, uv_r, FT_r); |
125 | | -} |
| 26 | + // Build maps from strings to enums |
| 27 | + std::map<std::string, EnergyChoice> energy_choice_map{ |
| 28 | + {"log_length", EnergyChoice::log_length}, |
| 29 | + {"log_scale", EnergyChoice::log_scale}, |
| 30 | + {"quadratic_sym_dirichlet", EnergyChoice::quadratic_sym_dirichlet}, |
| 31 | + {"sym_dirichlet", EnergyChoice::sym_dirichlet}, |
| 32 | + {"p_norm", EnergyChoice::p_norm}, |
| 33 | + }; |
| 34 | + |
| 35 | + // Get command line arguments |
| 36 | + CLI::App app{"Generate approximately isometric parameterization for a mesh."}; |
| 37 | + std::string mesh_filename = ""; |
| 38 | + std::string Th_hat_filename = ""; |
| 39 | + std::string output_dir = "./"; |
| 40 | + EnergyChoice energy_choice = EnergyChoice::log_length; |
| 41 | + bool use_discrete_metric = false; |
| 42 | + bool show_parameterization = false; |
| 43 | + auto proj_params = std::make_shared<ProjectionParameters>(); |
| 44 | + auto opt_params = std::make_shared<OptimizationParameters>(); |
| 45 | + app.add_option("--mesh", mesh_filename, "Mesh filepath")->check(CLI::ExistingFile)->required(); |
| 46 | + app.add_option("--cones", Th_hat_filename, "Cone angle filepath") |
| 47 | + ->check(CLI::ExistingFile) |
| 48 | + ->required(); |
| 49 | + app.add_option("--energy", energy_choice, "Energy to minimize") |
| 50 | + ->transform(CLI::CheckedTransformer(energy_choice_map, CLI::ignore_case)); |
| 51 | + app.add_option("--direction", opt_params->direction_choice, "Descent direction: projected_gradient, projected_newton"); |
| 52 | + app.add_option( |
| 53 | + "--num_iter", |
| 54 | + opt_params->num_iter, |
| 55 | + "Maximum number of iterations to perform") |
| 56 | + ->check(CLI::NonNegativeNumber); |
| 57 | + app.add_flag("--use_discrete_metric", use_discrete_metric, "Use edge lengths instead of Penner coordinates"); |
| 58 | + app.add_flag("--show_parameterization", show_parameterization, "Show final parameterization"); |
| 59 | + app.add_option("-o,--output", output_dir, "Output directory"); |
| 60 | + CLI11_PARSE(app, argc, argv); |
| 61 | + |
| 62 | + spdlog::set_level(spdlog::level::info); |
| 63 | + std::filesystem::create_directories(output_dir); |
| 64 | + opt_params->output_dir = output_dir; |
| 65 | + |
| 66 | + // TODO Make this automatic |
| 67 | + if (use_discrete_metric) |
| 68 | + { |
| 69 | + proj_params->initial_ptolemy = false; |
| 70 | + proj_params->use_edge_flips = false; |
| 71 | + proj_params->max_itr = 30; |
| 72 | + } |
126 | 73 |
|
| 74 | + // Get input mesh |
| 75 | + Eigen::MatrixXd V, uv, N; |
| 76 | + Eigen::MatrixXi F, FT, FN; |
| 77 | + spdlog::info("Optimizing mesh at {}", mesh_filename); |
| 78 | + igl::readOBJ(mesh_filename, V, uv, N, F, FT, FN); |
| 79 | + |
| 80 | + // Get input angles |
| 81 | + std::vector<Scalar> Th_hat_init; |
| 82 | + spdlog::info("Using cone angles at {}", Th_hat_filename); |
| 83 | + read_vector_from_file(Th_hat_filename, Th_hat_init); |
| 84 | + std::vector<Scalar> Th_hat = correct_cone_angles(Th_hat_init); |
| 85 | + |
| 86 | + // Get initial mesh for optimization |
| 87 | + std::vector<int> vtx_reindex; |
| 88 | + std::vector<int> free_cones = {}; |
| 89 | + bool fix_boundary = false; |
| 90 | + std::unique_ptr<DifferentiableConeMetric> cone_metric = |
| 91 | + generate_initial_mesh(V, F, V, F, Th_hat, vtx_reindex, free_cones, fix_boundary, use_discrete_metric); |
| 92 | + |
| 93 | + // Get energy |
| 94 | + std::unique_ptr<EnergyFunctor> opt_energy = generate_energy(V, F, Th_hat, *cone_metric, energy_choice); |
| 95 | + |
| 96 | + // Optimize the metric |
| 97 | + std::unique_ptr<DifferentiableConeMetric> optimized_cone_metric = |
| 98 | + optimize_metric(*cone_metric, *opt_energy, proj_params, opt_params); |
| 99 | + VectorX optimized_metric_coords = optimized_cone_metric->get_reduced_metric_coordinates(); |
| 100 | + |
| 101 | + // Write the output metric coordinates |
| 102 | + std::string output_filename = join_path(output_dir, "optimized_metric_coords"); |
| 103 | + write_vector(optimized_metric_coords, output_filename, 17); |
| 104 | + |
| 105 | + // Generate overlay VF mesh with parametrization |
| 106 | + if (use_discrete_metric) { |
| 107 | + auto vf_res = generate_VF_mesh_from_discrete_metric( |
| 108 | + V, |
| 109 | + F, |
| 110 | + Th_hat, |
| 111 | + optimized_metric_coords); |
| 112 | + Eigen::MatrixXd V_l = std::get<0>(vf_res); |
| 113 | + Eigen::MatrixXi F_l = std::get<1>(vf_res); |
| 114 | + Eigen::MatrixXd uv_l = std::get<2>(vf_res); |
| 115 | + Eigen::MatrixXi FT_l = std::get<3>(vf_res); |
| 116 | + |
| 117 | + // Write the overlay output |
| 118 | + output_filename = join_path(output_dir, "mesh_with_uv.obj"); |
| 119 | + write_obj_with_uv(output_filename, V_l, F_l, uv_l, FT_l); |
| 120 | + |
| 121 | + // Optionally show final parameterization |
| 122 | + if (show_parameterization) view_parameterization(V_l, F_l, uv_l, FT_l); |
| 123 | + } else { |
| 124 | + std::vector<bool> is_cut = {}; |
| 125 | + bool do_best_fit_scaling = false; |
| 126 | + auto vf_res = generate_VF_mesh_from_metric( |
| 127 | + V, |
| 128 | + F, |
| 129 | + Th_hat, |
| 130 | + *cone_metric, |
| 131 | + optimized_metric_coords, |
| 132 | + is_cut, |
| 133 | + do_best_fit_scaling); |
| 134 | + OverlayMesh<Scalar> m_o = std::get<0>(vf_res); |
| 135 | + Eigen::MatrixXd V_o = std::get<1>(vf_res); |
| 136 | + Eigen::MatrixXi F_o = std::get<2>(vf_res); |
| 137 | + Eigen::MatrixXd uv_o = std::get<3>(vf_res); |
| 138 | + Eigen::MatrixXi FT_o = std::get<4>(vf_res); |
| 139 | + std::vector<int> fn_to_f_o = std::get<7>(vf_res); |
| 140 | + std::vector<std::pair<int, int>> endpoints_o = std::get<8>(vf_res); |
| 141 | + |
| 142 | + // Write the overlay output |
| 143 | + output_filename = join_path(output_dir, "overlay_mesh_with_uv.obj"); |
| 144 | + write_obj_with_uv(output_filename, V_o, F_o, uv_o, FT_o); |
| 145 | + |
| 146 | + // Get refinement mesh |
| 147 | + Eigen::MatrixXd V_r; |
| 148 | + Eigen::MatrixXi F_r; |
| 149 | + Eigen::MatrixXd uv_r; |
| 150 | + Eigen::MatrixXi FT_r; |
| 151 | + std::vector<int> fn_to_f_r; |
| 152 | + std::vector<std::pair<int, int>> endpoints_r; |
| 153 | + RefinementMesh refinement_mesh(V_o, F_o, uv_o, FT_o, fn_to_f_o, endpoints_o); |
| 154 | + refinement_mesh.get_VF_mesh(V_r, F_r, uv_r, FT_r, fn_to_f_r, endpoints_r); |
| 155 | + |
| 156 | + // Write the refined output |
| 157 | + output_filename = join_path(output_dir, "refined_mesh_with_uv.obj"); |
| 158 | + write_obj_with_uv(output_filename, V_r, F_r, uv_r, FT_r); |
| 159 | + |
| 160 | + // Optionally show final parameterization |
| 161 | + if (show_parameterization) view_parameterization(V_r, F_r, uv_r, FT_r); |
| 162 | + } |
| 163 | +} |
0 commit comments