X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FAirports%2Fapt_loader.cxx;h=34cccff20cf7ce6f52618e2c3088215c4ded2fb3;hb=386aefe69358ce41a11c9afeb8f56e26758fe56b;hp=b12d062321091d3875ab8ad6f03f0a40d1b93b07;hpb=050221c30697d5abc9658f5b626418286895c16b;p=flightgear.git diff --git a/src/Airports/apt_loader.cxx b/src/Airports/apt_loader.cxx index b12d06232..34cccff20 100644 --- a/src/Airports/apt_loader.cxx +++ b/src/Airports/apt_loader.cxx @@ -26,6 +26,8 @@ # include #endif +#include "apt_loader.hxx" + #include #include // atof(), atoi() @@ -37,13 +39,22 @@ #include #include #include +#include #include #include "simple.hxx" #include "runways.hxx" +#include "pavement.hxx" +#if ENABLE_ATCDCL +# include +#else + #include +#endif -#include "apt_loader.hxx" +#include + +using namespace std; static FGPositioned::Type fptypeFromRobinType(int aType) { @@ -60,9 +71,21 @@ static FGPositioned::Type fptypeFromRobinType(int aType) class APTLoader { public: - void parseAPT(const string &aptdb_file) + + APTLoader() + : last_apt_id(""), + last_apt_name(""), + last_apt_elev(0.0), + last_apt_info(""), + last_apt_type("") + {} + + + + void parseAPT(const string &aptdb_file, FGCommList *comm_list) { sg_gzifstream in( aptdb_file ); + if ( !in.is_open() ) { SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << aptdb_file ); exit(-1); @@ -105,12 +128,18 @@ public: *p = 0; } SG_LOG( SG_GENERAL, SG_INFO, "Data file version = " << tmp ); - } else if ( line_id == 1 /* Airport */ || + } else if ( line_id == 1 /* Airport */ || line_id == 16 /* Seaplane base */ || line_id == 17 /* Heliport */ ) { parseAirportLine(simgear::strutils::split(line)); - } else if ( line_id == 10 ) { - parseRunwayLine(simgear::strutils::split(line)); + } 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)); } else if ( line_id == 18 ) { // beacon entry (ignore) } else if ( line_id == 14 ) { @@ -124,18 +153,38 @@ public: got_tower = true; } else if ( line_id == 19 ) { // windsock entry (ignore) + } else if ( line_id == 20 ) { + // Taxiway sign (ignore) + } else if ( line_id == 21 ) { + // lighting objects (ignore) } else if ( line_id == 15 ) { // custom startup locations (ignore) } else if ( line_id == 0 ) { // ?? - } else if ( line_id >= 50 && line_id <= 56 ) { - // frequency entries (ignore) + } else if ( line_id == 50 ) { + + parseATISLine(comm_list, simgear::strutils::split(line)); + + } else if ( line_id >= 51 && line_id <= 56 ) { + // other frequency entries (ignore) + } else if ( line_id == 110 ) { + pavement = true; + parsePavementLine850(simgear::strutils::split(line, 0, 4)); + } 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; } 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 ); - exit(-1); + exit( -1 ); } } @@ -143,6 +192,7 @@ public: } private: + vector token; double rwy_lat_accum; double rwy_lon_accum; double last_rwy_heading; @@ -152,10 +202,14 @@ private: string last_apt_name; double last_apt_elev; SGGeod tower; - int last_apt_type; + string last_apt_info; + string last_apt_type; + string pavement_ident; + bool pavement; vector runways; vector taxiways; + vector pavements; void addAirport() { @@ -183,9 +237,8 @@ private: SGGeod pos(SGGeod::fromDegFt(lon, lat, last_apt_elev)); FGAirport* apt = new FGAirport(last_apt_id, pos, tower, last_apt_name, false, - fptypeFromRobinType(last_apt_type)); - - apt->setRunwaysAndTaxiways(runways, taxiways); + fptypeFromRobinType(atoi(last_apt_type.c_str()))); + apt->setRunwaysAndTaxiways(runways, taxiways, pavements); } void parseAirportLine(const vector& token) @@ -206,7 +259,7 @@ private: last_apt_name += " "; } last_apt_name += token[token.size() - 1]; - last_apt_type = atoi( token[0].c_str() ); + last_apt_type = token[0]; // clear runway list for start of next airport rwy_lon_accum = 0.0; @@ -214,7 +267,7 @@ private: rwy_count = 0; } - void parseRunwayLine(const vector& token) + void parseRunwayLine810(const vector& token) { double lat = atof( token[1].c_str() ); double lon = atof( token[2].c_str() ); @@ -231,7 +284,7 @@ private: last_rwy_heading = heading; int surface_code = atoi( token[10].c_str() ); - SGGeod pos(SGGeod::fromDegFt(lon, lat, 0.0)); + SGGeod pos(SGGeod::fromDegFt(lon, lat, last_apt_elev)); if (rwy_no[0] == 'x') { // taxiway @@ -254,24 +307,228 @@ private: FGRunway* rwy = new FGRunway(NULL, rwy_no, pos, heading, length, width, displ_thresh1, stopway1, surface_code, false); runways.push_back(rwy); - + FGRunway* reciprocal = new FGRunway(NULL, FGRunway::reverseIdent(rwy_no), pos, heading + 180.0, length, width, displ_thresh2, stopway2, surface_code, true); - + runways.push_back(reciprocal); + + rwy->setReciprocalRunway(reciprocal); + reciprocal->setReciprocalRunway(rwy); } } + + void parseRunwayLine850(const vector& 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); + + rwy->setReciprocalRunway(reciprocal); + reciprocal->setReciprocalRunway(rwy); + } + + void parseWaterRunwayLine850(const vector& 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); + + rwy->setReciprocalRunway(reciprocal); + reciprocal->setReciprocalRunway(rwy); + } + + void parseHelipadLine850(const vector& 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& token) + { + if ( token.size() >= 5 ) { + pavement_ident = token[4]; + if ( !pavement_ident.empty() && pavement_ident[pavement_ident.size()-1] == '\r' ) + pavement_ident.erase( pavement_ident.size()-1 ); + } else { + pavement_ident = "xx"; + } + } + + void parsePavementNodeLine850(int num, const vector& 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); + } + } + + void parseATISLine(FGCommList *comm_list, const vector& 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. +#if ENABLE_ATCDCL + 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); +#else +#endif +#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 + } + }; + // 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. -bool fgAirportDBLoad( const string &aptdb_file, const string &metar_file ) +bool fgAirportDBLoad( const string &aptdb_file, + FGCommList *comm_list, const std::string &metar_file ) { - APTLoader ld; - ld.parseAPT(aptdb_file); + APTLoader ld; + ld.parseAPT(aptdb_file, comm_list); // // Load the metar.dat file and update apt db with stations that // have metar data.