Skip to content

Commit 2883eaa

Browse files
committed
temp check
1 parent db4d4ba commit 2883eaa

3 files changed

Lines changed: 185 additions & 0 deletions

File tree

src/generic/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
add_subdirectory(common)
2+
add_subdirectory(convex_hull)
23
add_subdirectory(digital_filter)
34
add_subdirectory(polynomial)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
add_executable(test_convex_hull convex_hull.cpp)
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
#include <algorithm>
2+
#include <iostream>
3+
#include <optional>
4+
5+
template <typename T>
6+
struct Point {
7+
T x;
8+
T y;
9+
};
10+
11+
/**
12+
* @brief Get the Cross Product of segment (a, b) and (a, c)
13+
*
14+
* Example:
15+
* W(3, 4)
16+
* V(5, 2)
17+
* (0,0)
18+
*
19+
* V x W = VxWy - WxVy
20+
* = | 5 3 |
21+
* | 2 4 |
22+
* = (5 * 4) - (2 * 3) = 14 (counter-clockwise)
23+
*
24+
* @tparam T
25+
* @param a
26+
* @param b
27+
* @param c
28+
* @return T positive for counter-clockwise, negative for clockwise, zero for
29+
* collinear
30+
*/
31+
template <typename T>
32+
T GetCrossProduct(const Point<T> &a, const Point<T> &b, const Point<T> &c) {
33+
return ((b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x));
34+
}
35+
36+
template <typename T>
37+
Point<T> SwapAndGetFirstPoint(std::vector<Point<T>> &points) {
38+
auto iterator = std::min_element(
39+
points.begin(), points.end(), [](const Point<T> a, const Point<T> b) {
40+
return ((a.y < b.y) || ((a.y == b.y) && (a.x < b.x)));
41+
});
42+
auto old_first_point = points[0];
43+
points[0] = *iterator;
44+
*iterator = old_first_point;
45+
return points[0];
46+
}
47+
48+
template <typename T>
49+
std::vector<Point<T>> GetConvexHull(std::vector<Point<T>> &points) {
50+
if (points.size() < 3) {
51+
return std::vector<Point<T>>{};
52+
}
53+
auto first_point = SwapAndGetFirstPoint(points);
54+
std::sort(points.begin() + 1, points.end(),
55+
[&](const Point<T> &b, const Point<T> &c) {
56+
return (GetCrossProduct(first_point, b, c) < 0);
57+
});
58+
59+
std::vector<Point<T>> result;
60+
auto it = points.begin();
61+
62+
auto value = *it++;
63+
std::cout << "Adding... " << value.x << " " << value.y << std::endl;
64+
65+
result.push_back(value);
66+
67+
value = *it++;
68+
std::cout << "Adding... " << value.x << " " << value.y << std::endl;
69+
70+
result.push_back(value);
71+
72+
value = *it++;
73+
std::cout << "Adding... " << value.x << " " << value.y << std::endl;
74+
75+
result.push_back(value);
76+
77+
while (it != points.end()) {
78+
// StepConverge
79+
// Pop off any points that make a convex angle with *it
80+
while (GetCrossProduct(*(result.rbegin() + 1), *(result.rbegin()), *it) >=
81+
0) {
82+
std::cout << "Popping out: " << result.back().x << " " << result.back().y
83+
<< std::endl;
84+
result.pop_back();
85+
}
86+
87+
auto value = *it++;
88+
std::cout << "Adding... " << value.x << " " << value.y << std::endl;
89+
result.push_back(value);
90+
}
91+
92+
return result;
93+
}
94+
95+
template <typename T>
96+
class ConvexHull {
97+
public:
98+
using Callback = std::function<void(const Point<T> &)>;
99+
explicit ConvexHull(const std::vector<Point<T>> &points)
100+
: points_(points), current_index_(0) {
101+
auto first_point = SwapAndGetFirstPoint(points_);
102+
std::sort(points_.begin() + 1, points_.end(),
103+
[&](const Point<T> &b, const Point<T> &c) {
104+
return (GetCrossProduct(first_point, b, c) < 0);
105+
});
106+
initialize_first_three_points_ = true;
107+
}
108+
109+
std::optional<std::vector<Point<T>>> StepForward(Callback insert_callback,
110+
Callback pop_callback) {
111+
if (points_.size() < 3) {
112+
return std::nullopt;
113+
} else {
114+
if (initialize_first_three_points_) {
115+
for (auto i = 0; i < 3; ++i) {
116+
InsertCurrentValueWithCallback(insert_callback);
117+
}
118+
initialize_first_three_points_ = false;
119+
return std::nullopt;
120+
}
121+
}
122+
123+
if (current_index_ < points_.size()) {
124+
if (GetCrossProduct(*(results_.rbegin() + 1), *(results_.rbegin()),
125+
points_.at(current_index_)) >= 0) {
126+
PopCurrentValueWithCallback(pop_callback);
127+
} else {
128+
InsertCurrentValueWithCallback(insert_callback);
129+
}
130+
} else {
131+
return results_;
132+
}
133+
134+
return std::nullopt;
135+
}
136+
137+
private:
138+
void InsertCurrentValueWithCallback(Callback insert_callback) {
139+
const auto value = points_.at(current_index_);
140+
insert_callback(value);
141+
results_.push_back(value);
142+
current_index_++;
143+
}
144+
145+
void PopCurrentValueWithCallback(Callback pop_callback) {
146+
pop_callback(results_.back());
147+
results_.pop_back();
148+
}
149+
150+
std::vector<Point<T>> points_;
151+
std::vector<Point<T>> results_;
152+
size_t current_index_;
153+
bool initialize_first_three_points_;
154+
};
155+
156+
int main() {
157+
auto points = std::vector<Point<int>>{{0, 3}, {1, 1}, {2, 2}, {4, 4},
158+
{0, 0}, {1, 2}, {3, 1}, {3, 3}};
159+
auto result = GetConvexHull(points);
160+
std::cout << "Results" << std::endl;
161+
for (const auto value : result) {
162+
std::cout << value.x << " " << value.y << std::endl;
163+
}
164+
165+
std::cout << "-------------------" << std::endl;
166+
auto convex_hull = ConvexHull(points);
167+
while (convex_hull.StepForward(
168+
[](const Point<int> &point) {
169+
std::cout << "Adding... " << point.x << " " << point.y
170+
<< std::endl;
171+
},
172+
[](const Point<int> &point) {
173+
std::cout << "Popping out: " << point.x << " " << point.y
174+
<< std::endl;
175+
}) == std::nullopt) {
176+
}
177+
auto new_result = convex_hull.StepForward([](const Point<int> &) {},
178+
[](const Point<int> &) {});
179+
std::cout << "Results" << std::endl;
180+
for (const auto value : *new_result) {
181+
std::cout << value.x << " " << value.y << std::endl;
182+
}
183+
}

0 commit comments

Comments
 (0)