Flow123d  release_2.2.0-914-gf1a3a4f
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 "system/global_defs.h"
21 #include <ctime>
22 #include <stack>
23 
24 /**
25  * Minimum reduction of box size to allow
26  * splitting of a node during tree creation.
27  */
28 const double BIHTree::size_reduce_factor = 0.8;
29 
30 
31 BIHTree::BIHTree(Mesh* mesh, unsigned int soft_leaf_size_limit)
32 : mesh_(mesh),
33  elements_(mesh_->element_box_),
34  main_box_(mesh_->mesh_box_),
35  leaf_size_limit(soft_leaf_size_limit), r_gen(123)
36 {
37  OLD_ASSERT(mesh != nullptr, " ");
38 
40 
41  max_n_levels = 2*log(mesh->n_elements())/log(2);
42  nodes_.reserve(2*mesh_->n_elements() / leaf_size_limit);
43  in_leaves_.resize(elements_.size());
44  for(unsigned int i=0; i<in_leaves_.size(); i++) in_leaves_[i] = i;
45 
46  // make root node
47  nodes_.push_back(BIHNode());
48  nodes_.back().set_leaf(0, in_leaves_.size(), 0, 0);
49  make_node(main_box_, 0);
50 }
51 
52 
54 
55 }
56 
57 const BoundingBox& BIHTree::ele_bounding_box(unsigned int ele_idx) const
58 {
59  ASSERT_DBG(ele_idx < elements_.size());
60  return elements_[ele_idx];
61 }
62 
63 
64 void BIHTree::split_node(const BoundingBox &node_box, unsigned int node_idx) {
65  BIHNode &node = nodes_[node_idx];
66  OLD_ASSERT(node.is_leaf(), " ");
67  unsigned int axis = node_box.longest_axis();
68  double median = estimate_median(axis, node);
69 
70  // split elements in node according to the median
71  auto left = in_leaves_.begin() + node.leaf_begin(); // first of unresolved elements in @p in_leaves_
72  auto right = in_leaves_.begin() + node.leaf_end()-1; // last of unresolved elements in @p in_leaves_
73 
74  double left_bound=node_box.min(axis); // max bound of the left group
75  double right_bound=node_box.max(axis); // min bound of the right group
76 
77  while (left != right) {
78  if ( elements_[ *left ].projection_center(axis) < median) {
79  left_bound = std::max( left_bound, elements_[ *left ].max(axis) );
80  ++left;
81  }
82  else {
83  while ( left != right
84  && elements_[ *right ].projection_center(axis) >= median ) {
85  right_bound = std::min( right_bound, elements_[ *right ].min(axis) );
86  --right;
87  }
88  std::swap( *left, *right);
89  }
90  }
91  // in any case left==right is now the first element of the right group
92 
93  if ( elements_[ *left ].projection_center(axis) < median) {
94  left_bound = std::max( left_bound, elements_[ *left ].max(axis) );
95  ++left;
96  ++right;
97  } else {
98  right_bound = std::min( right_bound, elements_[ *right ].min(axis) );
99  }
100 
101  unsigned int left_begin = node.leaf_begin();
102  unsigned int left_end = left - in_leaves_.begin();
103  unsigned int right_end = node.leaf_end();
104  unsigned int depth = node.depth()+1;
105  // create new leaf nodes and possibly call split_node on them
106  // can not use node reference anymore
107  nodes_.push_back(BIHNode());
108  nodes_.back().set_leaf(left_begin, left_end, left_bound, depth);
109  nodes_.push_back(BIHNode());
110  nodes_.back().set_leaf(left_end, right_end, right_bound, depth);
111 
112  nodes_[node_idx].set_non_leaf(nodes_.size()-2, nodes_.size()-1, axis);
113 
114 // xprintf(Msg, "%d %f %f %f %f %d %d\n", node_idx, node_box.min(axis), left_bound, right_bound, node_box.max(axis),
115 // left_end - left_begin, right_end - left_end );
116 }
117 
118 
119 void BIHTree::make_node(const BoundingBox &box, unsigned int node_idx) {
120  // we must refer to the node by index to prevent seg. fault due to nodes_ reallocation
121 
122  split_node(box,node_idx);
123 
124  {
125  BIHNode &node = nodes_[node_idx];
126  BIHNode &child = nodes_[ node.child(0) ];
127  BoundingBox node_box(box);
128  node_box.set_max(node.axis(), child.bound() );
129  if ( child.leaf_size() > leaf_size_limit
130  && child.depth() < max_n_levels)
131 // && ( node.axis() != node_box.longest_axis()
132 // || node_box.size(node_box.longest_axis()) < box.size(node.axis()) * size_reduce_factor )
133 // )
134  {
135  make_node(node_box, node.child(0) );
136  }
137 // else{
138 // xprintf(Msg,"%d %d %f %f\n",node_idx, child.leaf_size(),
139 // node_box.size(node_box.longest_axis()),
140 // box.size(node.axis()));
141 // }
142  }
143 
144  {
145  BIHNode &node = nodes_[node_idx];
146  BIHNode &child = nodes_[ node.child(1) ];
147  BoundingBox node_box(box);
148  node_box.set_min(node.axis(), child.bound() );
149  if ( child.leaf_size() > leaf_size_limit
150  && child.depth() < max_n_levels)
151 // && ( node.axis() != node_box.longest_axis()
152 // || node_box.size(node_box.longest_axis()) < box.size(node.axis()) * size_reduce_factor )
153 // )
154  {
155  make_node(node_box, node.child(1) );
156  }
157 // else{
158 // xprintf(Msg,"%d %d %f %f\n",node_idx, child.leaf_size(),
159 // node_box.size(node_box.longest_axis()),
160 // box.size(node.axis()));
161 // }
162  }
163 }
164 
165 
166 double BIHTree::estimate_median(unsigned char axis, const BIHNode &node)
167 {
168  unsigned int median_idx;
169  unsigned int n_elements = node.leaf_size();
170 
171  // TODO: possible optimizations:
172  // - try to apply nth_element directly to in_leaves_ array
173  // - if current approach is better (due to cache memory), check randomization of median for large meshes
174  // - good balancing of tree is crutial both for creation and find method
175 
176 // unsigned int sample_size = 50+n_elements/5;
177 // if (n_elements > sample_size) {
178 // // random sample
179 // std::uniform_int_distribution<unsigned int> distribution(node.leaf_begin(), node.leaf_end()-1);
180 // coors_.resize(sample_size);
181 // for (unsigned int i=0; i<coors_.size(); i++) {
182 // median_idx = distribution(this->r_gen);
183 //
184 // coors_[i] = elements_[ in_leaves_[ median_idx ] ].projection_center(axis);
185 // }
186 //
187 // } else
188  {
189  // all elements
190  coors_.resize(n_elements);
191  for (unsigned int i=0; i<coors_.size(); i++) {
192  median_idx = node.leaf_begin() + i;
193  coors_[i] = elements_[ in_leaves_[ median_idx ] ].projection_center(axis);
194  }
195 
196  }
197 
198  unsigned int median_position = (unsigned int)(coors_.size() / 2);
199  std::nth_element(coors_.begin(), coors_.begin()+median_position, coors_.end());
200 
201  return coors_[median_position];
202 }
203 
204 
205 unsigned int BIHTree::get_element_count() const {
206  return elements_.size();
207 }
208 
209 
211  return main_box_;
212 }
213 
214 
215 void BIHTree::find_bounding_box(const BoundingBox &box, std::vector<unsigned int> &result_list, bool full_list) const
216 {
217  std::stack<unsigned int, std::vector<unsigned int> > node_stack;
218  OLD_ASSERT_EQUAL(result_list.size() , 0);
219 
220  unsigned int counter = 0;
221  node_stack.push(0);
222  while (! node_stack.empty()) {
223  const BIHNode &node = nodes_[node_stack.top()];
224  //DebugOut().fmt("node: {}\n", node_stack.top() );
225  node_stack.pop();
226 
227 
228  if (node.is_leaf()) {
229 
230  counter ++;
231  //START_TIMER("leaf");
232  for (unsigned int i=node.leaf_begin(); i<node.leaf_end(); i++) {
233  if (full_list || elements_[ in_leaves_[i] ].intersect(box)) {
234 
235  result_list.push_back(in_leaves_[i]);
236  }
237  }
238  //END_TIMER("leaf");
239  } else {
240  //START_TIMER("recursion");
241  if ( ! box.projection_gt( node.axis(), nodes_[node.child(0)].bound() ) ) {
242  // box intersects left group
243  node_stack.push( node.child(0) );
244  }
245  if ( ! box.projection_lt( node.axis(), nodes_[node.child(1)].bound() ) ) {
246  // box intersects right group
247  node_stack.push( node.child(1) );
248  }
249  //END_TIMER("recursion");
250  }
251  }
252 
253 // xprintf(Msg,"leaves: %d\n",counter);
254 
255 #ifdef FLOW123D_DEBUG_ASSERTS
256  // check uniqueness of element indexes
257  std::vector<unsigned int> cpy(result_list);
258  sort(cpy.begin(), cpy.end());
259  std::vector<unsigned int>::iterator it = unique(cpy.begin(), cpy.end());
260  OLD_ASSERT_EQUAL(cpy.size() , it - cpy.begin());
261 #endif
262 }
263 
264 
265 void BIHTree::find_point(const Space<3>::Point &point, std::vector<unsigned int> &result_list, bool full_list) const
266 {
267  find_bounding_box(BoundingBox(point), result_list, full_list);
268 }
269 
270 
271 
void set_max(unsigned int axis, double max)
Definition: bounding_box.hh:97
static const double size_reduce_factor
required reduction in size of box to allow further splitting
Definition: bih_tree.hh:99
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:45
unsigned int child(unsigned int i_child) const
Return index of child node.
Definition: bih_node.hh:103
Mesh * mesh_
mesh
Definition: bih_tree.hh:120
unsigned char longest_axis() const
unsigned int max_n_levels
Maximal count of BIH tree levels.
Definition: bih_tree.hh:131
void split_node(const BoundingBox &node_box, unsigned int node_idx)
create bounding boxes of element
Definition: bih_tree.cc:64
BoundingBox & main_box_
Main bounding box. (from mesh)
Definition: bih_tree.hh:124
double estimate_median(unsigned char axis, const BIHNode &node)
Definition: bih_tree.cc:166
Definition: mesh.h:99
std::vector< BoundingBox > & elements_
vector of mesh elements bounding boxes (from mesh)
Definition: bih_tree.hh:122
void compute_element_boxes()
Precompute element bounding boxes if it is not done yet.
Definition: mesh.cc:731
void make_node(const BoundingBox &box, unsigned int node_idx)
create child nodes of node given by node_idx
Definition: bih_tree.cc:119
#define OLD_ASSERT(...)
Definition: global_defs.h:131
Global macros to enhance readability and debugging, general constants.
unsigned int n_elements() const
Definition: mesh.h:156
void find_bounding_box(const BoundingBox &boundingBox, std::vector< unsigned int > &result_list, bool full_list=false) const
Definition: bih_tree.cc:215
unsigned int leaf_size_limit
Maximal number of elements stored in a leaf node of BIH tree.
Definition: bih_tree.hh:129
arma::vec::fixed< spacedim > Point
Definition: point.hh:33
const BoundingBox & tree_box() const
Definition: bih_tree.cc:210
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:53
BIHTree(Mesh *mesh, unsigned int soft_leaf_size_limit=20)
Definition: bih_tree.cc:31
std::vector< double > coors_
temporary vector stored values of coordinations for calculating median
Definition: bih_tree.hh:136
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:134
unsigned int get_element_count() const
Definition: bih_tree.cc:205
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:265
#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)
#define OLD_ASSERT_EQUAL(a, b)
Definition: global_defs.h:133
bool is_leaf() const
return true if node is leaf
Definition: bih_node.hh:56
const Point & min() const
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:57
std::vector< BIHNode > nodes_
vector of tree nodes
Definition: bih_tree.hh:127