UGDK  0.5.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
intervalkdtree.h
Go to the documentation of this file.
1 #ifndef UGDK_UTIL_INTERVALKDTREE_H_
2 #define UGDK_UTIL_INTERVALKDTREE_H_
3 
4 #include <cassert>
5 #include <cstddef>
6 #include <map>
7 #include <list>
8 #include <climits>
9 #ifdef DEBUG
10 #include <iostream>
11 #endif
12 
13 #include <ugdk/structure.h>
14 #include <ugdk/structure/box.h>
15 
16 namespace ugdk {
17 namespace structure {
18 namespace ikdtree {
19 
20 template <class T, int DIMENSIONS>
22  public:
23  IntervalKDTree(const Box<DIMENSIONS>& tree_bounding_box,
24  unsigned int max_elements_per_leaf);
25  ~IntervalKDTree ();
26 
27  void Clear();
28  void Insert(const Box<DIMENSIONS>& bounding_box, const T& element);
29  void Remove(const T& element);
30  void Update(const Box<DIMENSIONS>& new_bounding_box, const T& element);
31 
32  template<class OutputIterator>
33  void FindIntersectingItems(const Box<DIMENSIONS>& boundary, OutputIterator output) const;
34 
35  typename std::map<T, Item<T, DIMENSIONS>* >::const_iterator begin() const;
36  typename std::map<T, Item<T, DIMENSIONS>* >::const_iterator end() const;
37 
38  unsigned int max_elements_per_leaf() const;
39 
40 #ifdef DEBUG
41  unsigned int max_height_;
42  void PrintTree() const;
43 #endif
44 
45  private:
46  void UpdateItem (Item<T, DIMENSIONS> * item);
47 
48  unsigned int max_elements_per_leaf_;
49  Box<DIMENSIONS> tree_bounding_box_;
50  std::map<T, Item<T, DIMENSIONS>* > container_items_;
51  Node<T, DIMENSIONS> * root_;
52 };
53 
54 //************* Implementation **************
55 
56 //**** Classes needed for implementation ****
57 
58 template <class T, int DIMENSIONS>
59 class Item : public Box<DIMENSIONS> {
60  public :
61  Item(const Box<DIMENSIONS>& bounding_box, const T& element);
62  ~Item();
63 
64  const T& element() const;
65 
68 
69 #ifdef DEBUG
70  void Print() const;
71 #endif
72 
73  private:
74  typedef Box<DIMENSIONS> super;
75  T element_;
76  Node<T, DIMENSIONS>* container_node_;
77 };
78 
79 template <class T, int DIMENSIONS>
80 class Node : public Box<DIMENSIONS> {
81  public:
82  Node(IntervalKDTree<T, DIMENSIONS> * tree, Node *parent, int depth,
83  const std::array<Coordinate, DIMENSIONS>& min_coordinates,
84  const std::array<Coordinate, DIMENSIONS>& max_coordinates);
85  Node(IntervalKDTree<T, DIMENSIONS> * tree, Node *parent, int depth,
86  const Box<DIMENSIONS>& coordinates);
87  ~Node ();
88 
89  void InsertItem(Item<T, DIMENSIONS> *item);
90  void RemoveItem(Item<T, DIMENSIONS> *item);
91 
92  template<typename Iterator>
93  void FindIntersectingItems(const Box<DIMENSIONS>& boundary, Iterator it) const;
94 
95  void Clear();
96 
97  int depth_;
100 
101 #ifdef DEBUG
102  void PrintTreeRootedAtThisNode();
103 #endif
104 
105  private:
106  void Divide();
107  void Merge();
108 
109  typedef Box<DIMENSIONS> super;
111  Node * parent_;
112  Node * low_child_, * high_child_;
113 
114  // TODO: Test if some kind of tree is faster than a list
115  // Maybe an interval tree along one of the other axis (not
116  // on the axis that this node divides)
117  // Maybe even another KD-Interval-Tree. (but taking care to not
118  // have infinite recursive trees)
119  std::list<Item<T, DIMENSIONS> *> items_;
120 };
121 
122 // IntervalKDTree implementation
123 
124 template <class T, int DIMENSIONS>
126  const Box<DIMENSIONS>& _tree_bounding_box,
127  unsigned int _max_elements_per_leaf) :
128  max_elements_per_leaf_(_max_elements_per_leaf),
129  tree_bounding_box_(_tree_bounding_box),
130  container_items_() {
131  root_ = new Node<T, DIMENSIONS>(this, nullptr, 0, _tree_bounding_box);
132 #ifdef DEBUG
133  max_height_ = 0;
134 #endif
135 }
136 
137 template <class T, int DIMENSIONS>
139  root_->Clear ();
140  delete root_;
141 }
142 
143 template <class T, int DIMENSIONS>
145  container_items_.clear ();
146  root_->Clear ();
147  delete root_;
148  root_ = new Node<T,DIMENSIONS> (this, nullptr, 0, tree_bounding_box_);
149 }
150 
151 template <class T, int DIMENSIONS>
152 void IntervalKDTree<T, DIMENSIONS>::Insert (const Box<DIMENSIONS>& bounding_box, const T& element) {
153  // Shouldn't insert an element twice!
154  assert (!container_items_.count (element));
155  Item<T, DIMENSIONS> * item = new Item<T, DIMENSIONS> (bounding_box, element);
156  root_->InsertItem (item);
157  container_items_[element] = item;
158 }
159 
160 template <class T, int DIMENSIONS>
161 void IntervalKDTree<T, DIMENSIONS>::Remove (const T& element) {
162  assert (container_items_.count (element));
163  if (container_items_.count (element)) {
164  Item<T, DIMENSIONS> *item = container_items_[element];
165  Node<T, DIMENSIONS> *node = item->container_node();
166  node->RemoveItem (item);
167  container_items_.erase (element);
168  delete item;
169  }
170 }
171 
172 template <class T, int DIMENSIONS>
174  const T& element) {
175  // Shouldn't update an unexisting element!
176  assert (container_items_.count(element));
177  Item<T, DIMENSIONS> * item = container_items_[element];
178  item->UpdateBox (new_bounding_box);
179  UpdateItem (item);
180 }
181 
182 template <class T, int DIMENSIONS>
184  Node<T, DIMENSIONS> *container_node = item->container_node ();
185 
186  if ((container_node->has_children_ &&
187  (item->IsBelow (container_node->depth_,
188  container_node->division_boundary_)
189  || item->IsAbove (container_node->depth_,
190  container_node->division_boundary_))
191  ) || !container_node->Contains (*item)) {
192  // We need to place it in a different node
193  // Remove and add item
194  container_node->RemoveItem (item);
195  root_->InsertItem (item);
196  }
197 }
198 
199 template <class T, int DIMENSIONS>
200 template <class OutputIterator>
201 void IntervalKDTree<T, DIMENSIONS>::FindIntersectingItems(const Box<DIMENSIONS>& boundary, OutputIterator output) const {
202  root_->FindIntersectingItems(boundary, output);
203 }
204 
205 template <class T, int DIMENSIONS>
206 typename std::map<T, Item<T, DIMENSIONS>* >::const_iterator IntervalKDTree<T, DIMENSIONS>::begin() const {
207  return container_items_.begin();
208 }
209 
210 template <class T, int DIMENSIONS>
211 typename std::map<T, Item<T, DIMENSIONS>* >::const_iterator IntervalKDTree<T, DIMENSIONS>::end() const {
212  return container_items_.end();
213 }
214 
215 template <class T, int DIMENSIONS>
217  return max_elements_per_leaf_;
218 }
219 
220 #ifdef DEBUG
221 template <class T, int DIMENSIONS>
223  root_->PrintTreeRootedAtThisNode ();
224 }
225 #endif
226 
227 // Item Implementation
228 
229 template <class T, int DIMENSIONS>
230 Item<T, DIMENSIONS>::Item(const Box<DIMENSIONS>& bounding_box, const T& _element) :
231  super(bounding_box), element_(_element) {}
232 
233 template <class T, int DIMENSIONS>
235 
236 template <class T, int DIMENSIONS>
238  return container_node_;
239 }
240 
241 template <class T, int DIMENSIONS>
243  container_node_ = _container_node;
244 }
245 
246 template <class T, int DIMENSIONS>
248  return element_;
249 }
250 
251 #ifdef DEBUG
252 template <class T, int DIMENSIONS>
253 void Item<T, DIMENSIONS>::Print() const {
254  std::cout << element_;
255 }
256 #endif
257 
258 // Node Implementation
259 
260 template <class T, int DIMENSIONS>
262  const std::array<Coordinate, DIMENSIONS>& min_coordinates,
263  const std::array<Coordinate, DIMENSIONS>& max_coordinates)
264 
265  : super (min_coordinates, max_coordinates), depth_(depth), has_children_(false),
266  tree_(tree), parent_(parent), low_child_(nullptr), high_child_(nullptr) {}
267 
268 template <class T, int DIMENSIONS>
270  Node *parent, int depth, const Box<DIMENSIONS>& coordinates)
271 
272  : super (coordinates), depth_(depth), has_children_(false),
273  tree_(tree), parent_(parent), low_child_(nullptr), high_child_(nullptr) {}
274 
275 template <class T, int DIMENSIONS>
277  delete low_child_;
278  delete high_child_;
279 }
280 
281 template <class T, int DIMENSIONS>
283 #ifdef DEBUG
284  if (static_cast<unsigned int>(depth_) > tree_->max_height_) {
285  tree_->max_height_ = depth_;
286  }
287 #endif
288  if (has_children_) {
289  if (item->IsBelow (depth_, division_boundary_)) {
290  assert (low_child_);
291  low_child_->InsertItem (item);
292  return;
293  } else if (item->IsAbove (depth_, division_boundary_)) {
294  assert (high_child_);
295  high_child_->InsertItem (item);
296  return;
297  }
298  }
299  items_.push_back (item);
300  item->set_container_node (this);
301  if (!has_children_ && items_.size() > tree_->max_elements_per_leaf()) {
302  Divide ();
303  }
304 }
305 
306 template <class T, int DIMENSIONS>
308  items_.remove (item);
309  if (parent_)
310  parent_->Merge ();
311 }
312 
313 template <class T, int DIMENSIONS>
314 template <class Iterator>
315 void Node<T, DIMENSIONS>::FindIntersectingItems(const Box<DIMENSIONS>& boundary, Iterator output) const {
316  for (Item<T, DIMENSIONS>* it : items_)
317  if (boundary.Intersects(it))
318  *output++ = it->element();
319  if (has_children_) {
320  if (boundary.IsBelow(depth_, division_boundary_)) {
321  low_child_->FindIntersectingItems(boundary, output);
322  } else if (boundary.IsAbove(depth_, division_boundary_)) {
323  high_child_->FindIntersectingItems(boundary, output);
324  } else {
325  low_child_->FindIntersectingItems(boundary, output);
326  high_child_->FindIntersectingItems(boundary, output);
327  }
328  }
329 }
330 
331 template <class T, int DIMENSIONS>
333  assert (!has_children_);
334  has_children_ = true;
335 
336  int dimension = depth_ % DIMENSIONS;
337  // TODO: Test other strategies for dividing space
338  division_boundary_ = ( this->min_coordinates_[dimension]
339  + this->max_coordinates_[dimension]) / 2;
340 
341  std::array<Coordinate, DIMENSIONS> new_min_coordinates,
342  new_max_coordinates;
343  for (int k = 0; k < DIMENSIONS; ++k) {
344  if (k == dimension) {
345  new_min_coordinates[k] = new_max_coordinates[k]
346  = division_boundary_;
347  } else {
348  new_min_coordinates[k] = this->min_coordinates_[k];
349  new_max_coordinates[k] = this->max_coordinates_[k];
350  }
351  }
352  low_child_ = new Node(tree_, this, depth_ + 1, this->min_coordinates_, new_max_coordinates);
353  high_child_ = new Node(tree_, this, depth_ + 1, new_min_coordinates, this->max_coordinates_);
354 
355  std::list<Item<T, DIMENSIONS> *> old_items_list = items_;
356  items_.clear();
357  for (Item<T, DIMENSIONS>* it : old_items_list)
358  InsertItem(it);
359 }
360 
361 template <class T, int DIMENSIONS>
362 void Node<T, DIMENSIONS>::Merge () {
363  assert (has_children_);
364  if ( !low_child_->has_children_
365  && !high_child_->has_children_
366  && (items_.size ()
367  + low_child_->items_.size ()
368  + high_child_->items_.size ()
369  < tree_->max_elements_per_leaf () )) {
370  for (Item<T, DIMENSIONS>* it : low_child_->items_) {
371  items_.push_back(it);
372  it->set_container_node(this);
373  }
374  for (Item<T, DIMENSIONS>* it : high_child_->items_) {
375  items_.push_back(it);
376  it->set_container_node(this);
377  }
378  delete low_child_;
379  low_child_ = nullptr;
380  delete high_child_;
381  high_child_ = nullptr;
382  has_children_ = false;
383  if (parent_)
384  parent_->Merge();
385  }
386 }
387 
388 template <class T, int DIMENSIONS>
390  if (has_children_) {
391  low_child_->Clear ();
392  high_child_->Clear ();
393  delete low_child_;
394  low_child_ = nullptr;
395  delete high_child_;
396  high_child_ = nullptr;
397  }
398  for (Item<T, DIMENSIONS>* it : items_)
399  delete it;
400  items_.clear();
401 }
402 
403 #ifdef DEBUG
404 template <class T, int DIMENSIONS>
406  if (has_children_) {
407  high_child_->PrintTreeRootedAtThisNode ();
408  }
409  for (int i = 0; i < depth_; ++i) {
410  std::cout << "\t";
411  }
412  int i = 0;
413  for (auto it = items_.begin(); it != items_.end(); ++it, ++i) {
414  std::cout << "[" << i << "] = ";
415  (*it)->Print ();
416  std::cout << "; ";
417  }
418  std::cout << std::endl;
419  if (has_children_) {
420  low_child_->PrintTreeRootedAtThisNode ();
421  }
422 }
423 #endif
424 
425 } // namespace ikdtree
426 } // namespace structure
427 } // namespace ugdk
428 
429 #endif
const Point & min_coordinates() const
Definition: box.h:85
const T & element() const
Definition: intervalkdtree.h:247
~Node()
Definition: intervalkdtree.h:276
void set_container_node(Node< T, DIMENSIONS > *container_node)
Definition: intervalkdtree.h:242
bool IsAbove(int depth, Coordinate boundary) const
Definition: box.h:56
void RemoveItem(Item< T, DIMENSIONS > *item)
Definition: intervalkdtree.h:307
unsigned int max_elements_per_leaf() const
Definition: intervalkdtree.h:216
Definition: intervalkdtree.h:80
void Remove(const T &element)
Definition: intervalkdtree.h:161
bool Intersects(const Box *box) const
Definition: box.h:74
Definition: animation.h:11
Definition: intervalkdtree.h:21
void FindIntersectingItems(const Box< DIMENSIONS > &boundary, Iterator it) const
Definition: intervalkdtree.h:315
Node< T, DIMENSIONS > * container_node() const
Definition: intervalkdtree.h:237
void UpdateBox(const Box &)
Definition: box.h:46
const Point & max_coordinates() const
Definition: box.h:90
void FindIntersectingItems(const Box< DIMENSIONS > &boundary, OutputIterator output) const
Definition: intervalkdtree.h:201
~Item()
Definition: intervalkdtree.h:234
std::map< T, Item< T, DIMENSIONS > * >::const_iterator begin() const
Definition: intervalkdtree.h:206
~IntervalKDTree()
Definition: intervalkdtree.h:138
void Update(const Box< DIMENSIONS > &new_bounding_box, const T &element)
Definition: intervalkdtree.h:173
bool IsBelow(int depth, Coordinate boundary) const
Definition: box.h:51
Definition: intervalkdtree.h:59
int depth_
Definition: intervalkdtree.h:97
Definition: box.h:11
void Insert(const Box< DIMENSIONS > &bounding_box, const T &element)
Definition: intervalkdtree.h:152
std::map< T, Item< T, DIMENSIONS > * >::const_iterator end() const
Definition: intervalkdtree.h:211
IntervalKDTree(const Box< DIMENSIONS > &tree_bounding_box, unsigned int max_elements_per_leaf)
Definition: intervalkdtree.h:125
Item(const Box< DIMENSIONS > &bounding_box, const T &element)
Definition: intervalkdtree.h:230
Coordinate division_boundary_
Definition: intervalkdtree.h:98
void Clear()
Definition: intervalkdtree.h:144
void InsertItem(Item< T, DIMENSIONS > *item)
Definition: intervalkdtree.h:282
void Clear()
Definition: intervalkdtree.h:389
bool Contains(const Box &box) const
Definition: box.h:61
double Coordinate
Definition: structure.h:7
Node(IntervalKDTree< T, DIMENSIONS > *tree, Node *parent, int depth, const std::array< Coordinate, DIMENSIONS > &min_coordinates, const std::array< Coordinate, DIMENSIONS > &max_coordinates)
Definition: intervalkdtree.h:261
bool has_children_
Definition: intervalkdtree.h:99