bool RORouteDef::repairCurrentRoute(SUMOAbstractRouter<ROEdge, ROVehicle>& router, SUMOTime begin, const ROVehicle& veh, ConstROEdgeVector oldEdges, ConstROEdgeVector& newEdges) const { MsgHandler* mh = (OptionsCont::getOptions().getBool("ignore-errors") ? MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance()); const int initialSize = (int)oldEdges.size(); if (initialSize == 1) { if (myUsingJTRR) { /// only ROJTRRouter is supposed to handle this type of input router.compute(oldEdges.front(), 0, &veh, begin, newEdges); } else { newEdges = oldEdges; } } else { if (oldEdges.front()->prohibits(&veh)) { // option repair.from is in effect const std::string& frontID = oldEdges.front()->getID(); for (ConstROEdgeVector::iterator i = oldEdges.begin(); i != oldEdges.end();) { if ((*i)->prohibits(&veh) || (*i)->isInternal()) { i = oldEdges.erase(i); } else { WRITE_MESSAGE("Changing invalid starting edge '" + frontID + "' to '" + (*i)->getID() + "' for vehicle '" + veh.getID() + "'."); break; } } } if (oldEdges.size() == 0) { mh->inform("Could not find new starting edge for vehicle '" + veh.getID() + "'."); return false; } if (oldEdges.back()->prohibits(&veh)) { // option repair.to is in effect const std::string& backID = oldEdges.back()->getID(); // oldEdges cannot get empty here, otherwise we would have left the stage when checking "from" while (oldEdges.back()->prohibits(&veh) || oldEdges.back()->isInternal()) { oldEdges.pop_back(); } WRITE_MESSAGE("Changing invalid destination edge '" + backID + "' to edge '" + oldEdges.back()->getID() + "' for vehicle '" + veh.getID() + "'."); } ConstROEdgeVector mandatory = veh.getMandatoryEdges(oldEdges.front(), oldEdges.back()); assert(mandatory.size() >= 2); // removed prohibited for (ConstROEdgeVector::iterator i = oldEdges.begin(); i != oldEdges.end();) { if ((*i)->prohibits(&veh) || (*i)->isInternal()) { // no need to check the mandatories here, this was done before i = oldEdges.erase(i); } else { ++i; } } // reconnect remaining edges if (mandatory.size() > oldEdges.size() && initialSize > 2) { WRITE_MESSAGE("There are stop edges which were not part of the original route for vehicle '" + veh.getID() + "'."); } const ConstROEdgeVector& targets = mandatory.size() > oldEdges.size() ? mandatory : oldEdges; newEdges.push_back(*(targets.begin())); ConstROEdgeVector::iterator nextMandatory = mandatory.begin() + 1; int lastMandatory = 0; for (ConstROEdgeVector::const_iterator i = targets.begin() + 1; i != targets.end() && nextMandatory != mandatory.end(); ++i) { if ((*(i - 1))->isConnectedTo(*i, &veh)) { newEdges.push_back(*i); } else { if (initialSize > 2) { // only inform if the input is (probably) not a trip WRITE_MESSAGE("Edge '" + (*(i - 1))->getID() + "' not connected to edge '" + (*i)->getID() + "' for vehicle '" + veh.getID() + "'."); } const ROEdge* const last = newEdges.back(); newEdges.pop_back(); if (!router.compute(last, *i, &veh, begin, newEdges)) { // backtrack: try to route from last mandatory edge to next mandatory edge // XXX add option for backtracking in smaller increments // (i.e. previous edge to edge after *i) // we would then need to decide whether we have found a good // tradeoff between faithfulness to the input data and detour-length ConstROEdgeVector edges; if (lastMandatory >= (int)newEdges.size() || last == newEdges[lastMandatory] || !router.compute(newEdges[lastMandatory], *nextMandatory, &veh, begin, edges)) { mh->inform("Mandatory edge '" + (*i)->getID() + "' not reachable by vehicle '" + veh.getID() + "'."); return false; } while (*i != *nextMandatory) { ++i; } newEdges.erase(newEdges.begin() + lastMandatory + 1, newEdges.end()); std::copy(edges.begin() + 1, edges.end(), back_inserter(newEdges)); } } if (*i == *nextMandatory) { nextMandatory++; lastMandatory = (int)newEdges.size() - 1; } } } return true; }