12#include <geogram/basic/attributes.h>
13#include <geogram/mesh/mesh.h>
14#include <geogram/mesh/mesh_io.h>
15#include <mmg/libmmg.h>
25typedef unsigned int uint;
32 void to_geogram_mesh(
const Eigen::MatrixXd &
V,
const Eigen::MatrixXi &
F, GEO::Mesh &M)
36 M.vertices.create_vertices((
int)
V.rows());
37 for (
int i = 0; i < (int)
M.vertices.nb(); ++i)
39 GEO::vec3 &p =
M.vertices.point(i);
42 p[2] = (
V.cols() == 2 ? 0 :
V(i, 2));
47 M.facets.create_triangles((
int)
F.rows());
49 else if (
F.cols() == 4)
51 M.facets.create_quads((
int)
F.rows());
55 throw std::runtime_error(
"Mesh faces not supported");
57 for (
int c = 0; c < (int)
M.facets.nb(); ++c)
59 for (
int lv = 0; lv <
F.cols(); ++lv)
61 M.facets.set_vertex(c, lv,
F(c, lv));
67 void to_geogram_mesh(
const Eigen::MatrixXd &
V,
const Eigen::MatrixXi &
F,
const Eigen::MatrixXi &T, GEO::Mesh &M)
72 M.cells.create_tets((
int)
T.rows());
74 else if (
T.rows() != 0)
76 throw std::runtime_error(
"Mesh cells not supported");
78 for (
int c = 0; c < (int)
M.cells.nb(); ++c)
80 for (
int lv = 0; lv <
T.cols(); ++lv)
82 M.cells.set_vertex(c, lv,
T(c, lv));
88 void from_geogram_mesh(
const GEO::Mesh &M, Eigen::MatrixXd &
V, Eigen::MatrixXi &
F, Eigen::MatrixXi &T)
90 V.resize(
M.vertices.nb(), 3);
91 for (
int i = 0; i < (int)
M.vertices.nb(); ++i)
93 GEO::vec3 p =
M.vertices.point(i);
94 V.row(i) << p[0], p[1], p[2];
96 assert(
M.facets.are_simplices());
97 F.resize(
M.facets.nb(), 3);
98 for (
int c = 0; c < (int)
M.facets.nb(); ++c)
100 for (
int lv = 0; lv < 3; ++lv)
102 F(c, lv) =
M.facets.vertex(c, lv);
105 assert(
M.cells.are_simplices());
106 T.resize(
M.cells.nb(), 4);
107 for (
int c = 0; c < (int)
M.cells.nb(); ++c)
109 for (
int lv = 0; lv < 4; ++lv)
111 T(c, lv) =
M.cells.vertex(c, lv);
116 bool mmg_to_geo(
const MMG5_pMesh mmg, GEO::Mesh &M)
118 logger().trace(
"converting MMG5_pMesh to GEO::Mesh ...");
122 assert(mmg->dim == 3);
124 M.vertices.create_vertices((uint)mmg->np);
125 M.edges.create_edges((uint)mmg->na);
126 M.facets.create_triangles((uint)mmg->nt);
127 M.cells.create_tets((uint)mmg->ne);
129 for (uint v = 0; v <
M.vertices.nb(); ++v)
131 for (uint d = 0; d < (uint)mmg->dim; ++d)
133 M.vertices.point_ptr(v)[d] = mmg->point[v + 1].c[d];
136 for (uint e = 0;
e <
M.edges.nb(); ++
e)
138 M.edges.set_vertex(e, 0, (uint)mmg->edge[
e + 1].a - 1);
139 M.edges.set_vertex(e, 1, (uint)mmg->edge[
e + 1].b - 1);
141 for (uint t = 0; t <
M.facets.nb(); ++t)
143 M.facets.set_vertex(t, 0, (uint)mmg->tria[t + 1].v[0] - 1);
144 M.facets.set_vertex(t, 1, (uint)mmg->tria[t + 1].v[1] - 1);
145 M.facets.set_vertex(t, 2, (uint)mmg->tria[t + 1].v[2] - 1);
147 for (uint c = 0; c <
M.cells.nb(); ++c)
149 M.cells.set_vertex(c, 0, (uint)mmg->tetra[c + 1].v[0] - 1);
150 M.cells.set_vertex(c, 1, (uint)mmg->tetra[c + 1].v[1] - 1);
151 M.cells.set_vertex(c, 2, (uint)mmg->tetra[c + 1].v[2] - 1);
152 M.cells.set_vertex(c, 3, (uint)mmg->tetra[c + 1].v[3] - 1);
160 bool geo_to_mmg(
const GEO::Mesh &M, MMG5_pMesh &mmg, MMG5_pSol &sol,
bool volume_mesh =
true)
162 logger().trace(
"converting GEO::M to MMG5_pMesh ...");
163 assert(
M.vertices.dimension() == 3);
164 if (
M.facets.nb() > 0)
165 assert(
M.facets.are_simplices());
166 if (
M.cells.nb() > 0)
167 assert(
M.cells.are_simplices());
171 MMG3D_Init_mesh(MMG5_ARG_start, MMG5_ARG_ppMesh, &mmg, MMG5_ARG_ppMet, &sol, MMG5_ARG_end);
175 MMGS_Init_mesh(MMG5_ARG_start, MMG5_ARG_ppMesh, &mmg, MMG5_ARG_ppMet, &sol, MMG5_ARG_end);
178 if (volume_mesh && MMG3D_Set_meshSize(mmg, (
int)
M.vertices.nb(), (
int)
M.cells.nb(), 0,
179 (
int)
M.facets.nb(), 0,
184 logger().error(
"failed to MMG3D_Set_meshSize");
187 else if (!volume_mesh && MMGS_Set_meshSize(mmg, (
int)
M.vertices.nb(), (
int)
M.facets.nb(), (
int)
M.edges.nb()
191 logger().error(
"failed to MMGS_Set_meshSize");
195 for (uint v = 0; v < (uint)mmg->np; ++v)
197 for (uint d = 0; d <
M.vertices.dimension(); ++d)
199 mmg->point[v + 1].c[d] =
M.vertices.point_ptr(v)[d];
202 for (uint e = 0;
e < (uint)mmg->na; ++
e)
204 mmg->edge[
e + 1].a = (int)
M.edges.vertex(e, 0) + 1;
205 mmg->edge[
e + 1].b = (int)
M.edges.vertex(e, 1) + 1;
207 for (uint t = 0; t < (uint)mmg->nt; ++t)
209 mmg->tria[t + 1].v[0] = (int)
M.facets.vertex(t, 0) + 1;
210 mmg->tria[t + 1].v[1] = (int)
M.facets.vertex(t, 1) + 1;
211 mmg->tria[t + 1].v[2] = (int)
M.facets.vertex(t, 2) + 1;
215 for (uint c = 0; c < (uint)mmg->ne; ++c)
217 mmg->tetra[c + 1].v[0] = (int)
M.cells.vertex(c, 0) + 1;
218 mmg->tetra[c + 1].v[1] = (int)
M.cells.vertex(c, 1) + 1;
219 mmg->tetra[c + 1].v[2] = (int)
M.cells.vertex(c, 2) + 1;
220 mmg->tetra[c + 1].v[3] = (int)
M.cells.vertex(c, 3) + 1;
224 if (volume_mesh && MMG3D_Set_solSize(mmg, sol, MMG5_Vertex, (
int)
M.vertices.nb(), MMG5_Scalar) != 1)
226 logger().error(
"failed to MMG3D_Set_solSize");
229 else if (!volume_mesh && MMGS_Set_solSize(mmg, sol, MMG5_Vertex, (
int)
M.vertices.nb(), MMG5_Scalar) != 1)
231 logger().error(
"failed to MMGS_Set_solSize");
234 for (uint v = 0; v <
M.vertices.nb(); ++v)
238 if (volume_mesh && MMG3D_Chk_meshData(mmg, sol) != 1)
240 logger().error(
"error in mmg: inconsistent mesh and sol");
243 else if (!volume_mesh && MMGS_Chk_meshData(mmg, sol) != 1)
245 logger().error(
"error in mmg: inconsistent mesh and sol");
251 MMG3D_Set_handGivenMesh(mmg);
257 void mmg2d_free(MMG5_pMesh mmg, MMG5_pSol sol)
259 MMG2D_Free_all(MMG5_ARG_start,
260 MMG5_ARG_ppMesh, &mmg, MMG5_ARG_ppMet, &sol, MMG5_ARG_end);
263 void mmg3d_free(MMG5_pMesh mmg, MMG5_pSol sol)
265 MMG3D_Free_all(MMG5_ARG_start,
266 MMG5_ARG_ppMesh, &mmg, MMG5_ARG_ppMet, &sol, MMG5_ARG_end);
269 void mmgs_free(MMG5_pMesh mmg, MMG5_pSol sol)
271 MMGS_Free_all(MMG5_ARG_start,
272 MMG5_ARG_ppMesh, &mmg, MMG5_ARG_ppMet, &sol, MMG5_ARG_end);
275 bool mmg_wrapper_test_geo2mmg2geo(
const GEO::Mesh &M_in, GEO::Mesh &M_out)
277 MMG5_pMesh mmg =
nullptr;
278 MMG5_pSol sol =
nullptr;
279 bool ok = geo_to_mmg(M_in, mmg, sol);
282 ok = mmg_to_geo(mmg, M_out);
283 mmg3d_free(mmg, sol);
287 bool mmg2d_tri_remesh(
const GEO::Mesh &M, GEO::Mesh &M_out,
const MmgOptions &opt)
289 MMG5_pMesh mesh =
nullptr;
290 MMG5_pSol met =
nullptr;
291 bool ok = geo_to_mmg(M, mesh, met,
false);
294 logger().error(
"mmg2d_remesh: failed to convert mesh to MMG5_pMesh");
295 mmg2d_free(mesh, met);
300 MMG2D_Set_dparameter(mesh, met, MMG2D_DPARAM_angleDetection, opt.angle_value);
301 if (opt.enable_anisotropy)
303 MMG2D_Set_solSize(mesh, met, MMG5_Vertex, 0, MMG5_Tensor);
305 if (opt.hsiz == 0. || opt.metric_attribute !=
"no_metric")
307 MMG2D_Set_dparameter(mesh, met, MMG2D_DPARAM_hmin, opt.hmin);
308 MMG2D_Set_dparameter(mesh, met, MMG2D_DPARAM_hmax, opt.hmax);
313 MMG2D_Set_dparameter(mesh, met, MMG2D_DPARAM_hsiz, opt.hsiz);
315 MMG2D_Set_dparameter(mesh, met, MMG2D_DPARAM_hausd, opt.hausd);
316 MMG2D_Set_dparameter(mesh, met, MMG2D_DPARAM_hgrad, opt.hgrad);
317 MMG2D_Set_iparameter(mesh, met, MMG2D_IPARAM_angle,
int(opt.angle_detection));
318 MMG2D_Set_iparameter(mesh, met, MMG2D_IPARAM_noswap,
int(opt.noswap));
319 MMG2D_Set_iparameter(mesh, met, MMG2D_IPARAM_noinsert,
int(opt.noinsert));
320 MMG2D_Set_iparameter(mesh, met, MMG2D_IPARAM_nomove,
int(opt.nomove));
321 MMG2D_Set_iparameter(mesh, met, MMG2D_IPARAM_nosurf,
int(opt.nosurf));
322 if (opt.metric_attribute !=
"no_metric")
324 if (!
M.vertices.attributes().is_defined(opt.metric_attribute))
326 logger().error(
"mmg2D_remesh: {} is not a vertex attribute, cancel", opt.metric_attribute);
329 GEO::Attribute<double> h_local(
M.vertices.attributes(), opt.metric_attribute);
330 for (uint v = 0; v <
M.vertices.nb(); ++v)
332 met->m[v + 1] = h_local[v];
336 int ier = MMG2D_mmg2dlib(mesh, met);
337 if (ier != MMG5_SUCCESS)
339 logger().error(
"mmg2d_remesh: failed to remesh");
340 mmg2d_free(mesh, met);
344 ok = mmg_to_geo(mesh, M_out);
346 mmg2d_free(mesh, met);
350 bool mmgs_tri_remesh(
const GEO::Mesh &M, GEO::Mesh &M_out,
const MmgOptions &opt)
352 MMG5_pMesh mesh =
nullptr;
353 MMG5_pSol met =
nullptr;
354 bool ok = geo_to_mmg(M, mesh, met,
false);
357 logger().error(
"mmgs_remesh: failed to convert mesh to MMG5_pMesh");
358 mmgs_free(mesh, met);
363 MMGS_Set_dparameter(mesh, met, MMGS_DPARAM_angleDetection, opt.angle_value);
364 if (opt.enable_anisotropy)
366 MMGS_Set_solSize(mesh, met, MMG5_Vertex, 0, MMG5_Tensor);
368 if (opt.hsiz == 0. || opt.metric_attribute !=
"no_metric")
370 MMGS_Set_dparameter(mesh, met, MMGS_DPARAM_hmin, opt.hmin);
371 MMGS_Set_dparameter(mesh, met, MMGS_DPARAM_hmax, opt.hmax);
376 MMGS_Set_dparameter(mesh, met, MMGS_DPARAM_hsiz, opt.hsiz);
378 MMGS_Set_dparameter(mesh, met, MMGS_DPARAM_hausd, opt.hausd);
379 MMGS_Set_dparameter(mesh, met, MMGS_DPARAM_hgrad, opt.hgrad);
380 MMGS_Set_iparameter(mesh, met, MMGS_IPARAM_angle,
int(opt.angle_detection));
381 MMGS_Set_iparameter(mesh, met, MMGS_IPARAM_noswap,
int(opt.noswap));
382 MMGS_Set_iparameter(mesh, met, MMGS_IPARAM_noinsert,
int(opt.noinsert));
383 MMGS_Set_iparameter(mesh, met, MMGS_IPARAM_nomove,
int(opt.nomove));
384 if (opt.metric_attribute !=
"no_metric")
386 if (!
M.vertices.attributes().is_defined(opt.metric_attribute))
388 logger().error(
"mmgs_remesh: {} is not a vertex attribute, cancel", opt.metric_attribute);
391 GEO::Attribute<double> h_local(
M.vertices.attributes(), opt.metric_attribute);
392 for (uint v = 0; v <
M.vertices.nb(); ++v)
394 met->m[v + 1] = h_local[v];
398 int ier = MMGS_mmgslib(mesh, met);
399 if (ier != MMG5_SUCCESS)
401 logger().error(
"mmgs_remesh: failed to remesh");
402 mmgs_free(mesh, met);
406 ok = mmg_to_geo(mesh, M_out);
408 mmgs_free(mesh, met);
412 bool mmg3d_tet_remesh(
const GEO::Mesh &M, GEO::Mesh &M_out,
const MmgOptions &opt)
414 MMG5_pMesh mesh =
nullptr;
415 MMG5_pSol met =
nullptr;
416 bool ok = geo_to_mmg(M, mesh, met,
true);
419 logger().error(
"mmg3d_remesh: failed to convert mesh to MMG5_pMesh");
420 mmg3d_free(mesh, met);
425 MMG3D_Set_dparameter(mesh, met, MMG3D_DPARAM_angleDetection, opt.angle_value);
426 if (opt.enable_anisotropy)
428 MMG3D_Set_solSize(mesh, met, MMG5_Vertex, 0, MMG5_Tensor);
430 if (opt.hsiz == 0. || opt.metric_attribute !=
"no_metric")
432 MMG3D_Set_dparameter(mesh, met, MMG3D_DPARAM_hmin, opt.hmin);
433 MMG3D_Set_dparameter(mesh, met, MMG3D_DPARAM_hmax, opt.hmax);
438 MMG3D_Set_dparameter(mesh, met, MMG3D_DPARAM_hsiz, opt.hsiz);
440 MMG3D_Set_dparameter(mesh, met, MMG3D_DPARAM_hausd, opt.hausd);
441 MMG3D_Set_dparameter(mesh, met, MMG3D_DPARAM_hgrad, opt.hgrad);
442 MMG3D_Set_iparameter(mesh, met, MMG3D_IPARAM_angle,
int(opt.angle_detection));
443 MMG3D_Set_iparameter(mesh, met, MMG3D_IPARAM_noswap,
int(opt.noswap));
444 MMG3D_Set_iparameter(mesh, met, MMG3D_IPARAM_noinsert,
int(opt.noinsert));
445 MMG3D_Set_iparameter(mesh, met, MMG3D_IPARAM_nomove,
int(opt.nomove));
446 MMG3D_Set_iparameter(mesh, met, MMG3D_IPARAM_nosurf,
int(opt.nosurf));
447 MMG3D_Set_iparameter(mesh, met, MMG3D_IPARAM_opnbdy,
int(opt.opnbdy));
448 MMG3D_Set_iparameter(mesh, met, MMG3D_IPARAM_optim,
int(opt.optim));
449 MMG3D_Set_iparameter(mesh, met, MMG3D_IPARAM_optimLES,
int(opt.optimLES));
450 if (opt.metric_attribute !=
"no_metric")
452 if (!
M.vertices.attributes().is_defined(opt.metric_attribute))
454 logger().error(
"mmg3D_remesh: {} is not a vertex attribute, cancel", opt.metric_attribute);
457 GEO::Attribute<double> h_local(
M.vertices.attributes(), opt.metric_attribute);
458 for (uint v = 0; v <
M.vertices.nb(); ++v)
460 met->m[v + 1] = h_local[v];
464 int ier = MMG3D_mmg3dlib(mesh, met);
465 if (ier != MMG5_SUCCESS)
467 logger().error(
"mmg3d_remesh: failed to remesh");
468 mmg3d_free(mesh, met);
472 ok = mmg_to_geo(mesh, M_out);
474 mmg3d_free(mesh, met);
478 bool mmg3d_extract_iso(
const GEO::Mesh &M, GEO::Mesh &M_out,
const MmgOptions &opt)
480 if (!opt.level_set || opt.ls_attribute ==
"no_ls" || !
M.vertices.attributes().is_defined(opt.ls_attribute))
482 logger().error(
"mmg3D_iso: {} is not a vertex attribute, cancel", opt.ls_attribute);
485 if (opt.angle_detection)
487 logger().warn(
"mmg3D_iso: angle_detection shoud probably be disabled because level set functions are smooth");
490 MMG5_pMesh mesh =
nullptr;
491 MMG5_pSol met =
nullptr;
492 bool ok = geo_to_mmg(M, mesh, met,
true);
495 logger().error(
"mmg3d_remesh: failed to convert mesh to MMG5_pMesh");
496 mmg3d_free(mesh, met);
499 GEO::Attribute<double> ls(
M.vertices.attributes(), opt.ls_attribute);
500 for (uint v = 0; v <
M.vertices.nb(); ++v)
502 met->m[v + 1] = ls[v];
517 MMG3D_Set_iparameter(mesh, met, MMG3D_IPARAM_iso, 1);
518 MMG3D_Set_dparameter(mesh, met, MMG3D_DPARAM_ls, opt.ls_value);
519 MMG3D_Set_dparameter(mesh, met, MMG3D_DPARAM_angleDetection, opt.angle_value);
522 MMG3D_Set_dparameter(mesh, met, MMG3D_DPARAM_hmin, opt.hmin);
523 MMG3D_Set_dparameter(mesh, met, MMG3D_DPARAM_hmax, opt.hmax);
527 logger().error(
"mmg3d_iso: should not use hsiz parameter for level set mode");
528 mmg3d_free(mesh, met);
531 MMG3D_Set_dparameter(mesh, met, MMG3D_DPARAM_hausd, opt.hausd);
532 MMG3D_Set_dparameter(mesh, met, MMG3D_DPARAM_hgrad, opt.hgrad);
533 MMG3D_Set_iparameter(mesh, met, MMG3D_IPARAM_angle,
int(opt.angle_detection));
534 MMG3D_Set_iparameter(mesh, met, MMG3D_IPARAM_noswap,
int(opt.noswap));
535 MMG3D_Set_iparameter(mesh, met, MMG3D_IPARAM_noinsert, 1);
536 MMG3D_Set_iparameter(mesh, met, MMG3D_IPARAM_nomove, 1);
537 MMG3D_Set_iparameter(mesh, met, MMG3D_IPARAM_nosurf, 1);
542 int ier = MMG3D_mmg3dls(mesh, met,
nullptr);
543 if (ier != MMG5_SUCCESS)
545 logger().error(
"mmg3d_iso: failed to remesh isovalue");
546 mmg3d_free(mesh, met);
551 ok = mmg_to_geo(mesh, M_out);
552 GEO::Attribute<double> ls_out(M_out.vertices.attributes(), opt.ls_attribute);
553 for (uint v = 0; v < M_out.vertices.nb(); ++v)
555 ls_out[v] = met->m[v + 1];
579 mmg3d_free(mesh, met);
587 void remesh_adaptive_2d(
const Eigen::MatrixXd &
V,
const Eigen::MatrixXi &
F,
const Eigen::VectorXd &S,
588 Eigen::MatrixXd &OV, Eigen::MatrixXi &OF, MmgOptions opt)
590 assert(
V.cols() == 2 ||
V.cols() == 3);
591 assert(
V.rows() == S.size());
596 opt.metric_attribute =
"scalar";
598 GEO::Attribute<double> scalar(
M.vertices.attributes(), opt.metric_attribute);
599 for (
int v = 0; v <
M.vertices.nb(); ++v)
605 mmg2d_tri_remesh(M, M_out, opt);
612 OV.conservativeResize(OV.rows(), 2);
615 void remesh_adaptive_3d(
const Eigen::MatrixXd &
V,
const Eigen::MatrixXi &T,
const Eigen::VectorXd &S,
616 Eigen::MatrixXd &OV, Eigen::MatrixXi &OF, Eigen::MatrixXi &OT, MmgOptions opt)
618 assert(
V.cols() == 3);
619 assert(
V.rows() == S.size());
624 opt.metric_attribute =
"scalar";
626 GEO::Attribute<double> scalar(
M.vertices.attributes(), opt.metric_attribute);
627 for (
int v = 0; v <
M.vertices.nb(); ++v)
633 mmg3d_tet_remesh(M, M_out, opt);
void to_geogram_mesh(const Eigen::MatrixXd &V, const Eigen::MatrixXi &F, GEO::Mesh &M)
Converts a triangle mesh to a Geogram mesh.
void from_geogram_mesh(const GEO::Mesh &M, Eigen::MatrixXd &V, Eigen::MatrixXi &F, Eigen::MatrixXi &T)
Extract simplices from a Geogram mesh.
spdlog::logger & logger()
Retrieves the current logger.