-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathConvexHull.cpp
More file actions
94 lines (80 loc) · 2.86 KB
/
ConvexHull.cpp
File metadata and controls
94 lines (80 loc) · 2.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include "Point.cpp" //LATEX_IGNORED_LINE
#include "Segment.cpp" //LATEX_IGNORED_LINE
using namespace std;
/*LATEX_DESC_BEGIN***************************
@\begin{minipage}{0.85\textwidth}
Given a vector of points, return the convex hull in CCW order. \\
A convex hull is the smallest convex polygon that contains all the points.
\end{minipage}\hfill \begin{minipage}{0.14\textwidth} \includegraphics[height=4\baselineskip]{geometry/ConvexHull} \end{minipage} @
If you want colinear points in border, change the >=0 to >0 in the while's.
**WARNING:**if collinear and all input PT are collinear, may have duplicated points (the round trip)
*****************************LATEX_DESC_END*/
vector<PT> ConvexHull(vector<PT> pts, bool sorted=false){
if(!sorted) sort(begin(pts), end(pts));
pts.resize(unique(begin(pts), end(pts)) - begin(pts));
if(pts.size() <= 1) return pts;
int s=0, n=pts.size();
vector<PT> h(2*n+1);
for(int i=0; i<n; h[s++] = pts[i++])
while(s > 1 && h[s-2].cross(pts[i], h[s-1]) >= 0 )
s--;
for(int i=n-2, t=s; ~i; h[s++] = pts[i--])
while(s > t && h[s-2].cross(pts[i], h[s-1]) >= 0 )
s--;
h.resize(s-1);
return h;
} //PT operators needed: {- % == <}
/*BLOCK_DESC_BEGIN Check **if a point is inside convex hull** (CCW, no collinear).
If strict == true, then pt on boundary return false
O(log N)
BLOCK_DESC_END*/
bool isInside(const vector<PT>& h, PT p, bool strict = true){
int a = 1, b = h.size() - 1, r = !strict;
if(h.size() < 3) return r && onSegment(h[0], h.back(), p);
if(h[0].cross(h[a], h[b]) > 0) swap(a, b);
if(h[0].cross(h[a], p) >= r || h[0].cross(h[b], p) <= -r) return false;
while(abs(a-b) > 1){
int c = (a + b) / 2;
if(h[0].cross(h[c], p) > 0) b = c;
else a = c;
}
return h[a].cross(h[b], p) < r;
}
/*BLOCK_DESC_BEGIN Check **if a point is inside convex hull** \\ O(log N) BLOCK_DESC_END*/
bool isInside(const vector<PT> &h, PT p){
if(h[0].cross(p, h[1]) > 0 || h[0].cross(p, h.back()) < 0) return false;
int n = h.size(), l=1, r = n-1;
while(l != r){
int mid = (l+r+1)/2;
if(h[0].cross(p, h[mid]) < 0) l = mid;
else r = mid - 1;
}
return h[l].cross(h[(l+1)%n], p) >= 0;
}
/*BLOCK_DESC_BEGIN
Given a convex hull h and a point p, returns the indice of h **where the dot product is maximized**.
This code assumes that there are NO 3 colinear points!
BLOCK_DESC_END*/
int maximizeScalarProduct(const std::vector<PT> &h, PT v) {
int ans = 0, n = h.size();
if(n < 20){
for(int i=0; i<n; i++)
if(v*h[ans] < v*h[i])
ans = i;
return ans;
}
for(int rep=0; rep<2; rep++){
int l = 2, r = n-1;
while(l != r){
int mid = (l+r+1)/2;
int f = v*h[mid] >= v*h[mid-1];
if(rep) f |= v*h[mid-1] < v*h[0];
else f &= v*h[mid] >= v*h[0];
if(f) l = mid;
else r = mid - 1;
}
if(v*h[ans] < v*h[l]) ans = l;
}
if(v*h[ans] < v*h[1] ) ans = 1;
return ans;
}