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

WorldModelUpdate.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 
00048 #include "WorldModel.h"
00049 #include "Parse.h"
00050 #include <stdio.h>      // needed for sprintf
00051 #include <list>         // needed for list
00052 
00053 #include <sys/times.h>  // needed for times
00054 #include <sys/time.h>
00055 #include <sys/resource.h>
00056 #include <unistd.h>
00057 
00058 
00059 /*****************************************************************************/
00060 /********************* CLASS WORLDMODEL **************************************/
00061 /*****************************************************************************/
00062 
00063 
00075 void WorldModel::processSeeGlobalInfo( ObjectT o, Time time,
00076       VecPosition pos, VecPosition vel, AngDeg angBody, AngDeg angNeck)
00077 {
00078   DynamicObject * dobj;
00079   PlayerObject * pobj;
00080 
00081   if( o == OBJECT_ILLEGAL ) 
00082     return;
00083   if( SoccerTypes::isPlayer( o ) )
00084   {
00085     pobj = (PlayerObject*)getObjectPtrFromType( o );
00086     pobj->setTimeLastSeen( time );
00087     pobj->setGlobalPositionLastSee( pos, time ); 
00088     pobj->setTimeChangeInformation( time );            
00089     pobj->setGlobalPosition( pos, time );
00090     pobj->setGlobalVelocity( vel, time );
00091     pobj->setGlobalBodyAngle( angBody, time );
00092     pobj->setGlobalNeckAngle( VecPosition::normalizeAngle(angBody+angNeck),
00093                                                                      time );
00094     pobj->setIsKnownPlayer( true );
00095       
00096   }
00097   else if( SoccerTypes::isBall( o ) )
00098   {
00099     dobj = (DynamicObject*)getObjectPtrFromType( o );
00100     dobj->setTimeLastSeen( time );
00101     dobj->setGlobalPosition( pos, time );
00102     dobj->setGlobalVelocity( vel, time );
00103   }
00104 }
00105 
00121 bool WorldModel::processNewAgentInfo( ViewQualityT vq, ViewAngleT va,
00122      double dStamina, double dEffort, double dSpeed, AngDeg angSpeed,
00123      AngDeg angHeadAngle, int iTackleExpires, int iArmMovable, 
00124      int iArmExpires, VecPosition posArm )
00125 {
00126   Stamina sta = agentObject.getStamina();
00127 
00128   sta.setStamina                   ( dStamina                              );
00129   sta.setEffort                    ( dEffort                               );
00130   agentObject.setStamina           ( sta                                   );
00131   // this is already done when change_view is sent, and thus updated to the
00132   // predicted view angle, quality in the next cycle...
00133   if( vq == VQ_ILLEGAL )
00134     agentObject.setViewQuality       ( vq                                  );
00135   if( va == VA_ILLEGAL )
00136     agentObject.setViewAngle         ( va                                  );
00137   agentObject.setSpeedRelToNeck    ( VecPosition( dSpeed, angSpeed, POLAR) );
00138   agentObject.setBodyAngleRelToNeck( angHeadAngle                          );
00139   agentObject.setTackleExpires     ( iTackleExpires                        );
00140   agentObject.setArmMovable        ( iArmMovable == 0                      );
00141   agentObject.setArmExpires        ( iArmExpires                           );
00142   agentObject.setGlobalArmPosition ( getAgentGlobalPosition() + posArm     );
00143 
00144   return true;
00145 }
00146 
00170 void WorldModel::processNewObjectInfo( ObjectT o, Time time,
00171       double dDist, int iDir, double dDistChange, double dDirChange,
00172       AngDeg angRelBodyAng,   AngDeg angRelNeckAng, bool isGoalie,
00173       ObjectT objMin, ObjectT objMax, double dPointDir,  bool isTackling )
00174 {
00175   if( dDist == UnknownDoubleValue || o == OBJECT_ILLEGAL )
00176     return; // no sense to update when only angle is known.
00177 
00178   if( SoccerTypes::isFlag( o ) )
00179   {
00180 
00181     Flags[SoccerTypes::getIndex(o)].setRelativePosition(
00182                                                       dDist,(double)iDir,time);
00183     Flags[SoccerTypes::getIndex(o)].setTimeLastSeen    ( time                );
00184     Flags[SoccerTypes::getIndex(o)].setType            ( o                   );
00185   }
00186   else if( SoccerTypes::isPlayer( o ) || SoccerTypes::isBall( o ) )
00187   {
00188     DynamicObject *d ;
00189 
00190     // if we do not have all information, update UnknownPlayer array
00191     if( !( SoccerTypes::isKnownPlayer( o ) || SoccerTypes::isBall( o ) ) )
00192     {
00193       UnknownPlayers[iNrUnknownPlayers].setIsKnownPlayer( false );
00194       UnknownPlayers[iNrUnknownPlayers].setPossibleRange( objMin, objMax );
00195       d = &UnknownPlayers[iNrUnknownPlayers];
00196       iNrUnknownPlayers++;
00197     }
00198     else // else update the known object (teammate, opponent, ball)
00199     {
00200       d = (DynamicObject*)getObjectPtrFromType( o );
00201       if( SoccerTypes::isPlayer( o ) )
00202         ((PlayerObject*)d)->setIsKnownPlayer( true );
00203     }
00204 
00205     if( d != NULL )  // if object was known
00206     {
00207       // set all values for this dynamicobject
00208       d->setRelativePosition( dDist, (double)iDir, time );
00209       if( dDistChange != UnknownDoubleValue )
00210         d->setRelativeDistanceChange( dDistChange, time );
00211       if( dDirChange != UnknownDoubleValue )
00212         d->setRelativeAngleChange( dDirChange, time );
00213       if( angRelBodyAng != UnknownAngleValue )
00214         ((PlayerObject*)d)->setRelativeBodyAngle( angRelBodyAng, time );
00215       if( angRelNeckAng != UnknownAngleValue )
00216         ((PlayerObject*)d)->setRelativeNeckAngle( angRelNeckAng, time );
00217       if( isGoalie == true && SoccerTypes::isPlayer( o ))
00218         ((PlayerObject*)d)->setIsGoalie( true );
00219       else if( SoccerTypes::isPlayer( o ))
00220         ((PlayerObject*)d)->setIsGoalie( false );
00221       d->setType( o );
00222       d->setTimeLastSeen( time );
00223 
00224       if( isTackling )
00225       {
00226         // if last observed tackle time has been passed. 
00227         if( ((PlayerObject*)d)->getTimeTackle() + SS->getTackleCycles() 
00228                                              < getCurrentTime() )
00229           ((PlayerObject*)d)->setTimeTackle( getCurrentTime() - 1  );
00230       }
00231       else
00232           ((PlayerObject*)d)->setTimeTackle( Time(-1,0)  );
00233 
00234       if( dPointDir != UnknownDoubleValue )
00235         ((PlayerObject*)d)->setGlobalArm( dPointDir, getCurrentTime() );
00236 
00237       // check if there wasn't an unknown player located in the worldmodel
00238       // that corresponded to the same player
00239       if( SoccerTypes::isPlayer( o ) && SoccerTypes::isKnownPlayer( o )  )
00240       {
00241         int        iIndex;
00242         ObjectT    objMin = OBJECT_ILLEGAL;
00243         double     dMinDist = 1000.0, dTmp;
00244         ObjectSetT set = SoccerTypes::isOpponent( o )
00245                              ? OBJECT_SET_OPPONENTS
00246                              : OBJECT_SET_TEAMMATES;
00247 
00248         for( ObjectT obj = iterateObjectStart( iIndex, set );
00249              obj != OBJECT_ILLEGAL;
00250              obj = iterateObjectNext ( iIndex, set ) )
00251         {
00252           if( obj != getAgentObjectType() && isKnownPlayer( obj ) == false )
00253           {
00254             dTmp=(getRelativePosition(obj)-d->getRelativePosition()
00255                                                           ).getMagnitude();
00256             if( dTmp < dMinDist )
00257             {
00258               objMin   = obj;
00259               dMinDist = dTmp;
00260             }
00261           }
00262         }
00263         iterateObjectDone( iIndex );
00264         if( objMin != OBJECT_ILLEGAL &&
00265             dMinDist < PS->getPlayerDistTolerance() &&
00266             dMinDist < getMaxTraveledDistance( objMin )  )
00267         {
00268           PlayerObject *pob = (PlayerObject*) getObjectPtrFromType( objMin );
00269           pob->setTimeLastSeen( -1 ); // delete the unknown player
00270           Log.log( 464, "set time objMin %d to -1 mapped to  player %d %f %f", 
00271                    objMin, o, dMinDist, getMaxTraveledDistance( objMin )  );
00272         }
00273         else
00274           Log.log( 464, "don't set time objMin %d to -1  player %d dist %f", 
00275                    objMin, o, dMinDist  );
00276 
00277       }
00278     }
00279   }
00280   else if( SoccerTypes::isLine( o ) )
00281   {
00282     // angle returned is angle of neck angle with line, convert to angle
00283     // of neck with orthogonal to line
00284     iDir = ( iDir < 0 ) ? (90 + iDir ) : - (90 - iDir );
00285 
00286     Lines[SoccerTypes::getIndex(o)].setRelativePosition(
00287                                                      dDist,(double)iDir,time);
00288     Lines[SoccerTypes::getIndex(o)].setTimeLastSeen( time );
00289     Lines[SoccerTypes::getIndex(o)].setType( o );
00290   }
00291 }
00292 
00300 bool WorldModel::storePlayerMessage( int iPlayer, char *strMsg, int iCycle )
00301 {
00302   strcpy( m_strPlayerMsg, strMsg );
00303   m_iCycleInMsg = iCycle;
00304   m_timePlayerMsg  = getCurrentTime();
00305   m_iMessageSender = iPlayer;
00306   return true;
00307 }
00308 
00310 bool WorldModel::processPlayerMessage( )
00311 {
00312   static char strMessage[MAX_MSG];                      // location for message
00313   int         iDiff = getCurrentCycle() - m_iCycleInMsg;// time difference
00314   double      dDiff = (double)iDiff/100.0;              // conf difference
00315   char        *strMsg;
00316   strcpy( strMessage, m_strPlayerMsg );
00317   strMsg = strMessage;                                  // pointer to work with
00318 
00319   char cOffside = strMsg[1];                        // read offside information
00320   if( cOffside >= 'a' && cOffside <= 'z' )          // a-z corresponds to 0-25
00321   {
00322     m_dCommOffsideX    = (double)(cOffside - 'a');
00323     m_timeCommOffsideX = getCurrentTime() - 1;
00324   }
00325   else if( cOffside >= 'A' && cOffside <= 'Z' )     // A-Z corresponds to 26-52
00326   {
00327     m_dCommOffsideX = 26 + (double)(cOffside - 'A');
00328     m_timeCommOffsideX = getCurrentTime() - 1;
00329   }
00330   else                                              // wrong message
00331     return false;
00332 
00333   if( strMsg[2] >= '0' && strMsg[2] <= '9' &&       // received ball info
00334       strlen( strMessage ) == 12)
00335   {
00336     // translate ball position nd velocity back to initial range.
00337     double dBallX =    (int)(strMsg[2]-'0')*10 +(int)(strMsg[3] - '0' ) - 48.0;
00338     double dBallY =    (int)(strMsg[4]-'0')*10 +(int)(strMsg[5] - '0' ) - 34.0;
00339     double dBallVelX = (int)(strMsg[6]-'0') + (int)(strMsg[7] - '0' )/10.0-2.7;
00340     double dBallVelY = (int)(strMsg[8]-'0') + (int)(strMsg[9] - '0' )/10.0-2.7;
00341 
00342     VecPosition pos( dBallX, dBallY );
00343     VecPosition vel( dBallVelX, dBallVelY );
00344     for( int i = 0; i < iDiff ; i ++ )
00345     {
00346       pos += vel;
00347       vel *= SS->getBallDecay();
00348     }
00349 
00350     // if ball not seen or felt for three cycles, update ball information
00351     if( getTimeLastSeen( OBJECT_BALL ) == -1 ||
00352         (
00353           getTimeChangeInformation( OBJECT_BALL ) < getCurrentTime() - 3 &&
00354           getRelativeDistance( OBJECT_BALL ) > SS->getVisibleDistance()  
00355          ) ||
00356         (
00357           getTimeChangeInformation( OBJECT_BALL ) < getCurrentTime() - iDiff &&
00358           vel.getDistanceTo( getGlobalVelocity(OBJECT_BALL) ) > 0.3 &&
00359           getRelativeDistance( OBJECT_BALL ) > SS->getVisibleDistance()
00360         )
00361       )
00362     {
00363       Log.log( 600,
00364         "update ball comm. (%1.2f,%1.2f)(%1.2f,%1.2f) diff %d, last %d",
00365              pos.getX(), pos.getY(), vel.getX(), vel.getY(), iDiff,
00366              getTimeLastSeen( OBJECT_BALL ).getTime() );
00367       Log.log( 601, "update ball from comm (%1.2f,%1.2f)(%1.2f,%1.2f) diff %d",
00368              pos.getX(), pos.getY(), vel.getX(), vel.getY(), iDiff );
00369       processPerfectHearInfoBall( pos, vel, 1.00 - dDiff - 0.01 )    ;
00370     }
00371     else
00372       Log.log( 600, "do not update ball time_change %d, now %d, diff %d, d %f",
00373         getTimeChangeInformation( OBJECT_BALL ).getTime(),
00374         getCurrentCycle(),
00375         iDiff,
00376         vel.getDistanceTo( getGlobalVelocity(OBJECT_BALL) ) );
00377    }
00378   else if( strlen( strMessage ) == 12 &&            // received attacker info
00379            strMsg[2] >= 'a' && strMsg[2] <= 'a' + 10 &&
00380            strMsg[6] == ' ' )
00381   {
00382     ObjectT objOpp
00383              = SoccerTypes::getOpponentObjectFromIndex((int)(strMsg[2]-'a'));
00384     char   *str  = &strMsg[3];                      // get pointer to string
00385     double dOppX = -1*Parse::parseFirstInt( &str );
00386     dOppX /= 10.0;
00387     double dOppY = Parse::parseFirstInt( &str );
00388     dOppY /= 10.0;
00389     VecPosition posOpp( dOppX, dOppY );
00390     processPerfectHearInfo( objOpp, posOpp, 0.99, false )  ;
00391   }
00392 
00393   return true;
00394 }
00395 
00396 bool WorldModel::processRecvThink( bool b )
00397 {
00398   m_bRecvThink = b;
00399   if( b == true && SS->getSynchMode() == true )
00400   {
00401 #ifdef WIN32
00402     //EnterCriticalSection( &mutex_newInfo );
00403     bNewInfo            = true;
00404     SetEvent            (  event_newInfo );
00405     //LeaveCriticalSection( &mutex_newInfo );
00406 #else
00407     pthread_mutex_lock  ( &mutex_newInfo );
00408     bNewInfo            = true;
00409     pthread_cond_signal ( &cond_newInfo );
00410     pthread_mutex_unlock( &mutex_newInfo );
00411 #endif
00412   }
00413   return true;
00414 }
00415 
00423 bool WorldModel::processPerfectHearInfoBall( VecPosition posGlobal,
00424                              VecPosition vel, double dConf )
00425 {
00426   Log.log( 501, "ball conf: %f %d", getConfidence( OBJECT_BALL ),
00427     getTimeLastSeen( OBJECT_BALL ).getTime() );
00428   if( Ball.getConfidence( getCurrentTime() ) < dConf ||
00429       vel.getDistanceTo( getGlobalVelocity(OBJECT_BALL) ) > 0.3  )
00430   {
00431     Time time = getTimeFromConfidence( dConf );
00432     Ball.setGlobalPosition( posGlobal, time );
00433     Ball.setGlobalVelocity( vel,       time );
00434     Ball.setTimeLastSeen  (            time );
00435     updateObjectRelativeFromGlobal( OBJECT_BALL );
00436     setTimeLastHearMessage( getCurrentTime() );          
00437     return true;
00438   }
00439   return false;
00440 }
00441 
00453 bool WorldModel::processPerfectHearInfo( ObjectT o, VecPosition posGlobal,
00454                                          double dConf, bool bIsGoalie )
00455 {
00456   if( SoccerTypes::isBall( o ) || o == getAgentObjectType() )
00457     return false; // ball should be called with processPerfectHearInfoBall
00458   else if( !SoccerTypes::isKnownPlayer( o ) )
00459     return processUnsureHearInfo( o, posGlobal, dConf );
00460 
00461   PlayerObject *object = (PlayerObject *)getObjectPtrFromType( o );
00462   if( object == NULL )
00463     return false;
00464 
00465   Time time = getTimeFromConfidence( dConf ) ;
00466 
00467   // if we are not sure about the exact player number of this player in
00468   // the world model (getIsKnownPlayer() == false) we overwrite the
00469   // information of this player since the player who said this information
00470   // is sure about it (otherwise processUnsureHearInfo would be called instead
00471   // of processPERFECTHearInfo)
00472   if( object->getConfidence( getCurrentTime() ) < dConf ||
00473       object->getIsKnownPlayer() == false  )
00474   {
00475     object->setGlobalPosition     ( posGlobal         , time );
00476     object->setTimeLastSeen       ( time                     );
00477     object->setGlobalVelocity     ( VecPosition( 0, 0), time );
00478     object->setIsKnownPlayer      ( true                     );
00479     object->setIsGoalie           ( bIsGoalie                );
00480     updateObjectRelativeFromGlobal( o                        );
00481     setTimeLastHearMessage( getCurrentTime() );              
00482     return true;
00483   }
00484   return false;
00485 }
00486 
00498 bool WorldModel::processUnsureHearInfo( ObjectT o, VecPosition pos,
00499                                                double dConf )
00500 {
00501   double     dMinDist;        // used to find closest player to pos
00502   ObjectT    objInitial = o;
00503 
00504   if( o != OBJECT_TEAMMATE_UNKNOWN && o != OBJECT_OPPONENT_UNKNOWN )
00505     return false;
00506 
00507   // if o is a teammate find closest teammate to pos and store distance
00508   if( SoccerTypes::isTeammate( o ) )
00509     o = getClosestInSetTo( OBJECT_SET_TEAMMATES, pos, &dMinDist);
00510   else if( SoccerTypes::isOpponent( o ) )  // if o is an opponent, do the same
00511     o = getClosestInSetTo( OBJECT_SET_OPPONENTS, pos, &dMinDist);
00512 
00513   if( o == getAgentObjectType() &&
00514      pos.getDistanceTo(getAgentGlobalPosition())<PS->getPlayerDistTolerance())
00515     return false;  // do not update my own position, localization is better
00516 
00517   // if opponent or teammate was found and distance lies in tolerance distance
00518   //  update this opponent or teammate with the specified information.
00519   // else put the information in the first player position of which we have
00520   //  no information.
00521   else if( SoccerTypes::isKnownPlayer(o) &&
00522            dMinDist < PS->getPlayerDistTolerance())
00523   {
00524     processPerfectHearInfo( o, pos, dConf );
00525     return true;
00526   }
00527 
00528   if( objInitial == OBJECT_TEAMMATE_UNKNOWN )
00529     o = getFirstEmptySpotInSet( OBJECT_SET_TEAMMATES );
00530   else if( objInitial == OBJECT_OPPONENT_UNKNOWN )
00531     o = getFirstEmptySpotInSet( OBJECT_SET_OPPONENTS );
00532   else
00533     return false ;  // in case of OBJECT_PLAYER_UNKNOWN
00534 
00535   if( o != OBJECT_ILLEGAL )   // can be the case that there is no empty spot
00536   {
00537     processPerfectHearInfo( o, pos, dConf );
00538     setIsKnownPlayer( o, false );
00539   }
00540   return true;
00541 }
00542 
00563 bool WorldModel::processNewHeteroPlayer( int iIndex,    double dPlayerSpeedMax,
00564             double dStaminaIncMax, double dPlayerDecay, double dInertiaMoment,
00565             double dDashPowerRate, double dPlayerSize,  double dKickableMargin,
00566             double dKickRand,      double dExtraStamina,double dEffortMax,
00567             double dEffortMin )
00568 {
00569    pt[iIndex].dPlayerSpeedMax  = dPlayerSpeedMax;
00570    pt[iIndex].dStaminaIncMax   = dStaminaIncMax;
00571    pt[iIndex].dPlayerDecay     = dPlayerDecay;
00572    pt[iIndex].dInertiaMoment   = dInertiaMoment;
00573    pt[iIndex].dDashPowerRate   = dDashPowerRate;
00574    pt[iIndex].dPlayerSize      = dPlayerSize;
00575    pt[iIndex].dKickableMargin  = dKickableMargin;
00576    pt[iIndex].dKickRand        = dKickRand;
00577    pt[iIndex].dExtraStamina    = dExtraStamina;
00578    pt[iIndex].dEffortMax       = dEffortMax;
00579    pt[iIndex].dEffortMin       = dEffortMin;
00580    pt[iIndex].dMaximalKickDist = dKickableMargin +   
00581                                  dPlayerSize +       
00582                                  SS->getBallSize();
00583 
00584    return true;
00585 }
00586 
00596 void WorldModel::processCatchedBall( RefereeMessageT rm, Time time )
00597 {
00598   if( rm == REFC_GOALIE_CATCH_BALL_LEFT && sideSide == SIDE_LEFT )
00599     timeLastCatch = time;
00600   else if( rm == REFC_GOALIE_CATCH_BALL_RIGHT && sideSide == SIDE_RIGHT )
00601     timeLastCatch = time;
00602   Ball.setGlobalVelocity( VecPosition(0,0), getCurrentTime() );
00603 }
00604 
00613 void WorldModel::processQueuedCommands( SoccerCommand commands[],
00614                                         int iCommands )
00615 {
00616   if( iCommands > CMD_MAX_COMMANDS )
00617   {
00618     cerr << "(WorldModel::setQueuedCommands) queuedCommands array cannot "
00619          << "contain so many commands!\n";
00620     return;
00621   }
00622 
00623   // put all sent commands to the array which stores queued commands.
00624   for( int i = 0 ; i < iCommands ; i ++ )
00625   {
00626     commands[i].time                             = getCurrentTime();
00627     queuedCommands[(int)commands[i].commandType] = commands[i];
00628   }
00629 }
00630 
00638 bool WorldModel::updateAll( )
00639 {
00640   static Timing timer;
00641   double dTimeSense = 0.0, dTimeSee = 0.0, dTimeComm=0.0, dTimeFastest = 0.0;
00642   static struct tms times1, times2;
00643   
00644   bool        bReturn            = false, bUpdateAfterSee = false;
00645   bool        bUpdateAfterSense  = false, bDebug = false;
00646   static Time timeLastHoleRecorded;
00647   static Time timeBeginInterval;
00648   static Time timePlayersCounted;
00649   static int  iNrHolesLastTime   = 0;
00650   static Time timeLastSenseUpdate;
00651   static Time timeLastSeeUpdate;
00652   static Time timeLastSayUpdate;
00653   if( bDebug )
00654   {
00655     timer.restartTime();
00656     times( &times1 );
00657   }
00658     
00659   // check if last update of agent was not more than one cycle ago
00660   if( agentObject.getTimeGlobalPosition() < getCurrentTime() - 1  )
00661     Log.log( 3, "(WorldModel::updateAll) missed a sense??" );
00662 
00663   // call update method depending on last received message
00664   if( isFullStateOn( ) == true ) 
00665   {
00666     Log.log( 4, "full state is on" );
00667     updateRelativeFromGlobal();   
00668     timeLastSenseMessage = timeLastRecvSeeMessage;   
00669     timeLastSeeMessage   = timeLastRecvSeeMessage;       
00670     bUpdateAfterSee = bUpdateAfterSense = false;
00671     bReturn = true;
00672   }
00673   else
00674   {
00675     Log.log( 4, "full state is off" );  
00676     if( getTimeLastRecvSeeMessage() > timeLastSeeUpdate )
00677       bUpdateAfterSee = true;
00678     if( getTimeLastRecvSenseMessage() > timeLastSenseUpdate )
00679       bUpdateAfterSense = true;
00680   }
00681 
00682   // rare situation: can occur that see arrives between sense and calling
00683   // updateAll or sense arrives between see and calling updateAll.
00684   if( bUpdateAfterSee && bUpdateAfterSense )
00685   {
00686     Log.log( 3, "!!! Two updates !!! " );
00687     Log.log( 3, "see: %d sense: %d", getTimeLastRecvSeeMessage().getTime(),
00688        getTimeLastRecvSenseMessage().getTime() );
00689     if( getTimeLastRecvSeeMessage( ) == getTimeLastRecvSenseMessage() )
00690     {
00691       Log.log( 3, "update sense" );
00692       timeLastSenseMessage = timeLastRecvSenseMessage;
00693       bReturn  = updateAfterSenseMessage( );
00694       if( bDebug ) dTimeSense = timer.getElapsedTime(1000);
00695       updateRelativeFromGlobal();
00696       Log.log( 3, "update see" );
00697       timeLastSeeMessage = timeLastRecvSeeMessage;
00698       bReturn &= updateAfterSeeMessage( );
00699       if( bDebug ) dTimeSee = timer.getElapsedTime(1000) - dTimeSense;
00700     }
00701     else if( getTimeLastRecvSeeMessage( ) < getTimeLastRecvSenseMessage() )
00702     {
00703       Log.log( 3, "update see" );
00704       timeLastSeeMessage = timeLastRecvSeeMessage;
00705       bReturn  = updateAfterSeeMessage( );
00706       if( bDebug ) dTimeSee = timer.getElapsedTime(1000);
00707       Log.log( 3, "update sense" );
00708       timeLastSenseMessage = timeLastRecvSenseMessage;
00709       bReturn &= updateAfterSenseMessage( );
00710       updateRelativeFromGlobal();
00711       if( bDebug ) dTimeSense = timer.getElapsedTime(1000) - dTimeSee;
00712     }
00713     timeLastSenseUpdate = getTimeLastSenseMessage();
00714     timeLastSeeUpdate   = getTimeLastSeeMessage();
00715   }
00716   else if( bUpdateAfterSee )                        // process see message
00717   {
00718     Log.log( 3, "update see" );
00719     timeLastSeeMessage = timeLastRecvSeeMessage;
00720     bReturn           = updateAfterSeeMessage( );
00721     timeLastSeeUpdate = getTimeLastSeeMessage();
00722     if( bDebug ) dTimeSee = timer.getElapsedTime(1000);
00723   }
00724   else if( bUpdateAfterSense )                      // process sense message
00725   {
00726     Log.log( 3, "update sense" );
00727     timeLastSenseMessage = timeLastRecvSenseMessage;
00728     bReturn             = updateAfterSenseMessage( );
00729     timeLastSenseUpdate = getTimeLastSenseMessage();
00730     updateRelativeFromGlobal();
00731     if( bDebug ) dTimeSense = timer.getElapsedTime(1000);
00732   }
00733 
00734   if( timeLastSayUpdate != m_timePlayerMsg &&
00735       isFullStateOn() == false        )            // process communication msg
00736   {
00737     Log.log( 3, "update hear" );
00738     if( bDebug ) dTimeComm = timer.getElapsedTime(1000);
00739     timeLastSayUpdate = m_timePlayerMsg;
00740     processPlayerMessage();
00741     if( bDebug ) dTimeComm = timer.getElapsedTime(1000) - dTimeComm;
00742   }
00743 
00744   SoccerCommand soc = getChangeViewCommand( );
00745   if( ! soc.isIllegal() )
00746   {
00747     setAgentViewAngle( soc.va );
00748     setAgentViewQuality( soc.vq );
00749   }
00750 
00751   // check for holes
00752   if( isQueuedActionPerformed() == false &&
00753       timeLastHoleRecorded != getCurrentTime() &&
00754       isFullStateOn() == false )
00755   {
00756     Log.log( 2, "HOLE recorded" );
00757     timeLastHoleRecorded = getCurrentTime();
00758     iNrHoles++;
00759   }
00760 
00761   // determine number of holes in last time interval and act accordingly
00762   int    iTimeDiff = getCurrentTime() - timeBeginInterval;
00763   double dHolePerc = (double)(iNrHoles - iNrHolesLastTime)/iTimeDiff*100;
00764   if( ! isLastMessageSee( ) && iTimeDiff % 400 == 0 && dHolePerc > 1.0 &&
00765       PS->getFractionWaitSeeEnd() > 0.70 )
00766   {
00767     PS->setFractionWaitSeeEnd( PS->getFractionWaitSeeEnd() - 0.05 );
00768     timeBeginInterval = getCurrentTime();
00769     cerr << getCurrentCycle() << ": lowered send time to " <<
00770             PS->getFractionWaitSeeEnd() << " for player number "   <<
00771             getPlayerNumber()           <<
00772             "; nr of holes is "<< dHolePerc << "%" << "( " << iNrHoles << ", "
00773             << iNrHolesLastTime << ")" << endl;
00774     iNrHolesLastTime   = iNrHoles;
00775   }
00776 
00777   // store some statistics about number of players seen each cycle
00778   if( bUpdateAfterSense == true  && ! isTimeStopped() &&
00779       getCurrentTime() != timePlayersCounted )
00780   {
00781     iNrTeammatesSeen += getNrInSetInRectangle( OBJECT_SET_TEAMMATES );
00782     iNrOpponentsSeen += getNrInSetInRectangle( OBJECT_SET_OPPONENTS );
00783     timePlayersCounted = getCurrentTime();
00784   }
00785 
00786   // log specific information when log level is set
00787   if( Log.isInLogLevel( 456 ) )
00788     logObjectInformation( 456, getAgentObjectType() );
00789 
00790   if( bUpdateAfterSee == true )
00791     Log.logWithTime(3, "  finished update_all see; start determining action" );
00792   if( bUpdateAfterSense == true )
00793     Log.logWithTime(3, "  finished update_all sense;start determining action");
00794 
00795   if( Log.isInLogLevel( 459 ) )
00796   {
00797     Log.log( 459, "%s%s", strLastSeeMessage, strLastSenseMessage );
00798     show( OBJECT_BALL, Log.getOutputStream() );
00799     show( OBJECT_SET_PLAYERS, Log.getOutputStream() );
00800   }
00801   if( ( Log.isInLogLevel( 101 ) && getRelativeDistance( OBJECT_BALL ) < 2.0 ) )
00802     show( OBJECT_BALL, Log.getOutputStream() );
00803   if( Log.isInLogLevel( 556 ) && 
00804       getRelativeDistance( OBJECT_BALL ) < SS->getVisibleDistance() )
00805   {
00806     Log.log( 556, "%s", strLastSeeMessage );
00807     show( OBJECT_SET_PLAYERS, Log.getOutputStream() );
00808     show( OBJECT_BALL, Log.getOutputStream() );
00809   }
00810   if( LogDraw.isInLogLevel( 460 ) )
00811   {
00812     int iCycles;
00813     dTimeFastest = timer.getElapsedTime( 1000 );
00814     ObjectT obj = getFastestInSetTo(OBJECT_SET_OPPONENTS,OBJECT_BALL,&iCycles);
00815     logCircle( 460, getGlobalPosition( obj ), 1.5 );
00816     logCircle( 460, predictPosAfterNrCycles( OBJECT_BALL, iCycles ), 0.5 );
00817     obj=getFastestInSetTo(OBJECT_SET_TEAMMATES_NO_GOALIE,OBJECT_BALL,&iCycles);
00818     logCircle( 460, getGlobalPosition( obj ), 1.5 );   
00819     logCircle( 460, predictPosAfterNrCycles( OBJECT_BALL, iCycles ), 0.75 );  
00820     dTimeFastest = timer.getElapsedTime( 1000 ) - dTimeFastest;
00821   }
00822 
00823   if( LogDraw.isInLogLevel( 701 ) )
00824     drawCoordinationGraph( );
00825 
00826   logLine( 602, VecPosition( getOffsideX(), -PITCH_WIDTH/2.0),
00827            VecPosition( getOffsideX(),  PITCH_WIDTH/2.0) );       
00828   if( bDebug ) 
00829   {
00830      Log.logWithTime( 461, "time update all: %f\n time comm:        %1.5f\n\
00831      time see:       %1.5f\n time sense:    %1.5f\n time fastest:     %1.5f\n\
00832      time rest:      %1.5f\n utime:         %1.5f", 
00833      timer.getElapsedTime()*1000, dTimeComm, dTimeSee, dTimeSense,dTimeFastest,
00834      timer.getElapsedTime()*1000-(dTimeComm+dTimeSee+dTimeSense+dTimeFastest ),
00835      times2.tms_utime  - times1.tms_utime );
00836   }
00837   return bReturn;
00838 }
00839 
00840 /*****************************************************************************/
00841 /*************** WORLDMODEL: SEE RELATED UPDATES *****************************/
00842 /*****************************************************************************/
00843 
00844 void  WorldModel::processLastSeeMessage( )
00845 {
00846   ObjectT o;
00847   double  dDist, dDistChange,    dDirChange,    dPointDir,    dTemp;
00848   int     iDir;
00849   AngDeg  angBodyFacingDir, angHeadFacingDir;
00850   Time    time = getTimeLastSeeMessage();
00851   bool    isGoalie, isTackling;
00852   static char strTmp[MAX_MSG];
00853   char   *strMsg = strLastSeeMessage ;
00854   Parse::parseFirstInt( &strMsg );         // get the time
00855 
00856   ObjectT objMin     = OBJECT_ILLEGAL;
00857   ObjectT objMax     = OBJECT_ILLEGAL;
00858 
00859   while( *strMsg != ')' )                          // " ((objname.." or ")"
00860   {
00861     dDist = dDistChange = dDirChange = dTemp = dPointDir = UnknownDoubleValue;
00862     angBodyFacingDir = angHeadFacingDir =         UnknownAngleValue;
00863     strMsg += 2;          // get the object name
00864     isTackling = false;
00865 
00866     // get the object name from the first part of the string
00867 //    cerr << "string: |" << strMsg << endl;
00868     o = SoccerTypes::getObjectFromStr( &strMsg, &isGoalie, getTeamName() );
00869 
00870     if( o == OBJECT_ILLEGAL )
00871     {
00872       Log.log( 4, "Illegal object in: %s", strLastSeeMessage );
00873       Log.log( 4, "rest of message: %s", strMsg );
00874     }
00875     else if( SoccerTypes::isKnownPlayer( o ) )    // we know the player
00876       objMin = o;
00877     else if( SoccerTypes::isPlayer( o ) )         // and thus an unknown player
00878     {
00879       if( SoccerTypes::isTeammate( o ) &&
00880           ( objMin == OBJECT_ILLEGAL || SoccerTypes::isOpponent( objMin ) ) )
00881         objMin = OBJECT_TEAMMATE_1 ;
00882       else if( SoccerTypes::isOpponent( o )  &&
00883           ( objMin == OBJECT_ILLEGAL || SoccerTypes::isTeammate( objMin ) ) )
00884         objMin = OBJECT_OPPONENT_1 ;
00885       else if( objMin == OBJECT_ILLEGAL )
00886         objMin = (getSide() == SIDE_LEFT ) ? OBJECT_TEAMMATE_1
00887                                            : OBJECT_OPPONENT_1 ;
00888       else if( objMin == OBJECT_TEAMMATE_11 )
00889         objMin = OBJECT_OPPONENT_1;
00890       else if( objMin == OBJECT_OPPONENT_11 )
00891         objMin = OBJECT_TEAMMATE_1;
00892       else
00893         objMin = (ObjectT)((int)objMin + 1);
00894 
00895       if( objMin == getAgentObjectType() )
00896       {
00897          if( objMin == OBJECT_TEAMMATE_11 )
00898            objMin = OBJECT_OPPONENT_1;
00899          else if( objMin == OBJECT_OPPONENT_11 )
00900            objMin = OBJECT_TEAMMATE_1;
00901          else
00902           objMin = (ObjectT)((int)objMin + 1);
00903       }
00904       strcpy( strTmp, strMsg );                  // get the maximum object by
00905       objMax = getMaxRangeUnknownPlayer( objMin, strTmp ); // look to next obj
00906     }
00907 
00908     dTemp = Parse::parseFirstDouble( &strMsg );   // parse first value
00909     if ( *strMsg == ')' )                         // if it was the only value
00910       iDir = (int)dTemp;                          // it was the direction
00911     else
00912     {
00913       dDist = dTemp;                              // else it was distance
00914       iDir = Parse::parseFirstInt( &strMsg );     // and have to get direction
00915 
00916       double dValues[7];
00917       int    i = 0;
00918       if( *strMsg == ' ' )                        // stil not finished 
00919       {                                           // get dist and dir change
00920         while( *strMsg != ')' && *(strMsg+1) != 't' && i < 7 )
00921         {
00922           dValues[i]  = Parse::parseFirstDouble( &strMsg ); 
00923           i++;
00924         }
00925       }
00926 
00927       switch( i )
00928       {
00929         case 0:
00930           break;
00931         case 1:
00932           dPointDir   = dValues[0];
00933           break;
00934         case 5:
00935           dPointDir   = dValues[4]; // fall through
00936         case 4:
00937           angBodyFacingDir = dValues[2];
00938           angHeadFacingDir = dValues[3]; // fall through
00939         case 2:                        // in case of ball 
00940           dDistChange = dValues[0];
00941           dDirChange  = dValues[1];
00942           break;
00943         default:
00944           cerr << "(WorldModelUpdate::analyzeSee) wrong param nr " << i <<endl;
00945 
00946       }
00947 
00948       if( *(strMsg+1) == 't') 
00949         isTackling = true;
00950     }
00951 
00952     // go to end object information
00953     // skip ending bracket of object information.
00954     Parse::gotoFirstOccurenceOf( ')', &strMsg );
00955     strMsg++;
00956 
00957     if( SoccerTypes::isPlayer( o ) && !SoccerTypes::isKnownPlayer( o ) )
00958     {
00959       if( objMin != OBJECT_ILLEGAL )
00960       {
00961         if( objMin == objMax )
00962         {
00963           Log.log( 459, "range, only %d left", objMin );
00964           o = objMin;
00965         }
00966         else if( SoccerTypes::isTeammate( objMin ) &&
00967                  SoccerTypes::isTeammate( objMax ) )
00968           o = OBJECT_TEAMMATE_UNKNOWN;
00969         else if( SoccerTypes::isOpponent( objMin ) &&
00970                  SoccerTypes::isOpponent( objMax ) )
00971           o = OBJECT_OPPONENT_UNKNOWN;
00972       }
00973     }
00974 
00975     // process the parsed information (unread values are Unknown...)
00976     processNewObjectInfo( o, time, dDist, iDir, dDistChange,
00977            dDirChange, angBodyFacingDir, angHeadFacingDir,
00978            isGoalie, objMin, objMax, dPointDir, isTackling );
00979   }
00980 }
00981 
00987 bool WorldModel::updateAfterSeeMessage( )
00988 {
00989   processLastSeeMessage( );
00990 
00991    // update the agent (global position and angle using flags and lines)
00992   if( getCurrentTime().getTime() != -1 )
00993     updateAgentObjectAfterSee( );
00994 
00995   mapUnknownPlayers( getTimeLastSeeMessage() ); // map players with unknown nr
00996 
00997   // walk past all players on the field an when new information was perceived
00998   // (and put in the relative attributes) update this dynamic object. When it
00999   // was not seen, convert its global position (this is an estimate from the
01000   // sense message) to a relative position
01001   double dConfThr = PS->getPlayerConfThr();
01002   int    iIndex;
01003 
01004   for( ObjectT o = iterateObjectStart( iIndex, OBJECT_SET_PLAYERS, dConfThr );
01005        o != OBJECT_ILLEGAL;
01006        o = iterateObjectNext ( iIndex, OBJECT_SET_PLAYERS, dConfThr ) )
01007   {
01008     if( getTimeLastSeen( o ) == getTimeLastSeeMessage() &&
01009         o != getAgentObjectType()  )
01010       updateDynamicObjectAfterSee   ( o );
01011     else
01012       updateObjectRelativeFromGlobal( o );
01013   }
01014   iterateObjectDone( iIndex );
01015 
01016   // if ball was seen update him, otherwise make estimated global relative
01017   if( getTimeLastSeen( OBJECT_BALL ) == getTimeLastSeeMessage() )
01018     updateDynamicObjectAfterSee   ( OBJECT_BALL );
01019   else
01020     updateObjectRelativeFromGlobal( OBJECT_BALL );
01021 
01022   // delete objects from wordmodel that should have been seen, but aren't
01023   if( Log.isInLogLevel( 2 ) )
01024     show( OBJECT_BALL, Log.getOutputStream() );
01025   removeGhosts();
01026   if( Log.isInLogLevel( 2 ) )
01027     show( OBJECT_BALL, Log.getOutputStream() );
01028 
01029 
01030   return true;
01031 }
01032 
01037 bool WorldModel::updateAgentObjectAfterSee(  )
01038 {
01039   VecPosition posGlobal, velGlobal;
01040   AngDeg      angGlobal;
01041 
01042   // calculate the state of the agent
01043   calculateStateAgent( &posGlobal, &velGlobal, &angGlobal );
01044 
01045   // and set the needed attributes
01046   agentObject.setTimeLastSeen         ( getTimeLastSeeMessage() );
01047   // store difference with predicted global position to compensate for error
01048   // in global position when global velocity is calculated for other objects.
01049   agentObject.setPositionDifference(posGlobal-agentObject.getGlobalPosition());
01050   agentObject.setGlobalPosition       ( posGlobal, getTimeLastSeeMessage() );
01051   agentObject.setGlobalPositionLastSee( posGlobal, getTimeLastSeeMessage() );
01052   agentObject.setGlobalNeckAngle      ( angGlobal );
01053   agentObject.setGlobalVelocity       ( velGlobal, getTimeLastSeeMessage() );
01054 
01055   return true;
01056 }
01057 
01058 
01064 bool WorldModel::updateDynamicObjectAfterSee( ObjectT o )
01065 {
01066   VecPosition posGlobal, velGlobal;
01067 
01068   if( o == OBJECT_BALL )
01069   {
01070     calculateStateBall           ( &posGlobal, &velGlobal              );
01071     Ball.setGlobalVelocity       ( velGlobal,  getTimeLastSeeMessage() );
01072     Ball.setGlobalPosition       ( posGlobal,  getTimeLastSeeMessage() );
01073     Ball.setGlobalPositionLastSee( posGlobal,  getTimeLastSeeMessage() );
01074     return true;
01075   }
01076   else if( SoccerTypes::isKnownPlayer( o )  )
01077   {
01078     calculateStatePlayer( o, &posGlobal, &velGlobal );
01079 
01080     PlayerObject *pob = (PlayerObject*) getObjectPtrFromType( o );
01081 
01082     // the time of the velocity does not have to be set, since it equals
01083     // the time the last change information has been set.
01084     pob->setGlobalVelocity       ( velGlobal, getTimeLastSeeMessage() );
01085     pob->setGlobalPosition       ( posGlobal, getTimeLastSeeMessage() );
01086     pob->setGlobalPositionLastSee( posGlobal, getTimeLastSeeMessage() );
01087 
01088     if( pob->getTimeRelativeAngles() == getTimeLastSeeMessage() )
01089     {
01090       AngDeg ang = getAgentGlobalNeckAngle() + pob->getRelativeBodyAngle();
01091       ang = VecPosition::normalizeAngle( ang );
01092       pob->setGlobalBodyAngle( ang, getTimeLastSeeMessage() );
01093       pob->setGlobalBodyAngleLastSee( ang );
01094       ang = getAgentGlobalNeckAngle() + pob->getRelativeNeckAngle();
01095       ang = VecPosition::normalizeAngle( ang );
01096       pob->setGlobalNeckAngle( ang, getTimeLastSeeMessage() );
01097       pob->setGlobalVelocityLastSee( velGlobal );          
01098     }
01099     return true;
01100   }
01101 
01102   return false;
01103 }
01104 
01105 
01106 /*****************************************************************************/
01107 /******************* SENSE RELATED UPDATES ***********************************/
01108 /*****************************************************************************/
01109 
01110 void WorldModel::processLastSenseMessage( )
01111 {
01112   char   *strMsg = strLastSenseMessage ;
01113 
01114   Parse::parseFirstInt( &strMsg );// get time
01115   strMsg++;                                      // go to ( before view_mode
01116 
01117   Parse::gotoFirstOccurenceOf( ' ', &strMsg );   // skip view_mode
01118   strMsg++;                                      // skip space
01119 
01120   ViewQualityT vq = SoccerTypes::getViewQualityFromStr( strMsg );// get quality
01121   Parse::gotoFirstOccurenceOf( ' ', &strMsg );
01122   strMsg++;                                      // skip space; get view_angle
01123   ViewAngleT va = SoccerTypes::getViewAngleFromStr( strMsg );
01124   double dStamina = Parse::parseFirstDouble( &strMsg );  // get stamina
01125   double dEffort  = Parse::parseFirstDouble( &strMsg );  // get effort
01126 
01127   double dSpeed   = Parse::parseFirstDouble( &strMsg );  // get speed
01128   AngDeg angSpeed = Parse::parseFirstDouble( &strMsg );  // get speed ang
01129 
01130   // minus sign since we store angle between neck and body and not vice versa
01131   int iHeadAngle = - Parse::parseFirstInt( &strMsg );    // get head_angle
01132 
01133   // set all number of performed commands
01134   setNrOfCommands( CMD_KICK       , Parse::parseFirstInt( &strMsg ) );
01135   setNrOfCommands( CMD_DASH       , Parse::parseFirstInt( &strMsg ) );
01136   setNrOfCommands( CMD_TURN       , Parse::parseFirstInt( &strMsg ) );
01137   setNrOfCommands( CMD_SAY        , Parse::parseFirstInt( &strMsg ) );
01138   setNrOfCommands( CMD_TURNNECK   , Parse::parseFirstInt( &strMsg ) );
01139   setNrOfCommands( CMD_CATCH      , Parse::parseFirstInt( &strMsg ) );
01140   setNrOfCommands( CMD_MOVE       , Parse::parseFirstInt( &strMsg ) );
01141   setNrOfCommands( CMD_CHANGEVIEW , Parse::parseFirstInt( &strMsg ) );
01142   int    iArmMovable = Parse::parseFirstInt( &strMsg );         // arm movable
01143   int    iArmExpires = Parse::parseFirstInt( &strMsg );         // arm expires
01144   double dArmDist    = Parse::parseFirstDouble( &strMsg );      // arm dist
01145   AngDeg angArm      = Parse::parseFirstDouble( &strMsg );       // arm dir 
01146 
01147   setNrOfCommands( CMD_POINTTO    , Parse::parseFirstInt( &strMsg ) );// count
01148 
01149   // focus target can be none (no integer) so check this
01150   int i = Parse::parseFirstInt( &strMsg );
01151   char c = (i >= 10 ) ? *(strMsg-4) : *(strMsg-3);
01152   Log.log( 602, "focus %d |%c|", i, c );
01153   if( c == 'l' || c == 'r' )    // target l or r
01154   {
01155     Log.log( 602, "set focus: %d", 
01156                     SoccerTypes::getTeammateObjectFromIndex( -1 + i ) );
01157     setObjectFocus( SoccerTypes::getTeammateObjectFromIndex( -1 + i ) );
01158     i = Parse::parseFirstInt( &strMsg );
01159   }
01160   setNrOfCommands( CMD_ATTENTIONTO , i );
01161   
01162   int iTackleExpires = Parse::parseFirstInt( &strMsg );   // tackle expires
01163   setNrOfCommands( CMD_TACKLE , Parse::parseFirstInt( &strMsg ) );
01164 
01165   angArm = VecPosition::normalizeAngle( angArm );
01166   processNewAgentInfo( vq, va, dStamina, dEffort, dSpeed,
01167         (AngDeg) angSpeed, (AngDeg)iHeadAngle, iTackleExpires,
01168          iArmMovable, iArmExpires, VecPosition( dArmDist, angArm, POLAR ));
01169 }
01170 
01179 bool WorldModel::updateAfterSenseMessage( )
01180 {
01181   processLastSenseMessage( );
01182 
01183   // update agent information
01184   updateAgentAndBallAfterSense( );
01185 
01186   // update all global information of players that have a good confidence
01187   double dConfThr = PS->getPlayerConfThr();
01188   int    iIndex;
01189     
01190   for( ObjectT o = iterateObjectStart( iIndex, OBJECT_SET_PLAYERS, dConfThr );
01191        o != OBJECT_ILLEGAL;
01192        o = iterateObjectNext ( iIndex, OBJECT_SET_PLAYERS, dConfThr ) )
01193   {
01194     if( o != getAgentObjectType() && getTimeGlobalPosition(o) > 0 &&
01195         ! isBeforeKickOff() )
01196     {
01197       updateDynamicObjectForNextCycle( o,
01198                                  getCurrentTime() - getTimeGlobalPosition(o) );
01199     }
01200   }
01201   iterateObjectDone( iIndex);
01202 
01203   // before the kick off all player information can be set to their strat. pos
01204   if( isBeforeKickOff() )
01205   {
01206     for( ObjectT o = iterateObjectStart( iIndex, OBJECT_SET_TEAMMATES, -2000 );
01207          o != OBJECT_ILLEGAL;
01208          o = iterateObjectNext ( iIndex, OBJECT_SET_TEAMMATES, -2000  ) )
01209    {  
01210       if( o == getAgentObjectType() )
01211         continue;
01212       PlayerObject *pob = (PlayerObject*) getObjectPtrFromType( o );
01213     
01214       VecPosition pos = getStrategicPosition( SoccerTypes::getIndex( o )  ) ;
01215       VecPosition vel( 0, 0 );
01216 
01217       pob->setGlobalVelocity       ( vel, getTimeLastSenseMessage() );
01218       pob->setGlobalPosition       ( pos, getTimeLastSenseMessage() );
01219       pob->setGlobalPositionLastSee( pos, getTimeLastSenseMessage() );    
01220       pob->setTimeLastSeen         ( getTimeLastSenseMessage() - 2 );    
01221       updateObjectRelativeFromGlobal( o );
01222       Log.log( 459, "set info %d (%f,%f)", SoccerTypes::getIndex( o ),
01223         pos.getX(), pos.getY() );
01224     }
01225     Ball.setGlobalPosition( VecPosition(0,0), getTimeLastSenseMessage() );
01226     Ball.setGlobalVelocity( VecPosition(0,0), getTimeLastSenseMessage() );
01227   }
01228 //    show( OBJECT_SET_PLAYERS, Log.getOutputStream() );  
01229   iterateObjectDone( iIndex);
01230 
01231   return true;
01232 }
01233 
01239 bool WorldModel::updateAgentAndBallAfterSense( )
01240 {
01241   // get info from commands from previous cycle (if timestopped current cycle)
01242   bool        bBallUpdated   = false;
01243   VecPosition pos            = getAgentGlobalPosition();
01244   AngDeg      angGlobalNeck  = getAgentGlobalNeckAngle();
01245   AngDeg      angGlobalBody  = getAgentGlobalBodyAngle();
01246   Stamina     sta            = getAgentStamina();
01247   VecPosition velNeck        = agentObject.getSpeedRelToNeck(); // !!
01248   VecPosition vel            = getAgentGlobalVelocity();
01249   Time        time           = getCurrentTime() - 1 ;
01250 
01251   // first update information based on performed actions without using
01252   // the received velocity information.
01253   for( int i = 0; i < CMD_MAX_COMMANDS; i ++  )
01254   {
01255     if( performedCommands[i] == true && // sense msg indicates we executed this
01256         ( queuedCommands[i].time.getTime() == time.getTime() ||      // no hole
01257           queuedCommands[i].time.getTime() == time.getTime() - 1 ) )// hole
01258     {
01259       switch( queuedCommands[i].commandType )
01260       {
01261         case CMD_TURN:
01262         case CMD_TURNNECK:
01263         case CMD_DASH:
01264         case CMD_TACKLE: // in case of tackle do not update ball -> we do not
01265                          // know whether tackle succeeded
01266           predictStateAfterCommand( queuedCommands[i], &pos, &vel,
01267                                     &angGlobalBody, &angGlobalNeck, 
01268                                     getAgentObjectType(), &sta );
01269           break;
01270         case CMD_KICK:
01271           updateBallAfterKick( queuedCommands[i] );
01272           bBallUpdated     = true;         // should not be updated later on.
01273           queuedCommands[i].time.updateTime( -1 );
01274           break;
01275         case CMD_MOVE:
01276           pos.setVecPosition( queuedCommands[i].dX, queuedCommands[i].dY );
01277           initParticlesAgent( pos );
01278           break;
01279         default:
01280           break;
01281       }
01282     }
01283   }
01284 
01285   // update the ball when not done yet
01286   if( !bBallUpdated )
01287   {
01288     m_bPerformedKick = false;
01289     updateDynamicObjectForNextCycle( OBJECT_BALL, 1 );
01290   }
01291   else
01292     m_bPerformedKick = true;
01293 
01294   // now use velocity information to check whether a collision occured
01295   velNeck.rotate( angGlobalNeck ); // make relative info global
01296   double dDistBall = pos.getDistanceTo( getBallPos() );
01297 
01298   if( velNeck.getMagnitude() < EPSILON &&
01299       vel.getMagnitude() > 0.01 &&
01300       dDistBall < 0.6 )
01301     Log.log( 102, "I assume collision after kick" );
01302 
01303   if( (   
01304         velNeck.getMagnitude() < EPSILON &&
01305         vel.getMagnitude() > 0.01 &&
01306         dDistBall < 0.8
01307         ) 
01308       ||
01309     ( dDistBall<SS->getPlayerSize()+SS->getBallSize() && // ball too close AND
01310         velNeck.getMagnitude( ) < EPSILON                 // vel. gives no info
01311        )
01312      ||                                                   // OR
01313      ( dDistBall < SS->getMaximalKickDist() + 0.5  &&     // ball close
01314       velNeck.getMagnitude( ) > EPSILON &&                // can compare vel
01315       ( sign( vel.getX() ) != sign( velNeck.getX() ) ||   // both signs have
01316         fabs( vel.getX() ) < 0.08 )                &&     // changed or are
01317       ( sign( vel.getY() ) != sign( velNeck.getY() ) ||   // so small it is in
01318         fabs( vel.getY() ) < 0.08 )                &&     // error range
01319        velNeck.getMagnitude() < 0.25 * vel.getMagnitude() ) ) // lessened a lot
01320   {
01321     m_bWasCollision = true;
01322     m_timeLastCollision = getCurrentTime();
01323     double dDistPlayer;
01324     getClosestInSetTo(
01325          OBJECT_SET_PLAYERS, getAgentObjectType(), &dDistPlayer );
01326     if( dDistBall < dDistPlayer )
01327     {
01328       updateBallForCollision( pos );
01329       Log.log( 102, "COLLISION WITH BALL %f, vel(%f,%f) velNeck(%f,%f)",
01330          dDistBall, vel.getX(), vel.getY(), velNeck.getX(), velNeck.getY() );
01331     }
01332     else
01333       Log.log( 102, "COLLISION WITH PLAYER vel(%f,%f) velNeck(%f,%f)",
01334          vel.getX(), vel.getY(), velNeck.getX(), velNeck.getY() );
01335 
01336     // new vel. agent is the one received from sense message
01337     vel = velNeck;
01338   }
01339   else
01340   {
01341     if( dDistBall < SS->getVisibleDistance() )
01342       Log.log( 102, "No collision: dist: %f, velNeck (%f,%f), vel (%f,%f)",
01343         dDistBall, velNeck.getX(), velNeck.getY(), vel.getX(), vel.getY() );
01344     m_bWasCollision = false;
01345     // use better vel. estimate in sense message to update information
01346     pos            = getAgentGlobalPosition();
01347     angGlobalNeck  = getAgentGlobalNeckAngle();
01348     angGlobalBody  = getAgentGlobalBodyAngle();
01349     sta            = getAgentStamina();
01350     vel            = agentObject.getSpeedRelToNeck();
01351 
01352     // calculate velocity at end of previous cycle using velocity from
01353     // current cycle. Although we do not know direction yet (this is
01354     // relative to neck which is not yet known), we can use the
01355     // magnitude to determine traveled  distance (speed) of the agent
01356     // After neck angle is estimated, we can rotate velocity vector
01357     // to get actual velocity.
01358     vel.setMagnitude( vel.getMagnitude()/SS->getPlayerDecay() );
01359 
01360     for( int i = 0; i < CMD_MAX_COMMANDS; i ++  )
01361     {
01362       if( performedCommands[i] == true &&
01363           ( queuedCommands[i].time.getTime() == time.getTime() ||
01364             queuedCommands[i].time.getTime() == time.getTime() - 1 ) )
01365       {
01366         switch( queuedCommands[i].commandType )
01367         {
01368           case CMD_TURN:
01369           case CMD_TURNNECK:
01370             predictStateAfterCommand( queuedCommands[i], &pos, &vel,
01371                                &angGlobalBody, &angGlobalNeck, 
01372                                getAgentObjectType(), &sta );
01373             break;
01374           case CMD_MOVE:
01375             pos.setVecPosition( queuedCommands[i].dX, queuedCommands[i].dY );
01376             initParticlesAgent( pos );
01377             break;
01378           case CMD_DASH:     // no action needed, since resulting
01379                              // vel. is already available from sense
01380                              // this vel can be used to update pos
01381             break;
01382           case CMD_TACKLE:   // no action needed, we are never sure that tackle
01383                              // is executed
01384             break;
01385          default:
01386             break;
01387         }
01388       }
01389       queuedCommands[i].time.updateTime( -1 );            // processed
01390     }
01391     // reset pos and vel information to previous cycle (since can be
01392     // changed in predictStateAfterCommand)
01393     vel = agentObject.getSpeedRelToNeck();
01394     pos = getAgentGlobalPosition();
01395     vel.setMagnitude( vel.getMagnitude()/SS->getPlayerDecay() );
01396     vel.rotate( angGlobalNeck ); // rotate vel using information about neck
01397 
01398     // predict global position using the calculated vel at the end of
01399     // the previous cycle (power and direction can thus both be set
01400     // to zero). There is just little noise in this perception, so
01401     // gives a good estimate
01402     predictStateAfterDash( 0.0, &pos, &vel, &sta, 0, getAgentObjectType() );
01403   }
01404 
01405   // update particles that keep track of position of agent using vel
01406   updateParticlesAgent( vel, true );
01407 
01408   // body angle is not set since relative angle to neck is already
01409   // set after parsing sense_body message, same holds for stamina
01410   agentObject.setGlobalPosition ( pos,        getCurrentTime() );
01411   agentObject.setGlobalVelocity ( vel,        getCurrentTime() );
01412   agentObject.setGlobalNeckAngle( angGlobalNeck );
01413 
01414   return true;
01415 }
01416 
01424 bool WorldModel::updateBallAfterKick( SoccerCommand soc )
01425 {
01426   if( getRelativeDistance( OBJECT_BALL ) < SS->getMaximalKickDist() )
01427   {
01428     VecPosition posBall, velBall;
01429     predictBallInfoAfterCommand( soc, &posBall, &velBall );
01430     Ball.setGlobalPosition( posBall, getCurrentTime()  );
01431     Ball.setGlobalVelocity( velBall, getCurrentTime()  );
01432 // updateParticlesBall( particlesPosBall, particlesVelBall, 
01433 //                        iNrParticlesBall, dPower, ang );
01434   }
01435   else
01436   {
01437     updateDynamicObjectForNextCycle( OBJECT_BALL, 1 );
01438 //  updateParticlesBall( particlesPosBall, particlesVelBall, 
01439 //  iNrParticlesBall, 0, 0 );
01440 #ifdef WIN32
01441     Log.log( 21, "(WorldModel::%s) KICK command, but ball not kickable (%f)",
01442         "updateBallAfterKick", getRelativeDistance( OBJECT_BALL ) );
01443 #else
01444     Log.log( 21, "(WorldModel::%s) KICK command, but ball not kickable (%f)",
01445         __FUNCTION__, getRelativeDistance( OBJECT_BALL ) );
01446 #endif
01447   }
01448   return true;
01449 }
01450 
01457 bool WorldModel::updateDynamicObjectForNextCycle( ObjectT obj, int iCycles)
01458 {
01459   DynamicObject *o = (DynamicObject*) getObjectPtrFromType( obj );
01460   if( o == NULL )
01461     return false;
01462 
01463   // get velocity and add it to current global position
01464   VecPosition vel = getGlobalVelocity( obj );
01465   VecPosition pos = getGlobalPosition( obj );
01466   VecPosition posBall = getBallPos();
01467   //  ObjectT objFastest =  getFastestInSetTo( OBJECT_SET_TEAMMATES, 
01468   //                                       OBJECT_BALL );
01469   if( SoccerTypes::isBall( obj ) )
01470   {
01471     for( int i = 0; i < iCycles ; i++ )
01472     {
01473       pos += vel;
01474       vel *= SS->getBallDecay();
01475     }
01476     double  dDist;
01477     ObjectT objOpp =
01478         getClosestInSetTo( OBJECT_SET_OPPONENTS, OBJECT_BALL, &dDist );
01479     if( objOpp != OBJECT_ILLEGAL &&
01480         pos.getDistanceTo( getGlobalPosition( objOpp ) )
01481                            < getMaximalKickDist( objOpp ) )
01482     {
01483       Log.log( 556, "update dyn. obj; set ball velocity to 0, opp has it" );
01484       vel.setVecPosition(0,0);
01485     }
01486   }
01487   else if( SoccerTypes::isTeammate( obj ) && 
01488            obj != OBJECT_TEAMMATE_1 && getPlayMode() == PM_PLAY_ON )
01489   {
01490     for( int i = 0; i < iCycles ; i++ )
01491     {
01492       // no idea of intention opponent, just let him roll out
01493       pos += vel;
01494       vel *= SS->getPlayerDecay();
01495     }
01496   }
01497   else if( SoccerTypes::isOpponent( obj ) )
01498   {
01499     VecPosition velBall = getGlobalVelocity( OBJECT_BALL );
01500     for( int i = 0; i < iCycles ; i++ )
01501     {
01502       // no idea of intention opponent, just let him roll out
01503       if( obj == getOppGoalieType() )
01504   ;
01505       // if it is the fastest opponent, move him towards ball
01506       else if( obj == getFastestInSetTo( OBJECT_SET_OPPONENTS, OBJECT_BALL ) )
01507       {
01508   AngDeg ang = (getBallPos()-getGlobalPosition( obj )).getDirection();
01509   pos += VecPosition( 0.3, ang, POLAR );
01510   vel *= SS->getPlayerDecay();
01511   Log.log( 556, "update fastest opp to (%f,%f) cyc %d", 
01512      pos.getX(), pos.getY(), iCycles );     
01513       }
01514       else if( velBall.getX() > 0 && ! ( isDeadBallUs() || isDeadBallThem() ) 
01515          && ! ( fabs( pos.getX() ) > PENALTY_X + 5 ) )
01516       {
01517   pos += VecPosition( (velBall.getX() > 1.0) ? 0.5 : 0.25, 0 );
01518   vel *= SS->getPlayerDecay();
01519       }
01520       else if( ! ( isDeadBallUs() || isDeadBallThem() )
01521          && ! ( fabs( pos.getX() ) > PENALTY_X + 5 ) )
01522       {
01523   //     pos += vel;
01524   pos -= VecPosition( (velBall.getX() < -1.0 ) ? 0.5 : 0.25, 0 );
01525   vel *= SS->getPlayerDecay();
01526       }
01527     }
01528   }
01529 
01530   o->setGlobalVelocity ( vel, getCurrentTime() );
01531   o->setGlobalPosition ( pos, getCurrentTime() );
01532 
01533   return true;
01534 }
01535 
01536 
01541 bool WorldModel::updateBallForCollision( VecPosition posAgent )
01542 {
01543   VecPosition posBall  = getGlobalPosition( OBJECT_BALL );
01544   VecPosition velBall  = getGlobalVelocity( OBJECT_BALL );
01545 
01546   // get the direction the ball was coming from and put it at small distance
01547   // and multiply the velocity with -0.1
01548   AngDeg ang = (posBall - posAgent).getDirection();
01549   Ball.setGlobalPosition( posAgent + VecPosition( 0.2, ang, POLAR ),
01550                             getCurrentTime() );
01551   Ball.setGlobalVelocity( velBall*-0.1, getCurrentTime() );
01552   Log.log( 102, "updateBallForCollision; vel from (%f,%f) to (%f,%f)",
01553         velBall.getX(), velBall.getY(), getGlobalVelocity(OBJECT_BALL).getX(),
01554         getGlobalVelocity(OBJECT_BALL).getY() );
01555   return true;
01556 }
01557 
01563 bool WorldModel::updateRelativeFromGlobal()
01564 {
01565   double dConfThr = PS->getPlayerConfThr();
01566   int    iIndex;
01567 
01568   // update all player objects
01569   for( ObjectT o = iterateObjectStart( iIndex, OBJECT_SET_PLAYERS, dConfThr );
01570        o != OBJECT_ILLEGAL;
01571        o = iterateObjectNext ( iIndex, OBJECT_SET_PLAYERS, dConfThr ) )
01572   {
01573     if( o != getAgentObjectType() )
01574       updateObjectRelativeFromGlobal( o );
01575   }
01576   iterateObjectDone( iIndex);
01577 
01578   // and also the ball
01579   if( isConfidenceGood( OBJECT_BALL ) )
01580     updateObjectRelativeFromGlobal( OBJECT_BALL );
01581 
01582   // flags and lines are not updated, since they are not used except
01583   // immediately after see message when they're up to date.
01584   return true;
01585 }
01586 
01592 bool WorldModel::updateObjectRelativeFromGlobal( ObjectT o )
01593 {
01594   Object *obj = (Object*) getObjectPtrFromType( o );
01595   if( obj == NULL )
01596     return false;
01597 
01598   // get global position and translate and rotate it to agent neck
01599   VecPosition rel = obj->getGlobalPosition();
01600   rel.globalToRelative( getAgentGlobalPosition(), getAgentGlobalNeckAngle() );
01601   obj->setRelativePosition( rel, obj->getTimeGlobalPosition() );
01602   return true;
01603 }
01604 
01613 bool WorldModel::calculateStateAgent( VecPosition *posGlobal,
01614                      VecPosition *velGlobal, AngDeg *angGlobal )
01615 {
01616   int    iNrLeft;
01617 
01618   // first determine global neck angle
01619   ObjectT objLine = getFurthestRelativeInSet( OBJECT_SET_LINES );
01620   if( objLine != OBJECT_ILLEGAL )
01621   {
01622     double angGlobalLine = getGlobalAngle  ( objLine );
01623     AngDeg angRelLine    = getRelativeAngle( objLine );
01624     *angGlobal           = angGlobalLine - angRelLine;
01625     *angGlobal           = VecPosition::normalizeAngle( *angGlobal );
01626   }
01627   else
01628   {
01629     Log.log( 21, 
01630              "(WorldModel::calculateStateAgent) no line in last see message" );
01631     *angGlobal           = getAgentGlobalNeckAngle();
01632   }
01633 
01634   // use global neck angle to determine estimate of current global velocity
01635   // neck angle is better estimate than after sense -> better estimate velocity
01636   // update all position particles of the agent with this velocity
01637   //  'false' denotes update after see message. Since global neck angle can
01638   //  be determined more precise after 'see' it is better to predict position
01639   //  again (although it was already done after sense)
01640   // and then check which particles are possible given current perceptions
01641   *velGlobal = agentObject.getSpeedRelToNeck().rotate( *angGlobal );
01642   velGlobal->setMagnitude( velGlobal->getMagnitude()/SS->getPlayerDecay() );
01643 
01644   updateParticlesAgent          ( *velGlobal, false );
01645   iNrLeft = checkParticlesAgent ( *angGlobal        );
01646 
01647   if( iNrLeft == 0 ) // if no particles left, initialize all particles
01648   {
01649     // initialize particles (from random samples using closest flag)
01650     // check particles are then checked with other flags
01651     initParticlesAgent ( *angGlobal );
01652     iNrLeft = checkParticlesAgent( *angGlobal );
01653     if( iNrLeft == 0 )
01654     {
01655       // not succeeded, use second method (weighted average flags)
01656       // and initialize all particles to this position
01657       calculateStateAgent2( posGlobal, velGlobal, angGlobal );
01658       initParticlesAgent( *posGlobal );
01659       return false;
01660     }
01661   }
01662 
01663   // determine global position (= average of all particles)
01664   // and resample all particles
01665   *posGlobal = averageParticles( particlesPosAgent, iNrLeft );
01666   resampleParticlesAgent( iNrLeft );
01667 
01668   // use the position to calculate better global neck angle of the agent
01669   // and recalculate global velocity with improved neck angle
01670   AngDeg ang = calculateAngleAgentWithPos( *posGlobal );
01671   if( ang != UnknownAngleValue )
01672     *angGlobal = ang;
01673 
01674   *velGlobal = agentObject.getSpeedRelToNeck().rotate(*angGlobal);
01675   return true;
01676 }
01677 
01685 void WorldModel::initParticlesAgent( AngDeg angGlobal )
01686 {
01687   double  dDist, dMaxRadius, dMinRadius, dInput;
01688   AngDeg  ang;
01689 
01690   // get closest flag from which samples will be generated
01691   ObjectT objFlag = getClosestRelativeInSet( OBJECT_SET_FLAGS );
01692 
01693  if( objFlag == OBJECT_ILLEGAL )
01694  {
01695     Log.log( 21, "(WorldModel::%s) no flag in last see message",
01696        "initParticlesAgent" );
01697     return;
01698  }
01699 
01700   // get the distance to this flag and the possible range it was derived from.
01701   dInput = getRelativeDistance( objFlag );
01702   getMinMaxDistQuantizeValue( dInput, &dMinRadius, &dMaxRadius,
01703                                                SS->getQuantizeStepL(), 0.1 ) ;
01704 
01705   // get the perceived angle to this flag (add 180 to get angle relative from
01706   // flag to agent ) and make it global by adding global neck angle agent.
01707   AngDeg angFlag   = getRelativeAngle( objFlag ) + 180 + angGlobal ;
01708   // for all particles
01709   for( int i = 0 ; i < iNrParticlesAgent ; i++ )
01710   {
01711     // determine random point from distance range and
01712     // determine random point from the range it could be generated from
01713     // angles are rounded and since noise is in global neck angle and relative
01714     // angle flag, maximum error is in range [-0.5,0.5] + [-0.5,0.5] = [-1,1].
01715     dDist = dMinRadius + drand48()*(dMaxRadius-dMinRadius);
01716     ang   = VecPosition::normalizeAngle( angFlag - 1.0 + 2*drand48() );
01717 
01718     // create random point from possible interval
01719     particlesPosAgent[i] = getGlobalPosition( objFlag ) +
01720                            VecPosition( dDist, ang, POLAR );
01721   }
01722 }
01723 
01729 void WorldModel::initParticlesAgent( VecPosition posInitial )
01730 {
01731   for( int i = 0 ; i < iNrParticlesAgent ; i++ )
01732     particlesPosAgent[i] = posInitial;
01733 }
01734 
01744 int WorldModel::checkParticlesAgent( AngDeg angGlobalNeck  )
01745 {
01746   double dMaxRadius, dMinRadius, dInput, dDist;
01747   AngDeg ang;
01748   int    iIndex, iNrLeft = iNrParticlesAgent, iLength = iNrParticlesAgent;
01749 
01750   // for all current perceived flags
01751   for( ObjectT o = iterateObjectStart( iIndex, OBJECT_SET_FLAGS, 1.0 );
01752        o != OBJECT_ILLEGAL;
01753        o = iterateObjectNext ( iIndex, OBJECT_SET_FLAGS, 1.0 ) )
01754   {
01755     iNrLeft = 0;                        // reset number of correct particles
01756     dInput = getRelativeDistance( o );  // get possible distance range
01757     getMinMaxDistQuantizeValue( dInput, &dMinRadius, &dMaxRadius,
01758                                     SS->getQuantizeStepL(), 0.1 )  ;
01759 
01760     // find all "correct points"
01761     for( int i = 0; i < iLength; i ++ )
01762     {
01763       // determine distance particle to flag
01764       // determine difference in direction between direction between global
01765       // flag and agent position and global perceived direction
01766       dDist = particlesPosAgent[i].getDistanceTo( getGlobalPosition( o ) );
01767       ang = (getGlobalPosition(o) - particlesPosAgent[i]).getDirection();
01768       ang = ang - ( getRelativeAngle( o ) + angGlobalNeck );
01769 
01770       // if in possible range, save it (maximum angle range is 0.5 for
01771       // neck angle and 0.5 for relative flag angle gives 1.0)
01772       if( dDist > dMinRadius && dDist < dMaxRadius &&
01773           fabs(VecPosition::normalizeAngle( ang )) <= 1.0 )
01774         particlesPosAgent[iNrLeft++] = particlesPosAgent[i];
01775     }
01776     // change maximum of correct particles
01777     iLength = iNrLeft;
01778   }
01779   return iNrLeft;
01780 }
01781 
01792 void WorldModel::updateParticlesAgent( VecPosition vel, bool bAfterSense )
01793 {
01794   // used to denote last added velocity
01795   static VecPosition prev_vel;
01796 
01797   for( int i = 0; i < iNrParticlesAgent  ; i ++ )
01798   {
01799     if( bAfterSense == false ) // if after see, subtract last added 'vel'
01800     {
01801       particlesPosAgent[i].setX( particlesPosAgent[i].getX()-prev_vel.getX());
01802       particlesPosAgent[i].setY( particlesPosAgent[i].getY()-prev_vel.getY());
01803     }
01804 
01805     particlesPosAgent[i].setX( particlesPosAgent[i].getX( ) + vel.getX() );
01806     particlesPosAgent[i].setY( particlesPosAgent[i].getY( ) + vel.getY() );
01807   }
01808   prev_vel = vel;
01809 }
01810 
01811 
01816 VecPosition WorldModel::averageParticles( VecPosition posArray[], int iLength )
01817 {
01818   if( iLength == 0 )
01819     return VecPosition( UnknownDoubleValue, UnknownDoubleValue );
01820 
01821   // take average of particles
01822   double x = 0, y = 0;
01823   for( int i = 0; i < iLength  ; i ++ )
01824   {
01825      x += posArray[ i ].getX( );
01826      y += posArray[ i ].getY( );
01827   }
01828 
01829   return VecPosition( x/iLength, y/iLength );
01830 }
01831 
01838 void WorldModel::resampleParticlesAgent( int iLeft )
01839 {
01840   for ( int i = iLeft; i < iNrParticlesAgent; i ++ )
01841     particlesPosAgent[ i ] = particlesPosAgent[ (int)(drand48()*iLeft) ];
01842 }
01843 
01852 bool WorldModel::calculateStateAgent2( VecPosition *posGlobal,
01853                                    VecPosition *velGlobal, AngDeg *angGlobal)
01854 {
01855   double      x=0.0, y=0.0, dMinRadius1, dMaxRadius1, dMinRadius2, dMaxRadius2;
01856   double      dTotalVar = UnknownDoubleValue, dVar, K;
01857   int         iIndex1, iIndex2;
01858   ObjectT     obj2;
01859   VecPosition pos;
01860 
01861   // for all flags that were perceived in last see message
01862   for( ObjectT obj1 = iterateObjectStart( iIndex1, OBJECT_SET_FLAGS, 1.0 );
01863        obj1 != OBJECT_ILLEGAL;
01864        obj1 = iterateObjectNext ( iIndex1, OBJECT_SET_FLAGS, 1.0 ) )
01865   {
01866     // calculate global position with all other flags using two flags
01867     iIndex2 = iIndex1;
01868     for( obj2 = iterateObjectNext ( iIndex2, OBJECT_SET_FLAGS, 1.0 ) ;
01869          obj2 != OBJECT_ILLEGAL;
01870          obj2 = iterateObjectNext ( iIndex2, OBJECT_SET_FLAGS, 1.0 ) )
01871     {
01872       // calculate the position using the two flags
01873       pos = calculatePosAgentWith2Flags( obj1, obj2 );
01874 
01875       // get distance range from which perceived value can originate from
01876       // calculate variance (=weighted factor) based on the distance to the
01877       // two flags, use variance corresponding to uniform distribution
01878       // this is not completely correct, better would be to use the
01879       // intersection area size of the two circle, but is too computational
01880       // intensive
01881       getMinMaxDistQuantizeValue(getRelativeDistance(obj1),
01882                  &dMinRadius1, &dMaxRadius1, SS->getQuantizeStepL(), 0.1 )  ;
01883       getMinMaxDistQuantizeValue(getRelativeDistance(obj2),
01884                  &dMinRadius2, &dMaxRadius2, SS->getQuantizeStepL(), 0.1 )  ;
01885       dVar =  (dMaxRadius1-dMinRadius1)*(dMaxRadius1-dMinRadius1)/12;
01886       dVar += (dMaxRadius2-dMinRadius2)*(dMaxRadius2-dMinRadius2)/12;
01887 
01888       if( pos.getX() != UnknownDoubleValue &&
01889           dTotalVar  == UnknownDoubleValue )
01890       {
01891         dTotalVar = dVar;                     // initialize the position
01892         x         = pos.getX();
01893         y         = pos.getY();
01894       }
01895       else if( pos.getX() != UnknownDoubleValue )
01896       {
01897         K = dTotalVar / ( dVar + dTotalVar ); // otherwise use new position
01898         x += K*( pos.getX() - x );            // based on weighted variance
01899         y += K*( pos.getY() - y );
01900         dTotalVar -= K*dTotalVar;
01901       }
01902     }
01903     iterateObjectDone( iIndex2 );
01904   }
01905   iterateObjectDone( iIndex1 );
01906   posGlobal->setVecPosition( x, y );
01907 
01908   // now calculate global position (experiments show best results are obtained
01909   // when average with all perceived flags is taken).
01910   *angGlobal = calculateAngleAgentWithPos( *posGlobal );
01911 
01912   // update velocity since after 'see' we have a better estimate of neck angle
01913   *velGlobal = agentObject.getSpeedRelToNeck().rotate(*angGlobal);
01914 
01915   return true;
01916 }
01917 
01927 bool WorldModel::calculateStateAgent3( VecPosition *posGlobal,
01928                                     VecPosition *velGlobal, AngDeg *angGlobal )
01929 {
01930   // first determine the two closest flags
01931   ObjectT objFlag1 = getClosestRelativeInSet( OBJECT_SET_FLAGS );
01932   ObjectT objFlag2 = getSecondClosestRelativeInSet( OBJECT_SET_FLAGS );
01933   ObjectT objLine = getFurthestRelativeInSet( OBJECT_SET_LINES );
01934 
01935   // first determine global neck angle with furthest line (max. error is 0.5)
01936   if( objLine != OBJECT_ILLEGAL )
01937   {
01938     double angGlobalLine = getGlobalAngle  ( objLine );
01939     AngDeg angRelLine    = getRelativeAngle( objLine );
01940     *angGlobal           = angGlobalLine - angRelLine;
01941     *angGlobal           = VecPosition::normalizeAngle( *angGlobal );
01942   }
01943 
01944   // if two flags were seen in last see message
01945   //   calculate global position using two closest flags (Cosinus rule)
01946   //     except when rel angle flags is smaller than 8 (gives bad results)
01947   //       except when no line is seen
01948   if( objFlag1 != OBJECT_ILLEGAL && objFlag2 != OBJECT_ILLEGAL &&
01949       (
01950          fabs(getRelativeAngle(objFlag1) - getRelativeAngle(objFlag2)) > 8.0
01951          || objLine == OBJECT_ILLEGAL
01952       ) )
01953   {
01954     *posGlobal = calculatePosAgentWith2Flags( objFlag1, objFlag2 );
01955   }
01956   else if( objFlag1 != OBJECT_ILLEGAL && objLine != OBJECT_ILLEGAL )
01957   {
01958     // calculate global position as follows:
01959     //   - get the global position of the closest flag
01960     //   - get the rel vector to this flag using global neck angle
01961     //   - global position = global pos flag - relative vector
01962 
01963     VecPosition posGlobalFlag = getGlobalPosition( objFlag1 );
01964     VecPosition relPosFlag    = VecPosition::getVecPositionFromPolar(
01965       getRelativeDistance( objFlag1 ),
01966       *angGlobal + getRelativeAngle( objFlag1 ) );
01967     *posGlobal                = posGlobalFlag - relPosFlag;
01968   }
01969   else
01970   {
01971     cout << "(WorldModel::calculateStateAgent3) cannot determine pos in cycle "
01972          << getCurrentCycle() << endl;
01973     return false;
01974   }
01975 
01976   // calculate global velocity using the absolute neck angle
01977   *velGlobal = agentObject.getSpeedRelToNeck().rotate(*angGlobal);
01978 
01979   return true;
01980 }
01981 
01993 VecPosition WorldModel::calculatePosAgentWith2Flags( ObjectT objFlag1,
01994                                                      ObjectT objFlag2 )
01995 {
01996     double      xA, yA, xB, yB, rA, rB;
01997     AngDeg      aA, aB;
01998 
01999     // get all information of the two flags
02000     xA = getGlobalPosition  ( objFlag1 ).getX();
02001     yA = getGlobalPosition  ( objFlag1 ).getY();
02002     rA = getRelativeDistance( objFlag1 );
02003     aA = getRelativeAngle   ( objFlag1 );
02004     xB = getGlobalPosition  ( objFlag2 ).getX();
02005     yB = getGlobalPosition  ( objFlag2 ).getY();
02006     rB = getRelativeDistance( objFlag2 );
02007     aB = getRelativeAngle   ( objFlag2 );
02008 
02009     double      L, dx, dy, d_par, d_orth;
02010     double      x, y;
02011     // Sign is like this 'because' y-axis increases from top to bottom
02012     double sign = ((aB - aA) > 0.0) ? 1.0 : -1.0;
02013 
02014     // From Cosinus rule: rB rB = L L + rA rA - 2 L rA cos(aB)
02015     // with:              rA cos(aB) = d_par
02016     // and:               d_par^2 + d_orth^2 = rA^2
02017     // Finally:
02018     // Position from landmark position and vectors parallel and orthogonal
02019     // to line from landmark A to B
02020 
02021     dx = xB - xA;
02022     dy = yB - yA;
02023     L = sqrt(dx*dx + dy*dy);                   // distance between two flags
02024 
02025     dx /= L; dy /= L;                          // normalize
02026 
02027     d_par = (L*L + rA*rA - rB*rB) / (2.0 * L); // dist from flag1 to orth proj
02028     double arg = rA*rA - d_par*d_par;
02029     d_orth = (arg > 0.0) ? sqrt(arg) : 0.0;
02030 
02031     x = xA + d_par * dx - sign * d_orth * dy;
02032     y = yA + d_par * dy + sign * d_orth * dx;
02033 
02034     return VecPosition( x, y );
02035 }
02036 
02048 AngDeg WorldModel::calculateAngleAgentWithPos( VecPosition pos )
02049 {
02050   int    iNrFlags = 0, iIndex;
02051   double dCosX=0, dSinX=0 ,dAngleNow, xA, yA, aA;
02052 
02053   for( ObjectT obj = iterateObjectStart( iIndex, OBJECT_SET_FLAGS, 1.0 );
02054        obj != OBJECT_ILLEGAL;
02055        obj = iterateObjectNext ( iIndex, OBJECT_SET_FLAGS, 1.0 ) )
02056   {
02057     xA = getGlobalPosition( obj ).getX();
02058     yA = getGlobalPosition( obj ).getY();
02059     aA = getRelativeAngle( obj );
02060 
02061     // calculate global direction between flag and agent
02062     // calculate global neck angle by subtracting relative angle to flag
02063     dAngleNow = atan2Deg( yA - pos.getY(), xA - pos.getX() );
02064     dAngleNow = VecPosition::normalizeAngle( dAngleNow - aA );
02065 
02066     // add cosine part of angle and sine part separately; this to avoid
02067     // boundary problem when computing average angle (average of -176 and
02068     // 178 equals -179 and not 1).
02069     dCosX += cosDeg( dAngleNow );
02070     dSinX += sinDeg( dAngleNow );
02071     iNrFlags++;
02072 
02073   }
02074   iterateObjectDone( iIndex );
02075 
02076   // calculate average cosine and sine part and determine corresponding angle
02077   dCosX /= (double)iNrFlags;
02078   dSinX /= (double)iNrFlags;
02079   if( iNrFlags == 0 )
02080     return UnknownAngleValue;
02081 
02082   return VecPosition::normalizeAngle( atan2Deg( dSinX, dCosX  ) )  ;
02083 }
02084 
02085 
02091 VecPosition WorldModel::calculateVelocityDynamicObject( ObjectT o )
02092 {
02093   DynamicObject * dobj = (DynamicObject*) getObjectPtrFromType( o );
02094   if( dobj == NULL )
02095     return VecPosition( UnknownDoubleValue, UnknownDoubleValue );
02096   double dDistCh = dobj->getRelativeDistanceChange(   );
02097   double angCh   = dobj->getRelativeAngleChange   (   );
02098   double dDist   = getRelativeDistance            ( o );
02099   double ang     = getRelativeAngle               ( o );
02100 
02101   double velx = dDistCh * cosDeg(ang) - Deg2Rad(angCh) * dDist * sinDeg( ang );
02102   double vely = dDistCh * sinDeg(ang) + Deg2Rad(angCh) * dDist * cosDeg( ang );
02103 
02104   VecPosition vel( velx, vely );
02105   return vel.relativeToGlobal( getAgentGlobalVelocity(),
02106                                getAgentGlobalNeckAngle() );
02107 }
02108 
02109 
02115 bool WorldModel::calculateStateBall( VecPosition *posGlobal,
02116                                      VecPosition *velGlobal )
02117 {
02118   // set the global position of the ball as follows:
02119   //  - get the relative position from the agent to it in world-axis
02120   //  - add global position agent to this relative position
02121   VecPosition posRelWorld =
02122       VecPosition( getRelativeDistance( OBJECT_BALL ),
02123                    getRelativeAngle( OBJECT_BALL ) + getAgentGlobalNeckAngle(),
02124                    POLAR );
02125   *posGlobal = getAgentGlobalPosition() + posRelWorld;
02126 
02127   if( isBeforeKickOff() )
02128   {
02129     posGlobal->setVecPosition( 0, 0 );
02130     velGlobal->setVecPosition( 0, 0 );
02131     return true;
02132   }
02133 
02134   *velGlobal = getGlobalVelocity(OBJECT_BALL);
02135   if( Ball.getTimeChangeInformation( ) == getTimeLastSeen( OBJECT_BALL ) )
02136   {
02137     *velGlobal = calculateVelocityDynamicObject( OBJECT_BALL );;
02138     Log.log( 458, "vel based on change info: (%f,%f)", velGlobal->getX(),
02139                           velGlobal->getY() );
02140     // average result with predicted velocity from last see message
02141     // this has the best result for the ball: see program absvelocity.C
02142     // only use average when no big chance (kick,turn or dash) has occured
02143     if( fabs(velGlobal->getX() - getGlobalVelocity(OBJECT_BALL).getX())
02144                                       <= 2*SS->getBallRand()*getBallSpeed() &&
02145         fabs(velGlobal->getY() - getGlobalVelocity(OBJECT_BALL).getY())
02146                                       <= 2*SS->getBallRand()*getBallSpeed() )
02147     {
02148       *velGlobal = (*velGlobal + getGlobalVelocity(OBJECT_BALL))/2.0;
02149       Log.log( 458, "average ball vel to (%f,%f)", velGlobal->getX(),
02150                           velGlobal->getY() );
02151     }
02152   }
02153   else if( getRelativeDistance(OBJECT_BALL) < SS->getVisibleDistance() &&
02154            getTimeLastSeeMessage() - Ball.getTimeGlobalPosDerivedFromSee() < 3)
02155   {
02156     // no change information but have got feel info -> use position based vel.
02157     // get the difference with the previous known global position
02158     // and subtract the position difference (this difference is caused by
02159     // the fact that the global position calculation contains a lot of noise
02160     // now the noise is filtered, since we compare the velocity as if its
02161     // position was seen "with the noise" of the last cycle).
02162 
02163     VecPosition posGlobalDiff   = *posGlobal - Ball.getGlobalPositionLastSee()
02164                                          - agentObject.getPositionDifference();
02165     Log.log( 101, "2 pos: ball(%f,%f), ball_prev(%f,%f), agentdiff(%f,%f)",
02166         posGlobal->getX(), posGlobal->getY(),
02167         Ball.getGlobalPositionLastSee().getX(),
02168         Ball.getGlobalPositionLastSee().getY(),
02169         agentObject.getPositionDifference().getX(),
02170         agentObject.getPositionDifference().getY() );
02171 
02172     // difference in global positions is distance traveled, we have to make
02173     // distinction whether this distance is traveled in one or two cycles.
02174     // 1 cycle:
02175     //   distance difference equals last velocity so only have to multiply with
02176     //   decay
02177     // 2 cycles:
02178     //   do not update, since kick can be performed causing large change
02179     //   of which we have no see information (so thus use sense update)
02180 
02181     if( getTimeLastSeeMessage() - Ball.getTimeGlobalPosDerivedFromSee() == 1 &&
02182         m_bWasCollision == false )
02183     {
02184       *velGlobal = posGlobalDiff*SS->getBallDecay();
02185       Log.log( 458, "vel based on 2 pos: (%f,%f)", velGlobal->getX(),
02186                           velGlobal->getY() );
02187       Log.log( 101, "vel based on 2 pos: (%f,%f)", velGlobal->getX(),
02188                           velGlobal->getY() );
02189     }
02190     else if(getTimeLastSeeMessage()-Ball.getTimeGlobalPosDerivedFromSee()==2 &&
02191         m_bWasCollision == false )
02192     {
02193       VecPosition velTmp, posTmp;
02194       double      dDist;      
02195       // we have seen ball for the last time two cycles ago
02196       // name v velocity after first cycle, vel. now is then v*d^2. 
02197       // v can be calculated as v + v * d = diff -> v = diff / ( 1 + d)
02198 
02199       // velTmp is now distance traveled in previous cycle.
02200       // get position in previous cycle.
02201       // if no opponent or I could have shot the ball, update velocity.
02202       velTmp = (posGlobalDiff/(1+SS->getBallDecay()))*SS->getBallDecay();
02203       posTmp = *posGlobal - velTmp;
02204       getClosestInSetTo( OBJECT_SET_PLAYERS, posTmp, &dDist );
02205       if( dDist > SS->getMaximalKickDist() &&
02206           m_bPerformedKick == false &&
02207     (getCurrentTime() - m_timeLastCollision) > 3 )
02208       {
02209         *velGlobal = velTmp * SS->getBallDecay();
02210          Log.log( 458, "vel based on 3 pos: (%f,%f)", velGlobal->getX(),
02211                           velGlobal->getY() );
02212       }
02213     }
02214     else if( getTimeLastSeeMessage()-Ball.getTimeGlobalPosDerivedFromSee() > 2)
02215     {
02216 #ifdef WIN32
02217       Log.log( 20, "(WorldModel:%s) time difference too large" ,
02218                     "calculateStateBall" );
02219 #else
02220       Log.log( 20, "(WorldModel:%s) time difference too large" ,__FUNCTION__ );
02221 #endif
02222 
02223     }
02224   }
02225   else
02226     Log.log( 458, "vel ball not updated", velGlobal->getX(),velGlobal->getY());
02227     // object too far away do not estimate velocity, sense has updated it
02228     // already
02229 
02230   // change velocity when the ball
02231   //   has been catched or play mode is not play_on
02232   //   is in kickable distance opponent
02233   //   higher than max speed with added noise
02234   // change position when it is a kick_in: know y coordinate
02235   // change position when it is a back_pass_[rl]: know positions
02236   if( getTimeSinceLastCatch() < 2 ||
02237       (getPlayMode() != PM_PLAY_ON && !isGoalKickUs() && !isGoalKickThem() &&
02238        !isPenaltyUs() && !isPenaltyThem() ))
02239     velGlobal->setMagnitude( 0.0 );
02240   else if( getNrInSetInCircle( OBJECT_SET_OPPONENTS,
02241                             Circle(*posGlobal,SS->getMaximalKickDist())) > 0
02242            && getRelativeDistance( OBJECT_BALL ) > SS->getMaximalKickDist() )
02243     velGlobal->setMagnitude( 0.0 );
02244   else if( velGlobal->getMagnitude() >
02245                            ( 1.0 + SS->getBallRand() )*SS->getBallSpeedMax() )
02246     velGlobal->setMagnitude( SS->getBallSpeedMax() );
02247 
02248   if( isKickInUs() || isKickInThem() )
02249     posGlobal->setY( sign( posGlobal->getY() ) * PITCH_WIDTH/2.0 );
02250   else if( isBackPassUs() )
02251     posGlobal->setVecPosition( - PENALTY_X,
02252                                sign(posGlobal->getY())*PENALTY_AREA_WIDTH/2.0);
02253   else if( isBackPassThem() )
02254     posGlobal->setVecPosition( + PENALTY_X,
02255                                sign(posGlobal->getY())*PENALTY_AREA_WIDTH/2.0);
02256 
02257   Log.log( 458, "final ball vel: (%f,%f)",velGlobal->getX(),velGlobal->getY());
02258   if( getRelativeDistance(OBJECT_BALL) < SS->getVisibleDistance() )
02259     Log.log( 101, "direction old: %f, new: %f",
02260              ( getGlobalPosition( OBJECT_BALL ) - 
02261                getAgentGlobalPosition()).getDirection(),
02262          ( *posGlobal - getAgentGlobalPosition()).getDirection() );
02263   return true;
02264 }
02265 
02266 
02267 
02274 bool WorldModel::calculateStatePlayer( ObjectT o, VecPosition *posGlobal,
02275                                        VecPosition *velGlobal )
02276 {
02277   PlayerObject *pob = (PlayerObject*) getObjectPtrFromType( o );
02278   if( pob == NULL )
02279     return false;
02280 
02281   // set the global position of this dynamic object as follows:
02282   //  - get the relative position from the agent to it in world-axis
02283   //  - add global position agent to this relative position
02284   VecPosition posRelWorld =
02285       VecPosition( getRelativeDistance( o ),
02286                    getRelativeAngle( o ) + agentObject.getGlobalNeckAngle(),
02287                    POLAR );
02288   *posGlobal = getAgentGlobalPosition() + posRelWorld;
02289 
02290   *velGlobal = getGlobalVelocity( o ) ; 
02291   if( pob->getTimeChangeInformation( ) == getTimeLastSeen( o ) )
02292   {
02293     // calculate the global velocity using the distance and angle change
02294     // with the formula from the soccermanual
02295     *velGlobal = calculateVelocityDynamicObject( o );
02296   }
02297   else
02298       ; // object too far away do not estimate velocity, sense has updated it
02299         // already and does not really matter then
02300 
02301   if( velGlobal->getMagnitude() >=
02302                       ( 1.0 + SS->getPlayerRand())*SS->getPlayerSpeedMax() )
02303     velGlobal->setMagnitude( SS->getPlayerSpeedMax() );
02304 
02305   return true;
02306 }
02307 
02308 
02322 bool WorldModel::getMinMaxDistQuantizeValue( double dOutput, double *dMin,
02323                                         double *dMax,   double x1, double x2 )
02324 {
02325   // change output a little bit to circumvent boundaries
02326   // q = quantize(e^(quantize(ln(V),x1)),x2) with quantize(V,Q) = rint(V/Q)*Q
02327   // e^(quantize(ln(V),x1)_min = invQuantize( q, x2 )
02328   // quantize(ln(V),x1) = ln ( invQuantize( q, x2 ) )
02329   // ln(V) = invQuantize( ln ( invQuantize( q, x2 ) ), x1 )
02330   // V_min = e^( invQuantize( ln ( invQuantize( q, x2 ) ), x1 ) )
02331   // apply inverse quantize twice to get correct value
02332   dOutput -= 1.0e-10;
02333   if( dOutput < 0 )
02334     *dMin = 0.0;
02335   else
02336     *dMin = exp( invQuantizeMin( log( invQuantizeMin(dOutput,x2) ), x1 ) );
02337   dOutput += 2.0e-10;
02338   *dMax = exp( invQuantizeMax( log( invQuantizeMax(dOutput,x2) ), x1 ) );
02339   return true;
02340 }
02341 
02351 bool WorldModel::getMinMaxDirChange( double dOutput, double *dMin,
02352                                      double *dMax,   double x1     )
02353 {
02354  *dMin = invQuantizeMin( dOutput, x1 ) ;
02355  *dMax = invQuantizeMax( dOutput, x1 ) ;
02356  return true;
02357 }
02358 
02373 bool WorldModel::getMinMaxDistChange( double dOutput, double dDist,
02374          double *dMin, double *dMax, double x1, double xDist1, double xDist2)
02375 {
02376   // Q_dist = quantize(e^(quantize(ln(V),xDist1)),xDist2)
02377   // q = Q_dist * Quantize( distance_change/distance, x1 )
02378   // dOutput = q/Q_dist = Quantize( distance_change/distance, x1 )
02379   // (distance_change/distance)_min = invQmin(q/Q_dist, x1 )
02380   // real distance is not know so should take into account distance range
02381   double dMinDist, dMaxDist;
02382   getMinMaxDistQuantizeValue( dDist, &dMinDist, &dMaxDist, xDist1, xDist2 );
02383   dOutput = dOutput/dDist;
02384   double dMinCh = invQuantizeMin( dOutput, x1 ) ;
02385   double dMaxCh = invQuantizeMax( dOutput, x1 ) ;
02386   *dMin = min( dMinDist*dMinCh, dMaxDist*dMinCh );
02387   *dMax = max( dMinDist*dMaxCh, dMaxDist*dMaxCh );
02388   return true;
02389 }
02390 
02396 double WorldModel::invQuantizeMin( double dOutput, double dQuantizeStep )
02397 {
02398   // q = quantize( V, Q ) = rint(V/Q)*Q -> q/Q = rint( V/Q)
02399   // min = rint(q/Q)-0.5 = V_min/Q -> V_min = (rint(q/Q)-0.5)*Q
02400   return max(1.0e-10,(rint( dOutput / dQuantizeStep )-0.5 )*dQuantizeStep);
02401 }
02402 
02408 double WorldModel::invQuantizeMax( double dOutput, double dQuantizeStep )
02409 {
02410   // q = quantize( V, Q ) = rint(V/Q)*Q -> q/Q = rint( V/Q)
02411   // max = rint(q/Q)+0.5 = V_max/Q -> V_max = (rint(q/Q)-0.5)*Q
02412   return (rint( dOutput/dQuantizeStep) + 0.5 )*dQuantizeStep;
02413 }
02414 
02426 void WorldModel::mapUnknownPlayers( Time time)
02427 {
02428   double      dDist, dMinDist;
02429   VecPosition pos, posAgent = getAgentGlobalPosition();
02430   ObjectT     o, o_new, objTmp;
02431   int         index;
02432 
02433   // for all unknown players, try to map it to closest teammate or opponent
02434   for( int j = 0; j < iNrUnknownPlayers; j ++ )
02435   {
02436     pos = posAgent + VecPosition( UnknownPlayers[j].getRelativeDistance(),
02437     VecPosition::normalizeAngle( getAgentGlobalNeckAngle() + 
02438                UnknownPlayers[j].getRelativeAngle() ),
02439           POLAR );
02440     dMinDist = 1000.0;
02441     o     = UnknownPlayers[j].getType();
02442     o_new = OBJECT_ILLEGAL;
02443     Log.log( 464, "map unknown player: %d %f %f (%f,%f) neck %f",
02444                   o, 
02445                   UnknownPlayers[j].getRelativeDistance(),
02446                   UnknownPlayers[j].getRelativeAngle(),
02447                   pos.getX(), pos.getY(),
02448                   getAgentGlobalNeckAngle() );
02449     if( ! SoccerTypes::isOpponent( o ) ) // TEAMMATE_UNKNOWN or PLAYER_UNKNOWN
02450     {
02451       for( int i = 0 ; i < MAX_TEAMMATES ; i++ )
02452       {
02453         objTmp = Teammates[i].getType();
02454         if( isConfidenceGood( objTmp ) && getTimeLastSeen( objTmp ) != time &&
02455             objTmp != getAgentObjectType()  ) 
02456         {
02457           dDist = pos.getDistanceTo( Teammates[i].getGlobalPosition( ) );
02458           Log.log( 464, "distance with %d %f (%f,%f)", objTmp, dDist,
02459                       Teammates[i].getRelativeDistance(),
02460                       Teammates[i].getRelativeAngle()  );
02461           if( dDist < dMinDist )
02462           {
02463             o_new    = objTmp;
02464             dMinDist = dDist;
02465           }
02466         }
02467         else
02468           Log.log( 464, "not possible: distance with %d (%f,%f) conf %d  \
02469                          last_seen (%d,%d), now (%d,%d)",
02470                    objTmp,
02471                    Teammates[i].getRelativeDistance(),
02472                    Teammates[i].getRelativeAngle(),
02473                    isConfidenceGood( objTmp ),
02474                    getTimeLastSeen( objTmp ).getTime(),
02475                    getTimeLastSeen( objTmp ).getTimeStopped(),
02476                    time.getTime(),
02477                    time.getTimeStopped());
02478 
02479       }
02480     }
02481     if( ! SoccerTypes::isTeammate( o ) ) // OPPONENT_UNKNOWN or PLAYER_UNKNOWN
02482     {
02483       for( int i = 0 ; i < MAX_OPPONENTS ; i++ )
02484       {
02485         objTmp = Opponents[i].getType();
02486         if( isConfidenceGood( objTmp ) && getTimeLastSeen( objTmp ) != time ) 
02487         {
02488           dDist = pos.getDistanceTo( Opponents[i].getGlobalPosition( ) );
02489           Log.log( 464, "distance with %d %f (%f,%f)", objTmp, dDist,
02490                       Opponents[i].getRelativeDistance(),
02491                       Opponents[i].getRelativeAngle()  );
02492           if( dDist < dMinDist )
02493           {
02494             o_new    = objTmp;
02495             dMinDist = dDist;
02496           }
02497         }
02498         else
02499           Log.log( 464, "not possible: distance with %d (%f,%f) conf %d  \
02500                          last_seen (%d,%d), now (%d,%d)",
02501                    objTmp,
02502                    Opponents[i].getRelativeDistance(),
02503                    Opponents[i].getRelativeAngle(),
02504                    isConfidenceGood( objTmp ),
02505                    getTimeLastSeen( objTmp ).getTime(),
02506                    getTimeLastSeen( objTmp ).getTimeStopped(),
02507                    time.getTime(),
02508                    time.getTimeStopped());
02509       }
02510     }
02511 
02512     Log.log( 464, "closest obj %d, found %f, max_move %f rel_dist %f type %d",
02513              o_new, dMinDist, getMaxTraveledDistance( o_new ),
02514              UnknownPlayers[j].getRelativeDistance(), 
02515              UnknownPlayers[j].getType() );
02516 
02517     // if player found and in tolerated distance update player
02518     // information.  else if not mapped to player put information in
02519     // first player position of which we have no info.  if we do not
02520     // know it is a teammate or opponent only assume opponent when it
02521     // is very close since then it is probably an opponent trying to
02522     // get ball
02523     if( SoccerTypes::isKnownPlayer(o_new)
02524         && dMinDist < PS->getPlayerDistTolerance()
02525         && dMinDist < getMaxTraveledDistance( o_new ) + 2 ) // 2 for the noise
02526     {
02527       UnknownPlayers[j].setType( o_new );
02528       if( SoccerTypes::isTeammate( o_new ) )
02529       {
02530         index = SoccerTypes::getIndex(o_new);
02531         UnknownPlayers[j].setHeteroPlayerType(
02532                                   Teammates[index].getHeteroPlayerType( ) );
02533         Teammates[index] = UnknownPlayers[j];
02534         Log.log( 464, "map to known teammate %d (%f,%f) conf %f", index + 1,
02535            Teammates[index].getGlobalPosition().getX(),
02536            Teammates[index].getGlobalPosition().getY(),
02537            Teammates[index].getConfidence( getCurrentTime() ) );
02538       }
02539       else if( SoccerTypes::isOpponent( o_new ) )
02540       {
02541         index = SoccerTypes::getIndex(o_new );
02542         UnknownPlayers[j].setHeteroPlayerType(
02543                                   Opponents[index].getHeteroPlayerType( ) );
02544         Opponents[index] = UnknownPlayers[j];
02545         Log.log( 464, "map to known opponent %d (time %d)", 
02546      index + 1, UnknownPlayers[j].getTimeLastSeen().getTime() );
02547       }
02548     }
02549     else if( UnknownPlayers[j].getType() == OBJECT_TEAMMATE_UNKNOWN )
02550     {
02551       o_new = getFirstEmptySpotInSet( OBJECT_SET_TEAMMATES, j );
02552 
02553       if( o_new != OBJECT_ILLEGAL )
02554       {
02555         index = SoccerTypes::getIndex(o_new);
02556         UnknownPlayers[j].setHeteroPlayerType(
02557                                   Teammates[index].getHeteroPlayerType( ) );
02558         UnknownPlayers[j].setType( o_new );
02559         Teammates[index] = UnknownPlayers[j];
02560         Log.log( 464, "map to unknown teammate %d", index + 1 );
02561       }
02562     }
02563     else if( UnknownPlayers[j].getType() == OBJECT_OPPONENT_UNKNOWN )
02564     {                                      // could not map info to a player
02565       o_new = getFirstEmptySpotInSet( OBJECT_SET_OPPONENTS, j );
02566       Log.log( 464, "map unkown opponent to %d", o_new );
02567       if( o_new != OBJECT_ILLEGAL )
02568       {
02569         index = SoccerTypes::getIndex(o_new);
02570         UnknownPlayers[j].setHeteroPlayerType(
02571                                   Opponents[index].getHeteroPlayerType( ) );
02572         UnknownPlayers[j].setType( o_new );
02573         Opponents[index] = UnknownPlayers[j];
02574         Log.log( 464, "map to unknown opponent %d", index + 1 );
02575       }
02576       else
02577       {
02578         Log.log( 464, "couldn't find empty spot for unk. opponent" );
02579         if( Log.isInLogLevel( 464 ) )
02580           show( OBJECT_SET_PLAYERS, Log.getOutputStream() );       
02581 //        if( getRelativeDistance( OBJECT_BALL ) < 3.0 )
02582 //        cerr << getPlayerNumber() << ", " << 
02583 //          getCurrentCycle() << " couldn't find empty spot" << endl;
02584       }
02585     }
02586     else if( UnknownPlayers[j].getType() == OBJECT_PLAYER_UNKNOWN &&
02587          ( UnknownPlayers[j].getRelativeDistance() < SS->getVisibleDistance() 
02588            || ( dMinDist - getMaxTraveledDistance( o_new ) ) > 10   ) )
02589     {
02590       o_new = getFirstEmptySpotInSet( OBJECT_SET_OPPONENTS );
02591       Log.log( 464, "map unkown player to %d", o_new );
02592       if( o_new != OBJECT_ILLEGAL )
02593       {
02594         index = SoccerTypes::getIndex(o_new);
02595         UnknownPlayers[j].setHeteroPlayerType(
02596                                   Opponents[index].getHeteroPlayerType( ) );
02597         UnknownPlayers[j].setType( o_new );
02598         Opponents[index] = UnknownPlayers[j];
02599         Log.log( 464, "map to unknown close opponent %d", index + 1 );
02600       }
02601     }
02602   }
02603   Log.log( 464, "end map unknown player" );
02604 
02605   iNrUnknownPlayers  = 0;
02606 }
02607 
02615 bool WorldModel::updateSSToHeteroPlayerType( int iIndex )
02616 {
02617   SS->setPlayerSpeedMax( pt[iIndex].dPlayerSpeedMax );
02618   SS->setStaminaIncMax ( pt[iIndex].dStaminaIncMax  );
02619   SS->setPlayerDecay   ( pt[iIndex].dPlayerDecay    );
02620   SS->setInertiaMoment ( pt[iIndex].dInertiaMoment  );
02621   SS->setDashPowerRate ( pt[iIndex].dDashPowerRate  );
02622   SS->setPlayerSize    ( pt[iIndex].dPlayerSize     );
02623   SS->setKickableMargin( pt[iIndex].dKickableMargin );
02624   SS->setKickRand      ( pt[iIndex].dKickRand       );
02625   SS->setExtraStamina  ( pt[iIndex].dExtraStamina   );
02626   SS->setEffortMax     ( pt[iIndex].dEffortMax      );
02627   SS->setEffortMin     ( pt[iIndex].dEffortMin      );
02628   
02629   return true;
02630 }
02631 
02635 bool WorldModel::resetTimeObjects( )
02636 {
02637   Ball.setTimeLastSeen             ( Time( -1, 0) );
02638   for( int i = 0 ; i < MAX_TEAMMATES ; i ++ )
02639     Teammates[i].setTimeLastSeen   ( Time( -1, 0) );
02640   for( int i = 0 ; i < MAX_OPPONENTS ; i ++ )
02641     Opponents[i].setTimeLastSeen   ( Time( -1, 0) );
02642   for( int i = 0 ; i < MAX_FLAGS     ; i ++ )
02643     Flags[i].setTimeLastSeen   ( Time( -1, 0) );
02644   for( int i = 0 ; i < MAX_LINES     ; i ++ )
02645     Lines[i].setTimeLastSeen   ( Time( -1, 0) );
02646   agentObject.setTimeLastSeen      ( Time( -1, 0) );
02647   return true;
02648 }
02649 
02653 void WorldModel::removeGhosts( )
02654 {
02655   AngDeg dAngle=SoccerTypes::getHalfViewAngleValue(agentObject.getViewAngle());
02656   dAngle -= 0.35*dAngle; // make somewhat smaller for error
02657   VecPosition posAgent = getAgentGlobalPosition();
02658 
02659   if( fabs( getRelativeAngle( OBJECT_BALL ) ) < dAngle
02660        && getTimeLastSeen( OBJECT_BALL ) != getTimeLastSeeMessage() )
02661   {
02662     double dDist;
02663     ObjectT objOpp=getClosestInSetTo(OBJECT_SET_OPPONENTS,OBJECT_BALL,&dDist);
02664     // when opp is very close and ball is not seen (and also not felt) set it
02665     // at the opponent position
02666     if( dDist < 2.0 && 
02667   posAgent.getDistanceTo( getGlobalPosition( objOpp ) ) < 4.5  &&
02668   getTimeLastSeen( objOpp ) != getTimeLastSeeMessage() ) 
02669     {
02670       Log.log( 556, "ball not seen, but opp close, set ball to that pos" );
02671       Ball.setGlobalPosition( getGlobalPosition( objOpp ),
02672             Ball.getTimeGlobalPosition() );
02673     }
02674     else
02675     {
02676       Log.log( 556, "ball not in cone: set time ball at -1 %f %f",
02677          fabs( getRelativeAngle( OBJECT_BALL ) ), dAngle );
02678       Ball.setTimeLastSeen( Time( -1, 0 ) );
02679     }
02680   }
02681 
02682   // ball should be "seen" when it is in visible distance. 0.9 is for noise
02683   if( fabs( getRelativeDistance( OBJECT_BALL ) ) < 0.9*SS->getVisibleDistance()
02684        && getTimeLastSeen( OBJECT_BALL ) != getTimeLastSeeMessage() )
02685   {
02686     double dDist;
02687     ObjectT objOpp=getClosestInSetTo(OBJECT_SET_OPPONENTS,OBJECT_BALL,&dDist);
02688     if( dDist < 2.0 )
02689     {
02690       Log.log( 556, "ball not seen, but opp close, set ball to that pos" );
02691       Ball.setGlobalPosition( getGlobalPosition( objOpp ),
02692             Ball.getTimeGlobalPosition() );
02693     }
02694     else
02695     {
02696       Log.log( 556, "ball not in vis. dist: set time ball at -1 %f %f",
02697          fabs( getRelativeAngle( OBJECT_BALL ) ), dAngle );
02698       Ball.setTimeLastSeen( Time( -1, 0 ) );
02699     }
02700   }
02701 
02702   // now remove all opponents. If an opponent is not seen while you expect him
02703   // somewhere, he has moved a lot. It's no use keeping his current position
02704   // in the world model, since he would still be considered in passing
02705   // confidence, etc.
02706   int iIndex;
02707   for( ObjectT o = iterateObjectStart( iIndex, OBJECT_SET_OPPONENTS );
02708        o != OBJECT_ILLEGAL;
02709        o = iterateObjectNext ( iIndex, OBJECT_SET_OPPONENTS ) )
02710   {
02711     if(  fabs( getRelativeAngle( o ) ) < dAngle 
02712 //          || getRelativeDistance( o ) < SS->getVisibleDistance() )
02713          && getTimeLastSeen( o ) != getTimeLastSeeMessage() &&
02714          o != getOppGoalieType() )
02715     {
02716       Log.log( 556, "opponent %d not in cone: (angle %f>%f) see (%d,%d)",
02717          SoccerTypes::getIndex( o ) + 1,
02718                fabs( getRelativeAngle( o ) ), dAngle,
02719                getTimeLastSeeMessage().getTime(),getTimeLastSeen(o).getTime());
02720 
02721       AngDeg ang = 
02722         SoccerTypes::getHalfViewAngleValue(agentObject.getViewAngle());
02723       AngDeg angOpp = (getGlobalPosition(o)-posAgent).getDirection();
02724       AngDeg angNeck = getAgentGlobalNeckAngle();
02725       // could have move both ways
02726       if( fabs(VecPosition::normalizeAngle( angOpp - angNeck )) < 10 &&
02727           getCurrentTime() - getTimeGlobalAngles(o) < 4 )
02728         angOpp = (getGlobalPosition(o)+
02729                   VecPosition(2.0, getGlobalBodyAngle(o), POLAR )-posAgent)
02730           .getDirection();
02731       if( VecPosition::normalizeAngle( angOpp - angNeck )  > 0 )
02732         angOpp = angNeck + ang;
02733       else
02734         angOpp = angNeck - ang;
02735       angOpp = VecPosition::normalizeAngle( angOpp );
02736       DynamicObject *obj = (DynamicObject*) getObjectPtrFromType( o );
02737 
02738       // if at edge change him otherwise delete
02739       if( fabs( getRelativeAngle( o ) ) + 20 > dAngle )
02740       {
02741         VecPosition posNew = posAgent+
02742           VecPosition(getRelativeDistance(o),angOpp, POLAR);
02743         if( posNew.getDistanceTo( getGlobalPosition( o ) ) <
02744             getMaxTraveledDistance( o ) )
02745         {
02746           obj->setGlobalPosition( posNew, getCurrentTime());
02747     //          obj->setGlobalPosition( posNew, getTimeLastSeen(o));
02748           Log.log( 556, "set opp at angle %f", angOpp );
02749           updateObjectRelativeFromGlobal( o );
02750         }
02751         else
02752           Log.log( 556, "do not reposition opp too far dist %f",  
02753                    posNew.getDistanceTo( getGlobalPosition( o ) ));
02754       }
02755       else
02756       {
02757   setTimeLastSeen( o, Time( -1, 0 ) );
02758   Log.log( 556, "remove opponent not in cone at angle %f %f %f", angOpp,
02759      fabs(getRelativeAngle(o)), dAngle  );
02760       }
02761     }
02762     if( getRelativeDistance(o) < SS->getVisibleDistance( ) 
02763   && getTimeLastSeen( o ) != getTimeLastSeeMessage() )
02764     {
02765       Log.log( 556, "opp %d not felt, place him outside vis. dist", o );  
02766       DynamicObject *obj = (DynamicObject*) getObjectPtrFromType( o );
02767       VecPosition posNew = posAgent + VecPosition( SS->getVisibleDistance(), 
02768         (getGlobalPosition( o ) - getAgentGlobalPosition()).
02769         getDirection(), POLAR );
02770       obj->setGlobalPosition( posNew, getCurrentTime(  ));
02771       //      obj->setGlobalPosition( posNew, getTimeLastSeen( o ));
02772       updateObjectRelativeFromGlobal( o );
02773     }
02774   }
02775   iterateObjectDone( iIndex );
02776 
02777   // now remove all teammates. If a teammate is not seen while you expect him
02778   // somewhere, he has moved a lot. It's no use keeping his current position
02779   // in the world model, since he would still be considered in passing
02780   // confidence, etc.
02781   for( ObjectT o = iterateObjectStart( iIndex, OBJECT_SET_TEAMMATES );
02782        o != OBJECT_ILLEGAL;
02783        o = iterateObjectNext ( iIndex, OBJECT_SET_TEAMMATES ) )
02784   {
02785     if( fabs( getRelativeAngle( o ) ) < dAngle 
02786 //       ||getRelativeDistance( o ) < SS->getVisibleDistance() )
02787            && getTimeLastSeen( o ) != getTimeLastSeeMessage() )
02788     {
02789       Log.log( 556, "teammate %d not in cone: (angle %f>%f) see (%d,%d)",
02790          SoccerTypes::getIndex( o ) + 1,
02791          fabs( getRelativeAngle( o ) ), dAngle,
02792          getTimeLastSeeMessage().getTime(), getTimeLastSeen( o ).getTime() );
02793       setTimeLastSeen( o, Time( -1, 0 ) );
02794     }
02795   }
02796   iterateObjectDone( iIndex );
02797 
02798 }
02799 
02809 void WorldModel::initParticlesBall( VecPosition posArray[],
02810                                     VecPosition velArray[], int iLength )
02811 {
02812   // declare a bunch of variables
02813   double dDistBall, dDistChange = UnknownDoubleValue;
02814   AngDeg angBall, angChange   = UnknownAngleValue;
02815   double dMinDist, dMaxDist, dMinCh, dMaxCh, dDistTmp, dDistChTmp, dVelX,dVelY;
02816   AngDeg angChMin, angChMax,     angTmp,   angChTmp;
02817 
02818   // no information  received -> no initialization
02819   if( Ball.getTimeRelativePosition() != getTimeLastSeeMessage() )
02820     return;
02821 
02822   // get perceived values for distance and angle with ball
02823   dDistBall = getRelativeDistance( OBJECT_BALL );
02824   angBall   = getRelativeAngle( OBJECT_BALL );
02825 
02826   // get perceived values for distance and direction change
02827   if( Ball.getTimeChangeInformation( ) == getTimeLastSeeMessage() )
02828   {
02829     dDistChange = Ball.getRelativeDistanceChange();
02830     angChange   = Ball.getRelativeAngleChange();
02831   }
02832 
02833   // get ranges from which values could originate
02834   getMinMaxDistQuantizeValue( dDistBall, &dMinDist, &dMaxDist, 0.1, 0.1 );
02835   getMinMaxDistChange( dDistChange, dDistBall, &dMinCh, &dMaxCh, 0.02, 0.1,0.1);
02836   getMinMaxDirChange ( angChange, &angChMin, &angChMax, 0.1 );
02837 
02838   for( int i = 0; i < iLength; i ++ )
02839   {
02840     // make random distance and angle from range (angle is rounded)
02841     // and make pos
02842     dDistTmp   = dMinDist + drand48()*fabs(dMaxDist - dMinDist); // angle->sign
02843     angTmp     = angBall  + drand48() - 0.5;
02844 
02845     posArray[i].setVecPosition( dDistTmp, angTmp, POLAR );
02846     posArray[i].relativeToGlobal( getAgentGlobalPosition(),
02847                                   getAgentGlobalNeckAngle() );
02848 
02849     if( dDistChange != UnknownDoubleValue )
02850     {
02851       // make random values for direction and distance change and make velocity
02852       angChTmp   = angChMin + drand48()*(angChMax-angChMin);
02853       dDistChTmp = dMinCh   + drand48()*(dMaxCh-dMinCh);
02854 
02855       dVelX=dDistChTmp*
02856         cosDeg(angTmp)-Deg2Rad(angChTmp)*dDistTmp*sinDeg(angTmp);
02857       dVelY=dDistChTmp*
02858         sinDeg(angTmp)+Deg2Rad(angChTmp)*dDistTmp*cosDeg(angTmp);
02859 
02860       velArray[i].setVecPosition( dVelX, dVelY );
02861       velArray[i].relativeToGlobal( getAgentGlobalVelocity(),
02862                                     getAgentGlobalNeckAngle() );
02863     }
02864     else
02865       velArray[i].setVecPosition( 0, 0 );
02866   }
02867 }
02868 
02879 void WorldModel::checkParticlesBall( VecPosition posArray[],
02880              VecPosition velArray[], int iLength, int *iNrParticlesLeft )
02881 {
02882   bool   bIllegal;
02883   double dMinDist, dMaxDist, dMinCh, dMaxCh, dMag;
02884   double dDistBall, dDistChange = UnknownDoubleValue;
02885   AngDeg angBall,  angChange;
02886   double dDistChTmp;
02887   AngDeg angChTmp, angChMin, angChMax;
02888   VecPosition pos_rel, vel_rel;
02889 
02890   // no new perceptions, do not check
02891   if( getTimeLastSeen( OBJECT_BALL ) != getTimeLastSeeMessage() )
02892     return;
02893 
02894   // initialize values distance, direction, distance change and
02895   // direction change and get the associated ranges
02896   dDistBall = getRelativeDistance( OBJECT_BALL );
02897   angBall   = getRelativeAngle( OBJECT_BALL );
02898   getMinMaxDistQuantizeValue( dDistBall, &dMinDist, &dMaxDist, 0.1, 0.1 );
02899 
02900   if( getTimeLastSeen( OBJECT_BALL ) == Ball.getTimeChangeInformation( ) )
02901   {
02902     dDistChange = Ball.getRelativeDistanceChange();
02903     angChange   = Ball.getRelativeAngleChange();
02904     getMinMaxDirChange ( angChange, &angChMin, &angChMax, 0.1);
02905     getMinMaxDistChange( dDistChange,dDistBall, &dMinCh, &dMaxCh,0.02,0.1,0.1);
02906 
02907   }
02908 
02909   *iNrParticlesLeft = 0;
02910   for( int i = 0; i < iLength; i ++ )
02911   {
02912     // get particles and make them relative to the agent to compare
02913     pos_rel = posArray[i];
02914     vel_rel = velArray[i];
02915     pos_rel.globalToRelative( getAgentGlobalPosition(),
02916                               getAgentGlobalNeckAngle() );
02917     vel_rel.globalToRelative( getAgentGlobalVelocity(),
02918                               getAgentGlobalNeckAngle() );
02919 
02920     bIllegal = false;
02921 
02922     dMag = pos_rel.getMagnitude();
02923     if( dMag <  dMinDist || dMag > dMaxDist )
02924     {
02925       bIllegal = true;
02926     }
02927     if( fabs( VecPosition::normalizeAngle(pos_rel.getDirection() - angBall) )
02928          > 0.5 )
02929     {
02930       bIllegal = true;
02931     }
02932 
02933     if( dDistChange != UnknownDoubleValue )
02934     {
02935       dDistChTmp = (vel_rel.getX()*(pos_rel.getX()/dMag)) +
02936                    (vel_rel.getY()*(pos_rel.getY()/dMag));
02937       angChTmp   = Rad2Deg( ((vel_rel.getY()*pos_rel.getX()/dMag) -
02938                              (vel_rel.getX()*pos_rel.getY()/dMag)))/dMag ;
02939 
02940       if( angChTmp < angChMin || angChTmp > angChMax )
02941       {
02942         bIllegal = true;
02943       }
02944       if( dDistChTmp < dMinCh || dDistChTmp > dMaxCh )
02945       {
02946         bIllegal = true;
02947       }
02948     }
02949 
02950     // if not illegal, save particles and raise iNrParticlesLeft
02951     if( bIllegal == false )
02952     {
02953       posArray[*iNrParticlesLeft]     = posArray[i];
02954       velArray[(*iNrParticlesLeft)++] = velArray[i];
02955     }
02956   }
02957 }
02958 
02967 void WorldModel::updateParticlesBall( VecPosition posArray[],
02968                VecPosition velArray[], int iLength, double dPower, AngDeg ang )
02969 {
02970   double dRand = SS->getBallRand();
02971   double dMaxRand;
02972 
02973   for( int i = 0; i < iLength; i ++ )
02974   {
02975     // if power supplied, assume ball (and thus particles) are kicked
02976     if( dPower > EPSILON )
02977     {
02978       ang = VecPosition::normalizeAngle(ang + getAgentGlobalBodyAngle() );
02979       velArray[i] += VecPosition(getActualKickPowerRate()*dPower, ang, POLAR) ;
02980       if( velArray[i].getMagnitude() > SS->getBallSpeedMax() )
02981         velArray[i].setMagnitude( SS->getBallSpeedMax() );
02982     }
02983 
02984     // add noise in same way server does.
02985     dMaxRand = dRand * velArray[i].getMagnitude();
02986     velArray[i] += VecPosition(
02987                    (-1 + 2*drand48())*dMaxRand,
02988                    (-1 + 2*drand48())*dMaxRand );
02989     posArray[i] += velArray[i];
02990     velArray[i] *= SS->getBallDecay();
02991   }
02992 }
02993 
02994 
03004 void WorldModel::resampleParticlesBall( VecPosition posArray[],
03005 VecPosition velArray[], int iLength, int iLeft )
03006 {
03007   int iRand ;
03008   for ( int i = iLeft; i < iLength; i ++ )
03009   {
03010     iRand = (int)(drand48()*iLeft);       // pick random particle
03011     posArray[ i ] = posArray[ iRand ];    // and copy contents
03012     velArray[ i ] = velArray[ iRand ];
03013   }
03014 }
03015 
03016 ObjectT WorldModel::getMaxRangeUnknownPlayer( ObjectT obj, char* strMsg )
03017 {
03018   list<ObjectT> l;
03019   ObjectT o;
03020   bool    isGoalie, bCont = true;
03021   int     i, loop;
03022 //  bool    isTeammate = SoccerTypes::isTeammate( obj );
03023   ObjectT objMax = (getSide()==SIDE_LEFT) ? OBJECT_OPPONENT_11
03024                                           : OBJECT_TEAMMATE_11 ;
03025 
03026   while( bCont == true )
03027   {
03028     i = Parse::gotoFirstOccurenceOf( '(', &strMsg );
03029     if( i == -1 )
03030       bCont = false;                             // no more objects
03031     else
03032     {
03033       strMsg++;
03034       o = SoccerTypes::getObjectFromStr(&strMsg,&isGoalie,getTeamName());
03035       if( SoccerTypes::isPlayer( o ) )
03036         l.push_back( o );
03037     }
03038   }
03039   Log.log( 459, "list size %d", l.size() );
03040   while( ! l.empty() )
03041   {
03042     o = l.back();
03043     l.pop_back();
03044     if( SoccerTypes::isKnownPlayer( o ) )      // max range is one lower
03045       objMax = o;
03046     else if( SoccerTypes::isOpponent( o ) && 
03047              SoccerTypes::isTeammate( objMax ) )
03048       objMax = OBJECT_OPPONENT_11;
03049     else if( SoccerTypes::isTeammate( o ) && 
03050              SoccerTypes::isOpponent( objMax ) )
03051       objMax = OBJECT_TEAMMATE_11;
03052 
03053     if( objMax == getAgentObjectType() )
03054       loop = 2;
03055     else
03056       loop = 1;
03057 
03058     for( int j = 0; j < loop; j ++ )
03059     {
03060       i = SoccerTypes::getIndex( objMax );
03061       if( objMax == OBJECT_TEAMMATE_1 )
03062         objMax = OBJECT_OPPONENT_11;
03063       else if( objMax == OBJECT_OPPONENT_1 )
03064         objMax = OBJECT_TEAMMATE_11;
03065       else if( SoccerTypes::isTeammate( objMax ) )
03066         objMax = SoccerTypes::getTeammateObjectFromIndex( i - 1 );
03067       else if( SoccerTypes::isOpponent( objMax ) )
03068         objMax = SoccerTypes::getOpponentObjectFromIndex( i - 1 );
03069     }
03070     Log.log( 459, "processs %d new obj_max: %d", o, objMax );
03071 
03072   }
03073 
03074   return objMax;
03075 }

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