// << arr->getId() <<endl;
// }
if (prev->name == "park2")
- dep->releaseParking(fp->getGate());
-
+ {
+ dep->getDynamics()->releaseParking(fp->getGate());
+ }
+ // Some debug messages, specific to TESTING THE Logical networks.
//if ((arr->getId() == string("EHAM")) && (prev->name == "Center"))
// {
//
// Otherwise use the current aircraft position.
if (firstFlight)
{
- if (!(dep->getAvailableParking(&lat, &lon, &heading, &gateId, radius, fltType, aircraftType, airline)))
+ if (!(dep->getDynamics()->getAvailableParking(&lat, &lon,
+ &heading, &gateId,
+ radius, fltType,
+ aircraftType, airline)))
{
cerr << "Could not find parking " << endl;
}
}
else
{
- dep->getParking(gateId, &lat, &lon, &heading);
+ dep->getDynamics()->getParking(gateId, &lat, &lon, &heading);
//lat = latitude;
//lon = longitude;
//heading = getHeading();
// "NOTE: this is currently fixed to "com" for commercial traffic
// Should be changed to be used dynamically to allow "gen" and "mil"
// as well
- apt->getActiveRunway("com", 1, activeRunway);
+ apt->getDynamics()->getActiveRunway("com", 1, activeRunway);
if (!(globals->get_runways()->search(apt->getId(),
activeRunway,
&rwy)))
geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth,
rwy._length * SG_FEET_TO_METER * 0.5 - 5.0,
&lat2, &lon2, &az2 );
- if (apt->getGroundNetwork()->exists())
+ if (apt->getDynamics()->getGroundNetwork()->exists())
{
intVec ids;
- int runwayId = apt->getGroundNetwork()->findNearestNode(lat2, lon2);
+ int runwayId = apt->getDynamics()->getGroundNetwork()->findNearestNode(lat2, lon2);
//int currId = apt->getGroundNetwork()->findNearestNode(latitude,longitude);
//exit(1);
// Starting from gate 0 is a bit of a hack...
FGTaxiRoute route;
if (gateId >= 0)
- route = apt->getGroundNetwork()->findShortestRoute(gateId, runwayId);
+ route = apt->getDynamics()->getGroundNetwork()->findShortestRoute(gateId, runwayId);
else
- route = apt->getGroundNetwork()->findShortestRoute(0, runwayId);
+ route = apt->getDynamics()->getGroundNetwork()->findShortestRoute(0, runwayId);
intVecIterator i;
//cerr << "creating route : ";
// No route found: go from gate directly to runway
{
//i = ids.end()-1;
//cerr << "Creating Node: " << node << endl;
- FGTaxiNode *tn = apt->getGroundNetwork()->findNode(node);
+ FGTaxiNode *tn = apt->getDynamics()->getGroundNetwork()->findNode(node);
//ids.pop_back();
wpt = new waypoint;
wpt->name = "taxiway"; // fixme: should be the name of the taxiway
//geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth,
// rwy._length * SG_FEET_TO_METER * 0.5 - 5.0,
// &lat2, &lon2, &az2 );
- apt->getAvailableParking(&lat, &lon, &heading, &gateId, radius, fltType, acType, airline);
+ apt->getDynamics()->getAvailableParking(&lat, &lon, &heading, &gateId, radius, fltType, acType, airline);
heading += 180.0;
if (heading > 360)
heading -= 360;
double lat3 = (*(waypoints.end()-1))->latitude;
double lon3 = (*(waypoints.end()-1))->longitude;
cerr << (*(waypoints.end()-1))->name << endl;
- if (apt->getGroundNetwork()->exists())
+ if (apt->getDynamics()->getGroundNetwork()->exists())
{
intVec ids;
- int runwayId = apt->getGroundNetwork()->findNearestNode(lat3, lon3);
+ int runwayId = apt->getDynamics()->getGroundNetwork()->findNearestNode(lat3, lon3);
//int currId = apt->getGroundNetwork()->findNearestNode(latitude,longitude);
//exit(1);
// Starting from gate 0 is a bit of a hack...
FGTaxiRoute route;
if (gateId >= 0)
- route = apt->getGroundNetwork()->findShortestRoute(runwayId, gateId);
+ route = apt->getDynamics()->getGroundNetwork()->findShortestRoute(runwayId, gateId);
else
- route = apt->getGroundNetwork()->findShortestRoute(runwayId, 0);
+ route = apt->getDynamics()->getGroundNetwork()->findShortestRoute(runwayId, 0);
intVecIterator i;
//cerr << "creating route : ";
// No route found: go from gate directly to runway
{
//i = ids.end()-1;
//cerr << "Creating Node: " << node << endl;
- FGTaxiNode *tn = apt->getGroundNetwork()->findNode(node);
+ FGTaxiNode *tn = apt->getDynamics()->getGroundNetwork()->findNode(node);
//ids.pop_back();
wpt = new waypoint;
wpt->name = "taxiway"; // fixme: should be the name of the taxiway
// "NOTE: this is currently fixed to "com" for commercial traffic
// Should be changed to be used dynamically to allow "gen" and "mil"
// as well
- apt->getActiveRunway("com", 1, activeRunway);
+ apt->getDynamics()->getActiveRunway("com", 1, activeRunway);
if (!(globals->get_runways()->search(apt->getId(),
activeRunway,
&rwy)))
// "NOTE: this is currently fixed to "com" for commercial traffic
// Should be changed to be used dynamically to allow "gen" and "mil"
// as well
- apt->getActiveRunway("com", 1, activeRunway);
+ apt->getDynamics()->getActiveRunway("com", 1, activeRunway);
if (!(globals->get_runways()->search(apt->getId(),
activeRunway,
&rwy)))
//string name;
// should be changed dynamically to allow "gen" and "mil"
- arr->getActiveRunway("com", 2, activeRunway);
+ arr->getDynamics()->getActiveRunway("com", 2, activeRunway);
if (!(globals->get_runways()->search(arr->getId(),
activeRunway,
&rwy)))
//Beginning of Decent
//string name;
// allow "mil" and "gen" as well
- apt->getActiveRunway("com", 2, activeRunway);
+ apt->getDynamics()->getActiveRunway("com", 2, activeRunway);
if (!(globals->get_runways()->search(apt->getId(),
activeRunway,
&rwy)))
double lat;
double lon;
double heading;
- apt->getParking(gateId, &lat, &lon, &heading);
+ apt->getDynamics()->getParking(gateId, &lat, &lon, &heading);
heading += 180.0;
if (heading > 360)
heading -= 360;
_enroute = true;
_destID = destID;
_pos = pt;
- _destPos = dclGetAirportPos(destID); // TODO - check if we are within the tower catchment area already.
+ _destPos = fgGetAirportPos(destID); // TODO - check if we are within the tower catchment area already.
_cruise_alt = (_destPos.elev() + 2500.0) * SG_FEET_TO_METER; // TODO look at terrain elevation as well
_pos.setelev(_cruise_alt);
// initially set waypoint as airport location
slope = atan((_wp.elev() - _pos.elev()) / dclGetHorizontalSeparation(_wp, _pos)) * DCL_RADIANS_TO_DEGREES;
double thesh_offset = 0.0;
Point3D opos = ortho.ConvertToLocal(_pos);
- double angToApt = atan((_pos.elev() - dclGetAirportElev(airportID)) / (opos.y() - thesh_offset)) * DCL_RADIANS_TO_DEGREES;
+ double angToApt = atan((_pos.elev() - fgGetAirportElev(airportID)) / (opos.y() - thesh_offset)) * DCL_RADIANS_TO_DEGREES;
//cout << "angToApt = " << angToApt << ' ';
slope = (angToApt > -5.0 ? 0.0 : angToApt);
//cout << "slope = " << slope << '\n';
ConditionalTransmit(4);
}
}
- if(_pos.elev() < (dclGetAirportElev(airportID) + (1000.0 * SG_FEET_TO_METER))) slope = 0.0;
+ if(_pos.elev() < (fgGetAirportElev(airportID) + (1000.0 * SG_FEET_TO_METER))) slope = 0.0;
}
}
if(_incoming) {
Point3D orthopos = ortho.ConvertToLocal(_pos);
// TODO - Check whether to start descent
// become _local after the 3 mile report.
- if(_pos.elev() < (dclGetAirportElev(airportID) + (1000.0 * SG_FEET_TO_METER))) slope = 0.0;
+ if(_pos.elev() < (fgGetAirportElev(airportID) + (1000.0 * SG_FEET_TO_METER))) slope = 0.0;
// TODO - work out why I needed to add the above line to stop the plane going underground!!!
// (Although it's worth leaving it in as a robustness check anyway).
if(_straightIn) {
//cout << "Established at " << orthopos << '\n';
}
double thesh_offset = 30.0;
- //cout << "orthopos.y = " << orthopos.y() << " alt = " << _pos.elev() - dclGetAirportElev(airportID) << '\n';
+ //cout << "orthopos.y = " << orthopos.y() << " alt = " << _pos.elev() - fgGetAirportElev(airportID) << '\n';
if(_established && (orthopos.y() > -5400.0)) {
- slope = atan((_pos.elev() - dclGetAirportElev(airportID)) / (orthopos.y() - thesh_offset)) * DCL_RADIANS_TO_DEGREES;
+ slope = atan((_pos.elev() - fgGetAirportElev(airportID)) / (orthopos.y() - thesh_offset)) * DCL_RADIANS_TO_DEGREES;
//cout << "slope0 = " << slope << '\n';
}
//cout << "slope1 = " << slope << '\n';
if((orthopos.x() * patternDirection) > 0.0) { // 45 deg entry
tmp.setx(2000 * patternDirection);
tmp.sety((rwy.end2ortho.y() / 2.0) + 2000);
- tmp.setelev(dclGetAirportElev(airportID) + (1000 * SG_FEET_TO_METER));
+ tmp.setelev(fgGetAirportElev(airportID) + (1000 * SG_FEET_TO_METER));
_e45 = true;
//cout << "45 deg entry... ";
} else {
tmp.setx(1000 * patternDirection * -1);
tmp.sety(rwy.end2ortho.y());
- tmp.setelev(dclGetAirportElev(airportID) + (1000 * SG_FEET_TO_METER));
+ tmp.setelev(fgGetAirportElev(airportID) + (1000 * SG_FEET_TO_METER));
_e45 = false;
//cout << "90 deg entry... ";
}
} else {
tmp.setx(0);
tmp.sety(-5400);
- tmp.setelev((5400.0 / 6.0) + dclGetAirportElev(airportID) + 10.0);
+ tmp.setelev((5400.0 / 6.0) + fgGetAirportElev(airportID) + 10.0);
//cout << "Straight in... ";
}
//cout << "Waypoint is " << tmp << '\n';
_controlled = false;
}
// Get the airport elevation
- aptElev = dclGetAirportElev(airportID.c_str());
+ aptElev = fgGetAirportElev(airportID.c_str());
//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.
if(descending) {
if(orthopos.y() < -50.0) {
double thesh_offset = 30.0;
- slope = atan((_pos.elev() - dclGetAirportElev(airportID)) / (orthopos.y() - thesh_offset)) * DCL_RADIANS_TO_DEGREES;
- //cout << "slope = " << slope << ", elev = " << _pos.elev() << ", apt_elev = " << dclGetAirportElev(airportID) << ", op.y = " << orthopos.y() << '\n';
+ slope = atan((_pos.elev() - fgGetAirportElev(airportID)) / (orthopos.y() - thesh_offset)) * DCL_RADIANS_TO_DEGREES;
+ //cout << "slope = " << slope << ", elev = " << _pos.elev() << ", apt_elev = " << fgGetAirportElev(airportID) << ", op.y = " << orthopos.y() << '\n';
if(slope < -10.0) slope = -10.0;
_savedSlope = slope;
_pitch = -4.0;
#include <Main/fg_props.hxx>
#include <Main/globals.hxx>
#include <simgear/math/sg_random.h>
-
#include <list>
#ifdef _MSC_VER
ext = file.substr(pos + 1);
if(ext == "taxi") {
f_ident = file.substr(0, pos);
- FGAirport a;
- if(dclFindAirportID(f_ident, &a)) {
- SGBucket sgb(a.getLongitude(), a.getLatitude());
+ const FGAirport *a = fgFindAirportID( f_ident);
+ if(a){
+ SGBucket sgb(a->getLongitude(), a->getLatitude());
int idx = sgb.gen_index();
if(facilities.find(idx) != facilities.end()) {
facilities[idx]->push_back(f_ident);
/*
// TESTING
FGATCAlignedProjection ortho;
- ortho.Init(dclGetAirportPos("KEMT"), 205.0); // Guess of rwy19 heading
+ ortho.Init(fgGetAirportPos("KEMT"), 205.0); // Guess of rwy19 heading
//Point3D ip = ortho.ConvertFromLocal(Point3D(6000, 1000, 1000)); // 90 deg entry
//Point3D ip = ortho.ConvertFromLocal(Point3D(-7000, 3000, 1000)); // 45 deg entry
Point3D ip = ortho.ConvertFromLocal(Point3D(1000, -7000, 1000)); // straight-in
ai_activated_map_iterator apt_itr = activated.begin();
while(apt_itr != activated.end()) {
//cout << "FIRST IS " << (*apt_itr).first << '\n';
- if(dclGetHorizontalSeparation(userPos, dclGetAirportPos((*apt_itr).first)) > (35.0 * 1600.0)) {
+ if(dclGetHorizontalSeparation(userPos, fgGetAirportPos((*apt_itr).first)) > (35.0 * 1600.0)) {
// Then get rid of it and make sure the iterator is left pointing to the next one!
string s = (*apt_itr).first;
if(traffic.find(s) != traffic.end()) {
//cout << "s = " << s << " size = " << (*it).second.size() << '\n';
// Only generate extra traffic if within a certain distance of the user,
// TODO - maybe take users's tuned freq into account as well.
- double d = dclGetHorizontalSeparation(userPos, dclGetAirportPos(s));
+ double d = dclGetHorizontalSeparation(userPos, fgGetAirportPos(s));
if(d < (15.0 * 1600.0)) {
double cd = 0.0;
bool gen = false;
//cout << "Size of list is " << (*it).second.size() << " at " << s << '\n';
if((*it).second.size()) {
FGAIEntity* e = *((*it).second.rbegin()); // Get the last airplane currently scheduled to arrive at this airport.
- cd = dclGetHorizontalSeparation(e->GetPos(), dclGetAirportPos(s));
+ cd = dclGetHorizontalSeparation(e->GetPos(), fgGetAirportPos(s));
if(cd < (d < 5000 ? 10000 : d + 5000)) {
gen = true;
}
/*
// TODO - check for military airports - this should be in the current data.
// UGGH - there's no point at the moment - everything is labelled civil in basic.dat!
- FGAirport a;
- if(dclFindAirportID(ident, &a)) {
+ FGAirport a = fgFindAirportID(ident, &a);
+ if(a) {
cout << "CODE IS " << a.code << '\n';
} else {
// UG - can't find the airport!
}
*/
- Point3D aptpos = dclGetAirportPos(ident); // TODO - check for elev of -9999
+ Point3D aptpos = fgGetAirportPos(ident); // TODO - check for elev of -9999
//cout << "ident = " << ident << ", elev = " << aptpos.elev() << '\n';
// Operate from airports at 3000ft and below only to avoid the default cloud layers and since we don't degrade AI performance with altitude.
for(twd_itr = towered.begin(); twd_itr != towered.end(); twd_itr++) {
// Only activate the closest airport not already activated each time.
if(activated.find(twd_itr->ident) == activated.end()) {
- double sep = dclGetHorizontalSeparation(Point3D(lon, lat, elev), dclGetAirportPos(twd_itr->ident));
+ double sep = dclGetHorizontalSeparation(Point3D(lon, lat, elev), fgGetAirportPos(twd_itr->ident));
if(sep < closest) {
closest = sep;
s = twd_itr->ident;
atcUppercase(ident);
string label;
- FGAirport a;
- if (!dclFindAirportID(ident, &a)) {
+ const FGAirport *a = fgFindAirportID(ident);
+ if (!a) {
label = "Airport " + ident + " not found in database.";
mkDialog(label.c_str());
return;
int n = 0; // Number of ATC frequencies at this airport
comm_list_type stations;
- int found = current_commlist->FindByPos(a.getLongitude(), a.getLatitude(), a.getElevation(), 20.0, &stations);
+ int found = current_commlist->FindByPos(a->getLongitude(), a->getLatitude(), a->getElevation(), 20.0, &stations);
if(found) {
ostringstream ostr;
comm_list_iterator itr = stations.begin();
#include <simgear/misc/sg_path.hxx>
#include <simgear/debug/logstream.hxx>
#include <Airports/simple.hxx>
-
#include "ATCmgr.hxx"
#include "commlist.hxx"
#include "ATCdisplay.hxx"
airport_atc_map[ident]->numAI++;
return(true);
} else {
- FGAirport ap;
- if(dclFindAirportID(ident, &ap)) {
+ const FGAirport *ap = fgFindAirportID(ident);
+ if (ap) {
//cout << "ident = " << ident << '\n';
AirportATC *a = new AirportATC;
// I'm not entirely sure that this AirportATC structure business is actually needed - it just duplicates what we can find out anyway!
- a->lon = ap.getLongitude();
- a->lat = ap.getLatitude();
- a->elev = ap.getElevation();
+ a->lon = ap->getLongitude();
+ a->lat = ap->getLatitude();
+ a->elev = ap->getElevation();
a->atis_freq = GetFrequency(ident, ATIS);
//cout << "ATIS freq = " << a->atis_freq << '\n';
a->atis_active = false;
return(true);
} else {
//cout << "NOT IN MAP - creating new..." << endl;
- FGAirport ap;
- if(dclFindAirportID(ident, &ap)) {
+ const FGAirport *ap = fgFindAirportID(ident);
+ if (ap) {
AirportATC *a = new AirportATC;
// I'm not entirely sure that this AirportATC structure business is actually needed - it just duplicates what we can find out anyway!
- a->lon = ap.getLongitude();
- a->lat = ap.getLatitude();
- a->elev = ap.getElevation();
+ a->lon = ap->getLongitude();
+ a->lat = ap->getLatitude();
+ a->elev = ap->getElevation();
a->atis_freq = GetFrequency(ident, ATIS);
a->atis_active = false;
a->tower_freq = GetFrequency(ident, TOWER);
return a3;
}
-//================================================================================================================
-
-// Airport stuff. The next two functions are straight copies of their fg.... equivalents
-// in fg_init.cxx, and are just here temporarily until some rationalisation occurs.
-// find basic airport location info from airport database
-bool dclFindAirportID( const string& id, FGAirport *a ) {
- const FGAirport* result;
-
- if ( id.length() ) {
- SG_LOG( SG_GENERAL, SG_INFO, "Searching for airport code = " << id );
-
- result = globals->get_airports()->search(id);
- if ( result == NULL ) {
- SG_LOG( SG_GENERAL, SG_WARN,
- "Failed to find " << id << " in apt.dat.gz" );
- return false;
- }
- } else {
- return false;
- }
-
- *a = *result;
-
- SG_LOG( SG_GENERAL, SG_INFO,
- "Position for " << id << " is ("
- << a->getLongitude() << ", "
- << a->getLatitude() << ")" );
-
- return true;
-}
-
-// get airport elevation
-double dclGetAirportElev( const string& id ) {
- FGAirport a;
- // double lon, lat;
-
- SG_LOG( SG_ATC, SG_INFO,
- "Finding elevation for airport: " << id );
-
- if ( dclFindAirportID( id, &a ) ) {
- return a.getElevation() * SG_FEET_TO_METER;
- } else {
- return -9999.0;
- }
-}
-
-// get airport position
-Point3D dclGetAirportPos( const string& id ) {
- FGAirport a;
- // double lon, lat;
-
- SG_LOG( SG_ATC, SG_INFO,
- "Finding position for airport: " << id );
-
- if ( dclFindAirportID( id, &a ) ) {
- return Point3D(a.getLongitude(), a.getLatitude(), a.getElevation());
- } else {
- return Point3D(0.0, 0.0, -9999.0);
- }
-}
-
// Runway stuff
// Given a Point3D (lon/lat/elev) and an FGRunway struct, determine if the point lies on the runway
bool OnRunway(const Point3D& pt, const FGRunway& rwy) {
// difference is negative if a1 > a2 and positive if a2 > a1
double GetAngleDiff_deg( const double &a1, const double &a2);
-
-/*******************************
-*
-* Airport-related functions
-*
-********************************/
-
-// The next two functions are straight copies of their fg.... equivalents
-// in fg_init.cxx, and are just here temporarily until some rationalisation occurs.
-
-// find basic airport location info from airport database
-bool dclFindAirportID( const string& id, FGAirport *a );
-
-// get airport elevation IN METERS
-double dclGetAirportElev( const string& id );
-
-// get airport position (elev portion in FEET)
-Point3D dclGetAirportPos( const string& id );
-
/****************
*
* Runways
ATCData ad2 = *itr;
//Point3D p1(*itr.lon, *itr.lat, *itr.elev);
Point3D p1(ad2.lon, ad2.lat, ad2.elev);
- FGAirport a;
- if(dclFindAirportID(ad2.ident, &a)) {
+ const FGAirport *a = fgFindAirportID(ad2.ident);
+ if (a) {
Point3D p2(lon, lat, elev);
tmp = dclGetHorizontalSeparation(p1, p2);
if(tmp <= closest) {
// This is basically a wrapper for a call to the airport database to get the airport
// position followed by a call to FindByPos(...)
bool FGCommList::FindByCode( const string& ICAO, ATCData& ad, atc_type tp ) {
- FGAirport a;
- if ( dclFindAirportID( ICAO, &a ) ) {
+ const FGAirport *a = fgFindAirportID( ICAO);
+ if ( a) {
comm_list_type stations;
- int found = FindByPos(a.getLongitude(), a.getLatitude(), a.getElevation(), 10.0, &stations, tp);
+ int found = FindByPos(a->getLongitude(), a->getLatitude(), a->getElevation(), 10.0, &stations, tp);
if(found) {
comm_list_iterator itr = stations.begin();
while(itr != stations.end()) {
// TODO - attempt to get a departure control pointer to see if we need to hand off departing traffic to departure.
// Get the airport elevation
- aptElev = dclGetAirportElev(ident.c_str());
+ aptElev = fgGetAirportElev(ident.c_str());
// TODO - this function only assumes one active rwy.
DoRwyDetails();
libAirports_a_SOURCES = \
apt_loader.cxx apt_loader.hxx \
runways.cxx runways.hxx \
- simple.cxx simple.hxx
+ simple.cxx simple.hxx \
+ runwayprefs.cxx runwayprefs.hxx \
+ parking.cxx parking.hxx \
+ groundnetwork.cxx groundnetwork.hxx \
+ dynamics.cxx dynamics.hxx
calc_loc_SOURCES = calc_loc.cxx
calc_loc_LDADD = -lsgmath -lsgdebug -lsgmisc -lz $(base_LIBS)
--- /dev/null
+// dynamics.cxx - Code to manage the higher order airport ground activities
+// Written by Durk Talsma, started December 2004.
+//
+//
+// 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
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+// $Id$
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef _MSC_VER
+# define _USE_MATH_DEFINES
+#endif
+//#include <math.h>
+#include <algorithm>
+
+#include <simgear/compiler.h>
+
+#include <plib/sg.h>
+#include <plib/ul.h>
+
+#include <Environment/environment_mgr.hxx>
+#include <Environment/environment.hxx>
+#include <simgear/misc/sg_path.hxx>
+#include <simgear/props/props.hxx>
+#include <simgear/structure/subsystem_mgr.hxx>
+#include <simgear/debug/logstream.hxx>
+#include <simgear/route/waypoint.hxx>
+#include <Main/globals.hxx>
+#include <Main/fg_props.hxx>
+#include <Airports/runways.hxx>
+#include <simgear/xml/easyxml.hxx>
+
+#include STL_STRING
+#include <vector>
+
+SG_USING_STD(string);
+SG_USING_STD(vector);
+SG_USING_STD(sort);
+SG_USING_STD(random_shuffle);
+
+#include "parking.hxx"
+#include "groundnetwork.hxx"
+#include "runwayprefs.hxx"
+#include "dynamics.hxx"
+
+/********** FGAirport Dynamics *********************************************/
+
+FGAirportDynamics::FGAirportDynamics(double lat, double lon, double elev, string id) :
+ _latitude(lat),
+ _longitude(lon),
+ _elevation(elev),
+ _id(id)
+{
+ lastUpdate = 0;
+ for (int i = 0; i < 10; i++)
+ {
+ avWindHeading [i] = 0;
+ avWindSpeed [i] = 0;
+ }
+}
+
+
+// Note that the ground network should also be copied
+FGAirportDynamics::FGAirportDynamics(const FGAirportDynamics& other)
+{
+ for (FGParkingVecConstIterator ip= other.parkings.begin(); ip != other.parkings.end(); ip++)
+ parkings.push_back(*(ip));
+ rwyPrefs = other.rwyPrefs;
+ lastUpdate = other.lastUpdate;
+
+ stringVecConstIterator il;
+ for (il = other.landing.begin(); il != other.landing.end(); il++)
+ landing.push_back(*il);
+ for (il = other.takeoff.begin(); il != other.takeoff.end(); il++)
+ takeoff.push_back(*il);
+ lastUpdate = other.lastUpdate;
+ for (int i = 0; i < 10; i++)
+ {
+ avWindHeading [i] = other.avWindHeading[i];
+ avWindSpeed [i] = other.avWindSpeed [i];
+ }
+}
+
+// Destructor
+FGAirportDynamics::~FGAirportDynamics()
+{
+
+}
+
+
+// Initialization required after XMLRead
+void FGAirportDynamics::init()
+{
+ // This may seem a bit weird to first randomly shuffle the parkings
+ // and then sort them again. However, parkings are sorted here by ascending
+ // radius. Since many parkings have similar radii, with each radius class they will
+ // still be allocated relatively systematically. Randomizing prior to sorting will
+ // prevent any initial orderings to be destroyed, leading (hopefully) to a more
+ // naturalistic gate assignment.
+ random_shuffle(parkings.begin(), parkings.end());
+ sort(parkings.begin(), parkings.end());
+ // add the gate positions to the ground network.
+ groundNetwork.addNodes(&parkings);
+ groundNetwork.init();
+}
+
+bool FGAirportDynamics::getAvailableParking(double *lat, double *lon, double *heading, int *gateId, double rad, const string &flType, const string &acType, const string &airline)
+{
+ bool found = false;
+ bool available = false;
+ //string gateType;
+
+ FGParkingVecIterator i;
+// if (flType == "cargo")
+// {
+// gateType = "RAMP_CARGO";
+// }
+// else if (flType == "ga")
+// {
+// gateType = "RAMP_GA";
+// }
+// else gateType = "GATE";
+
+ if (parkings.begin() == parkings.end())
+ {
+ //cerr << "Could not find parking spot at " << _id << endl;
+ *lat = _latitude;
+ *lon = _longitude;
+ *heading = 0;
+ found = true;
+ }
+ else
+ {
+ // First try finding a parking with a designated airline code
+ for (i = parkings.begin(); !(i == parkings.end() || found); i++)
+ {
+ //cerr << "Gate Id: " << i->getIndex()
+ // << " Type : " << i->getType()
+ // << " Codes : " << i->getCodes()
+ // << " Radius: " << i->getRadius()
+ // << " Name : " << i->getName()
+ // << " Available: " << i->isAvailable() << endl;
+ available = true;
+ // Taken by another aircraft
+ if (!(i->isAvailable()))
+ {
+ available = false;
+ continue;
+ }
+ // No airline codes, so skip
+ if (i->getCodes().empty())
+ {
+ available = false;
+ continue;
+ }
+ else // Airline code doesn't match
+ if (i->getCodes().find(airline, 0) == string::npos)
+ {
+ available = false;
+ continue;
+ }
+ // Type doesn't match
+ if (i->getType() != flType)
+ {
+ available = false;
+ continue;
+ }
+ // too small
+ if (i->getRadius() < rad)
+ {
+ available = false;
+ continue;
+ }
+
+ if (available)
+ {
+ *lat = i->getLatitude ();
+ *lon = i->getLongitude();
+ *heading = i->getHeading ();
+ *gateId = i->getIndex ();
+ i->setAvailable(false);
+ found = true;
+ }
+ }
+ // then try again for those without codes.
+ for (i = parkings.begin(); !(i == parkings.end() || found); i++)
+ {
+ available = true;
+ if (!(i->isAvailable()))
+ {
+ available = false;
+ continue;
+ }
+ if (!(i->getCodes().empty()))
+ {
+ if ((i->getCodes().find(airline,0) == string::npos))
+ {
+ available = false;
+ continue;
+ }
+ }
+ if (i->getType() != flType)
+ {
+ available = false;
+ continue;
+ }
+
+ if (i->getRadius() < rad)
+ {
+ available = false;
+ continue;
+ }
+
+ if (available)
+ {
+ *lat = i->getLatitude ();
+ *lon = i->getLongitude();
+ *heading = i->getHeading ();
+ *gateId = i->getIndex ();
+ i->setAvailable(false);
+ found = true;
+ }
+ }
+ // And finally once more if that didn't work. Now ignore the airline codes, as a last resort
+ for (i = parkings.begin(); !(i == parkings.end() || found); i++)
+ {
+ available = true;
+ if (!(i->isAvailable()))
+ {
+ available = false;
+ continue;
+ }
+ if (i->getType() != flType)
+ {
+ available = false;
+ continue;
+ }
+
+ if (i->getRadius() < rad)
+ {
+ available = false;
+ continue;
+ }
+
+ if (available)
+ {
+ *lat = i->getLatitude ();
+ *lon = i->getLongitude();
+ *heading = i->getHeading ();
+ *gateId = i->getIndex ();
+ i->setAvailable(false);
+ found = true;
+ }
+ }
+ }
+ if (!found)
+ {
+ //cerr << "Traffic overflow at" << _id
+ // << ". flType = " << flType
+ // << ". airline = " << airline
+ // << " Radius = " <<rad
+ // << endl;
+ *lat = _latitude;
+ *lon = _longitude;
+ *heading = 0;
+ *gateId = -1;
+ //exit(1);
+ }
+ return found;
+}
+
+void FGAirportDynamics::getParking (int id, double *lat, double* lon, double *heading)
+{
+ if (id < 0)
+ {
+ *lat = _latitude;
+ *lon = _longitude;
+ *heading = 0;
+ }
+ else
+ {
+ FGParkingVecIterator i = parkings.begin();
+ for (i = parkings.begin(); i != parkings.end(); i++)
+ {
+ if (id == i->getIndex())
+ {
+ *lat = i->getLatitude();
+ *lon = i->getLongitude();
+ *heading = i->getLongitude();
+ }
+ }
+ }
+}
+
+FGParking *FGAirportDynamics::getParking(int i)
+{
+ if (i < (int)parkings.size())
+ return &(parkings[i]);
+ else
+ return 0;
+}
+string FGAirportDynamics::getParkingName(int i)
+{
+ if (i < (int)parkings.size() && i >= 0)
+ return (parkings[i].getName());
+ else
+ return string("overflow");
+}
+void FGAirportDynamics::releaseParking(int id)
+{
+ if (id >= 0)
+ {
+
+ FGParkingVecIterator i = parkings.begin();
+ for (i = parkings.begin(); i != parkings.end(); i++)
+ {
+ if (id == i->getIndex())
+ {
+ i -> setAvailable(true);
+ }
+ }
+ }
+}
+
+void FGAirportDynamics::startXML () {
+ //cout << "Start XML" << endl;
+}
+
+void FGAirportDynamics::endXML () {
+ //cout << "End XML" << endl;
+}
+
+void FGAirportDynamics::startElement (const char * name, const XMLAttributes &atts) {
+ // const char *attval;
+ FGParking park;
+ FGTaxiNode taxiNode;
+ FGTaxiSegment taxiSegment;
+ int index = 0;
+ taxiSegment.setIndex(index);
+ //cout << "Start element " << name << endl;
+ string attname;
+ string value;
+ string gateName;
+ string gateNumber;
+ string lat;
+ string lon;
+ if (name == string("Parking"))
+ {
+ for (int i = 0; i < atts.size(); i++)
+ {
+ //cout << " " << atts.getName(i) << '=' << atts.getValue(i) << endl;
+ attname = atts.getName(i);
+ if (attname == string("index"))
+ park.setIndex(atoi(atts.getValue(i)));
+ else if (attname == string("type"))
+ park.setType(atts.getValue(i));
+ else if (attname == string("name"))
+ gateName = atts.getValue(i);
+ else if (attname == string("number"))
+ gateNumber = atts.getValue(i);
+ else if (attname == string("lat"))
+ park.setLatitude(atts.getValue(i));
+ else if (attname == string("lon"))
+ park.setLongitude(atts.getValue(i));
+ else if (attname == string("heading"))
+ park.setHeading(atof(atts.getValue(i)));
+ else if (attname == string("radius")) {
+ string radius = atts.getValue(i);
+ if (radius.find("M") != string::npos)
+ radius = radius.substr(0, radius.find("M",0));
+ //cerr << "Radius " << radius <<endl;
+ park.setRadius(atof(radius.c_str()));
+ }
+ else if (attname == string("airlineCodes"))
+ park.setCodes(atts.getValue(i));
+ }
+ park.setName((gateName+gateNumber));
+ parkings.push_back(park);
+ }
+ if (name == string("node"))
+ {
+ for (int i = 0; i < atts.size() ; i++)
+ {
+ attname = atts.getName(i);
+ if (attname == string("index"))
+ taxiNode.setIndex(atoi(atts.getValue(i)));
+ if (attname == string("lat"))
+ taxiNode.setLatitude(atts.getValue(i));
+ if (attname == string("lon"))
+ taxiNode.setLongitude(atts.getValue(i));
+ }
+ groundNetwork.addNode(taxiNode);
+ }
+ if (name == string("arc"))
+ {
+ taxiSegment.setIndex(++index);
+ for (int i = 0; i < atts.size() ; i++)
+ {
+ attname = atts.getName(i);
+ if (attname == string("begin"))
+ taxiSegment.setStartNodeRef(atoi(atts.getValue(i)));
+ if (attname == string("end"))
+ taxiSegment.setEndNodeRef(atoi(atts.getValue(i)));
+ }
+ groundNetwork.addSegment(taxiSegment);
+ }
+ // sort by radius, in asending order, so that smaller gates are first in the list
+}
+
+void FGAirportDynamics::endElement (const char * name) {
+ //cout << "End element " << name << endl;
+
+}
+
+void FGAirportDynamics::data (const char * s, int len) {
+ string token = string(s,len);
+ //cout << "Character data " << string(s,len) << endl;
+ //if ((token.find(" ") == string::npos && (token.find('\n')) == string::npos))
+ //value += token;
+ //else
+ //value = string("");
+}
+
+void FGAirportDynamics::pi (const char * target, const char * data) {
+ //cout << "Processing instruction " << target << ' ' << data << endl;
+}
+
+void FGAirportDynamics::warning (const char * message, int line, int column) {
+ cout << "Warning: " << message << " (" << line << ',' << column << ')'
+ << endl;
+}
+
+void FGAirportDynamics::error (const char * message, int line, int column) {
+ cout << "Error: " << message << " (" << line << ',' << column << ')'
+ << endl;
+}
+
+void FGAirportDynamics::setRwyUse(const FGRunwayPreference& ref)
+{
+ rwyPrefs = ref;
+ //cerr << "Exiting due to not implemented yet" << endl;
+ //exit(1);
+}
+void FGAirportDynamics::getActiveRunway(const string &trafficType, int action, string &runway)
+{
+ double windSpeed;
+ double windHeading;
+ double maxTail;
+ double maxCross;
+ string name;
+ string type;
+
+ if (!(rwyPrefs.available()))
+ {
+ runway = chooseRunwayFallback();
+ return; // generic fall back goes here
+ }
+ else
+ {
+ RunwayGroup *currRunwayGroup = 0;
+ int nrActiveRunways = 0;
+ time_t dayStart = fgGetLong("/sim/time/utc/day-seconds");
+ if (((dayStart - lastUpdate) > 600) || trafficType != prevTrafficType)
+ {
+ landing.clear();
+ takeoff.clear();
+ //lastUpdate = dayStart;
+ prevTrafficType = trafficType;
+
+ FGEnvironment
+ stationweather = ((FGEnvironmentMgr *) globals->get_subsystem("environment"))
+ ->getEnvironment(getLatitude(),
+ getLongitude(),
+ getElevation());
+
+ windSpeed = stationweather.get_wind_speed_kt();
+ windHeading = stationweather.get_wind_from_heading_deg();
+ double averageWindSpeed = 0;
+ double averageWindHeading = 0;
+ double cosHeading = 0;
+ double sinHeading = 0;
+ // Initialize at the beginning of the next day or startup
+ if ((lastUpdate == 0) || (dayStart < lastUpdate))
+ {
+ for (int i = 0; i < 10; i++)
+ {
+ avWindHeading [i] = windHeading;
+ avWindSpeed [i] = windSpeed;
+ }
+ }
+ else
+ {
+ if (windSpeed != avWindSpeed[9]) // update if new metar data
+ {
+ // shift the running average
+ for (int i = 0; i < 9 ; i++)
+ {
+ avWindHeading[i] = avWindHeading[i+1];
+ avWindSpeed [i] = avWindSpeed [i+1];
+ }
+ }
+ avWindHeading[9] = windHeading;
+ avWindSpeed [9] = windSpeed;
+ }
+
+ for (int i = 0; i < 10; i++)
+ {
+ averageWindSpeed += avWindSpeed [i];
+ //averageWindHeading += avWindHeading [i];
+ cosHeading += cos(avWindHeading[i] * SG_DEGREES_TO_RADIANS);
+ sinHeading += sin(avWindHeading[i] * SG_DEGREES_TO_RADIANS);
+ }
+ averageWindSpeed /= 10;
+ //averageWindHeading /= 10;
+ cosHeading /= 10;
+ sinHeading /= 10;
+ averageWindHeading = atan2(sinHeading, cosHeading) *SG_RADIANS_TO_DEGREES;
+ if (averageWindHeading < 0)
+ averageWindHeading += 360.0;
+ //cerr << "Wind Heading " << windHeading << " average " << averageWindHeading << endl;
+ //cerr << "Wind Speed " << windSpeed << " average " << averageWindSpeed << endl;
+ lastUpdate = dayStart;
+ //if (wind_speed == 0) {
+ // wind_heading = 270; This forces West-facing rwys to be used in no-wind situations
+ // which is consistent with Flightgear's initial setup.
+ //}
+
+ //string rwy_no = globals->get_runways()->search(apt->getId(), int(wind_heading));
+ string scheduleName;
+ //cerr << "finding active Runway for" << _id << endl;
+ //cerr << "Nr of seconds since day start << " << dayStart << endl;
+ ScheduleTime *currSched;
+ //cerr << "A"<< endl;
+ currSched = rwyPrefs.getSchedule(trafficType.c_str());
+ if (!(currSched))
+ return;
+ //cerr << "B"<< endl;
+ scheduleName = currSched->getName(dayStart);
+ maxTail = currSched->getTailWind ();
+ maxCross = currSched->getCrossWind ();
+ //cerr << "SChedule anme = " << scheduleName << endl;
+ if (scheduleName.empty())
+ return;
+ //cerr << "C"<< endl;
+ currRunwayGroup = rwyPrefs.getGroup(scheduleName);
+ //cerr << "D"<< endl;
+ if (!(currRunwayGroup))
+ return;
+ nrActiveRunways = currRunwayGroup->getNrActiveRunways();
+ //cerr << "Nr of Active Runways = " << nrActiveRunways << endl;
+ currRunwayGroup->setActive(_id, averageWindSpeed, averageWindHeading, maxTail, maxCross);
+ nrActiveRunways = currRunwayGroup->getNrActiveRunways();
+ for (int i = 0; i < nrActiveRunways; i++)
+ {
+ type = "unknown"; // initialize to something other than landing or takeoff
+ currRunwayGroup->getActive(i, name, type);
+ if (type == "landing")
+ {
+ landing.push_back(name);
+ //cerr << "Landing " << name << endl;
+ }
+ if (type == "takeoff")
+ {
+ takeoff.push_back(name);
+ //cerr << "takeoff " << name << endl;
+ }
+ }
+ }
+ if (action == 1) // takeoff
+ {
+ int nr = takeoff.size();
+ if (nr)
+ {
+ runway = takeoff[(rand() % nr)];
+ }
+ else
+ { // Fallback
+ runway = chooseRunwayFallback();
+ }
+ }
+ if (action == 2) // landing
+ {
+ int nr = landing.size();
+ if (nr)
+ {
+ runway = landing[(rand() % nr)];
+ }
+ else
+ { //fallback
+ runway = chooseRunwayFallback();
+ }
+ }
+
+ //runway = globals->get_runways()->search(_id, int(windHeading));
+ //cerr << "Seleceted runway: " << runway << endl;
+ }
+}
+
+string FGAirportDynamics::chooseRunwayFallback()
+{
+ FGEnvironment
+ stationweather = ((FGEnvironmentMgr *) globals->get_subsystem("environment"))
+ ->getEnvironment(getLatitude(),
+ getLongitude(),
+ getElevation());
+
+ double windSpeed = stationweather.get_wind_speed_kt();
+ double windHeading = stationweather.get_wind_from_heading_deg();
+ if (windSpeed == 0) {
+ windHeading = 270; // This forces West-facing rwys to be used in no-wind situations
+ //which is consistent with Flightgear's initial setup.
+ }
+
+ return globals->get_runways()->search(_id, int(windHeading));
+}
--- /dev/null
+// dynamics.hxx - a class to manage the higher order airport ground activities
+// Written by Durk Talsma, started December 2004.
+//
+//
+// 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
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+// $Id$
+
+
+#ifndef _AIRPORT_DYNAMICS_HXX_
+#define _AIRPORT_DYNAMICS_HXX_
+
+
+#ifndef __cplusplus
+# error This library requires C++
+#endif
+
+
+
+class FGAirportDynamics : public XMLVisitor {
+
+private:
+ double _longitude; // degrees
+ double _latitude; // degrees
+ double _elevation; // ft
+ string _id;
+
+ FGParkingVec parkings;
+ FGRunwayPreference rwyPrefs;
+ FGGroundNetwork groundNetwork;
+
+ time_t lastUpdate;
+ string prevTrafficType;
+ stringVec landing;
+ stringVec takeoff;
+
+ // Experimental keep a running average of wind dir and speed to prevent
+ // Erratic runway changes.
+ // Note: I should add these to the copy constructor and assigment operator to be
+ // constistent
+ double avWindHeading [10];
+ double avWindSpeed [10];
+
+ string chooseRunwayFallback();
+
+public:
+ FGAirportDynamics(double, double, double, string);
+ FGAirportDynamics(const FGAirportDynamics &other);
+ ~FGAirportDynamics();
+
+
+ void init();
+ double getLongitude() const { return _longitude;};
+ // Returns degrees
+ double getLatitude() const { return _latitude; };
+ // Returns ft
+ double getElevation() const { return _elevation;};
+
+ void getActiveRunway(const string& trafficType, int action, string& runway);
+ bool getAvailableParking(double *lat, double *lon,
+ double *heading, int *gate, double rad, const string& fltype,
+ const string& acType, const string& airline);
+ void getParking (int id, double *lat, double* lon, double *heading);
+ FGParking *getParking(int i);
+ void releaseParking(int id);
+ string getParkingName(int i);
+ //FGAirport *getAddress() { return this; };
+ //const string &getName() const { return _name;};
+ // Returns degrees
+
+ FGGroundNetwork* getGroundNetwork() { return &groundNetwork; };
+
+
+ void setRwyUse(const FGRunwayPreference& ref);
+
+ // Some overloaded virtual XMLVisitor members
+ virtual void startXML ();
+ virtual void endXML ();
+ virtual void startElement (const char * name, const XMLAttributes &atts);
+ virtual void endElement (const char * name);
+ virtual void data (const char * s, int len);
+ virtual void pi (const char * target, const char * data);
+ virtual void warning (const char * message, int line, int column);
+ virtual void error (const char * message, int line, int column);
+};
+
+
+
+#endif
--- /dev/null
+// groundnet.cxx - Implimentation of the FlightGear airport ground handling code
+//
+// Written by Durk Talsma, started June 2005.
+//
+// Copyright (C) 2004 Durk Talsma.
+//
+// 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
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+// $Id$
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef _MSC_VER
+# define _USE_MATH_DEFINES
+#endif
+#include <math.h>
+#include <algorithm>
+
+#include <simgear/compiler.h>
+
+//#include <plib/sg.h>
+//#include <plib/ul.h>
+
+//#include <Environment/environment_mgr.hxx>
+//#include <Environment/environment.hxx>
+//#include <simgear/misc/sg_path.hxx>
+//#include <simgear/props/props.hxx>
+//#include <simgear/structure/subsystem_mgr.hxx>
+#include <simgear/debug/logstream.hxx>
+#include <simgear/route/waypoint.hxx>
+//#include <Main/globals.hxx>
+//#include <Main/fg_props.hxx>
+//#include <Airports/runways.hxx>
+
+//#include STL_STRING
+
+#include "groundnetwork.hxx"
+
+SG_USING_STD(sort);
+
+/**************************************************************************
+ * FGTaxiNode
+ *************************************************************************/
+FGTaxiNode::FGTaxiNode()
+{
+}
+
+/***************************************************************************
+ * FGTaxiSegment
+ **************************************************************************/
+FGTaxiSegment::FGTaxiSegment()
+{
+}
+
+void FGTaxiSegment::setStart(FGTaxiNodeVector *nodes)
+{
+ FGTaxiNodeVectorIterator i = nodes->begin();
+ while (i != nodes->end())
+ {
+ if (i->getIndex() == startNode)
+ {
+ start = i->getAddress();
+ i->addSegment(this);
+ return;
+ }
+ i++;
+ }
+}
+
+void FGTaxiSegment::setEnd(FGTaxiNodeVector *nodes)
+{
+ FGTaxiNodeVectorIterator i = nodes->begin();
+ while (i != nodes->end())
+ {
+ if (i->getIndex() == endNode)
+ {
+ end = i->getAddress();
+ return;
+ }
+ i++;
+ }
+}
+
+// There is probably a computationally cheaper way of
+// doing this.
+void FGTaxiSegment::setTrackDistance()
+{
+ double course;
+ SGWayPoint first (start->getLongitude(),
+ start->getLatitude(),
+ 0);
+ SGWayPoint second (end->getLongitude(),
+ end->getLatitude(),
+ 0);
+ first.CourseAndDistance(second, &course, &length);
+
+}
+
+bool FGTaxiRoute::next(int *val)
+{
+ //for (intVecIterator i = nodes.begin(); i != nodes.end(); i++)
+ // cerr << "FGTaxiRoute contains : " << *(i) << endl;
+ //cerr << "Offset from end: " << nodes.end() - currNode << endl;
+ //if (currNode != nodes.end())
+ // cerr << "true" << endl;
+ //else
+ // cerr << "false" << endl;
+
+ if (currNode == nodes.end())
+ return false;
+ *val = *(currNode);
+ currNode++;
+ return true;
+};
+/***************************************************************************
+ * FGGroundNetwork()
+ **************************************************************************/
+
+FGGroundNetwork::FGGroundNetwork()
+{
+ hasNetwork = false;
+ foundRoute = false;
+ totalDistance = 0;
+ maxDistance = 0;
+}
+
+void FGGroundNetwork::addSegment(const FGTaxiSegment &seg)
+{
+ segments.push_back(seg);
+}
+
+void FGGroundNetwork::addNode(const FGTaxiNode &node)
+{
+ nodes.push_back(node);
+}
+
+void FGGroundNetwork::addNodes(FGParkingVec *parkings)
+{
+ FGTaxiNode n;
+ FGParkingVecIterator i = parkings->begin();
+ while (i != parkings->end())
+ {
+ n.setIndex(i->getIndex());
+ n.setLatitude(i->getLatitude());
+ n.setLongitude(i->getLongitude());
+ nodes.push_back(n);
+
+ i++;
+ }
+}
+
+
+
+void FGGroundNetwork::init()
+{
+ hasNetwork = true;
+ FGTaxiSegmentVectorIterator i = segments.begin();
+ while(i != segments.end()) {
+ //cerr << "initializing node " << i->getIndex() << endl;
+ i->setStart(&nodes);
+ i->setEnd (&nodes);
+ i->setTrackDistance();
+ //cerr << "Track distance = " << i->getLength() << endl;
+ //cerr << "Track ends at" << i->getEnd()->getIndex() << endl;
+ i++;
+ }
+ //exit(1);
+}
+
+int FGGroundNetwork::findNearestNode(double lat, double lon)
+{
+ double minDist = HUGE_VAL;
+ double course, dist;
+ int index;
+ SGWayPoint first (lon,
+ lat,
+ 0);
+
+ for (FGTaxiNodeVectorIterator
+ itr = nodes.begin();
+ itr != nodes.end(); itr++)
+ {
+ double course;
+ SGWayPoint second (itr->getLongitude(),
+ itr->getLatitude(),
+ 0);
+ first.CourseAndDistance(second, &course, &dist);
+ if (dist < minDist)
+ {
+ minDist = dist;
+ index = itr->getIndex();
+ //cerr << "Minimum distance of " << minDist << " for index " << index << endl;
+ }
+ }
+ return index;
+}
+
+FGTaxiNode *FGGroundNetwork::findNode(int idx)
+{
+ for (FGTaxiNodeVectorIterator
+ itr = nodes.begin();
+ itr != nodes.end(); itr++)
+ {
+ if (itr->getIndex() == idx)
+ return itr->getAddress();
+ }
+ return 0;
+}
+
+FGTaxiRoute FGGroundNetwork::findShortestRoute(int start, int end)
+{
+ foundRoute = false;
+ totalDistance = 0;
+ FGTaxiNode *firstNode = findNode(start);
+ FGTaxiNode *lastNode = findNode(end);
+ //prevNode = prevPrevNode = -1;
+ //prevNode = start;
+ routes.clear();
+ traceStack.clear();
+ trace(firstNode, end, 0, 0);
+ FGTaxiRoute empty;
+
+ if (!foundRoute)
+ {
+ SG_LOG( SG_GENERAL, SG_INFO, "Failed to find route from waypoint " << start << " to " << end );
+ exit(1);
+ }
+ sort(routes.begin(), routes.end());
+ //for (intVecIterator i = route.begin(); i != route.end(); i++)
+ // {
+ // rte->push_back(*i);
+ // }
+
+ if (routes.begin() != routes.end())
+ return *(routes.begin());
+ else
+ return empty;
+}
+
+
+void FGGroundNetwork::trace(FGTaxiNode *currNode, int end, int depth, double distance)
+{
+ traceStack.push_back(currNode->getIndex());
+ totalDistance += distance;
+ //cerr << "Starting trace " << depth << " total distance: " << totalDistance<< endl;
+ //<< currNode->getIndex() << endl;
+
+ // If the current route matches the required end point we found a valid route
+ // So we can add this to the routing table
+ if (currNode->getIndex() == end)
+ {
+ //cerr << "Found route : " << totalDistance << "" << " " << *(traceStack.end()-1) << endl;
+ routes.push_back(FGTaxiRoute(traceStack,totalDistance));
+ traceStack.pop_back();
+ if (!(foundRoute))
+ maxDistance = totalDistance;
+ else
+ if (totalDistance < maxDistance)
+ maxDistance = totalDistance;
+ foundRoute = true;
+ totalDistance -= distance;
+ return;
+ }
+
+
+ // search if the currentNode has been encountered before
+ // if so, we should step back one level, because it is
+ // rather rediculous to proceed further from here.
+ // if the current node has not been encountered before,
+ // i should point to traceStack.end()-1; and we can continue
+ // if i is not traceStack.end, the previous node was found,
+ // and we should return.
+ // This only works at trace levels of 1 or higher though
+ if (depth > 0) {
+ intVecIterator i = traceStack.begin();
+ while ((*i) != currNode->getIndex()) {
+ //cerr << "Route so far : " << (*i) << endl;
+ i++;
+ }
+ if (i != traceStack.end()-1) {
+ traceStack.pop_back();
+ totalDistance -= distance;
+ return;
+ }
+ // If the total distance from start to the current waypoint
+ // is longer than that of a route we can also stop this trace
+ // and go back one level.
+ if ((totalDistance > maxDistance) && foundRoute)
+ {
+ //cerr << "Stopping rediculously long trace: " << totalDistance << endl;
+ traceStack.pop_back();
+ totalDistance -= distance;
+ return;
+ }
+ }
+
+ //cerr << "2" << endl;
+ if (currNode->getBeginRoute() != currNode->getEndRoute())
+ {
+ //cerr << "3" << endl;
+ for (FGTaxiSegmentPointerVectorIterator
+ i = currNode->getBeginRoute();
+ i != currNode->getEndRoute();
+ i++)
+ {
+ //cerr << (*i)->getLenght() << endl;
+ trace((*i)->getEnd(), end, depth+1, (*i)->getLength());
+ // {
+ // // cerr << currNode -> getIndex() << " ";
+ // route.push_back(currNode->getIndex());
+ // return true;
+ // }
+ }
+ }
+ else
+ {
+ SG_LOG( SG_GENERAL, SG_DEBUG, "4" );
+ }
+ traceStack.pop_back();
+ totalDistance -= distance;
+ return;
+}
+
--- /dev/null
+// groundnet.hxx - A number of classes to handle taxiway
+// assignments by the AI code
+//
+// Written by Durk Talsma, started June 2005.
+//
+// Copyright (C) 2004 Durk Talsma.
+//
+// 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
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+// $Id$
+
+#ifndef _GROUNDNETWORK_HXX_
+#define _GROUNDNETWORK_HXX_
+
+#include STL_STRING
+#include <vector>
+
+SG_USING_STD(string);
+SG_USING_STD(vector);
+
+#include "parking.hxx"
+
+class FGTaxiSegment; // forward reference
+
+typedef vector<FGTaxiSegment> FGTaxiSegmentVector;
+typedef vector<FGTaxiSegment*> FGTaxiSegmentPointerVector;
+typedef vector<FGTaxiSegment>::iterator FGTaxiSegmentVectorIterator;
+typedef vector<FGTaxiSegment*>::iterator FGTaxiSegmentPointerVectorIterator;
+
+/**************************************************************************************
+ * class FGTaxiNode
+ *************************************************************************************/
+class FGTaxiNode
+{
+private:
+ double lat;
+ double lon;
+ int index;
+ FGTaxiSegmentPointerVector next; // a vector to all the segments leaving from this node
+
+public:
+ FGTaxiNode();
+ FGTaxiNode(double, double, int);
+
+ void setIndex(int idx) { index = idx;};
+ void setLatitude (double val) { lat = val;};
+ void setLongitude(double val) { lon = val;};
+ void setLatitude (const string& val) { lat = processPosition(val); };
+ void setLongitude(const string& val) { lon = processPosition(val); };
+ void addSegment(FGTaxiSegment *segment) { next.push_back(segment); };
+
+ double getLatitude() { return lat;};
+ double getLongitude(){ return lon;};
+
+ int getIndex() { return index; };
+ FGTaxiNode *getAddress() { return this;};
+ FGTaxiSegmentPointerVectorIterator getBeginRoute() { return next.begin(); };
+ FGTaxiSegmentPointerVectorIterator getEndRoute() { return next.end(); };
+};
+
+typedef vector<FGTaxiNode> FGTaxiNodeVector;
+typedef vector<FGTaxiNode>::iterator FGTaxiNodeVectorIterator;
+
+/***************************************************************************************
+ * class FGTaxiSegment
+ **************************************************************************************/
+class FGTaxiSegment
+{
+private:
+ int startNode;
+ int endNode;
+ double length;
+ FGTaxiNode *start;
+ FGTaxiNode *end;
+ int index;
+
+public:
+ FGTaxiSegment();
+ FGTaxiSegment(FGTaxiNode *, FGTaxiNode *, int);
+
+ void setIndex (int val) { index = val; };
+ void setStartNodeRef (int val) { startNode = val; };
+ void setEndNodeRef (int val) { endNode = val; };
+
+ void setStart(FGTaxiNodeVector *nodes);
+ void setEnd (FGTaxiNodeVector *nodes);
+ void setTrackDistance();
+
+ FGTaxiNode * getEnd() { return end;};
+ double getLength() { return length; };
+ int getIndex() { return index; };
+
+
+};
+
+
+typedef vector<int> intVec;
+typedef vector<int>::iterator intVecIterator;
+
+class FGTaxiRoute
+{
+private:
+ intVec nodes;
+ double distance;
+ intVecIterator currNode;
+
+public:
+ FGTaxiRoute() { distance = 0; currNode = nodes.begin(); };
+ FGTaxiRoute(intVec nds, double dist) { nodes = nds; distance = dist; currNode = nodes.begin();};
+ bool operator< (const FGTaxiRoute &other) const {return distance < other.distance; };
+ bool empty () { return nodes.begin() == nodes.end(); };
+ bool next(int *val);
+
+ void first() { currNode = nodes.begin(); };
+};
+
+typedef vector<FGTaxiRoute> TaxiRouteVector;
+typedef vector<FGTaxiRoute>::iterator TaxiRouteVectorIterator;
+
+/**************************************************************************************
+ * class FGGroundNetWork
+ *************************************************************************************/
+class FGGroundNetwork
+{
+private:
+ bool hasNetwork;
+ FGTaxiNodeVector nodes;
+ FGTaxiSegmentVector segments;
+ //intVec route;
+ intVec traceStack;
+ TaxiRouteVector routes;
+
+ bool foundRoute;
+ double totalDistance, maxDistance;
+
+public:
+ FGGroundNetwork();
+
+ void addNode (const FGTaxiNode& node);
+ void addNodes (FGParkingVec *parkings);
+ void addSegment(const FGTaxiSegment& seg);
+
+ void init();
+ bool exists() { return hasNetwork; };
+ int findNearestNode(double lat, double lon);
+ FGTaxiNode *findNode(int idx);
+ FGTaxiRoute findShortestRoute(int start, int end);
+ void trace(FGTaxiNode *, int, int, double dist);
+
+};
+
+#endif
--- /dev/null
+// parking.cxx - Implementation of a class to manage aircraft parking in
+// FlightGear. This code is intended to be used by AI code and
+// initial user-startup location selection.
+//
+// Written by Durk Talsma, started December 2004.
+//
+// Copyright (C) 2004 Durk Talsma.
+//
+// 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
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+// $Id$
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef _MSC_VER
+# define _USE_MATH_DEFINES
+#endif
+//#include <math.h>
+//#include <algorithm>
+
+#include <simgear/compiler.h>
+
+//#include <plib/sg.h>
+//#include <plib/ul.h>
+
+//#include <Environment/environment_mgr.hxx>
+//#include <Environment/environment.hxx>
+//#include <simgear/misc/sg_path.hxx>
+//#include <simgear/props/props.hxx>
+//#include <simgear/structure/subsystem_mgr.hxx>
+//#include <simgear/debug/logstream.hxx>
+//#include <Main/globals.hxx>
+//#include <Main/fg_props.hxx>
+//#include <Airports/runways.hxx>
+
+#include STL_STRING
+
+#include "parking.hxx"
+
+
+/*****************************************************************************
+ * Helper function for parsing position string
+ ****************************************************************************/
+double processPosition(const string &pos)
+{
+ string prefix;
+ string subs;
+ string degree;
+ string decimal;
+ int sign = 1;
+ double value;
+ subs = pos;
+ prefix= subs.substr(0,1);
+ if (prefix == string("S") || (prefix == string("W")))
+ sign = -1;
+ subs = subs.substr(1, subs.length());
+ degree = subs.substr(0, subs.find(" ",0));
+ decimal = subs.substr(subs.find(" ",0), subs.length());
+
+
+ //cerr << sign << " "<< degree << " " << decimal << endl;
+ value = sign * (atof(degree.c_str()) + atof(decimal.c_str())/60.0);
+ //cerr << value <<endl;
+ //exit(1);
+ return value;
+}
+
+
+/*********************************************************************************
+ * FGParking
+ ********************************************************************************/
+FGParking::FGParking(double lat,
+ double lon,
+ double hdg,
+ double rad,
+ int idx,
+ const string &name,
+ const string &tpe,
+ const string &codes)
+{
+ latitude = lat;
+ longitude = lon;
+ heading = hdg;
+ parkingName = name;
+ index = idx;
+ type = tpe;
+ airlineCodes = codes;
+}
--- /dev/null
+// parking.hxx - A class to handle airport startup locations in
+// FlightGear. This code is intended to be used by AI code and
+// initial user-startup location selection.
+//
+// Written by Durk Talsma, started December 2004.
+//
+// Copyright (C) 2004 Durk Talsma.
+//
+// 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
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+// $Id$
+
+#ifndef _PARKING_HXX_
+#define _PARKING_HXX_
+
+#ifndef __cplusplus
+# error This library requires C++
+#endif
+
+#include STL_STRING
+#include <vector>
+
+
+
+
+SG_USING_STD(string);
+SG_USING_STD(vector);
+
+double processPosition(const string& pos);
+
+class FGParking {
+private:
+ double latitude;
+ double longitude;
+ double heading;
+ double radius;
+ int index;
+ string parkingName;
+ string type;
+ string airlineCodes;
+
+ bool available;
+
+
+
+public:
+ FGParking() { available = true;};
+ //FGParking(FGParking &other);
+ FGParking(double lat,
+ double lon,
+ double hdg,
+ double rad,
+ int idx,
+ const string& name,
+ const string& tpe,
+ const string& codes);
+ void setLatitude (const string& lat) { latitude = processPosition(lat); };
+ void setLongitude(const string& lon) { longitude = processPosition(lon); };
+ void setHeading (double hdg) { heading = hdg; };
+ void setRadius (double rad) { radius = rad; };
+ void setIndex (int idx) { index = idx; };
+ void setName (const string& name) { parkingName = name; };
+ void setType (const string& tpe) { type = tpe; };
+ void setCodes (const string& codes){ airlineCodes= codes;};
+
+ bool isAvailable () { return available;};
+ void setAvailable(bool val) { available = val; };
+
+ double getLatitude () { return latitude; };
+ double getLongitude() { return longitude; };
+ double getHeading () { return heading; };
+ double getRadius () { return radius; };
+ int getIndex () { return index; };
+ string getType () { return type; };
+ string getCodes () { return airlineCodes;};
+ string getName () { return parkingName; };
+
+ bool operator< (const FGParking &other) const {return radius < other.radius; };
+};
+
+typedef vector<FGParking> FGParkingVec;
+typedef vector<FGParking>::iterator FGParkingVecIterator;
+typedef vector<FGParking>::const_iterator FGParkingVecConstIterator;
+
+#endif
--- /dev/null
+// runwayprefs.cxx - class implementations corresponding to runwayprefs.hxx
+// assignments by the AI code
+//
+// Written by Durk Talsma, started January 2005.
+//
+// Copyright (C) 2004 Durk Talsma.
+//
+// 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
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+// $Id$
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef _MSC_VER
+# define _USE_MATH_DEFINES
+#endif
+#include <math.h>
+//#include <algorithm>
+
+#include <simgear/compiler.h>
+
+//#include <plib/sg.h>
+//#include <plib/ul.h>
+
+//#include <Environment/environment_mgr.hxx>
+//#include <Environment/environment.hxx>
+//#include <simgear/misc/sg_path.hxx>
+//#include <simgear/props/props.hxx>
+//#include <simgear/structure/subsystem_mgr.hxx>
+#include <simgear/debug/logstream.hxx>
+#include <Main/globals.hxx>
+//#include <Main/fg_props.hxx>
+#include <Airports/runways.hxx>
+
+#include "runwayprefs.hxx"
+
+/******************************************************************************
+ * ScheduleTime
+ ***************e*************************************************************/
+void ScheduleTime::clear()
+{
+ start.clear();
+ end.clear();
+ scheduleNames.clear();
+}
+
+
+ScheduleTime::ScheduleTime(const ScheduleTime &other)
+{
+ //timeVec start;
+ timeVecConstIterator i;
+ for (i = other.start.begin(); i != other.start.end(); i++)
+ start.push_back(*i);
+ for (i = other.end.begin(); i != other.end.end(); i++)
+ end.push_back(*i);
+ stringVecConstIterator k;
+ for (k = other.scheduleNames.begin(); k != other.scheduleNames.end(); k++)
+ scheduleNames.push_back(*k);
+
+ //timeVec end;
+ //stringVec scheduleNames;
+ tailWind = other.tailWind;
+ crssWind = other.tailWind;
+}
+
+
+ScheduleTime & ScheduleTime::operator= (const ScheduleTime &other)
+{
+ //timeVec start;
+ clear();
+ timeVecConstIterator i;
+ for (i = other.start.begin(); i != other.start.end(); i++)
+ start.push_back(*i);
+ for (i = other.end.begin(); i != other.end.end(); i++)
+ end.push_back(*i);
+ stringVecConstIterator k;
+ for (k = other.scheduleNames.begin(); k != other.scheduleNames.end(); k++)
+ scheduleNames.push_back(*k);
+
+ //timeVec end;
+ //stringVec scheduleNames;
+ tailWind = other.tailWind;
+ crssWind = other.tailWind;
+ return *this;
+}
+string ScheduleTime::getName(time_t dayStart)
+{
+ if ((start.size() != end.size()) || (start.size() != scheduleNames.size()))
+ {
+ SG_LOG( SG_GENERAL, SG_INFO, "Unable to parse schedule times" );
+ exit(1);
+ }
+ else
+ {
+ int nrItems = start.size();
+ //cerr << "Nr of items to process: " << nrItems << endl;
+ if (nrItems > 0)
+ {
+ for (unsigned int i = 0; i < start.size(); i++)
+ {
+ //cerr << i << endl;
+ if ((dayStart >= start[i]) && (dayStart <= end[i]))
+ return scheduleNames[i];
+ }
+ }
+ //couldn't find one so return 0;
+ //cerr << "Returning 0 " << endl;
+ }
+ return string(0);
+}
+/******************************************************************************
+ * RunwayList
+ *****************************************************************************/
+
+RunwayList::RunwayList(const RunwayList &other)
+{
+ type = other.type;
+ stringVecConstIterator i;
+ for (i = other.preferredRunways.begin(); i != other.preferredRunways.end(); i++)
+ preferredRunways.push_back(*i);
+}
+RunwayList& RunwayList::operator= (const RunwayList &other)
+{
+ type = other.type;
+ preferredRunways.clear();
+ stringVecConstIterator i;
+ for (i = other.preferredRunways.begin(); i != other.preferredRunways.end(); i++)
+ preferredRunways.push_back(*i);
+ return *this;
+}
+void RunwayList::set(const string &tp, const string &lst)
+{
+ //weekday = atoi(timeCopy.substr(0,1).c_str());
+ // timeOffsetInDays = weekday - currTimeDate->getGmt()->tm_wday;
+ // timeCopy = timeCopy.substr(2,timeCopy.length());
+ type = tp;
+ string rwys = lst;
+ string rwy;
+ while (rwys.find(",") != string::npos)
+ {
+ rwy = rwys.substr(0, rwys.find(",",0));
+ //cerr << "adding runway [" << rwy << "] to the list " << endl;
+ preferredRunways.push_back(rwy);
+ rwys.erase(0, rwys.find(",",0)+1); // erase until after the first whitspace
+ while (rwys[0] == ' ')
+ rwys.erase(0, 1); // Erase any leading whitespaces.
+ //cerr << "Remaining runway list " << rwys;
+ }
+ preferredRunways.push_back(rwys);
+ //exit(1);
+}
+
+void RunwayList::clear()
+{
+ type = "";
+ preferredRunways.clear();
+}
+/****************************************************************************
+ *
+ ***************************************************************************/
+
+RunwayGroup::RunwayGroup(const RunwayGroup &other)
+{
+ name = other.name;
+ RunwayListVecConstIterator i;
+ for (i = other.rwyList.begin(); i != other.rwyList.end(); i++)
+ rwyList.push_back(*i);
+ choice[0] = other.choice[0];
+ choice[1] = other.choice[1];
+ nrActive = other.nrActive;
+}
+RunwayGroup& RunwayGroup:: operator= (const RunwayGroup &other)
+{
+ rwyList.clear();
+ name = other.name;
+ RunwayListVecConstIterator i;
+ for (i = other.rwyList.begin(); i != other.rwyList.end(); i++)
+ rwyList.push_back(*i);
+ choice[0] = other.choice[0];
+ choice[1] = other.choice[1];
+ nrActive = other.nrActive;
+ return *this;
+}
+
+void RunwayGroup::setActive(const string &aptId,
+ double windSpeed,
+ double windHeading,
+ double maxTail,
+ double maxCross)
+{
+
+ FGRunway rwy;
+ int activeRwys = rwyList.size(); // get the number of runways active
+ int nrOfPreferences;
+ // bool found = true;
+ // double heading;
+ double hdgDiff;
+ double crossWind;
+ double tailWind;
+ string name;
+
+ if (activeRwys > 0)
+ {
+ nrOfPreferences = rwyList[0].getRwyList()->size();
+ for (int i = 0; i < nrOfPreferences; i++)
+ {
+ bool validSelection = true;
+ for (int j = 0; j < activeRwys; j++)
+ {
+ //cerr << "I J " << i << " " << j << endl;
+ name = rwyList[j].getRwyList(i);
+ //cerr << "Name of Runway: " << name << endl;
+ if (globals->get_runways()->search( aptId,
+ name,
+ &rwy))
+ {
+ //cerr << "Succes" << endl;
+ hdgDiff = fabs(windHeading - rwy._heading);
+ //cerr << "Wind Heading: " << windHeading << "Runway Heading: " <<rwy._heading << endl;
+ //cerr << "Wind Speed : " << windSpeed << endl;
+ if (hdgDiff > 180)
+ hdgDiff = 360 - hdgDiff;
+ //cerr << "Heading diff: " << hdgDiff << endl;
+ hdgDiff *= ((2*M_PI)/360.0); // convert to radians
+ crossWind = windSpeed * sin(hdgDiff);
+ tailWind = -windSpeed * cos(hdgDiff);
+ //cerr << "Tailwind : " << tailWind << endl;
+ //cerr << "Crosswnd : " << crossWind << endl;
+ if ((tailWind > maxTail) || (crossWind > maxCross))
+ validSelection = false;
+ }else {
+ SG_LOG( SG_GENERAL, SG_INFO, "Failed to find runway " << name << " at " << aptId );
+ exit(1);
+ }
+
+ }
+ if (validSelection)
+ {
+ //cerr << "Valid runay selection : " << i << endl;
+ nrActive = activeRwys;
+ active = i;
+ return;
+ }
+ }
+ // If this didn't work, due to heavy winds, try again
+ // but select only one landing and one takeoff runway.
+ choice[0] = 0;
+ choice[1] = 0;
+ for (int i = activeRwys-1; i; i--)
+ {
+ if (rwyList[i].getType() == string("landing"))
+ choice[0] = i;
+ if (rwyList[i].getType() == string("takeoff"))
+ choice[1] = i;
+ }
+ //cerr << "Choosing " << choice[0] << " for landing and " << choice[1] << "for takeoff" << endl;
+ nrOfPreferences = rwyList[0].getRwyList()->size();
+ for (int i = 0; i < nrOfPreferences; i++)
+ {
+ bool validSelection = true;
+ for (int j = 0; j < 2; j++)
+ {
+ //cerr << "I J " << i << " " << j << endl;
+ name = rwyList[choice[j]].getRwyList(i);
+ //cerr << "Name of Runway: " << name << endl;
+ if (globals->get_runways()->search( aptId,
+ name,
+ &rwy))
+ {
+ //cerr << "Succes" << endl;
+ hdgDiff = fabs(windHeading - rwy._heading);
+ //cerr << "Wind Heading: " << windHeading << "Runway Heading: " <<rwy._heading << endl;
+ //cerr << "Wind Speed : " << windSpeed << endl;
+ if (hdgDiff > 180)
+ hdgDiff = 360 - hdgDiff;
+ //cerr << "Heading diff: " << hdgDiff << endl;
+ hdgDiff *= ((2*M_PI)/360.0); // convert to radians
+ crossWind = windSpeed * sin(hdgDiff);
+ tailWind = -windSpeed * cos(hdgDiff);
+ //cerr << "Tailwind : " << tailWind << endl;
+ //cerr << "Crosswnd : " << crossWind << endl;
+ if ((tailWind > maxTail) || (crossWind > maxCross))
+ validSelection = false;
+ }else {
+ SG_LOG( SG_GENERAL, SG_INFO, "Failed to find runway " << name << " at " << aptId );
+ exit(1);
+ }
+
+ }
+ if (validSelection)
+ {
+ //cerr << "Valid runay selection : " << i << endl;
+ active = i;
+ nrActive = 2;
+ return;
+ }
+ }
+ }
+ active = -1;
+ //RunwayListVectorIterator i; // = rwlist.begin();
+ //stringVecIterator j;
+ //for (i = rwyList.begin(); i != rwyList.end(); i++)
+ // {
+ // cerr << i->getType();
+ // for (j = i->getRwyList()->begin(); j != i->getRwyList()->end(); j++)
+ // {
+ // cerr << (*j);
+ // }
+ // cerr << endl;
+ // }
+ //for (int
+
+}
+
+void RunwayGroup::getActive(int i, string &name, string &type)
+{
+ if (i == -1)
+ {
+ return;
+ }
+ if (nrActive == (int)rwyList.size())
+ {
+ name = rwyList[i].getRwyList(active);
+ type = rwyList[i].getType();
+ }
+ else
+ {
+ name = rwyList[choice[i]].getRwyList(active);
+ type = rwyList[choice[i]].getType();
+ }
+}
+/*****************************************************************************
+ * FGRunway preference
+ ****************************************************************************/
+FGRunwayPreference::FGRunwayPreference()
+{
+ //cerr << "Running default Constructor" << endl;
+ initialized = false;
+}
+
+FGRunwayPreference::FGRunwayPreference(const FGRunwayPreference &other)
+{
+ initialized = other.initialized;
+ value = other.value;
+ scheduleName = other.scheduleName;
+
+ comTimes = other.comTimes; // Commercial Traffic;
+ genTimes = other.genTimes; // General Aviation;
+ milTimes = other.milTimes; // Military Traffic;
+ currTimes= other.currTimes; // Needed for parsing;
+
+ rwyList = other.rwyList;
+ rwyGroup = other.rwyGroup;
+ PreferenceListConstIterator i;
+ for (i = other.preferences.begin(); i != other.preferences.end(); i++)
+ preferences.push_back(*i);
+}
+
+FGRunwayPreference & FGRunwayPreference::operator= (const FGRunwayPreference &other)
+{
+ initialized = other.initialized;
+ value = other.value;
+ scheduleName = other.scheduleName;
+
+ comTimes = other.comTimes; // Commercial Traffic;
+ genTimes = other.genTimes; // General Aviation;
+ milTimes = other.milTimes; // Military Traffic;
+ currTimes= other.currTimes; // Needed for parsing;
+
+ rwyList = other.rwyList;
+ rwyGroup = other.rwyGroup;
+ PreferenceListConstIterator i;
+ preferences.clear();
+ for (i = other.preferences.begin(); i != other.preferences.end(); i++)
+ preferences.push_back(*i);
+ return *this;
+}
+
+ScheduleTime *FGRunwayPreference::getSchedule(const char *trafficType)
+{
+ if (!(strcmp(trafficType, "com"))) {
+ return &comTimes;
+ }
+ if (!(strcmp(trafficType, "gen"))) {
+ return &genTimes;
+ }
+ if (!(strcmp(trafficType, "mil"))) {
+ return &milTimes;
+ }
+ return 0;
+}
+
+RunwayGroup *FGRunwayPreference::getGroup(const string &groupName)
+{
+ PreferenceListIterator i = preferences.begin();
+ if (preferences.begin() == preferences.end())
+ return 0;
+ while (!(i == preferences.end() || i->getName() == groupName))
+ i++;
+ if (i != preferences.end())
+ return &(*i);
+ else
+ return 0;
+}
+
+void FGRunwayPreference::startXML () {
+ // cout << "Start XML" << endl;
+}
+
+void FGRunwayPreference::endXML () {
+ cout << "End XML" << endl;
+}
+
+void FGRunwayPreference::startElement (const char * name, const XMLAttributes &atts) {
+ //cout << "StartElement " << name << endl;
+ value = string("");
+ if (!(strcmp(name, "wind"))) {
+ //cerr << "Will be processing Wind" << endl;
+ for (int i = 0; i < atts.size(); i++)
+ {
+ //cout << " " << atts.getName(i) << '=' << atts.getValue(i) << endl;
+ //attname = atts.getName(i);
+ if (atts.getName(i) == string("tail")) {
+ //cerr << "Tail Wind = " << atts.getValue(i) << endl;
+ currTimes.setTailWind(atof(atts.getValue(i)));
+ }
+ if (atts.getName(i) == string("cross")) {
+ //cerr << "Cross Wind = " << atts.getValue(i) << endl;
+ currTimes.setCrossWind(atof(atts.getValue(i)));
+ }
+ }
+ }
+ if (!(strcmp(name, "time"))) {
+ //cerr << "Will be processing time" << endl;
+ for (int i = 0; i < atts.size(); i++)
+ {
+ if (atts.getName(i) == string("start")) {
+ //cerr << "Start Time = " << atts.getValue(i) << endl;
+ currTimes.addStartTime(processTime(atts.getValue(i)));
+ }
+ if (atts.getName(i) == string("end")) {
+ //cerr << "End time = " << atts.getValue(i) << endl;
+ currTimes.addEndTime(processTime(atts.getValue(i)));
+ }
+ if (atts.getName(i) == string("schedule")) {
+ //cerr << "Schedule Name = " << atts.getValue(i) << endl;
+ currTimes.addScheduleName(atts.getValue(i));
+ }
+ }
+ }
+ if (!(strcmp(name, "takeoff"))) {
+ rwyList.clear();
+ }
+ if (!(strcmp(name, "landing")))
+ {
+ rwyList.clear();
+ }
+ if (!(strcmp(name, "schedule"))) {
+ for (int i = 0; i < atts.size(); i++)
+ {
+ //cout << " " << atts.getName(i) << '=' << atts.getValue(i) << endl;
+ //attname = atts.getName(i);
+ if (atts.getName(i) == string("name")) {
+ //cerr << "Schedule name = " << atts.getValue(i) << endl;
+ scheduleName = atts.getValue(i);
+ }
+ }
+ }
+}
+
+//based on a string containing hour and minute, return nr seconds since day start.
+time_t FGRunwayPreference::processTime(const string &tme)
+{
+ string hour = tme.substr(0, tme.find(":",0));
+ string minute = tme.substr(tme.find(":",0)+1, tme.length());
+
+ //cerr << "hour = " << hour << " Minute = " << minute << endl;
+ return (atoi(hour.c_str()) * 3600 + atoi(minute.c_str()) * 60);
+}
+
+void FGRunwayPreference::endElement (const char * name) {
+ //cout << "End element " << name << endl;
+ if (!(strcmp(name, "rwyuse"))) {
+ initialized = true;
+ }
+ if (!(strcmp(name, "com"))) { // Commercial Traffic
+ //cerr << "Setting time table for commerical traffic" << endl;
+ comTimes = currTimes;
+ currTimes.clear();
+ }
+ if (!(strcmp(name, "gen"))) { // General Aviation
+ //cerr << "Setting time table for general aviation" << endl;
+ genTimes = currTimes;
+ currTimes.clear();
+ }
+ if (!(strcmp(name, "mil"))) { // Military Traffic
+ //cerr << "Setting time table for military traffic" << endl;
+ genTimes = currTimes;
+ currTimes.clear();
+ }
+
+ if (!(strcmp(name, "takeoff"))) {
+ //cerr << "Adding takeoff: " << value << endl;
+ rwyList.set(name, value);
+ rwyGroup.add(rwyList);
+ }
+ if (!(strcmp(name, "landing"))) {
+ //cerr << "Adding landing: " << value << endl;
+ rwyList.set(name, value);
+ rwyGroup.add(rwyList);
+ }
+ if (!(strcmp(name, "schedule"))) {
+ //cerr << "Adding schedule" << scheduleName << endl;
+ rwyGroup.setName(scheduleName);
+ //rwyGroup.addRunways(rwyList);
+ preferences.push_back(rwyGroup);
+ rwyGroup.clear();
+ //exit(1);
+ }
+}
+
+void FGRunwayPreference::data (const char * s, int len) {
+ string token = string(s,len);
+ //cout << "Character data " << string(s,len) << endl;
+ //if ((token.find(" ") == string::npos && (token.find('\n')) == string::npos))
+ // value += token;
+ //else
+ // value = string("");
+ value += token;
+}
+
+void FGRunwayPreference::pi (const char * target, const char * data) {
+ //cout << "Processing instruction " << target << ' ' << data << endl;
+}
+
+void FGRunwayPreference::warning (const char * message, int line, int column) {
+ cout << "Warning: " << message << " (" << line << ',' << column << ')'
+ << endl;
+}
+
+void FGRunwayPreference::error (const char * message, int line, int column) {
+ cout << "Error: " << message << " (" << line << ',' << column << ')'
+ << endl;
+}
--- /dev/null
+// runwayprefs.hxx - A number of classes to configure runway
+// assignments by the AI code
+//
+// Written by Durk Talsma, started January 2005.
+//
+// Copyright (C) 2004 Durk Talsma.
+//
+// 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
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+// $Id$
+
+#ifndef _RUNWAYPREFS_HXX_
+#define _RUNWAYPREFS_HXX_
+
+#include <simgear/xml/easyxml.hxx>
+
+typedef vector<time_t> timeVec;
+typedef vector<time_t>::const_iterator timeVecConstIterator;
+
+typedef vector<string> stringVec;
+typedef vector<string>::iterator stringVecIterator;
+typedef vector<string>::const_iterator stringVecConstIterator;
+
+
+/***************************************************************************/
+class ScheduleTime {
+private:
+ timeVec start;
+ timeVec end;
+ stringVec scheduleNames;
+ double tailWind;
+ double crssWind;
+public:
+ ScheduleTime() : tailWind(0), crssWind(0) {};
+ ScheduleTime(const ScheduleTime &other);
+ ScheduleTime &operator= (const ScheduleTime &other);
+ string getName(time_t dayStart);
+
+ void clear();
+ void addStartTime(time_t time) { start.push_back(time); };
+ void addEndTime (time_t time) { end. push_back(time); };
+ void addScheduleName(const string& sched) { scheduleNames.push_back(sched); };
+ void setTailWind(double wnd) { tailWind = wnd; };
+ void setCrossWind(double wnd) { tailWind = wnd; };
+
+ double getTailWind() { return tailWind; };
+ double getCrossWind() { return crssWind; };
+};
+
+//typedef vector<ScheduleTime> ScheduleTimes;
+/*****************************************************************************/
+
+class RunwayList
+{
+private:
+ string type;
+ stringVec preferredRunways;
+public:
+ RunwayList() {};
+ RunwayList(const RunwayList &other);
+ RunwayList& operator= (const RunwayList &other);
+
+ void set(const string&, const string&);
+ void clear();
+
+ string getType() { return type; };
+ stringVec *getRwyList() { return &preferredRunways; };
+ string getRwyList(int j) { return preferredRunways[j]; };
+};
+
+typedef vector<RunwayList> RunwayListVec;
+typedef vector<RunwayList>::iterator RunwayListVectorIterator;
+typedef vector<RunwayList>::const_iterator RunwayListVecConstIterator;
+
+
+/*****************************************************************************/
+
+class RunwayGroup
+{
+private:
+ string name;
+ RunwayListVec rwyList;
+ int active;
+ //stringVec runwayNames;
+ int choice[2];
+ int nrActive;
+public:
+ RunwayGroup() {};
+ RunwayGroup(const RunwayGroup &other);
+ RunwayGroup &operator= (const RunwayGroup &other);
+
+ void setName(const string& nm) { name = nm; };
+ void add(const RunwayList& list) { rwyList.push_back(list);};
+ void setActive(const string& aptId, double windSpeed, double windHeading, double maxTail, double maxCross);
+
+ int getNrActiveRunways() { return nrActive;};
+ void getActive(int i, string& name, string& type);
+
+ string getName() { return name; };
+ void clear() { rwyList.clear(); };
+ //void add(string, string);
+};
+
+typedef vector<RunwayGroup> PreferenceList;
+typedef vector<RunwayGroup>::iterator PreferenceListIterator;
+typedef vector<RunwayGroup>::const_iterator PreferenceListConstIterator;
+
+/******************************************************************************/
+
+class FGRunwayPreference : public XMLVisitor {
+private:
+ string value;
+ string scheduleName;
+
+ ScheduleTime comTimes; // Commercial Traffic;
+ ScheduleTime genTimes; // General Aviation;
+ ScheduleTime milTimes; // Military Traffic;
+ ScheduleTime currTimes; // Needed for parsing;
+
+ RunwayList rwyList;
+ RunwayGroup rwyGroup;
+ PreferenceList preferences;
+
+ time_t processTime(const string&);
+ bool initialized;
+
+public:
+ FGRunwayPreference();
+ FGRunwayPreference(const FGRunwayPreference &other);
+
+ FGRunwayPreference & operator= (const FGRunwayPreference &other);
+ ScheduleTime *getSchedule(const char *trafficType);
+ RunwayGroup *getGroup(const string& groupName);
+ bool available() { return initialized; };
+
+ // Some overloaded virtual XMLVisitor members
+ virtual void startXML ();
+ virtual void endXML ();
+ virtual void startElement (const char * name, const XMLAttributes &atts);
+ virtual void endElement (const char * name);
+ virtual void data (const char * s, int len);
+ virtual void pi (const char * target, const char * data);
+ virtual void warning (const char * message, int line, int column);
+ virtual void error (const char * message, int line, int column);
+};
+
+#endif
#include <simgear/misc/sg_path.hxx>
#include <simgear/props/props.hxx>
#include <simgear/structure/subsystem_mgr.hxx>
+//#include <simgear/route/waypoint.hxx>
#include <simgear/debug/logstream.hxx>
#include <Main/globals.hxx>
#include <Main/fg_props.hxx>
SG_USING_STD(random_shuffle);
-/******************************************************************************
- * ScheduleTime
- ***************e*************************************************************/
-void ScheduleTime::clear()
-{
- start.clear();
- end.clear();
- scheduleNames.clear();
-}
-
-
-ScheduleTime::ScheduleTime(const ScheduleTime &other)
-{
- //timeVec start;
- timeVecConstIterator i;
- for (i = other.start.begin(); i != other.start.end(); i++)
- start.push_back(*i);
- for (i = other.end.begin(); i != other.end.end(); i++)
- end.push_back(*i);
- stringVecConstIterator k;
- for (k = other.scheduleNames.begin(); k != other.scheduleNames.end(); k++)
- scheduleNames.push_back(*k);
-
- //timeVec end;
- //stringVec scheduleNames;
- tailWind = other.tailWind;
- crssWind = other.tailWind;
-}
-
-
-ScheduleTime & ScheduleTime::operator= (const ScheduleTime &other)
-{
- //timeVec start;
- clear();
- timeVecConstIterator i;
- for (i = other.start.begin(); i != other.start.end(); i++)
- start.push_back(*i);
- for (i = other.end.begin(); i != other.end.end(); i++)
- end.push_back(*i);
- stringVecConstIterator k;
- for (k = other.scheduleNames.begin(); k != other.scheduleNames.end(); k++)
- scheduleNames.push_back(*k);
-
- //timeVec end;
- //stringVec scheduleNames;
- tailWind = other.tailWind;
- crssWind = other.tailWind;
- return *this;
-}
-string ScheduleTime::getName(time_t dayStart)
-{
- if ((start.size() != end.size()) || (start.size() != scheduleNames.size()))
- {
- SG_LOG( SG_GENERAL, SG_INFO, "Unable to parse schedule times" );
- exit(1);
- }
- else
- {
- int nrItems = start.size();
- //cerr << "Nr of items to process: " << nrItems << endl;
- if (nrItems > 0)
- {
- for (unsigned int i = 0; i < start.size(); i++)
- {
- //cerr << i << endl;
- if ((dayStart >= start[i]) && (dayStart <= end[i]))
- return scheduleNames[i];
- }
- }
- //couldn't find one so return 0;
- //cerr << "Returning 0 " << endl;
- }
- return string(0);
-}
-/******************************************************************************
- * RunwayList
- *****************************************************************************/
-
-RunwayList::RunwayList(const RunwayList &other)
-{
- type = other.type;
- stringVecConstIterator i;
- for (i = other.preferredRunways.begin(); i != other.preferredRunways.end(); i++)
- preferredRunways.push_back(*i);
-}
-RunwayList& RunwayList::operator= (const RunwayList &other)
-{
- type = other.type;
- preferredRunways.clear();
- stringVecConstIterator i;
- for (i = other.preferredRunways.begin(); i != other.preferredRunways.end(); i++)
- preferredRunways.push_back(*i);
- return *this;
-}
-void RunwayList::set(const string &tp, const string &lst)
-{
- //weekday = atoi(timeCopy.substr(0,1).c_str());
- // timeOffsetInDays = weekday - currTimeDate->getGmt()->tm_wday;
- // timeCopy = timeCopy.substr(2,timeCopy.length());
- type = tp;
- string rwys = lst;
- string rwy;
- while (rwys.find(",") != string::npos)
- {
- rwy = rwys.substr(0, rwys.find(",",0));
- //cerr << "adding runway [" << rwy << "] to the list " << endl;
- preferredRunways.push_back(rwy);
- rwys.erase(0, rwys.find(",",0)+1); // erase until after the first whitspace
- while (rwys[0] == ' ')
- rwys.erase(0, 1); // Erase any leading whitespaces.
- //cerr << "Remaining runway list " << rwys;
- }
- preferredRunways.push_back(rwys);
- //exit(1);
-}
-
-void RunwayList::clear()
-{
- type = "";
- preferredRunways.clear();
-}
-/****************************************************************************
- *
- ***************************************************************************/
-
-RunwayGroup::RunwayGroup(const RunwayGroup &other)
-{
- name = other.name;
- RunwayListVecConstIterator i;
- for (i = other.rwyList.begin(); i != other.rwyList.end(); i++)
- rwyList.push_back(*i);
- choice[0] = other.choice[0];
- choice[1] = other.choice[1];
- nrActive = other.nrActive;
-}
-RunwayGroup& RunwayGroup:: operator= (const RunwayGroup &other)
-{
- rwyList.clear();
- name = other.name;
- RunwayListVecConstIterator i;
- for (i = other.rwyList.begin(); i != other.rwyList.end(); i++)
- rwyList.push_back(*i);
- choice[0] = other.choice[0];
- choice[1] = other.choice[1];
- nrActive = other.nrActive;
- return *this;
-}
-
-void RunwayGroup::setActive(const string &aptId,
- double windSpeed,
- double windHeading,
- double maxTail,
- double maxCross)
-{
-
- FGRunway rwy;
- int activeRwys = rwyList.size(); // get the number of runways active
- int nrOfPreferences;
- // bool found = true;
- // double heading;
- double hdgDiff;
- double crossWind;
- double tailWind;
- string name;
-
- if (activeRwys > 0)
- {
- nrOfPreferences = rwyList[0].getRwyList()->size();
- for (int i = 0; i < nrOfPreferences; i++)
- {
- bool validSelection = true;
- for (int j = 0; j < activeRwys; j++)
- {
- //cerr << "I J " << i << " " << j << endl;
- name = rwyList[j].getRwyList(i);
- //cerr << "Name of Runway: " << name << endl;
- if (globals->get_runways()->search( aptId,
- name,
- &rwy))
- {
- //cerr << "Succes" << endl;
- hdgDiff = fabs(windHeading - rwy._heading);
- //cerr << "Wind Heading: " << windHeading << "Runway Heading: " <<rwy._heading << endl;
- //cerr << "Wind Speed : " << windSpeed << endl;
- if (hdgDiff > 180)
- hdgDiff = 360 - hdgDiff;
- //cerr << "Heading diff: " << hdgDiff << endl;
- hdgDiff *= ((2*M_PI)/360.0); // convert to radians
- crossWind = windSpeed * sin(hdgDiff);
- tailWind = -windSpeed * cos(hdgDiff);
- //cerr << "Tailwind : " << tailWind << endl;
- //cerr << "Crosswnd : " << crossWind << endl;
- if ((tailWind > maxTail) || (crossWind > maxCross))
- validSelection = false;
- }else {
- SG_LOG( SG_GENERAL, SG_INFO, "Failed to find runway " << name << " at " << aptId );
- exit(1);
- }
-
- }
- if (validSelection)
- {
- //cerr << "Valid runay selection : " << i << endl;
- nrActive = activeRwys;
- active = i;
- return;
- }
- }
- // If this didn't work, due to heavy winds, try again
- // but select only one landing and one takeoff runway.
- choice[0] = 0;
- choice[1] = 0;
- for (int i = activeRwys-1; i; i--)
- {
- if (rwyList[i].getType() == string("landing"))
- choice[0] = i;
- if (rwyList[i].getType() == string("takeoff"))
- choice[1] = i;
- }
- //cerr << "Choosing " << choice[0] << " for landing and " << choice[1] << "for takeoff" << endl;
- nrOfPreferences = rwyList[0].getRwyList()->size();
- for (int i = 0; i < nrOfPreferences; i++)
- {
- bool validSelection = true;
- for (int j = 0; j < 2; j++)
- {
- //cerr << "I J " << i << " " << j << endl;
- name = rwyList[choice[j]].getRwyList(i);
- //cerr << "Name of Runway: " << name << endl;
- if (globals->get_runways()->search( aptId,
- name,
- &rwy))
- {
- //cerr << "Succes" << endl;
- hdgDiff = fabs(windHeading - rwy._heading);
- //cerr << "Wind Heading: " << windHeading << "Runway Heading: " <<rwy._heading << endl;
- //cerr << "Wind Speed : " << windSpeed << endl;
- if (hdgDiff > 180)
- hdgDiff = 360 - hdgDiff;
- //cerr << "Heading diff: " << hdgDiff << endl;
- hdgDiff *= ((2*M_PI)/360.0); // convert to radians
- crossWind = windSpeed * sin(hdgDiff);
- tailWind = -windSpeed * cos(hdgDiff);
- //cerr << "Tailwind : " << tailWind << endl;
- //cerr << "Crosswnd : " << crossWind << endl;
- if ((tailWind > maxTail) || (crossWind > maxCross))
- validSelection = false;
- }else {
- SG_LOG( SG_GENERAL, SG_INFO, "Failed to find runway " << name << " at " << aptId );
- exit(1);
- }
-
- }
- if (validSelection)
- {
- //cerr << "Valid runay selection : " << i << endl;
- active = i;
- nrActive = 2;
- return;
- }
- }
- }
- active = -1;
- //RunwayListVectorIterator i; // = rwlist.begin();
- //stringVecIterator j;
- //for (i = rwyList.begin(); i != rwyList.end(); i++)
- // {
- // cerr << i->getType();
- // for (j = i->getRwyList()->begin(); j != i->getRwyList()->end(); j++)
- // {
- // cerr << (*j);
- // }
- // cerr << endl;
- // }
- //for (int
-
-}
-
-void RunwayGroup::getActive(int i, string &name, string &type)
-{
- if (i == -1)
- {
- return;
- }
- if (nrActive == (int)rwyList.size())
- {
- name = rwyList[i].getRwyList(active);
- type = rwyList[i].getType();
- }
- else
- {
- name = rwyList[choice[i]].getRwyList(active);
- type = rwyList[choice[i]].getType();
- }
-}
-/*****************************************************************************
- * FGRunway preference
- ****************************************************************************/
-FGRunwayPreference::FGRunwayPreference()
-{
- //cerr << "Running default Constructor" << endl;
- initialized = false;
-}
-
-FGRunwayPreference::FGRunwayPreference(const FGRunwayPreference &other)
-{
- initialized = other.initialized;
- value = other.value;
- scheduleName = other.scheduleName;
-
- comTimes = other.comTimes; // Commercial Traffic;
- genTimes = other.genTimes; // General Aviation;
- milTimes = other.milTimes; // Military Traffic;
- currTimes= other.currTimes; // Needed for parsing;
-
- rwyList = other.rwyList;
- rwyGroup = other.rwyGroup;
- PreferenceListConstIterator i;
- for (i = other.preferences.begin(); i != other.preferences.end(); i++)
- preferences.push_back(*i);
-}
-
-FGRunwayPreference & FGRunwayPreference::operator= (const FGRunwayPreference &other)
-{
- initialized = other.initialized;
- value = other.value;
- scheduleName = other.scheduleName;
-
- comTimes = other.comTimes; // Commercial Traffic;
- genTimes = other.genTimes; // General Aviation;
- milTimes = other.milTimes; // Military Traffic;
- currTimes= other.currTimes; // Needed for parsing;
-
- rwyList = other.rwyList;
- rwyGroup = other.rwyGroup;
- PreferenceListConstIterator i;
- preferences.clear();
- for (i = other.preferences.begin(); i != other.preferences.end(); i++)
- preferences.push_back(*i);
- return *this;
-}
-
-ScheduleTime *FGRunwayPreference::getSchedule(const char *trafficType)
-{
- if (!(strcmp(trafficType, "com"))) {
- return &comTimes;
- }
- if (!(strcmp(trafficType, "gen"))) {
- return &genTimes;
- }
- if (!(strcmp(trafficType, "mil"))) {
- return &milTimes;
- }
- return 0;
-}
-
-RunwayGroup *FGRunwayPreference::getGroup(const string &groupName)
-{
- PreferenceListIterator i = preferences.begin();
- if (preferences.begin() == preferences.end())
- return 0;
- while (!(i == preferences.end() || i->getName() == groupName))
- i++;
- if (i != preferences.end())
- return &(*i);
- else
- return 0;
-}
-
-void FGRunwayPreference::startXML () {
- // cout << "Start XML" << endl;
-}
-void FGRunwayPreference::endXML () {
- cout << "End XML" << endl;
-}
-void FGRunwayPreference::startElement (const char * name, const XMLAttributes &atts) {
- //cout << "StartElement " << name << endl;
- value = string("");
- if (!(strcmp(name, "wind"))) {
- //cerr << "Will be processing Wind" << endl;
- for (int i = 0; i < atts.size(); i++)
- {
- //cout << " " << atts.getName(i) << '=' << atts.getValue(i) << endl;
- //attname = atts.getName(i);
- if (atts.getName(i) == string("tail")) {
- //cerr << "Tail Wind = " << atts.getValue(i) << endl;
- currTimes.setTailWind(atof(atts.getValue(i)));
- }
- if (atts.getName(i) == string("cross")) {
- //cerr << "Cross Wind = " << atts.getValue(i) << endl;
- currTimes.setCrossWind(atof(atts.getValue(i)));
- }
- }
- }
- if (!(strcmp(name, "time"))) {
- //cerr << "Will be processing time" << endl;
- for (int i = 0; i < atts.size(); i++)
- {
- if (atts.getName(i) == string("start")) {
- //cerr << "Start Time = " << atts.getValue(i) << endl;
- currTimes.addStartTime(processTime(atts.getValue(i)));
- }
- if (atts.getName(i) == string("end")) {
- //cerr << "End time = " << atts.getValue(i) << endl;
- currTimes.addEndTime(processTime(atts.getValue(i)));
- }
- if (atts.getName(i) == string("schedule")) {
- //cerr << "Schedule Name = " << atts.getValue(i) << endl;
- currTimes.addScheduleName(atts.getValue(i));
- }
- }
- }
- if (!(strcmp(name, "takeoff"))) {
- rwyList.clear();
- }
- if (!(strcmp(name, "landing")))
- {
- rwyList.clear();
- }
- if (!(strcmp(name, "schedule"))) {
- for (int i = 0; i < atts.size(); i++)
- {
- //cout << " " << atts.getName(i) << '=' << atts.getValue(i) << endl;
- //attname = atts.getName(i);
- if (atts.getName(i) == string("name")) {
- //cerr << "Schedule name = " << atts.getValue(i) << endl;
- scheduleName = atts.getValue(i);
- }
- }
- }
-}
-
-//based on a string containing hour and minute, return nr seconds since day start.
-time_t FGRunwayPreference::processTime(const string &tme)
-{
- string hour = tme.substr(0, tme.find(":",0));
- string minute = tme.substr(tme.find(":",0)+1, tme.length());
-
- //cerr << "hour = " << hour << " Minute = " << minute << endl;
- return (atoi(hour.c_str()) * 3600 + atoi(minute.c_str()) * 60);
-}
-
-void FGRunwayPreference::endElement (const char * name) {
- //cout << "End element " << name << endl;
- if (!(strcmp(name, "rwyuse"))) {
- initialized = true;
- }
- if (!(strcmp(name, "com"))) { // Commercial Traffic
- //cerr << "Setting time table for commerical traffic" << endl;
- comTimes = currTimes;
- currTimes.clear();
- }
- if (!(strcmp(name, "gen"))) { // General Aviation
- //cerr << "Setting time table for general aviation" << endl;
- genTimes = currTimes;
- currTimes.clear();
- }
- if (!(strcmp(name, "mil"))) { // Military Traffic
- //cerr << "Setting time table for military traffic" << endl;
- genTimes = currTimes;
- currTimes.clear();
- }
-
- if (!(strcmp(name, "takeoff"))) {
- //cerr << "Adding takeoff: " << value << endl;
- rwyList.set(name, value);
- rwyGroup.add(rwyList);
- }
- if (!(strcmp(name, "landing"))) {
- //cerr << "Adding landing: " << value << endl;
- rwyList.set(name, value);
- rwyGroup.add(rwyList);
- }
- if (!(strcmp(name, "schedule"))) {
- //cerr << "Adding schedule" << scheduleName << endl;
- rwyGroup.setName(scheduleName);
- //rwyGroup.addRunways(rwyList);
- preferences.push_back(rwyGroup);
- rwyGroup.clear();
- //exit(1);
- }
-}
-
-void FGRunwayPreference::data (const char * s, int len) {
- string token = string(s,len);
- //cout << "Character data " << string(s,len) << endl;
- //if ((token.find(" ") == string::npos && (token.find('\n')) == string::npos))
- // value += token;
- //else
- // value = string("");
- value += token;
-}
-
-void FGRunwayPreference::pi (const char * target, const char * data) {
- //cout << "Processing instruction " << target << ' ' << data << endl;
-}
-
-void FGRunwayPreference::warning (const char * message, int line, int column) {
- cout << "Warning: " << message << " (" << line << ',' << column << ')'
- << endl;
-}
-
-void FGRunwayPreference::error (const char * message, int line, int column) {
- cout << "Error: " << message << " (" << line << ',' << column << ')'
- << endl;
-}
-
-/*****************************************************************************
- * Helper function for parsing position string
- ****************************************************************************/
-double processPosition(const string &pos)
-{
- string prefix;
- string subs;
- string degree;
- string decimal;
- int sign = 1;
- double value;
- subs = pos;
- prefix= subs.substr(0,1);
- if (prefix == string("S") || (prefix == string("W")))
- sign = -1;
- subs = subs.substr(1, subs.length());
- degree = subs.substr(0, subs.find(" ",0));
- decimal = subs.substr(subs.find(" ",0), subs.length());
-
-
- //cerr << sign << " "<< degree << " " << decimal << endl;
- value = sign * (atof(degree.c_str()) + atof(decimal.c_str())/60.0);
- //cerr << value <<endl;
- //exit(1);
- return value;
-}
-
-
-/*********************************************************************************
- * FGParking
- ********************************************************************************/
-FGParking::FGParking(double lat,
- double lon,
- double hdg,
- double rad,
- int idx,
- const string &name,
- const string &tpe,
- const string &codes)
-{
- latitude = lat;
- longitude = lon;
- heading = hdg;
- parkingName = name;
- index = idx;
- type = tpe;
- airlineCodes = codes;
-}
/***************************************************************************
***************************************************************************/
FGAirport::FGAirport() : _longitude(0), _latitude(0), _elevation(0)
{
- lastUpdate = 0;
- for (int i = 0; i < 10; i++)
- {
- avWindHeading [i] = 0;
- avWindSpeed [i] = 0;
- }
+ dynamics = 0;
}
-FGAirport::FGAirport(const FGAirport& other)
-{
- _id = other._id;
- _longitude = other._longitude;
- _latitude = other._latitude;
- _elevation = other._elevation;
- _name = other._name;
- _has_metar = other._has_metar;
- for (FGParkingVecConstIterator ip= other.parkings.begin(); ip != other.parkings.end(); ip++)
- parkings.push_back(*(ip));
- rwyPrefs = other.rwyPrefs;
- lastUpdate = other.lastUpdate;
-
- stringVecConstIterator il;
- for (il = other.landing.begin(); il != other.landing.end(); il++)
- landing.push_back(*il);
- for (il = other.takeoff.begin(); il != other.takeoff.end(); il++)
- takeoff.push_back(*il);
- lastUpdate = other.lastUpdate;
- for (int i = 0; i < 10; i++)
- {
- avWindHeading [i] = other.avWindHeading[i];
- avWindSpeed [i] = other.avWindSpeed [i];
- }
-}
FGAirport::FGAirport(const string &id, double lon, double lat, double elev, const string &name, bool has_metar)
{
_latitude = lat;
_elevation = elev;
_name = name;
- _has_metar = has_metar;
- lastUpdate = 0;
- for (int i = 0; i < 10; i++)
- {
- avWindHeading [i] = 0;
- avWindSpeed [i] = 0;
- }
-
+ _has_metar = has_metar;
+ dynamics = 0;
}
-// Initialization required after XMLRead
-void FGAirport::init()
+FGAirport::~FGAirport()
{
- // This may seem a bit weird to first randomly shuffle the parkings
- // and then sort them again. However, parkings are sorted here by ascending
- // radius. Since many parkings have similar radii, with each radius class they will
- // still be allocated relatively systematically. Randomizing prior to sorting will
- // prevent any initial orderings to be destroyed, leading (hopefully) to a more
- // naturalistic gate assignment.
- random_shuffle(parkings.begin(), parkings.end());
- sort(parkings.begin(), parkings.end());
- // add the gate positions to the ground network.
- groundNetwork.addNodes(&parkings);
- groundNetwork.init();
+ delete dynamics;
}
-bool FGAirport::getAvailableParking(double *lat, double *lon, double *heading, int *gateId, double rad, const string &flType, const string &acType, const string &airline)
-{
- bool found = false;
- bool available = false;
- //string gateType;
- FGParkingVecIterator i;
-// if (flType == "cargo")
-// {
-// gateType = "RAMP_CARGO";
-// }
-// else if (flType == "ga")
-// {
-// gateType = "RAMP_GA";
-// }
-// else gateType = "GATE";
-
- if (parkings.begin() == parkings.end())
- {
- //cerr << "Could not find parking spot at " << _id << endl;
- *lat = _latitude;
- *lon = _longitude;
- *heading = 0;
- found = true;
- }
- else
- {
- // First try finding a parking with a designated airline code
- for (i = parkings.begin(); !(i == parkings.end() || found); i++)
- {
- //cerr << "Gate Id: " << i->getIndex()
- // << " Type : " << i->getType()
- // << " Codes : " << i->getCodes()
- // << " Radius: " << i->getRadius()
- // << " Name : " << i->getName()
- // << " Available: " << i->isAvailable() << endl;
- available = true;
- // Taken by another aircraft
- if (!(i->isAvailable()))
- {
- available = false;
- continue;
- }
- // No airline codes, so skip
- if (i->getCodes().empty())
- {
- available = false;
- continue;
- }
- else // Airline code doesn't match
- if (i->getCodes().find(airline, 0) == string::npos)
- {
- available = false;
- continue;
- }
- // Type doesn't match
- if (i->getType() != flType)
- {
- available = false;
- continue;
- }
- // too small
- if (i->getRadius() < rad)
- {
- available = false;
- continue;
- }
-
- if (available)
- {
- *lat = i->getLatitude ();
- *lon = i->getLongitude();
- *heading = i->getHeading ();
- *gateId = i->getIndex ();
- i->setAvailable(false);
- found = true;
- }
- }
- // then try again for those without codes.
- for (i = parkings.begin(); !(i == parkings.end() || found); i++)
- {
- available = true;
- if (!(i->isAvailable()))
- {
- available = false;
- continue;
- }
- if (!(i->getCodes().empty()))
- {
- if ((i->getCodes().find(airline,0) == string::npos))
- {
- available = false;
- continue;
- }
- }
- if (i->getType() != flType)
- {
- available = false;
- continue;
- }
-
- if (i->getRadius() < rad)
- {
- available = false;
- continue;
- }
-
- if (available)
- {
- *lat = i->getLatitude ();
- *lon = i->getLongitude();
- *heading = i->getHeading ();
- *gateId = i->getIndex ();
- i->setAvailable(false);
- found = true;
- }
- }
- // And finally once more if that didn't work. Now ignore the airline codes, as a last resort
- for (i = parkings.begin(); !(i == parkings.end() || found); i++)
- {
- available = true;
- if (!(i->isAvailable()))
- {
- available = false;
- continue;
- }
- if (i->getType() != flType)
- {
- available = false;
- continue;
- }
-
- if (i->getRadius() < rad)
- {
- available = false;
- continue;
- }
-
- if (available)
- {
- *lat = i->getLatitude ();
- *lon = i->getLongitude();
- *heading = i->getHeading ();
- *gateId = i->getIndex ();
- i->setAvailable(false);
- found = true;
- }
- }
- }
- if (!found)
- {
- //cerr << "Traffic overflow at" << _id
- // << ". flType = " << flType
- // << ". airline = " << airline
- // << " Radius = " <<rad
- // << endl;
- *lat = _latitude;
- *lon = _longitude;
- *heading = 0;
- *gateId = -1;
- //exit(1);
- }
- return found;
-}
-
-void FGAirport::getParking (int id, double *lat, double* lon, double *heading)
-{
- if (id < 0)
- {
- *lat = _latitude;
- *lon = _longitude;
- *heading = 0;
- }
- else
- {
- FGParkingVecIterator i = parkings.begin();
- for (i = parkings.begin(); i != parkings.end(); i++)
- {
- if (id == i->getIndex())
- {
- *lat = i->getLatitude();
- *lon = i->getLongitude();
- *heading = i->getLongitude();
- }
- }
- }
-}
-
-FGParking *FGAirport::getParking(int i)
-{
- if (i < (int)parkings.size())
- return &(parkings[i]);
- else
- return 0;
-}
-string FGAirport::getParkingName(int i)
-{
- if (i < (int)parkings.size() && i >= 0)
- return (parkings[i].getName());
- else
- return string("overflow");
-}
-void FGAirport::releaseParking(int id)
+FGAirportDynamics * FGAirport::getDynamics()
{
- if (id >= 0)
- {
-
- FGParkingVecIterator i = parkings.begin();
- for (i = parkings.begin(); i != parkings.end(); i++)
- {
- if (id == i->getIndex())
- {
- i -> setAvailable(true);
- }
- }
- }
-}
-void FGAirport::startXML () {
- //cout << "Start XML" << endl;
-}
-
-void FGAirport::endXML () {
- //cout << "End XML" << endl;
-}
-
-void FGAirport::startElement (const char * name, const XMLAttributes &atts) {
- // const char *attval;
- FGParking park;
- FGTaxiNode taxiNode;
- FGTaxiSegment taxiSegment;
- int index = 0;
- taxiSegment.setIndex(index);
- //cout << "Start element " << name << endl;
- string attname;
- string value;
- string gateName;
- string gateNumber;
- string lat;
- string lon;
- if (name == string("Parking"))
- {
- for (int i = 0; i < atts.size(); i++)
- {
- //cout << " " << atts.getName(i) << '=' << atts.getValue(i) << endl;
- attname = atts.getName(i);
- if (attname == string("index"))
- park.setIndex(atoi(atts.getValue(i)));
- else if (attname == string("type"))
- park.setType(atts.getValue(i));
- else if (attname == string("name"))
- gateName = atts.getValue(i);
- else if (attname == string("number"))
- gateNumber = atts.getValue(i);
- else if (attname == string("lat"))
- park.setLatitude(atts.getValue(i));
- else if (attname == string("lon"))
- park.setLongitude(atts.getValue(i));
- else if (attname == string("heading"))
- park.setHeading(atof(atts.getValue(i)));
- else if (attname == string("radius")) {
- string radius = atts.getValue(i);
- if (radius.find("M") != string::npos)
- radius = radius.substr(0, radius.find("M",0));
- //cerr << "Radius " << radius <<endl;
- park.setRadius(atof(radius.c_str()));
- }
- else if (attname == string("airlineCodes"))
- park.setCodes(atts.getValue(i));
- }
- park.setName((gateName+gateNumber));
- parkings.push_back(park);
- }
- if (name == string("node"))
- {
- for (int i = 0; i < atts.size() ; i++)
- {
- attname = atts.getName(i);
- if (attname == string("index"))
- taxiNode.setIndex(atoi(atts.getValue(i)));
- if (attname == string("lat"))
- taxiNode.setLatitude(atts.getValue(i));
- if (attname == string("lon"))
- taxiNode.setLongitude(atts.getValue(i));
- }
- groundNetwork.addNode(taxiNode);
- }
- if (name == string("arc"))
- {
- taxiSegment.setIndex(++index);
- for (int i = 0; i < atts.size() ; i++)
- {
- attname = atts.getName(i);
- if (attname == string("begin"))
- taxiSegment.setStartNodeRef(atoi(atts.getValue(i)));
- if (attname == string("end"))
- taxiSegment.setEndNodeRef(atoi(atts.getValue(i)));
- }
- groundNetwork.addSegment(taxiSegment);
- }
- // sort by radius, in asending order, so that smaller gates are first in the list
-}
-
-void FGAirport::endElement (const char * name) {
- //cout << "End element " << name << endl;
-
-}
-
-void FGAirport::data (const char * s, int len) {
- string token = string(s,len);
- //cout << "Character data " << string(s,len) << endl;
- //if ((token.find(" ") == string::npos && (token.find('\n')) == string::npos))
- //value += token;
- //else
- //value = string("");
-}
-
-void FGAirport::pi (const char * target, const char * data) {
- //cout << "Processing instruction " << target << ' ' << data << endl;
-}
-
-void FGAirport::warning (const char * message, int line, int column) {
- cout << "Warning: " << message << " (" << line << ',' << column << ')'
- << endl;
-}
-
-void FGAirport::error (const char * message, int line, int column) {
- cout << "Error: " << message << " (" << line << ',' << column << ')'
- << endl;
-}
-
-void FGAirport::setRwyUse(const FGRunwayPreference& ref)
-{
- rwyPrefs = ref;
- //cerr << "Exiting due to not implemented yet" << endl;
- //exit(1);
-}
-void FGAirport::getActiveRunway(const string &trafficType, int action, string &runway)
-{
- double windSpeed;
- double windHeading;
- double maxTail;
- double maxCross;
- string name;
- string type;
-
- if (!(rwyPrefs.available()))
- {
- runway = chooseRunwayFallback();
- return; // generic fall back goes here
- }
+ if (dynamics != 0)
+ return dynamics;
else
{
- RunwayGroup *currRunwayGroup = 0;
- int nrActiveRunways = 0;
- time_t dayStart = fgGetLong("/sim/time/utc/day-seconds");
- if (((dayStart - lastUpdate) > 600) || trafficType != prevTrafficType)
- {
- landing.clear();
- takeoff.clear();
- //lastUpdate = dayStart;
- prevTrafficType = trafficType;
+ FGRunwayPreference rwyPrefs;
+ cerr << "Trying to load dynamics for " << _id << endl;
+ dynamics = new FGAirportDynamics(_latitude, _longitude, _elevation, _id);
- FGEnvironment
- stationweather = ((FGEnvironmentMgr *) globals->get_subsystem("environment"))
- ->getEnvironment(getLatitude(),
- getLongitude(),
- getElevation());
-
- windSpeed = stationweather.get_wind_speed_kt();
- windHeading = stationweather.get_wind_from_heading_deg();
- double averageWindSpeed = 0;
- double averageWindHeading = 0;
- double cosHeading = 0;
- double sinHeading = 0;
- // Initialize at the beginning of the next day or startup
- if ((lastUpdate == 0) || (dayStart < lastUpdate))
- {
- for (int i = 0; i < 10; i++)
- {
- avWindHeading [i] = windHeading;
- avWindSpeed [i] = windSpeed;
- }
- }
- else
- {
- if (windSpeed != avWindSpeed[9]) // update if new metar data
- {
- // shift the running average
- for (int i = 0; i < 9 ; i++)
- {
- avWindHeading[i] = avWindHeading[i+1];
- avWindSpeed [i] = avWindSpeed [i+1];
- }
- }
- avWindHeading[9] = windHeading;
- avWindSpeed [9] = windSpeed;
- }
-
- for (int i = 0; i < 10; i++)
- {
- averageWindSpeed += avWindSpeed [i];
- //averageWindHeading += avWindHeading [i];
- cosHeading += cos(avWindHeading[i] * SG_DEGREES_TO_RADIANS);
- sinHeading += sin(avWindHeading[i] * SG_DEGREES_TO_RADIANS);
- }
- averageWindSpeed /= 10;
- //averageWindHeading /= 10;
- cosHeading /= 10;
- sinHeading /= 10;
- averageWindHeading = atan2(sinHeading, cosHeading) *SG_RADIANS_TO_DEGREES;
- if (averageWindHeading < 0)
- averageWindHeading += 360.0;
- //cerr << "Wind Heading " << windHeading << " average " << averageWindHeading << endl;
- //cerr << "Wind Speed " << windSpeed << " average " << averageWindSpeed << endl;
- lastUpdate = dayStart;
- //if (wind_speed == 0) {
- // wind_heading = 270; This forces West-facing rwys to be used in no-wind situations
- // which is consistent with Flightgear's initial setup.
- //}
-
- //string rwy_no = globals->get_runways()->search(apt->getId(), int(wind_heading));
- string scheduleName;
- //cerr << "finding active Runway for" << _id << endl;
- //cerr << "Nr of seconds since day start << " << dayStart << endl;
- ScheduleTime *currSched;
- //cerr << "A"<< endl;
- currSched = rwyPrefs.getSchedule(trafficType.c_str());
- if (!(currSched))
- return;
- //cerr << "B"<< endl;
- scheduleName = currSched->getName(dayStart);
- maxTail = currSched->getTailWind ();
- maxCross = currSched->getCrossWind ();
- //cerr << "SChedule anme = " << scheduleName << endl;
- if (scheduleName.empty())
- return;
- //cerr << "C"<< endl;
- currRunwayGroup = rwyPrefs.getGroup(scheduleName);
- //cerr << "D"<< endl;
- if (!(currRunwayGroup))
- return;
- nrActiveRunways = currRunwayGroup->getNrActiveRunways();
- //cerr << "Nr of Active Runways = " << nrActiveRunways << endl;
- currRunwayGroup->setActive(_id, averageWindSpeed, averageWindHeading, maxTail, maxCross);
- nrActiveRunways = currRunwayGroup->getNrActiveRunways();
- for (int i = 0; i < nrActiveRunways; i++)
- {
- type = "unknown"; // initialize to something other than landing or takeoff
- currRunwayGroup->getActive(i, name, type);
- if (type == "landing")
- {
- landing.push_back(name);
- //cerr << "Landing " << name << endl;
- }
- if (type == "takeoff")
- {
- takeoff.push_back(name);
- //cerr << "takeoff " << name << endl;
- }
- }
- }
- if (action == 1) // takeoff
- {
- int nr = takeoff.size();
- if (nr)
- {
- runway = takeoff[(rand() % nr)];
- }
- else
- { // Fallback
- runway = chooseRunwayFallback();
- }
- }
- if (action == 2) // landing
- {
- int nr = landing.size();
- if (nr)
- {
- runway = landing[(rand() % nr)];
- }
- else
- { //fallback
- runway = chooseRunwayFallback();
- }
- }
+ SGPath parkpath( globals->get_fg_root() );
+ parkpath.append( "/Airports/AI/" );
+ parkpath.append(_id);
+ parkpath.append("parking.xml");
- //runway = globals->get_runways()->search(_id, int(windHeading));
- //cerr << "Seleceted runway: " << runway << endl;
- }
-}
-
-string FGAirport::chooseRunwayFallback()
-{
- FGEnvironment
- stationweather = ((FGEnvironmentMgr *) globals->get_subsystem("environment"))
- ->getEnvironment(getLatitude(),
- getLongitude(),
- getElevation());
-
- double windSpeed = stationweather.get_wind_speed_kt();
- double windHeading = stationweather.get_wind_from_heading_deg();
- if (windSpeed == 0) {
- windHeading = 270; // This forces West-facing rwys to be used in no-wind situations
- //which is consistent with Flightgear's initial setup.
- }
-
- return globals->get_runways()->search(_id, int(windHeading));
-}
-
-
-
-/**************************************************************************
- * FGTaxiNode
- *************************************************************************/
-FGTaxiNode::FGTaxiNode()
-{
-}
-
-/***************************************************************************
- * FGTaxiSegment
- **************************************************************************/
-FGTaxiSegment::FGTaxiSegment()
-{
-}
-
-void FGTaxiSegment::setStart(FGTaxiNodeVector *nodes)
-{
- FGTaxiNodeVectorIterator i = nodes->begin();
- while (i != nodes->end())
- {
- if (i->getIndex() == startNode)
+ SGPath rwyPrefPath( globals->get_fg_root() );
+ rwyPrefPath.append( "/Airports/AI/" );
+ rwyPrefPath.append(_id);
+ rwyPrefPath.append("rwyuse.xml");
+ //if (ai_dirs.find(id.c_str()) != ai_dirs.end()
+ // && parkpath.exists())
+ if (parkpath.exists())
{
- start = i->getAddress();
- i->addSegment(this);
- return;
+ try {
+ readXML(parkpath.str(),*dynamics);
+ dynamics->init();
+ }
+ catch (const sg_exception &e) {
+ //cerr << "unable to read " << parkpath.str() << endl;
+ }
}
- i++;
- }
-}
-
-void FGTaxiSegment::setEnd(FGTaxiNodeVector *nodes)
-{
- FGTaxiNodeVectorIterator i = nodes->begin();
- while (i != nodes->end())
- {
- if (i->getIndex() == endNode)
+ //if (ai_dirs.find(id.c_str()) != ai_dirs.end()
+ // && rwyPrefPath.exists())
+ if (rwyPrefPath.exists())
{
- end = i->getAddress();
- return;
- }
- i++;
- }
-}
-
-// There is probably a computationally cheaper way of
-// doing this.
-void FGTaxiSegment::setTrackDistance()
-{
- double course;
- SGWayPoint first (start->getLongitude(),
- start->getLatitude(),
- 0);
- SGWayPoint second (end->getLongitude(),
- end->getLatitude(),
- 0);
- first.CourseAndDistance(second, &course, &length);
-
-}
-
-bool FGTaxiRoute::next(int *val)
-{
- //for (intVecIterator i = nodes.begin(); i != nodes.end(); i++)
- // cerr << "FGTaxiRoute contains : " << *(i) << endl;
- //cerr << "Offset from end: " << nodes.end() - currNode << endl;
- //if (currNode != nodes.end())
- // cerr << "true" << endl;
- //else
- // cerr << "false" << endl;
-
- if (currNode == nodes.end())
- return false;
- *val = *(currNode);
- currNode++;
- return true;
-};
-/***************************************************************************
- * FGGroundNetwork()
- **************************************************************************/
-
-FGGroundNetwork::FGGroundNetwork()
-{
- hasNetwork = false;
- foundRoute = false;
- totalDistance = 0;
- maxDistance = 0;
-}
-
-void FGGroundNetwork::addSegment(const FGTaxiSegment &seg)
-{
- segments.push_back(seg);
-}
-
-void FGGroundNetwork::addNode(const FGTaxiNode &node)
-{
- nodes.push_back(node);
-}
-
-void FGGroundNetwork::addNodes(FGParkingVec *parkings)
-{
- FGTaxiNode n;
- FGParkingVecIterator i = parkings->begin();
- while (i != parkings->end())
- {
- n.setIndex(i->getIndex());
- n.setLatitude(i->getLatitude());
- n.setLongitude(i->getLongitude());
- nodes.push_back(n);
-
- i++;
- }
-}
-
-
-
-void FGGroundNetwork::init()
-{
- hasNetwork = true;
- FGTaxiSegmentVectorIterator i = segments.begin();
- while(i != segments.end()) {
- //cerr << "initializing node " << i->getIndex() << endl;
- i->setStart(&nodes);
- i->setEnd (&nodes);
- i->setTrackDistance();
- //cerr << "Track distance = " << i->getLength() << endl;
- //cerr << "Track ends at" << i->getEnd()->getIndex() << endl;
- i++;
- }
- //exit(1);
-}
-
-int FGGroundNetwork::findNearestNode(double lat, double lon)
-{
- double minDist = HUGE_VAL;
- double course, dist;
- int index;
- SGWayPoint first (lon,
- lat,
- 0);
-
- for (FGTaxiNodeVectorIterator
- itr = nodes.begin();
- itr != nodes.end(); itr++)
- {
- double course;
- SGWayPoint second (itr->getLongitude(),
- itr->getLatitude(),
- 0);
- first.CourseAndDistance(second, &course, &dist);
- if (dist < minDist)
- {
- minDist = dist;
- index = itr->getIndex();
- //cerr << "Minimum distance of " << minDist << " for index " << index << endl;
+ try {
+ readXML(rwyPrefPath.str(), rwyPrefs);
+ dynamics->setRwyUse(rwyPrefs);
+ }
+ catch (const sg_exception &e) {
+ //cerr << "unable to read " << rwyPrefPath.str() << endl;
+ //exit(1);
+ }
}
+ //exit(1);
}
- return index;
-}
-
-FGTaxiNode *FGGroundNetwork::findNode(int idx)
-{
- for (FGTaxiNodeVectorIterator
- itr = nodes.begin();
- itr != nodes.end(); itr++)
- {
- if (itr->getIndex() == idx)
- return itr->getAddress();
- }
- return 0;
-}
-
-FGTaxiRoute FGGroundNetwork::findShortestRoute(int start, int end)
-{
- foundRoute = false;
- totalDistance = 0;
- FGTaxiNode *firstNode = findNode(start);
- FGTaxiNode *lastNode = findNode(end);
- //prevNode = prevPrevNode = -1;
- //prevNode = start;
- routes.clear();
- traceStack.clear();
- trace(firstNode, end, 0, 0);
- FGTaxiRoute empty;
-
- if (!foundRoute)
- {
- SG_LOG( SG_GENERAL, SG_INFO, "Failed to find route from waypoint " << start << " to " << end );
- exit(1);
- }
- sort(routes.begin(), routes.end());
- //for (intVecIterator i = route.begin(); i != route.end(); i++)
- // {
- // rte->push_back(*i);
- // }
-
- if (routes.begin() != routes.end())
- return *(routes.begin());
- else
- return empty;
+ return dynamics;
}
-void FGGroundNetwork::trace(FGTaxiNode *currNode, int end, int depth, double distance)
-{
- traceStack.push_back(currNode->getIndex());
- totalDistance += distance;
- //cerr << "Starting trace " << depth << " total distance: " << totalDistance<< endl;
- //<< currNode->getIndex() << endl;
-
- // If the current route matches the required end point we found a valid route
- // So we can add this to the routing table
- if (currNode->getIndex() == end)
- {
- //cerr << "Found route : " << totalDistance << "" << " " << *(traceStack.end()-1) << endl;
- routes.push_back(FGTaxiRoute(traceStack,totalDistance));
- traceStack.pop_back();
- if (!(foundRoute))
- maxDistance = totalDistance;
- else
- if (totalDistance < maxDistance)
- maxDistance = totalDistance;
- foundRoute = true;
- totalDistance -= distance;
- return;
- }
-
-
- // search if the currentNode has been encountered before
- // if so, we should step back one level, because it is
- // rather rediculous to proceed further from here.
- // if the current node has not been encountered before,
- // i should point to traceStack.end()-1; and we can continue
- // if i is not traceStack.end, the previous node was found,
- // and we should return.
- // This only works at trace levels of 1 or higher though
- if (depth > 0) {
- intVecIterator i = traceStack.begin();
- while ((*i) != currNode->getIndex()) {
- //cerr << "Route so far : " << (*i) << endl;
- i++;
- }
- if (i != traceStack.end()-1) {
- traceStack.pop_back();
- totalDistance -= distance;
- return;
- }
- // If the total distance from start to the current waypoint
- // is longer than that of a route we can also stop this trace
- // and go back one level.
- if ((totalDistance > maxDistance) && foundRoute)
- {
- //cerr << "Stopping rediculously long trace: " << totalDistance << endl;
- traceStack.pop_back();
- totalDistance -= distance;
- return;
- }
- }
-
- //cerr << "2" << endl;
- if (currNode->getBeginRoute() != currNode->getEndRoute())
- {
- //cerr << "3" << endl;
- for (FGTaxiSegmentPointerVectorIterator
- i = currNode->getBeginRoute();
- i != currNode->getEndRoute();
- i++)
- {
- //cerr << (*i)->getLenght() << endl;
- trace((*i)->getEnd(), end, depth+1, (*i)->getLength());
- // {
- // // cerr << currNode -> getIndex() << " ";
- // route.push_back(currNode->getIndex());
- // return true;
- // }
- }
- }
- else
- {
- SG_LOG( SG_GENERAL, SG_DEBUG, "4" );
- }
- traceStack.pop_back();
- totalDistance -= distance;
- return;
-}
// code to free this list after parsing of apt.dat is finished;
// non-issue at the moment, however, as there are no AI subdirectories
// in the base package.
+//
+// Note: 2005/12/23: This is probably not necessary anymore, because I'm
+// Switching to runtime airport dynamics loading (DT).
FGAirportList::FGAirportList()
{
- ulDir* d;
- ulDirEnt* dent;
- SGPath aid( globals->get_fg_root() );
- aid.append( "/Airports/AI" );
- if((d = ulOpenDir(aid.c_str())) == NULL)
- return;
- while((dent = ulReadDir(d)) != NULL) {
- SG_LOG( SG_GENERAL, SG_DEBUG, "Dent: " << dent->d_name );
- ai_dirs.insert(dent->d_name);
- }
- ulCloseDir(d);
+// ulDir* d;
+// ulDirEnt* dent;
+// SGPath aid( globals->get_fg_root() );
+// aid.append( "/Airports/AI" );
+// if((d = ulOpenDir(aid.c_str())) == NULL)
+// return;
+// while((dent = ulReadDir(d)) != NULL) {
+// SG_LOG( SG_GENERAL, SG_DEBUG, "Dent: " << dent->d_name );
+// ai_dirs.insert(dent->d_name);
+// }
+// ulCloseDir(d);
}
{
FGRunwayPreference rwyPrefs;
FGAirport* a = new FGAirport(id, longitude, latitude, elevation, name, has_metar);
- SGPath parkpath( globals->get_fg_root() );
- parkpath.append( "/Airports/AI/" );
- parkpath.append(id);
- parkpath.append("parking.xml");
-
- SGPath rwyPrefPath( globals->get_fg_root() );
- rwyPrefPath.append( "/Airports/AI/" );
- rwyPrefPath.append(id);
- rwyPrefPath.append("rwyuse.xml");
- if (ai_dirs.find(id.c_str()) != ai_dirs.end()
- && parkpath.exists())
- {
- try {
- readXML(parkpath.str(),*a);
- a->init();
- }
- catch (const sg_exception &e) {
- //cerr << "unable to read " << parkpath.str() << endl;
- }
- }
- if (ai_dirs.find(id.c_str()) != ai_dirs.end()
- && rwyPrefPath.exists())
- {
- try {
- readXML(rwyPrefPath.str(), rwyPrefs);
- a->setRwyUse(rwyPrefs);
- }
- catch (const sg_exception &e) {
- //cerr << "unable to read " << rwyPrefPath.str() << endl;
- //exit(1);
- }
- }
+
airports_by_id[a->getId()] = a;
// try and read in an auxilary file
airports_by_id[id]->setMetar(true);
}
}
+
+// find basic airport location info from airport database
+const FGAirport *fgFindAirportID( const string& id) {
+ const FGAirport* result = NULL;
+ if ( id.length() ) {
+ SG_LOG( SG_GENERAL, SG_INFO, "Searching for airport code = " << id );
+
+ result = globals->get_airports()->search( id );
+
+ if ( result == NULL ) {
+ SG_LOG( SG_GENERAL, SG_ALERT,
+ "Failed to find " << id << " in apt.dat.gz" );
+ return NULL;
+ }
+ } else {
+ return NULL;
+ }
+ SG_LOG( SG_GENERAL, SG_INFO,
+ "Position for " << id << " is ("
+ << result->getLongitude() << ", "
+ << result->getLatitude() << ")" );
+
+ return result;
+}
+
+
+// get airport elevation
+double fgGetAirportElev( const string& id ) {
+
+ // double lon, lat;
+
+ SG_LOG( SG_GENERAL, SG_INFO,
+ "Finding elevation for airport: " << id );
+
+ const FGAirport *a=fgFindAirportID( id);
+ if (a) {
+ return a->getElevation();
+ } else {
+ return -9999.0;
+ }
+}
+
+// get airport position
+Point3D fgGetAirportPos( const string& id ) {
+ // double lon, lat;
+
+ SG_LOG( SG_ATC, SG_INFO,
+ "Finding position for airport: " << id );
+
+ const FGAirport *a = fgFindAirportID( id);
+
+ if (a) {
+ return Point3D(a->getLongitude(), a->getLatitude(), a->getElevation());
+ } else {
+ return Point3D(0.0, 0.0, -9999.0);
+ }
+}
# include <config.h>
#endif
#include <simgear/math/point3d.hxx>
-#include <simgear/route/waypoint.hxx>
+
#include <simgear/compiler.h>
-#include <simgear/xml/easyxml.hxx>
+//#include <simgear/xml/easyxml.hxx>
#include STL_STRING
#include <map>
#include <set>
#include <vector>
+#include "runwayprefs.hxx"
+#include "parking.hxx"
+#include "groundnetwork.hxx"
+#include "dynamics.hxx"
+
SG_USING_STD(string);
SG_USING_STD(map);
SG_USING_STD(set);
SG_USING_STD(vector);
-typedef vector<string> stringVec;
-typedef vector<string>::iterator stringVecIterator;
-typedef vector<string>::const_iterator stringVecConstIterator;
-
-typedef vector<time_t> timeVec;
-typedef vector<time_t>::const_iterator timeVecConstIterator;
-
-
-/***************************************************************************/
-class ScheduleTime {
-private:
- timeVec start;
- timeVec end;
- stringVec scheduleNames;
- double tailWind;
- double crssWind;
-public:
- ScheduleTime() : tailWind(0), crssWind(0) {};
- ScheduleTime(const ScheduleTime &other);
- ScheduleTime &operator= (const ScheduleTime &other);
- string getName(time_t dayStart);
-
- void clear();
- void addStartTime(time_t time) { start.push_back(time); };
- void addEndTime (time_t time) { end. push_back(time); };
- void addScheduleName(const string& sched) { scheduleNames.push_back(sched); };
- void setTailWind(double wnd) { tailWind = wnd; };
- void setCrossWind(double wnd) { tailWind = wnd; };
-
- double getTailWind() { return tailWind; };
- double getCrossWind() { return crssWind; };
-};
-
-//typedef vector<ScheduleTime> ScheduleTimes;
-/*****************************************************************************/
-
-class RunwayList
-{
-private:
- string type;
- stringVec preferredRunways;
-public:
- RunwayList() {};
- RunwayList(const RunwayList &other);
- RunwayList& operator= (const RunwayList &other);
-
- void set(const string&, const string&);
- void clear();
-
- string getType() { return type; };
- stringVec *getRwyList() { return &preferredRunways; };
- string getRwyList(int j) { return preferredRunways[j]; };
-};
-
-typedef vector<RunwayList> RunwayListVec;
-typedef vector<RunwayList>::iterator RunwayListVectorIterator;
-typedef vector<RunwayList>::const_iterator RunwayListVecConstIterator;
-
-
-/*****************************************************************************/
-
-class RunwayGroup
-{
-private:
- string name;
- RunwayListVec rwyList;
- int active;
- //stringVec runwayNames;
- int choice[2];
- int nrActive;
-public:
- RunwayGroup() {};
- RunwayGroup(const RunwayGroup &other);
- RunwayGroup &operator= (const RunwayGroup &other);
-
- void setName(string nm) { name = nm; };
- void add(RunwayList list) { rwyList.push_back(list);};
- void setActive(const string& aptId, double windSpeed, double windHeading, double maxTail, double maxCross);
-
- int getNrActiveRunways() { return nrActive;};
- void getActive(int i, string& name, string& type);
-
- string getName() { return name; };
- void clear() { rwyList.clear(); };
- //void add(string, string);
-};
-
-typedef vector<RunwayGroup> PreferenceList;
-typedef vector<RunwayGroup>::iterator PreferenceListIterator;
-typedef vector<RunwayGroup>::const_iterator PreferenceListConstIterator;
-/******************************************************************************/
-
-class FGRunwayPreference : public XMLVisitor {
-private:
- string value;
- string scheduleName;
-
- ScheduleTime comTimes; // Commercial Traffic;
- ScheduleTime genTimes; // General Aviation;
- ScheduleTime milTimes; // Military Traffic;
- ScheduleTime currTimes; // Needed for parsing;
-
- RunwayList rwyList;
- RunwayGroup rwyGroup;
- PreferenceList preferences;
-
- time_t processTime(const string&);
- bool initialized;
-
-public:
- FGRunwayPreference();
- FGRunwayPreference(const FGRunwayPreference &other);
-
- FGRunwayPreference & operator= (const FGRunwayPreference &other);
- ScheduleTime *getSchedule(const char *trafficType);
- RunwayGroup *getGroup(const string& groupName);
- bool available() { return initialized; };
-
- // Some overloaded virtual XMLVisitor members
- virtual void startXML ();
- virtual void endXML ();
- virtual void startElement (const char * name, const XMLAttributes &atts);
- virtual void endElement (const char * name);
- virtual void data (const char * s, int len);
- virtual void pi (const char * target, const char * data);
- virtual void warning (const char * message, int line, int column);
- virtual void error (const char * message, int line, int column);
-};
-
-double processPosition(const string& pos);
-
-class FGParking {
-private:
- double latitude;
- double longitude;
- double heading;
- double radius;
- int index;
- string parkingName;
- string type;
- string airlineCodes;
-
- bool available;
-
-
-
-public:
- FGParking() { available = true;};
- //FGParking(FGParking &other);
- FGParking(double lat,
- double lon,
- double hdg,
- double rad,
- int idx,
- const string& name,
- const string& tpe,
- const string& codes);
- void setLatitude (const string& lat) { latitude = processPosition(lat); };
- void setLongitude(const string& lon) { longitude = processPosition(lon); };
- void setHeading (double hdg) { heading = hdg; };
- void setRadius (double rad) { radius = rad; };
- void setIndex (int idx) { index = idx; };
- void setName (const string& name) { parkingName = name; };
- void setType (const string& tpe) { type = tpe; };
- void setCodes (const string& codes){ airlineCodes= codes;};
-
- bool isAvailable () { return available;};
- void setAvailable(bool val) { available = val; };
-
- double getLatitude () { return latitude; };
- double getLongitude() { return longitude; };
- double getHeading () { return heading; };
- double getRadius () { return radius; };
- int getIndex () { return index; };
- string getType () { return type; };
- string getCodes () { return airlineCodes;};
- string getName () { return parkingName; };
-
- bool operator< (const FGParking &other) const {return radius < other.radius; };
-};
-
-typedef vector<FGParking> FGParkingVec;
-typedef vector<FGParking>::iterator FGParkingVecIterator;
-typedef vector<FGParking>::const_iterator FGParkingVecConstIterator;
-
-class FGTaxiSegment; // forward reference
-
-typedef vector<FGTaxiSegment> FGTaxiSegmentVector;
-typedef vector<FGTaxiSegment*> FGTaxiSegmentPointerVector;
-typedef vector<FGTaxiSegment>::iterator FGTaxiSegmentVectorIterator;
-typedef vector<FGTaxiSegment*>::iterator FGTaxiSegmentPointerVectorIterator;
-
-/**************************************************************************************
- * class FGTaxiNode
- *************************************************************************************/
-class FGTaxiNode
-{
-private:
- double lat;
- double lon;
- int index;
- FGTaxiSegmentPointerVector next; // a vector to all the segments leaving from this node
-
-public:
- FGTaxiNode();
- FGTaxiNode(double, double, int);
-
- void setIndex(int idx) { index = idx;};
- void setLatitude (double val) { lat = val;};
- void setLongitude(double val) { lon = val;};
- void setLatitude (const string& val) { lat = processPosition(val); };
- void setLongitude(const string& val) { lon = processPosition(val); };
- void addSegment(FGTaxiSegment *segment) { next.push_back(segment); };
-
- double getLatitude() { return lat;};
- double getLongitude(){ return lon;};
-
- int getIndex() { return index; };
- FGTaxiNode *getAddress() { return this;};
- FGTaxiSegmentPointerVectorIterator getBeginRoute() { return next.begin(); };
- FGTaxiSegmentPointerVectorIterator getEndRoute() { return next.end(); };
-};
-
-typedef vector<FGTaxiNode> FGTaxiNodeVector;
-typedef vector<FGTaxiNode>::iterator FGTaxiNodeVectorIterator;
-
-/***************************************************************************************
- * class FGTaxiSegment
- **************************************************************************************/
-class FGTaxiSegment
-{
-private:
- int startNode;
- int endNode;
- double length;
- FGTaxiNode *start;
- FGTaxiNode *end;
- int index;
-
-public:
- FGTaxiSegment();
- FGTaxiSegment(FGTaxiNode *, FGTaxiNode *, int);
-
- void setIndex (int val) { index = val; };
- void setStartNodeRef (int val) { startNode = val; };
- void setEndNodeRef (int val) { endNode = val; };
-
- void setStart(FGTaxiNodeVector *nodes);
- void setEnd (FGTaxiNodeVector *nodes);
- void setTrackDistance();
-
- FGTaxiNode * getEnd() { return end;};
- double getLength() { return length; };
- int getIndex() { return index; };
-
-};
-
-
-typedef vector<int> intVec;
-typedef vector<int>::iterator intVecIterator;
-
-class FGTaxiRoute
-{
-private:
- intVec nodes;
- double distance;
- intVecIterator currNode;
-public:
- FGTaxiRoute() { distance = 0; currNode = nodes.begin(); };
- FGTaxiRoute(intVec nds, double dist) { nodes = nds; distance = dist; currNode = nodes.begin();};
- bool operator< (const FGTaxiRoute &other) const {return distance < other.distance; };
- bool empty () { return nodes.begin() == nodes.end(); };
- bool next(int *val);
-
- void first() { currNode = nodes.begin(); };
-};
-
-typedef vector<FGTaxiRoute> TaxiRouteVector;
-typedef vector<FGTaxiRoute>::iterator TaxiRouteVectorIterator;
-
-/**************************************************************************************
- * class FGGroundNetWork
- *************************************************************************************/
-class FGGroundNetwork
-{
-private:
- bool hasNetwork;
- FGTaxiNodeVector nodes;
- FGTaxiSegmentVector segments;
- //intVec route;
- intVec traceStack;
- TaxiRouteVector routes;
-
- bool foundRoute;
- double totalDistance, maxDistance;
-
-public:
- FGGroundNetwork();
-
- void addNode (const FGTaxiNode& node);
- void addNodes (FGParkingVec *parkings);
- void addSegment(const FGTaxiSegment& seg);
-
- void init();
- bool exists() { return hasNetwork; };
- int findNearestNode(double lat, double lon);
- FGTaxiNode *findNode(int idx);
- FGTaxiRoute findShortestRoute(int start, int end);
- void trace(FGTaxiNode *, int, int, double dist);
-
-};
/***************************************************************************************
*
**************************************************************************************/
-class FGAirport : public XMLVisitor{
+class FGAirport {
private:
string _id;
double _longitude; // degrees
double _latitude; // degrees
double _elevation; // ft
- string _code; // depricated and can be removed
string _name;
bool _has_metar;
- FGParkingVec parkings;
- FGRunwayPreference rwyPrefs;
- FGGroundNetwork groundNetwork;
-
- time_t lastUpdate;
- string prevTrafficType;
- stringVec landing;
- stringVec takeoff;
-
- // Experimental keep a running average of wind dir and speed to prevent
- // Erratic runway changes.
- // Note: I should add these to the copy constructor and assigment operator to be
- // constistent
- double avWindHeading [10];
- double avWindSpeed [10];
-
- string chooseRunwayFallback();
+ FGAirportDynamics *dynamics;
public:
FGAirport();
- FGAirport(const FGAirport &other);
- //operator= (FGAirport &other);
+ // FGAirport(const FGAirport &other);
FGAirport(const string& id, double lon, double lat, double elev, const string& name, bool has_metar);
+ ~FGAirport();
- void init();
- void getActiveRunway(const string& trafficType, int action, string& runway);
- bool getAvailableParking(double *lat, double *lon, double *heading, int *gate, double rad, const string& fltype,
- const string& acType, const string& airline);
- void getParking (int id, double *lat, double* lon, double *heading);
- FGParking *getParking(int i); // { if (i < parkings.size()) return parkings[i]; else return 0;};
- void releaseParking(int id);
- string getParkingName(int i);
string getId() const { return _id;};
const string &getName() const { return _name;};
- //FGAirport *getAddress() { return this; };
- //const string &getName() const { return _name;};
- // Returns degrees
double getLongitude() const { return _longitude;};
// Returns degrees
double getLatitude() const { return _latitude; };
// Returns ft
double getElevation() const { return _elevation;};
bool getMetar() const { return _has_metar;};
- FGGroundNetwork* getGroundNetwork() { return &groundNetwork; };
-
void setId(const string& id) { _id = id;};
void setMetar(bool value) { _has_metar = value; };
- void setRwyUse(const FGRunwayPreference& ref);
-
- // Some overloaded virtual XMLVisitor members
- virtual void startXML ();
- virtual void endXML ();
- virtual void startElement (const char * name, const XMLAttributes &atts);
- virtual void endElement (const char * name);
- virtual void data (const char * s, int len);
- virtual void pi (const char * target, const char * data);
- virtual void warning (const char * message, int line, int column);
- virtual void error (const char * message, int line, int column);
+ FGAirportDynamics *getDynamics();
+private:
+ FGAirport operator=(FGAirport &other);
+ FGAirport(const FGAirport&);
};
typedef map < string, FGAirport* > airport_map;
airport_map airports_by_id;
airport_list airports_array;
- set < string > ai_dirs;
+ //set < string > ai_dirs;
public:
};
+// find basic airport location info from airport database
+const FGAirport *fgFindAirportID( const string& id);
+
+// get airport elevation
+double fgGetAirportElev( const string& id );
+
+// get airport position
+Point3D fgGetAirportPos( const string& id );
#endif // _FG_SIMPLE_HXX
int NewWaypoint( const string& Tgt_Alt )
{
string TgtAptId;
- FGAirport a;
FGFix f;
double alt = 0.0;
}
FGRouteMgr *rm = (FGRouteMgr *)globals->get_subsystem("route-manager");
-
- if ( fgFindAirportID( TgtAptId, &a ) ) {
+ const FGAirport *a = fgFindAirportID( TgtAptId);
+ if (a) {
SG_LOG( SG_GENERAL, SG_INFO,
"Adding waypoint (airport) = " << TgtAptId );
sprintf( NewTgtAirportId, "%s", TgtAptId.c_str() );
- SGWayPoint wp( a.getLongitude(), a.getLatitude(), alt,
+ SGWayPoint wp( a->getLongitude(), a->getLatitude(), alt,
SGWayPoint::WGS84, TgtAptId );
rm->add_waypoint( wp );
_error_count( 0 ),
_stale_count( 0 ),
_dt( 0.0 ),
- _error_dt( 0.0 )
+ _error_dt( 0.0 ),
+ last_apt(0)
{
#if defined(ENABLE_THREADS)
thread = new MetarThread(this);
if ( result.m != NULL ) {
SG_LOG( SG_GENERAL, SG_INFO, "closest station w/ metar = "
<< a->getId());
- last_apt = *a;
+ last_apt = a;
_icao = a->getId();
search_elapsed = 0.0;
fetch_elapsed = 0.0;
latitude->getDoubleValue(),
true );
if ( a ) {
- if ( last_apt.getId() != a->getId()
+ if ( !last_apt || last_apt->getId() != a->getId()
|| fetch_elapsed > same_station_interval_sec )
{
SG_LOG( SG_GENERAL, SG_INFO, "closest station w/ metar = "
<< a->getId());
request_queue.push( a->getId() );
- last_apt = *a;
+ last_apt = a;
_icao = a->getId();
search_elapsed = 0.0;
fetch_elapsed = 0.0;
float same_station_interval_sec;
float search_elapsed;
float fetch_elapsed;
- FGAirport last_apt;
+ const FGAirport *last_apt;
SGPropertyNode *proxy_host;
SGPropertyNode *proxy_port;
SGPropertyNode *proxy_auth;
#include <stdlib.h>
#include <string.h> // strcmp()
-
#if defined( unix ) || defined( __CYGWIN__ )
# include <unistd.h> // for gethostname()
#endif
}
-// find basic airport location info from airport database
-bool fgFindAirportID( const string& id, FGAirport *a ) {
- const FGAirport* result;
- if ( id.length() ) {
- SG_LOG( SG_GENERAL, SG_INFO, "Searching for airport code = " << id );
-
- result = globals->get_airports()->search( id );
-
- if ( result == NULL ) {
- SG_LOG( SG_GENERAL, SG_ALERT,
- "Failed to find " << id << " in apt.dat.gz" );
- return false;
- }
- } else {
- return false;
- }
-
- *a = *result;
-
- SG_LOG( SG_GENERAL, SG_INFO,
- "Position for " << id << " is ("
- << a->getLongitude() << ", "
- << a->getLatitude() << ")" );
- return true;
-}
-
-
-// get airport elevation
-static double fgGetAirportElev( const string& id ) {
- FGAirport a;
- // double lon, lat;
-
- SG_LOG( SG_GENERAL, SG_INFO,
- "Finding elevation for airport: " << id );
-
- if ( fgFindAirportID( id, &a ) ) {
- return a.getElevation();
- } else {
- return -9999.0;
- }
-}
#if 0
// Preset lon/lat given an airport id
static bool fgSetPosFromAirportID( const string& id ) {
- FGAirport a;
+ FGAirport *a;
// double lon, lat;
SG_LOG( SG_GENERAL, SG_INFO,
if ( fgFindAirportID( id, &a ) ) {
// presets
- fgSetDouble("/sim/presets/longitude-deg", a.longitude );
- fgSetDouble("/sim/presets/latitude-deg", a.latitude );
+ fgSetDouble("/sim/presets/longitude-deg", a->longitude );
+ fgSetDouble("/sim/presets/latitude-deg", a->latitude );
// other code depends on the actual postition being set so set
// that as well
- fgSetDouble("/position/longitude-deg", a.longitude );
- fgSetDouble("/position/latitude-deg", a.latitude );
+ fgSetDouble("/position/longitude-deg", a->longitude );
+ fgSetDouble("/position/latitude-deg", a->latitude );
SG_LOG( SG_GENERAL, SG_INFO,
- "Position for " << id << " is (" << a.longitude
- << ", " << a.latitude << ")" );
+ "Position for " << id << " is (" << a->longitude
+ << ", " << a->latitude << ")" );
return true;
} else {
// Set current tower position lon/lat given an airport id
static bool fgSetTowerPosFromAirportID( const string& id, double hdg ) {
- FGAirport a;
+
// tower height hard coded for now...
float towerheight=50.0f;
float fudge_lon = fabs(sin(hdg)) * .003f;
float fudge_lat = .003f - fudge_lon;
- if ( fgFindAirportID( id, &a ) ) {
- fgSetDouble("/sim/tower/longitude-deg", a.getLongitude() + fudge_lon);
- fgSetDouble("/sim/tower/latitude-deg", a.getLatitude() + fudge_lat);
- fgSetDouble("/sim/tower/altitude-ft", a.getElevation() + towerheight);
+ const FGAirport *a = fgFindAirportID( id);
+ if ( a) {
+ fgSetDouble("/sim/tower/longitude-deg", a->getLongitude() + fudge_lon);
+ fgSetDouble("/sim/tower/latitude-deg", a->getLatitude() + fudge_lat);
+ fgSetDouble("/sim/tower/altitude-ft", a->getElevation() + towerheight);
return true;
} else {
return false;
// = fgGetNode("/sim/presets/latitude-deg");
// static const SGPropertyNode *altitude
// = fgGetNode("/sim/presets/altitude-ft");
-
SG_LOG( SG_GENERAL, SG_INFO, "Initialize Subsystems");
SG_LOG( SG_GENERAL, SG_INFO, "========== ==========");
// Save the initial state for future
// reference.
globals->saveInitialState();
-
+
return true;
}