#include <config.h>
#include <sstream>
#include <iostream>
#include <cassert>
#include <algorithm>
#include <utils/common/MsgHandler.h>
#include <utils/common/ToString.h>
#include <utils/options/OptionsCont.h>
#include "NBEdge.h"
#include "NBOwnTLDef.h"
#include "NBTrafficLightLogicCont.h"
#include "NBNodeCont.h"
#include "NBTypeCont.h"
#include "NBNode.h"
#include "NBAlgorithms.h"
#define DEBUGCOND (n.getID() == "C")
#define DEBUGCOND2(obj) (true)
void
NBTurningDirectionsComputer::computeTurnDirections(NBNodeCont& nc, bool warn) {
for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
computeTurnDirectionsForNode(i->second, warn);
}
}
void
NBTurningDirectionsComputer::computeTurnDirectionsForNode(NBNode* node, bool warn) {
const std::vector<NBEdge*>& incoming = node->getIncomingEdges();
const std::vector<NBEdge*>& outgoing = node->getOutgoingEdges();
for (std::vector<NBEdge*>::const_iterator k = incoming.begin(); k != incoming.end(); ++k) {
(*k)->setTurningDestination(nullptr);
}
std::vector<Combination> combinations;
const bool geometryLike = node->geometryLike();
for (NBEdge* outedge : outgoing) {
for (NBEdge* e : incoming) {
const double signedAngle = NBHelpers::normRelAngle(e->getAngleAtNode(node), outedge->getAngleAtNode(node));
if (signedAngle > 0 && signedAngle < 177 && e->getGeometry().back().distanceTo2D(outedge->getGeometry().front()) < POSITION_EPS) {
#ifdef DEBUG_TURNAROUNDS
if (DEBUGCOND2(node)) {
std::cout << "incoming=" << e->getID() << " outgoing=" << outedge->getID() << " signedAngle=" << signedAngle << " skipped\n";
}
#endif
continue;
}
double angle = fabs(signedAngle);
#ifdef DEBUG_TURNAROUNDS
if (DEBUGCOND2(node)) {
std::cout << "incoming=" << e->getID() << " outgoing=" << outedge->getID() << " relAngle=" << NBHelpers::relAngle(e->getAngleAtNode(node), outedge->getAngleAtNode(node)) << "\n";
}
#endif
const bool badPermissions = ((outedge->getPermissions() & e->getPermissions() & ~SVC_PEDESTRIAN) == 0
&& !geometryLike
&& outedge->getPermissions() != e->getPermissions());
if (e->getFromNode() == outedge->getToNode()
&& (angle > 120 || e->getFromNode()->getPosition() == e->getToNode()->getPosition())
&& !badPermissions) {
angle += 360;
}
if (angle < 160) {
if (angle > 135) {
const double inFA = getFarAngleAtNode(e, node);
const double outFA = getFarAngleAtNode(outedge, node);
const double signedFarAngle = NBHelpers::normRelAngle(inFA, outFA);
#ifdef DEBUG_TURNAROUNDS
if (DEBUGCOND2(node)) {
std::cout << " inFA=" << inFA << " outFA=" << outFA << " sFA=" << signedFarAngle << "\n";
}
#endif
if (signedFarAngle > -160) {
continue;
}
} else {
continue;
}
}
if (badPermissions) {
angle -= 90;
}
Combination c;
c.from = e;
c.to = outedge;
c.angle = angle;
combinations.push_back(c);
}
}
std::sort(combinations.begin(), combinations.end(), combination_by_angle_sorter());
std::set<NBEdge*> seen;
#ifdef DEBUG_TURNAROUNDS
if (DEBUGCOND2(node)) {
std::cout << "check combinations at " << node->getID() << "\n";
}
#endif
for (std::vector<Combination>::const_iterator j = combinations.begin(); j != combinations.end(); ++j) {
#ifdef DEBUG_TURNAROUNDS
if (DEBUGCOND2(node)) {
std::cout << " from=" << (*j).from->getID() << " to=" << (*j).to->getID() << " a=" << (*j).angle << "\n";
}
#endif
if (seen.find((*j).from) != seen.end() || seen.find((*j).to) != seen.end()) {
if ((*j).angle > 360 && warn) {
WRITE_WARNINGF(TL("Ambiguity in turnarounds computation at junction '%'."), node->getID());
warn = false;
}
continue;
}
seen.insert((*j).from);
seen.insert((*j).to);
bool onlyPossible = (*j).from->getConnections().size() != 0 && !(*j).from->isConnectedTo((*j).to);
#ifdef DEBUG_TURNAROUNDS
if (DEBUGCOND2(node)) {
std::cout << " setTurningDestination from=" << (*j).from->getID() << " to=" << (*j).to->getID() << " onlyPossible=" << onlyPossible << "\n";
}
#endif
(*j).from->setTurningDestination((*j).to, onlyPossible);
}
}
double
NBTurningDirectionsComputer::getFarAngleAtNode(const NBEdge* e, const NBNode* n, double dist) {
Position atNode;
Position far;
double angle;
const NBEdge* next = e;
if (e->getToNode() == n) {
atNode = e->getGeometry().back();
while (dist > 0) {
const double length = next->getGeometry().length();
if (dist <= length) {
far = next->getGeometry().positionAtOffset(length - dist);
break;
} else {
far = next->getGeometry().front();
dist -= length;
if (next->getToNode()->getIncomingEdges().size() == 1) {
next = next->getToNode()->getIncomingEdges().front();
} else {
break;
}
}
}
angle = far.angleTo2D(atNode);
} else {
atNode = e->getGeometry().front();
while (dist > 0) {
const double length = next->getGeometry().length();
if (dist <= length) {
far = next->getGeometry().positionAtOffset(dist);
break;
} else {
far = next->getGeometry().back();
dist -= length;
if (next->getToNode()->getOutgoingEdges().size() == 1) {
next = next->getToNode()->getOutgoingEdges().front();
} else {
break;
}
}
}
angle = atNode.angleTo2D(far);
}
return GeomHelper::legacyDegree(angle);
}
void
NBNodesEdgesSorter::sortNodesEdges(NBNodeCont& nc, bool useNodeShape) {
for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
i->second->sortEdges(useNodeShape);
}
}
void
NBNodesEdgesSorter::swapWhenReversed(const NBNode* const n,
const std::vector<NBEdge*>::iterator& i1,
const std::vector<NBEdge*>::iterator& i2) {
NBEdge* e1 = *i1;
NBEdge* e2 = *i2;
if (e2->getToNode() == n && e2->isTurningDirectionAt(e1)) {
std::swap(*i1, *i2);
}
}
void
NBNodeTypeComputer::computeNodeTypes(NBNodeCont& nc, NBTrafficLightLogicCont& tlc) {
validateRailCrossings(nc, tlc);
const OptionsCont& oc = OptionsCont::getOptions();
const double rightBeforeLeftSpeed = oc.getFloat("junctions.right-before-left.speed-threshold");
for (const auto& nodeIt : nc) {
NBNode* const n = nodeIt.second;
if (n->myType != SumoXMLNodeType::UNKNOWN && n->myType != SumoXMLNodeType::DEAD_END) {
n->myTypeWasGuessed = false;
continue;
}
if (oc.getBool("keep-nodes-unregulated") || oc.isInStringVector("keep-nodes-unregulated.explicit", n->getID())
|| (oc.getBool("keep-nodes-unregulated.district-nodes") && (n->isNearDistrict() || n->isDistrict()))) {
n->myType = SumoXMLNodeType::NOJUNCTION;
continue;
}
bool waterway = true;
for (NBEdge* e : n->getEdges()) {
if (!isWaterway(e->getPermissions())) {
waterway = false;
break;
}
}
if (waterway && (n->myType == SumoXMLNodeType::UNKNOWN || n->myType == SumoXMLNodeType::DEAD_END)) {
n->myType = SumoXMLNodeType::NOJUNCTION;
continue;
}
if (n->myIncomingEdges.size() == 1) {
n->myType = SumoXMLNodeType::PRIORITY;
continue;
}
if (n->isSimpleContinuation()) {
n->myType = SumoXMLNodeType::PRIORITY;
continue;
}
if (isRailwayNode(n)) {
if (n->unsignalizedOperation()
&& (int)n->getIncomingEdges().size() == 2
&& (int)n->getOutgoingEdges().size() == 1) {
n->myType = SumoXMLNodeType::ZIPPER;
} else {
n->myType = SumoXMLNodeType::PRIORITY;
}
continue;
}
SumoXMLNodeType type = oc.getBool("junctions.left-before-right") ? SumoXMLNodeType::LEFT_BEFORE_RIGHT : SumoXMLNodeType::RIGHT_BEFORE_LEFT;
for (EdgeVector::const_iterator i = n->myIncomingEdges.begin(); i != n->myIncomingEdges.end(); i++) {
for (EdgeVector::const_iterator j = i + 1; j != n->myIncomingEdges.end(); j++) {
if (n->getOppositeIncoming(*j) == *i && n->myIncomingEdges.size() > 2) {
continue;
}
const double s1 = (*i)->getSpeed();
const double s2 = (*j)->getSpeed();
const int p1 = (*i)->getPriority();
const int p2 = (*j)->getPriority();
if (fabs(s1 - s2) > (9.5 / 3.6) || MAX2(s1, s2) >= rightBeforeLeftSpeed || p1 != p2) {
type = SumoXMLNodeType::PRIORITY;
break;
}
}
}
n->myType = type;
n->myTypeWasGuessed = true;
}
}
void
NBNodeTypeComputer::validateRailCrossings(NBNodeCont& nc, NBTrafficLightLogicCont& tlc) {
for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
NBNode* n = (*i).second;
if (n->myType == SumoXMLNodeType::RAIL_CROSSING) {
int numRailway = 0;
int numNonRailIn = 0;
int numNonRailOut = 0;
std::set<const NBNode*> nonRailNodes;
int numNonRailwayNonPed = 0;
for (NBEdge* e : n->getIncomingEdges()) {
if ((e->getPermissions() & ~SVC_RAIL_CLASSES) != 0) {
numNonRailIn += 1;
if (e->getPermissions() != SVC_PEDESTRIAN) {
numNonRailwayNonPed++;
}
nonRailNodes.insert(e->getFromNode());
} else if ((e->getPermissions() & SVC_RAIL_CLASSES) != 0) {
numRailway++;
}
}
for (NBEdge* e : n->getOutgoingEdges()) {
if ((e->getPermissions() & ~SVC_RAIL_CLASSES) != 0) {
numNonRailOut += 1;
nonRailNodes.insert(e->getToNode());
}
}
if (numNonRailIn == 0 || numNonRailOut == 0 || numRailway == 0) {
WRITE_WARNINGF(TL("Converting invalid rail_crossing to priority junction '%'."), n->getID());
n->myType = SumoXMLNodeType::PRIORITY;
} else if (numNonRailwayNonPed > 2 || nonRailNodes.size() > 2) {
WRITE_WARNINGF(TL("Converting invalid rail_crossing to traffic_light at junction '%'."), n->getID());
TrafficLightType type = SUMOXMLDefinitions::TrafficLightTypes.get(OptionsCont::getOptions().getString("tls.default-type"));
NBTrafficLightDefinition* tlDef = new NBOwnTLDef(n->getID(), n, 0, type);
n->myType = SumoXMLNodeType::TRAFFIC_LIGHT;
if (!tlc.insert(tlDef)) {
n->removeTrafficLight(tlDef);
n->myType = SumoXMLNodeType::PRIORITY;
delete tlDef;
WRITE_WARNINGF(TL("Could not allocate tls '%'."), n->getID());
}
}
}
}
}
bool
NBNodeTypeComputer::isRailwayNode(const NBNode* n) {
bool hasRailway = false;
for (NBEdge* e : n->getIncomingEdges()) {
if ((e->getPermissions() & ~(SVC_RAIL_CLASSES | SVC_TAXI)) != 0) {
return false;
} else if ((e->getPermissions() & SVC_RAIL_CLASSES) != 0) {
hasRailway = true;
}
}
return hasRailway;
}
void
NBEdgePriorityComputer::computeEdgePriorities(NBNodeCont& nc) {
for (const auto& node : nc) {
for (NBEdge* const edge : node.second->myAllEdges) {
edge->setJunctionPriority(node.second, NBEdge::JunctionPriority::MINOR_ROAD);
}
node.second->markBentPriority(false);
if (node.second->myIncomingEdges.size() == 1 && node.second->myOutgoingEdges.size() == 1) {
continue;
}
if (node.second->getType() != SumoXMLNodeType::RIGHT_BEFORE_LEFT
&& node.second->getType() != SumoXMLNodeType::LEFT_BEFORE_RIGHT
&& node.second->getType() != SumoXMLNodeType::ALLWAY_STOP
&& node.second->getType() != SumoXMLNodeType::NOJUNCTION) {
if (node.second->getRightOfWay() == RightOfWay::EDGEPRIORITY) {
for (NBEdge* e : node.second->getIncomingEdges()) {
e->setJunctionPriority(node.second, e->getPriority());
}
} else {
setPriorityJunctionPriorities(*node.second);
}
}
}
}
void
NBEdgePriorityComputer::setPriorityJunctionPriorities(NBNode& n, bool forceStraight) {
if (n.myIncomingEdges.size() == 0 || n.myOutgoingEdges.size() == 0) {
return;
}
int minPrio = std::numeric_limits<int>::max();
int maxPrio = -std::numeric_limits<int>::max();
int maxNumLanes = -std::numeric_limits<int>::max();
double maxSpeed = -std::numeric_limits<double>::max();
SVCPermissions all = 0;
for (NBEdge* const edge : n.myAllEdges) {
all |= edge->getPermissions();
}
if ((all & (SVC_PASSENGER & SVC_TRAM & SVC_BUS)) != 0) {
all = (SVC_PASSENGER & SVC_TRAM & SVC_BUS);
} else if ((all & ~SVC_VULNERABLE) != 0) {
all &= ~SVC_VULNERABLE;
}
if (forceStraight) {
for (NBEdge* const edge : n.myAllEdges) {
edge->setJunctionPriority(&n, NBEdge::JunctionPriority::MINOR_ROAD);
minPrio = MIN2(minPrio, edge->getPriority());
maxPrio = MAX2(maxPrio, edge->getPriority());
maxNumLanes = MAX2(maxNumLanes, edge->getNumLanesThatAllow(all, false));
maxSpeed = MAX2(maxSpeed, edge->getSpeed());
}
}
EdgeVector incoming = n.myIncomingEdges;
EdgeVector outgoing = n.myOutgoingEdges;
std::sort(incoming.begin(), incoming.end(), NBContHelper::edge_by_priority_sorter(all));
EdgeVector bestIncoming;
NBEdge* bestIn = incoming[0];
while (incoming.size() > 0 && (forceStraight || samePriority(bestIn, incoming[0], all))) {
bestIncoming.push_back(*incoming.begin());
incoming.erase(incoming.begin());
}
assert(outgoing.size() != 0);
sort(outgoing.begin(), outgoing.end(), NBContHelper::edge_by_priority_sorter(all));
EdgeVector bestOutgoing;
const NBEdge* const firstOut = outgoing[0];
while (outgoing.size() > 0 && (forceStraight || samePriority(firstOut, outgoing[0], all))) {
bestOutgoing.push_back(*outgoing.begin());
outgoing.erase(outgoing.begin());
}
const bool mainDirectionExplicit = (
bestIncoming.size() == 1 && n.myIncomingEdges.size() <= 2
&& (incoming.size() == 0 || bestIncoming[0]->getPriority() > incoming[0]->getPriority())
&& bestOutgoing.size() == 1 && n.myOutgoingEdges.size() <= 2
&& (outgoing.size() == 0 || bestOutgoing[0]->getPriority() > outgoing[0]->getPriority())
&& !bestIncoming[0]->isTurningDirectionAt(bestOutgoing[0]));
EdgeVector::iterator i;
std::map<NBEdge*, NBEdge*> counterIncomingEdges;
std::map<NBEdge*, NBEdge*> counterOutgoingEdges;
incoming = n.myIncomingEdges;
outgoing = n.myOutgoingEdges;
for (i = bestIncoming.begin(); i != bestIncoming.end(); ++i) {
std::sort(incoming.begin(), incoming.end(), NBContHelper::edge_opposite_direction_sorter(*i, &n, !forceStraight));
counterIncomingEdges[*i] = *incoming.begin();
std::sort(outgoing.begin(), outgoing.end(), NBContHelper::edge_opposite_direction_sorter(*i, &n, !forceStraight));
counterOutgoingEdges[*i] = *outgoing.begin();
}
#ifdef DEBUG_SETPRIORITIES
if (DEBUGCOND) {
std::map<std::string, std::string> tmp1;
for (auto item : counterIncomingEdges) {
tmp1[item.first->getID()] = item.second->getID();
}
std::map<std::string, std::string> tmp2;
for (auto item : counterOutgoingEdges) {
tmp2[item.first->getID()] = item.second->getID();
}
std::cout << "n=" << n.getID() << " forceStraight=" << forceStraight << " bestIn=" << bestIn->getID() << " bestOut=" << toString(bestOutgoing)
<< " counterBest=" << counterIncomingEdges.find(bestIncoming[0])->second->getID()
<< " mainExplicit=" << mainDirectionExplicit
<< " forceStraight=" << forceStraight
<< "\n bestIncoming=" << toString(bestIncoming) << " allIncoming=" << toString(incoming)
<< "\n bestOutgoing=" << toString(bestOutgoing) << " allOutgoing=" << toString(outgoing)
<< "\n counterIncomingEdges=" << toString(tmp1)
<< "\n counterOutgoingEdges=" << toString(tmp2)
<< "\n";
}
#endif
const bool hasTLS = n.isTLControlled();
if (bestIncoming.size() == 1) {
NBEdge* best1 = extractAndMarkFirst(n, bestIncoming);
if (!mainDirectionExplicit && counterIncomingEdges.find(best1) != counterIncomingEdges.end()) {
NBEdge* s = counterIncomingEdges.find(best1)->second;
const double minAngleDiff = GeomHelper::getMinAngleDiff(best1->getAngleAtNode(&n), s->getAngleAtNode(&n));
if (minAngleDiff > 180 - 45
|| (minAngleDiff > 75 && s->getPriority() == best1->getPriority() && hasDifferentPriorities(incoming, best1))) {
s->setJunctionPriority(&n, NBEdge::PRIORITY_ROAD);
}
}
markBestParallel(n, best1, nullptr);
assert(bestOutgoing.size() != 0);
sort(bestOutgoing.begin(), bestOutgoing.end(), NBContHelper::edge_similar_direction_sorter(best1));
NBEdge* bestOut = extractAndMarkFirst(n, bestOutgoing);
if (!mainDirectionExplicit && counterOutgoingEdges.find(bestOut) != counterOutgoingEdges.end()) {
NBEdge* s = counterOutgoingEdges.find(bestOut)->second;
if (GeomHelper::getMinAngleDiff(bestOut->getAngleAtNode(&n), s->getAngleAtNode(&n)) > 180 - 45) {
s->setJunctionPriority(&n, NBEdge::PRIORITY_ROAD);
}
}
const bool isBent = n.getDirection(best1, bestOut) != LinkDirection::STRAIGHT;
#ifdef DEBUG_SETPRIORITIES
if (DEBUGCOND) {
std::cout << " best1=" << best1->getID() << " bestOut=" << bestOut->getID() << " bestOutgoing=" << toString(bestOutgoing) << " mainDirectionExplicit=" << mainDirectionExplicit << " isBent=" << isBent << "\n";
}
#endif
if (isBent && hasTLS && !forceStraight) {
setPriorityJunctionPriorities(n, true);
} else {
n.markBentPriority(isBent);
}
return;
}
double bestAngle = -1;
NBEdge* bestFirst = nullptr;
NBEdge* bestSecond = nullptr;
for (i = bestIncoming.begin(); i != bestIncoming.end(); ++i) {
EdgeVector::iterator j;
NBEdge* t1 = *i;
double angle1 = t1->getAngleAtNode(&n) + 180;
if (angle1 >= 360) {
angle1 -= 360;
}
for (j = i + 1; j != bestIncoming.end(); ++j) {
NBEdge* t2 = *j;
double angle2 = t2->getAngleAtNode(&n) + 180;
if (angle2 >= 360) {
angle2 -= 360;
}
double score = forceStraight ? getScore(t1, t2, minPrio, maxPrio, maxNumLanes, maxSpeed, all) : 0;
double angle = GeomHelper::getMinAngleDiff(angle1, angle2) + 45 * score;
if (angle > bestAngle) {
bestAngle = MAX2(angle, bestAngle);
bestFirst = *i;
bestSecond = *j;
}
}
}
bestFirst->setJunctionPriority(&n, NBEdge::PRIORITY_ROAD);
sort(bestOutgoing.begin(), bestOutgoing.end(), NBContHelper::edge_similar_direction_sorter(bestFirst));
#ifdef DEBUG_SETPRIORITIES
if (DEBUGCOND) {
std::cout << " bestFirst=" << bestFirst->getID() << " bestOutgoingFirst=" << toString(bestOutgoing) << "\n";
}
#endif
if (bestOutgoing.size() != 0) {
extractAndMarkFirst(n, bestOutgoing);
}
bestSecond->setJunctionPriority(&n, NBEdge::PRIORITY_ROAD);
sort(bestOutgoing.begin(), bestOutgoing.end(), NBContHelper::edge_similar_direction_sorter(bestSecond));
#ifdef DEBUG_SETPRIORITIES
if (DEBUGCOND) {
std::cout << " bestSecond=" << bestSecond->getID() << " bestOutgoingSecond=" << toString(bestOutgoing) << "\n";
}
#endif
if (bestOutgoing.size() != 0) {
extractAndMarkFirst(n, bestOutgoing);
}
const bool isBent = GeomHelper::getMinAngleDiff(bestFirst->getAngleAtNode(&n), bestSecond->getAngleAtNode(&n)) < 135;
if (isBent && hasTLS && !forceStraight) {
setPriorityJunctionPriorities(n, true);
} else {
n.markBentPriority(isBent);
markBestParallel(n, bestFirst, bestSecond);
}
}
double
NBEdgePriorityComputer::getScore(const NBEdge* e1, const NBEdge* e2, int minPrio, int maxPrio, int maxNumLanes, double maxSpeed, SVCPermissions permissions) {
double normPrio1 = 1;
double normPrio2 = 1;
if (minPrio != maxPrio) {
normPrio1 = ((e1->getPriority() - minPrio) / (maxPrio - minPrio)) * 0.9 + 0.1;
normPrio2 = ((e2->getPriority() - minPrio) / (maxPrio - minPrio)) * 0.9 + 0.1;
}
return (normPrio1
* e1->getNumLanesThatAllow(permissions, false) / maxNumLanes
* e1->getSpeed() / maxSpeed
* normPrio2
* e2->getNumLanesThatAllow(permissions, false) / maxNumLanes
* e2->getSpeed() / maxSpeed);
}
void
NBEdgePriorityComputer::markBestParallel(const NBNode& n, NBEdge* bestFirst, NBEdge* bestSecond) {
const double a1 = bestFirst->getAngleAtNode(&n);
const double a2 = bestSecond == nullptr ? a1 : bestSecond->getAngleAtNode(&n);
SVCPermissions p1 = bestFirst->getPermissions();
SVCPermissions p2 = bestSecond == nullptr ? p1 : bestSecond->getPermissions();
for (NBEdge* e : n.getIncomingEdges()) {
SVCPermissions perm = e->getPermissions();
if (((GeomHelper::getMinAngleDiff(e->getAngleAtNode(&n), a1) < 10
|| GeomHelper::getMinAngleDiff(e->getAngleAtNode(&n), a2) < 10))
&& (p1 & perm) == 0 && (p2 & perm) == 0) {
e->setJunctionPriority(&n, NBEdge::PRIORITY_ROAD);
}
}
}
NBEdge*
NBEdgePriorityComputer::extractAndMarkFirst(NBNode& n, std::vector<NBEdge*>& s, int prio) {
if (s.size() == 0) {
return nullptr;
}
NBEdge* ret = s.front();
s.erase(s.begin());
ret->setJunctionPriority(&n, prio);
return ret;
}
bool
NBEdgePriorityComputer::samePriority(const NBEdge* const e1, const NBEdge* const e2, SVCPermissions permissions) {
if (e1 == e2) {
return true;
}
if (e1->getPriority() != e2->getPriority()) {
return false;
}
if ((int) e1->getSpeed() != (int) e2->getSpeed()) {
return false;
}
return e1->getNumLanesThatAllow(permissions, false) == (int) e2->getNumLanesThatAllow(permissions, false);
}
bool
NBEdgePriorityComputer::hasDifferentPriorities(const EdgeVector& edges, const NBEdge* excluded) {
if (edges.size() < 2) {
return false;
}
int prio = edges[0] == excluded ? edges[1]->getPriority() : edges[0]->getPriority();
for (auto e : edges) {
if (e != excluded && e->getPriority() != prio) {
return true;
}
}
return false;
}
NBNodesEdgesSorter::crossing_by_junction_angle_sorter::crossing_by_junction_angle_sorter(const NBNode* node, const EdgeVector& ordering) {
myOrdering = ordering;
sort(myOrdering.begin(), myOrdering.end(), NBContHelper::edge_by_angle_to_nodeShapeCentroid_sorter(node));
rotate(myOrdering.begin(), std::find(myOrdering.begin(), myOrdering.end(), ordering.front()), myOrdering.end());
}