libspatialindex API Reference  (git-trunk)
tprtree/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 "TPRTree.h"
35 #include "Node.h"
36 #include "Index.h"
37 
38 using namespace SpatialIndex;
39 using namespace SpatialIndex::TPRTree;
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  sizeof(double) +
59  (m_children * (4 * m_pTree->m_dimension * sizeof(double) + sizeof(double) + sizeof(id_type) + sizeof(uint32_t))) +
60  m_totalDataLength +
61  (4 * m_pTree->m_dimension * sizeof(double)));
62 }
63 
64 void Node::loadFromByteArray(const uint8_t* ptr)
65 {
66  m_nodeMBR = m_pTree->m_infiniteRegion;
67 
68  // skip the node type information, it is not needed.
69  ptr += sizeof(uint32_t);
70 
71  memcpy(&m_level, ptr, sizeof(uint32_t));
72  ptr += sizeof(uint32_t);
73 
74  memcpy(&m_children, ptr, sizeof(uint32_t));
75  ptr += sizeof(uint32_t);
76 
77  memcpy(&(m_nodeMBR.m_startTime), ptr, sizeof(double));
78  ptr += sizeof(double);
79  m_nodeMBR.m_endTime = std::numeric_limits<double>::max();
80  //memcpy(&(m_nodeMBR.m_endTime), ptr, sizeof(double));
81  //ptr += sizeof(double);
82 
83  for (uint32_t cChild = 0; cChild < m_children; ++cChild)
84  {
85  m_ptrMBR[cChild] = m_pTree->m_regionPool.acquire();
86  m_ptrMBR[cChild]->makeDimension(m_pTree->m_dimension);
87 
88  memcpy(m_ptrMBR[cChild]->m_pLow, ptr, m_pTree->m_dimension * sizeof(double));
89  ptr += m_pTree->m_dimension * sizeof(double);
90  memcpy(m_ptrMBR[cChild]->m_pHigh, ptr, m_pTree->m_dimension * sizeof(double));
91  ptr += m_pTree->m_dimension * sizeof(double);
92  memcpy(m_ptrMBR[cChild]->m_pVLow, ptr, m_pTree->m_dimension * sizeof(double));
93  ptr += m_pTree->m_dimension * sizeof(double);
94  memcpy(m_ptrMBR[cChild]->m_pVHigh, ptr, m_pTree->m_dimension * sizeof(double));
95  ptr += m_pTree->m_dimension * sizeof(double);
96  memcpy(&(m_ptrMBR[cChild]->m_startTime), ptr, sizeof(double));
97  ptr += sizeof(double);
98  m_ptrMBR[cChild]->m_endTime = std::numeric_limits<double>::max();
99 
100  memcpy(&(m_pIdentifier[cChild]), ptr, sizeof(id_type));
101  ptr += sizeof(id_type);
102 
103  memcpy(&(m_pDataLength[cChild]), ptr, sizeof(uint32_t));
104  ptr += sizeof(uint32_t);
105 
106  if (m_pDataLength[cChild] > 0)
107  {
108  m_totalDataLength += m_pDataLength[cChild];
109  m_pData[cChild] = new uint8_t[m_pDataLength[cChild]];
110  memcpy(m_pData[cChild], ptr, m_pDataLength[cChild]);
111  ptr += m_pDataLength[cChild];
112  }
113  else
114  {
115  m_pData[cChild] = nullptr;
116  }
117 
118  //m_nodeMBR.combineRegion(*(m_ptrMBR[cChild]));
119  }
120 
121  memcpy(m_nodeMBR.m_pLow, ptr, m_pTree->m_dimension * sizeof(double));
122  ptr += m_pTree->m_dimension * sizeof(double);
123  memcpy(m_nodeMBR.m_pHigh, ptr, m_pTree->m_dimension * sizeof(double));
124  ptr += m_pTree->m_dimension * sizeof(double);
125  memcpy(m_nodeMBR.m_pVLow, ptr, m_pTree->m_dimension * sizeof(double));
126  ptr += m_pTree->m_dimension * sizeof(double);
127  memcpy(m_nodeMBR.m_pVHigh, ptr, m_pTree->m_dimension * sizeof(double));
128  //ptr += m_pTree->m_dimension * sizeof(double);
129 }
130 
131 void Node::storeToByteArray(uint8_t** data, uint32_t& len)
132 {
133  len = getByteArraySize();
134 
135  *data = new uint8_t[len];
136  uint8_t* ptr = *data;
137 
138  uint32_t nodeType;
139 
140  if (m_level == 0) nodeType = PersistentLeaf;
141  else nodeType = PersistentIndex;
142 
143  memcpy(ptr, &nodeType, sizeof(uint32_t));
144  ptr += sizeof(uint32_t);
145 
146  memcpy(ptr, &m_level, sizeof(uint32_t));
147  ptr += sizeof(uint32_t);
148 
149  memcpy(ptr, &m_children, sizeof(uint32_t));
150  ptr += sizeof(uint32_t);
151 
152  memcpy(ptr, &(m_nodeMBR.m_startTime), sizeof(double));
153  ptr += sizeof(double);
154 
155  for (uint32_t cChild = 0; cChild < m_children; ++cChild)
156  {
157  memcpy(ptr, m_ptrMBR[cChild]->m_pLow, m_pTree->m_dimension * sizeof(double));
158  ptr += m_pTree->m_dimension * sizeof(double);
159  memcpy(ptr, m_ptrMBR[cChild]->m_pHigh, m_pTree->m_dimension * sizeof(double));
160  ptr += m_pTree->m_dimension * sizeof(double);
161  memcpy(ptr, m_ptrMBR[cChild]->m_pVLow, m_pTree->m_dimension * sizeof(double));
162  ptr += m_pTree->m_dimension * sizeof(double);
163  memcpy(ptr, m_ptrMBR[cChild]->m_pVHigh, m_pTree->m_dimension * sizeof(double));
164  ptr += m_pTree->m_dimension * sizeof(double);
165  memcpy(ptr, &(m_ptrMBR[cChild]->m_startTime), sizeof(double));
166  ptr += sizeof(double);
167 
168  memcpy(ptr, &(m_pIdentifier[cChild]), sizeof(id_type));
169  ptr += sizeof(id_type);
170 
171  memcpy(ptr, &(m_pDataLength[cChild]), sizeof(uint32_t));
172  ptr += sizeof(uint32_t);
173 
174  if (m_pDataLength[cChild] > 0)
175  {
176  memcpy(ptr, m_pData[cChild], m_pDataLength[cChild]);
177  ptr += m_pDataLength[cChild];
178  }
179  }
180 
181  // store the node MBR for efficiency. This increases the node size a little bit.
182  memcpy(ptr, m_nodeMBR.m_pLow, m_pTree->m_dimension * sizeof(double));
183  ptr += m_pTree->m_dimension * sizeof(double);
184  memcpy(ptr, m_nodeMBR.m_pHigh, m_pTree->m_dimension * sizeof(double));
185  ptr += m_pTree->m_dimension * sizeof(double);
186  memcpy(ptr, m_nodeMBR.m_pVLow, m_pTree->m_dimension * sizeof(double));
187  ptr += m_pTree->m_dimension * sizeof(double);
188  memcpy(ptr, m_nodeMBR.m_pVHigh, m_pTree->m_dimension * sizeof(double));
189  //ptr += m_pTree->m_dimension * sizeof(double);
190 
191  assert(len == (ptr - *data) + m_pTree->m_dimension * sizeof(double));
192 }
193 
194 //
195 // SpatialIndex::IEntry interface
196 //
198 {
199  return m_identifier;
200 }
201 
202 void Node::getShape(IShape** out) const
203 {
204  *out = new MovingRegion(m_nodeMBR);
205 }
206 
207 //
208 // SpatialIndex::INode interface
209 //
210 uint32_t Node::getChildrenCount() const
211 {
212  return m_children;
213 }
214 
216 {
217  if (index >= m_children) throw Tools::IndexOutOfBoundsException(index);
218 
219  return m_pIdentifier[index];
220 }
221 
222 void Node::getChildShape(uint32_t index, IShape** out) const
223 {
224  if (index >= m_children) throw Tools::IndexOutOfBoundsException(index);
225 
226  *out = new MovingRegion(*(m_ptrMBR[index]));
227 }
228 
229 void Node::getChildData(uint32_t index, uint32_t& length, uint8_t** data) const
230 {
231  if (index >= m_children) throw Tools::IndexOutOfBoundsException(index);
232  if (m_pData[index] == nullptr)
233  {
234  length = 0;
235  data = nullptr;
236  }
237  else
238  {
239  length = m_pDataLength[index];
240  *data = m_pData[index];
241  }
242 }
243 
244 uint32_t Node::getLevel() const
245 {
246  return m_level;
247 }
248 
249 bool Node::isLeaf() const
250 {
251  return (m_level == 0);
252 }
253 
254 bool Node::isIndex() const
255 {
256  return (m_level != 0);
257 }
258 
259 //
260 // Internal
261 //
262 
263 Node::Node()
264 = default;
265 
266 Node::Node(SpatialIndex::TPRTree::TPRTree* pTree, id_type id, uint32_t level, uint32_t capacity) :
267  m_pTree(pTree),
268  m_level(level),
269  m_identifier(id),
270  m_children(0),
271  m_capacity(capacity),
272  m_pData(nullptr),
273  m_ptrMBR(nullptr),
274  m_pIdentifier(nullptr),
275  m_pDataLength(nullptr),
276  m_totalDataLength(0)
277 {
278  m_nodeMBR.makeInfinite(m_pTree->m_dimension);
279 
280  try
281  {
282  m_pDataLength = new uint32_t[m_capacity + 1];
283  m_pData = new uint8_t*[m_capacity + 1];
284  m_ptrMBR = new MovingRegionPtr[m_capacity + 1];
285  m_pIdentifier = new id_type[m_capacity + 1];
286  }
287  catch (...)
288  {
289  delete[] m_pDataLength;
290  delete[] m_pData;
291  delete[] m_ptrMBR;
292  delete[] m_pIdentifier;
293  throw;
294  }
295 }
296 
298 {
299  if (m_pData != nullptr)
300  {
301  for (uint32_t cChild = 0; cChild < m_children; ++cChild)
302  {
303  if (m_pData[cChild] != nullptr) delete[] m_pData[cChild];
304  }
305 
306  delete[] m_pData;
307  }
308 
309  delete[] m_pDataLength;
310  delete[] m_ptrMBR;
311  delete[] m_pIdentifier;
312 }
313 
314 Node& Node::operator=(const Node&)
315 {
316  throw Tools::IllegalStateException("Node::operator =: This should never be called.");
317 }
318 
319 bool Node::insertEntry(uint32_t dataLength, uint8_t* pData, MovingRegion& mbr, id_type id)
320 {
321  assert(m_children < m_capacity);
322 
323  m_pDataLength[m_children] = dataLength;
324  m_pData[m_children] = pData;
325  m_ptrMBR[m_children] = m_pTree->m_regionPool.acquire();
326  *(m_ptrMBR[m_children]) = mbr;
327  m_pIdentifier[m_children] = id;
328 
329  m_totalDataLength += dataLength;
330  ++m_children;
331 
332  if (m_nodeMBR.m_startTime != m_pTree->m_currentTime)
333  {
334  m_nodeMBR.m_startTime = m_pTree->m_currentTime;
335 
336  for (uint32_t cDim = 0; cDim < m_nodeMBR.m_dimension; ++cDim)
337  {
338  m_nodeMBR.m_pLow[cDim] = std::numeric_limits<double>::max();
339  m_nodeMBR.m_pHigh[cDim] = -std::numeric_limits<double>::max();
340  m_nodeMBR.m_pVLow[cDim] = std::numeric_limits<double>::max();
341  m_nodeMBR.m_pVHigh[cDim] = -std::numeric_limits<double>::max();
342 
343  for (uint32_t cChild = 0; cChild < m_children; ++cChild)
344  {
345  m_nodeMBR.m_pLow[cDim] = std::min(m_nodeMBR.m_pLow[cDim], m_ptrMBR[cChild]->getExtrapolatedLow(cDim, m_nodeMBR.m_startTime));
346  m_nodeMBR.m_pHigh[cDim] = std::max(m_nodeMBR.m_pHigh[cDim], m_ptrMBR[cChild]->getExtrapolatedHigh(cDim, m_nodeMBR.m_startTime));
347  m_nodeMBR.m_pVLow[cDim] = std::min(m_nodeMBR.m_pVLow[cDim], m_ptrMBR[cChild]->m_pVLow[cDim]);
348  m_nodeMBR.m_pVHigh[cDim] = std::max(m_nodeMBR.m_pVHigh[cDim], m_ptrMBR[cChild]->m_pVHigh[cDim]);
349  }
350  m_nodeMBR.m_pLow[cDim] -= 2.0 * std::numeric_limits<double>::epsilon();
351  m_nodeMBR.m_pHigh[cDim] += 2.0 * std::numeric_limits<double>::epsilon();
352  }
353  }
354  else if (
355  //m_nodeMBR.m_pLow[0] != std::numeric_limits<double>::max() &&
356  ! m_nodeMBR.containsRegionAfterTime(m_pTree->m_currentTime, mbr))
357  {
358  for (uint32_t cDim = 0; cDim < m_nodeMBR.m_dimension; ++cDim)
359  {
360  double l = m_nodeMBR.getExtrapolatedLow(cDim, m_pTree->m_currentTime);
361  double rl = mbr.getExtrapolatedLow(cDim, m_pTree->m_currentTime);
362  if (rl <= l)
363  {
364  m_nodeMBR.m_pLow[cDim] = rl - 2.0 * std::numeric_limits<double>::epsilon();
365  }
366 
367  double h = m_nodeMBR.getExtrapolatedHigh(cDim, m_pTree->m_currentTime);
368  double rh = mbr.getExtrapolatedHigh(cDim, m_pTree->m_currentTime);
369  if (rh >= h)
370  {
371  m_nodeMBR.m_pHigh[cDim] = rh + 2.0 * std::numeric_limits<double>::epsilon();
372  }
373 
374  m_nodeMBR.m_pVLow[cDim] = std::min(m_nodeMBR.m_pVLow[cDim], mbr.m_pVLow[cDim]);
375  m_nodeMBR.m_pVHigh[cDim] = std::max(m_nodeMBR.m_pVHigh[cDim], mbr.m_pVHigh[cDim]);
376  }
377  }
378 
379 #ifndef NDEBUG
380  for (uint32_t cChild = 0; cChild < m_children; ++cChild)
381  {
382  assert(m_nodeMBR.containsRegionAfterTime(m_nodeMBR.m_startTime, *(m_ptrMBR[cChild])));
383  }
384 #endif
385 
386  return true;
387 }
388 
389 void Node::deleteEntry(uint32_t index)
390 {
391  assert(index >= 0 && index < m_children);
392 
393  // cache it, since I might need it for "touches" later.
394  MovingRegionPtr ptrR = m_ptrMBR[index];
395 
396  m_totalDataLength -= m_pDataLength[index];
397  if (m_pData[index] != nullptr) delete[] m_pData[index];
398 
399  if (m_children > 1 && index != m_children - 1)
400  {
401  m_pDataLength[index] = m_pDataLength[m_children - 1];
402  m_pData[index] = m_pData[m_children - 1];
403  m_ptrMBR[index] = m_ptrMBR[m_children - 1];
404  m_pIdentifier[index] = m_pIdentifier[m_children - 1];
405  }
406 
407  --m_children;
408 
409  // WARNING: index has now changed. Do not use it below here.
410 
411  if (m_children == 0)
412  {
413  m_nodeMBR = m_pTree->m_infiniteRegion;
414  }
415  else //if (m_pTree->m_bTightMBRs && m_nodeMBR.touchesRegion(*ptrR))
416  {
417  m_nodeMBR.m_startTime = m_pTree->m_currentTime;
418 
419  for (uint32_t cDim = 0; cDim < m_nodeMBR.m_dimension; ++cDim)
420  {
421  m_nodeMBR.m_pLow[cDim] = std::numeric_limits<double>::max();
422  m_nodeMBR.m_pHigh[cDim] = -std::numeric_limits<double>::max();
423  m_nodeMBR.m_pVLow[cDim] = std::numeric_limits<double>::max();
424  m_nodeMBR.m_pVHigh[cDim] = -std::numeric_limits<double>::max();
425 
426  for (uint32_t cChild = 0; cChild < m_children; ++cChild)
427  {
428  m_nodeMBR.m_pLow[cDim] = std::min(m_nodeMBR.m_pLow[cDim], m_ptrMBR[cChild]->getExtrapolatedLow(cDim, m_nodeMBR.m_startTime));
429  m_nodeMBR.m_pHigh[cDim] = std::max(m_nodeMBR.m_pHigh[cDim], m_ptrMBR[cChild]->getExtrapolatedHigh(cDim, m_nodeMBR.m_startTime));
430  m_nodeMBR.m_pVLow[cDim] = std::min(m_nodeMBR.m_pVLow[cDim], m_ptrMBR[cChild]->m_pVLow[cDim]);
431  m_nodeMBR.m_pVHigh[cDim] = std::max(m_nodeMBR.m_pVHigh[cDim], m_ptrMBR[cChild]->m_pVHigh[cDim]);
432  }
433  m_nodeMBR.m_pLow[cDim] -= 2.0 * std::numeric_limits<double>::epsilon();
434  m_nodeMBR.m_pHigh[cDim] += 2.0 * std::numeric_limits<double>::epsilon();
435  }
436 
437 #ifndef NDEBUG
438  for (uint32_t cChild = 0; cChild < m_children; ++cChild)
439  {
440  assert(m_nodeMBR.containsRegionAfterTime(m_pTree->m_currentTime, *(m_ptrMBR[cChild])) == true);
441  }
442 #endif
443  }
444 }
445 
446 bool Node::insertData(uint32_t dataLength, uint8_t* pData, MovingRegion& mbr, id_type id, std::stack<id_type>& pathBuffer, uint8_t* overflowTable)
447 {
448  if (m_children < m_capacity)
449  {
450  bool bNeedToAdjust = insertEntry(dataLength, pData, mbr, id);
451  m_pTree->writeNode(this);
452 
453  if (bNeedToAdjust && ! pathBuffer.empty())
454  {
455  id_type cParent = pathBuffer.top(); pathBuffer.pop();
456  NodePtr ptrN = m_pTree->readNode(cParent);
457  Index* p = static_cast<Index*>(ptrN.get());
458  p->adjustTree(this, pathBuffer);
459  }
460 
461  return bNeedToAdjust;
462  }
463  else if (false &&
464  m_pTree->m_treeVariant == TPRV_RSTAR &&
465  !pathBuffer.empty() &&
466  overflowTable[m_level] == 0)
467  {
468  overflowTable[m_level] = 1;
469 
470  std::vector<uint32_t> vReinsert, vKeep;
471  reinsertData(dataLength, pData, mbr, id, vReinsert, vKeep);
472 
473  uint32_t lReinsert = static_cast<uint32_t>(vReinsert.size());
474  uint32_t lKeep = static_cast<uint32_t>(vKeep.size());
475 
476  uint8_t** reinsertdata = nullptr;
477  MovingRegionPtr* reinsertmbr = nullptr;
478  id_type* reinsertid = nullptr;
479  uint32_t* reinsertlen = nullptr;
480  uint8_t** keepdata = nullptr;
481  MovingRegionPtr* keepmbr = nullptr;
482  id_type* keepid = nullptr;
483  uint32_t* keeplen = nullptr;
484 
485  try
486  {
487  reinsertdata = new uint8_t*[lReinsert];
488  reinsertmbr = new MovingRegionPtr[lReinsert];
489  reinsertid = new id_type[lReinsert];
490  reinsertlen = new uint32_t[lReinsert];
491 
492  keepdata = new uint8_t*[m_capacity + 1];
493  keepmbr = new MovingRegionPtr[m_capacity + 1];
494  keepid = new id_type[m_capacity + 1];
495  keeplen = new uint32_t[m_capacity + 1];
496  }
497  catch (...)
498  {
499  delete[] reinsertdata;
500  delete[] reinsertmbr;
501  delete[] reinsertid;
502  delete[] reinsertlen;
503  delete[] keepdata;
504  delete[] keepmbr;
505  delete[] keepid;
506  delete[] keeplen;
507  throw;
508  }
509 
510  uint32_t cIndex;
511 
512  for (cIndex = 0; cIndex < lReinsert; ++cIndex)
513  {
514  reinsertlen[cIndex] = m_pDataLength[vReinsert[cIndex]];
515  reinsertdata[cIndex] = m_pData[vReinsert[cIndex]];
516  reinsertmbr[cIndex] = m_ptrMBR[vReinsert[cIndex]];
517  reinsertid[cIndex] = m_pIdentifier[vReinsert[cIndex]];
518  }
519 
520  for (cIndex = 0; cIndex < lKeep; ++cIndex)
521  {
522  keeplen[cIndex] = m_pDataLength[vKeep[cIndex]];
523  keepdata[cIndex] = m_pData[vKeep[cIndex]];
524  keepmbr[cIndex] = m_ptrMBR[vKeep[cIndex]];
525  keepid[cIndex] = m_pIdentifier[vKeep[cIndex]];
526  }
527 
528  delete[] m_pDataLength;
529  delete[] m_pData;
530  delete[] m_ptrMBR;
531  delete[] m_pIdentifier;
532 
533  m_pDataLength = keeplen;
534  m_pData = keepdata;
535  m_ptrMBR = keepmbr;
536  m_pIdentifier = keepid;
537  m_children = lKeep;
538  m_totalDataLength = 0;
539 
540  for (uint32_t cChild = 0; cChild < m_children; ++cChild) m_totalDataLength += m_pDataLength[cChild];
541 
542  m_nodeMBR.m_startTime = m_pTree->m_currentTime;
543 
544  for (uint32_t cDim = 0; cDim < m_nodeMBR.m_dimension; ++cDim)
545  {
546  m_nodeMBR.m_pLow[cDim] = std::numeric_limits<double>::max();
547  m_nodeMBR.m_pHigh[cDim] = -std::numeric_limits<double>::max();
548  m_nodeMBR.m_pVLow[cDim] = std::numeric_limits<double>::max();
549  m_nodeMBR.m_pVHigh[cDim] = -std::numeric_limits<double>::max();
550 
551  for (uint32_t cChild = 0; cChild < m_children; ++cChild)
552  {
553  m_nodeMBR.m_pLow[cDim] = std::min(m_nodeMBR.m_pLow[cDim], m_ptrMBR[cChild]->getExtrapolatedLow(cDim, m_nodeMBR.m_startTime));
554  m_nodeMBR.m_pHigh[cDim] = std::max(m_nodeMBR.m_pHigh[cDim], m_ptrMBR[cChild]->getExtrapolatedHigh(cDim, m_nodeMBR.m_startTime));
555  m_nodeMBR.m_pVLow[cDim] = std::min(m_nodeMBR.m_pVLow[cDim], m_ptrMBR[cChild]->m_pVLow[cDim]);
556  m_nodeMBR.m_pVHigh[cDim] = std::max(m_nodeMBR.m_pVHigh[cDim], m_ptrMBR[cChild]->m_pVHigh[cDim]);
557  }
558  m_nodeMBR.m_pLow[cDim] -= 2.0 * std::numeric_limits<double>::epsilon();
559  m_nodeMBR.m_pHigh[cDim] += 2.0 * std::numeric_limits<double>::epsilon();
560  }
561 
562 #ifndef NDEBUG
563  for (uint32_t cChild = 0; cChild < m_children; ++cChild)
564  {
565  assert(m_nodeMBR.containsRegionAfterTime(m_nodeMBR.m_startTime, *(m_ptrMBR[cChild])));
566  }
567 #endif
568 
569  m_pTree->writeNode(this);
570 
571  // Divertion from R*-Tree algorithm here. First adjust
572  // the path to the root, then start reinserts, to avoid complicated handling
573  // of changes to the same node from multiple insertions.
574  id_type cParent = pathBuffer.top(); pathBuffer.pop();
575  NodePtr ptrN = m_pTree->readNode(cParent);
576  Index* p = static_cast<Index*>(ptrN.get());
577  p->adjustTree(this, pathBuffer);
578 
579  for (cIndex = 0; cIndex < lReinsert; ++cIndex)
580  {
581  m_pTree->insertData_impl(
582  reinsertlen[cIndex], reinsertdata[cIndex],
583  *(reinsertmbr[cIndex]), reinsertid[cIndex],
584  m_level, overflowTable);
585  }
586 
587  delete[] reinsertdata;
588  delete[] reinsertmbr;
589  delete[] reinsertid;
590  delete[] reinsertlen;
591 
592  return true;
593  }
594  else
595  {
596  NodePtr n;
597  NodePtr nn;
598  split(dataLength, pData, mbr, id, n, nn);
599 
600  if (pathBuffer.empty())
601  {
602  n->m_level = m_level;
603  nn->m_level = m_level;
604  n->m_identifier = -1;
605  nn->m_identifier = -1;
606 
607 #ifndef NDEBUG
608  for (uint32_t cChild = 0; cChild < n->m_children; ++cChild)
609  {
610  assert(n->m_nodeMBR.containsRegionAfterTime(n->m_nodeMBR.m_startTime, *(n->m_ptrMBR[cChild])) == true);
611  }
612  for (uint32_t cChild = 0; cChild < nn->m_children; ++cChild)
613  {
614  assert(nn->m_nodeMBR.containsRegionAfterTime(nn->m_nodeMBR.m_startTime, *(nn->m_ptrMBR[cChild])) == true);
615  }
616 #endif
617 
618  m_pTree->writeNode(n.get());
619  m_pTree->writeNode(nn.get());
620 
621  NodePtr ptrR = m_pTree->m_indexPool.acquire();
622  if (ptrR.get() == nullptr)
623  {
624  ptrR = NodePtr(new Index(m_pTree, m_pTree->m_rootID, m_level + 1), &(m_pTree->m_indexPool));
625  }
626  else
627  {
628  //ptrR->m_pTree = m_pTree;
629  ptrR->m_identifier = m_pTree->m_rootID;
630  ptrR->m_level = m_level + 1;
631  ptrR->m_nodeMBR = m_pTree->m_infiniteRegion;
632  }
633 
634  ptrR->insertEntry(0, nullptr, n->m_nodeMBR, n->m_identifier);
635  ptrR->insertEntry(0, nullptr, nn->m_nodeMBR, nn->m_identifier);
636 
637  m_pTree->writeNode(ptrR.get());
638 
639  m_pTree->m_stats.m_nodesInLevel[m_level] = 2;
640  m_pTree->m_stats.m_nodesInLevel.push_back(1);
641  m_pTree->m_stats.m_treeHeight = m_level + 2;
642  }
643  else
644  {
645  n->m_level = m_level;
646  nn->m_level = m_level;
647  n->m_identifier = m_identifier;
648  nn->m_identifier = -1;
649 
650 #ifndef NDEBUG
651  for (uint32_t cChild = 0; cChild < n->m_children; ++cChild)
652  {
653  assert(n->m_nodeMBR.containsRegionAfterTime(n->m_nodeMBR.m_startTime, *(n->m_ptrMBR[cChild])) == true);
654  }
655  for (uint32_t cChild = 0; cChild < nn->m_children; ++cChild)
656  {
657  assert(nn->m_nodeMBR.containsRegionAfterTime(nn->m_nodeMBR.m_startTime, *(nn->m_ptrMBR[cChild])) == true);
658  }
659 #endif
660 
661  m_pTree->writeNode(n.get());
662  m_pTree->writeNode(nn.get());
663 
664  id_type cParent = pathBuffer.top(); pathBuffer.pop();
665  NodePtr ptrN = m_pTree->readNode(cParent);
666  Index* p = static_cast<Index*>(ptrN.get());
667  p->adjustTree(n.get(), nn.get(), pathBuffer, overflowTable);
668  }
669 
670  return true;
671  }
672 }
673 
674 void Node::reinsertData(uint32_t dataLength, uint8_t* pData, MovingRegion& mbr, id_type id, std::vector<uint32_t>& reinsert, std::vector<uint32_t>& keep)
675 {
676  ReinsertEntry** v = new ReinsertEntry*[m_capacity + 1];
677 
678  m_pDataLength[m_children] = dataLength;
679  m_pData[m_children] = pData;
680  m_ptrMBR[m_children] = m_pTree->m_regionPool.acquire();
681  *(m_ptrMBR[m_children]) = mbr;
682  m_pIdentifier[m_children] = id;
683 
684  Tools::Interval ivT(m_pTree->m_currentTime, m_pTree->m_currentTime + m_pTree->m_horizon);
685 
686  for (uint32_t cChild = 0; cChild < m_capacity + 1; ++cChild)
687  {
688  try
689  {
690  v[cChild] = new ReinsertEntry(cChild, 0.0);
691  }
692  catch (...)
693  {
694  for (uint32_t i = 0; i < cChild; ++i) delete v[i];
695  delete[] v;
696  throw;
697  }
698 
699  v[cChild]->m_dist = m_nodeMBR.getCenterDistanceInTime(ivT, *(m_ptrMBR[cChild]));
700  }
701 
702  // sort by increasing order of distances.
703  ::qsort(v, m_capacity + 1, sizeof(ReinsertEntry*), ReinsertEntry::compareReinsertEntry);
704 
705  uint32_t cReinsert = static_cast<uint32_t>(std::floor((m_capacity + 1) * m_pTree->m_reinsertFactor));
706 
707  uint32_t cCount;
708 
709  for (cCount = 0; cCount < cReinsert; ++cCount)
710  {
711  reinsert.push_back(v[cCount]->m_index);
712  delete v[cCount];
713  }
714 
715  for (cCount = cReinsert; cCount < m_capacity + 1; ++cCount)
716  {
717  keep.push_back(v[cCount]->m_index);
718  delete v[cCount];
719  }
720 
721  delete[] v;
722 }
723 
724 /*
725 void Node::rtreeSplit(uint32_t dataLength, uint8_t* pData, Region& mbr, id_type id, std::vector<uint32_t>& group1, std::vector<uint32_t>& group2)
726 {
727  uint32_t cChild;
728  uint32_t minimumLoad = static_cast<uint32_t>(std::floor(m_capacity * m_pTree->m_fillFactor));
729 
730  // use this mask array for marking visited entries.
731  uint8_t* mask = new uint8_t[m_capacity + 1];
732  memset(mask, 0, m_capacity + 1);
733 
734  // insert new data in the node for easier manipulation. Data arrays are always
735  // by one larger than node capacity.
736  m_pDataLength[m_capacity] = dataLength;
737  m_pData[m_capacity] = pData;
738  m_ptrMBR[m_capacity] = m_pTree->m_regionPool.acquire();
739  *(m_ptrMBR[m_capacity]) = mbr;
740  m_pIdentifier[m_capacity] = id;
741 
742  // initialize each group with the seed entries.
743  uint32_t seed1, seed2;
744  pickSeeds(seed1, seed2);
745 
746  group1.push_back(seed1);
747  group2.push_back(seed2);
748 
749  mask[seed1] = 1;
750  mask[seed2] = 1;
751 
752  // find MBR of each group.
753  RegionPtr mbr1 = m_pTree->m_regionPool.acquire();
754  *mbr1 = *(m_ptrMBR[seed1]);
755  RegionPtr mbr2 = m_pTree->m_regionPool.acquire();
756  *mbr2 = *(m_ptrMBR[seed2]);
757 
758  // count how many entries are left unchecked (exclude the seeds here.)
759  uint32_t cRemaining = m_capacity + 1 - 2;
760 
761  while (cRemaining > 0)
762  {
763  if (minimumLoad - group1.size() == cRemaining)
764  {
765  // all remaining entries must be assigned to group1 to comply with minimun load requirement.
766  for (cChild = 0; cChild < m_capacity + 1; ++cChild)
767  {
768  if (mask[cChild] == 0)
769  {
770  group1.push_back(cChild);
771  mask[cChild] = 1;
772  --cRemaining;
773  }
774  }
775  }
776  else if (minimumLoad - group2.size() == cRemaining)
777  {
778  // all remaining entries must be assigned to group2 to comply with minimun load requirement.
779  for (cChild = 0; cChild < m_capacity + 1; ++cChild)
780  {
781  if (mask[cChild] == 0)
782  {
783  group2.push_back(cChild);
784  mask[cChild] = 1;
785  --cRemaining;
786  }
787  }
788  }
789  else
790  {
791  // For all remaining entries compute the difference of the cost of grouping an
792  // entry in either group. When done, choose the entry that yielded the maximum
793  // difference. In case of linear split, select any entry (e.g. the first one.)
794  uint32_t sel;
795  double md1 = 0.0, md2 = 0.0;
796  double m = -std::numeric_limits<double>::max();
797  double d1, d2, d;
798  double a1 = mbr1->getArea();
799  double a2 = mbr2->getArea();
800 
801  RegionPtr a = m_pTree->m_regionPool.acquire();
802  RegionPtr b = m_pTree->m_regionPool.acquire();
803 
804  for (cChild = 0; cChild < m_capacity + 1; ++cChild)
805  {
806  if (mask[cChild] == 0)
807  {
808  mbr1->getCombinedRegion(*a, *(m_ptrMBR[cChild]));
809  d1 = a->getArea() - a1;
810  mbr2->getCombinedRegion(*b, *(m_ptrMBR[cChild]));
811  d2 = b->getArea() - a2;
812  d = std::abs(d1 - d2);
813 
814  if (d > m)
815  {
816  m = d;
817  md1 = d1; md2 = d2;
818  sel = cChild;
819  if (m_pTree->m_treeVariant== RV_LINEAR || m_pTree->m_treeVariant == RV_RSTAR) break;
820  }
821  }
822  }
823 
824  // determine the group where we should add the new entry.
825  int32_t group = -1;
826 
827  if (md1 < md2)
828  {
829  group1.push_back(sel);
830  group = 1;
831  }
832  else if (md2 < md1)
833  {
834  group2.push_back(sel);
835  group = 2;
836  }
837  else if (a1 < a2)
838  {
839  group1.push_back(sel);
840  group = 1;
841  }
842  else if (a2 < a1)
843  {
844  group2.push_back(sel);
845  group = 2;
846  }
847  else if (group1.size() < group2.size())
848  {
849  group1.push_back(sel);
850  group = 1;
851  }
852  else if (group2.size() < group1.size())
853  {
854  group2.push_back(sel);
855  group = 2;
856  }
857  else
858  {
859  group1.push_back(sel);
860  group = 1;
861  }
862  mask[sel] = 1;
863  --cRemaining;
864  if (group == 1)
865  {
866  mbr1->combineRegion(*(m_ptrMBR[sel]));
867  }
868  else
869  {
870  mbr2->combineRegion(*(m_ptrMBR[sel]));
871  }
872  }
873  }
874 
875  delete[] mask;
876 }
877 */
878 
879 void Node::rstarSplit(uint32_t dataLength, uint8_t* pData, MovingRegion& mbr, id_type id, std::vector<uint32_t>& group1, std::vector<uint32_t>& group2)
880 {
881  RstarSplitEntry** dataLow = nullptr;
882  RstarSplitEntry** dataHigh = nullptr;
883  RstarSplitEntry** dataVLow = nullptr;
884  RstarSplitEntry** dataVHigh = nullptr;
885 
886  try
887  {
888  dataLow = new RstarSplitEntry*[m_capacity + 1];
889  dataHigh = new RstarSplitEntry*[m_capacity + 1];
890  dataVLow = new RstarSplitEntry*[m_capacity + 1];
891  dataVHigh = new RstarSplitEntry*[m_capacity + 1];
892  }
893  catch (...)
894  {
895  delete[] dataLow;
896  delete[] dataHigh;
897  delete[] dataVLow;
898  delete[] dataVHigh;
899  throw;
900  }
901 
902  m_pDataLength[m_capacity] = dataLength;
903  m_pData[m_capacity] = pData;
904  m_ptrMBR[m_capacity] = m_pTree->m_regionPool.acquire();
905  *(m_ptrMBR[m_capacity]) = mbr;
906  m_pIdentifier[m_capacity] = id;
907 
908  uint32_t nodeSPF = static_cast<uint32_t>(std::floor((m_capacity + 1) * m_pTree->m_splitDistributionFactor));
909  uint32_t splitDistribution = (m_capacity + 1) - (2 * nodeSPF) + 2;
910 
911  Tools::Interval ivT(m_pTree->m_currentTime, m_pTree->m_currentTime + m_pTree->m_horizon);
912 
913  uint32_t cChild = 0, cDim, cIndex;
914 
915  for (cChild = 0; cChild <= m_capacity; ++cChild)
916  {
917  try
918  {
919  dataLow[cChild] = new RstarSplitEntry(m_ptrMBR[cChild].get(), cChild, 0);
920  }
921  catch (...)
922  {
923  for (uint32_t i = 0; i < cChild; ++i) delete dataLow[i];
924  delete[] dataLow;
925  delete[] dataHigh;
926  throw;
927  }
928 
929  dataHigh[cChild] = dataLow[cChild];
930  dataVLow[cChild] = dataLow[cChild];
931  dataVHigh[cChild] = dataLow[cChild];
932  }
933 
934  double minimumMargin = std::numeric_limits<double>::max();
935  uint32_t splitAxis = std::numeric_limits<uint32_t>::max();
936  uint32_t sortOrder = std::numeric_limits<uint32_t>::max();
937 
938  // chooseSplitAxis.
939  for (cDim = 0; cDim < m_pTree->m_dimension; ++cDim)
940  {
941  ::qsort(dataLow, m_capacity + 1, sizeof(RstarSplitEntry*), RstarSplitEntry::compareLow);
942  ::qsort(dataHigh, m_capacity + 1, sizeof(RstarSplitEntry*), RstarSplitEntry::compareHigh);
943  ::qsort(dataVLow, m_capacity + 1, sizeof(RstarSplitEntry*), RstarSplitEntry::compareVLow);
944  ::qsort(dataVHigh, m_capacity + 1, sizeof(RstarSplitEntry*), RstarSplitEntry::compareVHigh);
945 
946  // calculate sum of margins and overlap for all distributions.
947  double marginl = 0.0;
948  double marginh = 0.0;
949  double marginvl = 0.0;
950  double marginvh = 0.0;
951 
952  MovingRegion bbl1, bbl2, bbh1, bbh2;
953  MovingRegion bbvl1, bbvl2, bbvh1, bbvh2;
954 
955  for (cChild = 1; cChild <= splitDistribution; ++cChild)
956  {
957  uint32_t l = nodeSPF - 1 + cChild;
958 
959  bbl1 = *(dataLow[0]->m_pRegion);
960  bbh1 = *(dataHigh[0]->m_pRegion);
961  bbvl1 = *(dataVLow[0]->m_pRegion);
962  bbvh1 = *(dataVHigh[0]->m_pRegion);
963 
964  for (cIndex = 1; cIndex < l; ++cIndex)
965  {
966  bbl1.combineRegionAfterTime(m_pTree->m_currentTime, *(dataLow[cIndex]->m_pRegion));
967  bbh1.combineRegionAfterTime(m_pTree->m_currentTime, *(dataHigh[cIndex]->m_pRegion));
968  bbvl1.combineRegionAfterTime(m_pTree->m_currentTime, *(dataVLow[cIndex]->m_pRegion));
969  bbvh1.combineRegionAfterTime(m_pTree->m_currentTime, *(dataVHigh[cIndex]->m_pRegion));
970  }
971 
972  bbl2 = *(dataLow[l]->m_pRegion);
973  bbh2 = *(dataHigh[l]->m_pRegion);
974  bbvl2 = *(dataVLow[l]->m_pRegion);
975  bbvh2 = *(dataVHigh[l]->m_pRegion);
976 
977  for (cIndex = l + 1; cIndex <= m_capacity; ++cIndex)
978  {
979  bbl2.combineRegionAfterTime(m_pTree->m_currentTime, *(dataLow[cIndex]->m_pRegion));
980  bbh2.combineRegionAfterTime(m_pTree->m_currentTime, *(dataHigh[cIndex]->m_pRegion));
981  bbvl2.combineRegionAfterTime(m_pTree->m_currentTime, *(dataVLow[cIndex]->m_pRegion));
982  bbvh2.combineRegionAfterTime(m_pTree->m_currentTime, *(dataVHigh[cIndex]->m_pRegion));
983  }
984 
985  marginl += bbl1.getProjectedSurfaceAreaInTime(ivT) + bbl2.getProjectedSurfaceAreaInTime(ivT);
986  marginh += bbh1.getProjectedSurfaceAreaInTime(ivT) + bbh2.getProjectedSurfaceAreaInTime(ivT);
987  marginvl += bbvl1.getProjectedSurfaceAreaInTime(ivT) + bbvl2.getProjectedSurfaceAreaInTime(ivT);
988  marginvh += bbvh1.getProjectedSurfaceAreaInTime(ivT) + bbvh2.getProjectedSurfaceAreaInTime(ivT);
989  } // for (cChild)
990 
991  double margin = std::min(std::min(marginl, marginh), std::min(marginvl, marginvh));
992 
993  // keep minimum margin as split axis.
994  if (margin < minimumMargin)
995  {
996  minimumMargin = margin;
997  splitAxis = cDim;
998  if (marginl < marginh && marginl < marginvl && marginl < marginvh) sortOrder = 0;
999  else if (marginh < marginl && marginh < marginvl && marginh < marginvh) sortOrder = 1;
1000  else if (marginvl < marginl && marginvl < marginh && marginvl < marginvh) sortOrder = 2;
1001  else if (marginvh < marginl && marginvh < marginh && marginvh < marginvl) sortOrder = 3;
1002  }
1003 
1004  // increase the dimension according to which the data entries should be sorted.
1005  for (cChild = 0; cChild <= m_capacity; ++cChild)
1006  {
1007  dataLow[cChild]->m_sortDim = cDim + 1;
1008  }
1009  } // for (cDim)
1010 
1011  for (cChild = 0; cChild <= m_capacity; ++cChild)
1012  {
1013  dataLow[cChild]->m_sortDim = splitAxis;
1014  }
1015 
1016  if (sortOrder == 0)
1017  ::qsort(dataLow, m_capacity + 1, sizeof(RstarSplitEntry*), RstarSplitEntry::compareLow);
1018  else if (sortOrder == 1)
1019  ::qsort(dataLow, m_capacity + 1, sizeof(RstarSplitEntry*), RstarSplitEntry::compareHigh);
1020  else if (sortOrder == 2)
1021  ::qsort(dataLow, m_capacity + 1, sizeof(RstarSplitEntry*), RstarSplitEntry::compareVLow);
1022  else if (sortOrder == 3)
1023  ::qsort(dataLow, m_capacity + 1, sizeof(RstarSplitEntry*), RstarSplitEntry::compareVHigh);
1024 
1025  double ma = std::numeric_limits<double>::max();
1026  double mo = std::numeric_limits<double>::max();
1027  uint32_t splitPoint = std::numeric_limits<uint32_t>::max();
1028 
1029  MovingRegion bb1, bb2;
1030 
1031  for (cChild = 1; cChild <= splitDistribution; ++cChild)
1032  {
1033  uint32_t l = nodeSPF - 1 + cChild;
1034 
1035  bb1 = *(dataLow[0]->m_pRegion);
1036 
1037  for (cIndex = 1; cIndex < l; ++cIndex)
1038  {
1039  bb1.combineRegionAfterTime(m_pTree->m_currentTime, *(dataLow[cIndex]->m_pRegion));
1040  }
1041 
1042  bb2 = *(dataLow[l]->m_pRegion);
1043 
1044  for (cIndex = l + 1; cIndex <= m_capacity; ++cIndex)
1045  {
1046  bb2.combineRegionAfterTime(m_pTree->m_currentTime, *(dataLow[cIndex]->m_pRegion));
1047  }
1048 
1049  double o = bb1.getIntersectingAreaInTime(ivT, bb2);
1050 
1051  if (o < mo)
1052  {
1053  splitPoint = cChild;
1054  mo = o;
1055  ma = bb1.getAreaInTime(ivT) + bb2.getAreaInTime(ivT);
1056  }
1057  else if (o == mo)
1058  {
1059  double a = bb1.getAreaInTime(ivT) + bb2.getAreaInTime(ivT);
1060 
1061  if (a < ma)
1062  {
1063  splitPoint = cChild;
1064  ma = a;
1065  }
1066  }
1067  } // for (cChild)
1068 
1069  uint32_t l1 = nodeSPF - 1 + splitPoint;
1070 
1071  for (cIndex = 0; cIndex < l1; ++cIndex)
1072  {
1073  group1.push_back(dataLow[cIndex]->m_index);
1074  delete dataLow[cIndex];
1075  }
1076 
1077  for (cIndex = l1; cIndex <= m_capacity; ++cIndex)
1078  {
1079  group2.push_back(dataLow[cIndex]->m_index);
1080  delete dataLow[cIndex];
1081  }
1082 
1083  delete[] dataLow;
1084  delete[] dataHigh;
1085  delete[] dataVLow;
1086  delete[] dataVHigh;
1087 }
1088 
1089 /*
1090 void Node::pickSeeds(uint32_t& index1, uint32_t& index2)
1091 {
1092  double separation = -std::numeric_limits<double>::max();
1093  double inefficiency = -std::numeric_limits<double>::max();
1094  uint32_t cDim, cChild, cIndex;
1095 
1096  switch (m_pTree->m_treeVariant)
1097  {
1098  case RV_LINEAR:
1099  case RV_RSTAR:
1100  for (cDim = 0; cDim < m_pTree->m_dimension; ++cDim)
1101  {
1102  double leastLower = m_ptrMBR[0]->m_pLow[cDim];
1103  double greatestUpper = m_ptrMBR[0]->m_pHigh[cDim];
1104  uint32_t greatestLower = 0;
1105  uint32_t leastUpper = 0;
1106  double width;
1107 
1108  for (cChild = 1; cChild <= m_capacity; ++cChild)
1109  {
1110  if (m_ptrMBR[cChild]->m_pLow[cDim] > m_ptrMBR[greatestLower]->m_pLow[cDim]) greatestLower = cChild;
1111  if (m_ptrMBR[cChild]->m_pHigh[cDim] < m_ptrMBR[leastUpper]->m_pHigh[cDim]) leastUpper = cChild;
1112 
1113  leastLower = std::min(m_ptrMBR[cChild]->m_pLow[cDim], leastLower);
1114  greatestUpper = std::max(m_ptrMBR[cChild]->m_pHigh[cDim], greatestUpper);
1115  }
1116 
1117  width = greatestUpper - leastLower;
1118  if (width <= 0) width = 1;
1119 
1120  double f = (m_ptrMBR[greatestLower]->m_pLow[cDim] - m_ptrMBR[leastUpper]->m_pHigh[cDim]) / width;
1121 
1122  if (f > separation)
1123  {
1124  index1 = leastUpper;
1125  index2 = greatestLower;
1126  separation = f;
1127  }
1128  } // for (cDim)
1129 
1130  if (index1 == index2)
1131  {
1132  if (index2 == 0) ++index2;
1133  else --index2;
1134  }
1135 
1136  break;
1137  case RV_QUADRATIC:
1138  // for each pair of Regions (account for overflow Region too!)
1139  for (cChild = 0; cChild < m_capacity; ++cChild)
1140  {
1141  double a = m_ptrMBR[cChild]->getArea();
1142 
1143  for (cIndex = cChild + 1; cIndex <= m_capacity; ++cIndex)
1144  {
1145  // get the combined MBR of those two entries.
1146  Region r;
1147  m_ptrMBR[cChild]->getCombinedRegion(r, *(m_ptrMBR[cIndex]));
1148 
1149  // find the inefficiency of grouping these entries together.
1150  double d = r.getArea() - a - m_ptrMBR[cIndex]->getArea();
1151 
1152  if (d > inefficiency)
1153  {
1154  inefficiency = d;
1155  index1 = cChild;
1156  index2 = cIndex;
1157  }
1158  } // for (cIndex)
1159  } // for (cChild)
1160 
1161  break;
1162  default:
1163  throw Tools::NotSupportedException("Node::pickSeeds: Tree variant not supported.");
1164  }
1165 }
1166 */
1167 
1168 void Node::condenseTree(std::stack<NodePtr>& toReinsert, std::stack<id_type>& pathBuffer, NodePtr& ptrThis)
1169 {
1170  uint32_t minimumLoad = static_cast<uint32_t>(std::floor(m_capacity * m_pTree->m_fillFactor));
1171 
1172  if (pathBuffer.empty())
1173  {
1174  // eliminate root if it has only one child.
1175  if (m_level != 0 && m_children == 1)
1176  {
1177  NodePtr ptrN = m_pTree->readNode(m_pIdentifier[0]);
1178  m_pTree->deleteNode(ptrN.get());
1179  ptrN->m_identifier = m_pTree->m_rootID;
1180  m_pTree->writeNode(ptrN.get());
1181 
1182  m_pTree->m_stats.m_nodesInLevel.pop_back();
1183  m_pTree->m_stats.m_treeHeight -= 1;
1184  // HACK: pending deleteNode for deleted child will decrease nodesInLevel, later on.
1185  m_pTree->m_stats.m_nodesInLevel[m_pTree->m_stats.m_treeHeight - 1] = 2;
1186  }
1187  }
1188  else
1189  {
1190  id_type cParent = pathBuffer.top(); pathBuffer.pop();
1191  NodePtr ptrParent = m_pTree->readNode(cParent);
1192  Index* p = static_cast<Index*>(ptrParent.get());
1193 
1194  // find the entry in the parent, that points to this node.
1195  uint32_t child;
1196 
1197  for (child = 0; child != p->m_children; ++child)
1198  {
1199  if (p->m_pIdentifier[child] == m_identifier) break;
1200  }
1201 
1202  if (m_children < minimumLoad)
1203  {
1204  // used space less than the minimum
1205  // 1. eliminate node entry from the parent. deleteEntry will fix the parent's MBR.
1206  p->deleteEntry(child);
1207  // 2. add this node to the stack in order to reinsert its entries.
1208  toReinsert.push(ptrThis);
1209  }
1210  else
1211  {
1212  // adjust the entry in 'p' to contain the new bounding region of this node.
1213  *(p->m_ptrMBR[child]) = m_nodeMBR;
1214 
1215  // global recalculation necessary since the MBR can only shrink in size,
1216  // due to data removal.
1217  //if (m_pTree->m_bTightMBRs)
1218  //{
1219 
1220  p->m_nodeMBR.m_startTime = m_pTree->m_currentTime;
1221 
1222  for (uint32_t cDim = 0; cDim < p->m_nodeMBR.m_dimension; ++cDim)
1223  {
1224  p->m_nodeMBR.m_pLow[cDim] = std::numeric_limits<double>::max();
1225  p->m_nodeMBR.m_pHigh[cDim] = -std::numeric_limits<double>::max();
1226  p->m_nodeMBR.m_pVLow[cDim] = std::numeric_limits<double>::max();
1227  p->m_nodeMBR.m_pVHigh[cDim] = -std::numeric_limits<double>::max();
1228 
1229  for (uint32_t cChild = 0; cChild < p->m_children; ++cChild)
1230  {
1231  p->m_nodeMBR.m_pLow[cDim] = std::min(p->m_nodeMBR.m_pLow[cDim], p->m_ptrMBR[cChild]->getExtrapolatedLow(cDim, m_pTree->m_currentTime));
1232  p->m_nodeMBR.m_pHigh[cDim] = std::max(p->m_nodeMBR.m_pHigh[cDim], p->m_ptrMBR[cChild]->getExtrapolatedHigh(cDim, m_pTree->m_currentTime));
1233  p->m_nodeMBR.m_pVLow[cDim] = std::min(p->m_nodeMBR.m_pVLow[cDim], p->m_ptrMBR[cChild]->m_pVLow[cDim]);
1234  p->m_nodeMBR.m_pVHigh[cDim] = std::max(p->m_nodeMBR.m_pVHigh[cDim], p->m_ptrMBR[cChild]->m_pVHigh[cDim]);
1235  }
1236  p->m_nodeMBR.m_pLow[cDim] -= 2.0 * std::numeric_limits<double>::epsilon();
1237  p->m_nodeMBR.m_pHigh[cDim] += 2.0 * std::numeric_limits<double>::epsilon();
1238  }
1239  //}
1240  }
1241 
1242  // write parent node back to storage.
1243  m_pTree->writeNode(p);
1244 
1245  p->condenseTree(toReinsert, pathBuffer, ptrParent);
1246  }
1247 }
virtual double getExtrapolatedHigh(uint32_t index, double t) const
bool isLeaf() const override
void makeDimension(uint32_t dimension) override
virtual double getExtrapolatedLow(uint32_t index, double t) const
id_type getChildIdentifier(uint32_t index) const override
void makeInfinite(uint32_t dimension) override
PoolPointer< X > acquire()
Definition: PointerPool.h:64
void storeToByteArray(uint8_t **data, uint32_t &len) override
virtual double getCenterDistanceInTime(const MovingRegion &r) const
virtual double getProjectedSurfaceAreaInTime() const
double * m_pLow
Definition: Region.h:98
void loadFromByteArray(const uint8_t *data) override
Definition: tprtree/Node.cc:64
virtual double getIntersectingAreaInTime(const MovingRegion &r) const
void getChildShape(uint32_t index, IShape **out) const override
double getAreaInTime() const override
uint32_t m_dimension
Definition: Region.h:97
double * m_pHigh
Definition: Region.h:99
X * get() const noexcept
Definition: PoolPointer.h:55
Tools::PoolPointer< Node > NodePtr
Definition: tprtree/Node.h:39
virtual void combineRegionAfterTime(double t, const MovingRegion &r)
bool isIndex() const override
uint32_t getLevel() const override
Tools::IObject * clone() override
Definition: tprtree/Node.cc:44
void getChildData(uint32_t index, uint32_t &length, uint8_t **data) const override
int64_t id_type
Definition: SpatialIndex.h:41
SpatialIndex::ISpatialIndex & index()
id_type getIdentifier() const override
uint32_t getByteArraySize() override
Definition: tprtree/Node.cc:52
uint32_t getChildrenCount() const override
void getShape(IShape **out) const override
virtual bool containsRegionAfterTime(double t, const MovingRegion &r) const