]> git.mxchange.org Git - flightgear.git/blob - src/AIModel/AIFlightPlanCreate.cxx
Merge branch 'maint2' into next
[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
21 #ifdef HAVE_CONFIG_H
22 #  include <config.h>
23 #endif
24
25 #include "AIFlightPlan.hxx"
26 #include <simgear/math/sg_geodesy.hxx>
27 #include <Airports/runways.hxx>
28 #include <Airports/dynamics.hxx>
29
30 #include <Environment/environment_mgr.hxx>
31 #include <Environment/environment.hxx>
32
33
34 /* FGAIFlightPlan::create()
35  * dynamically create a flight plan for AI traffic, based on data provided by the
36  * Traffic Manager, when reading a filed flightplan failes. (DT, 2004/07/10) 
37  *
38  * This is the top-level function, and the only one that is publicly available.
39  *
40  */ 
41
42
43 // Check lat/lon values during initialization;
44 void FGAIFlightPlan::create(FGAirport *dep, FGAirport *arr, int legNr, 
45                             double alt, double speed, double latitude, 
46                             double longitude, bool firstFlight,double radius, 
47                             const string& fltType, const string& aircraftType, 
48                             const string& airline)
49
50   int currWpt = wpt_iterator - waypoints.begin();
51   switch(legNr)
52     {
53       case 1:
54       createPushBack(firstFlight,dep, latitude, longitude, 
55                      radius, fltType, aircraftType, airline);
56       break;
57     case 2: 
58       createTaxi(firstFlight, 1, dep, latitude, longitude, 
59                  radius, fltType, aircraftType, airline);
60       break;
61     case 3: 
62       createTakeOff(firstFlight, dep, speed, fltType);
63       break;
64     case 4: 
65       createClimb(firstFlight, dep, speed, alt, fltType);
66       break;
67     case 5: 
68       createCruise(firstFlight, dep,arr, latitude, longitude, speed, alt, fltType);
69       break;
70     case 6: 
71       createDecent(arr, fltType);
72       break;
73     case 7: 
74       createLanding(arr);
75       break;
76     case 8: 
77       createTaxi(false, 2, arr, latitude, longitude, radius, 
78                  fltType, aircraftType, airline);
79       break;
80       case 9: 
81         createParking(arr, radius);
82       break;
83     default:
84       //exit(1);
85       SG_LOG(SG_INPUT, SG_ALERT, "AIFlightPlan::create() attempting to create unknown leg"
86              " this is probably an internal program error");
87     }
88   wpt_iterator = waypoints.begin()+currWpt;
89   leg++;
90 }
91
92
93
94
95
96
97 /*******************************************************************
98  * createCreate Taxi. 
99  * initialize the Aircraft at the parking location
100  ******************************************************************/
101 void FGAIFlightPlan::createTaxi(bool firstFlight, int direction, 
102                                 FGAirport *apt, double latitude, double longitude, 
103                                 double radius, const string& fltType, 
104                                 const string& acType, const string& airline)
105 {
106   double heading;
107   double lat, lon;
108   double lat2, lon2, az2;
109   waypoint *wpt;
110
111   int nrWaypointsToSkip;
112
113    if (direction == 1)
114     {
115       // If this function is called during initialization,
116       // make sure we obtain a valid gate ID first
117       // and place the model at the location of the gate.
118       if (firstFlight)
119         {
120           if (!(apt->getDynamics()->getAvailableParking(&lat, &lon, 
121                                                         &heading, &gateId, 
122                                                         radius, fltType, 
123                                                         acType, airline)))
124             {
125               SG_LOG(SG_INPUT, SG_WARN, "Could not find parking for a " << 
126                      acType <<
127                      " of flight type " << fltType <<
128                      " of airline     " << airline <<
129                      " at airport     " << apt->getId());
130             }
131           //waypoint *wpt = new waypoint;
132           //wpt->name      = "park";
133           //wpt->latitude  = lat;
134           //wpt->longitude = lon;
135           //wpt->altitude  = apt->getElevation();
136           //wpt->speed     = -10; 
137           //wpt->crossat   = -10000;
138           //wpt->gear_down = true;
139           //wpt->flaps_down= true;
140           //wpt->finished  = false;
141           //wpt->on_ground = true;
142           //waypoints.push_back(wpt);  
143         }
144       string rwyClass = getRunwayClassFromTrafficType(fltType);
145       apt->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway);
146       rwy = apt->getRunwayByIdent(activeRunway);
147       
148       // Determine the beginning of he runway
149       heading = rwy->headingDeg();
150       double azimuth = heading + 180.0;
151       while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
152       geo_direct_wgs_84 ( 0, rwy->latitude(), rwy->longitude(), azimuth, 
153                           rwy->lengthM() * 0.5 - 5.0,
154                           &lat2, &lon2, &az2 );
155
156       if (apt->getDynamics()->getGroundNetwork()->exists())
157         {
158           intVec ids;
159           int runwayId = apt->getDynamics()->getGroundNetwork()->findNearestNode(lat2, 
160                                                                                  lon2);
161
162           
163           // A negative gateId indicates an overflow parking, use a
164           // fallback mechanism for this. 
165           // Starting from gate 0 in this case is a bit of a hack
166           // which requires a more proper solution later on.
167           //FGTaxiRoute route;
168           delete taxiRoute;
169           taxiRoute = new FGTaxiRoute;
170
171           // Determine which node to start from.
172           int node;
173           // Find out which node to start from
174           FGParking *park = apt->getDynamics()->getParking(gateId);
175           if (park)
176                 node = park->getPushBackPoint();
177           else
178                 node = 0;
179           if (node == -1)
180              node = gateId;
181
182           // HAndle case where parking doens't have a node
183           if ((node == 0) && park) {
184                 if (firstFlight) {
185                     node = gateId;
186                 } else {
187                     node = lastNodeVisited;
188                 }
189           }
190
191           //cerr << "Using node " << node << endl;
192             *taxiRoute = apt->getDynamics()->getGroundNetwork()->findShortestRoute(node, runwayId);
193           intVecIterator i;
194          
195           if (taxiRoute->empty()) {
196             //Add the runway startpoint;
197             wpt = new waypoint;
198             wpt->name      = "Airport Center";
199             wpt->latitude  = latitude;
200             wpt->longitude = longitude;
201             wpt->altitude  = apt->getElevation();
202             wpt->speed     = 15; 
203             wpt->crossat   = -10000;
204             wpt->gear_down = true;
205             wpt->flaps_down= true;
206             wpt->finished  = false;
207             wpt->on_ground = true;
208             wpt->routeIndex = 0;
209             waypoints.push_back(wpt);
210             
211             //Add the runway startpoint;
212             wpt = new waypoint;
213             wpt->name      = "Runway Takeoff";
214             wpt->latitude  = lat2;
215             wpt->longitude = lon2;
216             wpt->altitude  = apt->getElevation();
217             wpt->speed     = 15; 
218             wpt->crossat   = -10000;
219             wpt->gear_down = true;
220             wpt->flaps_down= true;
221             wpt->finished  = false;
222             wpt->on_ground = true;
223             wpt->routeIndex = 0;
224             waypoints.push_back(wpt);   
225           } else {
226             int node;
227             taxiRoute->first();
228             //bool isPushBackPoint = false;
229             if (firstFlight) {
230
231               // If this is called during initialization, randomly
232               // skip a number of waypoints to get a more realistic
233               // taxi situation.
234               //isPushBackPoint = true;
235               int nrWaypoints = taxiRoute->size();
236               nrWaypointsToSkip = rand() % nrWaypoints;
237               // but make sure we always keep two active waypoints
238               // to prevent a segmentation fault
239               for (int i = 0; i < nrWaypointsToSkip-2; i++) {
240                 //isPushBackPoint = false;
241                 taxiRoute->next(&node);
242               }
243               apt->getDynamics()->releaseParking(gateId);
244             } else {
245                if (taxiRoute->size() > 1) {
246                    taxiRoute->next(&node); // chop off the first waypoint, because that is already the last of the pushback route
247                }
248             }
249             int route;
250             while(taxiRoute->next(&node, &route))
251               {
252                 //FGTaxiNode *tn = apt->getDynamics()->getGroundNetwork()->findSegment(node)->getEnd();
253                 char buffer[10];
254                 snprintf (buffer, 10, "%d", node);
255                 FGTaxiNode *tn = apt->getDynamics()->getGroundNetwork()->findNode(node);
256                 //ids.pop_back();  
257                 wpt = new waypoint;
258                 wpt->name      = string(buffer); // fixme: should be the name of the taxiway
259                 wpt->latitude  = tn->getLatitude();
260                 wpt->longitude = tn->getLongitude();
261                 // Elevation is currently disregarded when on_ground is true
262                 // because the AIModel obtains a periodic ground elevation estimate.
263                 wpt->altitude  = apt->getElevation();
264                 wpt->speed     = 15; 
265                 wpt->crossat   = -10000;
266                 wpt->gear_down = true;
267                 wpt->flaps_down= true;
268                 wpt->finished  = false;
269                 wpt->on_ground = true;
270                 wpt->routeIndex = route;
271                 waypoints.push_back(wpt);
272               }
273              /*
274             //cerr << endl;
275             // finally, rewind the taxiRoute object to the point where we started
276             // generating the Flightplan, for AI use.
277             // This is a bit tricky, because the 
278             taxiRoute->first();
279             if (firstFlight) { 
280               for (int i = 0; i < nrWaypointsToSkip-1; i++) {
281                 taxiRoute->next(&node);
282               }
283             } else {
284               int size = taxiRoute->size();
285               if (size > 2) {
286                 //taxiRoute->next(&node);
287                 //taxiRoute->next(&node);       
288                 //taxiRoute->next(&node);
289               }
290             }*/
291           } // taxiRoute not empty
292         }
293       else 
294         {
295           // This is the fallback mechanism, in case no ground network is available
296           //Add the runway startpoint;
297           wpt = new waypoint;
298           wpt->name      = "Airport Center";
299           wpt->latitude  = apt->getLatitude();
300           wpt->longitude = apt->getLongitude();
301           wpt->altitude  = apt->getElevation();
302           wpt->speed     = 15; 
303           wpt->crossat   = -10000;
304           wpt->gear_down = true;
305           wpt->flaps_down= true;
306           wpt->finished  = false;
307           wpt->on_ground = true;
308           wpt->routeIndex = 0;
309           waypoints.push_back(wpt);
310           
311           //Add the runway startpoint;
312           wpt = new waypoint;
313           wpt->name      = "Runway Takeoff";
314           wpt->latitude  = lat2;
315           wpt->longitude = lon2;
316           wpt->altitude  = apt->getElevation();
317           wpt->speed     = 15; 
318           wpt->crossat   = -10000;
319           wpt->gear_down = true;
320           wpt->flaps_down= true;
321           wpt->finished  = false;
322           wpt->on_ground = true;
323           wpt->routeIndex = 0;
324           waypoints.push_back(wpt);
325         }
326     }
327   else  // Landing taxi
328     {
329       apt->getDynamics()->getAvailableParking(&lat, &lon, &heading, 
330                                               &gateId, radius, fltType, 
331                                               acType, airline);
332      
333       double lat3 = (*(waypoints.end()-1))->latitude;
334       double lon3 = (*(waypoints.end()-1))->longitude;
335       //cerr << (*(waypoints.end()-1))->name << endl;
336       
337       // Find a route from runway end to parking/gate.
338       if (apt->getDynamics()->getGroundNetwork()->exists())
339         {
340           intVec ids;
341           int runwayId = apt->getDynamics()->getGroundNetwork()->findNearestNode(lat3, 
342                                                                                  lon3);
343           // A negative gateId indicates an overflow parking, use a
344           // fallback mechanism for this. 
345           // Starting from gate 0 is a bit of a hack...
346           //FGTaxiRoute route;
347           delete taxiRoute;
348           taxiRoute = new FGTaxiRoute;
349           if (gateId >= 0)
350             *taxiRoute = apt->getDynamics()->getGroundNetwork()->findShortestRoute(runwayId, 
351                                                                               gateId);
352           else
353             *taxiRoute = apt->getDynamics()->getGroundNetwork()->findShortestRoute(runwayId, 0);
354           intVecIterator i;
355          
356           // No route found: go from gate directly to runway
357           if (taxiRoute->empty()) {
358             //Add the runway startpoint;
359             wpt = new waypoint;
360             wpt->name      = "Airport Center";
361             wpt->latitude  = latitude;
362             wpt->longitude = longitude;
363             wpt->altitude  = apt->getElevation();
364             wpt->speed     = 15; 
365             wpt->crossat   = -10000;
366             wpt->gear_down = true;
367             wpt->flaps_down= true;
368             wpt->finished  = false;
369             wpt->on_ground = true;
370             wpt->routeIndex = 0;
371             waypoints.push_back(wpt);
372             
373             //Add the runway startpoint;
374             wpt = new waypoint;
375             wpt->name      = "Runway Takeoff";
376             wpt->latitude  = lat3;
377             wpt->longitude = lon3;
378             wpt->altitude  = apt->getElevation();
379             wpt->speed     = 15; 
380             wpt->crossat   = -10000;
381             wpt->gear_down = true;
382             wpt->flaps_down= true;
383             wpt->finished  = false;
384             wpt->on_ground = true;
385             wpt->routeIndex = 0;
386             waypoints.push_back(wpt);   
387           } else {
388             int node;
389             taxiRoute->first();
390             int size = taxiRoute->size();
391             // Omit the last two waypoints, as 
392             // those are created by createParking()
393             int route;
394             for (int i = 0; i < size-2; i++)
395               {
396                 taxiRoute->next(&node, &route);
397                 char buffer[10];
398                 snprintf (buffer, 10, "%d", node);
399                 //FGTaxiNode *tn = apt->getDynamics()->getGroundNetwork()->findNode(node);
400                 FGTaxiNode *tn = apt->getDynamics()->getGroundNetwork()->findNode(node);
401                 wpt = new waypoint;
402                 //wpt->name      = "taxiway"; // fixme: should be the name of the taxiway
403                 wpt->name      = string(buffer);// fixme: should be the name of the taxiway
404                 wpt->latitude  = tn->getLatitude();
405                 wpt->longitude = tn->getLongitude();
406                 wpt->altitude  = apt->getElevation();
407                 wpt->speed     = 15; 
408                 wpt->crossat   = -10000;
409                 wpt->gear_down = true;
410                 wpt->flaps_down= true;
411                 wpt->finished  = false;
412                 wpt->on_ground = true;
413                 wpt->routeIndex = route;
414                 waypoints.push_back(wpt);
415               }
416             //taxiRoute->first();
417             //taxiRoute->next(&node);
418           }
419         }
420       else
421         {
422           // Use a fallback mechanism in case no ground network is available
423           // obtain the location of the gate entrance point 
424           heading += 180.0;
425           if (heading > 360)
426             heading -= 360;
427           geo_direct_wgs_84 ( 0, lat, lon, heading, 
428                               100,
429                               &lat2, &lon2, &az2 );
430           wpt = new waypoint;
431           wpt->name      = "Airport Center";
432           wpt->latitude  = apt->getLatitude();
433           wpt->longitude = apt->getLongitude();
434           wpt->altitude  = apt->getElevation();
435           wpt->speed     = 15; 
436           wpt->crossat   = -10000;
437           wpt->gear_down = true;
438           wpt->flaps_down= true;
439           wpt->finished  = false;
440           wpt->on_ground = true;
441           wpt->routeIndex = 0;
442           waypoints.push_back(wpt);
443          
444           wpt = new waypoint;
445           wpt->name      = "Begin Parking"; //apt->getId(); //wpt_node->getStringValue("name", "END");
446           wpt->latitude  = lat2;
447           wpt->longitude = lon2;
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           //waypoint* wpt;
459           //double lat;
460           //double lon;
461           //double heading;
462           apt->getDynamics()->getParking(gateId, &lat, &lon, &heading);
463           heading += 180.0;
464           if (heading > 360)
465             heading -= 360; 
466           
467           wpt = new waypoint;
468           wpt->name      = "END"; //wpt_node->getStringValue("name", "END");
469           wpt->latitude  = lat;
470           wpt->longitude = lon;
471           wpt->altitude  = 19;
472           wpt->speed     = 15; 
473           wpt->crossat   = -10000;
474           wpt->gear_down = true;
475           wpt->flaps_down= true;
476           wpt->finished  = false;
477           wpt->on_ground = true;
478           wpt->routeIndex = 0;
479           waypoints.push_back(wpt);
480         }
481       
482     }
483 }
484
485 /*******************************************************************
486  * CreateTakeOff 
487  * initialize the Aircraft at the parking location
488  ******************************************************************/
489 void FGAIFlightPlan::createTakeOff(bool firstFlight, FGAirport *apt, double speed, const string &fltType)
490 {
491   double heading;
492   double lat, lon, az;
493   double lat2, lon2, az2;
494   waypoint *wpt;
495   
496   // Get the current active runway, based on code from David Luff
497   // This should actually be unified and extended to include 
498   // Preferential runway use schema's 
499   if (firstFlight)
500     {
501       //string name;
502       string rwyClass = getRunwayClassFromTrafficType(fltType);
503       apt->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway);
504       rwy = apt->getRunwayByIdent(activeRunway);
505     }
506   // Acceleration point, 105 meters into the runway,
507   heading = rwy->headingDeg();
508   double azimuth = heading + 180.0;
509   while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
510   geo_direct_wgs_84 ( 0, rwy->latitude(), rwy->longitude(), azimuth, 
511                       rwy->lengthM() * 0.5 - 105.0,
512                       &lat2, &lon2, &az2 );
513   wpt = new waypoint; 
514   wpt->name      = "accel"; 
515   wpt->latitude  = lat2; 
516   wpt->longitude = lon2; 
517   wpt->altitude  = apt->getElevation();
518   wpt->speed     = speed;  
519   wpt->crossat   = -10000;
520   wpt->gear_down = true;
521   wpt->flaps_down= true;
522   wpt->finished  = false;
523   wpt->on_ground = true;
524   wpt->routeIndex = 0;
525   waypoints.push_back(wpt); 
526   
527   lat = lat2;
528   lon = lon2;
529   az  = az2;
530   
531   //Start Climbing to 3000 ft. Let's do this 
532   // at the center of the runway for now:
533   // 
534   geo_direct_wgs_84 ( 0, lat, lon, heading, 
535   2560 * SG_FEET_TO_METER,
536   &lat2, &lon2, &az2 );
537   
538   wpt = new waypoint;
539   wpt->name      = "SOC";
540   wpt->latitude  = rwy->latitude();
541   wpt->longitude = rwy->longitude();
542   wpt->altitude  = apt->getElevation()+1000;
543   wpt->speed     = speed; 
544   wpt->crossat   = -10000;
545   wpt->gear_down = true;
546   wpt->flaps_down= true;
547   wpt->finished  = false;
548   wpt->on_ground = false;
549   wpt->routeIndex = 0;
550   waypoints.push_back(wpt);
551
552
553  geo_direct_wgs_84 ( 0, rwy->latitude(), rwy->longitude(), heading, 
554   rwy->lengthM(),
555   &lat2, &lon2, &az2 );
556
557   wpt = new waypoint;
558   wpt->name      = "3000 ft";
559   wpt->latitude  = lat2;
560   wpt->longitude = lon2;
561   wpt->altitude  = apt->getElevation()+3000;
562   wpt->speed     = speed; 
563   wpt->crossat   = -10000;
564   wpt->gear_down = true;
565   wpt->flaps_down= true;
566   wpt->finished  = false;
567   wpt->on_ground = false;
568   wpt->routeIndex = 0;
569   waypoints.push_back(wpt);
570
571 // Finally, add two more waypoints, so that aircraft will remain under
572   // Tower control until they have reached the 3000 ft climb point
573
574
575  geo_direct_wgs_84 ( 0, rwy->latitude(), rwy->longitude(), heading, 
576   5000,
577   &lat2, &lon2, &az2 );
578
579
580   wpt = new waypoint;
581   wpt->name      = "5000 ft";
582   wpt->latitude  = lat2;
583   wpt->longitude = lon2;
584   wpt->altitude  = apt->getElevation()+5000;
585   wpt->speed     = speed;
586   wpt->crossat   = -10000;
587   wpt->gear_down = true;
588   wpt->flaps_down= true;
589   wpt->finished  = false;
590   wpt->on_ground = false;
591   wpt->routeIndex = 0;
592   waypoints.push_back(wpt);  
593   //cerr << "Created takeoff plan : " << endl;
594   //for (wpt_vector_iterator i = waypoints.begin(); i != waypoints.end(); i++) {
595   //     cerr << "Waypoint Name: " << (*i)->name << ". Speed = " << (*i)->speed << endl;
596   //}
597
598
599  //  geo_direct_wgs_84 ( 0, rwy->latitude(), rwy->longitude(), heading, 
600 //   100000,
601 //   &lat2, &lon2, &az2 );
602 //   wpt = new waypoint;
603 //   wpt->name      = "5100 ft";
604 //   wpt->latitude  = lat2;
605 //   wpt->longitude = lon2;
606 //   wpt->altitude  = apt->getElevation()+5100;
607 //   wpt->speed     = speed; 
608 //   wpt->crossat   = -10000;
609 //   wpt->gear_down = true;
610 //   wpt->flaps_down= true;
611 //   wpt->finished  = false;
612 //   wpt->on_ground = false;
613 //   wpt->routeIndex = 0;
614 //   waypoints.push_back(wpt);
615 }
616  
617 /*******************************************************************
618  * CreateClimb
619  * initialize the Aircraft at the parking location
620  ******************************************************************/
621 void FGAIFlightPlan::createClimb(bool firstFlight, FGAirport *apt, double speed, double alt, const string &fltType)
622 {
623   double heading;
624   //FGRunway rwy;
625   double lat2, lon2, az2;
626   //int direction;
627   waypoint *wpt;
628
629  
630   if (firstFlight)
631     {
632       //string name;
633       string rwyClass = getRunwayClassFromTrafficType(fltType);
634       apt->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway);
635       rwy = apt->getRunwayByIdent(activeRunway);
636     }
637   
638   
639   heading = rwy->headingDeg();
640   double azimuth = heading + 180.0;
641   while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
642   //cerr << "Creating climb at : " << rwy._id << " " << rwy._rwy_no << endl;
643   geo_direct_wgs_84 ( 0, rwy->latitude(), rwy->longitude(), heading, 
644                       10*SG_NM_TO_METER,
645                       &lat2, &lon2, &az2 );
646   wpt = new waypoint;
647   wpt->name      = "10000ft climb";
648   wpt->latitude  = lat2;
649   wpt->longitude = lon2;
650   wpt->altitude  = 10000;
651   wpt->speed     = speed; 
652   wpt->crossat   = -10000;
653   wpt->gear_down = true;
654   wpt->flaps_down= true;
655   wpt->finished  = false;
656   wpt->on_ground = false;
657   wpt->routeIndex = 0;
658   waypoints.push_back(wpt); 
659   
660
661   geo_direct_wgs_84 ( 0, rwy->latitude(), rwy->longitude(), heading, 
662                       20*SG_NM_TO_METER,
663                       &lat2, &lon2, &az2 );
664   wpt = new waypoint;
665   wpt->name      = "18000ft climb";
666   wpt->latitude  = lat2;
667   wpt->longitude = lon2;
668   wpt->altitude  = 18000;
669   wpt->speed     = speed; 
670   wpt->crossat   = -10000;
671   wpt->gear_down = true;
672   wpt->flaps_down= true;
673   wpt->finished  = false;
674   wpt->on_ground = false;
675   wpt->routeIndex = 0;
676   waypoints.push_back(wpt); 
677 }
678
679
680 // /*******************************************************************
681 //  * CreateCruise
682 //  * initialize the Aircraft at the parking location
683 //  ******************************************************************/
684 // void FGAIFlightPlan::createCruise(bool firstFlight, FGAirport *dep, 
685 //                                FGAirport *arr, double latitude, 
686 //                                double longitude, double speed, 
687 //                                double alt)
688 // {
689 //   double wind_speed;
690 //   double wind_heading;
691 //   double heading;
692 //   double lat, lon, az;
693 //   double lat2, lon2, az2;
694 //   double azimuth;
695 //   waypoint *wpt;
696
697 //   wpt = new waypoint;
698 //   wpt->name      = "Cruise"; //wpt_node->getStringValue("name", "END");
699 //   wpt->latitude  = latitude;
700 //   wpt->longitude = longitude;
701 //   wpt->altitude  = alt;
702 //   wpt->speed     = speed; 
703 //   wpt->crossat   = -10000;
704 //   wpt->gear_down = false;
705 //   wpt->flaps_down= false;
706 //   wpt->finished  = false;
707 //   wpt->on_ground = false;
708 //   waypoints.push_back(wpt); 
709   
710  
711 //   // should be changed dynamically to allow "gen" and "mil"
712 //   arr->getDynamics()->getActiveRunway("com", 2, activeRunway);
713 //   if (!(globals->get_runways()->search(arr->getId(), 
714 //                                     activeRunway, 
715 //                                     &rwy)))
716 //     {
717 //       SG_LOG(SG_INPUT, SG_ALERT, "Failed to find runway " << 
718 //           activeRunway << 
719 //           " at airport     " << arr->getId());
720 //       exit(1);
721 //     }
722 //   heading = rwy->headingDeg();
723 //   azimuth = heading + 180.0;
724 //   while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
725   
726   
727 //   geo_direct_wgs_84 ( 0, rwy->latitude(), rwy->longitude(), azimuth, 
728 //                    110000,
729 //                    &lat2, &lon2, &az2 );
730 //   wpt = new waypoint;
731 //   wpt->name      = "BOD";
732 //   wpt->latitude  = lat2;
733 //   wpt->longitude = lon2;
734 //   wpt->altitude  = alt;
735 //   wpt->speed     = speed; 
736 //   wpt->crossat   = alt;
737 //   wpt->gear_down = false;
738 //   wpt->flaps_down= false;
739 //   wpt->finished  = false;
740 //   wpt->on_ground = false;
741 //   waypoints.push_back(wpt); 
742 // }
743
744 /*******************************************************************
745  * CreateDecent
746  * initialize the Aircraft at the parking location
747  ******************************************************************/
748 void FGAIFlightPlan::createDecent(FGAirport *apt, const string &fltType)
749 {
750
751   // Ten thousand ft. Slowing down to 240 kts
752   double heading;
753   //FGRunway rwy;
754   double lat2, lon2, az2;
755   double azimuth;
756   //int direction;
757   waypoint *wpt;
758
759   //Beginning of Decent
760   //string name;
761   // allow "mil" and "gen" as well
762   string rwyClass = getRunwayClassFromTrafficType(fltType);
763   apt->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway);
764   rwy = apt->getRunwayByIdent(activeRunway);
765      
766   heading = rwy->headingDeg();
767   azimuth = heading + 180.0;
768   while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
769   geo_direct_wgs_84 ( 0, rwy->latitude(), rwy->longitude(), azimuth, 
770                       100000,
771                       &lat2, &lon2, &az2 );
772   
773   wpt = new waypoint;
774   wpt->name      = "Dec 10000ft"; //wpt_node->getStringValue("name", "END");
775   wpt->latitude  = lat2;
776   wpt->longitude = lon2;
777   wpt->altitude  = apt->getElevation();
778   wpt->speed     = 240; 
779   wpt->crossat   = 10000;
780   wpt->gear_down = false;
781   wpt->flaps_down= false;
782   wpt->finished  = false;
783   wpt->on_ground = false;
784   wpt->routeIndex = 0;
785   waypoints.push_back(wpt);  
786   
787   // Three thousand ft. Slowing down to 160 kts
788   geo_direct_wgs_84 ( 0, rwy->latitude(), rwy->longitude(), azimuth, 
789                       8*SG_NM_TO_METER,
790                       &lat2, &lon2, &az2 );
791   wpt = new waypoint;
792   wpt->name      = "DEC 3000ft"; //wpt_node->getStringValue("name", "END");
793   wpt->latitude  = lat2;
794   wpt->longitude = lon2;
795   wpt->altitude  = apt->getElevation();
796   wpt->speed     = 160; 
797   wpt->crossat   = 3000;
798   wpt->gear_down = true;
799   wpt->flaps_down= true;
800   wpt->finished  = false;
801   wpt->on_ground = false;
802   wpt->routeIndex = 0;
803   waypoints.push_back(wpt);
804 }
805 /*******************************************************************
806  * CreateLanding
807  * initialize the Aircraft at the parking location
808  ******************************************************************/
809 void FGAIFlightPlan::createLanding(FGAirport *apt)
810 {
811   // Ten thousand ft. Slowing down to 150 kts
812   double heading;
813   //FGRunway rwy;
814   double lat2, lon2, az2;
815   double azimuth;
816   //int direction;
817   waypoint *wpt;
818
819   
820   heading = rwy->headingDeg();
821   azimuth = heading + 180.0;
822   while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
823
824   //Runway Threshold
825  geo_direct_wgs_84 ( 0, rwy->latitude(), rwy->longitude(), azimuth, 
826                      rwy->lengthM() *0.45,
827                      &lat2, &lon2, &az2 );
828   wpt = new waypoint;
829   wpt->name      = "Threshold"; //wpt_node->getStringValue("name", "END");
830   wpt->latitude  = lat2;
831   wpt->longitude = lon2;
832   wpt->altitude  = apt->getElevation();
833   wpt->speed     = 150; 
834   wpt->crossat   = apt->getElevation();
835   wpt->gear_down = true;
836   wpt->flaps_down= true;
837   wpt->finished  = false;
838   wpt->on_ground = true;
839   wpt->routeIndex = 0;
840   waypoints.push_back(wpt); 
841
842  //Full stop at the runway centerpoint
843  geo_direct_wgs_84 ( 0, rwy->latitude(), rwy->longitude(), azimuth, 
844                      rwy->lengthFt() *0.45,
845                       &lat2, &lon2, &az2 );
846   wpt = new waypoint;
847   wpt->name      = "Center"; //wpt_node->getStringValue("name", "END");
848   wpt->latitude  = rwy->latitude();
849   wpt->longitude = rwy->longitude();
850   wpt->altitude  = apt->getElevation();
851   wpt->speed     = 30; 
852   wpt->crossat   = -10000;
853   wpt->gear_down = true;
854   wpt->flaps_down= true;
855   wpt->finished  = false;
856   wpt->on_ground = true;
857   wpt->routeIndex = 0;
858   waypoints.push_back(wpt);
859
860  geo_direct_wgs_84 ( 0, rwy->latitude(), rwy->longitude(), heading, 
861                      rwy->lengthM() *0.45,
862                      &lat2, &lon2, &az2 );
863   wpt = new waypoint;
864   wpt->name      = "Threshold"; //wpt_node->getStringValue("name", "END");
865   wpt->latitude  = lat2;
866   wpt->longitude = lon2;
867   wpt->altitude  = apt->getElevation();
868   wpt->speed     = 15; 
869   wpt->crossat   = apt->getElevation();
870   wpt->gear_down = true;
871   wpt->flaps_down= true;
872   wpt->finished  = false;
873   wpt->on_ground = true;
874   wpt->routeIndex = 0;
875   waypoints.push_back(wpt); 
876 }
877
878 /*******************************************************************
879  * CreateParking
880  * initialize the Aircraft at the parking location
881  ******************************************************************/
882 void FGAIFlightPlan::createParking(FGAirport *apt, double radius)
883 {
884   waypoint* wpt;
885   double lat, lat2;
886   double lon, lon2;
887   double az2;
888   double heading;
889   apt->getDynamics()->getParking(gateId, &lat, &lon, &heading);
890   heading += 180.0;
891   if (heading > 360)
892     heading -= 360; 
893   geo_direct_wgs_84 ( 0, lat, lon, heading, 
894                       2.2*radius,           
895                       &lat2, &lon2, &az2 );
896   wpt = new waypoint;
897   wpt->name      = "taxiStart";
898   wpt->latitude  = lat2;
899   wpt->longitude = lon2;
900   wpt->altitude  = apt->getElevation();
901   wpt->speed     = 10; 
902   wpt->crossat   = -10000;
903   wpt->gear_down = true;
904   wpt->flaps_down= true;
905   wpt->finished  = false;
906   wpt->on_ground = true;
907   wpt->routeIndex = 0;
908   waypoints.push_back(wpt); 
909   geo_direct_wgs_84 ( 0, lat, lon, heading, 
910                       0.1 *radius,           
911                       &lat2, &lon2, &az2 );
912   wpt = new waypoint;
913   wpt->name      = "taxiStart";
914   wpt->latitude  = lat2;
915   wpt->longitude = lon2;
916   wpt->altitude  = apt->getElevation();
917   wpt->speed     = 10; 
918   wpt->crossat   = -10000;
919   wpt->gear_down = true;
920   wpt->flaps_down= true;
921   wpt->finished  = false;
922   wpt->on_ground = true;
923   wpt->routeIndex = 0;
924   waypoints.push_back(wpt);   
925
926   wpt = new waypoint;
927   wpt->name      = "END"; //wpt_node->getStringValue("name", "END");
928   wpt->latitude  = lat;
929   wpt->longitude = lon;
930   wpt->altitude  = apt->getElevation();
931   wpt->speed     = 15; 
932   wpt->crossat   = -10000;
933   wpt->gear_down = true;
934   wpt->flaps_down= true;
935   wpt->finished  = false;
936   wpt->on_ground = true;
937   wpt->routeIndex = 0;
938   waypoints.push_back(wpt);
939 }
940
941 /**
942  *
943  * @param fltType a string describing the type of
944  * traffic, normally used for gate assignments
945  * @return a converted string that gives the runway
946  * preference schedule to be used at aircraft having
947  * a preferential runway schedule implemented (i.e.
948  * having a rwyprefs.xml file
949  * 
950  * Currently valid traffic types for gate assignment:
951  * - gate (commercial gate)
952  * - cargo (commercial gargo),
953  * - ga (general aviation) ,
954  * - ul (ultralight),
955  * - mil-fighter (military - fighter),
956  * - mil-transport (military - transport)
957  *
958  * Valid runway classes:
959  * - com (commercial traffic: jetliners, passenger and cargo)
960  * - gen (general aviation)
961  * - ul (ultralight: I can imagine that these may share a runway with ga on some airports)
962  * - mil (all military traffic)
963  */
964 string FGAIFlightPlan::getRunwayClassFromTrafficType(string fltType)
965 {
966     if ((fltType == "gate") || (fltType == "cargo")) { 
967         return string("com");
968     }
969     if (fltType == "ga") {
970         return string ("gen");
971     }
972     if (fltType == "ul") {
973         return string("ul");
974     }
975     if ((fltType == "mil-fighter") || (fltType == "mil-transport")) { 
976         return string("mil");
977     }
978    return string("com");
979 }