]> git.mxchange.org Git - flightgear.git/blobdiff - src/Navaids/NavDataCache.cxx
Overhaul the ground-net / parking code.
[flightgear.git] / src / Navaids / NavDataCache.cxx
index 5d228c4bcf7dd4d21447884e4b9ab6969ee19bef..c5cd7feea06615341ceb22459f6fec4beebab7af 100644 (file)
@@ -60,6 +60,8 @@
 #include "PositionedOctree.hxx"
 #include <Airports/apt_loader.hxx>
 #include <Navaids/airways.hxx>
+#include <Airports/parking.hxx>
+#include <Airports/gnnode.hxx>
 
 using std::string;
 
@@ -68,7 +70,7 @@ using std::string;
 
 namespace {
 
-const int SCHEMA_VERSION = 4;
+const int SCHEMA_VERSION = 5;
 
 // 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
@@ -461,6 +463,29 @@ public:
            ")");
     
     runSQL("CREATE INDEX airway_edge_from ON airway_edge(a)");
+    
+    runSQL("CREATE TABLE taxi_node ("
+           "hold_type INT,"
+           "on_runway BOOL,"
+           "pushback BOOL"
+           ")");
+    
+    runSQL("CREATE TABLE parking ("
+           "heading FLOAT,"
+           "radius INT,"
+           "gate_type VARCHAR,"
+           "airlines VARCHAR,"
+           "pushback INT64"
+           ")");
+    
+    runSQL("CREATE TABLE groundnet_edge ("
+           "airport INT64,"
+           "a INT64,"
+           "b INT64"
+           ")");
+    
+    runSQL("CREATE INDEX groundnet_edge_airport ON groundnet_edge(airport)");
+    runSQL("CREATE INDEX groundnet_edge_from ON groundnet_edge(a)");
   }
   
   void prepareQueries()
@@ -570,6 +595,7 @@ public:
     sqlite3_bind_int(findILS, 4, FGPositioned::ILS);
     sqlite3_bind_int(findILS, 5, FGPositioned::LOC);
     
+  // airways 
     findAirway = prepare("SELECT rowid FROM airway WHERE network=?1 AND ident=?2");
     insertAirway = prepare("INSERT INTO airway (ident, network) "
                            "VALUES (?1, ?2)");
@@ -580,6 +606,47 @@ public:
     isPosInAirway = prepare("SELECT rowid FROM airway_edge WHERE network=?1 AND a=?2");
     
     airwayEdgesFrom = prepare("SELECT airway, b FROM airway_edge WHERE network=?1 AND a=?2");
+    
+  // parking / taxi-node graph
+    insertTaxiNode = prepare("INSERT INTO taxi_node (rowid, hold_type, on_runway, pushback) VALUES(?1, ?2, ?3, 0)");
+    insertParkingPos = prepare("INSERT INTO parking (rowid, heading, radius, gate_type, airlines) "
+                               "VALUES (?1, ?2, ?3, ?4, ?5)");
+    setParkingPushBack = prepare("UPDATE parking SET pushback=?2 WHERE rowid=?1");
+    
+    loadTaxiNodeStmt = prepare("SELECT hold_type, on_runway FROM taxi_node WHERE rowid=?1");
+    loadParkingPos = prepare("SELECT heading, radius, gate_type, airlines, pushback FROM parking WHERE rowid=?1");
+    taxiEdgesFrom = prepare("SELECT b FROM groundnet_edge WHERE a=?1");
+    pushbackEdgesFrom = prepare("SELECT b FROM groundnet_edge, taxi_node WHERE "
+                                "a=?1 AND groundnet_edge.b = taxi_node.rowid AND pushback=1");
+    
+    insertTaxiEdge = prepare("INSERT INTO groundnet_edge (airport, a,b) VALUES(?1, ?2, ?3)");
+    
+    markTaxiNodeAsPushback = prepare("UPDATE taxi_node SET pushback=1 WHERE rowid=?1");
+    airportTaxiNodes = prepare("SELECT rowid FROM positioned WHERE (type=?2 OR type=?3) AND airport=?1");
+    sqlite3_bind_int(airportTaxiNodes, 2, FGPositioned::PARKING);
+    sqlite3_bind_int(airportTaxiNodes, 3, FGPositioned::TAXI_NODE);
+    
+    airportPushbackNodes = prepare("SELECT positioned.rowid FROM positioned, taxi_node WHERE "\
+                                   "airport=?1 AND positioned.rowid=taxi_node.rowid AND pushback=1 "
+                                   "AND (type=?2 OR type=?3)");
+    sqlite3_bind_int(airportPushbackNodes, 2, FGPositioned::PARKING);
+    sqlite3_bind_int(airportPushbackNodes, 3, FGPositioned::TAXI_NODE);
+    
+    findNearestTaxiNode = prepare("SELECT positioned.rowid FROM positioned, taxi_node WHERE "
+                                  "positioned.rowid = taxi_node.rowid AND airport=?1 "
+                                  "ORDER BY distanceCartSqr(cart_x, cart_y, cart_z, ?2, ?3, ?4) "
+                                  "LIMIT 1");
+    
+    findNearestRunwayTaxiNode = prepare("SELECT positioned.rowid FROM positioned, taxi_node WHERE "
+                                        "positioned.rowid = taxi_node.rowid AND airport=?1 "
+                                        "AND on_runway=1 " 
+                                        "ORDER BY distanceCartSqr(cart_x, cart_y, cart_z, ?2, ?3, ?4) ");
+    
+    findAirportParking = prepare("SELECT positioned.rowid FROM positioned, parking WHERE "
+                                 "airport=?1 AND type=?4 AND "
+                                 "radius >= ?2 AND gate_type = ?3 AND "
+                                 "parking.rowid=positioned.rowid");
+    sqlite3_bind_int(findAirportParking, 4, FGPositioned::PARKING);
   }
   
   void writeIntProperty(const string& key, int value)
@@ -678,6 +745,35 @@ public:
     return new FGNavRecord(rowId, ty, id, name, pos, freq, rangeNm, mulituse, runway);
   }
   
+  FGPositioned* loadParking(sqlite3_int64 rowId,
+                            const string& name, const SGGeod& pos,
+                            PositionedID airport)
+  {
+    reset(loadParkingPos);
+    sqlite3_bind_int64(loadParkingPos, 1, rowId);
+    execSelect1(loadParkingPos);
+    
+    double heading = sqlite3_column_double(loadParkingPos, 0);
+    int radius = sqlite3_column_int(loadParkingPos, 1);
+    string aircraftType((char*) sqlite3_column_text(loadParkingPos, 2));
+    string airlines((char*) sqlite3_column_text(loadParkingPos, 3));
+    PositionedID pushBack = sqlite3_column_int64(loadParkingPos, 4);
+    
+    return new FGParking(rowId, pos, heading, radius, name, aircraftType, airlines, pushBack);
+  }
+  
+  FGPositioned* loadTaxiNode(sqlite3_int64 rowId, const SGGeod& pos,
+                             PositionedID airport)
+  {
+    reset(loadTaxiNodeStmt);
+    sqlite3_bind_int64(loadTaxiNodeStmt, 1, rowId);
+    execSelect1(loadTaxiNodeStmt);
+    
+    int hold_type = sqlite3_column_int(loadTaxiNodeStmt, 0);
+    bool onRunway = sqlite3_column_int(loadTaxiNodeStmt, 1);
+    return new FGTaxiNode(rowId, pos, onRunway, hold_type);
+  }
+  
   PositionedID insertPositioned(FGPositioned::Type ty, const string& ident,
                                 const string& name, const SGGeod& pos, PositionedID apt,
                                 bool spatialIndex)
@@ -822,6 +918,12 @@ public:
   sqlite3_stmt_ptr findAirway, insertAirwayEdge, isPosInAirway, airwayEdgesFrom,
   insertAirway;
   
+// groundnet (parking, taxi node graph)
+  sqlite3_stmt_ptr loadTaxiNodeStmt, loadParkingPos, insertTaxiNode, insertParkingPos;
+  sqlite3_stmt_ptr taxiEdgesFrom, pushbackEdgesFrom, insertTaxiEdge, markTaxiNodeAsPushback,
+    airportTaxiNodes, airportPushbackNodes, findNearestTaxiNode, findAirportParking,
+    setParkingPushBack, findNearestRunwayTaxiNode;
+  
 // since there's many permutations of ident/name queries, we create
 // them programtically, but cache the exact query by its raw SQL once
 // used.
@@ -910,6 +1012,12 @@ FGPositioned* NavDataCache::NavDataCachePrivate::loadFromStmt(sqlite3_stmt_ptr q
     case FGPositioned::FREQ_UNICOM:
       return loadComm(rowid, ty, ident, name, pos, aptId);
       
+    case FGPositioned::TAXI_NODE:
+      return loadTaxiNode(rowid, pos, aptId);
+      
+    case FGPositioned::PARKING:
+      return loadParking(rowid, ident, pos, aptId);
+      
     default:
       return NULL;
   }
@@ -1173,6 +1281,20 @@ void NavDataCache::stampCacheFile(const SGPath& path)
   d->execInsert(d->stampFileCache);
 }
 
+void NavDataCache::beginTransaction()
+{
+  d->runSQL("BEGIN");
+}
+  
+void NavDataCache::commitTransaction()
+{
+  d->runSQL("COMMIT");
+}
+  
+void NavDataCache::abortTransaction()
+{
+  d->runSQL("ROLLBACK");
+}
 
 FGPositioned* NavDataCache::loadById(PositionedID rowid)
 {
@@ -1723,5 +1845,128 @@ PositionedID NavDataCache::findNavaidForRunway(PositionedID runway, FGPositioned
   return sqlite3_column_int64(d->findNavaidForRunway, 0);
 }
   
+PositionedID
+NavDataCache::insertParking(const std::string& name, const SGGeod& aPos,
+                            PositionedID aAirport,
+                           double aHeading, int aRadius, const std::string& aAircraftType,
+                           const std::string& aAirlines)
+{
+  sqlite3_int64 rowId = d->insertPositioned(FGPositioned::PARKING, name, "", aPos, aAirport, false);
+  
+// we need to insert a row into the taxi_node table, otherwise we can't maintain
+// the appropriate pushback flag.
+  d->reset(d->insertTaxiNode);
+  sqlite3_bind_int64(d->insertTaxiNode, 1, rowId);
+  sqlite3_bind_int(d->insertTaxiNode, 2, 0);
+  sqlite3_bind_int(d->insertTaxiNode, 3, 0);
+  d->execInsert(d->insertTaxiNode);
+  
+  d->reset(d->insertParkingPos);
+  sqlite3_bind_int64(d->insertParkingPos, 1, rowId);
+  sqlite3_bind_double(d->insertParkingPos, 2, aHeading);
+  sqlite3_bind_int(d->insertParkingPos, 3, aRadius);
+  sqlite_bind_stdstring(d->insertParkingPos, 4, aAircraftType);
+  sqlite_bind_stdstring(d->insertParkingPos, 5, aAirlines);
+  return d->execInsert(d->insertParkingPos);
+}
+  
+void NavDataCache::setParkingPushBackRoute(PositionedID parking, PositionedID pushBackNode)
+{
+  d->reset(d->setParkingPushBack);
+  sqlite3_bind_int64(d->setParkingPushBack, 1, parking);
+  sqlite3_bind_int64(d->setParkingPushBack, 2, pushBackNode);
+  d->execUpdate(d->setParkingPushBack);
+}
+
+PositionedID
+NavDataCache::insertTaxiNode(const SGGeod& aPos, PositionedID aAirport, int aHoldType, bool aOnRunway)
+{
+  sqlite3_int64 rowId = d->insertPositioned(FGPositioned::TAXI_NODE, string(), string(), aPos, aAirport, false);
+  d->reset(d->insertTaxiNode);
+  sqlite3_bind_int64(d->insertTaxiNode, 1, rowId);
+  sqlite3_bind_int(d->insertTaxiNode, 2, aHoldType);
+  sqlite3_bind_int(d->insertTaxiNode, 3, aOnRunway);
+  return d->execInsert(d->insertTaxiNode);
+}
+  
+void NavDataCache::insertGroundnetEdge(PositionedID aAirport, PositionedID from, PositionedID to)
+{
+  d->reset(d->insertTaxiEdge);
+  sqlite3_bind_int64(d->insertTaxiEdge, 1, aAirport);
+  sqlite3_bind_int64(d->insertTaxiEdge, 2, from);
+  sqlite3_bind_int64(d->insertTaxiEdge, 3, to);
+  d->execInsert(d->insertTaxiEdge);
+}
+  
+PositionedIDVec NavDataCache::groundNetNodes(PositionedID aAirport, bool onlyPushback)
+{
+  sqlite3_stmt_ptr q = onlyPushback ? d->airportPushbackNodes : d->airportTaxiNodes;
+  d->reset(q);
+  sqlite3_bind_int64(q, 1, aAirport);
+  return d->selectIds(q);
+}
+  
+void NavDataCache::markGroundnetAsPushback(PositionedID nodeId)
+{
+  d->reset(d->markTaxiNodeAsPushback);
+  sqlite3_bind_int64(d->markTaxiNodeAsPushback, 1, nodeId);
+  d->execUpdate(d->markTaxiNodeAsPushback);
+}
+
+static double headingDifferenceDeg(double crs1, double crs2)
+{
+  double diff =  crs2 - crs1;
+  SG_NORMALIZE_RANGE(diff, -180.0, 180.0);
+  return diff;
+}
+  
+PositionedID NavDataCache::findGroundNetNode(PositionedID airport, const SGGeod& aPos,
+                                             bool onRunway, FGRunway* aRunway)
+{
+  sqlite3_stmt_ptr q = onRunway ? d->findNearestRunwayTaxiNode : d->findNearestTaxiNode;
+  d->reset(q);
+  sqlite3_bind_int64(q, 1, airport);
+  
+  SGVec3d cartPos(SGVec3d::fromGeod(aPos));
+  sqlite3_bind_double(q, 2, cartPos.x());
+  sqlite3_bind_double(q, 3, cartPos.y());
+  sqlite3_bind_double(q, 4, cartPos.z());
+  
+  while (d->execSelect(q)) {
+    PositionedID id = sqlite3_column_int64(q, 0);
+    if (!aRunway) {
+      return id;
+    }
+    
+  // ensure found node lies on the runway
+    FGPositionedRef node = loadById(id);
+    double course = SGGeodesy::courseDeg(node->geod(), aRunway->end());
+    if (fabs(headingDifferenceDeg(course, aRunway->headingDeg())) < 3.0 ) {
+      return id;
+    }
+  }
+  
+  return 0;
+}
+  
+PositionedIDVec NavDataCache::groundNetEdgesFrom(PositionedID pos, bool onlyPushback)
+{
+  sqlite3_stmt_ptr q = onlyPushback ? d->pushbackEdgesFrom : d->taxiEdgesFrom;
+  d->reset(q);
+  sqlite3_bind_int64(q, 1, pos);
+  return d->selectIds(q);
+}
+
+PositionedIDVec NavDataCache::findAirportParking(PositionedID airport, const std::string& flightType,
+                                   int radius)
+{
+  d->reset(d->findAirportParking);
+  sqlite3_bind_int64(d->findAirportParking, 1, airport);
+  sqlite3_bind_int(d->findAirportParking, 2, radius);
+  sqlite_bind_stdstring(d->findAirportParking, 3, flightType);
+  
+  return d->selectIds(d->findAirportParking);
+}
+
 } // of namespace flightgear