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 +
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 
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.0);
231  uint32_t indexCapacity(0);
232  uint32_t leafCapacity(0);
233  uint32_t dimension(0);
234  uint32_t pageSize(0);
235  uint32_t numberOfPages(0);
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 
566 {
567  if (query.getDimension() != m_dimension) throw Tools::IllegalArgumentException("nearestNeighborQuery: Shape has the wrong number of dimensions.");
568 
569  auto ascending = [](const NNEntry* lhs, const NNEntry* rhs) { return lhs->m_minDist > rhs->m_minDist; };
570  std::priority_queue<NNEntry*, std::vector<NNEntry*>, decltype(ascending)> queue(ascending);
571 
572  queue.push(new NNEntry(m_rootID, nullptr, 0.0));
573 
574  uint32_t count = 0;
575  double knearest = 0.0;
576 
577  while (! queue.empty())
578  {
579  NNEntry* pFirst = queue.top();
580 
581  // report all nearest neighbors with equal greatest distances.
582  // (neighbors can be more than k, if many happen to have the same greatest distance).
583  if (count >= k && pFirst->m_minDist > knearest) break;
584 
585  queue.pop();
586 
587  if (pFirst->m_pEntry == nullptr)
588  {
589  // n is a leaf or an index.
590  NodePtr n = readNode(pFirst->m_id);
591  v.visitNode(*n);
592 
593  for (uint32_t cChild = 0; cChild < n->m_children; ++cChild)
594  {
595  if (n->m_level == 0)
596  {
597  Data* e = new Data(n->m_pDataLength[cChild], n->m_pData[cChild], *(n->m_ptrMBR[cChild]), n->m_pIdentifier[cChild]);
598  // we need to compare the query with the actual data entry here, so we call the
599  // appropriate getMinimumDistance method of NearestNeighborComparator.
600  queue.push(new NNEntry(n->m_pIdentifier[cChild], e, nnc.getMinimumDistance(query, *e)));
601  }
602  else
603  {
604  queue.push(new NNEntry(n->m_pIdentifier[cChild], nullptr, nnc.getMinimumDistance(query, *(n->m_ptrMBR[cChild]))));
605  }
606  }
607  }
608  else
609  {
610  v.visitData(*(static_cast<IData*>(pFirst->m_pEntry)));
611  ++(m_stats.m_u64QueryResults);
612  ++count;
613  knearest = pFirst->m_minDist;
614  delete pFirst->m_pEntry;
615  }
616 
617  delete pFirst;
618  }
619 
620  while (! queue.empty())
621  {
622  NNEntry* e = queue.top(); queue.pop();
623  if (e->m_pEntry != nullptr) delete e->m_pEntry;
624  delete e;
625  }
626 }
627 
629 {
630  if (query.getDimension() != m_dimension) throw Tools::IllegalArgumentException("nearestNeighborQuery: Shape has the wrong number of dimensions.");
631  NNComparator nnc;
632  nearestNeighborQuery(k, query, v, nnc);
633 }
634 
635 
637 {
638  if (query.getDimension() != m_dimension)
639  throw Tools::IllegalArgumentException("selfJoinQuery: Shape has the wrong number of dimensions.");
640 
641  RegionPtr mbr = m_regionPool.acquire();
642  query.getMBR(*mbr);
643  selfJoinQuery(m_rootID, m_rootID, *mbr, v);
644 }
645 
647 {
648  id_type next = m_rootID;
649  bool hasNext = true;
650 
651  while (hasNext)
652  {
653  NodePtr n = readNode(next);
654  qs.getNextEntry(*n, next, hasNext);
655  }
656 }
657 
659 {
660  Tools::Variant var;
661 
662  // dimension
664  var.m_val.ulVal = m_dimension;
665  out.setProperty("Dimension", var);
666 
667  // index capacity
669  var.m_val.ulVal = m_indexCapacity;
670  out.setProperty("IndexCapacity", var);
671 
672  // leaf capacity
674  var.m_val.ulVal = m_leafCapacity;
675  out.setProperty("LeafCapacity", var);
676 
677  // R-tree variant
679  var.m_val.lVal = m_treeVariant;
680  out.setProperty("TreeVariant", var);
681 
682  // fill factor
684  var.m_val.dblVal = m_fillFactor;
685  out.setProperty("FillFactor", var);
686 
687  // near minimum overlap factor
689  var.m_val.ulVal = m_nearMinimumOverlapFactor;
690  out.setProperty("NearMinimumOverlapFactor", var);
691 
692  // split distribution factor
694  var.m_val.dblVal = m_splitDistributionFactor;
695  out.setProperty("SplitDistributionFactor", var);
696 
697  // reinsert factor
699  var.m_val.dblVal = m_reinsertFactor;
700  out.setProperty("ReinsertFactor", var);
701 
702  // tight MBRs
704  var.m_val.blVal = m_bTightMBRs;
705  out.setProperty("EnsureTightMBRs", var);
706 
707  // index pool capacity
709  var.m_val.ulVal = m_indexPool.getCapacity();
710  out.setProperty("IndexPoolCapacity", var);
711 
712  // leaf pool capacity
714  var.m_val.ulVal = m_leafPool.getCapacity();
715  out.setProperty("LeafPoolCapacity", var);
716 
717  // region pool capacity
719  var.m_val.ulVal = m_regionPool.getCapacity();
720  out.setProperty("RegionPoolCapacity", var);
721 
722  // point pool capacity
724  var.m_val.ulVal = m_pointPool.getCapacity();
725  out.setProperty("PointPoolCapacity", var);
726 
728  var.m_val.llVal = m_headerID;
729  out.setProperty("IndexIdentifier", var);
730 
731 }
732 
734 {
735  switch (ct)
736  {
737  case CT_NODEREAD:
738  m_readNodeCommands.push_back(std::shared_ptr<ICommand>(pCommand));
739  break;
740  case CT_NODEWRITE:
741  m_writeNodeCommands.push_back(std::shared_ptr<ICommand>(pCommand));
742  break;
743  case CT_NODEDELETE:
744  m_deleteNodeCommands.push_back(std::shared_ptr<ICommand>(pCommand));
745  break;
746  }
747 }
748 
750 {
751  bool ret = true;
752  std::stack<ValidateEntry> st;
753  NodePtr root = readNode(m_rootID);
754 
755  if (root->m_level != m_stats.m_u32TreeHeight - 1)
756  {
757  std::cerr << "Invalid tree height." << std::endl;
758  return false;
759  }
760 
761  std::map<uint32_t, uint32_t> nodesInLevel;
762  nodesInLevel.insert(std::pair<uint32_t, uint32_t>(root->m_level, 1));
763 
764  ValidateEntry e(root->m_nodeMBR, root);
765  st.push(e);
766 
767  while (! st.empty())
768  {
769  e = st.top(); st.pop();
770 
771  Region tmpRegion;
772  tmpRegion = m_infiniteRegion;
773 
774  for (uint32_t cDim = 0; cDim < tmpRegion.m_dimension; ++cDim)
775  {
776  tmpRegion.m_pLow[cDim] = std::numeric_limits<double>::max();
777  tmpRegion.m_pHigh[cDim] = -std::numeric_limits<double>::max();
778 
779  for (uint32_t cChild = 0; cChild < e.m_pNode->m_children; ++cChild)
780  {
781  tmpRegion.m_pLow[cDim] = std::min(tmpRegion.m_pLow[cDim], e.m_pNode->m_ptrMBR[cChild]->m_pLow[cDim]);
782  tmpRegion.m_pHigh[cDim] = std::max(tmpRegion.m_pHigh[cDim], e.m_pNode->m_ptrMBR[cChild]->m_pHigh[cDim]);
783  }
784  }
785 
786  if (! (tmpRegion == e.m_pNode->m_nodeMBR))
787  {
788  std::cerr << "Invalid parent information." << std::endl;
789  ret = false;
790  }
791  else if (! (tmpRegion == e.m_parentMBR))
792  {
793  std::cerr << "Error in parent." << std::endl;
794  ret = false;
795  }
796 
797  if (e.m_pNode->m_level != 0)
798  {
799  for (uint32_t cChild = 0; cChild < e.m_pNode->m_children; ++cChild)
800  {
801  NodePtr ptrN = readNode(e.m_pNode->m_pIdentifier[cChild]);
802  ValidateEntry tmpEntry(*(e.m_pNode->m_ptrMBR[cChild]), ptrN);
803 
804  std::map<uint32_t, uint32_t>::iterator itNodes = nodesInLevel.find(tmpEntry.m_pNode->m_level);
805 
806  if (itNodes == nodesInLevel.end())
807  {
808  nodesInLevel.insert(std::pair<uint32_t, uint32_t>(tmpEntry.m_pNode->m_level, 1l));
809  }
810  else
811  {
812  nodesInLevel[tmpEntry.m_pNode->m_level] = nodesInLevel[tmpEntry.m_pNode->m_level] + 1;
813  }
814 
815  st.push(tmpEntry);
816  }
817  }
818  }
819 
820  uint32_t nodes = 0;
821  for (uint32_t cLevel = 0; cLevel < m_stats.m_u32TreeHeight; ++cLevel)
822  {
823  if (nodesInLevel[cLevel] != m_stats.m_nodesInLevel[cLevel])
824  {
825  std::cerr << "Invalid nodesInLevel information." << std::endl;
826  ret = false;
827  }
828 
829  nodes += m_stats.m_nodesInLevel[cLevel];
830  }
831 
832  if (nodes != m_stats.m_u32Nodes)
833  {
834  std::cerr << "Invalid number of nodes information." << std::endl;
835  ret = false;
836  }
837 
838  return ret;
839 }
840 
842 {
843  *out = new Statistics(m_stats);
844 }
845 
847 {
848  storeHeader();
849 }
850 
851 void SpatialIndex::RTree::RTree::initNew(Tools::PropertySet& ps)
852 {
853  Tools::Variant var;
854 
855  // tree variant
856  var = ps.getProperty("TreeVariant");
857  if (var.m_varType != Tools::VT_EMPTY)
858  {
859  if (
860  var.m_varType != Tools::VT_LONG ||
861  (var.m_val.lVal != RV_LINEAR &&
862  var.m_val.lVal != RV_QUADRATIC &&
863  var.m_val.lVal != RV_RSTAR))
864  throw Tools::IllegalArgumentException("initNew: Property TreeVariant must be Tools::VT_LONG and of RTreeVariant type");
865 
866  m_treeVariant = static_cast<RTreeVariant>(var.m_val.lVal);
867  }
868 
869  // fill factor
870  // it cannot be larger than 50%, since linear and quadratic split algorithms
871  // require assigning to both nodes the same number of entries.
872  var = ps.getProperty("FillFactor");
873  if (var.m_varType != Tools::VT_EMPTY)
874  {
875  if (var.m_varType != Tools::VT_DOUBLE)
876  throw Tools::IllegalArgumentException("initNew: Property FillFactor was not of type Tools::VT_DOUBLE");
877 
878  if (var.m_val.dblVal <= 0.0)
879  throw Tools::IllegalArgumentException("initNew: Property FillFactor was less than 0.0");
880 
881  if (((m_treeVariant == RV_LINEAR || m_treeVariant == RV_QUADRATIC) && var.m_val.dblVal > 0.5))
882  throw Tools::IllegalArgumentException( "initNew: Property FillFactor must be in range "
883  "(0.0, 0.5) for LINEAR or QUADRATIC index types");
884  if ( var.m_val.dblVal >= 1.0)
885  throw Tools::IllegalArgumentException( "initNew: Property FillFactor must be in range "
886  "(0.0, 1.0) for RSTAR index type");
887  m_fillFactor = var.m_val.dblVal;
888  }
889 
890  // index capacity
891  var = ps.getProperty("IndexCapacity");
892  if (var.m_varType != Tools::VT_EMPTY)
893  {
894  if (var.m_varType != Tools::VT_ULONG || var.m_val.ulVal < 4)
895  throw Tools::IllegalArgumentException("initNew: Property IndexCapacity must be Tools::VT_ULONG and >= 4");
896 
897  m_indexCapacity = var.m_val.ulVal;
898  }
899 
900  // leaf capacity
901  var = ps.getProperty("LeafCapacity");
902  if (var.m_varType != Tools::VT_EMPTY)
903  {
904  if (var.m_varType != Tools::VT_ULONG || var.m_val.ulVal < 4)
905  throw Tools::IllegalArgumentException("initNew: Property LeafCapacity must be Tools::VT_ULONG and >= 4");
906 
907  m_leafCapacity = var.m_val.ulVal;
908  }
909 
910  // near minimum overlap factor
911  var = ps.getProperty("NearMinimumOverlapFactor");
912  if (var.m_varType != Tools::VT_EMPTY)
913  {
914  if (
915  var.m_varType != Tools::VT_ULONG ||
916  var.m_val.ulVal < 1 ||
917  var.m_val.ulVal > m_indexCapacity ||
918  var.m_val.ulVal > m_leafCapacity)
919  throw Tools::IllegalArgumentException("initNew: Property NearMinimumOverlapFactor must be Tools::VT_ULONG and less than both index and leaf capacities");
920 
921  m_nearMinimumOverlapFactor = var.m_val.ulVal;
922  }
923 
924  // split distribution factor
925  var = ps.getProperty("SplitDistributionFactor");
926  if (var.m_varType != Tools::VT_EMPTY)
927  {
928  if (
929  var.m_varType != Tools::VT_DOUBLE ||
930  var.m_val.dblVal <= 0.0 ||
931  var.m_val.dblVal >= 1.0)
932  throw Tools::IllegalArgumentException("initNew: Property SplitDistributionFactor must be Tools::VT_DOUBLE and in (0.0, 1.0)");
933 
934  m_splitDistributionFactor = var.m_val.dblVal;
935  }
936 
937  // reinsert factor
938  var = ps.getProperty("ReinsertFactor");
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 ReinsertFactor must be Tools::VT_DOUBLE and in (0.0, 1.0)");
946 
947  m_reinsertFactor = var.m_val.dblVal;
948  }
949 
950  // dimension
951  var = ps.getProperty("Dimension");
952  if (var.m_varType != Tools::VT_EMPTY)
953  {
954  if (var.m_varType != Tools::VT_ULONG)
955  throw Tools::IllegalArgumentException("initNew: Property Dimension must be Tools::VT_ULONG");
956  if (var.m_val.ulVal <= 1)
957  throw Tools::IllegalArgumentException("initNew: Property Dimension must be greater than 1");
958 
959  m_dimension = var.m_val.ulVal;
960  }
961 
962  // tight MBRs
963  var = ps.getProperty("EnsureTightMBRs");
964  if (var.m_varType != Tools::VT_EMPTY)
965  {
966  if (var.m_varType != Tools::VT_BOOL)
967  throw Tools::IllegalArgumentException("initNew: Property EnsureTightMBRs must be Tools::VT_BOOL");
968 
969  m_bTightMBRs = var.m_val.blVal;
970  }
971 
972  // index pool capacity
973  var = ps.getProperty("IndexPoolCapacity");
974  if (var.m_varType != Tools::VT_EMPTY)
975  {
976  if (var.m_varType != Tools::VT_ULONG)
977  throw Tools::IllegalArgumentException("initNew: Property IndexPoolCapacity must be Tools::VT_ULONG");
978 
979  m_indexPool.setCapacity(var.m_val.ulVal);
980  }
981 
982  // leaf pool capacity
983  var = ps.getProperty("LeafPoolCapacity");
984  if (var.m_varType != Tools::VT_EMPTY)
985  {
986  if (var.m_varType != Tools::VT_ULONG)
987  throw Tools::IllegalArgumentException("initNew: Property LeafPoolCapacity must be Tools::VT_ULONG");
988 
989  m_leafPool.setCapacity(var.m_val.ulVal);
990  }
991 
992  // region pool capacity
993  var = ps.getProperty("RegionPoolCapacity");
994  if (var.m_varType != Tools::VT_EMPTY)
995  {
996  if (var.m_varType != Tools::VT_ULONG)
997  throw Tools::IllegalArgumentException("initNew: Property RegionPoolCapacity must be Tools::VT_ULONG");
998 
999  m_regionPool.setCapacity(var.m_val.ulVal);
1000  }
1001 
1002  // point pool capacity
1003  var = ps.getProperty("PointPoolCapacity");
1004  if (var.m_varType != Tools::VT_EMPTY)
1005  {
1006  if (var.m_varType != Tools::VT_ULONG)
1007  throw Tools::IllegalArgumentException("initNew: Property PointPoolCapacity must be Tools::VT_ULONG");
1008 
1009  m_pointPool.setCapacity(var.m_val.ulVal);
1010  }
1011 
1012  m_infiniteRegion.makeInfinite(m_dimension);
1013 
1014  m_stats.m_u32TreeHeight = 1;
1015  m_stats.m_nodesInLevel.push_back(0);
1016 
1017  Leaf root(this, -1);
1018  m_rootID = writeNode(&root);
1019 
1020  storeHeader();
1021 }
1022 
1023 void SpatialIndex::RTree::RTree::initOld(Tools::PropertySet& ps)
1024 {
1025  loadHeader();
1026 
1027  // only some of the properties may be changed.
1028  // the rest are just ignored.
1029 
1030  Tools::Variant var;
1031 
1032  // tree variant
1033  var = ps.getProperty("TreeVariant");
1034  if (var.m_varType != Tools::VT_EMPTY)
1035  {
1036  if (
1037  var.m_varType != Tools::VT_LONG ||
1038  (var.m_val.lVal != RV_LINEAR &&
1039  var.m_val.lVal != RV_QUADRATIC &&
1040  var.m_val.lVal != RV_RSTAR))
1041  throw Tools::IllegalArgumentException("initOld: Property TreeVariant must be Tools::VT_LONG and of RTreeVariant type");
1042 
1043  m_treeVariant = static_cast<RTreeVariant>(var.m_val.lVal);
1044  }
1045 
1046  // near minimum overlap factor
1047  var = ps.getProperty("NearMinimumOverlapFactor");
1048  if (var.m_varType != Tools::VT_EMPTY)
1049  {
1050  if (
1051  var.m_varType != Tools::VT_ULONG ||
1052  var.m_val.ulVal < 1 ||
1053  var.m_val.ulVal > m_indexCapacity ||
1054  var.m_val.ulVal > m_leafCapacity)
1055  throw Tools::IllegalArgumentException("initOld: Property NearMinimumOverlapFactor must be Tools::VT_ULONG and less than both index and leaf capacities");
1056 
1057  m_nearMinimumOverlapFactor = var.m_val.ulVal;
1058  }
1059 
1060  // split distribution factor
1061  var = ps.getProperty("SplitDistributionFactor");
1062  if (var.m_varType != Tools::VT_EMPTY)
1063  {
1064  if (var.m_varType != Tools::VT_DOUBLE || var.m_val.dblVal <= 0.0 || var.m_val.dblVal >= 1.0)
1065  throw Tools::IllegalArgumentException("initOld: Property SplitDistributionFactor must be Tools::VT_DOUBLE and in (0.0, 1.0)");
1066 
1067  m_splitDistributionFactor = var.m_val.dblVal;
1068  }
1069 
1070  // reinsert factor
1071  var = ps.getProperty("ReinsertFactor");
1072  if (var.m_varType != Tools::VT_EMPTY)
1073  {
1074  if (var.m_varType != Tools::VT_DOUBLE || var.m_val.dblVal <= 0.0 || var.m_val.dblVal >= 1.0)
1075  throw Tools::IllegalArgumentException("initOld: Property ReinsertFactor must be Tools::VT_DOUBLE and in (0.0, 1.0)");
1076 
1077  m_reinsertFactor = var.m_val.dblVal;
1078  }
1079 
1080  // tight MBRs
1081  var = ps.getProperty("EnsureTightMBRs");
1082  if (var.m_varType != Tools::VT_EMPTY)
1083  {
1084  if (var.m_varType != Tools::VT_BOOL) throw Tools::IllegalArgumentException("initOld: Property EnsureTightMBRs must be Tools::VT_BOOL");
1085 
1086  m_bTightMBRs = var.m_val.blVal;
1087  }
1088 
1089  // index pool capacity
1090  var = ps.getProperty("IndexPoolCapacity");
1091  if (var.m_varType != Tools::VT_EMPTY)
1092  {
1093  if (var.m_varType != Tools::VT_ULONG) throw Tools::IllegalArgumentException("initOld: Property IndexPoolCapacity must be Tools::VT_ULONG");
1094 
1095  m_indexPool.setCapacity(var.m_val.ulVal);
1096  }
1097 
1098  // leaf pool capacity
1099  var = ps.getProperty("LeafPoolCapacity");
1100  if (var.m_varType != Tools::VT_EMPTY)
1101  {
1102  if (var.m_varType != Tools::VT_ULONG) throw Tools::IllegalArgumentException("initOld: Property LeafPoolCapacity must be Tools::VT_ULONG");
1103 
1104  m_leafPool.setCapacity(var.m_val.ulVal);
1105  }
1106 
1107  // region pool capacity
1108  var = ps.getProperty("RegionPoolCapacity");
1109  if (var.m_varType != Tools::VT_EMPTY)
1110  {
1111  if (var.m_varType != Tools::VT_ULONG) throw Tools::IllegalArgumentException("initOld: Property RegionPoolCapacity must be Tools::VT_ULONG");
1112 
1113  m_regionPool.setCapacity(var.m_val.ulVal);
1114  }
1115 
1116  // point pool capacity
1117  var = ps.getProperty("PointPoolCapacity");
1118  if (var.m_varType != Tools::VT_EMPTY)
1119  {
1120  if (var.m_varType != Tools::VT_ULONG) throw Tools::IllegalArgumentException("initOld: Property PointPoolCapacity must be Tools::VT_ULONG");
1121 
1122  m_pointPool.setCapacity(var.m_val.ulVal);
1123  }
1124 
1125  m_infiniteRegion.makeInfinite(m_dimension);
1126 }
1127 
1128 void SpatialIndex::RTree::RTree::storeHeader()
1129 {
1130  const uint32_t headerSize =
1131  sizeof(id_type) + // m_rootID
1132  sizeof(RTreeVariant) + // m_treeVariant
1133  sizeof(double) + // m_fillFactor
1134  sizeof(uint32_t) + // m_indexCapacity
1135  sizeof(uint32_t) + // m_leafCapacity
1136  sizeof(uint32_t) + // m_nearMinimumOverlapFactor
1137  sizeof(double) + // m_splitDistributionFactor
1138  sizeof(double) + // m_reinsertFactor
1139  sizeof(uint32_t) + // m_dimension
1140  sizeof(char) + // m_bTightMBRs
1141  sizeof(uint32_t) + // m_stats.m_nodes
1142  sizeof(uint64_t) + // m_stats.m_data
1143  sizeof(uint32_t) + // m_stats.m_treeHeight
1144  m_stats.m_u32TreeHeight * sizeof(uint32_t); // m_stats.m_nodesInLevel
1145 
1146  uint8_t* header = new uint8_t[headerSize];
1147  uint8_t* ptr = header;
1148 
1149  memcpy(ptr, &m_rootID, sizeof(id_type));
1150  ptr += sizeof(id_type);
1151  memcpy(ptr, &m_treeVariant, sizeof(RTreeVariant));
1152  ptr += sizeof(RTreeVariant);
1153  memcpy(ptr, &m_fillFactor, sizeof(double));
1154  ptr += sizeof(double);
1155  memcpy(ptr, &m_indexCapacity, sizeof(uint32_t));
1156  ptr += sizeof(uint32_t);
1157  memcpy(ptr, &m_leafCapacity, sizeof(uint32_t));
1158  ptr += sizeof(uint32_t);
1159  memcpy(ptr, &m_nearMinimumOverlapFactor, sizeof(uint32_t));
1160  ptr += sizeof(uint32_t);
1161  memcpy(ptr, &m_splitDistributionFactor, sizeof(double));
1162  ptr += sizeof(double);
1163  memcpy(ptr, &m_reinsertFactor, sizeof(double));
1164  ptr += sizeof(double);
1165  memcpy(ptr, &m_dimension, sizeof(uint32_t));
1166  ptr += sizeof(uint32_t);
1167  char c = (char) m_bTightMBRs;
1168  memcpy(ptr, &c, sizeof(char));
1169  ptr += sizeof(char);
1170  memcpy(ptr, &(m_stats.m_u32Nodes), sizeof(uint32_t));
1171  ptr += sizeof(uint32_t);
1172  memcpy(ptr, &(m_stats.m_u64Data), sizeof(uint64_t));
1173  ptr += sizeof(uint64_t);
1174  memcpy(ptr, &(m_stats.m_u32TreeHeight), sizeof(uint32_t));
1175  ptr += sizeof(uint32_t);
1176 
1177  for (uint32_t cLevel = 0; cLevel < m_stats.m_u32TreeHeight; ++cLevel)
1178  {
1179  memcpy(ptr, &(m_stats.m_nodesInLevel[cLevel]), sizeof(uint32_t));
1180  ptr += sizeof(uint32_t);
1181  }
1182 
1183  m_pStorageManager->storeByteArray(m_headerID, headerSize, header);
1184 
1185  delete[] header;
1186 }
1187 
1188 void SpatialIndex::RTree::RTree::loadHeader()
1189 {
1190  uint32_t headerSize;
1191  uint8_t* header = nullptr;
1192  m_pStorageManager->loadByteArray(m_headerID, headerSize, &header);
1193 
1194  uint8_t* ptr = header;
1195 
1196  memcpy(&m_rootID, ptr, sizeof(id_type));
1197  ptr += sizeof(id_type);
1198  memcpy(&m_treeVariant, ptr, sizeof(RTreeVariant));
1199  ptr += sizeof(RTreeVariant);
1200  memcpy(&m_fillFactor, ptr, sizeof(double));
1201  ptr += sizeof(double);
1202  memcpy(&m_indexCapacity, ptr, sizeof(uint32_t));
1203  ptr += sizeof(uint32_t);
1204  memcpy(&m_leafCapacity, ptr, sizeof(uint32_t));
1205  ptr += sizeof(uint32_t);
1206  memcpy(&m_nearMinimumOverlapFactor, ptr, sizeof(uint32_t));
1207  ptr += sizeof(uint32_t);
1208  memcpy(&m_splitDistributionFactor, ptr, sizeof(double));
1209  ptr += sizeof(double);
1210  memcpy(&m_reinsertFactor, ptr, sizeof(double));
1211  ptr += sizeof(double);
1212  memcpy(&m_dimension, ptr, sizeof(uint32_t));
1213  ptr += sizeof(uint32_t);
1214  char c;
1215  memcpy(&c, ptr, sizeof(char));
1216  m_bTightMBRs = (c != 0);
1217  ptr += sizeof(char);
1218  memcpy(&(m_stats.m_u32Nodes), ptr, sizeof(uint32_t));
1219  ptr += sizeof(uint32_t);
1220  memcpy(&(m_stats.m_u64Data), ptr, sizeof(uint64_t));
1221  ptr += sizeof(uint64_t);
1222  memcpy(&(m_stats.m_u32TreeHeight), ptr, sizeof(uint32_t));
1223  ptr += sizeof(uint32_t);
1224 
1225  for (uint32_t cLevel = 0; cLevel < m_stats.m_u32TreeHeight; ++cLevel)
1226  {
1227  uint32_t cNodes;
1228  memcpy(&cNodes, ptr, sizeof(uint32_t));
1229  ptr += sizeof(uint32_t);
1230  m_stats.m_nodesInLevel.push_back(cNodes);
1231  }
1232 
1233  delete[] header;
1234 }
1235 
1236 void SpatialIndex::RTree::RTree::insertData_impl(uint32_t dataLength, uint8_t* pData, Region& mbr, id_type id)
1237 {
1238  assert(mbr.getDimension() == m_dimension);
1239 
1240  std::stack<id_type> pathBuffer;
1241  uint8_t* overflowTable = nullptr;
1242 
1243  try
1244  {
1245  NodePtr root = readNode(m_rootID);
1246 
1247  overflowTable = new uint8_t[root->m_level];
1248  memset(overflowTable, 0, root->m_level);
1249 
1250  NodePtr l = root->chooseSubtree(mbr, 0, pathBuffer);
1251  if (l.get() == root.get())
1252  {
1253  assert(root.unique());
1254  root.relinquish();
1255  }
1256  l->insertData(dataLength, pData, mbr, id, pathBuffer, overflowTable);
1257 
1258  delete[] overflowTable;
1259  ++(m_stats.m_u64Data);
1260  }
1261  catch (...)
1262  {
1263  delete[] overflowTable;
1264  throw;
1265  }
1266 }
1267 
1268 void SpatialIndex::RTree::RTree::insertData_impl(uint32_t dataLength, uint8_t* pData, Region& mbr, id_type id, uint32_t level, uint8_t* overflowTable)
1269 {
1270  assert(mbr.getDimension() == m_dimension);
1271 
1272  std::stack<id_type> pathBuffer;
1273  NodePtr root = readNode(m_rootID);
1274  NodePtr n = root->chooseSubtree(mbr, level, pathBuffer);
1275 
1276  assert(n->m_level == level);
1277 
1278  if (n.get() == root.get())
1279  {
1280  assert(root.unique());
1281  root.relinquish();
1282  }
1283  n->insertData(dataLength, pData, mbr, id, pathBuffer, overflowTable);
1284 }
1285 
1286 bool SpatialIndex::RTree::RTree::deleteData_impl(const Region& mbr, id_type id)
1287 {
1288  assert(mbr.m_dimension == m_dimension);
1289 
1290  std::stack<id_type> pathBuffer;
1291  NodePtr root = readNode(m_rootID);
1292  NodePtr l = root->findLeaf(mbr, id, pathBuffer);
1293  if (l.get() == root.get())
1294  {
1295  assert(root.unique());
1296  root.relinquish();
1297  }
1298 
1299  if (l.get() != nullptr)
1300  {
1301  Leaf* pL = static_cast<Leaf*>(l.get());
1302  pL->deleteData(mbr, id, pathBuffer);
1303  --(m_stats.m_u64Data);
1304  return true;
1305  }
1306 
1307  return false;
1308 }
1309 
1310 SpatialIndex::id_type SpatialIndex::RTree::RTree::writeNode(Node* n)
1311 {
1312  uint8_t* buffer;
1313  uint32_t dataLength;
1314  n->storeToByteArray(&buffer, dataLength);
1315 
1316  id_type page;
1317  if (n->m_identifier < 0) page = StorageManager::NewPage;
1318  else page = n->m_identifier;
1319 
1320  try
1321  {
1322  m_pStorageManager->storeByteArray(page, dataLength, buffer);
1323  delete[] buffer;
1324  }
1325  catch (InvalidPageException& e)
1326  {
1327  delete[] buffer;
1328  std::cerr << e.what() << std::endl;
1329  throw;
1330  }
1331 
1332  if (n->m_identifier < 0)
1333  {
1334  n->m_identifier = page;
1335  ++(m_stats.m_u32Nodes);
1336 
1337 #ifndef NDEBUG
1338  try
1339  {
1340  m_stats.m_nodesInLevel[n->m_level] = m_stats.m_nodesInLevel.at(n->m_level) + 1;
1341  }
1342  catch(...)
1343  {
1344  throw Tools::IllegalStateException("writeNode: writing past the end of m_nodesInLevel.");
1345  }
1346 #else
1347  m_stats.m_nodesInLevel[n->m_level] = m_stats.m_nodesInLevel[n->m_level] + 1;
1348 #endif
1349  }
1350 
1351  ++(m_stats.m_u64Writes);
1352 
1353  for (size_t cIndex = 0; cIndex < m_writeNodeCommands.size(); ++cIndex)
1354  {
1355  m_writeNodeCommands[cIndex]->execute(*n);
1356  }
1357 
1358  return page;
1359 }
1360 
1361 SpatialIndex::RTree::NodePtr SpatialIndex::RTree::RTree::readNode(id_type page)
1362 {
1363  uint32_t dataLength;
1364  uint8_t* buffer;
1365 
1366  try
1367  {
1368  m_pStorageManager->loadByteArray(page, dataLength, &buffer);
1369  }
1370  catch (InvalidPageException& e)
1371  {
1372  std::cerr << e.what() << std::endl;
1373  throw;
1374  }
1375 
1376  try
1377  {
1378  uint32_t nodeType;
1379  memcpy(&nodeType, buffer, sizeof(uint32_t));
1380 
1381  NodePtr n;
1382 
1383  if (nodeType == PersistentIndex) n = m_indexPool.acquire();
1384  else if (nodeType == PersistentLeaf) n = m_leafPool.acquire();
1385  else throw Tools::IllegalStateException("readNode: failed reading the correct node type information");
1386 
1387  if (n.get() == nullptr)
1388  {
1389  if (nodeType == PersistentIndex) n = NodePtr(new Index(this, -1, 0), &m_indexPool);
1390  else if (nodeType == PersistentLeaf) n = NodePtr(new Leaf(this, -1), &m_leafPool);
1391  }
1392 
1393  //n->m_pTree = this;
1394  n->m_identifier = page;
1395  n->loadFromByteArray(buffer);
1396 
1397  ++(m_stats.m_u64Reads);
1398 
1399  for (size_t cIndex = 0; cIndex < m_readNodeCommands.size(); ++cIndex)
1400  {
1401  m_readNodeCommands[cIndex]->execute(*n);
1402  }
1403 
1404  delete[] buffer;
1405  return n;
1406  }
1407  catch (...)
1408  {
1409  delete[] buffer;
1410  throw;
1411  }
1412 }
1413 
1414 void SpatialIndex::RTree::RTree::deleteNode(Node* n)
1415 {
1416  try
1417  {
1418  m_pStorageManager->deleteByteArray(n->m_identifier);
1419  }
1420  catch (InvalidPageException& e)
1421  {
1422  std::cerr << e.what() << std::endl;
1423  throw;
1424  }
1425 
1426  --(m_stats.m_u32Nodes);
1427  m_stats.m_nodesInLevel[n->m_level] = m_stats.m_nodesInLevel[n->m_level] - 1;
1428 
1429  for (size_t cIndex = 0; cIndex < m_deleteNodeCommands.size(); ++cIndex)
1430  {
1431  m_deleteNodeCommands[cIndex]->execute(*n);
1432  }
1433 }
1434 
1435 void SpatialIndex::RTree::RTree::rangeQuery(RangeQueryType type, const IShape& query, IVisitor& v)
1436 {
1437  std::stack<NodePtr> st;
1438  NodePtr root = readNode(m_rootID);
1439 
1440  if (root->m_children > 0 && query.intersectsShape(root->m_nodeMBR)) st.push(root);
1441 
1442  while (! st.empty())
1443  {
1444  NodePtr n = st.top(); st.pop();
1445 
1446  if (n->m_level == 0)
1447  {
1448  v.visitNode(*n);
1449 
1450  for (uint32_t cChild = 0; cChild < n->m_children; ++cChild)
1451  {
1452  bool b;
1453  if (type == ContainmentQuery) b = query.containsShape(*(n->m_ptrMBR[cChild]));
1454  else b = query.intersectsShape(*(n->m_ptrMBR[cChild]));
1455 
1456  if (b)
1457  {
1458  Data data = Data(n->m_pDataLength[cChild], n->m_pData[cChild], *(n->m_ptrMBR[cChild]), n->m_pIdentifier[cChild]);
1459  v.visitData(data);
1460  ++(m_stats.m_u64QueryResults);
1461  }
1462  }
1463  }
1464  else
1465  {
1466  v.visitNode(*n);
1467 
1468  for (uint32_t cChild = 0; cChild < n->m_children; ++cChild)
1469  {
1470  if (query.intersectsShape(*(n->m_ptrMBR[cChild]))) st.push(readNode(n->m_pIdentifier[cChild]));
1471  }
1472  }
1473  }
1474 }
1475 
1477 {
1478  NodePtr n1 = readNode(id1);
1479  NodePtr n2 = readNode(id2);
1480  vis.visitNode(*n1);
1481  vis.visitNode(*n2);
1482 
1483  for (uint32_t cChild1 = 0; cChild1 < n1->m_children; ++cChild1)
1484  {
1485  if (r.intersectsRegion(*(n1->m_ptrMBR[cChild1])))
1486  {
1487  for (uint32_t cChild2 = 0; cChild2 < n2->m_children; ++cChild2)
1488  {
1489  if (
1490  r.intersectsRegion(*(n2->m_ptrMBR[cChild2])) &&
1491  n1->m_ptrMBR[cChild1]->intersectsRegion(*(n2->m_ptrMBR[cChild2])))
1492  {
1493  if (n1->m_level == 0)
1494  {
1495  if (n1->m_pIdentifier[cChild1] != n2->m_pIdentifier[cChild2])
1496  {
1497  assert(n2->m_level == 0);
1498 
1499  std::vector<const IData*> v;
1500  Data e1(n1->m_pDataLength[cChild1], n1->m_pData[cChild1], *(n1->m_ptrMBR[cChild1]), n1->m_pIdentifier[cChild1]);
1501  Data e2(n2->m_pDataLength[cChild2], n2->m_pData[cChild2], *(n2->m_ptrMBR[cChild2]), n2->m_pIdentifier[cChild2]);
1502  v.push_back(&e1);
1503  v.push_back(&e2);
1504  vis.visitData(v);
1505  }
1506  }
1507  else
1508  {
1509  Region rr = r.getIntersectingRegion(n1->m_ptrMBR[cChild1]->getIntersectingRegion(*(n2->m_ptrMBR[cChild2])));
1510  selfJoinQuery(n1->m_pIdentifier[cChild1], n2->m_pIdentifier[cChild2], rr, vis);
1511  }
1512  }
1513  }
1514  }
1515  }
1516 }
1517 
1518 void SpatialIndex::RTree::RTree::visitSubTree(NodePtr subTree, IVisitor& v)
1519 {
1520  std::stack<NodePtr> st;
1521  st.push(subTree);
1522 
1523  while (! st.empty())
1524  {
1525  NodePtr n = st.top(); st.pop();
1526  v.visitNode(*n);
1527 
1528  if(n->m_level == 0)
1529  {
1530  for (uint32_t cChild = 0; cChild < n->m_children; ++cChild)
1531  {
1532  Data data = Data(n->m_pDataLength[cChild], n->m_pData[cChild], *(n->m_ptrMBR[cChild]), n->m_pIdentifier[cChild]);
1533  v.visitData(data);
1534  ++(m_stats.m_u64QueryResults);
1535  }
1536  }
1537  else
1538  {
1539  for (uint32_t cChild = 0; cChild < n->m_children; ++cChild)
1540  {
1541  st.push(readNode(n->m_pIdentifier[cChild]));
1542  }
1543  }
1544  }
1545 }
1546 
1547 std::ostream& SpatialIndex::RTree::operator<<(std::ostream& os, const RTree& t)
1548 {
1549  os << "Dimension: " << t.m_dimension << std::endl
1550  << "Fill factor: " << t.m_fillFactor << std::endl
1551  << "Index capacity: " << t.m_indexCapacity << std::endl
1552  << "Leaf capacity: " << t.m_leafCapacity << std::endl
1553  << "Tight MBRs: " << ((t.m_bTightMBRs) ? "enabled" : "disabled") << std::endl;
1554 
1555  if (t.m_treeVariant == RV_RSTAR)
1556  {
1557  os << "Near minimum overlap factor: " << t.m_nearMinimumOverlapFactor << std::endl
1558  << "Reinsert factor: " << t.m_reinsertFactor << std::endl
1559  << "Split distribution factor: " << t.m_splitDistributionFactor << std::endl;
1560  }
1561 
1562  if (t.m_stats.getNumberOfNodesInLevel(0) > 0)
1563  os << "Utilization: " << 100 * t.m_stats.getNumberOfData() / (t.m_stats.getNumberOfNodesInLevel(0) * t.m_leafCapacity) << "%" << std::endl
1564  << t.m_stats;
1565 
1566  #ifndef NDEBUG
1567  os << "Leaf pool hits: " << t.m_leafPool.m_hits << std::endl
1568  << "Leaf pool misses: " << t.m_leafPool.m_misses << std::endl
1569  << "Index pool hits: " << t.m_indexPool.m_hits << std::endl
1570  << "Index pool misses: " << t.m_indexPool.m_misses << std::endl
1571  << "Region pool hits: " << t.m_regionPool.m_hits << std::endl
1572  << "Region pool misses: " << t.m_regionPool.m_misses << std::endl
1573  << "Point pool hits: " << t.m_pointPool.m_hits << std::endl
1574  << "Point pool misses: " << t.m_pointPool.m_misses << std::endl;
1575  #endif
1576 
1577  return os;
1578 }
std::vector< uint64_t > & GetResults()
Definition: IdVisitor.h:45
virtual void deleteByteArray(const id_type id)=0
VariantType m_varType
Definition: Tools.h:277
uint64_t GetResultCount() const
Definition: IdVisitor.h:44
SIDX_DLL ISpatialIndex * loadRTree(IStorageManager &in, id_type indexIdentifier)
Definition: RTree.cc:346
uint32_t ulVal
Definition: Tools.h:289
void setProperty(std::string property, Variant const &v)
Definition: Tools.cc:354
virtual void containsWhatQuery(const IShape &query, IVisitor &v)
Definition: RTree.cc:500
Data * clone() override
Definition: RTree.cc:58
void bulkLoadUsingSTR(RTree *pTree, IDataStream &stream, uint32_t bindex, uint32_t bleaf, uint32_t pageSize, uint32_t numberOfPages)
Definition: BulkLoader.cc:320
Data(uint32_t len, uint8_t *pData, Region &r, id_type id)
Definition: RTree.cc:43
void storeToByteArray(uint8_t **data, uint32_t &len) override
Definition: RTree.cc:115
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 getStatistics(IStatistics **out) const
Definition: RTree.cc:841
PoolPointer< X > acquire()
Definition: PointerPool.h:64
uint64_t getNumberOfData() const override
virtual void addCommand(ICommand *pCommand, CommandType ct)
Definition: RTree.cc:733
void loadFromByteArray(const uint8_t *data) override
Definition: rtree/Node.cc:63
uint32_t getByteArraySize() override
Definition: RTree.cc:85
void getShape(IShape **out) const override
Definition: RTree.cc:68
virtual void storeByteArray(id_type &id, const uint32_t len, const uint8_t *const data)=0
RTree(IStorageManager &, Tools::PropertySet &)
Definition: RTree.cc:358
virtual void getIndexProperties(Tools::PropertySet &out) const
Definition: RTree.cc:658
void getData(uint32_t &len, uint8_t **data) const override
Definition: RTree.cc:73
double * m_pLow
Definition: Region.h:98
virtual bool isIndexValid()
Definition: RTree.cc:749
virtual void pointLocationQuery(const Point &query, IVisitor &v)
Definition: RTree.cc:558
SIDX_DLL ISpatialIndex * returnRTree(IStorageManager &ind, Tools::PropertySet &in)
Definition: RTree.cc:143
std::ostream & operator<<(std::ostream &os, const RTree &t)
Definition: RTree.cc:1547
virtual void queryStrategy(IQueryStrategy &qs)
Definition: RTree.cc:646
uint32_t m_dimension
Definition: Point.h:77
virtual void loadByteArray(const id_type id, uint32_t &len, uint8_t **data)=0
virtual uint32_t getDimension() const =0
virtual bool intersectsRegion(const Region &in) const
Definition: Region.cc:264
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
union Tools::Variant::@0 m_val
virtual void visitNode(const INode &in)=0
int64_t llVal
Definition: Tools.h:283
virtual void nearestNeighborQuery(uint32_t k, const IShape &query, IVisitor &v, INearestNeighborComparator &)
Definition: RTree.cc:565
virtual bool intersectsShape(const IShape &in) const =0
virtual void internalNodesQuery(const IShape &query, IVisitor &v)
Definition: RTree.cc:436
uint32_t m_dimension
Definition: Region.h:97
double * m_pHigh
Definition: Region.h:99
bool unique() const noexcept
Definition: PoolPointer.h:56
virtual uint32_t getNumberOfNodesInLevel(uint32_t l) const
X * get() const noexcept
Definition: PoolPointer.h:55
virtual void visitData(const IData &in)=0
void storeToByteArray(uint8_t **data, uint32_t &length) override
Definition: Region.cc:161
virtual void makeInfinite(uint32_t dimension)
Definition: Region.cc:551
Tools::PoolPointer< Node > NodePtr
Definition: rtree/Node.h:40
id_type getIdentifier() const override
Definition: RTree.cc:63
uint32_t getDimension() const override
Definition: Region.cc:229
void setCapacity(uint32_t c)
Definition: PointerPool.h:105
virtual double getMinimumDistance(const IShape &query, const IShape &entry)=0
virtual void selfJoinQuery(const IShape &s, IVisitor &v)
Definition: RTree.cc:636
uint32_t getByteArraySize() override
Definition: Region.cc:143
void storeToByteArray(uint8_t **data, uint32_t &len) override
Definition: rtree/Node.cc:112
id_type getIdentifier() const override
Definition: rtree/Node.cc:164
int32_t lVal
Definition: Tools.h:282
virtual Region getIntersectingRegion(const Region &r) const
Definition: Region.cc:431
double dblVal
Definition: Tools.h:286
void loadFromByteArray(const uint8_t *data) override
Definition: RTree.cc:94
virtual bool deleteData(const IShape &shape, id_type id)
Definition: RTree.cc:424
virtual void getMBR(Region &out) const =0
uint32_t getCapacity() const
Definition: PointerPool.h:104
int64_t id_type
Definition: SpatialIndex.h:41
Variant getProperty(std::string property) const
Definition: Tools.cc:346
bool blVal
Definition: Tools.h:291
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
virtual void getNextEntry(const IEntry &previouslyFetched, id_type &nextEntryToFetch, bool &bFetchNextEntry)=0
virtual bool containsShape(const IShape &in) const =0
virtual void flush()
Definition: RTree.cc:846
void loadFromByteArray(const uint8_t *data) override
Definition: Region.cc:148
void relinquish() noexcept
Definition: PoolPointer.h:57
virtual void deleteData(const Region &mbr, id_type id, std::stack< id_type > &pathBuffer)
Definition: rtree/Leaf.cc:111