00001
00002 #include "PathPlanner.h"
00003 #include "Shared/ProjectInterface.h"
00004 #include "Vision/SegmentedColorGenerator.h"
00005 #include <iostream>
00006 #include <ctime>
00007 #include <vector>
00008 #include <queue>
00009 #include <map>
00010 #include <math.h>
00011
00012 using namespace std;
00013
00014 namespace DualCoding {
00015
00016 using ProjectInterface::defSegmentedColorGenerator;
00017
00018 PathPlanner::PathPlanner(coordinate_t xMax, coordinate_t xMin, coordinate_t yMax, coordinate_t yMin)
00019 : allStates(), unreached(NULL), reached(),
00020 numX((unsigned int) ((xMax-xMin)/size)+1), numY((unsigned int) ((yMax-yMin)/size)+1),
00021 minX(xMin), minY(yMin), dX((xMax-xMin)/numX), dY((yMax-yMin)/numY),
00022 start(), goal(), maxDistance(800), costs(),
00023 startPt(), goalPt(),startOrientation(), goalOrientation(),
00024 costMap(NULL), landmarks(), lmCosts(), obstacles()
00025 {
00026 unreached = new vector<state*>[numX*numY*4];
00027 costMap = new unsigned int [numX*numY];
00028
00029 costs[transF] = 1;
00030 costs[transB] = 2;
00031 costs[transY] = 4;
00032 costs[rotate] = 3;
00033 costs[noLM] = 20;
00034 costs[oneLM] = 10;
00035 }
00036
00037 void PathPlanner::findPath() {
00038 initialize();
00039 while (!reached.empty()) {
00040 edge top = reached.top();
00041 if (top.from != NULL && top.from->dst == NULL) {
00042 top.from->cost = top.cost;
00043 top.from->dst = top.to;
00044 vector<state*>& lms = unreached[top.from->loc.pos*4 + top.from->loc.dir];
00045 for (vector<state*>::iterator it = lms.begin();
00046 it != lms.end(); it++)
00047 if ((*it)->lms == top.from->lms) {
00048 lms.erase(it);
00049 break;
00050 }
00051 if (top.from->loc==start) {
00052 cout << "best path:\n";
00053 state* s = top.from;
00054 while(s) {
00055 cout << toString(*s) << endl;
00056 s = s->dst;
00057 }
00058 cout << endl;
00059 break;
00060 }
00061 else
00062 findLinks(*top.from);
00063 }
00064 reached.pop();
00065 }
00066 cout << "done: " << reached.empty() << endl;
00067 }
00068
00069 void PathPlanner::findLinks(state& s) {
00070 unsigned int newCostMotion = s.cost+lmCosts[s.lms.first]+lmCosts[s.lms.second]+1;
00071 if (s.lms.first < 0) {
00072 if (s.lms.second < 0)
00073 newCostMotion += costs[noLM];
00074 else
00075 newCostMotion += costs[oneLM];
00076 }
00077 {
00078 if (s.loc.pos%numY+1 < numY) {
00079 if (state* it = thereIs(s.loc.pos+1,s.loc.dir,s.lms)) {
00080 if (s.loc.dir==direction::E)
00081 reached.push(edge(*it,s,newCostMotion+costMap[s.loc.pos]+costs[transB]));
00082 else if (s.loc.dir == direction::W)
00083 reached.push(edge(*it,s,newCostMotion+costMap[s.loc.pos]+costs[transF]));
00084 else
00085 reached.push(edge(*it,s,newCostMotion+costMap[s.loc.pos]+costs[transY]));
00086 }
00087 }
00088 if (s.loc.pos%numY > 0) {
00089 if (state* it = thereIs(s.loc.pos-1,s.loc.dir,s.lms)) {
00090 if (s.loc.dir==direction::E)
00091 reached.push(edge(*it,s,newCostMotion+costMap[s.loc.pos]+costs[transF]));
00092 else if (s.loc.dir == direction::W)
00093 reached.push(edge(*it,s,newCostMotion+costMap[s.loc.pos]+costs[transB]));
00094 else
00095 reached.push(edge(*it,s,newCostMotion+costMap[s.loc.pos]+costs[transY]));
00096 }
00097 }
00098 if (s.loc.pos < numY*(numX-1)) {
00099 if (state* it = thereIs(s.loc.pos+numY,s.loc.dir,s.lms)) {
00100 if (s.loc.dir==direction::N)
00101 reached.push(edge(*it,s,newCostMotion+costMap[s.loc.pos]+costs[transF]));
00102 else if (s.loc.dir == direction::S)
00103 reached.push(edge(*it,s,newCostMotion+costMap[s.loc.pos]+costs[transB]));
00104 else
00105 reached.push(edge(*it,s,newCostMotion+costMap[s.loc.pos]+costs[transY]));
00106 }
00107 }
00108 if (s.loc.pos >= numY) {
00109 if (state* it = thereIs(s.loc.pos-numY,s.loc.dir,s.lms)) {
00110 if (s.loc.dir==direction::N)
00111 reached.push(edge(*it,s,newCostMotion+costMap[s.loc.pos]+costs[transB]));
00112 else if (s.loc.dir == direction::S)
00113 reached.push(edge(*it,s,newCostMotion+costMap[s.loc.pos]+costs[transF]));
00114 else
00115 reached.push(edge(*it,s,newCostMotion+costMap[s.loc.pos]+costs[transY]));
00116 }
00117 }
00118 }
00119 {
00120 const int newRotateCost = newCostMotion+costs[rotate];
00121 if (state* it = thereIs(s.loc.pos,s.loc.dir.cw(),s.lms))
00122 reached.push(edge(*it,s,newRotateCost+costMap[s.loc.pos]));
00123 if (state* it = thereIs(s.loc.pos,s.loc.dir.ccw(),s.lms))
00124 reached.push(edge(*it,s,newRotateCost+costMap[s.loc.pos]));
00125 }
00126 {
00127 vector<pair<int,int> > lms = findLMs(s.loc);
00128 for (vector<pair<int,int> >::const_iterator it = lms.begin();
00129 it != lms.end(); it++)
00130 if (*it != s.lms)
00131 reached.push(edge(*(thereIs(s.loc.pos,s.loc.dir,*it)),s,s.cost+1));
00132 }
00133 }
00134
00135
00136 Point PathPlanner::findWorldCoords(unsigned int pos) {
00137 return Point (minX+dX*(pos/numY),minY+dY*(pos%numY),0);
00138 }
00139
00140
00141 void PathPlanner::computeLandmarkCosts() {
00142 map<unsigned int, float> distSum;
00143 map<unsigned int, vector<unsigned int> > lmsSortedByColor;
00144 for (map<unsigned int, PointData>::const_iterator it1 = landmarks.begin();
00145 it1 != landmarks.end(); it1++) {
00146 map<unsigned int, PointData>::const_iterator it2 = it1;
00147 it2++;
00148 for (; it2 != landmarks.end(); it2++)
00149 if (it1->second.getColor() == it2->second.getColor()) {
00150 float dist = it1->second.getCentroid().xyDistanceFrom(it2->second);
00151 float cost = 10000/(dist*dist);
00152 distSum[it1->first] += cost;
00153 distSum[it2->first] += cost;
00154 }
00155 lmsSortedByColor[defSegmentedColorGenerator->getColorIndex(it1->second.getColor())].push_back(it1->first);
00156 }
00157 for (map<unsigned int, vector<unsigned int> >::const_iterator col_it = lmsSortedByColor.begin();
00158 col_it != lmsSortedByColor.end(); col_it++)
00159 for (vector<unsigned int>::const_iterator lm_it = col_it->second.begin();
00160 lm_it != col_it->second.end(); lm_it++)
00161 lmCosts[*lm_it] = (unsigned int) distSum[*lm_it];
00162 }
00163
00164 void PathPlanner::initialize() {
00165
00166 float minStartDist = findWorldCoords(0).distanceFrom(startPt);
00167 float minGoalDist = findWorldCoords(0).distanceFrom(goalPt);
00168 unsigned int startIdx=0, goalIdx=0;
00169 for (unsigned int pos = 1; pos < numX*numY; pos++) {
00170 float startDist = findWorldCoords(pos).distanceFrom(startPt);
00171 float goalDist = findWorldCoords(pos).distanceFrom(goalPt);
00172 if (startDist < minStartDist) {
00173 minStartDist = startDist;
00174 startIdx = pos;
00175 }
00176 if (goalDist < minGoalDist) {
00177 minGoalDist = goalDist;
00178 goalIdx = pos;
00179 }
00180 }
00181 start.pos = startIdx;
00182 goal.pos = goalIdx;
00183
00184 if (startOrientation > M_PI/4) {
00185 if (startOrientation < M_PI*3/4)
00186 start.dir = direction::W;
00187 else if (startOrientation < M_PI*5/4)
00188 start.dir = direction::S;
00189 else if (startOrientation < M_PI*7/4)
00190 start.dir = direction::E;
00191 }
00192 else
00193 start.dir = direction::N;
00194
00195 if (goalOrientation > M_PI/4) {
00196 if (goalOrientation < M_PI*3/4)
00197 goal.dir = direction::W;
00198 else if (goalOrientation < M_PI*5/4)
00199 goal.dir = direction::S;
00200 else if (goalOrientation < M_PI*7/4)
00201 goal.dir = direction::E;
00202 }
00203 else
00204 goal.dir = direction::N;
00205
00206
00207
00208 for (unsigned int pos = 0; pos < numX*numY; pos++) {
00209 costMap[pos] = 0;
00210 for (vector<pair<Point, unsigned int> >::const_iterator it = obstacles.begin();
00211 it != obstacles.end(); it++) {
00212 Point vec = findWorldCoords(pos)-it->first;
00213 float distSq = (vec.coordX()*vec.coordX() + vec.coordY()*vec.coordY())/10000;
00214 costMap[pos] += (unsigned int) ((distSq > 0) ? it->second/distSq : -1U);
00215 }
00216 }
00217 computeLandmarkCosts();
00218 cout << "costs:\n";
00219 cout << " costs[transF]: " << costs[transF] << endl;
00220 cout << " costs[transB]: " << costs[transB] << endl;
00221 cout << " costs[transY]: " << costs[transY] << endl;
00222 cout << " costs[rotate]: " << costs[rotate] << endl;
00223 cout << " costs[noLM]: " << costs[noLM] << endl;
00224 cout << " costs[oneLM]: " << costs[oneLM] << endl;
00225
00226 cout << "landmarks:\n";
00227 for (map<unsigned int, PointData>::const_iterator it = landmarks.begin();
00228 it != landmarks.end(); it++)
00229 cout<< "lm id " << it->first << " at " << it->second
00230
00231 << ", cost=" << lmCosts[it->first] << endl;
00232
00233 cout << "obstacles:\n";
00234 for (vector<pair<Point, unsigned int> >::const_iterator it = obstacles.begin();
00235 it != obstacles.end(); it++)
00236 cout << " " << it->first << ": " << it->second << endl;
00237
00238
00239 cout << "costMap:\n";
00240 for (int j = numX-1; j >= 0; j--) {
00241 for (int i = numY-1; i >= 0; i--)
00242 if (i+j*numY == start.pos)
00243 cout << " S";
00244 else if (i+j*numY == goal.pos)
00245 cout << " G";
00246 else
00247 cout << " " << costMap[i+j*numY];
00248 cout << endl;
00249 }
00250
00251 while (!reached.empty())
00252 reached.pop();
00253 for (unsigned int i = 0; i < numX*numY*4; i++)
00254 unreached[i].clear();
00255 while (!allStates.empty())
00256 allStates.pop();
00257
00258
00259 vector<state*> goals;
00260 fillState(0,goal.pos);
00261 for (unsigned int i = 0; i < 4; i++) {
00262 location loc (goal.pos,i);
00263 vector<pair<int,int> > lms = findLMs(loc);
00264 for (vector<pair<int,int> >::const_iterator it = lms.begin();
00265 it < lms.end(); it++) {
00266 allStates.push(state(loc,*it));
00267 if (i == goal.dir)
00268 goals.push_back(&allStates.back());
00269 else
00270 unreached[loc.pos*4 + loc.dir].push_back(&(allStates.back()));
00271 }
00272 }
00273 fillState(goal.pos+1,numX*numY);
00274
00275 cout << "start state:\n";
00276 cout << " " << findWorldCoords(start.pos) << endl;
00277
00278
00279
00280 cout << "goal state(s):\n";
00281 for (vector<state*>::iterator it = goals.begin();
00282 it != goals.end(); it++) {
00283 (*it)->cost = 0;
00284 findLinks(**it);
00285 cout << " " << toString(**it) << " => " << findWorldCoords((*it)->loc.pos) << endl;
00286 }
00287 }
00288
00289 void PathPlanner::fillState(unsigned int low, unsigned int high) {
00290 for (unsigned int pos = low; pos < high; pos++) {
00291 for (unsigned int i = 0; i < 4; i++) {
00292 location loc(pos,i);
00293 vector<pair<int,int> > lms = findLMs(loc);
00294 for (vector<pair<int,int> >::const_iterator it = lms.begin();
00295 it < lms.end(); it++) {
00296 allStates.push(state(loc,*it));
00297 unreached[loc.pos*4 + loc.dir].push_back(&(allStates.back()));
00298 }
00299 }
00300 }
00301 }
00302
00303 PathPlanner::state* PathPlanner::thereIs(unsigned int pos, PathPlanner::direction dir, std::pair<int,int> lms) {
00304
00305 const vector<state*>& states = unreached[pos*4 + (unsigned int) dir];
00306 for (vector<state*>::const_iterator it = states.begin();
00307 it < states.end(); it++)
00308 if ((*it)->lms == lms)
00309 return *it;
00310 return NULL;
00311 }
00312
00313
00314 std::vector<std::pair<int,int> > PathPlanner::findLMs(location loc) {
00315 vector<int> lms;
00316 lms.push_back(-1);
00317 for (map<unsigned int, PointData>::const_iterator it = landmarks.begin();
00318 it != landmarks.end(); it++)
00319 if (isLMVisible(loc,it->second)) lms.push_back(it->first);
00320 vector<pair<int,int> > lmPairs;
00321 lmPairs.push_back(pair<int,int>(-1,-1));
00322 for(vector<int>::const_iterator it1 = lms.begin();
00323 it1 != lms.end(); it1++)
00324 for(vector<int>::const_iterator it2 = it1+1;
00325 it2 != lms.end(); it2++)
00326 lmPairs.push_back(pair<int,int>(*it1,*it2));
00327 return lmPairs;
00328 }
00329
00330 bool PathPlanner::isLMVisible(location l, const Point& lm) {
00331 Point agent = findWorldCoords(l.pos);
00332 float dx = lm.coordX()-agent.coordX();
00333 float dy = lm.coordY()-agent.coordY();
00334 float distance = sqrt(dx*dx + dy*dy);
00335
00336 if (distance > maxDistance || distance < 200) return false;
00337 AngTwoPi angle = atan2(dy,dx);
00338
00339 switch (l.dir) {
00340 case direction::N: return (angle < M_PI/3 || angle > M_PI*5/3);
00341 case direction::W: return (angle > M_PI/6 && angle < M_PI*5/6);
00342 case direction::S: return (angle > M_PI*2/3 && angle < M_PI*4/3);
00343 case direction::E: return (angle > M_PI*7/6 && angle < M_PI*11/6);
00344 };
00345 return false;
00346 }
00347
00348 std::string PathPlanner::toString(const PathPlanner::state &s) {
00349 stringstream ss;
00350 ss << "[(" << (s.loc.pos/numY) << ',' << (s.loc.pos%numY) << ','
00351 << s.loc.dir << "), (" << s.lms.first << ',' << s.lms.second << "), " << s.cost << ']';
00352 return ss.str();
00353 }
00354
00355 std::ostream& operator<<(std::ostream& out, const PathPlanner::direction& d) {
00356 switch (d) {
00357 case PathPlanner::direction::N: out << "N"; break;
00358 case PathPlanner::direction::W: out << "W"; break;
00359 case PathPlanner::direction::S: out << "S"; break;
00360 default: out << "E"; break;
00361 };
00362 return out;
00363 }
00364
00365
00366 }