Files
omath/docs/linear_algebra/triangle.md
Orange 0510dd8328 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.
2025-10-31 16:14:20 +03:00

174 lines
5.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# `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*