header_utils
Loading...
Searching...
No Matches
polygon.h
1
4
5#pragma once
6
7#include "geometry_common.h"
8#include "./segment.h"
9#include "./triangles.h"
10#include <array>
11
12namespace ghassanpl::geometry
13{
14 template <std::floating_point T>
15 struct tpolygon
16 {
17 using tvec = glm::tvec2<T>;
18 using value_type = T;
19
20 std::vector<glm::tvec2<T>> vertices;
21
22 tvec& operator[](size_t index) { return vertices.at(index); }
23 tvec const& operator[](size_t index) const { return vertices.at(index); }
24
25 auto cbegin() const { return std::ranges::cbegin(vertices); }
26 auto cend() const { return std::ranges::cend(vertices); }
27 auto begin() { return std::ranges::begin(vertices); }
28 auto end() { return std::ranges::end(vertices); }
29 auto begin() const { return std::ranges::cbegin(vertices); }
30 auto end() const { return std::ranges::cend(vertices); }
31 auto size() const { return std::ranges::size(vertices); }
32
33 bool is_valid() const noexcept { return vertices.size() > 2; }
34
35 struct convexity {
36 bool simple = false;
37 bool convex = false;
38 constexpr bool is_simple() const { return simple; }
39 constexpr bool intersects_itself() const { return !simple; }
40 constexpr bool is_convex() const { return convex; }
41 constexpr bool is_concave() const noexcept { return simple && !convex; }
42 };
43
44 convexity calculate_convexity() const noexcept;
45 tpolygon<T> convex_hull() const noexcept;
46
47 std::optional<tsegment<T>> edge(size_t index) const
48 {
49 const auto c = vertices.size();
50 if (c < 2 || index >= c - 1) return std::nullopt;
51 return tsegment<T>{vertices[index], vertices[index + 1]};
52 }
53
54 std::optional<tvec> vertex(size_t index) const
55 {
56 const auto c = vertices.size();
57 if (c < 2 || index >= c) return std::nullopt;
58 return vertices[index];
59 }
60
61 template <typename FUNC>
62 void for_each_edge(FUNC&& func)
63 {
64 const auto c = vertices.size();
65 if (c < 2) return;
66
67 for (size_t i = 0; i < c - 1; ++i)
68 func(tsegment<T>{vertices[i], vertices[i + 1]});
69 }
70
71 std::vector<tsegment<T>> edges() const noexcept
72 {
73 std::vector<tsegment<T>> result;
74 for_each_edge([&](auto&& seg) { result.push_back(seg); });
75 return result;
76 }
77
78 std::vector<T> interior_angles() const noexcept;
79
80 T edge_length() const
81 {
82 T result{};
83 for_each_edge([&](tvec const& v1, tvec const& v2) {
84 result += glm::distance(v1, v2);
85 });
86 return result;
87 }
88
89 tvec edge_point(T t) const
90 {
91 const auto el = edge_length();
92 return edge_point(t, el);
93 }
94
95 tvec edge_point_alpha(T t) const
96 {
97 const auto el = edge_length();
98 return edge_point(t * el, el);
99 }
100
101 tvec projected(tvec pt) const;
102
103 T calculate_area() const;
104
105 trec2<T> bounding_box() const
106 {
107 trec2<T> res = trec2<T>::exclusive();
108 for (auto& v : vertices)
109 res.include(v);
110 return res;
111 }
112
114 bool contains(tvec test) const
115 {
116 bool ret = false;
117 const size_t nvert = vertices.size();
118 for (size_t i = 0, j = nvert - 1; i < nvert; j = i++)
119 {
120 if (((vertices[i].y > test.y) != (vertices[j].y > test.y)) &&
121 (test.x < (vertices[j].x - vertices[i].x) * (test.y - vertices[i].y) / (vertices[j].y - vertices[i].y) + vertices[i].x))
122 {
123 ret = !ret;
124 }
125 }
126 return ret;
127 }
128
129 private:
130
131 tvec edge_point(T t, T precalced_length) const
132 {
133 auto c = vertices.size();
134 if (c < 2)
135 return c ? vertices[0] : tvec{};
136
137 t = fmod(t, precalced_length);
138 for (size_t i = 0; i < c - 1; ++i)
139 {
140 const auto d = glm::distance(vertices[i], vertices[i + 1]);
141 if (t <= d)
142 return glm::mix(vertices[i], vertices[i + 1], t / d);
143
144 t -= d;
145 }
146 return vertices[0];
147 }
148 };
149
150 using polygon = tpolygon<float>;
151 static_assert(shape<polygon, float>);
152 static_assert(std::ranges::random_access_range<polygon>);
153
154 template <std::floating_point T, std::integral IDX = size_t>
155 struct polygon_triangulation
156 {
157 using tvec = glm::tvec2<T>;
158 using value_type = T;
159
160 tpolygon<T> const& poly;
161 std::vector<tindexed_triangle<IDX>> triangles;
162
163 template <typename FUNC>
164 void for_each_triangle(FUNC&& func)
165 {
166 for (auto& tr : triangles)
167 {
168 return tr.as_triangle(poly);
169 }
170 }
171
172 T edge_length() const { return poly.edge_length(); }
173 tvec edge_point_alpha(T t) const { return poly.edge_point_alpha(t); }
174 tvec edge_point(T t) const { return poly.edge_point(t); }
175 trec2<T> bounding_box() const { return poly.bounding_box(); }
176 tvec projected(glm::tvec2<T> pt) const { return poly.projected(pt); }
177
178 bool contains(glm::tvec2<T> pt) const;
179 T calculate_area() const;
180 };
181
182 static_assert(area_shape<polygon_triangulation<float>, float>);
183
184 template <std::floating_point T, std::integral IDX = size_t>
185 struct triangulated_polygon
186 {
187 using tvec = glm::tvec2<T>;
188 using value_type = T;
189
190 tpolygon<T> poly;
191 std::vector<tindexed_triangle<IDX>> triangles;
192
193 T edge_length() const { return poly.edge_length(); }
194 tvec edge_point_alpha(T t) const { return poly.edge_point_alpha(t); }
195 tvec edge_point(T t) const { return poly.edge_point(t); }
196 trec2<T> bounding_box() const { return poly.bounding_box(); }
197 tvec projected(glm::tvec2<T> pt) const { return poly.projected(pt); }
198
199 bool contains(glm::tvec2<T> pt) const;
200 T calculate_area() const;
201 };
202
203 static_assert(area_shape<triangulated_polygon<float>, float>);
204
205 template <typename POLY>
206 auto calculate_indexed_triangle_area(POLY const& poly, indexed_triangle const& triangle)
207 {
208 const auto a = poly[triangle.indices[0]];
209 const auto b = poly[triangle.indices[1]];
210 const auto c = poly[triangle.indices[2]];
211 using T = typename POLY::value_type;
212 return geometry::ttriangle<T>{a, b, c}.calculate_area();
213 }
214
215 template <typename TR>
216 auto calculate_total_area(TR const& trpoly)
217 {
218 using T = decltype(trpoly.poly)::value_type;
219 T result{};
220 for (auto& tr : trpoly.triangles)
221 result += calculate_indexed_triangle_area(trpoly.poly, tr);
222 return result;
223 }
224
225 template <typename T>
226 polygon_triangulation<T> triangulate(tpolygon<T> const& poly)
227 {
228 polygon_triangulation<T> result{poly};
230 throw "unimplemented";
231 return result;
232 }
233
234 namespace immutable
235 {
236 template <std::floating_point T>
237 struct tpolygon
238 {
239 using tvec = glm::tvec2<T>;
240 using value_type = T;
241 using mutable_polygon = geometry::tpolygon<T>;
242
243 tpolygon() noexcept = default;
244 tpolygon(tpolygon const&) noexcept = default;
245 tpolygon(tpolygon&&) noexcept = default;
246 tpolygon& operator=(tpolygon const&) noexcept = default;
247 tpolygon& operator=(tpolygon&&) noexcept = default;
248
250 requires std::constructible_from<mutable_polygon, ARGS...>
251 tpolygon(ARGS&&... args) noexcept
252 : m_poly(std::forward<ARGS>(args)...)
253 {
254 }
255
257 template <typename POLY_OR_ARR>
258 tpolygon(POLY_OR_ARR&& poly, std::vector<indexed_triangle> triangles, std::vector<T> cached_triangle_areas, T cached_area)
259 : m_poly(std::forward<POLY_OR_ARR>(poly))
260 , m_triangles(std::move(triangles))
261 , m_cached_triangle_areas(std::move(cached_triangle_areas))
262 , m_cached_area(cached_area)
263 {
264
265 }
266
267
268 tvec const& operator[](size_t index) const { return m_poly.vertices.at(index); }
269
270 auto cbegin() const noexcept { return std::ranges::cbegin(m_poly.vertices); }
271 auto cend() const noexcept { return std::ranges::cend(m_poly.vertices); }
272 auto begin() const noexcept { return std::ranges::cbegin(m_poly.vertices); }
273 auto end() const noexcept { return std::ranges::cend(m_poly.vertices); }
274 auto size() const noexcept { return std::ranges::size(m_poly.vertices); }
275
276 const auto* operator->() const noexcept { return &m_poly; }
277
278 const auto& polygon() const noexcept { return m_poly; }
279
280 T edge_length() const { return m_poly.edge_length(); }
281 tvec edge_point_alpha(T t) const { return m_poly.edge_point_alpha(t); }
282 tvec edge_point(T t) const { return m_poly.edge_point(t); }
283 trec2<T> bounding_box() const { return m_poly.bounding_box(); }
284 tvec projected(glm::tvec2<T> pt) const { return m_poly.projected(pt); }
285
286 bool contains(glm::tvec2<T> pt) const;
287
288 T calculate_area() const
289 {
290 triangulate();
291 return m_cached_area;
292 }
293
294 auto const& triangles() const
295 {
296 triangulate();
297 return m_triangles;
298 }
299
300 auto const& areas() const
301 {
302 triangulate();
303 return m_cached_triangle_areas;
304 }
305
306 bool has_triangle(size_t i) const { triangulate(); return i < m_triangles.size(); }
307 auto triangle(size_t i) const { triangulate(); return m_triangles.at(i).as_triangle(m_poly); }
308 T triangle_area(size_t i) const { triangulate(); return m_cached_triangle_areas.at(i); }
309
310 protected:
311
312 geometry::tpolygon<T> m_poly;
313 mutable std::vector<indexed_triangle> m_triangles;
314 mutable std::vector<T> m_cached_triangle_areas;
315 mutable T m_cached_area = std::numeric_limits<T>::lowest();
316
317 void triangulate() const
318 {
319 if (m_triangles.empty() && m_poly.vertices.size() > 2)
320 {
321 auto&& [poly, triangles] = geometry::triangulate(m_poly);
322 m_triangles = std::move(triangles);
323
324 m_cached_triangle_areas.reserve(m_triangles.size());
325 T cached_area{};
326 for (auto& tr : m_triangles)
327 {
328 const auto area = calculate_indexed_triangle_area(poly, tr);
329 m_cached_triangle_areas.push_back(area);
330 cached_area += area;
331 }
332 m_cached_area = cached_area;
333 }
334 }
335 };
336
337 using polygon = tpolygon<float>;
338 static_assert(area_shape<polygon, float>);
339 }
340
342
343 template <std::floating_point T>
344 struct tpolyline;
345}
constexpr auto bit_count
Equal to the number of bits in the type.
Definition bits.h:33
constexpr __contains_fn contains
contains(range, el)
Definition ranges.h:247