RSMesh 1.0.0
一个曲面重构的系统,输入为点云,输出为obj,stl等主流格式的网格文件,使用的方法为径向基函数插值,采取了并行优化、Intel-MKL等优化措施,支持百万级别的点云
载入中...
搜索中...
未找到
rmt_surface.h
1//
2// Created by RainSure on 2024/2/23.
3//
4
5#ifndef RSMESH_RMT_SURFACE_H
6#define RSMESH_RMT_SURFACE_H
7
8#include <array>
9#include <iterator>
10#include <memory>
11#include <optional>
12#include <vector>
13#include "common/macros.h"
14#include "isosurface/isosurface_types.h"
15#include "isosurface/rmt_lattice.h"
16#include "isosurface/rmt_node.h"
17#include "isosurface/isosurface_types.h"
18#include "types.h"
19#include "boost/iterator/iterator_facade.hpp"
20
21namespace rsmesh::isosurface {
22 namespace detail {
24 // List of indices of the three edges of each tetrahedron.
25 static constexpr std::array<std::array<edge_index, 3>, 6> EdgeIndices{
26 {{0, 1, 4}, {0, 4, 3}, {0, 3, 9}, {0, 9, 12}, {0, 12, 13}, {0, 13, 1}}};
27
28 // List of indices of the three outer edges of each tetrahedron as:
29 // ei0 ei1 ei2
30 // node0 ------> node1 ------> node2 ------> node0
31 // <------ <------ <------
32 // ~ei0 ~ei1 ~ei2
33 // where
34 // ei0: outer edge from node0 to node1
35 // ~ei0: opposite outer edge of e0 from node1 to node0.
36 static constexpr std::array<std::array<edge_index, 3>, 6> OuterEdgeIndices{
37 {{2, 6, 12}, {5, 9, 13}, {6, 11, 1}, {8, 13, 4}, {11, 2, 3}, {10, 4, 9}}};
38
39 // Encode four signs of tetrahedron nodes into an integer.
40 template <binary_sign s, binary_sign s0, binary_sign s1, binary_sign s2>
41 static constexpr int tetrahedron_type() {
42 return (s2 << 3) | (s1 << 2) | (s0 << 1) | s;
43 }
44
45 public:
46 rmt_tetrahedron(const rmt_node& node, int index) : node_(node), index_(index) {}
47
48 // Adds 0, 1 or 2 triangular faces of the isosurface in this tetrahedron.
49 template <class OutputIterator>
50 void get_faces(OutputIterator faces) const {
51 auto ei0 = EdgeIndices.at(index_)[0];
52 auto ei1 = EdgeIndices.at(index_)[1];
53 auto ei2 = EdgeIndices.at(index_)[2];
54
55 const auto& node0 = node_.neighbor(ei0);
56 const auto& node1 = node_.neighbor(ei1);
57 const auto& node2 = node_.neighbor(ei2);
58
59 if (degenerate(node_, node0, node1, node2)) {
60 return;
61 }
62
63 auto oei0 = OuterEdgeIndices.at(index_)[0];
64 auto oei1 = OuterEdgeIndices.at(index_)[1];
65 auto oei2 = OuterEdgeIndices.at(index_)[2];
66
67 // Check six edges to obtain vertices
68
69 auto v0 = vertex_on_edge(node_, ei0, node0);
70 auto v1 = vertex_on_edge(node_, ei1, node1);
71 auto v2 = vertex_on_edge(node_, ei2, node2);
72 auto v3 = vertex_on_edge(node0, oei0, node1);
73 auto v4 = vertex_on_edge(node1, oei1, node2);
74 auto v5 = vertex_on_edge(node2, oei2, node0);
75
76 auto tetra = tetrahedron_type(node_.value_sign(), node0.value_sign(), node1.value_sign(),
77 node2.value_sign());
78
79 switch (tetra) {
80 case tetrahedron_type<Pos, Pos, Pos, Pos>():
81 case tetrahedron_type<Neg, Neg, Neg, Neg>():
82 // No faces.
83 break;
84 case tetrahedron_type<Neg, Pos, Pos, Pos>():
85 // v0-v1-v2
86 *faces++ = {v0.value(), v1.value(), v2.value()};
87 break;
88 case tetrahedron_type<Pos, Neg, Neg, Neg>():
89 // v0-v2-v1
90 *faces++ = {v0.value(), v2.value(), v1.value()};
91 break;
92 case tetrahedron_type<Pos, Neg, Pos, Pos>():
93 // v0-v5-v3
94 *faces++ = {v0.value(), v5.value(), v3.value()};
95 break;
96 case tetrahedron_type<Neg, Pos, Neg, Neg>():
97 // v0-v3-v5
98 *faces++ = {v0.value(), v3.value(), v5.value()};
99 break;
100 case tetrahedron_type<Pos, Pos, Neg, Pos>():
101 // v1-v3-v4
102 *faces++ = {v1.value(), v3.value(), v4.value()};
103 break;
104 case tetrahedron_type<Neg, Neg, Pos, Neg>():
105 // v1-v4-v3
106 *faces++ = {v1.value(), v4.value(), v3.value()};
107 break;
108 case tetrahedron_type<Pos, Pos, Pos, Neg>():
109 // v2-v4-v5
110 *faces++ = {v2.value(), v4.value(), v5.value()};
111 break;
112 case tetrahedron_type<Neg, Neg, Neg, Pos>():
113 // v2-v5-v4
114 *faces++ = {v2.value(), v5.value(), v4.value()};
115 break;
116 case tetrahedron_type<Neg, Neg, Pos, Pos>():
117 // v5-v3-v1, v5-v1-v2
118 *faces++ = {v5.value(), v3.value(), v1.value()};
119 *faces++ = {v5.value(), v1.value(), v2.value()};
120 break;
121 case tetrahedron_type<Pos, Pos, Neg, Neg>():
122 // v5-v1-v3, v5-v2-v1
123 *faces++ = {v5.value(), v1.value(), v3.value()};
124 *faces++ = {v5.value(), v2.value(), v1.value()};
125 break;
126 case tetrahedron_type<Neg, Pos, Neg, Pos>():
127 // v0-v3-v4, v0-v4-v2
128 *faces++ = {v0.value(), v3.value(), v4.value()};
129 *faces++ = {v0.value(), v4.value(), v2.value()};
130 break;
131 case tetrahedron_type<Pos, Neg, Pos, Neg>():
132 // v0-v4-v3, v0-v2-v4
133 *faces++ = {v0.value(), v4.value(), v3.value()};
134 *faces++ = {v0.value(), v2.value(), v4.value()};
135 break;
136 case tetrahedron_type<Neg, Pos, Pos, Neg>():
137 // v5-v0-v1, v5-v1-v4
138 *faces++ = {v5.value(), v0.value(), v1.value()};
139 *faces++ = {v5.value(), v1.value(), v4.value()};
140 break;
141 case tetrahedron_type<Pos, Neg, Neg, Pos>():
142 // v5-v1-v0, v5-v4-v1
143 *faces++ = {v5.value(), v1.value(), v0.value()};
144 *faces++ = {v5.value(), v4.value(), v1.value()};
145 break;
146 default:
147 RSMESH_UNREACHABLE();
148 break;
149 }
150 }
151
152 private:
153 friend class rmt_tetrahedron_iterator;
154
155 // Test if the tetrahedron is degenerate due to clamping within the bbox.
156 static bool degenerate(const rmt_node& node, const rmt_node& node0, const rmt_node& node1,
157 const rmt_node& node2) {
158 const auto& p = node.position();
159 const auto& p0 = node0.position();
160 const auto& p1 = node1.position();
161 const auto& p2 = node2.position();
162
163 return (p.array() == p0.array() && p.array() == p1.array() && p.array() == p2.array()).any();
164 }
165
166 static int tetrahedron_type(binary_sign s, binary_sign s0, binary_sign s1, binary_sign s2) {
167 return (s2 << 3) | (s1 << 2) | (s0 << 1) | s;
168 }
169
170 static std::optional<vertex_index> vertex_on_edge(const rmt_node& node, edge_index edge_idx,
171 const rmt_node& opp_node) {
172 if (node.has_intersection(edge_idx)) {
173 return node.vertex_on_edge(edge_idx);
174 }
175
176 auto opp_edge_idx = OppositeEdge.at(edge_idx);
177 if (opp_node.has_intersection(opp_edge_idx)) {
178 return opp_node.vertex_on_edge(opp_edge_idx);
179 }
180
181 return {};
182 }
183
184 const rmt_node& node_;
185 const int index_;
186 };
187
189 : public boost::iterator_facade<rmt_tetrahedron_iterator, rmt_tetrahedron,
190 std::input_iterator_tag, rmt_tetrahedron, int> {
191 // The number of tetrahedra in a cell.
192 static constexpr int kNumTetrahedra = 6;
193
194 public:
195 explicit rmt_tetrahedron_iterator(const rmt_node& node) : node_(node) {
196 while (is_valid() && !tetrahedron_exists()) {
197 // Some of the tetrahedron nodes do not exist.
198 index_++;
199 }
200 }
201
202 bool is_valid() const { return index_ < kNumTetrahedra; }
203
204 private:
205 friend class boost::iterator_core_access;
206
207 reference dereference() const {
208 RSMESH_ASSERT(is_valid());
209
210 return {node_, index_};
211 }
212
213 bool equal(const rmt_tetrahedron_iterator& other) const {
214 RSMESH_ASSERT(std::addressof(node_) == std::addressof(other.node_));
215
216 return index_ == other.index_;
217 }
218
219 void increment() {
220 RSMESH_ASSERT(is_valid());
221
222 do {
223 index_++;
224 } while (is_valid() && !tetrahedron_exists());
225 }
226
227 // Returns if all nodes corresponding to three vertices of the tetrahedron exist.
228 bool tetrahedron_exists() const {
229 return node_.has_neighbor(rmt_tetrahedron::EdgeIndices.at(index_)[0]) &&
230 node_.has_neighbor(rmt_tetrahedron::EdgeIndices.at(index_)[1]) &&
231 node_.has_neighbor(rmt_tetrahedron::EdgeIndices.at(index_)[2]);
232 }
233
234 const rmt_node& node_;
235 int index_{};
236 };
237 } // namespace detail
238
240 public:
241 explicit rmt_surface(const rmt_lattice& lattice) : lattice_(lattice) {}
242
243 Eigen::Matrix<index_t, Eigen::Dynamic, 3, Eigen::RowMajor> get_faces() const {
244 Eigen::Matrix<index_t, Eigen::Dynamic, 3, Eigen::RowMajor> faces(
245 static_cast<index_t>(faces_.size()), 3);
246
247 index_t n_faces = 0;
248
249 auto it = faces.rowwise().begin();
250 for (const auto& face : faces_) {
251 auto v0 = lattice_.clustered_vertex_index(face[0]);
252 auto v1 = lattice_.clustered_vertex_index(face[1]);
253 auto v2 = lattice_.clustered_vertex_index(face[2]);
254
255 if (v0 == v1 || v1 == v2 || v2 == v0) {
256 // Degenerated face.
257 continue;
258 }
259
260 *it++ << v0, v1, v2;
261 n_faces++;
262 }
263
264 faces.conservativeResize(n_faces, 3);
265 return faces;
266 }
267
268 void generate_surface() {
269 faces_.clear();
270
271 auto inserter = std::back_inserter(faces_);
272
273 for (const auto& ci_node : lattice_.node_list_) {
274 const auto& node = ci_node.second;
275
276 for (detail::rmt_tetrahedron_iterator it(node); it.is_valid(); ++it) {
277 it->get_faces(inserter);
278 }
279 }
280 }
281
282 private:
283 const rmt_lattice& lattice_;
284 std::vector<face> faces_;
285 };
286
287}
288
289#endif //RSMESH_RMT_SURFACE_H
该命名空间下主要定义了等值面提取相关的类和函数