]> git.mxchange.org Git - flightgear.git/blob - src/AIModel/AIFlightPlanCreate.cxx
482d16aeef0e6b08708bfb5b313e151f64e6da0b
[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
589  //  geo_direct_wgs_84 ( 0, rwy->latitude(), rwy->longitude(), heading, 
590 //   100000,
591 //   &lat2, &lon2, &az2 );
592 //   wpt = new waypoint;
593 //   wpt->name      = "5100 ft";
594 //   wpt->latitude  = lat2;
595 //   wpt->longitude = lon2;
596 //   wpt->altitude  = apt->getElevation()+5100;
597 //   wpt->speed     = speed; 
598 //   wpt->crossat   = -10000;
599 //   wpt->gear_down = true;
600 //   wpt->flaps_down= true;
601 //   wpt->finished  = false;
602 //   wpt->on_ground = false;
603 //   wpt->routeIndex = 0;
604 //   waypoints.push_back(wpt);
605 }
606  
607 /*******************************************************************
608  * CreateClimb
609  * initialize the Aircraft at the parking location
610  ******************************************************************/
611 void FGAIFlightPlan::createClimb(bool firstFlight, FGAirport *apt, double speed, double alt, const string &fltType)
612 {
613   double heading;
614   //FGRunway rwy;
615   double lat2, lon2, az2;
616   //int direction;
617   waypoint *wpt;
618
619  
620   if (firstFlight)
621     {
622       //string name;
623       string rwyClass = getRunwayClassFromTrafficType(fltType);
624       apt->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway);
625       rwy = apt->getRunwayByIdent(activeRunway);
626     }
627   
628   
629   heading = rwy->headingDeg();
630   double azimuth = heading + 180.0;
631   while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
632   //cerr << "Creating climb at : " << rwy._id << " " << rwy._rwy_no << endl;
633   geo_direct_wgs_84 ( 0, rwy->latitude(), rwy->longitude(), heading, 
634                       10*SG_NM_TO_METER,
635                       &lat2, &lon2, &az2 );
636   wpt = new waypoint;
637   wpt->name      = "10000ft climb";
638   wpt->latitude  = lat2;
639   wpt->longitude = lon2;
640   wpt->altitude  = 10000;
641   wpt->speed     = speed; 
642   wpt->crossat   = -10000;
643   wpt->gear_down = true;
644   wpt->flaps_down= true;
645   wpt->finished  = false;
646   wpt->on_ground = false;
647   wpt->routeIndex = 0;
648   waypoints.push_back(wpt); 
649   
650
651   geo_direct_wgs_84 ( 0, rwy->latitude(), rwy->longitude(), heading, 
652                       20*SG_NM_TO_METER,
653                       &lat2, &lon2, &az2 );
654   wpt = new waypoint;
655   wpt->name      = "18000ft climb";
656   wpt->latitude  = lat2;
657   wpt->longitude = lon2;
658   wpt->altitude  = 18000;
659   wpt->speed     = speed; 
660   wpt->crossat   = -10000;
661   wpt->gear_down = true;
662   wpt->flaps_down= true;
663   wpt->finished  = false;
664   wpt->on_ground = false;
665   wpt->routeIndex = 0;
666   waypoints.push_back(wpt); 
667 }
668
669
670 // /*******************************************************************
671 //  * CreateCruise
672 //  * initialize the Aircraft at the parking location
673 //  ******************************************************************/
674 // void FGAIFlightPlan::createCruise(bool firstFlight, FGAirport *dep, 
675 //                                FGAirport *arr, double latitude, 
676 //                                double longitude, double speed, 
677 //                                double alt)
678 // {
679 //   double wind_speed;
680 //   double wind_heading;
681 //   double heading;
682 //   double lat, lon, az;
683 //   double lat2, lon2, az2;
684 //   double azimuth;
685 //   waypoint *wpt;
686
687 //   wpt = new waypoint;
688 //   wpt->name      = "Cruise"; //wpt_node->getStringValue("name", "END");
689 //   wpt->latitude  = latitude;
690 //   wpt->longitude = longitude;
691 //   wpt->altitude  = alt;
692 //   wpt->speed     = speed; 
693 //   wpt->crossat   = -10000;
694 //   wpt->gear_down = false;
695 //   wpt->flaps_down= false;
696 //   wpt->finished  = false;
697 //   wpt->on_ground = false;
698 //   waypoints.push_back(wpt); 
699   
700  
701 //   // should be changed dynamically to allow "gen" and "mil"
702 //   arr->getDynamics()->getActiveRunway("com", 2, activeRunway);
703 //   if (!(globals->get_runways()->search(arr->getId(), 
704 //                                     activeRunway, 
705 //                                     &rwy)))
706 //     {
707 //       SG_LOG(SG_INPUT, SG_ALERT, "Failed to find runway " << 
708 //           activeRunway << 
709 //           " at airport     " << arr->getId());
710 //       exit(1);
711 //     }
712 //   heading = rwy->headingDeg();
713 //   azimuth = heading + 180.0;
714 //   while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
715   
716   
717 //   geo_direct_wgs_84 ( 0, rwy->latitude(), rwy->longitude(), azimuth, 
718 //                    110000,
719 //                    &lat2, &lon2, &az2 );
720 //   wpt = new waypoint;
721 //   wpt->name      = "BOD";
722 //   wpt->latitude  = lat2;
723 //   wpt->longitude = lon2;
724 //   wpt->altitude  = alt;
725 //   wpt->speed     = speed; 
726 //   wpt->crossat   = alt;
727 //   wpt->gear_down = false;
728 //   wpt->flaps_down= false;
729 //   wpt->finished  = false;
730 //   wpt->on_ground = false;
731 //   waypoints.push_back(wpt); 
732 // }
733
734 /*******************************************************************
735  * CreateDecent
736  * initialize the Aircraft at the parking location
737  ******************************************************************/
738 void FGAIFlightPlan::createDecent(FGAirport *apt, const string &fltType)
739 {
740
741   // Ten thousand ft. Slowing down to 240 kts
742   double heading;
743   //FGRunway rwy;
744   double lat2, lon2, az2;
745   double azimuth;
746   //int direction;
747   waypoint *wpt;
748
749   //Beginning of Decent
750   //string name;
751   // allow "mil" and "gen" as well
752   string rwyClass = getRunwayClassFromTrafficType(fltType);
753   apt->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway);
754   rwy = apt->getRunwayByIdent(activeRunway);
755      
756   heading = rwy->headingDeg();
757   azimuth = heading + 180.0;
758   while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
759   geo_direct_wgs_84 ( 0, rwy->latitude(), rwy->longitude(), azimuth, 
760                       100000,
761                       &lat2, &lon2, &az2 );
762   
763   wpt = new waypoint;
764   wpt->name      = "Dec 10000ft"; //wpt_node->getStringValue("name", "END");
765   wpt->latitude  = lat2;
766   wpt->longitude = lon2;
767   wpt->altitude  = apt->getElevation();
768   wpt->speed     = 240; 
769   wpt->crossat   = 10000;
770   wpt->gear_down = false;
771   wpt->flaps_down= false;
772   wpt->finished  = false;
773   wpt->on_ground = false;
774   wpt->routeIndex = 0;
775   waypoints.push_back(wpt);  
776   
777   // Three thousand ft. Slowing down to 160 kts
778   geo_direct_wgs_84 ( 0, rwy->latitude(), rwy->longitude(), azimuth, 
779                       8*SG_NM_TO_METER,
780                       &lat2, &lon2, &az2 );
781   wpt = new waypoint;
782   wpt->name      = "DEC 3000ft"; //wpt_node->getStringValue("name", "END");
783   wpt->latitude  = lat2;
784   wpt->longitude = lon2;
785   wpt->altitude  = apt->getElevation();
786   wpt->speed     = 160; 
787   wpt->crossat   = 3000;
788   wpt->gear_down = true;
789   wpt->flaps_down= true;
790   wpt->finished  = false;
791   wpt->on_ground = false;
792   wpt->routeIndex = 0;
793   waypoints.push_back(wpt);
794 }
795 /*******************************************************************
796  * CreateLanding
797  * initialize the Aircraft at the parking location
798  ******************************************************************/
799 void FGAIFlightPlan::createLanding(FGAirport *apt)
800 {
801   // Ten thousand ft. Slowing down to 150 kts
802   double heading;
803   //FGRunway rwy;
804   double lat2, lon2, az2;
805   double azimuth;
806   //int direction;
807   waypoint *wpt;
808
809   
810   heading = rwy->headingDeg();
811   azimuth = heading + 180.0;
812   while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
813
814   //Runway Threshold
815  geo_direct_wgs_84 ( 0, rwy->latitude(), rwy->longitude(), azimuth, 
816                      rwy->lengthM() *0.45,
817                      &lat2, &lon2, &az2 );
818   wpt = new waypoint;
819   wpt->name      = "Threshold"; //wpt_node->getStringValue("name", "END");
820   wpt->latitude  = lat2;
821   wpt->longitude = lon2;
822   wpt->altitude  = apt->getElevation();
823   wpt->speed     = 150; 
824   wpt->crossat   = apt->getElevation();
825   wpt->gear_down = true;
826   wpt->flaps_down= true;
827   wpt->finished  = false;
828   wpt->on_ground = true;
829   wpt->routeIndex = 0;
830   waypoints.push_back(wpt); 
831
832  //Full stop at the runway centerpoint
833  geo_direct_wgs_84 ( 0, rwy->latitude(), rwy->longitude(), azimuth, 
834                      rwy->lengthFt() *0.45,
835                       &lat2, &lon2, &az2 );
836   wpt = new waypoint;
837   wpt->name      = "Center"; //wpt_node->getStringValue("name", "END");
838   wpt->latitude  = rwy->latitude();
839   wpt->longitude = rwy->longitude();
840   wpt->altitude  = apt->getElevation();
841   wpt->speed     = 30; 
842   wpt->crossat   = -10000;
843   wpt->gear_down = true;
844   wpt->flaps_down= true;
845   wpt->finished  = false;
846   wpt->on_ground = true;
847   wpt->routeIndex = 0;
848   waypoints.push_back(wpt);
849
850  geo_direct_wgs_84 ( 0, rwy->latitude(), rwy->longitude(), heading, 
851                      rwy->lengthM() *0.45,
852                      &lat2, &lon2, &az2 );
853   wpt = new waypoint;
854   wpt->name      = "Threshold"; //wpt_node->getStringValue("name", "END");
855   wpt->latitude  = lat2;
856   wpt->longitude = lon2;
857   wpt->altitude  = apt->getElevation();
858   wpt->speed     = 15; 
859   wpt->crossat   = apt->getElevation();
860   wpt->gear_down = true;
861   wpt->flaps_down= true;
862   wpt->finished  = false;
863   wpt->on_ground = true;
864   wpt->routeIndex = 0;
865   waypoints.push_back(wpt); 
866 }
867
868 /*******************************************************************
869  * CreateParking
870  * initialize the Aircraft at the parking location
871  ******************************************************************/
872 void FGAIFlightPlan::createParking(FGAirport *apt, double radius)
873 {
874   waypoint* wpt;
875   double lat, lat2;
876   double lon, lon2;
877   double az2;
878   double heading;
879   apt->getDynamics()->getParking(gateId, &lat, &lon, &heading);
880   heading += 180.0;
881   if (heading > 360)
882     heading -= 360; 
883   geo_direct_wgs_84 ( 0, lat, lon, heading, 
884                       2.2*radius,           
885                       &lat2, &lon2, &az2 );
886   wpt = new waypoint;
887   wpt->name      = "taxiStart";
888   wpt->latitude  = lat2;
889   wpt->longitude = lon2;
890   wpt->altitude  = apt->getElevation();
891   wpt->speed     = 10; 
892   wpt->crossat   = -10000;
893   wpt->gear_down = true;
894   wpt->flaps_down= true;
895   wpt->finished  = false;
896   wpt->on_ground = true;
897   wpt->routeIndex = 0;
898   waypoints.push_back(wpt); 
899   geo_direct_wgs_84 ( 0, lat, lon, heading, 
900                       0.1 *radius,           
901                       &lat2, &lon2, &az2 );
902   wpt = new waypoint;
903   wpt->name      = "taxiStart";
904   wpt->latitude  = lat2;
905   wpt->longitude = lon2;
906   wpt->altitude  = apt->getElevation();
907   wpt->speed     = 10; 
908   wpt->crossat   = -10000;
909   wpt->gear_down = true;
910   wpt->flaps_down= true;
911   wpt->finished  = false;
912   wpt->on_ground = true;
913   wpt->routeIndex = 0;
914   waypoints.push_back(wpt);   
915
916   wpt = new waypoint;
917   wpt->name      = "END"; //wpt_node->getStringValue("name", "END");
918   wpt->latitude  = lat;
919   wpt->longitude = lon;
920   wpt->altitude  = apt->getElevation();
921   wpt->speed     = 15; 
922   wpt->crossat   = -10000;
923   wpt->gear_down = true;
924   wpt->flaps_down= true;
925   wpt->finished  = false;
926   wpt->on_ground = true;
927   wpt->routeIndex = 0;
928   waypoints.push_back(wpt);
929 }
930
931 /**
932  *
933  * @param fltType a string describing the type of
934  * traffic, normally used for gate assignments
935  * @return a converted string that gives the runway
936  * preference schedule to be used at aircraft having
937  * a preferential runway schedule implemented (i.e.
938  * having a rwyprefs.xml file
939  * 
940  * Currently valid traffic types for gate assignment:
941  * - gate (commercial gate)
942  * - cargo (commercial gargo),
943  * - ga (general aviation) ,
944  * - ul (ultralight),
945  * - mil-fighter (military - fighter),
946  * - mil-transport (military - transport)
947  *
948  * Valid runway classes:
949  * - com (commercial traffic: jetliners, passenger and cargo)
950  * - gen (general aviation)
951  * - ul (ultralight: I can imagine that these may share a runway with ga on some airports)
952  * - mil (all military traffic)
953  */
954 string FGAIFlightPlan::getRunwayClassFromTrafficType(string fltType)
955 {
956     if ((fltType == "gate") || (fltType == "cargo")) { 
957         return string("com");
958     }
959     if (fltType == "ga") {
960         return string ("gen");
961     }
962     if (fltType == "ul") {
963         return string("ul");
964     }
965     if ((fltType == "mil-fighter") || (fltType == "mil-transport")) { 
966         return string("mil");
967     }
968    return string("com");
969 }