X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FAirports%2Fgroundnetwork.cxx;h=b4f48caeeea2f158dc3a8d0042933d1fb94efb99;hb=49030e700ba276d5cd6ffa4f4e661a266fa0105c;hp=711efa50b203a8e0e7a97a28cdc7e4c9ab4a9d65;hpb=e389bed31f089ad7db1bb285e5bddf00febe4bc8;p=flightgear.git diff --git a/src/Airports/groundnetwork.cxx b/src/Airports/groundnetwork.cxx index 711efa50b..b4f48caee 100644 --- a/src/Airports/groundnetwork.cxx +++ b/src/Airports/groundnetwork.cxx @@ -41,51 +41,24 @@ //#include
//#include +#include #include -//#include STL_STRING +//#include #include "groundnetwork.hxx" -SG_USING_STD(sort); - - - -/************************************************************************** - * FGTaxiNode - *************************************************************************/ -FGTaxiNode::FGTaxiNode() -{ -} - -void FGTaxiNode::sortEndSegments(bool byLength) -{ - if (byLength) - sort(next.begin(), next.end(), sortByLength); - else - sort(next.begin(), next.end(), sortByHeadingDiff); -} - - -bool compare_nodes(FGTaxiNode *a, FGTaxiNode *b) { -return (*a) < (*b); -} - /*************************************************************************** * FGTaxiSegment **************************************************************************/ -FGTaxiSegment::FGTaxiSegment() -{ - oppositeDirection = 0; - isActive = true; -} void FGTaxiSegment::setStart(FGTaxiNodeVector *nodes) { FGTaxiNodeVectorIterator i = nodes->begin(); while (i != nodes->end()) { + //cerr << "Scanning start node index" << (*i)->getIndex() << endl; if ((*i)->getIndex() == startNode) { start = (*i)->getAddress(); @@ -94,6 +67,7 @@ void FGTaxiSegment::setStart(FGTaxiNodeVector *nodes) } i++; } + SG_LOG(SG_GENERAL, SG_ALERT, "Could not find start node " << startNode << endl); } void FGTaxiSegment::setEnd(FGTaxiNodeVector *nodes) @@ -101,6 +75,7 @@ void FGTaxiSegment::setEnd(FGTaxiNodeVector *nodes) FGTaxiNodeVectorIterator i = nodes->begin(); while (i != nodes->end()) { + //cerr << "Scanning end node index" << (*i)->getIndex() << endl; if ((*i)->getIndex() == endNode) { end = (*i)->getAddress(); @@ -108,6 +83,7 @@ void FGTaxiSegment::setEnd(FGTaxiNodeVector *nodes) } i++; } + SG_LOG(SG_GENERAL, SG_ALERT, "Could not find end node " << endNode << endl); } @@ -135,17 +111,7 @@ void FGTaxiSegment::setCourseDiff(double crse) headingDiff = fabs(headingDiff - 360); } -bool compare_segments(FGTaxiSegment *a, FGTaxiSegment *b) { -return (*a) < (*b); -} - -bool sortByHeadingDiff(FGTaxiSegment *a, FGTaxiSegment *b) { - return a->hasSmallerHeadingDiff(*b); -} -bool sortByLength(FGTaxiSegment *a, FGTaxiSegment *b) { - return a->getLength() > b->getLength(); -} /*************************************************************************** * FGTaxiRoute **************************************************************************/ @@ -225,6 +191,13 @@ void FGTaxiRoute::rewind(int route) /*************************************************************************** * FGGroundNetwork() **************************************************************************/ +bool compare_nodes(FGTaxiNode *a, FGTaxiNode *b) { +return (*a) < (*b); +} + +bool compare_segments(FGTaxiSegment *a, FGTaxiSegment *b) { +return (*a) < (*b); +} FGGroundNetwork::FGGroundNetwork() { @@ -232,7 +205,7 @@ FGGroundNetwork::FGGroundNetwork() foundRoute = false; totalDistance = 0; maxDistance = 0; - maxDepth = 1000; + //maxDepth = 1000; count = 0; currTraffic = activeTraffic.begin(); @@ -247,6 +220,7 @@ FGGroundNetwork::~FGGroundNetwork() delete (*node); } nodes.clear(); + pushBackNodes.clear(); for (FGTaxiSegmentVectorIterator seg = segments.begin(); seg != segments.end(); seg++) @@ -291,13 +265,17 @@ void FGGroundNetwork::init() //sort(segments.begin(), segments.end(), compare_segments()); FGTaxiSegmentVectorIterator i = segments.begin(); while(i != segments.end()) { - //cerr << "initializing node " << i->getIndex() << endl; (*i)->setStart(&nodes); (*i)->setEnd (&nodes); (*i)->setTrackDistance(); (*i)->setIndex(index); - //cerr << "Track distance = " << i->getLength() << endl; - //cerr << "Track ends at" << i->getEnd()->getIndex() << endl; + if ((*i)->isPushBack()) { + pushBackNodes.push_back((*i)->getEnd()); + } + //SG_LOG(SG_GENERAL, SG_BULK, "initializing segment " << (*i)->getIndex() << endl); + //SG_LOG(SG_GENERAL, SG_BULK, "Track distance = " << (*i)->getLength() << endl); + //SG_LOG(SG_GENERAL, SG_BULK, "Track runs from " << (*i)->getStart()->getIndex() << " to " + // << (*i)->getEnd()->getIndex() << endl); i++; index++; } @@ -323,6 +301,13 @@ void FGGroundNetwork::init() } i++; } + //FGTaxiNodeVectorIterator j = nodes.begin(); + //while (j != nodes.end()) { + // if ((*j)->getHoldPointType() == 3) { + // pushBackNodes.push_back((*j)); + // } + // j++; + //} //cerr << "Done initializing ground network" << endl; //exit(1); } @@ -392,264 +377,113 @@ FGTaxiSegment *FGGroundNetwork::findSegment(int idx) } } -FGTaxiRoute FGGroundNetwork::findShortestRoute(int start, int end) -{ - double course; - double length; - 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); - for (FGTaxiSegmentVectorIterator - itr = segments.begin(); - itr != segments.end(); itr++) - { - (*itr)->setCourseDiff(course); - } - //FGTaxiNodeVectorIterator nde = nodes.begin(); - //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) - { - 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()) - { - // if ((routes.begin()->getDepth() < 0.5 * maxDepth) && (maxDepth > 1)) -// { -// maxDepth--; -// cerr << "Max search depth decreased to : " << maxDepth; -// } -// else -// { -// maxDepth++; -// cerr << "Max search depth increased to : " << maxDepth; -// } - return *(routes.begin()); - } - else - return empty; -} - -void FGGroundNetwork::trace(FGTaxiNode *currNode, int end, int depth, double distance) +FGTaxiRoute FGGroundNetwork::findShortestRoute(int start, int end, bool fullSearch) { - // Just check some preconditions of the trace algorithm - if (nodesStack.size() != routesStack.size()) - { - SG_LOG(SG_GENERAL, SG_ALERT, "size of nodesStack and routesStack is not equal. NodesStack :" - << nodesStack.size() << ". RoutesStack : " << routesStack.size()); - } - nodesStack.push_back(currNode->getIndex()); - totalDistance += distance; - //cerr << "Starting trace " << currNode->getIndex() << " " << "total distance: " << totalDistance << endl; - // << currNode->getIndex() << endl; - - // If the current route matches the required end point we found a valid route - // So we can add this to the routing table - if (currNode->getIndex() == end) - { - maxDepth = depth; - //cerr << "Found route : " << totalDistance << "" << " " << *(nodesStack.end()-1) << " Depth = " << depth << endl; - routes.push_back(FGTaxiRoute(nodesStack,routesStack,totalDistance, depth)); - if (nodesStack.empty() || routesStack.empty()) - { - printRoutingError(string("while finishing route")); - } - nodesStack.pop_back(); - routesStack.pop_back(); - if (!(foundRoute)) { - maxDistance = totalDistance; - } - else - if (totalDistance < maxDistance) - maxDistance = totalDistance; - foundRoute = true; - totalDistance -= distance; - return; +//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 *currNodesSet; + if (fullSearch) { + currNodesSet = &nodes; + } else { + currNodesSet = &pushBackNodes; } - - // search if the currentNode has been encountered before - // if so, we should step back one level, because it is - // rather rediculous to proceed further from here. - // if the current node has not been encountered before, - // i should point to nodesStack.end()-1; and we can continue - // if i is not nodesStack.end, the previous node was found, - // and we should return. - // This only works at trace levels of 1 or higher though - if (depth > 0) { - intVecIterator i = nodesStack.begin(); - while ((*i) != currNode->getIndex()) { - //cerr << "Route so far : " << (*i) << endl; - i++; - } - if (i != nodesStack.end()-1) { - if (nodesStack.empty() || routesStack.empty()) - { - printRoutingError(string("while returning from an already encountered node")); - } - nodesStack.pop_back(); - routesStack.pop_back(); - totalDistance -= distance; - return; - } - if (depth >= maxDepth) { - count++; - if (!(count % 100000)) { - maxDepth--; // Gradually decrease maxdepth, to prevent "eternal searches" - //cerr << "Reducing maxdepth to " << maxDepth << endl; - } - nodesStack.pop_back(); - routesStack.pop_back(); - totalDistance -= distance; - return; + for (FGTaxiNodeVectorIterator + itr = currNodesSet->begin(); + itr != currNodesSet->end(); itr++) { + (*itr)->setPathScore(HUGE_VAL); //infinity by all practical means + (*itr)->setPreviousNode(0); // + (*itr)->setPreviousSeg (0); // + } + + FGTaxiNode *firstNode = findNode(start); + firstNode->setPathScore(0); + + FGTaxiNode *lastNode = findNode(end); + + FGTaxiNodeVector unvisited(*currNodesSet); // working copy + + while (!unvisited.empty()) { + FGTaxiNode* best = *(unvisited.begin()); + for (FGTaxiNodeVectorIterator + itr = unvisited.begin(); + itr != unvisited.end(); itr++) { + if ((*itr)->getPathScore() < best->getPathScore()) + best = (*itr); + } + + 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++) { + if (fullSearch || (*seg)->isPushBack()) { + 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); // + } + } else { + // // cerr << "Skipping TaxiSegment " << (*seg)->getIndex() << endl; + } + } + } } - // If the total distance from start to the current waypoint - // is longer than that of a route we can also stop this trace - // and go back one level. - if ((totalDistance > maxDistance) && foundRoute) - //if (foundRoute) - { - //cerr << "Stopping rediculously long trace: " << totalDistance << endl; - if (nodesStack.empty() || routesStack.empty()) - { - printRoutingError(string("while returning from finding a rediculously long route")); - } - nodesStack.pop_back(); - routesStack.pop_back(); - totalDistance -= distance; - return; - } - } - - //cerr << "2" << endl; - if (currNode->getBeginRoute() != currNode->getEndRoute()) - { - double course, length; - //cerr << "3" << endl; - // calculate distance and heading "as the crow flies" between starn and end points" - SGWayPoint first(currNode->getLongitude(), - currNode->getLatitude(), - 0); - //SGWayPoint second (lastNode->getLongitude(), - // lastNode->getLatitude(), - // 0); - - first.CourseAndDistance(destination, &course, &length); - //for (FGTaxiSegmentVectorIterator - // itr = segments.begin(); - // itr != segments.end(); itr++) - // { - // (*itr)->setCourseDiff(course); - // } - //FGTaxiNodeVectorIterator nde = nodes.begin(); - //while (nde != nodes.end()) { - //(*nde)->sortEndSegments(); - //nde++; - - for (FGTaxiSegmentVectorIterator - i = currNode->getBeginRoute(); - i != currNode->getEndRoute(); - i++) - { - (*i)->setCourseDiff(course); - } - currNode->sortEndSegments(foundRoute); - for (FGTaxiSegmentVectorIterator - i = currNode->getBeginRoute(); - i != currNode->getEndRoute(); - i++) - { - //cerr << (*i)->getLength() << endl; - //cerr << (*i)->getIndex() << endl; - int idx = (*i)->getIndex(); - routesStack.push_back((*i)->getIndex()); - trace((*i)->getEnd(), end, depth+1, (*i)->getLength()); - // { - // // cerr << currNode -> getIndex() << " "; - // route.push_back(currNode->getIndex()); - // return true; - // } - } - } - else - { - //SG_LOG( SG_GENERAL, SG_DEBUG, "4" ); - } - if (nodesStack.empty()) - { - printRoutingError(string("while finishing trace")); - } - nodesStack.pop_back(); - // Make sure not to dump the level-zero routesStack entry, because that was never created. - if (depth) - { - routesStack.pop_back(); - //cerr << "leaving trace " << routesStack.size() << endl; + + if (lastNode->getPathScore() == 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); } - totalDistance -= distance; - return; } -void FGGroundNetwork::printRoutingError(string mess) -{ - SG_LOG(SG_GENERAL, SG_ALERT, "Error in ground network trace algorithm " << mess); - if (nodesStack.empty()) - { - SG_LOG(SG_GENERAL, SG_ALERT, " nodesStack is empty. Dumping routesStack"); - for (intVecIterator i = routesStack.begin() ; i != routesStack.end(); i++) - SG_LOG(SG_GENERAL, SG_ALERT, "Route " << (*i)); - } - if (routesStack.empty()) - { - SG_LOG(SG_GENERAL, SG_ALERT, " routesStack is empty. Dumping nodesStack"); - for (intVecIterator i = nodesStack.begin() ; i != nodesStack.end(); i++) - SG_LOG(SG_GENERAL, SG_ALERT, "Node " << (*i)); - } - //exit(1); +int FGTaxiSegment::getPenalty(int nGates) { + int penalty = 0; + if (end->getIndex() < nGates) { + penalty += 10000; + } + if (end->getIsOnRunway()) { // For now. In future versions, need to find out whether runway is active. + penalty += 1000; + } + return penalty; } +/* ATC Related Functions */ void FGGroundNetwork::announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentPosition, double lat, double lon, double heading, double speed, double alt, double radius, int leg, - string callsign) + FGAIAircraft *aircraft) { TrafficVectorIterator i = activeTraffic.begin(); // Search search if the current id alread has an entry @@ -670,7 +504,7 @@ void FGGroundNetwork::announcePosition(int id, FGAIFlightPlan *intendedRoute, in rec.setPositionAndIntentions(currentPosition, intendedRoute); rec.setPositionAndHeading(lat, lon, heading, speed, alt); rec.setRadius(radius); // only need to do this when creating the record. - rec.setCallSign(callsign); + rec.setAircraft(aircraft); activeTraffic.push_back(rec); } else { i->setPositionAndIntentions(currentPosition, intendedRoute); @@ -729,20 +563,34 @@ void FGGroundNetwork::update(int id, double lat, double lon, double heading, dou // return; //else // setDt(0); + current->clearResolveCircularWait(); + current->setWaitsForId(0); checkSpeedAdjustment(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, double lon, double heading, 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 i = activeTraffic.begin(); bool otherReasonToSlowDown = false; @@ -765,9 +613,10 @@ void FGGroundNetwork::checkSpeedAdjustment(int id, double lat, SG_LOG(SG_GENERAL, SG_ALERT, "AI error: Trying to access non-existing aircraft in FGGroundNetwork::checkSpeedAdjustment"); } current = i; - closest = current; + //closest = current; + previousInstruction = current->getSpeedAdjustment(); - double mindist = HUGE; + double mindist = HUGE_VAL; if (activeTraffic.size()) { double course, dist, bearing, minbearing; @@ -775,7 +624,7 @@ void FGGroundNetwork::checkSpeedAdjustment(int id, double lat, lat, alt); //TrafficVector iterator closest; - //closest = current; + closest = current; for (TrafficVectorIterator i = activeTraffic.begin(); i != activeTraffic.end(); i++) { @@ -804,25 +653,24 @@ void FGGroundNetwork::checkSpeedAdjustment(int id, double lat, for (TrafficVectorIterator i = towerController->getActiveTraffic().begin(); i != towerController->getActiveTraffic().end(); i++) { - if (i != current) { - //SGWayPoint curr (lon, - // lat, - // alt); - SGWayPoint other (i->getLongitude (), - i->getLatitude (), - i->getAltitude ()); - other.CourseAndDistance(curr, &course, &dist); - bearing = fabs(heading-course); - if (bearing > 180) - bearing = 360-bearing; - if ((dist < mindist) && (bearing < 60.0)) - { - mindist = dist; - closest = i; - minbearing = bearing; - otherReasonToSlowDown = true; - } - } + //cerr << "Comparing " << current->getId() << " and " << i->getId() << endl; + //SGWayPoint curr (lon, + // lat, + // alt); + SGWayPoint other (i->getLongitude (), + i->getLatitude (), + i->getAltitude ()); + other.CourseAndDistance(curr, &course, &dist); + bearing = fabs(heading-course); + if (bearing > 180) + bearing = 360-bearing; + if ((dist < mindist) && (bearing < 60.0)) + { + mindist = dist; + closest = i; + minbearing = bearing; + otherReasonToSlowDown = true; + } } } // Finally, check UserPosition @@ -860,7 +708,7 @@ void FGGroundNetwork::checkSpeedAdjustment(int id, double lat, return; else current->setWaitsForId(closest->getId()); - if (closest != current) + if (closest->getId() != current->getId()) current->setSpeedAdjustment(closest->getSpeed()* (mindist/100)); else current->setSpeedAdjustment(0); // This can only happen when the user aircraft is the one closest @@ -878,15 +726,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, double lon, double heading, 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 i = activeTraffic.begin(); @@ -916,7 +767,7 @@ void FGGroundNetwork::checkHoldPosition(int id, double lat, for (i = activeTraffic.begin(); i != activeTraffic.end(); i++) { - if (i != current) + if (i->getId() != current->getId()) { int node = current->crosses(this, *i); if (node != -1) @@ -929,8 +780,7 @@ void FGGroundNetwork::checkHoldPosition(int id, double lat, SGWayPoint nodePos(findNode(node)->getLongitude (), findNode(node)->getLatitude (), alt); - - + SGWayPoint other (i->getLongitude (), i->getLatitude (), i->getAltitude ()); @@ -980,6 +830,7 @@ void FGGroundNetwork::checkHoldPosition(int id, double lat, { current->setHoldPosition(true); + current->setWaitsForId(i->getId()); //cerr << "Hold check 5: " << current->getCallSign() <<" Setting Hold Position: distance to node (" << node << ") " // << dist << " meters. Waiting for " << i->getCallSign(); //if (opposing) @@ -1000,6 +851,113 @@ 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 != 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; + + if (id == target) { + //cerr << "aircraft waits for user" << endl; + return false; + } + + + 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_WARN, "Detected circular wait condition: Id = " << id << "target = " << target); + return true; + } else { + return false; + } +} + // Note that this function is probably obsolete... bool FGGroundNetwork::hasInstruction(int id) { @@ -1046,3 +1004,4 @@ FGATCInstruction FGGroundNetwork::getInstruction(int id) return FGATCInstruction(); } +