Files
secondo/Algebras/RTree/RTreeAlgebra.h

5101 lines
136 KiB
C
Raw Normal View History

2026-01-23 17:03:45 +08:00
/*
//paragraph [1] Title: [{\Large \bf \begin{center}] [\end{center}}]
//paragraph [10] Footnote: [{\footnote{] [}}]
//[TOC] [\tableofcontents]
{\Large \bf Anhang D: RTree-Template }
[1] Header-File of R-Tree Algebra
1996, Original code from Claudio Esperanca
October 1997, Geraldo Zimbrao made some adaptions.
July 2003, Victor Almeida.
October 2003, Victor Almeida changed the R-Tree class to be a template
on the number of dimensions.
October 2004, Herbert Schoenhammer, tested and divided in Header-File and
Implementation File. Some few corrections in SplitAlgorithms LinearSplit and
AxisSplit were done.
December 2005, Victor Almeida deleted the deprecated algebra levels
(~executable~, ~descriptive~, and ~hibrid~). Only the executable
level remains. Models are also removed from type constructors.
February 2007, Christian Duentgen added operator for bulk loading
R-trees.
July 2008, Christian Duentgen added definitions required for the
~Nearest NeighborAlgebra~ on request of Angelika Braese.
[TOC]
0 Overview
This header file implements a disk-resident representation of a R-Tree.
Setting some parameters the R-Tree-behaviour of Guttman or the R[*]-Tree
of Kriegel et al. can be selected.
The R-Tree is implemented as a template to satisfy the usage with various
dimensions. The desired dimensions are passed as a parameter to the template.
1 Defines and Includes
*/
#ifndef __RTREEPNJ_ALGEBRA_H__
#define __RTREEPNJ_ALGEBRA_H__
#include "stdarg.h"
#ifdef SECONDO_WIN32
#define Rectangle SecondoRectangle
#endif
#include <iostream>
#include <stack>
#include <limits>
#include <string.h>
// Includes required by extensions for the NearestNeighborAlgebra:
#include <vector>
#include <queue>
#include "NestedList.h"
#include "Algebras/Rectangle/RectangleAlgebra.h"
#include "Algebras/Relation-C++/RelationAlgebra.h"
#include "Attribute.h"
extern NestedList* nl;
#define BBox Rectangle
#define BBoxSet RectangleSet
/*
2 Constants
*/
const int MAX_PATH_SIZE = 50;
/*
The maximum height of the R-Tree.
Below are a bunch of constants that will govern
some decisions that have to be made when inserting or
deleting a node into the R-tree. By setting this flags
in a particular pattern, it should be possible to obtain
assorted flavors of R-tree and R[*]-tree behaviours.
*/
const int minimize_leafnode_overlap = 1;
/*
Checked while choosing the node in which a new entry will be placed.
Makes the insertion algorithm behave differently when next to the
bottom-most level of the tree, in that it will try to minimize
leaf node overlap instead of minimizing area enlargement (as is done
with the upper levels).
Used in R[*]-trees.
*/
const int leafnode_subset_max = 32;
/*
If minimize\_leafnode\_overlap is set, this variable determines
how many of the leafnodes will actually be checked (Kriegel et al
recommend 32). This set is chosed amongst the leafnodes that
result in least area enlargement.
*/
const int do_forced_reinsertion = 1;
/*
Checked while trying to insert an entry into a full leaf node. If set,
some of the entries of the leaf node (governed by variable
forced\_reinsertion\_percent below) will be reinserted into the tree.
Used in R[*]-trees.
*/
const int forced_reinsertion_percent = 30;
/*
A number between 0 and 100 that indicates the percentage full leaf node
entries that will be reinserted if the node overflows.
Used in R[*]-trees.
Only one of the three next flags below should be set
*/
const int do_linear_split = 0;
/*
If set, Guttman's linear split algorithm is performed.
Used in standard R-trees
*/
const int do_quadratic_split = 0;
/*
If set, Guttman's quadratic split algorithm is performed.
Used in standard R-trees
*/
const int do_axis_split = 1;
/*
If set, Krigel et al's axis split algorithm is performed.
*/
#define BULKLOAD_LEAF_SKIPPING true
/*
If set to 'true', ~leaf skipping~ is activated within the bulk
loading mechanism. Otherwise, set to 'false'.
Leaf skipping will result in more nodes, but with smaller bounding boxes,
when bulkloading an R-tree.
*/
const double BULKLOAD_TOLERANCE = 8.0;
/*
Tolerance for ~leaf skipping~ in bulkload mechanism.
The tolerance specifies, which multiple of the average distance
of bounding boxes is acceptable within a single node.
Value must be >0.0.
*/
const double BULKLOAD_MIN_ENTRIES_FACTOR = 0.0;
/*
Specifies a multiple of MinEntries, that must be reached, before
~leaf skipping~ is performed during a bulkload.
Value should be between 0.0 and 1.0.
*/
const int BULKLOAD_INITIAL_SEQ_LENGTH = 20;
/*
Specifies the minimum number of the first N entries, that will be inserted
without ~leaf skipping~. This holds only for the first N entries on each level.
After that, ~BULKLOAD\_MIN\_ENTRIES\_FACTOR~ will control the skipping behaviour.
*/
/*
2 Template Class ~DistanceElement~
Required for Nearest Neighbour operations.
*/
template<class LeafInfo>
class DistanceElement
{
private:
long nodeId;
bool leaf;
LeafInfo tpId;
double distance;
int level;
public:
bool IsLeaf() const { return leaf; }
LeafInfo TupleId() const { return tpId; }
long NodeId() const { return nodeId; }
int Level() const { return level; }
struct Near : public std::binary_function< DistanceElement<LeafInfo>,
DistanceElement<LeafInfo>, bool >
{
bool operator()(const DistanceElement<LeafInfo> e1,
const DistanceElement<LeafInfo> e2) const
{
return e1.distance >= e2.distance;
}
};
DistanceElement():
nodeId( -1 ),
leaf( true ),
tpId( -1 ),
level( -1 )
{}
DistanceElement( long node, bool l, LeafInfo tid,
double dist, int curLevel ):
nodeId( node ),
leaf( l ),
tpId( tid ),
distance( dist ),
level( curLevel )
{}
virtual ~DistanceElement()
{}
};
typedef std::vector< DistanceElement<TupleId> > NNVector;
typedef std::priority_queue< DistanceElement<TupleId>, NNVector,
DistanceElement<TupleId>::Near > NNpriority_queue;
/*
3 Struct ~R\_TreeEntry~
*/
struct TwoLayerLeafInfo
{
TupleId tupleId;
int low;
int high;
TwoLayerLeafInfo() {}
TwoLayerLeafInfo( TupleId tupleId, int low, int high ):
tupleId( tupleId ), low( low ), high( high )
{}
};
template<unsigned dim>
struct R_TreeEntry
{
BBox<dim> box;
/*
If it is a leaf entry, then the bounding box spatially constains the spatial
object. If it is an internal entry, the bounding box contains all bounding
boxes of the entries of its child node.
*/
virtual ~R_TreeEntry()
{}
/*
The virtual destructor.
*/
virtual void Read( char *buffer, int& offset ) = 0;
/*
Reads an entry from the buffer. Offset is increased.
*/
virtual void Write( char *buffer, int& offset ) = 0;
/*
Writes an entry to the buffer. Offset is increased.
*/
};
/*
3 Struct ~R\_TreeInternalEntry~
This struct will store an entry inside an internal node of the R\_Tree.
*/
template<unsigned dim>
struct R_TreeInternalEntry : public R_TreeEntry<dim>
{
SmiRecordId pointer;
/*
Points to the child node.
*/
inline R_TreeInternalEntry() {}
/*
The simple constructor.
*/
inline R_TreeInternalEntry( const BBox<dim>& box, SmiRecordId pointer = 0 ) :
pointer( pointer )
{
this->box = box;
}
/*
The second constructor passing a bounding box and a page.
*/
inline R_TreeInternalEntry( const R_TreeInternalEntry<dim>& e ):
pointer( e.pointer )
{
this->box = e.box;
}
/*
The copy constructor.
*/
inline R_TreeInternalEntry<dim>& operator=
( const R_TreeInternalEntry<dim>& entry )
{
this->box = entry.box;
this->pointer = entry.pointer;
return *this;
}
/*
Redefinition of the assignement operator.
*/
static int Size()
{
return sizeof( BBox<dim> ) + sizeof( SmiRecordId );
}
/*
Returns the size of the entry in disk.
*/
void Read( char *buffer, int& offset )
{
memcpy((char*)(&this->box), buffer+offset, sizeof(BBox<dim>) );
new(&this->box) BBox<dim>();
offset += sizeof(BBox<dim>);
memcpy( &pointer, buffer+offset, sizeof(SmiRecordId) );
offset += sizeof(SmiRecordId);
}
/*
Reads an entry from the buffer. Offset is increased.
*/
void Write( char *buffer, int& offset )
{
memcpy( buffer+offset,(void*)(&this->box), sizeof(BBox<dim>) );
offset += sizeof(BBox<dim>);
memcpy( buffer+offset, &pointer, sizeof(SmiRecordId) );
offset += sizeof(SmiRecordId);
}
/*
Writes an entry to the buffer. Offset is increased.
*/
};
/*
4 Struct ~R\_TreeLeafEntry~
This struct will store an entry inside a leaf node of the R\_Tree.
*/
template<unsigned dim, class Info>
struct R_TreeLeafEntry : public R_TreeEntry<dim>
{
Info info;
/*
Stores the leaf entry information.
*/
inline R_TreeLeafEntry() {}
/*
The simple constructor.
*/
inline R_TreeLeafEntry( const BBox<dim>& box, const Info& info ) :
info( info )
{
this->box = box;
}
/*
The second constructor passing a bounding box and the info.
*/
inline R_TreeLeafEntry( const R_TreeLeafEntry<dim, Info>& e ):
info( e.info )
{
this->box = e.box;
}
/*
The copy constructor.
*/
inline R_TreeLeafEntry<dim, Info>& operator=
( const R_TreeLeafEntry<dim, Info>& entry )
{
this->box = entry.box;
this->info = entry.info;
return *this;
}
/*
Redefinition of the assignement operator.
*/
static int Size()
{
return sizeof( BBox<dim> ) + sizeof( Info );
}
/*
Returns the size of the entry in disk.
*/
void Read( char *buffer, int& offset )
{
memcpy((char*)( &this->box), buffer+offset, sizeof(BBox<dim>) );
new(&this->box) BBox<dim>();
offset += sizeof(BBox<dim>);
memcpy( &info, buffer+offset, sizeof(Info) );
offset += sizeof(Info);
}
/*
Reads an entry from the buffer. Offset is increased.
*/
void Write( char *buffer, int& offset )
{
memcpy( buffer+offset,(char*)( &this->box), sizeof(BBox<dim>) );
offset += sizeof(BBox<dim>);
memcpy( buffer+offset, &info, sizeof(Info) );
offset += sizeof(Info);
}
/*
Writes an entry to the buffer. Offset is increased.
*/
};
template<unsigned dim>
class IntrospectResult
{
public:
int level;
long nodeId;
BBox<dim> MBR;
long fatherId;
bool isLeaf;
int minEntries;
int maxEntries;
int countEntries;
R_TreeEntry<dim>** entries;//
IntrospectResult():
level( -1 ),
nodeId( -1 ),
fatherId( -1 ),
isLeaf( true ),
minEntries( -1 ),
maxEntries( -1 ),
countEntries( -1 ),
entries(new R_TreeEntry<dim>*[maxEntries+1])
{
double dmin[dim], dmax[dim];
for(unsigned int i=0; i < dim; i++)
{
dmin[i] = 0.0;
dmax[i] = 0.0;
}
//
for(int i = 0 ;i <= maxEntries;i++)
entries[i] = NULL;
//
MBR = Rectangle<dim>(true, dmin, dmax);
}
IntrospectResult( int lev, int node, BBox<dim> box,
long father, bool leaf,
int minE, int maxE, int countE ):
level( lev ),
nodeId( node ),
MBR( box ),
fatherId( father ),
isLeaf( leaf ),
minEntries( minE ),
maxEntries( maxE ),
countEntries( countE ),
entries(new R_TreeEntry<dim>*[maxEntries+1])
{
for(int i = 0 ;i <= maxEntries;i++)
entries[i] = NULL;
}
IntrospectResult<dim>& operator=(const IntrospectResult<dim>& src){
// delete old entries
for(int i=0;i<=maxEntries;i++){
if(entries[i]){
delete entries[i];
entries[i] = 0;
}
}
if(maxEntries != src.maxEntries){ // different number of entries
if(entries){
delete [] entries;
}
entries = new R_TreeEntry<dim>*[src.maxEntries+1];
}
// copy values
level = src.level;
nodeId = src.nodeId;
MBR = src.MBR;
fatherId = src.fatherId;
isLeaf = src.isLeaf;
minEntries = src.minEntries;
maxEntries = src.maxEntries;
countEntries = src.countEntries;
for(int i=0;i<=maxEntries;i++){
entries[i] = src.entries[i];
}
return *this;
}
virtual ~IntrospectResult()
{
if(entries){
for(int i=0;i<=maxEntries;i++){
if(entries[i]){
delete entries[i];
entries[i] = 0;
}
}
delete[] entries;
entries = 0;
}
}
};
/*
4 Class ~R\_TreeNode~
This is a node in the R-Tree.
*/
template<unsigned dim, class LeafInfo>
class R_TreeNode
{
public:
R_TreeNode( const bool leaf, const int min, const int max );
/*
The constructor.
*/
R_TreeNode( const R_TreeNode<dim, LeafInfo>& n );
/*
The copy constructor.
*/
~R_TreeNode();
/*
The destructor.
*/
static int SizeOfEmptyNode();
/*
This is a class function that returns the size in bytes of an empty node.
It will be used to calculate how many entries fit in a node, given a page size.
*/
int Size() const;
/*
Returns the maximum size in bytes of this node, i.e., how many bytes in disk
this node would occupy at most if written with method ~Write~.
*/
int EntryCount() const
{ return count; }
/*
Returns the number of entries in this node.
*/
int MaxEntries() const
{ return maxEntries; }
/*
Returns the max number of entries this node supports.
*/
int MinEntries() const
{ return minEntries; }
/*
Returns the max number of entries this node supports.
*/
bool IsLeaf() const
{ return leaf; }
/*
Tells whether this node is a leaf node.
*/
R_TreeEntry<dim>& operator[] ( int index ) const {
assert( index >= 0 );
assert(index <= maxEntries );
assert(index < count);
return *entries[ index ];
}
/*
Returns entry given by index.
*/
R_TreeLeafEntry<dim,LeafInfo>* GetLeafEntry(const int index) const;
R_TreeInternalEntry<dim>* GetInternalEntry(const int index) const;
BBox<dim> BoundingBox() const;
BBox<dim> BoundingBox(int entryid) const
{
assert(entryid >= 0 && entryid <= maxEntries);
return entries[entryid]->box;
}
/*
Returns the bounding box of this node.
*/
void Clear()
{
for( int i = 0; i <= maxEntries; i++ )
{
if(entries[i]){
delete entries[ i ];
entries[ i ] = 0;
}
}
count = 0;
modified = true;
}
/*
Clears all entries.
*/
R_TreeNode<dim, LeafInfo>& operator = ( const R_TreeNode<dim, LeafInfo>& );
/*
Assignment operator between nodes.
*/
bool Remove( int );
/*
Removes the given entry from the node. Returns true if successful
or false if underflow (The entry is deleted regardless).
*/
bool Insert( const R_TreeEntry<dim>& e );
/*
Adds ~e~ to this node if possible. Returns ~true~ if successful,
i.e., if there is enough room in the node, or ~false~ if the insertion
caused an overflow. In the latter case, the entry is inserted,
but the node should be split by whoever called the insert method.
*/
void splitOneDimenNode( R_TreeNode<dim, LeafInfo>& n1,
R_TreeNode<dim, LeafInfo>& n2,
int** sortedEntries );
/*
Special split function for one dimensional nodes.
*/
void Split( R_TreeNode<dim, LeafInfo>& n1, R_TreeNode<dim, LeafInfo>& n2 );
/*
Splits this node in two: ~n1~ and ~n2~, which should be empty nodes.
*/
void UpdateBox( BBox<dim>& box, SmiRecordId pointer );
/*
Update entry corresponding to ~pointer~ to have bounding box ~box~.
*/
void Read( SmiRecordFile *file, const SmiRecordId pointer );
void Read( SmiRecord& record );
/*
Reads this node from an ~SmiRecordFile~ at position ~id~.
*/
void Write( SmiRecordFile *file, const SmiRecordId pointer );
void Write( SmiRecord& record );
/*
Writes this node to an ~SmiRecordFile~ at position ~id~
*/
void SetInternal( int minEntries, int maxEntries )
{
assert( count == 0 );
leaf = false;
this->minEntries = minEntries;
this->maxEntries = maxEntries;
modified = true;
}
/*
Converts a leaf node to an internal one. The node must be empty.
*/
//////////////////////////////////////////////////
void SetModified(){modified = true;}
//////////////////////////////////////////////////////
private:
bool leaf;
/*
Flag that tells whether this is a leaf node
*/
int minEntries;
/*
Min \# of entries per node.
*/
int maxEntries;
/*
Max \# of entries per node.
*/
int count;
/*
Number of entries in this node.
*/
R_TreeEntry<dim>** entries;
/*
Array of entries.
*/
bool modified;
/*
A flag that indicates when a node is modified. This avoids
writing unnecessarily.
*/
void LinearPickSeeds( int& seed1, int& seed2 ) const;
/*
Implements the linear ~PickSeeds~ algorithm of Guttman.
Linear algorithm that selects 2 seed entries to use as anchors
for the node splitting algorithm. The entry numbers are returned
in ~seed1~ and ~seed2~.
*/
void QuadraticPickSeeds( int& seed1, int& seed2 ) const;
/*
Implementation of the quadratic 'PickSeeds' Algorithm of Guttman.
Quadratic algorithm that selects 2 seed entries to use as anchors
for the node splitting algorithm. The entry numbers are returned
in ~seed1~ and ~seed2~.
*/
int QuadraticPickNext( BBox<dim>& b1, BBox<dim>& b2 ) const;
/*
Returns the entry position that should be assigned next to one of the
two groups with bounding boxes ~b1~ and ~b2~, respectively.
(Algorithm ~PickNext~ of Guttman)
*/
};
/*
4.1 The constructors
*/
template<unsigned dim, class LeafInfo>
R_TreeNode<dim, LeafInfo>::R_TreeNode( const bool leaf,
const int min,
const int max ) :
leaf( leaf ),
minEntries( min ),
maxEntries( max ),
count( 0 ),
entries( new R_TreeEntry<dim>*[ max + 1 ] ),
modified( true )
{
for( int i = 0; i <= maxEntries; i++ ){
entries[ i ] = 0;
}
}
template<unsigned dim, class LeafInfo>
R_TreeNode<dim, LeafInfo>::R_TreeNode( const R_TreeNode<dim, LeafInfo>& node ) :
leaf( node.leaf ),
minEntries( node.minEntries ),
maxEntries( node.maxEntries ),
count( node.count ),
entries( new R_TreeEntry<dim>*[ node.maxEntries + 1 ] ),
modified( true )
{
int i;
for( i = 0; i < node.EntryCount(); i++ )
{
if( leaf )
entries[ i ] =
new R_TreeLeafEntry<dim, LeafInfo>( (R_TreeLeafEntry<dim,
LeafInfo>&)*node.entries[ i ] );
else
entries[ i ] =
new R_TreeInternalEntry<dim>( (
R_TreeInternalEntry<dim>&)*node.entries[ i ] );
}
for( ; i <= node.maxEntries; i++ ){
entries[ i ] = NULL;
}
}
/*
4.2 The destructor
*/
template<unsigned dim, class LeafInfo>
R_TreeNode<dim, LeafInfo>::~R_TreeNode()
{
for( int i = 0; i <= count; i++ ){
delete entries[ i ];
}
delete []entries;
}
template<unsigned dim, class LeafInfo>
int R_TreeNode<dim, LeafInfo>::SizeOfEmptyNode()
{
return sizeof( bool ) + // leaf
sizeof( int ); // count
}
template<unsigned dim, class LeafInfo>
int R_TreeNode<dim, LeafInfo>::Size() const
{
int size = SizeOfEmptyNode();
if( leaf )
size += R_TreeLeafEntry<dim, LeafInfo>::Size() * maxEntries;
else
size += R_TreeInternalEntry<dim>::Size() * maxEntries;
return size;
}
template<unsigned dim, class LeafInfo>
R_TreeNode<dim, LeafInfo>& R_TreeNode<dim, LeafInfo>::operator=
(const R_TreeNode<dim, LeafInfo>& node )
{
// delete old entries
for(int i=0;i<=count; i++){
delete entries[i];
entries[i] = 0;
}
leaf = node.leaf;
count = node.count;
modified = true;
// if there are a change in size, resize the entries array
if(maxEntries!=node.maxEntries){
delete[] entries;
entries = new R_TreeEntry<dim>*[node.maxEntries +1];
for(int i=node.count; i<=node.maxEntries; i++){
entries[i] = 0;
}
}
for( int i = 0; i < node.count; i++ ) {
if( leaf ){
entries[ i ] = new R_TreeLeafEntry<dim, LeafInfo>
( (R_TreeLeafEntry<dim, LeafInfo>&)*node.entries[ i ] );
} else {
entries[ i ] = new R_TreeInternalEntry<dim>
( (R_TreeInternalEntry<dim>&)*node.entries[ i ] );
}
}
return *this;
}
template<unsigned dim, class LeafInfo>
bool R_TreeNode<dim, LeafInfo>::Remove( int index )
{
assert( index >= 0 && index < count );
delete entries[ index ];
entries[ index ] = entries[ count - 1 ];
entries[ count - 1 ] = 0;
count -= 1;
modified = true;
return (count >= minEntries);
}
/*
4.3 Method Insert
*/
template<unsigned dim, class LeafInfo>
bool R_TreeNode<dim, LeafInfo>::Insert( const R_TreeEntry<dim>& ent )
{
assert( count <= maxEntries );
if( leaf )
entries[ count++ ] = new R_TreeLeafEntry<dim, LeafInfo>
( (R_TreeLeafEntry<dim, LeafInfo>&)ent );
else
entries[ count++ ] = new R_TreeInternalEntry<dim>
( (R_TreeInternalEntry<dim>&)ent );
modified = true;
return (count <= maxEntries);
}
/*
4.3 Method LinearPickSeeds
*/
template<unsigned dim, class LeafInfo>
void R_TreeNode<dim, LeafInfo>::LinearPickSeeds( int& seed1, int& seed2 ) const
{
assert( EntryCount() == MaxEntries() + 1 );
// This should be called only if the node has an overflow
double maxMinVal[ dim ];
double minMaxVal[ dim ];
double minVal[ dim ];
double maxVal[ dim ];
double sep[ dim ];
double maxSep = -std::numeric_limits<double>::max();
int maxMinNode[ dim ];
int minMaxNode[ dim ];
int bestD = -1;
for( unsigned i = 0; i < dim; i++ )
{
maxMinVal[i] = -std::numeric_limits<double>::max();
minMaxVal[i] = std::numeric_limits<double>::max();
minVal[i] = std::numeric_limits<double>::max();
maxVal[i] = -std::numeric_limits<double>::max();
maxMinNode[i] = -1;
minMaxNode[i] = -1;
}
for( int i = 0; i < EntryCount(); i++ )
{
for( unsigned d = 0; d < dim; d++ )
{
if( entries[ i ]->box.MinD( d ) > maxMinVal[ d ] )
{
maxMinVal[ d ] = entries[ i ]->box.MinD( d );
maxMinNode[ d ] = i;
}
if( entries[ i ]->box.MinD( d ) < minVal[ d ] )
minVal[ d ] = entries[ i ]->box.MinD( d );
if( entries[ i ]->box.MaxD( d ) < minMaxVal[ d ] )
{
minMaxVal[ d ] = entries[ i ]->box.MaxD( d );
minMaxNode[ d ] = i;
}
if( entries[ i ]->box.MaxD( d ) > maxVal[ d ] )
maxVal[ d ] = entries[ i ]->box.MaxD( d );
}
}
for( unsigned d = 0; d < dim; d++ )
{
assert( maxMinNode[ d ] != -1 && minMaxNode[ d ] != -1 );
assert( maxVal[ d ] > minVal[ d ] );
sep[ d ] = double( maxMinVal[ d ] - minMaxVal[ d ] )
/ (maxVal[ d ] - minVal[ d ]);
if( sep[ d ] > maxSep )
{
bestD = d;
maxSep = sep[ d ];
}
}
assert( bestD != -1 );
seed1 = maxMinNode[ bestD ];
seed2 = minMaxNode[ bestD ];
if( seed1 == seed2 )
{
if( seed2 == 0 )
seed2++;
else
seed2--;
}
}
/*
4.4 Method QuadraticPickSeeds
*/
template<unsigned dim, class LeafInfo>
void R_TreeNode<dim, LeafInfo>::QuadraticPickSeeds( int& seed1,
int& seed2 ) const
{
assert( EntryCount() == MaxEntries() + 1 );
// This should be called only if the node has an overflow
double bestWaste = -std::numeric_limits<double>::max();
double *area = new double[ MaxEntries() + 1 ]; // Compute areas just once
int i;
for( i = 0; i < EntryCount(); i++ )
{
int j;
area[ i ] = entries[ i ]->box.Area();
for( j = 0; j < i; ++j )
{
double totalArea = entries[ i ]->box.Union( entries[ j ]->box ).Area();
double waste = totalArea - area[ i ] - area[ j ];
if( waste > bestWaste )
{
seed1 = i;
seed2 = j;
bestWaste = waste;
}
}
}
delete [] area;
}
/*
4.5 Method QuadraticPickNext
*/
template<unsigned dim, class LeafInfo>
int R_TreeNode<dim, LeafInfo>::QuadraticPickNext( BBox<dim>& b1,
BBox<dim>& b2 ) const
{
double area1 = b1.Area();
double area2 = b2.Area();
double bestDiff = -1;
int besti = -1;
for( int i = 0; i < count; i++ )
{
double d1 = b1.Union( entries[ i ]->box ).Area() - area1;
double d2 = b2.Union( entries[ i ]->box ).Area() - area2;
double diff = fabs( d1 - d2 );
assert( d1 >= 0 && d2 >= 0 );
if( diff > bestDiff )
{
bestDiff = diff;
besti = i;
}
}
assert( besti >= 0 );
return besti;
}
struct SortedArrayItem
{
int index;
double pri;
};
int myCompare( const void* a, const void* b );
class SortedArray
{
public:
SortedArray( unsigned max ) : max( max ), i( 0 ), n( 0 ), sorted( 0 )
{ a = new SortedArrayItem[ max ]; }
~SortedArray ()
{ delete [] a; }
int empty() const
{ return i == n; }
void push( int index, double pri );
int head()
{ if( !sorted ) sort(); return a[ i ].index; }
double headPri()
{ if( !sorted ) sort(); return a[ i ].pri; }
int pop()
{ if( !sorted ) sort(); assert( i <= n ); return a[ i++ ].index; }
private:
int max;
int i;
int n;
int sorted;
SortedArrayItem* a;
void sort()
{
assert( i == 0 && n > 0 && !sorted );
qsort( a, n, sizeof( SortedArrayItem ), myCompare );
sorted = 1;
}
};
inline void SortedArray::push( int index, double pri )
{
if( i == n )
{
i = n = 0;
sorted = 0;
}
assert( n < max && i == 0 );
a[ n ].index = index;
a[ n ].pri = pri;
n++;
};
/*
4.6 Method Split
4.6.1 Special case for only one dimension
*/
template<unsigned dim,class LeafInfo>
void R_TreeNode<dim,LeafInfo>::splitOneDimenNode(
R_TreeNode<dim,LeafInfo>& n1,
R_TreeNode<dim,LeafInfo>& n2,
int** sortedEntries){
assert(dim==1);
double minD = entries[sortedEntries[0][MaxEntries()/2]]->box.MinD(0);
double maxD = entries[sortedEntries[1][MaxEntries()/2]]->box.MaxD(0);
double avg = (minD+maxD)/2.0;
int mE = MaxEntries()-MinEntries();
for(int i=0;i<EntryCount();i++){
if(n1.EntryCount() > mE){
n2.Insert( *entries[ i ]);
} else if(n2.EntryCount() > mE){
n1.Insert( *entries[ i ]);
} else {
double avgi = ( entries[i]->box.MinD(0) + entries[i]->box.MaxD(0))/2.0;
if(avgi < avg){
n1.Insert( *entries[ i ] );
} else {
n2.Insert( *entries[ i ]);
}
}
}
}
/*
4.6.2 General function
*/
template<unsigned dim, class LeafInfo>
void R_TreeNode<dim, LeafInfo>::Split( R_TreeNode<dim,
LeafInfo>& n1,
R_TreeNode<dim,
LeafInfo>& n2 )
// Splits this node into two ones: n1 and n2, which must be empty nodes.
{
assert( EntryCount() == MaxEntries() + 1 );
// Make sure this node is ready to be split
assert( n1.EntryCount() == 0 && n2.EntryCount() == 0 );
assert( n1.MinEntries() == MinEntries() && n1.MaxEntries() == MaxEntries() );
assert( n2.MinEntries() == MinEntries() && n2.MaxEntries() == MaxEntries() );
// Make sure n1 and n2 are ok
if( do_axis_split )
{ // Do R[*]-Tree style split
int *sortedEntry[ 2*dim ] = { NULL }; // Arrays of sorted entries
for( unsigned d = 0; d < dim; d++ )
{ // Compute sorted lists.
// Sort entries numbers by minimum value of axis 'd'.
int* psort = sortedEntry[ 2*d ] = new int[ MaxEntries() + 1 ];
SortedArray sort( MaxEntries() + 1 );
int i;
for( i = 0; i <= MaxEntries(); i++ )
sort.push( i, entries[ i ]->box.MinD( d ) );
for( i = 0; i <= MaxEntries(); i++ )
*psort++ = sort.pop();
assert( sort.empty() );
// Sort entries numbers by maximum value of axis 'd'
psort = sortedEntry[ 2*d + 1 ] = new int[ MaxEntries() + 1 ];
for( i = 0; i <= MaxEntries(); i++ )
sort.push( i, entries[ i ]->box.MaxD( d ) );
for( i = 0; i <= MaxEntries(); i++ )
*psort++ = sort.pop();
assert( sort.empty() );
}
if(dim==1){ // for only 1 dimension, there is no
//reason for computing the split
// dimension
splitOneDimenNode( n1,n2,sortedEntry);
delete [] sortedEntry[ 0 ];
delete [] sortedEntry[ 1 ];
modified = true;
return;
}
struct StatStruct
{
double margin;
double overlap;
double area;
} *stat = new StatStruct[ dim*dim*(MaxEntries() + 2 - 2*MinEntries()) ],
*pstat = stat; // Array of distribution statistics
double minMarginSum = std::numeric_limits<double>::max();
int minMarginAxis = -1;
// Compute statistics for the various distributions
for( unsigned d = 0; d < dim; d++ )
{ // Sum margins over all distributions correspondig to one axis
double marginSum = 0.0;
for( unsigned minMax = 0; minMax < 2; minMax++ )
{ // psort points to one of the sorted arrays of entries
int* psort = sortedEntry[ 2*d + minMax ];
// Start by computing the cummulative bounding boxes of the
// 'MaxEntries()-MinEntries()+1' entries of each end of the scale
BBox<dim> *b1 = new BBox<dim>[ MaxEntries() + 1 ];
BBox<dim> *b2 = new BBox<dim>[ MaxEntries() + 1 ];
int i, splitPoint;
b1[ 0 ] = entries[ psort[ 0 ] ]->box;
b2[ 0 ] = entries[ psort[ MaxEntries() ] ]->box;
for( i = 1; i <= MaxEntries(); i++ )
{
b1[i] = b1[i-1].Union(entries[psort[i]]->box );
b2[i] = b2[i-1].Union(entries[psort[MaxEntries()-i]]->box);
}
// Now compute the statistics for the
// MaxEntries() - 2*MinEntries() + 2 distributions
for( splitPoint = MinEntries() - 1;
splitPoint <= MaxEntries() - MinEntries();
splitPoint++ )
{
BBox<dim>& box1 = b1[ splitPoint ];
BBox<dim>& box2 = b2[ MaxEntries() - splitPoint - 1 ];
pstat->margin = box1.Perimeter() + box2.Perimeter();
pstat->overlap = box1.Intersection( box2 ).Area();
pstat->area = box1.Area() + box2.Area();
marginSum += pstat->margin;
pstat += 1;
assert( pstat - stat <=
(int)(dim*dim*(MaxEntries() + 2 - 2*MinEntries())) );
}
delete [] b2;
delete [] b1;
}
if( marginSum < minMarginSum )
{
minMarginSum = marginSum;
minMarginAxis = d;
}
}
assert( pstat - stat == 2*(int)dim*(MaxEntries() + 2 - 2*MinEntries()));
// At this point we have in minMarginAxis the axis on which we will
// split. Choose the distribution with minimum overlap,
// breaking ties by choosing the distribution with minimum Area
{
double minOverlap = std::numeric_limits<double>::max();
double minArea = std::numeric_limits<double>::max();
int minSplitPoint = -1;
int *sort = 0;
int d = minMarginAxis;
pstat = &stat[ 2*d*(MaxEntries() + 2 - 2*MinEntries()) ];
for( unsigned minMax = 0; minMax < 2; minMax++ )
{
int *psort = sortedEntry[ 2*d + minMax ];
int splitPoint;
for( splitPoint = MinEntries() - 1;
splitPoint <= MaxEntries()-MinEntries();
splitPoint++, pstat++ )
if( pstat->overlap < minOverlap ||
(pstat->overlap == minOverlap && pstat->area < minArea) )
{
minOverlap = pstat->overlap;
minArea = pstat->area;
minSplitPoint = splitPoint;
sort = psort;
}
}
assert( sort != 0 );
assert( pstat - stat == (d + 1 )*2*(MaxEntries() + 2 - 2*MinEntries()) );
// Picked distribution; now put the corresponding entries in the
// two split blocks
for( int i = 0; i <= minSplitPoint; i++ )
n1.Insert( *entries[ sort[ i ] ] );
for( int i = minSplitPoint + 1; i <= MaxEntries(); i++ )
n2.Insert( *entries[ sort[ i ] ] );
assert( AlmostEqual(
n1.BoundingBox().Intersection( n2.BoundingBox() ).Area(),
minOverlap ));
// Deallocate the sortedEntry arrays
for( unsigned i = 0; i < 2*dim; i++)
delete [] sortedEntry[ i ];
delete [] stat;
}
}
else
{ // Do regular R-tree split
int seed1, seed2; // Pick seeds
if( do_quadratic_split )
QuadraticPickSeeds( seed1, seed2 );
else
{
assert( do_linear_split );
LinearPickSeeds( seed1, seed2 );
}
// Put the two seeds in n1 and n2 and mark them
BBox<dim> box1 = entries[ seed1 ]->box;
BBox<dim> box2 = entries[ seed2 ]->box;
n1.Insert( *entries[ seed1 ] );
n2.Insert( *entries[ seed2 ] );
// Make sure that we delete entries from end of the array first
if( seed1 > seed2 )
{
Remove( seed1 );
Remove( seed2 );
}
else
{
Remove( seed2 );
Remove( seed1 );
}
{ // Successively choose a not yet assigned entry and put it into n1 or n2
int i = 0;
int notAssigned = EntryCount();
assert( notAssigned == MaxEntries() - 1 );
while( notAssigned > 0 )
{
if( n1.EntryCount() + notAssigned == n1.MinEntries() )
{ // Insert all remaining entries in n1
for( i = 0; i < EntryCount() ; i++, notAssigned-- ){
n1.Insert( *entries[ i ] );
delete entries[i];
entries[i] = 0;
}
count = 0;
assert( notAssigned == 0 );
}
else if( n2.EntryCount() + notAssigned == n2.MinEntries() )
{ // Insert all remaining entries in n2
for( i = 0; i < EntryCount(); ++i, notAssigned-- ){
n2.Insert( *entries[ i ] );
delete entries[i];
entries[i] = 0;
}
count = 0;
assert( notAssigned == 0 );
}
else
{
BBox<dim> union1, union2;
if( do_quadratic_split )
i = QuadraticPickNext( box1, box2 );
else
{
assert( do_linear_split );
i = 0;
}
union1 = box1.Union( entries[ i ]->box );
union2 = box2.Union( entries[ i ]->box );
if( union1.Area() - box1.Area() < union2.Area() - box2.Area() )
{
n1.Insert( *entries[ i ] );
box1 = union1;
}
else
{
n2.Insert( *entries[ i ] );
box2 = union2;
}
Remove( i );
notAssigned--;
}
}
assert( notAssigned == 0 );
assert( EntryCount() == 0 );
}
}
assert( n1.EntryCount() + n2.EntryCount() == MaxEntries() + 1 );
assert( n1.EntryCount() >= MinEntries() && n1.EntryCount() <= MaxEntries() );
assert( n2.EntryCount() >= MinEntries() && n2.EntryCount() <= MaxEntries() );
modified = true;
}
/*
4.7 Method BoundingBox
*/
template<unsigned dim, class LeafInfo>
BBox<dim> R_TreeNode<dim, LeafInfo>::BoundingBox() const
{
if( count == 0 )
return BBox<dim>( false );
else
{
BBox<dim> result = entries[ 0 ]->box;
int i;
for( i = 1; i < count; i++ )
result = result.Union( entries[ i ]->box );
return result;
}
}
/*
4.8 Method UpdateBox
*/
template<unsigned dim, class LeafInfo>
void R_TreeNode<dim, LeafInfo>::UpdateBox( BBox<dim>& b, SmiRecordId pointer )
{
assert( !leaf );
modified = true;
for( int i = 0; i < count; i++ )
if( ((R_TreeInternalEntry<dim>*)entries[ i ])->pointer == pointer )
{
entries[ i ]->box = b;
return;
}
// Should never reach this point
assert( 0 );
}
template<unsigned dim, class LeafInfo>
void R_TreeNode<dim, LeafInfo>::Read( SmiRecordFile *file,
const SmiRecordId pointer )
{
SmiRecord record;
int RecordSelected = file->SelectRecord( pointer, record, SmiFile::ReadOnly );
assert( RecordSelected );
Read( record );
}
template<unsigned dim, class LeafInfo>
void R_TreeNode<dim, LeafInfo>::Read( SmiRecord& record )
{
int offset = 0;
size_t readed;
char* buffer = record.GetData(readed);
// Reads leaf, count
memcpy( &leaf, buffer + offset, sizeof( leaf ) );
offset += sizeof( leaf );
memcpy( &count, buffer + offset, sizeof( count ) );
offset += sizeof( count );
assert( count <= maxEntries );
// Now read the entry array.
for( int i = 0; i < count; i++ )
{
if( leaf )
entries[ i ] = new R_TreeLeafEntry<dim, LeafInfo>();
else
entries[ i ] = new R_TreeInternalEntry<dim>();
entries[ i ]->Read( buffer, offset );
}
free(buffer);
assert(offset<=(int)readed); // otherwise some entries will be uninitialized
modified = false;
}
template<unsigned dim, class LeafInfo>
void R_TreeNode<dim, LeafInfo>::Write( SmiRecordFile *file,
const SmiRecordId pointer )
{
if( modified )
{
SmiRecord record;
int RecordSelected = file->SelectRecord( pointer, record, SmiFile::Update );
assert( RecordSelected );
Write( record );
}
}
template<unsigned dim, class LeafInfo>
void R_TreeNode<dim, LeafInfo>::Write( SmiRecord& record )
{
if( modified )
{
int offset = 0;
char buffer[Size() + 1];
memset( buffer, 0, Size() + 1 );
// Writes leaf, count
memcpy( buffer + offset, &leaf, sizeof( leaf ) );
offset += sizeof( leaf );
memcpy( buffer + offset, &count, sizeof( count ) );
offset += sizeof( count );
//cout << "R_TreeNode<dim, LeafInfo>::Write(): count/maxEntries = "
// << count << "/" << maxEntries << "." << endl;
assert( count <= maxEntries );
// Now write the entry array.
for( int i = 0; i < count; i++ )
entries[i]->Write( buffer, offset );
int RecordWritten = record.Write( buffer, Size(), 0 );
assert( RecordWritten );
modified = false;
}
}
/*
5 Class ~R\_Tree~
This class implements the R-Tree.
*/
template<unsigned dim, class LeafInfo>
class BulkLoadInfo
{
public:
R_TreeNode<dim, LeafInfo> *node[MAX_PATH_SIZE];
bool skipLeaf;
int currentLevel;
int currentHeight;
int nodeCount;
int entryCount;
long levelEntryCounter[MAX_PATH_SIZE];
double levelDistanceSum[MAX_PATH_SIZE];
BBox<dim> levelLastBox[MAX_PATH_SIZE];
BulkLoadInfo(const bool &leafSkipping = false) :
skipLeaf( leafSkipping ),
currentLevel( 0 ),
currentHeight( 0 ),
nodeCount( 0 ),
entryCount( 0 )
{
for(int i=0; i < MAX_PATH_SIZE; i++)
{
node[i] = NULL;
levelEntryCounter[i] = 0;
levelDistanceSum[i] = 0.0;
levelLastBox[i] = BBox<dim>(false);
}
};
virtual ~BulkLoadInfo()
{
for(int i=0; i < MAX_PATH_SIZE; i++)
if(node[i] != NULL)
delete node[i];
};
};
template <unsigned dim, class LeafInfo>
class R_Tree
{
public:
/*
The first constructor. Creates an empty R-tree.
*/
R_Tree( const int pageSize, const bool isTemp );
/*
Opens an existing R-tree.
*/
R_Tree( SmiRecordFile *file );
R_Tree( const SmiFileId fileId, const bool isTemp );
R_Tree( SmiRecordFile *file,
const SmiRecordId headerRecordId );
R_Tree( const SmiFileId fileId,bool update, const bool isTemp );
/////////////////////////////////////////////////////////////////////////////
R_Tree( const SmiFileId fileid,const int, const bool isTemp);
void Clear();
void OpenFile(const SmiFileId fileid){file->Open(fileid);}
void CloseFile(){file->Close();}
void SwitchHeader(R_Tree<dim,LeafInfo>*);
int GetShare(){return header.share;}
void IncreaseShare(){header.share++; WriteHeader();}
void DecreaseShare(){header.share--; WriteHeader();}
void MergeRtree();
SmiRecordId Record_Path_Id(){return header.path_rec_id;}
////////////////////////////////////////////////////////////////////////////
void Clone(R_Tree<dim,LeafInfo>*);
SmiRecordId DFVisit_Rtree(R_Tree<dim,LeafInfo>*,R_TreeNode<dim,LeafInfo>*);
/*
The destructor.
*/
~R_Tree();
/*
Open and Save are used by NetworkAlgebra to save and open the rtree of network.
*/
bool Open( SmiRecord& valueRecord,
size_t& offset,
std::string typeInfo,
Word &value);
bool Save(SmiRecord& valueRecord,
size_t& offset);
/*
The type name used in Secondo:
*/
inline static const std::string BasicType(){
if(dim==2){
return "rtree";
} else {
std::ostringstream ss;
ss << "rtree" << dim;
return ss.str();
}
}
static const bool checkType(ListExpr type){
return listutils::isRTreeDescription(type, BasicType());
}
/*
Deletes the file of the R-Tree.
*/
inline void DeleteFile()
{
if(nodePtr){
delete nodePtr;
nodePtr=0;
}
file->Close();
file->Drop();
}
/*
Returns the ~SmiFileId~ of the R-Tree database file.
*/
inline SmiFileId FileId()
{
return file->GetFileId();
}
inline void GetNode(SmiRecordId id, R_TreeNode<dim, LeafInfo>& result) {
result.Read(file,id);
}
/*
Returns the ~SmiRecordId~ of the root node.
*/
inline SmiRecordId RootRecordId() const
{
return header.rootRecordId;
}
/*
Returns the ~SmiRecordId~ of the header node.
*/
inline SmiRecordId HeaderRecordId() const
{
return header.headerRecordId;
}
inline int MinEntries( int level ) const
{
return level == Height() ? header.minLeafEntries
: header.minInternalEntries;
}
inline int MinLeafEntries() const{
return header.minLeafEntries;
}
inline int MinInternalEntries() const{
return header.minInternalEntries;
}
/*
Returns the minimum number of entries per node.
*/
inline int MaxEntries( int level ) const
{
return level == Height() ? header.maxLeafEntries
: header.maxInternalEntries;
}
inline int MaxLeafEntries() const{
return header.maxLeafEntries;
}
inline int MaxInternalEntries() const{
return header.maxInternalEntries;
}
/*
Returns the maximum number of entries per node.
*/
inline int EntryCount() const
{
return header.entryCount;
}
/*
Return the total number of (leaf) entries in this tree.
*/
inline int NodeCount() const
{
return header.nodeCount;
}
/*
Returns the total number of nodes in this tree.
*/
inline int Height() const
{
return header.height;
}
/*
Returns the height of this tree.
*/
BBox<dim> BoundingBox();
/*
Returns the bounding box of this rtree.
*/
void Insert( const R_TreeLeafEntry<dim, LeafInfo>& );
/*
Inserts the given entry somewhere in the tree.
*/
bool Remove( const R_TreeLeafEntry<dim, LeafInfo>& );
/*
Deletes the given entry from the tree. Returns ~true~ if entry found
and successfully deleted, and ~false~ otherwise.
*/
bool First( const BBox<dim>& bx,
R_TreeLeafEntry<dim, LeafInfo>& result,
int replevel = -1 );
bool First( const BBoxSet<dim>& searchBoxSet,
R_TreeLeafEntry<dim, LeafInfo>& result );
bool Next( R_TreeLeafEntry<dim, LeafInfo>& result );
/*
Sets ~result~ to the (leaf) entry corresponding to the first/next
object whose bounding box overlaps ~bx~.
Returns ~true~ if a suitable entry was found and ~false~ if not.
Setting ~replevel~ to a value != -1 forces the search to return
entries at that level of the tree regardless of whether they
are at leaf nodes or not.
*/
R_TreeNode<dim, LeafInfo>& Root();
/*
Loads ~nodePtr~ with the root node and returns it.
*/
bool checkRecordId(SmiRecordId nodeId);
bool InitializeBulkLoad(const bool &leafSkipping = BULKLOAD_LEAF_SKIPPING);
/*
Verifies, that the R-tree is empty. Use this before calling
~InsertBulkLoad()~.
Data structures used during bulk loading will be initialized.
*/
void InsertBulkLoad(const R_TreeEntry<dim>& entry);
/*
Insert an entry in the bulk loading mode. The R-tree will be
constructed bottom up.
*/
bool FinalizeBulkLoad();
/*
Call this after inserting the last entry in the bulk loading mode.
The root will be changed to point to the constructed R-tree.
Data structures used during bulk loading will be deleted.
*/
bool IntrospectFirst(IntrospectResult<dim>& result);
bool IntrospectNext(IntrospectResult<dim>& result);
bool IntrospectNextE(unsigned long& nodeid, BBox<dim>& box,unsigned long&
tupleid);
SmiRecordId SmiNodeId(int currlevel)
{
assert(currlevel >= 0 && currlevel <= Height());
return path[currlevel];
}
/*
The last two methods are used to produce a sequence of node decriptions, that
can be used to inspect the R-tree structure.
*/
void FirstDistanceScan( const BBox<dim>& box );
/*
FirstDistanceScan initializes the priority queue.
Implemented by NearestNeighborAlgebra.
*/
void LastDistanceScan( );
/*
LastDistanceScan deletes the priority queue of the distancescan
Implemented by NearestNeighborAlgebra.
*/
bool NextDistanceScan( const BBox<dim>& box, LeafInfo& result );
/*
NextDistanceScan returns true and fills the result with the
ID of the next tuple if there is a next tuple else it returns false
Implemented by NearestNeighborAlgebra.
*/
void GetNeighborNode(const R_TreeLeafEntry<dim, LeafInfo>& ent ,
std::vector<int>& list);
R_TreeNode<dim, LeafInfo> *GetMyNode(SmiRecordId& address,
const bool leaf,
const int min, const int max )
{
return GetNode(address,leaf,min,max);
}
bool getFileStats( SmiStatResultType &result );
////////////
bool InitializeBLI(const bool& leafSkipping=BULKLOAD_LEAF_SKIPPING);
std::ostream& printHeader(std::ostream& o) const{
return header.print(o);
}
///////////
private:
bool fileOwner;
SmiRecordFile *file;
/*
The record file of the R-Tree.
*/
struct Header
{
SmiRecordId headerRecordId; // Header node address.
SmiRecordId rootRecordId; // Root node address (Path[ 0 ]).
int minLeafEntries; // min # of entries per leaf node.
int maxLeafEntries; // max # of entries per leaf node.
int minInternalEntries; // min # of entries per internal node.
int maxInternalEntries; // max # of entries per internal node.
int nodeCount; // number of nodes in this tree.
int entryCount; // number of entries in this tree.
int height; // height of the tree.
//new record
SmiRecordId second_head_id; //two rtrees on the same file
SmiRecordId path_rec_id; //record update path for new coverage
int share;
Header() :
headerRecordId( 0 ), rootRecordId( 0 ),
minLeafEntries( 0 ), maxLeafEntries( 0 ),
minInternalEntries( 0 ), maxInternalEntries( 0 ),
nodeCount( 0 ), entryCount( 0 ), height( 0 ),
second_head_id(0),path_rec_id(0), share(0)
{}
Header( SmiRecordId _headerRecordId, SmiRecordId _rootRecordId = 0,
int _minEntries = 0, int _maxEntries = 0,
int _minInternalEntries = 0, int _maxInternalEntries = 0,
int _nodeCount = 0, int _entryCount = 0,
int _nodeSize = 0, int _height = 0, int s =0 ) :
headerRecordId( _headerRecordId ),
rootRecordId( _rootRecordId ),
minLeafEntries( _minEntries ),
maxLeafEntries( _maxEntries ),
minInternalEntries( _minInternalEntries ),
maxInternalEntries( _maxInternalEntries ),
nodeCount( _nodeCount ),
entryCount( _entryCount ),
height( _height ), share(s)
{}
std::ostream& print(std::ostream& o) const{
o << "RTreeHeader["
<< "headerRecordId = " << headerRecordId
<< ", rootRecordId = " << rootRecordId
<< ", minLeafEntries = " << minLeafEntries
<< ", maxLeafEntries = " << maxLeafEntries
<< ", minInternalEntries = " << minInternalEntries
<< ", maxInternalEntries = " << maxInternalEntries
<< ", nodeCount = " << nodeCount
<< ", entryCount = " << entryCount
<< ", height = " << height
<< ", second_head_id = " << second_head_id
<< ", path_rec_id = " << path_rec_id
<< ", share = " << share
<< "]";
return o;
}
} header;
/*
The header of the R-Tree which will be written (read) to (from) the file.
*/
SmiRecordId path[ MAX_PATH_SIZE ];
/*
Addresses of all nodes in the current path.
*/
int pathEntry[ MAX_PATH_SIZE ];
/*
Indices of entries down the current path.
*/
int overflowFlag[ MAX_PATH_SIZE ];
/*
Flags used in Insert which control the forced reinsertion process.
*/
R_TreeNode<dim, LeafInfo> *nodePtr;
/*
The current node of the R-tree.
*/
int currLevel;
/*
Current level (of ~nodePtr~).
*/
int currEntry;
/*
Current entry within ~nodePtr~.
*/
int reportLevel;
/*
Report level for first/next.
*/
BBox<dim> searchBox;
BBoxSet<dim> searchBoxSet;
/*
Bounding box for first/next.
*/
enum SearchType { NoSearch, BoxSearch, BoxSetSearch };
SearchType searchType;
/*
A flag that tells whether we're in the middle of a First/Next
scan of the tree.
*/
void PutNode( const SmiRecordId address, R_TreeNode<dim, LeafInfo> **node );
void PutNode( SmiRecord& record, R_TreeNode<dim, LeafInfo> **node );
/*
Writes the node ~node~ at file position ~address~.
Also deletes the node.
*/
R_TreeNode<dim, LeafInfo> *GetNode( const SmiRecordId address,
const bool leaf,
const int min, const int max );
R_TreeNode<dim, LeafInfo> *GetNode( SmiRecord& record, const bool leaf,
const int min, const int max );
/*
Reads a node at file position ~address~. This function creates a new
node that must be deleted somewhere.
*/
void WriteHeader();
/*
Writes the header of this tree.
*/
void ReadHeader();
/*
Reads the header of this rtree.
*/
void InsertEntry( const R_TreeEntry<dim>& );
/*
Inserts given entry in current node.
*/
void LocateBestNode( const R_TreeEntry<dim>& ent, int level );
/*
Locates the "best" node of level ~level~ to insert ~ent~.
*/
bool FindEntry( const R_TreeLeafEntry<dim, LeafInfo>& ent );
/*
Finds the given entry ~ent~ in the tree. If successful, ~true~ is
returned and ~currEntry~ and ~nodePtr~ are set to point to the
found entry. Otherwise, ~false~ is returned.
*/
void UpdateBox();
/*
Updates "bottom-up" bounding boxes of nodes in path
(i.e., from leaf to root).
*/
void GotoLevel( int level );
/*
Loads the node at the given ~level~ (must be in the current path).
*/
void DownLevel( int entryno );
/*
Loads the child node of the current node given by ~entryno~.
*/
void UpLevel();
/*
Loads the father node.
*/
/*
Private InsertBulkLoad method. Additionally gets the TreeNode to insert into.
*/
void InsertBulkLoad(R_TreeNode<dim, LeafInfo> *node,
const R_TreeEntry<dim>& entry);
bool bulkMode;
/*
true, iff in bulk loading mode
*/
BulkLoadInfo<dim, LeafInfo> *bli;
/*
Info maintained during bulk loading
*/
long nodeIdCounter;
/*
A counter used in ~Introspect~ routines
*/
long nodeId[ MAX_PATH_SIZE ];
/*
An array to save the nodeIds of the path during the ~Introspect~ routines
*/
NNpriority_queue* pq;
/*
The priority queue for the distancescan functions
Used by NearestNeighborAlgebra.
*/
bool distanceFlag;
/*
true, after a call of FirstDistanceScan
Used by NearestNeighborAlgebra.
*/
unsigned long noentrynode;//noentryin currnode
};
/*
5.1 The constructors
*/
template <unsigned dim, class LeafInfo>
R_Tree<dim, LeafInfo>::R_Tree( const int pageSize, const bool isTemp ) :
fileOwner( true ),
file( new SmiRecordFile( true, pageSize, isTemp) ),
header(),
nodePtr( NULL ),
currLevel( -1 ),
currEntry( -1 ),
reportLevel( -1 ),
searchBox( false ),
searchBoxSet(),
searchType( NoSearch ),
bulkMode( false ),
bli( NULL ),
nodeIdCounter( 0 )
{
file->Create();
// Calculating maxEntries e minEntries
int nodeEmptySize = R_TreeNode<dim, LeafInfo>::SizeOfEmptyNode();
int leafEntrySize = sizeof( R_TreeLeafEntry<dim, LeafInfo> ),
internalEntrySize = sizeof( R_TreeInternalEntry<dim> );
int maxLeaf = ( pageSize - nodeEmptySize ) / leafEntrySize,
maxInternal = ( pageSize - nodeEmptySize ) / internalEntrySize;
header.maxLeafEntries = maxLeaf;
header.minLeafEntries = (int)(maxLeaf * 0.4);
header.maxInternalEntries = maxInternal;
header.minInternalEntries = (int)(maxInternal * 0.4);
assert( header.maxLeafEntries >= 2*header.minLeafEntries &&
header.minLeafEntries > 0 );
assert( header.maxInternalEntries >= 2*header.minInternalEntries &&
header.minInternalEntries > 0 );
// initialize overflowflag array
for( int i = 0; i < MAX_PATH_SIZE; i++ )
{
overflowFlag[ i ] = 0;
nodeId[ i ] = 0;
}
nodePtr = new R_TreeNode<dim, LeafInfo>( true,
MinEntries( 0 ),
MaxEntries( 0 ) );
// Creating a new page for the R-Tree header.
SmiRecord headerRecord;
int AppendedRecord = file->AppendRecord( header.headerRecordId,
headerRecord );
assert( AppendedRecord );
assert( header.headerRecordId == 1 );
// Creating the root node.
SmiRecordId rootRecno;
SmiRecord rootRecord;
AppendedRecord = file->AppendRecord( rootRecno, rootRecord );
assert( AppendedRecord );
header.rootRecordId = path[ 0 ] = rootRecno;
header.nodeCount = 1;
nodePtr->Write( rootRecord );
currLevel = 0;
}
template<unsigned dim, class LeafInfo>
void R_Tree<dim,LeafInfo>::Clear(){
assert(file);
file->Truncate(); // delete all stuff in file
// reset header entries which depend on entries
header.nodeCount = 0;
header.entryCount = 0;
header.height = 0;
header.second_head_id = 0;
header.path_rec_id = 0;
header.share = 0;
currLevel = -1;
currEntry = -1;
reportLevel = -1;
searchBoxSet.Clear();
searchBox.SetDefined(false);
searchType = NoSearch;
bulkMode = false;
if(bli) {
delete bli;
bli = 0;
}
nodeIdCounter = 0;
// NNpriority queue is managed from outside
distanceFlag = false;
noentrynode = 0;
// initialize member arrays
// should be replaced by memset
for( int i = 0; i < MAX_PATH_SIZE; i++ )
{
overflowFlag[ i ] = 0;
nodeId[ i ] = 0;
path[i] = 0;
pathEntry[i] = 0;
}
if(nodePtr){
delete nodePtr;
}
nodePtr = new R_TreeNode<dim, LeafInfo>( true,
MinEntries( 0 ),
MaxEntries( 0 ) );
// Creating a new page for the R-Tree header.
SmiRecord headerRecord;
int AppendedRecord = file->AppendRecord( header.headerRecordId,
headerRecord );
assert( AppendedRecord );
assert( header.headerRecordId == 1 );
// Creating the root node.
SmiRecordId rootRecno;
SmiRecord rootRecord;
AppendedRecord = file->AppendRecord( rootRecno, rootRecord );
assert( AppendedRecord );
header.rootRecordId = path[ 0 ] = rootRecno;
header.nodeCount = 1;
nodePtr->Write( rootRecord );
currLevel = 0;
};
template <unsigned dim, class LeafInfo>
R_Tree<dim, LeafInfo>::R_Tree( SmiRecordFile *file ) :
fileOwner( false ),
file( file ),
header(),
nodePtr( NULL ),
currLevel( -1 ),
currEntry( -1 ),
reportLevel( -1 ),
searchBox( false ),
searchBoxSet(),
searchType( NoSearch ),
bulkMode( false ),
bli( NULL ),
nodeIdCounter( 0 )
{
// Calculating maxEntries e minEntries
int nodeEmptySize = R_TreeNode<dim, LeafInfo>::SizeOfEmptyNode();
int leafEntrySize = sizeof( R_TreeLeafEntry<dim, LeafInfo> ),
internalEntrySize = sizeof( R_TreeInternalEntry<dim> );
int maxLeaf = ( file->GetRecordLength() - nodeEmptySize ) /
leafEntrySize,
maxInternal = ( file->GetRecordLength() - nodeEmptySize ) /
internalEntrySize;
header.maxLeafEntries = maxLeaf;
header.minLeafEntries = (int)(maxLeaf * 0.4);
header.maxInternalEntries = maxInternal;
header.minInternalEntries = (int)(maxInternal * 0.4);
assert( header.maxLeafEntries >= 2*header.minLeafEntries &&
header.minLeafEntries > 0 );
assert( header.maxInternalEntries >= 2*header.minInternalEntries &&
header.minInternalEntries > 0 );
// initialize overflowflag array
for( int i = 0; i < MAX_PATH_SIZE; i++ )
{
overflowFlag[ i ] = 0;
nodeId[ i ] = 0;
}
nodePtr = new R_TreeNode<dim, LeafInfo>( true,
MinEntries( 0 ),
MaxEntries( 0 ) );
// Creating a new page for the R-Tree header.
SmiRecord headerRecord;
int AppendedRecord =
file->AppendRecord( header.headerRecordId, headerRecord );
assert( AppendedRecord );
// Creating the root node.
SmiRecordId rootRecno;
SmiRecord rootRecord;
AppendedRecord = file->AppendRecord( rootRecno, rootRecord );
assert( AppendedRecord );
header.rootRecordId = path[ 0 ] = rootRecno;
header.nodeCount = 1;
nodePtr->Write( rootRecord );
currLevel = 0;
}
template <unsigned dim, class LeafInfo>
R_Tree<dim, LeafInfo>::R_Tree( const SmiFileId fileid , const bool isTemp) :
fileOwner( true ),
file( new SmiRecordFile( true,0,isTemp ) ),
header( 1 ),
nodePtr( NULL ),
currLevel( -1 ),
currEntry( -1 ),
reportLevel( -1 ),
searchBox( false ),
searchBoxSet(),
searchType( NoSearch ),
bulkMode(false),
bli(0),
nodeIdCounter( 0 )
{
// cout<<"111"<<endl;
file->Open( fileid );
// initialize overflowflag array
for( int i = 0; i < MAX_PATH_SIZE; i++ )
{
overflowFlag[ i ] = 0;
nodeId[ i ] = 0;
}
ReadHeader();
assert( header.maxLeafEntries >= 2*header.minLeafEntries &&
header.minLeafEntries > 0 );
assert( header.maxInternalEntries >= 2*header.minInternalEntries &&
header.minInternalEntries > 0 );
currLevel = 0;
// cout<<"header share"<<header.share<<endl;
if(header.share > 0) header.share++;
nodePtr = GetNode( RootRecordId(),
currLevel == Height(),
MinEntries( currLevel ),
MaxEntries( currLevel ) );
path[ 0 ] = header.rootRecordId;
}
template <unsigned dim, class LeafInfo>
R_Tree<dim, LeafInfo>::R_Tree( SmiRecordFile *file,
const SmiRecordId headerRecordId ) :
fileOwner( false ),
file( file ),
header( headerRecordId ),
nodePtr( NULL ),
currLevel( -1 ),
currEntry( -1 ),
reportLevel( -1 ),
searchBox( false ),
searchBoxSet(),
searchType( NoSearch ),
bulkMode(false),
bli(0),
nodeIdCounter( 0 )
{
// cout<<"222"<<endl;
// initialize overflowflag array
for( int i = 0; i < MAX_PATH_SIZE; i++ )
{
overflowFlag[ i ] = 0;
nodeId[ i ] = 0;
}
ReadHeader();
assert( header.maxLeafEntries >= 2*header.minLeafEntries &&
header.minLeafEntries > 0 );
assert( header.maxInternalEntries >= 2*header.minInternalEntries &&
header.minInternalEntries > 0 );
currLevel = 0;
nodePtr = GetNode( RootRecordId(),
currLevel == Height(),
MinEntries( currLevel ),
MaxEntries( currLevel ) );
path[ 0 ] = header.rootRecordId;
}
/*
Open an existing R-Tree file and create a new R-Tree on it
*/
template <unsigned dim, class LeafInfo>
R_Tree<dim, LeafInfo>::R_Tree( const SmiFileId fileid,const int pageSize,
const bool isTemp ) :
fileOwner( true ),
file( new SmiRecordFile( true,0,isTemp ) ),
header(),
nodePtr( NULL ),
currLevel( -1 ),
currEntry( -1 ),
reportLevel( -1 ),
searchBox( false ),
searchBoxSet(),
searchType( NoSearch ),
bulkMode(false),
bli(NULL),
nodeIdCounter( 0 )
{
// cout<<"333"<<endl;
file->Open(fileid);
// Calculating maxEntries e minEntries
int nodeEmptySize = R_TreeNode<dim, LeafInfo>::SizeOfEmptyNode();
int leafEntrySize = sizeof( R_TreeLeafEntry<dim, LeafInfo> ),
internalEntrySize = sizeof( R_TreeInternalEntry<dim> );
int maxLeaf = ( pageSize - nodeEmptySize ) / leafEntrySize,
maxInternal = ( pageSize - nodeEmptySize ) / internalEntrySize;
header.maxLeafEntries = maxLeaf;
header.minLeafEntries = (int)(maxLeaf * 0.4);
header.maxInternalEntries = maxInternal;
header.minInternalEntries = (int)(maxInternal * 0.4);
assert( header.maxLeafEntries >= 2*header.minLeafEntries &&
header.minLeafEntries > 0 );
assert( header.maxInternalEntries >= 2*header.minInternalEntries &&
header.minInternalEntries > 0 );
// initialize overflowflag array
for( int i = 0; i < MAX_PATH_SIZE; i++ )
{
overflowFlag[ i ] = 0;
nodeId[ i ] = 0;
}
nodePtr = new R_TreeNode<dim, LeafInfo>( true,
MinEntries( 0 ),
MaxEntries( 0 ) );
// Creating a new page for the R-Tree header.
SmiRecord headerRecord;
int AppendedRecord = file->AppendRecord( header.headerRecordId,
headerRecord );
assert( AppendedRecord );
// Creating the root node.
SmiRecordId rootRecno;
SmiRecord rootRecord;
AppendedRecord = file->AppendRecord( rootRecno, rootRecord );
assert( AppendedRecord );
header.rootRecordId = path[ 0 ] = rootRecno;
header.nodeCount = 1;
nodePtr->Write( rootRecord );
currLevel = 0;
}
template <unsigned dim, class LeafInfo>
R_Tree<dim, LeafInfo>::R_Tree( const SmiFileId fileid, bool update,
const bool isTemp ) :
fileOwner( true ),
file( new SmiRecordFile( true,0,isTemp ) ),
header(1),
nodePtr( NULL ),
currLevel( -1 ),
currEntry( -1 ),
reportLevel( -1 ),
searchBox( false ),
searchBoxSet(),
searchType( NoSearch ),
bulkMode(false),
bli(NULL),
nodeIdCounter( 0 )
{
// cout<<"444"<<endl;
file->Open( fileid );
// initialize overflowflag array
for( int i = 0; i < MAX_PATH_SIZE; i++ )
{
overflowFlag[ i ] = 0;
nodeId[ i ] = 0;
}
ReadHeader();
assert( header.maxLeafEntries >= 2*header.minLeafEntries &&
header.minLeafEntries > 0 );
assert( header.maxInternalEntries >= 2*header.minInternalEntries &&
header.minInternalEntries > 0 );
currLevel = 0;
nodePtr = GetNode( RootRecordId(),
currLevel == Height(),
MinEntries( currLevel ),
MaxEntries( currLevel ) );
path[ 0 ] = header.rootRecordId;
}
/*
5.2 The destructor
*/
template <unsigned dim, class LeafInfo>
R_Tree<dim, LeafInfo>::~R_Tree()
{
// cout<<"~R_Tree()"<<endl;
header.share--;
if( file->IsOpen() )
{
if( nodePtr != NULL )
PutNode( path[ currLevel ], &nodePtr );
WriteHeader();
if( fileOwner )
file->Close();
}
if(fileOwner)
{
delete file;
}
if(bli != NULL)
{
delete bli;
bli = NULL;
}
}
/*
5.3 Reading and writing the header
*/
template <unsigned dim, class LeafInfo>
void R_Tree<dim, LeafInfo>::ReadHeader()
{
SmiRecord record;
int RecordSelected =
file->SelectRecord( header.headerRecordId,
record,
SmiFile::ReadOnly );
assert( RecordSelected );
int RecordRead = record.Read( &header, sizeof( Header ), 0 )
== sizeof( Header );
assert( RecordRead );
}
template <unsigned dim, class LeafInfo>
void R_Tree<dim, LeafInfo>::WriteHeader()
{
SmiRecord record;
int RecordSelected =
file->SelectRecord( header.headerRecordId,
record,
SmiFile::Update );
assert( RecordSelected );
int RecordWritten =
record.Write( &header, sizeof( Header ), 0 ) == sizeof( Header );
assert( RecordWritten );
}
/*
5.4 Method PutNode: Putting node to disk
*/
template <unsigned dim, class LeafInfo>
void R_Tree<dim, LeafInfo>::PutNode( const SmiRecordId recno,
R_TreeNode<dim, LeafInfo> **node )
{
assert( file->IsOpen() );
(*node)->Write( file, recno );
delete *node;
*node = NULL;
}
template <unsigned dim, class LeafInfo>
void R_Tree<dim, LeafInfo>::PutNode( SmiRecord& record,
R_TreeNode<dim, LeafInfo> **node )
{
(*node)->Write( record );
delete *node;
*node = NULL;
}
/*
5.5 Method GetNode: Getting node from disk
*/
template <unsigned dim, class LeafInfo>
R_TreeNode<dim, LeafInfo> *R_Tree<dim, LeafInfo>::GetNode(
const SmiRecordId recno,
const bool leaf,
const int min,
const int max )
{
assert( file->IsOpen() );
R_TreeNode<dim, LeafInfo> *node =
new R_TreeNode<dim, LeafInfo>( leaf, min, max );
node->Read( file, recno );
return node;
}
template <unsigned dim, class LeafInfo>
R_TreeNode<dim, LeafInfo> *R_Tree<dim, LeafInfo>::GetNode(
SmiRecord& record,
const bool leaf,
const int min,
const int max )
{
R_TreeNode<dim, LeafInfo> *node =
new R_TreeNode<dim, LeafInfo>( leaf, min, max );
node->Read( record );
return node;
}
/*
5.6 Method BoundingBox
*/
template <unsigned dim, class LeafInfo>
BBox<dim> R_Tree<dim, LeafInfo>::BoundingBox()
// Returns the bounding box of this R_Tree
{
if( currLevel == 0 )
return nodePtr->BoundingBox();
else
{
R_TreeNode<dim, LeafInfo> *tmp =
GetNode( RootRecordId(),
0,
MinEntries(currLevel),
MaxEntries(currLevel) );
BBox<dim> result = tmp->BoundingBox();
delete tmp;
return result;
}
}
/*
5.7 Method Insert
*/
template <unsigned dim, class LeafInfo>
void R_Tree<dim,LeafInfo>::Insert(const R_TreeLeafEntry<dim,LeafInfo>& entry)
{
searchType = NoSearch;
LocateBestNode( entry, Height() );
InsertEntry( entry );
header.entryCount++;
}
/*
5.8 Method LocateBestNode
*/
template <unsigned dim, class LeafInfo>
void R_Tree<dim, LeafInfo>::LocateBestNode( const R_TreeEntry<dim>& entry,
int level )
{ GotoLevel( 0 );
// Top down search for a node of level 'level'
while( currLevel < level )
{
int bestNode = -1;
if( currLevel + 1 == Height() && minimize_leafnode_overlap )
{ // Best node is the one that gives minimum overlap. However,
// we should only take into consideration the k nodes that
// result in least enlargement, where k is given by
// leafnode_subset_max.
SortedArray enlargeList( MaxEntries(currLevel) + 1 );
int i, j, k;
for( i = 0; i < nodePtr->EntryCount(); i++ )
{
R_TreeEntry<dim> &son = (*nodePtr)[ i ];
enlargeList.push( i,
son.box.Union( entry.box ).Area() - son.box.Area() );
}
if( enlargeList.headPri() == 0.0 )
bestNode = enlargeList.pop();
// ...No need to do the overlap enlargement tests
else
{
double bestEnlargement = std::numeric_limits<double>::max(),
bestoverlap = std::numeric_limits<double>::max();
// Now compute the overlap enlargements
for( k = 0; !enlargeList.empty() && k < leafnode_subset_max; k++ )
{
double enlargement = enlargeList.headPri(),
overlapBefore = 0.0,
overlapAfter = 0.0,
overlap;
i = enlargeList.pop();
BBox<dim> boxBefore = (*nodePtr)[ i ].box;
BBox<dim> boxAfter = boxBefore.Union( entry.box );
for( j = 0; j < nodePtr->EntryCount(); ++j )
if( j == i )
continue;
else
{
R_TreeEntry<dim> &son = (*nodePtr)[ j ];
overlapBefore += boxBefore.Intersection( son.box ).Area();
overlapAfter += boxAfter.Intersection( son.box ).Area();
}
overlap = overlapAfter - overlapBefore;
if( overlap < bestoverlap ||
(overlap == bestoverlap && enlargement < bestEnlargement) )
{
bestoverlap = overlap;
bestEnlargement = enlargement;
bestNode = i;
}
}
}
}
else
{
double bestEnlargement = std::numeric_limits<double>::max();
int i;
for( i = 0; i < nodePtr->EntryCount(); i++ )
{
R_TreeEntry<dim> &son = (*nodePtr)[ i ];
double enlargement = son.box.Union( entry.box ).Area() - son.box.Area();
if( enlargement < bestEnlargement )
{
bestNode = i;
bestEnlargement = enlargement;
}
}
}
assert( bestNode != -1 );
DownLevel( bestNode );
}
}
/*
5.9 Method GotoLevel
*/
template <unsigned dim, class LeafInfo>
void R_Tree<dim, LeafInfo>::GotoLevel( int level )
{
if( currLevel == level )
{
if( nodePtr == NULL )
nodePtr = GetNode( path[ currLevel ],
Height() == level,
MinEntries(currLevel),
MaxEntries(currLevel) );
}
else
{
assert( level >= 0 && level <= Height() );
if( nodePtr != NULL )
PutNode( path[ currLevel ], &nodePtr );
currLevel = level;
nodePtr = GetNode( path[ currLevel ],
Height() == level,
MinEntries(currLevel),
MaxEntries(currLevel) );
}
}
/*
5.10 Method DownLevel
*/
template <unsigned dim, class LeafInfo>
void R_Tree<dim, LeafInfo>::DownLevel( int entryNo )
{
assert( currLevel != Height() );
assert( nodePtr != 0 );
assert( entryNo >= 0 && entryNo < nodePtr->EntryCount() );
pathEntry[ currLevel ] = entryNo;
path[ currLevel+1 ] =
((R_TreeInternalEntry<dim>&)(*nodePtr)[ entryNo ]).pointer;
PutNode( path[ currLevel ], &nodePtr );
currLevel += 1;
nodePtr = GetNode( path[ currLevel ],
Height() == currLevel,
MinEntries(currLevel),
MaxEntries(currLevel) );
}
/*
5.11 Method InsertEntry
*/
template <unsigned dim, class LeafInfo>
void R_Tree<dim, LeafInfo>::InsertEntry( const R_TreeEntry<dim>& entry )
{
assert( file->IsOpen() );
if( nodePtr->Insert( entry ) ){
UpdateBox();
} else {
if( !do_forced_reinsertion || currLevel == 0 ||
overflowFlag[ Height() - currLevel ] )
{ // Node splitting is necessary
R_TreeNode<dim, LeafInfo> *n1 =
new R_TreeNode<dim, LeafInfo>
(nodePtr->IsLeaf(), nodePtr->MinEntries(), nodePtr->MaxEntries());
R_TreeNode<dim, LeafInfo> *n2 =
new R_TreeNode<dim, LeafInfo>
(nodePtr->IsLeaf(), nodePtr->MinEntries(), nodePtr->MaxEntries() );
nodePtr->Split( *n1, *n2 );
// Write split nodes and update parent
if( currLevel == 0)
{ // splitting root node
nodePtr->Clear();
nodePtr->SetInternal( header.minInternalEntries,
header.maxInternalEntries );
BBox<dim> n1Box( n1->BoundingBox() );
SmiRecordId node1recno;
SmiRecord node1record;
int RecordAppended = file->AppendRecord( node1recno, node1record );
assert( RecordAppended );
PutNode( node1record, &n1 ); // deletes n1
int EntryInserted =
nodePtr->Insert( R_TreeInternalEntry<dim>(n1Box,node1recno));
assert(EntryInserted);
BBox<dim> n2Box( n2->BoundingBox() );
SmiRecordId node2recno;
SmiRecord node2record;
RecordAppended = file->AppendRecord( node2recno, node2record );
assert( RecordAppended );
PutNode( node2record, &n2 ); // deletes n2
EntryInserted =
nodePtr->Insert(R_TreeInternalEntry<dim>(n2Box,node2recno));
assert(EntryInserted);
header.height += 1;
header.nodeCount += 2;
}
else
{ // splitting non-root node
SmiRecordId newNoderecno;
SmiRecord newNoderecord;
int RecordAppended = file->AppendRecord( newNoderecno, newNoderecord );
assert( RecordAppended );
R_TreeInternalEntry<dim> newEntry( n2->BoundingBox(), newNoderecno );
PutNode( newNoderecord, &n2 ); // deletes n2
header.nodeCount++;
// Copy all entries from n1 to nodePtr
nodePtr->Clear();
*nodePtr = *n1;
delete n1;
UpdateBox();
UpLevel();
InsertEntry( newEntry );
}
}
else
{ // Do forced reinsertion instead of split
int reinsertLevel = Height() - currLevel;
// Avoid reinserting at this level
overflowFlag[ reinsertLevel ] = 1;
// Compute the center of the node
BBox<dim> nodeBox = nodePtr->BoundingBox();
double nodeCenter[ dim ];
for( unsigned i = 0; i < dim; i++ )
nodeCenter[ i ] = (nodeBox.MinD( i ) + nodeBox.MaxD( i ))/2;
// Make list sorted by distance from the center of each
// entry bounding box to the center of the bounding box
// of all entries.
// NOTE: We use CHESSBOARD metric for the distance
SortedArray distSort( MaxEntries(currLevel) + 1 );
for( int i = 0; i < nodePtr->EntryCount(); i++ )
{
double entryDistance = 0.0;
for( unsigned j = 0; j < dim; j++ )
{
double centerEntry = ((*nodePtr)[ i ].box.MinD( j ) +
(*nodePtr)[ i ].box.MaxD( j ))/2;
double dist = fabs( centerEntry - nodeCenter[ j ] );
if( dist > entryDistance )
entryDistance = dist;
}
distSort.push( i, entryDistance );
}
{ // Write node with the entries that will stay
int maxEntries = MaxEntries(currLevel),
minEntries = MinEntries(currLevel);
R_TreeEntry<dim> **tmp = new R_TreeEntry<dim>*[ maxEntries + 1 ];
int *keepFlag = new int[ maxEntries + 1 ];
bool leaf = nodePtr->IsLeaf();
int deleteCount, n = 0;
for( int i = 0; i <= maxEntries; i++ )
{
keepFlag[ i ] = 0;
tmp[i] = 0;
}
deleteCount = (forced_reinsertion_percent * maxEntries) / 100;
assert( maxEntries - deleteCount >= minEntries );
for( int i = maxEntries-deleteCount; i >= 0; i-- )
keepFlag[ distSort.pop() ] = 1;
for( int i = maxEntries; i >= 0; i-- )
if( !keepFlag[ i ] )
{
if( leaf )
tmp[ i ] = new R_TreeLeafEntry<dim, LeafInfo>
( (R_TreeLeafEntry<dim, LeafInfo>&)(*nodePtr)[ i ] );
else
tmp[ i ] = new R_TreeInternalEntry<dim>
( (R_TreeInternalEntry<dim>&)(*nodePtr)[ i ] );
n++;
nodePtr->Remove( i );
}
assert( n == deleteCount );
UpdateBox();
// Reinsert remaining entries( using "close reinsert" --
// see R*tree paper, pg 327)
while( !distSort.empty() )
{
int entryNo = distSort.pop();
R_TreeEntry<dim> *reinsertEntry = tmp[ entryNo ];
assert( !keepFlag[ entryNo ] );
LocateBestNode( *reinsertEntry, Height() - reinsertLevel );
InsertEntry( *reinsertEntry );
}
// Reset flag so that other insertion operations may cause the
// forced reinsertion process to take place
overflowFlag[ reinsertLevel ] = 0;
for( int i = 0; i <= maxEntries; i++ )
delete tmp[i];
delete [] tmp;
delete [] keepFlag;
}
}
}
}
/*
5.12 Method UpLevel
*/
template <unsigned dim, class LeafInfo>
void R_Tree<dim, LeafInfo>::UpLevel()
{
assert( currLevel > 0 );
if( nodePtr != NULL )
PutNode( path[ currLevel ], &nodePtr );
currLevel -= 1;
nodePtr = GetNode( path[ currLevel ],
Height() == currLevel,
MinEntries(currLevel),
MaxEntries(currLevel) );
}
/*
5.13 Method UpdateBox
*/
template <unsigned dim, class LeafInfo>
void R_Tree<dim, LeafInfo>::UpdateBox()
{
// Save where we were before
int formerlevel = currLevel;
for( int l = currLevel; l > 0; l-- )
{
// Compute bounding box of child
BBox<dim> box = nodePtr->BoundingBox();
// Update 'father' node
UpLevel();
nodePtr->UpdateBox( box, path[ l ] );
}
// Return to where we were before
GotoLevel( formerlevel );
}
/*
5.14 Method FindEntry
*/
template <unsigned dim, class LeafInfo>
bool R_Tree<dim, LeafInfo>::FindEntry(
const R_TreeLeafEntry<dim, LeafInfo>& entry )
{
// First see if the current entry is the one that is being sought,
// as is the case with many searches followed by Delete
if( currLevel == Height() &&
currEntry >= 0 && currEntry < nodePtr->EntryCount() &&
nodePtr != 0 &&
(*nodePtr)[ currEntry ].box == entry.box &&
((R_TreeLeafEntry<dim, LeafInfo>&)(*nodePtr)[ currEntry ]).info
== entry.info )
return true;
// Load root node
GotoLevel( 0 );
// Init search params
searchBox = entry.box;
currEntry = 0;
// Search the tree until no more subtrees are found in the root
while( currEntry < nodePtr->EntryCount() || currLevel > 0 )
{
if( currEntry >= nodePtr->EntryCount())
{ // All entries or subtrees of the current node were
// examined. Go up on the tree
UpLevel();
currEntry = pathEntry[ currLevel ];
currEntry++;
}
else // Try another subtree or entry
if( currLevel == Height() ) // This is a leaf node. Search all entries
while( currEntry < nodePtr->EntryCount() )
{
if( (*nodePtr)[ currEntry ].box == entry.box &&
((R_TreeLeafEntry<dim, LeafInfo>&)(*nodePtr)[ currEntry ]).
info == entry.info )
return true; // Found it
currEntry++;
}
else // This is an internal node. Search all subtrees
while( currEntry < nodePtr->EntryCount() )
if( (*nodePtr)[ currEntry ].box.Intersects( searchBox ) )
{ // Found a possible subtree. Go down
DownLevel( currEntry );
currEntry = 0;
break;
}
else
currEntry++;
// No subtree was found. Go up
}
// Entry Not found
return false;
}
/*
5.15 Method First
*/
template <unsigned dim, class LeafInfo>
bool R_Tree<dim, LeafInfo>::First( const BBox<dim>& box,
R_TreeLeafEntry<dim,
LeafInfo>& result,
int replevel )
{
// Remember that we have started a scan of the R_Tree
searchType = BoxSearch;
// Init search params
searchBox = box;
reportLevel = replevel;
// Load root node
GotoLevel( 0 );
// Finish with the actual search
currEntry = -1;
return Next( result );
}
template<unsigned dim, class LeafInfo>
bool R_Tree<dim, LeafInfo>::First( const BBoxSet<dim>& boxSet,
R_TreeLeafEntry<dim, LeafInfo>& result )
{
// Remember that we have started a scan of the R_Tree
searchType = BoxSetSearch;
// Init search params
searchBoxSet = boxSet;
// Load root node
GotoLevel( 0 );
// Finish with the actual search
currEntry = -1;
return Next( result );
}
/*
5.16 Method Next
*/
template <unsigned dim, class LeafInfo>
bool R_Tree<dim, LeafInfo>::Next( R_TreeLeafEntry<dim, LeafInfo>& result )
{
// Next can be called only after a 'First' or a 'Next' operation
assert( searchType != NoSearch );
bool retcode = false;
while( currEntry < nodePtr->EntryCount() || currLevel > 0 )
if( currEntry >= nodePtr->EntryCount())
{ // All entries in this node were examined. Go up the tree
// Find entry in father node corresponding to this node.
UpLevel();
assert( pathEntry[ currLevel ] < nodePtr->EntryCount() );
currEntry = pathEntry[ currLevel ];
}
else
{ // Search next entry / subtree in this node
currEntry++;
if( currEntry < nodePtr->EntryCount() )
{
if( searchType == BoxSearch ?
searchBox.Intersects( (*nodePtr)[ currEntry ].box ) :
searchBoxSet.Intersects( (*nodePtr)[ currEntry ].box ) )
{
if( nodePtr->IsLeaf() || currLevel == reportLevel)
{ // Found an appropriate entry
result = (R_TreeLeafEntry<dim, LeafInfo>&)(*nodePtr)[ currEntry ];
retcode = true;
break;
}
else
{ // Go down the tree
DownLevel( currEntry );
currEntry = -1;
}
}
}
}
return retcode;
}
/*
Variants of ~First~ and ~Next~ for introspection into the R-tree.
The complete r-tree will be iterated, but only all entries on replevel
will be returned, unless replevel == -1.
*/
template <unsigned dim, class LeafInfo>
bool R_Tree<dim, LeafInfo>::IntrospectFirst( IntrospectResult<dim>& result)
{
// create result for root
result = IntrospectResult<dim>
(
0,
0,
BoundingBox(),
-1,
nodePtr->IsLeaf(),
nodePtr->MinEntries(),
nodePtr->MaxEntries(),
nodePtr->EntryCount()
);
// Load root node
GotoLevel( 0 );
nodeIdCounter = 0;
nodeId[currLevel] = 0;
// Remember that we have started a scan of the R_Tree
searchType = BoxSearch;
currEntry = -1;
for(int i = 0; i < MAX_PATH_SIZE; i++)
{
pathEntry[i] = -1;
nodeId[i] = -1;
}
return true;
}
template <unsigned dim, class LeafInfo>
bool R_Tree<dim, LeafInfo>::IntrospectNextE(unsigned long& nodeid,BBox<dim>&
box,unsigned long& tupleid )
{
// Next can be called only after a 'IntrospectFirst'
// or a 'IntrospectNext' operation
assert( searchType == BoxSearch );
bool retcode = false;
pathEntry[currLevel]++;
// printf("pathEntry %d\n",pathEntry[currLevel]);
// printf("EntryCount() %d\n",nodePtr->EntryCount());
// printf("currLevel %d\n",currLevel);
while( pathEntry[currLevel] < nodePtr->EntryCount() || currLevel > 0 )
{
if( pathEntry[currLevel] >= nodePtr->EntryCount())
{ // All entries in this node were examined. Go up the tree
// Find entry in father node corresponding to this node.
nodeId[currLevel] = -1;
pathEntry[ currLevel ] = -1;
UpLevel();
assert( pathEntry[ currLevel ] < nodePtr->EntryCount() );
pathEntry[currLevel]++;
}
else
{ // Search next entry / subtree in this node
// pathEntry[currLevel]++;
if( nodeId[ currLevel ] < 0)
nodeId[ currLevel ] = nodeIdCounter;
if( pathEntry[currLevel] < nodePtr->EntryCount() )
{ // produce result
if( nodePtr->IsLeaf() )
{ // Found leaf node
// get complete node
// printf("leaf\n");
R_TreeLeafEntry<dim, LeafInfo> entry =
(R_TreeLeafEntry<dim, LeafInfo>&)
(*nodePtr)[ pathEntry[ currLevel ] ];
//
box = entry.box;
tupleid = entry.info;
nodeid = path[currLevel];
retcode = true;
break;
}
else // internal node
{ // Found internal node
// printf("internal node\n");
R_TreeInternalEntry<dim> entry =
(R_TreeInternalEntry<dim>&) (*nodePtr)[pathEntry[ currLevel]];
// printf("pathEntry currLevel %d, %d\n",currLevel,pathEntry[currLevel]);
DownLevel( pathEntry[currLevel] );
nodeId[currLevel] = ++nodeIdCounter; // set nodeId
// printf("pathEntry currLevel %d, %d\n",currLevel,pathEntry[currLevel]);
pathEntry[currLevel]++;
// pathEntry[currLevel] = -1; // reset for next iteration
} // end else
} //end if
} // end else
} // end while
// pathEntry[currLevel] += nodePtr->EntryCount();
return retcode;
}
template <unsigned dim, class LeafInfo>
bool R_Tree<dim, LeafInfo>::IntrospectNext( IntrospectResult<dim>& result )
{
// Next can be called only after a 'IntrospectFirst'
// or a 'IntrospectNext' operation
assert( searchType == BoxSearch );
bool retcode = false;
pathEntry[currLevel]++;
while( pathEntry[currLevel] < nodePtr->EntryCount() || currLevel > 0 )
{
if( pathEntry[currLevel] >= nodePtr->EntryCount())
{ // All entries in this node were examined. Go up the tree
// Find entry in father node corresponding to this node.
nodeId[currLevel] = -1;
pathEntry[ currLevel ] = -1;
UpLevel();
assert( pathEntry[ currLevel ] < nodePtr->EntryCount() );
pathEntry[currLevel]++;
}
else
{ // Search next entry / subtree in this node
// pathEntry[currLevel]++;
if( nodeId[ currLevel ] < 0)
nodeId[ currLevel ] = nodeIdCounter;
if( pathEntry[currLevel] < nodePtr->EntryCount() )
{ // produce result
if( nodePtr->IsLeaf() )
{ // Found leaf node
// get complete node
R_TreeLeafEntry<dim, LeafInfo> entry =
(R_TreeLeafEntry<dim, LeafInfo>&)
(*nodePtr)[ pathEntry[ currLevel ] ];
result = IntrospectResult<dim>
(
currLevel+1, // the entries shall have bigger levels
++nodeIdCounter, // and get their own node numbers
entry.box,
nodeId[currLevel],
true, // use some
1, // resonable standard
1, // values for
1 // these attributes
);
}
else // internal node
{ // Found internal node
DownLevel( pathEntry[currLevel] );
nodeId[currLevel] = ++nodeIdCounter; // set nodeId
R_TreeInternalEntry<dim> entry =
(R_TreeInternalEntry<dim>&) (*nodePtr)[ 0 ];
result = IntrospectResult<dim>
(
currLevel,
nodeIdCounter,
nodePtr->BoundingBox(),
nodeId[currLevel-1], // currLevel >= 1 (DownLevel)
nodePtr->IsLeaf(),
nodePtr->MinEntries(),
nodePtr->MaxEntries(),
nodePtr->EntryCount()
);
// pathEntry[currLevel] = -1; // reset for next iteration
} // end else
retcode = true;
break;
} //end if
} // end else
} // end while
return retcode;
}
/*
5.17 Method Remove
*/
template <unsigned dim, class LeafInfo>
bool R_Tree<dim, LeafInfo>::Remove( const R_TreeLeafEntry<dim,
LeafInfo>& entry )
{
assert( file->IsOpen() );
searchType = NoSearch;
// First locate the entry in the tree
if( !FindEntry( entry ) )
return false;
else
{ // Create a list of nodes whose entries must be reinserted
std::stack<int> reinsertLevelList;
std::stack<R_TreeNode<dim, LeafInfo>*> reinsertNodeList;
BBox<dim> sonBox( false );
// remove leaf node entry
nodePtr->Remove( currEntry );
header.entryCount -= 1;
while( currLevel > 0 )
{
int underflow = nodePtr->EntryCount() < MinEntries( currLevel );
if( underflow )
{ // Current node has underflow. Save it for later reinsertion
R_TreeNode<dim, LeafInfo>* nodePtrcopy = new R_TreeNode<dim, LeafInfo>
( *nodePtr );
reinsertNodeList.push( nodePtrcopy );
reinsertLevelList.push( currLevel );
// Remove node from the tree
nodePtr->Clear();
int RecordDeleted = file->DeleteRecord( path[ currLevel ] );
assert( RecordDeleted );
delete nodePtr; // destroy in memory node
nodePtr = 0; // avoid flushing node durcing UpLevel
}
else
sonBox = nodePtr->BoundingBox();
// Find entry corresponding to this node in father node
UpLevel();
currEntry = pathEntry[ currLevel ];
// Adjust father node
if( underflow ) // remove corresponding entry in father node
nodePtr->Remove( currEntry );
else // Adjust father node entry bounding box
(*nodePtr)[ currEntry ].box = sonBox;
}
// Reinsert entries in every node of reinsertNodeList
while( !reinsertNodeList.empty() )
{
R_TreeNode<dim, LeafInfo>* tmp = reinsertNodeList.top();
int level = reinsertLevelList.top(), i;
reinsertNodeList.pop();
reinsertLevelList.pop();
for( i = 0; i < tmp->EntryCount(); i++ )
{
assert( level <= Height() );
LocateBestNode( (*tmp)[ i ], level );
InsertEntry( (*tmp)[ i ] );
}
delete tmp;
}
// See if root node now has only one son
if( Height() == 0 ) // we are done
return true;
// Load root node
GotoLevel( 0 );
assert( !nodePtr->IsLeaf());
if( nodePtr->EntryCount() == 1 )
{ // root node has only one son
long newRoot = ((R_TreeInternalEntry<dim>&)(*nodePtr)[ 0 ]).pointer;
// Remove former root node from the tree
file->DeleteRecord( RootRecordId() );
delete nodePtr; nodePtr = NULL;
// Retrieve new root
header.rootRecordId = path[ 0 ] = newRoot;
GotoLevel( 0 );
// Tree has diminished in height()
header.height -= 1;
}
return true;
}
}
template <unsigned dim, class LeafInfo>
void R_Tree<dim, LeafInfo>::GetNeighborNode(const R_TreeLeafEntry<dim, LeafInfo>
& ent ,std::vector<int>& list)
{
if(FindEntry(ent)){
//currEntry,;
//R_TreeNode<dim,LeafInfo>* nodePtr;
if(nodePtr->IsLeaf()){
for(int i = 0;i < nodePtr->EntryCount();i++){
if(i != currEntry){
R_TreeLeafEntry<2,LeafInfo> *entry = nodePtr->GetLeafEntry(i);
list.push_back(entry->info);
}
}
}
}
}
/*
5.18 Method Root
*/
template <unsigned dim, class LeafInfo>
R_TreeLeafEntry<dim,LeafInfo>*
R_TreeNode<dim,LeafInfo>::GetLeafEntry(const int index) const
{
assert(index >= 0 && index <= maxEntries);
return (R_TreeLeafEntry<dim,LeafInfo>*)entries[index];
}
template <unsigned dim, class LeafInfo>
R_TreeInternalEntry<dim>*
R_TreeNode<dim,LeafInfo>::GetInternalEntry(const int index) const
{
assert(index >= 0 && index < count);
return (R_TreeInternalEntry<dim>*)entries[index];
}
template <unsigned dim, class LeafInfo>
R_TreeNode<dim, LeafInfo>& R_Tree<dim, LeafInfo>::Root()
// Loads nodeptr with the root node
{
GotoLevel( 0 );
return *nodePtr;
}
template <unsigned dim, class LeafInfo>
bool R_Tree<dim, LeafInfo>::InitializeBulkLoad(const bool &leafSkipping)
{
assert( NodeCount() == 1 );
if(bulkMode ||
bli != NULL)
{
return false;
}
bulkMode = true;
bli = new BulkLoadInfo<dim, LeafInfo>(leafSkipping);
return true;
};
template <unsigned dim, class LeafInfo>
void R_Tree<dim, LeafInfo>::InsertBulkLoad(const R_TreeEntry<dim>& entry)
{
if( bli->node[0] != NULL ) {
assert(bulkMode == true);
}
bli->currentLevel = 0;
if( bli->node[0] == NULL ) { // create a fresh leaf node
bli->node[0] = new R_TreeNode<dim,LeafInfo>(true,
header.minLeafEntries,
header.maxLeafEntries);
bli->nodeCount++;
}
InsertBulkLoad(bli->node[0], entry);
bli->entryCount++;
return;
}
template <unsigned dim, class LeafInfo>
void R_Tree<dim, LeafInfo>::InsertBulkLoad(R_TreeNode<dim, LeafInfo> *node,
const R_TreeEntry<dim>& entry)
{
assert( bulkMode == true );
assert( node != NULL );
if( !bli->levelLastBox[bli->currentLevel].IsDefined() ) {
// initialize when called for the first time
bli->levelLastBox[bli->currentLevel] = entry.box;
}
// trace the distance to the last entry inserted into this node:
double dist = entry.box.Distance(bli->levelLastBox[bli->currentLevel]);
bli->levelEntryCounter[bli->currentLevel]++;
bli->levelDistanceSum[bli->currentLevel] += dist;
bli->levelLastBox[bli->currentLevel] = entry.box;
// update average distance of all entries on this level
double avgDist = bli->levelDistanceSum[bli->currentLevel]
/ (MAX(bli->levelEntryCounter[bli->currentLevel],2) - 1);
// cout << "Level = " << bli->currentLevel << endl
// << " dist = " << dist
// << " avgDist = " << avgDist
// << " #Entries =" << bli->node[bli->currentLevel]->EntryCount()
// << "/" << bli->node[bli->currentLevel]->MaxEntries()
// << endl;
if( ( bli->node[bli->currentLevel]->EntryCount() <
bli->node[bli->currentLevel]->MaxEntries() // fits into node
)
&&
( !bli->skipLeaf // standard case
|| ( dist <= (avgDist * BULKLOAD_TOLERANCE) ) // distance OK
|| ( bli->node[bli->currentLevel]->EntryCount() <=
bli->node[bli->currentLevel]->MinEntries() *
BULKLOAD_MIN_ENTRIES_FACTOR ) // too few entries
|| ( bli->levelEntryCounter[bli->currentLevel] <=
BULKLOAD_INITIAL_SEQ_LENGTH)
)
)
{ // insert the entry into this (already existing) node
// cout << " --> Inserting here!" << endl;
bli->node[bli->currentLevel]->Insert(entry);
return;
} // else: node is already full (or distance to large)...
// cout << " --> Passing upwards..." << endl;
// Write node[currentLevel] to disk
// Request SMI for a fresh record (and its Id):
assert(file->IsOpen());
SmiRecordId recId;
SmiRecord rec;
bool RecordAppended = file->AppendRecord(recId, rec);
assert(RecordAppended);
// write the current node into the fresh record
bli->node[bli->currentLevel]->Write(file, recId);
// if no father node exists, create one
if( bli->node[bli->currentLevel+1] == NULL ) {
assert (bli->currentHeight == bli->currentLevel);
bli->currentHeight++; // increase height reached
bli->node[bli->currentLevel+1] =
new R_TreeNode<dim,LeafInfo>(false,
header.minInternalEntries,
header.maxInternalEntries);
bli->nodeCount++;
}
// change to father
bli->currentLevel++;
// Insert son into father (by recursive call)
InsertBulkLoad(
bli->node[bli->currentLevel],
R_TreeInternalEntry<dim>(
bli->node[bli->currentLevel-1]->BoundingBox(),
recId ) );
// delete node and create a new node instead
bli->currentLevel--; // change back to original level
delete bli->node[bli->currentLevel];
bli->node[bli->currentLevel] = NULL;
if(bli->currentLevel == 0) { // create a leaf node
bli->node[bli->currentLevel] =
new R_TreeNode<dim,LeafInfo>(true,
header.minLeafEntries,
header.maxLeafEntries);
} else { // create an internal node
bli->node[bli->currentLevel] =
new R_TreeNode<dim,LeafInfo>(false,
header.minInternalEntries,
header.maxInternalEntries);
}
bli->nodeCount++;
// finally, insert the original entry passed as argument
bli->node[bli->currentLevel]->Insert(entry);
return;
};
/*
Merge two rtrees which are stored in the same file
1) height1 > height2 insert second r-tree to the first
2) height1 = height2 create a new node and insert the two into it
3) height1 < height2 insert first r-tree to the second
*/
/*template <unsigned dim, class LeafInfo>
void R_Tree<dim, LeafInfo>::MergeRtree(R_Tree<dim,LeafInfo>* rtree_in1,
R_Tree<dim,LeafInfo>* rtree_in2)
{
//get root node of the second rtree
SmiRecordId adr2 = rtree_in2->RootRecordId();
R_TreeNode<dim,TupleId>* root2 = rtree_in2->GetMyNode(adr2,false,
MinEntries(0),MaxEntries(0));
R_TreeInternalEntry<dim> e2(root2->BoundingBox(),adr2);
delete root2;
//get root node of the first rtree
SmiRecord record1;
int RecordSelected =
file->SelectRecord(header.second_head_id,record1,SmiFile::ReadOnly);
assert(RecordSelected);
Header temp_head;
int RecordRead = record1.Read(&temp_head,sizeof(Header),0) == sizeof(Header);
assert(RecordRead);
SmiRecordId root1_id = temp_head.rootRecordId;
int tree1_node_count = temp_head.nodeCount;
int tree1_entry_count = temp_head.entryCount;
R_TreeNode<dim,TupleId>* insert_node;
//create an entry on the second root node
//first assume, the height of first rtree is higher than the second
// cout<<" height1 "<<temp_head.height<<" height2 "<<header.height<<endl;
if(temp_head.height > header.height){
int cur_height = temp_head.height;//height of first r-tree
vector<SmiRecordId> path;
SmiRecordId path_record_id = root1_id;
while(cur_height > header.height){
path.push_back(path_record_id);
insert_node = GetMyNode(path_record_id,false,
MinEntries(0),MaxEntries(0));
assert(insert_node->IsLeaf() == false);
int i = insert_node->EntryCount();
R_TreeInternalEntry<dim> e =
(R_TreeInternalEntry<dim>&)(*insert_node)[i-1];
path_record_id = e.pointer;
delete insert_node;
cur_height--;
}
//new height
header.height = temp_head.height;
assert(path.size() > 0);
int index = path.size()-1;
///////////////////////////////////////////////////////////////////
R_TreeNode<dim,TupleId>* update_path = new
R_TreeNode<dim,LeafInfo>(false,MinEntries(0),MaxEntries(0));
//the entries have to recalculate coverage number
//////////////////////////////////////////////////////////////////
// find where to insert and insert the root of second rtree
for(; index >= 0;index--){
R_TreeNode<dim,TupleId>* node = GetMyNode(path[index],false,
MinEntries(0),MaxEntries(0));
int i = node->EntryCount();
if(i < node->MaxEntries()){ //find the place to insert
// cout<<"before "<<node->BoundingBox()<<endl;
assert(node->Insert(e2));
node->UpdateBox(e2.box,e2.pointer);
header.entryCount++;
// cout<<"after "<<node->BoundingBox()<<endl;
//////////// replace entry for update parent node///////////
e2.box = node->BoundingBox();
e2.pointer = path[index];
update_path->Insert(e2); //recored new coverage id
///////////////////////////////////////////////////////////
PutNode(path[index],&node);
delete node;
break;
}else{ //node is full
delete node;
node = new
R_TreeNode<dim,LeafInfo>(false,MinEntries(0),MaxEntries(0));
SmiRecordId new_node_rec_id;
SmiRecord new_node_rec;
int AppendRecord = file->AppendRecord(new_node_rec_id,new_node_rec);
assert(AppendRecord);
e2.pointer = new_node_rec_id;
node->Insert(e2);
node->UpdateBox(e2.box,e2.pointer);
node->Write(new_node_rec);
header.nodeCount++;
update_path->Insert(e2); //recored new coverage id
delete node;
}
}
//update parent node
index--;
while(index >= 0){
R_TreeNode<dim,TupleId>* node = GetMyNode(path[index],false,
MinEntries(0),MaxEntries(0));
node->UpdateBox(e2.box,e2.pointer);
PutNode(path[index],&node);
e2.box = node->BoundingBox();
e2.pointer = path[index];
update_path->Insert(e2); //recored new coverage id
delete node;
}
///////////////////////////////////////////////////////
SmiRecordId path_rec_id;
SmiRecord path_rec;
int append = file->AppendRecord(path_rec_id,path_rec);
assert(append);
update_path->Write(path_rec);
delete update_path;
//update header
header.entryCount += tree1_entry_count;
header.nodeCount += tree1_node_count;
header.rootRecordId = root1_id;
header.path_rec_id = path_rec_id;
WriteHeader();
}else if(temp_head.height == header.height){
/// create a new node and insert the two root nodes as entries//////
R_TreeNode<dim,TupleId>* node = new
R_TreeNode<dim,LeafInfo>(false,MinEntries(0),MaxEntries(0));
SmiRecordId new_node_rec_id;
SmiRecord new_node_rec;
int AppendRecord = file->AppendRecord(new_node_rec_id,new_node_rec);
assert(AppendRecord);
R_TreeNode<dim,TupleId>* root1 = rtree_in1->GetMyNode(root1_id,false,
MinEntries(0),MaxEntries(0));
R_TreeInternalEntry<dim> e1(root1->BoundingBox(),root1_id);
delete root1;
//update new node
node->Insert(e1);
node->UpdateBox(e1.box,e1.pointer);
node->Insert(e2);
node->UpdateBox(e2.box,e2.pointer);
////////////////how to insert e1 and e2 into new root//////////////
cout<<"the same height"<<endl;
//////////////////////////////////////////////////////////////////
node->Write(new_node_rec);
BBox<3> bbox = node->BoundingBox();
delete node;
//////////// record update path ///////////////
R_TreeNode<dim,TupleId>* update_path = new
R_TreeNode<dim,LeafInfo>(false,MinEntries(0),MaxEntries(0));
R_TreeInternalEntry<dim> e3(bbox,new_node_rec_id);
update_path->Insert(e3);
SmiRecordId path_rec_id;
SmiRecord path_rec;
AppendRecord = file->AppendRecord(path_rec_id,path_rec);
assert(AppendRecord);
update_path->Write(path_rec);
delete update_path;
///////////update header///////////////////////
// cout<<"node count "<<header.nodeCount<<
// " entry count "<< header.entryCount<<endl;
header.nodeCount++;
header.entryCount += 2;
header.entryCount += tree1_entry_count;
header.nodeCount += tree1_node_count;
header.rootRecordId = new_node_rec_id;
header.height++;
////////////
header.path_rec_id = path_rec_id;
////////////
WriteHeader();
}else{ //height1 < height
///////// insert the first r-tree to the second r-tree /////////////
int cur_height = header.height;//height of first r-tree
vector<SmiRecordId> path;
SmiRecordId path_record_id = adr2;
while(cur_height > temp_head.height){
path.push_back(path_record_id);
insert_node = GetMyNode(path_record_id,false,
MinEntries(0),MaxEntries(0));
assert(insert_node->IsLeaf() == false);
R_TreeInternalEntry<dim> e =
(R_TreeInternalEntry<dim>&)(*insert_node)[0];
path_record_id = e.pointer;
delete insert_node;
cur_height--;
}
assert(path.size() > 0);
///////////////////////////////////////////////////////////////////
R_TreeNode<dim,TupleId>* update_path = new
R_TreeNode<dim,LeafInfo>(false,MinEntries(0),MaxEntries(0));
//the entries have to recalculate coverage number
///////////////////////////////////////////////////////////////////
int index = path.size()-1;
// find where to insert and insert the root of second rtree
for(; index >= 0;index--){
R_TreeNode<dim,TupleId>* node = GetMyNode(path[index],false,
MinEntries(0),MaxEntries(0));
int i = node->EntryCount();
if(i < node->MaxEntries()){ //find the place to insert
R_TreeNode<dim,TupleId>* node_copy = new
R_TreeNode<dim,LeafInfo>(false,MinEntries(0),MaxEntries(0));
// cout<<"before "<<node_copy->BoundingBox()<<endl;
////// insert the first r-tree ahead //
assert(node_copy->Insert(e2));
node_copy->UpdateBox(e2.box,e2.pointer);
header.entryCount++;
///////////copy the original entry ////
for(int j = 0;j < i;j++){
R_TreeInternalEntry<dim> e =
(R_TreeInternalEntry<dim>&)(*node)[j];
assert(node_copy->Insert(e));
node_copy->UpdateBox(e.box,e.pointer);
}
// cout<<"after "<<node_copy->BoundingBox()<<endl;
delete node;
//////////// replace entry for update parent node///////////
e2.box = node_copy->BoundingBox();
e2.pointer = path[index];
update_path->Insert(e2); //recored new coverage id
///////////////////////////////////////////////////////////
PutNode(path[index],&node_copy);
delete node_copy;
break;
}else{ //node is full
delete node;
node = new
R_TreeNode<dim,LeafInfo>(false,MinEntries(0),MaxEntries(0));
SmiRecordId new_node_rec_id;
SmiRecord new_node_rec;
int AppendRecord = file->AppendRecord(new_node_rec_id,new_node_rec);
assert(AppendRecord);
e2.pointer = new_node_rec_id;
node->Insert(e2);
node->UpdateBox(e2.box,e2.pointer);
node->Write(new_node_rec);
header.nodeCount++;
update_path->Insert(e2); //recored new coverage id
delete node;
}
}
//update parent node
index--;
while(index >= 0){
R_TreeNode<dim,TupleId>* node = GetMyNode(path[index],false,
MinEntries(0),MaxEntries(0));
node->UpdateBox(e2.box,e2.pointer);
PutNode(path[index],&node);
e2.box = node->BoundingBox();
e2.pointer = path[index];
update_path->Insert(e2); //recored new coverage id
delete node;
}
/////////////////////////////////////////////////////////
SmiRecordId path_rec_id;
SmiRecord path_rec;
int append = file->AppendRecord(path_rec_id,path_rec);
assert(append);
update_path->Write(path_rec);
delete update_path;
//update header
header.entryCount += tree1_entry_count;
header.nodeCount += tree1_node_count;
header.rootRecordId = adr2;
header.path_rec_id = path_rec_id;
WriteHeader();
}
}*/
template <unsigned dim, class LeafInfo>
void R_Tree<dim, LeafInfo>::MergeRtree()
{
//get root node of the second rtree
SmiRecordId adr2 = RootRecordId();
R_TreeNode<dim,TupleId>* root2 = GetMyNode(adr2,false,
MinEntries(0),MaxEntries(0));
R_TreeInternalEntry<dim> e2(root2->BoundingBox(),adr2);
delete root2;
//get root node of the first rtree
SmiRecord record1;
int RecordSelected =
file->SelectRecord(header.second_head_id,record1,SmiFile::ReadOnly);
assert(RecordSelected);
Header temp_head;
int RecordRead = record1.Read(&temp_head,sizeof(Header),0) == sizeof(Header);
assert(RecordRead);
SmiRecordId root1_id = temp_head.rootRecordId;
R_TreeNode<dim,TupleId>* root1 = GetMyNode(root1_id,false,
MinEntries(0),MaxEntries(0));
R_TreeInternalEntry<dim> e1(root1->BoundingBox(),root1_id);
delete root1;
int tree1_node_count = temp_head.nodeCount;
int tree1_entry_count = temp_head.entryCount;
R_TreeNode<dim,TupleId>* insert_node;
//create an entry on the second root node
//first assume, the height of first rtree is higher than the second
// cout<<" height1 "<<temp_head.height<<" height2 "<<header.height<<endl;
if(temp_head.height > header.height){
int cur_height = temp_head.height;//height of first r-tree
std::vector<SmiRecordId> path;
SmiRecordId path_record_id = root1_id;
while(cur_height > header.height){
path.push_back(path_record_id);
insert_node = GetMyNode(path_record_id,false,
MinEntries(0),MaxEntries(0));
assert(insert_node->IsLeaf() == false);
int i = insert_node->EntryCount();
R_TreeInternalEntry<dim> e =
(R_TreeInternalEntry<dim>&)(*insert_node)[i-1];
path_record_id = e.pointer;
delete insert_node;
cur_height--;
}
//new height
header.height = temp_head.height;
assert(path.size() > 0);
int index = path.size()-1;
/* int temp_index = index;
while(temp_index >= 0){
cout<<"path[temp_index] "<<path[temp_index]<<endl;
temp_index--;
}*/
///////////////////////////////////////////////////////////////////
R_TreeNode<dim,TupleId>* update_path = new
R_TreeNode<dim,LeafInfo>(false,MinEntries(0),MaxEntries(0));
//the entries have to recalculate coverage number
//////////////////////////////////////////////////////////////////
// find where to insert and insert the root of second rtree
for(; index >= 0;index--){
R_TreeNode<dim,TupleId>* node = GetMyNode(path[index],false,
MinEntries(0),MaxEntries(0));
int i = node->EntryCount();
if(i < node->MaxEntries()){ //find the place to insert
// cout<<"before "<<node->BoundingBox()<<endl;
assert(node->Insert(e2));
node->UpdateBox(e2.box,e2.pointer);
header.entryCount++;
// cout<<"after "<<node->BoundingBox()<<endl;
//////////// replace entry for update parent node///////////
e2.box = node->BoundingBox();
e2.pointer = path[index];
update_path->Insert(e2); //record new coverage id
///////////////////////////////////////////////////////////
PutNode(path[index],&node);
delete node;
break;
}else{ //node is full
delete node;
node = new
R_TreeNode<dim,LeafInfo>(false,MinEntries(0),MaxEntries(0));
SmiRecordId new_node_rec_id;
SmiRecord new_node_rec;
int AppendRecord = file->AppendRecord(new_node_rec_id,new_node_rec);
assert(AppendRecord);
e2.pointer = new_node_rec_id;
node->Insert(e2);
node->UpdateBox(e2.box,e2.pointer);
node->Write(new_node_rec);
header.nodeCount++;
update_path->Insert(e2); //record new coverage id
delete node;
}
}
//update parent node
index--;
while(index >= 0){
// cout<<"index "<<path[index]<<" e2 "<<e2.pointer<<endl;
// cout<<"path[index] "<<path[index]<<endl;
R_TreeNode<dim,TupleId>* node = GetMyNode(path[index],false,
MinEntries(0),MaxEntries(0));
node->UpdateBox(e2.box,e2.pointer);
// cout<<node->BoundingBox()<<endl;
e2.box = node->BoundingBox();
e2.pointer = path[index];
update_path->Insert(e2); //record new coverage id
PutNode(path[index],&node);
delete node;
index--;
}
///////////////////////////////////////////////////////
SmiRecordId path_rec_id;
SmiRecord path_rec;
int append = file->AppendRecord(path_rec_id,path_rec);
assert(append);
update_path->Write(path_rec);
delete update_path;
//update header
header.entryCount += tree1_entry_count;
header.nodeCount += tree1_node_count;
header.rootRecordId = root1_id;
header.path_rec_id = path_rec_id;
header.share = 2;
WriteHeader();
}else if(temp_head.height == header.height){
/// create a new node and insert the two root nodes as entries//////
R_TreeNode<dim,TupleId>* node = new
R_TreeNode<dim,LeafInfo>(false,MinEntries(0),MaxEntries(0));
SmiRecordId new_node_rec_id;
SmiRecord* new_node_rec = new SmiRecord();
int AppendRecord = file->AppendRecord(new_node_rec_id,*new_node_rec);
assert(AppendRecord);
///////////////////////////////////////////////////////////////
R_TreeNode<dim,TupleId>* n1 = GetMyNode(e1.pointer,false,
MinEntries(0),MaxEntries(0));
R_TreeNode<dim,TupleId>* n2 = GetMyNode(e2.pointer,false,
MinEntries(0),MaxEntries(0));
// cout<<" n1 entry "<<n1->EntryCount()
// <<" n2 entry "<<n2->EntryCount()<<endl;
if(n1->EntryCount() >= MinEntries(0) &&
n2->EntryCount() >= MinEntries(0)){
// cout<<"11"<<endl;
node->Insert(e1);
node->UpdateBox(e1.box,e1.pointer);
node->Insert(e2);
node->UpdateBox(e2.box,e2.pointer);
delete n1;
delete n2;
header.entryCount += 2;
}else if((n1->EntryCount() + n2->EntryCount())
< node->MaxEntries()){
// cout<<"222"<<endl;
for(int i = 0;i < n2->EntryCount();i++){
R_TreeInternalEntry<dim> e =
(R_TreeInternalEntry<dim>&)(*n2)[i];
n1->Insert(e);
n1->UpdateBox(e.box, e.pointer);
}
R_TreeInternalEntry<dim> e3(n1->BoundingBox(),e1.pointer);
PutNode(e1.pointer, &n1);
node->Insert(e3);
node->UpdateBox(e3.box,e3.pointer);
delete n2;
header.entryCount += 1;
}else if(n1->EntryCount() > n2->EntryCount()){
// cout<<"333"<<endl;
int deviation = MinEntries(0) - n2->EntryCount();
assert(deviation > 0);
assert(n1->EntryCount() - deviation > n1->MinEntries());
R_TreeNode<dim,TupleId>* n3 =
new R_TreeNode<dim,LeafInfo>
(false, MinEntries(0),MaxEntries(0));
for(int i = n1->EntryCount() - deviation;
i < n1->EntryCount();i++){
R_TreeInternalEntry<dim> e =
(R_TreeInternalEntry<dim>&)(*n1)[i];
n3->Insert(e);
n3->UpdateBox(e.box, e.pointer);
}
//////////////////////////////////////////
R_TreeNode<dim,TupleId>* n4 =
new R_TreeNode<dim,LeafInfo>
(false, MinEntries(0),MaxEntries(0));
for(int i = 0; i < deviation;i++){
R_TreeInternalEntry<dim> e =
(R_TreeInternalEntry<dim>&)(*n1)[i];
n4->Insert(e);
n4->UpdateBox(e.box, e.pointer);
}
R_TreeInternalEntry<dim> e3(n4->BoundingBox(),e1.pointer);
PutNode(e1.pointer,&n4);
node->Insert(e3);
node->UpdateBox(e3.box, e3.pointer);
/////////////////////////////////////////////
for(int i = 0;i < n2->EntryCount();i++){
R_TreeInternalEntry<dim> e =
(R_TreeInternalEntry<dim>&)(*n2)[i];
n3->Insert(e);
n3->UpdateBox(e.box, e.pointer);
}
R_TreeInternalEntry<dim> e4(n3->BoundingBox(),e2.pointer);
PutNode(e2.pointer,&n3);
node->Insert(e4);
node->UpdateBox(e4.box, e4.pointer);
delete n1;
delete n2;
header.entryCount += 2;
}else if(n2->EntryCount() > n1->EntryCount()){
// cout<<"44"<<endl;
int deviation = MinEntries(0) - n1->EntryCount();
assert(deviation > 0);
assert(n2->EntryCount() - deviation > n2->MinEntries());
for(int i = 0; i < deviation;i++){
R_TreeInternalEntry<dim> e =
(R_TreeInternalEntry<dim>&)(*n2)[i];
n1->Insert(e);
n1->UpdateBox(e.box, e.pointer);
}
R_TreeNode<dim,TupleId>* n3 =
new R_TreeNode<dim,LeafInfo>
(false, MinEntries(0),MaxEntries(0));
for(int i = deviation; i < n2->EntryCount();i++){
R_TreeInternalEntry<dim> e =
(R_TreeInternalEntry<dim>&)(*n2)[i];
n3->Insert(e);
n3->UpdateBox(e.box, e.pointer);
}
PutNode(e1.pointer,&n1);
node->Insert(e1);
node->UpdateBox(e1.box,e1.pointer);
R_TreeInternalEntry<dim> e3(n3->BoundingBox(),e2.pointer);
PutNode(e2.pointer,&n3);
node->Insert(e3);
node->UpdateBox(e3.box,e3.pointer);
header.entryCount += 2;
}else assert(false);
////////////////////////////////////////////////////////////
//update new node
/* node->Insert(e1);
node->UpdateBox(e1.box,e1.pointer);
node->Insert(e2);
node->UpdateBox(e2.box,e2.pointer);*/
BBox<3> bbox = node->BoundingBox();
PutNode(*new_node_rec,&node);
// nodePtr->Insert(R_TreeInternalEntry<dim>(bbox,new_node_rec_id));
delete new_node_rec;
delete node;
//////////// record update path ///////////////
R_TreeNode<dim,TupleId>* update_path = new
R_TreeNode<dim,LeafInfo>(false,MinEntries(0),MaxEntries(0));
R_TreeInternalEntry<dim> e3(bbox, new_node_rec_id);
update_path->Insert(e3);
SmiRecordId path_rec_id;
SmiRecord path_rec;
AppendRecord = file->AppendRecord(path_rec_id, path_rec);
assert(AppendRecord);
update_path->Write(path_rec);
delete update_path;
///////////update header///////////////////////
// cout<<"node count "<<header.nodeCount<<
// " entry count "<< header.entryCount<<endl;
header.nodeCount++;
// header.entryCount += 2;
header.entryCount += tree1_entry_count;
header.nodeCount += tree1_node_count;
header.rootRecordId = new_node_rec_id;
header.height++;
////////////
header.path_rec_id = path_rec_id;
/////////////
path[0] = new_node_rec_id;
header.share = 2;
WriteHeader();
// cout<<"header "<<header.headerRecordId<<"root id "<<RootRecordId()<<endl;
/* ReadHeader();
nodePtr = GetNode(RootRecordId(),false,MinEntries(0),MaxEntries(0));
path[0] = header.rootRecordId;*/
// PutNode(RootRecordId(),&nodePtr);
}else{ //height1 < height2
///////// insert the first r-tree to the second r-tree /////////////
int cur_height = header.height;//height of second r-tree
std::vector<SmiRecordId> path;
SmiRecordId path_record_id = adr2;
while(cur_height > temp_head.height){
path.push_back(path_record_id);
insert_node = GetMyNode(path_record_id,false,
MinEntries(0),MaxEntries(0));
assert(insert_node->IsLeaf() == false);
R_TreeInternalEntry<dim> e =
(R_TreeInternalEntry<dim>&)(*insert_node)[0];
path_record_id = e.pointer;
delete insert_node;
cur_height--;
}
assert(path.size() > 0);
///////////////////////////////////////////////////////////////////
R_TreeNode<dim,TupleId>* update_path = new
R_TreeNode<dim,LeafInfo>(false,MinEntries(0),MaxEntries(0));
//the entries have to recalculate coverage number
///////////////////////////////////////////////////////////////////
int index = path.size()-1;
// find where to insert and insert the root of second rtree
for(; index >= 0;index--){
R_TreeNode<dim,TupleId>* node = GetMyNode(path[index],false,
MinEntries(0),MaxEntries(0));
int i = node->EntryCount();
if(i < node->MaxEntries()){ //find the place to insert
R_TreeNode<dim,TupleId>* node_copy = new
R_TreeNode<dim,LeafInfo>(false,MinEntries(0),MaxEntries(0));
// cout<<"before "<<node_copy->BoundingBox()<<endl;
////// insert the first r-tree ahead //
assert(node_copy->Insert(e1));
node_copy->UpdateBox(e1.box,e1.pointer);
header.entryCount++;
///////////copy the original entry ////
for(int j = 0;j < i;j++){
R_TreeInternalEntry<dim> e =
(R_TreeInternalEntry<dim>&)(*node)[j];
assert(node_copy->Insert(e));
node_copy->UpdateBox(e.box,e.pointer);
}
// cout<<"after "<<node_copy->BoundingBox()<<endl;
delete node;
//////////// replace entry for update parent node///////////
e1.box = node_copy->BoundingBox();
e1.pointer = path[index];
update_path->Insert(e1); //recored new coverage id
///////////////////////////////////////////////////////////
PutNode(path[index],&node_copy);
delete node_copy;
break;
}else{ //node is full
delete node;
node = new
R_TreeNode<dim,LeafInfo>(false,MinEntries(0),MaxEntries(0));
SmiRecordId new_node_rec_id;
SmiRecord new_node_rec;
int AppendRecord = file->AppendRecord(new_node_rec_id,new_node_rec);
assert(AppendRecord);
e1.pointer = new_node_rec_id;
node->Insert(e1);
node->UpdateBox(e1.box,e1.pointer);
node->Write(new_node_rec);
header.nodeCount++;
update_path->Insert(e1); //recored new coverage id
delete node;
}
}
//update parent node
index--;
while(index >= 0){
R_TreeNode<dim,TupleId>* node = GetMyNode(path[index],false,
MinEntries(0),MaxEntries(0));
node->UpdateBox(e1.box,e1.pointer);
e1.box = node->BoundingBox();
e1.pointer = path[index];
update_path->Insert(e1); //record new coverage id
PutNode(path[index],&node);
delete node;
index--;
}
/////////////////////////////////////////////////////////
SmiRecordId path_rec_id;
SmiRecord path_rec;
int append = file->AppendRecord(path_rec_id,path_rec);
assert(append);
update_path->Write(path_rec);
delete update_path;
//update header
header.entryCount += tree1_entry_count;
header.nodeCount += tree1_node_count;
header.rootRecordId = adr2;
header.path_rec_id = path_rec_id;
header.share = 2;
// cout<<"write path_rec_id "<<header.path_rec_id<<endl;
WriteHeader();
// ReadHeader();
// cout<<"read path_rec_id "<<header.path_rec_id<<endl;
}
}
/*
Switch the header content of the first and second R-tree
afterwards, query R-tree will open the second rtree
but there is a record in the header of the first rtree pointing to the second
rtree, so that reverse operator is still valid
*/
template <unsigned dim, class LeafInfo>
void R_Tree<dim, LeafInfo>::SwitchHeader(R_Tree<dim,LeafInfo>* rtree_in)
{
SmiRecord record1;
int RecordSelected =
file->SelectRecord(rtree_in->HeaderRecordId(),record1,SmiFile::ReadOnly);
assert(RecordSelected);
Header temp_head;
int RecordRead = record1.Read(&temp_head,sizeof(Header),0) == sizeof(Header);
assert(RecordRead);
file->SelectRecord(rtree_in->HeaderRecordId(),record1,SmiFile::Update);
assert(RecordSelected);
//write second head into the file (recno-1)
SmiRecordId sec_head_id = HeaderRecordId();
header.second_head_id = sec_head_id;
header.headerRecordId = 1;
int RecordWrite = record1.Write(&header,sizeof(Header),0) == sizeof(Header);
assert(RecordWrite);
//write first head into the file
SmiRecord record2;
RecordSelected =
file->SelectRecord(header.second_head_id,record2,SmiFile::Update);
assert(RecordSelected);
temp_head.headerRecordId = sec_head_id;
temp_head.second_head_id = 1;
RecordWrite = record2.Write(&temp_head,sizeof(Header),0) == sizeof(Header);
assert(RecordWrite);
}
/*
DF traverse R-Tree, get new RecordId
Recursively calling
1) write the leaf node into file
2) when all entries of a node have been written to the file,
the (parent) node is written into the file (a record)
3) repeat this process unitl root node
*/
template <unsigned dim, class LeafInfo>
SmiRecordId R_Tree<dim, LeafInfo>::
DFVisit_Rtree(R_Tree<dim,LeafInfo>* rtree_in,R_TreeNode<dim,LeafInfo>* node)
{
if(node->IsLeaf()){
SmiRecordId recordid;
SmiRecord record;
int AppendRecord =
file->AppendRecord(recordid,record);
assert(AppendRecord);
node->SetModified();
node->Write(record);
return recordid;
}else{
R_TreeNode<dim,LeafInfo>* new_n =
new R_TreeNode<dim,LeafInfo>(node->IsLeaf(),MinEntries(0),MaxEntries(0));
for(int i = 0;i < node->EntryCount();i++){
R_TreeInternalEntry<dim> e =
(R_TreeInternalEntry<dim>&)(*node)[i];
R_TreeNode<dim,LeafInfo>* n = rtree_in->GetMyNode(
e.pointer,false,rtree_in->MinEntries(0),rtree_in->MaxEntries(0));
SmiRecordId recid;
recid = DFVisit_Rtree(rtree_in,n);
new_n->Insert(R_TreeInternalEntry<dim>(e.box,recid));
delete n;
}
SmiRecordId recordid;
SmiRecord record;
int AppendRecord =
file->AppendRecord(recordid,record);
assert(AppendRecord);
new_n->SetModified();
new_n->Write(record);
delete new_n;
return recordid;
}
}
/*
Copy an R-Tree, 1) Using BulkLoad 2) DF Traversal
The key issue is for different files, the recordId is different and can't be
controled (which is returned by berkeleydb library function)
*/
template <unsigned dim, class LeafInfo>
void R_Tree<dim, LeafInfo>::Clone(R_Tree<dim,LeafInfo>* rtree_in)
{
/* assert(InitializeBulkLoad());
BBox<dim> searchbox(rtree_in->BoundingBox());
R_TreeLeafEntry<dim,LeafInfo> e;
if(rtree_in->First(searchbox,e)){
InsertBulkLoad(e);
while(rtree_in->Next(e)){
InsertBulkLoad(e);
}
}
assert(FinalizeBulkLoad());*/
////////////////////// root /////////////////////////////
SmiRecordId root_id = rtree_in->RootRecordId();
R_TreeNode<dim,LeafInfo>* rootnode = rtree_in->GetMyNode(
root_id,false,rtree_in->MinEntries(0),rtree_in->MaxEntries(0));
root_id = DFVisit_Rtree(rtree_in,rootnode);
header.nodeCount = rtree_in->NodeCount();
header.entryCount = rtree_in->EntryCount();
header.height = rtree_in->Height();
header.rootRecordId = root_id;
delete rootnode;
}
template <unsigned dim, class LeafInfo>
bool R_Tree<dim, LeafInfo>::FinalizeBulkLoad()
{
if ( bulkMode != true ) {
return false;
}
// write all nodes to disk and delete them from memory
// the array bli->node[i] contains all nodes, that need to be flushed outputs
// onto disk. This is done bottom-up (starting at the leaf-level): Each node
// is written to disk and then inserted into the node one level above.
// During insertion, ancestor nodes may be changed, written to disk or being
// replaced by other nodes.
bool finished = false;
for(int i=0; i < MAX_PATH_SIZE; i++) { // level == 0 means the leaf level
if( !finished
&& i <= bli->currentHeight
&& bli->node[i] != NULL) { // need to write the node
// request SMI for a fresh record
assert(file->IsOpen());
SmiRecordId recId;
SmiRecord rec;
int RecordAppended = file->AppendRecord(recId, rec);
assert(RecordAppended);
// write current node to that record
bli->node[i]->Write(rec);
if( i < bli->currentHeight ) { // Insert a non-root node into its father
assert( i+1 <= bli->currentHeight );
assert( bli->node[i+1] != NULL );
if(i == 0) {// leaf level
assert( bli->node[i]->IsLeaf() == true );
} else { // inner level
assert( bli->node[i]->IsLeaf() == false );
// create an entry for this node to insert into the father
}
// create an entry for this node to insert into the father
R_TreeInternalEntry<dim> entry( bli->node[i]->BoundingBox(),
recId );
bli->currentLevel = i+1;
InsertBulkLoad(bli->node[i+1],entry);
} else {// ( i == bli->currentHeight): replace the root node
assert( i == bli->currentHeight );
// Verify, that the current rtree is empty:
assert( NodeCount() == 1 );
assert( EntryCount() == 0 );
SmiRecordId newRootId = recId;
// Remove old root node from the tree
file->DeleteRecord( RootRecordId() );
delete nodePtr;
nodePtr = NULL;
currLevel = 0;
currEntry = -1;
reportLevel = -1;
searchBox.SetDefined(false);
searchType = NoSearch;
// Set new root to topmost node from bulkloading
header.nodeCount = bli->nodeCount;
header.entryCount = bli->entryCount;
header.height = bli->currentHeight;
header.rootRecordId = newRootId;
path[ 0 ] = newRootId;
WriteHeader();
finished = true;
}
}
// ALWAYS: delete the current node from memory
if( bli->node[i] != NULL ) {
delete bli->node[i];
bli->node[i] = NULL;
}
} // end for
delete bli;
bli = NULL;
if(!finished){
// happens if no things are do do above
WriteHeader();
}
// re-initialize the rtree
ReadHeader();
assert( header.maxLeafEntries >= 2*header.minLeafEntries &&
header.minLeafEntries > 0 );
assert( header.maxInternalEntries >= 2*header.minInternalEntries &&
header.minInternalEntries > 0 );
currLevel = 0;
//assert(nodePtr==0);
nodePtr = GetNode( RootRecordId(),
currLevel == Height(),
MinEntries( currLevel ),
MaxEntries( currLevel ) );
path[ 0 ] = header.rootRecordId;
return true;
};
template <unsigned dim, class LeafInfo>
bool R_Tree<dim, LeafInfo>::getFileStats( SmiStatResultType &result )
{
result = file->GetFileStatistics(SMI_STATS_EAGER);
std::stringstream fileid;
fileid << file->GetFileId();
result.push_back(std::pair<std::string,std::string>("FilePurpose",
"SecondaryRtreeIndexFile"));
result.push_back(std::pair<std::string,std::string>("FileId",fileid.str()));
return true;
}
/*
6 Template functions for the type constructors
6.1 ~Out~-function
It does not make sense to have an R-Tree as an independent value
since the record ids stored in it become obsolete as soon as
the underlying relation is deleted. Therefore this function
outputs will show only some statistics about the tree.
*/
template <unsigned dim>
ListExpr OutRTree(ListExpr typeInfo, Word value)
{
if( nl->BoolValue(nl->Fourth(typeInfo)) == true )
{
ListExpr bboxList, appendList;
R_Tree<dim, TwoLayerLeafInfo> *rtree =
(R_Tree<dim, TwoLayerLeafInfo> *)value.addr;
bboxList = nl->OneElemList(
nl->RealAtom( rtree->BoundingBox().MinD( 0 ) ));
appendList = bboxList;
appendList = nl->Append(appendList,
nl->RealAtom( rtree->BoundingBox().MaxD( 0 ) ));
for( unsigned i = 1; i < dim; i++)
{
appendList = nl->Append(appendList,
nl->RealAtom( rtree->BoundingBox().MinD( i ) ));
appendList = nl->Append(appendList,
nl->RealAtom( rtree->BoundingBox().MaxD( i ) ));
}
return nl->FiveElemList(
nl->StringAtom( "R-Tree statistics" ),
nl->TwoElemList( nl->StringAtom( "Height" ),
nl->IntAtom( rtree->Height() ) ),
nl->TwoElemList( nl->StringAtom( "# of (leaf) entries" ),
nl->IntAtom( rtree->EntryCount() ) ),
nl->TwoElemList( nl->StringAtom( "# of nodes" ),
nl->IntAtom( rtree->NodeCount() ) ),
nl->TwoElemList( nl->StringAtom( "Bounding Box" ), bboxList ) );
}
else
{
ListExpr bboxList, appendList;
R_Tree<dim, TupleId> *rtree = (R_Tree<dim, TupleId> *)value.addr;
bboxList = nl->OneElemList(
nl->RealAtom( rtree->BoundingBox().MinD( 0 ) ));
appendList = bboxList;
appendList = nl->Append(appendList,
nl->RealAtom( rtree->BoundingBox().MaxD( 0 ) ));
for( unsigned i = 1; i < dim; i++)
{
appendList = nl->Append(appendList,
nl->RealAtom( rtree->BoundingBox().MinD( i ) ));
appendList = nl->Append(appendList,
nl->RealAtom( rtree->BoundingBox().MaxD( i ) ));
}
return nl->FiveElemList(
nl->StringAtom( "R-Tree statistics" ),
nl->TwoElemList( nl->StringAtom( "Height" ),
nl->IntAtom( rtree->Height() ) ),
nl->TwoElemList( nl->StringAtom( "# of (leaf) entries" ),
nl->IntAtom( rtree->EntryCount() ) ),
nl->TwoElemList( nl->StringAtom( "# of nodes" ),
nl->IntAtom( rtree->NodeCount() ) ),
nl->TwoElemList( nl->StringAtom( "Bounding Box" ), bboxList ) );
}
}
/*
6.2 ~In~-function
Reading an R-Tree from a list does not make sense because an R-Tree
is not an independent value. Therefore calling this function leads
to program abort.
*/
template <unsigned dim>
Word InRTree( ListExpr typeInfo, ListExpr value,
int errorPos, ListExpr& errorInfo, bool& correct )
{
correct = false;
return SetWord(Address(0));
}
/*
6.3 ~Create~-function
*/
template <unsigned dim>
Word CreateRTree( const ListExpr typeInfo )
{
if( nl->BoolValue(nl->Fourth(typeInfo)) == true )
return SetWord( new R_Tree<dim, TwoLayerLeafInfo>( 4000, false) );
else
return SetWord( new R_Tree<dim, TupleId>( 4000, false ));
}
/*
6.4 ~Close~-function
*/
template <unsigned dim>
void CloseRTree( const ListExpr typeInfo, Word& w )
{
if( nl->BoolValue(nl->Fourth(typeInfo)) == true )
{
R_Tree<dim, TwoLayerLeafInfo>* rtree = (R_Tree<dim,
TwoLayerLeafInfo>*)w.addr;
delete rtree;
}
else
{
R_Tree<dim, TupleId>* rtree = (R_Tree<dim, TupleId>*)w.addr;
delete rtree;
}
}
/*
6.5 ~Clone~-function
Not implemented yet.
implemented by Jianqiu xu --- 2009.11.30
*/
template <unsigned dim>
Word CloneRTree( const ListExpr typeInfo, const Word& w )
{
/////////////// new implementation ////////////////////////////
R_Tree<dim,TupleId>* rtree = (R_Tree<dim,TupleId>*)w.addr;
R_Tree<dim,TupleId>* newrtree =
new R_Tree<dim,TupleId>(4000, false);
newrtree->Clone(rtree);
return SetWord( newrtree);
//////////////// original version ////////////////////////////////////////
// return SetWord( Address(0) );
}
/*
6.6 ~Delete~-function
*/
template <unsigned dim>
void DeleteRTree( const ListExpr typeInfo, Word& w )
{
if (nl->ListLength(typeInfo) == 4)
{
if( nl->BoolValue(nl->Fourth(typeInfo)) == true )
{
R_Tree<dim, TwoLayerLeafInfo>* rtree = (R_Tree<dim,
TwoLayerLeafInfo>*)w.addr;
/* rtree->DeleteFile();
delete rtree;*/
// cout<<"DeleteRTree1 "<<rtree->GetShare()<<endl;
if(rtree->GetShare() > 0){
rtree->DecreaseShare();
rtree->CloseFile();
}else{
rtree->DeleteFile();
delete rtree;
}
return;
}
}
R_Tree<dim, TupleId>* rtree = (R_Tree<dim, TupleId>*)w.addr;
/* rtree->DeleteFile();
delete rtree;*/
// cout<<"DeleteRTree2 "<<rtree->GetShare()<<endl;
if(rtree->GetShare() > 0){
rtree->DecreaseShare();
rtree->CloseFile();
}else{
rtree->DeleteFile();
delete rtree;
}
}
/*
6.7 ~Cast~-function
*/
template <unsigned dim>
void* CastRTree( void* addr)
{
return ( 0 );
}
/*
6.8 ~Open~-function
*/
template <unsigned dim>
bool OpenRTree( SmiRecord& valueRecord,
size_t& offset,
const ListExpr typeInfo,
Word& value )
{
SmiFileId fileid;
valueRecord.Read( &fileid, sizeof( SmiFileId ), offset );
offset += sizeof( SmiFileId );
if( nl->BoolValue(nl->Fourth(typeInfo)) == true )
{
R_Tree<dim, TwoLayerLeafInfo> *rtree =
new R_Tree<dim, TwoLayerLeafInfo>( fileid, false );
value = SetWord( rtree );
}
else
{
R_Tree<dim, TupleId> *rtree = new R_Tree<dim, TupleId>( fileid, false );
value = SetWord( rtree );
}
return true;
}
/*
6.9 ~Save~-function
*/
template <unsigned dim>
bool SaveRTree( SmiRecord& valueRecord,
size_t& offset,
const ListExpr typeInfo,
Word& value )
{
SmiFileId fileId;
if( nl->BoolValue(nl->Fourth(typeInfo)) == true )
{
R_Tree<dim, TwoLayerLeafInfo> *rtree =
(R_Tree<dim, TwoLayerLeafInfo> *)value.addr;
fileId = rtree->FileId();
}
else
{
assert(value.addr);
R_Tree<dim, TupleId> *rtree = (R_Tree<dim, TupleId> *)value.addr;
fileId = rtree->FileId();
}
valueRecord.Write( &fileId, sizeof( SmiFileId ), offset );
offset += sizeof( SmiFileId );
return true;
}
/*
6.10 ~SizeOf~-function
*/
template <unsigned dim>
int SizeOfRTree()
{
return sizeof(SmiFileId);
}
template<unsigned dim>
struct RTreeNodesLocalInfo {
bool firstCall;
bool finished;
TupleType *resultTupleType;
R_Tree<dim, TupleId> *rtree;
};
template <unsigned dim, class LeafInfo>
bool R_Tree<dim, LeafInfo>::Open(SmiRecord& valueRecord,
size_t& offset,
std::string typeInfo,
Word &value)
{
SmiFileId fileId;
size_t n = sizeof(SmiFileId);
valueRecord.Read(&fileId, n, offset);
offset += n;
value = SetWord(new R_Tree<dim, LeafInfo> (fileId,false));
return true;
};
template <unsigned dim, class LeafInfo>
bool R_Tree<dim, LeafInfo>::Save(SmiRecord& valueRecord,
size_t& offset)
{
const size_t n=sizeof(SmiFileId);
SmiFileId fileId= this->FileId();
if (valueRecord.Write(&fileId, n, offset) != n) return false;
offset += n;
return true;
};
template <unsigned dim, class LeafInfo>
bool R_Tree<dim,LeafInfo>::InitializeBLI(const bool& leafSkipping)
{
if(bulkMode)
{
cout << "bulkMode" << endl;
}
if(bli != NULL)
{
cout << "bli" << endl;
delete bli;
bli = NULL;
}
// if(bulkMode || bli != NULL)
// return false;
bulkMode = true;
bli = new BulkLoadInfo<dim,LeafInfo>(leafSkipping);
return true;
}
typedef R_Tree<1, TupleId> RTree1TID;
typedef R_Tree<2, TupleId> RTree2TID;
typedef R_Tree<3, TupleId> RTree3TID;
typedef R_Tree<4, TupleId> RTree4TID;
typedef R_Tree<8, TupleId> RTree8TID;
typedef R_Tree<1, TwoLayerLeafInfo> RTree1TLLI;
typedef R_Tree<2, TwoLayerLeafInfo> RTree2TLLI;
typedef R_Tree<3, TwoLayerLeafInfo> RTree3TLLI;
typedef R_Tree<4, TwoLayerLeafInfo> RTree4TLLI;
typedef R_Tree<8, TwoLayerLeafInfo> RTree8TLLI;
#endif