Flow123d
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 : r_gen(123), mesh_(mesh), leaf_size_limit(soft_leaf_size_limit)
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 }