RSMesh 1.0.0
一个曲面重构的系统,输入为点云,输出为obj,stl等主流格式的网格文件,使用的方法为径向基函数插值,采取了并行优化、Intel-MKL等优化措施,支持百万级别的点云
载入中...
搜索中...
未找到
fmm_symmetric_evaluator.cpp
1//
2// Created by RainSure on 2024/2/4.
3//
4
5#include "fmm/fmm_symmetric_evaluator.h"
6#include "ScalFMM/Kernels/Chebyshev/FChebCell.hpp"
7#include "ScalFMM/Kernels/P2P/FP2PParticleContainerIndexed.hpp"
8#include "ScalFMM/Components/FSimpleLeaf.hpp"
9#include "ScalFMM/Kernels/Chebyshev/FChebSymKernel.hpp"
10#include "ScalFMM/Containers/FOctree.hpp"
11#include "fmm/fmm_rbf_kernel.h"
12#include "ScalFMM/Core/FFmmAlgorithmThread.hpp"
13
14namespace rsmesh::fmm {
15 template <int Order>
17 using Cell = FChebCell<double, Order>;
18 using ParticleContainer = FP2PParticleContainerIndexed<double>;
19 using Leaf = FSimpleLeaf<double, ParticleContainer>;
20 using Octree = FOctree<double, Cell, ParticleContainer, Leaf>;
21 using InterpolatedKernel = FChebSymKernel<double, Cell, ParticleContainer, fmm_rbf_kernel, Order>;
22 using Fmm = FFmmAlgorithmThread<Octree, Cell, ParticleContainer, InterpolatedKernel, Leaf>;
23
24 static constexpr int FmmAlgorithmScheduleChunkSize = 1;
25
26 public:
27 impl(const model& model, int tree_height, const geometry::bbox3d& bbox)
28 : model_(model), rbf_kernel_(model.rbf()) {
29 auto a_bbox = bbox.transform(model.rbf().anisotropy());
30 auto width = 1.01 * a_bbox.size().maxCoeff();
31 if (width == 0.0) {
32 width = 1.0;
33 }
34 auto center = a_bbox.center();
35
36 interpolated_kernel_ = std::make_unique<InterpolatedKernel>(
37 tree_height, width, FPoint<double>(center.data()), &rbf_kernel_);
38
39 tree_ = std::make_unique<Octree>(tree_height, std::max(1, tree_height - 4), width,
40 FPoint<double>(center.data()));
41
42 fmm_ = std::make_unique<Fmm>(tree_.get(), interpolated_kernel_.get(),
43 int{FmmAlgorithmScheduleChunkSize});
44 }
45
46 valuesd evaluate() const {
47 reset_tree();
48
49 fmm_->execute();
50
51 auto self_potential = model_.rbf().evaluate_isotropic(geometry::vector3d::Zero());
52 return potentials() + weights_ * self_potential;
53 }
54
55 void set_points(const geometry::points3d& points) {
56 n_points_ = points.rows();
57
58 // Remove all source particles.
59 tree_->forEachLeaf([](Leaf* leaf) {
60 auto& particles = *leaf->getSrc();
61 particles.clear();
62 });
63
64 // Insert points.
65 auto a = model_.rbf().anisotropy();
66 for (index_t idx = 0; idx < n_points_; idx++) {
67 auto ap = geometry::transform_point(a, points.row(idx));
68 tree_->insert(FPoint<double>(ap.data()), idx, 0.0);
69 }
70
71 update_weight_ptrs();
72 update_potential_ptrs();
73 }
74
75 void set_weights(const Eigen::Ref<const valuesd>& weights) {
76 RSMESH_ASSERT(weights.rows() == n_points_);
77
78 // Update weights.
79 for (index_t idx = 0; idx < n_points_; idx++) {
80 *weight_ptrs_.at(idx) = weights(idx);
81 }
82
83 weights_ = weights;
84 }
85
86 private:
87 valuesd potentials() const {
88 valuesd phi = valuesd::Zero(n_points_);
89
90 for (index_t i = 0; i < n_points_; i++) {
91 phi(i) = *potential_ptrs_.at(i);
92 }
93
94 return phi;
95 }
96
97 void reset_tree() const {
98 tree_->forEachCell([](Cell* cell) { cell->resetToInitialState(); });
99
100 tree_->forEachLeaf([](Leaf* leaf) {
101 auto& particles = *leaf->getTargets();
102 particles.resetForcesAndPotential();
103 });
104 }
105
106 void update_potential_ptrs() {
107 potential_ptrs_.resize(n_points_);
108 tree_->forEachLeaf([&](Leaf* leaf) {
109 const auto& particles = *leaf->getTargets();
110
111 const auto& indices = particles.getIndexes();
112 const double* potentials = particles.getPotentials();
113
114 auto n_particles = static_cast<index_t>(particles.getNbParticles());
115 for (index_t i = 0; i < n_particles; i++) {
116 auto idx = static_cast<index_t>(indices[i]);
117
118 potential_ptrs_.at(idx) = &potentials[i];
119 }
120 });
121 }
122
123 void update_weight_ptrs() {
124 weight_ptrs_.resize(n_points_);
125 tree_->forEachLeaf([&](Leaf* leaf) {
126 auto& particles = *leaf->getSrc();
127
128 const auto& indices = particles.getIndexes();
129 double* weights = particles.getPhysicalValues();
130
131 auto n_particles = static_cast<index_t>(particles.getNbParticles());
132 for (index_t i = 0; i < n_particles; i++) {
133 auto idx = static_cast<index_t>(indices[i]);
134
135 weight_ptrs_.at(idx) = &weights[i];
136 }
137 });
138 }
139
140 const model& model_;
141 const fmm_rbf_kernel rbf_kernel_;
142
143 index_t n_points_{};
144 valuesd weights_;
145
146 std::unique_ptr<Fmm> fmm_;
147 std::unique_ptr<InterpolatedKernel> interpolated_kernel_;
148 std::unique_ptr<Octree> tree_;
149
150 std::vector<const double*> potential_ptrs_;
151 std::vector<double*> weight_ptrs_;
152 };
153
154 template <int Order>
156 const geometry::bbox3d& bbox)
157 : pimpl_(std::make_unique<impl>(model, tree_height, bbox)) {}
158
159 template <int Order>
161
162 template <int Order>
164 return pimpl_->evaluate();
165 }
166
167 template <int Order>
168 void fmm_symmetric_evaluator<Order>::set_points(const geometry::points3d& points) {
169 pimpl_->set_points(points);
170 }
171
172 template <int Order>
173 void fmm_symmetric_evaluator<Order>::set_weights(const Eigen::Ref<const valuesd>& weights) {
174 pimpl_->set_weights(weights);
175 }
176
177 template class fmm_symmetric_evaluator<6>;
178 template class fmm_symmetric_evaluator<10>;
179}
描述了一个插值模型
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