diff --git a/Makefile b/Makefile index a055b5a..1167306 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,13 @@ FLAGS = -std=c++11 -O3 -Wall -Werror -LIBS = -lrt -all: example.out +all: example.out wrap-example.out example.out: test/example.cpp ${CXX} $(FLAGS) -o $@ $^ $(LIBS) +wrap-example.out: test/wrap-example.cpp + ${CXX} $(FLAGS) -o $@ $^ $(LIBS) chaff-init: - git subtree add --prefix src/chaff https://github.com/xavierholt/chaff.git master --squash + git subtree add --prefix src/chaff https://github.com/xavierholt/chaff.git master --squash chaff-pull: - git subtree pull --prefix src/chaff https://github.com/xavierholt/chaff.git master --squash + git subtree pull --prefix src/chaff https://github.com/xavierholt/chaff.git master --squash clean: - rm -f example.out + rm -f example.out wrap-example.out diff --git a/src/nodes/all.h b/src/nodes/all.h index 91a546c..5c6245f 100644 --- a/src/nodes/all.h +++ b/src/nodes/all.h @@ -2,23 +2,27 @@ template class Node; template class Leaf; template class Tree; template class Twig; +template class Wrap; #include "node.h" #include "leaf.h" #include "tree.h" #include "twig.h" +#include "wrap.h" template Node* Tree::insert(const typename CORE::Item& item) { - int c = child(CORE::point(item)); - if(mNodes[c]) { - mNodes[c] = mNodes[c]->insert(item); + const Coord c = CORE::coordinate(CORE::point(item), this->mAxis); + const int i = (c > this->mMidpoint); + + if(mNodes[i]) { + mNodes[i] = mNodes[i]->insert(item); } else if(this->mDepth + 1 < CORE::MAX_DEPTH) { - mNodes[c] = new Twig(this, item); + mNodes[i] = new Twig(this, item); } else { - mNodes[c] = new Leaf(this, item); + mNodes[i] = new Leaf(this, item); } return this; diff --git a/src/nodes/leaf.h b/src/nodes/leaf.h index 1df3bff..38e182e 100644 --- a/src/nodes/leaf.h +++ b/src/nodes/leaf.h @@ -21,6 +21,10 @@ template class Leaf : public Node mItems[0] = item; } + Leaf* asLeaf() { + return this; + } + public: ~Leaf() { delete [] mItems; diff --git a/src/nodes/node.h b/src/nodes/node.h index d8d438c..feac628 100644 --- a/src/nodes/node.h +++ b/src/nodes/node.h @@ -39,7 +39,7 @@ template class Node mMidpoint = (mMinima[mAxis] + mMaxima[mAxis]) / 2; } - Node(const Point& min, const Point& max): mDepth(0), mAxis(0) { + Node(const Point& min, const Point& max, int depth = 0): mDepth(depth), mAxis(depth % CORE::DIMENSIONS) { for(int i = 0; i < CORE::DIMENSIONS; ++i) { mMinima[i] = CORE::coordinate(min, i); mMaxima[i] = CORE::coordinate(max, i); @@ -59,6 +59,11 @@ template class Node return result; } + virtual Leaf* asLeaf() {return 0;} + virtual Tree* asTree() {return 0;} + virtual Twig* asTwig() {return 0;} + virtual Wrap* asWrap() {return 0;} + public: virtual ~Node() { // Nothing to do. diff --git a/src/nodes/tree.h b/src/nodes/tree.h index 014bc06..d05dee3 100644 --- a/src/nodes/tree.h +++ b/src/nodes/tree.h @@ -17,8 +17,8 @@ template class Tree : public Node mNodes[1] = 0; } - int child(const Point& point) const { - return (CORE::coordinate(point, this->mAxis) > this->mMidpoint); + Tree* asTree() { + return this; } public: @@ -37,9 +37,11 @@ template class Tree : public Node Node* insert(const Item& item); Node* remove(const Item& item) { - int c = child(CORE::point(item)); - if(mNodes[c]) { - mNodes[c] = mNodes[c]->remove(item); + const Coord c = CORE::coordinate(CORE::point(item), this->mAxis); + const int i = (c > this->mMidpoint); + + if(mNodes[i]) { + mNodes[i] = mNodes[i]->remove(item); if(mNodes[0] == 0 && mNodes[1] == 0 && this->mDepth != 0) { delete this; return 0; @@ -50,15 +52,15 @@ template class Tree : public Node } void search(const Point& point, Finder& finder) const { - Coord diff = CORE::coordinate(point, this->mAxis) - this->mMidpoint; - int idx = (diff > 0); + const Coord d = CORE::coordinate(point, this->mAxis) - this->mMidpoint; + const int i = (d > 0); - if(mNodes[idx]) { - mNodes[idx]->search(point, finder); + if(mNodes[i]) { + mNodes[i]->search(point, finder); } - if(diff * diff < finder.score() && mNodes[idx ^ 1]) { - mNodes[idx ^ 1]->search(point, finder); + if(d * d < finder.score() && mNodes[i ^ 1]) { + mNodes[i ^ 1]->search(point, finder); } } }; diff --git a/src/nodes/twig.h b/src/nodes/twig.h index 984ef79..7b02b4c 100644 --- a/src/nodes/twig.h +++ b/src/nodes/twig.h @@ -18,6 +18,10 @@ template class Twig : public Node mItems[0] = item; } + Twig* asTwig() { + return this; + } + public: Node* insert(const Item& item) { if(mCount >= CORE::STORAGE) { diff --git a/src/nodes/wrap.h b/src/nodes/wrap.h new file mode 100644 index 0000000..c3129fa --- /dev/null +++ b/src/nodes/wrap.h @@ -0,0 +1,75 @@ +template class Wrap : public Node +{ + typedef typename CORE::Item Item; + typedef typename CORE::Point Point; + typedef typename CORE::Coord Coord; + typedef Chaff::MinFinder Finder; + +protected: + Node* mChild; + +protected: + Wrap(const Point& min, const Point& max, int wraps, int depth): Node(min, max, depth) { + if(wraps > 1) { + mChild = new Wrap(min, max, wraps - 1, depth + 1); + } + else { + mChild = new Tree(min, max); + } + } + + Wrap* asWrap() { + return this; + } + + template + static T mod(T num, T dnm) { + num -= int(num / dnm) * dnm; + return num + dnm * (num < 0); + } + +public: + Wrap(const Point& min, const Point& max, int wraps = CORE::DIMENSIONS): Node(min, max) { + if(wraps > 1) { + mChild = new Wrap(min, max, wraps - 1, 1); + } + else { + mChild = new Tree(min, max); + } + } + + ~Wrap() { + delete mChild; + } + + Node* insert(const Item& item) { + mChild->insert(item); + return this; + } + + Node* remove(const Item& item) { + mChild->remove(item); + return this; + } + + void search(const Point& point, Finder& finder) const { + const Coord min = this->mMinima[this->mAxis]; + const Coord max = this->mMaxima[this->mAxis]; + const Coord rng = max - min; + const Coord val = mod(point[this->mAxis] - min, rng) + min; + + Point scratch(point); + scratch[this->mAxis] = val; + mChild->search(scratch, finder); + + if(finder.score() > val - min) { + scratch[this->mAxis] = val + rng; + mChild->search(scratch, finder); + } + + if(finder.score() > max - val) { + scratch[this->mAxis] = val - rng; + mChild->search(scratch, finder); + } + } +}; diff --git a/test/wrap-example.cpp b/test/wrap-example.cpp new file mode 100644 index 0000000..618a2f1 --- /dev/null +++ b/test/wrap-example.cpp @@ -0,0 +1,46 @@ +#include "../src/tree.h" +#include + +struct Point +{ + float data[3]; + + Point() {} + Point(float x, float y, float z) { + data[0] = x; + data[1] = y; + data[2] = z; + } + + float& operator [] (int i) { + return data[i]; + } + + float operator [] (int i) const { + return data[i]; + } + + bool operator == (const Point& p) const { + return data[0] == p[0] && data[1] == p[1] && data[2] == p[2]; + } + + friend std::ostream& operator << (std::ostream& s, const Point& p) { + return s << '(' << p[0] << ", " << p[1] << ", " << p[2] << ')'; + } +}; + +int main() { + typedef KD::Core<3, Point> CORE; + + Point min(0, 0, 0); + Point max(8, 8, 8); + KD::Wrap kdtree(min, max); + + kdtree.insert(Point(1, 2, 3)); + kdtree.insert(Point(8, 2, 5)); + kdtree.insert(Point(1, 0, 8)); + kdtree.insert(Point(3, 1, 4)); + + std::cout << kdtree.nearest(Point(8, 8, 8)) << std::endl; + return 0; +}