alaCarte Maps
Renderer for OpenStreetMap tiles
rtree.hpp
Go to the documentation of this file.
1 
21 #pragma once
22 #ifndef RTREE_HPP
23 #define RTREE_HPP
24 
25 
26 #include "settings.hpp"
27 
28 #include <boost/archive/basic_archive.hpp>
29 #include <boost/serialization/vector.hpp>
30 #include <boost/algorithm/string.hpp>
31 #include <boost/iostreams/device/mapped_file.hpp>
32 
33 #include <fstream>
34 #include <algorithm>
35 #include <stack>
36 
37 #include "utils/transform.hpp"
38 
39 #define NUM_CHILDREN 50
40 #define LEAF_SIZE (16 * 1024)
41 
42 template <class id_t, class data_t>
43 class RTree {
44 
45 private:
46  // explicit typing to use function overloading
47  template <class _id_t, class _data_t,
48  size_t leaf_elements = ((LEAF_SIZE - sizeof(uint16_t)) / (sizeof(uint32_t) + sizeof(data_t)))>
49  class RLeaf
50  {
51  public:
52  static size_t num_elements() { return leaf_elements; }
53 
54  _id_t ids[leaf_elements];
55  _data_t data[leaf_elements];
57  uint16_t size;
58 
59  RLeaf(): size(0) {}
60 
61  void addData(const _data_t& d, _id_t id)
62  {
63  data[size] = d;
64  ids[size] = id;
65  size++;
66  }
67 
68  bool isFull() { return (size == leaf_elements); }
69  };
70 
71  class RNode
72  {
73  public:
75  uint32_t children[NUM_CHILDREN];
77  uint8_t size;
78 
79  RNode(): size(0) {}
80 
81  // for leaf nodes the index is -1 (0xFFFFFFFF)
82  void addChild(const FixedRect& bound, uint32_t index = (uint32_t) -1)
83  {
84  bounds[size] = bound;
85  children[size] = index;
86  size++;
87  }
88 
89  bool isFull() const { return (size == NUM_CHILDREN); }
90  bool isLeaf() const { return (size > 0 && children[0] == (uint32_t) -1); }
91 
92  private:
93  friend class boost::serialization::access;
94  template<typename Archive>
95  void serialize(Archive &ar, const unsigned int version){
96  ar & bounds;
97  ar & children;
98  ar & size;
99  }
100  };
101 
102 public:
103  RTree() = default;
104  void build(std::vector<data_t>& data, const string& leafPath);
105  bool search ( boost::shared_ptr<std::vector<id_t> >& result,
106  const FixedRect& rect, bool returnOnFirst = false ) const;
107  bool contains(const FixedRect& rect) const
108  {
109  shared_ptr<std::vector<id_t> > geoIDs = boost::make_shared< std::vector<id_t> >();
110  return search(geoIDs, rect, true);
111  };
112 
114  void setLeafFile(const string& path, uint64_t offset, uint64_t length)
115  {
116  input.open(path, length, offset);
117  if (!input.is_open())
118  BOOST_THROW_EXCEPTION(excp::FileNotFoundException() << excp::InfoFileName(path));
119  this->offset = offset;
120  this->length = length;
121  }
122 
123 private:
124  std::vector<RNode> tree;
125  boost::iostreams::mapped_file_source input;
126  uint64_t offset;
127  uint64_t length;
128 
129  void buildLeaves (const std::vector<data_t>& rects, const string& leafPath);
130  void writeLeaves (const std::vector<id_t>& ids, const std::vector<data_t>& rects, const string& leafPath);
131  void buildLevels ();
132  RLeaf<id_t, data_t>* readLeaf (uint32_t nodeIdx, uint32_t childIdx) const;
133  void getSubTree ( uint32_t rootIdx, boost::shared_ptr<std::vector<id_t> >& ids ) const;
134  FixedRect getBoundingBox ( const FixedRect keys[], size_t size) const;
135  FixedRect getBoundingBox ( const FixedPoint keys[], size_t size) const;
136  coord_t getX (const FixedPoint& p);
137  coord_t getX (const FixedRect& r);
138  coord_t getY (const FixedPoint& p);
139  coord_t getY (const FixedRect& r);
140  bool searchLeaf (const RLeaf<id_t, FixedPoint>* leaf,
141  boost::shared_ptr<std::vector<id_t> >& result,
142  const FixedRect& rect,
143  bool returnOnFirst) const;
144  bool searchLeaf (const RLeaf<id_t, FixedRect>* leaf,
145  boost::shared_ptr<std::vector<id_t> >& result,
146  const FixedRect& rect,
147  bool returnOnFirst) const;
148 
149  /* debug functions */
150  bool validate () const;
151  void printTree () const;
152  void printLeaves (const string& leafPath) const;
153 
154  friend class boost::serialization::access;
155  template<typename Archive>
156  void load(Archive &ar, const unsigned int version){
157  ar >> tree;
158  }
159  template<typename Archive>
160  void save(Archive &ar, const unsigned int version) const
161  {
162  ar << tree;
163  }
164  BOOST_SERIALIZATION_SPLIT_MEMBER()
165 };
166 
168 template<class id_t, class data_t>
169 void RTree<id_t, data_t>::build(std::vector<data_t>& data, const string& leafPath)
170 {
171  LOG_SEV(geo_log, info) << "Objects: " << data.size();
172 
173  // create leaf file and first tree level
174  buildLeaves(data, leafPath);
175 
176  // build inner tree nodes
177  LOG_SEV(geo_log, info) << " - build levels";
178  buildLevels();
179 
180  LOG_SEV(geo_log, info) << " - reverse";
181  std::reverse(tree.begin(), tree.end());
182  for (RNode& node : tree)
183  {
184  for (int i = 0; i < NUM_CHILDREN; i++)
185  {
186  if (node.isLeaf())
187  continue;
188  node.children[i] = tree.size() - 1 - node.children[i];
189  }
190  }
191 }
192 
194 template<class id_t, class data_t>
196 {
197  FixedPoint p = r.getCenter();
198  return p.x;
199 }
200 
202 template<class id_t, class data_t>
204 {
205  return p.x;
206 }
207 
209 template<class id_t, class data_t>
211 {
212  FixedPoint p = r.getCenter();
213  return p.y;
214 }
215 
217 template<class id_t, class data_t>
219 {
220  return p.y;
221 }
222 
223 template<class id_t, class data_t>
224 void RTree<id_t, data_t>::buildLeaves (const std::vector<data_t>& data, const string& leafPath)
225 {
226  LOG_SEV(geo_log, info) << " - computing ids";
227  std::vector<id_t> ids;
228  for (int i = 0; i < data.size(); i++)
229  ids.push_back(id_t(i));
230 
231  LOG_SEV(geo_log, info) << " - sorting leaves";
232  std::sort(ids.begin(), ids.end(),
233  [&](id_t a, id_t b)
234  {
235  return (this->getX(data[a.getRaw()]) < this->getX(data[b.getRaw()]));
236  }
237  );
238 
239  // number of elements per leaf
241  // number of leaves
242  size_t p = ceil(data.size() / (double) n);
243  // number of slices
244  size_t s = ceil(sqrt(p));
245  // size of each slice
246  size_t t = s * n;
247 
248  for (size_t start = 0; start < data.size(); start += t)
249  {
250  size_t end = start + t;
251  if ( end > data.size() )
252  end = data.size();
253 
254  // sort content of leaf by y coordinate
255  std::sort(ids.begin()+start, ids.begin()+end,
256  [&](id_t a, id_t b)
257  {
258  return (this->getY(data[a.getRaw()]) < this->getY(data[b.getRaw()]));
259  }
260  );
261  }
262 
263  writeLeaves(ids, data, leafPath);
264 }
265 
267 template<class id_t, class data_t>
268 void RTree<id_t, data_t>::writeLeaves (const std::vector<id_t>& ids,
269  const std::vector<data_t>& data,
270  const string& leafPath)
271 {
272  LOG_SEV(geo_log, info) << " - writing leaves";
273 
274  std::ofstream output(leafPath, std::ios::out | std::ios::binary);
275 
276  // fill data in leaves and write to disk
277  RNode node;
278  RLeaf<id_t, data_t> leaf;
279  for (id_t id : ids)
280  {
281  leaf.addData(data[id.getRaw()], id);
282  if (leaf.isFull())
283  {
284  FixedRect bound = getBoundingBox(leaf.data, leaf.size);
285  node.addChild(bound);
286  if (node.isFull())
287  {
288  tree.push_back(node);
289  node.size = 0;
290  }
291 
292  output.write((char*) &leaf, sizeof(leaf));
293  leaf.size = 0;
294  }
295  }
296 
297  // last leaf was not full
298  if (leaf.size > 0)
299  {
300  FixedRect bound = getBoundingBox(leaf.data, leaf.size);
301  node.addChild(bound);
302  if (node.isFull())
303  {
304  tree.push_back(node);
305  node.size = 0;
306  }
307 
308  output.write((char*) &leaf, sizeof(leaf));
309  }
310 
311  // inner node was not completed
312  if (node.size > 0)
313  tree.push_back(node);
314 }
315 
317 template<class id_t, class data_t>
319 {
320  size_t start = 0;
321  size_t end = tree.size() - 1;
322  RNode node;
323 
324  uint32_t levels = 1;
325 
326  // add nodes until the root is reached
327  while (start < end)
328  {
329  levels++;
330  // add bounding boxes of NUM_CHILDREN child nodes to new node
331  for (size_t i = start; i <= end; i++)
332  {
333  FixedRect bound = getBoundingBox(tree[i].bounds, tree[i].size);
334  node.addChild(bound, i);
335  if (node.isFull())
336  {
337  tree.push_back(node);
338  node.size = 0;
339  }
340  }
341 
342  // node was not completly filled
343  if (node.size > 0) {
344  tree.push_back(node);
345  node.size = 0;
346  }
347 
348  start = end + 1;
349  end = tree.size() - 1;
350  }
351 
352  LOG_SEV(geo_log, info) << " -> " << levels << " levels.";
353 }
354 
356 template<class id_t, class data_t>
357 #ifdef _MSC_VER
358 typename
359 #endif
360 RTree<id_t, data_t>::RLeaf<id_t, data_t>*
361 RTree<id_t, data_t>::readLeaf (uint32_t nodeIdx, uint32_t childIdx) const
362 {
363  // reverse index, so that it correspons with the id of the saved leaves
364  uint32_t leafID = (tree.size() - 1 - nodeIdx) * NUM_CHILDREN + childIdx;
365  return (((RLeaf<id_t, data_t>*) input.data()) + leafID);
366 }
367 
369 template<class id_t, class data_t>
371 {
372  for (int i = 0; i < tree.size(); i++)
373  {
374  const RNode& node = tree[i];
375 
376  if (node.isLeaf())
377  {
378  RLeaf<id_t, data_t>* leaf;
379  for (int c = 0; c < node.size; c++)
380  {
381  leaf = readLeaf(i, c);
382  FixedRect bounds = getBoundingBox(leaf->data, leaf->size);
383  if (bounds != node.bounds[c])
384  return false;
385  }
386  continue;
387  }
388 
389  for (int c = 0; c < node.size; c++)
390  {
391  uint32_t childIdx = node.children[c];
392  FixedRect bounds = getBoundingBox(tree[childIdx].bounds, tree[childIdx].size);
393  if (bounds != node.bounds[c])
394  return false;
395  }
396  }
397 
398  return true;
399 }
400 
402 template<class id_t, class data_t>
404  boost::shared_ptr<std::vector<id_t> >& result,
405  const FixedRect& rect,
406  bool returnOnFirst) const
407 {
408  for (int j = 0; j < leaf->size; j++)
409  {
410  if (rect.intersects(leaf->data[j]))
411  {
412  if (returnOnFirst)
413  return true;
414  result->push_back(leaf->ids[j]);
415  }
416  }
417 
418  return false;
419 }
420 
422 template<class id_t, class data_t>
424  boost::shared_ptr<std::vector<id_t> >& result,
425  const FixedRect& rect,
426  bool returnOnFirst) const
427 {
428  for (int j = 0; j < leaf->size; j++)
429  {
430  if (rect.contains(leaf->data[j]))
431  {
432  if (returnOnFirst)
433  return true;
434  result->push_back(leaf->ids[j]);
435  }
436  }
437 
438  return false;
439 }
440 
442 template<class id_t, class data_t>
443 bool RTree<id_t, data_t>::search (boost::shared_ptr<std::vector<id_t> >& result,
444  const FixedRect& rect,
445  bool returnOnFirst) const
446 {
447  if (tree.size() == 0)
448  return false;
449 
450  // start at root
451  std::stack<uint32_t> stack;
452  stack.push(0);
453 
454  RLeaf<id_t, data_t>* leaf;
455  do {
456  uint32_t idx = stack.top();
457  const RNode& node = tree[idx];
458  stack.pop();
459 
460  // reached leaf check contained rects
461  if ( node.isLeaf() )
462  {
463  // for every child node check bounds
464  for (int i = 0; i < node.size; i++)
465  {
466  // if bound is contained add all ids
467  if (rect.contains(node.bounds[i]))
468  {
469  if (returnOnFirst)
470  return true;
471 
472  leaf = readLeaf(idx, i);
473  result->insert(result->end(), &leaf->ids[0], &leaf->ids[leaf->size]);
474  }
475  // if bound intersects search in leaf
476  else if (rect.intersects(node.bounds[i]))
477  {
478  leaf = readLeaf(idx, i);
479  bool containedData = searchLeaf(leaf, result, rect, returnOnFirst);
480 
481  if (returnOnFirst && containedData)
482  return true;
483  }
484  }
485 
486  continue;
487  }
488 
489  // no leaf, check child nodes
490  for (int i = 0; i < node.size; i++)
491  {
492  const FixedRect& bound = node.bounds[i];
493  // if bound is contained add sub tree
494  if ( rect.contains ( bound ) )
495  {
496  if (returnOnFirst)
497  return true;
498 
499  getSubTree ( node.children[i], result);
500  }
501  // add intersecting nodes to stack to search next
502  else if ( rect.intersects( bound ) )
503  stack.push( node.children[i] );
504  }
505 
506  } while (!stack.empty());
507 
508  return (result->size() > 0);
509 }
510 
512 template<class id_t, class data_t>
513 void RTree<id_t, data_t>::getSubTree ( uint32_t rootIdx, boost::shared_ptr<std::vector<id_t> >& ids ) const
514 {
515  std::stack<uint32_t> subTreeStack;
516  subTreeStack.push(rootIdx);
517 
518  RLeaf<id_t, data_t>* leaf;
519  do {
520  uint32_t idx = subTreeStack.top();
521  const RNode& node = tree[idx];
522  subTreeStack.pop();
523 
524  if ( node.isLeaf() )
525  {
526  for (int i = 0; i < node.size; i++)
527  {
528  leaf = readLeaf(idx, i);
529  ids->insert(ids->end(), &leaf->ids[0], &leaf->ids[leaf->size]);
530  }
531  }
532  else
533  {
534  for (int i = 0; i < node.size; i++)
535  subTreeStack.push(node.children[i]);
536  }
537  } while (!subTreeStack.empty());
538 }
539 
541 template<class id_t, class data_t>
543 {
544  FixedRect bound = keys[0];
545 
546  for (int i = 1; i < size; i++)
547  bound.enclose(keys[i]);
548 
549  return bound;
550 }
551 
553 template<class id_t, class data_t>
555 {
556  FixedRect bound(keys[0].x, keys[0].y, keys[0].x, keys[0].y);
557 
558  for (int i = 1; i < size; i++)
559  bound.enclose(keys[i]);
560 
561  return bound;
562 }
563 
565 template<class id_t, class data_t>
566 void RTree<id_t, data_t>::printLeaves (const string& leafPath) const
567 {
568  std::ofstream log(leafPath + ".log", std::ios::out);
569 
570  for (int i = tree.size() - 1; i >= 0 && tree[i].isLeaf(); i--)
571  {
572  log << "L(";
573  for (int c = 0; c < tree[i].size; c++)
574  {
575  FixedRect& r = tree[i].bounds[c];
576  log << "R(" << r.minX << ", " << r.minY << ", " << r.maxX << ", " << r.maxY << "), ";
577  }
578  log << ") ";
579  }
580 }
581 
583 template<class id_t, class data_t>
585 {
586  size_t start = 0;
587  // walk levels
588  while (start < tree.size())
589  {
590  if (tree[start].isLeaf()) {
591  RLeaf<id_t, data_t> leaf;
592  printf("L(");
593  for (int c = 0; c < tree[start].size; c++)
594  {
595  uint32_t leafID = (tree.size() - 1 - start) * NUM_CHILDREN + c;
596  printf(" %i", leafID);
597  }
598  printf(" ) ");
599  start++;
600  } else {
601  // index of last child is first of next level
602  size_t end = tree[start].children[tree[start].size - 1];
603  for (int i = start; i < end; i++)
604  {
605  RNode& node = tree[i];
606  printf("(");
607  for (int c = 0; c < node.size; c++)
608  printf(" %i", node.children[c]);
609  printf(" ) ");
610  }
611  printf("\n");
612  start = end;
613  }
614  }
615  printf("\n");
616 }
617 
618 #endif
619 
void build(std::vector< data_t > &data, const string &leafPath)
starts to build the tree for the given data
Definition: rtree.hpp:169
bool searchLeaf(const RLeaf< id_t, FixedPoint > *leaf, boost::shared_ptr< std::vector< id_t > > &result, const FixedRect &rect, bool returnOnFirst) const
Specialisation for point based data.
Definition: rtree.hpp:423
uint64_t length
Definition: rtree.hpp:127
bool isFull()
Definition: rtree.hpp:68
#define NUM_CHILDREN
Definition: rtree.hpp:39
_data_t data[leaf_elements]
Definition: rtree.hpp:55
#define LEAF_SIZE
Definition: rtree.hpp:40
void save(Archive &ar, const unsigned int version) const
Definition: rtree.hpp:160
void getSubTree(uint32_t rootIdx, boost::shared_ptr< std::vector< id_t > > &ids) const
used when a sub-tree is fully contained in the search rectangle
Definition: rtree.hpp:513
bool isFull() const
Definition: rtree.hpp:89
uint8_t size
number of contained elements
Definition: rtree.hpp:77
bool intersects(const basic_rect< T > &bounding) const
Definition: rect.hpp:143
uint64_t offset
Definition: rtree.hpp:126
void printTree() const
For debugging.
Definition: rtree.hpp:584
FixedRect getBoundingBox(const FixedRect keys[], size_t size) const
size muste be greater than 0
Definition: rtree.hpp:542
std::int32_t coord_t
Definition: settings.hpp:117
RTree()=default
void buildLeaves(const std::vector< data_t > &rects, const string &leafPath)
Definition: rtree.hpp:224
bool contains(const basic_vector2< T > &p) const
Definition: rect.hpp:130
bool contains(const FixedRect &rect) const
Definition: rtree.hpp:107
void load(Archive &ar, const unsigned int version)
Definition: rtree.hpp:156
T minY
Definition: rect.hpp:52
static size_t num_elements()
Definition: rtree.hpp:52
std::vector< RNode > tree
Definition: rtree.hpp:124
void buildLevels()
builds all levels above leafs
Definition: rtree.hpp:318
boost::iostreams::mapped_file_source input
Definition: rtree.hpp:125
#define LOG_SEV(log, lvl)
Definition: settings.hpp:78
bool search(boost::shared_ptr< std::vector< id_t > > &result, const FixedRect &rect, bool returnOnFirst=false) const
if returnOnFirst is set it return true if it found data in the querry rectangle
Definition: rtree.hpp:443
Thrown if a file was not found.
Definition: exceptions.hpp:73
uint16_t size
number of contained elements
Definition: rtree.hpp:57
void enclose(const basic_rect< T > &other)
Definition: rect.hpp:96
void writeLeaves(const std::vector< id_t > &ids, const std::vector< data_t > &rects, const string &leafPath)
Fills first tree layer for leaf RNode objects an saves RLeaf objects to file.
Definition: rtree.hpp:268
FixedRect bounds[NUM_CHILDREN]
Definition: rtree.hpp:74
uint32_t children[NUM_CHILDREN]
Definition: rtree.hpp:75
coord_t getX(const FixedPoint &p)
get x coordinate of point based types
Definition: rtree.hpp:203
void addData(const _data_t &d, _id_t id)
Definition: rtree.hpp:61
coord_t getY(const FixedPoint &p)
get x coordinate of point based types
Definition: rtree.hpp:218
T maxX
Definition: rect.hpp:53
_id_t ids[leaf_elements]
Definition: rtree.hpp:54
void serialize(Archive &ar, const unsigned int version)
Definition: rtree.hpp:95
bool validate() const
debugging function to check validity of bounding boxes
Definition: rtree.hpp:370
bool isLeaf() const
Definition: rtree.hpp:90
boost::error_info< struct TagFileName, string > InfoFileName
Use this to inform about a file name.
Definition: exceptions.hpp:43
void setLeafFile(const string &path, uint64_t offset, uint64_t length)
is called after deserialisation to set offets in the archive
Definition: rtree.hpp:114
void printLeaves(const string &leafPath) const
For debugging.
Definition: rtree.hpp:566
RLeaf< id_t, data_t > * readLeaf(uint32_t nodeIdx, uint32_t childIdx) const
reads a leaf from file
Definition: rtree.hpp:361
void addChild(const FixedRect &bound, uint32_t index=(uint32_t)-1)
Definition: rtree.hpp:82
T maxY
Definition: rect.hpp:54
T minX
Definition: rect.hpp:51
basic_vector2< T > getCenter() const
Definition: rect.hpp:116