2011-10-09 00:25:04 +02:00
// FGAIAircraft - FGAIBase-derived class creates an AI airplane
2003-11-28 15:48:05 +00:00
//
// Written by David Culp, started October 2003.
//
// Copyright (C) 2003 David P. Culp - davidculp2@comcast.net
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
2006-02-21 01:16:04 +00:00
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
2003-11-28 15:48:05 +00:00
# ifdef HAVE_CONFIG_H
# include <config.h>
# endif
2005-02-10 09:01:51 +00:00
# include <simgear/route/waypoint.hxx>
2003-11-28 15:48:05 +00:00
# include <Main/fg_props.hxx>
# include <Main/globals.hxx>
2005-02-10 09:01:51 +00:00
# include <Main/viewer.hxx>
2003-11-28 15:48:05 +00:00
# include <Scenery/scenery.hxx>
2005-02-10 09:01:51 +00:00
# include <Scenery/tilemgr.hxx>
2008-08-14 18:13:39 +00:00
# include <Airports/dynamics.hxx>
2010-10-20 17:54:16 +01:00
# include <Airports/simple.hxx>
2005-02-10 09:01:51 +00:00
2003-11-28 15:48:05 +00:00
# include <string>
# include <math.h>
2004-12-05 09:34:03 +00:00
# include <time.h>
2009-10-02 05:44:56 +00:00
2005-02-18 10:16:30 +00:00
# ifdef _MSC_VER
# include <float.h>
# define finite _finite
2005-10-06 11:08:26 +00:00
# elif defined(__sun) || defined(sgi)
2005-05-07 08:56:42 +00:00
# include <ieeefp.h>
2005-02-18 10:16:30 +00:00
# endif
2003-11-28 15:48:05 +00:00
2008-07-27 16:25:13 +00:00
using std : : string ;
2003-11-28 15:48:05 +00:00
# include "AIAircraft.hxx"
2007-06-28 07:47:20 +00:00
# include "performancedata.hxx"
# include "performancedb.hxx"
2011-10-09 00:25:04 +02:00
# include <signal.h>
2007-06-28 07:47:20 +00:00
2006-10-06 17:36:31 +00:00
//#include <Airports/trafficcontroller.hxx>
2007-06-09 11:49:16 +00:00
2011-06-25 20:44:44 +02:00
FGAIAircraft : : FGAIAircraft ( FGAISchedule * ref ) :
/* HOT must be disabled for AI Aircraft,
* otherwise traffic detection isn ' t working as expected . */
FGAIBase ( otAircraft , false )
{
2006-05-13 10:02:17 +00:00
trafficRef = ref ;
2007-07-09 05:07:56 +00:00
if ( trafficRef ) {
2006-05-13 10:02:17 +00:00
groundOffset = trafficRef - > getGroundOffset ( ) ;
2011-06-25 20:44:44 +02:00
setCallSign ( trafficRef - > getCallSign ( ) ) ;
2007-07-09 05:07:56 +00:00
}
2006-05-13 10:02:17 +00:00
else
groundOffset = 0 ;
2011-08-03 23:09:52 +02:00
fp = 0 ;
controller = 0 ;
prevController = 0 ;
towerController = 0 ;
2006-05-13 10:02:17 +00:00
dt_count = 0 ;
dt_elev_count = 0 ;
use_perf_vs = true ;
2006-10-29 19:30:21 +00:00
no_roll = false ;
tgt_speed = 0 ;
speed = 0 ;
groundTargetSpeed = 0 ;
2006-05-13 10:02:17 +00:00
// set heading and altitude locks
hdg_lock = false ;
alt_lock = false ;
roll = 0 ;
headingChangeRate = 0.0 ;
2009-09-04 17:03:50 +00:00
headingError = 0 ;
2010-08-29 19:25:34 +02:00
minBearing = 360 ;
speedFraction = 1.0 ;
2006-09-19 17:04:22 +00:00
holdPos = false ;
2010-04-25 08:32:53 +00:00
needsTaxiClearance = false ;
2011-01-10 20:53:46 +01:00
_needsGroundElevation = true ;
2007-06-28 07:47:20 +00:00
_performance = 0 ; //TODO initialize to JET_TRANSPORT from PerformanceDB
2009-09-04 17:03:50 +00:00
dt = 0 ;
2011-08-07 21:38:50 +02:00
takeOffStatus = 0 ;
2003-11-28 15:48:05 +00:00
}
2007-06-10 06:06:57 +00:00
FGAIAircraft : : ~ FGAIAircraft ( ) {
2006-05-13 10:02:17 +00:00
//delete fp;
2007-06-09 11:49:16 +00:00
if ( controller )
controller - > signOff ( getID ( ) ) ;
2003-11-28 15:48:05 +00:00
}
2006-05-13 10:02:17 +00:00
2007-06-10 06:06:57 +00:00
void FGAIAircraft : : readFromScenario ( SGPropertyNode * scFileNode ) {
2006-05-13 10:02:17 +00:00
if ( ! scFileNode )
return ;
2006-02-11 13:16:56 +00:00
2006-05-13 10:02:17 +00:00
FGAIBase : : readFromScenario ( scFileNode ) ;
2006-02-11 13:16:56 +00:00
2006-05-13 10:02:17 +00:00
setPerformance ( scFileNode - > getStringValue ( " class " , " jet_transport " ) ) ;
setFlightPlan ( scFileNode - > getStringValue ( " flightplan " ) ,
2007-06-10 06:06:57 +00:00
scFileNode - > getBoolValue ( " repeat " , false ) ) ;
2006-05-13 10:02:17 +00:00
setCallSign ( scFileNode - > getStringValue ( " callsign " ) ) ;
2003-11-28 15:48:05 +00:00
}
2006-05-13 10:02:17 +00:00
2007-06-10 06:06:57 +00:00
void FGAIAircraft : : bind ( ) {
2003-12-21 20:12:55 +00:00
FGAIBase : : bind ( ) ;
2004-01-22 21:13:47 +00:00
props - > tie ( " controls/gear/gear-down " ,
2007-06-10 06:06:57 +00:00
SGRawValueMethods < FGAIAircraft , bool > ( * this ,
& FGAIAircraft : : _getGearDown ) ) ;
2009-03-22 13:49:51 +00:00
props - > tie ( " transponder-id " ,
SGRawValueMethods < FGAIAircraft , const char * > ( * this ,
& FGAIAircraft : : _getTransponderCode ) ) ;
2003-12-21 20:12:55 +00:00
}
2006-05-13 10:02:17 +00:00
2007-06-10 06:06:57 +00:00
void FGAIAircraft : : unbind ( ) {
2003-12-21 20:12:55 +00:00
FGAIBase : : unbind ( ) ;
2004-01-22 21:13:47 +00:00
2004-09-08 13:21:40 +00:00
props - > untie ( " controls/gear/gear-down " ) ;
2009-03-22 13:49:51 +00:00
props - > untie ( " transponder-id " ) ;
2003-12-21 20:12:55 +00:00
}
2003-11-28 15:48:05 +00:00
2007-06-10 06:06:57 +00:00
void FGAIAircraft : : update ( double dt ) {
2006-05-13 10:02:17 +00:00
FGAIBase : : update ( dt ) ;
Run ( dt ) ;
Transform ( ) ;
2003-11-28 15:48:05 +00:00
}
2007-06-10 06:06:57 +00:00
void FGAIAircraft : : setPerformance ( const std : : string & acclass ) {
2007-06-28 07:47:20 +00:00
static PerformanceDB perfdb ; //TODO make it a global service
setPerformance ( perfdb . getDataFor ( acclass ) ) ;
}
2006-02-11 13:16:56 +00:00
2006-05-13 10:02:17 +00:00
2007-06-28 07:47:20 +00:00
void FGAIAircraft : : setPerformance ( PerformanceData * ps ) {
_performance = ps ;
}
2006-05-13 10:02:17 +00:00
2003-11-28 15:48:05 +00:00
2007-06-28 07:47:20 +00:00
void FGAIAircraft : : Run ( double dt ) {
FGAIAircraft : : dt = dt ;
2010-02-19 00:31:38 +00:00
bool outOfSight = false ,
flightplanActive = true ;
updatePrimaryTargetValues ( flightplanActive , outOfSight ) ; // target hdg, alt, speed
if ( outOfSight ) {
return ;
2007-06-28 07:47:20 +00:00
}
2010-02-19 00:31:38 +00:00
if ( ! flightplanActive ) {
groundTargetSpeed = 0 ;
2007-06-28 07:47:20 +00:00
}
2003-11-28 15:48:05 +00:00
2007-06-28 07:47:20 +00:00
handleATCRequests ( ) ; // ATC also has a word to say
updateSecondaryTargetValues ( ) ; // target roll, vertical speed, pitch
updateActualState ( ) ;
2011-04-29 20:44:05 +02:00
// We currently have one situation in which an AIAircraft object is used that is not attached to the
// AI manager. In this particular case, the AIAircraft is used to shadow the user's aircraft's behavior in the AI world.
// Since we perhaps don't want a radar entry of our own aircraft, the following conditional should probably be adequate
// enough
if ( manager )
UpdateRadar ( manager ) ;
2008-12-10 16:04:10 +00:00
checkVisibility ( ) ;
2007-06-28 07:47:20 +00:00
}
2006-06-16 14:22:21 +00:00
2008-12-10 16:04:10 +00:00
void FGAIAircraft : : checkVisibility ( )
{
2009-06-09 12:16:21 +00:00
double visibility_meters = fgGetDouble ( " /environment/visibility-m " ) ;
FGViewer * vw = globals - > get_current_view ( ) ;
invisible = ( SGGeodesy : : distanceM ( vw - > getPosition ( ) , pos ) > visibility_meters ) ;
2008-12-10 16:04:10 +00:00
}
2003-11-28 15:48:05 +00:00
2007-06-10 06:06:57 +00:00
void FGAIAircraft : : AccelTo ( double speed ) {
2006-05-13 10:02:17 +00:00
tgt_speed = speed ;
2011-10-10 18:51:41 +02:00
//assertSpeed(speed);
2011-01-10 20:53:46 +01:00
if ( ! isStationary ( ) )
_needsGroundElevation = true ;
2003-11-28 15:48:05 +00:00
}
2007-06-10 06:06:57 +00:00
void FGAIAircraft : : PitchTo ( double angle ) {
2006-05-13 10:02:17 +00:00
tgt_pitch = angle ;
alt_lock = false ;
2003-11-28 15:48:05 +00:00
}
2007-06-10 06:06:57 +00:00
void FGAIAircraft : : RollTo ( double angle ) {
2006-05-13 10:02:17 +00:00
tgt_roll = angle ;
hdg_lock = false ;
2003-11-28 15:48:05 +00:00
}
2007-06-10 06:06:57 +00:00
void FGAIAircraft : : YawTo ( double angle ) {
2006-05-13 10:02:17 +00:00
tgt_yaw = angle ;
2003-11-28 15:48:05 +00:00
}
2007-06-10 06:06:57 +00:00
void FGAIAircraft : : ClimbTo ( double alt_ft ) {
2006-06-24 00:00:27 +00:00
tgt_altitude_ft = alt_ft ;
2006-05-13 10:02:17 +00:00
alt_lock = true ;
2003-11-28 15:48:05 +00:00
}
2007-06-10 06:06:57 +00:00
void FGAIAircraft : : TurnTo ( double heading ) {
2006-05-13 10:02:17 +00:00
tgt_heading = heading ;
hdg_lock = true ;
2003-11-28 15:48:05 +00:00
}
2007-06-10 06:06:57 +00:00
double FGAIAircraft : : sign ( double x ) {
2007-06-09 11:49:16 +00:00
if ( x = = 0.0 )
return x ;
2006-05-13 10:02:17 +00:00
else
2007-06-09 11:49:16 +00:00
return x / fabs ( x ) ;
2003-11-28 15:48:05 +00:00
}
2004-05-15 09:07:55 +00:00
2006-05-13 10:02:17 +00:00
2007-06-10 06:06:57 +00:00
void FGAIAircraft : : setFlightPlan ( const std : : string & flightplan , bool repeat ) {
if ( ! flightplan . empty ( ) ) {
2006-05-13 10:02:17 +00:00
FGAIFlightPlan * fp = new FGAIFlightPlan ( flightplan ) ;
fp - > setRepeat ( repeat ) ;
SetFlightPlan ( fp ) ;
}
2006-02-11 13:16:56 +00:00
}
2006-05-13 10:02:17 +00:00
2007-06-10 06:06:57 +00:00
void FGAIAircraft : : SetFlightPlan ( FGAIFlightPlan * f ) {
2006-05-13 10:02:17 +00:00
delete fp ;
fp = f ;
2004-05-15 09:07:55 +00:00
}
2006-05-13 10:02:17 +00:00
2007-06-10 06:06:57 +00:00
void FGAIAircraft : : ProcessFlightPlan ( double dt , time_t now ) {
2007-06-09 11:49:16 +00:00
// the one behind you
2011-07-31 19:27:44 +02:00
FGAIWaypoint * prev = 0 ;
2007-06-09 11:49:16 +00:00
// the one ahead
2011-07-31 19:27:44 +02:00
FGAIWaypoint * curr = 0 ;
2007-06-09 11:49:16 +00:00
// the next plus 1
2011-07-31 19:27:44 +02:00
FGAIWaypoint * next = 0 ;
2006-05-13 10:02:17 +00:00
2005-02-10 09:01:51 +00:00
prev = fp - > getPreviousWaypoint ( ) ;
curr = fp - > getCurrentWaypoint ( ) ;
next = fp - > getNextWaypoint ( ) ;
2007-06-09 11:49:16 +00:00
2006-05-13 10:02:17 +00:00
dt_count + = dt ;
2006-08-26 07:22:20 +00:00
///////////////////////////////////////////////////////////////////////////
// Initialize the flightplan
//////////////////////////////////////////////////////////////////////////
2007-06-10 06:06:57 +00:00
if ( ! prev ) {
2007-06-09 11:49:16 +00:00
handleFirstWaypoint ( ) ;
return ;
} // end of initialization
2007-06-15 20:52:32 +00:00
if ( ! fpExecutable ( now ) )
return ;
2007-06-09 11:49:16 +00:00
dt_count = 0 ;
2006-05-13 10:02:17 +00:00
2010-08-29 19:25:34 +02:00
double distanceToDescent ;
if ( reachedEndOfCruise ( distanceToDescent ) ) {
if ( ! loadNextLeg ( distanceToDescent ) ) {
setDie ( true ) ;
return ;
}
prev = fp - > getPreviousWaypoint ( ) ;
curr = fp - > getCurrentWaypoint ( ) ;
next = fp - > getNextWaypoint ( ) ;
}
2007-06-10 06:06:57 +00:00
if ( ! leadPointReached ( curr ) ) {
2007-06-09 11:49:16 +00:00
controlHeading ( curr ) ;
controlSpeed ( curr , next ) ;
2011-10-09 00:25:04 +02:00
2011-07-24 12:48:13 +02:00
/*
2011-04-19 18:01:24 +02:00
if ( speed < 0 ) {
cerr < < getCallSign ( )
< < " : verifying lead distance to waypoint : "
< < fp - > getCurrentWaypoint ( ) - > name < < " "
< < fp - > getLeadDistance ( ) < < " . Distance to go "
< < ( fp - > getDistanceToGo ( pos . getLatitudeDeg ( ) , pos . getLongitudeDeg ( ) , curr ) )
< < " . Target speed = "
< < tgt_speed
< < " . Current speed = "
< < speed
< < " . Minimum Bearing " < < minBearing
< < endl ;
2011-07-24 12:48:13 +02:00
} */
2007-06-10 06:06:57 +00:00
} else {
2011-07-31 19:27:44 +02:00
if ( curr - > isFinished ( ) ) //end of the flight plan
2007-06-09 11:49:16 +00:00
{
2006-05-13 10:02:17 +00:00
if ( fp - > getRepeat ( ) )
fp - > restart ( ) ;
else
setDie ( true ) ;
return ;
}
2007-06-10 06:06:57 +00:00
if ( next ) {
2007-06-09 11:49:16 +00:00
//TODO more intelligent method in AIFlightPlan, no need to send data it already has :-)
2006-05-13 10:02:17 +00:00
tgt_heading = fp - > getBearing ( curr , next ) ;
spinCounter = 0 ;
}
2007-06-09 11:49:16 +00:00
//TODO let the fp handle this (loading of next leg)
2009-06-14 15:24:30 +00:00
fp - > IncrementWaypoint ( trafficRef ! = 0 ) ;
2010-08-29 19:25:34 +02:00
if ( ( ( ! ( fp - > getNextWaypoint ( ) ) ) ) & & ( trafficRef ! = 0 ) )
2008-11-16 13:41:24 +00:00
if ( ! loadNextLeg ( ) ) {
setDie ( true ) ;
return ;
}
2006-05-13 10:02:17 +00:00
prev = fp - > getPreviousWaypoint ( ) ;
curr = fp - > getCurrentWaypoint ( ) ;
next = fp - > getNextWaypoint ( ) ;
// Now that we have incremented the waypoints, excute some traffic manager specific code
2007-06-10 06:06:57 +00:00
if ( trafficRef ) {
2007-06-09 11:49:16 +00:00
//TODO isn't this best executed right at the beginning?
2007-06-10 06:06:57 +00:00
if ( ! aiTrafficVisible ( ) ) {
2006-05-13 10:02:17 +00:00
setDie ( true ) ;
return ;
}
2007-06-10 06:06:57 +00:00
if ( ! handleAirportEndPoints ( prev , now ) ) {
2006-05-13 10:02:17 +00:00
setDie ( true ) ;
return ;
}
2007-06-09 11:49:16 +00:00
announcePositionToController ( ) ;
2006-05-13 10:02:17 +00:00
}
2007-06-10 06:06:57 +00:00
if ( next ) {
2008-04-02 19:01:48 +00:00
fp - > setLeadDistance ( tgt_speed , tgt_heading , curr , next ) ;
2006-05-13 10:02:17 +00:00
}
2011-10-09 00:25:04 +02:00
2011-07-31 19:27:44 +02:00
if ( ! ( prev - > getOn_ground ( ) ) ) // only update the tgt altitude from flightplan if not on the ground
2007-06-09 11:49:16 +00:00
{
2011-07-31 19:27:44 +02:00
tgt_altitude_ft = prev - > getAltitude ( ) ;
if ( curr - > getCrossat ( ) > - 1000.0 ) {
2006-05-13 10:02:17 +00:00
use_perf_vs = false ;
2011-10-09 00:25:04 +02:00
// Distance to go in meters
double vert_dist_ft = curr - > getCrossat ( ) - altitude_ft ;
double err_dist = prev - > getCrossat ( ) - altitude_ft ;
double dist_m = fp - > getDistanceToGo ( pos . getLatitudeDeg ( ) , pos . getLongitudeDeg ( ) , curr ) ;
tgt_vs = calcVerticalSpeed ( vert_dist_ft , dist_m , speed , err_dist ) ;
2011-10-05 21:40:47 +02:00
checkTcas ( ) ;
2011-07-31 19:27:44 +02:00
tgt_altitude_ft = curr - > getCrossat ( ) ;
2007-06-10 06:06:57 +00:00
} else {
2006-05-13 10:02:17 +00:00
use_perf_vs = true ;
}
}
2011-07-31 19:27:44 +02:00
AccelTo ( prev - > getSpeed ( ) ) ;
2006-05-13 10:02:17 +00:00
hdg_lock = alt_lock = true ;
2011-07-31 19:27:44 +02:00
no_roll = prev - > getOn_ground ( ) ;
2004-05-15 09:07:55 +00:00
}
}
2011-10-09 00:25:04 +02:00
double FGAIAircraft : : calcVerticalSpeed ( double vert_ft , double dist_m , double speed , double err )
{
// err is negative when we passed too high
double vert_m = vert_ft * SG_FEET_TO_METER ;
double err_m = err * SG_FEET_TO_METER ;
//double angle = atan2(vert_m, dist_m);
double speedMs = ( speed * SG_NM_TO_METER ) / 3600 ;
//double vs = cos(angle) * speedMs; // Now in m/s
double vs = 0 ;
//cerr << "Error term = " << err_m << endl;
if ( dist_m ) {
vs = ( ( vert_m ) / dist_m ) * speedMs ;
}
// Convert to feet per minute
vs * = ( SG_METER_TO_FEET * 60 ) ;
//if (getCallSign() == "LUFTHANSA2002")
//if (fabs(vs) > 100000) {
// if (getCallSign() == "LUFTHANSA2057") {
// cerr << getCallSign() << " " << fp->getPreviousWaypoint()->getName() << ". Alt = " << altitude_ft << " vertical dist = " << vert_m << " horiz dist = " << dist_m << " << angle = " << angle * SG_RADIANS_TO_DEGREES << " vs " << vs << " horizontal speed " << speed << "Previous crossAT " << fp->getPreviousWaypoint()->getCrossat() << endl;
// //= (curr->getCrossat() - altitude_ft) / (fp->getDistanceToGo(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr)
// // / 6076.0 / speed*60.0);
// //raise(SIGSEGV);
// }
return vs ;
}
void FGAIAircraft : : assertSpeed ( double speed )
{
if ( ( speed < - 50 ) | | ( speed > 1000 ) ) {
cerr < < getCallSign ( ) < < " "
< < " Previous waypoint " < < fp - > getPreviousWaypoint ( ) - > getName ( ) < < " "
< < " Departure airport " < < trafficRef - > getDepartureAirport ( ) < < " "
< < " Leg " < < fp - > getLeg ( ) < < " "
< < " target_speed << " < < tgt_speed < < " "
< < " speedFraction << " < < speedFraction < < " "
< < " Currecnt speed << " < < speed < < " "
< < endl ;
2011-10-10 18:51:41 +02:00
//raise(SIGSEGV);
2011-10-09 00:25:04 +02:00
}
}
2011-01-17 23:33:54 +01:00
void FGAIAircraft : : checkTcas ( void )
{
if ( props - > getIntValue ( " tcas/threat-level " , 0 ) = = 3 )
{
int RASense = props - > getIntValue ( " tcas/ra-sense " , 0 ) ;
if ( ( RASense > 0 ) & & ( tgt_vs < 4000 ) )
// upward RA: climb!
tgt_vs = 4000 ;
else
if ( RASense < 0 )
{
// downward RA: descend!
if ( altitude_ft < 1000 )
{
// too low: level off
if ( tgt_vs > 0 )
tgt_vs = 0 ;
}
else
{
if ( tgt_vs > - 4000 )
tgt_vs = - 4000 ;
}
}
}
}
2007-06-09 11:49:16 +00:00
2007-06-10 06:06:57 +00:00
void FGAIAircraft : : initializeFlightPlan ( ) {
2006-08-26 07:22:20 +00:00
}
2006-05-13 10:02:17 +00:00
2007-06-10 06:06:57 +00:00
bool FGAIAircraft : : _getGearDown ( ) const {
2007-06-28 07:47:20 +00:00
return _performance - > gearExtensible ( this ) ;
2004-09-08 13:21:40 +00:00
}
2005-02-10 09:01:51 +00:00
2009-03-22 13:49:51 +00:00
const char * FGAIAircraft : : _getTransponderCode ( ) const {
return transponderCode . c_str ( ) ;
}
2011-07-31 19:27:44 +02:00
// NOTE: Check whether the new (delayed leg increment code has any effect on this code.
// Probably not, because it should only be executed after we have already passed the leg incrementing waypoint.
2009-03-22 13:49:51 +00:00
2010-08-29 19:25:34 +02:00
bool FGAIAircraft : : loadNextLeg ( double distance ) {
2007-06-09 11:49:16 +00:00
2006-05-13 10:02:17 +00:00
int leg ;
2011-08-01 21:34:33 +02:00
if ( ( leg = fp - > getLeg ( ) ) = = 9 ) {
2008-11-16 13:41:24 +00:00
if ( ! trafficRef - > next ( ) ) {
return false ;
}
2007-07-09 05:07:56 +00:00
setCallSign ( trafficRef - > getCallSign ( ) ) ;
2011-08-01 21:34:33 +02:00
leg = 0 ;
2006-05-13 10:02:17 +00:00
fp - > setLeg ( leg ) ;
2005-02-10 09:01:51 +00:00
}
2007-06-09 11:49:16 +00:00
2006-05-13 10:02:17 +00:00
FGAirport * dep = trafficRef - > getDepartureAirport ( ) ;
FGAirport * arr = trafficRef - > getArrivalAirport ( ) ;
2007-06-10 06:06:57 +00:00
if ( ! ( dep & & arr ) ) {
2006-05-13 10:02:17 +00:00
setDie ( true ) ;
2007-06-10 06:06:57 +00:00
} else {
2006-05-13 10:02:17 +00:00
double cruiseAlt = trafficRef - > getCruiseAlt ( ) * 100 ;
2009-01-30 18:48:44 +00:00
fp - > create ( this ,
dep ,
2007-06-10 06:06:57 +00:00
arr ,
2011-07-31 19:27:44 +02:00
leg + 1 ,
2009-01-30 18:48:44 +00:00
cruiseAlt ,
2007-06-10 06:06:57 +00:00
trafficRef - > getSpeed ( ) ,
_getLatitude ( ) ,
_getLongitude ( ) ,
false ,
trafficRef - > getRadius ( ) ,
trafficRef - > getFlightType ( ) ,
acType ,
2010-08-29 19:25:34 +02:00
company ,
distance ) ;
2008-11-16 13:41:24 +00:00
//cerr << "created leg " << leg << " for " << trafficRef->getCallSign() << endl;
2005-02-10 09:01:51 +00:00
}
2008-11-16 13:41:24 +00:00
return true ;
2005-02-10 09:01:51 +00:00
}
2006-05-13 10:02:17 +00:00
// Note: This code is copied from David Luff's AILocalTraffic
2005-02-10 09:01:51 +00:00
// Warning - ground elev determination is CPU intensive
// Either this function or the logic of how often it is called
// will almost certainly change.
2007-06-10 06:06:57 +00:00
void FGAIAircraft : : getGroundElev ( double dt ) {
2006-05-13 10:02:17 +00:00
dt_elev_count + = dt ;
2011-01-10 20:53:46 +01:00
if ( ! needGroundElevation ( ) )
return ;
2006-05-13 10:02:17 +00:00
// Update minimally every three secs, but add some randomness
2008-07-13 12:51:06 +00:00
// to prevent all AI objects doing this in synchrony
2006-05-13 10:02:17 +00:00
if ( dt_elev_count < ( 3.0 ) + ( rand ( ) % 10 ) )
return ;
2007-06-28 07:47:20 +00:00
dt_elev_count = 0 ;
2006-05-13 10:02:17 +00:00
// Only do the proper hitlist stuff if we are within visible range of the viewer.
2007-06-10 06:06:57 +00:00
if ( ! invisible ) {
2006-05-13 10:02:17 +00:00
double visibility_meters = fgGetDouble ( " /environment/visibility-m " ) ;
FGViewer * vw = globals - > get_current_view ( ) ;
2009-06-09 12:16:21 +00:00
if ( SGGeodesy : : distanceM ( vw - > getPosition ( ) , pos ) > visibility_meters ) {
2006-05-13 10:02:17 +00:00
return ;
}
double range = 500.0 ;
2010-11-19 13:59:43 +01:00
if ( globals - > get_tile_mgr ( ) - > schedule_scenery ( pos , range , 5.0 ) )
{
double alt ;
if ( getGroundElevationM ( SGGeod : : fromGeodM ( pos , 20000 ) , alt , 0 ) )
2011-01-10 20:53:46 +01:00
{
2010-11-19 13:59:43 +01:00
tgt_altitude_ft = alt * SG_METER_TO_FEET ;
2011-01-10 20:53:46 +01:00
if ( isStationary ( ) )
{
// aircraft is stationary and we obtained altitude for this spot - we're done.
_needsGroundElevation = false ;
}
}
2006-05-13 10:02:17 +00:00
}
}
2006-01-30 13:29:49 +00:00
}
2006-04-19 17:36:41 +00:00
2006-05-13 10:02:17 +00:00
2007-06-10 06:06:57 +00:00
void FGAIAircraft : : doGroundAltitude ( ) {
2011-10-09 00:25:04 +02:00
if ( ( fp - > getLeg ( ) = = 7 ) & & ( ( altitude_ft - tgt_altitude_ft ) > 5 ) ) {
tgt_vs = - 500 ;
} else {
if ( ( fabs ( altitude_ft - ( tgt_altitude_ft + groundOffset ) ) > 1000.0 ) | |
( isStationary ( ) ) )
altitude_ft = ( tgt_altitude_ft + groundOffset ) ;
else
altitude_ft + = 0.1 * ( ( tgt_altitude_ft + groundOffset ) - altitude_ft ) ;
tgt_vs = 0 ;
}
2006-04-19 17:36:41 +00:00
}
2006-05-13 10:02:17 +00:00
2007-06-10 06:06:57 +00:00
void FGAIAircraft : : announcePositionToController ( ) {
if ( trafficRef ) {
2007-06-09 11:49:16 +00:00
int leg = fp - > getLeg ( ) ;
2006-05-13 10:02:17 +00:00
2008-07-13 12:51:06 +00:00
// Note that leg has been incremented after creating the current leg, so we should use
2007-06-09 11:49:16 +00:00
// leg numbers here that are one higher than the number that is used to create the leg
2011-07-31 19:27:44 +02:00
// NOTE: As of July, 30, 2011, the post-creation leg updating is no longer happening.
// Leg numbers are updated only once the aircraft passes the last waypoint created for that legm so I should probably just use
// the original leg numbers here!
2007-06-10 06:06:57 +00:00
switch ( leg ) {
2011-07-31 19:27:44 +02:00
case 1 : // Startup and Push back
2008-07-13 12:51:06 +00:00
if ( trafficRef - > getDepartureAirport ( ) - > getDynamics ( ) )
controller = trafficRef - > getDepartureAirport ( ) - > getDynamics ( ) - > getStartupController ( ) ;
break ;
2011-07-31 19:27:44 +02:00
case 2 : // Taxiing to runway
2007-06-10 06:06:57 +00:00
if ( trafficRef - > getDepartureAirport ( ) - > getDynamics ( ) - > getGroundNetwork ( ) - > exists ( ) )
controller = trafficRef - > getDepartureAirport ( ) - > getDynamics ( ) - > getGroundNetwork ( ) ;
break ;
2011-07-31 19:27:44 +02:00
case 3 : //Take off tower controller
2007-06-10 06:06:57 +00:00
if ( trafficRef - > getDepartureAirport ( ) - > getDynamics ( ) ) {
controller = trafficRef - > getDepartureAirport ( ) - > getDynamics ( ) - > getTowerController ( ) ;
2011-10-09 00:25:04 +02:00
towerController = 0 ;
2007-06-10 06:06:57 +00:00
} else {
cerr < < " Error: Could not find Dynamics at airport : " < < trafficRef - > getDepartureAirport ( ) - > getId ( ) < < endl ;
}
break ;
2011-07-31 19:27:44 +02:00
case 6 :
2010-08-29 19:25:34 +02:00
if ( trafficRef - > getDepartureAirport ( ) - > getDynamics ( ) ) {
controller = trafficRef - > getArrivalAirport ( ) - > getDynamics ( ) - > getApproachController ( ) ;
}
break ;
2011-07-31 19:27:44 +02:00
case 8 : // Taxiing for parking
2007-06-10 06:06:57 +00:00
if ( trafficRef - > getArrivalAirport ( ) - > getDynamics ( ) - > getGroundNetwork ( ) - > exists ( ) )
controller = trafficRef - > getArrivalAirport ( ) - > getDynamics ( ) - > getGroundNetwork ( ) ;
break ;
default :
controller = 0 ;
break ;
2007-06-09 11:49:16 +00:00
}
2006-08-26 07:22:20 +00:00
2007-06-10 06:06:57 +00:00
if ( ( controller ! = prevController ) & & ( prevController ! = 0 ) ) {
2007-06-09 11:49:16 +00:00
prevController - > signOff ( getID ( ) ) ;
}
prevController = controller ;
2007-06-10 06:06:57 +00:00
if ( controller ) {
2011-07-31 19:27:44 +02:00
controller - > announcePosition ( getID ( ) , fp , fp - > getCurrentWaypoint ( ) - > getRouteIndex ( ) ,
2007-06-10 06:06:57 +00:00
_getLatitude ( ) , _getLongitude ( ) , hdg , speed , altitude_ft ,
2008-07-13 12:51:06 +00:00
trafficRef - > getRadius ( ) , leg , this ) ;
2007-06-09 11:49:16 +00:00
}
2006-08-26 07:22:20 +00:00
}
}
2011-08-07 21:38:50 +02:00
void FGAIAircraft : : scheduleForATCTowerDepartureControl ( int state ) {
if ( ! takeOffStatus ) {
2011-08-03 23:09:52 +02:00
int leg = fp - > getLeg ( ) ;
if ( trafficRef ) {
if ( trafficRef - > getDepartureAirport ( ) - > getDynamics ( ) ) {
towerController = trafficRef - > getDepartureAirport ( ) - > getDynamics ( ) - > getTowerController ( ) ;
} else {
cerr < < " Error: Could not find Dynamics at airport : " < < trafficRef - > getDepartureAirport ( ) - > getId ( ) < < endl ;
}
if ( towerController ) {
towerController - > announcePosition ( getID ( ) , fp , fp - > getCurrentWaypoint ( ) - > getRouteIndex ( ) ,
_getLatitude ( ) , _getLongitude ( ) , hdg , speed , altitude_ft ,
trafficRef - > getRadius ( ) , leg , this ) ;
2011-08-10 21:39:28 +02:00
//cerr << "Scheduling " << trafficRef->getCallSign() << " for takeoff " << endl;
2011-08-03 23:09:52 +02:00
}
}
}
2011-08-07 21:38:50 +02:00
takeOffStatus = state ;
2011-08-03 23:09:52 +02:00
}
2008-07-13 12:51:06 +00:00
// Process ATC instructions and report back
2006-08-26 07:22:20 +00:00
2007-06-10 06:06:57 +00:00
void FGAIAircraft : : processATC ( FGATCInstruction instruction ) {
2007-06-28 07:47:20 +00:00
if ( instruction . getCheckForCircularWait ( ) ) {
// This is not exactly an elegant solution,
// but at least it gives me a chance to check
// if circular waits are resolved.
// For now, just take the offending aircraft
// out of the scene
setDie ( true ) ;
// a more proper way should be - of course - to
// let an offending aircraft take an evasive action
// for instance taxi back a little bit.
}
2007-06-09 11:49:16 +00:00
//cerr << "Processing ATC instruction (not Implimented yet)" << endl;
2007-06-10 06:06:57 +00:00
if ( instruction . getHoldPattern ( ) ) { }
2006-08-26 07:22:20 +00:00
2007-06-09 11:49:16 +00:00
// Hold Position
2007-06-10 06:06:57 +00:00
if ( instruction . getHoldPosition ( ) ) {
if ( ! holdPos ) {
2007-06-09 11:49:16 +00:00
holdPos = true ;
}
AccelTo ( 0.0 ) ;
2007-06-10 06:06:57 +00:00
} else {
if ( holdPos ) {
2007-06-09 11:49:16 +00:00
//if (trafficRef)
2008-07-13 12:51:06 +00:00
// cerr << trafficRef->getCallSign() << " Resuming Taxi." << endl;
2007-06-09 11:49:16 +00:00
holdPos = false ;
}
// Change speed Instruction. This can only be excecuted when there is no
// Hold position instruction.
2007-06-10 06:06:57 +00:00
if ( instruction . getChangeSpeed ( ) ) {
2007-06-09 11:49:16 +00:00
// if (trafficRef)
//cerr << trafficRef->getCallSign() << " Changing Speed " << endl;
AccelTo ( instruction . getSpeed ( ) ) ;
2007-06-10 06:06:57 +00:00
} else {
2011-07-31 19:27:44 +02:00
if ( fp ) AccelTo ( fp - > getPreviousWaypoint ( ) - > getSpeed ( ) ) ;
2007-06-09 11:49:16 +00:00
}
}
2007-06-10 06:06:57 +00:00
if ( instruction . getChangeHeading ( ) ) {
2007-06-09 11:49:16 +00:00
hdg_lock = false ;
TurnTo ( instruction . getHeading ( ) ) ;
2007-06-10 06:06:57 +00:00
} else {
if ( fp ) {
hdg_lock = true ;
}
2007-06-09 11:49:16 +00:00
}
2007-06-10 06:06:57 +00:00
if ( instruction . getChangeAltitude ( ) ) { }
2007-06-09 11:49:16 +00:00
}
2007-06-10 06:06:57 +00:00
void FGAIAircraft : : handleFirstWaypoint ( ) {
2007-06-09 11:49:16 +00:00
bool eraseWaypoints ; //TODO YAGNI
2008-04-02 19:01:48 +00:00
headingError = 0 ;
2007-06-10 06:06:57 +00:00
if ( trafficRef ) {
2007-06-09 11:49:16 +00:00
eraseWaypoints = true ;
2007-06-10 06:06:57 +00:00
} else {
2007-06-09 11:49:16 +00:00
eraseWaypoints = false ;
}
2011-07-31 19:27:44 +02:00
FGAIWaypoint * prev = 0 ; // the one behind you
FGAIWaypoint * curr = 0 ; // the one ahead
FGAIWaypoint * next = 0 ; // the next plus 1
2007-06-09 11:49:16 +00:00
spinCounter = 0 ;
//TODO fp should handle this
fp - > IncrementWaypoint ( eraseWaypoints ) ;
if ( ! ( fp - > getNextWaypoint ( ) ) & & trafficRef )
2008-11-16 13:41:24 +00:00
if ( ! loadNextLeg ( ) ) {
setDie ( true ) ;
return ;
}
2007-06-09 11:49:16 +00:00
prev = fp - > getPreviousWaypoint ( ) ; //first waypoint
curr = fp - > getCurrentWaypoint ( ) ; //second waypoint
next = fp - > getNextWaypoint ( ) ; //third waypoint (might not exist!)
2011-07-31 19:27:44 +02:00
setLatitude ( prev - > getLatitude ( ) ) ;
setLongitude ( prev - > getLongitude ( ) ) ;
setSpeed ( prev - > getSpeed ( ) ) ;
setAltitude ( prev - > getAltitude ( ) ) ;
2007-06-09 11:49:16 +00:00
2011-07-31 19:27:44 +02:00
if ( prev - > getSpeed ( ) > 0.0 )
setHeading ( fp - > getBearing ( prev - > getLatitude ( ) , prev - > getLongitude ( ) , curr ) ) ;
2007-06-09 11:49:16 +00:00
else
2011-07-31 19:27:44 +02:00
setHeading ( fp - > getBearing ( curr - > getLatitude ( ) , curr - > getLongitude ( ) , prev ) ) ;
2007-06-09 11:49:16 +00:00
// If next doesn't exist, as in incrementally created flightplans for
// AI/Trafficmanager created plans,
// Make sure lead distance is initialized otherwise
if ( next )
fp - > setLeadDistance ( speed , hdg , curr , next ) ;
2011-07-31 19:27:44 +02:00
if ( curr - > getCrossat ( ) > - 1000.0 ) //use a calculated descent/climb rate
2007-06-09 11:49:16 +00:00
{
use_perf_vs = false ;
2011-10-09 00:25:04 +02:00
//tgt_vs = (curr->getCrossat() - prev->getAltitude())
// / (fp->getDistanceToGo(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr)
// / 6076.0 / prev->getSpeed()*60.0);
double vert_dist_ft = curr - > getCrossat ( ) - altitude_ft ;
double err_dist = prev - > getCrossat ( ) - altitude_ft ;
double dist_m = fp - > getDistanceToGo ( pos . getLatitudeDeg ( ) , pos . getLongitudeDeg ( ) , curr ) ;
tgt_vs = calcVerticalSpeed ( vert_dist_ft , dist_m , speed , err_dist ) ;
2011-10-05 21:40:47 +02:00
checkTcas ( ) ;
2011-07-31 19:27:44 +02:00
tgt_altitude_ft = curr - > getCrossat ( ) ;
2007-06-10 06:06:57 +00:00
} else {
2007-06-09 11:49:16 +00:00
use_perf_vs = true ;
2011-07-31 19:27:44 +02:00
tgt_altitude_ft = prev - > getAltitude ( ) ;
2007-06-09 11:49:16 +00:00
}
alt_lock = hdg_lock = true ;
2011-07-31 19:27:44 +02:00
no_roll = prev - > getOn_ground ( ) ;
2007-06-10 06:06:57 +00:00
if ( no_roll ) {
2007-06-09 11:49:16 +00:00
Transform ( ) ; // make sure aip is initialized.
getGroundElev ( 60.1 ) ; // make sure it's executed first time around, so force a large dt value
doGroundAltitude ( ) ;
2011-01-10 20:53:46 +01:00
_needsGroundElevation = true ; // check ground elevation again (maybe scenery wasn't available yet)
2007-06-09 11:49:16 +00:00
}
// Make sure to announce the aircraft's position
announcePositionToController ( ) ;
prevSpeed = 0 ;
}
/**
* Check Execution time ( currently once every 100 ms )
* Add a bit of randomization to prevent the execution of all flight plans
* in synchrony , which can add significant periodic framerate flutter .
*
* @ param now
* @ return
*/
2007-06-10 06:06:57 +00:00
bool FGAIAircraft : : fpExecutable ( time_t now ) {
2007-06-09 11:49:16 +00:00
double rand_exec_time = ( rand ( ) % 100 ) / 100 ;
return ( dt_count > ( 0.1 + rand_exec_time ) ) & & ( fp - > isActive ( now ) ) ;
}
/**
* Check to see if we ' ve reached the lead point for our next turn
*
* @ param curr
* @ return
*/
2011-07-31 19:27:44 +02:00
bool FGAIAircraft : : leadPointReached ( FGAIWaypoint * curr ) {
2007-06-09 11:49:16 +00:00
double dist_to_go = fp - > getDistanceToGo ( pos . getLatitudeDeg ( ) , pos . getLongitudeDeg ( ) , curr ) ;
//cerr << "2" << endl;
double lead_dist = fp - > getLeadDistance ( ) ;
// experimental: Use fabs, because speed can be negative (I hope) during push_back.
2011-07-31 19:27:44 +02:00
if ( ( dist_to_go < fabs ( 10.0 * speed ) ) & & ( speed < 0 ) & & ( tgt_speed < 0 ) & & fp - > getCurrentWaypoint ( ) - > contains ( " PushBackPoint " ) ) {
2011-04-19 18:01:24 +02:00
tgt_speed = - ( dist_to_go / 10.0 ) ;
if ( tgt_speed > - 0.5 ) {
tgt_speed = - 0.5 ;
}
2011-10-10 18:51:41 +02:00
//assertSpeed(tgt_speed);
2011-07-31 19:27:44 +02:00
if ( fp - > getPreviousWaypoint ( ) - > getSpeed ( ) < tgt_speed ) {
fp - > getPreviousWaypoint ( ) - > setSpeed ( tgt_speed ) ;
2011-04-19 18:01:24 +02:00
}
}
2007-06-10 06:06:57 +00:00
if ( lead_dist < fabs ( 2 * speed ) ) {
2007-06-15 20:52:32 +00:00
//don't skip over the waypoint
lead_dist = fabs ( 2 * speed ) ;
//cerr << "Extending lead distance to " << lead_dist << endl;
2007-06-09 11:49:16 +00:00
}
//prev_dist_to_go = dist_to_go;
2008-04-02 19:01:48 +00:00
//if (dist_to_go < lead_dist)
2008-11-16 13:41:24 +00:00
// cerr << trafficRef->getCallSign() << " Distance : "
// << dist_to_go << ": Lead distance "
// << lead_dist << " " << curr->name
// << " Ground target speed " << groundTargetSpeed << endl;
2010-09-27 17:48:38 +02:00
double bearing = 0 ;
2011-10-09 23:44:42 +02:00
// don't do bearing calculations for ground traffic
2010-08-29 19:25:34 +02:00
bearing = getBearing ( fp - > getBearing ( pos . getLatitudeDeg ( ) , pos . getLongitudeDeg ( ) , curr ) ) ;
if ( bearing < minBearing ) {
minBearing = bearing ;
if ( minBearing < 10 ) {
minBearing = 10 ;
}
if ( ( minBearing < 360.0 ) & & ( minBearing > 10.0 ) ) {
2011-10-09 00:25:04 +02:00
speedFraction = 0.5 + ( cos ( minBearing * SG_DEGREES_TO_RADIANS ) * 0.5 ) ;
2010-08-29 19:25:34 +02:00
} else {
speedFraction = 1.0 ;
}
2011-10-09 23:44:42 +02:00
}
2010-08-29 19:25:34 +02:00
if ( trafficRef ) {
//cerr << "Tracking callsign : \"" << fgGetString("/ai/track-callsign") << "\"" << endl;
2011-10-05 21:40:47 +02:00
/* if (trafficRef->getCallSign() == fgGetString("/ai/track-callsign")) {
2010-08-29 19:25:34 +02:00
cerr < < trafficRef - > getCallSign ( ) < < " " < < tgt_altitude_ft < < " " < < _getSpeed ( ) < < " "
2011-10-05 21:40:47 +02:00
< < _getAltitude ( ) < < " " < < _getLatitude ( ) < < " " < < _getLongitude ( ) < < " " < < dist_to_go < < " " < < lead_dist < < " " < < curr - > name < < " " < < vs < < " " < < tgt_vs < < " " < < bearing < < " " < < minBearing < < " " < < speedFraction < < endl ;
} */
2010-08-29 19:25:34 +02:00
}
2011-10-09 23:44:42 +02:00
if ( ( dist_to_go < lead_dist ) | |
( ( dist_to_go > prev_dist_to_go ) & & ( bearing > ( minBearing * 1.1 ) ) ) ) {
2010-08-29 19:25:34 +02:00
minBearing = 360 ;
2011-10-09 00:25:04 +02:00
speedFraction = 1.0 ;
2011-10-09 23:44:42 +02:00
prev_dist_to_go = HUGE_VAL ;
2010-08-29 19:25:34 +02:00
return true ;
} else {
2011-10-09 23:44:42 +02:00
prev_dist_to_go = dist_to_go ;
2010-08-29 19:25:34 +02:00
return false ;
}
2007-06-09 11:49:16 +00:00
}
2011-10-26 17:26:11 +01:00
bool FGAIAircraft : : aiTrafficVisible ( )
{
SGVec3d cartPos = SGVec3d : : fromGeod ( pos ) ;
const double d2 = ( TRAFFICTOAIDISTTODIE * SG_NM_TO_METER ) *
( TRAFFICTOAIDISTTODIE * SG_NM_TO_METER ) ;
return ( distSqr ( cartPos , globals - > get_aircraft_positon_cart ( ) ) < d2 ) ;
2007-06-09 11:49:16 +00:00
}
/**
* Handle release of parking gate , once were taxiing . Also ensure service time at the gate
* in the case of an arrival .
*
* @ param prev
* @ return
*/
//TODO the trafficRef is the right place for the method
2011-07-31 19:27:44 +02:00
bool FGAIAircraft : : handleAirportEndPoints ( FGAIWaypoint * prev , time_t now ) {
2007-06-09 11:49:16 +00:00
// prepare routing from one airport to another
FGAirport * dep = trafficRef - > getDepartureAirport ( ) ;
FGAirport * arr = trafficRef - > getArrivalAirport ( ) ;
if ( ! ( dep & & arr ) )
return false ;
// This waypoint marks the fact that the aircraft has passed the initial taxi
// departure waypoint, so it can release the parking.
2008-11-16 13:41:24 +00:00
//cerr << trafficRef->getCallSign() << " has passed waypoint " << prev->name << " at speed " << speed << endl;
2011-08-07 21:38:50 +02:00
//cerr << "Passing waypoint : " << prev->getName() << endl;
2011-07-31 19:27:44 +02:00
if ( prev - > contains ( " PushBackPoint " ) ) {
2007-06-09 11:49:16 +00:00
dep - > getDynamics ( ) - > releaseParking ( fp - > getGate ( ) ) ;
2010-04-25 08:32:53 +00:00
AccelTo ( 0.0 ) ;
2011-08-07 21:38:50 +02:00
//setTaxiClearanceRequest(true);
2007-06-15 20:52:32 +00:00
}
2011-07-31 19:27:44 +02:00
if ( prev - > contains ( " legend " ) ) {
fp - > incrementLeg ( ) ;
}
2011-08-03 23:09:52 +02:00
if ( prev - > contains ( string ( " DepartureHold " ) ) ) {
2011-08-10 21:39:28 +02:00
//cerr << "Passing point DepartureHold" << endl;
2011-10-09 00:25:04 +02:00
scheduleForATCTowerDepartureControl ( 1 ) ;
2011-08-03 23:09:52 +02:00
}
2011-10-09 00:25:04 +02:00
if ( prev - > contains ( string ( " Accel " ) ) ) {
takeOffStatus = 3 ;
}
2011-10-09 23:44:42 +02:00
//if (prev->contains(string("landing"))) {
// if (speed < _performance->vTaxi() * 2) {
// fp->shortenToFirst(2, "legend");
// }
//}
2011-10-10 21:55:09 +02:00
//if (prev->contains(string("final"))) {
//
// cerr << getCallSign() << " "
// << fp->getPreviousWaypoint()->getName()
// << ". Alt = " << altitude_ft
// << " vs " << vs
// << " horizontal speed " << speed
// << "Previous crossAT " << fp->getPreviousWaypoint()->getCrossat()
// << "Airport elevation" << getTrafficRef()->getArrivalAirport()->getElevation()
// << "Altitude difference " << (altitude_ft - fp->getPreviousWaypoint()->getCrossat()) << endl;
//q}
2007-06-09 11:49:16 +00:00
// This is the last taxi waypoint, and marks the the end of the flight plan
// so, the schedule should update and wait for the next departure time.
2011-07-31 19:27:44 +02:00
if ( prev - > contains ( " END " ) ) {
2007-06-09 11:49:16 +00:00
time_t nextDeparture = trafficRef - > getDepartureTime ( ) ;
// make sure to wait at least 20 minutes at parking to prevent "nervous" taxi behavior
2007-06-10 06:06:57 +00:00
if ( nextDeparture < ( now + 1200 ) ) {
2007-06-09 11:49:16 +00:00
nextDeparture = now + 1200 ;
}
2011-08-07 21:38:50 +02:00
fp - > setTime ( nextDeparture ) ;
2007-06-09 11:49:16 +00:00
}
return true ;
}
/**
* Check difference between target bearing and current heading and correct if necessary .
*
* @ param curr
*/
2011-07-31 19:27:44 +02:00
void FGAIAircraft : : controlHeading ( FGAIWaypoint * curr ) {
2007-06-09 11:49:16 +00:00
double calc_bearing = fp - > getBearing ( pos . getLatitudeDeg ( ) , pos . getLongitudeDeg ( ) , curr ) ;
//cerr << "Bearing = " << calc_bearing << endl;
2007-06-10 06:06:57 +00:00
if ( speed < 0 ) {
2007-06-09 11:49:16 +00:00
calc_bearing + = 180 ;
if ( calc_bearing > 360 )
calc_bearing - = 360 ;
}
2007-06-10 06:06:57 +00:00
if ( finite ( calc_bearing ) ) {
2007-06-09 11:49:16 +00:00
double hdg_error = calc_bearing - tgt_heading ;
2007-07-10 07:01:54 +00:00
if ( fabs ( hdg_error ) > 0.01 ) {
2007-06-09 11:49:16 +00:00
TurnTo ( calc_bearing ) ;
}
2007-06-10 06:06:57 +00:00
} else {
2007-06-09 11:49:16 +00:00
cerr < < " calc_bearing is not a finite number : "
2007-06-10 06:06:57 +00:00
< < " Speed " < < speed
< < " pos : " < < pos . getLatitudeDeg ( ) < < " , " < < pos . getLongitudeDeg ( )
2011-07-31 19:27:44 +02:00
< < " waypoint " < < curr - > getLatitude ( ) < < " , " < < curr - > getLongitude ( ) < < endl ;
cerr < < " waypoint name " < < curr - > getName ( ) ;
2007-06-09 11:49:16 +00:00
exit ( 1 ) ; // FIXME
}
}
/**
* Update the lead distance calculation if speed has changed sufficiently
* to prevent spinning ( hopefully ) ;
*
* @ param curr
* @ param next
*/
2011-07-31 19:27:44 +02:00
void FGAIAircraft : : controlSpeed ( FGAIWaypoint * curr , FGAIWaypoint * next ) {
2007-06-09 11:49:16 +00:00
double speed_diff = speed - prevSpeed ;
2007-06-10 06:06:57 +00:00
if ( fabs ( speed_diff ) > 10 ) {
2007-06-09 11:49:16 +00:00
prevSpeed = speed ;
2011-10-10 18:51:41 +02:00
//assertSpeed(speed);
2007-07-10 07:01:54 +00:00
if ( next ) {
fp - > setLeadDistance ( speed , tgt_heading , curr , next ) ;
}
2007-06-09 11:49:16 +00:00
}
}
/**
* Update target values ( heading , alt , speed ) depending on flight plan or control properties
*/
2010-02-19 00:31:38 +00:00
void FGAIAircraft : : updatePrimaryTargetValues ( bool & flightplanActive , bool & aiOutOfSight ) {
2007-06-09 11:49:16 +00:00
if ( fp ) // AI object has a flightplan
{
//TODO make this a function of AIBase
time_t now = time ( NULL ) + fgGetLong ( " /sim/time/warp " ) ;
//cerr << "UpateTArgetValues() " << endl;
ProcessFlightPlan ( dt , now ) ;
2007-07-21 12:29:09 +00:00
// Do execute Ground elev for inactive aircraft, so they
// Are repositioned to the correct ground altitude when the user flies within visibility range.
// In addition, check whether we are out of user range, so this aircraft
// can be deleted.
if ( onGround ( ) ) {
2007-06-09 11:49:16 +00:00
Transform ( ) ; // make sure aip is initialized.
2007-07-21 12:29:09 +00:00
getGroundElev ( dt ) ;
doGroundAltitude ( ) ;
// Transform();
pos . setElevationFt ( altitude_ft ) ;
}
if ( trafficRef ) {
//cerr << trafficRef->getRegistration() << " Setting altitude to " << altitude_ft;
2010-02-19 00:31:38 +00:00
aiOutOfSight = ! aiTrafficVisible ( ) ;
if ( aiOutOfSight ) {
2007-07-21 12:29:09 +00:00
setDie ( true ) ;
//cerr << trafficRef->getRegistration() << " is set to die " << endl;
2010-02-19 00:31:38 +00:00
aiOutOfSight = true ;
return ;
2007-06-09 11:49:16 +00:00
}
2007-07-21 12:29:09 +00:00
}
2008-07-13 12:51:06 +00:00
timeElapsed = now - fp - > getStartTime ( ) ;
2010-02-19 00:31:38 +00:00
flightplanActive = fp - > isActive ( now ) ;
2007-07-21 12:29:09 +00:00
} else {
2007-06-09 11:49:16 +00:00
// no flight plan, update target heading, speed, and altitude
// from control properties. These default to the initial
// settings in the config file, but can be changed "on the
// fly".
string lat_mode = props - > getStringValue ( " controls/flight/lateral-mode " ) ;
2007-06-10 06:06:57 +00:00
if ( lat_mode = = " roll " ) {
2007-06-09 11:49:16 +00:00
double angle
2007-06-10 06:06:57 +00:00
= props - > getDoubleValue ( " controls/flight/target-roll " ) ;
2007-06-09 11:49:16 +00:00
RollTo ( angle ) ;
2007-06-10 06:06:57 +00:00
} else {
2007-06-09 11:49:16 +00:00
double angle
2007-06-10 06:06:57 +00:00
= props - > getDoubleValue ( " controls/flight/target-hdg " ) ;
2007-06-09 11:49:16 +00:00
TurnTo ( angle ) ;
}
string lon_mode
2007-06-10 06:06:57 +00:00
= props - > getStringValue ( " controls/flight/longitude-mode " ) ;
if ( lon_mode = = " alt " ) {
2007-06-09 11:49:16 +00:00
double alt = props - > getDoubleValue ( " controls/flight/target-alt " ) ;
ClimbTo ( alt ) ;
2007-06-10 06:06:57 +00:00
} else {
2007-06-09 11:49:16 +00:00
double angle
2007-06-10 06:06:57 +00:00
= props - > getDoubleValue ( " controls/flight/target-pitch " ) ;
2007-06-09 11:49:16 +00:00
PitchTo ( angle ) ;
}
AccelTo ( props - > getDoubleValue ( " controls/flight/target-spd " ) ) ;
}
}
2007-06-10 06:06:57 +00:00
void FGAIAircraft : : updatePosition ( ) {
2007-06-09 11:49:16 +00:00
// convert speed to degrees per second
double speed_north_deg_sec = cos ( hdg * SGD_DEGREES_TO_RADIANS )
2007-06-10 06:06:57 +00:00
* speed * 1.686 / ft_per_deg_lat ;
2007-06-09 11:49:16 +00:00
double speed_east_deg_sec = sin ( hdg * SGD_DEGREES_TO_RADIANS )
2007-06-10 06:06:57 +00:00
* speed * 1.686 / ft_per_deg_lon ;
2007-06-09 11:49:16 +00:00
// set new position
pos . setLatitudeDeg ( pos . getLatitudeDeg ( ) + speed_north_deg_sec * dt ) ;
pos . setLongitudeDeg ( pos . getLongitudeDeg ( ) + speed_east_deg_sec * dt ) ;
}
2007-06-10 06:06:57 +00:00
void FGAIAircraft : : updateHeading ( ) {
2007-06-09 11:49:16 +00:00
// adjust heading based on current bank angle
if ( roll = = 0.0 )
roll = 0.01 ;
2007-06-10 06:06:57 +00:00
if ( roll ! = 0.0 ) {
2007-06-09 11:49:16 +00:00
// double turnConstant;
//if (no_roll)
// turnConstant = 0.0088362;
//else
// turnConstant = 0.088362;
// If on ground, calculate heading change directly
2007-06-28 07:47:20 +00:00
if ( onGround ( ) ) {
2007-06-09 11:49:16 +00:00
double headingDiff = fabs ( hdg - tgt_heading ) ;
2008-04-02 19:01:48 +00:00
double bank_sense = 0.0 ;
/*
double diff = fabs ( hdg - tgt_heading ) ;
if ( diff > 180 )
diff = fabs ( diff - 360 ) ;
double sum = hdg + diff ;
if ( sum > 360.0 )
sum - = 360.0 ;
if ( fabs ( sum - tgt_heading ) < 1.0 ) {
bank_sense = 1.0 ; // right turn
} else {
bank_sense = - 1.0 ; // left turn
} */
2007-06-09 11:49:16 +00:00
if ( headingDiff > 180 )
headingDiff = fabs ( headingDiff - 360 ) ;
2008-04-02 19:01:48 +00:00
double sum = hdg + headingDiff ;
if ( sum > 360.0 )
sum - = 360.0 ;
if ( fabs ( sum - tgt_heading ) > 0.0001 ) {
bank_sense = - 1.0 ;
} else {
bank_sense = 1.0 ;
}
2008-07-13 12:51:06 +00:00
//if (trafficRef)
2011-04-19 18:01:24 +02:00
// cerr << trafficRef->getCallSign() << " Heading "
// << hdg << ". Target " << tgt_heading << ". Diff " << fabs(sum - tgt_heading) << ". Speed " << speed << endl;
2008-04-02 19:01:48 +00:00
//if (headingDiff > 60) {
groundTargetSpeed = tgt_speed ; // * cos(headingDiff * SG_DEGREES_TO_RADIANS);
2011-10-10 18:51:41 +02:00
//assertSpeed(groundTargetSpeed);
2008-04-02 19:01:48 +00:00
//groundTargetSpeed = tgt_speed - tgt_speed * (headingDiff/180);
//} else {
// groundTargetSpeed = tgt_speed;
//}
2007-06-09 11:49:16 +00:00
if ( sign ( groundTargetSpeed ) ! = sign ( tgt_speed ) )
groundTargetSpeed = 0.21 * sign ( tgt_speed ) ; // to prevent speed getting stuck in 'negative' mode
2011-10-10 18:51:41 +02:00
//assertSpeed(groundTargetSpeed);
2011-04-19 18:01:24 +02:00
// Only update the target values when we're not moving because otherwise we might introduce an enormous target change rate while waiting a the gate, or holding.
if ( speed ! = 0 ) {
if ( headingDiff > 30.0 ) {
// invert if pushed backward
headingChangeRate + = 10.0 * dt * sign ( roll ) ;
// Clamp the maximum steering rate to 30 degrees per second,
// But only do this when the heading error is decreasing.
if ( ( headingDiff < headingError ) ) {
if ( headingChangeRate > 30 )
headingChangeRate = 30 ;
else if ( headingChangeRate < - 30 )
headingChangeRate = - 30 ;
}
} else {
if ( speed ! = 0 ) {
if ( fabs ( headingChangeRate ) > headingDiff )
headingChangeRate = headingDiff * sign ( roll ) ;
else
headingChangeRate + = dt * sign ( roll ) ;
}
2008-04-02 19:01:48 +00:00
}
2007-06-09 11:49:16 +00:00
}
2011-04-19 18:01:24 +02:00
if ( trafficRef )
2011-05-07 10:03:27 +02:00
//cerr << trafficRef->getCallSign() << " Heading "
// << hdg << ". Target " << tgt_heading << ". Diff " << fabs(sum - tgt_heading) << ". Speed " << speed << "Heading change rate : " << headingChangeRate << " bacnk sence " << bank_sense << endl;
2011-04-19 18:01:24 +02:00
hdg + = headingChangeRate * dt * sqrt ( fabs ( speed ) / 15 ) ;
2008-04-02 19:01:48 +00:00
headingError = headingDiff ;
2011-10-09 23:44:42 +02:00
if ( fabs ( headingError ) < 1.0 ) {
hdg = tgt_heading ;
}
2007-06-10 06:06:57 +00:00
} else {
if ( fabs ( speed ) > 1.0 ) {
2007-06-09 11:49:16 +00:00
turn_radius_ft = 0.088362 * speed * speed
2007-06-10 06:06:57 +00:00
/ tan ( fabs ( roll ) / SG_RADIANS_TO_DEGREES ) ;
} else {
2007-06-09 11:49:16 +00:00
// Check if turn_radius_ft == 0; this might lead to a division by 0.
turn_radius_ft = 1.0 ;
}
double turn_circum_ft = SGD_2PI * turn_radius_ft ;
double dist_covered_ft = speed * 1.686 * dt ;
double alpha = dist_covered_ft / turn_circum_ft * 360.0 ;
hdg + = alpha * sign ( roll ) ;
}
2007-06-10 06:06:57 +00:00
while ( hdg > 360.0 ) {
2007-06-09 11:49:16 +00:00
hdg - = 360.0 ;
spinCounter + + ;
}
2007-06-10 06:06:57 +00:00
while ( hdg < 0.0 ) {
2007-06-09 11:49:16 +00:00
hdg + = 360.0 ;
spinCounter - - ;
}
}
}
2007-06-28 07:47:20 +00:00
void FGAIAircraft : : updateBankAngleTarget ( ) {
2007-06-09 11:49:16 +00:00
// adjust target bank angle if heading lock engaged
2007-06-10 06:06:57 +00:00
if ( hdg_lock ) {
2007-06-09 11:49:16 +00:00
double bank_sense = 0.0 ;
double diff = fabs ( hdg - tgt_heading ) ;
if ( diff > 180 )
diff = fabs ( diff - 360 ) ;
double sum = hdg + diff ;
if ( sum > 360.0 )
sum - = 360.0 ;
2007-06-10 06:06:57 +00:00
if ( fabs ( sum - tgt_heading ) < 1.0 ) {
2007-06-09 11:49:16 +00:00
bank_sense = 1.0 ; // right turn
2007-06-10 06:06:57 +00:00
} else {
2007-06-09 11:49:16 +00:00
bank_sense = - 1.0 ; // left turn
}
2007-06-28 07:47:20 +00:00
if ( diff < _performance - > maximumBankAngle ( ) ) {
2007-06-09 11:49:16 +00:00
tgt_roll = diff * bank_sense ;
2007-06-10 06:06:57 +00:00
} else {
2007-06-28 07:47:20 +00:00
tgt_roll = _performance - > maximumBankAngle ( ) * bank_sense ;
2007-06-09 11:49:16 +00:00
}
2007-06-28 07:47:20 +00:00
if ( ( fabs ( ( double ) spinCounter ) > 1 ) & & ( diff > _performance - > maximumBankAngle ( ) ) ) {
2007-06-09 11:49:16 +00:00
tgt_speed * = 0.999 ; // Ugly hack: If aircraft get stuck, they will continually spin around.
// The only way to resolve this is to make them slow down.
}
}
}
2007-06-28 07:47:20 +00:00
void FGAIAircraft : : updateVerticalSpeedTarget ( ) {
2007-06-09 11:49:16 +00:00
// adjust target Altitude, based on ground elevation when on ground
2007-06-28 07:47:20 +00:00
if ( onGround ( ) ) {
2007-06-09 11:49:16 +00:00
getGroundElev ( dt ) ;
doGroundAltitude ( ) ;
2007-06-28 07:47:20 +00:00
} else if ( alt_lock ) {
// find target vertical speed
if ( use_perf_vs ) {
2007-06-10 06:06:57 +00:00
if ( altitude_ft < tgt_altitude_ft ) {
2007-06-09 11:49:16 +00:00
tgt_vs = tgt_altitude_ft - altitude_ft ;
2007-06-28 07:47:20 +00:00
if ( tgt_vs > _performance - > climbRate ( ) )
tgt_vs = _performance - > climbRate ( ) ;
2007-06-10 06:06:57 +00:00
} else {
2007-06-09 11:49:16 +00:00
tgt_vs = tgt_altitude_ft - altitude_ft ;
2007-06-28 07:47:20 +00:00
if ( tgt_vs < ( - _performance - > descentRate ( ) ) )
tgt_vs = - _performance - > descentRate ( ) ;
2007-06-09 11:49:16 +00:00
}
2007-06-28 07:47:20 +00:00
} else {
2011-10-09 00:25:04 +02:00
double vert_dist_ft = fp - > getCurrentWaypoint ( ) - > getCrossat ( ) - altitude_ft ;
double err_dist = 0 ; //prev->getCrossat() - altitude_ft;
double dist_m = fp - > getDistanceToGo ( pos . getLatitudeDeg ( ) , pos . getLongitudeDeg ( ) , fp - > getCurrentWaypoint ( ) ) ;
tgt_vs = calcVerticalSpeed ( vert_dist_ft , dist_m , speed , err_dist ) ;
//cerr << "Target vs before : " << tgt_vs;
/* double max_vs = 10*(tgt_altitude_ft - altitude_ft);
2007-06-09 11:49:16 +00:00
double min_vs = 100 ;
if ( tgt_altitude_ft < altitude_ft )
min_vs = - 100.0 ;
if ( ( fabs ( tgt_altitude_ft - altitude_ft ) < 1500.0 )
2007-06-10 06:06:57 +00:00
& & ( fabs ( max_vs ) < fabs ( tgt_vs ) ) )
2007-06-09 11:49:16 +00:00
tgt_vs = max_vs ;
if ( fabs ( tgt_vs ) < fabs ( min_vs ) )
2011-10-09 00:25:04 +02:00
tgt_vs = min_vs ; */
//cerr << "target vs : after " << tgt_vs << endl;
2007-06-09 11:49:16 +00:00
}
2007-06-28 07:47:20 +00:00
} //else
// tgt_vs = 0.0;
2011-01-17 23:33:54 +01:00
checkTcas ( ) ;
2007-06-28 07:47:20 +00:00
}
void FGAIAircraft : : updatePitchAngleTarget ( ) {
// if on ground and above vRotate -> initial rotation
if ( onGround ( ) & & ( speed > _performance - > vRotate ( ) ) )
tgt_pitch = 8.0 ; // some rough B737 value
//TODO pitch angle on approach and landing
// match pitch angle to vertical speed
else if ( tgt_vs > 0 ) {
tgt_pitch = tgt_vs * 0.005 ;
} else {
tgt_pitch = tgt_vs * 0.002 ;
2007-06-09 11:49:16 +00:00
}
}
2008-07-13 12:51:06 +00:00
string FGAIAircraft : : atGate ( ) {
string tmp ( " " ) ;
if ( fp - > getLeg ( ) < 3 ) {
if ( trafficRef ) {
if ( fp - > getGate ( ) > 0 ) {
FGParking * park =
trafficRef - > getDepartureAirport ( ) - > getDynamics ( ) - > getParking ( fp - > getGate ( ) ) ;
tmp = park - > getName ( ) ;
}
}
}
return tmp ;
}
2007-06-28 07:47:20 +00:00
void FGAIAircraft : : handleATCRequests ( ) {
//TODO implement NullController for having no ATC to save the conditionals
if ( controller ) {
2011-04-03 17:58:16 +02:00
controller - > updateAircraftInformation ( getID ( ) ,
pos . getLatitudeDeg ( ) ,
pos . getLongitudeDeg ( ) ,
hdg ,
speed ,
altitude_ft , dt ) ;
2007-06-28 07:47:20 +00:00
processATC ( controller - > getInstruction ( getID ( ) ) ) ;
}
2011-10-09 00:25:04 +02:00
if ( towerController ) {
towerController - > updateAircraftInformation ( getID ( ) ,
pos . getLatitudeDeg ( ) ,
pos . getLongitudeDeg ( ) ,
hdg ,
speed ,
altitude_ft , dt ) ;
}
2007-06-28 07:47:20 +00:00
}
2007-06-09 11:49:16 +00:00
2007-06-28 07:47:20 +00:00
void FGAIAircraft : : updateActualState ( ) {
//update current state
//TODO have a single tgt_speed and check speed limit on ground on setting tgt_speed
updatePosition ( ) ;
2007-06-09 11:49:16 +00:00
2007-06-28 07:47:20 +00:00
if ( onGround ( ) )
speed = _performance - > actualSpeed ( this , groundTargetSpeed , dt ) ;
else
2010-08-29 19:25:34 +02:00
speed = _performance - > actualSpeed ( this , ( tgt_speed * speedFraction ) , dt ) ;
2011-10-10 18:51:41 +02:00
//assertSpeed(speed);
2007-06-28 07:47:20 +00:00
updateHeading ( ) ;
roll = _performance - > actualBankAngle ( this , tgt_roll , dt ) ;
// adjust altitude (meters) based on current vertical speed (fpm)
altitude_ft + = vs / 60.0 * dt ;
pos . setElevationFt ( altitude_ft ) ;
vs = _performance - > actualVerticalSpeed ( this , tgt_vs , dt ) ;
pitch = _performance - > actualPitch ( this , tgt_pitch , dt ) ;
2007-06-09 11:49:16 +00:00
}
2007-06-28 07:47:20 +00:00
void FGAIAircraft : : updateSecondaryTargetValues ( ) {
// derived target state values
updateBankAngleTarget ( ) ;
updateVerticalSpeedTarget ( ) ;
updatePitchAngleTarget ( ) ;
2007-06-09 11:49:16 +00:00
2007-06-28 07:47:20 +00:00
//TODO calculate wind correction angle (tgt_yaw)
2006-08-26 07:22:20 +00:00
}
2010-08-29 19:25:34 +02:00
bool FGAIAircraft : : reachedEndOfCruise ( double & distance ) {
2011-07-31 19:27:44 +02:00
FGAIWaypoint * curr = fp - > getCurrentWaypoint ( ) ;
if ( curr - > getName ( ) = = string ( " BOD " ) ) {
2010-08-29 19:25:34 +02:00
double dist = fp - > getDistanceToGo ( pos . getLatitudeDeg ( ) , pos . getLongitudeDeg ( ) , curr ) ;
double descentSpeed = ( getPerformance ( ) - > vDescent ( ) * SG_NM_TO_METER ) / 3600.0 ; // convert from kts to meter/s
double descentRate = ( getPerformance ( ) - > descentRate ( ) * SG_FEET_TO_METER ) / 60.0 ; // convert from feet/min to meter/s
double verticalDistance = ( ( altitude_ft - 2000.0 ) - trafficRef - > getArrivalAirport ( ) - > getElevation ( ) ) * SG_FEET_TO_METER ;
double descentTimeNeeded = verticalDistance / descentRate ;
double distanceCovered = descentSpeed * descentTimeNeeded ;
//cerr << "Tracking : " << fgGetString("/ai/track-callsign");
2011-10-05 21:40:47 +02:00
if ( trafficRef - > getCallSign ( ) = = fgGetString ( " /ai/track-callsign " ) ) {
cerr < < " Checking for end of cruise stage for : " < < trafficRef - > getCallSign ( ) < < endl ;
cerr < < " Descent rate : " < < descentRate < < endl ;
cerr < < " Descent speed : " < < descentSpeed < < endl ;
cerr < < " VerticalDistance : " < < verticalDistance < < " . Altitude : " < < altitude_ft < < " . Elevation " < < trafficRef - > getArrivalAirport ( ) - > getElevation ( ) < < endl ;
cerr < < " DecentTimeNeeded : " < < descentTimeNeeded < < endl ;
cerr < < " DistanceCovered : " < < distanceCovered < < endl ;
}
2010-08-29 19:25:34 +02:00
//cerr << "Distance = " << distance << endl;
distance = distanceCovered ;
if ( dist < distanceCovered ) {
2011-10-05 21:40:47 +02:00
if ( trafficRef - > getCallSign ( ) = = fgGetString ( " /ai/track-callsign " ) ) {
//exit(1);
}
2010-08-29 19:25:34 +02:00
return true ;
} else {
return false ;
}
} else {
return false ;
}
}
void FGAIAircraft : : resetPositionFromFlightPlan ( )
{
// the one behind you
2011-07-31 19:27:44 +02:00
FGAIWaypoint * prev = 0 ;
2010-08-29 19:25:34 +02:00
// the one ahead
2011-07-31 19:27:44 +02:00
FGAIWaypoint * curr = 0 ;
2010-08-29 19:25:34 +02:00
// the next plus 1
2011-07-31 19:27:44 +02:00
FGAIWaypoint * next = 0 ;
2010-08-29 19:25:34 +02:00
prev = fp - > getPreviousWaypoint ( ) ;
curr = fp - > getCurrentWaypoint ( ) ;
next = fp - > getNextWaypoint ( ) ;
2011-07-31 19:27:44 +02:00
setLatitude ( prev - > getLatitude ( ) ) ;
setLongitude ( prev - > getLongitude ( ) ) ;
2010-08-29 19:25:34 +02:00
double tgt_heading = fp - > getBearing ( curr , next ) ;
setHeading ( tgt_heading ) ;
2011-07-31 19:27:44 +02:00
setAltitude ( prev - > getAltitude ( ) ) ;
setSpeed ( prev - > getSpeed ( ) ) ;
2010-08-29 19:25:34 +02:00
}
double FGAIAircraft : : getBearing ( double crse )
{
double hdgDiff = fabs ( hdg - crse ) ;
if ( hdgDiff > 180 )
hdgDiff = fabs ( hdgDiff - 360 ) ;
return hdgDiff ;
}
time_t FGAIAircraft : : checkForArrivalTime ( string wptName ) {
2011-07-31 19:27:44 +02:00
FGAIWaypoint * curr = 0 ;
2010-08-29 19:25:34 +02:00
curr = fp - > getCurrentWaypoint ( ) ;
double tracklength = fp - > checkTrackLength ( wptName ) ;
if ( tracklength > 0.1 ) {
tracklength + = fp - > getDistanceToGo ( pos . getLatitudeDeg ( ) , pos . getLongitudeDeg ( ) , curr ) ;
} else {
return 0 ;
}
time_t now = time ( NULL ) + fgGetLong ( " /sim/time/warp " ) ;
time_t arrivalTime = fp - > getArrivalTime ( ) ;
time_t ete = tracklength / ( ( speed * SG_NM_TO_METER ) / 3600.0 ) ;
time_t secondsToGo = arrivalTime - now ;
2011-10-05 21:40:47 +02:00
if ( trafficRef - > getCallSign ( ) = = fgGetString ( " /ai/track-callsign " ) ) {
cerr < < " Checking arrival time: ete " < < ete < < " . Time to go : " < < secondsToGo < < " . Track length = " < < tracklength < < endl ;
}
2010-08-29 19:25:34 +02:00
return ( ete - secondsToGo ) ; // Positive when we're too slow...
2011-01-17 23:33:54 +01:00
}