libspatialindex API Reference  (git-trunk)
tprtree/Index.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 "TPRTree.h"
33 #include "Node.h"
34 #include "Leaf.h"
35 #include "Index.h"
36 
37 using namespace SpatialIndex;
38 using namespace SpatialIndex::TPRTree;
39 
41 = default;
42 
43 Index::Index(SpatialIndex::TPRTree::TPRTree* pTree, id_type id, uint32_t level) : Node(pTree, id, level, pTree->m_indexCapacity)
44 {
45 }
46 
47 NodePtr Index::chooseSubtree(const MovingRegion& mbr, uint32_t insertionLevel, std::stack<id_type>& pathBuffer)
48 {
49  if (m_level == insertionLevel) return NodePtr(this, &(m_pTree->m_indexPool));
50 
51  pathBuffer.push(m_identifier);
52 
53  uint32_t child = 0;
54 
55  switch (m_pTree->m_treeVariant)
56  {
57  case TPRV_RSTAR:
58  if (m_level == 1)
59  {
60  // if this node points to leaves...
61  child = findLeastOverlap(mbr);
62  }
63  else
64  {
65  child = findLeastEnlargement(mbr);
66  }
67  break;
68  default:
69  throw Tools::NotSupportedException("Index::chooseSubtree: Tree variant not supported.");
70  }
71  assert(child != std::numeric_limits<uint32_t>::max());
72 
73  NodePtr n = m_pTree->readNode(m_pIdentifier[child]);
74  NodePtr ret = n->chooseSubtree(mbr, insertionLevel, pathBuffer);
75  assert(n.unique());
76  if (ret.get() == n.get()) n.relinquish();
77 
78  return ret;
79 }
80 
81 NodePtr Index::findLeaf(const MovingRegion& mbr, id_type id, std::stack<id_type>& pathBuffer)
82 {
83  pathBuffer.push(m_identifier);
84 
85  for (uint32_t cChild = 0; cChild < m_children; ++cChild)
86  {
87  if (m_ptrMBR[cChild]->containsRegionAfterTime(m_pTree->m_currentTime, mbr))
88  {
89  NodePtr n = m_pTree->readNode(m_pIdentifier[cChild]);
90  NodePtr l = n->findLeaf(mbr, id, pathBuffer);
91  if (n.get() == l.get()) n.relinquish();
92  if (l.get() != nullptr) return l;
93  }
94  }
95 
96  pathBuffer.pop();
97 
98  return NodePtr();
99 }
100 
101 void Index::split(uint32_t dataLength, uint8_t* pData, MovingRegion& mbr, id_type id, NodePtr& pLeft, NodePtr& pRight)
102 {
103  ++(m_pTree->m_stats.m_splits);
104 
105  std::vector<uint32_t> g1, g2;
106 
107  switch (m_pTree->m_treeVariant)
108  {
109  case TPRV_RSTAR:
110  rstarSplit(dataLength, pData, mbr, id, g1, g2);
111  break;
112  default:
113  throw Tools::NotSupportedException("Index::split: Tree variant not supported.");
114  }
115 
116  pLeft = m_pTree->m_indexPool.acquire();
117  pRight = m_pTree->m_indexPool.acquire();
118 
119  if (pLeft.get() == nullptr) pLeft = NodePtr(new Index(m_pTree, m_identifier, m_level), &(m_pTree->m_indexPool));
120  if (pRight.get() == nullptr) pRight = NodePtr(new Index(m_pTree, -1, m_level), &(m_pTree->m_indexPool));
121 
122  pLeft->m_nodeMBR = m_pTree->m_infiniteRegion;
123  pRight->m_nodeMBR = m_pTree->m_infiniteRegion;
124 
125  uint32_t cIndex;
126 
127  for (cIndex = 0; cIndex < g1.size(); ++cIndex)
128  {
129  pLeft->insertEntry(0, nullptr, *(m_ptrMBR[g1[cIndex]]), m_pIdentifier[g1[cIndex]]);
130  }
131 
132  for (cIndex = 0; cIndex < g2.size(); ++cIndex)
133  {
134  pRight->insertEntry(0, nullptr, *(m_ptrMBR[g2[cIndex]]), m_pIdentifier[g2[cIndex]]);
135  }
136 }
137 
138 uint32_t Index::findLeastEnlargement(const MovingRegion& r) const
139 {
140  double area = std::numeric_limits<double>::max();
141  uint32_t best = std::numeric_limits<uint32_t>::max();
142 
143  MovingRegionPtr t = m_pTree->m_regionPool.acquire();
144  Tools::Interval ivT(m_pTree->m_currentTime, m_pTree->m_currentTime + m_pTree->m_horizon);
145 
146  for (uint32_t cChild = 0; cChild < m_children; ++cChild)
147  {
148  // I need the combined region from current time up to infinity here.
149  m_ptrMBR[cChild]->getCombinedRegionAfterTime(ivT.getLowerBound(), *t, r);
150 
151  double a = m_ptrMBR[cChild]->getAreaInTime(ivT);
152  double b = t->getAreaInTime(ivT);
153  double enl = b - a;
154 
155  if (enl < area)
156  {
157  area = enl;
158  best = cChild;
159  }
160  else if (enl == area)
161  {
162  // this will rarely happen, so compute best area on the fly only
163  // when necessary.
164  if (a < m_ptrMBR[best]->getAreaInTime(ivT)) best = cChild;
165  }
166  }
167 
168  return best;
169 }
170 
171 uint32_t Index::findLeastOverlap(const MovingRegion& r) const
172 {
173  OverlapEntry** entries = new OverlapEntry*[m_children];
174 
175  double leastOverlap = std::numeric_limits<double>::max();
176  double me = std::numeric_limits<double>::max();
177  OverlapEntry* best = nullptr;
178 
179  Tools::Interval ivT(m_pTree->m_currentTime, m_pTree->m_currentTime + m_pTree->m_horizon);
180 
181  // find combined region and enlargement of every entry and store it.
182  for (uint32_t cChild = 0; cChild < m_children; ++cChild)
183  {
184  try
185  {
186  entries[cChild] = new OverlapEntry();
187  }
188  catch (...)
189  {
190  for (uint32_t i = 0; i < cChild; ++i) delete entries[i];
191  delete[] entries;
192  throw;
193  }
194 
195  entries[cChild]->m_index = cChild;
196  entries[cChild]->m_original = m_ptrMBR[cChild];
197  entries[cChild]->m_combined = m_pTree->m_regionPool.acquire();
198  m_ptrMBR[cChild]->getCombinedRegionAfterTime(m_pTree->m_currentTime, *(entries[cChild]->m_combined), r);
199  entries[cChild]->m_oa = entries[cChild]->m_original->getAreaInTime(ivT);
200  entries[cChild]->m_ca = entries[cChild]->m_combined->getAreaInTime(ivT);
201  entries[cChild]->m_enlargement = entries[cChild]->m_ca - entries[cChild]->m_oa;
202 
203  if (entries[cChild]->m_enlargement < me)
204  {
205  me = entries[cChild]->m_enlargement;
206  best = entries[cChild];
207  }
208  else if (entries[cChild]->m_enlargement == me && entries[cChild]->m_oa < best->m_oa)
209  {
210  best = entries[cChild];
211  }
212  }
213 
214  if (me < -std::numeric_limits<double>::epsilon() || me > std::numeric_limits<double>::epsilon())
215  {
216  uint32_t cIterations;
217 
218  if (m_children > m_pTree->m_nearMinimumOverlapFactor)
219  {
220  // sort entries in increasing order of enlargement.
221  ::qsort(entries, m_children,
222  sizeof(OverlapEntry*),
224  assert(entries[0]->m_enlargement <= entries[m_children - 1]->m_enlargement);
225 
226  cIterations = m_pTree->m_nearMinimumOverlapFactor;
227  }
228  else
229  {
230  cIterations = m_children;
231  }
232 
233  // calculate overlap of most important original entries (near minimum overlap cost).
234  for (uint32_t cIndex = 0; cIndex < cIterations; ++cIndex)
235  {
236  double dif = 0.0;
237  OverlapEntry* e = entries[cIndex];
238 
239  for (uint32_t cChild = 0; cChild < m_children; ++cChild)
240  {
241  if (e->m_index != cChild)
242  {
243  double f = e->m_combined->getIntersectingAreaInTime(ivT, *(m_ptrMBR[cChild]));
244  if (f != 0.0) dif += f - e->m_original->getIntersectingAreaInTime(ivT, *(m_ptrMBR[cChild]));
245  }
246  } // for (cChild)
247 
248  if (dif < leastOverlap)
249  {
250  leastOverlap = dif;
251  best = entries[cIndex];
252  }
253  else if (dif == leastOverlap)
254  {
255  if (e->m_enlargement == best->m_enlargement)
256  {
257  // keep the one with least area.
258  if (e->m_original->getAreaInTime(ivT) < best->m_original->getAreaInTime(ivT)) best = entries[cIndex];
259  }
260  else
261  {
262  // keep the one with least enlargement.
263  if (e->m_enlargement < best->m_enlargement) best = entries[cIndex];
264  }
265  }
266  } // for (cIndex)
267  }
268 
269  uint32_t ret = best->m_index;
270 
271  for (uint32_t cChild = 0; cChild < m_children; ++cChild)
272  {
273  delete entries[cChild];
274  }
275  delete[] entries;
276 
277  return ret;
278 }
279 
280 void Index::adjustTree(Node* n, std::stack<id_type>& pathBuffer)
281 {
282  ++(m_pTree->m_stats.m_adjustments);
283 
284  // find entry pointing to old node;
285  uint32_t child;
286  for (child = 0; child < m_children; ++child)
287  {
288  if (m_pIdentifier[child] == n->m_identifier) break;
289  }
290  assert(child < m_children);
291 
292  // MBR needs recalculation if either:
293  // 1. the NEW child MBR is not contained.
294  // 2. the OLD child MBR is touching.
295  //Tools::Interval ivT(m_pTree->m_currentTime, m_pTree->m_currentTime + m_pTree->m_horizon);
296  //bool bContained = m_nodeMBR.containsRegionInTime(ivT, n->m_nodeMBR);
297 
298  *(m_ptrMBR[child]) = n->m_nodeMBR;
299 
300  //if (! bContained)
301  //{
302  // update the MBR at the current time anyway, to make tighter.
303  m_nodeMBR.m_startTime = m_pTree->m_currentTime;
304 
305  for (uint32_t cDim = 0; cDim < m_nodeMBR.m_dimension; ++cDim)
306  {
307  m_nodeMBR.m_pLow[cDim] = std::numeric_limits<double>::max();
308  m_nodeMBR.m_pHigh[cDim] = -std::numeric_limits<double>::max();
309  m_nodeMBR.m_pVLow[cDim] = std::numeric_limits<double>::max();
310  m_nodeMBR.m_pVHigh[cDim] = -std::numeric_limits<double>::max();
311 
312  for (uint32_t cChild = 0; cChild < m_children; ++cChild)
313  {
314  m_nodeMBR.m_pLow[cDim] = std::min(m_nodeMBR.m_pLow[cDim], m_ptrMBR[cChild]->getExtrapolatedLow(cDim, m_nodeMBR.m_startTime));
315  m_nodeMBR.m_pHigh[cDim] = std::max(m_nodeMBR.m_pHigh[cDim], m_ptrMBR[cChild]->getExtrapolatedHigh(cDim, m_nodeMBR.m_startTime));
316  m_nodeMBR.m_pVLow[cDim] = std::min(m_nodeMBR.m_pVLow[cDim], m_ptrMBR[cChild]->m_pVLow[cDim]);
317  m_nodeMBR.m_pVHigh[cDim] = std::max(m_nodeMBR.m_pVHigh[cDim], m_ptrMBR[cChild]->m_pVHigh[cDim]);
318  }
319  m_nodeMBR.m_pLow[cDim] -= 2.0 * std::numeric_limits<double>::epsilon();
320  m_nodeMBR.m_pHigh[cDim] += 2.0 * std::numeric_limits<double>::epsilon();
321  }
322  //}
323 
324 #ifndef NDEBUG
325  for (uint32_t cChild = 0; cChild < m_children; ++cChild)
326  {
327  assert(m_nodeMBR.containsRegionAfterTime(m_pTree->m_currentTime, *(m_ptrMBR[cChild])) == true);
328  }
329 #endif
330 
331  m_pTree->writeNode(this);
332 
333  if ( ! pathBuffer.empty())
334  {
335  id_type cParent = pathBuffer.top(); pathBuffer.pop();
336  NodePtr ptrN = m_pTree->readNode(cParent);
337  Index* p = static_cast<Index*>(ptrN.get());
338  p->adjustTree(this, pathBuffer);
339  }
340 }
341 
342 void Index::adjustTree(Node* n1, Node* n2, std::stack<id_type>& pathBuffer, uint8_t* overflowTable)
343 {
344  ++(m_pTree->m_stats.m_adjustments);
345 
346  // find entry pointing to old node;
347  uint32_t child;
348  for (child = 0; child < m_children; ++child)
349  {
350  if (m_pIdentifier[child] == n1->m_identifier) break;
351  }
352  assert(child < m_children);
353 
354  // MBR needs recalculation if either:
355  // 1. the NEW child MBR is not contained.
356  // 2. the OLD child MBR is touching.
357  //Tools::Interval ivT(m_pTree->m_currentTime, m_pTree->m_currentTime + m_pTree->m_horizon);
358  //bool bContained = m_nodeMBR.containsRegionInTime(ivT, n1->m_nodeMBR);
359 
360  *(m_ptrMBR[child]) = n1->m_nodeMBR;
361 
362  //if (! bContaied)
363  //{
364  m_nodeMBR.m_startTime = m_pTree->m_currentTime;
365 
366  for (uint32_t cDim = 0; cDim < m_nodeMBR.m_dimension; ++cDim)
367  {
368  m_nodeMBR.m_pLow[cDim] = std::numeric_limits<double>::max();
369  m_nodeMBR.m_pHigh[cDim] = -std::numeric_limits<double>::max();
370  m_nodeMBR.m_pVLow[cDim] = std::numeric_limits<double>::max();
371  m_nodeMBR.m_pVHigh[cDim] = -std::numeric_limits<double>::max();
372 
373  for (uint32_t cChild = 0; cChild < m_children; ++cChild)
374  {
375  m_nodeMBR.m_pLow[cDim] = std::min(m_nodeMBR.m_pLow[cDim], m_ptrMBR[cChild]->getExtrapolatedLow(cDim, m_nodeMBR.m_startTime));
376  m_nodeMBR.m_pHigh[cDim] = std::max(m_nodeMBR.m_pHigh[cDim], m_ptrMBR[cChild]->getExtrapolatedHigh(cDim, m_nodeMBR.m_startTime));
377  m_nodeMBR.m_pVLow[cDim] = std::min(m_nodeMBR.m_pVLow[cDim], m_ptrMBR[cChild]->m_pVLow[cDim]);
378  m_nodeMBR.m_pVHigh[cDim] = std::max(m_nodeMBR.m_pVHigh[cDim], m_ptrMBR[cChild]->m_pVHigh[cDim]);
379  }
380  m_nodeMBR.m_pLow[cDim] -= 2.0 * std::numeric_limits<double>::epsilon();
381  m_nodeMBR.m_pHigh[cDim] += 2.0 * std::numeric_limits<double>::epsilon();
382  }
383  //}
384 
385 #ifndef NDEBUG
386  for (uint32_t cChild = 0; cChild < m_children; ++cChild)
387  {
388  assert(m_nodeMBR.containsRegionAfterTime(m_pTree->m_currentTime, *(m_ptrMBR[cChild])) == true);
389  }
390 #endif
391 
392  // No write necessary here. insertData will write the node if needed.
393  //m_pTree->writeNode(this);
394 
395  bool bAdjusted = insertData(0, nullptr, n2->m_nodeMBR, n2->m_identifier, pathBuffer, overflowTable);
396 
397  // if n2 is contained in the node and there was no split or reinsert,
398  // we need to adjust only if recalculation took place.
399  // In all other cases insertData above took care of adjustment.
400  if (! bAdjusted && ! pathBuffer.empty())
401  {
402  id_type cParent = pathBuffer.top(); pathBuffer.pop();
403  NodePtr ptrN = m_pTree->readNode(cParent);
404  Index* p = static_cast<Index*>(ptrN.get());
405  p->adjustTree(this, pathBuffer);
406  }
407 }
uint32_t findLeastEnlargement(const Region &) const
Definition: rtree/Index.cc:145
void adjustTree(Node *, std::stack< id_type > &, bool force=false)
Definition: rtree/Index.cc:283
static int compareEntries(const void *pv1, const void *pv2)
NodePtr chooseSubtree(const Region &mbr, uint32_t level, std::stack< id_type > &pathBuffer) override
Definition: rtree/Index.cc:46
Index(const Tools::PropertySet &poProperties)
Definition: capi/Index.cc:76
uint32_t findLeastOverlap(const Region &) const
Definition: rtree/Index.cc:176
double getAreaInTime() const override
bool unique() const noexcept
Definition: PoolPointer.h:56
X * get() const noexcept
Definition: PoolPointer.h:55
Tools::PoolPointer< Node > NodePtr
Definition: rtree/Node.h:40
Index(RTree *pTree, id_type id, uint32_t level)
Definition: rtree/Index.cc:42
void split(uint32_t dataLength, uint8_t *pData, Region &mbr, id_type id, NodePtr &left, NodePtr &right) override
Definition: rtree/Index.cc:104
NodePtr findLeaf(const Region &mbr, id_type id, std::stack< id_type > &pathBuffer) override
Definition: rtree/Index.cc:84
int64_t id_type
Definition: SpatialIndex.h:41
void relinquish() noexcept
Definition: PoolPointer.h:57