2172 lines
50 KiB
C
2172 lines
50 KiB
C
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Implementation of the trajectory bundle tree.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
#ifndef TBTREE_H
|
||
|
|
#define TBTREE_H
|
||
|
|
|
||
|
|
#include "Algebras/TupleIdentifier/TupleIdentifier.h"
|
||
|
|
#include "Algebras/Rectangle/RectangleAlgebra.h"
|
||
|
|
#include "SecondoSMI.h"
|
||
|
|
#include "Algebras/Temporal/TemporalAlgebra.h"
|
||
|
|
#include "NestedList.h"
|
||
|
|
#include "ListUtils.h"
|
||
|
|
#include <cassert>
|
||
|
|
#include <vector>
|
||
|
|
#include <iostream>
|
||
|
|
|
||
|
|
namespace tbtree{
|
||
|
|
|
||
|
|
|
||
|
|
bool CheckTBTree(ListExpr type, ListExpr& ErrorInfo);
|
||
|
|
|
||
|
|
/*
|
||
|
|
1 Class LeafInfo
|
||
|
|
|
||
|
|
This class contains the information of an leaf entry in the tree.
|
||
|
|
|
||
|
|
*/
|
||
|
|
class TBLeafInfo{
|
||
|
|
public:
|
||
|
|
|
||
|
|
/*
|
||
|
|
~Constructors~
|
||
|
|
|
||
|
|
*/
|
||
|
|
TBLeafInfo():tid(0){}
|
||
|
|
TBLeafInfo(const TupleId& id): tid(id) {}
|
||
|
|
TBLeafInfo(const TBLeafInfo& li): tid(li.tid) {}
|
||
|
|
/*
|
||
|
|
~ Assignment operator~
|
||
|
|
|
||
|
|
*/
|
||
|
|
TBLeafInfo& operator=(const TBLeafInfo& li){
|
||
|
|
this->tid = li.tid;
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool operator==(const TBLeafInfo& li) const{
|
||
|
|
return (this->tid == li.tid);
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
~ Destructor~
|
||
|
|
|
||
|
|
*/
|
||
|
|
~TBLeafInfo() {}
|
||
|
|
|
||
|
|
/*
|
||
|
|
~Getter~
|
||
|
|
|
||
|
|
*/
|
||
|
|
inline TupleId getTupleId() const{
|
||
|
|
return tid;
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
Writing into a buffer.
|
||
|
|
|
||
|
|
*/
|
||
|
|
inline void writeTo(char* buffer,unsigned int& offset) const{
|
||
|
|
memcpy(buffer+offset, &tid, sizeof(TupleId));
|
||
|
|
offset += sizeof(TupleId);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
Reading from a buffer.
|
||
|
|
|
||
|
|
|
||
|
|
*/
|
||
|
|
inline void readFrom(const char* buffer, unsigned int& offset) {
|
||
|
|
memcpy(&tid, buffer+offset, sizeof(TupleId));
|
||
|
|
offset += sizeof(TupleId);
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
Size required for a buffer.
|
||
|
|
|
||
|
|
*/
|
||
|
|
static int bufferSize() {
|
||
|
|
return sizeof(TupleId);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
prints out this object
|
||
|
|
|
||
|
|
*/
|
||
|
|
std::ostream& print(std::ostream& os){
|
||
|
|
return os << tid ;
|
||
|
|
}
|
||
|
|
|
||
|
|
private:
|
||
|
|
TupleId tid;
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
2 class InnerInfo
|
||
|
|
|
||
|
|
This class contains the information of an entry of an inner node in the tree.
|
||
|
|
|
||
|
|
*/
|
||
|
|
class InnerInfo{
|
||
|
|
public:
|
||
|
|
/*
|
||
|
|
Constructors
|
||
|
|
|
||
|
|
*/
|
||
|
|
InnerInfo(): pointer(0){}
|
||
|
|
InnerInfo(const SmiRecordId& p): pointer(p) {}
|
||
|
|
InnerInfo(const InnerInfo& ii): pointer(ii.pointer) {}
|
||
|
|
|
||
|
|
/*
|
||
|
|
Assignment operator
|
||
|
|
|
||
|
|
*/
|
||
|
|
InnerInfo& operator=(const InnerInfo& ii){
|
||
|
|
pointer = ii.pointer;
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
|
||
|
|
inline bool operator==(const InnerInfo& ii) const{
|
||
|
|
return this->pointer == ii.pointer;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
Destructor
|
||
|
|
|
||
|
|
*/
|
||
|
|
~InnerInfo(){}
|
||
|
|
|
||
|
|
/*
|
||
|
|
Getter
|
||
|
|
|
||
|
|
*/
|
||
|
|
inline SmiRecordId getPointer() const{
|
||
|
|
return pointer;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
Writing into a buffer.
|
||
|
|
|
||
|
|
*/
|
||
|
|
inline void writeTo(char* buffer, unsigned int& offset) const{
|
||
|
|
memcpy(buffer + offset, &pointer, sizeof(SmiRecordId));
|
||
|
|
offset += sizeof(SmiRecordId);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
Reading from a buffer.
|
||
|
|
|
||
|
|
*/
|
||
|
|
inline void readFrom(const char* buffer,unsigned int& offset) {
|
||
|
|
memcpy(&pointer, buffer + offset, sizeof(SmiRecordId));
|
||
|
|
offset += sizeof(SmiRecordId);
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
Required buffersize to store it.
|
||
|
|
|
||
|
|
*/
|
||
|
|
static int bufferSize() {
|
||
|
|
return sizeof(SmiRecordId);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
prints out the pointer
|
||
|
|
|
||
|
|
*/
|
||
|
|
std::ostream& print(std::ostream& os){
|
||
|
|
return os << pointer;
|
||
|
|
}
|
||
|
|
|
||
|
|
private:
|
||
|
|
SmiRecordId pointer;
|
||
|
|
};
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
Function copying a defined rectangle into a buffer
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<int Dim>
|
||
|
|
inline void writeRectangle(const Rectangle<Dim>& r,
|
||
|
|
char* buffer,
|
||
|
|
unsigned int& offset){
|
||
|
|
assert(r.IsDefined());
|
||
|
|
for(int i = 0; i< Dim; i++){
|
||
|
|
double d = r.MinD(i);
|
||
|
|
memcpy(buffer+offset, &d, sizeof(double));
|
||
|
|
offset += sizeof(double);
|
||
|
|
d = r.MaxD(i);
|
||
|
|
memcpy(buffer+offset, &d, sizeof(double));
|
||
|
|
offset += sizeof(double);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
Function reading a rectangle from a buffer
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<int Dim>
|
||
|
|
inline void readRectangle(Rectangle<Dim>& r,
|
||
|
|
const char* buffer,
|
||
|
|
unsigned int& offset){
|
||
|
|
double mi[Dim];
|
||
|
|
double ma[Dim];
|
||
|
|
double d;
|
||
|
|
for(int i = 0; i< Dim; i++){
|
||
|
|
memcpy(&d, buffer+offset, sizeof(double));
|
||
|
|
offset += sizeof(double);
|
||
|
|
mi[i] = d;
|
||
|
|
memcpy(&d, buffer+offset, sizeof(double));
|
||
|
|
offset += sizeof(double);
|
||
|
|
ma[i] = d;
|
||
|
|
}
|
||
|
|
r.Set(true, mi, ma);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
Size required to store a rectangle.
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<int Dim>
|
||
|
|
inline int rectBufferSize(){
|
||
|
|
return 2 * Dim * sizeof(double);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
3 Class Entry
|
||
|
|
|
||
|
|
This class realized an entry within the tree. It should be
|
||
|
|
intantiated with InnerInfo or LeafInfo.
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<int Dim, class Info>
|
||
|
|
class Entry{
|
||
|
|
public:
|
||
|
|
/*
|
||
|
|
Constructors
|
||
|
|
|
||
|
|
*/
|
||
|
|
Entry() {}
|
||
|
|
Entry(const Rectangle<Dim>& b,const Info& i): box(b), info(i) {}
|
||
|
|
Entry(const Entry<Dim, Info>& src): box(src.box), info(src.info) {}
|
||
|
|
/*
|
||
|
|
Assignment operator
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
Entry<Dim, Info>& operator=(const Entry<Dim, Info>& e){
|
||
|
|
this->box = e.box;
|
||
|
|
this->info = e.info;
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
|
||
|
|
inline bool operator==(const Entry<Dim, Info>& e) const{
|
||
|
|
return (this->box == e.box) && (this->info==e.info);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
Destructor
|
||
|
|
|
||
|
|
*/
|
||
|
|
~Entry() {}
|
||
|
|
|
||
|
|
/*
|
||
|
|
Getter
|
||
|
|
|
||
|
|
*/
|
||
|
|
inline const Rectangle<Dim> getBox() const{
|
||
|
|
return box;
|
||
|
|
}
|
||
|
|
|
||
|
|
inline const Info& getInfo() const{
|
||
|
|
return info;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
Writing into a buffer
|
||
|
|
|
||
|
|
*/
|
||
|
|
inline void writeTo(char* buffer, unsigned int& offset) const{
|
||
|
|
writeRectangle<Dim>(box, buffer, offset);
|
||
|
|
info.writeTo(buffer, offset);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
Reading from a buffer
|
||
|
|
|
||
|
|
*/
|
||
|
|
inline void readFrom(const char* buffer,unsigned int& offset) {
|
||
|
|
readRectangle<Dim>(box, buffer, offset);
|
||
|
|
info.readFrom(buffer, offset);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
Required BufferSize
|
||
|
|
|
||
|
|
*/
|
||
|
|
inline static int bufferSize(){
|
||
|
|
return rectBufferSize<Dim>() + Info::bufferSize();
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
Let the box be the union of the original box and b;
|
||
|
|
|
||
|
|
*/
|
||
|
|
inline void addBox(const Rectangle<Dim>& b){
|
||
|
|
box = box.Union(b);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
Prints entry to stream;
|
||
|
|
|
||
|
|
*/
|
||
|
|
std::ostream& print(std::ostream& os){
|
||
|
|
os << "(";
|
||
|
|
box.Print(os);
|
||
|
|
os << ", ";
|
||
|
|
info.print(os);
|
||
|
|
os << ")";
|
||
|
|
return os;
|
||
|
|
}
|
||
|
|
|
||
|
|
private:
|
||
|
|
Rectangle<Dim> box;
|
||
|
|
Info info;
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
class BasicNode
|
||
|
|
|
||
|
|
This is the super class for all types of nodes.
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<unsigned Dim>
|
||
|
|
class BasicNode{
|
||
|
|
public:
|
||
|
|
|
||
|
|
/*
|
||
|
|
1 Constructors
|
||
|
|
|
||
|
|
*/
|
||
|
|
BasicNode(uint16_t min1, uint16_t max1):
|
||
|
|
min(min1), max(max1), current(0) {}
|
||
|
|
BasicNode(const BasicNode<Dim>& src):
|
||
|
|
min(src.min), max(src.max), current(src.current) {}
|
||
|
|
/*
|
||
|
|
2 Assignment operator
|
||
|
|
|
||
|
|
*/
|
||
|
|
BasicNode<Dim>& operator=(const BasicNode<Dim>& src){
|
||
|
|
this->min = src.min;
|
||
|
|
this->max = src.max;
|
||
|
|
this->current = src.current;
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
3 Comparison
|
||
|
|
|
||
|
|
*/
|
||
|
|
inline bool operator==(const BasicNode<Dim>& bn) const{
|
||
|
|
return this->min == bn.min &&
|
||
|
|
this->max == bn.max &&
|
||
|
|
this->current == bn.current;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
4 some pure virtual functions.
|
||
|
|
|
||
|
|
*/
|
||
|
|
virtual ~BasicNode() {}
|
||
|
|
|
||
|
|
virtual void writeTo(char* buffer, unsigned int& offset) const = 0;
|
||
|
|
virtual void readFrom(const char* buffer,unsigned int& offset) = 0;
|
||
|
|
virtual Rectangle<Dim> getBox() const = 0;
|
||
|
|
virtual const bool isLeaf()const = 0;
|
||
|
|
virtual int bufferSize() const =0;
|
||
|
|
virtual std::ostream& print(std::ostream& os ) const=0;
|
||
|
|
virtual BasicNode<Dim>* clone() const=0;
|
||
|
|
|
||
|
|
/*
|
||
|
|
5 some Getter
|
||
|
|
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
uint16_t entryCount() const{
|
||
|
|
return current;
|
||
|
|
}
|
||
|
|
|
||
|
|
inline uint16_t getMin() const{
|
||
|
|
return min;
|
||
|
|
}
|
||
|
|
|
||
|
|
inline virtual uint16_t getMax() const{
|
||
|
|
return max;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
protected:
|
||
|
|
uint16_t min; // minimum entrycount
|
||
|
|
uint16_t max; // maximum entrycount
|
||
|
|
uint16_t current; // current entrycount
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
4 Class Node
|
||
|
|
|
||
|
|
This is the super class of inner nodes and leaf nodes.
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<unsigned Dim, class Info>
|
||
|
|
class Node : public BasicNode<Dim>{
|
||
|
|
public:
|
||
|
|
/*
|
||
|
|
4.1 Constructors
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
Node(int min1, int max1): BasicNode<Dim>(min1,max1){
|
||
|
|
entries = new Entry<Dim, Info>*[BasicNode<Dim>::max +1];
|
||
|
|
for(int i=0;i<BasicNode<Dim>::max+1; i++){
|
||
|
|
entries[i] = 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
Node(const Node<Dim, Info>& src) : BasicNode<Dim>(src){
|
||
|
|
entries = new Entry<Dim,Info>*[BasicNode<Dim>::max +1];
|
||
|
|
for(int i=0;i< src.entryCount(); i++){
|
||
|
|
this->entries[i] = new Entry<Dim, Info>(*(src.entries[i]));
|
||
|
|
}
|
||
|
|
for(int i=src.entryCount(); i<BasicNode<Dim>::max; i++){
|
||
|
|
this->entries[i] = 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
4.2 Assignment operator
|
||
|
|
|
||
|
|
*/
|
||
|
|
Node& operator=(const Node<Dim, Info>& src) {
|
||
|
|
// first, delete all included entries
|
||
|
|
for(int i=0; i< BasicNode<Dim>::current; i++){
|
||
|
|
delete entries[i];
|
||
|
|
entries[i] = 0;
|
||
|
|
}
|
||
|
|
// if the size is different, adopt it
|
||
|
|
if(BasicNode<Dim>::max!=src.max){
|
||
|
|
delete[] entries;
|
||
|
|
entries = new Entry<Dim, Info>*[src.max+1];
|
||
|
|
}
|
||
|
|
BasicNode<Dim>::operator=(src);
|
||
|
|
for(int i=0;i< BasicNode<Dim>::current; i++){
|
||
|
|
entries[i] = new Entry<Dim, Info>(*(src.entries[i]));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
4.3 Comparision
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
bool operator==(const Node<Dim, Info>& n) const{
|
||
|
|
if(! (BasicNode<Dim>::operator==(n))){
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
for(int i=0;i<BasicNode<Dim>::current; i++){
|
||
|
|
if(!( *(this->entries[i]) == *(n.entries[i]))){
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
4.4 Destructor
|
||
|
|
|
||
|
|
*/
|
||
|
|
virtual ~Node(){
|
||
|
|
for(int i=0;i<BasicNode<Dim>::current;i++){
|
||
|
|
delete entries[i];
|
||
|
|
}
|
||
|
|
BasicNode<Dim>::current = 0;
|
||
|
|
delete[] entries;
|
||
|
|
entries = 0;
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
4.5 ~deleteEntries~
|
||
|
|
|
||
|
|
Removes all entries from this node.
|
||
|
|
|
||
|
|
*/
|
||
|
|
inline void deleteEntries() {
|
||
|
|
for(int i=0;i<BasicNode<Dim>::current;i++){
|
||
|
|
delete entries[i];
|
||
|
|
}
|
||
|
|
BasicNode<Dim>::current = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
4.6 ~getEntry~
|
||
|
|
|
||
|
|
Returns the entry at the given position.
|
||
|
|
|
||
|
|
*/
|
||
|
|
inline const Entry<Dim, Info>* getEntry(int index) const{
|
||
|
|
assert(index<BasicNode<Dim>::current);
|
||
|
|
return entries[index];
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
4.7 ~getBox~
|
||
|
|
|
||
|
|
Returns the union of all boxes of all entries.
|
||
|
|
|
||
|
|
*/
|
||
|
|
inline virtual Rectangle<Dim> getBox() const{
|
||
|
|
if(BasicNode<Dim>::current==0){
|
||
|
|
Rectangle<Dim> r(false);
|
||
|
|
return r;
|
||
|
|
} else {
|
||
|
|
Rectangle<Dim> res(entries[0]->getBox());
|
||
|
|
for(int i=1; i< BasicNode<Dim>::current; i++){
|
||
|
|
res = res.Union(entries[i]->getBox());
|
||
|
|
}
|
||
|
|
return res;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
4.8 ~writeTo~
|
||
|
|
|
||
|
|
Writes this node to an existing buffer.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
inline virtual void writeTo(char* buffer, unsigned int& offset) const{
|
||
|
|
uint16_t c = BasicNode<Dim>::current;
|
||
|
|
memcpy(buffer+offset, &c, sizeof(uint16_t));
|
||
|
|
offset += sizeof(uint16_t);
|
||
|
|
for(int i=0; i< BasicNode<Dim>::current; i++){
|
||
|
|
entries[i]->writeTo(buffer, offset);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
4.9 ~readFrom~
|
||
|
|
|
||
|
|
Reconstructs the node from a buffer.
|
||
|
|
|
||
|
|
*/
|
||
|
|
inline virtual void readFrom(const char* buffer,unsigned int& offset){
|
||
|
|
// delete old entries
|
||
|
|
for(int i=0;i<BasicNode<Dim>::current; i++){
|
||
|
|
delete entries[i];
|
||
|
|
entries[i] = 0;
|
||
|
|
}
|
||
|
|
uint16_t c;
|
||
|
|
memcpy(&c, buffer+offset, sizeof(uint16_t));
|
||
|
|
BasicNode<Dim>::current = c;
|
||
|
|
offset += sizeof(uint16_t);
|
||
|
|
for(int i=0; i< BasicNode<Dim>::current; i++){
|
||
|
|
entries[i] = new Entry<Dim, Info>();
|
||
|
|
entries[i]->readFrom(buffer, offset);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
4.10 ~bufferSize~
|
||
|
|
|
||
|
|
Returns the number of bytes required to store this node.
|
||
|
|
|
||
|
|
*/
|
||
|
|
inline virtual int bufferSize() const{
|
||
|
|
return sizeof(uint16_t) +
|
||
|
|
BasicNode<Dim>::current*Entry<Dim, Info>::bufferSize();
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
4.11 ~getMax~
|
||
|
|
|
||
|
|
Return the maximum count of nodes which can be placed in a buffer with
|
||
|
|
given size.
|
||
|
|
|
||
|
|
*/
|
||
|
|
static uint32_t getMax(const uint32_t buffersize){
|
||
|
|
uint32_t ls = buffersize - sizeof(uint16_t); // current
|
||
|
|
return ls / Entry<Dim, Info>::bufferSize();
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
4.12 ~isFull~
|
||
|
|
|
||
|
|
Returns true if no more elements can be inserted into this node.
|
||
|
|
|
||
|
|
*/
|
||
|
|
inline bool isFull() const{
|
||
|
|
return BasicNode<Dim>::current == BasicNode<Dim>::max -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
4.12 ~insert~
|
||
|
|
|
||
|
|
Appends a new entry. If there is an overflow, the result will be true.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
inline bool insert(const Entry<Dim, Info>& e){
|
||
|
|
assert(BasicNode<Dim>::current <= BasicNode<Dim>::max);
|
||
|
|
|
||
|
|
|
||
|
|
entries[BasicNode<Dim>::current] = new Entry<Dim, Info>(e);
|
||
|
|
BasicNode<Dim>::current++;
|
||
|
|
return BasicNode<Dim>::current==BasicNode<Dim>::max+1;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
4.14 ~addBoxAt~
|
||
|
|
|
||
|
|
Builds the uion of the given box and the box of element at position pos
|
||
|
|
and stores the result at posiotion pos.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
inline void addBoxAt(const int pos, const Rectangle<Dim>& r){
|
||
|
|
entries[pos]->addBox(r);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
4.15 ~remove~
|
||
|
|
|
||
|
|
Removes the entrie at position pos from this node.
|
||
|
|
|
||
|
|
*/
|
||
|
|
inline void remove(const int index){
|
||
|
|
assert(index < BasicNode<Dim>::current);
|
||
|
|
delete entries[index];
|
||
|
|
BasicNode<Dim>::current--;
|
||
|
|
for(int i=index; i<BasicNode<Dim>::current; i++){
|
||
|
|
entries[i] = entries[i+1];
|
||
|
|
}
|
||
|
|
entries[BasicNode<Dim>::current] = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
4.16 getEmptyNode()
|
||
|
|
|
||
|
|
pure virtual.
|
||
|
|
|
||
|
|
|
||
|
|
*/
|
||
|
|
virtual Node* getEmptyNode()const = 0;
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
~updateEntry~
|
||
|
|
|
||
|
|
Replaces the entry at the given position by the new one.
|
||
|
|
|
||
|
|
*/
|
||
|
|
inline void updateEntry(int pos, Entry<Dim, Info> e){
|
||
|
|
assert(pos < BasicNode<Dim>::current);
|
||
|
|
*(entries[pos]) = e;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
~isLeaf~
|
||
|
|
|
||
|
|
pure virtual.
|
||
|
|
|
||
|
|
*/
|
||
|
|
virtual const bool isLeaf() const = 0;
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
~print~
|
||
|
|
|
||
|
|
*/
|
||
|
|
std::ostream& print(std::ostream& os) const{
|
||
|
|
os << "(node - ";
|
||
|
|
os << (isLeaf() ? "leaf" : "inner");
|
||
|
|
os << "[" << BasicNode<Dim>::min <<", "
|
||
|
|
<< BasicNode<Dim>::max << ", "
|
||
|
|
<< BasicNode<Dim>::current << "] ::{" ;
|
||
|
|
for(int i=0;i<BasicNode<Dim>::current;i++){
|
||
|
|
entries[i]->print(os);
|
||
|
|
}
|
||
|
|
os << "}])";
|
||
|
|
return os;
|
||
|
|
}
|
||
|
|
|
||
|
|
protected:
|
||
|
|
Entry<Dim, Info>** entries;
|
||
|
|
};
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
Class ~QNodeSplitter~
|
||
|
|
|
||
|
|
This class provides some functions to split a node into 2 new ones
|
||
|
|
using quadratic split algorithm.
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<int Dim, class Info>
|
||
|
|
class QNodeSplitter{
|
||
|
|
public:
|
||
|
|
std::pair<Node<Dim, Info>*, Node<Dim, Info>* >
|
||
|
|
splitNode(Node<Dim, Info>& node){
|
||
|
|
std::pair<int, int> seeds = pickSeeds(node);
|
||
|
|
int index1 = seeds.first;
|
||
|
|
int index2 = seeds.second;
|
||
|
|
Node<Dim, Info>* node1 = node.getEmptyNode();
|
||
|
|
Node<Dim, Info>* node2 = node.getEmptyNode();
|
||
|
|
node1->insert(*(node.getEntry(index1)));
|
||
|
|
node2->insert(*(node.getEntry(index2)));
|
||
|
|
node.remove(std::max(index1,index2));
|
||
|
|
node.remove(std::min(index1,index2));
|
||
|
|
int min = node.getMin();
|
||
|
|
|
||
|
|
while(node.entryCount() > 0){
|
||
|
|
if(node.entryCount() + node1->entryCount() == min){
|
||
|
|
for(int i=0;i<node.entryCount();i++){
|
||
|
|
node1->insert(*node.getEntry(i));
|
||
|
|
}
|
||
|
|
node.deleteEntries();
|
||
|
|
}else if(node.entryCount() + node2->entryCount() == min){
|
||
|
|
for(int i=0;i<node.entryCount();i++){
|
||
|
|
node2->insert(*(node.getEntry(i)));
|
||
|
|
}
|
||
|
|
node.deleteEntries();
|
||
|
|
} else {
|
||
|
|
std::pair<unsigned int, unsigned int> next =
|
||
|
|
pickNext(&node,node1,node2);
|
||
|
|
if(next.second == 1){
|
||
|
|
node1->insert(*(node.getEntry(next.first)));
|
||
|
|
} else {
|
||
|
|
node2->insert(*node.getEntry(next.first));
|
||
|
|
}
|
||
|
|
node.remove(next.first);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return std::make_pair(node1,node2);
|
||
|
|
} // end of splitNode
|
||
|
|
|
||
|
|
private:
|
||
|
|
|
||
|
|
typedef Node<Dim,Info> node_type;
|
||
|
|
|
||
|
|
std::pair<unsigned int,unsigned int> pickSeeds(const node_type& n) const{
|
||
|
|
std::pair<int, int> res;
|
||
|
|
double d = 0;
|
||
|
|
for(int i=0;i<n.entryCount();i++){
|
||
|
|
for(int j=i+1;j<n.entryCount();j++){
|
||
|
|
Rectangle<Dim> r1(n.getEntry(i)->getBox());
|
||
|
|
Rectangle<Dim> r2(n.getEntry(j)->getBox());
|
||
|
|
double d2 = 2 * r1.Union(r2).Area() - (r1.Area() + r2.Area());
|
||
|
|
if(d2>d){
|
||
|
|
res.first = i;
|
||
|
|
res.second = j;
|
||
|
|
d = d2;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if(d==0){ // all boxes are the same
|
||
|
|
res.first = 0;
|
||
|
|
res.second = n.entryCount()-1;
|
||
|
|
}
|
||
|
|
return res;
|
||
|
|
}
|
||
|
|
|
||
|
|
std::pair<unsigned int,unsigned int>
|
||
|
|
pickNext(const node_type* source,
|
||
|
|
const node_type* grpone,
|
||
|
|
const node_type* grptwo) const{
|
||
|
|
double d1 = source->getEntry(0)->getBox().Union(grpone->getBox()).Area();
|
||
|
|
double d2 = source->getEntry(0)->getBox().Union(grptwo->getBox()).Area();
|
||
|
|
unsigned int index = 0;
|
||
|
|
unsigned int bestgrp = -1;
|
||
|
|
double d = std::fabs(d1-d2);
|
||
|
|
Rectangle<Dim> b1 = grpone->getBox();
|
||
|
|
Rectangle<Dim> b2 = grptwo->getBox();
|
||
|
|
double a1 = b1.Area();
|
||
|
|
double a2 = b2.Area();
|
||
|
|
|
||
|
|
for(int i=1;i<source->entryCount();i++){
|
||
|
|
d1 = source->getEntry(i)->getBox().Union(b1).Area();
|
||
|
|
d2 = source->getEntry(i)->getBox().Union(b2).Area();
|
||
|
|
double d3 = std::fabs(d1-d2);
|
||
|
|
if(d3>d){
|
||
|
|
d = d3;
|
||
|
|
index = i;
|
||
|
|
d1 = d1 - a1;
|
||
|
|
d2 = d2 - a2;
|
||
|
|
if(d1!=d2){
|
||
|
|
bestgrp = d1<d2?1:2;
|
||
|
|
} else if(a1!=a2){
|
||
|
|
bestgrp = a1<a2?1:2;
|
||
|
|
} else if(grpone->entryCount()!=grptwo->entryCount()){
|
||
|
|
bestgrp = grpone->entryCount()<grptwo->entryCount()? 1:2;
|
||
|
|
} else { // all criterions failed
|
||
|
|
bestgrp = 1;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
std::pair<unsigned int , unsigned int> res;
|
||
|
|
res.first = index;
|
||
|
|
res.second = bestgrp;
|
||
|
|
return res;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
};
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
5 class TBLeafNode
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<int Dim, class Info>
|
||
|
|
class TBLeafNode : public Node<Dim, Info>{
|
||
|
|
public:
|
||
|
|
/*
|
||
|
|
5.1 Constructors
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
TBLeafNode() {}
|
||
|
|
TBLeafNode(int min, int max, int trjid1):
|
||
|
|
Node<Dim, Info>(min,max), next(0), trjid(trjid1){}
|
||
|
|
|
||
|
|
TBLeafNode(const TBLeafNode& src): Node<Dim, Info>(src),
|
||
|
|
next(src.next),
|
||
|
|
trjid(src.trjid){ }
|
||
|
|
/*
|
||
|
|
5.2 Assignment Operator
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
inline TBLeafNode& operator=(const TBLeafNode<Dim,Info>& src){
|
||
|
|
Node<Dim, Info>::operator=(src);
|
||
|
|
this->next = src.next;
|
||
|
|
this->trjid = src.trjid;
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
5.3 Comparison
|
||
|
|
|
||
|
|
*/
|
||
|
|
inline bool operator==(const TBLeafNode<Dim, Info>& ln)const{
|
||
|
|
return Node<Dim, Info>::operator==(ln) &&
|
||
|
|
this->next == ln.next &&
|
||
|
|
this->trjid == ln.trjid;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
5.4 Destructor
|
||
|
|
|
||
|
|
*/
|
||
|
|
virtual ~TBLeafNode(){
|
||
|
|
Node<Dim, Info>::deleteEntries();
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
5.5 isLeaf
|
||
|
|
|
||
|
|
Returns allways true.
|
||
|
|
|
||
|
|
*/
|
||
|
|
inline virtual const bool isLeaf() const{
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
5.6 Import/Export to a buffer
|
||
|
|
|
||
|
|
*/
|
||
|
|
inline virtual void writeTo(char* buffer, unsigned int& offset) const{
|
||
|
|
Node<Dim, Info>::writeTo(buffer, offset);
|
||
|
|
memcpy(buffer + offset, &next, sizeof(SmiRecordId));
|
||
|
|
offset += sizeof(SmiRecordId);
|
||
|
|
memcpy(buffer + offset, &trjid, sizeof(int));
|
||
|
|
offset += sizeof(int);
|
||
|
|
}
|
||
|
|
|
||
|
|
inline virtual void readFrom(const char* buffer,unsigned int& offset){
|
||
|
|
Node<Dim, Info>::readFrom(buffer, offset);
|
||
|
|
memcpy(&next, buffer + offset, sizeof(SmiRecordId));
|
||
|
|
offset += sizeof(SmiRecordId);
|
||
|
|
memcpy(&trjid, buffer + offset, sizeof(int));
|
||
|
|
offset += sizeof(int);
|
||
|
|
}
|
||
|
|
|
||
|
|
inline int bufferSize() const{
|
||
|
|
return Node<Dim, Info>::bufferSize() + sizeof(SmiRecordId)+sizeof(int);
|
||
|
|
}
|
||
|
|
|
||
|
|
inline uint16_t getMax(){
|
||
|
|
return BasicNode<3>::getMax();
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
~getMax~
|
||
|
|
|
||
|
|
Returns the maximum number of nodes whiach can be placed into a buffer with
|
||
|
|
given size.
|
||
|
|
|
||
|
|
*/
|
||
|
|
static uint32_t getMax(const uint32_t buffersize){
|
||
|
|
uint32_t ls = buffersize - (sizeof(SmiRecordId) + sizeof(int));
|
||
|
|
return Node<Dim,Info>::getMax(ls);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
Getter / Setter
|
||
|
|
|
||
|
|
*/
|
||
|
|
inline SmiRecordId getNext() const{
|
||
|
|
return next;
|
||
|
|
}
|
||
|
|
|
||
|
|
inline void setNext(const SmiRecordId id){
|
||
|
|
next = id;
|
||
|
|
}
|
||
|
|
|
||
|
|
inline int getTrjId() const{
|
||
|
|
return trjid;
|
||
|
|
}
|
||
|
|
|
||
|
|
inline void setTrjId(const int trjid){
|
||
|
|
this->trjid = trjid;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
Returns a node wiout any entries.
|
||
|
|
|
||
|
|
*/
|
||
|
|
inline Node<Dim, Info>* getEmptyNode() const{
|
||
|
|
return new TBLeafNode<Dim, Info>(BasicNode<Dim>::min,
|
||
|
|
BasicNode<Dim>::max, 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
Prints out this node.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
virtual std::ostream& print(std::ostream& os)const{
|
||
|
|
return Node<Dim, Info>::print(os) << next << endl;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
Returns a clone of this node.
|
||
|
|
|
||
|
|
*/
|
||
|
|
inline virtual BasicNode<Dim>* clone() const{
|
||
|
|
return new TBLeafNode<Dim, Info>(*this);
|
||
|
|
}
|
||
|
|
|
||
|
|
private:
|
||
|
|
SmiRecordId next;
|
||
|
|
int trjid;
|
||
|
|
};
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
5 class InnerNode
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<int Dim, class Info>
|
||
|
|
class InnerNode : public Node<Dim, Info>{
|
||
|
|
public:
|
||
|
|
/*
|
||
|
|
5.1 Constructors
|
||
|
|
|
||
|
|
*/
|
||
|
|
InnerNode(const int min1, const int max1): Node<Dim, Info>(min1, max1) {}
|
||
|
|
|
||
|
|
InnerNode(const InnerNode<Dim, Info>& src): Node<Dim, Info>(src) {}
|
||
|
|
|
||
|
|
/*
|
||
|
|
5.2 Assignment operator
|
||
|
|
|
||
|
|
*/
|
||
|
|
inline InnerNode& operator=(const InnerNode<Dim, Info>& src) {
|
||
|
|
return Node<Dim, Info>::operator=(src);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
5.3 Comparison
|
||
|
|
|
||
|
|
*/
|
||
|
|
inline bool operator==(const InnerNode<Dim, Info>& in) const{
|
||
|
|
return Node<Dim, Info>::operator==(in);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
5.4 Destructor
|
||
|
|
|
||
|
|
*/
|
||
|
|
virtual ~InnerNode(){
|
||
|
|
Node<Dim, Info>::deleteEntries();
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
~isLeaf~
|
||
|
|
|
||
|
|
returns allways false.
|
||
|
|
|
||
|
|
*/
|
||
|
|
inline virtual const bool isLeaf() const{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
~selectBestNode~
|
||
|
|
|
||
|
|
for details see Gutmans paper about the r-tree.
|
||
|
|
|
||
|
|
*/
|
||
|
|
int selectBestNode(const Rectangle<Dim>& r) const{
|
||
|
|
assert( (Node<Dim, Info>::current)>0);
|
||
|
|
int res = 0;
|
||
|
|
Rectangle<Dim> r1(Node<Dim, Info>::entries[0]->getBox());
|
||
|
|
double diff = r1.Union(r).Area() - r1.Area();
|
||
|
|
for(int i=1; i< (Node<Dim, Info>::current); i++){
|
||
|
|
r1 = Node<Dim, Info>::entries[i]->getBox();
|
||
|
|
double diff2 = r1.Union(r).Area() - r1.Area();
|
||
|
|
if(diff2<diff){
|
||
|
|
res = i;
|
||
|
|
diff = diff2;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return res;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
~getEmptyNode~
|
||
|
|
|
||
|
|
Returns a node without any entries.
|
||
|
|
|
||
|
|
*/
|
||
|
|
inline Node<Dim, Info>* getEmptyNode() const{
|
||
|
|
return new InnerNode<Dim, Info>(BasicNode<Dim>::min,
|
||
|
|
BasicNode<Dim>::max);
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
~clone~
|
||
|
|
|
||
|
|
Returns a clone of this node.
|
||
|
|
|
||
|
|
*/
|
||
|
|
inline virtual BasicNode<Dim>* clone() const{
|
||
|
|
return new InnerNode<Dim, Info>(*this);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
~getMax~
|
||
|
|
|
||
|
|
Returns the maximum number of inner nodes which can be stored
|
||
|
|
into a buffer of given size.
|
||
|
|
|
||
|
|
*/
|
||
|
|
inline static uint32_t getMax(uint32_t buffersize){
|
||
|
|
return Node<Dim,Info>::getMax(buffersize);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
};
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
5 Class PathEntry
|
||
|
|
|
||
|
|
This class supports the searchNode function of a tbtree.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
template<int Dim>
|
||
|
|
struct pathEntry{
|
||
|
|
public:
|
||
|
|
pathEntry(const SmiRecordId id1, BasicNode<Dim>* node1, const int pos1):
|
||
|
|
id(id1), node(node1), pos(pos1){}
|
||
|
|
pathEntry(const pathEntry& pe):id(pe.id), node(pe.node), pos(pe.pos){}
|
||
|
|
|
||
|
|
inline pathEntry& operator=(const pathEntry& s){
|
||
|
|
this->id = s.id;
|
||
|
|
this->node = s.node;
|
||
|
|
this->pos = s.pos;
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
|
||
|
|
inline bool operator==(const pathEntry& s)const{
|
||
|
|
return this->id == s.id &&
|
||
|
|
this->node == s.node &&
|
||
|
|
this->pos == s.pos;
|
||
|
|
}
|
||
|
|
|
||
|
|
~pathEntry(){}
|
||
|
|
|
||
|
|
SmiRecordId id; // the record id
|
||
|
|
BasicNode<Dim>* node; // the node corresponding to that id
|
||
|
|
int pos; // position of the next entry
|
||
|
|
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
7 class TBTree
|
||
|
|
|
||
|
|
|
||
|
|
This is the implementation of a tbtree. In contrast to the
|
||
|
|
original paper, we don't store the direction in each leaf entry.
|
||
|
|
Instead we store an trip id in each leaf node.
|
||
|
|
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
class TBTree{
|
||
|
|
public:
|
||
|
|
|
||
|
|
/*
|
||
|
|
Creates an empty TBTree
|
||
|
|
|
||
|
|
*/
|
||
|
|
TBTree(const int pageSize): file(true, pageSize-64),rootId(0){
|
||
|
|
file.Create();
|
||
|
|
int size = file.GetRecordLength();
|
||
|
|
recordLength = size;
|
||
|
|
leafMax = TBLeafNode<3, TBLeafInfo>::getMax(size);
|
||
|
|
leafMin = leafMax / 4;
|
||
|
|
|
||
|
|
innerMax = InnerNode<3, InnerInfo>::getMax(size);
|
||
|
|
|
||
|
|
innerMin = innerMax / 4;
|
||
|
|
noEntries = 0;
|
||
|
|
noNodes = 0;
|
||
|
|
noLeafNodes = 0;
|
||
|
|
level = 0;
|
||
|
|
Rectangle<3> b(false);
|
||
|
|
box = b;
|
||
|
|
SmiRecord dummy;
|
||
|
|
headerId =0;
|
||
|
|
saveHeader();
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
Opens an existing TBTRee from file
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
TBTree(const SmiFileId id, SmiRecordId hid): file(true), headerId(hid){
|
||
|
|
file.Open(id);
|
||
|
|
readHeader();
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
~ Destructor ~
|
||
|
|
|
||
|
|
*/
|
||
|
|
~TBTree(){
|
||
|
|
if(file.IsOpen()){
|
||
|
|
saveHeader();
|
||
|
|
file.Close();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
Returns the fileId of the underlying file.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
inline SmiFileId getFileId() {
|
||
|
|
return file.GetFileId();
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
Returns the record id of the record storing the header of the tree.
|
||
|
|
|
||
|
|
*/
|
||
|
|
inline SmiRecordId getHeaderId() const{
|
||
|
|
return headerId;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
Returns the record id storing the root of the tree. If the tree is emty, the
|
||
|
|
result will be 0.
|
||
|
|
|
||
|
|
*/
|
||
|
|
inline SmiRecordId getRootId() const{
|
||
|
|
return rootId;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
Returns the node stored at the given id.
|
||
|
|
|
||
|
|
*/
|
||
|
|
inline BasicNode<3>* getNode(const SmiRecordId id){
|
||
|
|
return readNode(id);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
Stores a new entry.
|
||
|
|
|
||
|
|
*/
|
||
|
|
void insert(const temporalalgebra::UPoint& up,
|
||
|
|
const int trjid, const TupleId tid){
|
||
|
|
if(!up.IsDefined()){
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
noEntries++;
|
||
|
|
TBLeafInfo li(tid);
|
||
|
|
Entry<3, TBLeafInfo> e(up.BoundingBox(), li);
|
||
|
|
if(!rootId){ // the tree is empty
|
||
|
|
TBLeafNode<3, TBLeafInfo> node(leafMin, leafMax, trjid);
|
||
|
|
node.insert(e);
|
||
|
|
rootId = saveNode(node);
|
||
|
|
level++;
|
||
|
|
box = e.getBox();
|
||
|
|
return;
|
||
|
|
} else {
|
||
|
|
box = box.Union(e.getBox());
|
||
|
|
std::vector<pathEntry<3> > path;
|
||
|
|
TBLeafNode<3, TBLeafInfo>* newLeaf(0);
|
||
|
|
SmiRecordId id(0);
|
||
|
|
if(searchNode(rootId, path, e, trjid)) {
|
||
|
|
TBLeafNode<3, TBLeafInfo>* leaf =
|
||
|
|
dynamic_cast<TBLeafNode<3, TBLeafInfo>* >
|
||
|
|
(path[path.size()-1].node);
|
||
|
|
if(!leaf->isFull()) {
|
||
|
|
leaf->insert(e);
|
||
|
|
updateNode(path[path.size()-1].id, *leaf);
|
||
|
|
Rectangle<3> b = leaf->getBox();
|
||
|
|
updatePath(path, b);
|
||
|
|
} else {
|
||
|
|
assert(! leaf->getNext());
|
||
|
|
newLeaf = new TBLeafNode<3, TBLeafInfo>(leafMin, leafMax, trjid);
|
||
|
|
newLeaf->insert(e);
|
||
|
|
id = saveNode(*newLeaf);
|
||
|
|
leaf->setNext(id);
|
||
|
|
updateNode(path[path.size()-1].id, *leaf); // update next
|
||
|
|
}
|
||
|
|
} else { // no predecessor was found -> create a new leaf
|
||
|
|
newLeaf = new TBLeafNode<3, TBLeafInfo>(leafMin, leafMax,trjid);
|
||
|
|
newLeaf->insert(e);
|
||
|
|
id = saveNode(*newLeaf);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
// path processed or needless, delete the entries
|
||
|
|
for(unsigned int i=0;i<path.size(); i++){
|
||
|
|
assert(path[i].node); // dont allow an empty entry
|
||
|
|
delete path[i].node;
|
||
|
|
path[i].node = 0;
|
||
|
|
}
|
||
|
|
while(!path.empty()){
|
||
|
|
path.pop_back();
|
||
|
|
}
|
||
|
|
if(newLeaf){ // there is new leaf which has to
|
||
|
|
// inserted into the tree structure
|
||
|
|
SmiRecordId newRootId = insertLeaf(id, e.getBox());
|
||
|
|
if(newRootId!=rootId){
|
||
|
|
level++;
|
||
|
|
}
|
||
|
|
rootId = newRootId;
|
||
|
|
delete newLeaf;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
~insertLeaf~
|
||
|
|
|
||
|
|
Stores a new Leaf in the tree. To be used in bulk loading.
|
||
|
|
Returns the id of the used record
|
||
|
|
|
||
|
|
*/
|
||
|
|
SmiRecordId insertLeaf(const TBLeafNode<3, TBLeafInfo>& leaf,
|
||
|
|
const SmiRecordId predecessor = 0){
|
||
|
|
assert(leaf.entryCount() >0);
|
||
|
|
|
||
|
|
noEntries += leaf.entryCount();
|
||
|
|
SmiRecordId id = saveNode(leaf); // save the leaf
|
||
|
|
if(!rootId){ // tree was empty
|
||
|
|
level++;
|
||
|
|
box = leaf.getBox();
|
||
|
|
rootId = id;
|
||
|
|
return id;
|
||
|
|
}
|
||
|
|
|
||
|
|
// there is a predecessor
|
||
|
|
if(predecessor){
|
||
|
|
TBLeafNode<3, TBLeafInfo>* pred =
|
||
|
|
dynamic_cast<TBLeafNode<3, TBLeafInfo>*>(readNode(predecessor));
|
||
|
|
pred->setNext(id);
|
||
|
|
updateNode(predecessor, * pred);
|
||
|
|
delete pred;
|
||
|
|
}
|
||
|
|
// update bounding box
|
||
|
|
box = box.Union(leaf.getBox());
|
||
|
|
// insert the new leaf into the structure
|
||
|
|
SmiRecordId newRootId = insertLeaf(id, leaf.getBox());
|
||
|
|
if(newRootId!=rootId){
|
||
|
|
level++;
|
||
|
|
rootId = newRootId;
|
||
|
|
}
|
||
|
|
return id;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
Returns a new empty leaf node
|
||
|
|
|
||
|
|
*/
|
||
|
|
TBLeafNode<3, TBLeafInfo>* getEmptyLeaf(const TupleId trjid){
|
||
|
|
return new TBLeafNode<3, TBLeafInfo>(leafMin, leafMax, trjid);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
Deletes the underlying file. After that operator, the TBTree is not longer
|
||
|
|
usable.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
void deleteFile(){
|
||
|
|
file.Close();
|
||
|
|
file.Drop();
|
||
|
|
}
|
||
|
|
|
||
|
|
std::string toString(){
|
||
|
|
|
||
|
|
std::ostringstream os;
|
||
|
|
os << "[ -- tbtree -- " << endl
|
||
|
|
<< " fileId : " << file.GetFileId() << endl
|
||
|
|
<< " rootId : " << rootId << endl
|
||
|
|
<< " headerId : " << headerId << endl
|
||
|
|
<< " leafMin : " << leafMin << endl
|
||
|
|
<< " leafMax : " << leafMax << endl
|
||
|
|
<< " innerMin : " << innerMin << endl
|
||
|
|
<< " innerMax : " << innerMax << endl
|
||
|
|
<< " entries : " << noEntries << endl
|
||
|
|
<< " nodes : " << noNodes << endl
|
||
|
|
<< " leafNodes : " << noLeafNodes << endl
|
||
|
|
<< " level : " << level << endl
|
||
|
|
<< " recordLength : " << recordLength << endl
|
||
|
|
<< " box : ";
|
||
|
|
if(!box.IsDefined()){
|
||
|
|
os << "undef";
|
||
|
|
} else {
|
||
|
|
os << box;
|
||
|
|
}
|
||
|
|
os << endl << "]";
|
||
|
|
return os.str();
|
||
|
|
|
||
|
|
}
|
||
|
|
/*
|
||
|
|
Some Getter
|
||
|
|
|
||
|
|
*/
|
||
|
|
int entryCount() const{
|
||
|
|
return noEntries;
|
||
|
|
}
|
||
|
|
int nodeCount() const{
|
||
|
|
return noNodes;
|
||
|
|
}
|
||
|
|
int leafnodeCount() const{
|
||
|
|
return noLeafNodes;
|
||
|
|
}
|
||
|
|
|
||
|
|
int getHeight() const{
|
||
|
|
return level;
|
||
|
|
}
|
||
|
|
|
||
|
|
Rectangle<3> getBox()const{
|
||
|
|
return box;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool 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",
|
||
|
|
"SecondaryTBTreetreeIndexFile"));
|
||
|
|
result.push_back(std::pair<std::string,std::string>(
|
||
|
|
"FileId",fileid.str()));
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
static const std::string BasicType(){
|
||
|
|
return "tbtree";
|
||
|
|
}
|
||
|
|
|
||
|
|
static const bool checkType(ListExpr type){
|
||
|
|
ListExpr errorInfo = listutils::emptyErrorInfo();
|
||
|
|
return CheckTBTree(type, errorInfo);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
calculate number of different trajectories in this node
|
||
|
|
|
||
|
|
*/
|
||
|
|
int getcoverage(BasicNode<3>* n){
|
||
|
|
if(n->isLeaf())
|
||
|
|
return 1;
|
||
|
|
InnerNode<3,InnerInfo>* innernode =
|
||
|
|
dynamic_cast<InnerNode<3, InnerInfo>* >(n);
|
||
|
|
std::vector<int> trajid;
|
||
|
|
std::vector<Entry<3,InnerInfo> > list1;
|
||
|
|
std::vector<Entry<3,InnerInfo> > list2;
|
||
|
|
for(unsigned int i = 0;i < innernode->entryCount();i++){
|
||
|
|
list1.push_back(*(innernode->getEntry(i)));
|
||
|
|
}
|
||
|
|
SmiRecordId adr;
|
||
|
|
while(!list1.empty()){
|
||
|
|
for(unsigned int i = 0;i < list1.size();i++){
|
||
|
|
adr = list1[i].getInfo().getPointer();
|
||
|
|
BasicNode<3>* node = getNode(adr);
|
||
|
|
if(node->isLeaf()){ //get trajid
|
||
|
|
TBLeafNode<3,TBLeafInfo>* leafnode =
|
||
|
|
dynamic_cast<TBLeafNode<3, TBLeafInfo>* >(node);
|
||
|
|
trajid.push_back(leafnode->getTrjId());
|
||
|
|
}
|
||
|
|
else{
|
||
|
|
innernode = dynamic_cast<InnerNode<3, InnerInfo>* >(node);
|
||
|
|
for(unsigned int j = 0;j < innernode->entryCount();j++)
|
||
|
|
list2.push_back(*(innernode->getEntry(j)));
|
||
|
|
}
|
||
|
|
delete node;
|
||
|
|
}
|
||
|
|
list1.clear();
|
||
|
|
list1.swap(list2);
|
||
|
|
list2.clear();
|
||
|
|
}
|
||
|
|
stable_sort(trajid.begin(),trajid.end());
|
||
|
|
std::vector<int>::iterator end;
|
||
|
|
end = unique(trajid.begin(),trajid.end());
|
||
|
|
std::vector<int>::iterator begin = trajid.begin();
|
||
|
|
int count = 0;
|
||
|
|
while(begin != end){
|
||
|
|
begin++;
|
||
|
|
count++;
|
||
|
|
}
|
||
|
|
return count;
|
||
|
|
}
|
||
|
|
|
||
|
|
// for CloneTBtree
|
||
|
|
void Clone(TBTree*);
|
||
|
|
SmiRecordId DFVisit_TBtree(TBTree*,tbtree::BasicNode<3>*);
|
||
|
|
|
||
|
|
private:
|
||
|
|
SmiRecordFile file;
|
||
|
|
SmiRecordId rootId;
|
||
|
|
SmiRecordId headerId;
|
||
|
|
uint16_t leafMin;
|
||
|
|
uint16_t leafMax;
|
||
|
|
uint16_t innerMin;
|
||
|
|
uint16_t innerMax;
|
||
|
|
|
||
|
|
uint32_t noEntries; // numer of stored entries
|
||
|
|
uint32_t noNodes; // number of nodes in the tree
|
||
|
|
uint32_t level; // height of the tree
|
||
|
|
uint32_t noLeafNodes; // number of leaf nodes
|
||
|
|
Rectangle<3> box; // bounding boc of the whole tree
|
||
|
|
uint32_t recordLength;
|
||
|
|
|
||
|
|
void saveHeader() {
|
||
|
|
|
||
|
|
//unsigned int size = 4*sizeof(uint16_t) + sizeof(SmiRecordId) +
|
||
|
|
// 4*sizeof(uint32_t) + sizeof(char) +
|
||
|
|
// rectBufferSize<3>();
|
||
|
|
unsigned int size = recordLength;
|
||
|
|
char buffer[size];
|
||
|
|
memset(buffer,0,size);
|
||
|
|
unsigned int offset = 0;
|
||
|
|
// rootid
|
||
|
|
memcpy(buffer+offset, &rootId, sizeof(SmiRecordId));
|
||
|
|
offset += sizeof(SmiRecordId);
|
||
|
|
// min, max stuff
|
||
|
|
memcpy(buffer+offset, &leafMin, sizeof(uint16_t));
|
||
|
|
offset += sizeof(uint16_t);
|
||
|
|
memcpy(buffer+offset, &leafMax, sizeof(uint16_t));
|
||
|
|
offset += sizeof(uint16_t);
|
||
|
|
memcpy(buffer+offset, &innerMin, sizeof(uint16_t));
|
||
|
|
offset += sizeof(uint16_t);
|
||
|
|
memcpy(buffer+offset, &innerMax, sizeof(uint16_t));
|
||
|
|
offset += sizeof(uint16_t);
|
||
|
|
// counters
|
||
|
|
memcpy(buffer+offset, &noEntries, sizeof(uint32_t));
|
||
|
|
offset += sizeof(uint32_t);
|
||
|
|
memcpy(buffer+offset, &noNodes, sizeof(uint32_t));
|
||
|
|
offset += sizeof(uint32_t);
|
||
|
|
memcpy(buffer+offset, &noLeafNodes, sizeof(uint32_t));
|
||
|
|
offset += sizeof(uint32_t);
|
||
|
|
memcpy(buffer+offset, &level, sizeof(uint32_t));
|
||
|
|
offset += sizeof(uint32_t);
|
||
|
|
// bounding box
|
||
|
|
if(box.IsDefined()){
|
||
|
|
char c = 1;
|
||
|
|
memcpy(buffer+offset,&c,sizeof(char));
|
||
|
|
offset += sizeof(char);
|
||
|
|
writeRectangle<3>(box, buffer, offset);
|
||
|
|
} else {
|
||
|
|
char c = 0;
|
||
|
|
memcpy(buffer+offset,&c,sizeof(char));
|
||
|
|
offset += sizeof(char);
|
||
|
|
double d = -1;
|
||
|
|
for(int i=0;i<2*3; i++){
|
||
|
|
memcpy(buffer+offset,&d, sizeof(double));
|
||
|
|
offset += sizeof(double);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if(offset>size){
|
||
|
|
cout << "offset = " << offset << " , size = " << size << endl;
|
||
|
|
}
|
||
|
|
assert(offset<=size);
|
||
|
|
|
||
|
|
// store the buffer
|
||
|
|
SmiRecord record;
|
||
|
|
if(headerId != 0){
|
||
|
|
file.SelectRecord(headerId, record, SmiFile::Update);
|
||
|
|
SmiSize hss = record.Write(buffer,size,0);
|
||
|
|
assert(hss == size);
|
||
|
|
} else {
|
||
|
|
file.AppendRecord(headerId, record);
|
||
|
|
assert(headerId !=0);
|
||
|
|
SmiSize hss = record.Write(buffer,size,0);
|
||
|
|
assert(hss == size);
|
||
|
|
}
|
||
|
|
record.Finish();
|
||
|
|
}
|
||
|
|
|
||
|
|
void readHeader(){
|
||
|
|
// read buffer
|
||
|
|
unsigned int size = 4*sizeof(uint16_t) + sizeof(SmiRecordId) +
|
||
|
|
4*sizeof(uint32_t) + sizeof(char) +
|
||
|
|
rectBufferSize<3>() ;
|
||
|
|
char buffer[size];
|
||
|
|
SmiRecord record;
|
||
|
|
file.SelectRecord(headerId, record);
|
||
|
|
recordLength = record.Size();
|
||
|
|
SmiSize hs = record.Read(buffer,size,0);
|
||
|
|
unsigned int offset = 0;
|
||
|
|
assert(hs == size);
|
||
|
|
memcpy(&rootId, buffer+offset, sizeof(SmiRecordId));
|
||
|
|
offset += sizeof(SmiRecordId);
|
||
|
|
memcpy(&leafMin, buffer+offset, sizeof(uint16_t));
|
||
|
|
offset += sizeof(uint16_t);
|
||
|
|
memcpy(&leafMax, buffer+offset, sizeof(uint16_t));
|
||
|
|
offset += sizeof(uint16_t);
|
||
|
|
memcpy(& innerMin, buffer+offset, sizeof(uint16_t));
|
||
|
|
offset += sizeof(uint16_t);
|
||
|
|
memcpy(&innerMax, buffer+offset, sizeof(uint16_t));
|
||
|
|
offset += sizeof(uint16_t);
|
||
|
|
// counters
|
||
|
|
memcpy(&noEntries, buffer+offset, sizeof(uint32_t));
|
||
|
|
offset += sizeof(uint32_t);
|
||
|
|
memcpy(&noNodes, buffer+offset, sizeof(uint32_t));
|
||
|
|
offset += sizeof(uint32_t);
|
||
|
|
memcpy(&noLeafNodes, buffer+offset, sizeof(uint32_t));
|
||
|
|
offset += sizeof(uint32_t);
|
||
|
|
memcpy(&level, buffer+offset, sizeof(uint32_t));
|
||
|
|
offset += sizeof(uint32_t);
|
||
|
|
// bounding box
|
||
|
|
char c;
|
||
|
|
memcpy(&c, buffer+offset, sizeof(char));
|
||
|
|
offset += sizeof(char);
|
||
|
|
if(c==0){
|
||
|
|
box.SetDefined(false);
|
||
|
|
} else {
|
||
|
|
readRectangle<3>(box, buffer, offset);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
static bool EqualNodes(const BasicNode<3>* n1, const BasicNode<3>* n2) {
|
||
|
|
if(n1->isLeaf()!=n2->isLeaf()){
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
if(n1->isLeaf()){
|
||
|
|
const TBLeafNode<3, TBLeafInfo>* ln1 =
|
||
|
|
dynamic_cast<const TBLeafNode<3, TBLeafInfo>*>(n1);
|
||
|
|
const TBLeafNode<3, TBLeafInfo>* ln2 =
|
||
|
|
dynamic_cast<const TBLeafNode<3, TBLeafInfo>*>(n2);
|
||
|
|
return *ln1 == *ln2;
|
||
|
|
} else {
|
||
|
|
const InnerNode<3, InnerInfo>* in1 =
|
||
|
|
dynamic_cast<const InnerNode<3, InnerInfo>*>(n1);
|
||
|
|
const InnerNode<3, InnerInfo>* in2 =
|
||
|
|
dynamic_cast<const InnerNode<3, InnerInfo>*>(n2);
|
||
|
|
return *in1 == *in2;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
SmiRecordId saveNode(const BasicNode<3>& n){
|
||
|
|
noNodes++;
|
||
|
|
if(n.isLeaf()){
|
||
|
|
noLeafNodes++;
|
||
|
|
}
|
||
|
|
assert(n.entryCount()>0); // never save an empty node
|
||
|
|
unsigned int size = recordLength;
|
||
|
|
char buffer[size];
|
||
|
|
memset(buffer,0,size);
|
||
|
|
char leaf = n.isLeaf()?1:0;
|
||
|
|
unsigned int offset = 0;
|
||
|
|
memcpy(buffer , &leaf, sizeof(char));
|
||
|
|
offset += sizeof(char);
|
||
|
|
n.writeTo(buffer, offset);
|
||
|
|
SmiRecordId id = 0;
|
||
|
|
SmiRecord record;
|
||
|
|
file.AppendRecord(id, record);
|
||
|
|
SmiSize os = 0; // offset
|
||
|
|
SmiSize rss = record.Write(buffer, size, os);
|
||
|
|
assert(rss == size);
|
||
|
|
record.Finish();
|
||
|
|
return id;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
void updateNode(const SmiRecordId id, const BasicNode<3>& n){
|
||
|
|
assert(n.entryCount() > 0);
|
||
|
|
SmiRecord record;
|
||
|
|
file.SelectRecord(id, record, SmiFile::Update);
|
||
|
|
// unsigned int size = n.bufferSize()+sizeof(char);
|
||
|
|
unsigned int size = recordLength;
|
||
|
|
char buffer[size];
|
||
|
|
memset(buffer,0,size);
|
||
|
|
unsigned int offset = 0;
|
||
|
|
char isLeaf = n.isLeaf()?1:0;
|
||
|
|
memcpy(buffer,&isLeaf,sizeof(char));
|
||
|
|
offset += sizeof(char);
|
||
|
|
n.writeTo(buffer, offset);
|
||
|
|
|
||
|
|
|
||
|
|
SmiSize os = 0; // offset
|
||
|
|
SmiSize rss = record.Write(buffer, size, os);
|
||
|
|
assert(rss == size);
|
||
|
|
if(record.Size()>size){
|
||
|
|
record.Truncate(size);
|
||
|
|
}
|
||
|
|
record.Finish();
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
BasicNode<3>* readNode(const SmiRecordId id) {
|
||
|
|
SmiRecord record;
|
||
|
|
file.SelectRecord(id, record);
|
||
|
|
SmiSize size = record.Size();
|
||
|
|
assert(size>1);
|
||
|
|
|
||
|
|
char buffer[size];
|
||
|
|
SmiSize bs = record.Read(buffer, size, 0); // read record completely
|
||
|
|
assert(bs == size);
|
||
|
|
unsigned int offset = 0;
|
||
|
|
char leaf;
|
||
|
|
memcpy(&leaf, buffer, sizeof(char));
|
||
|
|
offset += sizeof(char);
|
||
|
|
BasicNode<3>* res(0);
|
||
|
|
if(leaf==1){
|
||
|
|
res = createLeafNodeFrom(buffer, offset);
|
||
|
|
} else {
|
||
|
|
res = createInnerNodeFrom(buffer, offset);
|
||
|
|
}
|
||
|
|
assert(offset<=size);
|
||
|
|
return res;
|
||
|
|
}
|
||
|
|
|
||
|
|
TBLeafNode<3, TBLeafInfo>* createLeafNodeFrom(const char* buffer,
|
||
|
|
unsigned int& offset){
|
||
|
|
TBLeafNode<3, TBLeafInfo>* res =
|
||
|
|
new TBLeafNode<3, TBLeafInfo>(leafMin, leafMax, 0);
|
||
|
|
res->readFrom(buffer, offset);
|
||
|
|
return res;
|
||
|
|
}
|
||
|
|
|
||
|
|
InnerNode<3, InnerInfo>* createInnerNodeFrom(const char* buffer,
|
||
|
|
unsigned int& offset){
|
||
|
|
InnerNode<3, InnerInfo>* res =
|
||
|
|
new InnerNode<3, InnerInfo>(innerMin, innerMax);
|
||
|
|
res->readFrom(buffer, offset);
|
||
|
|
return res;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
bool searchNode(const SmiRecordId id, std::vector<pathEntry<3> >& path,
|
||
|
|
const Entry<3, TBLeafInfo>& li, const int trjid ) {
|
||
|
|
|
||
|
|
BasicNode<3>* bn = readNode(id);
|
||
|
|
assert(bn->entryCount()>0);
|
||
|
|
|
||
|
|
|
||
|
|
if(bn->isLeaf()){
|
||
|
|
TBLeafNode<3, TBLeafInfo>* leaf =
|
||
|
|
dynamic_cast<TBLeafNode<3, TBLeafInfo>*> (bn);
|
||
|
|
if(leaf->getTrjId()==trjid && leaf->getNext()==0){
|
||
|
|
path.push_back(pathEntry<3>(id,leaf, -1));
|
||
|
|
return true;
|
||
|
|
} else {
|
||
|
|
delete leaf;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
} else { // an inner node
|
||
|
|
InnerNode<3, InnerInfo>* node =
|
||
|
|
dynamic_cast<InnerNode<3, InnerInfo>* >(bn);
|
||
|
|
const Entry<3, InnerInfo>* entry;
|
||
|
|
uint16_t c = node->entryCount();
|
||
|
|
for(uint16_t i=0; i < c; i++){
|
||
|
|
|
||
|
|
entry = node->getEntry(i);
|
||
|
|
if(entry->getBox().Intersects(li.getBox())){
|
||
|
|
path.push_back(pathEntry<3>(id, node,i));
|
||
|
|
if(searchNode(entry->getInfo().getPointer(), path, li, trjid)){
|
||
|
|
return true;
|
||
|
|
} else {
|
||
|
|
path.pop_back();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
delete node;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
void updatePath(const std::vector<pathEntry<3> >& path,
|
||
|
|
const Rectangle<3>& b ) {
|
||
|
|
// a new entry was inserted at the end of the path.
|
||
|
|
// we have to update the bounding boxes of all nodes in a path
|
||
|
|
for(int i=path.size()-2; i>=0;i--){
|
||
|
|
InnerNode<3, InnerInfo>* node =
|
||
|
|
dynamic_cast<InnerNode<3, InnerInfo>* >(path[i].node);
|
||
|
|
int pos = path[i].pos;
|
||
|
|
Rectangle<3> r = node->getEntry(pos)->getBox();
|
||
|
|
if(r.Contains(b)){
|
||
|
|
return;
|
||
|
|
} else {
|
||
|
|
node->addBoxAt(pos, b);
|
||
|
|
updateNode(path[i].id, *node);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
~InsertLeaf~
|
||
|
|
|
||
|
|
This function embedds the leaf with given id and box into the tree structure.
|
||
|
|
|
||
|
|
*/
|
||
|
|
SmiRecordId insertLeaf(const SmiRecordId& id, const Rectangle<3>& rect){
|
||
|
|
std::pair<SmiRecordId, SmiRecordId> res =
|
||
|
|
insertLeafRec(rootId, id, rect, 0);
|
||
|
|
if(res.second==0){
|
||
|
|
return res.first;
|
||
|
|
} else {
|
||
|
|
BasicNode<3>* s1 = readNode(res.first);
|
||
|
|
BasicNode<3>* s2 = readNode(res.second);
|
||
|
|
Entry<3, InnerInfo> e1(s1->getBox(), res.first);
|
||
|
|
Entry<3, InnerInfo> e2(s2->getBox(), res.second);
|
||
|
|
InnerNode<3, InnerInfo> n(innerMin, innerMax);
|
||
|
|
n.insert(e1);
|
||
|
|
n.insert(e2);
|
||
|
|
delete s1;
|
||
|
|
delete s2;
|
||
|
|
return saveNode(n);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
std::pair<SmiRecordId, SmiRecordId>
|
||
|
|
insertLeafRec(const SmiRecordId rootId,
|
||
|
|
const SmiRecordId& id,
|
||
|
|
const Rectangle<3>& rect,
|
||
|
|
const int level){
|
||
|
|
BasicNode<3>* root = readNode(rootId);
|
||
|
|
if(root->isLeaf()){
|
||
|
|
std::pair<SmiRecordId, SmiRecordId> res(rootId, id);
|
||
|
|
delete root;
|
||
|
|
return res;
|
||
|
|
} else {
|
||
|
|
InnerNode<3, InnerInfo>* iroot =
|
||
|
|
dynamic_cast<InnerNode<3, InnerInfo>*>(root);
|
||
|
|
int sonIndex = iroot->selectBestNode(rect);
|
||
|
|
SmiRecordId sonId = iroot->getEntry(sonIndex)->getInfo().getPointer();
|
||
|
|
std::pair<SmiRecordId, SmiRecordId> sonRes =
|
||
|
|
insertLeafRec(sonId, id, rect, level+1);
|
||
|
|
if(sonRes.second == 0 ){ // no split required
|
||
|
|
Rectangle<3> b(root->getBox());
|
||
|
|
if(!b.Contains(rect)){ // bounding box update required
|
||
|
|
b = b.Union(rect);
|
||
|
|
Entry<3, InnerInfo> newSon(b, sonId);
|
||
|
|
iroot->updateEntry(sonIndex, newSon);
|
||
|
|
updateNode(rootId, *iroot);
|
||
|
|
}
|
||
|
|
delete iroot;
|
||
|
|
sonRes.first = rootId;
|
||
|
|
return sonRes;
|
||
|
|
} else { // son was split into two nodes
|
||
|
|
// update first son
|
||
|
|
BasicNode<3>* firstSon = readNode(sonRes.first);
|
||
|
|
Entry<3, InnerInfo> newSon1(firstSon->getBox(), sonRes.first);
|
||
|
|
BasicNode<3>* secondSon = readNode(sonRes.second);
|
||
|
|
Entry<3, InnerInfo> newSon2(secondSon->getBox(), sonRes.second);
|
||
|
|
delete firstSon;
|
||
|
|
delete secondSon;
|
||
|
|
iroot->updateEntry(sonIndex, newSon1);
|
||
|
|
if(!iroot->insert(newSon2)){ // root has space enough
|
||
|
|
updateNode(rootId, *iroot);
|
||
|
|
sonRes.first = rootId;
|
||
|
|
sonRes.second = 0;
|
||
|
|
delete iroot;
|
||
|
|
return sonRes;
|
||
|
|
} else {
|
||
|
|
QNodeSplitter<3, InnerInfo> ns;
|
||
|
|
std::pair<Node<3, InnerInfo>*, Node<3, InnerInfo>* > nodes =
|
||
|
|
ns.splitNode(*iroot);
|
||
|
|
delete iroot;
|
||
|
|
updateNode(rootId, *(nodes.first));
|
||
|
|
sonRes.first = rootId;
|
||
|
|
sonRes.second = saveNode(*(nodes.second));
|
||
|
|
delete nodes.first;
|
||
|
|
delete nodes.second;
|
||
|
|
return sonRes;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
9 classes for a tree traversal
|
||
|
|
|
||
|
|
|
||
|
|
9.1 Iterator element
|
||
|
|
|
||
|
|
|
||
|
|
Using an iterator implementation, instances of obkjects of this class
|
||
|
|
will be returned as return values.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
template<int Dim>
|
||
|
|
class IteratorElement{
|
||
|
|
public:
|
||
|
|
/*
|
||
|
|
~Constructors~
|
||
|
|
|
||
|
|
|
||
|
|
*/
|
||
|
|
IteratorElement(): ownId(0),parentId(0), node(0), level(0){}
|
||
|
|
|
||
|
|
IteratorElement(SmiRecordId ownId1,
|
||
|
|
SmiRecordId parentId1,
|
||
|
|
BasicNode<Dim>* node1,
|
||
|
|
int level1): ownId(ownId1), parentId(parentId1),
|
||
|
|
node(node1), level(level1) {}
|
||
|
|
|
||
|
|
IteratorElement( const IteratorElement<Dim>& s):
|
||
|
|
ownId(s.ownId), parentId(s.parentId),
|
||
|
|
node(s.node), level(s.level) {}
|
||
|
|
/*
|
||
|
|
Assignment operator
|
||
|
|
|
||
|
|
*/
|
||
|
|
IteratorElement<Dim>& operator=(const IteratorElement<Dim>& s){
|
||
|
|
ownId = s.ownId;
|
||
|
|
parentId = s.parentId;
|
||
|
|
node = s.node;
|
||
|
|
level = s.level;
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
~Destructor~
|
||
|
|
|
||
|
|
*/
|
||
|
|
~IteratorElement(){}
|
||
|
|
|
||
|
|
void deleteNode(){
|
||
|
|
if(node){
|
||
|
|
delete node;
|
||
|
|
node = 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
~Getter~
|
||
|
|
|
||
|
|
*/
|
||
|
|
SmiRecordId getOwnId() const{ return ownId; }
|
||
|
|
SmiRecordId getParentId() const {return parentId;}
|
||
|
|
BasicNode<Dim>* getNode() const { return node; }
|
||
|
|
int getLevel() const { return level; }
|
||
|
|
|
||
|
|
/*
|
||
|
|
~print~
|
||
|
|
|
||
|
|
*/
|
||
|
|
std::ostream& print(std::ostream& os){
|
||
|
|
return os << "ownId = " << ownId << ", parentId = "
|
||
|
|
<< parentId << ", level = " << level;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
private:
|
||
|
|
SmiRecordId ownId; // id of the node
|
||
|
|
SmiRecordId parentId; // parent id, 0 if root
|
||
|
|
BasicNode<Dim>* node; // the node
|
||
|
|
int level; // level (0 = root)
|
||
|
|
};
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
|
||
|
|
Class PathElement
|
||
|
|
|
||
|
|
For internal use within the DepthSearch class.
|
||
|
|
|
||
|
|
*/
|
||
|
|
template<int Dim>
|
||
|
|
class PathElement: public IteratorElement<Dim>{
|
||
|
|
public:
|
||
|
|
PathElement(SmiRecordId ownId,
|
||
|
|
SmiRecordId parentId,
|
||
|
|
BasicNode<Dim>* node,
|
||
|
|
int level): IteratorElement<Dim>(ownId, parentId, node, level),
|
||
|
|
pos(0), used(false) {}
|
||
|
|
|
||
|
|
PathElement(const PathElement<Dim>& p): IteratorElement<Dim>(p),
|
||
|
|
pos(p.pos), used(p.used){}
|
||
|
|
|
||
|
|
PathElement<Dim>& operator=(const PathElement<Dim>& s){
|
||
|
|
IteratorElement<Dim>::operator=(s);
|
||
|
|
pos = s.pos;
|
||
|
|
used = s.used;
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
|
||
|
|
std::ostream& print(std::ostream& os){
|
||
|
|
return IteratorElement<Dim>::print(os) << " , pos = "
|
||
|
|
<< pos << ", used = " << used;
|
||
|
|
}
|
||
|
|
|
||
|
|
int pos;
|
||
|
|
bool used;
|
||
|
|
};
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
Class NoPruner
|
||
|
|
|
||
|
|
Prunes no entry.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
template<class InnerNode>
|
||
|
|
class NoPruner{
|
||
|
|
public:
|
||
|
|
inline bool prune(const InnerNode& node, const int pos) const{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
/*
|
||
|
|
Class IntersectsPruner
|
||
|
|
|
||
|
|
Prunes all entries whose bounding box does not intersect the
|
||
|
|
rectangle given in construction of this class.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
template<unsigned Dim, class InnerNode>
|
||
|
|
class IntersectsPruner{
|
||
|
|
public:
|
||
|
|
IntersectsPruner(const Rectangle<Dim> rect1): rect(rect1){}
|
||
|
|
|
||
|
|
inline bool prune(const InnerNode& node, const int pos) const{
|
||
|
|
return !rect.Intersects(node.getEntry(pos)->getBox());
|
||
|
|
}
|
||
|
|
|
||
|
|
Rectangle<Dim> getBox() const{
|
||
|
|
return rect;
|
||
|
|
}
|
||
|
|
|
||
|
|
private:
|
||
|
|
Rectangle<Dim> rect;
|
||
|
|
|
||
|
|
};
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
Class DepthSearc
|
||
|
|
|
||
|
|
|
||
|
|
This is an iterator class which performs a depth search on a tree.
|
||
|
|
By setting Select and Prune classes this class can be used in a
|
||
|
|
flexible way.
|
||
|
|
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
template<class Tree, class InnerNode, int Dim, class Select, class Pruner>
|
||
|
|
class DepthSearch{
|
||
|
|
public:
|
||
|
|
/*
|
||
|
|
~Constructor~
|
||
|
|
|
||
|
|
*/
|
||
|
|
DepthSearch(Tree* tree1, const Select& select1, const Pruner pruner1):
|
||
|
|
tree(tree1), select(select1), pruner(pruner1){
|
||
|
|
SmiRecordId rid = tree->getRootId();
|
||
|
|
if(rid){
|
||
|
|
init(rid);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
~Next~
|
||
|
|
|
||
|
|
Returns the next node.
|
||
|
|
|
||
|
|
*/
|
||
|
|
bool next(IteratorElement<Dim>& result){
|
||
|
|
if(path.empty()){
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
return next1(result);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*
|
||
|
|
~finish~
|
||
|
|
|
||
|
|
Destroys local variables.
|
||
|
|
|
||
|
|
*/
|
||
|
|
void finish(){
|
||
|
|
while(!path.empty()){
|
||
|
|
PathElement<Dim> p = path.top();
|
||
|
|
delete p.getNode();
|
||
|
|
path.pop();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
std::stack<PathElement<Dim> > getPath()
|
||
|
|
{
|
||
|
|
return path;
|
||
|
|
}
|
||
|
|
|
||
|
|
private:
|
||
|
|
Tree* tree;
|
||
|
|
std::stack<PathElement<Dim> > path;
|
||
|
|
Select select;
|
||
|
|
Pruner pruner;
|
||
|
|
|
||
|
|
/* puts the root of the tree to the path */
|
||
|
|
void init(SmiRecordId rid){
|
||
|
|
BasicNode<Dim>* root = tree->getNode(rid);
|
||
|
|
PathElement<Dim> p(rid, 0, root , 0);
|
||
|
|
path.push(p);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* gets the next objects */
|
||
|
|
bool next1(IteratorElement<Dim>& result){
|
||
|
|
|
||
|
|
while(!path.empty()){
|
||
|
|
|
||
|
|
PathElement<Dim> top = path.top();
|
||
|
|
|
||
|
|
if(!(top.used) ){
|
||
|
|
path.pop();
|
||
|
|
top.used = true;
|
||
|
|
path.push(top);
|
||
|
|
if(select(top.getNode())){
|
||
|
|
IteratorElement<Dim> r(top.getOwnId(), top.getParentId(),
|
||
|
|
top.getNode()->clone(),top.getLevel());
|
||
|
|
result = r;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if(top.getNode()->isLeaf()){ // used leaf found
|
||
|
|
path.pop();
|
||
|
|
delete top.getNode();
|
||
|
|
if(path.empty()){
|
||
|
|
return false;
|
||
|
|
} else {
|
||
|
|
top = path.top();
|
||
|
|
top.pos++;
|
||
|
|
path.pop();
|
||
|
|
path.push(top);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// p contains an inner node
|
||
|
|
while(top.pos == top.getNode()->entryCount()){ // no more sons available
|
||
|
|
path.pop();
|
||
|
|
delete top.getNode();
|
||
|
|
if(path.empty()){
|
||
|
|
return false;
|
||
|
|
} else {
|
||
|
|
top = path.top();
|
||
|
|
top.pos++;
|
||
|
|
path.pop();
|
||
|
|
path.push(top);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
InnerNode* in = dynamic_cast<InnerNode*>(top.getNode());
|
||
|
|
if(!pruner.prune(*in, top.pos)){
|
||
|
|
SmiRecordId sonId = in->getEntry(top.pos)->getInfo().getPointer();
|
||
|
|
BasicNode<Dim>* son = tree->getNode(sonId);
|
||
|
|
PathElement<Dim> p(sonId, top.getOwnId(), son , top.getLevel()+1);
|
||
|
|
path.push(p);
|
||
|
|
} else {
|
||
|
|
path.pop();
|
||
|
|
top.pos++;
|
||
|
|
path.push(top);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
} // end of namespace tbtree
|
||
|
|
|
||
|
|
|
||
|
|
#endif
|
||
|
|
|
||
|
|
|