#include "sqlite3.h"
// SimGear
+#include <simgear/sg_inlines.h>
#include <simgear/structure/exception.hxx>
#include <simgear/debug/logstream.hxx>
#include <simgear/bucket/newbucket.hxx>
#include "PositionedOctree.hxx"
#include <Airports/apt_loader.hxx>
#include <Navaids/airways.hxx>
+#include "poidb.hxx"
#include <Airports/parking.hxx>
#include <Airports/gnnode.hxx>
const int MAX_RETRIES = 10;
const int SCHEMA_VERSION = 8;
-const int CACHE_SIZE_KBYTES= 16000;
+const int CACHE_SIZE_KBYTES= 32 * 1024;
// bind a std::string to a sqlite statement. The std::string must live the
// entire duration of the statement execution - do not pass a temporary
void init()
{
SG_LOG(SG_NAVCACHE, SG_INFO, "NavCache at:" << path);
- sqlite3_open_v2(path.c_str(), &db,
+
+ // see http://code.google.com/p/flightgear-bugs/issues/detail?id=1055
+ // for the logic here. Sigh.
+ std::string pathUtf8 = simgear::strutils::convertWindowsLocal8BitToUtf8(path.str());
+ sqlite3_open_v2(pathUtf8.c_str(), &db,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
setRunwayReciprocal = prepare("UPDATE runway SET reciprocal=?2 WHERE rowid=?1");
setRunwayILS = prepare("UPDATE runway SET ils=?2 WHERE rowid=?1");
+ setNavaidColocated = prepare("UPDATE navaid SET colocated=?2 WHERE rowid=?1");
updateRunwayThreshold = prepare("UPDATE runway SET heading=?2, displaced_threshold=?3, stopway=?4 WHERE rowid=?1");
insertPositionedQuery = prepare("INSERT INTO positioned "
" VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8)");
runwayLengthFtQuery = prepare("SELECT length_ft FROM runway WHERE rowid=?1");
+ removePOIQuery = prepare("DELETE FROM positioned WHERE type=?1 AND ident=?2");
+
// query statement
findClosestWithIdent = prepare("SELECT rowid FROM positioned WHERE ident=?1 "
AND_TYPED " ORDER BY distanceCartSqr(cart_x, cart_y, cart_z, ?4, ?5, ?6)");
}
int rangeNm = sqlite3_column_int(loadNavaid, 0),
- freq = sqlite3_column_int(loadNavaid, 1);
+ freq = sqlite3_column_int(loadNavaid, 1);
double mulituse = sqlite3_column_double(loadNavaid, 2);
- //sqlite3_int64 colocated = sqlite3_column_int64(loadNavaid, 4);
+ PositionedID colocated = sqlite3_column_int64(loadNavaid, 4);
reset(loadNavaid);
-
- return new FGNavRecord(rowId, ty, id, name, pos, freq, rangeNm, mulituse, runway);
+
+ FGNavRecord* n = new FGNavRecord(rowId, ty, id, name, pos, freq, rangeNm, mulituse, runway);
+ if (colocated) {
+ n->setColocatedDME(colocated);
+ }
+
+ return n;
}
FGPositioned* loadParking(sqlite3_int64 rowId,
return r;
}
- FGPositioned::List findAllByString(const string& s, const string& column,
+ FGPositionedList findAllByString(const string& s, const string& column,
FGPositioned::Filter* filter, bool exact)
{
string query = s;
sqlite3_bind_int(stmt, 3, filter->maxType());
}
- FGPositioned::List result;
+ FGPositionedList result;
// run the prepared SQL
while (stepSelect(stmt))
{
deferredOctreeUpdates.clear();
}
+
+ void removePositionedWithIdent(FGPositioned::Type ty, const std::string& aIdent)
+ {
+ sqlite3_bind_int(removePOIQuery, 1, ty);
+ sqlite_bind_stdstring(removePOIQuery, 2, aIdent);
+ execUpdate(removePOIQuery);
+ reset(removePOIQuery);
+ }
NavDataCache* outer;
sqlite3* db;
bool transactionAborted;
sqlite3_stmt_ptr beginTransactionStmt, commitTransactionStmt, rollbackTransactionStmt;
- SGPath aptDatPath, metarDatPath, navDatPath, fixDatPath,
+ SGPath aptDatPath, metarDatPath, navDatPath, fixDatPath, poiDatPath,
carrierDatPath, airwayDatPath;
sqlite3_stmt_ptr readPropertyQuery, writePropertyQuery,
sqlite3_stmt_ptr insertPositionedQuery, insertAirport, insertTower, insertRunway,
insertCommStation, insertNavaid;
- sqlite3_stmt_ptr setAirportMetar, setRunwayReciprocal, setRunwayILS,
+ sqlite3_stmt_ptr setAirportMetar, setRunwayReciprocal, setRunwayILS, setNavaidColocated,
setAirportPos, updateRunwayThreshold, updateILS;
+ sqlite3_stmt_ptr removePOIQuery;
sqlite3_stmt_ptr findClosestWithIdent;
// octree (spatial index) related queries
case FGPositioned::MOBILE_TACAN:
{
if (aptId > 0) {
- FGAirport* apt = (FGAirport*) outer->loadById(aptId);
+ FGAirport* apt = FGPositioned::loadById<FGAirport>(aptId);
if (apt->validateILSData()) {
- SG_LOG(SG_NAVCACHE, SG_INFO, "re-loaded ILS data for " << apt->ident());
// queried data above is probably invalid, force us to go around again
// (the next time through, validateILSData will return false)
return outer->loadById(rowid);
return new FGFix(rowid, ident, pos);
case FGPositioned::WAYPOINT:
+ case FGPositioned::COUNTRY:
+ case FGPositioned::CITY:
+ case FGPositioned::TOWN:
+ case FGPositioned::VILLAGE:
{
- FGPositioned* wpt = new FGPositioned(rowid, FGPositioned::WAYPOINT, ident, pos);
+ FGPositioned* wpt = new FGPositioned(rowid, ty, ident, pos);
return wpt;
}
d->fixDatPath = SGPath(globals->get_fg_root());
d->fixDatPath.append("Navaids/fix.dat.gz");
+
+ d->poiDatPath = SGPath(globals->get_fg_root());
+ d->poiDatPath.append("Navaids/poi.dat.gz");
d->carrierDatPath = SGPath(globals->get_fg_root());
d->carrierDatPath.append("Navaids/carrier_nav.dat.gz");
{
assert(static_instance == this);
static_instance = NULL;
- SG_LOG(SG_NAVCACHE, SG_INFO, "closing the navcache");
d.reset();
}
isCachedFileModified(d->metarDatPath) ||
isCachedFileModified(d->navDatPath) ||
isCachedFileModified(d->fixDatPath) ||
+ isCachedFileModified(d->poiDatPath) ||
isCachedFileModified(d->airwayDatPath))
{
SG_LOG(SG_NAVCACHE, SG_INFO, "NavCache: main cache rebuild required");
try {
d->close(); // completely close the sqlite object
d->path.remove(); // remove the file on disk
- d->init(); // star again from scratch
+ d->init(); // start again from scratch
- Transaction txn(this);
- // initialise the root octree node
+ // initialise the root octree node
d->runSQL("INSERT INTO octree (rowid, children) VALUES (1, 0)");
-
+
SGTimeStamp st;
- st.stamp();
-
- airportDBLoad(d->aptDatPath);
- SG_LOG(SG_NAVCACHE, SG_INFO, "apt.dat load took:" << st.elapsedMSec());
-
- metarDataLoad(d->metarDatPath);
- stampCacheFile(d->aptDatPath);
- stampCacheFile(d->metarDatPath);
-
- st.stamp();
- loadFixes(d->fixDatPath);
- stampCacheFile(d->fixDatPath);
- SG_LOG(SG_NAVCACHE, SG_INFO, "fix.dat load took:" << st.elapsedMSec());
-
- st.stamp();
- navDBInit(d->navDatPath);
- stampCacheFile(d->navDatPath);
- SG_LOG(SG_NAVCACHE, SG_INFO, "nav.dat load took:" << st.elapsedMSec());
-
- loadCarrierNav(d->carrierDatPath);
- stampCacheFile(d->carrierDatPath);
-
- st.stamp();
- Airway::load(d->airwayDatPath);
- stampCacheFile(d->airwayDatPath);
- SG_LOG(SG_NAVCACHE, SG_INFO, "awy.dat load took:" << st.elapsedMSec());
-
- d->flushDeferredOctreeUpdates();
-
- string sceneryPaths = simgear::strutils::join(globals->get_fg_scenery(), ";");
- writeStringProperty("scenery_paths", sceneryPaths);
-
- txn.commit();
+ {
+ Transaction txn(this);
+
+ st.stamp();
+ airportDBLoad(d->aptDatPath);
+ SG_LOG(SG_NAVCACHE, SG_INFO, "apt.dat load took:" << st.elapsedMSec());
+
+ metarDataLoad(d->metarDatPath);
+ stampCacheFile(d->aptDatPath);
+ stampCacheFile(d->metarDatPath);
+
+ st.stamp();
+ loadFixes(d->fixDatPath);
+ stampCacheFile(d->fixDatPath);
+ SG_LOG(SG_NAVCACHE, SG_INFO, "fix.dat load took:" << st.elapsedMSec());
+
+ st.stamp();
+ navDBInit(d->navDatPath);
+ stampCacheFile(d->navDatPath);
+ SG_LOG(SG_NAVCACHE, SG_INFO, "nav.dat load took:" << st.elapsedMSec());
+
+ st.stamp();
+ txn.commit();
+ SG_LOG(SG_NAVCACHE, SG_INFO, "stage 1 commit took:" << st.elapsedMSec());
+ }
+
+#ifdef SG_WINDOWS
+ SG_LOG(SG_NAVCACHE, SG_ALERT, "SKIPPING POI load on Windows");
+#else
+ {
+ Transaction txn(this);
+
+ st.stamp();
+ poiDBInit(d->poiDatPath);
+ stampCacheFile(d->poiDatPath);
+ SG_LOG(SG_NAVCACHE, SG_INFO, "poi.dat load took:" << st.elapsedMSec());
+
+ st.stamp();
+ txn.commit();
+ SG_LOG(SG_NAVCACHE, SG_INFO, "POI commit took:" << st.elapsedMSec());
+ }
+#endif
+
+ {
+ Transaction txn(this);
+ loadCarrierNav(d->carrierDatPath);
+ stampCacheFile(d->carrierDatPath);
+
+ st.stamp();
+ Airway::load(d->airwayDatPath);
+ stampCacheFile(d->airwayDatPath);
+ SG_LOG(SG_NAVCACHE, SG_INFO, "awy.dat load took:" << st.elapsedMSec());
+
+ d->flushDeferredOctreeUpdates();
+
+ string sceneryPaths = simgear::strutils::join(globals->get_fg_scenery(), ";");
+ writeStringProperty("scenery_paths", sceneryPaths);
+
+ st.stamp();
+ txn.commit();
+ SG_LOG(SG_NAVCACHE, SG_INFO, "final commit took:" << st.elapsedMSec());
+
+ }
+
} catch (sg_exception& e) {
SG_LOG(SG_NAVCACHE, SG_ALERT, "caught exception rebuilding navCache:" << e.what());
}
if (delta != 0)
{
SG_LOG(SG_NAVCACHE, SG_DEBUG, "NavCache: rebuild required for " << path << ". Timestamps: " << modtime << " != " << path.modTime());
- if (delta < 30)
- {
- // File system time stamp has slightly changed. It's unlikely that the user has managed to change a file, start fgfs,
- // and then changed file again within x seconds - so it's suspicious...
- SG_LOG(SG_NAVCACHE, SG_ALERT, "NavCache: suspicious file timestamp change. Please report this to FlightGear. "
- << "Delta: " << delta << ", Timestamps: " << modtime << ", " << path.modTime() << ", path: " << path);
- }
}
else
{
d->transactionAborted = true;
}
-FGPositioned* NavDataCache::loadById(PositionedID rowid)
+FGPositionedRef NavDataCache::loadById(PositionedID rowid)
{
if (rowid == 0) {
return NULL;
sqlite3_bind_int(d->insertNavaid, 3, range);
sqlite3_bind_double(d->insertNavaid, 4, multiuse);
sqlite3_bind_int64(d->insertNavaid, 5, runway);
+ sqlite3_bind_int64(d->insertNavaid, 6, 0);
return d->execInsert(d->insertNavaid);
}
+void NavDataCache::setNavaidColocated(PositionedID navaid, PositionedID colocatedDME)
+{
+ // Update DB entries...
+ sqlite3_bind_int64(d->setNavaidColocated, 1, navaid);
+ sqlite3_bind_int64(d->setNavaidColocated, 2, colocatedDME);
+ d->execUpdate(d->setNavaidColocated);
+
+ // ...and the in-memory copy of the navrecord
+ if (d->cache.find(navaid) != d->cache.end()) {
+ FGNavRecord* rec = (FGNavRecord*) d->cache[navaid].get();
+ rec->setColocatedDME(colocatedDME);
+ }
+}
+
void NavDataCache::updateILS(PositionedID ils, const SGGeod& newPos, double aHdg)
{
sqlite3_bind_int64(d->updateILS, 1, ils);
return d->insertPositioned(FGPositioned::FIX, ident, string(), aPos, 0, true);
}
-PositionedID NavDataCache::createUserWaypoint(const std::string& ident, const SGGeod& aPos)
+PositionedID NavDataCache::createPOI(FGPositioned::Type ty, const std::string& ident, const SGGeod& aPos)
{
- return d->insertPositioned(FGPositioned::WAYPOINT, ident, string(), aPos, 0,
+ return d->insertPositioned(ty, ident, string(), aPos, 0,
true /* spatial index */);
}
+
+bool NavDataCache::removePOI(FGPositioned::Type ty, const std::string& aIdent)
+{
+ d->removePositionedWithIdent(ty, aIdent);
+ // should remove from the live cache too?
+
+ return true;
+}
void NavDataCache::setAirportMetar(const string& icao, bool hasMetar)
{
d->execUpdate(d->setAirportMetar);
}
-FGPositioned::List NavDataCache::findAllWithIdent(const string& s,
- FGPositioned::Filter* filter, bool exact)
+//------------------------------------------------------------------------------
+FGPositionedList NavDataCache::findAllWithIdent( const string& s,
+ FGPositioned::Filter* filter,
+ bool exact )
{
return d->findAllByString(s, "ident", filter, exact);
}
-FGPositioned::List NavDataCache::findAllWithName(const string& s,
- FGPositioned::Filter* filter, bool exact)
+//------------------------------------------------------------------------------
+FGPositionedList NavDataCache::findAllWithName( const string& s,
+ FGPositioned::Filter* filter,
+ bool exact )
{
return d->findAllByString(s, "name", filter, exact);
}
-
-FGPositionedRef NavDataCache::findClosestWithIdent(const string& aIdent,
- const SGGeod& aPos, FGPositioned::Filter* aFilter)
+
+//------------------------------------------------------------------------------
+FGPositionedRef NavDataCache::findClosestWithIdent( const string& aIdent,
+ const SGGeod& aPos,
+ FGPositioned::Filter* aFilter )
{
sqlite_bind_stdstring(d->findClosestWithIdent, 1, aIdent);
if (aFilter) {