1
0
Fork 0

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:
jmt 2009-01-08 21:11:08 +00:00 committed by Tim Moore
parent 8ad7f4eb70
commit 2d852024c6
2 changed files with 78 additions and 57 deletions

View file

@ -37,6 +37,9 @@
typedef std::multimap<std::string, FGPositioned*> NamedPositionedIndex; typedef std::multimap<std::string, FGPositioned*> NamedPositionedIndex;
typedef std::pair<NamedPositionedIndex::const_iterator, NamedPositionedIndex::const_iterator> NamedIndexRange; 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 * 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 * 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::set<FGPositioned*, OrderByType> BucketEntry;
typedef std::map<long int, BucketEntry> SpatialPositionedIndex; typedef std::map<long int, BucketEntry> SpatialPositionedIndex;
@ -122,6 +140,12 @@ spatialFilterInBucket(const SGBucket& aBucket, FGPositioned::Filter* aFilter, FG
return; 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) { for ( ; l != u; ++l) {
if ((*aFilter)(*l)) { if ((*aFilter)(*l)) {
aResult.push_back(*l); aResult.push_back(*l);
@ -148,55 +172,6 @@ spatialFind(const SGGeod& aPos, double aRange,
} // of i-iteration } // 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 class RangePredictate
@ -263,12 +238,19 @@ namedFindClosest(const std::string& aIdent, const SGGeod& aOrigin, FGPositioned:
// sequential iterators, not random-access ones // sequential iterators, not random-access ones
NamedPositionedIndex::const_iterator check = range.first; NamedPositionedIndex::const_iterator check = range.first;
if (++check == range.second) { if (++check == range.second) {
// excellent, only one match in the range - all we care about is the type // excellent, only one match in the range
if (aFilter && !aFilter->pass(range.first->second)) { FGPositioned* r = range.first->second;
return NULL; // type check failed if (aFilter) {
} if (aFilter->hasTypeRange() && !aFilter->passType(r->type())) {
return NULL;
return range.first->second; }
if (!aFilter->pass(r)) {
return NULL;
}
} // of have a filter
return r;
} // of short-circuit logic for single-element range } // of short-circuit logic for single-element range
// multiple matches, we need to actually check the distance to each one // 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)); SGVec3d cartOrigin(SGVec3d::fromGeod(aOrigin));
for (; it != range.second; ++it) { for (; it != range.second; ++it) {
if (aFilter && !aFilter->pass(range.first->second)) { FGPositioned::Type ty = range.first->second->type();
continue; if (aFilter) {
if (aFilter->hasTypeRange() && !aFilter->passType(ty)) {
continue;
}
if (!aFilter->pass(range.first->second)) {
continue;
}
} }
// find distance // 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) : FGPositioned::FGPositioned(Type ty, const std::string& aIdent, const SGGeod& aPos, bool aIndexed) :
mType(ty), mType(ty),
mPosition(aPos), mPosition(aPos),

View file

@ -113,6 +113,22 @@ public:
virtual bool pass(FGPositioned* aPos) const virtual bool pass(FGPositioned* aPos) const
{ return true; } { 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 bool operator()(FGPositioned* aPos) const
{ return pass(aPos); } { return pass(aPos); }
}; };