RSMesh 1.0.0
一个曲面重构的系统,输入为点云,输出为obj,stl等主流格式的网格文件,使用的方法为径向基函数插值,采取了并行优化、Intel-MKL等优化措施,支持百万级别的点云
载入中...
搜索中...
未找到
fmm_evaluator.cpp
1//
2// Created by RainSure on 2024/2/4.
3//
4
5#include "fmm/fmm_evaluator.h"
6#include "ScalFMM/Components/FTypedLeaf.hpp"
7#include "ScalFMM/Containers/FOctree.hpp"
8#include "ScalFMM/Core/FFmmAlgorithmThreadTsm.hpp"
9#include "ScalFMM/Kernels/Chebyshev/FChebCell.hpp"
10#include "ScalFMM/Kernels/Chebyshev/FChebSymKernel.hpp"
11#include "ScalFMM/Kernels/P2P/FP2PParticleContainerIndexed.hpp"
12#include <algorithm>
13#include "common/macros.h"
14#include "fmm/fmm_rbf_kernel.h"
15
16
17namespace rsmesh::fmm {
18 template<int Order>
19 class fmm_evaluator<Order>::impl {
20 using Cell = FTypedChebCell<double, Order>;
21 using ParticleContainer = FP2PParticleContainerIndexed<double>;
22 using Leaf = FTypedLeaf<double, ParticleContainer>;
23 using Octree = FOctree<double, Cell, ParticleContainer, Leaf>;
24 using InterpolatedKernel = FChebSymKernel<double, Cell, ParticleContainer, fmm_rbf_kernel, Order>;
25 using Fmm = FFmmAlgorithmThreadTsm<Octree, Cell, ParticleContainer, InterpolatedKernel, Leaf>;
26
27 static constexpr int FmmAlgorithmScheduleChunkSize = 1;
28 public:
29 impl(const model& model, int tree_height, const geometry::bbox3d& bbox) :
30 model_(model), rbf_kernel_(model.rbf()) {
31 auto a_bbox = bbox.transform(model.rbf().anisotropy());
32 auto width = 1.01 * a_bbox.size().maxCoeff();
33 if(width == 0.0) {
34 width = 1.0;
35 }
36 auto center = a_bbox.center();
37
38 interpolated_kernel_ = std::make_unique<InterpolatedKernel>(
39 tree_height, width, FPoint<double>(center.data()), &rbf_kernel_);
40
41 tree_ = std::make_unique<Octree>(tree_height, std::max(1, tree_height - 4), width,
42 FPoint<double>(center.data()));
43
44 fmm_ = std::make_unique<Fmm>(tree_.get(), interpolated_kernel_.get(),
45 int{FmmAlgorithmScheduleChunkSize});
46 }
47
48 [[nodiscard]] valuesd evaluate() const {
49 tree_->forEachLeaf([](Leaf* leaf) {
50 auto& particles = *leaf->getTargets();
51 particles.resetForcesAndPotential();
52 });
53
54 fmm_->execute(FFmmM2L | FFmmL2L | FFmmL2P | FFmmP2P);
55
56 return potentials();
57 }
58
59 void set_field_points(const geometry::points3d& points) {
60 n_fld_points_ = points.rows();
61
62 // Remove all target particles.
63 tree_->forEachLeaf([](Leaf* leaf) {
64 auto& particles = *leaf->getTargets();
65 particles.clear();
66 });
67
68 // Insert target particles.
69 auto a = model_.rbf().anisotropy();
70 for (index_t idx = 0; idx < n_fld_points_; idx++) {
71 auto ap = geometry::transform_point(a, points.row(idx));
72 tree_->insert(FPoint<double>(ap.data()), FParticleType::FParticleTypeTarget, idx, 0.0);
73 }
74
75 fmm_->updateTargetCells();
76
77 update_potential_ptrs();
78 }
79
80 void set_source_points(const geometry::points3d& points) {
81 n_src_points_ = points.rows();
82
83 // Remove all source particles.
84 tree_->forEachLeaf([&](Leaf* leaf) {
85 auto& particles = *leaf->getSrc();
86 particles.clear();
87 });
88
89 // Insert source particles.
90 auto a = model_.rbf().anisotropy();
91 for (index_t idx = 0; idx < n_src_points_; idx++) {
92 auto ap = geometry::transform_point(a, points.row(idx));
93 tree_->insert(FPoint<double>(ap.data()), FParticleType::FParticleTypeSource, idx, 0.0);
94 }
95
96 update_weight_ptrs();
97 }
98
99 void set_source_points_and_weights(const geometry::points3d& points,
100 const Eigen::Ref<const valuesd>& weights) {
101 RSMESH_ASSERT(weights.rows() == points.rows());
102
103 n_src_points_ = points.rows();
104
105 // Remove all source particles.
106 tree_->forEachLeaf([&](Leaf* leaf) {
107 auto& particles = *leaf->getSrc();
108 particles.clear();
109 });
110
111 // Insert source particles.
112 auto a = model_.rbf().anisotropy();
113 for (index_t idx = 0; idx < n_src_points_; idx++) {
114 auto ap = geometry::transform_point(a, points.row(idx));
115 tree_->insert(FPoint<double>(ap.data()), FParticleType::FParticleTypeSource, idx,
116 weights(idx));
117 }
118
119 tree_->forEachCell([&](Cell* cell) { cell->resetToInitialState(); });
120
121 fmm_->execute(FFmmP2M | FFmmM2M);
122
123 weight_ptrs_.clear();
124 }
125
126 void set_weights(const Eigen::Ref<const valuesd>& weights) {
127 RSMESH_ASSERT(weights.rows() == n_src_points_);
128
129 if (n_src_points_ == 0) {
130 return;
131 }
132
133 if (weight_ptrs_.empty()) {
134 update_weight_ptrs();
135 }
136
137 for (index_t idx = 0; idx < n_src_points_; idx++) {
138 *weight_ptrs_.at(idx) = weights(idx);
139 }
140
141 tree_->forEachCell([](Cell* cell) { cell->resetToInitialState(); });
142
143 fmm_->execute(FFmmP2M | FFmmM2M);
144 }
145
146 private:
147 [[nodiscard]] valuesd potentials() const {
148 valuesd phi = valuesd::Zero(n_fld_points_);
149
150 for (index_t i = 0; i < n_fld_points_; i++) {
151 phi(i) = *potential_ptrs_.at(i);
152 }
153
154 return phi;
155 }
156
157 void update_potential_ptrs() {
158 potential_ptrs_.resize(n_fld_points_);
159 tree_->forEachLeaf([&](Leaf* leaf) {
160 const auto& particles = *leaf->getTargets();
161
162 const auto& indices = particles.getIndexes();
163 const double* potentials = particles.getPotentials();
164
165 auto n_particles = static_cast<index_t>(particles.getNbParticles());
166 for (index_t i = 0; i < n_particles; i++) {
167 auto idx = static_cast<index_t>(indices[i]);
168
169 potential_ptrs_.at(idx) = &potentials[i];
170 }
171 });
172 }
173
174 void update_weight_ptrs() {
175 weight_ptrs_.resize(n_src_points_);
176 tree_->forEachLeaf([&](Leaf* leaf) {
177 auto& particles = *leaf->getSrc();
178
179 const auto& indices = particles.getIndexes();
180 double* weights = particles.getPhysicalValues();
181
182 auto n_particles = static_cast<index_t>(particles.getNbParticles());
183 for (index_t i = 0; i < n_particles; i++) {
184 auto idx = static_cast<index_t>(indices[i]);
185
186 weight_ptrs_.at(idx) = &weights[i];
187 }
188 });
189 }
190
191 const model& model_;
192 const fmm_rbf_kernel rbf_kernel_;
193
194 index_t n_src_points_{};
195 index_t n_fld_points_{};
196
197 std::unique_ptr<Fmm> fmm_;
198 std::unique_ptr<InterpolatedKernel> interpolated_kernel_;
199 std::unique_ptr<Octree> tree_;
200
201 std::vector<const double*> potential_ptrs_;
202 std::vector<double*> weight_ptrs_;
203 };
204
205 template<int Order>
206 fmm_evaluator<Order>::fmm_evaluator(const rsmesh::model &model, int tree_height, const geometry::bbox3d &bbox) :pimpl_(std::make_unique<impl>(model, tree_height, bbox)) {
207
208 }
209
210 template<int Order>
212
213 template<int Order>
214 valuesd fmm_evaluator<Order>::evaluate() const {
215 return pimpl_->evaluate();
216 }
217
218 template<int Order>
219 void fmm_evaluator<Order>::set_field_points(const geometry::points3d &points) {
220 pimpl_->set_field_points(points);
221 }
222
223 template<int Order>
224 void fmm_evaluator<Order>::set_source_points(const geometry::points3d &points) {
225 pimpl_->set_source_points(points);
226 }
227
228 template<int Order>
229 void fmm_evaluator<Order>::set_source_points_and_weights(const geometry::points3d &points,
230 const Eigen::Ref<const valuesd> &weights) {
231 pimpl_->set_source_points_and_weights(points, weights);
232 }
233
234 template<int Order>
235 void fmm_evaluator<Order>::set_weights(const Eigen::Ref<const valuesd> &weights) {
236 pimpl_->set_weights(weights);
237 }
238
239 template class fmm_evaluator<6>;
240 template class fmm_evaluator<10>;
241} // namespace rsmesh::fmm
描述了一个插值模型
Definition model.h:21
vectors3d points3d
3维点的集合
Definition point3d.h:48
point3d transform_point(const linear_transformation3d &lhs, const point3d &p)
对一个三维点进行线性变换
Definition point3d.h:75