At large search ranges (320 or 640NM range on the 777), the search time can blow up, especially if distant airports are being loaded. Add a time-bounded spatial query, and use it, so performance stays tolerable.
if (!_cachedItemsValid) {
Filter filt(this);
filt.minRunwayLengthFt = fgGetDouble("/sim/navdb/min-runway-length-ft", 2000);
- _itemsInRange = FGPositioned::findClosestN(_pos, _maxSymbols, _rangeNm, &filt);
+ bool wasTimeLimited;
+ _itemsInRange = FGPositioned::findClosestNPartial(_pos, _maxSymbols, _rangeNm,
+ &filt, wasTimeLimited);
_cachedItemsValid = true;
_cachedPos = SGVec3d::fromGeod(_pos);
+
+ if (wasTimeLimited) {
+ // re-query next frame, to load incrementally
+ _cachedItemsValid = false;
+ }
}
// sort by distance from pos, so symbol limits are accurate
return result;
}
-void findNearestN(const SGVec3d& aPos, unsigned int aN, double aCutoffM, FGPositioned::Filter* aFilter, FGPositioned::List& aResults)
+bool findNearestN(const SGVec3d& aPos, unsigned int aN, double aCutoffM, FGPositioned::Filter* aFilter, FGPositioned::List& aResults, int aCutoffMsec)
{
aResults.clear();
FindNearestPQueue pq;
pq.push(Ordered<Node*>(global_spatialOctree, 0));
double cut = aCutoffM;
- while (!pq.empty()) {
+ SGTimeStamp tm;
+ tm.stamp();
+
+ while (!pq.empty() && (tm.elapsedMSec() < aCutoffMsec)) {
if (!results.empty()) {
// terminate the search if we have sufficent results, and we are
// sure no node still on the queue contains a closer match
double furthestResultOrder = results.back().order();
- // std::cout << "furthest result:" << furthestResultOrder << ", top node order:" << pq.top().order() << std::endl;
if ((results.size() >= aN) && (furthestResultOrder < pq.top().order())) {
+ // clear the PQ to mark this has 'full results' instead of partial
+ pq = FindNearestPQueue();
break;
}
}
Node* nd = pq.top().get();
pq.pop();
-// std::cout << "visiting:" << std::oct << nd->guid() << "(" << std::dec << nd->guid() << ")" << std::endl;
nd->visit(aPos, cut, aFilter, results, pq);
} // of queue iteration
for (unsigned int r=0; r<numResults; ++r) {
aResults[r] = results[r].get();
}
+
+ return !pq.empty();
}
bool findAllWithinRange(const SGVec3d& aPos, double aRangeM, FGPositioned::Filter* aFilter, FGPositioned::List& aResults, int aCutoffMsec)
mutable bool childrenLoaded;
};
- void findNearestN(const SGVec3d& aPos, unsigned int aN, double aCutoffM, FGPositioned::Filter* aFilter, FGPositioned::List& aResults);
+ bool findNearestN(const SGVec3d& aPos, unsigned int aN, double aCutoffM, FGPositioned::Filter* aFilter, FGPositioned::List& aResults, int aCutoffMsec);
bool findAllWithinRange(const SGVec3d& aPos, double aRangeM, FGPositioned::Filter* aFilter, FGPositioned::List& aResults, int aCutoffMsec);
} // of namespace Octree
validateSGGeod(aPos);
List result;
- Octree::findNearestN(SGVec3d::fromGeod(aPos), aN, aCutoffNm * SG_NM_TO_METER, aFilter, result);
+ int limitMsec = 0xffff;
+ Octree::findNearestN(SGVec3d::fromGeod(aPos), aN, aCutoffNm * SG_NM_TO_METER, aFilter, result, limitMsec);
return result;
}
-
+
+FGPositioned::List
+FGPositioned::findClosestNPartial(const SGGeod& aPos, unsigned int aN, double aCutoffNm, Filter* aFilter, bool &aPartial)
+{
+ validateSGGeod(aPos);
+
+ List 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)
{
* @param aCutoffNm - maximum distance to search within, in nautical miles
*/
static List findClosestN(const SGGeod& aPos, unsigned int aN, double aCutoffNm, Filter* aFilter = NULL);
-
+
+ /**
+ * Same as above, but with a time-bound in msec too.
+ */
+ static List findClosestNPartial(const SGGeod& aPos, unsigned int aN, double aCutoffNm, Filter* aFilter,
+ bool& aPartial);
+
/**
* Map a candidate type string to a real type. Returns INVALID if the string
* does not correspond to a defined type.