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