Files
secondo/Algebras/RIndex/RIndex.h
2026-01-23 17:03:45 +08:00

687 lines
14 KiB
C++

/*
1 General class
*/
#include "../Rectangle/RectangleAlgebra.h"
/*
1 The Index class
*/
template<int rdim, typename T, int cdim> class RIndexNode;
template <int dim, class T>
class RIndex{
public:
/*
1.1 Constructor
This constructor creates a new empty index;
*/
RIndex():root(0){}
/*
1.2 Destructor
The index is destroyed
*/
~RIndex(){
if(root){
delete root;
root = 0;
}
}
/*
1.3 Insert
Inserts a pair consisting of a rectangle and data belonging to this rectangle
into this index;
*/
void insert(const Rectangle<dim> & r,
const T& t){
if(!r.IsDefined()){
return;
}
if(root){
root->insert(r,t);
} else {
root = new RIndexNode<dim, T, dim>(r,t);
}
}
/*
1.4 Erase
This function removes an entry from the index. If the entry was not found, the
result of this function is false, true otherwise.
*/
bool erase(const Rectangle<dim>& r, const T& t){
if(!r.IsDefined()){
return false;
}
if(!root){
return false;
}
bool found = false;
RIndexNode<dim, T, dim>* newRoot = root->erase(r,t,found);
if(newRoot == 0){
delete root;
root = 0;
}
return found;
}
/*
1.5 findsimple
This functions collects all rectangles insersecting the parameter
rectangle and stores them
into res. This function is just for checking the structure.
*/
void findSimple(const Rectangle<dim>& r,
std::vector<std::pair<Rectangle<dim> , T> >& res){
res.clear();
if(!r.IsDefined()){
return;
}
if(root){
root->findSimple(r,res);
}
}
/*
1.6 countEntries
Returns the number of elements even if their are erased.
*/
uint32_t countEntries(){
if(root){
return root->countEntries();
} else {
return 0;
}
}
/*
1.8 height
Returns the height of a tree (0, iff tree is empty, 1 for a single leaf).
*/
uint32_t height(){
if(!root){
return 0;
} else {
return root->height();
}
}
uint32_t noLeafs(){
if(!root){
return 0;
} else {
return root->noLeafs();
}
}
uint32_t dim0Entries(){
if(!root){
return 0;
} else {
return root->dim0Entries();
}
}
uint32_t dim0Leafs(){
if(!root){
return 0;
} else {
return root->dim0Leafs();
}
}
uint32_t maxBranches(){
if(!root){
return 0;
} else {
return root->maxBranches();
}
}
uint32_t branches(){
if(!root){
return 0;
} else {
return root->branches();
}
}
size_t usedMem(){
if(!root){
return sizeof(*this);
} else {
return sizeof(*this) + root->usedMem();
}
}
/*
TODO:
Implementing an iterator class and a find function
*/
private:
RIndexNode<dim, T, dim>* root;
};
/*
2 Implementation of a single node
*/
template<int rdim, typename T, int cdim>
class RIndexNode{
public:
/*
2.1 Constructor
This constructor creates a single node without sons.
*/
RIndexNode(const Rectangle<rdim> r, const T& t):
rect(r), data(t), bbox(r), erased(false){
quadrants = new RIndexNode<rdim, T, cdim>*[ (1 << cdim) ];
planes = new RIndexNode<rdim, T, cdim-1>*[cdim];
for(int i=0; i< (1 << cdim) ; i++){
quadrants[i] = 0;
}
for(int i=0;i<cdim; i++){
planes[i] = 0;
}
}
/*
2.2 Destructor
Destroys this node and all subtrees.
*/
~RIndexNode(){
for(int i=0;i< (1 << cdim); i++){
if(quadrants[i]){
delete quadrants[i];
quadrants[i] = 0;
}
}
for(int i=0;i<cdim; i++){
if(planes[i]){
delete planes[i];
planes[i] = 0;
}
}
delete[] quadrants;
delete[] planes;
}
/*
2.3 Insert
Inserts a new entry into this subtree.
*/
void insert(const Rectangle<rdim>& r, const T& t){
bbox = bbox.Union(r);
int i = 0;
bool usePlanes = getSon(r,i);
if(usePlanes){
if(planes[i]){
planes[i]->insert(r,t);
} else {
planes[i] = new RIndexNode<rdim,T,cdim-1>(r,t);
}
} else {
if(quadrants[i]){
quadrants[i]->insert(r,t);
} else {
quadrants[i] = new RIndexNode<rdim,T,cdim>(r,t);
}
}
}
/*
2.4 Erase
Removes an entry from this structure.
The parameter found must be initialized with false to get a correct result.
The return value is this node or 0, if this subtree becomes empty.
*/
RIndexNode<rdim, T, cdim>* erase(const Rectangle<rdim>& r,
const T& t, bool& found){
if( (rect==r) && (t==data) && (!erased) ){
// this node is remove
found = true;
if(isLeaf() ){
erased = true;
return 0;
} else {
erased = true;
return this;
}
}
// try to find the victim within a subtree
int i=0;
bool isPlane = getSon(r,i);
if(isPlane){
if(!planes[i]){ // not found
return this;
} else {
RIndexNode<rdim,T,cdim-1>* newSon = planes[i].erase(r,t);
if(newSon==0){
delete planes[i];
planes[i] = 0;
if(erased && isLeaf()){
return 0;
} else {
updateBBox();
return this;
}
} else {
planes[i] = newSon;
return this;
}
}
} else { // victim is in a quadrant
if(!quadrants[i]){
return this; // not found
} else {
RIndexNode<rdim, T, cdim>* newSon = quadrants[i].earse(r,t);
if(newSon==0){
delete quadrants[i];
quadrants[i] = 0;
if(erased && isLeaf()){
return 0;
} else {
updateBBox();
return this;
}
}
}
}
}
void findSimple(const Rectangle<rdim>& r,
std::vector<std::pair<Rectangle<rdim> , T> >& res){
if(!bbox.Intersects(r)){
return;
}
if(rect.Intersects(r)){
std::pair<Rectangle<rdim> , T> p(rect,data);
res.push_back(p);
}
for(int i=0;i<cdim; i++){
if(planes[i]){
planes[i]->findSimple(r,res);
}
}
// we don't check whether we have to search for a special
// quadrant because the bounding box
// check will do it
for(int i=0; i< (1 << cdim) ; i++){
if(quadrants[i]){
quadrants[i]->findSimple(r,res);
}
}
}
uint32_t countEntries(){
uint32_t sum = 0;
for(int i=0;i<cdim; i++){
if(planes[i]){
sum += planes[i]->countEntries();
}
}
// we don't check whether we have to search for a
// special quadrant because the bounding box
// check will do it
for(int i=0; i< (1 << cdim) ; i++){
if(quadrants[i]){
sum += quadrants[i]->countEntries();
}
}
return sum + 1;
}
uint32_t height(){
uint32_t h = 0;
for(int i=0;i<cdim; i++){
if(planes[i]){
uint32_t h2 = planes[i]->height();
h = h>h2?h:h2;
}
}
for(int i=0; i< (1 << cdim) ; i++){
if(quadrants[i]){
uint32_t h2 = quadrants[i]->height();
h = h>h2?h:h2;
}
}
return h + 1;
}
const Rectangle<rdim>& getBBox() const{
return bbox;
}
uint32_t noLeafs(){
int count = 0;
for(int i=0;i<cdim; i++){
if(planes[i]){
count += planes[i]->noLeafs();
}
}
for(int i=0; i< (1 << cdim) ; i++){
if(quadrants[i]){
count += quadrants[i]->noLeafs();
}
}
return count>0?count:1;
}
uint32_t dim0Entries(){
int count = 0;
for(int i=0;i<cdim; i++){
if(planes[i]){
count += planes[i]->dim0Entries();
}
}
return count;
}
uint32_t dim0Leafs(){
int count = 0;
for(int i=0;i<cdim; i++){
if(planes[i]){
count += planes[i]->dim0Leafs();
}
}
return count;
}
uint32_t maxBranches(){
int branches = 0;
for(int i=0;i<cdim; i++){
if(planes[i]){
branches += planes[i]->maxBranches();
}
}
for(int i=0; i< (1 << cdim) ; i++){
if(quadrants[i]){
branches += quadrants[i]->maxBranches();
}
}
return branches + cdim + (1 << cdim);
}
uint32_t branches(){
int branches = 0;
for(int i=0;i<cdim; i++){
if(planes[i]){
branches++;
branches += planes[i]->branches();
}
}
for(int i=0; i< (1 << cdim) ; i++){
if(quadrants[i]){
branches++;
branches += quadrants[i]->branches();
}
}
return branches;
}
size_t usedMem(){
int mem = 0;
for(int i=0;i<cdim; i++){
if(planes[i]){
mem += planes[i]->usedMem();
}
}
for(int i=0; i< (1 << cdim) ; i++){
if(quadrants[i]){
mem += quadrants[i]->usedMem();
}
}
return mem + sizeof(*this);;
}
private:
Rectangle<rdim> rect; // the assigned rectangle
T data; // the assigned data
Rectangle<rdim> bbox; // bounding box of the complete subtree
bool erased; // mark for deleted entry
RIndexNode<rdim, T, cdim>** quadrants; // sons for the quadrants
RIndexNode<rdim, T, cdim-1>** planes;// sons for all planes
/*
2.3 getSon
*/
// returns true, if this rectangle must be inserted into planes
// returns false, if the rectangle must be inserted into quadrants
// the index is set to the appropriate index within the corresponding array
bool getSon(const Rectangle<rdim>& r, int& index) const{
// check planes
for(int i=0;i<cdim; i++){
if( (r.MinD(i)<=rect.MinD(i)) && (r.MaxD(i)>=rect.MinD(i))){
index = i;
return true;
}
}
index = 0;
for(int i=0; i<cdim; i++){
if(r.MaxD(i) < rect.MinD(i)){
index |= (1 << i);
}
}
return false;
}
int noSons() const{
int sum = 0;
for(int i=0;i<cdim;i++){
if(planes[i]){
sum++;
}
}
for(int i=0;i< (1<< cdim); i++){
if(quadrants[i]){
sum++;
}
}
return sum;
}
bool isLeaf() const{
for(int i=0;i<cdim;i++){
if(planes[i]){
return false;
}
}
for(int i=0;i< (1<< cdim); i++){
if(quadrants[i]){
return false;
}
}
return true;
}
// computes the bbox from the stored rectangle and the bboxes from the sons
void updateBBox(){
bbox = rect;
for(int i=0;i<cdim;i++){
if(planes[i]){
bbox = bbox.Union(planes[i]->bbox);
}
}
for(int i=0;i < (1 << cdim); i++){
if(quadrants[i]){
bbox = bbox.Union(quadrants[i]->bbox);
}
}
}
};
/*
2 Specialisation for cdim == 1
*/
template<int rdim, typename T>
class RIndexNode<rdim, T,0>{
public:
RIndexNode(const Rectangle<rdim> r, const T& t){
bbox = r;
insert(r,t);
}
~RIndexNode(){
}
void insert(const Rectangle<rdim>& r, const T& t){
bbox = bbox.Union(r);
std::pair<Rectangle<rdim>,T> p(r,t);
content.push_back(p);
}
RIndexNode<rdim, T , 1>* erase(const Rectangle<rdim>& r,
const T& t, bool& found){
assert(false); // not implemented yet
}
void findSimple(const Rectangle<rdim>& r,
std::vector<std::pair<Rectangle<rdim> , T> >& res){
if(!bbox.Intersects(r)){
return;
}
typename std::vector<std::pair<Rectangle<rdim>,T> >::iterator it;
for(it = content.begin(); it!=content.end(); it++){
if(it->first.Intersects(r)){
res.push_back(*it);
}
}
}
uint32_t countEntries(){
return content.size();
}
const Rectangle<rdim>& getBBox(){
return bbox;
}
uint32_t height(){
return 1;
}
uint32_t noLeafs(){ // at dimension 0, we have a leaf in each case
return 1;
}
uint32_t dim0Entries(){
return content.size();
}
uint32_t dim0Leafs(){
return 1;
}
uint32_t branches() {
return 0;
}
uint32_t maxBranches(){
return 0;
}
size_t usedMem(){
return sizeof(*this) +
sizeof(std::pair<Rectangle<rdim>,T>) * content.capacity();
}
private:
Rectangle<rdim> bbox;
std::vector<std::pair<Rectangle<rdim>,T> > content;
};