Basic infrastructure to expose type ranges from filters, and hence reduce
how many candidates need to be submitted to the pass() hook.
This commit is contained in:
parent
8ad7f4eb70
commit
2d852024c6
2 changed files with 78 additions and 57 deletions
|
@ -37,6 +37,9 @@
|
|||
typedef std::multimap<std::string, FGPositioned*> NamedPositionedIndex;
|
||||
typedef std::pair<NamedPositionedIndex::const_iterator, NamedPositionedIndex::const_iterator> NamedIndexRange;
|
||||
|
||||
using std::lower_bound;
|
||||
using std::upper_bound;
|
||||
|
||||
/**
|
||||
* Order positioned elements by type, then pointer address. This allows us to
|
||||
* use range searches (lower_ and upper_bound) to grab items of a particular
|
||||
|
@ -52,6 +55,21 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class LowerLimitOfType
|
||||
{
|
||||
public:
|
||||
bool operator()(const FGPositioned* a, const FGPositioned::Type b) const
|
||||
{
|
||||
return a->type() < b;
|
||||
}
|
||||
|
||||
bool operator()(const FGPositioned::Type a, const FGPositioned* b) const
|
||||
{
|
||||
return a < b->type();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
typedef std::set<FGPositioned*, OrderByType> BucketEntry;
|
||||
typedef std::map<long int, BucketEntry> SpatialPositionedIndex;
|
||||
|
||||
|
@ -122,6 +140,12 @@ spatialFilterInBucket(const SGBucket& aBucket, FGPositioned::Filter* aFilter, FG
|
|||
return;
|
||||
}
|
||||
|
||||
if (aFilter->hasTypeRange()) {
|
||||
// avoid many calls to the filter hook
|
||||
l = lower_bound(it->second.begin(), it->second.end(), aFilter->minType(), LowerLimitOfType());
|
||||
u = upper_bound(l, it->second.end(), aFilter->maxType(), LowerLimitOfType());
|
||||
}
|
||||
|
||||
for ( ; l != u; ++l) {
|
||||
if ((*aFilter)(*l)) {
|
||||
aResult.push_back(*l);
|
||||
|
@ -148,55 +172,6 @@ spatialFind(const SGGeod& aPos, double aRange,
|
|||
} // of i-iteration
|
||||
}
|
||||
|
||||
/*
|
||||
class LowerLimitOfType
|
||||
{
|
||||
public:
|
||||
bool operator()(const FGPositioned* a, const FGPositioned::Type b) const
|
||||
{
|
||||
return a->type() < b;
|
||||
}
|
||||
|
||||
bool operator()(const FGPositioned::Type a, const FGPositioned* b) const
|
||||
{
|
||||
return a < b->type();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
spatialFindTyped(const SGGeod& aPos, double aRange, FGPositioned::Type aLower, FGPositioned::Type aUpper, FGPositioned::List& aResult)
|
||||
{
|
||||
SGBucket buck(aPos);
|
||||
double lat = aPos.getLatitudeDeg(),
|
||||
lon = aPos.getLongitudeDeg();
|
||||
|
||||
int bx = (int)( aRange*SG_NM_TO_METER / buck.get_width_m() / 2);
|
||||
int by = (int)( aRange*SG_NM_TO_METER / buck.get_height_m() / 2 );
|
||||
|
||||
// loop over bucket range
|
||||
for ( int i=-bx; i<=bx; i++) {
|
||||
for ( int j=-by; j<=by; j++) {
|
||||
buck = sgBucketOffset(lon, lat, i, j);
|
||||
|
||||
SpatialPositionedIndex::const_iterator it;
|
||||
it = global_spatialIndex.find(buck.gen_index());
|
||||
if (it == global_spatialIndex.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BucketEntry::const_iterator l = std::lower_bound(it->second.begin(), it->second.end(), aLower, LowerLimitOfType());
|
||||
BucketEntry::const_iterator u = std::upper_bound(l, it->second.end(), aUpper, LowerLimitOfType());
|
||||
|
||||
for ( ; l != u; ++l) {
|
||||
aResult.push_back(*l);
|
||||
}
|
||||
|
||||
} // of j-iteration
|
||||
} // of i-iteration
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
*/
|
||||
class RangePredictate
|
||||
|
@ -263,12 +238,19 @@ namedFindClosest(const std::string& aIdent, const SGGeod& aOrigin, FGPositioned:
|
|||
// sequential iterators, not random-access ones
|
||||
NamedPositionedIndex::const_iterator check = range.first;
|
||||
if (++check == range.second) {
|
||||
// excellent, only one match in the range - all we care about is the type
|
||||
if (aFilter && !aFilter->pass(range.first->second)) {
|
||||
return NULL; // type check failed
|
||||
}
|
||||
|
||||
return range.first->second;
|
||||
// excellent, only one match in the range
|
||||
FGPositioned* r = range.first->second;
|
||||
if (aFilter) {
|
||||
if (aFilter->hasTypeRange() && !aFilter->passType(r->type())) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!aFilter->pass(r)) {
|
||||
return NULL;
|
||||
}
|
||||
} // of have a filter
|
||||
|
||||
return r;
|
||||
} // of short-circuit logic for single-element range
|
||||
|
||||
// multiple matches, we need to actually check the distance to each one
|
||||
|
@ -278,8 +260,15 @@ namedFindClosest(const std::string& aIdent, const SGGeod& aOrigin, FGPositioned:
|
|||
SGVec3d cartOrigin(SGVec3d::fromGeod(aOrigin));
|
||||
|
||||
for (; it != range.second; ++it) {
|
||||
if (aFilter && !aFilter->pass(range.first->second)) {
|
||||
continue;
|
||||
FGPositioned::Type ty = range.first->second->type();
|
||||
if (aFilter) {
|
||||
if (aFilter->hasTypeRange() && !aFilter->passType(ty)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!aFilter->pass(range.first->second)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// find distance
|
||||
|
@ -428,6 +417,22 @@ char** searchAirportNamesAndIdents(const std::string& aFilter)
|
|||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool
|
||||
FGPositioned::Filter::hasTypeRange() const
|
||||
{
|
||||
assert(minType() <= maxType());
|
||||
return (minType() != INVALID) && (maxType() != INVALID);
|
||||
}
|
||||
|
||||
bool
|
||||
FGPositioned::Filter::passType(Type aTy) const
|
||||
{
|
||||
assert(hasTypeRange());
|
||||
return (minType() <= aTy) && (maxType() >= aTy);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
FGPositioned::FGPositioned(Type ty, const std::string& aIdent, const SGGeod& aPos, bool aIndexed) :
|
||||
mType(ty),
|
||||
mPosition(aPos),
|
||||
|
|
|
@ -113,6 +113,22 @@ public:
|
|||
virtual bool pass(FGPositioned* aPos) const
|
||||
{ return true; }
|
||||
|
||||
virtual Type minType() const
|
||||
{ return INVALID; }
|
||||
|
||||
virtual Type maxType() const
|
||||
{ return INVALID; }
|
||||
|
||||
/**
|
||||
* Test if this filter has a non-empty type range
|
||||
*/
|
||||
bool hasTypeRange() const;
|
||||
|
||||
/**
|
||||
* Assuming hasTypeRange is true, test if a given type passes the range
|
||||
*/
|
||||
bool passType(Type aTy) const;
|
||||
|
||||
bool operator()(FGPositioned* aPos) const
|
||||
{ return pass(aPos); }
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue