-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathquick_hull.hpp
145 lines (114 loc) · 4.71 KB
/
quick_hull.hpp
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
140
141
142
143
144
145
#ifndef quick_hull_hpp
#define quick_hull_hpp
#include <vector>
#include <string>
#include <iostream>
#include <utility>
#include "convex_hull_base.hpp"
#include "point.hpp"
#include "line.hpp"
#include "vector2d.hpp"
#include "math_utility.hpp"
namespace csce {
template<typename T>
class quick_hull : public csce::convex_hull_base<T> {
public:
quick_hull(int _nthreads) : csce::convex_hull_base<T>(_nthreads) {}
std::string name() const {
return "Quick Hull";
}
std::vector<csce::point<T>> compute_hull(std::vector<csce::point<T>>& points) {
std::vector<csce::point<T>> hull;
auto left_most_point = get_left_most(points);
hull.push_back(left_most_point);
auto right_most_point = get_right_most(points);
hull.push_back(right_most_point);
line<T> left_to_right = { left_most_point, right_most_point };
line<T> right_to_left = { right_most_point, left_most_point };
auto p = pp(points, left_to_right);
get_hull(p.first, left_to_right, hull);
get_hull(p.second, right_to_left, hull);
return hull;
}
// first has ccw for a -> b, second has cw for a -> b
std::pair<std::vector<csce::point<T>>, std::vector<csce::point<T>>> pp(std::vector<csce::point<T>>& points, csce::line<T>& segment) {
std::pair<std::vector<csce::point<T>>, std::vector<csce::point<T>>> partition;
partition.first = { };
partition.second = { };
for (int i = 0; i < points.size(); i++) {
if (segment.to_vector2d().ccw(csce::vector2d<T>(segment.a, points[i]))) {
partition.first.push_back(points[i]);
} else if (segment.to_vector2d().cw(csce::vector2d<T>(segment.a, points[i]))) {
partition.second.push_back(points[i]);
}
}
return partition;
}
void get_hull(std::vector<csce::point<T>>& points, csce::line<T>& boundary, std::vector<csce::point<T>>& hull) {
if (points.size() == 0) {
return;
}
auto hull_point = find_hull_point(points, boundary);
hull.push_back(hull_point);
csce::line<T> a = { boundary.a, hull_point };
auto left = pp(points, a).first;
csce::line<T> b = { hull_point, boundary.b };
auto right = pp(points, b).first;
get_hull(left, a, hull);
get_hull(right, b, hull);
}
/**
* Has no concept of orientation. Will grab the maximal distance point
* on either side of the boundary. Therefore, must pass a line segment
* that is a boundary (i.e. all points are on one side of the line and
* within the bounds of the boundary end points).
*/
csce::point<T> find_hull_point(std::vector<csce::point<T>>& points, csce::line<T>& boundary) {
if (points.size() == 0) {
throw "No points to find maximal distance!";
}
int index_of_maxial = 0;
for (int i = 1; i < points.size(); i++) {
auto dist = boundary.distance_to(points[i]);
auto max = boundary.distance_to(points[index_of_maxial]);
if (csce::math_utility::less_than(max, dist)) {
index_of_maxial = i;
}
}
return points[index_of_maxial];
}
csce::point<T> get_left_most(std::vector<csce::point<T>>& points) {
if (points.size() == 0) {
throw "There are no points!";
}
csce::point<T> left_most = points[0];
auto start = points.begin();
auto end = points.end();
for (auto current_point = start; current_point != end; current_point++) {
if (left_most.x <= current_point->x) {
continue;
}
left_most = *current_point;
}
return left_most;
}
csce::point<T> get_right_most(std::vector<csce::point<T>>& points) {
if (points.size() == 0) {
throw "There are no points!";
}
csce::point<T> right_most = points[0];
auto start = points.begin();
auto end = points.end();
for (auto current_point = start; current_point != end; current_point++) {
if (right_most.x >= current_point->x) {
continue;
}
right_most = *current_point;
}
return right_most;
}
~quick_hull() {}
private:
};
}
#endif /* quick_hull_hpp */