Adds documentation for the `omath::ViewAngles` struct, clarifying its purpose, common usage patterns, and the definition of the types of pitch, yaw and roll. Also, adds short explanations of how to use ViewAngles and what tradeoffs exist between using raw float types and strongly typed Angle<> types.
3.9 KiB
omath::pathfinding::NavigationMesh — Lightweight vertex graph for A*
Header: your project’s
pathfinding/navigation_mesh.hppNamespace:omath::pathfindingNodes:Vector3<float>(3D points) Storage: adjacency mapunordered_map<Vector3<float>, std::vector<Vector3<float>>>
A minimal navigation mesh represented as a vertex/edge graph. Each vertex is a Vector3<float> and neighbors are stored in an adjacency list. Designed to pair with Astar::find_path.
API
class NavigationMesh final {
public:
// Nearest graph vertex to an arbitrary 3D point.
// On success -> closest vertex; on failure -> std::string error (e.g., empty mesh).
[[nodiscard]]
std::expected<Vector3<float>, std::string>
get_closest_vertex(const Vector3<float>& point) const noexcept;
// Read-only neighbor list for a vertex key.
// If vertex is absent, implementation should return an empty list (see notes).
[[nodiscard]]
const std::vector<Vector3<float>>&
get_neighbors(const Vector3<float>& vertex) const noexcept;
// True if the graph has no vertices/edges.
[[nodiscard]]
bool empty() const;
// Serialize/deserialize the graph (opaque binary).
[[nodiscard]] std::vector<uint8_t> serialize() const noexcept;
void deserialize(const std::vector<uint8_t>& raw) noexcept;
// Public adjacency (vertex -> neighbors)
std::unordered_map<Vector3<float>, std::vector<Vector3<float>>> m_vertex_map;
};
Quick start
using omath::Vector3;
using omath::pathfinding::NavigationMesh;
// Build a tiny mesh (triangle)
NavigationMesh nav;
nav.m_vertex_map[ {0,0,0} ] = { {1,0,0}, {0,0,1} };
nav.m_vertex_map[ {1,0,0} ] = { {0,0,0}, {0,0,1} };
nav.m_vertex_map[ {0,0,1} ] = { {0,0,0}, {1,0,0} };
// Query the closest node to an arbitrary point
auto q = nav.get_closest_vertex({0.3f, 0.0f, 0.2f});
if (q) {
const auto& v = *q;
const auto& nbrs = nav.get_neighbors(v);
(void)nbrs;
}
Semantics & expectations
-
Nearest vertex
get_closest_vertex(p)should scan known vertices and return the one with minimal Euclidean distance top. If the mesh is empty, expect an error (unexpectedwith a message). -
Neighbors
get_neighbors(v)returns the adjacency list forv. Ifvis not present, a conventional behavior is to return a reference to a static empty vector (since the API isnoexceptand returns by reference). Verify in your implementation. -
Graph invariants (recommended)
- Neighbor links are symmetric for undirected navigation (if
uhasv, thenvhasu). - No self-loops unless explicitly desired.
- Vertices are unique keys; hashing uses
std::hash<Vector3<float>>(be mindful of floating-point equality).
- Neighbor links are symmetric for undirected navigation (if
Serialization
serialize()→ opaque, implementation-defined binary of the currentm_vertex_map.deserialize(raw)→ restores the internal map fromraw. Keep versioning in mind if you evolve the format (e.g., add a header/magic/version).
Performance
Let V = m_vertex_map.size() and E = Σ|neighbors(v)|.
get_closest_vertex: O(V) (linear scan) unless you back it with a spatial index (KD-tree, grid, etc.).get_neighbors: O(1) average (hash lookup).- Memory: O(V + E).
Usage notes
- Floating-point keys: Using
Vector3<float>as an unordered_map key relies on yourstd::hash<omath::Vector3<float>>and exactoperator==. Avoid building meshes with numerically “close but not equal” duplicates; consider canonicalizing or using integer IDs if needed. - Pathfinding: Pair with
Astar::find_path(start, end, nav); the A* heuristic can use straight-line distance between vertex positions.
Minimal test ideas
- Empty mesh →
get_closest_vertexreturns error;empty() == true. - Single vertex → nearest always that vertex; neighbors empty.
- Symmetric edges →
get_neighbors(a)containsband vice versa. - Serialization round-trip preserves vertex/edge counts and neighbor lists.