Flow123d  jenkins-Flow123d-windows-release-multijob-285
bih_tree.cc
Go to the documentation of this file.
1 /**!
2  *
3  * Copyright (C) 2007 Technical University of Liberec. All rights reserved.
4  *
5  * Please make a following refer to Flow123d on your project site if you use the program for any purpose,
6  * especially for academic research:
7  * Flow123d, Research Centre: Advanced Remedial Technologies, Technical University of Liberec, Czech Republic
8  *
9  * This program is free software; you can redistribute it and/or modify it under the terms
10  * of the GNU General Public License version 3 as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14  * See the GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along with this program; if not,
17  * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 021110-1307, USA.
18  *
19  *
20  * $Id: bih_tree.cc 1567 2012-02-28 13:24:58Z jan.brezina $
21  * $Revision: 1567 $
22  * $LastChangedBy: jan.brezina $
23  * $LastChangedDate: 2012-02-28 14:24:58 +0100 (Tue, 28 Feb 2012) $
24  *
25  *
26  */
27 
28 #include "mesh/bih_tree.hh"
29 #include "mesh/bih_node.hh"
30 #include "system/global_defs.h"
31 #include <ctime>
32 #include <stack>
33 
34 /**
35  * Minimum reduction of box size to allow
36  * splitting of a node during tree creation.
37  */
38 const double BIHTree::size_reduce_factor = 0.8;
39 
40 
41 BIHTree::BIHTree(Mesh* mesh, unsigned int soft_leaf_size_limit)
42 : mesh_(mesh), leaf_size_limit(soft_leaf_size_limit), r_gen(123)
43 {
44  ASSERT(mesh != nullptr, " ");
45  max_n_levels = 2*log(mesh->n_elements())/log(2);
46 
47  nodes_.reserve(2*mesh_->n_elements() / leaf_size_limit);
48  element_boxes();
49 
50  in_leaves_.resize(elements_.size());
51  for(unsigned int i=0; i<in_leaves_.size(); i++) in_leaves_[i] = i;
52 
53  // make root node
54  nodes_.push_back(BIHNode());
55  nodes_.back().set_leaf(0, in_leaves_.size(), 0, 0);
56  // make root box
57  Node* node = mesh_->node_vector.begin();
58  main_box_ = BoundingBox(node->point(), node->point());
59  FOR_NODES(mesh_, node ) {
60  main_box_.expand( node->point() );
61  }
62 
63  make_node(main_box_, 0);
64 }
65 
66 
68 
69 }
70 
71 
72 void BIHTree::split_node(const BoundingBox &node_box, unsigned int node_idx) {
73  BIHNode &node = nodes_[node_idx];
74  ASSERT(node.is_leaf(), " ");
75  unsigned int axis = node_box.longest_axis();
76  double median = estimate_median(axis, node);
77 
78  // split elements in node according to the median
79  auto left = in_leaves_.begin() + node.leaf_begin(); // first of unresolved elements in @p in_leaves_
80  auto right = in_leaves_.begin() + node.leaf_end()-1; // last of unresolved elements in @p in_leaves_
81 
82  double left_bound=node_box.min(axis); // max bound of the left group
83  double right_bound=node_box.max(axis); // min bound of the right group
84 
85  while (left != right) {
86  if ( elements_[ *left ].projection_center(axis) < median) {
87  left_bound = std::max( left_bound, elements_[ *left ].max(axis) );
88  ++left;
89  }
90  else {
91  while ( left != right
92  && elements_[ *right ].projection_center(axis) >= median ) {
93  right_bound = std::min( right_bound, elements_[ *right ].min(axis) );
94  --right;
95  }
96  std::swap( *left, *right);
97  }
98  }
99  // in any case left==right is now the first element of the right group
100 
101  if ( elements_[ *left ].projection_center(axis) < median) {
102  left_bound = std::max( left_bound, elements_[ *left ].max(axis) );
103  ++left;
104  ++right;
105  } else {
106  right_bound = std::min( right_bound, elements_[ *right ].min(axis) );
107  }
108 
109  unsigned int left_begin = node.leaf_begin();
110  unsigned int left_end = left - in_leaves_.begin();
111  unsigned int right_end = node.leaf_end();
112  unsigned int depth = node.depth()+1;
113  // create new leaf nodes and possibly call split_node on them
114  // can not use node reference anymore
115  nodes_.push_back(BIHNode());
116  nodes_.back().set_leaf(left_begin, left_end, left_bound, depth);
117  nodes_.push_back(BIHNode());
118  nodes_.back().set_leaf(left_end, right_end, right_bound, depth);
119 
120  nodes_[node_idx].set_non_leaf(nodes_.size()-2, nodes_.size()-1, axis);
121 }
122 
123 
124 void BIHTree::make_node(const BoundingBox &box, unsigned int node_idx) {
125  // we must refer to the node by index to prevent seg. fault due to nodes_ reallocation
126 
127  split_node(box,node_idx);
128 
129  {
130  BIHNode &node = nodes_[node_idx];
131  BIHNode &child = nodes_[ node.child(0) ];
132  BoundingBox node_box(box);
133  node_box.set_max(node.axis(), child.bound() );
134  if ( child.leaf_size() > leaf_size_limit
135  && child.depth() < max_n_levels
136  && ( node.axis() != node_box.longest_axis()
137  || node_box.size(node_box.longest_axis()) < box.size(node.axis()) * size_reduce_factor )
138  )
139  {
140  make_node(node_box, node.child(0) );
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  }
158 }
159 
160 
161 double BIHTree::estimate_median(unsigned char axis, const BIHNode &node)
162 {
163  unsigned int median_idx;
164  unsigned int n_elements = node.leaf_size();
165 
166  if (n_elements > max_median_sample_size) {
167  // random sample
168  std::uniform_int_distribution<unsigned int> distribution(node.leaf_begin(), node.leaf_end()-1);
170  for (unsigned int i=0; i<coors_.size(); i++) {
171  median_idx = distribution(this->r_gen);
172 
173  coors_[i] = elements_[ in_leaves_[ median_idx ] ].projection_center(axis);
174  }
175 
176  } else {
177  // all elements
178  coors_.resize(n_elements);
179  for (unsigned int i=0; i<coors_.size(); i++) {
180  median_idx = node.leaf_begin() + i;
181  coors_[i] = elements_[ in_leaves_[ median_idx ] ].projection_center(axis);
182  }
183 
184  }
185 
186  unsigned int median_position = (unsigned int)(coors_.size() / 2);
187  std::nth_element(coors_.begin(), coors_.begin()+median_position, coors_.end());
188 
189  return coors_[median_position];
190 }
191 
192 
194  return elements_.size();
195 }
196 
197 
199  return main_box_;
200 }
201 
202 
204 {
205  std::stack<unsigned int, std::vector<unsigned int> > node_stack;
206  ASSERT_EQUAL(result_list.size() , 0);
207 
208  node_stack.push(0);
209  while (! node_stack.empty()) {
210  const BIHNode &node = nodes_[node_stack.top()];
211  //DBGMSG("node: %d\n", node_stack.top() );
212  node_stack.pop();
213 
214 
215  if (node.is_leaf()) {
216 
217  //START_TIMER("leaf");
218  for (unsigned int i=node.leaf_begin(); i<node.leaf_end(); i++) {
219  if (elements_[ in_leaves_[i] ].intersect(box)) {
220 
221  result_list.push_back(in_leaves_[i]);
222  }
223  }
224  //END_TIMER("leaf");
225  } else {
226  //START_TIMER("recursion");
227  if ( ! box.projection_gt( node.axis(), nodes_[node.child(0)].bound() ) ) {
228  // box intersects left group
229  node_stack.push( node.child(0) );
230  }
231  if ( ! box.projection_lt( node.axis(), nodes_[node.child(1)].bound() ) ) {
232  // box intersects right group
233  node_stack.push( node.child(1) );
234  }
235  //END_TIMER("recursion");
236  }
237  }
238 
239 
240 #ifdef DEBUG_ASSERT
241  // check uniqueness of element indexes
242  sort(result_list.begin(), result_list.end());
243  it = unique(result_list.begin(), result_list.end());
244  ASSERT_EQUAL(searsearchedElements.size() , it - result_list.begin());
245 #endif
246 }
247 
248 
250  find_bounding_box(BoundingBox(point), result_list);
251 }
252 
253 
255  elements_.resize(mesh_->element.size());
256  unsigned int i=0;
257  FOR_ELEMENTS(mesh_, element) {
258  elements_[i] = element->bounding_box();
259 
260  i++;
261  }
262 }
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:104
unsigned int leaf_end() const
Definition: bih_node.hh:84
double bound() const
Definition: bih_node.hh:108
Bounding box in 3d ambient space.
Definition: bounding_box.hh:55
unsigned int child(unsigned int i_child) const
Return index of child node.
Definition: bih_node.hh:114
const BoundingBox & tree_box()
Definition: bih_tree.cc:198
Mesh * mesh_
mesh
Definition: bih_tree.hh:125
Definition: nodes.hh:44
void find_bounding_box(const BoundingBox &boundingBox, std::vector< unsigned int > &result_list)
Definition: bih_tree.cc:203
unsigned char longest_axis() const
#define FOR_ELEMENTS(_mesh_, __i)
Definition: mesh.h:364
unsigned int max_n_levels
Maximal count of BIH tree levels.
Definition: bih_tree.hh:135
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:72
std::vector< BoundingBox > elements_
vector of mesh elements bounding boxes
Definition: bih_tree.hh:127
double estimate_median(unsigned char axis, const BIHNode &node)
Definition: bih_tree.cc:161
void expand(const Point &point)
Definition: mesh.h:109
void element_boxes()
create bounding boxes of element
Definition: bih_tree.cc:254
BoundingBox main_box_
Main bounding box.
Definition: bih_tree.hh:131
void make_node(const BoundingBox &box, unsigned int node_idx)
create child nodes of node given by node_idx
Definition: bih_tree.cc:124
unsigned int size() const
Returns size of the container. This is independent of the allocated space.
Definition: sys_vector.hh:401
Global macros to enhance readability and debugging, general constants.
unsigned int n_elements() const
Definition: mesh.h:141
#define ASSERT(...)
Definition: global_defs.h:121
unsigned int leaf_size_limit
Maximal number of elements stored in a leaf node of BIH tree.
Definition: bih_tree.hh:133
arma::vec::fixed< spacedim > Point
Definition: point.hh:23
#define ASSERT_EQUAL(a, b)
Definition: global_defs.h:136
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:72
bool projection_gt(unsigned int axis, double value) const
~BIHTree()
Definition: bih_tree.cc:67
FullIter begin()
Definition: sys_vector.hh:393
BIHTree(Mesh *mesh, unsigned int soft_leaf_size_limit=20)
Definition: bih_tree.cc:41
std::vector< double > coors_
temporary vector stored values of coordinations for calculating median
Definition: bih_tree.hh:140
#define FOR_NODES(_mesh_, i)
Definition: mesh.h:72
double size(unsigned int axis) const
std::vector< unsigned int > in_leaves_
vector stored element indexes in leaf nodes
Definition: bih_tree.hh:138
unsigned int leaf_size() const
Definition: bih_node.hh:95
std::mt19937 r_gen
Definition: bih_tree.hh:143
unsigned int get_element_count()
Definition: bih_tree.cc:193
unsigned int axis() const
return axes (coordination of splitting) of inner node
Definition: bih_node.hh:102
void set_min(unsigned int axis, double min)
bool is_leaf() const
return true if node is leaf
Definition: bih_node.hh:67
const Point & min() const
void find_point(const Space< 3 >::Point &point, std::vector< unsigned int > &result_list)
Definition: bih_tree.cc:249
arma::vec3 & point()
Definition: nodes.hh:80
static const unsigned int max_median_sample_size
max count of elements to estimate median - value must be even
Definition: bih_tree.hh:51
NodeVector node_vector
Vector of nodes of the mesh.
Definition: mesh.h:203
unsigned int leaf_begin() const
Definition: bih_node.hh:78
ElementVector element
Vector of elements of the mesh.
Definition: mesh.h:205
std::vector< BIHNode > nodes_
vector of tree nodes
Definition: bih_tree.hh:129