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