13#include <wmtk/utils/DisableWarnings.hpp>
14#include <igl/barycenter.h>
15#include <igl/exterior_edges.h>
16#include <igl/median.h>
17#include <igl/remove_duplicate_vertices.h>
18#include <igl/winding_number.h>
19#include <wmtk/utils/EnableWarnings.hpp>
25namespace wmtk::utils {
54 Eigen::MatrixXi SVI, SVJ, SF;
55 igl::remove_duplicate_vertices(V, F, 0.0, m_V, SVI, SVJ, SF);
56 add_node(std::move(SF));
71 Eigen::RowVector3d min_corner, max_corner;
72 int left = -1, right = -1;
76 static Eigen::MatrixXi
cap_of(
const Eigen::MatrixXi& F)
78 const Eigen::MatrixXi E = igl::exterior_edges(F);
79 if (E.size() == 0)
return Eigen::MatrixXi(0, 3);
80 const int s = E(0, 0);
81 std::vector<Eigen::Index> rows;
82 for (Eigen::Index i = 0; i < E.rows(); ++i) {
83 if (E(i, 0) != s && E(i, 1) != s) rows.push_back(i);
85 Eigen::MatrixXi cap(rows.size(), 3);
86 for (
size_t k = 0; k < rows.size(); ++k) {
87 cap.row(k) << s, E(rows[k], 0), E(rows[k], 1);
92 int add_node(Eigen::MatrixXi F)
96 n.min_corner.setConstant(std::numeric_limits<double>::infinity());
97 n.max_corner.setConstant(-std::numeric_limits<double>::infinity());
98 for (Eigen::Index i = 0; i < F.rows(); ++i) {
99 for (Eigen::Index j = 0; j < F.cols(); ++j) {
100 n.min_corner = n.min_corner.cwiseMin(m_V.row(F(i, j)));
101 n.max_corner = n.max_corner.cwiseMax(m_V.row(F(i, j)));
105 m_nodes.push_back(std::move(n));
106 return int(m_nodes.size()) - 1;
113 const Eigen::Index n_faces = m_nodes[node].F.rows();
114 if (n_faces <=
kMinFaces || m_nodes[node].cap.rows() - 2 >= n_faces)
return;
117 double longest = -std::numeric_limits<double>::infinity();
118 for (
int d = 0; d < 3; ++d) {
119 const double len = m_nodes[node].max_corner[d] - m_nodes[node].min_corner[d];
126 igl::barycenter(m_V, m_nodes[node].F, BC);
128 igl::median(BC.col(axis), split_value);
130 std::vector<Eigen::Index> left, right;
131 for (Eigen::Index i = 0; i < n_faces; ++i) {
132 (BC(i, axis) <= split_value ? left : right).push_back(i);
134 if (left.empty() || right.empty())
return;
135 const auto rows_of = [&](
const std::vector<Eigen::Index>& rows) {
136 Eigen::MatrixXi F(rows.size(), 3);
137 for (
size_t k = 0; k < rows.size(); ++k) F.row(k) = m_nodes[node].F.row(rows[k]);
140 const int l = add_node(rows_of(left));
141 m_nodes[node].left = l;
143 const int r = add_node(rows_of(right));
144 m_nodes[node].right = r;
148 bool inside(
const Node& n,
const Eigen::RowVector3d& p)
const
151 for (
int d = 0; d < 3; ++d) {
152 if (p[d] < n.min_corner[d] || p[d] > n.max_corner[d])
return false;
160 const Node& n = m_nodes[node];
168 return igl::winding_number(m_V, n.F, p);
171 if (n.cap.rows() - 2 < n.F.rows())
return igl::winding_number(m_V, n.cap, p);
172 return igl::winding_number(m_V, n.F, p);
176 std::vector<Node> m_nodes;
The hierarchy libigl's winding_number(V, F, O, W) evaluates a triangle mesh with – igl::WindingNumber...
Definition WindingNumberHierarchy.hpp:50
static Eigen::MatrixXi cap_of(const Eigen::MatrixXi &F)
igl::triangle_fan(igl::exterior_edges(F)), with a fixed apex instead of a random one.
Definition WindingNumberHierarchy.hpp:76
double node_winding_number(const int node, const Eigen::RowVector3d &p) const
WindingNumberTree::winding_number, exact method.
Definition WindingNumberHierarchy.hpp:158
static constexpr Eigen::Index kMinFaces
Fewest faces a node is split at, as igl's WindingNumberAABB_MIN_F.
Definition WindingNumberHierarchy.hpp:65
double winding_number(const Eigen::RowVector3d &p) const
Winding number of p with respect to the mesh.
Definition WindingNumberHierarchy.hpp:61
void grow(const int node)
WindingNumberAABB::grow with the median split.
Definition WindingNumberHierarchy.hpp:110
Definition WindingNumberHierarchy.hpp:68