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);
+ }
}
}
using std::sort;
using std::random_shuffle;
-
-
+// magic import of a helper which uses FGPositioned internals
+extern char** searchAirportNamesAndIdents(const std::string& aFilter);
/***************************************************************************
* FGAirport
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);
}
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
{
// 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);
}
#include <simgear/compiler.h>
#include <string>
-#include <map>
#include <vector>
#include "Navaids/positioned.hxx"
* 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;
/**
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;
class FGAirportList {
private:
- airport_map airports_by_id;
airport_list airports_array;
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.
*/
FGMetarEnvironmentCtrl::FGMetarEnvironmentCtrl ()
: env( new FGInterpolateEnvironmentCtrl ),
- _icao( "" ),
metar_loaded( false ),
search_interval_sec( 60.0 ), // 1 minute
same_station_interval_sec( 900.0 ), // 15 minutes
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 );
// 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
// 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 {
#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
// 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;
}
}
}
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.
_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();
// A convenience wrapper around FGMetar
struct FGMetarResult {
- std::string icao;
+ FGAirport* airport;
FGMetar *m;
};
private:
FGInterpolateEnvironmentCtrl *env;
- std::string _icao;
bool metar_loaded;
float station_elevation_ft;
float search_interval_sec;
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);
/**
* 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.
/**
* 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.
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);
}
// 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);
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();
#include <map>
#include <set>
-#include <algorithm>
+#include <algorithm> // for sort
+#include <locale> // for char-traits toupper
#include <iostream>
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) :
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);
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();
}
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();
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);