summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/filesystem.cpp2
-rw-r--r--lib/filesystem.h2
-rw-r--r--lib/jsonParse-persistence.h3
-rw-r--r--lib/maths.cpp101
-rw-r--r--lib/maths.h377
-rw-r--r--lib/stream_support.h38
-rw-r--r--lib/triangle.h108
7 files changed, 437 insertions, 194 deletions
diff --git a/lib/filesystem.cpp b/lib/filesystem.cpp
index 7e8ab9c..5c0c6f8 100644
--- a/lib/filesystem.cpp
+++ b/lib/filesystem.cpp
@@ -37,7 +37,7 @@ namespace filesystem {
}
// NOLINTNEXTLINE(hicpp-vararg)
- fh::fh(const char * path, int flags, int mode) : h {open(path, flags, mode)}
+ fh::fh(const char * path, int flags, mode_t mode) : h {open(path, flags, mode)}
{
if (h == -1) {
throw_filesystem_error("open", errno, path);
diff --git a/lib/filesystem.h b/lib/filesystem.h
index b076f43..92dc08d 100644
--- a/lib/filesystem.h
+++ b/lib/filesystem.h
@@ -30,7 +30,7 @@ namespace filesystem {
class [[nodiscard]] fh final {
public:
- fh(const char * path, int flags, int mode);
+ fh(const char * path, int flags, mode_t mode);
~fh();
NO_MOVE(fh);
NO_COPY(fh);
diff --git a/lib/jsonParse-persistence.h b/lib/jsonParse-persistence.h
index 6edebc7..e4e64c0 100644
--- a/lib/jsonParse-persistence.h
+++ b/lib/jsonParse-persistence.h
@@ -15,6 +15,9 @@ namespace Persistence {
inline T
loadState(std::istream & in)
{
+ if (!in.good()) {
+ throw std::runtime_error("Input stream not in good state");
+ }
T t {};
stk.push(std::make_unique<SelectionT<T>>(std::ref(t)));
loadState(in);
diff --git a/lib/maths.cpp b/lib/maths.cpp
index 51e27fe..3a9bf9b 100644
--- a/lib/maths.cpp
+++ b/lib/maths.cpp
@@ -19,96 +19,17 @@ flat_orientation(const Direction3D & diff)
return (std::isnan(e[0][0])) ? oneeighty : e;
}
-// Helper to lookup into a matrix given an xy vector coordinate
-template<typename M, typename I>
-inline auto &
-operator^(M & m, glm::vec<2, I> xy)
-{
- return m[xy.x][xy.y];
-}
-
-// Create a matrix for the angle, given the targets into the matrix
-template<typename M, typename I>
-inline auto
-rotation(typename M::value_type a, glm::vec<2, I> c1, glm::vec<2, I> s1, glm::vec<2, I> c2, glm::vec<2, I> ms2)
-{
- M m(1);
- sincosf(a, m ^ s1, m ^ c1);
- m ^ c2 = m ^ c1;
- m ^ ms2 = -(m ^ s1);
- return m;
-}
-
-// Create a flat (2D) transformation matrix
-glm::mat2
-rotate_flat(float a)
-{
- return rotation<glm::mat2, glm::length_t>(a, {0, 0}, {0, 1}, {1, 1}, {1, 0});
-}
-
-// Create a yaw transformation matrix
-glm::mat4
-rotate_yaw(float a)
-{
- return rotation<glm::mat4, glm::length_t>(a, {0, 0}, {1, 0}, {1, 1}, {0, 1});
-}
-
-// Create a roll transformation matrix
-glm::mat4
-rotate_roll(float a)
-{
- return rotation<glm::mat4, glm::length_t>(a, {0, 0}, {2, 0}, {2, 2}, {0, 2});
-}
-
-// Create a pitch transformation matrix
-glm::mat4
-rotate_pitch(float a)
-{
- return rotation<glm::mat4, glm::length_t>(a, {1, 1}, {1, 2}, {2, 2}, {2, 1});
-}
-
-// Create a combined yaw, pitch, roll transformation matrix
-glm::mat4
-rotate_ypr(Rotation3D a)
-{
- return rotate_yaw(a.y) * rotate_pitch(a.x) * rotate_roll(a.z);
-}
-
-glm::mat4
-rotate_yp(Rotation2D a)
-{
- return rotate_yaw(a.y) * rotate_pitch(a.x);
-}
-
-float
-vector_yaw(const Direction2D & diff)
-{
- return std::atan2(diff.x, diff.y);
-}
-
-float
-vector_pitch(const Direction3D & diff)
-{
- return std::atan(diff.z);
-}
-
-float
-round_frac(const float & v, const float & frac)
-{
- return std::round(v / frac) * frac;
-}
-
-float
-normalize(float ang)
-{
- while (ang > pi) {
- ang -= two_pi;
- }
- while (ang <= -pi) {
- ang += two_pi;
- }
- return ang;
-}
+static_assert(pow(1, 0) == 1);
+static_assert(pow(1, 1) == 1);
+static_assert(pow(1, 2) == 1);
+static_assert(pow(2, 0) == 1);
+static_assert(pow(2, 1) == 2);
+static_assert(pow(2, 2) == 4);
+static_assert(pow(2, 3) == 8);
+static_assert(pow(3, 0) == 1);
+static_assert(pow(3, 1) == 3);
+static_assert(pow(3, 2) == 9);
+static_assert(pow(pi, 3) == 31.006278991699219F);
float
operator"" _mph(const long double v)
diff --git a/lib/maths.h b/lib/maths.h
index 3127d3c..3959896 100644
--- a/lib/maths.h
+++ b/lib/maths.h
@@ -5,11 +5,15 @@
#include <glm/glm.hpp>
#include <glm/gtc/constants.hpp>
#include <numeric>
+#include <optional>
#include <stdexcept>
#include <utility>
+template<typename T>
+concept Arithmetic = std::is_arithmetic_v<T>;
+
struct Arc : public std::pair<Angle, Angle> {
- template<glm::length_t Lc, glm::length_t Le, typename T, glm::qualifier Q>
+ template<glm::length_t Lc, glm::length_t Le, Arithmetic T, glm::qualifier Q>
requires(Lc >= 2, Le >= 2)
Arc(const glm::vec<Lc, T, Q> & centre, const glm::vec<Le, T, Q> & e0p, const glm::vec<Le, T, Q> & e1p) :
Arc {RelativePosition2D {e0p.xy() - centre.xy()}, RelativePosition2D {e1p.xy() - centre.xy()}}
@@ -17,22 +21,22 @@ struct Arc : public std::pair<Angle, Angle> {
}
Arc(const RelativePosition2D & dir0, const RelativePosition2D & dir1);
- Arc(const Angle angb, const Angle anga);
+ Arc(Angle anga, Angle angb);
auto
- operator[](bool i) const
+ operator[](bool getSecond) const
{
- return i ? second : first;
+ return getSecond ? second : first;
}
- [[nodiscard]] constexpr inline float
+ [[nodiscard]] constexpr float
length() const
{
return second - first;
}
};
-constexpr const RelativePosition3D up {0, 0, 1};
+constexpr const RelativePosition3D up {0, 0, 1}; // NOLINT(readability-identifier-length)
constexpr const RelativePosition3D down {0, 0, -1};
constexpr const RelativePosition3D north {0, 1, 0};
constexpr const RelativePosition3D south {0, -1, 0};
@@ -40,7 +44,7 @@ constexpr const RelativePosition3D east {1, 0, 0};
constexpr const RelativePosition3D west {-1, 0, 0};
constexpr auto half_pi {glm::half_pi<float>()};
constexpr auto quarter_pi {half_pi / 2};
-constexpr auto pi {glm::pi<float>()};
+constexpr auto pi {glm::pi<float>()}; // NOLINT(readability-identifier-length)
constexpr auto two_pi {glm::two_pi<float>()};
constexpr auto degreesToRads = pi / 180.F;
@@ -48,154 +52,314 @@ constexpr auto earthMeanRadius = 6371.01F; // In km
constexpr auto astronomicalUnit = 149597890.F; // In km
template<glm::length_t D>
-constexpr inline GlobalPosition<D>
-operator+(const GlobalPosition<D> & g, const RelativePosition<D> & r)
+constexpr GlobalPosition<D>
+operator+(const GlobalPosition<D> & global, const RelativePosition<D> & relative)
{
- return g + GlobalPosition<D>(glm::round(r));
+ return global + GlobalPosition<D>(glm::round(relative));
}
template<glm::length_t D>
-constexpr inline GlobalPosition<D>
-operator+(const GlobalPosition<D> & g, const CalcPosition<D> & r)
+constexpr GlobalPosition<D>
+operator+(const GlobalPosition<D> & global, const CalcPosition<D> & relative)
{
- return g + GlobalPosition<D>(r);
+ return global + GlobalPosition<D>(relative);
}
template<glm::length_t D>
-constexpr inline GlobalPosition<D>
-operator-(const GlobalPosition<D> & g, const RelativePosition<D> & r)
+constexpr GlobalPosition<D>
+operator-(const GlobalPosition<D> & global, const RelativePosition<D> & relative)
{
- return g - GlobalPosition<D>(glm::round(r));
+ return global - GlobalPosition<D>(glm::round(relative));
}
template<glm::length_t D>
-constexpr inline GlobalPosition<D>
-operator-(const GlobalPosition<D> & g, const CalcPosition<D> & r)
+constexpr GlobalPosition<D>
+operator-(const GlobalPosition<D> & global, const CalcPosition<D> & relative)
+{
+ return global - GlobalPosition<D>(relative);
+}
+
+template<glm::length_t D, std::integral T, glm::qualifier Q>
+constexpr RelativePosition<D>
+difference(const glm::vec<D, T, Q> & globalA, const glm::vec<D, T, Q> & globalB)
{
- return g - GlobalPosition<D>(r);
+ return globalA - globalB;
}
glm::mat4 flat_orientation(const Rotation3D & diff);
-// C++ wrapper for C's sincosf, but with references, not pointers
-inline auto
-sincosf(float a, float & s, float & c)
+namespace {
+ // Helpers
+ // C++ wrapper for C's sincosf, but with references, not pointers
+ template<std::floating_point T>
+ constexpr void
+ sincos(T angle, T & sinOut, T & cosOut)
+ {
+ if consteval {
+ sinOut = std::sin(angle);
+ cosOut = std::cos(angle);
+ }
+ else {
+ if constexpr (std::is_same_v<T, float>) {
+ ::sincosf(angle, &sinOut, &cosOut);
+ }
+ else if constexpr (std::is_same_v<T, double>) {
+ ::sincos(angle, &sinOut, &cosOut);
+ }
+ else if constexpr (std::is_same_v<T, long double>) {
+ ::sincosl(angle, &sinOut, &cosOut);
+ }
+ }
+ }
+
+ template<std::floating_point T, glm::qualifier Q = glm::qualifier::defaultp>
+ constexpr auto
+ sincos(const T angle)
+ {
+ glm::vec<2, T, Q> sincosOut {};
+ sincos(angle, sincosOut.x, sincosOut.y);
+ return sincosOut;
+ }
+
+ // Helper to lookup into a matrix given an xy vector coordinate
+ template<glm::length_t C, glm::length_t R, Arithmetic T, glm::qualifier Q, std::integral I = glm::length_t>
+ constexpr auto &
+ operator^(glm::mat<C, R, T, Q> & matrix, const glm::vec<2, I> rowCol)
+ {
+ return matrix[rowCol.x][rowCol.y];
+ }
+
+ // Create a matrix for the angle, given the targets into the matrix
+ template<glm::length_t D, std::floating_point T, glm::qualifier Q, std::integral I = glm::length_t>
+ constexpr auto
+ rotation(const T angle, const glm::vec<2, I> cos1, const glm::vec<2, I> sin1, const glm::vec<2, I> cos2,
+ const glm::vec<2, I> negSin1)
+ {
+ glm::mat<D, D, T, Q> out(1);
+ sincos(angle, out ^ sin1, out ^ cos1);
+ out ^ cos2 = out ^ cos1;
+ out ^ negSin1 = -(out ^ sin1);
+ return out;
+ }
+}
+
+// Create a flat transformation matrix
+template<glm::length_t D = 2, glm::qualifier Q = glm::qualifier::defaultp, std::floating_point T>
+ requires(D >= 2)
+constexpr auto
+rotate_flat(const T angle)
+{
+ return rotation<D, T, Q>(angle, {0, 0}, {0, 1}, {1, 1}, {1, 0});
+}
+
+// Create a yaw transformation matrix
+template<glm::length_t D = 3, glm::qualifier Q = glm::qualifier::defaultp, std::floating_point T>
+ requires(D >= 2)
+constexpr auto
+rotate_yaw(const T angle)
+{
+ return rotation<D, T, Q>(angle, {0, 0}, {1, 0}, {1, 1}, {0, 1});
+}
+
+// Create a roll transformation matrix
+template<glm::length_t D = 3, glm::qualifier Q = glm::qualifier::defaultp, std::floating_point T>
+ requires(D >= 3)
+constexpr auto
+rotate_roll(const T angle)
+{
+ return rotation<D, T, Q>(angle, {0, 0}, {2, 0}, {2, 2}, {0, 2});
+}
+
+// Create a pitch transformation matrix
+template<glm::length_t D = 3, glm::qualifier Q = glm::qualifier::defaultp, std::floating_point T>
+ requires(D >= 3)
+constexpr auto
+rotate_pitch(const T angle)
+{
+ return rotation<D, T, Q>(angle, {1, 1}, {1, 2}, {2, 2}, {2, 1});
+}
+
+// Create a combined yaw, pitch, roll transformation matrix
+template<glm::length_t D = 3, glm::qualifier Q = glm::qualifier::defaultp, std::floating_point T>
+ requires(D >= 3)
+constexpr auto
+rotate_ypr(const glm::vec<3, T, Q> & angles)
{
- return sincosf(a, &s, &c);
+ return rotate_yaw<D>(angles.y) * rotate_pitch<D>(angles.x) * rotate_roll<D>(angles.z);
}
-inline Rotation2D
-sincosf(float a)
+template<glm::length_t D = 3, glm::qualifier Q = glm::qualifier::defaultp, std::floating_point T>
+ requires(D >= 3)
+constexpr auto
+rotate_yp(const T yaw, const T pitch)
{
- Rotation2D sc;
- sincosf(a, sc.x, sc.y);
- return sc;
+ return rotate_yaw<D>(yaw) * rotate_pitch<D>(pitch);
}
-glm::mat2 rotate_flat(float);
-glm::mat4 rotate_roll(float);
-glm::mat4 rotate_yaw(float);
-glm::mat4 rotate_pitch(float);
-glm::mat4 rotate_yp(Rotation2D);
-glm::mat4 rotate_ypr(Rotation3D);
+template<glm::length_t D = 3, glm::qualifier Q = glm::qualifier::defaultp, std::floating_point T>
+ requires(D >= 3)
+constexpr auto
+rotate_yp(const glm::vec<2, T, Q> & angles)
+{
+ return rotate_yp<D>(angles.y, angles.x);
+}
+
+template<glm::length_t D, glm::qualifier Q = glm::qualifier::defaultp, std::floating_point T>
+ requires(D >= 2)
+constexpr auto
+vector_yaw(const glm::vec<D, T, Q> & diff)
+{
+ return std::atan2(diff.x, diff.y);
+}
-float vector_yaw(const Direction2D & diff);
-float vector_pitch(const Direction3D & diff);
+template<glm::length_t D, glm::qualifier Q = glm::qualifier::defaultp, std::floating_point T>
+ requires(D >= 3)
+constexpr auto
+vector_pitch(const glm::vec<D, T, Q> & diff)
+{
+ return std::atan(diff.z);
+}
-template<typename T, glm::qualifier Q>
-glm::vec<2, T, Q>
-vector_normal(const glm::vec<2, T, Q> & v)
+template<std::floating_point T, glm::qualifier Q>
+constexpr glm::vec<2, T, Q>
+vector_normal(const glm::vec<2, T, Q> & vector)
{
- return {-v.y, v.x};
+ return {-vector.y, vector.x};
};
-float round_frac(const float & v, const float & frac);
+template<std::floating_point T>
+constexpr auto
+round_frac(const T value, const T frac)
+{
+ return std::round(value / frac) * frac;
+}
-template<typename T>
-inline constexpr auto
-sq(T v)
+template<Arithmetic T>
+ requires requires(T value) { value * value; }
+constexpr auto
+sq(T value)
{
- return v * v;
+ return value * value;
}
template<glm::qualifier Q>
-inline constexpr glm::vec<3, int64_t, Q>
-crossProduct(const glm::vec<3, int64_t, Q> a, const glm::vec<3, int64_t, Q> b)
+constexpr glm::vec<3, int64_t, Q>
+crossProduct(const glm::vec<3, int64_t, Q> & valueA, const glm::vec<3, int64_t, Q> & valueB)
{
return {
- (a.y * b.z) - (a.z * b.y),
- (a.z * b.x) - (a.x * b.z),
- (a.x * b.y) - (a.y * b.x),
+ (valueA.y * valueB.z) - (valueA.z * valueB.y),
+ (valueA.z * valueB.x) - (valueA.x * valueB.z),
+ (valueA.x * valueB.y) - (valueA.y * valueB.x),
};
}
template<std::integral T, glm::qualifier Q>
-inline constexpr glm::vec<3, T, Q>
-crossProduct(const glm::vec<3, T, Q> a, const glm::vec<3, T, Q> b)
+constexpr glm::vec<3, T, Q>
+crossProduct(const glm::vec<3, T, Q> & valueA, const glm::vec<3, T, Q> & valueB)
{
- return crossProduct<Q>(a, b);
+ return crossProduct<Q>(valueA, valueB);
}
template<std::floating_point T, glm::qualifier Q>
-inline constexpr glm::vec<3, T, Q>
-crossProduct(const glm::vec<3, T, Q> a, const glm::vec<3, T, Q> b)
+constexpr glm::vec<3, T, Q>
+crossProduct(const glm::vec<3, T, Q> & valueA, const glm::vec<3, T, Q> & valueB)
{
- return glm::cross(a, b);
+ return glm::cross(valueA, valueB);
}
-template<typename R = float, typename Ta, typename Tb>
-inline constexpr auto
-ratio(Ta a, Tb b)
+template<Arithmetic R = float, Arithmetic Ta, Arithmetic Tb>
+constexpr auto
+ratio(const Ta valueA, const Tb valueB)
{
- return (static_cast<R>(a) / static_cast<R>(b));
+ using Common = std::common_type_t<Ta, Ta>;
+ return static_cast<R>((static_cast<Common>(valueA) / static_cast<Common>(valueB)));
}
-template<typename R = float, typename T, glm::qualifier Q>
-inline constexpr auto
-ratio(glm::vec<2, T, Q> v)
+template<Arithmetic R = float, Arithmetic T, glm::qualifier Q>
+constexpr auto
+ratio(const glm::vec<2, T, Q> & value)
{
- return ratio<R>(v.x, v.y);
+ return ratio<R>(value.x, value.y);
}
-template<glm::length_t L = 3, typename T, glm::qualifier Q>
-inline constexpr glm::vec<L, T, Q>
-perspective_divide(glm::vec<4, T, Q> v)
+template<glm::length_t L = 3, std::floating_point T, glm::qualifier Q>
+constexpr auto
+perspective_divide(const glm::vec<4, T, Q> & value)
{
- return v / v.w;
+ return value / value.w;
}
-template<glm::length_t L1, glm::length_t L2, typename T, glm::qualifier Q>
-inline constexpr glm::vec<L1 + L2, T, Q>
-operator||(const glm::vec<L1, T, Q> v1, const glm::vec<L2, T, Q> v2)
+template<glm::length_t L1, glm::length_t L2, Arithmetic T, glm::qualifier Q>
+constexpr glm::vec<L1 + L2, T, Q>
+operator||(const glm::vec<L1, T, Q> valueA, const glm::vec<L2, T, Q> valueB)
{
- return {v1, v2};
+ return {valueA, valueB};
}
-template<glm::length_t L, typename T, glm::qualifier Q>
-inline constexpr glm::vec<L + 1, T, Q>
-operator||(const glm::vec<L, T, Q> v1, const T v2)
+template<glm::length_t L, Arithmetic T, glm::qualifier Q>
+constexpr glm::vec<L + 1, T, Q>
+operator||(const glm::vec<L, T, Q> valueA, const T valueB)
{
- return {v1, v2};
+ return {valueA, valueB};
}
-template<glm::length_t L, typename T, glm::qualifier Q>
-inline constexpr glm::vec<L, T, Q>
-perspectiveMultiply(const glm::vec<L, T, Q> & p, const glm::mat<L + 1, L + 1, T, Q> & mutation)
+template<glm::length_t L, std::floating_point T, glm::qualifier Q>
+constexpr glm::vec<L, T, Q>
+perspectiveMultiply(const glm::vec<L, T, Q> & base, const glm::mat<L + 1, L + 1, T, Q> & mutation)
{
- const auto p2 = mutation * (p || T(1));
- return p2 / p2.w;
+ const auto mutated = mutation * (base || T(1));
+ return mutated / mutated.w;
}
-template<glm::length_t L, typename T, glm::qualifier Q>
-inline constexpr glm::vec<L, T, Q>
-perspectiveApply(glm::vec<L, T, Q> & p, const glm::mat<L + 1, L + 1, T, Q> & mutation)
+template<glm::length_t L, std::floating_point T, glm::qualifier Q>
+constexpr glm::vec<L, T, Q>
+perspectiveApply(glm::vec<L, T, Q> & base, const glm::mat<L + 1, L + 1, T, Q> & mutation)
{
- return p = perspectiveMultiply(p, mutation);
+ return base = perspectiveMultiply(base, mutation);
+}
+
+template<std::floating_point T>
+constexpr T
+normalize(T ang)
+{
+ while (ang > glm::pi<T>()) {
+ ang -= glm::two_pi<T>();
+ }
+ while (ang <= -glm::pi<T>()) {
+ ang += glm::two_pi<T>();
+ }
+ return ang;
}
-float normalize(float ang);
+template<Arithmetic T> using CalcType = std::conditional_t<std::is_floating_point_v<T>, T, int64_t>;
+
+template<Arithmetic T, glm::qualifier Q = glm::defaultp>
+[[nodiscard]] constexpr std::optional<glm::vec<2, T, Q>>
+linesIntersectAt(const glm::vec<2, T, Q> Aabs, const glm::vec<2, T, Q> Babs, const glm::vec<2, T, Q> Cabs,
+ const glm::vec<2, T, Q> Dabs)
+{
+ using CT = CalcType<T>;
+ using CVec = glm::vec<2, CT, Q>;
+ // Line AB represented as a1x + b1y = c1
+ const CVec Brel = Babs - Aabs;
+ const CT a1 = Brel.y;
+ const CT b1 = -Brel.x;
+
+ // Line CD represented as a2x + b2y = c2
+ const CVec Crel = Cabs - Aabs, Del = Dabs - Aabs;
+ const CT a2 = Del.y - Crel.y;
+ const CT b2 = Crel.x - Del.x;
+ const CT c2 = (a2 * Crel.x) + (b2 * Crel.y);
+
+ const auto determinant = (a1 * b2) - (a2 * b1);
+
+ if (determinant == 0) {
+ return std::nullopt;
+ }
+ return Aabs + CVec {(b1 * c2) / -determinant, (a1 * c2) / determinant};
+}
-template<typename T, glm::qualifier Q>
+template<Arithmetic T, glm::qualifier Q>
std::pair<glm::vec<2, T, Q>, bool>
find_arc_centre(glm::vec<2, T, Q> start, Rotation2D startDir, glm::vec<2, T, Q> end, Rotation2D endDir)
{
@@ -208,17 +372,17 @@ find_arc_centre(glm::vec<2, T, Q> start, Rotation2D startDir, glm::vec<2, T, Q>
throw std::runtime_error("no intersection");
}
-template<typename T, glm::qualifier Q>
+template<Arithmetic T, glm::qualifier Q>
std::pair<glm::vec<2, T, Q>, bool>
find_arc_centre(glm::vec<2, T, Q> start, Angle entrys, glm::vec<2, T, Q> end, Angle entrye)
{
if (start == end) {
return {start, false};
}
- return find_arc_centre(start, sincosf(entrys + half_pi), end, sincosf(entrye - half_pi));
+ return find_arc_centre(start, sincos(entrys + half_pi), end, sincos(entrye - half_pi));
}
-template<typename T, glm::qualifier Q>
+template<Arithmetic T, glm::qualifier Q>
Angle
find_arcs_radius(glm::vec<2, T, Q> start, Rotation2D ad, glm::vec<2, T, Q> end, Rotation2D bd)
{
@@ -243,33 +407,46 @@ find_arcs_radius(glm::vec<2, T, Q> start, Rotation2D ad, glm::vec<2, T, Q> end,
/ (2 * (sq(X) - 2 * X * Z + sq(Z) + sq(Y) - 2 * Y * W + sq(W) - 4));
}
-template<typename T, glm::qualifier Q>
+template<Arithmetic T, glm::qualifier Q>
std::pair<Angle, Angle>
find_arcs_radius(glm::vec<2, T, Q> start, Angle entrys, glm::vec<2, T, Q> end, Angle entrye)
{
const auto getrad = [&](auto leftOrRight) {
- return find_arcs_radius(start, sincosf(entrys + leftOrRight), end, sincosf(entrye + leftOrRight));
+ return find_arcs_radius(start, sincos(entrys + leftOrRight), end, sincos(entrye + leftOrRight));
};
return {getrad(-half_pi), getrad(half_pi)};
}
-template<typename T>
+template<Arithmetic T>
auto
midpoint(const std::pair<T, T> & v)
{
return std::midpoint(v.first, v.second);
}
+// std::pow is not constexpr
+template<Arithmetic T>
+ requires requires(T n) { n *= n; }
+constexpr T
+pow(const T base, std::integral auto exp)
+{
+ T res {1};
+ while (exp--) {
+ res *= base;
+ }
+ return res;
+}
+
// Conversions
-template<typename T>
-inline constexpr auto
+template<Arithmetic T>
+constexpr auto
mph_to_ms(T v)
{
return v / 2.237L;
}
-template<typename T>
-inline constexpr auto
+template<Arithmetic T>
+constexpr auto
kph_to_ms(T v)
{
return v / 3.6L;
@@ -278,3 +455,9 @@ kph_to_ms(T v)
// ... literals are handy for now, probably go away when we load stuff externally
float operator"" _mph(const long double v);
float operator"" _kph(const long double v);
+
+constexpr float
+operator"" _degrees(long double degrees)
+{
+ return static_cast<float>(degrees) * degreesToRads;
+}
diff --git a/lib/stream_support.h b/lib/stream_support.h
index 57d82a1..f21622a 100644
--- a/lib/stream_support.h
+++ b/lib/stream_support.h
@@ -4,8 +4,10 @@
#include <glm/glm.hpp>
#include <iostream>
#include <maths.h>
+#include <source_location>
#include <span>
#include <sstream>
+#include <tuple>
#include <type_traits>
template<typename S>
@@ -16,14 +18,14 @@ concept NonStringIterableCollection
namespace std {
std::ostream &
- operator<<(std::ostream & s, const NonStringIterableCollection auto & v)
+ operator<<(std::ostream & s, const NonStringIterableCollection auto & collection)
{
s << '(';
- for (const auto & i : v) {
- if (&i != &*v.begin()) {
+ for (size_t nth {}; const auto & element : collection) {
+ if (nth++) {
s << ", ";
}
- s << i;
+ s << element;
}
return s << ')';
}
@@ -49,6 +51,22 @@ namespace std {
return (s << '(' << v.first << ", " << v.second << ')');
}
+ namespace {
+ template<typename... T, size_t... Idx>
+ std::ostream &
+ printTuple(std::ostream & s, const std::tuple<T...> & v, std::integer_sequence<size_t, Idx...>)
+ {
+ return ((s << (Idx ? ", " : "") << std::get<Idx>(v)), ...);
+ }
+ }
+
+ template<typename... T>
+ std::ostream &
+ operator<<(std::ostream & s, const std::tuple<T...> & v)
+ {
+ return printTuple(s << '{', v, std::make_index_sequence<sizeof...(T)>()) << '}';
+ }
+
inline std::ostream &
operator<<(std::ostream & s, const Arc & arc)
{
@@ -75,4 +93,14 @@ streamed_string(const T & v)
return std::move(ss).str();
}
-#define CLOG(x) std::cerr << __LINE__ << " : " #x " : " << x << "\n";
+namespace {
+ template<typename T>
+ void
+ clogImpl(const T & value, const std::string_view name,
+ const std::source_location loc = std::source_location::current())
+ {
+ std::cerr << loc.line() << " : " << name << " : " << value << "\n";
+ }
+}
+
+#define CLOG(x) clogImpl(x, #x)
diff --git a/lib/triangle.h b/lib/triangle.h
new file mode 100644
index 0000000..812bfab
--- /dev/null
+++ b/lib/triangle.h
@@ -0,0 +1,108 @@
+#pragma once
+
+#include "config/types.h"
+#include "maths.h"
+#include <glm/glm.hpp>
+
+template<glm::length_t Dim, Arithmetic T, glm::qualifier Q = glm::defaultp>
+struct Triangle : public glm::vec<3, glm::vec<Dim, T, Q>> {
+ using Point = glm::vec<Dim, T, Q>;
+ using Base = glm::vec<3, glm::vec<Dim, T, Q>>;
+ using Base::Base;
+
+ [[nodiscard]] constexpr Point
+ operator*(BaryPosition bari) const
+ {
+ return p(0) + (sideDifference(1) * bari.x) + (sideDifference(2) * bari.y);
+ }
+
+ [[nodiscard]] constexpr Point
+ centroid() const
+ {
+ return [this]<glm::length_t... Axis>(std::integer_sequence<glm::length_t, Axis...>) {
+ return Point {(p(0)[Axis] + p(1)[Axis] + p(2)[Axis]) / 3 ...};
+ }(std::make_integer_sequence<glm::length_t, Dim>());
+ }
+
+ [[nodiscard]] constexpr auto
+ area() const
+ requires(Dim == 3)
+ {
+ return glm::length(crossProduct(sideDifference(1), sideDifference(2))) / T {2};
+ }
+
+ [[nodiscard]] constexpr Normal3D
+ normal() const
+ requires(Dim == 3)
+ {
+ return crossProduct(sideDifference(1), sideDifference(2));
+ }
+
+ [[nodiscard]] constexpr Normal3D
+ nnormal() const
+ requires(Dim == 3)
+ {
+ return glm::normalize(normal());
+ }
+
+ [[nodiscard]] constexpr auto
+ sideDifference(glm::length_t side) const
+ {
+ return difference(p(side), p(0));
+ }
+
+ [[nodiscard]] constexpr auto
+ angle(glm::length_t corner) const
+ {
+ return Arc {P(corner), P(corner + 2), P(corner + 1)}.length();
+ }
+
+ template<glm::length_t D = Dim>
+ [[nodiscard]] constexpr auto
+ angleAt(const glm::vec<D, T, Q> pos) const
+ requires(D <= Dim)
+ {
+ for (glm::length_t i {}; i < 3; ++i) {
+ if (glm::vec<D, T, Q> {p(i)} == pos) {
+ return angle(i);
+ }
+ }
+ return 0.F;
+ }
+
+ [[nodiscard]] constexpr auto
+ p(const glm::length_t idx) const
+ {
+ return Base::operator[](idx);
+ }
+
+ [[nodiscard]] constexpr auto
+ P(const glm::length_t idx) const
+ {
+ return Base::operator[](idx % 3);
+ }
+
+ [[nodiscard]] constexpr Point *
+ begin()
+ {
+ return &(Base::x);
+ }
+
+ [[nodiscard]] constexpr const Point *
+ begin() const
+ {
+ return &(Base::x);
+ }
+
+ [[nodiscard]] constexpr Point *
+ end()
+ {
+ return begin() + 3;
+ }
+
+ [[nodiscard]] constexpr const Point *
+ end() const
+ {
+ return begin() + 3;
+ }
+};