From cda2337041ea72c9dc1db6f9cb0d729bdf12e2e2 Mon Sep 17 00:00:00 2001 From: scttgs0 Date: Tue, 23 May 2023 00:56:19 -0500 Subject: [PATCH] Maintenance: apt_loader SPDX tags. parameter to loadAirportFormFile() changed to const&. parameter to Line() ctor changed to const&. parameter to loadAirport() changed to const&. member variable initialization. ++prefix for complex types. virtual dtor. --- src/Airports/apt_loader.cxx | 1389 +++++++++++++++++------------------ src/Airports/apt_loader.hxx | 20 +- 2 files changed, 691 insertions(+), 718 deletions(-) diff --git a/src/Airports/apt_loader.cxx b/src/Airports/apt_loader.cxx index c19c51833..1e8e05f52 100644 --- a/src/Airports/apt_loader.cxx +++ b/src/Airports/apt_loader.cxx @@ -1,261 +1,239 @@ -// 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 -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -// -// $Id$ - +/* + * SPDX-FileName: apt_loader.cxx + * SPDX-FileComment: a front end loader of the apt.dat file. This loader populates the runway and basic classes. + * SPDX-FileCopyrightText: Copyright (C) 2004 Curtis L. Olson - http://www.flightgear.org/~curt + * SPDX-License-Identifier: GPL-2.0-or-later + */ #ifdef HAVE_CONFIG_H -# include +#include #endif -#include "apt_loader.hxx" - -#include - #include +#include +#include // std::size_t +#include // isspace() +#include +#include // std::istringstream #include // atof(), atoi() #include // memchr() -#include // isspace() -#include +#include +#include // std::pair, std::move() +#include +#include #include #include #include +#include #include #include -#include -#include // std::size_t -#include -#include -#include // std::pair, std::move() - -#include "airport.hxx" -#include "runways.hxx" -#include "pavement.hxx" +#include #include #include -#include -#include -#include // std::istringstream +#include "airport.hxx" +#include "apt_loader.hxx" +#include "pavement.hxx" +#include "runways.hxx" + -using std::vector; using std::string; +using std::vector; namespace strutils = simgear::strutils; static FGPositioned::Type fptypeFromRobinType(unsigned 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"); - } + 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"); + } } -namespace flightgear -{ +namespace flightgear { APTLoader::APTLoader() - : last_apt_id(""), - last_apt_elev(0.0), - currentAirportPosID(0), - cache(NavDataCache::instance()) -{ } + : last_apt_id(""), + last_apt_elev(0.0), + currentAirportPosID(0), + cache(NavDataCache::instance()) +{ +} -APTLoader::~APTLoader() { } +APTLoader::~APTLoader() {} -void APTLoader::readAptDatFile(const SGPath &aptdb_file, +void APTLoader::readAptDatFile(const SGPath& aptdb_file, std::size_t bytesReadSoFar, std::size_t totalSizeOfAllAptDatFiles) { - string apt_dat = aptdb_file.utf8Str(); // full path to the file being parsed - sg_gzifstream in(aptdb_file, std::ios_base::in | std::ios_base::binary, true); + string apt_dat = aptdb_file.utf8Str(); // full path to the file being parsed + sg_gzifstream in(aptdb_file, std::ios_base::in | std::ios_base::binary, true); - if ( !in.is_open() ) { - const std::string errMsg = simgear::strutils::error_string(errno); - SG_LOG( SG_GENERAL, SG_ALERT, - "Cannot open file '" << apt_dat << "': " << errMsg ); - throw sg_io_exception("Cannot open file (" + errMsg + ")", - sg_location(aptdb_file)); - } - - string line; - - unsigned int rowCode = 0; // terminology used in the apt.dat format spec - unsigned int line_num = 0; - // "airport identifier": terminology used in the apt.dat format spec. It is - // often an ICAO code, but not always. - string currentAirportId; - // Boolean used to make sure we don't try to load the same airport several - // times. Defaults to true only to ensure we don't add garbage to - // 'airportInfoMap' under the key "" (empty airport identifier) in case the - // apt.dat file doesn't have a start-of-airport row code (1, 16 or 17) after - // its header---which would be invalid, anyway. - bool skipAirport = true; - - // Read the apt.dat header (two lines) - while ( line_num < 2 && std::getline(in, line) ) { - // 'line' may end with an \r character (tested on Linux, only \n was - // stripped: std::getline() only discards the _native_ line terminator) - line_num++; - - if ( line_num == 1 ) { - std::string stripped_line = simgear::strutils::strip(line); - // First line indicates IBM ("I") or Macintosh ("A") line endings. - if ( stripped_line != "I" && stripped_line != "A" ) { - std::string pb = "invalid first line (neither 'I' nor 'A')"; - SG_LOG( SG_GENERAL, SG_ALERT, aptdb_file << ": " << pb); - throw sg_format_exception("cannot parse '" + apt_dat + "': " + pb, - stripped_line); - } - } else { // second line of the file - vector fields(strutils::split(line, 0, 1)); - - if (fields.empty()) { - string errMsg = "unable to parse format version: empty line"; - SG_LOG(SG_GENERAL, SG_ALERT, apt_dat << ": " << errMsg); - throw sg_format_exception("cannot parse '" + apt_dat + "': " + errMsg, - string()); - } else { - unsigned int aptDatFormatVersion = - strutils::readNonNegativeInt(fields[0]); - SG_LOG(SG_GENERAL, SG_INFO, - "apt.dat format version (" << apt_dat << "): " << - aptDatFormatVersion); - } - } - } // end of the apt.dat header - - throwExceptionIfStreamError(in, aptdb_file); - - while ( std::getline(in, line) ) { - // 'line' may end with an \r character, see above - line_num++; - - if ( isBlankOrCommentLine(line) ) - continue; - - if ((line_num % 100) == 0) { - // every 100 lines - unsigned int percent = ((bytesReadSoFar + in.approxOffset()) * 100) - / totalSizeOfAllAptDatFiles; - cache->setRebuildPhaseProgress( - NavDataCache::REBUILD_READING_APT_DAT_FILES, percent); + if (!in.is_open()) { + const std::string errMsg = simgear::strutils::error_string(errno); + SG_LOG(SG_GENERAL, SG_ALERT, + "Cannot open file '" << apt_dat << "': " << errMsg); + throw sg_io_exception("Cannot open file (" + errMsg + ")", + sg_location(aptdb_file)); } - // Extract the first field into 'rowCode' - rowCode = atoi(line.c_str()); + string line; - if ( rowCode == 1 /* Airport */ || - rowCode == 16 /* Seaplane base */ || - rowCode == 17 /* Heliport */ ) { - vector tokens(simgear::strutils::split(line)); - if (tokens.size() < 6) { - SG_LOG( SG_GENERAL, SG_WARN, - apt_dat << ":" << line_num << ": invalid airport header " - "(at least 6 fields are required)" ); - skipAirport = true; // discard everything until the next airport header - continue; - } + unsigned int rowCode = 0; // terminology used in the apt.dat format spec + unsigned int line_num = 0; + // "airport identifier": terminology used in the apt.dat format spec. It is + // often an ICAO code, but not always. + string currentAirportId; + // Boolean used to make sure we don't try to load the same airport several + // times. Defaults to true only to ensure we don't add garbage to + // 'airportInfoMap' under the key "" (empty airport identifier) in case the + // apt.dat file doesn't have a start-of-airport row code (1, 16 or 17) after + // its header---which would be invalid, anyway. + bool skipAirport = true; - currentAirportId = tokens[4]; // often an ICAO, but not always - // Check if the airport is already in 'airportInfoMap'; get the - // existing entry, if any, otherwise insert a new one. - std::pair - insertRetval = airportInfoMap.insert( - AirportInfoMapType::value_type(currentAirportId, RawAirportInfo())); - skipAirport = !insertRetval.second; + // Read the apt.dat header (two lines) + while (line_num < 2 && std::getline(in, line)) { + // 'line' may end with an \r character (tested on Linux, only \n was + // stripped: std::getline() only discards the _native_ line terminator) + line_num++; - if ( skipAirport ) { - SG_LOG( SG_GENERAL, SG_INFO, - apt_dat << ":" << line_num << ": skipping airport " << - currentAirportId << " (already defined earlier)" ); - } else { - // We haven't seen this airport yet in any apt.dat file - RawAirportInfo& airportInfo = insertRetval.first->second; - airportInfo.file = aptdb_file; - airportInfo.rowCode = rowCode; - airportInfo.firstLineNum = line_num; - airportInfo.firstLineTokens = std::move(tokens); - } - } else if ( rowCode == 99 ) { - SG_LOG( SG_GENERAL, SG_DEBUG, - apt_dat << ":" << line_num << ": code 99 found " - "(normally at end of file)" ); - } else if ( !skipAirport ) { - // Line belonging to an already started, and not skipped airport entry; - // just append it. - airportInfoMap[currentAirportId].otherLines.emplace_back( - line_num, rowCode, line); - } - } // of file reading loop + if (line_num == 1) { + std::string stripped_line = simgear::strutils::strip(line); + // First line indicates IBM ("I") or Macintosh ("A") line endings. + if (stripped_line != "I" && stripped_line != "A") { + std::string pb = "invalid first line (neither 'I' nor 'A')"; + SG_LOG(SG_GENERAL, SG_ALERT, aptdb_file << ": " << pb); + throw sg_format_exception("cannot parse '" + apt_dat + "': " + pb, + stripped_line); + } + } else { // second line of the file + vector fields(strutils::split(line, 0, 1)); - throwExceptionIfStreamError(in, aptdb_file); + if (fields.empty()) { + string errMsg = "unable to parse format version: empty line"; + SG_LOG(SG_GENERAL, SG_ALERT, apt_dat << ": " << errMsg); + throw sg_format_exception("cannot parse '" + apt_dat + "': " + errMsg, + string()); + } else { + unsigned int aptDatFormatVersion = + strutils::readNonNegativeInt(fields[0]); + SG_LOG(SG_GENERAL, SG_INFO, + "apt.dat format version (" << apt_dat << "): " << aptDatFormatVersion); + } + } + } // end of the apt.dat header + + throwExceptionIfStreamError(in, aptdb_file); + + while (std::getline(in, line)) { + // 'line' may end with an \r character, see above + line_num++; + + if (isBlankOrCommentLine(line)) + continue; + + if ((line_num % 100) == 0) { + // every 100 lines + unsigned int percent = ((bytesReadSoFar + in.approxOffset()) * 100) / totalSizeOfAllAptDatFiles; + cache->setRebuildPhaseProgress( + NavDataCache::REBUILD_READING_APT_DAT_FILES, percent); + } + + // Extract the first field into 'rowCode' + rowCode = atoi(line.c_str()); + + if (rowCode == 1 /* Airport */ || + rowCode == 16 /* Seaplane base */ || + rowCode == 17 /* Heliport */) { + vector tokens(simgear::strutils::split(line)); + if (tokens.size() < 6) { + SG_LOG(SG_GENERAL, SG_WARN, + apt_dat << ":" << line_num << ": invalid airport header " + "(at least 6 fields are required)"); + skipAirport = true; // discard everything until the next airport header + continue; + } + + currentAirportId = tokens[4]; // often an ICAO, but not always + // Check if the airport is already in 'airportInfoMap'; get the + // existing entry, if any, otherwise insert a new one. + std::pair + insertRetval = airportInfoMap.insert( + AirportInfoMapType::value_type(currentAirportId, RawAirportInfo())); + skipAirport = !insertRetval.second; + + if (skipAirport) { + SG_LOG(SG_GENERAL, SG_INFO, + apt_dat << ":" << line_num << ": skipping airport " << currentAirportId << " (already defined earlier)"); + } else { + // We haven't seen this airport yet in any apt.dat file + RawAirportInfo& airportInfo = insertRetval.first->second; + airportInfo.file = aptdb_file; + airportInfo.rowCode = rowCode; + airportInfo.firstLineNum = line_num; + airportInfo.firstLineTokens = std::move(tokens); + } + } else if (rowCode == 99) { + SG_LOG(SG_GENERAL, SG_DEBUG, + apt_dat << ":" << line_num << ": code 99 found " + "(normally at end of file)"); + } else if (!skipAirport) { + // Line belonging to an already started, and not skipped airport entry; + // just append it. + airportInfoMap[currentAirportId].otherLines.emplace_back( + line_num, rowCode, line); + } + } // of file reading loop + + throwExceptionIfStreamError(in, aptdb_file); } void APTLoader::loadAirports() { - AirportInfoMapType::size_type nbLoadedAirports = 0; - AirportInfoMapType::size_type nbAirports = airportInfoMap.size(); + AirportInfoMapType::size_type nbLoadedAirports = 0; + AirportInfoMapType::size_type nbAirports = airportInfoMap.size(); - // Loop over all airports found in all apt.dat files - for (AirportInfoMapType::const_iterator it = airportInfoMap.begin(); - it != airportInfoMap.end(); it++) { - // Full path to the apt.dat file this airport info comes from - const string aptDat = it->second.file.utf8Str(); + // Loop over all airports found in all apt.dat files + for (AirportInfoMapType::const_iterator it = airportInfoMap.begin(); + it != airportInfoMap.end(); ++it) { + // Full path to the apt.dat file this airport info comes from + const string aptDat = it->second.file.utf8Str(); - // this is just the current airport identifier - last_apt_id = it->first; - RawAirportInfo rawinfo = it->second; + // this is just the current airport identifier + last_apt_id = it->first; + RawAirportInfo rawinfo = it->second; - loadAirport(aptDat, last_apt_id, &rawinfo); - nbLoadedAirports++; + loadAirport(aptDat, last_apt_id, &rawinfo); + nbLoadedAirports++; - if ((nbLoadedAirports % 300) == 0) { - // Every 300 airports - unsigned int percent = nbLoadedAirports * 100 / nbAirports; - cache->setRebuildPhaseProgress(NavDataCache::REBUILD_LOADING_AIRPORTS, - percent); - } - } // of loop over 'airportInfoMap' + if ((nbLoadedAirports % 300) == 0) { + // Every 300 airports + unsigned int percent = nbLoadedAirports * 100 / nbAirports; + cache->setRebuildPhaseProgress(NavDataCache::REBUILD_LOADING_AIRPORTS, + percent); + } + } // of loop over 'airportInfoMap' - SG_LOG( SG_GENERAL, SG_INFO, - "Loaded data for " << nbLoadedAirports << " airports" ); + SG_LOG(SG_GENERAL, SG_INFO, + "Loaded data for " << nbLoadedAirports << " airports"); } // Parse and return specific apt.dat file containing a single airport. -const FGAirport* APTLoader::loadAirportFromFile(std::string id, const SGPath& aptdb_file) +const FGAirport* APTLoader::loadAirportFromFile(const std::string& id, const SGPath& aptdb_file) { - std::size_t bytesReadSoFar = 10; - std::size_t totalSizeOfAllAptDatFiles = 100; + std::size_t bytesReadSoFar = 10; + std::size_t totalSizeOfAllAptDatFiles = 100; - readAptDatFile(aptdb_file.str(), bytesReadSoFar, totalSizeOfAllAptDatFiles); + readAptDatFile(aptdb_file.str(), bytesReadSoFar, totalSizeOfAllAptDatFiles); - RawAirportInfo rawInfo = airportInfoMap[id]; - return loadAirport(aptdb_file.c_str(), id, &rawInfo, true); + RawAirportInfo rawInfo = airportInfoMap[id]; + return loadAirport(aptdb_file.c_str(), id, &rawInfo, true); } static bool isCommLine(const int code) @@ -263,184 +241,182 @@ static bool isCommLine(const int code) return ((code >= 50) && (code <= 56)) || ((code >= 1050) && (code <= 1056)); } -const FGAirport* APTLoader::loadAirport(const string aptDat, const std::string airportID, RawAirportInfo* airport_info, bool createFGAirport) +const FGAirport* APTLoader::loadAirport(const string& aptDat, const std::string& airportID, RawAirportInfo* airport_info, bool createFGAirport) { - // The first line for this airport was already split over whitespace, but - // remains to be parsed for the most part. - parseAirportLine(airport_info->rowCode, airport_info->firstLineTokens); - const LinesList& lines = airport_info->otherLines; + // The first line for this airport was already split over whitespace, but + // remains to be parsed for the most part. + parseAirportLine(airport_info->rowCode, airport_info->firstLineTokens); + const LinesList& lines = airport_info->otherLines; - NodeBlock current_block = None; + NodeBlock current_block = None; - // Loop over the second and subsequent lines - for (LinesList::const_iterator linesIt = lines.begin(); - linesIt != lines.end(); linesIt++) { - // Beware that linesIt->str may end with an '\r' character, see above! - unsigned int rowCode = linesIt->rowCode; + // Loop over the second and subsequent lines + for (LinesList::const_iterator linesIt = lines.begin(); + linesIt != lines.end(); ++linesIt) { + // Beware that linesIt->str may end with an '\r' character, see above! + unsigned int rowCode = linesIt->rowCode; - if ( rowCode == 10 ) { // Runway v810 - parseRunwayLine810(aptDat, linesIt->number, - simgear::strutils::split(linesIt->str)); - } else if ( rowCode == 100 ) { // Runway v850 - parseRunwayLine850(aptDat, linesIt->number, - simgear::strutils::split(linesIt->str)); - } else if ( rowCode == 101 ) { // Water Runway v850 - parseWaterRunwayLine850(aptDat, linesIt->number, - simgear::strutils::split(linesIt->str)); - } else if ( rowCode == 102 ) { // Helipad v850 - parseHelipadLine850(aptDat, linesIt->number, + if (rowCode == 10) { // Runway v810 + parseRunwayLine810(aptDat, linesIt->number, + simgear::strutils::split(linesIt->str)); + } else if (rowCode == 100) { // Runway v850 + parseRunwayLine850(aptDat, linesIt->number, + simgear::strutils::split(linesIt->str)); + } else if (rowCode == 101) { // Water Runway v850 + parseWaterRunwayLine850(aptDat, linesIt->number, + simgear::strutils::split(linesIt->str)); + } else if (rowCode == 102) { // Helipad v850 + parseHelipadLine850(aptDat, linesIt->number, + simgear::strutils::split(linesIt->str)); + } else if (rowCode == 18) { + // beacon entry (ignore) + } else if (rowCode == 14) { // Viewpoint/control tower + parseViewpointLine(aptDat, linesIt->number, + simgear::strutils::split(linesIt->str)); + } else if (rowCode == 19) { + // windsock entry (ignore) + } else if (rowCode == 20) { + // Taxiway sign (ignore) + } else if (rowCode == 21) { + // lighting objects (ignore) + } else if (rowCode == 15) { + // custom startup locations (ignore) + } else if (rowCode == 0) { + // ?? + } else if (isCommLine(rowCode)) { + parseCommLine(aptDat, linesIt->number, rowCode, simgear::strutils::split(linesIt->str)); - } else if ( rowCode == 18 ) { - // beacon entry (ignore) - } else if ( rowCode == 14 ) { // Viewpoint/control tower - parseViewpointLine(aptDat, linesIt->number, - simgear::strutils::split(linesIt->str)); - } else if ( rowCode == 19 ) { - // windsock entry (ignore) - } else if ( rowCode == 20 ) { - // Taxiway sign (ignore) - } else if ( rowCode == 21 ) { - // lighting objects (ignore) - } else if ( rowCode == 15 ) { - // custom startup locations (ignore) - } else if ( rowCode == 0 ) { - // ?? - } else if (isCommLine(rowCode)) { - parseCommLine(aptDat, linesIt->number, rowCode, - simgear::strutils::split(linesIt->str)); - } else if (rowCode == 110) { - current_block = Pavement; - parsePavementLine850(simgear::strutils::split(linesIt->str, 0, 4)); - } else if (rowCode >= 111 && rowCode <= 116) { - switch (current_block) { - case Pavement : - parseNodeLine850(&pavements, aptDat, linesIt->number, rowCode, - simgear::strutils::split(linesIt->str)); - break; - case AirportBoundary : - parseNodeLine850(&airport_boundary, aptDat, linesIt->number, rowCode, - simgear::strutils::split(linesIt->str)); - break; - case LinearFeature : - parseNodeLine850(&linear_feature, aptDat, linesIt->number, rowCode, - simgear::strutils::split(linesIt->str)); - break; - default : - case None : - std::ostringstream oss; - string cleanedLine = cleanLine(linesIt->str); - oss << aptDat << ":" << linesIt->number << ": unexpected row code " << - rowCode; - SG_LOG( SG_GENERAL, SG_ALERT, oss.str() << " (" << cleanedLine << ")" ); - throw sg_format_exception(oss.str(), cleanedLine); - break; - } - } else if (rowCode == 120) { - current_block = LinearFeature; - } else if (rowCode == 130) { - current_block = AirportBoundary; - } else if (rowCode >= 1000) { - // airport traffic flow (ignore) + } else if (rowCode == 110) { + current_block = Pavement; + parsePavementLine850(simgear::strutils::split(linesIt->str, 0, 4)); + } else if (rowCode >= 111 && rowCode <= 116) { + switch (current_block) { + case Pavement: + parseNodeLine850(&pavements, aptDat, linesIt->number, rowCode, + simgear::strutils::split(linesIt->str)); + break; + case AirportBoundary: + parseNodeLine850(&airport_boundary, aptDat, linesIt->number, rowCode, + simgear::strutils::split(linesIt->str)); + break; + case LinearFeature: + parseNodeLine850(&linear_feature, aptDat, linesIt->number, rowCode, + simgear::strutils::split(linesIt->str)); + break; + default: + case None: + std::ostringstream oss; + string cleanedLine = cleanLine(linesIt->str); + oss << aptDat << ":" << linesIt->number << ": unexpected row code " << rowCode; + SG_LOG(SG_GENERAL, SG_ALERT, oss.str() << " (" << cleanedLine << ")"); + throw sg_format_exception(oss.str(), cleanedLine); + break; + } + } else if (rowCode == 120) { + current_block = LinearFeature; + } else if (rowCode == 130) { + current_block = AirportBoundary; + } else if (rowCode >= 1000) { + // airport traffic flow (ignore) + } else { + std::ostringstream oss; + string cleanedLine = cleanLine(linesIt->str); + oss << aptDat << ":" << linesIt->number << ": unknown row code " << rowCode; + SG_LOG(SG_GENERAL, SG_ALERT, oss.str() << " (" << cleanedLine << ")"); + throw sg_format_exception(oss.str(), cleanedLine); + } + } // of loop over the second and subsequent apt.dat lines for the airport + + finishAirport(aptDat); + + if (createFGAirport) { + FGAirportRef airport = FGAirport::findByIdent(airportID); + + std::for_each( + pavements.begin(), + pavements.end(), + [airport](FGPavementRef p) { airport->addPavement(p); }); + + std::for_each( + airport_boundary.begin(), + airport_boundary.end(), + [airport](FGPavementRef p) { airport->addBoundary(p); }); + + std::for_each( + linear_feature.begin(), + linear_feature.end(), + [airport](FGPavementRef p) { airport->addLineFeature(p); }); + + pavements.clear(); + airport_boundary.clear(); + linear_feature.clear(); + + + return airport; + } else { - std::ostringstream oss; - string cleanedLine = cleanLine(linesIt->str); - oss << aptDat << ":" << linesIt->number << ": unknown row code " << rowCode; - SG_LOG(SG_GENERAL, SG_ALERT, oss.str() << " (" << cleanedLine << ")"); - throw sg_format_exception(oss.str(), cleanedLine); + // No FGAirport requested + return NULL; } - } // of loop over the second and subsequent apt.dat lines for the airport - - finishAirport(aptDat); - - if (createFGAirport) { - FGAirportRef airport = FGAirport::findByIdent(airportID); - - std::for_each( - pavements.begin(), - pavements.end(), - [airport] (FGPavementRef p) { airport->addPavement(p); } ); - - std::for_each( - airport_boundary.begin(), - airport_boundary.end(), - [airport] (FGPavementRef p) { airport->addBoundary(p); } ); - - std::for_each( - linear_feature.begin(), - linear_feature.end(), - [airport] (FGPavementRef p) { airport->addLineFeature(p); } ); - - pavements.clear(); - airport_boundary.clear(); - linear_feature.clear(); - - - return airport; - - } else { - // No FGAirport requested - return NULL; - } } // Tell whether an apt.dat line is blank or a comment line bool APTLoader::isBlankOrCommentLine(const std::string& line) { - size_t pos = line.find_first_not_of(" \t"); - return ( pos == std::string::npos || - line[pos] == '\r' || - line.find("##", pos) == pos ); + size_t pos = line.find_first_not_of(" \t"); + return (pos == std::string::npos || + line[pos] == '\r' || + line.find("##", pos) == pos); } std::string APTLoader::cleanLine(const std::string& line) { - std::string res = line; + std::string res = line; - // Lines obtained from readAptDatFile() may end with \r, which can be quite - // confusing when printed to the terminal. - for (std::string::reverse_iterator it = res.rbegin(); - it != res.rend() && *it == '\r'; /* empty */) - { // The beauty of C++ iterators... - it = std::string::reverse_iterator(res.erase( (it+1).base() )); - } + // Lines obtained from readAptDatFile() may end with \r, which can be quite + // confusing when printed to the terminal. + for (std::string::reverse_iterator it = res.rbegin(); + it != res.rend() && *it == '\r'; + /* empty */) { // The beauty of C++ iterators... + it = std::string::reverse_iterator(res.erase((it + 1).base())); + } - return res; + return res; } void APTLoader::throwExceptionIfStreamError(const sg_gzifstream& input_stream, const SGPath& path) { - if (input_stream.bad()) { - const std::string errMsg = simgear::strutils::error_string(errno); + if (input_stream.bad()) { + const std::string errMsg = simgear::strutils::error_string(errno); - SG_LOG( SG_NAVAID, SG_ALERT, - "Error while reading '" << path.utf8Str() << "': " << errMsg ); - throw sg_io_exception("APTLoader: error reading file (" + errMsg + ")", - sg_location(path)); - } + SG_LOG(SG_NAVAID, SG_ALERT, + "Error while reading '" << path.utf8Str() << "': " << errMsg); + throw sg_io_exception("APTLoader: error reading file (" + errMsg + ")", + sg_location(path)); + } } void APTLoader::finishAirport(const string& aptDat) { - if (currentAirportPosID == 0) { - return; - } + if (currentAirportPosID == 0) { + return; + } + + if (!rwy_count) { + currentAirportPosID = 0; + SG_LOG(SG_GENERAL, SG_ALERT, "Error in '" << aptDat << "': no runways for " << last_apt_id << ", skipping."); + return; + } + + double lat = rwy_lat_accum / (double)rwy_count; + double lon = rwy_lon_accum / (double)rwy_count; + + SGGeod pos(SGGeod::fromDegFt(lon, lat, last_apt_elev)); + cache->updatePosition(currentAirportPosID, pos); - if (!rwy_count) { currentAirportPosID = 0; - SG_LOG( SG_GENERAL, SG_ALERT, "Error in '" << aptDat << - "': no runways for " << last_apt_id << ", skipping." ); - return; - } - - double lat = rwy_lat_accum / (double)rwy_count; - double lon = rwy_lon_accum / (double)rwy_count; - - SGGeod pos(SGGeod::fromDegFt(lon, lat, last_apt_elev)); - cache->updatePosition(currentAirportPosID, pos); - - currentAirportPosID = 0; } // 'rowCode' is passed to avoid decoding it twice, since that work was already @@ -448,469 +424,464 @@ void APTLoader::finishAirport(const string& aptDat) void APTLoader::parseAirportLine(unsigned int rowCode, const vector& token) { - // The algorithm in APTLoader::readAptDatFile() ensures this is at least 5. - vector::size_type lastIndex = token.size() - 1; - const string& id(token[4]); - double elev = atof( token[1].c_str() ); - last_apt_elev = elev; + // The algorithm in APTLoader::readAptDatFile() ensures this is at least 5. + vector::size_type lastIndex = token.size() - 1; + const string& id(token[4]); + double elev = atof(token[1].c_str()); + last_apt_elev = elev; - string name; - // build the name - for ( vector::size_type i = 5; i < lastIndex; ++i ) { - name += token[i] + " "; - } - name += token[lastIndex]; + string name; + // build the name + for (vector::size_type i = 5; i < lastIndex; ++i) { + name += token[i] + " "; + } + name += token[lastIndex]; - // clear runway list for start of next airport - rwy_lon_accum = 0.0; - rwy_lat_accum = 0.0; - rwy_count = 0; + // clear runway list for start of next airport + rwy_lon_accum = 0.0; + rwy_lat_accum = 0.0; + rwy_count = 0; - currentAirportPosID = cache->insertAirport(fptypeFromRobinType(rowCode), - id, name); + currentAirportPosID = cache->insertAirport(fptypeFromRobinType(rowCode), + id, name); } void APTLoader::parseRunwayLine810(const string& aptDat, unsigned int lineNum, const vector& token) { - if (token.size() < 11) { - SG_LOG( SG_GENERAL, SG_WARN, - aptDat << ":" << lineNum << ": invalid v810 runway line " << - "(row code 10): at least 11 fields are required" ); - return; - } + if (token.size() < 11) { + SG_LOG(SG_GENERAL, SG_WARN, + aptDat << ":" << lineNum << ": invalid v810 runway line " + << "(row code 10): at least 11 fields are required"); + return; + } - double lat = atof( token[1].c_str() ); - double lon = atof( token[2].c_str() ); - rwy_lat_accum += lat; - rwy_lon_accum += lon; - rwy_count++; + double lat = atof(token[1].c_str()); + double lon = atof(token[2].c_str()); + rwy_lat_accum += lat; + rwy_lon_accum += lon; + rwy_count++; - const string& rwy_no(token[3]); + const 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() ); - length *= SG_FEET_TO_METER; - width *= SG_FEET_TO_METER; + 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 ); + // 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; + last_rwy_heading = heading; - int surface_code = atoi( token[10].c_str() ); + int surface_code = atoi(token[10].c_str()); - if (rwy_no[0] == 'x') { // Taxiway - cache->insertRunway( - FGPositioned::TAXIWAY, rwy_no, pos_1, currentAirportPosID, - 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, currentAirportPosID, - heading, length, width, 0.0, 0.0, surface_code); - } else { - // (pair of) runways - string rwy_displ_threshold = token[6]; - vector displ - = 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; + if (rwy_no[0] == 'x') { // Taxiway + cache->insertRunway( + FGPositioned::TAXIWAY, rwy_no, pos_1, currentAirportPosID, + 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, currentAirportPosID, + heading, length, width, 0.0, 0.0, surface_code); + } else { + // (pair of) runways + string rwy_displ_threshold = token[6]; + vector displ = 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; + 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; - SGGeod pos_2 = SGGeodesy::direct( pos_1, heading, length ); + SGGeod pos_2 = SGGeodesy::direct(pos_1, heading, length); - PositionedID rwy = cache->insertRunway(FGPositioned::RUNWAY, rwy_no, pos_1, - currentAirportPosID, heading, length, - width, displ_thresh1, stopway1, - surface_code); + PositionedID rwy = cache->insertRunway(FGPositioned::RUNWAY, rwy_no, pos_1, + currentAirportPosID, heading, length, + width, displ_thresh1, stopway1, + surface_code); - PositionedID reciprocal = cache->insertRunway( - FGPositioned::RUNWAY, - FGRunway::reverseIdent(rwy_no), pos_2, - currentAirportPosID, - SGMiscd::normalizePeriodic(0, 360, heading + 180.0), - length, width, displ_thresh2, stopway2, - surface_code); + PositionedID reciprocal = cache->insertRunway( + FGPositioned::RUNWAY, + FGRunway::reverseIdent(rwy_no), pos_2, + currentAirportPosID, + SGMiscd::normalizePeriodic(0, 360, heading + 180.0), + length, width, displ_thresh2, stopway2, + surface_code); - cache->setRunwayReciprocal(rwy, reciprocal); - } + cache->setRunwayReciprocal(rwy, reciprocal); + } } void APTLoader::parseRunwayLine850(const string& aptDat, unsigned int lineNum, const vector& token) { - if (token.size() < 26) { - SG_LOG( SG_GENERAL, SG_WARN, - aptDat << ":" << lineNum << ": invalid v850 runway line " << - "(row code 100): at least 26 fields are required" ); - return; - } + if (token.size() < 26) { + SG_LOG(SG_GENERAL, SG_WARN, + aptDat << ":" << lineNum << ": invalid v850 runway line " + << "(row code 100): at least 26 fields are required"); + return; + } - double width = atof( token[1].c_str() ); - int surface_code = atoi( token[2].c_str() ); - int shoulder_code = atoi( token[3].c_str() ); - float smoothness = atof( token[4].c_str() ); - int center_lights = atoi( token[5].c_str() ); - int edge_lights = atoi( token[6].c_str() ); - int distance_remaining = atoi( token[7].c_str() ); + double width = atof(token[1].c_str()); + int surface_code = atoi(token[2].c_str()); + int shoulder_code = atoi(token[3].c_str()); + float smoothness = atof(token[4].c_str()); + int center_lights = atoi(token[5].c_str()); + int edge_lights = atoi(token[6].c_str()); + int distance_remaining = atoi(token[7].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_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 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; - SGGeodesy::inverse( pos_1, pos_2, heading_1, heading_2, length ); + double length, heading_1, heading_2; + SGGeodesy::inverse(pos_1, pos_2, heading_1, heading_2, length); - last_rwy_heading = heading_1; + last_rwy_heading = heading_1; - const string& rwy_no_1(token[8]); - const string& rwy_no_2(token[17]); - if ( rwy_no_1.empty() || rwy_no_2.empty() ) // these tests are weird... - return; + const string& rwy_no_1(token[8]); + const string& rwy_no_2(token[17]); + if (rwy_no_1.empty() || rwy_no_2.empty()) // these tests are weird... + return; - double displ_thresh1 = atof( token[11].c_str() ); - double displ_thresh2 = atof( token[20].c_str() ); + 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() ); + double stopway1 = atof(token[12].c_str()); + double stopway2 = atof(token[21].c_str()); - int markings1 = atoi( token[13].c_str() ); - int markings2 = atoi( token[22].c_str() ); + int markings1 = atoi(token[13].c_str()); + int markings2 = atoi(token[22].c_str()); - int approach1 = atoi( token[14].c_str() ); - int approach2 = atoi( token[23].c_str() ); + int approach1 = atoi(token[14].c_str()); + int approach2 = atoi(token[23].c_str()); - int tdz1 = atoi( token[15].c_str() ); - int tdz2 = atoi( token[24].c_str() ); + int tdz1 = atoi(token[15].c_str()); + int tdz2 = atoi(token[24].c_str()); - int reil1 = atoi( token[16].c_str() ); - int reil2 = atoi( token[25].c_str() ); + int reil1 = atoi(token[16].c_str()); + int reil2 = atoi(token[25].c_str()); - PositionedID rwy = cache->insertRunway(FGPositioned::RUNWAY, rwy_no_1, pos_1, - currentAirportPosID, heading_1, length, - width, displ_thresh1, stopway1, markings1, - approach1, tdz1, reil1, - surface_code, shoulder_code, smoothness, - center_lights, edge_lights, distance_remaining); + PositionedID rwy = cache->insertRunway(FGPositioned::RUNWAY, rwy_no_1, pos_1, + currentAirportPosID, heading_1, length, + width, displ_thresh1, stopway1, markings1, + approach1, tdz1, reil1, + surface_code, shoulder_code, smoothness, + center_lights, edge_lights, distance_remaining); - PositionedID reciprocal = cache->insertRunway( - FGPositioned::RUNWAY, - rwy_no_2, pos_2, - currentAirportPosID, heading_2, length, - width, displ_thresh2, stopway2, markings2, - approach2, tdz2, reil2, - surface_code, shoulder_code, smoothness, - center_lights, edge_lights, distance_remaining); + PositionedID reciprocal = cache->insertRunway( + FGPositioned::RUNWAY, + rwy_no_2, pos_2, + currentAirportPosID, heading_2, length, + width, displ_thresh2, stopway2, markings2, + approach2, tdz2, reil2, + surface_code, shoulder_code, smoothness, + center_lights, edge_lights, distance_remaining); - cache->setRunwayReciprocal(rwy, reciprocal); + cache->setRunwayReciprocal(rwy, reciprocal); } void APTLoader::parseWaterRunwayLine850(const string& aptDat, unsigned int lineNum, const vector& token) { - if (token.size() < 9) { - SG_LOG( SG_GENERAL, SG_WARN, - aptDat << ":" << lineNum << ": invalid v850 water runway line " << - "(row code 101): at least 9 fields are required" ); - return; - } + if (token.size() < 9) { + SG_LOG(SG_GENERAL, SG_WARN, + aptDat << ":" << lineNum << ": invalid v850 water runway line " + << "(row code 101): at least 9 fields are required"); + return; + } - double width = atof( token[1].c_str() ); + double width = atof(token[1].c_str()); - 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_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 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; - SGGeodesy::inverse( pos_1, pos_2, heading_1, heading_2, length ); + double length, heading_1, heading_2; + SGGeodesy::inverse(pos_1, pos_2, heading_1, heading_2, length); - last_rwy_heading = heading_1; + last_rwy_heading = heading_1; - const string& rwy_no_1(token[3]); - const string& rwy_no_2(token[6]); + const string& rwy_no_1(token[3]); + const string& rwy_no_2(token[6]); - // For water runways we overload the edge_lights to indicate use of buoys, - // as they too will be objects. Also, water runways don't have edge lights. - PositionedID rwy = cache->insertRunway(FGPositioned::RUNWAY, rwy_no_1, pos_1, - currentAirportPosID, heading_1, length, - width, 0.0, 0.0, 0, 0, 0, 0, 13, 0, 1.0, 0, 1, 0); + // For water runways we overload the edge_lights to indicate use of buoys, + // as they too will be objects. Also, water runways don't have edge lights. + PositionedID rwy = cache->insertRunway(FGPositioned::RUNWAY, rwy_no_1, pos_1, + currentAirportPosID, heading_1, length, + width, 0.0, 0.0, 0, 0, 0, 0, 13, 0, 1.0, 0, 1, 0); - PositionedID reciprocal = cache->insertRunway( - FGPositioned::RUNWAY, - rwy_no_2, pos_2, - currentAirportPosID, heading_2, length, - width, 0.0, 0.0, 13); + PositionedID reciprocal = cache->insertRunway( + FGPositioned::RUNWAY, + rwy_no_2, pos_2, + currentAirportPosID, heading_2, length, + width, 0.0, 0.0, 13); - cache->setRunwayReciprocal(rwy, reciprocal); + cache->setRunwayReciprocal(rwy, reciprocal); } void APTLoader::parseHelipadLine850(const string& aptDat, unsigned int lineNum, const vector& token) { - if (token.size() < 12) { - SG_LOG( SG_GENERAL, SG_WARN, - aptDat << ":" << lineNum << ": invalid v850 helipad line " << - "(row code 102): at least 12 fields are required" ); - return; - } + if (token.size() < 12) { + SG_LOG(SG_GENERAL, SG_WARN, + aptDat << ":" << lineNum << ": invalid v850 helipad line " + << "(row code 102): at least 12 fields are required"); + return; + } - double length = atof( token[5].c_str() ); - double width = atof( token[6].c_str() ); + 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() ); - SGGeod pos(SGGeod::fromDegFt(lon, lat, 0.0)); - rwy_lat_accum += lat; - rwy_lon_accum += lon; - rwy_count++; + 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() ); + double heading = atof(token[4].c_str()); - last_rwy_heading = heading; + last_rwy_heading = heading; - const string& rwy_no(token[1]); - int surface_code = atoi( token[7].c_str() ); - int markings = atoi( token[8].c_str() ); - int shoulder_code = atoi( token[9].c_str() ); - float smoothness = atof( token[10].c_str() ); - int edge_lights = atoi( token[11].c_str() ); + const string& rwy_no(token[1]); + int surface_code = atoi(token[7].c_str()); + int markings = atoi(token[8].c_str()); + int shoulder_code = atoi(token[9].c_str()); + float smoothness = atof(token[10].c_str()); + int edge_lights = atoi(token[11].c_str()); - cache->insertRunway(FGPositioned::HELIPAD, rwy_no, pos, - currentAirportPosID, heading, length, - width, 0.0, 0.0, markings, 0, 0, 0, - surface_code, shoulder_code, smoothness, 0, edge_lights, 0); + cache->insertRunway(FGPositioned::HELIPAD, rwy_no, pos, + currentAirportPosID, heading, length, + width, 0.0, 0.0, markings, 0, 0, 0, + surface_code, shoulder_code, smoothness, 0, edge_lights, 0); } void APTLoader::parseViewpointLine(const string& aptDat, unsigned int lineNum, const vector& token) { - if (token.size() < 5) { - SG_LOG( SG_GENERAL, SG_WARN, - aptDat << ":" << lineNum << ": invalid viewpoint line " - "(row code 14): at least 5 fields are required" ); - } else { - 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); - cache->insertTower(currentAirportPosID, tower); - } + if (token.size() < 5) { + SG_LOG(SG_GENERAL, SG_WARN, + aptDat << ":" << lineNum << ": invalid viewpoint line " + "(row code 14): at least 5 fields are required"); + } else { + 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); + cache->insertTower(currentAirportPosID, tower); + } } void APTLoader::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"; - } + 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 APTLoader::parseNodeLine850(NodeList *nodelist, +void APTLoader::parseNodeLine850(NodeList* nodelist, const string& aptDat, unsigned int lineNum, int rowCode, const vector& token) { - static const unsigned int minNbTokens[] = {3, 5, 3, 5, 3, 5}; - assert(111 <= rowCode && rowCode <= 116); + static const unsigned int minNbTokens[] = {3, 5, 3, 5, 3, 5}; + assert(111 <= rowCode && rowCode <= 116); - if (token.size() < minNbTokens[rowCode-111]) { - SG_LOG( SG_GENERAL, SG_WARN, - aptDat << ":" << lineNum << ": invalid v850 node line " << - "(row code " << rowCode << "): at least " << - minNbTokens[rowCode-111] << " fields are required" ); - return; - } + if (token.size() < minNbTokens[rowCode - 111]) { + SG_LOG(SG_GENERAL, SG_WARN, + aptDat << ":" << lineNum << ": invalid v850 node line " + << "(row code " << rowCode << "): at least " << minNbTokens[rowCode - 111] << " fields are required"); + return; + } - double lat = atof( token[1].c_str() ); - double lon = atof( token[2].c_str() ); - SGGeod pos(SGGeod::fromDegFt(lon, lat, 0.0)); + 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() ) || ( nodelist->size() == 0 )) { - pvt = new FGPavement( 0, pavement_ident, pos ); - nodelist->push_back( pvt ); - pavement_ident = ""; - } else { - pvt = nodelist->back(); - } + FGPavement* pvt = 0; + if ((!pavement_ident.empty()) || (nodelist->size() == 0)) { + pvt = new FGPavement(0, pavement_ident, pos); + nodelist->push_back(pvt); + pavement_ident = ""; + } else { + pvt = nodelist->back(); + } - int paintCode = 0; - int lightCode = 0; + int paintCode = 0; + int lightCode = 0; - // Line information. The 2nd last token is the painted line type. Last token - // is the light type of the segment. Only applicable to codes 111-114. - if ((rowCode < 115) && (token.size() == (minNbTokens[rowCode-111] + 1))) { - // We've got a line paint code but no lighting code - paintCode = atoi(token[minNbTokens[rowCode-111]].c_str()); - } + // Line information. The 2nd last token is the painted line type. Last token + // is the light type of the segment. Only applicable to codes 111-114. + if ((rowCode < 115) && (token.size() == (minNbTokens[rowCode - 111] + 1))) { + // We've got a line paint code but no lighting code + paintCode = atoi(token[minNbTokens[rowCode - 111]].c_str()); + } - if ((rowCode < 115) && (token.size() == (minNbTokens[rowCode-111] + 2))) { - // We've got a line paint code and a lighting code - paintCode = atoi(token[minNbTokens[rowCode-111] -1].c_str()); - lightCode = atoi(token[minNbTokens[rowCode-111]].c_str()); - } + if ((rowCode < 115) && (token.size() == (minNbTokens[rowCode - 111] + 2))) { + // We've got a line paint code and a lighting code + paintCode = atoi(token[minNbTokens[rowCode - 111] - 1].c_str()); + lightCode = atoi(token[minNbTokens[rowCode - 111]].c_str()); + } - if ((rowCode == 112) || (rowCode == 114) || (rowCode == 116)) { - 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, (rowCode == 114) || (rowCode == 116), (rowCode == 114), paintCode, lightCode); - } else { - pvt->addNode(pos, (rowCode == 113) || (rowCode == 115), (rowCode == 113), paintCode, lightCode); - } + if ((rowCode == 112) || (rowCode == 114) || (rowCode == 116)) { + 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, (rowCode == 114) || (rowCode == 116), (rowCode == 114), paintCode, lightCode); + } else { + pvt->addNode(pos, (rowCode == 113) || (rowCode == 115), (rowCode == 113), paintCode, lightCode); + } } void APTLoader::parseCommLine(const string& aptDat, unsigned int lineNum, unsigned int rowCode, const vector& token) { - if (token.size() < 3) { - SG_LOG( SG_GENERAL, SG_WARN, - aptDat << ":" << lineNum << ": invalid Comm Frequency line " << - "(row code " << rowCode << "): at least 3 fields are required" ); - return; - } else if (rwy_count <= 0) { - SG_LOG( SG_GENERAL, SG_ALERT, - aptDat << ":" << lineNum << ": no runways, skipping Comm " << - "Frequency line for " << last_apt_id ); - // There used to be no 'return' here. Not sure how useful this is, but - // clearly this code block doesn't make sense without it, so here it is. - return; - } - - SGGeod pos = SGGeod::fromDegFt(rwy_lon_accum / (double)rwy_count, - rwy_lat_accum / (double)rwy_count, - last_apt_elev); - - const bool isAPT1000Code = rowCode > 1000; - if (isAPT1000Code) { - rowCode -= 1000; - } - - // short int representing tens of kHz, or just kHz directly - int freqKhz = std::stoi(token[1]); - if (isAPT1000Code) { - const int channel = freqKhz % 25; - if (channel != 0 && channel != 5 && channel != 10 && channel != 15) { - SG_LOG(SG_GENERAL, SG_ALERT, - aptDat << ":" << lineNum << ": skipping invalid 8.333 kHz Frequency " << freqKhz << " for " << last_apt_id); - return; - } - } else { - freqKhz *= 10; - const int remainder = freqKhz % 100; - // this is to ensure frequencies such as 126.12 become 126.125 - if (remainder == 20 || remainder == 70) { - freqKhz += 5; - } - - if (freqKhz % 25) { - SG_LOG(SG_GENERAL, SG_ALERT, - aptDat << ":" << lineNum << ": skipping invalid 25 kHz Frequency " << freqKhz << " for " << last_apt_id); - return; - } - } - - if (freqKhz < 118000 || freqKhz >= 137000) { - SG_LOG(SG_GENERAL, SG_ALERT, - aptDat << ":" << lineNum << ": skipping out of range Frequency " << freqKhz << " for " << last_apt_id); - return; - } - - int rangeNm = 50; - FGPositioned::Type ty; - - switch (rowCode) { - case 50: - ty = FGPositioned::FREQ_AWOS; - for (size_t i = 2; i < token.size(); ++i) - { - if (token[i] == "ATIS") - { - ty = FGPositioned::FREQ_ATIS; - break; - } + if (token.size() < 3) { + SG_LOG(SG_GENERAL, SG_WARN, + aptDat << ":" << lineNum << ": invalid Comm Frequency line " + << "(row code " << rowCode << "): at least 3 fields are required"); + return; + } else if (rwy_count <= 0) { + SG_LOG(SG_GENERAL, SG_ALERT, + aptDat << ":" << lineNum << ": no runways, skipping Comm " + << "Frequency line for " << last_apt_id); + // There used to be no 'return' here. Not sure how useful this is, but + // clearly this code block doesn't make sense without it, so here it is. + return; } - 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"); - } + SGGeod pos = SGGeod::fromDegFt(rwy_lon_accum / (double)rwy_count, + rwy_lat_accum / (double)rwy_count, + last_apt_elev); - // Name can contain whitespace. All tokens after the second token are - // part of the name. - string name = token[2]; - for (size_t i = 3; i < token.size(); ++i) - name += ' ' + token[i]; + const bool isAPT1000Code = rowCode > 1000; + if (isAPT1000Code) { + rowCode -= 1000; + } - cache->insertCommStation(ty, name, pos, freqKhz, rangeNm, - currentAirportPosID); + // short int representing tens of kHz, or just kHz directly + int freqKhz = std::stoi(token[1]); + if (isAPT1000Code) { + const int channel = freqKhz % 25; + if (channel != 0 && channel != 5 && channel != 10 && channel != 15) { + SG_LOG(SG_GENERAL, SG_ALERT, + aptDat << ":" << lineNum << ": skipping invalid 8.333 kHz Frequency " << freqKhz << " for " << last_apt_id); + return; + } + } else { + freqKhz *= 10; + const int remainder = freqKhz % 100; + // this is to ensure frequencies such as 126.12 become 126.125 + if (remainder == 20 || remainder == 70) { + freqKhz += 5; + } + + if (freqKhz % 25) { + SG_LOG(SG_GENERAL, SG_ALERT, + aptDat << ":" << lineNum << ": skipping invalid 25 kHz Frequency " << freqKhz << " for " << last_apt_id); + return; + } + } + + if (freqKhz < 118000 || freqKhz >= 137000) { + SG_LOG(SG_GENERAL, SG_ALERT, + aptDat << ":" << lineNum << ": skipping out of range Frequency " << freqKhz << " for " << last_apt_id); + return; + } + + int rangeNm = 50; + FGPositioned::Type ty; + + switch (rowCode) { + 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 whitespace. All tokens after the second token are + // part of the name. + string name = token[2]; + for (size_t i = 3; i < token.size(); ++i) + name += ' ' + token[i]; + + cache->insertCommStation(ty, name, pos, freqKhz, rangeNm, + currentAirportPosID); } // The 'metar.dat' file lists the airports that have METAR available. bool metarDataLoad(const SGPath& metar_file) { - sg_gzifstream metar_in( metar_file ); - 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_gzifstream metar_in(metar_file); + if (!metar_in.is_open()) { + SG_LOG(SG_GENERAL, SG_ALERT, "Cannot open file: " << metar_file); + return false; } - } - return true; + NavDataCache* cache = NavDataCache::instance(); + + string ident; + while (metar_in) { + metar_in >> ident; + if (ident == "#" || ident == "//") { + metar_in >> skipeol; + } else { + cache->setAirportMetar(ident, true); + } + } + + return true; } -} // of namespace flightgear +} // namespace flightgear diff --git a/src/Airports/apt_loader.hxx b/src/Airports/apt_loader.hxx index f789d8580..e6f34fd15 100644 --- a/src/Airports/apt_loader.hxx +++ b/src/Airports/apt_loader.hxx @@ -7,7 +7,6 @@ #pragma once -#include "airport.hxx" #include #include #include @@ -18,18 +17,21 @@ #include #include +#include "airport.hxx" + class NavDataCache; class sg_gzifstream; class FGPavement; + namespace flightgear { class APTLoader { public: APTLoader(); - ~APTLoader(); + virtual ~APTLoader(); // Read the specified apt.dat file into 'airportInfoMap'. // 'bytesReadSoFar' and 'totalSizeOfAllAptDatFiles' are used for progress @@ -43,11 +45,11 @@ public: // Load a specific airport defined in aptdb_file, and return a "rich" view // of the airport including taxiways, pavement and line features. - const FGAirport* loadAirportFromFile(std::string id, const SGPath& aptdb_file); + const FGAirport* loadAirportFromFile(const std::string& id, const SGPath& aptdb_file); private: struct Line { - Line(unsigned int number_, unsigned int rowCode_, std::string str_) + Line(unsigned int number_, unsigned int rowCode_, const std::string& str_) : number(number_), rowCode(rowCode_), str(str_) {} unsigned int number; @@ -78,7 +80,7 @@ private: APTLoader(const APTLoader&); // disable copy constructor APTLoader& operator=(const APTLoader&); // disable copy-assignment operator - const FGAirport* loadAirport(const std::string aptDat, const std::string airportID, RawAirportInfo* airport_info, bool createFGAirport = false); + const FGAirport* loadAirport(const std::string& aptDat, const std::string& airportID, RawAirportInfo* airport_info, bool createFGAirport = false); // Tell whether an apt.dat line is blank or a comment line bool isBlankOrCommentLine(const std::string& line); @@ -111,10 +113,10 @@ private: std::vector token; AirportInfoMapType airportInfoMap; - double rwy_lat_accum; - double rwy_lon_accum; - double last_rwy_heading; - int rwy_count; + double rwy_lat_accum{0.0}; + double rwy_lon_accum{0.0}; + double last_rwy_heading{0.0}; + int rwy_count{0}; std::string last_apt_id; double last_apt_elev; SGGeod tower;