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