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
|
|
|
|
|
2009-09-18 15:27:19 +00:00
|
|
|
#include "apt_loader.hxx"
|
|
|
|
|
2004-12-22 23:57:07 +00:00
|
|
|
#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>
|
James Turner:
Trivial patch, but an important milestone:
Convert FGAirport to inherit FGPositioned. This concludes the first phase of the FGPositioned changes, and hopefully the most intrusive ones - adding in the base class. There's lots (and lots) of further work to do on the indexing and querying side, as well as cleaning up the accessors, but that will happen in single source files, or a group of related files at a time.
As a trivial note, this patch does fix a bug where the very last airport in apt.dat would get an invalid type. So for all you people who just love to fly to EHYB (Ypenburg, The Hague), things may work a little more sanely.
I'll intentionally let the dust settle after this patch, so any weird behaviour I may potentially have introduced shows up. Just to re-iterate, so far there should be absolutely no user-visible change in the behaviour of anything - navaids, position init, the route manager, AI flight plans, etc. If there is, please let me know and I'll fix it ASAP.
2008-09-13 08:07:22 +00:00
|
|
|
#include <simgear/structure/exception.hxx>
|
2010-05-02 21:57:08 +00:00
|
|
|
#include <simgear/bucket/newbucket.hxx>
|
2004-12-22 23:57:07 +00:00
|
|
|
|
2008-07-25 18:38:29 +00:00
|
|
|
#include <string>
|
2004-12-22 23:57:07 +00:00
|
|
|
|
|
|
|
#include "simple.hxx"
|
|
|
|
#include "runways.hxx"
|
2009-06-14 11:08:21 +00:00
|
|
|
#include "pavement.hxx"
|
2009-12-30 14:11:16 +00:00
|
|
|
#if ENABLE_ATCDCL
|
|
|
|
# include <ATCDCL/commlist.hxx>
|
2010-01-05 20:04:54 +00:00
|
|
|
#else
|
|
|
|
#include <ATC/atcutils.hxx>
|
2009-12-30 14:11:16 +00:00
|
|
|
#endif
|
2004-12-22 23:57:07 +00:00
|
|
|
|
2009-09-18 15:27:19 +00:00
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
using namespace std;
|
2004-12-22 23:57:07 +00:00
|
|
|
|
James Turner:
Trivial patch, but an important milestone:
Convert FGAirport to inherit FGPositioned. This concludes the first phase of the FGPositioned changes, and hopefully the most intrusive ones - adding in the base class. There's lots (and lots) of further work to do on the indexing and querying side, as well as cleaning up the accessors, but that will happen in single source files, or a group of related files at a time.
As a trivial note, this patch does fix a bug where the very last airport in apt.dat would get an invalid type. So for all you people who just love to fly to EHYB (Ypenburg, The Hague), things may work a little more sanely.
I'll intentionally let the dust settle after this patch, so any weird behaviour I may potentially have introduced shows up. Just to re-iterate, so far there should be absolutely no user-visible change in the behaviour of anything - navaids, position init, the route manager, AI flight plans, etc. If there is, please let me know and I'll fix it ASAP.
2008-09-13 08:07:22 +00:00
|
|
|
static FGPositioned::Type fptypeFromRobinType(int aType)
|
|
|
|
{
|
|
|
|
switch (aType) {
|
|
|
|
case 1: return FGPositioned::AIRPORT;
|
|
|
|
case 16: return FGPositioned::SEAPORT;
|
|
|
|
case 17: return FGPositioned::HELIPORT;
|
|
|
|
default:
|
|
|
|
SG_LOG(SG_GENERAL, SG_ALERT, "unsupported type:" << aType);
|
|
|
|
throw sg_range_exception("Unsupported airport type", "fptypeFromRobinType");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-29 22:23:22 +00:00
|
|
|
class APTLoader
|
2007-09-09 23:21:48 +00:00
|
|
|
{
|
2008-12-29 22:23:22 +00:00
|
|
|
public:
|
2009-09-18 15:27:19 +00:00
|
|
|
|
|
|
|
APTLoader()
|
|
|
|
: last_apt_id(""),
|
|
|
|
last_apt_name(""),
|
|
|
|
last_apt_elev(0.0),
|
|
|
|
last_apt_info(""),
|
|
|
|
last_apt_type("")
|
|
|
|
{}
|
|
|
|
|
2009-12-30 14:11:16 +00:00
|
|
|
|
2010-01-05 20:04:54 +00:00
|
|
|
|
2009-09-18 15:27:19 +00:00
|
|
|
void parseAPT(const string &aptdb_file, FGCommList *comm_list)
|
2008-12-29 22:23:22 +00:00
|
|
|
{
|
2004-12-22 23:57:07 +00:00
|
|
|
sg_gzifstream in( aptdb_file );
|
2009-09-18 15:27:19 +00:00
|
|
|
|
2004-12-22 23:57:07 +00:00
|
|
|
if ( !in.is_open() ) {
|
|
|
|
SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << aptdb_file );
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
string line;
|
2005-05-30 08:47:00 +00:00
|
|
|
char tmp[2049];
|
|
|
|
tmp[2048] = 0;
|
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
|
|
|
|
|
|
|
while ( ! in.eof() ) {
|
2008-12-29 22:23:22 +00:00
|
|
|
in.getline(tmp, 2048);
|
|
|
|
line = tmp; // string copy, ack
|
|
|
|
line_num++;
|
|
|
|
|
|
|
|
if ( !line.size() || isspace(tmp[0])) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (line.size() >= 3) {
|
|
|
|
char *p = (char *)memchr(tmp, ' ', 3);
|
|
|
|
if ( p )
|
|
|
|
*p = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
line_id = atoi(tmp);
|
|
|
|
if ( tmp[0] == 'I' ) {
|
|
|
|
// 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);
|
|
|
|
// vector<string> vers_token = simgear::strutils::split( tmp );
|
|
|
|
if ( strlen(tmp) > 4 ) {
|
|
|
|
char *p = (char *)memchr(tmp, ' ', 4);
|
|
|
|
if ( p )
|
|
|
|
*p = 0;
|
2004-12-22 23:57:07 +00:00
|
|
|
}
|
2008-12-29 22:23:22 +00:00
|
|
|
SG_LOG( SG_GENERAL, SG_INFO, "Data file version = " << tmp );
|
2009-06-14 11:08:21 +00:00
|
|
|
} else if ( line_id == 1 /* Airport */ ||
|
2005-05-30 08:47:00 +00:00
|
|
|
line_id == 16 /* Seaplane base */ ||
|
|
|
|
line_id == 17 /* Heliport */ ) {
|
2008-12-29 22:23:22 +00:00
|
|
|
parseAirportLine(simgear::strutils::split(line));
|
2009-06-14 11:08:21 +00:00
|
|
|
} else if ( line_id == 10 ) { // Runway v810
|
|
|
|
parseRunwayLine810(simgear::strutils::split(line));
|
|
|
|
} else if ( line_id == 100 ) { // Runway v850
|
|
|
|
parseRunwayLine850(simgear::strutils::split(line));
|
|
|
|
} else if ( line_id == 101 ) { // Water Runway v850
|
|
|
|
parseWaterRunwayLine850(simgear::strutils::split(line));
|
|
|
|
} else if ( line_id == 102 ) { // Helipad v850
|
|
|
|
parseHelipadLine850(simgear::strutils::split(line));
|
2008-12-29 22:23:22 +00:00
|
|
|
} else if ( line_id == 18 ) {
|
|
|
|
// beacon entry (ignore)
|
|
|
|
} else if ( line_id == 14 ) {
|
|
|
|
// control tower entry
|
|
|
|
vector<string> 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() );
|
|
|
|
tower = SGGeod::fromDegFt(lon, lat, elev + last_apt_elev);
|
|
|
|
got_tower = true;
|
|
|
|
} else if ( line_id == 19 ) {
|
|
|
|
// windsock entry (ignore)
|
2009-06-14 11:08:21 +00:00
|
|
|
} else if ( line_id == 20 ) {
|
|
|
|
// Taxiway sign (ignore)
|
|
|
|
} else if ( line_id == 21 ) {
|
|
|
|
// lighting objects (ignore)
|
2008-12-29 22:23:22 +00:00
|
|
|
} else if ( line_id == 15 ) {
|
|
|
|
// custom startup locations (ignore)
|
|
|
|
} else if ( line_id == 0 ) {
|
|
|
|
// ??
|
2009-09-18 15:27:19 +00:00
|
|
|
} else if ( line_id == 50 ) {
|
2010-01-05 20:04:54 +00:00
|
|
|
|
2009-09-18 15:27:19 +00:00
|
|
|
parseATISLine(comm_list, simgear::strutils::split(line));
|
2010-01-05 20:04:54 +00:00
|
|
|
|
2009-09-18 15:27:19 +00:00
|
|
|
} else if ( line_id >= 51 && line_id <= 56 ) {
|
|
|
|
// other frequency entries (ignore)
|
2009-06-14 11:08:21 +00:00
|
|
|
} else if ( line_id == 110 ) {
|
|
|
|
pavement = true;
|
2009-06-14 16:22:35 +00:00
|
|
|
parsePavementLine850(simgear::strutils::split(line, 0, 4));
|
2009-06-14 11:08:21 +00:00
|
|
|
} else if ( line_id >= 111 && line_id <= 114 ) {
|
|
|
|
if ( pavement )
|
|
|
|
parsePavementNodeLine850(line_id, simgear::strutils::split(line));
|
|
|
|
} else if ( line_id >= 115 && line_id <= 116 ) {
|
|
|
|
// other pavement nodes (ignore)
|
|
|
|
} else if ( line_id == 120 ) {
|
|
|
|
pavement = false;
|
|
|
|
} else if ( line_id == 130 ) {
|
|
|
|
pavement = false;
|
2008-12-29 22:23:22 +00:00
|
|
|
} else if ( line_id == 99 ) {
|
|
|
|
SG_LOG( SG_GENERAL, SG_DEBUG, "End of file reached" );
|
|
|
|
} else {
|
|
|
|
SG_LOG( SG_GENERAL, SG_ALERT,
|
|
|
|
"Unknown line(#" << line_num << ") in file: " << line );
|
2009-06-14 11:08:21 +00:00
|
|
|
exit( -1 );
|
2008-12-29 22:23:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
addAirport();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2009-09-18 15:27:19 +00:00
|
|
|
vector<string> token;
|
2008-12-29 22:23:22 +00:00
|
|
|
double rwy_lat_accum;
|
|
|
|
double rwy_lon_accum;
|
|
|
|
double last_rwy_heading;
|
|
|
|
int rwy_count;
|
|
|
|
bool got_tower;
|
|
|
|
string last_apt_id;
|
|
|
|
string last_apt_name;
|
|
|
|
double last_apt_elev;
|
|
|
|
SGGeod tower;
|
2009-09-18 15:27:19 +00:00
|
|
|
string last_apt_info;
|
|
|
|
string last_apt_type;
|
2009-06-14 11:08:21 +00:00
|
|
|
string pavement_ident;
|
|
|
|
bool pavement;
|
2008-12-29 22:23:22 +00:00
|
|
|
|
|
|
|
vector<FGRunwayPtr> runways;
|
|
|
|
vector<FGTaxiwayPtr> taxiways;
|
2009-06-14 11:08:21 +00:00
|
|
|
vector<FGPavementPtr> pavements;
|
2008-12-29 22:23:22 +00:00
|
|
|
|
|
|
|
void addAirport()
|
|
|
|
{
|
|
|
|
if (last_apt_id.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!rwy_count) {
|
|
|
|
SG_LOG(SG_GENERAL, SG_ALERT, "ERROR: No runways for " << last_apt_id
|
|
|
|
<< ", skipping." );
|
|
|
|
return;
|
|
|
|
}
|
2004-12-22 23:57:07 +00:00
|
|
|
|
2008-12-29 22:23:22 +00:00
|
|
|
double lat = rwy_lat_accum / (double)rwy_count;
|
|
|
|
double lon = rwy_lon_accum / (double)rwy_count;
|
2004-12-22 23:57:07 +00:00
|
|
|
|
2008-12-29 22:23:22 +00:00
|
|
|
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, last_apt_elev + tower_height);
|
|
|
|
}
|
2004-12-22 23:57:07 +00:00
|
|
|
|
2008-12-29 22:23:22 +00:00
|
|
|
SGGeod pos(SGGeod::fromDegFt(lon, lat, last_apt_elev));
|
|
|
|
FGAirport* apt = new FGAirport(last_apt_id, pos, tower, last_apt_name, false,
|
2009-09-18 15:27:19 +00:00
|
|
|
fptypeFromRobinType(atoi(last_apt_type.c_str())));
|
2009-06-14 11:08:21 +00:00
|
|
|
apt->setRunwaysAndTaxiways(runways, taxiways, pavements);
|
2008-12-29 22:23:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void parseAirportLine(const vector<string>& token)
|
|
|
|
{
|
|
|
|
const string& id(token[4]);
|
|
|
|
double elev = atof( token[1].c_str() );
|
2008-08-14 18:13:39 +00:00
|
|
|
|
2008-12-29 22:23:22 +00:00
|
|
|
addAirport();
|
2008-08-14 18:13:39 +00:00
|
|
|
|
2008-12-29 22:23:22 +00:00
|
|
|
last_apt_id = id;
|
|
|
|
last_apt_elev = elev;
|
|
|
|
last_apt_name = "";
|
|
|
|
got_tower = false;
|
|
|
|
|
|
|
|
// build the name
|
|
|
|
for ( unsigned int i = 5; i < token.size() - 1; ++i ) {
|
|
|
|
last_apt_name += token[i];
|
|
|
|
last_apt_name += " ";
|
2004-12-22 23:57:07 +00:00
|
|
|
}
|
2008-12-29 22:23:22 +00:00
|
|
|
last_apt_name += token[token.size() - 1];
|
2009-09-18 15:27:19 +00:00
|
|
|
last_apt_type = token[0];
|
2008-12-29 22:23:22 +00:00
|
|
|
|
|
|
|
// clear runway list for start of next airport
|
|
|
|
rwy_lon_accum = 0.0;
|
|
|
|
rwy_lat_accum = 0.0;
|
|
|
|
rwy_count = 0;
|
|
|
|
}
|
|
|
|
|
2009-06-14 11:08:21 +00:00
|
|
|
void parseRunwayLine810(const vector<string>& token)
|
2008-12-29 22:23:22 +00:00
|
|
|
{
|
|
|
|
double lat = atof( token[1].c_str() );
|
|
|
|
double lon = atof( token[2].c_str() );
|
|
|
|
rwy_lat_accum += lat;
|
|
|
|
rwy_lon_accum += lon;
|
|
|
|
rwy_count++;
|
2004-12-22 23:57:07 +00:00
|
|
|
|
2008-12-29 22:23:22 +00:00
|
|
|
const string& rwy_no(token[3]);
|
2007-09-09 23:21:48 +00:00
|
|
|
|
2008-12-29 22:23:22 +00:00
|
|
|
double heading = atof( token[4].c_str() );
|
|
|
|
double length = atoi( token[5].c_str() );
|
|
|
|
double width = atoi( token[8].c_str() );
|
|
|
|
|
|
|
|
last_rwy_heading = heading;
|
|
|
|
|
|
|
|
int surface_code = atoi( token[10].c_str() );
|
2009-09-08 11:23:53 +00:00
|
|
|
SGGeod pos(SGGeod::fromDegFt(lon, lat, last_apt_elev));
|
2008-12-29 22:23:22 +00:00
|
|
|
|
|
|
|
if (rwy_no[0] == 'x') {
|
|
|
|
// taxiway
|
|
|
|
FGTaxiway* t = new FGTaxiway(rwy_no, pos, heading, length, width, surface_code);
|
|
|
|
taxiways.push_back(t);
|
|
|
|
} else {
|
|
|
|
// (pair of) runways
|
|
|
|
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() );
|
|
|
|
|
|
|
|
FGRunway* rwy = new FGRunway(NULL, rwy_no, pos, heading, length,
|
|
|
|
width, displ_thresh1, stopway1, surface_code, false);
|
|
|
|
runways.push_back(rwy);
|
2009-06-14 11:08:21 +00:00
|
|
|
|
2008-12-29 22:23:22 +00:00
|
|
|
FGRunway* reciprocal = new FGRunway(NULL, FGRunway::reverseIdent(rwy_no),
|
|
|
|
pos, heading + 180.0, length, width,
|
|
|
|
displ_thresh2, stopway2, surface_code, true);
|
2009-06-14 11:08:21 +00:00
|
|
|
|
2008-12-29 22:23:22 +00:00
|
|
|
runways.push_back(reciprocal);
|
2009-09-16 00:17:12 +00:00
|
|
|
|
|
|
|
rwy->setReciprocalRunway(reciprocal);
|
|
|
|
reciprocal->setReciprocalRunway(rwy);
|
2008-12-29 22:23:22 +00:00
|
|
|
}
|
|
|
|
}
|
2009-06-14 11:08:21 +00:00
|
|
|
|
|
|
|
void parseRunwayLine850(const vector<string>& token)
|
|
|
|
{
|
|
|
|
double width = atof( token[1].c_str() ) * SG_METER_TO_FEET;
|
|
|
|
int surface_code = atoi( token[2].c_str() );
|
|
|
|
|
|
|
|
double lat_1 = atof( token[9].c_str() );
|
|
|
|
double lon_1 = atof( token[10].c_str() );
|
|
|
|
SGGeod pos_1(SGGeod::fromDegFt(lon_1, lat_1, 0.0));
|
|
|
|
rwy_lat_accum += lat_1;
|
|
|
|
rwy_lon_accum += lon_1;
|
|
|
|
rwy_count++;
|
|
|
|
|
|
|
|
double lat_2 = atof( token[18].c_str() );
|
|
|
|
double lon_2 = atof( token[19].c_str() );
|
|
|
|
SGGeod pos_2(SGGeod::fromDegFt(lon_2, lat_2, 0.0));
|
|
|
|
rwy_lat_accum += lat_2;
|
|
|
|
rwy_lon_accum += lon_2;
|
|
|
|
rwy_count++;
|
|
|
|
|
|
|
|
double length, heading_1, heading_2, dummy;
|
|
|
|
SGGeodesy::inverse( pos_1, pos_2, heading_1, heading_2, length );
|
|
|
|
SGGeod pos;
|
|
|
|
SGGeodesy::direct( pos_1, heading_1, length / 2.0, pos, dummy );
|
|
|
|
length *= SG_METER_TO_FEET;
|
|
|
|
|
|
|
|
last_rwy_heading = heading_1;
|
|
|
|
|
|
|
|
const string& rwy_no_1(token[8]);
|
|
|
|
const string& rwy_no_2(token[17]);
|
|
|
|
if ( rwy_no_1.size() == 0 || rwy_no_2.size() == 0 )
|
|
|
|
return;
|
|
|
|
|
|
|
|
double displ_thresh1 = atof( token[11].c_str() );
|
|
|
|
double displ_thresh2 = atof( token[20].c_str() );
|
|
|
|
|
|
|
|
double stopway1 = atof( token[12].c_str() );
|
|
|
|
double stopway2 = atof( token[21].c_str() );
|
|
|
|
|
|
|
|
FGRunway* rwy = new FGRunway(NULL, rwy_no_1, pos, heading_1, length,
|
|
|
|
width, displ_thresh1, stopway1, surface_code, false);
|
|
|
|
runways.push_back(rwy);
|
|
|
|
|
|
|
|
FGRunway* reciprocal = new FGRunway(NULL, rwy_no_2,
|
|
|
|
pos, heading_2, length, width,
|
|
|
|
displ_thresh2, stopway2, surface_code, true);
|
|
|
|
runways.push_back(reciprocal);
|
2009-09-16 00:17:12 +00:00
|
|
|
|
|
|
|
rwy->setReciprocalRunway(reciprocal);
|
|
|
|
reciprocal->setReciprocalRunway(rwy);
|
2009-06-14 11:08:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void parseWaterRunwayLine850(const vector<string>& token)
|
|
|
|
{
|
|
|
|
double width = atof( token[1].c_str() ) * SG_METER_TO_FEET;
|
|
|
|
|
|
|
|
double lat_1 = atof( token[4].c_str() );
|
|
|
|
double lon_1 = atof( token[5].c_str() );
|
|
|
|
SGGeod pos_1(SGGeod::fromDegFt(lon_1, lat_1, 0.0));
|
|
|
|
rwy_lat_accum += lat_1;
|
|
|
|
rwy_lon_accum += lon_1;
|
|
|
|
rwy_count++;
|
|
|
|
|
|
|
|
double lat_2 = atof( token[7].c_str() );
|
|
|
|
double lon_2 = atof( token[8].c_str() );
|
|
|
|
SGGeod pos_2(SGGeod::fromDegFt(lon_2, lat_2, 0.0));
|
|
|
|
rwy_lat_accum += lat_2;
|
|
|
|
rwy_lon_accum += lon_2;
|
|
|
|
rwy_count++;
|
|
|
|
|
|
|
|
double length, heading_1, heading_2, dummy;
|
|
|
|
SGGeodesy::inverse( pos_1, pos_2, heading_1, heading_2, length );
|
|
|
|
SGGeod pos;
|
|
|
|
SGGeodesy::direct( pos_1, heading_1, length / 2.0, pos, dummy );
|
|
|
|
|
|
|
|
last_rwy_heading = heading_1;
|
|
|
|
|
|
|
|
const string& rwy_no_1(token[3]);
|
|
|
|
const string& rwy_no_2(token[6]);
|
|
|
|
|
|
|
|
FGRunway* rwy = new FGRunway(NULL, rwy_no_1, pos, heading_1, length,
|
|
|
|
width, 0.0, 0.0, 13, false);
|
|
|
|
runways.push_back(rwy);
|
|
|
|
|
|
|
|
FGRunway* reciprocal = new FGRunway(NULL, rwy_no_2,
|
|
|
|
pos, heading_2, length, width,
|
|
|
|
0.0, 0.0, 13, true);
|
|
|
|
runways.push_back(reciprocal);
|
2009-09-16 00:17:12 +00:00
|
|
|
|
|
|
|
rwy->setReciprocalRunway(reciprocal);
|
|
|
|
reciprocal->setReciprocalRunway(rwy);
|
2009-06-14 11:08:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void parseHelipadLine850(const vector<string>& token)
|
|
|
|
{
|
|
|
|
double length = atof( token[5].c_str() ) * SG_METER_TO_FEET;
|
|
|
|
double width = atof( token[6].c_str() ) * SG_METER_TO_FEET;
|
|
|
|
|
|
|
|
double lat = atof( token[2].c_str() );
|
|
|
|
double lon = atof( token[3].c_str() );
|
|
|
|
SGGeod pos(SGGeod::fromDegFt(lon, lat, 0.0));
|
|
|
|
rwy_lat_accum += lat;
|
|
|
|
rwy_lon_accum += lon;
|
|
|
|
rwy_count++;
|
|
|
|
|
|
|
|
double heading = atof( token[4].c_str() );
|
|
|
|
|
|
|
|
last_rwy_heading = heading;
|
|
|
|
|
|
|
|
const string& rwy_no(token[1]);
|
|
|
|
int surface_code = atoi( token[7].c_str() );
|
|
|
|
|
|
|
|
FGRunway* rwy = new FGRunway(NULL, rwy_no, pos, heading, length,
|
|
|
|
width, 0.0, 0.0, surface_code, false);
|
|
|
|
runways.push_back(rwy);
|
|
|
|
}
|
|
|
|
|
|
|
|
void parsePavementLine850(const vector<string>& token)
|
|
|
|
{
|
|
|
|
if ( token.size() >= 5 ) {
|
|
|
|
pavement_ident = token[4];
|
2009-06-14 16:22:35 +00:00
|
|
|
if ( !pavement_ident.empty() && pavement_ident[pavement_ident.size()-1] == '\r' )
|
|
|
|
pavement_ident.erase( pavement_ident.size()-1 );
|
2009-06-14 11:08:21 +00:00
|
|
|
} else {
|
|
|
|
pavement_ident = "xx";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void parsePavementNodeLine850(int num, const vector<string>& token)
|
|
|
|
{
|
|
|
|
double lat = atof( token[1].c_str() );
|
|
|
|
double lon = atof( token[2].c_str() );
|
|
|
|
SGGeod pos(SGGeod::fromDegFt(lon, lat, 0.0));
|
|
|
|
|
|
|
|
FGPavement* pvt = 0;
|
|
|
|
if ( !pavement_ident.empty() ) {
|
|
|
|
pvt = new FGPavement( pavement_ident, pos );
|
|
|
|
pavements.push_back( pvt );
|
|
|
|
pavement_ident = "";
|
|
|
|
} else {
|
|
|
|
pvt = pavements.back();
|
|
|
|
}
|
|
|
|
if ( num == 112 || num == 114 ) {
|
|
|
|
double lat_b = atof( token[3].c_str() );
|
|
|
|
double lon_b = atof( token[4].c_str() );
|
|
|
|
SGGeod pos_b(SGGeod::fromDegFt(lon_b, lat_b, 0.0));
|
|
|
|
pvt->addBezierNode(pos, pos_b, num == 114);
|
|
|
|
} else {
|
|
|
|
pvt->addNode(pos, num == 113);
|
|
|
|
}
|
|
|
|
}
|
2010-01-05 20:04:54 +00:00
|
|
|
|
2009-09-18 15:27:19 +00:00
|
|
|
void parseATISLine(FGCommList *comm_list, const vector<string>& token)
|
|
|
|
{
|
|
|
|
if ( rwy_count <= 0 ) {
|
|
|
|
SG_LOG( SG_GENERAL, SG_ALERT,
|
|
|
|
"No runways; skipping AWOS for " + last_apt_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
// This assumes/requires that any code-50 line (ATIS or AWOS)
|
|
|
|
// applies to the preceding code-1 line (airport ID and name)
|
|
|
|
// and that a full set of code-10 lines (runway descriptors)
|
|
|
|
// has come between the code-1 and code-50 lines.
|
|
|
|
// typical code-50 lines:
|
|
|
|
// 50 11770 ATIS
|
|
|
|
// 50 11770 AWOS 3
|
|
|
|
// This code parallels code found in "operator>>" in ATC.hxx;
|
|
|
|
// FIXME: unify the code.
|
2010-01-05 20:04:54 +00:00
|
|
|
#if ENABLE_ATCDCL
|
2009-09-18 15:27:19 +00:00
|
|
|
ATCData a;
|
|
|
|
a.geod = SGGeod::fromDegFt(rwy_lon_accum / (double)rwy_count,
|
|
|
|
rwy_lat_accum / (double)rwy_count, last_apt_elev);
|
|
|
|
a.range = 50; // give all ATISs small range
|
|
|
|
a.ident = last_apt_id;
|
|
|
|
a.name = last_apt_name;
|
|
|
|
// short int representing tens of kHz:
|
|
|
|
a.freq = atoi(token[1].c_str());
|
|
|
|
if (token[2] == "ATIS") a.type = ATIS;
|
|
|
|
else a.type = AWOS; // ASOS same as AWOS
|
|
|
|
|
|
|
|
// generate cartesian coordinates
|
|
|
|
a.cart = SGVec3d::fromGeod(a.geod);
|
|
|
|
comm_list->commlist_freq[a.freq].push_back(a);
|
|
|
|
|
|
|
|
SGBucket bucket(a.geod);
|
|
|
|
int bucknum = bucket.gen_index();
|
|
|
|
comm_list->commlist_bck[bucknum].push_back(a);
|
2010-01-05 20:04:54 +00:00
|
|
|
#else
|
|
|
|
#endif
|
2009-09-18 15:27:19 +00:00
|
|
|
#if 0
|
|
|
|
SG_LOG( SG_GENERAL, SG_ALERT,
|
|
|
|
"Loaded ATIS/AWOS for airport: " << a.ident
|
|
|
|
<< " lat: " << a.geod.getLatitudeDeg()
|
|
|
|
<< " lon: " << a.geod.getLongitudeDeg()
|
|
|
|
<< " freq: " << a.freq
|
|
|
|
<< " type: " << a.type );
|
|
|
|
#endif
|
|
|
|
}
|
2010-01-05 20:04:54 +00:00
|
|
|
|
2008-12-29 22:23:22 +00:00
|
|
|
};
|
|
|
|
|
2009-12-30 14:11:16 +00:00
|
|
|
|
2008-12-29 22:23:22 +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.
|
2009-09-18 15:27:19 +00:00
|
|
|
bool fgAirportDBLoad( const string &aptdb_file,
|
|
|
|
FGCommList *comm_list, const std::string &metar_file )
|
2008-12-29 22:23:22 +00:00
|
|
|
{
|
2009-09-18 15:27:19 +00:00
|
|
|
|
2008-12-29 22:23:22 +00:00
|
|
|
APTLoader ld;
|
2009-09-18 15:27:19 +00:00
|
|
|
ld.parseAPT(aptdb_file, comm_list);
|
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 {
|
2008-12-26 15:26:42 +00:00
|
|
|
FGAirport* apt = FGAirport::findByIdent(ident);
|
|
|
|
if (apt) {
|
|
|
|
apt->setMetar(true);
|
|
|
|
}
|
2004-12-22 23:57:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SG_LOG(SG_GENERAL, SG_INFO, "[FINISHED LOADING]");
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2008-12-29 22:23:22 +00:00
|
|
|
|