20#include <simgear/compiler.h>
21#include <simgear/constants.h>
22#include <simgear/debug/logstream.hxx>
23#include <simgear/math/SGGeod.hxx>
24#include <simgear/math/SGMathFwd.hxx>
25#include <simgear/math/SGVec3.hxx>
26#include <simgear/misc/strutils.hxx>
27#include <simgear/misc/sg_path.hxx>
28#include <simgear/structure/exception.hxx>
29#include <simgear/io/iostreams/sgstream.hxx>
30#include <simgear/props/props_io.hxx>
31#include <simgear/sg_inlines.h>
46namespace strutils = simgear::strutils;
56 if (inputStream.bad()) {
57 const std::string errMsg = simgear::strutils::error_string(errno);
59 SG_LOG(SG_NAVAID, SG_ALERT,
60 "Error while reading '" << path.utf8Str() <<
"': " << errMsg);
61 throw sg_io_exception(
"Error reading file (" + errMsg +
")",
89 SG_LOG(SG_NAVAID, SG_DEBUG,
"navaid " << ident <<
" has no range set, using defaults");
116static bool isNearby(
const SGGeod& pos1,
const SGGeod& pos2) {
117 double distNm = dist(SGVec3d::fromGeod(pos1),
118 SGVec3d::fromGeod(pos2)) * SG_METER_TO_NM;
123 const std::string&
name,
124 const SGGeod& pos,
int freq)
130 return navaidId != 0;
133 return navRecord->
get_freq() == freq;
142 const string& line,
const string& utf8Path,
unsigned int lineNum,
146 int rowCode, elev_ft, freq, range;
148 double lat, lon, multiuse;
151 string ident,
name, arpt_code;
153 if (simgear::strutils::starts_with(line,
"#")) {
159 if (version < 1100) {
167 vector<string> fields(simgear::strutils::split(line, 0, num_splits));
168 vector<string>::size_type nbFields = fields.size();
169 static const string endOfData =
"99";
173 }
else if (nbFields == 1) {
174 if (fields[0] != endOfData) {
175 SG_LOG( SG_NAVAID, SG_WARN,
176 utf8Path <<
":" << lineNum <<
": malformed line: only one "
177 "field, but it is not '99'" );
181 }
else if (nbFields < 9) {
182 SG_LOG( SG_NAVAID, SG_WARN,
183 utf8Path <<
":" << lineNum <<
": invalid line "
184 "(at least 9 fields are required)" );
192 rowCode = std::stoi(fields[0]);
193 lat = std::stod(fields[1]);
194 lon = std::stod(fields[2]);
195 elev_ft = std::stoi(fields[3]);
196 freq = std::stoi(fields[4]);
197 range = std::stoi(fields[5]);
198 multiuse = std::stod(fields[6]);
200 if (version >= 1100) {
207 if ((rowCode == 2 || rowCode == 3 || rowCode == 12 || rowCode == 13)
208 && fields[8] ==
"ENRT") {
211 name = fields[8] +
" " + fields[10];
218 name = simgear::strutils::simplify(
name);
219 }
catch (
const std::logic_error& exc) {
222 SG_LOG( SG_NAVAID, SG_WARN,
223 utf8Path <<
":" << lineNum <<
": unable to parse (" <<
224 exc.what() <<
"): '" <<
225 simgear::strutils::stripTrailingNewlines(line) <<
"'" );
229 SGGeod pos(SGGeod::fromDegFt(lon, lat,
static_cast<double>(elev_ft)));
236 static std::set<int> ignoredCodes;
237 if (ignoredCodes.insert(rowCode).second) {
238 SG_LOG(SG_NAVAID, SG_WARN,
239 utf8Path <<
":" << lineNum <<
": unrecognized row code "
240 << rowCode <<
", ignoring this line and all further lines "
241 <<
"with the same code");
278 auto loadedNavsKey = std::make_tuple(type, ident,
name);
279 auto matchingNavs = _loadedNavs.equal_range(loadedNavsKey);
280 for (
auto it = matchingNavs.first; it != matchingNavs.second; ++it) {
282 SG_LOG(SG_NAVAID, SG_INFO,
283 utf8Path <<
":" << lineNum <<
": skipping navaid '" <<
284 name <<
"' (already defined nearby)");
288 _loadedNavs.emplace(loadedNavsKey, pos);
291 FGPositioned::TypeFilter dupTypeFilter(type);
297 SG_LOG(SG_NAVAID, SG_INFO,
298 utf8Path <<
":" << lineNum <<
": skipping navaid '" <<
299 name <<
"' (nearby suspected duplicate '" << ref->name() <<
"')");
307 if (!arp.first || !arp.second) {
308 SG_LOG(SG_NAVAID, SG_INFO,
309 utf8Path <<
":" << lineNum <<
": couldn't find matching runway " <<
310 "for marker '" <<
name <<
"', skipping.");
314 if (arp.second && (elev_ft <= 0)) {
318 pos.setElevationFt(runway->geod().getElevationFt());
321 return cache->insertNavaid(type,
string(),
name, pos, 0, 0, 0,
322 arp.first, arp.second);
339 if (
name.find(
"VOR-DME") != std::string::npos ) {
341 }
else if (
name.find(
"DME-ILS") != std::string::npos ) {
344 }
else if (
name.find(
"VORTAC") != std::string::npos ) {
346 }
else if (
name.find(
"NDB-DME") != std::string::npos ) {
350 if (f.maxType() > 0) {
354 string_list navaid_part = simgear::strutils::split(ref.get()->name(), 0 ,1);
356 if ( simgear::strutils::uppercase(navaid_part[0]) == simgear::strutils::uppercase(dme_part[0]) ) {
357 navaid_dme = ref.get()->guid();
359 SG_LOG(SG_NAVAID, SG_INFO,
360 utf8Path <<
":" << lineNum <<
": DME '" << ident <<
"' (" <<
361 name <<
"): while looking for a colocated navaid, found " <<
362 "that the closest match has wrong name: '" <<
363 ref->ident() <<
"' (" << ref->name() <<
")");
366 SG_LOG(SG_NAVAID, SG_INFO,
367 utf8Path <<
":" << lineNum <<
": couldn't find any colocated "
368 "navaid for DME '" << ident <<
"' (" <<
name <<
")");
374 arp = cache->findAirportRunway(
name);
375 if (!arp.first || !arp.second) {
376 SG_LOG(SG_NAVAID, SG_INFO,
377 utf8Path <<
":" << lineNum <<
": couldn't find matching runway " <<
378 "for ILS/LOC/GS navaid '" <<
name <<
"', ignoring it.");
389 pos.setElevationFt(runway->geod().getElevationFt());
397 multiuse, arp.first, arp.second);
400 cache->setRunwayILS(arp.second, r);
404 cache->setNavaidColocated(navaid_dme, r);
412 std::size_t bytesReadSoFar,
413 std::size_t totalSizeOfAllDatFiles)
416 const SGPath path = sceneryLocation.
datPath;
417 const string utf8Path = path.utf8Str();
418 sg_gzifstream in(path);
420 if ( !in.is_open() ) {
421 throw sg_io_exception(
422 "Cannot open file (" + simgear::strutils::error_string(errno) +
")",
429 for (
int i = 0;
i < 2;
i++) {
430 std::getline(in, line);
434 unsigned int lineNumber;
435 unsigned int version;
436 vector<string> fields(simgear::strutils::split(line, 0, 1));
439 if (fields.empty()) {
440 throw sg_format_exception();
442 version = strutils::readNonNegativeInt<unsigned int>(fields[0]);
443 }
catch (
const sg_exception& exc) {
444 std::string strippedLine = simgear::strutils::stripTrailingNewlines(line);
445 std::string errMsg = utf8Path +
": ";
447 if (fields.empty()) {
448 errMsg +=
"unable to parse format version: empty line";
449 SG_LOG(SG_NAVAID, SG_ALERT, errMsg);
451 errMsg +=
"unable to parse format version";
452 SG_LOG(SG_NAVAID, SG_ALERT,
453 errMsg <<
" (" << exc.what() <<
"): " << strippedLine);
456 throw sg_format_exception(errMsg, strippedLine);
459 SG_LOG(SG_NAVAID, SG_INFO,
460 "nav.dat format version (" << utf8Path <<
"): " << version);
462 for (lineNumber = 3; std::getline(in, line); lineNumber++) {
465 if ((lineNumber % 100) == 0) {
467 unsigned int percent = ((bytesReadSoFar + in.approxOffset()) * 100)
468 / totalSizeOfAllDatFiles;
479 SG_LOG( SG_NAVAID, SG_DEBUG,
"Opening file: " << path );
480 const string utf8Path = path.utf8Str();
481 sg_gzifstream in(path);
483 if ( !in.is_open() ) {
484 throw sg_io_exception(
485 "Cannot open file (" + simgear::strutils::error_string(errno) +
")",
490 unsigned int lineNumber;
492 for (lineNumber = 1; std::getline(in, line); lineNumber++) {
502 SG_LOG( SG_NAVAID, SG_DEBUG,
"opening file: " << path );
503 sg_gzifstream inchannel( path );
505 if ( !inchannel.is_open() ) {
506 SG_LOG( SG_NAVAID, SG_ALERT,
"Cannot open file: " << path );
511 inchannel >> skipeol;
512 while ( ! inchannel.eof() ) {
515 channellist->
add ( r );
SGSharedPtr< FGRunway > FGRunwayRef
static FGPositionedRef findClosestWithIdent(const std::string &aIdent, const SGGeod &aPos, Filter *aFilter=NULL)
static SGSharedPtr< T > loadById(PositionedID id)
@ DME
important that DME & TACAN are adjacent to keep the TacanFilter efficient - DMEs are proxies for TACA...
bool add(FGTACANRecord *r)
PositionedID findNavaidForRunway(PositionedID runway, FGPositioned::Type ty)
Given a runway and type, find the corresponding navaid (ILS / GS / OM)
static NavDataCache * instance()
void setRebuildPhaseProgress(RebuildPhase ph, unsigned int percent=0)
AirportRunwayPair findAirportRunway(const std::string &name)
given a navaid name (or similar) from apt.dat / nav.dat, find the corresponding airport and runway ID...
bool loadTacan(const SGPath &path, FGTACANList *channellist)
void loadNav(const NavDataCache::SceneryLocation &sceneryLocation, std::size_t bytesReadSoFar, std::size_t totalSizeOfAllDatFiles)
void loadCarrierNav(const SGPath &path)
static const double DUPLICATE_DETECTION_RADIUS_NM
std::vector< std::string > string_list
FlightPlan.hxx - defines a full flight-plan object, including departure, cruise, arrival information ...
static bool canBeDuplicate(FGPositionedRef ref, FGPositioned::Type type, const std::string &name, const SGGeod &pos, int freq)
SGSharedPtr< FGPositioned > FGPositionedRef
static const double DUPLICATE_DETECTION_RADIUS_NM
static bool isNearby(const SGGeod &pos1, const SGGeod &pos2)
std::pair< PositionedID, PositionedID > AirportRunwayPair
a pair of airport ID, runway ID
static FGPositioned::Type mapRobinTypeToFGPType(int aTy)
static void throwExceptionIfStreamError(const std::istream &inputStream, const SGPath &path)
static double defaultNavRange(const string &ident, FGPositioned::Type type)
const double FG_TACAN_DEFAULT_RANGE
const double FG_DME_DEFAULT_RANGE
const double FG_NAV_DEFAULT_RANGE
const double FG_LOC_DEFAULT_RANGE