From d6277068f50c661144c6ae183225a48e7c37028d Mon Sep 17 00:00:00 2001
From: jmt <jmt>
Date: Tue, 23 Dec 2008 12:37:59 +0000
Subject: [PATCH] (first commit, partly a low-risk thing to sanity check my
 setup) Add a helper predicate to FGAirport to encapsulate the common 'does
 this airport have a suitable runway of at least xxxx ft?' query. Also add a
 FGPositioned filter built on the predicate, and a 'closest airport' helper.

---
 src/Airports/runways.hxx |  3 +++
 src/Airports/simple.cxx  | 51 ++++++++++++++++++++++++++++++++++++++++
 src/Airports/simple.hxx  | 34 +++++++++++++++++++++++++++
 3 files changed, 88 insertions(+)

diff --git a/src/Airports/runways.hxx b/src/Airports/runways.hxx
index a2cc2ae62..9289e3404 100644
--- a/src/Airports/runways.hxx
+++ b/src/Airports/runways.hxx
@@ -129,6 +129,9 @@ public:
   void setAirport(FGAirport* aAirport)
   { _airport = aAirport; }
   
+  int surface() const 
+  { return _surface_code; }
+  
     std::string _rwy_no;
 
     double _lon;
diff --git a/src/Airports/simple.cxx b/src/Airports/simple.cxx
index 354cff448..1dc6b7d76 100644
--- a/src/Airports/simple.cxx
+++ b/src/Airports/simple.cxx
@@ -192,6 +192,28 @@ FGRunway* FGAirport::findBestRunwayForHeading(double aHeading) const
   return result;
 }
 
+bool FGAirport::hasHardRunwayOfLengthFt(double aLengthFt) const
+{
+  unsigned int numRunways(mRunways.size());
+  for (unsigned int r=0; r<numRunways; ++r) {
+    FGRunway* rwy = mRunways[r];
+    if (rwy->isReciprocal()) {
+      continue; // we only care about lengths, so don't do work twice
+    }
+    
+    int surface = rwy->surface();
+    if ((surface != 1) && (surface != 2)) {
+      continue; // no hard surface
+    }
+    
+    if (rwy->lengthFt() >= aLengthFt) {
+      return true; // we're done!
+    }
+  } // of runways iteration
+
+  return false;
+}
+
 unsigned int FGAirport::numTaxiways() const
 {
   return mTaxiways.size();
@@ -233,6 +255,35 @@ FGRunway* FGAirport::getActiveRunwayForUsage() const
   return findBestRunwayForHeading(hdg);
 }
 
+FGAirport* FGAirport::findClosest(const SGGeod& aPos, double aCuttofNm, Filter* filter)
+{
+  AirportFilter aptFilter;
+  if (filter == NULL) {
+    filter = &aptFilter;
+  }
+  
+  FGPositionedRef r = FGPositioned::findClosest(aPos, aCuttofNm, filter);
+  if (!r) {
+    return NULL;
+  }
+  
+  return static_cast<FGAirport*>(r.ptr());
+}
+
+FGAirport::HardSurfaceFilter::HardSurfaceFilter(double minLengthFt) :
+  mMinLengthFt(minLengthFt)
+{
+}
+      
+bool FGAirport::HardSurfaceFilter::pass(FGPositioned* aPos) const
+{
+  if (aPos->type() != AIRPORT) {
+    return false; // exclude seaports and heliports as well, we need a runways
+  }
+   
+  return static_cast<FGAirport*>(aPos)->hasHardRunwayOfLengthFt(mMinLengthFt);
+}
+
 /******************************************************************************
  * FGAirportList
  *****************************************************************************/
diff --git a/src/Airports/simple.hxx b/src/Airports/simple.hxx
index 2ec8a9173..a37524318 100644
--- a/src/Airports/simple.hxx
+++ b/src/Airports/simple.hxx
@@ -86,10 +86,44 @@ public:
     FGRunway* getRunwayByIdent(const std::string& aIdent) const;
     FGRunway* findBestRunwayForHeading(double aHeading) const;
     
+     /**
+     * Useful predicate for FMS/GPS/NAV displays and similar - check if this
+     * aiport has a hard-surfaced runway of at least the specified length.
+     * For the moment, hard means asphalt or concrete, not gravel or a
+     * lake bed.
+     */
+    bool hasHardRunwayOfLengthFt(double aLengthFt) const;
+    
     unsigned int numTaxiways() const;
     FGRunway* getTaxiwayByIndex(unsigned int aIndex) const;
     
     void addRunway(FGRunway* aRunway);
+    
+    class AirportFilter : public Filter
+     {
+     public:
+       virtual bool pass(FGPositioned* aPos) const { 
+         Type ty(aPos->type());
+         return (ty >= AIRPORT) && (ty <= SEAPORT);
+       }
+     };
+     
+     class HardSurfaceFilter : public Filter
+     {
+     public:
+       HardSurfaceFilter(double minLengthFt);
+       
+       virtual bool pass(FGPositioned* aPos) const;
+     private:
+       double mMinLengthFt;
+     };
+     
+     /**
+      * Syntactic wrapper around FGPositioned::findClosest - find the closest
+      * match for filter, and return it cast to FGAirport. The default filter
+      * passes all airports, including seaports and heliports.
+      */
+     static FGAirport* findClosest(const SGGeod& aPos, double aCuttofNm, Filter* filter = NULL);
 private:
     typedef std::vector<FGRunwayPtr>::const_iterator Runway_iterator;
     /**