From: mfranz Date: Fri, 5 Oct 2007 21:54:52 +0000 (+0000) Subject: - make FGAirport::search() more versatile, so that it can't only search X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=15139a42b6a064e66bff74958893dd748769d68c;p=flightgear.git - make FGAirport::search() more versatile, so that it can't only search the next airport or airport with METAR station, but about any type of airport - as a side effect this change makes it also 30 to 50% faster :-) In the long run this linear search shall be replaced with a spatial algorithm (like octree), which will be a much bigger performance gain. --- diff --git a/src/Airports/simple.cxx b/src/Airports/simple.cxx index 6efac4c0e..e92b08fbd 100644 --- a/src/Airports/simple.cxx +++ b/src/Airports/simple.cxx @@ -187,25 +187,35 @@ const FGAirport* FGAirportList::findFirstById( const string& id, bool exact ) // search for the airport nearest the specified position -FGAirport* FGAirportList::search( double lon_deg, double lat_deg, - bool with_metar ) +FGAirport* FGAirportList::search(double lon_deg, double lat_deg) +{ + static FGAirportSearchFilter accept_any; + return search(lon_deg, lat_deg, accept_any); +} + + +// search for the airport nearest the specified position and +// passing the filter +FGAirport* FGAirportList::search(double lon_deg, double lat_deg, + FGAirportSearchFilter& search) { - int closest = -1; double min_dist = 360.0; - unsigned int i; - for ( i = 0; i < airports_array.size(); ++i ) { + airport_list_iterator it = airports_array.begin(); + airport_list_iterator end = airports_array.end(); + airport_list_iterator closest = end; + for (; it != end; ++it) { + if (!search.acceptable(*it)) + continue; + // crude manhatten distance based on lat/lon difference - double d = fabs(lon_deg - airports_array[i]->getLongitude()) - + fabs(lat_deg - airports_array[i]->getLatitude()); - if ( d < min_dist ) { - if ( !with_metar || (with_metar&&airports_array[i]->getMetar()) ) { - closest = i; - min_dist = d; - } + double d = fabs(lon_deg - (*it)->getLongitude()) + + fabs(lat_deg - (*it)->getLatitude()); + if (d < min_dist) { + closest = it; + min_dist = d; } } - - return ( closest > -1 ? airports_array[closest] : NULL ); + return closest != end ? *closest : 0; } diff --git a/src/Airports/simple.hxx b/src/Airports/simple.hxx index 9251ee423..d1930730a 100644 --- a/src/Airports/simple.hxx +++ b/src/Airports/simple.hxx @@ -106,6 +106,12 @@ private: }; +class FGAirportSearchFilter { +public: + virtual ~FGAirportSearchFilter() {} + virtual bool acceptable(FGAirport*) { return true; } +}; + typedef map < string, FGAirport* > airport_map; typedef airport_map::iterator airport_map_iterator; @@ -122,7 +128,6 @@ private: airport_map airports_by_id; airport_list airports_array; - //set < string > ai_dirs; public: // Constructor (new) @@ -150,10 +155,10 @@ public: // search for the airport closest to the specified position // (currently a linear inefficient search so it's probably not - // best to use this at runtime.) If with_metar is true, then only - // return station id's marked as having metar data. - // Returns NULL if fails (unlikely unless none have metar and with_metar spec'd!) - FGAirport* search( double lon_deg, double lat_deg, bool with_metar ); + // best to use this at runtime.) An FGAirportSearchFilter class + // can be used to restrict the possible choices to a subtype. + FGAirport* search( double lon_deg, double lat_deg ); + FGAirport* search( double lon_deg, double lat_deg, FGAirportSearchFilter& ); /** * Return the number of airports in the list. diff --git a/src/Environment/environment_ctrl.cxx b/src/Environment/environment_ctrl.cxx index 82af0e027..5733ed67a 100644 --- a/src/Environment/environment_ctrl.cxx +++ b/src/Environment/environment_ctrl.cxx @@ -41,6 +41,9 @@ SG_USING_STD(sort); +class metar_filter : public FGAirportSearchFilter { + virtual bool acceptable(FGAirport *a) { return a->getMetar(); } +} metar_only; //////////////////////////////////////////////////////////////////////// @@ -648,7 +651,7 @@ FGMetarEnvironmentCtrl::init () const FGAirport* a = globals->get_airports() ->search( longitude->getDoubleValue(), latitude->getDoubleValue(), - true ); + metar_only ); if ( a ) { FGMetarResult result = fetch_data( a->getId() ); if ( result.m != NULL ) { @@ -711,7 +714,7 @@ FGMetarEnvironmentCtrl::update(double delta_time_sec) const FGAirport* a = globals->get_airports() ->search( longitude->getDoubleValue(), latitude->getDoubleValue(), - true ); + metar_only ); if ( a ) { if ( !last_apt || last_apt->getId() != a->getId() || fetch_elapsed > same_station_interval_sec ) diff --git a/src/Instrumentation/gps.cxx b/src/Instrumentation/gps.cxx index ae0f3c810..b466948c4 100644 --- a/src/Instrumentation/gps.cxx +++ b/src/Instrumentation/gps.cxx @@ -308,7 +308,7 @@ GPS::update (double delta_time_sec) // If the get-nearest-airport-node is true. // Get the nearest airport, and set it as waypoint 1. if (_get_nearest_airport_node->getBoolValue()) { - const FGAirport* a = globals->get_airports()->search(longitude_deg, latitude_deg, false); + const FGAirport* a = globals->get_airports()->search(longitude_deg, latitude_deg); if(a) { _wp1_ID_node->setStringValue(a->getId().c_str()); wp1_longitude_deg = a->getLongitude(); diff --git a/src/Scripting/NasalSys.cxx b/src/Scripting/NasalSys.cxx index 32dcb98e6..423935d34 100644 --- a/src/Scripting/NasalSys.cxx +++ b/src/Scripting/NasalSys.cxx @@ -496,11 +496,11 @@ static naRef f_airportinfo(naContext c, naRef me, int argc, naRef* args) FGAirportList *aptlst = globals->get_airports(); FGAirport *apt; if(argc == 0) - apt = aptlst->search(lon->getDoubleValue(), lat->getDoubleValue(), false); + apt = aptlst->search(lon->getDoubleValue(), lat->getDoubleValue()); else if(argc == 1 && naIsString(args[0])) apt = aptlst->search(naStr_data(args[0])); else if(argc == 2 && naIsNum(args[0]) && naIsNum(args[1])) - apt = aptlst->search(args[1].num, args[0].num, false); + apt = aptlst->search(args[1].num, args[0].num); else { naRuntimeError(c, "airportinfo() with invalid function arguments"); return naNil();