1
0
Fork 0

Another clean-up iteration: FGAirportList::search is gone, replaced by two

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.
This commit is contained in:
jmt 2008-12-26 15:26:42 +00:00
parent b2d4612beb
commit 660d59a098
10 changed files with 163 additions and 104 deletions

View 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);
}
}
}

View 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" );
if ( id.empty() ) {
return NULL;
}
} else {
return NULL;
}
SG_LOG( SG_GENERAL, SG_BULK,
"Position for " << id << " is ("
<< result->getLongitude() << ", "
<< result->getLatitude() << ")" );
return result;
return FGAirport::findByIdent(id);
}

View 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.
*/

View 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();

View 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.

View 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);
}

View file

@ -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();

View 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) :

View 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();

View 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);