-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathquick_hull_parallel.hpp
153 lines (122 loc) · 5.17 KB
/
quick_hull_parallel.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
146
147
148
149
150
151
152
153
#ifndef quick_hull_parallel_hpp
#define quick_hull_parallel_hpp
#include <vector>
#include <string>
#include <iostream>
#include <utility>
#include <thread>
#include <mutex>
#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_parallel : public csce::convex_hull_base<T> {
public:
quick_hull_parallel(int _nthreads) : csce::convex_hull_base<T>(_nthreads) { }
std::string name() const {
return "Quick Hull (Parallel)";
}
std::vector<csce::point<T>> compute_hull(std::vector<csce::point<T>>& points) {
auto left_most_point = get_left_most(points);
this->hull.push_back(left_most_point);
auto right_most_point = get_right_most(points);
this->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 partition = pp(points, left_to_right);
std::thread l_thread(&csce::quick_hull_parallel<T>::get_hull, this, partition.first, left_to_right);
std::thread r_thread(&csce::quick_hull_parallel<T>::get_hull, this, partition.second, right_to_left);
l_thread.join();
r_thread.join();
return this->hull;
}
void get_hull(const std::vector<csce::point<T>>& points, const csce::line<T>& boundary) {
if (points.size() == 0) {
return;
}
auto hull_point = find_hull_point(points, boundary);
this->mut.lock();
this->hull.push_back(hull_point);
this->mut.unlock();
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);
get_hull(right, b);
}
// 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(const std::vector<csce::point<T>>& points, const csce::line<T>& segment) const {
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;
}
/**
* 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(const std::vector<csce::point<T>>& points, const csce::line<T>& boundary) const {
if (points.size() == 0) {
throw "No points to find maximal distance!";
}
int index_of_maximal = 0;
for (int i = 1; i < points.size(); i++) {
auto dist = boundary.distance_to(points[i]);
auto max = boundary.distance_to(points[index_of_maximal]);
if (csce::math_utility::less_than(max, dist)) {
index_of_maximal = i;
}
}
return points[index_of_maximal];
}
csce::point<T> get_left_most(const std::vector<csce::point<T>>& points) const {
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(const std::vector<csce::point<T>>& points) const {
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_parallel() {}
private:
int nthread;
std::vector<csce::point<T>> hull;
std::mutex mut;
};
}
#endif /* quick_hull_parallel_hpp */