]> 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 3cc8a255e3984f97eaac333cf485e3a5621b0b7c..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,7 +72,7 @@ using std::string;
 namespace {
 
 const int MAX_RETRIES = 10;
-const int SCHEMA_VERSION = 7;
+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
@@ -212,7 +213,11 @@ public:
   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);
     
     
@@ -552,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 "
@@ -573,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)");
@@ -733,7 +741,7 @@ public:
       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);
@@ -782,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,
@@ -850,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;
@@ -876,7 +889,7 @@ public:
       sqlite3_bind_int(stmt, 3, filter->maxType());
     }
     
-    FGPositioned::List result;
+    FGPositionedList result;
   // run the prepared SQL
     while (stepSelect(stmt))
     {
@@ -921,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;
@@ -939,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,
@@ -950,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
@@ -1040,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
@@ -1056,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;
     }
       
@@ -1089,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 {
@@ -1122,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");
@@ -1153,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");
@@ -1214,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);
@@ -1439,7 +1483,7 @@ void NavDataCache::abortTransaction()
   d->transactionAborted = true;
 }
 
-FGPositioned* NavDataCache::loadById(PositionedID rowid)
+FGPositionedRef NavDataCache::loadById(PositionedID rowid)
 {
   if (rowid == 0) {
     return NULL;
@@ -1552,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,
@@ -1564,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
@@ -1592,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);
@@ -1619,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)
 {
@@ -1632,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) {