libspatialindex API Reference  (git-trunk)
MVRTree.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 <limits>
29 
31 
32 #include "Node.h"
33 #include "Leaf.h"
34 #include "Index.h"
35 #include "MVRTree.h"
36 
37 #include <cstring>
38 
39 using namespace SpatialIndex::MVRTree;
40 
41 SpatialIndex::MVRTree::Data::Data(uint32_t len, uint8_t* pData, TimeRegion& r, id_type id)
42  : m_id(id), m_region(r), m_pData(nullptr), m_dataLength(len)
43 {
44  if (m_dataLength > 0)
45  {
46  m_pData = new uint8_t[m_dataLength];
47  memcpy(m_pData, pData, m_dataLength);
48  }
49 }
50 
52 {
53  delete[] m_pData;
54 }
55 
57 {
58  return new Data(m_dataLength, m_pData, m_region, m_id);
59 }
60 
62 {
63  return m_id;
64 }
65 
67 {
68  *out = new TimeRegion(m_region);
69 }
70 
71 void SpatialIndex::MVRTree::Data::getData(uint32_t& len, uint8_t** data) const
72 {
73  len = m_dataLength;
74  *data = nullptr;
75 
76  if (m_dataLength > 0)
77  {
78  *data = new uint8_t[m_dataLength];
79  memcpy(*data, m_pData, m_dataLength);
80  }
81 }
82 
84 {
85  return
86  sizeof(id_type) +
87  sizeof(uint32_t) +
88  m_dataLength +
90 }
91 
93 {
94  memcpy(&m_id, ptr, sizeof(id_type));
95  ptr += sizeof(id_type);
96 
97  delete[] m_pData;
98  m_pData = nullptr;
99 
100  memcpy(&m_dataLength, ptr, sizeof(uint32_t));
101  ptr += sizeof(uint32_t);
102 
103  if (m_dataLength > 0)
104  {
105  m_pData = new uint8_t[m_dataLength];
106  memcpy(m_pData, ptr, m_dataLength);
107  ptr += m_dataLength;
108  }
109 
111 }
112 
113 void SpatialIndex::MVRTree::Data::storeToByteArray(uint8_t** data, uint32_t& len)
114 {
115  // it is thread safe this way.
116  uint32_t regionsize;
117  uint8_t* regiondata = nullptr;
118  m_region.storeToByteArray(&regiondata, regionsize);
119 
120  len = sizeof(id_type) + sizeof(uint32_t) + m_dataLength + regionsize;
121 
122  *data = new uint8_t[len];
123  uint8_t* ptr = *data;
124 
125  memcpy(ptr, &m_id, sizeof(id_type));
126  ptr += sizeof(id_type);
127  memcpy(ptr, &m_dataLength, sizeof(uint32_t));
128  ptr += sizeof(uint32_t);
129 
130  if (m_dataLength > 0)
131  {
132  memcpy(ptr, m_pData, m_dataLength);
133  ptr += m_dataLength;
134  }
135 
136  memcpy(ptr, regiondata, regionsize);
137  delete[] regiondata;
138  // ptr += regionsize;
139 }
140 
142 {
144  return si;
145 }
146 
149  double fillFactor,
150  uint32_t indexCapacity,
151  uint32_t leafCapacity,
152  uint32_t dimension,
153  MVRTreeVariant rv,
154  id_type& indexIdentifier)
155 {
156  Tools::Variant var;
158 
160  var.m_val.dblVal = fillFactor;
161  ps.setProperty("FillFactor", var);
162 
164  var.m_val.ulVal = indexCapacity;
165  ps.setProperty("IndexCapacity", var);
166 
168  var.m_val.ulVal = leafCapacity;
169  ps.setProperty("LeafCapacity", var);
170 
172  var.m_val.ulVal = dimension;
173  ps.setProperty("Dimension", var);
174 
176  var.m_val.lVal = rv;
177  ps.setProperty("TreeVariant", var);
178 
179  ISpatialIndex* ret = returnMVRTree(sm, ps);
180 
182  var = ps.getProperty("IndexIdentifier");
183  indexIdentifier = var.m_val.llVal;
184 
185  return ret;
186 }
187 
189 {
190  Tools::Variant var;
192 
194  var.m_val.llVal = indexIdentifier;
195  ps.setProperty("IndexIdentifier", var);
196 
197  return returnMVRTree(sm, ps);
198 }
199 
201  m_pStorageManager(&sm),
202  m_headerID(StorageManager::NewPage),
203  m_treeVariant(RV_RSTAR),
204  m_fillFactor(0.7),
205  m_indexCapacity(100),
206  m_leafCapacity(100),
207  m_nearMinimumOverlapFactor(32),
208  m_splitDistributionFactor(0.4),
209  m_reinsertFactor(0.3),
210  m_strongVersionOverflow(0.8),
211  //m_strongVersionUnderflow(0.2),
212  m_versionUnderflow(0.3),
213  m_dimension(2),
214  m_bTightMBRs(true),
215  m_bHasVersionCopied(false),
216  m_currentTime(0.0),
217  m_pointPool(500),
218  m_regionPool(1000),
219  m_indexPool(100),
220  m_leafPool(100)
221 {
222 
223  Tools::Variant var = ps.getProperty("IndexIdentifier");
224  if (var.m_varType != Tools::VT_EMPTY)
225  {
226  if (var.m_varType == Tools::VT_LONGLONG) m_headerID = var.m_val.llVal;
227  else if (var.m_varType == Tools::VT_LONG) m_headerID = var.m_val.lVal;
228  // for backward compatibility only.
229  else throw Tools::IllegalArgumentException("MVRTree: Property IndexIdentifier must be Tools::VT_LONGLONG");
230 
231  initOld(ps);
232  }
233  else
234  {
235  initNew(ps);
237  var.m_val.llVal = m_headerID;
238  ps.setProperty("IndexIdentifier", var);
239  }
240 }
241 
243 {
244  storeHeader();
245 }
246 
247 //
248 // ISpatialIndex interface
249 //
250 
251 void SpatialIndex::MVRTree::MVRTree::insertData(uint32_t len, const uint8_t* pData, const IShape& shape, id_type id)
252 {
253  if (shape.getDimension() != m_dimension) throw Tools::IllegalArgumentException("insertData: Shape has the wrong number of dimensions.");
254  const Tools::IInterval* ti = dynamic_cast<const Tools::IInterval*>(&shape);
255  if (ti == nullptr) throw Tools::IllegalArgumentException("insertData: Shape does not support the Tools::IInterval interface.");
256  if (ti->getLowerBound() < m_currentTime) throw Tools::IllegalArgumentException("insertData: Shape start time is older than tree current time.");
257 
258  // convert the shape into a TimeRegion (R-Trees index regions only; i.e., approximations of the shapes).
259  Region mbrold;
260  shape.getMBR(mbrold);
261 
262  TimeRegionPtr mbr = m_regionPool.acquire();
263  mbr->makeDimension(mbrold.m_dimension);
264 
265  memcpy(mbr->m_pLow, mbrold.m_pLow, mbrold.m_dimension * sizeof(double));
266  memcpy(mbr->m_pHigh, mbrold.m_pHigh, mbrold.m_dimension * sizeof(double));
267  mbr->m_startTime = ti->getLowerBound();
268  mbr->m_endTime = std::numeric_limits<double>::max();
269 
270  uint8_t* buffer = nullptr;
271 
272  if (len > 0)
273  {
274  buffer = new uint8_t[len];
275  memcpy(buffer, pData, len);
276  }
277 
278  insertData_impl(len, buffer, *mbr, id);
279  // the buffer is stored in the tree. Do not delete here.
280 }
281 
283 {
284  if (shape.getDimension() != m_dimension) throw Tools::IllegalArgumentException("deleteData: Shape has the wrong number of dimensions.");
285  const Tools::IInterval* ti = dynamic_cast<const Tools::IInterval*>(&shape);
286  if (ti == nullptr) throw Tools::IllegalArgumentException("deleteData: Shape does not support the Tools::IInterval interface.");
287 
288  Region mbrold;
289  shape.getMBR(mbrold);
290 
291  TimeRegionPtr mbr = m_regionPool.acquire();
292  mbr->makeDimension(mbrold.m_dimension);
293 
294  memcpy(mbr->m_pLow, mbrold.m_pLow, mbrold.m_dimension * sizeof(double));
295  memcpy(mbr->m_pHigh, mbrold.m_pHigh, mbrold.m_dimension * sizeof(double));
296  mbr->m_startTime = ti->getLowerBound();
297  mbr->m_endTime = ti->getUpperBound();
298 
299  bool ret = deleteData_impl(*mbr, id);
300 
301  return ret;
302 }
303 
304 
306 {
307  throw Tools::IllegalStateException("internalNodesQuery: not impelmented yet.");
308 }
309 
311 {
312  if (query.getDimension() != m_dimension) throw Tools::IllegalArgumentException("containsWhatQuery: Shape has the wrong number of dimensions.");
313  rangeQuery(ContainmentQuery, query, v);
314 }
315 
317 {
318  if (query.getDimension() != m_dimension) throw Tools::IllegalArgumentException("intersectsWithQuery: Shape has the wrong number of dimensions.");
319  rangeQuery(IntersectionQuery, query, v);
320 }
321 
323 {
324  if (query.m_dimension != m_dimension) throw Tools::IllegalArgumentException("pointLocationQuery: Shape has the wrong number of dimensions.");
325  const Tools::IInterval* ti = dynamic_cast<const Tools::IInterval*>(&query);
326  if (ti == nullptr) throw Tools::IllegalArgumentException("pointLocationQuery: Shape does not support the Tools::IInterval interface.");
327  TimeRegion r(query, query, *ti);
328  rangeQuery(IntersectionQuery, r, v);
329 }
330 
332 {
333  throw Tools::IllegalStateException("nearestNeighborQuery: not impelmented yet.");
334 }
335 
337 {
338  if (query.getDimension() != m_dimension) throw Tools::IllegalArgumentException("nearestNeighborQuery: Shape has the wrong number of dimensions.");
339  NNComparator nnc;
340  nearestNeighborQuery(k, query, v, nnc);
341 }
342 
344 {
345  throw Tools::IllegalStateException("selfJoinQuery: not impelmented yet.");
346 }
347 
349 {
350  id_type next = m_roots[m_roots.size() - 1].m_id;
351  bool hasNext = true;
352 
353  while (hasNext)
354  {
355  NodePtr n = readNode(next);
356  qs.getNextEntry(*n, next, hasNext);
357  }
358 }
359 
361 {
362  Tools::Variant var;
363 
364  // dimension
366  var.m_val.ulVal = m_dimension;
367  out.setProperty("Dimension", var);
368 
369  // index capacity
371  var.m_val.ulVal = m_indexCapacity;
372  out.setProperty("IndexCapacity", var);
373 
374  // leaf capacity
376  var.m_val.ulVal = m_leafCapacity;
377  out.setProperty("LeafCapacity", var);
378 
379  // Tree variant
381  var.m_val.lVal = m_treeVariant;
382  out.setProperty("TreeVariant", var);
383 
384  // fill factor
386  var.m_val.dblVal = m_fillFactor;
387  out.setProperty("FillFactor", var);
388 
389  // near minimum overlap factor
391  var.m_val.ulVal = m_nearMinimumOverlapFactor;
392  out.setProperty("NearMinimumOverlapFactor", var);
393 
394  // split distribution factor
396  var.m_val.dblVal = m_splitDistributionFactor;
397  out.setProperty("SplitDistributionFactor", var);
398 
399  // reinsert factor
401  var.m_val.dblVal = m_reinsertFactor;
402  out.setProperty("ReinsertFactor", var);
403 
404  // tight MBRs
406  var.m_val.blVal = m_bTightMBRs;
407  out.setProperty("EnsureTightMBRs", var);
408 
409  // index pool capacity
411  var.m_val.ulVal = m_indexPool.getCapacity();
412  out.setProperty("IndexPoolCapacity", var);
413 
414  // leaf pool capacity
416  var.m_val.ulVal = m_leafPool.getCapacity();
417  out.setProperty("LeafPoolCapacity", var);
418 
419  // region pool capacity
421  var.m_val.ulVal = m_regionPool.getCapacity();
422  out.setProperty("RegionPoolCapacity", var);
423 
424  // point pool capacity
426  var.m_val.ulVal = m_pointPool.getCapacity();
427  out.setProperty("PointPoolCapacity", var);
428 
429  // strong version overflow
431  var.m_val.dblVal = m_strongVersionOverflow;
432  out.setProperty("StrongVersionOverflow", var);
433 
434  // strong version underflow
435  //var.m_varType = Tools::VT_DOUBLE;
436  //var.m_val.dblVal = m_strongVersionUnderflow;
437  //out.setProperty("StrongVersionUnderflow", var);
438 
439  // weak version underflow
441  var.m_val.dblVal = m_versionUnderflow;
442  out.setProperty("VersionUnderflow", var);
443 
445  var.m_val.llVal = m_headerID;
446  out.setProperty("IndexIdentifier", var);
447 }
448 
450 {
451  switch (ct)
452  {
453  case CT_NODEREAD:
454  m_readNodeCommands.push_back(std::shared_ptr<ICommand>(pCommand));
455  break;
456  case CT_NODEWRITE:
457  m_writeNodeCommands.push_back(std::shared_ptr<ICommand>(pCommand));
458  break;
459  case CT_NODEDELETE:
460  m_deleteNodeCommands.push_back(std::shared_ptr<ICommand>(pCommand));
461  break;
462  }
463 }
464 
466 {
467  bool ret = true;
468  std::stack<ValidateEntry> st;
469  std::set<id_type> visitedEntries;
470  uint32_t degenerateEntries = 0;
471 
472  for (uint32_t cRoot = 0; cRoot < m_roots.size(); ++cRoot)
473  {
474  NodePtr root = readNode(m_roots[cRoot].m_id);
475 
476  if (root->m_level != m_stats.m_treeHeight[cRoot] - 1)
477  {
478  std::cerr << "Invalid tree height." << std::endl;
479  return false;
480  }
481 
482  ValidateEntry e(0, root->m_nodeMBR, root);
483  e.m_bIsDead = (root->m_nodeMBR.m_endTime < std::numeric_limits<double>::max()) ? true : false;
484  st.push(e);
485  }
486 
487  while (! st.empty())
488  {
489  ValidateEntry e = st.top(); st.pop();
490 
491  std::set<id_type>::iterator itSet = visitedEntries.find(e.m_pNode->m_identifier);
492  if (itSet == visitedEntries.end())
493  {
494  visitedEntries.insert(e.m_pNode->m_identifier);
495  if (e.m_pNode->m_nodeMBR.m_startTime == e.m_pNode->m_nodeMBR.m_endTime) ++degenerateEntries;
496  }
497 
498  TimeRegion tmpRegion;
499  tmpRegion = m_infiniteRegion;
500 
501  for (uint32_t cDim = 0; cDim < tmpRegion.m_dimension; ++cDim)
502  {
503  for (uint32_t cChild = 0; cChild < e.m_pNode->m_children; ++cChild)
504  {
505  tmpRegion.m_pLow[cDim] = std::min(tmpRegion.m_pLow[cDim], e.m_pNode->m_ptrMBR[cChild]->m_pLow[cDim]);
506  tmpRegion.m_pHigh[cDim] = std::max(tmpRegion.m_pHigh[cDim], e.m_pNode->m_ptrMBR[cChild]->m_pHigh[cDim]);
507  }
508  }
509 
510  tmpRegion.m_startTime = e.m_pNode->m_nodeMBR.m_startTime;
511  tmpRegion.m_endTime = e.m_pNode->m_nodeMBR.m_endTime;
512  if (! (tmpRegion == e.m_pNode->m_nodeMBR))
513  {
514  std::cerr << "Invalid parent information." << std::endl;
515  ret = false;
516  }
517 
518  if (! e.m_bIsDead)
519  {
520  tmpRegion.m_startTime = e.m_parentMBR.m_startTime;
521  tmpRegion.m_endTime = e.m_parentMBR.m_endTime;
522  if (! (tmpRegion == e.m_parentMBR))
523  {
524  std::cerr << "Error in parent (Node id: " << e.m_pNode->m_identifier << ", Parent id: " << e.m_parentID << ")." << std::endl;
525  ret = false;
526  }
527  }
528 
529  if (e.m_pNode->m_level != 0)
530  {
531  for (uint32_t cChild = 0; cChild < e.m_pNode->m_children; ++cChild)
532  {
533  NodePtr ptrN = readNode(e.m_pNode->m_pIdentifier[cChild]);
534 
535  bool bIsDead =
536  (e.m_pNode->m_ptrMBR[cChild]->m_endTime < std::numeric_limits<double>::max() || e.m_bIsDead) ? true : false;
537 
538  // if the parent says that this child is dead, force it dead since
539  // this information is not propagated for efficiency and is inconsistent.
540  if (bIsDead) ptrN->m_nodeMBR.m_endTime = e.m_pNode->m_ptrMBR[cChild]->m_endTime;
541 
542  ValidateEntry tmpEntry(e.m_pNode->m_identifier, *(e.m_pNode->m_ptrMBR[cChild]), ptrN);
543  tmpEntry.m_bIsDead = bIsDead;
544  st.push(tmpEntry);
545  }
546  }
547  }
548 
549  //std::cerr << "Total accessible nodes: " << visitedEntries.size() << std::endl;
550  //std::cerr << "Degenerate nodes: " << degenerateEntries << std::endl;
551 
552  return ret;
553 }
554 
556 {
557  *out = new Statistics(m_stats);
558 }
559 
561 {
562  storeHeader();
563 }
564 
565 void SpatialIndex::MVRTree::MVRTree::initNew(Tools::PropertySet& ps)
566 {
567  Tools::Variant var;
568 
569  // tree variant
570  var = ps.getProperty("TreeVariant");
571  if (var.m_varType != Tools::VT_EMPTY)
572  {
573  if (var.m_varType != Tools::VT_LONG || (var.m_val.lVal != RV_LINEAR && var.m_val.lVal != RV_QUADRATIC && var.m_val.lVal != RV_RSTAR))
574  throw Tools::IllegalArgumentException("initNew: Property TreeVariant must be Tools::VT_LONG and of MVRTreeVariant type");
575 
576  m_treeVariant = static_cast<MVRTreeVariant>(var.m_val.lVal);
577  }
578 
579  // fill factor
580  // it cannot be larger than 50%, since linear and quadratic split algorithms
581  // require assigning to both nodes the same number of entries.
582  var = ps.getProperty("FillFactor");
583  if (var.m_varType != Tools::VT_EMPTY)
584  {
585  if (
586  var.m_varType != Tools::VT_DOUBLE ||
587  var.m_val.dblVal <= 0.0 ||
588  //((m_treeVariant == RV_LINEAR || m_treeVariant == RV_QUADRATIC) && var.m_val.dblVal > 0.5) ||
589  var.m_val.dblVal >= 1.0)
590  throw Tools::IllegalArgumentException("initNew: Property FillFactor must be Tools::VT_DOUBLE and in (0.0, 1.0) for RSTAR, (0.0, 0.5) for LINEAR and QUADRATIC");
591 
592  m_fillFactor = var.m_val.dblVal;
593  }
594 
595  // index capacity
596  var = ps.getProperty("IndexCapacity");
597  if (var.m_varType != Tools::VT_EMPTY)
598  {
599  if (var.m_varType != Tools::VT_ULONG || var.m_val.ulVal < 10)
600  throw Tools::IllegalArgumentException("initNew: Property IndexCapacity must be Tools::VT_ULONG and >= 10");
601 
602  m_indexCapacity = var.m_val.ulVal;
603  }
604 
605  // leaf capacity
606  var = ps.getProperty("LeafCapacity");
607  if (var.m_varType != Tools::VT_EMPTY)
608  {
609  if (var.m_varType != Tools::VT_ULONG || var.m_val.ulVal < 10)
610  throw Tools::IllegalArgumentException("initNew: Property LeafCapacity must be Tools::VT_ULONG and >= 10");
611 
612  m_leafCapacity = var.m_val.ulVal;
613  }
614 
615  // near minimum overlap factor
616  var = ps.getProperty("NearMinimumOverlapFactor");
617  if (var.m_varType != Tools::VT_EMPTY)
618  {
619  if (var.m_varType != Tools::VT_ULONG || var.m_val.ulVal < 1 || var.m_val.ulVal > m_indexCapacity || var.m_val.ulVal > m_leafCapacity)
620  throw Tools::IllegalArgumentException("initNew: Property NearMinimumOverlapFactor must be Tools::VT_ULONG and less than both index and leaf capacities");
621 
622  m_nearMinimumOverlapFactor = var.m_val.ulVal;
623  }
624 
625  // split distribution factor
626  var = ps.getProperty("SplitDistributionFactor");
627  if (var.m_varType != Tools::VT_EMPTY)
628  {
629  if (var.m_varType != Tools::VT_DOUBLE || var.m_val.dblVal <= 0.0 || var.m_val.dblVal >= 1.0)
630  throw Tools::IllegalArgumentException("initNew: Property SplitDistributionFactor must be Tools::VT_DOUBLE and in (0.0, 1.0)");
631 
632  m_splitDistributionFactor = var.m_val.dblVal;
633  }
634 
635  // reinsert factor
636  var = ps.getProperty("ReinsertFactor");
637  if (var.m_varType != Tools::VT_EMPTY)
638  {
639  if (var.m_varType != Tools::VT_DOUBLE || var.m_val.dblVal <= 0.0 || var.m_val.dblVal >= 1.0)
640  throw Tools::IllegalArgumentException("initNew: Property ReinsertFactor must be Tools::VT_DOUBLE and in (0.0, 1.0)");
641 
642  m_reinsertFactor = var.m_val.dblVal;
643  }
644 
645  // dimension
646  var = ps.getProperty("Dimension");
647  if (var.m_varType != Tools::VT_EMPTY)
648  {
649  if (var.m_varType != Tools::VT_ULONG) throw Tools::IllegalArgumentException("initNew: Property Dimension must be Tools::VT_ULONG");
650  if (var.m_val.ulVal <= 1) throw Tools::IllegalArgumentException("initNew: Property Dimension must be greater than 1");
651 
652  m_dimension = var.m_val.ulVal;
653  }
654 
655  // tight MBRs
656  var = ps.getProperty("EnsureTightMBRs");
657  if (var.m_varType != Tools::VT_EMPTY)
658  {
659  if (var.m_varType != Tools::VT_BOOL) throw Tools::IllegalArgumentException("initNew: Property EnsureTightMBRs must be Tools::VT_BOOL");
660 
661  m_bTightMBRs = var.m_val.blVal;
662  }
663 
664  // index pool capacity
665  var = ps.getProperty("IndexPoolCapacity");
666  if (var.m_varType != Tools::VT_EMPTY)
667  {
668  if (var.m_varType != Tools::VT_ULONG) throw Tools::IllegalArgumentException("initNew: Property IndexPoolCapacity must be Tools::VT_ULONG");
669 
670  m_indexPool.setCapacity(var.m_val.ulVal);
671  }
672 
673  // leaf pool capacity
674  var = ps.getProperty("LeafPoolCapacity");
675  if (var.m_varType != Tools::VT_EMPTY)
676  {
677  if (var.m_varType != Tools::VT_ULONG) throw Tools::IllegalArgumentException("initNew: Property LeafPoolCapacity must be Tools::VT_ULONG");
678 
679  m_leafPool.setCapacity(var.m_val.ulVal);
680  }
681 
682  // region pool capacity
683  var = ps.getProperty("RegionPoolCapacity");
684  if (var.m_varType != Tools::VT_EMPTY)
685  {
686  if (var.m_varType != Tools::VT_ULONG) throw Tools::IllegalArgumentException("initNew: Property RegionPoolCapacity must be Tools::VT_ULONG");
687 
688  m_regionPool.setCapacity(var.m_val.ulVal);
689  }
690 
691  // point pool capacity
692  var = ps.getProperty("PointPoolCapacity");
693  if (var.m_varType != Tools::VT_EMPTY)
694  {
695  if (var.m_varType != Tools::VT_ULONG) throw Tools::IllegalArgumentException("initNew: Property PointPoolCapacity must be Tools::VT_ULONG");
696 
697  m_pointPool.setCapacity(var.m_val.ulVal);
698  }
699 
700  // strong version overflow
701  var = ps.getProperty("StrongVersionOverflow");
702  if (var.m_varType != Tools::VT_EMPTY)
703  {
704  if (var.m_varType != Tools::VT_DOUBLE || var.m_val.dblVal <= 0.0 || var.m_val.dblVal >= 1.0)
705  throw Tools::IllegalArgumentException("initNew: Property StrongVersionOverflow must be Tools::VT_DOUBLE and in (0.0, 1.0)");
706 
707  m_strongVersionOverflow = var.m_val.dblVal;
708  }
709 
710  // strong version underflow
711  //var = ps.getProperty("StrongVersionUnderflow");
712  //if (var.m_varType != Tools::VT_EMPTY)
713  //{
714  // if (var.m_varType != Tools::VT_DOUBLE ||
715  // var.m_val.dblVal <= 0.0 ||
716  // var.m_val.dblVal >= 1.0) throw Tools::IllegalArgumentException("Property StrongVersionUnderflow must be Tools::VT_DOUBLE and in (0.0, 1.0)");
717 
718  // m_strongVersionUnderflow = var.m_val.dblVal;
719  //}
720 
721  // weak version underflow
722  var = ps.getProperty("VersionUnderflow");
723  if (var.m_varType != Tools::VT_EMPTY)
724  {
725  if (var.m_varType != Tools::VT_DOUBLE || var.m_val.dblVal <= 0.0 || var.m_val.dblVal >= 1.0)
726  throw Tools::IllegalArgumentException("initNew: Property VersionUnderflow must be Tools::VT_DOUBLE and in (0.0, 1.0)");
727 
728  m_versionUnderflow = var.m_val.dblVal;
729  }
730 
731  m_infiniteRegion.makeInfinite(m_dimension);
732 
733  m_stats.m_treeHeight.push_back(1);
734  m_stats.m_nodesInLevel.push_back(1);
735 
736  Leaf root(this, -1);
737  root.m_nodeMBR.m_startTime = 0.0;
738  root.m_nodeMBR.m_endTime = std::numeric_limits<double>::max();
739  writeNode(&root);
740  m_roots.emplace_back(root.m_identifier, root.m_nodeMBR.m_startTime, root.m_nodeMBR.m_endTime);
741 
742  storeHeader();
743 }
744 
745 void SpatialIndex::MVRTree::MVRTree::initOld(Tools::PropertySet& ps)
746 {
747  loadHeader();
748 
749  // only some of the properties may be changed.
750  // the rest are just ignored.
751 
752  Tools::Variant var;
753 
754  // tree variant
755  var = ps.getProperty("TreeVariant");
756  if (var.m_varType != Tools::VT_EMPTY)
757  {
758  if (var.m_varType != Tools::VT_LONG || (var.m_val.lVal != RV_LINEAR && var.m_val.lVal != RV_QUADRATIC && var.m_val.lVal != RV_RSTAR))
759  throw Tools::IllegalArgumentException("initOld: Property TreeVariant must be Tools::VT_LONG and of MVRTreeVariant type");
760 
761  m_treeVariant = static_cast<MVRTreeVariant>(var.m_val.lVal);
762  }
763 
764  // near minimum overlap factor
765  var = ps.getProperty("NearMinimumOverlapFactor");
766  if (var.m_varType != Tools::VT_EMPTY)
767  {
768  if (var.m_varType != Tools::VT_ULONG || var.m_val.ulVal < 1 || var.m_val.ulVal > m_indexCapacity || var.m_val.ulVal > m_leafCapacity)
769  throw Tools::IllegalArgumentException("initOld: Property NearMinimumOverlapFactor must be Tools::VT_ULONG and less than both index and leaf capacities");
770 
771  m_nearMinimumOverlapFactor = var.m_val.ulVal;
772  }
773 
774  // split distribution factor
775  var = ps.getProperty("SplitDistributionFactor");
776  if (var.m_varType != Tools::VT_EMPTY)
777  {
778  if (var.m_varType != Tools::VT_DOUBLE || var.m_val.dblVal <= 0.0 || var.m_val.dblVal >= 1.0)
779  throw Tools::IllegalArgumentException("initOld: Property SplitDistributionFactor must be Tools::VT_DOUBLE and in (0.0, 1.0)");
780 
781  m_splitDistributionFactor = var.m_val.dblVal;
782  }
783 
784  // reinsert factor
785  var = ps.getProperty("ReinsertFactor");
786  if (var.m_varType != Tools::VT_EMPTY)
787  {
788  if (var.m_varType != Tools::VT_DOUBLE ||var.m_val.dblVal <= 0.0 || var.m_val.dblVal >= 1.0)
789  throw Tools::IllegalArgumentException("initOld: Property ReinsertFactor must be Tools::VT_DOUBLE and in (0.0, 1.0)");
790 
791  m_reinsertFactor = var.m_val.dblVal;
792  }
793 
794  // tight MBRs
795  var = ps.getProperty("EnsureTightMBRs");
796  if (var.m_varType != Tools::VT_EMPTY)
797  {
798  if (var.m_varType != Tools::VT_BOOL) throw Tools::IllegalArgumentException("initOld: Property EnsureTightMBRs must be Tools::VT_BOOL");
799 
800  m_bTightMBRs = var.m_val.blVal;
801  }
802 
803  // index pool capacity
804  var = ps.getProperty("IndexPoolCapacity");
805  if (var.m_varType != Tools::VT_EMPTY)
806  {
807  if (var.m_varType != Tools::VT_ULONG) throw Tools::IllegalArgumentException("initOld: Property IndexPoolCapacity must be Tools::VT_ULONG");
808 
809  m_indexPool.setCapacity(var.m_val.ulVal);
810  }
811 
812  // leaf pool capacity
813  var = ps.getProperty("LeafPoolCapacity");
814  if (var.m_varType != Tools::VT_EMPTY)
815  {
816  if (var.m_varType != Tools::VT_ULONG) throw Tools::IllegalArgumentException("initOld: Property LeafPoolCapacity must be Tools::VT_ULONG");
817 
818  m_leafPool.setCapacity(var.m_val.ulVal);
819  }
820 
821  // region pool capacity
822  var = ps.getProperty("RegionPoolCapacity");
823  if (var.m_varType != Tools::VT_EMPTY)
824  {
825  if (var.m_varType != Tools::VT_ULONG) throw Tools::IllegalArgumentException("initOld: Property RegionPoolCapacity must be Tools::VT_ULONG");
826 
827  m_regionPool.setCapacity(var.m_val.ulVal);
828  }
829 
830  // point pool capacity
831  var = ps.getProperty("PointPoolCapacity");
832  if (var.m_varType != Tools::VT_EMPTY)
833  {
834  if (var.m_varType != Tools::VT_ULONG) throw Tools::IllegalArgumentException("initOld: Property PointPoolCapacity must be Tools::VT_ULONG");
835 
836  m_pointPool.setCapacity(var.m_val.ulVal);
837  }
838 
839  m_infiniteRegion.makeInfinite(m_dimension);
840 }
841 
842 void SpatialIndex::MVRTree::MVRTree::storeHeader()
843 {
844  const uint32_t headerSize =
845  sizeof(uint32_t) + // size of m_roots
846  static_cast<uint32_t>(m_roots.size())
847  * (sizeof(id_type) + 2 * sizeof(double)) + // m_roots
848  sizeof(MVRTreeVariant) + // m_treeVariant
849  sizeof(double)+ // m_fillFactor
850  sizeof(uint32_t) + // m_indexCapacity
851  sizeof(uint32_t) + // m_leafCapacity
852  sizeof(uint32_t) + // m_nearMinimumOverlapFactor
853  sizeof(double) + // m_splitDistributionFactor
854  sizeof(double) + // m_reinsertFactor
855  sizeof(uint32_t) + // m_dimension
856  sizeof(uint8_t) + // m_bTightMBRs
857  sizeof(uint32_t) + // m_stats.m_nodes
858  sizeof(uint64_t) + // m_stats.m_totalData
859  sizeof(uint32_t) + // m_stats.m_deadIndexNodes
860  sizeof(uint32_t) + // m_stats.m_deadLeafNodes
861  sizeof(uint64_t) + // m_stats.m_data
862  sizeof(uint32_t) + // size of m_stats.m_treeHeight
863  static_cast<uint32_t>(m_stats.m_treeHeight.size())
864  * sizeof(uint32_t) + // m_stats.m_treeHeight
865  sizeof(double) + // m_strongVersionOverflow
866  //sizeof(double) + // m_strongVersionUnderflow
867  sizeof(double) + // m_versionUnderflow
868  sizeof(double) + // m_currentTime
869  sizeof(uint32_t) + // m_nodesInLevel size
870  static_cast<uint32_t>(m_stats.m_nodesInLevel.size())
871  * sizeof(uint32_t); // m_nodesInLevel values
872 
873  uint8_t* header = new uint8_t[headerSize];
874  uint8_t* ptr = header;
875 
876  uint32_t u32I = static_cast<uint32_t>(m_roots.size());
877  memcpy(ptr, &u32I, sizeof(uint32_t));
878  ptr += sizeof(uint32_t);
879 
880  for (size_t cIndex = 0; cIndex < m_roots.size(); ++cIndex)
881  {
882  RootEntry& e = m_roots[cIndex];
883  memcpy(ptr, &(e.m_id), sizeof(id_type));
884  ptr += sizeof(id_type);
885  memcpy(ptr, &(e.m_startTime), sizeof(double));
886  ptr += sizeof(double);
887  memcpy(ptr, &(e.m_endTime), sizeof(double));
888  ptr += sizeof(double);
889  }
890 
891  memcpy(ptr, &m_treeVariant, sizeof(MVRTreeVariant));
892  ptr += sizeof(MVRTreeVariant);
893  memcpy(ptr, &m_fillFactor, sizeof(double));
894  ptr += sizeof(double);
895  memcpy(ptr, &m_indexCapacity, sizeof(uint32_t));
896  ptr += sizeof(uint32_t);
897  memcpy(ptr, &m_leafCapacity, sizeof(uint32_t));
898  ptr += sizeof(uint32_t);
899  memcpy(ptr, &m_nearMinimumOverlapFactor, sizeof(uint32_t));
900  ptr += sizeof(uint32_t);
901  memcpy(ptr, &m_splitDistributionFactor, sizeof(double));
902  ptr += sizeof(double);
903  memcpy(ptr, &m_reinsertFactor, sizeof(double));
904  ptr += sizeof(double);
905  memcpy(ptr, &m_dimension, sizeof(uint32_t));
906  ptr += sizeof(uint32_t);
907  uint8_t c = (uint8_t) m_bTightMBRs;
908  memcpy(ptr, &c, sizeof(uint8_t));
909  ptr += sizeof(uint8_t);
910  memcpy(ptr, &(m_stats.m_u32Nodes), sizeof(uint32_t));
911  ptr += sizeof(uint32_t);
912  memcpy(ptr, &(m_stats.m_u64TotalData), sizeof(uint64_t));
913  ptr += sizeof(uint64_t);
914  memcpy(ptr, &(m_stats.m_u32DeadIndexNodes), sizeof(uint32_t));
915  ptr += sizeof(uint32_t);
916  memcpy(ptr, &(m_stats.m_u32DeadLeafNodes), sizeof(uint32_t));
917  ptr += sizeof(uint32_t);
918  memcpy(ptr, &(m_stats.m_u64Data), sizeof(uint64_t));
919  ptr += sizeof(uint64_t);
920 
921  u32I = static_cast<uint32_t>(m_stats.m_treeHeight.size());
922  memcpy(ptr, &u32I, sizeof(uint32_t));
923  ptr += sizeof(uint32_t);
924 
925  for (size_t cIndex = 0; cIndex < m_stats.m_treeHeight.size(); ++cIndex)
926  {
927  u32I = m_stats.m_treeHeight[cIndex];
928  memcpy(ptr, &u32I, sizeof(uint32_t));
929  ptr += sizeof(uint32_t);
930  }
931 
932  memcpy(ptr, &m_strongVersionOverflow, sizeof(double));
933  ptr += sizeof(double);
934  //memcpy(ptr, &m_strongVersionUnderflow, sizeof(double));
935  //ptr += sizeof(double);
936  memcpy(ptr, &m_versionUnderflow, sizeof(double));
937  ptr += sizeof(double);
938  memcpy(ptr, &m_currentTime, sizeof(double));
939  ptr += sizeof(double);
940 
941  u32I = static_cast<uint32_t>(m_stats.m_nodesInLevel.size());
942  memcpy(ptr, &u32I, sizeof(uint32_t));
943  ptr += sizeof(uint32_t);
944 
945  for (size_t cLevel = 0; cLevel < m_stats.m_nodesInLevel.size(); ++cLevel)
946  {
947  u32I = m_stats.m_nodesInLevel[cLevel];
948  memcpy(ptr, &u32I, sizeof(uint32_t));
949  ptr += sizeof(uint32_t);
950  }
951 
952  m_pStorageManager->storeByteArray(m_headerID, headerSize, header);
953 
954  delete[] header;
955 }
956 
957 void SpatialIndex::MVRTree::MVRTree::loadHeader()
958 {
959  uint32_t headerSize;
960  uint8_t* header = nullptr;
961  m_pStorageManager->loadByteArray(m_headerID, headerSize, &header);
962 
963  uint8_t* ptr = header;
964 
965  uint32_t rootsSize;
966  memcpy(&rootsSize, ptr, sizeof(uint32_t));
967  ptr += sizeof(uint32_t);
968 
969  for (uint32_t cIndex = 0; cIndex < rootsSize; ++cIndex)
970  {
971  RootEntry e;
972  memcpy(&(e.m_id), ptr, sizeof(id_type));
973  ptr += sizeof(id_type);
974  memcpy(&(e.m_startTime), ptr, sizeof(double));
975  ptr += sizeof(double);
976  memcpy(&(e.m_endTime), ptr, sizeof(double));
977  ptr += sizeof(double);
978  m_roots.push_back(e);
979  }
980 
981  memcpy(&m_treeVariant, ptr, sizeof(MVRTreeVariant));
982  ptr += sizeof(MVRTreeVariant);
983  memcpy(&m_fillFactor, ptr, sizeof(double));
984  ptr += sizeof(double);
985  memcpy(&m_indexCapacity, ptr, sizeof(uint32_t));
986  ptr += sizeof(uint32_t);
987  memcpy(&m_leafCapacity, ptr, sizeof(uint32_t));
988  ptr += sizeof(uint32_t);
989  memcpy(&m_nearMinimumOverlapFactor, ptr, sizeof(uint32_t));
990  ptr += sizeof(uint32_t);
991  memcpy(&m_splitDistributionFactor, ptr, sizeof(double));
992  ptr += sizeof(double);
993  memcpy(&m_reinsertFactor, ptr, sizeof(double));
994  ptr += sizeof(double);
995  memcpy(&m_dimension, ptr, sizeof(uint32_t));
996  ptr += sizeof(uint32_t);
997  uint8_t c;
998  memcpy(&c, ptr, sizeof(uint8_t));
999  m_bTightMBRs = (c != 0);
1000  ptr += sizeof(uint8_t);
1001  memcpy(&(m_stats.m_u32Nodes), ptr, sizeof(uint32_t));
1002  ptr += sizeof(uint32_t);
1003  memcpy(&(m_stats.m_u64TotalData), ptr, sizeof(uint64_t));
1004  ptr += sizeof(uint64_t);
1005  memcpy(&(m_stats.m_u32DeadIndexNodes), ptr, sizeof(uint32_t));
1006  ptr += sizeof(uint32_t);
1007  memcpy(&(m_stats.m_u32DeadLeafNodes), ptr, sizeof(uint32_t));
1008  ptr += sizeof(uint32_t);
1009  memcpy(&(m_stats.m_u64Data), ptr, sizeof(uint64_t));
1010  ptr += sizeof(uint64_t);
1011 
1012  uint32_t treeHeightSize;
1013  memcpy(&treeHeightSize, ptr, sizeof(uint32_t));
1014  ptr += sizeof(uint32_t);
1015 
1016  for (uint32_t cIndex = 0; cIndex < treeHeightSize; ++cIndex)
1017  {
1018  uint32_t u32I;
1019  memcpy(&u32I, ptr, sizeof(uint32_t));
1020  m_stats.m_treeHeight.push_back(u32I);
1021  ptr += sizeof(uint32_t);
1022  }
1023 
1024  memcpy(&m_strongVersionOverflow, ptr, sizeof(double));
1025  ptr += sizeof(double);
1026  //memcpy(&m_strongVersionUnderflow, ptr, sizeof(double));
1027  //ptr += sizeof(double);
1028  memcpy(&m_versionUnderflow, ptr, sizeof(double));
1029  ptr += sizeof(double);
1030  memcpy(&m_currentTime, ptr, sizeof(double));
1031  ptr += sizeof(double);
1032 
1033  uint32_t nodesInLevelSize;
1034  memcpy(&nodesInLevelSize, ptr, sizeof(uint32_t));
1035  ptr += sizeof(uint32_t);
1036 
1037  for (uint32_t cLevel = 0; cLevel < nodesInLevelSize; ++cLevel)
1038  {
1039  uint32_t u32I;
1040  memcpy(&u32I, ptr, sizeof(uint32_t));
1041  ptr += sizeof(uint32_t);
1042  m_stats.m_nodesInLevel.push_back(u32I);
1043  }
1044 
1045  delete[] header;
1046 }
1047 
1048 void SpatialIndex::MVRTree::MVRTree::insertData_impl(uint32_t dataLength, uint8_t* pData, TimeRegion& mbr, id_type id)
1049 {
1050  assert(mbr.getDimension() == m_dimension);
1051  assert(m_currentTime <= mbr.m_startTime);
1052 
1053  std::stack<id_type> pathBuffer;
1054  m_currentTime = mbr.m_startTime;
1055 
1056  NodePtr root = readNode(m_roots[m_roots.size() - 1].m_id);
1057  NodePtr l = root->chooseSubtree(mbr, 0, pathBuffer);
1058 
1059  if (l.get() == root.get())
1060  {
1061  assert(root.unique());
1062  root.relinquish();
1063  }
1064  l->insertData(dataLength, pData, mbr, id, pathBuffer, m_infiniteRegion, -1, false);
1065 
1066  ++(m_stats.m_u64Data);
1067  ++(m_stats.m_u64TotalData);
1068 }
1069 
1070 void SpatialIndex::MVRTree::MVRTree::insertData_impl(uint32_t dataLength, uint8_t* pData, TimeRegion& mbr, id_type id, uint32_t level)
1071 {
1072  assert(mbr.getDimension() == m_dimension);
1073 
1074  std::stack<id_type> pathBuffer;
1075 
1076  NodePtr root = readNode(m_roots[m_roots.size() - 1].m_id);
1077  NodePtr l = root->chooseSubtree(mbr, level, pathBuffer);
1078 
1079  assert(l->m_level == level);
1080 
1081  if (l.get() == root.get())
1082  {
1083  assert(root.unique());
1084  root.relinquish();
1085  }
1086  l->insertData(dataLength, pData, mbr, id, pathBuffer, m_infiniteRegion, -1, false);
1087 }
1088 
1089 bool SpatialIndex::MVRTree::MVRTree::deleteData_impl(const TimeRegion& mbr, id_type id)
1090 {
1091  assert(mbr.m_dimension == m_dimension);
1092 
1093  m_currentTime = mbr.m_endTime;
1094 
1095  std::stack<id_type> pathBuffer;
1096  NodePtr root = readNode(m_roots[m_roots.size() - 1].m_id);
1097  NodePtr l = root->findLeaf(mbr, id, pathBuffer);
1098 
1099  if (l.get() == root.get())
1100  {
1101  assert(root.unique());
1102  root.relinquish();
1103  }
1104 
1105  if (l.get() != nullptr)
1106  {
1107  l->deleteData(id, mbr.m_endTime, pathBuffer);
1108  --(m_stats.m_u64Data);
1109  return true;
1110  }
1111 
1112  return false;
1113 }
1114 
1115 SpatialIndex::id_type SpatialIndex::MVRTree::MVRTree::writeNode(Node* n)
1116 {
1117  uint8_t* buffer;
1118  uint32_t dataLength;
1119  n->storeToByteArray(&buffer, dataLength);
1120 
1121  id_type page;
1122  if (n->m_identifier < 0) page = StorageManager::NewPage;
1123  else page = n->m_identifier;
1124 
1125  try
1126  {
1127  m_pStorageManager->storeByteArray(page, dataLength, buffer);
1128  delete[] buffer;
1129  }
1130  catch (InvalidPageException& e)
1131  {
1132  delete[] buffer;
1133  std::cerr << e.what() << std::endl;
1134  //std::cerr << *this << std::endl;
1135  throw Tools::IllegalStateException("writeNode: failed with Tools::InvalidPageException");
1136  }
1137 
1138  if (n->m_identifier < 0)
1139  {
1140  n->m_identifier = page;
1141  ++(m_stats.m_u32Nodes);
1142  }
1143 
1144  ++(m_stats.m_u64Writes);
1145 
1146  for (size_t cIndex = 0; cIndex < m_writeNodeCommands.size(); ++cIndex)
1147  {
1148  m_writeNodeCommands[cIndex]->execute(*n);
1149  }
1150 
1151  return page;
1152 }
1153 
1154 SpatialIndex::MVRTree::NodePtr SpatialIndex::MVRTree::MVRTree::readNode(id_type id)
1155 {
1156  uint32_t dataLength;
1157  uint8_t* buffer;
1158 
1159  try
1160  {
1161  m_pStorageManager->loadByteArray(id, dataLength, &buffer);
1162  }
1163  catch (InvalidPageException& e)
1164  {
1165  std::cerr << e.what() << std::endl;
1166  //std::cerr << *this << std::endl;
1167  throw Tools::IllegalStateException("readNode: failed with Tools::InvalidPageException");
1168  }
1169 
1170  try
1171  {
1172  uint32_t nodeType;
1173  memcpy(&nodeType, buffer, sizeof(uint32_t));
1174 
1175  NodePtr n;
1176 
1177  if (nodeType == PersistentIndex) n = m_indexPool.acquire();
1178  else if (nodeType == PersistentLeaf) n = m_leafPool.acquire();
1179  else throw Tools::IllegalStateException("readNode: failed reading the correct node type information");
1180 
1181  if (n.get() == nullptr)
1182  {
1183  if (nodeType == PersistentIndex) n = NodePtr(new Index(this, -1, 0), &m_indexPool);
1184  else if (nodeType == PersistentLeaf) n = NodePtr(new Leaf(this, -1), &m_leafPool);
1185  }
1186 
1187  //n->m_pTree = this;
1188  n->m_identifier = id;
1189  n->loadFromByteArray(buffer);
1190 
1191  ++(m_stats.m_u64Reads);
1192 
1193  for (size_t cIndex = 0; cIndex < m_readNodeCommands.size(); ++cIndex)
1194  {
1195  m_readNodeCommands[cIndex]->execute(*n);
1196  }
1197 
1198  delete[] buffer;
1199  return n;
1200  }
1201  catch (...)
1202  {
1203  delete[] buffer;
1204  throw;
1205  }
1206 }
1207 
1208 void SpatialIndex::MVRTree::MVRTree::deleteNode(Node* n)
1209 {
1210  try
1211  {
1212  m_pStorageManager->deleteByteArray(n->m_identifier);
1213  }
1214  catch (InvalidPageException& e)
1215  {
1216  std::cerr << e.what() << std::endl;
1217  //std::cerr << *this << std::endl;
1218  throw Tools::IllegalStateException("deleteNode: failed with Tools::InvalidPageException");
1219  }
1220 
1221  --(m_stats.m_u32Nodes);
1222 
1223  for (size_t cIndex = 0; cIndex < m_deleteNodeCommands.size(); ++cIndex)
1224  {
1225  m_deleteNodeCommands[cIndex]->execute(*n);
1226  }
1227 }
1228 
1229 void SpatialIndex::MVRTree::MVRTree::rangeQuery(RangeQueryType type, const IShape& query, IVisitor& v)
1230 {
1231  // any shape that implements IInterval and IShape, can be used here.
1232  // FIXME: I am not using ITimeShape yet, even though I should.
1233 
1234  const Tools::IInterval* ti = dynamic_cast<const Tools::IInterval*>(&query);
1235  if (ti == nullptr) throw Tools::IllegalArgumentException("rangeQuery: Shape does not support the Tools::IInterval interface.");
1236 
1237  std::set<id_type> visitedNodes;
1238  std::set<id_type> visitedData;
1239  std::stack<NodePtr> st;
1240  std::vector<id_type> ids;
1241  findRootIdentifiers(*ti, ids);
1242 
1243  for (size_t cRoot = 0; cRoot < ids.size(); ++cRoot)
1244  {
1245  NodePtr root = readNode(ids[cRoot]);
1246  if (root->m_children > 0 && query.intersectsShape(root->m_nodeMBR)) st.push(root);
1247  }
1248 
1249  while (! st.empty())
1250  {
1251  NodePtr n = st.top(); st.pop();
1252  visitedNodes.insert(n->m_identifier);
1253 
1254  if (n->m_level == 0)
1255  {
1256  v.visitNode(*n);
1257 
1258  for (uint32_t cChild = 0; cChild < n->m_children; ++cChild)
1259  {
1260  if (visitedData.find(n->m_pIdentifier[cChild]) != visitedData.end()) continue;
1261 
1262  bool b;
1263  if (type == ContainmentQuery) b = (n->m_ptrMBR[cChild])->intersectsInterval(*ti) && query.containsShape(*(n->m_ptrMBR[cChild]));
1264  else b = (n->m_ptrMBR[cChild])->intersectsInterval(*ti) && query.intersectsShape(*(n->m_ptrMBR[cChild]));
1265 
1266  if (b)
1267  {
1268  visitedData.insert(n->m_pIdentifier[cChild]);
1269  Data data = Data(n->m_pDataLength[cChild], n->m_pData[cChild], *(n->m_ptrMBR[cChild]), n->m_pIdentifier[cChild]);
1270  v.visitData(data);
1271  ++(m_stats.m_u64QueryResults);
1272  }
1273  }
1274  }
1275  else
1276  {
1277  v.visitNode(*n);
1278 
1279  for (uint32_t cChild = 0; cChild < n->m_children; ++cChild)
1280  {
1281  if (
1282  visitedNodes.find(n->m_pIdentifier[cChild]) == visitedNodes.end() &&
1283  n->m_ptrMBR[cChild]->intersectsInterval(*ti) &&
1284  query.intersectsShape(*(n->m_ptrMBR[cChild])))
1285  st.push(readNode(n->m_pIdentifier[cChild]));
1286  }
1287  }
1288  }
1289 }
1290 
1291 void SpatialIndex::MVRTree::MVRTree::findRootIdentifiers(const Tools::IInterval& ti, std::vector<id_type>& ids)
1292 {
1293  ids.clear();
1294 
1295  for (size_t cRoot = 0; cRoot < m_roots.size(); ++cRoot)
1296  {
1297  RootEntry& e = m_roots[cRoot];
1298  if (ti.intersectsInterval(Tools::IT_RIGHTOPEN, e.m_startTime, e.m_endTime)) ids.push_back(e.m_id);
1299  }
1300 }
1301 
1302 std::string SpatialIndex::MVRTree::MVRTree::printRootInfo() const
1303 {
1304  std::ostringstream s;
1305 
1306  for (size_t cRoot = 0; cRoot < m_roots.size(); ++cRoot)
1307  {
1308  const RootEntry& e = m_roots[cRoot];
1309 
1310  s << "Root " << cRoot << ": Start " << e.m_startTime << ", End " << e.m_endTime << std::endl;
1311  }
1312 
1313  return s.str();
1314 }
1315 
1316 std::ostream& SpatialIndex::MVRTree::operator<<(std::ostream& os, const MVRTree& t)
1317 {
1318  os << "Dimension: " << t.m_dimension << std::endl
1319  << "Fill factor: " << t.m_fillFactor << std::endl
1320  << "Index capacity: " << t.m_indexCapacity << std::endl
1321  << "Leaf capacity: " << t.m_leafCapacity << std::endl
1322  << "Tight MBRs: " << ((t.m_bTightMBRs) ? "enabled" : "disabled") << std::endl;
1323 
1324  if (t.m_treeVariant == RV_RSTAR)
1325  {
1326  os << "Near minimum overlap factor: " << t.m_nearMinimumOverlapFactor << std::endl
1327  << "Reinsert factor: " << t.m_reinsertFactor << std::endl
1328  << "Split distribution factor: " << t.m_splitDistributionFactor << std::endl
1329  << "Strong version overflow: " << t.m_strongVersionOverflow << std::endl
1330  //<< "Strong version underflow: " << t.m_strongVersionUnderflow << std::endl
1331  << "Weak version underflow: " << t.m_versionUnderflow << std::endl;
1332  }
1333 
1334  // it is difficult to count utilization
1335  //os << "Utilization: " << 100 * t.m_stats.m_totalData / (t.m_stats.getNumberOfNodesInLevel(0) * t.m_leafCapacity) << "%" << std::endl
1336 
1337  os << t.m_stats;
1338  os << t.printRootInfo();
1339 
1340  #ifndef NDEBUG
1341  os << "Leaf pool hits: " << t.m_leafPool.m_hits << std::endl
1342  << "Leaf pool misses: " << t.m_leafPool.m_misses << std::endl
1343  << "Index pool hits: " << t.m_indexPool.m_hits << std::endl
1344  << "Index pool misses: " << t.m_indexPool.m_misses << std::endl
1345  << "Region pool hits: " << t.m_regionPool.m_hits << std::endl
1346  << "Region pool misses: " << t.m_regionPool.m_misses << std::endl
1347  << "Point pool hits: " << t.m_pointPool.m_hits << std::endl
1348  << "Point pool misses: " << t.m_pointPool.m_misses << std::endl;
1349  #endif
1350 
1351  return os;
1352 }
virtual void selfJoinQuery(const IShape &s, IVisitor &v)
Definition: MVRTree.cc:343
void storeToByteArray(uint8_t **data, uint32_t &len) override
Definition: MVRTree.cc:113
std::ostream & operator<<(std::ostream &os, const MVRTree &t)
Definition: MVRTree.cc:1316
uint32_t getByteArraySize() override
Definition: MVRTree.cc:83
virtual void deleteByteArray(const id_type id)=0
virtual bool intersectsInterval(const IInterval &) const =0
VariantType m_varType
Definition: Tools.h:277
uint32_t ulVal
Definition: Tools.h:289
void setProperty(std::string property, Variant const &v)
Definition: Tools.cc:354
virtual bool deleteData(const IShape &shape, id_type id)
Definition: MVRTree.cc:282
void storeToByteArray(uint8_t **data, uint32_t &len) override
Definition: TimeRegion.cc:231
void makeInfinite(uint32_t dimension) override
Definition: TimeRegion.cc:376
PoolPointer< X > acquire()
Definition: PointerPool.h:64
virtual void nearestNeighborQuery(uint32_t k, const IShape &query, IVisitor &v, INearestNeighborComparator &)
Definition: MVRTree.cc:331
virtual double getLowerBound() const =0
void loadFromByteArray(const uint8_t *data) override
Definition: MVRTree.cc:92
void getData(uint32_t &len, uint8_t **data) const override
Definition: MVRTree.cc:71
virtual void storeByteArray(id_type &id, const uint32_t len, const uint8_t *const data)=0
virtual void queryStrategy(IQueryStrategy &qs)
Definition: MVRTree.cc:348
double * m_pLow
Definition: Region.h:98
Data * clone() override
Definition: MVRTree.cc:56
bool intersectsInterval(const Tools::IInterval &ti) const override
void loadFromByteArray(const uint8_t *data) override
Definition: TimeRegion.cc:213
uint32_t m_dimension
Definition: Point.h:77
id_type getIdentifier() const override
Definition: MVRTree.cc:61
virtual void loadByteArray(const id_type id, uint32_t &len, uint8_t **data)=0
virtual uint32_t getDimension() const =0
union Tools::Variant::@0 m_val
Tools::PoolPointer< Node > NodePtr
Definition: mvrtree/Node.h:40
virtual void visitNode(const INode &in)=0
virtual void getIndexProperties(Tools::PropertySet &out) const
Definition: MVRTree.cc:360
int64_t llVal
Definition: Tools.h:283
SIDX_DLL ISpatialIndex * createNewMVRTree(IStorageManager &in, double fillFactor, uint32_t indexCapacity, uint32_t leafCapacity, uint32_t dimension, MVRTreeVariant rv, id_type &out_indexIdentifier)
Definition: MVRTree.cc:147
virtual bool intersectsShape(const IShape &in) const =0
uint32_t m_dimension
Definition: Region.h:97
double * m_pHigh
Definition: Region.h:99
bool unique() const noexcept
Definition: PoolPointer.h:56
virtual void containsWhatQuery(const IShape &query, IVisitor &v)
Definition: MVRTree.cc:310
X * get() const noexcept
Definition: PoolPointer.h:55
virtual void visitData(const IData &in)=0
virtual void pointLocationQuery(const Point &query, IVisitor &v)
Definition: MVRTree.cc:322
uint32_t getDimension() const override
Definition: Region.cc:229
void setCapacity(uint32_t c)
Definition: PointerPool.h:105
uint32_t getByteArraySize() override
Definition: TimeRegion.cc:208
SIDX_DLL ISpatialIndex * loadMVRTree(IStorageManager &in, id_type indexIdentifier)
Definition: MVRTree.cc:188
virtual void insertData(uint32_t len, const uint8_t *pData, const IShape &shape, id_type id)
Definition: MVRTree.cc:251
int32_t lVal
Definition: Tools.h:282
SIDX_DLL ISpatialIndex * returnMVRTree(IStorageManager &ind, Tools::PropertySet &in)
Definition: MVRTree.cc:141
double dblVal
Definition: Tools.h:286
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
virtual void internalNodesQuery(const IShape &query, IVisitor &v)
Definition: MVRTree.cc:305
bool blVal
Definition: Tools.h:291
void makeDimension(uint32_t dimension) override
Definition: TimeRegion.cc:389
virtual void getNextEntry(const IEntry &previouslyFetched, id_type &nextEntryToFetch, bool &bFetchNextEntry)=0
virtual bool containsShape(const IShape &in) const =0
void storeToByteArray(uint8_t **data, uint32_t &len) override
MVRTree(IStorageManager &, Tools::PropertySet &)
Definition: MVRTree.cc:200
virtual bool isIndexValid()
Definition: MVRTree.cc:465
void relinquish() noexcept
Definition: PoolPointer.h:57
virtual void intersectsWithQuery(const IShape &query, IVisitor &v)
Definition: MVRTree.cc:316
void loadFromByteArray(const uint8_t *data) override
Definition: mvrtree/Node.cc:66
virtual void getStatistics(IStatistics **out) const
Definition: MVRTree.cc:555
virtual void addCommand(ICommand *pCommand, CommandType ct)
Definition: MVRTree.cc:449
Data(uint32_t len, uint8_t *pData, TimeRegion &r, id_type id)
Definition: MVRTree.cc:41
void getShape(IShape **out) const override
Definition: MVRTree.cc:66
virtual double getUpperBound() const =0