]> git.mxchange.org Git - flightgear.git/blob - src/AIModel/AIFlightPlanCreate.cxx
296a5920cae4f9b8ceb56c49c10ade29b84dbe92
[flightgear.git] / src / AIModel / AIFlightPlanCreate.cxx
1 /******************************************************************************
2  * AIFlightPlanCreate.cxx
3  * Written by Durk Talsma, started May, 2004.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18  *
19  **************************************************************************/
20 #include "AIFlightPlan.hxx"
21 #include <simgear/math/sg_geodesy.hxx>
22 #include <Airports/runways.hxx>
23
24 #include <Environment/environment_mgr.hxx>
25 #include <Environment/environment.hxx>
26
27
28 /* FGAIFlightPlan::create()
29  * dynamically create a flight plan for AI traffic, based on data provided by the
30  * Traffic Manager, when reading a filed flightplan failes. (DT, 2004/07/10) 
31  *
32  * This is the top-level function, and the only one that is publicly available.
33  *
34  */ 
35
36
37 // Check lat/lon values during initialization;
38 void FGAIFlightPlan::create(FGAirport *dep, FGAirport *arr, int legNr, 
39                             double alt, double speed, double latitude, 
40                             double longitude, bool firstFlight,double radius, 
41                             const string& fltType, const string& aircraftType, 
42                             const string& airline)
43
44   int currWpt = wpt_iterator - waypoints.begin();
45   switch(legNr)
46     {
47     case 1:
48       createPushBack(firstFlight,dep, latitude, longitude, 
49                      radius, fltType, aircraftType, airline);
50       break;
51     case 2: 
52       createTaxi(firstFlight, 1, dep, latitude, longitude, 
53                  radius, fltType, aircraftType, airline);
54       break;
55     case 3: 
56       createTakeOff(firstFlight, dep, speed);
57       break;
58     case 4: 
59       createClimb(firstFlight, dep, speed, alt);
60       break;
61     case 5: 
62       createCruise(firstFlight, dep,arr, latitude, longitude, speed, alt);
63       break;
64     case 6: 
65       createDecent(arr);
66       break;
67     case 7: 
68       createLanding(arr);
69       break;
70     case 8: 
71       createTaxi(false, 2, arr, latitude, longitude, radius, 
72                  fltType, aircraftType, airline);
73       break;
74       case 9: 
75         createParking(arr, radius);
76       break;
77     default:
78       //exit(1);
79       SG_LOG(SG_INPUT, SG_ALERT, "AIFlightPlan::create() attempting to create unknown leg"
80              " this is probably an internal program error");
81     }
82   wpt_iterator = waypoints.begin()+currWpt;
83   leg++;
84 }
85
86 /*******************************************************************
87  * createPushBack
88  * initialize the Aircraft at the parking location
89  ******************************************************************/
90 void FGAIFlightPlan::createPushBack(bool firstFlight, FGAirport *dep, 
91                                     double latitude,
92                                     double longitude,
93                                     double radius,
94                                     const string& fltType,
95                                     const string& aircraftType,
96                                     const string& airline)
97 {
98   double heading;
99   double lat;
100   double lon;
101   double lat2;
102   double lon2;
103   double az2;
104   
105   //int currWpt = wpt_iterator - waypoints.begin();
106   // Erase all existing waypoints.
107   //resetWaypoints();
108   
109   // We only need to get a valid parking if this is the first leg. 
110   // Otherwise use the current aircraft position.
111   if (firstFlight)
112     {
113       if (!(dep->getDynamics()->getAvailableParking(&lat, &lon, 
114                                                     &heading, &gateId, 
115                                                     radius, fltType, 
116                                                     aircraftType, airline)))
117         {
118           SG_LOG(SG_INPUT, SG_WARN, "Could not find parking for a " << 
119                  aircraftType <<
120                  " of flight type " << fltType << 
121                  " of airline     " << airline <<
122                  " at airport     " << dep->getId());
123         }
124     }
125   else
126     {
127       dep->getDynamics()->getParking(gateId, &lat, &lon, &heading);
128     }
129   heading += 180.0;
130   if (heading > 360)
131     heading -= 360;
132   waypoint *wpt = new waypoint;
133   wpt->name      = "park";
134   wpt->latitude  = lat;
135   wpt->longitude = lon;
136   wpt->altitude  = dep->getElevation();
137   wpt->speed     = -10; 
138   wpt->crossat   = -10000;
139   wpt->gear_down = true;
140   wpt->flaps_down= true;
141   wpt->finished  = false;
142   wpt->on_ground = true;
143   waypoints.push_back(wpt); 
144   
145   // Add park twice, because it uses park once for initialization and once
146   // to trigger the departure ATC message 
147   geo_direct_wgs_84 ( 0, lat, lon, heading, 
148                       10, 
149                       &lat2, &lon2, &az2 );
150   wpt = new waypoint;
151   wpt->name      = "park2";
152   wpt->latitude  = lat2;
153   wpt->longitude = lon2;
154   wpt->altitude  = dep->getElevation();
155   wpt->speed     = -10; 
156   wpt->crossat   = -10000;
157   wpt->gear_down = true;
158   wpt->flaps_down= true;
159   wpt->finished  = false;
160   wpt->on_ground = true;
161   waypoints.push_back(wpt); 
162   geo_direct_wgs_84 ( 0, lat, lon, heading, 
163                       2.2*radius,           
164                       &lat2, &lon2, &az2 );
165   wpt = new waypoint;
166   wpt->name      = "taxiStart";
167   wpt->latitude  = lat2;
168   wpt->longitude = lon2;
169   wpt->altitude  = dep->getElevation();
170   wpt->speed     = 10; 
171   wpt->crossat   = -10000;
172   wpt->gear_down = true;
173   wpt->flaps_down= true;
174   wpt->finished  = false;
175   wpt->on_ground = true;
176   waypoints.push_back(wpt);  
177 }
178
179 /*******************************************************************
180  * createCreate Taxi. 
181  * initialize the Aircraft at the parking location
182  ******************************************************************/
183 void FGAIFlightPlan::createTaxi(bool firstFlight, int direction, 
184                                 FGAirport *apt, double latitude, double longitude, 
185                                 double radius, const string& fltType, 
186                                 const string& acType, const string& airline)
187 {
188   double wind_speed;
189   double wind_heading;
190   double heading;
191   double lat, lon, az;
192   double lat2, lon2, az2;
193   waypoint *wpt;
194
195    if (direction == 1)
196     {
197       // If this function is called during initialization,
198       // make sure we obtain a valid gate ID first
199       // and place the model at the location of the gate.
200       if (firstFlight)
201         {
202           if (!(apt->getDynamics()->getAvailableParking(&lat, &lon, 
203                                                         &heading, &gateId, 
204                                                         radius, fltType, 
205                                                         acType, airline)))
206             {
207               SG_LOG(SG_INPUT, SG_WARN, "Could not find parking for a " << 
208                      acType <<
209                      " of flight type " << fltType <<
210                      " of airline     " << airline <<
211                      " at airport     " << apt->getId());
212             }
213           //waypoint *wpt = new waypoint;
214           //wpt->name      = "park";
215           //wpt->latitude  = lat;
216           //wpt->longitude = lon;
217           //wpt->altitude  = apt->getElevation();
218           //wpt->speed     = -10; 
219           //wpt->crossat   = -10000;
220           //wpt->gear_down = true;
221           //wpt->flaps_down= true;
222           //wpt->finished  = false;
223           //wpt->on_ground = true;
224           //waypoints.push_back(wpt);  
225         }
226       // "NOTE: this is currently fixed to "com" for commercial traffic
227       // Should be changed to be used dynamically to allow "gen" and "mil"
228       // as well
229       apt->getDynamics()->getActiveRunway("com", 1, activeRunway);
230       if (!(globals->get_runways()->search(apt->getId(), 
231                                             activeRunway, 
232                                             &rwy)))
233         {
234            SG_LOG(SG_INPUT, SG_ALERT, "Failed to find runway " << 
235                   activeRunway << 
236                   " at airport     " << apt->getId());
237            exit(1);
238         } 
239
240       // Determine the beginning of he runway
241       heading = rwy._heading;
242       double azimuth = heading + 180.0;
243       while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
244       geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, 
245                           rwy._length * SG_FEET_TO_METER * 0.5 - 5.0,
246                           &lat2, &lon2, &az2 );
247
248       if (apt->getDynamics()->getGroundNetwork()->exists())
249         {
250           intVec ids;
251           int runwayId = apt->getDynamics()->getGroundNetwork()->findNearestNode(lat2, 
252                                                                                  lon2);
253
254           
255           // A negative gateId indicates an overflow parking, use a
256           // fallback mechanism for this. 
257           // Starting from gate 0 in this case is a bit of a hack
258           // which requires a more proper solution later on.
259           FGTaxiRoute route;
260           if (gateId >= 0)
261             route = apt->getDynamics()->getGroundNetwork()->findShortestRoute(gateId, 
262                                                                               runwayId);
263           else
264             route = apt->getDynamics()->getGroundNetwork()->findShortestRoute(0, runwayId);
265           intVecIterator i;
266          
267           if (route.empty()) {
268             //Add the runway startpoint;
269             wpt = new waypoint;
270             wpt->name      = "Airport Center";
271             wpt->latitude  = latitude;
272             wpt->longitude = longitude;
273             wpt->altitude  = apt->getElevation();
274             wpt->speed     = 15; 
275             wpt->crossat   = -10000;
276             wpt->gear_down = true;
277             wpt->flaps_down= true;
278             wpt->finished  = false;
279             wpt->on_ground = true;
280             waypoints.push_back(wpt);
281             
282             //Add the runway startpoint;
283             wpt = new waypoint;
284             wpt->name      = "Runway Takeoff";
285             wpt->latitude  = lat2;
286             wpt->longitude = lon2;
287             wpt->altitude  = apt->getElevation();
288             wpt->speed     = 15; 
289             wpt->crossat   = -10000;
290             wpt->gear_down = true;
291             wpt->flaps_down= true;
292             wpt->finished  = false;
293             wpt->on_ground = true;
294             waypoints.push_back(wpt);   
295           } else {
296             int node;
297             route.first();
298             bool isPushBackPoint = false;
299             if (firstFlight) {
300               // If this is called during initialization, randomly
301               // skip a number of waypoints to get a more realistic
302               // taxi situation.
303               isPushBackPoint = true;
304               int nrWaypoints = route.size();
305               int nrWaypointsToSkip = rand() % nrWaypoints;
306               for (int i = 0; i < nrWaypointsToSkip; i++) {
307                 isPushBackPoint = false;
308                 route.next(&node);
309               }
310             }
311             else {
312               //chop off the first two waypoints, because
313               // those have already been created
314               // by create pushback
315               int size = route.size();
316               if (size > 2) {
317                 route.next(&node);
318                 route.next(&node);
319               }
320             }
321             while(route.next(&node))
322               {
323                 FGTaxiNode *tn = apt->getDynamics()->getGroundNetwork()->findNode(node);
324                 //ids.pop_back();  
325                 wpt = new waypoint;
326                 wpt->name      = "taxiway"; // fixme: should be the name of the taxiway
327                 wpt->latitude  = tn->getLatitude();
328                 wpt->longitude = tn->getLongitude();
329                 // Elevation is currently disregarded when on_ground is true
330                 // because the AIModel obtains a periodic ground elevation estimate.
331                 wpt->altitude  = apt->getElevation();
332                 if (isPushBackPoint) {
333                   wpt->speed = -10;
334                   isPushBackPoint = false;
335                 }
336                 else {
337                   wpt->speed     = 15; 
338                 }
339                 wpt->crossat   = -10000;
340                 wpt->gear_down = true;
341                 wpt->flaps_down= true;
342                 wpt->finished  = false;
343                 wpt->on_ground = true;
344                 waypoints.push_back(wpt);
345               }
346             cerr << endl;
347           }
348         }
349       else 
350         {
351           // This is the fallback mechanism, in case no ground network is available
352           //Add the runway startpoint;
353           wpt = new waypoint;
354           wpt->name      = "Airport Center";
355           wpt->latitude  = apt->getLatitude();
356           wpt->longitude = apt->getLongitude();
357           wpt->altitude  = apt->getElevation();
358           wpt->speed     = 15; 
359           wpt->crossat   = -10000;
360           wpt->gear_down = true;
361           wpt->flaps_down= true;
362           wpt->finished  = false;
363           wpt->on_ground = true;
364           waypoints.push_back(wpt);
365           
366           //Add the runway startpoint;
367           wpt = new waypoint;
368           wpt->name      = "Runway Takeoff";
369           wpt->latitude  = lat2;
370           wpt->longitude = lon2;
371           wpt->altitude  = apt->getElevation();
372           wpt->speed     = 15; 
373           wpt->crossat   = -10000;
374           wpt->gear_down = true;
375           wpt->flaps_down= true;
376           wpt->finished  = false;
377           wpt->on_ground = true;
378           waypoints.push_back(wpt);
379         }
380     }
381   else  // Landing taxi
382     {
383       apt->getDynamics()->getAvailableParking(&lat, &lon, &heading, 
384                                               &gateId, radius, fltType, 
385                                               acType, airline);
386      
387       double lat3 = (*(waypoints.end()-1))->latitude;
388       double lon3 = (*(waypoints.end()-1))->longitude;
389       //cerr << (*(waypoints.end()-1))->name << endl;
390       
391       // Find a route from runway end to parking/gate.
392       if (apt->getDynamics()->getGroundNetwork()->exists())
393         {
394           intVec ids;
395           int runwayId = apt->getDynamics()->getGroundNetwork()->findNearestNode(lat3, 
396                                                                                  lon3);
397           // A negative gateId indicates an overflow parking, use a
398           // fallback mechanism for this. 
399           // Starting from gate 0 is a bit of a hack...
400           FGTaxiRoute route;
401           if (gateId >= 0)
402             route = apt->getDynamics()->getGroundNetwork()->findShortestRoute(runwayId, 
403                                                                               gateId);
404           else
405             route = apt->getDynamics()->getGroundNetwork()->findShortestRoute(runwayId, 0);
406           intVecIterator i;
407          
408           // No route found: go from gate directly to runway
409           if (route.empty()) {
410             //Add the runway startpoint;
411             wpt = new waypoint;
412             wpt->name      = "Airport Center";
413             wpt->latitude  = latitude;
414             wpt->longitude = longitude;
415             wpt->altitude  = apt->getElevation();
416             wpt->speed     = 15; 
417             wpt->crossat   = -10000;
418             wpt->gear_down = true;
419             wpt->flaps_down= true;
420             wpt->finished  = false;
421             wpt->on_ground = true;
422             waypoints.push_back(wpt);
423             
424             //Add the runway startpoint;
425             wpt = new waypoint;
426             wpt->name      = "Runway Takeoff";
427             wpt->latitude  = lat2;
428             wpt->longitude = lon2;
429             wpt->altitude  = apt->getElevation();
430             wpt->speed     = 15; 
431             wpt->crossat   = -10000;
432             wpt->gear_down = true;
433             wpt->flaps_down= true;
434             wpt->finished  = false;
435             wpt->on_ground = true;
436             waypoints.push_back(wpt);   
437           } else {
438             int node;
439             route.first();
440             int size = route.size();
441             // Omit the last two waypoints, as 
442             // those are created by createParking()
443             for (int i = 0; i < size-2; i++)
444               {
445                 route.next(&node);
446                 FGTaxiNode *tn = apt->getDynamics()->getGroundNetwork()->findNode(node);
447                 wpt = new waypoint;
448                 wpt->name      = "taxiway"; // fixme: should be the name of the taxiway
449                 wpt->latitude  = tn->getLatitude();
450                 wpt->longitude = tn->getLongitude();
451                 wpt->altitude  = apt->getElevation();
452                 wpt->speed     = 15; 
453                 wpt->crossat   = -10000;
454                 wpt->gear_down = true;
455                 wpt->flaps_down= true;
456                 wpt->finished  = false;
457                 wpt->on_ground = true;
458                 waypoints.push_back(wpt);
459               }
460           }
461         }
462       else
463         {
464           // Use a fallback mechanism in case no ground network is available
465           // obtain the location of the gate entrance point 
466           heading += 180.0;
467           if (heading > 360)
468             heading -= 360;
469           geo_direct_wgs_84 ( 0, lat, lon, heading, 
470                               100,
471                               &lat2, &lon2, &az2 );
472           wpt = new waypoint;
473           wpt->name      = "Airport Center";
474           wpt->latitude  = apt->getLatitude();
475           wpt->longitude = apt->getLongitude();
476           wpt->altitude  = apt->getElevation();
477           wpt->speed     = 15; 
478           wpt->crossat   = -10000;
479           wpt->gear_down = true;
480           wpt->flaps_down= true;
481           wpt->finished  = false;
482           wpt->on_ground = true;
483           waypoints.push_back(wpt);
484          
485           wpt = new waypoint;
486           wpt->name      = "Begin Parking"; //apt->getId(); //wpt_node->getStringValue("name", "END");
487           wpt->latitude  = lat2;
488           wpt->longitude = lon2;
489           wpt->altitude  = apt->getElevation();
490           wpt->speed     = 15; 
491           wpt->crossat   = -10000;
492           wpt->gear_down = true;
493           wpt->flaps_down= true;
494           wpt->finished  = false;
495           wpt->on_ground = true;
496           waypoints.push_back(wpt); 
497
498           //waypoint* wpt;
499           //double lat;
500           //double lon;
501           //double heading;
502           apt->getDynamics()->getParking(gateId, &lat, &lon, &heading);
503           heading += 180.0;
504           if (heading > 360)
505             heading -= 360; 
506           
507           wpt = new waypoint;
508           wpt->name      = "END"; //wpt_node->getStringValue("name", "END");
509           wpt->latitude  = lat;
510           wpt->longitude = lon;
511           wpt->altitude  = 19;
512           wpt->speed     = 15; 
513           wpt->crossat   = -10000;
514           wpt->gear_down = true;
515           wpt->flaps_down= true;
516           wpt->finished  = false;
517           wpt->on_ground = true;
518           waypoints.push_back(wpt);
519         }
520       
521     }
522 }
523
524 /*******************************************************************
525  * CreateTakeOff 
526  * initialize the Aircraft at the parking location
527  ******************************************************************/
528 void FGAIFlightPlan::createTakeOff(bool firstFlight, FGAirport *apt, double speed)
529 {
530   double wind_speed;
531   double wind_heading;
532   double heading;
533   double lat, lon, az;
534   double lat2, lon2, az2;
535   waypoint *wpt;
536   
537   // Get the current active runway, based on code from David Luff
538   // This should actually be unified and extended to include 
539   // Preferential runway use schema's 
540   if (firstFlight)
541     {
542       //string name;
543        // "NOTE: this is currently fixed to "com" for commercial traffic
544       // Should be changed to be used dynamically to allow "gen" and "mil"
545       // as well
546       apt->getDynamics()->getActiveRunway("com", 1, activeRunway);
547         if (!(globals->get_runways()->search(apt->getId(), 
548                                               activeRunway, 
549                                               &rwy)))
550           {
551             SG_LOG(SG_INPUT, SG_ALERT, "Failed to find runway " << 
552                    activeRunway << 
553                    " at airport     " << apt->getId());
554             exit(1);
555           }
556     }
557   heading = rwy._heading;
558   double azimuth = heading + 180.0;
559   while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
560   geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, 
561                       rwy._length * SG_FEET_TO_METER * 0.5 - 105.0,
562                       &lat2, &lon2, &az2 );
563   wpt = new waypoint; 
564   wpt->name      = "accel"; 
565   wpt->latitude  = lat2; 
566   wpt->longitude = lon2; 
567   wpt->altitude  = apt->getElevation();
568   wpt->speed     = speed;  
569   wpt->crossat   = -10000;
570   wpt->gear_down = true;
571   wpt->flaps_down= true;
572   wpt->finished  = false;
573   wpt->on_ground = true;
574   waypoints.push_back(wpt); 
575   
576   lat = lat2;
577   lon = lon2;
578   az  = az2;
579   
580   //Next: the Start of Climb
581   geo_direct_wgs_84 ( 0, lat, lon, heading, 
582   2560 * SG_FEET_TO_METER,
583   &lat2, &lon2, &az2 );
584   
585   wpt = new waypoint;
586   wpt->name      = "SOC";
587   wpt->latitude  = lat2;
588   wpt->longitude = lon2;
589   wpt->altitude  = apt->getElevation()+3000;
590   wpt->speed     = speed; 
591   wpt->crossat   = -10000;
592   wpt->gear_down = true;
593   wpt->flaps_down= true;
594   wpt->finished  = false;
595   wpt->on_ground = false;
596   waypoints.push_back(wpt);
597 }
598  
599 /*******************************************************************
600  * CreateClimb
601  * initialize the Aircraft at the parking location
602  ******************************************************************/
603 void FGAIFlightPlan::createClimb(bool firstFlight, FGAirport *apt, double speed, double alt)
604 {
605   double wind_speed;
606   double wind_heading;
607   double heading;
608   //FGRunway rwy;
609   double lat, lon, az;
610   double lat2, lon2, az2;
611   //int direction;
612   waypoint *wpt;
613
614  
615   if (firstFlight)
616     {
617       //string name;
618       // "NOTE: this is currently fixed to "com" for commercial traffic
619       // Should be changed to be used dynamically to allow "gen" and "mil"
620       // as well
621       apt->getDynamics()->getActiveRunway("com", 1, activeRunway);
622         if (!(globals->get_runways()->search(apt->getId(), 
623                                               activeRunway, 
624                                               &rwy)))
625           {
626             SG_LOG(SG_INPUT, SG_ALERT, "Failed to find runway " << 
627                    activeRunway << 
628                    " at airport     " << apt->getId());
629             exit(1);
630           }
631     }
632   
633   
634   heading = rwy._heading;
635   double azimuth = heading + 180.0;
636   while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
637   geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, heading, 
638                       10*SG_NM_TO_METER,
639                       &lat2, &lon2, &az2 );
640   wpt = new waypoint;
641   wpt->name      = "10000ft climb";
642   wpt->latitude  = lat2;
643   wpt->longitude = lon2;
644   wpt->altitude  = 10000;
645   wpt->speed     = speed; 
646   wpt->crossat   = -10000;
647   wpt->gear_down = true;
648   wpt->flaps_down= true;
649   wpt->finished  = false;
650   wpt->on_ground = false;
651   waypoints.push_back(wpt); 
652   
653
654   geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, heading, 
655                       20*SG_NM_TO_METER,
656                       &lat2, &lon2, &az2 );
657   wpt = new waypoint;
658   wpt->name      = "18000ft climb";
659   wpt->latitude  = lat2;
660   wpt->longitude = lon2;
661   wpt->altitude  = 18000;
662   wpt->speed     = speed; 
663   wpt->crossat   = -10000;
664   wpt->gear_down = true;
665   wpt->flaps_down= true;
666   wpt->finished  = false;
667   wpt->on_ground = false;
668   waypoints.push_back(wpt); 
669 }
670
671
672 /*******************************************************************
673  * CreateCruise
674  * initialize the Aircraft at the parking location
675  ******************************************************************/
676 void FGAIFlightPlan::createCruise(bool firstFlight, FGAirport *dep, 
677                                   FGAirport *arr, double latitude, 
678                                   double longitude, double speed, 
679                                   double alt)
680 {
681   double wind_speed;
682   double wind_heading;
683   double heading;
684   double lat, lon, az;
685   double lat2, lon2, az2;
686   double azimuth;
687   waypoint *wpt;
688
689   wpt = new waypoint;
690   wpt->name      = "Cruise"; //wpt_node->getStringValue("name", "END");
691   wpt->latitude  = latitude;
692   wpt->longitude = longitude;
693   wpt->altitude  = alt;
694   wpt->speed     = speed; 
695   wpt->crossat   = -10000;
696   wpt->gear_down = false;
697   wpt->flaps_down= false;
698   wpt->finished  = false;
699   wpt->on_ground = false;
700   waypoints.push_back(wpt); 
701   
702  
703   // should be changed dynamically to allow "gen" and "mil"
704   arr->getDynamics()->getActiveRunway("com", 2, activeRunway);
705   if (!(globals->get_runways()->search(arr->getId(), 
706                                        activeRunway, 
707                                        &rwy)))
708     {
709       SG_LOG(SG_INPUT, SG_ALERT, "Failed to find runway " << 
710              activeRunway << 
711              " at airport     " << arr->getId());
712       exit(1);
713     }
714   heading = rwy._heading;
715   azimuth = heading + 180.0;
716   while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
717   
718   
719   geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, 
720                       110000,
721                       &lat2, &lon2, &az2 );
722   wpt = new waypoint;
723   wpt->name      = "BOD";
724   wpt->latitude  = lat2;
725   wpt->longitude = lon2;
726   wpt->altitude  = alt;
727   wpt->speed     = speed; 
728   wpt->crossat   = alt;
729   wpt->gear_down = false;
730   wpt->flaps_down= false;
731   wpt->finished  = false;
732   wpt->on_ground = false;
733   waypoints.push_back(wpt); 
734 }
735
736 /*******************************************************************
737  * CreateDecent
738  * initialize the Aircraft at the parking location
739  ******************************************************************/
740 void FGAIFlightPlan::createDecent(FGAirport *apt)
741 {
742
743   // Ten thousand ft. Slowing down to 240 kts
744   double wind_speed;
745   double wind_heading;
746   double heading;
747   //FGRunway rwy;
748   double lat, lon, az;
749   double lat2, lon2, az2;
750   double azimuth;
751   //int direction;
752   waypoint *wpt;
753
754   //Beginning of Decent
755   //string name;
756   // allow "mil" and "gen" as well
757   apt->getDynamics()->getActiveRunway("com", 2, activeRunway);
758   if (!(globals->get_runways()->search(apt->getId(), 
759                                        activeRunway, 
760                                        &rwy)))
761     {
762       SG_LOG(SG_INPUT, SG_ALERT, "Failed to find runway " << 
763              activeRunway << 
764              " at airport     " << apt->getId());
765       exit(1);
766     }
767   
768   heading = rwy._heading;
769   azimuth = heading + 180.0;
770   while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
771   geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, 
772                       100000,
773                       &lat2, &lon2, &az2 );
774   
775   wpt = new waypoint;
776   wpt->name      = "Dec 10000ft"; //wpt_node->getStringValue("name", "END");
777   wpt->latitude  = lat2;
778   wpt->longitude = lon2;
779   wpt->altitude  = apt->getElevation();
780   wpt->speed     = 240; 
781   wpt->crossat   = 10000;
782   wpt->gear_down = false;
783   wpt->flaps_down= false;
784   wpt->finished  = false;
785   wpt->on_ground = false;
786   waypoints.push_back(wpt);  
787   
788   // Three thousand ft. Slowing down to 160 kts
789   geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, 
790                       8*SG_NM_TO_METER,
791                       &lat2, &lon2, &az2 );
792   wpt = new waypoint;
793   wpt->name      = "DEC 3000ft"; //wpt_node->getStringValue("name", "END");
794   wpt->latitude  = lat2;
795   wpt->longitude = lon2;
796   wpt->altitude  = apt->getElevation();
797   wpt->speed     = 160; 
798   wpt->crossat   = 3000;
799   wpt->gear_down = true;
800   wpt->flaps_down= true;
801   wpt->finished  = false;
802   wpt->on_ground = false;
803   waypoints.push_back(wpt);
804 }
805 /*******************************************************************
806  * CreateLanding
807  * initialize the Aircraft at the parking location
808  ******************************************************************/
809 void FGAIFlightPlan::createLanding(FGAirport *apt)
810 {
811   // Ten thousand ft. Slowing down to 150 kts
812   double wind_speed;
813   double wind_heading;
814   double heading;
815   //FGRunway rwy;
816   double lat, lon, az;
817   double lat2, lon2, az2;
818   double azimuth;
819   //int direction;
820   waypoint *wpt;
821
822   
823   heading = rwy._heading;
824   azimuth = heading + 180.0;
825   while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
826
827   //Runway Threshold
828  geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, 
829                      rwy._length*0.45 * SG_FEET_TO_METER,
830                      &lat2, &lon2, &az2 );
831   wpt = new waypoint;
832   wpt->name      = "Threshold"; //wpt_node->getStringValue("name", "END");
833   wpt->latitude  = lat2;
834   wpt->longitude = lon2;
835   wpt->altitude  = apt->getElevation();
836   wpt->speed     = 150; 
837   wpt->crossat   = apt->getElevation();
838   wpt->gear_down = true;
839   wpt->flaps_down= true;
840   wpt->finished  = false;
841   wpt->on_ground = true;
842   waypoints.push_back(wpt); 
843
844  //Full stop at the runway centerpoint
845  geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, 
846                      rwy._length*0.45,
847                       &lat2, &lon2, &az2 );
848   wpt = new waypoint;
849   wpt->name      = "Center"; //wpt_node->getStringValue("name", "END");
850   wpt->latitude  = rwy._lat;
851   wpt->longitude = rwy._lon;
852   wpt->altitude  = apt->getElevation();
853   wpt->speed     = 30; 
854   wpt->crossat   = -10000;
855   wpt->gear_down = true;
856   wpt->flaps_down= true;
857   wpt->finished  = false;
858   wpt->on_ground = true;
859   waypoints.push_back(wpt);
860
861  geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, heading, 
862                      rwy._length*0.45 * SG_FEET_TO_METER,
863                      &lat2, &lon2, &az2 );
864   wpt = new waypoint;
865   wpt->name      = "Threshold"; //wpt_node->getStringValue("name", "END");
866   wpt->latitude  = lat2;
867   wpt->longitude = lon2;
868   wpt->altitude  = apt->getElevation();
869   wpt->speed     = 15; 
870   wpt->crossat   = apt->getElevation();
871   wpt->gear_down = true;
872   wpt->flaps_down= true;
873   wpt->finished  = false;
874   wpt->on_ground = true;
875   waypoints.push_back(wpt); 
876 }
877
878 /*******************************************************************
879  * CreateParking
880  * initialize the Aircraft at the parking location
881  ******************************************************************/
882 void FGAIFlightPlan::createParking(FGAirport *apt, double radius)
883 {
884   waypoint* wpt;
885   double lat, lat2;
886   double lon, lon2;
887   double az2;
888   double heading;
889   apt->getDynamics()->getParking(gateId, &lat, &lon, &heading);
890   heading += 180.0;
891   if (heading > 360)
892     heading -= 360; 
893   geo_direct_wgs_84 ( 0, lat, lon, heading, 
894                       2.2*radius,           
895                       &lat2, &lon2, &az2 );
896   wpt = new waypoint;
897   wpt->name      = "taxiStart";
898   wpt->latitude  = lat2;
899   wpt->longitude = lon2;
900   wpt->altitude  = apt->getElevation();
901   wpt->speed     = 10; 
902   wpt->crossat   = -10000;
903   wpt->gear_down = true;
904   wpt->flaps_down= true;
905   wpt->finished  = false;
906   wpt->on_ground = true;
907   waypoints.push_back(wpt); 
908   geo_direct_wgs_84 ( 0, lat, lon, heading, 
909                       0.1 *radius,           
910                       &lat2, &lon2, &az2 );
911   wpt = new waypoint;
912   wpt->name      = "taxiStart";
913   wpt->latitude  = lat2;
914   wpt->longitude = lon2;
915   wpt->altitude  = apt->getElevation();
916   wpt->speed     = 10; 
917   wpt->crossat   = -10000;
918   wpt->gear_down = true;
919   wpt->flaps_down= true;
920   wpt->finished  = false;
921   wpt->on_ground = true;
922   waypoints.push_back(wpt);   
923
924   wpt = new waypoint;
925   wpt->name      = "END"; //wpt_node->getStringValue("name", "END");
926   wpt->latitude  = lat;
927   wpt->longitude = lon;
928   wpt->altitude  = apt->getElevation();
929   wpt->speed     = 15; 
930   wpt->crossat   = -10000;
931   wpt->gear_down = true;
932   wpt->flaps_down= true;
933   wpt->finished  = false;
934   wpt->on_ground = true;
935   waypoints.push_back(wpt);
936 }