// // Created by Vlad on 28.07.2024. // #include "omath/pathfinding/navigation_mesh.hpp" #include #include #include #include namespace omath::pathfinding { std::expected, std::string> NavigationMesh::get_closest_vertex(const Vector3& point) const noexcept { const auto res = std::ranges::min_element(m_vertex_map, [&point](const auto& a, const auto& b) { return a.first.distance_to(point) < b.first.distance_to(point); }); if (res == m_vertex_map.cend()) return std::unexpected("Failed to get closest point"); return res->first; } const std::vector>& NavigationMesh::get_neighbors(const Vector3& vertex) const noexcept { return m_vertex_map.at(vertex); } bool NavigationMesh::empty() const { return m_vertex_map.empty(); } std::vector NavigationMesh::serialize() const noexcept { std::vector raw; // Pre-calculate total size for better performance std::size_t total_size = 0; for (const auto& [vertex, neighbors] : m_vertex_map) { total_size += sizeof(vertex) + sizeof(std::uint16_t) + sizeof(Vector3) * neighbors.size(); } raw.reserve(total_size); auto dump_to_vector = [&raw](const T& t) { const auto* byte_ptr = reinterpret_cast(&t); raw.insert(raw.end(), byte_ptr, byte_ptr + sizeof(T)); }; for (const auto& [vertex, neighbors] : m_vertex_map) { // Clamp neighbors count to fit in uint16_t (prevents silent data corruption) // NOTE: If neighbors.size() > 65535, only the first 65535 neighbors will be serialized. // This is a limitation of the current serialization format using uint16_t for count. const auto clamped_count = std::min(neighbors.size(), std::numeric_limits::max()); const auto neighbors_count = static_cast(clamped_count); dump_to_vector(vertex); dump_to_vector(neighbors_count); // Only serialize up to the clamped count for (std::size_t i = 0; i < clamped_count; ++i) dump_to_vector(neighbors[i]); } return raw; } void NavigationMesh::deserialize(const std::vector& raw) noexcept { auto load_from_vector = [](const std::vector& vec, std::size_t& offset, auto& value) { if (offset + sizeof(value) > vec.size()) throw std::runtime_error("Deserialize: Invalid input data size."); std::copy_n(vec.data() + offset, sizeof(value), reinterpret_cast(&value)); offset += sizeof(value); }; m_vertex_map.clear(); std::size_t offset = 0; while (offset < raw.size()) { Vector3 vertex; load_from_vector(raw, offset, vertex); std::uint16_t neighbors_count; load_from_vector(raw, offset, neighbors_count); std::vector> neighbors; neighbors.reserve(neighbors_count); for (std::size_t i = 0; i < neighbors_count; ++i) { Vector3 neighbor; load_from_vector(raw, offset, neighbor); neighbors.push_back(neighbor); } m_vertex_map.emplace(vertex, std::move(neighbors)); } } } // namespace omath::pathfinding