Flow123d  jenkins-Flow123d-windows32-release-multijob-28
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  //DBGMSG("left_bound: %g\n", left_bound);
89  ++left;
90  }
91  else {
92  while ( left != right
93  && elements_[ *right ].projection_center(axis) >= median ) {
94  right_bound = std::min( right_bound, elements_[ *right ].min(axis) );
95  //DBGMSG("right_bound: %g\n", right_bound);
96  --right;
97  }
98  std::swap( *left, *right);
99  }
100  }
101  // in any case left==right is now the first element of the right group
102 
103  if ( elements_[ *left ].projection_center(axis) < median) {
104  left_bound = std::max( left_bound, elements_[ *left ].max(axis) );
105  //DBGMSG("left_bound: %g\n", left_bound);
106  ++left;
107  ++right;
108  } else {
109  right_bound = std::min( right_bound, elements_[ *right ].min(axis) );
110  //DBGMSG("right_bound: %g\n", right_bound);
111  }
112 
113  unsigned int left_begin = node.leaf_begin();
114  unsigned int left_end = left - in_leaves_.begin();
115  unsigned int right_end = node.leaf_end();
116  unsigned int depth = node.depth()+1;
117  // create new leaf nodes and possibly call split_node on them
118  // can not use node reference anymore
119  nodes_.push_back(BIHNode());
120  nodes_.back().set_leaf(left_begin, left_end, left_bound, depth);
121  nodes_.push_back(BIHNode());
122  nodes_.back().set_leaf(left_end, right_end, right_bound, depth);
123 
124  nodes_[node_idx].set_non_leaf(nodes_.size()-2, nodes_.size()-1, axis);
125 }
126 
127 
128 void BIHTree::make_node(const BoundingBox &box, unsigned int node_idx) {
129  // we must refer to the node by index to prevent seg. fault due to nodes_ reallocation
130 
131  split_node(box,node_idx);
132 
133  {
134  BIHNode &node = nodes_[node_idx];
135  BIHNode &child = nodes_[ node.child(0) ];
136 // DBGMSG("Node: %d\n",node.child(0));
137  BoundingBox node_box(box);
138  node_box.set_max(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(0) );
146  }
147  }
148 
149  {
150  BIHNode &node = nodes_[node_idx];
151  BIHNode &child = nodes_[ node.child(1) ];
152 // DBGMSG("Node: %d\n",node.child(1));
153  BoundingBox node_box(box);
154  node_box.set_min(node.axis(), child.bound() );
155  if ( child.leaf_size() > leaf_size_limit
156  && child.depth() < max_n_levels
157  && ( node.axis() != node_box.longest_axis()
158  || node_box.size(node_box.longest_axis()) < box.size(node.axis()) * size_reduce_factor )
159  )
160  {
161  make_node(node_box, node.child(1) );
162  }
163  }
164 }
165 
166 
167 double BIHTree::estimate_median(unsigned char axis, const BIHNode &node)
168 {
169  unsigned int median_idx;
170  unsigned int n_elements = node.leaf_size();
171 
172  if (n_elements > max_median_sample_size) {
173  // random sample
174  std::uniform_int_distribution<unsigned int> distribution(node.leaf_begin(), node.leaf_end()-1);
176  for (unsigned int i=0; i<coors_.size(); i++) {
177  median_idx = distribution(this->r_gen);
178 
179  coors_[i] = elements_[ in_leaves_[ median_idx ] ].projection_center(axis);
180  //DBGMSG(" random idx: %d, coor: %g\n", median_idx, coors_[i]);
181  }
182 
183  } else {
184  // all elements
185  coors_.resize(n_elements);
186  for (unsigned int i=0; i<coors_.size(); i++) {
187  median_idx = node.leaf_begin() + i;
188  coors_[i] = elements_[ in_leaves_[ median_idx ] ].projection_center(axis);
189  }
190 
191  }
192 
193  unsigned int median_position = (unsigned int)(coors_.size() / 2);
194  std::nth_element(coors_.begin(), coors_.begin()+median_position, coors_.end());
195 
196  //DBGMSG("median pos: %d %g\n", median_position, coors_[median_position]);
197  return coors_[median_position];
198 }
199 
200 
202  return elements_.size();
203 }
204 
205 
207  return main_box_;
208 }
209 
210 
212 {
213  std::stack<unsigned int, std::vector<unsigned int> > node_stack;
214  ASSERT_EQUAL(result_list.size() , 0);
215 
216  node_stack.push(0);
217  while (! node_stack.empty()) {
218  const BIHNode &node = nodes_[node_stack.top()];
219  //DBGMSG("node: %d\n", node_stack.top() );
220  node_stack.pop();
221 
222 
223  if (node.is_leaf()) {
224 
225  //DBGMSG( "leaf-size %d\n", node.leaf_size() );
226  //START_TIMER("leaf");
227  for (unsigned int i=node.leaf_begin(); i<node.leaf_end(); i++) {
228  //DBGMSG("check i: %d i_ele: %d id: %d\n", i, in_leaves_[i], mesh_->element( in_leaves_[i] ).id());
229  //DBGCOUT( << "in leaf: " << elements_[ in_leaves_[i] ] <<endl );
230  if (elements_[ in_leaves_[i] ].intersect(box)) {
231 
232  //DBGMSG("el_id: %d\n" , mesh_->element(in_leaves_[i]).id() );
233  result_list.push_back(in_leaves_[i]);
234  }
235  }
236  //END_TIMER("leaf");
237  } else {
238  //DBGMSG("axis: %d bound left: %g right: %g\n",node.axis(),nodes_[node.child(0)].bound(), nodes_[node.child(1)].bound());
239  //START_TIMER("recursion");
240  if ( ! box.projection_gt( node.axis(), nodes_[node.child(0)].bound() ) ) {
241  //DBGMSG("push:%d\n", node.child(0));
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  //DBGMSG("push:%d\n", node.child(1));
247  // box intersects right group
248  node_stack.push( node.child(1) );
249  }
250  //END_TIMER("recursion");
251  }
252  }
253 
254 
255 #ifdef DEBUG_ASSERT
256  // check uniqueness of element indexes
257  sort(result_list.begin(), result_list.end());
258  it = unique(result_list.begin(), result_list.end());
259  ASSERT_EQUAL(searsearchedElements.size() , it - result_list.begin());
260 #endif
261 }
262 
263 
265  find_bounding_box(BoundingBox(point), result_list);
266 }
267 
268 
270  elements_.resize(mesh_->element.size());
271  unsigned int i=0;
272  FOR_ELEMENTS(mesh_, element) {
273  elements_[i] = element->bounding_box();
274 
275  i++;
276  }
277 }
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:206
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:211
unsigned char longest_axis() const
#define FOR_ELEMENTS(_mesh_, __i)
Definition: mesh.h:359
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:167
void expand(const Point &point)
Definition: mesh.h:108
void element_boxes()
create bounding boxes of element
Definition: bih_tree.cc:269
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:128
unsigned int size() const
Returns size of the container. This is independent of the allocated space.
Definition: sys_vector.hh:412
Global macros to enhance readability and debugging, general constants.
unsigned int n_elements() const
Definition: mesh.h:137
#define ASSERT(...)
Definition: global_defs.h:120
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:30
#define ASSERT_EQUAL(a, b)
Definition: global_defs.h:135
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:404
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:71
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:201
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:264
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:196
unsigned int leaf_begin() const
Definition: bih_node.hh:78
ElementVector element
Vector of elements of the mesh.
Definition: mesh.h:198
std::vector< BIHNode > nodes_
vector of tree nodes
Definition: bih_tree.hh:129