]> git.mxchange.org Git - flightgear.git/commitdiff
Further extensions to FGPositioned to support ongoing GPS work.
authorjmt <jmt>
Sun, 27 Sep 2009 23:12:58 +0000 (23:12 +0000)
committerTim Moore <timoore@redhat.com>
Mon, 28 Sep 2009 22:01:56 +0000 (00:01 +0200)
src/Navaids/positioned.cxx
src/Navaids/positioned.hxx

index 6324578c36013a03a728c9712fb2d8e946981d6a..93204670b22dbb77e02af1a1c9cb0e1852997421 100644 (file)
@@ -474,6 +474,10 @@ FGPositioned::cart() const
 
 FGPositioned::Type FGPositioned::typeFromName(const std::string& aName)
 {
+  if (aName.empty() || (aName == "")) {
+    return INVALID;
+  }
+
   typedef struct {
     const char* _name;
     Type _ty;
@@ -489,7 +493,8 @@ FGPositioned::Type FGPositioned::typeFromName(const std::string& aName)
     {"dme", DME},
   // aliases
     {"waypoint", WAYPOINT},
-  
+    {"apt", AIRPORT},
+    
     {NULL, INVALID}
   };
   
@@ -585,55 +590,60 @@ FGPositioned::findClosestN(const SGGeod& aPos, unsigned int aN, double aCutoffNm
   return spatialGetClosest(aPos, aN, aCutoffNm, aFilter);
 }
 
-/*
 FGPositionedRef
 FGPositioned::findNextWithPartialId(FGPositionedRef aCur, const std::string& aId, Filter* aFilter)
 {
+  // It is essential to bound our search, to avoid iterating all the way to the end of the database.
+  // Do this by generating a second ID with the final character incremented by 1.
+  // e.g., if the partial ID is "KI", we wish to search "KIxxx" but not "KJ".
+  std::string upperBoundId = aId;
+  upperBoundId[upperBoundId.size()-1]++;
+  NamedPositionedIndex::const_iterator upperBound = global_namedIndex.lower_bound(upperBoundId);
+
   NamedIndexRange range = global_namedIndex.equal_range(aId);
-  for (; range.first != range.second; ++range.first) {
-    FGPositionedRef candidate = range.first->second;
-    if (aCur == candidate) {
-      aCur = NULL; // found our start point, next match will pass
-      continue;
-    }
-    
-    if (aFilter) {
-      if (aFilter->hasTypeRange() && !aFilter->passType(candidate->type())) {
+  while (range.first != upperBound) {
+    for (; range.first != range.second; ++range.first) {
+      FGPositionedRef candidate = range.first->second;
+      if (aCur == candidate) {
+        aCur = NULL; // found our start point, next match will pass
         continue;
       }
 
-      if(!aFilter->pass(candidate)) {
-        continue;
+      if (aFilter) {
+        if (aFilter->hasTypeRange() && !aFilter->passType(candidate->type())) {
+          continue;
+        }
+
+        if (!aFilter->pass(candidate)) {
+          continue;
+        }
+      }
+
+      if (!aCur) {
+        return candidate;
       }
     }
-  
-    if (!aCur) {
-      return candidate;
-    }
+
+    // Unable to match the filter with this range - try the next range.
+    range = global_namedIndex.equal_range(range.second->first);
   }
-  
-  return NULL; // fell out, no match in range
-}*/
 
+  return NULL; // Reached the end of the valid sequence with no match.  
+}
+  
 FGPositionedRef
-FGPositioned::findNextWithPartialId(FGPositionedRef aCur, const std::string& aId, Filter* aFilter)
+FGPositioned::findWithPartialId(const std::string& aId, Filter* aFilter, int aOffset)
 {
-  // It is essential to bound our search, to avoid iterating all the way to the end of the database.
-  // Do this by generating a second ID with the final character incremented by 1.
-  // e.g., if the partial ID is "KI", we wish to search "KIxxx" but not "KJ".
+  // see comment in findNextWithPartialId concerning upperBoundId
   std::string upperBoundId = aId;
   upperBoundId[upperBoundId.size()-1]++;
   NamedPositionedIndex::const_iterator upperBound = global_namedIndex.lower_bound(upperBoundId);
 
   NamedIndexRange range = global_namedIndex.equal_range(aId);
+  
   while (range.first != upperBound) {
     for (; range.first != range.second; ++range.first) {
       FGPositionedRef candidate = range.first->second;
-      if (aCur == candidate) {
-        aCur = NULL; // found our start point, next match will pass
-        continue;
-      }
-
       if (aFilter) {
         if (aFilter->hasTypeRange() && !aFilter->passType(candidate->type())) {
           continue;
@@ -644,8 +654,10 @@ FGPositioned::findNextWithPartialId(FGPositionedRef aCur, const std::string& aId
         }
       }
 
-      if (!aCur) {
+      if (aOffset == 0) {
         return candidate;
+      } else {
+        --aOffset; // seen one more valid result, decrement the count
       }
     }
 
@@ -655,5 +667,50 @@ FGPositioned::findNextWithPartialId(FGPositionedRef aCur, const std::string& aId
 
   return NULL; // Reached the end of the valid sequence with no match.  
 }
+
+/**
+ * Wrapper filter which proxies to an inner filter, but also ensures the
+ * ident starts with supplied partial ident.
+ */
+class PartialIdentFilter : public FGPositioned::Filter
+{
+public:
+  PartialIdentFilter(const std::string& ident, FGPositioned::Filter* filter) :
+    _ident(ident),
+    _inner(filter)
+  { ; }
   
+  virtual bool pass(FGPositioned* aPos) const
+  {
+    if (!_inner->pass(aPos)) {
+      return false;
+    }
+    
+    return (::strncmp(aPos->ident().c_str(), _ident.c_str(), _ident.size()) == 0);
+  }
+    
+  virtual FGPositioned::Type minType() const
+  { return _inner->minType(); }
+    
+  virtual FGPositioned::Type maxType() const
+  { return _inner->maxType(); }
+    
+private:
+  std::string _ident;
+  FGPositioned::Filter* _inner;
+};
+
+FGPositionedRef
+FGPositioned::findClosestWithPartialId(const SGGeod& aPos, const std::string& aId, Filter* aFilter, int aOffset)
+{
+  PartialIdentFilter pf(aId, aFilter);
+  List matches = spatialGetClosest(aPos, aOffset + 1, 1000.0, &pf);
+  
+  if ((int) matches.size() <= aOffset) {
+    SG_LOG(SG_GENERAL, SG_INFO, "FGPositioned::findClosestWithPartialId, couldn't match enough with prefix:" << aId);
+    return NULL; // couldn't find a match within the cutoff distance
+  }
+  
+  return matches[aOffset];
+}
 
index 4d1f6081fbb32252dde13bac5a38a6d2d47278ef..b56f3b0933521c05244a51eeb8db7bfe98c78765 100644 (file)
@@ -158,6 +158,11 @@ public:
    */
   static FGPositionedRef findNextWithPartialId(FGPositionedRef aCur, const std::string& aId, Filter* aFilter = NULL);
   
+  /**
+   * As above, but searches using an offset index
+   */
+  static FGPositionedRef findWithPartialId(const std::string& aId, Filter* aFilter, int aOffset);
+  
   /**
    * Find all items with the specified ident, and return then sorted by
    * distance from a position
@@ -182,12 +187,18 @@ public:
    * Very large cutoff values will make this slow.
    * 
    * @result The matches (possibly less than N, depending on the filter and cutoff),
-  *    sorted by distance from the search pos
+   *    sorted by distance from the search pos
    * @param aN - number of matches to find
    * @param aCutoffNm - maximum distance to search within, in nautical miles
    */
   static List findClosestN(const SGGeod& aPos, unsigned int aN, double aCutoffNm, Filter* aFilter = NULL);
   
+  /**
+   * Find the closest match based on partial id (with an offset to allow selecting the n-th closest).
+   * Cutoff distance is limited internally, to avoid making this very slow.
+   */
+  static FGPositionedRef findClosestWithPartialId(const SGGeod& aPos, const std::string& aId, Filter* aFilter, int aOffset);
+
   /**
    * Map a candidate type string to a real type. Returns INVALID if the string
    * does not correspond to a defined type.