Adds documentation for Vector4 and incorporates ImGui integration

Adds comprehensive documentation for the `Vector4` class, outlining constructors, operators, and utility functions. Includes detailed notes on `clamp` functionality and potential ImGui integration caveats. Incorporates optional ImGui integration with explanations for correct usage and potential improvements.
This commit is contained in:
2025-10-31 16:14:20 +03:00
parent ce9758c86b
commit 0510dd8328
5 changed files with 1015 additions and 1 deletions

View File

@@ -0,0 +1,173 @@
# `omath::Triangle` — Simple 3D triangle utility
> Header: your projects `triangle.hpp`
> Namespace: `omath`
> Depends on: `omath::Vector3<float>` (from `vector3.hpp`)
A tiny helper around three `Vector3<float>` 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 Vector> class Triangle`, but the stored vertices are concretely `Vector3<float>`. In practice this type is currently **fixed to `Vector3<float>`**. 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<void> tri( // template arg unused; any placeholder ok
Vector3<float>{0,0,0}, // v1
Vector3<float>{0,0,1}, // v2 (right angle is tested at v2)
Vector3<float>{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<float> m_vertex1; // v1
Vector3<float> m_vertex2; // v2 (the corner tested by is_rectangular)
Vector3<float> m_vertex3; // v3
```
---
## Constructors
```cpp
constexpr Triangle() = default;
constexpr Triangle(const Vector3<float>& v1,
const Vector3<float>& v2,
const Vector3<float>& v3);
```
---
## Methods
```cpp
// Normal (unit) using right-handed cross product:
// n = (v3 - v2) × (v1 - v2), then normalized()
[[nodiscard]] constexpr Vector3<float> 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<float> side_a_vector() const; // v1 - v2
[[nodiscard]] constexpr Vector3<float> 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<float> 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 `v1v2`, 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 triangles plane
```cpp
Vector3<float> 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<float>& v1,
const Vector3<float>& v2,
const Vector3<float>& v3);
Vector3<float> m_vertex1, m_vertex2, m_vertex3;
[[nodiscard]] constexpr Vector3<float> calculate_normal() const;
[[nodiscard]] float side_a_length() const;
[[nodiscard]] float side_b_length() const;
[[nodiscard]] constexpr Vector3<float> side_a_vector() const;
[[nodiscard]] constexpr Vector3<float> side_b_vector() const;
[[nodiscard]] constexpr float hypot() const;
[[nodiscard]] constexpr bool is_rectangular() const;
[[nodiscard]] constexpr Vector3<float> 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*

View File

@@ -0,0 +1,291 @@
# `omath::Vector2` — 2D vector (C++20/23)
> Header: your projects `vector2.hpp`
> Namespace: `omath`
> Template: `template<class Type> requires std::is_arithmetic_v<Type>`
`Vector2<Type>` 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<float>;
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<Type, Type> 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<float>`)**
```cpp
template<> struct std::hash<omath::Vector2<float>> {
std::size_t operator()(const omath::Vector2<float>&) const noexcept;
};
```
Example:
```cpp
std::unordered_set<omath::Vector2<float>> set;
set.insert({1.f, 2.f});
```
* **`std::formatter`** (for any `Type`)
```cpp
// prints "[x, y]" for char / wchar_t / char8_t
template<class Type>
struct std::formatter<omath::Vector2<Type>>;
```
---
## 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; theyre still `noexcept`.
---
## Examples
### Component-wise operations and scalar scaling
```cpp
omath::Vector2<float> 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<double> 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<omath::Vector2<float>, int> counts;
counts[{1.f, 2.f}] = 42;
```
### ImGui interop
```cpp
#define OMATH_IMGUI_INTEGRATION
#include "vector2.hpp"
omath::Vector2<float> v{10, 20};
ImVec2 iv = v.to_im_vec2();
v = omath::Vector2<float>::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<Type,Type> 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*

View File

@@ -0,0 +1,297 @@
# `omath::Vector3` — 3D vector (C++20/23)
> Header: your projects `vector3.hpp`
> Namespace: `omath`
> Template: `template<class Type> requires std::is_arithmetic_v<Type>`
> Depends on: `omath::Vector2<Type>` (base class), `omath::Angle` (for `angle_between`)
> C++: uses `std::expected` ⇒ **C++23** recommended (or a backport)
`Vector3<Type>` extends `Vector2<Type>` 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<float>;
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>
Type y{0}; // inherited from Vector2<Type>
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<Type,Type,Type>;
// 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<float, 0.f, 180.f, AngleFlags::Clamped>,
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<float>`)**
```cpp
template<> struct std::hash<omath::Vector3<float>> {
std::size_t operator()(const omath::Vector3<float>&) const noexcept;
};
```
Example:
```cpp
std::unordered_map<omath::Vector3<float>, int> counts;
counts[{1.f, 2.f, 3.f}] = 7;
```
* **`std::formatter`** (all character types)
```cpp
template<class Type>
struct std::formatter<omath::Vector3<Type>>; // 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<float> 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<float> 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<float> 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<Type,Type,Type>;
// Angles
std::expected<omath::Angle<float,0.f,180.f,AngleFlags::Clamped>, 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<Type>` (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*

View File

@@ -0,0 +1,253 @@
# `omath::Vector4` — 4D vector (C++20/23)
> Header: your projects `vector4.hpp`
> Namespace: `omath`
> Template: `template<class Type> requires std::is_arithmetic_v<Type>`
> Inherits: `omath::Vector3<Type>` (brings `x`, `y`, `z` and most scalar ops)
`Vector4<Type>` extends `Vector3<Type>` 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<float>;
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>:
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<float> and (in current code) sets only x,y,z.
// See "Notes & caveats" for a corrected version you may prefer.
static Vector4<float> from_im_vec4(const ImVec4& other) noexcept;
#endif
```
---
## Hashing & formatting
* **Hash specialization** (only for `Vector4<float>`):
```cpp
template<> struct std::hash<omath::Vector4<float>> {
std::size_t operator()(const omath::Vector4<float>&) const noexcept;
};
```
Example:
```cpp
std::unordered_map<omath::Vector4<float>, int> counts;
counts[{1.f, 2.f, 3.f, 1.f}] = 7;
```
* **`std::formatter`** (for any `Type`, all character kinds):
```cpp
template<class Type>
struct std::formatter<omath::Vector4<Type>>; // -> "[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 `<imgui.h>` itself. Ensure its included **before** this header whenever `OMATH_IMGUI_INTEGRATION` is defined.
* `from_im_vec4` currently returns `Vector4<float>` and (in the snippet shown) initializes **only x,y,z**. A more consistent version would be:
```cpp
#ifdef OMATH_IMGUI_INTEGRATION
static Vector4<Type> from_im_vec4(const ImVec4& v) noexcept {
return {static_cast<Type>(v.x), static_cast<Type>(v.y),
static_cast<Type>(v.z), static_cast<Type>(v.w)};
}
#endif
```
* Many scalar compound operators (`+= Type`, `-= Type`) are inherited from `Vector3<Type>`.
---
## 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<float> 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*