diff --git a/CgSceneGraph/CgKdTree.cpp b/CgSceneGraph/CgKdTree.cpp deleted file mode 100644 index 77e9fb6af797f49902297db666de20c1929d1ce1..0000000000000000000000000000000000000000 --- a/CgSceneGraph/CgKdTree.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include "CgKdTree.h" - -CgKdTree::CgKdTree() { - -} - -CgKdTree::~CgKdTree() { - m_points.clear(); -} - -void CgKdTree::buildTree(glm::vec3* begin, glm::vec3* end, int depth) { - auto half_size = (end - begin) / 2; - - if(begin == end || half_size == 0) { - // zero or one element, nothing to do - return; - } else { - // more than one element! - - // partially sort and ensure median element - // is in the middle (runs in O(n)) - // about 4x faster on tyra.obj than std::sort - std::nth_element(begin, begin + half_size, end, [=](glm::vec3 a, glm::vec3 b) { - return a[depth % 3] < b[depth % 3]; - }); - - // split array in two (excluding median) and recurse - buildTree(begin, begin + half_size, depth + 1); - buildTree(begin + half_size + 1, end, depth + 1); - } -} - -void CgKdTree::init(std::vector<glm::vec3>& points) { - // copy points for now. - m_points = points; - buildTree(&m_points.front(), &(*(m_points.end() - 1)), 0); -} - -std::vector<int> CgKdTree::getNearestNeighbors(int current_point, unsigned int k) { - std::vector<int> erg(k); - std::iota(erg.begin(), erg.end(), 0); - return erg; -} - -void CgKdTree::traverseBFO(std::function<void(glm::vec3*, const unsigned int)> fn) { - // queue of pairs of vec3 pointers - // (range of points in the current node and its children) - std::queue<std::pair<glm::vec3*, glm::vec3*>> q; - if(m_points.empty()) return; - unsigned int depth = 0; - q.push({&m_points.front(), &(*(m_points.end() - 1))}); - while(!q.empty()) { - int level_count = q.size(); - for(int i = 0; i < level_count; i++) { - auto curr = q.front(); - glm::vec3* begin = curr.first; - glm::vec3* end = curr.second; - unsigned int half_size = (end - begin) / 2; - glm::vec3* curr_pointer = begin + half_size; - fn(curr_pointer, depth); - // push left & right half of array to reconstruct splits - if(half_size != 0) q.push({begin, begin + half_size}); - if(begin + half_size != end) q.push({begin + half_size + 1, end}); - q.pop(); - } - depth += 1; - } -} - -const std::vector<glm::vec3>& CgKdTree::getVertices() const { - return m_points; -} \ No newline at end of file diff --git a/CgSceneGraph/CgKdTree.h b/CgSceneGraph/CgKdTree.h deleted file mode 100644 index 228c39ddcae161e51c65316cb43034e5a2ec86a9..0000000000000000000000000000000000000000 --- a/CgSceneGraph/CgKdTree.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef CGKDTREE_H -#define CGKDTREE_H - -#include <vector> -#include <queue> -#include <glm/glm.hpp> -#include <string> -#include <iostream> -#include <algorithm> -#include <numeric> -#include <utility> -#include <functional> - -class CgKdTree -{ -public: - CgKdTree(); - ~CgKdTree(); - void init(std::vector<glm::vec3>& points); - std::vector<int> getNearestNeighbors(int current_point,unsigned int k); - std::vector<double> getSplits(); - const std::vector<glm::vec3>& getVertices() const; - // traverse the tree in BFO and call a function on each node - void traverseBFO(std::function<void(glm::vec3*, const unsigned int)> fn); - -private: - // builds a kd-tree between the pointers begin and end - void buildTree(glm::vec3* begin, glm::vec3* end, int depth); - std::vector<glm::vec3> m_points; -}; - -#endif // CGKDTREE_H \ No newline at end of file diff --git a/CgSceneGraph/CgPointCloud.cpp b/CgSceneGraph/CgPointCloud.cpp index b79cba5c43af9af8a7c6a729b01cf5df77293162..c419e3f0b6816e4bcf0071d5ab44518e914c319b 100644 --- a/CgSceneGraph/CgPointCloud.cpp +++ b/CgSceneGraph/CgPointCloud.cpp @@ -9,20 +9,15 @@ CgPointCloud::CgPointCloud(51) CgPointCloud::CgPointCloud(int id): m_type(Cg::PointCloud), -m_id(id) -{ - +m_id(id) { m_vertices.push_back(glm::vec3(0.0,0.0,0.0)); m_vertex_normals.push_back(glm::vec3(0.0,0.0,1.0)); m_vertex_colors.push_back(glm::vec3(0.0,0.0,1.0)); - calculateSplatOrientations(); - } -CgPointCloud::~CgPointCloud() -{ +CgPointCloud::~CgPointCloud() { m_vertices.clear(); m_vertex_normals.clear(); m_vertex_colors.clear(); @@ -30,8 +25,7 @@ CgPointCloud::~CgPointCloud() } -void CgPointCloud::calculateSplatOrientations() -{ +void CgPointCloud::calculateSplatOrientations() { // calculate local coordinate system for splats (arbitrary orientation of ellipse in plane) // replace this if you have the real coordinate system, use up vector = y-Axis of your local coordinate system instead of getPerpendicularVector(...) @@ -52,15 +46,6 @@ void CgPointCloud::calculateSplatOrientations() } -CgKdTree* CgPointCloud::getKdTree() { - return &m_kd_tree; -} - -const std::vector<glm::vec3>& CgPointCloud::getVertices() const { - return m_kd_tree.getVertices(); -} - - void CgPointCloud::init( std::string filename, bool cheat_normals) { m_vertices.clear(); @@ -74,44 +59,83 @@ void CgPointCloud::init( std::string filename, bool cheat_normals) ObjLoader loader; loader.load(filename); loader.getPositionData(m_vertices); - m_kd_tree.init(m_vertices); - //run_timed(10, [=]{m_kd_tree.init(m_vertices);}); // do this for cheating with the normals // you need to replace this by a normal estimation algorithm - if(cheat_normals) - loader.getNormalData(m_vertex_normals); + if(cheat_normals) loader.getNormalData(m_vertex_normals); + buildKdTree(&m_vertices.front(), &(*(m_vertices.end() - 1)), 0); - // calculate local coordinate system for splats (arbitrary orientation of ellipse in plane) - // replace this if you have the real coordinate system, use up vector = y-Axis of your local coordinate system instead of getPerpendicularVector(...) - + // calculate local coordinate system for splats + // (arbitrary orientation of ellipse in plane) + // replace this if you have the real coordinate + // system, use up vector = y-Axis of your local + // coordinate system instead of getPerpendicularVector(...) calculateSplatOrientations(); //add a standard color for each point if lighting turned off - for(unsigned int i=0;i<m_vertices.size();i++) - { - m_vertex_colors.push_back(glm::vec3(0.0,1.0,0.0)); - } - - - //test of getNeartestNeighbors(..) method - // generates blue dots on the tail of the bunny + for(unsigned int i=0;i<m_vertices.size();i++) { + m_vertex_colors.push_back(glm::vec3(0.0,1.0,0.0)); + } unsigned int k=50; - std::vector<int> neighbors = m_kd_tree.getNearestNeighbors(0,k); + std::vector<int> neighbors = getNearestNeighbors(0,k); - for(unsigned int i=0;i<k;i++) - { - m_vertex_colors[neighbors[i]]=glm::vec3(0.0,0.0,1.0); - } + for(unsigned int i = 0;i < k; i++) { + m_vertex_colors[neighbors[i]] = glm::vec3(0.0,0.0,1.0); + } } +void CgPointCloud::buildKdTree(glm::vec3* begin, glm::vec3* end, int depth) { + auto half_size = (end - begin) / 2; + + if(begin == end || half_size == 0) { + // zero or one element, nothing to do + return; + } else { + // more than one element! + + // partially sort and ensure median element + // is in the middle (runs in O(n)) + // about 4x faster on tyra.obj than std::sort + std::nth_element(begin, begin + half_size, end, [=](glm::vec3 a, glm::vec3 b) { + return a[depth % 3] < b[depth % 3]; + }); + + // split array in two (excluding median) and recurse + buildKdTree(begin, begin + half_size, depth + 1); + buildKdTree(begin + half_size + 1, end, depth + 1); + } +} -std::vector<int> CgPointCloud::getNearestNeighbors(int current_point,unsigned int k) -{ +void CgPointCloud::traverseBFO(std::function<void(glm::vec3*, const unsigned int)> fn) { + // queue of pairs of vec3 pointers + // (range of points in the current node and its children) + std::queue<std::pair<glm::vec3*, glm::vec3*>> q; + if(m_vertices.empty()) return; + unsigned int depth = 0; + q.push({&m_vertices.front(), &(*(m_vertices.end() - 1))}); + while(!q.empty()) { + int level_count = q.size(); + for(int i = 0; i < level_count; i++) { + auto curr = q.front(); + glm::vec3* begin = curr.first; + glm::vec3* end = curr.second; + unsigned int half_size = (end - begin) / 2; + glm::vec3* curr_pointer = begin + half_size; + fn(curr_pointer, depth); + // push left & right half of array to reconstruct splits + if(half_size != 0) q.push({begin, begin + half_size}); + if(begin + half_size != end) q.push({begin + half_size + 1, end}); + q.pop(); + } + depth += 1; + } +} + +std::vector<int> CgPointCloud::getNearestNeighbors(int current_point,unsigned int k) { - glm::vec3 q= m_vertices[current_point]; + glm::vec3 q = m_vertices[current_point]; std::vector<std::pair<double,int>> distances; diff --git a/CgSceneGraph/CgPointCloud.h b/CgSceneGraph/CgPointCloud.h index 83ddbbcb97246db2f6e246ef1456b2a28c950884..ddbfba204b3082b2074a2fcbfeff26287e7730f5 100644 --- a/CgSceneGraph/CgPointCloud.h +++ b/CgSceneGraph/CgPointCloud.h @@ -2,16 +2,20 @@ #define CGPOINTCLOUD_H #include <vector> +#include <queue> #include <limits> #include <glm/glm.hpp> #include <string> +#include <algorithm> +#include <iostream> +#include <numeric> +#include <utility> +#include <functional> #include "CgBase/CgBasePointCloud.h" -#include "CgSceneGraph/CgKdTree.h" #include "CgSceneGraph/CgAABB.h" #include "CgBase/CgEnums.h" #include "CgUtils/ObjLoader.h" #include <glm/gtc/matrix_transform.hpp> -#include <algorithm> class CgPointCloud : public CgBasePointCloud { @@ -49,14 +53,15 @@ public: // read a dataset from file, can cheat the normals, i.e read the mormals from file void init( std::string filename, bool cheat_normals=false); - CgKdTree* getKdTree(); - // the center of gravity of the object, for rendering const glm::vec3 getCenter() const; // returns the point clouds AABB const CgAABB getAABB() const; + // traverse the kd-tree in BFO and call a function on each node + void traverseBFO(std::function<void(glm::vec3*, const unsigned int)> fn); + private: // the following demonstration methods have to be replaced by your own calculations @@ -68,13 +73,14 @@ private: glm::vec3 getPerpendicularVector(glm::vec3 arg); // for demonstration purposes, very inefficient - std::vector<int> getNearestNeighbors(int current_point,unsigned int k); + std::vector<int> getNearestNeighbors(int current_point, unsigned int k); + // rearrange the vec3 between begin and end so they form a kd-tree + void buildKdTree(glm::vec3* begin, glm::vec3* end, int depth); std::vector<glm::vec3> m_vertices; std::vector<glm::vec3> m_vertex_normals; std::vector<glm::vec3> m_vertex_colors; - CgKdTree m_kd_tree; // indices of vertices for which a splat will be rendered std::vector<unsigned int> m_splat_indices; @@ -85,12 +91,11 @@ private: const Cg::ObjectType m_type; const unsigned int m_id; - - }; inline Cg::ObjectType CgPointCloud::getType() const {return m_type;} inline unsigned int CgPointCloud::getID() const {return m_id;} +inline const std::vector<glm::vec3>& CgPointCloud::getVertices() const{return m_vertices;} inline const std::vector<glm::vec3>& CgPointCloud::getVertexNormals() const{return m_vertex_normals;} inline const std::vector<glm::vec3>& CgPointCloud::getVertexColors() const{return m_vertex_colors;} inline const std::vector<glm::mat4>& CgPointCloud::getSplatOrientations() const{return m_splat_orientations;} diff --git a/CgSceneGraph/CgSceneControl.cpp b/CgSceneGraph/CgSceneControl.cpp index a40c1dd16cfbc9740f55db704971797295b35424..997e33991b5d00b64a0864a2ea22003203400c0d 100644 --- a/CgSceneGraph/CgSceneControl.cpp +++ b/CgSceneGraph/CgSceneControl.cpp @@ -177,7 +177,7 @@ void CgSceneControl::createKdTreeViz(int max_depth) { // recalculate mesh if(m_pointcloud != nullptr && max_depth != -1) { std::vector<double> splits; - m_pointcloud->getKdTree()->traverseBFO([&](glm::vec3* point, unsigned int depth) { + m_pointcloud->traverseBFO([&](glm::vec3* point, unsigned int depth) { splits.push_back((*point)[depth % 3]); }); std::queue<CgAABB> aabb_queue; diff --git a/ExerciseVC.pro b/ExerciseVC.pro index aabdf813e2bb4f62fff05a902764c57e4e50546d..f7cb3432e8ffd2006512908262d5de3db9ae01dd 100644 --- a/ExerciseVC.pro +++ b/ExerciseVC.pro @@ -26,7 +26,6 @@ SOURCES += main.cpp \ CgQtViewer/CgTrackball.cpp \ CgEvents/CgWindowResizeEvent.cpp \ CgSceneGraph/CgTriangleMesh.cpp \ - CgSceneGraph/CgKdTree.cpp \ CgUtils/ObjLoader.cpp \ CgEvents/CgTrackballEvent.cpp @@ -65,7 +64,6 @@ HEADERS += \ CgQtViewer/CgTrackball.h \ CgEvents/CgWindowResizeEvent.h \ CgSceneGraph/CgTriangleMesh.h \ - CgSceneGraph/CgKdTree.h \ CgSceneGraph/CgAABB.h \ CgUtils/ObjLoader.h \ CgUtils/Timer.h \