#include <queue>
#include <memory>
+#include <boost/foreach.hpp>
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/algorithm/string/predicate.hpp>
}
}
+static bool validateFilter(FGPositioned::Filter* filter)
+{
+ if (filter->maxType() < filter->minType()) {
+ SG_LOG(SG_GENERAL, SG_WARN, "invalid positioned filter specified");
+ return false;
+ }
+
+ return true;
+}
+
///////////////////////////////////////////////////////////////////////////////
FGPositioned*
FGPositioned::createUserWaypoint(const std::string& aIdent, const SGGeod& aPos)
{
- PositionedID id = NavDataCache::instance()->createUserWaypoint(aIdent, aPos);
- return NavDataCache::instance()->loadById(id);
+ NavDataCache* cache = NavDataCache::instance();
+ TypeFilter filter(WAYPOINT);
+ FGPositionedList existing = cache->findAllWithIdent(aIdent, &filter, true);
+ if (!existing.empty()) {
+ SG_LOG(SG_NAVAID, SG_WARN, "attempt to insert duplicate WAYPOINT:" << aIdent);
+ return existing.front().ptr();
+ }
+
+ PositionedID id = cache->createPOI(WAYPOINT, aIdent, aPos);
+ return cache->loadById(id);
+}
+
+bool FGPositioned::deleteUserWaypoint(const std::string& aIdent)
+{
+ NavDataCache* cache = NavDataCache::instance();
+ return cache->removePOI(WAYPOINT, aIdent);
}
+
const SGVec3d&
FGPositioned::cart() const
{
{"ground", FREQ_GROUND},
{"approach", FREQ_APP_DEP},
{"departure", FREQ_APP_DEP},
+ {"runway", RUNWAY},
+ {"helipad", HELIPAD},
+ {"country", COUNTRY},
+ {"city", CITY},
+ {"town", TOWN},
+ {"village", VILLAGE},
+
// aliases
+ {"localizer", LOC},
{"gnd", FREQ_GROUND},
{"twr", FREQ_TOWER},
{"waypoint", WAYPOINT},
{"apt", AIRPORT},
{"arpt", AIRPORT},
+ {"rwy", RUNWAY},
{"any", INVALID},
{"all", INVALID},
{
switch (aTy) {
case RUNWAY: return "runway";
+ case HELIPAD: return "helipad";
case TAXIWAY: return "taxiway";
case PAVEMENT: return "pavement";
case PARKING: return "parking stand";
case VOR: return "VOR";
case NDB: return "NDB";
case ILS: return "ILS";
- case LOC: return "localiser";
+ case LOC: return "localizer";
case GS: return "glideslope";
case OM: return "outer-marker";
case MM: return "middle-marker";
case FREQ_UNICOM: return "unicom";
case FREQ_APP_DEP: return "approach-departure";
case TAXI_NODE: return "taxi-node";
+ case COUNTRY: return "country";
+ case CITY: return "city";
+ case TOWN: return "town";
+ case VILLAGE: return "village";
default:
return "unknown";
}
return NULL;
}
- List r = NavDataCache::instance()->findAllWithIdent(aIdent, aFilter, true);
+ FGPositionedList r =
+ NavDataCache::instance()->findAllWithIdent(aIdent, aFilter, true);
if (r.empty()) {
return NULL;
}
return r.front();
}
-FGPositioned::List
+FGPositionedList
FGPositioned::findWithinRange(const SGGeod& aPos, double aRangeNm, Filter* aFilter)
{
validateSGGeod(aPos);
- List result;
+ if (!validateFilter(aFilter)) {
+ return FGPositionedList();
+ }
+
+ FGPositionedList result;
Octree::findAllWithinRange(SGVec3d::fromGeod(aPos),
- aRangeNm * SG_NM_TO_METER, aFilter, result);
+ aRangeNm * SG_NM_TO_METER, aFilter, result, 0xffffff);
+ return result;
+}
+
+FGPositionedList
+FGPositioned::findWithinRangePartial(const SGGeod& aPos, double aRangeNm, Filter* aFilter, bool& aPartial)
+{
+ validateSGGeod(aPos);
+
+ if (!validateFilter(aFilter)) {
+ return FGPositionedList();
+ }
+
+ int limitMsec = 32;
+ FGPositionedList result;
+ aPartial = Octree::findAllWithinRange(SGVec3d::fromGeod(aPos),
+ aRangeNm * SG_NM_TO_METER, aFilter, result,
+ limitMsec);
return result;
}
-FGPositioned::List
+FGPositionedList
FGPositioned::findAllWithIdent(const std::string& aIdent, Filter* aFilter, bool aExact)
{
+ if (!validateFilter(aFilter)) {
+ return FGPositionedList();
+ }
+
return NavDataCache::instance()->findAllWithIdent(aIdent, aFilter, aExact);
}
-FGPositioned::List
+FGPositionedList
FGPositioned::findAllWithName(const std::string& aName, Filter* aFilter, bool aExact)
{
+ if (!validateFilter(aFilter)) {
+ return FGPositionedList();
+ }
+
return NavDataCache::instance()->findAllWithName(aName, aFilter, aExact);
}
{
validateSGGeod(aPos);
- List l(findClosestN(aPos, 1, aCutoffNm, aFilter));
+ if (!validateFilter(aFilter)) {
+ return NULL;
+ }
+
+ FGPositionedList l(findClosestN(aPos, 1, aCutoffNm, aFilter));
if (l.empty()) {
return NULL;
}
return l.front();
}
-FGPositioned::List
+FGPositionedList
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);
+ FGPositionedList result;
+ int limitMsec = 0xffff;
+ Octree::findNearestN(SGVec3d::fromGeod(aPos), aN, aCutoffNm * SG_NM_TO_METER, aFilter, result, limitMsec);
return result;
}
-
+
+FGPositionedList
+FGPositioned::findClosestNPartial(const SGGeod& aPos, unsigned int aN, double aCutoffNm, Filter* aFilter, bool &aPartial)
+{
+ validateSGGeod(aPos);
+
+ FGPositionedList result;
+ int limitMsec = 32;
+ aPartial = Octree::findNearestN(SGVec3d::fromGeod(aPos), aN, aCutoffNm * SG_NM_TO_METER, aFilter, result,
+ limitMsec);
+ return result;
+}
+
void
-FGPositioned::sortByRange(List& aResult, const SGGeod& aPos)
+FGPositioned::sortByRange(FGPositionedList& aResult, const SGGeod& aPos)
{
validateSGGeod(aPos);
SGVec3d cartPos(SGVec3d::fromGeod(aPos));
// computer ordering values
Octree::FindNearestResults r;
- List::iterator it = aResult.begin(), lend = aResult.end();
+ FGPositionedList::iterator it = aResult.begin(), lend = aResult.end();
for (; it != lend; ++it) {
double d2 = distSqr((*it)->cart(), cartPos);
r.push_back(Octree::OrderedPositioned(*it, d2));
const_cast<SGVec3d&>(mCart) = SGVec3d::fromGeod(newPos);
}
+//------------------------------------------------------------------------------
+FGPositionedRef FGPositioned::loadByIdImpl(PositionedID id)
+{
+ return flightgear::NavDataCache::instance()->loadById(id);
+}
+
FGPositioned::TypeFilter::TypeFilter(Type aTy) :
- mMinType(aTy),
- mMaxType(aTy)
+ mMinType(LAST_TYPE),
+ mMaxType(INVALID)
{
addType(aTy);
}
mMaxType = std::max(mMaxType, aTy);
}
+FGPositioned::TypeFilter
+FGPositioned::TypeFilter::fromString(const std::string& aFilterSpec)
+{
+ if (aFilterSpec.empty()) {
+ throw sg_format_exception("empty filter spec:", aFilterSpec);
+ }
+
+ string_list parts = simgear::strutils::split(aFilterSpec, ",");
+ TypeFilter f;
+
+ BOOST_FOREACH(std::string token, parts) {
+ f.addType(typeFromName(token));
+ }
+
+ return f;
+}
+
bool
FGPositioned::TypeFilter::pass(FGPositioned* aPos) const
{
std::vector<Type>::const_iterator it = types.begin(),
end = types.end();
for (; it != end; ++it) {
- return aPos->type() == *it;
+ if (aPos->type() == *it) {
+ return true;
+ }
}
return false;