00001 #include "WaypointEngine.h"
00002 #include "Shared/mathutils.h"
00003
00004 void WaypointEngine::go() {
00005 isRunning=true;
00006 for(unsigned int i=0; i<3; i++) {
00007 curVel[i]=0;
00008 pathStartPos[i]=sourcePos[i]=curPos[i];
00009 }
00010 curWaypoint=waypoints.begin();
00011 if ( waypoints.empty() )
00012 return;
00013 Waypoint target(curPos[0],curPos[1],Waypoint::POSTYPE_ABSOLUTE,curPos[2],false,0,isTracking,defaultTurnSpeed);
00014 target.apply(waypoints.front(),eps);
00015 targetPos[0]=target.x;
00016 targetPos[1]=target.y;
00017 targetPos[2]=target.angle;
00018 lastUpdateTime=get_time();
00019 setTargetWaypoint(curWaypoint);
00020 }
00021
00022 void WaypointEngine::pause() {
00023
00024 isRunning=false;
00025 }
00026
00027 void WaypointEngine::unpause() {
00028 if(curWaypoint==waypoints.end())
00029 go();
00030 isRunning=true;
00031 for(unsigned int i=0; i<3; i++)
00032 curVel[i]=0;
00033 lastUpdateTime=get_time();
00034 }
00035
00036 bool WaypointEngine::cycle() {
00037 if(!isRunning)
00038 return false;
00039
00040 unsigned int curtime=get_time();
00041 if(curWaypoint!=waypoints.end()) {
00042 computeCurrentPosition(curtime);
00043 checkNextWaypoint(curtime);
00044 }
00045 if(curWaypoint!=waypoints.end()) {
00046 computeIdeal(curtime);
00047 computeNewVelocity(curtime);
00048 }
00049
00050 return true;
00051 }
00052
00053 #ifdef TGT_IS_CREATE
00054 float WaypointEngine::tgtCreateTurnFudgeFactor(float angle) {
00055 float fudge;
00056 float thresholds[4] = {0.0, 2.5, 5.0, 10.0};
00057 float scales[4] = {0.0, 0.039, 0.051, 0.06};
00058 float degAngle = fabs(angle * 180.0/M_PI);
00059
00060 bool found = false;
00061 for(unsigned int i = 1; i < 4; i++) {
00062 if(degAngle >= thresholds[i-1] && degAngle < thresholds[i]) {
00063 if((i-1) != 0)
00064 fudge = ((scales[i] - scales[i-1])/(thresholds[i]-thresholds[i-1]))*degAngle + (2 * scales[i-1]) - scales[i];
00065 else
00066 fudge = ((scales[i] - scales[i-1])/(thresholds[i]-thresholds[i-1]))*degAngle;
00067 found = true;
00068 }
00069 }
00070
00071 if(!found)
00072 fudge = scales[3];
00073
00074 if(angle <= 0)
00075 fudge *= -1;
00076
00077 return fudge;
00078 }
00079 #endif
00080
00081 float WaypointEngine::fudgedAngle(float originalAngle) {
00082 #ifdef TGT_IS_CREATE
00083 return originalAngle + tgtCreateTurnFudgeFactor(originalAngle);
00084 #else
00085 return originalAngle;
00086 #endif
00087 }
00088
00089 void WaypointEngine::addEgocentricWaypoint(float forward, float left, float angle, bool angleIsRelative, float fwdSpeed, float turnSpeed) {
00090 waypoints.push_back(Waypoint(forward,left,Waypoint::POSTYPE_EGOCENTRIC,fudgedAngle(angle),angleIsRelative,fwdSpeed,isTracking,turnSpeed>=0?turnSpeed:defaultTurnSpeed));
00091 }
00092
00093
00094 void WaypointEngine::setTargetWaypoint(WaypointListIter_t iter) {
00095
00096 bool isLoop=false;
00097 if(iter==waypoints.end()) {
00098 if(isLooping && waypoints.size()>0) {
00099 iter=waypoints.begin();
00100 for(unsigned int i=0; i<3; i++)
00101 pathStartPos[i]=curPos[i];
00102 isLoop=true;
00103 } else {
00104 isRunning=false;
00105 curWaypoint=iter;
00106 for(unsigned int i=0; i<3; i++) {
00107 sourcePos[i]=targetPos[i];
00108 targetPos[i]=curPos[i];
00109 curVel[i]=0;
00110 }
00111 return;
00112 }
00113 }
00114 if(iter== (iter+1) || isLoop)
00115 for(unsigned int i=0; i<3; i++)
00116 sourcePos[i]=targetPos[i];
00117 else
00118 for(unsigned int i=0; i<3; i++)
00119 sourcePos[i]=curPos[i];
00120
00121 Waypoint target;
00122 if(isLoop)
00123 target=calcAbsoluteCoords(iter,pathStartPos[0],pathStartPos[1],pathStartPos[2]);
00124 else
00125 target=calcAbsoluteCoords(iter);
00126 targetPos[0]=target.x;
00127 targetPos[1]=target.y;
00128 targetPos[2]=target.angle;
00129
00130 float dx=targetPos[0]-sourcePos[0];
00131 float dy=targetPos[1]-sourcePos[1];
00132 waypointDistance=std::sqrt(dx*dx+dy*dy);
00133 waypointTime=get_time();
00134 curWaypoint=iter;
00135 float radiusRatio=std::sin(target.arc/2);
00136 arcRadius = (radiusRatio==0) ? 0 : (waypointDistance/2)/radiusRatio;
00137 pathLength = arcRadius!=0 ? arcRadius*target.arc : waypointDistance;
00138
00139
00140
00141 }
00142
00143
00144 unsigned int WaypointEngine::getBinSize() const {
00145 unsigned int numPrecision=9;
00146 unsigned int wpSize=0;
00147 unsigned int boilerplateSize=0;
00148 boilerplateSize+=strlen("#WyP\n");
00149 boilerplateSize+=strlen("#add_{point|arc} {ego|off|abs} x_val y_val {hold|follow} angle_val speed_val arc_val\n");
00150 wpSize+=strlen("max_turn_speed ")+numPrecision+1;
00151 wpSize+=strlen("track_path false\n");
00152 wpSize+=strlen("add_point ")+4+numPrecision*5+1*5+strlen("follow");
00153 boilerplateSize+=strlen("#END\n");
00154 return wpSize*waypoints.size()+boilerplateSize;
00155 }
00156
00157 unsigned int WaypointEngine::loadBuffer(const char buf[], unsigned int len, const char* filename) {
00158 unsigned int origlen=len;
00159 waypoints.clear();
00160 if(strncmp("#WyP\n",buf,5)!=0 && strncmp("#WyP\r",buf,5)!=0) {
00161 return 0;
00162 }
00163
00164 float turn=defaultTurnSpeed;
00165 bool track=isTracking;
00166 char cmd[40];
00167 char posType[40];
00168 float x_val=0;
00169 float y_val=0;
00170 char angType[40];
00171 bool ang_val=0;
00172 float angle_val=0;
00173 float speed_val=0;
00174 float arc_val=0;
00175 unsigned int linenum=1;
00176 while(len<=origlen && len>0) {
00177
00178 if(buf[0]=='\r') {
00179 buf++; len--;
00180 if(buf[0]=='\n') {
00181 buf++; len--;
00182 }
00183 linenum++;
00184 continue;
00185 }
00186 if(buf[0]=='\n') {
00187 buf++; len--;
00188 linenum++;
00189 continue;
00190 }
00191 if(buf[0]=='#') {
00192 if(strncmp("#END\n",buf,5)==0 || strncmp("#END\r",buf,5)==0) {
00193 return origlen-len+5;
00194 } else if(strncmp("#END\r\n",buf,6)==0) {
00195 return origlen-len+6;
00196 } else {
00197 while(len>0 && *buf!='\n' && *buf!='\r') {len--;buf++;}
00198 if(*buf=='\n') {
00199 buf++;
00200 len--;
00201 }
00202 linenum++;
00203 continue;
00204 }
00205 }
00206 int used=-1U;
00207 sscanf(buf,"%40s%n",cmd,&used);
00208 if(!checkInc(used,buf,len,"*** ERROR Waypoint list load corrupted - ran out of room line %d\n",linenum)) return 0;
00209 if(strncasecmp(cmd,"add_point",9)==0 || strncasecmp(cmd,"add_arc",7)==0) {
00210 sscanf(buf,"%40s %g %g %40s %g %g %g%n",posType,&x_val,&y_val,angType,&angle_val,&speed_val,&arc_val,&used);
00211 if(!checkInc(used,buf,len,"*** ERROR Waypoint list load corrupted - bad read on add at line %d\n",linenum)) return 0;
00212 if(strncasecmp(angType,"hold",4)==0)
00213 ang_val=false;
00214 else if(strncasecmp(angType,"follow",6)==0)
00215 ang_val=true;
00216 else {
00217 printf("*** ERROR WaypointEngine: Invalid angle value type %s\n",angType);
00218 return 0;
00219 }
00220 if(strncasecmp(cmd,"add_point",9)==0) {
00221 if(strncasecmp(posType,"ego",3)==0)
00222 addEgocentricWaypoint(x_val,y_val,angle_val,ang_val,speed_val);
00223 else if(strncasecmp(posType,"off",3)==0)
00224 addOffsetWaypoint(x_val,y_val,angle_val,ang_val,speed_val);
00225 else if(strncasecmp(posType,"abs",3)==0)
00226 addAbsoluteWaypoint(x_val,y_val,angle_val,ang_val,speed_val);
00227 else {
00228 printf("*** ERROR WaypointEngine: Invalid position type %s\n",posType);
00229 return 0;
00230 }
00231 waypoints.back().arc=arc_val;
00232 } else {
00233 if(strncasecmp(posType,"ego",3)==0)
00234 addEgocentricArc(x_val,y_val,angle_val,ang_val,speed_val,arc_val);
00235 else if(strncasecmp(posType,"off",3)==0)
00236 addOffsetArc(x_val,y_val,angle_val,ang_val,speed_val,arc_val);
00237 else if(strncasecmp(posType,"abs",3)==0)
00238 addAbsoluteArc(x_val,y_val,angle_val,ang_val,speed_val,arc_val);
00239 else {
00240 printf("*** ERROR WaypointEngine: Invalid position type %s\n",posType);
00241 return 0;
00242 }
00243 }
00244 waypoints.back().trackPath=track;
00245 waypoints.back().turnSpeed=turn;
00246 } else if(strncasecmp(cmd,"track_path",10)==0) {
00247 int track_tmp;
00248 sscanf(buf,"%d%n",&track_tmp,&used);
00249 track=track_tmp;
00250 if(!checkInc(used,buf,len,"*** ERROR Waypoint load corrupted - bad read on track_path line %d\n",linenum)) return 0;
00251 } else if(strncasecmp(cmd,"max_turn_speed",14)==0) {
00252 sscanf(buf,"%g%n",&turn,&used);
00253 if(!checkInc(used,buf,len,"*** ERROR Waypoint load corrupted - bad read on max_turn_speed line %d\n",linenum)) return 0;
00254 } else {
00255 printf("*** ERROR WaypointEngine: Invalid command %s\n",cmd);
00256 return 0;
00257 }
00258
00259 linenum++;
00260 }
00261 std::cout << "*** WARNING WaypointEngine: load missing #END" << std::endl;
00262 return origlen-len;
00263 }
00264
00265 unsigned int WaypointEngine::saveBuffer(char buf[], unsigned int len) const {
00266 unsigned int origLen=len;
00267 unsigned int used;
00268 unsigned int cnt=0;
00269
00270 used=snprintf(buf,len,"#WyP\n");
00271 if(!checkInc(used,buf,len,"*** ERROR Waypoint list save failed on header\n")) return 0;
00272
00273 used=snprintf(buf,len,"#add_{point|arc} {ego|off|abs} x_val y_val {hold|follow} angle_val speed_val arc_val\n");
00274 if(!checkInc(used,buf,len,"*** ERROR Waypoint list save failed on header\n")) return 0;
00275
00276
00277 float turn=waypoints.front().turnSpeed-1;
00278 bool track=!waypoints.front().trackPath;
00279
00280 for(WaypointListConstIter_t it=waypoints.begin(); it!=waypoints.end(); it++) {
00281 if(it->turnSpeed!=turn) {
00282 turn=it->turnSpeed;
00283 used=snprintf(buf,len,"max_turn_speed %g\n",turn);
00284 if(!checkInc(used,buf,len,"*** ERROR Waypoint list save failed on waypoint %d turnSpeed\n",cnt)) return 0;
00285 }
00286 if(it->trackPath!=track) {
00287 track=it->trackPath;
00288 used=snprintf(buf,len,"track_path %d\n",track);
00289 if(!checkInc(used,buf,len,"*** ERROR Waypoint list save failed on waypoint %d\n trackPath",cnt)) return 0;
00290 }
00291 const char * posType=NULL;
00292 switch(it->posType) {
00293 case Waypoint::POSTYPE_EGOCENTRIC:
00294 posType="EGO"; break;
00295 case Waypoint::POSTYPE_OFFSET:
00296 posType="OFF"; break;
00297 case Waypoint::POSTYPE_ABSOLUTE:
00298 posType="ABS"; break;
00299 }
00300 if(it->arc!=0)
00301 used=snprintf(buf,len,"add_point %s %g %g %s %g %g %g\n",posType,it->x,it->y,(it->angleIsRelative?"FOLLOW":"HOLD"),it->angle,it->speed,it->arc);
00302 else
00303 used=snprintf(buf,len,"add_point %s %g %g %s %g %g %g\n",posType,it->x,it->y,(it->angleIsRelative?"FOLLOW":"HOLD"),it->angle,it->speed,it->arc);
00304 if(!checkInc(used,buf,len,"*** ERROR Waypoint list save failed on waypoint %d\n",cnt)) return 0;
00305 cnt++;
00306 }
00307
00308 used=snprintf(buf,len,"#END\n");
00309 if(!checkInc(used,buf,len,"*** ERROR Waypoint list save failed on footer\n")) return 0;
00310
00311 return origLen-len;
00312 }
00313
00314 void WaypointEngine::init() {
00315 eps[0]=eps[1]= 5.0f;
00316 eps[2]=0.0175f;
00317 for(unsigned int i=0; i<3; i++)
00318 pathStartPos[i]=targetPos[i]=sourcePos[i]=curPos[i]=curVel[i]=0;
00319 for(unsigned int i=0; i<4; i++)
00320 idealPos[i]=0;
00321 }
00322
00323
00324 void WaypointEngine::fixArc(float arc) {
00325 Waypoint& center=waypoints.back();
00326 float cdx=center.x;
00327 float cdy=center.y;
00328 if(center.posType==Waypoint::POSTYPE_ABSOLUTE) {
00329
00330 if(waypoints.size()<=1) {
00331 cdx-=pathStartPos[0];
00332 cdy-=pathStartPos[1];
00333 } else {
00334 Waypoint start=calcAbsoluteCoords(waypoints.end()-2);
00335 cdx-=start.x;
00336 cdy-=start.y;
00337 }
00338 }
00339 float r=std::sqrt(cdx*cdx+cdy*cdy);
00340 float ca=std::atan2(cdy,cdx);
00341 center.x-=r*std::cos(ca-arc);
00342 center.y-=r*std::sin(ca-arc);
00343 center.arc=arc;
00344 }
00345
00346 void WaypointEngine::computeCurrentPosition(unsigned int t) {
00347 float dt=(t-lastUpdateTime)/1000.f;
00348 float df=dt*curVel[0];
00349 float ds=dt*curVel[1];
00350 float da=dt*curVel[2];
00351
00352 float avgAngle=curPos[2]+da/2;
00353 float ca=std::cos(avgAngle);
00354 float sa=std::sin(avgAngle);
00355
00356 curPos[0]+=df*ca-ds*sa;
00357 curPos[1]+=df*sa+ds*ca;
00358 curPos[2]+=da;
00359 curPos[2]=mathutils::normalizeAngle(curPos[2]);
00360
00361 lastUpdateTime=t;
00362 }
00363
00364 void WaypointEngine::checkNextWaypoint(unsigned int ) {
00365 float rx=targetPos[0]-curPos[0];
00366 float ry=targetPos[1]-curPos[1];
00367 float ra=targetPos[2]-curPos[2];
00368 if(fabs(rx)<eps[0] && fabs(ry)<eps[1] && fabs(ra)<eps[2]) {
00369 setTargetWaypoint(curWaypoint+1);
00370 }
00371 }
00372
00373 void WaypointEngine::computeIdeal(unsigned int t) {
00374 Waypoint& cur=(*curWaypoint);
00375 if(cur.trackPath) {
00376 float dx=targetPos[0]-sourcePos[0];
00377 float dy=targetPos[1]-sourcePos[1];
00378
00379 float dt=(t-waypointTime)/1000.f;
00380 float ideal_travel=dt*cur.speed;
00381 float p=1;
00382 if(pathLength!=0) {
00383 p=ideal_travel/pathLength;
00384 if(p>1)
00385 p=1;
00386 }
00387 if(arcRadius==0) {
00388 idealPos[0]=sourcePos[0]+dx*p;
00389 idealPos[1]=sourcePos[1]+dy*p;
00390 idealPos[2]=targetPos[2];
00391 idealPos[3]=std::atan2(dy,dx);
00392 } else {
00393
00394 float bearing=std::atan2(dy,dx);
00395 float center_bearing=bearing+((float)M_PI-cur.arc)/2;
00396 float cx=sourcePos[0]+arcRadius*std::cos(center_bearing);
00397 float cy=sourcePos[1]+arcRadius*std::sin(center_bearing);
00398 float arc_bearing=center_bearing-(float)M_PI+cur.arc*p;
00399
00400 idealPos[0]=cx+arcRadius*std::cos(arc_bearing);
00401 idealPos[1]=cy+arcRadius*std::sin(arc_bearing);
00402 idealPos[3]=arc_bearing+(float)M_PI/2;
00403 idealPos[2]=cur.angle;
00404 if(cur.angleIsRelative)
00405 idealPos[2]+=idealPos[3];
00406 idealPos[2]=mathutils::normalizeAngle(idealPos[2]);
00407 idealPos[3]=mathutils::normalizeAngle(idealPos[3]);
00408 }
00409 } else {
00410 idealPos[0]=curPos[0];
00411 idealPos[1]=curPos[1];
00412 float rx=targetPos[0]-curPos[0];
00413 float ry=targetPos[1]-curPos[1];
00414 if(std::abs(rx)<eps[0] && std::abs(ry)<eps[1]) {
00415 idealPos[2]=targetPos[2];
00416 } else {
00417 idealPos[2]=cur.angle;
00418 if(cur.angleIsRelative) {
00419 float dx=targetPos[0]-curPos[0];
00420 float dy=targetPos[1]-curPos[1];
00421 idealPos[2]+=std::atan2(dy,dx);
00422 }
00423 idealPos[2]=mathutils::normalizeAngle(idealPos[2]);
00424 }
00425 idealPos[3]=std::atan2(ry,rx);
00426 if(arcRadius!=0) {
00427
00428 float dt=(t-waypointTime)/1000.f;
00429 float ideal_travel=dt*cur.speed;
00430 float p=1;
00431 if(pathLength!=0) {
00432 p=ideal_travel/pathLength;
00433 if(p>1)
00434 p=1;
00435 }
00436 float arc=cur.arc*(1-p)/2;
00437 idealPos[2]=mathutils::normalizeAngle(idealPos[2]-arc);
00438 idealPos[3]=mathutils::normalizeAngle(idealPos[3]-arc);
00439 }
00440 }
00441 }
00442
00443 void WaypointEngine::computeNewVelocity(unsigned int ) {
00444 Waypoint& cur=(*curWaypoint);
00445
00446
00447
00448 float dx=targetPos[0]-idealPos[0];
00449 float dy=targetPos[1]-idealPos[1];
00450 float spd=std::sqrt(dx*dx+dy*dy)/(FrameTime*NumFrames)*1000.f;
00451 if(spd>cur.speed) {
00452
00453 curVel[0]=cur.speed*std::cos(idealPos[3]-curPos[2]);
00454 curVel[1]=cur.speed*std::sin(idealPos[3]-curPos[2]);
00455 } else {
00456
00457 curVel[0]=spd*std::cos(idealPos[3]-curPos[2]);
00458 curVel[1]=spd*std::sin(idealPos[3]-curPos[2]);
00459 }
00460 if(arcRadius==0)
00461 curVel[2]=0;
00462 else
00463 curVel[2]=cur.speed/arcRadius;
00464
00465
00466
00467
00468 float ex=idealPos[0]-curPos[0];
00469 float ey=idealPos[1]-curPos[1];
00470 float ed=std::sqrt(ex*ex+ey*ey);
00471 float ehead=std::atan2(ey,ex)-curPos[2];
00472 float ea=mathutils::normalizeAngle(idealPos[2]-curPos[2]);
00473 float easpd=ea/(FrameTime*NumFrames)*1000.f;
00474 easpd=mathutils::limitRange(easpd,-cur.turnSpeed,cur.turnSpeed);
00475 curVel[0]+=Pcorr*ed*std::cos(ehead);
00476 curVel[1]+=Pcorr*ed*std::sin(ehead);
00477 curVel[2]+=easpd;
00478 }
00479
00480
00481
00482
00483