]> git.mxchange.org Git - flightgear.git/commitdiff
Durk Talsma, Olaf Flebbe & Mathias Fröhlich:
authorehofman <ehofman>
Thu, 29 Dec 2005 13:58:21 +0000 (13:58 +0000)
committerehofman <ehofman>
Thu, 29 Dec 2005 13:58:21 +0000 (13:58 +0000)
Split up simple.cxx

26 files changed:
src/AIModel/AIAircraft.cxx
src/AIModel/AIFlightPlanCreate.cxx
src/ATC/AIGAVFRTraffic.cxx
src/ATC/AILocalTraffic.cxx
src/ATC/AIMgr.cxx
src/ATC/ATCDialog.cxx
src/ATC/ATCmgr.cxx
src/ATC/ATCutils.cxx
src/ATC/ATCutils.hxx
src/ATC/commlist.cxx
src/ATC/tower.cxx
src/Airports/Makefile.am
src/Airports/dynamics.cxx [new file with mode: 0644]
src/Airports/dynamics.hxx [new file with mode: 0644]
src/Airports/groundnetwork.cxx [new file with mode: 0644]
src/Airports/groundnetwork.hxx [new file with mode: 0644]
src/Airports/parking.cxx [new file with mode: 0644]
src/Airports/parking.hxx [new file with mode: 0644]
src/Airports/runwayprefs.cxx [new file with mode: 0644]
src/Airports/runwayprefs.hxx [new file with mode: 0644]
src/Airports/simple.cxx
src/Airports/simple.hxx
src/Autopilot/auto_gui.cxx
src/Environment/environment_ctrl.cxx
src/Environment/environment_ctrl.hxx
src/Main/fg_init.cxx

index bbc5b9bfa796031f6e405f3226193b910487bb57..997fcad5764767cd23629fd78cc14af91b87fee7 100644 (file)
@@ -664,8 +664,10 @@ void FGAIAircraft::ProcessFlightPlan( double dt, time_t now )
        //       << 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"))
        //  {
        //    
index 5c0aa56e3697310aed517fb9662f8e9a55a673b1..62ae72da1ce75761496a16eab0424c3a4e0552bc 100644 (file)
@@ -115,14 +115,17 @@ void FGAIFlightPlan::createPushBack(bool firstFlight, FGAirport *dep,
   // 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();
@@ -204,7 +207,7 @@ void FGAIFlightPlan::createTaxi(bool firstFlight, int direction, FGAirport *apt,
       // "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)))
@@ -223,10 +226,10 @@ void FGAIFlightPlan::createTaxi(bool firstFlight, int direction, FGAirport *apt,
       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);
          
@@ -235,9 +238,9 @@ void FGAIFlightPlan::createTaxi(bool firstFlight, int direction, FGAirport *apt,
          // 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
@@ -276,7 +279,7 @@ void FGAIFlightPlan::createTaxi(bool firstFlight, int direction, FGAirport *apt,
              {
                //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
@@ -354,7 +357,7 @@ void FGAIFlightPlan::createTaxi(bool firstFlight, int direction, FGAirport *apt,
       //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;
@@ -364,10 +367,10 @@ void FGAIFlightPlan::createTaxi(bool firstFlight, int direction, FGAirport *apt,
       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);
          
@@ -376,9 +379,9 @@ void FGAIFlightPlan::createTaxi(bool firstFlight, int direction, FGAirport *apt,
          // 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
@@ -417,7 +420,7 @@ void FGAIFlightPlan::createTaxi(bool firstFlight, int direction, FGAirport *apt,
              {
                //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
@@ -514,7 +517,7 @@ void FGAIFlightPlan::createTakeOff(bool firstFlight, FGAirport *apt, double spee
        // "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)))
@@ -609,7 +612,7 @@ void FGAIFlightPlan::createClimb(bool firstFlight, FGAirport *apt, double speed,
       // "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)))
@@ -708,7 +711,7 @@ void FGAIFlightPlan::createCruise(bool firstFlight, FGAirport *dep, FGAirport *a
  
   //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)))
@@ -787,7 +790,7 @@ void FGAIFlightPlan::createDecent(FGAirport *apt)
   //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)))
@@ -943,7 +946,7 @@ void FGAIFlightPlan::createParking(FGAirport *apt)
   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; 
index 72c7685a51c50322d015b244dbc3b4e3a93be3bf..c5df6d2402d4c9520d5a10b48c8b4ac9cc01b4fd 100644 (file)
@@ -79,7 +79,7 @@ bool FGAIGAVFRTraffic::Init(const Point3D& pt, const string& destID, const strin
        _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
@@ -218,7 +218,7 @@ void FGAIGAVFRTraffic::FlyPlane(double dt) {
                                        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';
@@ -246,7 +246,7 @@ void FGAIGAVFRTraffic::FlyPlane(double dt) {
                                        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) {
@@ -254,7 +254,7 @@ void FGAIGAVFRTraffic::FlyPlane(double dt) {
                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) {
@@ -265,9 +265,9 @@ void FGAIGAVFRTraffic::FlyPlane(double dt) {
                                //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';
@@ -437,20 +437,20 @@ Point3D FGAIGAVFRTraffic::GetPatternApproachPos() {
                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';
index c8caac821946c6d8f78031921dd950f46ba40464..997db2a94ad9fcfda86eb8f95a1b223298e69ded 100644 (file)
@@ -156,7 +156,7 @@ void FGAILocalTraffic::GetAirportDetails(const string& id) {
                _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.
@@ -1069,8 +1069,8 @@ void FGAILocalTraffic::FlyTrafficPattern(double dt) {
                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;
index 3c36cde91721b5996538cda2f8858e6be783599a..022e094879dadd55c49bac3e5579c002c3a88a3b 100644 (file)
@@ -24,7 +24,6 @@
 #include <Main/fg_props.hxx>
 #include <Main/globals.hxx>
 #include <simgear/math/sg_random.h>
-
 #include <list>
 
 #ifdef _MSC_VER
@@ -131,9 +130,9 @@ void FGAIMgr::init() {
                        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);
@@ -159,7 +158,7 @@ void FGAIMgr::init() {
        /*
        // 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
@@ -209,7 +208,7 @@ void FGAIMgr::update(double dt) {
                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()) {
@@ -237,14 +236,14 @@ void FGAIMgr::update(double dt) {
                        //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;
                                        }
@@ -331,8 +330,8 @@ void FGAIMgr::GenerateSimpleAirportTraffic(const string& ident, double min_dist)
        /*
        // 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!
@@ -340,7 +339,7 @@ void FGAIMgr::GenerateSimpleAirportTraffic(const string& ident, double min_dist)
        }
        */
        
-       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.
@@ -554,7 +553,7 @@ void FGAIMgr::SearchByPos(double range) {
                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;
index 0f1bc8e652c4bba38acbee0ec0c83cbc2af2f225..b54679d5cdb1a6ea3755b0c3c6582bcc5466986d 100644 (file)
@@ -365,8 +365,8 @@ void FGATCDialog::FreqDisplay(string& 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;
@@ -379,7 +379,7 @@ void FGATCDialog::FreqDisplay(string& ident) {
        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();
index 6aa95a547c2ae743bb89d352422a048420280bf2..ff348c2ce43926eaebcb544141b349e78d33fff2 100644 (file)
@@ -21,7 +21,6 @@
 #include <simgear/misc/sg_path.hxx>
 #include <simgear/debug/logstream.hxx>
 #include <Airports/simple.hxx>
-
 #include "ATCmgr.hxx"
 #include "commlist.hxx"
 #include "ATCdisplay.hxx"
@@ -216,14 +215,14 @@ bool FGATCMgr::AIRegisterAirport(const string& ident) {
                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;
@@ -266,13 +265,13 @@ bool FGATCMgr::CommRegisterAirport(const string& ident, int chan, const atc_type
                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);
index 5387880c74ccd4808160f18f21db9bce9cbb3936..ab561acb321991533bd10cda597cfc8f1fad9a4d 100644 (file)
@@ -291,67 +291,6 @@ double GetAngleDiff_deg( const double &a1, const double &a2) {
   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) {
index 2acfc9d186fff567522dbf19fe7dc9c16ece1ddd..85cb65841bc30d53742f225ae2d049c9e619d314 100644 (file)
@@ -92,25 +92,6 @@ void dclBoundHeading(double &hdg);
 // 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
index af2da411752a2ff95f4e4d2dd946ca0ffc871c3b..6e977149368d7abe4b292b31b351056987ce6759 100644 (file)
@@ -246,8 +246,8 @@ double FGCommList::FindClosest( double lon, double lat, double elev, ATCData& ad
                                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) {
@@ -273,10 +273,10 @@ double FGCommList::FindClosest( double lon, double lat, double elev, ATCData& ad
 // 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()) {
index 4b8115df64fa45072cf76bedeea020dc96ff77d4..17aeb9ab0edb2c7b5d5a2ea14072177eeddba3bb 100644 (file)
@@ -291,7 +291,7 @@ void FGTower::Init() {
        // 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();
index 7a92691f96ffa8548708a105a369e1ba91751eee..bb9e960f7a685fdf53ff26e1818d8d1455450fb5 100644 (file)
@@ -5,7 +5,11 @@ noinst_PROGRAMS = calc_loc
 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)
diff --git a/src/Airports/dynamics.cxx b/src/Airports/dynamics.cxx
new file mode 100644 (file)
index 0000000..e8eb6f6
--- /dev/null
@@ -0,0 +1,630 @@
+// 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));
+}
diff --git a/src/Airports/dynamics.hxx b/src/Airports/dynamics.hxx
new file mode 100644 (file)
index 0000000..3c787a9
--- /dev/null
@@ -0,0 +1,101 @@
+// 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
diff --git a/src/Airports/groundnetwork.cxx b/src/Airports/groundnetwork.cxx
new file mode 100644 (file)
index 0000000..fd41d8a
--- /dev/null
@@ -0,0 +1,337 @@
+// 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;
+}
+
diff --git a/src/Airports/groundnetwork.hxx b/src/Airports/groundnetwork.hxx
new file mode 100644 (file)
index 0000000..8cf1baa
--- /dev/null
@@ -0,0 +1,164 @@
+// 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
diff --git a/src/Airports/parking.cxx b/src/Airports/parking.cxx
new file mode 100644 (file)
index 0000000..b846a13
--- /dev/null
@@ -0,0 +1,102 @@
+// 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;
+}
diff --git a/src/Airports/parking.hxx b/src/Airports/parking.hxx
new file mode 100644 (file)
index 0000000..278d907
--- /dev/null
@@ -0,0 +1,97 @@
+// 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
diff --git a/src/Airports/runwayprefs.cxx b/src/Airports/runwayprefs.cxx
new file mode 100644 (file)
index 0000000..f98e965
--- /dev/null
@@ -0,0 +1,558 @@
+// 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;
+}
diff --git a/src/Airports/runwayprefs.hxx b/src/Airports/runwayprefs.hxx
new file mode 100644 (file)
index 0000000..17148de
--- /dev/null
@@ -0,0 +1,159 @@
+// 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
index 464c32fea2c899f00d22a273f69b8757380ac357..36459fd16daf998fbb70d5767a58b63562dc54db 100644 (file)
@@ -44,6 +44,7 @@
 #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>
@@ -57,563 +58,8 @@ SG_USING_STD(sort);
 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;
-}
 
 
 /***************************************************************************
@@ -621,39 +67,9 @@ FGParking::FGParking(double lat,
  ***************************************************************************/
 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)
 {
@@ -662,826 +78,67 @@ FGAirport::FGAirport(const string &id, double lon, double lat, double elev, cons
   _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;
-}
 
 
 
@@ -1495,19 +152,22 @@ void FGGroundNetwork::trace(FGTaxiNode *currNode, int end, int depth, double dis
 // 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);
 }
 
 
@@ -1525,38 +185,7 @@ void FGAirportList::add( const string &id, const double longitude,
 {
     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
@@ -1646,3 +275,60 @@ void FGAirportList::has_metar( const string &id ) {
         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);
+    }
+}
index 774f69118608ee770de1612a509c757c7c7811a9..b6b255fef186497ce4ec7d8adf10bb27364f2b16 100644 (file)
 #  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;
@@ -454,7 +111,7 @@ private:
 
     airport_map airports_by_id;
     airport_list airports_array;
-    set < string > ai_dirs;
+  //set < string > ai_dirs;
 
 public:
 
@@ -514,6 +171,14 @@ 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
 
index e7ae0a45dc032fc1c1952674ed0b2b474151667e..ce88be3416beff2db4452bf113bf1653294fbf89 100644 (file)
@@ -644,7 +644,6 @@ void TgtAptDialog_OK (puObject *)
 int NewWaypoint( const string& Tgt_Alt )
 {
   string TgtAptId;
-  FGAirport a;
   FGFix f;
 
   double alt = 0.0;
@@ -661,15 +660,15 @@ int NewWaypoint( const string& Tgt_Alt )
   }
 
   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 );
 
index 87b79544aa9245e98c86652b810fd5e7565a68cb..310ba7d722c58a7d75c6f291be0ce2a9060db6dd 100644 (file)
@@ -328,7 +328,8 @@ FGMetarEnvironmentCtrl::FGMetarEnvironmentCtrl ()
       _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);
@@ -412,7 +413,7 @@ FGMetarEnvironmentCtrl::init ()
             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;
@@ -470,13 +471,13 @@ FGMetarEnvironmentCtrl::update(double delta_time_sec)
                              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;
index c38e033fcb317f9678ca3a3bec8bdb5887e68625..879c902bb48669d0c47490a25aea84a579183801 100644 (file)
@@ -173,7 +173,7 @@ private:
     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;
index 6e292a0c23e680c6c2b7b44541aa22ca7d2b3563..834c2dc6cf7536591a80375ad5f86104c0f1a88a 100644 (file)
@@ -35,7 +35,6 @@
 #include <stdlib.h>
 #include <string.h>             // strcmp()
 
-
 #if defined( unix ) || defined( __CYGWIN__ )
 #  include <unistd.h>           // for gethostname()
 #endif
@@ -625,48 +624,7 @@ bool fgInitConfig ( int argc, char **argv ) {
 }
 
 
-// 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 
@@ -676,7 +634,7 @@ static double fgGetAirportElev( const string& id ) {
 
 // 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,
@@ -684,17 +642,17 @@ static bool fgSetPosFromAirportID( const string& id ) {
 
     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 {
@@ -706,7 +664,7 @@ static bool fgSetPosFromAirportID( const string& id ) {
 
 // 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;
 
@@ -714,10 +672,11 @@ static bool fgSetTowerPosFromAirportID( const string& id, double hdg ) {
     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;
@@ -1578,7 +1537,6 @@ bool fgInitSubsystems() {
     //     = 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, "========== ==========");
 
@@ -1879,7 +1837,7 @@ bool fgInitSubsystems() {
                                 // Save the initial state for future
                                 // reference.
     globals->saveInitialState();
-
+    
     return true;
 }