TheAlgorithms/C++
1.0.0
All the algorithms implemented in C++
Toggle main menu visibility
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
*******************************************************************************/
52
namespace
geometry
{
53
54
/******************************************************************************
55
* @namespace graham scan
56
* @brief convex hull algorithm
57
*******************************************************************************/
58
namespace
grahamscan {
59
60
/******************************************************************************
61
* @struct Point
62
* @brief for X and Y co-ordinates of the co-ordinate.
63
*******************************************************************************/
64
struct
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
71
Point
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
*******************************************************************************/
78
Point
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
*******************************************************************************/
92
int
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
*******************************************************************************/
104
int
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
*******************************************************************************/
120
int
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
*******************************************************************************/
139
std::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
math::fibonacci_sum::result
uint64_t result(uint64_t n)
Definition
fibonacci_sum.cpp:77
geometry
for std::swap
Definition
graham_scan_functions.hpp:52
Point
Definition
line_segment_intersection.cpp:12
Point::y
int y
Point respect to x coordinate.
Definition
line_segment_intersection.cpp:14
geometry::grahamscan::Point
Definition
graham_scan_functions.hpp:64
geometry
graham_scan_functions.hpp
Generated by
1.18.0