feat: project skeleton, core types and math with transform tests

This commit is contained in:
Martino Ferrari committed 2026-09-27 20:54:19 +02:00
1 parent e4051bc6b5
commit 8a7e9e97f8
21 files changed
+515 -2

No files matched your search

+31
View File
@@ -0,0 +1,31 @@
#pragma once
#include <plot/core/types.hpp>
namespace plot::math {
/// Column-major 3x3 matrix of `f32`, the layout OpenGL expects for `mat3`
/// uniforms.
struct Mat3 {
f32 m[9] = {1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f};
static constexpr Mat3 identity() noexcept { return Mat3{}; }
/// Column-major product `(*this) * rhs`.
constexpr Mat3 operator*(const Mat3& rhs) const noexcept {
Mat3 out{0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
for (usize col = 0; col < 3; ++col) {
for (usize row = 0; row < 3; ++row) {
f32 acc = 0.0f;
for (usize k = 0; k < 3; ++k) acc += m[k * 3 + row] * rhs.m[col * 3 + k];
out.m[col * 3 + row] = acc;
}
}
return out;
}
};
} // namespace plot::math
namespace plot {
using math::Mat3;
}
+48
View File
@@ -0,0 +1,48 @@
#pragma once
#include <cmath>
#include <plot/core/types.hpp>
namespace plot::math {
/// Affine data->screen mapping: `screen = data * s + t`, applied after `log10`
/// when the corresponding log flag is set.
struct Transform {
f64 sx = 1.0, tx = 0.0;
f64 sy = 1.0, ty = 0.0;
bool log_x = false, log_y = false;
f64 to_screen_x(f64 x) const noexcept {
const f64 v = log_x ? log10_positive(x) : x;
return v * sx + tx;
}
f64 to_screen_y(f64 y) const noexcept {
const f64 v = log_y ? log10_positive(y) : y;
return v * sy + ty;
}
f64 to_data_x(f64 screen_x) const noexcept {
const f64 v = (screen_x - tx) / sx;
return log_x ? std::pow(10.0, v) : v;
}
f64 to_data_y(f64 screen_y) const noexcept {
const f64 v = (screen_y - ty) / sy;
return log_y ? std::pow(10.0, v) : v;
}
/// Set scale/offset so `x` and `y` map onto `[px0,px1]` and `[py0,py1]`.
/// A degenerate range is widened by +/-0.5 in the (possibly logarithmic)
/// coordinate so the resulting mapping always stays invertible.
static Transform from_range(Range x, Range y, f64 px0, f64 px1, f64 py0, f64 py1, bool lx,
bool ly) noexcept;
/// `log10` of `v`, with `v` clamped to at least 1e-300 first.
static f64 log10_positive(f64 v) noexcept;
};
} // namespace plot::math
namespace plot {
using math::Transform;
}
+28
View File
@@ -0,0 +1,28 @@
#pragma once
#include <cmath>
#include <plot/core/types.hpp>
namespace plot::math {
/// 2D vector of `f32`, used for pixel offsets and normalised device coords.
struct Vec2 {
f32 x = 0.0f;
f32 y = 0.0f;
constexpr Vec2 operator+(const Vec2& o) const noexcept { return {x + o.x, y + o.y}; }
constexpr Vec2 operator-(const Vec2& o) const noexcept { return {x - o.x, y - o.y}; }
constexpr Vec2 operator*(f32 s) const noexcept { return {x * s, y * s}; }
constexpr Vec2 operator/(f32 s) const noexcept { return {x / s, y / s}; }
constexpr f32 dot(const Vec2& o) const noexcept { return x * o.x + y * o.y; }
f32 length() const noexcept { return std::sqrt(x * x + y * y); }
};
constexpr Vec2 operator*(f32 s, const Vec2& v) noexcept { return v * s; }
} // namespace plot::math
namespace plot {
using math::Vec2;
}