RSMesh 1.0.0
一个曲面重构的系统,输入为点云,输出为obj,stl等主流格式的网格文件,使用的方法为径向基函数插值,采取了并行优化、Intel-MKL等优化措施,支持百万级别的点云
载入中...
搜索中...
未找到
rmt_lattice.h
1//
2// Created by RainSure on 2024/2/23.
3//
4
5#ifndef RSMESH_RMT_LATTICE_H
6#define RSMESH_RMT_LATTICE_H
7
8#include <array>
9#include <cmath>
10#include <memory>
11#include <unordered_map>
12#include <unordered_set>
13#include <utility>
14#include <vector>
15#include "geometry/point3d.h"
16#include "geometry/bbox3d.h"
17#include "isosurface/isosurface_types.h"
18#include "isosurface/field_function.h"
19#include "isosurface/rmt_node.h"
20#include "isosurface/rmt_node_list.h"
21#include "isosurface/rmt_primitive_lattice.h"
22#include "types.h"
23
24namespace rsmesh::isosurface {
25 inline const std::array<edge_index, 14> OppositeEdge{7, 8, 9, 10, 11, 12, 13, 0, 1, 2, 3, 4, 5, 6};
26
28 friend class rmt_surface;
29
31
32 static constexpr double kZeroValueReplacement = 1e-10;
33
34 rmt_node_list node_list_;
35 std::vector<cell_vector> nodes_to_evaluate_;
36 std::unordered_set<cell_vector> added_cells_;
37 std::vector<cell_vector> last_added_cells_;
38
39 std::vector<geometry::point3d> vertices_;
40 std::unordered_map<vertex_index, vertex_index> cluster_map_;
41
42 static bool has_intersection(const rmt_node* a, const rmt_node* b) {
43 return a != nullptr && b != nullptr && a->value_sign() != b->value_sign();
44 }
45
46 // Add nodes corresponding to eight vertices of the cell.
47 void add_cell(const cell_vector& cv) {
48 if (added_cells_.contains(cv)) {
49 return;
50 }
51
52 add_node(cv);
53 add_node(cv + NeighborCellVectors[4]);
54 add_node(cv + NeighborCellVectors[9]);
55 add_node(cv + NeighborCellVectors[3]);
56 add_node(cv + NeighborCellVectors[13]);
57 add_node(cv + NeighborCellVectors[1]);
58 add_node(cv + NeighborCellVectors[12]);
59 add_node(cv + NeighborCellVectors[0]);
60
61 added_cells_.insert(cv);
62 last_added_cells_.push_back(cv);
63 }
64
65 bool add_node(const cell_vector& cv) {
66 if (node_list_.contains(cv)) {
67 return false;
68 }
69
70 return add_node_unchecked(cv);
71 }
72
73 bool add_node_unchecked(const cell_vector& cv) {
74 auto p = cell_node_point(cv);
75
76 // Due to the numerical error in the rotation of the lattice,
77 // nodes are not perfectly aligned with planes.
78 // Round the position of the node to prevent creation of near-degenerate tetrahedra.
79 auto unit = resolution() / 100.0;
80 p = unit * (p.array() / unit).round();
81
82 if (!extended_bbox().contains(p)) {
83 return false;
84 }
85
86 node_list_.emplace(cv, rmt_node{clamp_to_bbox(p)});
87
88 nodes_to_evaluate_.push_back(cv);
89 return true;
90 }
91
92 geometry::point3d clamp_to_bbox(const geometry::point3d& p) const {
93 return p.array().max(bbox().min().array()).min(bbox().max().array());
94 }
95
96 vertex_index clustered_vertex_index(vertex_index vi) const {
97 return cluster_map_.contains(vi) ? cluster_map_.at(vi) : vi;
98 }
99
100 // Evaluates field values for each node in nodes_to_evaluate_.
101 void evaluate_field(const field_function& field_fn, double isovalue) {
102 if (nodes_to_evaluate_.empty()) {
103 return;
104 }
105
106 geometry::points3d points(nodes_to_evaluate_.size(), 3);
107
108 auto point_it = points.rowwise().begin();
109 for (const auto& cv : nodes_to_evaluate_) {
110 *point_it++ = node_list_.at(cv).position();
111 }
112
113 valuesd values = field_fn(points).array() - isovalue;
114
115 index_t i{};
116 for (const auto& cv : nodes_to_evaluate_) {
117 auto value = values(i);
118 if (value == 0.0) {
119 value = kZeroValueReplacement;
120 }
121
122 node_list_.at(cv).set_value(value);
123 i++;
124 }
125
126 nodes_to_evaluate_.clear();
127 }
128
129 // Removes nodes without any intersections.
130 void remove_free_nodes(const std::vector<cell_vector>& node_cvs) {
131 for (const auto& cv : node_cvs) {
132 auto it = node_list_.find(cv);
133 if (it->second.is_free()) {
134 node_list_.erase(it->first);
135 }
136 }
137 }
138
139 void track_surface() {
140 std::unordered_set<cell_vector> cells_to_add;
141
142 // Check 12 edges of each cell and add neighbor cells adjacent to an edge
143 // at which ends the field values take opposite signs.
144 for (const auto& cv : last_added_cells_) {
145 auto iaaa = cv;
146 auto iaab = cv + NeighborCellVectors[4];
147 auto iaba = cv + NeighborCellVectors[9];
148 auto iabb = cv + NeighborCellVectors[3];
149 auto ibaa = cv + NeighborCellVectors[13];
150 auto ibab = cv + NeighborCellVectors[1];
151 auto ibba = cv + NeighborCellVectors[12];
152 auto ibbb = cv + NeighborCellVectors[0];
153
154 const auto* aaa = node_list_.node_ptr(iaaa);
155 const auto* aab = node_list_.node_ptr(iaab);
156 const auto* aba = node_list_.node_ptr(iaba);
157 const auto* abb = node_list_.node_ptr(iabb);
158 const auto* baa = node_list_.node_ptr(ibaa);
159 const auto* bab = node_list_.node_ptr(ibab);
160 const auto* bba = node_list_.node_ptr(ibba);
161 const auto* bbb = node_list_.node_ptr(ibbb);
162
163 // __a and __b
164 if (has_intersection(aaa, aab)) { // o -> 4
165 cells_to_add.insert(iaaa + NeighborCellVectors[2]);
166 cells_to_add.insert(iaaa + NeighborCellVectors[5]);
167 cells_to_add.insert(iaaa + NeighborCellVectors[6]);
168 }
169 if (has_intersection(aba, abb)) { // 9 -> 3
170 cells_to_add.insert(iaba);
171 cells_to_add.insert(iaba + NeighborCellVectors[5]);
172 cells_to_add.insert(iaba + NeighborCellVectors[6]);
173 }
174 if (has_intersection(baa, bab)) { // 13 -> 1
175 cells_to_add.insert(ibaa);
176 cells_to_add.insert(ibaa + NeighborCellVectors[2]);
177 cells_to_add.insert(ibaa + NeighborCellVectors[5]);
178 }
179 if (has_intersection(bba, bbb)) { // 12 -> 0
180 cells_to_add.insert(ibba);
181 cells_to_add.insert(ibba + NeighborCellVectors[2]);
182 cells_to_add.insert(ibba + NeighborCellVectors[6]);
183 }
184
185 // _a_ and _b_
186 if (has_intersection(aaa, aba)) { // o -> 9
187 cells_to_add.insert(iaaa + NeighborCellVectors[6]);
188 cells_to_add.insert(iaaa + NeighborCellVectors[8]);
189 cells_to_add.insert(iaaa + NeighborCellVectors[11]);
190 }
191 if (has_intersection(aab, abb)) { // 4 -> 3
192 cells_to_add.insert(iaab);
193 cells_to_add.insert(iaab + NeighborCellVectors[6]);
194 cells_to_add.insert(iaab + NeighborCellVectors[8]);
195 }
196 if (has_intersection(baa, bba)) { // 13 -> 12
197 cells_to_add.insert(ibaa);
198 cells_to_add.insert(ibaa + NeighborCellVectors[8]);
199 cells_to_add.insert(ibaa + NeighborCellVectors[11]);
200 }
201 if (has_intersection(bab, bbb)) { // 1 -> 0
202 cells_to_add.insert(ibab);
203 cells_to_add.insert(ibab + NeighborCellVectors[6]);
204 cells_to_add.insert(ibab + NeighborCellVectors[11]);
205 }
206
207 // a__ and b__
208 if (has_intersection(aaa, baa)) { // o -> 13
209 cells_to_add.insert(iaaa + NeighborCellVectors[2]);
210 cells_to_add.insert(iaaa + NeighborCellVectors[10]);
211 cells_to_add.insert(iaaa + NeighborCellVectors[11]);
212 }
213 if (has_intersection(aab, bab)) { // 4 -> 1
214 cells_to_add.insert(iaab);
215 cells_to_add.insert(iaab + NeighborCellVectors[2]);
216 cells_to_add.insert(iaab + NeighborCellVectors[10]);
217 }
218 if (has_intersection(aba, bba)) { // 9 -> 12
219 cells_to_add.insert(iaba);
220 cells_to_add.insert(iaba + NeighborCellVectors[10]);
221 cells_to_add.insert(iaba + NeighborCellVectors[11]);
222 }
223 if (has_intersection(abb, bbb)) { // 3 -> 0
224 cells_to_add.insert(iabb);
225 cells_to_add.insert(iabb + NeighborCellVectors[2]);
226 cells_to_add.insert(iabb + NeighborCellVectors[11]);
227 }
228 }
229
230 last_added_cells_.clear();
231
232 for (const auto& cv : cells_to_add) {
233 add_cell(cv);
234 }
235 }
236
237 void update_neighbor_cache() {
238 for (auto& cv_node : node_list_) {
239 const auto& cv = cv_node.first;
240 auto& node = cv_node.second;
241
242 auto neighbors = std::make_unique<std::array<rmt_node*, 14>>();
243
244 for (edge_index ei = 0; ei < 14; ei++) {
245 neighbors->at(ei) = node_list_.neighbor_node_ptr(cv, ei);
246 }
247
248 node.set_neighbors(std::move(neighbors));
249 }
250 }
251
252 public:
253 rmt_lattice(const geometry::bbox3d& bbox, double resolution) : base(bbox, resolution) {}
254
255 // Add all nodes inside the boundary.
256 void add_all_nodes(const field_function& field_fn, double isovalue) {
257 std::vector<cell_vector> new_nodes;
258 std::vector<cell_vector> prev_nodes;
259
260 for (auto cv2 = cv_min(2); cv2 <= cv_max(2); cv2++) {
261 for (auto cv1 = cv_min(1); cv1 <= cv_max(1); cv1++) {
262 for (auto cv0 = cv_min(0); cv0 <= cv_max(0); cv0++) {
263 cell_vector cv(cv0, cv1, cv2);
264 if (add_node_unchecked(cv)) {
265 new_nodes.push_back(cv);
266 }
267 }
268 }
269
270 if (cv2 > cv_min(2)) {
271 evaluate_field(field_fn, isovalue);
272 generate_vertices(prev_nodes);
273 remove_free_nodes(prev_nodes);
274 }
275
276 prev_nodes.swap(new_nodes);
277 new_nodes.clear();
278 }
279
280 remove_free_nodes(prev_nodes);
281
282 update_neighbor_cache();
283 }
284
285 void add_nodes_by_tracking(const field_function& field_fm, double isovalue) {
286 evaluate_field(field_fm, isovalue);
287 while (!last_added_cells_.empty()) {
288 track_surface();
289 evaluate_field(field_fm, isovalue);
290 }
291
292 std::vector<cell_vector> all_nodes;
293 for (const auto& cv_node : node_list_) {
294 all_nodes.push_back(cv_node.first);
295 }
296
297 generate_vertices(all_nodes);
298 remove_free_nodes(all_nodes);
299
300 update_neighbor_cache();
301 }
302
303 void add_cell_contains_point(const geometry::point3d& p) {
304 if (!extended_bbox().contains(p)) {
305 return;
306 }
307
308 add_cell(cell_vector_from_point(p));
309 }
310
311 void clear() {
312 node_list_.clear();
313 nodes_to_evaluate_.clear();
314 cluster_map_.clear();
315 vertices_.clear();
316 }
317
318 void cluster_vertices() {
319 for (auto& ci_node : node_list_) {
320 auto& node = ci_node.second;
321 const auto& p = node.position();
322 if ((p.array() == bbox().min().array() || p.array() == bbox().max().array()).any()) {
323 // Do not cluster boundary nodes' vertices.
324 continue;
325 }
326 node.cluster(vertices_, cluster_map_);
327 }
328 }
329
330 void generate_vertices(const std::vector<cell_vector>& node_cvs) {
331 static constexpr std::array<edge_index, 7> CellEdgeIndices{0, 1, 3, 4, 9, 12, 13};
332
333#pragma omp parallel for
334 // NOLINTNEXTLINE(modernize-loop-convert)
335 for (std::ptrdiff_t i = 0; i < static_cast<std::ptrdiff_t>(node_cvs.size()); i++) {
336 const auto& cv = node_cvs.at(i);
337 auto& node = node_list_.at(cv);
338
339 // "distance" to the intersection point (if exists) from the node
340 auto d = std::abs(node.value());
341 const auto& p = node.position();
342
343 for (auto ei : CellEdgeIndices) {
344 auto* node2_ptr = node_list_.neighbor_node_ptr(cv, ei);
345 if (node2_ptr == nullptr) {
346 // There is no neighbor node on the opposite end of the edge.
347 continue;
348 }
349
350 auto& node2 = *node2_ptr;
351 if (node.value_sign() == node2.value_sign()) {
352 // There is no intersection on the edge.
353 continue;
354 }
355
356 // "distance" to the intersection point from the neighbor node
357 auto d2 = std::abs(node2.value());
358 const auto& p2 = node2.position();
359
360 // Do not interpolate when coordinates are the same
361 // to prevent boundary vertices from being moved.
362 geometry::point3d vertex =
363 (p.array() == p2.array()).select(p, (d2 * p + d * p2) / (d + d2));
364
365#pragma omp critical
366 {
367 auto vi = static_cast<vertex_index>(vertices_.size());
368 vertices_.emplace_back(vertex);
369
370 if (d < d2) {
371 node.insert_vertex(vi, ei);
372 } else {
373 node2.insert_vertex(vi, OppositeEdge.at(ei));
374 }
375
376 node.set_intersection(ei);
377 node2.set_intersection(OppositeEdge.at(ei));
378 }
379 }
380 }
381 }
382
383 geometry::points3d get_vertices() {
384 geometry::points3d vertices(static_cast<index_t>(vertices_.size()), 3);
385 auto it = vertices.rowwise().begin();
386 for (const auto& v : vertices_) {
387 *it++ = v;
388 }
389 return vertices;
390 }
391
392 void uncluster_vertices(const std::unordered_set<vertex_index>& vis) {
393 auto it = cluster_map_.begin();
394 while (it != cluster_map_.end()) {
395 if (vis.contains(it->second)) {
396 // Uncluster.
397 it = cluster_map_.erase(it);
398 } else {
399 ++it;
400 }
401 }
402 }
403 };
404}
405
406#endif //RSMESH_RMT_LATTICE_H
vectors3d points3d
3维点的集合
Definition point3d.h:48
vector3d point3d
3维点
Definition point3d.h:39
该命名空间下主要定义了等值面提取相关的类和函数