header_utils
Loading...
Searching...
No Matches
triangles.h
1
4
5#pragma once
6
7#include "geometry_common.h"
8#include "./segment.h"
9
10namespace ghassanpl::geometry
11{
15
16 template <std::floating_point T>
17 struct ttriangle
18 {
19 using tvec = glm::tvec2<T>;
20 using value_type = T;
21
22 tvec a{};
23 tvec b{};
24 tvec c{};
25
26 template <typename FUNC>
27 void for_each_edge(FUNC&& func) const
28 {
29 func(a, b);
30 func(b, c);
31 func(c, a);
32 }
33
34 trec2<T> bounding_box() const
35 {
36 trec2<T> res;
37 res += a; res += b; res += c;
38 return res;
39 }
40
41 T edge_length() const
42 {
43 return glm::distance(a, b) + glm::distance(b, c) + glm::distance(c, a);
44 }
45
46 tvec edge_point_alpha(T t) const;
47 tvec edge_point(T t) const;
48 tvec closest_point_to(tvec pt) const;
49
50 static auto sign(tvec const& p1, tvec const& p2, tvec const& p3) noexcept
51 {
52 return (p1.x - p3.x) * (p2.y - p3.y) - (p2.x - p3.x) * (p1.y - p3.y);
53 }
54
55 winding_order winding() const noexcept
56 {
57 const auto d = sign(a, b, c);
58 return d > 0 ? winding_order::clockwise : winding_order::counter_clockwise;
59 }
60
61 bool contains(tvec pt) const noexcept
62 {
63 const auto d1 = sign(pt, a, b);
64 const auto d2 = sign(pt, b, c);
65 const auto d3 = sign(pt, c, a);
66 const auto has_neg = (d1 < 0) || (d2 < 0) || (d3 < 0);
67 const auto has_pos = (d1 > 0) || (d2 > 0) || (d3 > 0);
68 return !(has_neg && has_pos);
69 }
70
71 auto calculate_area() const noexcept
72 {
73 const auto A = std::sqrt((b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y));
74 const auto B = std::sqrt((b.x - c.x) * (b.x - c.x) + (b.y - c.y) * (b.y - c.y));
75 const auto C = std::sqrt((b.x - c.x) * (a.x - c.x) + (a.y - c.y) * (a.y - c.y));
76 const auto s = (A + B + C) * T(0.5);
77 return std::sqrt(s * (s - A) * (s - B) * (s - C));
78 }
79
80 auto centroid() const
81 {
82 return (a + b + c) / T(3);
83 }
84
85 glm::tvec3<T> barycentric_coords_of(glm::tvec2<T> pt) const
86 {
87 const auto v0 = b - a;
88 const auto v1 = c - a;
89 const auto v2 = pt - a;
90 const auto d00 = glm::dot(v0, v0);
91 const auto d01 = glm::dot(v0, v1);
92 const auto d11 = glm::dot(v1, v1);
93 const auto d20 = glm::dot(v2, v0);
94 const auto d21 = glm::dot(v2, v1);
95 const auto denom = d00 * d11 - d01 * d01;
96 const auto v = (d11 * d20 - d01 * d21) / denom;
97 const auto w = (d00 * d21 - d01 * d20) / denom;
98 const auto u = 1 - v - w;
99 return { u, v, w };
100 }
101
102 glm::tvec2<T> euclidean_coords_of(glm::tvec3<T> barycentric) const
103 {
104 return a * barycentric.x + b * barycentric.y + c * barycentric.z;
105 }
106
107 /*
108 tcircle<T> circumcircle()
109 {
110 Doub a0, a1, c0, c1, det, asq, csq, ctr0, ctr1, rad2;
111 a0 = a.x[0] - b.x[0]; a1 = a.x[1] - b.x[1];
112 c0 = c.x[0] - b.x[0]; c1 = c.x[1] - b.x[1];
113 det = a0 * c1 - c0 * a1;
114 if (det == 0.0) throw("no circle thru colinear points");
115 det = 0.5 / det;
116 asq = a0 * a0 + a1 * a1;
117 csq = c0 * c0 + c1 * c1;
118 ctr0 = det * (asq * c1 - csq * a1);
119 ctr1 = det * (csq * a0 - asq * c0);
120 rad2 = ctr0 * ctr0 + ctr1 * ctr1;
121 return { {ctr0 + b.x[0], ctr1 + b.x[1]}, sqrt(rad2));
122 }
123 */
124
125 template <typename FUNC>
126 void for_each_vertex(FUNC&& func) const
127 {
128 func(a);
129 func(b);
130 func(c);
131 }
132
133 size_t vertex_count() const { return 3; }
134
135 size_t edge_count() const { return 3; }
136
137 auto edge(size_t index) const -> std::optional<std::pair<glm::tvec2<T>, glm::tvec2<T>>>
138 {
139 switch (index)
140 {
141 case 0: return std::make_pair(a, b);
142 case 1: return std::make_pair(b, c);
143 case 2: return std::make_pair(c, a);
144 }
145 return std::nullopt;
146 }
147
148 auto vertex(size_t index) const -> std::optional<tvec>
149 {
150 switch (index)
151 {
152 case 0: return a;
153 case 1: return b;
154 case 2: return c;
155 }
156 return std::nullopt;
157 }
158 };
159
160 using triangle = ttriangle<float>;
161 static_assert(area_shape<float, triangle>);
162 static_assert(polygon_shape<float, triangle>);
163
165 template <std::integral IDX_TYPE = size_t>
167 {
169
170 std::array<IDX_TYPE, 3> indices{};
171
172 template <std::ranges::random_access_range T>
173 auto a(T&& range) const -> std::ranges::range_value_t<T>
174 {
175 return range[indices[0]];
176 }
177 template <std::ranges::random_access_range T>
178 auto b(T&& range) const -> std::ranges::range_value_t<T>
179 {
180 return range[indices[1]];
181 }
182 template <std::ranges::random_access_range T>
183 auto c(T&& range) const -> std::ranges::range_value_t<T>
184 {
185 return range[indices[2]];
186 }
187
188 template <std::ranges::random_access_range T>
189 auto as_triangle(T&& range) const -> ttriangle<typename std::ranges::range_value_t<T>::value_type> { return { at(range, indices[0]), at(range, indices[1]), at(range, indices[2]) }; }
190 };
191
192 using indexed_triangle = tindexed_triangle<size_t>;
193
195}
A shape for which the concept of an "area" has a finite interpretation.
A shape with vertices and edges.
constexpr decltype(auto) at(random_access_range auto &range, std::integral auto index)
Returns a reference to the value at index of range.
Definition ranges.h:61
constexpr __contains_fn contains
contains(range, el)
Definition ranges.h:264
Stores three indices to a indexable_polygonlike that together form a triangle.
Definition triangles.h:167