1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-26 09:35:28 +00:00

Pathfinding Overhaul - Even more cleanup and spacing corrections, small renaming (more to come), removed a few unnecessary actions that wasted CPU time and tmp RAM.

This commit is contained in:
Torben Carrington 2013-05-29 17:33:33 -07:00
parent 96fdaf7410
commit 7b465ae4f1
2 changed files with 65 additions and 107 deletions

View File

@ -10,18 +10,36 @@
namespace namespace
{ {
// helpers functions struct found_path {};
float distanceZCorrected(ESM::Pathgrid::Point point,float x,float y,float z)
typedef boost::adjacency_list< boost::vecS, boost::vecS, boost::undirectedS,
boost::property<boost::vertex_index_t, int, ESM::Pathgrid::Point>, boost::property<boost::edge_weight_t, float> >
PathGridGraph;
typedef boost::property_map<PathGridGraph, boost::edge_weight_t>::type WeightMap;
typedef PathGridGraph::vertex_descriptor PointID;
typedef PathGridGraph::edge_descriptor PointConnectionID;
class goalVisited : public boost::default_dijkstra_visitor
{
public:
goalVisited(PointID goal) {mGoal = goal;};
void examine_vertex(PointID u, const PathGridGraph g) {if(u == mGoal) throw found_path();};
private:
PointID mGoal;
};
float distanceZCorrected(ESM::Pathgrid::Point point, float x, float y, float z)
{ {
return sqrt((point.mX - x) * (point.mX - x) + (point.mY - y) * (point.mY - y) + 0.1 * (point.mZ - z) * (point.mZ - z)); return sqrt((point.mX - x) * (point.mX - x) + (point.mY - y) * (point.mY - y) + 0.1 * (point.mZ - z) * (point.mZ - z));
} }
float distance(ESM::Pathgrid::Point point,float x,float y,float z) float distance(ESM::Pathgrid::Point point, float x, float y, float z)
{ {
return sqrt((point.mX - x) * (point.mX - x) + (point.mY - y) * (point.mY - y) + (point.mZ - z) * (point.mZ - z)); return sqrt((point.mX - x) * (point.mX - x) + (point.mY - y) * (point.mY - y) + (point.mZ - z) * (point.mZ - z));
} }
float distance(ESM::Pathgrid::Point a,ESM::Pathgrid::Point b) float distance(ESM::Pathgrid::Point a, ESM::Pathgrid::Point b)
{ {
return sqrt(float(a.mX - b.mX) * (a.mX - b.mX) + (a.mY - b.mY) * (a.mY - b.mY) + (a.mZ - b.mZ) * (a.mZ - b.mZ)); return sqrt(float(a.mX - b.mX) * (a.mX - b.mX) + (a.mY - b.mY) * (a.mY - b.mY) + (a.mZ - b.mZ) * (a.mZ - b.mZ));
} }
@ -30,90 +48,30 @@ namespace
{ {
if(a > 0) if(a > 0)
return 1.0; return 1.0;
else return -1.0;
return -1.0;
} }
int getClosestPoint(const ESM::Pathgrid* grid,float x,float y,float z) int getClosestPoint(const ESM::Pathgrid* grid, float x, float y, float z)
{ {
if(!grid) if(!grid || grid->mPoints.empty())
return -1;
if(grid->mPoints.empty())
return -1; return -1;
float m = distance(grid->mPoints[0],x,y,z); float distanceBetween = distance(grid->mPoints[0], x, y, z);
int i0 = 0; int closestIndex = 0;
for(unsigned int i = 1; i < grid->mPoints.size(); ++i) for(unsigned int counter = 1; counter < grid->mPoints.size(); counter++)
{ {
if(distance(grid->mPoints[i],x,y,z) < m) if(distance(grid->mPoints[counter], x, y, z) < distanceBetween)
{ {
m = distance(grid->mPoints[i],x,y,z); distanceBetween = distance(grid->mPoints[counter], x, y, z);
i0 = i; closestIndex = counter;
} }
} }
return i0;
return closestIndex;
} }
typedef boost::adjacency_list<boost::vecS,boost::vecS,boost::undirectedS, PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid, float xCell = 0, float yCell = 0)
boost::property<boost::vertex_index_t,int,ESM::Pathgrid::Point>,boost::property<boost::edge_weight_t,float> > PathGridGraph;
typedef boost::property_map<PathGridGraph, boost::edge_weight_t>::type WeightMap;
typedef PathGridGraph::vertex_descriptor PointID;
typedef PathGridGraph::edge_descriptor PointConnectionID;
struct found_path {};
/*class goalVisited : public boost::default_astar_visitor
{
public:
goalVisited(PointID goal) : mGoal(goal) {}
void examine_vertex(PointID u, const PathGridGraph g)
{
if(u == mGoal)
throw found_path();
}
private:
PointID mGoal;
};
class DistanceHeuristic : public boost::atasr_heuristic <PathGridGraph, float>
{
public:
DistanceHeuristic(const PathGridGraph & l, PointID goal)
: mGraph(l), mGoal(goal) {}
float operator()(PointID u)
{
const ESM::Pathgrid::Point & U = mGraph[u];
const ESM::Pathgrid::Point & V = mGraph[mGoal];
float dx = U.mX - V.mX;
float dy = U.mY - V.mY;
float dz = U.mZ - V.mZ;
return sqrt(dx * dx + dy * dy + dz * dz);
}
private:
const PathGridGraph & mGraph;
PointID mGoal;
};*/
class goalVisited : public boost::default_dijkstra_visitor
{
public:
goalVisited(PointID goal) : mGoal(goal) {}
void examine_vertex(PointID u, const PathGridGraph g)
{
if(u == mGoal)
throw found_path();
}
private:
PointID mGoal;
};
PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid,float xCell = 0,float yCell = 0)
{ {
PathGridGraph graph; PathGridGraph graph;
@ -132,39 +90,38 @@ PointID mGoal;
PointConnectionID edge; PointConnectionID edge;
bool done; bool done;
boost::tie(edge,done) = boost::add_edge(u,v,graph); boost::tie(edge, done) = boost::add_edge(u, v, graph);
WeightMap weightmap = boost::get(boost::edge_weight, graph); WeightMap weightmap = boost::get(boost::edge_weight, graph);
weightmap[edge] = distance(graph[u],graph[v]); weightmap[edge] = distance(graph[u], graph[v]);
} }
return graph; return graph;
} }
std::list<ESM::Pathgrid::Point> findPath(PointID start,PointID end,PathGridGraph graph){ std::list<ESM::Pathgrid::Point> findPath(PointID start, PointID end, PathGridGraph graph)
{
std::vector<PointID> p(boost::num_vertices(graph)); std::vector<PointID> p(boost::num_vertices(graph));
std::vector<float> d(boost::num_vertices(graph)); std::vector<float> d(boost::num_vertices(graph));
std::list<ESM::Pathgrid::Point> shortest_path; std::list<ESM::Pathgrid::Point> shortest_path;
try { try
boost::dijkstra_shortest_paths {
( boost::dijkstra_shortest_paths(graph, start,
graph, boost::predecessor_map(&p[0]).distance_map(&d[0]).visitor(goalVisited(end)));
start, }
boost::predecessor_map(&p[0]).distance_map(&d[0]).visitor(goalVisited(end))//.weight_map(boost::get(&Edge::distance, graph))
);
} catch(found_path fg) { catch(found_path fg)
for(PointID v = end; ; v = p[v]) { {
for(PointID v = end; ; v = p[v])
{
shortest_path.push_front(graph[v]); shortest_path.push_front(graph[v]);
if(p[v] == v) if(p[v] == v)
break; break;
} }
} }
return shortest_path; return shortest_path;
} }
//end of helpers functions
} }
namespace MWMechanics namespace MWMechanics
@ -181,53 +138,53 @@ namespace MWMechanics
mIsPathConstructed = false; mIsPathConstructed = false;
} }
void PathFinder::buildPath(ESM::Pathgrid::Point startPoint,ESM::Pathgrid::Point endPoint, void PathFinder::buildPath(ESM::Pathgrid::Point startPoint, ESM::Pathgrid::Point endPoint,
const ESM::Pathgrid* pathGrid,float xCell,float yCell) const ESM::Pathgrid* pathGrid, float xCell, float yCell)
{ {
//first check if there is an obstacle //first check if there is an obstacle
if(MWBase::Environment::get().getWorld()->castRay(startPoint.mX,startPoint.mY,startPoint.mZ, if(MWBase::Environment::get().getWorld()->castRay(startPoint.mX, startPoint.mY, startPoint.mZ,
endPoint.mX,endPoint.mY,endPoint.mZ) ) endPoint.mX, endPoint.mY, endPoint.mZ) )
{ {
int start = getClosestPoint(pathGrid,startPoint.mX - xCell,startPoint.mY - yCell,startPoint.mZ); int start = getClosestPoint(pathGrid, startPoint.mX - xCell, startPoint.mY - yCell,startPoint.mZ);
int end = getClosestPoint(pathGrid,endPoint.mX - xCell,endPoint.mY - yCell,endPoint.mZ); int end = getClosestPoint(pathGrid, endPoint.mX - xCell, endPoint.mY - yCell, endPoint.mZ);
if(start != -1 && end != -1) if(start != -1 && end != -1)
{ {
PathGridGraph graph = buildGraph(pathGrid,xCell,yCell); PathGridGraph graph = buildGraph(pathGrid, xCell, yCell);
mPath = findPath(start,end,graph); mPath = findPath(start, end, graph);
} }
} }
mPath.push_back(endPoint); mPath.push_back(endPoint);
mIsPathConstructed = true; mIsPathConstructed = true;
} }
float PathFinder::getZAngleToNext(float x,float y,float z) float PathFinder::getZAngleToNext(float x, float y, float z)
{ {
if(mPath.empty()) if(mPath.empty())
return 0; /// shouldn't happen! return 0; // shouldn't happen!
ESM::Pathgrid::Point nextPoint = *mPath.begin(); ESM::Pathgrid::Point nextPoint = *mPath.begin();
float dX = nextPoint.mX - x; float dX = nextPoint.mX - x;
float dY = nextPoint.mY - y; float dY = nextPoint.mY - y;
float h = sqrt(dX * dX + dY * dY); float h = sqrt(dX * dX + dY * dY);
return Ogre::Radian(acos(dY / h) * sgn(asin(dX / h))).valueDegrees(); return Ogre::Radian(acos(dY / h) * sgn(asin(dX / h))).valueDegrees();
} }
bool PathFinder::checkIfNextPointReached(float x,float y,float z) bool PathFinder::checkIfNextPointReached(float x, float y, float z)
{ {
if(mPath.empty()) if(mPath.empty())
return true; return true;
ESM::Pathgrid::Point nextPoint = *mPath.begin(); ESM::Pathgrid::Point nextPoint = *mPath.begin();
if(distanceZCorrected(nextPoint,x,y,z) < 20) if(distanceZCorrected(nextPoint, x, y, z) < 20)
{ {
mPath.pop_front(); mPath.pop_front();
if(mPath.empty()) if(mPath.empty())
return true; return true;
nextPoint = *mPath.begin();
} }
return false; return false;
} }

View File

@ -15,7 +15,8 @@ namespace MWMechanics
void buildPath(ESM::Pathgrid::Point startPoint,ESM::Pathgrid::Point endPoint, void buildPath(ESM::Pathgrid::Point startPoint,ESM::Pathgrid::Point endPoint,
const ESM::Pathgrid* pathGrid,float xCell = 0,float yCell = 0); const ESM::Pathgrid* pathGrid,float xCell = 0,float yCell = 0);
bool checkIfNextPointReached(float x,float y,float z);//returns true if the last point of the path has been reached. bool checkIfNextPointReached(float x,float y,float z);
///< \Returns true if the last point of the path has been reached.
float getZAngleToNext(float x,float y,float z); float getZAngleToNext(float x,float y,float z);
std::list<ESM::Pathgrid::Point> getPath(); std::list<ESM::Pathgrid::Point> getPath();