+
+ d->reset(d->airwayEdgesFrom);
+ return result;
+}
+
+PositionedID NavDataCache::findNavaidForRunway(PositionedID runway, FGPositioned::Type ty)
+{
+ sqlite3_bind_int64(d->findNavaidForRunway, 1, runway);
+ sqlite3_bind_int(d->findNavaidForRunway, 2, ty);
+
+ PositionedID result = 0;
+ if (d->execSelect(d->findNavaidForRunway)) {
+ result = sqlite3_column_int64(d->findNavaidForRunway, 0);
+ }
+
+ d->reset(d->findNavaidForRunway);
+ return result;
+}
+
+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.
+ 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);
+
+ 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)
+{
+ 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);
+ 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)
+{
+ 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;
+ sqlite3_bind_int64(q, 1, aAirport);
+ return d->selectIds(q);
+}
+
+void NavDataCache::markGroundnetAsPushback(PositionedID nodeId)
+{
+ 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;
+ 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());
+
+ PositionedID result = 0;
+ while (d->execSelect(q)) {
+ PositionedID id = sqlite3_column_int64(q, 0);
+ if (!aRunway) {
+ result = id;
+ break;
+ }
+
+ // 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 ) {
+ result = id;
+ break;
+ }
+ }
+
+ d->reset(q);