-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathkd.cpp
118 lines (112 loc) · 2.86 KB
/
kd.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
#include "kd.hpp"
static real variance(std::vector<Point *> &pts, size_t b, size_t e, KDAxis a) {
real mean = 0.0;
real var = 0.0;
switch (a) {
case KDAxis::KDX:
for (size_t i = b; i != e; i++) {
mean += pts[i]->x;
}
mean /= b - e + 1;
for (size_t i = b; i != e; i++) {
real diff = pts[i]->x - mean;
var += diff * diff;
}
return var;
case KDAxis::KDY:
for (size_t i = b; i != e; i++) {
mean += pts[i]->y;
}
mean /= b - e + 1;
for (size_t i = b; i != e; i++) {
real diff = pts[i]->y - mean;
var += diff * diff;
}
return var;
case KDAxis::KDZ:
for (size_t i = b; i != e; i++) {
mean += pts[i]->z;
}
mean /= b - e + 1;
for (size_t i = b; i != e; i++) {
real diff = pts[i]->z - mean;
var += diff * diff;
}
return var;
}
}
static size_t partite(std::vector<Point *> &pts, size_t b, size_t e,
KDAxis a) {
real v;
std::vector<Point *>::iterator h;
size_t mid = (b + e) / 2;
std::swap(pts[b], pts[mid]);
switch (a) {
case KDAxis::KDX:
v = pts[b]->x;
h = std::partition(pts.begin() + b + 1, pts.begin() + e + 1,
[v](Point *x){return x->x <= v;});
break;
case KDAxis::KDY:
v = pts[b]->y;
h = std::partition(pts.begin() + b + 1, pts.begin() + e + 1,
[v](Point *x){return x->y <= v;});
break;
case KDAxis::KDZ:
v = pts[b]->z;
h = std::partition(pts.begin() + b + 1, pts.begin() + e + 1,
[v](Point *x){return x->z <= v;});
break;
}
std::swap(pts[b], *(h - 1));
return h - 1 - pts.begin();
}
static KDAxis max(real &x, real &y, real &z) {
if (x >= y) {
if (x >= z) {
return KDAxis::KDX;
} else {
return KDAxis::KDZ;
}
} else {
if (y >= z) {
return KDAxis::KDY;
} else {
return KDAxis::KDZ;
}
}
}
static real get_coord(Point *p, KDAxis a) {
switch (a) {
case KDAxis::KDX:
return p->x;
case KDAxis::KDY:
return p->y;
case KDAxis::KDZ:
return p->z;
}
}
static KDTree build_rec(std::vector<Point *> &pts, size_t b, size_t e) {
if (b == e) {
KDTreeBase *p = new KDTreeLeaf(pts[b]);
return KDTree(shared_ptr<KDTreeBase>(p));
} else {
real
var_x = variance(pts, b, e, KDAxis::KDX),
var_y = variance(pts, b, e, KDAxis::KDY),
var_z = variance(pts, b, e, KDAxis::KDZ);
KDAxis a = max(var_x, var_y, var_z);
a = KDAxis::KDX;
size_t mid = partite(pts, b, e, a);
if (mid == e) {
mid -= 1;
}
KDTreeNode *p = new KDTreeNode(build_rec(pts, b, mid),
build_rec(pts, mid + 1, e),
a, get_coord(pts[mid], a));
return KDTree(shared_ptr<KDTreeBase>(p));
}
}
KDTree buildKDTree(std::vector<Point *> &pts) {
return build_rec(pts, 0, pts.size() - 1);
}