Thomas Foerster: Replaced AI network route tracing algorithm by a much more
efficiently performing "Dijkstra algorithm". Durk Talsma: Added the detection of "circular" wait situations in the AI ground network. A circular wait is a situation where aircraft a waits for b; b waits for c; and c (in turn) waits for a. The checkCircularWaits function detects these situations. The current "solution" to a circular wait is rather crude: Remove the aircraft from the scene. A proper solution needs a lot more work, however, and at least this patch stops the AI system from clogging up. in case of a circular wait.
This commit is contained in:
parent
1613d7e63e
commit
54ef3b77d5
4 changed files with 308 additions and 177 deletions
|
@ -232,7 +232,7 @@ FGGroundNetwork::FGGroundNetwork()
|
||||||
foundRoute = false;
|
foundRoute = false;
|
||||||
totalDistance = 0;
|
totalDistance = 0;
|
||||||
maxDistance = 0;
|
maxDistance = 0;
|
||||||
maxDepth = 1000;
|
//maxDepth = 1000;
|
||||||
count = 0;
|
count = 0;
|
||||||
currTraffic = activeTraffic.begin();
|
currTraffic = activeTraffic.begin();
|
||||||
|
|
||||||
|
@ -392,172 +392,172 @@ FGTaxiSegment *FGGroundNetwork::findSegment(int idx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FGTaxiRoute FGGroundNetwork::findShortestRoute(int start, int end)
|
FGTaxiRoute FGGroundNetwork::findShortestRoute(int start, int end)
|
||||||
{
|
{
|
||||||
double course;
|
//implements Dijkstra's algorithm to find shortest distance route from start to end
|
||||||
double length;
|
//taken from http://en.wikipedia.org/wiki/Dijkstra's_algorithm
|
||||||
foundRoute = false;
|
|
||||||
totalDistance = 0;
|
|
||||||
FGTaxiNode *firstNode = findNode(start);
|
|
||||||
FGTaxiNode *lastNode = findNode(end);
|
|
||||||
//prevNode = prevPrevNode = -1;
|
|
||||||
//prevNode = start;
|
|
||||||
routes.clear();
|
|
||||||
nodesStack.clear();
|
|
||||||
routesStack.clear();
|
|
||||||
// calculate distance and heading "as the crow flies" between starn and end points"
|
|
||||||
SGWayPoint first(firstNode->getLongitude(),
|
|
||||||
firstNode->getLatitude(),
|
|
||||||
0);
|
|
||||||
destination = SGWayPoint(lastNode->getLongitude(),
|
|
||||||
lastNode->getLatitude(),
|
|
||||||
0);
|
|
||||||
|
|
||||||
first.CourseAndDistance(destination, &course, &length);
|
//double INFINITE = 100000000000.0;
|
||||||
for (FGTaxiSegmentVectorIterator
|
// initialize scoring values
|
||||||
itr = segments.begin();
|
for (FGTaxiNodeVectorIterator
|
||||||
itr != segments.end(); itr++)
|
itr = nodes.begin();
|
||||||
{
|
itr != nodes.end(); itr++) {
|
||||||
(*itr)->setCourseDiff(course);
|
(*itr)->pathscore = HUGE_VAL; //infinity by all practical means
|
||||||
}
|
(*itr)->previousnode = 0; //
|
||||||
//FGTaxiNodeVectorIterator nde = nodes.begin();
|
(*itr)->previousseg = 0; //
|
||||||
//while (nde != nodes.end()) {
|
}
|
||||||
// (*nde)->sortEndSegments();
|
|
||||||
// nde++;
|
|
||||||
//}
|
|
||||||
maxDepth = 1000;
|
|
||||||
//do
|
|
||||||
// {
|
|
||||||
// cerr << "Begin of Trace " << start << " to "<< end << " maximum depth = " << maxDepth << endl;
|
|
||||||
trace(firstNode, end, 0, 0);
|
|
||||||
// maxDepth--;
|
|
||||||
// }
|
|
||||||
//while ((routes.size() != 0) && (maxDepth > 0));
|
|
||||||
//cerr << "End of Trace" << endl;
|
|
||||||
FGTaxiRoute empty;
|
|
||||||
|
|
||||||
if (!foundRoute)
|
FGTaxiNode *firstNode = findNode(start);
|
||||||
{
|
firstNode->pathscore = 0;
|
||||||
SG_LOG( SG_GENERAL, SG_ALERT, "Failed to find route from waypoint " << start << " to " << end << " at " <<
|
|
||||||
parent->getId());
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
sort(routes.begin(), routes.end());
|
|
||||||
//for (intVecIterator i = route.begin(); i != route.end(); i++)
|
|
||||||
// {
|
|
||||||
// rte->push_back(*i);
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (routes.begin() != routes.end())
|
FGTaxiNode *lastNode = findNode(end);
|
||||||
{
|
|
||||||
// if ((routes.begin()->getDepth() < 0.5 * maxDepth) && (maxDepth > 1))
|
FGTaxiNodeVector unvisited(nodes); // working copy
|
||||||
// {
|
|
||||||
// maxDepth--;
|
while (!unvisited.empty()) {
|
||||||
// cerr << "Max search depth decreased to : " << maxDepth;
|
FGTaxiNode* best = *(unvisited.begin());
|
||||||
// }
|
for (FGTaxiNodeVectorIterator
|
||||||
// else
|
itr = unvisited.begin();
|
||||||
// {
|
itr != unvisited.end(); itr++) {
|
||||||
// maxDepth++;
|
if ((*itr)->pathscore < best->pathscore)
|
||||||
// cerr << "Max search depth increased to : " << maxDepth;
|
best = (*itr);
|
||||||
// }
|
}
|
||||||
return *(routes.begin());
|
|
||||||
|
FGTaxiNodeVectorIterator newend = remove(unvisited.begin(), unvisited.end(), best);
|
||||||
|
unvisited.erase(newend, unvisited.end());
|
||||||
|
|
||||||
|
if (best == lastNode) { // found route or best not connected
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
for (FGTaxiSegmentVectorIterator
|
||||||
|
seg = best->getBeginRoute();
|
||||||
|
seg != best->getEndRoute(); seg++) {
|
||||||
|
FGTaxiNode* tgt = (*seg)->getEnd();
|
||||||
|
double alt = best->pathscore + (*seg)->getLength();
|
||||||
|
if (alt < tgt->pathscore) { // Relax (u,v)
|
||||||
|
tgt->pathscore = alt;
|
||||||
|
tgt->previousnode = best;
|
||||||
|
tgt->previousseg = *seg; //
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastNode->pathscore == HUGE_VAL) {
|
||||||
|
// no valid route found
|
||||||
|
SG_LOG( SG_GENERAL, SG_ALERT, "Failed to find route from waypoint " << start << " to " << end << " at " <<
|
||||||
|
parent->getId());
|
||||||
|
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->previousnode != 0) {
|
||||||
|
nodes.push_back(bt->getIndex());
|
||||||
|
routes.push_back(bt->previousseg->getIndex());
|
||||||
|
bt = bt->previousnode;
|
||||||
|
}
|
||||||
|
nodes.push_back(start);
|
||||||
|
reverse(nodes.begin(), nodes.end());
|
||||||
|
reverse(routes.begin(), routes.end());
|
||||||
|
|
||||||
|
return FGTaxiRoute(nodes, routes, lastNode->pathscore, 0);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
return empty;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void FGGroundNetwork::trace(FGTaxiNode *currNode, int end, int depth, double distance)
|
// void FGGroundNetwork::trace(FGTaxiNode *currNode, int end, int depth, double distance)
|
||||||
{
|
// {
|
||||||
// Just check some preconditions of the trace algorithm
|
// // Just check some preconditions of the trace algorithm
|
||||||
if (nodesStack.size() != routesStack.size())
|
// if (nodesStack.size() != routesStack.size())
|
||||||
{
|
// {
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT, "size of nodesStack and routesStack is not equal. NodesStack :"
|
// SG_LOG(SG_GENERAL, SG_ALERT, "size of nodesStack and routesStack is not equal. NodesStack :"
|
||||||
<< nodesStack.size() << ". RoutesStack : " << routesStack.size());
|
// << nodesStack.size() << ". RoutesStack : " << routesStack.size());
|
||||||
}
|
// }
|
||||||
nodesStack.push_back(currNode->getIndex());
|
// nodesStack.push_back(currNode->getIndex());
|
||||||
totalDistance += distance;
|
// totalDistance += distance;
|
||||||
//cerr << "Starting trace " << currNode->getIndex() << " " << "total distance: " << totalDistance << endl;
|
// //cerr << "Starting trace " << currNode->getIndex() << " " << "total distance: " << totalDistance << endl;
|
||||||
// << currNode->getIndex() << endl;
|
// // << currNode->getIndex() << endl;
|
||||||
|
//
|
||||||
// If the current route matches the required end point we found a valid route
|
// // If the current route matches the required end point we found a valid route
|
||||||
// So we can add this to the routing table
|
// // So we can add this to the routing table
|
||||||
if (currNode->getIndex() == end)
|
// if (currNode->getIndex() == end)
|
||||||
{
|
// {
|
||||||
maxDepth = depth;
|
// maxDepth = depth;
|
||||||
//cerr << "Found route : " << totalDistance << "" << " " << *(nodesStack.end()-1) << " Depth = " << depth << endl;
|
// //cerr << "Found route : " << totalDistance << "" << " " << *(nodesStack.end()-1) << " Depth = " << depth << endl;
|
||||||
routes.push_back(FGTaxiRoute(nodesStack,routesStack,totalDistance, depth));
|
// routes.push_back(FGTaxiRoute(nodesStack,routesStack,totalDistance, depth));
|
||||||
if (nodesStack.empty() || routesStack.empty())
|
// if (nodesStack.empty() || routesStack.empty())
|
||||||
{
|
// {
|
||||||
printRoutingError(string("while finishing route"));
|
// printRoutingError(string("while finishing route"));
|
||||||
}
|
// }
|
||||||
nodesStack.pop_back();
|
// nodesStack.pop_back();
|
||||||
routesStack.pop_back();
|
// routesStack.pop_back();
|
||||||
if (!(foundRoute)) {
|
// if (!(foundRoute)) {
|
||||||
maxDistance = totalDistance;
|
// maxDistance = totalDistance;
|
||||||
}
|
// }
|
||||||
else
|
// else
|
||||||
if (totalDistance < maxDistance)
|
// if (totalDistance < maxDistance)
|
||||||
maxDistance = totalDistance;
|
// maxDistance = totalDistance;
|
||||||
foundRoute = true;
|
// foundRoute = true;
|
||||||
totalDistance -= distance;
|
// totalDistance -= distance;
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
// search if the currentNode has been encountered before
|
// // search if the currentNode has been encountered before
|
||||||
// if so, we should step back one level, because it is
|
// // if so, we should step back one level, because it is
|
||||||
// rather rediculous to proceed further from here.
|
// // rather rediculous to proceed further from here.
|
||||||
// if the current node has not been encountered before,
|
// // if the current node has not been encountered before,
|
||||||
// i should point to nodesStack.end()-1; and we can continue
|
// // i should point to nodesStack.end()-1; and we can continue
|
||||||
// if i is not nodesStack.end, the previous node was found,
|
// // if i is not nodesStack.end, the previous node was found,
|
||||||
// and we should return.
|
// // and we should return.
|
||||||
// This only works at trace levels of 1 or higher though
|
// // This only works at trace levels of 1 or higher though
|
||||||
if (depth > 0) {
|
// if (depth > 0) {
|
||||||
intVecIterator i = nodesStack.begin();
|
// intVecIterator i = nodesStack.begin();
|
||||||
while ((*i) != currNode->getIndex()) {
|
// while ((*i) != currNode->getIndex()) {
|
||||||
//cerr << "Route so far : " << (*i) << endl;
|
// //cerr << "Route so far : " << (*i) << endl;
|
||||||
i++;
|
// i++;
|
||||||
}
|
// }
|
||||||
if (i != nodesStack.end()-1) {
|
// if (i != nodesStack.end()-1) {
|
||||||
if (nodesStack.empty() || routesStack.empty())
|
// if (nodesStack.empty() || routesStack.empty())
|
||||||
{
|
// {
|
||||||
printRoutingError(string("while returning from an already encountered node"));
|
// printRoutingError(string("while returning from an already encountered node"));
|
||||||
}
|
// }
|
||||||
nodesStack.pop_back();
|
// nodesStack.pop_back();
|
||||||
routesStack.pop_back();
|
// routesStack.pop_back();
|
||||||
totalDistance -= distance;
|
// totalDistance -= distance;
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
if (depth >= maxDepth) {
|
// if (depth >= maxDepth) {
|
||||||
count++;
|
// count++;
|
||||||
if (!(count % 100000)) {
|
// if (!(count % 100000)) {
|
||||||
maxDepth--; // Gradually decrease maxdepth, to prevent "eternal searches"
|
// maxDepth--; // Gradually decrease maxdepth, to prevent "eternal searches"
|
||||||
//cerr << "Reducing maxdepth to " << maxDepth << endl;
|
// //cerr << "Reducing maxdepth to " << maxDepth << endl;
|
||||||
}
|
// }
|
||||||
nodesStack.pop_back();
|
// nodesStack.pop_back();
|
||||||
routesStack.pop_back();
|
// routesStack.pop_back();
|
||||||
totalDistance -= distance;
|
// totalDistance -= distance;
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
// If the total distance from start to the current waypoint
|
// // If the total distance from start to the current waypoint
|
||||||
// is longer than that of a route we can also stop this trace
|
// // is longer than that of a route we can also stop this trace
|
||||||
// and go back one level.
|
// // and go back one level.
|
||||||
if ((totalDistance > maxDistance) && foundRoute)
|
// if ((totalDistance > maxDistance) && foundRoute)
|
||||||
//if (foundRoute)
|
// //if (foundRoute)
|
||||||
{
|
// {
|
||||||
//cerr << "Stopping rediculously long trace: " << totalDistance << endl;
|
// //cerr << "Stopping rediculously long trace: " << totalDistance << endl;
|
||||||
if (nodesStack.empty() || routesStack.empty())
|
// if (nodesStack.empty() || routesStack.empty())
|
||||||
{
|
// {
|
||||||
printRoutingError(string("while returning from finding a rediculously long route"));
|
// printRoutingError(string("while returning from finding a rediculously long route"));
|
||||||
}
|
// }
|
||||||
nodesStack.pop_back();
|
// nodesStack.pop_back();
|
||||||
routesStack.pop_back();
|
// routesStack.pop_back();
|
||||||
totalDistance -= distance;
|
// totalDistance -= distance;
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
/*
|
||||||
//cerr << "2" << endl;
|
//cerr << "2" << endl;
|
||||||
if (currNode->getBeginRoute() != currNode->getEndRoute())
|
if (currNode->getBeginRoute() != currNode->getEndRoute())
|
||||||
{
|
{
|
||||||
|
@ -625,7 +625,7 @@ void FGGroundNetwork::trace(FGTaxiNode *currNode, int end, int depth, double dis
|
||||||
}
|
}
|
||||||
totalDistance -= distance;
|
totalDistance -= distance;
|
||||||
return;
|
return;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
void FGGroundNetwork::printRoutingError(string mess)
|
void FGGroundNetwork::printRoutingError(string mess)
|
||||||
{
|
{
|
||||||
|
@ -729,20 +729,34 @@ void FGGroundNetwork::update(int id, double lat, double lon, double heading, dou
|
||||||
// return;
|
// return;
|
||||||
//else
|
//else
|
||||||
// setDt(0);
|
// setDt(0);
|
||||||
|
current->clearResolveCircularWait();
|
||||||
|
current->setWaitsForId(0);
|
||||||
checkSpeedAdjustment(id, lat, lon, heading, speed, alt);
|
checkSpeedAdjustment(id, lat, lon, heading, speed, alt);
|
||||||
checkHoldPosition (id, lat, lon, heading, speed, alt);
|
checkHoldPosition (id, lat, lon, heading, speed, alt);
|
||||||
|
if (checkForCircularWaits(id)) {
|
||||||
|
i->setResolveCircularWait();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Scan for a speed adjustment change. Find the nearest aircraft that is in front
|
||||||
|
and adjust speed when we get too close. Only do this when current position and/or
|
||||||
|
intentions of the current aircraft match current taxiroute position of the proximate
|
||||||
|
aircraft. For traffic that is on other routes we need to issue a "HOLD Position"
|
||||||
|
instruction. See below for the hold position instruction.
|
||||||
|
|
||||||
|
Note that there currently still is one flaw in the logic that needs to be addressed.
|
||||||
|
can be situations where one aircraft is in front of the current aircraft, on a separate
|
||||||
|
route, but really close after an intersection coming off the current route. This
|
||||||
|
aircraft is still close enough to block the current aircraft. This situation is currently
|
||||||
|
not addressed yet, but should be.
|
||||||
|
*/
|
||||||
|
|
||||||
void FGGroundNetwork::checkSpeedAdjustment(int id, double lat,
|
void FGGroundNetwork::checkSpeedAdjustment(int id, double lat,
|
||||||
double lon, double heading,
|
double lon, double heading,
|
||||||
double speed, double alt)
|
double speed, double alt)
|
||||||
{
|
{
|
||||||
|
|
||||||
// Scan for a speed adjustment change. Find the nearest aircraft that is in front
|
|
||||||
// and adjust speed when we get too close. Only do this when current position and/or
|
|
||||||
// intentions of the current aircraft match current taxiroute position of the proximate
|
|
||||||
// aircraft. For traffic that is on other routes we need to issue a "HOLD Position"
|
|
||||||
// instruction. See below for the hold position instruction.
|
|
||||||
TrafficVectorIterator current, closest;
|
TrafficVectorIterator current, closest;
|
||||||
TrafficVectorIterator i = activeTraffic.begin();
|
TrafficVectorIterator i = activeTraffic.begin();
|
||||||
bool otherReasonToSlowDown = false;
|
bool otherReasonToSlowDown = false;
|
||||||
|
@ -766,6 +780,7 @@ void FGGroundNetwork::checkSpeedAdjustment(int id, double lat,
|
||||||
}
|
}
|
||||||
current = i;
|
current = i;
|
||||||
//closest = current;
|
//closest = current;
|
||||||
|
|
||||||
previousInstruction = current->getSpeedAdjustment();
|
previousInstruction = current->getSpeedAdjustment();
|
||||||
double mindist = HUGE;
|
double mindist = HUGE;
|
||||||
if (activeTraffic.size())
|
if (activeTraffic.size())
|
||||||
|
@ -877,15 +892,18 @@ void FGGroundNetwork::checkSpeedAdjustment(int id, double lat,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Check for "Hold position instruction".
|
||||||
|
The hold position should be issued under the following conditions:
|
||||||
|
1) For aircraft entering or crossing a runway with active traffic on it, or landing aircraft near it
|
||||||
|
2) For taxiing aircraft that use one taxiway in opposite directions
|
||||||
|
3) For crossing or merging taxiroutes.
|
||||||
|
*/
|
||||||
|
|
||||||
void FGGroundNetwork::checkHoldPosition(int id, double lat,
|
void FGGroundNetwork::checkHoldPosition(int id, double lat,
|
||||||
double lon, double heading,
|
double lon, double heading,
|
||||||
double speed, double alt)
|
double speed, double alt)
|
||||||
{
|
{
|
||||||
// Check for "Hold position instruction".
|
|
||||||
// The hold position should be issued under the following conditions:
|
|
||||||
// 1) For aircraft entering or crossing a runway with active traffic on it, or landing aircraft near it
|
|
||||||
// 2) For taxiing aircraft that use one taxiway in opposite directions
|
|
||||||
// 3) For crossing or merging taxiroutes.
|
|
||||||
|
|
||||||
TrafficVectorIterator current;
|
TrafficVectorIterator current;
|
||||||
TrafficVectorIterator i = activeTraffic.begin();
|
TrafficVectorIterator i = activeTraffic.begin();
|
||||||
|
@ -929,7 +947,6 @@ void FGGroundNetwork::checkHoldPosition(int id, double lat,
|
||||||
findNode(node)->getLatitude (),
|
findNode(node)->getLatitude (),
|
||||||
alt);
|
alt);
|
||||||
|
|
||||||
|
|
||||||
SGWayPoint other (i->getLongitude (),
|
SGWayPoint other (i->getLongitude (),
|
||||||
i->getLatitude (),
|
i->getLatitude (),
|
||||||
i->getAltitude ());
|
i->getAltitude ());
|
||||||
|
@ -979,6 +996,7 @@ void FGGroundNetwork::checkHoldPosition(int id, double lat,
|
||||||
|
|
||||||
{
|
{
|
||||||
current->setHoldPosition(true);
|
current->setHoldPosition(true);
|
||||||
|
current->setWaitsForId(i->getId());
|
||||||
//cerr << "Hold check 5: " << current->getCallSign() <<" Setting Hold Position: distance to node (" << node << ") "
|
//cerr << "Hold check 5: " << current->getCallSign() <<" Setting Hold Position: distance to node (" << node << ") "
|
||||||
// << dist << " meters. Waiting for " << i->getCallSign();
|
// << dist << " meters. Waiting for " << i->getCallSign();
|
||||||
//if (opposing)
|
//if (opposing)
|
||||||
|
@ -999,6 +1017,101 @@ void FGGroundNetwork::checkHoldPosition(int id, double lat,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether situations occur where the current aircraft is waiting for itself
|
||||||
|
* due to higher order interactions.
|
||||||
|
* A 'circular' wait is a situation where a waits for b, b waits for c, and c waits
|
||||||
|
* for a. Ideally each aircraft only waits for one other aircraft, so by tracing
|
||||||
|
* through this list of waiting aircraft, we can check if we'd eventually end back
|
||||||
|
* at the current aircraft.
|
||||||
|
*
|
||||||
|
* Note that we should consider the situation where we are actually checking aircraft
|
||||||
|
* d, which is waiting for aircraft a. d is not part of the loop, but is held back by
|
||||||
|
* the looping aircraft. If we don't check for that, this function will get stuck into
|
||||||
|
* endless loop.
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool FGGroundNetwork::checkForCircularWaits(int id)
|
||||||
|
{
|
||||||
|
//cerr << "Performing Wait check " << id << endl;
|
||||||
|
int target = 0;
|
||||||
|
TrafficVectorIterator current, other;
|
||||||
|
TrafficVectorIterator i = activeTraffic.begin();
|
||||||
|
int trafficSize = activeTraffic.size();
|
||||||
|
if (trafficSize) {
|
||||||
|
//while ((i->getId() != id) && i != activeTraffic.end())
|
||||||
|
while (i != activeTraffic.end()) {
|
||||||
|
if (i->getId() == id) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (i == activeTraffic.end() || (trafficSize == 0)) {
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "AI error: Trying to access non-existing aircraft in FGGroundNetwork::checkForCircularWaits");
|
||||||
|
}
|
||||||
|
|
||||||
|
current = i;
|
||||||
|
target = current->getWaitsForId();
|
||||||
|
//bool printed = false; // Note that this variable is for debugging purposes only.
|
||||||
|
int counter = 0;
|
||||||
|
while ((target > 0) && (target != id) && counter++ < trafficSize) {
|
||||||
|
//printed = true;
|
||||||
|
TrafficVectorIterator i = activeTraffic.begin();
|
||||||
|
if (trafficSize) {
|
||||||
|
//while ((i->getId() != id) && i != activeTraffic.end())
|
||||||
|
while (i != activeTraffic.end()) {
|
||||||
|
if (i->getId() == target) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (i == activeTraffic.end() || (trafficSize == 0)) {
|
||||||
|
//cerr << "[Waiting for traffic at Runway: DONE] " << endl << endl;;
|
||||||
|
// The target id is not found on the current network, which means it's at the tower
|
||||||
|
//SG_LOG(SG_GENERAL, SG_ALERT, "AI error: Trying to access non-existing aircraft in FGGroundNetwork::checkForCircularWaits");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
other = i;
|
||||||
|
target = other->getWaitsForId();
|
||||||
|
|
||||||
|
// actually this trap isn't as impossible as it first seemed:
|
||||||
|
// the setWaitsForID(id) is set to current when the aircraft
|
||||||
|
// is waiting for the user controlled aircraft.
|
||||||
|
//if (current->getId() == other->getId()) {
|
||||||
|
// cerr << "Caught the impossible trap" << endl;
|
||||||
|
// cerr << "Current = " << current->getId() << endl;
|
||||||
|
// cerr << "Other = " << other ->getId() << endl;
|
||||||
|
// for (TrafficVectorIterator at = activeTraffic.begin();
|
||||||
|
// at != activeTraffic.end();
|
||||||
|
// at++) {
|
||||||
|
// cerr << "currently active aircraft : " << at->getCallSign() << " with Id " << at->getId() << " waits for " << at->getWaitsForId() << endl;
|
||||||
|
// }
|
||||||
|
// exit(1);
|
||||||
|
if (current->getId() == other->getId())
|
||||||
|
return false;
|
||||||
|
//}
|
||||||
|
//cerr << current->getCallSign() << " (" << current->getId() << ") " << " -> " << other->getCallSign()
|
||||||
|
// << " (" << other->getId() << "); " << endl;;
|
||||||
|
//current = other;
|
||||||
|
}
|
||||||
|
//if (printed)
|
||||||
|
// cerr << "[done] " << endl << endl;;
|
||||||
|
if (id == target) {
|
||||||
|
SG_LOG(SG_GENERAL, SG_INFO, "Detected circular wait condition");
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Note that this function is probably obsolete...
|
// Note that this function is probably obsolete...
|
||||||
bool FGGroundNetwork::hasInstruction(int id)
|
bool FGGroundNetwork::hasInstruction(int id)
|
||||||
{
|
{
|
||||||
|
@ -1045,3 +1158,4 @@ FGATCInstruction FGGroundNetwork::getInstruction(int id)
|
||||||
return FGATCInstruction();
|
return FGATCInstruction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -81,6 +81,12 @@ public:
|
||||||
bool operator<(const FGTaxiNode &other) const { return index < other.index; };
|
bool operator<(const FGTaxiNode &other) const { return index < other.index; };
|
||||||
|
|
||||||
void sortEndSegments(bool);
|
void sortEndSegments(bool);
|
||||||
|
|
||||||
|
// used in way finding
|
||||||
|
double pathscore;
|
||||||
|
FGTaxiNode* previousnode;
|
||||||
|
FGTaxiSegment* previousseg;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef vector<FGTaxiNode*> FGTaxiNodeVector;
|
typedef vector<FGTaxiNode*> FGTaxiNodeVector;
|
||||||
|
@ -190,7 +196,7 @@ class FGGroundNetwork : public FGATCController
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
bool hasNetwork;
|
bool hasNetwork;
|
||||||
int maxDepth;
|
//int maxDepth;
|
||||||
int count;
|
int count;
|
||||||
FGTaxiNodeVector nodes;
|
FGTaxiNodeVector nodes;
|
||||||
FGTaxiSegmentVector segments;
|
FGTaxiSegmentVector segments;
|
||||||
|
@ -230,7 +236,7 @@ public:
|
||||||
FGTaxiNode *findNode(int idx);
|
FGTaxiNode *findNode(int idx);
|
||||||
FGTaxiSegment *findSegment(int idx);
|
FGTaxiSegment *findSegment(int idx);
|
||||||
FGTaxiRoute findShortestRoute(int start, int end);
|
FGTaxiRoute findShortestRoute(int start, int end);
|
||||||
void trace(FGTaxiNode *, int, int, double dist);
|
//void trace(FGTaxiNode *, int, int, double dist);
|
||||||
|
|
||||||
void setParent(FGAirport *par) { parent = par; };
|
void setParent(FGAirport *par) { parent = par; };
|
||||||
|
|
||||||
|
@ -241,6 +247,8 @@ public:
|
||||||
virtual void update(int id, double lat, double lon, double heading, double speed, double alt, double dt);
|
virtual void update(int id, double lat, double lon, double heading, double speed, double alt, double dt);
|
||||||
virtual bool hasInstruction(int id);
|
virtual bool hasInstruction(int id);
|
||||||
virtual FGATCInstruction getInstruction(int id);
|
virtual FGATCInstruction getInstruction(int id);
|
||||||
|
|
||||||
|
bool checkForCircularWaits(int id);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -300,6 +300,7 @@ FGATCInstruction::FGATCInstruction()
|
||||||
changeSpeed = false;
|
changeSpeed = false;
|
||||||
changeHeading = false;
|
changeHeading = false;
|
||||||
changeAltitude = false;
|
changeAltitude = false;
|
||||||
|
resolveCircularWait = false;
|
||||||
|
|
||||||
double speed = 0;
|
double speed = 0;
|
||||||
double heading = 0;
|
double heading = 0;
|
||||||
|
@ -308,7 +309,7 @@ FGATCInstruction::FGATCInstruction()
|
||||||
|
|
||||||
bool FGATCInstruction::hasInstruction()
|
bool FGATCInstruction::hasInstruction()
|
||||||
{
|
{
|
||||||
return (holdPattern || holdPosition || changeSpeed || changeHeading || changeAltitude);
|
return (holdPattern || holdPosition || changeSpeed || changeHeading || changeAltitude || resolveCircularWait);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,7 @@ private:
|
||||||
bool changeSpeed;
|
bool changeSpeed;
|
||||||
bool changeHeading;
|
bool changeHeading;
|
||||||
bool changeAltitude;
|
bool changeAltitude;
|
||||||
|
bool resolveCircularWait;
|
||||||
|
|
||||||
double speed;
|
double speed;
|
||||||
double heading;
|
double heading;
|
||||||
|
@ -76,19 +77,23 @@ public:
|
||||||
double getHeading () { return heading; };
|
double getHeading () { return heading; };
|
||||||
double getAlt () { return alt; };
|
double getAlt () { return alt; };
|
||||||
|
|
||||||
|
bool getCheckForCircularWait() { return resolveCircularWait; };
|
||||||
|
|
||||||
void setHoldPattern (bool val) { holdPattern = val; };
|
void setHoldPattern (bool val) { holdPattern = val; };
|
||||||
void setHoldPosition (bool val) { holdPosition = val; };
|
void setHoldPosition (bool val) { holdPosition = val; };
|
||||||
void setChangeSpeed (bool val) { changeSpeed = val; };
|
void setChangeSpeed (bool val) { changeSpeed = val; };
|
||||||
void setChangeHeading (bool val) { changeHeading = val; };
|
void setChangeHeading (bool val) { changeHeading = val; };
|
||||||
void setChangeAltitude(bool val) { changeAltitude = val; };
|
void setChangeAltitude(bool val) { changeAltitude = val; };
|
||||||
|
|
||||||
|
void setResolveCircularWait (bool val) { resolveCircularWait = val; };
|
||||||
|
|
||||||
void setSpeed (double val) { speed = val; };
|
void setSpeed (double val) { speed = val; };
|
||||||
void setHeading (double val) { heading = val; };
|
void setHeading (double val) { heading = val; };
|
||||||
void setAlt (double val) { alt = val; };
|
void setAlt (double val) { alt = val; };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************************
|
/**
|
||||||
* class FGATCController
|
* class FGATCController
|
||||||
* NOTE: this class serves as an abstraction layer for all sorts of ATC controller.
|
* NOTE: this class serves as an abstraction layer for all sorts of ATC controller.
|
||||||
*************************************************************************************/
|
*************************************************************************************/
|
||||||
|
@ -170,6 +175,9 @@ public:
|
||||||
|
|
||||||
void setWaitsForId(int id) { waitsForId = id; };
|
void setWaitsForId(int id) { waitsForId = id; };
|
||||||
|
|
||||||
|
void setResolveCircularWait() { instruction.setResolveCircularWait(true); };
|
||||||
|
void clearResolveCircularWait() { instruction.setResolveCircularWait(false); };
|
||||||
|
|
||||||
string getRunway() { return runway; };
|
string getRunway() { return runway; };
|
||||||
void setCallSign(string clsgn) { callsign = clsgn; };
|
void setCallSign(string clsgn) { callsign = clsgn; };
|
||||||
string getCallSign() { return callsign; };
|
string getCallSign() { return callsign; };
|
||||||
|
|
Loading…
Reference in a new issue