libspatialindex API Reference  (git-trunk)
RTree.cc
Go to the documentation of this file.
1 /******************************************************************************
2  * Project: libspatialindex - A C++ library for spatial indexing
3  * Author: Marios Hadjieleftheriou, mhadji@gmail.com
4  ******************************************************************************
5  * Copyright (c) 2002, Marios Hadjieleftheriou
6  *
7  * All rights reserved.
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining a
10  * copy of this software and associated documentation files (the "Software"),
11  * to deal in the Software without restriction, including without limitation
12  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13  * and/or sell copies of the Software, and to permit persons to whom the
14  * Software is furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be included
17  * in all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25  * DEALINGS IN THE SOFTWARE.
26 ******************************************************************************/
27 
28 #include <cstring>
29 #include <cmath>
30 #include <limits>
31 
34 #include "Node.h"
35 #include "Leaf.h"
36 #include "Index.h"
37 #include "BulkLoader.h"
38 #include "RTree.h"
39 
40 using namespace SpatialIndex::RTree;
41 using namespace SpatialIndex;
42 
43 SpatialIndex::RTree::Data::Data(uint32_t len, uint8_t* pData, Region& r, id_type id)
44  : m_id(id), m_region(r), m_pData(nullptr), m_dataLength(len)
45 {
46  if (m_dataLength > 0)
47  {
48  m_pData = new uint8_t[m_dataLength];
49  memcpy(m_pData, pData, m_dataLength);
50  }
51 }
52 
54 {
55  delete[] m_pData;
56 }
57 
59 {
60  return new Data(m_dataLength, m_pData, m_region, m_id);
61 }
62 
64 {
65  return m_id;
66 }
67 
69 {
70  *out = new Region(m_region);
71 }
72 
73 void SpatialIndex::RTree::Data::getData(uint32_t& len, uint8_t** data) const
74 {
75  len = m_dataLength;
76  *data = nullptr;
77 
78  if (m_dataLength > 0)
79  {
80  *data = new uint8_t[m_dataLength];
81  memcpy(*data, m_pData, m_dataLength);
82  }
83 }
84 
86 {
87  return
88  sizeof(id_type) +
89  sizeof(uint32_t) +
90  m_dataLength +
91  m_region.getByteArraySize();
92 }
93 
95 {
96  memcpy(&m_id, ptr, sizeof(id_type));
97  ptr += sizeof(id_type);
98 
99  delete[] m_pData;
100  m_pData = nullptr;
101 
102  memcpy(&m_dataLength, ptr, sizeof(uint32_t));
103  ptr += sizeof(uint32_t);
104 
105  if (m_dataLength > 0)
106  {
107  m_pData = new uint8_t[m_dataLength];
108  memcpy(m_pData, ptr, m_dataLength);
109  ptr += m_dataLength;
110  }
111 
112  m_region.loadFromByteArray(ptr);
113 }
114 
115 void SpatialIndex::RTree::Data::storeToByteArray(uint8_t** data, uint32_t& len)
116 {
117  // it is thread safe this way.
118  uint32_t regionsize;
119  uint8_t* regiondata = nullptr;
120  m_region.storeToByteArray(&regiondata, regionsize);
121 
122  len = sizeof(id_type) + sizeof(uint32_t) + m_dataLength + regionsize;
123 
124  *data = new uint8_t[len];
125  uint8_t* ptr = *data;
126 
127  memcpy(ptr, &m_id, sizeof(id_type));
128  ptr += sizeof(id_type);
129  memcpy(ptr, &m_dataLength, sizeof(uint32_t));
130  ptr += sizeof(uint32_t);
131 
132  if (m_dataLength > 0)
133  {
134  memcpy(ptr, m_pData, m_dataLength);
135  ptr += m_dataLength;
136  }
137 
138  memcpy(ptr, regiondata, regionsize);
139  delete[] regiondata;
140  // ptr += regionsize;
141 }
142 
144 {
146  return si;
147 }
148 
151  double fillFactor,
152  uint32_t indexCapacity,
153  uint32_t leafCapacity,
154  uint32_t dimension,
155  RTreeVariant rv,
156  id_type& indexIdentifier)
157 {
158  Tools::Variant var;
160 
162  var.m_val.dblVal = fillFactor;
163  ps.setProperty("FillFactor", var);
164 
166  var.m_val.ulVal = indexCapacity;
167  ps.setProperty("IndexCapacity", var);
168 
170  var.m_val.ulVal = leafCapacity;
171  ps.setProperty("LeafCapacity", var);
172 
174  var.m_val.ulVal = dimension;
175  ps.setProperty("Dimension", var);
176 
178  var.m_val.lVal = rv;
179  ps.setProperty("TreeVariant", var);
180 
181  ISpatialIndex* ret = returnRTree(sm, ps);
182 
184  var = ps.getProperty("IndexIdentifier");
185  indexIdentifier = var.m_val.llVal;
186 
187  return ret;
188 }
189 
191  BulkLoadMethod m,
192  IDataStream& stream,
194  double fillFactor,
195  uint32_t indexCapacity,
196  uint32_t leafCapacity,
197  uint32_t dimension,
199  id_type& indexIdentifier)
200 {
201  SpatialIndex::ISpatialIndex* tree = createNewRTree(sm, fillFactor, indexCapacity, leafCapacity, dimension, rv, indexIdentifier);
202 
203  uint32_t bindex = static_cast<uint32_t>(std::floor(static_cast<double>(indexCapacity * fillFactor)));
204  uint32_t bleaf = static_cast<uint32_t>(std::floor(static_cast<double>(leafCapacity * fillFactor)));
205 
207 
208  switch (m)
209  {
210  case BLM_STR:
211  bl.bulkLoadUsingSTR(static_cast<RTree*>(tree), stream, bindex, bleaf, 10000, 100);
212  break;
213  default:
214  throw Tools::IllegalArgumentException("createAndBulkLoadNewRTree: Unknown bulk load method.");
215  break;
216  }
217 
218  return tree;
219 }
220 
222  BulkLoadMethod m,
223  IDataStream& stream,
225  Tools::PropertySet& ps,
226  id_type& indexIdentifier)
227 {
228  Tools::Variant var;
230  double fillFactor(0.7);
231  uint32_t indexCapacity(100);
232  uint32_t leafCapacity(100);
233  uint32_t dimension(2);
234  uint32_t pageSize(10000);
235  uint32_t numberOfPages(100);
236 
237  // tree variant
238  var = ps.getProperty("TreeVariant");
239  if (var.m_varType != Tools::VT_EMPTY)
240  {
241  if (
242  var.m_varType != Tools::VT_LONG ||
243  (var.m_val.lVal != RV_LINEAR &&
244  var.m_val.lVal != RV_QUADRATIC &&
245  var.m_val.lVal != RV_RSTAR))
246  throw Tools::IllegalArgumentException("createAndBulkLoadNewRTree: Property TreeVariant must be Tools::VT_LONG and of RTreeVariant type");
247 
248  rv = static_cast<RTreeVariant>(var.m_val.lVal);
249  }
250 
251  // fill factor
252  // it cannot be larger than 50%, since linear and quadratic split algorithms
253  // require assigning to both nodes the same number of entries.
254  var = ps.getProperty("FillFactor");
255  if (var.m_varType != Tools::VT_EMPTY)
256  {
257  if (var.m_varType != Tools::VT_DOUBLE)
258  throw Tools::IllegalArgumentException("createAndBulkLoadNewRTree: Property FillFactor was not of type Tools::VT_DOUBLE");
259 
260  if (var.m_val.dblVal <= 0.0)
261  throw Tools::IllegalArgumentException("createAndBulkLoadNewRTree: Property FillFactor was less than 0.0");
262 
263  if (((rv == RV_LINEAR || rv == RV_QUADRATIC) && var.m_val.dblVal > 0.5))
264  throw Tools::IllegalArgumentException( "createAndBulkLoadNewRTree: Property FillFactor must be in range (0.0, 0.5) for LINEAR or QUADRATIC index types");
265  if ( var.m_val.dblVal >= 1.0)
266  throw Tools::IllegalArgumentException("createAndBulkLoadNewRTree: Property FillFactor must be in range (0.0, 1.0) for RSTAR index type");
267  fillFactor = var.m_val.dblVal;
268  }
269 
270  // index capacity
271  var = ps.getProperty("IndexCapacity");
272  if (var.m_varType != Tools::VT_EMPTY)
273  {
274  if (var.m_varType != Tools::VT_ULONG || var.m_val.ulVal < 4)
275  throw Tools::IllegalArgumentException("createAndBulkLoadNewRTree: Property IndexCapacity must be Tools::VT_ULONG and >= 4");
276 
277  indexCapacity = var.m_val.ulVal;
278  }
279 
280  // leaf capacity
281  var = ps.getProperty("LeafCapacity");
282  if (var.m_varType != Tools::VT_EMPTY)
283  {
284  if (var.m_varType != Tools::VT_ULONG || var.m_val.ulVal < 4)
285  throw Tools::IllegalArgumentException("createAndBulkLoadNewRTree: Property LeafCapacity must be Tools::VT_ULONG and >= 4");
286 
287  leafCapacity = var.m_val.ulVal;
288  }
289 
290  // dimension
291  var = ps.getProperty("Dimension");
292  if (var.m_varType != Tools::VT_EMPTY)
293  {
294  if (var.m_varType != Tools::VT_ULONG)
295  throw Tools::IllegalArgumentException("createAndBulkLoadNewRTree: Property Dimension must be Tools::VT_ULONG");
296  if (var.m_val.ulVal <= 1)
297  throw Tools::IllegalArgumentException("createAndBulkLoadNewRTree: Property Dimension must be greater than 1");
298 
299  dimension = var.m_val.ulVal;
300  }
301 
302  // page size
303  var = ps.getProperty("ExternalSortBufferPageSize");
304  if (var.m_varType != Tools::VT_EMPTY)
305  {
306  if (var.m_varType != Tools::VT_ULONG)
307  throw Tools::IllegalArgumentException("createAndBulkLoadNewRTree: Property ExternalSortBufferPageSize must be Tools::VT_ULONG");
308  if (var.m_val.ulVal <= 1)
309  throw Tools::IllegalArgumentException("createAndBulkLoadNewRTree: Property ExternalSortBufferPageSize must be greater than 1");
310 
311  pageSize = var.m_val.ulVal;
312  }
313 
314  // number of pages
315  var = ps.getProperty("ExternalSortBufferTotalPages");
316  if (var.m_varType != Tools::VT_EMPTY)
317  {
318  if (var.m_varType != Tools::VT_ULONG)
319  throw Tools::IllegalArgumentException("createAndBulkLoadNewRTree: Property ExternalSortBufferTotalPages must be Tools::VT_ULONG");
320  if (var.m_val.ulVal <= 1)
321  throw Tools::IllegalArgumentException("createAndBulkLoadNewRTree: Property ExternalSortBufferTotalPages must be greater than 1");
322 
323  numberOfPages = var.m_val.ulVal;
324  }
325 
326  SpatialIndex::ISpatialIndex* tree = createNewRTree(sm, fillFactor, indexCapacity, leafCapacity, dimension, rv, indexIdentifier);
327 
328  uint32_t bindex = static_cast<uint32_t>(std::floor(static_cast<double>(indexCapacity * fillFactor)));
329  uint32_t bleaf = static_cast<uint32_t>(std::floor(static_cast<double>(leafCapacity * fillFactor)));
330 
332 
333  switch (m)
334  {
335  case BLM_STR:
336  bl.bulkLoadUsingSTR(static_cast<RTree*>(tree), stream, bindex, bleaf, pageSize, numberOfPages);
337  break;
338  default:
339  throw Tools::IllegalArgumentException("createAndBulkLoadNewRTree: Unknown bulk load method.");
340  break;
341  }
342 
343  return tree;
344 }
345 
347 {
348  Tools::Variant var;
350 
352  var.m_val.llVal = indexIdentifier;
353  ps.setProperty("IndexIdentifier", var);
354 
355  return returnRTree(sm, ps);
356 }
357 
359  m_pStorageManager(&sm),
360  m_rootID(StorageManager::NewPage),
361  m_headerID(StorageManager::NewPage),
362  m_treeVariant(RV_RSTAR),
363  m_fillFactor(0.7),
364  m_indexCapacity(100),
365  m_leafCapacity(100),
366  m_nearMinimumOverlapFactor(32),
367  m_splitDistributionFactor(0.4),
368  m_reinsertFactor(0.3),
369  m_dimension(2),
370  m_bTightMBRs(true),
371  m_pointPool(500),
372  m_regionPool(1000),
373  m_indexPool(100),
374  m_leafPool(100)
375 {
376  Tools::Variant var = ps.getProperty("IndexIdentifier");
377  if (var.m_varType != Tools::VT_EMPTY)
378  {
379  if (var.m_varType == Tools::VT_LONGLONG) m_headerID = var.m_val.llVal;
380  else if (var.m_varType == Tools::VT_LONG) m_headerID = var.m_val.lVal;
381  // for backward compatibility only.
382  else throw Tools::IllegalArgumentException("RTree: Property IndexIdentifier must be Tools::VT_LONGLONG");
383 
384  initOld(ps);
385  }
386  else
387  {
388  initNew(ps);
390  var.m_val.llVal = m_headerID;
391  ps.setProperty("IndexIdentifier", var);
392  }
393 }
394 
396 {
397  storeHeader();
398 }
399 
400 //
401 // ISpatialIndex interface
402 //
403 
404 void SpatialIndex::RTree::RTree::insertData(uint32_t len, const uint8_t* pData, const IShape& shape, id_type id)
405 {
406  if (shape.getDimension() != m_dimension) throw Tools::IllegalArgumentException("insertData: Shape has the wrong number of dimensions.");
407 
408  // convert the shape into a Region (R-Trees index regions only; i.e., approximations of the shapes).
409  RegionPtr mbr = m_regionPool.acquire();
410  shape.getMBR(*mbr);
411 
412  uint8_t* buffer = nullptr;
413 
414  if (len > 0)
415  {
416  buffer = new uint8_t[len];
417  memcpy(buffer, pData, len);
418  }
419 
420  insertData_impl(len, buffer, *mbr, id);
421  // the buffer is stored in the tree. Do not delete here.
422 }
423 
425 {
426  if (shape.getDimension() != m_dimension) throw Tools::IllegalArgumentException("deleteData: Shape has the wrong number of dimensions.");
427 
428  RegionPtr mbr = m_regionPool.acquire();
429  shape.getMBR(*mbr);
430  bool ret = deleteData_impl(*mbr, id);
431 
432  return ret;
433 }
434 
435 
437 {
438  if (query.getDimension() != m_dimension) throw Tools::IllegalArgumentException("containsWhatQuery: Shape has the wrong number of dimensions.");
439 
440 #ifdef HAVE_PTHREAD_H
441  Tools::LockGuard lock(&m_lock);
442 #endif
443 
444  try
445  {
446  std::stack<NodePtr> st;
447  NodePtr root = readNode(m_rootID);
448  st.push(root);
449 
450  while (! st.empty())
451  {
452  NodePtr n = st.top(); st.pop();
453 
454  if(query.containsShape(n->m_nodeMBR))
455  {
456  IdVisitor vId = IdVisitor();
457  visitSubTree(n, vId);
458  const uint64_t nObj = vId.GetResultCount();
459  uint64_t *obj = new uint64_t[nObj];
460  std::copy(vId.GetResults().begin(), vId.GetResults().end(), obj);
461 
462  Data data = Data((uint32_t)(sizeof(uint64_t) * nObj), (uint8_t *) obj, n->m_nodeMBR, n->getIdentifier());
463  v.visitData(data);
464  ++(m_stats.m_u64QueryResults);
465  }
466  else
467  {
468  if(n->m_level == 0)
469  {
470  for (uint32_t cChild = 0; cChild < n->m_children; ++cChild)
471  {
472  if(query.containsShape(*(n->m_ptrMBR[cChild])))
473  {
474  Data data = Data(sizeof(id_type), (uint8_t *) &n->m_pIdentifier[cChild], *(n->m_ptrMBR[cChild]), n->getIdentifier());
475  v.visitData(data);
476  ++(m_stats.m_u64QueryResults);
477  }
478  }
479  }
480  else //not a leaf
481  {
482  if(query.intersectsShape(n->m_nodeMBR))
483  {
484  for (uint32_t cChild = 0; cChild < n->m_children; ++cChild)
485  {
486  st.push(readNode(n->m_pIdentifier[cChild]));
487  }
488  }
489  }
490  }
491  }
492 
493  }
494  catch (...)
495  {
496  throw;
497  }
498 }
499 
501 {
502  if (query.getDimension() != m_dimension) throw Tools::IllegalArgumentException("containsWhatQuery: Shape has the wrong number of dimensions.");
503 
504  try
505  {
506  std::stack<NodePtr> st;
507  NodePtr root = readNode(m_rootID);
508  st.push(root);
509 
510  while (! st.empty())
511  {
512  NodePtr n = st.top(); st.pop();
513 
514  if(n->m_level == 0)
515  {
516  v.visitNode(*n);
517 
518  for (uint32_t cChild = 0; cChild < n->m_children; ++cChild)
519  {
520  if(query.containsShape(*(n->m_ptrMBR[cChild])))
521  {
522  Data data = Data(n->m_pDataLength[cChild], n->m_pData[cChild], *(n->m_ptrMBR[cChild]), n->m_pIdentifier[cChild]);
523  v.visitData(data);
524  ++(m_stats.m_u64QueryResults);
525  }
526  }
527  }
528  else //not a leaf
529  {
530  if(query.containsShape(n->m_nodeMBR))
531  {
532  visitSubTree(n, v);
533  }
534  else if(query.intersectsShape(n->m_nodeMBR))
535  {
536  v.visitNode(*n);
537 
538  for (uint32_t cChild = 0; cChild < n->m_children; ++cChild)
539  {
540  st.push(readNode(n->m_pIdentifier[cChild]));
541  }
542  }
543  }
544  }
545 
546  }
547  catch (...)
548  {
549  throw;
550  }
551 }
553 {
554  if (query.getDimension() != m_dimension) throw Tools::IllegalArgumentException("intersectsWithQuery: Shape has the wrong number of dimensions.");
555  rangeQuery(IntersectionQuery, query, v);
556 }
557 
559 {
560  if (query.m_dimension != m_dimension) throw Tools::IllegalArgumentException("pointLocationQuery: Shape has the wrong number of dimensions.");
561  Region r(query, query);
562  rangeQuery(IntersectionQuery, r, v);
563 }
564 
565 template <class T, class S, class C>
566  S& Container(std::priority_queue<T, S, C>& q) {
567  struct HackedQueue : private std::priority_queue<T, S, C> {
568  static S& Container(std::priority_queue<T, S, C>& q) {
569  return q.*&HackedQueue::c;
570  }
571  };
572  return HackedQueue::Container(q);
573 }
574 
575 double SpatialIndex::RTree::RTree::nearestNeighborQuery(uint32_t k, const IShape& query, IVisitor& v, INearestNeighborComparator& nnc, double max_dist)
576 {
577  if (query.getDimension() != m_dimension) throw Tools::IllegalArgumentException("nearestNeighborQuery: Shape has the wrong number of dimensions.");
578 
579  auto ascending = [](const NNEntry& lhs, const NNEntry& rhs) { return lhs.m_minDist > rhs.m_minDist; };
580  std::priority_queue<NNEntry, std::vector<NNEntry>, decltype(ascending)> queue(ascending);
581 
582  // Extract the container from the queue
583  std::vector<NNEntry>& queue_c = Container(queue);
584  queue_c.reserve(64);
585 
586  queue.push(NNEntry(m_rootID, nullptr, 0.0));
587 
588  uint32_t count = 0;
589  double knearest = 0.0;
590 
591  while (! queue.empty())
592  {
593  NNEntry pFirst = queue.top();
594 
595  if (max_dist && pFirst.m_minDist > max_dist) break;
596 
597  // report all nearest neighbors with equal greatest distances.
598  // (neighbors can be more than k, if many happen to have the same greatest distance).
599  if (count >= k && pFirst.m_minDist > knearest) break;
600 
601  queue.pop();
602 
603  if (pFirst.m_pEntry == nullptr)
604  {
605  // n is a leaf or an index.
606  NodePtr n = readNode(pFirst.m_id);
607  v.visitNode(*n);
608 
609  for (uint32_t cChild = 0; cChild < n->m_children; ++cChild)
610  {
611  if (n->m_level == 0)
612  {
613  Data* e = new Data(n->m_pDataLength[cChild], n->m_pData[cChild], *(n->m_ptrMBR[cChild]), n->m_pIdentifier[cChild]);
614  // we need to compare the query with the actual data entry here, so we call the
615  // appropriate getMinimumDistance method of NearestNeighborComparator.
616  queue.push(NNEntry(n->m_pIdentifier[cChild], e, nnc.getMinimumDistance(query, e->m_region)));
617  }
618  else
619  {
620  queue.push(NNEntry(n->m_pIdentifier[cChild], nullptr, nnc.getMinimumDistance(query, *(n->m_ptrMBR[cChild]))));
621  }
622  }
623  }
624  else
625  {
626  v.visitData(*(static_cast<IData*>(pFirst.m_pEntry)));
627  ++(m_stats.m_u64QueryResults);
628  ++count;
629  knearest = pFirst.m_minDist;
630  delete pFirst.m_pEntry;
631  }
632  }
633 
634  for (auto& e : queue_c)
635  if (e.m_pEntry)
636  delete e.m_pEntry;
637 
638  return knearest;
639 }
640 
641 double SpatialIndex::RTree::RTree::nearestNeighborQuery(uint32_t k, const IShape& query, IVisitor& v, double max_dist)
642 {
643  if (query.getDimension() != m_dimension) throw Tools::IllegalArgumentException("nearestNeighborQuery: Shape has the wrong number of dimensions.");
644  NNComparator nnc;
645  return nearestNeighborQuery(k, query, v, nnc, max_dist);
646 }
647 
648 
650 {
651  if (query.getDimension() != m_dimension)
652  throw Tools::IllegalArgumentException("selfJoinQuery: Shape has the wrong number of dimensions.");
653 
654  RegionPtr mbr = m_regionPool.acquire();
655  query.getMBR(*mbr);
656  selfJoinQuery(m_rootID, m_rootID, *mbr, v);
657 }
658 
660 {
661  id_type next = m_rootID;
662  bool hasNext = true;
663 
664  while (hasNext)
665  {
666  NodePtr n = readNode(next);
667  qs.getNextEntry(*n, next, hasNext);
668  }
669 }
670 
672 {
673  Tools::Variant var;
674 
675  // dimension
677  var.m_val.ulVal = m_dimension;
678  out.setProperty("Dimension", var);
679 
680  // index capacity
682  var.m_val.ulVal = m_indexCapacity;
683  out.setProperty("IndexCapacity", var);
684 
685  // leaf capacity
687  var.m_val.ulVal = m_leafCapacity;
688  out.setProperty("LeafCapacity", var);
689 
690  // R-tree variant
692  var.m_val.lVal = m_treeVariant;
693  out.setProperty("TreeVariant", var);
694 
695  // fill factor
697  var.m_val.dblVal = m_fillFactor;
698  out.setProperty("FillFactor", var);
699 
700  // near minimum overlap factor
702  var.m_val.ulVal = m_nearMinimumOverlapFactor;
703  out.setProperty("NearMinimumOverlapFactor", var);
704 
705  // split distribution factor
707  var.m_val.dblVal = m_splitDistributionFactor;
708  out.setProperty("SplitDistributionFactor", var);
709 
710  // reinsert factor
712  var.m_val.dblVal = m_reinsertFactor;
713  out.setProperty("ReinsertFactor", var);
714 
715  // tight MBRs
717  var.m_val.blVal = m_bTightMBRs;
718  out.setProperty("EnsureTightMBRs", var);
719 
720  // index pool capacity
722  var.m_val.ulVal = m_indexPool.getCapacity();
723  out.setProperty("IndexPoolCapacity", var);
724 
725  // leaf pool capacity
727  var.m_val.ulVal = m_leafPool.getCapacity();
728  out.setProperty("LeafPoolCapacity", var);
729 
730  // region pool capacity
732  var.m_val.ulVal = m_regionPool.getCapacity();
733  out.setProperty("RegionPoolCapacity", var);
734 
735  // point pool capacity
737  var.m_val.ulVal = m_pointPool.getCapacity();
738  out.setProperty("PointPoolCapacity", var);
739 
741  var.m_val.llVal = m_headerID;
742  out.setProperty("IndexIdentifier", var);
743 
744 }
745 
747 {
748  switch (ct)
749  {
750  case CT_NODEREAD:
751  m_readNodeCommands.push_back(std::shared_ptr<ICommand>(pCommand));
752  break;
753  case CT_NODEWRITE:
754  m_writeNodeCommands.push_back(std::shared_ptr<ICommand>(pCommand));
755  break;
756  case CT_NODEDELETE:
757  m_deleteNodeCommands.push_back(std::shared_ptr<ICommand>(pCommand));
758  break;
759  }
760 }
761 
763 {
764  bool ret = true;
765  std::stack<ValidateEntry> st;
766  NodePtr root = readNode(m_rootID);
767 
768  if (root->m_level != m_stats.m_u32TreeHeight - 1)
769  {
770  std::cerr << "Invalid tree height." << std::endl;
771  return false;
772  }
773 
774  std::map<uint32_t, uint32_t> nodesInLevel;
775  nodesInLevel.insert(std::pair<uint32_t, uint32_t>(root->m_level, 1));
776 
777  ValidateEntry e(root->m_nodeMBR, root);
778  st.push(e);
779 
780  while (! st.empty())
781  {
782  e = st.top(); st.pop();
783 
784  Region tmpRegion;
785  tmpRegion = m_infiniteRegion;
786 
787  for (uint32_t cDim = 0; cDim < tmpRegion.m_dimension; ++cDim)
788  {
789  tmpRegion.m_pLow[cDim] = std::numeric_limits<double>::max();
790  tmpRegion.m_pHigh[cDim] = -std::numeric_limits<double>::max();
791 
792  for (uint32_t cChild = 0; cChild < e.m_pNode->m_children; ++cChild)
793  {
794  tmpRegion.m_pLow[cDim] = std::min(tmpRegion.m_pLow[cDim], e.m_pNode->m_ptrMBR[cChild]->m_pLow[cDim]);
795  tmpRegion.m_pHigh[cDim] = std::max(tmpRegion.m_pHigh[cDim], e.m_pNode->m_ptrMBR[cChild]->m_pHigh[cDim]);
796  }
797  }
798 
799  if (! (tmpRegion == e.m_pNode->m_nodeMBR))
800  {
801  std::cerr << "Invalid parent information." << std::endl;
802  ret = false;
803  }
804  else if (! (tmpRegion == e.m_parentMBR))
805  {
806  std::cerr << "Error in parent." << std::endl;
807  ret = false;
808  }
809 
810  if (e.m_pNode->m_level != 0)
811  {
812  for (uint32_t cChild = 0; cChild < e.m_pNode->m_children; ++cChild)
813  {
814  NodePtr ptrN = readNode(e.m_pNode->m_pIdentifier[cChild]);
815  ValidateEntry tmpEntry(*(e.m_pNode->m_ptrMBR[cChild]), ptrN);
816 
817  std::map<uint32_t, uint32_t>::iterator itNodes = nodesInLevel.find(tmpEntry.m_pNode->m_level);
818 
819  if (itNodes == nodesInLevel.end())
820  {
821  nodesInLevel.insert(std::pair<uint32_t, uint32_t>(tmpEntry.m_pNode->m_level, 1l));
822  }
823  else
824  {
825  nodesInLevel[tmpEntry.m_pNode->m_level] = nodesInLevel[tmpEntry.m_pNode->m_level] + 1;
826  }
827 
828  st.push(tmpEntry);
829  }
830  }
831  }
832 
833  uint32_t nodes = 0;
834  for (uint32_t cLevel = 0; cLevel < m_stats.m_u32TreeHeight; ++cLevel)
835  {
836  if (nodesInLevel[cLevel] != m_stats.m_nodesInLevel[cLevel])
837  {
838  std::cerr << "Invalid nodesInLevel information." << std::endl;
839  ret = false;
840  }
841 
842  nodes += m_stats.m_nodesInLevel[cLevel];
843  }
844 
845  if (nodes != m_stats.m_u32Nodes)
846  {
847  std::cerr << "Invalid number of nodes information." << std::endl;
848  ret = false;
849  }
850 
851  return ret;
852 }
853 
855 {
856  *out = new Statistics(m_stats);
857 }
858 
860 {
861  storeHeader();
862 }
863 
864 void SpatialIndex::RTree::RTree::initNew(Tools::PropertySet& ps)
865 {
866  Tools::Variant var;
867 
868  // tree variant
869  var = ps.getProperty("TreeVariant");
870  if (var.m_varType != Tools::VT_EMPTY)
871  {
872  if (
873  var.m_varType != Tools::VT_LONG ||
874  (var.m_val.lVal != RV_LINEAR &&
875  var.m_val.lVal != RV_QUADRATIC &&
876  var.m_val.lVal != RV_RSTAR))
877  throw Tools::IllegalArgumentException("initNew: Property TreeVariant must be Tools::VT_LONG and of RTreeVariant type");
878 
879  m_treeVariant = static_cast<RTreeVariant>(var.m_val.lVal);
880  }
881 
882  // fill factor
883  // it cannot be larger than 50%, since linear and quadratic split algorithms
884  // require assigning to both nodes the same number of entries.
885  var = ps.getProperty("FillFactor");
886  if (var.m_varType != Tools::VT_EMPTY)
887  {
888  if (var.m_varType != Tools::VT_DOUBLE)
889  throw Tools::IllegalArgumentException("initNew: Property FillFactor was not of type Tools::VT_DOUBLE");
890 
891  if (var.m_val.dblVal <= 0.0)
892  throw Tools::IllegalArgumentException("initNew: Property FillFactor was less than 0.0");
893 
894  if (((m_treeVariant == RV_LINEAR || m_treeVariant == RV_QUADRATIC) && var.m_val.dblVal > 0.5))
895  throw Tools::IllegalArgumentException( "initNew: Property FillFactor must be in range "
896  "(0.0, 0.5) for LINEAR or QUADRATIC index types");
897  if ( var.m_val.dblVal >= 1.0)
898  throw Tools::IllegalArgumentException( "initNew: Property FillFactor must be in range "
899  "(0.0, 1.0) for RSTAR index type");
900  m_fillFactor = var.m_val.dblVal;
901  }
902 
903  // index capacity
904  var = ps.getProperty("IndexCapacity");
905  if (var.m_varType != Tools::VT_EMPTY)
906  {
907  if (var.m_varType != Tools::VT_ULONG || var.m_val.ulVal < 4)
908  throw Tools::IllegalArgumentException("initNew: Property IndexCapacity must be Tools::VT_ULONG and >= 4");
909 
910  m_indexCapacity = var.m_val.ulVal;
911  }
912 
913  // leaf capacity
914  var = ps.getProperty("LeafCapacity");
915  if (var.m_varType != Tools::VT_EMPTY)
916  {
917  if (var.m_varType != Tools::VT_ULONG || var.m_val.ulVal < 4)
918  throw Tools::IllegalArgumentException("initNew: Property LeafCapacity must be Tools::VT_ULONG and >= 4");
919 
920  m_leafCapacity = var.m_val.ulVal;
921  }
922 
923  // near minimum overlap factor
924  var = ps.getProperty("NearMinimumOverlapFactor");
925  if (var.m_varType != Tools::VT_EMPTY)
926  {
927  if (
928  var.m_varType != Tools::VT_ULONG ||
929  var.m_val.ulVal < 1 ||
930  var.m_val.ulVal > m_indexCapacity ||
931  var.m_val.ulVal > m_leafCapacity)
932  throw Tools::IllegalArgumentException("initNew: Property NearMinimumOverlapFactor must be Tools::VT_ULONG and less than both index and leaf capacities");
933 
934  m_nearMinimumOverlapFactor = var.m_val.ulVal;
935  }
936 
937  // split distribution factor
938  var = ps.getProperty("SplitDistributionFactor");
939  if (var.m_varType != Tools::VT_EMPTY)
940  {
941  if (
942  var.m_varType != Tools::VT_DOUBLE ||
943  var.m_val.dblVal <= 0.0 ||
944  var.m_val.dblVal >= 1.0)
945  throw Tools::IllegalArgumentException("initNew: Property SplitDistributionFactor must be Tools::VT_DOUBLE and in (0.0, 1.0)");
946 
947  m_splitDistributionFactor = var.m_val.dblVal;
948  }
949 
950  // reinsert factor
951  var = ps.getProperty("ReinsertFactor");
952  if (var.m_varType != Tools::VT_EMPTY)
953  {
954  if (
955  var.m_varType != Tools::VT_DOUBLE ||
956  var.m_val.dblVal <= 0.0 ||
957  var.m_val.dblVal >= 1.0)
958  throw Tools::IllegalArgumentException("initNew: Property ReinsertFactor must be Tools::VT_DOUBLE and in (0.0, 1.0)");
959 
960  m_reinsertFactor = var.m_val.dblVal;
961  }
962 
963  // dimension
964  var = ps.getProperty("Dimension");
965  if (var.m_varType != Tools::VT_EMPTY)
966  {
967  if (var.m_varType != Tools::VT_ULONG)
968  throw Tools::IllegalArgumentException("initNew: Property Dimension must be Tools::VT_ULONG");
969  if (var.m_val.ulVal <= 1)
970  throw Tools::IllegalArgumentException("initNew: Property Dimension must be greater than 1");
971 
972  m_dimension = var.m_val.ulVal;
973  }
974 
975  // tight MBRs
976  var = ps.getProperty("EnsureTightMBRs");
977  if (var.m_varType != Tools::VT_EMPTY)
978  {
979  if (var.m_varType != Tools::VT_BOOL)
980  throw Tools::IllegalArgumentException("initNew: Property EnsureTightMBRs must be Tools::VT_BOOL");
981 
982  m_bTightMBRs = var.m_val.blVal;
983  }
984 
985  // index pool capacity
986  var = ps.getProperty("IndexPoolCapacity");
987  if (var.m_varType != Tools::VT_EMPTY)
988  {
989  if (var.m_varType != Tools::VT_ULONG)
990  throw Tools::IllegalArgumentException("initNew: Property IndexPoolCapacity must be Tools::VT_ULONG");
991 
992  m_indexPool.setCapacity(var.m_val.ulVal);
993  }
994 
995  // leaf pool capacity
996  var = ps.getProperty("LeafPoolCapacity");
997  if (var.m_varType != Tools::VT_EMPTY)
998  {
999  if (var.m_varType != Tools::VT_ULONG)
1000  throw Tools::IllegalArgumentException("initNew: Property LeafPoolCapacity must be Tools::VT_ULONG");
1001 
1002  m_leafPool.setCapacity(var.m_val.ulVal);
1003  }
1004 
1005  // region pool capacity
1006  var = ps.getProperty("RegionPoolCapacity");
1007  if (var.m_varType != Tools::VT_EMPTY)
1008  {
1009  if (var.m_varType != Tools::VT_ULONG)
1010  throw Tools::IllegalArgumentException("initNew: Property RegionPoolCapacity must be Tools::VT_ULONG");
1011 
1012  m_regionPool.setCapacity(var.m_val.ulVal);
1013  }
1014 
1015  // point pool capacity
1016  var = ps.getProperty("PointPoolCapacity");
1017  if (var.m_varType != Tools::VT_EMPTY)
1018  {
1019  if (var.m_varType != Tools::VT_ULONG)
1020  throw Tools::IllegalArgumentException("initNew: Property PointPoolCapacity must be Tools::VT_ULONG");
1021 
1022  m_pointPool.setCapacity(var.m_val.ulVal);
1023  }
1024 
1025  m_infiniteRegion.makeInfinite(m_dimension);
1026 
1027  m_stats.m_u32TreeHeight = 1;
1028  m_stats.m_nodesInLevel.push_back(0);
1029 
1030  Leaf root(this, -1);
1031  m_rootID = writeNode(&root);
1032 
1033  storeHeader();
1034 }
1035 
1036 void SpatialIndex::RTree::RTree::initOld(Tools::PropertySet& ps)
1037 {
1038  loadHeader();
1039 
1040  // only some of the properties may be changed.
1041  // the rest are just ignored.
1042 
1043  Tools::Variant var;
1044 
1045  // tree variant
1046  var = ps.getProperty("TreeVariant");
1047  if (var.m_varType != Tools::VT_EMPTY)
1048  {
1049  if (
1050  var.m_varType != Tools::VT_LONG ||
1051  (var.m_val.lVal != RV_LINEAR &&
1052  var.m_val.lVal != RV_QUADRATIC &&
1053  var.m_val.lVal != RV_RSTAR))
1054  throw Tools::IllegalArgumentException("initOld: Property TreeVariant must be Tools::VT_LONG and of RTreeVariant type");
1055 
1056  m_treeVariant = static_cast<RTreeVariant>(var.m_val.lVal);
1057  }
1058 
1059  // near minimum overlap factor
1060  var = ps.getProperty("NearMinimumOverlapFactor");
1061  if (var.m_varType != Tools::VT_EMPTY)
1062  {
1063  if (
1064  var.m_varType != Tools::VT_ULONG ||
1065  var.m_val.ulVal < 1 ||
1066  var.m_val.ulVal > m_indexCapacity ||
1067  var.m_val.ulVal > m_leafCapacity)
1068  throw Tools::IllegalArgumentException("initOld: Property NearMinimumOverlapFactor must be Tools::VT_ULONG and less than both index and leaf capacities");
1069 
1070  m_nearMinimumOverlapFactor = var.m_val.ulVal;
1071  }
1072 
1073  // split distribution factor
1074  var = ps.getProperty("SplitDistributionFactor");
1075  if (var.m_varType != Tools::VT_EMPTY)
1076  {
1077  if (var.m_varType != Tools::VT_DOUBLE || var.m_val.dblVal <= 0.0 || var.m_val.dblVal >= 1.0)
1078  throw Tools::IllegalArgumentException("initOld: Property SplitDistributionFactor must be Tools::VT_DOUBLE and in (0.0, 1.0)");
1079 
1080  m_splitDistributionFactor = var.m_val.dblVal;
1081  }
1082 
1083  // reinsert factor
1084  var = ps.getProperty("ReinsertFactor");
1085  if (var.m_varType != Tools::VT_EMPTY)
1086  {
1087  if (var.m_varType != Tools::VT_DOUBLE || var.m_val.dblVal <= 0.0 || var.m_val.dblVal >= 1.0)
1088  throw Tools::IllegalArgumentException("initOld: Property ReinsertFactor must be Tools::VT_DOUBLE and in (0.0, 1.0)");
1089 
1090  m_reinsertFactor = var.m_val.dblVal;
1091  }
1092 
1093  // tight MBRs
1094  var = ps.getProperty("EnsureTightMBRs");
1095  if (var.m_varType != Tools::VT_EMPTY)
1096  {
1097  if (var.m_varType != Tools::VT_BOOL) throw Tools::IllegalArgumentException("initOld: Property EnsureTightMBRs must be Tools::VT_BOOL");
1098 
1099  m_bTightMBRs = var.m_val.blVal;
1100  }
1101 
1102  // index pool capacity
1103  var = ps.getProperty("IndexPoolCapacity");
1104  if (var.m_varType != Tools::VT_EMPTY)
1105  {
1106  if (var.m_varType != Tools::VT_ULONG) throw Tools::IllegalArgumentException("initOld: Property IndexPoolCapacity must be Tools::VT_ULONG");
1107 
1108  m_indexPool.setCapacity(var.m_val.ulVal);
1109  }
1110 
1111  // leaf pool capacity
1112  var = ps.getProperty("LeafPoolCapacity");
1113  if (var.m_varType != Tools::VT_EMPTY)
1114  {
1115  if (var.m_varType != Tools::VT_ULONG) throw Tools::IllegalArgumentException("initOld: Property LeafPoolCapacity must be Tools::VT_ULONG");
1116 
1117  m_leafPool.setCapacity(var.m_val.ulVal);
1118  }
1119 
1120  // region pool capacity
1121  var = ps.getProperty("RegionPoolCapacity");
1122  if (var.m_varType != Tools::VT_EMPTY)
1123  {
1124  if (var.m_varType != Tools::VT_ULONG) throw Tools::IllegalArgumentException("initOld: Property RegionPoolCapacity must be Tools::VT_ULONG");
1125 
1126  m_regionPool.setCapacity(var.m_val.ulVal);
1127  }
1128 
1129  // point pool capacity
1130  var = ps.getProperty("PointPoolCapacity");
1131  if (var.m_varType != Tools::VT_EMPTY)
1132  {
1133  if (var.m_varType != Tools::VT_ULONG) throw Tools::IllegalArgumentException("initOld: Property PointPoolCapacity must be Tools::VT_ULONG");
1134 
1135  m_pointPool.setCapacity(var.m_val.ulVal);
1136  }
1137 
1138  m_infiniteRegion.makeInfinite(m_dimension);
1139 }
1140 
1141 void SpatialIndex::RTree::RTree::storeHeader()
1142 {
1143  const uint32_t headerSize =
1144  sizeof(id_type) + // m_rootID
1145  sizeof(RTreeVariant) + // m_treeVariant
1146  sizeof(double) + // m_fillFactor
1147  sizeof(uint32_t) + // m_indexCapacity
1148  sizeof(uint32_t) + // m_leafCapacity
1149  sizeof(uint32_t) + // m_nearMinimumOverlapFactor
1150  sizeof(double) + // m_splitDistributionFactor
1151  sizeof(double) + // m_reinsertFactor
1152  sizeof(uint32_t) + // m_dimension
1153  sizeof(char) + // m_bTightMBRs
1154  sizeof(uint32_t) + // m_stats.m_nodes
1155  sizeof(uint64_t) + // m_stats.m_data
1156  sizeof(uint32_t) + // m_stats.m_treeHeight
1157  m_stats.m_u32TreeHeight * sizeof(uint32_t); // m_stats.m_nodesInLevel
1158 
1159  uint8_t* header = new uint8_t[headerSize];
1160  uint8_t* ptr = header;
1161 
1162  memcpy(ptr, &m_rootID, sizeof(id_type));
1163  ptr += sizeof(id_type);
1164  memcpy(ptr, &m_treeVariant, sizeof(RTreeVariant));
1165  ptr += sizeof(RTreeVariant);
1166  memcpy(ptr, &m_fillFactor, sizeof(double));
1167  ptr += sizeof(double);
1168  memcpy(ptr, &m_indexCapacity, sizeof(uint32_t));
1169  ptr += sizeof(uint32_t);
1170  memcpy(ptr, &m_leafCapacity, sizeof(uint32_t));
1171  ptr += sizeof(uint32_t);
1172  memcpy(ptr, &m_nearMinimumOverlapFactor, sizeof(uint32_t));
1173  ptr += sizeof(uint32_t);
1174  memcpy(ptr, &m_splitDistributionFactor, sizeof(double));
1175  ptr += sizeof(double);
1176  memcpy(ptr, &m_reinsertFactor, sizeof(double));
1177  ptr += sizeof(double);
1178  memcpy(ptr, &m_dimension, sizeof(uint32_t));
1179  ptr += sizeof(uint32_t);
1180  char c = (char) m_bTightMBRs;
1181  memcpy(ptr, &c, sizeof(char));
1182  ptr += sizeof(char);
1183  memcpy(ptr, &(m_stats.m_u32Nodes), sizeof(uint32_t));
1184  ptr += sizeof(uint32_t);
1185  memcpy(ptr, &(m_stats.m_u64Data), sizeof(uint64_t));
1186  ptr += sizeof(uint64_t);
1187  memcpy(ptr, &(m_stats.m_u32TreeHeight), sizeof(uint32_t));
1188  ptr += sizeof(uint32_t);
1189 
1190  for (uint32_t cLevel = 0; cLevel < m_stats.m_u32TreeHeight; ++cLevel)
1191  {
1192  memcpy(ptr, &(m_stats.m_nodesInLevel[cLevel]), sizeof(uint32_t));
1193  ptr += sizeof(uint32_t);
1194  }
1195 
1196  m_pStorageManager->storeByteArray(m_headerID, headerSize, header);
1197 
1198  delete[] header;
1199 }
1200 
1201 void SpatialIndex::RTree::RTree::loadHeader()
1202 {
1203  uint32_t headerSize;
1204  uint8_t* header = nullptr;
1205  m_pStorageManager->loadByteArray(m_headerID, headerSize, &header);
1206 
1207  uint8_t* ptr = header;
1208 
1209  memcpy(&m_rootID, ptr, sizeof(id_type));
1210  ptr += sizeof(id_type);
1211  memcpy(&m_treeVariant, ptr, sizeof(RTreeVariant));
1212  ptr += sizeof(RTreeVariant);
1213  memcpy(&m_fillFactor, ptr, sizeof(double));
1214  ptr += sizeof(double);
1215  memcpy(&m_indexCapacity, ptr, sizeof(uint32_t));
1216  ptr += sizeof(uint32_t);
1217  memcpy(&m_leafCapacity, ptr, sizeof(uint32_t));
1218  ptr += sizeof(uint32_t);
1219  memcpy(&m_nearMinimumOverlapFactor, ptr, sizeof(uint32_t));
1220  ptr += sizeof(uint32_t);
1221  memcpy(&m_splitDistributionFactor, ptr, sizeof(double));
1222  ptr += sizeof(double);
1223  memcpy(&m_reinsertFactor, ptr, sizeof(double));
1224  ptr += sizeof(double);
1225  memcpy(&m_dimension, ptr, sizeof(uint32_t));
1226  ptr += sizeof(uint32_t);
1227  char c;
1228  memcpy(&c, ptr, sizeof(char));
1229  m_bTightMBRs = (c != 0);
1230  ptr += sizeof(char);
1231  memcpy(&(m_stats.m_u32Nodes), ptr, sizeof(uint32_t));
1232  ptr += sizeof(uint32_t);
1233  memcpy(&(m_stats.m_u64Data), ptr, sizeof(uint64_t));
1234  ptr += sizeof(uint64_t);
1235  memcpy(&(m_stats.m_u32TreeHeight), ptr, sizeof(uint32_t));
1236  ptr += sizeof(uint32_t);
1237 
1238  for (uint32_t cLevel = 0; cLevel < m_stats.m_u32TreeHeight; ++cLevel)
1239  {
1240  uint32_t cNodes;
1241  memcpy(&cNodes, ptr, sizeof(uint32_t));
1242  ptr += sizeof(uint32_t);
1243  m_stats.m_nodesInLevel.push_back(cNodes);
1244  }
1245 
1246  delete[] header;
1247 }
1248 
1249 void SpatialIndex::RTree::RTree::insertData_impl(uint32_t dataLength, uint8_t* pData, Region& mbr, id_type id)
1250 {
1251  assert(mbr.getDimension() == m_dimension);
1252 
1253  std::stack<id_type> pathBuffer;
1254  uint8_t* overflowTable = nullptr;
1255 
1256  try
1257  {
1258  NodePtr root = readNode(m_rootID);
1259 
1260  overflowTable = new uint8_t[root->m_level];
1261  memset(overflowTable, 0, root->m_level);
1262 
1263  NodePtr l = root->chooseSubtree(mbr, 0, pathBuffer);
1264  if (l.get() == root.get())
1265  {
1266  assert(root.unique());
1267  root.relinquish();
1268  }
1269  l->insertData(dataLength, pData, mbr, id, pathBuffer, overflowTable);
1270 
1271  delete[] overflowTable;
1272  ++(m_stats.m_u64Data);
1273  }
1274  catch (...)
1275  {
1276  delete[] overflowTable;
1277  throw;
1278  }
1279 }
1280 
1281 void SpatialIndex::RTree::RTree::insertData_impl(uint32_t dataLength, uint8_t* pData, Region& mbr, id_type id, uint32_t level, uint8_t* overflowTable)
1282 {
1283  assert(mbr.getDimension() == m_dimension);
1284 
1285  std::stack<id_type> pathBuffer;
1286  NodePtr root = readNode(m_rootID);
1287  NodePtr n = root->chooseSubtree(mbr, level, pathBuffer);
1288 
1289  assert(n->m_level == level);
1290 
1291  if (n.get() == root.get())
1292  {
1293  assert(root.unique());
1294  root.relinquish();
1295  }
1296  n->insertData(dataLength, pData, mbr, id, pathBuffer, overflowTable);
1297 }
1298 
1299 bool SpatialIndex::RTree::RTree::deleteData_impl(const Region& mbr, id_type id)
1300 {
1301  assert(mbr.m_dimension == m_dimension);
1302 
1303  std::stack<id_type> pathBuffer;
1304  NodePtr root = readNode(m_rootID);
1305  NodePtr l = root->findLeaf(mbr, id, pathBuffer);
1306  if (l.get() == root.get())
1307  {
1308  assert(root.unique());
1309  root.relinquish();
1310  }
1311 
1312  if (l.get() != nullptr)
1313  {
1314  Leaf* pL = static_cast<Leaf*>(l.get());
1315  pL->deleteData(mbr, id, pathBuffer);
1316  --(m_stats.m_u64Data);
1317  return true;
1318  }
1319 
1320  return false;
1321 }
1322 
1323 SpatialIndex::id_type SpatialIndex::RTree::RTree::writeNode(Node* n)
1324 {
1325  uint8_t* buffer;
1326  uint32_t dataLength;
1327  n->storeToByteArray(&buffer, dataLength);
1328 
1329  id_type page;
1330  if (n->m_identifier < 0) page = StorageManager::NewPage;
1331  else page = n->m_identifier;
1332 
1333  try
1334  {
1335  m_pStorageManager->storeByteArray(page, dataLength, buffer);
1336  delete[] buffer;
1337  }
1338  catch (InvalidPageException& e)
1339  {
1340  delete[] buffer;
1341  std::cerr << e.what() << std::endl;
1342  throw;
1343  }
1344 
1345  if (n->m_identifier < 0)
1346  {
1347  n->m_identifier = page;
1348  ++(m_stats.m_u32Nodes);
1349 
1350  m_stats.m_nodesInLevel[n->m_level] = m_stats.m_nodesInLevel[n->m_level] + 1;
1351  }
1352 
1353  ++(m_stats.m_u64Writes);
1354 
1355  for (size_t cIndex = 0; cIndex < m_writeNodeCommands.size(); ++cIndex)
1356  {
1357  m_writeNodeCommands[cIndex]->execute(*n);
1358  }
1359 
1360  return page;
1361 }
1362 
1363 SpatialIndex::RTree::NodePtr SpatialIndex::RTree::RTree::readNode(id_type page)
1364 {
1365  uint32_t dataLength;
1366  uint8_t* buffer;
1367 
1368  try
1369  {
1370  m_pStorageManager->loadByteArray(page, dataLength, &buffer);
1371  }
1372  catch (InvalidPageException& e)
1373  {
1374  std::cerr << e.what() << std::endl;
1375  throw;
1376  }
1377 
1378  try
1379  {
1380  uint32_t nodeType;
1381  memcpy(&nodeType, buffer, sizeof(uint32_t));
1382 
1383  NodePtr n;
1384 
1385  if (nodeType == PersistentIndex) n = m_indexPool.acquire();
1386  else if (nodeType == PersistentLeaf) n = m_leafPool.acquire();
1387  else throw Tools::IllegalStateException("readNode: failed reading the correct node type information");
1388 
1389  if (n.get() == nullptr)
1390  {
1391  if (nodeType == PersistentIndex) n = NodePtr(new Index(this, -1, 0), &m_indexPool);
1392  else if (nodeType == PersistentLeaf) n = NodePtr(new Leaf(this, -1), &m_leafPool);
1393  }
1394 
1395  //n->m_pTree = this;
1396  n->m_identifier = page;
1397  n->loadFromByteArray(buffer);
1398 
1399  ++(m_stats.m_u64Reads);
1400 
1401  for (size_t cIndex = 0; cIndex < m_readNodeCommands.size(); ++cIndex)
1402  {
1403  m_readNodeCommands[cIndex]->execute(*n);
1404  }
1405 
1406  delete[] buffer;
1407  return n;
1408  }
1409  catch (...)
1410  {
1411  delete[] buffer;
1412  throw;
1413  }
1414 }
1415 
1416 void SpatialIndex::RTree::RTree::deleteNode(Node* n)
1417 {
1418  try
1419  {
1420  m_pStorageManager->deleteByteArray(n->m_identifier);
1421  }
1422  catch (InvalidPageException& e)
1423  {
1424  std::cerr << e.what() << std::endl;
1425  throw;
1426  }
1427 
1428  --(m_stats.m_u32Nodes);
1429  m_stats.m_nodesInLevel[n->m_level] = m_stats.m_nodesInLevel[n->m_level] - 1;
1430 
1431  for (size_t cIndex = 0; cIndex < m_deleteNodeCommands.size(); ++cIndex)
1432  {
1433  m_deleteNodeCommands[cIndex]->execute(*n);
1434  }
1435 }
1436 
1437 void SpatialIndex::RTree::RTree::rangeQuery(RangeQueryType type, const IShape& query, IVisitor& v)
1438 {
1439  std::stack<NodePtr> st;
1440  NodePtr root = readNode(m_rootID);
1441 
1442  if (root->m_children > 0 && query.intersectsShape(root->m_nodeMBR)) st.push(root);
1443 
1444  while (! st.empty())
1445  {
1446  NodePtr n = st.top(); st.pop();
1447 
1448  if (n->m_level == 0)
1449  {
1450  v.visitNode(*n);
1451 
1452  for (uint32_t cChild = 0; cChild < n->m_children; ++cChild)
1453  {
1454  bool b;
1455  if (type == ContainmentQuery) b = query.containsShape(*(n->m_ptrMBR[cChild]));
1456  else b = query.intersectsShape(*(n->m_ptrMBR[cChild]));
1457 
1458  if (b)
1459  {
1460  Data data = Data(n->m_pDataLength[cChild], n->m_pData[cChild], *(n->m_ptrMBR[cChild]), n->m_pIdentifier[cChild]);
1461  v.visitData(data);
1462  ++(m_stats.m_u64QueryResults);
1463  }
1464  }
1465  }
1466  else
1467  {
1468  v.visitNode(*n);
1469 
1470  for (uint32_t cChild = 0; cChild < n->m_children; ++cChild)
1471  {
1472  if (query.intersectsShape(*(n->m_ptrMBR[cChild]))) st.push(readNode(n->m_pIdentifier[cChild]));
1473  }
1474  }
1475  }
1476 }
1477 
1479 {
1480  NodePtr n1 = readNode(id1);
1481  NodePtr n2 = readNode(id2);
1482  vis.visitNode(*n1);
1483  vis.visitNode(*n2);
1484 
1485  for (uint32_t cChild1 = 0; cChild1 < n1->m_children; ++cChild1)
1486  {
1487  if (r.intersectsRegion(*(n1->m_ptrMBR[cChild1])))
1488  {
1489  for (uint32_t cChild2 = 0; cChild2 < n2->m_children; ++cChild2)
1490  {
1491  if (
1492  r.intersectsRegion(*(n2->m_ptrMBR[cChild2])) &&
1493  n1->m_ptrMBR[cChild1]->intersectsRegion(*(n2->m_ptrMBR[cChild2])))
1494  {
1495  if (n1->m_level == 0)
1496  {
1497  if (n1->m_pIdentifier[cChild1] != n2->m_pIdentifier[cChild2])
1498  {
1499  assert(n2->m_level == 0);
1500 
1501  std::vector<const IData*> v;
1502  Data e1(n1->m_pDataLength[cChild1], n1->m_pData[cChild1], *(n1->m_ptrMBR[cChild1]), n1->m_pIdentifier[cChild1]);
1503  Data e2(n2->m_pDataLength[cChild2], n2->m_pData[cChild2], *(n2->m_ptrMBR[cChild2]), n2->m_pIdentifier[cChild2]);
1504  v.push_back(&e1);
1505  v.push_back(&e2);
1506  vis.visitData(v);
1507  }
1508  }
1509  else
1510  {
1511  Region rr = r.getIntersectingRegion(n1->m_ptrMBR[cChild1]->getIntersectingRegion(*(n2->m_ptrMBR[cChild2])));
1512  selfJoinQuery(n1->m_pIdentifier[cChild1], n2->m_pIdentifier[cChild2], rr, vis);
1513  }
1514  }
1515  }
1516  }
1517  }
1518 }
1519 
1520 void SpatialIndex::RTree::RTree::visitSubTree(NodePtr subTree, IVisitor& v)
1521 {
1522  std::stack<NodePtr> st;
1523  st.push(subTree);
1524 
1525  while (! st.empty())
1526  {
1527  NodePtr n = st.top(); st.pop();
1528  v.visitNode(*n);
1529 
1530  if(n->m_level == 0)
1531  {
1532  for (uint32_t cChild = 0; cChild < n->m_children; ++cChild)
1533  {
1534  Data data = Data(n->m_pDataLength[cChild], n->m_pData[cChild], *(n->m_ptrMBR[cChild]), n->m_pIdentifier[cChild]);
1535  v.visitData(data);
1536  ++(m_stats.m_u64QueryResults);
1537  }
1538  }
1539  else
1540  {
1541  for (uint32_t cChild = 0; cChild < n->m_children; ++cChild)
1542  {
1543  st.push(readNode(n->m_pIdentifier[cChild]));
1544  }
1545  }
1546  }
1547 }
1548 
1549 std::ostream& SpatialIndex::RTree::operator<<(std::ostream& os, const RTree& t)
1550 {
1551  os << "Dimension: " << t.m_dimension << std::endl
1552  << "Fill factor: " << t.m_fillFactor << std::endl
1553  << "Index capacity: " << t.m_indexCapacity << std::endl
1554  << "Leaf capacity: " << t.m_leafCapacity << std::endl
1555  << "Tight MBRs: " << ((t.m_bTightMBRs) ? "enabled" : "disabled") << std::endl;
1556 
1557  if (t.m_treeVariant == RV_RSTAR)
1558  {
1559  os << "Near minimum overlap factor: " << t.m_nearMinimumOverlapFactor << std::endl
1560  << "Reinsert factor: " << t.m_reinsertFactor << std::endl
1561  << "Split distribution factor: " << t.m_splitDistributionFactor << std::endl;
1562  }
1563 
1564  if (t.m_stats.getNumberOfNodesInLevel(0) > 0)
1565  os << "Utilization: " << 100 * t.m_stats.getNumberOfData() / (t.m_stats.getNumberOfNodesInLevel(0) * t.m_leafCapacity) << "%" << std::endl
1566  << t.m_stats;
1567 
1568  return os;
1569 }
S & Container(std::priority_queue< T, S, C > &q)
Definition: RTree.cc:566
std::vector< uint64_t > & GetResults()
Definition: IdVisitor.h:45
uint64_t GetResultCount() const
Definition: IdVisitor.h:44
virtual double getMinimumDistance(const IShape &query, const IShape &entry)=0
virtual void getNextEntry(const IEntry &previouslyFetched, id_type &nextEntryToFetch, bool &bFetchNextEntry)=0
virtual bool containsShape(const IShape &in) const =0
virtual bool intersectsShape(const IShape &in) const =0
virtual uint32_t getDimension() const =0
virtual void getMBR(Region &out) const =0
virtual void visitNode(const INode &in)=0
virtual void visitData(const IData &in)=0
uint32_t m_dimension
Definition: Point.h:79
void bulkLoadUsingSTR(RTree *pTree, IDataStream &stream, uint32_t bindex, uint32_t bleaf, uint32_t pageSize, uint32_t numberOfPages)
Definition: BulkLoader.cc:312
id_type getIdentifier() const override
Definition: RTree.cc:63
void getShape(IShape **out) const override
Definition: RTree.cc:68
void storeToByteArray(uint8_t **data, uint32_t &len) override
Definition: RTree.cc:115
void getData(uint32_t &len, uint8_t **data) const override
Definition: RTree.cc:73
Data(uint32_t len, uint8_t *pData, Region &r, id_type id)
Definition: RTree.cc:43
uint32_t getByteArraySize() override
Definition: RTree.cc:85
void loadFromByteArray(const uint8_t *data) override
Definition: RTree.cc:94
Data * clone() override
Definition: RTree.cc:58
virtual void deleteData(const Region &mbr, id_type id, std::stack< id_type > &pathBuffer)
Definition: rtree/Leaf.cc:111
void loadFromByteArray(const uint8_t *data) override
Definition: rtree/Node.cc:63
void storeToByteArray(uint8_t **data, uint32_t &len) override
Definition: rtree/Node.cc:112
id_type getIdentifier() const override
Definition: rtree/Node.cc:164
virtual bool deleteData(const IShape &shape, id_type id)
Definition: RTree.cc:424
virtual void getStatistics(IStatistics **out) const
Definition: RTree.cc:854
virtual double nearestNeighborQuery(uint32_t k, const IShape &query, IVisitor &v, INearestNeighborComparator &, double max_dist=0.0)
Definition: RTree.cc:575
virtual void queryStrategy(IQueryStrategy &qs)
Definition: RTree.cc:659
RTree(IStorageManager &, Tools::PropertySet &)
Definition: RTree.cc:358
virtual void addCommand(ICommand *pCommand, CommandType ct)
Definition: RTree.cc:746
virtual void flush()
Definition: RTree.cc:859
virtual void getIndexProperties(Tools::PropertySet &out) const
Definition: RTree.cc:671
virtual void pointLocationQuery(const Point &query, IVisitor &v)
Definition: RTree.cc:558
virtual void internalNodesQuery(const IShape &query, IVisitor &v)
Definition: RTree.cc:436
virtual void containsWhatQuery(const IShape &query, IVisitor &v)
Definition: RTree.cc:500
virtual bool isIndexValid()
Definition: RTree.cc:762
virtual void intersectsWithQuery(const IShape &query, IVisitor &v)
Definition: RTree.cc:552
virtual void insertData(uint32_t len, const uint8_t *pData, const IShape &shape, id_type shapeIdentifier)
Definition: RTree.cc:404
virtual void selfJoinQuery(const IShape &s, IVisitor &v)
Definition: RTree.cc:649
uint64_t getNumberOfData() const override
virtual uint32_t getNumberOfNodesInLevel(uint32_t l) const
double * m_pHigh
Definition: Region.h:101
uint32_t getDimension() const override
Definition: Region.cc:208
uint32_t m_dimension
Definition: Region.h:99
virtual Region getIntersectingRegion(const Region &r) const
Definition: Region.cc:410
double * m_pLow
Definition: Region.h:100
virtual bool intersectsRegion(const Region &in) const
Definition: Region.cc:243
bool unique() const noexcept
Definition: PoolPointer.h:56
X * get() const noexcept
Definition: PoolPointer.h:55
void relinquish() noexcept
Definition: PoolPointer.h:57
void setProperty(std::string property, Variant const &v)
Definition: Tools.cc:354
Variant getProperty(std::string property) const
Definition: Tools.cc:346
int64_t llVal
Definition: Tools.h:283
uint32_t ulVal
Definition: Tools.h:289
bool blVal
Definition: Tools.h:291
union Tools::Variant::@0 m_val
int32_t lVal
Definition: Tools.h:282
double dblVal
Definition: Tools.h:286
VariantType m_varType
Definition: Tools.h:277
SIDX_DLL ISpatialIndex * loadRTree(IStorageManager &in, id_type indexIdentifier)
Definition: RTree.cc:346
SIDX_DLL ISpatialIndex * createAndBulkLoadNewRTree(BulkLoadMethod m, IDataStream &stream, IStorageManager &sm, double fillFactor, uint32_t indexCapacity, uint32_t leafCapacity, uint32_t dimension, RTreeVariant rv, id_type &indexIdentifier)
Definition: RTree.cc:190
Tools::PoolPointer< Node > NodePtr
Definition: rtree/Node.h:40
SIDX_DLL ISpatialIndex * returnRTree(IStorageManager &ind, Tools::PropertySet &in)
Definition: RTree.cc:143
SIDX_DLL ISpatialIndex * createNewRTree(IStorageManager &sm, double fillFactor, uint32_t indexCapacity, uint32_t leafCapacity, uint32_t dimension, RTreeVariant rv, id_type &indexIdentifier)
Definition: RTree.cc:149
std::ostream & operator<<(std::ostream &os, const RTree &t)
Definition: RTree.cc:1549
int64_t id_type
Definition: SpatialIndex.h:41
@ VT_BOOL
Definition: Tools.h:100
@ VT_EMPTY
Definition: Tools.h:103
@ VT_LONGLONG
Definition: Tools.h:104
@ VT_LONG
Definition: Tools.h:90
@ VT_DOUBLE
Definition: Tools.h:94
@ VT_ULONG
Definition: Tools.h:97