]> git.mxchange.org Git - flightgear.git/blob - src/AIModel/AIFlightPlan.cxx
Melchior FRANZ:
[flightgear.git] / src / AIModel / AIFlightPlan.cxx
1 // FGAIFlightPlan - class for loading and storing  AI flight plans
2 // Written by David Culp, started May 2004
3 // - davidculp2@comcast.net
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., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19
20
21 #include <simgear/misc/sg_path.hxx>
22 #include <simgear/debug/logstream.hxx>
23 #include <simgear/route/waypoint.hxx>
24 #include <simgear/math/sg_geodesy.hxx>
25 #include <simgear/structure/exception.hxx>
26 #include <simgear/constants.h>
27 #ifdef __BORLANDC__
28 #  define exception c_exception
29 #endif
30 #include <simgear/props/props.hxx>
31 #include <Main/globals.hxx>
32 #include <Main/fg_props.hxx>
33 #include <Main/fg_init.hxx>
34 #include <Airports/simple.hxx>
35 #include <Airports/runways.hxx>
36
37
38 #include <Environment/environment_mgr.hxx>
39 #include <Environment/environment.hxx>
40
41 #include "AIFlightPlan.hxx"
42
43
44 FGAIFlightPlan::FGAIFlightPlan(string filename)
45 {
46   int i;
47   start_time = 0;
48   SGPath path( globals->get_fg_root() );
49   path.append( ("/Data/AI/FlightPlans/" + filename).c_str() );
50   SGPropertyNode root;
51
52   try {
53       readProperties(path.str(), &root);
54   } catch (const sg_exception &e) {
55       SG_LOG(SG_GENERAL, SG_ALERT,
56        "Error reading AI flight plan: " << path.str());
57        // cout << path.str() << endl;
58       return;
59   }
60
61   SGPropertyNode * node = root.getNode("flightplan");
62   for (i = 0; i < node->nChildren(); i++) { 
63      //cout << "Reading waypoint " << i << endl;        
64      waypoint* wpt = new waypoint;
65      SGPropertyNode * wpt_node = node->getChild(i);
66      wpt->name      = wpt_node->getStringValue("name", "END");
67      wpt->latitude  = wpt_node->getDoubleValue("lat", 0);
68      wpt->longitude = wpt_node->getDoubleValue("lon", 0);
69      wpt->altitude  = wpt_node->getDoubleValue("alt", 0);
70      wpt->speed     = wpt_node->getDoubleValue("ktas", 0);
71      wpt->crossat   = wpt_node->getDoubleValue("crossat", -10000);
72      wpt->gear_down = wpt_node->getBoolValue("gear-down", false);
73      wpt->flaps_down= wpt_node->getBoolValue("flaps-down", false);
74      wpt->on_ground = wpt_node->getBoolValue("on-ground", false);
75
76      if (wpt->name == "END") wpt->finished = true;
77      else wpt->finished = false;
78
79      waypoints.push_back( wpt );
80    }
81
82   wpt_iterator = waypoints.begin();
83   //cout << waypoints.size() << " waypoints read." << endl;
84 }
85
86
87 // This is a modified version of the constructor,
88 // Which not only reads the waypoints from a 
89 // Flight plan file, but also adds the current
90 // Position computed by the traffic manager, as well
91 // as setting speeds and altitude computed by the
92 // traffic manager. 
93 FGAIFlightPlan::FGAIFlightPlan(FGAIModelEntity *entity,
94                                double course,
95                                time_t start,
96                                FGAirport *dep,
97                                FGAirport *arr)
98 {
99   start_time = start;
100   bool useInitialWayPoint = true;
101   bool useCurrentWayPoint = false;
102   SGPath path( globals->get_fg_root() );
103   path.append( "/Data/AI/FlightPlans" );
104   path.append( entity->path );
105   SGPropertyNode root;
106   
107   // This is a bit of a hack:
108   // Normally the value of course will be used to evaluate whether
109   // or not a waypoint will be used for midair initialization of 
110   // an AI aircraft. However, if a course value of 999 will be passed
111   // when an update request is received, which will by definition always be
112   // on the ground and should include all waypoints.
113   if (course == 999) 
114     {
115       useInitialWayPoint = false;
116       useCurrentWayPoint = true;
117     }
118
119   try {
120     readProperties(path.str(), &root);
121     
122     SGPropertyNode * node = root.getNode("flightplan");
123   
124     //waypoints.push_back( init_waypoint );
125     for (int i = 0; i < node->nChildren(); i++) { 
126       //cout << "Reading waypoint " << i << endl;
127       waypoint* wpt = new waypoint;
128       SGPropertyNode * wpt_node = node->getChild(i);
129       wpt->name      = wpt_node->getStringValue("name", "END");
130       wpt->latitude  = wpt_node->getDoubleValue("lat", 0);
131       wpt->longitude = wpt_node->getDoubleValue("lon", 0);
132       wpt->altitude  = wpt_node->getDoubleValue("alt", 0);
133       wpt->speed     = wpt_node->getDoubleValue("ktas", 0);
134       //wpt->speed     = speed;
135       wpt->crossat   = wpt_node->getDoubleValue("crossat", -10000);
136       wpt->gear_down = wpt_node->getBoolValue("gear-down", false);
137       wpt->flaps_down= wpt_node->getBoolValue("flaps-down", false);
138       
139       if (wpt->name == "END") wpt->finished = true;
140       else wpt->finished = false;
141       waypoints.push_back(wpt);
142     }
143   }
144   catch (const sg_exception &e) {
145     //SG_LOG(SG_GENERAL, SG_ALERT,
146     // "Error reading AI flight plan: ");
147     // cout << path.str() << endl;
148     // cout << "Trying to create this plan dynamically" << endl;
149     // cout << "Route from " << dep->id << " to " << arr->id << endl;
150        create(dep,arr, entity->altitude, entity->speed);
151        // Now that we have dynamically created a flight plan,
152        // we need to add some code that pops any waypoints already past.
153        //return;
154   }
155   waypoint* init_waypoint   = new waypoint;
156   init_waypoint->name       = string("initial position");
157   init_waypoint->latitude   = entity->latitude;
158   init_waypoint->longitude  = entity->longitude;
159   init_waypoint->altitude   = entity->altitude;
160   init_waypoint->speed      = entity->speed;
161   init_waypoint->crossat    = - 10000;
162   init_waypoint->gear_down  = false;
163   init_waypoint->flaps_down = false;
164   init_waypoint->finished   = false;
165
166   wpt_vector_iterator i = waypoints.begin();
167   while (i != waypoints.end())
168     {
169       //cerr << "Checking status of each waypoint: " << (*i)->name << endl;
170        SGWayPoint first(init_waypoint->longitude, 
171                        init_waypoint->latitude, 
172                        init_waypoint->altitude);
173       SGWayPoint curr ((*i)->longitude, 
174                        (*i)->latitude, 
175                        (*i)->altitude);
176       double crse, crsDiff;
177       double dist;
178       curr.CourseAndDistance(first, &crse, &dist);
179       
180       dist *= SG_METER_TO_NM;
181       
182       // We're only interested in the absolute value of crsDiff
183       // wich should fall in the 0-180 deg range.
184       crsDiff = fabs(crse-course);
185       if (crsDiff > 180)
186         crsDiff = 360-crsDiff;
187       // These are the three conditions that we consider including
188       // in our flight plan:
189       // 1) current waypoint is less then 100 miles away OR
190       // 2) curren waypoint is ahead of us, at any distance
191      
192       if ((dist > 20.0) && (crsDiff > 90.0) && ((*i)->name != string ("EOF")))
193         {
194           //useWpt = false;
195           // Once we start including waypoints, we have to continue, even though
196           // one of the following way point would suffice. 
197           // so once is the useWpt flag is set to true, we cannot reset it to false.
198           //cerr << "Discarding waypoint: " << (*i)->name 
199           //   << ": Course difference = " << crsDiff
200           //  << "Course = " << course
201           // << "crse   = " << crse << endl;
202         }
203       else
204         useCurrentWayPoint = true;
205       
206       if (useCurrentWayPoint)
207         {
208           if ((dist > 100.0) && (useInitialWayPoint))
209             {
210               //waypoints.push_back(init_waypoint);;
211               waypoints.insert(i, init_waypoint);
212               //cerr << "Using waypoint : " << init_waypoint->name <<  endl;
213             }
214           //if (useInitialWayPoint)
215           // {
216           //    (*i)->speed = dist; // A hack
217           //  }
218           //waypoints.push_back( wpt );
219           //cerr << "Using waypoint : " << (*i)->name 
220           //  << ": course diff : " << crsDiff 
221           //   << "Course = " << course
222           //   << "crse   = " << crse << endl
223           //    << "distance      : " << dist << endl;
224           useInitialWayPoint = false;
225           i++;
226         }
227       else 
228         {
229           //delete wpt;
230           delete *(i);
231           i = waypoints.erase(i);
232         }
233     }
234   //for (i = waypoints.begin(); i != waypoints.end(); i++)
235   //  cerr << "Using waypoint : " << (*i)->name << endl;
236   wpt_iterator = waypoints.begin();
237   //cout << waypoints.size() << " waypoints read." << endl;
238 }
239
240
241
242
243 FGAIFlightPlan::~FGAIFlightPlan()
244 {
245   waypoints.clear();
246 }
247
248
249 FGAIFlightPlan::waypoint*
250 FGAIFlightPlan::getPreviousWaypoint( void )
251 {
252   if (wpt_iterator == waypoints.begin()) {
253     return 0;
254   } else {
255     wpt_vector_iterator prev = wpt_iterator;
256     return *(--prev);
257   }
258 }
259
260 FGAIFlightPlan::waypoint*
261 FGAIFlightPlan::getCurrentWaypoint( void )
262 {
263   return *wpt_iterator;
264 }
265
266 FGAIFlightPlan::waypoint*
267 FGAIFlightPlan::getNextWaypoint( void )
268 {
269   if (wpt_iterator == waypoints.end()) {
270     return 0;
271   } else {
272     wpt_vector_iterator next = wpt_iterator;
273     return *(++next);
274   }
275 }
276
277 void FGAIFlightPlan::IncrementWaypoint( void )
278 {
279   wpt_iterator++;
280 }
281
282 // gives distance in feet from a position to a waypoint
283 double FGAIFlightPlan::getDistanceToGo(double lat, double lon, waypoint* wp){
284    // get size of a degree at the present latitude
285    // this won't work over large distances
286    double ft_per_deg_lat = 366468.96 - 3717.12 * cos(lat / SG_RADIANS_TO_DEGREES);
287    double ft_per_deg_lon = 365228.16 * cos(lat / SG_RADIANS_TO_DEGREES);
288    double lat_diff_ft = fabs(wp->latitude - lat) * ft_per_deg_lat;
289    double lon_diff_ft = fabs(wp->longitude - lon) * ft_per_deg_lon;
290    return sqrt((lat_diff_ft * lat_diff_ft) + (lon_diff_ft * lon_diff_ft));
291 }
292
293 // sets distance in feet from a lead point to the current waypoint
294 void FGAIFlightPlan::setLeadDistance(double speed, double bearing, 
295                                      waypoint* current, waypoint* next){
296   double turn_radius = 0.1911 * speed * speed; // an estimate for 25 degrees bank
297   double inbound = bearing;
298   double outbound = getBearing(current, next);
299   double diff = fabs(inbound - outbound);
300   if (diff > 180.0) diff = 360.0 - diff;
301   lead_distance = turn_radius * sin(diff * SG_DEGREES_TO_RADIANS); 
302 }
303
304 void FGAIFlightPlan::setLeadDistance(double distance_ft){
305   lead_distance = distance_ft;
306 }
307
308
309 double FGAIFlightPlan::getBearing(waypoint* first, waypoint* second){
310   return getBearing(first->latitude, first->longitude, second);
311 }
312
313
314 double FGAIFlightPlan::getBearing(double lat, double lon, waypoint* wp){
315   double course, distance;
316  //  double latd = lat;
317 //   double lond = lon;
318 //   double latt = wp->latitude;
319 //   double lont = wp->longitude;
320 //   double ft_per_deg_lat = 366468.96 - 3717.12 * cos(lat/SG_RADIANS_TO_DEGREES);
321 //   double ft_per_deg_lon = 365228.16 * cos(lat/SG_RADIANS_TO_DEGREES);
322
323 //   if (lond < 0.0) {
324 //     lond+=360.0;
325 //     lont+=360;
326 //   }
327 //   if (lont < 0.0) {
328 //     lond+=360.0;
329 //     lont+=360.0;
330 //   }
331 //   latd+=90.0;
332 //   latt+=90.0;
333
334 //   double lat_diff = (latt - latd) * ft_per_deg_lat;
335 //   double lon_diff = (lont - lond) * ft_per_deg_lon;
336 //   double angle = atan(fabs(lat_diff / lon_diff)) * SG_RADIANS_TO_DEGREES;
337
338 //   bool southerly = true;
339 //   if (latt > latd) southerly = false;
340 //   bool easterly = false;
341 //   if (lont > lond) easterly = true;
342 //   if (southerly && easterly) return 90.0 + angle;
343 //   if (!southerly && easterly) return 90.0 - angle;
344 //   if (southerly && !easterly) return 270.0 - angle;
345 //   if (!southerly && !easterly) return 270.0 + angle; 
346   SGWayPoint sgWp(wp->longitude,wp->latitude, wp->altitude, SGWayPoint::WGS84, string("temp"));
347   sgWp.CourseAndDistance(lon, lat, wp->altitude, &course, &distance);
348   return course;
349   // Omit a compiler warning.
350  
351 }
352
353 /* FGAIFlightPlan::create()
354  * dynamically create a flight plan for AI traffic, based on data provided by the
355  * Traffic Manager, when reading a filed flightplan failes. (DT, 2004/07/10) 
356  *
357  * Probably need to split this into separate functions for different parts of the flight
358
359  * once the code matures a bit more.
360  *
361  */ 
362 void FGAIFlightPlan::create(FGAirport *dep, FGAirport *arr, double alt, double speed)
363 {
364 double wind_speed;
365   double wind_heading;
366   FGRunway rwy;
367   double lat, lon, az;
368   double lat2, lon2, az2;
369   int direction;
370   
371   //waypoints.push_back(wpt);
372   // Create the outbound taxi leg, for now simplified as a 
373   // Direct route from the airport center point to the start
374   // of the runway.
375   ///////////////////////////////////////////////////////////
376     //cerr << "Cruise Alt << " << alt << endl;
377     // Temporary code to add some small random variation to aircraft parking positions;
378   direction = (rand() % 360);
379 geo_direct_wgs_84 ( 0, dep->latitude, dep->longitude, direction, 
380       100,
381       &lat2, &lon2, &az2 );
382   waypoint *wpt = new waypoint;
383   wpt->name      = dep->id; //wpt_node->getStringValue("name", "END");
384   wpt->latitude  = lat2;
385   wpt->longitude = lon2;
386   wpt->altitude  = dep->elevation + 19; // probably need to add some model height to it
387   wpt->speed     = 15; 
388   wpt->crossat   = -10000;
389   wpt->gear_down = true;
390   wpt->flaps_down= true;
391   wpt->finished  = false;
392   wpt->on_ground = true;
393   waypoints.push_back(wpt);
394   
395   // Get the current active runway, based on code from David Luff
396   FGEnvironment 
397     stationweather = ((FGEnvironmentMgr *) globals->get_subsystem("environment"))
398     ->getEnvironment(dep->latitude, dep->longitude, dep->elevation);
399   
400   wind_speed = stationweather.get_wind_speed_kt();
401   wind_heading = stationweather.get_wind_from_heading_deg();
402   if (wind_speed == 0) {
403     wind_heading = 270; // This forces West-facing rwys to be used in no-wind situations
404                         // which is consistent with Flightgear's initial setup.
405   }
406   
407   string rwy_no = globals->get_runways()->search(dep->id, int(wind_heading));
408   if (!(globals->get_runways()->search(dep->id, (int) wind_heading, &rwy )))
409     {
410       cout << "Failed to find runway for " << dep->id << endl;
411       // Hmm, how do we handle a potential error like this?
412       exit(1);
413     }
414
415  
416   double heading = rwy.heading;
417   double azimuth = heading + 180.0;
418   while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
419   geo_direct_wgs_84 ( 0, rwy.lat, rwy.lon, azimuth, 
420                       rwy.length * SG_FEET_TO_METER * 0.5 - 5.0,
421                       &lat2, &lon2, &az2 );
422   
423   //Add the runway startpoint;
424   wpt = new waypoint;
425   wpt->name      = rwy.id;
426   wpt->latitude  = lat2;
427   wpt->longitude = lon2;
428   wpt->altitude  = dep->elevation + 19;
429   wpt->speed     = 15; 
430   wpt->crossat   = -10000;
431   wpt->gear_down = true;
432   wpt->flaps_down= true;
433   wpt->finished  = false;
434   wpt->on_ground = true;
435   waypoints.push_back(wpt);
436
437   //Next: The point on the runway where we begin to accelerate to take-off speed
438   //100 meters down the runway seems to work. Shorter distances cause problems with
439   // the turn with larger aircraft
440   geo_direct_wgs_84 ( 0, rwy.lat, rwy.lon, azimuth, 
441                       rwy.length * SG_FEET_TO_METER * 0.5 - 105.0,
442                       &lat2, &lon2, &az2 );
443   wpt = new waypoint;
444   wpt->name      = "accel";
445   wpt->latitude  = lat2;
446   wpt->longitude = lon2;
447   wpt->altitude  = dep->elevation + 19;
448   wpt->speed     = speed; 
449   wpt->crossat   = -10000;
450   wpt->gear_down = true;
451   wpt->flaps_down= true;
452   wpt->finished  = false;
453   wpt->on_ground = true;
454   waypoints.push_back(wpt); 
455   
456   lat = lat2;
457   lon = lon2;
458   az  = az2;
459
460  //Next: the Start of Climb
461   geo_direct_wgs_84 ( 0, lat, lon, heading, 
462                       2560 * SG_FEET_TO_METER,
463                       &lat2, &lon2, &az2 );
464
465   wpt = new waypoint;
466   wpt->name      = "SOC";
467   wpt->latitude  = lat2;
468   wpt->longitude = lon2;
469   wpt->altitude  = alt + 19;
470   wpt->speed     = speed; 
471   wpt->crossat   = -10000;
472   wpt->gear_down = true;
473   wpt->flaps_down= true;
474   wpt->finished  = false;
475   wpt->on_ground = false;
476   waypoints.push_back(wpt); 
477
478 //Next: the Top of Climb
479   geo_direct_wgs_84 ( 0, lat, lon, heading, 
480                       20*SG_NM_TO_METER,
481                       &lat2, &lon2, &az2 );
482   wpt = new waypoint;
483   wpt->name      = "10000ft climb";
484   wpt->latitude  = lat2;
485   wpt->longitude = lon2;
486   wpt->altitude  = 10000;
487   wpt->speed     = speed; 
488   wpt->crossat   = -10000;
489   wpt->gear_down = true;
490   wpt->flaps_down= true;
491   wpt->finished  = false;
492   wpt->on_ground = false;
493   waypoints.push_back(wpt); 
494
495
496
497   //Beginning of Decent
498   stationweather = ((FGEnvironmentMgr *)globals->get_subsystem("environment"))
499     ->getEnvironment(arr->latitude, arr->longitude, arr->elevation);
500
501   wind_speed = stationweather.get_wind_speed_kt();
502   wind_heading = stationweather.get_wind_from_heading_deg();
503
504   if (wind_speed == 0) {
505     wind_heading = 270; // This forces West-facing rwys to be used in no-wind situations
506                         // which is consistent with Flightgear's initial setup.
507   }
508
509   rwy_no = globals->get_runways()->search(arr->id, int(wind_heading));
510   //cout << "Using runway # " << rwy_no << " for departure at " << dep->id << endl;
511   
512    if (!(globals->get_runways()->search(arr->id, (int) wind_heading, &rwy )))
513     {
514       cout << "Failed to find runway for " << arr->id << endl;
515       // Hmm, how do we handle a potential error like this?
516       exit(1);
517     }
518   //cerr << "Done" << endl;
519  heading = rwy.heading;
520  azimuth = heading + 180.0;
521  while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
522
523  
524
525  geo_direct_wgs_84 ( 0, rwy.lat, rwy.lon, azimuth, 
526                      100000,
527                      &lat2, &lon2, &az2 );
528   wpt = new waypoint;
529   wpt->name      = "BOD"; //wpt_node->getStringValue("name", "END");
530   wpt->latitude  = lat2;
531   wpt->longitude = lon2;
532   wpt->altitude  = 10000;
533   wpt->speed     = speed; 
534   wpt->crossat   = alt +19;
535   wpt->gear_down = false;
536   wpt->flaps_down= false;
537   wpt->finished  = false;
538   wpt->on_ground = false;
539   waypoints.push_back(wpt); 
540
541   // Ten thousand ft. Slowing down to 240 kts
542   geo_direct_wgs_84 ( 0, rwy.lat, rwy.lon, azimuth, 
543                      20*SG_NM_TO_METER,
544                      &lat2, &lon2, &az2 );
545   wpt = new waypoint;
546   wpt->name      = "Dec 10000ft"; //wpt_node->getStringValue("name", "END");
547   wpt->latitude  = lat2;
548   wpt->longitude = lon2;
549   wpt->altitude  = arr->elevation + 19;
550   wpt->speed     = 240; 
551   wpt->crossat   = 10000;
552   wpt->gear_down = false;
553   wpt->flaps_down= false;
554   wpt->finished  = false;
555   wpt->on_ground = false;
556   waypoints.push_back(wpt);  
557
558   // Three thousand ft. Slowing down to 160 kts
559   geo_direct_wgs_84 ( 0, rwy.lat, rwy.lon, azimuth, 
560                      8*SG_NM_TO_METER,
561                      &lat2, &lon2, &az2 );
562   wpt = new waypoint;
563   wpt->name      = "DEC 3000ft"; //wpt_node->getStringValue("name", "END");
564   wpt->latitude  = lat2;
565   wpt->longitude = lon2;
566   wpt->altitude  = arr->elevation + 19;
567   wpt->speed     = 160; 
568   wpt->crossat   = 3000;
569   wpt->gear_down = true;
570   wpt->flaps_down= true;
571   wpt->finished  = false;
572   wpt->on_ground = false;
573   waypoints.push_back(wpt); 
574   //Runway Threshold
575  geo_direct_wgs_84 ( 0, rwy.lat, rwy.lon, azimuth, 
576                      rwy.length*0.45 * SG_FEET_TO_METER,
577                      &lat2, &lon2, &az2 );
578   wpt = new waypoint;
579   wpt->name      = "Threshold"; //wpt_node->getStringValue("name", "END");
580   wpt->latitude  = lat2;
581   wpt->longitude = lon2;
582   wpt->altitude  = arr->elevation + 19;
583   wpt->speed     = 15; 
584   wpt->crossat   = arr->elevation + 19;
585   wpt->gear_down = true;
586   wpt->flaps_down= true;
587   wpt->finished  = false;
588   wpt->on_ground = true;
589   waypoints.push_back(wpt); 
590
591  //Full stop at the runway centerpoint
592  geo_direct_wgs_84 ( 0, rwy.lat, rwy.lon, azimuth, 
593                      rwy.length*0.45,
594                      &lat2, &lon2, &az2 );
595   wpt = new waypoint;
596   wpt->name      = "Center"; //wpt_node->getStringValue("name", "END");
597   wpt->latitude  = rwy.lat;
598   wpt->longitude = rwy.lon;
599   wpt->altitude  = arr->elevation + 19;
600   wpt->speed     = 15; 
601   wpt->crossat   = -10000;
602   wpt->gear_down = true;
603   wpt->flaps_down= true;
604   wpt->finished  = false;
605   wpt->on_ground = true;
606   waypoints.push_back(wpt); 
607
608 direction = (rand() % 360);
609 geo_direct_wgs_84 ( 0, arr->latitude, arr->longitude, direction, 
610   100,
611   &lat2, &lon2, &az2 );
612
613   // Add the final destination waypoint
614   wpt = new waypoint;
615   wpt->name      = arr->id; //wpt_node->getStringValue("name", "END");
616   wpt->latitude  = lat2;
617   wpt->longitude = lon2;
618   wpt->altitude  = arr->elevation+19;
619   wpt->speed     = 15; 
620   wpt->crossat   = -10000;
621   wpt->gear_down = true;
622   wpt->flaps_down= true;
623   wpt->finished  = false;
624   wpt->on_ground = true;
625   waypoints.push_back(wpt); 
626
627   // And finally one more named "END"
628   wpt = new waypoint;
629   wpt->name      = "END"; //wpt_node->getStringValue("name", "END");
630   wpt->latitude  = lat2;
631   wpt->longitude = lon2;
632   wpt->altitude  = 19;
633   wpt->speed     = 15; 
634   wpt->crossat   = -10000;
635   wpt->gear_down = true;
636   wpt->flaps_down= true;
637   wpt->finished  = true;
638   wpt->on_ground = true;
639   waypoints.push_back(wpt);
640
641  // And finally one more named "EOF"
642   wpt = new waypoint;
643   wpt->name      = "EOF"; //wpt_node->getStringValue("name", "END");
644   wpt->latitude  = lat2;
645   wpt->longitude = lon2;
646   wpt->altitude  = 19;
647   wpt->speed     = 15; 
648   wpt->crossat   = -10000;
649   wpt->gear_down = true;
650   wpt->flaps_down= true;
651   wpt->finished  = true;
652   wpt->on_ground  = true;
653   waypoints.push_back(wpt);
654 }