diff --git a/CgQtViewer/CgQtGui.cpp b/CgQtViewer/CgQtGui.cpp index 30dd7d2c3dccf582c27222d98dc440062024f73f..4cc60893dceeedaf96fe967cebf681f0c5bc9ba9 100644 --- a/CgQtViewer/CgQtGui.cpp +++ b/CgQtViewer/CgQtGui.cpp @@ -156,7 +156,7 @@ void CgQtGui::createKdTreeOptionPanel(QWidget* parent) /* label */ - QLabel *max_depth_label = new QLabel("depth limit (0 for none):"); + QLabel *max_depth_label = new QLabel("depth limit:"); tab1_control->addWidget(max_depth_label); max_depth_label->setAlignment(Qt::AlignTop); max_depth_label->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed); @@ -165,9 +165,9 @@ void CgQtGui::createKdTreeOptionPanel(QWidget* parent) max_kd_depth_spinbox = new QSpinBox(); tab1_control->addWidget(max_kd_depth_spinbox); - max_kd_depth_spinbox->setMinimum(0); + max_kd_depth_spinbox->setMinimum(1); max_kd_depth_spinbox->setMaximum(50); - max_kd_depth_spinbox->setValue(0); + max_kd_depth_spinbox->setValue(7); connect(max_kd_depth_spinbox, SIGNAL(valueChanged(int) ), this, SLOT(slotKdDepthSpinboxChanged()) ); tab1_control->addWidget(max_kd_depth_spinbox); max_kd_depth_spinbox->setAlignment(Qt::AlignTop); diff --git a/CgSceneGraph/CgKdTree.cpp b/CgSceneGraph/CgKdTree.cpp index 1725edb87229e99cd30e1dc51c7708eb458d590b..77e9fb6af797f49902297db666de20c1929d1ce1 100644 --- a/CgSceneGraph/CgKdTree.cpp +++ b/CgSceneGraph/CgKdTree.cpp @@ -1,58 +1,39 @@ #include "CgKdTree.h" -// nodes -CgKdTree::TreeNode::TreeNode(glm::vec3 point) { - m_point = point; - m_lower = nullptr; - m_higher = nullptr; -} - -CgKdTree::TreeNode::~TreeNode() { - if(m_lower) delete m_lower; - if(m_higher) delete m_higher; -} - -// kdtree API CgKdTree::CgKdTree() { } CgKdTree::~CgKdTree() { m_points.clear(); - if(m_root) delete m_root; } -// builds a kd-tree out of the glm::vec3 between -// begin (inclusive) and end (exklusive) -CgKdTree::TreeNode* CgKdTree::buildTree(glm::vec3* begin, glm::vec3* end, int depth) { +void CgKdTree::buildTree(glm::vec3* begin, glm::vec3* end, int depth) { auto half_size = (end - begin) / 2; - if(begin == end) { // array is empty - return nullptr; - } else if(half_size == 0) { // there is one element - return new CgKdTree::TreeNode(*begin); - } else { // more than one element! + 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)) + // 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]; }); - // create node with median point - auto node = new CgKdTree::TreeNode(begin[half_size]); // split array in two (excluding median) and recurse - node->m_lower = buildTree(begin, begin + half_size, depth + 1); - node->m_higher = buildTree(begin + half_size + 1, end, depth + 1); - - return node; + 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; - m_root = buildTree(&points.front(), &(*(points.end() - 1)), 0); + buildTree(&m_points.front(), &(*(m_points.end() - 1)), 0); } std::vector<int> CgKdTree::getNearestNeighbors(int current_point, unsigned int k) { @@ -61,23 +42,31 @@ std::vector<int> CgKdTree::getNearestNeighbors(int current_point, unsigned int k return erg; } -// return the locations of the split planes in a breadth-first manner -std::vector<double> CgKdTree::getSplits() { - std::vector<double> erg; - std::queue<CgKdTree::TreeNode*> q; - if(m_root == nullptr) return erg; - int depth = 0; - q.push(m_root); +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++) { - CgKdTree:TreeNode* curr = q.front(); - erg.push_back(curr->m_point[depth % 3]); - if(curr->m_lower != nullptr) q.push(curr->m_lower); - if(curr->m_higher != nullptr) q.push(curr->m_higher); + 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; } - return erg; +} + +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 index 3077dee555212a7d5da46bdb4c4f9b18d782f063..228c39ddcae161e51c65316cb43034e5a2ec86a9 100644 --- a/CgSceneGraph/CgKdTree.h +++ b/CgSceneGraph/CgKdTree.h @@ -8,6 +8,8 @@ #include <iostream> #include <algorithm> #include <numeric> +#include <utility> +#include <functional> class CgKdTree { @@ -17,23 +19,14 @@ public: 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: - class TreeNode - { - private: - TreeNode(glm::vec3 point); - ~TreeNode(); - glm::vec3 m_point; - TreeNode* m_lower; - TreeNode* m_higher; - friend class CgKdTree; - }; -private: - CgKdTree::TreeNode* m_root; - CgKdTree::TreeNode* buildTree(glm::vec3* begin, glm::vec3* end, int depth); + // 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 14ada35a6356ef90c3a66e10594623677e4d0a92..b79cba5c43af9af8a7c6a729b01cf5df77293162 100644 --- a/CgSceneGraph/CgPointCloud.cpp +++ b/CgSceneGraph/CgPointCloud.cpp @@ -1,8 +1,4 @@ #include "CgPointCloud.h" -#include "CgBase/CgEnums.h" -#include "CgUtils/ObjLoader.h" -#include <glm/gtc/matrix_transform.hpp> -#include <algorithm> CgPointCloud::CgPointCloud(): @@ -60,6 +56,10 @@ 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) { diff --git a/CgSceneGraph/CgPointCloud.h b/CgSceneGraph/CgPointCloud.h index dc32281f35931fc25b437d3d6f4e475d4eb4a698..83ddbbcb97246db2f6e246ef1456b2a28c950884 100644 --- a/CgSceneGraph/CgPointCloud.h +++ b/CgSceneGraph/CgPointCloud.h @@ -8,6 +8,10 @@ #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 { @@ -25,7 +29,7 @@ public: //inherited from CgBasePointCloud // vertex positions in local coordinates - const std::vector<glm::vec3>& getVertices() const; + const std::vector<glm::vec3>& getVertices() const; // normal directions in local coordinates (normalized) const std::vector<glm::vec3>& getVertexNormals() const; @@ -87,7 +91,6 @@ private: 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 fba8257a8c696309086e8c1437ba0b589abe560e..a40c1dd16cfbc9740f55db704971797295b35424 100644 --- a/CgSceneGraph/CgSceneControl.cpp +++ b/CgSceneGraph/CgSceneControl.cpp @@ -175,9 +175,11 @@ void CgSceneControl::createKdTreeViz(int max_depth) { m_kd_tree_mesh.clear(); // recalculate mesh - max_depth = max_depth == 0 ? 7 : max_depth; if(m_pointcloud != nullptr && max_depth != -1) { - std::vector<double> splits = m_pointcloud->getKdTree()->getSplits(); + std::vector<double> splits; + m_pointcloud->getKdTree()->traverseBFO([&](glm::vec3* point, unsigned int depth) { + splits.push_back((*point)[depth % 3]); + }); std::queue<CgAABB> aabb_queue; aabb_queue.push(m_pointcloud->getAABB()); unsigned int index = 0; @@ -197,7 +199,7 @@ void CgSceneControl::createKdTreeViz(int max_depth) { span1[current_axis] = 0.0; span2[current_axis] = 0.0; span2[next_axis] = -span2[next_axis]; - CgQuad* new_quad = new CgQuad(34 + index, quad_position, span1, span2); + CgQuad* new_quad = new CgQuad(1000 + index, quad_position, span1, span2); m_renderer->init(new_quad); m_kd_tree_mesh.push_back(new_quad); @@ -533,7 +535,6 @@ void CgSceneControl::renderObjects() m_current_transformation = m_current_transformation * orientations[splat_indices[i]]; m_current_transformation = glm::translate(m_current_transformation,m_center); - } } }