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