2004-12-22 23:57:07 +00:00
|
|
|
// apt_loader.cxx -- a front end loader of the apt.dat file. This loader
|
|
|
|
// populates the runway and basic classes.
|
|
|
|
//
|
|
|
|
// Written by Curtis Olson, started August 2000.
|
|
|
|
//
|
|
|
|
// Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt
|
|
|
|
//
|
|
|
|
// This program is free software; you can redistribute it and/or
|
|
|
|
// modify it under the terms of the GNU General Public License as
|
|
|
|
// published by the Free Software Foundation; either version 2 of the
|
|
|
|
// License, or (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful, but
|
|
|
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
// General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with this program; if not, write to the Free Software
|
2006-02-21 01:16:04 +00:00
|
|
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2004-12-22 23:57:07 +00:00
|
|
|
//
|
|
|
|
// $Id$
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include <config.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <simgear/compiler.h>
|
|
|
|
|
|
|
|
#include <stdlib.h> // atof(), atoi()
|
2005-05-30 08:47:00 +00:00
|
|
|
#include <string.h> // memchr()
|
2005-05-27 18:49:45 +00:00
|
|
|
#include <ctype.h> // isspace()
|
2004-12-22 23:57:07 +00:00
|
|
|
|
|
|
|
#include <simgear/constants.h>
|
|
|
|
#include <simgear/debug/logstream.hxx>
|
|
|
|
#include <simgear/misc/sgstream.hxx>
|
|
|
|
#include <simgear/misc/strutils.hxx>
|
|
|
|
|
2008-07-25 18:38:29 +00:00
|
|
|
#include <string>
|
2004-12-22 23:57:07 +00:00
|
|
|
|
|
|
|
#include "simple.hxx"
|
|
|
|
#include "runways.hxx"
|
|
|
|
|
|
|
|
#include "apt_loader.hxx"
|
|
|
|
|
2008-08-14 18:13:39 +00:00
|
|
|
FGAirport* addAirport(FGAirportList *airports, const string& apt_id, const string& apt_name,
|
2007-09-09 23:21:48 +00:00
|
|
|
int rwy_count, double rwy_lat_accum, double rwy_lon_accum, double last_rwy_heading,
|
2007-10-05 12:59:43 +00:00
|
|
|
double apt_elev, SGGeod& tower, bool got_tower, int type)
|
2007-09-09 23:21:48 +00:00
|
|
|
{
|
2007-10-05 12:59:43 +00:00
|
|
|
if (apt_id.empty())
|
2008-08-14 18:13:39 +00:00
|
|
|
return NULL;
|
2007-10-05 12:59:43 +00:00
|
|
|
|
|
|
|
if (!rwy_count) {
|
|
|
|
SG_LOG(SG_GENERAL, SG_ALERT, "ERROR: No runways for " << apt_id
|
|
|
|
<< ", skipping." );
|
2008-08-14 18:13:39 +00:00
|
|
|
return NULL;
|
2007-09-09 23:21:48 +00:00
|
|
|
}
|
2007-10-05 12:59:43 +00:00
|
|
|
|
|
|
|
double lat = rwy_lat_accum / (double)rwy_count;
|
|
|
|
double lon = rwy_lon_accum / (double)rwy_count;
|
|
|
|
|
|
|
|
if (!got_tower) {
|
|
|
|
// tower height hard coded for now...
|
|
|
|
const float tower_height = 50.0f;
|
|
|
|
// make a little off the heading for 1 runway airports...
|
|
|
|
float fudge_lon = fabs(sin(last_rwy_heading * SGD_DEGREES_TO_RADIANS)) * .003f;
|
|
|
|
float fudge_lat = .003f - fudge_lon;
|
|
|
|
tower = SGGeod::fromDegFt(lon + fudge_lon, lat + fudge_lat, apt_elev + tower_height);
|
|
|
|
}
|
|
|
|
|
2008-08-14 18:13:39 +00:00
|
|
|
return airports->add(apt_id, SGGeod::fromDegFt(lon, lat, apt_elev), tower, apt_name, false,
|
2007-10-05 12:59:43 +00:00
|
|
|
type == 1/*airport*/, type == 16/*seaport*/, type == 17/*heliport*/);
|
2007-09-09 23:21:48 +00:00
|
|
|
}
|
2004-12-22 23:57:07 +00:00
|
|
|
|
|
|
|
// Load the airport data base from the specified aptdb file. The
|
|
|
|
// metar file is used to mark the airports as having metar available
|
|
|
|
// or not.
|
2008-08-14 18:13:39 +00:00
|
|
|
bool fgAirportDBLoad( FGAirportList *airports,
|
2004-12-22 23:57:07 +00:00
|
|
|
const string &aptdb_file, const string &metar_file )
|
|
|
|
{
|
|
|
|
//
|
|
|
|
// Load the apt.dat file
|
|
|
|
//
|
|
|
|
|
|
|
|
sg_gzifstream in( aptdb_file );
|
|
|
|
if ( !in.is_open() ) {
|
|
|
|
SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << aptdb_file );
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
vector<string> token;
|
|
|
|
string last_apt_id = "";
|
|
|
|
double last_apt_elev = 0.0;
|
|
|
|
string last_apt_name = "";
|
|
|
|
string last_apt_info = "";
|
2007-10-14 10:05:41 +00:00
|
|
|
int last_apt_type = 0;
|
2007-09-09 23:21:48 +00:00
|
|
|
SGGeod last_tower;
|
|
|
|
bool got_tower = false;
|
2004-12-22 23:57:07 +00:00
|
|
|
string line;
|
2005-05-30 08:47:00 +00:00
|
|
|
char tmp[2049];
|
|
|
|
tmp[2048] = 0;
|
James Turner:
Convert FGRunway to be heap-based, and inherit FGPositioned. This is a large, ugly change, since FGRunway was essentially a plain struct, with no accessors or abstraction. This change adds various helpers and accessors to FGRunway, but doesn't change many places to use them - that will be a follow up series of patches. It's still a large patch, but outside of FGAirport and FGRunway, mostly mechanical search-and-replace.
An interesting part of this change is that reciprocal runways now exist as independent objects, rather than being created on the fly by the search methods. This simplifies some pieces of code that search for and iterate runways. For users who only want one 'end' of a runway, the new 'isReciprocal' predicate allows them to ignore the 'other' end. Current the only user of this is the 'ground-radar' ATC feature. If we had data on which runways are truly 'single-ended', it would now be trivial to use this in the airport loader to *not* create the reciprocal.
2008-09-11 08:38:09 +00:00
|
|
|
vector<FGRunwayPtr> runways;
|
2008-08-14 18:13:39 +00:00
|
|
|
|
2005-05-30 08:47:00 +00:00
|
|
|
unsigned int line_id = 0;
|
|
|
|
unsigned int line_num = 0;
|
2004-12-22 23:57:07 +00:00
|
|
|
double rwy_lon_accum = 0.0;
|
|
|
|
double rwy_lat_accum = 0.0;
|
|
|
|
int rwy_count = 0;
|
2007-09-09 23:21:48 +00:00
|
|
|
double last_rwy_heading = 0.0;
|
2004-12-22 23:57:07 +00:00
|
|
|
|
|
|
|
while ( ! in.eof() ) {
|
|
|
|
in.getline(tmp, 2048);
|
|
|
|
line = tmp;
|
2005-05-30 08:47:00 +00:00
|
|
|
line_num++;
|
2005-05-27 17:46:35 +00:00
|
|
|
|
2005-05-30 08:47:00 +00:00
|
|
|
SG_LOG( SG_GENERAL, SG_BULK, "#" << line_num << " '" << line << "'" );
|
2005-05-27 18:49:45 +00:00
|
|
|
if ( !line.size() || isspace(tmp[0]))
|
2005-05-27 17:46:35 +00:00
|
|
|
continue;
|
|
|
|
|
2005-05-30 08:47:00 +00:00
|
|
|
if (line.size() >= 3) {
|
2005-05-27 17:46:35 +00:00
|
|
|
char *p = (char *)memchr(tmp, ' ', 3);
|
|
|
|
if ( p )
|
|
|
|
*p = 0;
|
2004-12-22 23:57:07 +00:00
|
|
|
}
|
|
|
|
|
2005-05-30 08:47:00 +00:00
|
|
|
line_id = atoi(tmp);
|
|
|
|
if ( tmp[0] == 'I' ) {
|
2004-12-22 23:57:07 +00:00
|
|
|
// First line, indicates IBM (i.e. DOS line endings I
|
|
|
|
// believe.)
|
|
|
|
|
|
|
|
// move past this line and read and discard the next line
|
|
|
|
// which is the version and copyright information
|
|
|
|
in.getline(tmp, 2048);
|
2005-05-27 17:46:35 +00:00
|
|
|
// vector<string> vers_token = simgear::strutils::split( tmp );
|
2005-05-27 18:49:45 +00:00
|
|
|
if ( strlen(tmp) > 4 ) {
|
2005-05-27 17:46:35 +00:00
|
|
|
char *p = (char *)memchr(tmp, ' ', 4);
|
|
|
|
if ( p )
|
|
|
|
*p = 0;
|
|
|
|
}
|
2004-12-22 23:57:07 +00:00
|
|
|
SG_LOG( SG_GENERAL, SG_INFO, "Data file version = "
|
2005-05-27 17:46:35 +00:00
|
|
|
<< tmp );
|
2005-05-30 08:47:00 +00:00
|
|
|
} else if ( line_id == 1 /* Airport */ ||
|
|
|
|
line_id == 16 /* Seaplane base */ ||
|
|
|
|
line_id == 17 /* Heliport */ ) {
|
2004-12-22 23:57:07 +00:00
|
|
|
|
2005-05-27 17:46:35 +00:00
|
|
|
token.clear();
|
|
|
|
token = simgear::strutils::split(line);
|
2004-12-22 23:57:07 +00:00
|
|
|
string id = token[4];
|
|
|
|
double elev = atof( token[1].c_str() );
|
2005-01-15 14:25:58 +00:00
|
|
|
SG_LOG( SG_GENERAL, SG_BULK, "Next airport = " << id << " "
|
2004-12-22 23:57:07 +00:00
|
|
|
<< elev );
|
|
|
|
|
2008-08-14 18:13:39 +00:00
|
|
|
FGAirport* apt = addAirport(airports, last_apt_id, last_apt_name, rwy_count, rwy_lat_accum, rwy_lon_accum,
|
2007-10-14 10:05:41 +00:00
|
|
|
last_rwy_heading, last_apt_elev, last_tower, got_tower, last_apt_type);
|
2004-12-22 23:57:07 +00:00
|
|
|
|
2008-08-14 18:13:39 +00:00
|
|
|
for (unsigned int r=0; r< runways.size(); ++r) {
|
|
|
|
apt->addRunway(runways[r]);
|
|
|
|
}
|
|
|
|
|
|
|
|
runways.clear();
|
|
|
|
|
2004-12-22 23:57:07 +00:00
|
|
|
last_apt_id = id;
|
2007-09-09 23:21:48 +00:00
|
|
|
last_apt_elev = elev;
|
2004-12-22 23:57:07 +00:00
|
|
|
last_apt_name = "";
|
2007-09-09 23:21:48 +00:00
|
|
|
got_tower = false;
|
2004-12-22 23:57:07 +00:00
|
|
|
|
|
|
|
// build the name
|
|
|
|
for ( unsigned int i = 5; i < token.size() - 1; ++i ) {
|
|
|
|
last_apt_name += token[i];
|
|
|
|
last_apt_name += " ";
|
|
|
|
}
|
|
|
|
last_apt_name += token[token.size() - 1];
|
|
|
|
|
|
|
|
last_apt_info = line;
|
2007-10-14 10:05:41 +00:00
|
|
|
last_apt_type = atoi( token[0].c_str() );
|
2004-12-22 23:57:07 +00:00
|
|
|
|
|
|
|
// clear runway list for start of next airport
|
|
|
|
rwy_lon_accum = 0.0;
|
|
|
|
rwy_lat_accum = 0.0;
|
|
|
|
rwy_count = 0;
|
2005-05-30 08:47:00 +00:00
|
|
|
} else if ( line_id == 10 ) {
|
2005-05-27 17:46:35 +00:00
|
|
|
token.clear();
|
|
|
|
token = simgear::strutils::split(line);
|
|
|
|
|
2004-12-22 23:57:07 +00:00
|
|
|
// runway entry
|
|
|
|
double lat = atof( token[1].c_str() );
|
|
|
|
double lon = atof( token[2].c_str() );
|
|
|
|
rwy_lat_accum += lat;
|
|
|
|
rwy_lon_accum += lon;
|
|
|
|
rwy_count++;
|
|
|
|
|
|
|
|
string rwy_no = token[3];
|
|
|
|
|
|
|
|
double heading = atof( token[4].c_str() );
|
|
|
|
double length = atoi( token[5].c_str() );
|
|
|
|
double width = atoi( token[8].c_str() );
|
2007-09-09 23:21:48 +00:00
|
|
|
|
|
|
|
last_rwy_heading = heading;
|
2004-12-22 23:57:07 +00:00
|
|
|
|
|
|
|
string rwy_displ_threshold = token[6];
|
|
|
|
vector<string> displ
|
|
|
|
= simgear::strutils::split( rwy_displ_threshold, "." );
|
|
|
|
double displ_thresh1 = atof( displ[0].c_str() );
|
|
|
|
double displ_thresh2 = atof( displ[1].c_str() );
|
|
|
|
|
|
|
|
string rwy_stopway = token[7];
|
|
|
|
vector<string> stop
|
|
|
|
= simgear::strutils::split( rwy_stopway, "." );
|
|
|
|
double stopway1 = atof( stop[0].c_str() );
|
|
|
|
double stopway2 = atof( stop[1].c_str() );
|
|
|
|
|
|
|
|
int surface_code = atoi( token[10].c_str() );
|
|
|
|
|
James Turner:
Convert FGRunway to be heap-based, and inherit FGPositioned. This is a large, ugly change, since FGRunway was essentially a plain struct, with no accessors or abstraction. This change adds various helpers and accessors to FGRunway, but doesn't change many places to use them - that will be a follow up series of patches. It's still a large patch, but outside of FGAirport and FGRunway, mostly mechanical search-and-replace.
An interesting part of this change is that reciprocal runways now exist as independent objects, rather than being created on the fly by the search methods. This simplifies some pieces of code that search for and iterate runways. For users who only want one 'end' of a runway, the new 'isReciprocal' predicate allows them to ignore the 'other' end. Current the only user of this is the 'ground-radar' ATC feature. If we had data on which runways are truly 'single-ended', it would now be trivial to use this in the airport loader to *not* create the reciprocal.
2008-09-11 08:38:09 +00:00
|
|
|
FGRunway* rwy = new FGRunway(NULL, rwy_no, lon, lat, heading, length,
|
|
|
|
width, displ_thresh1, stopway1, surface_code, false);
|
|
|
|
|
|
|
|
FGRunway* reciprocal = new FGRunway(NULL, FGRunway::reverseIdent(rwy_no),
|
|
|
|
lon, lat, heading + 180.0, length, width,
|
|
|
|
displ_thresh2, stopway2, surface_code, true);
|
|
|
|
|
2008-08-14 18:13:39 +00:00
|
|
|
runways.push_back(rwy);
|
James Turner:
Convert FGRunway to be heap-based, and inherit FGPositioned. This is a large, ugly change, since FGRunway was essentially a plain struct, with no accessors or abstraction. This change adds various helpers and accessors to FGRunway, but doesn't change many places to use them - that will be a follow up series of patches. It's still a large patch, but outside of FGAirport and FGRunway, mostly mechanical search-and-replace.
An interesting part of this change is that reciprocal runways now exist as independent objects, rather than being created on the fly by the search methods. This simplifies some pieces of code that search for and iterate runways. For users who only want one 'end' of a runway, the new 'isReciprocal' predicate allows them to ignore the 'other' end. Current the only user of this is the 'ground-radar' ATC feature. If we had data on which runways are truly 'single-ended', it would now be trivial to use this in the airport loader to *not* create the reciprocal.
2008-09-11 08:38:09 +00:00
|
|
|
runways.push_back(reciprocal);
|
2005-05-30 08:47:00 +00:00
|
|
|
} else if ( line_id == 18 ) {
|
2004-12-22 23:57:07 +00:00
|
|
|
// beacon entry (ignore)
|
2005-05-30 08:47:00 +00:00
|
|
|
} else if ( line_id == 14 ) {
|
2007-09-09 23:21:48 +00:00
|
|
|
// control tower entry
|
|
|
|
token.clear();
|
|
|
|
token = simgear::strutils::split(line);
|
|
|
|
|
|
|
|
double lat = atof( token[1].c_str() );
|
|
|
|
double lon = atof( token[2].c_str() );
|
|
|
|
double elev = atof( token[3].c_str() );
|
|
|
|
last_tower = SGGeod::fromDegFt(lon, lat, elev);
|
|
|
|
got_tower = true;
|
2005-05-30 08:47:00 +00:00
|
|
|
} else if ( line_id == 19 ) {
|
2004-12-22 23:57:07 +00:00
|
|
|
// windsock entry (ignore)
|
2005-05-30 08:47:00 +00:00
|
|
|
} else if ( line_id == 15 ) {
|
2004-12-22 23:57:07 +00:00
|
|
|
// custom startup locations (ignore)
|
2007-10-11 16:22:39 +00:00
|
|
|
} else if ( line_id == 0 ) {
|
|
|
|
// ??
|
2005-05-30 08:47:00 +00:00
|
|
|
} else if ( line_id >= 50 && line_id <= 56 ) {
|
2004-12-22 23:57:07 +00:00
|
|
|
// frequency entries (ignore)
|
2005-05-30 08:47:00 +00:00
|
|
|
} else if ( line_id == 99 ) {
|
2004-12-22 23:57:07 +00:00
|
|
|
SG_LOG( SG_GENERAL, SG_DEBUG, "End of file reached" );
|
|
|
|
} else {
|
|
|
|
SG_LOG( SG_GENERAL, SG_ALERT,
|
2005-05-30 08:47:00 +00:00
|
|
|
"Unknown line(#" << line_num << ") in file: " << line );
|
2004-12-22 23:57:07 +00:00
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-05 12:59:43 +00:00
|
|
|
// add the last airport being processed if any
|
2007-09-09 23:21:48 +00:00
|
|
|
addAirport(airports, last_apt_id, last_apt_name, rwy_count, rwy_lat_accum, rwy_lon_accum,
|
2007-10-05 12:59:43 +00:00
|
|
|
last_rwy_heading, last_apt_elev, last_tower, got_tower, 0);
|
2007-09-09 23:21:48 +00:00
|
|
|
|
2004-12-22 23:57:07 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// Load the metar.dat file and update apt db with stations that
|
|
|
|
// have metar data.
|
|
|
|
//
|
|
|
|
|
|
|
|
sg_gzifstream metar_in( metar_file );
|
|
|
|
if ( !metar_in.is_open() ) {
|
|
|
|
SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << metar_file );
|
|
|
|
}
|
|
|
|
|
|
|
|
string ident;
|
|
|
|
while ( metar_in ) {
|
|
|
|
metar_in >> ident;
|
|
|
|
if ( ident == "#" || ident == "//" ) {
|
|
|
|
metar_in >> skipeol;
|
|
|
|
} else {
|
2005-09-20 20:26:57 +00:00
|
|
|
const FGAirport* a = airports->search( ident );
|
|
|
|
if ( a ) airports->has_metar( ident );
|
2004-12-22 23:57:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SG_LOG(SG_GENERAL, SG_INFO, "[FINISHED LOADING]");
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|