Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
NBEdgeCont.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3// Copyright (C) 2001-2026 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/****************************************************************************/
21// Storage for edges, including some functionality operating on multiple edges
22/****************************************************************************/
23#include <config.h>
24
25#include <vector>
26#include <string>
27#include <cassert>
28#include <algorithm>
29#include <cmath>
30#include <utils/geom/Boundary.h>
43#include "NBNetBuilder.h"
44#include "NBEdgeCont.h"
45#include "NBNodeCont.h"
46#include "NBPTLineCont.h"
47#include "NBPTStop.h"
48#include "NBHelpers.h"
49#include "NBCont.h"
51#include "NBDistrictCont.h"
52#include "NBTypeCont.h"
53
54#define JOIN_TRAM_MAX_ANGLE 10
55#define JOIN_TRAM_MIN_LENGTH 3
56
57//#define DEBUG_GUESS_ROUNDABOUT
58//#define DEBUG_JOIN_TRAM
59#define DEBUG_EDGE_ID ""
60
61// ===========================================================================
62// method definitions
63// ===========================================================================
65 myTypeCont(tc),
66 myVehicleClasses2Keep(0),
67 myVehicleClasses2Remove(0),
68 myNeedGeoTransformedPruningBoundary(false) {
69}
70
71
75
76
77void
79 // set edges dismiss/accept options
80 myEdgesMinSpeed = oc.getFloat("keep-edges.min-speed");
81 myRemoveEdgesAfterLoading = oc.exists("keep-edges.postload") && oc.getBool("keep-edges.postload");
82 // we possibly have to load the edges to keep/remove
83 if (oc.isSet("keep-edges.input-file")) {
84 NBHelpers::loadEdgesFromFile(oc.getString("keep-edges.input-file"), myEdges2Keep);
85 }
86 if (oc.isSet("remove-edges.input-file")) {
87 NBHelpers::loadEdgesFromFile(oc.getString("remove-edges.input-file"), myEdges2Remove);
88 }
89 if (oc.isSet("keep-edges.explicit")) {
90 const std::vector<std::string> edges = oc.getStringVector("keep-edges.explicit");
91 myEdges2Keep.insert(edges.begin(), edges.end());
92 }
93 if (oc.isSet("remove-edges.explicit")) {
94 const std::vector<std::string> edges = oc.getStringVector("remove-edges.explicit");
95 myEdges2Remove.insert(edges.begin(), edges.end());
96 }
97 if (oc.exists("keep-edges.by-vclass") && oc.isSet("keep-edges.by-vclass")) {
98 myVehicleClasses2Keep = parseVehicleClasses(oc.getStringVector("keep-edges.by-vclass"));
99 }
100 if (oc.exists("remove-edges.by-vclass") && oc.isSet("remove-edges.by-vclass")) {
101 myVehicleClasses2Remove = parseVehicleClasses(oc.getStringVector("remove-edges.by-vclass"));
102 }
103 if (oc.exists("keep-edges.by-type") && oc.isSet("keep-edges.by-type")) {
104 const std::vector<std::string> types = oc.getStringVector("keep-edges.by-type");
105 myTypes2Keep.insert(types.begin(), types.end());
106 }
107 if (oc.exists("remove-edges.by-type") && oc.isSet("remove-edges.by-type")) {
108 const std::vector<std::string> types = oc.getStringVector("remove-edges.by-type");
109 myTypes2Remove.insert(types.begin(), types.end());
110 }
111
112 if (oc.isSet("keep-edges.in-boundary") || oc.isSet("keep-edges.in-geo-boundary")) {
113
114 std::string polyPlainString = oc.getValueString(oc.isSet("keep-edges.in-boundary") ?
115 "keep-edges.in-boundary" : "keep-edges.in-geo-boundary");
116 // try interpreting the boundary like shape attribute with spaces
117 bool ok = true;
118 PositionVector boundaryShape = GeomConvHelper::parseShapeReporting(polyPlainString, "pruning-boundary", 0, ok, false, false);
119 if (ok) {
120 if (boundaryShape.size() < 2) {
121 throw ProcessError(TL("Invalid boundary: need at least 2 coordinates"));
122 } else if (boundaryShape.size() == 2) {
123 // prunning boundary (box)
124 myPruningBoundary.push_back(boundaryShape[0]);
125 myPruningBoundary.push_back(Position(boundaryShape[1].x(), boundaryShape[0].y()));
126 myPruningBoundary.push_back(boundaryShape[1]);
127 myPruningBoundary.push_back(Position(boundaryShape[0].x(), boundaryShape[1].y()));
128 } else {
129 myPruningBoundary = boundaryShape;
130 }
131 } else {
132 // maybe positions are separated by ',' instead of ' '
133 std::vector<std::string> polyS = oc.getStringVector(oc.isSet("keep-edges.in-boundary") ?
134 "keep-edges.in-boundary" : "keep-edges.in-geo-boundary");
135 std::vector<double> poly;
136 for (std::vector<std::string>::iterator i = polyS.begin(); i != polyS.end(); ++i) {
137 poly.push_back(StringUtils::toDouble((*i))); // !!! may throw something anyhow...
138 }
139 if (poly.size() < 4) {
140 throw ProcessError(TL("Invalid boundary: need at least 2 coordinates"));
141 } else if (poly.size() % 2 != 0) {
142 throw ProcessError(TL("Invalid boundary: malformed coordinate"));
143 } else if (poly.size() == 4) {
144 // prunning boundary (box)
145 myPruningBoundary.push_back(Position(poly[0], poly[1]));
146 myPruningBoundary.push_back(Position(poly[2], poly[1]));
147 myPruningBoundary.push_back(Position(poly[2], poly[3]));
148 myPruningBoundary.push_back(Position(poly[0], poly[3]));
149 } else {
150 for (std::vector<double>::iterator j = poly.begin(); j != poly.end();) {
151 double x = *j++;
152 double y = *j++;
153 myPruningBoundary.push_back(Position(x, y));
154 }
155 }
156 }
157 myNeedGeoTransformedPruningBoundary = oc.isSet("keep-edges.in-geo-boundary");
158 }
159}
160
161
162void
164 for (const auto& i : myEdges) {
165 delete i.second;
166 }
167 myEdges.clear();
168 for (const auto& i : myExtractedEdges) {
169 delete i.second;
170 }
171 myExtractedEdges.clear();
172 for (NBEdge* const e : myEdgeCemetery) {
173 delete e;
174 }
175 myEdgeCemetery.clear();
176}
177
178
179
180// ----- edge access methods
181bool
182NBEdgeCont::insert(NBEdge* edge, bool ignorePrunning) {
183 if (myEdges.count(edge->getID()) != 0) {
184 return false;
185 }
186 if (!ignorePrunning && ignoreFilterMatch(edge)) {
187 edge->getFromNode()->removeEdge(edge);
188 edge->getToNode()->removeEdge(edge);
189 myIgnoredEdges.insert(edge->getID());
190 delete edge;
191 } else {
193 if (oc.exists("dismiss-vclasses") && oc.getBool("dismiss-vclasses")) {
195 }
196 myEdges[edge->getID()] = edge;
197 }
198 return true;
199}
200
201
202bool
205 // check whether the edge is a named edge to keep
206 if (myEdges2Keep.size() != 0) {
207 if (myEdges2Keep.count(edge->getID()) == 0) {
208 // explicit whitelisting may be combined additively with other filters
210 && myTypes2Keep.size() == 0 && myTypes2Remove.size() == 0
211 && myPruningBoundary.size() == 0) {
212 return true;
213 }
214 } else {
215 // explicit whitelisting overrides other filters
216 return false;
217 }
218 }
219 // remove edges which allow a speed below a set one (set using "keep-edges.min-speed")
220 if (edge->getSpeed() < myEdgesMinSpeed) {
221 return true;
222 }
223 // check whether the edge shall be removed because it does not allow any of the wished classes
224 if (myVehicleClasses2Keep != 0 && (myVehicleClasses2Keep & edge->getPermissions()) == 0) {
225 return true;
226 }
227 // check whether the edge shall be removed due to allowing unwished classes only
229 return true;
230 }
231 }
232 // check whether the edge is a named edge to remove
233 if (myEdges2Remove.size() != 0) {
234 if (myEdges2Remove.count(edge->getID()) != 0) {
235 return true;
236 }
237 }
238 // check whether the edge shall be removed because it does not have one of the requested types
239 if (myTypes2Keep.size() != 0) {
240 if (myTypes2Keep.count(edge->getTypeID()) == 0) {
241 return true;
242 }
243 }
244 // check whether the edge shall be removed because it has one of the forbidden types
245 if (myTypes2Remove.size() != 0) {
246 if (myTypes2Remove.count(edge->getTypeID()) > 0) {
247 return true;
248 }
249 }
250 // check whether the edge is within the pruning boundary
251 if (myPruningBoundary.size() != 0) {
253 if (GeoConvHelper::getProcessing().usingGeoProjection()) {
255 } else if (GeoConvHelper::getLoaded().usingGeoProjection()) {
256 // XXX what if input file with different projections are loaded?
257 for (int i = 0; i < (int) myPruningBoundary.size(); i++) {
259 }
260 } else {
261 WRITE_ERROR(TL("Cannot prune edges using a geo-boundary because no projection has been loaded"));
262 }
264 }
265 if (!(edge->getGeometry().getBoxBoundary().grow(POSITION_EPS).overlapsWith(myPruningBoundary))) {
266 return true;
267 } else if (!(edge->getGeometry().partialWithin(myPruningBoundary, 2 * POSITION_EPS) || edge->getGeometry().intersects(myPruningBoundary))) {
268 // a more detailed check is necessary because the bounding box may be much bigger than the edge
269 // @note: overlapsWith implicitly closes the edge shape but this is not wanted here
270 return true;
271 }
272 }
274 return true;
275 }
276 return false;
277}
278
279
280NBEdge*
281NBEdgeCont::retrieve(const std::string& id, bool retrieveExtracted) const {
282 EdgeCont::const_iterator i = myEdges.find(id);
283 if (i == myEdges.end()) {
284 if (retrieveExtracted) {
285 i = myExtractedEdges.find(id);
286 if (i == myExtractedEdges.end()) {
287 return nullptr;
288 }
289 } else {
290 return nullptr;
291 }
292 }
293 return (*i).second;
294}
295
296// FIXME: This can't work
297/*
298NBEdge*
299NBEdgeCont::retrievePossiblySplit(const std::string& id, bool downstream) const {
300 NBEdge* edge = retrieve(id);
301 if (edge == 0) {
302 return 0;
303 }
304 const EdgeVector* candidates = downstream ? &edge->getToNode()->getOutgoingEdges() : &edge->getFromNode()->getIncomingEdges();
305 while (candidates->size() == 1) {
306 const std::string& nextID = candidates->front()->getID();
307 if (nextID.find(id) != 0 || nextID.size() <= id.size() + 1 || (nextID[id.size()] != '.' && nextID[id.size()] != '-')) {
308 break;
309 }
310 edge = candidates->front();
311 candidates = downstream ? &edge->getToNode()->getOutgoingEdges() : &edge->getFromNode()->getIncomingEdges();
312 }
313 return edge;
314}*/
315
316NBEdge*
317NBEdgeCont::retrievePossiblySplit(const std::string& id, bool downstream) const {
318 NBEdge* edge = retrieve(id);
319 if (edge != nullptr) {
320 return edge;
321 }
322 // NOTE: (TODO) for multiply split edges (e.g. 15[0][0]) one could try recursion
323 if ((retrieve(id + "[0]") != nullptr) && (retrieve(id + "[1]") != nullptr)) {
324 // Edge was split during the netbuilding process
325 if (downstream) {
326 return retrieve(id + "[1]");
327 } else {
328 return retrieve(id + "[0]");
329 }
330 }
331 return edge;
332}
333
334
335NBEdge*
336NBEdgeCont::retrievePossiblySplit(const std::string& id, const std::string& hint, bool incoming) const {
337 // try to retrieve using the given name (iterative)
338 NBEdge* edge = retrieve(id);
339 if (edge != nullptr) {
340 return edge;
341 }
342 // now, we did not find it; we have to look over all possibilities
343 EdgeVector hints;
344 // check whether at least the hint was not splitted
345 NBEdge* hintedge = retrieve(hint);
346 if (hintedge == nullptr) {
347 hints = getGeneratedFrom(hint);
348 } else {
349 hints.push_back(hintedge);
350 }
351 EdgeVector candidates = getGeneratedFrom(id);
352 for (const NBEdge* const currHint : hints) {
353 for (NBEdge* const poss_searched : candidates) {
354 const NBNode* const node = incoming ? poss_searched->myTo : poss_searched->myFrom;
355 const EdgeVector& cont = incoming ? node->getOutgoingEdges() : node->getIncomingEdges();
356 if (find(cont.begin(), cont.end(), currHint) != cont.end()) {
357 return poss_searched;
358 }
359 }
360 }
361 return nullptr;
362}
363
364
365NBEdge*
366NBEdgeCont::retrievePossiblySplit(const std::string& id, double pos) const {
367 // check whether the edge was not split, yet
368 NBEdge* edge = retrieve(id);
369 if (edge != nullptr) {
370 return edge;
371 }
372 int maxLength = 0;
373 std::string tid = id + "[";
374 for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
375 if ((*i).first.find(tid) == 0) {
376 maxLength = MAX2(maxLength, (int)(*i).first.length());
377 }
378 }
379 // find the part of the edge which matches the position
380 double seen = 0;
381 std::vector<std::string> names;
382 names.push_back(id + "[1]");
383 names.push_back(id + "[0]");
384 while (names.size() > 0) {
385 // retrieve the first subelement (to follow)
386 std::string cid = names.back();
387 names.pop_back();
388 edge = retrieve(cid);
389 // The edge was splitted; check its subparts within the
390 // next step
391 if (edge == nullptr) {
392 if ((int)cid.length() + 3 < maxLength) {
393 names.push_back(cid + "[1]");
394 names.push_back(cid + "[0]");
395 }
396 }
397 // an edge with the name was found,
398 // check whether the position lies within it
399 else {
400 seen += edge->getLength();
401 if (seen >= pos) {
402 return edge;
403 }
404 }
405 }
406 return nullptr;
407}
408
409
410void
412 extract(dc, edge);
413 delete edge;
414}
415
416
417void
418NBEdgeCont::extract(NBDistrictCont& dc, NBEdge* edge, bool remember) {
419 if (remember) {
420 const auto& prevExtracted = myExtractedEdges.find(edge->getID());
421 if (prevExtracted != myExtractedEdges.end()) {
422 if (edge != prevExtracted->second) {
423 myEdgeCemetery.insert(prevExtracted->second);
424 prevExtracted->second = edge;
425 }
426 } else {
427 myExtractedEdges[edge->getID()] = edge;
428 }
429 }
430 myEdges.erase(edge->getID());
431 edge->myFrom->removeEdge(edge);
432 edge->myTo->removeEdge(edge);
434}
435
436
437void
438NBEdgeCont::rename(NBEdge* edge, const std::string& newID) {
439 if (myEdges.count(newID) != 0) {
440 throw ProcessError(TLF("Attempt to rename edge using existing id '%'", newID));
441 }
442 myEdges.erase(edge->getID());
443 edge->setID(newID);
444 myEdges[newID] = edge;
445 // update oppositeID
446 if (edge->getLanes().back().oppositeID != "") {
447 NBEdge* oppo = retrieve(SUMOXMLDefinitions::getEdgeIDFromLane(edge->getLanes().back().oppositeID));
448 if (oppo != nullptr) {
449 oppo->getLaneStruct(oppo->getNumLanes() - 1).oppositeID = edge->getLaneID(edge->getNumLanes() - 1);
450 }
451 }
452}
453
454
455// ----- explicit edge manipulation methods
456
457void
458NBEdgeCont::processSplits(NBEdge* e, std::vector<Split> splits,
460 if (splits.empty()) {
461 return;
462 }
463 const std::string origID = e->getID();
464 sort(splits.begin(), splits.end(), split_sorter());
465 int maxNumLanes = e->getNumLanes();
466 // compute the node positions and sort the lanes
467 for (Split& split : splits) {
468 sort(split.lanes.begin(), split.lanes.end());
469 maxNumLanes = MAX2(maxNumLanes, (int)split.lanes.size());
470 }
471 // split the edge
472 std::vector<int> currLanes;
473 for (int l = 0; l < e->getNumLanes(); ++l) {
474 currLanes.push_back(l);
475 }
476 if (e->getNumLanes() != (int)splits.back().lanes.size()) {
477 // invalidate traffic light definitions loaded from a SUMO network
478 e->getToNode()->invalidateTLS(tlc, true, true);
479 // if the number of lanes changes the connections should be
480 // recomputed
481 e->invalidateConnections(true);
482 }
483
484 std::string firstID = "";
485 double seen = 0;
486 for (const Split& exp : splits) {
487 assert(exp.lanes.size() != 0);
488 if (exp.pos > 0 && e->getLoadedLength() + seen > exp.pos && exp.pos > seen) {
489 nc.insert(exp.node);
490 nc.markAsSplit(exp.node);
491 // split the edge
492 const std::string idBefore = exp.idBefore == "" ? e->getID() : exp.idBefore;
493 const std::string idAfter = exp.idAfter == "" ? exp.nameID : exp.idAfter;
494 if (firstID == "") {
495 firstID = idBefore;
496 }
497 const bool ok = splitAt(dc, e, exp.pos - seen, exp.node,
498 idBefore, idAfter, e->getNumLanes(), (int) exp.lanes.size(), exp.speed);
499 if (!ok) {
500 WRITE_WARNINGF(TL("Error on parsing a split (edge '%')."), origID);
501 return;
502 }
503 seen = exp.pos;
504 std::vector<int> newLanes = exp.lanes;
505 NBEdge* pe = retrieve(idBefore);
506 NBEdge* ne = retrieve(idAfter);
507 // reconnect lanes
508 pe->invalidateConnections(true);
509 // new on right
510 int rightMostP = currLanes[0];
511 int rightMostN = newLanes[0];
512 for (int l = 0; l < (int) rightMostP - (int) rightMostN; ++l) {
514 }
515 // new on left
516 int leftMostP = currLanes.back();
517 int leftMostN = newLanes.back();
518 for (int l = 0; l < (int) leftMostN - (int) leftMostP; ++l) {
519 pe->addLane2LaneConnection(pe->getNumLanes() - 1, ne, leftMostN - l - rightMostN, NBEdge::Lane2LaneInfoType::VALIDATED, true);
520 }
521 // all other connected
522 for (int l = 0; l < maxNumLanes; ++l) {
523 if (find(currLanes.begin(), currLanes.end(), l) == currLanes.end()) {
524 continue;
525 }
526 if (find(newLanes.begin(), newLanes.end(), l) == newLanes.end()) {
527 continue;
528 }
529 pe->addLane2LaneConnection(l - rightMostP, ne, l - rightMostN, NBEdge::Lane2LaneInfoType::VALIDATED, true);
530 }
531 // if there are edges at this node which are not connected
532 // we can assume that this split was attached to an
533 // existing node. Reset all connections to let the default
534 // algorithm recompute them
535 if (exp.node->getIncomingEdges().size() > 1 || exp.node->getOutgoingEdges().size() > 1 || exp.node->getType() == SumoXMLNodeType::ZIPPER) {
536 for (NBEdge* in : exp.node->getIncomingEdges()) {
537 in->invalidateConnections(true);
538 }
539 }
540 // move to next
541 e = ne;
542 currLanes = newLanes;
543 } else if (exp.pos == 0) {
544 const int laneCountDiff = e->getNumLanes() - (int)exp.lanes.size();
545 if (laneCountDiff < 0) {
546 e->incLaneNo(-laneCountDiff);
547 } else {
548 e->decLaneNo(laneCountDiff);
549 }
550 currLanes = exp.lanes;
551 // invalidate traffic light definition loaded from a SUMO network
552 // XXX it would be preferable to reconstruct the phase definitions heuristically
553 e->getFromNode()->invalidateTLS(tlc, true, true);
554 if (exp.speed != -1.) {
555 e->setSpeed(-1, exp.speed);
556 }
557 } else {
558 WRITE_WARNINGF(TL("Split at '%' lies beyond the edge's length (edge '%')."), toString(exp.pos), origID);
559 }
560 }
561 // patch lane offsets
562 e = retrieve(firstID);
563 if (e != nullptr) {
564 if (splits.front().pos != 0) {
565 // add a dummy split at the beginning to ensure correct offset
566 Split start;
567 start.pos = 0;
568 for (int lane = 0; lane < (int)e->getNumLanes(); ++lane) {
569 start.lanes.push_back(lane);
570 }
571 start.offset = splits.front().offset;
572 start.offsetFactor = splits.front().offsetFactor;
573 splits.insert(splits.begin(), start);
574 }
575 for (const Split& split : splits) {
576 int maxLeft = split.lanes.back();
577 double offset = split.offset;
578 if (maxLeft < maxNumLanes) {
580 offset += split.offsetFactor * SUMO_const_laneWidth * (maxNumLanes - 1 - maxLeft);
581 } else {
582 offset += split.offsetFactor * SUMO_const_halfLaneWidth * (maxNumLanes - 1 - maxLeft);
583 }
584 }
585 int maxRight = split.lanes.front();
586 if (maxRight > 0 && e->getLaneSpreadFunction() == LaneSpreadFunction::CENTER) {
587 offset -= split.offsetFactor * SUMO_const_halfLaneWidth * maxRight;
588 }
589 //std::cout << " processSplits " << origID << " splitOffset=" << (*i).offset << " offset=" << offset << "\n";
590 if (offset != 0) {
592 g.move2side(offset);
593 e->setGeometry(g);
594 }
595 if (e->getToNode()->getOutgoingEdges().size() != 0) {
596 e = e->getToNode()->getOutgoingEdges()[0];
597 }
598 }
599 }
600}
601
602
603bool
605 return splitAt(dc, edge, node, edge->getID() + "[0]", edge->getID() + "[1]",
606 (int) edge->myLanes.size(), (int) edge->myLanes.size());
607}
608
609
610bool
612 const std::string& firstEdgeName,
613 const std::string& secondEdgeName,
614 int noLanesFirstEdge, int noLanesSecondEdge,
615 const double speed, const double friction,
616 const int changedLeft) {
617 double pos;
618 pos = edge->getGeometry().nearest_offset_to_point2D(node->getPosition());
619 if (pos <= 0) {
621 edge->myFrom->getPosition(), edge->myTo->getPosition(),
622 node->getPosition());
623 }
624 if (pos <= 0 || pos + POSITION_EPS > edge->getGeometry().length()) {
625 return false;
626 }
627 return splitAt(dc, edge, pos, node, firstEdgeName, secondEdgeName,
628 noLanesFirstEdge, noLanesSecondEdge, speed, friction, changedLeft);
629}
630
631
632bool
634 NBEdge* edge, double pos, NBNode* node,
635 const std::string& firstEdgeName,
636 const std::string& secondEdgeName,
637 int noLanesFirstEdge, int noLanesSecondEdge,
638 const double speed, const double friction,
639 const int changedLeft) {
640 if (firstEdgeName != edge->getID() && myEdges.count(firstEdgeName) != 0) {
641 WRITE_ERRORF(TL("Could not insert edge '%' before split of edge '%'."), firstEdgeName, edge->getID());
642 return false;
643 }
644 if (secondEdgeName == firstEdgeName || (secondEdgeName != edge->getID() && myEdges.count(secondEdgeName) != 0)) {
645 WRITE_ERRORF(TL("Could not insert edge '%' after split of edge '%'."), secondEdgeName, edge->getID());
646 return false;
647 }
648 // there must be at least some overlap between first and second edge
649 assert(changedLeft > -((int)noLanesFirstEdge));
650 assert(changedLeft < (int)noLanesSecondEdge);
651
652 // build the new edges' geometries
653 double geomPos = pos;
654 if (edge->hasLoadedLength()) {
655 geomPos = edge->getGeometry().nearest_offset_to_point2D(node->getPosition());
656 if (geomPos <= 0) {
657 geomPos = pos * edge->getGeometry().length() / edge->getLoadedLength();
658 }
659 }
660 std::pair<PositionVector, PositionVector> geoms = edge->getGeometry().splitAt(geomPos);
661 // reduce inaccuracies and preserve bidi
662 if (geoms.first[-1].almostSame(node->getPosition()) || edge->isBidi()) {
663 geoms.first[-1] = node->getPosition();
664 geoms.second[0] = node->getPosition();
665 }
666 // build and insert the edges
667 NBEdge* one = new NBEdge(firstEdgeName, edge->myFrom, node, edge, geoms.first, noLanesFirstEdge);
668 NBEdge* two = new NBEdge(secondEdgeName, node, edge->myTo, edge, geoms.second, noLanesSecondEdge);
669 if (OptionsCont::getOptions().getBool("output.original-names")) {
670 const std::string origID = edge->getLaneStruct(0).getParameter(SUMO_PARAM_ORIGID, edge->getID());
671 if (firstEdgeName != origID) {
672 one->setOrigID(origID, false);
673 }
674 if (secondEdgeName != origID) {
675 two->setOrigID(origID, false);
676 }
677 }
678 two->copyConnectionsFrom(edge);
679 if (speed != -1.) {
680 two->setSpeed(-1, speed);
681 }
682 if (friction != -1.) {
683 two->setFriction(-1, friction);
684 }
685 if (edge->getDistance() != 0) {
686 one->setDistance(edge->getDistance());
687 two->setDistance(one->getDistance() + pos);
688 }
689 if (edge->hasLoadedLength()) {
690 one->setLoadedLength(pos);
691 two->setLoadedLength(edge->getLoadedLength() - pos);
692 }
693 // replace information about this edge within the nodes
694 edge->myFrom->replaceOutgoing(edge, one, 0);
695 edge->myTo->replaceIncoming(edge, two, 0);
696 // patch tls
697 for (NBTrafficLightDefinition* const tld : edge->myFrom->getControllingTLS()) {
698 tld->replaceRemoved(edge, -1, one, -1, false);
699 }
700 for (NBTrafficLightDefinition* const tld : edge->myTo->getControllingTLS()) {
701 tld->replaceRemoved(edge, -1, two, -1, true);
702 }
703 // the edge is now occuring twice in both nodes...
704 // clean up
705 edge->myFrom->removeDoubleEdges();
706 edge->myTo->removeDoubleEdges();
707 // add connections from the first to the second edge
708 // there will be as many connections as there are lanes on the second edge
709 // by default lanes will be added / discontinued on the right side
710 // (appropriate for highway on-/off-ramps)
711 const int offset = (int)one->getNumLanes() - (int)two->getNumLanes() + changedLeft;
712 for (int i2 = 0; i2 < (int)two->getNumLanes(); i2++) {
713 const int i1 = MIN2(MAX2((int)0, i2 + offset), (int)one->getNumLanes());
715 throw ProcessError(TL("Could not set connection!"));
716 }
717 }
719 if (myEdges2Keep.count(edge->getID()) != 0) {
720 myEdges2Keep.insert(one->getID());
721 myEdges2Keep.insert(two->getID());
722 }
723 if (myEdges2Remove.count(edge->getID()) != 0) {
724 myEdges2Remove.insert(one->getID());
725 myEdges2Remove.insert(two->getID());
726 }
727 }
728 // erase the splitted edge
729 patchRoundabouts(edge, one, two, myRoundabouts);
730 patchRoundabouts(edge, one, two, myGuessedRoundabouts);
731 const std::string oldID = edge->getID();
732 extract(dc, edge, true);
733 insert(one, true); // duplicate id check happened earlier
734 insert(two, true); // duplicate id check happened earlier
735 myEdgesSplit[edge] = {one, two};
736 myWasSplit.insert(one);
737 myWasSplit.insert(two);
738 return true;
739}
740
741
742std::string
743NBEdgeCont::createUnusedID(const std::string& base, const std::string& sep) {
744 std::string result = base;
745 int i = 0;
746 while (myEdges.find(result) != myEdges.end()) {
747 result = base + sep + toString(i++);
748 }
749 return result;
750}
751
752
753void
754NBEdgeCont::patchRoundabouts(NBEdge* orig, NBEdge* part1, NBEdge* part2, std::set<EdgeSet>& roundabouts) {
755 std::set<EdgeSet> addLater;
756 for (std::set<EdgeSet>::iterator it = roundabouts.begin(); it != roundabouts.end(); ++it) {
757 EdgeSet roundaboutSet = *it;
758 if (roundaboutSet.count(orig) > 0) {
759 roundaboutSet.erase(orig);
760 roundaboutSet.insert(part1);
761 roundaboutSet.insert(part2);
762 }
763 addLater.insert(roundaboutSet);
764 }
765 roundabouts.clear();
766 roundabouts.insert(addLater.begin(), addLater.end());
767}
768
769
770// ----- container access methods
771std::vector<std::string>
773 std::vector<std::string> ret;
774 for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
775 ret.push_back((*i).first);
776 }
777 return ret;
778}
779
780
781NBEdge*
782NBEdgeCont::getSplitBase(const std::string& edgeID) const {
783 NBEdge* longest = nullptr;
784 for (auto item : myEdgesSplit) {
785 if (item.first->getID() == edgeID) {
786 if (longest == nullptr || longest->getLoadedLength() < item.first->getLoadedLength()) {
787 longest = const_cast<NBEdge*>(item.first);
788 }
789 }
790 }
791 return longest;
792}
793
794// ----- Adapting the input
795int
797 EdgeVector toRemove;
798 for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
799 NBEdge* edge = (*i).second;
800 if (!myEdges2Keep.count(edge->getID())) {
801 edge->getFromNode()->removeEdge(edge);
802 edge->getToNode()->removeEdge(edge);
803 toRemove.push_back(edge);
804 }
805 }
806 for (EdgeVector::iterator j = toRemove.begin(); j != toRemove.end(); ++j) {
807 erase(dc, *j);
808 }
809 return (int)toRemove.size();
810}
811
812
813void
815 // make a copy of myEdges because splitting will modify it
816 EdgeCont edges = myEdges;
817 for (auto& item : edges) {
818 NBEdge* edge = item.second;
819 if (edge->getGeometry().size() < 3) {
820 continue;
821 }
822 PositionVector geom = edge->getGeometry();
823 const std::string id = edge->getID();
824 double offset = 0;
825 for (int i = 1; i < (int)geom.size() - 1; i++) {
826 offset += geom[i - 1].distanceTo(geom[i]);
827 std::string nodeID = id + "." + toString((int)offset);
828 if (!nc.insert(nodeID, geom[i])) {
829 WRITE_WARNING("Could not split geometry of edge '" + id + "' at index " + toString(i));
830 continue;
831 }
832 NBNode* node = nc.retrieve(nodeID);
833 splitAt(dc, edge, node, edge->getID(), nodeID, edge->getNumLanes(), edge->getNumLanes());
834 edge = retrieve(nodeID);
835 }
836 }
837}
838
839
840void
841NBEdgeCont::reduceGeometries(const double minDist) {
842 for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
843 (*i).second->reduceGeometry(minDist);
844 }
845}
846
847
848void
849NBEdgeCont::checkGeometries(const double maxAngle, bool fixAngle, const double minRadius, bool fix, bool fixRailways, bool silent) {
850 if (maxAngle > 0 || minRadius > 0) {
851 for (auto& item : myEdges) {
852 if ((item.second->getPermissions() & (SVC_PUBLIC_CLASSES | SVC_PASSENGER)) == 0) {
853 continue;
854 }
855 item.second->checkGeometry(maxAngle, fixAngle, minRadius, fix || (fixRailways && isRailway(item.second->getPermissions())), silent);
856 }
857 }
858}
859
860
861// ----- processing methods
862void
864 for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); i++) {
865 (*i).second->clearControllingTLInformation();
866 }
867}
868
869
870void
872 for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
873 (*i).second->sortOutgoingConnectionsByAngle();
874 }
875}
876
877
878void
880 for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
881 (*i).second->computeEdge2Edges(noLeftMovers);
882 }
883}
884
885
886void
888 for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
889 (*i).second->computeLanes2Edges();
890 }
891}
892
893
894void
896 const bool fixOppositeLengths = OptionsCont::getOptions().getBool("opposites.guess.fix-lengths");
897 for (const auto& edgeIt : myEdges) {
898 NBEdge* const edge = edgeIt.second;
899 edge->recheckLanes();
900 edge->recheckOpposite(*this, fixOppositeLengths);
901 }
902}
903
904
905void
906NBEdgeCont::appendTurnarounds(bool noTLSControlled, bool noFringe, bool onlyDeadends, bool onlyTurnlane, bool noGeometryLike) {
907 for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
908 (*i).second->appendTurnaround(noTLSControlled, noFringe, onlyDeadends, onlyTurnlane, noGeometryLike, true);
909 }
910}
911
912
913void
914NBEdgeCont::appendTurnarounds(const std::set<std::string>& ids, bool noTLSControlled) {
915 for (std::set<std::string>::const_iterator it = ids.begin(); it != ids.end(); it++) {
916 myEdges[*it]->appendTurnaround(noTLSControlled, false, false, false, false, false);
917 }
918}
919
920
921void
923 std::set<std::string> stopEdgeIDs;
924 for (auto& stopItem : sc.getStops()) {
925 stopEdgeIDs.insert(stopItem.second->getEdgeId());
926 }
927 for (auto& item : myEdges) {
928 NBEdge* edge = item.second;
929 if (edge->isBidiRail()
930 && (stopEdgeIDs.count(item.first) > 0 ||
931 stopEdgeIDs.count(edge->getTurnDestination(true)->getID()) > 0)) {
932 NBEdge* to = edge->getTurnDestination(true);
933 assert(to != 0);
934 edge->setConnection(edge->getNumLanes() - 1,
935 to, to->getNumLanes() - 1, NBEdge::Lane2LaneInfoType::VALIDATED, false, false,
939 // finalize connections to prevent removal during recheck
941 }
942 }
943}
944
945void
946NBEdgeCont::computeEdgeShapes(double smoothElevationThreshold) {
947 for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
948 (*i).second->computeEdgeShape(smoothElevationThreshold);
949 }
950 // equalize length of opposite edges
951 for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); i++) {
952 NBEdge* edge = i->second;
953 const std::string& oppositeID = edge->getLanes().back().oppositeID;
954 if (oppositeID != "" && oppositeID != "-") {
955 NBEdge* oppEdge = retrieve(oppositeID.substr(0, oppositeID.rfind("_")));
956 if (oppEdge == nullptr || oppEdge->getLaneID(oppEdge->getNumLanes() - 1) != oppositeID) {
957 continue;
958 }
959 if (fabs(oppEdge->getLength() - edge->getLength()) > NUMERICAL_EPS) {
960 double avgLength = (oppEdge->getLength() + edge->getLength()) / 2;
961 edge->setAverageLengthWithOpposite(avgLength);
962 oppEdge->setAverageLengthWithOpposite(avgLength);
963 }
964 }
965 }
966}
967
968
969void
971 for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
972 (*i).second->computeLaneShapes();
973 }
974}
975
976
977void
980 EdgeVector edges) {
981 // !!! Attention!
982 // No merging of the geometry to come is being done
983 // The connections are moved from one edge to another within
984 // the replacement where the edge is a node's incoming edge.
985
986 // count the number of lanes, the speed and the id
987 int nolanes = 0;
988 double speed = 0;
989 int priority = -1;
990 bool joinEdges = true;
991 std::string id;
992 sort(edges.begin(), edges.end(), NBContHelper::same_connection_edge_sorter());
993 // retrieve the connected nodes
994 NBEdge* tpledge = *(edges.begin());
995 NBNode* from = tpledge->getFromNode();
996 NBNode* to = tpledge->getToNode();
997 EdgeVector::const_iterator i;
998 int myPriority = (*edges.begin())->getPriority();
999 for (i = edges.begin(); i != edges.end(); i++) {
1000 // some assertions
1001 assert((*i)->getFromNode() == from);
1002 assert((*i)->getToNode() == to);
1003 // ad the number of lanes the current edge has
1004 nolanes += (*i)->getNumLanes();
1005 // build the id
1006 if (i != edges.begin()) {
1007 id += "+";
1008 }
1009 id += (*i)->getID();
1010 // compute the speed
1011 speed += (*i)->getSpeed();
1012 // build the priority
1013 // merged edges should have the same inherited priority
1014 if (myPriority == (*i)->getPriority()) {
1015 priority = myPriority;
1016 } else {
1017 priority = -1;
1018 joinEdges = false;
1019 }
1020 }
1021 if (joinEdges) {
1022 speed /= (double)edges.size();
1023 // build the new edge
1024 NBEdge* newEdge = new NBEdge(id, from, to, "", speed, NBEdge::UNSPECIFIED_FRICTION, nolanes, priority,
1026 tpledge->myLaneSpreadFunction, tpledge->getStreetName());
1027 // copy lane attributes
1028 int laneIndex = 0;
1029 for (i = edges.begin(); i != edges.end(); ++i) {
1030 const std::vector<NBEdge::Lane>& lanes = (*i)->getLanes();
1031 for (int j = 0; j < (int)lanes.size(); ++j) {
1032 newEdge->setPermissions(lanes[j].permissions, laneIndex);
1033 newEdge->setLaneWidth(laneIndex, lanes[j].width);
1034 newEdge->setEndOffset(laneIndex, lanes[j].endOffset);
1035 laneIndex++;
1036 }
1037 }
1038 insert(newEdge, true);
1039 // replace old edge by current within the nodes
1040 // and delete the old
1041 from->replaceOutgoing(edges, newEdge);
1042 to->replaceIncoming(edges, newEdge);
1043 // patch connections
1044 // add edge2edge-information
1045 for (i = edges.begin(); i != edges.end(); i++) {
1046 EdgeVector ev = (*i)->getConnectedEdges();
1047 for (EdgeVector::iterator j = ev.begin(); j != ev.end(); j++) {
1048 newEdge->addEdge2EdgeConnection(*j);
1049 }
1050 }
1051 // copy outgoing connections to the new edge
1052 int currLane = 0;
1053 for (i = edges.begin(); i != edges.end(); i++) {
1054 newEdge->moveOutgoingConnectionsFrom(*i, currLane);
1055 currLane += (*i)->getNumLanes();
1056 }
1057 // patch tl-information
1058 currLane = 0;
1059 for (i = edges.begin(); i != edges.end(); i++) {
1060 int noLanes = (*i)->getNumLanes();
1061 for (int j = 0; j < noLanes; j++, currLane++) {
1062 // replace in traffic lights
1063 tlc.replaceRemoved(*i, j, newEdge, currLane, true);
1064 tlc.replaceRemoved(*i, j, newEdge, currLane, false);
1065 }
1066 }
1067 // delete joined edges
1068 for (i = edges.begin(); i != edges.end(); i++) {
1069 extract(dc, *i, true);
1070 }
1071 }
1072}
1073
1074
1075void
1077 //@todo magic values
1078 const bool fixOppositeLengths = OptionsCont::getOptions().getBool("opposites.guess.fix-lengths");
1079 // ensure consistency of loaded values before starting to guess
1080 for (const auto& edgeIt : myEdges) {
1081 NBEdge* const edge = edgeIt.second;
1082 edge->recheckOpposite(*this, fixOppositeLengths);
1083 }
1084 for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
1085 NBEdge* edge = i->second;
1086 edge->guessOpposite();
1087 }
1088}
1089
1090
1091void
1093 for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
1094 NBEdge* opposite = getOppositeByID(i->first);
1095 if (opposite != nullptr) {
1096 i->second->setLaneSpreadFunction(LaneSpreadFunction::RIGHT);
1098 } else {
1099 i->second->setLaneSpreadFunction(LaneSpreadFunction::CENTER);
1100 }
1101 }
1102}
1103
1104
1105NBEdge*
1106NBEdgeCont::getOppositeByID(const std::string& edgeID) const {
1107 const std::string oppositeID = edgeID[0] == '-' ? edgeID.substr(1) : "-" + edgeID;
1108 EdgeCont::const_iterator it = myEdges.find(oppositeID);
1109 return it != myEdges.end() ? it->second : (NBEdge*)nullptr;
1110}
1111
1112NBEdge*
1113NBEdgeCont::getByID(const std::string& edgeID) const {
1114 EdgeCont::const_iterator it = myEdges.find(edgeID);
1115 return it != myEdges.end() ? it->second : (NBEdge*)nullptr;
1116}
1117
1118// ----- other
1119void
1120NBEdgeCont::addPostProcessConnection(const std::string& from, int fromLane, const std::string& to, int toLane, bool mayDefinitelyPass,
1121 KeepClear keepClear, double contPos, double visibility, double speed, double friction, double length,
1122 const PositionVector& customShape, bool uncontrolled, bool warnOnly,
1123 SVCPermissions permissions, bool indirectLeft, const std::string& edgeType, SVCPermissions changeLeft, SVCPermissions changeRight) {
1124 myConnections[from].push_back(PostProcessConnection(from, fromLane, to, toLane, mayDefinitelyPass, keepClear, contPos, visibility,
1125 speed, friction, length, customShape, uncontrolled, warnOnly, permissions, indirectLeft, edgeType, changeLeft, changeRight));
1126}
1127
1128bool
1129NBEdgeCont::hasPostProcessConnection(const std::string& from, const std::string& to) {
1130 if (myConnections.count(from) == 0) {
1131 return false;
1132 } else {
1133 if (to == "") {
1134 // wildcard
1135 return true;
1136 }
1137 for (const auto& ppc : myConnections[from]) {
1138 if (ppc.to == to) {
1139 return true;
1140 }
1141 }
1142 return false;
1143 }
1144}
1145
1146void
1148 const bool warnOnly = OptionsCont::getOptions().exists("ignore-errors.connections") && OptionsCont::getOptions().getBool("ignore-errors.connections");
1149 for (const auto& item : myConnections) {
1150 for (std::vector<PostProcessConnection>::const_iterator i = item.second.begin(); i != item.second.end(); ++i) {
1151 NBEdge* from = retrievePossiblySplit((*i).from, true);
1152 NBEdge* to = retrievePossiblySplit((*i).to, false);
1153 if (from == nullptr || to == nullptr ||
1154 !from->addLane2LaneConnection((*i).fromLane, to, (*i).toLane, NBEdge::Lane2LaneInfoType::USER, true, (*i).mayDefinitelyPass,
1155 (*i).keepClear, (*i).contPos, (*i).visibility, (*i).speed, (*i).friction, (*i).customLength, (*i).customShape,
1156 (*i).uncontrolled, (*i).permissions, (*i).indirectLeft, (*i).edgeType, (*i).changeLeft, (*i).changeRight,
1157 true)) {
1158 const std::string msg = "Could not insert connection between '" + (*i).from + "' and '" + (*i).to + "' after build.";
1159 if (warnOnly || (*i).warnOnly) {
1160 WRITE_WARNING(msg);
1161 } else {
1162 WRITE_ERROR(msg);
1163 }
1164 }
1165 }
1166 }
1167 // during loading we also kept some ambiguous connections in hope they might be valid after processing
1168 // we need to make sure that all invalid connections are removed now
1169 for (EdgeCont::iterator it = myEdges.begin(); it != myEdges.end(); ++it) {
1170 NBEdge* edge = it->second;
1171 NBNode* to = edge->getToNode();
1172 // make a copy because we may delete connections
1173 std::vector<NBEdge::Connection> connections = edge->getConnections();
1174 for (std::vector<NBEdge::Connection>::iterator it_con = connections.begin(); it_con != connections.end(); ++it_con) {
1175 NBEdge::Connection& c = *it_con;
1176 if (c.toEdge != nullptr && c.toEdge->getFromNode() != to) {
1177 WRITE_WARNING("Found and removed invalid connection from edge '" + edge->getID() +
1178 "' to edge '" + c.toEdge->getID() + "' via junction '" + to->getID() + "'.");
1180 }
1181 }
1182 }
1183}
1184
1185
1187NBEdgeCont::getGeneratedFrom(const std::string& id) const {
1188 int len = (int)id.length();
1189 EdgeVector ret;
1190 for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
1191 std::string curr = (*i).first;
1192 // the next check makes it possibly faster - we don not have
1193 // to compare the names
1194 if ((int)curr.length() <= len) {
1195 continue;
1196 }
1197 // the name must be the same as the given id but something
1198 // beginning with a '[' must be appended to it
1199 if (curr.substr(0, len) == id && curr[len] == '[') {
1200 ret.push_back((*i).second);
1201 continue;
1202 }
1203 // ok, maybe the edge is a compound made during joining of edges
1204 std::string::size_type pos = curr.find(id);
1205 // surely not
1206 if (pos == std::string::npos) {
1207 continue;
1208 }
1209 // check leading char
1210 if (pos > 0) {
1211 if (curr[pos - 1] != ']' && curr[pos - 1] != '+') {
1212 // actually, this is another id
1213 continue;
1214 }
1215 }
1216 if (pos + id.length() < curr.length()) {
1217 if (curr[pos + id.length()] != '[' && curr[pos + id.length()] != '+') {
1218 // actually, this is another id
1219 continue;
1220 }
1221 }
1222 ret.push_back((*i).second);
1223 }
1224 return ret;
1225}
1226
1227
1228int
1230 myGuessedRoundabouts.clear();
1231 std::set<NBEdge*> loadedRoundaboutEdges;
1232 for (std::set<EdgeSet>::const_iterator it = myRoundabouts.begin(); it != myRoundabouts.end(); ++it) {
1233 loadedRoundaboutEdges.insert(it->begin(), it->end());
1234 }
1235 // step 1: keep only those edges which have no turnarounds and which are not
1236 // part of a loaded roundabout
1237 std::set<NBEdge*> candidates;
1238 SVCPermissions valid = SVCAll & ~SVC_PEDESTRIAN;
1239 for (EdgeCont::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
1240 NBEdge* e = (*i).second;
1241 NBNode* const to = e->getToNode();
1242 if (e->getTurnDestination() == nullptr
1243 && to->getConnectionTo(e->getFromNode()) == nullptr
1244 && (e->getPermissions() & valid) != 0) {
1245 candidates.insert(e);
1246 }
1247 }
1248
1249 // step 2:
1250 std::set<NBEdge*> visited;
1251 for (std::set<NBEdge*>::const_iterator i = candidates.begin(); i != candidates.end(); ++i) {
1252 EdgeVector loopEdges;
1253 // start with a random edge (this doesn't have to be a roundabout edge)
1254 // loop over connected edges (using always the leftmost one)
1255 // and keep the list in loopEdges
1256 // continue until we loop back onto a loopEdges and extract the loop
1257 NBEdge* e = (*i);
1258 if (visited.count(e) > 0) {
1259 // already seen
1260 continue;
1261 }
1262 loopEdges.push_back(e);
1263 bool doLoop = true;
1264#ifdef DEBUG_GUESS_ROUNDABOUT
1266#endif
1267 do {
1268#ifdef DEBUG_GUESS_ROUNDABOUT
1269 if (gDebugFlag1) {
1270 std::cout << " e=" << e->getID() << " loopEdges=" << toString(loopEdges) << "\n";
1271 gDebugFlag1 = true;
1272 }
1273#endif
1274 visited.insert(e);
1275 const EdgeVector& edges = e->getToNode()->getEdges();
1277 && !e->getToNode()->typeWasGuessed()) {
1278 doLoop = false;
1279#ifdef DEBUG_GUESS_ROUNDABOUT
1280 if (gDebugFlag1) {
1281 std::cout << " rbl\n";
1282 }
1283 gDebugFlag1 = false;
1284#endif
1285 break;
1286 }
1288 doLoop = false;
1289#ifdef DEBUG_GUESS_ROUNDABOUT
1290 if (gDebugFlag1) {
1291 std::cout << " disabled\n";
1292 }
1293 gDebugFlag1 = false;
1294#endif
1295 break;
1296 }
1297 if (edges.size() < 2) {
1298 doLoop = false;
1299#ifdef DEBUG_GUESS_ROUNDABOUT
1300 if (gDebugFlag1) {
1301 std::cout << " deadend\n";
1302 }
1303 gDebugFlag1 = false;
1304#endif
1305 break;
1306 }
1307 if (e->getTurnDestination(true) != nullptr || e->getToNode()->getConnectionTo(e->getFromNode()) != nullptr) {
1308 // do not follow turn-arounds while in a (tentative) loop
1309 doLoop = false;
1310#ifdef DEBUG_GUESS_ROUNDABOUT
1311 if (gDebugFlag1) {
1312 std::cout << " invalid turnAround e=" << e->getID() << " dest=" << Named::getIDSecure(e->getTurnDestination()) << "\n";
1313 }
1314 gDebugFlag1 = false;
1315#endif
1316 break;
1317 }
1318 EdgeVector::const_iterator me = std::find(edges.begin(), edges.end(), e);
1319 NBContHelper::nextCW(edges, me);
1320 NBEdge* left = *me;
1321 while ((left->getPermissions() & valid) == 0 && left != e) {
1322 NBContHelper::nextCW(edges, me);
1323 left = *me;
1324 }
1325 if (left == e) {
1326 // no usable continuation edge found
1327 doLoop = false;
1328#ifdef DEBUG_GUESS_ROUNDABOUT
1329 if (gDebugFlag1) {
1330 std::cout << " noContinuation\n";
1331 }
1332 gDebugFlag1 = false;
1333#endif
1334 break;
1335 }
1336 NBContHelper::nextCW(edges, me);
1337 NBEdge* nextLeft = *me;
1338 double angle = fabs(NBHelpers::relAngle(e->getAngleAtNode(e->getToNode()), left->getAngleAtNode(e->getToNode())));
1339 double nextAngle = nextLeft == e ? 180 : fabs(NBHelpers::relAngle(e->getAngleAtNode(e->getToNode()), nextLeft->getAngleAtNode(e->getToNode())));
1340#ifdef DEBUG_GUESS_ROUNDABOUT
1341 if (gDebugFlag1) {
1342 std::cout << " e=" << e->getID() << " left=" << left->getID() << " nextLeft=" << nextLeft->getID() << " angle=" << angle << " nextAngle=" << nextAngle << " eLength=" << e->getLength() << " lLength=" << left->getLength() << " dist=" << e->getLaneShape(0).back().distanceTo2D(left->getLaneShape(0).front()) << "\n";
1343 }
1344#endif
1345 // there should be no straigher edge further left
1346 if (angle >= 90 && nextAngle < 45) {
1347 doLoop = false;
1348#ifdef DEBUG_GUESS_ROUNDABOUT
1349 if (gDebugFlag1) {
1350 std::cout << " failed nextAngle=" << nextAngle << "\n";
1351 }
1352 gDebugFlag1 = false;
1353#endif
1354 break;
1355 }
1356 // roundabouts do not have sharp turns (or they wouldn't be called 'round')
1357 // however, if the roundabout is very small then most of the roundness may be in the junction so the angle may be as high as 180 (for smooth attachments at a joined junction)
1358 if (angle >= 90) {
1359 double edgeAngle = fabs(NBHelpers::relAngle(e->getStartAngle(), e->getEndAngle()));
1360 double edgeAngle2 = fabs(NBHelpers::relAngle(left->getStartAngle(), left->getEndAngle()));
1361 double edgeRadius = e->getGeometry().length2D() / DEG2RAD(edgeAngle);
1362 double edgeRadius2 = left->getGeometry().length2D() / DEG2RAD(edgeAngle2);
1363 const double avgRadius = 0.5 * (edgeRadius + edgeRadius2);
1364 double junctionRadius = e->getLaneShape(0).back().distanceTo2D(left->getLaneShape(0).front()) / DEG2RAD(angle);
1365 //std::cout << " junction=" << e->getToNode()->getID() << " e=" << e->getID() << " left=" << left->getID() << " angle=" << angle << " eRadius=" << edgeRadius << " eRadius2=" << edgeRadius2 << " jRadius3=" << junctionRadius << "\n";
1366 if (junctionRadius < 0.8 * avgRadius) {
1367 doLoop = false;
1368#ifdef DEBUG_GUESS_ROUNDABOUT
1369 if (gDebugFlag1) {
1370 std::cout << " failed angle=" << angle << " eRadius=" << edgeRadius << " eRadius2=" << edgeRadius2 << " jRadius3=" << junctionRadius << "\n";
1371 }
1372 gDebugFlag1 = false;
1373#endif
1374 break;
1375 }
1376 }
1377
1378 EdgeVector::const_iterator loopClosed = std::find(loopEdges.begin(), loopEdges.end(), left);
1379 const int loopSize = (int)(loopEdges.end() - loopClosed);
1380 if (loopSize > 0) {
1381 // loop found
1382 if (loopSize < 3) {
1383 doLoop = false; // need at least 3 edges for a roundabout
1384 } else if (loopSize < (int)loopEdges.size()) {
1385 // remove initial edges not belonging to the loop
1386 EdgeVector(loopEdges.begin() + (loopEdges.size() - loopSize), loopEdges.end()).swap(loopEdges);
1387 }
1388 // count attachments to the outside. need at least 3 or a roundabout doesn't make much sense
1389 int attachments = 0;
1390 for (EdgeVector::const_iterator j = loopEdges.begin(); j != loopEdges.end(); ++j) {
1391 if ((*j)->getToNode()->getEdges().size() > 2) {
1392 attachments++;
1393 }
1394 }
1395 if (attachments < 3) {
1396 doLoop = false;
1397#ifdef DEBUG_GUESS_ROUNDABOUT
1398 if (gDebugFlag1) {
1399 std::cout << " attachments=" << attachments << "\n";
1400 }
1401 gDebugFlag1 = false;
1402#endif
1403 }
1404 break;
1405 }
1406 if (visited.count(left) > 0) {
1407 doLoop = false;
1408 } else {
1409 // keep going
1410 loopEdges.push_back(left);
1411 e = left;
1412 }
1413 } while (doLoop);
1414 if (doLoop) {
1415 // check form factor to avoid elongated shapes (circle: 1, square: ~0.79)
1416#ifdef DEBUG_GUESS_ROUNDABOUT
1417 if (gDebugFlag1) {
1418 std::cout << " formFactor=" << formFactor(loopEdges) << "\n";
1419 }
1420#endif
1421 double loopLength = 0;
1422 for (const NBEdge* const le : loopEdges) {
1423 loopLength += le->getLoadedLength();
1424 }
1425 if (formFactor(loopEdges) > 0.6
1426 && loopLength < OptionsCont::getOptions().getFloat("roundabouts.guess.max-length")) {
1427 // collected edges are marked in markRoundabouts
1428 EdgeSet guessed(loopEdges.begin(), loopEdges.end());
1429 if (loadedRoundaboutEdges.count(loopEdges.front()) != 0) {
1430 if (find(myRoundabouts.begin(), myRoundabouts.end(), guessed) == myRoundabouts.end()) {
1431 for (auto it = myRoundabouts.begin(); it != myRoundabouts.end(); it++) {
1432 if ((*it).count(loopEdges.front()) != 0) {
1433 WRITE_WARNINGF(TL("Replacing loaded roundabout '%' with '%'."), toString(*it), toString(guessed));
1434 myRoundabouts.erase(it);
1435 break;
1436 }
1437 }
1438 myGuessedRoundabouts.insert(guessed);
1439 }
1440 } else {
1441 myGuessedRoundabouts.insert(guessed);
1442#ifdef DEBUG_GUESS_ROUNDABOUT
1443 if (gDebugFlag1) {
1444 std::cout << " foundRoundabout=" << toString(loopEdges) << "\n";
1445 }
1446#endif
1447 }
1448 }
1449 }
1450#ifdef DEBUG_GUESS_ROUNDABOUT
1451 gDebugFlag1 = false;
1452#endif
1453 }
1454 return (int)myGuessedRoundabouts.size();
1455}
1456
1457
1458int
1460 std::set<NBEdge*> candidateEdges;
1461 for (const auto& edge : myEdges) {
1462 NBEdge* const e = edge.second;
1464 candidateEdges.insert(e);
1465 }
1466 }
1467 std::set<NBEdge*> visited;
1468 int extracted = 0;
1469 for (const auto& edgeIt : candidateEdges) {
1470 EdgeVector loopEdges;
1471 NBEdge* e = edgeIt;
1472 if (visited.count(e) > 0) {
1473 // already seen
1474 continue;
1475 }
1476 loopEdges.push_back(e);
1477 bool doLoop = true;
1478 //
1479 do {
1480 if (std::find(visited.begin(), visited.end(), e) != visited.end()) {
1481 if (loopEdges.size() > 1) {
1482 addRoundabout(EdgeSet(loopEdges.begin(), loopEdges.end()));
1483 ++extracted;
1484 }
1485 doLoop = false;
1486 break;
1487 }
1488 visited.insert(e);
1489 loopEdges.push_back(e);
1490 const EdgeVector& outgoingEdges = e->getToNode()->getOutgoingEdges();
1491 EdgeVector::const_iterator me = std::find_if(outgoingEdges.begin(), outgoingEdges.end(), [](const NBEdge * outgoingEdge) {
1492 return outgoingEdge->getJunctionPriority(outgoingEdge->getToNode()) == NBEdge::JunctionPriority::ROUNDABOUT;
1493 });
1494 if (me == outgoingEdges.end()) { // no closed loop
1495 doLoop = false;
1496 } else {
1497 e = *me;
1498 }
1499 } while (doLoop);
1500 }
1501 return extracted;
1502}
1503
1504
1505void
1507 // only loaded roundabouts are of concern here since guessing comes later
1508 std::set<EdgeSet> validRoundabouts;
1509 std::set<NBEdge*> validEdges;
1510 for (auto item : myEdges) {
1511 validEdges.insert(item.second);
1512 }
1513 for (EdgeSet roundabout : myRoundabouts) {
1514 EdgeSet validRoundabout;
1515 for (NBEdge* cand : roundabout) {
1516 if (validEdges.count(cand) != 0) {
1517 validRoundabout.insert(cand);
1518 }
1519 }
1520 if (validRoundabout.size() > 0) {
1521 validRoundabouts.insert(validRoundabout);
1522 }
1523 }
1524 myRoundabouts = validRoundabouts;
1525}
1526
1527
1528double
1530 // A circle (which maximizes area per circumference) has a formfactor of 1, non-circular shapes have a smaller value
1531 PositionVector points;
1532 for (EdgeVector::const_iterator it = loopEdges.begin(); it != loopEdges.end(); ++it) {
1533 points.append((*it)->getGeometry());
1534 }
1535 double circumference = points.length2D();
1536 return 4 * M_PI * points.area() / (circumference * circumference);
1537}
1538
1539
1540const std::set<EdgeSet>
1542 std::set<EdgeSet> result = myRoundabouts;
1543 result.insert(myGuessedRoundabouts.begin(), myGuessedRoundabouts.end());
1544 return result;
1545}
1546
1547
1548void
1550 if (roundabout.size() > 0) {
1551 if (find(myRoundabouts.begin(), myRoundabouts.end(), roundabout) != myRoundabouts.end()) {
1552 WRITE_WARNING("Ignoring duplicate roundabout: " + toString(roundabout));
1553 } else {
1554 myRoundabouts.insert(roundabout);
1555 }
1556 }
1557}
1558
1559void
1561 for (auto it = myRoundabouts.begin(); it != myRoundabouts.end(); ++it) {
1562 for (NBEdge* e : *it) {
1563 if (e->getToNode() == node) {
1564 myRoundabouts.erase(it);
1565 return;
1566 }
1567 }
1568 }
1569}
1570
1571void
1576
1577void
1578NBEdgeCont::removeRoundaboutEdges(const EdgeSet& toRemove, std::set<EdgeSet>& roundabouts) {
1579 // members of a set are constant so we have to do some tricks
1580 std::vector<EdgeSet> rList;
1581 for (const EdgeSet& r : roundabouts) {
1582 EdgeSet r2;
1583 std::set_difference(r.begin(), r.end(), toRemove.begin(), toRemove.end(), std::inserter(r2, r2.end()));
1584 rList.push_back(r2);
1585 }
1586 roundabouts.clear();
1587 roundabouts.insert(rList.begin(), rList.end());
1588}
1589
1590
1591void
1593 for (const EdgeSet& roundaboutSet : getRoundabouts()) {
1594 for (NBEdge* const edge : roundaboutSet) {
1595 // disable turnarounds on incoming edges
1596 NBNode* const node = edge->getToNode();
1597 for (NBEdge* const inEdge : node->getIncomingEdges()) {
1598 if (roundaboutSet.count(inEdge) > 0) {
1599 continue;
1600 }
1601 if (inEdge->getStep() >= NBEdge::EdgeBuildingStep::LANES2LANES_USER) {
1602 continue;
1603 }
1604 if (inEdge->getTurnDestination() != nullptr) {
1605 inEdge->removeFromConnections(inEdge->getTurnDestination(), -1);
1606 } else {
1607 // also remove connections that are effecively a turnaround but
1608 // where not correctly detector due to geometrical quirks
1609 const std::vector<NBEdge::Connection> cons = inEdge->getConnections();
1610 for (const NBEdge::Connection& con : cons) {
1611 if (con.toEdge && roundaboutSet.count(con.toEdge) == 0) {
1612 const double angle = fabs(NBHelpers::normRelAngle(inEdge->getAngleAtNode(node), con.toEdge->getAngleAtNode(node)));
1613 if (angle > 160) {
1614 inEdge->removeFromConnections(con.toEdge, -1);
1615 }
1616 }
1617 }
1618 }
1619
1620 }
1621 // let the connections to succeeding roundabout edge have a higher priority
1622 edge->setJunctionPriority(node, NBEdge::JunctionPriority::ROUNDABOUT);
1623 edge->setJunctionPriority(edge->getFromNode(), NBEdge::JunctionPriority::ROUNDABOUT);
1624 node->setRoundabout();
1625 }
1626 }
1627}
1628
1629
1630void
1632 for (EdgeCont::iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
1633 NBEdge* e = i->second;
1634 const double offset = MAX2(0., e->getLength() - 3);
1635 if (e->getToNode()->isSimpleContinuation(false)) {
1636 // not a "real" junction?
1637 continue;
1638 }
1639 const SumoXMLNodeType nodeType = e->getToNode()->getType();
1640 switch (nodeType) {
1642 // yield or major?
1643 if (e->getJunctionPriority(e->getToNode()) > 0) {
1645 } else {
1647 }
1648 break;
1650 // yield or major?
1651 if (e->getJunctionPriority(e->getToNode()) > 0) {
1653 } else {
1655 }
1656 break;
1659 break;
1662 break;
1665 break;
1666 default:
1667 break;
1668 }
1669 }
1670}
1671
1672
1673int
1674NBEdgeCont::guessSpecialLanes(SUMOVehicleClass svc, double width, double minSpeed, double maxSpeed, bool fromPermissions, const std::string& excludeOpt,
1676 int lanesCreated = 0;
1677 std::vector<std::string> edges;
1678 if (excludeOpt != "") {
1679 edges = OptionsCont::getOptions().getStringVector(excludeOpt);
1680 }
1681 std::set<std::string> exclude(edges.begin(), edges.end());
1682 for (EdgeCont::iterator it = myEdges.begin(); it != myEdges.end(); it++) {
1683 NBEdge* edge = it->second;
1684 if (// not excluded
1685 exclude.count(edge->getID()) == 0
1686 // does not yet have a sidewalk/bikelane
1687 && !edge->hasRestrictedLane(svc)
1688 // needs a sidewalk/bikelane
1689 && ((edge->getPermissions() & ~SVC_VULNERABLE) != 0 || (edge->getPermissions() & svc) == 0)
1690 && (
1691 // guess.from-permissions
1692 (fromPermissions && (edge->getPermissions() & svc) != 0)
1693 // guess from speed
1694 || (!fromPermissions && edge->getSpeed() > minSpeed && edge->getSpeed() <= maxSpeed)
1695 )) {
1696 edge->addRestrictedLane(width, svc);
1697 lanesCreated += 1;
1698 if (svc != SVC_PEDESTRIAN) {
1700 // preserve existing connections and only add new ones
1703 for (NBEdge* to : edge->getToNode()->getOutgoingEdges()) {
1705 }
1706 // patching TLS is not feasible because existing states may
1707 // change from 'G' to 'g' when bike lanes are added (i.e. right-turns)
1708 } else {
1709 edge->invalidateConnections(true);
1711 }
1712 edge->getFromNode()->invalidateTLS(tlc, true, false);
1713 edge->getToNode()->invalidateTLS(tlc, true, false);
1714 }
1715 } else if (!fromPermissions && edge->getSpeed() > maxSpeed && !edge->hasRestrictedLane(svc)) {
1716 edge->disallowVehicleClass(-1, svc);
1717 }
1718 }
1719 return lanesCreated;
1720}
1721
1722
1723void
1725 for (auto item : myEdges) {
1726 item.second->updateChangeRestrictions(ignoring);
1727 }
1728}
1729
1730
1731void
1732NBEdgeCont::addPrefix(const std::string& prefix) {
1733 // make a copy of node containers
1734 const auto nodeContainerCopy = myEdges;
1735 myEdges.clear();
1736 for (const auto& node : nodeContainerCopy) {
1737 node.second->setID(prefix + node.second->getID());
1738 myEdges[node.second->getID()] = node.second;
1739 }
1740}
1741
1742
1743int
1744NBEdgeCont::remapIDs(bool numericaIDs, bool reservedIDs, bool keptIDs, const std::string& prefix, NBPTStopCont& sc) {
1745 bool startGiven = !OptionsCont::getOptions().isDefault("numerical-ids.edge-start");
1746 if (!numericaIDs && !reservedIDs && prefix == "" && !startGiven) {
1747 return 0;
1748 }
1749 std::vector<std::string> avoid;
1750 if (startGiven) {
1751 avoid.push_back(toString(OptionsCont::getOptions().getInt("numerical-ids.edge-start") - 1));
1752 } else {
1753 avoid = getAllNames();
1754 }
1755 std::set<std::string> reserve;
1756 if (reservedIDs) {
1757 NBHelpers::loadPrefixedIDsFomFile(OptionsCont::getOptions().getString("reserved-ids"), "edge:", reserve);
1758 avoid.insert(avoid.end(), reserve.begin(), reserve.end());
1759 }
1760 IDSupplier idSupplier("", avoid);
1761 std::set<NBEdge*, ComparatorIdLess> toChange;
1762 for (EdgeCont::iterator it = myEdges.begin(); it != myEdges.end(); it++) {
1763 if (startGiven) {
1764 toChange.insert(it->second);
1765 continue;
1766 }
1767 if (numericaIDs) {
1768 try {
1769 StringUtils::toLong(it->first);
1770 } catch (NumberFormatException&) {
1771 toChange.insert(it->second);
1772 }
1773 }
1774 if (reservedIDs && reserve.count(it->first) > 0) {
1775 toChange.insert(it->second);
1776 }
1777 }
1778 std::set<std::string> keep;
1779 if (keptIDs) {
1780 NBHelpers::loadPrefixedIDsFomFile(OptionsCont::getOptions().getString("kept-ids"), "edge:", keep);
1781 for (auto it = toChange.begin(); it != toChange.end();) {
1782 if (keep.count((*it)->getID()) != 0) {
1783 toChange.erase(it++);
1784 } else {
1785 it++;
1786 }
1787 }
1788 }
1789
1790 std::map<std::string, std::vector<std::shared_ptr<NBPTStop> > > stopsOnEdge;
1791 for (const auto& item : sc.getStops()) {
1792 stopsOnEdge[item.second->getEdgeId()].push_back(item.second);
1793 }
1794
1795 const bool origNames = OptionsCont::getOptions().getBool("output.original-names");
1796 for (NBEdge* edge : toChange) {
1797 myEdges.erase(edge->getID());
1798 }
1799 for (NBEdge* edge : toChange) {
1800 const std::string origID = edge->getID();
1801 if (origNames) {
1802 edge->setOrigID(origID, false);
1803 }
1804 edge->setID(idSupplier.getNext());
1805 myEdges[edge->getID()] = edge;
1806 for (std::shared_ptr<NBPTStop> stop : stopsOnEdge[origID]) {
1807 stop->setEdgeId(prefix + edge->getID(), *this);
1808 }
1809 }
1810 if (prefix.empty()) {
1811 return (int)toChange.size();
1812 } else {
1813 int renamed = 0;
1814 // make a copy because we will modify the map
1815 auto oldEdges = myEdges;
1816 for (auto item : oldEdges) {
1817 if (!StringUtils::startsWith(item.first, prefix) && keep.count(item.first) == 0) {
1818 rename(item.second, prefix + item.first);
1819 renamed++;
1820 }
1821 }
1822 return renamed;
1823 }
1824}
1825
1826
1827void
1828NBEdgeCont::checkOverlap(double threshold, double zThreshold) const {
1829 for (EdgeCont::const_iterator it = myEdges.begin(); it != myEdges.end(); it++) {
1830 const NBEdge* e1 = it->second;
1831 Boundary b1 = e1->getGeometry().getBoxBoundary();
1832 b1.grow(e1->getTotalWidth());
1833 PositionVector outline1 = e1->getCCWBoundaryLine(*e1->getFromNode());
1834 outline1.append(e1->getCCWBoundaryLine(*e1->getToNode()));
1835 // check is symmetric. only check once per pair
1836 for (EdgeCont::const_iterator it2 = it; it2 != myEdges.end(); it2++) {
1837 const NBEdge* e2 = it2->second;
1838 if (e1 == e2) {
1839 continue;
1840 }
1841 Boundary b2 = e2->getGeometry().getBoxBoundary();
1842 b2.grow(e2->getTotalWidth());
1843 if (b1.overlapsWith(b2)) {
1844 PositionVector outline2 = e2->getCCWBoundaryLine(*e2->getFromNode());
1845 outline2.append(e2->getCCWBoundaryLine(*e2->getToNode()));
1846 const double overlap = outline1.getOverlapWith(outline2, zThreshold);
1847 if (overlap > threshold) {
1848 WRITE_WARNINGF(TL("Edge '%' overlaps with edge '%' by %."), e1->getID(), e2->getID(), overlap);
1849 }
1850 }
1851 }
1852 }
1853}
1854
1855
1856void
1857NBEdgeCont::checkGrade(double threshold) const {
1858 for (EdgeCont::const_iterator it = myEdges.begin(); it != myEdges.end(); it++) {
1859 const NBEdge* edge = it->second;
1860 for (int i = 0; i < (int)edge->getNumLanes(); i++) {
1861 double maxJump = 0;
1862 const double grade = edge->getLaneShape(i).getMaxGrade(maxJump);
1863 if (maxJump > 0.01) {
1864 WRITE_WARNINGF(TL("Edge '%' has a vertical jump of %m."), edge->getID(), maxJump);
1865 } else if (grade > threshold) {
1866 WRITE_WARNINGF(TL("Edge '%' has a grade of %%."), edge->getID(), grade * 100, "%");
1867 break;
1868 }
1869 }
1870 const std::vector<NBEdge::Connection>& connections = edge->getConnections();
1871 for (std::vector<NBEdge::Connection>::const_iterator it_con = connections.begin(); it_con != connections.end(); ++it_con) {
1872 const NBEdge::Connection& c = *it_con;
1873 double maxJump = 0;
1874 const double grade = MAX2(c.shape.getMaxGrade(maxJump), c.viaShape.getMaxGrade(maxJump));
1875 if (maxJump > 0.01) {
1876 WRITE_WARNINGF(TL("Connection '%' has a vertical jump of %m."), c.getDescription(edge), maxJump);
1877 } else if (grade > threshold) {
1878 WRITE_WARNINGF(TL("Connection '%' has a grade of %%."), c.getDescription(edge), grade * 100, "%");
1879 break;
1880 }
1881 }
1882 }
1883}
1884
1885
1886int
1888 int affectedEdges = 0;
1889 for (auto item : myEdges) {
1890 if (item.second->joinLanes(perms)) {
1891 affectedEdges++;
1892 }
1893 }
1894 return affectedEdges;
1895}
1896
1897
1898bool
1899NBEdgeCont::MinLaneComparatorIdLess::operator()(const std::pair<NBEdge*, int>& a, const std::pair<NBEdge*, int>& b) const {
1900 if (a.first->getID() == b.first->getID()) {
1901 return a.second < b.second;
1902 }
1903 return a.first->getID() < b.first->getID();
1904}
1905
1906int
1908 // this is different from joinSimilarEdges because there don't need to be
1909 // shared nodes and tram edges may be split
1910 std::vector<NBEdge*> tramEdges;
1911 std::vector<NBEdge*> targetEdges;
1912 for (auto item : myEdges) {
1913 SVCPermissions permissions = item.second->getPermissions();
1914 if (isTram(permissions)) {
1915 if (item.second->getNumLanes() == 1) {
1916 tramEdges.push_back(item.second);
1917 } else {
1918 WRITE_WARNINGF(TL("Not joining tram edge '%' with % lanes."), item.second->getID(), item.second->getNumLanes());
1919 }
1920 } else if ((permissions & (SVC_PASSENGER | SVC_BUS)) != 0) {
1921 targetEdges.push_back(item.second);
1922 }
1923 }
1924 if (tramEdges.empty() || targetEdges.empty()) {
1925 return 0;
1926 }
1927 int numJoined = 0;
1928 NamedRTree tramTree;
1929 for (NBEdge* const edge : tramEdges) {
1930 const Boundary& bound = edge->getGeometry().getBoxBoundary();
1931 float min[2] = { static_cast<float>(bound.xmin()), static_cast<float>(bound.ymin()) };
1932 float max[2] = { static_cast<float>(bound.xmax()), static_cast<float>(bound.ymax()) };
1933 tramTree.Insert(min, max, edge);
1934 }
1935 // {targetEdge, laneIndex : tramEdge}
1936 std::map<std::pair<NBEdge*, int>, NBEdge*, MinLaneComparatorIdLess> matches;
1937
1938 for (NBEdge* const edge : targetEdges) {
1939 Boundary bound = edge->getGeometry().getBoxBoundary();
1940 bound.grow(maxDist + edge->getTotalWidth());
1941 float min[2] = { static_cast<float>(bound.xmin()), static_cast<float>(bound.ymin()) };
1942 float max[2] = { static_cast<float>(bound.xmax()), static_cast<float>(bound.ymax()) };
1943 std::set<const Named*> near;
1944 Named::StoringVisitor visitor(near);
1945 tramTree.Search(min, max, visitor);
1946 // the nearby set is actually just re-sorting according to the id to make the tests comparable
1947 std::set<NBEdge*, ComparatorIdLess> nearby;
1948 for (const Named* namedEdge : near) {
1949 nearby.insert(const_cast<NBEdge*>(static_cast<const NBEdge*>(namedEdge)));
1950 }
1951 for (NBEdge* const tramEdge : nearby) {
1952 // find a continous stretch of tramEdge that runs along one of the lanes of the road edge
1953 PositionVector tramShape = tramEdge->getGeometry();
1954 if (tramEdge->getToNode() == edge->getToNode()) {
1955 tramShape.extrapolate(tramShape.back().distanceTo2D(edge->getGeometry().back()), false, true);
1956 }
1957 double minEdgeDist = maxDist + 1;
1958 int minLane = -1;
1959 // find the lane where the maximum distance from the tram geometry
1960 // is minimal and within maxDist
1961 for (int i = 0; i < edge->getNumLanes(); i++) {
1962 double maxLaneDist = -1;
1963 if ((edge->getPermissions(i) & (SVC_PASSENGER | SVC_BUS)) != 0) {
1964 const PositionVector& laneShape = edge->getLaneShape(i);
1965 for (Position pos : laneShape) {
1966 const double dist = tramShape.distance2D(pos, false);
1967#ifdef DEBUG_JOIN_TRAM
1968 //if (edge->getID() == "106838214#1") {
1969 // std::cout << " edge=" << edge->getID() << " tramEdge=" << tramEdge->getID() << " lane=" << i << " pos=" << pos << " dist=" << dist << "\n";
1970 //}
1971#endif
1972 if (dist == GeomHelper::INVALID_OFFSET || dist > maxDist) {
1973 maxLaneDist = -1;
1974 break;
1975 }
1976 maxLaneDist = MAX2(maxLaneDist, dist);
1977 }
1978 if (maxLaneDist >= 0 && maxLaneDist < minEdgeDist) {
1979 minEdgeDist = maxLaneDist;
1980 minLane = i;
1981 }
1982 }
1983 }
1984 if (minLane >= 0) {
1985 // edge could run in the wrong direction and still fit the threshold we check the angle as well
1986 const PositionVector& laneShape = edge->getLaneShape(minLane);
1987 const double offset1 = tramShape.nearest_offset_to_point2D(laneShape.front(), false);
1988 const double offset2 = tramShape.nearest_offset_to_point2D(laneShape.back(), false);
1989 Position p1 = tramShape.positionAtOffset2D(offset1);
1990 Position p2 = tramShape.positionAtOffset2D(offset2);
1991 double tramAngle = GeomHelper::legacyDegree(p1.angleTo2D(p2), true);
1992 double laneAngle = GeomHelper::legacyDegree(laneShape[0].angleTo2D(laneShape[-1]), true);
1993 const double angleMismatch = MIN2(GeomHelper::getMinAngleDiff(tramAngle, edge->getTotalAngle()),
1994 GeomHelper::getMinAngleDiff(tramAngle, laneAngle));
1995 bool angleOK = angleMismatch < JOIN_TRAM_MAX_ANGLE;
1996 if (angleOK && offset2 > offset1) {
1997 std::pair<NBEdge*, int> key = std::make_pair(edge, minLane);
1998 if (matches.count(key) == 0) {
1999 matches[key] = tramEdge;
2000 } else {
2001 WRITE_WARNINGF(TL("Ambiguous tram edges '%' and '%' for lane '%'."), matches[key]->getID(), tramEdge->getID(), edge->getLaneID(minLane));
2002 }
2003#ifdef DEBUG_JOIN_TRAM
2004 std::cout << edge->getLaneID(minLane) << " is close to tramEdge " << tramEdge->getID() << " maxLaneDist=" << minEdgeDist << " tramLength=" << tramEdge->getLength() << " edgeLength=" << edge->getLength() << " tramAngle=" << tramAngle << " edgeAngle=" << edge->getTotalAngle() << "\n";
2005#endif
2006 }
2007 }
2008 }
2009 }
2010 if (matches.size() == 0) {
2011 return 0;
2012 }
2013 const bool origNames = OptionsCont::getOptions().getBool("output.original-names");
2014 // find continous runs of matched edges for each tramEdge
2015 for (NBEdge* tramEdge : tramEdges) {
2016 std::vector<std::pair<double, std::pair<NBEdge*, int> > > roads;
2017 for (auto item : matches) {
2018 if (item.second == tramEdge) {
2019 NBEdge* road = item.first.first;
2020 int laneIndex = item.first.second;
2021 const PositionVector& laneShape = road->getLaneShape(laneIndex);
2022 double tramPos = tramEdge->getGeometry().nearest_offset_to_point2D(laneShape.front(), false);
2023 //std::cout << " road=" << road->getID() << " tramEdge=" << tramEdge->getID() << " tramShape=" << tramEdge->getGeometry() << " laneFront=" << laneShape.front() << " tramPos=" << tramPos << "\n";
2024 roads.push_back(std::make_pair(tramPos, item.first));
2025 }
2026 }
2027 if (roads.size() != 0) {
2028
2029 sort(roads.begin(), roads.end());
2030#ifdef DEBUG_JOIN_TRAM
2031 std::cout << " tramEdge=" << tramEdge->getID() << " roads=";
2032 for (auto item : roads) {
2033 std::cout << item.second.first->getLaneID(item.second.second) << ",";
2034 }
2035 std::cout << " offsets=";
2036 for (auto item : roads) {
2037 std::cout << item.first << ",";
2038 }
2039 std::cout << "\n";
2040#endif
2041 // merge tramEdge into road lanes
2042 EdgeVector replacement;
2043 double pos = 0;
2044 int tramPart = 0;
2045 std::string tramEdgeID = tramEdge->getID();
2046 NBNode* tramFrom = tramEdge->getFromNode();
2047 PositionVector tramShape = tramEdge->getGeometry();
2048 const double tramLength = tramShape.length();
2049 EdgeVector incoming = tramFrom->getIncomingEdges();
2050 bool erasedLast = false;
2051 for (const auto& item : roads) {
2052 const double gap = item.first - pos;
2053 NBEdge* road = item.second.first;
2054 int laneIndex = item.second.second;
2055 if (gap >= JOIN_TRAM_MIN_LENGTH && road->getFromNode() != tramEdge->getFromNode()) {
2056#ifdef DEBUG_JOIN_TRAM
2057 std::cout << " splitting tramEdge=" << tramEdge->getID() << " at " << item.first << " (gap=" << gap << ")\n";
2058#endif
2059 const std::string firstPartID = tramEdgeID + "#" + toString(tramPart++);
2060 splitAt(dc, tramEdge, gap, road->getFromNode(), firstPartID, tramEdgeID, 1, 1);
2061 tramEdge = retrieve(tramEdgeID); // second part;
2062 NBEdge* firstPart = retrieve(firstPartID);
2063 firstPart->invalidateConnections(true);
2064 incoming.clear();
2065 incoming.push_back(firstPart);
2066 replacement.push_back(firstPart);
2067 }
2068 pos = item.first + road->getGeometry().length();
2069 numJoined++;
2070 replacement.push_back(road);
2071 // merge section of tramEdge into road lane
2072 if (road->getToNode() != tramEdge->getToNode() && (tramLength - pos) >= JOIN_TRAM_MIN_LENGTH) {
2073 tramEdge->reinitNodes(road->getToNode(), tramEdge->getToNode());
2074 tramEdge->setGeometry(tramShape.getSubpart(pos, tramShape.length()));
2075 erasedLast = false;
2076#ifdef DEBUG_JOIN_TRAM
2077 std::cout << " shorted tramEdge=" << tramEdge->getID() << " (joined with roadEdge=" << road->getID() << "\n";
2078#endif
2079 } else {
2080#ifdef DEBUG_JOIN_TRAM
2081 std::cout << " erased tramEdge=" << tramEdge->getID() << "\n";
2082#endif
2083 extract(dc, tramEdge, true);
2084 erasedLast = true;
2085 }
2086 road->setPermissions(road->getPermissions(laneIndex) | SVC_TRAM, laneIndex);
2087 if (origNames) {
2088 road->setOrigID(tramEdgeID, true, laneIndex);
2089 }
2090 for (NBEdge* in : incoming) {
2091 if (isTram(in->getPermissions()) && !in->isConnectedTo(road)) {
2092 if (in->getFromNode() != road->getFromNode()) {
2093 in->reinitNodes(in->getFromNode(), road->getFromNode());
2094 } else {
2095 extract(dc, in, true);
2096#ifdef DEBUG_JOIN_TRAM
2097 std::cout << " erased incoming tramEdge=" << in->getID() << "\n";
2098#endif
2099 }
2100 }
2101 }
2102 incoming.clear();
2103 }
2104 NBEdge* lastRoad = roads.back().second.first;
2105 if (erasedLast) {
2106 // copy to avoid concurrent modification
2107 auto outEdges = tramEdge->getToNode()->getOutgoingEdges();
2108 for (NBEdge* out : outEdges) {
2109 if (isTram(out->getPermissions()) && !lastRoad->isConnectedTo(out)) {
2110 if (lastRoad->getToNode() != out->getToNode()) {
2111 out->reinitNodes(lastRoad->getToNode(), out->getToNode());
2112 } else {
2113 extract(dc, out, true);
2114#ifdef DEBUG_JOIN_TRAM
2115 std::cout << " erased outgoing tramEdge=" << out->getID() << "\n";
2116#endif
2117
2118 }
2119 }
2120 }
2121 } else {
2122 replacement.push_back(tramEdge);
2123 }
2124 // update ptstops and ptlines
2125 sc.replaceEdge(tramEdgeID, replacement);
2126 lc.replaceEdge(tramEdgeID, replacement);
2127 }
2128 }
2129
2130 return numJoined;
2131}
2132
2133
2136 EdgeVector result;
2137 for (auto item : myEdges) {
2138 item.second->setNumericalID((int)result.size());
2139 result.push_back(item.second);
2140 }
2141 return result;
2142}
2143
2146 EdgeVector all = getAllEdges();
2147 return RouterEdgeVector(all.begin(), all.end());
2148}
2149
2150bool
2152 bool ok = true;
2153 for (const auto& item : myEdges) {
2154 NBEdge* e = item.second;
2155 if (nc.retrieve(e->getFromNode()->getID()) == nullptr) {
2156 WRITE_ERRORF(TL("Edge's '%' from-node '%' is not known."), e->getID(), e->getFromNode()->getID());
2157 ok = false;
2158 }
2159 if (nc.retrieve(e->getToNode()->getID()) == nullptr) {
2160 WRITE_ERRORF(TL("Edge's '%' to-node '%' is not known."), e->getID(), e->getToNode()->getID());
2161 ok = false;
2162 }
2163
2164 }
2165 return ok;
2166}
2167
2168
2169void
2171 for (auto item : myEdges) {
2172 NBEdge* e = item.second;
2173 if (e->hasLoadedLength() && myWasSplit.count(e) != 0) {
2174 // subtract half the length of the longest incoming / outgoing connection
2175 double maxLengthOut = 0;
2176 for (const NBEdge::Connection& c : e->getConnections()) {
2177 maxLengthOut = MAX2(maxLengthOut, c.length + c.viaLength);
2178 }
2179 double maxLengthIn = 0;
2180 for (const NBEdge* in : e->getIncomingEdges()) {
2181 for (const NBEdge::Connection& c : in->getConnectionsFromLane(-1, e, -1)) {
2182 maxLengthIn = MAX2(maxLengthIn, c.length + c.viaLength);
2183 }
2184 }
2185 e->setLoadedLength(MAX2(POSITION_EPS, e->getLoadedLength() - (maxLengthIn + maxLengthOut) / 2));
2186 }
2187 }
2188}
2189
2190void
2192 for (auto item : myEdges) {
2193 item.second->computeAngle();
2194 }
2195}
2196
2197
2198std::set<std::string>
2200 std::set<std::string> result;
2201 for (auto item : myEdges) {
2202 if (item.second->getTypeID() != "") {
2203 result.insert(item.second->getTypeID());
2204 }
2205 }
2206 return result;
2207}
2208
2209
2210int
2212 EdgeSet toRemove;
2213 for (const auto& item : myEdges) {
2214 NBEdge* edge = item.second;
2215 // remove edges which allow a speed below a set one (set using "keep-edges.min-speed")
2216 // explicit whitelist overrides removal
2217 if (edge->getSpeed() < myEdgesMinSpeed && myEdges2Keep.count(edge->getID()) == 0) {
2218 toRemove.insert(edge);
2219 }
2220 }
2221 const int numRemoved = (int)toRemove.size();
2222 for (NBEdge* edge : toRemove) {
2223 erase(dc, edge);
2224 }
2225 return numRemoved;
2226}
2227
2228
2229int
2231 EdgeSet toRemove;
2232 for (const auto& item : myEdges) {
2233 NBEdge* edge = item.second;
2234 // check whether the edge shall be removed because it does not allow any of the wished classes
2235 // explicit whitelist overrides removal
2236 if (myVehicleClasses2Keep != 0 && (myVehicleClasses2Keep & edge->getPermissions()) == 0 && myEdges2Keep.count(edge->getID()) == 0) {
2237 toRemove.insert(edge);
2238 }
2239 // check whether the edge shall be removed due to allowing unwished classes only
2240 // explicit whitelist overrides removal
2242 toRemove.insert(edge);
2243 }
2244 }
2245 const int numRemoved = (int)toRemove.size();
2246 for (NBEdge* edge : toRemove) {
2247 erase(dc, edge);
2248 }
2249 return numRemoved;
2250}
2251
2252
2253int
2255 EdgeSet toRemove;
2256 for (auto item : myEdges) {
2257 NBEdge* const edge = item.second;
2258 std::vector<int> indices;
2259 int idx = 0;
2260 for (const auto& lane : edge->getLanes()) {
2261 if (lane.width != NBEdge::UNSPECIFIED_WIDTH && lane.width < minWidth) {
2262 indices.push_back(idx);
2263 }
2264 idx++;
2265 }
2266 if ((int)indices.size() == edge->getNumLanes()) {
2267 toRemove.insert(edge);
2268 } else {
2269 std::reverse(indices.begin(), indices.end());
2270 for (const int i : indices) {
2271 edge->deleteLane(i, false, true);
2272 }
2273 }
2274 }
2275 int numRemoved = 0;
2276 for (NBEdge* edge : toRemove) {
2277 // explicit whitelist overrides removal
2278 if (myEdges2Keep.size() == 0 || myEdges2Keep.count(edge->getID()) == 0) {
2279 extract(dc, edge);
2280 numRemoved++;
2281 }
2282 }
2283 return numRemoved;
2284}
2285
2286
2287int
2288NBEdgeCont::attachRemoved(NBNodeCont& nc, NBDistrictCont& dc, const double maxDist) {
2289 int numSplit = 0;
2290 std::map<std::string, std::vector<std::string> > node2edge;
2291 for (auto item : myEdges) {
2292 if (item.second->hasParameter(SUMO_PARAM_REMOVED_NODES)) {
2293 for (std::string& nodeID : StringTokenizer(item.second->getParameter(SUMO_PARAM_REMOVED_NODES)).getVector()) {
2294 node2edge[nodeID].push_back(item.first);
2295 }
2296 }
2297 }
2298 for (auto item : nc) {
2299 NBNode* n = item.second;
2300 auto itRN = node2edge.find(n->getID());
2301 if (itRN != node2edge.end()) {
2302 bool rebuildConnections = false;
2303 // make a copy because we modify the original
2304 std::vector<std::string> edgeIDs = itRN->second;
2305 for (const std::string& eID : edgeIDs) {
2306 NBEdge* edge = retrieve(eID);
2307 assert(edge != nullptr);
2308 const double dist = edge->getGeometry().distance2D(n->getPosition(), true);
2309 if (dist != GeomHelper::INVALID_OFFSET && dist <= maxDist) {
2310 std::string idAfter = edge->getID();
2311 int index = 1;
2312 size_t spos = idAfter.find("#");
2313 if (spos != std::string::npos && spos > 1) {
2314 idAfter = idAfter.substr(0, spos);
2315 }
2316 while (retrieve(idAfter + "#" + toString(index), true) != nullptr) {
2317 index++;
2318 }
2319 idAfter += "#" + toString(index);
2320 const bool ok = splitAt(dc, edge, n, edge->getID(), idAfter, edge->getNumLanes(), edge->getNumLanes());
2321 if (ok) {
2322 rebuildConnections = true;
2323 numSplit++;
2324 NBEdge* secondEdge = retrieve(eID); // original was extracted on splitting
2325 for (std::string& nodeID : StringTokenizer(secondEdge->getParameter(SUMO_PARAM_REMOVED_NODES)).getVector()) {
2326 node2edge[nodeID].push_back(idAfter);
2327 }
2328 }
2329 }
2330 }
2331 if (rebuildConnections) {
2332 for (NBEdge* e : n->getIncomingEdges()) {
2333 e->invalidateConnections(true);
2334 }
2335 }
2336 }
2337 }
2338 return numSplit;
2339}
2340
2341/****************************************************************************/
#define DEG2RAD(x)
Definition GeomHelper.h:35
std::vector< std::string > & split(const std::string &s, char delim, std::vector< std::string > &elems)
#define WRITE_WARNINGF(...)
Definition MsgHandler.h:287
#define WRITE_ERRORF(...)
Definition MsgHandler.h:296
#define WRITE_ERROR(msg)
Definition MsgHandler.h:295
#define WRITE_WARNING(msg)
Definition MsgHandler.h:286
#define TL(string)
Definition MsgHandler.h:304
#define TLF(string,...)
Definition MsgHandler.h:306
std::set< NBEdge * > EdgeSet
container for unique edges
Definition NBCont.h:50
std::vector< NBEdge * > EdgeVector
container for (sorted) edges
Definition NBCont.h:42
KeepClear
keepClear status of connections
Definition NBCont.h:58
@ KEEPCLEAR_UNSPECIFIED
Definition NBCont.h:61
std::vector< NBRouterEdge * > RouterEdgeVector
Definition NBCont.h:43
#define JOIN_TRAM_MIN_LENGTH
#define JOIN_TRAM_MAX_ANGLE
#define DEBUG_EDGE_ID
const SVCPermissions SVCAll
all VClasses are allowed
bool isRailway(SVCPermissions permissions)
Returns whether an edge with the given permissions is a (exclusive) railway edge.
bool isTram(SVCPermissions permissions)
Returns whether an edge with the given permissions is a tram edge.
SVCPermissions parseVehicleClasses(const std::string &allowedS)
Parses the given definition of allowed vehicle classes into the given containers Deprecated classes g...
long long int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
SUMOVehicleClass
Definition of vehicle classes to differ between different lane usage and authority types.
@ SVC_PASSENGER
vehicle is a passenger car (a "normal" car)
@ SVC_TRAM
vehicle is a light rail
@ SVC_PUBLIC_CLASSES
public transport
@ SVC_BUS
vehicle is a bus
@ SVC_PEDESTRIAN
pedestrian
const std::string SUMO_PARAM_ORIGID
const std::string SUMO_PARAM_REMOVED_NODES
SumoXMLNodeType
Numbers representing special SUMO-XML-attribute values for representing node- (junction-) types used ...
bool gDebugFlag1
global utility flags for debugging
Definition StdDefs.cpp:44
const double SUMO_const_laneWidth
Definition StdDefs.h:52
T MIN2(T a, T b)
Definition StdDefs.h:80
const double SUMO_const_haltingSpeed
the speed threshold at which vehicles are considered as halting
Definition StdDefs.h:62
T MAX2(T a, T b)
Definition StdDefs.h:86
const double SUMO_const_halfLaneWidth
Definition StdDefs.h:53
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:57
A class that stores a 2D geometrical boundary.
Definition Boundary.h:39
double ymin() const
Returns minimum y-coordinate.
Definition Boundary.cpp:127
double xmin() const
Returns minimum x-coordinate.
Definition Boundary.cpp:115
Boundary & grow(double by)
extends the boundary by the given amount
Definition Boundary.cpp:340
bool overlapsWith(const AbstractPoly &poly, double offset=0) const
Returns whether the boundary overlaps with the given polygon.
Definition Boundary.cpp:194
double ymax() const
Returns maximum y-coordinate.
Definition Boundary.cpp:133
double xmax() const
Returns maximum x-coordinate.
Definition Boundary.cpp:121
static GeoConvHelper & getProcessing()
the coordinate transformation to use for input conversion and processing
bool x2cartesian_const(Position &from) const
Converts the given coordinate into a cartesian using the previous initialisation.
static GeoConvHelper & getLoaded()
the coordinate transformation that was loaded fron an input file
static PositionVector parseShapeReporting(const std::string &shpdef, const std::string &objecttype, const char *objectid, bool &ok, bool allowEmpty, bool report=true)
Builds a PositionVector from a string representation, reporting occurred errors.
static const double INVALID_OFFSET
a value to signify offsets outside the range of [0, Line.length()]
Definition GeomHelper.h:50
static double nearest_offset_on_line_to_point2D(const Position &lineStart, const Position &lineEnd, const Position &p, bool perpendicular=true)
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.
std::string getNext()
Returns the next id.
static void nextCW(const EdgeVector &edges, EdgeVector::const_iterator &from)
A container for districts.
void removeFromSinksAndSources(NBEdge *const e)
Removes the given edge from the lists of sources and sinks in all stored districts.
Sorts splits by their position (increasing)
Definition NBEdgeCont.h:805
void patchRoundabouts(NBEdge *orig, NBEdge *part1, NBEdge *part2, std::set< EdgeSet > &roundabouts)
fix roundabout information after splitting an edge
void computeEdgeShapes(double smoothElevationThreshold=-1)
Computes the shapes of all edges stored in the container.
NBEdge * getByID(const std::string &edgeID) const
Returns the edge with id if it exists.
const std::set< EdgeSet > getRoundabouts() const
Returns the determined roundabouts.
void computeEdge2Edges(bool noLeftMovers)
Computes for each edge the approached edges.
int guessRoundabouts()
Determines which edges belong to roundabouts and increases their priority.
bool myNeedGeoTransformedPruningBoundary
whether a geo transform has been applied to the pruning boundary
Definition NBEdgeCont.h:793
~NBEdgeCont()
Destructor.
void sortOutgoingLanesConnections()
Sorts all lanes of all edges within the container by their direction.
void addRoundabout(const EdgeSet &roundabout)
add user specified roundabout
std::set< EdgeSet > myRoundabouts
Edges marked as belonging to a roundabout by the user (each EdgeVector is a roundabout)
Definition NBEdgeCont.h:797
void appendRailwayTurnarounds(const NBPTStopCont &sc)
Appends turnarounds to all bidiRail edges with stops.
std::set< std::string > myEdges2Remove
Set of ids of edges which shall explicitly be removed.
Definition NBEdgeCont.h:775
std::set< std::string > myIgnoredEdges
The ids of ignored edges.
Definition NBEdgeCont.h:755
void updateAllChangeRestrictions(SVCPermissions ignoring)
modify all restrictions on lane changing for edges and connections
double myEdgesMinSpeed
The minimum speed an edge may have in order to be kept (default: -1)
Definition NBEdgeCont.h:766
void recheckPostProcessConnections()
Try to set any stored connections.
void extract(NBDistrictCont &dc, NBEdge *edge, bool remember=false)
Removes the given edge from the container like erase but does not delete it.
void processSplits(NBEdge *e, std::vector< Split > splits, NBNodeCont &nc, NBDistrictCont &dc, NBTrafficLightLogicCont &tlc)
process splits
EdgeVector getAllEdges() const
return all edges
void erase(NBDistrictCont &dc, NBEdge *edge)
Removes the given edge from the container (deleting it)
NBEdge * retrieve(const std::string &id, bool retrieveExtracted=false) const
Returns the edge that has the given id.
std::set< std::string > myTypes2Keep
Set of edges types which shall be kept.
Definition NBEdgeCont.h:784
void recheckLanes()
Rechecks whether all lanes have a successor for each of the stored edges.
NBEdge * getOppositeByID(const std::string &edgeID) const
Returns the edge with negated id if it exists.
void checkGeometries(const double maxAngle, bool fixAngle, const double minRadius, bool fix, bool fixRailways, bool silent=false)
EdgeCont myExtractedEdges
The extracted edges which are kept for reference.
Definition NBEdgeCont.h:749
std::string createUnusedID(const std::string &base, const std::string &sep)
if base is an existing edge id, find a unused id of the form base + sep + INT
void reduceGeometries(const double minDist)
void recheckLaneSpread()
Rechecks whether the lane spread is proper.
bool ignoreFilterMatch(NBEdge *edge)
Returns true if this edge matches one of the removal criteria.
void removeRoundabout(const NBNode *node)
remove roundabout that contains the given node
void cleanupRoundabouts()
void splitGeometry(NBDistrictCont &dc, NBNodeCont &nc)
Splits edges into multiple if they have a complex geometry.
void addPostProcessConnection(const std::string &from, int fromLane, const std::string &to, int toLane, bool mayDefinitelyPass, KeepClear keepClear, double contPos, double visibility, double speed, double friction, double length, const PositionVector &customShape, bool uncontrolled, bool warnOnly, SVCPermissions permissions=SVC_UNSPECIFIED, bool indirectLeft=false, const std::string &edgeType="", SVCPermissions changeLeft=SVC_UNSPECIFIED, SVCPermissions changeRight=SVC_UNSPECIFIED)
Adds a connection which could not be set during loading.
std::set< std::string > getUsedTypes() const
return all edge types in used
void computeLanes2Edges()
Computes for each edge which lanes approach the next edges.
int extractRoundabouts()
Determines which edges have been marked as roundabouts and stores them internally.
NBEdge * retrievePossiblySplit(const std::string &id, bool downstream) const
Tries to retrieve an edge, even if it is splitted.
RouterEdgeVector getAllRouterEdges() const
return all router edges
std::set< const NBEdge * > myWasSplit
the edges that were created as result of splitting
Definition NBEdgeCont.h:760
void rename(NBEdge *edge, const std::string &newID)
Renames the edge. Throws exception if newID already exists.
int joinTramEdges(NBDistrictCont &dc, NBPTStopCont &sc, NBPTLineCont &lc, double maxDist)
join tram edges into adjacent lanes
bool hasPostProcessConnection(const std::string &from, const std::string &to="")
add post process connections
EdgeCont myEdges
The instance of the dictionary (id->edge)
Definition NBEdgeCont.h:746
int removeUnwishedEdges(NBDistrictCont &dc)
Removes unwished edges (not in keep-edges)
std::set< std::string > myEdges2Keep
Set of ids of edges which shall explicitly be kept.
Definition NBEdgeCont.h:772
NBTypeCont & myTypeCont
The network builder; used to obtain type information.
Definition NBEdgeCont.h:636
void generateStreetSigns()
assigns street signs to edges based on toNode types
void clearControllingTLInformation() const
Clears information about controlling traffic lights for all connenections of all edges.
std::set< EdgeSet > myGuessedRoundabouts
Edges marked as belonging to a roundabout after guessing.
Definition NBEdgeCont.h:800
void computeAngles()
compute all edge angles
void clear()
Deletes all edges.
void guessOpposites()
Sets opposite lane information for geometrically close edges.
void markRoundabouts()
mark edge priorities and prohibit turn-arounds for all roundabout edges
std::set< std::string > myTypes2Remove
Set of edges types which shall be removed.
Definition NBEdgeCont.h:787
void applyOptions(OptionsCont &oc)
Initialises the storage by applying given options.
void removeRoundaboutEdges(const EdgeSet &toRemove)
remove edges from all stored roundabouts
PositionVector myPruningBoundary
Boundary within which an edge must be located in order to be kept.
Definition NBEdgeCont.h:790
int joinLanes(SVCPermissions perms)
join adjacent lanes with the given permissions
void checkOverlap(double threshold, double zThreshold) const
check whether edges overlap
SVCPermissions myVehicleClasses2Remove
Set of vehicle types which need not be supported (edges which allow ONLY these are removed)
Definition NBEdgeCont.h:781
int guessSpecialLanes(SUMOVehicleClass svc, double width, double minSpeed, double maxSpeed, bool fromPermissions, const std::string &excludeOpt, NBTrafficLightLogicCont &tlc)
add sidwalks to edges within the given limits or permissions and return the number of edges affected
EdgeVector getGeneratedFrom(const std::string &id) const
Returns the edges which have been built by splitting the edge of the given id.
void appendTurnarounds(bool noTLSControlled, bool noFringe, bool onlyDeadends, bool onlyTurnlane, bool noGeometryLike)
Appends turnarounds to all edges stored in the container.
SVCPermissions myVehicleClasses2Keep
Set of vehicle types which must be allowed on edges in order to keep them.
Definition NBEdgeCont.h:778
void computeLaneShapes()
Computes the shapes of all lanes of all edges stored in the container.
void joinSameNodeConnectingEdges(NBDistrictCont &dc, NBTrafficLightLogicCont &tlc, EdgeVector edges)
Joins the given edges because they connect the same nodes.
std::map< std::string, NBEdge * > EdgeCont
The type of the dictionary where an edge may be found by its id.
Definition NBEdgeCont.h:743
void addPrefix(const std::string &prefix)
add prefix to all edges
void fixSplitCustomLength()
adapt custom lengths of split edges to account for intersection size
std::map< const NBEdge *, std::pair< NBEdge *, NBEdge * > > myEdgesSplit
the number of splits of edges during the building
Definition NBEdgeCont.h:758
NBEdge * getSplitBase(const std::string &edgeID) const
std::map< std::string, std::vector< PostProcessConnection > > myConnections
The list of connections to recheck.
Definition NBEdgeCont.h:740
bool insert(NBEdge *edge, bool ignorePrunning=false)
Adds an edge to the dictionary.
NBEdgeCont(NBTypeCont &tc)
Constructor.
std::set< NBEdge * > myEdgeCemetery
The edges which got extracted twice but may still be referenced somewhere TODO smart_ptr?
Definition NBEdgeCont.h:752
bool checkConsistency(const NBNodeCont &nc)
ensure that all edges have valid nodes
static double formFactor(const EdgeVector &loopEdges)
compute the form factor for a loop of edges
int removeLanesByWidth(NBDistrictCont &dc, const double minWidth)
bool splitAt(NBDistrictCont &dc, NBEdge *edge, NBNode *node)
Splits the edge at the position nearest to the given node.
std::vector< std::string > getAllNames() const
Returns all ids of known edges.
int removeEdgesBySpeed(NBDistrictCont &dc)
return number of edges removed
int remapIDs(bool numericaIDs, bool reservedIDs, bool keptIDs, const std::string &prefix, NBPTStopCont &sc)
remap node IDs accoring to options –numerical-ids and –reserved-ids
void checkGrade(double threshold) const
check whether edges are to steep
int attachRemoved(NBNodeCont &nc, NBDistrictCont &dc, const double maxDist)
return number of edges split
int removeEdgesByPermissions(NBDistrictCont &dc)
bool myRemoveEdgesAfterLoading
Whether edges shall be joined and patched first, then removed.
Definition NBEdgeCont.h:769
The representation of a single edge during network building.
Definition NBEdge.h:92
NBEdge * guessOpposite(bool reguess=false)
set oppositeID and return opposite edge if found
Definition NBEdge.cpp:5068
double getLength() const
Returns the computed length of the edge.
Definition NBEdge.h:599
SVCPermissions getPermissions(int lane=-1) const
get the union of allowed classes over all lanes or for a specific lane
Definition NBEdge.cpp:4543
const std::vector< Connection > & getConnections() const
Returns the connections.
Definition NBEdge.h:1047
void setPermissions(SVCPermissions permissions, int lane=-1)
set allowed/disallowed classes for the given lane or for all lanes if -1 is given
Definition NBEdge.cpp:4506
@ ROUNDABOUT
Definition NBEdge.h:387
double getLoadedLength() const
Returns the length was set explicitly or the computed length if it wasn't set.
Definition NBEdge.h:608
void recheckOpposite(const NBEdgeCont &ec, bool fixOppositeLengths)
recheck whether all opposite and bidi settings are consistent
Definition NBEdge.cpp:3201
void setSpeed(int lane, double speed)
set lane specific speed (negative lane implies set for all lanes)
Definition NBEdge.cpp:4458
NBNode * getToNode() const
Returns the destination node of the edge.
Definition NBEdge.h:552
PositionVector getCCWBoundaryLine(const NBNode &n) const
get the outer boundary of this edge when going counter-clock-wise around the given node
Definition NBEdge.cpp:3961
static const double UNSPECIFIED_FRICTION
unspecified lane friction
Definition NBEdge.h:355
void incLaneNo(int by)
increment lane
Definition NBEdge.cpp:4239
Lane & getLaneStruct(int lane)
Definition NBEdge.h:1451
void setAverageLengthWithOpposite(double val)
patch average lane length in regard to the opposite edge
Definition NBEdge.cpp:4563
void disallowVehicleClass(int lane, SUMOVehicleClass vclass)
set disallowed class for the given lane or for all lanes if -1 is given
Definition NBEdge.cpp:4302
const PositionVector & getGeometry() const
Returns the geometry of the edge.
Definition NBEdge.h:789
LaneSpreadFunction getLaneSpreadFunction() const
Returns how this edge's lanes' lateral offset is computed.
Definition NBEdge.cpp:1021
bool isBidiRail(bool ignoreSpread=false) const
whether this edge is part of a bidirectional railway
Definition NBEdge.cpp:772
void dismissVehicleClassInformation()
dimiss vehicle class information
Definition NBEdge.cpp:4569
EdgeBuildingStep getStep() const
The building step of this edge.
Definition NBEdge.h:641
LaneSpreadFunction myLaneSpreadFunction
The information about how to spread the lanes.
Definition NBEdge.h:1814
bool hasLoadedLength() const
Returns whether a length was set explicitly.
Definition NBEdge.h:618
bool addEdge2EdgeConnection(NBEdge *dest, bool overrideRemoval=false, SVCPermissions permission=SVC_UNSPECIFIED)
Adds a connection to another edge.
Definition NBEdge.cpp:1120
bool addLane2LaneConnection(int fromLane, NBEdge *dest, int toLane, Lane2LaneInfoType type, bool mayUseSameDestination=false, bool mayDefinitelyPass=false, KeepClear keepClear=KEEPCLEAR_UNSPECIFIED, double contPos=UNSPECIFIED_CONTPOS, double visibility=UNSPECIFIED_VISIBILITY_DISTANCE, double speed=UNSPECIFIED_SPEED, double friction=UNSPECIFIED_FRICTION, double length=myDefaultConnectionLength, const PositionVector &customShape=PositionVector::EMPTY, const bool uncontrolled=UNSPECIFIED_CONNECTION_UNCONTROLLED, SVCPermissions permissions=SVC_UNSPECIFIED, const bool indirectLeft=false, const std::string &edgeType="", SVCPermissions changeLeft=SVC_UNSPECIFIED, SVCPermissions changeRight=SVC_UNSPECIFIED, bool postProcess=false)
Adds a connection between the specified this edge's lane and an approached one.
Definition NBEdge.cpp:1156
void setDistance(double distance)
set kilometrage at start of edge (negative value implies couting down along the edge)
Definition NBEdge.h:1425
const std::vector< NBEdge::Lane > & getLanes() const
Returns the lane definitions.
Definition NBEdge.h:736
@ LANES2LANES_DONE
Lanes to lanes - relationships are computed; no recheck is necessary/wished.
@ LANES2LANES_USER
Lanes to lanes - relationships are loaded; no recheck is necessary/wished.
double getSpeed() const
Returns the speed allowed on this edge.
Definition NBEdge.h:625
NBNode * myTo
Definition NBEdge.h:1763
const std::string & getID() const
Definition NBEdge.h:1551
double getDistance() const
get distance
Definition NBEdge.h:685
void setLaneWidth(int lane, double width)
set lane specific width (negative lane implies set for all lanes)
Definition NBEdge.cpp:4329
void setLaneSpreadFunction(LaneSpreadFunction spread)
(Re)sets how the lanes lateral offset shall be computed
Definition NBEdge.cpp:1015
std::vector< Lane > myLanes
Lane information.
Definition NBEdge.h:1831
int getNumLanes() const
Returns the number of lanes.
Definition NBEdge.h:526
void setFriction(int lane, double friction)
set lane specific friction (negative lane implies set for all lanes)
Definition NBEdge.cpp:4474
static const double UNSPECIFIED_CONTPOS
unspecified internal junction position
Definition NBEdge.h:358
void addRestrictedLane(double width, SUMOVehicleClass vclass)
add a lane of the given width, restricted to the given class and shift existing connections
Definition NBEdge.cpp:4771
void removeFromConnections(NBEdge *toEdge, int fromLane=-1, int toLane=-1, bool tryLater=false, const bool adaptToLaneRemoval=false, const bool keepPossibleTurns=false)
Removes the specified connection(s)
Definition NBEdge.cpp:1473
void invalidateConnections(bool reallowSetting=false)
invalidate current connections of edge
Definition NBEdge.cpp:1554
double getTotalWidth() const
Returns the combined width of all lanes of this edge.
Definition NBEdge.cpp:4381
static const double UNSPECIFIED_VISIBILITY_DISTANCE
unspecified foe visibility for connections
Definition NBEdge.h:361
bool isConnectedTo(const NBEdge *e, const bool ignoreTurnaround=false) const
Returns the information whethe a connection to the given edge has been added (or computed)
Definition NBEdge.cpp:1354
void addSign(NBSign sign)
add Sign
Definition NBEdge.h:1483
void deleteLane(int index, bool recompute, bool shiftIndices)
delete lane
Definition NBEdge.cpp:4250
void moveOutgoingConnectionsFrom(NBEdge *e, int laneOff)
move outgoing connection
Definition NBEdge.cpp:3837
std::string getLaneID(int lane) const
get lane ID
Definition NBEdge.cpp:4181
@ USER
The connection was given by the user.
@ VALIDATED
The connection was computed and validated.
@ COMPUTED
The connection was computed.
double getStartAngle() const
Returns the angle at the start of the edge (relative to the node shape center) The angle is computed ...
Definition NBEdge.h:561
bool setConnection(int lane, NBEdge *destEdge, int destLane, Lane2LaneInfoType type, bool mayUseSameDestination=false, bool mayDefinitelyPass=false, KeepClear keepClear=KEEPCLEAR_UNSPECIFIED, double contPos=UNSPECIFIED_CONTPOS, double visibility=UNSPECIFIED_VISIBILITY_DISTANCE, double speed=UNSPECIFIED_SPEED, double friction=UNSPECIFIED_FRICTION, double length=myDefaultConnectionLength, const PositionVector &customShape=PositionVector::EMPTY, const bool uncontrolled=UNSPECIFIED_CONNECTION_UNCONTROLLED, SVCPermissions permissions=SVC_UNSPECIFIED, bool indirectLeft=false, const std::string &edgeType="", SVCPermissions changeLeft=SVC_UNSPECIFIED, SVCPermissions changeRight=SVC_UNSPECIFIED, bool postProcess=false)
Adds a connection to a certain lane of a certain edge.
Definition NBEdge.cpp:1209
int getJunctionPriority(const NBNode *const node) const
Returns the junction priority (normalised for the node currently build)
Definition NBEdge.cpp:2160
const std::string & getTypeID() const
get ID of type
Definition NBEdge.h:1187
const std::string & getStreetName() const
Returns the street name of this edge.
Definition NBEdge.h:675
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition NBEdge.h:545
NBEdge * getTurnDestination(bool possibleDestination=false) const
Definition NBEdge.cpp:4172
double getAngleAtNode(const NBNode *const node) const
Returns the angle of the edge's geometry at the given node.
Definition NBEdge.cpp:2186
bool isBidi() const
return whether this edge should be a bidi edge
Definition NBEdge.h:1435
static const double UNSPECIFIED_WIDTH
unspecified lane width
Definition NBEdge.h:346
bool hasRestrictedLane(SUMOVehicleClass vclass) const
returns whether any lane already allows the given vclass exclusively
Definition NBEdge.cpp:4760
void copyConnectionsFrom(NBEdge *src)
copy connections from antoher edge
Definition NBEdge.cpp:1669
double getEndAngle() const
Returns the angle at the end of the edge (relative to the node shape center) The angle is computed in...
Definition NBEdge.h:570
void declareConnectionsAsLoaded(EdgeBuildingStep step=EdgeBuildingStep::LANES2LANES_USER)
declares connections as fully loaded. This is needed to avoid recomputing connections if an edge has ...
Definition NBEdge.h:1465
void setEndOffset(int lane, double offset)
set lane specific end-offset (negative lane implies set for all lanes)
Definition NBEdge.cpp:4412
static const double UNSPECIFIED_OFFSET
unspecified lane offset
Definition NBEdge.h:349
bool recheckLanes()
recheck whether all lanes within the edge are all right and optimises the connections once again
Definition NBEdge.cpp:2957
void setOrigID(const std::string origID, const bool append, const int laneIdx=-1)
set origID for all lanes or for a specific lane
Definition NBEdge.cpp:4916
const PositionVector & getLaneShape(int i) const
Returns the shape of the nth lane.
Definition NBEdge.cpp:1009
void setLoadedLength(double val)
set loaded length
Definition NBEdge.cpp:4558
void decLaneNo(int by)
decrement lane
Definition NBEdge.cpp:4270
NBNode * myFrom
The source and the destination node.
Definition NBEdge.h:1763
void setGeometry(const PositionVector &g, bool inner=false)
(Re)sets the edge's geometry
Definition NBEdge.cpp:660
EdgeVector getIncomingEdges() const
Returns the list of incoming edges unsorted.
Definition NBEdge.cpp:1416
static void loadPrefixedIDsFomFile(const std::string &file, const std::string prefix, std::set< std::string > &into)
Add prefixed ids defined in file.
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
static void loadEdgesFromFile(const std::string &file, std::set< std::string > &into)
Add edge ids defined in file (either ID or edge:ID per line) into the given set.
Definition NBHelpers.cpp:86
static bool transformCoordinates(PositionVector &from, bool includeInBoundary=true, GeoConvHelper *from_srs=nullptr)
Container for nodes during the netbuilding process.
Definition NBNodeCont.h:57
bool insert(const std::string &id, const Position &position, NBDistrict *district=0)
Inserts a node into the map.
NBNode * retrieve(const std::string &id) const
Returns the node with the given name.
void markAsSplit(const NBNode *node)
mark a node as being created form a split
Definition NBNodeCont.h:371
Represents a single node (junction) during network building.
Definition NBNode.h:66
void invalidateOutgoingConnections(bool reallowSetting=false)
invalidate outgoing connections
Definition NBNode.cpp:2145
void removeEdge(NBEdge *edge, bool removeFromConnections=true)
Removes edge from this node and optionally removes connections as well.
Definition NBNode.cpp:2076
const std::set< NBTrafficLightDefinition * > & getControllingTLS() const
Returns the traffic lights that were assigned to this node (The set of tls that control this node)
Definition NBNode.h:347
bool isSimpleContinuation(bool checkLaneNumbers=true, bool checkWidth=false) const
check if node is a simple continuation
Definition NBNode.cpp:561
void recheckVClassConnections(NBEdge *currentOutgoing)
ensure connectivity for all vClasses
Definition NBNode.cpp:1549
SumoXMLNodeType getType() const
Returns the type of this node.
Definition NBNode.h:287
const EdgeVector & getIncomingEdges() const
Returns this node's incoming edges (The edges which yield in this node)
Definition NBNode.h:270
void invalidateTLS(NBTrafficLightLogicCont &tlCont, bool addedConnections, bool removedConnections)
causes the traffic light to be computed anew
Definition NBNode.cpp:477
const EdgeVector & getOutgoingEdges() const
Returns this node's outgoing edges (The edges which start at this node)
Definition NBNode.h:275
void replaceOutgoing(NBEdge *which, NBEdge *by, int laneOff)
Replaces occurrences of the first edge within the list of outgoing by the second Connections are rema...
Definition NBNode.cpp:1861
void replaceIncoming(NBEdge *which, NBEdge *by, int laneOff)
Replaces occurrences of the first edge within the list of incoming by the second Connections are rema...
Definition NBNode.cpp:1897
const Position & getPosition() const
Definition NBNode.h:262
const EdgeVector & getEdges() const
Returns all edges which participate in this node (Edges that start or end at this node)
Definition NBNode.h:280
bool typeWasGuessed() const
return whether a priority road turns at this node
Definition NBNode.h:859
RoundaboutType getRoundaboutType() const
Returns roundabout type.
Definition NBNode.h:312
void removeDoubleEdges()
remove duble edges
Definition NBNode.cpp:1965
NBEdge * getConnectionTo(NBNode *n) const
get connection to certain node
Definition NBNode.cpp:2810
void replaceEdge(const std::string &edgeID, const EdgeVector &replacement)
replace the edge with the given edge list in all lines
Container for public transport stops during the net building process.
void replaceEdge(const std::string &edgeID, const std::vector< NBEdge * > &replacement)
replace the edge with the closes edge on the given edge list in all stops
const std::map< std::string, std::shared_ptr< NBPTStop > > & getStops() const
Returns an unmodifiable reference to the stored pt stops.
A class representing a single street sign.
Definition NBSign.h:41
@ SIGN_TYPE_ALLWAY_STOP
Definition NBSign.h:48
@ SIGN_TYPE_YIELD
Definition NBSign.h:46
@ SIGN_TYPE_STOP
Definition NBSign.h:47
@ SIGN_TYPE_PRIORITY
Definition NBSign.h:50
@ SIGN_TYPE_RIGHT_BEFORE_LEFT
Definition NBSign.h:51
@ SIGN_TYPE_LEFT_BEFORE_RIGHT
Definition NBSign.h:52
The base class for traffic light logic definitions.
A container for traffic light definitions and built programs.
void replaceRemoved(NBEdge *removed, int removedLane, NBEdge *by, int byLane, bool incoming)
Replaces occurrences of the removed edge/lane in all definitions by the given edge.
A storage for available edgeTypes of edges.
Definition NBTypeCont.h:52
bool getEdgeTypeShallBeDiscarded(const std::string &edgeType) const
Returns the information whether edges of this edgeType shall be discarded.
bool knows(const std::string &edgeType) const
Returns whether the named edgeType is in the container.
Allows to store the object; used as context while traveling the rtree in TraCI.
Definition Named.h:89
Base class for objects which have an id.
Definition Named.h:53
virtual void setID(const std::string &newID)
resets the id
Definition Named.h:81
static std::string getIDSecure(const T *obj, const std::string &fallBack="NULL")
get an identifier for Named-like object which may be Null
Definition Named.h:66
const std::string & getID() const
Returns the id.
Definition Named.h:73
A RT-tree for efficient storing of SUMO's Named objects.
Definition NamedRTree.h:61
void Insert(const float a_min[2], const float a_max[2], Named *const &a_data)
Insert entry.
Definition NamedRTree.h:79
int Search(const float a_min[2], const float a_max[2], const Named::StoringVisitor &c) const
Find all within search rectangle.
Definition NamedRTree.h:112
A storage for options typed value containers)
Definition OptionsCont.h:89
bool isSet(const std::string &name, bool failOnNonExistant=true) const
Returns the information whether the named option is set.
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
std::string getString(const std::string &name) const
Returns the string-value of the named option (only for Option_String)
bool isDefault(const std::string &name) const
Returns the information whether the named option has still the default value.
bool exists(const std::string &name) const
Returns the information whether the named option is known.
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
const StringVector & getStringVector(const std::string &name) const
Returns the list of string-value of the named option (only for Option_StringVector)
std::string getValueString(const std::string &name) const
Returns the string-value of the named option (all options)
static OptionsCont & getOptions()
Retrieves the options.
virtual const std::string getParameter(const std::string &key, const std::string defaultValue="") const
Returns the value for a given key.
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:283
A list of positions.
double length2D() const
Returns the length.
void append(const PositionVector &v, double sameThreshold=2.0)
double length() const
Returns the length.
double distance2D(const Position &p, bool perpendicular=false) const
closest 2D-distance to point p (or -1 if perpendicular is true and the point is beyond this vector)
double nearest_offset_to_point2D(const Position &p, bool perpendicular=true) const
return the nearest offest to point 2D
std::pair< PositionVector, PositionVector > splitAt(double where, bool use2D=false) const
Returns the two lists made when this list vector is splitted at the given point.
void move2side(double amount, double maxExtension=100)
move position vector to side using certain amount
Boundary getBoxBoundary() const
Returns a boundary enclosing this list of lines.
void extrapolate(const double val, const bool onlyFirst=false, const bool onlyLast=false)
extrapolate position vector
double getOverlapWith(const PositionVector &poly, double zThreshold) const
Returns the maximum overlaps between this and the given polygon (when not separated by at least zThre...
Position positionAtOffset2D(double pos, double lateralOffset=0, bool extrapolateBeyond=false) const
Returns the position at the given length.
bool partialWithin(const AbstractPoly &poly, double offset=0) const
Returns the information whether this polygon lies partially within the given polygon.
double getMaxGrade(double &maxJump) const
double area() const
Returns the area (0 for non-closed)
bool intersects(const Position &p1, const Position &p2) const
Returns the information whether this list of points interesects the given line.
PositionVector getSubpart(double beginOffset, double endOffset) const
get subpart of a position vector
static std::string getEdgeIDFromLane(const std::string laneID)
return edge id when given the lane ID
std::vector< std::string > getVector()
return vector of strings
static long long int toLong(const std::string &sData)
converts a string into the long value described by it by calling the char-type converter,...
static double toDouble(const std::string &sData)
converts a string into the double value described by it by calling the char-type converter
static bool startsWith(const std::string &str, const std::string prefix)
Checks whether a given string starts with the prefix.
unsigned node
#define M_PI
Definition odrSpiral.cpp:45
A structure which describes a connection between edges or lanes.
Definition NBEdge.h:201
NBEdge * toEdge
The edge the connections yields in.
Definition NBEdge.h:213
PositionVector viaShape
shape of via
Definition NBEdge.h:282
std::string getDescription(const NBEdge *parent) const
get string describing this connection
Definition NBEdge.cpp:104
PositionVector shape
shape of Connection
Definition NBEdge.h:270
std::string oppositeID
An opposite lane ID, if given.
Definition NBEdge.h:179
bool operator()(const std::pair< NBEdge *, int > &a, const std::pair< NBEdge *, int > &b) const
A structure representing a connection between two lanes.
Definition NBEdgeCont.h:641
A structure which describes changes of lane number or speed along the road.
Definition NBEdgeCont.h:189
int offsetFactor
direction in which to apply the offset (used by netgenerate for lefthand networks)
Definition NBEdgeCont.h:209
double offset
lateral offset to edge geometry
Definition NBEdgeCont.h:207
double pos
The position of this change.
Definition NBEdgeCont.h:193
std::vector< int > lanes
The lanes after this change.
Definition NBEdgeCont.h:191