]> git.mxchange.org Git - flightgear.git/commitdiff
Another clean-up iteration: FGAirportList::search is gone, replaced by two
authorjmt <jmt>
Fri, 26 Dec 2008 15:26:42 +0000 (15:26 +0000)
committerjmt <jmt>
Fri, 26 Dec 2008 15:26:42 +0000 (15:26 +0000)
static FGAirport helpers. As a result, another global index goes away. Use
the helpers to avoid ugly FGPositioned down-casts in various places.

Also converts the environment/METAR code to deal with FGAirport pointers,
instead of string identifiers, and contains work-in-progress code to implement
the AirportList dialog using FGPositioned. This isn't enabled yet for various
reasons, but is the final piece to allow FGAirportList to be removed.

src/Airports/apt_loader.cxx
src/Airports/simple.cxx
src/Airports/simple.hxx
src/Environment/environment_ctrl.cxx
src/Environment/environment_ctrl.hxx
src/Environment/fgclouds.cxx
src/Instrumentation/mk_viii.cxx
src/Navaids/positioned.cxx
src/Scripting/NasalSys.cxx
src/Traffic/SchedFlight.cxx

index 92495181a7ea5ec08fcbd277c8f9d5176f0a8899..d0602ac69c5c5c379a54d8c857e309e7b40603cf 100644 (file)
@@ -289,8 +289,10 @@ bool fgAirportDBLoad( FGAirportList *airports,
         if ( ident == "#" || ident == "//" ) {
             metar_in >> skipeol;
         } else {
-            const FGAirport* a = airports->search( ident );
-            if ( a ) const_cast<FGAirport*>(a)->setMetar(true);
+            FGAirport* apt = FGAirport::findByIdent(ident);
+            if (apt) {
+                apt->setMetar(true);
+            }
         }
     }
 
index e7b9a48d88344448732bfdc53c8e55b932ab1f0d..af1e0de195e04eb42219494a52aaed80ce140e6d 100644 (file)
@@ -52,8 +52,8 @@
 using std::sort;
 using std::random_shuffle;
 
-
-
+// magic import of a helper which uses FGPositioned internals
+extern char** searchAirportNamesAndIdents(const std::string& aFilter);
 
 /***************************************************************************
  * FGAirport
@@ -279,32 +279,41 @@ bool FGAirport::HardSurfaceFilter::pass(FGPositioned* aPos) const
   return static_cast<FGAirport*>(aPos)->hasHardRunwayOfLengthFt(mMinLengthFt);
 }
 
+FGAirport* FGAirport::findByIdent(const std::string& aIdent)
+{
+  FGPositionedRef r;
+  AirportFilter filter;
+  r = FGPositioned::findNextWithPartialId(r, aIdent, &filter);
+  if (!r) {
+    return NULL; // we don't warn here, let the caller do that
+  }
+  return static_cast<FGAirport*>(r.ptr());
+}
+
+FGAirport* FGAirport::getByIdent(const std::string& aIdent)
+{
+  FGPositionedRef r;
+  AirportFilter filter;
+  r = FGPositioned::findNextWithPartialId(r, aIdent, &filter);
+  if (!r) {
+    throw sg_range_exception("No such airport with ident: " + aIdent);
+  }
+  return static_cast<FGAirport*>(r.ptr());
+}
+
+char** FGAirport::searchNamesAndIdents(const std::string& aFilter)
+{
+  // we delegate all the work to a horrible helper in FGPositioned, which can
+  // access the (private) index data.
+  return searchAirportNamesAndIdents(aFilter);
+}
+
 /******************************************************************************
  * FGAirportList
  *****************************************************************************/
 
-// Populates a list of subdirectories of $FG_ROOT/Airports/AI so that
-// the add() method doesn't have to try opening 2 XML files in each of
-// thousands of non-existent directories.  FIXME: should probably add
-// code to free this list after parsing of apt.dat is finished;
-// non-issue at the moment, however, as there are no AI subdirectories
-// in the base package.
-//
-// Note: 2005/12/23: This is probably not necessary anymore, because I'm
-// Switching to runtime airport dynamics loading (DT).
 FGAirportList::FGAirportList()
 {
-//     ulDir* d;
-//     ulDirEnt* dent;
-//     SGPath aid( globals->get_fg_root() );
-//     aid.append( "/Airports/AI" );
-//     if((d = ulOpenDir(aid.c_str())) == NULL)
-//         return;
-//     while((dent = ulReadDir(d)) != NULL) {
-//         SG_LOG( SG_GENERAL, SG_DEBUG, "Dent: " << dent->d_name );
-//         ai_dirs.insert(dent->d_name);
-//     }
-//     ulCloseDir(d);
 }
 
 
@@ -321,20 +330,11 @@ FGAirport* FGAirportList::add( const string &id, const SGGeod& location, const S
                          const string &name, bool has_metar, FGPositioned::Type aType)
 {
     FGAirport* a = new FGAirport(id, location, tower_location, name, has_metar, aType);
-    airports_by_id[a->getId()] = a;
     // try and read in an auxilary file
-
     airports_array.push_back( a );
     return a;
 }
 
-// search for the specified id
-FGAirport* FGAirportList::search( const string& id)
-{
-    airport_map_iterator itr = airports_by_id.find(id);
-    return (itr == airports_by_id.end() ? NULL : itr->second);
-}
-
 int
 FGAirportList::size () const
 {
@@ -354,26 +354,11 @@ const FGAirport *FGAirportList::getAirport( unsigned int index ) const
 // find basic airport location info from airport database
 const FGAirport *fgFindAirportID( const string& id)
 {
-    const FGAirport* result = NULL;
-    if ( id.length() ) {
-        SG_LOG( SG_GENERAL, SG_BULK, "Searching for airport code = " << id );
-
-        result = globals->get_airports()->search( id );
-
-        if ( result == NULL ) {
-            SG_LOG( SG_GENERAL, SG_ALERT,
-                    "Failed to find " << id << " in apt.dat.gz" );
-            return NULL;
-        }
-    } else {
+    if ( id.empty() ) {
         return NULL;
     }
-    SG_LOG( SG_GENERAL, SG_BULK,
-            "Position for " << id << " is ("
-            << result->getLongitude() << ", "
-            << result->getLatitude() << ")" );
-
-    return result;
+    
+    return FGAirport::findByIdent(id);
 }
 
 
index 8b2aaf10f30ab9c7ade17ed962c4da22f7e05250..6d95bcf87626a1fadbca11c60873fc3145580e00 100644 (file)
@@ -30,7 +30,6 @@
 #include <simgear/compiler.h>
 
 #include <string>
-#include <map>
 #include <vector>
 
 #include "Navaids/positioned.hxx"
@@ -123,6 +122,26 @@ public:
       * passes all airports, including seaports and heliports.
       */
      static FGAirport* findClosest(const SGGeod& aPos, double aCuttofNm, Filter* filter = NULL);
+     
+     /**
+      * Helper to look up an FGAirport instance by unique ident. Throws an 
+      * exception if the airport could not be found - so callers can assume
+      * the result is non-NULL.
+      */
+     static FGAirport* getByIdent(const std::string& aIdent);
+     
+     /**
+      * Helper to look up an FGAirport instance by unique ident. Returns NULL
+      * if the airport could not be found.
+      */
+     static FGAirport* findByIdent(const std::string& aIdent);
+     
+     /**
+      * Specialised helper to implement the AirportList dialog. Performs a
+      * case-insensitive search on airport names and ICAO codes, and returns
+      * matches in a format suitable for use by a puaList. 
+      */
+     static char** searchNamesAndIdents(const std::string& aFilter);
 private:
     typedef std::vector<FGRunwayPtr>::const_iterator Runway_iterator;
     /**
@@ -137,10 +156,6 @@ private:
     std::vector<FGRunwayPtr> mTaxiways;
 };
 
-typedef std::map < std::string, FGAirport* > airport_map;
-typedef airport_map::iterator airport_map_iterator;
-typedef airport_map::const_iterator const_airport_map_iterator;
-
 typedef std::vector < FGAirport * > airport_list;
 typedef airport_list::iterator airport_list_iterator;
 typedef airport_list::const_iterator const_airport_list_iterator;
@@ -150,7 +165,6 @@ typedef airport_list::const_iterator const_airport_list_iterator;
 class FGAirportList {
 private:
 
-    airport_map airports_by_id;
     airport_list airports_array;
 
 public:
@@ -164,10 +178,6 @@ public:
     FGAirport* add( const std::string& id, const SGGeod& location, const SGGeod& tower,
               const std::string& name, bool has_metar, FGPositioned::Type aType);
 
-    // search for the specified id.
-    // Returns NULL if unsucessfull.
-    FGAirport* search( const std::string& id );
-
     /**
      * Return the number of airports in the list.
      */
index e0844d81d068b205f2676d0f45ec18338c12a6fb..8fb0ad8fea53b57073ee4b8bc483dc547e720ae8 100644 (file)
@@ -336,7 +336,6 @@ FGInterpolateEnvironmentCtrl::bucket::lessThan(bucket *a, bucket *b)
 
 FGMetarEnvironmentCtrl::FGMetarEnvironmentCtrl ()
     : env( new FGInterpolateEnvironmentCtrl ),
-      _icao( "" ),
       metar_loaded( false ),
       search_interval_sec( 60.0 ),        // 1 minute
       same_station_interval_sec( 900.0 ), // 15 minutes
@@ -667,17 +666,16 @@ FGMetarEnvironmentCtrl::init ()
 
     while ( !found_metar && (_error_count < 3) ) {
         AirportWithMetar filter;
-        FGPositionedRef a = FGPositioned::findClosest(pos, 10000.0, &filter);
+        FGAirport* a = FGAirport::findClosest(pos, 10000.0, &filter);
         if (!a) {
           break;
         }
         
-        FGMetarResult result = fetch_data(a->ident());
+        FGMetarResult result = fetch_data(a);
         if ( result.m != NULL ) {
             SG_LOG( SG_GENERAL, SG_INFO, "closest station w/ metar = "
                     << a->ident());
             last_apt = a;
-            _icao = a->ident();
             search_elapsed = 0.0;
             fetch_elapsed = 0.0;
             update_metar_properties( result.m );
@@ -688,7 +686,7 @@ FGMetarEnvironmentCtrl::init ()
             // mark as no metar so it doesn't show up in subsequent
             // searches.
             SG_LOG( SG_GENERAL, SG_INFO, "no metar at metar = " << a->ident() );
-            static_cast<FGAirport*>(a.ptr())->setMetar(false);
+            a->setMetar(false);
         }
     } // of airprot-with-metar search iteration
     
@@ -729,16 +727,15 @@ FGMetarEnvironmentCtrl::update(double delta_time_sec)
     // queue
     if ( search_elapsed > search_interval_sec ) {
         AirportWithMetar filter;
-        FGPositionedRef a = FGPositioned::findClosest(pos, 10000.0, &filter);
+        FGAirport* a = FGAirport::findClosest(pos, 10000.0, &filter);
         if (a) {
           if ( !last_apt || last_apt->ident() != a->ident()
                  || fetch_elapsed > same_station_interval_sec )
             {
                 SG_LOG( SG_GENERAL, SG_INFO, "closest station w/ metar = "
                         << a->ident());
-                request_queue.push( a->ident() );
+                request_queue.push(a);
                 last_apt = a;
-                _icao = a->ident();
                 search_elapsed = 0.0;
                 fetch_elapsed = 0.0;
             } else {
@@ -760,15 +757,15 @@ FGMetarEnvironmentCtrl::update(double delta_time_sec)
 
 #if !defined(ENABLE_THREADS)
     // No loader thread running so manually fetch the data
-    string id = "";
+    FGAirport* apt = NULL;
     while ( !request_queue.empty() ) {
-        id = request_queue.front();
+        apt = request_queue.front();
         request_queue.pop();
     }
 
-    if ( !id.empty() ) {
-        SG_LOG( SG_GENERAL, SG_INFO, "inline fetching = " << id );
-        result = fetch_data( id );
+    if (apt) {
+        SG_LOG( SG_GENERAL, SG_INFO, "inline fetching = " << apt->ident() );
+        result = fetch_data( apt );
         result_queue.push( result );
     }
 #endif // ENABLE_THREADS
@@ -786,9 +783,8 @@ FGMetarEnvironmentCtrl::update(double delta_time_sec)
             // mark as no metar so it doesn't show up in subsequent
             // searches, and signal an immediate re-search.
             SG_LOG( SG_GENERAL, SG_WARN,
-                    "no metar at station = " << result.icao );
-            const FGAirport* apt = globals->get_airports()->search(result.icao);
-            const_cast<FGAirport*>(apt)->setMetar(false);
+                    "no metar at station = " << result.airport->ident() );
+            result.airport->setMetar(false);
             search_elapsed = 9999.0;
         }
     }
@@ -804,10 +800,10 @@ FGMetarEnvironmentCtrl::setEnvironment (FGEnvironment * environment)
 }
 
 FGMetarResult
-FGMetarEnvironmentCtrl::fetch_data( const string &icao )
+FGMetarEnvironmentCtrl::fetch_data(FGAirport* apt)
 {
     FGMetarResult result;
-    result.icao = icao;
+    result.airport = apt;
 
     // if the last error was more than three seconds ago,
     // then pretent nothing happened.
@@ -819,18 +815,14 @@ FGMetarEnvironmentCtrl::fetch_data( const string &icao )
         _error_count = 0;
     }
 
-    // fetch station elevation if exists
-    const FGAirport* a = globals->get_airports()->search( icao );
-    if ( a ) {
-        station_elevation_ft = a->getElevation();
-    }
+    station_elevation_ft = apt->getElevation();
 
     // fetch current metar data
     try {
         string host = proxy_host->getStringValue();
         string auth = proxy_auth->getStringValue();
         string port = proxy_port->getStringValue();
-        result.m = new FGMetar( icao, host, port, auth);
+        result.m = new FGMetar( apt->ident(), host, port, auth);
 
         long max_age = metar_max_age->getLongValue();
         long age = result.m->getAge_min();
index 9538548ec746d8ee0612f7857b3ee6d7ec1e0a46..b49610e328a998474d1adbf63ddf7b6f4c078f70 100644 (file)
@@ -137,7 +137,7 @@ private:
 
 // A convenience wrapper around FGMetar
 struct FGMetarResult {
-    std::string icao;
+    FGAirport* airport;
     FGMetar *m;
 };
 
@@ -160,7 +160,6 @@ public:
 private:
     FGInterpolateEnvironmentCtrl *env;
 
-    std::string _icao;
     bool metar_loaded;
     float station_elevation_ft;
     float search_interval_sec;
@@ -174,7 +173,7 @@ private:
     SGPropertyNode_ptr proxy_auth;
     SGPropertyNode_ptr metar_max_age;
 
-    FGMetarResult fetch_data( const string &icao );
+    FGMetarResult fetch_data(FGAirport* apt);
     virtual void update_metar_properties( const FGMetar *m );
     void update_env_config();
     double interpolate_prop(const char * currentname, const char * requiredname, double dvalue);
@@ -200,7 +199,7 @@ private:
     /**
      * FIFO queue which holds a pointer to the fetched metar data.
      */
-    SGBlockingQueue <std::string > request_queue;
+    SGBlockingQueue <FGAirport*> request_queue;
 
     /**
      * FIFO queue which holds a pointer to the fetched metar data.
@@ -210,7 +209,7 @@ private:
     /**
      * FIFO queue which holds a pointer to the fetched metar data.
      */
-    std::queue <std::string > request_queue;
+    std::queue <FGAirport*> request_queue;
 
     /**
      * FIFO queue which holds a pointer to the fetched metar data.
index 04e2dbe602c0a6423603be333648880f1985baf9..1a3897981592e0b9e506f187872b3f8aee9475b9 100644 (file)
@@ -464,7 +464,7 @@ void FGClouds::buildScenario( const string& scenario ) {
         if( station == "XXXX" )
             station_elevation_ft = fgGetDouble("/position/ground-elev-m", 0.0);
         else {
-            const FGAirport* a = globals->get_airports()->search( station );
+            const FGAirport* a = FGAirport::findByIdent(station);
             station_elevation_ft = (a ? a->getElevation() : 0.0);
         }
 
index 8908078c9d347dfd986e80d9b9363f0a9b5bfe55..50e1df1a75ec323c32597bd2166098ff9ccb593a 100755 (executable)
@@ -4521,7 +4521,7 @@ MK_VIII::TCFHandler::update_runway ()
   // large airports, which may have a runway located far away from
   // the airport's reference point.
   AirportFilter filter(mk);
-  FGPositionedRef apt = FGPositioned::findClosest(
+  FGAirport* apt = FGAirport::findClosest(
     SGGeod::fromDeg(mk_data(gps_longitude).get(), mk_data(gps_latitude).get()),
     30.0, &filter);
       
@@ -4529,7 +4529,7 @@ MK_VIII::TCFHandler::update_runway ()
   
          has_runway = true;
 
-         FGRunway* _runway = select_runway(static_cast<FGAirport*>(apt.ptr()));
+         FGRunway* _runway = select_runway(apt);
     
          runway.center.latitude = _runway->latitude();
          runway.center.longitude = _runway->longitude();
index 54bc57c4eb6ffa84ee7d623d78a5a3dd1d5f44a5..37445073976cb4b0c7576d709ff13e169b492668 100644 (file)
@@ -24,7 +24,8 @@
 
 #include <map>
 #include <set>
-#include <algorithm>
+#include <algorithm> // for sort
+#include <locale> // for char-traits toupper
 
 #include <iostream>
 
@@ -336,6 +337,78 @@ spatialGetClosest(const SGGeod& aPos, unsigned int aN, double aCutoffNm, FGPosit
   return result;
 }
 
+//////////////////////////////////////////////////////////////////////////////
+
+/**
+ * A special purpose helper (imported by FGAirport::searchNamesAndIdents) to
+ * implement the AirportList dialog. It's unfortunate that it needs to reside
+ * here, but for now it's least ugly solution.
+ */
+char** searchAirportNamesAndIdents(const std::string& aFilter)
+{
+  const std::ctype<char> &ct = std::use_facet<std::ctype<char> >(std::locale());
+  std::string filter(aFilter);
+  if (!filter.empty()) {
+    ct.toupper((char *)filter.data(), (char *)filter.data() + filter.size());
+  }
+  
+  NamedPositionedIndex::const_iterator it = global_namedIndex.begin();
+  NamedPositionedIndex::const_iterator end = global_namedIndex.end();
+  
+  FGPositioned::List matches;
+  if (aFilter.empty()) {
+    matches.reserve(2000);
+  }
+  
+  for (; it != end; ++it) {
+    FGPositioned::Type ty = it->second->type();
+    if ((ty < FGPositioned::AIRPORT) || (ty > FGPositioned::SEAPORT)) {
+      continue;
+    }
+    
+    if (aFilter.empty()) {
+      matches.push_back(it->second);
+      continue;
+    }
+    
+    if ((it->second->name().find(aFilter) == std::string::npos) &&
+        (it->second->ident().find(aFilter) == std::string::npos)) {
+      continue;
+    }
+    
+    matches.push_back(it->second);
+  }
+  
+  // convert results to format comptible with puaList
+  unsigned int numMatches = matches.size();
+  char** result = new char*[numMatches + 1];
+  result[numMatches] = NULL; // end-of-list marker
+  
+  // nasty code to avoid excessive string copying and allocations.
+  // We format results as follows (note whitespace!):
+  //   ' name-of-airport-chars   (icao)'
+  // so the total length is:
+  //    1 + strlen(name) + 4 + 4 (for the ICAO) + 1 + 1 (for the null)
+  // which gives a grand total of 11 + the length of the name.
+  
+  for (unsigned int i=0; i<numMatches; ++i) {
+    int nameLength = matches[i]->name().size();
+    char* entry = new char[nameLength + 11];
+    entry[0] = ' ';
+    memcpy(entry + 1, matches[i]->name().c_str(), nameLength);
+    entry[nameLength + 1] = ' ';
+    entry[nameLength + 2] = ' ';
+    entry[nameLength + 3] = ' ';
+    entry[nameLength + 4] = '(';
+    memcpy(entry + nameLength + 5, matches[i]->ident().c_str(), 4);
+    entry[nameLength + 9] = ')';
+    entry[nameLength + 10] = 0;
+    result[i] = entry;
+  }
+  
+  return result;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 FGPositioned::FGPositioned(Type ty, const std::string& aIdent, const SGGeod& aPos, bool aIndexed) :
index 61055ce4ebb6d475facaadb89fa9f51ca94f3a6a..af2d51c662a319bd47e82f817b5cfc56cf59593f 100644 (file)
@@ -524,7 +524,7 @@ static naRef f_airportinfo(naContext c, naRef me, int argc, naRef* args)
     static SGConstPropertyNode_ptr latn = fgGetNode("/position/latitude-deg", true);
     static SGConstPropertyNode_ptr lonn = fgGetNode("/position/longitude-deg", true);
     SGGeod pos;
-    FGPositionedRef ref;
+    FGAirport* apt = NULL;
     
     if(argc >= 2 && naIsNum(args[0]) && naIsNum(args[1])) {
         pos = SGGeod::fromDeg(args[1].num, args[0].num);
@@ -547,8 +547,8 @@ static naRef f_airportinfo(naContext c, naRef me, int argc, naRef* args)
         else if(!strcmp(s, "heliport")) filter.type = FGPositioned::HELIPORT;
         else {
             // user provided an <id>, hopefully
-            ref = globals->get_airports()->search(s);
-            if (!ref) {
+            apt = FGAirport::findByIdent(s);
+            if (!apt) {
                 naRuntimeError(c, "airportinfo() couldn't find airport:%s", s);
                 return naNil();
             }
@@ -558,13 +558,11 @@ static naRef f_airportinfo(naContext c, naRef me, int argc, naRef* args)
         return naNil();
     }
     
-    if (!ref) {
-        ref = FGPositioned::findClosest(pos, maxRange, &filter);
+    if (!apt) {
+        apt = FGAirport::findClosest(pos, maxRange, &filter);
+        if(!apt) return naNil();
     }
     
-    if(!ref) return naNil();
-    FGAirport *apt = static_cast<FGAirport*>(ref.ptr());
-    
     string id = apt->ident();
     string name = apt->name();
 
index 0fad5b88d7af7fd7f47d032661361bcd80ae47f5..56db6204cba1cba31b04cd9b3c1462584190046a 100644 (file)
@@ -271,13 +271,13 @@ FGAirport * FGScheduledFlight::getArrivalAirport  ()
 bool FGScheduledFlight::initializeAirports()
 {
   //cerr << "Initializing using : " << depId << " " << arrId << endl;
-  departurePort = globals->get_airports()->search(depId);
+  departurePort = FGAirport::findByIdent(depId);
   if(departurePort == NULL)
     {
       SG_LOG( SG_GENERAL, SG_WARN, "Traffic manager could not find departure airport : " << depId);
       return false;
     }
-  arrivalPort = globals->get_airports()->search(arrId);
+  arrivalPort = FGAirport::findByIdent(arrId);
   if(arrivalPort == NULL)
     {
       SG_LOG( SG_GENERAL, SG_WARN, "Traffic manager could not find arrival airport   : " << arrId);