//
// simple.cxx -- a really simplistic class to manage airport ID,
-// lat, lon of the center of one of it's runways, and
-// elevation in feet.
+// lat, lon of the center of one of it's runways, and
+// elevation in feet.
//
// Written by Curtis Olson, started April 1998.
//
# include <config.h>
#endif
+#include <math.h>
+
#include <simgear/compiler.h>
#include <simgear/debug/logstream.hxx>
#include <simgear/misc/sgstream.hxx>
#include STL_STRING
-#include STL_FUNCTIONAL
-#include STL_ALGORITHM
+#include STL_IOSTREAM
#include "simple.hxx"
SG_USING_NAMESPACE(std);
-
-#ifndef _MSC_VER
-# define NDEBUG // she don't work without it.
-#endif
-#include <mk4.h>
-#include <mk4str.h>
-#ifndef _MSC_VER
-# undef NDEBUG
-#endif
-
-#ifdef SG_HAVE_STD_INCLUDES
-# include <istream>
-#elif defined( SG_HAVE_NATIVE_SGI_COMPILERS )
-# include <iostream.h>
-#elif defined( __BORLANDC__ )
-# include <iostream>
-#else
-# include <istream.h>
-#endif
-#if ! defined( SG_HAVE_NATIVE_SGI_COMPILERS )
SG_USING_STD(istream);
-#endif
inline istream&
operator >> ( istream& in, FGAirport& a )
{
- return in >> a.id >> a.latitude >> a.longitude >> a.elevation;
-}
-
-
-FGAirports::FGAirports( const string& file ) {
- // open the specified database readonly
- storage = new c4_Storage( file.c_str(), false );
-
- if ( !storage->Strategy().IsValid() ) {
- SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << file );
- exit(-1);
- }
-
- vAirport = new c4_View;
- *vAirport =
- storage->GetAs("airport[ID:S,Longitude:F,Latitude:F,Elevation:F]");
-}
-
-
-// search for the specified id
-bool
-FGAirports::search( const string& id, FGAirport* a ) const
-{
- c4_StringProp pID ("ID");
- c4_FloatProp pLon ("Longitude");
- c4_FloatProp pLat ("Latitude");
- c4_FloatProp pElev ("Elevation");
+ string junk;
+ in >> junk >> a.id >> a.latitude >> a.longitude >> a.elevation
+ >> a.code;
- int idx = vAirport->Find(pID[id.c_str()]);
- cout << "idx = " << idx << endl;
+ getline( in,a.name );
- if ( idx == -1 ) {
- return false;
+ // Remove the space before the name
+ if ( a.name.substr(0,1) == " " ) {
+ a.name = a.name.erase(0,1);
}
- c4_RowRef r = vAirport->GetAt(idx);
- a->id = (const char *) pID(r); /// NHV fix wrong case crash
- a->longitude = (double) pLon(r);
- a->latitude = (double) pLat(r);
- a->elevation = (double) pElev(r);
-
- return true;
-}
+ a.has_metar = false;
+#if 0
+ // As a quick seed for the has_metar value, only airports with
+ // four-letter codes can have metar stations
+ a.has_metar = (isalpha(a.id[0]) && isalpha(a.id[1]) && isalpha(a.id[2])
+ && isalpha(a.id[3]) && !a.id[4]);
+#endif
-FGAirport
-FGAirports::search( const string& id ) const
-{
- FGAirport a;
- search( id, &a );
- return a;
+ return in;
}
-// Destructor
-FGAirports::~FGAirports( void ) {
- delete storage;
-}
-
+FGAirportList::FGAirportList( const string &airport_file,
+ const string &metar_file ) {
+ SG_LOG( SG_GENERAL, SG_INFO, "Reading simple airport list: "
+ << airport_file );
-// Constructor
-FGAirportsUtil::FGAirportsUtil() {
-}
+ // open the specified file for reading
+ sg_gzifstream apt_in( airport_file );
+ if ( !apt_in.is_open() ) {
+ SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << airport_file );
+ exit(-1);
+ }
+ // skip header line
+ apt_in >> skipeol;
-// load the data
-int FGAirportsUtil::load( const string& file ) {
FGAirport a;
+ while ( apt_in ) {
+ apt_in >> a;
+ airports_by_id[a.id] = a;
+ airports_array.push_back( &airports_by_id[a.id] );
+ }
- airports.erase( airports.begin(), airports.end() );
- sg_gzifstream in( file );
- if ( !in.is_open() ) {
- SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << file );
- exit(-1);
- } else {
- SG_LOG( SG_GENERAL, SG_ALERT, "opened: " << file );
- }
+ SG_LOG( SG_GENERAL, SG_INFO, "Reading simple metar station list: "
+ << metar_file );
- // skip first line of file
- char tmp[2048];
- in.getline( tmp, 2048 );
-
- // read in each line of the file
-
-#ifdef __MWERKS__
-
- in >> ::skipws;
- char c = 0;
- while ( in.get(c) && c != '\0' ) {
- if ( c == 'A' ) {
- in >> a;
- SG_LOG( SG_GENERAL, SG_INFO, a.id );
- in >> skipeol;
- airports.insert(a);
- } else if ( c == 'R' ) {
- in >> skipeol;
- } else {
- in >> skipeol;
- }
- in >> ::skipws;
+ // open the specified file for reading
+ sg_gzifstream metar_in( metar_file );
+ if ( !metar_in.is_open() ) {
+ SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << metar_file );
}
-#else
-
- in >> ::skipws;
- string token;
- while ( ! in.eof() ) {
- in >> token;
- if ( token == "A" ) {
- in >> a;
- SG_LOG( SG_GENERAL, SG_INFO, "in <- " << a.id );
- in >> skipeol;
- airports.insert(a);
- } else if ( token == "R" ) {
- in >> skipeol;
- } else {
- in >> skipeol;
- }
- in >> ::skipws;
+ string ident;
+ while ( metar_in ) {
+ metar_in >> ident;
+ if ( ident == "#" || ident == "//" ) {
+ metar_in >> skipeol;
+ } else {
+ airport_map_iterator apt = airports_by_id.find( ident );
+ if ( apt == airports_by_id.end() ) {
+ SG_LOG( SG_GENERAL, SG_DEBUG, "no apt = " << ident );
+ } else {
+ SG_LOG( SG_GENERAL, SG_DEBUG, "metar = " << ident );
+ airports_by_id[ident].has_metar = true;
+ }
+ }
}
-
-#endif
-
- return 1;
}
-// save the data in gdbm format
-bool FGAirportsUtil::dump_mk4( const string& file ) {
-
- // open database for writing
- c4_Storage storage( file.c_str(), true );
-
- // need to do something about error handling here!
-
- // define the properties
- c4_StringProp pID ("ID");
- c4_FloatProp pLon ("Longitude");
- c4_FloatProp pLat ("Latitude");
- c4_FloatProp pElev ("Elevation");
-
- // Start with an empty view of the proper structure.
- c4_View vAirport =
- storage.GetAs("airport[ID:S,Longitude:F,Latitude:F,Elevation:F]");
-
- c4_Row row;
+// search for the specified id
+FGAirport FGAirportList::search( const string& id) {
+ return airports_by_id[id];
+}
- const_iterator current = airports.begin();
- const_iterator end = airports.end();
- while ( current != end ) {
- // add each airport record
- cout << "out -> " << current->id << endl;
- pID (row) = current->id.c_str();
- pLon (row) = current->longitude;
- pLat (row) = current->latitude;
- pElev (row) = current->elevation;
- vAirport.Add(row);
- ++current;
+// search for the airport nearest the specified position
+FGAirport FGAirportList::search( double lon_deg, double lat_deg,
+ bool with_metar ) {
+ int closest = 0;
+ double min_dist = 360.0;
+ unsigned int i;
+ for ( i = 0; i < airports_array.size(); ++i ) {
+ // crude manhatten distance based on lat/lon difference
+ double d = fabs(lon_deg - airports_array[i]->longitude)
+ + fabs(lat_deg - airports_array[i]->latitude);
+ if ( d < min_dist ) {
+ if ( !with_metar || (with_metar && airports_array[i]->has_metar) ) {
+ closest = i;
+ min_dist = d;
+ }
+ }
}
- // commit our changes
- storage.Commit();
-
- return true;
+ return *airports_array[closest];
}
-// search for the specified id
-bool
-FGAirportsUtil::search( const string& id, FGAirport* a ) const
-{
- const_iterator it = airports.find( FGAirport(id) );
- if ( it != airports.end() )
- {
- *a = *it;
- return true;
- }
- else
- {
- return false;
- }
+// Destructor
+FGAirportList::~FGAirportList( void ) {
}
-
-FGAirport
-FGAirportsUtil::search( const string& id ) const
+int
+FGAirportList::size () const
{
- FGAirport a;
- this->search( id, &a );
- return a;
+ return airports_array.size();
}
-
-// Destructor
-FGAirportsUtil::~FGAirportsUtil( void ) {
+const FGAirport *FGAirportList::getAirport( int index ) const
+{
+ return airports_array[index];
}
+/**
+ * Mark the specified airport record as not having metar
+ */
+void FGAirportList::no_metar( const string &id ) {
+ airports_by_id[id].has_metar = false;
+}