libspatialindex API Reference  (git-trunk)
mvrtree/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 "MVRTree.h"
35 #include "Node.h"
36 #include "Index.h"
37 #include "Leaf.h"
38 
39 using namespace SpatialIndex;
40 using namespace SpatialIndex::MVRTree;
41 
42 //
43 // Tools::IObject interface
44 //
46 {
47  throw Tools::NotSupportedException("IObject::clone should never be called.");
48 }
49 
50 //
51 // Tools::ISerializable interface
52 //
54 {
55  return
56  (sizeof(uint32_t) +
57  sizeof(uint32_t) +
58  sizeof(uint32_t) +
59  sizeof(double) +
60  sizeof(double) +
61  (m_children * (m_pTree->m_dimension * sizeof(double) * 2 + sizeof(id_type) + 2 * sizeof(double) + sizeof(uint32_t))) +
62  m_totalDataLength +
63  (2 * m_pTree->m_dimension * sizeof(double)));
64 }
65 
66 void Node::loadFromByteArray(const uint8_t* ptr)
67 {
68  m_nodeMBR = m_pTree->m_infiniteRegion;
69 
70  // skip the node type information, it is not needed.
71  ptr += sizeof(uint32_t);
72 
73  memcpy(&m_level, ptr, sizeof(uint32_t));
74  ptr += sizeof(uint32_t);
75 
76  memcpy(&m_children, ptr, sizeof(uint32_t));
77  ptr += sizeof(uint32_t);
78 
79  memcpy(&(m_nodeMBR.m_startTime), ptr, sizeof(double));
80  ptr += sizeof(double);
81  memcpy(&(m_nodeMBR.m_endTime), ptr, sizeof(double));
82  ptr += sizeof(double);
83 
84  for (uint32_t cChild = 0; cChild < m_children; ++cChild)
85  {
86  m_ptrMBR[cChild] = m_pTree->m_regionPool.acquire();
87  *(m_ptrMBR[cChild]) = m_pTree->m_infiniteRegion;
88 
89  memcpy(m_ptrMBR[cChild]->m_pLow, ptr, m_pTree->m_dimension * sizeof(double));
90  ptr += m_pTree->m_dimension * sizeof(double);
91  memcpy(m_ptrMBR[cChild]->m_pHigh, ptr, m_pTree->m_dimension * sizeof(double));
92  ptr += m_pTree->m_dimension * sizeof(double);
93  memcpy(&(m_pIdentifier[cChild]), ptr, sizeof(id_type));
94  ptr += sizeof(id_type);
95  memcpy(&(m_ptrMBR[cChild]->m_startTime), ptr, sizeof(double));
96  ptr += sizeof(double);
97  memcpy(&(m_ptrMBR[cChild]->m_endTime), ptr, sizeof(double));
98  ptr += sizeof(double);
99 
100  memcpy(&(m_pDataLength[cChild]), ptr, sizeof(uint32_t));
101  ptr += sizeof(uint32_t);
102 
103  if (m_pDataLength[cChild] > 0)
104  {
105  m_totalDataLength += m_pDataLength[cChild];
106  m_pData[cChild] = new uint8_t[m_pDataLength[cChild]];
107  memcpy(m_pData[cChild], ptr, m_pDataLength[cChild]);
108  ptr += m_pDataLength[cChild];
109  }
110  else
111  {
112  m_pData[cChild] = nullptr;
113  }
114 
115  //m_nodeMBR.combineRegion(*(m_ptrMBR[cChild]));
116  }
117 
118  memcpy(m_nodeMBR.m_pLow, ptr, m_pTree->m_dimension * sizeof(double));
119  ptr += m_pTree->m_dimension * sizeof(double);
120  memcpy(m_nodeMBR.m_pHigh, ptr, m_pTree->m_dimension * sizeof(double));
121  //ptr += m_pTree->m_dimension * sizeof(double);
122 }
123 
124 void Node::storeToByteArray(uint8_t** data, uint32_t& len)
125 {
126  len = getByteArraySize();
127 
128  *data = new uint8_t[len];
129  uint8_t* ptr = *data;
130 
131  uint32_t nodeType;
132 
133  if (m_level == 0) nodeType = PersistentLeaf;
134  else nodeType = PersistentIndex;
135 
136  memcpy(ptr, &nodeType, sizeof(uint32_t));
137  ptr += sizeof(uint32_t);
138 
139  memcpy(ptr, &m_level, sizeof(uint32_t));
140  ptr += sizeof(uint32_t);
141 
142  memcpy(ptr, &m_children, sizeof(uint32_t));
143  ptr += sizeof(uint32_t);
144 
145  memcpy(ptr, &(m_nodeMBR.m_startTime), sizeof(double));
146  ptr += sizeof(double);
147  memcpy(ptr, &(m_nodeMBR.m_endTime), sizeof(double));
148  ptr += sizeof(double);
149 
150  for (uint32_t cChild = 0; cChild < m_children; ++cChild)
151  {
152  memcpy(ptr, m_ptrMBR[cChild]->m_pLow, m_pTree->m_dimension * sizeof(double));
153  ptr += m_pTree->m_dimension * sizeof(double);
154  memcpy(ptr, m_ptrMBR[cChild]->m_pHigh, m_pTree->m_dimension * sizeof(double));
155  ptr += m_pTree->m_dimension * sizeof(double);
156  memcpy(ptr, &(m_pIdentifier[cChild]), sizeof(id_type));
157  ptr += sizeof(id_type);
158  memcpy(ptr, &(m_ptrMBR[cChild]->m_startTime), sizeof(double));
159  ptr += sizeof(double);
160  memcpy(ptr, &(m_ptrMBR[cChild]->m_endTime), sizeof(double));
161  ptr += sizeof(double);
162 
163  memcpy(ptr, &(m_pDataLength[cChild]), sizeof(uint32_t));
164  ptr += sizeof(uint32_t);
165 
166  if (m_pDataLength[cChild] > 0)
167  {
168  memcpy(ptr, m_pData[cChild], m_pDataLength[cChild]);
169  ptr += m_pDataLength[cChild];
170  }
171  }
172 
173  // store the node MBR for efficiency. This increases the node size a little bit.
174  memcpy(ptr, m_nodeMBR.m_pLow, m_pTree->m_dimension * sizeof(double));
175  ptr += m_pTree->m_dimension * sizeof(double);
176  memcpy(ptr, m_nodeMBR.m_pHigh, m_pTree->m_dimension * sizeof(double));
177  //ptr += m_pTree->m_dimension * sizeof(double);
178 }
179 
180 //
181 // SpatialIndex::IEntry interface
182 //
184 {
185  return m_identifier;
186 }
187 
188 void Node::getShape(IShape** out) const
189 {
190  *out = new TimeRegion(m_nodeMBR);
191 }
192 
193 //
194 // SpatialIndex::INode interface
195 //
196 uint32_t Node::getChildrenCount() const
197 {
198  return m_children;
199 }
200 
202 {
203  if (index >= m_children) throw Tools::IndexOutOfBoundsException(index);
204 
205  return m_pIdentifier[index];
206 }
207 
208 void Node::getChildShape(uint32_t index, IShape** out) const
209 {
210  if (index >= m_children) throw Tools::IndexOutOfBoundsException(index);
211 
212  *out = new TimeRegion(*(m_ptrMBR[index]));
213 }
214 
215 
216 void Node::getChildData(uint32_t index, uint32_t& length, uint8_t** data) const
217 {
218  if (index >= m_children) throw Tools::IndexOutOfBoundsException(index);
219  if (m_pData[index] == nullptr)
220  {
221  length = 0;
222  data = nullptr;
223  }
224  else
225  {
226  length = m_pDataLength[index];
227  *data = m_pData[index];
228  }
229 }
230 
231 uint32_t Node::getLevel() const
232 {
233  return m_level;
234 }
235 
236 bool Node::isLeaf() const
237 {
238  return (m_level == 0);
239 }
240 
241 bool Node::isIndex() const
242 {
243  return (m_level != 0);
244 }
245 
246 //
247 // Internal
248 //
249 
250 Node::Node()
251 = default;
252 
253  Node::Node(SpatialIndex::MVRTree::MVRTree* pTree, id_type id, uint32_t level, uint32_t capacity) :
254  m_pTree(pTree),
255  m_level(level),
256  m_identifier(id),
257  m_children(0),
258  m_capacity(capacity),
259  m_pData(nullptr),
260  m_ptrMBR(nullptr),
261  m_pIdentifier(nullptr),
262  m_pDataLength(nullptr),
263  m_totalDataLength(0)
264 {
265  m_nodeMBR.makeInfinite(m_pTree->m_dimension);
266 
267  try
268  {
269  m_pDataLength = new uint32_t[m_capacity + 2];
270  m_pData = new uint8_t*[m_capacity + 2];
271  m_ptrMBR = new TimeRegionPtr[m_capacity + 2];
272  m_pIdentifier = new id_type[m_capacity + 2];
273  }
274  catch (...)
275  {
276  delete[] m_pDataLength;
277  delete[] m_pData;
278  delete[] m_ptrMBR;
279  delete[] m_pIdentifier;
280  throw;
281  }
282 }
283 
285 {
286  if (m_pData != nullptr)
287  {
288  for (uint32_t cChild = 0; cChild < m_children; ++cChild)
289  {
290  if (m_pData[cChild] != nullptr) delete[] m_pData[cChild];
291  }
292 
293  delete[] m_pData;
294  delete[] m_pDataLength;
295  }
296 
297  if (m_ptrMBR != nullptr) delete[] m_ptrMBR;
298  if (m_pIdentifier != nullptr) delete[] m_pIdentifier;
299 }
300 
301 Node& Node::operator=(const Node&)
302 {
303  throw Tools::IllegalStateException("operator =: This should never be called.");
304 }
305 
306 void Node::insertEntry(uint32_t dataLength, uint8_t* pData, TimeRegion& mbr, id_type id)
307 {
308  assert(m_children < m_capacity);
309 
310  m_pDataLength[m_children] = dataLength;
311  m_pData[m_children] = pData;
312  m_ptrMBR[m_children] = m_pTree->m_regionPool.acquire();
313  *(m_ptrMBR[m_children]) = mbr;
314  m_pIdentifier[m_children] = id;
315 
316  m_totalDataLength += dataLength;
317  ++m_children;
318 
319  m_nodeMBR.combineRegionInTime(mbr);
320 }
321 
322 bool Node::deleteEntry(uint32_t index)
323 {
324  assert(index >= 0 && index < m_children);
325 
326  // cache it, since I might need it for "touches" later.
327  TimeRegionPtr ptrR = m_ptrMBR[index];
328 
329  m_totalDataLength -= m_pDataLength[index];
330  if (m_pData[index] != nullptr) delete[] m_pData[index];
331 
332  if (m_children > 1 && index != m_children - 1)
333  {
334  m_pDataLength[index] = m_pDataLength[m_children - 1];
335  m_pData[index] = m_pData[m_children - 1];
336  m_ptrMBR[index] = m_ptrMBR[m_children - 1];
337  m_pIdentifier[index] = m_pIdentifier[m_children - 1];
338  }
339 
340  --m_children;
341 
342  // WARNING: index has now changed. Do not use it below here.
343 
344  if (m_children == 0)
345  {
346  m_nodeMBR = m_pTree->m_infiniteRegion;
347  return true;
348  }
349  else if (m_pTree->m_bTightMBRs && m_nodeMBR.touchesShape(*ptrR))
350  {
351  for (uint32_t cDim = 0; cDim < m_nodeMBR.m_dimension; ++cDim)
352  {
353  m_nodeMBR.m_pLow[cDim] = std::numeric_limits<double>::max();
354  m_nodeMBR.m_pHigh[cDim] = -std::numeric_limits<double>::max();
355 
356  for (uint32_t cChild = 0; cChild < m_children; ++cChild)
357  {
358  m_nodeMBR.m_pLow[cDim] = std::min(m_nodeMBR.m_pLow[cDim], m_ptrMBR[cChild]->m_pLow[cDim]);
359  m_nodeMBR.m_pHigh[cDim] = std::max(m_nodeMBR.m_pHigh[cDim], m_ptrMBR[cChild]->m_pHigh[cDim]);
360  }
361  }
362  return true;
363  }
364 
365  return false;
366 }
367 
368 bool Node::insertData(
369  uint32_t dataLength, uint8_t* pData, TimeRegion& mbr, id_type id, std::stack<id_type>& pathBuffer,
370  TimeRegion& mbr2, id_type id2, bool bInsertMbr2, bool bForceAdjust)
371 {
372  // we should be certain that when bInsertMbr2 is true the node needs to be version split
373 
374  // this function returns true only if the node under modification has been stored (writeNode(this))
375  // it is needed since some times after a version copy we do not need to actually store the node. Only
376  // the parent has to be notified to modify the entry pointing
377  // to this node with the appropriate deletion time (thus we save one disk access)
378 
379  if ((! bInsertMbr2) && m_children < m_capacity)
380  {
381  // the node has empty space. Insert the entry here
382 
383  // this has to happen before insertEntry modifies m_nodeMBR.
384  bool b = m_nodeMBR.containsShape(mbr);
385 
386  insertEntry(dataLength, pData, mbr, id);
387  m_pTree->writeNode(this);
388 
389  // a forced adjust might be needed when a child has modified it MBR due to an entry deletion
390  // (when the entry start time becomes equal to the entry end time after a version copy)
391  if ((! b || bForceAdjust) && (! pathBuffer.empty()))
392  {
393  id_type cParent = pathBuffer.top(); pathBuffer.pop();
394  NodePtr ptrN = m_pTree->readNode(cParent);
395  Index* p = static_cast<Index*>(ptrN.get());
396  p->adjustTree(this, pathBuffer);
397  }
398 
399  return true;
400  }
401  else
402  {
403  // do a version copy
404 
405  bool bIsRoot = pathBuffer.empty();
406 
407  NodePtr ptrCopy;
408 
409  // copy live entries of this node into a new node. Create an index or a leaf respectively
410  if (m_level == 0)
411  {
412  ptrCopy = m_pTree->m_leafPool.acquire();
413  if (ptrCopy.get() == nullptr) ptrCopy = NodePtr(new Leaf(m_pTree, - 1), &(m_pTree->m_leafPool));
414  else ptrCopy->m_nodeMBR = m_pTree->m_infiniteRegion;
415  }
416  else
417  {
418  ptrCopy = m_pTree->m_indexPool.acquire();
419  if (ptrCopy.get() == nullptr) ptrCopy = NodePtr(new Index(m_pTree, -1, m_level), &(m_pTree->m_indexPool));
420  else
421  {
422  ptrCopy->m_level = m_level;
423  ptrCopy->m_nodeMBR = m_pTree->m_infiniteRegion;
424  }
425  }
426 
427  for (uint32_t cChild = 0; cChild < m_children; ++cChild)
428  {
429  if (! (m_ptrMBR[cChild]->m_endTime < std::numeric_limits<double>::max()))
430  {
431  uint8_t* data = nullptr;
432 
433  if (m_pDataLength[cChild] > 0)
434  {
435  data = new uint8_t[m_pDataLength[cChild]];
436  memcpy(data, m_pData[cChild], m_pDataLength[cChild] * sizeof(uint8_t));
437  }
438  ptrCopy->insertEntry(m_pDataLength[cChild], data, *(m_ptrMBR[cChild]), m_pIdentifier[cChild]);
439  ptrCopy->m_ptrMBR[ptrCopy->m_children - 1]->m_startTime = mbr.m_startTime;
440  }
441  }
442 
443  ptrCopy->m_nodeMBR.m_startTime = mbr.m_startTime;
444  m_nodeMBR.m_endTime = mbr.m_startTime;
445 
446  uint32_t children = (bInsertMbr2) ? ptrCopy->m_children + 2 : ptrCopy->m_children + 1;
447  assert(children > 0);
448 
449  if (children >= m_pTree->m_strongVersionOverflow * m_capacity)
450  {
451  // strong version overflow. Split!
452  NodePtr n;
453  NodePtr nn;
454  ptrCopy->split(dataLength, pData, mbr, id, n, nn, mbr2, id2, bInsertMbr2);
455  assert(n->m_children > 1 && nn->m_children > 1);
456 
457  if (bIsRoot)
458  {
459  // it is a root node. Special handling required.
460  n->m_level = ptrCopy->m_level;
461  nn->m_level = ptrCopy->m_level;
462  n->m_identifier = -1;
463  nn->m_identifier = -1;
464 
465  m_pTree->writeNode(n.get());
466  m_pTree->writeNode(nn.get());
467 
468  NodePtr ptrR = m_pTree->m_indexPool.acquire();
469  if (ptrR.get() == nullptr) ptrR = NodePtr(new Index(m_pTree, -1, ptrCopy->m_level + 1), &(m_pTree->m_indexPool));
470  else
471  {
472  //ptrR->m_pTree = m_pTree;
473  //ptrR->m_identifier = -1;
474  ptrR->m_level = ptrCopy->m_level + 1;
475  ptrR->m_nodeMBR = m_pTree->m_infiniteRegion;
476  }
477 
478  ptrR->insertEntry(0, nullptr, n->m_nodeMBR, n->m_identifier);
479  ptrR->insertEntry(0, nullptr, nn->m_nodeMBR, nn->m_identifier);
480 
481  if (m_nodeMBR.m_startTime == m_nodeMBR.m_endTime)
482  {
483  ptrR->m_identifier = m_identifier;
484  m_pTree->writeNode(ptrR.get());
485  m_pTree->m_stats.m_treeHeight[m_pTree->m_stats.m_treeHeight.size() - 1] = ptrR->m_level + 1;
486  m_pTree->m_stats.m_nodesInLevel.at(n->m_level) = m_pTree->m_stats.m_nodesInLevel[n->m_level] + 1;
487  assert(m_pTree->m_roots[m_pTree->m_roots.size() - 1].m_startTime == ptrCopy->m_nodeMBR.m_startTime &&
488  m_pTree->m_roots[m_pTree->m_roots.size() - 1].m_endTime == ptrCopy->m_nodeMBR.m_endTime);
489  }
490  else
491  {
492  m_pTree->writeNode(this);
493  m_pTree->writeNode(ptrR.get());
494 
495  assert(m_pTree->m_roots[m_pTree->m_roots.size() - 1].m_id == m_identifier);
496  m_pTree->m_roots[m_pTree->m_roots.size() - 1].m_startTime = m_nodeMBR.m_startTime;
497  m_pTree->m_roots[m_pTree->m_roots.size() - 1].m_endTime = m_nodeMBR.m_endTime;
498  m_pTree->m_roots.emplace_back(ptrR->m_identifier, ptrR->m_nodeMBR.m_startTime, ptrR->m_nodeMBR.m_endTime);
499  m_pTree->m_stats.m_treeHeight.push_back(ptrR->m_level + 1);
500  m_pTree->m_stats.m_nodesInLevel.at(n->m_level) = m_pTree->m_stats.m_nodesInLevel[n->m_level] + 2;
501  if (m_level > 0) ++(m_pTree->m_stats.m_u32DeadIndexNodes);
502  else ++(m_pTree->m_stats.m_u32DeadLeafNodes);
503  }
504 
505  if (ptrR->m_level >= m_pTree->m_stats.m_nodesInLevel.size()) m_pTree->m_stats.m_nodesInLevel.push_back(1);
506  else m_pTree->m_stats.m_nodesInLevel.at(ptrR->m_level) = m_pTree->m_stats.m_nodesInLevel[ptrR->m_level] + 1;
507 
508  return true;
509  }
510  else
511  {
512  bool b = false;
513 
514  n->m_level = ptrCopy->m_level;
515  nn->m_level = ptrCopy->m_level;
516 /*
517  if (m_nodeMBR.m_startTime == m_nodeMBR.m_endTime)
518  {
519  n->m_identifier = m_identifier;
520  m_pTree->m_stats.m_nodesInLevel[n->m_level] = m_pTree->m_stats.m_nodesInLevel[n->m_level] + 1;
521  b = true;
522  }
523  else
524  {
525  n->m_identifier = -1;
526  m_pTree->m_stats.m_nodesInLevel[n->m_level] = m_pTree->m_stats.m_nodesInLevel[n->m_level] + 2;
527  }
528 */
529  n->m_identifier = -1;
530  nn->m_identifier = -1;
531 
532  m_pTree->m_stats.m_nodesInLevel.at(n->m_level) = m_pTree->m_stats.m_nodesInLevel[n->m_level] + 2;
533  if (m_level > 0) ++(m_pTree->m_stats.m_u32DeadIndexNodes);
534  else ++(m_pTree->m_stats.m_u32DeadLeafNodes);
535 
536  m_pTree->writeNode(n.get());
537  m_pTree->writeNode(nn.get());
538 
539  id_type cParent = pathBuffer.top(); pathBuffer.pop();
540  NodePtr ptrN = m_pTree->readNode(cParent);
541  Index* p = static_cast<Index*>(ptrN.get());
542  ++(m_pTree->m_stats.m_u64Adjustments);
543 
544  // this is the special insertion function for two new nodes, defined below
545  p->insertData(n->m_nodeMBR, n->m_identifier, nn->m_nodeMBR, nn->m_identifier, this, pathBuffer);
546 
547  return b;
548  }
549  }
550  //else if (children < m_pTree->m_strongVersionUnderflow * m_capacity)
551  //{
552  // do not do this for now
553  //}
554  else
555  {
556  // the entry contains the appropriate number of live entries
557 
558  ptrCopy->insertEntry(dataLength, pData, mbr, id);
559  if (bInsertMbr2) ptrCopy->insertEntry(0, nullptr, mbr2, id2);
560 
561  if (bIsRoot)
562  {
563  if (m_nodeMBR.m_startTime == m_nodeMBR.m_endTime)
564  {
565  ptrCopy->m_identifier = m_identifier;
566  m_pTree->writeNode(ptrCopy.get());
567  assert(m_pTree->m_roots[m_pTree->m_roots.size() - 1].m_startTime == ptrCopy->m_nodeMBR.m_startTime &&
568  m_pTree->m_roots[m_pTree->m_roots.size() - 1].m_endTime == ptrCopy->m_nodeMBR.m_endTime);
569  }
570  else
571  {
572  m_pTree->writeNode(ptrCopy.get());
573  m_pTree->writeNode(this);
574 
575  assert(m_pTree->m_roots[m_pTree->m_roots.size() - 1].m_id == m_identifier);
576  m_pTree->m_roots[m_pTree->m_roots.size() - 1].m_startTime = m_nodeMBR.m_startTime;
577  m_pTree->m_roots[m_pTree->m_roots.size() - 1].m_endTime = m_nodeMBR.m_endTime;
578  m_pTree->m_roots.emplace_back(ptrCopy->m_identifier, ptrCopy->m_nodeMBR.m_startTime, ptrCopy->m_nodeMBR.m_endTime);
579  m_pTree->m_stats.m_treeHeight.push_back(ptrCopy->m_level + 1);
580 
581  m_pTree->m_stats.m_nodesInLevel.at(ptrCopy->m_level) = m_pTree->m_stats.m_nodesInLevel[ptrCopy->m_level] + 1;
582  if (m_level > 0) ++(m_pTree->m_stats.m_u32DeadIndexNodes);
583  else ++(m_pTree->m_stats.m_u32DeadLeafNodes);
584  }
585 
586  return true;
587  }
588  else
589  {
590  m_pTree->writeNode(ptrCopy.get());
591 
592  m_pTree->m_stats.m_nodesInLevel.at(ptrCopy->m_level) = m_pTree->m_stats.m_nodesInLevel[ptrCopy->m_level] + 1;
593  if (m_level > 0) ++(m_pTree->m_stats.m_u32DeadIndexNodes);
594  else ++(m_pTree->m_stats.m_u32DeadLeafNodes);
595 
596  id_type cParent = pathBuffer.top(); pathBuffer.pop();
597  NodePtr ptrN = m_pTree->readNode(cParent);
598  Index* p = static_cast<Index*>(ptrN.get());
599  ++(m_pTree->m_stats.m_u64Adjustments);
600 
601  uint32_t child;
602  for (child = 0; child < p->m_children; ++child)
603  {
604  if (p->m_pIdentifier[child] == m_identifier) break;
605  }
606 
607  // it might be needed to update the MBR since the child MBR might have changed
608  // from an entry deletion (from insertData, below, when m_startTime == m_endTime)
609  double st = p->m_ptrMBR[child]->m_startTime;
610  *(p->m_ptrMBR[child]) = m_nodeMBR;
611  p->m_ptrMBR[child]->m_startTime = st;
612  //p->m_ptrMBR[child]->m_endTime = mbr.m_startTime;
613 
614  // insert this new version copy into the parent
615  p->insertData(0, nullptr, ptrCopy->m_nodeMBR, ptrCopy->m_identifier, pathBuffer, m_pTree->m_infiniteRegion, -1, false);
616 
617  return false;
618  }
619  }
620  }
621 }
622 
623 void Node::insertData(TimeRegion& mbr1, id_type id1, TimeRegion& mbr2, id_type id2, Node* oldVersion, std::stack<id_type>& pathBuffer)
624 {
625  // this should be called only from insertData above
626  // it tries to fit two new entries into the node
627 
628  uint32_t child;
629  for (child = 0; child < m_children; ++child)
630  {
631  if (m_pIdentifier[child] == oldVersion->m_identifier) break;
632  }
633 
634  // save the original node MBR
635  bool bAdjust = false;
636  TimeRegionPtr ptrR = m_pTree->m_regionPool.acquire();
637  *ptrR = m_nodeMBR;
638 
639  // it might be needed to update the MBR since the child MBR might have changed
640  // from an entry deletion (when m_startTime == m_endTime)
641  double st = m_ptrMBR[child]->m_startTime;
642  *(m_ptrMBR[child]) = oldVersion->m_nodeMBR;
643  m_ptrMBR[child]->m_startTime = st;
644  //m_ptrMBR[child]->m_endTime = oldVersion->m_nodeMBR.m_endTime;
645 
646  if (m_children < m_capacity - 1)
647  {
648  // there is enough space for both new entries
649 
650  insertEntry(0, nullptr, mbr1, id1);
651  insertEntry(0, nullptr, mbr2, id2);
652 
653  m_pTree->writeNode(this);
654 
655  if ((! pathBuffer.empty()) && (bAdjust || ! (ptrR->containsShape(mbr1) && ptrR->containsShape(mbr2))))
656  {
657  id_type cParent = pathBuffer.top(); pathBuffer.pop();
658  NodePtr ptrN = m_pTree->readNode(cParent);
659  Index* p = static_cast<Index*>(ptrN.get());
660  p->adjustTree(this, pathBuffer);
661  }
662  }
663  else
664  {
665  // call a normal insertData which will trigger a version copy
666  // insertData will adjust the parent since this node will certainly do a version copy
667  bool bStored = insertData(0, nullptr, mbr1, id1, pathBuffer, mbr2, id2, true);
668  if (! bStored) m_pTree->writeNode(this);
669  }
670 }
671 
672 bool Node::deleteData(id_type id, double delTime, std::stack<id_type>& pathBuffer, bool bForceAdjust)
673 {
674  // it returns true if a new root has been created because all the entries of the old root have died.
675  // This is needed in case the root dies while there are pending reinsertions from multiple levels
676 
677  uint32_t child = m_capacity;
678  uint32_t alive = 0;
679  bool bAdjustParent = false;
680  TimeRegionPtr oldNodeMBR = m_pTree->m_regionPool.acquire();
681  *oldNodeMBR = m_nodeMBR;
682  NodePtr parent;
683 
684  // make sure that there are no "snapshot" entries
685  // find how many children are alive and locate the entry to be deleted
686  for (uint32_t cChild = 0; cChild < m_children; ++cChild)
687  {
688  assert(m_level != 0 || (m_ptrMBR[cChild]->m_startTime != m_ptrMBR[cChild]->m_endTime));
689  if (! (m_ptrMBR[cChild]->m_endTime < std::numeric_limits<double>::max())) ++alive;
690  if (m_pIdentifier[cChild] == id) child = cChild;
691  }
692 
693  assert(child < m_capacity);
694 
695  // either make the entry dead or, if its start time is equal to the deletion time,
696  // delete it from the node completely (in which case the parent MBR might need adjustment)
697  bool bAdjusted = false;
698 
699  if (m_level == 0 && m_ptrMBR[child]->m_startTime == delTime)
700  {
701  bAdjusted = deleteEntry(child);
702  bAdjustParent = bAdjusted;
703  }
704  else
705  {
706  m_ptrMBR[child]->m_endTime = delTime;
707  }
708 
709  // if it has not been adjusted yet (by deleteEntry) and it should be adjusted, do it.
710  // a forced adjustment is needed when a child node has adjusted its own MBR and signals
711  // the parent to adjust it, also.
712  if ((! bAdjusted) && bForceAdjust)
713  {
714  for (uint32_t cDim = 0; cDim < m_nodeMBR.m_dimension; ++cDim)
715  {
716  m_nodeMBR.m_pLow[cDim] = std::numeric_limits<double>::max();
717  m_nodeMBR.m_pHigh[cDim] = -std::numeric_limits<double>::max();
718 
719  for (uint32_t cChild = 0; cChild < m_children; ++cChild)
720  {
721  m_nodeMBR.m_pLow[cDim] = std::min(m_nodeMBR.m_pLow[cDim], m_ptrMBR[cChild]->m_pLow[cDim]);
722  m_nodeMBR.m_pHigh[cDim] = std::max(m_nodeMBR.m_pHigh[cDim], m_ptrMBR[cChild]->m_pHigh[cDim]);
723  }
724  }
725  // signal our parent to adjust its MBR also
726  bAdjustParent = true;
727  }
728 
729  // one less live entry from now on
730  --alive;
731 
732  if (alive < m_pTree->m_versionUnderflow * m_capacity && (! pathBuffer.empty()))
733  {
734  // if the weak version condition is broken, try to resolve it
735  // if this is a leaf and it can still hold some entries (since all entries might be dead now and
736  // the node full) try to borrow a live entry from a sibling
737  // [Yufei Tao, Dimitris Papadias, 'MV3R-Tree: A Spatio-Temporal Access Method for Timestamp and
738  // Interval Queries', Section 3.3]
739  if (m_level == 0 && m_children < m_capacity)
740  {
741  parent = m_pTree->readNode(pathBuffer.top());
742  pathBuffer.pop();
743 
744  // find us in our parent
745  for (child = 0; child < parent->m_children; ++child)
746  {
747  if (parent->m_pIdentifier[child] == m_identifier) break;
748  }
749 
750  // remember that the parent might be younger than us, pointing to us through a pointer
751  // created with a version copy. So the actual start time of this node through the path
752  // from the root might actually be different than the stored start time.
753  double actualNodeStartTime = parent->m_ptrMBR[child]->m_startTime;
754 
755  // find an appropriate sibling
756  for (uint32_t cSibling = 0; cSibling < parent->m_children; ++cSibling)
757  {
758  // it has to be different than us, it has to be alive and its MBR should intersect ours
759  if (
760  parent->m_pIdentifier[cSibling] != m_identifier &&
761  ! (parent->m_ptrMBR[cSibling]->m_endTime < std::numeric_limits<double>::max()) &&
762  parent->m_ptrMBR[cSibling]->intersectsShape(m_nodeMBR))
763  {
764  NodePtr sibling = m_pTree->readNode(parent->m_pIdentifier[cSibling]);
765  std::vector<DeleteDataEntry> toCheck;
766  alive = 0;
767 
768  // if this child does not have a single parent, we cannot borrow an entry.
769  bool bSingleParent = true;
770 
771  for (uint32_t cSiblingChild = 0; cSiblingChild < sibling->m_children; ++cSiblingChild)
772  {
773  // if the insertion time of any child is smaller than the starting time stored in the
774  // parent of this node than the node has more than one parent
775  if (sibling->m_ptrMBR[cSiblingChild]->m_startTime < parent->m_ptrMBR[cSibling]->m_startTime)
776  {
777  bSingleParent = false;
778  break;
779  }
780 
781  // find the live sibling entries, and also the ones that can be moved to this node
782  // sort them by area enlargement
783  if (! (sibling->m_ptrMBR[cSiblingChild]->m_endTime < std::numeric_limits<double>::max()))
784  {
785  ++alive;
786  if (sibling->m_ptrMBR[cSiblingChild]->m_startTime >= actualNodeStartTime)
787  {
788  TimeRegionPtr tmpR = m_pTree->m_regionPool.acquire();
789  *tmpR = m_nodeMBR;
790  tmpR->combineRegion(*(sibling->m_ptrMBR[cSiblingChild]));
791  double a = tmpR->getArea();
792  if (a <= m_nodeMBR.getArea() * 1.1) toCheck.emplace_back(cSiblingChild, a);
793  }
794  }
795  }
796 
797  // if the sibling has more than one parent or if we cannot remove an entry because we will
798  // cause a weak version overflow, this sibling is not appropriate
799  if ((! bSingleParent) || toCheck.empty() || alive == m_pTree->m_versionUnderflow * sibling->m_capacity + 1) continue;
800 
801  // create interval counters for checking weak version condition
802  // [Yufei Tao, Dimitris Papadias, 'MV3R-Tree: A Spatio-Temporal Access Method for Timestamp and
803  // Interval Queries', Section 3.2]
804  std::set<double> Si;
805  for (uint32_t cSiblingChild = 0; cSiblingChild < sibling->m_children; ++cSiblingChild)
806  {
807  Si.insert(sibling->m_ptrMBR[cSiblingChild]->m_startTime);
808  Si.insert(sibling->m_ptrMBR[cSiblingChild]->m_endTime);
809  }
810  // duplicate entries have been removed and the set is sorted
811  uint32_t* SiCounts = new uint32_t[Si.size() - 1];
812  memset(SiCounts, 0, (Si.size() - 1) * sizeof(uint32_t));
813 
814  for (uint32_t cSiblingChild = 0; cSiblingChild < sibling->m_children; ++cSiblingChild)
815  {
816  std::set<double>::iterator it1 = Si.begin();
817  std::set<double>::iterator it2 = Si.begin();
818  for (size_t cIndex = 0; cIndex < Si.size() - 1; ++cIndex)
819  {
820  ++it2;
821  if (
822  sibling->m_ptrMBR[cSiblingChild]->m_startTime <= *it1 &&
823  sibling->m_ptrMBR[cSiblingChild]->m_endTime >= *it2
824  ) ++(SiCounts[cIndex]);
825  ++it1;
826  }
827  }
828 
829  std::vector<DeleteDataEntry> Sdel;
830 
831  for (size_t cCheck = 0; cCheck < toCheck.size(); ++cCheck)
832  {
833  bool good = true;
834 
835  // check if it can be removed without a weak version underflow
836  std::set<double>::iterator it1 = Si.begin();
837  std::set<double>::iterator it2 = Si.begin();
838  for (size_t cIndex = 0; cIndex < Si.size() - 1; ++cIndex)
839  {
840  ++it2;
841  if (
842  sibling->m_ptrMBR[toCheck[cCheck].m_index]->m_startTime <= *it1 &&
843  sibling->m_ptrMBR[toCheck[cCheck].m_index]->m_endTime >= *it2 &&
844  SiCounts[cIndex] <= m_pTree->m_versionUnderflow * sibling->m_capacity)
845  {
846  good = false;
847  break;
848  }
849  ++it1;
850  }
851  if (good) Sdel.push_back(toCheck[cCheck]);
852  }
853 
854  delete[] SiCounts;
855 
856  if (Sdel.empty()) continue;
857 
858  // we found some entries. Sort them according to least enlargement, insert the best entry into
859  // this node, remove it from the sibling and update the MBRs of the parent
860 
861  sort(Sdel.begin(), Sdel.end(), DeleteDataEntry::compare);
862  uint32_t entry = Sdel[0].m_index;
863  bool b1 = m_nodeMBR.containsShape(*(sibling->m_ptrMBR[entry]));
864  bool b2 = sibling->m_nodeMBR.touchesShape(*(sibling->m_ptrMBR[entry]));
865 
866  insertEntry(sibling->m_pDataLength[entry], sibling->m_pData[entry], *(sibling->m_ptrMBR[entry]), sibling->m_pIdentifier[entry]);
867  sibling->m_pData[entry] = nullptr;
868 
869  // the weak version condition check above, guarantees that.
870  assert(sibling->m_children > 1);
871  sibling->deleteEntry(entry);
872 
873  m_pTree->writeNode(this);
874  m_pTree->writeNode(sibling.get());
875 
876  Index* p = static_cast<Index*>(parent.get());
877  if (((! b1) || bAdjustParent) && b2) p->adjustTree(this, sibling.get(), pathBuffer);
878  else if ((! b1) || bAdjustParent) p->adjustTree(this, pathBuffer);
879  else if (b2) p->adjustTree(sibling.get(), pathBuffer);
880 
881  return false;
882  }
883  }
884  }
885 
886  // either this is not a leaf, or an appropriate sibling was not found, so make this node dead
887  // and reinsert all live entries from the root
888  m_nodeMBR.m_endTime = delTime;
889  m_pTree->writeNode(this);
890  if (m_level > 0) ++(m_pTree->m_stats.m_u32DeadIndexNodes);
891  else ++(m_pTree->m_stats.m_u32DeadLeafNodes);
892 
893  if (parent.get() == nullptr)
894  {
895  parent = m_pTree->readNode(pathBuffer.top());
896  pathBuffer.pop();
897  }
898 
899  if (bAdjustParent)
900  {
901  // the correct child pointer might have been calculated already from earlier
902  if (child < parent->m_children && m_identifier != parent->m_pIdentifier[child])
903  {
904  for (child = 0; child < parent->m_children; ++child)
905  {
906  if (parent->m_pIdentifier[child] == m_identifier) break;
907  }
908  }
909 
910  // both start time and end time should be preserved since deleteData below needs
911  // to know how many entries where alive, including this one
912  double st = parent->m_ptrMBR[child]->m_startTime;
913  double en = parent->m_ptrMBR[child]->m_endTime;
914  *(parent->m_ptrMBR[child]) = m_nodeMBR;
915  parent->m_ptrMBR[child]->m_startTime = st;
916  parent->m_ptrMBR[child]->m_endTime = en;
917  }
918 
919  // delete this node from the parent node.
920  // if this node had been adjusted and its old MBR was touching the parent MBR, the
921  // parent MBR needs to be adjusted also.
922  // the deletion has to happen first, since the reinsertions might modify the path to this node
923  bool bNewRoot = parent->deleteData(m_identifier, delTime, pathBuffer, (bAdjustParent && parent->m_nodeMBR.touchesShape(*oldNodeMBR)));
924 
925  // reinsert all the live entries from the root
926 
927  // normally I should not modify any node instances, since writeNode might be caching nodes
928  // in main memory, even though I have persisted them, so I have to make copies
929 
930  // this code will try and reinsert whole paths if possible. It might be the case, though,
931  // that a root died, which means that all the live data entries have to be scanned and reinserted themselves
932  for (child = 0; child < m_children; ++child)
933  {
934  if (! (m_ptrMBR[child]->m_endTime < std::numeric_limits<double>::max()))
935  {
936  if (! bNewRoot || m_level == 0)
937  {
938  m_ptrMBR[child]->m_startTime = delTime;
939  m_pTree->insertData_impl(m_pDataLength[child], m_pData[child], *(m_ptrMBR[child]), m_pIdentifier[child], m_level);
940  // make sure we do not delete the data array from this node's destructor
941  m_pData[child] = nullptr;
942  }
943  else
944  {
945  std::stack<NodePtr> Sins;
946  Sins.push(m_pTree->readNode(m_pIdentifier[child]));
947  while (! Sins.empty())
948  {
949  NodePtr p = Sins.top(); Sins.pop();
950  if (p->m_level == 0)
951  {
952  for (uint32_t cIndex= 0; cIndex < p->m_children; ++cIndex)
953  {
954  if (! (p->m_ptrMBR[cIndex]->m_endTime < std::numeric_limits<double>::max()))
955  {
956  p->m_ptrMBR[cIndex]->m_startTime = delTime;
957  m_pTree->insertData_impl(p->m_pDataLength[cIndex], p->m_pData[cIndex], *(p->m_ptrMBR[cIndex]), p->m_pIdentifier[cIndex], p->m_level);
958  // make sure we do not delete the data array from this node's destructor
959  p->m_pData[cIndex] = nullptr;
960  }
961  }
962  }
963  else
964  {
965  for (uint32_t cIndex= 0; cIndex < p->m_children; ++cIndex)
966  {
967  if (! (p->m_ptrMBR[cIndex]->m_endTime < std::numeric_limits<double>::max()))
968  {
969  Sins.push(m_pTree->readNode(p->m_pIdentifier[cIndex]));
970  }
971  }
972  }
973  }
974  }
975  }
976  }
977  }
978  else
979  {
980  // either this is a root node or there is no weak version condition
981 
982  if (alive == 0 && pathBuffer.empty())
983  {
984  if (m_children > 0)
985  {
986  // all root children are dead. Create a new root
987  m_nodeMBR.m_endTime = delTime;
988  m_pTree->m_bHasVersionCopied = false;
989 
990  if (m_nodeMBR.m_startTime == m_nodeMBR.m_endTime)
991  {
992  Leaf root(m_pTree, m_identifier);
993  root.m_nodeMBR.m_startTime = m_nodeMBR.m_endTime;
994  root.m_nodeMBR.m_endTime = std::numeric_limits<double>::max();
995  m_pTree->writeNode(&root);
996 
997  m_pTree->m_stats.m_treeHeight[m_pTree->m_stats.m_treeHeight.size() - 1] = 1;
998  if (m_pTree->m_stats.m_nodesInLevel.at(m_level) == 1) m_pTree->m_stats.m_nodesInLevel.pop_back();
999  else m_pTree->m_stats.m_nodesInLevel.at(m_level) = m_pTree->m_stats.m_nodesInLevel[m_level] - 1;
1000  m_pTree->m_stats.m_nodesInLevel.at(0) = m_pTree->m_stats.m_nodesInLevel[0] + 1;
1001  }
1002  else
1003  {
1004  m_pTree->writeNode(this);
1005 
1006  if (m_level > 0) ++(m_pTree->m_stats.m_u32DeadIndexNodes);
1007  else ++(m_pTree->m_stats.m_u32DeadLeafNodes);
1008 
1009  Leaf root(m_pTree, -1);
1010  root.m_nodeMBR.m_startTime = m_nodeMBR.m_endTime;
1011  root.m_nodeMBR.m_endTime = std::numeric_limits<double>::max();
1012  m_pTree->writeNode(&root);
1013  assert(m_pTree->m_roots[m_pTree->m_roots.size() - 1].m_id == m_identifier);
1014  m_pTree->m_roots[m_pTree->m_roots.size() - 1].m_startTime = m_nodeMBR.m_startTime;
1015  m_pTree->m_roots[m_pTree->m_roots.size() - 1].m_endTime = m_nodeMBR.m_endTime;
1016  m_pTree->m_roots.emplace_back(root.m_identifier, root.m_nodeMBR.m_startTime, root.m_nodeMBR.m_endTime);
1017 
1018  m_pTree->m_stats.m_treeHeight.push_back(1);
1019  m_pTree->m_stats.m_nodesInLevel.at(root.m_level) = m_pTree->m_stats.m_nodesInLevel[root.m_level] + 1;
1020  }
1021  return true;
1022  }
1023  else
1024  {
1025  assert(m_level == 0);
1026  m_pTree->writeNode(this);
1027  m_pTree->m_bHasVersionCopied = false;
1028  return false;
1029  }
1030  }
1031  else if (bAdjustParent && (! pathBuffer.empty()))
1032  {
1033  // the parent needs to be adjusted
1034  m_pTree->writeNode(this);
1035  parent = m_pTree->readNode(pathBuffer.top());
1036  pathBuffer.pop();
1037  Index* p = static_cast<Index*>(parent.get());
1038  p->adjustTree(this, pathBuffer);
1039  }
1040  else
1041  {
1042  m_pTree->writeNode(this);
1043  }
1044  }
1045 
1046  return false;
1047 }
1048 
1049 void Node::rtreeSplit(
1050  uint32_t dataLength, uint8_t* pData, TimeRegion& mbr, id_type id, std::vector<uint32_t>& group1, std::vector<uint32_t>& group2,
1051  TimeRegion& mbr2, id_type id2, bool bInsertMbr2)
1052 {
1053  uint32_t cChild;
1054  uint32_t minimumLoad = static_cast<uint32_t>(std::floor(m_capacity * m_pTree->m_fillFactor));
1055 
1056  uint32_t cTotal = (bInsertMbr2) ? m_children + 2 : m_children + 1;
1057 
1058  // use this mask array for marking visited entries.
1059  uint8_t* mask = new uint8_t[cTotal];
1060  memset(mask, 0, cTotal);
1061 
1062  // insert new data in the node for easier manipulation. Data arrays are always
1063  // by two larger than node capacity.
1064  m_pDataLength[m_children] = dataLength;
1065  m_pData[m_children] = pData;
1066  m_ptrMBR[m_children] = m_pTree->m_regionPool.acquire();
1067  *(m_ptrMBR[m_children]) = mbr;
1068  m_pIdentifier[m_children] = id;
1069 
1070  if (bInsertMbr2)
1071  {
1072  m_pDataLength[m_children + 1] = 0;
1073  m_pData[m_children + 1] = nullptr;
1074  m_ptrMBR[m_children + 1] = m_pTree->m_regionPool.acquire();
1075  *(m_ptrMBR[m_children + 1]) = mbr2;
1076  m_pIdentifier[m_children + 1] = id2;
1077  }
1078 
1079  // initialize each group with the seed entries.
1080  uint32_t seed1, seed2;
1081  pickSeeds(seed1, seed2, cTotal);
1082 
1083  group1.push_back(seed1);
1084  group2.push_back(seed2);
1085 
1086  mask[seed1] = 1;
1087  mask[seed2] = 1;
1088 
1089  // find MBR of each group.
1090  TimeRegionPtr mbrA = m_pTree->m_regionPool.acquire();
1091  *mbrA = *(m_ptrMBR[seed1]);
1092  TimeRegionPtr mbrB = m_pTree->m_regionPool.acquire();
1093  *mbrB = *(m_ptrMBR[seed2]);
1094 
1095  // count how many entries are left unchecked (exclude the seeds here.)
1096  uint32_t cRemaining = cTotal - 2;
1097 
1098  while (cRemaining > 0)
1099  {
1100  if (minimumLoad - group1.size() == cRemaining)
1101  {
1102  // all remaining entries must be assigned to group1 to comply with minimun load requirement.
1103  for (cChild = 0; cChild < cTotal; ++cChild)
1104  {
1105  if (mask[cChild] == 0)
1106  {
1107  group1.push_back(cChild);
1108  mask[cChild] = 1;
1109  --cRemaining;
1110  }
1111  }
1112  }
1113  else if (minimumLoad - group2.size() == cRemaining)
1114  {
1115  // all remaining entries must be assigned to group2 to comply with minimun load requirement.
1116  for (cChild = 0; cChild < cTotal; ++cChild)
1117  {
1118  if (mask[cChild] == 0)
1119  {
1120  group2.push_back(cChild);
1121  mask[cChild] = 1;
1122  --cRemaining;
1123  }
1124  }
1125  }
1126  else
1127  {
1128  // For all remaining entries compute the difference of the cost of grouping an
1129  // entry in either group. When done, choose the entry that yielded the maximum
1130  // difference. In case of linear split, select any entry (e.g. the first one.)
1131  uint32_t sel;
1132  double md1 = 0.0, md2 = 0.0;
1133  double m = -std::numeric_limits<double>::max();
1134  double d1, d2, d;
1135  double a1 = mbrA->getArea();
1136  double a2 = mbrB->getArea();
1137 
1138  TimeRegionPtr a = m_pTree->m_regionPool.acquire();
1139  TimeRegionPtr b = m_pTree->m_regionPool.acquire();
1140 
1141  for (cChild = 0; cChild < cTotal; ++cChild)
1142  {
1143  if (mask[cChild] == 0)
1144  {
1145  mbrA->getCombinedRegion(*a, *(m_ptrMBR[cChild]));
1146  d1 = a->getArea() - a1;
1147  mbrB->getCombinedRegion(*b, *(m_ptrMBR[cChild]));
1148  d2 = b->getArea() - a2;
1149  d = std::abs(d1 - d2);
1150 
1151  if (d > m)
1152  {
1153  m = d;
1154  md1 = d1; md2 = d2;
1155  sel = cChild;
1156  if (m_pTree->m_treeVariant== RV_LINEAR || m_pTree->m_treeVariant == RV_RSTAR) break;
1157  }
1158  }
1159  }
1160 
1161  // determine the group where we should add the new entry.
1162  int32_t group = 1;
1163 
1164  if (md1 < md2)
1165  {
1166  group1.push_back(sel);
1167  group = 1;
1168  }
1169  else if (md2 < md1)
1170  {
1171  group2.push_back(sel);
1172  group = 2;
1173  }
1174  else if (a1 < a2)
1175  {
1176  group1.push_back(sel);
1177  group = 1;
1178  }
1179  else if (a2 < a1)
1180  {
1181  group2.push_back(sel);
1182  group = 2;
1183  }
1184  else if (group1.size() < group2.size())
1185  {
1186  group1.push_back(sel);
1187  group = 1;
1188  }
1189  else if (group2.size() < group1.size())
1190  {
1191  group2.push_back(sel);
1192  group = 2;
1193  }
1194  else
1195  {
1196  group1.push_back(sel);
1197  group = 1;
1198  }
1199  mask[sel] = 1;
1200  --cRemaining;
1201  if (group == 1)
1202  {
1203  mbrA->combineRegion(*(m_ptrMBR[sel]));
1204  }
1205  else
1206  {
1207  mbrB->combineRegion(*(m_ptrMBR[sel]));
1208  }
1209  }
1210  }
1211 
1212  delete[] mask;
1213 }
1214 
1215 void Node::rstarSplit(
1216  uint32_t dataLength, uint8_t* pData, TimeRegion& mbr, id_type id, std::vector<uint32_t>& group1, std::vector<uint32_t>& group2,
1217  TimeRegion& mbr2, id_type id2, bool bInsertMbr2)
1218 {
1219  RstarSplitEntry** dataLow = nullptr;
1220  RstarSplitEntry** dataHigh = nullptr;
1221 
1222  uint32_t cTotal = (bInsertMbr2) ? m_children + 2 : m_children + 1;
1223 
1224  try
1225  {
1226  dataLow = new RstarSplitEntry*[cTotal];
1227  dataHigh = new RstarSplitEntry*[cTotal];
1228  }
1229  catch (...)
1230  {
1231  delete[] dataLow;
1232  throw;
1233  }
1234 
1235  m_pDataLength[m_children] = dataLength;
1236  m_pData[m_children] = pData;
1237  m_ptrMBR[m_children] = m_pTree->m_regionPool.acquire();
1238  *(m_ptrMBR[m_children]) = mbr;
1239  m_pIdentifier[m_children] = id;
1240 
1241  if (bInsertMbr2)
1242  {
1243  m_pDataLength[m_children + 1] = 0;
1244  m_pData[m_children + 1] = nullptr;
1245  m_ptrMBR[m_children + 1] = m_pTree->m_regionPool.acquire();
1246  *(m_ptrMBR[m_children + 1]) = mbr2;
1247  m_pIdentifier[m_children + 1] = id2;
1248  }
1249 
1250  uint32_t nodeSPF = static_cast<uint32_t>(std::floor(cTotal * m_pTree->m_splitDistributionFactor));
1251  uint32_t splitDistribution = cTotal - (2 * nodeSPF) + 2;
1252 
1253  uint32_t cChild = 0, cDim, cIndex;
1254 
1255  for (cChild = 0; cChild < cTotal; ++cChild)
1256  {
1257  try
1258  {
1259  dataLow[cChild] = new RstarSplitEntry(m_ptrMBR[cChild].get(), cChild, 0);
1260  }
1261  catch (...)
1262  {
1263  for (uint32_t i = 0; i < cChild; ++i) delete dataLow[i];
1264  delete[] dataLow;
1265  delete[] dataHigh;
1266  throw;
1267  }
1268 
1269  dataHigh[cChild] = dataLow[cChild];
1270  }
1271 
1272  double minimumMargin = std::numeric_limits<double>::max();
1273  uint32_t splitAxis = std::numeric_limits<uint32_t>::max();
1274  uint32_t sortOrder = std::numeric_limits<uint32_t>::max();
1275 
1276  // chooseSplitAxis.
1277  for (cDim = 0; cDim < m_pTree->m_dimension; ++cDim)
1278  {
1279  ::qsort(dataLow,
1280  cTotal,
1281  sizeof(RstarSplitEntry*),
1282  RstarSplitEntry::compareLow);
1283 
1284  ::qsort(dataHigh,
1285  cTotal,
1286  sizeof(RstarSplitEntry*),
1287  RstarSplitEntry::compareHigh);
1288 
1289  // calculate sum of margins and overlap for all distributions.
1290  double marginl = 0.0;
1291  double marginh = 0.0;
1292 
1293  TimeRegion bbl1, bbl2, bbh1, bbh2;
1294 
1295  for (cChild = 1; cChild <= splitDistribution; ++cChild)
1296  {
1297  uint32_t l = nodeSPF - 1 + cChild;
1298 
1299  bbl1 = *(dataLow[0]->m_pRegion);
1300  bbh1 = *(dataHigh[0]->m_pRegion);
1301 
1302  for (cIndex = 1; cIndex < l; ++cIndex)
1303  {
1304  bbl1.combineRegion(*(dataLow[cIndex]->m_pRegion));
1305  bbh1.combineRegion(*(dataHigh[cIndex]->m_pRegion));
1306  }
1307 
1308  bbl2 = *(dataLow[l]->m_pRegion);
1309  bbh2 = *(dataHigh[l]->m_pRegion);
1310 
1311  for (cIndex = l + 1; cIndex < cTotal; ++cIndex)
1312  {
1313  bbl2.combineRegion(*(dataLow[cIndex]->m_pRegion));
1314  bbh2.combineRegion(*(dataHigh[cIndex]->m_pRegion));
1315  }
1316 
1317  marginl += bbl1.getMargin() + bbl2.getMargin();
1318  marginh += bbh1.getMargin() + bbh2.getMargin();
1319  } // for (cChild)
1320 
1321  double margin = std::min(marginl, marginh);
1322 
1323  // keep minimum margin as split axis.
1324  if (margin < minimumMargin)
1325  {
1326  minimumMargin = margin;
1327  splitAxis = cDim;
1328  sortOrder = (marginl < marginh) ? 0 : 1;
1329  }
1330 
1331  // increase the dimension according to which the data entries should be sorted.
1332  for (cChild = 0; cChild < cTotal; ++cChild)
1333  {
1334  dataLow[cChild]->m_sortDim = cDim + 1;
1335  }
1336  } // for (cDim)
1337 
1338  for (cChild = 0; cChild < cTotal; ++cChild)
1339  {
1340  dataLow[cChild]->m_sortDim = splitAxis;
1341  }
1342 
1343  ::qsort(
1344  dataLow,
1345  cTotal,
1346  sizeof(RstarSplitEntry*),
1347  (sortOrder == 0) ? RstarSplitEntry::compareLow : RstarSplitEntry::compareHigh);
1348 
1349  double ma = std::numeric_limits<double>::max();
1350  double mo = std::numeric_limits<double>::max();
1351  uint32_t splitPoint = std::numeric_limits<uint32_t>::max();
1352 
1353  TimeRegion bb1, bb2;
1354 
1355  for (cChild = 1; cChild <= splitDistribution; ++cChild)
1356  {
1357  uint32_t l = nodeSPF - 1 + cChild;
1358 
1359  bb1 = *(dataLow[0]->m_pRegion);
1360 
1361  for (cIndex = 1; cIndex < l; ++cIndex)
1362  {
1363  bb1.combineRegion(*(dataLow[cIndex]->m_pRegion));
1364  }
1365 
1366  bb2 = *(dataLow[l]->m_pRegion);
1367 
1368  for (cIndex = l + 1; cIndex < cTotal; ++cIndex)
1369  {
1370  bb2.combineRegion(*(dataLow[cIndex]->m_pRegion));
1371  }
1372 
1373  double o = bb1.getIntersectingArea(bb2);
1374 
1375  if (o < mo)
1376  {
1377  splitPoint = cChild;
1378  mo = o;
1379  ma = bb1.getArea() + bb2.getArea();
1380  }
1381  else if (o == mo)
1382  {
1383  double a = bb1.getArea() + bb2.getArea();
1384 
1385  if (a < ma)
1386  {
1387  splitPoint = cChild;
1388  ma = a;
1389  }
1390  }
1391  } // for (cChild)
1392 
1393  uint32_t l1 = nodeSPF - 1 + splitPoint;
1394 
1395  for (cIndex = 0; cIndex < l1; ++cIndex)
1396  {
1397  group1.push_back(dataLow[cIndex]->m_index);
1398  delete dataLow[cIndex];
1399  }
1400 
1401  for (cIndex = l1; cIndex < cTotal; ++cIndex)
1402  {
1403  group2.push_back(dataLow[cIndex]->m_index);
1404  delete dataLow[cIndex];
1405  }
1406 
1407  delete[] dataLow;
1408  delete[] dataHigh;
1409 }
1410 
1411 void Node::pickSeeds(uint32_t& index1, uint32_t& index2, uint32_t total)
1412 {
1413  double separation = -std::numeric_limits<double>::max();
1414  double inefficiency = -std::numeric_limits<double>::max();
1415  uint32_t cDim, cChild, cIndex;
1416 
1417  switch (m_pTree->m_treeVariant)
1418  {
1419  case RV_LINEAR:
1420  case RV_RSTAR:
1421  for (cDim = 0; cDim < m_pTree->m_dimension; ++cDim)
1422  {
1423  double leastLower = m_ptrMBR[0]->m_pLow[cDim];
1424  double greatestUpper = m_ptrMBR[0]->m_pHigh[cDim];
1425  uint32_t greatestLower = 0;
1426  uint32_t leastUpper = 0;
1427  double width;
1428 
1429  for (cChild = 1; cChild < total; ++cChild)
1430  {
1431  if (m_ptrMBR[cChild]->m_pLow[cDim] > m_ptrMBR[greatestLower]->m_pLow[cDim]) greatestLower = cChild;
1432  if (m_ptrMBR[cChild]->m_pHigh[cDim] < m_ptrMBR[leastUpper]->m_pHigh[cDim]) leastUpper = cChild;
1433 
1434  leastLower = std::min(m_ptrMBR[cChild]->m_pLow[cDim], leastLower);
1435  greatestUpper = std::max(m_ptrMBR[cChild]->m_pHigh[cDim], greatestUpper);
1436  }
1437 
1438  width = greatestUpper - leastLower;
1439  if (width <= 0) width = 1;
1440 
1441  double f = (m_ptrMBR[greatestLower]->m_pLow[cDim] - m_ptrMBR[leastUpper]->m_pHigh[cDim]) / width;
1442 
1443  if (f > separation)
1444  {
1445  index1 = leastUpper;
1446  index2 = greatestLower;
1447  separation = f;
1448  }
1449  } // for (cDim)
1450 
1451  if (index1 == index2)
1452  {
1453  if (index2 == 0) ++index2;
1454  else --index2;
1455  }
1456 
1457  break;
1458  case RV_QUADRATIC:
1459  // for each pair of Regions (account for overflow Region too!)
1460  for (cChild = 0; cChild < total - 1; ++cChild)
1461  {
1462  double a = m_ptrMBR[cChild]->getArea();
1463 
1464  for (cIndex = cChild + 1; cIndex < total; ++cIndex)
1465  {
1466  // get the combined MBR of those two entries.
1467  TimeRegion r;
1468  m_ptrMBR[cChild]->getCombinedRegion(r, *(m_ptrMBR[cIndex]));
1469 
1470  // find the inefficiency of grouping these entries together.
1471  double d = r.getArea() - a - m_ptrMBR[cIndex]->getArea();
1472 
1473  if (d > inefficiency)
1474  {
1475  inefficiency = d;
1476  index1 = cChild;
1477  index2 = cIndex;
1478  }
1479  } // for (cIndex)
1480  } // for (cChild)
1481 
1482  break;
1483  default:
1484  throw Tools::NotSupportedException("Node::pickSeeds: Tree variant not supported.");
1485  }
1486 }
1487 
1488 NodePtr Node::findNode(const TimeRegion& mbr, id_type id, std::stack<id_type>& pathBuffer)
1489 {
1490  pathBuffer.push(m_identifier);
1491 
1492  for (uint32_t cChild = 0; cChild < m_children; ++cChild)
1493  {
1494  if (m_pIdentifier[cChild] == id)
1495  return m_pTree->readNode(m_pIdentifier[cChild]);
1496 
1497  if (m_ptrMBR[cChild]->containsShape(mbr))
1498  {
1499  NodePtr n = m_pTree->readNode(m_pIdentifier[cChild]);
1500  NodePtr l = n->findNode(mbr, id, pathBuffer);
1501  assert(n.get() != l.get());
1502  if (l.get() != nullptr) return l;
1503  }
1504  }
1505 
1506  pathBuffer.pop();
1507 
1508  return NodePtr();
1509 }
void getChildShape(uint32_t index, IShape **out) const override
IObject * clone() override
Definition: mvrtree/Node.cc:45
void makeInfinite(uint32_t dimension) override
Definition: TimeRegion.cc:376
PoolPointer< X > acquire()
Definition: PointerPool.h:64
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
bool isIndex() const override
bool touchesShape(const IShape &in) const override
Definition: Region.cc:207
bool containsShape(const IShape &in) const override
Definition: Region.cc:194
Tools::PoolPointer< Node > NodePtr
Definition: mvrtree/Node.h:40
bool isLeaf() const override
virtual void combineRegionInTime(const TimeRegion &in)
Definition: TimeRegion.cc:181
virtual void combineRegion(const Region &in)
Definition: Region.cc:496
uint32_t m_dimension
Definition: Region.h:97
void getShape(IShape **out) const override
double * m_pHigh
Definition: Region.h:99
X * get() const noexcept
Definition: PoolPointer.h:55
double getArea() const override
Definition: Region.cc:239
void getChildData(uint32_t index, uint32_t &length, uint8_t **data) const override
bool intersectsShape(const IShape &in) const override
Definition: Region.cc:178
virtual double getMargin() const
Definition: Region.cc:483
uint32_t getLevel() const override
id_type getIdentifier() const override
int64_t id_type
Definition: SpatialIndex.h:41
SpatialIndex::ISpatialIndex & index()
id_type getChildIdentifier(uint32_t index) const override
void storeToByteArray(uint8_t **data, uint32_t &len) override
uint32_t getByteArraySize() override
Definition: mvrtree/Node.cc:53
uint32_t getChildrenCount() const override
void loadFromByteArray(const uint8_t *data) override
Definition: mvrtree/Node.cc:66