7#include <igl/remove_duplicate_vertices.h>
8#include <igl/barycentric_coordinates.h>
9#ifdef POLYFEM_WITH_TRIANGLE
10#include <igl/triangle/triangulate.h>
17 Eigen::MatrixXd sample_triangle(
21 const Eigen::MatrixXd &coords)
26 Eigen::MatrixXd
V(coords.rows(), a.size());
27 for (
int i = 0; i < coords.rows(); i++)
29 V.row(i) = coords(i, 0) * (b - a) + coords(i, 1) * (c - a) + a;
36 const Eigen::MatrixXd &
V,
37 const Eigen::MatrixXi &
F,
38 Eigen::MatrixXd &V_out,
39 Eigen::MatrixXi &F_out,
42 std::vector<Eigen::Triplet<double>> _, __;
47 const Eigen::MatrixXd &
V,
48 const Eigen::MatrixXi &
F,
49 const std::vector<Eigen::Triplet<double>> &W,
50 Eigen::MatrixXd &V_out,
51 Eigen::MatrixXi &F_out,
52 std::vector<Eigen::Triplet<double>> &W_out,
57 Eigen::VectorXi indices,
inverse;
58 igl::remove_duplicate_vertices(
59 V,
F, epsilon, V_out, indices,
inverse, F_out);
60 assert(indices.size() == V_out.rows());
64 std::sort(indices.data(), indices.data() + indices.size());
65 std::vector<int> removed_indices;
66 removed_indices.reserve(
V.rows() - indices.size());
67 for (
int i = 0, j = 0; i <
V.rows(); i++)
69 if (j < indices.size() && indices(j) == i)
72 removed_indices.push_back(i);
74 assert(removed_indices.size() ==
V.rows() - indices.size());
75 assert(std::is_sorted(removed_indices.begin(), removed_indices.end()));
79 W_out.reserve(W.size());
80 for (
const Eigen::Triplet<double> &w : W)
82 if (!std::binary_search(removed_indices.begin(), removed_indices.end(), w.row()))
83 W_out.emplace_back(
inverse(w.row()), w.col(), w.value());
90 for (
int i = 0; i <
F.cols(); i++)
94 (
V(
F.col(i), Eigen::all) -
V(
F.col((i + 1) %
F.cols()), Eigen::all))
105 const int n, Eigen::MatrixXd &
V, Eigen::MatrixXi &
F)
107 const double delta = 1.0 / (n - 1);
109 Eigen::MatrixXd ij2v = Eigen::MatrixXd::Constant(n, n, -1);
110 V.resize(n * (n + 1) / 2, 2);
113 for (
int i = 0; i < n; i++)
115 for (
int j = 0; j < n - i; j++)
118 V.row(vi++) << i * delta, j * delta;
121 assert(vi ==
V.rows());
124 F.resize((n - 1) * (n - 1), 3);
127 for (
int i = 0; i < n - 1; i++)
129 for (
int j = 0; j < n - 1; j++)
131 f << ij2v(i, j), ij2v(i + 1, j), ij2v(i, j + 1);
132 if (f.x() >= 0 && f.y() >= 0 && f.z() >= 0)
137 f << ij2v(i + 1, j), ij2v(i + 1, j + 1), ij2v(i, j + 1);
138 if (f.x() >= 0 && f.y() >= 0 && f.z() >= 0)
145 F.conservativeResize(fi, Eigen::NoChange);
149 const Eigen::MatrixXd &
V,
150 const Eigen::MatrixXi &
F,
151 const double out_max_edge_length,
152 Eigen::MatrixXd &V_out,
153 Eigen::MatrixXi &F_out)
158 std::max(1,
int(std::ceil(in_max_edge_length / out_max_edge_length)))
161 Eigen::MatrixXd coords;
162 Eigen::MatrixXi local_F;
165 Eigen::MatrixXd V_tmp(
F.rows() * coords.rows(),
V.cols());
166 Eigen::MatrixXi F_tmp(
F.rows() * local_F.rows(),
F.cols());
167 for (
int i = 0; i <
F.rows(); i++)
169 F_tmp.middleRows(i * local_F.rows(), local_F.rows()) =
170 local_F.array() + i * coords.rows();
171 V_tmp.middleRows(i * coords.rows(), coords.rows()) = sample_triangle(
172 V.row(
F(i, 0)),
V.row(
F(i, 1)),
V.row(
F(i, 2)), coords);
186 Eigen::MatrixXd
V(n + 1, a.size());
187 for (
int i = 0; i <= n; i++)
189 V.row(i) = (b - a) * (i /
double(n)) + a;
198 const double max_edge_len,
202 const int Nab = std::ceil((b - a).norm() / max_edge_len);
203 const int Nbc = std::ceil((c - b).norm() / max_edge_len);
204 const int Nca = std::ceil((a - c).norm() / max_edge_len);
205 V.resize(Nab + Nbc + Nca, a.size());
206 V.topRows(Nab) =
refine_edge(a, b, max_edge_len).topRows(Nab);
207 V.middleRows(Nab, Nbc) =
refine_edge(b, c, max_edge_len).topRows(Nbc);
208 V.bottomRows(Nca) =
refine_edge(c, a, max_edge_len).topRows(Nca);
210 E.resize(
V.rows(), 2);
211 for (
int i = 0; i <
V.rows(); i++)
213 E.row(i) << i, (i + 1) %
V.rows();
218 const Eigen::Vector3d &a,
219 const Eigen::Vector3d &b,
220 const Eigen::Vector3d &c,
225#ifdef POLYFEM_WITH_TRIANGLE
233 const Eigen::Matrix3d R =
234 Eigen::Quaterniond::FromTwoVectors(
235 (b - a).
cross(c - a).normalized(), Eigen::Vector3d::UnitZ())
239 Eigen::MatrixXd V_2D =
V * R.transpose();
240 const double z = V_2D(0, 2);
241 assert((abs(V_2D.col(2).array() -
z) < 1e-10).all());
242 V_2D.conservativeResize(Eigen::NoChange, 2);
244 igl::triangle::triangulate(
245 V_2D, E, Eigen::MatrixXi(), fmt::format(
"Ya{:f}qQ", max_area),
V,
F);
247 V.conservativeResize(
V.rows(), 3);
248 V.col(2).setConstant(
z);
253 for (
int i = 0; i <
F.rows(); i++)
257 F.row(fi++) =
F.row(i);
260 F.conservativeResize(fi, Eigen::NoChange);
267 const Eigen::Vector3d &a,
268 const Eigen::Vector3d &b,
269 const Eigen::Vector3d &c,
278 UV.resize(
V.rows(), 2);
279 for (
int i = 0; i < UV.rows(); i++)
281 Eigen::RowVector3d tmp;
282 igl::barycentric_coordinates(
283 V.row(i), a.transpose(), b.transpose(), c.transpose(), tmp);
284 UV.row(i) = tmp.head<2>();
289 const Eigen::MatrixXd &
V,
290 const Eigen::MatrixXi &
F,
292 Eigen::MatrixXd &V_out,
293 Eigen::MatrixXi &F_out)
295 Eigen::MatrixXd V_tmp(0,
V.cols());
296 Eigen::MatrixXi F_tmp(0,
F.cols());
297 for (
int i = 0; i <
F.rows(); i++)
299 Eigen::MatrixXd local_V;
300 Eigen::MatrixXi local_F;
305 F_tmp.conservativeResize(F_tmp.rows() + local_F.rows(), Eigen::NoChange);
306 F_tmp.bottomRows(local_F.rows()) = local_F.array() + V_tmp.rows();
308 V_tmp.conservativeResize(V_tmp.rows() + local_V.rows(), Eigen::NoChange);
309 V_tmp.bottomRows(local_V.rows()) = local_V;
Eigen::Matrix< double, dim, 1 > cross(const Eigen::Matrix< double, dim, 1 > &x, const Eigen::Matrix< double, dim, 1 > &y)
Eigen::MatrixXd refine_edge(const VectorNd &a, const VectorNd &b, const double max_edge_length)
Refine an edge (a, b) so each refined edge has length at most max_edge_length.
void irregular_triangle(const Eigen::Vector3d &a, const Eigen::Vector3d &b, const Eigen::Vector3d &c, const double max_edge_length, Eigen::MatrixXd &V, Eigen::MatrixXi &F)
Refine a triangle (a, b, c) into a well shaped triangle mesh.
void irregular_tessellation(const Eigen::MatrixXd &V, const Eigen::MatrixXi &F, const double max_edge_length, Eigen::MatrixXd &V_out, Eigen::MatrixXi &F_out)
Tessilate a triangle mesh (V, F) with well shaped triangles.
double max_edge_length(const Eigen::MatrixXd &V, const Eigen::MatrixXi &F)
Compute the maximum edge length of a triangle mesh (V, F)
void regular_grid_triangle_barycentric_coordinates(const int n, Eigen::MatrixXd &V, Eigen::MatrixXi &F)
Compute the barycentric coordinates of a regular grid of triangles.
void irregular_triangle_barycentric_coordinates(const Eigen::Vector3d &a, const Eigen::Vector3d &b, const Eigen::Vector3d &c, const double max_edge_length, Eigen::MatrixXd &UV, Eigen::MatrixXi &F)
Refine a triangle (a, b, c) into a well shaped triangle mesh.
void regular_grid_tessellation(const Eigen::MatrixXd &V, const Eigen::MatrixXi &F, const double out_max_edge_length, Eigen::MatrixXd &V_out, Eigen::MatrixXi &F_out)
Tessilate a triangle mesh (V, F) with regular grids of triangles of maximum edge length.
void refine_triangle_edges(const VectorNd &a, const VectorNd &b, const VectorNd &c, const double max_edge_len, Eigen::MatrixXd &V, Eigen::MatrixXi &E)
Refine the edges of a triangle (a, b, c) so each refined edge has length at most max_edge_length.
void stitch_mesh(const Eigen::MatrixXd &V, const Eigen::MatrixXi &F, Eigen::MatrixXd &V_out, Eigen::MatrixXi &F_out, const double epsilon)
Stitch a triangle mesh (V, F) together by removing duplicate vertices.
Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic, 0, 3, 3 > inverse(const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic, 0, 3, 3 > &mat)
double triangle_area(const Eigen::MatrixXd V)
Compute the signed area of a triangle defined by three points.
Eigen::Matrix< double, Eigen::Dynamic, 1, 0, 3, 1 > VectorNd
void log_and_throw_error(const std::string &msg)