Eclipse SUMO - Simulation of Urban MObility
NBAlgorithms.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3// Copyright (C) 2012-2022 German Aerospace Center (DLR) and others.
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// https://www.eclipse.org/legal/epl-2.0/
7// This Source Code may also be made available under the following Secondary
8// Licenses when the conditions for such availability set forth in the Eclipse
9// Public License 2.0 are satisfied: GNU General Public License, version 2
10// or later which is available at
11// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13/****************************************************************************/
19// Algorithms for network computation
20/****************************************************************************/
21#include <config.h>
22
23#include <sstream>
24#include <iostream>
25#include <cassert>
26#include <algorithm>
30#include "NBEdge.h"
31#include "NBOwnTLDef.h"
33#include "NBNodeCont.h"
34#include "NBTypeCont.h"
35#include "NBNode.h"
36#include "NBAlgorithms.h"
37
38
39//#define DEBUG_SETPRIORITIES
40#define DEBUGCOND (n.getID() == "C")
41
42// ===========================================================================
43// method definitions
44// ===========================================================================
45// ---------------------------------------------------------------------------
46// NBTurningDirectionsComputer
47// ---------------------------------------------------------------------------
48void
50 for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
51 computeTurnDirectionsForNode(i->second, warn);
52 }
53}
54
55void
57 const std::vector<NBEdge*>& incoming = node->getIncomingEdges();
58 const std::vector<NBEdge*>& outgoing = node->getOutgoingEdges();
59 // reset turning directions since this may be called multiple times
60 for (std::vector<NBEdge*>::const_iterator k = incoming.begin(); k != incoming.end(); ++k) {
61 (*k)->setTurningDestination(nullptr);
62 }
63 std::vector<Combination> combinations;
64 const bool geometryLike = node->geometryLike();
65 for (std::vector<NBEdge*>::const_iterator j = outgoing.begin(); j != outgoing.end(); ++j) {
66 NBEdge* outedge = *j;
67 for (std::vector<NBEdge*>::const_iterator k = incoming.begin(); k != incoming.end(); ++k) {
68 NBEdge* e = *k;
69 // @todo: check whether NBHelpers::relAngle is properly defined and whether it should really be used, here
70 const double signedAngle = NBHelpers::normRelAngle(e->getAngleAtNode(node), outedge->getAngleAtNode(node));
71 if (signedAngle > 0 && signedAngle < 177 && e->getGeometry().back().distanceTo2D(outedge->getGeometry().front()) < POSITION_EPS) {
72 // backwards curving edges can only be turnaround when there are
73 // non-default endpoints
74 continue;
75 }
76 double angle = fabs(signedAngle);
77 // std::cout << "incoming=" << e->getID() << " outgoing=" << outedge->getID() << " relAngle=" << NBHelpers::relAngle(e->getAngleAtNode(node), outedge->getAngleAtNode(node)) << "\n";
78 const bool badPermissions = ((outedge->getPermissions() & e->getPermissions() & ~SVC_PEDESTRIAN) == 0
79 && !geometryLike
80 && outedge->getPermissions() != e->getPermissions());
81 if (e->getFromNode() == outedge->getToNode()
82 && (angle > 120 || e->getFromNode()->getPosition() == e->getToNode()->getPosition())
83 && !badPermissions) {
84 // they connect the same nodes; should be the turnaround direction
85 // we'll assign a maximum number
86 //
87 // @todo: indeed, we have observed some pathological intersections
88 // see "294831560" in OSM/adlershof. Here, several edges are connecting
89 // same nodes. We have to do the angle check before...
90 //
91 // @todo: and well, there are some other as well, see plain import
92 // of delphi_muenchen (elmar), intersection "59534191". Not that it would
93 // be realistic in any means; we will warn, here.
94 angle += 360;
95 }
96 if (angle < 160) {
97 continue;
98 }
99 if (badPermissions) {
100 // penalty
101 angle -= 90;
102 }
103 Combination c;
104 c.from = e;
105 c.to = outedge;
106 c.angle = angle;
107 combinations.push_back(c);
108 }
109 }
110 // sort combinations so that the ones with the highest angle are at the begin
111 std::sort(combinations.begin(), combinations.end(), combination_by_angle_sorter());
112 std::set<NBEdge*> seen;
113 //std::cout << "check combinations at " << node->getID() << "\n";
114 for (std::vector<Combination>::const_iterator j = combinations.begin(); j != combinations.end(); ++j) {
115 //std::cout << " from=" << (*j).from->getID() << " to=" << (*j).to->getID() << " a=" << (*j).angle << "\n";
116 if (seen.find((*j).from) != seen.end() || seen.find((*j).to) != seen.end()) {
117 // do not regard already set edges
118 if ((*j).angle > 360 && warn) {
119 WRITE_WARNINGF(TL("Ambiguity in turnarounds computation at junction '%'."), node->getID());
120 //std::cout << " already seen: " << toString(seen) << "\n";
121 warn = false;
122 }
123 continue;
124 }
125 // mark as seen
126 seen.insert((*j).from);
127 seen.insert((*j).to);
128 // set turnaround information
129 bool onlyPossible = (*j).from->getConnections().size() != 0 && !(*j).from->isConnectedTo((*j).to);
130 //std::cout << " setTurningDestination from=" << (*j).from->getID() << " to=" << (*j).to->getID() << " onlyPossible=" << onlyPossible << "\n";
131 (*j).from->setTurningDestination((*j).to, onlyPossible);
132 }
133}
134
135
136// ---------------------------------------------------------------------------
137// NBNodesEdgesSorter
138// ---------------------------------------------------------------------------
139void
141 for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
142 i->second->sortEdges(useNodeShape);
143 }
144}
145
146
147void
149 const std::vector<NBEdge*>::iterator& i1,
150 const std::vector<NBEdge*>::iterator& i2) {
151 NBEdge* e1 = *i1;
152 NBEdge* e2 = *i2;
153 // @todo: The difference between "isTurningDirectionAt" and "isTurnaround"
154 // is not nice. Maybe we could get rid of it if we would always mark edges
155 // as turnarounds, even if they do not have to be added, as mentioned in
156 // notes on NBTurningDirectionsComputer::computeTurnDirectionsForNode
157 if (e2->getToNode() == n && e2->isTurningDirectionAt(e1)) {
158 std::swap(*i1, *i2);
159 }
160}
161
162
163// ---------------------------------------------------------------------------
164// NBNodeTypeComputer
165// ---------------------------------------------------------------------------
166void
168 validateRailCrossings(nc, tlc);
170 const double rightBeforeLeftSpeed = oc.getFloat("junctions.right-before-left.speed-threshold");
171 for (const auto& nodeIt : nc) {
172 NBNode* const n = nodeIt.second;
173 // the type may already be set from the data
175 n->myTypeWasGuessed = false;
176 continue;
177 }
178 // check whether the node was set to be unregulated by the user
179 if (oc.getBool("keep-nodes-unregulated") || oc.isInStringVector("keep-nodes-unregulated.explicit", n->getID())
180 || (oc.getBool("keep-nodes-unregulated.district-nodes") && (n->isNearDistrict() || n->isDistrict()))) {
182 continue;
183 }
184 // check whether the node is a waterway node. Set to unregulated by default
185 bool waterway = true;
186 for (NBEdge* e : n->getEdges()) {
187 if (!isWaterway(e->getPermissions())) {
188 waterway = false;
189 break;
190 }
191 }
192 if (waterway && (n->myType == SumoXMLNodeType::UNKNOWN || n->myType == SumoXMLNodeType::DEAD_END)) {
194 continue;
195 }
196
197 // check whether the junction is not a real junction
198 if (n->myIncomingEdges.size() == 1) {
200 continue;
201 }
202 // @todo "isSimpleContinuation" should be revalidated
203 if (n->isSimpleContinuation()) {
205 continue;
206 }
207 if (isRailwayNode(n)) {
208 // priority instead of unregulated to ensure that collisions can be detected
210 continue;
211 }
212 // determine the type
214 for (EdgeVector::const_iterator i = n->myIncomingEdges.begin(); i != n->myIncomingEdges.end(); i++) {
215 for (EdgeVector::const_iterator j = i + 1; j != n->myIncomingEdges.end(); j++) {
216 // @todo "getOppositeIncoming" should probably be refactored into something the edge knows
217 if (n->getOppositeIncoming(*j) == *i && n->myIncomingEdges.size() > 2) {
218 continue;
219 }
220 // @todo check against a legal document
221 // @todo figure out when SumoXMLNodeType::PRIORITY_STOP is appropriate
222 const double s1 = (*i)->getSpeed();
223 const double s2 = (*j)->getSpeed();
224 const int p1 = (*i)->getPriority();
225 const int p2 = (*j)->getPriority();
226 if (fabs(s1 - s2) > (9.5 / 3.6) || MAX2(s1, s2) >= rightBeforeLeftSpeed || p1 != p2) {
228 break;
229 }
230 }
231 }
232 // save type
233 n->myType = type;
234 n->myTypeWasGuessed = true;
235 }
236}
237
238
239void
241 for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
242 NBNode* n = (*i).second;
244 // check if it really is a rail crossing
245 int numRailway = 0;
246 int numNonRailIn = 0;
247 int numNonRailOut = 0;
248 std::set<const NBNode*> nonRailNodes;
249 int numNonRailwayNonPed = 0;
250 for (NBEdge* e : n->getIncomingEdges()) {
251 if ((e->getPermissions() & ~SVC_RAIL_CLASSES) != 0) {
252 numNonRailIn += 1;
253 if (e->getPermissions() != SVC_PEDESTRIAN) {
254 numNonRailwayNonPed++;
255 }
256 nonRailNodes.insert(e->getFromNode());
257 } else if ((e->getPermissions() & SVC_RAIL_CLASSES) != 0) {
258 numRailway++;
259 }
260 }
261 for (NBEdge* e : n->getOutgoingEdges()) {
262 if ((e->getPermissions() & ~SVC_RAIL_CLASSES) != 0) {
263 numNonRailOut += 1;
264 nonRailNodes.insert(e->getToNode());
265 }
266 }
267 if (numNonRailIn == 0 || numNonRailOut == 0 || numRailway == 0) {
268 // not a crossing (maybe unregulated or rail_signal)
270 } else if (numNonRailwayNonPed > 2 || nonRailNodes.size() > 2) {
271 // does not look like a rail crossing (roads in conflict). maybe a traffic light?
272 WRITE_WARNINGF(TL("Converting invalid rail_crossing to traffic_light at junction '%'."), n->getID());
274 NBTrafficLightDefinition* tlDef = new NBOwnTLDef(n->getID(), n, 0, type);
276 if (!tlc.insert(tlDef)) {
277 // actually, nothing should fail here
278 n->removeTrafficLight(tlDef);
280 delete tlDef;
281 WRITE_WARNINGF(TL("Could not allocate tls '%'."), n->getID());
282 }
283 }
284 }
285 }
286}
287
288
289bool
291 bool hasRailway = false;
292 for (NBEdge* e : n->getIncomingEdges()) {
293 if ((e->getPermissions() & ~SVC_RAIL_CLASSES) != 0) {
294 return false;
295 } else if ((e->getPermissions() & SVC_RAIL_CLASSES) != 0) {
296 hasRailway = true;
297 }
298 }
299 return hasRailway;
300}
301
302// ---------------------------------------------------------------------------
303// NBEdgePriorityComputer
304// ---------------------------------------------------------------------------
305void
307 for (const auto& node : nc) {
308 // preset all junction's edge priorities to zero
309 for (NBEdge* const edge : node.second->myAllEdges) {
310 edge->setJunctionPriority(node.second, NBEdge::JunctionPriority::MINOR_ROAD);
311 }
312 node.second->markBentPriority(false);
313 // check if the junction is not a real junction
314 if (node.second->myIncomingEdges.size() == 1 && node.second->myOutgoingEdges.size() == 1) {
315 continue;
316 }
317 // compute the priorities on junction when needed
318 if (node.second->getType() != SumoXMLNodeType::RIGHT_BEFORE_LEFT
319 && node.second->getType() != SumoXMLNodeType::LEFT_BEFORE_RIGHT
320 && node.second->getType() != SumoXMLNodeType::ALLWAY_STOP
321 && node.second->getType() != SumoXMLNodeType::NOJUNCTION) {
322 if (node.second->getRightOfWay() == RightOfWay::EDGEPRIORITY) {
323 for (NBEdge* e : node.second->getIncomingEdges()) {
324 e->setJunctionPriority(node.second, e->getPriority());
325 }
326 } else {
327 setPriorityJunctionPriorities(*node.second);
328 }
329 }
330 }
331}
332
333
334void
336 if (n.myIncomingEdges.size() == 0 || n.myOutgoingEdges.size() == 0) {
337 return;
338 }
339 int minPrio = std::numeric_limits<int>::max();
340 int maxPrio = -std::numeric_limits<int>::max();
341 int maxNumLanes = -std::numeric_limits<int>::max();
342 double maxSpeed = -std::numeric_limits<double>::max();
343 if (forceStraight) {
344 // called a second time, preset all junction's edge priorities to zero
345 for (NBEdge* const edge : n.myAllEdges) {
346 edge->setJunctionPriority(&n, NBEdge::JunctionPriority::MINOR_ROAD);
347 minPrio = MIN2(minPrio, edge->getPriority());
348 maxPrio = MAX2(maxPrio, edge->getPriority());
349 maxNumLanes = MAX2(maxNumLanes, edge->getNumLanes());
350 maxSpeed = MAX2(maxSpeed, edge->getSpeed());
351 }
352 }
353 EdgeVector incoming = n.myIncomingEdges;
354 EdgeVector outgoing = n.myOutgoingEdges;
355 // what we do want to have is to extract the pair of roads that are
356 // the major roads for this junction
357 // let's get the list of incoming edges with the highest priority
358 std::sort(incoming.begin(), incoming.end(), NBContHelper::edge_by_priority_sorter());
359 EdgeVector bestIncoming;
360 NBEdge* bestIn = incoming[0];
361 while (incoming.size() > 0 && (forceStraight || samePriority(bestIn, incoming[0]))) {
362 bestIncoming.push_back(*incoming.begin());
363 incoming.erase(incoming.begin());
364 }
365 // now, let's get the list of best outgoing
366 assert(outgoing.size() != 0);
367 sort(outgoing.begin(), outgoing.end(), NBContHelper::edge_by_priority_sorter());
368 EdgeVector bestOutgoing;
369 const NBEdge* const firstOut = outgoing[0];
370 while (outgoing.size() > 0 && (forceStraight || samePriority(firstOut, outgoing[0]))) { //->getPriority()==best->getPriority())
371 bestOutgoing.push_back(*outgoing.begin());
372 outgoing.erase(outgoing.begin());
373 }
374 // special case: user input makes mainDirection unambiguous
375 const bool mainDirectionExplicit = (
376 bestIncoming.size() == 1 && n.myIncomingEdges.size() <= 2
377 && (incoming.size() == 0 || bestIncoming[0]->getPriority() > incoming[0]->getPriority())
378 && bestOutgoing.size() == 1 && n.myOutgoingEdges.size() <= 2
379 && (outgoing.size() == 0 || bestOutgoing[0]->getPriority() > outgoing[0]->getPriority())
380 && !bestIncoming[0]->isTurningDirectionAt(bestOutgoing[0]));
381 // now, let's compute for each of the best incoming edges
382 // the incoming which is most opposite
383 // the outgoing which is most opposite
384 EdgeVector::iterator i;
385 std::map<NBEdge*, NBEdge*> counterIncomingEdges;
386 std::map<NBEdge*, NBEdge*> counterOutgoingEdges;
387 incoming = n.myIncomingEdges;
388 outgoing = n.myOutgoingEdges;
389 for (i = bestIncoming.begin(); i != bestIncoming.end(); ++i) {
390 std::sort(incoming.begin(), incoming.end(), NBContHelper::edge_opposite_direction_sorter(*i, &n, !forceStraight));
391 counterIncomingEdges[*i] = *incoming.begin();
392 std::sort(outgoing.begin(), outgoing.end(), NBContHelper::edge_opposite_direction_sorter(*i, &n, !forceStraight));
393 counterOutgoingEdges[*i] = *outgoing.begin();
394 }
395#ifdef DEBUG_SETPRIORITIES
396 if (DEBUGCOND) {
397 std::map<std::string, std::string> tmp1;
398 for (auto item : counterIncomingEdges) {
399 tmp1[item.first->getID()] = item.second->getID();
400 }
401 std::map<std::string, std::string> tmp2;
402 for (auto item : counterOutgoingEdges) {
403 tmp2[item.first->getID()] = item.second->getID();
404 }
405 std::cout << "n=" << n.getID() << " bestIn=" << bestIn->getID() << " bestOut=" << bestOut->getID()
406 << " counterBest=" << counterIncomingEdges.find(bestIncoming[0])->second->getID()
407 << " mainExplicit=" << mainDirectionExplicit
408 << " forceStraight=" << forceStraight
409 << "\n bestIncoming=" << toString(bestIncoming) << " allIncoming=" << toString(incoming)
410 << "\n bestOutgoing=" << toString(bestOutgoing) << " allOutgoing=" << toString(outgoing)
411 << "\n counterIncomingEdges=" << toString(tmp1)
412 << "\n counterOutgoingEdges=" << toString(tmp2)
413 << "\n";
414 }
415#endif
416 // at a tls junction we must prevent an underlying bent-priority layout
417 // because that would lead to invalid right-of-way rules for an oncoming
418 // tls layout (but not vice versa). See #7764
419 const bool hasTLS = n.isTLControlled();
420 // ok, let's try
421 // 1) there is one best incoming road
422 if (bestIncoming.size() == 1) {
423 // let's mark this road as the best
424 NBEdge* best1 = extractAndMarkFirst(n, bestIncoming);
425 if (!mainDirectionExplicit && counterIncomingEdges.find(best1) != counterIncomingEdges.end()) {
426 // ok, look, what we want is the opposit of the straight continuation edge
427 // but, what if such an edge does not exist? By now, we'll determine it
428 // geometrically
429 NBEdge* s = counterIncomingEdges.find(best1)->second;
430 const double minAngleDiff = GeomHelper::getMinAngleDiff(best1->getAngleAtNode(&n), s->getAngleAtNode(&n));
431 if (minAngleDiff > 180 - 45
432 || (minAngleDiff > 75 && s->getPriority() == best1->getPriority() && hasDifferentPriorities(incoming, best1))) {
434 }
435 }
436 markBestParallel(n, best1, nullptr);
437 assert(bestOutgoing.size() != 0);
438 // mark the best outgoing as the continuation
439 sort(bestOutgoing.begin(), bestOutgoing.end(), NBContHelper::edge_similar_direction_sorter(best1));
440 // assign extra priority if the priorities are unambiguous (regardless of geometry)
441 NBEdge* bestOut = extractAndMarkFirst(n, bestOutgoing);
442 if (!mainDirectionExplicit && counterOutgoingEdges.find(bestOut) != counterOutgoingEdges.end()) {
443 NBEdge* s = counterOutgoingEdges.find(bestOut)->second;
444 if (GeomHelper::getMinAngleDiff(bestOut->getAngleAtNode(&n), s->getAngleAtNode(&n)) > 180 - 45) {
445 s->setJunctionPriority(&n, 1);
446 }
447 }
448 const bool isBent = n.getDirection(best1, bestOut) != LinkDirection::STRAIGHT;
449#ifdef DEBUG_SETPRIORITIES
450 if (DEBUGCOND) {
451 std::cout << " best1=" << best1->getID() << " bestOut=" << bestOut->getID() << " bestOutgoing=" << toString(bestOutgoing) << " mainDirectionExplicit=" << mainDirectionExplicit << " isBent=" << isBent << "\n";
452 }
453#endif
454 if (isBent && hasTLS && !forceStraight) {
455 // redo but force straight computation
457 } else {
458 n.markBentPriority(isBent);
459 }
460 return;
461 }
462
463 // ok, what we want to do in this case is to determine which incoming
464 // has the best continuation...
465 // This means, when several incoming roads have the same priority,
466 // we want a (any) straight connection to be more priorised than a turning
467 double bestAngle = -1;
468 NBEdge* bestFirst = nullptr;
469 NBEdge* bestSecond = nullptr;
470 for (i = bestIncoming.begin(); i != bestIncoming.end(); ++i) {
471 EdgeVector::iterator j;
472 NBEdge* t1 = *i;
473 double angle1 = t1->getAngleAtNode(&n) + 180;
474 if (angle1 >= 360) {
475 angle1 -= 360;
476 }
477 for (j = i + 1; j != bestIncoming.end(); ++j) {
478 NBEdge* t2 = *j;
479 double angle2 = t2->getAngleAtNode(&n) + 180;
480 if (angle2 >= 360) {
481 angle2 -= 360;
482 }
483 double score = forceStraight ? getScore(t1, t2, minPrio, maxPrio, maxNumLanes, maxSpeed) : 0;
484 double angle = GeomHelper::getMinAngleDiff(angle1, angle2) + 45 * score;
485 if (angle > bestAngle) {
486 //if (forceStraight) std::cout << " node=" << n.getID() << " t1=" << t1->getID() << " t2=" << t2->getID() << " angle=" << angle << " bestAngle=" << bestAngle << " score=" << score << " minPrio=" << minPrio << " maxPrio=" << maxPrio << "\n";
487 bestAngle = MAX2(angle, bestAngle);
488 bestFirst = *i;
489 bestSecond = *j;
490 }
491 }
492 }
493 bestFirst->setJunctionPriority(&n, 1);
494 sort(bestOutgoing.begin(), bestOutgoing.end(), NBContHelper::edge_similar_direction_sorter(bestFirst));
495#ifdef DEBUG_SETPRIORITIES
496 if (DEBUGCOND) {
497 std::cout << " bestFirst=" << bestFirst->getID() << " bestOutgoingFirst=" << toString(bestOutgoing) << "\n";
498 }
499#endif
500 if (bestOutgoing.size() != 0) {
501 extractAndMarkFirst(n, bestOutgoing);
502 }
503 bestSecond->setJunctionPriority(&n, 1);
504 sort(bestOutgoing.begin(), bestOutgoing.end(), NBContHelper::edge_similar_direction_sorter(bestSecond));
505#ifdef DEBUG_SETPRIORITIES
506 if (DEBUGCOND) {
507 std::cout << " bestSecond=" << bestSecond->getID() << " bestOutgoingSecond=" << toString(bestOutgoing) << "\n";
508 }
509#endif
510 if (bestOutgoing.size() != 0) {
511 extractAndMarkFirst(n, bestOutgoing);
512 }
513 const bool isBent = GeomHelper::getMinAngleDiff(bestFirst->getAngleAtNode(&n), bestSecond->getAngleAtNode(&n)) < 135;
514 if (isBent && hasTLS && !forceStraight) {
515 // redo but force straight computation
517 } else {
518 n.markBentPriority(isBent);
519 markBestParallel(n, bestFirst, bestSecond);
520 }
521}
522
523double
524NBEdgePriorityComputer::getScore(const NBEdge* e1, const NBEdge* e2, int minPrio, int maxPrio, int maxNumLanes, double maxSpeed) {
525 // normalize priorities to [0.1,1]
526 double normPrio1 = 1;
527 double normPrio2 = 1;
528 if (minPrio != maxPrio) {
529 normPrio1 = ((e1->getPriority() - minPrio) / (maxPrio - minPrio)) * 0.9 + 0.1;
530 normPrio2 = ((e2->getPriority() - minPrio) / (maxPrio - minPrio)) * 0.9 + 0.1;
531 }
532 return (normPrio1
533 * e1->getNumLanes() / maxNumLanes
534 * e1->getSpeed() / maxSpeed
535 * normPrio2
536 * e2->getNumLanes() / maxNumLanes
537 * e2->getSpeed() / maxSpeed);
538}
539
540void
542 // edges running parallel to the main direction should also be prioritised
543 const double a1 = bestFirst->getAngleAtNode(&n);
544 const double a2 = bestSecond == nullptr ? a1 : bestSecond->getAngleAtNode(&n);
545 SVCPermissions p1 = bestFirst->getPermissions();
546 SVCPermissions p2 = bestSecond == nullptr ? p1 : bestSecond->getPermissions();
547 for (NBEdge* e : n.getIncomingEdges()) {
548 // @note: this rule might also apply if there are common permissions but
549 // then we would not further rules to resolve the priority between the best edge and its parallel edge
550 SVCPermissions perm = e->getPermissions();
551 if (((GeomHelper::getMinAngleDiff(e->getAngleAtNode(&n), a1) < 10
552 || GeomHelper::getMinAngleDiff(e->getAngleAtNode(&n), a2) < 10))
553 && (p1 & perm) == 0 && (p2 & perm) == 0) {
554 e->setJunctionPriority(&n, 1);
555 }
556 }
557}
558
559
560NBEdge*
561NBEdgePriorityComputer::extractAndMarkFirst(NBNode& n, std::vector<NBEdge*>& s, int prio) {
562 if (s.size() == 0) {
563 return nullptr;
564 }
565 NBEdge* ret = s.front();
566 s.erase(s.begin());
567 ret->setJunctionPriority(&n, prio);
568 return ret;
569}
570
571
572bool
573NBEdgePriorityComputer::samePriority(const NBEdge* const e1, const NBEdge* const e2) {
574 if (e1 == e2) {
575 return true;
576 }
577 if (e1->getPriority() != e2->getPriority()) {
578 return false;
579 }
580 if ((int) e1->getSpeed() != (int) e2->getSpeed()) {
581 return false;
582 }
583 return (int) e1->getNumLanes() == (int) e2->getNumLanes();
584}
585
586
587bool
589 if (edges.size() < 2) {
590 return false;
591 }
592 int prio = edges[0] == excluded ? edges[1]->getPriority() : edges[0]->getPriority();
593 for (auto e : edges) {
594 if (e != excluded && e->getPriority() != prio) {
595 return true;
596 }
597 }
598 return false;
599}
600
601
603 // reorder based on getAngleAtNodeToCenter
604 myOrdering = ordering;
606 // let the first edge remain the first
607 rotate(myOrdering.begin(), std::find(myOrdering.begin(), myOrdering.end(), ordering.front()), myOrdering.end());
608}
609
610
611/****************************************************************************/
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:266
#define TL(string)
Definition: MsgHandler.h:282
#define DEBUGCOND
std::vector< NBEdge * > EdgeVector
container for (sorted) edges
Definition: NBCont.h:42
bool isWaterway(SVCPermissions permissions)
Returns whether an edge with the given permission is a waterway edge.
@ SVC_RAIL_CLASSES
classes which drive on tracks
@ SVC_PEDESTRIAN
pedestrian
int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
TrafficLightType
@ STRAIGHT
The link is a straight direction.
SumoXMLNodeType
Numbers representing special SUMO-XML-attribute values for representing node- (junction-) types used ...
T MIN2(T a, T b)
Definition: StdDefs.h:71
T MAX2(T a, T b)
Definition: StdDefs.h:77
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:46
static double getMinAngleDiff(double angle1, double angle2)
Returns the minimum distance (clockwise/counter-clockwise) between both angles.
Definition: GeomHelper.cpp:173
Class to sort edges by their angle in relation to the given edge.
Definition: NBContHelper.h:142
The representation of a single edge during network building.
Definition: NBEdge.h:92
SVCPermissions getPermissions(int lane=-1) const
get the union of allowed classes over all lanes or for a specific lane
Definition: NBEdge.cpp:4137
@ PRIORITY_ROAD
Definition: NBEdge.h:392
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:552
const PositionVector & getGeometry() const
Returns the geometry of the edge.
Definition: NBEdge.h:787
double getSpeed() const
Returns the speed allowed on this edge.
Definition: NBEdge.h:625
const std::string & getID() const
Definition: NBEdge.h:1526
bool isTurningDirectionAt(const NBEdge *const edge) const
Returns whether the given edge is the opposite direction to this edge.
Definition: NBEdge.cpp:3430
int getNumLanes() const
Returns the number of lanes.
Definition: NBEdge.h:526
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition: NBEdge.h:545
double getAngleAtNode(const NBNode *const node) const
Returns the angle of the edge's geometry at the given node.
Definition: NBEdge.cpp:2083
int getPriority() const
Returns the priority of the edge.
Definition: NBEdge.h:533
void setJunctionPriority(const NBNode *const node, int prio)
Sets the junction priority of the edge.
Definition: NBEdge.cpp:2067
EdgeVector getIncomingEdges() const
Returns the list of incoming edges unsorted.
Definition: NBEdge.cpp:1347
static double getScore(const NBEdge *e1, const NBEdge *e2, int minPrio, int maxPrio, int maxNumLanes, double maxSpeed)
score pair of edges for multi-criteria evaluatoin of angle, priority, laneNumber and speed
static void markBestParallel(const NBNode &n, NBEdge *bestFirst, NBEdge *bestSecond)
set priority for edges that are parallel to the best edges
static NBEdge * extractAndMarkFirst(NBNode &n, std::vector< NBEdge * > &s, int prio=1)
Sets the priorites in case of a priority junction.
static bool hasDifferentPriorities(const EdgeVector &edges, const NBEdge *excluded)
return whether the priorite attribute can be used to distinguish the edges
static void computeEdgePriorities(NBNodeCont &nc)
Computes edge priorities within a node.
static void setPriorityJunctionPriorities(NBNode &n, bool forceStraight=false)
Sets the priorites in case of a priority junction.
static bool samePriority(const NBEdge *const e1, const NBEdge *const e2)
Returns whether both edges have the same priority.
static double normRelAngle(double angle1, double angle2)
ensure that reverse relAngles (>=179.999) always count as turnarounds (-180)
Definition: NBHelpers.cpp:58
Container for nodes during the netbuilding process.
Definition: NBNodeCont.h:58
std::map< std::string, NBNode * >::const_iterator begin() const
Returns the pointer to the begin of the stored nodes.
Definition: NBNodeCont.h:113
std::map< std::string, NBNode * >::const_iterator end() const
Returns the pointer to the end of the stored nodes.
Definition: NBNodeCont.h:118
Represents a single node (junction) during network building.
Definition: NBNode.h:66
LinkDirection getDirection(const NBEdge *const incoming, const NBEdge *const outgoing, bool leftHand=false) const
Returns the representation of the described stream's direction.
Definition: NBNode.cpp:2229
bool isSimpleContinuation(bool checkLaneNumbers=true, bool checkWidth=false) const
check if node is a simple continuation
Definition: NBNode.cpp:479
bool myTypeWasGuessed
whether the node type was guessed rather than loaded
Definition: NBNode.h:937
SumoXMLNodeType myType
The type of the junction.
Definition: NBNode.h:887
EdgeVector myOutgoingEdges
Vector of outgoing edges.
Definition: NBNode.h:872
const EdgeVector & getIncomingEdges() const
Returns this node's incoming edges (The edges which yield in this node)
Definition: NBNode.h:258
const EdgeVector & getOutgoingEdges() const
Returns this node's outgoing edges (The edges which start at this node)
Definition: NBNode.h:263
EdgeVector myAllEdges
Vector of incoming and outgoing edges.
Definition: NBNode.h:875
bool isDistrict() const
check if node is a district
Definition: NBNode.cpp:2493
const Position & getPosition() const
Definition: NBNode.h:250
void removeTrafficLight(NBTrafficLightDefinition *tlDef)
Removes the given traffic light from this node.
Definition: NBNode.cpp:375
const EdgeVector & getEdges() const
Returns all edges which participate in this node (Edges that start or end at this node)
Definition: NBNode.h:268
void markBentPriority(bool isBent)
mark whether a priority road turns at this node
Definition: NBNode.h:798
bool geometryLike() const
whether this is structurally similar to a geometry node
Definition: NBNode.cpp:3468
bool isNearDistrict() const
@chech if node is near district
Definition: NBNode.cpp:2476
EdgeVector myIncomingEdges
Vector of incoming edges.
Definition: NBNode.h:869
bool isTLControlled() const
Returns whether this node is controlled by any tls.
Definition: NBNode.h:321
NBEdge * getOppositeIncoming(NBEdge *e) const
returns the opposite incoming edge of certain edge
Definition: NBNode.cpp:1758
static bool isRailwayNode(const NBNode *n)
whether the given node only has rail edges
static void computeNodeTypes(NBNodeCont &nc, NBTrafficLightLogicCont &tlc)
Computes node types.
static void validateRailCrossings(NBNodeCont &nc, NBTrafficLightLogicCont &tlc)
Checks rail_crossing for validity.
crossing_by_junction_angle_sorter(const NBNode *node, const EdgeVector &ordering)
static void swapWhenReversed(const NBNode *const n, const std::vector< NBEdge * >::iterator &i1, const std::vector< NBEdge * >::iterator &i2)
Assures correct order for same-angle opposite-direction edges.
static void sortNodesEdges(NBNodeCont &nc, bool useNodeShape=false)
Sorts a node's edges clockwise regarding driving direction.
A traffic light logics which must be computed (only nodes/edges are given)
Definition: NBOwnTLDef.h:44
The base class for traffic light logic definitions.
A container for traffic light definitions and built programs.
bool insert(NBTrafficLightDefinition *logic, bool forceInsert=false)
Adds a logic definition to the dictionary.
Sorts "Combination"s by decreasing angle.
Definition: NBAlgorithms.h:75
static void computeTurnDirections(NBNodeCont &nc, bool warn=true)
Computes turnaround destinations for all edges (if exist)
static void computeTurnDirectionsForNode(NBNode *node, bool warn)
Computes turnaround destinations for all incoming edges of the given nodes (if any)
const std::string & getID() const
Returns the id.
Definition: Named.h:74
A storage for options typed value containers)
Definition: OptionsCont.h:89
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
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.
Definition: OptionsCont.cpp:59
bool isInStringVector(const std::string &optionName, const std::string &itemName) const
Returns the named option is a list of string values containing the specified item.
static StringBijection< TrafficLightType > TrafficLightTypes
traffic light types
T get(const std::string &str) const
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
Definition: json.hpp:21884
Stores the information about the angle between an incoming ("from") and an outgoing ("to") edge.
Definition: NBAlgorithms.h:65