14#include <geogram/basic/attributes.h>
15#include <geogram/mesh/mesh.h>
16#include <geogram/mesh/mesh_io.h>
17#include <igl/boundary_facets.h>
18#include <mmg/libmmg.h>
29typedef unsigned int uint;
37 bool orient_simplices(
const Eigen::MatrixXd &vertices, Eigen::MatrixXi &elements)
39 for (
int e = 0;
e < elements.rows(); ++
e)
42 if (elements.cols() == 3)
51 assert(elements.cols() == 4);
61 logger().error(
"MMG produced a degenerate simplex {}", e);
65 std::swap(elements(e, 1), elements(e, 2));
70 void to_geogram_mesh(
const Eigen::MatrixXd &
V,
const Eigen::MatrixXi &
F, GEO::Mesh &M)
74 M.vertices.create_vertices((
int)
V.rows());
75 for (
int i = 0; i < (int)
M.vertices.nb(); ++i)
77 GEO::vec3 &p =
M.vertices.point(i);
80 p[2] = (
V.cols() == 2 ? 0 :
V(i, 2));
85 M.facets.create_triangles((
int)
F.rows());
87 else if (
F.cols() == 4)
89 M.facets.create_quads((
int)
F.rows());
93 throw std::runtime_error(
"Mesh faces not supported");
95 for (
int c = 0; c < (int)
M.facets.nb(); ++c)
97 for (
int lv = 0; lv <
F.cols(); ++lv)
99 M.facets.set_vertex(c, lv,
F(c, lv));
105 void to_geogram_mesh(
const Eigen::MatrixXd &
V,
const Eigen::MatrixXi &
F,
const Eigen::MatrixXi &T, GEO::Mesh &M)
110 M.cells.create_tets((
int)
T.rows());
112 else if (
T.rows() != 0)
114 throw std::runtime_error(
"Mesh cells not supported");
116 for (
int c = 0; c < (int)
M.cells.nb(); ++c)
118 for (
int lv = 0; lv <
T.cols(); ++lv)
120 M.cells.set_vertex(c, lv,
T(c, lv));
126 void from_geogram_mesh(
const GEO::Mesh &M, Eigen::MatrixXd &
V, Eigen::MatrixXi &
F, Eigen::MatrixXi &T)
128 V.resize(
M.vertices.nb(), 3);
129 for (
int i = 0; i < (int)
M.vertices.nb(); ++i)
131 GEO::vec3 p =
M.vertices.point(i);
132 V.row(i) << p[0], p[1], p[2];
134 assert(
M.facets.are_simplices());
135 F.resize(
M.facets.nb(), 3);
136 for (
int c = 0; c < (int)
M.facets.nb(); ++c)
138 for (
int lv = 0; lv < 3; ++lv)
140 F(c, lv) =
M.facets.vertex(c, lv);
143 assert(
M.cells.are_simplices());
144 T.resize(
M.cells.nb(), 4);
145 for (
int c = 0; c < (int)
M.cells.nb(); ++c)
147 for (
int lv = 0; lv < 4; ++lv)
149 T(c, lv) =
M.cells.vertex(c, lv);
154 bool mmg_to_geo(
const MMG5_pMesh mmg, GEO::Mesh &M)
156 logger().trace(
"converting MMG5_pMesh to GEO::Mesh ...");
160 assert(mmg->dim == 2 || mmg->dim == 3);
162 M.vertices.create_vertices((uint)mmg->np);
163 M.edges.create_edges((uint)mmg->na);
164 M.facets.create_triangles((uint)mmg->nt);
165 M.cells.create_tets((uint)mmg->ne);
167 for (uint v = 0; v <
M.vertices.nb(); ++v)
169 for (uint d = 0; d < (uint)mmg->dim; ++d)
171 M.vertices.point_ptr(v)[d] = mmg->point[v + 1].c[d];
175 M.vertices.point_ptr(v)[2] = 0.;
177 for (uint e = 0;
e <
M.edges.nb(); ++
e)
179 M.edges.set_vertex(e, 0, (uint)mmg->edge[
e + 1].a - 1);
180 M.edges.set_vertex(e, 1, (uint)mmg->edge[
e + 1].b - 1);
182 for (uint t = 0; t <
M.facets.nb(); ++t)
184 M.facets.set_vertex(t, 0, (uint)mmg->tria[t + 1].v[0] - 1);
185 M.facets.set_vertex(t, 1, (uint)mmg->tria[t + 1].v[1] - 1);
186 M.facets.set_vertex(t, 2, (uint)mmg->tria[t + 1].v[2] - 1);
188 for (uint c = 0; mmg->dim == 3 && c <
M.cells.nb(); ++c)
190 M.cells.set_vertex(c, 0, (uint)mmg->tetra[c + 1].v[0] - 1);
191 M.cells.set_vertex(c, 1, (uint)mmg->tetra[c + 1].v[1] - 1);
192 M.cells.set_vertex(c, 2, (uint)mmg->tetra[c + 1].v[2] - 1);
193 M.cells.set_vertex(c, 3, (uint)mmg->tetra[c + 1].v[3] - 1);
201 bool geo_to_mmg(
const GEO::Mesh &M, MMG5_pMesh &mmg, MMG5_pSol &sol,
bool volume_mesh =
true)
203 logger().trace(
"converting GEO::M to MMG5_pMesh ...");
204 assert(
M.vertices.dimension() == 3);
205 if (
M.facets.nb() > 0)
206 assert(
M.facets.are_simplices());
207 if (
M.cells.nb() > 0)
208 assert(
M.cells.are_simplices());
212 MMG3D_Init_mesh(MMG5_ARG_start, MMG5_ARG_ppMesh, &mmg, MMG5_ARG_ppMet, &sol, MMG5_ARG_end);
216 MMGS_Init_mesh(MMG5_ARG_start, MMG5_ARG_ppMesh, &mmg, MMG5_ARG_ppMet, &sol, MMG5_ARG_end);
219 if (volume_mesh && MMG3D_Set_meshSize(mmg, (
int)
M.vertices.nb(), (
int)
M.cells.nb(), 0,
220 (
int)
M.facets.nb(), 0,
225 logger().error(
"failed to MMG3D_Set_meshSize");
228 else if (!volume_mesh && MMGS_Set_meshSize(mmg, (
int)
M.vertices.nb(), (
int)
M.facets.nb(), (
int)
M.edges.nb()
232 logger().error(
"failed to MMGS_Set_meshSize");
236 for (uint v = 0; v < (uint)mmg->np; ++v)
238 for (uint d = 0; d <
M.vertices.dimension(); ++d)
240 mmg->point[v + 1].c[d] =
M.vertices.point_ptr(v)[d];
243 for (uint e = 0;
e < (uint)mmg->na; ++
e)
245 mmg->edge[
e + 1].a = (int)
M.edges.vertex(e, 0) + 1;
246 mmg->edge[
e + 1].b = (int)
M.edges.vertex(e, 1) + 1;
248 for (uint t = 0; t < (uint)mmg->nt; ++t)
250 mmg->tria[t + 1].v[0] = (int)
M.facets.vertex(t, 0) + 1;
251 mmg->tria[t + 1].v[1] = (int)
M.facets.vertex(t, 1) + 1;
252 mmg->tria[t + 1].v[2] = (int)
M.facets.vertex(t, 2) + 1;
256 for (uint c = 0; c < (uint)mmg->ne; ++c)
258 mmg->tetra[c + 1].v[0] = (int)
M.cells.vertex(c, 0) + 1;
259 mmg->tetra[c + 1].v[1] = (int)
M.cells.vertex(c, 1) + 1;
260 mmg->tetra[c + 1].v[2] = (int)
M.cells.vertex(c, 2) + 1;
261 mmg->tetra[c + 1].v[3] = (int)
M.cells.vertex(c, 3) + 1;
265 if (volume_mesh && MMG3D_Set_solSize(mmg, sol, MMG5_Vertex, (
int)
M.vertices.nb(), MMG5_Scalar) != 1)
267 logger().error(
"failed to MMG3D_Set_solSize");
270 else if (!volume_mesh && MMGS_Set_solSize(mmg, sol, MMG5_Vertex, (
int)
M.vertices.nb(), MMG5_Scalar) != 1)
272 logger().error(
"failed to MMGS_Set_solSize");
275 for (uint v = 0; v <
M.vertices.nb(); ++v)
279 if (volume_mesh && MMG3D_Chk_meshData(mmg, sol) != 1)
281 logger().error(
"error in mmg: inconsistent mesh and sol");
284 else if (!volume_mesh && MMGS_Chk_meshData(mmg, sol) != 1)
286 logger().error(
"error in mmg: inconsistent mesh and sol");
292 MMG3D_Set_handGivenMesh(mmg);
298 bool geo_to_mmg2d(
const GEO::Mesh &M, MMG5_pMesh &mmg, MMG5_pSol &sol)
300 assert(
M.vertices.dimension() == 3);
301 assert(
M.facets.are_simplices());
303 MMG2D_Init_mesh(MMG5_ARG_start, MMG5_ARG_ppMesh, &mmg, MMG5_ARG_ppMet, &sol, MMG5_ARG_end);
304 if (!MMG2D_Set_meshSize(mmg,
M.vertices.nb(),
M.facets.nb(), 0,
M.edges.nb()))
306 logger().error(
"mmg2d_remesh: failed to allocate the MMG mesh");
310 for (
int v = 0; v < mmg->np; ++v)
312 mmg->point[v + 1].c[0] =
M.vertices.point_ptr(v)[0];
313 mmg->point[v + 1].c[1] =
M.vertices.point_ptr(v)[1];
315 for (
int e = 0;
e < mmg->na; ++
e)
318 mmg->edge[
e + 1].a =
M.edges.vertex(e, 0) + 1;
319 mmg->edge[
e + 1].b =
M.edges.vertex(e, 1) + 1;
321 for (
int t = 0; t < mmg->nt; ++t)
324 mmg->tria[t + 1].v[0] =
M.facets.vertex(t, 0) + 1;
325 mmg->tria[t + 1].v[1] =
M.facets.vertex(t, 1) + 1;
326 mmg->tria[t + 1].v[2] =
M.facets.vertex(t, 2) + 1;
329 if (!MMG2D_Set_solSize(mmg, sol, MMG5_Vertex,
M.vertices.nb(), MMG5_Scalar))
331 logger().error(
"failed to MMG2D_Set_solSize");
335 for (
int v = 0; v <
M.vertices.nb(); ++v)
338 if (!MMG2D_Chk_meshData(mmg, sol))
340 logger().error(
"error in mmg: inconsistent mesh and sol");
346 void mmg2d_free(MMG5_pMesh mmg, MMG5_pSol sol)
348 MMG2D_Free_all(MMG5_ARG_start,
349 MMG5_ARG_ppMesh, &mmg, MMG5_ARG_ppMet, &sol, MMG5_ARG_end);
352 void mmg3d_free(MMG5_pMesh mmg, MMG5_pSol sol)
354 MMG3D_Free_all(MMG5_ARG_start,
355 MMG5_ARG_ppMesh, &mmg, MMG5_ARG_ppMet, &sol, MMG5_ARG_end);
358 void mmgs_free(MMG5_pMesh mmg, MMG5_pSol sol)
360 MMGS_Free_all(MMG5_ARG_start,
361 MMG5_ARG_ppMesh, &mmg, MMG5_ARG_ppMet, &sol, MMG5_ARG_end);
364 bool mmg_wrapper_test_geo2mmg2geo(
const GEO::Mesh &M_in, GEO::Mesh &M_out)
366 MMG5_pMesh mmg =
nullptr;
367 MMG5_pSol sol =
nullptr;
368 bool ok = geo_to_mmg(M_in, mmg, sol);
371 ok = mmg_to_geo(mmg, M_out);
372 mmg3d_free(mmg, sol);
376 bool mmg2d_tri_remesh(
378 const std::vector<int> *pinned_vertices,
380 const MmgOptions &opt)
382 MMG5_pMesh mesh =
nullptr;
383 MMG5_pSol met =
nullptr;
384 bool ok = geo_to_mmg2d(M, mesh, met);
387 logger().error(
"mmg2d_remesh: failed to convert mesh to MMG5_pMesh");
388 mmg2d_free(mesh, met);
393 std::vector<bool> is_pinned(
M.vertices.nb(),
false);
394 if (pinned_vertices !=
nullptr)
396 for (
const int v : *pinned_vertices)
398 assert(v >= 0 && v <
M.vertices.nb());
400 MMG2D_Set_requiredVertex(mesh, v + 1);
403 for (
int e = 0;
e <
M.edges.nb(); ++
e)
405 if (is_pinned[
M.edges.vertex(e, 0)]
406 && is_pinned[
M.edges.vertex(e, 1)])
408 MMG2D_Set_requiredEdge(mesh, e + 1);
413 MMG2D_Set_dparameter(mesh, met, MMG2D_DPARAM_angleDetection, opt.angle_value);
414 if (opt.enable_anisotropy)
416 MMG2D_Set_solSize(mesh, met, MMG5_Vertex, 0, MMG5_Tensor);
418 const bool with_metric = opt.metric_attribute !=
"no_metric";
419 if (opt.hsiz == 0. || with_metric)
421 if (with_metric || !opt.optim)
423 MMG2D_Set_dparameter(mesh, met, MMG2D_DPARAM_hmin, opt.hmin);
424 MMG2D_Set_dparameter(mesh, met, MMG2D_DPARAM_hmax, opt.hmax);
434 MMG2D_Set_dparameter(mesh, met, MMG2D_DPARAM_hsiz, opt.hsiz);
436 MMG2D_Set_dparameter(mesh, met, MMG2D_DPARAM_hausd, opt.hausd);
437 MMG2D_Set_dparameter(mesh, met, MMG2D_DPARAM_hgrad, opt.hgrad);
438 MMG2D_Set_iparameter(mesh, met, MMG2D_IPARAM_angle,
int(opt.angle_detection));
439 MMG2D_Set_iparameter(mesh, met, MMG2D_IPARAM_noswap,
int(opt.noswap));
440 MMG2D_Set_iparameter(mesh, met, MMG2D_IPARAM_noinsert,
int(opt.noinsert));
441 MMG2D_Set_iparameter(mesh, met, MMG2D_IPARAM_nomove,
int(opt.nomove));
442 MMG2D_Set_iparameter(mesh, met, MMG2D_IPARAM_nosurf,
int(opt.nosurf));
443 MMG2D_Set_iparameter(mesh, met, MMG2D_IPARAM_optim,
int(opt.optim));
446 if (!
M.vertices.attributes().is_defined(opt.metric_attribute))
448 logger().error(
"mmg2D_remesh: {} is not a vertex attribute, cancel", opt.metric_attribute);
449 mmg2d_free(mesh, met);
452 GEO::Attribute<double> h_local(
M.vertices.attributes(), opt.metric_attribute);
453 for (
int v = 0; v <
M.vertices.nb(); ++v)
455 met->m[v + 1] = h_local[v];
459 int ier = MMG2D_mmg2dlib(mesh, met);
460 if (ier != MMG5_SUCCESS)
462 logger().error(
"mmg2d_remesh: failed to remesh");
463 mmg2d_free(mesh, met);
467 ok = mmg_to_geo(mesh, M_out);
469 mmg2d_free(mesh, met);
473 bool mmgs_tri_remesh(
const GEO::Mesh &M, GEO::Mesh &M_out,
const MmgOptions &opt)
475 MMG5_pMesh mesh =
nullptr;
476 MMG5_pSol met =
nullptr;
477 bool ok = geo_to_mmg(M, mesh, met,
false);
480 logger().error(
"mmgs_remesh: failed to convert mesh to MMG5_pMesh");
481 mmgs_free(mesh, met);
486 MMGS_Set_dparameter(mesh, met, MMGS_DPARAM_angleDetection, opt.angle_value);
487 if (opt.enable_anisotropy)
489 MMGS_Set_solSize(mesh, met, MMG5_Vertex, 0, MMG5_Tensor);
491 if (opt.hsiz == 0. || opt.metric_attribute !=
"no_metric")
493 MMGS_Set_dparameter(mesh, met, MMGS_DPARAM_hmin, opt.hmin);
494 MMGS_Set_dparameter(mesh, met, MMGS_DPARAM_hmax, opt.hmax);
499 MMGS_Set_dparameter(mesh, met, MMGS_DPARAM_hsiz, opt.hsiz);
501 MMGS_Set_dparameter(mesh, met, MMGS_DPARAM_hausd, opt.hausd);
502 MMGS_Set_dparameter(mesh, met, MMGS_DPARAM_hgrad, opt.hgrad);
503 MMGS_Set_iparameter(mesh, met, MMGS_IPARAM_angle,
int(opt.angle_detection));
504 MMGS_Set_iparameter(mesh, met, MMGS_IPARAM_noswap,
int(opt.noswap));
505 MMGS_Set_iparameter(mesh, met, MMGS_IPARAM_noinsert,
int(opt.noinsert));
506 MMGS_Set_iparameter(mesh, met, MMGS_IPARAM_nomove,
int(opt.nomove));
507 if (opt.metric_attribute !=
"no_metric")
509 if (!
M.vertices.attributes().is_defined(opt.metric_attribute))
511 logger().error(
"mmgs_remesh: {} is not a vertex attribute, cancel", opt.metric_attribute);
514 GEO::Attribute<double> h_local(
M.vertices.attributes(), opt.metric_attribute);
515 for (uint v = 0; v <
M.vertices.nb(); ++v)
517 met->m[v + 1] = h_local[v];
521 int ier = MMGS_mmgslib(mesh, met);
522 if (ier != MMG5_SUCCESS)
524 logger().error(
"mmgs_remesh: failed to remesh");
525 mmgs_free(mesh, met);
529 ok = mmg_to_geo(mesh, M_out);
531 mmgs_free(mesh, met);
535 bool mmg3d_tet_remesh(
537 const std::vector<int> *pinned_vertices,
539 const MmgOptions &opt)
541 MMG5_pMesh mesh =
nullptr;
542 MMG5_pSol met =
nullptr;
543 bool ok = geo_to_mmg(M, mesh, met,
true);
546 logger().error(
"mmg3d_remesh: failed to convert mesh to MMG5_pMesh");
547 mmg3d_free(mesh, met);
552 std::vector<bool> is_pinned(
M.vertices.nb(),
false);
553 if (pinned_vertices !=
nullptr)
555 for (
const int v : *pinned_vertices)
557 assert(v >= 0 && v <
M.vertices.nb());
559 MMG3D_Set_requiredVertex(mesh, v + 1);
562 for (
int f = 0;
f <
M.facets.nb(); ++
f)
564 if (is_pinned[
M.facets.vertex(f, 0)]
565 && is_pinned[
M.facets.vertex(f, 1)]
566 && is_pinned[
M.facets.vertex(f, 2)])
568 MMG3D_Set_requiredTriangle(mesh, f + 1);
573 MMG3D_Set_dparameter(mesh, met, MMG3D_DPARAM_angleDetection, opt.angle_value);
574 if (opt.enable_anisotropy)
576 MMG3D_Set_solSize(mesh, met, MMG5_Vertex, 0, MMG5_Tensor);
578 const bool with_metric = opt.metric_attribute !=
"no_metric";
579 if (opt.hsiz == 0. || with_metric)
581 if (with_metric || !opt.optim)
583 MMG3D_Set_dparameter(mesh, met, MMG3D_DPARAM_hmin, opt.hmin);
584 MMG3D_Set_dparameter(mesh, met, MMG3D_DPARAM_hmax, opt.hmax);
594 MMG3D_Set_dparameter(mesh, met, MMG3D_DPARAM_hsiz, opt.hsiz);
596 MMG3D_Set_dparameter(mesh, met, MMG3D_DPARAM_hausd, opt.hausd);
597 MMG3D_Set_dparameter(mesh, met, MMG3D_DPARAM_hgrad, opt.hgrad);
598 MMG3D_Set_iparameter(mesh, met, MMG3D_IPARAM_angle,
int(opt.angle_detection));
599 MMG3D_Set_iparameter(mesh, met, MMG3D_IPARAM_noswap,
int(opt.noswap));
600 MMG3D_Set_iparameter(mesh, met, MMG3D_IPARAM_noinsert,
int(opt.noinsert));
601 MMG3D_Set_iparameter(mesh, met, MMG3D_IPARAM_nomove,
int(opt.nomove));
602 MMG3D_Set_iparameter(mesh, met, MMG3D_IPARAM_nosurf,
int(opt.nosurf));
603 MMG3D_Set_iparameter(mesh, met, MMG3D_IPARAM_opnbdy,
int(opt.opnbdy));
604 MMG3D_Set_iparameter(mesh, met, MMG3D_IPARAM_optim,
int(opt.optim));
605 MMG3D_Set_iparameter(mesh, met, MMG3D_IPARAM_optimLES,
int(opt.optimLES));
608 if (!
M.vertices.attributes().is_defined(opt.metric_attribute))
610 logger().error(
"mmg3D_remesh: {} is not a vertex attribute, cancel", opt.metric_attribute);
611 mmg3d_free(mesh, met);
614 GEO::Attribute<double> h_local(
M.vertices.attributes(), opt.metric_attribute);
615 for (
int v = 0; v <
M.vertices.nb(); ++v)
617 met->m[v + 1] = h_local[v];
621 int ier = MMG3D_mmg3dlib(mesh, met);
622 if (ier != MMG5_SUCCESS)
624 logger().error(
"mmg3d_remesh: failed to remesh");
625 mmg3d_free(mesh, met);
629 ok = mmg_to_geo(mesh, M_out);
631 mmg3d_free(mesh, met);
635 bool mmg3d_extract_iso(
const GEO::Mesh &M, GEO::Mesh &M_out,
const MmgOptions &opt)
637 if (!opt.level_set || opt.ls_attribute ==
"no_ls" || !
M.vertices.attributes().is_defined(opt.ls_attribute))
639 logger().error(
"mmg3D_iso: {} is not a vertex attribute, cancel", opt.ls_attribute);
642 if (opt.angle_detection)
644 logger().warn(
"mmg3D_iso: angle_detection shoud probably be disabled because level set functions are smooth");
647 MMG5_pMesh mesh =
nullptr;
648 MMG5_pSol met =
nullptr;
649 bool ok = geo_to_mmg(M, mesh, met,
true);
652 logger().error(
"mmg3d_remesh: failed to convert mesh to MMG5_pMesh");
653 mmg3d_free(mesh, met);
656 GEO::Attribute<double> ls(
M.vertices.attributes(), opt.ls_attribute);
657 for (uint v = 0; v <
M.vertices.nb(); ++v)
659 met->m[v + 1] = ls[v];
674 MMG3D_Set_iparameter(mesh, met, MMG3D_IPARAM_iso, 1);
675 MMG3D_Set_dparameter(mesh, met, MMG3D_DPARAM_ls, opt.ls_value);
676 MMG3D_Set_dparameter(mesh, met, MMG3D_DPARAM_angleDetection, opt.angle_value);
679 MMG3D_Set_dparameter(mesh, met, MMG3D_DPARAM_hmin, opt.hmin);
680 MMG3D_Set_dparameter(mesh, met, MMG3D_DPARAM_hmax, opt.hmax);
684 logger().error(
"mmg3d_iso: should not use hsiz parameter for level set mode");
685 mmg3d_free(mesh, met);
688 MMG3D_Set_dparameter(mesh, met, MMG3D_DPARAM_hausd, opt.hausd);
689 MMG3D_Set_dparameter(mesh, met, MMG3D_DPARAM_hgrad, opt.hgrad);
690 MMG3D_Set_iparameter(mesh, met, MMG3D_IPARAM_angle,
int(opt.angle_detection));
691 MMG3D_Set_iparameter(mesh, met, MMG3D_IPARAM_noswap,
int(opt.noswap));
692 MMG3D_Set_iparameter(mesh, met, MMG3D_IPARAM_noinsert, 1);
693 MMG3D_Set_iparameter(mesh, met, MMG3D_IPARAM_nomove, 1);
694 MMG3D_Set_iparameter(mesh, met, MMG3D_IPARAM_nosurf, 1);
699 int ier = MMG3D_mmg3dls(mesh, met,
nullptr);
700 if (ier != MMG5_SUCCESS)
702 logger().error(
"mmg3d_iso: failed to remesh isovalue");
703 mmg3d_free(mesh, met);
708 ok = mmg_to_geo(mesh, M_out);
709 GEO::Attribute<double> ls_out(M_out.vertices.attributes(), opt.ls_attribute);
710 for (uint v = 0; v < M_out.vertices.nb(); ++v)
712 ls_out[v] = met->m[v + 1];
736 mmg3d_free(mesh, met);
745 const Eigen::MatrixXd &
V,
746 const Eigen::MatrixXi &
F,
750 const std::vector<int> *pinned_vertices)
752 assert(
V.cols() == 2);
753 assert(
F.cols() == 3);
756 if (!mmg2d_tri_remesh(M, pinned_vertices, M_out, opt))
761 OV.conservativeResize(OV.rows(), 2);
763 return orient_simplices(OV, OF);
766 void remesh_adaptive_2d(
const Eigen::MatrixXd &
V,
const Eigen::MatrixXi &
F,
const Eigen::VectorXd &S,
767 Eigen::MatrixXd &OV, Eigen::MatrixXi &OF, MmgOptions opt)
769 assert(
V.cols() == 2 ||
V.cols() == 3);
770 assert(
V.rows() == S.size());
771 assert(
F.cols() == 3);
775 opt.metric_attribute =
"scalar";
776 GEO::Attribute<double> scalar(
M.vertices.attributes(), opt.metric_attribute);
777 for (
int v = 0; v <
M.vertices.nb(); ++v)
780 if (!mmg2d_tri_remesh(M,
nullptr, M_out, opt))
784 OV.conservativeResize(OV.rows(), 2);
785 orient_simplices(OV, OF);
789 const Eigen::MatrixXd &
V,
790 const Eigen::MatrixXi &T,
795 const std::vector<int> *pinned_vertices)
797 assert(
V.cols() == 3);
798 assert(
T.cols() == 4);
800 Eigen::MatrixXi boundary;
801 igl::boundary_facets(T, boundary);
803 if (!mmg3d_tet_remesh(M, pinned_vertices, M_out, opt))
807 return orient_simplices(OV, OT);
810 void remesh_adaptive_3d(
const Eigen::MatrixXd &
V,
const Eigen::MatrixXi &T,
const Eigen::VectorXd &S,
811 Eigen::MatrixXd &OV, Eigen::MatrixXi &OF, Eigen::MatrixXi &OT, MmgOptions opt)
813 assert(
V.cols() == 3);
814 assert(
V.rows() == S.size());
819 opt.metric_attribute =
"scalar";
821 GEO::Attribute<double> scalar(
M.vertices.attributes(), opt.metric_attribute);
822 for (
int v = 0; v <
M.vertices.nb(); ++v)
828 if (!mmg3d_tet_remesh(M,
nullptr, M_out, opt))
833 orient_simplices(OV, OT);
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.
double tetrahedron_volume(const Eigen::Vector3d &a, const Eigen::Vector3d &b, const Eigen::Vector3d &c, const Eigen::Vector3d &d)
Compute the signed volume of a tetrahedron defined by four points.
double triangle_area_2D(const Eigen::Vector2d &a, const Eigen::Vector2d &b, const Eigen::Vector2d &c)
Compute the signed area of a 2D triangle defined by three points.
spdlog::logger & logger()
Retrieves the current logger.