Overhaul the ground-net / parking code.
Use the nav-data-cache to cache groundnet information, including parking positions and the taxi-node graph.
This commit is contained in:
parent
72131a4a49
commit
afcdbd3158
26 changed files with 1035 additions and 798 deletions
|
@ -862,7 +862,8 @@ bool FGAIAircraft::handleAirportEndPoints(FGAIWaypoint* prev, time_t now) {
|
|||
//cerr << trafficRef->getCallSign() << " has passed waypoint " << prev->name << " at speed " << speed << endl;
|
||||
//cerr << "Passing waypoint : " << prev->getName() << endl;
|
||||
if (prev->contains("PushBackPoint")) {
|
||||
dep->getDynamics()->releaseParking(fp->getGate());
|
||||
// clearing the parking assignment will release the gate
|
||||
fp->setGate(ParkingAssignment());
|
||||
AccelTo(0.0);
|
||||
//setTaxiClearanceRequest(true);
|
||||
}
|
||||
|
@ -1209,18 +1210,15 @@ void FGAIAircraft::updatePitchAngleTarget() {
|
|||
}
|
||||
}
|
||||
|
||||
string FGAIAircraft::atGate() {
|
||||
string tmp("");
|
||||
if (fp->getLeg() < 3) {
|
||||
if (trafficRef) {
|
||||
if (fp->getGate() > 0) {
|
||||
FGParking *park =
|
||||
trafficRef->getDepartureAirport()->getDynamics()->getParking(fp->getGate());
|
||||
tmp = park->getName();
|
||||
}
|
||||
}
|
||||
string FGAIAircraft::atGate()
|
||||
{
|
||||
if ((fp->getLeg() < 3) && trafficRef) {
|
||||
if (fp->getParkingGate()) {
|
||||
return fp->getParkingGate()->ident();
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
|
||||
return string();
|
||||
}
|
||||
|
||||
void FGAIAircraft::handleATCRequests() {
|
||||
|
|
|
@ -105,9 +105,8 @@ FGAIFlightPlan::FGAIFlightPlan()
|
|||
start_time = 0;
|
||||
arrivalTime = 0;
|
||||
leg = 10;
|
||||
gateId = 0;
|
||||
lastNodeVisited = 0;
|
||||
taxiRoute = 0;
|
||||
// taxiRoute = 0;
|
||||
wpt_iterator = waypoints.begin();
|
||||
isValid = true;
|
||||
}
|
||||
|
@ -121,9 +120,8 @@ FGAIFlightPlan::FGAIFlightPlan(const string& filename)
|
|||
start_time = 0;
|
||||
arrivalTime = 0;
|
||||
leg = 10;
|
||||
gateId = 0;
|
||||
lastNodeVisited = 0;
|
||||
taxiRoute = 0;
|
||||
// taxiRoute = 0;
|
||||
|
||||
|
||||
isValid = parseProperties(filename);
|
||||
|
@ -161,9 +159,8 @@ FGAIFlightPlan::FGAIFlightPlan(FGAIAircraft *ac,
|
|||
start_time = start;
|
||||
arrivalTime = 0;
|
||||
leg = 10;
|
||||
gateId = 0;
|
||||
lastNodeVisited = 0;
|
||||
taxiRoute = 0;
|
||||
// taxiRoute = 0;
|
||||
|
||||
if (parseProperties(p)) {
|
||||
isValid = true;
|
||||
|
@ -176,16 +173,7 @@ FGAIFlightPlan::FGAIFlightPlan(FGAIAircraft *ac,
|
|||
FGAIFlightPlan::~FGAIFlightPlan()
|
||||
{
|
||||
deleteWaypoints();
|
||||
delete taxiRoute;
|
||||
|
||||
// if we're parked at a gate, release it
|
||||
if (gateId >= 0) {
|
||||
FGAirport* apt = (leg >= 7) ? arrival : departure;
|
||||
if (apt) {
|
||||
SG_LOG(SG_AI, SG_INFO, "releasing parking gate " << gateId << " at " << apt->ident());
|
||||
apt->getDynamics()->releaseParking(gateId);
|
||||
}
|
||||
}
|
||||
//delete taxiRoute;
|
||||
}
|
||||
|
||||
void FGAIFlightPlan::createWaypoints(FGAIAircraft *ac,
|
||||
|
@ -227,7 +215,6 @@ void FGAIFlightPlan::createWaypoints(FGAIAircraft *ac,
|
|||
isValid = create(ac, dep, arr, leg, alt, speed, lat, lon,
|
||||
firstLeg, radius, fltType, acType, airline, dist);
|
||||
wpt_iterator = waypoints.begin();
|
||||
|
||||
}
|
||||
|
||||
bool FGAIFlightPlan::parseProperties(const std::string& filename)
|
||||
|
@ -454,14 +441,6 @@ void FGAIFlightPlan::restart()
|
|||
wpt_iterator = waypoints.begin();
|
||||
}
|
||||
|
||||
|
||||
void FGAIFlightPlan::deleteTaxiRoute()
|
||||
{
|
||||
delete taxiRoute;
|
||||
taxiRoute = 0;
|
||||
}
|
||||
|
||||
|
||||
int FGAIFlightPlan::getRouteIndex(int i) {
|
||||
if ((i > 0) && (i < (int)waypoints.size())) {
|
||||
return waypoints[i]->getRouteIndex();
|
||||
|
@ -470,7 +449,6 @@ int FGAIFlightPlan::getRouteIndex(int i) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
double FGAIFlightPlan::checkTrackLength(string wptName) {
|
||||
// skip the first two waypoints: first one is behind, second one is partially done;
|
||||
double trackDistance = 0;
|
||||
|
@ -494,3 +472,13 @@ void FGAIFlightPlan::shortenToFirst(unsigned int number, string name)
|
|||
}
|
||||
(waypoints.back())->setName((waypoints.back())->getName() + name);
|
||||
}
|
||||
|
||||
void FGAIFlightPlan::setGate(ParkingAssignment pka)
|
||||
{
|
||||
gate = pka;
|
||||
}
|
||||
|
||||
FGParking* FGAIFlightPlan::getParkingGate()
|
||||
{
|
||||
return gate.parking();
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
#include <simgear/compiler.h>
|
||||
#include <simgear/math/SGMath.hxx>
|
||||
#include <simgear/structure/SGSharedPtr.hxx>
|
||||
#include <Navaids/positioned.hxx>
|
||||
#include <Airports/dynamics.hxx>
|
||||
|
||||
// forward decls
|
||||
class FGTaxiRoute;
|
||||
|
@ -139,8 +141,7 @@ public:
|
|||
|
||||
void setLeg(int val) { leg = val;}
|
||||
void setTime(time_t st) { start_time = st; }
|
||||
int getGate() const { return gateId; }
|
||||
void setGate(int id) { gateId = id; };
|
||||
|
||||
|
||||
double getLeadInAngle() const { return leadInAngle; }
|
||||
const std::string& getRunway() const;
|
||||
|
@ -149,9 +150,9 @@ public:
|
|||
bool getRepeat(void) const { return repeat; }
|
||||
void restart(void);
|
||||
int getNrOfWayPoints() { return waypoints.size(); }
|
||||
int getRouteIndex(int i); // returns the AI related index of this current routes.
|
||||
FGTaxiRoute *getTaxiRoute() { return taxiRoute; }
|
||||
void deleteTaxiRoute();
|
||||
|
||||
int getRouteIndex(int i); // returns the AI related index of this current routes.
|
||||
|
||||
std::string getRunway() { return activeRunway; }
|
||||
bool isActive(time_t time) {return time >= this->getStartTime();}
|
||||
|
||||
|
@ -172,6 +173,8 @@ public:
|
|||
|
||||
void shortenToFirst(unsigned int number, std::string name);
|
||||
|
||||
void setGate(ParkingAssignment pka);
|
||||
FGParking* getParkingGate();
|
||||
private:
|
||||
FGAIFlightPlan *sid;
|
||||
typedef std::vector <FGAIWaypoint*> wpt_vector_type;
|
||||
|
@ -188,9 +191,9 @@ private:
|
|||
time_t start_time;
|
||||
time_t arrivalTime; // For AI/ATC purposes.
|
||||
int leg;
|
||||
int gateId, lastNodeVisited;
|
||||
ParkingAssignment gate;
|
||||
PositionedID lastNodeVisited;
|
||||
std::string activeRunway;
|
||||
FGTaxiRoute *taxiRoute;
|
||||
std::string name;
|
||||
bool isValid;
|
||||
FGAirportRef departure, arrival;
|
||||
|
|
|
@ -214,9 +214,9 @@ bool FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight,
|
|||
// and place the model at the location of the gate.
|
||||
if (firstFlight)
|
||||
{
|
||||
gateId = apt->getDynamics()->getAvailableParking(radius, fltType,
|
||||
gate = apt->getDynamics()->getAvailableParking(radius, fltType,
|
||||
acType, airline);
|
||||
if (gateId < 0) {
|
||||
if (!gate.isValid()) {
|
||||
SG_LOG(SG_AI, SG_WARN, "Could not find parking for a " <<
|
||||
acType <<
|
||||
" of flight type " << fltType <<
|
||||
|
@ -245,7 +245,7 @@ bool FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight,
|
|||
}
|
||||
|
||||
intVec ids;
|
||||
int runwayId = 0;
|
||||
PositionedID runwayId = 0;
|
||||
if (gn->getVersion() > 0) {
|
||||
runwayId = gn->findNearestNodeOnRunway(runwayTakeoff);
|
||||
} else {
|
||||
|
@ -256,75 +256,74 @@ bool FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight,
|
|||
// fallback mechanism for this.
|
||||
// Starting from gate 0 in this case is a bit of a hack
|
||||
// which requires a more proper solution later on.
|
||||
delete taxiRoute;
|
||||
taxiRoute = new FGTaxiRoute;
|
||||
// delete taxiRoute;
|
||||
// taxiRoute = new FGTaxiRoute;
|
||||
|
||||
// Determine which node to start from.
|
||||
int node = 0;
|
||||
PositionedID node = 0;
|
||||
// Find out which node to start from
|
||||
FGParking *park = apt->getDynamics()->getParking(gateId);
|
||||
FGParking *park = gate.parking();
|
||||
if (park) {
|
||||
node = park->getPushBackPoint();
|
||||
}
|
||||
|
||||
if (node == -1) {
|
||||
node = gateId;
|
||||
}
|
||||
// HAndle case where parking doens't have a node
|
||||
if ((node == 0) && park) {
|
||||
if (firstFlight) {
|
||||
node = gateId;
|
||||
} else {
|
||||
node = lastNodeVisited;
|
||||
if (node == -1) {
|
||||
node = park->guid();
|
||||
} else if (node == 0) {
|
||||
// HAndle case where parking doens't have a node
|
||||
if (firstFlight) {
|
||||
node = park->guid();
|
||||
} else {
|
||||
node = lastNodeVisited;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*taxiRoute = gn->findShortestRoute(node, runwayId);
|
||||
|
||||
FGTaxiRoute taxiRoute = gn->findShortestRoute(node, runwayId);
|
||||
intVecIterator i;
|
||||
|
||||
if (taxiRoute->empty()) {
|
||||
if (taxiRoute.empty()) {
|
||||
createDefaultTakeoffTaxi(ac, apt, rwy);
|
||||
return true;
|
||||
}
|
||||
|
||||
taxiRoute->first();
|
||||
taxiRoute.first();
|
||||
//bool isPushBackPoint = false;
|
||||
if (firstFlight) {
|
||||
// If this is called during initialization, randomly
|
||||
// skip a number of waypoints to get a more realistic
|
||||
// taxi situation.
|
||||
int nrWaypointsToSkip = rand() % taxiRoute->size();
|
||||
int nrWaypointsToSkip = rand() % taxiRoute.size();
|
||||
// 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);
|
||||
taxiRoute.next(&node);
|
||||
}
|
||||
apt->getDynamics()->releaseParking(gateId);
|
||||
|
||||
gate.release(); // free up our gate as required
|
||||
} else {
|
||||
if (taxiRoute->size() > 1) {
|
||||
taxiRoute->next(&node); // chop off the first waypoint, because that is already the last of the pushback route
|
||||
if (taxiRoute.size() > 1) {
|
||||
taxiRoute.next(&node); // chop off the first waypoint, because that is already the last of the pushback route
|
||||
}
|
||||
}
|
||||
|
||||
// push each node on the taxi route as a waypoint
|
||||
int route;
|
||||
// int route;
|
||||
//cerr << "Building taxi route" << endl;
|
||||
while (taxiRoute->next(&node, &route)) {
|
||||
while (taxiRoute.next(&node)) {
|
||||
char buffer[10];
|
||||
snprintf(buffer, 10, "%d", node);
|
||||
snprintf(buffer, 10, "%lld", node);
|
||||
FGTaxiNode *tn =
|
||||
apt->getDynamics()->getGroundNetwork()->findNode(node);
|
||||
FGAIWaypoint *wpt =
|
||||
createOnGround(ac, buffer, tn->geod(), apt->getElevation(),
|
||||
ac->getPerformance()->vTaxi());
|
||||
wpt->setRouteIndex(route);
|
||||
// wpt->setRouteIndex(route);
|
||||
//cerr << "Nodes left " << taxiRoute->nodesLeft() << " ";
|
||||
if (taxiRoute->nodesLeft() == 1) {
|
||||
if (taxiRoute.nodesLeft() == 1) {
|
||||
// Note that we actually have hold points in the ground network, but this is just an initial test.
|
||||
//cerr << "Setting departurehold point: " << endl;
|
||||
wpt->setName( wpt->getName() + string("DepartureHold"));
|
||||
}
|
||||
if (taxiRoute->nodesLeft() == 0) {
|
||||
if (taxiRoute.nodesLeft() == 0) {
|
||||
wpt->setName(wpt->getName() + string("Accel"));
|
||||
}
|
||||
pushBackWaypoint(wpt);
|
||||
|
@ -356,9 +355,8 @@ void FGAIFlightPlan::createDefaultLandingTaxi(FGAIAircraft * ac,
|
|||
ac->getPerformance()->vTaxi());
|
||||
pushBackWaypoint(wpt);
|
||||
|
||||
FGParking* parkPos = aAirport->getDynamics()->getParking(gateId);
|
||||
if (parkPos) {
|
||||
wpt = createOnGround(ac, "ENDtaxi", parkPos->geod(), airportElev,
|
||||
if (gate.isValid()) {
|
||||
wpt = createOnGround(ac, "ENDtaxi", gate.parking()->geod(), airportElev,
|
||||
ac->getPerformance()->vTaxi());
|
||||
pushBackWaypoint(wpt);
|
||||
}
|
||||
|
@ -370,12 +368,10 @@ bool FGAIFlightPlan::createLandingTaxi(FGAIAircraft * ac, FGAirport * apt,
|
|||
const string & acType,
|
||||
const string & airline)
|
||||
{
|
||||
gateId = apt->getDynamics()->getAvailableParking(radius, fltType,
|
||||
gate = apt->getDynamics()->getAvailableParking(radius, fltType,
|
||||
acType, airline);
|
||||
|
||||
SGGeod lastWptPos =
|
||||
SGGeod::fromDeg(waypoints.back()->getLongitude(),
|
||||
waypoints.back()->getLatitude());
|
||||
SGGeod lastWptPos = waypoints.back()->getPos();
|
||||
FGGroundNetwork *gn = apt->getDynamics()->getGroundNetwork();
|
||||
|
||||
// Find a route from runway end to parking/gate.
|
||||
|
@ -385,7 +381,7 @@ bool FGAIFlightPlan::createLandingTaxi(FGAIAircraft * ac, FGAirport * apt,
|
|||
}
|
||||
|
||||
intVec ids;
|
||||
int runwayId = 0;
|
||||
PositionedID runwayId = 0;
|
||||
if (gn->getVersion() == 1) {
|
||||
runwayId = gn->findNearestNodeOnRunway(lastWptPos);
|
||||
} else {
|
||||
|
@ -396,34 +392,35 @@ bool FGAIFlightPlan::createLandingTaxi(FGAIAircraft * ac, FGAirport * apt,
|
|||
// fallback mechanism for this.
|
||||
// Starting from gate 0 is a bit of a hack...
|
||||
//FGTaxiRoute route;
|
||||
delete taxiRoute;
|
||||
taxiRoute = new FGTaxiRoute;
|
||||
if (gateId >= 0)
|
||||
*taxiRoute = gn->findShortestRoute(runwayId, gateId);
|
||||
// delete taxiRoute;
|
||||
// taxiRoute = new FGTaxiRoute;
|
||||
FGTaxiRoute taxiRoute;
|
||||
if (gate.isValid())
|
||||
taxiRoute = gn->findShortestRoute(runwayId, gate.parking()->guid());
|
||||
else
|
||||
*taxiRoute = gn->findShortestRoute(runwayId, 0);
|
||||
taxiRoute = gn->findShortestRoute(runwayId, 0);
|
||||
intVecIterator i;
|
||||
|
||||
if (taxiRoute->empty()) {
|
||||
if (taxiRoute.empty()) {
|
||||
createDefaultLandingTaxi(ac, apt);
|
||||
return true;
|
||||
}
|
||||
|
||||
int node;
|
||||
taxiRoute->first();
|
||||
int size = taxiRoute->size();
|
||||
PositionedID node;
|
||||
taxiRoute.first();
|
||||
int size = taxiRoute.size();
|
||||
// Omit the last two waypoints, as
|
||||
// those are created by createParking()
|
||||
int route;
|
||||
// int route;
|
||||
for (int i = 0; i < size - 2; i++) {
|
||||
taxiRoute->next(&node, &route);
|
||||
taxiRoute.next(&node);
|
||||
char buffer[10];
|
||||
snprintf(buffer, 10, "%d", node);
|
||||
snprintf(buffer, 10, "%lld", node);
|
||||
FGTaxiNode *tn = gn->findNode(node);
|
||||
FGAIWaypoint *wpt =
|
||||
createOnGround(ac, buffer, tn->geod(), apt->getElevation(),
|
||||
ac->getPerformance()->vTaxi());
|
||||
wpt->setRouteIndex(route);
|
||||
// wpt->setRouteIndex(route);
|
||||
pushBackWaypoint(wpt);
|
||||
}
|
||||
return true;
|
||||
|
@ -638,21 +635,20 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
|
|||
origin = current;
|
||||
}
|
||||
|
||||
|
||||
double dAlt = 0; // = alt - (apt->getElevation() + 2000);
|
||||
FGTaxiNode * tn = 0;
|
||||
if (apt->getDynamics()->getGroundNetwork()) {
|
||||
int node = apt->getDynamics()->getGroundNetwork()->findNearestNode(refPoint);
|
||||
tn = apt->getDynamics()->getGroundNetwork()->findNode(node);
|
||||
}
|
||||
|
||||
if (tn) {
|
||||
dAlt = alt - ((tn->getElevationFt(apt->getElevation())) + 2000);
|
||||
dAlt = alt - ((tn->getElevationFt()) + 2000);
|
||||
} else {
|
||||
dAlt = alt - (apt->getElevation() + 2000);
|
||||
}
|
||||
|
||||
|
||||
double nPoints = 100;
|
||||
|
||||
char buffer[16];
|
||||
|
||||
// The descent path contains the following phases:
|
||||
|
@ -814,7 +810,7 @@ bool FGAIFlightPlan::createDescent(FGAIAircraft * ac, FGAirport * apt,
|
|||
//FGTaxiNode * tn = apt->getDynamics()->getGroundNetwork()->findNearestNode(initialTarget);
|
||||
double currentAltitude = 0;
|
||||
if (tn) {
|
||||
currentAltitude = (tn->getElevationFt(apt->getElevation())) + 2000;
|
||||
currentAltitude = (tn->getElevationFt()) + 2000;
|
||||
} else {
|
||||
currentAltitude = apt->getElevation() + 2000;
|
||||
}
|
||||
|
@ -906,12 +902,12 @@ bool FGAIFlightPlan::createLanding(FGAIAircraft * ac, FGAirport * apt,
|
|||
{
|
||||
double vTouchdown = ac->getPerformance()->vTouchdown();
|
||||
double vTaxi = ac->getPerformance()->vTaxi();
|
||||
double decel = ac->getPerformance()->deceleration() * 1.4;
|
||||
double decel = ac->getPerformance()->decelerationOnGround();
|
||||
double vApproach = ac->getPerformance()->vApproach();
|
||||
|
||||
double vTouchdownMetric = (vTouchdown * SG_NM_TO_METER) / 3600;
|
||||
double vTaxiMetric = (vTaxi * SG_NM_TO_METER) / 3600;
|
||||
double decelMetric = (decel * SG_NM_TO_METER) / 3600;
|
||||
double vTouchdownMetric = vTouchdown * SG_KT_TO_MPS;
|
||||
double vTaxiMetric = vTaxi * SG_KT_TO_MPS;
|
||||
double decelMetric = decel * SG_KT_TO_MPS;
|
||||
|
||||
char buffer[12];
|
||||
FGRunway * rwy = apt->getRunwayByIdent(activeRunway);
|
||||
|
@ -996,15 +992,14 @@ bool FGAIFlightPlan::createParking(FGAIAircraft * ac, FGAirport * apt,
|
|||
double aptElev = apt->getElevation();
|
||||
double vTaxi = ac->getPerformance()->vTaxi();
|
||||
double vTaxiReduced = vTaxi * (2.0 / 3.0);
|
||||
FGParking* parking = apt->getDynamics()->getParking(gateId);
|
||||
if (!parking) {
|
||||
if (!gate.isValid()) {
|
||||
wpt = createOnGround(ac, "END-Parking", apt->geod(), aptElev,
|
||||
vTaxiReduced);
|
||||
pushBackWaypoint(wpt);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
FGParking* parking = gate.parking();
|
||||
double heading = SGMiscd::normalizePeriodic(0, 360, parking->getHeading() + 180.0);
|
||||
double az; // unused
|
||||
SGGeod pos;
|
||||
|
|
|
@ -49,7 +49,6 @@ bool FGAIFlightPlan::createPushBack(FGAIAircraft *ac,
|
|||
double vTaxi = ac->getPerformance()->vTaxi();
|
||||
double vTaxiBackward = vTaxi * (-2.0/3.0);
|
||||
double vTaxiReduced = vTaxi * (2.0/3.0);
|
||||
FGTaxiRoute *pushBackRoute;
|
||||
// Active runway can be conditionally set by ATC, so at the start of a new flight, this
|
||||
// must be reset.
|
||||
activeRunway.clear();
|
||||
|
@ -63,9 +62,9 @@ bool FGAIFlightPlan::createPushBack(FGAIAircraft *ac,
|
|||
|
||||
// establish the parking position / gate if required
|
||||
if (firstFlight) {
|
||||
gateId = dep->getDynamics()->getAvailableParking(radius, fltType,
|
||||
gate = dep->getDynamics()->getAvailableParking(radius, fltType,
|
||||
aircraftType, airline);
|
||||
if (gateId < 0) {
|
||||
if (!gate.isValid()) {
|
||||
SG_LOG(SG_AI, SG_WARN, "Warning: Could not find parking for a " <<
|
||||
aircraftType <<
|
||||
" of flight type " << fltType <<
|
||||
|
@ -73,47 +72,47 @@ bool FGAIFlightPlan::createPushBack(FGAIAircraft *ac,
|
|||
" at airport " << dep->getId());
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
dep->getDynamics()->getParking(gateId);
|
||||
}
|
||||
|
||||
if (gateId < 0) {
|
||||
if (!gate.isValid()) {
|
||||
createPushBackFallBack(ac, firstFlight, dep,
|
||||
radius, fltType, aircraftType, airline);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
FGParking *parking = dep->getDynamics()->getParking(gateId);
|
||||
int pushBackNode = parking->getPushBackPoint();
|
||||
|
||||
pushBackRoute = parking->getPushBackRoute();
|
||||
if ((pushBackNode > 0) && (pushBackRoute == 0)) { // Load the already established route for this gate
|
||||
int node, rte;
|
||||
FGTaxiRoute route;
|
||||
//cerr << "Creating push-back for " << gateId << " (" << parking->getName() << ") using push-back point " << pushBackNode << endl;
|
||||
route = dep->getDynamics()->getGroundNetwork()->findShortestRoute(gateId, pushBackNode, false);
|
||||
parking->setPushBackRoute(std::auto_ptr<FGTaxiRoute>(new FGTaxiRoute(route)));
|
||||
|
||||
pushBackRoute = parking->getPushBackRoute();
|
||||
int size = pushBackRoute->size();
|
||||
|
||||
FGGroundNetwork* groundNet = dep->getDynamics()->getGroundNetwork();
|
||||
FGParking *parking = gate.parking();
|
||||
if (parking && parking->getPushBackPoint() > 0) {
|
||||
FGTaxiRoute route = groundNet->findShortestRoute(parking->guid(), parking->getPushBackPoint(), false);
|
||||
|
||||
int size = route.size();
|
||||
if (size < 2) {
|
||||
SG_LOG(SG_AI, SG_ALERT, "Push back route from gate " << gateId << " has only " << size << " nodes.");
|
||||
SG_LOG(SG_AI, SG_ALERT, "Using " << pushBackNode);
|
||||
SG_LOG(SG_AI, SG_ALERT, "Push back route from gate " << parking->ident() << " has only " << size << " nodes.");
|
||||
SG_LOG(SG_AI, SG_ALERT, "Using " << parking->getPushBackPoint());
|
||||
}
|
||||
pushBackRoute->first();
|
||||
while (pushBackRoute->next(&node, &rte))
|
||||
|
||||
route.first();
|
||||
PositionedID node, previous= 0;
|
||||
|
||||
while (route.next(&node))
|
||||
{
|
||||
//FGTaxiNode *tn = apt->getDynamics()->getGroundNetwork()->findSegment(node)->getEnd();
|
||||
char buffer[10];
|
||||
snprintf (buffer, 10, "%d", node);
|
||||
FGTaxiNode *tn = dep->getDynamics()->getGroundNetwork()->findNode(node);
|
||||
//ids.pop_back();
|
||||
//wpt = new waypoint;
|
||||
snprintf (buffer, 10, "%lld", node);
|
||||
FGTaxiNode *tn = groundNet->findNode(node);
|
||||
FGAIWaypoint *wpt = createOnGround(ac, string(buffer), tn->geod(), dep->getElevation(), vTaxiBackward);
|
||||
|
||||
wpt->setRouteIndex(rte);
|
||||
|
||||
if (previous) {
|
||||
FGTaxiSegment* segment = groundNet->findSegment(previous, node);
|
||||
wpt->setRouteIndex(segment->getIndex());
|
||||
} else {
|
||||
// not on the route yet, make up a unique segment ID
|
||||
int x = (int) tn->guid();
|
||||
wpt->setRouteIndex(x);
|
||||
}
|
||||
|
||||
pushBackWaypoint(wpt);
|
||||
previous = node;
|
||||
}
|
||||
// some special considerations for the last point:
|
||||
waypoints.back()->setName(string("PushBackPoint"));
|
||||
|
@ -123,36 +122,32 @@ bool FGAIFlightPlan::createPushBack(FGAIAircraft *ac,
|
|||
ac->setTaxiClearanceRequest(false);
|
||||
double az2 = 0.0;
|
||||
|
||||
//cerr << "Creating final push forward point for gate " << gateId << endl;
|
||||
FGTaxiNode *tn = dep->getDynamics()->getGroundNetwork()->findNode(gateId);
|
||||
// there aren't any routes for this parking.
|
||||
// in cases like these we should flag the gate as being inoperative and return false
|
||||
if (tn->arcs().empty()) {
|
||||
SG_LOG(SG_AI, SG_ALERT, "Gate " << gateId << "doesn't seem to have routes associated with it.");
|
||||
parking->setAvailable(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
FGTaxiSegment* pushForwardSegment = tn->arcs().front();
|
||||
lastNodeVisited = pushForwardSegment->getEnd()->getIndex();
|
||||
double distance = pushForwardSegment->getLength();
|
||||
FGTaxiSegment* pushForwardSegment = dep->getDynamics()->getGroundNetwork()->findSegment(parking->guid(), 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;
|
||||
}
|
||||
|
||||
double parkingHeading = parking->getHeading();
|
||||
|
||||
for (int i = 1; i < 10; i++) {
|
||||
SGGeod pushForwardPt;
|
||||
SGGeodesy::direct(parking->geod(), parkingHeading,
|
||||
((i / 10.0) * distance), pushForwardPt, az2);
|
||||
char buffer[16];
|
||||
snprintf(buffer, 16, "pushback-%02d", i);
|
||||
FGAIWaypoint *wpt = createOnGround(ac, string(buffer), pushForwardPt, dep->getElevation(), vTaxiReduced);
|
||||
lastNodeVisited = pushForwardSegment->getEnd()->getIndex();
|
||||
double distance = pushForwardSegment->getLength();
|
||||
|
||||
wpt->setRouteIndex(pushForwardSegment->getIndex());
|
||||
pushBackWaypoint(wpt);
|
||||
}
|
||||
// cerr << "Done " << endl;
|
||||
waypoints.back()->setName(string("PushBackPoint"));
|
||||
// cerr << "Done assinging new name" << endl;
|
||||
double parkingHeading = parking->getHeading();
|
||||
|
||||
for (int i = 1; i < 10; i++) {
|
||||
SGGeod pushForwardPt;
|
||||
SGGeodesy::direct(parking->geod(), parkingHeading,
|
||||
((i / 10.0) * distance), pushForwardPt, az2);
|
||||
char buffer[16];
|
||||
snprintf(buffer, 16, "pushback-%02d", i);
|
||||
FGAIWaypoint *wpt = createOnGround(ac, string(buffer), pushForwardPt, dep->getElevation(), vTaxiReduced);
|
||||
|
||||
wpt->setRouteIndex(pushForwardSegment->getIndex());
|
||||
pushBackWaypoint(wpt);
|
||||
}
|
||||
|
||||
waypoints.back()->setName(string("PushBackPoint"));
|
||||
// cerr << "Done assinging new name" << endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -107,6 +107,11 @@ double PerformanceData::actualSpeed(FGAIAircraft* ac, double tgt_speed, double d
|
|||
return speed;
|
||||
}
|
||||
|
||||
double PerformanceData::decelerationOnGround() const
|
||||
{
|
||||
return _deceleration * BRAKE_SETTING;
|
||||
}
|
||||
|
||||
double PerformanceData::actualBankAngle(FGAIAircraft* ac, double tgt_roll, double dt) {
|
||||
// check maximum bank angle
|
||||
if (fabs(tgt_roll) > _maxbank)
|
||||
|
|
|
@ -46,6 +46,7 @@ public:
|
|||
inline double vTouchdown () { return _vTouchdown; };
|
||||
inline double vCruise () { return _vCruise; };
|
||||
|
||||
double decelerationOnGround() const;
|
||||
private:
|
||||
double _acceleration;
|
||||
double _deceleration;
|
||||
|
|
|
@ -101,12 +101,11 @@ void FGATCManager::init() {
|
|||
FGAirport *apt = FGAirport::findByIdent(airport);
|
||||
if (apt && onGround) {// && !runway.empty()) {
|
||||
FGAirportDynamics* dcs = apt->getDynamics();
|
||||
int park_index = dcs->getNrOfParkings() - 1;
|
||||
//cerr << "found information: " << runway << " " << airport << ": parking = " << parking << endl;
|
||||
fp = new FGAIFlightPlan;
|
||||
while (park_index >= 0 && dcs->getParkingName(park_index) != parking) park_index--;
|
||||
ParkingAssignment pk(dcs->getParkingByName(parking));
|
||||
|
||||
// No valid parking location, so either at the runway or at a random location.
|
||||
if (parking.empty() || (park_index < 0)) {
|
||||
if (!pk.isValid()) {
|
||||
if (!runway.empty()) {
|
||||
controller = apt->getDynamics()->getTowerController();
|
||||
int stationFreq = apt->getDynamics()->getTowerFrequency(2);
|
||||
|
@ -134,12 +133,11 @@ void FGATCManager::init() {
|
|||
leg = 1;
|
||||
//double, lat, lon, head; // Unused variables;
|
||||
//int getId = apt->getDynamics()->getParking(gateId, &lat, &lon, &head);
|
||||
FGParking* parking = dcs->getParking(park_index);
|
||||
aircraftRadius = parking->getRadius();
|
||||
string fltType = parking->getType(); // gate / ramp, ga, etc etc.
|
||||
aircraftRadius = pk.parking()->getRadius();
|
||||
string fltType = pk.parking()->getType(); // gate / ramp, ga, etc etc.
|
||||
string aircraftType; // Unused.
|
||||
string airline; // Currently used for gate selection, but a fallback mechanism will apply when not specified.
|
||||
fp->setGate(park_index);
|
||||
fp->setGate(pk);
|
||||
if (!(fp->createPushBack(&ai_ac,
|
||||
false,
|
||||
apt,
|
||||
|
|
|
@ -1363,7 +1363,7 @@ void FGStartupController::render(bool visible)
|
|||
} else {
|
||||
elevationStart = ((i)->getAircraft()->_getAltitude() * SG_FEET_TO_METER);
|
||||
}
|
||||
double elevationEnd = segment->getEnd()->getElevationM(parent->getElevation()*SG_FEET_TO_METER);
|
||||
double elevationEnd = segment->getEnd()->getElevationM();
|
||||
if ((elevationEnd == 0) || (elevationEnd == parent->getElevation())) {
|
||||
SGGeod center2 = end;
|
||||
center2.setElevationM(SG_MAX_ELEVATION_M);
|
||||
|
@ -1425,8 +1425,8 @@ void FGStartupController::render(bool visible)
|
|||
obj_trans->setDataVariance(osg::Object::STATIC);
|
||||
FGTaxiSegment *segment = parent->getGroundNetwork()->findSegment(k);
|
||||
|
||||
double elevationStart = segment->getStart()->getElevationM(parent->getElevation()*SG_FEET_TO_METER);
|
||||
double elevationEnd = segment->getEnd ()->getElevationM(parent->getElevation()*SG_FEET_TO_METER);
|
||||
double elevationStart = segment->getStart()->getElevationM();
|
||||
double elevationEnd = segment->getEnd ()->getElevationM();
|
||||
if ((elevationStart == 0) || (elevationStart == parent->getElevation())) {
|
||||
SGGeod center2 = segment->getStart()->geod();
|
||||
center2.setElevationM(SG_MAX_ELEVATION_M);
|
||||
|
|
|
@ -19,9 +19,14 @@
|
|||
|
||||
#include <cstdlib>
|
||||
#include <cstring> // for strcmp
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include "dynamicloader.hxx"
|
||||
|
||||
#include <Navaids/NavDataCache.hxx>
|
||||
#include <Airports/dynamics.hxx>
|
||||
#include <Airports/simple.hxx>
|
||||
|
||||
/*****************************************************************************
|
||||
* Helper function for parsing position string
|
||||
****************************************************************************/
|
||||
|
@ -53,8 +58,25 @@ void FGAirportDynamicsXMLLoader::startXML () {
|
|||
//cout << "FGAirportDynamicsLoader::Start XML" << endl;
|
||||
}
|
||||
|
||||
void FGAirportDynamicsXMLLoader::endXML () {
|
||||
//cout << "End XML" << endl;
|
||||
void FGAirportDynamicsXMLLoader::endXML ()
|
||||
{
|
||||
std::map<PositionedID, int>::iterator it;
|
||||
flightgear::NavDataCache* cache = flightgear::NavDataCache::instance();
|
||||
|
||||
for (it = _parkingPushbacks.begin(); it != _parkingPushbacks.end(); ++it) {
|
||||
std::map<int, PositionedID>::iterator j = _idMap.find(it->second);
|
||||
if (j == _idMap.end()) {
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "bad groundnet, no node for index:" << it->first);
|
||||
continue;
|
||||
}
|
||||
|
||||
cache->setParkingPushBackRoute(it->first, j->second);
|
||||
}
|
||||
|
||||
BOOST_FOREACH(PositionedID id, _unreferencedNodes) {
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "unreferenced groundnet node:" << id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void FGAirportDynamicsXMLLoader::startParking(const XMLAttributes &atts)
|
||||
|
@ -100,10 +122,14 @@ void FGAirportDynamicsXMLLoader::startParking(const XMLAttributes &atts)
|
|||
|
||||
SGGeod pos(SGGeod::fromDeg(processPosition(lon), processPosition(lat)));
|
||||
|
||||
FGParking* pk = new FGParking(0, index, pos, heading, radius,
|
||||
gateName + gateNumber, type, airlineCodes);
|
||||
pk->setPushBackPoint(pushBackRoute);
|
||||
_dynamics->addParking(pk);
|
||||
PositionedID guid = flightgear::NavDataCache::instance()->insertParking(gateName + gateNumber, pos,
|
||||
_dynamics->parent()->guid(),
|
||||
heading, radius, type, airlineCodes);
|
||||
if (pushBackRoute > 0) {
|
||||
_parkingPushbacks[guid] = pushBackRoute;
|
||||
}
|
||||
|
||||
_idMap[index] = guid;
|
||||
}
|
||||
|
||||
void FGAirportDynamicsXMLLoader::startNode(const XMLAttributes &atts)
|
||||
|
@ -140,9 +166,15 @@ void FGAirportDynamicsXMLLoader::startNode(const XMLAttributes &atts)
|
|||
}
|
||||
}
|
||||
|
||||
if (_idMap.find(index) != _idMap.end()) {
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "duplicate ground-net index:" << index);
|
||||
}
|
||||
|
||||
SGGeod pos(SGGeod::fromDeg(processPosition(lon), processPosition(lat)));
|
||||
FGTaxiNode* taxiNode = new FGTaxiNode(0, index, pos, onRunway, holdPointType);
|
||||
_dynamics->getGroundNetwork()->addNode(taxiNode);
|
||||
PositionedID guid = flightgear::NavDataCache::instance()->insertTaxiNode(pos,
|
||||
_dynamics->parent()->guid(), holdPointType, onRunway);
|
||||
_idMap[index] = guid;
|
||||
_unreferencedNodes.insert(guid);
|
||||
}
|
||||
|
||||
void FGAirportDynamicsXMLLoader::startArc(const XMLAttributes &atts)
|
||||
|
@ -161,7 +193,22 @@ void FGAirportDynamicsXMLLoader::startArc(const XMLAttributes &atts)
|
|||
isPushBackRoute = std::atoi(atts.getValue(i)) != 0;
|
||||
}
|
||||
|
||||
_dynamics->getGroundNetwork()->addSegment(new FGTaxiSegment(begin, end, isPushBackRoute));
|
||||
IntPair e(begin, end);
|
||||
if (_arcSet.find(e) != _arcSet.end()) {
|
||||
SG_LOG(SG_GENERAL, SG_WARN, _dynamics->parent()->ident() << " ground-net: skipping duplicate edge:" << begin << "->" << end);
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
void FGAirportDynamicsXMLLoader::startElement (const char * name, const XMLAttributes &atts)
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <simgear/xml/easyxml.hxx>
|
||||
|
||||
#include "dynamics.hxx"
|
||||
#include <Navaids/positioned.hxx>
|
||||
|
||||
class FGAirportDynamicsXMLLoader : public XMLVisitor {
|
||||
public:
|
||||
|
@ -41,6 +42,20 @@ private:
|
|||
|
||||
FGAirportDynamics* _dynamics;
|
||||
string value;
|
||||
|
||||
// map from local (groundnet.xml) to global (nav-cache) IDs for nodes
|
||||
std::map<int, PositionedID> _idMap;
|
||||
|
||||
// data integrity - watch for unreferenced nodes and duplicated edges
|
||||
typedef std::pair<int, int> IntPair;
|
||||
std::set<IntPair> _arcSet;
|
||||
|
||||
std::set<PositionedID> _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;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include <Main/fg_props.hxx>
|
||||
#include <Airports/runways.hxx>
|
||||
#include <ATCDCL/ATCutils.hxx>
|
||||
#include <Navaids/NavDataCache.hxx>
|
||||
|
||||
#include "simple.hxx"
|
||||
#include "dynamics.hxx"
|
||||
|
@ -49,6 +50,105 @@ using std::vector;
|
|||
using std::sort;
|
||||
using std::random_shuffle;
|
||||
|
||||
class ParkingAssignment::ParkingAssignmentPrivate
|
||||
{
|
||||
public:
|
||||
ParkingAssignmentPrivate(FGParking* pk, FGAirport* apt) :
|
||||
refCount(0),
|
||||
parking(pk),
|
||||
airport(apt)
|
||||
{
|
||||
assert(pk);
|
||||
assert(apt);
|
||||
retain(); // initial count of 1
|
||||
}
|
||||
|
||||
~ParkingAssignmentPrivate()
|
||||
{
|
||||
airport->getDynamics()->releaseParking(parking->guid());
|
||||
}
|
||||
|
||||
void release()
|
||||
{
|
||||
if ((--refCount) == 0) {
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
void retain()
|
||||
{
|
||||
++refCount;
|
||||
}
|
||||
|
||||
unsigned int refCount;
|
||||
SGSharedPtr<FGParking> parking;
|
||||
SGSharedPtr<FGAirport> airport;
|
||||
};
|
||||
|
||||
ParkingAssignment::ParkingAssignment() :
|
||||
_sharedData(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
ParkingAssignment::~ParkingAssignment()
|
||||
{
|
||||
if (_sharedData) {
|
||||
_sharedData->release();
|
||||
}
|
||||
}
|
||||
|
||||
ParkingAssignment::ParkingAssignment(FGParking* pk, FGAirport* apt) :
|
||||
_sharedData(NULL)
|
||||
{
|
||||
if (pk) {
|
||||
_sharedData = new ParkingAssignmentPrivate(pk, apt);
|
||||
}
|
||||
}
|
||||
|
||||
ParkingAssignment::ParkingAssignment(const ParkingAssignment& aOther) :
|
||||
_sharedData(aOther._sharedData)
|
||||
{
|
||||
if (_sharedData) {
|
||||
_sharedData->retain();
|
||||
}
|
||||
}
|
||||
|
||||
void ParkingAssignment::operator=(const ParkingAssignment& aOther)
|
||||
{
|
||||
if (_sharedData == aOther._sharedData) {
|
||||
return; // self-assignment, special case
|
||||
}
|
||||
|
||||
if (_sharedData) {
|
||||
_sharedData->release();
|
||||
}
|
||||
|
||||
_sharedData = aOther._sharedData;
|
||||
if (_sharedData) {
|
||||
_sharedData->retain();
|
||||
}
|
||||
}
|
||||
|
||||
void ParkingAssignment::release()
|
||||
{
|
||||
if (_sharedData) {
|
||||
_sharedData->release();
|
||||
_sharedData = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool ParkingAssignment::isValid() const
|
||||
{
|
||||
return (_sharedData != NULL);
|
||||
}
|
||||
|
||||
FGParking* ParkingAssignment::parking() const
|
||||
{
|
||||
return _sharedData ? _sharedData->parking.ptr() : NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
FGAirportDynamics::FGAirportDynamics(FGAirport * ap):
|
||||
_ap(ap), rwyPrefs(ap),
|
||||
startupController (this),
|
||||
|
@ -70,96 +170,68 @@ FGAirportDynamics::~FGAirportDynamics()
|
|||
// Initialization required after XMLRead
|
||||
void FGAirportDynamics::init()
|
||||
{
|
||||
// This may seem a bit weird to first randomly shuffle the parkings
|
||||
// and then sort them again. However, parkings are sorted here by ascending
|
||||
// radius. Since many parkings have similar radii, with each radius class they will
|
||||
// still be allocated relatively systematically. Randomizing prior to sorting will
|
||||
// prevent any initial orderings to be destroyed, leading (hopefully) to a more
|
||||
// naturalistic gate assignment.
|
||||
random_shuffle(parkings.begin(), parkings.end());
|
||||
sort(parkings.begin(), parkings.end());
|
||||
// add the gate positions to the ground network.
|
||||
groundNetwork.setParent(_ap);
|
||||
groundNetwork.addNodes(&parkings);
|
||||
groundNetwork.init();
|
||||
groundNetwork.init(_ap);
|
||||
groundNetwork.setTowerController(&towerController);
|
||||
|
||||
}
|
||||
|
||||
int FGAirportDynamics::innerGetAvailableParking(double radius, const string & flType,
|
||||
const string & acType,
|
||||
FGParking* FGAirportDynamics::innerGetAvailableParking(double radius, const string & flType,
|
||||
const string & airline,
|
||||
bool skipEmptyAirlineCode)
|
||||
{
|
||||
BOOST_FOREACH(FGParking* i, parkings) {
|
||||
// Taken by another aircraft, or no airline codes
|
||||
if (!i->isAvailable()) {
|
||||
flightgear::NavDataCache* cache = flightgear::NavDataCache::instance();
|
||||
BOOST_FOREACH(PositionedID pk, cache->findAirportParking(_ap->guid(), flType, radius)) {
|
||||
if (!isParkingAvailable(pk)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (skipEmptyAirlineCode && i->getCodes().empty()) {
|
||||
FGParking* parking = getParking(pk);
|
||||
if (skipEmptyAirlineCode && parking->getCodes().empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// check airline codes match
|
||||
if (!airline.empty() && !i->getCodes().empty()) {
|
||||
if (i->getCodes().find(airline, 0) == string::npos) {
|
||||
if (!airline.empty() && !parking->getCodes().empty()) {
|
||||
if (parking->getCodes().find(airline, 0) == string::npos) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Type doesn't match
|
||||
if (i->getType() != flType) {
|
||||
continue;
|
||||
}
|
||||
// too small
|
||||
if (i->getRadius() < radius) {
|
||||
continue;
|
||||
}
|
||||
|
||||
i->setAvailable(false);
|
||||
return i->getIndex();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int FGAirportDynamics::getAvailableParking(double radius, const string & flType,
|
||||
const string & acType,
|
||||
const string & airline)
|
||||
{
|
||||
if (parkings.empty()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// most exact seach - airline codes must be present and match
|
||||
int result = innerGetAvailableParking(radius, flType, acType, airline, true);
|
||||
if (result >= 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// more tolerant - gates with empty airline codes are permitted
|
||||
result = innerGetAvailableParking(radius, flType, acType, airline, false);
|
||||
if (result >= 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// fallback - ignore the airline code entirely
|
||||
return innerGetAvailableParking(radius, flType, acType, string(), false);
|
||||
}
|
||||
|
||||
FGParking *FGAirportDynamics::getParking(int id)
|
||||
{
|
||||
BOOST_FOREACH(FGParking* i, parkings) {
|
||||
if (id == i->getIndex()) {
|
||||
return i;
|
||||
}
|
||||
setParkingAvailable(pk, false);
|
||||
return parking;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
string FGAirportDynamics::getParkingName(int id)
|
||||
ParkingAssignment FGAirportDynamics::getAvailableParking(double radius, const string & flType,
|
||||
const string & acType,
|
||||
const string & airline)
|
||||
{
|
||||
SG_UNUSED(acType); // sadly not used at the moment
|
||||
|
||||
// most exact seach - airline codes must be present and match
|
||||
FGParking* result = innerGetAvailableParking(radius, flType, airline, true);
|
||||
if (result) {
|
||||
return ParkingAssignment(result, _ap);
|
||||
}
|
||||
|
||||
// more tolerant - gates with empty airline codes are permitted
|
||||
result = innerGetAvailableParking(radius, flType, airline, false);
|
||||
if (result) {
|
||||
return ParkingAssignment(result, _ap);
|
||||
}
|
||||
|
||||
// fallback - ignore the airline code entirely
|
||||
result = innerGetAvailableParking(radius, flType, string(), false);
|
||||
return result ? ParkingAssignment(result, _ap) : ParkingAssignment();
|
||||
}
|
||||
|
||||
FGParking *FGAirportDynamics::getParking(PositionedID id) const
|
||||
{
|
||||
return static_cast<FGParking*>(flightgear::NavDataCache::instance()->loadById(id));
|
||||
}
|
||||
|
||||
string FGAirportDynamics::getParkingName(PositionedID id) const
|
||||
{
|
||||
FGParking* p = getParking(id);
|
||||
if (p) {
|
||||
|
@ -169,25 +241,38 @@ string FGAirportDynamics::getParkingName(int id)
|
|||
return string();
|
||||
}
|
||||
|
||||
int FGAirportDynamics::findParkingByName(const std::string& name) const
|
||||
ParkingAssignment FGAirportDynamics::getParkingByName(const std::string& name) const
|
||||
{
|
||||
BOOST_FOREACH(FGParking* i, parkings) {
|
||||
if (name == i->getName()) {
|
||||
return i->getIndex();
|
||||
}
|
||||
PositionedID guid = flightgear::NavDataCache::instance()->airportItemWithIdent(parent()->guid(), FGPositioned::PARKING, name);
|
||||
if (guid == 0) {
|
||||
return ParkingAssignment();
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
return ParkingAssignment(getParking(guid), _ap);
|
||||
}
|
||||
|
||||
void FGAirportDynamics::releaseParking(int id)
|
||||
void FGAirportDynamics::setParkingAvailable(PositionedID guid, bool available)
|
||||
{
|
||||
if (id >= 0) {
|
||||
FGParking* parking = getParking(id);
|
||||
if (parking) {
|
||||
parking->setAvailable(true);
|
||||
}
|
||||
}
|
||||
if (available) {
|
||||
releaseParking(guid);
|
||||
} else {
|
||||
occupiedParkings.insert(guid);
|
||||
}
|
||||
}
|
||||
|
||||
bool FGAirportDynamics::isParkingAvailable(PositionedID parking) const
|
||||
{
|
||||
return (occupiedParkings.find(parking) == occupiedParkings.end());
|
||||
}
|
||||
|
||||
void FGAirportDynamics::releaseParking(PositionedID id)
|
||||
{
|
||||
ParkingSet::iterator it = occupiedParkings.find(id);
|
||||
if (it == occupiedParkings.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
occupiedParkings.erase(it);
|
||||
}
|
||||
|
||||
void FGAirportDynamics::setRwyUse(const FGRunwayPreference & ref)
|
||||
|
@ -373,11 +458,6 @@ string FGAirportDynamics::chooseRunwayFallback()
|
|||
return rwy->ident();
|
||||
}
|
||||
|
||||
void FGAirportDynamics::addParking(FGParking* park)
|
||||
{
|
||||
parkings.push_back(park);
|
||||
}
|
||||
|
||||
double FGAirportDynamics::getElevation() const
|
||||
{
|
||||
return _ap->getElevation();
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
#ifndef _AIRPORT_DYNAMICS_HXX_
|
||||
#define _AIRPORT_DYNAMICS_HXX_
|
||||
|
||||
#include <set>
|
||||
|
||||
#include <ATC/trafficcontrol.hxx>
|
||||
#include "parking.hxx"
|
||||
#include "groundnetwork.hxx"
|
||||
|
@ -31,12 +33,38 @@
|
|||
class FGAirport;
|
||||
class FGEnvironment;
|
||||
|
||||
class ParkingAssignment
|
||||
{
|
||||
public:
|
||||
ParkingAssignment();
|
||||
~ParkingAssignment();
|
||||
|
||||
// create a parking assignment (and mark it as unavailable)
|
||||
ParkingAssignment(FGParking* pk, FGAirport* apt);
|
||||
|
||||
ParkingAssignment(const ParkingAssignment& aOther);
|
||||
void operator=(const ParkingAssignment& aOther);
|
||||
|
||||
bool isValid() const;
|
||||
FGParking* parking() const;
|
||||
|
||||
void release();
|
||||
private:
|
||||
void clear();
|
||||
|
||||
class ParkingAssignmentPrivate;
|
||||
ParkingAssignmentPrivate* _sharedData;
|
||||
};
|
||||
|
||||
class FGAirportDynamics {
|
||||
|
||||
private:
|
||||
FGAirport* _ap;
|
||||
|
||||
FGParkingVec parkings;
|
||||
typedef std::set<PositionedID> ParkingSet;
|
||||
// if a parking item is in this set, it is occupied
|
||||
ParkingSet occupiedParkings;
|
||||
|
||||
FGRunwayPreference rwyPrefs;
|
||||
FGStartupController startupController;
|
||||
FGGroundNetwork groundNetwork;
|
||||
|
@ -63,8 +91,8 @@ private:
|
|||
bool innerGetActiveRunway(const std::string &trafficType, int action, std::string &runway, double heading);
|
||||
std::string chooseRwyByHeading(stringVec rwys, double heading);
|
||||
|
||||
int innerGetAvailableParking(double radius, const std::string & flType,
|
||||
const std::string & acType, const std::string & airline,
|
||||
FGParking* innerGetAvailableParking(double radius, const std::string & flType,
|
||||
const std::string & airline,
|
||||
bool skipEmptyAirlineCode);
|
||||
public:
|
||||
FGAirportDynamics(FGAirport* ap);
|
||||
|
@ -98,28 +126,28 @@ public:
|
|||
{ return _ap; }
|
||||
|
||||
void getActiveRunway(const string& trafficType, int action, string& runway, double heading);
|
||||
|
||||
void addParking(FGParking* park);
|
||||
|
||||
/**
|
||||
* retrieve an available parking by GateID, or -1 if no suitable
|
||||
* parking location could be found.
|
||||
*/
|
||||
int getAvailableParking(double radius, const std::string& fltype,
|
||||
ParkingAssignment getAvailableParking(double radius, const std::string& fltype,
|
||||
const std::string& acType, const std::string& airline);
|
||||
|
||||
FGParking *getParking(int i);
|
||||
void releaseParking(int id);
|
||||
std::string getParkingName(int i);
|
||||
int getNrOfParkings() {
|
||||
return parkings.size();
|
||||
};
|
||||
void setParkingAvailable(PositionedID guid, bool available);
|
||||
|
||||
bool isParkingAvailable(PositionedID parking) const;
|
||||
|
||||
FGParking *getParking(PositionedID i) const;
|
||||
void releaseParking(PositionedID id);
|
||||
std::string getParkingName(PositionedID i) const;
|
||||
|
||||
/**
|
||||
* Find a parking gate index by name. Note names are often not unique
|
||||
* in our data, so will return the first match.
|
||||
* in our data, so will return the first match. If the parking is found,
|
||||
* it will be marked as in-use (unavailable)
|
||||
*/
|
||||
int findParkingByName(const std::string& name) const;
|
||||
ParkingAssignment getParkingByName(const std::string& name) const;
|
||||
|
||||
// ATC related functions.
|
||||
FGStartupController *getStartupController() {
|
||||
|
|
|
@ -4,16 +4,18 @@
|
|||
|
||||
#include "groundnetwork.hxx"
|
||||
|
||||
#include <Navaids/NavDataCache.hxx>
|
||||
#include <Main/globals.hxx>
|
||||
#include <Scenery/scenery.hxx>
|
||||
|
||||
using namespace flightgear;
|
||||
|
||||
/**************************************************************************
|
||||
* FGTaxiNode
|
||||
*************************************************************************/
|
||||
|
||||
FGTaxiNode::FGTaxiNode(PositionedID aGuid, int index, const SGGeod& pos, bool aOnRunway, int aHoldType) :
|
||||
FGTaxiNode::FGTaxiNode(PositionedID aGuid, const SGGeod& pos, bool aOnRunway, int aHoldType) :
|
||||
FGPositioned(aGuid, FGPositioned::PARKING, "", pos),
|
||||
index(index),
|
||||
isOnRunway(aOnRunway),
|
||||
holdType(aHoldType)
|
||||
{
|
||||
|
@ -29,35 +31,24 @@ void FGTaxiNode::setElevation(double val)
|
|||
// ignored for the moment
|
||||
}
|
||||
|
||||
double FGTaxiNode::getElevationFt(double refelev)
|
||||
double FGTaxiNode::getElevationFt()
|
||||
{
|
||||
#if 0
|
||||
double elevF = elevation();
|
||||
double elevationEnd = 0;
|
||||
if ((elevF == 0) || (elevF == refelev)) {
|
||||
SGGeod center2 = mPosition;
|
||||
FGScenery * local_scenery = globals->get_scenery();
|
||||
center2.setElevationM(SG_MAX_ELEVATION_M);
|
||||
if (local_scenery->get_elevation_m( center2, elevationEnd, NULL )) {
|
||||
geod.setElevationM(elevationEnd);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return mPosition.getElevationFt();
|
||||
}
|
||||
|
||||
double FGTaxiNode::getElevationM(double refelev)
|
||||
{
|
||||
return geod().getElevationM();
|
||||
}
|
||||
|
||||
FGTaxiSegment* FGTaxiNode::getArcTo(FGTaxiNode* aEnd) const
|
||||
{
|
||||
BOOST_FOREACH(FGTaxiSegment* arc, next) {
|
||||
if (arc->getEnd() == aEnd) {
|
||||
return arc;
|
||||
if (mPosition.getElevationFt() == 0.0) {
|
||||
SGGeod center2 = mPosition;
|
||||
FGScenery* local_scenery = globals->get_scenery();
|
||||
center2.setElevationM(SG_MAX_ELEVATION_M);
|
||||
double elevationEnd = -100;
|
||||
if (local_scenery->get_elevation_m( center2, elevationEnd, NULL )) {
|
||||
|
||||
mPosition.setElevationM(elevationEnd);
|
||||
NavDataCache::instance()->updatePosition(guid(), mPosition);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return mPosition.getElevationFt();
|
||||
}
|
||||
|
||||
double FGTaxiNode::getElevationM()
|
||||
{
|
||||
return getElevationFt() * SG_FEET_TO_METER;
|
||||
}
|
||||
|
|
|
@ -16,70 +16,29 @@
|
|||
#ifndef _GN_NODE_HXX_
|
||||
#define _GN_NODE_HXX_
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/structure/SGSharedPtr.hxx>
|
||||
|
||||
#include <Navaids/positioned.hxx>
|
||||
|
||||
class FGTaxiSegment;
|
||||
|
||||
typedef std::vector<FGTaxiSegment*> FGTaxiSegmentVector;
|
||||
typedef FGTaxiSegmentVector::iterator FGTaxiSegmentVectorIterator;
|
||||
|
||||
bool sortByHeadingDiff(FGTaxiSegment *a, FGTaxiSegment *b);
|
||||
bool sortByLength (FGTaxiSegment *a, FGTaxiSegment *b);
|
||||
|
||||
class FGTaxiNode : public FGPositioned
|
||||
{
|
||||
protected:
|
||||
int index;
|
||||
|
||||
bool isOnRunway;
|
||||
int holdType;
|
||||
FGTaxiSegmentVector next; // a vector of pointers to all the segments leaving from this node
|
||||
|
||||
// used in way finding - should really move to a dynamic struct
|
||||
double pathScore;
|
||||
FGTaxiNode* previousNode;
|
||||
FGTaxiSegment* previousSeg;
|
||||
|
||||
|
||||
public:
|
||||
FGTaxiNode(PositionedID aGuid, int index, const SGGeod& pos, bool aOnRunway, int aHoldType);
|
||||
FGTaxiNode(PositionedID aGuid, const SGGeod& pos, bool aOnRunway, int aHoldType);
|
||||
virtual ~FGTaxiNode();
|
||||
|
||||
void setElevation(double val);
|
||||
void addSegment(FGTaxiSegment *segment) { next.push_back(segment); };
|
||||
|
||||
void setPathScore (double val) { pathScore = val; };
|
||||
void setPreviousNode(FGTaxiNode *val) { previousNode = val; };
|
||||
void setPreviousSeg (FGTaxiSegment *val) { previousSeg = val; };
|
||||
|
||||
FGTaxiNode *getPreviousNode() { return previousNode; };
|
||||
FGTaxiSegment *getPreviousSegment() { return previousSeg; };
|
||||
|
||||
double getPathScore() { return pathScore; };
|
||||
|
||||
double getElevationM (double refelev);
|
||||
double getElevationFt(double refelev);
|
||||
double getElevationM ();
|
||||
double getElevationFt();
|
||||
|
||||
int getIndex() const { return index; };
|
||||
PositionedID getIndex() const { return guid(); };
|
||||
int getHoldPointType() const { return holdType; };
|
||||
bool getIsOnRunway() const { return isOnRunway; };
|
||||
|
||||
const FGTaxiSegmentVector& arcs() const
|
||||
{ return next; }
|
||||
|
||||
/// find the arg which leads from this node to another.
|
||||
/// returns NULL if no such arc exists.
|
||||
FGTaxiSegment* getArcTo(FGTaxiNode* aEnd) const;
|
||||
|
||||
bool operator<(const FGTaxiNode &other) const { return index < other.index; };
|
||||
|
||||
|
||||
};
|
||||
|
||||
typedef SGSharedPtr<FGTaxiNode> FGTaxiNode_ptr;
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <math.h>
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include <osg/Geode>
|
||||
|
@ -40,6 +41,7 @@
|
|||
#include <simgear/scene/material/mat.hxx>
|
||||
#include <simgear/scene/util/OsgMath.hxx>
|
||||
#include <simgear/structure/exception.hxx>
|
||||
#include <simgear/timing/timestamp.hxx>
|
||||
|
||||
#include <Airports/simple.hxx>
|
||||
#include <Airports/dynamics.hxx>
|
||||
|
@ -48,6 +50,7 @@
|
|||
#include <AIModel/AIAircraft.hxx>
|
||||
#include <AIModel/performancedata.hxx>
|
||||
#include <AIModel/AIFlightPlan.hxx>
|
||||
#include <Navaids/NavDataCache.hxx>
|
||||
|
||||
#include <ATC/atc_mgr.hxx>
|
||||
|
||||
|
@ -56,52 +59,50 @@
|
|||
#include "groundnetwork.hxx"
|
||||
|
||||
using std::string;
|
||||
using flightgear::NavDataCache;
|
||||
|
||||
/***************************************************************************
|
||||
* FGTaxiSegment
|
||||
**************************************************************************/
|
||||
|
||||
FGTaxiSegment::FGTaxiSegment(int aStart, int aEnd, bool isPushBack) :
|
||||
FGTaxiSegment::FGTaxiSegment(PositionedID aStart, PositionedID aEnd) :
|
||||
startNode(aStart),
|
||||
endNode(aEnd),
|
||||
length(0),
|
||||
heading(0),
|
||||
isActive(0),
|
||||
isPushBackRoute(isPushBack),
|
||||
start(0),
|
||||
end(0),
|
||||
index(0),
|
||||
oppositeDirection(0)
|
||||
{
|
||||
};
|
||||
|
||||
bool FGTaxiSegment::bindToNodes(const IndexTaxiNodeMap& nodes)
|
||||
{
|
||||
IndexTaxiNodeMap::const_iterator it = nodes.find(startNode);
|
||||
if (it == nodes.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
start = it->second;
|
||||
|
||||
it = nodes.find(endNode);
|
||||
if (it == nodes.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
end = it->second;
|
||||
|
||||
start->addSegment(this);
|
||||
double az2;
|
||||
SGGeodesy::inverse(start->geod(), end->geod(), heading, az2, length);
|
||||
return true;
|
||||
}
|
||||
|
||||
SGGeod FGTaxiSegment::getCenter() const
|
||||
{
|
||||
FGTaxiNode* start(getStart()), *end(getEnd());
|
||||
double heading, length, az2;
|
||||
SGGeodesy::inverse(start->geod(), end->geod(), heading, az2, length);
|
||||
return SGGeodesy::direct(start->geod(), heading, length * 0.5);
|
||||
}
|
||||
|
||||
FGTaxiNode* FGTaxiSegment::getEnd() const
|
||||
{
|
||||
return static_cast<FGTaxiNode*>(NavDataCache::instance()->loadById(endNode));
|
||||
}
|
||||
|
||||
FGTaxiNode* FGTaxiSegment::getStart() const
|
||||
{
|
||||
return static_cast<FGTaxiNode*>(NavDataCache::instance()->loadById(startNode));
|
||||
}
|
||||
|
||||
double FGTaxiSegment::getLength() const
|
||||
{
|
||||
return dist(getStart()->cart(), getEnd()->cart());
|
||||
}
|
||||
|
||||
double FGTaxiSegment::getHeading() const
|
||||
{
|
||||
return SGGeodesy::courseDeg(getStart()->geod(), getEnd()->geod());
|
||||
}
|
||||
|
||||
|
||||
void FGTaxiSegment::block(int id, time_t blockTime, time_t now)
|
||||
{
|
||||
BlockListIterator i = blockTimes.begin();
|
||||
|
@ -144,81 +145,17 @@ void FGTaxiSegment::unblock(time_t now)
|
|||
/***************************************************************************
|
||||
* FGTaxiRoute
|
||||
**************************************************************************/
|
||||
bool FGTaxiRoute::next(int *nde)
|
||||
bool FGTaxiRoute::next(PositionedID *nde)
|
||||
{
|
||||
//for (intVecIterator i = nodes.begin(); i != nodes.end(); i++)
|
||||
// cerr << "FGTaxiRoute contains : " << *(i) << endl;
|
||||
//cerr << "Offset from end: " << nodes.end() - currNode << endl;
|
||||
//if (currNode != nodes.end())
|
||||
// cerr << "true" << endl;
|
||||
//else
|
||||
// cerr << "false" << endl;
|
||||
//if (nodes.size() != (routes.size()) +1)
|
||||
// cerr << "ALERT: Misconfigured TaxiRoute : " << nodes.size() << " " << routes.size() << endl;
|
||||
|
||||
if (currNode == nodes.end())
|
||||
return false;
|
||||
|
||||
*nde = *(currNode);
|
||||
if (currNode != nodes.begin()) // make sure route corresponds to the end node
|
||||
currRoute++;
|
||||
|
||||
currNode++;
|
||||
return true;
|
||||
};
|
||||
|
||||
bool FGTaxiRoute::next(int *nde, int *rte)
|
||||
{
|
||||
//for (intVecIterator i = nodes.begin(); i != nodes.end(); i++)
|
||||
// cerr << "FGTaxiRoute contains : " << *(i) << endl;
|
||||
//cerr << "Offset from end: " << nodes.end() - currNode << endl;
|
||||
//if (currNode != nodes.end())
|
||||
// cerr << "true" << endl;
|
||||
//else
|
||||
// cerr << "false" << endl;
|
||||
if (nodes.size() != (routes.size()) + 1) {
|
||||
SG_LOG(SG_GENERAL, SG_ALERT,
|
||||
"ALERT: Misconfigured TaxiRoute : " << nodes.
|
||||
size() << " " << routes.size());
|
||||
throw sg_range_exception("misconfigured taxi route");
|
||||
}
|
||||
if (currNode == nodes.end())
|
||||
return false;
|
||||
*nde = *(currNode);
|
||||
//*rte = *(currRoute);
|
||||
if (currNode != nodes.begin()) // Make sure route corresponds to the end node
|
||||
{
|
||||
*rte = *(currRoute);
|
||||
currRoute++;
|
||||
} else {
|
||||
// If currNode points to the first node, this means the aircraft is not on the taxi node
|
||||
// yet. Make sure to return a unique identifyer in this situation though, because otherwise
|
||||
// the speed adjust AI code may be unable to resolve whether two aircraft are on the same
|
||||
// taxi route or not. the negative of the preceding route seems a logical choice, as it is
|
||||
// unique for any starting location.
|
||||
// Note that this is probably just a temporary fix until I get Parking / tower control working.
|
||||
*rte = -1 * *(currRoute);
|
||||
}
|
||||
currNode++;
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
void FGTaxiRoute::rewind(int route)
|
||||
{
|
||||
int currPoint;
|
||||
int currRoute;
|
||||
first();
|
||||
do {
|
||||
if (!(next(&currPoint, &currRoute))) {
|
||||
SG_LOG(SG_GENERAL, SG_ALERT,
|
||||
"Error in rewinding TaxiRoute: current" << currRoute <<
|
||||
" goal " << route);
|
||||
}
|
||||
} while (currRoute != route);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* FGGroundNetwork()
|
||||
**************************************************************************/
|
||||
|
@ -232,7 +169,6 @@ FGGroundNetwork::FGGroundNetwork() :
|
|||
parent(NULL)
|
||||
{
|
||||
hasNetwork = false;
|
||||
foundRoute = false;
|
||||
totalDistance = 0;
|
||||
maxDistance = 0;
|
||||
//maxDepth = 1000;
|
||||
|
@ -253,52 +189,16 @@ FGGroundNetwork::~FGGroundNetwork()
|
|||
// 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
|
||||
//cerr << "Running Groundnetwork Destructor " << endl;
|
||||
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(0777);
|
||||
}
|
||||
cacheData.append(airport + "-groundnet-cache.txt");
|
||||
cachefile.open(cacheData.str().c_str());
|
||||
saveData = true;
|
||||
}
|
||||
}
|
||||
cachefile << "[GroundNetcachedata:ref:2011:09:04]" << endl;
|
||||
for (FGTaxiNodeVectorIterator node = nodes.begin();
|
||||
node != nodes.end(); node++) {
|
||||
if (saveData) {
|
||||
cachefile << (*node)->getIndex () << " "
|
||||
<< (*node)->getElevationM (parent->getElevation()*SG_FEET_TO_METER) << " "
|
||||
<< endl;
|
||||
}
|
||||
delete(*node);
|
||||
}
|
||||
nodes.clear();
|
||||
pushBackNodes.clear();
|
||||
for (FGTaxiSegmentVectorIterator seg = segments.begin();
|
||||
seg != segments.end(); seg++) {
|
||||
delete(*seg);
|
||||
}
|
||||
segments.clear();
|
||||
if (saveData) {
|
||||
cachefile.close();
|
||||
}
|
||||
saveElevationCache();
|
||||
#endif
|
||||
BOOST_FOREACH(FGTaxiSegment* seg, segments) {
|
||||
delete seg;
|
||||
}
|
||||
}
|
||||
|
||||
void FGGroundNetwork::saveElevationCache() {
|
||||
//cerr << "Running Groundnetwork Destructor " << endl;
|
||||
void FGGroundNetwork::saveElevationCache()
|
||||
{
|
||||
#if 0
|
||||
bool saveData = false;
|
||||
ofstream cachefile;
|
||||
if (fgGetBool("/sim/ai/groundnet-cache")) {
|
||||
|
@ -331,59 +231,38 @@ void FGGroundNetwork::saveElevationCache() {
|
|||
if (saveData) {
|
||||
cachefile.close();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void FGGroundNetwork::addSegment(FGTaxiSegment* seg)
|
||||
{
|
||||
segments.push_back(seg);
|
||||
}
|
||||
|
||||
void FGGroundNetwork::addNode(FGTaxiNode* node)
|
||||
{
|
||||
assert(node);
|
||||
IndexTaxiNodeMap::iterator it = nodes.find(node->getIndex());
|
||||
if (it != nodes.end()) {
|
||||
throw sg_range_exception();
|
||||
}
|
||||
|
||||
nodes.insert(it, std::make_pair(node->getIndex(), node));
|
||||
}
|
||||
|
||||
void FGGroundNetwork::addNodes(FGParkingVec * parkings)
|
||||
{
|
||||
BOOST_FOREACH(FGParking* parking, *parkings) {
|
||||
addNode(parking);
|
||||
}
|
||||
}
|
||||
|
||||
void FGGroundNetwork::init()
|
||||
void FGGroundNetwork::init(FGAirport* pr)
|
||||
{
|
||||
if (networkInitialized) {
|
||||
FGATCController::init();
|
||||
//cerr << "FGground network already initialized" << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
parent = pr;
|
||||
assert(parent);
|
||||
hasNetwork = true;
|
||||
nextSave = 0;
|
||||
int index = 1;
|
||||
|
||||
// bind segments to nodes
|
||||
loadSegments();
|
||||
|
||||
// establish pairing of segments
|
||||
BOOST_FOREACH(FGTaxiSegment* segment, segments) {
|
||||
if (!segment->bindToNodes(nodes)) {
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "unable to bind taxiway segment");
|
||||
segment->setIndex(index++);
|
||||
|
||||
if (segment->oppositeDirection) {
|
||||
continue; // already establish
|
||||
}
|
||||
|
||||
segment->setIndex(index++);
|
||||
if (segment->isPushBack()) {
|
||||
pushBackNodes.push_back(segment->getEnd());
|
||||
}
|
||||
}
|
||||
|
||||
// establish pairing of segments
|
||||
BOOST_FOREACH(FGTaxiSegment* segment, segments) {
|
||||
FGTaxiSegment* opp = segment->getEnd()->getArcTo(segment->getStart());
|
||||
FGTaxiSegment* opp = findSegment(segment->endNode, segment->startNode);
|
||||
if (opp) {
|
||||
segment->setOpposite(opp);
|
||||
assert(opp->oppositeDirection == NULL);
|
||||
segment->oppositeDirection = opp;
|
||||
opp->oppositeDirection = segment;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -394,6 +273,18 @@ void FGGroundNetwork::init()
|
|||
networkInitialized = true;
|
||||
}
|
||||
|
||||
void FGGroundNetwork::loadSegments()
|
||||
{
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FGGroundNetwork::parseCache()
|
||||
{
|
||||
SGPath cacheData(globals->get_fg_home());
|
||||
|
@ -403,7 +294,7 @@ void FGGroundNetwork::parseCache()
|
|||
if (airport.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if 0
|
||||
char buffer[128];
|
||||
::snprintf(buffer, 128, "%c/%c/%c/",
|
||||
airport[0], airport[1], airport[2]);
|
||||
|
@ -437,76 +328,29 @@ void FGGroundNetwork::parseCache()
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int FGGroundNetwork::findNearestNode(const SGGeod & aGeod)
|
||||
int FGGroundNetwork::findNearestNode(const SGGeod & aGeod) const
|
||||
{
|
||||
double minDist = HUGE_VAL;
|
||||
int index = -1;
|
||||
|
||||
IndexTaxiNodeMap::iterator i;
|
||||
for (i = nodes.begin(); i != nodes.end(); i++) {
|
||||
double d = SGGeodesy::distanceM(aGeod, i->second->geod());
|
||||
if (d < minDist) {
|
||||
minDist = d;
|
||||
index = i->first;
|
||||
}
|
||||
}
|
||||
|
||||
return index;
|
||||
const bool onRunway = false;
|
||||
return NavDataCache::instance()->findGroundNetNode(parent->guid(), aGeod, onRunway);
|
||||
}
|
||||
|
||||
int FGGroundNetwork::findNearestNodeOnRunway(const SGGeod & aGeod, FGRunway* aRunway)
|
||||
int FGGroundNetwork::findNearestNodeOnRunway(const SGGeod & aGeod, FGRunway* aRunway) const
|
||||
{
|
||||
double minDist = HUGE_VAL;
|
||||
int index = -1;
|
||||
|
||||
IndexTaxiNodeMap::iterator i;
|
||||
for (i = nodes.begin(); i != nodes.end(); i++) {
|
||||
if (!i->second->getIsOnRunway()) {
|
||||
continue;
|
||||
}
|
||||
// check point lies on the runway - i.e that course from aGeod to the
|
||||
// runway end, matches the runway heading
|
||||
if (aRunway) {
|
||||
double course = SGGeodesy::courseDeg(i->second->geod(), aRunway->end());
|
||||
double headingDiff = course - aRunway->headingDeg();
|
||||
SG_NORMALIZE_RANGE(headingDiff, -180.0, 180.0);
|
||||
if (fabs(headingDiff) > 3.0) { // 3 degrees tolerance
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
double d = SGGeodesy::distanceM(aGeod, i->second->geod());
|
||||
if (d < minDist) {
|
||||
minDist = d;
|
||||
index = i->first;
|
||||
}
|
||||
}
|
||||
|
||||
return index;
|
||||
const bool onRunway = true;
|
||||
return NavDataCache::instance()->findGroundNetNode(parent->guid(), aGeod, onRunway, aRunway);
|
||||
}
|
||||
|
||||
FGTaxiNode* FGGroundNetwork::findNode(unsigned int idx)
|
||||
{
|
||||
IndexTaxiNodeMap::iterator i = nodes.find(idx);
|
||||
if (i == nodes.end()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return i->second;
|
||||
FGTaxiNode* FGGroundNetwork::findNode(PositionedID idx) const
|
||||
{
|
||||
|
||||
return static_cast<FGTaxiNode*>(NavDataCache::instance()->loadById(idx));
|
||||
}
|
||||
|
||||
FGTaxiSegment *FGGroundNetwork::findSegment(unsigned idx)
|
||||
{ /*
|
||||
for (FGTaxiSegmentVectorIterator
|
||||
itr = segments.begin();
|
||||
itr != segments.end(); itr++)
|
||||
{
|
||||
if (itr->getIndex() == idx)
|
||||
return itr->getAddress();
|
||||
}
|
||||
*/
|
||||
FGTaxiSegment *FGGroundNetwork::findSegment(unsigned idx) const
|
||||
{
|
||||
if ((idx > 0) && (idx <= segments.size()))
|
||||
return segments[idx - 1];
|
||||
else {
|
||||
|
@ -515,34 +359,57 @@ FGTaxiSegment *FGGroundNetwork::findSegment(unsigned idx)
|
|||
}
|
||||
}
|
||||
|
||||
FGTaxiSegment* FGGroundNetwork::findSegment(PositionedID from, PositionedID to) const
|
||||
{
|
||||
if (from == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// completely boring linear search of segments. Can be improved if/when
|
||||
// this ever becomes a hot-spot
|
||||
BOOST_FOREACH(FGTaxiSegment* seg, segments) {
|
||||
if (seg->startNode != from) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((to == 0) || (seg->endNode == to)) {
|
||||
return seg;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL; // not found
|
||||
}
|
||||
|
||||
FGTaxiRoute FGGroundNetwork::findShortestRoute(int start, int end,
|
||||
static int edgePenalty(FGTaxiNode* tn)
|
||||
{
|
||||
return (tn->type() == FGPositioned::PARKING ? 10000 : 0) +
|
||||
(tn->getIsOnRunway() ? 1000 : 0);
|
||||
}
|
||||
|
||||
class ShortestPathData
|
||||
{
|
||||
public:
|
||||
ShortestPathData() :
|
||||
score(HUGE_VAL)
|
||||
{}
|
||||
|
||||
double score;
|
||||
FGTaxiNode_ptr previousNode;
|
||||
};
|
||||
|
||||
FGTaxiRoute FGGroundNetwork::findShortestRoute(PositionedID start, PositionedID end,
|
||||
bool fullSearch)
|
||||
{
|
||||
//implements Dijkstra's algorithm to find shortest distance route from start to end
|
||||
//taken from http://en.wikipedia.org/wiki/Dijkstra's_algorithm
|
||||
|
||||
//double INFINITE = 100000000000.0;
|
||||
// initialize scoring values
|
||||
int nParkings = parent->getDynamics()->getNrOfParkings();
|
||||
FGTaxiNodeVector unvisited;
|
||||
flightgear::NavDataCache* cache = flightgear::NavDataCache::instance();
|
||||
std::map<FGTaxiNode*, ShortestPathData> searchData;
|
||||
|
||||
if (fullSearch) {
|
||||
// create vector from map values
|
||||
IndexTaxiNodeMap::iterator i;
|
||||
for (i = nodes.begin(); i != nodes.end(); i++) {
|
||||
unvisited.push_back(i->second);
|
||||
}
|
||||
} else {
|
||||
unvisited = pushBackNodes;
|
||||
BOOST_FOREACH(PositionedID n, cache->groundNetNodes(parent->guid(), !fullSearch)) {
|
||||
unvisited.push_back(findNode(n));
|
||||
}
|
||||
|
||||
BOOST_FOREACH(FGTaxiNode* node, unvisited) {
|
||||
node->setPathScore(HUGE_VAL); //infinity by all practical means
|
||||
node->setPreviousNode(0); //
|
||||
node->setPreviousSeg(0); //
|
||||
}
|
||||
|
||||
FGTaxiNode *firstNode = findNode(start);
|
||||
if (!firstNode)
|
||||
{
|
||||
|
@ -551,7 +418,7 @@ FGTaxiRoute FGGroundNetwork::findShortestRoute(int start, int end,
|
|||
<< " at " << ((parent) ? parent->getId() : "<unknown>"));
|
||||
return FGTaxiRoute();
|
||||
}
|
||||
firstNode->setPathScore(0);
|
||||
searchData[firstNode].score = 0.0;
|
||||
|
||||
FGTaxiNode *lastNode = findNode(end);
|
||||
if (!lastNode)
|
||||
|
@ -565,11 +432,11 @@ FGTaxiRoute FGGroundNetwork::findShortestRoute(int start, int end,
|
|||
while (!unvisited.empty()) {
|
||||
FGTaxiNode *best = unvisited.front();
|
||||
BOOST_FOREACH(FGTaxiNode* i, unvisited) {
|
||||
if (i->getPathScore() < best->getPathScore()) {
|
||||
if (searchData[i].score < searchData[best].score) {
|
||||
best = i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// remove 'best' from the unvisited set
|
||||
FGTaxiNodeVectorIterator newend =
|
||||
remove(unvisited.begin(), unvisited.end(), best);
|
||||
|
@ -579,59 +446,38 @@ FGTaxiRoute FGGroundNetwork::findShortestRoute(int start, int end,
|
|||
break;
|
||||
}
|
||||
|
||||
BOOST_FOREACH(FGTaxiSegment* seg, best->arcs()) {
|
||||
if (!fullSearch && !seg->isPushBack()) {
|
||||
continue; // inelligible!
|
||||
}
|
||||
|
||||
FGTaxiNode *tgt = seg->getEnd();
|
||||
double alt = best->getPathScore() + seg->getLength() +
|
||||
seg->getPenalty(nParkings);
|
||||
if (alt < tgt->getPathScore()) { // Relax (u,v)
|
||||
tgt->setPathScore(alt);
|
||||
tgt->setPreviousNode(best);
|
||||
tgt->setPreviousSeg(seg);
|
||||
BOOST_FOREACH(PositionedID targetId, cache->groundNetEdgesFrom(best->guid(), !fullSearch)) {
|
||||
FGTaxiNode* tgt = (FGTaxiNode*) cache->loadById(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;
|
||||
}
|
||||
} // of outgoing arcs/segments from current best node iteration
|
||||
} // of unvisited nodes remaining
|
||||
|
||||
if (lastNode->getPathScore() == HUGE_VAL) {
|
||||
if (searchData[lastNode].score == HUGE_VAL) {
|
||||
// no valid route found
|
||||
if (fullSearch) {
|
||||
SG_LOG(SG_GENERAL, SG_ALERT,
|
||||
"Failed to find route from waypoint " << start << " to "
|
||||
<< end << " at " << parent->getId());
|
||||
}
|
||||
FGTaxiRoute empty;
|
||||
return empty;
|
||||
//exit(1); //TODO exit more gracefully, no need to stall the whole sim with broken GN's
|
||||
} else {
|
||||
// assemble route from backtrace information
|
||||
intVec nodes, routes;
|
||||
FGTaxiNode *bt = lastNode;
|
||||
while (bt->getPreviousNode() != 0) {
|
||||
nodes.push_back(bt->getIndex());
|
||||
routes.push_back(bt->getPreviousSegment()->getIndex());
|
||||
bt = bt->getPreviousNode();
|
||||
}
|
||||
nodes.push_back(start);
|
||||
reverse(nodes.begin(), nodes.end());
|
||||
reverse(routes.begin(), routes.end());
|
||||
|
||||
return FGTaxiRoute(nodes, routes, lastNode->getPathScore(), 0);
|
||||
|
||||
return FGTaxiRoute();
|
||||
}
|
||||
}
|
||||
|
||||
int FGTaxiSegment::getPenalty(int nGates)
|
||||
{
|
||||
int penalty = 0;
|
||||
if (end->getIndex() < nGates) {
|
||||
penalty += 10000;
|
||||
|
||||
// assemble route from backtrace information
|
||||
PositionedIDVec nodes;
|
||||
FGTaxiNode *bt = lastNode;
|
||||
while (searchData[bt].previousNode != 0) {
|
||||
nodes.push_back(bt->guid());
|
||||
bt = searchData[bt].previousNode;
|
||||
}
|
||||
if (end->getIsOnRunway()) { // For now. In future versions, need to find out whether runway is active.
|
||||
penalty += 1000;
|
||||
}
|
||||
return penalty;
|
||||
nodes.push_back(start);
|
||||
reverse(nodes.begin(), nodes.end());
|
||||
return FGTaxiRoute(nodes, searchData[lastNode].score, 0);
|
||||
}
|
||||
|
||||
/* ATC Related Functions */
|
||||
|
@ -644,7 +490,8 @@ void FGGroundNetwork::announcePosition(int id,
|
|||
double radius, int leg,
|
||||
FGAIAircraft * aircraft)
|
||||
{
|
||||
init();
|
||||
assert(parent);
|
||||
|
||||
TrafficVectorIterator i = activeTraffic.begin();
|
||||
// Search search if the current id alread has an entry
|
||||
// This might be faster using a map instead of a vector, but let's start by taking a safe route
|
||||
|
@ -1345,7 +1192,7 @@ void FGGroundNetwork::render(bool visible)
|
|||
} else {
|
||||
elevationStart = ((i)->getAircraft()->_getAltitude());
|
||||
}
|
||||
double elevationEnd = segments[pos]->getEnd()->getElevationM(parent->getElevation()*SG_FEET_TO_METER);
|
||||
double elevationEnd = segments[pos]->getEnd()->getElevationM();
|
||||
//cerr << "Using elevation " << elevationEnd << endl;
|
||||
|
||||
if ((elevationEnd == 0) || (elevationEnd = parent->getElevation())) {
|
||||
|
@ -1406,8 +1253,8 @@ void FGGroundNetwork::render(bool visible)
|
|||
obj_trans->setDataVariance(osg::Object::STATIC);
|
||||
|
||||
// Experimental: Calculate slope here, based on length, and the individual elevations
|
||||
double elevationStart = segments[k]->getStart()->getElevationM(parent->getElevation()*SG_FEET_TO_METER);
|
||||
double elevationEnd = segments[k]->getEnd ()->getElevationM(parent->getElevation()*SG_FEET_TO_METER);
|
||||
double elevationStart = segments[k]->getStart()->getElevationM();
|
||||
double elevationEnd = segments[k]->getEnd ()->getElevationM();
|
||||
if ((elevationStart == 0) || (elevationStart == parent->getElevation())) {
|
||||
SGGeod center2 = segments[k]->getStart()->geod();
|
||||
center2.setElevationM(SG_MAX_ELEVATION_M);
|
||||
|
|
|
@ -72,57 +72,40 @@ typedef BlockList::iterator BlockListIterator;
|
|||
class FGTaxiSegment
|
||||
{
|
||||
private:
|
||||
int startNode;
|
||||
int endNode;
|
||||
double length;
|
||||
double heading;
|
||||
const PositionedID startNode;
|
||||
const PositionedID endNode;
|
||||
|
||||
bool isActive;
|
||||
bool isPushBackRoute;
|
||||
BlockList blockTimes;
|
||||
FGTaxiNode *start;
|
||||
FGTaxiNode *end;
|
||||
|
||||
int index;
|
||||
FGTaxiSegment *oppositeDirection;
|
||||
|
||||
friend class FGGroundNetwork;
|
||||
public:
|
||||
FGTaxiSegment(int start, int end, bool isPushBack);
|
||||
FGTaxiSegment(PositionedID start, PositionedID end);
|
||||
|
||||
void setIndex (int val) {
|
||||
index = val;
|
||||
};
|
||||
|
||||
void setOpposite(FGTaxiSegment *opp) {
|
||||
oppositeDirection = opp;
|
||||
};
|
||||
|
||||
bool bindToNodes(const IndexTaxiNodeMap& nodes);
|
||||
|
||||
void setDimensions(double elevation);
|
||||
void block(int id, time_t blockTime, time_t now);
|
||||
void unblock(time_t now);
|
||||
bool hasBlock(time_t now);
|
||||
|
||||
FGTaxiNode * getEnd() {
|
||||
return end;
|
||||
};
|
||||
FGTaxiNode * getStart() {
|
||||
return start;
|
||||
};
|
||||
double getLength() {
|
||||
return length;
|
||||
};
|
||||
int getIndex() {
|
||||
return index;
|
||||
};
|
||||
FGTaxiNode * getEnd() const;
|
||||
FGTaxiNode * getStart() const;
|
||||
|
||||
double getLength() const;
|
||||
|
||||
// compute the center of the arc
|
||||
SGGeod getCenter() const;
|
||||
|
||||
double getHeading() {
|
||||
return heading;
|
||||
};
|
||||
bool isPushBack() {
|
||||
return isPushBackRoute;
|
||||
double getHeading() const;
|
||||
|
||||
int getIndex() {
|
||||
return index;
|
||||
};
|
||||
|
||||
int getPenalty(int nGates);
|
||||
|
@ -130,7 +113,7 @@ public:
|
|||
bool operator<(const FGTaxiSegment &other) const {
|
||||
return index < other.index;
|
||||
};
|
||||
//bool hasSmallerHeadingDiff (const FGTaxiSegment &other) const { return headingDiff < other.headingDiff; };
|
||||
|
||||
FGTaxiSegment *opposite() {
|
||||
return oppositeDirection;
|
||||
};
|
||||
|
@ -150,60 +133,45 @@ typedef std::vector<int>::iterator intVecIterator;
|
|||
class FGTaxiRoute
|
||||
{
|
||||
private:
|
||||
intVec nodes;
|
||||
intVec routes;
|
||||
PositionedIDVec nodes;
|
||||
double distance;
|
||||
// int depth;
|
||||
intVecIterator currNode;
|
||||
intVecIterator currRoute;
|
||||
PositionedIDVec::iterator currNode;
|
||||
|
||||
public:
|
||||
FGTaxiRoute() {
|
||||
distance = 0;
|
||||
currNode = nodes.begin();
|
||||
currRoute = routes.begin();
|
||||
};
|
||||
FGTaxiRoute(intVec nds, intVec rts, double dist, int dpth) {
|
||||
|
||||
FGTaxiRoute(const PositionedIDVec& nds, double dist, int dpth) {
|
||||
nodes = nds;
|
||||
routes = rts;
|
||||
distance = dist;
|
||||
currNode = nodes.begin();
|
||||
currRoute = routes.begin();
|
||||
// depth = dpth;
|
||||
};
|
||||
|
||||
FGTaxiRoute& operator= (const FGTaxiRoute &other) {
|
||||
nodes = other.nodes;
|
||||
routes = other.routes;
|
||||
distance = other.distance;
|
||||
// depth = other.depth;
|
||||
currNode = nodes.begin();
|
||||
currRoute = routes.begin();
|
||||
return *this;
|
||||
};
|
||||
|
||||
FGTaxiRoute(const FGTaxiRoute& copy) :
|
||||
nodes(copy.nodes),
|
||||
routes(copy.routes),
|
||||
distance(copy.distance),
|
||||
// depth(copy.depth),
|
||||
currNode(nodes.begin()),
|
||||
currRoute(routes.begin())
|
||||
currNode(nodes.begin())
|
||||
{};
|
||||
|
||||
bool operator< (const FGTaxiRoute &other) const {
|
||||
return distance < other.distance;
|
||||
};
|
||||
bool empty () {
|
||||
return nodes.begin() == nodes.end();
|
||||
return nodes.empty();
|
||||
};
|
||||
bool next(int *nde);
|
||||
bool next(int *nde, int *rte);
|
||||
void rewind(int legNr);
|
||||
|
||||
bool next(PositionedID *nde);
|
||||
|
||||
void first() {
|
||||
currNode = nodes.begin();
|
||||
currRoute = routes.begin();
|
||||
};
|
||||
int size() {
|
||||
return nodes.size();
|
||||
|
@ -211,8 +179,6 @@ public:
|
|||
int nodesLeft() {
|
||||
return nodes.end() - currNode;
|
||||
};
|
||||
|
||||
// int getDepth() { return depth; };
|
||||
};
|
||||
|
||||
typedef std::vector<FGTaxiRoute> TaxiRouteVector;
|
||||
|
@ -231,12 +197,8 @@ private:
|
|||
int count;
|
||||
int version;
|
||||
|
||||
IndexTaxiNodeMap nodes;
|
||||
FGTaxiNodeVector pushBackNodes;
|
||||
|
||||
FGTaxiSegmentVector segments;
|
||||
|
||||
TaxiRouteVector routes;
|
||||
TrafficVector activeTraffic;
|
||||
TrafficVectorIterator currTraffic;
|
||||
|
||||
|
@ -255,18 +217,16 @@ private:
|
|||
|
||||
|
||||
void parseCache();
|
||||
|
||||
void loadSegments();
|
||||
public:
|
||||
FGGroundNetwork();
|
||||
~FGGroundNetwork();
|
||||
|
||||
void addNode (FGTaxiNode* node);
|
||||
void addNodes (FGParkingVec *parkings);
|
||||
void addSegment(FGTaxiSegment* seg);
|
||||
void setVersion (int v) { version = v;};
|
||||
|
||||
void setVersion (int v) { version = v;};
|
||||
int getVersion() { return version; };
|
||||
|
||||
void init();
|
||||
void init(FGAirport* pr);
|
||||
bool exists() {
|
||||
return hasNetwork;
|
||||
};
|
||||
|
@ -274,21 +234,21 @@ public:
|
|||
towerController = twrCtrlr;
|
||||
};
|
||||
|
||||
int findNearestNode(const SGGeod& aGeod);
|
||||
int findNearestNodeOnRunway(const SGGeod& aGeod, FGRunway* aRunway = NULL);
|
||||
int findNearestNode(const SGGeod& aGeod) const;
|
||||
int findNearestNodeOnRunway(const SGGeod& aGeod, FGRunway* aRunway = NULL) const;
|
||||
|
||||
FGTaxiNode *findNode(unsigned idx);
|
||||
FGTaxiSegment *findSegment(unsigned idx);
|
||||
FGTaxiRoute findShortestRoute(int start, int end, bool fullSearch=true);
|
||||
//void trace(FGTaxiNode *, int, int, double dist);
|
||||
|
||||
int getNrOfNodes() {
|
||||
return nodes.size();
|
||||
};
|
||||
|
||||
void setParent(FGAirport *par) {
|
||||
parent = par;
|
||||
};
|
||||
FGTaxiNode *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
|
||||
* segment originating at 'from' is acceptable.
|
||||
*/
|
||||
FGTaxiSegment* findSegment(PositionedID from, PositionedID to) const;
|
||||
|
||||
FGTaxiRoute findShortestRoute(PositionedID start, PositionedID end, bool fullSearch=true);
|
||||
|
||||
virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute,
|
||||
double lat, double lon, double hdg, double spd, double alt,
|
||||
|
|
|
@ -31,24 +31,23 @@
|
|||
#include <string>
|
||||
|
||||
#include "parking.hxx"
|
||||
#include "groundnetwork.hxx"
|
||||
|
||||
/*********************************************************************************
|
||||
* FGParking
|
||||
********************************************************************************/
|
||||
|
||||
FGParking::FGParking(PositionedID aGuid, int index, const SGGeod& pos,
|
||||
FGParking::FGParking(PositionedID aGuid, const SGGeod& pos,
|
||||
double aHeading, double aRadius,
|
||||
const std::string& name, const std::string& aType,
|
||||
const std::string& codes) :
|
||||
FGTaxiNode(aGuid, index, pos, false, 0),
|
||||
const std::string& codes,
|
||||
PositionedID pushBackNode) :
|
||||
FGTaxiNode(aGuid, pos, false, 0),
|
||||
heading(aHeading),
|
||||
radius(aRadius),
|
||||
parkingName(name),
|
||||
type(aType),
|
||||
airlineCodes(codes),
|
||||
available(true),
|
||||
pushBackPoint(0)
|
||||
pushBackPoint(pushBackNode)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -38,42 +38,33 @@
|
|||
|
||||
#include "gnnode.hxx"
|
||||
|
||||
class FGTaxiRoute;
|
||||
|
||||
|
||||
class FGParking : public FGTaxiNode
|
||||
{
|
||||
private:
|
||||
double heading;
|
||||
double radius;
|
||||
std::string parkingName;
|
||||
std::string type;
|
||||
std::string airlineCodes;
|
||||
|
||||
bool available;
|
||||
int pushBackPoint;
|
||||
std::auto_ptr<FGTaxiRoute> pushBackRoute;
|
||||
const double heading;
|
||||
const double radius;
|
||||
const std::string parkingName;
|
||||
const std::string type;
|
||||
const std::string airlineCodes;
|
||||
const PositionedID pushBackPoint;
|
||||
|
||||
SG_DISABLE_COPY(FGParking);
|
||||
public:
|
||||
FGParking(PositionedID aGuid, int index, const SGGeod& pos,
|
||||
FGParking(PositionedID aGuid, const SGGeod& pos,
|
||||
double heading, double radius,
|
||||
const std::string& name, const std::string& type,
|
||||
const std::string& codes);
|
||||
const std::string& codes,
|
||||
PositionedID pushBackNode);
|
||||
virtual ~FGParking();
|
||||
|
||||
#if 0
|
||||
void setHeading (double hdg) { heading = hdg; };
|
||||
void setRadius (double rad) { radius = rad; };
|
||||
|
||||
void setName (const std::string& name) { parkingName = name; };
|
||||
void setType (const std::string& tpe) { type = tpe; };
|
||||
void setCodes (const std::string& codes){ airlineCodes= codes;};
|
||||
|
||||
void setPushBackRoute(std::auto_ptr<FGTaxiRoute> val) { pushBackRoute = val; };
|
||||
void setPushBackPoint(int val) { pushBackPoint = val; };
|
||||
|
||||
bool isAvailable () const { return available;};
|
||||
void setAvailable(bool val) { available = val; };
|
||||
#endif
|
||||
|
||||
double getHeading () const { return heading; };
|
||||
double getRadius () const { return radius; };
|
||||
|
@ -82,8 +73,6 @@ public:
|
|||
std::string getCodes () const { return airlineCodes;};
|
||||
std::string getName () const { return parkingName; };
|
||||
|
||||
FGTaxiRoute * getPushBackRoute () { return pushBackRoute.get(); };
|
||||
|
||||
int getPushBackPoint () { return pushBackPoint; };
|
||||
|
||||
bool operator< (const FGParking &other) const {
|
||||
|
|
|
@ -112,7 +112,8 @@ FGAirportDynamics * FGAirport::getDynamics()
|
|||
|
||||
_dynamics = new FGAirportDynamics(this);
|
||||
XMLLoader::load(_dynamics);
|
||||
|
||||
_dynamics->init();
|
||||
|
||||
FGRunwayPreference rwyPrefs(this);
|
||||
XMLLoader::load(&rwyPrefs);
|
||||
_dynamics->setRwyUse(rwyPrefs);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/xml/easyxml.hxx>
|
||||
#include <simgear/misc/strutils.hxx>
|
||||
#include <simgear/timing/timestamp.hxx>
|
||||
|
||||
#include <Main/globals.hxx>
|
||||
#include <Main/fg_props.hxx>
|
||||
|
@ -32,6 +33,8 @@
|
|||
#include "simple.hxx"
|
||||
#include "runwayprefs.hxx"
|
||||
|
||||
#include <Navaids/NavDataCache.hxx>
|
||||
|
||||
using std::string;
|
||||
|
||||
XMLLoader::XMLLoader() {}
|
||||
|
@ -39,10 +42,32 @@ XMLLoader::~XMLLoader() {}
|
|||
|
||||
void XMLLoader::load(FGAirportDynamics* d)
|
||||
{
|
||||
FGAirportDynamicsXMLLoader visitor(d);
|
||||
if(loadAirportXMLDataIntoVisitor(d->parent()->ident(), "groundnet", visitor)) {
|
||||
d->init();
|
||||
SGPath path;
|
||||
if (!findAirportData(d->parent()->ident(), "groundnet", path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
flightgear::NavDataCache* cache = flightgear::NavDataCache::instance();
|
||||
if (!cache->isCachedFileModified(path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
SG_LOG(SG_GENERAL, SG_INFO, "reading groundnet data from " << path);
|
||||
SGTimeStamp t;
|
||||
try {
|
||||
cache->beginTransaction();
|
||||
t.stamp();
|
||||
{
|
||||
FGAirportDynamicsXMLLoader visitor(d);
|
||||
readXML(path.str(), visitor);
|
||||
} // ensure visitor is destroyed so its destructor runs
|
||||
cache->stampCacheFile(path);
|
||||
cache->commitTransaction();
|
||||
} catch (sg_exception& e) {
|
||||
cache->abortTransaction();
|
||||
}
|
||||
|
||||
SG_LOG(SG_GENERAL, SG_INFO, "parsing XML took " << t.elapsedMSec());
|
||||
}
|
||||
|
||||
void XMLLoader::load(FGRunwayPreference* p) {
|
||||
|
|
|
@ -169,7 +169,7 @@ static bool fgSetPosFromAirportIDandParkpos( const string& id, const string& par
|
|||
return false;
|
||||
}
|
||||
|
||||
int gateID;
|
||||
ParkingAssignment pka;
|
||||
double radius = fgGetDouble("/sim/dimensions/radius-m");
|
||||
if ((parkpos == string("AVAILABLE")) && (radius > 0)) {
|
||||
string fltType;
|
||||
|
@ -203,27 +203,25 @@ static bool fgSetPosFromAirportIDandParkpos( const string& id, const string& par
|
|||
}
|
||||
|
||||
string acType; // Currently not used by findAvailable parking, so safe to leave empty.
|
||||
gateID = dcs->getAvailableParking(radius, fltType, acType, acOperator);
|
||||
if (gateID >=0 ) {
|
||||
pka = dcs->getAvailableParking(radius, fltType, acType, acOperator);
|
||||
if (pka.isValid()) {
|
||||
fgGetString("/sim/presets/parkpos");
|
||||
fgSetString("/sim/presets/parkpos", dcs->getParking(gateID)->getName());
|
||||
fgSetString("/sim/presets/parkpos", pka.parking()->getName());
|
||||
} else {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT,
|
||||
"Failed to find a suitable parking at airport " << id );
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
gateID = dcs->findParkingByName(parkpos);
|
||||
if (gateID < 0) {
|
||||
pka = dcs->getParkingByName(parkpos);
|
||||
if (!pka.isValid()) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT,
|
||||
"Failed to find a parking at airport " << id << ":" << parkpos);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
FGParking* parking = dcs->getParking(gateID);
|
||||
parking->setAvailable(false);
|
||||
fgApplyStartOffset(parking->geod(), parking->getHeading());
|
||||
fgApplyStartOffset(pka.parking()->geod(), pka.parking()->getHeading());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -60,6 +60,8 @@
|
|||
#include "PositionedOctree.hxx"
|
||||
#include <Airports/apt_loader.hxx>
|
||||
#include <Navaids/airways.hxx>
|
||||
#include <Airports/parking.hxx>
|
||||
#include <Airports/gnnode.hxx>
|
||||
|
||||
using std::string;
|
||||
|
||||
|
@ -68,7 +70,7 @@ using std::string;
|
|||
|
||||
namespace {
|
||||
|
||||
const int SCHEMA_VERSION = 4;
|
||||
const int SCHEMA_VERSION = 5;
|
||||
|
||||
// bind a std::string to a sqlite statement. The std::string must live the
|
||||
// entire duration of the statement execution - do not pass a temporary
|
||||
|
@ -461,6 +463,29 @@ public:
|
|||
")");
|
||||
|
||||
runSQL("CREATE INDEX airway_edge_from ON airway_edge(a)");
|
||||
|
||||
runSQL("CREATE TABLE taxi_node ("
|
||||
"hold_type INT,"
|
||||
"on_runway BOOL,"
|
||||
"pushback BOOL"
|
||||
")");
|
||||
|
||||
runSQL("CREATE TABLE parking ("
|
||||
"heading FLOAT,"
|
||||
"radius INT,"
|
||||
"gate_type VARCHAR,"
|
||||
"airlines VARCHAR,"
|
||||
"pushback INT64"
|
||||
")");
|
||||
|
||||
runSQL("CREATE TABLE groundnet_edge ("
|
||||
"airport INT64,"
|
||||
"a INT64,"
|
||||
"b INT64"
|
||||
")");
|
||||
|
||||
runSQL("CREATE INDEX groundnet_edge_airport ON groundnet_edge(airport)");
|
||||
runSQL("CREATE INDEX groundnet_edge_from ON groundnet_edge(a)");
|
||||
}
|
||||
|
||||
void prepareQueries()
|
||||
|
@ -570,6 +595,7 @@ public:
|
|||
sqlite3_bind_int(findILS, 4, FGPositioned::ILS);
|
||||
sqlite3_bind_int(findILS, 5, FGPositioned::LOC);
|
||||
|
||||
// airways
|
||||
findAirway = prepare("SELECT rowid FROM airway WHERE network=?1 AND ident=?2");
|
||||
insertAirway = prepare("INSERT INTO airway (ident, network) "
|
||||
"VALUES (?1, ?2)");
|
||||
|
@ -580,6 +606,47 @@ public:
|
|||
isPosInAirway = prepare("SELECT rowid FROM airway_edge WHERE network=?1 AND a=?2");
|
||||
|
||||
airwayEdgesFrom = prepare("SELECT airway, b FROM airway_edge WHERE network=?1 AND a=?2");
|
||||
|
||||
// parking / taxi-node graph
|
||||
insertTaxiNode = prepare("INSERT INTO taxi_node (rowid, hold_type, on_runway, pushback) VALUES(?1, ?2, ?3, 0)");
|
||||
insertParkingPos = prepare("INSERT INTO parking (rowid, heading, radius, gate_type, airlines) "
|
||||
"VALUES (?1, ?2, ?3, ?4, ?5)");
|
||||
setParkingPushBack = prepare("UPDATE parking SET pushback=?2 WHERE rowid=?1");
|
||||
|
||||
loadTaxiNodeStmt = prepare("SELECT hold_type, on_runway FROM taxi_node WHERE rowid=?1");
|
||||
loadParkingPos = prepare("SELECT heading, radius, gate_type, airlines, pushback FROM parking WHERE rowid=?1");
|
||||
taxiEdgesFrom = prepare("SELECT b FROM groundnet_edge WHERE a=?1");
|
||||
pushbackEdgesFrom = prepare("SELECT b FROM groundnet_edge, taxi_node WHERE "
|
||||
"a=?1 AND groundnet_edge.b = taxi_node.rowid AND pushback=1");
|
||||
|
||||
insertTaxiEdge = prepare("INSERT INTO groundnet_edge (airport, a,b) VALUES(?1, ?2, ?3)");
|
||||
|
||||
markTaxiNodeAsPushback = prepare("UPDATE taxi_node SET pushback=1 WHERE rowid=?1");
|
||||
airportTaxiNodes = prepare("SELECT rowid FROM positioned WHERE (type=?2 OR type=?3) AND airport=?1");
|
||||
sqlite3_bind_int(airportTaxiNodes, 2, FGPositioned::PARKING);
|
||||
sqlite3_bind_int(airportTaxiNodes, 3, FGPositioned::TAXI_NODE);
|
||||
|
||||
airportPushbackNodes = prepare("SELECT positioned.rowid FROM positioned, taxi_node WHERE "\
|
||||
"airport=?1 AND positioned.rowid=taxi_node.rowid AND pushback=1 "
|
||||
"AND (type=?2 OR type=?3)");
|
||||
sqlite3_bind_int(airportPushbackNodes, 2, FGPositioned::PARKING);
|
||||
sqlite3_bind_int(airportPushbackNodes, 3, FGPositioned::TAXI_NODE);
|
||||
|
||||
findNearestTaxiNode = prepare("SELECT positioned.rowid FROM positioned, taxi_node WHERE "
|
||||
"positioned.rowid = taxi_node.rowid AND airport=?1 "
|
||||
"ORDER BY distanceCartSqr(cart_x, cart_y, cart_z, ?2, ?3, ?4) "
|
||||
"LIMIT 1");
|
||||
|
||||
findNearestRunwayTaxiNode = prepare("SELECT positioned.rowid FROM positioned, taxi_node WHERE "
|
||||
"positioned.rowid = taxi_node.rowid AND airport=?1 "
|
||||
"AND on_runway=1 "
|
||||
"ORDER BY distanceCartSqr(cart_x, cart_y, cart_z, ?2, ?3, ?4) ");
|
||||
|
||||
findAirportParking = prepare("SELECT positioned.rowid FROM positioned, parking WHERE "
|
||||
"airport=?1 AND type=?4 AND "
|
||||
"radius >= ?2 AND gate_type = ?3 AND "
|
||||
"parking.rowid=positioned.rowid");
|
||||
sqlite3_bind_int(findAirportParking, 4, FGPositioned::PARKING);
|
||||
}
|
||||
|
||||
void writeIntProperty(const string& key, int value)
|
||||
|
@ -678,6 +745,35 @@ public:
|
|||
return new FGNavRecord(rowId, ty, id, name, pos, freq, rangeNm, mulituse, runway);
|
||||
}
|
||||
|
||||
FGPositioned* loadParking(sqlite3_int64 rowId,
|
||||
const string& name, const SGGeod& pos,
|
||||
PositionedID airport)
|
||||
{
|
||||
reset(loadParkingPos);
|
||||
sqlite3_bind_int64(loadParkingPos, 1, rowId);
|
||||
execSelect1(loadParkingPos);
|
||||
|
||||
double heading = sqlite3_column_double(loadParkingPos, 0);
|
||||
int radius = sqlite3_column_int(loadParkingPos, 1);
|
||||
string aircraftType((char*) sqlite3_column_text(loadParkingPos, 2));
|
||||
string airlines((char*) sqlite3_column_text(loadParkingPos, 3));
|
||||
PositionedID pushBack = sqlite3_column_int64(loadParkingPos, 4);
|
||||
|
||||
return new FGParking(rowId, pos, heading, radius, name, aircraftType, airlines, pushBack);
|
||||
}
|
||||
|
||||
FGPositioned* loadTaxiNode(sqlite3_int64 rowId, const SGGeod& pos,
|
||||
PositionedID airport)
|
||||
{
|
||||
reset(loadTaxiNodeStmt);
|
||||
sqlite3_bind_int64(loadTaxiNodeStmt, 1, rowId);
|
||||
execSelect1(loadTaxiNodeStmt);
|
||||
|
||||
int hold_type = sqlite3_column_int(loadTaxiNodeStmt, 0);
|
||||
bool onRunway = sqlite3_column_int(loadTaxiNodeStmt, 1);
|
||||
return new FGTaxiNode(rowId, pos, onRunway, hold_type);
|
||||
}
|
||||
|
||||
PositionedID insertPositioned(FGPositioned::Type ty, const string& ident,
|
||||
const string& name, const SGGeod& pos, PositionedID apt,
|
||||
bool spatialIndex)
|
||||
|
@ -822,6 +918,12 @@ public:
|
|||
sqlite3_stmt_ptr findAirway, insertAirwayEdge, isPosInAirway, airwayEdgesFrom,
|
||||
insertAirway;
|
||||
|
||||
// groundnet (parking, taxi node graph)
|
||||
sqlite3_stmt_ptr loadTaxiNodeStmt, loadParkingPos, insertTaxiNode, insertParkingPos;
|
||||
sqlite3_stmt_ptr taxiEdgesFrom, pushbackEdgesFrom, insertTaxiEdge, markTaxiNodeAsPushback,
|
||||
airportTaxiNodes, airportPushbackNodes, findNearestTaxiNode, findAirportParking,
|
||||
setParkingPushBack, findNearestRunwayTaxiNode;
|
||||
|
||||
// since there's many permutations of ident/name queries, we create
|
||||
// them programtically, but cache the exact query by its raw SQL once
|
||||
// used.
|
||||
|
@ -910,6 +1012,12 @@ FGPositioned* NavDataCache::NavDataCachePrivate::loadFromStmt(sqlite3_stmt_ptr q
|
|||
case FGPositioned::FREQ_UNICOM:
|
||||
return loadComm(rowid, ty, ident, name, pos, aptId);
|
||||
|
||||
case FGPositioned::TAXI_NODE:
|
||||
return loadTaxiNode(rowid, pos, aptId);
|
||||
|
||||
case FGPositioned::PARKING:
|
||||
return loadParking(rowid, ident, pos, aptId);
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1173,6 +1281,20 @@ void NavDataCache::stampCacheFile(const SGPath& path)
|
|||
d->execInsert(d->stampFileCache);
|
||||
}
|
||||
|
||||
void NavDataCache::beginTransaction()
|
||||
{
|
||||
d->runSQL("BEGIN");
|
||||
}
|
||||
|
||||
void NavDataCache::commitTransaction()
|
||||
{
|
||||
d->runSQL("COMMIT");
|
||||
}
|
||||
|
||||
void NavDataCache::abortTransaction()
|
||||
{
|
||||
d->runSQL("ROLLBACK");
|
||||
}
|
||||
|
||||
FGPositioned* NavDataCache::loadById(PositionedID rowid)
|
||||
{
|
||||
|
@ -1723,5 +1845,128 @@ PositionedID NavDataCache::findNavaidForRunway(PositionedID runway, FGPositioned
|
|||
return sqlite3_column_int64(d->findNavaidForRunway, 0);
|
||||
}
|
||||
|
||||
PositionedID
|
||||
NavDataCache::insertParking(const std::string& name, const SGGeod& aPos,
|
||||
PositionedID aAirport,
|
||||
double aHeading, int aRadius, const std::string& aAircraftType,
|
||||
const std::string& aAirlines)
|
||||
{
|
||||
sqlite3_int64 rowId = d->insertPositioned(FGPositioned::PARKING, name, "", aPos, aAirport, false);
|
||||
|
||||
// we need to insert a row into the taxi_node table, otherwise we can't maintain
|
||||
// the appropriate pushback flag.
|
||||
d->reset(d->insertTaxiNode);
|
||||
sqlite3_bind_int64(d->insertTaxiNode, 1, rowId);
|
||||
sqlite3_bind_int(d->insertTaxiNode, 2, 0);
|
||||
sqlite3_bind_int(d->insertTaxiNode, 3, 0);
|
||||
d->execInsert(d->insertTaxiNode);
|
||||
|
||||
d->reset(d->insertParkingPos);
|
||||
sqlite3_bind_int64(d->insertParkingPos, 1, rowId);
|
||||
sqlite3_bind_double(d->insertParkingPos, 2, aHeading);
|
||||
sqlite3_bind_int(d->insertParkingPos, 3, aRadius);
|
||||
sqlite_bind_stdstring(d->insertParkingPos, 4, aAircraftType);
|
||||
sqlite_bind_stdstring(d->insertParkingPos, 5, aAirlines);
|
||||
return d->execInsert(d->insertParkingPos);
|
||||
}
|
||||
|
||||
void NavDataCache::setParkingPushBackRoute(PositionedID parking, PositionedID pushBackNode)
|
||||
{
|
||||
d->reset(d->setParkingPushBack);
|
||||
sqlite3_bind_int64(d->setParkingPushBack, 1, parking);
|
||||
sqlite3_bind_int64(d->setParkingPushBack, 2, pushBackNode);
|
||||
d->execUpdate(d->setParkingPushBack);
|
||||
}
|
||||
|
||||
PositionedID
|
||||
NavDataCache::insertTaxiNode(const SGGeod& aPos, PositionedID aAirport, int aHoldType, bool aOnRunway)
|
||||
{
|
||||
sqlite3_int64 rowId = d->insertPositioned(FGPositioned::TAXI_NODE, string(), string(), aPos, aAirport, false);
|
||||
d->reset(d->insertTaxiNode);
|
||||
sqlite3_bind_int64(d->insertTaxiNode, 1, rowId);
|
||||
sqlite3_bind_int(d->insertTaxiNode, 2, aHoldType);
|
||||
sqlite3_bind_int(d->insertTaxiNode, 3, aOnRunway);
|
||||
return d->execInsert(d->insertTaxiNode);
|
||||
}
|
||||
|
||||
void NavDataCache::insertGroundnetEdge(PositionedID aAirport, PositionedID from, PositionedID to)
|
||||
{
|
||||
d->reset(d->insertTaxiEdge);
|
||||
sqlite3_bind_int64(d->insertTaxiEdge, 1, aAirport);
|
||||
sqlite3_bind_int64(d->insertTaxiEdge, 2, from);
|
||||
sqlite3_bind_int64(d->insertTaxiEdge, 3, to);
|
||||
d->execInsert(d->insertTaxiEdge);
|
||||
}
|
||||
|
||||
PositionedIDVec NavDataCache::groundNetNodes(PositionedID aAirport, bool onlyPushback)
|
||||
{
|
||||
sqlite3_stmt_ptr q = onlyPushback ? d->airportPushbackNodes : d->airportTaxiNodes;
|
||||
d->reset(q);
|
||||
sqlite3_bind_int64(q, 1, aAirport);
|
||||
return d->selectIds(q);
|
||||
}
|
||||
|
||||
void NavDataCache::markGroundnetAsPushback(PositionedID nodeId)
|
||||
{
|
||||
d->reset(d->markTaxiNodeAsPushback);
|
||||
sqlite3_bind_int64(d->markTaxiNodeAsPushback, 1, nodeId);
|
||||
d->execUpdate(d->markTaxiNodeAsPushback);
|
||||
}
|
||||
|
||||
static double headingDifferenceDeg(double crs1, double crs2)
|
||||
{
|
||||
double diff = crs2 - crs1;
|
||||
SG_NORMALIZE_RANGE(diff, -180.0, 180.0);
|
||||
return diff;
|
||||
}
|
||||
|
||||
PositionedID NavDataCache::findGroundNetNode(PositionedID airport, const SGGeod& aPos,
|
||||
bool onRunway, FGRunway* aRunway)
|
||||
{
|
||||
sqlite3_stmt_ptr q = onRunway ? d->findNearestRunwayTaxiNode : d->findNearestTaxiNode;
|
||||
d->reset(q);
|
||||
sqlite3_bind_int64(q, 1, airport);
|
||||
|
||||
SGVec3d cartPos(SGVec3d::fromGeod(aPos));
|
||||
sqlite3_bind_double(q, 2, cartPos.x());
|
||||
sqlite3_bind_double(q, 3, cartPos.y());
|
||||
sqlite3_bind_double(q, 4, cartPos.z());
|
||||
|
||||
while (d->execSelect(q)) {
|
||||
PositionedID id = sqlite3_column_int64(q, 0);
|
||||
if (!aRunway) {
|
||||
return id;
|
||||
}
|
||||
|
||||
// ensure found node lies on the runway
|
||||
FGPositionedRef node = loadById(id);
|
||||
double course = SGGeodesy::courseDeg(node->geod(), aRunway->end());
|
||||
if (fabs(headingDifferenceDeg(course, aRunway->headingDeg())) < 3.0 ) {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
PositionedIDVec NavDataCache::groundNetEdgesFrom(PositionedID pos, bool onlyPushback)
|
||||
{
|
||||
sqlite3_stmt_ptr q = onlyPushback ? d->pushbackEdgesFrom : d->taxiEdgesFrom;
|
||||
d->reset(q);
|
||||
sqlite3_bind_int64(q, 1, pos);
|
||||
return d->selectIds(q);
|
||||
}
|
||||
|
||||
PositionedIDVec NavDataCache::findAirportParking(PositionedID airport, const std::string& flightType,
|
||||
int radius)
|
||||
{
|
||||
d->reset(d->findAirportParking);
|
||||
sqlite3_bind_int64(d->findAirportParking, 1, airport);
|
||||
sqlite3_bind_int(d->findAirportParking, 2, radius);
|
||||
sqlite_bind_stdstring(d->findAirportParking, 3, flightType);
|
||||
|
||||
return d->selectIds(d->findAirportParking);
|
||||
}
|
||||
|
||||
} // of namespace flightgear
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <Navaids/positioned.hxx>
|
||||
|
||||
class SGPath;
|
||||
class FGRunway;
|
||||
|
||||
namespace flightgear
|
||||
{
|
||||
|
@ -84,6 +85,16 @@ public:
|
|||
string_list readStringListProperty(const std::string& key);
|
||||
void writeStringListProperty(const std::string& key, const string_list& values);
|
||||
|
||||
// transaction API wrappers
|
||||
void beginTransaction();
|
||||
void commitTransaction();
|
||||
void abortTransaction();
|
||||
|
||||
/**
|
||||
* retrieve an FGPositioned from the cache.
|
||||
* This may be trivial if the object is previously loaded, or require actual
|
||||
* disk IO.
|
||||
*/
|
||||
FGPositioned* loadById(PositionedID guid);
|
||||
|
||||
PositionedID insertAirport(FGPositioned::Type ty, const std::string& ident,
|
||||
|
@ -112,8 +123,25 @@ public:
|
|||
|
||||
PositionedID createUserWaypoint(const std::string& ident, const SGGeod& aPos);
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
* Modify the position of an existing item.
|
||||
* Use with care, since loaded instances will not be updated (at present -
|
||||
* this behaviour could in theorey be improved)
|
||||
*/
|
||||
void updatePosition(PositionedID item, const SGGeod &pos);
|
||||
|
||||
FGPositioned::List findAllWithIdent(const std::string& ident,
|
||||
|
@ -125,15 +153,35 @@ public:
|
|||
const SGGeod& aPos, FGPositioned::Filter* aFilter);
|
||||
|
||||
|
||||
/**
|
||||
* Helper to implement the AirportSearch widget. Optimised text search of
|
||||
* airport names and idents, returning a list suitable for passing directly
|
||||
* to PLIB.
|
||||
*/
|
||||
char** searchAirportNamesAndIdents(const std::string& aFilter);
|
||||
|
||||
/**
|
||||
* Find the closest matching comm-station on a frequency, to a position.
|
||||
* The filter with be used for both type ranging and to validate the result
|
||||
* candidates.
|
||||
*/
|
||||
FGPositionedRef findCommByFreq(int freqKhz, const SGGeod& pos, FGPositioned::Filter* filt);
|
||||
|
||||
/**
|
||||
* find all items of a specified type (or range of types) at an airport
|
||||
*/
|
||||
PositionedIDVec airportItemsOfType(PositionedID apt, FGPositioned::Type ty,
|
||||
FGPositioned::Type maxTy = FGPositioned::INVALID);
|
||||
|
||||
/**
|
||||
* find the first match item of the specified type and ident, at an airport
|
||||
*/
|
||||
PositionedID airportItemWithIdent(PositionedID apt, FGPositioned::Type ty, const std::string& ident);
|
||||
|
||||
|
||||
/**
|
||||
* Find all navaids matching a particular frequency, sorted by range from the
|
||||
* supplied position. Type-range will be determined from the filter
|
||||
*/
|
||||
PositionedIDVec findNavaidsByFreq(int freqKhz, const SGGeod& pos, FGPositioned::Filter* filt);
|
||||
|
||||
/// overload version of the above that does not consider positioned when
|
||||
|
@ -175,8 +223,15 @@ public:
|
|||
// airways
|
||||
int findAirway(int network, const std::string& aName);
|
||||
|
||||
/**
|
||||
* insert an edge between two positioned nodes, into the network.
|
||||
* The airway identifier will be set accordingly. No reverse edge is created
|
||||
* by this method - edges are directional so a reverses must be explicitly
|
||||
* created.
|
||||
*/
|
||||
void insertEdge(int network, int airwayID, PositionedID from, PositionedID to);
|
||||
|
||||
/// is the specified positioned a node on the network?
|
||||
bool isInAirwayNetwork(int network, PositionedID pos);
|
||||
|
||||
/**
|
||||
|
@ -184,6 +239,17 @@ public:
|
|||
* in an airway
|
||||
*/
|
||||
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);
|
||||
private:
|
||||
NavDataCache();
|
||||
|
||||
|
|
|
@ -229,7 +229,7 @@ protected:
|
|||
void modifyPosition(const SGGeod& newPos);
|
||||
|
||||
const PositionedID mGuid;
|
||||
const SGGeod mPosition;
|
||||
SGGeod mPosition;
|
||||
const SGVec3d mCart;
|
||||
const Type mType;
|
||||
const std::string mIdent;
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
#include <Navaids/routePath.hxx>
|
||||
#include <Navaids/procedure.hxx>
|
||||
#include <Navaids/airways.hxx>
|
||||
#include <Navaids/NavDataCache.hxx>
|
||||
|
||||
using namespace flightgear;
|
||||
|
||||
|
@ -1339,13 +1340,16 @@ static naRef f_airport_parking(naContext c, naRef me, int argc, naRef* args)
|
|||
}
|
||||
|
||||
FGAirportDynamics* dynamics = apt->getDynamics();
|
||||
for (int i=0; i<dynamics->getNrOfParkings(); ++i) {
|
||||
FGParking* park = dynamics->getParking(i);
|
||||
// filter out based on availability and type
|
||||
if (onlyAvailable && !park->isAvailable()) {
|
||||
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;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue