Flow123d  release_2.2.0-20-gb8056ca
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), leaf_size_limit(soft_leaf_size_limit), r_gen(123)
33 {
34  OLD_ASSERT(mesh != nullptr, " ");
35  max_n_levels = 2*log(mesh->n_elements())/log(2);
36 
37  nodes_.reserve(2*mesh_->n_elements() / leaf_size_limit);
38  element_boxes();
39 
40  in_leaves_.resize(elements_.size());
41  for(unsigned int i=0; i<in_leaves_.size(); i++) in_leaves_[i] = i;
42 
43  // make root node
44  nodes_.push_back(BIHNode());
45  nodes_.back().set_leaf(0, in_leaves_.size(), 0, 0);
46  // make root box
47  Node* node = mesh_->node_vector.begin();
48  main_box_ = BoundingBox(node->point(), node->point());
49  FOR_NODES(mesh_, node ) {
50  main_box_.expand( node->point() );
51  }
52 
53  make_node(main_box_, 0);
54 }
55 
56 
58 
59 }
60 
61 
62 void BIHTree::split_node(const BoundingBox &node_box, unsigned int node_idx) {
63  BIHNode &node = nodes_[node_idx];
64  OLD_ASSERT(node.is_leaf(), " ");
65  unsigned int axis = node_box.longest_axis();
66  double median = estimate_median(axis, node);
67 
68  // split elements in node according to the median
69  auto left = in_leaves_.begin() + node.leaf_begin(); // first of unresolved elements in @p in_leaves_
70  auto right = in_leaves_.begin() + node.leaf_end()-1; // last of unresolved elements in @p in_leaves_
71 
72  double left_bound=node_box.min(axis); // max bound of the left group
73  double right_bound=node_box.max(axis); // min bound of the right group
74 
75  while (left != right) {
76  if ( elements_[ *left ].projection_center(axis) < median) {
77  left_bound = std::max( left_bound, elements_[ *left ].max(axis) );
78  ++left;
79  }
80  else {
81  while ( left != right
82  && elements_[ *right ].projection_center(axis) >= median ) {
83  right_bound = std::min( right_bound, elements_[ *right ].min(axis) );
84  --right;
85  }
86  std::swap( *left, *right);
87  }
88  }
89  // in any case left==right is now the first element of the right group
90 
91  if ( elements_[ *left ].projection_center(axis) < median) {
92  left_bound = std::max( left_bound, elements_[ *left ].max(axis) );
93  ++left;
94  ++right;
95  } else {
96  right_bound = std::min( right_bound, elements_[ *right ].min(axis) );
97  }
98 
99  unsigned int left_begin = node.leaf_begin();
100  unsigned int left_end = left - in_leaves_.begin();
101  unsigned int right_end = node.leaf_end();
102  unsigned int depth = node.depth()+1;
103  // create new leaf nodes and possibly call split_node on them
104  // can not use node reference anymore
105  nodes_.push_back(BIHNode());
106  nodes_.back().set_leaf(left_begin, left_end, left_bound, depth);
107  nodes_.push_back(BIHNode());
108  nodes_.back().set_leaf(left_end, right_end, right_bound, depth);
109 
110  nodes_[node_idx].set_non_leaf(nodes_.size()-2, nodes_.size()-1, axis);
111 }
112 
113 
114 void BIHTree::make_node(const BoundingBox &box, unsigned int node_idx) {
115  // we must refer to the node by index to prevent seg. fault due to nodes_ reallocation
116 
117  split_node(box,node_idx);
118 
119  {
120  BIHNode &node = nodes_[node_idx];
121  BIHNode &child = nodes_[ node.child(0) ];
122  BoundingBox node_box(box);
123  node_box.set_max(node.axis(), child.bound() );
124  if ( child.leaf_size() > leaf_size_limit
125  && child.depth() < max_n_levels
126  && ( node.axis() != node_box.longest_axis()
127  || node_box.size(node_box.longest_axis()) < box.size(node.axis()) * size_reduce_factor )
128  )
129  {
130  make_node(node_box, node.child(0) );
131  }
132  }
133 
134  {
135  BIHNode &node = nodes_[node_idx];
136  BIHNode &child = nodes_[ node.child(1) ];
137  BoundingBox node_box(box);
138  node_box.set_min(node.axis(), child.bound() );
139  if ( child.leaf_size() > leaf_size_limit
140  && child.depth() < max_n_levels
141  && ( node.axis() != node_box.longest_axis()
142  || node_box.size(node_box.longest_axis()) < box.size(node.axis()) * size_reduce_factor )
143  )
144  {
145  make_node(node_box, node.child(1) );
146  }
147  }
148 }
149 
150 
151 double BIHTree::estimate_median(unsigned char axis, const BIHNode &node)
152 {
153  unsigned int median_idx;
154  unsigned int n_elements = node.leaf_size();
155 
156  if (n_elements > max_median_sample_size) {
157  // random sample
158  std::uniform_int_distribution<unsigned int> distribution(node.leaf_begin(), node.leaf_end()-1);
160  for (unsigned int i=0; i<coors_.size(); i++) {
161  median_idx = distribution(this->r_gen);
162 
163  coors_[i] = elements_[ in_leaves_[ median_idx ] ].projection_center(axis);
164  }
165 
166  } else {
167  // all elements
168  coors_.resize(n_elements);
169  for (unsigned int i=0; i<coors_.size(); i++) {
170  median_idx = node.leaf_begin() + i;
171  coors_[i] = elements_[ in_leaves_[ median_idx ] ].projection_center(axis);
172  }
173 
174  }
175 
176  unsigned int median_position = (unsigned int)(coors_.size() / 2);
177  std::nth_element(coors_.begin(), coors_.begin()+median_position, coors_.end());
178 
179  return coors_[median_position];
180 }
181 
182 
184  return elements_.size();
185 }
186 
187 
189  return main_box_;
190 }
191 
192 
194 {
195  std::stack<unsigned int, std::vector<unsigned int> > node_stack;
196  OLD_ASSERT_EQUAL(result_list.size() , 0);
197 
198  node_stack.push(0);
199  while (! node_stack.empty()) {
200  const BIHNode &node = nodes_[node_stack.top()];
201  //DebugOut().fmt("node: {}\n", node_stack.top() );
202  node_stack.pop();
203 
204 
205  if (node.is_leaf()) {
206 
207  //START_TIMER("leaf");
208  for (unsigned int i=node.leaf_begin(); i<node.leaf_end(); i++) {
209  if (elements_[ in_leaves_[i] ].intersect(box)) {
210 
211  result_list.push_back(in_leaves_[i]);
212  }
213  }
214  //END_TIMER("leaf");
215  } else {
216  //START_TIMER("recursion");
217  if ( ! box.projection_gt( node.axis(), nodes_[node.child(0)].bound() ) ) {
218  // box intersects left group
219  node_stack.push( node.child(0) );
220  }
221  if ( ! box.projection_lt( node.axis(), nodes_[node.child(1)].bound() ) ) {
222  // box intersects right group
223  node_stack.push( node.child(1) );
224  }
225  //END_TIMER("recursion");
226  }
227  }
228 
229 
230 #ifdef FLOW123D_DEBUG_ASSERTS
231  // check uniqueness of element indexes
232  std::vector<unsigned int> cpy(result_list);
233  sort(cpy.begin(), cpy.end());
234  std::vector<unsigned int>::iterator it = unique(cpy.begin(), cpy.end());
235  OLD_ASSERT_EQUAL(cpy.size() , it - cpy.begin());
236 #endif
237 }
238 
239 
241 {
242  find_bounding_box(BoundingBox(point), result_list);
243 }
244 
245 
247  elements_.resize(mesh_->element.size());
248  unsigned int i=0;
249  FOR_ELEMENTS(mesh_, element) {
250  elements_[i] = element->bounding_box();
251 
252  i++;
253  }
254 }
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:94
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:115
Definition: nodes.hh:32
unsigned char longest_axis() const
#define FOR_ELEMENTS(_mesh_, __i)
Definition: mesh.h:426
unsigned int max_n_levels
Maximal count of BIH tree levels.
Definition: bih_tree.hh:125
void split_node(const BoundingBox &node_box, unsigned int node_idx)
split tree node given by node_idx, distribute elements to child nodes
Definition: bih_tree.cc:62
std::vector< BoundingBox > elements_
vector of mesh elements bounding boxes
Definition: bih_tree.hh:117
double estimate_median(unsigned char axis, const BIHNode &node)
Definition: bih_tree.cc:151
void expand(const Point &point)
Definition: mesh.h:97
void element_boxes()
create bounding boxes of element
Definition: bih_tree.cc:246
BoundingBox main_box_
Main bounding box.
Definition: bih_tree.hh:121
void make_node(const BoundingBox &box, unsigned int node_idx)
create child nodes of node given by node_idx
Definition: bih_tree.cc:114
unsigned int size() const
Returns size of the container. This is independent of the allocated space.
Definition: sys_vector.hh:391
#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:141
unsigned int leaf_size_limit
Maximal number of elements stored in a leaf node of BIH tree.
Definition: bih_tree.hh:123
arma::vec::fixed< spacedim > Point
Definition: point.hh:33
const BoundingBox & tree_box() const
Definition: bih_tree.cc:188
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:57
FullIter begin()
Definition: sys_vector.hh:383
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:130
void find_point(const Space< 3 >::Point &point, std::vector< unsigned int > &result_list) const
Definition: bih_tree.cc:240
#define FOR_NODES(_mesh_, i)
Definition: mesh.h:58
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
double size(unsigned int axis) const
void find_bounding_box(const BoundingBox &boundingBox, std::vector< unsigned int > &result_list) const
Definition: bih_tree.cc:193
std::vector< unsigned int > in_leaves_
vector stored element indexes in leaf nodes
Definition: bih_tree.hh:128
unsigned int leaf_size() const
Definition: bih_node.hh:84
std::mt19937 r_gen
Definition: bih_tree.hh:133
unsigned int get_element_count()
Definition: bih_tree.cc:183
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
arma::vec3 & point()
Definition: nodes.hh:68
static const unsigned int max_median_sample_size
max count of elements to estimate median - value must be even
Definition: bih_tree.hh:41
NodeVector node_vector
Vector of nodes of the mesh.
Definition: mesh.h:226
unsigned int leaf_begin() const
Definition: bih_node.hh:67
ElementVector element
Vector of elements of the mesh.
Definition: mesh.h:228
std::vector< BIHNode > nodes_
vector of tree nodes
Definition: bih_tree.hh:119