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