#pragma once #include "render/Renderer.h" #include #include #include namespace FRG { class PathFinder { public: struct ObstaclePolygon { std::string name; std::vector polygon; }; struct DynamicObstacle { Eigen::Vector3f position = Eigen::Vector3f::Zero(); float radius = 0.0f; }; struct Cell { int x = 0; int z = 0; }; struct NavigationArea { std::string name; bool available = true; std::vector polygon; }; void build(const std::string& configPath, const std::string& zipPath = ""); std::vector findPath(const Eigen::Vector3f& start, const Eigen::Vector3f& end) const; std::vector findPath(const Eigen::Vector3f& start, const Eigen::Vector3f& end, const std::vector& dynamicObstacles) const; // Like findPath, but when the destination is unreachable the character // walks as close as possible instead of not moving at all. std::vector findPathToNearest(const Eigen::Vector3f& start, const Eigen::Vector3f& end) const; std::vector findPathToNearest(const Eigen::Vector3f& start, const Eigen::Vector3f& end, const std::vector& dynamicObstacles) const; bool setAreaAvailable(const std::string& areaName, bool available); bool isReady() const { return ready; } bool isWalkable(const Eigen::Vector3f& point) const; const std::vector& getAreas() const { return areas; } const std::vector& getObstaclePolygons() const { return obstaclePolygons; } float getFloorY() const { return floorY; } void addObstaclePolygon(const ObstaclePolygon& polygon); bool saveConfig(const std::string& path) const; bool saveGrid(const std::string& path) const; private: float cellSize = 0.4f; float agentRadius = 0.45f; float floorY = 0.0f; float objectPadding = 0.25f; float boundaryPadding = 0.0f; float minX = 0.0f; float minZ = 0.0f; int gridWidth = 0; int gridDepth = 0; bool ready = false; std::string loadedConfigPath; std::string loadedZipPath; std::vector obstaclePolygons; std::vector walkable; std::vector areas; void loadConfig(const std::string& configPath, const std::string& zipPath); bool loadGrid(const std::string& path, const std::string& zipPath); void resetGridBounds(); void rebuildWalkableGrid(); void markAvailableAreasWalkable(); void markObstaclePolygonsBlocked(); bool worldToCell(const Eigen::Vector3f& point, Cell& out) const; Eigen::Vector3f cellCenter(const Cell& cell) const; bool isInsideGrid(const Cell& cell) const; bool isCellWalkable(const Cell& cell) const; int indexOf(const Cell& cell) const; bool findNearestWalkableCell(const Eigen::Vector3f& point, Cell& out) const; bool hasLineOfSight(const Cell& from, const Cell& to) const; std::vector smoothCells(const std::vector& cells) const; static bool pointInPolygon(float x, float z, const std::vector& polygon); bool isCellWalkable(const Cell& cell, const std::vector& walkableGrid) const; bool findNearestWalkableCell(const Eigen::Vector3f& point, Cell& out, const std::vector& walkableGrid) const; bool hasLineOfSight(const Cell& from, const Cell& to, const std::vector& walkableGrid) const; std::vector smoothCells(const std::vector& cells, const std::vector& walkableGrid) const; // A* that runs to exhaustion and returns a path to the reachable cell // geometrically closest to end when end itself is unreachable. std::vector findNearestReachableImpl(const Eigen::Vector3f& start, const Eigen::Vector3f& end, const std::vector& walkableGrid) const; std::vector runAStar(const Eigen::Vector3f& start, const Eigen::Vector3f& end, const std::vector& grid, bool returnNearestOnFail) const; }; } // namespace FRG