]> git.mxchange.org Git - flightgear.git/commitdiff
Durk Talsma:
authorehofman <ehofman>
Thu, 10 Feb 2005 09:01:51 +0000 (09:01 +0000)
committerehofman <ehofman>
Thu, 10 Feb 2005 09:01:51 +0000 (09:01 +0000)
I just heard from John Wojnaroski that you and he are going to work on getting
a flightgear demo machine up for the linux expo thursday and Friday. John
indicated that he would very much like to get a CVS version with the new
traffic code up and running before the expo.

29 files changed:
src/AIModel/AIAircraft.cxx
src/AIModel/AIAircraft.hxx
src/AIModel/AIBase.hxx
src/AIModel/AIFlightPlan.cxx
src/AIModel/AIFlightPlan.hxx
src/AIModel/AIFlightPlanCreate.cxx [new file with mode: 0644]
src/AIModel/AIManager.cxx
src/AIModel/Makefile.am
src/ATC/AIMgr.cxx
src/ATC/ATCDialog.cxx
src/ATC/ATCmgr.cxx
src/ATC/ATCutils.cxx
src/ATC/commlist.cxx
src/Airports/apt_loader.cxx
src/Airports/simple.cxx
src/Airports/simple.hxx
src/Autopilot/auto_gui.cxx
src/Environment/environment_ctrl.cxx
src/GUI/AirportList.cxx
src/GUI/Makefile.am
src/Instrumentation/gps.cxx
src/Main/fg_init.cxx
src/Navaids/navdb.cxx
src/Traffic/SchedFlight.cxx
src/Traffic/SchedFlight.hxx
src/Traffic/Schedule.cxx
src/Traffic/Schedule.hxx
src/Traffic/TrafficMgr.cxx
src/Traffic/TrafficMgr.hxx

index 4dc084bcc935ac607a4f8a27f840f5c1e5081762..da2159b21ed40a3df1fbb25a3fb66353a07f04de 100644 (file)
 #endif
 
 #include <simgear/math/point3d.hxx>
+#include <simgear/route/waypoint.hxx>
 #include <Main/fg_props.hxx>
 #include <Main/globals.hxx>
+#include <Main/viewer.hxx>
 #include <Scenery/scenery.hxx>
+#include <Scenery/tilemgr.hxx>
+
 #include <string>
 #include <math.h>
 #include <time.h>
@@ -33,7 +37,7 @@
 SG_USING_STD(string);
 
 #include "AIAircraft.hxx"
-
+   static string tempReg;
 //
 // accel, decel, climb_rate, descent_rate, takeoff_speed, climb_speed,
 // cruise_speed, descent_speed, land_speed
@@ -54,17 +58,24 @@ const FGAIAircraft::PERF_STRUCT FGAIAircraft::settings[] = {
 
 FGAIAircraft::FGAIAircraft(FGAIManager* mgr, FGAISchedule *ref) {
   trafficRef = ref;
+  if (trafficRef)
+    groundOffset = trafficRef->getGroundOffset();
+  else
+    groundOffset = 0;
    manager = mgr;   
    _type_str = "aircraft";
    _otype = otAircraft;
    fp = 0;
    dt_count = 0;
+   dt_elev_count = 0;
    use_perf_vs = true;
    isTanker = false;
 
    // set heading and altitude locks
    hdg_lock = false;
    alt_lock = false;
+   roll = 0;
+   headingChangeRate = 0.0;
 }
 
 
@@ -118,13 +129,24 @@ void FGAIAircraft::Run(double dt) {
 
    if (fp) 
      {
-       ProcessFlightPlan(dt);
        time_t now = time(NULL) + fgGetLong("/sim/time/warp");
+       ProcessFlightPlan(dt, now);
        if (now < fp->getStartTime())
-        return;
-       //ProcessFlightPlan(dt);
+        {
+          // Do execute Ground elev for inactive aircraft, so they
+          // Are repositioned to the correct ground altitude when the user flies within visibility range.
+          if (no_roll)
+            {
+              Transform();         // make sure aip is initialized.
+              getGroundElev(dt); // make sure it's exectuted first time around, so force a large dt value
+              //getGroundElev(dt); // Need to do this twice.
+              //cerr << trafficRef->getRegistration() << " Setting altitude to " << tgt_altitude << endl;
+              setAltitude(tgt_altitude);
+            }
+          return;
+        }
      }
-       
+  
    double turn_radius_ft;
    double turn_circum_ft;
    double speed_north_deg_sec;
@@ -133,11 +155,19 @@ void FGAIAircraft::Run(double dt) {
    double alpha;
 
    // adjust speed
-   double speed_diff = tgt_speed - speed;
+   double speed_diff; //= tgt_speed - speed;
+   if (!no_roll)
+     {
+       speed_diff = tgt_speed - speed;
+     }
+   else
+     {
+       speed_diff = groundTargetSpeed - speed;
+     }
    if (fabs(speed_diff) > 0.2) {
      if (speed_diff > 0.0) speed += performance->accel * dt;
      if (speed_diff < 0.0) {
-        if (!no_roll) {
+       if (no_roll) { // was (!no_roll) but seems more logical this way (ground brakes).
            speed -= performance->decel * dt * 3;
         } else {
            speed -= performance->decel * dt;
@@ -154,19 +184,98 @@ void FGAIAircraft::Run(double dt) {
    // set new position
    pos.setlat( pos.lat() + speed_north_deg_sec * dt);
    pos.setlon( pos.lon() + speed_east_deg_sec * dt); 
+   //if (!(finite(pos.lat()) && finite(pos.lon())))
+   //  {
+   //    cerr << "Position is not finite" << endl;
+   //    cerr << "speed = " << speed << endl;
+   //    cerr << "dt" << dt << endl;
+   //    cerr << "heading " << hdg << endl;
+   //    cerr << "speed east " << speed_east_deg_sec << endl;
+   //    cerr << "speed nrth " << speed_north_deg_sec << endl;
+   //    cerr << "deg_lat    " << ft_per_deg_lat << endl;
+   //    cerr << "deg_lon    " << ft_per_deg_lon << endl;
+   //  }
 
    // adjust heading based on current bank angle
+   if (roll == 0.0) 
+     roll = 0.01;
    if (roll != 0.0) {
-     turn_radius_ft = 0.088362 * speed * speed
-                       / tan( fabs(roll) / SG_RADIANS_TO_DEGREES );
-     turn_circum_ft = SGD_2PI * turn_radius_ft;
-     dist_covered_ft = speed * 1.686 * dt; 
-     alpha = dist_covered_ft / turn_circum_ft * 360.0;
-     hdg += alpha * sign( roll );
-     if ( hdg > 360.0 ) hdg -= 360.0;
-     if ( hdg < 0.0) hdg += 360.0;
+     // double turnConstant;
+     //if (no_roll)
+     //  turnConstant = 0.0088362;
+     //else 
+     //  turnConstant = 0.088362;
+     // If on ground, calculate heading change directly
+     if (no_roll) {
+       double headingDiff = fabs(hdg-tgt_heading);
+      
+       if (headingDiff > 180)
+        headingDiff = fabs(headingDiff - 360);
+       groundTargetSpeed = tgt_speed - (tgt_speed * (headingDiff/45));
+       if (sign(groundTargetSpeed) != sign(tgt_speed))
+        groundTargetSpeed = 0.21 * sign(tgt_speed); // to prevent speed getting stuck in 'negative' mode
+       if (headingDiff > 30.0)
+        {
+          
+          headingChangeRate += dt * sign(roll); // invert if pushed backward
+          // Print some debug statements to find out why aircraft may get stuck
+          // forever turning
+          //if (trafficRef->getDepartureAirport()->getId() == string("EHAM"))
+          //  {
+          //cerr << "Turning : " << trafficRef->getRegistration()
+          //cerr <<  " Speed = " << speed << " Heading " << hdg 
+          //<< " Target Heading " << tgt_heading 
+          //   << " Lead Distance " <<  fp->getLeadDistance()
+          //   << " Distance to go " 
+          //   << fp->getDistanceToGo(pos.lat(), pos.lon(), fp->getCurrentWaypoint())
+          //   << "waypoint name " << fp->getCurrentWaypoint()->name
+          //   << endl;
+          //}
+          if (headingChangeRate > 30) 
+            { 
+              headingChangeRate = 30;
+            }
+          else if (headingChangeRate < -30)
+            {
+              headingChangeRate = -30;
+            }
+        }
+       else
+        {
+          if (fabs(headingChangeRate) > headingDiff)
+            headingChangeRate = headingDiff*sign(roll);
+          else
+            headingChangeRate += dt * sign(roll);
+        }
+       hdg += headingChangeRate * dt;
+       //cerr << "On ground. Heading: " << hdg << ". Target Heading: " << tgt_heading << ". Target speed: " << groundTargetSpeed << ". heading change rate" << headingChangeRate << endl;
+     }
+     else {
+       if (fabs(speed) > 1.0) {
+        turn_radius_ft = 0.088362 * speed * speed
+          / tan( fabs(roll) / SG_RADIANS_TO_DEGREES );
+       }
+       else
+        {
+          turn_radius_ft = 1.0; // Check if turn_radius_ft == 0; this might lead to a division by 0.
+        }
+       turn_circum_ft = SGD_2PI * turn_radius_ft;
+       dist_covered_ft = speed * 1.686 * dt; 
+       alpha = dist_covered_ft / turn_circum_ft * 360.0;
+       hdg += alpha * sign(roll);
+     }
+     while ( hdg > 360.0 ) {
+       hdg -= 360.0;
+       spinCounter++;
+     }
+     while ( hdg < 0.0) 
+       {
+        hdg += 360.0;
+        spinCounter--;
+       }
    }
-
+     
+   
    // adjust target bank angle if heading lock engaged
    if (hdg_lock) {
      double bank_sense = 0.0;
@@ -174,7 +283,7 @@ void FGAIAircraft::Run(double dt) {
      if (diff > 180) diff = fabs(diff - 360);
      double sum = hdg + diff;
      if (sum > 360.0) sum -= 360.0;
-     if (fabs(sum - tgt_heading) < 1.0) { 
+     if (fabs(sum - tgt_heading) < 1.0) {
        bank_sense = 1.0;   // right turn
      } else {
        bank_sense = -1.0;  // left turn
@@ -184,6 +293,27 @@ void FGAIAircraft::Run(double dt) {
      } else {
          tgt_roll = 30.0 * bank_sense;
      }
+     if ((fabs((double) spinCounter) > 1) && (diff > 30))
+       {
+        tgt_speed *= 0.999; // Ugly hack: If aircraft get stuck, they will continually spin around.
+        // The only way to resolve this is to make them slow down. 
+        //if (tempReg.empty())
+        //  tempReg = trafficRef->getRegistration();
+        //if (trafficRef->getRegistration() == tempReg)
+        //  {
+        //    cerr << trafficRef->getRegistration() 
+        //       << " appears to be spinning: " << spinCounter << endl
+        //       << " speed          " << speed << endl
+        //       << " heading        " << hdg << endl
+        //       << " lead distance  " << fp->getLeadDistance() << endl
+        //       << " waypoint       " << fp->getCurrentWaypoint()->name
+        //       << " target heading " << tgt_heading << endl
+        //       << " lead in angle  " << fp->getLeadInAngle()<< endl
+        //       << " roll           " << roll << endl
+        //       << " target_roll    " << tgt_roll << endl;
+            
+        //  }
+       }
    }
 
    // adjust bank angle, use 9 degrees per second
@@ -191,6 +321,8 @@ void FGAIAircraft::Run(double dt) {
    if (fabs(bank_diff) > 0.2) {
      if (bank_diff > 0.0) roll += 9.0 * dt;
      if (bank_diff < 0.0) roll -= 9.0 * dt;
+     //while (roll > 180) roll -= 360;
+     //while (roll < 180) roll += 360;
    }
 
    // adjust altitude (meters) based on current vertical speed (fpm)
@@ -198,6 +330,11 @@ void FGAIAircraft::Run(double dt) {
    pos.setelev(altitude * SG_FEET_TO_METER);  
    double altitude_ft = altitude;
 
+   // adjust target Altitude, based on ground elevation when on ground
+   if (no_roll)
+     {
+       getGroundElev(dt);
+     }
    // find target vertical speed if altitude lock engaged
    if (alt_lock && use_perf_vs) {
      if (altitude_ft < tgt_altitude) {
@@ -303,9 +440,28 @@ void FGAIAircraft::SetFlightPlan(FGAIFlightPlan *f) {
   fp = f;
 }
 
-void FGAIAircraft::ProcessFlightPlan( double dt ) {
+void FGAIAircraft::ProcessFlightPlan( double dt, time_t now ) 
+{
+  bool eraseWaypoints;
+  if (trafficRef)
+    {
+//       FGAirport *arr;
+//       FGAirport *dep;
+      eraseWaypoints = true;
+//       cerr << trafficRef->getRegistration();
+//       cerr << "Departure airport " << endl;
+//       dep = trafficRef->getDepartureAirport();
+//       if (dep)
+//     cerr << dep->getId() << endl;
+//       cerr << "Arrival   airport " << endl;
+//       arr = trafficRef->getArrivalAirport();
+//       if (arr)
+//     cerr << arr->getId() <<endl << endl;;
+     }
+  else
+    eraseWaypoints = false;
 
+  //cerr << "Processing Flightplan" << endl;
   FGAIFlightPlan::waypoint* prev = 0; // the one behind you
   FGAIFlightPlan::waypoint* curr = 0; // the one ahead
   FGAIFlightPlan::waypoint* next = 0; // the next plus 1
@@ -313,118 +469,483 @@ void FGAIAircraft::ProcessFlightPlan( double dt ) {
   curr = fp->getCurrentWaypoint();
   next = fp->getNextWaypoint();
   dt_count += dt;
-
+  
   if (!prev) {  //beginning of flightplan, do this initialization once
-    fp->IncrementWaypoint();
+    //setBank(0.0);
+    spinCounter = 0;
+    tempReg = "";
+    //prev_dist_to_go = HUGE;
+    //cerr << "Before increment " << curr-> name << endl;
+    fp->IncrementWaypoint(eraseWaypoints); 
+    //prev = fp->getPreviousWaypoint(); //first waypoint
+    //curr = fp->getCurrentWaypoint();  //second waypoint
+    //next = fp->getNextWaypoint();     //third waypoint (might not exist!) 
+    //cerr << "After increment " << prev-> name << endl;
+    if (!(fp->getNextWaypoint()) && trafficRef)
+      {
+       loadNextLeg();
+      }
+    //cerr << "After load " << prev-> name << endl;
     prev = fp->getPreviousWaypoint(); //first waypoint
     curr = fp->getCurrentWaypoint();  //second waypoint
     next = fp->getNextWaypoint();     //third waypoint (might not exist!) 
+    //cerr << "After load " << prev-> name << endl;
     setLatitude(prev->latitude);
     setLongitude(prev->longitude);
     setSpeed(prev->speed);
     setAltitude(prev->altitude);
-    setHeading(fp->getBearing(prev->latitude, prev->longitude, curr));
-    if (next) fp->setLeadDistance(speed, hdg, curr, next);
+    if (prev->speed > 0.0)
+      setHeading(fp->getBearing(prev->latitude, prev->longitude, curr));
+    else
+      {
+       setHeading(fp->getBearing(curr->latitude, curr->longitude, prev));
+      }
+    // If next doesn't exist, as in incrementally created flightplans for 
+    // AI/Trafficmanager created plans, 
+    // Make sure lead distance is initialized otherwise
+    if (next) 
+      fp->setLeadDistance(speed, hdg, curr, next);
     
     if (curr->crossat > -1000.0) { //use a calculated descent/climb rate
-        use_perf_vs = false;
-        tgt_vs = (curr->crossat - prev->altitude)/
-                 (fp->getDistanceToGo(pos.lat(), pos.lon(), curr)/
-                                      6076.0/prev->speed*60.0);
+      use_perf_vs = false;
+      tgt_vs = (curr->crossat - prev->altitude)/
+       (fp->getDistanceToGo(pos.lat(), pos.lon(), curr)/
+        6076.0/prev->speed*60.0);
         tgt_altitude = curr->crossat;
     } else {
-        use_perf_vs = true;
-        tgt_altitude = prev->altitude;
+      use_perf_vs = true;
+      tgt_altitude = prev->altitude;
     }
     alt_lock = hdg_lock = true;
     no_roll = prev->on_ground;
+    if (no_roll)
+      {
+       Transform();         // make sure aip is initialized.
+       getGroundElev(60.1); // make sure it's exectuted first time around, so force a large dt value
+       //getGroundElev(60.1); // Need to do this twice.
+       //cerr << trafficRef->getRegistration() << " Setting altitude to " << tgt_altitude << endl;
+       setAltitude(tgt_altitude);
+      }
+    prevSpeed = 0;
     //cout << "First waypoint:  " << prev->name << endl;
     //cout << "  Target speed:    " << tgt_speed << endl;
     //cout << "  Target altitude: " << tgt_altitude << endl;
     //cout << "  Target heading:  " << tgt_heading << endl << endl;       
+    //cerr << "Done Flightplan init" << endl;
     return;  
   } // end of initialization
-
+  
   // let's only process the flight plan every 100 ms.
-  if (dt_count < 0.1) {
-    return;
-  } else {
-    dt_count = 0;
-
-    // check to see if we've reached the lead point for our next turn
-    double dist_to_go = fp->getDistanceToGo(pos.lat(), pos.lon(), curr); 
-    double lead_dist = fp->getLeadDistance();
-    if (lead_dist < (2*speed)) lead_dist = 2*speed;  //don't skip over the waypoint
-    //cout << "dist_to_go: " << dist_to_go << ",  lead_dist: " << lead_dist << endl;
-
-    if ( dist_to_go < lead_dist ) {
-      if (curr->finished) {  //end of the flight plan, so terminate
-         if (trafficRef)
-           {
-             delete fp;
-             //time_t now = time(NULL) + fgGetLong("/sim/time/warp");
-             trafficRef->next();
-
-             FGAIModelEntity entity;
-              entity.m_class = "jet_transport";
-              //entity.path = modelPath.c_str();
-              entity.flightplan = "none";
-              entity.latitude = _getLatitude();
-              entity.longitude = _getLongitude();
-              entity.altitude = trafficRef->getCruiseAlt() * 100; // convert from FL to feet
-              entity.speed = 450;
-             //entity.fp = new FGAIFlightPlan(&entity, courseToDest, i->getDepartureTime(), dep, arr);
-             entity.fp = new FGAIFlightPlan(&entity, 
-                                            999,  // A hack
-                                            trafficRef->getDepartureTime(), 
-                                            trafficRef->getDepartureAirport(), 
-                                            trafficRef->getArrivalAirport());
-             SetFlightPlan(entity.fp);
-           }
-         else 
-           {
-             setDie(true);
-             return;
-           }
+  if ((dt_count < 0.1) || (now < fp->getStartTime()))
+    {
+      //cerr  << "done fp dt" << endl;
+      return;
+    } else {
+      dt_count = 0;
+    }
+  // check to see if we've reached the lead point for our next turn
+  double dist_to_go = fp->getDistanceToGo(pos.lat(), pos.lon(), curr);
+  
+  //cerr << "2" << endl;
+  double lead_dist = fp->getLeadDistance();
+  //cerr << " Distance : " << dist_to_go << ": Lead distance " << lead_dist << endl;
+  // experimental: Use fabs, because speed can be negative (I hope) during push_back.
+  if (lead_dist < fabs(2*speed)) 
+    {
+      lead_dist = fabs(2*speed);  //don't skip over the waypoint
+      //cerr << "Extending lead distance to " << lead_dist << endl;
+    } 
+//   FGAirport * apt = trafficRef->getDepartureAirport();
+//   if ((dist_to_go > prev_dist_to_go) && trafficRef && apt)
+//     {
+//       if (apt->getId() == string("EHAM"))
+//     cerr << "Alert: " << trafficRef->getRegistration() << " is moving away from waypoint " << curr->name  << endl
+//          << "Target heading : " << tgt_heading << "act heading " << hdg << " Tgt speed : " << tgt_speed << endl
+//          << "Lead distance : " << lead_dist  << endl
+//          << "Distance to go: " << dist_to_go << endl;
+      
+//     }
+  prev_dist_to_go = dist_to_go;
+  //cerr << "2" << endl;
+  //if (no_roll)
+  //  lead_dist = 10.0;
+  //cout << "Leg : " << (fp->getLeg()-1) << ". dist_to_go: " << dist_to_go << ",  lead_dist: " << lead_dist << ", tgt_speed " << tgt_speed << ", tgt_heading " << tgt_heading << " speed " << speed << " hdg " << hdg << ". Altitude "  << altitude << " TAget alt :" << tgt_altitude << endl;
+  
+  if ( dist_to_go < lead_dist ) {
+    //prev_dist_to_go = HUGE;
+    // For traffic manager generated aircraft: 
+    // check if the aircraft flies of of user range. And adjust the
+    // Current waypoint's elevation according to Terrain Elevation
+    if (curr->finished) {  //end of the flight plan
+      {
+       setDie(true);
+       //cerr << "Done die end of fp" << endl;
       }
-       // we've reached the lead-point for the waypoint ahead 
-      if (next) tgt_heading = fp->getBearing(curr, next);  
-      fp->IncrementWaypoint();
-      prev = fp->getPreviousWaypoint();
-      curr = fp->getCurrentWaypoint();
-      next = fp->getNextWaypoint();
-      if (next) fp->setLeadDistance(speed, tgt_heading, curr, next);
-      if (curr->crossat > -1000.0) {
-        use_perf_vs = false;
-        tgt_vs = (curr->crossat - altitude)/
-                 (fp->getDistanceToGo(pos.lat(), pos.lon(), curr)/6076.0/speed*60.0);
-        tgt_altitude = curr->crossat;
-      } else {
-        use_perf_vs = true;
-        tgt_altitude = prev->altitude;
+      return;
+    }
+    
+    // we've reached the lead-point for the waypoint ahead 
+    //cerr << "4" << endl;
+    //cerr << "Situation after lead point" << endl;
+    //cerr << "Prviious: " << prev->name << endl;
+    //cerr << "Current : " << curr->name << endl;
+    //cerr << "Next    : " << next->name << endl;
+    if (next) 
+      {
+       tgt_heading = fp->getBearing(curr, next);  
+       spinCounter = 0;
+      }
+    fp->IncrementWaypoint(eraseWaypoints);
+    if (!(fp->getNextWaypoint()) && trafficRef)
+      {
+       loadNextLeg();
       }
-      tgt_speed = prev->speed;
-      hdg_lock = alt_lock = true;
-      no_roll = prev->on_ground;
-      //cout << "Crossing waypoint: " << prev->name << endl;
-      //cout << "  Target speed:    " << tgt_speed << endl;
-      //cout << "  Target altitude: " << tgt_altitude << endl;
-      //cout << "  Target heading:  " << tgt_heading << endl << endl;       
+    prev = fp->getPreviousWaypoint();
+    curr = fp->getCurrentWaypoint();
+    next = fp->getNextWaypoint();
+    // Now that we have incremented the waypoints, excute some traffic manager specific code
+    // based on the name of the waypoint we just passed.
+    if (trafficRef)
+      {        
+       double userLatitude  = fgGetDouble("/position/latitude-deg");
+       double userLongitude = fgGetDouble("/position/longitude-deg");
+       double course, distance;
+       SGWayPoint current  (pos.lon(),
+                            pos.lat(),
+                            0);
+       SGWayPoint user (   userLongitude,
+                           userLatitude,
+                           0);
+       user.CourseAndDistance(current, &course, &distance);
+       if ((distance * SG_METER_TO_NM) > TRAFFICTOAIDIST)
+         {
+           setDie(true);
+           //cerr << "done fp die out of range" << endl;
+           return;
+         }
+       
+       FGAirport * dep = trafficRef->getDepartureAirport();
+       FGAirport * arr = trafficRef->getArrivalAirport();
+       // At parking the beginning of the airport
+       if (!( dep && arr))
+         {
+           setDie(true);
+           return;
+         }
+       //if ((dep->getId() == string("EHAM") || (arr->getId() == string("EHAM"))))
+       //  {
+       //      cerr << trafficRef->getRegistration() 
+       //           << " Enroute from " << dep->getId() 
+       //           << " to "           << arr->getId()
+       //           << " just crossed " << prev->name
+       //           << " Assigned rwy     " << fp->getRunwayId()
+       //           << " " << fp->getRunway() << endl;
+       // }
+       //if ((dep->getId() == string("EHAM")) && (prev->name == "park2"))
+       //  {
+       //    cerr << "Schiphol ground " 
+       //       << trafficRef->getCallSign();
+       //    if (trafficRef->getHeavy())
+       //      cerr << "Heavy";
+       //    cerr << ", is type " 
+       //       << trafficRef->getAircraft()
+       //       << " ready to go. IFR to "
+       //       << arr->getId() <<endl;
+       //  }   
+       if (prev->name == "park2")
+         dep->releaseParking(fp->getGate());
+       
+       //if ((arr->getId() == string("EHAM")) && (prev->name  == "Center"))
+       //  {
+       //    
+       //    cerr << "Schiphol ground " 
+       //       << trafficRef->getCallSign();
+       //    if (trafficRef->getHeavy())
+       //      cerr << "Heavy";
+       //    cerr << " landed runway " 
+       //       << fp->getRunway()
+       //       << " request taxi to gate " 
+       //       << arr->getParkingName(fp->getGate()) 
+       //       << endl;
+       //  }
+       if (prev->name == "END")
+         fp->setTime(trafficRef->getDepartureTime());
+       //cerr << "5" << endl;
+      }
+    if (next) 
+      {
+       //cerr << "Current waypoint" << curr->name << endl;
+       //cerr << "Next waypoint" << next->name << endl;
+       fp->setLeadDistance(speed, tgt_heading, curr, next);
+      }
+    //cerr << "5.1" << endl;
+    if (curr->crossat > -1000.0) {
+      //cerr << "5.1a" << endl;
+      use_perf_vs = false;
+      tgt_vs = (curr->crossat - altitude)/
+       (fp->getDistanceToGo(pos.lat(), pos.lon(), curr)/6076.0/speed*60.0);
+      //cerr << "5.1b" << endl;
+      tgt_altitude = curr->crossat;
     } else {
-        double calc_bearing = fp->getBearing(pos.lat(), pos.lon(), curr);
-        double hdg_error = calc_bearing - tgt_heading;
-        if (fabs(hdg_error) > 1.0) {
-          TurnTo( calc_bearing ); 
-        }
+      //cerr << "5.1c" << endl;
+      use_perf_vs = true;
+      //cerr << "5.1d" << endl;        
+      tgt_altitude = prev->altitude;
+      //cerr << "Setting target altitude : " <<tgt_altitude << endl;
     }
-     
-  }
-
+    //cerr << "6" << endl;
+    tgt_speed = prev->speed;
+    hdg_lock = alt_lock = true;
+    no_roll = prev->on_ground;
+    //cout << "Crossing waypoint: " << prev->name << endl;
+    //cout << "  Target speed:    " << tgt_speed << endl;
+    //cout << "  Target altitude: " << tgt_altitude << endl;
+    //cout << "  Target heading:  " << tgt_heading << endl << endl;       
+  } else {
+    
+    double calc_bearing = fp->getBearing(pos.lat(), pos.lon(), curr);
+    //cerr << "Bearing = " << calc_bearing << endl;
+    if (speed < 0)
+      {
+       calc_bearing +=180;
+       if (calc_bearing > 360)
+         calc_bearing -= 360;
+      }
+    if (finite(calc_bearing))
+      {
+       double hdg_error = calc_bearing - tgt_heading;
+       if (fabs(hdg_error) > 1.0) {
+         TurnTo( calc_bearing ); 
+       }
+      }
+    else
+      {
+       cerr << "calc_bearing is not a finite number : "
+            << "Speed " << speed
+            << "pos : " << pos.lat() << ", " << pos.lon()
+            << "waypoint " << curr->latitude << ", " << curr->longitude << endl;
+       cerr << "waypoint name " << curr->name;
+       exit(1);
+      }
+    double speed_diff = speed - prevSpeed;
+    // Update the lead distance calculation if speed has changed sufficiently
+    // to prevent spinning (hopefully);
+    if (fabs(speed_diff) > 10)
+      { 
+       prevSpeed = speed;
+       fp->setLeadDistance(speed, tgt_heading, curr, next);
+      }
+    
+    //cerr << "Done Processing FlightPlan"<< endl;
+  } // if (dt count) else
 }
 
-
-bool FGAIAircraft::_getGearDown() const {
+  bool FGAIAircraft::_getGearDown() const {
    return ((props->getFloatValue("position/altitude-agl-ft") < 900.0)
             && (props->getFloatValue("velocities/airspeed-kt")
                  < performance->land_speed*1.25));
 }
+
+
+void FGAIAircraft::loadNextLeg() 
+{
+  //delete fp;
+  //time_t now = time(NULL) + fgGetLong("/sim/time/warp");
+  
+  
+  //FGAIModelEntity entity;
+  //entity.m_class = "jet_transport";
+  //entity.path = modelPath.c_str();
+  //entity.flightplan = "none";
+  //entity.latitude = _getLatitude();
+  //entity.longitude = _getLongitude();
+ //entity.altitude = trafficRef->getCruiseAlt() * 100; // convert from FL to feet
+  //entity.speed = 450; // HACK ALERT
+  //entity.fp = new FGAIFlightPlan(&entity, courseToDest, i->getDepartureTime(), dep, arr);
+  int leg;
+  if ((leg = fp->getLeg())  == 10)
+    {
+      trafficRef->next();
+      leg = 1;
+      fp->setLeg(leg);
+      
+      //cerr << "Resetting leg : " << leg << endl;
+    }
+  //{
+  //leg++;
+  //fp->setLeg(leg);
+  //cerr << "Creating leg number : " << leg << endl;
+  FGAirport *dep = trafficRef->getDepartureAirport();
+  FGAirport *arr = trafficRef->getArrivalAirport();
+  if (!(dep && arr))
+    {
+      setDie(true);
+      //cerr << "Failed to get airport in AIAircraft::ProcessFlightplan()" << endl;
+      //if (dep)
+      //  cerr << "Departure " << dep->getId() << endl;
+      //if (arr) 
+      //  cerr << "Arrival   " << arr->getId() << endl;
+    }
+  else
+    {
+      double cruiseAlt = trafficRef->getCruiseAlt() * 100;
+      //cerr << "Creating new leg using " << cruiseAlt << " as cruise altitude."<< endl;
+      
+      fp->create (dep,
+                 arr,
+                 leg,
+                 cruiseAlt, //(trafficRef->getCruiseAlt() * 100), // convert from FL to feet
+                 trafficRef->getSpeed(),
+                 _getLatitude(),
+                 _getLongitude(),
+                 false,
+                 trafficRef->getRadius(),
+                 trafficRef->getFlightType(), 
+                 acType,
+                 company);
+      //prev = fp->getPreviousWaypoint();
+      //curr = fp->getCurrentWaypoint();
+      //next = fp->getNextWaypoint();
+      //cerr << "25" << endl;
+      //if (next) 
+      //       {
+      //  //cerr << "Next waypoint" << next->name << endl;
+      //         fp->setLeadDistance(speed, tgt_heading, curr, next);
+      //       }
+      //cerr << "25.1" << endl;
+      //if (curr->crossat > -1000.0) {
+      //       //cerr << "25.1a" << endl;
+      //       use_perf_vs = false;
+      //       
+      //       tgt_vs = (curr->crossat - altitude)/
+      //         (fp->getDistanceToGo(pos.lat(), pos.lon(), curr)/6076.0/speed*60.0);
+      //       //cerr << "25.1b" << endl;
+      //       tgt_altitude = curr->crossat;
+      //} else {
+      //       //cerr << "25.1c" << endl;
+      //       use_perf_vs = true;
+      //       //cerr << "25.1d" << endl;      
+      //       tgt_altitude = prev->altitude;
+      //       //cerr << "Setting target altitude : " <<tgt_altitude << endl;
+      // }
+      //cerr << "26" << endl;
+      //tgt_speed = prev->speed;
+      //hdg_lock = alt_lock = true;
+      //no_roll = prev->on_ground;
+      
+    }
+  //}
+  //else
+  //{
+  //delete entity.fp;
+  //entity.fp = new FGAIFlightPlan(&entity, 
+  //                            999,  // A hack
+  //                            trafficRef->getDepartureTime(), 
+  //                            trafficRef->getDepartureAirport(), 
+  //                            trafficRef->getArrivalAirport(),
+  //                            false,
+  //                            acType,
+  //                            company);
+  //SetFlightPlan(entity.fp);
+}
+
+
+
+// Note: This code is copied from David Luff's AILocalTraffic 
+// Warning - ground elev determination is CPU intensive
+// Either this function or the logic of how often it is called
+// will almost certainly change.
+
+void FGAIAircraft::getGroundElev(double dt) {
+  dt_elev_count += dt;
+  //return;
+  if (dt_elev_count < (10.0 + (rand() % 100))) // Update minimally every 10 secs, but add some randomness to prevent them all IA objects doing this synced
+    {
+      return;
+    }
+  else
+    {
+      dt_elev_count = 0;
+    }
+  // It would be nice if we could set the correct tile center here in order to get a correct
+  // answer with one call to the function, but what I tried in the two commented-out lines
+  // below only intermittently worked, and I haven't quite groked why yet.
+  //SGBucket buck(pos.lon(), pos.lat());
+  //aip.getSGLocation()->set_tile_center(Point3D(buck.get_center_lon(), buck.get_center_lat(), 0.0));
+  
+  // Only do the proper hitlist stuff if we are within visible range of the viewer.
+  double visibility_meters = fgGetDouble("/environment/visibility-m"); 
+
+  FGViewer* vw = globals->get_current_view();
+  double 
+    course, 
+    distance;
+
+  //Point3D currView(vw->getLongitude_deg(), 
+  //              vw->getLatitude_deg(), 0.0);
+  SGWayPoint current  (pos.lon(),
+                      pos.lat(),
+                      0);
+  SGWayPoint view (   vw->getLongitude_deg(),
+                     vw->getLatitude_deg(),
+                     0);
+  view.CourseAndDistance(current, &course, &distance);
+  if(distance > visibility_meters) {
+    //aip.getSGLocation()->set_cur_elev_m(aptElev);
+    return;
+  }
+    
+  
+  //globals->get_tile_mgr()->prep_ssg_nodes( acmodel_location,
+  globals->get_tile_mgr()->prep_ssg_nodes( aip.getSGLocation(),        visibility_meters );
+  Point3D scenery_center = globals->get_scenery()->get_center();
+
+  globals->get_tile_mgr()->update( aip.getSGLocation(), 
+                                  visibility_meters, 
+                                  (aip.getSGLocation())->get_absolute_view_pos( scenery_center ) );
+  // save results of update in SGLocation for fdm...
+  
+  //if ( globals->get_scenery()->get_cur_elev() > -9990 ) {
+  //   acmodel_location->
+  //   set_cur_elev_m( globals->get_scenery()->get_cur_elev() );
+  //}
+  
+  // The need for this here means that at least 2 consecutive passes are needed :-(
+  aip.getSGLocation()->set_tile_center( globals->get_scenery()->get_next_center() );
+    globals->get_tile_mgr()->prep_ssg_nodes( aip.getSGLocation(),      visibility_meters );
+    //Point3D scenery_center = globals->get_scenery()->get_center();
+
+  globals->get_tile_mgr()->update( aip.getSGLocation(), 
+                                  visibility_meters, 
+                                  (aip.getSGLocation())->get_absolute_view_pos( scenery_center ) );
+  // save results of update in SGLocation for fdm...
+  
+  //if ( globals->get_scenery()->get_cur_elev() > -9990 ) {
+  //   acmodel_location->
+  //   set_cur_elev_m( globals->get_scenery()->get_cur_elev() );
+  //}
+  
+  // The need for this here means that at least 2 consecutive passes are needed :-(
+  aip.getSGLocation()->set_tile_center( globals->get_scenery()->get_next_center() );
+  //cerr << "Transform Elev is " << globals->get_scenery()->get_cur_elev() << '\n';
+  tgt_altitude = (globals->get_scenery()->get_cur_elev() * SG_METER_TO_FEET) + groundOffset;
+}
+
+//globals->get_tile_mgr()->prep_ssg_nodes( _aip.getSGLocation(),       visibility_meters );
+//Point3D scenery_center = globals->get_scenery()->get_center();
+//globals->get_tile_mgr()->update(_aip.getSGLocation(), visibility_meters, (_aip.getSGLocation())->get_absolute_view_pos( scenery_center ) );
+// save results of update in SGLocation for fdm...
+
+//if ( globals->get_scenery()->get_cur_elev() > -9990 ) {
+//     acmodel_location->
+//     set_cur_elev_m( globals->get_scenery()->get_cur_elev() );
+//}
+
+// The need for this here means that at least 2 consecutive passes are needed :-(
+//_aip.getSGLocation()->set_tile_center( globals->get_scenery()->get_next_center() );
+
+//cout << "Transform Elev is " << globals->get_scenery()->get_cur_elev() << '\n';
+//_aip.getSGLocation()->set_cur_elev_m(globals->get_scenery()->get_cur_elev());
+//return(globals->get_scenery()->get_cur_elev());
+//}
index f22ce44fee68e256aad59bfc7e08f0955aa8a429..ad1c7dae1002504f270c163800911e8e50c58bd9 100644 (file)
@@ -48,7 +48,6 @@ private:
        } PERF_STRUCT;
        
 public:
-
         enum aircraft_e {LIGHT=0, WW2_FIGHTER, JET_TRANSPORT, JET_FIGHTER, TANKER};
         static const PERF_STRUCT settings[];
        
@@ -68,7 +67,13 @@ public:
         void YawTo(double angle);
         void ClimbTo(double altitude);
         void TurnTo(double heading);
-        void ProcessFlightPlan( double dt );
+        void ProcessFlightPlan( double dt, time_t now );
+  void getGroundElev(double dt);
+  void loadNextLeg  ();
+
+  void setAcType(string ac) { acType = ac; };
+  void setCompany(string comp) { company = comp;};
+  //void setSchedule(FGAISchedule *ref) { trafficRef = ref;};
 
         inline void SetTanker(bool setting) { isTanker = setting; };
 
@@ -78,6 +83,10 @@ private:
         bool hdg_lock;
         bool alt_lock;
         double dt_count;  
+  double dt_elev_count;
+  double headingChangeRate;
+  double groundTargetSpeed;
+  double groundOffset;
         double dt; 
 
         const PERF_STRUCT *performance;
@@ -87,8 +96,15 @@ private:
 
        void Run(double dt);
         double sign(double x); 
+  
+  string acType;
+  string company;
+  int spinCounter;
+  double prevSpeed;
+  double prev_dist_to_go;
 
         bool _getGearDown() const;
+  bool reachedWaypoint;
 };
 
 
index fd8d8c85c254a49f84076123fc9ea733e4e065a6..82c4de8867446b1642bee38aae9562d79b87637a 100644 (file)
@@ -26,6 +26,7 @@
 #include <simgear/constants.h>
 #include <simgear/math/point3d.hxx>
 #include <simgear/scene/model/placement.hxx>
+#include <simgear/misc/sg_path.hxx>
 
 #include <Main/fg_props.hxx>
 
@@ -75,7 +76,9 @@ typedef struct {
    double radius;             // used by ship ojects, in feet
    double x_offset;           // used by ship ojects, in meters
    double y_offset;           // used by ship ojects, in meters
-   double z_offset;           // used by ship ojects, in meters    
+   double z_offset;           // used by ship ojects, in meters   
+  string acType;              // used by aircraft objects
+  string company;             // used by aircraft objects
 } FGAIModelEntity;
 
 
index 7ba7747f478eea820b68702a688602bbcf164e5b..19321f2bfd7c24746601ffb1624bc2b4bb929d53 100644 (file)
@@ -45,6 +45,8 @@ FGAIFlightPlan::FGAIFlightPlan(string filename)
 {
   int i;
   start_time = 0;
+  leg = 10;
+  gateId = 0;
   SGPath path( globals->get_fg_root() );
   path.append( ("/Data/AI/FlightPlans/" + filename).c_str() );
   SGPropertyNode root;
@@ -55,7 +57,7 @@ FGAIFlightPlan::FGAIFlightPlan(string filename)
       SG_LOG(SG_GENERAL, SG_ALERT,
        "Error reading AI flight plan: " << path.str());
        // cout << path.str() << endl;
-      return;
+     return;
   }
 
   SGPropertyNode * node = root.getNode("flightplan");
@@ -94,8 +96,15 @@ FGAIFlightPlan::FGAIFlightPlan(FGAIModelEntity *entity,
                               double course,
                               time_t start,
                               FGAirport *dep,
-                              FGAirport *arr)
+                              FGAirport *arr,
+                              bool firstLeg,
+                              double radius,
+                              string fltType,
+                              string acType,
+                              string airline)
 {
+  leg = 10;
+  gateId=0;
   start_time = start;
   bool useInitialWayPoint = true;
   bool useCurrentWayPoint = false;
@@ -116,55 +125,86 @@ FGAIFlightPlan::FGAIFlightPlan(FGAIModelEntity *entity,
       useCurrentWayPoint = true;
     }
 
-  try {
-    readProperties(path.str(), &root);
-    
-    SGPropertyNode * node = root.getNode("flightplan");
-  
-    //waypoints.push_back( init_waypoint );
-    for (int i = 0; i < node->nChildren(); i++) { 
-      //cout << "Reading waypoint " << i << endl;
-      waypoint* wpt = new waypoint;
-      SGPropertyNode * wpt_node = node->getChild(i);
-      wpt->name      = wpt_node->getStringValue("name", "END");
-      wpt->latitude  = wpt_node->getDoubleValue("lat", 0);
-      wpt->longitude = wpt_node->getDoubleValue("lon", 0);
-      wpt->altitude  = wpt_node->getDoubleValue("alt", 0);
-      wpt->speed     = wpt_node->getDoubleValue("ktas", 0);
-      //wpt->speed     = speed;
-      wpt->crossat   = wpt_node->getDoubleValue("crossat", -10000);
-      wpt->gear_down = wpt_node->getBoolValue("gear-down", false);
-      wpt->flaps_down= wpt_node->getBoolValue("flaps-down", false);
+  if (path.exists()) 
+    {
+      try 
+       {
+         readProperties(path.str(), &root);
+         
+         SGPropertyNode * node = root.getNode("flightplan");
+         
+         //waypoints.push_back( init_waypoint );
+         for (int i = 0; i < node->nChildren(); i++) { 
+           //cout << "Reading waypoint " << i << endl;
+           waypoint* wpt = new waypoint;
+           SGPropertyNode * wpt_node = node->getChild(i);
+           wpt->name      = wpt_node->getStringValue("name", "END");
+           wpt->latitude  = wpt_node->getDoubleValue("lat", 0);
+           wpt->longitude = wpt_node->getDoubleValue("lon", 0);
+           wpt->altitude  = wpt_node->getDoubleValue("alt", 0);
+           wpt->speed     = wpt_node->getDoubleValue("ktas", 0);
+           //wpt->speed     = speed;
+           wpt->crossat   = wpt_node->getDoubleValue("crossat", -10000);
+           wpt->gear_down = wpt_node->getBoolValue("gear-down", false);
+           wpt->flaps_down= wpt_node->getBoolValue("flaps-down", false);
+           
+           if (wpt->name == "END") wpt->finished = true;
+           else wpt->finished = false;
+           waypoints.push_back(wpt);
+         }
+       }
+      catch (const sg_exception &e) {
+       SG_LOG(SG_GENERAL, SG_ALERT,
+              "Error reading AI flight plan: ");
+       cerr << "Errno = " << errno << endl;
+       if (errno == ENOENT)
+         {
+           cerr << "Reason: No such file or directory" << endl;
+         }
+      }
+    }
+  else
+    {
+      // cout << path.str() << endl;
+      // cout << "Trying to create this plan dynamically" << endl;
+      // cout << "Route from " << dep->id << " to " << arr->id << endl;
+      time_t now = time(NULL) + fgGetLong("/sim/time/warp");
+      time_t timeDiff = now-start; 
+      leg = 1;
+      if ((timeDiff > 300) && (timeDiff < 1200))
+       leg = 2;
+      else if ((timeDiff >= 1200) && (timeDiff < 1500))
+       leg = 3;
+      else if ((timeDiff >= 1500) && (timeDiff < 2000))
+       leg = 4;
+      else if (timeDiff >= 2000)
+       leg = 5;
       
-      if (wpt->name == "END") wpt->finished = true;
-      else wpt->finished = false;
-      waypoints.push_back(wpt);
+      //cerr << "Set leg to : " << leg << endl;  
+      wpt_iterator = waypoints.begin();
+      create(dep,arr, leg, entity->altitude, entity->speed, entity->latitude, entity->longitude,
+            firstLeg, radius, fltType, acType, airline);
+      wpt_iterator = waypoints.begin();
+      //cerr << "after create: " << (*wpt_iterator)->name << endl;
+      //leg++;
+      // Now that we have dynamically created a flight plan,
+      // we need to add some code that pops any waypoints already past.
+      //return;
     }
-  }
-  catch (const sg_exception &e) {
-    //SG_LOG(SG_GENERAL, SG_ALERT,
-    // "Error reading AI flight plan: ");
-    // cout << path.str() << endl;
-    // cout << "Trying to create this plan dynamically" << endl;
-    // cout << "Route from " << dep->id << " to " << arr->id << endl;
-       create(dep,arr, entity->altitude, entity->speed);
-       // Now that we have dynamically created a flight plan,
-       // we need to add some code that pops any waypoints already past.
-       //return;
-  }
-  waypoint* init_waypoint   = new waypoint;
-  init_waypoint->name       = string("initial position");
-  init_waypoint->latitude   = entity->latitude;
-  init_waypoint->longitude  = entity->longitude;
-  init_waypoint->altitude   = entity->altitude;
-  init_waypoint->speed      = entity->speed;
-  init_waypoint->crossat    = - 10000;
-  init_waypoint->gear_down  = false;
-  init_waypoint->flaps_down = false;
-  init_waypoint->finished   = false;
-
-  wpt_vector_iterator i = waypoints.begin();
-  while (i != waypoints.end())
+  /*
+    waypoint* init_waypoint   = new waypoint;
+    init_waypoint->name       = string("initial position");
+    init_waypoint->latitude   = entity->latitude;
+    init_waypoint->longitude  = entity->longitude;
+    init_waypoint->altitude   = entity->altitude;
+    init_waypoint->speed      = entity->speed;
+    init_waypoint->crossat    = - 10000;
+    init_waypoint->gear_down  = false;
+    init_waypoint->flaps_down = false;
+    init_waypoint->finished   = false;
+    
+    wpt_vector_iterator i = waypoints.begin();
+    while (i != waypoints.end())
     {
       //cerr << "Checking status of each waypoint: " << (*i)->name << endl;
        SGWayPoint first(init_waypoint->longitude, 
@@ -229,11 +269,13 @@ FGAIFlightPlan::FGAIFlightPlan(FGAIModelEntity *entity,
          //delete wpt;
          delete *(i);
          i = waypoints.erase(i);
+         }
+         
        }
-    }
+  */
   //for (i = waypoints.begin(); i != waypoints.end(); i++)
   //  cerr << "Using waypoint : " << (*i)->name << endl;
-  wpt_iterator = waypoints.begin();
+  //wpt_iterator = waypoints.begin();
   //cout << waypoints.size() << " waypoints read." << endl;
 }
 
@@ -242,7 +284,13 @@ FGAIFlightPlan::FGAIFlightPlan(FGAIModelEntity *entity,
 
 FGAIFlightPlan::~FGAIFlightPlan()
 {
-  waypoints.clear();
+  deleteWaypoints();
+  //waypoints.clear();
+  //while (waypoints.begin() != waypoints.end())
+  //  {
+  //    delete *(waypoints.begin());
+  //    waypoints.erase (waypoints.begin());
+  //  }
 }
 
 
@@ -266,7 +314,9 @@ FGAIFlightPlan::getCurrentWaypoint( void )
 FGAIFlightPlan::waypoint*
 FGAIFlightPlan::getNextWaypoint( void )
 {
-  if (wpt_iterator == waypoints.end()) {
+  wpt_vector_iterator i = waypoints.end();
+  i--;  // end() points to one element after the last one. 
+  if (wpt_iterator == i) {
     return 0;
   } else {
     wpt_vector_iterator next = wpt_iterator;
@@ -274,14 +324,27 @@ FGAIFlightPlan::getNextWaypoint( void )
   }
 }
 
-void FGAIFlightPlan::IncrementWaypoint( void )
+void FGAIFlightPlan::IncrementWaypoint(bool eraseWaypoints )
 {
-  wpt_iterator++;
+  if (eraseWaypoints)
+    {
+      if (wpt_iterator == waypoints.begin())
+       wpt_iterator++;
+      else
+       {
+         delete *(waypoints.begin());
+         waypoints.erase(waypoints.begin());
+         wpt_iterator = waypoints.begin();
+         wpt_iterator++;
+       }
+    }
+  else
+    wpt_iterator++;
 }
 
 // gives distance in feet from a position to a waypoint
 double FGAIFlightPlan::getDistanceToGo(double lat, double lon, waypoint* wp){
-   // get size of a degree at the present latitude
+   // get size of a degree2 at the present latitude
    // this won't work over large distances
    double ft_per_deg_lat = 366468.96 - 3717.12 * cos(lat / SG_RADIANS_TO_DEGREES);
    double ft_per_deg_lon = 365228.16 * cos(lat / SG_RADIANS_TO_DEGREES);
@@ -293,12 +356,28 @@ double FGAIFlightPlan::getDistanceToGo(double lat, double lon, waypoint* wp){
 // sets distance in feet from a lead point to the current waypoint
 void FGAIFlightPlan::setLeadDistance(double speed, double bearing, 
                                      waypoint* current, waypoint* next){
-  double turn_radius = 0.1911 * speed * speed; // an estimate for 25 degrees bank
+  double turn_radius;
+    if (fabs(speed) > 1) 
+      turn_radius = 0.1911 * speed * speed; // an estimate for 25 degrees bank
+    else
+      turn_radius = 1.0;
+
   double inbound = bearing;
   double outbound = getBearing(current, next);
-  double diff = fabs(inbound - outbound);
-  if (diff > 180.0) diff = 360.0 - diff;
-  lead_distance = turn_radius * sin(diff * SG_DEGREES_TO_RADIANS); 
+  leadInAngle = fabs(inbound - outbound);
+  if (leadInAngle > 180.0) 
+    leadInAngle = 360.0 - leadInAngle;
+  if (leadInAngle < 1.0) // To prevent lead_dist from getting so small it is skipped 
+    leadInAngle = 1.0;
+  
+  lead_distance = turn_radius * sin(leadInAngle * SG_DEGREES_TO_RADIANS); 
+  //  if ((errno == EDOM) || (errno == ERANGE) || lead_distance < 1.0)
+  //  {
+  //    cerr << "Lead Distance = " << lead_distance
+  //      << "Diff          = " << diff
+  //      << "Turn Radius   = " << turn_radius 
+  //      << "Speed         = " << speed << endl;
+  //  }
 }
 
 void FGAIFlightPlan::setLeadDistance(double distance_ft){
@@ -345,310 +424,51 @@ double FGAIFlightPlan::getBearing(double lat, double lon, waypoint* wp){
 //   if (!southerly && !easterly) return 270.0 + angle; 
   SGWayPoint sgWp(wp->longitude,wp->latitude, wp->altitude, SGWayPoint::WGS84, string("temp"));
   sgWp.CourseAndDistance(lon, lat, wp->altitude, &course, &distance);
+  
   return course;
-  // Omit a compiler warning.
+  // Omit a compiler warning. 
+  //if ((errno == EDOM) || (errno == ERANGE))
+  //  {
+  //    cerr << "Lon:  " << wp->longitude
+  //      << "Lat       = " << wp->latitude
+  //   << "Tgt Lon   = " <<  
+  //   << "TgT Lat   = " << speed << endl;
+  //  }
+  
 }
 
-/* FGAIFlightPlan::create()
- * dynamically create a flight plan for AI traffic, based on data provided by the
- * Traffic Manager, when reading a filed flightplan failes. (DT, 2004/07/10) 
- *
- * Probably need to split this into separate functions for different parts of the flight
 
- * once the code matures a bit more.
- *
- */ 
-void FGAIFlightPlan::create(FGAirport *dep, FGAirport *arr, double alt, double speed)
-{
-double wind_speed;
-  double wind_heading;
-  FGRunway rwy;
-  double lat, lon, az;
-  double lat2, lon2, az2;
-  int direction;
-  
-  //waypoints.push_back(wpt);
-  // Create the outbound taxi leg, for now simplified as a 
-  // Direct route from the airport center point to the start
-  // of the runway.
-  ///////////////////////////////////////////////////////////
-    //cerr << "Cruise Alt << " << alt << endl;
-    // Temporary code to add some small random variation to aircraft parking positions;
-  direction = (rand() % 360);
-geo_direct_wgs_84 ( 0, dep->_latitude, dep->_longitude, direction, 
-      100,
-      &lat2, &lon2, &az2 );
-  waypoint *wpt = new waypoint;
-  wpt->name      = dep->_id; //wpt_node->getStringValue("name", "END");
-  wpt->latitude  = lat2;
-  wpt->longitude = lon2;
-  wpt->altitude  = dep->_elevation + 19; // probably need to add some model height to it
-  wpt->speed     = 15; 
-  wpt->crossat   = -10000;
-  wpt->gear_down = true;
-  wpt->flaps_down= true;
-  wpt->finished  = false;
-  wpt->on_ground = true;
-  waypoints.push_back(wpt);
-  
-  // Get the current active runway, based on code from David Luff
-  FGEnvironment 
-    stationweather = ((FGEnvironmentMgr *) globals->get_subsystem("environment"))
-    ->getEnvironment(dep->_latitude, dep->_longitude, dep->_elevation);
-  
-  wind_speed = stationweather.get_wind_speed_kt();
-  wind_heading = stationweather.get_wind_from_heading_deg();
-  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(dep->_id, int(wind_heading));
-  if (!(globals->get_runways()->search(dep->_id, (int) wind_heading, &rwy )))
-    {
-      cout << "Failed to find runway for " << dep->_id << endl;
-      // Hmm, how do we handle a potential error like this?
-      exit(1);
-    }
 
-  double heading = rwy._heading;
-  double azimuth = heading + 180.0;
-  while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
-  geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, 
-                     rwy._length * SG_FEET_TO_METER * 0.5 - 5.0,
-                     &lat2, &lon2, &az2 );
-  
-  //Add the runway startpoint;
-  wpt = new waypoint;
-  wpt->name      = rwy._id;
-  wpt->latitude  = lat2;
-  wpt->longitude = lon2;
-  wpt->altitude  = dep->_elevation + 19;
-  wpt->speed     = 15; 
-  wpt->crossat   = -10000;
-  wpt->gear_down = true;
-  wpt->flaps_down= true;
-  wpt->finished  = false;
-  wpt->on_ground = true;
-  waypoints.push_back(wpt);
-
-  //Next: The point on the runway where we begin to accelerate to take-off speed
-  //100 meters down the runway seems to work. Shorter distances cause problems with
-  // the turn with larger aircraft
-  geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, 
-                     rwy._length * SG_FEET_TO_METER * 0.5 - 105.0,
-                     &lat2, &lon2, &az2 );
-  wpt = new waypoint;
-  wpt->name      = "accel";
-  wpt->latitude  = lat2;
-  wpt->longitude = lon2;
-  wpt->altitude  = dep->_elevation + 19;
-  wpt->speed     = speed; 
-  wpt->crossat   = -10000;
-  wpt->gear_down = true;
-  wpt->flaps_down= true;
-  wpt->finished  = false;
-  wpt->on_ground = true;
-  waypoints.push_back(wpt); 
-  
-  lat = lat2;
-  lon = lon2;
-  az  = az2;
-
- //Next: the Start of Climb
-  geo_direct_wgs_84 ( 0, lat, lon, heading, 
-                     2560 * SG_FEET_TO_METER,
-                     &lat2, &lon2, &az2 );
-
-  wpt = new waypoint;
-  wpt->name      = "SOC";
-  wpt->latitude  = lat2;
-  wpt->longitude = lon2;
-  wpt->altitude  = alt + 19;
-  wpt->speed     = speed; 
-  wpt->crossat   = -10000;
-  wpt->gear_down = true;
-  wpt->flaps_down= true;
-  wpt->finished  = false;
-  wpt->on_ground = false;
-  waypoints.push_back(wpt); 
-
-//Next: the Top of Climb
-  geo_direct_wgs_84 ( 0, lat, lon, heading, 
-                     20*SG_NM_TO_METER,
-                     &lat2, &lon2, &az2 );
-  wpt = new waypoint;
-  wpt->name      = "10000ft climb";
-  wpt->latitude  = lat2;
-  wpt->longitude = lon2;
-  wpt->altitude  = 10000;
-  wpt->speed     = speed; 
-  wpt->crossat   = -10000;
-  wpt->gear_down = true;
-  wpt->flaps_down= true;
-  wpt->finished  = false;
-  wpt->on_ground = false;
-  waypoints.push_back(wpt); 
-
-
-
-  //Beginning of Decent
-  stationweather = ((FGEnvironmentMgr *)globals->get_subsystem("environment"))
-    ->getEnvironment(arr->_latitude, arr->_longitude, arr->_elevation);
-
-  wind_speed = stationweather.get_wind_speed_kt();
-  wind_heading = stationweather.get_wind_from_heading_deg();
-
-  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.
-  }
+void FGAIFlightPlan::deleteWaypoints()
+{
+  for (wpt_vector_iterator i = waypoints.begin(); i != waypoints.end();i++)
+    delete (*i);
+  waypoints.clear();
+}
 
-  rwy_no = globals->get_runways()->search(arr->_id, int(wind_heading));
-  //cout << "Using runway # " << rwy_no << " for departure at " << dep->_id << endl;
-  
-   if (!(globals->get_runways()->search(arr->_id, (int) wind_heading, &rwy )))
+// Delete all waypoints except the last, 
+// which we will recycle as the first waypoint in the next leg;
+void FGAIFlightPlan::resetWaypoints()
+{
+  if (waypoints.begin() == waypoints.end())
+    return;
+  else
     {
-      cout << "Failed to find runway for " << arr->_id << endl;
-      // Hmm, how do we handle a potential error like this?
-      exit(1);
+      waypoint *wpt = new waypoint;
+      wpt_vector_iterator i = waypoints.end();
+      i--;
+      wpt->name      = (*i)->name;
+      wpt->latitude  = (*i)->latitude;
+      wpt->longitude =  (*i)->longitude;
+      wpt->altitude  =  (*i)->altitude;
+      wpt->speed     =  (*i)->speed;
+      wpt->crossat   =  (*i)->crossat;
+      wpt->gear_down =  (*i)->gear_down;
+      wpt->flaps_down=  (*i)->flaps_down;
+      wpt->finished  = false;
+      wpt->on_ground =  (*i)->on_ground;
+      //cerr << "Recycling waypoint " << wpt->name << endl;
+      deleteWaypoints();
+      waypoints.push_back(wpt);
     }
-  //cerr << "Done" << endl;
- heading = rwy._heading;
- azimuth = heading + 180.0;
- while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
-
-
- geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, 
-                    100000,
-                    &lat2, &lon2, &az2 );
-  wpt = new waypoint;
-  wpt->name      = "BOD"; //wpt_node->getStringValue("name", "END");
-  wpt->latitude  = lat2;
-  wpt->longitude = lon2;
-  wpt->altitude  = 10000;
-  wpt->speed     = speed; 
-  wpt->crossat   = alt +19;
-  wpt->gear_down = false;
-  wpt->flaps_down= false;
-  wpt->finished  = false;
-  wpt->on_ground = false;
-  waypoints.push_back(wpt); 
-
-  // Ten thousand ft. Slowing down to 240 kts
-  geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, 
-                    20*SG_NM_TO_METER,
-                    &lat2, &lon2, &az2 );
-  wpt = new waypoint;
-  wpt->name      = "Dec 10000ft"; //wpt_node->getStringValue("name", "END");
-  wpt->latitude  = lat2;
-  wpt->longitude = lon2;
-  wpt->altitude  = arr->_elevation + 19;
-  wpt->speed     = 240; 
-  wpt->crossat   = 10000;
-  wpt->gear_down = false;
-  wpt->flaps_down= false;
-  wpt->finished  = false;
-  wpt->on_ground = false;
-  waypoints.push_back(wpt);  
-
-  // Three thousand ft. Slowing down to 160 kts
-  geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, 
-                    8*SG_NM_TO_METER,
-                    &lat2, &lon2, &az2 );
-  wpt = new waypoint;
-  wpt->name      = "DEC 3000ft"; //wpt_node->getStringValue("name", "END");
-  wpt->latitude  = lat2;
-  wpt->longitude = lon2;
-  wpt->altitude  = arr->_elevation + 19;
-  wpt->speed     = 160; 
-  wpt->crossat   = 3000;
-  wpt->gear_down = true;
-  wpt->flaps_down= true;
-  wpt->finished  = false;
-  wpt->on_ground = false;
-  waypoints.push_back(wpt); 
-  //Runway Threshold
- geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, 
-                    rwy._length*0.45 * SG_FEET_TO_METER,
-                    &lat2, &lon2, &az2 );
-  wpt = new waypoint;
-  wpt->name      = "Threshold"; //wpt_node->getStringValue("name", "END");
-  wpt->latitude  = lat2;
-  wpt->longitude = lon2;
-  wpt->altitude  = arr->_elevation + 19;
-  wpt->speed     = 15; 
-  wpt->crossat   = arr->_elevation + 19;
-  wpt->gear_down = true;
-  wpt->flaps_down= true;
-  wpt->finished  = false;
-  wpt->on_ground = true;
-  waypoints.push_back(wpt); 
-
- //Full stop at the runway centerpoint
- geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, 
-                    rwy._length*0.45,
-                    &lat2, &lon2, &az2 );
-  wpt = new waypoint;
-  wpt->name      = "Center"; //wpt_node->getStringValue("name", "END");
-  wpt->latitude  = rwy._lat;
-  wpt->longitude = rwy._lon;
-  wpt->altitude  = arr->_elevation + 19;
-  wpt->speed     = 15; 
-  wpt->crossat   = -10000;
-  wpt->gear_down = true;
-  wpt->flaps_down= true;
-  wpt->finished  = false;
-  wpt->on_ground = true;
-  waypoints.push_back(wpt); 
-
-direction = (rand() % 360);
-geo_direct_wgs_84 ( 0, arr->_latitude, arr->_longitude, direction, 
-  100,
-  &lat2, &lon2, &az2 );
-
-  // Add the final destination waypoint
-  wpt = new waypoint;
-  wpt->name      = arr->_id; //wpt_node->getStringValue("name", "END");
-  wpt->latitude  = lat2;
-  wpt->longitude = lon2;
-  wpt->altitude  = arr->_elevation+19;
-  wpt->speed     = 15; 
-  wpt->crossat   = -10000;
-  wpt->gear_down = true;
-  wpt->flaps_down= true;
-  wpt->finished  = false;
-  wpt->on_ground = true;
-  waypoints.push_back(wpt); 
-
-  // And finally one more named "END"
-  wpt = new waypoint;
-  wpt->name      = "END"; //wpt_node->getStringValue("name", "END");
-  wpt->latitude  = lat2;
-  wpt->longitude = lon2;
-  wpt->altitude  = 19;
-  wpt->speed     = 15; 
-  wpt->crossat   = -10000;
-  wpt->gear_down = true;
-  wpt->flaps_down= true;
-  wpt->finished  = true;
-  wpt->on_ground = true;
-  waypoints.push_back(wpt);
-
- // And finally one more named "EOF"
-  wpt = new waypoint;
-  wpt->name      = "EOF"; //wpt_node->getStringValue("name", "END");
-  wpt->latitude  = lat2;
-  wpt->longitude = lon2;
-  wpt->altitude  = 19;
-  wpt->speed     = 15; 
-  wpt->crossat   = -10000;
-  wpt->gear_down = true;
-  wpt->flaps_down= true;
-  wpt->finished  = true;
-  wpt->on_ground  = true;
-  waypoints.push_back(wpt);
 }
index bc4e21b90def720ee00cf1b6a7fd7e66a888866d..c527a57824189b69d1041bbceef817d346e544e9 100644 (file)
@@ -24,6 +24,7 @@
 #include <string>
 
 #include <Airports/simple.hxx>
+#include <Airports/runways.hxx>
 
 #include "AIBase.hxx"
 
@@ -53,15 +54,21 @@ public:
                 double course,
                 time_t start,
                 FGAirport *dep,
-                FGAirport *arr);
+                FGAirport *arr,
+                bool firstLeg,
+                double radius,
+                string fltType,
+                string acType,
+                string airline);
    ~FGAIFlightPlan();
 
    waypoint* getPreviousWaypoint( void );
    waypoint* getCurrentWaypoint( void );
    waypoint* getNextWaypoint( void );
-   void IncrementWaypoint( void );
+   void IncrementWaypoint( bool erase );
 
    double getDistanceToGo(double lat, double lon, waypoint* wp);
+   int getLeg () { return leg;};
    void setLeadDistance(double speed, double bearing, waypoint* current, waypoint* next);
    void setLeadDistance(double distance_ft);
    double getLeadDistance( void ) const {return lead_distance;}
@@ -69,10 +76,17 @@ public:
    double getBearing(double lat, double lon, waypoint* next);
   time_t getStartTime() { return start_time; }; 
 
-  void    create(FGAirport *dep, FGAirport *arr, double alt, double speed);
+  void    create(FGAirport *dep, FGAirport *arr, int leg, double alt, double speed, double lat, double lon,
+                bool firstLeg, double radius, string fltType, string aircraftType, string airline);
 
+  void setLeg(int val) { leg = val;};
+  void setTime(time_t st) { start_time = st; };
+  int getGate() { return gateId; };
+  double getLeadInAngle() { return leadInAngle; };
+  string getRunway() { return rwy._rwy_no; };
+  string getRunwayId() { return rwy._id; };
 private:
-
+  FGRunway rwy;
     typedef vector <waypoint*> wpt_vector_type;
     typedef wpt_vector_type::iterator wpt_vector_iterator;
 
@@ -81,8 +95,21 @@ private:
 
     double distance_to_go;
     double lead_distance;
+  double leadInAngle;
     time_t start_time;
-
+  int leg;
+  int gateId;
+
+  void createPushBack(bool, FGAirport*, double, double, double, string, string, string);
+  void createTaxi(bool, int, FGAirport *, double, string, string, string);
+  void createTakeOff(bool, FGAirport *, double);
+  void createClimb(bool, FGAirport *, double, double);
+  void createCruise(bool, FGAirport*, FGAirport*, double, double, double, double);
+  void createDecent(FGAirport *);
+  void createLanding(FGAirport *);
+  void createParking(FGAirport *);
+  void deleteWaypoints(); 
+  void resetWaypoints();
 };    
 
 
diff --git a/src/AIModel/AIFlightPlanCreate.cxx b/src/AIModel/AIFlightPlanCreate.cxx
new file mode 100644 (file)
index 0000000..f800f52
--- /dev/null
@@ -0,0 +1,822 @@
+/******************************************************************************
+ * AIFlightPlanCreate.cxx
+ * Written by Durk Talsma, started May, 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.
+ *
+ *
+ **************************************************************************/
+#include <AIFlightPlan.hxx>
+#include <simgear/math/sg_geodesy.hxx>
+#include <Airports/runways.hxx>
+
+#include <Environment/environment_mgr.hxx>
+#include <Environment/environment.hxx>
+
+
+/* FGAIFlightPlan::create()
+ * dynamically create a flight plan for AI traffic, based on data provided by the
+ * Traffic Manager, when reading a filed flightplan failes. (DT, 2004/07/10) 
+ *
+ * This is the top-level function, and the only one that publicly available.
+ *
+ */ 
+
+
+// Check lat/lon values during initialization;
+void FGAIFlightPlan::create(FGAirport *dep, FGAirport *arr, int legNr, double alt, double speed, 
+                           double latitude, double longitude, bool firstFlight,
+                           double radius, string fltType, string aircraftType, string airline)
+{ 
+  int currWpt = wpt_iterator - waypoints.begin();
+  switch(legNr)
+    {
+    case 1:
+      //cerr << "Creating Push_Back" << endl;
+      createPushBack(firstFlight,dep, latitude, longitude, radius, fltType, aircraftType, airline);
+      //cerr << "Done" << endl;
+      break;
+    case 2: 
+      //cerr << "Creating Taxi" << endl;
+      createTaxi(firstFlight, 1, dep, radius, fltType, aircraftType, airline);
+      break;
+    case 3: 
+      //cerr << "Creating TAkeoff" << endl;
+      createTakeOff(firstFlight, dep, speed);
+      break;
+    case 4: 
+      //cerr << "Creating Climb" << endl;
+      createClimb(firstFlight, dep, speed, alt);
+      break;
+    case 5: 
+      //cerr << "Creating Cruise" << endl;
+      createCruise(firstFlight, dep,arr, latitude, longitude, speed, alt);
+      break;
+    case 6: 
+      //cerr << "Creating Decent" << endl;
+      createDecent(arr);
+      break;
+    case 7: 
+      //cerr << "Creating Landing" << endl;
+      createLanding(arr);
+      break;
+    case 8: 
+      //cerr << "Creating Taxi 2" << endl;
+      createTaxi(false, 2, arr, radius, fltType, aircraftType, airline);
+      break;
+    case 9: 
+      //cerr << "Creating Parking" << endl;
+      createParking(arr);
+      break;
+    default:
+      //exit(1);
+      cerr << "Unknown case: " << legNr << endl;
+    }
+  wpt_iterator = waypoints.begin()+currWpt;
+  leg++;
+}
+
+/*******************************************************************
+ * createPushBack
+ * initialize the Aircraft at the parking location
+ ******************************************************************/
+void FGAIFlightPlan::createPushBack(bool firstFlight, FGAirport *dep, 
+                                   double latitude,
+                                   double longitude,
+                                   double radius,
+                                   string fltType,
+                                   string aircraftType,
+                                   string airline)
+{
+  double heading;
+  double lat;
+  double lon;
+  double lat2;
+  double lon2;
+  double az2;
+  
+  //int currWpt = wpt_iterator - waypoints.begin();
+  // Erase all existing waypoints.
+  //resetWaypoints();
+  
+  // We only need to get a valid parking if this is the first leg. 
+  // Otherwise use the current aircraft position.
+  if (firstFlight)
+    {
+      if (!(dep->getAvailableParking(&lat, &lon, &heading, &gateId, radius, fltType, aircraftType, airline)))
+       {
+         cerr << "Could not find parking " << endl;
+       }
+    }
+  else
+    {
+      dep->getParking(gateId, &lat, &lon, &heading);
+      //lat     = latitude;
+      //lon     = longitude;
+      //heading = getHeading();
+    }
+  heading += 180.0;
+  if (heading > 360)
+    heading -= 360;
+  waypoint *wpt = new waypoint;
+  wpt->name      = "park";
+  wpt->latitude  = lat;
+  wpt->longitude = lon;
+  wpt->altitude  = dep->getElevation();
+  wpt->speed     = -10; 
+  wpt->crossat   = -10000;
+  wpt->gear_down = true;
+  wpt->flaps_down= true;
+  wpt->finished  = false;
+  wpt->on_ground = true;
+  waypoints.push_back(wpt); 
+  
+  // Add park twice, because it uses park once for initialization and once
+  // to trigger the departure ATC message 
+  geo_direct_wgs_84 ( 0, lat, lon, heading, 
+                     10, 
+                     &lat2, &lon2, &az2 );
+  wpt = new waypoint;
+  wpt->name      = "park2";
+  wpt->latitude  = lat2;
+  wpt->longitude = lon2;
+  wpt->altitude  = dep->getElevation();
+  wpt->speed     = -10; 
+  wpt->crossat   = -10000;
+  wpt->gear_down = true;
+  wpt->flaps_down= true;
+  wpt->finished  = false;
+  wpt->on_ground = true;
+  waypoints.push_back(wpt); 
+  geo_direct_wgs_84 ( 0, lat, lon, heading, 
+                     100, 
+                     &lat2, &lon2, &az2 );
+  wpt = new waypoint;
+  wpt->name      = "taxiStart";
+  wpt->latitude  = lat2;
+  wpt->longitude = lon2;
+  wpt->altitude  = dep->getElevation();
+  wpt->speed     = 10; 
+  wpt->crossat   = -10000;
+  wpt->gear_down = true;
+  wpt->flaps_down= true;
+  wpt->finished  = false;
+  wpt->on_ground = true;
+  waypoints.push_back(wpt); 
+
+  //wpt = new waypoint;
+  //wpt->name = "END";
+  //wpt->finished = false;
+  //waypoints.push_back(wpt);  // add one more to prevent a segfault.  
+  //waypoints.push_back(wpt);  // add one more to prevent a segfault. 
+  //wpt_iterator = waypoints.begin();
+  //if (!firstFlight)
+  //  wpt_iterator++;
+  //wpt_iterator = waypoints.begin()+currWpt;
+}
+
+/*******************************************************************
+ * createCreate Taxi. 
+ * initialize the Aircraft at the parking location
+ ******************************************************************/
+void FGAIFlightPlan::createTaxi(bool firstFlight, int direction, FGAirport *apt, double radius, string fltType, string acType, string airline)
+{
+  double wind_speed;
+  double wind_heading;
+  double heading;
+  //FGRunway rwy;
+  double lat, lon, az;
+  double lat2, lon2, az2;
+  //int direction;
+  waypoint *wpt;
+
+  // Erase all existing waypoints.
+  //   wpt_vector_iterator i= waypoints.begin();
+  //resetWaypoints();
+  //int currWpt = wpt_iterator - waypoints.begin();
+  if (direction == 1)
+    {
+      
+      
+
+     
+      // Get the current active runway, based on code from David Luff
+      // This should actually be unified and extended to include 
+      // Preferential runway use schema's 
+      //FGEnvironment 
+      //stationweather = ((FGEnvironmentMgr *) globals->get_subsystem("environment"))
+      //->getEnvironment(apt->getLatitude(), apt->getLongitude(), apt->getElevation());
+      
+      //wind_speed = stationweather.get_wind_speed_kt();
+      //wind_heading = stationweather.get_wind_from_heading_deg();
+      //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 name;
+      apt->getActiveRunway("com", 1, &name);
+      if (!(globals->get_runways()->search(apt->getId(), 
+                                           name, 
+                                           &rwy)))
+       {
+         cout << "Failed to find runway for " << apt->getId() << endl;
+         // Hmm, how do we handle a potential error like this?
+         exit(1);
+       }
+      //string test;
+      //apt->getActiveRunway(string("com"), 1, &test);
+      //exit(1);
+      
+      heading = rwy._heading;
+      double azimuth = heading + 180.0;
+      while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
+      geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, 
+                         rwy._length * SG_FEET_TO_METER * 0.5 - 5.0,
+                         &lat2, &lon2, &az2 );
+      
+      //Add the runway startpoint;
+      wpt = new waypoint;
+      wpt->name      = "Airport Center";
+      wpt->latitude  = apt->getLatitude();
+      wpt->longitude = apt->getLongitude();
+      wpt->altitude  = apt->getElevation();
+      wpt->speed     = 15; 
+      wpt->crossat   = -10000;
+      wpt->gear_down = true;
+      wpt->flaps_down= true;
+      wpt->finished  = false;
+      wpt->on_ground = true;
+      waypoints.push_back(wpt);
+       
+      //Add the runway startpoint;
+      wpt = new waypoint;
+      wpt->name      = "Runway Takeoff";
+      wpt->latitude  = lat2;
+      wpt->longitude = lon2;
+      wpt->altitude  = apt->getElevation();
+      wpt->speed     = 15; 
+      wpt->crossat   = -10000;
+      wpt->gear_down = true;
+      wpt->flaps_down= true;
+      wpt->finished  = false;
+      wpt->on_ground = true;
+      waypoints.push_back(wpt);
+      //wpt = new waypoint;
+      //wpt->finished = false;
+      //waypoints.push_back(wpt);  // add one more to prevent a segfault. 
+    }
+  else
+    {
+      //direction = (rand() % 360);
+      //geo_direct_wgs_84 ( 0, arr->getLatitude(), arr->getLongitude(), direction, 
+      //100,
+      //&lat2, &lon2, &az2 );
+      
+      // This next statement really requires the flight plan to be
+      // split up into smaller sections, because 
+      // gate assignments will typically not be known until minutes before 
+      // landing, and certainly not at the start of a 10 hour flight.
+      apt->getAvailableParking(&lat, &lon, &heading, &gateId, radius, fltType, acType, airline);
+      heading += 180.0;
+      if (heading > 360)
+       heading -= 360;
+      geo_direct_wgs_84 ( 0, lat, lon, heading, 
+                         100,
+                         &lat2, &lon2, &az2 );
+      //Add the runway center
+      wpt = new waypoint;
+      wpt->name      = "Airport Center";
+      wpt->latitude  = apt->getLatitude();
+      wpt->longitude = apt->getLongitude();
+      wpt->altitude  = apt->getElevation();
+      wpt->speed     = 15; 
+      wpt->crossat   = -10000;
+      wpt->gear_down = true;
+      wpt->flaps_down= true;
+      wpt->finished  = false;
+      wpt->on_ground = true;
+      waypoints.push_back(wpt);
+
+      // Add the final destination waypoint
+      wpt = new waypoint;
+      wpt->name      = "Begin Parkingg"; //apt->getId(); //wpt_node->getStringValue("name", "END");
+      wpt->latitude  = lat2;
+      wpt->longitude = lon2;
+      wpt->altitude  = apt->getElevation();
+      wpt->speed     = 15; 
+      wpt->crossat   = -10000;
+      wpt->gear_down = true;
+      wpt->flaps_down= true;
+      wpt->finished  = false;
+      wpt->on_ground = true;
+      waypoints.push_back(wpt); 
+
+     
+    }
+  // wpt_iterator = waypoints.begin();
+  //if (!firstFlight)
+  // wpt_iterator++; 
+  //wpt_iterator = waypoints.begin()+currWpt;
+}
+
+/*******************************************************************
+ * CreateTakeOff 
+ * initialize the Aircraft at the parking location
+ ******************************************************************/
+void FGAIFlightPlan::createTakeOff(bool firstFlight, FGAirport *apt, double speed)
+{
+  double wind_speed;
+  double wind_heading;
+  double heading;
+  //FGRunway rwy;
+  double lat, lon, az;
+  double lat2, lon2, az2;
+  //int direction;
+  waypoint *wpt;
+  
+  
+  // Erase all existing waypoints.
+  // wpt_vector_iterator i= waypoints.begin();
+  //while(waypoints.begin() != waypoints.end())
+  //  {      
+  //    delete *(i);
+  //    waypoints.erase(i);
+  //  }
+  //resetWaypoints();
+  
+  
+  // Get the current active runway, based on code from David Luff
+  // This should actually be unified and extended to include 
+  // Preferential runway use schema's 
+  if (firstFlight)
+    {
+      string name;
+      apt->getActiveRunway("com", 1, &name);
+       if (!(globals->get_runways()->search(apt->getId(), 
+                                             name, 
+                                             &rwy)))
+         {
+           cout << "Failed to find runway for " << apt->getId() << endl;
+           // Hmm, how do we handle a potential error like this?
+           exit(1);
+         }
+       //string test;
+      //apt->getActiveRunway(string("com"), 1, &test);
+      //exit(1);
+    }
+  
+  heading = rwy._heading;
+  double azimuth = heading + 180.0;
+  while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
+  geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, 
+                     rwy._length * SG_FEET_TO_METER * 0.5 - 105.0,
+                     &lat2, &lon2, &az2 );
+  wpt = new waypoint; 
+  wpt->name      = "accel"; 
+  wpt->latitude  = lat2; 
+  wpt->longitude = lon2; 
+  wpt->altitude  = apt->getElevation();
+  wpt->speed     = speed;  
+  wpt->crossat   = -10000;
+  wpt->gear_down = true;
+  wpt->flaps_down= true;
+  wpt->finished  = false;
+  wpt->on_ground = true;
+  waypoints.push_back(wpt); 
+  
+  lat = lat2;
+  lon = lon2;
+  az  = az2;
+  
+  //Next: the Start of Climb
+  geo_direct_wgs_84 ( 0, lat, lon, heading, 
+  2560 * SG_FEET_TO_METER,
+  &lat2, &lon2, &az2 );
+  
+  wpt = new waypoint;
+  wpt->name      = "SOC";
+  wpt->latitude  = lat2;
+  wpt->longitude = lon2;
+  wpt->altitude  = apt->getElevation()+3000;
+  wpt->speed     = speed; 
+  wpt->crossat   = -10000;
+  wpt->gear_down = true;
+  wpt->flaps_down= true;
+  wpt->finished  = false;
+  wpt->on_ground = false;
+  waypoints.push_back(wpt);
+  //  waypoints.push_back(wpt);
+  //waypoints.push_back(wpt);  // add one more to prevent a segfault. 
+  // wpt_iterator = waypoints.begin();
+  //if (!firstFlight)
+  // wpt_iterator++;
+}
+/*******************************************************************
+ * CreateClimb
+ * initialize the Aircraft at the parking location
+ ******************************************************************/
+void FGAIFlightPlan::createClimb(bool firstFlight, FGAirport *apt, double speed, double alt)
+{
+  double wind_speed;
+  double wind_heading;
+  double heading;
+  //FGRunway rwy;
+  double lat, lon, az;
+  double lat2, lon2, az2;
+  //int direction;
+  waypoint *wpt;
+
+  // Erase all existing waypoints.
+  // wpt_vector_iterator i= waypoints.begin();
+  //while(waypoints.begin() != waypoints.end())
+  //  {      
+  //    delete *(i);
+  //    waypoints.erase(i);
+  //  }
+  //resetWaypoints();
+  
+  
+  // Get the current active runway, based on code from David Luff
+  // This should actually be unified and extended to include 
+  // Preferential runway use schema's 
+  if (firstFlight)
+    {
+      string name;
+      apt->getActiveRunway("com", 1, &name);
+       if (!(globals->get_runways()->search(apt->getId(), 
+                                             name, 
+                                             &rwy)))
+         {
+           cout << "Failed to find runway for " << apt->getId() << endl;
+           // Hmm, how do we handle a potential error like this?
+           exit(1);
+         }
+       //string test;
+       //apt->getActiveRunway(string("com"), 1, &test);
+      //exit(1);
+    }
+  
+  
+  heading = rwy._heading;
+  double azimuth = heading + 180.0;
+  while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
+  geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, heading, 
+                     10*SG_NM_TO_METER,
+                     &lat2, &lon2, &az2 );
+  wpt = new waypoint;
+  wpt->name      = "10000ft climb";
+  wpt->latitude  = lat2;
+  wpt->longitude = lon2;
+  wpt->altitude  = 10000;
+  wpt->speed     = speed; 
+  wpt->crossat   = -10000;
+  wpt->gear_down = true;
+  wpt->flaps_down= true;
+  wpt->finished  = false;
+  wpt->on_ground = false;
+  waypoints.push_back(wpt); 
+  
+
+  geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, heading, 
+                     20*SG_NM_TO_METER,
+                     &lat2, &lon2, &az2 );
+  wpt = new waypoint;
+  wpt->name      = "18000ft climb";
+  wpt->latitude  = lat2;
+  wpt->longitude = lon2;
+  wpt->altitude  = 18000;
+  wpt->speed     = speed; 
+  wpt->crossat   = -10000;
+  wpt->gear_down = true;
+  wpt->flaps_down= true;
+  wpt->finished  = false;
+  wpt->on_ground = false;
+  waypoints.push_back(wpt); 
+  //waypoints.push_back(wpt); 
+  //waypoints.push_back(wpt);  // add one more to prevent a segfault. 
+  // wpt_iterator = waypoints.begin();
+  //if (!firstFlight)
+  // wpt_iterator++;
+}
+
+
+/*******************************************************************
+ * CreateCruise
+ * initialize the Aircraft at the parking location
+ ******************************************************************/
+void FGAIFlightPlan::createCruise(bool firstFlight, FGAirport *dep, FGAirport *arr, double latitude, double longitude, double speed, double alt)
+{
+  double wind_speed;
+  double wind_heading;
+  double heading;
+  //FGRunway rwy;
+  double lat, lon, az;
+  double lat2, lon2, az2;
+  double azimuth;
+  //int direction;
+  waypoint *wpt;
+
+  // Erase all existing waypoints.
+  // wpt_vector_iterator i= waypoints.begin();
+  //while(waypoints.begin() != waypoints.end())
+  //  {      
+  //    delete *(i);
+  //    waypoints.erase(i);
+  //  }
+  //resetWaypoints();
+
+  wpt = new waypoint;
+  wpt->name      = "Cruise"; //wpt_node->getStringValue("name", "END");
+  wpt->latitude  = latitude;
+  wpt->longitude = longitude;
+  wpt->altitude  = alt;
+  wpt->speed     = speed; 
+  wpt->crossat   = -10000;
+  wpt->gear_down = false;
+  wpt->flaps_down= false;
+  wpt->finished  = false;
+  wpt->on_ground = false;
+  waypoints.push_back(wpt); 
+  //Beginning of Decent
+  string name;
+  arr->getActiveRunway("com", 2, &name);
+  if (!(globals->get_runways()->search(arr->getId(), 
+                                      name, 
+                                      &rwy)))
+    {
+      cout << "Failed to find runway for " << arr->getId() << endl;
+      // Hmm, how do we handle a potential error like this?
+      exit(1);
+    }
+  //string test;
+  //arr->getActiveRunway(string("com"), 1, &test);
+  //exit(1);
+  
+  //cerr << "Altitude = " << alt << endl;
+  //cerr << "Done" << endl;
+  //if (arr->getId() == "EHAM")
+  //  {
+  //    cerr << "Creating cruise to EHAM " << latitude << " " << longitude << endl;
+  //  }
+  heading = rwy._heading;
+  azimuth = heading + 180.0;
+  while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
+  
+  
+  // Note: This places us at the location of the active 
+  // runway during initial cruise. This needs to be 
+  // fixed later. 
+  geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, 
+                     110000,
+                     &lat2, &lon2, &az2 );
+  wpt = new waypoint;
+  wpt->name      = "BOD"; //wpt_node->getStringValue("name", "END");
+  wpt->latitude  = lat2;
+  wpt->longitude = lon2;
+  wpt->altitude  = alt;
+  wpt->speed     = speed; 
+  wpt->crossat   = alt;
+  wpt->gear_down = false;
+  wpt->flaps_down= false;
+  wpt->finished  = false;
+  wpt->on_ground = false;
+  waypoints.push_back(wpt); 
+  //waypoints.push_back(wpt);
+  //waypoints.push_back(wpt);  // add one more to prevent a segfault.  
+  //wpt_iterator = waypoints.begin();
+  //if (!firstFlight)
+  // wpt_iterator++;
+}
+
+/*******************************************************************
+ * CreateDecent
+ * initialize the Aircraft at the parking location
+ ******************************************************************/
+void FGAIFlightPlan::createDecent(FGAirport *apt)
+{
+
+  // Ten thousand ft. Slowing down to 240 kts
+  double wind_speed;
+  double wind_heading;
+  double heading;
+  //FGRunway rwy;
+  double lat, lon, az;
+  double lat2, lon2, az2;
+  double azimuth;
+  //int direction;
+  waypoint *wpt;
+
+  //// Erase all existing waypoints.
+  // wpt_vector_iterator i= waypoints.begin();
+  //while(waypoints.begin() != waypoints.end())
+  //  {      
+  //    delete *(i);
+  //    waypoints.erase(i);
+  //  }
+  //resetWaypoints();
+
+  //Beginning of Decent
+  string name;
+  apt->getActiveRunway("com", 2, &name);
+    if (!(globals->get_runways()->search(apt->getId(), 
+                                         name, 
+                                         &rwy)))
+      {
+       cout << "Failed to find runway for " << apt->getId() << endl;
+       // Hmm, how do we handle a potential error like this?
+       exit(1);
+      }
+    //string test;
+    //apt->getActiveRunway(string("com"), 1, &test);
+  //exit(1);
+
+  //cerr << "Done" << endl;
+  heading = rwy._heading;
+  azimuth = heading + 180.0;
+  while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
+  
+  
+  
+  geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, 
+                     100000,
+                     &lat2, &lon2, &az2 );
+  
+  wpt = new waypoint;
+  wpt->name      = "Dec 10000ft"; //wpt_node->getStringValue("name", "END");
+  wpt->latitude  = lat2;
+  wpt->longitude = lon2;
+  wpt->altitude  = apt->getElevation();
+  wpt->speed     = 240; 
+  wpt->crossat   = 10000;
+  wpt->gear_down = false;
+  wpt->flaps_down= false;
+  wpt->finished  = false;
+  wpt->on_ground = false;
+  waypoints.push_back(wpt);  
+
+  // Three thousand ft. Slowing down to 160 kts
+  geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, 
+                    8*SG_NM_TO_METER,
+                    &lat2, &lon2, &az2 );
+  wpt = new waypoint;
+  wpt->name      = "DEC 3000ft"; //wpt_node->getStringValue("name", "END");
+  wpt->latitude  = lat2;
+  wpt->longitude = lon2;
+  wpt->altitude  = apt->getElevation();
+  wpt->speed     = 160; 
+  wpt->crossat   = 3000;
+  wpt->gear_down = true;
+  wpt->flaps_down= true;
+  wpt->finished  = false;
+  wpt->on_ground = false;
+  waypoints.push_back(wpt);
+  //waypoints.push_back(wpt);
+  //waypoints.push_back(wpt);  // add one more to prevent a segfault. 
+  //wpt_iterator = waypoints.begin();
+  //wpt_iterator++;
+  //if (apt->getId() == "EHAM")
+  //  {
+  //    cerr << "Created Decend to EHAM " << lat2 << " " << lon2 << ": Runway = " << rwy._rwy_no 
+  //      << "heading " << heading << endl;
+  //  }
+}
+/*******************************************************************
+ * CreateLanding
+ * initialize the Aircraft at the parking location
+ ******************************************************************/
+void FGAIFlightPlan::createLanding(FGAirport *apt)
+{
+  // Ten thousand ft. Slowing down to 240 kts
+  double wind_speed;
+  double wind_heading;
+  double heading;
+  //FGRunway rwy;
+  double lat, lon, az;
+  double lat2, lon2, az2;
+  double azimuth;
+  //int direction;
+  waypoint *wpt;
+
+  
+  heading = rwy._heading;
+  azimuth = heading + 180.0;
+  while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
+
+  //Runway Threshold
+ geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, 
+                    rwy._length*0.45 * SG_FEET_TO_METER,
+                    &lat2, &lon2, &az2 );
+  wpt = new waypoint;
+  wpt->name      = "Threshold"; //wpt_node->getStringValue("name", "END");
+  wpt->latitude  = lat2;
+  wpt->longitude = lon2;
+  wpt->altitude  = apt->getElevation();
+  wpt->speed     = 150; 
+  wpt->crossat   = apt->getElevation();
+  wpt->gear_down = true;
+  wpt->flaps_down= true;
+  wpt->finished  = false;
+  wpt->on_ground = true;
+  waypoints.push_back(wpt); 
+
+ //Full stop at the runway centerpoint
+ geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, 
+                    rwy._length*0.45,
+                     &lat2, &lon2, &az2 );
+  wpt = new waypoint;
+  wpt->name      = "Center"; //wpt_node->getStringValue("name", "END");
+  wpt->latitude  = rwy._lat;
+  wpt->longitude = rwy._lon;
+  wpt->altitude  = apt->getElevation();
+  wpt->speed     = 30; 
+  wpt->crossat   = -10000;
+  wpt->gear_down = true;
+  wpt->flaps_down= true;
+  wpt->finished  = false;
+  wpt->on_ground = true;
+  waypoints.push_back(wpt);
+
+ geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, heading, 
+                    rwy._length*0.45 * SG_FEET_TO_METER,
+                    &lat2, &lon2, &az2 );
+  wpt = new waypoint;
+  wpt->name      = "Threshold"; //wpt_node->getStringValue("name", "END");
+  wpt->latitude  = lat2;
+  wpt->longitude = lon2;
+  wpt->altitude  = apt->getElevation();
+  wpt->speed     = 15; 
+  wpt->crossat   = apt->getElevation();
+  wpt->gear_down = true;
+  wpt->flaps_down= true;
+  wpt->finished  = false;
+  wpt->on_ground = true;
+  waypoints.push_back(wpt); 
+  //waypoints.push_back(wpt); 
+  //waypoints.push_back(wpt);  // add one more to prevent a segfault. 
+  //wpt_iterator = waypoints.begin();
+  //wpt_iterator++;
+
+  //if (apt->getId() == "EHAM")
+  //{
+  //  cerr << "Created Landing to EHAM " << lat2 << " " << lon2 << ": Runway = " << rwy._rwy_no 
+  //    << "heading " << heading << endl;
+  //}
+}
+
+/*******************************************************************
+ * CreateParking
+ * initialize the Aircraft at the parking location
+ ******************************************************************/
+void FGAIFlightPlan::createParking(FGAirport *apt)
+{
+  waypoint* wpt;
+  double lat;
+  double lon;
+  double heading;
+  apt->getParking(gateId, &lat, &lon, &heading);
+  heading += 180.0;
+  if (heading > 360)
+    heading -= 360; 
+
+  // Erase all existing waypoints.
+  // wpt_vector_iterator i= waypoints.begin();
+  //while(waypoints.begin() != waypoints.end())
+  //  {      
+  //    delete *(i);
+  //    waypoints.erase(i);
+  //  }
+  //resetWaypoints();
+  // And finally one more named "END"
+  wpt = new waypoint;
+  wpt->name      = "END"; //wpt_node->getStringValue("name", "END");
+  wpt->latitude  = lat;
+  wpt->longitude = lon;
+  wpt->altitude  = 19;
+  wpt->speed     = 15; 
+  wpt->crossat   = -10000;
+  wpt->gear_down = true;
+  wpt->flaps_down= true;
+  wpt->finished  = false;
+  wpt->on_ground = true;
+  waypoints.push_back(wpt);
+  //waypoints.push_back(wpt);
+  //waypoints.push_back(wpt);  // add one more to prevent a segfault. 
+  //wpt_iterator = waypoints.begin();
+  //wpt_iterator++;
+}
index 25f5425c7793cc5e0e9e9370084f7681e6c8bb6a..52d8e3da96d7879d967019bf8d173707b1ae397a 100644 (file)
@@ -156,6 +156,8 @@ FGAIManager::createAircraft( FGAIModelEntity *entity,   FGAISchedule *ref) {
         } else {
           ai_plane->SetPerformance(&FGAIAircraft::settings[FGAIAircraft::JET_TRANSPORT]);
         }
+       ai_plane->setAcType(entity->acType);
+       ai_plane->setCompany(entity->company);
         ai_plane->setHeading(entity->heading);
         ai_plane->setSpeed(entity->speed);
         ai_plane->setPath(entity->path.c_str());
index a44c13f90c00186e339f93898cfbbd9ddfe9df53..fc2aafeec10d88e8c0beafbd154a0f29b8ee6f38 100644 (file)
@@ -9,7 +9,7 @@ libAIModel_a_SOURCES = \
        AIBallistic.hxx AIBallistic.cxx \
        AIStorm.hxx AIStorm.cxx \
        AIThermal.hxx AIThermal.cxx \
-       AIFlightPlan.hxx AIFlightPlan.cxx \
+       AIFlightPlan.hxx AIFlightPlan.cxx AIFlightPlanCreate.cxx \
        AIScenario.hxx AIScenario.cxx \
         AICarrier.hxx AICarrier.cxx
 
index 50662f547952809e3b188ae3cf0dc88bd89eba26..93a878388e02ce2396368adaaec874160e54c59d 100644 (file)
@@ -133,7 +133,7 @@ void FGAIMgr::init() {
                                f_ident = file.substr(0, pos);
                                FGAirport a;
                                if(dclFindAirportID(f_ident, &a)) {
-                                       SGBucket sgb(a._longitude, a._latitude);
+                                       SGBucket sgb(a.getLongitude(), a.getLatitude());
                                        int idx = sgb.gen_index();
                                        if(facilities.find(idx) != facilities.end()) {
                                                facilities[idx]->push_back(f_ident);
index 0c96b36cefef1f8114ba26aa53472b72a4b229b7..42d8bf7be7f5b873d618145900c0569d2afaad84 100644 (file)
@@ -460,7 +460,7 @@ void FGATCDialog::FreqDisplay(string ident) {
     FGAirport a;
     if ( dclFindAirportID( ident, &a ) ) {
                comm_list_type stations;
-               int found = current_commlist->FindByPos(a._longitude, a._latitude, a._elevation, 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 26b1bc801e65e1b3471c81a59b784e944225feac..8084b0822d1704b246c7f8ec2453498a992f5974 100644 (file)
@@ -221,9 +221,9 @@ bool FGATCMgr::AIRegisterAirport(string ident) {
                        //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._longitude;
-                       a->lat = ap._latitude;
-                       a->elev = ap._elevation;
+                       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;
@@ -270,9 +270,9 @@ bool FGATCMgr::CommRegisterAirport(string ident, int chan, atc_type tp) {
                if(dclFindAirportID(ident, &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._longitude;
-                       a->lat = ap._latitude;
-                       a->elev = ap._elevation;
+                       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 55e9be7aa82a5b858d8651036bf7661f9f6d2136..02b0dc619772750d94666c8553aae77d96f22c23 100644 (file)
@@ -314,7 +314,7 @@ bool dclFindAirportID( const string& id, FGAirport *a ) {
         SG_LOG( SG_GENERAL, SG_INFO, "Searching for airport code = " << id );
 
         result = globals->get_airports()->search( id );
-        if ( result._id.empty() ) {
+        if ( result.getId().empty() ) {
             SG_LOG( SG_GENERAL, SG_WARN,
                     "Failed to find " << id << " in basic.dat.gz" );
             return false;
@@ -327,8 +327,8 @@ bool dclFindAirportID( const string& id, FGAirport *a ) {
 
     SG_LOG( SG_GENERAL, SG_INFO,
             "Position for " << id << " is ("
-            << a->_longitude << ", "
-            << a->_latitude << ")" );
+            << a->getLongitude() << ", "
+            << a->getLatitude() << ")" );
 
     return true;
 }
@@ -342,7 +342,7 @@ double dclGetAirportElev( const string& id ) {
             "Finding elevation for airport: " << id );
 
     if ( dclFindAirportID( id, &a ) ) {
-        return a._elevation * SG_FEET_TO_METER;
+        return a.getElevation() * SG_FEET_TO_METER;
     } else {
         return -9999.0;
     }
@@ -357,7 +357,7 @@ Point3D dclGetAirportPos( const string& id ) {
             "Finding position for airport: " << id );
 
     if ( dclFindAirportID( id, &a ) ) {
-        return Point3D(a._longitude, a._latitude, a._elevation);
+        return Point3D(a.getLongitude(), a.getLatitude(), a.getElevation());
     } else {
         return Point3D(0.0, 0.0, -9999.0);
     }
index a88ba3521eb3517247b0252945b58d2ae2af79a8..18e17173038dafa075ae6e54f1764bed92bb7b65 100644 (file)
@@ -276,7 +276,7 @@ bool FGCommList::FindByCode( string ICAO, ATCData& ad, atc_type tp ) {
     FGAirport a;
     if ( dclFindAirportID( ICAO, &a ) ) {
                comm_list_type stations;
-               int found = FindByPos(a._longitude, a._latitude, a._elevation, 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 a749bcda9be5a2521255db4437e54eac136ce68f..8de4822a0788c858d94ad319044f9833d808efdb 100644 (file)
@@ -232,8 +232,8 @@ bool fgAirportDBLoad( FGAirportList *airports, FGRunwayList *runways,
         if ( ident == "#" || ident == "//" ) {
             metar_in >> skipeol;
         } else {
-            FGAirport a = airports->search( ident );
-            if ( a._id == ident ) {
+            const FGAirport &a = airports->search( ident );
+            if ( a.getId() == ident ) {
                 airports->has_metar( ident );
             }
         }
index 5a3e509dc10549bc218650f874430fee235868e9..5c74391b486a05dd64dadd6f901084a76eb2bcf1 100644 (file)
@@ -4,6 +4,7 @@
 //               elevation in feet.
 //
 // Written by Curtis Olson, started April 1998.
+// Updated by Durk Talsma, started December, 2004.
 //
 // Copyright (C) 1998  Curtis L. Olson  - http://www.flightgear.org/~curt
 //
 #include <math.h>
 
 #include <simgear/compiler.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
 
 
 SG_USING_NAMESPACE(std);
 
+/******************************************************************************
+ * 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()))
+    {
+      cerr << "Unable to parse schedule times" << endl;
+      exit(1);
+    }
+  else
+    {
+      int nrItems = start.size();
+      //cerr << "Nr of items to process: " << nrItems << endl;
+      if (nrItems > 0)
+       {
+         for (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(string tp, 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;
+}
+
+void RunwayGroup::setActive(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 {
+                 cerr << "Failed to find runway " << name << " at " << aptId << endl;
+                 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 {
+                 cerr << "Failed to find runway " << name << " at " << aptId << endl;
+                 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 == 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;
+  }
+}
+
+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(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;
+}
+
+/*********************************************************************************
+ * FGParking
+ ********************************************************************************/
+FGParking::FGParking(double lat,
+                    double lon,
+                    double hdg,
+                    double rad,
+                    int idx,
+                    string name,
+                    string tpe,
+                    string codes)
+{
+  latitude     = lat;
+  longitude    = lon;
+  heading      = hdg;
+  parkingName  = name;
+  index        = idx;
+  type         = tpe;
+  airlineCodes = codes;
+}
+
+double FGParking::processPosition(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;
+}
+
+/***************************************************************************
+ * FGAirport
+ ***************************************************************************/
+FGAirport::FGAirport() : _longitude(0), _latitude(0), _elevation(0)
+{
+  lastUpdate = 0;
+  for (int i = 0; i < 10; i++)
+    {
+      avWindHeading [i] = 0;
+      avWindSpeed   [i] = 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 i= other.parkings.begin(); i != other.parkings.end(); i++)
+    parkings.push_back(*(i));
+  rwyPrefs = other.rwyPrefs;
+  lastUpdate = other.lastUpdate;
+  
+  stringVecConstIterator i;
+  for (i = other.landing.begin(); i != other.landing.end(); i++)
+    landing.push_back(*i);
+  for (i = other.takeoff.begin(); i != other.takeoff.end(); i++)
+    takeoff.push_back(*i);
+  lastUpdate = other.lastUpdate;
+  for (int i = 0; i < 10; i++)
+    {
+      avWindHeading [i] = other.avWindHeading[i];
+      avWindSpeed   [i] = other.avWindSpeed  [i];
+    }
+}
+
+FGAirport::FGAirport(string id, double lon, double lat, double elev, string name, bool has_metar)
+{
+  _id = id;
+  _longitude = lon;
+  _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;
+    }
+}
+
+bool FGAirport::getAvailableParking(double *lat, double *lon, double *heading, int *gateId, double rad, string flType, string acType, 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 < parkings.size()) 
+    return &(parkings[i]); 
+  else 
+    return 0;
+}
+string FGAirport::getParkingName(int i) 
+{ 
+  if (i < parkings.size() && i >= 0) 
+    return (parkings[i].getName()); 
+  else 
+    return string("overflow");
+}
+void FGAirport::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  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;
+  //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);
+    }  
+  // sort by radius, in asending order, so that smaller gates are first in the list
+  sort(parkings.begin(), parkings.end());
+}
+
+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(FGRunwayPreference& ref)
+{
+  rwyPrefs = ref;
+  //cerr << "Exiting due to not implemented yet" << endl;
+  //exit(1);
+}
+void FGAirport::getActiveRunway(string trafficType, int action, string *runway)
+{
+  double windSpeed;
+  double windHeading;
+  double maxTail;
+  double maxCross;
+  string name;
+  string type;
+
+  if (!(rwyPrefs.available()))
+    {
+      chooseRunwayFallback(runway);
+      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
+             chooseRunwayFallback(runway);
+           }
+       } 
+      if (action == 2) // landing
+       {
+         int nr = landing.size();
+         if (nr)
+           {
+             *runway = landing[(rand() % nr)];
+           }
+         else
+           {  //fallback
+              chooseRunwayFallback(runway);
+           }
+       }
+      
+      //*runway = globals->get_runways()->search(_id, int(windHeading));
+      //cerr << "Seleceted runway: " << *runway << endl;
+    }
+}
+
+void FGAirport::chooseRunwayFallback(string *runway)
+{   
+  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.
+  }
+  
+  *runway = globals->get_runways()->search(_id, int(windHeading));
+  return; // generic fall back goes here
+}
+
+/******************************************************************************
+ * FGAirportList
+ *****************************************************************************/
+
 
 // add an entry to the list
 void FGAirportList::add( const string id, const double longitude,
                          const double latitude, const double elevation,
                          const string name, const bool has_metar )
 {
-    FGAirport a;
-    a._id = id;
-    a._longitude = longitude;
-    a._latitude = latitude;
-    a._elevation = elevation;
-    a._name = name;
-    a._has_metar = has_metar;
-    airports_by_id[a._id] = a;
-    airports_array.push_back( &airports_by_id[a._id] );
+  FGRunwayPreference rwyPrefs;
+    FGAirport a(id, longitude, latitude, elevation, name, has_metar);
+    //a._id = id;
+    //a._longitude = longitude;
+    //a._latitude = latitude;
+    //a._elevation = elevation;
+    //a._name = name;
+    //a._has_metar = 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 (parkpath.exists()) 
+      {
+       try {
+         readXML(parkpath.str(),a);
+       } 
+       catch  (const sg_exception &e) {
+         //cerr << "unable to read " << parkpath.str() << endl;
+       }
+      }
+    if (rwyPrefPath.exists()) 
+      {
+       try {
+         readXML(rwyPrefPath.str(), rwyPrefs);
+         a.setRwyUse(rwyPrefs);
+       }
+       catch  (const sg_exception &e) {
+         //cerr << "unable to read " << rwyPrefPath.str() << endl;
+         //exit(1);
+       }
+      }
+    
+    airports_by_id[a.getId()] = a;
+    // try and read in an auxilary file
+   
+    airports_array.push_back( &airports_by_id[a.getId()] );
     SG_LOG( SG_GENERAL, SG_BULK, "Adding " << id << " pos = " << longitude
             << ", " << latitude << " elev = " << elevation );
 }
@@ -64,6 +1198,12 @@ FGAirport FGAirportList::search( const string& id) {
     return airports_by_id[id];
 }
 
+// search for the specified id and return a pointer
+FGAirport* FGAirportList::search( const string& id, FGAirport *result) {
+  FGAirport* retval = airports_by_id[id].getAddress();
+  //cerr << "Returning Airport of string " << id << " results in " << retval->getId();
+  return retval;
+}
 
 // search for the airport nearest the specified position
 FGAirport FGAirportList::search( double lon_deg, double lat_deg,
@@ -73,10 +1213,10 @@ FGAirport FGAirportList::search( double lon_deg, double lat_deg,
     unsigned int i;
     for ( i = 0; i < airports_array.size(); ++i ) {
         // crude manhatten distance based on lat/lon difference
-        double d = fabs(lon_deg - airports_array[i]->_longitude)
-            + fabs(lat_deg - airports_array[i]->_latitude);
+        double d = fabs(lon_deg - airports_array[i]->getLongitude())
+            + fabs(lat_deg - airports_array[i]->getLatitude());
         if ( d < min_dist ) {
-            if ( !with_metar || (with_metar&&airports_array[i]->_has_metar) ) {
+            if ( !with_metar || (with_metar&&airports_array[i]->getMetar()) ) {
                 closest = i;
                 min_dist = d;
             }
@@ -107,7 +1247,7 @@ const FGAirport *FGAirportList::getAirport( int index ) const
  * Mark the specified airport record as not having metar
  */
 void FGAirportList::no_metar( const string &id ) {
-    airports_by_id[id]._has_metar = false;
+    airports_by_id[id].setMetar(false);
 }
 
 
@@ -115,5 +1255,5 @@ void FGAirportList::no_metar( const string &id ) {
  * Mark the specified airport record as (yes) having metar
  */
 void FGAirportList::has_metar( const string &id ) {
-    airports_by_id[id]._has_metar = true;
+    airports_by_id[id].setMetar(true);
 }
index 4cb19528e1368d3986a3583ced1adfaab8cdcdd1..40eed975830dfd708af512d3adbb6d4ea3b6e542 100644 (file)
@@ -3,6 +3,7 @@
 //                 elevation in feet.
 //
 // Written by Curtis Olson, started April 1998.
+// Updated by Durk Talsma, started December 2004.
 //
 // Copyright (C) 1998  Curtis L. Olson  - http://www.flightgear.org/~curt
 //
@@ -37,6 +38,7 @@
 #endif
 
 #include <simgear/compiler.h>
+#include <simgear/xml/easyxml.hxx>
 
 #include STL_STRING
 #include <map>
@@ -46,17 +48,249 @@ SG_USING_STD(string);
 SG_USING_STD(map);
 SG_USING_STD(vector);
 
+typedef vector<string> stringVec;
+typedef vector<string>::iterator stringVecIterator;
+typedef vector<string>::const_iterator stringVecConstIterator;
 
-struct FGAirport {
-    string _id;
-    double _longitude;
-    double _latitude;
-    double _elevation;
-    string _code;               // depricated and can be removed
-    string _name;
-    bool _has_metar;
+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() {};
+  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(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(string, 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(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;
+/******************************************************************************/
 
-    FGAirport() : _longitude(0), _latitude(0), _elevation(0) {}
+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(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);
+};
+
+class FGParking {
+private:
+  double latitude;
+  double longitude;
+  double heading;
+  double radius;
+  int index;
+  string parkingName;
+  string type;
+  string airlineCodes;
+
+  bool available;
+
+  double processPosition(string pos);
+
+public:
+  FGParking() { available = true;};
+  //FGParking(FGParking &other);
+  FGParking(double lat,
+           double lon,
+           double hdg,
+           double rad,
+           int idx,
+           string name,
+           string tpe,
+           string codes);
+  void setLatitude (string lat)  { latitude    = processPosition(lat);  };
+  void setLongitude(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     (string name) { parkingName = name; };
+  void setType     (string tpe)  { type        = tpe;  };
+  void setCodes    (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 FGAirport : public XMLVisitor{
+private:
+  string _id;
+  double _longitude;
+  double _latitude;
+  double _elevation;
+  string _code;               // depricated and can be removed
+  string _name;
+  bool _has_metar;
+  FGParkingVec parkings;
+  FGRunwayPreference rwyPrefs;
+
+ 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];
+
+public:
+  FGAirport();
+  FGAirport(const FGAirport &other);
+  //operator= (FGAirport &other);
+  FGAirport(string id, double lon, double lat, double elev, string name, bool has_metar);
+  void getActiveRunway(string trafficType, int action, string *runway);
+  void chooseRunwayFallback(string *runway);
+  bool getAvailableParking(double *lat, double *lon, double *heading, int *gate, double rad, string fltype, 
+                          string acType, 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); 
+  const string getId() const { return _id;};
+  const string &getName() const { return _name;};
+  FGAirport *getAddress() { return this; };
+  double getLongitude() { return _longitude;};
+  double getLatitude()  { return _latitude; };
+  double getElevation() { return _elevation;};
+  bool   getMetar()     { return _has_metar;};
+  
+
+  void setId(string id) { _id = id;};
+  void setMetar(bool value) { _has_metar = value; };
+
+  void setRwyUse(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);
 };
 
 typedef map < string, FGAirport > airport_map;
@@ -97,6 +331,8 @@ public:
     // return station id's marked as having metar data.
     FGAirport search( double lon_deg, double lat_deg, bool with_metar );
 
+    // search and return a pointer;
+    FGAirport* search( const string& id, FGAirport *result);
 
     /**
      * Return the number of airports in the list.
index 38ddeb215748e6bc3aac902a99f126cd63c944ee..f328d49b8c00305cbce641cfbf70d1a0e02e0cdc 100644 (file)
@@ -668,7 +668,7 @@ int NewWaypoint( string Tgt_Alt )
 
       sprintf( NewTgtAirportId, "%s", TgtAptId.c_str() );
 
-      SGWayPoint wp( a._longitude, a._latitude, alt,
+      SGWayPoint wp( a.getLongitude(), a.getLatitude(), alt,
                      SGWayPoint::WGS84, TgtAptId );
       rm->add_waypoint( wp );
 
index d426d0e6e394159b22fb9376969417812bb07fba..21fb708e671a5315898b672ca1d380f6994150a1 100644 (file)
@@ -399,11 +399,11 @@ FGMetarEnvironmentCtrl::init ()
             ->search( longitude->getDoubleValue(),
                       latitude->getDoubleValue(),
                       true );
-        FGMetarResult result = fetch_data( a._id );
+        FGMetarResult result = fetch_data( a.getId() );
         if ( result.m != NULL ) {
-            SG_LOG( SG_GENERAL, SG_INFO, "closest station w/ metar = " << a._id);
+            SG_LOG( SG_GENERAL, SG_INFO, "closest station w/ metar = " << a.getId());
             last_apt = a;
-            _icao = a._id;
+            _icao = a.getId();
             search_elapsed = 0.0;
             fetch_elapsed = 0.0;
             update_metar_properties( result.m );
@@ -413,8 +413,8 @@ FGMetarEnvironmentCtrl::init ()
         } else {
             // mark as no metar so it doesn't show up in subsequent
             // searches.
-            SG_LOG( SG_GENERAL, SG_INFO, "no metar at metar = " << a._id );
-            globals->get_airports()->no_metar( a._id );
+            SG_LOG( SG_GENERAL, SG_INFO, "no metar at metar = " << a.getId() );
+            globals->get_airports()->no_metar( a.getId() );
         }
     }
 }
@@ -456,13 +456,13 @@ FGMetarEnvironmentCtrl::update(double delta_time_sec)
             ->search( longitude->getDoubleValue(),
                       latitude->getDoubleValue(),
                       true );
-        if ( last_apt._id != a._id
+        if ( last_apt.getId() != a.getId()
              || fetch_elapsed > same_station_interval_sec )
         {
-            SG_LOG( SG_GENERAL, SG_INFO, "closest station w/ metar = " << a._id);
-            request_queue.push( a._id );
+            SG_LOG( SG_GENERAL, SG_INFO, "closest station w/ metar = " << a.getId());
+            request_queue.push( a.getId() );
             last_apt = a;
-            _icao = a._id;
+            _icao = a.getId();
             search_elapsed = 0.0;
             fetch_elapsed = 0.0;
         } else {
@@ -534,7 +534,7 @@ FGMetarEnvironmentCtrl::fetch_data( const string &icao )
 
     // fetch station elevation if exists
     FGAirport a = globals->get_airports()->search( icao );
-    station_elevation_ft = a._elevation;
+    station_elevation_ft = a.getElevation();
 
     // fetch current metar data
     try {
index 88d77494d6bb655a84833b31a2aca4cf45bf21ff..16f9785d037664420a3c0199f7459286111c6b5c 100644 (file)
@@ -18,8 +18,8 @@ AirportList::AirportList (int x, int y, int width, int height)
     for (int i = 0; i < _nAirports; i++) {
         const FGAirport *airport = _airports->getAirport(i);
         snprintf(buf, 1023, "%s  %s",
-                 airport->_id.c_str(),
-                 airport->_name.c_str());
+                 airport->getId().c_str(),
+                 airport->getName().c_str());
 
         unsigned int buf_len = (strlen(buf) > 1023) ? 1023 : strlen(buf);
         
@@ -43,7 +43,7 @@ AirportList::~AirportList ()
 char *
 AirportList::getListStringValue ()
 {
-    return (char *)_airports->getAirport(getListIntegerValue())->_id.c_str();
+    return (char *)_airports->getAirport(getListIntegerValue())->getId().c_str();
 }
 
 // end of AirportList.cxx
index e6979c0b7830a731bb779e818408da0b02959986..9e587fdf7491db084deec8f881dcc4a9d98025d2 100644 (file)
@@ -22,4 +22,4 @@ layout_test_SOURCES = layout-test.cxx
 
 layout_test_LDADD = libGUI.a \
                     -lsgprops -lsgdebug -lsgstructure -lsgmisc -lsgxml \
-                    -lplibpw -lplibpu -lplibfnt -lplibul $(opengl_LIBS)
\ No newline at end of file
+                    -lplibpw -lplibpu -lplibfnt -lplibul $(opengl_LIBS)
index e1fe6077bdfcda9559f6888f2c098d105167ffc5..83dbac7e4ee9472465caf1daf563a0eb5b7573f1 100644 (file)
@@ -325,12 +325,12 @@ GPS::update (double delta_time_sec)
             FGAirport a;
             //cout << "Airport found" << endl;
             a = globals->get_airports()->search(longitude_deg, latitude_deg, false);
-            _wp1_ID_node->setStringValue(a._id.c_str());
-            wp1_longitude_deg = a._longitude;
-            wp1_latitude_deg = a._latitude;
-            _wp1_name_node->setStringValue(a._name.c_str());
+            _wp1_ID_node->setStringValue(a.getId().c_str());
+            wp1_longitude_deg = a.getLongitude();
+            wp1_latitude_deg = a.getLatitude();
+            _wp1_name_node->setStringValue(a.getName().c_str());
             _get_nearest_airport_node->setBoolValue(false);
-            _last_wp1_ID = wp1_ID = a._id.c_str();
+            _last_wp1_ID = wp1_ID = a.getId().c_str();
         }
         
         // If the waypoint 0 ID has changed, try to find the new ID
@@ -341,11 +341,11 @@ GPS::update (double delta_time_sec)
             if (waypont_type == "airport") {
                 FGAirport a;
                 a = globals->get_airports()->search( wp0_ID );
-                if ( a._id == wp0_ID ) {
+                if ( a.getId() == wp0_ID ) {
                     //cout << "Airport found" << endl;
-                    wp0_longitude_deg = a._longitude;
-                    wp0_latitude_deg = a._latitude;
-                    _wp0_name_node->setStringValue(a._name.c_str());
+                    wp0_longitude_deg = a.getLongitude();
+                    wp0_latitude_deg = a.getLatitude();
+                    _wp0_name_node->setStringValue(a.getName().c_str());
                 }
             }
             else if (waypont_type == "nav") {
@@ -380,11 +380,11 @@ GPS::update (double delta_time_sec)
             if (waypont_type == "airport") {
                 FGAirport a;
                 a = globals->get_airports()->search( wp1_ID );
-                if ( a._id == wp1_ID ) {
+                if ( a.getId() == wp1_ID ) {
                     //cout << "Airport found" << endl;
-                    wp1_longitude_deg = a._longitude;
-                    wp1_latitude_deg = a._latitude;
-                    _wp1_name_node->setStringValue(a._name.c_str());
+                    wp1_longitude_deg = a.getLongitude();
+                    wp1_latitude_deg = a.getLatitude();
+                    _wp1_name_node->setStringValue(a.getName().c_str());
                 }
             }
             else if (waypont_type == "nav") {
index 924b1b8cf94c45e22b7b3251e59e16041c8ecc55..176220ba67455179f4919cb38dc012b65206a9d4 100644 (file)
@@ -636,7 +636,7 @@ bool fgFindAirportID( const string& id, FGAirport *a ) {
 
         result = globals->get_airports()->search( id );
 
-        if ( result._id.empty() ) {
+        if ( result.getId().empty() ) {
             SG_LOG( SG_GENERAL, SG_ALERT,
                     "Failed to find " << id << " in basic.dat.gz" );
             return false;
@@ -649,8 +649,8 @@ bool fgFindAirportID( const string& id, FGAirport *a ) {
 
     SG_LOG( SG_GENERAL, SG_INFO,
             "Position for " << id << " is ("
-            << a->_longitude << ", "
-            << a->_latitude << ")" );
+            << a->getLongitude() << ", "
+            << a->getLatitude() << ")" );
 
     return true;
 }
@@ -665,7 +665,7 @@ static double fgGetAirportElev( const string& id ) {
             "Finding elevation for airport: " << id );
 
     if ( fgFindAirportID( id, &a ) ) {
-        return a._elevation;
+        return a.getElevation();
     } else {
         return -9999.0;
     }
@@ -718,9 +718,9 @@ static bool fgSetTowerPosFromAirportID( const string& id, double hdg ) {
     float fudge_lat = .003f - fudge_lon;
 
     if ( fgFindAirportID( id, &a ) ) {
-        fgSetDouble("/sim/tower/longitude-deg",  a._longitude + fudge_lon);
-        fgSetDouble("/sim/tower/latitude-deg",  a._latitude + fudge_lat);
-        fgSetDouble("/sim/tower/altitude-ft", a._elevation + towerheight);
+        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;
@@ -1715,11 +1715,11 @@ bool fgInitSubsystems() {
      globals->add_subsystem("Traffic Manager", new FGTrafficManager);
             FGTrafficManager *dispatcher = 
             (FGTrafficManager*) globals->get_subsystem("Traffic Manager");
-            SGPath path =globals->get_fg_root();
-            path.append("Traffic/fgtraffic.xml");
+            SGPath path = globals->get_fg_root();
+            path.append("/Traffic/fgtraffic.xml");
      readXML(path.str(),
-            *dispatcher);
-     globals->get_subsystem("Traffic Manager")->init();
+       *dispatcher);
+            //globals->get_subsystem("Traffic Manager")->init();
 
     globals->add_subsystem("instrumentation", new FGInstrumentMgr);
     globals->add_subsystem("systems", new FGSystemMgr);
index 1595e7a69a6b25535b870f28c480fc498f80b9a5..22cac4f03801f5da206396614cd261cbc6d5d400 100644 (file)
@@ -96,8 +96,8 @@ bool fgNavDBInit( FGAirportList *airports,
             // cout << r->get_type() << " " << r->get_apt_id() << " zero elev"
             //      << endl;
             FGAirport a = airports->search( r->get_apt_id() );
-            if ( a._id == r->get_apt_id() ) {
-                r->set_elev_ft( a._elevation );
+            if ( a.getId() == r->get_apt_id() ) {
+                r->set_elev_ft( a.getElevation() );
                 // cout << "  setting to " << a.elevation << endl;
             }
         }
index 245d3db0c87efbea91631239811e3cd0cbad9ad8..e02f54f879314b46116beae36ff8c7f3b13f3982 100644 (file)
@@ -81,6 +81,8 @@ FGScheduledFlight::FGScheduledFlight(const FGScheduledFlight &other)
   callsign        = other.callsign;
   fltRules        = other.fltRules;
   departurePort   = other.departurePort;
+  depId           = other.depId;
+  arrId           = other.arrId;
   departureTime   = other.departureTime;
   cruiseAltitude  = other.cruiseAltitude;
   arrivalPort     = other.arrivalPort;
@@ -100,8 +102,11 @@ FGScheduledFlight::FGScheduledFlight(string cs,
 {
   callsign          = cs;
   fltRules          = fr;
-  departurePort._id  = depPrt;
-  arrivalPort._id    = arrPrt;
+  //departurePort.setId(depPrt);
+  //arrivalPort.setId(arrPrt);
+  depId = depPrt;
+  arrId = arrPrt;
+  //cerr << "Constructor: departure " << depId << ". arrival " << arrId << endl;
   //departureTime     = processTimeString(deptime);
   //arrivalTime       = processTimeString(arrtime);
   cruiseAltitude    = cruiseAlt;
@@ -225,7 +230,10 @@ FGAirport *FGScheduledFlight::getDepartureAirport()
     {
       initializeAirports();
     }
-  return &departurePort;
+  if (initialized)
+    return departurePort;
+  else
+    return 0;
 }
 FGAirport * FGScheduledFlight::getArrivalAirport  ()
 {
@@ -233,7 +241,10 @@ FGAirport * FGScheduledFlight::getArrivalAirport  ()
     {
       initializeAirports();
     }
-  return &arrivalPort;
+   if (initialized)
+     return arrivalPort;
+   else
+     return 0;
 }
 
 // Upon the first time of requesting airport information
@@ -243,15 +254,24 @@ FGAirport * FGScheduledFlight::getArrivalAirport  ()
 // but we should improve that. The best idea is probably to cancel
 // this flight entirely by removing it from the schedule, if one
 // of the airports cannot be found. 
-void FGScheduledFlight::initializeAirports()
+bool FGScheduledFlight::initializeAirports()
 {
-  if(!(fgFindAirportID(arrivalPort._id, &arrivalPort  )))
+  //cerr << "Initializing using : " << depId << " " << arrId << endl;
+  departurePort = globals->get_airports()->search( depId, departurePort );
+  if(departurePort->getId().empty())
     {
-      //cerr << ": Could not find " << arrivalPort.id << endl; 
+      cerr << "Could not find " << depId << endl; 
+      return false;
     }
-  if(!(fgFindAirportID(departurePort._id, &departurePort)))
+  arrivalPort = globals->get_airports()->search(arrId, arrivalPort);
+  if(arrivalPort->getId().empty())
     {
-      //cerr << ": Could not find " << departurePort.id << endl;
+      cerr << "Could not find " << arrId << endl;
+      return false;
     }
+
+  //cerr << "Found : " << departurePort->getId() << endl;
+  //cerr << "Found : " << arrivalPort->getId() << endl;
   initialized = true;
+  return true;
 }
index 5f01f346ebd980b06ac6ea140ebee27afa0dbf2f..2396ae84b4f703e91bd8d9dba18702accc3021b3 100644 (file)
@@ -51,15 +51,17 @@ class FGScheduledFlight
 private:
   string callsign;
   string fltRules;
-  FGAirport departurePort;
-  FGAirport arrivalPort;
+  FGAirport *departurePort;
+  FGAirport *arrivalPort;
+  string depId;
+  string arrId;
   time_t departureTime;
   time_t arrivalTime;
   time_t repeatPeriod;
   int cruiseAltitude;
   bool initialized;
 
-  void initializeAirports();
  
 public:
   FGScheduledFlight();
@@ -77,6 +79,7 @@ public:
   ~FGScheduledFlight();
 
   void update();
+   bool initializeAirports();
   
   void adjustTime(time_t now);
 
@@ -94,7 +97,7 @@ public:
   };
 
   time_t processTimeString(string time);
-  
+  string getCallSign() {return callsign; };
 };
 
 typedef vector<FGScheduledFlight>           FGScheduledFlightVec;
index 0c622407e4ce74070bf6cc1275879cf4bb7c5477..b51a5db4e3f96032ee92fd072c24cbdebc789099 100644 (file)
@@ -65,11 +65,23 @@ FGAISchedule::FGAISchedule(string    mdl,
                           string    liv, 
                           string    reg, 
                           bool      hvy, 
+                          string act, 
+                          string arln, 
+                          string mclass, 
+                          string fltpe,
+                          double rad,
+                          double grnd,
                           FGScheduledFlightVec flt)
 {
   modelPath    = mdl; 
   livery       = liv; 
   registration = reg;
+  acType       = act;
+  airline      = arln;
+  m_class      = mclass;
+  flightType   = fltpe;
+  radius       = rad;
+  groundOffset = grnd;
   heavy = hvy;
   for (FGScheduledFlightVecIterator i = flt.begin();
        i != flt.end();
@@ -89,15 +101,49 @@ FGAISchedule::FGAISchedule(const FGAISchedule &other)
   lat          = other.lat;
   lon          = other.lon;
   AIManagerRef = other.AIManagerRef;
+  acType       = other.acType;
+  airline      = other.airline;
+  m_class      = other.m_class;
   firstRun     = other.firstRun;
+  radius       = other.radius;
+  groundOffset = other.groundOffset;
+  flightType   = other.flightType;
+  distanceToUser = other.distanceToUser;
 }
 
+
 FGAISchedule::~FGAISchedule()
 {
   
 } 
 
-void FGAISchedule::update(time_t now)
+bool FGAISchedule::init()
+{
+  //tm targetTimeDate;
+  //SGTime* currTimeDate = globals->get_time_params();
+
+  //tm *temp = currTimeDate->getGmt();
+  //char buffer[512];
+  //sgTimeFormatTime(&targetTimeDate, buffer);
+  //cout << "Scheduled Time " << buffer << endl; 
+  //cout << "Time :" << time(NULL) << " SGTime : " << sgTimeGetGMT(temp) << endl;
+  for (FGScheduledFlightVecIterator i = flights.begin(); 
+       i != flights.end(); 
+       i++)
+    {
+      //i->adjustTime(now);
+      if (!(i->initializeAirports()))
+       return false;
+    } 
+  //sort(flights.begin(), flights.end());
+  // Since time isn't initialized yet when this function is called,
+  // Find the closest possible airport.
+  // This should give a reasonable initialization order. 
+  setClosestDistanceToUser();
+  return true;
+}
+
+bool FGAISchedule::update(time_t now)
 {
   FGAirport *dep;
   FGAirport *arr;
@@ -110,7 +156,7 @@ void FGAISchedule::update(time_t now)
   string airport;
   
   double courseToUser,   courseToDest;
-  double distanceToUser, distanceToDest;
+  double distanceToDest;
   double speed;
 
   Point3D temp;
@@ -123,7 +169,7 @@ void FGAISchedule::update(time_t now)
     userLongitude;
 
   if (fgGetBool("/sim/traffic-manager/enabled") == false)
-    return;
+    return true;
   
   aimgr = (FGAIManager *) globals-> get_subsystem("ai_model");  
   // Before the flight status of this traffic entity is updated 
@@ -142,11 +188,11 @@ void FGAISchedule::update(time_t now)
   if (firstRun)
     {
       for (FGScheduledFlightVecIterator i = flights.begin(); 
-          i != flights.end(); 
-          i++)
-       {
-         i->adjustTime(now);
-       }
+          i != flights.end(); 
+          i++)
+       {
+         i->adjustTime(now);
+       }
       firstRun = false;
     }
   
@@ -168,13 +214,13 @@ void FGAISchedule::update(time_t now)
       userLatitude  = fgGetDouble("/position/latitude-deg");
       userLongitude = fgGetDouble("/position/longitude-deg");
 
-
+      //cerr << "Estimated minimum distance to user: " << distanceToUser << endl;
       // This flight entry is entirely in the past, do we need to 
       // push it forward in time to the next scheduled departure. 
       if ((i->getDepartureTime() < now) && (i->getArrivalTime() < now))
        {
          i->update();
-         return;
+         return true;
        }
 
       // Departure time in the past and arrival time in the future.
@@ -189,19 +235,21 @@ void FGAISchedule::update(time_t now)
        {
          dep = i->getDepartureAirport();
          arr = i->getArrivalAirport  ();
+         if (!(dep && arr))
+           return false;
          
-         temp = sgPolarToCart3d(Point3D(dep->_longitude * 
+         temp = sgPolarToCart3d(Point3D(dep->getLongitude() * 
                                         SG_DEGREES_TO_RADIANS, 
-                                        dep->_latitude  * 
+                                        dep->getLatitude()  * 
                                         SG_DEGREES_TO_RADIANS, 
                                         1.0));
          a[0] = temp.x();
          a[1] = temp.y();
          a[2] = temp.z();
          
-         temp = sgPolarToCart3d(Point3D(arr->_longitude *
+         temp = sgPolarToCart3d(Point3D(arr->getLongitude() *
                                         SG_DEGREES_TO_RADIANS,
-                                        arr->_latitude  *
+                                        arr->getLatitude()  *
                                         SG_DEGREES_TO_RADIANS, 
                                         1.0));
          b[0] = temp.x();
@@ -219,9 +267,21 @@ void FGAISchedule::update(time_t now)
          // total time enroute and elapsed time enroute. 
  
          totalTimeEnroute     = i->getArrivalTime() - i->getDepartureTime();
-         elapsedTimeEnroute   = now - i->getDepartureTime();
-         remainingTimeEnroute = i->getArrivalTime()   - now;  
-         
+         if (now > i->getDepartureTime())
+           {
+             //err << "Lat = " << lat << ", lon = " << lon << endl;
+             //cerr << "Time diff: " << now-i->getDepartureTime() << endl;
+             elapsedTimeEnroute   = now - i->getDepartureTime();
+             remainingTimeEnroute = i->getArrivalTime()   - now;  
+           }
+         else
+           {
+             lat = dep->getLatitude();
+             lon = dep->getLongitude();
+             elapsedTimeEnroute = 0;
+             remainingTimeEnroute = totalTimeEnroute;
+           }
+                 
          angle *= ( (double) elapsedTimeEnroute/ (double) totalTimeEnroute);
          
          
@@ -236,32 +296,30 @@ void FGAISchedule::update(time_t now)
                  newPos[j] += matrix[j][k]*a[k];
                }
            }
-
+         
          temp = sgCartToPolar3d(Point3D(newPos[0], newPos[1],newPos[2]));
-
          if (now > i->getDepartureTime())
            {
              //cerr << "Lat = " << lat << ", lon = " << lon << endl;
              //cerr << "Time diff: " << now-i->getDepartureTime() << endl;
              lat = temp.lat() * SG_RADIANS_TO_DEGREES;
              lon = temp.lon() * SG_RADIANS_TO_DEGREES; 
-             //err << "Lat = " << lat << ", lon = " << lon << endl;
-             //cerr << "Time diff: " << now-i->getDepartureTime() << endl;
            }
          else
            {
-             lat = dep->_latitude;
-             lon = dep->_longitude;
+             lat = dep->getLatitude();
+             lon = dep->getLongitude();
            }
          
+         
          SGWayPoint current  (lon,
                               lat,
                               i->getCruiseAlt());
          SGWayPoint user (   userLongitude,
                              userLatitude,
                              i->getCruiseAlt());
-         SGWayPoint dest (   arr->_longitude,
-                             arr->_latitude,
+         SGWayPoint dest (   arr->getLongitude(),
+                             arr->getLatitude(),
                              i->getCruiseAlt());
          // We really only need distance to user
          // and course to destination 
@@ -278,9 +336,9 @@ void FGAISchedule::update(time_t now)
          //cerr << registration << " is currently enroute from " 
          //   << dep->_id << " to " << arr->_id << "distance : " 
           //   << distanceToUser*SG_METER_TO_NM << endl;
-         if ((distanceToUser*SG_METER_TO_NM) < 500.0)
+         if ((distanceToUser*SG_METER_TO_NM) < TRAFFICTOAIDIST)
            {
-             string flightPlanName = dep->_id + string("-") + arr->_id + 
+             string flightPlanName = dep->getId() + string("-") + arr->getId() + 
                string(".xml");
              int alt;
              //if  ((i->getDepartureTime() < now))
@@ -294,32 +352,43 @@ void FGAISchedule::update(time_t now)
 
               FGAIModelEntity entity;
 
-              entity.m_class = "jet_transport";
+              entity.m_class = m_class; //"jet_transport";
+             entity.company = airline; //i->getAirline();
+             entity.acType  = acType; //i->getAcType();
               entity.path = modelPath.c_str();
               entity.flightplan = flightPlanName.c_str();
               entity.latitude = lat;
               entity.longitude = lon;
               entity.altitude = i->getCruiseAlt() *100; // convert from FL to feet
-              entity.speed = 450;
-             entity.fp = new FGAIFlightPlan(&entity, courseToDest, i->getDepartureTime(), dep, arr);
-
+              entity.speed = speed;
+             entity.roll  = 0.0;
+             entity.fp = new FGAIFlightPlan(&entity, courseToDest, i->getDepartureTime(), dep, 
+                                            arr,true, radius, flightType, acType, airline);
+             
              // Fixme: A non-existent model path results in an
              // abort, due to an unhandled exeption, in fg main loop.
              AIManagerRef = aimgr->createAircraft( &entity, this);
-             //cerr << "Created: " << AIManagerRef << endl;
+             //cerr << "Class: " << m_class << ". acType: " << acType << ". Airline: " << airline << ". Speed = " << speed << ". From " << dep->getId() << " to " << arr->getId() << ". Time Fraction = " << (remainingTimeEnroute/(double) totalTimeEnroute) << endl;
+             //cerr << "Latitude : " << lat << ". Longitude : " << lon << endl;
+             //cerr << "Dep      : " << dep->getLatitude()<< ", "<< dep->getLongitude() << endl;
+             //cerr << "Arr      : " << arr->getLatitude()<< ", "<< arr->getLongitude() << endl;
+             //cerr << "Time remaining = " << (remainingTimeEnroute/3600.0) << endl;
+             //cerr << "Total time     = " << (totalTimeEnroute/3600.0) << endl;
+             //cerr << "Distance remaining = " << distanceToDest*SG_METER_TO_NM << endl;
+             
            }
-         return;
-       }
+         return true;
+    }
 
       // Both departure and arrival time are in the future, so this
       // the aircraft is parked at the departure airport.
       // Currently this status is mostly ignored, but in future
       // versions, code should go here that -if within user range-
       // positions these aircraft at parking locations at the airport.
-      if ((i->getDepartureTime() > now) && (i->getArrivalTime() > now))
+  if ((i->getDepartureTime() > now) && (i->getArrivalTime() > now))
        { 
          dep = i->getDepartureAirport();
-         return;
+         return true;
        } 
     }
 }
@@ -331,3 +400,71 @@ void FGAISchedule::next()
   sort(flights.begin(), flights.end());
 }
 
+double FGAISchedule::getSpeed()
+{
+  double courseToUser,   courseToDest;
+  double distanceToUser, distanceToDest;
+  double speed, remainingTimeEnroute;
+  FGAirport *dep, *arr;
+
+  FGScheduledFlightVecIterator i = flights.begin();
+  dep = i->getDepartureAirport();
+  arr = i->getArrivalAirport  ();
+  if (!(dep && arr))
+    return 0;
+  SGWayPoint dest (   dep->getLongitude(),
+                     dep->getLatitude(),
+                     i->getCruiseAlt()); 
+  SGWayPoint curr (    arr->getLongitude(),
+                     arr->getLatitude(),
+                     i->getCruiseAlt());
+  remainingTimeEnroute     = i->getArrivalTime() - i->getDepartureTime();
+  dest.CourseAndDistance(curr, &courseToDest, &distanceToDest);
+  speed =  (distanceToDest*SG_METER_TO_NM) / 
+    ((double) remainingTimeEnroute/3600.0);
+  return speed;
+}
+
+
+void FGAISchedule::setClosestDistanceToUser()
+{
+  
+  
+  double course;
+  double dist;
+
+  Point3D temp;
+  time_t 
+    totalTimeEnroute, 
+    elapsedTimeEnroute;
+  double userLatitude  = fgGetDouble("/position/latitude-deg");
+  double userLongitude = fgGetDouble("/position/longitude-deg");
+
+  FGAirport *dep;
+  
+  distanceToUser = HUGE;
+  FGScheduledFlightVecIterator i = flights.begin();
+  while (i != flights.end())
+    {
+      dep = i->getDepartureAirport();
+      //if (!(dep))
+      //return HUGE;
+      
+      SGWayPoint user (   userLongitude,
+                         userLatitude,
+                         i->getCruiseAlt());
+      SGWayPoint current (dep->getLongitude(),
+                         dep->getLatitude(),
+                         0);
+      user.CourseAndDistance(current, &course, &dist);
+      if (dist < distanceToUser)
+       {
+         distanceToUser = dist;
+         //cerr << "Found closest distance to user for " << registration << " to be " << distanceToUser << " at airport " << dep->getId() << endl;
+       }
+      i++;
+    }
+  //return distToUser;
+}
index a919a7a5b4bc5292967868272244308017dbcb0c..6ccb5db6017306226df8ca6aab6fc5abad247b3d 100644 (file)
@@ -29,6 +29,7 @@
 #ifndef _FGSCHEDULE_HXX_
 #define _FGSCHEDULE_HXX_
 
+#define TRAFFICTOAIDIST 150.0
 
 
 class FGAISchedule
@@ -37,34 +38,56 @@ class FGAISchedule
   string modelPath;
   string livery;
   string registration;
+  string airline;
+  string acType;
+  string m_class;
+  string flightType;
   bool heavy;
   FGScheduledFlightVec flights;
   float lat;
   float lon; 
+  double radius;
+  double groundOffset;
+  double distanceToUser;
   void* AIManagerRef;
   bool firstRun;
 
 
  public:
   FGAISchedule();                                           // constructor
-  FGAISchedule(string, string, string, bool, FGScheduledFlightVec);  // construct & init
+  FGAISchedule(string, string, string, bool, string, string, string, string, double, double, FGScheduledFlightVec);  // construct & init
   FGAISchedule(const FGAISchedule &other);             // copy constructor
 
   ~FGAISchedule(); //destructor
 
-  void update(time_t now);
+  bool update(time_t now);
+  bool init();
+
+  double getSpeed         ();
+  void setClosestDistanceToUser();
   void next();   // forces the schedule to move on to the next flight.
 
   time_t      getDepartureTime    () { return flights.begin()->getDepartureTime   (); };
   FGAirport * getDepartureAirport () { return flights.begin()->getDepartureAirport(); };
   FGAirport * getArrivalAirport   () { return flights.begin()->getArrivalAirport  (); };
   int         getCruiseAlt        () { return flights.begin()->getCruiseAlt       (); };
+  double      getRadius           () { return radius; };
+  double      getGroundOffset     () { return groundOffset;};
+  string      getFlightType       () { return flightType;};
+  string      getAirline          () { return airline; };
+  string      getAircraft         () { return acType; };
+  string      getCallSign         () { return flights.begin()->getCallSign (); };
+  string      getRegistration     () { return registration;};
+  bool getHeavy                   () { return heavy; };
+  bool operator< (const FGAISchedule &other) const { return (distanceToUser < other.distanceToUser); };
+  //void * getAiRef                 () { return AIManagerRef; };
+  //FGAISchedule* getAddress        () { return this;};
   // More member functions follow later
 
 };
 
-typedef vector<FGAISchedule>           ScheduleVector;
-typedef vector<FGAISchedule>::iterator ScheduleVectorIterator;
+typedef vector<FGAISchedule >           ScheduleVector;
+typedef vector<FGAISchedule >::iterator ScheduleVectorIterator;
 
 #endif
 
index 9e6dded35b48ab3e2954a262b96507f373207f6a..cf2fa59801d8e8b5e89c561cf856a2ce01bfb053 100644 (file)
@@ -53,6 +53,7 @@
 #include <simgear/structure/subsystem_mgr.hxx>
 #include <simgear/xml/easyxml.hxx>
 
+#include <AIModel/AIAircraft.hxx>
 #include <AIModel/AIFlightPlan.hxx>
 #include <AIModel/AIBase.hxx>
 #include <Airports/simple.hxx>
@@ -72,22 +73,45 @@ FGTrafficManager::FGTrafficManager()
 
 
 void FGTrafficManager::init()
-{
+{ 
+  //cerr << "Initializing Schedules" << endl;
+  time_t now = time(NULL) + fgGetLong("/sim/time/warp");
+  currAircraft = scheduledAircraft.begin();
+  while (currAircraft != scheduledAircraft.end())
+    {
+      if (!(currAircraft->init()))
+       {
+         currAircraft=scheduledAircraft.erase(currAircraft);
+         //cerr << "Erasing " << currAircraft->getRegistration() << endl;
+         currAircraft--;
+       }
+      else 
+       {
+         currAircraft++;
+       }
+    }
+  //cerr << "Sorting by distance " << endl;
+  sort(scheduledAircraft.begin(), scheduledAircraft.end());
   currAircraft = scheduledAircraft.begin();
+  currAircraftClosest = scheduledAircraft.begin();
+  //cerr << "Done initializing schedules" << endl;
 }
 
 void FGTrafficManager::update(double something)
 {
-
-  //static const SGPropertyNode *warp = globals->get_props()->getNode("/sim/time/warp");
-  
-  //time_t now = time(NULL) + globals->get_warp();
   time_t now = time(NULL) + fgGetLong("/sim/time/warp");
-  //  cerr << "TrafficManager update" << globals->get_warp() << endl;
-    if(currAircraft == scheduledAircraft.end())
+  if(currAircraft == scheduledAircraft.end())
+    {
+      //cerr << "resetting schedule " << endl;
       currAircraft = scheduledAircraft.begin();
-    currAircraft->update(now);
-    currAircraft++;
+    }
+  if (!(currAircraft->update(now)))
+    {
+      // after proper initialization, we shouldnt get here.
+      // But let's make sure
+      cerr << "Failed to update aircraft schedule in traffic manager" << endl;
+    }
+  currAircraft++;
 }
 
 void FGTrafficManager::release(void *id)
@@ -146,6 +170,18 @@ void  FGTrafficManager::endElement (const char * name) {
     livery = value;
   else if (element == string("registration"))
     registration = value;
+  else if (element == string("airline"))
+    airline = value;
+  else if (element == string("actype"))
+    acType = value;
+  else if (element == string("flighttype"))
+    flighttype = value;
+  else if (element == string("radius"))
+    radius = atoi(value.c_str());
+  else if (element == string("offset"))
+    offset = atoi(value.c_str());
+  else if (element == string("performance-class"))
+    m_class = value;
   else if (element == string("heavy"))
     {
       if(value == string("true"))
@@ -195,10 +231,16 @@ void  FGTrafficManager::endElement (const char * name) {
     {
       //cerr << "Pushing back aircraft " << registration << endl;
       scheduledAircraft.push_back(FGAISchedule(mdl, 
-                                               livery, 
-                                               registration, 
-                                               heavy, 
-                                               flights));
+                                              livery, 
+                                              registration, 
+                                              heavy,
+                                              acType, 
+                                              airline, 
+                                              m_class, 
+                                              flighttype,
+                                              radius,
+                                              offset,
+                                              flights));
       while(flights.begin() != flights.end())
        flights.pop_back();
     }
index ab39afcf732c82e262ddbdd5003fa45cc65246f5..4dd3383f76ff388c14bb734ee3e6c9e06d2fa79d 100644 (file)
@@ -42,13 +42,14 @@ class FGTrafficManager : public SGSubsystem, public XMLVisitor
 {
 private:
   ScheduleVector scheduledAircraft;
-  ScheduleVectorIterator currAircraft;
+  ScheduleVectorIterator currAircraft, currAircraftClosest;
   string value;
 
   string mdl, livery, registration, callsign, fltrules, 
     port, timeString, departurePort, departureTime, arrivalPort, arrivalTime,
-    repeat;
+    repeat, acType, airline, m_class, flighttype;
   int cruiseAlt;
+  double radius, offset;
   bool heavy;
 
   IdList releaseList;