Main Page   Namespace List   Class Hierarchy   Compound List   File List   Compound Members   File Members  

WorldModelPredict.cpp

Go to the documentation of this file.
00001 /*
00002 Copyright (c) 2000-2003, Jelle Kok, University of Amsterdam
00003 All rights reserved.
00004 
00005 Redistribution and use in source and binary forms, with or without
00006 modification, are permitted provided that the following conditions are met:
00007 
00008 1. Redistributions of source code must retain the above copyright notice, this
00009 list of conditions and the following disclaimer.
00010 
00011 2. Redistributions in binary form must reproduce the above copyright notice,
00012 this list of conditions and the following disclaimer in the documentation
00013 and/or other materials provided with the distribution.
00014 
00015 3. Neither the name of the University of Amsterdam nor the names of its
00016 contributors may be used to endorse or promote products derived from this
00017 software without specific prior written permission.
00018 
00019 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00020 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00021 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00022 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
00023 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00024 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00025 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00026 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00027 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00028 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029 */
00030 
00047 #include <stdio.h>
00048 #include "WorldModel.h"
00049 
00050 /*****************************************************************************/
00051 /************************** PREDICTIONS **************************************/
00052 /*****************************************************************************/
00053 
00066 bool WorldModel::predictStateAfterCommand( SoccerCommand com,
00067     VecPosition *pos, VecPosition *vel, AngDeg *angGlobalBody,
00068     AngDeg *angGlobalNeck, ObjectT obj, Stamina *sta )
00069 {
00070   switch( com.commandType ) // based on kind of command, choose action
00071   {
00072     case CMD_DASH:
00073       predictStateAfterDash( com.dPower, pos, vel, sta, *angGlobalBody, obj );
00074       break;
00075     case CMD_TURN:
00076       predictStateAfterTurn( com.dAngle, pos, vel,
00077                              angGlobalBody, angGlobalNeck, obj, sta);
00078       break;
00079     case CMD_TURNNECK: // note that position and velocity are not updated
00080       *angGlobalNeck = VecPosition::normalizeAngle(*angGlobalNeck+com.dAngle);
00081       break;
00082     case CMD_KICK:
00083     case CMD_CATCH:
00084     case CMD_TACKLE:
00085       predictStateAfterDash( 0.0, pos, vel, sta, *angGlobalBody, obj );
00086       break;
00087     case CMD_MOVE:
00088       pos->setVecPosition( com.dX, com.dY );
00089       vel->setMagnitude( 0.0 );
00090       break;
00091     case CMD_ILLEGAL:
00092       predictStateAfterDash( 0.01, pos, vel, sta, *angGlobalBody, obj );
00093       break;
00094     default:
00095       return false;
00096   }
00097   return true;
00098 }
00099 
00110 bool WorldModel::predictAgentStateAfterCommand( SoccerCommand com,
00111     VecPosition *pos, VecPosition *vel, AngDeg *angGlobalBody,
00112     AngDeg *angGlobalNeck, Stamina *sta )
00113 {
00114   *pos           = getAgentGlobalPosition();
00115   *vel           = getAgentGlobalVelocity();
00116   *angGlobalBody = getAgentGlobalBodyAngle();
00117   *angGlobalNeck = getAgentGlobalNeckAngle();
00118   *sta           = getAgentStamina();
00119   predictStateAfterCommand( com, pos, vel, angGlobalBody, angGlobalNeck, 
00120                             getAgentObjectType(), sta );
00121 
00122   return true;
00123 }
00124 
00135 bool WorldModel::predictObjectStateAfterCommand( ObjectT obj,SoccerCommand com,
00136     VecPosition *pos, VecPosition *vel, AngDeg *angGlobalBody,
00137     AngDeg *angGlobalNeck, Stamina *sta )
00138 {
00139   if( obj == getAgentObjectType() )
00140     return predictAgentStateAfterCommand(
00141                com, pos, vel, angGlobalBody, angGlobalNeck, sta );
00142   *pos           = getGlobalPosition( obj );
00143   *vel           = getGlobalVelocity( obj );
00144   *angGlobalBody = getGlobalBodyAngle( obj  );
00145   *angGlobalNeck = getGlobalNeckAngle(obj );
00146   predictStateAfterCommand( com, pos, vel, angGlobalBody, angGlobalNeck, obj );
00147 
00148   return true;
00149 }
00150 
00156 VecPosition WorldModel::predictAgentPosAfterCommand( SoccerCommand com )
00157 {
00158   VecPosition p1, p2;
00159   AngDeg      a1, a2;
00160   Stamina     sta;
00161   predictAgentStateAfterCommand( com, &p1, &p2, &a1, &a2, &sta );
00162   return p1;
00163 }
00164 
00173 void WorldModel::predictStateAfterDash( double dActualPower, VecPosition *pos,
00174              VecPosition *vel, Stamina *sta, double dDirection, ObjectT obj )
00175 {
00176   // get acceleration associated with actualpower
00177   double dEffort = ( sta != NULL ) ? sta->getEffort() : getEffortMax( obj );
00178   double dAcc    = dActualPower * getDashPowerRate( obj ) * dEffort;
00179 
00180   // add it to the velocity; negative acceleration in backward direction
00181   if( dAcc > 0 )
00182     *vel += VecPosition::getVecPositionFromPolar( dAcc, dDirection );
00183   else
00184     *vel += VecPosition::getVecPositionFromPolar( fabs(dAcc),
00185         VecPosition::normalizeAngle(dDirection+180));
00186 
00187   // check if velocity doesn't exceed maximum speed
00188   if( vel->getMagnitude() > SS->getPlayerSpeedMax() )
00189     vel->setMagnitude( SS->getPlayerSpeedMax() );
00190 
00191   // add velocity to current global position and decrease velocity
00192   *pos += *vel;
00193   *vel *= getPlayerDecay(obj);
00194   if( sta != NULL )
00195     predictStaminaAfterDash( dActualPower, sta );
00196 }
00197 
00209 void WorldModel::predictStateAfterTurn( AngDeg dSendAngle, VecPosition *pos,
00210           VecPosition *vel, AngDeg *angBody, AngDeg *angNeck, ObjectT obj,
00211           Stamina *sta )
00212 {
00213   // calculate effective turning angle and neck accordingly
00214   double dEffectiveAngle;
00215   dEffectiveAngle = getActualTurnAngle( dSendAngle, vel->getMagnitude(), obj );
00216   *angBody = VecPosition::normalizeAngle( *angBody + dEffectiveAngle );
00217   *angNeck = VecPosition::normalizeAngle( *angNeck + dEffectiveAngle );
00218 
00219   // update as if dashed with no power
00220   predictStateAfterDash( 0.0, pos, vel, sta, *angBody, obj );
00221   return;
00222 }
00223 
00224 void WorldModel::predictBallInfoAfterCommand( SoccerCommand soc,
00225                   VecPosition *pos, VecPosition *vel )
00226 {
00227   VecPosition posBall = getGlobalPosition( OBJECT_BALL ) ;
00228   VecPosition velBall = getGlobalVelocity( OBJECT_BALL );
00229 
00230   if( soc.commandType == CMD_KICK )
00231   {
00232     int iAng   = (int)soc.dAngle;
00233     int iPower = (int)soc.dPower;
00234 
00235     // make angle relative to body
00236     // calculate added acceleration and add it to current velocity
00237     AngDeg ang = VecPosition::normalizeAngle(iAng+getAgentGlobalBodyAngle());
00238     velBall += VecPosition( getActualKickPowerRate()*iPower, ang, POLAR ) ;
00239     if( velBall.getMagnitude() > SS->getBallSpeedMax() )
00240       velBall.setMagnitude( SS->getBallSpeedMax() );
00241     Log.log( 600, "ang: %f kick_rate %f", ang, getActualKickPowerRate() );
00242     Log.log( 600, "update for kick: %f %f", soc.dPower, soc.dAngle );
00243   }  
00244 
00245   posBall += velBall;
00246   velBall *= SS->getBallDecay();
00247 
00248   if( pos != NULL )
00249     *pos = posBall;
00250   if( vel != NULL )
00251     *vel = velBall;
00252 }
00253 
00263 VecPosition WorldModel::predictPosAfterNrCycles( ObjectT o, double dCycles,
00264          int iDashPower, VecPosition *posIn, VecPosition *velIn, bool bUpdate )
00265 {
00266   VecPosition vel = ( velIn == NULL ) ? getGlobalVelocity( o ) : *velIn ;
00267   VecPosition pos = ( posIn == NULL ) ? getGlobalPosition( o ) : *posIn ;
00268 
00269   if( o == OBJECT_BALL )
00270   {
00271     // get the speed and the distance it travels in iCycle's.
00272     // use this distance and direction it travels in, to calculate new pos
00273     // geom series is serie s=a+ar+..+ar^n...decay=r,iCycles=n,dSpeed=a
00274     double dDist = Geometry::getSumGeomSeries( vel.getMagnitude(),
00275                                                SS->getBallDecay(),
00276                                                dCycles);
00277     pos          += VecPosition( dDist, vel.getDirection(), POLAR );
00278     vel          *= pow( SS->getBallDecay(), dCycles );
00279   }
00280   else if( SoccerTypes::isKnownPlayer( o )  )
00281   {
00282     double      dDirection = 0.0; // used when no info about global body
00283     Stamina     stamina;          // used when object is agent
00284 
00285     if( getAgentObjectType() == o )
00286     {
00287       dDirection = getAgentGlobalBodyAngle();
00288       stamina    = getAgentStamina();
00289     }
00290     else if( getTimeGlobalAngles(o) > getCurrentTime() - 2 )
00291       dDirection = getGlobalBodyAngle(o);
00292 
00293     for( int i = 0; i < (int)dCycles ; i ++ )
00294       predictStateAfterDash( iDashPower, &pos, &vel, &stamina, dDirection, o );
00295   }
00296 
00297   if( posIn != NULL && bUpdate )
00298     *posIn = pos;
00299   if( velIn != NULL && bUpdate )
00300     *velIn = vel;
00301 
00302   return pos;
00303 }
00304 
00311 VecPosition WorldModel::predictAgentPos( int iCycles, int iDashPower )
00312 {
00313   return predictPosAfterNrCycles( getAgentObjectType(), iCycles, iDashPower);
00314 }
00315 
00319 VecPosition WorldModel::predictFinalAgentPos(VecPosition *pos,VecPosition *vel)
00320 {
00321   VecPosition velAgent   = (vel==NULL) ? getAgentGlobalVelocity (): *vel;
00322   VecPosition posAgent   = (pos==NULL) ? getAgentGlobalPosition (): *pos;
00323   double      dDistExtra =
00324    Geometry::getSumInfGeomSeries(velAgent.getMagnitude(),SS->getPlayerDecay());
00325   return posAgent + VecPosition(dDistExtra,velAgent.getDirection(), POLAR );
00326 
00327 }
00328 
00331 int WorldModel::predictNrCyclesForDistance ( ObjectT o, double dDist,
00332                                              double dSpeed )
00333 {
00334   double dSpeedPrev = -1.0;
00335   int    iCycles    = 0;
00336   double dDecay     = getPlayerDecay( o );
00337   double dDashRate  = getDashPowerRate( o );
00338   double dMinDist   = getMaximalKickDist( o );
00339 
00340   // stop this loop when max speed is reached or the distance is traveled.
00341   while( dDist > dMinDist &&
00342          (fabs(dSpeed - dSpeedPrev) > EPSILON || dSpeed < 0.3 ) &&
00343          iCycles < 40 ) // ignore standing still and turning
00344   {
00345     dSpeedPrev = dSpeed;
00346     dSpeed    += SS->getMaxPower()*dDashRate;
00347     if( dSpeed > SS->getPlayerSpeedMax() )
00348       dSpeed = SS->getPlayerSpeedMax();
00349     dDist = max( 0, dDist - dSpeed );
00350     dSpeed *= dDecay;
00351     iCycles++;
00352   }
00353   dSpeed /= dDecay;
00354   
00355   // if distance not completely traveled yet, count the number of cycles to 
00356   // travel the remaining distance with this speed.
00357   if( dDist > dMinDist  )
00358    iCycles += (int)ceil(( dDist - dMinDist )/dSpeed);
00359   return max(0, iCycles ) ;
00360 }
00361 
00362 
00371 int WorldModel::predictNrCyclesToPoint( ObjectT o, VecPosition posTo )
00372 {
00373   char          strBuf[128];
00374   VecPosition   posGlobal = getGlobalPositionLastSee( o ), posPred;
00375   VecPosition   vel;
00376   int           iCycles;
00377   AngDeg        angBody, angNeck = 0, ang;
00378   AngDeg        angDes = (posTo-posGlobal).getDirection();
00379   SoccerCommand soc;
00380 
00381   Log.log( 460, "predict steps for %s with dist %f (time %d) and body %f (%d)",
00382               SoccerTypes::getObjectStr( strBuf, o ),
00383               posTo.getDistanceTo( posGlobal ),
00384               getTimeGlobalPositionLastSee( o ).getTime(),
00385               getGlobalBodyAngle(o), getTimeChangeInformation(o).getTime() );
00386 
00387   // if already in kickable distance, return 0
00388   if( posTo.getDistanceTo( posGlobal ) < getMaximalKickDist( o) )
00389   {
00390     Log.log( 460, "already close: 0" );
00391     return 0;
00392   }
00393 
00394   // first check how old the change info (and thus body and vel.) info is
00395   // if too old, assume information is perfect and set time to position info
00396   // otherwise update all information with stored information
00397   iCycles = getTimeChangeInformation(o).getTime() - getCurrentCycle();
00398   if( o == getAgentObjectType() )
00399   {
00400     angBody = getAgentGlobalBodyAngle();
00401     vel     = getAgentGlobalVelocity( );
00402     posPred = getAgentGlobalPosition( );
00403     iCycles = 0;
00404   }
00405   else if( iCycles < -3 )
00406   {
00407     angBody = angDes;
00408     vel.setVecPosition( 0.3, angDes, POLAR );
00409     if( SoccerTypes::isOpponent( o ) )
00410       iCycles = -2; // otherwise too optimistic
00411     else
00412       iCycles = 0;
00413     posPred = getGlobalPositionLastSee( o );
00414   }
00415   else
00416   {
00417     angBody = getGlobalBodyAngleLastSee( o );
00418     vel     = getGlobalVelocityLastSee( o );
00419     posPred = getGlobalPositionLastSee( o );
00420   }
00421 
00422   Log.log( 460, "rel. time angle info (des %f,now %f,speed %f): %d (%d-%d)",
00423        angDes, angBody, vel.getMagnitude(), iCycles,
00424        getTimeChangeInformation(o).getTime(), getCurrentCycle() );
00425 
00426   if( o != getAgentObjectType() &&
00427       getTimeGlobalPositionLastSee( o ) > getTimeChangeInformation(o) )
00428   {
00429     Log.log( 460, "update cycles to global pos. time: %d",
00430                   getTimeGlobalPositionLastSee( o ).getTime() );
00431     iCycles = max(iCycles,
00432                   getTimeGlobalPositionLastSee(o).getTime()-getCurrentCycle());
00433   }
00434 
00435   soc = predictCommandToMoveToPos(o,posTo,1,2.5,false,&posPred,&vel,&angBody );
00436   ang = VecPosition::normalizeAngle( angBody - angDes );
00437 
00438   // sometimes we dash to stand still and turn then
00439   while( soc.commandType == CMD_TURN ||
00440          ( fabs( ang ) > 20 && soc.commandType == CMD_DASH && soc.dPower < 0 ))
00441   {
00442     iCycles++;
00443     predictStateAfterCommand( soc, &posPred, &vel, &angBody, &angNeck, o );
00444     if( posTo.getDistanceTo( posPred ) < getMaximalKickDist( o ) )
00445     {
00446       Log.log( 460, "reached point during turning, vel %f: %d",
00447                         vel.getMagnitude(), iCycles );
00448       return iCycles;
00449     }
00450     soc=predictCommandToMoveToPos(o,posTo,1,2.5,false,&posPred,&vel,&angBody );
00451     ang = VecPosition::normalizeAngle( angBody - angDes );
00452   }
00453   Log.log( 460, "cycles after turning: %d (ang %f, %f) vel %f", 
00454            iCycles, ang, angDes, vel.getMagnitude() );
00455 
00456   if( o != getAgentObjectType() )
00457   {
00458     // iCycles++; // do not count last dash -> predictState not called
00459     double dVel = vel.rotate(-angBody).getX(); // get distance in direction
00460     iCycles += predictNrCyclesForDistance(o,posPred.getDistanceTo(posTo),dVel);
00461   }
00462   else
00463   {
00464     while( posPred.getDistanceTo( posTo ) > getMaximalKickDist( o ) )
00465     {
00466       soc=predictCommandToMoveToPos(o,posTo,1,2.5,0,&posPred,&vel,&angBody);
00467       predictStateAfterCommand( soc, &posPred, &vel, &angBody, &angNeck, o );  
00468       iCycles++;
00469     }
00470   }
00471 
00472   Log.log( 460, "total cycles: %d", iCycles );
00473   return iCycles;
00474 }
00475 
00481 int WorldModel::predictNrCyclesToObject( ObjectT objFrom, ObjectT objTo )
00482 {
00483   VecPosition posPrev(UnknownDoubleValue,UnknownDoubleValue);
00484 
00485   if( objFrom == OBJECT_ILLEGAL || objTo == OBJECT_ILLEGAL ||
00486       getGlobalPosition( objFrom ).getDistanceTo( getGlobalPosition( objTo )
00487       ) > 40 )
00488     return 101;
00489 
00490   // this is part of the intercept
00491   if( objFrom == getAgentObjectType() && objTo == OBJECT_BALL )
00492   {
00493      FeatureT  feature_type = FEATURE_INTERCEPT_CYCLES_ME;  
00494      if( isFeatureRelevant( feature_type ) )
00495      {
00496        return max(0,
00497              ((int)getFeature( feature_type ).getInfo() - getCurrentCycle() ));
00498      }
00499      else
00500      {
00501        Log.log( 460, "create intercept features" );
00502        createInterceptFeatures( );
00503        Log.log( 460, "call predict again" );
00504        return predictNrCyclesToObject( objFrom, objTo );
00505      }
00506   }
00507 
00508   // in case of ball with no velocity, calculate cycles to point
00509   if( objTo == OBJECT_BALL && getBallSpeed() < 0.01 )
00510     return predictNrCyclesToPoint( objFrom, getBallPos() );
00511 
00512   int         iCycles      = 0;
00513   int         iCyclesToObj = 100;
00514   VecPosition posObj(0,0);
00515 
00516   // continue calculating number of cycles to position until or we can get
00517   // earlier at object position, are past maximum allowed number of cycles or
00518   // the object does not move anymore.
00519   while( iCycles <= iCyclesToObj && iCycles < PS->getPlayerWhenToIntercept() &&
00520          posObj.getDistanceTo( posPrev ) > EPSILON )
00521   {
00522     iCycles      = iCycles + 1  ;
00523     posPrev      = posObj;
00524     posObj       = predictPosAfterNrCycles( objTo,   iCycles );
00525 
00526     if(getGlobalPosition(objFrom).getDistanceTo(posObj)/SS->getPlayerSpeedMax()
00527               < iCycles + 1 )
00528     {
00529       Log.log( 460, "predictNrCyclesToPoint after %d cycles", iCycles );
00530       iCyclesToObj = predictNrCyclesToPoint ( objFrom, posObj );
00531     }
00532   }
00533 
00534   return iCyclesToObj;
00535 }
00536 
00543 void WorldModel::predictStaminaAfterDash( double dPower, Stamina *stamina )
00544 {
00545   double sta = stamina->getStamina();
00546   double eff = stamina->getEffort();
00547   double rec = stamina->getRecovery();
00548 
00549   // double negative value when dashed backwards
00550   sta -= ( dPower > 0.0 ) ? dPower : -2*dPower ;
00551   if( sta < 0 ) sta = 0;
00552 
00553   // stamina below recovery threshold, lower recovery
00554   if( sta <= SS->getRecoverDecThr()*SS->getStaminaMax() &&
00555                          rec > SS->getRecoverMin() )
00556       rec -= SS->getRecoverDec();
00557 
00558   // stamina below effort decrease threshold, lower effort
00559   if( sta <= SS->getEffortDecThr()*SS->getStaminaMax() &&
00560                    eff > SS->getEffortMin() )
00561       eff -= SS->getEffortDec();
00562 
00563   // stamina higher than effort incr threshold, raise effort and check maximum
00564   if( sta >= SS->getEffortIncThr() * SS->getStaminaMax() &&
00565       eff < 1.0)
00566   {
00567     eff += SS->getEffortInc();
00568     if ( eff > 1.0 )
00569        eff = 1.0;
00570   }
00571 
00572   // increase stamina with (new) recovery value and check for maximum
00573   sta += rec*SS->getStaminaIncMax();
00574   if ( sta > SS->getStaminaMax() )
00575     sta = SS->getStaminaMax();
00576 
00577   stamina->setStamina ( sta );
00578   stamina->setEffort  ( eff );
00579   stamina->setRecovery( rec );
00580 }
00581 
00588 SoccerCommand WorldModel::predictCommandTurnTowards( ObjectT obj, VecPosition
00589   posTo, int iCycles, double dDistBack, bool bMoveBack,
00590   VecPosition *posIn, VecPosition *velIn, AngDeg *angBodyIn )
00591 {
00592   SoccerCommand soc, socFirst;
00593   VecPosition   pos, vel;
00594   AngDeg        angBody, ang, angNeck, angTo;
00595   Stamina       sta;
00596   bool          bFirst = true;
00597 
00598   // fill in all values
00599   angBody = ( angBodyIn == NULL ) ? getGlobalBodyAngle( obj ) : *angBodyIn;
00600   pos     = ( posIn     == NULL ) ? getGlobalPosition ( obj ) : *posIn;
00601   vel     = ( velIn     == NULL ) ? getGlobalVelocity ( obj ) : *velIn;
00602   angNeck = getGlobalNeckAngle( obj );
00603 
00604   // predict where we will finally stand when our current vel is propogated
00605   // and then check the orthogonal distance w.r.t. our body direction
00606   VecPosition posPred=predictPosAfterNrCycles( obj, min(iCycles,4),
00607                                                0, &pos, &vel, false );
00608   Line        line   =Line::makeLineFromPositionAndAngle( posPred, angBody );
00609   double      dDist  =line.getDistanceWithPoint( posTo );
00610 
00611   // get the angle to this point
00612   angTo = (posTo - posPred).getDirection();
00613   angTo = VecPosition::normalizeAngle( angTo - angBody );
00614 
00615   // determine whether we want to turn based on orthogonal distance 
00616   double dRatioTurn;
00617   if( pos.getDistanceTo(posTo) > 30.0 ) 
00618     dRatioTurn = 4.0;  
00619   if( pos.getDistanceTo(posTo) > 20.0 ) 
00620     dRatioTurn = 3.0;  
00621   else if( pos.getDistanceTo(posTo) > 10 ) 
00622     dRatioTurn = 2.0;
00623   else
00624     dRatioTurn = 0.90 ;
00625 
00626   AngDeg angTmp = angTo + (bMoveBack) ? 180 : 0;
00627   angTmp = VecPosition::normalizeAngle( angTmp );
00628   
00629   // turn when: 
00630   //  1. point lies outside our body range (forward and backwards)
00631   //  2. point lies outside distBack and behind us (forward move) 
00632   //  3. point lies outside distBack and in front of us backwards move)
00633   int    turn = 0;
00634   while( ( dDist > dRatioTurn*getMaximalKickDist( obj ) ||
00635           ( posPred.getDistanceTo( posTo ) > dDistBack && 
00636               ( ( fabs( angTo ) > 90 && bMoveBack == false  ) ||
00637                 ( fabs( angTo ) < 90 && bMoveBack == true ) ) ) )
00638          && turn < 5 && fabs( angTmp ) > PS->getPlayerWhenToTurnAngle() )
00639   {
00640 
00641      ang = (posTo - posPred).getDirection() + (( bMoveBack == true )?180:0);
00642      ang = VecPosition::normalizeAngle( ang - angBody );
00643      soc = SoccerCommand(CMD_TURN,getAngleForTurn(ang,vel.getMagnitude(),obj));
00644      Log.log( 468, "angTo %f, dDist %f, ang %f %d angBody %f soc %f vel %f %f",
00645               angTo, dDist, ang, obj, angBody, soc.dAngle, vel.getMagnitude(),
00646               getInertiaMoment( obj ));
00647      if( bFirst == true )
00648        socFirst = soc;
00649      bFirst = false;
00650      predictStateAfterTurn(soc.dAngle, &pos, &vel, &angBody,&angNeck,obj,&sta);
00651      line = Line::makeLineFromPositionAndAngle( posPred, angBody );
00652      dDist = line.getDistanceWithPoint( posTo );
00653      angTo = (posTo - posPred).getDirection();
00654      angTo = VecPosition::normalizeAngle( angTo - angBody );
00655      turn++;
00656   }
00657 
00658   // if very close and have to turn a lot, it may be better to move with our
00659   // back to that point
00660   if( turn > 1 && iCycles < 4 && posPred.getDistanceTo( posTo ) < dDistBack &&
00661       bMoveBack == false)
00662   {
00663      angBody = ( angBodyIn == NULL ) ? getGlobalBodyAngle( obj ) : *angBodyIn;
00664      pos     = ( posIn     == NULL ) ? getGlobalPosition ( obj ) : *posIn;
00665      vel     = ( velIn     == NULL ) ? getGlobalVelocity ( obj ) : *velIn;
00666      ang = (posTo - posPred).getDirection() + 180;
00667      ang = VecPosition::normalizeAngle( ang - angBody );
00668      soc = SoccerCommand(CMD_TURN,getAngleForTurn(ang,vel.getMagnitude(),obj));
00669      predictStateAfterTurn( soc.dAngle,&pos,&vel,&angBody,&angNeck,obj,&sta);
00670      line = Line::makeLineFromPositionAndAngle( posPred, angBody );
00671      dDist = line.getDistanceWithPoint( posTo );
00672      if( dDist < 0.9*getMaximalKickDist( obj )  )
00673      {
00674        Log.log( 463, "turn around and intercept with back" );
00675        return soc;
00676      }
00677   }
00678 
00679   return socFirst;
00680 }
00681 
00686 SoccerCommand WorldModel::predictCommandToMoveToPos( ObjectT obj, 
00687   VecPosition posTo, int iCycles, double dDistBack, 
00688   bool bMoveBack,VecPosition *posIn, VecPosition *velIn, AngDeg *angBodyIn)
00689 {
00690   VecPosition   pos, vel;
00691   AngDeg        angBody;
00692   SoccerCommand soc;
00693   double        dPower;
00694 
00695   // fill in all values
00696   angBody = ( angBodyIn == NULL ) ? getGlobalBodyAngle( obj ) : *angBodyIn;
00697   pos     = ( posIn     == NULL ) ? getGlobalPosition ( obj ) : *posIn;
00698   vel     = ( velIn     == NULL ) ? getGlobalVelocity ( obj ) : *velIn;
00699 
00700   soc = predictCommandTurnTowards(obj, posTo, iCycles, dDistBack, bMoveBack,
00701                                        posIn, velIn,   angBodyIn);
00702   if( ! soc.isIllegal() )
00703     return soc;
00704 
00705   dPower = getPowerForDash( posTo-pos, angBody, vel,getAgentEffort(),iCycles );
00706   return SoccerCommand( CMD_DASH, dPower );
00707 }
00708 
00715 SoccerCommand WorldModel::predictCommandToInterceptBall( ObjectT obj,
00716     SoccerCommand socClose, int *iCycles, VecPosition *posIntercept, 
00717     VecPosition *posIn, VecPosition *velIn, AngDeg *angBodyIn )
00718 {
00719   FeatureT feature_type = FEATURE_INTERCEPTION_POINT_BALL;
00720   
00721   // check whether we already have calculated this value
00722   if( isFeatureRelevant( feature_type ) )
00723   {
00724     int i = max(0,((int)getFeature(feature_type).getInfo()-getCurrentCycle()));
00725     if( iCycles != NULL )
00726       *iCycles = i;
00727     if( posIntercept != NULL )
00728       *posIntercept = predictPosAfterNrCycles( OBJECT_BALL, i );
00729 
00730     Log.log( 463, "intercept, use old info, feature %d: %d", feature_type,
00731         max(0,((int)getFeature( feature_type ).getInfo()-getCurrentCycle())));
00732     return getFeature( feature_type ).getCommand();
00733   }
00734 
00735   // declare all needed variables
00736   SoccerCommand soc;
00737   VecPosition   pos, vel, posPred, posBall(0,0), posBallTmp, velBall, posAgent;
00738   AngDeg        angBody, angNeck;
00739   int           iMinCyclesBall=100, iFirstBall=100;
00740   double        dMaxDist = getMaximalKickDist( obj );
00741   double        dBestX = UnknownDoubleValue;
00742   Stamina       sta;
00743   double        dMinOldIntercept = 100, dDistanceOfIntercept = 10.0;
00744   int           iOldIntercept = UnknownIntValue;
00745   static Time   timeLastIntercepted(-1,0);
00746   static VecPosition posOldIntercept;
00747 
00748   // didn't intercept ball in last two cycles -> reset old interception point
00749   if( (getCurrentTime() - timeLastIntercepted) > 2 )
00750     posOldIntercept.setVecPosition( UnknownDoubleValue, UnknownDoubleValue);
00751   timeLastIntercepted = getCurrentTime();
00752                                      
00753   int iCyclesBall = 0;
00754 
00755   Log.log( 468, "old interception point: (%f,%f)", posOldIntercept.getX(),
00756    posOldIntercept.getY() );
00757 
00758   // for each new pos of the ball, check whether agent can reach ball 
00759   // and update the best interception point
00760   while( iCyclesBall <= PS->getPlayerWhenToIntercept() &&
00761          iCyclesBall <= iFirstBall + 20 &&
00762          isInField( posBall ) == true )
00763   {
00764     // re-initialize all variables
00765     angBody = ( angBodyIn == NULL ) ? getGlobalBodyAngle( obj ) : *angBodyIn;
00766     angNeck = getGlobalNeckAngle( obj );
00767     pos     = ( posIn     == NULL ) ? getGlobalPosition ( obj ) : *posIn;
00768     vel     = ( velIn     == NULL ) ? getGlobalVelocity ( obj ) : *velIn;
00769     sta     = getAgentStamina();
00770     soc.commandType = CMD_ILLEGAL;
00771 
00772     // predict the ball position after iCycles and from that its velocity 
00773     posBallTmp = predictPosAfterNrCycles( OBJECT_BALL, iCyclesBall );
00774     if( iCyclesBall == 0 )
00775       velBall = getGlobalVelocity( OBJECT_BALL );
00776     else
00777       velBall = posBallTmp - posBall;
00778     posBall   = posBallTmp;
00779     
00780     // predict the agent position 
00781     posPred   = predictPosAfterNrCycles( obj, min(iCyclesBall,4), 0 );
00782     posAgent  = getGlobalPosition( obj );
00783 
00784     // if too far away, we can never reach it and try next cycle
00785     if( posPred.getDistanceTo(posBall)/getPlayerSpeedMax( obj )
00786           > iCyclesBall + dMaxDist || isInField( posBall ) == false )
00787     {
00788       iCyclesBall++;
00789       continue;
00790     }
00791 
00792     // predict our position after the same nr of cycles when intercepting 
00793     for( int i = 0; i < iCyclesBall; i++ )
00794     {
00795       soc = predictCommandToMoveToPos( obj, posBall, iCyclesBall - i ,
00796               2.5, false, &pos, &vel, &angBody );
00797       predictStateAfterCommand( soc, &pos, &vel, &angBody, &angNeck, obj );
00798     }
00799 
00800     // if in kickable distance, we can reach the ball!
00801     if (pos.getDistanceTo( posBall ) < dMaxDist  )
00802     {
00803       Log.log( 468, "can intercept ball in %d cycles, dist %f, old %f obj %d",
00804                iCyclesBall, pos.getDistanceTo( posBall ),
00805                posBall.getDistanceTo( posOldIntercept ), obj  );
00806 
00807       if( iMinCyclesBall == 100 ) // log first possible interception point
00808         iFirstBall = iMinCyclesBall = iCyclesBall;
00809 
00810       // too get some consistency in the interception point and avoid
00811       // too many turns, also keep track of the current possible
00812       // interception point.  This is the point close to the old
00813       // interception point. Two constraints are that the ball has to
00814       // have some speed (else it does not really matter where to
00815       // intercept) and the ball must be intercepted safely, that is
00816       // the ball is close to the body when intercepting. 
00817       if( posBall.getDistanceTo( posOldIntercept ) < 
00818                            min( 1.0, dMinOldIntercept ) &&
00819           pos.getDistanceTo( posBall ) < 0.70*getMaximalKickDist( obj ) &&
00820           velBall.getMagnitude() > 0.6 )
00821       {
00822         Log.log( 468, "update old interception point %d", iCyclesBall );
00823         dBestX           = posBall.getX();
00824         iOldIntercept    = iCyclesBall;
00825         dDistanceOfIntercept = pos.getDistanceTo( posBall );
00826         dMinOldIntercept = posBall.getDistanceTo( posOldIntercept );
00827       }
00828       // determine the safest interception point. This point must be
00829       // better than the current intercept, the distance to ball must
00830       // be very small after interception and close to the previous
00831       // calculated interception point
00832       else if( pos.getDistanceTo( posBall ) < dDistanceOfIntercept &&
00833                dDistanceOfIntercept > 0.50*getMaximalKickDist( obj ) &&
00834                ( iCyclesBall <= iMinCyclesBall + 3  ||
00835                  iCyclesBall <= iOldIntercept + 3 ) &&
00836                fabs( posBall.getY() ) < 32.0 &&
00837                fabs( posBall.getX() ) < 50.0 )
00838       {
00839         iMinCyclesBall = iCyclesBall;
00840         dDistanceOfIntercept = pos.getDistanceTo( posBall );
00841         Log.log( 468, "safer interception at %d", iMinCyclesBall );
00842         if( iOldIntercept == iMinCyclesBall - 1 )
00843         {
00844           Log.log( 468, "old interception point -> safer" );
00845           iOldIntercept = iMinCyclesBall;
00846         }
00847       }
00848     }
00849     else
00850       Log.log( 468, "cannot intercept ball in %d cycles, dist %f, %f and %f",
00851         iCyclesBall, pos.getDistanceTo(posBall), pos.getDistanceTo( posAgent ),
00852          posBall.getDistanceTo( posAgent ) - dMaxDist);;
00853 
00854     iCyclesBall++;
00855   }
00856 
00857   Log.log( 463, "first interception point:        %d cycles", iFirstBall );
00858   Log.log( 463, "best interception point:         %d cycles", iMinCyclesBall );
00859   Log.log( 463, "old interception point           %d cycles", iOldIntercept );
00860 
00861   // check special situations where we move to special position.
00862   if( !( iMinCyclesBall > iOldIntercept + 2 ) &&
00863       iOldIntercept != UnknownIntValue  )
00864   {
00865     Log.log( 463, "move to old interception point." );
00866     iMinCyclesBall = iOldIntercept;
00867   }
00868   else 
00869   {
00870     Log.log( 463, "move to first intercept" );
00871     iMinCyclesBall = iFirstBall;
00872   }
00873 
00874   posBall = predictPosAfterNrCycles( OBJECT_BALL, iMinCyclesBall );
00875   Log.log( 463, "choose %d cycles", iMinCyclesBall );
00876   logCircle( 463, posBall, 1.0 );
00877   if( iCycles != NULL )
00878     *iCycles = iMinCyclesBall;
00879 
00880   posOldIntercept = posBall;
00881   posPred = predictPosAfterNrCycles( obj, min(iMinCyclesBall,4), 0 );
00882   if( posIntercept != NULL )
00883     *posIntercept = posBall;
00884 
00885   if( iMinCyclesBall < 3 && ! socClose.isIllegal() )
00886   {
00887     Log.log( 463, "do close intercept" );
00888     iMinCyclesBall = 1;
00889     soc = socClose;
00890   }
00891   else if( posPred.getDistanceTo( posBall ) < 0.5 )
00892   {
00893     Log.log( 463, "intercept: do not move already close" );
00894     soc = SoccerCommand( CMD_ILLEGAL );
00895   }
00896   else
00897   {
00898     Log.log( 463, "intercept: move to (%f,%f)", posBall.getX(),posBall.getY());
00899     Log.log( 560, "intercept: move to (%f,%f) in %d cycles", 
00900              posBall.getX(),posBall.getY(), iMinCyclesBall);
00901     if( isDeadBallUs() && !isGoalKickUs())     // do not dash backwards
00902       soc = predictCommandToMoveToPos( obj, posBall, iMinCyclesBall, 0 );
00903     else
00904       soc = predictCommandToMoveToPos( obj, posBall, iMinCyclesBall );    
00905   }
00906 
00907   // store the calculated action as a feature
00908   if( obj == getAgentObjectType() )
00909     setFeature( feature_type,
00910                 Feature( getTimeLastSeeMessage(),
00911                          getTimeLastSenseMessage(),
00912                          getTimeLastHearMessage(),                       
00913                          OBJECT_ILLEGAL,
00914                          getTimeLastSeeMessage().getTime() + iMinCyclesBall,
00915                          soc ) );
00916   return soc;
00917 }
00918 
00929 bool WorldModel::isCollisionAfterCommand( SoccerCommand soc )
00930 {
00931   VecPosition posPred, velPred;
00932   AngDeg ang1, ang2;
00933   Stamina sta;
00934   
00935   predictAgentStateAfterCommand( soc, &posPred, &velPred, &ang1,&ang2,&sta );
00936   velPred /= SS->getPlayerDecay();
00937   VecPosition posBall = predictPosAfterNrCycles( OBJECT_BALL, 1 );
00938   if( soc.commandType == CMD_KICK )
00939     predictBallInfoAfterCommand( soc, &posBall );
00940   double  dDist   = posPred.getDistanceTo( posBall ) - 
00941                           SS->getPlayerSize() - SS->getBallSize();
00942   Log.log( 510, "check collision dist %f, noise_ball %f noise_me %f",
00943            dDist, getBallSpeed()*SS->getBallRand(), 
00944            velPred.getMagnitude()*SS->getPlayerRand() );
00945 
00946   // we could also take into account the error in player movement, but this
00947   // is very large, so we would in many cases get a dash
00948   if( dDist < getBallSpeed()*SS->getBallRand() )
00949     return true;
00950 
00951   return false;
00952 }
00953 

Generated on Fri Nov 7 11:45:41 2003 for UvA Trilearn 2003 Base Code by doxygen1.2.12 written by Dimitri van Heesch, © 1997-2001