KDTree.cpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. #include <algorithm>
  2. #include "common/utils/KDTree.h"
  3. KDTree::Triangle::Triangle(const Vector3& a, const Vector3& b, const Vector3& c) {
  4. v[0] = a;
  5. v[1] = b;
  6. v[2] = c;
  7. mid = (a + b + c) * (1.0f / 3.0f);
  8. }
  9. const Array<Vector3, 3>& KDTree::Triangle::data() const {
  10. return v;
  11. }
  12. const Vector3& KDTree::Triangle::operator[](int index) const {
  13. return v[index];
  14. }
  15. const Vector3& KDTree::Triangle::getMid() const {
  16. return mid;
  17. }
  18. KDTree::Node::Node() : splitDim(0), splitValue(0.0f), lessEqual(nullptr), greater(nullptr) {
  19. }
  20. KDTree::KDTree() {
  21. }
  22. KDTree::~KDTree() {
  23. clean(&root);
  24. }
  25. void KDTree::clean(Node* n) {
  26. if(n->lessEqual != nullptr) {
  27. clean(n->lessEqual);
  28. }
  29. if(n->greater != nullptr) {
  30. clean(n->greater);
  31. }
  32. delete n->lessEqual;
  33. delete n->greater;
  34. }
  35. void KDTree::build(std::vector<KDTree::Triangle>& data) {
  36. build(&root, data);
  37. }
  38. float KDTree::median(std::vector<KDTree::Triangle>& data, int dim) const {
  39. auto compare = [dim](const Triangle& a, const Triangle & b) {
  40. return a.getMid()[dim] < b.getMid()[dim];
  41. };
  42. size_t length = data.size();
  43. if((length & 1) == 0) {
  44. std::nth_element(data.begin(), data.begin() + (length / 2 - 1), data.end(), compare);
  45. float tmp = data[length / 2 - 1].getMid()[dim];
  46. std::nth_element(data.begin(), data.begin() + (length / 2), data.end(), compare);
  47. return (tmp + data[length / 2].getMid()[dim]) / 2;
  48. }
  49. std::nth_element(data.begin(), data.begin() + (length / 2), data.end(), compare);
  50. return data[length / 2].getMid()[dim];
  51. }
  52. void KDTree::build(Node* n, std::vector<KDTree::Triangle>& data) {
  53. if(data.size() == 0) {
  54. return;
  55. } else if(data.size() == 1) {
  56. n->data.push_back(data[0]);
  57. return;
  58. }
  59. // find min and max coordinates
  60. Vector3 min = data[0][0];
  61. Vector3 max = data[0][0];
  62. for(const Triangle& t : data) {
  63. for(const Vector3& v : t.data()) {
  64. min.set(std::min(min[0], v[0]), std::min(min[1], v[1]), std::min(min[2], v[2]));
  65. max.set(std::max(max[0], v[0]), std::max(max[1], v[1]), std::max(max[2], v[2]));
  66. }
  67. }
  68. // find biggest span and its dimension
  69. int splitDim = 0;
  70. float maxSpan = max[0] - min[0];
  71. for(int i = 1; i < 3; i++) {
  72. float span = max[i] - min[i];
  73. if(span > maxSpan) {
  74. splitDim = i;
  75. maxSpan = span;
  76. }
  77. }
  78. // assign data to node
  79. n->splitDim = splitDim;
  80. n->splitValue = median(data, splitDim);
  81. // storage for split data
  82. std::vector<KDTree::Triangle> lessEqualData;
  83. std::vector<KDTree::Triangle> greaterData;
  84. // actually split the data
  85. for(const Triangle& t : data) {
  86. // count points on each split side
  87. int lessEqualCounter = 0;
  88. int greaterCount = 0;
  89. for(const Vector3& v : t.data()) {
  90. if(v[n->splitDim] <= n->splitValue) {
  91. lessEqualCounter++;
  92. } else {
  93. greaterCount++;
  94. }
  95. }
  96. // put the data in the correct container
  97. if(lessEqualCounter == 3) {
  98. lessEqualData.push_back(t);
  99. } else if(greaterCount == 3) {
  100. greaterData.push_back(t);
  101. } else {
  102. n->data.push_back(t);
  103. }
  104. }
  105. // recursive calls
  106. if(lessEqualData.size() > 0) {
  107. n->lessEqual = new Node();
  108. build(n->lessEqual, lessEqualData);
  109. }
  110. if(greaterData.size() > 0) {
  111. n->greater = new Node();
  112. build(n->greater, greaterData);
  113. }
  114. }