]> git.mxchange.org Git - flightgear.git/blobdiff - src/Navaids/NavDataCache.cxx
Parse nav.dat DMEs and assign them to appropriate navaid, if applicable.
[flightgear.git] / src / Navaids / NavDataCache.cxx
index 6b102f2fbde6e0389699f1349f39bc62da214aa9..5928ddaa6a68a3b8f549c6354a5a8640744e24be 100644 (file)
@@ -51,7 +51,7 @@
 #include <Main/globals.hxx>
 #include "markerbeacon.hxx"
 #include "navrecord.hxx"
-#include <Airports/simple.hxx>
+#include <Airports/airport.hxx>
 #include <Airports/runways.hxx>
 #include <ATC/CommStation.hxx>
 #include "fix.hxx"
@@ -60,6 +60,7 @@
 #include "PositionedOctree.hxx"
 #include <Airports/apt_loader.hxx>
 #include <Navaids/airways.hxx>
+#include "poidb.hxx"
 #include <Airports/parking.hxx>
 #include <Airports/gnnode.hxx>
 
@@ -71,8 +72,9 @@ using std::string;
 namespace {
 
 const int MAX_RETRIES = 10;
-const int SCHEMA_VERSION = 6;
-
+const int SCHEMA_VERSION = 8;
+const int CACHE_SIZE_KBYTES= 16000;
+    
 // 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
 // std::string, or the compiler may delete it, freeing the C-string storage,
@@ -205,18 +207,17 @@ public:
   
   ~NavDataCachePrivate()
   {
-    BOOST_FOREACH(sqlite3_stmt_ptr stmt, prepared) {
-      sqlite3_finalize(stmt);
-    }
-    prepared.clear();
-    
-    sqlite3_close(db);
+    close();
   }
   
   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);
     
     
@@ -248,9 +249,23 @@ public:
       }
     }
     
+    // see http://www.sqlite.org/pragma.html#pragma_cache_size
+    // for the details, small cache would cause thrashing.
+    std::ostringstream q;
+    q << "PRAGMA cache_size=-" << CACHE_SIZE_KBYTES << ";";
+    runSQL(q.str());
     prepareQueries();
   }
   
+  void close()
+  {
+    BOOST_FOREACH(sqlite3_stmt_ptr stmt, prepared) {
+      sqlite3_finalize(stmt);
+    }
+    prepared.clear();
+    sqlite3_close(db);
+  }
+  
   void checkCacheFile()
   {
     SG_LOG(SG_NAVCACHE, SG_INFO, "running DB integrity check");
@@ -542,6 +557,7 @@ public:
     
     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 "
@@ -563,6 +579,8 @@ public:
                            " 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)");
@@ -714,13 +732,16 @@ public:
     if (ty == FGPositioned::TAXIWAY) {
       reset(loadRunwayStmt);
       return new FGTaxiway(rowId, id, pos, heading, lengthM, widthM, surface);
+    } else if (ty == FGPositioned::HELIPAD) {
+        reset(loadRunwayStmt);
+        return new FGHelipad(rowId, apt, id, pos, heading, lengthM, widthM, surface);
     } else {
       double displacedThreshold = sqlite3_column_double(loadRunwayStmt, 4);
       double stopway = sqlite3_column_double(loadRunwayStmt, 5);
       PositionedID reciprocal = sqlite3_column_int64(loadRunwayStmt, 6);
       PositionedID ils = sqlite3_column_int64(loadRunwayStmt, 7);
       FGRunway* r = new FGRunway(rowId, apt, id, pos, heading, lengthM, widthM,
-                          displacedThreshold, stopway, surface, false);
+                          displacedThreshold, stopway, surface);
       
       if (reciprocal > 0) {
         r->setReciprocalRunway(reciprocal);
@@ -769,12 +790,17 @@ public:
     }
     
     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,
@@ -837,7 +863,7 @@ public:
     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;
@@ -863,7 +889,7 @@ public:
       sqlite3_bind_int(stmt, 3, filter->maxType());
     }
     
-    FGPositioned::List result;
+    FGPositionedList result;
   // run the prepared SQL
     while (stepSelect(stmt))
     {
@@ -908,6 +934,14 @@ public:
     
     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;
@@ -926,7 +960,7 @@ public:
   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,
@@ -937,8 +971,9 @@ public:
   
   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
@@ -1010,6 +1045,7 @@ FGPositioned* NavDataCache::NavDataCachePrivate::loadById(sqlite3_int64 rowid)
       return new AirportTower(rowid, aptId, ident, pos);
       
     case FGPositioned::RUNWAY:
+    case FGPositioned::HELIPAD:
     case FGPositioned::TAXIWAY:
       return loadRunway(rowid, ty, ident, pos, aptId);
       
@@ -1026,7 +1062,7 @@ FGPositioned* NavDataCache::NavDataCachePrivate::loadById(sqlite3_int64 rowid)
     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
@@ -1042,8 +1078,12 @@ FGPositioned* NavDataCache::NavDataCachePrivate::loadById(sqlite3_int64 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;
     }
       
@@ -1075,7 +1115,16 @@ NavDataCache::NavDataCache()
 {
   const int MAX_TRIES = 3;
   SGPath homePath(globals->get_fg_home());
-  homePath.append("navdata.cache");
+  
+  std::ostringstream os;
+  string_list versionParts = simgear::strutils::split(VERSION, ".");
+  if (versionParts.size() < 2) {
+    os << "navdata.cache";
+  } else {
+    os << "navdata_" << versionParts[0] << "_" << versionParts[1] << ".cache";
+  }
+    
+  homePath.append(os.str());
   
   for (int t=0; t < MAX_TRIES; ++t) {
     try {
@@ -1108,6 +1157,9 @@ NavDataCache::NavDataCache()
 
   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");
@@ -1139,6 +1191,7 @@ bool NavDataCache::isRebuildRequired()
       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");
@@ -1173,20 +1226,11 @@ bool NavDataCache::rebuild()
 void NavDataCache::doRebuild()
 {
   try {
-    Transaction txn(this);
-    d->runSQL("DELETE FROM positioned");
-    d->runSQL("DELETE FROM airport");
-    d->runSQL("DELETE FROM runway");
-    d->runSQL("DELETE FROM navaid");
-    d->runSQL("DELETE FROM comm");
-    d->runSQL("DELETE FROM octree");
-    d->runSQL("DELETE FROM airway");
-    d->runSQL("DELETE FROM airway_edge");
-    d->runSQL("DELETE FROM taxi_node");
-    d->runSQL("DELETE FROM parking");
-    d->runSQL("DELETE FROM groundnet_edge");
-    d->runSQL("DELETE FROM stat_cache");
+    d->close(); // completely close the sqlite object
+    d->path.remove(); // remove the file on disk
+    d->init(); // star again from scratch
     
+    Transaction txn(this);
   // initialise the root octree node
     d->runSQL("INSERT INTO octree (rowid, children) VALUES (1, 0)");
     
@@ -1209,6 +1253,11 @@ void NavDataCache::doRebuild()
     navDBInit(d->navDatPath);
     stampCacheFile(d->navDatPath);
     SG_LOG(SG_NAVCACHE, SG_INFO, "nav.dat load took:" << st.elapsedMSec());
+
+    st.stamp();
+    poiDBInit(d->poiDatPath);
+    stampCacheFile(d->poiDatPath);
+    SG_LOG(SG_NAVCACHE, SG_INFO, "poi.dat load took:" << st.elapsedMSec());
     
     loadCarrierNav(d->carrierDatPath);
     stampCacheFile(d->carrierDatPath);
@@ -1434,7 +1483,7 @@ void NavDataCache::abortTransaction()
   d->transactionAborted = true;
 }
 
-FGPositioned* NavDataCache::loadById(PositionedID rowid)
+FGPositionedRef NavDataCache::loadById(PositionedID rowid)
 {
   if (rowid == 0) {
     return NULL;
@@ -1515,7 +1564,7 @@ NavDataCache::insertRunway(FGPositioned::Type ty, const string& ident,
 {
   // only runways are spatially indexed; don't bother indexing taxiways
   // or pavements
-  bool spatialIndex = (ty == FGPositioned::RUNWAY);
+  bool spatialIndex = ( ty == FGPositioned::RUNWAY || ty == FGPositioned::HELIPAD);
   
   sqlite3_int64 rowId = d->insertPositioned(ty, cleanRunwayNo(ident), "", pos, apt,
                                             spatialIndex);
@@ -1547,6 +1596,12 @@ void NavDataCache::setRunwayILS(PositionedID runway, PositionedID ils)
   sqlite3_bind_int64(d->setRunwayILS, 1, runway);
   sqlite3_bind_int64(d->setRunwayILS, 2, ils);
   d->execUpdate(d->setRunwayILS);
+    
+  // and the in-memory one
+  if (d->cache.find(runway) != d->cache.end()) {
+    FGRunway* instance = (FGRunway*) d->cache[runway].ptr();
+    instance->setILS(ils);
+  }
 }
   
 void NavDataCache::updateRunwayThreshold(PositionedID runwayID, const SGGeod &aThreshold,
@@ -1559,14 +1614,9 @@ void NavDataCache::updateRunwayThreshold(PositionedID runwayID, const SGGeod &aT
   sqlite3_bind_double(d->updateRunwayThreshold, 3, aDisplacedThreshold);
   sqlite3_bind_double(d->updateRunwayThreshold, 4, aStopway);
   d->execUpdate(d->updateRunwayThreshold);
-      
-// compute the new runway center, based on the threshold lat/lon and length,
-  double offsetFt = (0.5 * d->runwayLengthFt(runwayID));
-  SGGeod newCenter= SGGeodesy::direct(aThreshold, aHeading, offsetFt * SG_FEET_TO_METER);
-  newCenter.setElevationM(aThreshold.getElevationM());
-  
-// now update the positional data
-  updatePosition(runwayID, newCenter);
+
+  // now update the positional data
+  updatePosition(runwayID, aThreshold);
 }
   
 PositionedID
@@ -1587,9 +1637,24 @@ NavDataCache::insertNavaid(FGPositioned::Type ty, const string& ident,
   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);
@@ -1614,11 +1679,17 @@ PositionedID NavDataCache::insertFix(const std::string& ident, const SGGeod& aPo
   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 */);
 }
+    
+void NavDataCache::removePOI(FGPositioned::Type ty, const std::string& aIdent)
+{
+  d->removePositionedWithIdent(ty, aIdent);
+  // should remove from the live cache too?
+}
   
 void NavDataCache::setAirportMetar(const string& icao, bool hasMetar)
 {
@@ -1627,20 +1698,26 @@ 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) {
@@ -2115,9 +2192,10 @@ void NavDataCache::dropGroundnetFor(PositionedID aAirport)
   sqlite3_bind_int64(q, 2, aAirport);
   d->execUpdate(q);
   
-  q = d->prepare("DELETE FROM taxi_node WHERE rowid IN (SELECT rowid FROM positioned WHERE type=?1 AND airport=?2)");
+  q = d->prepare("DELETE FROM taxi_node WHERE rowid IN (SELECT rowid FROM positioned WHERE (type=?1 OR type=?2) AND airport=?3)");
   sqlite3_bind_int(q, 1, FGPositioned::TAXI_NODE);
-  sqlite3_bind_int64(q, 2, aAirport);
+  sqlite3_bind_int(q, 2, FGPositioned::PARKING);
+  sqlite3_bind_int64(q, 3, aAirport);
   d->execUpdate(q);
   
   q = d->prepare("DELETE FROM positioned WHERE (type=?1 OR type=?2) AND airport=?3");