NavDisplay: time-bound the spatial query.
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.
This commit is contained in:
parent
d0e9503766
commit
851029143e
5 changed files with 40 additions and 9 deletions
|
@ -998,9 +998,16 @@ void NavDisplay::findItems()
|
||||||
if (!_cachedItemsValid) {
|
if (!_cachedItemsValid) {
|
||||||
Filter filt(this);
|
Filter filt(this);
|
||||||
filt.minRunwayLengthFt = fgGetDouble("/sim/navdb/min-runway-length-ft", 2000);
|
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;
|
_cachedItemsValid = true;
|
||||||
_cachedPos = SGVec3d::fromGeod(_pos);
|
_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
|
// sort by distance from pos, so symbol limits are accurate
|
||||||
|
|
|
@ -223,7 +223,7 @@ int Branch::childMask() const
|
||||||
return result;
|
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();
|
aResults.clear();
|
||||||
FindNearestPQueue pq;
|
FindNearestPQueue pq;
|
||||||
|
@ -231,13 +231,17 @@ void findNearestN(const SGVec3d& aPos, unsigned int aN, double aCutoffM, FGPosit
|
||||||
pq.push(Ordered<Node*>(global_spatialOctree, 0));
|
pq.push(Ordered<Node*>(global_spatialOctree, 0));
|
||||||
double cut = aCutoffM;
|
double cut = aCutoffM;
|
||||||
|
|
||||||
while (!pq.empty()) {
|
SGTimeStamp tm;
|
||||||
|
tm.stamp();
|
||||||
|
|
||||||
|
while (!pq.empty() && (tm.elapsedMSec() < aCutoffMsec)) {
|
||||||
if (!results.empty()) {
|
if (!results.empty()) {
|
||||||
// terminate the search if we have sufficent results, and we are
|
// terminate the search if we have sufficent results, and we are
|
||||||
// sure no node still on the queue contains a closer match
|
// sure no node still on the queue contains a closer match
|
||||||
double furthestResultOrder = results.back().order();
|
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())) {
|
if ((results.size() >= aN) && (furthestResultOrder < pq.top().order())) {
|
||||||
|
// clear the PQ to mark this has 'full results' instead of partial
|
||||||
|
pq = FindNearestPQueue();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -245,7 +249,6 @@ void findNearestN(const SGVec3d& aPos, unsigned int aN, double aCutoffM, FGPosit
|
||||||
Node* nd = pq.top().get();
|
Node* nd = pq.top().get();
|
||||||
pq.pop();
|
pq.pop();
|
||||||
|
|
||||||
// std::cout << "visiting:" << std::oct << nd->guid() << "(" << std::dec << nd->guid() << ")" << std::endl;
|
|
||||||
nd->visit(aPos, cut, aFilter, results, pq);
|
nd->visit(aPos, cut, aFilter, results, pq);
|
||||||
} // of queue iteration
|
} // of queue iteration
|
||||||
|
|
||||||
|
@ -257,6 +260,8 @@ void findNearestN(const SGVec3d& aPos, unsigned int aN, double aCutoffM, FGPosit
|
||||||
for (unsigned int r=0; r<numResults; ++r) {
|
for (unsigned int r=0; r<numResults; ++r) {
|
||||||
aResults[r] = results[r].get();
|
aResults[r] = results[r].get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return !pq.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool findAllWithinRange(const SGVec3d& aPos, double aRangeM, FGPositioned::Filter* aFilter, FGPositioned::List& aResults, int aCutoffMsec)
|
bool findAllWithinRange(const SGVec3d& aPos, double aRangeM, FGPositioned::Filter* aFilter, FGPositioned::List& aResults, int aCutoffMsec)
|
||||||
|
|
|
@ -215,7 +215,7 @@ namespace Octree
|
||||||
mutable bool childrenLoaded;
|
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);
|
bool findAllWithinRange(const SGVec3d& aPos, double aRangeM, FGPositioned::Filter* aFilter, FGPositioned::List& aResults, int aCutoffMsec);
|
||||||
} // of namespace Octree
|
} // of namespace Octree
|
||||||
|
|
||||||
|
|
|
@ -251,10 +251,23 @@ FGPositioned::findClosestN(const SGGeod& aPos, unsigned int aN, double aCutoffNm
|
||||||
validateSGGeod(aPos);
|
validateSGGeod(aPos);
|
||||||
|
|
||||||
List result;
|
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;
|
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
|
void
|
||||||
FGPositioned::sortByRange(List& aResult, const SGGeod& aPos)
|
FGPositioned::sortByRange(List& aResult, const SGGeod& aPos)
|
||||||
{
|
{
|
||||||
|
|
|
@ -210,7 +210,13 @@ public:
|
||||||
* @param aCutoffNm - maximum distance to search within, in nautical miles
|
* @param aCutoffNm - maximum distance to search within, in nautical miles
|
||||||
*/
|
*/
|
||||||
static List findClosestN(const SGGeod& aPos, unsigned int aN, double aCutoffNm, Filter* aFilter = NULL);
|
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
|
* Map a candidate type string to a real type. Returns INVALID if the string
|
||||||
* does not correspond to a defined type.
|
* does not correspond to a defined type.
|
||||||
|
|
Loading…
Add table
Reference in a new issue