X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FAirports%2Fapt_loader.cxx;h=f2f3b712076fcbc9e013fbd560671165d5cbf5a0;hb=234e2bdf091c64587152965926fe0e789066dfdf;hp=8984214d994f305d35a7fd8cccbdff80ff496cf3;hpb=5a16a28893d08133cd46dd7c00dbb19b0cec9d9d;p=flightgear.git diff --git a/src/Airports/apt_loader.cxx b/src/Airports/apt_loader.cxx index 8984214d9..f2f3b7120 100644 --- a/src/Airports/apt_loader.cxx +++ b/src/Airports/apt_loader.cxx @@ -39,22 +39,22 @@ #include #include #include +#include #include -#include "simple.hxx" +#include "airport.hxx" #include "runways.hxx" #include "pavement.hxx" -#if ENABLE_ATCDCL -# include -#else - #include -#endif +#include +#include #include using namespace std; +typedef SGSharedPtr FGPavementPtr; + static FGPositioned::Type fptypeFromRobinType(int aType) { switch (aType) { @@ -67,27 +67,30 @@ static FGPositioned::Type fptypeFromRobinType(int aType) } } + +namespace flightgear +{ + class APTLoader { public: APTLoader() : last_apt_id(""), - last_apt_name(""), last_apt_elev(0.0), - last_apt_info(""), - last_apt_type("") - {} - - + last_apt_info("") + { + currentAirportID = 0; + cache = NavDataCache::instance(); + } - void parseAPT(const string &aptdb_file, FGCommList *comm_list) + void parseAPT(const SGPath &aptdb_file) { - sg_gzifstream in( aptdb_file ); + sg_gzifstream in( aptdb_file.str() ); if ( !in.is_open() ) { SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << aptdb_file ); - exit(-1); + throw sg_io_exception("cannot open APT file", aptdb_file); } string line; @@ -102,10 +105,10 @@ public: line = tmp; // string copy, ack line_num++; - if ( !line.size() || isspace(tmp[0])) { + if ( line.empty() || isspace(tmp[0]) || tmp[0] == '#' ) { continue; } - + if (line.size() >= 3) { char *p = (char *)memchr(tmp, ' ', 3); if ( p ) @@ -113,16 +116,16 @@ public: } line_id = atoi(tmp); - if ( tmp[0] == 'I' ) { - // First line, indicates IBM (i.e. DOS line endings I - // believe.) + if ( tmp[0] == 'I' || tmp[0] == 'A' ) { + // First line, indicates IBM ("I") or Macintosh ("A") + // line endings. // move past this line and read and discard the next line // which is the version and copyright information in.getline(tmp, 2048); - // vector vers_token = simgear::strutils::split( tmp ); - if ( strlen(tmp) > 4 ) { - char *p = (char *)memchr(tmp, ' ', 4); + + if ( strlen(tmp) > 5 ) { + char *p = (char *)memchr(tmp, ' ', 5); if ( p ) *p = 0; } @@ -150,6 +153,8 @@ public: double elev = atof( token[3].c_str() ); tower = SGGeod::fromDegFt(lon, lat, elev + last_apt_elev); got_tower = true; + + cache->insertTower(currentAirportID, tower); } else if ( line_id == 19 ) { // windsock entry (ignore) } else if ( line_id == 20 ) { @@ -160,12 +165,8 @@ public: // custom startup locations (ignore) } else if ( line_id == 0 ) { // ?? - } 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 >= 50 && line_id <= 56) { + parseCommLine(line_id, simgear::strutils::split(line)); } else if ( line_id == 110 ) { pavement = true; parsePavementLine850(simgear::strutils::split(line, 0, 4)); @@ -178,16 +179,18 @@ public: pavement = false; } else if ( line_id == 130 ) { pavement = false; + } else if ( line_id >= 1000 ) { + // airport traffic flow (ignore) } 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 ); + "Unknown line(#" << line_num << ") in apt.dat file: " << line ); + throw sg_format_exception("malformed line in apt.dat:", line); } } - addAirport(); + finishAirport(); } private: @@ -198,47 +201,50 @@ private: int rwy_count; bool got_tower; string last_apt_id; - string last_apt_name; double last_apt_elev; SGGeod tower; string last_apt_info; - string last_apt_type; string pavement_ident; bool pavement; - vector runways; - vector taxiways; + //vector runways; + //vector taxiways; vector pavements; - void addAirport() - { - if (last_apt_id.empty()) { + NavDataCache* cache; + PositionedID currentAirportID; + + void finishAirport() + { + if (currentAirportID == 0) { return; } - + if (!rwy_count) { - SG_LOG(SG_GENERAL, SG_ALERT, "ERROR: No runways for " << last_apt_id - << ", skipping." ); - return; + currentAirportID = 0; + SG_LOG(SG_GENERAL, SG_ALERT, "ERROR: No runways for " << last_apt_id + << ", skipping." ); + return; } 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, last_apt_elev + tower_height); + // 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); + + cache->insertTower(currentAirportID, tower); } SGGeod pos(SGGeod::fromDegFt(lon, lat, last_apt_elev)); - FGAirport* apt = new FGAirport(last_apt_id, pos, tower, last_apt_name, false, - fptypeFromRobinType(atoi(last_apt_type.c_str()))); - - apt->setRunwaysAndTaxiways(runways, taxiways, pavements); + cache->updatePosition(currentAirportID, pos); + + currentAirportID = 0; } void parseAirportLine(const vector& token) @@ -246,25 +252,26 @@ private: const string& id(token[4]); double elev = atof( token[1].c_str() ); - addAirport(); + // finish the previous airport + finishAirport(); - last_apt_id = id; last_apt_elev = elev; - last_apt_name = ""; got_tower = false; + string name; // build the name for ( unsigned int i = 5; i < token.size() - 1; ++i ) { - last_apt_name += token[i]; - last_apt_name += " "; + name += token[i] + " "; } - last_apt_name += token[token.size() - 1]; - last_apt_type = token[0]; + name += token[token.size() - 1]; // clear runway list for start of next airport rwy_lon_accum = 0.0; rwy_lat_accum = 0.0; rwy_count = 0; + + int robinType = atoi(token[0].c_str()); + currentAirportID = cache->insertAirport(fptypeFromRobinType(robinType), id, name); } void parseRunwayLine810(const vector& token) @@ -280,16 +287,23 @@ private: double heading = atof( token[4].c_str() ); double length = atoi( token[5].c_str() ); double width = atoi( token[8].c_str() ); + length *= SG_FEET_TO_METER; + width *= SG_FEET_TO_METER; + + // adjust lat / lon to the start of the runway/taxiway, not the middle + SGGeod pos_1 = SGGeodesy::direct( SGGeod::fromDegFt(lon, lat, last_apt_elev), heading, -length/2 ); last_rwy_heading = heading; int surface_code = atoi( token[10].c_str() ); - SGGeod pos(SGGeod::fromDegFt(lon, lat, last_apt_elev)); - - if (rwy_no[0] == 'x') { - // taxiway - FGTaxiway* t = new FGTaxiway(rwy_no, pos, heading, length, width, surface_code); - taxiways.push_back(t); + + if (rwy_no[0] == 'x') { // Taxiway + cache->insertRunway(FGPositioned::TAXIWAY, rwy_no, pos_1, currentAirportID, + heading, length, width, 0.0, 0.0, surface_code); + } else if (rwy_no[0] == 'H') { // Helipad + SGGeod pos(SGGeod::fromDegFt(lon, lat, last_apt_elev)); + cache->insertRunway(FGPositioned::HELIPAD, rwy_no, pos, currentAirportID, + heading, length, width, 0.0, 0.0, surface_code); } else { // (pair of) runways string rwy_displ_threshold = token[6]; @@ -297,31 +311,38 @@ private: = simgear::strutils::split( rwy_displ_threshold, "." ); double displ_thresh1 = atof( displ[0].c_str() ); double displ_thresh2 = atof( displ[1].c_str() ); + displ_thresh1 *= SG_FEET_TO_METER; + displ_thresh2 *= SG_FEET_TO_METER; string rwy_stopway = token[7]; vector stop = simgear::strutils::split( rwy_stopway, "." ); double stopway1 = atof( stop[0].c_str() ); double stopway2 = atof( stop[1].c_str() ); + stopway1 *= SG_FEET_TO_METER; + stopway2 *= SG_FEET_TO_METER; - 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); + SGGeod pos_2 = SGGeodesy::direct( pos_1, heading, length ); - runways.push_back(reciprocal); + PositionedID rwy = cache->insertRunway(FGPositioned::RUNWAY, rwy_no, pos_1, + currentAirportID, heading, length, + width, displ_thresh1, stopway1, + surface_code); - rwy->setReciprocalRunway(reciprocal); - reciprocal->setReciprocalRunway(rwy); + PositionedID reciprocal = cache->insertRunway(FGPositioned::RUNWAY, + FGRunway::reverseIdent(rwy_no), pos_2, + currentAirportID, + SGMiscd::normalizePeriodic(0, 360, heading + 180.0), + length, width, displ_thresh2, stopway2, + surface_code); + + cache->setRunwayReciprocal(rwy, reciprocal); } } void parseRunwayLine850(const vector& token) { - double width = atof( token[1].c_str() ) * SG_METER_TO_FEET; + double width = atof( token[1].c_str() ); int surface_code = atoi( token[2].c_str() ); double lat_1 = atof( token[9].c_str() ); @@ -338,17 +359,14 @@ private: rwy_lon_accum += lon_2; rwy_count++; - double length, heading_1, heading_2, dummy; + double length, heading_1, heading_2; 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 ) + if ( rwy_no_1.empty() || rwy_no_2.empty() ) return; double displ_thresh1 = atof( token[11].c_str() ); @@ -357,22 +375,23 @@ private: 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); + PositionedID rwy = cache->insertRunway(FGPositioned::RUNWAY, rwy_no_1, pos_1, + currentAirportID, heading_1, length, + width, displ_thresh1, stopway1, + surface_code); + + PositionedID reciprocal = cache->insertRunway(FGPositioned::RUNWAY, + rwy_no_2, pos_2, + currentAirportID, heading_2, length, + width, displ_thresh2, stopway2, + surface_code); - rwy->setReciprocalRunway(reciprocal); - reciprocal->setReciprocalRunway(rwy); + cache->setRunwayReciprocal(rwy, reciprocal); } void parseWaterRunwayLine850(const vector& token) { - double width = atof( token[1].c_str() ) * SG_METER_TO_FEET; + double width = atof( token[1].c_str() ); double lat_1 = atof( token[4].c_str() ); double lon_1 = atof( token[5].c_str() ); @@ -388,33 +407,30 @@ private: rwy_lon_accum += lon_2; rwy_count++; - double length, heading_1, heading_2, dummy; + double length, heading_1, heading_2; 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); + PositionedID rwy = cache->insertRunway(FGPositioned::RUNWAY, rwy_no_1, pos_1, + currentAirportID, heading_1, length, + width, 0.0, 0.0, 13); + + PositionedID reciprocal = cache->insertRunway(FGPositioned::RUNWAY, + rwy_no_2, pos_2, + currentAirportID, heading_2, length, + width, 0.0, 0.0, 13); - rwy->setReciprocalRunway(reciprocal); - reciprocal->setReciprocalRunway(rwy); + cache->setRunwayReciprocal(rwy, reciprocal); } 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 length = atof( token[5].c_str() ); + double width = atof( token[6].c_str() ); double lat = atof( token[2].c_str() ); double lon = atof( token[3].c_str() ); @@ -430,9 +446,9 @@ private: 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); + cache->insertRunway(FGPositioned::HELIPAD, rwy_no, pos, + currentAirportID, heading, length, + width, 0.0, 0.0, surface_code); } void parsePavementLine850(const vector& token) @@ -454,7 +470,7 @@ private: FGPavement* pvt = 0; if ( !pavement_ident.empty() ) { - pvt = new FGPavement( pavement_ident, pos ); + pvt = new FGPavement( 0, pavement_ident, pos ); pavements.push_back( pvt ); pavement_ident = ""; } else { @@ -470,90 +486,88 @@ private: } } - void parseATISLine(FGCommList *comm_list, const vector& token) + void parseCommLine(int lineId, const vector& token) { if ( rwy_count <= 0 ) { - SG_LOG( SG_GENERAL, SG_ALERT, - "No runways; skipping AWOS for " + last_apt_id); + SG_LOG( SG_GENERAL, SG_ALERT, "No runways; skipping comm 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; + + SGGeod pos = SGGeod::fromDegFt(rwy_lon_accum / (double)rwy_count, + rwy_lat_accum / (double)rwy_count, last_apt_elev); + // 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 - } + int freqKhz = atoi(token[1].c_str()) * 10; + int rangeNm = 50; + FGPositioned::Type ty; + // Make sure we only pass on stations with at least a name + if (token.size() >2){ + + switch (lineId) { + case 50: + ty = FGPositioned::FREQ_AWOS; + for( size_t i = 2; i < token.size(); ++i ) + { + if( token[i] == "ATIS" ) + { + ty = FGPositioned::FREQ_ATIS; + break; + } + } + break; + + case 51: ty = FGPositioned::FREQ_UNICOM; break; + case 52: ty = FGPositioned::FREQ_CLEARANCE; break; + case 53: ty = FGPositioned::FREQ_GROUND; break; + case 54: ty = FGPositioned::FREQ_TOWER; break; + case 55: + case 56: ty = FGPositioned::FREQ_APP_DEP; break; + default: + throw sg_range_exception("unsupported apt.dat comm station type"); + } -}; + // Name can contain white spaces. All tokens after the second token are + // part of the name. + std::string name = token[2]; + for( size_t i = 3; i < token.size(); ++i ) + name += ' ' + token[i]; + cache->insertCommStation(ty, name, pos, freqKhz, rangeNm, currentAirportID); + } + else SG_LOG( SG_GENERAL, SG_DEBUG, "Found unnamed comm. Skipping: " << lineId); + } +}; + // 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, - FGCommList *comm_list, const std::string &metar_file ) +bool airportDBLoad( const SGPath &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. - // - - 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 { - FGAirport* apt = FGAirport::findByIdent(ident); - if (apt) { - apt->setMetar(true); - } - } + APTLoader ld; + ld.parseAPT(aptdb_file); + return true; +} + +bool metarDataLoad(const SGPath& metar_file) +{ + sg_gzifstream metar_in( metar_file.str() ); + if ( !metar_in.is_open() ) { + SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << metar_file ); + return false; + } + + NavDataCache* cache = NavDataCache::instance(); + string ident; + while ( metar_in ) { + metar_in >> ident; + if ( ident == "#" || ident == "//" ) { + metar_in >> skipeol; + } else { + cache->setAirportMetar(ident, true); } - - SG_LOG(SG_GENERAL, SG_INFO, "[FINISHED LOADING]"); - - return true; + } + + return true; } +} // of namespace flightgear