8#include "../constexpr_math.h"
9#include "../enum_flags.h"
12#include "../functional.h"
14#include <glm/geometric.hpp>
15#include <glm/trigonometric.hpp>
24 template <
typename STRINGIFIER>
25 auto stringify(STRINGIFIER& str, glm::vec4& b) {
return str(
'[', b.x,
',', b.y,
',', b.z,
',', b.w,
']'); }
26 template <
typename STRINGIFIER>
27 auto stringify(STRINGIFIER& str, glm::vec4
const& b) {
return str(
'[', b.x,
',', b.y,
',', b.z,
',', b.w,
']'); }
29 template <
typename STRINGIFIER>
30 auto stringify(STRINGIFIER& str, glm::vec2& b) {
return str(
'[', b.x,
',', b.y,
']'); }
31 template <
typename STRINGIFIER>
32 auto stringify(STRINGIFIER& str, glm::vec2
const& b) {
return str(
'[', b.x,
',', b.y,
']'); }
34 template <std::
signed_
integral T>
35 constexpr auto to_signed(glm::tvec2<T> v)
noexcept {
return v; }
36 template <std::
unsigned_
integral T>
37 constexpr auto to_signed(glm::tvec2<T> v)
noexcept {
return glm::tvec2<std::make_signed_t<T>>(v); }
39 template <std::
unsigned_
integral T>
40 constexpr auto to_unsigned(glm::tvec2<T> v)
noexcept {
return v; }
41 template <std::
signed_
integral T>
42 constexpr auto to_unsigned(glm::tvec2<T> v)
noexcept {
return glm::tvec2<std::make_unsigned_t<T>>(v); }
45 template <std::
integral T, std::
integral U>
46 constexpr auto abs_distance(glm::tvec2<T> a, glm::tvec2<U> b)
noexcept {
return glm::abs(to_signed(a) - to_signed(b)); }
51 template <
typename T,
template <
typename U, glm::qualifier Q = glm::defaultp>
typename GLM_TYPE>
52 concept is_specialization_of = std::invocable<decltype([]<typename V>(GLM_TYPE<V>
const&) {}), T>;
58 struct precision_limits;
61 struct precision_limits<double>
63 static constexpr double equivalent_point_max_distance = 0.00002;
64 static constexpr double equivalent_texel_max_distance = 1.0 / 1024.0;
65 static constexpr double near_point_distance = 0.015;
66 static constexpr double point_on_plane_max_distance = 0.1;
67 static constexpr double point_on_line_max_distance = 0.1;
69 static constexpr double foldable_vertex_max_distance = 0.0004;
71 static constexpr double cos_1_deg = 0.99984769515;
72 static constexpr double cos_89_deg = 0.01745240643;
74 static constexpr double min_dot_product_of_parallel_normals = cos_1_deg;
75 static constexpr double max_dot_product_of_perpendicular_normals = cos_1_deg;
81 enum class winding_order
88 constexpr T dot(glm::tvec2<T>
const& a, glm::tvec2<T>
const& b)
noexcept
90 if (std::is_constant_evaluated())
91 return a.x * b.x + a.y * b.y;
93 return glm::dot(a, b);
97 constexpr glm::tvec2<T> length(glm::tvec2<T>
const& a)
noexcept
99 return cem::sqrt(geometry::dot(a, a));
102 template <
typename T>
103 constexpr std::pair<glm::tvec2<T>, T> dir_and_length(glm::tvec2<T>
const& a)
noexcept
105 const auto len = geometry::length(a);
106 if (len >= std::numeric_limits<T>::epsilon())
107 return { a / len, len };
111 template <
typename T>
112 constexpr glm::tvec2<T> with_length(glm::tvec2<T>
const& a, T length)
noexcept
114 const auto dl = geometry::dir_and_length(a);
115 return dl.first * length;
118 template <
typename T>
119 constexpr glm::tvec2<T> clamp_length(glm::tvec2<T>
const& a, T min, T max)
noexcept
121 const auto lsq = geometry::dot(a, a);
122 const auto sqmin = min * min;
123 const auto sqmax = max * max;
124 if (lsq < sqmin || sqmax < lsq)
126 const auto clamped = glm::clamp(lsq, min * min, max * max);
127 return with_length(a, cem::sqrt(lsq));
132 template <
typename T>
133 constexpr glm::tvec2<T> max_length(glm::tvec2<T>
const& a, T max)
noexcept
135 const auto lsq = geometry::dot(a, a);
136 const auto sqmax = max * max;
139 const auto clamped = glm::min(lsq, max * max);
140 return with_length(a, cem::sqrt(lsq));
146namespace ghassanpl::geometry::normals
154 template <
typename T,
size_t N>
155 static constexpr bool are_similar(glm::vec<N, T>
const& a, glm::vec<N, T>
const& b) {
156 constexpr auto min = precision_limits<T>::min_dot_product_of_parallel_normals;
157 return geometry::dot(a, b) >= min;
161 template <
typename T,
size_t N>
162 static constexpr bool are_parallel(glm::vec<N, T>
const& a, glm::vec<N, T>
const& b) {
163 constexpr auto min = precision_limits<T>::min_dot_product_of_parallel_normals;
164 return glm::abs(geometry::dot(a, b)) >= min;
168 template <
typename T,
size_t N>
170 constexpr auto max = precision_limits<T>::max_dot_product_of_perpendicular_normals;
171 return glm::abs(geometry::dot(a, b)) <= max;
192 template <std::
floating_po
int T>
193 constexpr basic_degrees_t<T> to_degrees(basic_radians_t<T> r) {
return degrees{ glm::degrees(*r) }; }
194 template <std::
floating_po
int T>
195 constexpr basic_radians_t<T> to_radians(basic_degrees_t<T> r) {
return degrees{ glm::radians(*r) }; }
197 template <
typename TARGET, std::
floating_po
int T>
198 requires std::same_as<TARGET, basic_degrees_t<T>>
199 constexpr TARGET named_cast(basic_radians_t<T>
const& radians)
201 return basic_degrees_t<T>{ glm::degrees(radians.value) };
204 template <
typename TARGET, std::
floating_po
int T>
205 requires std::same_as<TARGET, basic_radians_t<T>>
206 constexpr TARGET named_cast(basic_degrees_t<T>
const& degrees)
208 return basic_radians_t<T>{ glm::radians(degrees.value) };
216 template <std::
floating_po
int T>
217 constexpr basic_degrees_t<T> ensure_positive(basic_degrees_t<T> degrees)
noexcept {
218 const auto deg = cem::fmod(degrees.get(), T(360));
219 return basic_degrees_t<T>{ (deg < T(0)) ? deg + T(360) : deg };
222 template <std::
floating_po
int T>
223 constexpr basic_radians_t<T> ensure_positive(basic_radians_t<T> radians)
noexcept {
224 const auto rad = cem::fmod(radians.get(), glm::radians(T(360)));
225 return basic_radians_t<T>{ (rad < T(0)) ? rad + glm::radians(T(360)) : rad };
228 inline constexpr auto full_circle = degrees{ 360.0f };
229 inline constexpr auto half_circle = degrees{ 360.0f / 2.0f };
230 inline constexpr auto quarter_circle = degrees{ 360.0f / 4.0f };
232 template <
size_t NTH_SLICE,
size_t SLICE_COUNT, degrees starting_at = degrees{ 0.0f } >
233 inline constexpr std::pair<degrees, degrees> circle_slice = {
234 ensure_positive(degrees{NTH_SLICE * (360.0f / SLICE_COUNT)} + starting_at),
235 ensure_positive(degrees{(NTH_SLICE + 1) * (360.0f / SLICE_COUNT)} + starting_at)
238 constexpr std::pair<degrees, degrees> get_circle_slice(
size_t nth_slice,
size_t slice_count, degrees starting_at = degrees{ 0.0f })
noexcept
241 ensure_positive(degrees{nth_slice * (360.0f / slice_count)} + starting_at),
242 ensure_positive(degrees{(nth_slice + 1) * (360.0f / slice_count)} + starting_at)
252#ifndef GLM_ENABLE_EXPERIMENTAL
253#define GLM_ENABLE_EXPERIMENTAL
255#include <glm/gtx/polar_coordinates.hpp>
256#undef GLM_ENABLE_EXPERIMENTAL
260 template <
typename T>
261 using basic_polar2d_t = named<glm::tvec2<T>,
"polar", traits::location>;
263 using polar2d = basic_polar2d_t<float>;
265 template <
typename T>
inline basic_radians_t<T> rho(basic_polar2d_t<T>
const& polar) {
return basic_radians_t<T>{ polar.value.x }; }
266 template <
typename T>
inline basic_radians_t<T> phi(basic_polar2d_t<T>
const& polar) {
return basic_radians_t<T>{ polar.value.y }; }
267 template <
typename T>
inline basic_radians_t<T> theta(basic_polar2d_t<T>
const& polar) {
return basic_radians_t<T>{ polar.value.y }; }
269 template <
typename T>
270 basic_polar2d_t<T> polar(glm::tvec2<T>
const& euclidean)
272 const auto r = std::hypot(euclidean.x, euclidean.y);
273 const auto t = glm::atan(euclidean.y, euclidean.x);
274 return basic_polar2d_t<T>{ r, t };
277 template <
typename T>
278 basic_polar2d_t<T> polar_rho_phi(basic_radians_t<T> rho, basic_radians_t<T> phi)
280 return basic_polar2d_t<T>{ *rho, *phi };
283 template <
typename T>
284 glm::tvec2<T> euclidean(basic_polar2d_t<T>
const& polar)
286 const auto r = *rho(polar);
287 const auto t = *theta(polar);
288 return glm::tvec2<T>{ r * glm::cos(t), r * glm::sin(t) };
300 template <
typename T>
307 using value_type = T;
308 using vec2 = glm::tvec2<T>;
310 template <
typename U>
311 U distance(glm::tvec2<U>
const& point)
313 return (a * point.x + b * point.y + c) / std::hypot(a, b);
316 template <
typename U>
317 glm::tvec2<U> closest_point_to(glm::tvec2<U>
const& point)
319 const auto d = glm::distance(point);
320 return point - glm::tvec2<T>{ a, b } * d;
326 const auto d = a * point.x + b * point.y + c;
327 return d > 0 ? 1 : d < 0 ? -1 : 0;
333 template <
typename T>
336 return basic_line_t<T>{ p1.y - p2.y, p2.x - p1.x, p1.x * p2.y - p2.x * p1.y };
339 template <
typename T>
340 basic_line_t<T> line_from_dir(glm::tvec2<T>
const& dir)
342 return basic_line_t<T>{ dir.y, -dir.x, 0 };
356 template <
typename T>
362 bool overlaps(
interval const& other)
const {
return min <= other.max && other.min <= max; }
363 T overlap(
interval const& other)
const {
return (std::abs(other.min - max) < std::abs(other.max - min)) ? other.min - max : other.max - min; }
366 template <
typename T>
367 interval<T> projected_on_axis(glm::tvec2<T> axis, glm::tvec2<T>
const& point)
369 const auto len = glm::dot(axis, point);
basic_line_t< T > line_crossing_points(glm::tvec2< T > const &p1, glm::tvec2< T > const &p2)
TODO: Move these to the body as static methods?
#define ghassanpl_named_float_literal(named_name, suffix)
Creates a user-defined floating-point literal which will result in a given named type.
static constexpr bool are_perpendicular(glm::vec< N, T > const &a, glm::vec< N, T > const &b)
Whether these vectors are (mostly) perpendicular.
static constexpr bool are_similar(glm::vec< N, T > const &a, glm::vec< N, T > const &b)
Whether these vectors are (mostly) parallel and point in the same direction.
static constexpr bool are_parallel(glm::vec< N, T > const &a, glm::vec< N, T > const &b)
Whether these vectors are (mostly) parallel.
Primary namespace for everything in this library.
TODO: This all needs to be tested.
int side(vec2 const &point)
TODO: should we create enum { positive/above, negative/below, zero/on_line/colinear/coplanar }...
For interval<T> projected_on_axis(glm::tvec2<T> axis) const;.
Represents a 2D rectangle polygon_shape.
Used to create a strong typedef of T.
This trait implies the named type is an linear type, that is, a type that has the addition operator d...
Used in conjuction with traits::location, specifies which displacement type this is a location of.
This trait implies the named type is an affine type, that is, a type that does not have the addition ...