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-2023 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)
269 WRITE_WARNINGF(TL("Converting invalid rail_crossing to priority junction '%'."), n->getID());
271 } else if (numNonRailwayNonPed > 2 || nonRailNodes.size() > 2) {
272 // does not look like a rail crossing (roads in conflict). maybe a traffic light?
273 WRITE_WARNINGF(TL("Converting invalid rail_crossing to traffic_light at junction '%'."), n->getID());
275 NBTrafficLightDefinition* tlDef = new NBOwnTLDef(n->getID(), n, 0, type);
277 if (!tlc.insert(tlDef)) {
278 // actually, nothing should fail here
279 n->removeTrafficLight(tlDef);
281 delete tlDef;
282 WRITE_WARNINGF(TL("Could not allocate tls '%'."), n->getID());
283 }
284 }
285 }
286 }
287}
288
289
290bool
292 bool hasRailway = false;
293 for (NBEdge* e : n->getIncomingEdges()) {
294 if ((e->getPermissions() & ~SVC_RAIL_CLASSES) != 0) {
295 return false;
296 } else if ((e->getPermissions() & SVC_RAIL_CLASSES) != 0) {
297 hasRailway = true;
298 }
299 }
300 return hasRailway;
301}
302
303// ---------------------------------------------------------------------------
304// NBEdgePriorityComputer
305// ---------------------------------------------------------------------------
306void
308 for (const auto& node : nc) {
309 // preset all junction's edge priorities to zero
310 for (NBEdge* const edge : node.second->myAllEdges) {
311 edge->setJunctionPriority(node.second, NBEdge::JunctionPriority::MINOR_ROAD);
312 }
313 node.second->markBentPriority(false);
314 // check if the junction is not a real junction
315 if (node.second->myIncomingEdges.size() == 1 && node.second->myOutgoingEdges.size() == 1) {
316 continue;
317 }
318 // compute the priorities on junction when needed
319 if (node.second->getType() != SumoXMLNodeType::RIGHT_BEFORE_LEFT
320 && node.second->getType() != SumoXMLNodeType::LEFT_BEFORE_RIGHT
321 && node.second->getType() != SumoXMLNodeType::ALLWAY_STOP
322 && node.second->getType() != SumoXMLNodeType::NOJUNCTION) {
323 if (node.second->getRightOfWay() == RightOfWay::EDGEPRIORITY) {
324 for (NBEdge* e : node.second->getIncomingEdges()) {
325 e->setJunctionPriority(node.second, e->getPriority());
326 }
327 } else {
328 setPriorityJunctionPriorities(*node.second);
329 }
330 }
331 }
332}
333
334
335void
337 if (n.myIncomingEdges.size() == 0 || n.myOutgoingEdges.size() == 0) {
338 return;
339 }
340 int minPrio = std::numeric_limits<int>::max();
341 int maxPrio = -std::numeric_limits<int>::max();
342 int maxNumLanes = -std::numeric_limits<int>::max();
343 double maxSpeed = -std::numeric_limits<double>::max();
344 if (forceStraight) {
345 // called a second time, preset all junction's edge priorities to zero
346 for (NBEdge* const edge : n.myAllEdges) {
347 edge->setJunctionPriority(&n, NBEdge::JunctionPriority::MINOR_ROAD);
348 minPrio = MIN2(minPrio, edge->getPriority());
349 maxPrio = MAX2(maxPrio, edge->getPriority());
350 maxNumLanes = MAX2(maxNumLanes, edge->getNumLanes());
351 maxSpeed = MAX2(maxSpeed, edge->getSpeed());
352 }
353 }
354 EdgeVector incoming = n.myIncomingEdges;
355 EdgeVector outgoing = n.myOutgoingEdges;
356 // what we do want to have is to extract the pair of roads that are
357 // the major roads for this junction
358 // let's get the list of incoming edges with the highest priority
359 std::sort(incoming.begin(), incoming.end(), NBContHelper::edge_by_priority_sorter());
360 EdgeVector bestIncoming;
361 NBEdge* bestIn = incoming[0];
362 while (incoming.size() > 0 && (forceStraight || samePriority(bestIn, incoming[0]))) {
363 bestIncoming.push_back(*incoming.begin());
364 incoming.erase(incoming.begin());
365 }
366 // now, let's get the list of best outgoing
367 assert(outgoing.size() != 0);
368 sort(outgoing.begin(), outgoing.end(), NBContHelper::edge_by_priority_sorter());
369 EdgeVector bestOutgoing;
370 const NBEdge* const firstOut = outgoing[0];
371 while (outgoing.size() > 0 && (forceStraight || samePriority(firstOut, outgoing[0]))) { //->getPriority()==best->getPriority())
372 bestOutgoing.push_back(*outgoing.begin());
373 outgoing.erase(outgoing.begin());
374 }
375 // special case: user input makes mainDirection unambiguous
376 const bool mainDirectionExplicit = (
377 bestIncoming.size() == 1 && n.myIncomingEdges.size() <= 2
378 && (incoming.size() == 0 || bestIncoming[0]->getPriority() > incoming[0]->getPriority())
379 && bestOutgoing.size() == 1 && n.myOutgoingEdges.size() <= 2
380 && (outgoing.size() == 0 || bestOutgoing[0]->getPriority() > outgoing[0]->getPriority())
381 && !bestIncoming[0]->isTurningDirectionAt(bestOutgoing[0]));
382 // now, let's compute for each of the best incoming edges
383 // the incoming which is most opposite
384 // the outgoing which is most opposite
385 EdgeVector::iterator i;
386 std::map<NBEdge*, NBEdge*> counterIncomingEdges;
387 std::map<NBEdge*, NBEdge*> counterOutgoingEdges;
388 incoming = n.myIncomingEdges;
389 outgoing = n.myOutgoingEdges;
390 for (i = bestIncoming.begin(); i != bestIncoming.end(); ++i) {
391 std::sort(incoming.begin(), incoming.end(), NBContHelper::edge_opposite_direction_sorter(*i, &n, !forceStraight));
392 counterIncomingEdges[*i] = *incoming.begin();
393 std::sort(outgoing.begin(), outgoing.end(), NBContHelper::edge_opposite_direction_sorter(*i, &n, !forceStraight));
394 counterOutgoingEdges[*i] = *outgoing.begin();
395 }
396#ifdef DEBUG_SETPRIORITIES
397 if (DEBUGCOND) {
398 std::map<std::string, std::string> tmp1;
399 for (auto item : counterIncomingEdges) {
400 tmp1[item.first->getID()] = item.second->getID();
401 }
402 std::map<std::string, std::string> tmp2;
403 for (auto item : counterOutgoingEdges) {
404 tmp2[item.first->getID()] = item.second->getID();
405 }
406 std::cout << "n=" << n.getID() << " bestIn=" << bestIn->getID() << " bestOut=" << toString(bestOutgoing)
407 << " counterBest=" << counterIncomingEdges.find(bestIncoming[0])->second->getID()
408 << " mainExplicit=" << mainDirectionExplicit
409 << " forceStraight=" << forceStraight
410 << "\n bestIncoming=" << toString(bestIncoming) << " allIncoming=" << toString(incoming)
411 << "\n bestOutgoing=" << toString(bestOutgoing) << " allOutgoing=" << toString(outgoing)
412 << "\n counterIncomingEdges=" << toString(tmp1)
413 << "\n counterOutgoingEdges=" << toString(tmp2)
414 << "\n";
415 }
416#endif
417 // at a tls junction we must prevent an underlying bent-priority layout
418 // because that would lead to invalid right-of-way rules for an oncoming
419 // tls layout (but not vice versa). See #7764
420 const bool hasTLS = n.isTLControlled();
421 // ok, let's try
422 // 1) there is one best incoming road
423 if (bestIncoming.size() == 1) {
424 // let's mark this road as the best
425 NBEdge* best1 = extractAndMarkFirst(n, bestIncoming);
426 if (!mainDirectionExplicit && counterIncomingEdges.find(best1) != counterIncomingEdges.end()) {
427 // ok, look, what we want is the opposit of the straight continuation edge
428 // but, what if such an edge does not exist? By now, we'll determine it
429 // geometrically
430 NBEdge* s = counterIncomingEdges.find(best1)->second;
431 const double minAngleDiff = GeomHelper::getMinAngleDiff(best1->getAngleAtNode(&n), s->getAngleAtNode(&n));
432 if (minAngleDiff > 180 - 45
433 || (minAngleDiff > 75 && s->getPriority() == best1->getPriority() && hasDifferentPriorities(incoming, best1))) {
435 }
436 }
437 markBestParallel(n, best1, nullptr);
438 assert(bestOutgoing.size() != 0);
439 // mark the best outgoing as the continuation
440 sort(bestOutgoing.begin(), bestOutgoing.end(), NBContHelper::edge_similar_direction_sorter(best1));
441 // assign extra priority if the priorities are unambiguous (regardless of geometry)
442 NBEdge* bestOut = extractAndMarkFirst(n, bestOutgoing);
443 if (!mainDirectionExplicit && counterOutgoingEdges.find(bestOut) != counterOutgoingEdges.end()) {
444 NBEdge* s = counterOutgoingEdges.find(bestOut)->second;
445 if (GeomHelper::getMinAngleDiff(bestOut->getAngleAtNode(&n), s->getAngleAtNode(&n)) > 180 - 45) {
446 s->setJunctionPriority(&n, 1);
447 }
448 }
449 const bool isBent = n.getDirection(best1, bestOut) != LinkDirection::STRAIGHT;
450#ifdef DEBUG_SETPRIORITIES
451 if (DEBUGCOND) {
452 std::cout << " best1=" << best1->getID() << " bestOut=" << bestOut->getID() << " bestOutgoing=" << toString(bestOutgoing) << " mainDirectionExplicit=" << mainDirectionExplicit << " isBent=" << isBent << "\n";
453 }
454#endif
455 if (isBent && hasTLS && !forceStraight) {
456 // redo but force straight computation
458 } else {
459 n.markBentPriority(isBent);
460 }
461 return;
462 }
463
464 // ok, what we want to do in this case is to determine which incoming
465 // has the best continuation...
466 // This means, when several incoming roads have the same priority,
467 // we want a (any) straight connection to be more priorised than a turning
468 double bestAngle = -1;
469 NBEdge* bestFirst = nullptr;
470 NBEdge* bestSecond = nullptr;
471 for (i = bestIncoming.begin(); i != bestIncoming.end(); ++i) {
472 EdgeVector::iterator j;
473 NBEdge* t1 = *i;
474 double angle1 = t1->getAngleAtNode(&n) + 180;
475 if (angle1 >= 360) {
476 angle1 -= 360;
477 }
478 for (j = i + 1; j != bestIncoming.end(); ++j) {
479 NBEdge* t2 = *j;
480 double angle2 = t2->getAngleAtNode(&n) + 180;
481 if (angle2 >= 360) {
482 angle2 -= 360;
483 }
484 double score = forceStraight ? getScore(t1, t2, minPrio, maxPrio, maxNumLanes, maxSpeed) : 0;
485 double angle = GeomHelper::getMinAngleDiff(angle1, angle2) + 45 * score;
486 if (angle > bestAngle) {
487 //if (forceStraight) std::cout << " node=" << n.getID() << " t1=" << t1->getID() << " t2=" << t2->getID() << " angle=" << angle << " bestAngle=" << bestAngle << " score=" << score << " minPrio=" << minPrio << " maxPrio=" << maxPrio << "\n";
488 bestAngle = MAX2(angle, bestAngle);
489 bestFirst = *i;
490 bestSecond = *j;
491 }
492 }
493 }
494 bestFirst->setJunctionPriority(&n, 1);
495 sort(bestOutgoing.begin(), bestOutgoing.end(), NBContHelper::edge_similar_direction_sorter(bestFirst));
496#ifdef DEBUG_SETPRIORITIES
497 if (DEBUGCOND) {
498 std::cout << " bestFirst=" << bestFirst->getID() << " bestOutgoingFirst=" << toString(bestOutgoing) << "\n";
499 }
500#endif
501 if (bestOutgoing.size() != 0) {
502 extractAndMarkFirst(n, bestOutgoing);
503 }
504 bestSecond->setJunctionPriority(&n, 1);
505 sort(bestOutgoing.begin(), bestOutgoing.end(), NBContHelper::edge_similar_direction_sorter(bestSecond));
506#ifdef DEBUG_SETPRIORITIES
507 if (DEBUGCOND) {
508 std::cout << " bestSecond=" << bestSecond->getID() << " bestOutgoingSecond=" << toString(bestOutgoing) << "\n";
509 }
510#endif
511 if (bestOutgoing.size() != 0) {
512 extractAndMarkFirst(n, bestOutgoing);
513 }
514 const bool isBent = GeomHelper::getMinAngleDiff(bestFirst->getAngleAtNode(&n), bestSecond->getAngleAtNode(&n)) < 135;
515 if (isBent && hasTLS && !forceStraight) {
516 // redo but force straight computation
518 } else {
519 n.markBentPriority(isBent);
520 markBestParallel(n, bestFirst, bestSecond);
521 }
522}
523
524double
525NBEdgePriorityComputer::getScore(const NBEdge* e1, const NBEdge* e2, int minPrio, int maxPrio, int maxNumLanes, double maxSpeed) {
526 // normalize priorities to [0.1,1]
527 double normPrio1 = 1;
528 double normPrio2 = 1;
529 if (minPrio != maxPrio) {
530 normPrio1 = ((e1->getPriority() - minPrio) / (maxPrio - minPrio)) * 0.9 + 0.1;
531 normPrio2 = ((e2->getPriority() - minPrio) / (maxPrio - minPrio)) * 0.9 + 0.1;
532 }
533 return (normPrio1
534 * e1->getNumLanes() / maxNumLanes
535 * e1->getSpeed() / maxSpeed
536 * normPrio2
537 * e2->getNumLanes() / maxNumLanes
538 * e2->getSpeed() / maxSpeed);
539}
540
541void
543 // edges running parallel to the main direction should also be prioritised
544 const double a1 = bestFirst->getAngleAtNode(&n);
545 const double a2 = bestSecond == nullptr ? a1 : bestSecond->getAngleAtNode(&n);
546 SVCPermissions p1 = bestFirst->getPermissions();
547 SVCPermissions p2 = bestSecond == nullptr ? p1 : bestSecond->getPermissions();
548 for (NBEdge* e : n.getIncomingEdges()) {
549 // @note: this rule might also apply if there are common permissions but
550 // then we would not further rules to resolve the priority between the best edge and its parallel edge
551 SVCPermissions perm = e->getPermissions();
552 if (((GeomHelper::getMinAngleDiff(e->getAngleAtNode(&n), a1) < 10
553 || GeomHelper::getMinAngleDiff(e->getAngleAtNode(&n), a2) < 10))
554 && (p1 & perm) == 0 && (p2 & perm) == 0) {
555 e->setJunctionPriority(&n, 1);
556 }
557 }
558}
559
560
561NBEdge*
562NBEdgePriorityComputer::extractAndMarkFirst(NBNode& n, std::vector<NBEdge*>& s, int prio) {
563 if (s.size() == 0) {
564 return nullptr;
565 }
566 NBEdge* ret = s.front();
567 s.erase(s.begin());
568 ret->setJunctionPriority(&n, prio);
569 return ret;
570}
571
572
573bool
574NBEdgePriorityComputer::samePriority(const NBEdge* const e1, const NBEdge* const e2) {
575 if (e1 == e2) {
576 return true;
577 }
578 if (e1->getPriority() != e2->getPriority()) {
579 return false;
580 }
581 if ((int) e1->getSpeed() != (int) e2->getSpeed()) {
582 return false;
583 }
584 return (int) e1->getNumLanes() == (int) e2->getNumLanes();
585}
586
587
588bool
590 if (edges.size() < 2) {
591 return false;
592 }
593 int prio = edges[0] == excluded ? edges[1]->getPriority() : edges[0]->getPriority();
594 for (auto e : edges) {
595 if (e != excluded && e->getPriority() != prio) {
596 return true;
597 }
598 }
599 return false;
600}
601
602
604 // reorder based on getAngleAtNodeToCenter
605 myOrdering = ordering;
607 // let the first edge remain the first
608 rotate(myOrdering.begin(), std::find(myOrdering.begin(), myOrdering.end(), ordering.front()), myOrdering.end());
609}
610
611
612/****************************************************************************/
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:268
#define TL(string)
Definition: MsgHandler.h:284
#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:76
T MAX2(T a, T b)
Definition: StdDefs.h:82
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:4215
@ PRIORITY_ROAD
Definition: NBEdge.h:376
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:536
const PositionVector & getGeometry() const
Returns the geometry of the edge.
Definition: NBEdge.h:771
double getSpeed() const
Returns the speed allowed on this edge.
Definition: NBEdge.h:609
const std::string & getID() const
Definition: NBEdge.h:1515
bool isTurningDirectionAt(const NBEdge *const edge) const
Returns whether the given edge is the opposite direction to this edge.
Definition: NBEdge.cpp:3507
int getNumLanes() const
Returns the number of lanes.
Definition: NBEdge.h:510
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition: NBEdge.h:529
double getAngleAtNode(const NBNode *const node) const
Returns the angle of the edge's geometry at the given node.
Definition: NBEdge.cpp:2074
int getPriority() const
Returns the priority of the edge.
Definition: NBEdge.h:517
void setJunctionPriority(const NBNode *const node, int prio)
Sets the junction priority of the edge.
Definition: NBEdge.cpp:2058
EdgeVector getIncomingEdges() const
Returns the list of incoming edges unsorted.
Definition: NBEdge.cpp:1325
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:57
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:2306
bool isSimpleContinuation(bool checkLaneNumbers=true, bool checkWidth=false) const
check if node is a simple continuation
Definition: NBNode.cpp:504
bool myTypeWasGuessed
whether the node type was guessed rather than loaded
Definition: NBNode.h:962
SumoXMLNodeType myType
The type of the junction.
Definition: NBNode.h:912
EdgeVector myOutgoingEdges
Vector of outgoing edges.
Definition: NBNode.h:897
const EdgeVector & getIncomingEdges() const
Returns this node's incoming edges (The edges which yield in this node)
Definition: NBNode.h:266
const EdgeVector & getOutgoingEdges() const
Returns this node's outgoing edges (The edges which start at this node)
Definition: NBNode.h:271
EdgeVector myAllEdges
Vector of incoming and outgoing edges.
Definition: NBNode.h:900
bool isDistrict() const
check if node is a district
Definition: NBNode.cpp:2608
const Position & getPosition() const
Definition: NBNode.h:258
void removeTrafficLight(NBTrafficLightDefinition *tlDef)
Removes the given traffic light from this node.
Definition: NBNode.cpp:400
const EdgeVector & getEdges() const
Returns all edges which participate in this node (Edges that start or end at this node)
Definition: NBNode.h:276
void markBentPriority(bool isBent)
mark whether a priority road turns at this node
Definition: NBNode.h:817
bool geometryLike() const
whether this is structurally similar to a geometry node
Definition: NBNode.cpp:3595
bool isNearDistrict() const
@chech if node is near district
Definition: NBNode.cpp:2591
EdgeVector myIncomingEdges
Vector of incoming edges.
Definition: NBNode.h:894
bool isTLControlled() const
Returns whether this node is controlled by any tls.
Definition: NBNode.h:329
NBEdge * getOppositeIncoming(NBEdge *e) const
returns the opposite incoming edge of certain edge
Definition: NBNode.cpp:1825
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