/* This file is part of SECONDO. Copyright (C) 2004, University in Hagen, Department of Computer Science, Database Systems for New Applications. SECONDO is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. SECONDO 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 General Public License for more details. You should have received a copy of the GNU General Public License along with SECONDO; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //paragraph [1] Title: [{\Large \bf \begin{center}] [\end{center}}] //paragraph [10] Footnote: [{\footnote{] [}}] //[->] [$\rightarrow$] //[TOC] [ ableofcontents] //[_] [\_] RTree-Class Implementation */ #include #include #include #include #include #include #include #include #include #include #include #include "Algebra.h" #include "SecondoSystem.h" #include "SecondoCatalog.h" #include "NestedList.h" #include "NList.h" #include "QueryProcessor.h" #include "AlgebraManager.h" #include "StandardTypes.h" #include "Algebras/Relation-C++/RelationAlgebra.h" #include "DateTime.h" #include "Algebras/TupleIdentifier/TupleIdentifier.h" #include "Progress.h" #include "Algebras/FText/FTextAlgebra.h" #include "ListUtils.h" #include "NList.h" #include "Algebras/Standard-C++/LongInt.h" #include "Algebras/Rectangle/RectangleAlgebra.h" #include "RTree.h" #include "Cache/NoCache.h" #include "Cache/LruCache.h" #include "Cache/CacheBase.h" #include // ofstream #include #include "BPTree/BPTree.h" #include "WinUnix.h" #include #include #include #include using namespace std; using fialgebra::cache::LruCache; using fialgebra::cache::CacheBase; using fialgebra::cache::NoCache; //Implementation of R-Tree for portable Index namespace fialgebra{ template RTree::RTree(RTreeHeader* header, CacheBase* cache){ m_treeHeader = header; m_treeCache = cache; } template RTree* RTree::Create(const char* fileName, size_t cacheSize, size_t minEntries){ size_t pageSize = WinUnix::getPageSize(), maxEntries = RTreeNode::GetMax(pageSize); if (maxEntries == 0){ throw out_of_range("RTree::Create(const char*, size_t, size_t): " "Systems pageSize too small for a entry"); } else{ size_t fixedMinEntries = minEntries; if (fixedMinEntries == 0){ fixedMinEntries = max(maxEntries / 2, 1); } else{ fixedMinEntries = min(fixedMinEntries, max(maxEntries / 2, 1)); } ofstream stream(fileName, ofstream::binary | ofstream::app); if (stream.good()) { if (stream.tellp() == 0) { RTreeHeader* header = new RTreeHeader(pageSize, SizeOfRectangle(), dim, fixedMinEntries, 0, 0); stream.write(header->GetBytes(), header->GetPageSize()); stream.flush(); stream.close(); CacheBase* cache = new LruCache(const_cast(fileName), header->GetPageSize(), cacheSize); return new RTree(header, cache); } else { stream.close(); throw runtime_error("File allready existed!"); } } else { stream.close(); throw runtime_error("File couldn't be created!"); } } } template RTree* RTree::Open(const char * fileName, size_t cacheSize){ ifstream stream(fileName, ifstream::binary | ifstream::ate); if (!stream.good()) { stream.close(); throw runtime_error( "File couldn't be opened: " + string(fileName) ); } else { //cout << "\n Position " << stream.tellg() << "\n"; //cout << "\n PageSize " << WinUnix::getPageSize() << "\n"; size_t pageSize = WinUnix::getPageSize(), length = min(pageSize, stream.tellg()); stream.seekg(0, ios::beg); char* bytes = new char[length]; stream.read(bytes, length); stream.close(); RTreeHeader* header = new RTreeHeader(bytes, length, pageSize); if (header->GetMarker() != TreeHeaderMarker::Rtree){ delete(header); throw runtime_error("File isn't a valid R-Tree!"); } if (header->GetDimension() != dim){ delete(header); throw runtime_error("File contains a R-Tree " "with a different dimension!"); } CacheBase* cache = NULL; if (cacheSize == 0){ cache = new NoCache(fileName, header->GetPageSize(), 0); } else{ cache = new LruCache(fileName, header->GetPageSize(), cacheSize); } return new RTree(header, cache); } } /* This function is exclusively used by the * rebuildfrtree operator. The main purpose is * to check whether the first file that has been * passed to the operator actually contains a valid * RTree */ template RTree* RTree::OpenRebuild(const char * fileName, size_t cacheSize){ ifstream stream(fileName, ifstream::binary | ifstream::ate); if (!stream.good()) { stream.close(); throw runtime_error( "File couldn't be opened: " + string(fileName) ); } else { //cout << "\n Position " << stream.tellg() << "\n"; //cout << "\n PageSize " << WinUnix::getPageSize() << "\n"; size_t pageSize = WinUnix::getPageSize(), length = min(pageSize, stream.tellg()); stream.seekg(0, ios::beg); char* bytes = new char[length]; stream.read(bytes, length); stream.close(); RTreeHeader* header = new RTreeHeader(bytes, length, pageSize); if (header->GetMarker() != TreeHeaderMarker::Rtree){ delete(header); throw runtime_error("File isn't a valid R-Tree!"); } CacheBase* cache = NULL; if (cacheSize == 0){ cache = new NoCache(fileName, header->GetPageSize(), 0); } else{ cache = new LruCache(fileName, header->GetPageSize(), cacheSize); } return new RTree(header, cache); } } template void RTree::Insert( const Rectangle& box, size_t id ) { RTreeNode* node = NULL; // This variable saves the path (ids) from root to target leaf vector path; // 1. start with the root node // First we need to check if there is already a root node available // in case there is no existing root let´s create it and put the // ID into the root. Then we´re already done. if ( m_treeHeader->GetRoot() == 0 ) { // generate root node = CreateRTReeNode( true ); // write page number of root node into header m_treeHeader->SetRoot( node->GetNodeID() ); } else { // 2. There is already an existing root. // 2.1. We're requesting it. node = ReadNode( m_treeHeader->GetRoot() ); while ( !node->IsLeaf() ) { // 3.1. In order to find the target leaf we can use // the function "BestSonSearch" size_t nextID = BestSonIDSearch(*node, box); size_t numberOfEntries = node->GetNumberOfEntries(); for ( size_t i = 0; i < numberOfEntries; i++ ) { if ( node->GetIDAt( i ) == nextID ) { node->SetValueAt( i, node->GetValueAt( i ).Union( box ) ); break; } // if } // for path.push_back( node->GetNodeID() ); WriteNode( *node ); delete node; node = ReadNode(nextID); } // while } // else node->AddEntry( box, id ); while( node->GetNumberOfEntries() > node->GetMax() ) { RTreeNode* parent = NULL; if ( path.size() > 0 ) { parent = ReadNode( path.back() ); path.pop_back(); } // if SplitNode( node, parent ); if ( parent != NULL ) { WriteNode( *node ); delete node; node = parent; } else { break; } // else } // while WriteNode( *node ); delete node; node = 0; } // end of Insert template bool RTree::Delete(const Rectangle& box, size_t id){ stack> path; RTreeNode* node = NULL; size_t index = 0; if (m_treeHeader->GetRoot() != 0){ path.push(pair(m_treeHeader->GetRoot(), 0)); } //Find node and index while (node == NULL && !path.empty()){ RTreeNode* currentNode = ReadNode(path.top().first); size_t currentIndex = path.top().second; path.pop(); bool found = false; if (!currentNode->IsLeaf()){ while (!found && currentIndex < currentNode->GetNumberOfEntries()){ if (currentNode->GetValueAt(currentIndex).Contains(box)){ path.push(pair(currentNode->GetNodeID(), currentIndex)); path.push(pair(currentNode->GetIDAt(currentIndex), 0)); found = true; } else{ currentIndex++; } } delete(currentNode); currentNode = NULL; } else{ while (!found && currentIndex < currentNode->GetNumberOfEntries()){ if (currentNode->GetValueAt(currentIndex) == box && currentNode->GetIDAt(currentIndex) == id){ node = currentNode; index = currentIndex; found = true; } else{ currentIndex++; } } if (node == NULL){ delete(currentNode); currentNode = NULL; } } if(!found && !path.empty()){ path.top() = pair(path.top().first, path.top().second + 1); } } //Remove entry if found if (node != NULL){ node->RemoveEntryAt(index); //Not root and underflow? while (!path.empty() && node->GetNumberOfEntries() < m_treeHeader->GetMinEntries()){ //Remove node from parent RTreeNode* parent = ReadNode(path.top().first); parent->RemoveEntryAt(path.top().second); path.pop(); //Redistribute all entries for (size_t i = node->GetNumberOfEntries(); i > 0; i--){ const Rectangle& value = node->GetValueAt(i - 1); size_t id = node->GetIDAt(i - 1); RTreeNode* bestSon = BestSonSearch(*parent, value); bestSon->AddEntry(value, id); //Find best son's index and update value in parent for (size_t j = 0; j < parent->GetNumberOfEntries(); j++){ if (parent->GetIDAt(j) == bestSon->GetNodeID()){ parent->SetValueAt(j, bestSon->GetBox()); break; } } if (bestSon->GetNumberOfEntries() > bestSon->GetMax()){ SplitNode( bestSon, parent ); } WriteNode(*bestSon); delete(bestSon); bestSon = NULL; node->RemoveEntryAtEnd(); } RecycleNode(*node); WriteNode(*node); delete(node); node = parent; } //Overflow? if (node->GetNumberOfEntries() > node->GetMax()){ do{ RTreeNode* parent = path.empty() ? NULL : ReadNode(path.top().first); path.pop(); SplitNode( node, parent ); WriteNode(*node); delete(node); node = parent; } while (node->GetNumberOfEntries() > node->GetMax()); } //Root? else if (path.empty()){ //Only one child? if (!node->IsLeaf() && node->GetNumberOfEntries() == 1){ m_treeHeader->SetRoot(node->GetIDAt(0)); RecycleNode(*node); } //Were empty else if (node->GetNumberOfEntries() == 0){ m_treeHeader->SetRoot(0); RecycleNode(*node); } } WriteNode(*node); delete(node); node = NULL; return true; } else{ return false; } } template RTreeNode* RTree::ReadNode( size_t id ) { char* bytes = (char*)m_treeCache->Read( id, m_treeHeader->GetPageSize() ); return new RTreeNode( bytes, m_treeHeader->GetPageSize(), id ); } template void RTree::WriteNode( RTreeNode& myNode, size_t page ) { char* bytes = myNode.GetBytes(); m_treeCache->Write( page, (size_t)bytes, m_treeHeader->GetPageSize() ); } template void RTree::RecycleNode(RTreeNode& node) { node.ClearEntries(); node.AddEntry(Rectangle(false), m_treeHeader->GetEmptyPage()); m_treeHeader->SetEmptyPage(node.GetNodeID()); } //destructor saves changes that have been done within the tree //using delete(m_treeCache) template RTree::~RTree(){ m_treeCache->Write(0, (size_t)m_treeHeader->GetBytes(), RTreeHeader::GetHeaderSize()); delete(m_treeCache); m_treeCache = NULL; delete(m_treeHeader); m_treeHeader = NULL; } template void RTree::WriteNode(RTreeNode& node) { m_treeCache->Write(node.GetNodeID(), (size_t)node.GetBytes(), m_treeHeader->GetPageSize()); } template RTreeHeader* RTree::GetHeader(){ return m_treeHeader; } template RTreeNode* RTree::BestSonSearch( const RTreeNode& actualNode, const Rectangle& rect ) { RTreeNode* bestSon = ReadNode( actualNode.GetIDAt( 0 ) ); Rectangle box = actualNode.GetValueAt( 0 ); double bestArea = box.Area( NULL ); double bestIncrease = box.Union( rect ).Area( NULL ) - bestArea; for ( size_t i = 1; i < actualNode.GetNumberOfEntries(); i++ ) { box = actualNode.GetValueAt( i ); double area = box.Area( NULL ); double increase = box.Union( rect ).Area( NULL ) - area; if ( increase <= bestIncrease ) { RTreeNode* son = NULL; if ( increase < bestIncrease ) { son = ReadNode( actualNode.GetIDAt( i ) ); } else if ( area <= bestArea ) { son = ReadNode( actualNode.GetIDAt( i ) ); if ( area == bestArea && son->GetNumberOfEntries() >= bestSon->GetNumberOfEntries() ) { delete son; son = NULL; continue; } // if } else { continue; } // else delete bestSon; bestSon = son; bestArea = area; bestIncrease = increase; } // if } // for return bestSon; } template size_t RTree::BestSonIDSearch( const RTreeNode& actualNode, const Rectangle& rect ) { size_t sonNumber = 0; Rectangle sonBox = actualNode.GetValueAt(sonNumber); Rectangle tempBox = sonBox; double bestArea = sonBox.Area(); double area = bestArea; double bestIncrease = sonBox.Union(rect).Area() - bestArea; double increase = bestIncrease; int numberOfEntries = actualNode.GetNumberOfEntries(); for(int i = 1; i < numberOfEntries; i++){ tempBox = actualNode.GetValueAt(i); area = tempBox.Area(); bestArea = sonBox.Area(); increase = tempBox.Union(rect).Area() - area; if (increase < bestIncrease){ bestIncrease = increase; sonNumber = i; sonBox = tempBox; }//end of if (increase < bestIncrease) else{ if (increase == bestIncrease){ if (area < bestArea){ sonNumber = i; sonBox = tempBox; }// end of if (r.Area() < sonBox.Area()) else{ if(area == bestArea){ RTreeNode* tempNode = ReadNode(actualNode.GetIDAt(i)); RTreeNode* tempBestSon = ReadNode(sonNumber); if (tempBestSon->GetNumberOfEntries() > tempNode->GetNumberOfEntries()){ sonNumber = i; sonBox = tempBox; }// end of if (son->GetNumberOfEntries() > ... delete (tempNode); delete (tempBestSon); }// end of if(r.Area() == sonBox.Area()) } }// end of if (increase == bestIncrease) } }// end of for return actualNode.GetIDAt(sonNumber); } template void RTree::SplitNode( RTreeNode*& node, RTreeNode* parent ) { size_t numberOfEntries = node->GetNumberOfEntries(), seed1 = 0, seed2 = numberOfEntries - 1; double bestUnionArea = 0; for( size_t i = 0; i < numberOfEntries; i++ ) { const Rectangle& value1 = node->GetValueAt( i ); for( size_t j = i + 1; j < numberOfEntries; j++ ) { double unionArea = value1.Union( node->GetValueAt( j ) ).Area(); if ( unionArea > bestUnionArea ) { seed1 = i; seed2 = j; bestUnionArea = unionArea; } // if } // for } // for // I. now we need to generate two new nodes and assign rectangle and id RTreeNode* node1 = new RTreeNode( *node ); node1->ClearEntries(); node1->AddEntry( node->GetValueAt( seed1 ), node->GetIDAt( seed1 ) ); RTreeNode* node2 = CreateRTReeNode( node->IsLeaf() ); node2->AddEntry( node->GetValueAt( seed2 ), node->GetIDAt( seed2 ) ); // Remove seed1 and seed2 from the current node node->RemoveEntryAt( seed1 ); node->RemoveEntryAt( seed2 > seed1 ? seed2 - 1 : seed2 ); numberOfEntries -= 2; size_t minEntries = m_treeHeader->GetMinEntries(); // in this step all remaining entries of the passed node // get distributed to the son nodes while ( numberOfEntries > 0 ) { if ( numberOfEntries + node1->GetNumberOfEntries() == minEntries ) { while ( numberOfEntries > 0 ) { node1->AddEntry( node->GetValueAt( numberOfEntries - 1 ), node->GetIDAt( numberOfEntries - 1 ) ); node->RemoveEntryAtEnd(); numberOfEntries--; } // while } else if ( numberOfEntries + node2->GetNumberOfEntries() == minEntries ){ while ( numberOfEntries > 0 ) { node2->AddEntry( node->GetValueAt( numberOfEntries - 1 ), node->GetIDAt( numberOfEntries - 1 ) ); node->RemoveEntryAtEnd(); numberOfEntries--; } // while } else { // identifies where the next entry of the father node // needs to be inserted // initialize the bounding boxes of the two sons Rectangle box1 = node1->GetBox(), box2 = node2->GetBox(); double a1 = box1.Area(); double a2 = box2.Area(); // identify pair with largest delta (between bounding boxes) // calculates the amount the bounding box should be extended RTreeNode* target = NULL; unsigned int index=0; double d = 0.0; for ( size_t i = 0; i < numberOfEntries; i++ ) { const Rectangle& value = node->GetValueAt( i ); double d1 = value.Union(box1).Area() - a1, d2 = value.Union(box2).Area() - a2, d3 = abs(d1 - d2); if(target == NULL || d3 > d){ d = d3; index = i; if(d1 < d2){ target = node1; } else if(d2 < d1){ target = node2; } else if(a1 < a2){ target = node1; } else if(a2 < a1){ target = node2; } else if(node1->GetNumberOfEntries() < node2->GetNumberOfEntries()){ target = node1; } else if(node2->GetNumberOfEntries() < node1->GetNumberOfEntries()){ target = node2; } else{ // all criterions failed target = node1; } } } // for target->AddEntry( node->GetValueAt( index ), node->GetIDAt( index ) ); node->RemoveEntryAt( index ); numberOfEntries--; } // else } // while // Were splitting the root node if ( parent == NULL ) { RTreeNode* root = CreateRTReeNode( false ); root->AddEntry( node1->GetBox(), node1->GetNodeID() ); root->AddEntry( node2->GetBox(), node2->GetNodeID() ); m_treeHeader->SetRoot( root->GetNodeID() ); WriteNode( *root, root->GetNodeID() ); delete root; } else { for ( size_t i = 0; i < parent->GetNumberOfEntries(); i++ ) { if ( parent->GetIDAt( i ) == node1->GetNodeID() ) { parent->SetValueAt( i, node1->GetBox() ); } // if } // for parent->AddEntry( node2->GetBox(), node2->GetNodeID() ); } // else WriteNode( *node2 ); delete node2; node2 = NULL; delete node; node = node1; } // delivers the used cache template CacheBase* RTree::GetCache() { return m_treeCache; } template void RTree::RebuildR(const char* filename) { RTreeHeader* header1 = this->GetHeader(); // Remove target file if it exists fstream file2(filename); remove(filename); // Create target tree RTree* rt2 = Create(filename, 512, header1->GetMinEntries()); RTreeHeader* header2 = rt2->GetHeader(); // Copy header data header2->SetPageSize(header1->GetPageSize()); // Root node will be written to page 1 header2->SetRoot(1); // Pointer to list of empty pages is null pointer header2->SetEmptyPage(0); // First, copy root node to target file RTreeNode* yy1 = this->ReadNode(GetHeader()->GetRoot()); yy1->SetNodeID(1); size_t page = (rt2->GetCache())->NewPage(); RTreeNode yy11 = *yy1; rt2->WriteNode(yy11, page); delete yy1; // Second, copy the other nodes to target file unsigned int numbNodesToRead = 1; size_t pageReadNext = 1; unsigned int counter1 = 0; size_t yy3 = 0, yy4 = 0; bool endRebuild; RTreeNode* yy2; yy2 = rt2->ReadNode( pageReadNext ); endRebuild = yy2->IsLeaf(); delete yy2; while( !endRebuild ) { // for each node already written to target file fetch children // from source file and write them to target file; if leaf level // reached, end since no children exist. for (unsigned int i = 0; i < numbNodesToRead; i++) { // fetch next node which is already written to target file yy2 = rt2->ReadNode(pageReadNext); // yy3 = yy2->GetValueCount() + 1; Steffen fragen yy3 = yy2->GetNumberOfEntries(); yy4 = yy2->GetNodeID(); endRebuild = yy2->IsLeaf(); if(!endRebuild){ // fetch node's child nodes from source file for (unsigned int k = 0; k < yy3; k++) { yy1 = this->ReadNode(yy2->GetIDAt(k)); page = (rt2->GetCache())->NewPage(); // if child node is leaf, set PrevLeaf and NextLeaf // set child node's new page number yy1->SetNodeID(page); // set child node's new parent number yy1->SetParentNodeID(yy4); // write child node to target file rt2->WriteNode(*yy1, page); // Set child node's ID to new page number in node's // IDs array. yy2->SetIDAt(k, page); delete yy1; counter1++; } // for (unsigned int k = 0; k < yy3; k++) // write changed node back to target file rt2->WriteNode(*yy2); delete yy2; pageReadNext++; } else{ delete yy2; } } // for (unsigned int i = 0; i < numbNodesToRead; i++) // End of copying leaves numbNodesToRead = counter1; counter1 = 0; } // while delete rt2; } template RTreeNode* RTree:: GetChildNodeByIndex(RTreeNode* node, size_t index){ size_t i = 0; while (i< this -> AllNodesWithinRTree.size()) { // if (this -> AllNodesWithinRTree(i).nodeID == myNodeID) // { break; // return this -> AllNodesWithinRTree(i); // } i++; } return 0; } template size_t RTree::GetChildNodeID(RTreeNode *parent, RTreeNode *child){ size_t childNodeID = child->GetNodeID(); int i = 0; int mylength = parent->GetNumberOfEntries(); while (i < mylength) { if (parent->GetIDAt(i) == childNodeID){ return parent->GetIDAt(i); } } return 0; } template RTreeNode* RTree:: GetNodeByID(const Rectangle& box, const unsigned long id){ RTree rtr = *this; int mylength = rtr.AllNodesWithinRTree.size(); int i = 0; while (i < mylength){ RTreeNode rtn = rtr.AllNodesWithinRTree.at(i); if (id == rtn.GetNodeID()) { break; RTreeNode* result = &rtn; return result; } i++; } return 0; } template RTreeNode* RTree::GetParentNode(RTreeNode* node){ // unsigned long* pid = node -> parentNodeID; size_t pid = node->GetParentNodeID(); RTreeNode* myParentNode = this -> ReadNode(pid); return myParentNode; } template void RTree::RemoveNode(RTreeNode *toDelete){ delete toDelete; } template void RTree::InsertNode(RTreeNode* parent, RTreeNode* child){ int son_position = parent -> GetNumberOfEntries(); parent -> SetIDAt(son_position, child->GetNodeID()); } template void RTree::RemoveNodeFromRAM (RTreeNode* node){ } template RTreeNode* RTree::CreateRTReeNode(bool isLeaf){ size_t id = m_treeHeader->GetEmptyPage(); if (id != 0){ RTreeNode* node = ReadNode(m_treeHeader->GetEmptyPage()); m_treeHeader->SetEmptyPage(node->GetIDAt(0)); delete(node); } else{ id = m_treeCache->NewPage(); } return new RTreeNode(m_treeHeader->GetPageSize(), id, isLeaf); } template void RTree::ReinsertNodes(RTreeNode *node){ // node is a leaf and gets inserted if(node->IsLeaf()){ Insert(node->GetBox(), node->GetNodeID()); } /* node is not a leaf -> iterate through all * its children calling ReinsertNodes for each * of them */ else{ for(size_t i = 0; iGetNumberOfEntries(); i++){ ReinsertNodes(GetChildNodeByIndex(node,i)); } } RemoveNode(node); } template void RTree::CondenseTree(RTreeNode *parent){ //current node RTreeNode *x = parent; //saves all nodes to be inserted std::vector*> n; //if x is root we´re done, otherwise: while(x != root){ //Parent node of x RTreeNode *px = GetParentNode(x); /* x has not enough entries, hence remove x * from px and save this in n */ if(x->GetNumberOfEntries() < m_treeHeader->GetMinEntries()){ int index = GetChildNodeID(px,x); px->RemoveEntryAt(index); n.push_back(x); } else{ } // go up one level within the tree // setting x to its parent node x=px; } /* Re-Insert all leaves that were previously * removed into the tree */ for(auto it=n.begin(); it!= n.end(); it++){ ReinsertNodes(*it); } } // // Bulkload // // Start bulkload-mode template void RTree::BeginBulkload( const double maxDist ) { // Initialize bulkload-process // Check for empty tree if ( m_treeHeader->GetRoot() != 0 ) throw runtime_error( "Tree-file is not empty" ); // Create root node _curBulkNode = CreateRTReeNode( true ); // update header m_treeHeader->SetRoot( _curBulkNode->GetNodeID() ); if ( !_bulkStack.empty() ) throw runtime_error( "internal error" ); _bulkMaxHeight = 0; _bulkMaxDist = maxDist; } // Insert value in bulkload-mode template void RTree::Bulkload( const Rectangle& box, const size_t id ) { // Undefined rectangles will be skipped if ( !box.IsDefined() ) return; bool needNewNode = false; // If the current node is completely filled, we have to start a new one if ( _curBulkNode->GetNumberOfEntries() >= _curBulkNode->GetMax() ) needNewNode = true; // Check max. distance if ( !needNewNode && _bulkMaxDist > 0.0 && _curBulkNode->GetNumberOfEntries() > 0 ) { Rectangle b = _curBulkNode->GetBox(); double dist = box.Distance( b ); if ( dist > _bulkMaxDist ) needNewNode = true; } // if if ( needNewNode ) { // The stack contains all inner nodes on the path to the // current bulk node (leaf) if ( _bulkStack.size() < _bulkMaxHeight ) { // If the current path to the leaf is not as height as the most height // path, we can add another level of (inner) nodes. RTreeNode* newInterNode = CreateRTReeNode( false ); newInterNode->AddEntry( _curBulkNode->GetBox(), _curBulkNode->GetNodeID() ); RTreeNode* lastInnerNode = _bulkStack.top(); lastInnerNode->SetIDAt( lastInnerNode->GetNumberOfEntries() - 1, newInterNode->GetNodeID() ); lastInnerNode->SetValueAt( lastInnerNode->GetNumberOfEntries() - 1, newInterNode->GetBox() ); // Make persisten WriteNode( *newInterNode ); WriteNode( *lastInnerNode ); // Push the new "inter-node" to the stack _bulkStack.push( newInterNode ); } // if // The inner node, to which the new child-node will be added RTreeNode* innerNode = 0; while ( _bulkStack.size() > 0 ) { // Get and remove top element RTreeNode* stackNode = _bulkStack.top(); _bulkStack.pop(); // The bbox of the last child node has changed, so we update the // box here. size_t rightMostChildNodeId = stackNode->GetIDAt( stackNode->GetNumberOfEntries() - 1 ); RTreeNode* rightMostChildNode = ReadNode( rightMostChildNodeId ); stackNode->SetValueAt( stackNode->GetNumberOfEntries() - 1, rightMostChildNode->GetBox() ); // Make persisten WriteNode( *stackNode ); delete rightMostChildNode; rightMostChildNode = NULL; // If the node has space available, we can add more elements. // The node goes to the stack again. if ( stackNode->GetNumberOfEntries() < stackNode->GetMax() ) { innerNode = stackNode; _bulkStack.push( stackNode ); break; } else { delete stackNode; stackNode = NULL; } // else } // while // If we haven't found a node on the stack, that can handle more elements, // we have to create a new root node. if ( !innerNode ) { // Create new root node and attach old root node as child innerNode = CreateRTReeNode( false ); RTreeNode* oldRootNode = ReadNode( m_treeHeader->GetRoot() ); // Attach root node innerNode->AddEntry( oldRootNode->GetBox(), oldRootNode->GetNodeID() ); // Set new root node in header m_treeHeader->SetRoot( innerNode->GetNodeID() ); delete oldRootNode; oldRootNode = NULL; // Push the new root node to the stack _bulkStack.push( innerNode ); // Every new root node increments the max. heigth of the tree _bulkMaxHeight++; } // if // Add new child node to the found or created node RTreeNode* newLeaf = CreateRTReeNode( true ); innerNode->AddEntry( newLeaf->GetBox(), newLeaf->GetNodeID() ); // Make persisten WriteNode( *innerNode ); delete _curBulkNode; _curBulkNode = NULL; // The new created leaf is now the current leaf for adding // new elements. _curBulkNode = newLeaf; } // if // Adding the element to the current node _curBulkNode->AddEntry( box, id ); // Make persisten WriteNode( *_curBulkNode ); } // End bulkload-mode template void RTree::EndBulkload() { // traversing stack and adapt boxes while ( _bulkStack.size() > 0 ) { RTreeNode* lastNode = _bulkStack.top(); RTreeNode* rightChild = ReadNode( lastNode->GetIDAt( lastNode->GetNumberOfEntries() - 1 ) ); lastNode->SetValueAt( lastNode->GetNumberOfEntries() - 1, rightChild->GetBox() ); // Make persisten WriteNode( *lastNode ); // Remove node from stack an delete it _bulkStack.pop(); delete rightChild; rightChild = NULL; delete lastNode; lastNode = NULL; } // while if ( _curBulkNode ) { delete _curBulkNode; _curBulkNode = NULL; } // if } template void RTree::ToString(RTreeNode* node){ bool printed = false; size_t i = 0; if(!node->IsLeaf()){ while(i < node->GetNumberOfEntries()){ if(printed == false){ node->PrintNodeToString(); printed = true; } ToString(ReadNode(node->GetIDAt(i))); cout<<"i. "<PrintNodeToString(); } } template string RTree::ToString() { ostringstream o; o << "( tree " << endl; if (m_treeHeader->GetRoot() != 0){ RTreeNode* root = ReadNode(m_treeHeader->GetRoot()); PrintAsTree(o, *root, 0); delete(root); root = NULL; } else{ o << "is empty " << endl; } o << ")"; return o.str(); } template void RTree::PrintAsTree(ostream& o, RTreeNode& node, size_t depth) { for (size_t i = 0; i < depth; i++){ o << " "; } o << "("; o << "' (values:("; for(size_t i = 0; i < node.GetNumberOfEntries(); i++) { if(i != 0) { o << ", "; } o << "("; for (size_t d = 0; d < dim; d++){ o << node.GetValueAt(i).MinD(d) << ' ' << node.GetValueAt(i).MaxD(d); if (d + 1 < dim){ o << ' '; } } o << ")"; } o << "), ids:("; for(size_t i = 0; i < node.GetNumberOfEntries(); i++) { if(i != 0) { o << ", "; } o << node.GetIDAt(i); } o << ")) '"; o << "(Id: " << node.GetNodeID() << " Box: "; o << "("; for (size_t i = 0; i < dim; i++){ o << node.GetBox().MinD(i) << ' ' << node.GetBox().MaxD(i); if (i + 1 < dim){ o << ' '; } } o << ")"; o << " ValueCount: " << node.GetNumberOfEntries() << ")"; if (!node.IsLeaf()) { // not a leaf node for (size_t i = 0; i < (node.GetNumberOfEntries()); i++) { RTreeNode* child = ReadNode(node.GetIDAt(i)); o << endl; PrintAsTree(o, *child, depth + 1); delete(child); child = NULL; } } o << ")"; } template class RTree<1>; template class RTree<2>; template class RTree<3>; template class RTree<4>; template class RTree<8>; }// end of namespace fialgebra