libspatialindex API Reference  (git-trunk)
mvrtree/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 "MVRTree.h"
33 #include "Node.h"
34 #include "Leaf.h"
35 #include "Index.h"
36 
37 using namespace SpatialIndex;
38 using namespace SpatialIndex::MVRTree;
39 
41 = default;
42 
43 Index::Index(SpatialIndex::MVRTree::MVRTree* pTree, id_type id, uint32_t level) : Node(pTree, id, level, pTree->m_indexCapacity)
44 {
45 }
46 
47 NodePtr Index::chooseSubtree(const TimeRegion& 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 RV_LINEAR:
58  case RV_QUADRATIC:
59  child = findLeastEnlargement(mbr);
60  break;
61  case RV_RSTAR:
62  if (m_level == 1)
63  {
64  // if this node points to leaves...
65  child = findLeastOverlap(mbr);
66  }
67  else
68  {
69  child = findLeastEnlargement(mbr);
70  }
71  break;
72  default:
73  throw Tools::NotSupportedException("Index::chooseSubtree: Tree variant not supported.");
74  }
75  assert (child != std::numeric_limits<uint32_t>::max());
76 
77  NodePtr n = m_pTree->readNode(m_pIdentifier[child]);
78  NodePtr ret = n->chooseSubtree(mbr, insertionLevel, pathBuffer);
79  assert(n.unique());
80  if (ret.get() == n.get()) n.relinquish();
81 
82  return ret;
83 }
84 
85 NodePtr Index::findLeaf(const TimeRegion& mbr, id_type id, std::stack<id_type>& pathBuffer)
86 {
87  pathBuffer.push(m_identifier);
88 
89  for (uint32_t cChild = 0; cChild < m_children; ++cChild)
90  {
91  // check live nodes only.
92  if (m_ptrMBR[cChild]->m_endTime < std::numeric_limits<double>::max()) continue;
93  //if (m_ptrMBR[cChild]->m_endTime < std::numeric_limits<double>::max() ||
94  // m_ptrMBR[cChild]->m_startTime > mbr.m_startTime) continue;
95 
96  if (m_ptrMBR[cChild]->containsRegion(mbr))
97  {
98  NodePtr n = m_pTree->readNode(m_pIdentifier[cChild]);
99  NodePtr l = n->findLeaf(mbr, id, pathBuffer);
100  if (n.get() == l.get()) n.relinquish();
101  if (l.get() != nullptr) return l;
102  }
103  }
104 
105  pathBuffer.pop();
106 
107  return NodePtr();
108 }
109 
110 void Index::split(
111  uint32_t dataLength, uint8_t* pData, TimeRegion& mbr, id_type id, NodePtr& pLeft, NodePtr& pRight,
112  TimeRegion& mbr2, id_type id2, bool bInsertMbr2)
113 {
114  ++(m_pTree->m_stats.m_u64Splits);
115 
116  std::vector<uint32_t> g1, g2;
117 
118  switch (m_pTree->m_treeVariant)
119  {
120  case RV_LINEAR:
121  case RV_QUADRATIC:
122  rtreeSplit(dataLength, pData, mbr, id, g1, g2, mbr2, id2, bInsertMbr2);
123  break;
124  case RV_RSTAR:
125  rstarSplit(dataLength, pData, mbr, id, g1, g2, mbr2, id2, bInsertMbr2);
126  break;
127  default:
128  throw Tools::NotSupportedException("Index::split: Tree variant not supported.");
129  }
130 
131  pLeft = m_pTree->m_indexPool.acquire();
132  pRight = m_pTree->m_indexPool.acquire();
133 
134  if (pLeft.get() == nullptr) pLeft = NodePtr(new Index(m_pTree, m_identifier, m_level), &(m_pTree->m_indexPool));
135  if (pRight.get() == nullptr) pRight = NodePtr(new Index(m_pTree, -1, m_level), &(m_pTree->m_indexPool));
136 
137  pLeft->m_nodeMBR = m_pTree->m_infiniteRegion;
138  pRight->m_nodeMBR = m_pTree->m_infiniteRegion;
139 
140  uint32_t cIndex;
141 
142  for (cIndex = 0; cIndex < g1.size(); ++cIndex)
143  {
144  pLeft->insertEntry(0, nullptr, *(m_ptrMBR[g1[cIndex]]), m_pIdentifier[g1[cIndex]]);
145  }
146 
147  for (cIndex = 0; cIndex < g2.size(); ++cIndex)
148  {
149  pRight->insertEntry(0, nullptr, *(m_ptrMBR[g2[cIndex]]), m_pIdentifier[g2[cIndex]]);
150  }
151 }
152 
153 uint32_t Index::findLeastEnlargement(const TimeRegion& r) const
154 {
155  double area = std::numeric_limits<double>::max();
156  uint32_t best = std::numeric_limits<uint32_t>::max();
157 
158  TimeRegionPtr t = m_pTree->m_regionPool.acquire();
159 
160  for (uint32_t cChild = 0; cChild < m_children; ++cChild)
161  {
162  // if this child is already dead do not consider it.
163  if (m_ptrMBR[cChild]->m_endTime <= r.m_startTime) continue;
164 
165  m_ptrMBR[cChild]->getCombinedRegion(*t, r);
166 
167  double a = m_ptrMBR[cChild]->getArea();
168  double enl = t->getArea() - a;
169 
170  if (enl < area)
171  {
172  area = enl;
173  best = cChild;
174  }
175  else if (
176  enl > area - std::numeric_limits<double>::epsilon() &&
177  enl < area + std::numeric_limits<double>::epsilon())
178  {
179  if (a < m_ptrMBR[best]->getArea()) best = cChild;
180  }
181  }
182 
183  return best;
184 }
185 
186 uint32_t Index::findLeastOverlap(const TimeRegion& r) const
187 {
188  OverlapEntry** entries = new OverlapEntry*[m_children];
189 
190  double leastOverlap = std::numeric_limits<double>::max();
191  double me = std::numeric_limits<double>::max();
192  OverlapEntry* best = nullptr;
193  uint32_t cLiveEntries = 0;
194 
195  // find combined region and enlargement of every entry and store it.
196  for (uint32_t cChild = 0; cChild < m_children; ++cChild)
197  {
198  if (m_ptrMBR[cChild]->m_endTime <= r.m_startTime) continue;
199 
200  try
201  {
202  entries[cLiveEntries] = new OverlapEntry();
203  }
204  catch (...)
205  {
206  for (uint32_t i = 0; i < cLiveEntries; ++i) delete entries[i];
207  delete[] entries;
208  throw;
209  }
210 
211  entries[cLiveEntries]->m_index = cChild;
212  entries[cLiveEntries]->m_original = m_ptrMBR[cChild];
213  entries[cLiveEntries]->m_combined = m_pTree->m_regionPool.acquire();
214  m_ptrMBR[cChild]->getCombinedRegion(*(entries[cLiveEntries]->m_combined), r);
215  entries[cLiveEntries]->m_oa = entries[cLiveEntries]->m_original->getArea();
216  entries[cLiveEntries]->m_ca = entries[cLiveEntries]->m_combined->getArea();
217  entries[cLiveEntries]->m_enlargement = entries[cLiveEntries]->m_ca - entries[cLiveEntries]->m_oa;
218 
219  if (entries[cLiveEntries]->m_enlargement < me)
220  {
221  me = entries[cLiveEntries]->m_enlargement;
222  best = entries[cLiveEntries];
223  }
224  else if (entries[cLiveEntries]->m_enlargement == me && entries[cLiveEntries]->m_oa < best->m_oa)
225  {
226  best = entries[cLiveEntries];
227  }
228  ++cLiveEntries;
229  }
230 
231  if (me < -std::numeric_limits<double>::epsilon() || me > std::numeric_limits<double>::epsilon())
232  {
233  uint32_t cIterations;
234 
235  if (cLiveEntries > m_pTree->m_nearMinimumOverlapFactor)
236  {
237  // sort entries in increasing order of enlargement.
238  ::qsort(entries, cLiveEntries,
239  sizeof(OverlapEntry*),
240  OverlapEntry::compareEntries);
241  assert(entries[0]->m_enlargement <= entries[m_children - 1]->m_enlargement);
242 
243  cIterations = m_pTree->m_nearMinimumOverlapFactor;
244  }
245  else
246  {
247  cIterations = cLiveEntries;
248  }
249 
250  // calculate overlap of most important original entries (near minimum overlap cost).
251  for (uint32_t cIndex = 0; cIndex < cIterations; ++cIndex)
252  {
253  double dif = 0.0;
254  OverlapEntry* e = entries[cIndex];
255 
256  for (uint32_t cChild = 0; cChild < cLiveEntries; ++cChild)
257  {
258  if (cIndex != cChild)
259  {
260  double f = e->m_combined->getIntersectingArea(*(entries[cChild]->m_original));
261  if (f != 0.0) dif += f - e->m_original->getIntersectingArea(*(entries[cChild]->m_original));
262  }
263  } // for (cChild)
264 
265  if (dif < leastOverlap)
266  {
267  leastOverlap = dif;
268  best = e;
269  }
270  else if (dif == leastOverlap)
271  {
272  if (e->m_enlargement == best->m_enlargement)
273  {
274  // keep the one with least area.
275  if (e->m_original->getArea() < best->m_original->getArea()) best = e;
276  }
277  else
278  {
279  // keep the one with least enlargement.
280  if (e->m_enlargement < best->m_enlargement) best = e;
281  }
282  }
283  } // for (cIndex)
284  }
285 
286  uint32_t ret = best->m_index;
287 
288  for (uint32_t cChild = 0; cChild < cLiveEntries; ++cChild)
289  {
290  delete entries[cChild];
291  }
292  delete[] entries;
293 
294  return ret;
295 }
296 
297 void Index::adjustTree(Node* n, std::stack<id_type>& pathBuffer)
298 {
299  ++(m_pTree->m_stats.m_u64Adjustments);
300 
301  // find entry pointing to old node;
302  uint32_t child;
303  for (child = 0; child < m_children; ++child)
304  {
305  if (m_pIdentifier[child] == n->m_identifier) break;
306  }
307 
308  // MBR needs recalculation if either:
309  // 1. the NEW child MBR is not contained.
310  // 2. the OLD child MBR is touching.
311  bool bContained = m_nodeMBR.containsRegion(n->m_nodeMBR);
312  bool bTouches = m_nodeMBR.touchesRegion(*(m_ptrMBR[child]));
313  bool bRecompute = (! bContained || (bTouches && m_pTree->m_bTightMBRs));
314 
315  // we should not adjust time here
316  double st = m_ptrMBR[child]->m_startTime;
317  double en = m_ptrMBR[child]->m_endTime;
318  *(m_ptrMBR[child]) = n->m_nodeMBR;
319  m_ptrMBR[child]->m_startTime = st;
320  m_ptrMBR[child]->m_endTime = en;
321 
322  if (bRecompute)
323  {
324  // no need to update times here. The inserted MBR is younger than all nodes.
325 
326  for (uint32_t cDim = 0; cDim < m_nodeMBR.m_dimension; ++cDim)
327  {
328  m_nodeMBR.m_pLow[cDim] = std::numeric_limits<double>::max();
329  m_nodeMBR.m_pHigh[cDim] = -std::numeric_limits<double>::max();
330 
331  for (uint32_t cChild = 0; cChild < m_children; ++cChild)
332  {
333  m_nodeMBR.m_pLow[cDim] = std::min(m_nodeMBR.m_pLow[cDim], m_ptrMBR[cChild]->m_pLow[cDim]);
334  m_nodeMBR.m_pHigh[cDim] = std::max(m_nodeMBR.m_pHigh[cDim], m_ptrMBR[cChild]->m_pHigh[cDim]);
335  }
336  }
337  }
338 
339  m_pTree->writeNode(this);
340 
341  if (bRecompute && (! pathBuffer.empty()))
342  {
343  id_type cParent = pathBuffer.top(); pathBuffer.pop();
344  NodePtr ptrN = m_pTree->readNode(cParent);
345  Index* p = static_cast<Index*>(ptrN.get());
346  p->adjustTree(this, pathBuffer);
347  }
348 }
349 
350 void Index::adjustTree(Node* n, Node* nn, std::stack<id_type>& pathBuffer)
351 {
352  ++(m_pTree->m_stats.m_u64Adjustments);
353 
354  // find entry pointing to old node;
355  uint32_t child, child2 = m_capacity;
356  for (child = 0; child < m_children; ++child)
357  {
358  if (m_pIdentifier[child] == nn->m_identifier) child2 = child;
359  if (m_pIdentifier[child] == n->m_identifier) break;
360  }
361 
362  if (child2 == m_capacity)
363  {
364  for (child2 = child + 1; child2 < m_children; ++child2)
365  {
366  if (m_pIdentifier[child2] == nn->m_identifier) break;
367  }
368  }
369 
370  // MBR needs recalculation if either:
371  // 1. the NEW child MBR is not contained.
372  // 2. the OLD child MBR is touching.
373  // 3. the SIBLING MBR is touching.
374  bool b1 = m_nodeMBR.containsRegion(n->m_nodeMBR);
375  bool b2 = m_nodeMBR.touchesRegion(*(m_ptrMBR[child]));
376  bool b3 = m_nodeMBR.touchesRegion(*(m_ptrMBR[child2]));
377  bool bRecompute = (! b1) || ((b2 || b3) && m_pTree->m_bTightMBRs);
378 
379  // we should not adjust time here
380  double st = m_ptrMBR[child]->m_startTime;
381  double en = m_ptrMBR[child]->m_endTime;
382  *(m_ptrMBR[child]) = n->m_nodeMBR;
383  m_ptrMBR[child]->m_startTime = st;
384  m_ptrMBR[child]->m_endTime = en;
385 
386  st = m_ptrMBR[child2]->m_startTime;
387  en = m_ptrMBR[child2]->m_endTime;
388  *(m_ptrMBR[child2]) = nn->m_nodeMBR;
389  m_ptrMBR[child2]->m_startTime = st;
390  m_ptrMBR[child2]->m_endTime = en;
391 
392  if (bRecompute)
393  {
394  // no need to update times here. The inserted MBR is younger than all nodes.
395 
396  for (uint32_t cDim = 0; cDim < m_nodeMBR.m_dimension; ++cDim)
397  {
398  m_nodeMBR.m_pLow[cDim] = std::numeric_limits<double>::max();
399  m_nodeMBR.m_pHigh[cDim] = -std::numeric_limits<double>::max();
400 
401  for (uint32_t cChild = 0; cChild < m_children; ++cChild)
402  {
403  m_nodeMBR.m_pLow[cDim] = std::min(m_nodeMBR.m_pLow[cDim], m_ptrMBR[cChild]->m_pLow[cDim]);
404  m_nodeMBR.m_pHigh[cDim] = std::max(m_nodeMBR.m_pHigh[cDim], m_ptrMBR[cChild]->m_pHigh[cDim]);
405  }
406  }
407  }
408 
409  m_pTree->writeNode(this);
410 
411  if (bRecompute && (! pathBuffer.empty()))
412  {
413  id_type cParent = pathBuffer.top(); pathBuffer.pop();
414  NodePtr ptrN = m_pTree->readNode(cParent);
415  Index* p = static_cast<Index*>(ptrN.get());
416  p->adjustTree(this, pathBuffer);
417  }
418 }
virtual void getCombinedRegion(Region &out, const Region &in) const
Definition: Region.cc:503
double getArea() const override
Definition: Region.cc:218
bool unique() const noexcept
Definition: PoolPointer.h:56
X * get() const noexcept
Definition: PoolPointer.h:55
void relinquish() noexcept
Definition: PoolPointer.h:57
Tools::PoolPointer< Node > NodePtr
Definition: mvrtree/Node.h:40
int64_t id_type
Definition: SpatialIndex.h:41