diff --git a/src/GUI/BaseDiagram.cxx b/src/GUI/BaseDiagram.cxx index a18f109dc..b4a832e37 100644 --- a/src/GUI/BaseDiagram.cxx +++ b/src/GUI/BaseDiagram.cxx @@ -260,6 +260,11 @@ public: addType(FGPositioned::NDB); addType(FGPositioned::VOR); + // this doesn't work, since the cache does not actually contain TACAN entries + // addType(FGPositioned::TACAN); + // instead we look for DMEs and filter on the name + addType(FGPositioned::DME); + if (aircraft == LauncherController::Helicopter) { addType(FGPositioned::HELIPAD); } @@ -273,16 +278,24 @@ public: addType(FGPositioned::AIRPORT); } - virtual bool pass(FGPositioned* aPos) const + bool pass(FGPositioned* aPos) const override { bool ok = TypeFilter::pass(aPos); - if (ok && (aPos->type() == FGPositioned::FIX)) { + const auto ty = aPos->type(); + if (ok && (ty == FGPositioned::FIX)) { // ignore fixes which end in digits if (aPos->ident().length() > 4 && isdigit(aPos->ident()[3]) && isdigit(aPos->ident()[4])) { return false; } } + + if (ok && (ty == FGPositioned::DME)) { + if (!simgear::strutils::ends_with(aPos->name(), "TACAN")) { + return false; + } + } + return ok; } }; @@ -815,6 +828,11 @@ QPixmap BaseDiagram::iconForPositioned(const FGPositionedRef& pos, return QPixmap(":/vor-icon"); + // our filter only passes DMEs which are TACANs, so this is correct, + // until we actually record TACANs in the NavCache + case FGPositioned::DME: + return QPixmap(":/tacan-icon"); + case FGPositioned::AIRPORT: return iconForAirport(static_cast(pos.ptr()), options); diff --git a/src/GUI/LocationController.cxx b/src/GUI/LocationController.cxx index 2fcb877f2..c29dc53a8 100644 --- a/src/GUI/LocationController.cxx +++ b/src/GUI/LocationController.cxx @@ -571,9 +571,18 @@ void LocationController::restoreLocation(QVariantMap l) const SGGeod vicinity = SGGeod::fromDeg(l.value("vicinity-lon").toDouble(), l.value("vicinity-lat").toDouble()); - FGPositioned::TypeFilter filter({FGPositioned::Type::NDB, FGPositioned::Type::VOR, - FGPositioned::Type::FIX, FGPositioned::Type::WAYPOINT}); - m_location = FGPositioned::findClosestWithIdent(ident, vicinity, &filter); + // special-case TACANs so we don't get an ambiguity on VORTACs, where + // there would be a double hit on any ident + const auto isTacan = l.value("location-is-tacan").toBool(); + if (isTacan) { + FGPositioned::TypeFilter filter(FGPositioned::Type::DME); + m_location = FGPositioned::findClosestWithIdent(ident, vicinity, &filter); + } else { + FGPositioned::TypeFilter filter({FGPositioned::Type::NDB, FGPositioned::Type::VOR, + FGPositioned::Type::FIX, FGPositioned::Type::WAYPOINT}); + m_location = FGPositioned::findClosestWithIdent(ident, vicinity, &filter); + } + m_baseQml->setInner(m_location); } else if (l.contains("location-lat")) { m_locationIsLatLon = true; @@ -680,6 +689,11 @@ QVariantMap LocationController::saveLocation() const } } else { // not an aiport, must be a navaid locationSet.insert("location-navaid", QString::fromStdString(m_location->ident())); + if (m_location->type() == FGPositioned::DME) { + // so we don't get ambiguous on VORTACs, explicity mark TACANs + // otherwise every VORTAC would be ambiguous + locationSet.insert("location-is-tacan", true); + } locationSet.insert("vicinity-lat", m_location->geod().getLatitudeDeg()); locationSet.insert("vicinity-lon", m_location->geod().getLongitudeDeg()); @@ -714,11 +728,23 @@ void LocationController::setLocationProperties() { SGPropertyNode_ptr presets = fgGetNode("/sim/presets", true); - QStringList props = QStringList() << "vor-id" << "fix" << "ndb-id" << - "runway-requested" << "navaid-id" << "offset-azimuth-deg" << - "offset-distance-nm" << "glideslope-deg" << - "speed-set" << "on-ground" << "airspeed-kt" << - "airport-id" << "runway" << "parkpos" << "carrier" << "carrier-position"; + QStringList props = QStringList() << "vor-id" + << "fix" + << "ndb-id" + << "tacan-id" + << "runway-requested" + << "navaid-id" + << "offset-azimuth-deg" + << "offset-distance-nm" + << "glideslope-deg" + << "speed-set" + << "on-ground" + << "airspeed-kt" + << "airport-id" + << "runway" + << "parkpos" + << "carrier" + << "carrier-position"; Q_FOREACH(QString s, props) { SGPropertyNode* c = presets->getChild(s.toStdString()); @@ -835,6 +861,12 @@ void LocationController::setLocationProperties() case FGPositioned::FIX: fgSetString("/sim/presets/fix", m_location->ident()); break; + + // assume if a DME was selected, it was actually a TACAN + case FGPositioned::DME: + fgSetString("/sim/presets/tacan-id", m_location->ident()); + break; + default: break; } @@ -1031,6 +1063,11 @@ void LocationController::onCollectConfig() case FGPositioned::FIX: m_config->setArg("fix", m_location->ident()); break; + + case FGPositioned::DME: + m_config->setArg("tacan", m_location->ident()); + break; + default: break; } @@ -1162,6 +1199,9 @@ QString LocationController::description() const navaidType = QString("VOR"); break; case FGPositioned::NDB: navaidType = QString("NDB"); break; + case FGPositioned::DME: + navaidType = QString("TACAN"); + break; case FGPositioned::FIX: return tr("%2 waypoint %1").arg(ident).arg(offsetDesc); default: diff --git a/src/GUI/NavaidSearchModel.cxx b/src/GUI/NavaidSearchModel.cxx index d67e0f38f..4d15c8d85 100644 --- a/src/GUI/NavaidSearchModel.cxx +++ b/src/GUI/NavaidSearchModel.cxx @@ -116,6 +116,7 @@ public: addType(FGPositioned::VOR); addType(FGPositioned::FIX); addType(FGPositioned::NDB); + addType(FGPositioned::DME); // see custom pass() impl below } addType(FGPositioned::AIRPORT); @@ -137,6 +138,21 @@ public: addType(FGPositioned::SEAPORT); } } + + bool pass(FGPositioned* aPos) const override + { + bool ok = TypeFilter::pass(aPos); + const auto ty = aPos->type(); + + // filter only DMEs which are TACANs, until we have real TACANs in the DB + if (ok && (ty == FGPositioned::DME)) { + if (!simgear::strutils::ends_with(aPos->name(), "TACAN")) { + return false; + } + } + + return ok; + } }; void NavaidSearchModel::clear() diff --git a/src/GUI/assets/tacan-icon.png b/src/GUI/assets/tacan-icon.png new file mode 100644 index 000000000..7526e954a Binary files /dev/null and b/src/GUI/assets/tacan-icon.png differ diff --git a/src/GUI/resources.qrc b/src/GUI/resources.qrc index ea346e4b9..7f2955057 100644 --- a/src/GUI/resources.qrc +++ b/src/GUI/resources.qrc @@ -13,6 +13,7 @@ assets/airport-icon.png assets/airport-tower-icon.png assets/vor-dme-icon.png + assets/tacan-icon.png assets/seaport-tower-icon.png assets/ndb-small-icon.png assets/ndb-large-icon.png diff --git a/src/Main/options.cxx b/src/Main/options.cxx index 038109d90..8e5de40cb 100644 --- a/src/Main/options.cxx +++ b/src/Main/options.cxx @@ -692,6 +692,7 @@ clearLocation () fgSetString("/sim/presets/parkpos", ""); fgSetString("/sim/presets/carrier-position", ""); fgSetString("/sim/presets/fix", ""); + fgSetString("/sim/presets/tacan-id", ""); } /* @@ -805,6 +806,14 @@ fgOptLat( const char *arg ) return FG_OPTIONS_OK; } +static int +fgOptTACAN(const char* arg) +{ + clearLocation(); + fgSetString("/sim/presets/tacan-id", arg); + return FG_OPTIONS_OK; +} + static int fgOptAltitude( const char *arg ) { @@ -1842,6 +1851,7 @@ struct OptionDesc { {"carrier", true, OPTION_FUNC, "", false, "", fgOptCarrier }, {"carrier-position", true, OPTION_FUNC, "", false, "", fgOptCarrierPos }, {"fix", true, OPTION_FUNC, "", false, "", fgOptFIX }, + {"tacan", true, OPTION_FUNC, "", false, "", fgOptTACAN }, {"offset-distance", true, OPTION_DOUBLE, "/sim/presets/offset-distance-nm", false, "", 0 }, {"offset-azimuth", true, OPTION_DOUBLE, "/sim/presets/offset-azimuth-deg", false, "", 0 }, {"lon", true, OPTION_FUNC, "", false, "", fgOptLon }, diff --git a/src/Main/positioninit.cxx b/src/Main/positioninit.cxx index a3090cba5..f4b514ea3 100644 --- a/src/Main/positioninit.cxx +++ b/src/Main/positioninit.cxx @@ -596,6 +596,7 @@ bool initPosition() string carrier = fgGetString("/sim/presets/carrier"); string parkpos = fgGetString("/sim/presets/parkpos"); string fix = fgGetString("/sim/presets/fix"); + const auto tacan = fgGetString("/sim/presets/tacan-id"); // the launcher sets this to precisely identify a navaid PositionedID navaidId = fgGetInt("/sim/presets/navaid-id"); @@ -698,6 +699,14 @@ bool initPosition() } } + if (!set_pos & !tacan.empty()) { + // we don't record TACANs in the NavCache right now, instead we + // record DMEs, some of which have TACAN in the name. + if (fgSetPosFromNAV(tacan, 0.0, FGPositioned::DME, navaidId)) { + set_pos = true; + } + } + if ( !set_pos ) { const std::string defaultAirportId = fgGetString("/sim/presets/airport-id"); const FGAirport* airport = fgFindAirportID(defaultAirportId); diff --git a/src/Navaids/NavDataCache.cxx b/src/Navaids/NavDataCache.cxx index 30eced268..32630ec8e 100755 --- a/src/Navaids/NavDataCache.cxx +++ b/src/Navaids/NavDataCache.cxx @@ -2873,8 +2873,11 @@ NavDataCache::ThreadedGUISearch::ThreadedGUISearch(const std::string& term, bool sql = "SELECT rowid FROM positioned WHERE name LIKE '%" + term + "%' AND (type >= 1 AND type <= 3)"; } else { + // types are hard-coded here becuase this is only used by NavaidSearchModel + // in ther launcher. We would ideally use a TypeFilter but that would + // mean loading each positioned to filter them, which is inefficient. sql = "SELECT rowid FROM positioned WHERE name LIKE '%" + term - + "%' AND ((type >= 1 AND type <= 3) OR ((type >= 9 AND type <= 11))) "; + + "%' AND ((type >= 1 AND type <= 3) OR ((type >= 9 AND type <= 11)) OR (type=18 AND name LIKE '% TACAN') ) "; } sqlite3_prepare_v2(d->db, sql.c_str(), sql.length(), &d->query, NULL);