kick
/Users/morten/Programmering/cpp/kick/src/kick/math/kd_tree.cpp
00001 #include "kick/math/kd_tree.h"
00002 
00003 #include <algorithm>
00004 #include <cmath>
00005 
00006 using namespace std;
00007 using namespace glm;
00008 
00009 namespace kick {
00010     KDTreeNodeRef::KDTreeNodeRef()
00011     :id(-1) {
00012 
00013     }
00014 
00015     KDTreeNodeRef::KDTreeNodeRef(const KDTreeNodeRef &other)
00016             :id(other.id){
00017         for (int i=0;i<3;i++){
00018             triangle[i] = other.triangle[i];
00019         }
00020     }
00021 
00022     AABB KDTreeNodeRef::getAABB() const {
00023         AABB res;
00024         for (int i=0;i<3;i++){
00025             res.addPoint(triangle[i]);
00026         }
00027         return res;
00028     }
00029 
00030     bool KDTreeNodeRef::intersectRay(const Ray &ray, KDTreeHitInfo &hit) const {
00031         vec3 intersectionPoint;
00032         bool res = ray.intersectTriangle(triangle[0], triangle[1], triangle[2], intersectionPoint);
00033         float len = length(intersectionPoint - ray.origin());
00034         if (res && len < hit.distance){
00035             hit.distance = len;
00036             hit.collisionPoint = intersectionPoint;
00037             hit.hit = this;
00038         }
00039         return res;
00040     }
00041 
00042 
00043 // ___________________________________________________
00044 
00045     KDTreeNode::KDTreeNode(const AABB &aabb)
00046             : leftChild(NULL), rightChild(NULL), aabb(aabb) {
00047 
00048     }
00049 
00050     bool KDTreeNode::isLeaf() {
00051         return leftChild == NULL && rightChild == NULL;
00052     }
00053 
00054 // ___________________________________________________
00055 
00056 
00057     KDTree::KDTree()
00058             : rootNode(NULL) {
00059     }
00060 
00061 
00062     KDTree::~KDTree(void) {
00063     }
00064 
00065     void KDTree::init(std::vector<KDTreeNodeRef> &objectList, AABB &aabb) {
00066         this->objectList = objectList;
00067         this->aabb = aabb;
00068         this->rootNode = recursiveBuild(objectList, aabb, 0);
00069     }
00070 
00071     bool KDTree::first_intersection(Ray &ray, KDTreeHitInfo& hit) {
00072         float tNear, tFar;
00073         int aNear, aFar;
00074         bool intersected = aabb.intersect(ray, tNear, tFar,aNear, aFar);
00075         if (!intersected) {
00076             return false;
00077         }
00078 
00079         return intersect(this->rootNode, ray, hit, ray.origin());
00080 
00081     }
00082 
00083 // returns true if it has collisions inside aabb
00084     bool KDTree::intersect(KDTreeNode *child, const Ray &ray, KDTreeHitInfo& hit, vec3 startPoint) {
00085         bool collision = false;
00086         if (child->isLeaf()) {
00087             for (auto& node : child->objects) {
00088                 if (node.intersectRay(ray, hit)){
00089                     vec3 collisionPos = hit.collisionPoint;
00090                     collision = child->aabb.contains(collisionPos);
00091                 }
00092             }
00093         } else {
00094             float directionDelta = ray.direction()[child->splittingAxis];
00095 
00096             if (directionDelta < 0 && ray.origin()[child->splittingAxis] < child->splittingPlane) {
00097                 // only consider left child
00098                 collision = intersect(child->leftChild,  ray, hit, startPoint);
00099             } else if (directionDelta > 0 && ray.origin()[child->splittingAxis] > child->splittingPlane) {
00100                 // only consider right child
00101                 collision = intersect(child->rightChild, ray, hit, startPoint);
00102             } else {
00103                 // collision with splitting plane
00104                 if (directionDelta > 0) {
00105                     // if direction is from min to max (left to right)
00106                     collision = intersect(child->leftChild, ray, hit, startPoint);
00107                     if (!collision) {
00108                         float fNear, fFar;
00109                         int aNear, aFar;
00110                         if (child->rightChild->aabb.intersect(ray, fNear, fFar,aNear, aFar)) {
00111                             vec3 splitPlaneIntersect = ray.origin() + ray.direction() * fNear;
00112                             Ray newRay{splitPlaneIntersect, ray.direction()};
00113                             collision = intersect(child->rightChild, newRay, hit, startPoint);
00114                         }
00115                     }
00116                 } else {
00117                     // if direction is from min to max (left to right)
00118                     collision = intersect(child->rightChild, ray, hit, startPoint);
00119                     if (!collision) {
00120                         float fNear, fFar;
00121                         int aNear, aFar;
00122                         if (child->leftChild->aabb.intersect(ray, fNear, fFar,aNear, aFar)) {
00123                             vec3 splitPlaneIntersect = ray.origin() + ray.direction() * fNear;
00124                             Ray newRay{splitPlaneIntersect, ray.direction()};
00125                             collision = intersect(child->leftChild, newRay, hit, startPoint);
00126                         }
00127                     }
00128                 }
00129             }
00130         }
00131 
00132         return collision;
00133     }
00134 
00135     KDTreeNode *KDTree::recursiveBuild(const std::vector<KDTreeNodeRef>& objectList, AABB &aabb, int currentDepth) {
00136         KDTreeNode *res = new KDTreeNode(aabb);
00137         if (terminateBuild(objectList, aabb, currentDepth)) {
00138             for (const KDTreeNodeRef & nodeRef : objectList) {
00139                 res->objects.push_back(nodeRef);
00140             }
00141             return res;
00142         }
00143         findPlane(objectList, aabb, currentDepth, res);
00144 
00145         // split aabb with splitting plane
00146         AABB leftAabb(aabb);
00147         leftAabb.max[res->splittingAxis] = res->splittingPlane;
00148         AABB rightAabb(aabb);
00149         rightAabb.min[res->splittingAxis] = res->splittingPlane;
00150 
00151         vector < KDTreeNodeRef > leftObjects;
00152         vector < KDTreeNodeRef > rightObjects;
00153         for (const KDTreeNodeRef & nodeRef : objectList) {
00154             const AABB objectAABB = nodeRef.getAABB();
00155             if (leftAabb.intersect(objectAABB)) {
00156                 leftObjects.push_back(nodeRef);
00157             }
00158             if (rightAabb.intersect(objectAABB)) {
00159                 rightObjects.push_back(nodeRef);
00160             }
00161         }
00162         currentDepth++;
00163         res->leftChild = recursiveBuild(leftObjects, leftAabb, currentDepth);
00164         res->rightChild = recursiveBuild(rightObjects, rightAabb, currentDepth);
00165         return res;
00166     }
00167 
00168     KDTreeNaive::KDTreeNaive(int treeDepth, int minVoxelObjects)
00169             : KDTree(), treeDepth(treeDepth), minVoxelObjects(minVoxelObjects) {
00170     }
00171 
00172     void KDTreeNaive::findPlane(const std::vector<KDTreeNodeRef>& objectList, AABB &aabb, int currentDepth, KDTreeNode *node) {
00173         int axis = 0;
00174         vec3 len = aabb.max - aabb.min;
00175         float maxLen = 0;
00176         for (int i = 0; i < 3; i++) {
00177             if (len[i] > maxLen) {
00178                 maxLen = len[i];
00179                 axis = i;
00180             }
00181         }
00182         node->splittingAxis = axis;
00183         node->splittingPlane = 0.5f * (aabb.min[axis] + aabb.max[axis]);
00184     }
00185 
00186     bool KDTreeNaive::terminateBuild(const std::vector<KDTreeNodeRef>& objectList, AABB &aabb, int currentDepth) {
00187         return currentDepth == this->treeDepth || objectList.size() < minVoxelObjects;
00188     }
00189 }
 All Classes Functions Variables