1
0
Fork 0

Checkpoint - ground-net skips the cache

This commit is contained in:
James Turner 2015-12-01 00:01:27 +00:00
parent d56fbfd415
commit fc887b106b
27 changed files with 378 additions and 704 deletions

View file

@ -187,7 +187,7 @@ private:
time_t arrivalTime; // For AI/ATC purposes.
int leg;
ParkingAssignment gate;
PositionedID lastNodeVisited;
FGTaxiNodeRef lastNodeVisited;
std::string activeRunway;
std::string name;
bool isValid;

View file

@ -247,11 +247,11 @@ bool FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight,
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
@ -262,17 +262,15 @@ bool FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight,
// 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;
}
@ -280,8 +278,8 @@ bool FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight,
}
FGTaxiRoute taxiRoute;
if ( runwayId != 0 )
taxiRoute = gn->findShortestRoute(node, runwayId);
if ( runwayNode )
taxiRoute = gn->findShortestRoute(node, runwayNode);
if (taxiRoute.empty()) {
createDefaultTakeoffTaxi(ac, apt, rwy);
@ -289,6 +287,8 @@ bool FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight,
}
taxiRoute.first();
FGTaxiNodeRef skipNode;
//bool isPushBackPoint = false;
if (firstFlight) {
// If this is called during initialization, randomly
@ -298,13 +298,13 @@ bool FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight,
// 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
}
}
@ -315,13 +315,11 @@ bool FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight,
// 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() << " ";
@ -388,11 +386,11 @@ bool FGAIFlightPlan::createLandingTaxi(FGAIAircraft * ac, FGAirport * apt,
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
@ -400,26 +398,25 @@ bool FGAIFlightPlan::createLandingTaxi(FGAIAircraft * ac, FGAirport * apt,
// 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);
@ -638,10 +635,9 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
}
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) {
@ -967,14 +963,13 @@ bool FGAIFlightPlan::createLanding(FGAIAircraft * ac, FGAirport * apt,
}
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);

View file

@ -87,7 +87,7 @@ bool FGAIFlightPlan::createPushBack(FGAIAircraft *ac,
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) {
@ -96,15 +96,14 @@ bool FGAIFlightPlan::createPushBack(FGAIAircraft *ac,
}
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) {
@ -128,14 +127,14 @@ bool FGAIFlightPlan::createPushBack(FGAIAircraft *ac,
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();

View file

@ -109,7 +109,7 @@ void FGATCManager::init() {
// 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);

View file

@ -90,6 +90,7 @@ FGAirport::FGAirport( PositionedID aGuid,
FGAirport::~FGAirport()
{
SG_LOG(SG_NAVAID, SG_INFO, "deleting airport:" << ident());
delete _dynamics;
}

View file

@ -26,6 +26,7 @@
#include <Navaids/NavDataCache.hxx>
#include <Airports/dynamics.hxx>
#include <Airports/airport.hxx>
#include <Airports/groundnetwork.hxx>
using std::string;
@ -62,21 +63,21 @@ void FGAirportDynamicsXMLLoader::startXML () {
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());
}
}
@ -124,14 +125,16 @@ void FGAirportDynamicsXMLLoader::startParking(const XMLAttributes &atts)
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)
@ -168,15 +171,14 @@ 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)
@ -201,16 +203,28 @@ 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)

View file

@ -19,7 +19,7 @@
#include <simgear/xml/easyxml.hxx>
#include "dynamics.hxx"
#include <Navaids/positioned.hxx>
#include <Airports/parking.hxx>
class FGAirportDynamicsXMLLoader : public XMLVisitor {
public:
@ -43,19 +43,21 @@ private:
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

View file

@ -65,7 +65,7 @@ public:
~ParkingAssignmentPrivate()
{
airport->getDynamics()->releaseParking(parking->guid());
airport->getDynamics()->releaseParking(parking);
}
void release()
@ -81,8 +81,8 @@ public:
}
unsigned int refCount;
SGSharedPtr<FGParking> parking;
SGSharedPtr<FGAirport> airport;
FGParkingRef parking;
FGAirportRef airport;
};
ParkingAssignment::ParkingAssignment() :
@ -179,28 +179,29 @@ FGParking* FGAirportDynamics::innerGetAvailableParking(double radius, const stri
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;
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;
}
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;
}
}
setParkingAvailable(pk, false);
return parking;
}
return NULL;
return NULL;
}
ParkingAssignment FGAirportDynamics::getAvailableParking(double radius, const string & flType,
@ -226,46 +227,34 @@ ParkingAssignment FGAirportDynamics::getAvailableParking(double radius, const st
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()) {
@ -275,6 +264,41 @@ void FGAirportDynamics::releaseParking(PositionedID id)
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;

View file

@ -58,10 +58,12 @@ class FGAirportDynamics {
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;
@ -134,13 +136,14 @@ public:
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

View file

@ -14,10 +14,12 @@ using namespace flightgear;
* 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)
{
}
@ -45,16 +47,23 @@ double FGTaxiNode::getElevationFt()
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;

View file

@ -24,11 +24,14 @@
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);
@ -36,9 +39,13 @@ public:
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

View file

@ -65,7 +65,7 @@ using flightgear::NavDataCache;
* FGTaxiSegment
**************************************************************************/
FGTaxiSegment::FGTaxiSegment(PositionedID aStart, PositionedID aEnd) :
FGTaxiSegment::FGTaxiSegment(FGTaxiNode* aStart, FGTaxiNode* aEnd) :
startNode(aStart),
endNode(aEnd),
isActive(0),
@ -84,12 +84,12 @@ SGGeod FGTaxiSegment::getCenter() const
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
@ -145,7 +145,7 @@ void FGTaxiSegment::unblock(time_t now)
/***************************************************************************
* 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());
@ -153,7 +153,7 @@ bool FGTaxiRoute::next(PositionedID *nde, int *rte)
}
if (currNode == nodes.end())
return false;
*nde = *(currNode);
node = *(currNode);
if (currNode != nodes.begin()) {
*rte = *(currRoute);
currRoute++;
@ -191,63 +191,19 @@ FGGroundNetwork::FGGroundNetwork() :
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;
}
@ -257,7 +213,6 @@ void FGGroundNetwork::init(FGAirport* pr)
nextSave = 0;
int index = 1;
loadSegments();
// establish pairing of segments
BOOST_FOREACH(FGTaxiSegment* segment, segments) {
@ -274,87 +229,53 @@ void FGGroundNetwork::init(FGAirport* pr)
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;
void FGGroundNetwork::parseCache()
{
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);
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;
}
}
}
}
#endif
return result;
}
int FGGroundNetwork::findNearestNode(const SGGeod & aGeod) const
FGTaxiNodeRef FGGroundNetwork::findNearestNodeOnRunway(const SGGeod & aGeod, FGRunway* aRunway) const
{
const bool onRunway = false;
return NavDataCache::instance()->findGroundNetNode(parent->guid(), aGeod, onRunway);
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;
}
}
return result;
}
int FGGroundNetwork::findNearestNodeOnRunway(const SGGeod & aGeod, FGRunway* aRunway) const
const FGParkingList &FGGroundNetwork::allParkings() const
{
const bool onRunway = true;
return NavDataCache::instance()->findGroundNetNode(parent->guid(), aGeod, onRunway, aRunway);
}
FGTaxiNodeRef FGGroundNetwork::findNode(PositionedID idx) const
{
return FGPositioned::loadById<FGTaxiNode>(idx);
return m_parkings;
}
FGTaxiSegment *FGGroundNetwork::findSegment(unsigned idx) const
@ -367,7 +288,7 @@ 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;
@ -405,41 +326,22 @@ public:
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;
}
@ -450,22 +352,21 @@ FGTaxiRoute FGGroundNetwork::findShortestRoute(PositionedID start, PositionedID
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,
@ -477,13 +378,13 @@ FGTaxiRoute FGGroundNetwork::findShortestRoute(PositionedID start, PositionedID
}
// 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;
@ -492,7 +393,7 @@ FGTaxiRoute FGGroundNetwork::findShortestRoute(PositionedID start, PositionedID
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 */
@ -611,11 +512,6 @@ void FGGroundNetwork::updateAircraftInformation(int id, double lat, double lon,
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
@ -688,6 +584,20 @@ void FGGroundNetwork::updateAircraftInformation(int id, double lat, double lon,
}
}
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
@ -984,6 +894,46 @@ void FGGroundNetwork::checkHoldPosition(int id, double lat,
//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.

View file

@ -32,6 +32,8 @@
#include "parking.hxx"
#include <ATC/trafficcontrol.hxx>
class FGAirportDynamicsXMLLoader;
class Block
{
private:
@ -54,18 +56,20 @@ public:
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;
@ -107,10 +111,10 @@ public:
class FGTaxiRoute
{
private:
PositionedIDVec nodes;
FGTaxiNodeVector nodes;
intVec routes;
double distance;
PositionedIDVec::iterator currNode;
FGTaxiNodeVector::iterator currNode;
intVec::iterator currRoute;
public:
@ -120,7 +124,7 @@ 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;
@ -151,7 +155,7 @@ public:
bool empty () {
return nodes.empty();
};
bool next(PositionedID *nde, int *rte);
bool next(FGTaxiNodeRef& nde, int *rte);
void first() {
currNode = nodes.begin();
@ -171,6 +175,8 @@ public:
class FGGroundNetwork : public FGATCController
{
private:
friend class FGAirportDynamicsXMLLoader;
bool hasNetwork;
bool networkInitialized;
time_t nextSave;
@ -187,6 +193,10 @@ private:
FGTowerController *towerController;
FGAirport *parent;
FGParkingList m_parkings;
FGTaxiNodeVector m_nodes;
FGTaxiNodeRef findNodeByIndex(int index) const;
//void printRoutingError(string);
@ -196,9 +206,11 @@ private:
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();
@ -214,21 +226,22 @@ public:
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,
@ -245,7 +258,6 @@ public:
virtual std::string getName();
virtual void update(double dt);
void saveElevationCache();
void addVersion(int v) {version = v; };
};

View file

@ -36,21 +36,26 @@
* 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;
}

View file

@ -36,7 +36,7 @@
#include <memory> // for std::auto_ptr
#include "gnnode.hxx"
#include <Airports/airports_fwd.hxx>
class FGParking : public FGTaxiNode
{
@ -46,15 +46,15 @@ private:
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; };
@ -67,7 +67,8 @@ public:
// 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; };

View file

@ -49,25 +49,12 @@ void XMLLoader::load(FGAirportDynamics* d)
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());
}

View file

@ -699,6 +699,7 @@ void LocationWidget::onLocationChanged()
}
}
#if 0
m_ui->parkingCombo->clear();
FGAirportDynamics* dynamics = apt->getDynamics();
PositionedIDVec parkings = NavDataCache::instance()->airportItemsOfType(m_location->guid(),
@ -717,6 +718,7 @@ void LocationWidget::onLocationChanged()
m_ui->airportDiagram->addParking(park);
}
}
#endif
} else if (m_locationIsLatLon) {
m_ui->stack->setCurrentIndex(1);

View file

@ -1410,12 +1410,6 @@ do_set_scenery_paths(const SGPropertyNode* arg)
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;
}

View file

@ -616,11 +616,6 @@ fgInitNav ()
}
}
// 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 );

View file

@ -261,7 +261,7 @@ static bool fgSetPosFromAirportIDandParkpos( const string& id, const string& par
// 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;
}

View file

@ -1,7 +1,7 @@
#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);" \
@ -31,14 +31,7 @@ const int SCHEMA_VERSION = 14;
"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

View file

@ -600,47 +600,6 @@ 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)
@ -758,36 +717,6 @@ public:
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)
@ -949,12 +878,6 @@ 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.
@ -1043,12 +966,6 @@ FGPositioned* NavDataCache::NavDataCachePrivate::loadById(sqlite3_int64 rowid,
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;
}
@ -1200,19 +1117,6 @@ bool NavDataCache::isRebuildRequired()
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()) {
@ -2081,162 +1985,6 @@ PositionedID NavDataCache::findNavaidForRunway(PositionedID runway, FGPositioned
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
{

View file

@ -68,13 +68,7 @@ public:
* 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
{
@ -91,8 +85,8 @@ public:
*/
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);
@ -140,27 +134,6 @@ public:
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);
@ -269,18 +242,6 @@ public:
*/
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:

View file

@ -64,6 +64,7 @@ static bool validateFilter(FGPositioned::Filter* filter)
return true;
}
const PositionedID FGPositioned::TRANSIENT_ID = -2;
///////////////////////////////////////////////////////////////////////////////
@ -82,7 +83,6 @@ FGPositioned::FGPositioned( PositionedID aGuid,
FGPositioned::~FGPositioned()
{
// std::cout << "destroying:" << mIdent << "/" << nameForType(mType) << std::endl;
}
FGPositioned*

View file

@ -42,6 +42,7 @@ namespace flightgear { class NavDataCache; }
class FGPositioned : public SGReferenced
{
public:
static const PositionedID TRANSIENT_ID;
typedef enum {
INVALID = 0,

View file

@ -1352,20 +1352,10 @@ static naRef f_airport_parking(naContext c, naRef me, int argc, naRef* args)
}
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()));

View file

@ -208,27 +208,8 @@ f_airport_parking(FGAirport& apt, nasal::CallContext ctx)
{
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);
}
/**