| #ifndef _HashLink_h
|
| #define _HashLink_h
|
|
|
| #include "HashResult.h"
|
| #include "macros.h"
|
|
|
| #include <math.h>
|
| #include <cstdlib>
|
| #include <iostream>
|
| #include <cstddef>
|
|
|
| struct GeomHashParams {
|
| GeomHashParams(int dim, std::vector<float> cube_sizes, float resize_coefficient)
|
| : dimension(dim), cubeSizes(cube_sizes), resizeCoefficient(resize_coefficient)
|
| {
|
| if (cubeSizes.size() != (unsigned int) dimension) {
|
| std::cerr << "Invalid Parameter: the size of the cube_sizes vector has to be equal to the dimension of the hash" << std::endl;
|
| exit(1);
|
| }
|
| }
|
|
|
| GeomHashParams(int dim, float cube_size, float resize_coefficient)
|
| : dimension(dim), cubeSizes(dim, cube_size), resizeCoefficient(resize_coefficient)
|
| {}
|
|
|
| int dimension;
|
| std::vector<float> cubeSizes;
|
| float resizeCoefficient;
|
| };
|
|
|
| template<class KeyT, class DataT, class Bucket>
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| class HashLink
|
| {
|
| public:
|
| typedef std::vector<const Bucket* > BucketsPointerList;
|
|
|
| private:
|
| HashLink(const HashLink<KeyT, DataT, Bucket>&){
|
| std::cerr<<"HashLinkCC" << std::endl; exit(0);}
|
| protected:
|
|
|
| HashLink();
|
|
|
|
|
| HashLink(const HashLink<KeyT, DataT, Bucket>& hl,const int axis);
|
|
|
|
|
|
|
| static int cube(const float coord, const float cs);
|
|
|
|
|
|
|
| void resize(const int newStart, const int newStop);
|
|
|
|
|
|
|
| void buckResize(const int newStart, const int newStop);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| void put(const KeyT& key, const DataT& data, const GeomHashParams& params,
|
| int axis);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| void getInfinite(const KeyT &key, const float radius, const GeomHashParams& params, int axis,
|
| HashResult<DataT, Bucket>& result) const;
|
|
|
|
|
| void getEuclidean(const KeyT &key, const float radius, const GeomHashParams& params,
|
| int axis,
|
| HashResult<DataT, Bucket>& result) const;
|
|
|
|
|
| void getManhattan(const KeyT &key, const float radius, const GeomHashParams& params,
|
| int axis,
|
| HashResult<DataT, Bucket>& result) const;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| void get(const KeyT &key, const std::vector<float>& radii,
|
| const GeomHashParams& params, int axis,
|
| HashResult<DataT, Bucket>& result) const;
|
|
|
|
|
|
|
|
|
|
|
|
|
| void getAllNotEmpty(int axis, BucketsPointerList *result) const;
|
|
|
|
|
|
|
|
|
| void getAll(int axis, BucketsPointerList *result) const;
|
|
|
|
|
|
|
|
|
|
|
|
|
| const Bucket* getBucket(const KeyT &key, const GeomHashParams& params, int axis) const;
|
|
|
|
|
|
|
|
|
|
|
| void erase(const int axis);
|
|
|
| private:
|
| HashLink* next;
|
| int start, stop;
|
| };
|
|
|
| |
| |
|
|
|
|
| template<class KeyT, class DataT, class Bucket>
|
| HashLink<KeyT, DataT, Bucket>::HashLink(): next(NULL) {}
|
|
|
| template<class KeyT, class DataT, class Bucket>
|
| HashLink<KeyT, DataT, Bucket>::HashLink(const HashLink<KeyT, DataT, Bucket> &hl,const int axis)
|
| {
|
| if(hl.next == NULL){
|
| next=NULL;
|
| return;
|
| }
|
|
|
| start=hl.start;
|
| stop=hl.stop;
|
| unsigned int size = stop - start + 1;
|
|
|
| if (axis) {
|
|
|
| next = (HashLink*)::operator new(size*sizeof(HashLink));
|
|
|
|
|
| HashLink* copyEnd = next+(stop -start);
|
| for (HashLink* p=next, *q=hl.next; p<=copyEnd; ++p, ++q)
|
| *p = HashLink(*q,axis-1);
|
|
|
| }else{
|
| Bucket** newnext = (Bucket**)::operator new(size*sizeof(Bucket*));
|
|
|
|
|
| Bucket** copyEnd = newnext + (stop -start);
|
| for (Bucket** p=newnext, **q=(Bucket**)hl.next; p<=copyEnd; ++p, ++q){
|
| if(*q)
|
| *p = new Bucket(**q);
|
| else
|
| *p=NULL;
|
| }
|
|
|
| next=(HashLink*)newnext;
|
| }
|
| }
|
|
|
| template<class KeyT, class DataT, class Bucket>
|
| int HashLink<KeyT, DataT, Bucket>::cube(const float coord,
|
| const float cs)
|
| {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| if (coord < 0) return (int)(coord/cs) - 1;
|
| else return (int)(coord/cs);
|
| }
|
|
|
| template<class KeyT, class DataT, class Bucket>
|
| void HashLink<KeyT, DataT, Bucket>::resize(const int newStart,
|
| const int newStop)
|
| {
|
|
|
| unsigned int newSize = newStop - newStart + 1;
|
| HashLink* newNext = (HashLink*)::operator new(newSize*sizeof(HashLink));
|
|
|
|
|
| HashLink* copyStart = newNext + (start-newStart);
|
| HashLink* copyEnd = copyStart + (stop -start + 1);
|
| HashLink* newEnd = newNext + newSize;
|
| for (HashLink* p=newNext; p<copyStart; ++p) *p = HashLink();
|
| for (HashLink* p=copyStart, *q=next; p<copyEnd; ++p, ++q) *p = *q;
|
| for (HashLink* p=copyEnd; p<newEnd; ++p) *p = HashLink();
|
|
|
|
|
| ::operator delete(next);
|
|
|
|
|
| next = newNext;
|
| start = newStart;
|
| stop = newStop;
|
| }
|
|
|
| template<class KeyT, class DataT, class Bucket>
|
| void HashLink<KeyT, DataT, Bucket>::buckResize(const int newStart,
|
| const int newStop)
|
| {
|
| unsigned int newSize = newStop - newStart + 1;
|
| Bucket** newNext = (Bucket**)::operator new(newSize*sizeof(Bucket*));
|
|
|
|
|
| Bucket** copyStart = newNext + (start-newStart);
|
| Bucket** copyEnd = copyStart + (stop -start + 1);
|
| Bucket** newEnd = newNext + newSize;
|
| for (Bucket** p=newNext; p<copyStart; ++p)
|
| *p = NULL;
|
| for (Bucket** p=copyStart, **q=(Bucket**)next; p<copyEnd; ++p, ++q)
|
| *p = *q;
|
| for (Bucket** p=copyEnd; p<newEnd; ++p)
|
| *p = NULL;
|
|
|
|
|
| ::operator delete(next);
|
|
|
|
|
| next = (HashLink*)newNext;
|
| start = newStart;
|
| stop = newStop;
|
| }
|
|
|
|
|
| template<class KeyT, class DataT, class Bucket>
|
| void HashLink<KeyT, DataT, Bucket>::put(const KeyT& key, const DataT& data,
|
| const GeomHashParams& params,
|
| const int axis)
|
| {
|
| int pos = cube(key[axis], params.cubeSizes[axis]);
|
|
|
| if (axis) {
|
|
|
|
|
|
|
|
|
|
|
| if (next==NULL) {
|
| start = pos; stop = pos-1;
|
| resize(pos-axis, pos+axis);
|
| }
|
| else if (pos<start)
|
| resize(pos-(int)(params.resizeCoefficient*axis), stop);
|
| else if (pos>stop)
|
| resize(start, pos+(int)(params.resizeCoefficient*axis));
|
|
|
| next[pos-start].put(key, data, params, axis-1);
|
| } else {
|
|
|
|
|
|
|
| if (next==NULL) {
|
| start = pos; stop = pos-1;
|
| buckResize(pos-1, pos+1);
|
| }
|
| else if (pos<start)
|
| buckResize(pos-(int)(params.resizeCoefficient+1), stop);
|
| else if (pos>stop)
|
| buckResize(start, pos+(int)(params.resizeCoefficient+1));
|
|
|
| Bucket** bucket = ((Bucket**)next)+(pos-start);
|
| if (*bucket==NULL) *bucket = new Bucket;
|
| (*bucket)->push_back(data);
|
| }
|
| }
|
|
|
| template<class KeyT, class DataT, class Bucket>
|
| void HashLink<KeyT, DataT, Bucket>::getInfinite(const KeyT &key, const float radius,
|
| const GeomHashParams& params, int axis,
|
| HashResult<DataT, Bucket>& result) const
|
| {
|
| if (next) {
|
|
|
|
|
| int i = cube(key[axis]-radius, params.cubeSizes[axis]);
|
| i = ((start > i) ? start : i) - start;
|
| int to = cube(key[axis]+radius, params.cubeSizes[axis]);
|
| to = ((stop < to) ? stop : to) - start;
|
| if (axis)
|
| for (; i<=to; ++i)
|
| next[i].getInfinite(key, radius, params, axis-1, result);
|
| else
|
| for (Bucket** buckets = (Bucket**)next; i<=to; ++i)
|
| if (buckets[i] != NULL)
|
| result.push_back(buckets[i]);
|
| }
|
| return;
|
| }
|
|
|
|
|
| template<class KeyT, class DataT, class Bucket>
|
| void HashLink<KeyT, DataT, Bucket>::get(const KeyT &key, const std::vector<float>& radii,
|
| const GeomHashParams& params, int axis,
|
| HashResult<DataT, Bucket>& result) const
|
| {
|
| if (next) {
|
|
|
|
|
| int i = cube(key[axis]-radii[axis], params.cubeSizes[axis]);
|
| i = ((start > i) ? start : i) - start;
|
| int to = cube(key[axis] + radii[axis], params.cubeSizes[axis]);
|
| to = ((stop < to) ? stop : to) - start;
|
| if (axis)
|
| for (; i<=to; ++i)
|
| next[i].get(key, radii, params, axis-1, result);
|
| else
|
| for (Bucket** buckets = (Bucket**)next; i<=to; ++i)
|
| if (buckets[i] != NULL)
|
| result.push_back(buckets[i]);
|
| }
|
| return;
|
| }
|
|
|
|
|
| template<class KeyT, class DataT, class Bucket>
|
| void HashLink<KeyT, DataT, Bucket>::getManhattan(const KeyT &key, const float radius,
|
| const GeomHashParams& params, int axis,
|
| HashResult<DataT, Bucket>& result) const
|
| {
|
| if (next) {
|
|
|
|
|
| int i = cube(key[axis]-radius, params.cubeSizes[axis]);
|
| i = ((start > i) ? start : i);
|
| int to = cube(key[axis]+radius, params.cubeSizes[axis]);
|
| to = ((stop < to) ? stop : to);
|
| if (axis) {
|
| int center = cube(key[axis], params.cubeSizes[axis]);
|
| for (; i<=to; ++i) {
|
| if (i==center)
|
| next[i-start].getManhattan(key, radius, params, axis-1, result);
|
| else {
|
| float rdiff;
|
| if (i<center)
|
| rdiff = key[axis]-(i+1) * params.cubeSizes[axis];
|
| else
|
| rdiff = i * params.cubeSizes[axis] - key[axis];
|
| if (rdiff <= radius)
|
| next[i-start].getManhattan(key, radius-rdiff,
|
| params, axis-1, result);
|
| }
|
| }
|
| }
|
| else {
|
| Bucket* buck;
|
| for (Bucket** buckets = (Bucket**)next; i<=to; ++i)
|
| if ((buck = buckets[i-start]) != NULL)
|
| result.push_back(buck);
|
| }
|
| return;
|
| }
|
| }
|
|
|
| template<class KeyT, class DataT, class Bucket>
|
| void HashLink<KeyT, DataT, Bucket>::getEuclidean(const KeyT &key, const float radius,
|
| const GeomHashParams& params, int axis,
|
| HashResult<DataT, Bucket>& result) const
|
| {
|
| if (next) {
|
|
|
|
|
| int i = cube(key[axis]-radius, params.cubeSizes[axis]);
|
| i = ((start > i) ? start : i);
|
| int to = cube(key[axis]+radius, params.cubeSizes[axis]);
|
| to = ((stop < to) ? stop : to);
|
| if (axis) {
|
| int center = cube(key[axis], params.cubeSizes[axis]);
|
| for (; i<=to; ++i) {
|
| if (i==center)
|
| next[i-start].getEuclidean(key, radius, params, axis-1, result);
|
| else {
|
| float rdiff;
|
| if (i<center)
|
| rdiff = key[axis]-(i+1) * params.cubeSizes[axis];
|
| else
|
| rdiff = i* params.cubeSizes[axis] - key[axis];
|
| if (rdiff <= radius)
|
| next[i-start].getEuclidean(key, sqrt(sqr(radius)-sqr(rdiff)),
|
| params, axis-1, result);
|
| }
|
| }
|
| }
|
| else {
|
| Bucket* buck;
|
| for (Bucket** buckets = (Bucket**)next; i<=to; ++i)
|
| if ((buck = buckets[i-start]) != NULL)
|
| result.push_back(buck);
|
| }
|
| return;
|
| }
|
| }
|
|
|
| template<class KeyT, class DataT, class Bucket>
|
| void HashLink<KeyT, DataT, Bucket>::getAllNotEmpty(int axis, BucketsPointerList* result) const
|
| {
|
| if (next) {
|
|
|
|
|
| int i = 0;
|
| int to = stop - start;
|
| if (axis)
|
| for (; i<=to; ++i)
|
| next[i].getAllNotEmpty(axis-1, result);
|
| else
|
| for (Bucket** buckets = (Bucket**)next; i<=to; ++i)
|
| if (buckets[i] != NULL)
|
| result->push_back(buckets[i]);
|
| }
|
| return;
|
| }
|
|
|
| template<class KeyT, class DataT, class Bucket>
|
| void HashLink<KeyT, DataT, Bucket>::getAll(int axis, BucketsPointerList* result) const
|
| {
|
| if (next) {
|
|
|
|
|
| int i = 0;
|
| int to = stop - start;
|
| if (axis)
|
| for (; i<=to; ++i)
|
| next[i].getAll(axis-1, result);
|
| else
|
| for (Bucket** buckets = (Bucket**)next; i<=to; ++i)
|
| result->push_back(buckets[i]);
|
| }
|
| return;
|
| }
|
|
|
| template<class KeyT, class DataT, class Bucket>
|
| const Bucket* HashLink<KeyT, DataT, Bucket>::getBucket(const KeyT &key, const GeomHashParams& params,
|
| int axis) const {
|
| if (next) {
|
|
|
|
|
| int pos = cube(key[axis], params.cubeSizes[axis]);
|
| if (pos >= start && pos <= stop) {
|
| if (axis)
|
| return next[pos-start].getBucket(key, params, axis-1);
|
| else
|
| return *(((Bucket**)next)+pos-start);
|
| }
|
| }
|
| return NULL;
|
| }
|
|
|
| template<class KeyT, class DataT, class Bucket>
|
| void HashLink<KeyT, DataT, Bucket>::erase(const int axis)
|
| {
|
|
|
|
|
| if (next){
|
| if (axis) {
|
| HashLink* from = next;
|
| HashLink* to = next+(stop-start);
|
| for (; from<=to; ++from)
|
| from->erase(axis-1);
|
| }
|
| else {
|
| Bucket** from = (Bucket**)next;
|
| Bucket** to = from+(stop-start);
|
| for (; from<=to; ++from)
|
| if (*from != NULL) delete(*from);
|
| }
|
| ::operator delete(next);
|
|
|
| next=NULL;
|
| }
|
| }
|
|
|
| #endif
|
|
|