RSMesh 1.0.0
一个曲面重构的系统,输入为点云,输出为obj,stl等主流格式的网格文件,使用的方法为径向基函数插值,采取了并行优化、Intel-MKL等优化措施,支持百万级别的点云
载入中...
搜索中...
未找到
rbf_inequality_fitter.cpp
1//
2// Created by RainSure on 2024/2/29.
3//
4#include "interpolation/rbf_inequality_fitter.h"
5#include "point_cloud/distance_filter.h"
6#include "boost/range/irange.hpp"
7#include "common/zip_sort.h"
8#include "fmm/fmm_tree_height.h"
9#include "interpolation/rbf_incremental_fitter.h"
10#include "interpolation/rbf_solver.h"
11#include "types.h"
12#include <algorithm>
13#include <iostream>
14#include <iterator>
15#include <memory>
16#include <set>
17#include <unordered_set>
18
19namespace rsmesh::interpolation {
20 rbf_inequality_fitter::rbf_inequality_fitter(const model& model, const geometry::points3d& points)
21 : model_(model),
22 points_(points),
23 n_points_(points.rows()),
24 n_poly_basis_(model.poly_basis_size()),
25 bbox_(geometry::bbox3d::from_points(points)) {}
26
27 std::pair<std::vector<index_t>, valuesd> rbf_inequality_fitter::fit(
28 const valuesd& values, const valuesd& values_lb,
29 const valuesd& values_ub, double absolute_tolerance, int max_iter) const {
30 double filtering_distance = bbox_.size().mean() / 4.0;
31
32 auto not_nan = [](double d) { return !std::isnan(d); };
33 auto eq_idcs = arg_where(values, not_nan);
34 auto n_eq = static_cast<index_t>(eq_idcs.size());
35
36 auto lb_idcs = arg_where(values_lb, not_nan);
37 auto ub_idcs = arg_where(values_ub, not_nan);
38 std::vector<index_t> ineq_idcs;
39 std::set_union(lb_idcs.begin(), lb_idcs.end(), ub_idcs.begin(), ub_idcs.end(),
40 std::back_inserter(ineq_idcs));
41 auto n_ineq = static_cast<index_t>(ineq_idcs.size());
42 geometry::points3d ineq_points = points_(ineq_idcs, Eigen::all);
43
44 std::unique_ptr<rbf_solver> solver;
45 std::unique_ptr<rbf_evaluator<>> res_eval;
46 auto last_tree_height = 0;
47
48 valuesd weights = valuesd::Zero(n_points_ + n_poly_basis_);
49 auto centers = eq_idcs;
50 valuesd center_weights;
51 std::set<index_t> active_lb_idcs;
52 std::set<index_t> active_ub_idcs;
53
54 while (true) {
55 std::cout << "Active lower bounds: " << active_lb_idcs.size() << " / " << lb_idcs.size()
56 << std::endl;
57 std::cout << "Active upper bounds: " << active_ub_idcs.size() << " / " << ub_idcs.size()
58 << std::endl;
59
60 // Update centers (equality points + active inequality points).
61
62 centers.resize(n_eq);
63 std::set_union(active_lb_idcs.begin(), active_lb_idcs.end(), active_ub_idcs.begin(),
64 active_ub_idcs.end(), std::back_inserter(centers));
65
66 // Fit and evaluate residuals at all inequality points.
67
68 valuesd values_fit;
69 if (!centers.empty()) {
70 auto n_centers = static_cast<index_t>(centers.size());
71
72 auto tree_height = fmm::fmm_tree_height(n_centers);
73 if (tree_height != last_tree_height) {
74 solver = std::make_unique<rbf_solver>(model_, tree_height, bbox_);
75 res_eval = std::make_unique<rbf_evaluator<>>(model_, tree_height, bbox_);
76 last_tree_height = tree_height;
77 }
78
79 geometry::points3d center_points = points_(centers, Eigen::all);
80
81 valuesd center_values = values(centers, Eigen::all);
82 for (index_t i = n_eq; i < n_centers; i++) {
83 auto idx = centers.at(i);
84 center_values(i) = active_lb_idcs.contains(idx) ? values_lb(idx) : values_ub(idx);
85 }
86
87 center_weights = weights(centers, Eigen::all);
88 center_weights.conservativeResize(n_centers + n_poly_basis_);
89 center_weights.tail(n_poly_basis_) = weights.tail(n_poly_basis_);
90
91 solver->set_points(center_points);
92 center_weights = solver->solve(center_values, absolute_tolerance, max_iter, center_weights);
93
94 for (index_t i = 0; i < n_centers; i++) {
95 auto idx = centers.at(i);
96 weights(idx) = center_weights(i);
97 }
98 weights.tail(n_poly_basis_) = center_weights.tail(n_poly_basis_);
99
100 res_eval->set_source_points(center_points);
101 res_eval->set_weights(center_weights);
102 values_fit = res_eval->evaluate(ineq_points);
103 } else {
104 center_weights = valuesd::Zero(n_poly_basis_);
105 values_fit = valuesd::Zero(n_ineq);
106 }
107
108 // Incorporate inactive inequality points with large residuals.
109
110 auto indices = complementary_indices(centers);
111 auto n_indices = static_cast<index_t>(indices.size());
112 valuesd residuals = valuesd::Zero(n_indices);
113 for (index_t i = 0; i < n_indices; i++) {
114 auto idx = indices.at(i);
115 auto lb = values_lb(idx);
116 auto ub = values_ub(idx);
117 auto lb_res = std::isnan(lb) ? 0.0 : std::max(lb - values_fit(i), 0.0);
118 auto ub_res = std::isnan(ub) ? 0.0 : std::max(values_fit(i) - ub, 0.0);
119 residuals(i) = std::max(lb_res, ub_res);
120 }
121 common::zip_sort(indices.begin(), indices.end(), residuals.begin(), residuals.end(),
122 [](const auto& a, const auto& b) { return a.second > b.second; });
123 point_cloud::distance_filter filter(points_, filtering_distance, indices);
124 std::unordered_set<index_t> filtered_indices(filter.filtered_indices().begin(),
125 filter.filtered_indices().end());
126
127 // Update the active set.
128
129 auto active_set_changed = false;
130 for (index_t i = 0; i < n_ineq; i++) {
131 auto idx = ineq_idcs.at(i);
132
133 if (!std::isnan(values_lb(idx))) {
134 if (active_lb_idcs.contains(idx)) {
135 if (weights(idx) <= 0.0) {
136 active_lb_idcs.erase(idx);
137 active_set_changed = true;
138 }
139 } else {
140 if (values_fit(i) < values_lb(idx) - absolute_tolerance) {
141 if (filtered_indices.contains(idx)) {
142 active_lb_idcs.insert(idx);
143 weights(idx) = 0.0;
144 }
145 active_set_changed = true;
146 }
147 }
148 }
149 if (!std::isnan(values_ub(idx))) {
150 if (active_ub_idcs.contains(idx)) {
151 if (weights(idx) >= 0.0) {
152 active_ub_idcs.erase(idx);
153 active_set_changed = true;
154 }
155 } else {
156 if (values_fit(i) > values_ub(idx) + absolute_tolerance) {
157 if (filtered_indices.contains(idx)) {
158 active_ub_idcs.insert(idx);
159 weights(idx) = 0.0;
160 }
161 active_set_changed = true;
162 }
163 }
164 }
165 }
166
167 if (!active_set_changed) {
168 break;
169 }
170
171 filtering_distance *= 0.5;
172 }
173
174 return {std::move(centers), std::move(center_weights)};
175 }
176
177 std::vector<index_t> rbf_inequality_fitter::complementary_indices(
178 const std::vector<index_t>& indices) const {
179 std::vector<index_t> c_idcs(n_points_ - indices.size());
180
181 auto universe = boost::irange<index_t>(index_t{0}, n_points_);
182 auto idcs = indices;
183 std::sort(idcs.begin(), idcs.end());
184 std::set_difference(universe.begin(), universe.end(), idcs.begin(), idcs.end(), c_idcs.begin());
185
186 return c_idcs;
187 }
188}
vectors3d points3d
3维点的集合
Definition point3d.h:48
该命名空间下主要定义了插值相关的类和函数