#include <iostream>
#include <vector>
#include <algorithm>
struct Point {
float x;
float y;
};
// returns cross product p0p1 x p0p2
float direction(Point p0, Point p1, Point p2) {
return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y);
}
// returns squared distance between given points
float distSquared(Point a, Point b) {
return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
}
std::vector<Point> FindConvexHull(std::vector<Point> &points) {
// find minimum point
auto minimumIterator = std::min_element(points.begin(), points.end(), [](Point a, Point b) {
return a.y < b.y || (a.y == b.y && a.x < b.x);
});
// and swap it with the beginning of points vector
std::iter_swap(points.begin(), minimumIterator);
// sort the rest of the points based on orientation to minimum point (and on distance for same orientations)
std::sort(points.begin() + 1, points.end(), [=](Point a, Point b) {
float d = direction(points[0], a, b);
return d ? d > 0 : distSquared(points[0], a) < distSquared(points[0], b);
});
// add first 3 points to convex hull
std::vector<Point> convexHull;
convexHull.push_back(points[0]);
convexHull.push_back(points[1]);
convexHull.push_back(points[2]);
for (int i = 3; i < points.size(); ++i) {
// while going through points:
// convexHull[last-1], convexHull[last], points[i]
// there is no left turn
while (direction(convexHull[convexHull.size() - 2], convexHull.back(), points[i]) <= 0) {
// remove last point from convex hull
convexHull.pop_back();
}
// now there is left turn so add current point to convex hull
convexHull.push_back(points[i]);
}
return convexHull;
}
int main(int argc, char *argv[]) {
std::vector<Point> points = {
{ 1,4 },{ 2,1 },{ 2,5 },{ 3,3 },{ 4,2 },{ 4,7 },{ 5,4 },{ 5,6 },
{ 6,5 },{ 6,7 },{ 7,3 },{ 8,2 },{ 8,5 }
};
std::vector<Point> convexHull = FindConvexHull(points);
for (auto p : convexHull) {
std::cout << "(" << p.x << ", " << p.y << ")" << std::endl;
}
return 0;
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8dmVjdG9yPgojaW5jbHVkZSA8YWxnb3JpdGhtPgoKc3RydWN0IFBvaW50IHsKCWZsb2F0IHg7CglmbG9hdCB5Owp9OwoKLy8gcmV0dXJucyBjcm9zcyBwcm9kdWN0IHAwcDEgeCBwMHAyCmZsb2F0IGRpcmVjdGlvbihQb2ludCBwMCwgUG9pbnQgcDEsIFBvaW50IHAyKSB7CglyZXR1cm4gKHAxLnggLSBwMC54KSAqIChwMi55IC0gcDAueSkgLSAocDIueCAtIHAwLngpICogKHAxLnkgLSBwMC55KTsKfQoKLy8gcmV0dXJucyBzcXVhcmVkIGRpc3RhbmNlIGJldHdlZW4gZ2l2ZW4gcG9pbnRzCmZsb2F0IGRpc3RTcXVhcmVkKFBvaW50IGEsIFBvaW50IGIpIHsKCXJldHVybiAoYS54IC0gYi54KSAqIChhLnggLSBiLngpICsgKGEueSAtIGIueSkgKiAoYS55IC0gYi55KTsKfQoKc3RkOjp2ZWN0b3I8UG9pbnQ+IEZpbmRDb252ZXhIdWxsKHN0ZDo6dmVjdG9yPFBvaW50PiAmcG9pbnRzKSB7CgkvLyBmaW5kIG1pbmltdW0gcG9pbnQKCWF1dG8gbWluaW11bUl0ZXJhdG9yID0gc3RkOjptaW5fZWxlbWVudChwb2ludHMuYmVnaW4oKSwgcG9pbnRzLmVuZCgpLCBbXShQb2ludCBhLCBQb2ludCBiKSB7CgkJcmV0dXJuIGEueSA8IGIueSB8fCAoYS55ID09IGIueSAmJiBhLnggPCBiLngpOwoJfSk7CgkvLyBhbmQgc3dhcCBpdCB3aXRoIHRoZSBiZWdpbm5pbmcgb2YgcG9pbnRzIHZlY3RvcgoJc3RkOjppdGVyX3N3YXAocG9pbnRzLmJlZ2luKCksIG1pbmltdW1JdGVyYXRvcik7CgoJLy8gc29ydCB0aGUgcmVzdCBvZiB0aGUgcG9pbnRzIGJhc2VkIG9uIG9yaWVudGF0aW9uIHRvIG1pbmltdW0gcG9pbnQgKGFuZCBvbiBkaXN0YW5jZSBmb3Igc2FtZSBvcmllbnRhdGlvbnMpCglzdGQ6OnNvcnQocG9pbnRzLmJlZ2luKCkgKyAxLCBwb2ludHMuZW5kKCksIFs9XShQb2ludCBhLCBQb2ludCBiKSB7CgkJZmxvYXQgZCA9IGRpcmVjdGlvbihwb2ludHNbMF0sIGEsIGIpOwoJCXJldHVybiBkID8gZCA+IDAgOiBkaXN0U3F1YXJlZChwb2ludHNbMF0sIGEpIDwgZGlzdFNxdWFyZWQocG9pbnRzWzBdLCBiKTsKCX0pOwoKCS8vIGFkZCBmaXJzdCAzIHBvaW50cyB0byBjb252ZXggaHVsbAoJc3RkOjp2ZWN0b3I8UG9pbnQ+IGNvbnZleEh1bGw7Cgljb252ZXhIdWxsLnB1c2hfYmFjayhwb2ludHNbMF0pOwoJY29udmV4SHVsbC5wdXNoX2JhY2socG9pbnRzWzFdKTsKCWNvbnZleEh1bGwucHVzaF9iYWNrKHBvaW50c1syXSk7Cglmb3IgKGludCBpID0gMzsgaSA8IHBvaW50cy5zaXplKCk7ICsraSkgewoJCS8vIHdoaWxlIGdvaW5nIHRocm91Z2ggcG9pbnRzOgoJCS8vICBjb252ZXhIdWxsW2xhc3QtMV0sIGNvbnZleEh1bGxbbGFzdF0sIHBvaW50c1tpXQoJCS8vIHRoZXJlIGlzIG5vIGxlZnQgdHVybgoJCXdoaWxlIChkaXJlY3Rpb24oY29udmV4SHVsbFtjb252ZXhIdWxsLnNpemUoKSAtIDJdLCBjb252ZXhIdWxsLmJhY2soKSwgcG9pbnRzW2ldKSA8PSAwKSB7CgkJCS8vIHJlbW92ZSBsYXN0IHBvaW50IGZyb20gY29udmV4IGh1bGwKCQkJY29udmV4SHVsbC5wb3BfYmFjaygpOwoJCX0KCQkvLyBub3cgdGhlcmUgaXMgbGVmdCB0dXJuIHNvIGFkZCBjdXJyZW50IHBvaW50IHRvIGNvbnZleCBodWxsCgkJY29udmV4SHVsbC5wdXNoX2JhY2socG9pbnRzW2ldKTsKCX0KCXJldHVybiBjb252ZXhIdWxsOwp9CgppbnQgbWFpbihpbnQgYXJnYywgY2hhciAqYXJndltdKSB7CglzdGQ6OnZlY3RvcjxQb2ludD4gcG9pbnRzID0gewoJCXsgMSw0IH0seyAyLDEgfSx7IDIsNSB9LHsgMywzIH0seyA0LDIgfSx7IDQsNyB9LHsgNSw0IH0seyA1LDYgfSwKCQl7IDYsNSB9LHsgNiw3IH0seyA3LDMgfSx7IDgsMiB9LHsgOCw1IH0KCX07CglzdGQ6OnZlY3RvcjxQb2ludD4gY29udmV4SHVsbCA9IEZpbmRDb252ZXhIdWxsKHBvaW50cyk7Cglmb3IgKGF1dG8gcCA6IGNvbnZleEh1bGwpIHsKCQlzdGQ6OmNvdXQgPDwgIigiIDw8IHAueCA8PCAiLCAiIDw8IHAueSA8PCAiKSIgPDwgc3RkOjplbmRsOwoJfQoJcmV0dXJuIDA7Cn0=