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