Flow123d  release_3.0.0-506-g34af125
bih_tree.cc
Go to the documentation of this file.
1 /*!
2  *
3  * Copyright (C) 2015 Technical University of Liberec. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License version 3 as published by the
7  * Free Software Foundation. (http://www.gnu.org/licenses/gpl-3.0.en.html)
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12  *
13  *
14  * @file bih_tree.cc
15  * @brief
16  */
17 
18 #include "mesh/bih_tree.hh"
19 #include "mesh/bih_node.hh"
20 #include "mesh/mesh.h"
21 #include "system/global_defs.h"
22 #include <ctime>
23 #include <stack>
24 
25 /**
26  * Minimum reduction of box size to allow
27  * splitting of a node during tree creation.
28  */
29 const double BIHTree::size_reduce_factor = 0.8;
30 
31 const unsigned int BIHTree::default_leaf_size_limit = 20;
32 
33 
34 BIHTree::BIHTree(unsigned int soft_leaf_size_limit)
35 : leaf_size_limit(soft_leaf_size_limit) //, r_gen(123)
36 {}
37 
38 
40 }
41 
42 
44  for(BoundingBox box : boxes) {
45  this->elements_.push_back(box);
46  main_box_.expand(box);
47  }
48 }
49 
50 
52  ASSERT_GT(elements_.size(), 0);
53 
54  max_n_levels = 2*log2(elements_.size());
55  nodes_.reserve(2*elements_.size() / leaf_size_limit);
56  in_leaves_.resize(elements_.size());
57  for(unsigned int i=0; i<in_leaves_.size(); i++) in_leaves_[i] = i;
58 
59  // make root node
60  nodes_.push_back(BIHNode());
61  nodes_.back().set_leaf(0, in_leaves_.size(), 0, 0);
62  uint height = make_node(main_box_, 0);
63 
64  node_stack_.reserve(2*height);
65 }
66 
67 
68 const BoundingBox& BIHTree::ele_bounding_box(unsigned int ele_idx) const
69 {
70  ASSERT_DBG(ele_idx < elements_.size());
71  return elements_[ele_idx];
72 }
73 
74 
75 void BIHTree::split_node(const BoundingBox &node_box, unsigned int node_idx) {
76  BIHNode &node = nodes_[node_idx];
77  OLD_ASSERT(node.is_leaf(), " ");
78  unsigned int axis = node_box.longest_axis();
79  double median = estimate_median(axis, node);
80 
81  // split elements in node according to the median
82  auto left = in_leaves_.begin() + node.leaf_begin(); // first of unresolved elements in @p in_leaves_
83  auto right = in_leaves_.begin() + node.leaf_end()-1; // last of unresolved elements in @p in_leaves_
84 
85  double left_bound=node_box.min(axis); // max bound of the left group
86  double right_bound=node_box.max(axis); // min bound of the right group
87 
88  while (left != right) {
89  if ( elements_[ *left ].projection_center(axis) < median) {
90  left_bound = std::max( left_bound, elements_[ *left ].max(axis) );
91  ++left;
92  }
93  else {
94  while ( left != right
95  && elements_[ *right ].projection_center(axis) >= median ) {
96  right_bound = std::min( right_bound, elements_[ *right ].min(axis) );
97  --right;
98  }
99  std::swap( *left, *right);
100  }
101  }
102  // in any case left==right is now the first element of the right group
103 
104  if ( elements_[ *left ].projection_center(axis) < median) {
105  left_bound = std::max( left_bound, elements_[ *left ].max(axis) );
106  ++left;
107  ++right;
108  } else {
109  right_bound = std::min( right_bound, elements_[ *right ].min(axis) );
110  }
111 
112  unsigned int left_begin = node.leaf_begin();
113  unsigned int left_end = left - in_leaves_.begin();
114  unsigned int right_end = node.leaf_end();
115  unsigned int depth = node.depth()+1;
116  // create new leaf nodes and possibly call split_node on them
117  // can not use node reference anymore
118  nodes_.push_back(BIHNode());
119  nodes_.back().set_leaf(left_begin, left_end, left_bound, depth);
120  nodes_.push_back(BIHNode());
121  nodes_.back().set_leaf(left_end, right_end, right_bound, depth);
122 
123  nodes_[node_idx].set_non_leaf(nodes_.size()-2, nodes_.size()-1, axis);
124 
125 // xprintf(Msg, "%d %f %f %f %f %d %d\n", node_idx, node_box.min(axis), left_bound, right_bound, node_box.max(axis),
126 // left_end - left_begin, right_end - left_end );
127 }
128 
129 
130 uint BIHTree::make_node(const BoundingBox &box, unsigned int node_idx) {
131  // we must refer to the node by index to prevent seg. fault due to nodes_ reallocation
132 
133  uint height = 0;
134  split_node(box,node_idx);
135 
136  {
137  BIHNode &node = nodes_[node_idx];
138  BIHNode &child = nodes_[ node.child(0) ];
139  BoundingBox node_box(box);
140  node_box.set_max(node.axis(), child.bound() );
141  if ( child.leaf_size() > leaf_size_limit
142  && child.depth() < max_n_levels)
143 // && ( node.axis() != node_box.longest_axis()
144 // || node_box.size(node_box.longest_axis()) < box.size(node.axis()) * size_reduce_factor )
145 // )
146  {
147  uint ht = make_node(node_box, node.child(0) );
148  height = max(height, ht);
149  }
150 // else{
151 // xprintf(Msg,"%d %d %f %f\n",node_idx, child.leaf_size(),
152 // node_box.size(node_box.longest_axis()),
153 // box.size(node.axis()));
154 // }
155  }
156 
157  {
158  BIHNode &node = nodes_[node_idx];
159  BIHNode &child = nodes_[ node.child(1) ];
160  BoundingBox node_box(box);
161  node_box.set_min(node.axis(), child.bound() );
162  if ( child.leaf_size() > leaf_size_limit
163  && child.depth() < max_n_levels)
164 // && ( node.axis() != node_box.longest_axis()
165 // || node_box.size(node_box.longest_axis()) < box.size(node.axis()) * size_reduce_factor )
166 // )
167  {
168  uint ht = make_node(node_box, node.child(1) );
169  height = max(height, ht);
170  }
171 // else{
172 // xprintf(Msg,"%d %d %f %f\n",node_idx, child.leaf_size(),
173 // node_box.size(node_box.longest_axis()),
174 // box.size(node.axis()));
175 // }
176  }
177  return height+1;
178 }
179 
180 
181 double BIHTree::estimate_median(unsigned char axis, const BIHNode &node)
182 {
183  unsigned int median_idx;
184  unsigned int n_elements = node.leaf_size();
185 
186  // TODO: possible optimizations:
187  // - try to apply nth_element directly to in_leaves_ array
188  // - if current approach is better (due to cache memory), check randomization of median for large meshes
189  // - good balancing of tree is crutial both for creation and find method
190 
191 // unsigned int sample_size = 50+n_elements/5;
192 // if (n_elements > sample_size) {
193 // // random sample
194 // std::uniform_int_distribution<unsigned int> distribution(node.leaf_begin(), node.leaf_end()-1);
195 // coors_.resize(sample_size);
196 // for (unsigned int i=0; i<coors_.size(); i++) {
197 // median_idx = distribution(this->r_gen);
198 //
199 // coors_[i] = elements_[ in_leaves_[ median_idx ] ].projection_center(axis);
200 // }
201 //
202 // } else
203  {
204  // all elements
205  coors_.resize(n_elements);
206  for (unsigned int i=0; i<coors_.size(); i++) {
207  median_idx = node.leaf_begin() + i;
208  coors_[i] = elements_[ in_leaves_[ median_idx ] ].projection_center(axis);
209  }
210 
211  }
212 
213  unsigned int median_position = (unsigned int)(coors_.size() / 2);
214  std::nth_element(coors_.begin(), coors_.begin()+median_position, coors_.end());
215 
216  return coors_[median_position];
217 }
218 
219 
220 unsigned int BIHTree::get_element_count() const {
221  return elements_.size();
222 }
223 
224 
226  return main_box_;
227 }
228 
229 
230 void BIHTree::find_bounding_box(const BoundingBox &box, std::vector<unsigned int> &result_list, bool full_list) const
231 {
232 
233  ASSERT_EQ(result_list.size() , 0);
234 
235  unsigned int counter = 0;
236  node_stack_.clear();
237  node_stack_.push_back(0);
238  while (! node_stack_.empty()) {
239  const BIHNode &node = nodes_[node_stack_.back()];
240  //DebugOut().fmt("node: {}\n", node_stack.top() );
241  node_stack_.pop_back();
242 
243 
244  if (node.is_leaf()) {
245 
246  counter ++;
247  //START_TIMER("leaf");
248  for (unsigned int i=node.leaf_begin(); i<node.leaf_end(); i++) {
249  if (full_list || elements_[ in_leaves_[i] ].intersect(box)) {
250 
251  result_list.push_back(in_leaves_[i]);
252  }
253  }
254  //END_TIMER("leaf");
255  } else {
256  //START_TIMER("recursion");
257  if ( ! box.projection_gt( node.axis(), nodes_[node.child(0)].bound() ) ) {
258  // box intersects left group
259  node_stack_.push_back( node.child(0) );
260  }
261  if ( ! box.projection_lt( node.axis(), nodes_[node.child(1)].bound() ) ) {
262  // box intersects right group
263  node_stack_.push_back( node.child(1) );
264  }
265  //END_TIMER("recursion");
266  }
267  }
268  //node_stack_.pop_back();
269  //cout << "stack size: " << node_stack_.size();
270 
271 // xprintf(Msg,"leaves: %d\n",counter);
272 
273 //#ifdef FLOW123D_DEBUG_ASSERTS
274 // // check uniqueness of element indexes
275 // std::vector<unsigned int> cpy(result_list);
276 // sort(cpy.begin(), cpy.end());
277 // std::vector<unsigned int>::iterator it = unique(cpy.begin(), cpy.end());
278 // OLD_ASSERT_EQUAL(cpy.size() , it - cpy.begin());
279 //#endif
280 }
281 
282 
283 void BIHTree::find_point(const Space<3>::Point &point, std::vector<unsigned int> &result_list, bool full_list) const
284 {
285  find_bounding_box(BoundingBox(point), result_list, full_list);
286 }
287 
288 
289 
void set_max(unsigned int axis, double max)
static const double size_reduce_factor
required reduction in size of box to allow further splitting
Definition: bih_tree.hh:106
unsigned int leaf_end() const
Definition: bih_node.hh:73
double bound() const
Definition: bih_node.hh:97
Bounding box in 3d ambient space.
Definition: bounding_box.hh:54
unsigned int child(unsigned int i_child) const
Return index of child node.
Definition: bih_node.hh:103
unsigned int uint
unsigned char longest_axis() const
unsigned int max_n_levels
Maximal count of BIH tree levels.
Definition: bih_tree.hh:143
void split_node(const BoundingBox &node_box, unsigned int node_idx)
create bounding boxes of element
Definition: bih_tree.cc:75
#define ASSERT_GT(a, b)
Definition of comparative assert macro (Greater Than)
Definition: asserts.hh:311
std::vector< BoundingBox > elements_
mesh
Definition: bih_tree.hh:132
double estimate_median(unsigned char axis, const BIHNode &node)
Definition: bih_tree.cc:181
std::vector< unsigned int > node_stack_
Stack for search algorithms.
Definition: bih_tree.hh:136
void expand(const Point &point)
uint make_node(const BoundingBox &box, unsigned int node_idx)
Definition: bih_tree.cc:130
BoundingBox main_box_
Main bounding box. (from mesh)
Definition: bih_tree.hh:134
#define OLD_ASSERT(...)
Definition: global_defs.h:131
Global macros to enhance readability and debugging, general constants.
void find_bounding_box(const BoundingBox &boundingBox, std::vector< unsigned int > &result_list, bool full_list=false) const
Definition: bih_tree.cc:230
BIHTree(unsigned int soft_leaf_size_limit=BIHTree::default_leaf_size_limit)
Definition: bih_tree.cc:34
unsigned int leaf_size_limit
Maximal number of elements stored in a leaf node of BIH tree.
Definition: bih_tree.hh:141
arma::vec::fixed< spacedim > Point
Definition: point.hh:42
const BoundingBox & tree_box() const
Definition: bih_tree.cc:225
bool projection_lt(unsigned int axis, double value) const
const Point & max() const
unsigned char depth() const
return depth of leaf node
Definition: bih_node.hh:61
bool projection_gt(unsigned int axis, double value) const
~BIHTree()
Definition: bih_tree.cc:39
static const unsigned int default_leaf_size_limit
Default leaf size limit.
Definition: bih_tree.hh:45
std::vector< double > coors_
temporary vector stored values of coordinations for calculating median
Definition: bih_tree.hh:148
void swap(nlohmann::json &j1, nlohmann::json &j2) noexcept(is_nothrow_move_constructible< nlohmann::json >::value andis_nothrow_move_assignable< nlohmann::json >::value)
exchanges the values of two JSON objects
Definition: json.hpp:8688
std::vector< unsigned int > in_leaves_
vector stored element indexes in leaf nodes
Definition: bih_tree.hh:146
unsigned int get_element_count() const
Definition: bih_tree.cc:220
unsigned int leaf_size() const
Definition: bih_node.hh:84
void find_point(const Space< 3 >::Point &point, std::vector< unsigned int > &result_list, bool full_list=false) const
Definition: bih_tree.cc:283
#define ASSERT_DBG(expr)
Definition: asserts.hh:349
unsigned int axis() const
return axes (coordination of splitting) of inner node
Definition: bih_node.hh:91
void set_min(unsigned int axis, double min)
bool is_leaf() const
return true if node is leaf
Definition: bih_node.hh:56
const Point & min() const
void construct()
Definition: bih_tree.cc:51
void add_boxes(const std::vector< BoundingBox > &boxes)
Definition: bih_tree.cc:43
#define ASSERT_EQ(a, b)
Definition of comparative assert macro (EQual)
Definition: asserts.hh:327
unsigned int leaf_begin() const
Definition: bih_node.hh:67
const BoundingBox & ele_bounding_box(unsigned int ele_idx) const
Gets bounding box of element of given index ele_index.
Definition: bih_tree.cc:68
std::vector< BIHNode > nodes_
vector of tree nodes
Definition: bih_tree.hh:139