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