18 #include <igl/remove_duplicate_vertices.h>
19 #include <igl/unique_rows.h>
21 #include <fastenvelope/FastEnvelope.h>
22 #include <SimpleBVH/BVH.hpp>
24 #include <polysolve/Utils.hpp>
28 #include <unordered_set>
31 #include <tbb/concurrent_unordered_set.h>
32 #include <tbb/concurrent_vector.h>
33 #include <tbb/parallel_for.h>
34 #include <tbb/parallel_sort.h>
46 static int next(
int min,
int max)
48 static std::mt19937 gen(42);
49 int res = (gen() - std::mt19937::min()) /
50 double(std::mt19937::max() - std::mt19937::min()) * (max - min) +
59 for (
int i = vec.size() - 1; i > 0; --i) {
61 const int index =
next(0, i + 1);
62 swap(vec[i], vec[index]);
76 const std::vector<Eigen::Vector3d>&
vertices,
77 const std::vector<Eigen::Vector3i>&
faces,
86 m_bvh = std::make_shared<SimpleBVH::BVH>();
88 Eigen::MatrixXd V(
vertices.size(), 3);
93 m_facets.push_back({{V.row(F(i, 0)), V.row(F(i, 1)), V.row(F(i, 2))}});
96 m_bvh->init(V, F, SCALAR_ZERO);
99 bool is_out(
const std::array<Vector3, 3>& triangle)
const
109 SimpleBVH::VectorMax3d nearest_point;
110 double sq_dist = std::numeric_limits<double>::max();
112 if (prev_facet >= 0) {
113 m_bvh->point_facet_distance(p, prev_facet, nearest_point, sq_dist);
127 static const double sqrt3_2 = std::sqrt(3) / 2;
137 std::array<double, 3> ls;
138 for (
int i = 0; i < 3; i++) {
139 ls[i] = (vs[i] - vs[
mod3(i + 1)]).squaredNorm();
142 auto min_max = std::minmax_element(ls.begin(), ls.end());
143 const int min_i = min_max.first - ls.begin();
144 const int max_i = min_max.second - ls.begin();
153 if (N ==
int(N)) N -= 1;
165 for (
int n = 1; n < N; n++) {
172 const double h = (v2v0.dot(v1v0) * v1v0 / ls[max_i] - v2v0).norm();
182 const double sin_v0 = (v2v0.cross(v1v0)).norm() / (v2v0.norm() * v1v0.norm());
183 const double tan_v0 = (v2v0.cross(v1v0)).norm() / v2v0.dot(v1v0);
185 const double tan_v1 = -(v2v1.cross(v1v0)).norm() / (v2v1).dot(v1v0);
187 const double sin_v1 = (v2v1.cross(v1v0)).norm() / (v2v1.norm() * v1v0.norm());
189 for (
int m = 1; m <= M; m++) {
190 int n = sqrt3_2 / tan_v0 * m + 0.5;
191 int n1 = sqrt3_2 / tan_v0 * m;
192 if (m % 2 == 0 && n == n1) {
199 double delta_d = ((n + (m % 2) / 2.0) - m * sqrt3_2 / tan_v0) *
m_sampling_dist;
202 for (
int i = 0; i <= N1; i++) {
212 if (N ==
int(N)) N -= 1;
214 for (
int n = 1; n <= N; n++) {
223 if (N ==
int(N)) N -= 1;
226 for (
int n = 1; n <= N; n++) {
238 SimpleBVH::VectorMax3d nearest_point;
241 m_bvh->nearest_facet(p, nearest_point, sq_dist);
242 p[0] = nearest_point[0];
243 p[1] = nearest_point[1];
244 p[2] = nearest_point[2];
248 std::shared_ptr<fastEnvelope::FastEnvelope>
m_envelope =
nullptr;
249 std::shared_ptr<SimpleBVH::BVH>
m_bvh =
nullptr;
253 std::vector<std::array<SimpleBVH::VectorMax3d, 3>>
m_facets;
288 void one_ring_edge_set(
289 const std::vector<std::array<int, 2>>&
edges,
290 const std::vector<bool>& v_is_removed,
291 const std::vector<bool>& f_is_removed,
292 const std::vector<std::unordered_set<int>>& conn_fs,
293 const std::vector<Vector3>& input_vertices,
294 std::vector<int>& safe_set)
296 std::vector<int> indices(
edges.size());
297 std::iota(std::begin(indices), std::end(indices), 0);
300 std::vector<bool> unsafe_face(f_is_removed.size(),
false);
302 for (
const int e_id : indices) {
303 const auto e =
edges[e_id];
304 if (v_is_removed[e[0]] || v_is_removed[e[1]])
continue;
309 for (
const int f : conn_fs[e[0]]) {
310 if (f_is_removed[f])
continue;
312 if (unsafe_face[f]) {
318 for (
const int f : conn_fs[e[1]]) {
319 if (f_is_removed[f])
continue;
321 if (unsafe_face[f]) {
328 safe_set.push_back(e_id);
330 for (
const int f : conn_fs[e[0]]) {
331 if (f_is_removed[f])
continue;
333 assert(!unsafe_face[f]);
334 unsafe_face[f] =
true;
336 for (
const int f : conn_fs[e[1]]) {
337 if (f_is_removed[f])
continue;
340 unsafe_face[f] =
true;
347 const std::unordered_set<int>& s1,
348 const std::unordered_set<int>& s2,
351 if (s2.size() < s1.size()) {
356 v.reserve(std::min(s1.size(), s2.size()));
365 template <
typename T>
368 std::sort(v.begin(), v.end());
369 v.erase(std::unique(v.begin(), v.end()), v.end());
381 double res = v1.dot(v2) / (v1.norm() * v2.norm());
382 if (res > 1)
return 1;
383 if (res < -1)
return -1;
389 std::vector<Vector3>& input_vertices,
390 std::vector<Vector3i>& input_faces,
391 const double duplicate_tol)
393 Eigen::MatrixXd V_tmp(input_vertices.size(), 3), V_in;
394 Eigen::MatrixXi F_tmp(input_faces.size(), 3), F_in;
395 for (
int i = 0; i < input_vertices.size(); i++) V_tmp.row(i) = input_vertices[i];
396 for (
int i = 0; i < input_faces.size(); i++) F_tmp.row(i) = input_faces[i];
398 Eigen::VectorXi IV, _;
399 igl::remove_duplicate_vertices(V_tmp, F_tmp, duplicate_tol, V_in, IV, _, F_in);
401 for (
int i = 0; i < F_in.rows(); i++) {
403 for (
int j = 1; j < 3; j++) {
404 if (F_in(i, j) < F_in(i, j_min)) j_min = j;
406 if (j_min == 0)
continue;
407 int v0_id = F_in(i, j_min);
408 int v1_id = F_in(i, (j_min + 1) % 3);
409 int v2_id = F_in(i, (j_min + 2) % 3);
410 F_in.row(i) << v0_id, v1_id, v2_id;
414 igl::unique_rows(F_in, F_tmp, IF, _);
417 if (V_in.rows() == 0 || F_in.rows() == 0)
return;
419 logger().trace(
"remove duplicates: ");
420 logger().trace(
"#v: {} -> {}", input_vertices.size(), V_in.rows());
421 logger().trace(
"#f: {} -> {}", input_faces.size(), F_in.rows());
423 input_vertices.resize(V_in.rows());
425 input_faces.reserve(F_in.rows());
426 for (
int i = 0; i < V_in.rows(); i++) input_vertices[i] = V_in.row(i);
427 for (
int i = 0; i < F_in.rows(); i++) {
428 if (F_in(i, 0) == F_in(i, 1) || F_in(i, 0) == F_in(i, 2) || F_in(i, 2) == F_in(i, 1))
430 if (i > 0 && (F_in(i, 0) == F_in(i - 1, 0) && F_in(i, 1) == F_in(i - 1, 2) &&
431 F_in(i, 2) == F_in(i - 1, 1)))
434 Vector3 u = V_in.row(F_in(i, 1)) - V_in.row(F_in(i, 0));
435 Vector3 v = V_in.row(F_in(i, 2)) - V_in.row(F_in(i, 0));
437 if (area.norm() / 2 <= duplicate_tol)
continue;
438 input_faces.push_back(F_in.row(i));
443 std::vector<Vector3>& input_vertices,
444 std::vector<Vector3i>& input_faces,
446 std::vector<bool>& v_is_removed,
447 std::vector<bool>& f_is_removed,
448 std::vector<std::unordered_set<int>>& conn_fs)
451 std::vector<std::array<int, 2>>
edges;
452 tbb::concurrent_vector<std::array<int, 2>> edges_tbb;
454 const auto build_edges = [&]() {
456 edges.reserve(input_faces.size() * 3);
459 edges_tbb.reserve(input_faces.size() * 3);
461 tbb::parallel_for(
size_t(0), input_faces.size(), [&](
size_t f_id) {
462 if (f_is_removed[f_id]) return;
464 for (int j = 0; j < 3; j++) {
465 std::array<int, 2> e = {{input_faces[f_id][j], input_faces[f_id][mod3(j + 1)]}};
466 if (e[0] > e[1]) std::swap(e[0], e[1]);
467 edges_tbb.push_back(e);
471 edges.reserve(edges_tbb.size());
472 edges.insert(
edges.end(), edges_tbb.begin(), edges_tbb.end());
473 assert(edges_tbb.size() ==
edges.size());
474 tbb::parallel_sort(
edges.begin(),
edges.end());
479 std::vector<std::array<int, 2>>
edges;
480 edges.reserve(input_faces.size() * 3);
481 for (
size_t f_id = 0; f_id < input_faces.size(); ++f_id) {
482 if (f_is_removed[f_id])
continue;
484 const auto& f = input_faces[f_id];
485 for (
int j = 0; j < 3; j++) {
486 std::array<int, 2> e = {{f[j], f[
mod3(j + 1)]}};
487 if (e[0] > e[1]) std::swap(e[0], e[1]);
493 std::priority_queue<ElementInQueue, std::vector<ElementInQueue>, cmp_s> sm_queue;
494 for (
auto& e :
edges) {
495 double weight = (input_vertices[e[0]] - input_vertices[e[1]]).squaredNorm();
496 sm_queue.push(ElementInQueue(e, weight));
497 sm_queue.push(ElementInQueue(std::array<int, 2>({{e[1], e[0]}}), weight));
501 auto is_onering_clean = [&](
int v_id) {
502 std::vector<int> v_ids;
503 v_ids.reserve(conn_fs[v_id].size() * 2);
504 for (
const auto& f_id : conn_fs[v_id]) {
505 for (
int j = 0; j < 3; j++) {
506 if (input_faces[f_id][j] != v_id) v_ids.push_back(input_faces[f_id][j]);
509 std::sort(v_ids.begin(), v_ids.end());
511 if (v_ids.size() % 2 != 0)
return false;
512 for (
int i = 0; i < v_ids.size(); i += 2) {
513 if (v_ids[i] != v_ids[i + 1])
return false;
519 static const int SUC = 1;
520 static const int FAIL_CLEAN = 0;
521 static const int FAIL_FLIP = -1;
522 static const int FAIL_ENV = -2;
524 auto remove_an_edge = [&](
int v1_id,
int v2_id,
const std::vector<int>& n12_f_ids) {
525 if (!is_onering_clean(v1_id) || !is_onering_clean(v2_id))
return FAIL_CLEAN;
528 std::vector<int> new_f_ids;
529 for (
int f_id : conn_fs[v1_id]) {
530 if (f_id != n12_f_ids[0] && f_id != n12_f_ids[1]) new_f_ids.push_back(f_id);
532 for (
int f_id : conn_fs[v2_id]) {
533 if (f_id != n12_f_ids[0] && f_id != n12_f_ids[1]) new_f_ids.push_back(f_id);
538 Vector3 p = (input_vertices[v1_id] + input_vertices[v2_id]) / 2;
539 tree.project_to_sf(p);
549 for (
int f_id : new_f_ids) {
551 (input_vertices[input_faces[f_id][1]] - input_vertices[input_faces[f_id][2]])
553 input_vertices[input_faces[f_id][0]] -
554 input_vertices[input_faces[f_id][2]]);
556 for (
int j = 0; j < 3; j++) {
557 if (input_faces[f_id][j] == v1_id || input_faces[f_id][j] == v2_id) {
558 Vector3 new_nv = (input_vertices[input_faces[f_id][
mod3(j + 1)]] -
559 input_vertices[input_faces[f_id][
mod3(j + 2)]])
560 .cross(p - input_vertices[input_faces[f_id][
mod3(j + 2)]]);
561 if (old_nv.dot(new_nv) <= 0)
return FAIL_FLIP;
563 if (new_nv.norm() / 2 <= SCALAR_ZERO_2)
return FAIL_FLIP;
570 for (
int f_id : new_f_ids) {
571 for (
int j = 0; j < 3; j++) {
572 if (input_faces[f_id][j] == v1_id || input_faces[f_id][j] == v2_id) {
573 const std::array<Vector3, 3> tri = {
575 input_vertices[input_faces[f_id][
mod3(j + 1)]],
576 input_vertices[input_faces[f_id][
mod3(j + 2)]]}};
585 std::vector<int> n_v_ids;
586 for (
int f_id : new_f_ids) {
587 for (
int j = 0; j < 3; j++) {
588 if (input_faces[f_id][j] != v1_id && input_faces[f_id][j] != v2_id)
589 n_v_ids.push_back(input_faces[f_id][j]);
594 v_is_removed[v1_id] =
true;
595 input_vertices[v2_id] = p;
596 for (
int f_id : n12_f_ids) {
597 f_is_removed[f_id] =
true;
598 #ifndef WMTK_WITH_TBB
599 for (
int j = 0; j < 3; j++) {
600 if (input_faces[f_id][j] != v1_id) {
601 conn_fs[input_faces[f_id][j]].erase(f_id);
606 for (
int f_id : conn_fs[v1_id]) {
607 if (f_is_removed[f_id])
continue;
608 conn_fs[v2_id].insert(f_id);
609 for (
int j = 0; j < 3; j++) {
610 if (input_faces[f_id][j] == v1_id) input_faces[f_id][j] = v2_id;
614 #ifndef WMTK_WITH_TBB
616 for (
int v_id : n_v_ids) {
617 double weight = (input_vertices[v2_id] - input_vertices[v_id]).squaredNorm();
618 sm_queue.push(ElementInQueue(std::array<int, 2>({{v2_id, v_id}}), weight));
619 sm_queue.push(ElementInQueue(std::array<int, 2>({{v_id, v2_id}}), weight));
627 std::atomic<int> cnt(0);
633 const int stopping = input_vertices.size() / 10000.;
635 std::vector<int> safe_set;
638 one_ring_edge_set(
edges, v_is_removed, f_is_removed, conn_fs, input_vertices, safe_set);
641 tbb::parallel_for(
size_t(0), safe_set.size(), [&](
size_t i) {
643 std::array<int, 2>& v_ids = edges[safe_set[i]];
648 std::vector<int> n12_f_ids;
649 set_intersection(conn_fs[v_ids[0]], conn_fs[v_ids[1]], n12_f_ids);
651 if (n12_f_ids.size() != 2) return;
654 int res = remove_an_edge(v_ids[0], v_ids[1], n12_f_ids);
655 if (res == SUC) cnt++;
660 tbb::parallel_for(
size_t(0), conn_fs.size(), [&](
size_t i) {
665 std::vector<int> r_f_ids;
666 for (int f_id : conn_fs[i]) {
667 if (f_is_removed[f_id]) r_f_ids.push_back(f_id);
669 for (
int f_id : r_f_ids) conn_fs[i].erase(f_id);
674 }
while (cnt > stopping);
682 while (!sm_queue.empty()) {
683 std::array<int, 2> v_ids = sm_queue.top().v_ids;
684 double old_weight = sm_queue.top().weight;
687 if (v_is_removed[v_ids[0]] || v_is_removed[v_ids[1]])
continue;
688 if (old_weight != (input_vertices[v_ids[0]] - input_vertices[v_ids[1]]).squaredNorm())
691 std::vector<int> n12_f_ids;
693 if (n12_f_ids.size() != 2)
continue;
695 int res = remove_an_edge(v_ids[0], v_ids[1], n12_f_ids);
698 else if (res == FAIL_CLEAN)
700 else if (res == FAIL_FLIP)
702 else if (res == FAIL_ENV)
708 "{} success, {} fail, {} flip, {} out of envelope",
716 std::vector<Vector3>& input_vertices,
717 std::vector<Vector3i>& input_faces,
719 std::vector<bool>& v_is_removed,
720 std::vector<bool>& f_is_removed,
721 std::vector<std::unordered_set<int>>& conn_fs)
723 std::vector<std::array<int, 2>>
edges;
724 edges.reserve(input_faces.size() * 6);
725 for (
int i = 0; i < input_faces.size(); i++) {
726 if (f_is_removed[i])
continue;
727 auto& f = input_faces[i];
728 for (
int j = 0; j < 3; j++) {
729 std::array<int, 2> e = {{f[j], f[
mod3(j + 1)]}};
730 if (e[0] > e[1]) std::swap(e[0], e[1]);
736 std::priority_queue<ElementInQueue, std::vector<ElementInQueue>,
cmp_l> sm_queue;
737 for (
auto& e :
edges) {
738 double weight = (input_vertices[e[0]] - input_vertices[e[1]]).squaredNorm();
740 sm_queue.push(
ElementInQueue(std::array<int, 2>({{e[1], e[0]}}), weight));
744 while (!sm_queue.empty()) {
745 int v1_id = sm_queue.top().v_ids[0];
746 int v2_id = sm_queue.top().v_ids[1];
749 std::vector<int> n12_f_ids;
751 if (n12_f_ids.size() != 2)
continue;
753 std::array<int, 2> n_v_ids = {{-1, -1}};
754 for (
int j = 0; j < 3; j++) {
755 if (n_v_ids[0] < 0 && input_faces[n12_f_ids[0]][j] != v1_id &&
756 input_faces[n12_f_ids[0]][j] != v2_id)
757 n_v_ids[0] = input_faces[n12_f_ids[0]][j];
759 if (n_v_ids[1] < 0 && input_faces[n12_f_ids[1]][j] != v1_id &&
760 input_faces[n12_f_ids[1]][j] != v2_id)
761 n_v_ids[1] = input_faces[n12_f_ids[1]][j];
766 get_angle_cos(input_vertices[n_v_ids[0]], input_vertices[v1_id], input_vertices[v2_id]);
768 get_angle_cos(input_vertices[n_v_ids[1]], input_vertices[v1_id], input_vertices[v2_id]);
769 std::array<Vector3, 2> old_nvs;
770 for (
int f = 0; f < 2; f++) {
771 auto& a = input_vertices[input_faces[n12_f_ids[f]][0]];
772 auto& b = input_vertices[input_faces[n12_f_ids[f]][1]];
773 auto& c = input_vertices[input_faces[n12_f_ids[f]][2]];
774 old_nvs[f] = ((b - c).cross(a - c)).normalized();
776 if (cos_a0 > -0.999) {
777 if (old_nvs[0].dot(old_nvs[1]) < 1 - 1e-6)
782 auto& old_nv = cos_a1 < cos_a0 ? old_nvs[0] : old_nvs[1];
783 bool is_filp =
false;
784 for (
int f_id : n12_f_ids) {
785 auto& a = input_vertices[input_faces[f_id][0]];
786 auto& b = input_vertices[input_faces[f_id][1]];
787 auto& c = input_vertices[input_faces[f_id][2]];
788 if (old_nv.dot(((b - c).cross(a - c)).normalized()) < 0) {
793 if (is_filp)
continue;
797 input_vertices[v1_id],
798 input_vertices[n_v_ids[0]],
799 input_vertices[n_v_ids[1]]);
801 input_vertices[v2_id],
802 input_vertices[n_v_ids[0]],
803 input_vertices[n_v_ids[1]]);
804 if (std::min(cos_a0_new, cos_a1_new) <= std::min(cos_a0, cos_a1))
continue;
807 {{input_vertices[v1_id], input_vertices[n_v_ids[0]], input_vertices[n_v_ids[1]]}},
810 {{input_vertices[v2_id], input_vertices[n_v_ids[0]], input_vertices[n_v_ids[1]]}},
816 for (
int j = 0; j < 3; j++) {
817 if (input_faces[n12_f_ids[0]][j] == v2_id) input_faces[n12_f_ids[0]][j] = n_v_ids[1];
818 if (input_faces[n12_f_ids[1]][j] == v1_id) input_faces[n12_f_ids[1]][j] = n_v_ids[0];
820 conn_fs[v1_id].erase(n12_f_ids[1]);
821 conn_fs[v2_id].erase(n12_f_ids[0]);
822 conn_fs[n_v_ids[0]].insert(n12_f_ids[1]);
823 conn_fs[n_v_ids[1]].insert(n12_f_ids[0]);
827 logger().trace(
"{} faces are swapped!!", cnt);
833 std::vector<Vector3>& input_vertices,
834 std::vector<Vector3i>& input_faces,
836 const double duplicate_tol)
840 std::vector<bool> v_is_removed(input_vertices.size(),
false);
841 std::vector<bool> f_is_removed(input_faces.size(),
false);
843 std::vector<std::unordered_set<int>> conn_fs(input_vertices.size());
845 for (
int i = 0; i < input_faces.size(); i++) {
846 for (
int j = 0; j < 3; j++) conn_fs[input_faces[i][j]].insert(i);
849 double collapsing_time, swapping_time, cleanup_time;
852 POLYSOLVE_SCOPED_STOPWATCH(
"Collapsing", collapsing_time,
logger());
853 collapsing(input_vertices, input_faces, tree, v_is_removed, f_is_removed, conn_fs);
857 POLYSOLVE_SCOPED_STOPWATCH(
"Swapping", swapping_time,
logger());
858 swapping(input_vertices, input_faces, tree, v_is_removed, f_is_removed, conn_fs);
863 POLYSOLVE_SCOPED_STOPWATCH(
"Cleanup", cleanup_time,
logger());
864 std::vector<int> map_v_ids(input_vertices.size(), -1);
866 for (
int i = 0; i < input_vertices.size(); i++) {
867 if (v_is_removed[i] || conn_fs[i].empty())
continue;
872 std::vector<Vector3> new_input_vertices(cnt);
874 for (
int i = 0; i < input_vertices.size(); i++) {
875 if (v_is_removed[i] || conn_fs[i].empty())
continue;
876 new_input_vertices[cnt++] = input_vertices[i];
878 input_vertices = new_input_vertices;
882 for (
int i = 0; i < input_faces.size(); i++) {
883 if (f_is_removed[i])
continue;
884 for (
int j = 0; j < 3; j++) input_faces[i][j] = map_v_ids[input_faces[i][j]];
888 std::vector<Vector3i> new_input_faces(cnt);
890 for (
int i = 0; i < input_faces.size(); i++) {
891 if (f_is_removed[i])
continue;
892 new_input_faces[cnt] = input_faces[i];
895 input_faces = new_input_faces;
900 logger().debug(
"#v = {}", input_vertices.size());
901 logger().debug(
"#f = {}", input_faces.size());
904 out[
"collapsing_time"] = collapsing_time;
905 out[
"swapping_time"] = swapping_time;
906 out[
"cleanup_time"] = cleanup_time;
913 const std::string& postion_attr_name,
916 double duplicate_tol,
925 Eigen::MatrixX<int64_t> F;
930 Eigen::VectorXd bmin(V.cols());
931 bmin.setConstant(std::numeric_limits<double>::max());
932 Eigen::VectorXd bmax(V.cols());
933 bmax.setConstant(std::numeric_limits<double>::lowest());
935 std::vector<Eigen::Vector3d>
vertices(V.rows());
936 std::vector<Eigen::Vector3i>
faces(F.rows());
937 for (int64_t i = 0; i < V.rows(); i++) {
939 for (int64_t d = 0; d < bmax.size(); ++d) {
940 bmin[d] = std::min(bmin[d],
vertices[i][d]);
941 bmax[d] = std::max(bmax[d],
vertices[i][d]);
944 for (int64_t i = 0; i < F.rows(); i++)
faces[i] = F.row(i).cast<
int>();
946 const double bbdiag = (bmax - bmin).norm();
948 if (relative) main_eps *= bbdiag;
950 if (duplicate_tol < 0) duplicate_tol = SCALAR_ZERO;
951 if (relative) duplicate_tol *= bbdiag;
953 const double envelope_size = 2 * main_eps * (9 - 2 * sqrt(3)) / 25.0;
954 const double sampling_dist = (8.0 / 15.0) * main_eps;
962 for (int64_t i = 0; i < V.rows(); i++) V.row(i) =
vertices[i];
963 for (int64_t i = 0; i < F.rows(); i++) F.row(i) =
faces[i].cast<int64_t>();
965 auto res = std::make_shared<TriMesh>();
void serialize(MeshWriter &writer, const Mesh *local_root=nullptr) const
bool is_out_using_sampling(const std::array< Vector3, 3 > &vs) const
const double m_sampling_dist
bool is_out_envelope(const SimpleBVH::VectorMax3d &p, int &prev_facet) const
AABBWrapper(const std::vector< Eigen::Vector3d > &vertices, const std::vector< Eigen::Vector3i > &faces, double envelope_size, double sampling_dist, bool use_sampling)
bool is_out(const std::array< Vector3, 3 > &triangle) const
const bool m_use_sampling
const double m_envelope_size2
void project_to_sf(Vector3 &p) const
std::vector< std::array< SimpleBVH::VectorMax3d, 3 > > m_facets
std::shared_ptr< SimpleBVH::BVH > m_bvh
std::shared_ptr< fastEnvelope::FastEnvelope > m_envelope
ElementInQueue(const std::array< int, 2 > &ids, double w)
std::array< int, 2 > v_ids
static void shuffle(std::vector< T > &vec)
static int next(int min, int max)
void get_FV_matrix(MatrixX< int64_t > &matrix)
void get_double_matrix(const std::string &name, const PrimitiveType type, MatrixX< double > &matrix)
void collapsing(std::vector< Vector3 > &input_vertices, std::vector< Vector3i > &input_faces, const AABBWrapper &tree, std::vector< bool > &v_is_removed, std::vector< bool > &f_is_removed, std::vector< std::unordered_set< int >> &conn_fs)
void swapping(std::vector< Vector3 > &input_vertices, std::vector< Vector3i > &input_faces, const AABBWrapper &tree, std::vector< bool > &v_is_removed, std::vector< bool > &f_is_removed, std::vector< std::unordered_set< int >> &conn_fs)
void vector_unique(std::vector< T > &v)
std::tuple< std::shared_ptr< TriMesh >, nlohmann::json > tetwild_simplification(const TriMesh &mesh, const std::string &postion_attr_name, double main_eps, bool relative, double duplicate_tol, bool use_sampling)
Perform the simplification from the original tetwild.
double get_angle_cos(const Vector3 &p, const Vector3 &p1, const Vector3 &p2)
void set_intersection(const std::unordered_set< int > &s1, const std::unordered_set< int > &s2, std::vector< int > &v)
nlohmann::json simplify(std::vector< Vector3 > &input_vertices, std::vector< Vector3i > &input_faces, const AABBWrapper &tree, const double duplicate_tol)
bool is_out_envelope(const std::array< Vector3, 3 > &vs, const AABBWrapper &tree)
void remove_duplicates(std::vector< Vector3 > &input_vertices, std::vector< Vector3i > &input_faces, const double duplicate_tol)
attribute::MeshAttributeHandle set_matrix_attribute(const Mat &data, const std::string &name, const PrimitiveType &type, Mesh &mesh)
std::vector< Tuple > vertices(const Mesh &m, const Simplex &simplex)
std::vector< Tuple > edges(const Mesh &m, const Simplex &simplex)
SimplexCollection faces(const Mesh &mesh, const Simplex &simplex, const bool sort_and_clean)
Returns all faces of a simplex.
spdlog::logger & logger()
Retrieves the current logger.
Vector< double, 3 > Vector3d
bool operator()(const ElementInQueue &e1, const ElementInQueue &e2)
bool operator()(const ElementInQueue &e1, const ElementInQueue &e2)