TheAlgorithms/C++ 1.0.0
All the algorithms implemented in C++
Loading...
Searching...
No Matches
graham_scan_functions.hpp
1/******************************************************************************
2 * @file
3 * @brief Implementation of the [Convex
4 * Hull](https://en.wikipedia.org/wiki/Convex_hull) implementation using [Graham
5 * Scan](https://en.wikipedia.org/wiki/Graham_scan)
6 * @details
7 * In geometry, the convex hull or convex envelope or convex closure of a shape
8 * is the smallest convex set that contains it. The convex hull may be defined
9 * either as the intersection of all convex sets containing a given subset of a
10 * Euclidean space, or equivalently as the set of all convex combinations of
11 * points in the subset. For a bounded subset of the plane, the convex hull may
12 * be visualized as the shape enclosed by a rubber band stretched around the
13 * subset.
14 *
15 * The worst case time complexity of Jarvis’s Algorithm is O(n^2). Using
16 * Graham’s scan algorithm, we can find Convex Hull in O(nLogn) time.
17 *
18 * ### Implementation
19 *
20 * Sort points
21 * We first find the bottom-most point. The idea is to pre-process
22 * points be sorting them with respect to the bottom-most point. Once the points
23 * are sorted, they form a simple closed path.
24 * The sorting criteria is to use the orientation to compare angles without
25 * actually computing them (See the compare() function below) because
26 * computation of actual angles would be inefficient since trigonometric
27 * functions are not simple to evaluate.
28 *
29 * Accept or Reject Points
30 * Once we have the closed path, the next step is to traverse the path and
31 * remove concave points on this path using orientation. The first two points in
32 * sorted array are always part of Convex Hull. For remaining points, we keep
33 * track of recent three points, and find the angle formed by them. Let the
34 * three points be prev(p), curr(c) and next(n). If orientation of these points
35 * (considering them in same order) is not counterclockwise, we discard c,
36 * otherwise we keep it.
37 *
38 * @author [Lajat Manekar](https://github.com/Lazeeez)
39 *
40 *******************************************************************************/
41#include <algorithm>
42#include <cstdint>
43#include <cstdlib>
44#include <iostream>
45#include <stack>
46#include <vector>
47
48/******************************************************************************
49 * @namespace geometry
50 * @brief geometric algorithms
51 *******************************************************************************/
52namespace geometry {
53
54/******************************************************************************
55 * @namespace graham scan
56 * @brief convex hull algorithm
57 *******************************************************************************/
58namespace grahamscan {
59
60/******************************************************************************
61 * @struct Point
62 * @brief for X and Y co-ordinates of the co-ordinate.
63 *******************************************************************************/
64struct Point {
65 int x, y;
66};
67
68// A global point needed for sorting points with reference
69// to the first point Used in compare function of qsort()
70
71Point p0;
72
73/******************************************************************************
74 * @brief A utility function to find next to top in a stack.
75 * @param S Stack to be used for the process.
76 * @returns @param Point Co-ordinates of the Point <int, int>
77 *******************************************************************************/
78Point nextToTop(std::stack<Point> *S) {
79 Point p = S->top();
80 S->pop();
81 Point res = S->top();
82 S->push(p);
83 return res;
84}
85
86/******************************************************************************
87 * @brief A utility function to return square of distance between p1 and p2.
88 * @param p1 Co-ordinates of Point 1 <int, int>.
89 * @param p2 Co-ordinates of Point 2 <int, int>.
90 * @returns @param int distance between p1 and p2.
91 *******************************************************************************/
92int distSq(Point p1, Point p2) {
93 return (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y);
94}
95
96/******************************************************************************
97 * @brief To find orientation of ordered triplet (p, q, r).
98 * @param p Co-ordinates of Point p <int, int>.
99 * @param q Co-ordinates of Point q <int, int>.
100 * @param r Co-ordinates of Point r <int, int>.
101 * @returns @param int 0 --> p, q and r are collinear, 1 --> Clockwise,
102 * 2 --> Counterclockwise
103 *******************************************************************************/
104int orientation(Point p, Point q, Point r) {
105 int val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
106
107 if (val == 0) {
108 return 0; // collinear
109 }
110 return (val > 0) ? 1 : 2; // clock or counter-clock wise
111}
112
113/******************************************************************************
114 * @brief A function used by library function qsort() to sort an array of
115 * points with respect to the first point
116 * @param vp1 Co-ordinates of Point 1 <int, int>.
117 * @param vp2 Co-ordinates of Point 2 <int, int>.
118 * @returns @param int distance between p1 and p2.
119 *******************************************************************************/
120int compare(const void *vp1, const void *vp2) {
121 auto *p1 = static_cast<const Point *>(vp1);
122 auto *p2 = static_cast<const Point *>(vp2);
123
124 // Find orientation
125 int o = orientation(p0, *p1, *p2);
126 if (o == 0) {
127 return (distSq(p0, *p2) >= distSq(p0, *p1)) ? -1 : 1;
128 }
129
130 return (o == 2) ? -1 : 1;
131}
132
133/******************************************************************************
134 * @brief Prints convex hull of a set of n points.
135 * @param points vector of Point<int, int> with co-ordinates.
136 * @param size Size of the vector.
137 * @returns @param vector vector of Conver Hull.
138 *******************************************************************************/
139std::vector<Point> convexHull(std::vector<Point> points, uint64_t size) {
140 // Find the bottom-most point
141 int ymin = points[0].y, min = 0;
142 for (int i = 1; i < size; i++) {
143 int y = points[i].y;
144
145 // Pick the bottom-most or chose the left-most point in case of tie
146 if ((y < ymin) || (ymin == y && points[i].x < points[min].x)) {
147 ymin = points[i].y, min = i;
148 }
149 }
150
151 // Place the bottom-most point at first position
152 std::swap(points[0], points[min]);
153
154 // Sort n-1 points with respect to the first point. A point p1 comes
155 // before p2 in sorted output if p2 has larger polar angle
156 // (in counterclockwise direction) than p1.
157 p0 = points[0];
158 qsort(&points[1], size - 1, sizeof(Point), compare);
159
160 // If two or more points make same angle with p0, Remove all but the one
161 // that is farthest from p0 Remember that, in above sorting, our criteria
162 // was to keep the farthest point at the end when more than one points have
163 // same angle.
164 int m = 1; // Initialize size of modified array
165 for (int i = 1; i < size; i++) {
166 // Keep removing i while angle of i and i+1 is same with respect to p0
167 while (i < size - 1 && orientation(p0, points[i], points[i + 1]) == 0) {
168 i++;
169 }
170
171 points[m] = points[i];
172 m++; // Update size of modified array
173 }
174
175 // If modified array of points has less than 3 points, convex hull is not
176 // possible
177 if (m < 3) {
178 return {};
179 };
180
181 // Create an empty stack and push first three points to it.
182 std::stack<Point> St;
183 St.push(points[0]);
184 St.push(points[1]);
185 St.push(points[2]);
186
187 // Process remaining n-3 points
188 for (int i = 3; i < m; i++) {
189 // Keep removing top while the angle formed by
190 // points next-to-top, top, and points[i] makes
191 // a non-left turn
192 while (St.size() > 1 &&
193 orientation(nextToTop(&St), St.top(), points[i]) != 2) {
194 St.pop();
195 }
196 St.push(points[i]);
197 }
198
199 std::vector<Point> result;
200 // Now stack has the output points, push them into the resultant vector
201 while (!St.empty()) {
202 Point p = St.top();
203 result.push_back(p);
204 St.pop();
205 }
206
207 return result; // return resultant vector with Convex Hull co-ordinates.
208}
209} // namespace grahamscan
210} // namespace geometry
uint64_t result(uint64_t n)
for std::swap
int y
Point respect to x coordinate.