#include <config.h>
#include <utils/common/StringUtils.h>
#include <microsim/MSLane.h>
#include <microsim/MSEdge.h>
#include <microsim/MSNet.h>
#include <microsim/MSVehicleControl.h>
#include <microsim/MSStop.h>
#include <microsim/transportables/MSTransportable.h>
#include <microsim/transportables/MSPerson.h>
#include <microsim/traffic_lights/MSTLLogicControl.h>
#include <microsim/traffic_lights/MSSimpleTrafficLightLogic.h>
#include <microsim/traffic_lights/MSActuatedTrafficLightLogic.h>
#include <microsim/traffic_lights/MSDelayBasedTrafficLightLogic.h>
#include "microsim/traffic_lights/NEMAController.h"
#include <microsim/traffic_lights/MSRailSignal.h>
#include <microsim/traffic_lights/MSRailSignalConstraint.h>
#include <microsim/traffic_lights/MSRailSignalControl.h>
#include <netload/NLDetectorBuilder.h>
#include <libsumo/TraCIConstants.h>
#include <libsumo/StorageHelper.h>
#include "Helper.h"
#include "TrafficLight.h"
namespace libsumo {
SubscriptionResults TrafficLight::mySubscriptionResults;
ContextSubscriptionResults TrafficLight::myContextSubscriptionResults;
std::vector<std::string>
TrafficLight::getIDList() {
return MSNet::getInstance()->getTLSControl().getAllTLIds();
}
int
TrafficLight::getIDCount() {
return (int)getIDList().size();
}
std::string
TrafficLight::getRedYellowGreenState(const std::string& tlsID) {
return Helper::getTLS(tlsID).getActive()->getCurrentPhaseDef().getState();
}
std::vector<TraCILogic>
TrafficLight::getAllProgramLogics(const std::string& tlsID) {
std::vector<TraCILogic> result;
const std::vector<MSTrafficLightLogic*> logics = Helper::getTLS(tlsID).getAllLogics();
for (MSTrafficLightLogic* logic : logics) {
TraCILogic l(logic->getProgramID(), (int)logic->getLogicType(), logic->getCurrentPhaseIndex());
l.subParameter = logic->getParametersMap();
for (const MSPhaseDefinition* const phase : logic->getPhases()) {
l.phases.emplace_back(new TraCIPhase(STEPS2TIME(phase->duration), phase->getState(),
STEPS2TIME(phase->minDuration), STEPS2TIME(phase->maxDuration),
phase->getNextPhases(), phase->getName()));
}
result.emplace_back(l);
}
return result;
}
std::vector<std::string>
TrafficLight::getControlledJunctions(const std::string& tlsID) {
std::set<std::string> junctionIDs;
const MSTrafficLightLogic::LinkVectorVector& links = Helper::getTLS(tlsID).getActive()->getLinks();
for (const MSTrafficLightLogic::LinkVector& llinks : links) {
for (const MSLink* l : llinks) {
junctionIDs.insert(l->getJunction()->getID());
}
}
return std::vector<std::string>(junctionIDs.begin(), junctionIDs.end());
}
std::vector<std::string>
TrafficLight::getControlledLanes(const std::string& tlsID) {
std::vector<std::string> laneIDs;
const MSTrafficLightLogic::LaneVectorVector& lanes = Helper::getTLS(tlsID).getActive()->getLaneVectors();
for (const MSTrafficLightLogic::LaneVector& llanes : lanes) {
for (const MSLane* l : llanes) {
laneIDs.push_back(l->getID());
}
}
return laneIDs;
}
std::vector<std::vector<TraCILink> >
TrafficLight::getControlledLinks(const std::string& tlsID) {
std::vector<std::vector<TraCILink> > result;
const MSTrafficLightLogic::LaneVectorVector& lanes = Helper::getTLS(tlsID).getActive()->getLaneVectors();
const MSTrafficLightLogic::LinkVectorVector& links = Helper::getTLS(tlsID).getActive()->getLinks();
for (int i = 0; i < (int)lanes.size(); ++i) {
std::vector<TraCILink> subList;
const MSTrafficLightLogic::LaneVector& llanes = lanes[i];
const MSTrafficLightLogic::LinkVector& llinks = links[i];
for (int j = 0; j < (int)llanes.size(); ++j) {
MSLink* link = llinks[j];
const std::string to = link->getLane() != nullptr ? link->getLane()->getID() : "";
const std::string via = link->getViaLane() != nullptr ? link->getViaLane()->getID() : "";
subList.emplace_back(TraCILink(llanes[j]->getID(), via, to));
}
result.emplace_back(subList);
}
return result;
}
std::string
TrafficLight::getProgram(const std::string& tlsID) {
return Helper::getTLS(tlsID).getActive()->getProgramID();
}
int
TrafficLight::getPhase(const std::string& tlsID) {
return Helper::getTLS(tlsID).getActive()->getCurrentPhaseIndex();
}
std::string
TrafficLight::getPhaseName(const std::string& tlsID) {
return Helper::getTLS(tlsID).getActive()->getCurrentPhaseDef().getName();
}
double
TrafficLight::getPhaseDuration(const std::string& tlsID) {
return STEPS2TIME(Helper::getTLS(tlsID).getActive()->getCurrentPhaseDef().duration);
}
double
TrafficLight::getNextSwitch(const std::string& tlsID) {
return STEPS2TIME(Helper::getTLS(tlsID).getActive()->getNextSwitchTime());
}
double
TrafficLight::getSpentDuration(const std::string& tlsID) {
return STEPS2TIME(Helper::getTLS(tlsID).getActive()->getSpentDuration());
}
int
TrafficLight::getServedPersonCount(const std::string& tlsID, int index) {
MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getActive();
if (index < 0 || active->getPhaseNumber() <= index) {
throw TraCIException("The phase index " + toString(index) + " is not in the allowed range [0,"
+ toString(active->getPhaseNumber() - 1) + "].");
}
int result = 0;
const std::string& state = active->getPhases()[index]->getState();
for (int i = 0; i < (int)state.size(); i++) {
if (state[i] == LINKSTATE_TL_GREEN_MAJOR) {
for (MSLink* link : active->getLinksAt(i)) {
if (link->getLane()->getEdge().isCrossing()) {
for (MSTransportable* person : link->getLaneBefore()->getEdge().getPersons()) {
if (static_cast<MSPerson*>(person)->getNextEdge() == link->getLane()->getEdge().getID()) {
result += 1;
}
}
MSLane* walkingAreaAcross = link->getLane()->getLinkCont().front()->getLane();
for (MSTransportable* person : walkingAreaAcross->getEdge().getPersons()) {
if (static_cast<MSPerson*>(person)->getNextEdge() == link->getLane()->getEdge().getID()) {
result += 1;
}
}
} else if (link->getLaneBefore()->getEdge().isCrossing()) {
for (MSTransportable* person : link->getLane()->getEdge().getPersons()) {
if (static_cast<MSPerson*>(person)->getNextEdge() == link->getLaneBefore()->getEdge().getID()) {
result += 1;
}
}
}
}
}
}
return result;
}
std::vector<std::string>
TrafficLight::getBlockingVehicles(const std::string& tlsID, int linkIndex) {
std::vector<std::string> result;
MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
if (linkIndex < 0 || linkIndex >= active->getNumLinks()) {
throw TraCIException("The link index " + toString(linkIndex) + " is not in the allowed range [0,"
+ toString(active->getNumLinks() - 1) + "].");
}
for (const SUMOVehicle* veh : active->getBlockingVehicles(linkIndex)) {
result.push_back(veh->getID());
}
return result;
}
std::vector<std::string>
TrafficLight::getRivalVehicles(const std::string& tlsID, int linkIndex) {
std::vector<std::string> result;
MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
if (linkIndex < 0 || linkIndex >= active->getNumLinks()) {
throw TraCIException("The link index " + toString(linkIndex) + " is not in the allowed range [0,"
+ toString(active->getNumLinks() - 1) + "].");
}
for (const SUMOVehicle* veh : active->getRivalVehicles(linkIndex)) {
result.push_back(veh->getID());
}
return result;
}
std::vector<std::string>
TrafficLight::getPriorityVehicles(const std::string& tlsID, int linkIndex) {
std::vector<std::string> result;
MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
if (linkIndex < 0 || linkIndex >= active->getNumLinks()) {
throw TraCIException("The link index " + toString(linkIndex) + " is not in the allowed range [0,"
+ toString(active->getNumLinks() - 1) + "].");
}
for (const SUMOVehicle* veh : active->getPriorityVehicles(linkIndex)) {
result.push_back(veh->getID());
}
return result;
}
std::vector<TraCISignalConstraint>
TrafficLight::getConstraints(const std::string& tlsID, const std::string& tripId) {
std::vector<TraCISignalConstraint> result;
MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
MSRailSignal* s = dynamic_cast<MSRailSignal*>(active);
if (s == nullptr) {
throw TraCIException("'" + tlsID + "' is not a rail signal");
}
for (auto item : s->getConstraints()) {
if (tripId != "" && tripId != item.first) {
continue;
}
for (MSRailSignalConstraint* c : item.second) {
result.push_back(buildConstraint(tlsID, item.first, c));
}
}
return result;
}
std::vector<TraCISignalConstraint>
TrafficLight::getConstraintsByFoe(const std::string& foeSignal, const std::string& foeId) {
std::vector<TraCISignalConstraint> result;
for (const std::string& tlsID : getIDList()) {
MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
MSRailSignal* s = dynamic_cast<MSRailSignal*>(active);
if (s != nullptr) {
for (auto item : s->getConstraints()) {
for (MSRailSignalConstraint* cand : item.second) {
MSRailSignalConstraint_Predecessor* pc = dynamic_cast<MSRailSignalConstraint_Predecessor*>(cand);
if (pc != nullptr && pc->myFoeSignal->getID() == foeSignal
&& (foeId == "" || pc->myTripId == foeId)) {
result.push_back(buildConstraint(s->getID(), item.first, pc));
}
}
}
}
}
return result;
}
void
TrafficLight::addConstraint(const std::string& tlsID, const std::string& tripId, const std::string& foeSignal, const std::string& foeId, const int type, const int limit) {
MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
MSTrafficLightLogic* const active2 = Helper::getTLS(foeSignal).getDefault();
MSRailSignal* s = dynamic_cast<MSRailSignal*>(active);
MSRailSignal* s2 = dynamic_cast<MSRailSignal*>(active2);
if (s == nullptr) {
throw TraCIException("'" + tlsID + "' is not a rail signal");
}
if (s2 == nullptr) {
throw TraCIException("'" + foeSignal + "' is not a rail signal");
}
MSRailSignalConstraint* c = new MSRailSignalConstraint_Predecessor((MSRailSignalConstraint::ConstraintType)type, s2, foeId, limit, true);
s->addConstraint(tripId, c);
}
std::vector<TraCISignalConstraint>
TrafficLight::swapConstraints(const std::string& tlsID, const std::string& tripId, const std::string& foeSignal, const std::string& foeId) {
#ifdef DEBUG_CONSTRAINT_DEADLOCK
std::cout << "swapConstraints tlsId=" << tlsID << " tripId=" << tripId << " foeSignal=" << foeSignal << " foeId=" << foeId << "\n";
#endif
MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
MSTrafficLightLogic* const active2 = Helper::getTLS(foeSignal).getDefault();
MSRailSignal* s = dynamic_cast<MSRailSignal*>(active);
MSRailSignal* s2 = dynamic_cast<MSRailSignal*>(active2);
if (s == nullptr) {
throw TraCIException("'" + tlsID + "' is not a rail signal");
}
if (s2 == nullptr) {
throw TraCIException("'" + foeSignal + "' is not a rail signal");
}
MSRailSignalConstraint_Predecessor* c = nullptr;
for (auto item : s->getConstraints()) {
if (tripId == item.first) {
for (MSRailSignalConstraint* cand : item.second) {
MSRailSignalConstraint_Predecessor* pc = dynamic_cast<MSRailSignalConstraint_Predecessor*>(cand);
if (pc != nullptr && pc->myFoeSignal->getID() == foeSignal && pc->myTripId == foeId) {
c = pc;
break;
}
}
break;
}
}
if (c != nullptr) {
const int limit = c->myLimit;
MSRailSignalConstraint::ConstraintType type = c->getSwappedType();
MSRailSignalConstraint* swapped = new MSRailSignalConstraint_Predecessor(type, s, tripId, limit, true);
swapped->updateParameters(c->getParametersMap());
swapParameters(swapped);
s->removeConstraint(tripId, c);
s2->addConstraint(foeId, swapped);
return findConstraintsDeadLocks(foeId, tripId, foeSignal, tlsID);
} else {
throw TraCIException("Rail signal '" + tlsID + "' does not have a constraint for tripId '" + tripId + "' with foeSignal '" + foeSignal + "' and foeId '" + foeId + "'");
}
}
std::vector<std::pair<std::string, std::string> >
TrafficLight::getSwapParams(int constraintType) {
std::vector<std::pair<std::string, std::string> > result({
{"vehID", "foeID"},
{"line", "foeLine"},
{"arrival", "foeArrival"}});
if (constraintType == MSRailSignalConstraint::ConstraintType::BIDI_PREDECESSOR) {
std::vector<std::pair<std::string, std::string> > special({
{"busStop", "busStop2"},
{"priorStop", "priorStop2"},
{"stopArrival", "foeStopArrival"}});
result.insert(result.end(), special.begin(), special.end());
}
return result;
}
void
TrafficLight::swapParameters(MSRailSignalConstraint* c) {
for (auto keys : getSwapParams(c->getType())) {
swapParameters(c, keys.first, keys.second);
}
}
void
TrafficLight::swapParameters(MSRailSignalConstraint* c, const std::string& key1, const std::string& key2) {
const std::string value1 = c->getParameter(key1);
const std::string value2 = c->getParameter(key2);
if (value1 != "") {
c->setParameter(key2, value1);
} else {
c->unsetParameter(key2);
}
if (value2 != "") {
c->setParameter(key1, value2);
} else {
c->unsetParameter(key1);
}
}
void
TrafficLight::swapParameters(TraCISignalConstraint& c) {
for (auto keys : getSwapParams(c.type)) {
swapParameters(c, keys.first, keys.second);
}
}
void
TrafficLight::swapParameters(TraCISignalConstraint& c, const std::string& key1, const std::string& key2) {
auto it1 = c.param.find(key1);
auto it2 = c.param.find(key2);
const std::string value1 = it1 != c.param.end() ? it1->second : "";
const std::string value2 = it2 != c.param.end() ? it2->second : "";
if (value1 != "") {
c.param[key2] = value1;
} else {
c.param.erase(key2);
}
if (value2 != "") {
c.param[key1] = value2;
} else {
c.param.erase(key1);
}
}
void
TrafficLight::removeConstraints(const std::string& tlsID, const std::string& tripId, const std::string& foeSignal, const std::string& foeId) {
for (const std::string& tlsCand : getIDList()) {
if (tlsID == "" || tlsCand == tlsID) {
MSTrafficLightLogic* const active = Helper::getTLS(tlsCand).getDefault();
MSRailSignal* s = dynamic_cast<MSRailSignal*>(active);
if (s != nullptr) {
for (auto item : s->getConstraints()) {
if (tripId == "" || item.first == tripId) {
for (MSRailSignalConstraint* cand : item.second) {
MSRailSignalConstraint_Predecessor* pc = dynamic_cast<MSRailSignalConstraint_Predecessor*>(cand);
if (pc != nullptr
&& (foeId == "" || pc->myTripId == foeId)
&& (foeSignal == "" || pc->myFoeSignal->getID() == foeSignal)) {
cand->setActive(false);
}
}
}
}
}
}
}
}
void
TrafficLight::updateConstraints(const std::string& vehID, std::string tripId) {
MSBaseVehicle* veh = Helper::getVehicle(vehID);
std::string curTripId = veh->getParameter().getParameter("tripId", veh->getID());
tripId = tripId == "" ? curTripId : tripId;
std::map<const MSRailSignal*, std::set<std::string> > onRoute;
const ConstMSEdgeVector& route = veh->getRoute().getEdges();
auto routeIt = veh->getCurrentRouteEdge();
for (const MSStop& stop : veh->getStops()) {
for (auto it = routeIt; it < stop.edge; it++) {
const MSEdge* edge = *it;
if (edge->getToJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
if (it + 1 != route.end()) {
const MSEdge* next = *(it + 1);
const MSLink* link = edge->getLanes()[0]->getLinkTo(next->getLanes()[0]);
if (link != nullptr && link->getTLLogic() != nullptr) {
const MSRailSignal* s = dynamic_cast<const MSRailSignal*>(link->getTLLogic());
onRoute[s].insert(curTripId);
}
}
}
}
if (stop.pars.tripId != "") {
curTripId = stop.pars.tripId;
}
routeIt = stop.edge;
}
for (auto it = routeIt; it < route.end(); it++) {
const MSEdge* edge = *it;
if (edge->getToJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
if (it + 1 != route.end()) {
const MSEdge* next = *(it + 1);
const MSLink* link = edge->getLanes()[0]->getLinkTo(next->getLanes()[0]);
if (link != nullptr && link->getTLLogic() != nullptr) {
const MSRailSignal* s = dynamic_cast<const MSRailSignal*>(link->getTLLogic());
onRoute[s].insert(curTripId);
}
}
}
}
for (MSRailSignal* s : MSRailSignalControl::getInstance().getSignals()) {
std::vector<MSRailSignalConstraint*> onVeh;
std::vector<std::pair<std::string, MSRailSignalConstraint*> > byVeh;
for (auto item : s->getConstraints()) {
for (MSRailSignalConstraint* cand : item.second) {
MSRailSignalConstraint_Predecessor* pc = dynamic_cast<MSRailSignalConstraint_Predecessor*>(cand);
if (pc != nullptr && !pc->cleared() && pc->isActive()) {
if (item.first == tripId) {
if (onRoute[s].count(tripId) == 0) {
onVeh.push_back(cand);
}
} else if (pc->myTripId == tripId) {
if (onRoute[pc->myFoeSignal].count(tripId) == 0) {
byVeh.push_back(std::make_pair(item.first, cand));
}
}
}
}
}
for (MSRailSignalConstraint* c : onVeh) {
s->removeConstraint(tripId, c);
}
for (auto item : byVeh) {
s->removeConstraint(item.first, item.second);
}
}
}
std::vector<TraCISignalConstraint>
TrafficLight::findConstraintsDeadLocks(const std::string& foeId, const std::string& tripId, const std::string& foeSignal, const std::string& tlsID) {
std::vector<TraCISignalConstraint> result;
std::map<std::string, TraCISignalConstraint> constraintsOnTripId;
std::map<std::string, TraCISignalConstraint> constrainedByFoeId;
std::set<std::string> foeId2Cands1;
std::set<std::string> foeId2Cands2;
for (MSRailSignal* s : MSRailSignalControl::getInstance().getSignals()) {
for (auto item : s->getConstraints()) {
for (MSRailSignalConstraint* cand : item.second) {
MSRailSignalConstraint_Predecessor* pc = dynamic_cast<MSRailSignalConstraint_Predecessor*>(cand);
if (pc != nullptr && !pc->cleared() && pc->isActive()) {
if (item.first == tripId) {
libsumo::TraCISignalConstraint tsc = buildConstraint(s->getID(), item.first, pc);
constraintsOnTripId[pc->myTripId] = tsc;
foeId2Cands1.insert(pc->myTripId);
for (std::string& futureFoe2Id : getFutureTripIds(pc->myTripId)) {
foeId2Cands1.insert(futureFoe2Id);
constraintsOnTripId[futureFoe2Id] = tsc;
}
} else if (pc->myTripId == foeId) {
libsumo::TraCISignalConstraint tsc = buildConstraint(s->getID(), item.first, pc);
constrainedByFoeId[item.first] = tsc;
foeId2Cands2.insert(item.first);
for (std::string& futureTripId : getFutureTripIds(item.first)) {
foeId2Cands2.insert(futureTripId);
constrainedByFoeId[futureTripId] = tsc;
}
}
}
}
}
}
#ifdef DEBUG_CONSTRAINT_DEADLOCK
std::cout << "findConstraintsDeadLocks foeId=" << foeId << " tripId=" << tripId << " foeSignal=" << foeSignal << " tlsID=" << tlsID << "\n";
std::cout << " foeId2Cands1=" << toString(foeId2Cands1) << "\n";
std::cout << " foeId2Cands2=" << toString(foeId2Cands2) << "\n";
#endif
if (foeId2Cands1.size() > 0) {
SUMOVehicle* foe = getVehicleByTripId(foeId);
if (foe != nullptr) {
const MSEdge* foeEdge = foe->getEdge();
const double foePos = foe->getPositionOnLane();
for (const std::string& foeId2 : foeId2Cands1) {
SUMOVehicle* foe2 = getVehicleByTripId(foeId2);
if (foe2 != nullptr) {
const ConstMSEdgeVector& foe2Route = foe2->getRoute().getEdges();
const TraCISignalConstraint& c = constraintsOnTripId[foeId2];
bool foeAhead = false;
for (int i = foe2->getRoutePosition(); i < (int)foe2Route.size(); i++) {
const MSEdge* e = foe2Route[i];
if (e == foeEdge &&
((e != foe2->getEdge() || foe2->getPositionOnLane() < foePos)
|| (foe->hasDeparted() && !foe2->hasDeparted())
|| (!foe->hasDeparted() && !foe2->hasDeparted() &&
(foe->getParameter().depart < foe2->getParameter().depart
|| (foe->getParameter().depart == foe2->getParameter().depart && foe->getNumericalID() < foe2->getNumericalID())))
)) {
foeAhead = true;
#ifdef DEBUG_CONSTRAINT_DEADLOCK
std::cout << "findConstraintsDeadLocks foeId=" << foeId << " tripId=" << tripId << " foeSignal=" << foeSignal << "\n";
std::cout << " foeLeaderDeadlock foeEdge=" << foeEdge->getID() << " foe2=" << foe2->getParameter().getParameter("tripId", foe2->getID())
<< " routePos=" << foe2->getRoutePosition() << " futureRPos=" << i << " e=" << e->getID()
<< " " << constraintsOnTripId[foeId2].getString() << "\n";
#endif
break;
}
if (e->getToJunction()->getID() == foeSignal
|| e->getToJunction()->getID() == c.foeSignal) {
break;
}
}
if (foeAhead) {
TraCISignalConstraint nc;
nc.tripId = c.foeId;
nc.foeId = c.tripId;
nc.signalId = c.foeSignal;
nc.foeSignal = c.signalId;
nc.limit = c.limit;
nc.type = c.type;
nc.mustWait = true;
nc.active = true;
nc.param = c.param;
swapParameters(nc);
result.push_back(nc);
std::vector<TraCISignalConstraint> result2 = swapConstraints(c.signalId, c.tripId, c.foeSignal, c.foeId);
result.insert(result.end(), result2.begin(), result2.end());
const std::vector<TraCISignalConstraint>& result4 = findConstraintsDeadLocks(foeId, tripId, foeSignal, tlsID);
result.insert(result.end(), result4.begin(), result4.end());
return result;
}
}
}
}
}
if (foeId2Cands2.size() > 0) {
SUMOVehicle* ego = getVehicleByTripId(tripId);
if (ego != nullptr && (ego->hasDeparted() || !ego->getParameter().wasSet(VEHPARS_FORCE_REROUTE))) {
std::set<const MSEdge*> egoToSignal;
const double egoPos = ego->getPositionOnLane();
const ConstMSEdgeVector& egoRoute = ego->getRoute().getEdges();
for (int i = ego->getRoutePosition(); i < (int)egoRoute.size(); i++) {
const MSEdge* e = egoRoute[i];
egoToSignal.insert(e);
if (e->getToJunction()->getID() == tlsID) {
break;
}
}
for (const std::string& foeId2 : foeId2Cands2) {
SUMOVehicle* foe2 = getVehicleByTripId(foeId2);
if (foe2 != nullptr) {
if (egoToSignal.count(foe2->getEdge()) != 0
&& (foe2->getEdge() != ego->getEdge() || foe2->getPositionOnLane() > egoPos)) {
const TraCISignalConstraint& c = constrainedByFoeId[foeId2];
#ifdef DEBUG_CONSTRAINT_DEADLOCK
std::cout << "findConstraintsDeadLocks foeId=" << foeId << " tripId=" << tripId << " foeSignal=" << foeSignal << "\n";
std::cout << " egoLeaderDeadlock foe2Edge=" << foe2->getEdge()->getID() << " foe2=" << foe2->getParameter().getParameter("tripId", foe2->getID())
<< " " << c.getString() << "\n";
#endif
TraCISignalConstraint nc;
nc.tripId = c.foeId;
nc.foeId = c.tripId;
nc.signalId = c.foeSignal;
nc.foeSignal = c.signalId;
nc.limit = c.limit;
nc.type = c.type;
nc.mustWait = true;
nc.active = true;
nc.param = c.param;
swapParameters(nc);
result.push_back(nc);
std::vector<TraCISignalConstraint> result2 = swapConstraints(c.signalId, c.tripId, c.foeSignal, c.foeId);
result.insert(result.end(), result2.begin(), result2.end());
const std::vector<TraCISignalConstraint>& result4 = findConstraintsDeadLocks(foeId, tripId, foeSignal, tlsID);
result.insert(result.end(), result4.begin(), result4.end());
return result;
}
}
}
} else if (ego != nullptr) {
WRITE_WARNINGF(TL("Cannot check for all deadlocks on swapConstraints because the route for vehicle '%' is not computed yet"), ego->getID());
}
}
std::vector<std::string> foeIds2;
std::set_intersection(
foeId2Cands1.begin(), foeId2Cands1.end(),
foeId2Cands2.begin(), foeId2Cands2.end(),
std::back_inserter(foeIds2));
#ifdef DEBUG_CONSTRAINT_DEADLOCK
std::cout << "findConstraintsDeadLocks foeId=" << foeId << " tripId=" << tripId << " foeSignal=" << foeSignal << "\n";
for (const std::string& foeId2 : foeIds2) {
std::cout << " deadlockId=" << foeId2 << " " << constraintsOnTripId[foeId2].getString() << " " << constrainedByFoeId[foeId2].getString() << "\n";
}
#endif
if (foeIds2.size() > 0) {
TraCISignalConstraint c = constrainedByFoeId[foeIds2.front()];
if (c.type == MSRailSignalConstraint::ConstraintType::INSERTION_PREDECESSOR) {
c = constraintsOnTripId[foeIds2.front()];
}
TraCISignalConstraint nc;
nc.tripId = c.foeId;
nc.foeId = c.tripId;
nc.signalId = c.foeSignal;
nc.foeSignal = c.signalId;
nc.limit = c.limit;
nc.type = c.type;
nc.mustWait = true;
nc.active = true;
nc.param = c.param;
swapParameters(nc);
result.push_back(nc);
const std::vector<TraCISignalConstraint>& result2 = swapConstraints(c.signalId, c.tripId, c.foeSignal, c.foeId);
result.insert(result.end(), result2.begin(), result2.end());
if (foeIds2.size() > 1) {
const std::vector<TraCISignalConstraint>& result3 = findConstraintsDeadLocks(foeId, tripId, foeSignal, tlsID);
result.insert(result.end(), result3.begin(), result3.end());
}
}
return result;
}
SUMOVehicle*
TrafficLight::getVehicleByTripId(const std::string tripOrVehID) {
MSVehicleControl& c = MSNet::getInstance()->getVehicleControl();
for (MSVehicleControl::constVehIt i = c.loadedVehBegin(); i != c.loadedVehEnd(); ++i) {
SUMOVehicle* veh = i->second;
if (veh->getParameter().getParameter("tripId", veh->getID()) == tripOrVehID) {
return veh;
}
}
return nullptr;
}
std::vector<std::string>
TrafficLight::getFutureTripIds(const std::string vehID) {
std::vector<std::string> result;
MSBaseVehicle* veh = dynamic_cast<MSBaseVehicle*>(MSNet::getInstance()->getVehicleControl().getVehicle(vehID));
if (veh) {
std::string tripId = veh->getParameter().getParameter("tripId");
if (tripId != "") {
result.push_back(tripId);
}
for (const MSStop& stop : veh->getStops()) {
if (stop.pars.tripId != "") {
result.push_back(stop.pars.tripId);
}
}
}
return result;
}
std::string
TrafficLight::getParameter(const std::string& tlsID, const std::string& paramName) {
MSTrafficLightLogic* tll = Helper::getTLS(tlsID).getActive();
if (StringUtils::startsWith(paramName, "NEMA.") && tll->getLogicType() != TrafficLightType::NEMA) {
throw TraCIException("'" + tlsID + "' is not a NEMA controller");
}
return tll->getParameter(paramName, "");
}
LIBSUMO_GET_PARAMETER_WITH_KEY_IMPLEMENTATION(TrafficLight)
void
TrafficLight::setRedYellowGreenState(const std::string& tlsID, const std::string& state) {
Helper::getTLS(tlsID).setStateInstantiatingOnline(MSNet::getInstance()->getTLSControl(), state);
}
void
TrafficLight::setPhase(const std::string& tlsID, const int index) {
MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getActive();
if (index < 0 || active->getPhaseNumber() <= index) {
throw TraCIException("The phase index " + toString(index) + " is not in the allowed range [0,"
+ toString(active->getPhaseNumber() - 1) + "].");
}
const SUMOTime cTime = MSNet::getInstance()->getCurrentTimeStep();
const SUMOTime duration = active->getPhase(index).duration;
active->changeStepAndDuration(MSNet::getInstance()->getTLSControl(), cTime, index, duration);
}
void
TrafficLight::setPhaseName(const std::string& tlsID, const std::string& name) {
MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getActive();
const_cast<MSPhaseDefinition&>(active->getCurrentPhaseDef()).setName(name);
}
void
TrafficLight::setProgram(const std::string& tlsID, const std::string& programID) {
try {
Helper::getTLS(tlsID).switchTo(MSNet::getInstance()->getTLSControl(), programID);
} catch (ProcessError& e) {
throw TraCIException(e.what());
}
}
void
TrafficLight::setPhaseDuration(const std::string& tlsID, const double phaseDuration) {
MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getActive();
const SUMOTime cTime = MSNet::getInstance()->getCurrentTimeStep();
active->changeStepAndDuration(MSNet::getInstance()->getTLSControl(), cTime, -1, TIME2STEPS(phaseDuration));
}
void
TrafficLight::setProgramLogic(const std::string& tlsID, const TraCILogic& logic) {
MSTLLogicControl::TLSLogicVariants& vars = Helper::getTLS(tlsID);
if (logic.currentPhaseIndex >= (int)logic.phases.size()) {
throw TraCIException("set program: parameter index must be less than parameter phase number.");
}
std::vector<MSPhaseDefinition*> phases;
for (const std::shared_ptr<libsumo::TraCIPhase>& phase : logic.phases) {
MSPhaseDefinition* sumoPhase = new MSPhaseDefinition(TIME2STEPS(phase->duration), phase->state, phase->name);
sumoPhase->minDuration = TIME2STEPS(phase->minDur);
sumoPhase->maxDuration = TIME2STEPS(phase->maxDur);
sumoPhase->nextPhases = phase->next;
phases.push_back(sumoPhase);
}
if (vars.getLogic(logic.programID) == nullptr) {
MSTLLogicControl& tlc = MSNet::getInstance()->getTLSControl();
int step = logic.currentPhaseIndex;
const std::string basePath = "";
MSTrafficLightLogic* tlLogic = nullptr;
SUMOTime nextSwitch = MSNet::getInstance()->getCurrentTimeStep() + phases[0]->duration;
switch ((TrafficLightType)logic.type) {
case TrafficLightType::ACTUATED:
tlLogic = new MSActuatedTrafficLightLogic(tlc,
tlsID, logic.programID, 0,
phases, step, nextSwitch,
logic.subParameter, basePath);
break;
case TrafficLightType::NEMA:
tlLogic = new NEMALogic(tlc,
tlsID, logic.programID, 0,
phases, step, nextSwitch,
logic.subParameter, basePath);
break;
case TrafficLightType::DELAYBASED:
tlLogic = new MSDelayBasedTrafficLightLogic(tlc,
tlsID, logic.programID, 0,
phases, step, nextSwitch,
logic.subParameter, basePath);
break;
case TrafficLightType::STATIC:
tlLogic = new MSSimpleTrafficLightLogic(tlc,
tlsID, logic.programID, 0, TrafficLightType::STATIC,
phases, step, nextSwitch,
logic.subParameter);
break;
default:
throw TraCIException("Unsupported traffic light type '" + toString(logic.type) + "'");
}
try {
if (!vars.addLogic(logic.programID, tlLogic, true, true)) {
throw TraCIException("Could not add traffic light logic '" + logic.programID + "'");
}
} catch (const ProcessError& e) {
throw TraCIException(e.what());
}
NLDetectorBuilder db(*MSNet::getInstance());
tlLogic->init(db);
MSNet::getInstance()->createTLWrapper(tlLogic);
} else {
MSSimpleTrafficLightLogic* tlLogic = static_cast<MSSimpleTrafficLightLogic*>(vars.getLogic(logic.programID));
tlLogic->setPhases(phases, logic.currentPhaseIndex);
tlLogic->setTrafficLightSignals(MSNet::getInstance()->getCurrentTimeStep());
vars.executeOnSwitchActions();
}
}
void
TrafficLight::setParameter(const std::string& tlsID, const std::string& paramName, const std::string& value) {
MSTrafficLightLogic* tll = Helper::getTLS(tlsID).getActive();
if (StringUtils::startsWith(paramName, "NEMA.") && tll->getLogicType() != TrafficLightType::NEMA) {
throw TraCIException("'" + tlsID + "' is not a NEMA controller");
}
tll->setParameter(paramName, value);
}
LIBSUMO_SUBSCRIPTION_IMPLEMENTATION(TrafficLight, TL)
void
TrafficLight::setNemaSplits(const std::string& tlsID, const std::vector<double>& splits) {
setParameter(tlsID, "NEMA.splits", toString(splits));
}
void
TrafficLight::setNemaMaxGreens(const std::string& tlsID, const std::vector<double>& maxGreens) {
setParameter(tlsID, "NEMA.maxGreens", toString(maxGreens));
}
void
TrafficLight::setNemaCycleLength(const std::string& tlsID, double cycleLength) {
setParameter(tlsID, "NEMA.cycleLength", toString(cycleLength));
}
void
TrafficLight::setNemaOffset(const std::string& tlsID, double offset) {
setParameter(tlsID, "NEMA.offset", toString(offset));
}
libsumo::TraCISignalConstraint
TrafficLight::buildConstraint(const std::string& tlsID, const std::string& tripId, MSRailSignalConstraint* constraint) {
TraCISignalConstraint c;
c.tripId = tripId;
MSRailSignalConstraint_Predecessor* pc = dynamic_cast<MSRailSignalConstraint_Predecessor*>(constraint);
if (pc == nullptr) {
c.type = -1;
} else {
c.signalId = tlsID;
c.foeId = pc->myTripId;
c.foeSignal = pc->myFoeSignal->getID();
c.limit = pc->myLimit;
c.type = pc->getType();
c.mustWait = !pc->cleared() && pc->isActive();
c.active = pc->isActive();
c.param = constraint->getParametersMap();
}
return c;
}
std::shared_ptr<VariableWrapper>
TrafficLight::makeWrapper() {
return std::make_shared<Helper::SubscriptionWrapper>(handleVariable, mySubscriptionResults, myContextSubscriptionResults);
}
bool
TrafficLight::handleVariable(const std::string& objID, const int variable, VariableWrapper* wrapper, tcpip::Storage* paramData) {
switch (variable) {
case TRACI_ID_LIST:
return wrapper->wrapStringList(objID, variable, getIDList());
case ID_COUNT:
return wrapper->wrapInt(objID, variable, getIDCount());
case TL_RED_YELLOW_GREEN_STATE:
return wrapper->wrapString(objID, variable, getRedYellowGreenState(objID));
case TL_COMPLETE_DEFINITION_RYG:
return wrapper->wrapLogicVector(objID, variable, getAllProgramLogics(objID));
case TL_CONTROLLED_LANES:
return wrapper->wrapStringList(objID, variable, getControlledLanes(objID));
case TL_CONTROLLED_LINKS:
return wrapper->wrapLinkVectorVector(objID, variable, getControlledLinks(objID));
case TL_CURRENT_PHASE:
return wrapper->wrapInt(objID, variable, getPhase(objID));
case VAR_NAME:
return wrapper->wrapString(objID, variable, getPhaseName(objID));
case TL_CURRENT_PROGRAM:
return wrapper->wrapString(objID, variable, getProgram(objID));
case TL_PHASE_DURATION:
return wrapper->wrapDouble(objID, variable, getPhaseDuration(objID));
case TL_NEXT_SWITCH:
return wrapper->wrapDouble(objID, variable, getNextSwitch(objID));
case TL_SPENT_DURATION:
return wrapper->wrapDouble(objID, variable, getSpentDuration(objID));
case VAR_PERSON_NUMBER:
return wrapper->wrapInt(objID, variable, getServedPersonCount(objID, StoHelp::readTypedInt(*paramData)));
case TL_BLOCKING_VEHICLES:
return wrapper->wrapStringList(objID, variable, getBlockingVehicles(objID, StoHelp::readTypedInt(*paramData)));
case TL_RIVAL_VEHICLES:
return wrapper->wrapStringList(objID, variable, getRivalVehicles(objID, StoHelp::readTypedInt(*paramData)));
case TL_PRIORITY_VEHICLES:
return wrapper->wrapStringList(objID, variable, getPriorityVehicles(objID, StoHelp::readTypedInt(*paramData)));
case TL_CONSTRAINT:
return wrapper->wrapSignalConstraintVector(objID, variable, getConstraints(objID, StoHelp::readTypedString(*paramData)));
case TL_CONSTRAINT_BYFOE:
return wrapper->wrapSignalConstraintVector(objID, variable, getConstraintsByFoe(objID, StoHelp::readTypedString(*paramData)));
case TL_CONTROLLED_JUNCTIONS:
return wrapper->wrapStringList(objID, variable, getControlledJunctions(objID));
case VAR_PARAMETER:
return wrapper->wrapString(objID, variable, getParameter(objID, StoHelp::readTypedString(*paramData)));
case VAR_PARAMETER_WITH_KEY:
return wrapper->wrapStringPair(objID, variable, getParameterWithKey(objID, StoHelp::readTypedString(*paramData)));
default:
return false;
}
}
}