X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FNavaids%2Fpositioned.cxx;h=7aa183eba02be4a831f782f39b433c4871b210fc;hb=e9a9f8c96d2963f28e4ecb4eaa91e47b52aaecf6;hp=91715687740a55e6ae44f9ada121ad189f014b78;hpb=9e44be1df7d01515c1dc4a2cda9e340d00c4b887;p=flightgear.git diff --git a/src/Navaids/positioned.cxx b/src/Navaids/positioned.cxx index 917156877..7aa183eba 100644 --- a/src/Navaids/positioned.cxx +++ b/src/Navaids/positioned.cxx @@ -28,16 +28,24 @@ #include #include // for sort #include +#include #include #include +#include // for osg::isNaN + #include +#include #include #include #include +#include +#include - +#include "PositionedBinding.hxx" +#include "Airports/simple.hxx" +#include "Main/fg_props.hxx" typedef std::multimap NamedPositionedIndex; typedef std::pair NamedIndexRange; @@ -500,6 +508,15 @@ char** searchAirportNamesAndIdents(const std::string& aFilter) return result; } +static void validateSGGeod(const SGGeod& geod) +{ + if (osg::isNaN(geod.getLatitudeDeg()) || + osg::isNaN(geod.getLongitudeDeg())) + { + throw sg_range_exception("position is invalid, NaNs"); + } +} + /////////////////////////////////////////////////////////////////////////////// bool @@ -518,7 +535,9 @@ FGPositioned::Filter::passType(Type aTy) const static FGPositioned::List findAll(const NamedPositionedIndex& aIndex, - const std::string& aName, FGPositioned::Filter* aFilter) + const std::string& aName, + FGPositioned::Filter* aFilter, + bool aExact) { FGPositioned::List result; if (aName.empty()) { @@ -526,9 +545,16 @@ findAll(const NamedPositionedIndex& aIndex, } std::string name = boost::to_upper_copy(aName); - std::string upperBoundId = name; - upperBoundId[upperBoundId.size()-1]++; - NamedPositionedIndex::const_iterator upperBound = aIndex.lower_bound(upperBoundId); + NamedPositionedIndex::const_iterator upperBound; + + if (aExact) { + upperBound = aIndex.upper_bound(name); + } else { + std::string upperBoundId = name; + upperBoundId[upperBoundId.size()-1]++; + upperBound = aIndex.lower_bound(upperBoundId); + } + NamedPositionedIndex::const_iterator it = aIndex.lower_bound(name); for (; it != upperBound; ++it) { @@ -608,7 +634,15 @@ FGPositioned::Type FGPositioned::typeFromName(const std::string& aName) {"fix", FIX}, {"tacan", TACAN}, {"dme", DME}, + {"atis", FREQ_ATIS}, + {"awos", FREQ_AWOS}, + {"tower", FREQ_TOWER}, + {"ground", FREQ_GROUND}, + {"approach", FREQ_APP_DEP}, + {"departure", FREQ_APP_DEP}, // aliases + {"gnd", FREQ_GROUND}, + {"twr", FREQ_TOWER}, {"waypoint", WAYPOINT}, {"apt", AIRPORT}, {"arpt", AIRPORT}, @@ -652,18 +686,33 @@ const char* FGPositioned::nameForType(Type aTy) case WAYPOINT: return "waypoint"; case DME: return "dme"; case TACAN: return "tacan"; + case FREQ_TOWER: return "tower"; + case FREQ_ATIS: return "atis"; + case FREQ_AWOS: return "awos"; + case FREQ_GROUND: return "ground"; + case FREQ_CLEARANCE: return "clearance"; + case FREQ_UNICOM: return "unicom"; + case FREQ_APP_DEP: return "approach-departure"; default: return "unknown"; } } +flightgear::PositionedBinding* +FGPositioned::createBinding(SGPropertyNode* node) const +{ + return new flightgear::PositionedBinding(this, node); +} + /////////////////////////////////////////////////////////////////////////////// // search / query functions FGPositionedRef FGPositioned::findClosestWithIdent(const std::string& aIdent, const SGGeod& aPos, Filter* aFilter) { - FGPositioned::List r(findAll(global_identIndex, aIdent, aFilter)); + validateSGGeod(aPos); + + FGPositioned::List r(findAll(global_identIndex, aIdent, aFilter, true)); if (r.empty()) { return FGPositionedRef(); } @@ -675,6 +724,8 @@ FGPositioned::findClosestWithIdent(const std::string& aIdent, const SGGeod& aPos FGPositioned::List FGPositioned::findWithinRange(const SGGeod& aPos, double aRangeNm, Filter* aFilter) { + validateSGGeod(aPos); + List result; Octree::findAllWithinRange(SGVec3d::fromGeod(aPos), aRangeNm * SG_NM_TO_METER, aFilter, result); @@ -682,32 +733,36 @@ FGPositioned::findWithinRange(const SGGeod& aPos, double aRangeNm, Filter* aFilt } FGPositioned::List -FGPositioned::findAllWithIdent(const std::string& aIdent, Filter* aFilter) +FGPositioned::findAllWithIdent(const std::string& aIdent, Filter* aFilter, bool aExact) { - return findAll(global_identIndex, aIdent, aFilter); + return findAll(global_identIndex, aIdent, aFilter, aExact); } FGPositioned::List -FGPositioned::findAllWithName(const std::string& aName, Filter* aFilter) +FGPositioned::findAllWithName(const std::string& aName, Filter* aFilter, bool aExact) { - return findAll(global_nameIndex, aName, aFilter); + return findAll(global_nameIndex, aName, aFilter, aExact); } FGPositionedRef FGPositioned::findClosest(const SGGeod& aPos, double aCutoffNm, Filter* aFilter) { - List l(findClosestN(aPos, 1, aCutoffNm, aFilter)); - if (l.empty()) { - return NULL; - } - - assert(l.size() == 1); - return l.front(); + validateSGGeod(aPos); + + List l(findClosestN(aPos, 1, aCutoffNm, aFilter)); + if (l.empty()) { + return NULL; + } + + assert(l.size() == 1); + return l.front(); } FGPositioned::List FGPositioned::findClosestN(const SGGeod& aPos, unsigned int aN, double aCutoffNm, Filter* aFilter) { + validateSGGeod(aPos); + List result; Octree::findNearestN(SGVec3d::fromGeod(aPos), aN, aCutoffNm * SG_NM_TO_METER, aFilter, result); return result; @@ -763,6 +818,8 @@ FGPositioned::findNextWithPartialId(FGPositionedRef aCur, const std::string& aId void FGPositioned::sortByRange(List& aResult, const SGGeod& aPos) { + validateSGGeod(aPos); + SGVec3d cartPos(SGVec3d::fromGeod(aPos)); // computer ordering values Octree::FindNearestResults r; @@ -781,3 +838,145 @@ FGPositioned::sortByRange(List& aResult, const SGGeod& aPos) aResult[i] = r[i].get(); } } + +FGPositioned::Filter* createSearchFilter(const SGPropertyNode* arg) +{ + string sty(arg->getStringValue("type", "any")); + FGPositioned::Type ty = FGPositioned::typeFromName(sty); + double minRunwayLenFt = arg->getDoubleValue("min-runway-length-ft", -1.0); + + if ((ty == FGPositioned::AIRPORT) && (minRunwayLenFt > 0.0)) { + return new FGAirport::HardSurfaceFilter(minRunwayLenFt); + } else if (ty != FGPositioned::INVALID) { + FGPositioned::TypeFilter* tf = new FGPositioned::TypeFilter(ty); + + for (int t=1; arg->hasChild("type", t); ++t) { + sty = arg->getChild("type", t)->getStringValue(); + tf->addType(FGPositioned::typeFromName(sty)); + } + + return tf; + } + + return NULL; +} + +static SGGeod commandSearchPos(const SGPropertyNode* arg) +{ + if (arg->hasChild("longitude-deg") && arg->hasChild("latitude-deg")) { + return SGGeod::fromDeg(arg->getDoubleValue("longitude-deg"), + arg->getDoubleValue("latitude-deg")); + } + + // use current viewer/aircraft position + return SGGeod::fromDeg(fgGetDouble("/position/longitude-deg"), + fgGetDouble("/position/latitude-deg")); +} + +void commandClearExisting(const SGPropertyNode* arg) +{ + if (arg->getBoolValue("clear", true)) { + // delete all existing result children from their parent + string resultPath = arg->getStringValue("results"); + SGPropertyNode* n = fgGetNode(resultPath.c_str(), 0, true); + SGPropertyNode* pr = n->getParent(); + pr->removeChildren(n->getName(), false /* keep=false, i.e delete nodes */); + } +} + +bool commandFindClosest(const SGPropertyNode* arg) +{ + int n = arg->getIntValue("max-results", 1); + if ((n < 1) || (n > 100)) { + SG_LOG(SG_GENERAL, SG_WARN, "commandFindClosest: max-results invalid:" << n); + return false; + } + + string resultPath = arg->getStringValue("results"); + if (resultPath.empty()) { + SG_LOG(SG_GENERAL, SG_WARN, "commandFindClosest: no results path defined"); + return false; + } + + std::auto_ptr filt(createSearchFilter(arg)); +// cap search range, since huge ranges will overload everything + double cutoff = arg->getDoubleValue("cutoff-nm", 400.0); + SG_CLAMP_RANGE(cutoff, 0.0, 1000.0); + + SGGeod pos = commandSearchPos(arg); + commandClearExisting(arg); + + FGPositioned::List results = FGPositioned::findClosestN(pos, n, cutoff, filt.get()); + for (unsigned int i=0; igetStringValue("results"); + if (resultPath.empty()) { + SG_LOG(SG_GENERAL, SG_WARN, "commandFindByIdent: no results path defined"); + return false; + } + + std::auto_ptr filt(createSearchFilter(arg)); + SGGeod pos = commandSearchPos(arg); + commandClearExisting(arg); + + FGPositioned::List results; + bool exact = arg->getBoolValue("exact", true); + if (arg->hasChild("name")) { + results = FGPositioned::findAllWithName(arg->getStringValue("name"), filt.get(), exact); + } else if (arg->hasChild("ident")) { + results = FGPositioned::findAllWithIdent(arg->getStringValue("ident"), filt.get(), exact); + } else { + SG_LOG(SG_GENERAL, SG_WARN, "commandFindByIdent: no search term defined"); + return false; + } + + bool orderByRange = arg->getBoolValue("order-by-distance", true); + if (orderByRange) { + FGPositioned::sortByRange(results, pos); + } + + for (unsigned int i=0; iaddCommand("find-nearest", commandFindClosest); + SGCommandMgr::instance()->addCommand("find-by-ident", commandFindByIdent); +} + +FGPositioned::TypeFilter::TypeFilter(Type aTy) +{ + types.push_back(aTy); +} + +void FGPositioned::TypeFilter::addType(Type aTy) +{ + types.push_back(aTy); +} + +bool +FGPositioned::TypeFilter::pass(FGPositioned* aPos) const +{ + std::vector::const_iterator it = types.begin(), + end = types.end(); + for (; it != end; ++it) { + return aPos->type() == *it; + } + + return false; +} +