44 using tvec = glm::tvec2<T>;
47 std::vector<glm::tvec2<T>> vertices;
49 template <
typename... ARGS>
50 static tpolygon from_vertices(ARGS&&... args) {
51 return tpolygon{ { std::forward<ARGS>(args)... } };
59 shape.for_each_vertex([&result](
auto const& v) {
60 result.vertices.push_back(v);
65 tvec& operator[](
size_t index) {
return vertices.at(index); }
66 tvec
const& operator[](
size_t index)
const {
return vertices.at(index); }
68 auto cbegin()
const {
return std::ranges::cbegin(vertices); }
69 auto cend()
const {
return std::ranges::cend(vertices); }
70 auto begin() {
return std::ranges::begin(vertices); }
71 auto end() {
return std::ranges::end(vertices); }
72 auto begin()
const {
return std::ranges::cbegin(vertices); }
73 auto end()
const {
return std::ranges::cend(vertices); }
74 auto size()
const {
return std::ranges::size(vertices); }
76 bool is_valid()
const noexcept {
return vertices.size() > 2; }
145 size_t vertex_count()
const {
return vertices.size(); }
146 size_t edge_count()
const {
return vertices.size() < 2 ? 0 : vertices.size() - 1; }
148 std::optional<std::pair<tvec, tvec>> edge(
size_t index)
const
150 const auto c = vertices.size();
151 if (c < 2 || index >= c - 1)
return std::nullopt;
152 return std::pair{ vertices[index], vertices[index + 1] };
155 std::optional<tvec> vertex(
size_t index)
const
157 const auto c = vertices.size();
158 if (c < 2 || index >= c)
return std::nullopt;
159 return vertices[index];
162 template <
typename FUNC>
163 void for_each_vertex(FUNC&& func)
const
165 for (
auto& v : vertices)
169 template <
typename FUNC>
170 void for_each_edge(FUNC&& func)
const
172 const auto c = vertices.size();
175 if constexpr (std::invocable<FUNC, tvec const&, tvec const&>)
177 for (
size_t i = 0; i < c - 1; ++i)
178 func(vertices[i], vertices[i + 1]);
182 for (
size_t i = 0; i < c - 1; ++i)
183 func(std::pair{ vertices[i], vertices[i + 1] });
187 std::vector<tsegment<T>> edges()
const noexcept
190 for_each_edge(op::push_back_to(result));
194 std::vector<T> interior_angles()
const noexcept;
196 T edge_length()
const
199 for_each_edge([&](tvec
const& v1, tvec
const& v2) {
200 result += glm::distance(v1, v2);
205 tvec edge_point(T t)
const
207 const auto el = edge_length();
208 return edge_point(t, el);
211 tvec edge_point_alpha(T t)
const
213 const auto el = edge_length();
214 return edge_point(t * el, el);
217 tvec closest_point_to(tvec pt)
const;
219 T calculate_area()
const
222 for_each_edge([&](tvec
const& v1, tvec
const& v2) {
223 result += v1.x * v2.y - v2.x * v1.y;
225 return result * T(0.5);
228 tvec centroid()
const
233 for (
size_t i = 0; i < vertices.size(); ++i)
235 const auto xi = vertices[i].x;
236 const auto yi = vertices[i].y;
237 const auto xi1 = vertices[(i + 1) % vertices.size()].x;
238 const auto yi1 = vertices[(i + 1) % vertices.size()].y;
239 const auto d = xi * yi1 - xi1 * yi;
241 Cx += (xi + xi1) * d;
242 Cy += (yi + yi1) * d;
245 return { Cx / A, Cy / A };
250 trec2<T> res = trec2<T>::exclusive();
251 for (
auto& v : vertices)
262 const size_t nvert = vertices.size();
263 for (
size_t i = 0, j = nvert - 1; i < nvert; j = i++)
265 if (((vertices[i].y > test.y) != (vertices[j].y > test.y)) &&
266 (test.x < (vertices[j].x - vertices[i].x) * (test.y - vertices[i].y) / (vertices[j].y - vertices[i].y) + vertices[i].x))
276 tvec edge_point(T t, T precalced_length)
const
278 auto c = vertices.size();
280 return c ? vertices[0] : tvec{};
282 t = fmod(t, precalced_length);
283 for (
size_t i = 0; i < c - 1; ++i)
285 const auto d = glm::distance(vertices[i], vertices[i + 1]);
287 return glm::mix(vertices[i], vertices[i + 1], t / d);
304 using tvec = glm::tvec2<T>;
305 using value_type = T;
308 std::vector<tindexed_triangle<IDX>> triangles;
310 template <
typename FUNC>
311 void for_each_triangle(FUNC&& func)
313 for (
auto& tr : triangles)
315 return tr.as_triangle(poly);
319 T edge_length()
const {
return poly.edge_length(); }
320 tvec edge_point_alpha(T t)
const {
return poly.edge_point_alpha(t); }
321 tvec edge_point(T t)
const {
return poly.edge_point(t); }
322 trec2<T> bounding_box()
const {
return poly.bounding_box(); }
323 tvec closest_point_to(glm::tvec2<T> pt)
const {
return poly.closest_point_to(pt); }
327 T calculate_area()
const;
328 tvec centroid()
const;
503 using tvec = glm::tvec2<T>;
504 using value_type = T;
507 tpolygon()
noexcept =
default;
508 tpolygon(tpolygon
const&)
noexcept =
default;
509 tpolygon(tpolygon&&)
noexcept =
default;
510 tpolygon& operator=(tpolygon
const&)
noexcept =
default;
511 tpolygon& operator=(tpolygon&&)
noexcept =
default;
513 template <
typename... ARGS>
514 requires std::constructible_from<mutable_polygon, ARGS...>
515 tpolygon(ARGS&&... args) noexcept
516 : m_poly(std::forward<ARGS>(args)...)
521 template <
typename POLY_OR_ARR>
522 tpolygon(POLY_OR_ARR&& poly, std::vector<indexed_triangle> triangles, std::vector<T> cached_triangle_areas, T cached_area)
523 : m_poly(std::forward<POLY_OR_ARR>(poly))
524 , m_triangles(std::move(triangles))
525 , m_cached_triangle_areas(std::move(cached_triangle_areas))
526 , m_cached_area(cached_area)
532 tvec
const& operator[](
size_t index)
const {
return m_poly.vertices.at(index); }
534 auto cbegin() const noexcept {
return std::ranges::cbegin(m_poly.vertices); }
535 auto cend() const noexcept {
return std::ranges::cend(m_poly.vertices); }
536 auto begin() const noexcept {
return std::ranges::cbegin(m_poly.vertices); }
537 auto end() const noexcept {
return std::ranges::cend(m_poly.vertices); }
538 auto size() const noexcept {
return std::ranges::size(m_poly.vertices); }
540 const auto* operator->() const noexcept {
return &m_poly; }
542 const auto& polygon() const noexcept {
return m_poly; }
544 T edge_length()
const {
return m_poly.edge_length(); }
545 tvec edge_point_alpha(T t)
const {
return m_poly.edge_point_alpha(t); }
546 tvec edge_point(T t)
const {
return m_poly.edge_point(t); }
547 trec2<T> bounding_box()
const {
return m_poly.bounding_box(); }
548 tvec closest_point_to(glm::tvec2<T> pt)
const {
return m_poly.closest_point_to(pt); }
553 T calculate_area()
const
556 return m_cached_area;
559 tvec centroid()
const
562 return m_poly.centroid();
565 auto const& triangles()
const
571 auto const& areas()
const
574 return m_cached_triangle_areas;
577 bool has_triangle(
size_t i)
const { triangulate();
return i < m_triangles.size(); }
578 auto triangle(
size_t i)
const { triangulate();
return m_triangles.at(i).as_triangle(m_poly); }
579 T triangle_area(
size_t i)
const { triangulate();
return m_cached_triangle_areas.at(i); }
583 geometry::tpolygon<T> m_poly;
584 mutable std::vector<indexed_triangle> m_triangles;
585 mutable std::vector<T> m_cached_triangle_areas;
586 mutable T m_cached_area = std::numeric_limits<T>::lowest();
587 mutable tvec m_cached_centroid;
588 mutable polygon_classification m_cached_classification;
590 void triangulate()
const
592 if (m_triangles.empty() && m_poly.vertices.size() > 2)
594 auto&& [poly, triangles] = geometry::triangulate(m_poly);
595 m_triangles = std::move(triangles);
597 m_cached_triangle_areas.reserve(m_triangles.size());
599 for (
auto& tr : m_triangles)
601 const auto area = calculate_indexed_triangle_area(poly, tr);
602 m_cached_triangle_areas.push_back(area);
605 m_cached_area = cached_area;