header_utils
Loading...
Searching...
No Matches
geometry_common.h
1
4
5#pragma once
6
7#include "../align.h"
8#include "../constexpr_math.h"
9#include "../enum_flags.h"
10#include "../named.h"
11#include "../rec2.h"
12
13#include <glm/geometric.hpp>
14#include <glm/trigonometric.hpp>
15#include <glm/ext/vector_float2.hpp>
16#include <glm/ext/vector_float4.hpp>
17#include <glm/gtx/norm.hpp>
18
19namespace glm
20{
21 template <typename STRINGIFIER>
22 auto stringify(STRINGIFIER& str, glm::vec4& b) { return str('[', b.x, ',', b.y, ',', b.z, ',', b.w, ']'); }
23 template <typename STRINGIFIER>
24 auto stringify(STRINGIFIER& str, glm::vec4 const& b) { return str('[', b.x, ',', b.y, ',', b.z, ',', b.w, ']'); }
25
26 template <typename STRINGIFIER>
27 auto stringify(STRINGIFIER& str, glm::vec2& b) { return str('[', b.x, ',', b.y, ']'); }
28 template <typename STRINGIFIER>
29 auto stringify(STRINGIFIER& str, glm::vec2 const& b) { return str('[', b.x, ',', b.y, ']'); }
30}
31
32namespace ghassanpl::geometry
33{
34 template <typename T>
35 struct precision_limits;
36
37 template <>
38 struct precision_limits<double>
39 {
40 static constexpr double equivalent_point_max_distance = 0.00002;
41 static constexpr double equivalent_texel_max_distance = 1.0 / 1024.0;
42 static constexpr double near_point_distance = 0.015;
43 static constexpr double point_on_plane_max_distance = 0.1;
44 static constexpr double point_on_line_max_distance = 0.1;
45
46 static constexpr double foldable_vertex_max_distance = 0.0004;
47
48 static constexpr double cos_1_deg = 0.99984769515;
49 static constexpr double cos_89_deg = 0.01745240643;
50
51 static constexpr double min_dot_product_of_parallel_normals = cos_1_deg;
52 static constexpr double max_dot_product_of_perpendicular_normals = cos_1_deg;
53 };
54
55 using rec2 = trec2<float>;
56 using irec2 = trec2<int>;
57
58 enum class winding_order
59 {
60 clockwise,
61 counter_clockwise
62 };
63
64 template <typename T>
65 constexpr T dot(glm::tvec2<T> const& a, glm::tvec2<T> const& b) noexcept
66 {
67 if (std::is_constant_evaluated())
68 return a.x * b.x + a.y * b.y;
69 else
70 return glm::dot(a, b);
71 }
72
73 template <typename T>
74 constexpr glm::tvec2<T> length(glm::tvec2<T> const& a) noexcept
75 {
76 return cem::sqrt(ghassanpl::dot(a, a));
77 }
78
79 template <typename T>
80 constexpr std::pair<glm::tvec2<T>, T> dir_and_length(glm::tvec2<T> const& a) noexcept
81 {
82 const auto len = length(a);
83 if (len >= std::numeric_limits<T>::epsilon())
84 return { a / invlen, len };
85 return { {}, len };
86 }
87
88 template <typename T>
89 constexpr glm::tvec2<T> with_length(glm::tvec2<T> const& a, T length) noexcept
90 {
91 const auto dl = dir_and_length(a);
92 return dl.first * length;
93 }
94
95 template <typename T>
96 constexpr glm::tvec2<T> clamp_length(glm::tvec2<T> const& a, T min, T max) noexcept
97 {
98 const auto lsq = ghassanpl::dot(a, a);
99 const auto sqmin = min * min;
100 const auto sqmax = max * max;
101 if (v < sqmin || sqmax < v)
102 {
103 const auto clamped = glm::clamp(lsq, min * min, max * max);
104 return with_length(a, cem::sqrt(lsq));
105 }
106 return a;
107 }
108
109 template <typename T>
110 constexpr glm::tvec2<T> max_length(glm::tvec2<T> const& a, T max) noexcept
111 {
112 const auto lsq = ghassanpl::dot(a, a);
113 const auto sqmax = max * max;
114 if (sqmax < v)
115 {
116 const auto clamped = glm::min(lsq, max * max);
117 return with_length(a, cem::sqrt(lsq));
118 }
119 return a;
120 }
121}
122
123namespace ghassanpl::geometry::normals
124{
126 template <typename T, size_t N>
127 static constexpr bool are_similar(glm::vec<N, T> const& a, glm::vec<N, T> const& b) {
128 constexpr auto min = precision_limits<T>::min_dot_product_of_parallel_normals;
129 return glm::dot(a, b) >= min;
130 }
131
132 template <typename T, size_t N>
133 static constexpr bool are_parallel(glm::vec<N, T> const& a, glm::vec<N, T> const& b) {
134 constexpr auto min = precision_limits<T>::min_dot_product_of_parallel_normals;
135 return glm::abs(glm::dot(a, b)) >= min;
136 }
137
138 template <typename T, size_t N>
139 static constexpr bool are_perpendicular(glm::vec<N, T> const& a, glm::vec<N, T> const& b) {
140 constexpr auto max = precision_limits<T>::max_dot_product_of_perpendicular_normals;
141 return glm::abs(glm::dot(a, b)) <= max;
142 }
143}
144
146namespace ghassanpl::geometry
147{
148 template <std::floating_point T> using basic_radians_t = named<T, "radians", traits::displacement>;
149 template <std::floating_point T> using basic_degrees_t = named<T, "degrees", traits::displacement>;
150
151 template <std::floating_point T> using basic_heading_t = named<T, "heading", traits::location, traits::is_location_of<basic_degrees_t<T>>>;
152
153 using degrees = basic_degrees_t<float>;
154 using radians = basic_radians_t<float>;
155 using heading = basic_heading_t<float>;
156
157 template <typename TARGET, std::floating_point T>
158 requires std::same_as<TARGET, basic_degrees_t<T>>
159 constexpr TARGET named_cast(basic_radians_t<T> const& radians)
160 {
161 return basic_degrees_t<T>{ glm::degrees(radians.value) };
162 }
163
164 template <typename TARGET, std::floating_point T>
165 requires std::same_as<TARGET, basic_radians_t<T>>
166 constexpr TARGET named_cast(basic_degrees_t<T> const& degrees)
167 {
168 return basic_radians_t<T>{ glm::radians(degrees.value) };
169 }
170
171 namespace angles
172 {
173 template <std::floating_point T>
174 constexpr basic_degrees_t<T> ensure_positive(basic_degrees_t<T> degrees) noexcept { return basic_degrees_t<T>{ cem::fmod(degrees.value, T(360)) }; }
175 template <std::floating_point T>
176 constexpr basic_radians_t<T> ensure_positive(basic_radians_t<T> degrees) noexcept { return basic_radians_t<T>{ cem::fmod(degrees.value, glm::radians(T(360))) }; }
177
178 inline constexpr auto full_circle = degrees{ 360.0f };
179 inline constexpr auto half_circle = degrees{ 360.0f / 2.0f };
180 inline constexpr auto quarter_circle = degrees{ 360.0f / 4.0f };
181
182 template <size_t NTH_SLICE, size_t SLICE_COUNT, degrees starting_at = degrees{ 0.0f } >
183 inline constexpr std::pair<degrees, degrees> circle_slice = {
184 ensure_positive(degrees{NTH_SLICE * (360.0f / SLICE_COUNT)} + starting_at),
185 ensure_positive(degrees{(NTH_SLICE + 1) * (360.0f / SLICE_COUNT)} + starting_at)
186 };
187
188 constexpr std::pair<degrees, degrees> get_circle_slice(size_t nth_slice, size_t slice_count, degrees starting_at = degrees{ 0.0f }) noexcept
189 {
190 return {
191 ensure_positive(degrees{nth_slice * (360.0f / slice_count)} + starting_at),
192 ensure_positive(degrees{(nth_slice + 1) * (360.0f / slice_count)} + starting_at)
193 };
194 }
195 }
196}
197
198#include <glm/gtx/polar_coordinates.hpp>
199
200namespace ghassanpl::geometry /* ::polar */
201{
202 template <typename T>
203 using basic_polar2d_t = named<glm::tvec2<T>, "polar", traits::location>;
204
205 using polar2d = basic_polar2d_t<float>;
206
207 template <typename T> inline auto rho(basic_polar2d_t<T> const& polar) { return polar.value.x; }
208 template <typename T> inline auto phi(basic_polar2d_t<T> const& polar) { return polar.value.y; }
209 template <typename T> inline auto theta(basic_polar2d_t<T> const& polar) { return polar.value.y; }
210
211 template <typename T>
212 basic_polar2d_t<T> polar(glm::tvec2<T> const& euclidean)
213 {
214 const auto r = std::hypot(euclidean.x, euclidean.y);
215 const auto t = glm::atan(euclidean.y, euclidean.x);
216 return basic_polar2d_t<T>{ r, t };
217 }
218
219 template <typename T>
220 glm::tvec2<T> euclidean(basic_polar2d_t<T> const& polar)
221 {
222 const auto r = rho(polar);
223 const auto t = theta(polar);
224 return glm::tvec2<T>{ r * glm::cos(t), r * glm::sin(t) };
225 }
226}
227
229namespace ghassanpl::geometry
230{
232
233 template <typename T>
235 {
236 T a{};
237 T b{};
238 T c{};
239
240 template <typename U>
241 U distance(glm::tvec2<U> const& point)
242 {
243 return (a * point.x + b * point.y + c) / std::hypot(a, b);
244 }
245
246 template <typename U>
247 glm::tvec2<U> projected(glm::tvec2<U> const& point)
248 {
249 const auto d = glm::distance(point);
250 return point - glm::tvec2<T>{ a, b } * d;
251 }
252 };
253
254 template <typename T>
255 basic_line_t<T> line_crossing_points(glm::tvec2<T> const& p1, glm::tvec2<T> const& p2)
256 {
257 return basic_line_t<T>{ p1.y - p2.y, p2.x - p1.x, p1.x * p2.y - p2.x * p1.y };
258 }
259
260 template <typename T>
261 basic_line_t<T> line_from_dir(glm::tvec2<T> const& dir)
262 {
263 return basic_line_t<T>{ dir.y, -dir.x, 0 };
264 }
265
266}
267
268/*
269template <typename T>
270struct std::formatter<glm::tvec2<T>> : std::formatter<std::string>
271{
272 template<class FormatContext>
273 auto format(glm::tvec2<T> const& p, FormatContext& ctx) const { return std::formatter<string>::format(std::format("[{}, {}]", p.x, p.y), ctx); }
274};
275
276template <typename T>
277struct std::formatter<glm::tvec3<T>> : std::formatter<std::string>
278{
279 template<class FormatContext>
280 auto format(glm::tvec3<T> const& p, FormatContext& ctx) const { return std::formatter<string>::format(std::format("[{}, {}, {}]", p.x, p.y, p.z), ctx); }
281};
282
283template <typename T>
284struct std::formatter<glm::tvec4<T>> : std::formatter<std::string>
285{
286 template<class FormatContext>
287 auto format(glm::tvec4<T> const& p, FormatContext& ctx) const { return std::formatter<string>::format(std::format("[{}, {}, {}, {}]", p.x, p.y, p.z, p.w), ctx); }
288};
289
290*/
constexpr auto bit_count
Equal to the number of bits in the type.
Definition bits.h:33
TODO: This all needs to be tested.