43template <
class Container>
44auto hullCandidates(
const Container &points_) {
45 using Point = std::remove_cvref_t<
decltype(*std::begin(points_))>;
50 std::vector<Point> points(std::begin(points_), std::end(points_));
54 if (points.size() < 16) {
58 std::vector<decltype(filtered<Number>(points[0]))> approximations;
59 approximations.reserve(points.size());
60 for (
const Point &p : points) {
61 approximations.push_back(filtered<Number>(p));
64 std::size_t lowest = 0, rightmost = 0, highest = 0, leftmost = 0;
65 ApproximatePoint first = approximationOf(approximations[0]);
66 double lowY = first.y.value, highY = first.y.value;
67 double lowX = first.x.value, highX = first.x.value;
68 for (std::size_t i = 1; i < approximations.size(); ++i) {
69 const ApproximatePoint a = approximationOf(approximations[i]);
70 if (a.y.value < lowY) { lowY = a.y.value; lowest = i; }
71 if (a.x.value > highX) { highX = a.x.value; rightmost = i; }
72 if (a.y.value > highY) { highY = a.y.value; highest = i; }
73 if (a.x.value < lowX) { lowX = a.x.value; leftmost = i; }
76 const std::size_t corner[4] = {lowest, rightmost, highest, leftmost};
77 for (
int i = 0; i < 4; ++i) {
78 const auto turn = orientationSignOf(approximations[corner[i]],
79 approximations[corner[(i + 1) % 4]],
80 approximations[corner[(i + 2) % 4]]).value();
86 std::vector<Point> kept;
87 kept.reserve(points.size() / 8 + 16);
88 for (std::size_t i = 0; i < approximations.size(); ++i) {
90 for (
int e = 0; e < 4 && inside; ++e) {
91 inside = orientationSignOf(approximations[corner[e]],
92 approximations[corner[(e + 1) % 4]],
93 approximations[i]).value() > 0;
96 kept.push_back(points[i]);
113template <
class Po
int>
114std::vector<Point> grahamScanOf(
const std::vector<Point> &points,
bool keepCollinear) {
116 std::vector<Point> hull;
117 if (points.empty()) {
121 std::vector<decltype(filtered<Number>(points[0]))> approximations;
122 approximations.reserve(points.size());
123 for (
const Point &p : points) {
124 approximations.push_back(filtered<Number>(p));
127 std::vector<std::size_t> stack;
128 const auto turnsBack = [&](std::size_t candidate) {
129 const auto sign = orientationSignOf(approximations[stack[stack.size() - 2]],
130 approximations[stack.back()],
131 approximations[candidate]).value();
132 return keepCollinear ? sign < 0 : sign <= 0;
136 for (std::size_t i = 0; i < points.size(); ++i) {
137 while (stack.size() >= 2 && turnsBack(i)) {
144 const std::size_t lower_size = stack.size();
145 for (std::size_t i = points.size() - 1; i-- != 0;) {
146 while (stack.size() > lower_size && turnsBack(i)) {
152 if (stack.size() >= 2) {
156 hull.reserve(stack.size());
157 for (std::size_t i : stack) {
158 hull.push_back(points[i]);
176template<
class Container>
178 std::vector points = detail::hullCandidates(points_);
180 std::sort(points.begin(), points.end());
183 points.erase(std::unique(points.begin(), points.end()), points.end());
185 return detail::grahamScanOf(points,
false);
198template<
class Container>
200 std::vector points = detail::hullCandidates(points_);
202 std::sort(points.begin(), points.end());
205 points.erase(std::unique(points.begin(), points.end()), points.end());
207 return detail::grahamScanOf(points,
true);
221template<
class Container>
236template<
class Container>
Definition arrangement.hpp:67
auto grahamScanExtended(const Container &points_)
Computes the convex hull of a point container using Graham's scan.
Definition convexhull.hpp:199
auto convexHull(const Container &points_)
Computes the convex hull of a point container.
Definition convexhull.hpp:222
auto grahamScan(const Container &points_)
Computes the convex hull of a point container using Graham's scan.
Definition convexhull.hpp:177
auto convexHullExtended(const Container &points_)
Computes the convex hull of a point container.
Definition convexhull.hpp:237
Bichromatic (red-blue) boundary contact by one combined plane sweep.
TNumber NumberType
Definition point.hpp:131