/* 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 #include #include 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 inline void writeRectangle(const Rectangle& 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 inline void readRectangle(Rectangle& 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 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 class Entry{ public: /* Constructors */ Entry() {} Entry(const Rectangle& b,const Info& i): box(b), info(i) {} Entry(const Entry& src): box(src.box), info(src.info) {} /* Assignment operator */ Entry& operator=(const Entry& e){ this->box = e.box; this->info = e.info; return *this; } inline bool operator==(const Entry& e) const{ return (this->box == e.box) && (this->info==e.info); } /* Destructor */ ~Entry() {} /* Getter */ inline const Rectangle 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(box, buffer, offset); info.writeTo(buffer, offset); } /* Reading from a buffer */ inline void readFrom(const char* buffer,unsigned int& offset) { readRectangle(box, buffer, offset); info.readFrom(buffer, offset); } /* Required BufferSize */ inline static int bufferSize(){ return rectBufferSize() + Info::bufferSize(); } /* Let the box be the union of the original box and b; */ inline void addBox(const Rectangle& 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 box; Info info; }; /* class BasicNode This is the super class for all types of nodes. */ template class BasicNode{ public: /* 1 Constructors */ BasicNode(uint16_t min1, uint16_t max1): min(min1), max(max1), current(0) {} BasicNode(const BasicNode& src): min(src.min), max(src.max), current(src.current) {} /* 2 Assignment operator */ BasicNode& operator=(const BasicNode& src){ this->min = src.min; this->max = src.max; this->current = src.current; return *this; } /* 3 Comparison */ inline bool operator==(const BasicNode& 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 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* 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 class Node : public BasicNode{ public: /* 4.1 Constructors */ Node(int min1, int max1): BasicNode(min1,max1){ entries = new Entry*[BasicNode::max +1]; for(int i=0;i::max+1; i++){ entries[i] = 0; } } Node(const Node& src) : BasicNode(src){ entries = new Entry*[BasicNode::max +1]; for(int i=0;i< src.entryCount(); i++){ this->entries[i] = new Entry(*(src.entries[i])); } for(int i=src.entryCount(); i::max; i++){ this->entries[i] = 0; } } /* 4.2 Assignment operator */ Node& operator=(const Node& src) { // first, delete all included entries for(int i=0; i< BasicNode::current; i++){ delete entries[i]; entries[i] = 0; } // if the size is different, adopt it if(BasicNode::max!=src.max){ delete[] entries; entries = new Entry*[src.max+1]; } BasicNode::operator=(src); for(int i=0;i< BasicNode::current; i++){ entries[i] = new Entry(*(src.entries[i])); } } /* 4.3 Comparision */ bool operator==(const Node& n) const{ if(! (BasicNode::operator==(n))){ return false; } for(int i=0;i::current; i++){ if(!( *(this->entries[i]) == *(n.entries[i]))){ return false; } } return true; } /* 4.4 Destructor */ virtual ~Node(){ for(int i=0;i::current;i++){ delete entries[i]; } BasicNode::current = 0; delete[] entries; entries = 0; } /* 4.5 ~deleteEntries~ Removes all entries from this node. */ inline void deleteEntries() { for(int i=0;i::current;i++){ delete entries[i]; } BasicNode::current = 0; } /* 4.6 ~getEntry~ Returns the entry at the given position. */ inline const Entry* getEntry(int index) const{ assert(index::current); return entries[index]; } /* 4.7 ~getBox~ Returns the union of all boxes of all entries. */ inline virtual Rectangle getBox() const{ if(BasicNode::current==0){ Rectangle r(false); return r; } else { Rectangle res(entries[0]->getBox()); for(int i=1; i< BasicNode::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::current; memcpy(buffer+offset, &c, sizeof(uint16_t)); offset += sizeof(uint16_t); for(int i=0; i< BasicNode::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::current; i++){ delete entries[i]; entries[i] = 0; } uint16_t c; memcpy(&c, buffer+offset, sizeof(uint16_t)); BasicNode::current = c; offset += sizeof(uint16_t); for(int i=0; i< BasicNode::current; i++){ entries[i] = new Entry(); 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::current*Entry::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::bufferSize(); } /* 4.12 ~isFull~ Returns true if no more elements can be inserted into this node. */ inline bool isFull() const{ return BasicNode::current == BasicNode::max -1; } /* 4.12 ~insert~ Appends a new entry. If there is an overflow, the result will be true. */ inline bool insert(const Entry& e){ assert(BasicNode::current <= BasicNode::max); entries[BasicNode::current] = new Entry(e); BasicNode::current++; return BasicNode::current==BasicNode::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& 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::current); delete entries[index]; BasicNode::current--; for(int i=index; i::current; i++){ entries[i] = entries[i+1]; } entries[BasicNode::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 e){ assert(pos < BasicNode::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::min <<", " << BasicNode::max << ", " << BasicNode::current << "] ::{" ; for(int i=0;i::current;i++){ entries[i]->print(os); } os << "}])"; return os; } protected: Entry** entries; }; /* Class ~QNodeSplitter~ This class provides some functions to split a node into 2 new ones using quadratic split algorithm. */ template class QNodeSplitter{ public: std::pair*, Node* > splitNode(Node& node){ std::pair seeds = pickSeeds(node); int index1 = seeds.first; int index2 = seeds.second; Node* node1 = node.getEmptyNode(); Node* 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;iinsert(*node.getEntry(i)); } node.deleteEntries(); }else if(node.entryCount() + node2->entryCount() == min){ for(int i=0;iinsert(*(node.getEntry(i))); } node.deleteEntries(); } else { std::pair 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 node_type; std::pair pickSeeds(const node_type& n) const{ std::pair res; double d = 0; for(int i=0;i r1(n.getEntry(i)->getBox()); Rectangle 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 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 b1 = grpone->getBox(); Rectangle b2 = grptwo->getBox(); double a1 = b1.Area(); double a2 = b2.Area(); for(int i=1;ientryCount();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 = d1entryCount()!=grptwo->entryCount()){ bestgrp = grpone->entryCount()entryCount()? 1:2; } else { // all criterions failed bestgrp = 1; } } } std::pair res; res.first = index; res.second = bestgrp; return res; } }; /* 5 class TBLeafNode */ template class TBLeafNode : public Node{ public: /* 5.1 Constructors */ TBLeafNode() {} TBLeafNode(int min, int max, int trjid1): Node(min,max), next(0), trjid(trjid1){} TBLeafNode(const TBLeafNode& src): Node(src), next(src.next), trjid(src.trjid){ } /* 5.2 Assignment Operator */ inline TBLeafNode& operator=(const TBLeafNode& src){ Node::operator=(src); this->next = src.next; this->trjid = src.trjid; return *this; } /* 5.3 Comparison */ inline bool operator==(const TBLeafNode& ln)const{ return Node::operator==(ln) && this->next == ln.next && this->trjid == ln.trjid; } /* 5.4 Destructor */ virtual ~TBLeafNode(){ Node::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::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::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::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::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* getEmptyNode() const{ return new TBLeafNode(BasicNode::min, BasicNode::max, 0); } /* Prints out this node. */ virtual std::ostream& print(std::ostream& os)const{ return Node::print(os) << next << endl; } /* Returns a clone of this node. */ inline virtual BasicNode* clone() const{ return new TBLeafNode(*this); } private: SmiRecordId next; int trjid; }; /* 5 class InnerNode */ template class InnerNode : public Node{ public: /* 5.1 Constructors */ InnerNode(const int min1, const int max1): Node(min1, max1) {} InnerNode(const InnerNode& src): Node(src) {} /* 5.2 Assignment operator */ inline InnerNode& operator=(const InnerNode& src) { return Node::operator=(src); } /* 5.3 Comparison */ inline bool operator==(const InnerNode& in) const{ return Node::operator==(in); } /* 5.4 Destructor */ virtual ~InnerNode(){ Node::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& r) const{ assert( (Node::current)>0); int res = 0; Rectangle r1(Node::entries[0]->getBox()); double diff = r1.Union(r).Area() - r1.Area(); for(int i=1; i< (Node::current); i++){ r1 = Node::entries[i]->getBox(); double diff2 = r1.Union(r).Area() - r1.Area(); if(diff2* getEmptyNode() const{ return new InnerNode(BasicNode::min, BasicNode::max); } /* ~clone~ Returns a clone of this node. */ inline virtual BasicNode* clone() const{ return new InnerNode(*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::getMax(buffersize); } }; /* 5 Class PathEntry This class supports the searchNode function of a tbtree. */ template struct pathEntry{ public: pathEntry(const SmiRecordId id1, BasicNode* 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* 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 > path; TBLeafNode<3, TBLeafInfo>* newLeaf(0); SmiRecordId id(0); if(searchNode(rootId, path, e, trjid)) { TBLeafNode<3, TBLeafInfo>* leaf = dynamic_cast* > (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& 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*>(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("FilePurpose", "SecondaryTBTreetreeIndexFile")); result.push_back(std::pair( "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* >(n); std::vector trajid; std::vector > list1; std::vector > 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* >(node); trajid.push_back(leafnode->getTrjId()); } else{ innernode = dynamic_cast* >(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::iterator end; end = unique(trajid.begin(),trajid.end()); std::vector::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*>(n1); const TBLeafNode<3, TBLeafInfo>* ln2 = dynamic_cast*>(n2); return *ln1 == *ln2; } else { const InnerNode<3, InnerInfo>* in1 = dynamic_cast*>(n1); const InnerNode<3, InnerInfo>* in2 = dynamic_cast*>(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 >& 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*> (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* >(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 >& 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* >(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 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 insertLeafRec(const SmiRecordId rootId, const SmiRecordId& id, const Rectangle<3>& rect, const int level){ BasicNode<3>* root = readNode(rootId); if(root->isLeaf()){ std::pair res(rootId, id); delete root; return res; } else { InnerNode<3, InnerInfo>* iroot = dynamic_cast*>(root); int sonIndex = iroot->selectBestNode(rect); SmiRecordId sonId = iroot->getEntry(sonIndex)->getInfo().getPointer(); std::pair 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>* > 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 class IteratorElement{ public: /* ~Constructors~ */ IteratorElement(): ownId(0),parentId(0), node(0), level(0){} IteratorElement(SmiRecordId ownId1, SmiRecordId parentId1, BasicNode* node1, int level1): ownId(ownId1), parentId(parentId1), node(node1), level(level1) {} IteratorElement( const IteratorElement& s): ownId(s.ownId), parentId(s.parentId), node(s.node), level(s.level) {} /* Assignment operator */ IteratorElement& operator=(const IteratorElement& 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* 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* node; // the node int level; // level (0 = root) }; /* Class PathElement For internal use within the DepthSearch class. */ template class PathElement: public IteratorElement{ public: PathElement(SmiRecordId ownId, SmiRecordId parentId, BasicNode* node, int level): IteratorElement(ownId, parentId, node, level), pos(0), used(false) {} PathElement(const PathElement& p): IteratorElement(p), pos(p.pos), used(p.used){} PathElement& operator=(const PathElement& s){ IteratorElement::operator=(s); pos = s.pos; used = s.used; return *this; } std::ostream& print(std::ostream& os){ return IteratorElement::print(os) << " , pos = " << pos << ", used = " << used; } int pos; bool used; }; /* Class NoPruner Prunes no entry. */ template 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 class IntersectsPruner{ public: IntersectsPruner(const Rectangle rect1): rect(rect1){} inline bool prune(const InnerNode& node, const int pos) const{ return !rect.Intersects(node.getEntry(pos)->getBox()); } Rectangle getBox() const{ return rect; } private: Rectangle 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 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& result){ if(path.empty()){ return false; } return next1(result); } /* ~finish~ Destroys local variables. */ void finish(){ while(!path.empty()){ PathElement p = path.top(); delete p.getNode(); path.pop(); } } std::stack > getPath() { return path; } private: Tree* tree; std::stack > path; Select select; Pruner pruner; /* puts the root of the tree to the path */ void init(SmiRecordId rid){ BasicNode* root = tree->getNode(rid); PathElement p(rid, 0, root , 0); path.push(p); } /* gets the next objects */ bool next1(IteratorElement& result){ while(!path.empty()){ PathElement top = path.top(); if(!(top.used) ){ path.pop(); top.used = true; path.push(top); if(select(top.getNode())){ IteratorElement 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(top.getNode()); if(!pruner.prune(*in, top.pos)){ SmiRecordId sonId = in->getEntry(top.pos)->getInfo().getPointer(); BasicNode* son = tree->getNode(sonId); PathElement 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