]> git.mxchange.org Git - flightgear.git/blob - src/AIModel/AIAircraft.cxx
Make it optional whether a dialog can be dragged or not.
[flightgear.git] / src / AIModel / AIAircraft.cxx
1 // FGAIAircraft - FGAIBase-derived class creates an AI airplane
2 //
3 // Written by David Culp, started October 2003.
4 //
5 // Copyright (C) 2003  David P. Culp - davidculp2@comcast.net
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
21 #ifdef HAVE_CONFIG_H
22 #  include <config.h>
23 #endif
24
25 #include <simgear/math/point3d.hxx>
26 #include <simgear/route/waypoint.hxx>
27 #include <Main/fg_props.hxx>
28 #include <Main/globals.hxx>
29 #include <Main/viewer.hxx>
30 #include <Scenery/scenery.hxx>
31 #include <Scenery/tilemgr.hxx>
32
33 #include <string>
34 #include <math.h>
35 #include <time.h>
36 #ifdef _MSC_VER
37 #  include <float.h>
38 #  define finite _finite
39 #endif
40
41 SG_USING_STD(string);
42
43 #include "AIAircraft.hxx"
44    static string tempReg;
45 //
46 // accel, decel, climb_rate, descent_rate, takeoff_speed, climb_speed,
47 // cruise_speed, descent_speed, land_speed
48 //
49 const FGAIAircraft::PERF_STRUCT FGAIAircraft::settings[] = {
50     // light aircraft
51     {2.0, 2.0,  450.0, 1000.0,  70.0,  80.0, 100.0,  80.0,  60.0},
52     // ww2_fighter
53     {4.0, 2.0, 3000.0, 1500.0, 110.0, 180.0, 250.0, 200.0, 100.0},
54     // jet_transport
55     {5.0, 2.0, 3000.0, 1500.0, 140.0, 300.0, 430.0, 300.0, 130.0},
56     // jet_fighter
57     {7.0, 3.0, 4000.0, 2000.0, 150.0, 350.0, 500.0, 350.0, 150.0},
58     // tanker
59     {5.0, 2.0, 3000.0, 1500.0, 140.0, 300.0, 430.0, 300.0, 130.0}
60 };
61
62
63 FGAIAircraft::FGAIAircraft(FGAIManager* mgr, FGAISchedule *ref) {
64   trafficRef = ref;
65   if (trafficRef)
66     groundOffset = trafficRef->getGroundOffset();
67   else
68     groundOffset = 0;
69    manager = mgr;   
70    _type_str = "aircraft";
71    _otype = otAircraft;
72    fp = 0;
73    dt_count = 0;
74    dt_elev_count = 0;
75    use_perf_vs = true;
76    isTanker = false;
77
78    // set heading and altitude locks
79    hdg_lock = false;
80    alt_lock = false;
81    roll = 0;
82    headingChangeRate = 0.0;
83 }
84
85
86 FGAIAircraft::~FGAIAircraft() {
87 }
88
89
90 bool FGAIAircraft::init() {
91    refuel_node = fgGetNode("systems/refuel/contact", true);
92    return FGAIBase::init();
93 }
94
95 void FGAIAircraft::bind() {
96     FGAIBase::bind();
97
98     props->tie("controls/gear/gear-down",
99                SGRawValueMethods<FGAIAircraft,bool>(*this,
100                                               &FGAIAircraft::_getGearDown));
101 #if 0
102     props->getNode("controls/lighting/landing-lights", true)
103            ->alias("controls/gear/gear-down");
104 #endif
105 }
106
107 void FGAIAircraft::unbind() {
108     FGAIBase::unbind();
109
110     props->untie("controls/gear/gear-down");
111 #if 0
112     props->getNode("controls/lighting/landing-lights")->unalias();
113 #endif
114 }
115
116
117 void FGAIAircraft::update(double dt) {
118
119    FGAIBase::update(dt);
120    Run(dt);
121    Transform();
122 }
123
124 void FGAIAircraft::SetPerformance(const PERF_STRUCT *ps) {
125    
126    performance = ps;
127
128
129
130 void FGAIAircraft::Run(double dt) {
131
132    FGAIAircraft::dt = dt;
133
134    if (fp) 
135      {
136        time_t now = time(NULL) + fgGetLong("/sim/time/warp");
137        ProcessFlightPlan(dt, now);
138        if (now < fp->getStartTime())
139          {
140            // Do execute Ground elev for inactive aircraft, so they
141            // Are repositioned to the correct ground altitude when the user flies within visibility range.
142            if (no_roll)
143              {
144                Transform();         // make sure aip is initialized.
145                getGroundElev(dt); // make sure it's exectuted first time around, so force a large dt value
146                //getGroundElev(dt); // Need to do this twice.
147                //cerr << trafficRef->getRegistration() << " Setting altitude to " << tgt_altitude << endl;
148                setAltitude(tgt_altitude);
149              }
150            return;
151          }
152      }
153   
154    double turn_radius_ft;
155    double turn_circum_ft;
156    double speed_north_deg_sec;
157    double speed_east_deg_sec;
158    double dist_covered_ft;
159    double alpha;
160
161    // adjust speed
162    double speed_diff; //= tgt_speed - speed;
163    if (!no_roll)
164      {
165        speed_diff = tgt_speed - speed;
166      }
167    else
168      {
169        speed_diff = groundTargetSpeed - speed;
170      }
171    if (fabs(speed_diff) > 0.2) {
172      if (speed_diff > 0.0) speed += performance->accel * dt;
173      if (speed_diff < 0.0) {
174        if (no_roll) { // was (!no_roll) but seems more logical this way (ground brakes).
175            speed -= performance->decel * dt * 3;
176         } else {
177            speed -= performance->decel * dt;
178         }
179      }
180    } 
181    
182    // convert speed to degrees per second
183    speed_north_deg_sec = cos( hdg / SG_RADIANS_TO_DEGREES )
184                           * speed * 1.686 / ft_per_deg_lat;
185    speed_east_deg_sec  = sin( hdg / SG_RADIANS_TO_DEGREES )
186                           * speed * 1.686 / ft_per_deg_lon;
187
188    // set new position
189    pos.setlat( pos.lat() + speed_north_deg_sec * dt);
190    pos.setlon( pos.lon() + speed_east_deg_sec * dt); 
191    //if (!(finite(pos.lat()) && finite(pos.lon())))
192    //  {
193    //    cerr << "Position is not finite" << endl;
194    //    cerr << "speed = " << speed << endl;
195    //    cerr << "dt" << dt << endl;
196    //    cerr << "heading " << hdg << endl;
197    //    cerr << "speed east " << speed_east_deg_sec << endl;
198    //    cerr << "speed nrth " << speed_north_deg_sec << endl;
199    //    cerr << "deg_lat    " << ft_per_deg_lat << endl;
200    //    cerr << "deg_lon    " << ft_per_deg_lon << endl;
201    //  }
202
203    // adjust heading based on current bank angle
204    if (roll == 0.0) 
205      roll = 0.01;
206    if (roll != 0.0) {
207      // double turnConstant;
208      //if (no_roll)
209      //  turnConstant = 0.0088362;
210      //else 
211      //  turnConstant = 0.088362;
212      // If on ground, calculate heading change directly
213      if (no_roll) {
214        double headingDiff = fabs(hdg-tgt_heading);
215       
216        if (headingDiff > 180)
217          headingDiff = fabs(headingDiff - 360);
218        groundTargetSpeed = tgt_speed - (tgt_speed * (headingDiff/45));
219        if (sign(groundTargetSpeed) != sign(tgt_speed))
220          groundTargetSpeed = 0.21 * sign(tgt_speed); // to prevent speed getting stuck in 'negative' mode
221        if (headingDiff > 30.0)
222          {
223            
224            headingChangeRate += dt * sign(roll); // invert if pushed backward
225            // Print some debug statements to find out why aircraft may get stuck
226            // forever turning
227            //if (trafficRef->getDepartureAirport()->getId() == string("EHAM"))
228            //  {
229            //cerr << "Turning : " << trafficRef->getRegistration()
230            //cerr <<  " Speed = " << speed << " Heading " << hdg 
231            //<< " Target Heading " << tgt_heading 
232            //   << " Lead Distance " <<  fp->getLeadDistance()
233            //   << " Distance to go " 
234            //   << fp->getDistanceToGo(pos.lat(), pos.lon(), fp->getCurrentWaypoint())
235            //   << "waypoint name " << fp->getCurrentWaypoint()->name
236            //   << endl;
237            //}
238            if (headingChangeRate > 30) 
239              { 
240                headingChangeRate = 30;
241              }
242            else if (headingChangeRate < -30)
243              {
244                headingChangeRate = -30;
245              }
246          }
247        else
248          {
249            if (fabs(headingChangeRate) > headingDiff)
250              headingChangeRate = headingDiff*sign(roll);
251            else
252              headingChangeRate += dt * sign(roll);
253          }
254        hdg += headingChangeRate * dt;
255        //cerr << "On ground. Heading: " << hdg << ". Target Heading: " << tgt_heading << ". Target speed: " << groundTargetSpeed << ". heading change rate" << headingChangeRate << endl;
256      }
257      else {
258        if (fabs(speed) > 1.0) {
259          turn_radius_ft = 0.088362 * speed * speed
260            / tan( fabs(roll) / SG_RADIANS_TO_DEGREES );
261        }
262        else
263          {
264            turn_radius_ft = 1.0; // Check if turn_radius_ft == 0; this might lead to a division by 0.
265          }
266        turn_circum_ft = SGD_2PI * turn_radius_ft;
267        dist_covered_ft = speed * 1.686 * dt; 
268        alpha = dist_covered_ft / turn_circum_ft * 360.0;
269        hdg += alpha * sign(roll);
270      }
271      while ( hdg > 360.0 ) {
272        hdg -= 360.0;
273        spinCounter++;
274      }
275      while ( hdg < 0.0) 
276        {
277          hdg += 360.0;
278          spinCounter--;
279        }
280    }
281      
282    
283    // adjust target bank angle if heading lock engaged
284    if (hdg_lock) {
285      double bank_sense = 0.0;
286      double diff = fabs(hdg - tgt_heading);
287      if (diff > 180) diff = fabs(diff - 360);
288      double sum = hdg + diff;
289      if (sum > 360.0) sum -= 360.0;
290      if (fabs(sum - tgt_heading) < 1.0) {
291        bank_sense = 1.0;   // right turn
292      } else {
293        bank_sense = -1.0;  // left turn
294      } 
295      if (diff < 30) {
296          tgt_roll = diff * bank_sense; 
297      } else {
298          tgt_roll = 30.0 * bank_sense;
299      }
300      if ((fabs((double) spinCounter) > 1) && (diff > 30))
301        {
302          tgt_speed *= 0.999; // Ugly hack: If aircraft get stuck, they will continually spin around.
303          // The only way to resolve this is to make them slow down. 
304          //if (tempReg.empty())
305          //  tempReg = trafficRef->getRegistration();
306          //if (trafficRef->getRegistration() == tempReg)
307          //  {
308          //    cerr << trafficRef->getRegistration() 
309          //       << " appears to be spinning: " << spinCounter << endl
310          //       << " speed          " << speed << endl
311          //       << " heading        " << hdg << endl
312          //       << " lead distance  " << fp->getLeadDistance() << endl
313          //       << " waypoint       " << fp->getCurrentWaypoint()->name
314          //       << " target heading " << tgt_heading << endl
315          //       << " lead in angle  " << fp->getLeadInAngle()<< endl
316          //       << " roll           " << roll << endl
317          //       << " target_roll    " << tgt_roll << endl;
318              
319          //  }
320        }
321    }
322
323    // adjust bank angle, use 9 degrees per second
324    double bank_diff = tgt_roll - roll;
325    if (fabs(bank_diff) > 0.2) {
326      if (bank_diff > 0.0) roll += 9.0 * dt;
327      if (bank_diff < 0.0) roll -= 9.0 * dt;
328      //while (roll > 180) roll -= 360;
329      //while (roll < 180) roll += 360;
330    }
331
332    // adjust altitude (meters) based on current vertical speed (fpm)
333    altitude += vs / 60.0 * dt;
334    pos.setelev(altitude * SG_FEET_TO_METER);  
335    double altitude_ft = altitude;
336
337    // adjust target Altitude, based on ground elevation when on ground
338    if (no_roll)
339      {
340        getGroundElev(dt);
341      }
342    // find target vertical speed if altitude lock engaged
343    if (alt_lock && use_perf_vs) {
344      if (altitude_ft < tgt_altitude) {
345        tgt_vs = tgt_altitude - altitude_ft;
346        if (tgt_vs > performance->climb_rate)
347          tgt_vs = performance->climb_rate;
348      } else {
349        tgt_vs = tgt_altitude - altitude_ft;
350        if (tgt_vs  < (-performance->descent_rate))
351          tgt_vs = -performance->descent_rate;
352      }
353    }
354
355    if (alt_lock && !use_perf_vs) {
356      double max_vs = 4*(tgt_altitude - altitude);
357      double min_vs = 100;
358      if (tgt_altitude < altitude) min_vs = -100.0;
359      if ((fabs(tgt_altitude - altitude) < 1500.0) && 
360          (fabs(max_vs) < fabs(tgt_vs))) tgt_vs = max_vs;
361      if (fabs(tgt_vs) < fabs(min_vs)) tgt_vs = min_vs;
362    }   
363
364    // adjust vertical speed
365    double vs_diff = tgt_vs - vs;
366    if (fabs(vs_diff) > 10.0) {
367      if (vs_diff > 0.0) {
368        vs += 900.0 * dt;
369        if (vs > tgt_vs) vs = tgt_vs;
370      } else {
371        vs -= 400.0 * dt;
372        if (vs < tgt_vs) vs = tgt_vs;
373      }
374    }   
375    
376    // match pitch angle to vertical speed
377    if (vs > 0){
378      pitch = vs * 0.005;
379    } else {
380      pitch = vs * 0.002;
381    }
382
383    //###########################//
384    // do calculations for radar //
385    //###########################//
386    double range_ft2 = UpdateRadar(manager);
387
388    //************************************//
389    // Tanker code                        //
390    //************************************//
391
392    if ( isTanker) {
393      if ( (range_ft2 < 250.0 * 250.0) &&
394           (y_shift > 0.0)    &&
395           (elevation > 0.0) ) {
396        refuel_node->setBoolValue(true);
397      } else {
398        refuel_node->setBoolValue(false);
399      } 
400    }
401 }
402
403
404 void FGAIAircraft::AccelTo(double speed) {
405    tgt_speed = speed;
406 }
407
408
409 void FGAIAircraft::PitchTo(double angle) {
410    tgt_pitch = angle;
411    alt_lock = false;
412 }
413
414
415 void FGAIAircraft::RollTo(double angle) {
416    tgt_roll = angle;
417    hdg_lock = false; 
418 }
419
420
421 void FGAIAircraft::YawTo(double angle) {
422    tgt_yaw = angle;
423 }
424
425
426 void FGAIAircraft::ClimbTo(double altitude) {
427    tgt_altitude = altitude;
428    alt_lock = true;
429 }
430
431
432 void FGAIAircraft::TurnTo(double heading) {
433    tgt_heading = heading;
434    hdg_lock = true;
435 }
436
437
438 double FGAIAircraft::sign(double x) {
439   if ( x < 0.0 ) { return -1.0; }
440   else { return 1.0; }
441 }
442
443 void FGAIAircraft::SetFlightPlan(FGAIFlightPlan *f) {
444   fp = f;
445 }
446
447 void FGAIAircraft::ProcessFlightPlan( double dt, time_t now ) 
448 {
449   bool eraseWaypoints;
450   if (trafficRef)
451     {
452 //       FGAirport *arr;
453 //       FGAirport *dep;
454       eraseWaypoints = true;
455 //       cerr << trafficRef->getRegistration();
456 //       cerr << "Departure airport " << endl;
457 //       dep = trafficRef->getDepartureAirport();
458 //       if (dep)
459 //      cerr << dep->getId() << endl;
460 //       cerr << "Arrival   airport " << endl;
461 //       arr = trafficRef->getArrivalAirport();
462 //       if (arr)
463 //      cerr << arr->getId() <<endl << endl;;
464      }
465   else
466     eraseWaypoints = false;
467
468   //cerr << "Processing Flightplan" << endl;
469   FGAIFlightPlan::waypoint* prev = 0; // the one behind you
470   FGAIFlightPlan::waypoint* curr = 0; // the one ahead
471   FGAIFlightPlan::waypoint* next = 0; // the next plus 1
472   prev = fp->getPreviousWaypoint();
473   curr = fp->getCurrentWaypoint();
474   next = fp->getNextWaypoint();
475   dt_count += dt;
476   
477   if (!prev) {  //beginning of flightplan, do this initialization once
478     //setBank(0.0);
479     spinCounter = 0;
480     tempReg = "";
481     //prev_dist_to_go = HUGE;
482     //cerr << "Before increment " << curr-> name << endl;
483     fp->IncrementWaypoint(eraseWaypoints); 
484     //prev = fp->getPreviousWaypoint(); //first waypoint
485     //curr = fp->getCurrentWaypoint();  //second waypoint
486     //next = fp->getNextWaypoint();     //third waypoint (might not exist!) 
487     //cerr << "After increment " << prev-> name << endl;
488     if (!(fp->getNextWaypoint()) && trafficRef)
489       {
490         loadNextLeg();
491       }
492     //cerr << "After load " << prev-> name << endl;
493     prev = fp->getPreviousWaypoint(); //first waypoint
494     curr = fp->getCurrentWaypoint();  //second waypoint
495     next = fp->getNextWaypoint();     //third waypoint (might not exist!) 
496     //cerr << "After load " << prev-> name << endl;
497     setLatitude(prev->latitude);
498     setLongitude(prev->longitude);
499     setSpeed(prev->speed);
500     setAltitude(prev->altitude);
501     if (prev->speed > 0.0)
502       setHeading(fp->getBearing(prev->latitude, prev->longitude, curr));
503     else
504       {
505         setHeading(fp->getBearing(curr->latitude, curr->longitude, prev));
506       }
507     // If next doesn't exist, as in incrementally created flightplans for 
508     // AI/Trafficmanager created plans, 
509     // Make sure lead distance is initialized otherwise
510     if (next) 
511       fp->setLeadDistance(speed, hdg, curr, next);
512     
513     if (curr->crossat > -1000.0) { //use a calculated descent/climb rate
514       use_perf_vs = false;
515       tgt_vs = (curr->crossat - prev->altitude)/
516         (fp->getDistanceToGo(pos.lat(), pos.lon(), curr)/
517          6076.0/prev->speed*60.0);
518         tgt_altitude = curr->crossat;
519     } else {
520       use_perf_vs = true;
521       tgt_altitude = prev->altitude;
522     }
523     alt_lock = hdg_lock = true;
524     no_roll = prev->on_ground;
525     if (no_roll)
526       {
527         Transform();         // make sure aip is initialized.
528         getGroundElev(60.1); // make sure it's exectuted first time around, so force a large dt value
529         //getGroundElev(60.1); // Need to do this twice.
530         //cerr << trafficRef->getRegistration() << " Setting altitude to " << tgt_altitude << endl;
531         setAltitude(tgt_altitude);
532       }
533     prevSpeed = 0;
534     //cout << "First waypoint:  " << prev->name << endl;
535     //cout << "  Target speed:    " << tgt_speed << endl;
536     //cout << "  Target altitude: " << tgt_altitude << endl;
537     //cout << "  Target heading:  " << tgt_heading << endl << endl;       
538     //cerr << "Done Flightplan init" << endl;
539     return;  
540   } // end of initialization
541   
542   // let's only process the flight plan every 100 ms.
543   if ((dt_count < 0.1) || (now < fp->getStartTime()))
544     {
545       //cerr  << "done fp dt" << endl;
546       return;
547     } else {
548       dt_count = 0;
549     }
550   // check to see if we've reached the lead point for our next turn
551   double dist_to_go = fp->getDistanceToGo(pos.lat(), pos.lon(), curr);
552   
553   //cerr << "2" << endl;
554   double lead_dist = fp->getLeadDistance();
555   //cerr << " Distance : " << dist_to_go << ": Lead distance " << lead_dist << endl;
556   // experimental: Use fabs, because speed can be negative (I hope) during push_back.
557   if (lead_dist < fabs(2*speed)) 
558     {
559       lead_dist = fabs(2*speed);  //don't skip over the waypoint
560       //cerr << "Extending lead distance to " << lead_dist << endl;
561     } 
562 //   FGAirport * apt = trafficRef->getDepartureAirport();
563 //   if ((dist_to_go > prev_dist_to_go) && trafficRef && apt)
564 //     {
565 //       if (apt->getId() == string("EHAM"))
566 //      cerr << "Alert: " << trafficRef->getRegistration() << " is moving away from waypoint " << curr->name  << endl
567 //           << "Target heading : " << tgt_heading << "act heading " << hdg << " Tgt speed : " << tgt_speed << endl
568 //           << "Lead distance : " << lead_dist  << endl
569 //           << "Distance to go: " << dist_to_go << endl;
570       
571 //     }
572   prev_dist_to_go = dist_to_go;
573   //cerr << "2" << endl;
574   //if (no_roll)
575   //  lead_dist = 10.0;
576   //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;
577   
578   if ( dist_to_go < lead_dist ) {
579     //prev_dist_to_go = HUGE;
580     // For traffic manager generated aircraft: 
581     // check if the aircraft flies of of user range. And adjust the
582     // Current waypoint's elevation according to Terrain Elevation
583     if (curr->finished) {  //end of the flight plan
584       {
585         setDie(true);
586         //cerr << "Done die end of fp" << endl;
587       }
588       return;
589     }
590     
591     // we've reached the lead-point for the waypoint ahead 
592     //cerr << "4" << endl;
593     //cerr << "Situation after lead point" << endl;
594     //cerr << "Prviious: " << prev->name << endl;
595     //cerr << "Current : " << curr->name << endl;
596     //cerr << "Next    : " << next->name << endl;
597     if (next) 
598       {
599         tgt_heading = fp->getBearing(curr, next);  
600         spinCounter = 0;
601       }
602     fp->IncrementWaypoint(eraseWaypoints);
603     if (!(fp->getNextWaypoint()) && trafficRef)
604       {
605         loadNextLeg();
606       }
607     prev = fp->getPreviousWaypoint();
608     curr = fp->getCurrentWaypoint();
609     next = fp->getNextWaypoint();
610     // Now that we have incremented the waypoints, excute some traffic manager specific code
611     // based on the name of the waypoint we just passed.
612     if (trafficRef)
613       { 
614         double userLatitude  = fgGetDouble("/position/latitude-deg");
615         double userLongitude = fgGetDouble("/position/longitude-deg");
616         double course, distance;
617         SGWayPoint current  (pos.lon(),
618                              pos.lat(),
619                              0);
620         SGWayPoint user (   userLongitude,
621                             userLatitude,
622                             0);
623         user.CourseAndDistance(current, &course, &distance);
624         if ((distance * SG_METER_TO_NM) > TRAFFICTOAIDIST)
625           {
626             setDie(true);
627             //cerr << "done fp die out of range" << endl;
628             return;
629           }
630         
631         FGAirport * dep = trafficRef->getDepartureAirport();
632         FGAirport * arr = trafficRef->getArrivalAirport();
633         // At parking the beginning of the airport
634         if (!( dep && arr))
635           {
636             setDie(true);
637             return;
638           }
639         //if ((dep->getId() == string("EHAM") || (arr->getId() == string("EHAM"))))
640         //  {
641         //      cerr << trafficRef->getRegistration() 
642         //           << " Enroute from " << dep->getId() 
643         //           << " to "           << arr->getId()
644         //           << " just crossed " << prev->name
645         //           << " Assigned rwy     " << fp->getRunwayId()
646         //           << " " << fp->getRunway() << endl;
647         // }
648         //if ((dep->getId() == string("EHAM")) && (prev->name == "park2"))
649         //  {
650         //    cerr << "Schiphol ground " 
651         //       << trafficRef->getCallSign();
652         //    if (trafficRef->getHeavy())
653         //      cerr << "Heavy";
654         //    cerr << ", is type " 
655         //       << trafficRef->getAircraft()
656         //       << " ready to go. IFR to "
657         //       << arr->getId() <<endl;
658         //  }   
659         if (prev->name == "park2")
660           dep->releaseParking(fp->getGate());
661         
662         //if ((arr->getId() == string("EHAM")) && (prev->name  == "Center"))
663         //  {
664         //    
665         //    cerr << "Schiphol ground " 
666         //       << trafficRef->getCallSign();
667         //    if (trafficRef->getHeavy())
668         //      cerr << "Heavy";
669         //    cerr << " landed runway " 
670         //       << fp->getRunway()
671         //       << " request taxi to gate " 
672         //       << arr->getParkingName(fp->getGate()) 
673         //       << endl;
674         //  }
675         if (prev->name == "END")
676           fp->setTime(trafficRef->getDepartureTime());
677         //cerr << "5" << endl;
678       }
679     if (next) 
680       {
681         //cerr << "Current waypoint" << curr->name << endl;
682         //cerr << "Next waypoint" << next->name << endl;
683         fp->setLeadDistance(speed, tgt_heading, curr, next);
684       }
685     //cerr << "5.1" << endl;
686     if (curr->crossat > -1000.0) {
687       //cerr << "5.1a" << endl;
688       use_perf_vs = false;
689       tgt_vs = (curr->crossat - altitude)/
690         (fp->getDistanceToGo(pos.lat(), pos.lon(), curr)/6076.0/speed*60.0);
691       //cerr << "5.1b" << endl;
692       tgt_altitude = curr->crossat;
693     } else {
694       //cerr << "5.1c" << endl;
695       use_perf_vs = true;
696       //cerr << "5.1d" << endl; 
697       tgt_altitude = prev->altitude;
698       //cerr << "Setting target altitude : " <<tgt_altitude << endl;
699     }
700     //cerr << "6" << endl;
701     tgt_speed = prev->speed;
702     hdg_lock = alt_lock = true;
703     no_roll = prev->on_ground;
704     //cout << "Crossing waypoint: " << prev->name << endl;
705     //cout << "  Target speed:    " << tgt_speed << endl;
706     //cout << "  Target altitude: " << tgt_altitude << endl;
707     //cout << "  Target heading:  " << tgt_heading << endl << endl;       
708   } else {
709     
710     double calc_bearing = fp->getBearing(pos.lat(), pos.lon(), curr);
711     //cerr << "Bearing = " << calc_bearing << endl;
712     if (speed < 0)
713       {
714         calc_bearing +=180;
715         if (calc_bearing > 360)
716           calc_bearing -= 360;
717       }
718     if (finite(calc_bearing))
719       {
720         double hdg_error = calc_bearing - tgt_heading;
721         if (fabs(hdg_error) > 1.0) {
722           TurnTo( calc_bearing ); 
723         }
724       }
725     else
726       {
727         cerr << "calc_bearing is not a finite number : "
728              << "Speed " << speed
729              << "pos : " << pos.lat() << ", " << pos.lon()
730              << "waypoint " << curr->latitude << ", " << curr->longitude << endl;
731         cerr << "waypoint name " << curr->name;
732         exit(1);
733       }
734     double speed_diff = speed - prevSpeed;
735     // Update the lead distance calculation if speed has changed sufficiently
736     // to prevent spinning (hopefully);
737     if (fabs(speed_diff) > 10)
738       { 
739         prevSpeed = speed;
740         fp->setLeadDistance(speed, tgt_heading, curr, next);
741       }
742     
743     //cerr << "Done Processing FlightPlan"<< endl;
744   } // if (dt count) else
745 }
746
747   bool FGAIAircraft::_getGearDown() const {
748    return ((props->getFloatValue("position/altitude-agl-ft") < 900.0)
749             && (props->getFloatValue("velocities/airspeed-kt")
750                  < performance->land_speed*1.25));
751 }
752
753
754 void FGAIAircraft::loadNextLeg() 
755 {
756   //delete fp;
757   //time_t now = time(NULL) + fgGetLong("/sim/time/warp");
758   
759   
760   //FGAIModelEntity entity;
761   //entity.m_class = "jet_transport";
762   //entity.path = modelPath.c_str();
763   //entity.flightplan = "none";
764   //entity.latitude = _getLatitude();
765   //entity.longitude = _getLongitude();
766  //entity.altitude = trafficRef->getCruiseAlt() * 100; // convert from FL to feet
767   //entity.speed = 450; // HACK ALERT
768   //entity.fp = new FGAIFlightPlan(&entity, courseToDest, i->getDepartureTime(), dep, arr);
769   int leg;
770   if ((leg = fp->getLeg())  == 10)
771     {
772       trafficRef->next();
773       leg = 1;
774       fp->setLeg(leg);
775       
776       //cerr << "Resetting leg : " << leg << endl;
777     }
778   //{
779   //leg++;
780   //fp->setLeg(leg);
781   //cerr << "Creating leg number : " << leg << endl;
782   FGAirport *dep = trafficRef->getDepartureAirport();
783   FGAirport *arr = trafficRef->getArrivalAirport();
784   if (!(dep && arr))
785     {
786       setDie(true);
787       //cerr << "Failed to get airport in AIAircraft::ProcessFlightplan()" << endl;
788       //if (dep)
789       //  cerr << "Departure " << dep->getId() << endl;
790       //if (arr) 
791       //  cerr << "Arrival   " << arr->getId() << endl;
792     }
793   else
794     {
795       double cruiseAlt = trafficRef->getCruiseAlt() * 100;
796       //cerr << "Creating new leg using " << cruiseAlt << " as cruise altitude."<< endl;
797       
798       fp->create (dep,
799                   arr,
800                   leg,
801                   cruiseAlt, //(trafficRef->getCruiseAlt() * 100), // convert from FL to feet
802                   trafficRef->getSpeed(),
803                   _getLatitude(),
804                   _getLongitude(),
805                   false,
806                   trafficRef->getRadius(),
807                   trafficRef->getFlightType(), 
808                   acType,
809                   company);
810       //prev = fp->getPreviousWaypoint();
811       //curr = fp->getCurrentWaypoint();
812       //next = fp->getNextWaypoint();
813       //cerr << "25" << endl;
814       //if (next) 
815       //        {
816       //  //cerr << "Next waypoint" << next->name << endl;
817       //          fp->setLeadDistance(speed, tgt_heading, curr, next);
818       //        }
819       //cerr << "25.1" << endl;
820       //if (curr->crossat > -1000.0) {
821       //        //cerr << "25.1a" << endl;
822       //        use_perf_vs = false;
823       //        
824       //        tgt_vs = (curr->crossat - altitude)/
825       //          (fp->getDistanceToGo(pos.lat(), pos.lon(), curr)/6076.0/speed*60.0);
826       //        //cerr << "25.1b" << endl;
827       //        tgt_altitude = curr->crossat;
828       //} else {
829       //        //cerr << "25.1c" << endl;
830       //        use_perf_vs = true;
831       //        //cerr << "25.1d" << endl;      
832       //        tgt_altitude = prev->altitude;
833       //        //cerr << "Setting target altitude : " <<tgt_altitude << endl;
834       // }
835       //cerr << "26" << endl;
836       //tgt_speed = prev->speed;
837       //hdg_lock = alt_lock = true;
838       //no_roll = prev->on_ground;
839       
840     }
841   //}
842   //else
843   //{
844   //delete entity.fp;
845   //entity.fp = new FGAIFlightPlan(&entity, 
846   //                             999,  // A hack
847   //                             trafficRef->getDepartureTime(), 
848   //                             trafficRef->getDepartureAirport(), 
849   //                             trafficRef->getArrivalAirport(),
850   //                             false,
851   //                             acType,
852   //                             company);
853   //SetFlightPlan(entity.fp);
854 }
855
856
857
858 // Note: This code is copied from David Luff's AILocalTraffic 
859 // Warning - ground elev determination is CPU intensive
860 // Either this function or the logic of how often it is called
861 // will almost certainly change.
862
863 void FGAIAircraft::getGroundElev(double dt) {
864   dt_elev_count += dt;
865   //return;
866   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
867     {
868       return;
869     }
870   else
871     {
872       dt_elev_count = 0;
873     }
874   // It would be nice if we could set the correct tile center here in order to get a correct
875   // answer with one call to the function, but what I tried in the two commented-out lines
876   // below only intermittently worked, and I haven't quite groked why yet.
877   //SGBucket buck(pos.lon(), pos.lat());
878   //aip.getSGLocation()->set_tile_center(Point3D(buck.get_center_lon(), buck.get_center_lat(), 0.0));
879   
880   // Only do the proper hitlist stuff if we are within visible range of the viewer.
881   double visibility_meters = fgGetDouble("/environment/visibility-m");  
882  
883
884   FGViewer* vw = globals->get_current_view();
885   double 
886     course, 
887     distance;
888
889   //Point3D currView(vw->getLongitude_deg(), 
890   //               vw->getLatitude_deg(), 0.0);
891   SGWayPoint current  (pos.lon(),
892                        pos.lat(),
893                        0);
894   SGWayPoint view (   vw->getLongitude_deg(),
895                       vw->getLatitude_deg(),
896                       0);
897   view.CourseAndDistance(current, &course, &distance);
898   if(distance > visibility_meters) {
899     //aip.getSGLocation()->set_cur_elev_m(aptElev);
900     return;
901   }
902     
903   
904   //globals->get_tile_mgr()->prep_ssg_nodes( acmodel_location,
905   globals->get_tile_mgr()->prep_ssg_nodes( aip.getSGLocation(), visibility_meters );
906   Point3D scenery_center = globals->get_scenery()->get_center();
907
908   globals->get_tile_mgr()->update( aip.getSGLocation(), 
909                                    visibility_meters, 
910                                    (aip.getSGLocation())->get_absolute_view_pos( scenery_center ) );
911   // save results of update in SGLocation for fdm...
912   
913   //if ( globals->get_scenery()->get_cur_elev() > -9990 ) {
914   //    acmodel_location->
915   //    set_cur_elev_m( globals->get_scenery()->get_cur_elev() );
916   //}
917   
918   // The need for this here means that at least 2 consecutive passes are needed :-(
919   aip.getSGLocation()->set_tile_center( globals->get_scenery()->get_next_center() );
920     globals->get_tile_mgr()->prep_ssg_nodes( aip.getSGLocation(),       visibility_meters );
921     //Point3D scenery_center = globals->get_scenery()->get_center();
922
923   globals->get_tile_mgr()->update( aip.getSGLocation(), 
924                                    visibility_meters, 
925                                    (aip.getSGLocation())->get_absolute_view_pos( scenery_center ) );
926   // save results of update in SGLocation for fdm...
927   
928   //if ( globals->get_scenery()->get_cur_elev() > -9990 ) {
929   //    acmodel_location->
930   //    set_cur_elev_m( globals->get_scenery()->get_cur_elev() );
931   //}
932   
933   // The need for this here means that at least 2 consecutive passes are needed :-(
934   aip.getSGLocation()->set_tile_center( globals->get_scenery()->get_next_center() );
935   //cerr << "Transform Elev is " << globals->get_scenery()->get_cur_elev() << '\n';
936   tgt_altitude = (globals->get_scenery()->get_cur_elev() * SG_METER_TO_FEET) + groundOffset;
937 }
938
939 //globals->get_tile_mgr()->prep_ssg_nodes( _aip.getSGLocation(),        visibility_meters );
940 //Point3D scenery_center = globals->get_scenery()->get_center();
941 //globals->get_tile_mgr()->update(_aip.getSGLocation(), visibility_meters, (_aip.getSGLocation())->get_absolute_view_pos( scenery_center ) );
942 // save results of update in SGLocation for fdm...
943
944 //if ( globals->get_scenery()->get_cur_elev() > -9990 ) {
945 //      acmodel_location->
946 //      set_cur_elev_m( globals->get_scenery()->get_cur_elev() );
947 //}
948
949 // The need for this here means that at least 2 consecutive passes are needed :-(
950 //_aip.getSGLocation()->set_tile_center( globals->get_scenery()->get_next_center() );
951
952 //cout << "Transform Elev is " << globals->get_scenery()->get_cur_elev() << '\n';
953 //_aip.getSGLocation()->set_cur_elev_m(globals->get_scenery()->get_cur_elev());
954 //return(globals->get_scenery()->get_cur_elev());
955 //}