1
0
Fork 0

Removed a lot of the remaining hardwired KEMT stuff, made the initialisation more generic, added the ability to taxi from a parking spot to a runway, used real ground elevation more

This commit is contained in:
daveluff 2003-03-05 21:38:29 +00:00
parent 8bbaba3193
commit 42527ecf1b
4 changed files with 388 additions and 135 deletions

View file

@ -23,6 +23,7 @@
# include <config.h>
#endif
#include <Airports/runways.hxx>
#include <Main/globals.hxx>
#include <Main/location.hxx>
#include <Scenery/scenery.hxx>
@ -40,6 +41,10 @@ SG_USING_STD(string);
#include "ATCutils.hxx"
FGAILocalTraffic::FGAILocalTraffic() {
roll = 0.0;
pitch = 0.0;
hdg = 270.0;
//Hardwire initialisation for now - a lot of this should be read in from config eventually
Vr = 70.0;
best_rate_of_climb_speed = 70.0;
@ -56,31 +61,105 @@ FGAILocalTraffic::FGAILocalTraffic() {
nominalTaxiSpeed = 8.0;
taxiTurnRadius = 8.0;
wheelOffset = 1.45; // Warning - hardwired to the C172 - we need to read this in from file.
elevInitGood = false;
// Init the property nodes
wind_from_hdg = fgGetNode("/environment/wind-from-heading-deg", true);
wind_speed_knots = fgGetNode("/environment/wind-speed-kts", true);
circuitsToFly = 0;
liningUp = false;
}
FGAILocalTraffic::~FGAILocalTraffic() {
}
void FGAILocalTraffic::Init() {
// Get details of the active runway
// This is a private internal function and it is assumed that by the
// time it is called the tower control and airport code will have been set up.
void FGAILocalTraffic::GetRwyDetails() {
//cout << "GetRwyDetails called" << endl;
// Based on the airport-id and wind get the active runway
SGPath path( globals->get_fg_root() );
path.append( "Airports" );
path.append( "runways.mk4" );
FGRunways runways( path.c_str() );
//wind
double hdg = wind_from_hdg->getDoubleValue();
double speed = wind_speed_knots->getDoubleValue();
hdg = (speed == 0.0 ? 270.0 : hdg);
//cout << "Heading = " << hdg << '\n';
FGRunway runway;
bool rwyGood = runways.search(airportID, int(hdg), &runway);
if(rwyGood) {
// Get the threshold position
hdg = runway.heading;
//cout << "hdg reset to " << hdg << '\n';
double other_way = hdg - 180.0;
while(other_way <= 0.0) {
other_way += 360.0;
}
// move to the +l end/center of the runway
//cout << "Runway center is at " << runway.lon << ", " << runway.lat << '\n';
Point3D origin = Point3D(runway.lon, runway.lat, aptElev);
Point3D ref = origin;
double tshlon, tshlat, tshr;
double tolon, tolat, tor;
rwy.length = runway.length * SG_FEET_TO_METER;
geo_direct_wgs_84 ( aptElev, ref.lat(), ref.lon(), other_way,
rwy.length / 2.0 - 25.0, &tshlat, &tshlon, &tshr );
geo_direct_wgs_84 ( aptElev, ref.lat(), ref.lon(), hdg,
rwy.length / 2.0 - 25.0, &tolat, &tolon, &tor );
// Note - 25 meters in from the runway end is a bit of a hack to put the plane ahead of the user.
// now copy what we need out of runway into rwy
rwy.threshold_pos = Point3D(tshlon, tshlat, aptElev);
Point3D takeoff_end = Point3D(tolon, tolat, aptElev);
//cout << "Threshold position = " << tshlon << ", " << tshlat << ", " << aptElev << '\n';
//cout << "Takeoff position = " << tolon << ", " << tolat << ", " << aptElev << '\n';
rwy.hdg = hdg;
rwy.rwyID = runway.rwy_no;
// Set the projection for the local area
ortho.Init(rwy.threshold_pos, rwy.hdg);
rwy.end1ortho = ortho.ConvertToLocal(rwy.threshold_pos); // should come out as zero
rwy.end2ortho = ortho.ConvertToLocal(takeoff_end);
rwy.mag_var = 14.0; // TODO - remove this last hardwired bit!!
//(Although I don't think we even use the magvar any more?)
rwy.mag_hdg = rwy.hdg - rwy.mag_var;
rwy.ID = (int)rwy.mag_hdg / 10;
//cout << "rwy.ID = " << rwy.ID << '\n';
} else {
SG_LOG(SG_GENERAL, SG_ALERT, "Help - can't get good runway in FGAILocalTraffic!!\n");
}
}
/*
There are two possible scenarios during initialisation:
The first is that the user is flying towards the airport, and hence the traffic
could be initialised anywhere, as long as the AI planes are consistent with
each other.
The second is that the user has started the sim at or close to the airport, and
hence the traffic must be initialised with respect to the user as well as each other.
To a certain extent it's FGAIMgr that has to worry about this, but we need to provide
sufficient initialisation functionality within the plane classes to allow the manager
to initialy position them where and how required.
*/
bool FGAILocalTraffic::Init(string ICAO, OperatingState initialState, PatternLeg initialLeg) {
//cout << "FGAILocalTraffic.Init(...) called" << endl;
// Hack alert - Hardwired path!!
string planepath = "Aircraft/c172/Models/c172-dpm.ac";
SGPath path = globals->get_fg_root();
path.append(planepath);
aip.init(planepath.c_str());
aip.setVisible(true);
aip.setVisible(false); // This will be set to true once a valid ground elevation has been determined
globals->get_scenery()->get_scene_graph()->addKid(aip.getSceneGraph());
// is it OK to leave it like this until the first time transform is called?
// Really ought to be started in a parking space unless otherwise specified?
// Find the tower frequency - this is dependent on the ATC system being initialised before the AI system
// FIXME - ATM this is hardwired.
airportID = "KEMT";
airportID = ICAO;
AirportATC a;
if(globals->get_ATC_mgr()->GetAirportATCDetails((string)airportID, &a)) {
if(globals->get_ATC_mgr()->GetAirportATCDetails(airportID, &a)) {
if(a.tower_freq) { // Has a tower
tower = (FGTower*)globals->get_ATC_mgr()->GetATCPointer((string)airportID, TOWER); // Maybe need some error checking here
freq = (double)tower->get_freq() / 100.0;
@ -92,94 +171,220 @@ void FGAILocalTraffic::Init() {
//cout << "Unable to find airport details in FGAILocalTraffic::Init()\n";
}
// Initiallise the FGAirportData structure
// Initialise the relevant FGGround
// This needs a complete overhaul soon - what happens if we have 2 AI planes at same airport - they don't both need a structure
// This needs to be handled by the ATC manager or similar so only one set of physical data per airport is instantiated
// ie. TODO TODO FIXME FIXME
airport.Init();
// Get the airport elevation
aptElev = dclGetAirportElev(airportID.c_str()) * SG_FEET_TO_METER;
//cout << "Airport elev in AILocalTraffic = " << aptElev << '\n';
// WARNING - we use this elev for the whole airport - some assumptions in the code
// might fall down with very slopey airports.
//cout << "In Init(), initialState = " << initialState << '\n';
operatingState = initialState;
switch(operatingState) {
case PARKED:
ourGate = airport.GetGateNode();
if(ourGate == NULL) {
// Implies no available gates - what shall we do?
// For now just vanish the plane - possibly we can make this more elegant in the future
SG_LOG(SG_GENERAL, SG_ALERT, "No gate found by FGAILocalTraffic whilst attempting Init at " << airportID << '\n');
return(false);
}
pitch = 0.0;
roll = 0.0;
vel = 0.0;
slope = 0.0;
pos = ourGate->pos;
pos.setelev(aptElev);
hdg = ourGate->heading;
// Now we've set the position we can do the ground elev
elevInitGood = false;
inAir = false;
DoGroundElev();
Transform();
break;
case TAXIING:
// FIXME - implement this case properly
return(false); // remove this line when fixed!
break;
case IN_PATTERN:
// For now we'll always start the in_pattern case on the threshold ready to take-off
// since we've got the implementation for this case already.
// TODO - implement proper generic in_pattern startup.
// Get the active runway details (and copy them into rwy)
GetRwyDetails();
// Initial position on threshold for now
pos.setlat(rwy.threshold_pos.lat());
pos.setlon(rwy.threshold_pos.lon());
pos.setelev(rwy.threshold_pos.elev());
hdg = rwy.hdg;
// Now we've set the position we can do the ground elev
// This might not always be necessary if we implement in-air start
elevInitGood = false;
inAir = false;
DoGroundElev();
pitch = 0.0;
roll = 0.0;
leg = TAKEOFF_ROLL;
vel = 0.0;
slope = 0.0;
circuitsToFly = 0; // ie just fly this circuit and then stop
touchAndGo = false;
// FIXME TODO - pattern direction is still hardwired
patternDirection = -1; // Left
// At the bare minimum we ought to make sure it goes the right way at dual parallel rwy airports!
if(rwy.rwyID.size() == 3) {
patternDirection = (rwy.rwyID.substr(2,1) == "R" ? 1 : -1);
}
operatingState = IN_PATTERN;
Transform();
break;
default:
SG_LOG(SG_GENERAL, SG_ALERT, "Attempt to set unknown operating state in FGAILocalTraffic.Init(...)\n");
return(false);
}
return(true);
}
// Commands to do something from higher level logic
void FGAILocalTraffic::FlyCircuits(int numCircuits, bool tag) {
circuitsToFly += numCircuits - 1; // Hack (-1) because we only test and decrement circuitsToFly after landing
// thus flying one to many circuits. TODO - Need to sort this out better!
touchAndGo = tag;
//cout << "FlyCircuits called" << endl;
//At the moment we'll assume that we are always finished previous circuits when called,
//And just teleport to the threshold to start.
//This is a hack though, we need to check where we are and taxi out if appropriate.
operatingState = IN_PATTERN;
switch(operatingState) {
case IN_PATTERN:
circuitsToFly += numCircuits;
return;
break;
case TAXIING:
// For now we'll punt this and do nothing
break;
case PARKED:
circuitsToFly = numCircuits - 1; // Hack (-1) because we only test and decrement circuitsToFly after landing
// thus flying one too many circuits. TODO - Need to sort this out better!
touchAndGo = tag;
// Get the active runway details (and copy them into rwy)
GetRwyDetails();
// Get the takeoff node for the active runway, get a path to it and start taxiing
path = airport.GetPath(ourGate, rwy.rwyID);
if(path.size() < 2) {
// something has gone wrong
SG_LOG(SG_GENERAL, SG_ALERT, "Invalid path from gate to theshold in FGAILocalTraffic::FlyCircuits\n");
return;
}
/*
cout << "path returned was:" << endl;
for(unsigned int i=0; i<path.size(); ++i) {
switch(path[i]->struct_type) {
case NODE:
cout << "NODE " << ((node*)(path[i]))->nodeID << endl;
break;
case ARC:
cout << "ARC\n";
break;
}
}
*/
// pop the gate - we're here already!
path.erase(path.begin());
//path.erase(path.begin());
/*
cout << "path after popping front is:" << endl;
for(unsigned int i=0; i<path.size(); ++i) {
switch(path[i]->struct_type) {
case NODE:
cout << "NODE " << ((node*)(path[i]))->nodeID << endl;
break;
case ARC:
cout << "ARC\n";
break;
}
}
*/
taxiState = TD_OUTBOUND;
StartTaxi();
// Maybe the below should be set when we get to the threshold and prepare for TO?
// FIXME TODO - pattern direction is still hardwired
patternDirection = -1; // Left
// At the bare minimum we ought to make sure it goes the right way at dual parallel rwy airports!
if(rwy.rwyID.size() == 3) {
patternDirection = (rwy.rwyID.substr(2,1) == "R" ? 1 : -1);
}
// Hardwire to KEMT for now
// Hardwired points at each end of KEMT runway
Point3D P010(-118.037483, 34.081358, 296 * SG_FEET_TO_METER);
Point3D P190(-118.032308, 34.090456, 299.395263 * SG_FEET_TO_METER);
Point3D takeoff_end;
bool d010 = true; // use this to change the hardwired runway direction
if(d010) {
rwy.threshold_pos = P010;
takeoff_end = P190;
rwy.hdg = 25.32; //from default.apt
rwy.ID = 1;
patternDirection = -1; // Left
pos.setelev(rwy.threshold_pos.elev() + (-8.5 * SG_FEET_TO_METER)); // This is a complete hack - the rendered runway takes the underlying scenery elev rather than the published runway elev so I should use height above terrain or something.
} else {
rwy.threshold_pos = P190;
takeoff_end = P010;
rwy.hdg = 205.32;
rwy.ID = 19;
patternDirection = 1; // Right
pos.setelev(rwy.threshold_pos.elev() + (-0.0 * SG_FEET_TO_METER)); // This is a complete hack - the rendered runway takes the underlying scenery elev rather than the published runway elev so I should use height above terrain or something.
Transform();
break;
}
//rwy.threshold_pos.setlat(34.081358);
//rwy.threshold_pos.setlon(-118.037483);
//rwy.mag_hdg = 12.0;
//rwy.mag_var = 14.0;
//rwy.hdg = rwy.mag_hdg + rwy.mag_var;
//rwy.threshold_pos.setelev(296 * SG_FEET_TO_METER);
// Initial position on threshold for now
// TODO - check wind / default runway
pos.setlat(rwy.threshold_pos.lat());
pos.setlon(rwy.threshold_pos.lon());
hdg = rwy.hdg;
pitch = 0.0;
roll = 0.0;
leg = TAKEOFF_ROLL;
vel = 0.0;
slope = 0.0;
// Set the projection for the local area
ortho.Init(rwy.threshold_pos, rwy.hdg);
rwy.end1ortho = ortho.ConvertToLocal(rwy.threshold_pos); // should come out as zero
// Hardwire to KEMT for now
rwy.end2ortho = ortho.ConvertToLocal(takeoff_end);
//cout << "*********************************************************************************\n";
//cout << "*********************************************************************************\n";
//cout << "*********************************************************************************\n";
//cout << "end1ortho = " << rwy.end1ortho << '\n';
//cout << "end2ortho = " << rwy.end2ortho << '\n'; // end2ortho.x() should be zero or thereabouts
Transform();
}
// Run the internal calculations
void FGAILocalTraffic::Update(double dt) {
switch(operatingState) {
case IN_PATTERN:
//cout << "In IN_PATTERN\n";
if(!inAir) DoGroundElev();
if(!elevInitGood) {
if(aip.getFGLocation()->get_cur_elev_m() > -9990.0) {
pos.setelev(aip.getFGLocation()->get_cur_elev_m() + wheelOffset);
//cout << "TAKEOFF_ROLL, POS = " << pos.lon() << ", " << pos.lat() << ", " << pos.elev() << '\n';
//Transform();
aip.setVisible(true);
//cout << "Making plane visible!\n";
elevInitGood = true;
}
}
FlyTrafficPattern(dt);
Transform();
break;
case TAXIING:
//cout << "In TAXIING\n";
if(!elevInitGood) {
//DoGroundElev();
if(aip.getFGLocation()->get_cur_elev_m() > -9990.0) {
pos.setelev(aip.getFGLocation()->get_cur_elev_m() + wheelOffset);
//Transform();
aip.setVisible(true);
//Transform();
//cout << "Making plane visible!\n";
elevInitGood = true;
}
}
DoGroundElev();
Taxi(dt);
Transform();
break;
case PARKED:
//cout << "In PARKED\n";
if(!elevInitGood) {
DoGroundElev();
if(aip.getFGLocation()->get_cur_elev_m() > -9990.0) {
pos.setelev(aip.getFGLocation()->get_cur_elev_m() + wheelOffset);
//Transform();
aip.setVisible(true);
//Transform();
//cout << "Making plane visible!\n";
elevInitGood = true;
}
}
// Do nothing
Transform();
break;
default:
break;
@ -192,7 +397,6 @@ void FGAILocalTraffic::Update(double dt) {
void FGAILocalTraffic::FlyTrafficPattern(double dt) {
// Need to differentiate between in-air (IAS governed) and on-ground (vel governed)
// Take-off is an interesting case - we are on the ground but takeoff speed is IAS governed.
bool inAir = true; // FIXME - possibly make into a class variable
static bool transmitted = false; // FIXME - this is a hack
@ -222,18 +426,22 @@ void FGAILocalTraffic::FlyTrafficPattern(double dt) {
switch(leg) {
case TAKEOFF_ROLL:
inAir = false;
//inAir = false;
track = rwy.hdg;
if(vel < 80.0) {
double dveldt = 5.0;
vel += dveldt * dt;
}
if(aip.getFGLocation()->get_cur_elev_m() > -9990.0) {
pos.setelev(aip.getFGLocation()->get_cur_elev_m() + wheelOffset);
}
IAS = vel + (cos((hdg - wind_from) * DCL_DEGREES_TO_RADIANS) * wind_speed);
if(IAS >= 70) {
leg = CLIMBOUT;
pitch = 10.0;
IAS = best_rate_of_climb_speed;
slope = 7.0;
inAir = true;
}
break;
case CLIMBOUT:
@ -348,15 +556,26 @@ void FGAILocalTraffic::FlyTrafficPattern(double dt) {
// Try and track the extended centreline
track = rwy.hdg - (0.2 * orthopos.x());
//cout << "orthopos.x() = " << orthopos.x() << " hdg = " << hdg << '\n';
if(pos.elev() <= rwy.threshold_pos.elev()) {
pos.setelev(rwy.threshold_pos.elev());// + (-8.5 * SG_FEET_TO_METER)); // This is a complete hack - the rendered runway takes the underlying scenery elev rather than the published runway elev so I should use height above terrain or something.
slope = 0.0;
pitch = 0.0;
leg = LANDING_ROLL;
if(pos.elev() < (rwy.threshold_pos.elev()+20.0+wheelOffset)) {
DoGroundElev(); // Need to call it here expicitly on final since it's only called
// for us in update(...) when the inAir flag is false.
}
if(pos.elev() < (rwy.threshold_pos.elev()+10.0+wheelOffset)) {
if(aip.getFGLocation()->get_cur_elev_m() > -9990.0) {
if((aip.getFGLocation()->get_cur_elev_m() + wheelOffset) > pos.elev()) {
slope = 0.0;
pitch = 0.0;
leg = LANDING_ROLL;
inAir = false;
}
} // else need a fallback position based on arpt elev in case ground elev determination fails?
}
break;
case LANDING_ROLL:
inAir = false;
//inAir = false;
if(aip.getFGLocation()->get_cur_elev_m() > -9990.0) {
pos.setelev(aip.getFGLocation()->get_cur_elev_m() + wheelOffset);
}
track = rwy.hdg;
double dveldt = -5.0;
vel += dveldt * dt;
@ -506,8 +725,8 @@ void FGAILocalTraffic::ExitRunway(Point3D orthopos) {
}
++nItr;
}
in_dest = airport.GetGateNode();
if(in_dest == NULL) {
ourGate = airport.GetGateNode();
if(ourGate == NULL) {
// Implies no available gates - what shall we do?
// For now just vanish the plane - possibly we can make this more elegant in the future
SG_LOG(SG_GENERAL, SG_ALERT, "No gate found by FGAILocalTraffic whilst landing at " << airportID << '\n');
@ -515,7 +734,7 @@ void FGAILocalTraffic::ExitRunway(Point3D orthopos) {
operatingState = PARKED;
return;
}
path = airport.GetPath(rwyExit, in_dest);
path = airport.GetPath(rwyExit, ourGate);
/*
cout << "path returned was:" << endl;
for(unsigned int i=0; i<path.size(); ++i) {
@ -590,6 +809,40 @@ void FGAILocalTraffic::StartTaxi() {
//cout << "First taxi heading is " << desiredTaxiHeading << endl;
}
// speed in knots, headings in degrees, radius in meters.
static double TaxiTurnTowardsHeading(double current_hdg, double desired_hdg, double speed, double radius, double dt) {
// wrap heading - this prevents a logic bug where the plane would just go round in circles!!
while(current_hdg < 0.0) {
current_hdg += 360.0;
}
while(current_hdg > 360.0) {
current_hdg -= 360.0;
}
if(fabs(current_hdg - desired_hdg) > 0.1) {
// Which is the quickest direction to turn onto heading?
if(desired_hdg > current_hdg) {
if((desired_hdg - current_hdg) <= 180) {
// turn right
current_hdg += ((speed * 0.514444 * dt) / (radius * DCL_PI)) * 180.0;
// TODO - check that increments are less than the delta that we check for the right direction
// Probably need to reduce convergence speed as convergence is reached
} else {
current_hdg -= ((speed * 0.514444 * dt) / (radius * DCL_PI)) * 180.0;
}
} else {
if((current_hdg - desired_hdg) <= 180) {
// turn left
current_hdg -= ((speed * 0.514444 * dt) / (radius * DCL_PI)) * 180.0;
// TODO - check that increments are less than the delta that we check for the right direction
// Probably need to reduce convergence speed as convergence is reached
} else {
current_hdg += ((speed * 0.514444 * dt) / (radius * DCL_PI)) * 180.0;
}
}
}
return(current_hdg);
}
void FGAILocalTraffic::Taxi(double dt) {
//cout << "Taxi called" << endl;
// Logic - if we are further away from next point than turn radius then head for it
@ -598,6 +851,11 @@ void FGAILocalTraffic::Taxi(double dt) {
//Point3D orthopos = ortho.ConvertToLocal(pos); // ortho position of the plane
desiredTaxiHeading = GetHeadingFromTo(pos, nextTaxiNode->pos);
bool lastNode = (taxiPathPos == path.size() ? true : false);
if(lastNode) {
//cout << "LAST NODE\n";
}
// HACK ALERT! - for now we will taxi at constant speed for straights and turns
@ -605,37 +863,16 @@ void FGAILocalTraffic::Taxi(double dt) {
double dist_to_go = dclGetHorizontalSeparation(pos, nextTaxiNode->pos); // we may be able to do this more cheaply using orthopos
//cout << "dist_to_go = " << dist_to_go << endl;
if((nextTaxiNode->type == GATE) && (dist_to_go <= 0.1)) {
// This might be more robust to outward paths starting with a gate if we check for either
// last node or TD_INBOUND ?
// park up
//taxiing = false;
//parked = true;
operatingState = PARKED;
} else if((dist_to_go > taxiTurnRadius) || (nextTaxiNode->type == GATE)) {
} else if(((dist_to_go > taxiTurnRadius) || (nextTaxiNode->type == GATE)) && (!liningUp)){
// if the turn radius is r, and speed is s, then in a time dt we turn through
// ((s.dt)/(PI.r)) x 180 degrees
// or alternatively (s.dt)/r radians
//cout << "hdg = " << hdg << " desired taxi heading = " << desiredTaxiHeading << '\n';
if(fabs(hdg - desiredTaxiHeading) > 0.1) {
// Which is the quickest direction to turn onto heading?
if(desiredTaxiHeading > hdg) {
if((desiredTaxiHeading - hdg) <= 180) {
// turn right
hdg += ((nominalTaxiSpeed * 0.514444 * dt) / (taxiTurnRadius * DCL_PI)) * 180.0;
// TODO - check that increments are less than the delta that we check for the right direction
// Probably need to reduce convergence speed as convergence is reached
} else {
hdg -= ((nominalTaxiSpeed * 0.514444 * dt) / (taxiTurnRadius * DCL_PI)) * 180.0;
}
} else {
if((hdg - desiredTaxiHeading) <= 180) {
// turn left
hdg -= ((nominalTaxiSpeed * 0.514444 * dt) / (taxiTurnRadius * DCL_PI)) * 180.0;
// TODO - check that increments are less than the delta that we check for the right direction
// Probably need to reduce convergence speed as convergence is reached
} else {
hdg += ((nominalTaxiSpeed * 0.514444 * dt) / (taxiTurnRadius * DCL_PI)) * 180.0;
}
}
}
hdg = TaxiTurnTowardsHeading(hdg, desiredTaxiHeading, nominalTaxiSpeed, taxiTurnRadius, dt);
double vel = nominalTaxiSpeed;
//cout << "vel = " << vel << endl;
double dist = vel * 0.514444 * dt;
@ -648,6 +885,33 @@ void FGAILocalTraffic::Taxi(double dt) {
if(aip.getFGLocation()->get_cur_elev_m() > -9990) {
pos.setelev(aip.getFGLocation()->get_cur_elev_m() + wheelOffset);
} // else don't change the elev until we get a valid ground elev again!
} else if(lastNode) {
if(taxiState == TD_OUTBOUND) {
if((!liningUp) && (dist_to_go <= taxiTurnRadius)) {
liningUp = true;
}
if(liningUp) {
hdg = TaxiTurnTowardsHeading(hdg, rwy.hdg, nominalTaxiSpeed, taxiTurnRadius, dt);
double vel = nominalTaxiSpeed;
//cout << "vel = " << vel << endl;
double dist = vel * 0.514444 * dt;
//cout << "dist = " << dist << endl;
double track = hdg;
//cout << "track = " << track << endl;
double slope = 0.0;
pos = dclUpdatePosition(pos, track, slope, dist);
//cout << "Updated position...\n";
if(aip.getFGLocation()->get_cur_elev_m() > -9990) {
pos.setelev(aip.getFGLocation()->get_cur_elev_m() + wheelOffset);
} // else don't change the elev until we get a valid ground elev again!
if(fabs(hdg - rwy.hdg) <= 1.0) {
operatingState = IN_PATTERN;
leg = TAKEOFF_ROLL;
inAir = false;
liningUp = false;
}
}
} // else at the moment assume TD_INBOUND always ends in a gate in which case we can ignore it
} else {
// Time to turn (we've already checked it's not the end we're heading for).
// set the target node to be the next node which will prompt automatically turning onto

View file

@ -19,14 +19,6 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
/*****************************************************************
*
* WARNING - Curt has some ideas about AI traffic so anything in here
* may get rewritten or scrapped. Contact Curt curt@flightgear.org
* before spending any time or effort on this code!!!
*
******************************************************************/
#ifndef _FG_AILocalTraffic_HXX
#define _FG_AILocalTraffic_HXX
@ -40,6 +32,9 @@
#include "ATCProjection.hxx"
#include "ground.hxx"
#include <string>
SG_USING_STD(string);
typedef enum PatternLeg {
TAKEOFF_ROLL,
CLIMBOUT,
@ -74,7 +69,9 @@ typedef struct RunwayDetails {
double mag_hdg;
double mag_var;
double hdg; // true runway heading
double length; // In *METERS*
int ID; // 1 -> 36
string rwyID;
};
typedef struct StartofDescent {
@ -91,7 +88,7 @@ public:
~FGAILocalTraffic();
// Initialise
void Init();
bool Init(string ICAO, OperatingState initialState = PARKED, PatternLeg initialLeg = DOWNWIND);
// Run the internal calculations
void Update(double dt);
@ -118,7 +115,8 @@ private:
// and the runway aligned with the y axis.
// Airport/runway/pattern details
char* airportID; // The ICAO code of the airport that we're operating around
string airportID; // The ICAO code of the airport that we're operating around
double aptElev; // Airport elevation
FGGround airport; // FIXME FIXME FIXME This is a complete hardwired cop-out at the moment - we need to connect to the correct ground in the same way we do to the tower.
FGTower* tower; // A pointer to the tower control.
RunwayDetails rwy;
@ -144,6 +142,8 @@ private:
// Physical/rendering stuff
double wheelOffset; // Height above ground at which we need to render the plane whilst taxiing
bool elevInitGood; // We have had at least one good elev reading
bool inAir; // True when off the ground
// environment - some of this might get moved into FGAIPlane
SGPropertyNode* wind_from_hdg; //degrees
@ -165,11 +165,12 @@ private:
double desiredTaxiHeading;
double taxiTurnRadius;
double nominalTaxiSpeed;
Gate* in_dest;
Gate* ourGate;
ground_network_path_type path; // a path through the ground network for the plane to taxi
int taxiPathPos; // position of iterator in taxi path when applicable
unsigned int taxiPathPos; // position of iterator in taxi path when applicable
node* nextTaxiNode; // next node in taxi path
//Runway out_dest; //FIXME - implement this
bool liningUp; // Set true when the turn onto the runway heading is commenced when taxiing out
void FlyTrafficPattern(double dt);
@ -188,6 +189,8 @@ private:
void GetNextTaxiNode();
void DoGroundElev();
void GetRwyDetails();
};
#endif // _FG_AILocalTraffic_HXX

View file

@ -19,16 +19,6 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
/*****************************************************************
*
* WARNING - Curt has some ideas about AI traffic so anything in here
* may get rewritten or scrapped. Contact Curt curt@flightgear.org
* before spending any time or effort on this code!!!
*
******************************************************************/
#include <Main/fgfs.hxx>
#include <Main/fg_props.hxx>
@ -50,7 +40,8 @@ void FGAIMgr::init() {
// Hard wire some local traffic for now.
// This is regardless of location and hence *very* ugly but it is a start.
FGAILocalTraffic* local_traffic = new FGAILocalTraffic;
local_traffic->Init();
//local_traffic->Init("KEMT", IN_PATTERN, TAKEOFF_ROLL);
local_traffic->Init("KEMT");
local_traffic->FlyCircuits(1, true); // Fly 2 circuits with touch & go in between
ai_list.push_back(local_traffic);
}
@ -64,12 +55,15 @@ void FGAIMgr::unbind() {
void FGAIMgr::update(double dt) {
// Don't update any planes for first 50 runs through - this avoids some possible initialisation anomalies
static int i = 0;
i++;
if(i < 50) {
i++;
return;
}
// Traverse the list of active planes and run all their update methods
// TODO - spread the load - not all planes should need updating every frame.
// Note that this will require dt to be calculated for each plane though
// since they rely on it to calculate distance travelled.
ai_list_itr = ai_list.begin();
while(ai_list_itr != ai_list.end()) {
(*ai_list_itr)->Update(dt);

View file

@ -19,14 +19,6 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
/*****************************************************************
*
* WARNING - Curt has some ideas about AI traffic so anything in here
* may get rewritten or scrapped. Contact Curt curt@flightgear.org
* before spending any time or effort on this code!!!
*
******************************************************************/
#ifndef _FG_AIMGR_HXX
#define _FG_AIMGR_HXX