Visual Computing Library
All Classes Functions Variables Typedefs Enumerations Friends Modules Pages Concepts
convex_hull.h
1/*****************************************************************************
2 * VCLib *
3 * Visual Computing Library *
4 * *
5 * Copyright(C) 2021-2025 *
6 * Visual Computing Lab *
7 * ISTI - Italian National Research Council *
8 * *
9 * All rights reserved. *
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the Mozilla Public License Version 2.0 as published *
13 * by the Mozilla Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 * This program is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19 * Mozilla Public License Version 2.0 *
20 * (https://www.mozilla.org/en-US/MPL/2.0/) for more details. *
21 ****************************************************************************/
22
23#ifndef VCL_ALGORITHMS_CORE_POLYGON_CONVEX_HULL_H
24#define VCL_ALGORITHMS_CORE_POLYGON_CONVEX_HULL_H
25
26#include "core2.h"
27
28namespace vcl {
29
30namespace detail {
31
38template<Point2IteratorConcept InputIterator, typename OutputContainer>
39void grahamScanOnContainer(
40 const InputIterator first,
41 const InputIterator end,
42 OutputContainer& outContainer)
43{
44 // Iterators
45 InputIterator it1;
46 InputIterator it2;
47 InputIterator it3;
48
49 InputIterator last;
50
51 // Stack of iterator to the vector (it is going to be the output)
52 std::vector<InputIterator> stack;
53
54 // Last points to the last element of the collection
55 last = end;
56 last--;
57
58 assert(first != end);
59 assert(std::next(first) != end);
60 assert(*first != *last);
61
62 // Add first and last to the results
63 stack.push_back(last);
64 stack.push_back(first);
65
66 // Initializing t1
67 it1 = first;
68
69 // Skip points not at the left of first-last segment
70 do {
71 it1++;
72 } while (it1 != last && !areCounterClockwise(*first, *last, *it1));
73
74 if (it1 != last) {
75 // Initialize stack with the first element which could be in the convex
76 // hull
77 stack.push_back(it1);
78
79 it2 = it1;
80
81 // Iterator to stack, pointing to the previous element of the back
82 // element
83 typename std::vector<InputIterator>::reverse_iterator stackItR =
84 stack.rbegin();
85 stackItR++;
86
87 it3 = *stackItR;
88
89 for (it1++; it1 != last; it1++) {
90 // Skip point for which last element is on the right of
91 // it1 - it2 segment
92 if (areCounterClockwise(*it1, *it2, *last)) {
93 while (!areCounterClockwise(*it2, *it3, *it1)) {
94 // Pop from stack
95 stack.pop_back();
96
97 // Setting other iterators
98 it2 = it3;
99
100 stackItR = stack.rbegin();
101 stackItR++;
102
103 it3 = *stackItR;
104
105 assert(stack.size() >= 2);
106 }
107
108 // Add to stack it1 and setting other iterators
109 stack.push_back(it1);
110 it3 = it2;
111 it2 = it1;
112 }
113 }
114 }
115
116 // Writing on the output iterator the results
117 typename std::vector<InputIterator>::iterator sIter = stack.begin();
118 for (++sIter; sIter != stack.end(); ++sIter) {
119 outContainer.pushBack(**sIter);
120 }
121}
122
123} // namespace detail
124
136template<Point2IteratorConcept InputIterator>
138{
139 using PointType = std::decay_t<decltype(*first)>;
140
142
143 // If the container is empty
144 if (first == end)
145 return convexHull;
146
147 // Sort the points
148 std::vector<PointType> sortedPoints(first, end);
149 std::sort(sortedPoints.begin(), sortedPoints.end());
150
151 // If the is composed by 1 points (or more than 1 of the same point)
152 if (*(sortedPoints.begin()) == *(sortedPoints.rbegin())) {
153 convexHull.pushBack(*(sortedPoints.begin()));
154
155 return convexHull;
156 }
157
158 // Graham scan on upper and lower convex hull
159 detail::grahamScanOnContainer(
160 sortedPoints.begin(), sortedPoints.end(), convexHull);
161 detail::grahamScanOnContainer(
162 sortedPoints.rbegin(), sortedPoints.rend(), convexHull);
163
164 convexHull.pushBack(convexHull.point(0));
165 std::reverse(convexHull.begin(), convexHull.end());
166 convexHull.resize(convexHull.size() - 1);
167
168 return convexHull;
169}
170
171template<Range InputContainer>
172auto convexHull(const InputContainer& container)
173 requires Point2Concept<std::ranges::range_value_t<InputContainer>>
174{
175 return convexHull(container.begin(), container.end());
176}
177
178} // namespace vcl
179
180#endif // VCL_ALGORITHMS_CORE_POLYGON_CONVEX_HULL_H
A class representing a line segment in n-dimensional space. The class is parameterized by a PointConc...
Definition segment.h:43
The InputIterator concept is satisfied if T is an input iterator that implements the operator* return...
Definition iterators.h:46
auto convexHull(InputIterator first, InputIterator end)
Get the 2D convex hull using Graham scan algorithm on a set of points.
Definition convex_hull.h:137
bool areCounterClockwise(const PointType &p0, const PointType &p1, const PointType &p2)
Checks if the three points are counter-clockwise.
Definition core2.h:75