RSMesh 1.0.0
一个曲面重构的系统,输入为点云,输出为obj,stl等主流格式的网格文件,使用的方法为径向基函数插值,采取了并行优化、Intel-MKL等优化措施,支持百万级别的点云
载入中...
搜索中...
未找到
mesh_defect_finder.cpp
1//
2// Created by RainSure on 2024/2/29.
3//
4#include "isosurface/mesh_defects_finder.h"
5#include "isosurface/dense_undirected_graph.h"
6#include "geometry/point3d.h"
7#include <unordered_map>
8
9namespace rsmesh::isosurface {
10 mesh_defects_finder::mesh_defects_finder(const vertices_type& vertices, const faces_type& faces)
11 : vertices_(vertices), faces_(faces), vf_map_(vertices_.rows()) {
12 auto n_faces = faces.rows();
13 for (index_t fi = 0; fi < n_faces; fi++) {
14 auto f = faces.row(fi);
15 vf_map_.at(f(0)).push_back(fi);
16 vf_map_.at(f(1)).push_back(fi);
17 vf_map_.at(f(2)).push_back(fi);
18 }
19 }
20
21// Currently, only intersections between faces that share a single vertex are checked.
22 std::unordered_set<index_t> mesh_defects_finder::intersecting_faces() const {
23 std::unordered_set<index_t> result;
24
25 auto n_vertices = vertices_.rows();
26#pragma omp parallel for schedule(guided, 32)
27 for (index_t vi = 0; vi < n_vertices; vi++) {
28 const auto& fis = vf_map_.at(vi);
29
30 auto n_faces = static_cast<index_t>(fis.size());
31 for (index_t i = 0; i < n_faces - 1; i++) {
32 auto fi = fis.at(i);
33 auto a = next_vertex(fi, vi);
34 auto b = prev_vertex(fi, vi);
35 for (index_t j = i + 1; j < n_faces; j++) {
36 auto fj = fis.at(j);
37 auto c = next_vertex(fj, vi);
38 auto d = prev_vertex(fj, vi);
39
40 if (b == c || a == d) {
41 // Skip the pair of adjacent faces.
42 // As faces are oriented, we don't need to check other combinations.
43 continue;
44 }
45
46 if (segment_triangle_intersect(a, b, fj) || segment_triangle_intersect(c, d, fi)) {
47#pragma omp critical
48 {
49 result.insert(fi);
50 result.insert(fj);
51 }
52 }
53 }
54 }
55 }
56
57 return result;
58 }
59
60 std::unordered_set<index_t> mesh_defects_finder::singular_vertices() const {
61 std::unordered_set<index_t> result;
62
63 auto n_vertices = vertices_.rows();
64#pragma omp parallel for schedule(guided, 32)
65 for (index_t vi = 0; vi < n_vertices; vi++) {
66 const auto& fis = vf_map_.at(vi);
67
68 if (fis.empty()) {
69 // An isolated vertex.
70 continue;
71 }
72
73 std::unordered_map<index_t, index_t> to_local_vi;
74 for (auto fi : fis) {
75 to_local_vi.emplace(next_vertex(fi, vi), to_local_vi.size());
76 to_local_vi.emplace(prev_vertex(fi, vi), to_local_vi.size());
77 }
78
79 auto order = static_cast<index_t>(to_local_vi.size());
80
81 // The graph that represents the link complex of the vertex.
82 dense_undirected_graph g(order);
83
84 for (auto fi : fis) {
85 auto i = to_local_vi.at(next_vertex(fi, vi));
86 auto j = to_local_vi.at(prev_vertex(fi, vi));
87 g.add_edge(i, j);
88 }
89
90 // Check if the graph is a cycle or a path (in case of a boundary vertex).
91 // NOLINTNEXTLINE(readability-simplify-boolean-expr)
92 if (!(g.is_simple() && g.is_connected() && g.max_degree() <= 2)) {
93#pragma omp critical
94 result.insert(vi);
95 }
96 }
97
98 return result;
99 }
100
101 index_t mesh_defects_finder::next_vertex(index_t fi, index_t vi) const {
102 auto f = faces_.row(fi);
103 if (f(0) == vi) {
104 return f(1);
105 }
106 if (f(1) == vi) {
107 return f(2);
108 }
109 return f(0);
110 }
111
112 index_t mesh_defects_finder::prev_vertex(index_t fi, index_t vi) const {
113 auto f = faces_.row(fi);
114 if (f(0) == vi) {
115 return f(2);
116 }
117 if (f(1) == vi) {
118 return f(0);
119 }
120 return f(1);
121 }
122
123 double orient2d_inexact(const geometry::point2d& a, const geometry::point2d& b,
124 const geometry::point2d& c) {
125 Eigen::Matrix2d m;
126 m << a(0) - c(0), a(1) - c(1), b(0) - c(0), b(1) - c(1);
127 return m.determinant();
128 }
129
130 double orient3d_inexact(const geometry::point3d& a, const geometry::point3d& b,
131 const geometry::point3d& c, const geometry::point3d& d) {
132 Eigen::Matrix3d m;
133 m << a(0) - d(0), a(1) - d(1), a(2) - d(2), b(0) - d(0), b(1) - d(1), b(2) - d(2), c(0) - d(0),
134 c(1) - d(1), c(2) - d(2);
135 return m.determinant();
136 }
137
138 double coplanar_orientation(const geometry::point3d& a, const geometry::point3d& b,
139 const geometry::point3d& c) {
140 geometry::point2d a_xy(a(0), a(1));
141 geometry::point2d b_xy(b(0), b(1));
142 geometry::point2d c_xy(c(0), c(1));
143 auto abc_xy = orient2d_inexact(a_xy, b_xy, c_xy);
144 if (abc_xy != 0.0) {
145 return abc_xy;
146 }
147
148 geometry::point2d a_yz(a(1), a(2));
149 geometry::point2d b_yz(b(1), b(2));
150 geometry::point2d c_yz(c(1), c(2));
151 auto abc_yz = orient2d_inexact(a_yz, b_yz, c_yz);
152 if (abc_yz != 0.0) {
153 return abc_yz;
154 }
155
156 geometry::point2d a_zx(a(2), a(0));
157 geometry::point2d b_zx(b(2), b(0));
158 geometry::point2d c_zx(c(2), c(0));
159 auto abc_zx = orient2d_inexact(a_zx, b_zx, c_zx);
160 return abc_zx;
161 }
162
163 bool mesh_defects_finder::segment_triangle_intersect(index_t vi, index_t vj, index_t fi) const {
164 auto f = faces_.row(fi);
165
166 auto a = vertices_.row(f(0));
167 auto b = vertices_.row(f(1));
168 auto c = vertices_.row(f(2));
169 auto p = vertices_.row(vi);
170 auto q = vertices_.row(vj);
171
172 auto abcp = orient3d_inexact(a, b, c, p);
173 auto abcq = orient3d_inexact(a, b, c, q);
174
175 if ((abcp > 0.0 && abcq > 0.0) || (abcp < 0.0 && abcq < 0.0)) {
176 return false;
177 }
178
179 if (abcp == 0.0 && abcq == 0.0) {
180 auto pqa = coplanar_orientation(p, q, a);
181 auto pqb = coplanar_orientation(p, q, b);
182 auto pqc = coplanar_orientation(p, q, c);
183
184 // NOLINTNEXTLINE(readability-simplify-boolean-expr)
185 return !((pqa > 0.0 && pqb > 0.0 && pqc > 0.0) || (pqa < 0.0 && pqb < 0.0 && pqc < 0.0));
186 }
187
188 auto pqab = orient3d_inexact(p, q, a, b);
189 auto pqbc = orient3d_inexact(p, q, b, c);
190 auto pqca = orient3d_inexact(p, q, c, a);
191
192 return (pqab >= 0.0 && pqbc >= 0.0 && pqca >= 0.0) || (pqab <= 0.0 && pqbc <= 0.0 && pqca <= 0.0);
193 }
194}
该命名空间下主要定义了等值面提取相关的类和函数