Traffic improvements.
Make landings and takeoffs look more correct; tweak climb-out and touchdown phases in particular, so the turn to destination heading occurs earlier on climb out, and touchdown occurs close the GS transmitter / some distance down the runway from the beginning.
This commit is contained in:
parent
4e75587332
commit
c79e2465df
12 changed files with 324 additions and 312 deletions
|
@ -709,9 +709,9 @@ void FGAIAircraft::handleFirstWaypoint() {
|
||||||
setAltitude(prev->getAltitude());
|
setAltitude(prev->getAltitude());
|
||||||
|
|
||||||
if (prev->getSpeed() > 0.0)
|
if (prev->getSpeed() > 0.0)
|
||||||
setHeading(fp->getBearing(prev->getLatitude(), prev->getLongitude(), curr));
|
setHeading(fp->getBearing(prev, curr));
|
||||||
else
|
else
|
||||||
setHeading(fp->getBearing(curr->getLatitude(), curr->getLongitude(), prev));
|
setHeading(fp->getBearing(curr, prev));
|
||||||
|
|
||||||
// If next doesn't exist, as in incrementally created flightplans for
|
// If next doesn't exist, as in incrementally created flightplans for
|
||||||
// AI/Trafficmanager created plans,
|
// AI/Trafficmanager created plans,
|
||||||
|
@ -799,7 +799,7 @@ bool FGAIAircraft::leadPointReached(FGAIWaypoint* curr) {
|
||||||
// << " Ground target speed " << groundTargetSpeed << endl;
|
// << " Ground target speed " << groundTargetSpeed << endl;
|
||||||
double bearing = 0;
|
double bearing = 0;
|
||||||
// don't do bearing calculations for ground traffic
|
// don't do bearing calculations for ground traffic
|
||||||
bearing = getBearing(fp->getBearing(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr));
|
bearing = getBearing(fp->getBearing(pos, curr));
|
||||||
if (bearing < minBearing) {
|
if (bearing < minBearing) {
|
||||||
minBearing = bearing;
|
minBearing = bearing;
|
||||||
if (minBearing < 10) {
|
if (minBearing < 10) {
|
||||||
|
@ -913,12 +913,11 @@ bool FGAIAircraft::handleAirportEndPoints(FGAIWaypoint* prev, time_t now) {
|
||||||
* @param curr
|
* @param curr
|
||||||
*/
|
*/
|
||||||
void FGAIAircraft::controlHeading(FGAIWaypoint* curr) {
|
void FGAIAircraft::controlHeading(FGAIWaypoint* curr) {
|
||||||
double calc_bearing = fp->getBearing(pos.getLatitudeDeg(), pos.getLongitudeDeg(), curr);
|
double calc_bearing = fp->getBearing(pos, curr);
|
||||||
//cerr << "Bearing = " << calc_bearing << endl;
|
//cerr << "Bearing = " << calc_bearing << endl;
|
||||||
if (speed < 0) {
|
if (speed < 0) {
|
||||||
calc_bearing +=180;
|
calc_bearing +=180;
|
||||||
if (calc_bearing > 360)
|
SG_NORMALIZE_RANGE(calc_bearing, 0.0, 360.0);
|
||||||
calc_bearing -= 360;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (finite(calc_bearing)) {
|
if (finite(calc_bearing)) {
|
||||||
|
@ -1023,19 +1022,6 @@ void FGAIAircraft::updatePrimaryTargetValues(bool& flightplanActive, bool& aiOut
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGAIAircraft::updatePosition() {
|
|
||||||
// convert speed to degrees per second
|
|
||||||
double speed_north_deg_sec = cos( hdg * SGD_DEGREES_TO_RADIANS )
|
|
||||||
* speed * 1.686 / ft_per_deg_lat;
|
|
||||||
double speed_east_deg_sec = sin( hdg * SGD_DEGREES_TO_RADIANS )
|
|
||||||
* speed * 1.686 / ft_per_deg_lon;
|
|
||||||
|
|
||||||
// set new position
|
|
||||||
pos.setLatitudeDeg( pos.getLatitudeDeg() + speed_north_deg_sec * dt);
|
|
||||||
pos.setLongitudeDeg( pos.getLongitudeDeg() + speed_east_deg_sec * dt);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void FGAIAircraft::updateHeading() {
|
void FGAIAircraft::updateHeading() {
|
||||||
// adjust heading based on current bank angle
|
// adjust heading based on current bank angle
|
||||||
if (roll == 0.0)
|
if (roll == 0.0)
|
||||||
|
@ -1181,13 +1167,9 @@ void FGAIAircraft::updateVerticalSpeedTarget() {
|
||||||
// find target vertical speed
|
// find target vertical speed
|
||||||
if (use_perf_vs) {
|
if (use_perf_vs) {
|
||||||
if (altitude_ft < tgt_altitude_ft) {
|
if (altitude_ft < tgt_altitude_ft) {
|
||||||
tgt_vs = tgt_altitude_ft - altitude_ft;
|
tgt_vs = std::min(tgt_altitude_ft - altitude_ft, _performance->climbRate());
|
||||||
if (tgt_vs > _performance->climbRate())
|
|
||||||
tgt_vs = _performance->climbRate();
|
|
||||||
} else {
|
} else {
|
||||||
tgt_vs = tgt_altitude_ft - altitude_ft;
|
tgt_vs = std::max(tgt_altitude_ft - altitude_ft, -_performance->descentRate());
|
||||||
if (tgt_vs < (-_performance->descentRate()))
|
|
||||||
tgt_vs = -_performance->descentRate();
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
double vert_dist_ft = fp->getCurrentWaypoint()->getCrossat() - altitude_ft;
|
double vert_dist_ft = fp->getCurrentWaypoint()->getCrossat() - altitude_ft;
|
||||||
|
@ -1265,7 +1247,9 @@ void FGAIAircraft::handleATCRequests() {
|
||||||
void FGAIAircraft::updateActualState() {
|
void FGAIAircraft::updateActualState() {
|
||||||
//update current state
|
//update current state
|
||||||
//TODO have a single tgt_speed and check speed limit on ground on setting tgt_speed
|
//TODO have a single tgt_speed and check speed limit on ground on setting tgt_speed
|
||||||
updatePosition();
|
double distance = speed * SG_KT_TO_MPS * dt;
|
||||||
|
pos = SGGeodesy::direct(pos, hdg, distance);
|
||||||
|
|
||||||
|
|
||||||
if (onGround())
|
if (onGround())
|
||||||
speed = _performance->actualSpeed(this, groundTargetSpeed, dt, holdPos);
|
speed = _performance->actualSpeed(this, groundTargetSpeed, dt, holdPos);
|
||||||
|
|
|
@ -148,7 +148,6 @@ private:
|
||||||
void updatePrimaryTargetValues(bool& flightplanActive, bool& aiOutOfSight);
|
void updatePrimaryTargetValues(bool& flightplanActive, bool& aiOutOfSight);
|
||||||
|
|
||||||
void updateSecondaryTargetValues();
|
void updateSecondaryTargetValues();
|
||||||
void updatePosition();
|
|
||||||
void updateHeading();
|
void updateHeading();
|
||||||
void updateBankAngleTarget();
|
void updateBankAngleTarget();
|
||||||
void updateVerticalSpeedTarget();
|
void updateVerticalSpeedTarget();
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include <Main/fg_props.hxx>
|
#include <Main/fg_props.hxx>
|
||||||
#include <Main/fg_init.hxx>
|
#include <Main/fg_init.hxx>
|
||||||
#include <Airports/simple.hxx>
|
#include <Airports/simple.hxx>
|
||||||
|
#include <Airports/dynamics.hxx>
|
||||||
#include <Airports/runways.hxx>
|
#include <Airports/runways.hxx>
|
||||||
#include <Airports/groundnetwork.hxx>
|
#include <Airports/groundnetwork.hxx>
|
||||||
|
|
||||||
|
@ -124,45 +125,8 @@ FGAIFlightPlan::FGAIFlightPlan(const string& filename)
|
||||||
lastNodeVisited = 0;
|
lastNodeVisited = 0;
|
||||||
taxiRoute = 0;
|
taxiRoute = 0;
|
||||||
|
|
||||||
SGPath path( globals->get_fg_root() );
|
|
||||||
path.append( ("/AI/FlightPlans/" + filename).c_str() );
|
|
||||||
SGPropertyNode root;
|
|
||||||
|
|
||||||
try {
|
isValid = parseProperties(filename);
|
||||||
readProperties(path.str(), &root);
|
|
||||||
} catch (const sg_exception &) {
|
|
||||||
SG_LOG(SG_AI, SG_ALERT,
|
|
||||||
"Error reading AI flight plan: " << path.str());
|
|
||||||
// cout << path.str() << endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SGPropertyNode * node = root.getNode("flightplan");
|
|
||||||
for (int i = 0; i < node->nChildren(); i++) {
|
|
||||||
//cout << "Reading waypoint " << i << endl;
|
|
||||||
FGAIWaypoint* wpt = new FGAIWaypoint;
|
|
||||||
SGPropertyNode * wpt_node = node->getChild(i);
|
|
||||||
wpt->setName (wpt_node->getStringValue("name", "END" ));
|
|
||||||
wpt->setLatitude (wpt_node->getDoubleValue("lat", 0 ));
|
|
||||||
wpt->setLongitude (wpt_node->getDoubleValue("lon", 0 ));
|
|
||||||
wpt->setAltitude (wpt_node->getDoubleValue("alt", 0 ));
|
|
||||||
wpt->setSpeed (wpt_node->getDoubleValue("ktas", 0 ));
|
|
||||||
wpt->setCrossat (wpt_node->getDoubleValue("crossat", -10000 ));
|
|
||||||
wpt->setGear_down (wpt_node->getBoolValue("gear-down", false ));
|
|
||||||
wpt->setFlaps_down (wpt_node->getBoolValue("flaps-down", false ));
|
|
||||||
wpt->setOn_ground (wpt_node->getBoolValue("on-ground", false ));
|
|
||||||
wpt->setTime_sec (wpt_node->getDoubleValue("time-sec", 0 ));
|
|
||||||
wpt->setTime (wpt_node->getStringValue("time", "" ));
|
|
||||||
|
|
||||||
if (wpt->getName() == "END") wpt->setFinished(true);
|
|
||||||
else wpt->setFinished(false);
|
|
||||||
|
|
||||||
pushBackWaypoint( wpt );
|
|
||||||
}
|
|
||||||
|
|
||||||
wpt_iterator = waypoints.begin();
|
|
||||||
isValid = true;
|
|
||||||
//cout << waypoints.size() << " waypoints read." << endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -186,7 +150,9 @@ FGAIFlightPlan::FGAIFlightPlan(FGAIAircraft *ac,
|
||||||
double speed,
|
double speed,
|
||||||
const string& fltType,
|
const string& fltType,
|
||||||
const string& acType,
|
const string& acType,
|
||||||
const string& airline)
|
const string& airline) :
|
||||||
|
departure(dep),
|
||||||
|
arrival(arr)
|
||||||
{
|
{
|
||||||
sid = 0;
|
sid = 0;
|
||||||
repeat = false;
|
repeat = false;
|
||||||
|
@ -199,62 +165,44 @@ FGAIFlightPlan::FGAIFlightPlan(FGAIAircraft *ac,
|
||||||
lastNodeVisited = 0;
|
lastNodeVisited = 0;
|
||||||
taxiRoute = 0;
|
taxiRoute = 0;
|
||||||
|
|
||||||
SGPath path( globals->get_fg_root() );
|
if (parseProperties(p)) {
|
||||||
path.append( "/AI/FlightPlans" );
|
|
||||||
path.append( p );
|
|
||||||
|
|
||||||
SGPropertyNode root;
|
|
||||||
isValid = true;
|
isValid = true;
|
||||||
|
|
||||||
// This is a bit of a hack:
|
|
||||||
// Normally the value of course will be used to evaluate whether
|
|
||||||
// or not a waypoint will be used for midair initialization of
|
|
||||||
// an AI aircraft. However, if a course value of 999 will be passed
|
|
||||||
// when an update request is received, which will by definition always be
|
|
||||||
// on the ground and should include all waypoints.
|
|
||||||
// bool useInitialWayPoint = true;
|
|
||||||
// bool useCurrentWayPoint = false;
|
|
||||||
// if (course == 999)
|
|
||||||
// {
|
|
||||||
// useInitialWayPoint = false;
|
|
||||||
// useCurrentWayPoint = true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (path.exists())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
readProperties(path.str(), &root);
|
|
||||||
|
|
||||||
SGPropertyNode * node = root.getNode("flightplan");
|
|
||||||
|
|
||||||
//pushBackWaypoint( init_waypoint );
|
|
||||||
for (int i = 0; i < node->nChildren(); i++) {
|
|
||||||
//cout << "Reading waypoint " << i << endl;
|
|
||||||
FGAIWaypoint* wpt = new FGAIWaypoint;
|
|
||||||
SGPropertyNode * wpt_node = node->getChild(i);
|
|
||||||
wpt->setName (wpt_node->getStringValue("name", "END" ));
|
|
||||||
wpt->setLatitude (wpt_node->getDoubleValue("lat", 0 ));
|
|
||||||
wpt->setLongitude (wpt_node->getDoubleValue("lon", 0 ));
|
|
||||||
wpt->setAltitude (wpt_node->getDoubleValue("alt", 0 ));
|
|
||||||
wpt->setSpeed (wpt_node->getDoubleValue("ktas", 0 ));
|
|
||||||
wpt->setCrossat (wpt_node->getDoubleValue("crossat", -10000 ));
|
|
||||||
wpt->setGear_down (wpt_node->getBoolValue("gear-down", false ));
|
|
||||||
wpt->setFlaps_down (wpt_node->getBoolValue("flaps-down", false ));
|
|
||||||
|
|
||||||
if (wpt->getName() == "END") wpt->setFinished(true);
|
|
||||||
else wpt->setFinished(false);
|
|
||||||
pushBackWaypoint(wpt);
|
|
||||||
} // of node loop
|
|
||||||
wpt_iterator = waypoints.begin();
|
|
||||||
} catch (const sg_exception &e) {
|
|
||||||
SG_LOG(SG_AI, SG_WARN, "Error reading AI flight plan: " <<
|
|
||||||
e.getMessage() << " from " << e.getOrigin());
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// cout << path.str() << endl;
|
createWaypoints(ac, course, start, dep, arr, firstLeg, radius,
|
||||||
// cout << "Trying to create this plan dynamically" << endl;
|
alt, lat, lon, speed, fltType, acType, airline);
|
||||||
// cout << "Route from " << dep->id << " to " << arr->id << endl;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FGAIFlightPlan::~FGAIFlightPlan()
|
||||||
|
{
|
||||||
|
deleteWaypoints();
|
||||||
|
delete taxiRoute;
|
||||||
|
|
||||||
|
// if we're parked at a gate, release it
|
||||||
|
if (gateId >= 0) {
|
||||||
|
FGAirport* apt = (leg >= 7) ? arrival : departure;
|
||||||
|
if (apt) {
|
||||||
|
SG_LOG(SG_AI, SG_INFO, "releasing parking gate " << gateId << " at " << apt->ident());
|
||||||
|
apt->getDynamics()->releaseParking(gateId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGAIFlightPlan::createWaypoints(FGAIAircraft *ac,
|
||||||
|
double course,
|
||||||
|
time_t start,
|
||||||
|
FGAirport *dep,
|
||||||
|
FGAirport *arr,
|
||||||
|
bool firstLeg,
|
||||||
|
double radius,
|
||||||
|
double alt,
|
||||||
|
double lat,
|
||||||
|
double lon,
|
||||||
|
double speed,
|
||||||
|
const string& fltType,
|
||||||
|
const string& acType,
|
||||||
|
const string& airline)
|
||||||
|
{
|
||||||
time_t now = time(NULL) + fgGetLong("/sim/time/warp");
|
time_t now = time(NULL) + fgGetLong("/sim/time/warp");
|
||||||
time_t timeDiff = now-start;
|
time_t timeDiff = now-start;
|
||||||
leg = 1;
|
leg = 1;
|
||||||
|
@ -279,19 +227,48 @@ FGAIFlightPlan::FGAIFlightPlan(FGAIAircraft *ac,
|
||||||
isValid = create(ac, dep, arr, leg, alt, speed, lat, lon,
|
isValid = create(ac, dep, arr, leg, alt, speed, lat, lon,
|
||||||
firstLeg, radius, fltType, acType, airline, dist);
|
firstLeg, radius, fltType, acType, airline, dist);
|
||||||
wpt_iterator = waypoints.begin();
|
wpt_iterator = waypoints.begin();
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FGAIFlightPlan::parseProperties(const std::string& filename)
|
||||||
|
|
||||||
|
|
||||||
FGAIFlightPlan::~FGAIFlightPlan()
|
|
||||||
{
|
{
|
||||||
deleteWaypoints();
|
SGPath path( globals->get_fg_root() );
|
||||||
delete taxiRoute;
|
path.append( "/AI/FlightPlans/" + filename );
|
||||||
|
if (!path.exists()) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SGPropertyNode root;
|
||||||
|
try {
|
||||||
|
readProperties(path.str(), &root);
|
||||||
|
} catch (const sg_exception &e) {
|
||||||
|
SG_LOG(SG_AI, SG_ALERT, "Error reading AI flight plan: " << path.str()
|
||||||
|
<< "message:" << e.getFormattedMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SGPropertyNode * node = root.getNode("flightplan");
|
||||||
|
for (int i = 0; i < node->nChildren(); i++) {
|
||||||
|
FGAIWaypoint* wpt = new FGAIWaypoint;
|
||||||
|
SGPropertyNode * wpt_node = node->getChild(i);
|
||||||
|
wpt->setName (wpt_node->getStringValue("name", "END" ));
|
||||||
|
wpt->setLatitude (wpt_node->getDoubleValue("lat", 0 ));
|
||||||
|
wpt->setLongitude (wpt_node->getDoubleValue("lon", 0 ));
|
||||||
|
wpt->setAltitude (wpt_node->getDoubleValue("alt", 0 ));
|
||||||
|
wpt->setSpeed (wpt_node->getDoubleValue("ktas", 0 ));
|
||||||
|
wpt->setCrossat (wpt_node->getDoubleValue("crossat", -10000 ));
|
||||||
|
wpt->setGear_down (wpt_node->getBoolValue("gear-down", false ));
|
||||||
|
wpt->setFlaps_down (wpt_node->getBoolValue("flaps-down", false ));
|
||||||
|
wpt->setOn_ground (wpt_node->getBoolValue("on-ground", false ));
|
||||||
|
wpt->setTime_sec (wpt_node->getDoubleValue("time-sec", 0 ));
|
||||||
|
wpt->setTime (wpt_node->getStringValue("time", "" ));
|
||||||
|
wpt->setFinished ((wpt->getName() == "END"));
|
||||||
|
pushBackWaypoint( wpt );
|
||||||
|
}
|
||||||
|
|
||||||
|
wpt_iterator = waypoints.begin();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
FGAIWaypoint* const FGAIFlightPlan::getPreviousWaypoint( void ) const
|
FGAIWaypoint* const FGAIFlightPlan::getPreviousWaypoint( void ) const
|
||||||
{
|
{
|
||||||
|
@ -425,10 +402,9 @@ double FGAIFlightPlan::getBearing(FGAIWaypoint* first, FGAIWaypoint* second) con
|
||||||
return SGGeodesy::courseDeg(first->getPos(), second->getPos());
|
return SGGeodesy::courseDeg(first->getPos(), second->getPos());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double FGAIFlightPlan::getBearing(const SGGeod& aPos, FGAIWaypoint* wp) const
|
||||||
double FGAIFlightPlan::getBearing(double lat, double lon, FGAIWaypoint* wp) const
|
|
||||||
{
|
{
|
||||||
return SGGeodesy::courseDeg(SGGeod::fromDeg(lon, lat), wp->getPos());
|
return SGGeodesy::courseDeg(aPos, wp->getPos());
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGAIFlightPlan::deleteWaypoints()
|
void FGAIFlightPlan::deleteWaypoints()
|
||||||
|
|
|
@ -19,16 +19,21 @@
|
||||||
#ifndef _FG_AIFLIGHTPLAN_HXX
|
#ifndef _FG_AIFLIGHTPLAN_HXX
|
||||||
#define _FG_AIFLIGHTPLAN_HXX
|
#define _FG_AIFLIGHTPLAN_HXX
|
||||||
|
|
||||||
#include <simgear/compiler.h>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <simgear/math/SGMath.hxx>
|
|
||||||
|
|
||||||
|
#include <simgear/compiler.h>
|
||||||
|
#include <simgear/math/SGMath.hxx>
|
||||||
|
#include <simgear/structure/SGSharedPtr.hxx>
|
||||||
|
|
||||||
|
// forward decls
|
||||||
class FGTaxiRoute;
|
class FGTaxiRoute;
|
||||||
class FGRunway;
|
class FGRunway;
|
||||||
class FGAIAircraft;
|
class FGAIAircraft;
|
||||||
class FGAirport;
|
class FGAirport;
|
||||||
|
|
||||||
|
typedef SGSharedPtr<FGAirport> FGAirportRef;
|
||||||
|
|
||||||
class FGAIWaypoint {
|
class FGAIWaypoint {
|
||||||
private:
|
private:
|
||||||
std::string name;
|
std::string name;
|
||||||
|
@ -121,7 +126,8 @@ public:
|
||||||
void setLeadDistance(double distance_ft);
|
void setLeadDistance(double distance_ft);
|
||||||
double getLeadDistance( void ) const {return lead_distance;}
|
double getLeadDistance( void ) const {return lead_distance;}
|
||||||
double getBearing(FGAIWaypoint* previous, FGAIWaypoint* next) const;
|
double getBearing(FGAIWaypoint* previous, FGAIWaypoint* next) const;
|
||||||
double getBearing(double lat, double lon, FGAIWaypoint* next) const;
|
double getBearing(const SGGeod& aPos, FGAIWaypoint* next) const;
|
||||||
|
|
||||||
double checkTrackLength(std::string wptName);
|
double checkTrackLength(std::string wptName);
|
||||||
time_t getStartTime() const { return start_time; }
|
time_t getStartTime() const { return start_time; }
|
||||||
time_t getArrivalTime() const { return arrivalTime; }
|
time_t getArrivalTime() const { return arrivalTime; }
|
||||||
|
@ -187,9 +193,10 @@ private:
|
||||||
FGTaxiRoute *taxiRoute;
|
FGTaxiRoute *taxiRoute;
|
||||||
std::string name;
|
std::string name;
|
||||||
bool isValid;
|
bool isValid;
|
||||||
|
FGAirportRef departure, arrival;
|
||||||
|
|
||||||
void createPushBackFallBack(FGAIAircraft *, bool, FGAirport*, double radius, const std::string&, const std::string&, const std::string&);
|
void createPushBackFallBack(FGAIAircraft *, bool, FGAirport*, double radius, const std::string&, const std::string&, const std::string&);
|
||||||
bool createClimb(FGAIAircraft *, bool, FGAirport *, double, double, const std::string&);
|
bool createClimb(FGAIAircraft *, bool, FGAirport *, FGAirport* arrival, double, double, const std::string&);
|
||||||
bool createCruise(FGAIAircraft *, bool, FGAirport*, FGAirport*, double, double, double, double, const std::string&);
|
bool createCruise(FGAIAircraft *, bool, FGAirport*, FGAirport*, double, double, double, double, const std::string&);
|
||||||
bool createDescent(FGAIAircraft *, FGAirport *, double latitude, double longitude, double speed, double alt,const std::string&, double distance);
|
bool createDescent(FGAIAircraft *, FGAirport *, double latitude, double longitude, double speed, double alt,const std::string&, double distance);
|
||||||
bool createLanding(FGAIAircraft *, FGAirport *, const std::string&);
|
bool createLanding(FGAIAircraft *, FGAirport *, const std::string&);
|
||||||
|
@ -214,6 +221,28 @@ private:
|
||||||
|
|
||||||
//void createCruiseFallback(bool, FGAirport*, FGAirport*, double, double, double, double);
|
//void createCruiseFallback(bool, FGAirport*, FGAirport*, double, double, double, double);
|
||||||
void evaluateRoutePart(double deplat, double deplon, double arrlat, double arrlon);
|
void evaluateRoutePart(double deplat, double deplon, double arrlat, double arrlon);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* look for and parse an PropertyList flight-plan file - essentially
|
||||||
|
* a flat list waypoint objects, encoded to properties
|
||||||
|
*/
|
||||||
|
bool parseProperties(const std::string& filename);
|
||||||
|
|
||||||
|
void createWaypoints(FGAIAircraft *ac,
|
||||||
|
double course,
|
||||||
|
time_t start,
|
||||||
|
FGAirport *dep,
|
||||||
|
FGAirport *arr,
|
||||||
|
bool firstLeg,
|
||||||
|
double radius,
|
||||||
|
double alt,
|
||||||
|
double lat,
|
||||||
|
double lon,
|
||||||
|
double speed,
|
||||||
|
const std::string& fltType,
|
||||||
|
const std::string& acType,
|
||||||
|
const std::string& airline);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
wpt_vector_iterator getFirstWayPoint() { return waypoints.begin(); };
|
wpt_vector_iterator getFirstWayPoint() { return waypoints.begin(); };
|
||||||
wpt_vector_iterator getLastWayPoint() { return waypoints.end(); };
|
wpt_vector_iterator getLastWayPoint() { return waypoints.end(); };
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
#include <Environment/environment_mgr.hxx>
|
#include <Environment/environment_mgr.hxx>
|
||||||
#include <Environment/environment.hxx>
|
#include <Environment/environment.hxx>
|
||||||
#include <FDM/LaRCsim/basic_aero.h>
|
#include <FDM/LaRCsim/basic_aero.h>
|
||||||
|
#include <Navaids/navrecord.hxx>
|
||||||
|
|
||||||
|
|
||||||
/* FGAIFlightPlan::create()
|
/* FGAIFlightPlan::create()
|
||||||
|
@ -78,7 +79,7 @@ bool FGAIFlightPlan::create(FGAIAircraft * ac, FGAirport * dep,
|
||||||
retVal = createTakeOff(ac, firstFlight, dep, speed, fltType);
|
retVal = createTakeOff(ac, firstFlight, dep, speed, fltType);
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
retVal = createClimb(ac, firstFlight, dep, speed, alt, fltType);
|
retVal = createClimb(ac, firstFlight, dep, arr, speed, alt, fltType);
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
retVal = createCruise(ac, firstFlight, dep, arr, latitude, longitude, speed,
|
retVal = createCruise(ac, firstFlight, dep, arr, latitude, longitude, speed,
|
||||||
|
@ -460,20 +461,18 @@ bool FGAIFlightPlan::createTakeOff(FGAIAircraft * ac, bool firstFlight,
|
||||||
const string & fltType)
|
const string & fltType)
|
||||||
{
|
{
|
||||||
const double ACCEL_POINT = 105.0;
|
const double ACCEL_POINT = 105.0;
|
||||||
const double KNOTS_HOUR_TO_MSEC = SG_NM_TO_METER / 3600.0;
|
|
||||||
// climb-out angle in degrees. could move this to the perf-db but this
|
// climb-out angle in degrees. could move this to the perf-db but this
|
||||||
// value is pretty sane
|
// value is pretty sane
|
||||||
const double INITIAL_PITCH_ANGLE = 12.5;
|
const double INITIAL_PITCH_ANGLE = 10.0;
|
||||||
|
|
||||||
double accel = ac->getPerformance()->acceleration();
|
double accel = ac->getPerformance()->acceleration();
|
||||||
double vTaxi = ac->getPerformance()->vTaxi();
|
double vTaxi = ac->getPerformance()->vTaxi();
|
||||||
double vRotate = ac->getPerformance()->vRotate();
|
double vRotate = ac->getPerformance()->vRotate();
|
||||||
double vTakeoff = ac->getPerformance()->vTakeoff();
|
double vTakeoff = ac->getPerformance()->vTakeoff();
|
||||||
|
|
||||||
double accelMetric = accel * KNOTS_HOUR_TO_MSEC;
|
double accelMetric = accel * SG_KT_TO_MPS;
|
||||||
double vTaxiMetric = vTaxi * KNOTS_HOUR_TO_MSEC;
|
double vTaxiMetric = vTaxi * SG_KT_TO_MPS;
|
||||||
double vRotateMetric = vRotate * KNOTS_HOUR_TO_MSEC;
|
double vRotateMetric = vRotate * SG_KT_TO_MPS;
|
||||||
double vTakeoffMetric = vTakeoff * KNOTS_HOUR_TO_MSEC;
|
|
||||||
|
|
||||||
FGAIWaypoint *wpt;
|
FGAIWaypoint *wpt;
|
||||||
// Get the current active runway, based on code from David Luff
|
// Get the current active runway, based on code from David Luff
|
||||||
|
@ -498,7 +497,8 @@ bool FGAIFlightPlan::createTakeOff(FGAIAircraft * ac, bool firstFlight,
|
||||||
wpt = createOnGround(ac, "rotate", accelPoint, airportElev, vTakeoff);
|
wpt = createOnGround(ac, "rotate", accelPoint, airportElev, vTakeoff);
|
||||||
pushBackWaypoint(wpt);
|
pushBackWaypoint(wpt);
|
||||||
|
|
||||||
double vRef = vTakeoffMetric + 20; // climb-out at v2 + 20kts
|
double vRef = vTakeoff + 20; // climb-out at v2 + 20kts
|
||||||
|
|
||||||
double gearUpDist = d + pitchDistance(INITIAL_PITCH_ANGLE, 400 * SG_FEET_TO_METER);
|
double gearUpDist = d + pitchDistance(INITIAL_PITCH_ANGLE, 400 * SG_FEET_TO_METER);
|
||||||
accelPoint = rwy->pointOnCenterline(gearUpDist);
|
accelPoint = rwy->pointOnCenterline(gearUpDist);
|
||||||
|
|
||||||
|
@ -509,14 +509,22 @@ bool FGAIFlightPlan::createTakeOff(FGAIAircraft * ac, bool firstFlight,
|
||||||
wpt->setGear_down(false);
|
wpt->setGear_down(false);
|
||||||
pushBackWaypoint(wpt);
|
pushBackWaypoint(wpt);
|
||||||
|
|
||||||
|
// limit climbout speed to 240kts below 10000'
|
||||||
|
double vClimbBelow10000 = std::min(240.0, ac->getPerformance()->vClimb());
|
||||||
|
|
||||||
|
// create two climb-out points. This is important becuase the first climb point will
|
||||||
|
// be a (sometimes large) turn towards the destination, and we don't want to
|
||||||
|
// commence that turn below 2000'
|
||||||
double climbOut = d + pitchDistance(INITIAL_PITCH_ANGLE, 2000 * SG_FEET_TO_METER);
|
double climbOut = d + pitchDistance(INITIAL_PITCH_ANGLE, 2000 * SG_FEET_TO_METER);
|
||||||
accelPoint = rwy->pointOnCenterline(climbOut);
|
accelPoint = rwy->pointOnCenterline(climbOut);
|
||||||
wpt = createInAir(ac, "2000'", accelPoint, airportElev + 2000, vRef);
|
wpt = createInAir(ac, "2000'", accelPoint, airportElev + 2000, vClimbBelow10000);
|
||||||
|
pushBackWaypoint(wpt);
|
||||||
|
|
||||||
|
climbOut = d + pitchDistance(INITIAL_PITCH_ANGLE, 2500 * SG_FEET_TO_METER);
|
||||||
|
accelPoint = rwy->pointOnCenterline(climbOut);
|
||||||
|
wpt = createInAir(ac, "2500'", accelPoint, airportElev + 2500, vClimbBelow10000);
|
||||||
pushBackWaypoint(wpt);
|
pushBackWaypoint(wpt);
|
||||||
|
|
||||||
// as soon as we pass 2000', hand off to departure so the next acft can line up
|
|
||||||
// ideally the next aircraft would be able to line-up + hold but that's tricky
|
|
||||||
// with the current design.
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -525,12 +533,12 @@ bool FGAIFlightPlan::createTakeOff(FGAIAircraft * ac, bool firstFlight,
|
||||||
* initialize the Aircraft at the parking location
|
* initialize the Aircraft at the parking location
|
||||||
******************************************************************/
|
******************************************************************/
|
||||||
bool FGAIFlightPlan::createClimb(FGAIAircraft * ac, bool firstFlight,
|
bool FGAIFlightPlan::createClimb(FGAIAircraft * ac, bool firstFlight,
|
||||||
FGAirport * apt, double speed, double alt,
|
FGAirport * apt, FGAirport* arrival,
|
||||||
|
double speed, double alt,
|
||||||
const string & fltType)
|
const string & fltType)
|
||||||
{
|
{
|
||||||
FGAIWaypoint *wpt;
|
FGAIWaypoint *wpt;
|
||||||
// bool planLoaded = false;
|
// string fPLName;
|
||||||
string fPLName;
|
|
||||||
double vClimb = ac->getPerformance()->vClimb();
|
double vClimb = ac->getPerformance()->vClimb();
|
||||||
|
|
||||||
if (firstFlight) {
|
if (firstFlight) {
|
||||||
|
@ -546,18 +554,23 @@ bool FGAIFlightPlan::createClimb(FGAIAircraft * ac, bool firstFlight,
|
||||||
//cerr << " Cloning waypoint " << endl;
|
//cerr << " Cloning waypoint " << endl;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
FGRunway * rwy = apt->getRunwayByIdent(activeRunway);
|
FGRunway* runway = apt->getRunwayByIdent(activeRunway);
|
||||||
assert( rwy != NULL );
|
SGGeod cur = runway->end();
|
||||||
|
if (!waypoints.empty()) {
|
||||||
|
cur = waypoints.back()->getPos();
|
||||||
|
}
|
||||||
|
|
||||||
SGGeod climb1 = rwy->pointOnCenterline(10 * SG_NM_TO_METER);
|
// compute course towards destination
|
||||||
|
double course = SGGeodesy::courseDeg(cur, arrival->geod());
|
||||||
|
|
||||||
|
SGGeod climb1 = SGGeodesy::direct(cur, course, 10 * SG_NM_TO_METER);
|
||||||
wpt = createInAir(ac, "10000ft climb", climb1, 10000, vClimb);
|
wpt = createInAir(ac, "10000ft climb", climb1, 10000, vClimb);
|
||||||
wpt->setGear_down(true);
|
wpt->setGear_down(true);
|
||||||
wpt->setFlaps_down(true);
|
wpt->setFlaps_down(true);
|
||||||
pushBackWaypoint(wpt);
|
pushBackWaypoint(wpt);
|
||||||
|
|
||||||
SGGeod climb2 = rwy->pointOnCenterline(20 * SG_NM_TO_METER);
|
SGGeod climb2 = SGGeodesy::direct(cur, course, 20 * SG_NM_TO_METER);
|
||||||
wpt = cloneWithPos(ac, wpt, "18000ft climb", climb2);
|
wpt = createInAir(ac, "18000ft climb", climb2, 18000, vClimb);
|
||||||
wpt->setAltitude(18000);
|
|
||||||
pushBackWaypoint(wpt);
|
pushBackWaypoint(wpt);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -580,8 +593,6 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
|
||||||
FGAIWaypoint *wpt;
|
FGAIWaypoint *wpt;
|
||||||
double vDescent = ac->getPerformance()->vDescent();
|
double vDescent = ac->getPerformance()->vDescent();
|
||||||
double vApproach = ac->getPerformance()->vApproach();
|
double vApproach = ac->getPerformance()->vApproach();
|
||||||
double vTouchdown = ac->getPerformance()->vTouchdown();
|
|
||||||
|
|
||||||
|
|
||||||
//Beginning of Descent
|
//Beginning of Descent
|
||||||
string rwyClass = getRunwayClassFromTrafficType(fltType);
|
string rwyClass = getRunwayClassFromTrafficType(fltType);
|
||||||
|
@ -827,33 +838,6 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
|
||||||
|
|
||||||
// The approach leg should bring the aircraft to approximately 4-6 nm out, after which the landing phase should take over.
|
// The approach leg should bring the aircraft to approximately 4-6 nm out, after which the landing phase should take over.
|
||||||
//cerr << "Phase 3: Approach" << endl;
|
//cerr << "Phase 3: Approach" << endl;
|
||||||
double tgt_speed = vApproach;
|
|
||||||
distanceOut -= distanceCovered;
|
|
||||||
double touchDownPoint = 0; //(rwy->lengthM() * 0.1);
|
|
||||||
for (int i = 1; i < nPoints; i++) {
|
|
||||||
SGGeod result;
|
|
||||||
double currentDist = i * (distanceOut / nPoints);
|
|
||||||
//double currentAltitude =
|
|
||||||
// apt->getElevation() + 2000 - (i * 2000 / (nPoints-1));
|
|
||||||
double alt = currentAltitude - (i * 2000 / (nPoints - 1));
|
|
||||||
snprintf(buffer, 16, "final%03d", i);
|
|
||||||
result = rwy->pointOnCenterline((-distanceOut) + currentDist + touchDownPoint);
|
|
||||||
if (i == nPoints - 30) {
|
|
||||||
tgt_speed = vTouchdown;
|
|
||||||
}
|
|
||||||
wpt = createInAir(ac, buffer, result, alt, tgt_speed);
|
|
||||||
wpt->setCrossat(alt);
|
|
||||||
wpt->setTrackLength((distanceOut / nPoints));
|
|
||||||
// account for the extra distance due to an extended downwind leg
|
|
||||||
if (i == 1) {
|
|
||||||
wpt->setTrackLength(wpt->getTrackLength() + distanceCovered);
|
|
||||||
}
|
|
||||||
//cerr << "Track Length : " << wpt->trackLength;
|
|
||||||
pushBackWaypoint(wpt);
|
|
||||||
//if (apt->ident() == fgGetString("/sim/presets/airport-id")) {
|
|
||||||
// cerr << " Position : " << result.getLatitudeDeg() << " " << result.getLongitudeDeg() << " " << currentAltitude << " " << apt->getElevation() << " " << distanceOut << endl;
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
//cerr << "Done" << endl;
|
//cerr << "Done" << endl;
|
||||||
|
|
||||||
|
@ -885,10 +869,31 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
|
||||||
ac->resetPositionFromFlightPlan();
|
ac->resetPositionFromFlightPlan();
|
||||||
}
|
}
|
||||||
waypoints[1]->setName( (waypoints[1]->getName() + string("legend")));
|
waypoints[1]->setName( (waypoints[1]->getName() + string("legend")));
|
||||||
waypoints.back()->setName(waypoints.back()->getName() + "LandingThreshold");
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* compute the distance along the centerline, to the ILS glideslope
|
||||||
|
* transmitter. Return -1 if there's no GS for the runway
|
||||||
|
*/
|
||||||
|
static double runwayGlideslopeTouchdownDistance(FGRunway* rwy)
|
||||||
|
{
|
||||||
|
FGNavRecord* gs = rwy->glideslope();
|
||||||
|
if (!gs) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
SGVec3d runwayPosCart = SGVec3d::fromGeod(rwy->pointOnCenterline(0.0));
|
||||||
|
// compute a unit vector in ECF cartesian space, from the runway beginning to the end
|
||||||
|
SGVec3d runwayDirectionVec = normalize(SGVec3d::fromGeod(rwy->end()) - runwayPosCart);
|
||||||
|
SGVec3d gsTransmitterVec = gs->cart() - runwayPosCart;
|
||||||
|
|
||||||
|
// project the gsTransmitterVec along the runwayDirctionVec to get out
|
||||||
|
// final value (in metres)
|
||||||
|
double dist = dot(runwayDirectionVec, gsTransmitterVec);
|
||||||
|
return dist;
|
||||||
|
}
|
||||||
|
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
* CreateLanding
|
* CreateLanding
|
||||||
* Create a flight path from the "permision to land" point (currently
|
* Create a flight path from the "permision to land" point (currently
|
||||||
|
@ -902,108 +907,81 @@ bool FGAIFlightPlan::createLanding(FGAIAircraft * ac, FGAirport * apt,
|
||||||
double vTouchdown = ac->getPerformance()->vTouchdown();
|
double vTouchdown = ac->getPerformance()->vTouchdown();
|
||||||
double vTaxi = ac->getPerformance()->vTaxi();
|
double vTaxi = ac->getPerformance()->vTaxi();
|
||||||
double decel = ac->getPerformance()->deceleration() * 1.4;
|
double decel = ac->getPerformance()->deceleration() * 1.4;
|
||||||
|
double vApproach = ac->getPerformance()->vApproach();
|
||||||
|
|
||||||
double vTouchdownMetric = (vTouchdown * SG_NM_TO_METER) / 3600;
|
double vTouchdownMetric = (vTouchdown * SG_NM_TO_METER) / 3600;
|
||||||
double vTaxiMetric = (vTaxi * SG_NM_TO_METER) / 3600;
|
double vTaxiMetric = (vTaxi * SG_NM_TO_METER) / 3600;
|
||||||
double decelMetric = (decel * SG_NM_TO_METER) / 3600;
|
double decelMetric = (decel * SG_NM_TO_METER) / 3600;
|
||||||
|
|
||||||
//string rwyClass = getRunwayClassFromTrafficType(fltType);
|
|
||||||
//double heading = ac->getTrafficRef()->getCourse();
|
|
||||||
//apt->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway, heading);
|
|
||||||
//rwy = apt->getRunwayByIdent(activeRunway);
|
|
||||||
|
|
||||||
|
|
||||||
FGAIWaypoint *wpt;
|
|
||||||
//double aptElev = apt->getElevation();
|
|
||||||
double currElev = 0;
|
|
||||||
char buffer[12];
|
char buffer[12];
|
||||||
FGRunway * rwy = apt->getRunwayByIdent(activeRunway);
|
FGRunway * rwy = apt->getRunwayByIdent(activeRunway);
|
||||||
assert( rwy != NULL );
|
assert( rwy != NULL );
|
||||||
SGGeod refPoint = rwy->pointOnCenterline(0);
|
SGGeod threshold = rwy->threshold();
|
||||||
FGTaxiNode *tn = 0;
|
double currElev = threshold.getElevationFt();
|
||||||
if (apt->getDynamics()->getGroundNetwork()) {
|
|
||||||
int node = apt->getDynamics()->getGroundNetwork()->findNearestNode(refPoint);
|
|
||||||
tn = apt->getDynamics()->getGroundNetwork()->findNode(node);
|
|
||||||
}
|
|
||||||
if (tn) {
|
|
||||||
currElev = tn->getElevationFt(apt->getElevation());
|
|
||||||
} else {
|
|
||||||
currElev = apt->getElevation();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
double touchdownDistance = runwayGlideslopeTouchdownDistance(rwy);
|
||||||
|
if (touchdownDistance < 0.0) {
|
||||||
|
double landingLength = rwy->lengthM() - (rwy->displacedThresholdM());
|
||||||
|
// touchdown 25% of the way along the landing area
|
||||||
|
touchdownDistance = rwy->displacedThresholdM() + (landingLength * 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
SGGeod coord;
|
SGGeod coord;
|
||||||
|
// find glideslope entry point, 2000' above touchdown elevation
|
||||||
|
double glideslopeEntry = -((2000 * SG_FEET_TO_METER) / tan(3.0)) + touchdownDistance;
|
||||||
|
FGAIWaypoint *wpt = createInAir(ac, "Glideslope begin", rwy->pointOnCenterline(glideslopeEntry),
|
||||||
|
currElev + 2000, vApproach);
|
||||||
|
pushBackWaypoint(wpt);
|
||||||
|
|
||||||
|
// deceleration point, 500' above touchdown elevation - slow from approach speed
|
||||||
|
// to touchdown speed
|
||||||
|
double decelPoint = -((500 * SG_FEET_TO_METER) / tan(3.0)) + touchdownDistance;
|
||||||
|
wpt = createInAir(ac, "500' decel", rwy->pointOnCenterline(decelPoint),
|
||||||
|
currElev + 2000, vTouchdown);
|
||||||
|
pushBackWaypoint(wpt);
|
||||||
|
|
||||||
|
// compute elevation above the runway start, based on a 3-degree glideslope
|
||||||
|
double heightAboveRunwayStart = touchdownDistance *
|
||||||
|
tan(3.0 * SG_DEGREES_TO_RADIANS) * SG_METER_TO_FEET;
|
||||||
|
wpt = createInAir(ac, "CrossThreshold", rwy->begin(),
|
||||||
|
heightAboveRunwayStart + currElev, vTouchdown);
|
||||||
|
pushBackWaypoint(wpt);
|
||||||
|
|
||||||
|
double rolloutDistance = accelDistance(vTouchdownMetric, vTaxiMetric, decelMetric);
|
||||||
|
|
||||||
/*double distanceOut = rwy->lengthM() * .1;
|
|
||||||
double nPoints = 20;
|
|
||||||
for (int i = 1; i < nPoints; i++) {
|
|
||||||
snprintf(buffer, 12, "flare%d", i);
|
|
||||||
double currentDist = i * (distanceOut / nPoints);
|
|
||||||
double currentAltitude = apt->getElevation() + 20 - (i * 20 / nPoints);
|
|
||||||
coord = rwy->pointOnCenterline((currentDist * (i / nPoints)));
|
|
||||||
wpt = createInAir(ac, buffer, coord, currentAltitude, (vTouchdown));
|
|
||||||
}*/
|
|
||||||
double rolloutDistance =
|
|
||||||
(vTouchdownMetric * vTouchdownMetric - vTaxiMetric * vTaxiMetric) / (2 * decelMetric);
|
|
||||||
//cerr << " touchdown speed = " << vTouchdown << ". Rollout distance " << rolloutDistance << endl;
|
|
||||||
int nPoints = 50;
|
int nPoints = 50;
|
||||||
for (int i = 1; i < nPoints; i++) {
|
for (int i = 1; i < nPoints; i++) {
|
||||||
snprintf(buffer, 12, "landing03%d", i);
|
snprintf(buffer, 12, "landing03%d", i);
|
||||||
|
double t = ((double) i) / nPoints;
|
||||||
coord = rwy->pointOnCenterline((rolloutDistance * ((double) i / (double) nPoints)));
|
coord = rwy->pointOnCenterline(touchdownDistance + (rolloutDistance * t));
|
||||||
wpt = createOnGround(ac, buffer, coord, currElev, 2*vTaxi);
|
double vel = (vTouchdownMetric * (1.0 - t)) + (vTaxiMetric * t);
|
||||||
|
wpt = createOnGround(ac, buffer, coord, currElev, vel);
|
||||||
wpt->setCrossat(currElev);
|
wpt->setCrossat(currElev);
|
||||||
pushBackWaypoint(wpt);
|
pushBackWaypoint(wpt);
|
||||||
}
|
}
|
||||||
|
|
||||||
wpt->setSpeed(vTaxi);
|
wpt->setSpeed(vTaxi);
|
||||||
double mindist = 1.1 * rolloutDistance;
|
double mindist = (1.1 * rolloutDistance) + touchdownDistance;
|
||||||
double maxdist = rwy->lengthM();
|
|
||||||
//cerr << "Finding nearest exit" << endl;
|
|
||||||
FGGroundNetwork *gn = apt->getDynamics()->getGroundNetwork();
|
FGGroundNetwork *gn = apt->getDynamics()->getGroundNetwork();
|
||||||
if (gn) {
|
if (!gn) {
|
||||||
double min = 0;
|
return true;
|
||||||
for (int i = ceil(mindist); i < floor(maxdist); i++) {
|
}
|
||||||
|
|
||||||
coord = rwy->pointOnCenterline(mindist);
|
coord = rwy->pointOnCenterline(mindist);
|
||||||
int nodeId = 0;
|
int nodeId = 0;
|
||||||
if (gn->getVersion() > 0) {
|
if (gn->getVersion() > 0) {
|
||||||
nodeId = gn->findNearestNodeOnRunway(coord);
|
nodeId = gn->findNearestNodeOnRunway(coord, rwy);
|
||||||
} else {
|
} else {
|
||||||
nodeId = gn->findNearestNode(coord);
|
nodeId = gn->findNearestNode(coord);
|
||||||
}
|
}
|
||||||
if (tn)
|
|
||||||
tn = gn->findNode(nodeId);
|
|
||||||
if (!tn)
|
|
||||||
break;
|
|
||||||
|
|
||||||
double dist = SGGeodesy::distanceM(coord, tn->geod());
|
FGTaxiNode* tn = gn->findNode(nodeId);
|
||||||
if (dist < (min + 0.75)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
min = dist;
|
|
||||||
}
|
|
||||||
if (tn) {
|
if (tn) {
|
||||||
wpt = createOnGround(ac, buffer, tn->geod(), currElev, vTaxi);
|
wpt = createOnGround(ac, buffer, tn->geod(), currElev, vTaxi);
|
||||||
pushBackWaypoint(wpt);
|
pushBackWaypoint(wpt);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
//cerr << "Done. " << endl;
|
|
||||||
|
|
||||||
/*
|
|
||||||
//Runway Threshold
|
|
||||||
wpt = createOnGround(ac, "Threshold", rwy->threshold(), aptElev, vTouchdown);
|
|
||||||
wpt->crossat = apt->getElevation();
|
|
||||||
pushBackWaypoint(wpt);
|
|
||||||
|
|
||||||
// Roll-out
|
|
||||||
wpt = createOnGround(ac, "Center", rwy->geod(), aptElev, vTaxi*2);
|
|
||||||
pushBackWaypoint(wpt);
|
|
||||||
|
|
||||||
SGGeod rollOut = rwy->pointOnCenterline(rwy->lengthM() * 0.9);
|
|
||||||
wpt = createOnGround(ac, "Roll Out", rollOut, aptElev, vTaxi);
|
|
||||||
wpt->crossat = apt->getElevation();
|
|
||||||
pushBackWaypoint(wpt);
|
|
||||||
*/
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
|
|
||||||
#include <Airports/simple.hxx>
|
#include <Airports/simple.hxx>
|
||||||
#include <Airports/dynamics.hxx>
|
#include <Airports/dynamics.hxx>
|
||||||
|
#include <Airports/runways.hxx>
|
||||||
|
|
||||||
#include <AIModel/AIAircraft.hxx>
|
#include <AIModel/AIAircraft.hxx>
|
||||||
#include <AIModel/performancedata.hxx>
|
#include <AIModel/performancedata.hxx>
|
||||||
|
@ -455,7 +456,7 @@ int FGGroundNetwork::findNearestNode(const SGGeod & aGeod)
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
int FGGroundNetwork::findNearestNodeOnRunway(const SGGeod & aGeod)
|
int FGGroundNetwork::findNearestNodeOnRunway(const SGGeod & aGeod, FGRunway* aRunway)
|
||||||
{
|
{
|
||||||
double minDist = HUGE_VAL;
|
double minDist = HUGE_VAL;
|
||||||
int index = -1;
|
int index = -1;
|
||||||
|
@ -465,6 +466,16 @@ int FGGroundNetwork::findNearestNodeOnRunway(const SGGeod & aGeod)
|
||||||
if (!i->second->getIsOnRunway()) {
|
if (!i->second->getIsOnRunway()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// check point lies on the runway - i.e that course from aGeod to the
|
||||||
|
// runway end, matches the runway heading
|
||||||
|
if (aRunway) {
|
||||||
|
double course = SGGeodesy::courseDeg(i->second->geod(), aRunway->end());
|
||||||
|
double headingDiff = course - aRunway->headingDeg();
|
||||||
|
SG_NORMALIZE_RANGE(headingDiff, -180.0, 180.0);
|
||||||
|
if (fabs(headingDiff) > 3.0) { // 3 degrees tolerance
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
double d = SGGeodesy::distanceM(aGeod, i->second->geod());
|
double d = SGGeodesy::distanceM(aGeod, i->second->geod());
|
||||||
if (d < minDist) {
|
if (d < minDist) {
|
||||||
|
|
|
@ -31,13 +31,13 @@
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
class Block;
|
|
||||||
|
|
||||||
#include "gnnode.hxx"
|
#include "gnnode.hxx"
|
||||||
#include "parking.hxx"
|
#include "parking.hxx"
|
||||||
#include <ATC/trafficcontrol.hxx>
|
#include <ATC/trafficcontrol.hxx>
|
||||||
|
|
||||||
|
|
||||||
|
class Block;
|
||||||
|
class FGRunway;
|
||||||
class FGTaxiSegment; // forward reference
|
class FGTaxiSegment; // forward reference
|
||||||
class FGAIFlightPlan; // forward reference
|
class FGAIFlightPlan; // forward reference
|
||||||
class FGAirport; // forward reference
|
class FGAirport; // forward reference
|
||||||
|
@ -275,7 +275,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
int findNearestNode(const SGGeod& aGeod);
|
int findNearestNode(const SGGeod& aGeod);
|
||||||
int findNearestNodeOnRunway(const SGGeod& aGeod);
|
int findNearestNodeOnRunway(const SGGeod& aGeod, FGRunway* aRunway = NULL);
|
||||||
|
|
||||||
FGTaxiNode *findNode(unsigned idx);
|
FGTaxiNode *findNode(unsigned idx);
|
||||||
FGTaxiSegment *findSegment(unsigned idx);
|
FGTaxiSegment *findSegment(unsigned idx);
|
||||||
|
|
|
@ -149,6 +149,17 @@ FGNavRecord* FGRunway::ILS() const
|
||||||
return (FGNavRecord*) flightgear::NavDataCache::instance()->loadById(_ils);
|
return (FGNavRecord*) flightgear::NavDataCache::instance()->loadById(_ils);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FGNavRecord* FGRunway::glideslope() const
|
||||||
|
{
|
||||||
|
flightgear::NavDataCache* cache = flightgear::NavDataCache::instance();
|
||||||
|
PositionedID gsId = cache->findNavaidForRunway(guid(), FGPositioned::GS);
|
||||||
|
if (gsId == 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (FGNavRecord*) cache->loadById(gsId);
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<flightgear::SID*> FGRunway::getSIDs() const
|
std::vector<flightgear::SID*> FGRunway::getSIDs() const
|
||||||
{
|
{
|
||||||
FGAirport* apt = airport();
|
FGAirport* apt = airport();
|
||||||
|
|
|
@ -108,6 +108,11 @@ public:
|
||||||
|
|
||||||
FGNavRecord* ILS() const;
|
FGNavRecord* ILS() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* retrieve the associated glideslope transmitter, if one is defined.
|
||||||
|
*/
|
||||||
|
FGNavRecord* glideslope() const;
|
||||||
|
|
||||||
void setILS(PositionedID nav) { _ils = nav; }
|
void setILS(PositionedID nav) { _ils = nav; }
|
||||||
|
|
||||||
FGRunway* reciprocalRunway() const;
|
FGRunway* reciprocalRunway() const;
|
||||||
|
|
|
@ -528,6 +528,9 @@ public:
|
||||||
findNavsByFreqNoPos = prepare("SELECT positioned.rowid FROM positioned, navaid WHERE "
|
findNavsByFreqNoPos = prepare("SELECT positioned.rowid FROM positioned, navaid WHERE "
|
||||||
"positioned.rowid=navaid.rowid AND freq=?1 " AND_TYPED);
|
"positioned.rowid=navaid.rowid AND freq=?1 " AND_TYPED);
|
||||||
|
|
||||||
|
findNavaidForRunway = prepare("SELECT positioned.rowid FROM positioned, navaid WHERE "
|
||||||
|
"positioned.rowid=navaid.rowid AND runway=?1 AND type=?2");
|
||||||
|
|
||||||
// for an octree branch, return the child octree nodes which exist,
|
// for an octree branch, return the child octree nodes which exist,
|
||||||
// described as a bit-mask
|
// described as a bit-mask
|
||||||
getOctreeChildren = prepare("SELECT children FROM octree WHERE rowid=?1");
|
getOctreeChildren = prepare("SELECT children FROM octree WHERE rowid=?1");
|
||||||
|
@ -808,7 +811,7 @@ public:
|
||||||
|
|
||||||
sqlite3_stmt_ptr searchAirports;
|
sqlite3_stmt_ptr searchAirports;
|
||||||
sqlite3_stmt_ptr findCommByFreq, findNavsByFreq,
|
sqlite3_stmt_ptr findCommByFreq, findNavsByFreq,
|
||||||
findNavsByFreqNoPos;
|
findNavsByFreqNoPos, findNavaidForRunway;
|
||||||
sqlite3_stmt_ptr getAirportItems, getAirportItemByIdent;
|
sqlite3_stmt_ptr getAirportItems, getAirportItemByIdent;
|
||||||
sqlite3_stmt_ptr findAirportRunway,
|
sqlite3_stmt_ptr findAirportRunway,
|
||||||
findILS;
|
findILS;
|
||||||
|
@ -1708,5 +1711,17 @@ AirwayEdgeVec NavDataCache::airwayEdgesFrom(int network, PositionedID pos)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PositionedID NavDataCache::findNavaidForRunway(PositionedID runway, FGPositioned::Type ty)
|
||||||
|
{
|
||||||
|
d->reset(d->findNavaidForRunway);
|
||||||
|
sqlite3_bind_int64(d->findNavaidForRunway, 1, runway);
|
||||||
|
sqlite3_bind_int(d->findNavaidForRunway, 2, ty);
|
||||||
|
if (!d->execSelect(d->findNavaidForRunway)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sqlite3_column_int64(d->findNavaidForRunway, 0);
|
||||||
|
}
|
||||||
|
|
||||||
} // of namespace flightgear
|
} // of namespace flightgear
|
||||||
|
|
||||||
|
|
|
@ -140,6 +140,11 @@ public:
|
||||||
/// returning results. Only used by TACAN carrier search
|
/// returning results. Only used by TACAN carrier search
|
||||||
PositionedIDVec findNavaidsByFreq(int freqKhz, FGPositioned::Filter* filt);
|
PositionedIDVec findNavaidsByFreq(int freqKhz, FGPositioned::Filter* filt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a runway and type, find the corresponding navaid (ILS / GS / OM)
|
||||||
|
*/
|
||||||
|
PositionedID findNavaidForRunway(PositionedID runway, FGPositioned::Type ty);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* given a navaid name (or similar) from apt.dat / nav.dat, find the
|
* given a navaid name (or similar) from apt.dat / nav.dat, find the
|
||||||
* corresponding airport and runway IDs.
|
* corresponding airport and runway IDs.
|
||||||
|
|
|
@ -200,15 +200,15 @@ void FGTrafficManager::shutdown()
|
||||||
cachefile << "[TrafficManagerCachedata:ref:2011:09:04]" << endl;
|
cachefile << "[TrafficManagerCachedata:ref:2011:09:04]" << endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (ScheduleVectorIterator sched = scheduledAircraft.begin();
|
|
||||||
sched != scheduledAircraft.end(); sched++) {
|
BOOST_FOREACH(FGAISchedule* acft, scheduledAircraft) {
|
||||||
if (saveData) {
|
if (saveData) {
|
||||||
cachefile << (*sched)->getRegistration() << " "
|
cachefile << acft->getRegistration() << " "
|
||||||
<< (*sched)->getRunCount() << " "
|
<< acft->getRunCount() << " "
|
||||||
<< (*sched)->getHits() << " "
|
<< acft->getHits() << " "
|
||||||
<< (*sched)->getLastUsed() << endl;
|
<< acft->getLastUsed() << endl;
|
||||||
}
|
}
|
||||||
delete(*sched);
|
delete acft;
|
||||||
}
|
}
|
||||||
if (saveData) {
|
if (saveData) {
|
||||||
cachefile.close();
|
cachefile.close();
|
||||||
|
@ -271,10 +271,9 @@ void FGTrafficManager::finishInit()
|
||||||
SG_LOG(SG_AI, SG_INFO, "finishing AI-Traffic init");
|
SG_LOG(SG_AI, SG_INFO, "finishing AI-Traffic init");
|
||||||
loadHeuristics();
|
loadHeuristics();
|
||||||
|
|
||||||
// Do sorting and scoring separately, to take advantage of the "homeport| variable
|
// Do sorting and scoring separately, to take advantage of the "homeport" variable
|
||||||
for (currAircraft = scheduledAircraft.begin();
|
BOOST_FOREACH(FGAISchedule* schedule, scheduledAircraft) {
|
||||||
currAircraft != scheduledAircraft.end(); currAircraft++) {
|
schedule->setScore();
|
||||||
(*currAircraft)->setScore();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sort(scheduledAircraft.begin(), scheduledAircraft.end(),
|
sort(scheduledAircraft.begin(), scheduledAircraft.end(),
|
||||||
|
@ -372,7 +371,7 @@ void FGTrafficManager::update(double /*dt */ )
|
||||||
}
|
}
|
||||||
|
|
||||||
time_t now = time(NULL) + fgGetLong("/sim/time/warp");
|
time_t now = time(NULL) + fgGetLong("/sim/time/warp");
|
||||||
if (scheduledAircraft.size() == 0) {
|
if (scheduledAircraft.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue