]> git.mxchange.org Git - flightgear.git/blob - src/Traffic/Schedule.cxx
James Turner:
[flightgear.git] / src / Traffic / Schedule.cxx
1 /******************************************************************************
2  * Schedule.cxx
3  * Written by Durk Talsma, started May 5, 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  ****************************************************************************
21  *
22  *****************************************************************************/
23
24 #ifdef HAVE_CONFIG_H
25 #  include "config.h"
26 #endif
27
28 #define BOGUS 0xFFFF
29
30 #include <stdlib.h>
31 #include <time.h>
32 #include <iostream>
33 #include <fstream>
34
35
36 #include <string>
37 #include <vector>
38 #include <algorithm>
39
40 #include <plib/sg.h>
41
42 #include <simgear/compiler.h>
43 #include <simgear/math/polar3d.hxx>
44 #include <simgear/math/sg_geodesy.hxx>
45 #include <simgear/props/props.hxx>
46 #include <simgear/route/waypoint.hxx>
47 #include <simgear/structure/subsystem_mgr.hxx>
48 #include <simgear/xml/easyxml.hxx>
49
50 #include <AIModel/AIFlightPlan.hxx>
51 #include <AIModel/AIManager.hxx>
52 #include <AIModel/AIAircraft.hxx>
53 #include <Airports/simple.hxx>
54 #include <Main/fg_init.hxx>   // That's pretty ugly, but I need fgFindAirportID
55
56
57 #include "SchedFlight.hxx"
58 #include "TrafficMgr.hxx"
59
60 using std::sort;
61
62 /******************************************************************************
63  * the FGAISchedule class contains data members and code to maintain a
64  * schedule of Flights for an articically controlled aircraft. 
65  *****************************************************************************/
66 FGAISchedule::FGAISchedule()
67 {
68   firstRun     = true;
69   AIManagerRef = 0;
70
71   heavy = false;
72   lat = 0;
73   lon = 0;
74   radius = 0;
75   groundOffset = 0;
76   distanceToUser = 0;
77   //score = 0;
78 }
79
80 /*
81 FGAISchedule::FGAISchedule(string    mdl, 
82                            string    liv, 
83                            string    reg, 
84                            bool      hvy, 
85                            string act, 
86                            string arln, 
87                            string mclass, 
88                            string fltpe,
89                            double rad,
90                            double grnd,
91                            int    scre,
92                            FGScheduledFlightVec flt)*/
93 FGAISchedule::FGAISchedule(string model, 
94                            string lvry,
95                            string port, 
96                            string reg, 
97                            string flightId,
98                            bool   hvy, 
99                            string act, 
100                            string arln, 
101                            string mclass, 
102                            string fltpe, 
103                            double rad, 
104                            double grnd)
105 {
106   modelPath        = model; 
107   livery           = lvry; 
108   homePort         = port;
109   registration     = reg;
110   flightIdentifier = flightId;
111   acType           = act;
112   airline          = arln;
113   m_class          = mclass;
114   flightType       = fltpe;
115   lat              = 0;
116   lon              = 0;
117   radius           = rad;
118   groundOffset     = grnd;
119   distanceToUser   = 0;
120   heavy            = hvy;
121   /*for (FGScheduledFlightVecIterator i = flt.begin();
122        i != flt.end();
123        i++)
124     flights.push_back(new FGScheduledFlight((*(*i))));*/
125   AIManagerRef     = 0;
126   //score    = scre;
127   firstRun         = true;
128 }
129
130 FGAISchedule::FGAISchedule(const FGAISchedule &other)
131 {
132   modelPath          = other.modelPath;
133   homePort           = other.homePort;
134   livery             = other.livery;
135   registration       = other.registration;
136   heavy              = other.heavy;
137   flightIdentifier   = other.flightIdentifier;
138   flights            = other.flights;
139   lat                = other.lat;
140   lon                = other.lon;
141   AIManagerRef       = other.AIManagerRef;
142   acType             = other.acType;
143   airline            = other.airline;
144   m_class            = other.m_class;
145   firstRun           = other.firstRun;
146   radius             = other.radius;
147   groundOffset       = other.groundOffset;
148   flightType         = other.flightType;
149   //score            = other.score;
150   distanceToUser     = other.distanceToUser;
151   currentDestination = other.currentDestination;
152   firstRun           = other.firstRun;
153 }
154
155
156 FGAISchedule::~FGAISchedule()
157 {
158 /*  for (FGScheduledFlightVecIterator flt = flights.begin(); flt != flights.end(); flt++)
159     {
160       delete (*flt);
161     }
162   flights.clear();*/
163
164
165 bool FGAISchedule::init()
166 {
167   //tm targetTimeDate;
168   //SGTime* currTimeDate = globals->get_time_params();
169
170   //tm *temp = currTimeDate->getGmt();
171   //char buffer[512];
172   //sgTimeFormatTime(&targetTimeDate, buffer);
173   //cout << "Scheduled Time " << buffer << endl; 
174   //cout << "Time :" << time(NULL) << " SGTime : " << sgTimeGetGMT(temp) << endl;
175   /*for (FGScheduledFlightVecIterator i = flights.begin(); 
176        i != flights.end(); 
177        i++)
178     {
179       //i->adjustTime(now);
180       if (!((*i)->initializeAirports()))
181         return false;
182     } */
183   //sort(flights.begin(), flights.end());
184   // Since time isn't initialized yet when this function is called,
185   // Find the closest possible airport.
186   // This should give a reasonable initialization order. 
187   //setClosestDistanceToUser();
188   return true;
189 }
190
191 bool FGAISchedule::update(time_t now)
192
193   FGAirport *dep;
194   FGAirport *arr;
195   double angle;
196
197   FGAIManager *aimgr;
198   string airport;
199   
200   double courseToUser,   courseToDest;
201   double distanceToDest;
202   double speed;
203
204   time_t 
205     totalTimeEnroute, 
206     elapsedTimeEnroute,
207     remainingTimeEnroute, deptime = 0;
208   double
209     userLatitude,
210     userLongitude;
211
212   if (fgGetBool("/sim/traffic-manager/enabled") == false)
213     return true;
214   
215   aimgr = (FGAIManager *) globals-> get_subsystem("ai_model");  
216     // Out-of-work aircraft seeks employment. Willing to work irregular hours ...
217     //cerr << "About to find a flight " << endl;
218     if (flights.empty()) {
219         //execute this loop at least once. 
220         SG_LOG(SG_GENERAL, SG_INFO, "Scheduling for : " << modelPath << " " <<  registration << " " << homePort);
221         FGScheduledFlight *flight = 0;
222          do {
223             flight = findAvailableFlight(currentDestination, flightIdentifier);
224             if (flight) {
225                 currentDestination = flight->getArrivalAirport()->getId();
226                 time_t arr, dep;
227                 dep = flight->getDepartureTime();
228                 arr = flight->getArrivalTime();
229                 string depT = asctime(gmtime(&dep));
230                 string arrT = asctime(gmtime(&arr));
231
232                 depT = depT.substr(0,24);
233                 arrT = arrT.substr(0,24);
234                 SG_LOG(SG_GENERAL, SG_INFO, "  " << flight->getCallSign() << ":" 
235                                          << "  " << flight->getDepartureAirport()->getId() << ":"
236                                          << "  " << depT << ":"
237                                          << " \"" << flight->getArrivalAirport()->getId() << "\"" << ":"
238                                          << "  " << arrT << ":");
239             flights.push_back(flight);
240             }
241         } while ((currentDestination != homePort) && (flight != 0));
242         SG_LOG(SG_GENERAL, SG_INFO, cerr << " Done " << endl);
243     }
244     //cerr << " Done " << endl;
245    // No flights available for this aircraft
246   if (flights.size() == 0) {
247       return false;
248   }
249   // Sort all the scheduled flights according to scheduled departure time.
250   // Because this is done at every update, we only need to check the status
251   // of the first listed flight. 
252   //sort(flights.begin(), flights.end(), compareScheduledFlights);
253  if (firstRun) {
254      if (fgGetBool("/sim/traffic-manager/instantaneous-action") == true) {
255          deptime = now + rand() % 300; // Wait up to 5 minutes until traffic starts moving to prevent too many aircraft 
256                                    // from cluttering the gate areas.
257          cerr << "Scheduling " << registration << " for instantaneous action flight " << endl;
258      }
259      firstRun = false;
260   }
261   if (!deptime)
262     deptime = (*flights.begin())->getDepartureTime();
263   FGScheduledFlightVecIterator i = flights.begin();
264   SG_LOG (SG_GENERAL, SG_DEBUG,"Traffic Manager: Processing registration " << registration << " with callsign " << (*i)->getCallSign());
265   if (AIManagerRef)
266     {
267       // Check if this aircraft has been released. 
268       FGTrafficManager *tmgr = (FGTrafficManager *) globals->get_subsystem("Traffic Manager");
269       if (tmgr->isReleased(AIManagerRef))
270         AIManagerRef = 0;
271     }
272
273   if (!AIManagerRef)
274     {
275       userLatitude  = fgGetDouble("/position/latitude-deg");
276       userLongitude = fgGetDouble("/position/longitude-deg");
277
278       //cerr << "Estimated minimum distance to user: " << distanceToUser << endl;
279       // This flight entry is entirely in the past, do we need to 
280       // push it forward in time to the next scheduled departure. 
281       if (((*i)->getDepartureTime() < now) && ((*i)->getArrivalTime() < now))
282         {
283           SG_LOG (SG_GENERAL, SG_DEBUG, "Traffic Manager:      Flight is in the Past");
284           //cerr << modelPath << " " <<  registration << ": Flights from the past belong to the past :-)" << endl;
285           //exit(1);
286           // Don't just update: check whether we need to load a new leg. etc.
287           // This update occurs for distant aircraft, so we can update the current leg
288           // and detach it from the current list of aircraft. 
289           (*i)->update();
290           i = flights.erase(i);
291           return true;
292         }
293
294       // Departure time in the past and arrival time in the future.
295       // This flight is in progress, so we need to calculate it's
296       // approximate position and -if in range- create an AIAircraft
297       // object for it. 
298       //if ((i->getDepartureTime() < now) && (i->getArrivalTime() > now))
299       
300       // Part of this flight is in the future.
301       if ((*i)->getArrivalTime() > now)
302         {
303           
304           dep = (*i)->getDepartureAirport();
305           arr = (*i)->getArrivalAirport  ();
306           if (!(dep && arr))
307             return false;
308           
309           SGVec3d a = SGVec3d::fromGeoc(SGGeoc::fromDegM(dep->getLongitude(),
310                                                 dep->getLatitude(), 1));
311           SGVec3d b = SGVec3d::fromGeoc(SGGeoc::fromDegM(arr->getLongitude(),
312                                                 arr->getLatitude(), 1));
313           SGVec3d _cross = cross(b, a);
314           
315           angle = sgACos(dot(a, b));
316           
317           // Okay, at this point we have the angle between departure and 
318           // arrival airport, in degrees. From here we can interpolate the
319           // position of the aircraft by calculating the ratio between 
320           // total time enroute and elapsed time enroute. 
321  
322           totalTimeEnroute     = (*i)->getArrivalTime() - (*i)->getDepartureTime();
323           if (now > (*i)->getDepartureTime())
324             {
325               //err << "Lat = " << lat << ", lon = " << lon << endl;
326               //cerr << "Time diff: " << now-i->getDepartureTime() << endl;
327               elapsedTimeEnroute   = now - (*i)->getDepartureTime();
328               remainingTimeEnroute = (*i)->getArrivalTime()   - now;  
329               SG_LOG (SG_GENERAL, SG_DEBUG, "Traffic Manager:      Flight is in progress.");
330             }
331           else
332             {
333               lat = dep->getLatitude();
334               lon = dep->getLongitude();
335               elapsedTimeEnroute = 0;
336               remainingTimeEnroute = totalTimeEnroute;
337               SG_LOG (SG_GENERAL, SG_DEBUG, "Traffic Manager:      Flight is pending.");
338             }
339                   
340           angle *= ( (double) elapsedTimeEnroute/ (double) totalTimeEnroute);
341           
342           
343           //cout << "a = " << a[0] << " " << a[1] << " " << a[2] 
344           //     << "b = " << b[0] << " " << b[1] << " " << b[2] << endl;  
345           sgdMat4 matrix;
346           sgdMakeRotMat4(matrix, angle, _cross.sg()); 
347           SGVec3d newPos(0, 0, 0);
348           for(int j = 0; j < 3; j++)
349             {
350               for (int k = 0; k<3; k++)
351                 {
352                   newPos[j] += matrix[j][k]*a[k];
353                 }
354             }
355           
356           if (now > (*i)->getDepartureTime())
357             {
358               SGGeoc geoc = SGGeoc::fromCart(newPos);
359               lat = geoc.getLatitudeDeg();
360               lon = geoc.getLongitudeDeg(); 
361             }
362           else
363             {
364               lat = dep->getLatitude();
365               lon = dep->getLongitude();
366             }
367           
368           
369           SGWayPoint current  (lon,
370                                lat,
371                                (*i)->getCruiseAlt(), 
372                                SGWayPoint::SPHERICAL);
373           SGWayPoint user (   userLongitude,
374                               userLatitude,
375                               (*i)->getCruiseAlt(), 
376                               SGWayPoint::SPHERICAL);
377           SGWayPoint dest (   arr->getLongitude(),
378                               arr->getLatitude(),
379                               (*i)->getCruiseAlt(), 
380                               SGWayPoint::SPHERICAL);
381           // We really only need distance to user
382           // and course to destination 
383           user.CourseAndDistance(current, &courseToUser, &distanceToUser);
384           dest.CourseAndDistance(current, &courseToDest, &distanceToDest);
385           speed =  (distanceToDest*SG_METER_TO_NM) / 
386             ((double) remainingTimeEnroute/3600.0);
387           
388
389           // If distance between user and simulated aircaft is less
390           // then 500nm, create this flight. At jet speeds 500 nm is roughly
391           // one hour flight time, so that would be a good approximate point
392           // to start a more detailed simulation of this aircraft.
393           SG_LOG (SG_GENERAL, SG_DEBUG, "Traffic manager: " << registration << " is scheduled for a flight from " 
394              << dep->getId() << " to " << arr->getId() << ". Current distance to user: " 
395              << distanceToUser*SG_METER_TO_NM);
396           if ((distanceToUser*SG_METER_TO_NM) < TRAFFICTOAIDISTTOSTART)
397             {
398               string flightPlanName = dep->getId() + string("-") + arr->getId() + 
399                 string(".xml");
400               SG_LOG (SG_GENERAL, SG_DEBUG, "Traffic manager: Creating AIModel");
401               //int alt;
402               //if  ((i->getDepartureTime() < now))
403               //{
404               //          alt = i->getCruiseAlt() *100;
405               //        }
406               //else
407               //{
408               //          alt = dep->_elevation+19;
409               //        }
410
411               // Only allow traffic to be created when the model path (or the AI version of mp) exists
412               SGPath mp(globals->get_fg_root());
413               SGPath mp_ai = mp;
414
415               mp.append(modelPath);
416               mp_ai.append("AI");
417               mp_ai.append(modelPath);
418
419               if (mp.exists() || mp_ai.exists())
420               {
421                   FGAIAircraft *aircraft = new FGAIAircraft(this);
422                   aircraft->setPerformance(m_class); //"jet_transport";
423                   aircraft->setCompany(airline); //i->getAirline();
424                   aircraft->setAcType(acType); //i->getAcType();
425                   aircraft->setPath(modelPath.c_str());
426                   //aircraft->setFlightPlan(flightPlanName);
427                   aircraft->setLatitude(lat);
428                   aircraft->setLongitude(lon);
429                   aircraft->setAltitude((*i)->getCruiseAlt()*100); // convert from FL to feet
430                   aircraft->setSpeed(speed);
431                   aircraft->setBank(0);
432                   aircraft->SetFlightPlan(new FGAIFlightPlan(flightPlanName, courseToDest, deptime, 
433                                                              dep, arr,true, radius, 
434                                                              (*i)->getCruiseAlt()*100, 
435                                                              lat, lon, speed, flightType, acType, 
436                                                              airline));
437                   aimgr->attach(aircraft);
438                   
439                   
440                   AIManagerRef = aircraft->getID();
441                   //cerr << "Class: " << m_class << ". acType: " << acType << ". Airline: " << airline << ". Speed = " << speed << ". From " << dep->getId() << " to " << arr->getId() << ". Time Fraction = " << (remainingTimeEnroute/(double) totalTimeEnroute) << endl;
442                   //cerr << "Latitude : " << lat << ". Longitude : " << lon << endl;
443                   //cerr << "Dep      : " << dep->getLatitude()<< ", "<< dep->getLongitude() << endl;
444                   //cerr << "Arr      : " << arr->getLatitude()<< ", "<< arr->getLongitude() << endl;
445                   //cerr << "Time remaining = " << (remainingTimeEnroute/3600.0) << endl;
446                   //cerr << "Total time     = " << (totalTimeEnroute/3600.0) << endl;
447                   //cerr << "Distance remaining = " << distanceToDest*SG_METER_TO_NM << endl;
448                   }
449               else
450                 {
451                   SG_LOG(SG_INPUT, SG_WARN, "TrafficManager: Could not load model " << mp.str());
452                 }
453             }
454           return true;
455     }
456
457       // Both departure and arrival time are in the future, so this
458       // the aircraft is parked at the departure airport.
459       // Currently this status is mostly ignored, but in future
460       // versions, code should go here that -if within user range-
461       // positions these aircraft at parking locations at the airport.
462       if (((*i)->getDepartureTime() > now) && ((*i)->getArrivalTime() > now))
463         { 
464           dep = (*i)->getDepartureAirport();
465           return true;
466         } 
467     }
468   //cerr << "Traffic schedule got to beyond last clause" << endl;
469     // EMH: prevent a warning, should this be 'true' instead?
470     // DT: YES. Originally, this code couldn't be reached, but
471     // when the "if(!(AIManagerManager))" clause is false we
472     // fall through right to the end. This is a valid flow.
473     // the actual value is pretty innocent, only it triggers
474     // warning in TrafficManager::update().
475     // (which was added as a sanity check for myself in the first place. :-)
476     return true;
477 }
478
479
480 bool FGAISchedule::next()
481 {
482   FGScheduledFlightVecIterator i = flights.begin();
483   (*i)->release();
484   //FIXME: remove first entry, 
485   // load new flights until back at home airport
486   // Lock loaded flights
487   //sort(flights.begin(), flights.end(), compareScheduledFlights);
488   // until that time
489   i = flights.erase(i);
490   //cerr << "Next: scheduling for : " << modelPath << " " <<  registration << endl;
491   FGScheduledFlight *flight = findAvailableFlight(currentDestination, flightIdentifier);
492   if (flight) {
493       currentDestination = flight->getArrivalAirport()->getId();
494       time_t arr, dep;
495       dep = flight->getDepartureTime();
496       arr = flight->getArrivalTime();
497       string depT = asctime(gmtime(&dep));
498       string arrT = asctime(gmtime(&arr));
499
500       depT = depT.substr(0,24);
501       arrT = arrT.substr(0,24);
502       //cerr << "  " << flight->getCallSign() << ":" 
503       //     << "  " << flight->getDepartureAirport()->getId() << ":"
504       //     << "  " << depT << ":"
505       //     << " \"" << flight->getArrivalAirport()->getId() << "\"" << ":"
506       //     << "  " << arrT << ":" << endl;
507
508        flights.push_back(flight);
509        return true;
510   } else {
511        return false;
512   }
513   //cerr << "FGAISchedule :: next needs updating" << endl;
514   //exit(1);
515 }
516
517 FGScheduledFlight* FGAISchedule::findAvailableFlight (const string &currentDestination,
518                                                       const string &req)
519 {
520     time_t now = time(NULL) + fgGetLong("/sim/time/warp");
521
522     FGTrafficManager *tmgr = (FGTrafficManager *) globals->get_subsystem("Traffic Manager");
523     FGScheduledFlightVecIterator fltBegin, fltEnd;
524     fltBegin = tmgr->getFirstFlight(req);
525     fltEnd   = tmgr->getLastFlight(req);
526
527
528      //cerr << "Finding available flight " << endl;
529      // For Now:
530      // Traverse every registered flight
531      if (fltBegin == fltEnd) {
532           //cerr << "No Flights Scheduled for " << req << endl;
533      }
534      int counter = 0;
535      for (FGScheduledFlightVecIterator i = fltBegin; i != fltEnd; i++) {
536           (*i)->adjustTime(now);
537            //sort(fltBegin, fltEnd, compareScheduledFlights);
538            //cerr << counter++ << endl;
539      }
540      sort(fltBegin, fltEnd, compareScheduledFlights);
541      for (FGScheduledFlightVecIterator i = fltBegin; i != fltEnd; i++) {
542           //bool valid = true;
543           counter++;
544           if (!(*i)->isAvailable()) {
545                //cerr << (*i)->getCallSign() << "is no longer available" << endl;
546                continue;
547           }
548           if (!((*i)->getRequirement() == req)) {
549                continue;
550           }
551           if (!(((*i)->getArrivalAirport()) && ((*i)->getDepartureAirport()))) {
552               continue;
553           }
554           if (!(currentDestination.empty())) {
555               if (currentDestination != (*i)->getDepartureAirport()->getId()) {
556                    //cerr << (*i)->getCallSign() << "Doesn't match destination" << endl;
557                    //cerr << "Current Destination " << currentDestination << "Doesnt match flight's " <<
558                    //          (*i)->getArrivalAirport()->getId() << endl;
559                    continue;
560               }
561           }
562           //TODO: check time
563           // So, if we actually get here, we have a winner
564           //cerr << "found flight: " << req << " : " << currentDestination << " : " <<       
565           //         (*i)->getArrivalAirport()->getId() << endl;
566           (*i)->lock();
567           return (*i);
568      }
569      // matches req?
570      // if currentDestination has a value, does it match departure of next flight?
571      // is departure time later than planned arrival?
572      // is departure port valid?
573      // is arrival port valid?
574      //cerr << "Ack no flight found: " << endl;
575      return 0;
576 }
577
578 double FGAISchedule::getSpeed()
579 {
580   double courseToDest;
581   double distanceToDest;
582   double speed, remainingTimeEnroute;
583   FGAirport *dep, *arr;
584
585   FGScheduledFlightVecIterator i = flights.begin();
586   dep = (*i)->getDepartureAirport();
587   arr = (*i)->getArrivalAirport  ();
588   if (!(dep && arr))
589     return 0;
590  
591   SGWayPoint dest (   dep->getLongitude(),
592                       dep->getLatitude(),
593                       (*i)->getCruiseAlt(), 
594                       SGWayPoint::SPHERICAL); 
595   SGWayPoint curr (    arr->getLongitude(),
596                       arr->getLatitude(),
597                        (*i)->getCruiseAlt(), 
598                        SGWayPoint::SPHERICAL);
599   remainingTimeEnroute     = (*i)->getArrivalTime() - (*i)->getDepartureTime();
600   dest.CourseAndDistance(curr, &courseToDest, &distanceToDest);
601   speed =  (distanceToDest*SG_METER_TO_NM) / 
602     ((double) remainingTimeEnroute/3600.0);
603   if (speed < 300) {
604      //cerr << "Warning : calculated speed for " << (*i)->getCallSign() << " is low : " << speed << " clamping to 300" << endl;
605      speed = 300.0;
606   }
607   if (speed > 500) {
608      //cerr << "Warning : calculated speed for " << (*i)->getCallSign() << " is high : " << speed << " clamping to 300" << endl;
609      speed = 500.0;
610   }
611   return speed;
612 }
613 /*
614 bool compareSchedules(FGAISchedule*a, FGAISchedule*b)
615
616   //return (*a) < (*b); 
617
618 */
619
620 // void FGAISchedule::setClosestDistanceToUser()
621 // {
622   
623   
624 //   double course;
625 //   double dist;
626
627 //   Point3D temp;
628 //   time_t 
629 //     totalTimeEnroute, 
630 //     elapsedTimeEnroute;
631  
632 //   double userLatitude  = fgGetDouble("/position/latitude-deg");
633 //   double userLongitude = fgGetDouble("/position/longitude-deg");
634
635 //   FGAirport *dep;
636   
637 // #if defined( __CYGWIN__) || defined( __MINGW32__)
638 //   #define HUGE HUGE_VAL
639 // #endif
640 //   distanceToUser = HUGE;
641 //   FGScheduledFlightVecIterator i = flights.begin();
642 //   while (i != flights.end())
643 //     {
644 //       dep = i->getDepartureAirport();
645 //       //if (!(dep))
646 //       //return HUGE;
647       
648 //       SGWayPoint user (   userLongitude,
649 //                        userLatitude,
650 //                        i->getCruiseAlt());
651 //       SGWayPoint current (dep->getLongitude(),
652 //                        dep->getLatitude(),
653 //                        0);
654 //       user.CourseAndDistance(current, &course, &dist);
655 //       if (dist < distanceToUser)
656 //      {
657 //        distanceToUser = dist;
658 //        //cerr << "Found closest distance to user for " << registration << " to be " << distanceToUser << " at airport " << dep->getId() << endl;
659 //      }
660 //       i++;
661 //     }
662 //   //return distToUser;
663 // }
664