1#ifndef BVH_V2_REINSERTION_OPTIMIZER_H
2#define BVH_V2_REINSERTION_OPTIMIZER_H
13template <
typename Node>
65 template <
typename Derived>
71 template <
typename Derived>
73 std::vector<size_t> parents(
bvh.nodes.size());
76 [&] (
size_t begin,
size_t end) {
77 for (size_t i = begin; i < end; ++i) {
78 auto& node = bvh.nodes[i];
79 if (!node.is_leaf()) {
80 parents[node.index.first_id() + 0] = i;
81 parents[node.index.first_id() + 1] = i;
91 const auto node_count = std::min(bvh_.nodes.size(), target_count + 1);
92 std::vector<Candidate> candidates;
93 for (
size_t i = 1; i < node_count; ++i)
94 candidates.push_back(
Candidate { i, bvh_.nodes[i].get_bbox().get_half_area() });
95 std::make_heap(candidates.begin(), candidates.end(), std::greater<>{});
96 for (
size_t i = node_count; i < bvh_.nodes.size(); ++i) {
97 auto cost = bvh_.nodes[i].get_bbox().get_half_area();
98 if (candidates.front().cost < cost) {
99 std::pop_heap(candidates.begin(), candidates.end(), std::greater<>{});
100 candidates.back() =
Candidate { i, cost };
101 std::push_heap(candidates.begin(), candidates.end(), std::greater<>{});
108 assert(node_id != 0);
140 auto node_area = bvh_.nodes[node_id].get_bbox().get_half_area();
141 auto parent_area = bvh_.nodes[parents_[node_id]].get_bbox().get_half_area();
142 auto area_diff = parent_area;
144 auto pivot_bbox = bvh_.nodes[sibling_id].get_bbox();
145 auto parent_id = parents_[node_id];
146 auto pivot_id = parent_id;
148 std::vector<std::pair<Scalar, size_t>> stack;
151 stack.emplace_back(area_diff, sibling_id);
152 while (!stack.empty()) {
153 auto top = stack.back();
155 if (top.first - node_area <= best_reinsertion.area_diff)
158 auto& dst_node = bvh_.nodes[top.second];
159 auto merged_area = dst_node.get_bbox().extend(bvh_.nodes[node_id].get_bbox()).get_half_area();
160 auto reinsert_area = top.first - merged_area;
161 if (reinsert_area > best_reinsertion.area_diff) {
162 best_reinsertion.to = top.second;
163 best_reinsertion.area_diff = reinsert_area;
166 if (!dst_node.is_leaf()) {
167 auto child_area = reinsert_area + dst_node.get_bbox().get_half_area();
168 stack.emplace_back(child_area, dst_node.index.first_id() + 0);
169 stack.emplace_back(child_area, dst_node.index.first_id() + 1);
175 if (pivot_id != parent_id) {
176 pivot_bbox.extend(bvh_.nodes[sibling_id].get_bbox());
177 area_diff += bvh_.nodes[pivot_id].get_bbox().get_half_area() - pivot_bbox.get_half_area();
181 pivot_id = parents_[pivot_id];
182 }
while (pivot_id != 0);
185 best_reinsertion.to == parents_[best_reinsertion.from])
186 best_reinsertion = {};
187 return best_reinsertion;
192 auto parent_id = parents_[from];
193 auto sibling_node = bvh_.nodes[sibling_id];
194 auto dst_node = bvh_.nodes[to];
197 bvh_.nodes[sibling_id] = dst_node;
198 bvh_.nodes[parent_id] = sibling_node;
200 if (!dst_node.is_leaf()) {
201 parents_[dst_node.index.first_id() + 0] = sibling_id;
202 parents_[dst_node.index.first_id() + 1] = sibling_id;
204 if (!sibling_node.is_leaf()) {
205 parents_[sibling_node.index.first_id() + 0] = parent_id;
206 parents_[sibling_node.index.first_id() + 1] = parent_id;
209 parents_[sibling_id] = to;
212 refit_from(parent_id);
217 auto& node = bvh_.nodes[
index];
218 if (!node.is_leaf()) {
220 bvh_.nodes[node.index.first_id() + 0].get_bbox().extend(
221 bvh_.nodes[node.index.first_id() + 1].get_bbox()));
224 }
while (
index != 0);
228 return std::array<size_t, 5> {
236 template <
typename Derived>
238 auto batch_size = std::max(
size_t{1},
240 std::vector<Reinsertion> reinsertions;
241 std::vector<bool> touched(bvh_.nodes.size());
244 auto candidates = find_candidates(batch_size);
246 std::fill(touched.begin(), touched.end(),
false);
247 reinsertions.resize(candidates.size());
248 executor.
for_each(0, candidates.size(),
249 [&] (
size_t begin,
size_t end) {
250 for (size_t i = begin; i < end; ++i)
251 reinsertions[i] = find_reinsertion(candidates[i].node_id);
254 reinsertions.erase(std::remove_if(reinsertions.begin(), reinsertions.end(),
255 [] (
auto&
r) { return r.area_diff <= 0; }), reinsertions.end());
256 std::sort(reinsertions.begin(), reinsertions.end(), std::greater<>{});
258 for (
auto& reinsertion : reinsertions) {
259 auto conflicts = get_conflicts(reinsertion.from, reinsertion.to);
260 if (std::any_of(conflicts.begin(), conflicts.end(), [&] (
size_t i) { return touched[i]; }))
262 for (
auto conflict : conflicts)
263 touched[conflict] =
true;
264 reinsert_node(reinsertion.from, reinsertion.to);
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t r
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t index
static std::vector< size_t > compute_parents(Executor< Derived > &executor, const Bvh< Node > &bvh)
BVH_ALWAYS_INLINE std::vector< Candidate > find_candidates(size_t target_count)
Reinsertion find_reinsertion(size_t node_id)
typename Node::Scalar Scalar
BVH_ALWAYS_INLINE auto get_conflicts(size_t from, size_t to)
BVH_ALWAYS_INLINE void reinsert_node(size_t from, size_t to)
void optimize(Executor< Derived > &executor, const Config &config)
std::vector< size_t > parents_
BVH_ALWAYS_INLINE void refit_from(size_t index)
static void optimize(Bvh< Node > &bvh, const Config &config={})
ReinsertionOptimizer(Bvh< Node > &bvh, std::vector< size_t > &&parents)
static void optimize(Executor< Derived > &executor, Bvh< Node > &bvh, const Config &config)
static void optimize(ThreadPool &thread_pool, Bvh< Node > &bvh, const Config &config={})
static BVH_ALWAYS_INLINE size_t get_sibling_id(size_t node_id)
Returns the index of a sibling of a node.
Helper object that provides iteration and reduction over one-dimensional ranges.
void for_each(size_t begin, size_t end, const Loop &loop)
static BVH_ALWAYS_INLINE Index make_inner(size_t first_child)
Executor that executes in parallel using the given thread pool.
BVH_ALWAYS_INLINE bool operator>(const Candidate &other) const
size_t max_iter_count
Maximum number of iterations.
Scalar batch_size_ratio
Fraction of the number of nodes to optimize per iteration.
BVH_ALWAYS_INLINE bool operator>(const Reinsertion &other) const
Executor that executes serially.