Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
NBAlgorithms.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3// Copyright (C) 2012-2024 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 DEBUG_TURNAROUNDS
41#define DEBUGCOND (n.getID() == "C")
42//#define DEBUGCOND2(obj) (obj->getID() == "")
43#define DEBUGCOND2(obj) (true)
44
45// ===========================================================================
46// method definitions
47// ===========================================================================
48// ---------------------------------------------------------------------------
49// NBTurningDirectionsComputer
50// ---------------------------------------------------------------------------
51void
53 for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
54 computeTurnDirectionsForNode(i->second, warn);
55 }
56}
57
58void
60 const std::vector<NBEdge*>& incoming = node->getIncomingEdges();
61 const std::vector<NBEdge*>& outgoing = node->getOutgoingEdges();
62 // reset turning directions since this may be called multiple times
63 for (std::vector<NBEdge*>::const_iterator k = incoming.begin(); k != incoming.end(); ++k) {
64 (*k)->setTurningDestination(nullptr);
65 }
66 std::vector<Combination> combinations;
67 const bool geometryLike = node->geometryLike();
68 for (NBEdge* outedge : outgoing) {
69 for (NBEdge* e : incoming) {
70 // @todo: check whether NBHelpers::relAngle is properly defined and whether it should really be used, here
71 const double signedAngle = NBHelpers::normRelAngle(e->getAngleAtNode(node), outedge->getAngleAtNode(node));
72 if (signedAngle > 0 && signedAngle < 177 && e->getGeometry().back().distanceTo2D(outedge->getGeometry().front()) < POSITION_EPS) {
73 // backwards curving edges can only be turnaround when there are
74 // non-default endpoints
75#ifdef DEBUG_TURNAROUNDS
76 if (DEBUGCOND2(node)) {
77 std::cout << "incoming=" << e->getID() << " outgoing=" << outedge->getID() << " signedAngle=" << signedAngle << " skipped\n";
78 }
79#endif
80 continue;
81 }
82 double angle = fabs(signedAngle);
83#ifdef DEBUG_TURNAROUNDS
84 if (DEBUGCOND2(node)) {
85 std::cout << "incoming=" << e->getID() << " outgoing=" << outedge->getID() << " relAngle=" << NBHelpers::relAngle(e->getAngleAtNode(node), outedge->getAngleAtNode(node)) << "\n";
86 }
87#endif
88 const bool badPermissions = ((outedge->getPermissions() & e->getPermissions() & ~SVC_PEDESTRIAN) == 0
89 && !geometryLike
90 && outedge->getPermissions() != e->getPermissions());
91 if (e->getFromNode() == outedge->getToNode()
92 && (angle > 120 || e->getFromNode()->getPosition() == e->getToNode()->getPosition())
93 && !badPermissions) {
94 // they connect the same nodes; should be the turnaround direction
95 // we'll assign a maximum number
96 //
97 // @todo: indeed, we have observed some pathological intersections
98 // see "294831560" in OSM/adlershof. Here, several edges are connecting
99 // same nodes. We have to do the angle check before...
100 //
101 // @todo: and well, there are some other as well, see plain import
102 // of delphi_muenchen (elmar), intersection "59534191". Not that it would
103 // be realistic in any means; we will warn, here.
104 angle += 360;
105 }
106 if (angle < 160) {
107 if (angle > 135) {
108 // could be a turnaround with a green median island, look at
109 // angle further away from the junction
110 const double inFA = getFarAngleAtNode(e, node);
111 const double outFA = getFarAngleAtNode(outedge, node);
112 const double signedFarAngle = NBHelpers::normRelAngle(inFA, outFA);
113#ifdef DEBUG_TURNAROUNDS
114 if (DEBUGCOND2(node)) {
115 std::cout << " inFA=" << inFA << " outFA=" << outFA << " sFA=" << signedFarAngle << "\n";
116 }
117#endif
118 if (signedFarAngle > -160) {
119 continue;
120 }
121 } else {
122 continue;
123 }
124 }
125 if (badPermissions) {
126 // penalty
127 angle -= 90;
128 }
129 Combination c;
130 c.from = e;
131 c.to = outedge;
132 c.angle = angle;
133 combinations.push_back(c);
134 }
135 }
136 // sort combinations so that the ones with the highest angle are at the begin
137 std::sort(combinations.begin(), combinations.end(), combination_by_angle_sorter());
138 std::set<NBEdge*> seen;
139#ifdef DEBUG_TURNAROUNDS
140 if (DEBUGCOND2(node)) {
141 std::cout << "check combinations at " << node->getID() << "\n";
142 }
143#endif
144 for (std::vector<Combination>::const_iterator j = combinations.begin(); j != combinations.end(); ++j) {
145#ifdef DEBUG_TURNAROUNDS
146 if (DEBUGCOND2(node)) {
147 std::cout << " from=" << (*j).from->getID() << " to=" << (*j).to->getID() << " a=" << (*j).angle << "\n";
148 }
149#endif
150 if (seen.find((*j).from) != seen.end() || seen.find((*j).to) != seen.end()) {
151 // do not regard already set edges
152 if ((*j).angle > 360 && warn) {
153 WRITE_WARNINGF(TL("Ambiguity in turnarounds computation at junction '%'."), node->getID());
154 //std::cout << " already seen: " << toString(seen) << "\n";
155 warn = false;
156 }
157 continue;
158 }
159 // mark as seen
160 seen.insert((*j).from);
161 seen.insert((*j).to);
162 // set turnaround information
163 bool onlyPossible = (*j).from->getConnections().size() != 0 && !(*j).from->isConnectedTo((*j).to);
164#ifdef DEBUG_TURNAROUNDS
165 if (DEBUGCOND2(node)) {
166 std::cout << " setTurningDestination from=" << (*j).from->getID() << " to=" << (*j).to->getID() << " onlyPossible=" << onlyPossible << "\n";
167 }
168#endif
169 (*j).from->setTurningDestination((*j).to, onlyPossible);
170 }
171}
172
173
174double
176 Position atNode;
177 Position far;
178 double angle;
179 const NBEdge* next = e;
180 if (e->getToNode() == n) {
181 // search upstream
182 atNode = e->getGeometry().back();
183 while (dist > 0) {
184 const double length = next->getGeometry().length();
185 if (dist <= length) {
186 far = next->getGeometry().positionAtOffset(length - dist);
187 break;
188 } else {
189 far = next->getGeometry().front();
190 dist -= length;
191 if (next->getToNode()->getIncomingEdges().size() == 1) {
192 next = next->getToNode()->getIncomingEdges().front();
193 } else {
194 break;
195 }
196 }
197 }
198 angle = far.angleTo2D(atNode);
199 //std::cout << " e=" << e->getID() << " n=" << n->getID() << " far=" << far << " atNode=" << atNode << " a=" << RAD2DEG(angle) << "\n";
200 } else {
201 // search downstream
202 atNode = e->getGeometry().front();
203 while (dist > 0) {
204 const double length = next->getGeometry().length();
205 if (dist <= length) {
206 far = next->getGeometry().positionAtOffset(dist);
207 break;
208 } else {
209 far = next->getGeometry().back();
210 dist -= length;
211 if (next->getToNode()->getOutgoingEdges().size() == 1) {
212 next = next->getToNode()->getOutgoingEdges().front();
213 } else {
214 break;
215 }
216 }
217 }
218 angle = atNode.angleTo2D(far);
219 //std::cout << " e=" << e->getID() << " n=" << n->getID() << " atNode=" << atNode << " far=" << far << " a=" << RAD2DEG(angle) << "\n";
220 }
221 return GeomHelper::legacyDegree(angle);
222}
223
224
225// ---------------------------------------------------------------------------
226// NBNodesEdgesSorter
227// ---------------------------------------------------------------------------
228void
230 for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
231 i->second->sortEdges(useNodeShape);
232 }
233}
234
235
236void
238 const std::vector<NBEdge*>::iterator& i1,
239 const std::vector<NBEdge*>::iterator& i2) {
240 NBEdge* e1 = *i1;
241 NBEdge* e2 = *i2;
242 // @todo: The difference between "isTurningDirectionAt" and "isTurnaround"
243 // is not nice. Maybe we could get rid of it if we would always mark edges
244 // as turnarounds, even if they do not have to be added, as mentioned in
245 // notes on NBTurningDirectionsComputer::computeTurnDirectionsForNode
246 if (e2->getToNode() == n && e2->isTurningDirectionAt(e1)) {
247 std::swap(*i1, *i2);
248 }
249}
250
251
252// ---------------------------------------------------------------------------
253// NBNodeTypeComputer
254// ---------------------------------------------------------------------------
255void
257 validateRailCrossings(nc, tlc);
259 const double rightBeforeLeftSpeed = oc.getFloat("junctions.right-before-left.speed-threshold");
260 for (const auto& nodeIt : nc) {
261 NBNode* const n = nodeIt.second;
262 // the type may already be set from the data
264 n->myTypeWasGuessed = false;
265 continue;
266 }
267 // check whether the node was set to be unregulated by the user
268 if (oc.getBool("keep-nodes-unregulated") || oc.isInStringVector("keep-nodes-unregulated.explicit", n->getID())
269 || (oc.getBool("keep-nodes-unregulated.district-nodes") && (n->isNearDistrict() || n->isDistrict()))) {
271 continue;
272 }
273 // check whether the node is a waterway node. Set to unregulated by default
274 bool waterway = true;
275 for (NBEdge* e : n->getEdges()) {
276 if (!isWaterway(e->getPermissions())) {
277 waterway = false;
278 break;
279 }
280 }
281 if (waterway && (n->myType == SumoXMLNodeType::UNKNOWN || n->myType == SumoXMLNodeType::DEAD_END)) {
283 continue;
284 }
285
286 // check whether the junction is not a real junction
287 if (n->myIncomingEdges.size() == 1) {
289 continue;
290 }
291 // @todo "isSimpleContinuation" should be revalidated
292 if (n->isSimpleContinuation()) {
294 continue;
295 }
296 if (isRailwayNode(n)) {
297 // priority instead of unregulated to ensure that collisions can be detected
299 continue;
300 }
301 // determine the type
303 for (EdgeVector::const_iterator i = n->myIncomingEdges.begin(); i != n->myIncomingEdges.end(); i++) {
304 for (EdgeVector::const_iterator j = i + 1; j != n->myIncomingEdges.end(); j++) {
305 // @todo "getOppositeIncoming" should probably be refactored into something the edge knows
306 if (n->getOppositeIncoming(*j) == *i && n->myIncomingEdges.size() > 2) {
307 continue;
308 }
309 // @todo check against a legal document
310 // @todo figure out when SumoXMLNodeType::PRIORITY_STOP is appropriate
311 const double s1 = (*i)->getSpeed();
312 const double s2 = (*j)->getSpeed();
313 const int p1 = (*i)->getPriority();
314 const int p2 = (*j)->getPriority();
315 if (fabs(s1 - s2) > (9.5 / 3.6) || MAX2(s1, s2) >= rightBeforeLeftSpeed || p1 != p2) {
317 break;
318 }
319 }
320 }
321 // save type
322 n->myType = type;
323 n->myTypeWasGuessed = true;
324 }
325}
326
327
328void
330 for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
331 NBNode* n = (*i).second;
333 // check if it really is a rail crossing
334 int numRailway = 0;
335 int numNonRailIn = 0;
336 int numNonRailOut = 0;
337 std::set<const NBNode*> nonRailNodes;
338 int numNonRailwayNonPed = 0;
339 for (NBEdge* e : n->getIncomingEdges()) {
340 if ((e->getPermissions() & ~SVC_RAIL_CLASSES) != 0) {
341 numNonRailIn += 1;
342 if (e->getPermissions() != SVC_PEDESTRIAN) {
343 numNonRailwayNonPed++;
344 }
345 nonRailNodes.insert(e->getFromNode());
346 } else if ((e->getPermissions() & SVC_RAIL_CLASSES) != 0) {
347 numRailway++;
348 }
349 }
350 for (NBEdge* e : n->getOutgoingEdges()) {
351 if ((e->getPermissions() & ~SVC_RAIL_CLASSES) != 0) {
352 numNonRailOut += 1;
353 nonRailNodes.insert(e->getToNode());
354 }
355 }
356 if (numNonRailIn == 0 || numNonRailOut == 0 || numRailway == 0) {
357 // not a crossing (maybe unregulated or rail_signal)
358 WRITE_WARNINGF(TL("Converting invalid rail_crossing to priority junction '%'."), n->getID());
360 } else if (numNonRailwayNonPed > 2 || nonRailNodes.size() > 2) {
361 // does not look like a rail crossing (roads in conflict). maybe a traffic light?
362 WRITE_WARNINGF(TL("Converting invalid rail_crossing to traffic_light at junction '%'."), n->getID());
364 NBTrafficLightDefinition* tlDef = new NBOwnTLDef(n->getID(), n, 0, type);
366 if (!tlc.insert(tlDef)) {
367 // actually, nothing should fail here
368 n->removeTrafficLight(tlDef);
370 delete tlDef;
371 WRITE_WARNINGF(TL("Could not allocate tls '%'."), n->getID());
372 }
373 }
374 }
375 }
376}
377
378
379bool
381 bool hasRailway = false;
382 for (NBEdge* e : n->getIncomingEdges()) {
383 if ((e->getPermissions() & ~(SVC_RAIL_CLASSES | SVC_TAXI)) != 0) {
384 return false;
385 } else if ((e->getPermissions() & SVC_RAIL_CLASSES) != 0) {
386 hasRailway = true;
387 }
388 }
389 return hasRailway;
390}
391
392// ---------------------------------------------------------------------------
393// NBEdgePriorityComputer
394// ---------------------------------------------------------------------------
395void
397 for (const auto& node : nc) {
398 // preset all junction's edge priorities to zero
399 for (NBEdge* const edge : node.second->myAllEdges) {
400 edge->setJunctionPriority(node.second, NBEdge::JunctionPriority::MINOR_ROAD);
401 }
402 node.second->markBentPriority(false);
403 // check if the junction is not a real junction
404 if (node.second->myIncomingEdges.size() == 1 && node.second->myOutgoingEdges.size() == 1) {
405 continue;
406 }
407 // compute the priorities on junction when needed
408 if (node.second->getType() != SumoXMLNodeType::RIGHT_BEFORE_LEFT
409 && node.second->getType() != SumoXMLNodeType::LEFT_BEFORE_RIGHT
410 && node.second->getType() != SumoXMLNodeType::ALLWAY_STOP
411 && node.second->getType() != SumoXMLNodeType::NOJUNCTION) {
412 if (node.second->getRightOfWay() == RightOfWay::EDGEPRIORITY) {
413 for (NBEdge* e : node.second->getIncomingEdges()) {
414 e->setJunctionPriority(node.second, e->getPriority());
415 }
416 } else {
417 setPriorityJunctionPriorities(*node.second);
418 }
419 }
420 }
421}
422
423
424void
426 if (n.myIncomingEdges.size() == 0 || n.myOutgoingEdges.size() == 0) {
427 return;
428 }
429 int minPrio = std::numeric_limits<int>::max();
430 int maxPrio = -std::numeric_limits<int>::max();
431 int maxNumLanes = -std::numeric_limits<int>::max();
432 double maxSpeed = -std::numeric_limits<double>::max();
433 if (forceStraight) {
434 // called a second time, preset all junction's edge priorities to zero
435 for (NBEdge* const edge : n.myAllEdges) {
436 edge->setJunctionPriority(&n, NBEdge::JunctionPriority::MINOR_ROAD);
437 minPrio = MIN2(minPrio, edge->getPriority());
438 maxPrio = MAX2(maxPrio, edge->getPriority());
439 maxNumLanes = MAX2(maxNumLanes, edge->getNumLanes());
440 maxSpeed = MAX2(maxSpeed, edge->getSpeed());
441 }
442 }
443 EdgeVector incoming = n.myIncomingEdges;
444 EdgeVector outgoing = n.myOutgoingEdges;
445 // what we do want to have is to extract the pair of roads that are
446 // the major roads for this junction
447 // let's get the list of incoming edges with the highest priority
448 std::sort(incoming.begin(), incoming.end(), NBContHelper::edge_by_priority_sorter());
449 EdgeVector bestIncoming;
450 NBEdge* bestIn = incoming[0];
451 while (incoming.size() > 0 && (forceStraight || samePriority(bestIn, incoming[0]))) {
452 bestIncoming.push_back(*incoming.begin());
453 incoming.erase(incoming.begin());
454 }
455 // now, let's get the list of best outgoing
456 assert(outgoing.size() != 0);
457 sort(outgoing.begin(), outgoing.end(), NBContHelper::edge_by_priority_sorter());
458 EdgeVector bestOutgoing;
459 const NBEdge* const firstOut = outgoing[0];
460 while (outgoing.size() > 0 && (forceStraight || samePriority(firstOut, outgoing[0]))) { //->getPriority()==best->getPriority())
461 bestOutgoing.push_back(*outgoing.begin());
462 outgoing.erase(outgoing.begin());
463 }
464 // special case: user input makes mainDirection unambiguous
465 const bool mainDirectionExplicit = (
466 bestIncoming.size() == 1 && n.myIncomingEdges.size() <= 2
467 && (incoming.size() == 0 || bestIncoming[0]->getPriority() > incoming[0]->getPriority())
468 && bestOutgoing.size() == 1 && n.myOutgoingEdges.size() <= 2
469 && (outgoing.size() == 0 || bestOutgoing[0]->getPriority() > outgoing[0]->getPriority())
470 && !bestIncoming[0]->isTurningDirectionAt(bestOutgoing[0]));
471 // now, let's compute for each of the best incoming edges
472 // the incoming which is most opposite
473 // the outgoing which is most opposite
474 EdgeVector::iterator i;
475 std::map<NBEdge*, NBEdge*> counterIncomingEdges;
476 std::map<NBEdge*, NBEdge*> counterOutgoingEdges;
477 incoming = n.myIncomingEdges;
478 outgoing = n.myOutgoingEdges;
479 for (i = bestIncoming.begin(); i != bestIncoming.end(); ++i) {
480 std::sort(incoming.begin(), incoming.end(), NBContHelper::edge_opposite_direction_sorter(*i, &n, !forceStraight));
481 counterIncomingEdges[*i] = *incoming.begin();
482 std::sort(outgoing.begin(), outgoing.end(), NBContHelper::edge_opposite_direction_sorter(*i, &n, !forceStraight));
483 counterOutgoingEdges[*i] = *outgoing.begin();
484 }
485#ifdef DEBUG_SETPRIORITIES
486 if (DEBUGCOND) {
487 std::map<std::string, std::string> tmp1;
488 for (auto item : counterIncomingEdges) {
489 tmp1[item.first->getID()] = item.second->getID();
490 }
491 std::map<std::string, std::string> tmp2;
492 for (auto item : counterOutgoingEdges) {
493 tmp2[item.first->getID()] = item.second->getID();
494 }
495 std::cout << "n=" << n.getID() << " bestIn=" << bestIn->getID() << " bestOut=" << toString(bestOutgoing)
496 << " counterBest=" << counterIncomingEdges.find(bestIncoming[0])->second->getID()
497 << " mainExplicit=" << mainDirectionExplicit
498 << " forceStraight=" << forceStraight
499 << "\n bestIncoming=" << toString(bestIncoming) << " allIncoming=" << toString(incoming)
500 << "\n bestOutgoing=" << toString(bestOutgoing) << " allOutgoing=" << toString(outgoing)
501 << "\n counterIncomingEdges=" << toString(tmp1)
502 << "\n counterOutgoingEdges=" << toString(tmp2)
503 << "\n";
504 }
505#endif
506 // at a tls junction we must prevent an underlying bent-priority layout
507 // because that would lead to invalid right-of-way rules for an oncoming
508 // tls layout (but not vice versa). See #7764
509 const bool hasTLS = n.isTLControlled();
510 // ok, let's try
511 // 1) there is one best incoming road
512 if (bestIncoming.size() == 1) {
513 // let's mark this road as the best
514 NBEdge* best1 = extractAndMarkFirst(n, bestIncoming);
515 if (!mainDirectionExplicit && counterIncomingEdges.find(best1) != counterIncomingEdges.end()) {
516 // ok, look, what we want is the opposite of the straight continuation edge
517 // but, what if such an edge does not exist? By now, we'll determine it
518 // geometrically
519 NBEdge* s = counterIncomingEdges.find(best1)->second;
520 const double minAngleDiff = GeomHelper::getMinAngleDiff(best1->getAngleAtNode(&n), s->getAngleAtNode(&n));
521 if (minAngleDiff > 180 - 45
522 || (minAngleDiff > 75 && s->getPriority() == best1->getPriority() && hasDifferentPriorities(incoming, best1))) {
524 }
525 }
526 markBestParallel(n, best1, nullptr);
527 assert(bestOutgoing.size() != 0);
528 // mark the best outgoing as the continuation
529 sort(bestOutgoing.begin(), bestOutgoing.end(), NBContHelper::edge_similar_direction_sorter(best1));
530 // assign extra priority if the priorities are unambiguous (regardless of geometry)
531 NBEdge* bestOut = extractAndMarkFirst(n, bestOutgoing);
532 if (!mainDirectionExplicit && counterOutgoingEdges.find(bestOut) != counterOutgoingEdges.end()) {
533 NBEdge* s = counterOutgoingEdges.find(bestOut)->second;
534 if (GeomHelper::getMinAngleDiff(bestOut->getAngleAtNode(&n), s->getAngleAtNode(&n)) > 180 - 45) {
535 s->setJunctionPriority(&n, 1);
536 }
537 }
538 const bool isBent = n.getDirection(best1, bestOut) != LinkDirection::STRAIGHT;
539#ifdef DEBUG_SETPRIORITIES
540 if (DEBUGCOND) {
541 std::cout << " best1=" << best1->getID() << " bestOut=" << bestOut->getID() << " bestOutgoing=" << toString(bestOutgoing) << " mainDirectionExplicit=" << mainDirectionExplicit << " isBent=" << isBent << "\n";
542 }
543#endif
544 if (isBent && hasTLS && !forceStraight) {
545 // redo but force straight computation
547 } else {
548 n.markBentPriority(isBent);
549 }
550 return;
551 }
552
553 // ok, what we want to do in this case is to determine which incoming
554 // has the best continuation...
555 // This means, when several incoming roads have the same priority,
556 // we want a (any) straight connection to be more priorised than a turning
557 double bestAngle = -1;
558 NBEdge* bestFirst = nullptr;
559 NBEdge* bestSecond = nullptr;
560 for (i = bestIncoming.begin(); i != bestIncoming.end(); ++i) {
561 EdgeVector::iterator j;
562 NBEdge* t1 = *i;
563 double angle1 = t1->getAngleAtNode(&n) + 180;
564 if (angle1 >= 360) {
565 angle1 -= 360;
566 }
567 for (j = i + 1; j != bestIncoming.end(); ++j) {
568 NBEdge* t2 = *j;
569 double angle2 = t2->getAngleAtNode(&n) + 180;
570 if (angle2 >= 360) {
571 angle2 -= 360;
572 }
573 double score = forceStraight ? getScore(t1, t2, minPrio, maxPrio, maxNumLanes, maxSpeed) : 0;
574 double angle = GeomHelper::getMinAngleDiff(angle1, angle2) + 45 * score;
575 if (angle > bestAngle) {
576 //if (forceStraight) std::cout << " node=" << n.getID() << " t1=" << t1->getID() << " t2=" << t2->getID() << " angle=" << angle << " bestAngle=" << bestAngle << " score=" << score << " minPrio=" << minPrio << " maxPrio=" << maxPrio << "\n";
577 bestAngle = MAX2(angle, bestAngle);
578 bestFirst = *i;
579 bestSecond = *j;
580 }
581 }
582 }
583 bestFirst->setJunctionPriority(&n, 1);
584 sort(bestOutgoing.begin(), bestOutgoing.end(), NBContHelper::edge_similar_direction_sorter(bestFirst));
585#ifdef DEBUG_SETPRIORITIES
586 if (DEBUGCOND) {
587 std::cout << " bestFirst=" << bestFirst->getID() << " bestOutgoingFirst=" << toString(bestOutgoing) << "\n";
588 }
589#endif
590 if (bestOutgoing.size() != 0) {
591 extractAndMarkFirst(n, bestOutgoing);
592 }
593 bestSecond->setJunctionPriority(&n, 1);
594 sort(bestOutgoing.begin(), bestOutgoing.end(), NBContHelper::edge_similar_direction_sorter(bestSecond));
595#ifdef DEBUG_SETPRIORITIES
596 if (DEBUGCOND) {
597 std::cout << " bestSecond=" << bestSecond->getID() << " bestOutgoingSecond=" << toString(bestOutgoing) << "\n";
598 }
599#endif
600 if (bestOutgoing.size() != 0) {
601 extractAndMarkFirst(n, bestOutgoing);
602 }
603 const bool isBent = GeomHelper::getMinAngleDiff(bestFirst->getAngleAtNode(&n), bestSecond->getAngleAtNode(&n)) < 135;
604 if (isBent && hasTLS && !forceStraight) {
605 // redo but force straight computation
607 } else {
608 n.markBentPriority(isBent);
609 markBestParallel(n, bestFirst, bestSecond);
610 }
611}
612
613double
614NBEdgePriorityComputer::getScore(const NBEdge* e1, const NBEdge* e2, int minPrio, int maxPrio, int maxNumLanes, double maxSpeed) {
615 // normalize priorities to [0.1,1]
616 double normPrio1 = 1;
617 double normPrio2 = 1;
618 if (minPrio != maxPrio) {
619 normPrio1 = ((e1->getPriority() - minPrio) / (maxPrio - minPrio)) * 0.9 + 0.1;
620 normPrio2 = ((e2->getPriority() - minPrio) / (maxPrio - minPrio)) * 0.9 + 0.1;
621 }
622 return (normPrio1
623 * e1->getNumLanes() / maxNumLanes
624 * e1->getSpeed() / maxSpeed
625 * normPrio2
626 * e2->getNumLanes() / maxNumLanes
627 * e2->getSpeed() / maxSpeed);
628}
629
630void
632 // edges running parallel to the main direction should also be prioritised
633 const double a1 = bestFirst->getAngleAtNode(&n);
634 const double a2 = bestSecond == nullptr ? a1 : bestSecond->getAngleAtNode(&n);
635 SVCPermissions p1 = bestFirst->getPermissions();
636 SVCPermissions p2 = bestSecond == nullptr ? p1 : bestSecond->getPermissions();
637 for (NBEdge* e : n.getIncomingEdges()) {
638 // @note: this rule might also apply if there are common permissions but
639 // then we would not further rules to resolve the priority between the best edge and its parallel edge
640 SVCPermissions perm = e->getPermissions();
641 if (((GeomHelper::getMinAngleDiff(e->getAngleAtNode(&n), a1) < 10
642 || GeomHelper::getMinAngleDiff(e->getAngleAtNode(&n), a2) < 10))
643 && (p1 & perm) == 0 && (p2 & perm) == 0) {
644 e->setJunctionPriority(&n, 1);
645 }
646 }
647}
648
649
650NBEdge*
651NBEdgePriorityComputer::extractAndMarkFirst(NBNode& n, std::vector<NBEdge*>& s, int prio) {
652 if (s.size() == 0) {
653 return nullptr;
654 }
655 NBEdge* ret = s.front();
656 s.erase(s.begin());
657 ret->setJunctionPriority(&n, prio);
658 return ret;
659}
660
661
662bool
663NBEdgePriorityComputer::samePriority(const NBEdge* const e1, const NBEdge* const e2) {
664 if (e1 == e2) {
665 return true;
666 }
667 if (e1->getPriority() != e2->getPriority()) {
668 return false;
669 }
670 if ((int) e1->getSpeed() != (int) e2->getSpeed()) {
671 return false;
672 }
673 return (int) e1->getNumLanes() == (int) e2->getNumLanes();
674}
675
676
677bool
679 if (edges.size() < 2) {
680 return false;
681 }
682 int prio = edges[0] == excluded ? edges[1]->getPriority() : edges[0]->getPriority();
683 for (auto e : edges) {
684 if (e != excluded && e->getPriority() != prio) {
685 return true;
686 }
687 }
688 return false;
689}
690
691
693 // reorder based on getAngleAtNodeToCenter
694 myOrdering = ordering;
696 // let the first edge remain the first
697 rotate(myOrdering.begin(), std::find(myOrdering.begin(), myOrdering.end(), ordering.front()), myOrdering.end());
698}
699
700
701/****************************************************************************/
#define DEBUGCOND2(LANE)
#define DEBUGCOND(PED)
#define WRITE_WARNINGF(...)
Definition MsgHandler.h:296
#define TL(string)
Definition MsgHandler.h:315
std::vector< NBEdge * > EdgeVector
container for (sorted) edges
Definition NBCont.h:42
bool isWaterway(SVCPermissions permissions)
Returns whether an edge with the given permissions is a waterway edge.
long long int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
@ SVC_RAIL_CLASSES
classes which drive on tracks
@ SVC_TAXI
vehicle is a taxi
@ SVC_PEDESTRIAN
pedestrian
@ 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 legacyDegree(const double angle, const bool positive=false)
static double getMinAngleDiff(double angle1, double angle2)
Returns the minimum distance (clockwise/counter-clockwise) between both angles.
Class to sort edges by their angle in relation to the given edge.
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:4378
@ PRIORITY_ROAD
Definition NBEdge.h:386
@ MINOR_ROAD
Definition NBEdge.h:385
NBNode * getToNode() const
Returns the destination node of the edge.
Definition NBEdge.h:546
const PositionVector & getGeometry() const
Returns the geometry of the edge.
Definition NBEdge.h:783
double getSpeed() const
Returns the speed allowed on this edge.
Definition NBEdge.h:619
const std::string & getID() const
Definition NBEdge.h:1528
bool isTurningDirectionAt(const NBEdge *const edge) const
Returns whether the given edge is the opposite direction to this edge.
Definition NBEdge.cpp:3664
int getNumLanes() const
Returns the number of lanes.
Definition NBEdge.h:520
double getAngleAtNode(const NBNode *const node) const
Returns the angle of the edge's geometry at the given node.
Definition NBEdge.cpp:2158
int getPriority() const
Returns the priority of the edge.
Definition NBEdge.h:527
void setJunctionPriority(const NBNode *const node, int prio)
Sets the junction priority of the edge.
Definition NBEdge.cpp:2142
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 relAngle(double angle1, double angle2)
computes the relative angle between the two angles
Definition NBHelpers.cpp:45
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:2358
bool isSimpleContinuation(bool checkLaneNumbers=true, bool checkWidth=false) const
check if node is a simple continuation
Definition NBNode.cpp:510
bool myTypeWasGuessed
whether the node type was guessed rather than loaded
Definition NBNode.h:978
SumoXMLNodeType myType
The type of the junction.
Definition NBNode.h:928
EdgeVector myOutgoingEdges
Vector of outgoing edges.
Definition NBNode.h:913
const EdgeVector & getIncomingEdges() const
Returns this node's incoming edges (The edges which yield in this node)
Definition NBNode.h:268
const EdgeVector & getOutgoingEdges() const
Returns this node's outgoing edges (The edges which start at this node)
Definition NBNode.h:273
EdgeVector myAllEdges
Vector of incoming and outgoing edges.
Definition NBNode.h:916
bool isDistrict() const
check if node is a district
Definition NBNode.cpp:2662
void removeTrafficLight(NBTrafficLightDefinition *tlDef)
Removes the given traffic light from this node.
Definition NBNode.cpp:406
const EdgeVector & getEdges() const
Returns all edges which participate in this node (Edges that start or end at this node)
Definition NBNode.h:278
void markBentPriority(bool isBent)
mark whether a priority road turns at this node
Definition NBNode.h:830
bool geometryLike() const
whether this is structurally similar to a geometry node
Definition NBNode.cpp:3783
bool isNearDistrict() const
@chech if node is near district
Definition NBNode.cpp:2645
EdgeVector myIncomingEdges
Vector of incoming edges.
Definition NBNode.h:910
bool isTLControlled() const
Returns whether this node is controlled by any tls.
Definition NBNode.h:331
NBEdge * getOppositeIncoming(NBEdge *e) const
returns the opposite incoming edge of certain edge
Definition NBNode.cpp:1868
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.
static double getFarAngleAtNode(const NBEdge *e, const NBNode *n, double dist=50)
compute angle to junction at a point further away
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.
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.
A point in 2D or 3D with translation and scaling methods.
Definition Position.h:37
double angleTo2D(const Position &other) const
returns the angle in the plane of the vector pointing from here to the other position (in radians bet...
Definition Position.h:286
double length() const
Returns the length.
Position positionAtOffset(double pos, double lateralOffset=0) const
Returns the position at the given length.
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.