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