4
4
5
5
#include < vector>
6
6
#include < algorithm>
7
- #include < cmath>
8
7
9
8
namespace geometry
10
9
{
11
10
[[nodiscard]] static inline std::vector<ivec2>
12
- convex_hull_construct (std::vector<ivec2> points)
11
+ convex_hull_construct (std::vector<ivec2> points, bool strictly_convex = true )
13
12
{
14
13
// lowest y-coordinate and leftmost point
15
14
ivec2 pivot = *std::min_element (points.begin (), points.end ());
@@ -20,11 +19,27 @@ namespace geometry
20
19
[&pivot](const ivec2& a, const ivec2& b)
21
20
{
22
21
auto area = (a - pivot) * (b - pivot);
23
- auto a_smaller = ::abs (pivot.x - a.x ) + ::abs (pivot.y - a.y ) < ::abs (pivot.x - b.x ) + ::abs (pivot.y - b.y );
24
- return (area != 0 ) * (area > 0 ) + (area == 0 ) * a_smaller;
22
+ if (area == 0 )
23
+ {
24
+ auto pivot_a = a - pivot;
25
+ auto pivot_b = b - pivot;
26
+ return pivot_a.dot (pivot_a) < pivot_b.dot (pivot_b);
27
+ }
28
+ else
29
+ {
30
+ return area > 0 ;
31
+ }
25
32
}
26
33
);
27
34
35
+ if (!strictly_convex)
36
+ {
37
+ int reverse_index = (int )points.size () - 2 ;
38
+ while (reverse_index > 0 && (points.back () - pivot) * (points[reverse_index] - pivot) == 0 )
39
+ reverse_index--;
40
+ std::reverse (points.begin () + reverse_index + 1 , points.end ());
41
+ }
42
+
28
43
std::vector<ivec2> polygon;
29
44
polygon.reserve (points.size ());
30
45
@@ -34,9 +49,8 @@ namespace geometry
34
49
{
35
50
auto a = polygon.end ()[-2 ];
36
51
auto b = polygon.end ()[-1 ];
37
- auto & c = points[i];
38
-
39
- if ((b - a) * (c - a) > 0 )
52
+ auto area = (b - a) * (points[i] - a);
53
+ if (area > 0 || (area == 0 && !strictly_convex))
40
54
break ;
41
55
42
56
// remove last point if it results in a clockwise orientation or if the points are collinear
@@ -45,6 +59,9 @@ namespace geometry
45
59
polygon.push_back (points[i]);
46
60
}
47
61
62
+ if (strictly_convex && polygon.size () == 2 && polygon[0 ] == polygon[1 ])
63
+ polygon.pop_back ();
64
+
48
65
polygon.shrink_to_fit ();
49
66
return polygon;
50
67
}
0 commit comments