14#include <wmtk/utils/WindingNumberHierarchy.hpp>
17#include <wmtk/utils/DisableWarnings.hpp>
18#include <igl/remove_unreferenced.h>
19#include <wmtk/utils/EnableWarnings.hpp>
22#include <wmtk/threading/dynamic_parallel_for.hpp>
29namespace wmtk::utils {
32inline constexpr size_t kWindingNumberChunk = 256;
47inline double signed_angle_2d(
double ax,
double ay,
double bx,
double by,
double px,
double py)
50 double o2A[2] = {px - ax, py - ay};
51 double o2B[2] = {px - bx, py - by};
54 for (
int i = 0; i < 2; i++) {
55 o2Al += o2A[i] * o2A[i];
56 o2Bl += o2B[i] * o2B[i];
58 o2Al = std::sqrt(o2Al);
59 o2Bl = std::sqrt(o2Bl);
61 for (
int i = 0; i < 2; i++) {
69 constexpr double two_pi = 2.0 * 3.14159265358979323846;
70 return -std::atan2(o2B[0] * o2A[1] - o2B[1] * o2A[0], o2B[0] * o2A[0] + o2B[1] * o2A[1]) /
84winding_number_2d_point(
const Eigen::MatrixXd& V,
const Eigen::MatrixXi& E,
double px,
double py)
87 for (Eigen::Index f = 0; f < E.rows(); ++f) {
88 const Eigen::Index a = E(f, 0);
89 const Eigen::Index b = E(f, 1);
90 w += detail::signed_angle_2d(V(a, 0), V(a, 1), V(b, 0), V(b, 1), px, py);
100inline void winding_number(
101 const Eigen::MatrixXd& V,
102 const Eigen::MatrixXi& F,
103 const Eigen::MatrixXd& O,
108 if (O.rows() == 0 || F.rows() == 0 || V.rows() == 0)
return;
111 const WindingNumberHierarchy hier(V, F);
122 threading::dynamic_parallel_for(
123 static_cast<size_t>(O.rows()),
124 std::max(num_threads, 1),
126 [&](
const size_t begin,
const size_t end) {
127 for (size_t o = begin; o < end; ++o) {
128 W(o) = hier.winding_number(O.row(o));
139inline bool winding_number_inside(
double w)
145inline bool any_winding_number_inside(
const Eigen::VectorXd& W)
147 return (W.array() > 0.5).any();
159inline bool orient_winding_number(Eigen::VectorXd& W)
161 if (W.size() == 0 || any_winding_number_inside(W))
return false;
179inline void winding_number_by_group(
180 const Eigen::MatrixXd& V,
181 const Eigen::MatrixXi& F,
182 const std::vector<int>& group,
184 const Eigen::MatrixXd& O,
188 assert(group.size() ==
size_t(F.rows()));
189 W.setZero(O.rows(), n_groups);
190 std::vector<std::vector<int>> faces(n_groups);
191 for (Eigen::Index f = 0; f < F.rows(); ++f) {
192 assert(group[f] >= 0 && group[f] < n_groups);
193 faces[group[f]].push_back(
int(f));
195 for (
int g = 0; g < n_groups; ++g) {
196 if (faces[g].empty())
continue;
197 Eigen::MatrixXi Fg(faces[g].size(), 3);
198 for (
size_t i = 0; i < faces[g].size(); ++i) Fg.row(i) = F.row(faces[g][i]);
201 Eigen::MatrixXi Fg_compact;
203 igl::remove_unreferenced(V, Fg, Vg, Fg_compact, I);
205 winding_number(Vg, Fg_compact, O, w, num_threads);
228inline void winding_number_2d(
229 const Eigen::MatrixXd& V,
230 const Eigen::MatrixXi& E,
231 const Eigen::MatrixXd& O,
236 if (O.rows() == 0 || E.rows() == 0 || V.rows() == 0)
return;
239 threading::dynamic_parallel_for(
240 static_cast<size_t>(O.rows()),
241 std::max(num_threads, 1),
243 [&](
const size_t begin,
const size_t end) {
244 for (size_t o = begin; o < end; ++o) {
245 const Eigen::Index i = static_cast<Eigen::Index>(o);
246 W(i) = winding_number_2d_point(V, E, O(i, 0), O(i, 1));