aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'sci-libs/libspatialindex/svn/trunk/src/rtree/.svn/text-base/Node.cc.svn-base')
-rw-r--r--sci-libs/libspatialindex/svn/trunk/src/rtree/.svn/text-base/Node.cc.svn-base1074
1 files changed, 1074 insertions, 0 deletions
diff --git a/sci-libs/libspatialindex/svn/trunk/src/rtree/.svn/text-base/Node.cc.svn-base b/sci-libs/libspatialindex/svn/trunk/src/rtree/.svn/text-base/Node.cc.svn-base
new file mode 100644
index 000000000..09ecfe943
--- /dev/null
+++ b/sci-libs/libspatialindex/svn/trunk/src/rtree/.svn/text-base/Node.cc.svn-base
@@ -0,0 +1,1074 @@
+// Spatial Index Library
+//
+// Copyright (C) 2002 Navel Ltd.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// Email:
+// mhadji@gmail.com
+
+#include <cstring>
+#include <cmath>
+#include <limits>
+
+#include "../spatialindex/SpatialIndexImpl.h"
+#include "RTree.h"
+#include "Node.h"
+#include "Index.h"
+
+using namespace SpatialIndex::RTree;
+
+//
+// Tools::IObject interface
+//
+Tools::IObject* Node::clone()
+{
+ throw Tools::NotSupportedException("IObject::clone should never be called.");
+}
+
+//
+// Tools::ISerializable interface
+//
+uint32_t Node::getByteArraySize()
+{
+ return
+ (sizeof(uint32_t) +
+ sizeof(uint32_t) +
+ sizeof(uint32_t) +
+ (m_children * (m_pTree->m_dimension * sizeof(double) * 2 + sizeof(id_type) + sizeof(uint32_t))) +
+ m_totalDataLength +
+ (2 * m_pTree->m_dimension * sizeof(double)));
+}
+
+void Node::loadFromByteArray(const byte* ptr)
+{
+ m_nodeMBR = m_pTree->m_infiniteRegion;
+
+ // skip the node type information, it is not needed.
+ ptr += sizeof(uint32_t);
+
+ memcpy(&m_level, ptr, sizeof(uint32_t));
+ ptr += sizeof(uint32_t);
+
+ memcpy(&m_children, ptr, sizeof(uint32_t));
+ ptr += sizeof(uint32_t);
+
+ for (uint32_t u32Child = 0; u32Child < m_children; ++u32Child)
+ {
+ m_ptrMBR[u32Child] = m_pTree->m_regionPool.acquire();
+ *(m_ptrMBR[u32Child]) = m_pTree->m_infiniteRegion;
+
+ memcpy(m_ptrMBR[u32Child]->m_pLow, ptr, m_pTree->m_dimension * sizeof(double));
+ ptr += m_pTree->m_dimension * sizeof(double);
+ memcpy(m_ptrMBR[u32Child]->m_pHigh, ptr, m_pTree->m_dimension * sizeof(double));
+ ptr += m_pTree->m_dimension * sizeof(double);
+ memcpy(&(m_pIdentifier[u32Child]), ptr, sizeof(id_type));
+ ptr += sizeof(id_type);
+
+ memcpy(&(m_pDataLength[u32Child]), ptr, sizeof(uint32_t));
+ ptr += sizeof(uint32_t);
+
+ if (m_pDataLength[u32Child] > 0)
+ {
+ m_totalDataLength += m_pDataLength[u32Child];
+ m_pData[u32Child] = new byte[m_pDataLength[u32Child]];
+ memcpy(m_pData[u32Child], ptr, m_pDataLength[u32Child]);
+ ptr += m_pDataLength[u32Child];
+ }
+ else
+ {
+ m_pData[u32Child] = 0;
+ }
+
+ //m_nodeMBR.combineRegion(*(m_ptrMBR[u32Child]));
+ }
+
+ memcpy(m_nodeMBR.m_pLow, ptr, m_pTree->m_dimension * sizeof(double));
+ ptr += m_pTree->m_dimension * sizeof(double);
+ memcpy(m_nodeMBR.m_pHigh, ptr, m_pTree->m_dimension * sizeof(double));
+ //ptr += m_pTree->m_dimension * sizeof(double);
+}
+
+void Node::storeToByteArray(byte** data, uint32_t& len)
+{
+ len = getByteArraySize();
+
+ *data = new byte[len];
+ byte* ptr = *data;
+
+ uint32_t nodeType;
+
+ if (m_level == 0) nodeType = PersistentLeaf;
+ else nodeType = PersistentIndex;
+
+ memcpy(ptr, &nodeType, sizeof(uint32_t));
+ ptr += sizeof(uint32_t);
+
+ memcpy(ptr, &m_level, sizeof(uint32_t));
+ ptr += sizeof(uint32_t);
+
+ memcpy(ptr, &m_children, sizeof(uint32_t));
+ ptr += sizeof(uint32_t);
+
+ for (uint32_t u32Child = 0; u32Child < m_children; ++u32Child)
+ {
+ memcpy(ptr, m_ptrMBR[u32Child]->m_pLow, m_pTree->m_dimension * sizeof(double));
+ ptr += m_pTree->m_dimension * sizeof(double);
+ memcpy(ptr, m_ptrMBR[u32Child]->m_pHigh, m_pTree->m_dimension * sizeof(double));
+ ptr += m_pTree->m_dimension * sizeof(double);
+ memcpy(ptr, &(m_pIdentifier[u32Child]), sizeof(id_type));
+ ptr += sizeof(id_type);
+
+ memcpy(ptr, &(m_pDataLength[u32Child]), sizeof(uint32_t));
+ ptr += sizeof(uint32_t);
+
+ if (m_pDataLength[u32Child] > 0)
+ {
+ memcpy(ptr, m_pData[u32Child], m_pDataLength[u32Child]);
+ ptr += m_pDataLength[u32Child];
+ }
+ }
+
+ // store the node MBR for efficiency. This increases the node size a little bit.
+ memcpy(ptr, m_nodeMBR.m_pLow, m_pTree->m_dimension * sizeof(double));
+ ptr += m_pTree->m_dimension * sizeof(double);
+ memcpy(ptr, m_nodeMBR.m_pHigh, m_pTree->m_dimension * sizeof(double));
+ //ptr += m_pTree->m_dimension * sizeof(double);
+
+ assert(len == (ptr - *data) + m_pTree->m_dimension * sizeof(double));
+}
+
+//
+// SpatialIndex::IEntry interface
+//
+SpatialIndex::id_type Node::getIdentifier() const
+{
+ return m_identifier;
+}
+
+void Node::getShape(IShape** out) const
+{
+ *out = new Region(m_nodeMBR);
+}
+
+//
+// SpatialIndex::INode interface
+//
+uint32_t Node::getChildrenCount() const
+{
+ return m_children;
+}
+
+SpatialIndex::id_type Node::getChildIdentifier(uint32_t index) const
+{
+ if (index < 0 || index >= m_children) throw Tools::IndexOutOfBoundsException(index);
+
+ return m_pIdentifier[index];
+}
+
+void Node::getChildShape(uint32_t index, IShape** out) const
+{
+ if (index < 0 || index >= m_children) throw Tools::IndexOutOfBoundsException(index);
+
+ *out = new Region(*(m_ptrMBR[index]));
+}
+
+void Node::getChildData(uint32_t index, uint32_t& length, byte** data) const
+{
+ if (index < 0 || index >= m_children) throw Tools::IndexOutOfBoundsException(index);
+ if (m_pData[index] == NULL)
+ {
+ length = 0;
+ data = NULL;
+ }
+ else
+ {
+ length = m_pDataLength[index];
+ *data = m_pData[index];
+ }
+}
+
+uint32_t Node::getLevel() const
+{
+ return m_level;
+}
+
+bool Node::isLeaf() const
+{
+ return (m_level == 0);
+}
+
+bool Node::isIndex() const
+{
+ return (m_level != 0);
+}
+
+//
+// Internal
+//
+
+Node::Node() :
+ m_pTree(0),
+ m_level(0),
+ m_identifier(-1),
+ m_children(0),
+ m_capacity(0),
+ m_pData(0),
+ m_ptrMBR(0),
+ m_pIdentifier(0),
+ m_pDataLength(0),
+ m_totalDataLength(0)
+{
+}
+
+Node::Node(SpatialIndex::RTree::RTree* pTree, id_type id, uint32_t level, uint32_t capacity) :
+ m_pTree(pTree),
+ m_level(level),
+ m_identifier(id),
+ m_children(0),
+ m_capacity(capacity),
+ m_pData(0),
+ m_ptrMBR(0),
+ m_pIdentifier(0),
+ m_pDataLength(0),
+ m_totalDataLength(0)
+{
+ m_nodeMBR.makeInfinite(m_pTree->m_dimension);
+
+ try
+ {
+ m_pDataLength = new uint32_t[m_capacity + 1];
+ m_pData = new byte*[m_capacity + 1];
+ m_ptrMBR = new RegionPtr[m_capacity + 1];
+ m_pIdentifier = new id_type[m_capacity + 1];
+ }
+ catch (...)
+ {
+ delete[] m_pDataLength;
+ delete[] m_pData;
+ delete[] m_ptrMBR;
+ delete[] m_pIdentifier;
+ throw;
+ }
+}
+
+Node::~Node()
+{
+ if (m_pData != 0)
+ {
+ for (uint32_t u32Child = 0; u32Child < m_children; ++u32Child)
+ {
+ if (m_pData[u32Child] != 0) delete[] m_pData[u32Child];
+ }
+
+ delete[] m_pData;
+ }
+
+ delete[] m_pDataLength;
+ delete[] m_ptrMBR;
+ delete[] m_pIdentifier;
+}
+
+Node& Node::operator=(const Node& n)
+{
+ throw Tools::IllegalStateException("operator =: This should never be called.");
+}
+
+void Node::insertEntry(uint32_t dataLength, byte* pData, Region& mbr, id_type id)
+{
+ assert(m_children < m_capacity);
+
+ m_pDataLength[m_children] = dataLength;
+ m_pData[m_children] = pData;
+ m_ptrMBR[m_children] = m_pTree->m_regionPool.acquire();
+ *(m_ptrMBR[m_children]) = mbr;
+ m_pIdentifier[m_children] = id;
+
+ m_totalDataLength += dataLength;
+ ++m_children;
+
+ m_nodeMBR.combineRegion(mbr);
+}
+
+void Node::deleteEntry(uint32_t index)
+{
+ assert(index >= 0 && index < m_children);
+
+ // cache it, since I might need it for "touches" later.
+ RegionPtr ptrR = m_ptrMBR[index];
+
+ m_totalDataLength -= m_pDataLength[index];
+ if (m_pData[index] != 0) delete[] m_pData[index];
+
+ if (m_children > 1 && index != m_children - 1)
+ {
+ m_pDataLength[index] = m_pDataLength[m_children - 1];
+ m_pData[index] = m_pData[m_children - 1];
+ m_ptrMBR[index] = m_ptrMBR[m_children - 1];
+ m_pIdentifier[index] = m_pIdentifier[m_children - 1];
+ }
+
+ --m_children;
+
+ // WARNING: index has now changed. Do not use it below here.
+
+ if (m_children == 0)
+ {
+ m_nodeMBR = m_pTree->m_infiniteRegion;
+ }
+ else if (m_pTree->m_bTightMBRs && m_nodeMBR.touchesRegion(*ptrR))
+ {
+ for (uint32_t cDim = 0; cDim < m_nodeMBR.m_dimension; ++cDim)
+ {
+ m_nodeMBR.m_pLow[cDim] = std::numeric_limits<double>::max();
+ m_nodeMBR.m_pHigh[cDim] = -std::numeric_limits<double>::max();
+
+ for (uint32_t u32Child = 0; u32Child < m_children; ++u32Child)
+ {
+ m_nodeMBR.m_pLow[cDim] = std::min(m_nodeMBR.m_pLow[cDim], m_ptrMBR[u32Child]->m_pLow[cDim]);
+ m_nodeMBR.m_pHigh[cDim] = std::max(m_nodeMBR.m_pHigh[cDim], m_ptrMBR[u32Child]->m_pHigh[cDim]);
+ }
+ }
+ }
+}
+
+bool Node::insertData(uint32_t dataLength, byte* pData, Region& mbr, id_type id, std::stack<id_type>& pathBuffer, byte* overflowTable)
+{
+ if (m_children < m_capacity)
+ {
+ bool adjusted = false;
+
+ // this has to happen before insertEntry modifies m_nodeMBR.
+ bool b = m_nodeMBR.containsRegion(mbr);
+
+ insertEntry(dataLength, pData, mbr, id);
+ m_pTree->writeNode(this);
+
+ if ((! b) && (! pathBuffer.empty()))
+ {
+ id_type cParent = pathBuffer.top(); pathBuffer.pop();
+ NodePtr ptrN = m_pTree->readNode(cParent);
+ Index* p = static_cast<Index*>(ptrN.get());
+ p->adjustTree(this, pathBuffer);
+ adjusted = true;
+ }
+
+ return adjusted;
+ }
+ else if (m_pTree->m_treeVariant == RV_RSTAR && (! pathBuffer.empty()) && overflowTable[m_level] == 0)
+ {
+ overflowTable[m_level] = 1;
+
+ std::vector<uint32_t> vReinsert, vKeep;
+ reinsertData(dataLength, pData, mbr, id, vReinsert, vKeep);
+
+ uint32_t lReinsert = static_cast<uint32_t>(vReinsert.size());
+ uint32_t lKeep = static_cast<uint32_t>(vKeep.size());
+
+ byte** reinsertdata = 0;
+ RegionPtr* reinsertmbr = 0;
+ id_type* reinsertid = 0;
+ uint32_t* reinsertlen = 0;
+ byte** keepdata = 0;
+ RegionPtr* keepmbr = 0;
+ id_type* keepid = 0;
+ uint32_t* keeplen = 0;
+
+ try
+ {
+ reinsertdata = new byte*[lReinsert];
+ reinsertmbr = new RegionPtr[lReinsert];
+ reinsertid = new id_type[lReinsert];
+ reinsertlen = new uint32_t[lReinsert];
+
+ keepdata = new byte*[m_capacity + 1];
+ keepmbr = new RegionPtr[m_capacity + 1];
+ keepid = new id_type[m_capacity + 1];
+ keeplen = new uint32_t[m_capacity + 1];
+ }
+ catch (...)
+ {
+ delete[] reinsertdata;
+ delete[] reinsertmbr;
+ delete[] reinsertid;
+ delete[] reinsertlen;
+ delete[] keepdata;
+ delete[] keepmbr;
+ delete[] keepid;
+ delete[] keeplen;
+ throw;
+ }
+
+ uint32_t cIndex;
+
+ for (cIndex = 0; cIndex < lReinsert; ++cIndex)
+ {
+ reinsertlen[cIndex] = m_pDataLength[vReinsert[cIndex]];
+ reinsertdata[cIndex] = m_pData[vReinsert[cIndex]];
+ reinsertmbr[cIndex] = m_ptrMBR[vReinsert[cIndex]];
+ reinsertid[cIndex] = m_pIdentifier[vReinsert[cIndex]];
+ }
+
+ for (cIndex = 0; cIndex < lKeep; ++cIndex)
+ {
+ keeplen[cIndex] = m_pDataLength[vKeep[cIndex]];
+ keepdata[cIndex] = m_pData[vKeep[cIndex]];
+ keepmbr[cIndex] = m_ptrMBR[vKeep[cIndex]];
+ keepid[cIndex] = m_pIdentifier[vKeep[cIndex]];
+ }
+
+ delete[] m_pDataLength;
+ delete[] m_pData;
+ delete[] m_ptrMBR;
+ delete[] m_pIdentifier;
+
+ m_pDataLength = keeplen;
+ m_pData = keepdata;
+ m_ptrMBR = keepmbr;
+ m_pIdentifier = keepid;
+ m_children = lKeep;
+ m_totalDataLength = 0;
+
+ for (uint32_t u32Child = 0; u32Child < m_children; ++u32Child) m_totalDataLength += m_pDataLength[u32Child];
+
+ for (uint32_t cDim = 0; cDim < m_nodeMBR.m_dimension; ++cDim)
+ {
+ m_nodeMBR.m_pLow[cDim] = std::numeric_limits<double>::max();
+ m_nodeMBR.m_pHigh[cDim] = -std::numeric_limits<double>::max();
+
+ for (uint32_t u32Child = 0; u32Child < m_children; ++u32Child)
+ {
+ m_nodeMBR.m_pLow[cDim] = std::min(m_nodeMBR.m_pLow[cDim], m_ptrMBR[u32Child]->m_pLow[cDim]);
+ m_nodeMBR.m_pHigh[cDim] = std::max(m_nodeMBR.m_pHigh[cDim], m_ptrMBR[u32Child]->m_pHigh[cDim]);
+ }
+ }
+
+ m_pTree->writeNode(this);
+
+ // Divertion from R*-Tree algorithm here. First adjust
+ // the path to the root, then start reinserts, to avoid complicated handling
+ // of changes to the same node from multiple insertions.
+ id_type cParent = pathBuffer.top(); pathBuffer.pop();
+ NodePtr ptrN = m_pTree->readNode(cParent);
+ Index* p = static_cast<Index*>(ptrN.get());
+ p->adjustTree(this, pathBuffer);
+
+ for (cIndex = 0; cIndex < lReinsert; ++cIndex)
+ {
+ m_pTree->insertData_impl(
+ reinsertlen[cIndex], reinsertdata[cIndex],
+ *(reinsertmbr[cIndex]), reinsertid[cIndex],
+ m_level, overflowTable);
+ }
+
+ delete[] reinsertdata;
+ delete[] reinsertmbr;
+ delete[] reinsertid;
+ delete[] reinsertlen;
+
+ return true;
+ }
+ else
+ {
+ NodePtr n;
+ NodePtr nn;
+ split(dataLength, pData, mbr, id, n, nn);
+
+ if (pathBuffer.empty())
+ {
+ n->m_level = m_level;
+ nn->m_level = m_level;
+ n->m_identifier = -1;
+ nn->m_identifier = -1;
+ m_pTree->writeNode(n.get());
+ m_pTree->writeNode(nn.get());
+
+ NodePtr ptrR = m_pTree->m_indexPool.acquire();
+ if (ptrR.get() == 0)
+ {
+ ptrR = NodePtr(new Index(m_pTree, m_pTree->m_rootID, m_level + 1), &(m_pTree->m_indexPool));
+ }
+ else
+ {
+ //ptrR->m_pTree = m_pTree;
+ ptrR->m_identifier = m_pTree->m_rootID;
+ ptrR->m_level = m_level + 1;
+ ptrR->m_nodeMBR = m_pTree->m_infiniteRegion;
+ }
+
+ ptrR->insertEntry(0, 0, n->m_nodeMBR, n->m_identifier);
+ ptrR->insertEntry(0, 0, nn->m_nodeMBR, nn->m_identifier);
+
+ m_pTree->writeNode(ptrR.get());
+
+ m_pTree->m_stats.m_nodesInLevel[m_level] = 2;
+ m_pTree->m_stats.m_nodesInLevel.push_back(1);
+ m_pTree->m_stats.m_u32TreeHeight = m_level + 2;
+ }
+ else
+ {
+ n->m_level = m_level;
+ nn->m_level = m_level;
+ n->m_identifier = m_identifier;
+ nn->m_identifier = -1;
+
+ m_pTree->writeNode(n.get());
+ m_pTree->writeNode(nn.get());
+
+ id_type cParent = pathBuffer.top(); pathBuffer.pop();
+ NodePtr ptrN = m_pTree->readNode(cParent);
+ Index* p = static_cast<Index*>(ptrN.get());
+ p->adjustTree(n.get(), nn.get(), pathBuffer, overflowTable);
+ }
+
+ return true;
+ }
+}
+
+void Node::reinsertData(uint32_t dataLength, byte* pData, Region& mbr, id_type id, std::vector<uint32_t>& reinsert, std::vector<uint32_t>& keep)
+{
+ ReinsertEntry** v = new ReinsertEntry*[m_capacity + 1];
+
+ m_pDataLength[m_children] = dataLength;
+ m_pData[m_children] = pData;
+ m_ptrMBR[m_children] = m_pTree->m_regionPool.acquire();
+ *(m_ptrMBR[m_children]) = mbr;
+ m_pIdentifier[m_children] = id;
+
+ PointPtr nc = m_pTree->m_pointPool.acquire();
+ m_nodeMBR.getCenter(*nc);
+ PointPtr c = m_pTree->m_pointPool.acquire();
+
+ for (uint32_t u32Child = 0; u32Child < m_capacity + 1; ++u32Child)
+ {
+ try
+ {
+ v[u32Child] = new ReinsertEntry(u32Child, 0.0);
+ }
+ catch (...)
+ {
+ for (uint32_t i = 0; i < u32Child; ++i) delete v[i];
+ delete[] v;
+ throw;
+ }
+
+ m_ptrMBR[u32Child]->getCenter(*c);
+
+ // calculate relative distance of every entry from the node MBR (ignore square root.)
+ for (uint32_t cDim = 0; cDim < m_nodeMBR.m_dimension; ++cDim)
+ {
+ double d = nc->m_pCoords[cDim] - c->m_pCoords[cDim];
+ v[u32Child]->m_dist += d * d;
+ }
+ }
+
+ // sort by increasing order of distances.
+ ::qsort(v, m_capacity + 1, sizeof(ReinsertEntry*), ReinsertEntry::compareReinsertEntry);
+
+ uint32_t cReinsert = static_cast<uint32_t>(std::floor((m_capacity + 1) * m_pTree->m_reinsertFactor));
+
+ uint32_t cCount;
+
+ for (cCount = 0; cCount < cReinsert; ++cCount)
+ {
+ reinsert.push_back(v[cCount]->m_index);
+ delete v[cCount];
+ }
+
+ for (cCount = cReinsert; cCount < m_capacity + 1; ++cCount)
+ {
+ keep.push_back(v[cCount]->m_index);
+ delete v[cCount];
+ }
+
+ delete[] v;
+}
+
+void Node::rtreeSplit(uint32_t dataLength, byte* pData, Region& mbr, id_type id, std::vector<uint32_t>& group1, std::vector<uint32_t>& group2)
+{
+ uint32_t u32Child;
+ uint32_t minimumLoad = static_cast<uint32_t>(std::floor(m_capacity * m_pTree->m_fillFactor));
+
+ // use this mask array for marking visited entries.
+ byte* mask = new byte[m_capacity + 1];
+ bzero(mask, m_capacity + 1);
+
+ // insert new data in the node for easier manipulation. Data arrays are always
+ // by one larger than node capacity.
+ m_pDataLength[m_capacity] = dataLength;
+ m_pData[m_capacity] = pData;
+ m_ptrMBR[m_capacity] = m_pTree->m_regionPool.acquire();
+ *(m_ptrMBR[m_capacity]) = mbr;
+ m_pIdentifier[m_capacity] = id;
+ // m_totalDataLength does not need to be increased here.
+
+ // initialize each group with the seed entries.
+ uint32_t seed1, seed2;
+ pickSeeds(seed1, seed2);
+
+ group1.push_back(seed1);
+ group2.push_back(seed2);
+
+ mask[seed1] = 1;
+ mask[seed2] = 1;
+
+ // find MBR of each group.
+ RegionPtr mbr1 = m_pTree->m_regionPool.acquire();
+ *mbr1 = *(m_ptrMBR[seed1]);
+ RegionPtr mbr2 = m_pTree->m_regionPool.acquire();
+ *mbr2 = *(m_ptrMBR[seed2]);
+
+ // count how many entries are left unchecked (exclude the seeds here.)
+ uint32_t cRemaining = m_capacity + 1 - 2;
+
+ while (cRemaining > 0)
+ {
+ if (minimumLoad - group1.size() == cRemaining)
+ {
+ // all remaining entries must be assigned to group1 to comply with minimun load requirement.
+ for (u32Child = 0; u32Child < m_capacity + 1; ++u32Child)
+ {
+ if (mask[u32Child] == 0)
+ {
+ group1.push_back(u32Child);
+ mask[u32Child] = 1;
+ --cRemaining;
+ }
+ }
+ }
+ else if (minimumLoad - group2.size() == cRemaining)
+ {
+ // all remaining entries must be assigned to group2 to comply with minimun load requirement.
+ for (u32Child = 0; u32Child < m_capacity + 1; ++u32Child)
+ {
+ if (mask[u32Child] == 0)
+ {
+ group2.push_back(u32Child);
+ mask[u32Child] = 1;
+ --cRemaining;
+ }
+ }
+ }
+ else
+ {
+ // For all remaining entries compute the difference of the cost of grouping an
+ // entry in either group. When done, choose the entry that yielded the maximum
+ // difference. In case of linear split, select any entry (e.g. the first one.)
+ uint32_t sel;
+ double md1 = 0.0, md2 = 0.0;
+ double m = -std::numeric_limits<double>::max();
+ double d1, d2, d;
+ double a1 = mbr1->getArea();
+ double a2 = mbr2->getArea();
+
+ RegionPtr a = m_pTree->m_regionPool.acquire();
+ RegionPtr b = m_pTree->m_regionPool.acquire();
+
+ for (u32Child = 0; u32Child < m_capacity + 1; ++u32Child)
+ {
+ if (mask[u32Child] == 0)
+ {
+ mbr1->getCombinedRegion(*a, *(m_ptrMBR[u32Child]));
+ d1 = a->getArea() - a1;
+ mbr2->getCombinedRegion(*b, *(m_ptrMBR[u32Child]));
+ d2 = b->getArea() - a2;
+ d = std::abs(d1 - d2);
+
+ if (d > m)
+ {
+ m = d;
+ md1 = d1; md2 = d2;
+ sel = u32Child;
+ if (m_pTree->m_treeVariant== RV_LINEAR || m_pTree->m_treeVariant == RV_RSTAR) break;
+ }
+ }
+ }
+
+ // determine the group where we should add the new entry.
+ int32_t group = -1;
+
+ if (md1 < md2)
+ {
+ group1.push_back(sel);
+ group = 1;
+ }
+ else if (md2 < md1)
+ {
+ group2.push_back(sel);
+ group = 2;
+ }
+ else if (a1 < a2)
+ {
+ group1.push_back(sel);
+ group = 1;
+ }
+ else if (a2 < a1)
+ {
+ group2.push_back(sel);
+ group = 2;
+ }
+ else if (group1.size() < group2.size())
+ {
+ group1.push_back(sel);
+ group = 1;
+ }
+ else if (group2.size() < group1.size())
+ {
+ group2.push_back(sel);
+ group = 2;
+ }
+ else
+ {
+ group1.push_back(sel);
+ group = 1;
+ }
+ mask[sel] = 1;
+ --cRemaining;
+ if (group == 1)
+ {
+ mbr1->combineRegion(*(m_ptrMBR[sel]));
+ }
+ else
+ {
+ mbr2->combineRegion(*(m_ptrMBR[sel]));
+ }
+ }
+ }
+
+ delete[] mask;
+}
+
+void Node::rstarSplit(uint32_t dataLength, byte* pData, Region& mbr, id_type id, std::vector<uint32_t>& group1, std::vector<uint32_t>& group2)
+{
+ RstarSplitEntry** dataLow = 0;
+ RstarSplitEntry** dataHigh = 0;
+
+ try
+ {
+ dataLow = new RstarSplitEntry*[m_capacity + 1];
+ dataHigh = new RstarSplitEntry*[m_capacity + 1];
+ }
+ catch (...)
+ {
+ delete[] dataLow;
+ throw;
+ }
+
+ m_pDataLength[m_capacity] = dataLength;
+ m_pData[m_capacity] = pData;
+ m_ptrMBR[m_capacity] = m_pTree->m_regionPool.acquire();
+ *(m_ptrMBR[m_capacity]) = mbr;
+ m_pIdentifier[m_capacity] = id;
+ // m_totalDataLength does not need to be increased here.
+
+ uint32_t nodeSPF = static_cast<uint32_t>(
+ std::floor((m_capacity + 1) * m_pTree->m_splitDistributionFactor));
+ uint32_t splitDistribution = (m_capacity + 1) - (2 * nodeSPF) + 2;
+
+ uint32_t u32Child = 0, cDim, cIndex;
+
+ for (u32Child = 0; u32Child <= m_capacity; ++u32Child)
+ {
+ try
+ {
+ dataLow[u32Child] = new RstarSplitEntry(m_ptrMBR[u32Child].get(), u32Child, 0);
+ }
+ catch (...)
+ {
+ for (uint32_t i = 0; i < u32Child; ++i) delete dataLow[i];
+ delete[] dataLow;
+ delete[] dataHigh;
+ throw;
+ }
+
+ dataHigh[u32Child] = dataLow[u32Child];
+ }
+
+ double minimumMargin = std::numeric_limits<double>::max();
+ uint32_t splitAxis = std::numeric_limits<uint32_t>::max();
+ uint32_t sortOrder = std::numeric_limits<uint32_t>::max();
+
+ // chooseSplitAxis.
+ for (cDim = 0; cDim < m_pTree->m_dimension; ++cDim)
+ {
+ ::qsort(dataLow, m_capacity + 1, sizeof(RstarSplitEntry*), RstarSplitEntry::compareLow);
+ ::qsort(dataHigh, m_capacity + 1, sizeof(RstarSplitEntry*), RstarSplitEntry::compareHigh);
+
+ // calculate sum of margins and overlap for all distributions.
+ double marginl = 0.0;
+ double marginh = 0.0;
+
+ Region bbl1, bbl2, bbh1, bbh2;
+
+ for (u32Child = 1; u32Child <= splitDistribution; ++u32Child)
+ {
+ uint32_t l = nodeSPF - 1 + u32Child;
+
+ bbl1 = *(dataLow[0]->m_pRegion);
+ bbh1 = *(dataHigh[0]->m_pRegion);
+
+ for (cIndex = 1; cIndex < l; ++cIndex)
+ {
+ bbl1.combineRegion(*(dataLow[cIndex]->m_pRegion));
+ bbh1.combineRegion(*(dataHigh[cIndex]->m_pRegion));
+ }
+
+ bbl2 = *(dataLow[l]->m_pRegion);
+ bbh2 = *(dataHigh[l]->m_pRegion);
+
+ for (cIndex = l + 1; cIndex <= m_capacity; ++cIndex)
+ {
+ bbl2.combineRegion(*(dataLow[cIndex]->m_pRegion));
+ bbh2.combineRegion(*(dataHigh[cIndex]->m_pRegion));
+ }
+
+ marginl += bbl1.getMargin() + bbl2.getMargin();
+ marginh += bbh1.getMargin() + bbh2.getMargin();
+ } // for (u32Child)
+
+ double margin = std::min(marginl, marginh);
+
+ // keep minimum margin as split axis.
+ if (margin < minimumMargin)
+ {
+ minimumMargin = margin;
+ splitAxis = cDim;
+ sortOrder = (marginl < marginh) ? 0 : 1;
+ }
+
+ // increase the dimension according to which the data entries should be sorted.
+ for (u32Child = 0; u32Child <= m_capacity; ++u32Child)
+ {
+ dataLow[u32Child]->m_sortDim = cDim + 1;
+ }
+ } // for (cDim)
+
+ for (u32Child = 0; u32Child <= m_capacity; ++u32Child)
+ {
+ dataLow[u32Child]->m_sortDim = splitAxis;
+ }
+
+ ::qsort(dataLow, m_capacity + 1, sizeof(RstarSplitEntry*), (sortOrder == 0) ? RstarSplitEntry::compareLow : RstarSplitEntry::compareHigh);
+
+ double ma = std::numeric_limits<double>::max();
+ double mo = std::numeric_limits<double>::max();
+ uint32_t splitPoint = std::numeric_limits<uint32_t>::max();
+
+ Region bb1, bb2;
+
+ for (u32Child = 1; u32Child <= splitDistribution; ++u32Child)
+ {
+ uint32_t l = nodeSPF - 1 + u32Child;
+
+ bb1 = *(dataLow[0]->m_pRegion);
+
+ for (cIndex = 1; cIndex < l; ++cIndex)
+ {
+ bb1.combineRegion(*(dataLow[cIndex]->m_pRegion));
+ }
+
+ bb2 = *(dataLow[l]->m_pRegion);
+
+ for (cIndex = l + 1; cIndex <= m_capacity; ++cIndex)
+ {
+ bb2.combineRegion(*(dataLow[cIndex]->m_pRegion));
+ }
+
+ double o = bb1.getIntersectingArea(bb2);
+
+ if (o < mo)
+ {
+ splitPoint = u32Child;
+ mo = o;
+ ma = bb1.getArea() + bb2.getArea();
+ }
+ else if (o == mo)
+ {
+ double a = bb1.getArea() + bb2.getArea();
+
+ if (a < ma)
+ {
+ splitPoint = u32Child;
+ ma = a;
+ }
+ }
+ } // for (u32Child)
+
+ uint32_t l1 = nodeSPF - 1 + splitPoint;
+
+ for (cIndex = 0; cIndex < l1; ++cIndex)
+ {
+ group1.push_back(dataLow[cIndex]->m_index);
+ delete dataLow[cIndex];
+ }
+
+ for (cIndex = l1; cIndex <= m_capacity; ++cIndex)
+ {
+ group2.push_back(dataLow[cIndex]->m_index);
+ delete dataLow[cIndex];
+ }
+
+ delete[] dataLow;
+ delete[] dataHigh;
+}
+
+void Node::pickSeeds(uint32_t& index1, uint32_t& index2)
+{
+ double separation = -std::numeric_limits<double>::max();
+ double inefficiency = -std::numeric_limits<double>::max();
+ uint32_t cDim, u32Child, cIndex;
+
+ switch (m_pTree->m_treeVariant)
+ {
+ case RV_LINEAR:
+ case RV_RSTAR:
+ for (cDim = 0; cDim < m_pTree->m_dimension; ++cDim)
+ {
+ double leastLower = m_ptrMBR[0]->m_pLow[cDim];
+ double greatestUpper = m_ptrMBR[0]->m_pHigh[cDim];
+ uint32_t greatestLower = 0;
+ uint32_t leastUpper = 0;
+ double width;
+
+ for (u32Child = 1; u32Child <= m_capacity; ++u32Child)
+ {
+ if (m_ptrMBR[u32Child]->m_pLow[cDim] > m_ptrMBR[greatestLower]->m_pLow[cDim]) greatestLower = u32Child;
+ if (m_ptrMBR[u32Child]->m_pHigh[cDim] < m_ptrMBR[leastUpper]->m_pHigh[cDim]) leastUpper = u32Child;
+
+ leastLower = std::min(m_ptrMBR[u32Child]->m_pLow[cDim], leastLower);
+ greatestUpper = std::max(m_ptrMBR[u32Child]->m_pHigh[cDim], greatestUpper);
+ }
+
+ width = greatestUpper - leastLower;
+ if (width <= 0) width = 1;
+
+ double f = (m_ptrMBR[greatestLower]->m_pLow[cDim] - m_ptrMBR[leastUpper]->m_pHigh[cDim]) / width;
+
+ if (f > separation)
+ {
+ index1 = leastUpper;
+ index2 = greatestLower;
+ separation = f;
+ }
+ } // for (cDim)
+
+ if (index1 == index2)
+ {
+ if (index2 == 0) ++index2;
+ else --index2;
+ }
+
+ break;
+ case RV_QUADRATIC:
+ // for each pair of Regions (account for overflow Region too!)
+ for (u32Child = 0; u32Child < m_capacity; ++u32Child)
+ {
+ double a = m_ptrMBR[u32Child]->getArea();
+
+ for (cIndex = u32Child + 1; cIndex <= m_capacity; ++cIndex)
+ {
+ // get the combined MBR of those two entries.
+ Region r;
+ m_ptrMBR[u32Child]->getCombinedRegion(r, *(m_ptrMBR[cIndex]));
+
+ // find the inefficiency of grouping these entries together.
+ double d = r.getArea() - a - m_ptrMBR[cIndex]->getArea();
+
+ if (d > inefficiency)
+ {
+ inefficiency = d;
+ index1 = u32Child;
+ index2 = cIndex;
+ }
+ } // for (cIndex)
+ } // for (u32Child)
+
+ break;
+ default:
+ throw Tools::NotSupportedException("Node::pickSeeds: Tree variant not supported.");
+ }
+}
+
+void Node::condenseTree(std::stack<NodePtr>& toReinsert, std::stack<id_type>& pathBuffer, NodePtr& ptrThis)
+{
+ uint32_t minimumLoad = static_cast<uint32_t>(std::floor(m_capacity * m_pTree->m_fillFactor));
+
+ if (pathBuffer.empty())
+ {
+ // eliminate root if it has only one child.
+ if (m_level != 0 && m_children == 1)
+ {
+ NodePtr ptrN = m_pTree->readNode(m_pIdentifier[0]);
+ m_pTree->deleteNode(ptrN.get());
+ ptrN->m_identifier = m_pTree->m_rootID;
+ m_pTree->writeNode(ptrN.get());
+
+ m_pTree->m_stats.m_nodesInLevel.pop_back();
+ m_pTree->m_stats.m_u32TreeHeight -= 1;
+ // HACK: pending deleteNode for deleted child will decrease nodesInLevel, later on.
+ m_pTree->m_stats.m_nodesInLevel[m_pTree->m_stats.m_u32TreeHeight - 1] = 2;
+ }
+ }
+ else
+ {
+ id_type cParent = pathBuffer.top(); pathBuffer.pop();
+ NodePtr ptrParent = m_pTree->readNode(cParent);
+ Index* p = static_cast<Index*>(ptrParent.get());
+
+ // find the entry in the parent, that points to this node.
+ uint32_t child;
+
+ for (child = 0; child != p->m_children; ++child)
+ {
+ if (p->m_pIdentifier[child] == m_identifier) break;
+ }
+
+ if (m_children < minimumLoad)
+ {
+ // used space less than the minimum
+ // 1. eliminate node entry from the parent. deleteEntry will fix the parent's MBR.
+ p->deleteEntry(child);
+ // 2. add this node to the stack in order to reinsert its entries.
+ toReinsert.push(ptrThis);
+ }
+ else
+ {
+ // adjust the entry in 'p' to contain the new bounding region of this node.
+ *(p->m_ptrMBR[child]) = m_nodeMBR;
+
+ // global recalculation necessary since the MBR can only shrink in size,
+ // due to data removal.
+ if (m_pTree->m_bTightMBRs)
+ {
+ for (uint32_t cDim = 0; cDim < p->m_nodeMBR.m_dimension; ++cDim)
+ {
+ p->m_nodeMBR.m_pLow[cDim] = std::numeric_limits<double>::max();
+ p->m_nodeMBR.m_pHigh[cDim] = -std::numeric_limits<double>::max();
+
+ for (uint32_t u32Child = 0; u32Child < p->m_children; ++u32Child)
+ {
+ p->m_nodeMBR.m_pLow[cDim] = std::min(p->m_nodeMBR.m_pLow[cDim], p->m_ptrMBR[u32Child]->m_pLow[cDim]);
+ p->m_nodeMBR.m_pHigh[cDim] = std::max(p->m_nodeMBR.m_pHigh[cDim], p->m_ptrMBR[u32Child]->m_pHigh[cDim]);
+ }
+ }
+ }
+ }
+
+ // write parent node back to storage.
+ m_pTree->writeNode(p);
+
+ p->condenseTree(toReinsert, pathBuffer, ptrParent);
+ }
+}