libspatialindex API Reference  (git-trunk)
rtree/Node.cc
Go to the documentation of this file.
1 /******************************************************************************
2  * Project: libspatialindex - A C++ library for spatial indexing
3  * Author: Marios Hadjieleftheriou, mhadji@gmail.com
4  ******************************************************************************
5  * Copyright (c) 2002, Marios Hadjieleftheriou
6  *
7  * All rights reserved.
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining a
10  * copy of this software and associated documentation files (the "Software"),
11  * to deal in the Software without restriction, including without limitation
12  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13  * and/or sell copies of the Software, and to permit persons to whom the
14  * Software is furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be included
17  * in all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25  * DEALINGS IN THE SOFTWARE.
26 ******************************************************************************/
27 
28 #include <cstring>
29 #include <cmath>
30 #include <limits>
31 
33 
34 #include "RTree.h"
35 #include "Node.h"
36 #include "Index.h"
37 
38 using namespace SpatialIndex;
39 using namespace SpatialIndex::RTree;
40 
41 //
42 // Tools::IObject interface
43 //
45 {
46  throw Tools::NotSupportedException("IObject::clone should never be called.");
47 }
48 
49 //
50 // Tools::ISerializable interface
51 //
53 {
54  return
55  (sizeof(uint32_t) +
56  sizeof(uint32_t) +
57  sizeof(uint32_t) +
58  (m_children * (m_pTree->m_dimension * sizeof(double) * 2 + sizeof(id_type) + sizeof(uint32_t))) +
59  m_totalDataLength +
60  (2 * m_pTree->m_dimension * sizeof(double)));
61 }
62 
63 void Node::loadFromByteArray(const uint8_t* ptr)
64 {
65  m_nodeMBR = m_pTree->m_infiniteRegion;
66 
67  // skip the node type information, it is not needed.
68  ptr += sizeof(uint32_t);
69 
70  memcpy(&m_level, ptr, sizeof(uint32_t));
71  ptr += sizeof(uint32_t);
72 
73  memcpy(&m_children, ptr, sizeof(uint32_t));
74  ptr += sizeof(uint32_t);
75 
76  for (uint32_t u32Child = 0; u32Child < m_children; ++u32Child)
77  {
78  m_ptrMBR[u32Child] = m_pTree->m_regionPool.acquire();
79  *(m_ptrMBR[u32Child]) = m_pTree->m_infiniteRegion;
80 
81  memcpy(m_ptrMBR[u32Child]->m_pLow, ptr, m_pTree->m_dimension * sizeof(double));
82  ptr += m_pTree->m_dimension * sizeof(double);
83  memcpy(m_ptrMBR[u32Child]->m_pHigh, ptr, m_pTree->m_dimension * sizeof(double));
84  ptr += m_pTree->m_dimension * sizeof(double);
85  memcpy(&(m_pIdentifier[u32Child]), ptr, sizeof(id_type));
86  ptr += sizeof(id_type);
87 
88  memcpy(&(m_pDataLength[u32Child]), ptr, sizeof(uint32_t));
89  ptr += sizeof(uint32_t);
90 
91  if (m_pDataLength[u32Child] > 0)
92  {
93  m_totalDataLength += m_pDataLength[u32Child];
94  m_pData[u32Child] = new uint8_t[m_pDataLength[u32Child]];
95  memcpy(m_pData[u32Child], ptr, m_pDataLength[u32Child]);
96  ptr += m_pDataLength[u32Child];
97  }
98  else
99  {
100  m_pData[u32Child] = nullptr;
101  }
102 
103  //m_nodeMBR.combineRegion(*(m_ptrMBR[u32Child]));
104  }
105 
106  memcpy(m_nodeMBR.m_pLow, ptr, m_pTree->m_dimension * sizeof(double));
107  ptr += m_pTree->m_dimension * sizeof(double);
108  memcpy(m_nodeMBR.m_pHigh, ptr, m_pTree->m_dimension * sizeof(double));
109  //ptr += m_pTree->m_dimension * sizeof(double);
110 }
111 
112 void Node::storeToByteArray(uint8_t** data, uint32_t& len)
113 {
114  len = getByteArraySize();
115 
116  *data = new uint8_t[len];
117  uint8_t* ptr = *data;
118 
119  uint32_t nodeType;
120 
121  if (m_level == 0) nodeType = PersistentLeaf;
122  else nodeType = PersistentIndex;
123 
124  memcpy(ptr, &nodeType, sizeof(uint32_t));
125  ptr += sizeof(uint32_t);
126 
127  memcpy(ptr, &m_level, sizeof(uint32_t));
128  ptr += sizeof(uint32_t);
129 
130  memcpy(ptr, &m_children, sizeof(uint32_t));
131  ptr += sizeof(uint32_t);
132 
133  for (uint32_t u32Child = 0; u32Child < m_children; ++u32Child)
134  {
135  memcpy(ptr, m_ptrMBR[u32Child]->m_pLow, m_pTree->m_dimension * sizeof(double));
136  ptr += m_pTree->m_dimension * sizeof(double);
137  memcpy(ptr, m_ptrMBR[u32Child]->m_pHigh, m_pTree->m_dimension * sizeof(double));
138  ptr += m_pTree->m_dimension * sizeof(double);
139  memcpy(ptr, &(m_pIdentifier[u32Child]), sizeof(id_type));
140  ptr += sizeof(id_type);
141 
142  memcpy(ptr, &(m_pDataLength[u32Child]), sizeof(uint32_t));
143  ptr += sizeof(uint32_t);
144 
145  if (m_pDataLength[u32Child] > 0)
146  {
147  memcpy(ptr, m_pData[u32Child], m_pDataLength[u32Child]);
148  ptr += m_pDataLength[u32Child];
149  }
150  }
151 
152  // store the node MBR for efficiency. This increases the node size a little bit.
153  memcpy(ptr, m_nodeMBR.m_pLow, m_pTree->m_dimension * sizeof(double));
154  ptr += m_pTree->m_dimension * sizeof(double);
155  memcpy(ptr, m_nodeMBR.m_pHigh, m_pTree->m_dimension * sizeof(double));
156  //ptr += m_pTree->m_dimension * sizeof(double);
157 
158  assert(len == (ptr - *data) + m_pTree->m_dimension * sizeof(double));
159 }
160 
161 //
162 // SpatialIndex::IEntry interface
163 //
165 {
166  return m_identifier;
167 }
168 
169 void Node::getShape(IShape** out) const
170 {
171  *out = new Region(m_nodeMBR);
172 }
173 
174 //
175 // SpatialIndex::INode interface
176 //
177 uint32_t Node::getChildrenCount() const
178 {
179  return m_children;
180 }
181 
183 {
184  if (index >= m_children) throw Tools::IndexOutOfBoundsException(index);
185 
186  return m_pIdentifier[index];
187 }
188 
189 void Node::getChildShape(uint32_t index, IShape** out) const
190 {
191  if (index >= m_children) throw Tools::IndexOutOfBoundsException(index);
192 
193  *out = new Region(*(m_ptrMBR[index]));
194 }
195 
196 void Node::getChildData(uint32_t index, uint32_t& length, uint8_t** data) const
197 {
198  if (index >= m_children) throw Tools::IndexOutOfBoundsException(index);
199  if (m_pData[index] == nullptr)
200  {
201  length = 0;
202  data = nullptr;
203  }
204  else
205  {
206  length = m_pDataLength[index];
207  *data = m_pData[index];
208  }
209 }
210 
211 uint32_t Node::getLevel() const
212 {
213  return m_level;
214 }
215 
216 bool Node::isLeaf() const
217 {
218  return (m_level == 0);
219 }
220 
221 bool Node::isIndex() const
222 {
223  return (m_level != 0);
224 }
225 
226 //
227 // Internal
228 //
229 
230 Node::Node()
231 = default;
232 
233 Node::Node(SpatialIndex::RTree::RTree* pTree, id_type id, uint32_t level, uint32_t capacity) :
234  m_pTree(pTree),
235  m_level(level),
236  m_identifier(id),
237  m_children(0),
238  m_capacity(capacity),
239  m_pData(nullptr),
240  m_ptrMBR(nullptr),
241  m_pIdentifier(nullptr),
242  m_pDataLength(nullptr),
243  m_totalDataLength(0)
244 {
245  m_nodeMBR.makeInfinite(m_pTree->m_dimension);
246 
247  try
248  {
249  m_pDataLength = new uint32_t[m_capacity + 1];
250  m_pData = new uint8_t*[m_capacity + 1];
251  m_ptrMBR = new RegionPtr[m_capacity + 1];
252  m_pIdentifier = new id_type[m_capacity + 1];
253  }
254  catch (...)
255  {
256  delete[] m_pDataLength;
257  delete[] m_pData;
258  delete[] m_ptrMBR;
259  delete[] m_pIdentifier;
260  throw;
261  }
262 }
263 
265 {
266  if (m_pData != nullptr)
267  {
268  for (uint32_t u32Child = 0; u32Child < m_children; ++u32Child)
269  {
270  if (m_pData[u32Child] != nullptr) delete[] m_pData[u32Child];
271  }
272 
273  delete[] m_pData;
274  }
275 
276  delete[] m_pDataLength;
277  delete[] m_ptrMBR;
278  delete[] m_pIdentifier;
279 }
280 
281 Node& Node::operator=(const Node&)
282 {
283  throw Tools::IllegalStateException("operator =: This should never be called.");
284 }
285 
286 void Node::insertEntry(uint32_t dataLength, uint8_t* pData, Region& mbr, id_type id)
287 {
288  assert(m_children < m_capacity);
289 
290  m_pDataLength[m_children] = dataLength;
291  m_pData[m_children] = pData;
292  m_ptrMBR[m_children] = m_pTree->m_regionPool.acquire();
293  *(m_ptrMBR[m_children]) = mbr;
294  m_pIdentifier[m_children] = id;
295 
296  m_totalDataLength += dataLength;
297  ++m_children;
298 
299  m_nodeMBR.combineRegion(mbr);
300 }
301 
302 void Node::deleteEntry(uint32_t index)
303 {
304  assert(index >= 0 && index < m_children);
305 
306  // cache it, since I might need it for "touches" later.
307  RegionPtr ptrR = m_ptrMBR[index];
308 
309  m_totalDataLength -= m_pDataLength[index];
310  if (m_pData[index] != nullptr) delete[] m_pData[index];
311 
312  if (m_children > 1 && index != m_children - 1)
313  {
314  m_pDataLength[index] = m_pDataLength[m_children - 1];
315  m_pData[index] = m_pData[m_children - 1];
316  m_ptrMBR[index] = m_ptrMBR[m_children - 1];
317  m_pIdentifier[index] = m_pIdentifier[m_children - 1];
318  }
319 
320  --m_children;
321 
322  // WARNING: index has now changed. Do not use it below here.
323 
324  if (m_children == 0)
325  {
326  m_nodeMBR = m_pTree->m_infiniteRegion;
327  }
328  else if (m_pTree->m_bTightMBRs && m_nodeMBR.touchesRegion(*ptrR))
329  {
330  for (uint32_t cDim = 0; cDim < m_nodeMBR.m_dimension; ++cDim)
331  {
332  m_nodeMBR.m_pLow[cDim] = std::numeric_limits<double>::max();
333  m_nodeMBR.m_pHigh[cDim] = -std::numeric_limits<double>::max();
334 
335  for (uint32_t u32Child = 0; u32Child < m_children; ++u32Child)
336  {
337  m_nodeMBR.m_pLow[cDim] = std::min(m_nodeMBR.m_pLow[cDim], m_ptrMBR[u32Child]->m_pLow[cDim]);
338  m_nodeMBR.m_pHigh[cDim] = std::max(m_nodeMBR.m_pHigh[cDim], m_ptrMBR[u32Child]->m_pHigh[cDim]);
339  }
340  }
341  }
342 }
343 
344 bool Node::insertData(uint32_t dataLength, uint8_t* pData, Region& mbr, id_type id, std::stack<id_type>& pathBuffer, uint8_t* overflowTable)
345 {
346  if (m_children < m_capacity)
347  {
348  bool adjusted = false;
349 
350  // this has to happen before insertEntry modifies m_nodeMBR.
351  bool b = m_nodeMBR.containsRegion(mbr);
352 
353  insertEntry(dataLength, pData, mbr, id);
354  m_pTree->writeNode(this);
355 
356  if ((! b) && (! pathBuffer.empty()))
357  {
358  id_type cParent = pathBuffer.top(); pathBuffer.pop();
359  NodePtr ptrN = m_pTree->readNode(cParent);
360  Index* p = static_cast<Index*>(ptrN.get());
361  p->adjustTree(this, pathBuffer);
362  adjusted = true;
363  }
364 
365  return adjusted;
366  }
367  else if (m_pTree->m_treeVariant == RV_RSTAR && (! pathBuffer.empty()) && overflowTable[m_level] == 0)
368  {
369  overflowTable[m_level] = 1;
370 
371  std::vector<uint32_t> vReinsert, vKeep;
372  reinsertData(dataLength, pData, mbr, id, vReinsert, vKeep);
373 
374  uint32_t lReinsert = static_cast<uint32_t>(vReinsert.size());
375  uint32_t lKeep = static_cast<uint32_t>(vKeep.size());
376 
377  uint8_t** reinsertdata = nullptr;
378  RegionPtr* reinsertmbr = nullptr;
379  id_type* reinsertid = nullptr;
380  uint32_t* reinsertlen = nullptr;
381  uint8_t** keepdata = nullptr;
382  RegionPtr* keepmbr = nullptr;
383  id_type* keepid = nullptr;
384  uint32_t* keeplen = nullptr;
385 
386  try
387  {
388  reinsertdata = new uint8_t*[lReinsert];
389  reinsertmbr = new RegionPtr[lReinsert];
390  reinsertid = new id_type[lReinsert];
391  reinsertlen = new uint32_t[lReinsert];
392 
393  keepdata = new uint8_t*[m_capacity + 1];
394  keepmbr = new RegionPtr[m_capacity + 1];
395  keepid = new id_type[m_capacity + 1];
396  keeplen = new uint32_t[m_capacity + 1];
397  }
398  catch (...)
399  {
400  delete[] reinsertdata;
401  delete[] reinsertmbr;
402  delete[] reinsertid;
403  delete[] reinsertlen;
404  delete[] keepdata;
405  delete[] keepmbr;
406  delete[] keepid;
407  delete[] keeplen;
408  throw;
409  }
410 
411  uint32_t cIndex;
412 
413  for (cIndex = 0; cIndex < lReinsert; ++cIndex)
414  {
415  reinsertlen[cIndex] = m_pDataLength[vReinsert[cIndex]];
416  reinsertdata[cIndex] = m_pData[vReinsert[cIndex]];
417  reinsertmbr[cIndex] = m_ptrMBR[vReinsert[cIndex]];
418  reinsertid[cIndex] = m_pIdentifier[vReinsert[cIndex]];
419  }
420 
421  for (cIndex = 0; cIndex < lKeep; ++cIndex)
422  {
423  keeplen[cIndex] = m_pDataLength[vKeep[cIndex]];
424  keepdata[cIndex] = m_pData[vKeep[cIndex]];
425  keepmbr[cIndex] = m_ptrMBR[vKeep[cIndex]];
426  keepid[cIndex] = m_pIdentifier[vKeep[cIndex]];
427  }
428 
429  delete[] m_pDataLength;
430  delete[] m_pData;
431  delete[] m_ptrMBR;
432  delete[] m_pIdentifier;
433 
434  m_pDataLength = keeplen;
435  m_pData = keepdata;
436  m_ptrMBR = keepmbr;
437  m_pIdentifier = keepid;
438  m_children = lKeep;
439  m_totalDataLength = 0;
440 
441  for (uint32_t u32Child = 0; u32Child < m_children; ++u32Child) m_totalDataLength += m_pDataLength[u32Child];
442 
443  for (uint32_t cDim = 0; cDim < m_nodeMBR.m_dimension; ++cDim)
444  {
445  m_nodeMBR.m_pLow[cDim] = std::numeric_limits<double>::max();
446  m_nodeMBR.m_pHigh[cDim] = -std::numeric_limits<double>::max();
447 
448  for (uint32_t u32Child = 0; u32Child < m_children; ++u32Child)
449  {
450  m_nodeMBR.m_pLow[cDim] = std::min(m_nodeMBR.m_pLow[cDim], m_ptrMBR[u32Child]->m_pLow[cDim]);
451  m_nodeMBR.m_pHigh[cDim] = std::max(m_nodeMBR.m_pHigh[cDim], m_ptrMBR[u32Child]->m_pHigh[cDim]);
452  }
453  }
454 
455  m_pTree->writeNode(this);
456 
457  // Divertion from R*-Tree algorithm here. First adjust
458  // the path to the root, then start reinserts, to avoid complicated handling
459  // of changes to the same node from multiple insertions.
460  id_type cParent = pathBuffer.top(); pathBuffer.pop();
461  NodePtr ptrN = m_pTree->readNode(cParent);
462  Index* p = static_cast<Index*>(ptrN.get());
463  p->adjustTree(this, pathBuffer, true);
464 
465  for (cIndex = 0; cIndex < lReinsert; ++cIndex)
466  {
467  m_pTree->insertData_impl(
468  reinsertlen[cIndex], reinsertdata[cIndex],
469  *(reinsertmbr[cIndex]), reinsertid[cIndex],
470  m_level, overflowTable);
471  }
472 
473  delete[] reinsertdata;
474  delete[] reinsertmbr;
475  delete[] reinsertid;
476  delete[] reinsertlen;
477 
478  return true;
479  }
480  else
481  {
482  NodePtr n;
483  NodePtr nn;
484  split(dataLength, pData, mbr, id, n, nn);
485 
486  if (pathBuffer.empty())
487  {
488  n->m_level = m_level;
489  nn->m_level = m_level;
490  n->m_identifier = -1;
491  nn->m_identifier = -1;
492  m_pTree->writeNode(n.get());
493  m_pTree->writeNode(nn.get());
494 
495  NodePtr ptrR = m_pTree->m_indexPool.acquire();
496  if (ptrR.get() == nullptr)
497  {
498  ptrR = NodePtr(new Index(m_pTree, m_pTree->m_rootID, m_level + 1), &(m_pTree->m_indexPool));
499  }
500  else
501  {
502  //ptrR->m_pTree = m_pTree;
503  ptrR->m_identifier = m_pTree->m_rootID;
504  ptrR->m_level = m_level + 1;
505  ptrR->m_nodeMBR = m_pTree->m_infiniteRegion;
506  }
507 
508  ptrR->insertEntry(0, nullptr, n->m_nodeMBR, n->m_identifier);
509  ptrR->insertEntry(0, nullptr, nn->m_nodeMBR, nn->m_identifier);
510 
511  m_pTree->writeNode(ptrR.get());
512 
513  m_pTree->m_stats.m_nodesInLevel[m_level] = 2;
514  m_pTree->m_stats.m_nodesInLevel.push_back(1);
515  m_pTree->m_stats.m_u32TreeHeight = m_level + 2;
516  }
517  else
518  {
519  n->m_level = m_level;
520  nn->m_level = m_level;
521  n->m_identifier = m_identifier;
522  nn->m_identifier = -1;
523 
524  m_pTree->writeNode(n.get());
525  m_pTree->writeNode(nn.get());
526 
527  id_type cParent = pathBuffer.top(); pathBuffer.pop();
528  NodePtr ptrN = m_pTree->readNode(cParent);
529  Index* p = static_cast<Index*>(ptrN.get());
530  p->adjustTree(n.get(), nn.get(), pathBuffer, overflowTable);
531  }
532 
533  return true;
534  }
535 }
536 
537 void Node::reinsertData(uint32_t dataLength, uint8_t* pData, Region& mbr, id_type id, std::vector<uint32_t>& reinsert, std::vector<uint32_t>& keep)
538 {
539  ReinsertEntry** v = new ReinsertEntry*[m_capacity + 1];
540 
541  m_pDataLength[m_children] = dataLength;
542  m_pData[m_children] = pData;
543  m_ptrMBR[m_children] = m_pTree->m_regionPool.acquire();
544  *(m_ptrMBR[m_children]) = mbr;
545  m_pIdentifier[m_children] = id;
546 
547  PointPtr nc = m_pTree->m_pointPool.acquire();
548  m_nodeMBR.getCenter(*nc);
549  PointPtr c = m_pTree->m_pointPool.acquire();
550 
551  for (uint32_t u32Child = 0; u32Child < m_capacity + 1; ++u32Child)
552  {
553  try
554  {
555  v[u32Child] = new ReinsertEntry(u32Child, 0.0);
556  }
557  catch (...)
558  {
559  for (uint32_t i = 0; i < u32Child; ++i) delete v[i];
560  delete[] v;
561  throw;
562  }
563 
564  m_ptrMBR[u32Child]->getCenter(*c);
565 
566  // calculate relative distance of every entry from the node MBR (ignore square root.)
567  for (uint32_t cDim = 0; cDim < m_nodeMBR.m_dimension; ++cDim)
568  {
569  double d = nc->m_pCoords[cDim] - c->m_pCoords[cDim];
570  v[u32Child]->m_dist += d * d;
571  }
572  }
573 
574  // sort by increasing order of distances.
575  ::qsort(v, m_capacity + 1, sizeof(ReinsertEntry*), ReinsertEntry::compareReinsertEntry);
576 
577  uint32_t cReinsert = static_cast<uint32_t>(std::floor((m_capacity + 1) * m_pTree->m_reinsertFactor));
578 
579  uint32_t cCount;
580 
581  for (cCount = 0; cCount < m_capacity + 1; ++cCount)
582  {
583  if (cCount < m_capacity + 1 - cReinsert)
584  {
585  // Keep all but cReinsert nodes
586  keep.push_back(v[cCount]->m_index);
587  }
588  else
589  {
590  // Remove cReinsert nodes which will be
591  // reinserted into the tree. Since our array
592  // is already sorted in ascending order this
593  // matches the order suggested in the paper.
594  reinsert.push_back(v[cCount]->m_index);
595  }
596  delete v[cCount];
597  }
598 
599  delete[] v;
600 }
601 
602 void Node::rtreeSplit(uint32_t dataLength, uint8_t* pData, Region& mbr, id_type id, std::vector<uint32_t>& group1, std::vector<uint32_t>& group2)
603 {
604  uint32_t u32Child;
605  uint32_t minimumLoad = static_cast<uint32_t>(std::floor(m_capacity * m_pTree->m_fillFactor));
606 
607  // use this mask array for marking visited entries.
608  uint8_t* mask = new uint8_t[m_capacity + 1];
609  memset(mask, 0, m_capacity + 1);
610 
611  // insert new data in the node for easier manipulation. Data arrays are always
612  // by one larger than node capacity.
613  m_pDataLength[m_capacity] = dataLength;
614  m_pData[m_capacity] = pData;
615  m_ptrMBR[m_capacity] = m_pTree->m_regionPool.acquire();
616  *(m_ptrMBR[m_capacity]) = mbr;
617  m_pIdentifier[m_capacity] = id;
618  // m_totalDataLength does not need to be increased here.
619 
620  // initialize each group with the seed entries.
621  uint32_t seed1, seed2;
622  pickSeeds(seed1, seed2);
623 
624  group1.push_back(seed1);
625  group2.push_back(seed2);
626 
627  mask[seed1] = 1;
628  mask[seed2] = 1;
629 
630  // find MBR of each group.
631  RegionPtr mbr1 = m_pTree->m_regionPool.acquire();
632  *mbr1 = *(m_ptrMBR[seed1]);
633  RegionPtr mbr2 = m_pTree->m_regionPool.acquire();
634  *mbr2 = *(m_ptrMBR[seed2]);
635 
636  // count how many entries are left unchecked (exclude the seeds here.)
637  uint32_t cRemaining = m_capacity + 1 - 2;
638 
639  while (cRemaining > 0)
640  {
641  if (minimumLoad - group1.size() == cRemaining)
642  {
643  // all remaining entries must be assigned to group1 to comply with minimun load requirement.
644  for (u32Child = 0; u32Child < m_capacity + 1; ++u32Child)
645  {
646  if (mask[u32Child] == 0)
647  {
648  group1.push_back(u32Child);
649  mask[u32Child] = 1;
650  --cRemaining;
651  }
652  }
653  }
654  else if (minimumLoad - group2.size() == cRemaining)
655  {
656  // all remaining entries must be assigned to group2 to comply with minimun load requirement.
657  for (u32Child = 0; u32Child < m_capacity + 1; ++u32Child)
658  {
659  if (mask[u32Child] == 0)
660  {
661  group2.push_back(u32Child);
662  mask[u32Child] = 1;
663  --cRemaining;
664  }
665  }
666  }
667  else
668  {
669  // For all remaining entries compute the difference of the cost of grouping an
670  // entry in either group. When done, choose the entry that yielded the maximum
671  // difference. In case of linear split, select any entry (e.g. the first one.)
672  uint32_t sel;
673  double md1 = 0.0, md2 = 0.0;
674  double m = -std::numeric_limits<double>::max();
675  double d1, d2, d;
676  double a1 = mbr1->getArea();
677  double a2 = mbr2->getArea();
678 
679  RegionPtr a = m_pTree->m_regionPool.acquire();
680  RegionPtr b = m_pTree->m_regionPool.acquire();
681 
682  for (u32Child = 0; u32Child < m_capacity + 1; ++u32Child)
683  {
684  if (mask[u32Child] == 0)
685  {
686  mbr1->getCombinedRegion(*a, *(m_ptrMBR[u32Child]));
687  d1 = a->getArea() - a1;
688  mbr2->getCombinedRegion(*b, *(m_ptrMBR[u32Child]));
689  d2 = b->getArea() - a2;
690  d = std::abs(d1 - d2);
691 
692  if (d > m)
693  {
694  m = d;
695  md1 = d1; md2 = d2;
696  sel = u32Child;
697  if (m_pTree->m_treeVariant== RV_LINEAR || m_pTree->m_treeVariant == RV_RSTAR) break;
698  }
699  }
700  }
701 
702  // determine the group where we should add the new entry.
703  int32_t group = -1;
704 
705  if (md1 < md2)
706  {
707  group1.push_back(sel);
708  group = 1;
709  }
710  else if (md2 < md1)
711  {
712  group2.push_back(sel);
713  group = 2;
714  }
715  else if (a1 < a2)
716  {
717  group1.push_back(sel);
718  group = 1;
719  }
720  else if (a2 < a1)
721  {
722  group2.push_back(sel);
723  group = 2;
724  }
725  else if (group1.size() < group2.size())
726  {
727  group1.push_back(sel);
728  group = 1;
729  }
730  else if (group2.size() < group1.size())
731  {
732  group2.push_back(sel);
733  group = 2;
734  }
735  else
736  {
737  group1.push_back(sel);
738  group = 1;
739  }
740  mask[sel] = 1;
741  --cRemaining;
742  if (group == 1)
743  {
744  mbr1->combineRegion(*(m_ptrMBR[sel]));
745  }
746  else
747  {
748  mbr2->combineRegion(*(m_ptrMBR[sel]));
749  }
750  }
751  }
752 
753  delete[] mask;
754 }
755 
756 void Node::rstarSplit(uint32_t dataLength, uint8_t* pData, Region& mbr, id_type id, std::vector<uint32_t>& group1, std::vector<uint32_t>& group2)
757 {
758  RstarSplitEntry** dataLow = nullptr;
759  RstarSplitEntry** dataHigh = nullptr;
760 
761  try
762  {
763  dataLow = new RstarSplitEntry*[m_capacity + 1];
764  dataHigh = new RstarSplitEntry*[m_capacity + 1];
765  }
766  catch (...)
767  {
768  delete[] dataLow;
769  throw;
770  }
771 
772  m_pDataLength[m_capacity] = dataLength;
773  m_pData[m_capacity] = pData;
774  m_ptrMBR[m_capacity] = m_pTree->m_regionPool.acquire();
775  *(m_ptrMBR[m_capacity]) = mbr;
776  m_pIdentifier[m_capacity] = id;
777  // m_totalDataLength does not need to be increased here.
778 
779  uint32_t nodeSPF = static_cast<uint32_t>(
780  std::floor((m_capacity + 1) * m_pTree->m_splitDistributionFactor));
781  uint32_t splitDistribution = (m_capacity + 1) - (2 * nodeSPF) + 2;
782 
783  uint32_t u32Child = 0, cDim, cIndex;
784 
785  for (u32Child = 0; u32Child <= m_capacity; ++u32Child)
786  {
787  try
788  {
789  dataLow[u32Child] = new RstarSplitEntry(m_ptrMBR[u32Child].get(), u32Child, 0);
790  }
791  catch (...)
792  {
793  for (uint32_t i = 0; i < u32Child; ++i) delete dataLow[i];
794  delete[] dataLow;
795  delete[] dataHigh;
796  throw;
797  }
798 
799  dataHigh[u32Child] = dataLow[u32Child];
800  }
801 
802  double minimumMargin = std::numeric_limits<double>::max();
803  uint32_t splitAxis = std::numeric_limits<uint32_t>::max();
804  uint32_t sortOrder = std::numeric_limits<uint32_t>::max();
805 
806  // chooseSplitAxis.
807  for (cDim = 0; cDim < m_pTree->m_dimension; ++cDim)
808  {
809  ::qsort(dataLow, m_capacity + 1, sizeof(RstarSplitEntry*), RstarSplitEntry::compareLow);
810  ::qsort(dataHigh, m_capacity + 1, sizeof(RstarSplitEntry*), RstarSplitEntry::compareHigh);
811 
812  // calculate sum of margins and overlap for all distributions.
813  double marginl = 0.0;
814  double marginh = 0.0;
815 
816  Region bbl1, bbl2, bbh1, bbh2;
817 
818  for (u32Child = 1; u32Child <= splitDistribution; ++u32Child)
819  {
820  uint32_t l = nodeSPF - 1 + u32Child;
821 
822  bbl1 = *(dataLow[0]->m_pRegion);
823  bbh1 = *(dataHigh[0]->m_pRegion);
824 
825  for (cIndex = 1; cIndex < l; ++cIndex)
826  {
827  bbl1.combineRegion(*(dataLow[cIndex]->m_pRegion));
828  bbh1.combineRegion(*(dataHigh[cIndex]->m_pRegion));
829  }
830 
831  bbl2 = *(dataLow[l]->m_pRegion);
832  bbh2 = *(dataHigh[l]->m_pRegion);
833 
834  for (cIndex = l + 1; cIndex <= m_capacity; ++cIndex)
835  {
836  bbl2.combineRegion(*(dataLow[cIndex]->m_pRegion));
837  bbh2.combineRegion(*(dataHigh[cIndex]->m_pRegion));
838  }
839 
840  marginl += bbl1.getMargin() + bbl2.getMargin();
841  marginh += bbh1.getMargin() + bbh2.getMargin();
842  } // for (u32Child)
843 
844  double margin = std::min(marginl, marginh);
845 
846  // keep minimum margin as split axis.
847  if (margin < minimumMargin)
848  {
849  minimumMargin = margin;
850  splitAxis = cDim;
851  sortOrder = (marginl < marginh) ? 0 : 1;
852  }
853 
854  // increase the dimension according to which the data entries should be sorted.
855  for (u32Child = 0; u32Child <= m_capacity; ++u32Child)
856  {
857  dataLow[u32Child]->m_sortDim = cDim + 1;
858  }
859  } // for (cDim)
860 
861  for (u32Child = 0; u32Child <= m_capacity; ++u32Child)
862  {
863  dataLow[u32Child]->m_sortDim = splitAxis;
864  }
865 
866  ::qsort(dataLow, m_capacity + 1, sizeof(RstarSplitEntry*), (sortOrder == 0) ? RstarSplitEntry::compareLow : RstarSplitEntry::compareHigh);
867 
868  double ma = std::numeric_limits<double>::max();
869  double mo = std::numeric_limits<double>::max();
870  uint32_t splitPoint = std::numeric_limits<uint32_t>::max();
871 
872  Region bb1, bb2;
873 
874  for (u32Child = 1; u32Child <= splitDistribution; ++u32Child)
875  {
876  uint32_t l = nodeSPF - 1 + u32Child;
877 
878  bb1 = *(dataLow[0]->m_pRegion);
879 
880  for (cIndex = 1; cIndex < l; ++cIndex)
881  {
882  bb1.combineRegion(*(dataLow[cIndex]->m_pRegion));
883  }
884 
885  bb2 = *(dataLow[l]->m_pRegion);
886 
887  for (cIndex = l + 1; cIndex <= m_capacity; ++cIndex)
888  {
889  bb2.combineRegion(*(dataLow[cIndex]->m_pRegion));
890  }
891 
892  double o = bb1.getIntersectingArea(bb2);
893 
894  if (o < mo)
895  {
896  splitPoint = u32Child;
897  mo = o;
898  ma = bb1.getArea() + bb2.getArea();
899  }
900  else if (o == mo)
901  {
902  double a = bb1.getArea() + bb2.getArea();
903 
904  if (a < ma)
905  {
906  splitPoint = u32Child;
907  ma = a;
908  }
909  }
910  } // for (u32Child)
911 
912  uint32_t l1 = nodeSPF - 1 + splitPoint;
913 
914  for (cIndex = 0; cIndex < l1; ++cIndex)
915  {
916  group1.push_back(dataLow[cIndex]->m_index);
917  delete dataLow[cIndex];
918  }
919 
920  for (cIndex = l1; cIndex <= m_capacity; ++cIndex)
921  {
922  group2.push_back(dataLow[cIndex]->m_index);
923  delete dataLow[cIndex];
924  }
925 
926  delete[] dataLow;
927  delete[] dataHigh;
928 }
929 
930 void Node::pickSeeds(uint32_t& index1, uint32_t& index2)
931 {
932  double separation = -std::numeric_limits<double>::max();
933  double inefficiency = -std::numeric_limits<double>::max();
934  uint32_t cDim, u32Child, cIndex;
935 
936  switch (m_pTree->m_treeVariant)
937  {
938  case RV_LINEAR:
939  case RV_RSTAR:
940  for (cDim = 0; cDim < m_pTree->m_dimension; ++cDim)
941  {
942  double leastLower = m_ptrMBR[0]->m_pLow[cDim];
943  double greatestUpper = m_ptrMBR[0]->m_pHigh[cDim];
944  uint32_t greatestLower = 0;
945  uint32_t leastUpper = 0;
946  double width;
947 
948  for (u32Child = 1; u32Child <= m_capacity; ++u32Child)
949  {
950  if (m_ptrMBR[u32Child]->m_pLow[cDim] > m_ptrMBR[greatestLower]->m_pLow[cDim]) greatestLower = u32Child;
951  if (m_ptrMBR[u32Child]->m_pHigh[cDim] < m_ptrMBR[leastUpper]->m_pHigh[cDim]) leastUpper = u32Child;
952 
953  leastLower = std::min(m_ptrMBR[u32Child]->m_pLow[cDim], leastLower);
954  greatestUpper = std::max(m_ptrMBR[u32Child]->m_pHigh[cDim], greatestUpper);
955  }
956 
957  width = greatestUpper - leastLower;
958  if (width <= 0) width = 1;
959 
960  double f = (m_ptrMBR[greatestLower]->m_pLow[cDim] - m_ptrMBR[leastUpper]->m_pHigh[cDim]) / width;
961 
962  if (f > separation)
963  {
964  index1 = leastUpper;
965  index2 = greatestLower;
966  separation = f;
967  }
968  } // for (cDim)
969 
970  if (index1 == index2)
971  {
972  if (index2 == 0) ++index2;
973  else --index2;
974  }
975 
976  break;
977  case RV_QUADRATIC:
978  // for each pair of Regions (account for overflow Region too!)
979  for (u32Child = 0; u32Child < m_capacity; ++u32Child)
980  {
981  double a = m_ptrMBR[u32Child]->getArea();
982 
983  for (cIndex = u32Child + 1; cIndex <= m_capacity; ++cIndex)
984  {
985  // get the combined MBR of those two entries.
986  Region r;
987  m_ptrMBR[u32Child]->getCombinedRegion(r, *(m_ptrMBR[cIndex]));
988 
989  // find the inefficiency of grouping these entries together.
990  double d = r.getArea() - a - m_ptrMBR[cIndex]->getArea();
991 
992  if (d > inefficiency)
993  {
994  inefficiency = d;
995  index1 = u32Child;
996  index2 = cIndex;
997  }
998  } // for (cIndex)
999  } // for (u32Child)
1000 
1001  break;
1002  default:
1003  throw Tools::NotSupportedException("Node::pickSeeds: Tree variant not supported.");
1004  }
1005 }
1006 
1007 void Node::condenseTree(std::stack<NodePtr>& toReinsert, std::stack<id_type>& pathBuffer, NodePtr& ptrThis)
1008 {
1009  uint32_t minimumLoad = static_cast<uint32_t>(std::floor(m_capacity * m_pTree->m_fillFactor));
1010 
1011  if (pathBuffer.empty())
1012  {
1013  // eliminate root if it has only one child.
1014  if (m_level != 0 && m_children == 1)
1015  {
1016  NodePtr ptrN = m_pTree->readNode(m_pIdentifier[0]);
1017  m_pTree->deleteNode(ptrN.get());
1018  ptrN->m_identifier = m_pTree->m_rootID;
1019  m_pTree->writeNode(ptrN.get());
1020 
1021  m_pTree->m_stats.m_nodesInLevel.pop_back();
1022  m_pTree->m_stats.m_u32TreeHeight -= 1;
1023  // HACK: pending deleteNode for deleted child will decrease nodesInLevel, later on.
1024  m_pTree->m_stats.m_nodesInLevel[m_pTree->m_stats.m_u32TreeHeight - 1] = 2;
1025  }
1026  else
1027  {
1028  // due to data removal.
1029  if (m_pTree->m_bTightMBRs)
1030  {
1031  for (uint32_t cDim = 0; cDim < m_nodeMBR.m_dimension; ++cDim)
1032  {
1033  m_nodeMBR.m_pLow[cDim] = std::numeric_limits<double>::max();
1034  m_nodeMBR.m_pHigh[cDim] = -std::numeric_limits<double>::max();
1035 
1036  for (uint32_t u32Child = 0; u32Child < m_children; ++u32Child)
1037  {
1038  m_nodeMBR.m_pLow[cDim] = std::min(m_nodeMBR.m_pLow[cDim], m_ptrMBR[u32Child]->m_pLow[cDim]);
1039  m_nodeMBR.m_pHigh[cDim] = std::max(m_nodeMBR.m_pHigh[cDim], m_ptrMBR[u32Child]->m_pHigh[cDim]);
1040  }
1041  }
1042  }
1043 
1044  // write parent node back to storage.
1045  m_pTree->writeNode(this);
1046  }
1047  }
1048  else
1049  {
1050  id_type cParent = pathBuffer.top(); pathBuffer.pop();
1051  NodePtr ptrParent = m_pTree->readNode(cParent);
1052  Index* p = static_cast<Index*>(ptrParent.get());
1053 
1054  // find the entry in the parent, that points to this node.
1055  uint32_t child;
1056 
1057  for (child = 0; child != p->m_children; ++child)
1058  {
1059  if (p->m_pIdentifier[child] == m_identifier) break;
1060  }
1061 
1062  if (m_children < minimumLoad)
1063  {
1064  // used space less than the minimum
1065  // 1. eliminate node entry from the parent. deleteEntry will fix the parent's MBR.
1066  p->deleteEntry(child);
1067  // 2. add this node to the stack in order to reinsert its entries.
1068  toReinsert.push(ptrThis);
1069  }
1070  else
1071  {
1072  // adjust the entry in 'p' to contain the new bounding region of this node.
1073  *(p->m_ptrMBR[child]) = m_nodeMBR;
1074 
1075  // global recalculation necessary since the MBR can only shrink in size,
1076  // due to data removal.
1077  if (m_pTree->m_bTightMBRs)
1078  {
1079  for (uint32_t cDim = 0; cDim < p->m_nodeMBR.m_dimension; ++cDim)
1080  {
1081  p->m_nodeMBR.m_pLow[cDim] = std::numeric_limits<double>::max();
1082  p->m_nodeMBR.m_pHigh[cDim] = -std::numeric_limits<double>::max();
1083 
1084  for (uint32_t u32Child = 0; u32Child < p->m_children; ++u32Child)
1085  {
1086  p->m_nodeMBR.m_pLow[cDim] = std::min(p->m_nodeMBR.m_pLow[cDim], p->m_ptrMBR[u32Child]->m_pLow[cDim]);
1087  p->m_nodeMBR.m_pHigh[cDim] = std::max(p->m_nodeMBR.m_pHigh[cDim], p->m_ptrMBR[u32Child]->m_pHigh[cDim]);
1088  }
1089  }
1090  }
1091  }
1092 
1093  // write parent node back to storage.
1094  m_pTree->writeNode(p);
1095 
1096  p->condenseTree(toReinsert, pathBuffer, ptrParent);
1097  }
1098 }
bool isIndex() const override
Definition: rtree/Node.cc:221
virtual bool containsRegion(const Region &in) const
Definition: Region.cc:278
void adjustTree(Node *, std::stack< id_type > &, bool force=false)
Definition: rtree/Index.cc:283
PoolPointer< X > acquire()
Definition: PointerPool.h:64
virtual bool touchesRegion(const Region &in) const
Definition: Region.cc:292
void loadFromByteArray(const uint8_t *data) override
Definition: rtree/Node.cc:63
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
void getShape(IShape **out) const override
Definition: rtree/Node.cc:169
void getChildShape(uint32_t index, IShape **out) const override
Definition: rtree/Node.cc:189
uint32_t getChildrenCount() const override
Definition: rtree/Node.cc:177
uint32_t getLevel() const override
Definition: rtree/Node.cc:211
void getChildData(uint32_t index, uint32_t &length, uint8_t **data) const override
Definition: rtree/Node.cc:196
virtual void combineRegion(const Region &in)
Definition: Region.cc:496
uint32_t m_dimension
Definition: Region.h:97
double * m_pHigh
Definition: Region.h:99
X * get() const noexcept
Definition: PoolPointer.h:55
double getArea() const override
Definition: Region.cc:239
Tools::IObject * clone() override
Definition: rtree/Node.cc:44
virtual void makeInfinite(uint32_t dimension)
Definition: Region.cc:551
Tools::PoolPointer< Node > NodePtr
Definition: rtree/Node.h:40
void storeToByteArray(uint8_t **data, uint32_t &len) override
Definition: rtree/Node.cc:112
virtual double getMargin() const
Definition: Region.cc:483
bool isLeaf() const override
Definition: rtree/Node.cc:216
uint32_t getByteArraySize() override
Definition: rtree/Node.cc:52
id_type getIdentifier() const override
Definition: rtree/Node.cc:164
int64_t id_type
Definition: SpatialIndex.h:41
SpatialIndex::ISpatialIndex & index()
id_type getChildIdentifier(uint32_t index) const override
Definition: rtree/Node.cc:182
void getCenter(Point &out) const override
Definition: Region.cc:220