42#define MIN_GREEN_TIME 5
49#define DEBUGCOND (true)
50#define DEBUGEDGE(edge) (true)
62 const std::vector<NBNode*>& junctions,
SUMOTime offset,
65 myHaveSinglePhase(false),
73 myHaveSinglePhase(false),
81 myHaveSinglePhase(false),
114 for (
int e1l = 0; e1l < e1->
getNumLanes(); e1l++) {
116 for (
int e2l = 0; e2l < e2->
getNumLanes(); e2l++) {
118 for (std::vector<NBEdge::Connection>::iterator e1c = approached1.begin(); e1c != approached1.end(); ++e1c) {
122 for (std::vector<NBEdge::Connection>::iterator e2c = approached2.begin(); e2c != approached2.end(); ++e2c) {
126 const double sign = (
forbids(e1, (*e1c).toEdge, e2, (*e2c).toEdge,
true)
127 ||
forbids(e2, (*e2c).toEdge, e1, (*e1c).toEdge,
true)) ? -1 : 1;
132 if (prio1 == prio2) {
161#ifdef DEBUG_STREAM_ORDERING
163 std::cout <<
" sign=" << sign <<
" w1=" << w1 <<
" w2=" << w2 <<
" val=" << val
164 <<
" c1=" << (*e1c).getDescription(e1)
165 <<
" c2=" << (*e2c).getDescription(e2)
173#ifdef DEBUG_STREAM_ORDERING
175 std::cout <<
" computeUnblockedWeightedStreamNumber e1=" << e1->
getID() <<
" e2=" << e2->
getID() <<
" val=" << val <<
"\n";
182std::pair<NBEdge*, NBEdge*>
184 std::pair<NBEdge*, NBEdge*> bestPair(
static_cast<NBEdge*
>(
nullptr),
static_cast<NBEdge*
>(
nullptr));
185 double bestValue = -std::numeric_limits<double>::max();
186 for (EdgeVector::const_iterator i = edges.begin(); i != edges.end(); ++i) {
187 for (EdgeVector::const_iterator j = i + 1; j != edges.end(); ++j) {
189 if (value > bestValue) {
191 bestPair = std::pair<NBEdge*, NBEdge*>(*i, *j);
192 }
else if (value == bestValue) {
194 const double oa =
GeomHelper::getMinAngleDiff(bestPair.first->getAngleAtNode(bestPair.first->getToNode()), bestPair.second->getAngleAtNode(bestPair.second->getToNode()));
195 if (fabs(oa - ca) < NUMERICAL_EPS) {
196 if (bestPair.first->getID() < (*i)->getID()) {
197 bestPair = std::pair<NBEdge*, NBEdge*>(*i, *j);
199 }
else if (oa < ca) {
200 bestPair = std::pair<NBEdge*, NBEdge*>(*i, *j);
205 if (bestValue <= 0) {
207 if (bestPair.first->getPriority() < bestPair.second->getPriority()) {
208 std::swap(bestPair.first, bestPair.second);
210 bestPair.second =
nullptr;
212#ifdef DEBUG_STREAM_ORDERING
221std::pair<NBEdge*, NBEdge*>
223 if (incoming.size() == 1) {
225 std::pair<NBEdge*, NBEdge*> ret(*incoming.begin(),
static_cast<NBEdge*
>(
nullptr));
233 used.push_back(*incoming.begin());
236 for (EdgeVector::iterator i = incoming.begin() + 1; i != incoming.end() && prio ==
getToPrio(*i); ++i) {
240 if (used.size() < 2) {
244#ifdef DEBUG_STREAM_ORDERING
250 incoming.erase(find(incoming.begin(), incoming.end(), ret.first));
251 if (ret.second !=
nullptr) {
252 incoming.erase(find(incoming.begin(), incoming.end(), ret.second));
290 std::vector<std::pair<NBEdge*, NBEdge*> > chosenList;
291 std::vector<std::string> straightStates;
292 std::vector<std::string> leftStates;
297 std::vector<bool> isTurnaround;
298 std::vector<bool> hasTurnLane;
299 std::vector<int> fromLanes;
300 std::vector<int> toLanes;
301 std::vector<SUMOTime> crossingTime;
302 int totalNumLinks = 0;
303 for (
NBEdge*
const fromEdge : incoming) {
304 const int numLanes = fromEdge->getNumLanes();
306 for (
int i2 = 0; i2 < numLanes; i2++) {
307 bool hasLeft =
false;
308 bool hasPartLeft =
false;
309 bool hasStraight =
false;
310 bool hasRight =
false;
311 bool hasTurnaround =
false;
313 if (!fromEdge->mayBeTLSControlled(i2, approached.toEdge, approached.toLane)) {
316 fromEdges.push_back(fromEdge);
317 fromLanes.push_back(i2);
318 toLanes.push_back(approached.toLane);
319 toEdges.push_back(approached.toEdge);
320 if (approached.vmax < NUMERICAL_EPS || (fromEdge->getPermissions() &
SVC_PASSENGER) == 0
321 || (approached.toEdge->getPermissions() &
SVC_PASSENGER) == 0) {
322 crossingTime.push_back(0);
327 if (approached.toEdge !=
nullptr) {
328 isTurnaround.push_back(fromEdge->isTurningDirectionAt(approached.toEdge));
330 isTurnaround.push_back(
true);
332 LinkDirection dir = fromEdge->getToNode()->getDirection(fromEdge, approached.toEdge);
342 hasTurnaround =
true;
347 if (!fromEdge->mayBeTLSControlled(i2, approached.toEdge, approached.toLane)) {
350 hasTurnLane.push_back(
351 (hasLeft && !hasPartLeft && !hasStraight && !hasRight)
352 || (hasPartLeft && !hasLeft && !hasStraight && !hasRight)
353 || (hasPartLeft && hasLeft && edgeHasStraight && !hasRight)
354 || (!hasLeft && !hasPartLeft && !hasTurnaround && hasRight));
360 std::vector<NBNode::Crossing*> crossings;
362 const std::vector<NBNode::Crossing*>& c = node->getCrossings();
365 node->setCrossingTLIndices(
getID(), totalNumLinks);
367 copy(c.begin(), c.end(), std::back_inserter(crossings));
368 totalNumLinks += (int)c.size();
385 std::vector<int> greenPhases;
386 std::vector<bool> hadGreenMajor(totalNumLinks,
false);
387 while (toProc.size() > 0) {
388 bool groupTram =
false;
389 bool groupOther =
false;
390 std::pair<NBEdge*, NBEdge*> chosen;
391 std::set<const NBEdge*> chosenSet;
392 if (groupOpposites) {
393 if (incoming.size() == 2) {
396 double angle = fabs(
NBHelpers::relAngle(incoming[0]->getAngleAtNode(incoming[0]->getToNode()), incoming[1]->getAngleAtNode(incoming[1]->getToNode())));
399 chosen = std::pair<NBEdge*, NBEdge*>(toProc[0],
static_cast<NBEdge*
>(
nullptr));
400 toProc.erase(toProc.begin());
406 if (chosen.second ==
nullptr && chosen.first->getPermissions() ==
SVC_TRAM) {
408 for (
auto it = toProc.begin(); it != toProc.end();) {
409 if ((*it)->getPermissions() ==
SVC_TRAM) {
410 it = toProc.erase(it);
418 NBEdge* chosenEdge = toProc[0];
419 chosen = std::pair<NBEdge*, NBEdge*>(chosenEdge,
static_cast<NBEdge*
>(
nullptr));
420 toProc.erase(toProc.begin());
428 if (groupTram || groupOther) {
429 for (
auto it = toProc.begin(); it != toProc.end();) {
430 if ((*it)->getPermissions() == perms) {
431 it = toProc.erase(it);
439 std::string state(totalNumLinks,
'r');
445 chosenList.push_back(chosen);
446 chosenSet.insert(chosen.first);
447 if (chosen.second !=
nullptr) {
448 chosenSet.insert(chosen.second);
451 for (
const NBEdge* e : chosenSet) {
453 std::vector<NBEdge*> parallelBikeEdges;
454 for (
NBEdge* cand : toProc) {
456 double angle = fabs(
NBHelpers::relAngle(e->getAngleAtNode(e->getToNode()), cand->getAngleAtNode(cand->getToNode())));
459 parallelBikeEdges.push_back(cand);
463 for (
NBEdge* be : parallelBikeEdges) {
466 std::cout <<
" chosen=" << e->getID() <<
" be=" << be->getID() <<
"\n";
469 chosenSet.insert(be);
470 toProc.erase(std::find(toProc.begin(), toProc.end(), be));
476 bool haveGreen =
false;
477 for (
const NBEdge*
const fromEdge : incoming) {
478 const bool inChosen = chosenSet.count(fromEdge) != 0;
479 const int numLanes = fromEdge->getNumLanes();
480 for (
int i2 = 0; i2 < numLanes; i2++) {
482 if (!fromEdge->mayBeTLSControlled(i2, approached.toEdge, approached.toLane)) {
488 maxSpeed =
MAX2(maxSpeed, fromEdge->getSpeed());
502 std::cout <<
" state after plain straight movers " << state <<
"\n";
507 state =
allowCompatible(state, fromEdges, toEdges, fromLanes, toLanes);
510 std::cout <<
" state after allowing compatible " << state <<
"\n";
515 }
else if (groupOther) {
520 std::cout <<
" state after grouping by vClass " << state <<
"\n";
524 state =
allowUnrelated(state, fromEdges, toEdges, isTurnaround, crossings);
528 std::cout <<
" state after finding allowUnrelated " << state <<
"\n";
533 bool haveForbiddenLeftMover =
false;
534 std::vector<bool> rightTurnConflicts(pos,
false);
535 std::vector<bool> mergeConflicts(pos,
false);
536 state =
correctConflicting(state, fromEdges, toEdges, isTurnaround, fromLanes, toLanes, hadGreenMajor, haveForbiddenLeftMover, rightTurnConflicts, mergeConflicts);
537 for (
int i1 = 0; i1 < pos; ++i1) {
538 if (state[i1] ==
'G') {
539 hadGreenMajor[i1] =
true;
544 std::cout <<
" state after correcting left movers=" << state <<
"\n";
548 std::vector<bool> leftGreen(pos,
false);
550 bool foundLeftTurnLane =
false;
551 for (
int i1 = 0; i1 < pos; ++i1) {
552 if (state[i1] ==
'g' && !rightTurnConflicts[i1] && !mergeConflicts[i1] && hasTurnLane[i1]) {
553 foundLeftTurnLane =
true;
556 const bool buildLeftGreenPhase = (haveForbiddenLeftMover && !
myHaveSinglePhase && leftTurnTime > 0 && foundLeftTurnLane
557 && groupOpposites && !groupTram && !groupOther);
560 for (
int i1 = 0; i1 < pos; ++i1) {
561 if (state[i1] ==
'g' && !rightTurnConflicts[i1] && !mergeConflicts[i1]
563 && (!isTurnaround[i1] || (i1 > 0 && leftGreen[i1 - 1]))) {
564 leftGreen[i1] =
true;
565 if (fromEdges[i1]->getSpeed() > minorLeftSpeedThreshold) {
566 if (buildLeftGreenPhase) {
569 }
else if (!isTurnaround[i1]) {
570 WRITE_WARNINGF(
TL(
"Minor green from edge '%' to edge '%' exceeds %m/s. Maybe a left-turn lane is missing."),
571 fromEdges[i1]->
getID(), toEdges[i1]->
getID(), minorLeftSpeedThreshold);
579 std::cout <<
getID() <<
" state=" << state <<
" buildLeft=" << buildLeftGreenPhase <<
" hFLM=" << haveForbiddenLeftMover <<
" turnLane=" << foundLeftTurnLane
580 <<
" \nrtC=" <<
toString(rightTurnConflicts)
581 <<
" \nmC=" <<
toString(mergeConflicts)
582 <<
" \nhTL=" <<
toString(hasTurnLane)
587 straightStates.push_back(state);
589 const std::string vehicleState = state;
590 greenPhases.push_back((
int)logic->
getPhases().size());
593 const double minDurBySpeed = maxSpeed * 3.6 / 6 - 3.3;
595 if (chosen.first->getPermissions() ==
SVC_TRAM && (chosen.second ==
nullptr || chosen.second->getPermissions() ==
SVC_TRAM)) {
598 bool tramExclusive =
true;
599 for (
int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
600 if (state[i1] ==
'G') {
601 SVCPermissions linkPerm = (fromEdges[i1]->getPermissions() & toEdges[i1]->getPermissions());
603 tramExclusive =
false;
614 state =
addPedestrianPhases(logic, greenTime, minDur, maxDur, earliestEnd, latestEnd, state, crossings, fromEdges, toEdges);
616 for (
int i1 = pos; i1 < pos + (int)crossings.size(); ++i1) {
619 if (brakingTime > 0) {
622 for (
int i1 = 0; i1 < pos; ++i1) {
623 if (state[i1] !=
'G' && state[i1] !=
'g') {
626 if ((vehicleState[i1] >=
'a' && vehicleState[i1] <=
'z')
627 && buildLeftGreenPhase
628 && !rightTurnConflicts[i1]
629 && !mergeConflicts[i1]
634 maxCross =
MAX2(maxCross, crossingTime[i1]);
637 logic->
addStep(brakingTime, state);
639 if (!buildLeftGreenPhase) {
648 if (buildLeftGreenPhase) {
650 for (
int i1 = 0; i1 < pos; ++i1) {
651 if (state[i1] ==
'Y' || state[i1] ==
'y') {
659 leftStates.push_back(state);
660 state =
allowCompatible(state, fromEdges, toEdges, fromLanes, toLanes);
661 state =
correctConflicting(state, fromEdges, toEdges, isTurnaround, fromLanes, toLanes, hadGreenMajor, haveForbiddenLeftMover, rightTurnConflicts, mergeConflicts);
662 bool buildMixedGreenPhase =
false;
663 std::vector<bool> mixedGreen(pos,
false);
664 const std::string oldState = state;
666 state =
correctMixed(state, fromEdges, fromLanes, buildMixedGreenPhase, mixedGreen);
668 if (state != oldState) {
669 for (
int i1 = 0; i1 < pos; ++i1) {
670 if (mixedGreen[i1]) {
672 int yellowIndex = (int)logic->
getPhases().size() - 1;
673 if (allRedTime > 0) {
676 if (brakingTime > 0) {
681 state =
allowCompatible(state, fromEdges, toEdges, fromLanes, toLanes);
685 logic->
addStep(leftTurnTime, state, minDur, maxDur, earliestEnd, latestEnd);
688 if (brakingTime > 0) {
690 for (
int i1 = 0; i1 < pos; ++i1) {
691 if (state[i1] !=
'G' && state[i1] !=
'g') {
695 maxCross =
MAX2(maxCross, crossingTime[i1]);
698 logic->
addStep(brakingTime, state);
703 if (buildMixedGreenPhase) {
709 for (
int i1 = 0; i1 < pos; ++i1) {
710 if (state[i1] ==
'Y' || state[i1] ==
'y') {
714 if (mixedGreen[i1]) {
718 state =
allowCompatible(state, fromEdges, toEdges, fromLanes, toLanes);
719 state =
correctConflicting(state, fromEdges, toEdges, isTurnaround, fromLanes, toLanes, hadGreenMajor, haveForbiddenLeftMover, rightTurnConflicts, mergeConflicts);
722 logic->
addStep(leftTurnTime, state, minDur, maxDur, earliestEnd, latestEnd);
725 if (brakingTime > 0) {
727 for (
int i1 = 0; i1 < pos; ++i1) {
728 if (state[i1] !=
'G' && state[i1] !=
'g') {
732 maxCross =
MAX2(maxCross, crossingTime[i1]);
735 logic->
addStep(brakingTime, state);
742 std::string& s = straightStates.back();
743 std::string leftState = s;
744 for (
int ii = 0; ii < pos; ++ii) {
746 NBEdge* fromEdge = fromEdges[ii];
747 NBEdge* toEdge = toEdges[ii];
757 leftStates.push_back(leftState);
760 if (
myEdgesWithin.size() > 0 && !isNEMA && toProc.size() == 0) {
765 if (crossings.size() > 0) {
769 if (logic->
getPhases().size() == 2 && brakingTime > 0
772 logic->
addStep(redTime, std::string(totalNumLinks,
'r'));
775 if (crossings.size() > 0 && !onlyConts) {
785 if (nemaLogic ==
nullptr) {
786 WRITE_WARNINGF(
TL(
"Generating NEMA phases is not support for traffic light '%' with % incoming edges. Using tlType 'actuated' as fallback"),
getID(), incoming.size());
801 for (std::vector<int>::const_iterator it = greenPhases.begin(); it != greenPhases.end(); ++it) {
803 minGreenDuration =
MIN2(minGreenDuration, dur);
805 const int patchSeconds = (int)(
STEPS2TIME(cycleTime - totalDuration) / (double)greenPhases.size());
806 const int patchSecondsRest = (int)(
STEPS2TIME(cycleTime - totalDuration)) - patchSeconds * (
int)greenPhases.size();
810 || greenPhases.size() == 0) {
816 for (std::vector<int>::const_iterator it = greenPhases.begin(); it != greenPhases.end(); ++it) {
819 if (greenPhases.size() > 0) {
829 if (totalDuration > 0) {
830 if (totalDuration > 3 * (greenTime + 2 * brakingTime + leftTurnTime) && !isNEMA) {
845 for (
auto c : crossings) {
849 for (EdgeVector::const_iterator it_e = cross.
edges.begin(); it_e != cross.
edges.end(); ++it_e) {
850 const NBEdge* edge = *it_e;
851 if (edge == from || edge == to) {
864 std::string state,
const std::vector<NBNode::Crossing*>& crossings,
const EdgeVector& fromEdges,
const EdgeVector& toEdges) {
869 const std::string orig = state;
873 logic->
addStep(greenTime, state, minDur, maxDur, earliestEnd, latestEnd);
875 const SUMOTime pedTime = greenTime - pedClearingTime;
876 if (pedTime >= minPedTime) {
878 const int pedStates = (int)crossings.size();
879 logic->
addStep(pedTime, state, minDur, maxDur, earliestEnd, latestEnd);
880 state = state.substr(0, state.size() - pedStates) + std::string(pedStates,
'r');
881 logic->
addStep(pedClearingTime, state);
885 logic->
addStep(greenTime, state, minDur, maxDur, earliestEnd, latestEnd);
894 std::string result = state;
895 const int pos = (int)(state.size() - crossings.size());
896 for (
int ic = 0; ic < (int)crossings.size(); ++ic) {
897 const int i1 = pos + ic;
902 if (fromEdges[i2] != 0 && toEdges[i2] != 0 && fromEdges[i2]->getToNode() == cross.
node) {
903 for (EdgeVector::const_iterator it = cross.
edges.begin(); it != cross.
edges.end(); ++it) {
906 if (state[i2] !=
'r' && state[i2] !=
's' && (edge == fromEdges[i2] ||
922 for (
int i1 = 0; i1 < pos; ++i1) {
923 if (result[i1] ==
'G') {
924 for (
int ic = 0; ic < (int)crossings.size(); ++ic) {
926 if (fromEdges[i1] != 0 && toEdges[i1] != 0 && fromEdges[i1]->getToNode() == crossing.
node) {
927 const int i2 = pos + ic;
974 std::vector<bool> edgeInsideTLS;
976 edgeInsideTLS.push_back(e->isInsideTLS());
986 n->removeTrafficLight(&dummy);
991 e->setInsideTLS(edgeInsideTLS[i]);
995#ifdef DEBUG_CONTRELATION
997 std::cout <<
" contRelations at " <<
getID() <<
" prog=" <<
getProgramID() <<
":\n";
999 std::cout <<
" " << s.from1->
getID() <<
"->" << s.to1->getID() <<
" foe " << s.from2->getID() <<
"->" << s.to2->getID() <<
"\n";
1013 for (EdgeVector::iterator it = result.begin(); it != result.end();) {
1014 if ((*it)->getConnections().size() == 0 || (*it)->isInsideTLS()) {
1015 it = result.erase(it);
1026 const std::vector<int>& fromLanes,
const std::vector<int>& toLanes) {
1030 std::cout <<
" state after allowSingle " << state <<
"\n";
1037 std::cout <<
" state after allowFollowers " << state <<
"\n";
1043 std::cout <<
" state after allowPredecessors " << state <<
"\n";
1054 const int size = (int)fromEdges.size();
1055 NBEdge* greenEdge =
nullptr;
1056 for (
int i1 = 0; i1 < size; ++i1) {
1057 if (state[i1] ==
'G') {
1058 if (greenEdge ==
nullptr) {
1059 greenEdge = fromEdges[i1];
1060 }
else if (greenEdge != fromEdges[i1]) {
1065 if (greenEdge !=
nullptr) {
1066 for (
int i1 = 0; i1 < size; ++i1) {
1067 if (fromEdges[i1] == greenEdge) {
1082 for (
int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
1083 if (state[i1] ==
'G') {
1086 if (
forbidden(state, i1, fromEdges, toEdges,
true)) {
1089 bool followsChosen =
false;
1090 for (
int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
1091 if (state[i2] ==
'G' && fromEdges[i1] == toEdges[i2]) {
1092 followsChosen =
true;
1096 if (followsChosen) {
1108 const std::vector<int>& fromLanes,
const std::vector<int>& toLanes) {
1114 for (
int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
1115 if (state[i1] ==
'G') {
1118 if (
forbidden(state, i1, fromEdges, toEdges,
false)) {
1121 bool preceedsChosen =
false;
1122 for (
int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
1123 if (state[i2] ==
'G' && fromEdges[i2] == toEdges[i1]
1124 && fromLanes[i2] == toLanes[i1]) {
1125 preceedsChosen =
true;
1129 if (preceedsChosen) {
1141 const std::vector<bool>& isTurnaround,
1142 const std::vector<NBNode::Crossing*>& crossings) {
1143 for (
int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
1144 if (state[i1] ==
'G') {
1148 for (
int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
1149 if (state[i2] ==
'G' && !isTurnaround[i2] &&
1150 (
forbids(fromEdges[i2], toEdges[i2], fromEdges[i1], toEdges[i1],
true) ||
forbids(fromEdges[i1], toEdges[i1], fromEdges[i2], toEdges[i2],
true))) {
1165 for (
int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
1166 SVCPermissions linkPerm = (fromEdges[i1]->getPermissions() & toEdges[i1]->getPermissions());
1167 if ((linkPerm & ~perm) == 0) {
1177 for (
int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
1178 if (state[i2] ==
'G' &&
foes(fromEdges[i2], toEdges[i2], fromEdges[index], toEdges[index])) {
1180 !
needsCont(fromEdges[i2], toEdges[i2], fromEdges[index], toEdges[index]) &&
1181 !
needsCont(fromEdges[index], toEdges[index], fromEdges[i2], toEdges[i2]))) {
1192 const std::vector<bool>& isTurnaround,
1193 const std::vector<int>& fromLanes,
1194 const std::vector<int>& toLanes,
1195 const std::vector<bool>& hadGreenMajor,
1196 bool& haveForbiddenLeftMover,
1197 std::vector<bool>& rightTurnConflicts,
1198 std::vector<bool>& mergeConflicts) {
1200 for (
int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
1201 if (state[i1] ==
'G') {
1202 for (
int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
1203 if ((state[i2] ==
'G' || state[i2] ==
'g')) {
1205 fromEdges[i1], toEdges[i1], fromLanes[i1], fromEdges[i2], toEdges[i2], fromLanes[i2])) {
1206 rightTurnConflicts[i1] =
true;
1208 if (
forbids(fromEdges[i2], toEdges[i2], fromEdges[i1], toEdges[i1],
true, controlledWithin) || rightTurnConflicts[i1]) {
1213 if (!isTurnaround[i1] && !hadGreenMajor[i1] && !rightTurnConflicts[i1]) {
1214 haveForbiddenLeftMover =
true;
1216 }
else if (fromEdges[i1] == fromEdges[i2]
1217 && fromLanes[i1] != fromLanes[i2]
1218 && toEdges[i1] == toEdges[i2]
1219 && toLanes[i1] == toLanes[i2]
1220 && fromEdges[i1]->getToNode()->mergeConflictYields(fromEdges[i1], fromLanes[i1], fromLanes[i2], toEdges[i1], toLanes[i1])) {
1221 mergeConflicts[i1] =
true;
1227 if (state[i1] ==
'r') {
1229 fromEdges[i1]->getToNode()->getDirection(fromEdges[i1], toEdges[i1]) ==
LinkDirection::RIGHT) {
1232 for (
int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
1233 if (state[i2] ==
'G' && !isTurnaround[i2] &&
1234 (
forbids(fromEdges[i2], toEdges[i2], fromEdges[i1], toEdges[i1],
true) ||
1235 forbids(fromEdges[i1], toEdges[i1], fromEdges[i2], toEdges[i2],
true))) {
1236 const LinkDirection foeDir = fromEdges[i2]->getToNode()->getDirection(fromEdges[i2], toEdges[i2]);
1243 if (state[i1] ==
's') {
1245 for (
int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
1246 if (state[i2] ==
'G' && !isTurnaround[i2] &&
1247 (
forbids(fromEdges[i2], toEdges[i2], fromEdges[i1], toEdges[i1],
true) ||
1248 forbids(fromEdges[i1], toEdges[i1], fromEdges[i2], toEdges[i2],
true))) {
1262 const std::vector<int>& fromLanes,
1263 bool& buildMixedGreenPhase, std::vector<bool>& mixedGreen) {
1264 for (
int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
1265 if ((state[i1] ==
'G' || state[i1] ==
'g')) {
1266 for (
int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
1267 if (i1 != i2 && fromEdges[i1] == fromEdges[i2] && fromLanes[i1] == fromLanes[i2]
1268 && state[i2] !=
'G' && state[i2] !=
'g') {
1269 state[i1] = state[i2];
1271 mixedGreen[i1] =
true;
1272 if (fromEdges[i1]->getNumLanesThatAllow(
SVC_PASSENGER) > 1) {
1273 buildMixedGreenPhase =
true;
1285 std::vector<bool> foundGreen(fromEdges.size(),
false);
1286 for (
const auto& phase : logic->
getPhases()) {
1287 const std::string state = phase.state;
1288 for (
int j = 0; j < (int)fromEdges.size(); j++) {
1291 foundGreen[j] =
true;
1295 for (
int j = 0; j < (int)foundGreen.size(); j++) {
1296 if (!foundGreen[j]) {
1297 NBEdge* e = fromEdges[j];
1298 if (std::find(toProc.begin(), toProc.end(), e) == toProc.end()) {
1299 toProc.push_back(e);
1308 const std::vector<NBNode::Crossing*>& crossings,
const EdgeVector& fromEdges,
const EdgeVector& toEdges) {
1309 const int vehLinks = totalNumLinks - (int)crossings.size();
1310 std::vector<bool> foundGreen(crossings.size(),
false);
1311 const std::vector<NBTrafficLightLogic::PhaseDefinition>& phases = logic->
getPhases();
1312 for (
int i = 0; i < (int)phases.size(); i++) {
1313 const std::string state = phases[i].state;
1314 for (
int j = 0; j < (int)crossings.size(); j++) {
1317 foundGreen[j] =
true;
1321 for (
int j = 0; j < (int)foundGreen.size(); j++) {
1322 if (!foundGreen[j]) {
1324 if (phases.size() > 0) {
1325 bool needYellowPhase =
false;
1326 std::string state = phases.back().state;
1327 for (
int i1 = 0; i1 < vehLinks; ++i1) {
1328 if (state[i1] ==
'G' || state[i1] ==
'g') {
1330 needYellowPhase =
true;
1334 if (needYellowPhase && brakingTime > 0) {
1335 logic->
addStep(brakingTime, state);
1350 if (allRedTime > 0) {
1352 std::string allRedState = state;
1353 for (
int i = 0; i < (int)state.size(); i++) {
1354 if (allRedState[i] ==
'Y' || allRedState[i] ==
'y') {
1355 allRedState[i] =
'r';
1365 int minCustomIndex = -1;
1366 int maxCustomIndex = -1;
1369 const std::vector<NBNode::Crossing*>& c = (*i)->getCrossings();
1370 for (
auto crossing : c) {
1371 minCustomIndex =
MIN2(minCustomIndex, crossing->customTLIndex);
1372 minCustomIndex =
MIN2(minCustomIndex, crossing->customTLIndex2);
1373 maxCustomIndex =
MAX2(maxCustomIndex, crossing->customTLIndex);
1374 maxCustomIndex =
MAX2(maxCustomIndex, crossing->customTLIndex2);
1390 const int p = (int)logic->
getPhases().size();
1391 for (
int i1 = 0; i1 < n; ++i1) {
1393 for (
int i2 = 0; i2 < p; ++i2) {
1410 std::vector<bool> alwaysGreen(n,
true);
1411 for (
int i1 = 0; i1 < n; ++i1) {
1412 for (
const auto& phase : logic->
getPhases()) {
1413 if (phase.state[i1] !=
'G') {
1414 alwaysGreen[i1] =
false;
1419 const int p = (int)logic->
getPhases().size();
1420 for (
int i1 = 0; i1 < n; ++i1) {
1421 if (alwaysGreen[i1]) {
1422 for (
int i2 = 0; i2 < p; ++i2) {
1433 const int p = (int)logic->
getPhases().size();
1434 for (
int i1 = 0; i1 < n; ++i1) {
1435 if (fromEdges[i1]->isInsideTLS()) {
1436 for (
int i2 = 0; i2 < p; ++i2) {
1446 const int n = (int)state.size();
1448 for (
int i1 = 0; i1 < n; ++i1) {
1449 if (state[i1] ==
'y' && !fromEdges[i1]->isInsideTLS()) {
1450 for (
int i2 = 0; i2 < n; ++i2) {
1451 if (fromEdges[i2]->isInsideTLS()) {
1452 double gapSpeed = (toEdges[i1]->getSpeed() + fromEdges[i2]->getSpeed()) / 2;
1453 double time = fromEdges[i1]->getGeometry().back().distanceTo2D(fromEdges[i2]->getGeometry().back()) / gapSpeed;
1454 maxTime =
MAX2(maxTime, time);
1468 if (logic !=
nullptr) {
1486 int greenPhases = 0;
1487 for (
const auto& phase : tllDummy->
getPhases()) {
1488 if (phase.state.find_first_of(
"gG") != std::string::npos) {
1494 controlledNode->removeTrafficLight(&dummy);
1496 return greenPhases <= 2;
1503 const std::vector<std::pair<NBEdge*, NBEdge*> >& chosenList,
1504 const std::vector<std::string>& straightStates,
1505 const std::vector<std::string>& leftStates) {
1506 if (chosenList.size() != 2) {
1518 const int totalNumLinks = (int)straightStates[0].size();
1520 std::vector<int> ring1({1, 2, 3, 4});
1521 std::vector<int> ring2({5, 6, 7, 8});
1522 std::vector<int> barrier1({4, 8});
1523 std::vector<int> barrier2({2, 6});
1524 int phaseNameLeft = 1;
1525 for (
int i = 0; i < (int)chosenList.size(); i++) {
1526 NBEdge* e1 = chosenList[i].first;
1527 assert(e1 !=
nullptr);
1528 NBEdge* e2 = chosenList[i].second;
1529 if (i < (
int)leftStates.size()) {
1530 std::string left1 =
filterState(leftStates[i], fromEdges, e1);
1532 logic->
addStep(dur, left1, minMinDur, maxDur, earliestEnd, latestEnd, vehExt, yellow, red,
toString(phaseNameLeft));
1535 if (e2 !=
nullptr) {
1536 std::string straight2 =
filterState(straightStates[i], fromEdges, e2);
1537 logic->
addStep(dur, straight2, minMinDur, maxDur, earliestEnd, latestEnd, vehExt, yellow, red,
toString(phaseNameLeft + 1));
1538 if (i < (
int)leftStates.size()) {
1539 std::string left2 =
filterState(leftStates[i], fromEdges, e2);
1541 logic->
addStep(dur, left2, minMinDur, maxDur, earliestEnd, latestEnd, vehExt, yellow, red,
toString(phaseNameLeft + 4));
1546 std::string straight1 =
filterState(straightStates[i], fromEdges, e1);
1547 if (straight1 ==
"") {
1551 logic->
addStep(dur, straight1, minMinDur, maxDur, earliestEnd, latestEnd, vehExt, yellow, red,
toString(phaseNameLeft + 5));
1554 std::map<int, int> names;
1555 for (
int i = 0; i < (int)logic->
getPhases().size(); i++) {
1563 if (ring1[2] == 0 && ring1[3] == 0) {
1566 fixDurationSum(logic, names, ring1[0], ring1[1], ring2[0], ring2[1]);
1567 fixDurationSum(logic, names, ring1[2], ring1[3], ring2[2], ring2[3]);
1579 bool haveGreen =
false;
1580 for (
int j = 0; j < (int)state.size(); j++) {
1581 if (fromEdges[j] != e) {
1583 }
else if (state[j] !=
'r') {
1596 for (
int i = 0; i < (int)vec.size(); i++) {
1597 if (names.count(vec[i]) == 0) {
1599 if (names.count(vec[i] - 1) > 0) {
1600 vec[i] = vec[i] - 1;
1613 std::set<int> ring1existing;
1614 std::set<int> ring2existing;
1615 if (names.count(ring1a) != 0) {
1616 ring1existing.insert(ring1a);
1618 if (names.count(ring1b) != 0) {
1619 ring1existing.insert(ring1b);
1621 if (names.count(ring2a) != 0) {
1622 ring2existing.insert(ring2a);
1624 if (names.count(ring2b) != 0) {
1625 ring2existing.insert(ring2b);
1627 if (ring1existing.size() > 0 && ring2existing.size() > 0 &&
1628 ring1existing.size() != ring2existing.size()) {
1630 if (ring1existing.size() < ring2existing.size()) {
1631 pI = names.find(*ring1existing.begin())->second;
1633 pI = names.find(*ring2existing.begin())->second;
1636 SUMOTime newMaxDur = 2 * p.maxDur + p.yellow + p.red;
#define WRITE_WARNINGF(...)
std::vector< NBEdge * > EdgeVector
container for (sorted) edges
std::string time2string(SUMOTime t, bool humanReadable)
convert SUMOTime to string (independently of global format setting)
bool isRailway(SVCPermissions permissions)
Returns whether an edge with the given permission is a railway edge.
bool isForbidden(SVCPermissions permissions)
Returns whether an edge with the given permission is a forbidden edge.
@ SVC_PASSENGER
vehicle is a passenger car (a "normal" car)
@ SVC_BICYCLE
vehicle is a bicycle
@ SVC_DELIVERY
vehicle is a small delivery vehicle
@ SVC_TRAM
vehicle is a light rail
@ SVC_PEDESTRIAN
pedestrian
int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
LinkDirection
The different directions a link between two lanes may take (or a stream between two edges)....
@ PARTLEFT
The link is a partial left direction.
@ RIGHT
The link is a (hard) right direction.
@ TURN
The link is a 180 degree turn.
@ LEFT
The link is a (hard) left direction.
@ STRAIGHT
The link is a straight direction.
@ PARTRIGHT
The link is a partial right direction.
LinkState
The right-of-way state of a link between two lanes used when constructing a NBTrafficLightLogic,...
@ LINKSTATE_TL_GREEN_MAJOR
The link has green light, may pass.
@ LINKSTATE_TL_YELLOW_MINOR
The link has yellow light, has to brake anyway.
@ LINKSTATE_TL_RED
The link has red light (must brake)
@ LINKSTATE_TL_GREEN_MINOR
The link has green light, has to brake.
@ LINKSTATE_TL_OFF_NOSIGNAL
The link is controlled by a tls which is off, not blinking, may pass.
@ TRAFFIC_LIGHT_RIGHT_ON_RED
std::string joinToString(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
static double getMinAngleDiff(double angle1, double angle2)
Returns the minimum distance (clockwise/counter-clockwise) between both angles.
NBEdge * getFrom() const
returns the from-edge (start of the connection)
The representation of a single edge during network building.
SVCPermissions getPermissions(int lane=-1) const
get the union of allowed classes over all lanes or for a specific lane
const std::vector< Connection > & getConnections() const
Returns the connections.
NBNode * getToNode() const
Returns the destination node of the edge.
const std::string & getID() const
bool setControllingTLInformation(const NBConnection &c, const std::string &tlID)
Returns if the link could be set as to be controlled.
int getNumLanes() const
Returns the number of lanes.
std::vector< Connection > getConnectionsFromLane(int lane, const NBEdge *to=nullptr, int toLane=-1) const
Returns connections from a given lane.
int getJunctionPriority(const NBNode *const node) const
Returns the junction priority (normalised for the node currently build)
NBNode * getFromNode() const
Returns the origin node of the edge.
NBEdge * getTurnDestination(bool possibleDestination=false) const
static double relAngle(double angle1, double angle2)
computes the relative angle between the two angles
A definition of a pedestrian crossing.
const NBNode * node
The parent node of this crossing.
EdgeVector edges
The edges being crossed.
Represents a single node (junction) during network building.
LinkDirection getDirection(const NBEdge *const incoming, const NBEdge *const outgoing, bool leftHand=false) const
Returns the representation of the described stream's direction.
static bool rightTurnConflict(const NBEdge *from, const NBEdge *to, int fromLane, const NBEdge *prohibitorFrom, const NBEdge *prohibitorTo, int prohibitorFromLane)
return whether the given laneToLane connection is a right turn which must yield to a bicycle crossing...
bool mustBrakeForCrossing(const NBEdge *const from, const NBEdge *const to, const Crossing &crossing) const
Returns the information whether the described flow must brake for the given crossing.
Sorts edges by their priority within the node they end at.
A traffic light logics which must be computed (only nodes/edges are given)
void fixSuperfluousYellow(NBTrafficLightLogic *logic) const
avoid yellow signal between successive green (major) phases
std::string correctConflicting(std::string state, const EdgeVector &fromEdges, const EdgeVector &toEdges, const std::vector< bool > &isTurnaround, const std::vector< int > &fromLanes, const std::vector< int > &toLanes, const std::vector< bool > &hadGreenMajor, bool &haveForbiddenLeftMover, std::vector< bool > &rightTurnConflicts, std::vector< bool > &mergeConflicts)
change 'G' to 'g' for conflicting connections
void checkCustomCrossingIndices(NBTrafficLightLogic *logic) const
fix states in regard to custom crossing indices
static std::string patchStateForCrossings(const std::string &state, const std::vector< NBNode::Crossing * > &crossings, const EdgeVector &fromEdges, const EdgeVector &toEdges)
compute phase state in regard to pedestrian crossings
std::string allowByVClass(std::string state, const EdgeVector &fromEdges, const EdgeVector &toEdges, SVCPermissions perm)
int getMaxIndex()
Returns the maximum index controlled by this traffic light.
bool myHaveSinglePhase
Whether left-mover should not have an additional phase.
bool corridorLike() const
test whether a joined tls with layout 'opposites' would be built without dedicated left-turn phase
SUMOTime computeEscapeTime(const std::string &state, const EdgeVector &fromEdges, const EdgeVector &toEdges) const
compute time to clear all vehicles from within an alternateOneWay layout
void replaceRemoved(NBEdge *removed, int removedLane, NBEdge *by, int byLane, bool incoming)
Replaces a removed edge/lane.
std::pair< NBEdge *, NBEdge * > getBestPair(EdgeVector &incoming)
Returns the combination of two edges from the given which has most unblocked streams.
void collectLinks()
Collects the links participating in this traffic light.
void deactivateAlwaysGreen(NBTrafficLightLogic *logic) const
switch of signal for links that are always green
static void addGreenWithin(NBTrafficLightLogic *logic, const EdgeVector &fromEdges, EdgeVector &toProc)
ensure inner edges all get the green light eventually
NBTrafficLightLogic * computeLogicAndConts(int brakingTimeSeconds, bool onlyConts=false)
helper function for myCompute
static bool hasCrossing(const NBEdge *from, const NBEdge *to, const std::vector< NBNode::Crossing * > &crossings)
compute whether the given connection is crossed by pedestrians
std::string allowPredecessors(std::string state, const EdgeVector &fromEdges, const EdgeVector &toEdges, const std::vector< int > &fromLanes, const std::vector< int > &toLanes)
void deactivateInsideEdges(NBTrafficLightLogic *logic, const EdgeVector &fromEdges) const
switch of signal for links that are inside a joined tls
double computeUnblockedWeightedStreamNumber(const NBEdge *const e1, const NBEdge *const e2)
Returns how many streams outgoing from the edges can pass the junction without being blocked.
void remapRemoved(NBEdge *removed, const EdgeVector &incoming, const EdgeVector &outgoing)
Replaces occurrences of the removed edge in incoming/outgoing edges of all definitions.
int getToPrio(const NBEdge *const e)
Returns this edge's priority at the node it ends at.
NBTrafficLightLogic * buildNemaPhases(const EdgeVector &fromEdges, const std::vector< std::pair< NBEdge *, NBEdge * > > &chosenList, const std::vector< std::string > &straightStates, const std::vector< std::string > &leftStates)
std::string allowCompatible(std::string state, const EdgeVector &fromEdges, const EdgeVector &toEdges, const std::vector< int > &fromLanes, const std::vector< int > &toLanes)
allow connections that are compatible with the chosen edges
std::string correctMixed(std::string state, const EdgeVector &fromEdges, const std::vector< int > &fromLanes, bool &buildMixedGreenPhase, std::vector< bool > &mixedGreen)
prevent green and red from the same lane
void fixDurationSum(NBTrafficLightLogic *logic, const std::map< int, int > &names, int ring1a, int ring1b, int ring2a, int ring2b)
ensure that phase max durations before each barrier have the same sum in both rings
NBTrafficLightLogic * myCompute(int brakingTimeSeconds)
Computes the traffic light logic finally in dependence to the type.
std::string filterState(std::string state, const EdgeVector &fromEdges, const NBEdge *e)
mask out all greens that do not originate at the given edge
std::string allowFollowers(std::string state, const EdgeVector &fromEdges, const EdgeVector &toEdges)
void buildAllRedState(SUMOTime allRedTime, NBTrafficLightLogic *logic, const std::string &state)
double getDirectionalWeight(LinkDirection dir)
Returns the weight of a stream given its direction.
std::string allowSingleEdge(std::string state, const EdgeVector &fromEdges)
bool hasStraightConnection(const NBEdge *fromEdge)
check whether there is a straight connection from this edge
std::pair< NBEdge *, NBEdge * > getBestCombination(const EdgeVector &edges)
Returns the combination of two edges from the given which has most unblocked streams.
void initNeedsContRelation() const
static void addPedestrianScramble(NBTrafficLightLogic *logic, int totalNumLinks, SUMOTime greenTime, SUMOTime yellowTime, const std::vector< NBNode::Crossing * > &crossings, const EdgeVector &fromEdges, const EdgeVector &toEdges)
add an additional pedestrian phase if there are crossings that did not get green yet
NBOwnTLDef(const std::string &id, const std::vector< NBNode * > &junctions, SUMOTime offset, TrafficLightType type)
Constructor.
static EdgeVector getConnectedOuterEdges(const EdgeVector &incoming)
get edges that have connections
void filterMissingNames(std::vector< int > &vec, const std::map< int, int > &names, bool isBarrier)
keep only valid NEMA phase names (for params)
TrafficLightLayout myLayout
the layout for generated signal plans
bool forbidden(const std::string &state, int index, const EdgeVector &fromEdges, const EdgeVector &toEdges, bool allowCont)
whether the given index is forbidden by a green link in the current state
static std::string addPedestrianPhases(NBTrafficLightLogic *logic, const SUMOTime greenTime, const SUMOTime minDur, const SUMOTime maxDur, const SUMOTime earliestEnd, const SUMOTime latestEnd, std::string state, const std::vector< NBNode::Crossing * > &crossings, const EdgeVector &fromEdges, const EdgeVector &toEdges)
add 1 or 2 phases depending on the presence of pedestrian crossings
std::string allowUnrelated(std::string state, const EdgeVector &fromEdges, const EdgeVector &toEdges, const std::vector< bool > &isTurnaround, const std::vector< NBNode::Crossing * > &crossings)
void setTLControllingInformation() const
Informs edges about being controlled by a tls.
static const double MIN_SPEED_CROSSING_TIME
minimum speed for computing time to cross intersection
The base class for traffic light logic definitions.
const std::string & getProgramID() const
Returns the ProgramID.
const EdgeVector & getIncomingEdges() const
Returns the list of incoming edges (must be build first)
bool needsCont(const NBEdge *fromE, const NBEdge *toE, const NBEdge *otherFromE, const NBEdge *otherToE) const
std::vector< NBNode * > myControlledNodes
The container with participating nodes.
EdgeVector myIncomingEdges
The list of incoming edges.
NBTrafficLightLogic * compute(const OptionsCont &oc)
Computes the traffic light logic.
RightOnRedConflicts myRightOnRedConflicts
TrafficLightType myType
The algorithm type for the traffic light.
EdgeVector myEdgesWithin
The list of edges within the area controlled by the tls.
static const std::string DummyID
id for temporary definitions
bool forbids(const NBEdge *const possProhibitorFrom, const NBEdge *const possProhibitorTo, const NBEdge *const possProhibitedFrom, const NBEdge *const possProhibitedTo, bool regardNonSignalisedLowerPriority, bool sameNodeOnly=false) const
Returns the information whether "prohibited" flow must let "prohibitor" flow pass.
NBConnectionVector myControlledLinks
The list of controlled links.
virtual void setType(TrafficLightType type)
set the algorithm type (static etc..)
bool myNeedsContRelationReady
virtual void setParticipantsInformation()
Builds the list of participating nodes/edges/links.
void collectAllLinks(NBConnectionVector &into)
helper method for use in NBOwnTLDef and NBLoadedSUMOTLDef
SUMOTime myOffset
The offset in the program.
static const SUMOTime UNSPECIFIED_DURATION
bool foes(const NBEdge *const from1, const NBEdge *const to1, const NBEdge *const from2, const NBEdge *const to2) const
Returns the information whether the given flows cross.
bool myRightOnRedConflictsReady
NeedsContRelation myNeedsContRelation
A SUMO-compliant built logic for a traffic light.
SUMOTime getDuration() const
Returns the duration of the complete cycle.
void closeBuilding(bool checkVarDurations=true)
closes the building process
void setPhaseDuration(int phaseIndex, SUMOTime duration)
Modifies the duration for an existing phase (used by netedit)
void setPhaseState(int phaseIndex, int tlIndex, LinkState linkState)
Modifies the state for an existing phase (used by netedit)
void setPhaseMaxDuration(int phaseIndex, SUMOTime duration)
Modifies the max duration for an existing phase (used by netedit)
int getNumLinks()
Returns the number of participating links.
void setType(TrafficLightType type)
set the algorithm type (static etc..)
void setStateLength(int numLinks, LinkState fill=LINKSTATE_TL_RED)
const std::vector< PhaseDefinition > & getPhases() const
Returns the phases.
void addStep(const SUMOTime duration, const std::string &state, const std::vector< int > &next=std::vector< int >(), const std::string &name="", const int index=-1)
Adds a phase to the logic (static)
static std::string getIDSecure(const T *obj, const std::string &fallBack="NULL")
get an identifier for Named-like object which may be Null
const std::string & getID() const
Returns the id.
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
int getInt(const std::string &name) const
Returns the int-value of the named option (only for Option_Integer)
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
static OptionsCont & getOptions()
Retrieves the options.
virtual void setParameter(const std::string &key, const std::string &value)
Sets a parameter.
static StringBijection< TrafficLightLayout > TrafficLightLayouts
traffic light layouts
T get(const std::string &str) const
static int toInt(const std::string &sData)
converts a string into the integer value described by it by calling the char-type converter,...
NLOHMANN_BASIC_JSON_TPL_DECLARATION void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL &j1, nlohmann::NLOHMANN_BASIC_JSON_TPL &j2) noexcept(//NOLINT(readability-inconsistent-declaration-parameter-name) is_nothrow_move_constructible< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value &&//NOLINT(misc-redundant-expression) is_nothrow_move_assignable< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value)
exchanges the values of two JSON objects
A structure which describes a connection between edges or lanes.
data structure for caching needsCont information