]> git.mxchange.org Git - flightgear.git/commitdiff
James Turner:
authorehofman <ehofman>
Fri, 22 Aug 2008 11:22:22 +0000 (11:22 +0000)
committerehofman <ehofman>
Fri, 22 Aug 2008 11:22:22 +0000 (11:22 +0000)
This is a little intrusive on the KLN89 code, but avoids the wasteful cloning of the airports, runways and navaids which current happens, and also combines the ugly string ordering code.

src/Airports/simple.cxx
src/Airports/simple.hxx
src/Instrumentation/KLN89/kln89_page_fpl.cxx
src/Instrumentation/dclgps.cxx
src/Instrumentation/dclgps.hxx
src/Navaids/fixlist.cxx
src/Navaids/fixlist.hxx

index 89c2e6ec26d53781e7507596b47a6134451ab151..c550f4822627eba8ea535e03a5b8a08257ece8c1 100644 (file)
@@ -321,24 +321,42 @@ FGAirport* FGAirportList::search( const string& id)
     return (itr == airports_by_id.end() ? NULL : itr->second);
 }
 
+// wrap an FGIdentOrdering in an STL-compatible functor. not the most
+// efficent / pretty thing in the world, but avoids template nastiness in the 
+// headers, and we're only doing O(log(N)) comparisoms per search
+class orderingFunctor
+{
+public:
+  orderingFunctor(FGIdentOrdering* aOrder) :
+    mOrdering(aOrder)
+  { assert(aOrder); }
+  
+  bool operator()(const airport_map::value_type& aA, const std::string& aB) const
+  {
+    return mOrdering->compare(aA.first,aB);
+  }
+  
+private:
+  FGIdentOrdering* mOrdering;
+};
 
-// search for first subsequent alphabetically to supplied id
-const FGAirport* FGAirportList::findFirstById( const string& id, bool exact )
+const FGAirport* FGAirportList::findFirstById(const std::string& aIdent, FGIdentOrdering* aOrder)
 {
-    airport_map_iterator itr;
-    if (exact) {
-        itr = airports_by_id.find(id);
-    } else {
-        itr = airports_by_id.lower_bound(id);
-    }
-    if (itr == airports_by_id.end()) {
-        return (NULL);
-    } else {
-        return (itr->second);
-    }
+  airport_map_iterator itr;
+  if (aOrder) {
+    orderingFunctor func(aOrder);
+    itr = std::lower_bound(airports_by_id.begin(),airports_by_id.end(), aIdent, func);
+  } else {
+    itr = airports_by_id.lower_bound(aIdent);
+  }
+  
+  if (itr == airports_by_id.end()) {
+    return NULL;
+  }
+  
+  return itr->second;
 }
 
-
 // search for the airport nearest the specified position
 FGAirport* FGAirportList::search(double lon_deg, double lat_deg, double max_range)
 {
@@ -354,6 +372,7 @@ FGAirport* FGAirportList::search(double lon_deg, double lat_deg,
         FGAirportSearchFilter& filter)
 {
     double min_dist = max_range;
+
     airport_list_iterator it = airports_array.begin();
     airport_list_iterator end = airports_array.end();
     airport_list_iterator closest = end;
index b9b0c3e3358e0f47af02419c6fa3a9a6ee4e4757..bedbd7d9144f38799630dd71653766f582c128e4 100644 (file)
@@ -117,6 +117,14 @@ public:
     virtual bool pass(FGAirport*) { return true; }
 };
 
+class FGIdentOrdering {
+public:
+  virtual ~FGIdentOrdering()
+  { ; }
+  
+  virtual bool compare(const std::string& aA, const std::string& aB) const
+  { return aA < aB; }
+};
 
 typedef std::map < std::string, FGAirport* > airport_map;
 typedef airport_map::iterator airport_map_iterator;
@@ -152,11 +160,11 @@ public:
 
     // Search for the next airport in ASCII sequence to the supplied id.
     // eg. id = "KDC" or "KDCA" would both return "KDCA".
-    // If exact = true then only exact matches are returned.
     // NOTE: Numbers come prior to A-Z in ASCII sequence so id = "LD" would return "LD57", not "LDDP"
+    // optional ordering can make letters come before numbers
     // Implementation assumes airport codes are unique.
     // Returns NULL if unsucessfull.
-    const FGAirport* findFirstById( const std::string& id, bool exact = false );
+    const FGAirport* findFirstById(const std::string& aIdent, FGIdentOrdering* aOrder = NULL);
 
     // search for the airport closest to the specified position
     // (currently a linear inefficient search so it's probably not
index 24b04055e4910f76919a2b71ac34231f6ad65baf..b789343713650ad9666bbd70e37156ca0272fd41 100644 (file)
@@ -940,21 +940,21 @@ void KLN89FplPage::Knob2Left1() {
                                _bEntWp = true;
                                _fp0SelWpId.clear();    // Waypoints don't become the DTO default whilst being entered.
                                
-                               bool multi;
-                               const GPSWaypoint* wp = _kln89->FindFirstById(_entWpStr.substr(0, _wLinePos+1), multi, false);
+        GPSWaypoint* wp = _kln89->FindFirstById(_entWpStr.substr(0, _wLinePos+1));
                                if(NULL == wp) {
                                        // no-op
                                } else {
-                                       if(_entWp == NULL) {
-                                               _entWp = new GPSWaypoint;
-                                               if(_fplPos + (_uLinePos - 4) >= _kln89->_flightPlans[_subPage]->waypoints.size()) {
+                                       if(_entWp) {
+            *_entWp = *wp; // copy
+            delete wp;
+          } else {
+            _entWp = wp;
+            if(_fplPos + (_uLinePos - 4) >= _kln89->_flightPlans[_subPage]->waypoints.size()) {
                                                        _kln89->_flightPlans[_subPage]->waypoints.push_back(_entWp);
                                                } else {
                                                        _kln89->_flightPlans[_subPage]->waypoints.insert(_kln89->_flightPlans[_subPage]->waypoints.begin()+(_fplPos + (_uLinePos - 4)), _entWp);
                                                }
-                                       }
-                                       // copy
-                                       *_entWp = *wp;
+          }
                                }
                        }
                }
@@ -1013,21 +1013,21 @@ void KLN89FplPage::Knob2Right1() {
                                _bEntWp = true;
                                _fp0SelWpId.clear();    // Waypoints don't become the DTO default whilst being entered.
                                
-                               bool multi;
-                               const GPSWaypoint* wp = _kln89->FindFirstById(_entWpStr.substr(0, _wLinePos+1), multi, false);
+        GPSWaypoint* wp = _kln89->FindFirstById(_entWpStr.substr(0, _wLinePos+1));
                                if(NULL == wp) {
                                        // no-op
                                } else {
-                                       if(_entWp == NULL) {
-                                               _entWp = new GPSWaypoint;
-                                               if(_fplPos + (_uLinePos - 4) >= _kln89->_flightPlans[_subPage]->waypoints.size()) {
+                                       if(_entWp) {
+            *_entWp = *wp; // copy
+            delete wp;
+          } else {
+            _entWp = wp;
+            if(_fplPos + (_uLinePos - 4) >= _kln89->_flightPlans[_subPage]->waypoints.size()) {
                                                        _kln89->_flightPlans[_subPage]->waypoints.push_back(_entWp);
                                                } else {
                                                        _kln89->_flightPlans[_subPage]->waypoints.insert(_kln89->_flightPlans[_subPage]->waypoints.begin()+(_fplPos + (_uLinePos - 4)), _entWp);
                                                }
-                                       }
-                                       // copy
-                                       *_entWp = *wp;
+          }
                                }
                        }
                }
index 9c4ada7126715a45015ca6753395d2b00f0815a8..bff360b9441fe2c3e45d489feb63683e0c7c713b 100644 (file)
@@ -119,6 +119,15 @@ GPSWaypoint::GPSWaypoint() {
     appType = GPS_APP_NONE;
 }
 
+GPSWaypoint::GPSWaypoint(const std::string& aIdent, float aLat, float aLon, GPSWpType aType) :
+  id(aIdent),
+  lat(aLat),
+  lon(aLon),
+  type(aType),
+  appType(GPS_APP_NONE)
+{
+}
+
 GPSWaypoint::~GPSWaypoint() {}
 
 string GPSWaypoint::GetAprId() {
@@ -129,6 +138,33 @@ string GPSWaypoint::GetAprId() {
        else return(id);
 }
 
+GPSWaypoint* GPSWaypoint::createFromFix(const FGFix* aFix)
+{
+  assert(aFix);
+  return new GPSWaypoint(aFix->get_ident(), 
+    aFix->get_lat() * SG_DEGREES_TO_RADIANS,
+    aFix->get_lon() * SG_DEGREES_TO_RADIANS,
+    GPS_WP_INT);
+}
+
+GPSWaypoint* GPSWaypoint::createFromNav(const FGNavRecord* aNav)
+{
+  assert(aNav);
+  return new GPSWaypoint(aNav->get_ident(), 
+    aNav->get_lat() * SG_DEGREES_TO_RADIANS,
+    aNav->get_lon() * SG_DEGREES_TO_RADIANS,
+    (aNav->get_fg_type() == FG_NAV_VOR ? GPS_WP_VOR : GPS_WP_NDB));
+}
+
+GPSWaypoint* GPSWaypoint::createFromAirport(const FGAirport* aApt)
+{
+  assert(aApt);
+  return new GPSWaypoint(aApt->getId(), 
+    aApt->getLatitude() * SG_DEGREES_TO_RADIANS,
+    aApt->getLongitude() * SG_DEGREES_TO_RADIANS,
+    GPS_WP_APT);
+}
+
 ostream& operator << (ostream& os, GPSAppWpType type) {
        switch(type) {
                case(GPS_IAF):       return(os << "IAF");
@@ -301,12 +337,7 @@ DCLGPS::DCLGPS(RenderArea2D* instrument) {
 
 DCLGPS::~DCLGPS() {
        delete _time;
-       for(gps_waypoint_map_iterator itr = _waypoints.begin(); itr != _waypoints.end(); ++itr) {
-               for(unsigned int i = 0; i < (*itr).second.size(); ++i) {
-                       delete(((*itr).second)[i]);
-               }
-       }
-       delete _approachFP;             // Don't need to delete the waypoints inside since they point to
+  delete _approachFP;          // Don't need to delete the waypoints inside since they point to
                                                        // the waypoints in the approach database.
        // TODO - may need to delete the approach database!!
 }
@@ -329,332 +360,9 @@ void DCLGPS::init() {
        globals->get_commands()->addCommand("kln89_knob1right1", do_kln89_knob1right1);
        globals->get_commands()->addCommand("kln89_knob2left1", do_kln89_knob2left1);
        globals->get_commands()->addCommand("kln89_knob2right1", do_kln89_knob2right1);
-       
-       // Build the GPS-specific databases.
-       // TODO - consider splitting into real life GPS database regions - eg Americas, Europe etc.
-       // Note that this needs to run after FG's airport and nav databases are up and running
-       _waypoints.clear();
-       const airport_list* apts = globals->get_airports()->getAirportList();
-       for(unsigned int i = 0; i < apts->size(); ++i) {
-               FGAirport* a = (*apts)[i];
-               GPSWaypoint* w = new GPSWaypoint;
-               w->id = a->getId();
-               w->lat = a->getLatitude() * SG_DEGREES_TO_RADIANS;
-               w->lon = a->getLongitude() * SG_DEGREES_TO_RADIANS;
-               w->type = GPS_WP_APT;
-               gps_waypoint_map_iterator wtr = _waypoints.find(a->getId());
-               if(wtr == _waypoints.end()) {
-                       gps_waypoint_array arr;
-                       arr.push_back(w);
-                       _waypoints[w->id] = arr;
-               } else {
-                       wtr->second.push_back(w);
-               }
-       }
-       nav_map_type navs = globals->get_navlist()->get_navaids();
-       for(nav_map_iterator itr = navs.begin(); itr != navs.end(); ++itr) {
-               nav_list_type nlst = itr->second;
-               for(unsigned int i = 0; i < nlst.size(); ++i) {
-                       FGNavRecord* n = nlst[i];
-                       if(n->get_fg_type() == FG_NAV_VOR || n->get_fg_type() == FG_NAV_NDB) {  // We don't bother with ILS etc.
-                               GPSWaypoint* w = new GPSWaypoint;
-                               w->id = n->get_ident();
-                               w->lat = n->get_lat() * SG_DEGREES_TO_RADIANS;
-                               w->lon = n->get_lon() * SG_DEGREES_TO_RADIANS;
-                               w->type = (n->get_fg_type() == FG_NAV_VOR ? GPS_WP_VOR : GPS_WP_NDB);
-                               gps_waypoint_map_iterator wtr = _waypoints.find(n->get_ident());
-                               if(wtr == _waypoints.end()) {
-                                       gps_waypoint_array arr;
-                                       arr.push_back(w);
-                                       _waypoints[w->id] = arr;
-                               } else {
-                                       wtr->second.push_back(w);
-                               }
-                       }
-               }
-       }
-       const fix_map_type* fixes = globals->get_fixlist()->getFixList();
-       for(fix_map_const_iterator itr = fixes->begin(); itr != fixes->end(); ++itr) {
-               FGFix f = itr->second;
-               GPSWaypoint* w = new GPSWaypoint;
-               w->id = f.get_ident();
-               w->lat = f.get_lat() * SG_DEGREES_TO_RADIANS;
-               w->lon = f.get_lon() * SG_DEGREES_TO_RADIANS;
-               w->type = GPS_WP_INT;
-               gps_waypoint_map_iterator wtr = _waypoints.find(f.get_ident());
-               if(wtr == _waypoints.end()) {
-                       gps_waypoint_array arr;
-                       arr.push_back(w);
-                       _waypoints[w->id] = arr;
-               } else {
-                       wtr->second.push_back(w);
-               }
-       }
-       // TODO - add USR waypoints as well.
-       
+               
        // Not sure if this should be here, but OK for now.
        CreateDefaultFlightPlans();
-       
-       // Hack - hardwire some instrument approaches for testing.
-       // TODO - read these from file - either all at startup or as needed.
-       FGNPIAP* iap = new FGNPIAP;
-       iap->_id = "KHWD";
-       iap->_name = "VOR/DME OR GPS-B";
-       iap->_abbrev = "VOR/D";
-       iap->_rwyStr = "B";
-       iap->_IAF.clear();
-       iap->_IAP.clear();
-       iap->_MAP.clear();
-       // -------
-       GPSWaypoint* wp = new GPSWaypoint;
-       wp->id = "SUNOL";
-       bool multi;
-       // Nasty using the find any function here, but it saves converting data from FGFix etc. 
-       const GPSWaypoint* fp = FindFirstById(wp->id, multi, true); 
-       *wp = *fp;
-       wp->appType = GPS_IAF;
-       iap->_IAF.push_back(wp);
-       // -------
-       wp = new GPSWaypoint;
-       wp->id = "MABRY";
-       fp = FindFirstById(wp->id, multi, true); 
-       *wp = *fp;
-       wp->appType = GPS_IAF;
-       iap->_IAF.push_back(wp);
-       // -------
-       wp = new GPSWaypoint;
-       wp->id = "IMPLY";
-       fp = FindFirstById(wp->id, multi, true); 
-       *wp = *fp;
-       wp->appType = GPS_IAP;
-       iap->_IAP.push_back(wp);
-       // -------
-       wp = new GPSWaypoint;
-       wp->id = "DECOT";
-       fp = FindFirstById(wp->id, multi, true); 
-       *wp = *fp;
-       wp->appType = GPS_FAF;
-       iap->_IAP.push_back(wp);
-       // -------
-       wp = new GPSWaypoint;
-       wp->id = "MAPVV";
-       fp = FindFirstById(wp->id, multi, true); 
-       *wp = *fp;
-       wp->appType = GPS_MAP;
-       iap->_IAP.push_back(wp);
-       // -------
-       wp = new GPSWaypoint;
-       wp->id = "OAK";
-       fp = FindFirstById(wp->id, multi, true); 
-       *wp = *fp;
-       wp->appType = GPS_MAHP;
-       iap->_MAP.push_back(wp);
-       // -------
-       _np_iap[iap->_id].push_back(iap);
-       // -----------------------
-       // -----------------------
-       iap = new FGNPIAP;
-       iap->_id = "KHWD";
-       iap->_name = "VOR OR GPS-A";
-       iap->_abbrev = "VOR-";
-       iap->_rwyStr = "A";
-       iap->_IAF.clear();
-       iap->_IAP.clear();
-       iap->_MAP.clear();
-       // -------
-       wp = new GPSWaypoint;
-       wp->id = "SUNOL";
-       // Nasty using the find any function here, but it saves converting data from FGFix etc. 
-       fp = FindFirstById(wp->id, multi, true); 
-       *wp = *fp;
-       wp->appType = GPS_IAF;
-       iap->_IAF.push_back(wp);
-       // -------
-       wp = new GPSWaypoint;
-       wp->id = "MABRY";
-       fp = FindFirstById(wp->id, multi, true); 
-       *wp = *fp;
-       wp->appType = GPS_IAF;
-       iap->_IAF.push_back(wp);
-       // -------
-       wp = new GPSWaypoint;
-       wp->id = "IMPLY";
-       fp = FindFirstById(wp->id, multi, true); 
-       *wp = *fp;
-       wp->appType = GPS_IAP;
-       iap->_IAP.push_back(wp);
-       // -------
-       wp = new GPSWaypoint;
-       wp->id = "DECOT";
-       fp = FindFirstById(wp->id, multi, true); 
-       *wp = *fp;
-       wp->appType = GPS_FAF;
-       iap->_IAP.push_back(wp);
-       // -------
-       wp = new GPSWaypoint;
-       wp->id = "MAPVV";
-       fp = FindFirstById(wp->id, multi, true); 
-       *wp = *fp;
-       wp->appType = GPS_MAP;
-       iap->_IAP.push_back(wp);
-       // -------
-       wp = new GPSWaypoint;
-       wp->id = "OAK";
-       fp = FindFirstById(wp->id, multi, true); 
-       *wp = *fp;
-       wp->appType = GPS_MAHP;
-       iap->_MAP.push_back(wp);
-       // -------
-       _np_iap[iap->_id].push_back(iap);
-       // ------------------
-       // ------------------
-       /*
-       // Ugh - don't load this one - the waypoints required aren't in fix.dat.gz - result: program crash!
-       // TODO - make the IAP loader robust to absent waypoints.
-       iap = new FGNPIAP;
-       iap->_id = "KHWD";
-       iap->_name = "GPS RWY 28L";
-       iap->_abbrev = "GPS";
-       iap->_rwyStr = "28L";
-       iap->_IAF.clear();
-       iap->_IAP.clear();
-       iap->_MAP.clear();
-       // -------
-       wp = new GPSWaypoint;
-       wp->id = "SUNOL";
-       // Nasty using the find any function here, but it saves converting data from FGFix etc. 
-       fp = FindFirstById(wp->id, multi, true); 
-       *wp = *fp;
-       wp->appType = GPS_IAF;
-       iap->_IAF.push_back(wp);
-       // -------
-       wp = new GPSWaypoint;
-       wp->id = "SJC";
-       fp = FindFirstById(wp->id, multi, true); 
-       *wp = *fp;
-       wp->appType = GPS_IAF;
-       iap->_IAF.push_back(wp);
-       // -------
-       wp = new GPSWaypoint;
-       wp->id = "JOCPI";
-       fp = FindFirstById(wp->id, multi, true); 
-       *wp = *fp;
-       wp->appType = GPS_IAP;
-       iap->_IAP.push_back(wp);
-       // -------
-       wp = new GPSWaypoint;
-       wp->id = "SUDGE";
-       fp = FindFirstById(wp->id, multi, true); 
-       *wp = *fp;
-       wp->appType = GPS_FAF;
-       iap->_IAP.push_back(wp);
-       // -------
-       wp = new GPSWaypoint;
-       wp->id = "RW28L";
-       wp->appType = GPS_MAP;
-       if(wp->id.substr(0, 2) == "RW" && wp->appType == GPS_MAP) {
-               // Assume that this is a missed-approach point based on the runway number
-               // Get the runway threshold location etc
-       } else {
-               fp = FindFirstById(wp->id, multi, true);
-               if(fp == NULL) {
-                       cout << "Failed to find waypoint " << wp->id << " in database...\n";
-               } else {
-                       *wp = *fp;
-               }
-       }
-       iap->_IAP.push_back(wp);
-       // -------
-       wp = new GPSWaypoint;
-       wp->id = "OAK";
-       fp = FindFirstById(wp->id, multi, true); 
-       *wp = *fp;
-       wp->appType = GPS_MAHP;
-       iap->_MAP.push_back(wp);
-       // -------
-       _np_iap[iap->_id].push_back(iap);
-       */
-       iap = new FGNPIAP;
-       iap->_id = "C83";
-       iap->_name = "GPS RWY 30";
-       iap->_abbrev = "GPS";
-       iap->_rwyStr = "30";
-       iap->_IAF.clear();
-       iap->_IAP.clear();
-       iap->_MAP.clear();
-       // -------
-       wp = new GPSWaypoint;
-       wp->id = "MAXNI";
-       // Nasty using the find any function here, but it saves converting data from FGFix etc. 
-       fp = FindFirstById(wp->id, multi, true);
-       if(fp) {
-               *wp = *fp;
-               wp->appType = GPS_IAF;
-               iap->_IAF.push_back(wp);
-       }
-       // -------
-       wp = new GPSWaypoint;
-       wp->id = "PATYY";
-       fp = FindFirstById(wp->id, multi, true);
-       if(fp) {
-               *wp = *fp;
-               wp->appType = GPS_IAF;
-               iap->_IAF.push_back(wp);
-       }
-       // -------
-       wp = new GPSWaypoint;
-       wp->id = "TRACY";
-       fp = FindFirstById(wp->id, multi, true);
-       if(fp) {
-               *wp = *fp;
-               wp->appType = GPS_IAF;
-               iap->_IAF.push_back(wp);
-       }
-       // -------
-       wp = new GPSWaypoint;
-       wp->id = "TRACY";
-       fp = FindFirstById(wp->id, multi, true);
-       if(fp) {
-               *wp = *fp;
-               wp->appType = GPS_IAP;
-               iap->_IAP.push_back(wp);
-       }
-       // -------
-       wp = new GPSWaypoint;
-       wp->id = "BABPI";
-       fp = FindFirstById(wp->id, multi, true);
-       if(fp) {
-               *wp = *fp;
-               wp->appType = GPS_FAF;
-               iap->_IAP.push_back(wp);
-       }
-       // -------
-       wp = new GPSWaypoint;
-       wp->id = "AMOSY";
-       wp->appType = GPS_MAP;
-       if(wp->id.substr(0, 2) == "RW" && wp->appType == GPS_MAP) {
-               // Assume that this is a missed-approach point based on the runway number
-               // TODO: Get the runway threshold location etc
-               cout << "TODO - implement missed-approach point based on rwy no.\n";
-       } else {
-               fp = FindFirstById(wp->id, multi, true);
-               if(fp == NULL) {
-                       cout << "Failed to find waypoint " << wp->id << " in database...\n";
-               } else {
-                       *wp = *fp;
-                       wp->appType = GPS_MAP;
-               }
-       }
-       iap->_IAP.push_back(wp);
-       // -------
-       wp = new GPSWaypoint;
-       wp->id = "HAIRE";
-       fp = FindFirstById(wp->id, multi, true); 
-       *wp = *fp;
-       wp->appType = GPS_MAHP;
-       iap->_MAP.push_back(wp);
-       // -------
-       _np_iap[iap->_id].push_back(iap);
 }
 
 void DCLGPS::bind() {
@@ -962,8 +670,7 @@ double DCLGPS::GetCDIDeflection() const {
 
 void DCLGPS::DtoInitiate(const string& s) {
        //cout << "DtoInitiate, s = " << s << '\n';
-       bool multi;
-       const GPSWaypoint* wp = FindFirstById(s, multi, true);
+       const GPSWaypoint* wp = FindFirstByExactId(s);
        if(wp) {
                //cout << "Waypoint found, starting dto operation!\n";
                _dto = true;
@@ -972,6 +679,7 @@ void DCLGPS::DtoInitiate(const string& s) {
                _fromWaypoint.lon = _gpsLon;
                _fromWaypoint.type = GPS_WP_VIRT;
                _fromWaypoint.id = "DTOWP";
+    delete wp;
        } else {
                //cout << "Waypoint not found, ignoring dto request\n";
                // Should bring up the user waypoint page, but we're not implementing that yet.
@@ -1105,10 +813,10 @@ double DCLGPS::GetTimeToWaypoint(const string& id) {
        } else if(id == _activeWaypoint.id) {
                return(_eta);
        } else {
-               bool multi;
-               const GPSWaypoint* wp = FindFirstById(id, multi, true);
+               const GPSWaypoint* wp = FindFirstByExactId(id);
                if(wp == NULL) return(-1.0);
                double distm = GetGreatCircleDistance(_gpsLat, _gpsLon, wp->lat, wp->lon);
+    delete wp;
                return(distm / _groundSpeed_ms);
        }
        return(-1.0);   // Hopefully we never get here!
@@ -1312,79 +1020,116 @@ void DCLGPS::CreateFlightPlan(GPSFlightPlan* fp, vector<string> ids, vector<GPSW
 
 /***************************************/
 
-const GPSWaypoint* DCLGPS::ActualFindFirstById(const string& id, bool exact) {
-    gps_waypoint_map_const_iterator itr;
-    if(exact) {
-        itr = _waypoints.find(id);
-    } else {
-        itr = _waypoints.lower_bound(id);
-    }
-    if(itr == _waypoints.end()) {
-        return(NULL);
-    } else {
-               // TODO - don't just return the first one - either return all or the nearest one.
-        return((itr->second)[0]);
+/**
+ * STL functor for use with algorithms. This comapres strings according to
+ * the KLN-89's notion of ordering, with digits after letters.
+ * Also implements FGIdentOrdering so it can be passed into the various list
+ * find helpers.
+ */
+class stringOrderKLN89 : public FGIdentOrdering
+{
+public:
+  bool operator()(const gps_waypoint_map::value_type& aA, const std::string& aB) const
+  {
+    return compare(aA.first, aB);
+  }
+  
+  bool operator()(const std::string& aS1, const std::string& aS2) const
+  {
+    return compare(aS1, aS2);
+  }
+  
+  virtual bool compare(const std::string& aS1, const std::string& aS2) const
+  {
+    if (aS1.empty()) return true;
+    if (aS2.empty()) return false;
+    
+    char* a = (char*) aS1.c_str();
+    char* b = (char*) aS2.c_str();
+    
+    for ( ; *a && *b; ++a, ++b) {
+      if (*a == *b) continue;
+      
+      bool aDigit = isdigit(*a);
+      bool bDigit = isdigit(*b);
+      
+      if (aDigit == bDigit) {
+        return (*a < *b); // we already know they're not equal
+      }
+      
+      // digit-ness differs
+      if (aDigit) return false; // s1 = KS9 goes *after* s2 = KSA
+      assert(bDigit);
+      return true; // s1 = KSF, s2 = KS5, s1 is indeed < s2
     }
-}
-
-const GPSWaypoint* DCLGPS::FindFirstById(const string& id, bool &multi, bool exact) {
-       multi = false;
-       if(exact) return(ActualFindFirstById(id, exact));
-       
-       // OK, that was the easy case, now the fuzzy case
-       const GPSWaypoint* w1 = ActualFindFirstById(id);
-       if(w1 == NULL) return(w1);
-       
-       // The non-trivial code from here to the end of the function is all to deal with the fact that
-       // the KLN89 alphabetical order (numbers AFTER letters) differs from ASCII order (numbers BEFORE letters).
-       string id2 = id;
-       //string id3 = id+'0';
-       string id4 = id+'A';
-       // Increment the last char to provide the boundary.  Note that 'Z' -> '[' but we also need to check '0' for all since GPS has numbers after letters
-       //bool alfa = isalpha(id2[id2.size() - 1]);
-       id2[id2.size() - 1] = id2[id2.size() - 1] + 1;
-       const GPSWaypoint* w2 = ActualFindFirstById(id2);
-       //FGAirport* a3 = globals->get_airports()->findFirstById(id3);
-       const GPSWaypoint* w4 = ActualFindFirstById(id4);
-       //cout << "Strings sent were " << id << ", " << id2 << " and " << id4 << '\n';
-       //cout << "Airports returned were (a1, a2, a4): " << a1->getId() << ", " << a2->getId() << ", " << a4->getId() << '\n';
-       //cout << "Pointers were " << a1 << ", " << a2 << ", " << a4 << '\n';
-       
-       // TODO - the below handles the imediately following char OK
-       // eg id = "KD" returns "KDAA" instead of "KD5"
-       // but it doesn't handle numbers / letters further down the string,
-       // eg - id = "I" returns "IA01" instead of "IAN"
-       // We either need to provide a custom comparison operator, or recurse this function if !isalpha further down the string.
-       // (Currenly fixed with recursion).
-       
-       if(w4 != w2) { // A-Z match - preferred
-               //cout << "A-Z match!\n";
-               if(w4->id.size() - id.size() > 2) {
-                       // Check for numbers further on
-                       for(unsigned int i=id.size(); i<w4->id.size(); ++i) {
-                               if(!isalpha(w4->id[i])) {
-                                       //cout << "SUBSTR is " << (a4->getId()).substr(0, i) << '\n';
-                                       return(FindFirstById(w4->id.substr(0, i), multi, exact));
-                               }
-                       }
-               }
-               return(w4);
-       } else if(w1 != w2) {  // 0-9 match
-               //cout << "0-9 match!\n";
-               if(w1->id.size() - id.size() > 2) {
-                       // Check for numbers further on
-                       for(unsigned int i=id.size(); i<w1->id.size(); ++i) {
-                               if(!isalpha(w1->id[i])) {
-                                       //cout << "SUBSTR2 is " << (a4->getId()).substr(0, i) << '\n';
-                                       return(FindFirstById(w1->id.substr(0, i), multi, exact));
-                               }
-                       }
-               }
-               return(w1);
-       } else {  // No match
-               return(NULL);
-       }
-       return NULL;
+    
+    if (*b) return true; // *a == 0, s2 is longer
+    return false; // s1 is longer, or strings are equal
+  }
+};
+
+GPSWaypoint* DCLGPS::FindFirstById(const string& id) const
+{
+  stringOrderKLN89 ordering;
+  nav_list_type vors = globals->get_navlist()->findFirstByIdent(id, FG_NAV_VOR, false);
+  nav_list_type ndbs = globals->get_navlist()->findFirstByIdent(id, FG_NAV_NDB, false);
+  const FGFix* fix = globals->get_fixlist()->findFirstByIdent(id, &ordering);
+  const FGAirport* apt = globals->get_airports()->findFirstById(id, &ordering);
+  // search local gps waypoints (USR)
+
+// pick the best - ugly logic, sorry. This is a temporary fix to getting rid
+// of the huge local waypoint table, it'll die when there's a way to query
+// this stuff centrally.
+// what we're doing is using map inserts to order the result, then using
+// the first entry (begin()) as the lowest, hence best, match
+  map<string, GPSWpType, stringOrderKLN89> sorter;
+  if (fix) sorter[fix->get_ident()] = GPS_WP_INT;
+  if (apt) sorter[apt->getId()] = GPS_WP_APT;
+  if (!vors.empty()) sorter[vors.front()->get_ident()] = GPS_WP_VOR;
+  if (!ndbs.empty()) sorter[ndbs.front()->get_ident()] = GPS_WP_NDB;
+
+  if (sorter.empty()) return NULL; // no results at all
+  GPSWpType ty = sorter.begin()->second;
+  
+  switch (ty) {
+  case GPS_WP_INT: 
+    return GPSWaypoint::createFromFix(fix);
+  
+  case GPS_WP_APT:
+    return GPSWaypoint::createFromAirport(apt);
+  
+  case GPS_WP_VOR:
+    return GPSWaypoint::createFromNav(vors.front());
+    
+  case GPS_WP_NDB:
+    return GPSWaypoint::createFromNav(ndbs.front());
+  default:
+    return NULL; // can't happen
+  }
+}
+
+GPSWaypoint* DCLGPS::FindFirstByExactId(const string& id) const
+{
+  if (const FGAirport* apt = globals->get_airports()->search(id)) {
+    return GPSWaypoint::createFromAirport(apt);
+  }
+  
+  if (const FGFix* fix = globals->get_fixlist()->search(id)) {
+    return GPSWaypoint::createFromFix(fix);
+  }
+  
+  nav_list_type vors = globals->get_navlist()->findFirstByIdent(id, FG_NAV_VOR, true);
+  if (!vors.empty()) {
+    return GPSWaypoint::createFromNav(vors.front());
+  }
+  
+  nav_list_type ndbs = globals->get_navlist()->findFirstByIdent(id, FG_NAV_NDB, true);
+  if (!ndbs.empty()) {
+    return GPSWaypoint::createFromNav(ndbs.front());
+  }
+  
+  return NULL;
 }
 
 // Host specific lookup functions
@@ -1407,55 +1152,6 @@ FGNavRecord* DCLGPS::FindFirstVorById(const string& id, bool &multi, bool exact)
        }
        return(NULL);   // Shouldn't get here!
 }
-#if 0
-Overlays::NAV* DCLGPS::FindFirstVorById(const string& id, bool &multi, bool exact) {
-       // NOTE - at the moment multi is never set.
-       multi = false;
-       if(exact) return(_overlays->FindFirstVorById(id, exact));
-       
-       // OK, that was the easy case, now the fuzzy case
-       Overlays::NAV* n1 = _overlays->FindFirstVorById(id);
-       if(n1 == NULL) return(n1);
-       
-       string id2 = id;
-       string id3 = id+'0';
-       string id4 = id+'A';
-       // Increment the last char to provide the boundary.  Note that 'Z' -> '[' but we also need to check '0' for all since GPS has numbers after letters
-       bool alfa = isalpha(id2[id2.size() - 1]);
-       id2[id2.size() - 1] = id2[id2.size() - 1] + 1;
-       Overlays::NAV* n2 = _overlays->FindFirstVorById(id2);
-       //Overlays::NAV* n3 = _overlays->FindFirstVorById(id3);
-       //Overlays::NAV* n4 = _overlays->FindFirstVorById(id4);
-       //cout << "Strings sent were " << id << ", " << id2 << ", " << id3 << ", " << id4 << '\n';
-       
-       
-       if(alfa) {
-               if(n1 != n2) { // match
-                       return(n1);
-               } else {
-                       return(NULL);
-               }
-       }
-       
-       /*
-       if(n1 != n2) {
-               // Something matches - the problem is the number/letter preference order is reversed between the GPS and the STL
-               if(n4 != n2) {
-                       // There's a letter match - return that
-                       return(n4);
-               } else {
-                       // By definition we must have a number match
-                       if(n3 == n2) cout << "HELP - LOGIC FLAW in find VOR!\n";
-                       return(n3);
-               }
-       } else {
-               // No match
-               return(NULL);
-       }
-       */
-       return NULL;
-}
-#endif //0
 
 // TODO - add the ASCII / alphabetical stuff from the Atlas version
 FGNavRecord* DCLGPS::FindFirstNDBById(const string& id, bool &multi, bool exact) {
@@ -1476,179 +1172,25 @@ FGNavRecord* DCLGPS::FindFirstNDBById(const string& id, bool &multi, bool exact)
        }
        return(NULL);   // Shouldn't get here!
 }
-#if 0
-Overlays::NAV* DCLGPS::FindFirstNDBById(const string& id, bool &multi, bool exact) {
-       // NOTE - at the moment multi is never set.
-       multi = false;
-       if(exact) return(_overlays->FindFirstNDBById(id, exact));
-       
-       // OK, that was the easy case, now the fuzzy case
-       Overlays::NAV* n1 = _overlays->FindFirstNDBById(id);
-       if(n1 == NULL) return(n1);
-       
-       string id2 = id;
-       string id3 = id+'0';
-       string id4 = id+'A';
-       // Increment the last char to provide the boundary.  Note that 'Z' -> '[' but we also need to check '0' for all since GPS has numbers after letters
-       bool alfa = isalpha(id2[id2.size() - 1]);
-       id2[id2.size() - 1] = id2[id2.size() - 1] + 1;
-       Overlays::NAV* n2 = _overlays->FindFirstNDBById(id2);
-       //Overlays::NAV* n3 = _overlays->FindFirstNDBById(id3);
-       //Overlays::NAV* n4 = _overlays->FindFirstNDBById(id4);
-       //cout << "Strings sent were " << id << ", " << id2 << ", " << id3 << ", " << id4 << '\n';
-       
-       
-       if(alfa) {
-               if(n1 != n2) { // match
-                       return(n1);
-               } else {
-                       return(NULL);
-               }
-       }
-       
-       /*
-       if(n1 != n2) {
-               // Something matches - the problem is the number/letter preference order is reversed between the GPS and the STL
-               if(n4 != n2) {
-                       // There's a letter match - return that
-                       return(n4);
-               } else {
-                       // By definition we must have a number match
-                       if(n3 == n2) cout << "HELP - LOGIC FLAW in find VOR!\n";
-                       return(n3);
-               }
-       } else {
-               // No match
-               return(NULL);
-       }
-       */
-       return NULL;
-}
-#endif //0
 
-// TODO - add the ASCII / alphabetical stuff from the Atlas version
 const FGFix* DCLGPS::FindFirstIntById(const string& id, bool &multi, bool exact) {
        // NOTE - at the moment multi is never set, and indeed can't be
        // since FG can only map one Fix per ID at the moment.
        multi = false;
-       if(exact) return(globals->get_fixlist()->findFirstByIdent(id, exact));
-       
-       const FGFix* f1 = globals->get_fixlist()->findFirstByIdent(id, exact);
-       if(f1 == NULL) return(f1);
+       if (exact) return globals->get_fixlist()->search(id);
        
-       // The non-trivial code from here to the end of the function is all to deal with the fact that
-       // the KLN89 alphabetical order (numbers AFTER letters) differs from ASCII order (numbers BEFORE letters).
-       // It is copied from the airport version which is definately needed, but at present I'm not actually 
-       // sure if any fixes in FG or real-life have numbers in them!
-       string id2 = id;
-       //string id3 = id+'0';
-       string id4 = id+'A';
-       // Increment the last char to provide the boundary.  Note that 'Z' -> '[' but we also need to check '0' for all since GPS has numbers after letters
-       //bool alfa = isalpha(id2[id2.size() - 1]);
-       id2[id2.size() - 1] = id2[id2.size() - 1] + 1;
-       const FGFix* f2 = globals->get_fixlist()->findFirstByIdent(id2);
-       //const FGFix* a3 = globals->get_fixlist()->findFirstByIdent(id3);
-       const FGFix* f4 = globals->get_fixlist()->findFirstByIdent(id4);
-       
-       // TODO - the below handles the imediately following char OK
-       // eg id = "KD" returns "KDAA" instead of "KD5"
-       // but it doesn't handle numbers / letters further down the string,
-       // eg - id = "I" returns "IA01" instead of "IAN"
-       // We either need to provide a custom comparison operator, or recurse this function if !isalpha further down the string.
-       // (Currenly fixed with recursion).
-       
-       if(f4 != f2) { // A-Z match - preferred
-               //cout << "A-Z match!\n";
-               if(f4->get_ident().size() - id.size() > 2) {
-                       // Check for numbers further on
-                       for(unsigned int i=id.size(); i<f4->get_ident().size(); ++i) {
-                               if(!isalpha(f4->get_ident()[i])) {
-                                       //cout << "SUBSTR is " << (a4->getId()).substr(0, i) << '\n';
-                                       return(FindFirstIntById(f4->get_ident().substr(0, i), multi, exact));
-                               }
-                       }
-               }
-               return(f4);
-       } else if(f1 != f2) {  // 0-9 match
-               //cout << "0-9 match!\n";
-               if(f1->get_ident().size() - id.size() > 2) {
-                       // Check for numbers further on
-                       for(unsigned int i=id.size(); i<f1->get_ident().size(); ++i) {
-                               if(!isalpha(f1->get_ident()[i])) {
-                                       //cout << "SUBSTR2 is " << (a4->getId()).substr(0, i) << '\n';
-                                       return(FindFirstIntById(f1->get_ident().substr(0, i), multi, exact));
-                               }
-                       }
-               }
-               return(f1);
-       } else {  // No match
-               return(NULL);
-       }
-               
-       return NULL;    // Don't think we can ever get here.
+  stringOrderKLN89 ordering;
+  return globals->get_fixlist()->findFirstByIdent(id, &ordering);
 }
 
 const FGAirport* DCLGPS::FindFirstAptById(const string& id, bool &multi, bool exact) {
        // NOTE - at the moment multi is never set.
        //cout << "FindFirstAptById, id = " << id << '\n';
        multi = false;
-       if(exact) return(globals->get_airports()->findFirstById(id, exact));
-       
-       // OK, that was the easy case, now the fuzzy case
-       const FGAirport* a1 = globals->get_airports()->findFirstById(id);
-       if(a1 == NULL) return(a1);
+       if(exact) return(globals->get_airports()->search(id));
        
-       // The non-trivial code from here to the end of the function is all to deal with the fact that
-       // the KLN89 alphabetical order (numbers AFTER letters) differs from ASCII order (numbers BEFORE letters).
-       string id2 = id;
-       //string id3 = id+'0';
-       string id4 = id+'A';
-       // Increment the last char to provide the boundary.  Note that 'Z' -> '[' but we also need to check '0' for all since GPS has numbers after letters
-       //bool alfa = isalpha(id2[id2.size() - 1]);
-       id2[id2.size() - 1] = id2[id2.size() - 1] + 1;
-       const FGAirport* a2 = globals->get_airports()->findFirstById(id2);
-       //FGAirport* a3 = globals->get_airports()->findFirstById(id3);
-       const FGAirport* a4 = globals->get_airports()->findFirstById(id4);
-       //cout << "Strings sent were " << id << ", " << id2 << " and " << id4 << '\n';
-       //cout << "Airports returned were (a1, a2, a4): " << a1->getId() << ", " << a2->getId() << ", " << a4->getId() << '\n';
-       //cout << "Pointers were " << a1 << ", " << a2 << ", " << a4 << '\n';
-       
-       // TODO - the below handles the imediately following char OK
-       // eg id = "KD" returns "KDAA" instead of "KD5"
-       // but it doesn't handle numbers / letters further down the string,
-       // eg - id = "I" returns "IA01" instead of "IAN"
-       // We either need to provide a custom comparison operator, or recurse this function if !isalpha further down the string.
-       // (Currenly fixed with recursion).
-       
-       if(a4 != a2) { // A-Z match - preferred
-               //cout << "A-Z match!\n";
-               if(a4->getId().size() - id.size() > 2) {
-                       // Check for numbers further on
-                       for(unsigned int i=id.size(); i<a4->getId().size(); ++i) {
-                               if(!isalpha(a4->getId()[i])) {
-                                       //cout << "SUBSTR is " << (a4->getId()).substr(0, i) << '\n';
-                                       return(FindFirstAptById(a4->getId().substr(0, i), multi, exact));
-                               }
-                       }
-               }
-               return(a4);
-       } else if(a1 != a2) {  // 0-9 match
-               //cout << "0-9 match!\n";
-               if(a1->getId().size() - id.size() > 2) {
-                       // Check for numbers further on
-                       for(unsigned int i=id.size(); i<a1->getId().size(); ++i) {
-                               if(!isalpha(a1->getId()[i])) {
-                                       //cout << "SUBSTR2 is " << (a4->getId()).substr(0, i) << '\n';
-                                       return(FindFirstAptById(a1->getId().substr(0, i), multi, exact));
-                               }
-                       }
-               }
-               return(a1);
-       } else {  // No match
-               return(NULL);
-       }
-               
-       return NULL;
+  stringOrderKLN89 ordering;
+  return globals->get_airports()->findFirstById(id, &ordering);
 }
 
 FGNavRecord* DCLGPS::FindClosestVor(double lat_rad, double lon_rad) {
index 5526918272d9de158473a11183c82d626dff5a87..3766e6932d831c35d651538b45420662327b3783 100644 (file)
@@ -91,6 +91,13 @@ ostream& operator << (ostream& os, GPSAppWpType type);
 
 struct GPSWaypoint {
     GPSWaypoint();
+  
+  GPSWaypoint(const std::string& aIdent, float lat, float lon, GPSWpType aType);
+  
+  static GPSWaypoint* createFromFix(const FGFix* aFix);
+  static GPSWaypoint* createFromNav(const FGNavRecord* aNav);
+  static GPSWaypoint* createFromAirport(const FGAirport* aApt);
+  
     ~GPSWaypoint();
        string GetAprId();      // Returns the id with i, f, m or h added if appropriate. (Initial approach fix, final approach fix, etc)
        string id;
@@ -407,14 +414,13 @@ protected:
        // 
        
        // Data and lookup functions
-       // All waypoints mapped by id.
-       gps_waypoint_map _waypoints;
-private:
-       // Worker function for the below.
-       const GPSWaypoint* ActualFindFirstById(const string& id, bool exact = false);
+
+
 protected:
        // Find first of any type of waypoint by id.  (TODO - Possibly we should return multiple waypoints here).
-       const GPSWaypoint* FindFirstById(const string& id, bool &multi, bool exact = false); 
+  GPSWaypoint* FindFirstById(const string& id) const;
+  GPSWaypoint* FindFirstByExactId(const string& id) const;
+   
        FGNavRecord* FindFirstVorById(const string& id, bool &multi, bool exact = false);
        FGNavRecord* FindFirstNDBById(const string& id, bool &multi, bool exact = false);
        const FGAirport* FindFirstAptById(const string& id, bool &multi, bool exact = false);
index 36bdf420d44ea7c8ae93ee1f31fc4b91458b514e..29b246f9b95c4eef7eac00ed06bca169017a3def 100644 (file)
@@ -30,6 +30,8 @@
 #include <simgear/math/sg_geodesy.hxx>
 
 #include "fixlist.hxx"
+#include "Airports/simple.hxx";
+
 using std::pair;
 
 
@@ -120,17 +122,45 @@ bool FGFixList::query_and_offset( const string& ident, double lon, double lat,
     return true;
 }
 
-const FGFix* FGFixList::findFirstByIdent( const string& ident, bool exact)
+const FGFix* FGFixList::search(const string& ident)
 {
-    fix_map_iterator itr;
-    if(exact) {
-        itr = fixlist.find(ident);
-    } else {
-        itr = fixlist.lower_bound(ident);
-    }
-    if(itr == fixlist.end()) {
-        return(NULL);
-    } else {
-        return(&(itr->second));
-    }
+  fix_map_iterator itr = fixlist.find(ident);
+  if (itr == fixlist.end()) {
+    return NULL;
+  }
+  
+  return &itr->second;
+}
+
+class orderingFunctor
+{
+public:
+  orderingFunctor(FGIdentOrdering* aOrder) :
+    mOrdering(aOrder)
+  { assert(aOrder); }
+  
+  bool operator()(const fix_map_type::value_type& aA, const std::string& aB) const
+  {
+    return mOrdering->compare(aA.first,aB);
+  }
+  
+private:
+  FGIdentOrdering* mOrdering;
+};
+
+const FGFix* FGFixList::findFirstByIdent( const string& ident, FGIdentOrdering* aOrder)
+{
+  fix_map_iterator itr;
+  if (aOrder) {
+    orderingFunctor func(aOrder);
+    itr = std::lower_bound(fixlist.begin(),fixlist.end(), ident, func);
+  } else {
+    itr = fixlist.lower_bound(ident);
+  }
+  
+  if (itr == fixlist.end()) {
+    return NULL;
+  }
+  
+  return &itr->second;
 }
index cf81e8ce2519b5325916aa3e37f8cbee50fc5e99..d0b32eb80468e122bc54b2c909593b429965312a 100644 (file)
@@ -43,6 +43,8 @@ typedef multimap < string, FGFix > fix_map_type;
 typedef fix_map_type::iterator fix_map_iterator;
 typedef fix_map_type::const_iterator fix_map_const_iterator;
 
+class FGIdentOrdering; // FIXME, currently declared in Airports/simple.hxx
+
 class FGFixList {
 
     fix_map_type fixlist;
@@ -58,11 +60,13 @@ public:
     // query the database for the specified fix
     bool query( const string& ident, FGFix *f );
 
+    const FGFix* search(const string& ident);
+
     // Find fix of requested type with closest exact or following ident
     // (by ACSII values) to that supplied (ie. a lower-bound lookup).
     // Supplying true for exact forces only exact matches to be returned (similar to above function)
     // Returns NULL if no match found.
-    const FGFix* findFirstByIdent( const string& ident, bool exact = false );
+    const FGFix* findFirstByIdent( const string& ident, FGIdentOrdering* aOrder = NULL);
 
     // query the database for the specified fix, lon and lat are
     // in degrees, elev is in meters