]> git.mxchange.org Git - flightgear.git/blob - src/AIModel/AIFlightPlanCreate.cxx
Spectacular improvement in traffic manager initialization and preparatory
[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   int nrWaypointsToSkip;
196
197    if (direction == 1)
198     {
199       // If this function is called during initialization,
200       // make sure we obtain a valid gate ID first
201       // and place the model at the location of the gate.
202       if (firstFlight)
203         {
204           if (!(apt->getDynamics()->getAvailableParking(&lat, &lon, 
205                                                         &heading, &gateId, 
206                                                         radius, fltType, 
207                                                         acType, airline)))
208             {
209               SG_LOG(SG_INPUT, SG_WARN, "Could not find parking for a " << 
210                      acType <<
211                      " of flight type " << fltType <<
212                      " of airline     " << airline <<
213                      " at airport     " << apt->getId());
214             }
215           //waypoint *wpt = new waypoint;
216           //wpt->name      = "park";
217           //wpt->latitude  = lat;
218           //wpt->longitude = lon;
219           //wpt->altitude  = apt->getElevation();
220           //wpt->speed     = -10; 
221           //wpt->crossat   = -10000;
222           //wpt->gear_down = true;
223           //wpt->flaps_down= true;
224           //wpt->finished  = false;
225           //wpt->on_ground = true;
226           //waypoints.push_back(wpt);  
227         }
228       // "NOTE: this is currently fixed to "com" for commercial traffic
229       // Should be changed to be used dynamically to allow "gen" and "mil"
230       // as well
231       apt->getDynamics()->getActiveRunway("com", 1, activeRunway);
232       if (!(globals->get_runways()->search(apt->getId(), 
233                                             activeRunway, 
234                                             &rwy)))
235         {
236            SG_LOG(SG_INPUT, SG_ALERT, "Failed to find runway " << 
237                   activeRunway << 
238                   " at airport     " << apt->getId());
239            exit(1);
240         } 
241
242       // Determine the beginning of he runway
243       heading = rwy._heading;
244       double azimuth = heading + 180.0;
245       while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
246       geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, 
247                           rwy._length * SG_FEET_TO_METER * 0.5 - 5.0,
248                           &lat2, &lon2, &az2 );
249
250       if (apt->getDynamics()->getGroundNetwork()->exists())
251         {
252           intVec ids;
253           int runwayId = apt->getDynamics()->getGroundNetwork()->findNearestNode(lat2, 
254                                                                                  lon2);
255
256           
257           // A negative gateId indicates an overflow parking, use a
258           // fallback mechanism for this. 
259           // Starting from gate 0 in this case is a bit of a hack
260           // which requires a more proper solution later on.
261           //FGTaxiRoute route;
262           if (taxiRoute)
263             delete taxiRoute;
264           taxiRoute = new FGTaxiRoute;
265           if (gateId >= 0)
266             *taxiRoute = apt->getDynamics()->getGroundNetwork()->findShortestRoute(gateId, 
267                                                                               runwayId);
268           else
269             *taxiRoute = apt->getDynamics()->getGroundNetwork()->findShortestRoute(0, runwayId);
270           intVecIterator i;
271          
272           if (taxiRoute->empty()) {
273             //Add the runway startpoint;
274             wpt = new waypoint;
275             wpt->name      = "Airport Center";
276             wpt->latitude  = latitude;
277             wpt->longitude = longitude;
278             wpt->altitude  = apt->getElevation();
279             wpt->speed     = 15; 
280             wpt->crossat   = -10000;
281             wpt->gear_down = true;
282             wpt->flaps_down= true;
283             wpt->finished  = false;
284             wpt->on_ground = true;
285             waypoints.push_back(wpt);
286             
287             //Add the runway startpoint;
288             wpt = new waypoint;
289             wpt->name      = "Runway Takeoff";
290             wpt->latitude  = lat2;
291             wpt->longitude = lon2;
292             wpt->altitude  = apt->getElevation();
293             wpt->speed     = 15; 
294             wpt->crossat   = -10000;
295             wpt->gear_down = true;
296             wpt->flaps_down= true;
297             wpt->finished  = false;
298             wpt->on_ground = true;
299             waypoints.push_back(wpt);   
300           } else {
301             int node;
302             taxiRoute->first();
303             bool isPushBackPoint = false;
304             if (firstFlight) {
305               // If this is called during initialization, randomly
306               // skip a number of waypoints to get a more realistic
307               // taxi situation.
308               isPushBackPoint = true;
309               int nrWaypoints = taxiRoute->size();
310               nrWaypointsToSkip = rand() % nrWaypoints;
311               // but make sure we always keep two active waypoints
312               // to prevent a segmentation fault
313               for (int i = 0; i < nrWaypointsToSkip-2; i++) {
314                 isPushBackPoint = false;
315                 taxiRoute->next(&node);
316               }
317             }
318             else {
319               //chop off the first two waypoints, because
320               // those have already been created
321               // by create pushback
322               int size = taxiRoute->size();
323               if (size > 2) {
324                 taxiRoute->next(&node);
325                 taxiRoute->next(&node);
326               }
327             }
328             while(taxiRoute->next(&node))
329               {
330                 //FGTaxiNode *tn = apt->getDynamics()->getGroundNetwork()->findSegment(node)->getEnd();
331                 FGTaxiNode *tn = apt->getDynamics()->getGroundNetwork()->findNode(node);
332                 //ids.pop_back();  
333                 wpt = new waypoint;
334                 wpt->name      = "taxiway"; // fixme: should be the name of the taxiway
335                 wpt->latitude  = tn->getLatitude();
336                 wpt->longitude = tn->getLongitude();
337                 // Elevation is currently disregarded when on_ground is true
338                 // because the AIModel obtains a periodic ground elevation estimate.
339                 wpt->altitude  = apt->getElevation();
340                 if (isPushBackPoint) {
341                   wpt->speed = -10;
342                   isPushBackPoint = false;
343                 }
344                 else {
345                   wpt->speed     = 15; 
346                 }
347                 wpt->crossat   = -10000;
348                 wpt->gear_down = true;
349                 wpt->flaps_down= true;
350                 wpt->finished  = false;
351                 wpt->on_ground = true;
352                 waypoints.push_back(wpt);
353               }
354             //cerr << endl;
355             // finally, rewind the taxiRoute object to the point where we started
356             taxiRoute->first();
357             if (firstFlight) { 
358               for (int i = 0; i < nrWaypointsToSkip-2; i++) {
359                 taxiRoute->next(&node);
360               }
361             } else {
362               int size = taxiRoute->size();
363               if (size > 2) {
364                 taxiRoute->next(&node);
365                 taxiRoute->next(&node);
366               }
367             }
368           }
369         }
370       else 
371         {
372           // This is the fallback mechanism, in case no ground network is available
373           //Add the runway startpoint;
374           wpt = new waypoint;
375           wpt->name      = "Airport Center";
376           wpt->latitude  = apt->getLatitude();
377           wpt->longitude = apt->getLongitude();
378           wpt->altitude  = apt->getElevation();
379           wpt->speed     = 15; 
380           wpt->crossat   = -10000;
381           wpt->gear_down = true;
382           wpt->flaps_down= true;
383           wpt->finished  = false;
384           wpt->on_ground = true;
385           waypoints.push_back(wpt);
386           
387           //Add the runway startpoint;
388           wpt = new waypoint;
389           wpt->name      = "Runway Takeoff";
390           wpt->latitude  = lat2;
391           wpt->longitude = lon2;
392           wpt->altitude  = apt->getElevation();
393           wpt->speed     = 15; 
394           wpt->crossat   = -10000;
395           wpt->gear_down = true;
396           wpt->flaps_down= true;
397           wpt->finished  = false;
398           wpt->on_ground = true;
399           waypoints.push_back(wpt);
400         }
401     }
402   else  // Landing taxi
403     {
404       apt->getDynamics()->getAvailableParking(&lat, &lon, &heading, 
405                                               &gateId, radius, fltType, 
406                                               acType, airline);
407      
408       double lat3 = (*(waypoints.end()-1))->latitude;
409       double lon3 = (*(waypoints.end()-1))->longitude;
410       //cerr << (*(waypoints.end()-1))->name << endl;
411       
412       // Find a route from runway end to parking/gate.
413       if (apt->getDynamics()->getGroundNetwork()->exists())
414         {
415           intVec ids;
416           int runwayId = apt->getDynamics()->getGroundNetwork()->findNearestNode(lat3, 
417                                                                                  lon3);
418           // A negative gateId indicates an overflow parking, use a
419           // fallback mechanism for this. 
420           // Starting from gate 0 is a bit of a hack...
421           //FGTaxiRoute route;
422           if (taxiRoute)
423             delete taxiRoute;
424           taxiRoute = new FGTaxiRoute;
425           if (gateId >= 0)
426             *taxiRoute = apt->getDynamics()->getGroundNetwork()->findShortestRoute(runwayId, 
427                                                                               gateId);
428           else
429             *taxiRoute = apt->getDynamics()->getGroundNetwork()->findShortestRoute(runwayId, 0);
430           intVecIterator i;
431          
432           // No route found: go from gate directly to runway
433           if (taxiRoute->empty()) {
434             //Add the runway startpoint;
435             wpt = new waypoint;
436             wpt->name      = "Airport Center";
437             wpt->latitude  = latitude;
438             wpt->longitude = longitude;
439             wpt->altitude  = apt->getElevation();
440             wpt->speed     = 15; 
441             wpt->crossat   = -10000;
442             wpt->gear_down = true;
443             wpt->flaps_down= true;
444             wpt->finished  = false;
445             wpt->on_ground = true;
446             waypoints.push_back(wpt);
447             
448             //Add the runway startpoint;
449             wpt = new waypoint;
450             wpt->name      = "Runway Takeoff";
451             wpt->latitude  = lat2;
452             wpt->longitude = lon2;
453             wpt->altitude  = apt->getElevation();
454             wpt->speed     = 15; 
455             wpt->crossat   = -10000;
456             wpt->gear_down = true;
457             wpt->flaps_down= true;
458             wpt->finished  = false;
459             wpt->on_ground = true;
460             waypoints.push_back(wpt);   
461           } else {
462             int node;
463             taxiRoute->first();
464             int size = taxiRoute->size();
465             // Omit the last two waypoints, as 
466             // those are created by createParking()
467             for (int i = 0; i < size-2; i++)
468               {
469                 taxiRoute->next(&node);
470                 //FGTaxiNode *tn = apt->getDynamics()->getGroundNetwork()->findNode(node);
471                 FGTaxiNode *tn = apt->getDynamics()->getGroundNetwork()->findNode(node);
472                 wpt = new waypoint;
473                 wpt->name      = "taxiway"; // fixme: should be the name of the taxiway
474                 wpt->latitude  = tn->getLatitude();
475                 wpt->longitude = tn->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           }
486         }
487       else
488         {
489           // Use a fallback mechanism in case no ground network is available
490           // obtain the location of the gate entrance point 
491           heading += 180.0;
492           if (heading > 360)
493             heading -= 360;
494           geo_direct_wgs_84 ( 0, lat, lon, heading, 
495                               100,
496                               &lat2, &lon2, &az2 );
497           wpt = new waypoint;
498           wpt->name      = "Airport Center";
499           wpt->latitude  = apt->getLatitude();
500           wpt->longitude = apt->getLongitude();
501           wpt->altitude  = apt->getElevation();
502           wpt->speed     = 15; 
503           wpt->crossat   = -10000;
504           wpt->gear_down = true;
505           wpt->flaps_down= true;
506           wpt->finished  = false;
507           wpt->on_ground = true;
508           waypoints.push_back(wpt);
509          
510           wpt = new waypoint;
511           wpt->name      = "Begin Parking"; //apt->getId(); //wpt_node->getStringValue("name", "END");
512           wpt->latitude  = lat2;
513           wpt->longitude = lon2;
514           wpt->altitude  = apt->getElevation();
515           wpt->speed     = 15; 
516           wpt->crossat   = -10000;
517           wpt->gear_down = true;
518           wpt->flaps_down= true;
519           wpt->finished  = false;
520           wpt->on_ground = true;
521           waypoints.push_back(wpt); 
522
523           //waypoint* wpt;
524           //double lat;
525           //double lon;
526           //double heading;
527           apt->getDynamics()->getParking(gateId, &lat, &lon, &heading);
528           heading += 180.0;
529           if (heading > 360)
530             heading -= 360; 
531           
532           wpt = new waypoint;
533           wpt->name      = "END"; //wpt_node->getStringValue("name", "END");
534           wpt->latitude  = lat;
535           wpt->longitude = lon;
536           wpt->altitude  = 19;
537           wpt->speed     = 15; 
538           wpt->crossat   = -10000;
539           wpt->gear_down = true;
540           wpt->flaps_down= true;
541           wpt->finished  = false;
542           wpt->on_ground = true;
543           waypoints.push_back(wpt);
544         }
545       
546     }
547 }
548
549 /*******************************************************************
550  * CreateTakeOff 
551  * initialize the Aircraft at the parking location
552  ******************************************************************/
553 void FGAIFlightPlan::createTakeOff(bool firstFlight, FGAirport *apt, double speed)
554 {
555   double wind_speed;
556   double wind_heading;
557   double heading;
558   double lat, lon, az;
559   double lat2, lon2, az2;
560   waypoint *wpt;
561   
562   // Get the current active runway, based on code from David Luff
563   // This should actually be unified and extended to include 
564   // Preferential runway use schema's 
565   if (firstFlight)
566     {
567       //string name;
568        // "NOTE: this is currently fixed to "com" for commercial traffic
569       // Should be changed to be used dynamically to allow "gen" and "mil"
570       // as well
571       apt->getDynamics()->getActiveRunway("com", 1, activeRunway);
572         if (!(globals->get_runways()->search(apt->getId(), 
573                                               activeRunway, 
574                                               &rwy)))
575           {
576             SG_LOG(SG_INPUT, SG_ALERT, "Failed to find runway " << 
577                    activeRunway << 
578                    " at airport     " << apt->getId());
579             exit(1);
580           }
581     }
582   heading = rwy._heading;
583   double azimuth = heading + 180.0;
584   while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
585   geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, 
586                       rwy._length * SG_FEET_TO_METER * 0.5 - 105.0,
587                       &lat2, &lon2, &az2 );
588   wpt = new waypoint; 
589   wpt->name      = "accel"; 
590   wpt->latitude  = lat2; 
591   wpt->longitude = lon2; 
592   wpt->altitude  = apt->getElevation();
593   wpt->speed     = speed;  
594   wpt->crossat   = -10000;
595   wpt->gear_down = true;
596   wpt->flaps_down= true;
597   wpt->finished  = false;
598   wpt->on_ground = true;
599   waypoints.push_back(wpt); 
600   
601   lat = lat2;
602   lon = lon2;
603   az  = az2;
604   
605   //Next: the Start of Climb
606   geo_direct_wgs_84 ( 0, lat, lon, heading, 
607   2560 * SG_FEET_TO_METER,
608   &lat2, &lon2, &az2 );
609   
610   wpt = new waypoint;
611   wpt->name      = "SOC";
612   wpt->latitude  = lat2;
613   wpt->longitude = lon2;
614   wpt->altitude  = apt->getElevation()+3000;
615   wpt->speed     = speed; 
616   wpt->crossat   = -10000;
617   wpt->gear_down = true;
618   wpt->flaps_down= true;
619   wpt->finished  = false;
620   wpt->on_ground = false;
621   waypoints.push_back(wpt);
622 }
623  
624 /*******************************************************************
625  * CreateClimb
626  * initialize the Aircraft at the parking location
627  ******************************************************************/
628 void FGAIFlightPlan::createClimb(bool firstFlight, FGAirport *apt, double speed, double alt)
629 {
630   double wind_speed;
631   double wind_heading;
632   double heading;
633   //FGRunway rwy;
634   double lat, lon, az;
635   double lat2, lon2, az2;
636   //int direction;
637   waypoint *wpt;
638
639  
640   if (firstFlight)
641     {
642       //string name;
643       // "NOTE: this is currently fixed to "com" for commercial traffic
644       // Should be changed to be used dynamically to allow "gen" and "mil"
645       // as well
646       apt->getDynamics()->getActiveRunway("com", 1, activeRunway);
647         if (!(globals->get_runways()->search(apt->getId(), 
648                                               activeRunway, 
649                                               &rwy)))
650           {
651             SG_LOG(SG_INPUT, SG_ALERT, "Failed to find runway " << 
652                    activeRunway << 
653                    " at airport     " << apt->getId());
654             exit(1);
655           }
656     }
657   
658   
659   heading = rwy._heading;
660   double azimuth = heading + 180.0;
661   while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
662   //cerr << "Creating climb at : " << rwy._id << " " << rwy._rwy_no << endl;
663   geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, heading, 
664                       10*SG_NM_TO_METER,
665                       &lat2, &lon2, &az2 );
666   wpt = new waypoint;
667   wpt->name      = "10000ft climb";
668   wpt->latitude  = lat2;
669   wpt->longitude = lon2;
670   wpt->altitude  = 10000;
671   wpt->speed     = speed; 
672   wpt->crossat   = -10000;
673   wpt->gear_down = true;
674   wpt->flaps_down= true;
675   wpt->finished  = false;
676   wpt->on_ground = false;
677   waypoints.push_back(wpt); 
678   
679
680   geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, heading, 
681                       20*SG_NM_TO_METER,
682                       &lat2, &lon2, &az2 );
683   wpt = new waypoint;
684   wpt->name      = "18000ft climb";
685   wpt->latitude  = lat2;
686   wpt->longitude = lon2;
687   wpt->altitude  = 18000;
688   wpt->speed     = speed; 
689   wpt->crossat   = -10000;
690   wpt->gear_down = true;
691   wpt->flaps_down= true;
692   wpt->finished  = false;
693   wpt->on_ground = false;
694   waypoints.push_back(wpt); 
695 }
696
697
698 // /*******************************************************************
699 //  * CreateCruise
700 //  * initialize the Aircraft at the parking location
701 //  ******************************************************************/
702 // void FGAIFlightPlan::createCruise(bool firstFlight, FGAirport *dep, 
703 //                                FGAirport *arr, double latitude, 
704 //                                double longitude, double speed, 
705 //                                double alt)
706 // {
707 //   double wind_speed;
708 //   double wind_heading;
709 //   double heading;
710 //   double lat, lon, az;
711 //   double lat2, lon2, az2;
712 //   double azimuth;
713 //   waypoint *wpt;
714
715 //   wpt = new waypoint;
716 //   wpt->name      = "Cruise"; //wpt_node->getStringValue("name", "END");
717 //   wpt->latitude  = latitude;
718 //   wpt->longitude = longitude;
719 //   wpt->altitude  = alt;
720 //   wpt->speed     = speed; 
721 //   wpt->crossat   = -10000;
722 //   wpt->gear_down = false;
723 //   wpt->flaps_down= false;
724 //   wpt->finished  = false;
725 //   wpt->on_ground = false;
726 //   waypoints.push_back(wpt); 
727   
728  
729 //   // should be changed dynamically to allow "gen" and "mil"
730 //   arr->getDynamics()->getActiveRunway("com", 2, activeRunway);
731 //   if (!(globals->get_runways()->search(arr->getId(), 
732 //                                     activeRunway, 
733 //                                     &rwy)))
734 //     {
735 //       SG_LOG(SG_INPUT, SG_ALERT, "Failed to find runway " << 
736 //           activeRunway << 
737 //           " at airport     " << arr->getId());
738 //       exit(1);
739 //     }
740 //   heading = rwy._heading;
741 //   azimuth = heading + 180.0;
742 //   while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
743   
744   
745 //   geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, 
746 //                    110000,
747 //                    &lat2, &lon2, &az2 );
748 //   wpt = new waypoint;
749 //   wpt->name      = "BOD";
750 //   wpt->latitude  = lat2;
751 //   wpt->longitude = lon2;
752 //   wpt->altitude  = alt;
753 //   wpt->speed     = speed; 
754 //   wpt->crossat   = alt;
755 //   wpt->gear_down = false;
756 //   wpt->flaps_down= false;
757 //   wpt->finished  = false;
758 //   wpt->on_ground = false;
759 //   waypoints.push_back(wpt); 
760 // }
761
762 /*******************************************************************
763  * CreateDecent
764  * initialize the Aircraft at the parking location
765  ******************************************************************/
766 void FGAIFlightPlan::createDecent(FGAirport *apt)
767 {
768
769   // Ten thousand ft. Slowing down to 240 kts
770   double wind_speed;
771   double wind_heading;
772   double heading;
773   //FGRunway rwy;
774   double lat, lon, az;
775   double lat2, lon2, az2;
776   double azimuth;
777   //int direction;
778   waypoint *wpt;
779
780   //Beginning of Decent
781   //string name;
782   // allow "mil" and "gen" as well
783   apt->getDynamics()->getActiveRunway("com", 2, activeRunway);
784   if (!(globals->get_runways()->search(apt->getId(), 
785                                        activeRunway, 
786                                        &rwy)))
787     {
788       SG_LOG(SG_INPUT, SG_ALERT, "Failed to find runway " << 
789              activeRunway << 
790              " at airport     " << apt->getId());
791       exit(1);
792     }
793   
794   heading = rwy._heading;
795   azimuth = heading + 180.0;
796   while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
797   geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, 
798                       100000,
799                       &lat2, &lon2, &az2 );
800   
801   wpt = new waypoint;
802   wpt->name      = "Dec 10000ft"; //wpt_node->getStringValue("name", "END");
803   wpt->latitude  = lat2;
804   wpt->longitude = lon2;
805   wpt->altitude  = apt->getElevation();
806   wpt->speed     = 240; 
807   wpt->crossat   = 10000;
808   wpt->gear_down = false;
809   wpt->flaps_down= false;
810   wpt->finished  = false;
811   wpt->on_ground = false;
812   waypoints.push_back(wpt);  
813   
814   // Three thousand ft. Slowing down to 160 kts
815   geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, 
816                       8*SG_NM_TO_METER,
817                       &lat2, &lon2, &az2 );
818   wpt = new waypoint;
819   wpt->name      = "DEC 3000ft"; //wpt_node->getStringValue("name", "END");
820   wpt->latitude  = lat2;
821   wpt->longitude = lon2;
822   wpt->altitude  = apt->getElevation();
823   wpt->speed     = 160; 
824   wpt->crossat   = 3000;
825   wpt->gear_down = true;
826   wpt->flaps_down= true;
827   wpt->finished  = false;
828   wpt->on_ground = false;
829   waypoints.push_back(wpt);
830 }
831 /*******************************************************************
832  * CreateLanding
833  * initialize the Aircraft at the parking location
834  ******************************************************************/
835 void FGAIFlightPlan::createLanding(FGAirport *apt)
836 {
837   // Ten thousand ft. Slowing down to 150 kts
838   double wind_speed;
839   double wind_heading;
840   double heading;
841   //FGRunway rwy;
842   double lat, lon, az;
843   double lat2, lon2, az2;
844   double azimuth;
845   //int direction;
846   waypoint *wpt;
847
848   
849   heading = rwy._heading;
850   azimuth = heading + 180.0;
851   while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
852
853   //Runway Threshold
854  geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, 
855                      rwy._length*0.45 * SG_FEET_TO_METER,
856                      &lat2, &lon2, &az2 );
857   wpt = new waypoint;
858   wpt->name      = "Threshold"; //wpt_node->getStringValue("name", "END");
859   wpt->latitude  = lat2;
860   wpt->longitude = lon2;
861   wpt->altitude  = apt->getElevation();
862   wpt->speed     = 150; 
863   wpt->crossat   = apt->getElevation();
864   wpt->gear_down = true;
865   wpt->flaps_down= true;
866   wpt->finished  = false;
867   wpt->on_ground = true;
868   waypoints.push_back(wpt); 
869
870  //Full stop at the runway centerpoint
871  geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth, 
872                      rwy._length*0.45,
873                       &lat2, &lon2, &az2 );
874   wpt = new waypoint;
875   wpt->name      = "Center"; //wpt_node->getStringValue("name", "END");
876   wpt->latitude  = rwy._lat;
877   wpt->longitude = rwy._lon;
878   wpt->altitude  = apt->getElevation();
879   wpt->speed     = 30; 
880   wpt->crossat   = -10000;
881   wpt->gear_down = true;
882   wpt->flaps_down= true;
883   wpt->finished  = false;
884   wpt->on_ground = true;
885   waypoints.push_back(wpt);
886
887  geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, heading, 
888                      rwy._length*0.45 * SG_FEET_TO_METER,
889                      &lat2, &lon2, &az2 );
890   wpt = new waypoint;
891   wpt->name      = "Threshold"; //wpt_node->getStringValue("name", "END");
892   wpt->latitude  = lat2;
893   wpt->longitude = lon2;
894   wpt->altitude  = apt->getElevation();
895   wpt->speed     = 15; 
896   wpt->crossat   = apt->getElevation();
897   wpt->gear_down = true;
898   wpt->flaps_down= true;
899   wpt->finished  = false;
900   wpt->on_ground = true;
901   waypoints.push_back(wpt); 
902 }
903
904 /*******************************************************************
905  * CreateParking
906  * initialize the Aircraft at the parking location
907  ******************************************************************/
908 void FGAIFlightPlan::createParking(FGAirport *apt, double radius)
909 {
910   waypoint* wpt;
911   double lat, lat2;
912   double lon, lon2;
913   double az2;
914   double heading;
915   apt->getDynamics()->getParking(gateId, &lat, &lon, &heading);
916   heading += 180.0;
917   if (heading > 360)
918     heading -= 360; 
919   geo_direct_wgs_84 ( 0, lat, lon, heading, 
920                       2.2*radius,           
921                       &lat2, &lon2, &az2 );
922   wpt = new waypoint;
923   wpt->name      = "taxiStart";
924   wpt->latitude  = lat2;
925   wpt->longitude = lon2;
926   wpt->altitude  = apt->getElevation();
927   wpt->speed     = 10; 
928   wpt->crossat   = -10000;
929   wpt->gear_down = true;
930   wpt->flaps_down= true;
931   wpt->finished  = false;
932   wpt->on_ground = true;
933   waypoints.push_back(wpt); 
934   geo_direct_wgs_84 ( 0, lat, lon, heading, 
935                       0.1 *radius,           
936                       &lat2, &lon2, &az2 );
937   wpt = new waypoint;
938   wpt->name      = "taxiStart";
939   wpt->latitude  = lat2;
940   wpt->longitude = lon2;
941   wpt->altitude  = apt->getElevation();
942   wpt->speed     = 10; 
943   wpt->crossat   = -10000;
944   wpt->gear_down = true;
945   wpt->flaps_down= true;
946   wpt->finished  = false;
947   wpt->on_ground = true;
948   waypoints.push_back(wpt);   
949
950   wpt = new waypoint;
951   wpt->name      = "END"; //wpt_node->getStringValue("name", "END");
952   wpt->latitude  = lat;
953   wpt->longitude = lon;
954   wpt->altitude  = apt->getElevation();
955   wpt->speed     = 15; 
956   wpt->crossat   = -10000;
957   wpt->gear_down = true;
958   wpt->flaps_down= true;
959   wpt->finished  = false;
960   wpt->on_ground = true;
961   waypoints.push_back(wpt);
962 }