PolyFEM
Loading...
Searching...
No Matches
PolyhedronQuadrature.cpp
Go to the documentation of this file.
1
3#include "TetQuadrature.hpp"
4#include <igl/writeMESH.h>
5#ifdef POLYFEM_WITH_MMG
6#include <boost/filesystem.hpp>
7#endif
8#include <vector>
9#include <cassert>
10#include <iostream>
12
13namespace polyfem
14{
16
17 void tertrahedralize_star_shaped_surface(const Eigen::MatrixXd &V, const Eigen::MatrixXi &F,
18 const Eigen::RowVector3d &kernel, Eigen::MatrixXd &OV, Eigen::MatrixXi &OF, Eigen::MatrixXi &OT)
19 {
20 assert(V.cols() == 3);
21 OV.resize(V.rows() + 1, V.cols());
22 OV.topRows(V.rows()) = V;
23 OV.bottomRows(1) = kernel;
24 OF = F;
25 OT.resize(OF.rows(), 4);
26 OT.col(0).setConstant(V.rows());
27 OT.rightCols(3) = F;
28 }
29
30 namespace quadrature
31 {
32 namespace
33 {
34
35#ifdef POLYFEM_WITH_MMG
36
37 // try to remesh volume if polyhedron creates more than this # of quadrature points
38 const int max_num_quadrature_points = 2048;
39
40 bool mmg_remesh_volume(const Eigen::MatrixXd &V, const Eigen::MatrixXi &F, const Eigen::MatrixXi &T,
41 Eigen::MatrixXd &TV, Eigen::MatrixXi &TF, Eigen::MatrixXi &TT)
42 {
43 using namespace boost;
44
45 double scaling = (V.colwise().maxCoeff() - V.colwise().minCoeff()).maxCoeff();
46 Eigen::RowVector3d translation = V.colwise().minCoeff();
47
48 auto tmp_dir = filesystem::temp_directory_path();
49 auto base_path = tmp_dir / filesystem::unique_path("polyfem_%%%%-%%%%-%%%%-%%%%");
50 auto f_input = base_path;
51 f_input += "_in.mesh";
52 auto f_output = base_path;
53 f_output += "_out.mesh";
54 auto f_sol = base_path;
55 f_sol += "_out.sol";
56
57 TV = (V.rowwise() - translation) / scaling;
58 igl::writeMESH(f_input.string(), TV, T, F);
59
60 std::string app(POLYFEM_MMG_PATH);
61 std::string cmd = app + " -ar 20 -hausd 0.01 -v 0 -in " + f_input.string() + " -out " + f_output.string();
62#ifndef WIN32
63 cmd += " &> /dev/null";
64#endif
65 logger().trace("Running command:\n {}", cmd);
66 if (::system(cmd.c_str()) == 0)
67 {
68 GEO::Mesh M;
69 GEO::mesh_load(f_output.string(), M);
70 from_geogram_mesh(M, TV, TF, TT);
71 TV = (scaling * TV).rowwise() + translation;
72
73 filesystem::remove(f_input);
74 filesystem::remove(f_output);
75 filesystem::remove(f_sol);
76 return true;
77 }
78 else
79 {
80 filesystem::remove(f_input);
81 return false;
82 }
83 }
84
85#endif
86
87 template <class TriMat>
88 double transform_pts(const TriMat &tri, const Eigen::MatrixXd &pts, Eigen::MatrixXd &transformed)
89 {
90 Eigen::Matrix3d matrix;
91 matrix.row(0) = tri.row(1) - tri.row(0);
92 matrix.row(1) = tri.row(2) - tri.row(0);
93 matrix.row(2) = tri.row(3) - tri.row(0);
94
95 transformed = pts * matrix;
96
97 transformed.col(0).array() += tri(0, 0);
98 transformed.col(1).array() += tri(0, 1);
99 transformed.col(2).array() += tri(0, 2);
100
101 return matrix.determinant();
102 }
103
104 } // anonymous namespace
105
107
108 void PolyhedronQuadrature::get_quadrature(const Eigen::MatrixXd &V, const Eigen::MatrixXi &F,
109 const Eigen::RowVector3d &kernel, const int order, Quadrature &quadr)
110 {
111 std::string flags = "Qpq2.0";
112 Eigen::VectorXi J;
113 Eigen::MatrixXd VV, OV, TV;
114 Eigen::MatrixXi OF, TF, tets;
115
116 Quadrature tet_quadr_pts;
117 TetQuadrature tet_quadr;
118 tet_quadr.get_quadrature(4, tet_quadr_pts);
119 // assert(tet_quadr_pts.weights.minCoeff() >= 0);
120
121 double scaling = (V.colwise().maxCoeff() - V.colwise().minCoeff()).maxCoeff();
122 Eigen::RowVector3d translation = V.colwise().minCoeff();
123
124 tertrahedralize_star_shaped_surface(V, F, kernel, TV, TF, tets);
125
126#ifdef POLYFEM_WITH_MMG
127 if (tet_quadr_pts.weights.size() * tets.rows() > max_num_quadrature_points)
128 {
129 Eigen::MatrixXd V0;
130 Eigen::MatrixXi F0, T0;
131 bool res = mmg_remesh_volume(TV, TF, tets, V0, F0, T0);
132
133 if (res && T0.rows() < tets.rows())
134 {
135 TV = V0;
136 TF = F0;
137 tets = T0;
138 }
139 }
140#endif
141
142 const long offset = tet_quadr_pts.weights.rows();
143 quadr.points.resize(tets.rows() * offset, 3);
144 quadr.weights.resize(tets.rows() * offset, 1);
145
146 Eigen::MatrixXd transformed_points;
147
148 for (long i = 0; i < tets.rows(); ++i)
149 {
150 Eigen::Matrix<double, 4, 3> tetra;
151 const auto &indices = tets.row(i);
152 tetra.row(0) = TV.row(indices(0));
153 tetra.row(1) = TV.row(indices(1));
154 tetra.row(2) = TV.row(indices(2));
155 tetra.row(3) = TV.row(indices(3));
156
157 // viewer.data.add_edges(triangle.row(0), triangle.row(1), Eigen::Vector3d(1,0,0).transpose());
158 // viewer.data.add_edges(triangle.row(0), triangle.row(2), Eigen::Vector3d(1,0,0).transpose());
159 // viewer.data.add_edges(triangle.row(2), triangle.row(1), Eigen::Vector3d(1,0,0).transpose());
160
161 const double det = transform_pts(tetra, tet_quadr_pts.points, transformed_points);
162 assert(det > 0);
163
164 quadr.points.block(i * offset, 0, transformed_points.rows(), transformed_points.cols()) = transformed_points;
165 quadr.weights.block(i * offset, 0, tet_quadr_pts.weights.rows(), tet_quadr_pts.weights.cols()) = tet_quadr_pts.weights * det;
166 }
167
168 // assert(quadr.weights.minCoeff() >= 0);
169 }
170 } // namespace quadrature
171} // namespace polyfem
int V
Quadrature quadrature
static void get_quadrature(const Eigen::MatrixXd &V, const Eigen::MatrixXi &F, const Eigen::RowVector3d &kernel, const int order, Quadrature &quadr)
Gets the quadrature points & weights for a polyhedron.
void get_quadrature(const int order, Quadrature &quad)
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.
Definition Logger.cpp:44
void tertrahedralize_star_shaped_surface(const Eigen::MatrixXd &V, const Eigen::MatrixXi &F, const Eigen::RowVector3d &kernel, Eigen::MatrixXd &OV, Eigen::MatrixXi &OF, Eigen::MatrixXi &OT)
Tetrahedralize a star-shaped mesh, with a given point in its kernel.