9#include <SimpleBVH/BVH.hpp>
11#include <igl/barycentric_coordinates.h>
20 using RowMajorMatrixX = Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
26 Eigen::MatrixXd uv_to_uvw(
const Eigen::MatrixXd &uv,
const int local_fid)
28 assert(uv.cols() == 2);
30 Eigen::MatrixXd uvw = Eigen::MatrixXd::Zero(uv.rows(), 3);
35 uvw.col(0) = uv.col(1);
36 uvw.col(1) = uv.col(0);
39 uvw.col(0) = uv.col(0);
40 uvw.col(2) = uv.col(1);
44 uvw.col(2) = 1 - uv.col(0).array() - uv.col(1).array();
47 uvw.col(1) = uv.col(1);
48 uvw.col(2) = uv.col(0);
56 Eigen::MatrixXd extract_face_vertices(
57 const basis::ElementBases &element,
const int local_fid)
59 Eigen::MatrixXd UV(3, 2);
64 const Eigen::MatrixXd UVW = uv_to_uvw(UV, local_fid);
67 element.eval_geom_mapping(UVW,
V);
74 const std::vector<basis::ElementBases> &bases,
75 const std::vector<basis::ElementBases> &geom_bases,
76 const std::vector<LocalBoundary> &total_local_boundary,
80 Eigen::MatrixXd &proxy_vertices,
81 Eigen::MatrixXi &proxy_faces,
82 std::vector<Eigen::Triplet<double>> &displacement_map_entries,
97 std::vector<double> proxy_vertices_list;
98 std::vector<int> proxy_faces_list;
99 std::vector<Eigen::Triplet<double>> displacement_map_entries_tmp;
102 Eigen::MatrixXi F_local;
109 for (
const LocalBoundary &local_boundary : total_local_boundary)
116 for (
int fi = 0; fi < local_boundary.size(); fi++)
118 const int local_fid = local_boundary.local_primitive_id(fi);
123 const Eigen::MatrixXd node_positions = extract_face_vertices(g, local_fid);
125 node_positions.row(0), node_positions.row(1), node_positions.row(2),
130 Eigen::MatrixXd UVW = uv_to_uvw(UV, local_fid);
132 Eigen::MatrixXd V_local;
133 g.eval_geom_mapping(UVW, V_local);
134 assert(V_local.rows() == UV.rows());
136 const int offset = proxy_vertices_list.size() / dim;
137 for (
const double x : V_local.reshaped<Eigen::RowMajor>())
138 proxy_vertices_list.push_back(
x);
139 for (
const int i : F_local.reshaped<Eigen::RowMajor>())
140 proxy_faces_list.push_back(i + offset);
144 assert(basis.global().size() == 1);
145 const int basis_id = basis.global()[0].index;
147 const Eigen::MatrixXd basis_values = basis(UVW);
149 for (
int i = 0; i < basis_values.size(); i++)
151 displacement_map_entries_tmp.emplace_back(
152 offset + i, basis_id, basis_values(i));
160 Eigen::Map<RowMajorMatrixX<double>>(proxy_vertices_list.data(), proxy_vertices_list.size() / dim, dim),
161 Eigen::Map<RowMajorMatrixX<int>>(proxy_faces_list.data(), proxy_faces_list.size() / dim, dim),
162 displacement_map_entries_tmp,
163 proxy_vertices, proxy_faces, displacement_map_entries);
169 const std::vector<basis::ElementBases> &bases,
170 const std::vector<basis::ElementBases> &geom_bases,
171 const std::vector<mesh::LocalBoundary> &total_local_boundary,
174 const Eigen::MatrixXd &proxy_vertices,
175 std::vector<Eigen::Triplet<double>> &displacement_map_entries)
188 if (basis.order() != 1)
189 log_and_throw_error(
"build_collision_proxy_displacement_map() is only implemented for P1 geometry!");
195 std::vector<std::array<Eigen::Vector3d, 2>> boxes(
196 geom_bases.size(), {{Eigen::Vector3d::Zero(), Eigen::Vector3d::Zero()}});
197 for (
int i = 0; i < geom_bases.size(); i++)
199 const Eigen::MatrixXd nodes = geom_bases[i].nodes();
200 boxes[i][0].head(dim) = nodes.colwise().minCoeff();
201 boxes[i][1].head(dim) = nodes.colwise().maxCoeff();
248 for (
int i = 0; i < proxy_vertices.rows(); i++)
250 Eigen::Vector3d v = Eigen::Vector3d::Zero();
251 v.head(dim) = proxy_vertices.row(i);
253 std::vector<unsigned int> candidates;
254 bvh.intersect_box(v, v, candidates);
257 int closest_element_id = -1;
259 for (
const unsigned int element_id : candidates)
261 const Eigen::MatrixXd nodes = geom_bases[element_id].nodes();
264 assert(nodes.rows() == 3);
265 Eigen::RowVector3d bc;
266 igl::barycentric_coordinates(
267 proxy_vertices.row(i), nodes.row(0), nodes.row(1), nodes.row(2), bc);
272 assert(dim == 3 &&
nodes.rows() == 4);
273 Eigen::RowVector4d bc;
274 igl::barycentric_coordinates(
278 if (vhat.minCoeff() >= 0 && vhat.maxCoeff() <= 1 && vhat.sum() <= 1)
280 closest_element_id = element_id;
285 if (closest_element_id < 0)
288 log_and_throw_error(
"build_collision_proxy_displacement_map(): closest point query not implemented!");
304 for (
const basis::Basis &basis : bases[closest_element_id].bases)
306 assert(basis.global().size() == 1);
307 const int j = basis.global()[0].index;
308 displacement_map_entries.emplace_back(i, j, basis(vhat.transpose())(0));
316 const std::string &mesh_filename,
317 const std::string &weights_filename,
318 const Eigen::VectorXi &in_node_to_node,
319 const json &transformation,
320 Eigen::MatrixXd &vertices,
321 Eigen::VectorXi &codim_vertices,
322 Eigen::MatrixXi &edges,
323 Eigen::MatrixXi &
faces,
324 std::vector<Eigen::Triplet<double>> &displacement_map_entries)
331 const std::string &mesh_filename,
332 const json &transformation,
333 Eigen::MatrixXd &vertices,
334 Eigen::VectorXi &codim_vertices,
335 Eigen::MatrixXi &edges,
336 Eigen::MatrixXi &
faces)
338 Eigen::MatrixXi codim_edges;
342 igl::edges(
faces, edges);
344 utils::append_rows(edges, codim_edges);
347 std::array<RowVectorNd, 2> bbox;
348 bbox[0] = vertices.colwise().minCoeff();
349 bbox[1] = vertices.colwise().maxCoeff();
351 if (vertices.cols() > 2 && bbox[0][2] == bbox[1][2] && bbox[0][2] == 0)
353 vertices = vertices.leftCols(2).eval();
354 bbox[0] = vertices.colwise().minCoeff();
355 bbox[1] = vertices.colwise().maxCoeff();
363 (bbox[1] - bbox[0]).cwiseAbs().transpose(),
365 vertices = (vertices * A.transpose()).rowwise() + b.transpose();
369 const std::string &weights_filename,
370 const Eigen::VectorXi &in_node_to_node,
371 const size_t num_proxy_vertices,
372 std::vector<Eigen::Triplet<double>> &displacement_map_entries)
375 const size_t num_fe_nodes = in_node_to_node.size();
377 h5pp::File file(weights_filename, h5pp::FileAccess::READONLY);
378 const std::array<long, 2> shape = file.readAttribute<std::array<long, 2>>(
"weight_triplets",
"shape");
379 assert(shape[0] == num_proxy_vertices && shape[1] == num_fe_nodes);
380 Eigen::VectorXd values = file.readDataset<Eigen::VectorXd>(
"weight_triplets/values");
381 Eigen::VectorXi rows = file.readDataset<Eigen::VectorXi>(
"weight_triplets/rows");
382 Eigen::VectorXi cols = file.readDataset<Eigen::VectorXi>(
"weight_triplets/cols");
383 assert(rows.maxCoeff() < num_proxy_vertices);
384 assert(cols.maxCoeff() < num_fe_nodes);
391 displacement_map_entries.clear();
392 displacement_map_entries.reserve(values.size());
394 assert(in_node_to_node.size() == num_fe_nodes);
395 for (
int i = 0; i < values.size(); i++)
398 displacement_map_entries.emplace_back(rows[i], in_node_to_node[cols[i]], values[i]);
std::vector< Eigen::VectorXi > faces
Represents one basis function and its gradient.
Stores the basis functions for a given element in a mesh (facet in 2d, cell in 3d).
std::vector< Basis > bases
one basis function per node in the element
Boundary primitive IDs for a single element.
void load_collision_proxy(const std::string &mesh_filename, const std::string &weights_filename, const Eigen::VectorXi &in_node_to_node, const json &transformation, Eigen::MatrixXd &vertices, Eigen::VectorXi &codim_vertices, Eigen::MatrixXi &edges, Eigen::MatrixXi &faces, std::vector< Eigen::Triplet< double > > &displacement_map_entries)
Load a collision proxy mesh and displacement map from files.
void construct_affine_transformation(const double unit_scale, const json &transform, const VectorNd &mesh_dimensions, MatrixNd &A, VectorNd &b)
Construct an affine transformation .
void build_collision_proxy(const std::vector< basis::ElementBases > &bases, const std::vector< basis::ElementBases > &geom_bases, const std::vector< LocalBoundary > &total_local_boundary, const int n_bases, const int dim, const double max_edge_length, Eigen::MatrixXd &proxy_vertices, Eigen::MatrixXi &proxy_faces, std::vector< Eigen::Triplet< double > > &displacement_map_entries, const CollisionProxyTessellation tessellation)
void build_collision_proxy_displacement_map(const std::vector< basis::ElementBases > &bases, const std::vector< basis::ElementBases > &geom_bases, const std::vector< mesh::LocalBoundary > &total_local_boundary, const int n_bases, const int dim, const Eigen::MatrixXd &proxy_vertices, std::vector< Eigen::Triplet< double > > &displacement_map_entries)
Build a collision proxy displacement map for a given mesh and proxy mesh.
void load_collision_proxy_mesh(const std::string &mesh_filename, const json &transformation, Eigen::MatrixXd &vertices, Eigen::VectorXi &codim_vertices, Eigen::MatrixXi &edges, Eigen::MatrixXi &faces)
Load a collision proxy mesh from a file.
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.
CollisionProxyTessellation
@ IRREGULAR
Irregular tessellation of the mesh (requires POLYFEM_WITH_TRIANGLE)
@ REGULAR
Regular tessellation of the mesh.
void load_collision_proxy_displacement_map(const std::string &weights_filename, const Eigen::VectorXi &in_node_to_node, const size_t num_proxy_vertices, std::vector< Eigen::Triplet< double > > &displacement_map_entries)
Load a collision proxy displacement map from files.
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.
bool read_surface_mesh(const std::string &mesh_path, Eigen::MatrixXd &vertices, Eigen::VectorXi &codim_vertices, Eigen::MatrixXi &codim_edges, Eigen::MatrixXi &faces)
read a surface mesh
Eigen::Matrix< double, Eigen::Dynamic, 1, 0, 3, 1 > VectorNd
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor, 3, 3 > MatrixNd
void log_and_throw_error(const std::string &msg)