NavData: don't load XML extension files from unsuitable scenery paths
Add a 'scenery_path' field to the 'airport' table of the SQLite NavDataCache database. For each airport, this field indicates the scenery realpath() that contributed the apt.dat file for the airport (as an exception, for airports whose apt.dat file is $FG_ROOT/Airports/apt.dat.gz, the path thus stored is for now $FG_ROOT, which is technically not a scenery path). This path is then made available via FGAirport::sceneryPath(), which allows us to implement the following change (in this commit): A) The lookup of *.procedures.xml is unchanged. B) For other XML extension files (groundnet, ils, runway_rename, threshold, twr): - The search performed by XMLLoader::findAirportData() through globals->get_fg_scenery() stops immediately after the scenery path p that contributed the apt.dat file for the airport. - Paths that come earlier than p in globals->get_fg_scenery() order may contain XML extension files that will *override* sibling files that might exist in p (as was already the case before this commit). The rationale behind this change is that we don't want a custom scenery with good data in its NavData folder regarding airport FOO to get "ruined" by files such as FOO.threshold.xml present in the TerraSync directory---which is assumed to come later in globals->get_fg_scenery() order. *.procedures.xml files are excluded from the change because there is a widespread use of a huge set of procedure files for the whole world; if airport FOO in a custom scenery has no procedure files, we do want to let FlightGear find FOO.procedures.xml inside the scenery path containing the huge dataset (which should come *after* custom sceneries in globals->get_fg_scenery() order so as to give these custom sceneries the option to provide better *.procedures.xml files and have them take precedence over less specialized sources such as the huge dataset). Reference discussion: https://sourceforge.net/p/flightgear/mailman/flightgear-devel/thread/CAKor_THrQCiS1ES_ENSrmn1j3s39dX0qQXSbYBUz6yuokse_pQ%40mail.gmail.com/#msg37860751
This commit is contained in:
parent
a207cdd207
commit
351ca111ad
14 changed files with 134 additions and 60 deletions
|
@ -73,7 +73,8 @@ osgDB::ReaderWriter::ReadResult AirportBuilder::readNode(const std::string& file
|
||||||
const std::string airportId = aptFile.file_base();
|
const std::string airportId = aptFile.file_base();
|
||||||
APTLoader aptLoader;
|
APTLoader aptLoader;
|
||||||
|
|
||||||
const FGAirport* airport = aptLoader.loadAirportFromFile(airportId, aptFile);
|
const FGAirport* airport = aptLoader.loadAirportFromFile(
|
||||||
|
airportId, {aptFile, SGPath()}); // maybe provide a path if this is used
|
||||||
if (! airport) return ReadResult::FILE_NOT_HANDLED;
|
if (! airport) return ReadResult::FILE_NOT_HANDLED;
|
||||||
|
|
||||||
SG_LOG( SG_TERRAIN, SG_DEBUG, "Building airport : " << airportId << " " << airport->getName());
|
SG_LOG( SG_TERRAIN, SG_DEBUG, "Building airport : " << airportId << " " << airport->getName());
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include <simgear/debug/ErrorReportingCallback.hxx>
|
#include <simgear/debug/ErrorReportingCallback.hxx>
|
||||||
#include <simgear/debug/logstream.hxx>
|
#include <simgear/debug/logstream.hxx>
|
||||||
|
@ -54,10 +55,12 @@ FGAirport::FGAirport( PositionedID aGuid,
|
||||||
const SGGeod& location,
|
const SGGeod& location,
|
||||||
const std::string &name,
|
const std::string &name,
|
||||||
bool has_metar,
|
bool has_metar,
|
||||||
Type aType ):
|
Type aType,
|
||||||
|
SGPath sceneryPath):
|
||||||
FGPositioned(aGuid, aType, id, location),
|
FGPositioned(aGuid, aType, id, location),
|
||||||
_name(name),
|
_name(name),
|
||||||
_has_metar(has_metar),
|
_has_metar(has_metar),
|
||||||
|
_sceneryPath(std::move(sceneryPath)),
|
||||||
mTowerDataLoaded(false),
|
mTowerDataLoaded(false),
|
||||||
mHasTower(false),
|
mHasTower(false),
|
||||||
mRunwaysLoaded(false),
|
mRunwaysLoaded(false),
|
||||||
|
@ -90,6 +93,11 @@ bool FGAirport::isHeliport() const
|
||||||
return type() == HELIPORT;
|
return type() == HELIPORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SGPath FGAirport::sceneryPath() const
|
||||||
|
{
|
||||||
|
return _sceneryPath;
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
unsigned int FGAirport::numRunways() const
|
unsigned int FGAirport::numRunways() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <simgear/compiler.h>
|
#include <simgear/compiler.h>
|
||||||
|
#include <simgear/misc/sg_path.hxx>
|
||||||
|
|
||||||
#include <Navaids/positioned.hxx>
|
#include <Navaids/positioned.hxx>
|
||||||
#include <Navaids/procedure.hxx>
|
#include <Navaids/procedure.hxx>
|
||||||
|
@ -30,8 +31,15 @@ class FGGroundNetwork;
|
||||||
class FGAirport : public FGPositioned
|
class FGAirport : public FGPositioned
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
// 'sceneryPath' is the scenery path that provided the apt.dat file for
|
||||||
|
// the airport (except for the “default dat file” under $FG_ROOT and the
|
||||||
|
// null SGPath special case, 'sceneryPath' should be an element of
|
||||||
|
// globals->get_fg_scenery()). Knowing this allows one to stop looking for
|
||||||
|
// files such as ils.xml or threshold.xml in scenery paths that come later
|
||||||
|
// in globals->get_fg_scenery() order (cf. XMLLoader::findAirportData()).
|
||||||
FGAirport(PositionedID aGuid, const std::string& id, const SGGeod& location,
|
FGAirport(PositionedID aGuid, const std::string& id, const SGGeod& location,
|
||||||
const std::string& name, bool has_metar, Type aType);
|
const std::string& name, bool has_metar, Type aType,
|
||||||
|
SGPath sceneryPath = SGPath());
|
||||||
~FGAirport();
|
~FGAirport();
|
||||||
|
|
||||||
static bool isType(FGPositioned::Type ty)
|
static bool isType(FGPositioned::Type ty)
|
||||||
|
@ -39,6 +47,9 @@ public:
|
||||||
return (ty >= FGPositioned::AIRPORT) && (ty <= FGPositioned::SEAPORT);
|
return (ty >= FGPositioned::AIRPORT) && (ty <= FGPositioned::SEAPORT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return the realpath() of the scenery folder under which we found the
|
||||||
|
// apt.dat file for this airport.
|
||||||
|
SGPath sceneryPath() const;
|
||||||
const std::string& getId() const { return ident(); }
|
const std::string& getId() const { return ident(); }
|
||||||
const std::string& getName() const { return _name; }
|
const std::string& getName() const { return _name; }
|
||||||
std::string toString() const { return "an airport " + ident(); }
|
std::string toString() const { return "an airport " + ident(); }
|
||||||
|
@ -350,6 +361,7 @@ private:
|
||||||
|
|
||||||
std::string _name;
|
std::string _name;
|
||||||
bool _has_metar = false;
|
bool _has_metar = false;
|
||||||
|
const SGPath _sceneryPath;
|
||||||
|
|
||||||
void loadRunways() const;
|
void loadRunways() const;
|
||||||
void loadHelipads() const;
|
void loadHelipads() const;
|
||||||
|
|
|
@ -68,10 +68,11 @@ APTLoader::APTLoader()
|
||||||
|
|
||||||
APTLoader::~APTLoader() {}
|
APTLoader::~APTLoader() {}
|
||||||
|
|
||||||
void APTLoader::readAptDatFile(const SGPath& aptdb_file,
|
void APTLoader::readAptDatFile(const NavDataCache::SceneryLocation& sceneryLocation,
|
||||||
std::size_t bytesReadSoFar,
|
std::size_t bytesReadSoFar,
|
||||||
std::size_t totalSizeOfAllAptDatFiles)
|
std::size_t totalSizeOfAllAptDatFiles)
|
||||||
{
|
{
|
||||||
|
const SGPath aptdb_file = sceneryLocation.datPath;
|
||||||
string apt_dat = aptdb_file.utf8Str(); // full path to the file being parsed
|
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);
|
sg_gzifstream in(aptdb_file, std::ios_base::in | std::ios_base::binary, true);
|
||||||
|
|
||||||
|
@ -175,6 +176,7 @@ void APTLoader::readAptDatFile(const SGPath& aptdb_file,
|
||||||
// We haven't seen this airport yet in any apt.dat file
|
// We haven't seen this airport yet in any apt.dat file
|
||||||
RawAirportInfo& airportInfo = insertRetval.first->second;
|
RawAirportInfo& airportInfo = insertRetval.first->second;
|
||||||
airportInfo.file = aptdb_file;
|
airportInfo.file = aptdb_file;
|
||||||
|
airportInfo.sceneryPath = sceneryLocation.sceneryPath;
|
||||||
airportInfo.rowCode = rowCode;
|
airportInfo.rowCode = rowCode;
|
||||||
airportInfo.firstLineNum = line_num;
|
airportInfo.firstLineNum = line_num;
|
||||||
airportInfo.firstLineTokens = std::move(tokens);
|
airportInfo.firstLineTokens = std::move(tokens);
|
||||||
|
@ -203,7 +205,7 @@ void APTLoader::loadAirports()
|
||||||
for (AirportInfoMapType::const_iterator it = airportInfoMap.begin();
|
for (AirportInfoMapType::const_iterator it = airportInfoMap.begin();
|
||||||
it != airportInfoMap.end(); ++it) {
|
it != airportInfoMap.end(); ++it) {
|
||||||
// Full path to the apt.dat file this airport info comes from
|
// Full path to the apt.dat file this airport info comes from
|
||||||
const string aptDat = it->second.file.utf8Str();
|
const SGPath aptDat = it->second.file;
|
||||||
|
|
||||||
// this is just the current airport identifier
|
// this is just the current airport identifier
|
||||||
last_apt_id = it->first;
|
last_apt_id = it->first;
|
||||||
|
@ -225,15 +227,15 @@ void APTLoader::loadAirports()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse and return specific apt.dat file containing a single airport.
|
// Parse and return specific apt.dat file containing a single airport.
|
||||||
const FGAirport* APTLoader::loadAirportFromFile(const std::string& id, const SGPath& aptdb_file)
|
const FGAirport* APTLoader::loadAirportFromFile(const std::string& id, const NavDataCache::SceneryLocation& sceneryLocation)
|
||||||
{
|
{
|
||||||
std::size_t bytesReadSoFar = 10;
|
std::size_t bytesReadSoFar = 10;
|
||||||
std::size_t totalSizeOfAllAptDatFiles = 100;
|
std::size_t totalSizeOfAllAptDatFiles = 100;
|
||||||
|
|
||||||
readAptDatFile(aptdb_file.str(), bytesReadSoFar, totalSizeOfAllAptDatFiles);
|
readAptDatFile(sceneryLocation, bytesReadSoFar, totalSizeOfAllAptDatFiles);
|
||||||
|
|
||||||
RawAirportInfo rawInfo = airportInfoMap[id];
|
RawAirportInfo rawInfo = airportInfoMap[id];
|
||||||
return loadAirport(aptdb_file.c_str(), id, &rawInfo, true);
|
return loadAirport(sceneryLocation.datPath, id, &rawInfo, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isCommLine(const int code)
|
static bool isCommLine(const int code)
|
||||||
|
@ -241,13 +243,15 @@ static bool isCommLine(const int code)
|
||||||
return ((code >= 50) && (code <= 56)) || ((code >= 1050) && (code <= 1056));
|
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 SGPath& aptDatFile, const std::string& airportID, RawAirportInfo* airport_info, bool createFGAirport)
|
||||||
{
|
{
|
||||||
// The first line for this airport was already split over whitespace, but
|
// The first line for this airport was already split over whitespace, but
|
||||||
// remains to be parsed for the most part.
|
// remains to be parsed for the most part.
|
||||||
parseAirportLine(airport_info->rowCode, airport_info->firstLineTokens);
|
parseAirportLine(airport_info->rowCode, airport_info->firstLineTokens,
|
||||||
|
airport_info->sceneryPath);
|
||||||
const LinesList& lines = airport_info->otherLines;
|
const LinesList& lines = airport_info->otherLines;
|
||||||
|
|
||||||
|
const string aptDat = aptDatFile.utf8Str();
|
||||||
NodeBlock current_block = None;
|
NodeBlock current_block = None;
|
||||||
|
|
||||||
// Loop over the second and subsequent lines
|
// Loop over the second and subsequent lines
|
||||||
|
@ -422,7 +426,8 @@ void APTLoader::finishAirport(const string& aptDat)
|
||||||
// 'rowCode' is passed to avoid decoding it twice, since that work was already
|
// 'rowCode' is passed to avoid decoding it twice, since that work was already
|
||||||
// done in order to detect the start of the new airport.
|
// done in order to detect the start of the new airport.
|
||||||
void APTLoader::parseAirportLine(unsigned int rowCode,
|
void APTLoader::parseAirportLine(unsigned int rowCode,
|
||||||
const vector<string>& token)
|
const vector<string>& token,
|
||||||
|
const SGPath& sceneryPath)
|
||||||
{
|
{
|
||||||
// The algorithm in APTLoader::readAptDatFile() ensures this is at least 5.
|
// The algorithm in APTLoader::readAptDatFile() ensures this is at least 5.
|
||||||
vector<string>::size_type lastIndex = token.size() - 1;
|
vector<string>::size_type lastIndex = token.size() - 1;
|
||||||
|
@ -443,7 +448,7 @@ void APTLoader::parseAirportLine(unsigned int rowCode,
|
||||||
rwy_count = 0;
|
rwy_count = 0;
|
||||||
|
|
||||||
currentAirportPosID = cache->insertAirport(fptypeFromRobinType(rowCode),
|
currentAirportPosID = cache->insertAirport(fptypeFromRobinType(rowCode),
|
||||||
id, name);
|
id, name, sceneryPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
void APTLoader::parseRunwayLine810(const string& aptDat, unsigned int lineNum,
|
void APTLoader::parseRunwayLine810(const string& aptDat, unsigned int lineNum,
|
||||||
|
|
|
@ -9,9 +9,11 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <Navaids/positioned.hxx>
|
#include <Navaids/positioned.hxx>
|
||||||
|
#include <Navaids/NavDataCache.hxx>
|
||||||
#include <simgear/compiler.h>
|
#include <simgear/compiler.h>
|
||||||
#include <simgear/math/SGGeod.hxx>
|
#include <simgear/math/SGGeod.hxx>
|
||||||
#include <simgear/misc/sg_path.hxx>
|
#include <simgear/misc/sg_path.hxx>
|
||||||
|
@ -20,7 +22,6 @@
|
||||||
#include "airport.hxx"
|
#include "airport.hxx"
|
||||||
|
|
||||||
|
|
||||||
class NavDataCache;
|
|
||||||
class sg_gzifstream;
|
class sg_gzifstream;
|
||||||
class FGPavement;
|
class FGPavement;
|
||||||
|
|
||||||
|
@ -36,7 +37,8 @@ public:
|
||||||
// Read the specified apt.dat file into 'airportInfoMap'.
|
// Read the specified apt.dat file into 'airportInfoMap'.
|
||||||
// 'bytesReadSoFar' and 'totalSizeOfAllAptDatFiles' are used for progress
|
// 'bytesReadSoFar' and 'totalSizeOfAllAptDatFiles' are used for progress
|
||||||
// information.
|
// information.
|
||||||
void readAptDatFile(const SGPath& aptdb_file, std::size_t bytesReadSoFar,
|
void readAptDatFile(const NavDataCache::SceneryLocation& sceneryLocation,
|
||||||
|
std::size_t bytesReadSoFar,
|
||||||
std::size_t totalSizeOfAllAptDatFiles);
|
std::size_t totalSizeOfAllAptDatFiles);
|
||||||
// Read all airports gathered in 'airportInfoMap' and load them into the
|
// Read all airports gathered in 'airportInfoMap' and load them into the
|
||||||
// navdata cache (even in case of overlapping apt.dat files,
|
// navdata cache (even in case of overlapping apt.dat files,
|
||||||
|
@ -45,7 +47,7 @@ public:
|
||||||
|
|
||||||
// Load a specific airport defined in aptdb_file, and return a "rich" view
|
// Load a specific airport defined in aptdb_file, and return a "rich" view
|
||||||
// of the airport including taxiways, pavement and line features.
|
// of the airport including taxiways, pavement and line features.
|
||||||
const FGAirport* loadAirportFromFile(const std::string& id, const SGPath& aptdb_file);
|
const FGAirport* loadAirportFromFile(const std::string& id, const NavDataCache::SceneryLocation& sceneryLocation);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Line {
|
struct Line {
|
||||||
|
@ -62,6 +64,8 @@ private:
|
||||||
struct RawAirportInfo {
|
struct RawAirportInfo {
|
||||||
// apt.dat file where the airport was defined
|
// apt.dat file where the airport was defined
|
||||||
SGPath file;
|
SGPath file;
|
||||||
|
// Base path of the corresponding scenery
|
||||||
|
SGPath sceneryPath;
|
||||||
// Row code for the airport (1, 16 or 17)
|
// Row code for the airport (1, 16 or 17)
|
||||||
unsigned int rowCode;
|
unsigned int rowCode;
|
||||||
// Line number in the apt.dat file where the airport definition starts
|
// Line number in the apt.dat file where the airport definition starts
|
||||||
|
@ -80,7 +84,7 @@ private:
|
||||||
APTLoader(const APTLoader&); // disable copy constructor
|
APTLoader(const APTLoader&); // disable copy constructor
|
||||||
APTLoader& operator=(const APTLoader&); // disable copy-assignment operator
|
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 SGPath& aptDat, const std::string& airportID, RawAirportInfo* airport_info, bool createFGAirport = false);
|
||||||
|
|
||||||
// Tell whether an apt.dat line is blank or a comment line
|
// Tell whether an apt.dat line is blank or a comment line
|
||||||
bool isBlankOrCommentLine(const std::string& line);
|
bool isBlankOrCommentLine(const std::string& line);
|
||||||
|
@ -89,7 +93,8 @@ private:
|
||||||
void throwExceptionIfStreamError(const sg_gzifstream& input_stream,
|
void throwExceptionIfStreamError(const sg_gzifstream& input_stream,
|
||||||
const SGPath& path);
|
const SGPath& path);
|
||||||
void parseAirportLine(unsigned int rowCode,
|
void parseAirportLine(unsigned int rowCode,
|
||||||
const std::vector<std::string>& token);
|
const std::vector<std::string>& token,
|
||||||
|
const SGPath& sceneryPath);
|
||||||
void finishAirport(const std::string& aptDat);
|
void finishAirport(const std::string& aptDat);
|
||||||
void parseRunwayLine810(const std::string& aptDat, unsigned int lineNum,
|
void parseRunwayLine810(const std::string& aptDat, unsigned int lineNum,
|
||||||
const std::vector<std::string>& token);
|
const std::vector<std::string>& token);
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include <simgear/misc/sg_path.hxx>
|
#include <simgear/misc/sg_path.hxx>
|
||||||
#include <simgear/xml/easyxml.hxx>
|
#include <simgear/xml/easyxml.hxx>
|
||||||
|
@ -105,11 +106,19 @@ void XMLLoader::load(FGRunwayPreference* p) {
|
||||||
bool XMLLoader::findAirportData(const std::string& aICAO,
|
bool XMLLoader::findAirportData(const std::string& aICAO,
|
||||||
const std::string& aFileName, SGPath& aPath)
|
const std::string& aFileName, SGPath& aPath)
|
||||||
{
|
{
|
||||||
|
FGAirportRef airport = FGAirport::findByIdent(aICAO);
|
||||||
|
if (!airport) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
string fileName(aFileName);
|
string fileName(aFileName);
|
||||||
if (!simgear::strutils::ends_with(aFileName, ".xml")) {
|
if (!simgear::strutils::ends_with(aFileName, ".xml")) {
|
||||||
fileName.append(".xml");
|
fileName.append(".xml");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bool performFullTraversal = airport->sceneryPath().isNull() ||
|
||||||
|
!fileName.compare("procedures.xml");
|
||||||
|
|
||||||
PathList sc = globals->get_fg_scenery();
|
PathList sc = globals->get_fg_scenery();
|
||||||
char buffer[128];
|
char buffer[128];
|
||||||
::snprintf(buffer, 128, "%c/%c/%c/%s.%s",
|
::snprintf(buffer, 128, "%c/%c/%c/%s.%s",
|
||||||
|
@ -119,13 +128,18 @@ bool XMLLoader::findAirportData(const std::string& aICAO,
|
||||||
for (PathList::const_iterator it = sc.begin(); it != sc.end(); ++it) {
|
for (PathList::const_iterator it = sc.begin(); it != sc.end(); ++it) {
|
||||||
// fg_senery contains empty strings as "markers" (see FGGlobals::set_fg_scenery)
|
// fg_senery contains empty strings as "markers" (see FGGlobals::set_fg_scenery)
|
||||||
if (!it->isNull()) {
|
if (!it->isNull()) {
|
||||||
SGPath path(*it);
|
const SGPath path = *it / "Airports" / buffer;
|
||||||
path.append("Airports");
|
|
||||||
path.append(string(buffer));
|
|
||||||
if (path.exists()) {
|
if (path.exists()) {
|
||||||
aPath = path;
|
aPath = std::move(path);
|
||||||
return true;
|
return true;
|
||||||
} // of path exists
|
} // of path exists
|
||||||
|
|
||||||
|
// Unless we are in “full traversal mode”, don't look in scenery paths
|
||||||
|
// that come after the one which contributed the apt.dat file for the
|
||||||
|
// airport.
|
||||||
|
if (!performFullTraversal && *it == airport->sceneryPath()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} // of scenery path iteration
|
} // of scenery path iteration
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -3110,7 +3110,15 @@ void Options::printJSONReport() const
|
||||||
// For this method, it doesn't matter if the cache is out-of-date
|
// For this method, it doesn't matter if the cache is out-of-date
|
||||||
const NavDataCache::DatFilesGroupInfo& datFilesInfo =
|
const NavDataCache::DatFilesGroupInfo& datFilesInfo =
|
||||||
cache->getDatFilesInfo(datType);
|
cache->getDatFilesInfo(datType);
|
||||||
cJSON *datPathsNode = p->createJSONArrayFromPathList(datFilesInfo.paths);
|
|
||||||
|
// Create a list of SGPath instances (for the .dat files) from the list of
|
||||||
|
// NavDataCache::SceneryLocation structs that datFilesInfo.paths is.
|
||||||
|
PathList datFiles(datFilesInfo.paths.size());
|
||||||
|
const auto map = [](const auto& e) { return e.datPath; };
|
||||||
|
std::transform(std::cbegin(datFilesInfo.paths),
|
||||||
|
std::cend(datFilesInfo.paths), std::begin(datFiles), map);
|
||||||
|
|
||||||
|
cJSON *datPathsNode = p->createJSONArrayFromPathList(datFiles);
|
||||||
string key = NavDataCache::datTypeStr[datType] + ".dat files";
|
string key = NavDataCache::datTypeStr[datType] + ".dat files";
|
||||||
cJSON_AddItemToObject(navDataNode, key.c_str(), datPathsNode);
|
cJSON_AddItemToObject(navDataNode, key.c_str(), datPathsNode);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
const int SCHEMA_VERSION = 21;
|
const int SCHEMA_VERSION = 22;
|
||||||
|
|
||||||
#define SCHEMA_SQL \
|
#define SCHEMA_SQL \
|
||||||
"CREATE TABLE properties (key VARCHAR, value VARCHAR);" \
|
"CREATE TABLE properties (key VARCHAR, value VARCHAR);" \
|
||||||
|
@ -15,7 +15,7 @@ const int SCHEMA_VERSION = 21;
|
||||||
"CREATE INDEX pos_name ON positioned(name collate nocase);" \
|
"CREATE INDEX pos_name ON positioned(name collate nocase);" \
|
||||||
"CREATE INDEX pos_apt_type ON positioned(airport, type);" \
|
"CREATE INDEX pos_apt_type ON positioned(airport, type);" \
|
||||||
\
|
\
|
||||||
"CREATE TABLE airport (has_metar BOOL);" \
|
"CREATE TABLE airport (scenery_path VARCHAR, has_metar BOOL);" \
|
||||||
"CREATE TABLE comm (freq_khz INT,range_nm INT);" \
|
"CREATE TABLE comm (freq_khz INT,range_nm INT);" \
|
||||||
"CREATE INDEX comm_freq ON comm(freq_khz);" \
|
"CREATE INDEX comm_freq ON comm(freq_khz);" \
|
||||||
\
|
\
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include <stdint.h> // for int64_t
|
#include <stdint.h> // for int64_t
|
||||||
#include <sstream> // for std::ostringstream
|
#include <sstream> // for std::ostringstream
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#ifdef SYSTEM_SQLITE
|
#ifdef SYSTEM_SQLITE
|
||||||
// the standard sqlite3.h doesn't give a way to set SQLITE_UINT64_TYPE,
|
// the standard sqlite3.h doesn't give a way to set SQLITE_UINT64_TYPE,
|
||||||
|
@ -563,7 +564,7 @@ public:
|
||||||
"(path, stamp, sha) VALUES (?,?, ?)");
|
"(path, stamp, sha) VALUES (?,?, ?)");
|
||||||
|
|
||||||
loadPositioned = prepare("SELECT " POSITIONED_COLS " FROM positioned WHERE rowid=?");
|
loadPositioned = prepare("SELECT " POSITIONED_COLS " FROM positioned WHERE rowid=?");
|
||||||
loadAirportStmt = prepare("SELECT has_metar FROM airport WHERE rowid=?");
|
loadAirportStmt = prepare("SELECT scenery_path, has_metar FROM airport WHERE rowid=?");
|
||||||
loadNavaid = prepare("SELECT range_nm, freq, multiuse, runway, colocated FROM navaid WHERE rowid=?");
|
loadNavaid = prepare("SELECT range_nm, freq, multiuse, runway, colocated FROM navaid WHERE rowid=?");
|
||||||
loadCommStation = prepare("SELECT freq_khz, range_nm FROM comm WHERE rowid=?");
|
loadCommStation = prepare("SELECT freq_khz, range_nm FROM comm WHERE rowid=?");
|
||||||
loadRunwayStmt = prepare("SELECT heading, length_ft, width_m, surface, displaced_threshold,"
|
loadRunwayStmt = prepare("SELECT heading, length_ft, width_m, surface, displaced_threshold,"
|
||||||
|
@ -588,7 +589,7 @@ public:
|
||||||
|
|
||||||
setAirportPos = prepare("UPDATE positioned SET lon=?2, lat=?3, elev_m=?4, octree_node=?5, "
|
setAirportPos = prepare("UPDATE positioned SET lon=?2, lat=?3, elev_m=?4, octree_node=?5, "
|
||||||
"cart_x=?6, cart_y=?7, cart_z=?8 WHERE rowid=?1");
|
"cart_x=?6, cart_y=?7, cart_z=?8 WHERE rowid=?1");
|
||||||
insertAirport = prepare("INSERT INTO airport (rowid, has_metar) VALUES (?, ?)");
|
insertAirport = prepare("INSERT INTO airport (rowid, scenery_path, has_metar) VALUES (?, ?, ?)");
|
||||||
insertNavaid = prepare("INSERT INTO navaid (rowid, freq, range_nm, multiuse, runway, colocated)"
|
insertNavaid = prepare("INSERT INTO navaid (rowid, freq, range_nm, multiuse, runway, colocated)"
|
||||||
" VALUES (?1, ?2, ?3, ?4, ?5, ?6)");
|
" VALUES (?1, ?2, ?3, ?4, ?5, ?6)");
|
||||||
|
|
||||||
|
@ -704,10 +705,12 @@ public:
|
||||||
{
|
{
|
||||||
sqlite3_bind_int64(loadAirportStmt, 1, rowId);
|
sqlite3_bind_int64(loadAirportStmt, 1, rowId);
|
||||||
execSelect1(loadAirportStmt);
|
execSelect1(loadAirportStmt);
|
||||||
bool hasMetar = (sqlite3_column_int(loadAirportStmt, 0) > 0);
|
SGPath sceneryPath{(char *) sqlite3_column_text(loadAirportStmt, 0)};
|
||||||
|
bool hasMetar = (sqlite3_column_int(loadAirportStmt, 1) > 0);
|
||||||
reset(loadAirportStmt);
|
reset(loadAirportStmt);
|
||||||
|
|
||||||
return new FGAirport(rowId, id, pos, name, hasMetar, ty);
|
return new FGAirport(rowId, id, pos, name, hasMetar, ty,
|
||||||
|
std::move(sceneryPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
FGRunwayBase* loadRunway(sqlite3_int64 rowId, FGPositioned::Type ty,
|
FGRunwayBase* loadRunway(sqlite3_int64 rowId, FGPositioned::Type ty,
|
||||||
|
@ -1156,7 +1159,7 @@ void NavDataCache::NavDataCachePrivate::findDatFiles(
|
||||||
const std::string name = f.file();
|
const std::string name = f.file();
|
||||||
if (simgear::strutils::ends_with(name, ".dat") ||
|
if (simgear::strutils::ends_with(name, ".dat") ||
|
||||||
simgear::strutils::ends_with(name, ".dat.gz")) {
|
simgear::strutils::ends_with(name, ".dat.gz")) {
|
||||||
result.paths.push_back(f);
|
result.paths.push_back({f, path});
|
||||||
result.totalSize += f.sizeInBytes();
|
result.totalSize += f.sizeInBytes();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1167,9 +1170,9 @@ void NavDataCache::NavDataCachePrivate::findDatFiles(
|
||||||
// now
|
// now
|
||||||
SGPath defaultDatFile(globals->get_fg_root());
|
SGPath defaultDatFile(globals->get_fg_root());
|
||||||
defaultDatFile.append(NavDataCache::defaultDatFile[datFileType]);
|
defaultDatFile.append(NavDataCache::defaultDatFile[datFileType]);
|
||||||
if ((result.paths.empty() || result.paths.back() != defaultDatFile) &&
|
if ((result.paths.empty() || result.paths.back().datPath != defaultDatFile) &&
|
||||||
defaultDatFile.isFile()) {
|
defaultDatFile.isFile()) {
|
||||||
result.paths.push_back(defaultDatFile);
|
result.paths.push_back({defaultDatFile, globals->get_fg_root()});
|
||||||
result.totalSize += defaultDatFile.sizeInBytes();
|
result.totalSize += defaultDatFile.sizeInBytes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1195,8 +1198,8 @@ bool NavDataCache::NavDataCachePrivate::areDatFilesModified(
|
||||||
NavDataCache::datTypeStr[datFileType];
|
NavDataCache::datTypeStr[datFileType];
|
||||||
const string_list cachedFiles = outer->readOrderedStringListProperty(
|
const string_list cachedFiles = outer->readOrderedStringListProperty(
|
||||||
datTypeStr + ".dat files", SGPath::pathListSep);
|
datTypeStr + ".dat files", SGPath::pathListSep);
|
||||||
const PathList& datFiles = datFilesGroupInfo.paths;
|
const auto& datFiles = datFilesGroupInfo.paths;
|
||||||
PathList::const_iterator datFilesIt = datFiles.begin();
|
auto datFilesIt = datFiles.cbegin();
|
||||||
string_list::const_iterator cachedFilesIt = cachedFiles.begin();
|
string_list::const_iterator cachedFilesIt = cachedFiles.begin();
|
||||||
// Same logic as in NavDataCachePrivate::isCachedFileModified()
|
// Same logic as in NavDataCachePrivate::isCachedFileModified()
|
||||||
sgDebugPriority logLevel = verbose ? SG_WARN : SG_DEBUG;
|
sgDebugPriority logLevel = verbose ? SG_WARN : SG_DEBUG;
|
||||||
|
@ -1210,7 +1213,7 @@ bool NavDataCache::NavDataCachePrivate::areDatFilesModified(
|
||||||
}
|
}
|
||||||
|
|
||||||
while (datFilesIt != datFiles.end()) {
|
while (datFilesIt != datFiles.end()) {
|
||||||
const SGPath& path = *(datFilesIt++);
|
const SGPath& path = (datFilesIt++)->datPath;
|
||||||
|
|
||||||
if (!path.exists()) {
|
if (!path.exists()) {
|
||||||
throw sg_exception(
|
throw sg_exception(
|
||||||
|
@ -1643,25 +1646,24 @@ void NavDataCache::setRebuildPhaseProgress(RebuildPhase ph, unsigned int percent
|
||||||
|
|
||||||
void NavDataCache::loadDatFiles(
|
void NavDataCache::loadDatFiles(
|
||||||
DatFileType type,
|
DatFileType type,
|
||||||
std::function<void(const SGPath&, std::size_t, std::size_t)> loader)
|
std::function<void(const SceneryLocation&, std::size_t, std::size_t)> loader)
|
||||||
{
|
{
|
||||||
SGTimeStamp st;
|
SGTimeStamp st;
|
||||||
string typeStr = datTypeStr[type];
|
const string typeStr = datTypeStr[type];
|
||||||
string_list datFiles;
|
string_list datFiles;
|
||||||
NavDataCache::DatFilesGroupInfo datFilesInfo = getDatFilesInfo(type);
|
const NavDataCache::DatFilesGroupInfo datFilesInfo = getDatFilesInfo(type);
|
||||||
const PathList datPaths = datFilesInfo.paths;
|
const SceneryLocationList sceneryLocations = datFilesInfo.paths;
|
||||||
std::size_t bytesReadSoFar = 0;
|
std::size_t bytesReadSoFar = 0;
|
||||||
|
|
||||||
st.stamp();
|
st.stamp();
|
||||||
for (PathList::const_iterator it = datPaths.begin();
|
for (const auto& scLoc : sceneryLocations) {
|
||||||
it != datPaths.end(); it++) {
|
const string path = scLoc.datPath.realpath().utf8Str();
|
||||||
string path = it->realpath().utf8Str();
|
|
||||||
datFiles.push_back(path);
|
datFiles.push_back(path);
|
||||||
SG_LOG(SG_GENERAL, SG_INFO,
|
SG_LOG(SG_GENERAL, SG_INFO,
|
||||||
"Loading " + typeStr + ".dat file: '" << path << "'");
|
"Loading " + typeStr + ".dat file: '" << std::move(path) << "'");
|
||||||
loader(*it, bytesReadSoFar, datFilesInfo.totalSize);
|
loader(scLoc, bytesReadSoFar, datFilesInfo.totalSize);
|
||||||
bytesReadSoFar += it->sizeInBytes();
|
bytesReadSoFar += scLoc.datPath.sizeInBytes();
|
||||||
stampCacheFile(*it); // this uses the realpath() of the file
|
stampCacheFile(scLoc.datPath); // this uses the realpath() of the file
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store the list of .dat files we have loaded
|
// Store the list of .dat files we have loaded
|
||||||
|
@ -2032,8 +2034,10 @@ FGPositionedRef NavDataCache::loadById(PositionedID rowid)
|
||||||
}
|
}
|
||||||
|
|
||||||
PositionedID NavDataCache::insertAirport(FGPositioned::Type ty, const string& ident,
|
PositionedID NavDataCache::insertAirport(FGPositioned::Type ty, const string& ident,
|
||||||
const string& name)
|
const string& name,
|
||||||
|
const SGPath& sceneryPath)
|
||||||
{
|
{
|
||||||
|
const string sceneryPath_str = sceneryPath.utf8Str();
|
||||||
// airports have their pos computed based on the avergae runway centres
|
// airports have their pos computed based on the avergae runway centres
|
||||||
// so the pos isn't available immediately. Pass a dummy pos and avoid
|
// so the pos isn't available immediately. Pass a dummy pos and avoid
|
||||||
// doing spatial indexing until later
|
// doing spatial indexing until later
|
||||||
|
@ -2042,6 +2046,7 @@ PositionedID NavDataCache::insertAirport(FGPositioned::Type ty, const string& id
|
||||||
false /* spatial index */);
|
false /* spatial index */);
|
||||||
|
|
||||||
sqlite3_bind_int64(d->insertAirport, 1, rowId);
|
sqlite3_bind_int64(d->insertAirport, 1, rowId);
|
||||||
|
sqlite_bind_stdstring(d->insertAirport, 2, sceneryPath_str);
|
||||||
d->execInsert(d->insertAirport);
|
d->execInsert(d->insertAirport);
|
||||||
|
|
||||||
return rowId;
|
return rowId;
|
||||||
|
|
|
@ -10,9 +10,10 @@
|
||||||
#include <cstddef> // for std::size_t
|
#include <cstddef> // for std::size_t
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <Main/globals.hxx> // for PathList
|
|
||||||
#include <Navaids/positioned.hxx>
|
#include <Navaids/positioned.hxx>
|
||||||
|
#include <simgear/misc/sg_path.hxx>
|
||||||
#include <simgear/misc/strutils.hxx> // for string_list
|
#include <simgear/misc/strutils.hxx> // for string_list
|
||||||
|
|
||||||
|
|
||||||
|
@ -66,9 +67,16 @@ public:
|
||||||
DATFILETYPE_LAST
|
DATFILETYPE_LAST
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SceneryLocation {
|
||||||
|
SGPath datPath;
|
||||||
|
SGPath sceneryPath; // scenery realpath() the dat file belongs to
|
||||||
|
};
|
||||||
|
|
||||||
|
using SceneryLocationList = std::vector<SceneryLocation>;
|
||||||
|
|
||||||
struct DatFilesGroupInfo {
|
struct DatFilesGroupInfo {
|
||||||
DatFileType datFileType; // for instance, DATFILETYPE_APT
|
DatFileType datFileType; // for instance, DATFILETYPE_APT
|
||||||
PathList paths; // SGPath instances
|
SceneryLocationList paths;
|
||||||
std::size_t totalSize; // total size of all these files, in bytes
|
std::size_t totalSize; // total size of all these files, in bytes
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -144,7 +152,8 @@ public:
|
||||||
FGPositionedRef loadById(PositionedID guid);
|
FGPositionedRef loadById(PositionedID guid);
|
||||||
|
|
||||||
PositionedID insertAirport(FGPositioned::Type ty, const std::string& ident,
|
PositionedID insertAirport(FGPositioned::Type ty, const std::string& ident,
|
||||||
const std::string& name);
|
const std::string& name,
|
||||||
|
const SGPath& sceneryPath);
|
||||||
void insertTower(PositionedID airportId, const SGGeod& pos);
|
void insertTower(PositionedID airportId, const SGGeod& pos);
|
||||||
|
|
||||||
|
|
||||||
|
@ -335,7 +344,7 @@ private:
|
||||||
// A generic function for loading all navigation data files of the
|
// A generic function for loading all navigation data files of the
|
||||||
// specified type (apt/fix/nav etc.) using the passed type-specific loader.
|
// specified type (apt/fix/nav etc.) using the passed type-specific loader.
|
||||||
void loadDatFiles(DatFileType type,
|
void loadDatFiles(DatFileType type,
|
||||||
std::function<void(const SGPath&, std::size_t, std::size_t)> loader);
|
std::function<void(const SceneryLocation&, std::size_t, std::size_t)> loader);
|
||||||
|
|
||||||
void doRebuild();
|
void doRebuild();
|
||||||
|
|
||||||
|
|
|
@ -65,9 +65,11 @@ FixesLoader::~FixesLoader()
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
// Load fixes from the specified fix.dat (or fix.dat.gz) file
|
// Load fixes from the specified fix.dat (or fix.dat.gz) file
|
||||||
void FixesLoader::loadFixes(const SGPath& path, std::size_t bytesReadSoFar,
|
void FixesLoader::loadFixes(const NavDataCache::SceneryLocation& sceneryLocation,
|
||||||
|
std::size_t bytesReadSoFar,
|
||||||
std::size_t totalSizeOfAllDatFiles)
|
std::size_t totalSizeOfAllDatFiles)
|
||||||
{
|
{
|
||||||
|
const SGPath path = sceneryLocation.datPath;
|
||||||
sg_gzifstream in( path );
|
sg_gzifstream in( path );
|
||||||
const std::string utf8path = path.utf8Str();
|
const std::string utf8path = path.utf8Str();
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#define _FG_FIXLIST_HXX
|
#define _FG_FIXLIST_HXX
|
||||||
|
|
||||||
|
|
||||||
|
#include <Navaids/NavDataCache.hxx>
|
||||||
#include <simgear/compiler.h>
|
#include <simgear/compiler.h>
|
||||||
#include <simgear/math/SGGeod.hxx>
|
#include <simgear/math/SGGeod.hxx>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
@ -35,8 +36,6 @@ class sg_gzifstream;
|
||||||
|
|
||||||
namespace flightgear
|
namespace flightgear
|
||||||
{
|
{
|
||||||
class NavDataCache; // forward declaration
|
|
||||||
|
|
||||||
class FixesLoader
|
class FixesLoader
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -44,7 +43,8 @@ namespace flightgear
|
||||||
~FixesLoader();
|
~FixesLoader();
|
||||||
|
|
||||||
// Load fixes from the specified fix.dat (or fix.dat.gz) file
|
// Load fixes from the specified fix.dat (or fix.dat.gz) file
|
||||||
void loadFixes(const SGPath& path, std::size_t bytesReadSoFar,
|
void loadFixes(const NavDataCache::SceneryLocation& sceneryLocation,
|
||||||
|
std::size_t bytesReadSoFar,
|
||||||
std::size_t totalSizeOfAllDatFiles);
|
std::size_t totalSizeOfAllDatFiles);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -426,10 +426,12 @@ PositionedID NavLoader::processNavLine(
|
||||||
}
|
}
|
||||||
|
|
||||||
// load and initialize the navigational databases
|
// load and initialize the navigational databases
|
||||||
void NavLoader::loadNav(const SGPath& path, std::size_t bytesReadSoFar,
|
void NavLoader::loadNav(const NavDataCache::SceneryLocation& sceneryLocation,
|
||||||
|
std::size_t bytesReadSoFar,
|
||||||
std::size_t totalSizeOfAllDatFiles)
|
std::size_t totalSizeOfAllDatFiles)
|
||||||
{
|
{
|
||||||
NavDataCache* cache = NavDataCache::instance();
|
NavDataCache* cache = NavDataCache::instance();
|
||||||
|
const SGPath path = sceneryLocation.datPath;
|
||||||
const string utf8Path = path.utf8Str();
|
const string utf8Path = path.utf8Str();
|
||||||
sg_gzifstream in(path);
|
sg_gzifstream in(path);
|
||||||
|
|
||||||
|
|
|
@ -27,11 +27,13 @@
|
||||||
|
|
||||||
#include <simgear/compiler.h>
|
#include <simgear/compiler.h>
|
||||||
#include <simgear/math/SGGeod.hxx>
|
#include <simgear/math/SGGeod.hxx>
|
||||||
#include <string>
|
#include <Navaids/NavDataCache.hxx>
|
||||||
#include <map>
|
|
||||||
#include <tuple>
|
|
||||||
#include <Navaids/positioned.hxx>
|
#include <Navaids/positioned.hxx>
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
// forward decls
|
// forward decls
|
||||||
class FGTACANList;
|
class FGTACANList;
|
||||||
class SGPath;
|
class SGPath;
|
||||||
|
@ -42,7 +44,8 @@ namespace flightgear
|
||||||
class NavLoader {
|
class NavLoader {
|
||||||
public:
|
public:
|
||||||
// load and initialize the navigational databases
|
// load and initialize the navigational databases
|
||||||
void loadNav(const SGPath& path, std::size_t bytesReadSoFar,
|
void loadNav(const NavDataCache::SceneryLocation& sceneryLocation,
|
||||||
|
std::size_t bytesReadSoFar,
|
||||||
std::size_t totalSizeOfAllDatFiles);
|
std::size_t totalSizeOfAllDatFiles);
|
||||||
|
|
||||||
void loadCarrierNav(const SGPath& path);
|
void loadCarrierNav(const SGPath& path);
|
||||||
|
|
Loading…
Add table
Reference in a new issue