-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathBVTree.cpp
139 lines (124 loc) · 4.17 KB
/
BVTree.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// This file contains implementations of the functions in BVTreeQuestion.h.
#include "BVTree.h"
#include <cassert>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
double BVTreeNode::distanceToVolumeSq(const Vec3d & x) const
{
double distSq = 0.0;
for (int i = 0; i != 3; ++i)
{
double dlo = volume_.first[i] - x[i];
double dhi = x[i] - volume_.second[i];
double e = std::max(std::max(dlo, dhi), 0.0);
distSq += e * e;
}
return distSq;
}
static BVTreeNode makeBVTree(std::vector<Vec3d>::iterator start,
std::vector<Vec3d>::iterator end,
const int maxPointsInLeaf)
{
assert(start != end);
// Create bounding volume over the given point set.
int numPoints = 0;
Box volume = {*start, *start};
for (auto itr = start; itr != end; ++itr)
{
const auto & point = *itr;
numPoints++;
for (int i = 0; i < 3; ++i)
{
volume.first[i] = std::min(volume.first[i], point[i]);
volume.second[i] = std::max(volume.second[i], point[i]);
}
}
if (numPoints < maxPointsInLeaf)
{
// Create a leaf node.
auto points = std::vector<Vec3d>(start, end);
return BVTreeNode(volume, std::move(points), {});
}
// Partition the point set into separate volumes with minimal overlap.
int maxDim = -1;
double maxExtent = -1.0;
for (int i = 0; i < 3; ++i)
{
double extent = volume.second[i] - volume.first[i];
assert(extent >= 0.0);
if (extent >= maxExtent)
{
maxExtent = extent;
maxDim = i;
}
}
double midpoint = (volume.first[maxDim] + volume.second[maxDim]) / 2.0;
auto separator =
std::partition(start, end, [=](const Vec3d & point) { return point[maxDim] < midpoint; });
return BVTreeNode(
volume, {},
{makeBVTree(start, separator, maxPointsInLeaf), makeBVTree(separator, end, maxPointsInLeaf)});
}
BVTreeNode makeBVTree(std::vector<Vec3d> points, const int maxPointsInLeaf)
{
assert(!points.empty());
return makeBVTree(points.begin(), points.end(), maxPointsInLeaf);
}
double distanceCalcIn3DSpace(const Vec3d first, const Vec3d second)
{
return std::sqrt(
std::pow(((double)second[0] - double(first[0])), 2.0d)
+
std::pow((double(second[1]) - double(first[1])), 2.0d)
+
std::pow((double(second[2]) - double(first[2])), 2.0d)
);
}
Vec3d nearestPoint(const BVTreeNode & root, const Vec3d & queryPoint)
{
// Coordinate to be returned
static Vec3d nearestCoordinates;
// Height of tree > 1
if (root.children().size() == 1)
{
// No need to compare volumes. Node has only one child.
nearestPoint(root.children()[0], queryPoint);
} else if (root.children().size() > 1)
{
// Initializing the iterative variables equal to the first child
BVTreeNode iter = root.children()[0];
// Divide and Conquer Strategy
if (root.children()[0].distanceToVolumeSq(queryPoint)
>
root.children()[1].distanceToVolumeSq(queryPoint))
{
iter = root.children()[1];
}
// Go one level down the BVH tree.
nearestPoint(iter, queryPoint);
} else
{
// Stop Iterating through the tree
// The current node is the leaf node that should contain the point
// closest to the queryPoint
// Initializing the shortest distance to the query point equal to
// the first point contained inside the node
double shortestDistance = distanceCalcIn3DSpace(root.points()[0],
queryPoint);
nearestCoordinates = root.points()[0];
for(int points_index = 1; points_index < root.points().size();
++points_index)
{
if (shortestDistance > distanceCalcIn3DSpace(root.points()
[points_index], queryPoint))
{
shortestDistance = distanceCalcIn3DSpace(root.points()
[points_index], queryPoint);
nearestCoordinates = root.points()[points_index];
}
}
}
return nearestCoordinates;
}