time_t arrivalTime; // For AI/ATC purposes.
int leg;
ParkingAssignment gate;
- PositionedID lastNodeVisited;
+ FGTaxiNodeRef lastNodeVisited;
std::string activeRunway;
std::string name;
bool isValid;
return true;
}
- PositionedID runwayId = 0;
+ FGTaxiNodeRef runwayNode;
if (gn->getVersion() > 0) {
- runwayId = gn->findNearestNodeOnRunway(runwayTakeoff);
+ FGTaxiNodeRef runwayNode = gn->findNearestNodeOnRunway(runwayTakeoff);
} else {
- runwayId = gn->findNearestNode(runwayTakeoff);
+ FGTaxiNodeRef runwayNode = gn->findNearestNode(runwayTakeoff);
}
// A negative gateId indicates an overflow parking, use a
// taxiRoute = new FGTaxiRoute;
// Determine which node to start from.
- PositionedID node = 0;
+ FGTaxiNodeRef node;
// Find out which node to start from
FGParking *park = gate.parking();
if (park) {
node = park->getPushBackPoint();
- if (node == -1) {
- node = park->guid();
- } else if (node == 0) {
+ if (node == 0) {
// Handle case where parking doesn't have a node
if (firstFlight) {
- node = park->guid();
+ node = park;
} else {
node = lastNodeVisited;
}
}
FGTaxiRoute taxiRoute;
- if ( runwayId != 0 )
- taxiRoute = gn->findShortestRoute(node, runwayId);
+ if ( runwayNode )
+ taxiRoute = gn->findShortestRoute(node, runwayNode);
if (taxiRoute.empty()) {
createDefaultTakeoffTaxi(ac, apt, rwy);
}
taxiRoute.first();
+ FGTaxiNodeRef skipNode;
+
//bool isPushBackPoint = false;
if (firstFlight) {
// If this is called during initialization, randomly
// but make sure we always keep two active waypoints
// to prevent a segmentation fault
for (int i = 0; i < nrWaypointsToSkip - 3; i++) {
- taxiRoute.next(&node, &route);
+ taxiRoute.next(skipNode, &route);
}
gate.release(); // free up our gate as required
} else {
if (taxiRoute.size() > 1) {
- taxiRoute.next(&node, &route); // chop off the first waypoint, because that is already the last of the pushback route
+ taxiRoute.next(skipNode, &route); // chop off the first waypoint, because that is already the last of the pushback route
}
}
// Note that the line wpt->setRouteIndex was commented out by revision [afcdbd] 2012-01-01,
// which breaks the rendering functions.
// These can probably be generated on the fly however.
- while (taxiRoute.next(&node, &route)) {
+ while (taxiRoute.next(node, &route)) {
char buffer[10];
- snprintf(buffer, 10, "%lld", (long long int) node);
- FGTaxiNode *tn =
- apt->getDynamics()->getGroundNetwork()->findNode(node);
+ snprintf(buffer, 10, "%d", node->getIndex());
FGAIWaypoint *wpt =
- createOnGround(ac, buffer, tn->geod(), apt->getElevation(),
+ createOnGround(ac, buffer, node->geod(), apt->getElevation(),
ac->getPerformance()->vTaxi());
wpt->setRouteIndex(route);
//cerr << "Nodes left " << taxiRoute->nodesLeft() << " ";
return true;
}
- PositionedID runwayId = 0;
+ FGTaxiNodeRef runwayNode;
if (gn->getVersion() == 1) {
- runwayId = gn->findNearestNodeOnRunway(lastWptPos);
+ runwayNode = gn->findNearestNodeOnRunway(lastWptPos);
} else {
- runwayId = gn->findNearestNode(lastWptPos);
+ runwayNode = gn->findNearestNode(lastWptPos);
}
//cerr << "Using network node " << runwayId << endl;
// A negative gateId indicates an overflow parking, use a
// Starting from gate 0 doesn't work, so don't try it
FGTaxiRoute taxiRoute;
if (gate.isValid())
- taxiRoute = gn->findShortestRoute(runwayId, gate.parking()->guid());
+ taxiRoute = gn->findShortestRoute(runwayNode, gate.parking());
if (taxiRoute.empty()) {
createDefaultLandingTaxi(ac, apt);
return true;
}
- PositionedID node;
+ FGTaxiNodeRef node;
taxiRoute.first();
int size = taxiRoute.size();
// Omit the last two waypoints, as
// those are created by createParking()
// int route;
for (int i = 0; i < size - 2; i++) {
- taxiRoute.next(&node, &route);
+ taxiRoute.next(node, &route);
char buffer[10];
- snprintf(buffer, 10, "%lld", (long long int) node);
- FGTaxiNode *tn = gn->findNode(node);
+ snprintf(buffer, 10, "%d", node->getIndex());
FGAIWaypoint *wpt =
- createOnGround(ac, buffer, tn->geod(), apt->getElevation(),
+ createOnGround(ac, buffer, node->geod(), apt->getElevation(),
ac->getPerformance()->vTaxi());
wpt->setRouteIndex(route);
}
double dAlt = 0; // = alt - (apt->getElevation() + 2000);
- FGTaxiNode * tn = 0;
+ FGTaxiNodeRef tn;
if (apt->getDynamics()->getGroundNetwork()) {
- int node = apt->getDynamics()->getGroundNetwork()->findNearestNode(refPoint);
- tn = apt->getDynamics()->getGroundNetwork()->findNode(node);
+ tn = apt->getDynamics()->getGroundNetwork()->findNearestNode(refPoint);
}
if (tn) {
}
coord = rwy->pointOnCenterline(mindist);
- int nodeId = 0;
+ FGTaxiNodeRef tn;
if (gn->getVersion() > 0) {
- nodeId = gn->findNearestNodeOnRunway(coord, rwy);
+ tn = gn->findNearestNodeOnRunway(coord, rwy);
} else {
- nodeId = gn->findNearestNode(coord);
+ tn = gn->findNearestNode(coord);
}
- FGTaxiNode* tn = gn->findNode(nodeId);
if (tn) {
wpt = createOnGround(ac, buffer, tn->geod(), currElev, vTaxi);
pushBackWaypoint(wpt);
FGGroundNetwork* groundNet = dep->getDynamics()->getGroundNetwork();
FGParking *parking = gate.parking();
if (parking && parking->getPushBackPoint() > 0) {
- FGTaxiRoute route = groundNet->findShortestRoute(parking->guid(), parking->getPushBackPoint(), false);
+ FGTaxiRoute route = groundNet->findShortestRoute(parking, parking->getPushBackPoint(), false);
int size = route.size();
if (size < 2) {
}
route.first();
- PositionedID node;
+ FGTaxiNodeRef node;
int rte;
- while (route.next(&node, &rte))
+ while (route.next(node, &rte))
{
char buffer[10];
- snprintf (buffer, 10, "%lld", (long long int) node);
- FGTaxiNode *tn = groundNet->findNode(node);
- FGAIWaypoint *wpt = createOnGround(ac, string(buffer), tn->geod(), dep->getElevation(), vTaxiBackward);
+ snprintf (buffer, 10, "%d", node->getIndex());
+ FGAIWaypoint *wpt = createOnGround(ac, string(buffer), node->geod(), dep->getElevation(), vTaxiBackward);
/*
if (previous) {
ac->setTaxiClearanceRequest(false);
double az2 = 0.0;
- FGTaxiSegment* pushForwardSegment = dep->getDynamics()->getGroundNetwork()->findSegment(parking->guid(), 0);
+ FGTaxiSegment* pushForwardSegment = dep->getDynamics()->getGroundNetwork()->findSegment(parking, 0);
// there aren't any routes for this parking.
if (!pushForwardSegment) {
SG_LOG(SG_AI, SG_ALERT, "Gate " << parking->ident() << "doesn't seem to have routes associated with it.");
return false;
}
- lastNodeVisited = pushForwardSegment->getEnd()->getIndex();
+ lastNodeVisited = pushForwardSegment->getEnd();
double distance = pushForwardSegment->getLength();
double parkingHeading = parking->getHeading();
// No valid parking location, so either at the runway or at a random location.
if (pk.isValid()) {
- dcs->setParkingAvailable(pk.parking()->guid(), false);
+ dcs->setParkingAvailable(pk.parking(), false);
fp = new FGAIFlightPlan;
controller = apt->getDynamics()->getStartupController();
int stationFreq = apt->getDynamics()->getGroundFrequency(1);
FGAirport::~FGAirport()
{
+ SG_LOG(SG_NAVAID, SG_INFO, "deleting airport:" << ident());
delete _dynamics;
}
#include <Navaids/NavDataCache.hxx>
#include <Airports/dynamics.hxx>
#include <Airports/airport.hxx>
+#include <Airports/groundnetwork.hxx>
using std::string;
void FGAirportDynamicsXMLLoader::endXML ()
{
- std::map<PositionedID, int>::iterator it;
- flightgear::NavDataCache* cache = flightgear::NavDataCache::instance();
+ ParkingPushbackIndex::const_iterator it;
for (it = _parkingPushbacks.begin(); it != _parkingPushbacks.end(); ++it) {
- std::map<int, PositionedID>::iterator j = _idMap.find(it->second);
- if (j == _idMap.end()) {
+ NodeIndexMap::const_iterator j = _indexMap.find(it->second);
+ if (j == _indexMap.end()) {
SG_LOG(SG_NAVAID, SG_WARN, "bad groundnet, no node for index:" << it->first);
continue;
}
+
+ it->first->setPushBackPoint(j->second);
- cache->setParkingPushBackRoute(it->first, j->second);
}
- BOOST_FOREACH(PositionedID id, _unreferencedNodes) {
- SG_LOG(SG_NAVAID, SG_WARN, "unreferenced groundnet node:" << id);
+ BOOST_FOREACH(FGTaxiNodeRef node, _unreferencedNodes) {
+ SG_LOG(SG_NAVAID, SG_WARN, "unreferenced groundnet node:" << node->ident());
}
}
SGGeod pos(SGGeod::fromDeg(processPosition(lon), processPosition(lat)));
- PositionedID guid = flightgear::NavDataCache::instance()->insertParking(gateName + gateNumber, pos,
- _dynamics->parent()->guid(),
- heading, radius, type, airlineCodes);
+ FGParkingRef parking(new FGParking(index,
+ pos, heading, radius,
+ gateName + gateNumber,
+ type, airlineCodes));
if (pushBackRoute > 0) {
- _parkingPushbacks[guid] = pushBackRoute;
+ _parkingPushbacks[parking] = pushBackRoute;
}
- _idMap[index] = guid;
+ _indexMap[index] = parking;
+ _dynamics->getGroundNetwork()->addParking(parking);
}
void FGAirportDynamicsXMLLoader::startNode(const XMLAttributes &atts)
}
}
- if (_idMap.find(index) != _idMap.end()) {
+ if (_indexMap.find(index) != _indexMap.end()) {
SG_LOG(SG_NAVAID, SG_WARN, "duplicate ground-net index:" << index);
}
SGGeod pos(SGGeod::fromDeg(processPosition(lon), processPosition(lat)));
- PositionedID guid = flightgear::NavDataCache::instance()->insertTaxiNode(pos,
- _dynamics->parent()->guid(), holdPointType, onRunway);
- _idMap[index] = guid;
- _unreferencedNodes.insert(guid);
+ FGTaxiNodeRef node(new FGTaxiNode(index, pos, onRunway, holdPointType));
+ _indexMap[index] = node;
+ _unreferencedNodes.insert(node);
}
void FGAirportDynamicsXMLLoader::startArc(const XMLAttributes &atts)
return;
}
- _arcSet.insert(e);
- flightgear::NavDataCache::instance()->insertGroundnetEdge(_dynamics->parent()->guid(),
- _idMap[begin], _idMap[end]);
-
- _unreferencedNodes.erase(_idMap[begin]);
- _unreferencedNodes.erase(_idMap[end]);
-
- if (isPushBackRoute) {
- flightgear::NavDataCache::instance()->markGroundnetAsPushback(_idMap[end]);
+ NodeIndexMap::const_iterator it;
+ FGTaxiNodeRef fromNode, toNode;
+ it = _indexMap.find(begin);
+ if (it == _indexMap.end()) {
+ SG_LOG(SG_NAVAID, SG_WARN, "ground-net: bad edge:" << begin << "->" << end << ", begin index unknown");
+ return;
+ } else {
+ _unreferencedNodes.erase(it->second);
+ fromNode = it->second;
}
+
+ it = _indexMap.find(end);
+ if (it == _indexMap.end()) {
+ SG_LOG(SG_NAVAID, SG_WARN, "ground-net: bad edge:" << begin << "->" << end << ", end index unknown");
+ return;
+ } else {
+ _unreferencedNodes.erase(it->second);
+ toNode = it->second;
+ }
+
+ _arcSet.insert(e);
+ _dynamics->getGroundNetwork()->addSegment(fromNode, toNode);
}
void FGAirportDynamicsXMLLoader::startElement (const char * name, const XMLAttributes &atts)
#include <simgear/xml/easyxml.hxx>
#include "dynamics.hxx"
-#include <Navaids/positioned.hxx>
+#include <Airports/parking.hxx>
class FGAirportDynamicsXMLLoader : public XMLVisitor {
public:
FGAirportDynamics* _dynamics;
std::string value;
- // map from local (groundnet.xml) to global (nav-cache) IDs for nodes
- std::map<int, PositionedID> _idMap;
+ // map from local (groundnet.xml) ids to parking instances
+ typedef std::map<int, FGTaxiNodeRef> NodeIndexMap;
+ NodeIndexMap _indexMap;
// data integrity - watch for unreferenced nodes and duplicated edges
typedef std::pair<int, int> IntPair;
std::set<IntPair> _arcSet;
- std::set<PositionedID> _unreferencedNodes;
+ std::set<FGTaxiNodeRef> _unreferencedNodes;
// map from allocated parking position to its local push-back node
// used to defer binding the push-back node until we've processed
// all nodes
- std::map<PositionedID, int> _parkingPushbacks;
+ typedef std::map<FGParkingRef, int> ParkingPushbackIndex;
+ ParkingPushbackIndex _parkingPushbacks;
};
#endif
~ParkingAssignmentPrivate()
{
- airport->getDynamics()->releaseParking(parking->guid());
+ airport->getDynamics()->releaseParking(parking);
}
void release()
}
unsigned int refCount;
- SGSharedPtr<FGParking> parking;
- SGSharedPtr<FGAirport> airport;
+ FGParkingRef parking;
+ FGAirportRef airport;
};
ParkingAssignment::ParkingAssignment() :
const string & airline,
bool skipEmptyAirlineCode)
{
- flightgear::NavDataCache* cache = flightgear::NavDataCache::instance();
- BOOST_FOREACH(PositionedID pk, cache->findAirportParking(_ap->guid(), flType, radius)) {
- if (!isParkingAvailable(pk)) {
- continue;
- }
-
- FGParking* parking = getParking(pk);
- if (skipEmptyAirlineCode && parking->getCodes().empty()) {
- continue;
- }
-
- if (!airline.empty() && !parking->getCodes().empty()) {
- if (parking->getCodes().find(airline, 0) == string::npos) {
- continue;
- }
+ const FGParkingList& parkings(groundNetwork.allParkings());
+ FGParkingList::const_iterator it;
+ for (it = parkings.begin(); it != parkings.end(); ++it) {
+ FGParkingRef parking = *it;
+ if (!isParkingAvailable(parking)) {
+ continue;
+ }
+
+ if (skipEmptyAirlineCode && parking->getCodes().empty()) {
+ continue;
+ }
+
+ if (!airline.empty() && !parking->getCodes().empty()) {
+ if (parking->getCodes().find(airline, 0) == string::npos) {
+ continue;
+ }
+ }
+
+ setParkingAvailable(parking, false);
+ return parking;
}
-
- setParkingAvailable(pk, false);
- return parking;
- }
-
- return NULL;
+
+ return NULL;
}
ParkingAssignment FGAirportDynamics::getAvailableParking(double radius, const string & flType,
return result ? ParkingAssignment(result, _ap) : ParkingAssignment();
}
-FGParkingRef FGAirportDynamics::getParking(PositionedID id) const
-{
- return FGPositioned::loadById<FGParking>(id);
-}
-
-string FGAirportDynamics::getParkingName(PositionedID id) const
-{
- FGParking* p = getParking(id);
- if (p) {
- return p->getName();
- }
-
- return string();
-}
-
ParkingAssignment FGAirportDynamics::getParkingByName(const std::string& name) const
{
- PositionedID guid = flightgear::NavDataCache::instance()->airportItemWithIdent(parent()->guid(), FGPositioned::PARKING, name);
- if (guid == 0) {
- return ParkingAssignment();
- }
-
- return ParkingAssignment(getParking(guid), _ap);
+ const FGParkingList& parkings(groundNetwork.allParkings());
+ FGParkingList::const_iterator it;
+ for (it = parkings.begin(); it != parkings.end(); ++it) {
+ if ((*it)->name() == name) {
+ return ParkingAssignment(*it, _ap);
+ }
+ }
+
+ return ParkingAssignment();
}
-void FGAirportDynamics::setParkingAvailable(PositionedID guid, bool available)
+void FGAirportDynamics::setParkingAvailable(FGParking* park, bool available)
{
if (available) {
- releaseParking(guid);
+ releaseParking(park);
} else {
- occupiedParkings.insert(guid);
+ occupiedParkings.insert(park);
}
}
-bool FGAirportDynamics::isParkingAvailable(PositionedID parking) const
+bool FGAirportDynamics::isParkingAvailable(FGParking* parking) const
{
return (occupiedParkings.find(parking) == occupiedParkings.end());
}
-void FGAirportDynamics::releaseParking(PositionedID id)
+void FGAirportDynamics::releaseParking(FGParking* id)
{
ParkingSet::iterator it = occupiedParkings.find(id);
if (it == occupiedParkings.end()) {
occupiedParkings.erase(it);
}
+class GetParkingsPredicate
+{
+ bool mustBeAvailable;
+ std::string type;
+ const FGAirportDynamics* dynamics;
+public:
+ GetParkingsPredicate(bool b, const std::string& ty, const FGAirportDynamics* dyn) :
+ mustBeAvailable(b),
+ type(ty),
+ dynamics(dyn)
+ {}
+
+ bool operator()(const FGParkingRef& park) const
+ {
+ if (!type.empty() && (park->getType() != type))
+ return true;
+
+ if (mustBeAvailable && !dynamics->isParkingAvailable(park)) {
+ return true;
+ }
+
+ return false;
+ }
+};
+
+FGParkingList FGAirportDynamics::getParkings(bool onlyAvailable, const std::string &type) const
+{
+ FGParkingList result(groundNetwork.allParkings());
+
+ GetParkingsPredicate pred(onlyAvailable, type, this);
+ FGParkingList::iterator it = std::remove_if(result.begin(), result.end(), pred);
+ result.erase(it, result.end());
+ return result;
+}
+
void FGAirportDynamics::setRwyUse(const FGRunwayPreference & ref)
{
rwyPrefs = ref;
private:
FGAirport* _ap;
- typedef std::set<PositionedID> ParkingSet;
+ typedef std::set<FGParkingRef> ParkingSet;
// if a parking item is in this set, it is occupied
ParkingSet occupiedParkings;
+
+
FGRunwayPreference rwyPrefs;
FGStartupController startupController;
FGGroundNetwork groundNetwork;
ParkingAssignment getAvailableParking(double radius, const std::string& fltype,
const std::string& acType, const std::string& airline);
- void setParkingAvailable(PositionedID guid, bool available);
+ void setParkingAvailable(FGParking* park, bool available);
- bool isParkingAvailable(PositionedID parking) const;
+ bool isParkingAvailable(FGParking* parking) const;
- FGParkingRef getParking(PositionedID i) const;
- void releaseParking(PositionedID id);
- std::string getParkingName(PositionedID i) const;
+ FGParkingRef getParking(FGParking* i) const;
+ void releaseParking(FGParking* id);
+
+ FGParkingList getParkings(bool onlyAvailable, const std::string& type) const;
/**
* Find a parking gate index by name. Note names are often not unique
* FGTaxiNode
*************************************************************************/
-FGTaxiNode::FGTaxiNode(PositionedID aGuid, const SGGeod& pos, bool aOnRunway, int aHoldType) :
- FGPositioned(aGuid, FGPositioned::PARKING, "", pos),
+FGTaxiNode::FGTaxiNode(int index, const SGGeod& pos, bool aOnRunway, int aHoldType) :
+ FGPositioned(TRANSIENT_ID, FGPositioned::PARKING, "", pos),
+ m_index(index),
isOnRunway(aOnRunway),
- holdType(aHoldType)
+ holdType(aHoldType),
+ m_isPushback(false)
{
}
SGGeod newPos = pos;
newPos.setElevationM(elevationEnd);
// this will call modifyPosition to update mPosition
- NavDataCache* cache = NavDataCache::instance();
- NavDataCache::Transaction txn(cache);
- cache->updatePosition(guid(), newPos);
- txn.commit();
+ modifyPosition(newPos);
}
}
return pos.getElevationFt();
}
+int FGTaxiNode::getIndex() const
+{
+ return m_index;
+}
+
+void FGTaxiNode::setIsPushback()
+{
+ m_isPushback = true;
+}
+
double FGTaxiNode::getElevationM()
{
return getElevationFt() * SG_FEET_TO_METER;
class FGTaxiNode : public FGPositioned
{
protected:
+ const int m_index;
+
bool isOnRunway;
int holdType;
+ bool m_isPushback;
public:
- FGTaxiNode(PositionedID aGuid, const SGGeod& pos, bool aOnRunway, int aHoldType);
+ FGTaxiNode(int index, const SGGeod& pos, bool aOnRunway, int aHoldType);
virtual ~FGTaxiNode();
void setElevation(double val);
double getElevationM ();
double getElevationFt();
- PositionedID getIndex() const { return guid(); };
+ int getIndex() const;
+
int getHoldPointType() const { return holdType; };
bool getIsOnRunway() const { return isOnRunway; };
+ bool isPushback() const { return m_isPushback; }
+
+ void setIsPushback();
};
#endif
* FGTaxiSegment
**************************************************************************/
-FGTaxiSegment::FGTaxiSegment(PositionedID aStart, PositionedID aEnd) :
+FGTaxiSegment::FGTaxiSegment(FGTaxiNode* aStart, FGTaxiNode* aEnd) :
startNode(aStart),
endNode(aEnd),
isActive(0),
FGTaxiNodeRef FGTaxiSegment::getEnd() const
{
- return FGPositioned::loadById<FGTaxiNode>(endNode);
+ return const_cast<FGTaxiNode*>(endNode);
}
FGTaxiNodeRef FGTaxiSegment::getStart() const
{
- return FGPositioned::loadById<FGTaxiNode>(startNode);
+ return const_cast<FGTaxiNode*>(startNode);
}
double FGTaxiSegment::getLength() const
/***************************************************************************
* FGTaxiRoute
**************************************************************************/
-bool FGTaxiRoute::next(PositionedID *nde, int *rte)
+bool FGTaxiRoute::next(FGTaxiNodeRef& node, int *rte)
{
if (nodes.size() != (routes.size()) + 1) {
SG_LOG(SG_GENERAL, SG_ALERT, "ALERT: Misconfigured TaxiRoute : " << nodes.size() << " " << routes.size());
}
if (currNode == nodes.end())
return false;
- *nde = *(currNode);
+ node = *(currNode);
if (currNode != nodes.begin()) {
*rte = *(currRoute);
currRoute++;
FGGroundNetwork::~FGGroundNetwork()
{
-// JMT 2012-09-8 - disabling the groundnet-caching as part of enabling the
-// navcache. The problem isn't the NavCache - it's that for the past few years,
-// we have not being running destructors on FGPositioned classes, and hence,
-// not running this code.
-// When I fix FGPositioned lifetimes (unloading-at-runtime support), this
-// will need to be re-visited so it can run safely during shutdown.
-#if 0
- saveElevationCache();
-#endif
+
BOOST_FOREACH(FGTaxiSegment* seg, segments) {
delete seg;
}
-}
-void FGGroundNetwork::saveElevationCache()
-{
-#if 0
- bool saveData = false;
- ofstream cachefile;
- if (fgGetBool("/sim/ai/groundnet-cache")) {
- SGPath cacheData(globals->get_fg_home());
- cacheData.append("ai");
- string airport = parent->getId();
-
- if ((airport) != "") {
- char buffer[128];
- ::snprintf(buffer, 128, "%c/%c/%c/",
- airport[0], airport[1], airport[2]);
- cacheData.append(buffer);
- if (!cacheData.exists()) {
- cacheData.create_dir(0755);
- }
- cacheData.append(airport + "-groundnet-cache.txt");
- cachefile.open(cacheData.str().c_str());
- saveData = true;
- }
- }
- cachefile << "[GroundNetcachedata:ref:2011:09:04]" << endl;
- for (IndexTaxiNodeMap::iterator node = nodes.begin();
- node != nodes.end(); node++) {
- if (saveData) {
- cachefile << node->second->getIndex () << " "
- << node->second->getElevationM (parent->getElevation()*SG_FEET_TO_METER) << " "
- << endl;
- }
- }
- if (saveData) {
- cachefile.close();
- }
-#endif
+ // owning references to ground-net nodes will also drop
}
void FGGroundNetwork::init(FGAirport* pr)
{
if (networkInitialized) {
+ SG_LOG(SG_GENERAL, SG_WARN, "duplicate ground-network init");
FGATCController::init();
- //cerr << "FGground network already initialized" << endl;
return;
}
nextSave = 0;
int index = 1;
- loadSegments();
// establish pairing of segments
BOOST_FOREACH(FGTaxiSegment* segment, segments) {
opp->oppositeDirection = segment;
}
}
-
- if (fgGetBool("/sim/ai/groundnet-cache")) {
- parseCache();
- }
networkInitialized = true;
}
-void FGGroundNetwork::loadSegments()
+FGTaxiNodeRef FGGroundNetwork::findNearestNode(const SGGeod & aGeod) const
{
- flightgear::NavDataCache* cache = flightgear::NavDataCache::instance();
-// iterate over all ground-net nodes in this airport
- BOOST_FOREACH(PositionedID node, cache->groundNetNodes(parent->guid(), false)) {
- // find all segments leaving the node
- BOOST_FOREACH(PositionedID end, cache->groundNetEdgesFrom(node, false)) {
- segments.push_back(new FGTaxiSegment(node, end));
+ double d = DBL_MAX;
+ SGVec3d cartPos = SGVec3d::fromGeod(aGeod);
+ FGTaxiNodeRef result;
+
+ FGTaxiNodeVector::const_iterator it;
+ for (it = m_nodes.begin(); it != m_nodes.end(); ++it) {
+ double localDistanceSqr = distSqr(cartPos, (*it)->cart());
+ if (localDistanceSqr < d) {
+ d = localDistanceSqr;
+ result = *it;
+ }
}
- }
+
+ return result;
}
-void FGGroundNetwork::parseCache()
+FGTaxiNodeRef FGGroundNetwork::findNearestNodeOnRunway(const SGGeod & aGeod, FGRunway* aRunway) const
{
- SGPath cacheData(globals->get_fg_home());
- cacheData.append("ai");
- string airport = parent->getId();
-
- if (airport.empty()) {
- return;
- }
-#if 0
- char buffer[128];
- ::snprintf(buffer, 128, "%c/%c/%c/",
- airport[0], airport[1], airport[2]);
- cacheData.append(buffer);
- if (!cacheData.exists()) {
- cacheData.create_dir(0755);
- }
- int index;
- double elev;
- cacheData.append(airport + "-groundnet-cache.txt");
- if (cacheData.exists()) {
- ifstream data(cacheData.c_str());
- string revisionStr;
- data >> revisionStr;
- if (revisionStr != "[GroundNetcachedata:ref:2011:09:04]") {
- SG_LOG(SG_GENERAL, SG_ALERT,"GroundNetwork Warning: discarding outdated cachefile " <<
- cacheData.c_str() << " for Airport " << airport);
- } else {
- for (IndexTaxiNodeMap::iterator i = nodes.begin();
- i != nodes.end();
- i++) {
- i->second->setElevation(parent->elevation() * SG_FEET_TO_METER);
- data >> index >> elev;
- if (data.eof())
- break;
- if (index != i->second->getIndex()) {
- SG_LOG(SG_GENERAL, SG_ALERT, "Index read from ground network cache at airport " << airport << " does not match index in the network itself");
- } else {
- i->second->setElevation(elev);
+ SG_UNUSED(aRunway);
+
+ double d = DBL_MAX;
+ SGVec3d cartPos = SGVec3d::fromGeod(aGeod);
+ FGTaxiNodeRef result = 0;
+ FGTaxiNodeVector::const_iterator it;
+ for (it = m_nodes.begin(); it != m_nodes.end(); ++it) {
+ if (!(*it)->getIsOnRunway())
+ continue;
+
+ double localDistanceSqr = distSqr(cartPos, (*it)->cart());
+ if (localDistanceSqr < d) {
+ d = localDistanceSqr;
+ result = *it;
}
- }
}
- }
-#endif
-}
-
-int FGGroundNetwork::findNearestNode(const SGGeod & aGeod) const
-{
- const bool onRunway = false;
- return NavDataCache::instance()->findGroundNetNode(parent->guid(), aGeod, onRunway);
-}
-int FGGroundNetwork::findNearestNodeOnRunway(const SGGeod & aGeod, FGRunway* aRunway) const
-{
- const bool onRunway = true;
- return NavDataCache::instance()->findGroundNetNode(parent->guid(), aGeod, onRunway, aRunway);
+ return result;
}
-FGTaxiNodeRef FGGroundNetwork::findNode(PositionedID idx) const
+const FGParkingList &FGGroundNetwork::allParkings() const
{
- return FGPositioned::loadById<FGTaxiNode>(idx);
+ return m_parkings;
}
FGTaxiSegment *FGGroundNetwork::findSegment(unsigned idx) const
}
}
-FGTaxiSegment* FGGroundNetwork::findSegment(PositionedID from, PositionedID to) const
+FGTaxiSegment* FGGroundNetwork::findSegment(const FGTaxiNode* from, const FGTaxiNode* to) const
{
if (from == 0) {
return NULL;
FGTaxiNodeRef previousNode;
};
-FGTaxiRoute FGGroundNetwork::findShortestRoute(PositionedID start, PositionedID end,
- bool fullSearch)
+FGTaxiRoute FGGroundNetwork::findShortestRoute(FGTaxiNode* start, FGTaxiNode* end, bool fullSearch)
{
+ if (!start || !end) {
+ throw sg_exception("Bad arguments to findShortestRoute");
+ }
//implements Dijkstra's algorithm to find shortest distance route from start to end
//taken from http://en.wikipedia.org/wiki/Dijkstra's_algorithm
- FGTaxiNodeVector unvisited;
- flightgear::NavDataCache* cache = flightgear::NavDataCache::instance();
+ FGTaxiNodeVector unvisited(m_nodes);
std::map<FGTaxiNode*, ShortestPathData> searchData;
-
- BOOST_FOREACH(PositionedID n, cache->groundNetNodes(parent->guid(), !fullSearch)) {
- unvisited.push_back(findNode(n));
- }
-
- FGTaxiNode *firstNode = findNode(start);
- if (!firstNode)
- {
- SG_LOG(SG_GENERAL, SG_ALERT,
- "Error in ground network. Failed to find first waypoint: " << start
- << " at " << ((parent) ? parent->getId() : "<unknown>"));
- return FGTaxiRoute();
- }
- searchData[firstNode].score = 0.0;
- FGTaxiNode *lastNode = findNode(end);
- if (!lastNode)
- {
- SG_LOG(SG_GENERAL, SG_ALERT,
- "Error in ground network. Failed to find last waypoint: " << end
- << " at " << ((parent) ? parent->getId() : "<unknown>"));
- return FGTaxiRoute();
- }
+ searchData[start].score = 0.0;
while (!unvisited.empty()) {
- FGTaxiNode *best = unvisited.front();
- BOOST_FOREACH(FGTaxiNode* i, unvisited) {
+ // find lowest scored unvisited
+ FGTaxiNodeRef best = unvisited.front();
+ BOOST_FOREACH(FGTaxiNodeRef i, unvisited) {
if (searchData[i].score < searchData[best].score) {
best = i;
}
remove(unvisited.begin(), unvisited.end(), best);
unvisited.erase(newend, unvisited.end());
- if (best == lastNode) { // found route or best not connected
+ if (best == end) { // found route or best not connected
break;
}
- BOOST_FOREACH(PositionedID targetId, cache->groundNetEdgesFrom(best->guid(), !fullSearch)) {
- FGTaxiNodeRef tgt = FGPositioned::loadById<FGTaxiNode>(targetId);
- double edgeLength = dist(best->cart(), tgt->cart());
- double alt = searchData[best].score + edgeLength + edgePenalty(tgt);
- if (alt < searchData[tgt].score) { // Relax (u,v)
- searchData[tgt].score = alt;
- searchData[tgt].previousNode = best;
+ BOOST_FOREACH(FGTaxiNodeRef target, segmentsFrom(best)) {
+ double edgeLength = dist(best->cart(), target->cart());
+ double alt = searchData[best].score + edgeLength + edgePenalty(target);
+ if (alt < searchData[target].score) { // Relax (u,v)
+ searchData[target].score = alt;
+ searchData[target].previousNode = best;
}
} // of outgoing arcs/segments from current best node iteration
} // of unvisited nodes remaining
- if (searchData[lastNode].score == HUGE_VAL) {
+ if (searchData[end].score == HUGE_VAL) {
// no valid route found
if (fullSearch) {
SG_LOG(SG_GENERAL, SG_ALERT,
}
// assemble route from backtrace information
- PositionedIDVec nodes;
+ FGTaxiNodeVector nodes;
intVec routes;
- FGTaxiNode *bt = lastNode;
+ FGTaxiNode *bt = end;
while (searchData[bt].previousNode != 0) {
- nodes.push_back(bt->guid());
- FGTaxiSegment *segment = findSegment(searchData[bt].previousNode->guid(), bt->guid());
+ nodes.push_back(bt);
+ FGTaxiSegment *segment = findSegment(searchData[bt].previousNode, bt);
int idx = segment->getIndex();
routes.push_back(idx);
bt = searchData[bt].previousNode;
nodes.push_back(start);
reverse(nodes.begin(), nodes.end());
reverse(routes.begin(), routes.end());
- return FGTaxiRoute(nodes, routes, searchData[lastNode].score, 0);
+ return FGTaxiRoute(nodes, routes, searchData[end].score, 0);
}
/* ATC Related Functions */
double heading, double speed, double alt,
double dt)
{
- time_t currentTime = time(NULL);
- if (nextSave < currentTime) {
- saveElevationCache();
- nextSave = currentTime + 100 + rand() % 200;
- }
// Check whether aircraft are on hold due to a preceding pushback. If so, make sure to
// Transmit air-to-ground "Ready to taxi request:
// Transmit ground to air approval / hold
}
}
+
+FGTaxiNodeRef FGGroundNetwork::findNodeByIndex(int index) const
+{
+ FGTaxiNodeVector::const_iterator it;
+ for (it = m_nodes.begin(); it != m_nodes.end(); ++it) {
+ if ((*it)->getIndex() == index) {
+ return *it;
+ }
+ }
+
+ return FGTaxiNodeRef();
+}
+
+
/**
Scan for a speed adjustment change. Find the nearest aircraft that is in front
and adjust speed when we get too close. Only do this when current position and/or
//current->setState(0);
}
+void FGGroundNetwork::addSegment(const FGTaxiNodeRef &from, const FGTaxiNodeRef &to)
+{
+ FGTaxiSegment* seg = new FGTaxiSegment(from, to);
+ segments.push_back(seg);
+
+ FGTaxiNodeVector::iterator it = std::find(m_nodes.begin(), m_nodes.end(), from);
+ if (it == m_nodes.end()) {
+ m_nodes.push_back(from);
+ }
+
+ it = std::find(m_nodes.begin(), m_nodes.end(), to);
+ if (it == m_nodes.end()) {
+ m_nodes.push_back(to);
+ }
+}
+
+void FGGroundNetwork::addParking(const FGParkingRef &park)
+{
+ m_parkings.push_back(park);
+
+
+ FGTaxiNodeVector::iterator it = std::find(m_nodes.begin(), m_nodes.end(), park);
+ if (it == m_nodes.end()) {
+ m_nodes.push_back(park);
+ }
+}
+
+FGTaxiNodeVector FGGroundNetwork::segmentsFrom(const FGTaxiNodeRef &from) const
+{
+ FGTaxiNodeVector result;
+ FGTaxiSegmentVector::const_iterator it;
+ for (it = segments.begin(); it != segments.end(); ++it) {
+ if ((*it)->getStart() == from) {
+ result.push_back((*it)->getEnd());
+ }
+ }
+
+ return result;
+}
+
/**
* Check whether situations occur where the current aircraft is waiting for itself
* due to higher order interactions.
#include "parking.hxx"
#include <ATC/trafficcontrol.hxx>
+class FGAirportDynamicsXMLLoader;
+
class Block
{
private:
class FGTaxiSegment
{
private:
- const PositionedID startNode;
- const PositionedID endNode;
+ // weak (non-owning) pointers deliberately here:
+ // the ground-network owns the nodes
+ const FGTaxiNode* startNode;
+ const FGTaxiNode* endNode;
bool isActive;
BlockList blockTimes;
int index;
- FGTaxiSegment *oppositeDirection;
+ FGTaxiSegment *oppositeDirection; // also deliberatley weak
friend class FGGroundNetwork;
public:
- FGTaxiSegment(PositionedID start, PositionedID end);
+ FGTaxiSegment(FGTaxiNode* start, FGTaxiNode* end);
void setIndex (int val) {
index = val;
class FGTaxiRoute
{
private:
- PositionedIDVec nodes;
+ FGTaxiNodeVector nodes;
intVec routes;
double distance;
- PositionedIDVec::iterator currNode;
+ FGTaxiNodeVector::iterator currNode;
intVec::iterator currRoute;
public:
currRoute = routes.begin();
};
- FGTaxiRoute(const PositionedIDVec& nds, intVec rts, double dist, int dpth) {
+ FGTaxiRoute(const FGTaxiNodeVector& nds, intVec rts, double dist, int dpth) {
nodes = nds;
routes = rts;
distance = dist;
bool empty () {
return nodes.empty();
};
- bool next(PositionedID *nde, int *rte);
+ bool next(FGTaxiNodeRef& nde, int *rte);
void first() {
currNode = nodes.begin();
class FGGroundNetwork : public FGATCController
{
private:
+ friend class FGAirportDynamicsXMLLoader;
+
bool hasNetwork;
bool networkInitialized;
time_t nextSave;
FGTowerController *towerController;
FGAirport *parent;
+ FGParkingList m_parkings;
+ FGTaxiNodeVector m_nodes;
+
+ FGTaxiNodeRef findNodeByIndex(int index) const;
//void printRoutingError(string);
double heading, double speed, double alt);
- void parseCache();
-
- void loadSegments();
+ void addSegment(const FGTaxiNodeRef& from, const FGTaxiNodeRef& to);
+ void addParking(const FGParkingRef& park);
+
+ FGTaxiNodeVector segmentsFrom(const FGTaxiNodeRef& from) const;
+
public:
FGGroundNetwork();
~FGGroundNetwork();
towerController = twrCtrlr;
};
- int findNearestNode(const SGGeod& aGeod) const;
- int findNearestNodeOnRunway(const SGGeod& aGeod, FGRunway* aRunway = NULL) const;
+ FGTaxiNodeRef findNearestNode(const SGGeod& aGeod) const;
+ FGTaxiNodeRef findNearestNodeOnRunway(const SGGeod& aGeod, FGRunway* aRunway = NULL) const;
+
+ FGTaxiSegment *findSegment(unsigned int idx) const;
+
+ const FGParkingList& allParkings() const;
- FGTaxiNodeRef findNode(PositionedID idx) const;
- FGTaxiSegment *findSegment(unsigned idx) const;
-
/**
* Find the taxiway segment joining two (ground-net) nodes. Returns
* NULL if no such segment exists.
- * It is permitted to pass 0 for the 'to' ID, indicating that any
+ * It is permitted to pass HULL for the 'to' indicating that any
* segment originating at 'from' is acceptable.
*/
- FGTaxiSegment* findSegment(PositionedID from, PositionedID to) const;
+ FGTaxiSegment *findSegment(const FGTaxiNode* from, const FGTaxiNode* to) const;
- FGTaxiRoute findShortestRoute(PositionedID start, PositionedID end, bool fullSearch=true);
+ FGTaxiRoute findShortestRoute(FGTaxiNode* start, FGTaxiNode* end, bool fullSearch=true);
virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute,
double lat, double lon, double hdg, double spd, double alt,
virtual std::string getName();
virtual void update(double dt);
- void saveElevationCache();
void addVersion(int v) {version = v; };
};
* FGParking
********************************************************************************/
-FGParking::FGParking(PositionedID aGuid, const SGGeod& pos,
+FGParking::FGParking(int index,
+ const SGGeod& pos,
double aHeading, double aRadius,
- const std::string& name, const std::string& aType,
- const std::string& codes,
- PositionedID pushBackNode) :
- FGTaxiNode(aGuid, pos, false, 0),
+ const std::string& name,
+ const std::string& aType,
+ const std::string& codes) :
+ FGTaxiNode(index, pos, false, 0),
heading(aHeading),
radius(aRadius),
parkingName(name),
type(aType),
- airlineCodes(codes),
- pushBackPoint(pushBackNode)
+ airlineCodes(codes)
{
}
FGParking::~FGParking()
{
}
+
+void FGParking::setPushBackPoint(const FGTaxiNodeRef &node)
+{
+ pushBackPoint = node;
+}
#include <memory> // for std::auto_ptr
#include "gnnode.hxx"
-
+#include <Airports/airports_fwd.hxx>
class FGParking : public FGTaxiNode
{
const std::string parkingName;
const std::string type;
const std::string airlineCodes;
- const PositionedID pushBackPoint;
+ FGTaxiNodeRef pushBackPoint;
SG_DISABLE_COPY(FGParking);
public:
- FGParking(PositionedID aGuid, const SGGeod& pos,
+ FGParking(int index,
+ const SGGeod& pos,
double heading, double radius,
const std::string& name, const std::string& type,
- const std::string& codes,
- PositionedID pushBackNode);
+ const std::string& codes);
virtual ~FGParking();
double getHeading () const { return heading; };
// TODO do parkings have different name and ident?
virtual const std::string& name() const { return parkingName; }
- int getPushBackPoint () { return pushBackPoint; };
+ void setPushBackPoint(const FGTaxiNodeRef& node);
+ FGTaxiNodeRef getPushBackPoint () { return pushBackPoint; };
bool operator< (const FGParking &other) const {
return radius < other.radius; };
return;
}
- flightgear::NavDataCache* cache = flightgear::NavDataCache::instance();
- //if (!cache->isCachedFileModified(path) || cache->isReadOnly()) {
- // return;
- //}
-
+
SG_LOG(SG_NAVAID, SG_INFO, "reading groundnet data from " << path);
SGTimeStamp t;
try {
- flightgear::NavDataCache::Transaction txn(cache);
- t.stamp();
- {
- // drop all current data
- cache->dropGroundnetFor(d->parent()->guid());
-
FGAirportDynamicsXMLLoader visitor(d);
readXML(path.str(), visitor);
- } // ensure visitor is destroyed so its destructor runs
- cache->stampCacheFile(path);
- txn.commit();
} catch (sg_exception& e) {
SG_LOG(SG_NAVAID, SG_INFO, "parsing groundnet XML failed:" << e.getFormattedMessage());
}
}
}
+#if 0
m_ui->parkingCombo->clear();
FGAirportDynamics* dynamics = apt->getDynamics();
PositionedIDVec parkings = NavDataCache::instance()->airportItemsOfType(m_location->guid(),
m_ui->airportDiagram->addParking(park);
}
}
+#endif
} else if (m_locationIsLatLon) {
m_ui->stack->setCurrentIndex(1);
globals->append_fg_scenery(root.str());
}
- // might need to drop ground-nets from the DB. Also need to drop
- // them from memory, but this is tricky since FGAirportDynamics holds
- // an instance directly, and AI code may have pointers to ground-net
- // nodes. For now we'll leave-in memory versions untouched.
- flightgear::NavDataCache::instance()->dropGroundnetsIfRequired();
-
return true;
}
}
}
- // depend on when the NavCache was initialised, scenery paths may not
- // have been setup. This is a safe place to consistently check the value,
- // and drop the ground-nets if something has changed
- cache->dropGroundnetsIfRequired();
-
FGTACANList *channellist = new FGTACANList;
globals->set_channellist( channellist );
// The parking will be released after this function returns.
// As a temporary measure, I'll try to reserve the parking via the atc_manager, which should work, because it uses the same
// mechanism as the AI traffic code.
- dcs->setParkingAvailable(pka.parking()->guid(), false);
+ dcs->setParkingAvailable(pka.parking(), false);
fgApplyStartOffset(pka.parking()->geod(), pka.parking()->getHeading());
return true;
}
#ifndef FG_NAVCACHE_SCHEMA_HXX
#define FG_NAVCACHE_SCHEMA_HXX
-const int SCHEMA_VERSION = 14;
+const int SCHEMA_VERSION = 15;
#define SCHEMA_SQL \
"CREATE TABLE properties (key VARCHAR, value VARCHAR);" \
"CREATE INDEX airway_ident ON airway(ident);" \
\
"CREATE TABLE airway_edge (network INT,airway INT64,a INT64,b INT64);" \
-"CREATE INDEX airway_edge_from ON airway_edge(a);" \
-\
-"CREATE TABLE taxi_node (hold_type INT,on_runway BOOL,pushback BOOL);" \
-"CREATE TABLE parking (heading FLOAT,radius INT,gate_type VARCHAR," \
- "airlines VARCHAR,pushback INT64);" \
-"CREATE TABLE groundnet_edge (airport INT64,a INT64,b INT64);" \
-"CREATE INDEX groundnet_edge_airport ON groundnet_edge(airport);" \
-"CREATE INDEX groundnet_edge_from ON groundnet_edge(a);"
+"CREATE INDEX airway_edge_from ON airway_edge(a);"
#endif
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)
return n;
}
- FGPositioned* loadParking(sqlite3_int64 rowId,
- const string& name, const SGGeod& pos,
- PositionedID airport)
- {
- 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);
- reset(loadParkingPos);
-
- return new FGParking(rowId, pos, heading, radius, name, aircraftType, airlines, pushBack);
- }
-
- FGPositioned* loadTaxiNode(sqlite3_int64 rowId, const SGGeod& pos,
- PositionedID airport)
- {
- sqlite3_bind_int64(loadTaxiNodeStmt, 1, rowId);
- execSelect1(loadTaxiNodeStmt);
-
- int hold_type = sqlite3_column_int(loadTaxiNodeStmt, 0);
- bool onRunway = sqlite3_column_int(loadTaxiNodeStmt, 1);
- reset(loadTaxiNodeStmt);
-
- 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)
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.
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;
}
return false;
}
-bool NavDataCache::dropGroundnetsIfRequired()
-{
- string sceneryPaths = simgear::strutils::join(globals->get_fg_scenery(), ";");
- if (readStringProperty("scenery_paths") != sceneryPaths) {
- SG_LOG(SG_NAVCACHE, SG_INFO, "NavCache: scenery paths changed, dropping ground nets");
- dropAllGroundnets();
- writeStringProperty("scenery_paths", sceneryPaths);
- return true;
- }
-
- return false;
-}
-
NavDataCache::RebuildPhase NavDataCache::rebuild()
{
if (!d->rebuilder.get()) {
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);
- return result;
-}
-
-PositionedIDVec NavDataCache::groundNetEdgesFrom(PositionedID pos, bool onlyPushback)
-{
- sqlite3_stmt_ptr q = onlyPushback ? d->pushbackEdgesFrom : d->taxiEdgesFrom;
- sqlite3_bind_int64(q, 1, pos);
- return d->selectIds(q);
-}
-
-PositionedIDVec NavDataCache::findAirportParking(PositionedID airport, const std::string& flightType,
- int radius)
-{
- 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);
-}
-
-void NavDataCache::dropGroundnetFor(PositionedID aAirport)
-{
- sqlite3_stmt_ptr q = d->prepare("DELETE FROM parking WHERE rowid IN (SELECT rowid FROM positioned WHERE type=?1 AND airport=?2)");
- sqlite3_bind_int(q, 1, FGPositioned::PARKING);
- 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 OR type=?2) AND airport=?3)");
- sqlite3_bind_int(q, 1, FGPositioned::TAXI_NODE);
- 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");
- sqlite3_bind_int(q, 1, FGPositioned::TAXI_NODE);
- sqlite3_bind_int(q, 2, FGPositioned::PARKING);
- sqlite3_bind_int64(q, 3, aAirport);
- d->execUpdate(q);
-
- q = d->prepare("DELETE FROM groundnet_edge WHERE airport=?1");
- sqlite3_bind_int64(q, 1, aAirport);
- d->execUpdate(q);
-}
-
-void NavDataCache::dropAllGroundnets()
-{
- SG_LOG(SG_NAVCACHE, SG_INFO, "dropping ground-net data");
- beginTransaction();
- d->runSQL("DELETE FROM groundnet_edge");
- d->runSQL("DELETE FROM parking");
- d->runSQL("DELETE FROM taxi_node");
-
- sqlite3_stmt_ptr q = d->prepare("DELETE FROM positioned WHERE (type=?1 OR type=?2)");
- sqlite3_bind_int(q, 1, FGPositioned::TAXI_NODE);
- sqlite3_bind_int(q, 2, FGPositioned::PARKING);
- d->execUpdate(q);
- commitTransaction();
-}
bool NavDataCache::isReadOnly() const
{
* This can happen is the cache file is missing or damaged, or one of the
** global input files is changed.
*/
- bool isRebuildRequired();
-
- /**
- * check if cached scenery paths have changed, and if so, drop scenery-
- * dependant data such as ground-nets.
- */
- bool dropGroundnetsIfRequired();
+ bool isRebuildRequired();
enum RebuildPhase
{
*/
RebuildPhase rebuild();
- unsigned int rebuildPhaseCompletionPercentage() const;
- void setRebuildPhaseProgress(RebuildPhase ph, unsigned int percent = 0);
+ unsigned int rebuildPhaseCompletionPercentage() const;
+ void setRebuildPhaseProgress(RebuildPhase ph, unsigned int percent = 0);
bool isCachedFileModified(const SGPath& path) const;
void stampCacheFile(const SGPath& path);
PositionedID createPOI(FGPositioned::Type ty, const std::string& ident, const SGGeod& aPos);
bool removePOI(FGPositioned::Type ty, const std::string& aIdent);
-
- void dropGroundnetFor(PositionedID aAirport);
-
- /**
- * Remove all ground-nets globally from the cache.
- * This includes parking and taxi-nodes and edges between them. It's useful
- * when scenery paths change, since the ground-nets depend on the scenery.
- * Using this we can avoid havind to rebuild the entire cache.
- */
- void dropAllGroundnets();
-
- PositionedID insertParking(const std::string& name, const SGGeod& aPos,
- PositionedID aAirport,
- double aHeading, int aRadius, const std::string& aAircraftType,
- const std::string& aAirlines);
-
- void setParkingPushBackRoute(PositionedID parking, PositionedID pushBackNode);
-
- PositionedID insertTaxiNode(const SGGeod& aPos, PositionedID aAirport, int aHoldType, bool aOnRunway);
-
- void insertGroundnetEdge(PositionedID aAirport, PositionedID from, PositionedID to);
/// update the metar flag associated with an airport
void setAirportMetar(const std::string& icao, bool hasMetar);
*/
AirwayEdgeVec airwayEdgesFrom(int network, PositionedID pos);
-// ground-network
- PositionedIDVec groundNetNodes(PositionedID aAirport, bool onlyPushback);
- void markGroundnetAsPushback(PositionedID nodeId);
-
- PositionedID findGroundNetNode(PositionedID airport, const SGGeod& aPos,
- bool onRunway, FGRunway* aRunway = NULL);
- PositionedIDVec groundNetEdgesFrom(PositionedID pos, bool onlyPushback);
-
- PositionedIDVec findAirportParking(PositionedID airport, const std::string& flightType,
- int radius);
-
-
class Transaction
{
public:
return true;
}
+const PositionedID FGPositioned::TRANSIENT_ID = -2;
///////////////////////////////////////////////////////////////////////////////
FGPositioned::~FGPositioned()
{
-// std::cout << "destroying:" << mIdent << "/" << nameForType(mType) << std::endl;
}
FGPositioned*
class FGPositioned : public SGReferenced
{
public:
+ static const PositionedID TRANSIENT_ID;
typedef enum {
INVALID = 0,
}
FGAirportDynamics* dynamics = apt->getDynamics();
- PositionedIDVec parkings = flightgear::NavDataCache::instance()->airportItemsOfType(apt->guid(),
- FGPositioned::PARKING);
-
- BOOST_FOREACH(PositionedID parking, parkings) {
- // filter out based on availability and type
- if (onlyAvailable && !dynamics->isParkingAvailable(parking)) {
- continue;
- }
-
- FGParking* park = dynamics->getParking(parking);
- if (!type.empty() && (park->getType() != type)) {
- continue;
- }
-
+ FGParkingList parkings = dynamics->getParkings(onlyAvailable, type);
+ FGParkingList::const_iterator it;
+ for (it = parkings.begin(); it != parkings.end(); ++it) {
+ FGParkingRef park = *it;
const SGGeod& parkLoc = park->geod();
naRef ph = naNewHash(c);
hashset(c, ph, "name", stringToNasal(c, park->getName()));
{
std::string type = ctx.getArg<std::string>(0);
bool only_available = ctx.getArg<bool>(1);
-
FGAirportDynamics* dynamics = apt.getDynamics();
- PositionedIDVec parkings =
- flightgear::NavDataCache::instance()
- ->airportItemsOfType(apt.guid(), FGPositioned::PARKING);
-
- FGParkingList ret;
- BOOST_FOREACH(PositionedID parking, parkings)
- {
- // filter out based on availability and type
- if( only_available && !dynamics->isParkingAvailable(parking) )
- continue;
-
- FGParking* park = dynamics->getParking(parking);
- if( !type.empty() && (park->getType() != type) )
- continue;
-
- ret.push_back(park);
- }
-
- return ret;
+ return dynamics->getParkings(only_available, type);
}
/**