diff --git a/docs/linear_algebra/triangle.md b/docs/linear_algebra/triangle.md new file mode 100644 index 0000000..fc80f88 --- /dev/null +++ b/docs/linear_algebra/triangle.md @@ -0,0 +1,173 @@ +# `omath::Triangle` — Simple 3D triangle utility + +> Header: your project’s `triangle.hpp` +> Namespace: `omath` +> Depends on: `omath::Vector3` (from `vector3.hpp`) + +A tiny helper around three `Vector3` vertices with convenience methods for normals, edge vectors/lengths, a right-angle test (at **`v2`**), and the triangle centroid. + +> **Note on the template parameter** +> +> The class is declared as `template class Triangle`, but the stored vertices are concretely `Vector3`. In practice this type is currently **fixed to `Vector3`**. You can ignore the template parameter or refactor to store `Vector` if you intend true genericity. + +--- + +## Vertex layout & naming + +``` +v1 +|\ +| \ +a | \ hypot = |v1 - v3| +| \ +v2 -- v3 + b + +a = |v1 - v2| (side_a_length) +b = |v3 - v2| (side_b_length) +``` + +* **`side_a_vector()`** = `v1 - v2` (points from v2 → v1) +* **`side_b_vector()`** = `v3 - v2` (points from v2 → v3) +* **Right-angle check** uses `a² + b² ≈ hypot²` with an epsilon of `1e-4`. + +--- + +## Quick start + +```cpp +#include "triangle.hpp" +using omath::Vector3; +using omath::Triangle; + +Triangle tri( // template arg unused; any placeholder ok + Vector3{0,0,0}, // v1 + Vector3{0,0,1}, // v2 (right angle is tested at v2) + Vector3{1,0,1} // v3 +); + +auto n = tri.calculate_normal(); // unit normal (right-handed: (v3-v2) × (v1-v2)) +float a = tri.side_a_length(); // |v1 - v2| +float b = tri.side_b_length(); // |v3 - v2| +float hyp = tri.hypot(); // |v1 - v3| +bool rect = tri.is_rectangular(); // true if ~right triangle at v2 +auto C = tri.mid_point(); // centroid (average of v1,v2,v3) +``` + +--- + +## Data members + +```cpp +Vector3 m_vertex1; // v1 +Vector3 m_vertex2; // v2 (the corner tested by is_rectangular) +Vector3 m_vertex3; // v3 +``` + +--- + +## Constructors + +```cpp +constexpr Triangle() = default; +constexpr Triangle(const Vector3& v1, + const Vector3& v2, + const Vector3& v3); +``` + +--- + +## Methods + +```cpp +// Normal (unit) using right-handed cross product: +// n = (v3 - v2) × (v1 - v2), then normalized() +[[nodiscard]] constexpr Vector3 calculate_normal() const; + +// Edge lengths with the naming from the diagram +[[nodiscard]] float side_a_length() const; // |v1 - v2| +[[nodiscard]] float side_b_length() const; // |v3 - v2| + +// Edge vectors (from v2 to the other vertex) +[[nodiscard]] constexpr Vector3 side_a_vector() const; // v1 - v2 +[[nodiscard]] constexpr Vector3 side_b_vector() const; // v3 - v2 + +// Hypotenuse length between v1 and v3 +[[nodiscard]] constexpr float hypot() const; // |v1 - v3| + +// Right-triangle check at vertex v2 (Pythagoras with epsilon 1e-4) +[[nodiscard]] constexpr bool is_rectangular() const; + +// Centroid of the triangle (average of the 3 vertices) +[[nodiscard]] constexpr Vector3 mid_point() const; // actually the centroid +``` + +### Notes & edge cases + +* **Normal direction** follows the right-hand rule for the ordered vertices `{v2 → v3} × {v2 → v1}`. + Swap vertex order to flip the normal. +* **Degenerate triangles** (collinear or overlapping vertices) yield a **zero vector** normal (since `normalized()` of the zero vector returns the zero vector in your math types). +* **`mid_point()` is the centroid**, not the midpoint of any single edge. If you need the midpoint of edge `v1–v2`, use `(m_vertex1 + m_vertex2) * 0.5f`. + +--- + +## Examples + +### Area and plane from existing API + +```cpp +const auto a = tri.side_a_vector(); +const auto b = tri.side_b_vector(); +const auto n = b.cross(a); // unnormalized normal +float area = 0.5f * n.length(); // triangle area + +// Plane equation n̂·(x - v2) = 0 +auto nhat = n.length() > 0 ? n / n.length() : n; +float d = -nhat.dot(tri.m_vertex2); +``` + +### Project a point onto the triangle’s plane + +```cpp +Vector3 p{0.3f, 1.0f, 0.7f}; +auto n = tri.calculate_normal(); +float t = n.dot(tri.m_vertex2 - p); // signed distance along normal +auto projected = p + n * t; // on-plane projection +``` + +--- + +## API summary (signatures) + +```cpp +class Triangle final { +public: + constexpr Triangle(); + constexpr Triangle(const Vector3& v1, + const Vector3& v2, + const Vector3& v3); + + Vector3 m_vertex1, m_vertex2, m_vertex3; + + [[nodiscard]] constexpr Vector3 calculate_normal() const; + [[nodiscard]] float side_a_length() const; + [[nodiscard]] float side_b_length() const; + [[nodiscard]] constexpr Vector3 side_a_vector() const; + [[nodiscard]] constexpr Vector3 side_b_vector() const; + [[nodiscard]] constexpr float hypot() const; + [[nodiscard]] constexpr bool is_rectangular() const; + [[nodiscard]] constexpr Vector3 mid_point() const; +}; +``` + +--- + +## Suggestions (optional improvements) + +* If generic vectors are intended, store `Vector m_vertex*;` and constrain `Vector` to the required ops (`-`, `cross`, `normalized`, `distance_to`, `+`, `/`). +* Consider renaming `mid_point()` → `centroid()` to avoid ambiguity. +* Expose an `area()` helper and (optionally) a barycentric coordinate routine if you plan to use this in rasterization or intersection tests. + +--- + +*Last updated: 31 Oct 2025* diff --git a/docs/linear_algebra/vector2.md b/docs/linear_algebra/vector2.md new file mode 100644 index 0000000..483b144 --- /dev/null +++ b/docs/linear_algebra/vector2.md @@ -0,0 +1,291 @@ +# `omath::Vector2` — 2D vector (C++20/23) + +> Header: your project’s `vector2.hpp` +> Namespace: `omath` +> Template: `template requires std::is_arithmetic_v` + +`Vector2` is a lightweight, POD-like 2D math type with arithmetic, geometry helpers, comparisons, hashing (for `float`), optional ImGui interop, and `std::formatter` support. + +--- + +## Quick start + +```cpp +#include "vector2.hpp" +using omath::Vector2; + +using Vec2f = Vector2; + +Vec2f a{3.f, 4.f}; +Vec2f b{1.f, 2.f}; + +auto d = a.distance_to(b); // ≈ 3.1623 +auto dot = a.dot(b); // 11 +auto len = a.length(); // 5 +auto unit_a = a.normalized(); // (0.6, 0.8) + +// Component-wise mutate +Vec2f c{2, 3}; +c *= b; // c -> (2*1, 3*2) = (2, 6) + +// Scalar ops (non-mutating + mutating) +auto scaled = a * 0.5f; // (1.5, 2) +a *= 2.f; // (6, 8) + +// Ordering by length() +bool shorter = (b < a); + +// Formatted printing +std::string s = std::format("a = {}", a); // "a = [6, 8]" +``` + +--- + +## Members + +```cpp +Type x{0}; +Type y{0}; +``` + +--- + +## Constructors + +```cpp +constexpr Vector2(); // (0,0) +constexpr Vector2(const Type& x, const Type& y) noexcept; +``` + +--- + +## Equality & ordering + +```cpp +constexpr bool operator==(const Vector2&) const noexcept; // component-wise equality +constexpr bool operator!=(const Vector2&) const noexcept; + +bool operator< (const Vector2&) const noexcept; // compares by length() +bool operator> (const Vector2&) const noexcept; +bool operator<=(const Vector2&) const noexcept; +bool operator>=(const Vector2&) const noexcept; +``` + +> **Note:** `<`, `>`, `<=`, `>=` order vectors by **magnitude** (not lexicographically). + +--- + +## Arithmetic + +### With another vector (component-wise, **mutating**) + +```cpp +Vector2& operator+=(const Vector2&) noexcept; +Vector2& operator-=(const Vector2&) noexcept; +Vector2& operator*=(const Vector2&) noexcept; // Hadamard product (x*=x, y*=y) +Vector2& operator/=(const Vector2&) noexcept; +``` + +> Non-mutating `v * u` / `v / u` (vector × vector) are **not** provided. +> Use `v *= u` (mutating) or build a new vector explicitly. + +### With a scalar + +```cpp +Vector2& operator*=(const Type& v) noexcept; +Vector2& operator/=(const Type& v) noexcept; +Vector2& operator+=(const Type& v) noexcept; +Vector2& operator-=(const Type& v) noexcept; + +constexpr Vector2 operator*(const Type& v) const noexcept; +constexpr Vector2 operator/(const Type& v) const noexcept; +``` + +### Binary (+/−) with another vector (non-mutating) + +```cpp +constexpr Vector2 operator+(const Vector2&) const noexcept; +constexpr Vector2 operator-(const Vector2&) const noexcept; +``` + +### Unary + +```cpp +constexpr Vector2 operator-() const noexcept; // negation +``` + +--- + +## Geometry & helpers + +```cpp +Type distance_to (const Vector2&) const noexcept; // sqrt of squared distance +constexpr Type distance_to_sqr(const Vector2&) const noexcept; + +constexpr Type dot(const Vector2&) const noexcept; + +#ifndef _MSC_VER +constexpr Type length() const noexcept; // uses std::hypot; constexpr on non-MSVC +constexpr Vector2 normalized() const noexcept; // returns *this if length==0 +#else +Type length() const noexcept; +Vector2 normalized() const noexcept; +#endif + +constexpr Type length_sqr() const noexcept; // x*x + y*y +Vector2& abs() noexcept; // component-wise absolute (constexpr-friendly impl) + +constexpr Type sum() const noexcept; // x + y +constexpr std::tuple as_tuple() const noexcept; +``` + +--- + +## ImGui integration (optional) + +Define `OMATH_IMGUI_INTEGRATION` **before** including the header. + +```cpp +#ifdef OMATH_IMGUI_INTEGRATION +constexpr ImVec2 to_im_vec2() const noexcept; // {float(x), float(y)} +static Vector2 from_im_vec2(const ImVec2&) noexcept; +#endif +``` + +--- + +## Hashing & formatting + +* **Hash (for `Vector2`)** + + ```cpp + template<> struct std::hash> { + std::size_t operator()(const omath::Vector2&) const noexcept; + }; + ``` + + Example: + + ```cpp + std::unordered_set> set; + set.insert({1.f, 2.f}); + ``` + +* **`std::formatter`** (for any `Type`) + + ```cpp + // prints "[x, y]" for char / wchar_t / char8_t + template + struct std::formatter>; + ``` + +--- + +## Notes & invariants + +* `Type` must be arithmetic (e.g., `float`, `double`, `int`, …). +* `normalized()` returns the input unchanged if `length() == 0`. +* `abs()` uses a constexpr-friendly implementation (not `std::abs`) to allow compile-time evaluation. +* On MSVC, `length()`/`normalized()` are not `constexpr` due to library constraints; they’re still `noexcept`. + +--- + +## Examples + +### Component-wise operations and scalar scaling + +```cpp +omath::Vector2 u{2, 3}, v{4, 5}; + +u += v; // (6, 8) +u -= v; // (2, 3) +u *= v; // (8, 15) Hadamard product (mutates u) +auto w = v * 2.0f; // (8, 10) non-mutating scalar multiply +``` + +### Geometry helpers + +```cpp +omath::Vector2 p{0.0, 0.0}, q{3.0, 4.0}; + +auto dsq = p.distance_to_sqr(q); // 25 +auto d = p.distance_to(q); // 5 +auto dot = p.dot(q); // 0 +auto uq = q.normalized(); // (0.6, 0.8) +``` + +### Using as a key in unordered containers (`float`) + +```cpp +std::unordered_map, int> counts; +counts[{1.f, 2.f}] = 42; +``` + +### ImGui interop + +```cpp +#define OMATH_IMGUI_INTEGRATION +#include "vector2.hpp" + +omath::Vector2 v{10, 20}; +ImVec2 iv = v.to_im_vec2(); +v = omath::Vector2::from_im_vec2(iv); +``` + +--- + +## API summary (signatures) + +```cpp +// Constructors +constexpr Vector2(); +constexpr Vector2(const Type& x, const Type& y) noexcept; + +// Equality & ordering +constexpr bool operator==(const Vector2&) const noexcept; +constexpr bool operator!=(const Vector2&) const noexcept; +bool operator< (const Vector2&) const noexcept; +bool operator> (const Vector2&) const noexcept; +bool operator<=(const Vector2&) const noexcept; +bool operator>=(const Vector2&) const noexcept; + +// Compound (vector/vector and scalar) +Vector2& operator+=(const Vector2&) noexcept; +Vector2& operator-=(const Vector2&) noexcept; +Vector2& operator*=(const Vector2&) noexcept; +Vector2& operator/=(const Vector2&) noexcept; +Vector2& operator*=(const Type&) noexcept; +Vector2& operator/=(const Type&) noexcept; +Vector2& operator+=(const Type&) noexcept; +Vector2& operator-=(const Type&) noexcept; + +// Non-mutating arithmetic +constexpr Vector2 operator+(const Vector2&) const noexcept; +constexpr Vector2 operator-(const Vector2&) const noexcept; +constexpr Vector2 operator*(const Type&) const noexcept; +constexpr Vector2 operator/(const Type&) const noexcept; +constexpr Vector2 operator-() const noexcept; + +// Geometry +Type distance_to(const Vector2&) const noexcept; +constexpr Type distance_to_sqr(const Vector2&) const noexcept; +constexpr Type dot(const Vector2&) const noexcept; +Type length() const noexcept; // constexpr on non-MSVC +Vector2 normalized() const noexcept; // constexpr on non-MSVC +constexpr Type length_sqr() const noexcept; +Vector2& abs() noexcept; +constexpr Type sum() const noexcept; +constexpr std::tuple as_tuple() const noexcept; + +// ImGui (optional) +#ifdef OMATH_IMGUI_INTEGRATION +constexpr ImVec2 to_im_vec2() const noexcept; +static Vector2 from_im_vec2(const ImVec2&) noexcept; +#endif + +// Hash (float) and formatter are specialized in the header +``` + +--- + +*Last updated: 31 Oct 2025* diff --git a/docs/linear_algebra/vector3.md b/docs/linear_algebra/vector3.md new file mode 100644 index 0000000..6347925 --- /dev/null +++ b/docs/linear_algebra/vector3.md @@ -0,0 +1,297 @@ +# `omath::Vector3` — 3D vector (C++20/23) + +> Header: your project’s `vector3.hpp` +> Namespace: `omath` +> Template: `template requires std::is_arithmetic_v` +> Depends on: `omath::Vector2` (base class), `omath::Angle` (for `angle_between`) +> C++: uses `std::expected` ⇒ **C++23** recommended (or a backport) + +`Vector3` extends `Vector2` with a `z` component and 3D operations: arithmetic, geometry (dot, cross, distance), normalization, angle-between with robust error signaling, hashing (for `float`) and `std::formatter` support. + +--- + +## Quick start + +```cpp +#include "vector3.hpp" +using omath::Vector3; + +using Vec3f = Vector3; + +Vec3f a{3, 4, 0}; +Vec3f b{1, 2, 2}; + +auto d = a.distance_to(b); // Euclidean distance +auto dot = a.dot(b); // 3*1 + 4*2 + 0*2 = 11 +auto cr = a.cross(b); // (8, -6, 2) +auto len = a.length(); // hypot(x,y,z) +auto unit = a.normalized(); // safe normalize (returns a if length==0) + +if (auto ang = a.angle_between(b)) { + float deg = ang->as_degrees(); // [0, 180], clamped +} else { + // vectors have zero length -> no defined angle +} +``` + +--- + +## Data members + +```cpp +Type x{0}; // inherited from Vector2 +Type y{0}; // inherited from Vector2 +Type z{0}; +``` + +--- + +## Constructors + +```cpp +constexpr Vector3() noexcept; +constexpr Vector3(const Type& x, const Type& y, const Type& z) noexcept; +``` + +--- + +## Equality & ordering + +```cpp +constexpr bool operator==(const Vector3&) const noexcept; // component-wise +constexpr bool operator!=(const Vector3&) const noexcept; + +bool operator< (const Vector3&) const noexcept; // compare by length() +bool operator> (const Vector3&) const noexcept; +bool operator<=(const Vector3&) const noexcept; +bool operator>=(const Vector3&) const noexcept; +``` + +> **Note:** Ordering uses **magnitude**, not lexicographic order. + +--- + +## Arithmetic (mutating) + +Component-wise with another vector: + +```cpp +Vector3& operator+=(const Vector3&) noexcept; +Vector3& operator-=(const Vector3&) noexcept; +Vector3& operator*=(const Vector3&) noexcept; // Hadamard product +Vector3& operator/=(const Vector3&) noexcept; +``` + +With a scalar: + +```cpp +Vector3& operator*=(const Type& v) noexcept; +Vector3& operator/=(const Type& v) noexcept; +Vector3& operator+=(const Type& v) noexcept; +Vector3& operator-=(const Type& v) noexcept; +``` + +--- + +## Arithmetic (non-mutating) + +```cpp +constexpr Vector3 operator-() const noexcept; +constexpr Vector3 operator+(const Vector3&) const noexcept; +constexpr Vector3 operator-(const Vector3&) const noexcept; +constexpr Vector3 operator*(const Vector3&) const noexcept; // Hadamard +constexpr Vector3 operator/(const Vector3&) const noexcept; // Hadamard +constexpr Vector3 operator*(const Type& scalar) const noexcept; +constexpr Vector3 operator/(const Type& scalar) const noexcept; +``` + +--- + +## Geometry & helpers + +```cpp +// Distances & lengths +Type distance_to(const Vector3&) const; // sqrt of squared distance +constexpr Type distance_to_sqr(const Vector3&) const noexcept; +#ifndef _MSC_VER +constexpr Type length() const; // hypot(x,y,z) +constexpr Type length_2d() const; // 2D length from base +constexpr Vector3 normalized() const; // returns *this if length==0 +#else +Type length() const noexcept; +Type length_2d() const noexcept; +Vector3 normalized() const noexcept; +#endif +constexpr Type length_sqr() const noexcept; + +// Products +constexpr Type dot(const Vector3&) const noexcept; +constexpr Vector3 cross(const Vector3&) const noexcept; // right-handed + +// Sums & tuples +constexpr Type sum() const noexcept; // x + y + z +constexpr Type sum_2d() const noexcept; // x + y +constexpr auto as_tuple() const noexcept -> std::tuple; + +// Utilities +Vector3& abs() noexcept; // component-wise absolute +``` + +--- + +## Angles & orthogonality + +```cpp +enum class Vector3Error { IMPOSSIBLE_BETWEEN_ANGLE }; + +// Angle in degrees, clamped to [0,180]. Error if any vector has zero length. +std::expected< + omath::Angle, + Vector3Error +> angle_between(const Vector3& other) const noexcept; + +bool is_perpendicular(const Vector3& other) const noexcept; // true if angle == 90° +``` + +--- + +## Hashing & formatting + +* **Hash (for `Vector3`)** + + ```cpp + template<> struct std::hash> { + std::size_t operator()(const omath::Vector3&) const noexcept; + }; + ``` + + Example: + + ```cpp + std::unordered_map, int> counts; + counts[{1.f, 2.f, 3.f}] = 7; + ``` + +* **`std::formatter`** (all character types) + + ```cpp + template + struct std::formatter>; // prints "[x, y, z]" + ``` + +--- + +## Error handling + +* `angle_between()` returns `std::unexpected(Vector3Error::IMPOSSIBLE_BETWEEN_ANGLE)` if either vector length is zero. +* Other operations are total for arithmetic `Type` (no throwing behavior in this class). + +--- + +## Examples + +### Cross product & perpendicular check + +```cpp +omath::Vector3 x{1,0,0}, y{0,1,0}; +auto z = x.cross(y); // (0,0,1) +bool perp = x.is_perpendicular(y); // true +``` + +### Safe normalization and angle + +```cpp +omath::Vector3 u{0,0,0}, v{1,1,0}; +auto nu = u.normalized(); // returns {0,0,0} +if (auto ang = u.angle_between(v)) { + // won't happen: u has zero length → error +} else { + // handle degenerate case +} +``` + +### Hadamard vs scalar multiply + +```cpp +omath::Vector3 a{2,3,4}, b{5,6,7}; +auto h = a * b; // (10, 18, 28) component-wise +auto s = a * 2.f; // (4, 6, 8) scalar +``` + +--- + +## API summary (signatures) + +```cpp +// Ctors +constexpr Vector3() noexcept; +constexpr Vector3(const Type& x, const Type& y, const Type& z) noexcept; + +// Equality & ordering +constexpr bool operator==(const Vector3&) const noexcept; +constexpr bool operator!=(const Vector3&) const noexcept; +bool operator< (const Vector3&) const noexcept; +bool operator> (const Vector3&) const noexcept; +bool operator<=(const Vector3&) const noexcept; +bool operator>=(const Vector3&) const noexcept; + +// Mutating arithmetic +Vector3& operator+=(const Vector3&) noexcept; +Vector3& operator-=(const Vector3&) noexcept; +Vector3& operator*=(const Vector3&) noexcept; +Vector3& operator/=(const Vector3&) noexcept; +Vector3& operator*=(const Type&) noexcept; +Vector3& operator/=(const Type&) noexcept; +Vector3& operator+=(const Type&) noexcept; +Vector3& operator-=(const Type&) noexcept; + +// Non-mutating arithmetic +constexpr Vector3 operator-() const noexcept; +constexpr Vector3 operator+(const Vector3&) const noexcept; +constexpr Vector3 operator-(const Vector3&) const noexcept; +constexpr Vector3 operator*(const Vector3&) const noexcept; +constexpr Vector3 operator/(const Vector3&) const noexcept; +constexpr Vector3 operator*(const Type&) const noexcept; +constexpr Vector3 operator/(const Type&) const noexcept; + +// Geometry +Type distance_to(const Vector3&) const; +constexpr Type distance_to_sqr(const Vector3&) const noexcept; +#ifndef _MSC_VER +constexpr Type length() const; +constexpr Type length_2d() const; +constexpr Vector3 normalized() const; +#else +Type length() const noexcept; +Type length_2d() const noexcept; +Vector3 normalized() const noexcept; +#endif +constexpr Type length_sqr() const noexcept; +constexpr Type dot(const Vector3&) const noexcept; +constexpr Vector3 cross(const Vector3&) const noexcept; + +Vector3& abs() noexcept; +constexpr Type sum() const noexcept; +constexpr Type sum_2d() const noexcept; +constexpr auto as_tuple() const noexcept -> std::tuple; + +// Angles +std::expected, omath::Vector3Error> +angle_between(const Vector3&) const noexcept; +bool is_perpendicular(const Vector3&) const noexcept; + +// Hash (float) and formatter specializations provided below the class +``` + +--- + +## Notes + +* Inherits all public API of `Vector2` (including `x`, `y`, many operators, and helpers used internally). +* `normalized()` returns the original vector if its length is zero (no NaNs). +* `cross()` uses the standard right-handed definition. +* `length()`/`normalized()` are `constexpr` on non-MSVC; MSVC builds provide `noexcept` runtime versions. + +--- + +*Last updated: 31 Oct 2025* diff --git a/docs/linear_algebra/vector4.md b/docs/linear_algebra/vector4.md new file mode 100644 index 0000000..833fa73 --- /dev/null +++ b/docs/linear_algebra/vector4.md @@ -0,0 +1,253 @@ +# `omath::Vector4` — 4D vector (C++20/23) + +> Header: your project’s `vector4.hpp` +> Namespace: `omath` +> Template: `template requires std::is_arithmetic_v` +> Inherits: `omath::Vector3` (brings `x`, `y`, `z` and most scalar ops) + +`Vector4` extends `Vector3` with a `w` component and 4D operations: component-wise arithmetic, scalar ops, dot/length helpers, clamping, hashing (for `float`) and `std::formatter` support. Optional ImGui interop is available behind a macro. + +--- + +## Quick start + +```cpp +#include "vector4.hpp" +using omath::Vector4; + +using Vec4f = Vector4; + +Vec4f a{1, 2, 3, 1}; +Vec4f b{4, 5, 6, 2}; + +// Component-wise & scalar ops +auto c = a + b; // (5, 7, 9, 3) +c *= 0.5f; // (2.5, 3.5, 4.5, 1.5) +auto h = a * b; // Hadamard: (4, 10, 18, 2) + +// Dot / length +float d = a.dot(b); // 1*4 + 2*5 + 3*6 + 1*2 = 32 +float L = a.length(); // sqrt(x²+y²+z²+w²) + +// Clamp (x,y,z only; see notes) +Vec4f col{1.4f, -0.2f, 0.7f, 42.f}; +col.clamp(0.f, 1.f); // -> (1, 0, 0.7, w unchanged) +``` + +--- + +## Data members + +```cpp +// Inherited from Vector3: +Type x{0}; +Type y{0}; +Type z{0}; + +// Added in Vector4: +Type w{0}; +``` + +--- + +## Constructors + +```cpp +constexpr Vector4() noexcept; // (0,0,0,0) +constexpr Vector4(const Type& x, const Type& y, + const Type& z, const Type& w); // value-init +``` + +--- + +## Equality & ordering + +```cpp +constexpr bool operator==(const Vector4&) const noexcept; // component-wise +constexpr bool operator!=(const Vector4&) const noexcept; + +bool operator< (const Vector4&) const noexcept; // compare by length() +bool operator> (const Vector4&) const noexcept; +bool operator<=(const Vector4&) const noexcept; +bool operator>=(const Vector4&) const noexcept; +``` + +> **Note:** Ordering uses **magnitude** (Euclidean norm), not lexicographic order. + +--- + +## Arithmetic (mutating) + +With another vector (component-wise): + +```cpp +Vector4& operator+=(const Vector4&) noexcept; +Vector4& operator-=(const Vector4&) noexcept; +Vector4& operator*=(const Vector4&) noexcept; // Hadamard +Vector4& operator/=(const Vector4&) noexcept; +``` + +With a scalar: + +```cpp +Vector4& operator*=(const Type& v) noexcept; +Vector4& operator/=(const Type& v) noexcept; + +// From base class (inherited): +Vector4& operator+=(const Type& v) noexcept; // adds v to x,y,z (and w via base? see notes) +Vector4& operator-=(const Type& v) noexcept; +``` + +--- + +## Arithmetic (non-mutating) + +```cpp +constexpr Vector4 operator-() const noexcept; +constexpr Vector4 operator+(const Vector4&) const noexcept; +constexpr Vector4 operator-(const Vector4&) const noexcept; +constexpr Vector4 operator*(const Vector4&) const noexcept; // Hadamard +constexpr Vector4 operator/(const Vector4&) const noexcept; // Hadamard +constexpr Vector4 operator*(const Type& scalar) const noexcept; +constexpr Vector4 operator/(const Type& scalar) const noexcept; +``` + +--- + +## Geometry & helpers + +```cpp +constexpr Type length_sqr() const noexcept; // x² + y² + z² + w² +Type length() const noexcept; // std::sqrt(length_sqr()) +constexpr Type dot(const Vector4& rhs) const noexcept; + +Vector4& abs() noexcept; // component-wise absolute +Vector4& clamp(const Type& min, const Type& max) noexcept; + // clamps x,y,z; leaves w unchanged (see notes) +constexpr Type sum() const noexcept; // x + y + z + w +``` + +--- + +## ImGui integration (optional) + +Guarded by `OMATH_IMGUI_INTEGRATION`: + +```cpp +#ifdef OMATH_IMGUI_INTEGRATION +constexpr ImVec4 to_im_vec4() const noexcept; +// NOTE: Provided signature returns Vector4 and (in current code) sets only x,y,z. +// See "Notes & caveats" for a corrected version you may prefer. +static Vector4 from_im_vec4(const ImVec4& other) noexcept; +#endif +``` + +--- + +## Hashing & formatting + +* **Hash specialization** (only for `Vector4`): + + ```cpp + template<> struct std::hash> { + std::size_t operator()(const omath::Vector4&) const noexcept; + }; + ``` + + Example: + + ```cpp + std::unordered_map, int> counts; + counts[{1.f, 2.f, 3.f, 1.f}] = 7; + ``` + +* **`std::formatter`** (for any `Type`, all character kinds): + + ```cpp + template + struct std::formatter>; // -> "[x, y, z, w]" + ``` + +--- + +## Notes & caveats (as implemented) + +* `clamp(min,max)` **clamps only `x`, `y`, `z`** and **does not clamp `w`**. This may be intentional (e.g., when `w` is a homogeneous coordinate) — document your intent in your codebase. + If you want to clamp `w` too: + + ```cpp + w = std::clamp(w, min, max); + ``` + +* **ImGui interop**: + + * The header references `ImVec4` but does not include `` itself. Ensure it’s included **before** this header whenever `OMATH_IMGUI_INTEGRATION` is defined. + * `from_im_vec4` currently returns `Vector4` and (in the snippet shown) initializes **only x,y,z**. A more consistent version would be: + + ```cpp + #ifdef OMATH_IMGUI_INTEGRATION + static Vector4 from_im_vec4(const ImVec4& v) noexcept { + return {static_cast(v.x), static_cast(v.y), + static_cast(v.z), static_cast(v.w)}; + } + #endif + ``` + +* Many scalar compound operators (`+= Type`, `-= Type`) are inherited from `Vector3`. + +--- + +## API summary (signatures) + +```cpp +// Ctors +constexpr Vector4() noexcept; +constexpr Vector4(const Type& x, const Type& y, const Type& z, const Type& w); + +// Equality & ordering +constexpr bool operator==(const Vector4&) const noexcept; +constexpr bool operator!=(const Vector4&) const noexcept; +bool operator< (const Vector4&) const noexcept; +bool operator> (const Vector4&) const noexcept; +bool operator<=(const Vector4&) const noexcept; +bool operator>=(const Vector4&) const noexcept; + +// Mutating arithmetic +Vector4& operator+=(const Vector4&) noexcept; +Vector4& operator-=(const Vector4&) noexcept; +Vector4& operator*=(const Vector4&) noexcept; +Vector4& operator/=(const Vector4&) noexcept; +Vector4& operator*=(const Type&) noexcept; +Vector4& operator/=(const Type&) noexcept; +// (inherited) Vector4& operator+=(const Type&) noexcept; +// (inherited) Vector4& operator-=(const Type&) noexcept; + +// Non-mutating arithmetic +constexpr Vector4 operator-() const noexcept; +constexpr Vector4 operator+(const Vector4&) const noexcept; +constexpr Vector4 operator-(const Vector4&) const noexcept; +constexpr Vector4 operator*(const Vector4&) const noexcept; +constexpr Vector4 operator/(const Vector4&) const noexcept; +constexpr Vector4 operator*(const Type&) const noexcept; +constexpr Vector4 operator/(const Type&) const noexcept; + +// Geometry & helpers +constexpr Type length_sqr() const noexcept; +Type length() const noexcept; +constexpr Type dot(const Vector4&) const noexcept; +Vector4& abs() noexcept; +Vector4& clamp(const Type& min, const Type& max) noexcept; +constexpr Type sum() const noexcept; + +// ImGui (optional) +#ifdef OMATH_IMGUI_INTEGRATION +constexpr ImVec4 to_im_vec4() const noexcept; +static Vector4 from_im_vec4(const ImVec4&) noexcept; // see note for preferred template version +#endif + +// Hash (float) and formatter specializations provided below the class +``` + +--- + +*Last updated: 31 Oct 2025* diff --git a/mkdocs.yml b/mkdocs.yml index 91c36ad..08deb72 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,3 +1,3 @@ -site_name: OM Docs +site_name: OMATH Docs theme: name: darkly \ No newline at end of file