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