⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dstar.cpp

📁 D星算法
💻 CPP
字号:
/* Dstar.cpp * James Neufeld (neufeld@cs.ualberta.ca) */#include "Dstar.h"#include <stdio.h>#ifdef USE_OPEN_GL#ifdef MACOS#include <OpenGL/gl.h>#else#include <GL/gl.h>#endif#endif/* void Dstar::Dstar() * -------------------------- * Constructor sets constants. */Dstar::Dstar() {   maxSteps = 80000;  // node expansions before we give up  C1       = 1;      // cost of an unseen cell}/* float Dstar::keyHashCode(state u)  * --------------------------  * Returns the key hash code for the state u, this is used to compare * a state that have been updated */float Dstar::keyHashCode(state u) {  return (float)(u.k.first + 1193*u.k.second);}/* bool Dstar::isValid(state u)  * -------------------------- * Returns true if state u is on the open list or not by checking if * it is in the hash table. */bool Dstar::isValid(state u) {    ds_oh::iterator cur = openHash.find(u);  if (cur == openHash.end()) return false;  if (!close(keyHashCode(u), cur->second)) return false;  return true;  }/* void Dstar::getPath()  * -------------------------- * Returns the path created by replan() */list<state> Dstar::getPath() {  return path;}/* bool Dstar::occupied(state u) * -------------------------- * returns true if the cell is occupied (non-traversable), false * otherwise. non-traversable are marked with a cost < 0. */bool Dstar::occupied(state u) {    ds_ch::iterator cur = cellHash.find(u);    if (cur == cellHash.end()) return false;  return (cur->second.cost < 0);}/* void Dstar::init(int sX, int sY, int gX, int gY) * -------------------------- * Init dstar with start and goal coordinates, rest is as per * [S. Koenig, 2002] */void Dstar::init(int sX, int sY, int gX, int gY) {    cellHash.clear();  path.clear();  openHash.clear();  while(!openList.empty()) openList.pop();  k_m = 0;    s_start.x = sX;  s_start.y = sY;  s_goal.x  = gX;  s_goal.y  = gY;  cellInfo tmp;  tmp.g = tmp.rhs =  0;  tmp.cost = C1;  cellHash[s_goal] = tmp;  tmp.g = tmp.rhs = heuristic(s_start,s_goal);  tmp.cost = C1;  cellHash[s_start] = tmp;  s_start = calculateKey(s_start);  s_last = s_start;}/* void Dstar::makeNewCell(state u) * -------------------------- * Checks if a cell is in the hash table, if not it adds it in. */void Dstar::makeNewCell(state u) {    if (cellHash.find(u) != cellHash.end()) return;  cellInfo tmp;  tmp.g       = tmp.rhs = heuristic(u,s_goal);  tmp.cost    = C1;  cellHash[u] = tmp;  }/* double Dstar::getG(state u) * -------------------------- * Returns the G value for state u. */double Dstar::getG(state u) {  if (cellHash.find(u) == cellHash.end())     return heuristic(u,s_goal);  return cellHash[u].g;  }/* double Dstar::getRHS(state u) * -------------------------- * Returns the rhs value for state u. */double Dstar::getRHS(state u) {  if (u == s_goal) return 0;    if (cellHash.find(u) == cellHash.end())     return heuristic(u,s_goal);  return cellHash[u].rhs;  }/* void Dstar::setG(state u, double g) * -------------------------- * Sets the G value for state u */void Dstar::setG(state u, double g) {    makeNewCell(u);    cellHash[u].g = g; }/* void Dstar::setRHS(state u, double rhs) * -------------------------- * Sets the rhs value for state u */double Dstar::setRHS(state u, double rhs) {    makeNewCell(u);  cellHash[u].rhs = rhs;}/* double Dstar::eightCondist(state a, state b)  * -------------------------- * Returns the 8-way distance between state a and state b. */double Dstar::eightCondist(state a, state b) {  double temp;  double min = abs(a.x - b.x);  double max = abs(a.y - b.y);  if (min > max) {    double temp = min;    min = max;    max = temp;  }  return ((M_SQRT2-1.0)*min + max);}/* int Dstar::computeShortestPath() * -------------------------- * As per [S. Koenig, 2002] except for 2 main modifications: * 1. We stop planning after a number of steps, 'maxsteps' we do this *    because this algorithm can plan forever if the start is *    surrounded by obstacles.  * 2. We lazily remove states from the open list so we never have to *    iterate through it. */int Dstar::computeShortestPath() {    list<state> s;  list<state>::iterator i;  if (openList.empty()) return 1;  int k=0;  while ((!openList.empty()) &&          (openList.top() < (s_start = calculateKey(s_start))) ||          (getRHS(s_start) != getG(s_start))) {    if (k++ > maxSteps) {      fprintf(stderr, "At maxsteps\n");      return -1;    }    state u;    bool test = (getRHS(s_start) != getG(s_start));        // lazy remove    while(1) {       if (openList.empty()) return 1;      u = openList.top();      openList.pop();            if (!isValid(u)) continue;      if (!(u < s_start) && (!test)) return 2;      break;    }        ds_oh::iterator cur = openHash.find(u);    openHash.erase(cur);    state k_old = u;    if (k_old < calculateKey(u)) { // u is out of date      insert(u);    } else if (getG(u) > getRHS(u)) { // needs update (got better)      setG(u,getRHS(u));      getPred(u,s);      for (i=s.begin();i != s.end(); i++) {        updateVertex(*i);      }    } else {   // g <= rhs, state has got worse      setG(u,INFINITY);      getPred(u,s);      for (i=s.begin();i != s.end(); i++) {        updateVertex(*i);      }      updateVertex(u);    }  }  return 0;}/* bool Dstar::close(double x, double y)  * -------------------------- * Returns true if x and y are within 10E-5, false otherwise */bool Dstar::close(double x, double y) {      if (isinf(x) && isinf(y)) return true;  return (fabs(x-y) < 0.00001);  }/* void Dstar::updateVertex(state u) * -------------------------- * As per [S. Koenig, 2002] */void Dstar::updateVertex(state u) {  list<state> s;  list<state>::iterator i;   if (u != s_goal) {    getSucc(u,s);    double tmp = INFINITY;    double tmp2;    for (i=s.begin();i != s.end(); i++) {      tmp2 = getG(*i) + cost(u,*i);      if (tmp2 < tmp) tmp = tmp2;    }    if (!close(getRHS(u),tmp)) setRHS(u,tmp);  }  if (!close(getG(u),getRHS(u))) insert(u);  }/* void Dstar::insert(state u)  * -------------------------- * Inserts state u into openList and openHash. */void Dstar::insert(state u) {    ds_oh::iterator cur;  float csum;  u    = calculateKey(u);  cur  = openHash.find(u);  csum = keyHashCode(u);  // return if cell is already in list. TODO: this should be  // uncommented except it introduces a bug, I suspect that there is a  // bug somewhere else and having duplicates in the openList queue  // hides the problem...  //if ((cur != openHash.end()) && (close(csum,cur->second))) return;    openHash[u] = csum;  openList.push(u);} /* void Dstar::remove(state u) * -------------------------- * Removes state u from openHash. The state is removed from the * openList lazilily (in replan) to save computation. */void Dstar::remove(state u) {    ds_oh::iterator cur = openHash.find(u);  if (cur == openHash.end()) return;  openHash.erase(cur);}/* double Dstar::trueDist(state a, state b)  * -------------------------- * Euclidean cost between state a and state b. */double Dstar::trueDist(state a, state b) {    float x = a.x-b.x;  float y = a.y-b.y;  return sqrt(x*x + y*y);  }/* double Dstar::heuristic(state a, state b) * -------------------------- * Pretty self explanitory, the heristic we use is the 8-way distance * scaled by a constant C1 (should be set to <= min cost). */double Dstar::heuristic(state a, state b) {  return eightCondist(a,b)*C1;}/* state Dstar::calculateKey(state u) * -------------------------- * As per [S. Koenig, 2002] */state Dstar::calculateKey(state u) {    double val = fmin(getRHS(u),getG(u));    u.k.first  = val + heuristic(u,s_start) + k_m;  u.k.second = val;  return u;}/* double Dstar::cost(state a, state b) * -------------------------- * Returns the cost of moving from state a to state b. This could be * either the cost of moving off state a or onto state b, we went with * the former. This is also the 8-way cost. */double Dstar::cost(state a, state b) {  int xd = abs(a.x-b.x);  int yd = abs(a.y-b.y);  double scale = 1;  if (xd+yd>1) scale = M_SQRT2;  if (cellHash.count(a) == 0) return scale*C1;  return scale*cellHash[a].cost;}/* void Dstar::updateCell(int x, int y, double val) * -------------------------- * As per [S. Koenig, 2002] */void Dstar::updateCell(int x, int y, double val) {     state u;    u.x = x;  u.y = y;  if ((u == s_start) || (u == s_goal)) return;  makeNewCell(u);   cellHash[u].cost = val;  updateVertex(u);}/* void Dstar::getSucc(state u,list<state> &s) * -------------------------- * Returns a list of successor states for state u, since this is an * 8-way graph this list contains all of a cells neighbours. Unless * the cell is occupied in which case it has no successors.  */void Dstar::getSucc(state u,list<state> &s) {    s.clear();  u.k.first  = -1;  u.k.second = -1;  if (occupied(u)) return;  u.x += 1;  s.push_front(u);  u.y += 1;  s.push_front(u);  u.x -= 1;  s.push_front(u);  u.x -= 1;  s.push_front(u);  u.y -= 1;  s.push_front(u);  u.y -= 1;  s.push_front(u);  u.x += 1;  s.push_front(u);  u.x += 1;  s.push_front(u);}/* void Dstar::getPred(state u,list<state> &s) * -------------------------- * Returns a list of all the predecessor states for state u. Since * this is for an 8-way connected graph the list contails all the * neighbours for state u. Occupied neighbours are not added to the * list. */void Dstar::getPred(state u,list<state> &s) {    s.clear();  u.k.first  = -1;  u.k.second = -1;  u.x += 1;  if (!occupied(u)) s.push_front(u);  u.y += 1;  if (!occupied(u)) s.push_front(u);  u.x -= 1;  if (!occupied(u)) s.push_front(u);  u.x -= 1;  if (!occupied(u)) s.push_front(u);  u.y -= 1;  if (!occupied(u)) s.push_front(u);  u.y -= 1;  if (!occupied(u)) s.push_front(u);  u.x += 1;  if (!occupied(u)) s.push_front(u);  u.x += 1;  if (!occupied(u)) s.push_front(u);  }/* void Dstar::updateStart(int x, int y) * -------------------------- * Update the position of the robot, this does not force a replan. */void Dstar::updateStart(int x, int y) {  s_start.x = x;  s_start.y = y;    k_m += heuristic(s_last,s_start);  s_start = calculateKey(s_start);  s_last  = s_start;  }/* void Dstar::updateGoal(int x, int y) * -------------------------- * This is somewhat of a hack, to change the position of the goal we * first save all of the non-empty on the map, clear the map, move the * goal, and re-add all of non-empty cells. Since most of these cells * are not between the start and goal this does not seem to hurt * performance too much. Also it free's up a good deal of memory we * likely no longer use. */void Dstar::updateGoal(int x, int y) {     list< pair<ipoint2, double> > toAdd;  pair<ipoint2, double> tp;    ds_ch::iterator i;  list< pair<ipoint2, double> >::iterator kk;    for(i=cellHash.begin(); i!=cellHash.end(); i++) {    if (!close(i->second.cost, C1)) {      tp.first.x = i->first.x;      tp.first.y = i->first.y;      tp.second = i->second.cost;      toAdd.push_back(tp);    }  }  cellHash.clear();  openHash.clear();  while(!openList.empty())    openList.pop();    k_m = 0;    s_goal.x  = x;  s_goal.y  = y;  cellInfo tmp;  tmp.g = tmp.rhs =  0;  tmp.cost = C1;  cellHash[s_goal] = tmp;  tmp.g = tmp.rhs = heuristic(s_start,s_goal);  tmp.cost = C1;  cellHash[s_start] = tmp;  s_start = calculateKey(s_start);  s_last = s_start;      for (kk=toAdd.begin(); kk != toAdd.end(); kk++) {    updateCell(kk->first.x, kk->first.y, kk->second);  }  }/* bool Dstar::replan() * -------------------------- * Updates the costs for all cells and computes the shortest path to * goal. Returns true if a path is found, false otherwise. The path is * computed by doing a greedy search over the cost+g values in each * cells. In order to get around the problem of the robot taking a * path that is near a 45 degree angle to goal we break ties based on *  the metric euclidean(state, goal) + euclidean(state,start).  */bool Dstar::replan() {  path.clear();  int res = computeShortestPath();  //printf("res: %d ols: %d ohs: %d tk: [%f %f] sk: [%f %f] sgr: (%f,%f)\n",res,openList.size(),openHash.size(),openList.top().k.first,openList.top().k.second, s_start.k.first, s_start.k.second,getRHS(s_start),getG(s_start));  if (res < 0) {    fprintf(stderr, "NO PATH TO GOAL\n");    return false;  }  list<state> n;  list<state>::iterator i;  state cur = s_start;   if (isinf(getG(s_start))) {    fprintf(stderr, "NO PATH TO GOAL\n");    return false;  }    while(cur != s_goal) {        path.push_back(cur);    getSucc(cur, n);    if (n.empty()) {      fprintf(stderr, "NO PATH TO GOAL\n");      return false;    }    double cmin = INFINITY;    double tmin;    state smin;        for (i=n.begin(); i!=n.end(); i++) {        //if (occupied(*i)) continue;      double val  = cost(cur,*i);      double val2 = trueDist(*i,s_goal) + trueDist(s_start,*i); // (Euclidean) cost to goal + cost to pred      val += getG(*i);      if (close(val,cmin)) {        if (tmin > val2) {          tmin = val2;          cmin = val;          smin = *i;        }      } else if (val < cmin) {        tmin = val2;        cmin = val;        smin = *i;      }    }    n.clear();    cur = smin;  }  path.push_back(s_goal);  return true;}#ifdef USE_OPEN_GLvoid Dstar::draw() {  ds_ch::iterator iter;  ds_oh::iterator iter1;  state t;  list<state>::iterator iter2;    glBegin(GL_QUADS);  for(iter=cellHash.begin(); iter != cellHash.end(); iter++) {    if (iter->second.cost == 1) glColor3f(0,1,0);    else if (iter->second.cost < 0 ) glColor3f(1,0,0);    else glColor3f(0,0,1);    drawCell(iter->first,0.45);  }  glColor3f(1,1,0);  drawCell(s_start,0.45);  glColor3f(1,0,1);  drawCell(s_goal,0.45);  for(iter1=openHash.begin(); iter1 != openHash.end(); iter1++) {    glColor3f(0.4,0,0.8);    drawCell(iter1->first, 0.2);  }    glEnd();  glLineWidth(4);  glBegin(GL_LINE_STRIP);  glColor3f(0.6, 0.1, 0.4);  for(iter2=path.begin(); iter2 != path.end(); iter2++) {    glVertex3f(iter2->x, iter2->y, 0.2);  }  glEnd();}void Dstar::drawCell(state s, float size) {  float x = s.x;  float y = s.y;      glVertex2f(x - size, y - size);  glVertex2f(x + size, y - size);  glVertex2f(x + size, y + size);  glVertex2f(x - size, y + size);}#elsevoid Dstar::draw() {}void Dstar::drawCell(state s, float z) {}#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -