X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FInstrumentation%2Fdclgps.cxx;h=3156c55ac531f6cfd58e40898dd2d80a33963aee;hb=43b300fe46d8013a90009ec8e1a923ec53a396b5;hp=cafa056c1fdb7ecd502bc321c10474a2b6b83880;hpb=a243a24393cd4f9ab1033e9afe4bc2e49af85c28;p=flightgear.git diff --git a/src/Instrumentation/dclgps.cxx b/src/Instrumentation/dclgps.cxx index cafa056c1..3156c55ac 100644 --- a/src/Instrumentation/dclgps.cxx +++ b/src/Instrumentation/dclgps.cxx @@ -27,11 +27,17 @@ #include #include +#include +#include + #include
+#include +#include +#include + #include -SG_USING_STD(cout); -//using namespace std; +using namespace std; // Command callbacks for FlightGear @@ -116,6 +122,15 @@ GPSWaypoint::GPSWaypoint() { appType = GPS_APP_NONE; } +GPSWaypoint::GPSWaypoint(const std::string& aIdent, float aLat, float aLon, GPSWpType aType) : + id(aIdent), + lat(aLat), + lon(aLon), + type(aType), + appType(GPS_APP_NONE) +{ +} + GPSWaypoint::~GPSWaypoint() {} string GPSWaypoint::GetAprId() { @@ -126,6 +141,45 @@ string GPSWaypoint::GetAprId() { else return(id); } +static GPSWpType +GPSWpTypeFromFGPosType(FGPositioned::Type aType) +{ + switch (aType) { + case FGPositioned::AIRPORT: + case FGPositioned::SEAPORT: + case FGPositioned::HELIPORT: + return GPS_WP_APT; + + case FGPositioned::VOR: + return GPS_WP_VOR; + + case FGPositioned::NDB: + return GPS_WP_NDB; + + case FGPositioned::WAYPOINT: + return GPS_WP_USR; + + case FGPositioned::FIX: + return GPS_WP_INT; + + default: + return GPS_WP_USR; + } +} + +GPSWaypoint* GPSWaypoint::createFromPositioned(const FGPositioned* aPos) +{ + if (!aPos) { + return NULL; // happens if find returns no match + } + + return new GPSWaypoint(aPos->ident(), + aPos->latitude() * SG_DEGREES_TO_RADIANS, + aPos->longitude() * SG_DEGREES_TO_RADIANS, + GPSWpTypeFromFGPosType(aPos->type()) + ); +} + ostream& operator << (ostream& os, GPSAppWpType type) { switch(type) { case(GPS_IAF): return(os << "IAF"); @@ -298,12 +352,7 @@ DCLGPS::DCLGPS(RenderArea2D* instrument) { DCLGPS::~DCLGPS() { delete _time; - for(gps_waypoint_map_iterator itr = _waypoints.begin(); itr != _waypoints.end(); ++itr) { - for(unsigned int i = 0; i < (*itr).second.size(); ++i) { - delete(((*itr).second)[i]); - } - } - delete _approachFP; // Don't need to delete the waypoints inside since they point to + delete _approachFP; // Don't need to delete the waypoints inside since they point to // the waypoints in the approach database. // TODO - may need to delete the approach database!! } @@ -326,332 +375,9 @@ void DCLGPS::init() { globals->get_commands()->addCommand("kln89_knob1right1", do_kln89_knob1right1); globals->get_commands()->addCommand("kln89_knob2left1", do_kln89_knob2left1); globals->get_commands()->addCommand("kln89_knob2right1", do_kln89_knob2right1); - - // Build the GPS-specific databases. - // TODO - consider splitting into real life GPS database regions - eg Americas, Europe etc. - // Note that this needs to run after FG's airport and nav databases are up and running - _waypoints.clear(); - const airport_list* apts = globals->get_airports()->getAirportList(); - for(unsigned int i = 0; i < apts->size(); ++i) { - FGAirport* a = (*apts)[i]; - GPSWaypoint* w = new GPSWaypoint; - w->id = a->getId(); - w->lat = a->getLatitude() * SG_DEGREES_TO_RADIANS; - w->lon = a->getLongitude() * SG_DEGREES_TO_RADIANS; - w->type = GPS_WP_APT; - gps_waypoint_map_iterator wtr = _waypoints.find(a->getId()); - if(wtr == _waypoints.end()) { - gps_waypoint_array arr; - arr.push_back(w); - _waypoints[w->id] = arr; - } else { - wtr->second.push_back(w); - } - } - nav_map_type navs = globals->get_navlist()->get_navaids(); - for(nav_map_iterator itr = navs.begin(); itr != navs.end(); ++itr) { - nav_list_type nlst = itr->second; - for(unsigned int i = 0; i < nlst.size(); ++i) { - FGNavRecord* n = nlst[i]; - if(n->get_fg_type() == FG_NAV_VOR || n->get_fg_type() == FG_NAV_NDB) { // We don't bother with ILS etc. - GPSWaypoint* w = new GPSWaypoint; - w->id = n->get_ident(); - w->lat = n->get_lat() * SG_DEGREES_TO_RADIANS; - w->lon = n->get_lon() * SG_DEGREES_TO_RADIANS; - w->type = (n->get_fg_type() == FG_NAV_VOR ? GPS_WP_VOR : GPS_WP_NDB); - gps_waypoint_map_iterator wtr = _waypoints.find(n->get_ident()); - if(wtr == _waypoints.end()) { - gps_waypoint_array arr; - arr.push_back(w); - _waypoints[w->id] = arr; - } else { - wtr->second.push_back(w); - } - } - } - } - const fix_map_type* fixes = globals->get_fixlist()->getFixList(); - for(fix_map_const_iterator itr = fixes->begin(); itr != fixes->end(); ++itr) { - FGFix f = itr->second; - GPSWaypoint* w = new GPSWaypoint; - w->id = f.get_ident(); - w->lat = f.get_lat() * SG_DEGREES_TO_RADIANS; - w->lon = f.get_lon() * SG_DEGREES_TO_RADIANS; - w->type = GPS_WP_INT; - gps_waypoint_map_iterator wtr = _waypoints.find(f.get_ident()); - if(wtr == _waypoints.end()) { - gps_waypoint_array arr; - arr.push_back(w); - _waypoints[w->id] = arr; - } else { - wtr->second.push_back(w); - } - } - // TODO - add USR waypoints as well. - + // Not sure if this should be here, but OK for now. CreateDefaultFlightPlans(); - - // Hack - hardwire some instrument approaches for testing. - // TODO - read these from file - either all at startup or as needed. - FGNPIAP* iap = new FGNPIAP; - iap->_id = "KHWD"; - iap->_name = "VOR/DME OR GPS-B"; - iap->_abbrev = "VOR/D"; - iap->_rwyStr = "B"; - iap->_IAF.clear(); - iap->_IAP.clear(); - iap->_MAP.clear(); - // ------- - GPSWaypoint* wp = new GPSWaypoint; - wp->id = "SUNOL"; - bool multi; - // Nasty using the find any function here, but it saves converting data from FGFix etc. - const GPSWaypoint* fp = FindFirstById(wp->id, multi, true); - *wp = *fp; - wp->appType = GPS_IAF; - iap->_IAF.push_back(wp); - // ------- - wp = new GPSWaypoint; - wp->id = "MABRY"; - fp = FindFirstById(wp->id, multi, true); - *wp = *fp; - wp->appType = GPS_IAF; - iap->_IAF.push_back(wp); - // ------- - wp = new GPSWaypoint; - wp->id = "IMPLY"; - fp = FindFirstById(wp->id, multi, true); - *wp = *fp; - wp->appType = GPS_IAP; - iap->_IAP.push_back(wp); - // ------- - wp = new GPSWaypoint; - wp->id = "DECOT"; - fp = FindFirstById(wp->id, multi, true); - *wp = *fp; - wp->appType = GPS_FAF; - iap->_IAP.push_back(wp); - // ------- - wp = new GPSWaypoint; - wp->id = "MAPVV"; - fp = FindFirstById(wp->id, multi, true); - *wp = *fp; - wp->appType = GPS_MAP; - iap->_IAP.push_back(wp); - // ------- - wp = new GPSWaypoint; - wp->id = "OAK"; - fp = FindFirstById(wp->id, multi, true); - *wp = *fp; - wp->appType = GPS_MAHP; - iap->_MAP.push_back(wp); - // ------- - _np_iap[iap->_id].push_back(iap); - // ----------------------- - // ----------------------- - iap = new FGNPIAP; - iap->_id = "KHWD"; - iap->_name = "VOR OR GPS-A"; - iap->_abbrev = "VOR-"; - iap->_rwyStr = "A"; - iap->_IAF.clear(); - iap->_IAP.clear(); - iap->_MAP.clear(); - // ------- - wp = new GPSWaypoint; - wp->id = "SUNOL"; - // Nasty using the find any function here, but it saves converting data from FGFix etc. - fp = FindFirstById(wp->id, multi, true); - *wp = *fp; - wp->appType = GPS_IAF; - iap->_IAF.push_back(wp); - // ------- - wp = new GPSWaypoint; - wp->id = "MABRY"; - fp = FindFirstById(wp->id, multi, true); - *wp = *fp; - wp->appType = GPS_IAF; - iap->_IAF.push_back(wp); - // ------- - wp = new GPSWaypoint; - wp->id = "IMPLY"; - fp = FindFirstById(wp->id, multi, true); - *wp = *fp; - wp->appType = GPS_IAP; - iap->_IAP.push_back(wp); - // ------- - wp = new GPSWaypoint; - wp->id = "DECOT"; - fp = FindFirstById(wp->id, multi, true); - *wp = *fp; - wp->appType = GPS_FAF; - iap->_IAP.push_back(wp); - // ------- - wp = new GPSWaypoint; - wp->id = "MAPVV"; - fp = FindFirstById(wp->id, multi, true); - *wp = *fp; - wp->appType = GPS_MAP; - iap->_IAP.push_back(wp); - // ------- - wp = new GPSWaypoint; - wp->id = "OAK"; - fp = FindFirstById(wp->id, multi, true); - *wp = *fp; - wp->appType = GPS_MAHP; - iap->_MAP.push_back(wp); - // ------- - _np_iap[iap->_id].push_back(iap); - // ------------------ - // ------------------ - /* - // Ugh - don't load this one - the waypoints required aren't in fix.dat.gz - result: program crash! - // TODO - make the IAP loader robust to absent waypoints. - iap = new FGNPIAP; - iap->_id = "KHWD"; - iap->_name = "GPS RWY 28L"; - iap->_abbrev = "GPS"; - iap->_rwyStr = "28L"; - iap->_IAF.clear(); - iap->_IAP.clear(); - iap->_MAP.clear(); - // ------- - wp = new GPSWaypoint; - wp->id = "SUNOL"; - // Nasty using the find any function here, but it saves converting data from FGFix etc. - fp = FindFirstById(wp->id, multi, true); - *wp = *fp; - wp->appType = GPS_IAF; - iap->_IAF.push_back(wp); - // ------- - wp = new GPSWaypoint; - wp->id = "SJC"; - fp = FindFirstById(wp->id, multi, true); - *wp = *fp; - wp->appType = GPS_IAF; - iap->_IAF.push_back(wp); - // ------- - wp = new GPSWaypoint; - wp->id = "JOCPI"; - fp = FindFirstById(wp->id, multi, true); - *wp = *fp; - wp->appType = GPS_IAP; - iap->_IAP.push_back(wp); - // ------- - wp = new GPSWaypoint; - wp->id = "SUDGE"; - fp = FindFirstById(wp->id, multi, true); - *wp = *fp; - wp->appType = GPS_FAF; - iap->_IAP.push_back(wp); - // ------- - wp = new GPSWaypoint; - wp->id = "RW28L"; - wp->appType = GPS_MAP; - if(wp->id.substr(0, 2) == "RW" && wp->appType == GPS_MAP) { - // Assume that this is a missed-approach point based on the runway number - // Get the runway threshold location etc - } else { - fp = FindFirstById(wp->id, multi, true); - if(fp == NULL) { - cout << "Failed to find waypoint " << wp->id << " in database...\n"; - } else { - *wp = *fp; - } - } - iap->_IAP.push_back(wp); - // ------- - wp = new GPSWaypoint; - wp->id = "OAK"; - fp = FindFirstById(wp->id, multi, true); - *wp = *fp; - wp->appType = GPS_MAHP; - iap->_MAP.push_back(wp); - // ------- - _np_iap[iap->_id].push_back(iap); - */ - iap = new FGNPIAP; - iap->_id = "C83"; - iap->_name = "GPS RWY 30"; - iap->_abbrev = "GPS"; - iap->_rwyStr = "30"; - iap->_IAF.clear(); - iap->_IAP.clear(); - iap->_MAP.clear(); - // ------- - wp = new GPSWaypoint; - wp->id = "MAXNI"; - // Nasty using the find any function here, but it saves converting data from FGFix etc. - fp = FindFirstById(wp->id, multi, true); - if(fp) { - *wp = *fp; - wp->appType = GPS_IAF; - iap->_IAF.push_back(wp); - } - // ------- - wp = new GPSWaypoint; - wp->id = "PATYY"; - fp = FindFirstById(wp->id, multi, true); - if(fp) { - *wp = *fp; - wp->appType = GPS_IAF; - iap->_IAF.push_back(wp); - } - // ------- - wp = new GPSWaypoint; - wp->id = "TRACY"; - fp = FindFirstById(wp->id, multi, true); - if(fp) { - *wp = *fp; - wp->appType = GPS_IAF; - iap->_IAF.push_back(wp); - } - // ------- - wp = new GPSWaypoint; - wp->id = "TRACY"; - fp = FindFirstById(wp->id, multi, true); - if(fp) { - *wp = *fp; - wp->appType = GPS_IAP; - iap->_IAP.push_back(wp); - } - // ------- - wp = new GPSWaypoint; - wp->id = "BABPI"; - fp = FindFirstById(wp->id, multi, true); - if(fp) { - *wp = *fp; - wp->appType = GPS_FAF; - iap->_IAP.push_back(wp); - } - // ------- - wp = new GPSWaypoint; - wp->id = "AMOSY"; - wp->appType = GPS_MAP; - if(wp->id.substr(0, 2) == "RW" && wp->appType == GPS_MAP) { - // Assume that this is a missed-approach point based on the runway number - // TODO: Get the runway threshold location etc - cout << "TODO - implement missed-approach point based on rwy no.\n"; - } else { - fp = FindFirstById(wp->id, multi, true); - if(fp == NULL) { - cout << "Failed to find waypoint " << wp->id << " in database...\n"; - } else { - *wp = *fp; - wp->appType = GPS_MAP; - } - } - iap->_IAP.push_back(wp); - // ------- - wp = new GPSWaypoint; - wp->id = "HAIRE"; - fp = FindFirstById(wp->id, multi, true); - *wp = *fp; - wp->appType = GPS_MAHP; - iap->_MAP.push_back(wp); - // ------- - _np_iap[iap->_id].push_back(iap); } void DCLGPS::bind() { @@ -959,8 +685,7 @@ double DCLGPS::GetCDIDeflection() const { void DCLGPS::DtoInitiate(const string& s) { //cout << "DtoInitiate, s = " << s << '\n'; - bool multi; - const GPSWaypoint* wp = FindFirstById(s, multi, true); + const GPSWaypoint* wp = FindFirstByExactId(s); if(wp) { //cout << "Waypoint found, starting dto operation!\n"; _dto = true; @@ -969,6 +694,7 @@ void DCLGPS::DtoInitiate(const string& s) { _fromWaypoint.lon = _gpsLon; _fromWaypoint.type = GPS_WP_VIRT; _fromWaypoint.id = "DTOWP"; + delete wp; } else { //cout << "Waypoint not found, ignoring dto request\n"; // Should bring up the user waypoint page, but we're not implementing that yet. @@ -1102,10 +828,10 @@ double DCLGPS::GetTimeToWaypoint(const string& id) { } else if(id == _activeWaypoint.id) { return(_eta); } else { - bool multi; - const GPSWaypoint* wp = FindFirstById(id, multi, true); + const GPSWaypoint* wp = FindFirstByExactId(id); if(wp == NULL) return(-1.0); double distm = GetGreatCircleDistance(_gpsLat, _gpsLon, wp->lat, wp->lon); + delete wp; return(distm / _groundSpeed_ms); } return(-1.0); // Hopefully we never get here! @@ -1309,347 +1035,83 @@ void DCLGPS::CreateFlightPlan(GPSFlightPlan* fp, vector ids, vectortype()) { + case FGPositioned::AIRPORT: + // how about heliports and seaports? + case FGPositioned::NDB: + case FGPositioned::VOR: + case FGPositioned::WAYPOINT: + case FGPositioned::FIX: + break; + default: return false; // reject all other types } - if(itr == _waypoints.end()) { - return(NULL); - } else { - // TODO - don't just return the first one - either return all or the nearest one. - return((itr->second)[0]); - } -} + return true; + } +}; -const GPSWaypoint* DCLGPS::FindFirstById(const string& id, bool &multi, bool exact) { - multi = false; - if(exact) return(ActualFindFirstById(id, exact)); - - // OK, that was the easy case, now the fuzzy case - const GPSWaypoint* w1 = ActualFindFirstById(id); - if(w1 == NULL) return(w1); - - // The non-trivial code from here to the end of the function is all to deal with the fact that - // the KLN89 alphabetical order (numbers AFTER letters) differs from ASCII order (numbers BEFORE letters). - string id2 = id; - //string id3 = id+'0'; - string id4 = id+'A'; - // Increment the last char to provide the boundary. Note that 'Z' -> '[' but we also need to check '0' for all since GPS has numbers after letters - //bool alfa = isalpha(id2[id2.size() - 1]); - id2[id2.size() - 1] = id2[id2.size() - 1] + 1; - const GPSWaypoint* w2 = ActualFindFirstById(id2); - //FGAirport* a3 = globals->get_airports()->findFirstById(id3); - const GPSWaypoint* w4 = ActualFindFirstById(id4); - //cout << "Strings sent were " << id << ", " << id2 << " and " << id4 << '\n'; - //cout << "Airports returned were (a1, a2, a4): " << a1->getId() << ", " << a2->getId() << ", " << a4->getId() << '\n'; - //cout << "Pointers were " << a1 << ", " << a2 << ", " << a4 << '\n'; - - // TODO - the below handles the imediately following char OK - // eg id = "KD" returns "KDAA" instead of "KD5" - // but it doesn't handle numbers / letters further down the string, - // eg - id = "I" returns "IA01" instead of "IAN" - // We either need to provide a custom comparison operator, or recurse this function if !isalpha further down the string. - // (Currenly fixed with recursion). - - if(w4 != w2) { // A-Z match - preferred - //cout << "A-Z match!\n"; - if(w4->id.size() - id.size() > 2) { - // Check for numbers further on - for(unsigned int i=id.size(); iid.size(); ++i) { - if(!isalpha(w4->id[i])) { - //cout << "SUBSTR is " << (a4->getId()).substr(0, i) << '\n'; - return(FindFirstById(w4->id.substr(0, i), multi, exact)); - } - } - } - return(w4); - } else if(w1 != w2) { // 0-9 match - //cout << "0-9 match!\n"; - if(w1->id.size() - id.size() > 2) { - // Check for numbers further on - for(unsigned int i=id.size(); iid.size(); ++i) { - if(!isalpha(w1->id[i])) { - //cout << "SUBSTR2 is " << (a4->getId()).substr(0, i) << '\n'; - return(FindFirstById(w1->id.substr(0, i), multi, exact)); - } - } - } - return(w1); - } else { // No match - return(NULL); - } - return NULL; -} - -// Host specific lookup functions -// TODO - add the ASCII / alphabetical stuff from the Atlas version -FGNavRecord* DCLGPS::FindFirstVorById(const string& id, bool &multi, bool exact) { - // NOTE - at the moment multi is never set. - multi = false; - //if(exact) return(_overlays->FindFirstVorById(id, exact)); - - nav_list_type nav = globals->get_navlist()->findFirstByIdent(id, FG_NAV_VOR, exact); - - if(nav.size() > 1) multi = true; - //return(nav.empty() ? NULL : *(nav.begin())); - - // The above is sort of what we want - unfortunately we can't guarantee no NDB/ILS at the moment - if(nav.empty()) return(NULL); - - for(nav_list_iterator it = nav.begin(); it != nav.end(); ++it) { - if((*it)->get_type() == 3) return(*it); - } - return(NULL); // Shouldn't get here! -} -#if 0 -Overlays::NAV* DCLGPS::FindFirstVorById(const string& id, bool &multi, bool exact) { - // NOTE - at the moment multi is never set. - multi = false; - if(exact) return(_overlays->FindFirstVorById(id, exact)); - - // OK, that was the easy case, now the fuzzy case - Overlays::NAV* n1 = _overlays->FindFirstVorById(id); - if(n1 == NULL) return(n1); - - string id2 = id; - string id3 = id+'0'; - string id4 = id+'A'; - // Increment the last char to provide the boundary. Note that 'Z' -> '[' but we also need to check '0' for all since GPS has numbers after letters - bool alfa = isalpha(id2[id2.size() - 1]); - id2[id2.size() - 1] = id2[id2.size() - 1] + 1; - Overlays::NAV* n2 = _overlays->FindFirstVorById(id2); - //Overlays::NAV* n3 = _overlays->FindFirstVorById(id3); - //Overlays::NAV* n4 = _overlays->FindFirstVorById(id4); - //cout << "Strings sent were " << id << ", " << id2 << ", " << id3 << ", " << id4 << '\n'; - - - if(alfa) { - if(n1 != n2) { // match - return(n1); - } else { - return(NULL); - } - } - - /* - if(n1 != n2) { - // Something matches - the problem is the number/letter preference order is reversed between the GPS and the STL - if(n4 != n2) { - // There's a letter match - return that - return(n4); - } else { - // By definition we must have a number match - if(n3 == n2) cout << "HELP - LOGIC FLAW in find VOR!\n"; - return(n3); - } - } else { - // No match - return(NULL); - } - */ - return NULL; +GPSWaypoint* DCLGPS::FindFirstById(const string& id) const +{ + DCLGPSFilter filter; + FGPositionedRef result = FGPositioned::findNextWithPartialId(NULL, id, &filter); + return GPSWaypoint::createFromPositioned(result); } -#endif //0 -// TODO - add the ASCII / alphabetical stuff from the Atlas version -FGNavRecord* DCLGPS::FindFirstNDBById(const string& id, bool &multi, bool exact) { - // NOTE - at the moment multi is never set. - multi = false; - //if(exact) return(_overlays->FindFirstVorById(id, exact)); - - nav_list_type nav = globals->get_navlist()->findFirstByIdent(id, FG_NAV_NDB, exact); - - if(nav.size() > 1) multi = true; - //return(nav.empty() ? NULL : *(nav.begin())); - - // The above is sort of what we want - unfortunately we can't guarantee no NDB/ILS at the moment - if(nav.empty()) return(NULL); - - for(nav_list_iterator it = nav.begin(); it != nav.end(); ++it) { - if((*it)->get_type() == 2) return(*it); - } - return(NULL); // Shouldn't get here! -} -#if 0 -Overlays::NAV* DCLGPS::FindFirstNDBById(const string& id, bool &multi, bool exact) { - // NOTE - at the moment multi is never set. - multi = false; - if(exact) return(_overlays->FindFirstNDBById(id, exact)); - - // OK, that was the easy case, now the fuzzy case - Overlays::NAV* n1 = _overlays->FindFirstNDBById(id); - if(n1 == NULL) return(n1); - - string id2 = id; - string id3 = id+'0'; - string id4 = id+'A'; - // Increment the last char to provide the boundary. Note that 'Z' -> '[' but we also need to check '0' for all since GPS has numbers after letters - bool alfa = isalpha(id2[id2.size() - 1]); - id2[id2.size() - 1] = id2[id2.size() - 1] + 1; - Overlays::NAV* n2 = _overlays->FindFirstNDBById(id2); - //Overlays::NAV* n3 = _overlays->FindFirstNDBById(id3); - //Overlays::NAV* n4 = _overlays->FindFirstNDBById(id4); - //cout << "Strings sent were " << id << ", " << id2 << ", " << id3 << ", " << id4 << '\n'; - - - if(alfa) { - if(n1 != n2) { // match - return(n1); - } else { - return(NULL); - } - } - - /* - if(n1 != n2) { - // Something matches - the problem is the number/letter preference order is reversed between the GPS and the STL - if(n4 != n2) { - // There's a letter match - return that - return(n4); - } else { - // By definition we must have a number match - if(n3 == n2) cout << "HELP - LOGIC FLAW in find VOR!\n"; - return(n3); - } - } else { - // No match - return(NULL); - } - */ - return NULL; +GPSWaypoint* DCLGPS::FindFirstByExactId(const string& id) const +{ + SGGeod pos(SGGeod::fromRad(_lon, _lat)); + FGPositionedRef result = FGPositioned::findClosestWithIdent(id, pos); + return GPSWaypoint::createFromPositioned(result); } -#endif //0 // TODO - add the ASCII / alphabetical stuff from the Atlas version -const FGFix* DCLGPS::FindFirstIntById(const string& id, bool &multi, bool exact) { - // NOTE - at the moment multi is never set, and indeed can't be - // since FG can only map one Fix per ID at the moment. - multi = false; - if(exact) return(globals->get_fixlist()->findFirstByIdent(id, exact)); - - const FGFix* f1 = globals->get_fixlist()->findFirstByIdent(id, exact); - if(f1 == NULL) return(f1); - - // The non-trivial code from here to the end of the function is all to deal with the fact that - // the KLN89 alphabetical order (numbers AFTER letters) differs from ASCII order (numbers BEFORE letters). - // It is copied from the airport version which is definately needed, but at present I'm not actually - // sure if any fixes in FG or real-life have numbers in them! - string id2 = id; - //string id3 = id+'0'; - string id4 = id+'A'; - // Increment the last char to provide the boundary. Note that 'Z' -> '[' but we also need to check '0' for all since GPS has numbers after letters - //bool alfa = isalpha(id2[id2.size() - 1]); - id2[id2.size() - 1] = id2[id2.size() - 1] + 1; - const FGFix* f2 = globals->get_fixlist()->findFirstByIdent(id2); - //const FGFix* a3 = globals->get_fixlist()->findFirstByIdent(id3); - const FGFix* f4 = globals->get_fixlist()->findFirstByIdent(id4); - - // TODO - the below handles the imediately following char OK - // eg id = "KD" returns "KDAA" instead of "KD5" - // but it doesn't handle numbers / letters further down the string, - // eg - id = "I" returns "IA01" instead of "IAN" - // We either need to provide a custom comparison operator, or recurse this function if !isalpha further down the string. - // (Currenly fixed with recursion). - - if(f4 != f2) { // A-Z match - preferred - //cout << "A-Z match!\n"; - if(f4->get_ident().size() - id.size() > 2) { - // Check for numbers further on - for(unsigned int i=id.size(); iget_ident().size(); ++i) { - if(!isalpha(f4->get_ident()[i])) { - //cout << "SUBSTR is " << (a4->getId()).substr(0, i) << '\n'; - return(FindFirstIntById(f4->get_ident().substr(0, i), multi, exact)); - } - } - } - return(f4); - } else if(f1 != f2) { // 0-9 match - //cout << "0-9 match!\n"; - if(f1->get_ident().size() - id.size() > 2) { - // Check for numbers further on - for(unsigned int i=id.size(); iget_ident().size(); ++i) { - if(!isalpha(f1->get_ident()[i])) { - //cout << "SUBSTR2 is " << (a4->getId()).substr(0, i) << '\n'; - return(FindFirstIntById(f1->get_ident().substr(0, i), multi, exact)); - } - } - } - return(f1); - } else { // No match - return(NULL); - } - - return NULL; // Don't think we can ever get here. -} - -const FGAirport* DCLGPS::FindFirstAptById(const string& id, bool &multi, bool exact) { - // NOTE - at the moment multi is never set. - //cout << "FindFirstAptById, id = " << id << '\n'; - multi = false; - if(exact) return(globals->get_airports()->findFirstById(id, exact)); - - // OK, that was the easy case, now the fuzzy case - const FGAirport* a1 = globals->get_airports()->findFirstById(id); - if(a1 == NULL) return(a1); - - // The non-trivial code from here to the end of the function is all to deal with the fact that - // the KLN89 alphabetical order (numbers AFTER letters) differs from ASCII order (numbers BEFORE letters). - string id2 = id; - //string id3 = id+'0'; - string id4 = id+'A'; - // Increment the last char to provide the boundary. Note that 'Z' -> '[' but we also need to check '0' for all since GPS has numbers after letters - //bool alfa = isalpha(id2[id2.size() - 1]); - id2[id2.size() - 1] = id2[id2.size() - 1] + 1; - const FGAirport* a2 = globals->get_airports()->findFirstById(id2); - //FGAirport* a3 = globals->get_airports()->findFirstById(id3); - const FGAirport* a4 = globals->get_airports()->findFirstById(id4); - //cout << "Strings sent were " << id << ", " << id2 << " and " << id4 << '\n'; - //cout << "Airports returned were (a1, a2, a4): " << a1->getId() << ", " << a2->getId() << ", " << a4->getId() << '\n'; - //cout << "Pointers were " << a1 << ", " << a2 << ", " << a4 << '\n'; - - // TODO - the below handles the imediately following char OK - // eg id = "KD" returns "KDAA" instead of "KD5" - // but it doesn't handle numbers / letters further down the string, - // eg - id = "I" returns "IA01" instead of "IAN" - // We either need to provide a custom comparison operator, or recurse this function if !isalpha further down the string. - // (Currenly fixed with recursion). - - if(a4 != a2) { // A-Z match - preferred - //cout << "A-Z match!\n"; - if(a4->getId().size() - id.size() > 2) { - // Check for numbers further on - for(unsigned int i=id.size(); igetId().size(); ++i) { - if(!isalpha(a4->getId()[i])) { - //cout << "SUBSTR is " << (a4->getId()).substr(0, i) << '\n'; - return(FindFirstAptById(a4->getId().substr(0, i), multi, exact)); - } - } - } - return(a4); - } else if(a1 != a2) { // 0-9 match - //cout << "0-9 match!\n"; - if(a1->getId().size() - id.size() > 2) { - // Check for numbers further on - for(unsigned int i=id.size(); igetId().size(); ++i) { - if(!isalpha(a1->getId()[i])) { - //cout << "SUBSTR2 is " << (a4->getId()).substr(0, i) << '\n'; - return(FindFirstAptById(a1->getId().substr(0, i), multi, exact)); - } - } - } - return(a1); - } else { // No match - return(NULL); - } - - return NULL; -} - -FGNavRecord* DCLGPS::FindClosestVor(double lat_rad, double lon_rad) { - return(globals->get_navlist()->findClosest(lon_rad, lat_rad, 0.0, FG_NAV_VOR)); +FGPositioned* DCLGPS::FindTypedFirstById(const string& id, FGPositioned::Type ty, bool &multi, bool exact) +{ + multi = false; + FGPositioned::TypeFilter filter(ty); + + if (exact) { + FGPositioned::List matches = + FGPositioned::findAllWithIdentSortedByRange(id, SGGeod::fromRad(_lon, _lat), &filter); + multi = (matches.size() > 1); + return matches.empty() ? NULL : matches.front().ptr(); + } + + return FGPositioned::findNextWithPartialId(NULL, id, &filter); +} + +FGNavRecord* DCLGPS::FindFirstVorById(const string& id, bool &multi, bool exact) +{ + return dynamic_cast(FindTypedFirstById(id, FGPositioned::VOR, multi, exact)); +} + +FGNavRecord* DCLGPS::FindFirstNDBById(const string& id, bool &multi, bool exact) +{ + return dynamic_cast(FindTypedFirstById(id, FGPositioned::NDB, multi, exact)); +} + +const FGFix* DCLGPS::FindFirstIntById(const string& id, bool &multi, bool exact) +{ + return dynamic_cast(FindTypedFirstById(id, FGPositioned::FIX, multi, exact)); +} + +const FGAirport* DCLGPS::FindFirstAptById(const string& id, bool &multi, bool exact) +{ + return dynamic_cast(FindTypedFirstById(id, FGPositioned::AIRPORT, multi, exact)); +} + +FGNavRecord* DCLGPS::FindClosestVor(double lat_rad, double lon_rad) { + FGPositioned::TypeFilter filter(FGPositioned::VOR); + double cutoff = 1000; // nautical miles + FGPositionedRef v = FGPositioned::findClosest(SGGeod::fromRad(lon_rad, lat_rad), cutoff, &filter); + if (!v) { + return NULL; + } + + return dynamic_cast(v.ptr()); } //----------------------------------------------------------------------------------------------------------