Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2024 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file NBEdge.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Sascha Krieg
18 : /// @author Michael Behrisch
19 : /// @author Laura Bieker
20 : /// @author Leonhard Luecken
21 : /// @date Tue, 20 Nov 2001
22 : ///
23 : // Methods for the representation of a single edge
24 : /****************************************************************************/
25 : #include <config.h>
26 :
27 : #include <vector>
28 : #include <string>
29 : #include <algorithm>
30 : #include <cmath>
31 : #include <iomanip>
32 : #include <utils/common/MsgHandler.h>
33 : #include <utils/common/StringTokenizer.h>
34 : #include <utils/common/StringUtils.h>
35 : #include <utils/common/ToString.h>
36 : #include <utils/common/UtilExceptions.h>
37 : #include <utils/common/StdDefs.h>
38 : #include <utils/geom/GeomHelper.h>
39 : #include <utils/options/OptionsCont.h>
40 : #include "NBEdgeCont.h"
41 : #include "NBNode.h"
42 : #include "NBNodeCont.h"
43 : #include "NBContHelper.h"
44 : #include "NBHelpers.h"
45 : #include "NBTrafficLightDefinition.h"
46 : #include "NBOwnTLDef.h"
47 : #include "NBTypeCont.h"
48 : #include "NBEdge.h"
49 :
50 : //#define ADDITIONAL_WARNINGS
51 : //#define DEBUG_CONNECTION_GUESSING
52 : //#define DEBUG_CONNECTION_CHECKING
53 : //#define DEBUG_ANGLES
54 : //#define DEBUG_NODE_BORDER
55 : //#define DEBUG_REPLACECONNECTION
56 : //#define DEBUG_JUNCTIONPRIO
57 : //#define DEBUG_TURNSIGNS
58 : //#define DEBUG_CUT_LANES
59 : #define DEBUGID ""
60 : #define DEBUGCOND (getID() == DEBUGID)
61 : //#define DEBUGCOND (StringUtils::startsWith(getID(), DEBUGID))
62 : //#define DEBUGCOND (getID() == "22762377#1" || getID() == "146511467")
63 : #define DEBUGCOND2(obj) ((obj != 0 && (obj)->getID() == DEBUGID))
64 : //#define DEBUGCOND (true)
65 :
66 : // ===========================================================================
67 : // static members
68 : // ===========================================================================
69 : const double NBEdge::UNSPECIFIED_WIDTH = -1;
70 : const double NBEdge::UNSPECIFIED_OFFSET = 0;
71 : const double NBEdge::UNSPECIFIED_SPEED = -1;
72 : const double NBEdge::UNSPECIFIED_FRICTION = 1.;
73 : const double NBEdge::UNSPECIFIED_CONTPOS = -1;
74 : const double NBEdge::UNSPECIFIED_VISIBILITY_DISTANCE = -1;
75 :
76 : const double NBEdge::UNSPECIFIED_SIGNAL_OFFSET = -1;
77 : const double NBEdge::UNSPECIFIED_LOADED_LENGTH = -1;
78 : const double NBEdge::ANGLE_LOOKAHEAD = 10.0;
79 : const int NBEdge::UNSPECIFIED_INTERNAL_LANE_INDEX = -1;
80 : const bool NBEdge::UNSPECIFIED_CONNECTION_UNCONTROLLED = false;
81 :
82 : double NBEdge::myDefaultConnectionLength = NBEdge::UNSPECIFIED_LOADED_LENGTH;
83 :
84 : NBEdge NBEdge::DummyEdge;
85 :
86 : ConstRouterEdgePairVector NBEdge::Connection::myViaSuccessors = ConstRouterEdgePairVector({ std::pair<NBRouterEdge*, NBRouterEdge*>(nullptr, nullptr) });
87 :
88 : // ===========================================================================
89 : // method definitions
90 : // ===========================================================================
91 : std::string
92 566001 : NBEdge::Connection::getInternalLaneID() const {
93 1132002 : return id + "_" + toString(internalLaneIndex);
94 : }
95 :
96 :
97 : std::string
98 85895 : NBEdge::Connection::getInternalViaLaneID() const {
99 171790 : return viaID + "_" + toString(internalViaLaneIndex);
100 : }
101 :
102 :
103 : std::string
104 342 : NBEdge::Connection::getDescription(const NBEdge* parent) const {
105 2052 : return (Named::getIDSecure(parent) + "_" + toString(fromLane) + "->" + Named::getIDSecure(toEdge) + "_" + toString(toLane)
106 1026 : + (permissions == SVC_UNSPECIFIED ? "" : " (" + getVehicleClassNames(permissions) + ")"));
107 : }
108 :
109 :
110 634599 : NBEdge::Connection::Connection(int fromLane_, NBEdge* toEdge_, int toLane_, const bool mayDefinitelyPass_) :
111 634599 : fromLane(fromLane_),
112 634599 : toEdge(toEdge_),
113 634599 : toLane(toLane_),
114 634599 : mayDefinitelyPass(mayDefinitelyPass_),
115 634599 : customLength(myDefaultConnectionLength),
116 1269111 : id(toEdge_ == nullptr ? "" : toEdge->getFromNode()->getID()) {
117 634599 : }
118 :
119 :
120 141948 : NBEdge::Lane::Lane(NBEdge* e, const std::string& origID_) :
121 141948 : speed(e->getSpeed()),
122 141948 : friction(e->getFriction()),
123 141948 : permissions(SVCAll),
124 141948 : preferred(0),
125 141948 : changeLeft(SVCAll),
126 141948 : changeRight(SVCAll),
127 141948 : endOffset(e->getEndOffset()),
128 141948 : laneStopOffset(e->getEdgeStopOffset()),
129 141948 : width(e->getLaneWidth()),
130 141948 : accelRamp(false),
131 283896 : connectionsDone(false) {
132 141948 : if (origID_ != "") {
133 33873 : setParameter(SUMO_PARAM_ORIGID, origID_);
134 : }
135 141948 : }
136 :
137 :
138 : /* -------------------------------------------------------------------------
139 : * NBEdge::ToEdgeConnectionsAdder-methods
140 : * ----------------------------------------------------------------------- */
141 : void
142 420234 : NBEdge::ToEdgeConnectionsAdder::execute(const int lane, const int virtEdge) {
143 : // check
144 : assert((int)myTransitions.size() > virtEdge);
145 : // get the approached edge
146 420234 : NBEdge* succEdge = myTransitions[virtEdge];
147 : std::vector<int> lanes;
148 :
149 : // check whether the currently regarded, approached edge has already
150 : // a connection starting at the edge which is currently being build
151 : std::map<NBEdge*, std::vector<int> >::iterator i = myConnections.find(succEdge);
152 420234 : if (i != myConnections.end()) {
153 : // if there were already lanes assigned, get them
154 330233 : lanes = (*i).second;
155 : }
156 :
157 : // check whether the current lane was already used to connect the currently
158 : // regarded approached edge
159 420234 : std::vector<int>::iterator j = std::find(lanes.begin(), lanes.end(), lane);
160 420234 : if (j == lanes.end()) {
161 : // if not, add it to the list
162 100554 : lanes.push_back(lane);
163 : }
164 : // set information about connecting lanes
165 420234 : myConnections[succEdge] = lanes;
166 420234 : }
167 :
168 :
169 :
170 : /* -------------------------------------------------------------------------
171 : * NBEdge::MainDirections-methods
172 : * ----------------------------------------------------------------------- */
173 45904 : NBEdge::MainDirections::MainDirections(const EdgeVector& outgoing, NBEdge* parent, NBNode* to, const std::vector<int>& availableLanes) : myStraightest(-1) {
174 : NBContHelper::edge_similar_direction_sorter sorter(parent);
175 45904 : const NBEdge* straight = nullptr;
176 135965 : for (const NBEdge* const out : outgoing) {
177 90061 : const SVCPermissions outPerms = out->getPermissions();
178 90242 : for (const int l : availableLanes) {
179 90128 : if ((parent->myLanes[l].permissions & outPerms) != 0) {
180 89947 : if (straight == nullptr || sorter(out, straight)) {
181 67827 : straight = out;
182 : }
183 : break;
184 : }
185 : }
186 : }
187 45904 : if (straight == nullptr) {
188 4031 : return;
189 : }
190 45856 : myStraightest = (int)std::distance(outgoing.begin(), std::find(outgoing.begin(), outgoing.end(), straight));
191 :
192 : // check whether the right turn has a higher priority
193 : assert(outgoing.size() > 0);
194 45856 : const LinkDirection straightestDir = to->getDirection(parent, straight);
195 : #ifdef DEBUG_CONNECTION_GUESSING
196 : if (DEBUGCOND2(parent)) {
197 : std::cout << " MainDirections edge=" << parent->getID() << " straightest=" << straight->getID() << " dir=" << toString(straightestDir) << "\n";
198 : }
199 : #endif
200 45856 : if (NBNode::isTrafficLight(to->getType()) &&
201 4280 : (straightestDir == LinkDirection::STRAIGHT || straightestDir == LinkDirection::PARTLEFT || straightestDir == LinkDirection::PARTRIGHT)) {
202 3983 : myDirs.push_back(MainDirections::Direction::FORWARD);
203 3983 : return;
204 : }
205 41873 : if (outgoing[0]->getJunctionPriority(to) == 1) {
206 22387 : myDirs.push_back(MainDirections::Direction::RIGHTMOST);
207 : }
208 : // check whether the left turn has a higher priority
209 41873 : if (outgoing.back()->getJunctionPriority(to) == 1) {
210 : // ok, the left turn belongs to the higher priorised edges on the junction
211 : // let's check, whether it has also a higher priority (lane number/speed)
212 : // than the current
213 22627 : if (outgoing.back()->getPriority() > straight->getPriority() ||
214 : outgoing.back()->getNumLanes() > straight->getNumLanes()) {
215 1228 : myDirs.push_back(MainDirections::Direction::LEFTMOST);
216 : }
217 : }
218 : // check whether the forward direction has a higher priority
219 : // check whether it has a higher priority and is going straight
220 41873 : if (straight->getJunctionPriority(to) == 1 && to->getDirection(parent, straight) == LinkDirection::STRAIGHT) {
221 20211 : myDirs.push_back(MainDirections::Direction::FORWARD);
222 : }
223 0 : }
224 :
225 :
226 45904 : NBEdge::MainDirections::~MainDirections() {}
227 :
228 :
229 : bool
230 45856 : NBEdge::MainDirections::empty() const {
231 45856 : return myDirs.empty();
232 : }
233 :
234 :
235 : bool
236 171653 : NBEdge::MainDirections::includes(Direction d) const {
237 171653 : return std::find(myDirs.begin(), myDirs.end(), d) != myDirs.end();
238 : }
239 :
240 :
241 : /* -------------------------------------------------------------------------
242 : * NBEdge::connections_relative_edgelane_sorter-methods
243 : * ----------------------------------------------------------------------- */
244 : int
245 154330 : NBEdge::connections_relative_edgelane_sorter::operator()(const Connection& c1, const Connection& c2) const {
246 154330 : if (c1.toEdge != c2.toEdge) {
247 119091 : return NBContHelper::relative_outgoing_edge_sorter(myEdge)(c1.toEdge, c2.toEdge);
248 : }
249 35239 : return c1.toLane < c2.toLane;
250 : }
251 :
252 :
253 : /* -------------------------------------------------------------------------
254 : * NBEdge-methods
255 : * ----------------------------------------------------------------------- */
256 15350 : NBEdge::NBEdge(const std::string& id, NBNode* from, NBNode* to,
257 : std::string type, double speed, double friction, int nolanes,
258 : int priority, double laneWidth, double endOffset,
259 15350 : LaneSpreadFunction spread, const std::string& streetName) :
260 15350 : Named(StringUtils::convertUmlaute(id)),
261 15350 : myStep(EdgeBuildingStep::INIT),
262 15350 : myType(StringUtils::convertUmlaute(type)),
263 15350 : myFrom(from), myTo(to),
264 15350 : myStartAngle(0), myEndAngle(0), myTotalAngle(0),
265 15350 : myPriority(priority), mySpeed(speed), myFriction(friction),
266 15350 : myDistance(0),
267 15350 : myTurnDestination(nullptr),
268 15350 : myPossibleTurnDestination(nullptr),
269 15350 : myFromJunctionPriority(-1), myToJunctionPriority(-1),
270 15350 : myLaneSpreadFunction(spread), myEndOffset(endOffset),
271 15350 : myLaneWidth(laneWidth),
272 15350 : myLoadedLength(UNSPECIFIED_LOADED_LENGTH),
273 15350 : myAmInTLS(false), myAmMacroscopicConnector(false),
274 15350 : myStreetName(streetName),
275 15350 : mySignalPosition(Position::INVALID),
276 15350 : mySignalNode(nullptr),
277 15350 : myIsOffRamp(false),
278 15350 : myIsBidi(false),
279 46050 : myIndex(-1) {
280 15350 : init(nolanes, false, "");
281 15350 : }
282 :
283 :
284 90001 : NBEdge::NBEdge(const std::string& id, NBNode* from, NBNode* to,
285 : std::string type, double speed, double friction, int nolanes,
286 : int priority, double laneWidth, double endOffset,
287 : PositionVector geom,
288 : LaneSpreadFunction spread,
289 : const std::string& streetName,
290 : const std::string& origID,
291 90001 : bool tryIgnoreNodePositions) :
292 90001 : Named(StringUtils::convertUmlaute(id)),
293 90001 : myStep(EdgeBuildingStep::INIT),
294 90002 : myType(StringUtils::convertUmlaute(type)),
295 90001 : myFrom(from), myTo(to),
296 90001 : myStartAngle(0), myEndAngle(0), myTotalAngle(0),
297 90001 : myPriority(priority), mySpeed(speed), myFriction(friction),
298 90001 : myDistance(0),
299 90001 : myTurnDestination(nullptr),
300 90001 : myPossibleTurnDestination(nullptr),
301 90001 : myFromJunctionPriority(-1), myToJunctionPriority(-1),
302 90001 : myGeom(geom), myLaneSpreadFunction(spread), myEndOffset(endOffset),
303 90001 : myLaneWidth(laneWidth),
304 90001 : myLoadedLength(UNSPECIFIED_LOADED_LENGTH),
305 90001 : myAmInTLS(false), myAmMacroscopicConnector(false),
306 90001 : myStreetName(streetName),
307 90001 : mySignalPosition(Position::INVALID),
308 90001 : mySignalNode(nullptr),
309 90001 : myIsOffRamp(false),
310 90001 : myIsBidi(false),
311 270003 : myIndex(-1) {
312 90001 : init(nolanes, tryIgnoreNodePositions, origID);
313 90012 : }
314 :
315 :
316 2273 : NBEdge::NBEdge(const std::string& id, NBNode* from, NBNode* to, const NBEdge* tpl, const PositionVector& geom, int numLanes) :
317 2273 : Named(StringUtils::convertUmlaute(id)),
318 2273 : myStep(EdgeBuildingStep::INIT),
319 2273 : myType(tpl->getTypeID()),
320 2273 : myFrom(from), myTo(to),
321 2273 : myStartAngle(0), myEndAngle(0), myTotalAngle(0),
322 2273 : myPriority(tpl->getPriority()), mySpeed(tpl->getSpeed()),
323 2273 : myFriction(tpl->getFriction()),
324 2273 : myDistance(0),
325 2273 : myTurnDestination(nullptr),
326 2273 : myPossibleTurnDestination(nullptr),
327 2273 : myFromJunctionPriority(-1), myToJunctionPriority(-1),
328 : myGeom(geom),
329 2273 : myLaneSpreadFunction(tpl->getLaneSpreadFunction()),
330 2273 : myEndOffset(tpl->getEndOffset()),
331 2273 : myEdgeStopOffset(tpl->getEdgeStopOffset()),
332 2273 : myLaneWidth(tpl->getLaneWidth()),
333 2273 : myLoadedLength(UNSPECIFIED_LOADED_LENGTH),
334 2273 : myAmInTLS(false),
335 2273 : myAmMacroscopicConnector(false),
336 2273 : myStreetName(tpl->getStreetName()),
337 2273 : mySignalPosition(to == tpl->myTo ? tpl->mySignalPosition : Position::INVALID),
338 2273 : mySignalNode(to == tpl->myTo ? tpl->mySignalNode : nullptr),
339 2273 : myIsOffRamp(false),
340 2273 : myIsBidi(false),
341 4546 : myIndex(-1) {
342 3334 : init(numLanes > 0 ? numLanes : tpl->getNumLanes(), myGeom.size() > 0, "");
343 5696 : for (int i = 0; i < getNumLanes(); i++) {
344 3423 : const int tplIndex = MIN2(i, tpl->getNumLanes() - 1);
345 3423 : setSpeed(i, tpl->getLaneSpeed(tplIndex));
346 3423 : setFriction(i, tpl->getLaneFriction(tplIndex));
347 3423 : setPermissions(tpl->getPermissions(tplIndex), i);
348 3423 : setLaneWidth(i, tpl->myLanes[tplIndex].width);
349 3423 : setLaneType(i, tpl->myLanes[tplIndex].type);
350 3423 : myLanes[i].updateParameters(tpl->myLanes[tplIndex].getParametersMap());
351 3423 : if (to == tpl->myTo) {
352 1260 : setEndOffset(i, tpl->myLanes[tplIndex].endOffset);
353 1260 : setEdgeStopOffset(i, tpl->myLanes[tplIndex].laneStopOffset);
354 : }
355 : }
356 2273 : if (tpl->myLoadedLength > 0 && to == tpl->getFromNode() && from == tpl->getToNode() && geom == tpl->getGeometry().reverse()) {
357 3 : myLoadedLength = tpl->myLoadedLength;
358 : }
359 2273 : updateParameters(tpl->getParametersMap());
360 2273 : }
361 :
362 :
363 2031 : NBEdge::NBEdge() :
364 : Named("DUMMY"),
365 2031 : myStep(EdgeBuildingStep::INIT),
366 2031 : myFrom(nullptr), myTo(nullptr),
367 2031 : myStartAngle(0), myEndAngle(0), myTotalAngle(0),
368 2031 : myPriority(0), mySpeed(0), myFriction(UNSPECIFIED_FRICTION),
369 2031 : myDistance(0),
370 2031 : myTurnDestination(nullptr),
371 2031 : myPossibleTurnDestination(nullptr),
372 2031 : myFromJunctionPriority(-1), myToJunctionPriority(-1),
373 2031 : myLaneSpreadFunction(LaneSpreadFunction::RIGHT),
374 2031 : myEndOffset(0),
375 2031 : myEdgeStopOffset(StopOffset()),
376 2031 : myLaneWidth(0),
377 2031 : myLoadedLength(UNSPECIFIED_LOADED_LENGTH),
378 2031 : myAmInTLS(false),
379 2031 : myAmMacroscopicConnector(false),
380 2031 : mySignalPosition(Position::INVALID),
381 6093 : mySignalNode(nullptr) {
382 2031 : }
383 :
384 :
385 : void
386 1876 : NBEdge::reinit(NBNode* from, NBNode* to, const std::string& type,
387 : double speed, double friction, int nolanes, int priority,
388 : PositionVector geom, double laneWidth, double endOffset,
389 : const std::string& streetName,
390 : LaneSpreadFunction spread,
391 : bool tryIgnoreNodePositions) {
392 1876 : if (myFrom != from) {
393 10 : myFrom->removeEdge(this, false);
394 : }
395 1876 : if (myTo != to) {
396 11 : myTo->removeEdge(this, false);
397 : }
398 1876 : myType = StringUtils::convertUmlaute(type);
399 1876 : myFrom = from;
400 1876 : myTo = to;
401 1876 : myPriority = priority;
402 : //?myTurnDestination(0),
403 : //?myFromJunctionPriority(-1), myToJunctionPriority(-1),
404 : myGeom = geom;
405 1876 : myLaneSpreadFunction = spread;
406 1876 : myLoadedLength = UNSPECIFIED_LOADED_LENGTH;
407 1876 : myStreetName = streetName;
408 : //?, myAmTurningWithAngle(0), myAmTurningOf(0),
409 : //?myAmInTLS(false), myAmMacroscopicConnector(false)
410 :
411 : // preserve lane-specific settings (geometry must be recomputed)
412 : // if new lanes are added they copy the values from the leftmost lane (if specified)
413 1876 : const std::vector<Lane> oldLanes = myLanes;
414 3752 : init(nolanes, tryIgnoreNodePositions, oldLanes.empty() ? "" : oldLanes[0].getParameter(SUMO_PARAM_ORIGID));
415 3840 : for (int i = 0; i < (int)nolanes; ++i) {
416 1964 : PositionVector newShape = myLanes[i].shape;
417 1964 : myLanes[i] = oldLanes[MIN2(i, (int)oldLanes.size() - 1)];
418 : myLanes[i].shape = newShape;
419 1964 : }
420 : // however, if the new edge defaults are explicityly given, they override the old settings
421 1876 : if (endOffset != UNSPECIFIED_OFFSET) {
422 1 : setEndOffset(-1, endOffset);
423 : }
424 1876 : if (laneWidth != UNSPECIFIED_WIDTH) {
425 2 : setLaneWidth(-1, laneWidth);
426 : }
427 1876 : if (speed != UNSPECIFIED_SPEED) {
428 28 : setSpeed(-1, speed);
429 : }
430 1876 : if (friction != UNSPECIFIED_FRICTION) {
431 0 : setFriction(-1, friction);
432 : }
433 1876 : }
434 :
435 :
436 : void
437 6369 : NBEdge::reinitNodes(NBNode* from, NBNode* to) {
438 : // connections may still be valid
439 6369 : if (from == nullptr || to == nullptr) {
440 0 : throw ProcessError(TLF("At least one of edge's '%' nodes is not known.", myID));
441 : }
442 6369 : if (myFrom != from) {
443 3262 : myFrom->removeEdge(this, false);
444 : }
445 6369 : if (myTo != to) {
446 3095 : myTo->removeEdge(this, false);
447 : }
448 : // remove first from both nodes and then add to the new nodes
449 : // (otherwise reversing does not work)
450 6369 : if (myFrom != from) {
451 3262 : myFrom = from;
452 3262 : myFrom->addOutgoingEdge(this);
453 : }
454 6369 : if (myTo != to) {
455 3095 : myTo = to;
456 3095 : myTo->addIncomingEdge(this);
457 : }
458 6369 : computeAngle();
459 6369 : }
460 :
461 :
462 : void
463 109500 : NBEdge::init(int noLanes, bool tryIgnoreNodePositions, const std::string& origID) {
464 109500 : if (noLanes == 0) {
465 0 : throw ProcessError(TLF("Edge '%' needs at least one lane.", myID));
466 : }
467 109500 : if (myFrom == nullptr || myTo == nullptr) {
468 0 : throw ProcessError(TLF("At least one of edge's '%' nodes is not known.", myID));
469 : }
470 109500 : if (!SUMOXMLDefinitions::isValidNetID(myID)) {
471 3 : throw ProcessError(TLF("Invalid edge id '%'.", myID));
472 : }
473 : // revisit geometry
474 : // should have at least two points at the end...
475 : // and in dome cases, the node positions must be added
476 : // attempt symmetrical removal for forward and backward direction
477 : // (very important for bidiRail)
478 109499 : if (myFrom->getID() < myTo->getID()) {
479 56467 : PositionVector reverse = myGeom.reverse();
480 56467 : reverse.removeDoublePoints(POSITION_EPS, true);
481 112934 : myGeom = reverse.reverse();
482 56467 : } else {
483 53032 : myGeom.removeDoublePoints(POSITION_EPS, true);
484 : }
485 :
486 109499 : if (!tryIgnoreNodePositions || myGeom.size() < 2) {
487 38650 : if (myGeom.size() == 0) {
488 38343 : myGeom.push_back(myFrom->getPosition());
489 38343 : myGeom.push_back(myTo->getPosition());
490 : } else {
491 307 : myGeom.push_back_noDoublePos(myTo->getPosition());
492 307 : myGeom.push_front_noDoublePos(myFrom->getPosition());
493 : }
494 : }
495 109499 : if (myGeom.size() < 2) {
496 : myGeom.clear();
497 0 : myGeom.push_back(myFrom->getPosition());
498 0 : myGeom.push_back(myTo->getPosition());
499 : }
500 109499 : if (myGeom.size() == 2 && myGeom[0] == myGeom[1]) {
501 12 : WRITE_WARNINGF(TL("Edge's '%' from- and to-node are at the same position."), myID);
502 4 : int patchIndex = myFrom->getID() < myTo->getID() ? 1 : 0;
503 4 : myGeom[patchIndex].add(Position(POSITION_EPS, POSITION_EPS));
504 : }
505 : //
506 109499 : myFrom->addOutgoingEdge(this);
507 109499 : myTo->addIncomingEdge(this);
508 : // prepare container
509 : assert(myGeom.size() >= 2);
510 109499 : myLength = myGeom.length();
511 109499 : if ((int)myLanes.size() > noLanes) {
512 : // remove connections starting at the removed lanes
513 6 : for (int lane = noLanes; lane < (int)myLanes.size(); ++lane) {
514 3 : removeFromConnections(nullptr, lane, -1);
515 : }
516 : // remove connections targeting the removed lanes
517 3 : const EdgeVector& incoming = myFrom->getIncomingEdges();
518 6 : for (EdgeVector::const_iterator i = incoming.begin(); i != incoming.end(); i++) {
519 6 : for (int lane = noLanes; lane < (int)myLanes.size(); ++lane) {
520 3 : (*i)->removeFromConnections(this, -1, lane);
521 : }
522 : }
523 : }
524 : myLanes.clear();
525 247390 : for (int i = 0; i < noLanes; i++) {
526 275782 : myLanes.push_back(Lane(this, origID));
527 : }
528 109499 : computeLaneShapes();
529 109499 : computeAngle();
530 :
531 : #ifdef DEBUG_CONNECTION_GUESSING
532 : if (DEBUGCOND) {
533 : std::cout << "init edge=" << getID() << "\n";
534 : for (Connection& c : myConnections) {
535 : std::cout << " conn " << c.getDescription(this) << "\n";
536 : }
537 : for (Connection& c : myConnectionsToDelete) {
538 : std::cout << " connToDelete " << c.getDescription(this) << "\n";
539 : }
540 : }
541 : #endif
542 109499 : }
543 :
544 :
545 217227 : NBEdge::~NBEdge() {}
546 :
547 :
548 : // ----------- Applying offset
549 : void
550 67775 : NBEdge::reshiftPosition(double xoff, double yoff) {
551 67775 : myGeom.add(xoff, yoff, 0);
552 155103 : for (Lane& lane : myLanes) {
553 87328 : lane.customShape.add(xoff, yoff, 0);
554 : }
555 67775 : computeLaneShapes(); // old shapes are dubious if computed with large coordinates
556 74023 : for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
557 6248 : (*i).customShape.add(xoff, yoff, 0);
558 : }
559 : if (mySignalPosition != Position::INVALID) {
560 : mySignalPosition.add(xoff, yoff);
561 : }
562 67775 : myFromBorder.add(xoff, yoff, 0);
563 67775 : myToBorder.add(xoff, yoff, 0);
564 67775 : computeEdgeShape();
565 67775 : computeAngle(); // update angles because they are numerically sensitive (especially where based on centroids)
566 67775 : }
567 :
568 :
569 : void
570 1144 : NBEdge::mirrorX() {
571 1144 : myGeom.mirrorX();
572 3029 : for (int i = 0; i < (int)myLanes.size(); i++) {
573 1885 : myLanes[i].shape.mirrorX();
574 1885 : myLanes[i].customShape.mirrorX();
575 : }
576 2496 : for (Connection& c : myConnections) {
577 1352 : c.shape.mirrorX();
578 1352 : c.viaShape.mirrorX();
579 1352 : c.customShape.mirrorX();
580 : }
581 : if (mySignalPosition != Position::INVALID) {
582 24 : mySignalPosition.sety(-mySignalPosition.y());
583 : }
584 1144 : computeAngle(); // update angles because they are numerically sensitive (especially where based on centroids)
585 1144 : }
586 :
587 :
588 : // ----------- Edge geometry access and computation
589 : const PositionVector
590 2246 : NBEdge::getInnerGeometry() const {
591 2246 : return myGeom.getSubpartByIndex(1, (int)myGeom.size() - 2);
592 : }
593 :
594 :
595 : bool
596 91965 : NBEdge::hasDefaultGeometry() const {
597 91965 : return myGeom.size() == 2 && hasDefaultGeometryEndpoints();
598 : }
599 :
600 :
601 : bool
602 59186 : NBEdge::hasDefaultGeometryEndpoints() const {
603 110612 : return myGeom.front().almostSame(myFrom->getPosition(), 0.01) &&
604 51426 : myGeom.back().almostSame(myTo->getPosition(), 0.01);
605 : }
606 :
607 :
608 : bool
609 162004 : NBEdge::hasDefaultGeometryEndpointAtNode(const NBNode* node) const {
610 : // do not extend past the node position
611 162004 : if (node == myFrom) {
612 : return myGeom.front() == node->getPosition();
613 : } else {
614 : assert(node == myTo);
615 : return myGeom.back() == node->getPosition();
616 : }
617 : }
618 :
619 : Position
620 3146 : NBEdge::getEndpointAtNode(const NBNode* node) const {
621 3146 : return node == myFrom ? myGeom.front() : myGeom.back();
622 : }
623 :
624 : void
625 0 : NBEdge::resetEndpointAtNode(const NBNode* node) {
626 : assert(myGeom.size() >= 2);
627 0 : if (node == myFrom) {
628 0 : myGeom[0] = myFrom->getPosition();
629 0 : } else if (node == myTo) {
630 0 : myGeom[-1] = myTo->getPosition();
631 : } else {
632 : assert(false);
633 : }
634 0 : }
635 :
636 : void
637 3989 : NBEdge::setGeometry(const PositionVector& s, bool inner) {
638 3989 : Position begin = myGeom.front(); // may differ from node position
639 3989 : Position end = myGeom.back(); // may differ from node position
640 : myGeom = s;
641 3989 : if (inner) {
642 0 : myGeom.insert(myGeom.begin(), begin);
643 0 : myGeom.push_back(end);
644 : }
645 : // ensure non-zero length (see ::init)
646 3989 : if (myGeom.size() == 2 && myGeom[0] == myGeom[1]) {
647 6 : WRITE_WARNINGF(TL("Edge's '%' from- and to-node are at the same position."), myID);
648 2 : int patchIndex = myFrom->getID() < myTo->getID() ? 1 : 0;
649 2 : myGeom[patchIndex].add(Position(POSITION_EPS, POSITION_EPS));
650 : }
651 3989 : computeLaneShapes();
652 3989 : computeAngle();
653 3989 : myLength = myGeom.length();
654 3989 : }
655 :
656 :
657 : void
658 0 : NBEdge::extendGeometryAtNode(const NBNode* node, double maxExtent) {
659 : //std::cout << "extendGeometryAtNode edge=" << getID() << " node=" << node->getID() << " nodePos=" << node->getPosition() << " extent=" << maxExtent << " geom=" << myGeom;
660 0 : if (node == myFrom) {
661 0 : myGeom.extrapolate(maxExtent, true);
662 0 : double offset = myGeom.nearest_offset_to_point2D(node->getPosition());
663 : //std::cout << " geom2=" << myGeom << " offset=" << offset;
664 0 : if (offset != GeomHelper::INVALID_OFFSET) {
665 0 : myGeom = myGeom.getSubpart2D(MIN2(offset, myGeom.length2D() - 2 * POSITION_EPS), myGeom.length2D());
666 : }
667 : } else {
668 : assert(node == myTo);
669 0 : myGeom.extrapolate(maxExtent, false, true);
670 0 : double offset = myGeom.nearest_offset_to_point2D(node->getPosition());
671 : //std::cout << " geom2=" << myGeom << " offset=" << offset;
672 0 : if (offset != GeomHelper::INVALID_OFFSET) {
673 0 : myGeom = myGeom.getSubpart2D(0, MAX2(offset, 2 * POSITION_EPS));
674 : }
675 : }
676 : //std::cout << " geom3=" << myGeom << "\n";
677 0 : }
678 :
679 :
680 : void
681 2 : NBEdge::shortenGeometryAtNode(const NBNode* node, double reduction) {
682 : //std::cout << "shortenGeometryAtNode edge=" << getID() << " node=" << node->getID() << " nodePos=" << node->getPosition() << " reduction=" << reduction << " geom=" << myGeom;
683 2 : reduction = MIN2(reduction, myGeom.length2D() - 2 * POSITION_EPS);
684 2 : if (node == myFrom) {
685 2 : myGeom = myGeom.getSubpart2D(reduction, myGeom.length2D());
686 : } else {
687 2 : myGeom = myGeom.getSubpart2D(0, myGeom.length2D() - reduction);
688 : }
689 2 : computeLaneShapes();
690 : //std::cout << " geom2=" << myGeom << "\n";
691 2 : }
692 :
693 :
694 : void
695 219932 : NBEdge::setNodeBorder(const NBNode* node, const Position& p, const Position& p2, bool rectangularCut) {
696 219932 : PositionVector border;
697 219932 : if (rectangularCut) {
698 : const double extend = 100;
699 3330 : border = myGeom.getOrthogonal(p, extend, node == myTo);
700 : } else {
701 218267 : border.push_back(p);
702 218267 : border.push_back(p2);
703 : }
704 219932 : if (border.size() == 2) {
705 219932 : border.extrapolate2D(getTotalWidth());
706 219932 : if (node == myFrom) {
707 : myFromBorder = border;
708 : } else {
709 : assert(node == myTo);
710 : myToBorder = border;
711 : }
712 : }
713 : #ifdef DEBUG_NODE_BORDER
714 : gDebugFlag1 = DEBUGCOND;
715 : if (DEBUGCOND) std::cout << "setNodeBorder edge=" << getID() << " node=" << node->getID()
716 : << " rect=" << rectangularCut
717 : << " p=" << p << " p2=" << p2
718 : << " border=" << border
719 : << " myGeom=" << myGeom
720 : << "\n";
721 :
722 : #endif
723 219932 : }
724 :
725 :
726 : const PositionVector&
727 290 : NBEdge::getNodeBorder(const NBNode* node) const {
728 290 : if (node == myFrom) {
729 145 : return myFromBorder;
730 : } else {
731 : assert(node == myTo);
732 145 : return myToBorder;
733 : }
734 : }
735 :
736 :
737 : void
738 29454 : NBEdge::resetNodeBorder(const NBNode* node) {
739 29454 : if (node == myFrom) {
740 : myFromBorder.clear();
741 : } else {
742 : assert(node == myTo);
743 : myToBorder.clear();
744 : }
745 29454 : }
746 :
747 :
748 : bool
749 4809102 : NBEdge::isBidiRail(bool ignoreSpread) const {
750 4809102 : return (isRailway(getPermissions())
751 155353 : && (ignoreSpread || myLaneSpreadFunction == LaneSpreadFunction::CENTER)
752 153225 : && myPossibleTurnDestination != nullptr
753 109782 : && myPossibleTurnDestination->myPossibleTurnDestination == this
754 102376 : && (ignoreSpread || myPossibleTurnDestination->getLaneSpreadFunction() == LaneSpreadFunction::CENTER)
755 102305 : && isRailway(myPossibleTurnDestination->getPermissions())
756 9618204 : && myPossibleTurnDestination->getGeometry().reverse() == getGeometry());
757 : }
758 :
759 :
760 : bool
761 4468804 : NBEdge::isBidiEdge(bool checkPotential) const {
762 4468804 : return myPossibleTurnDestination != nullptr
763 4194807 : && myPossibleTurnDestination->myPossibleTurnDestination == this
764 3971216 : && (myIsBidi || myPossibleTurnDestination->myIsBidi || checkPotential)
765 2423 : && myPossibleTurnDestination->getToNode() == getFromNode()
766 2423 : && myPossibleTurnDestination->getLaneSpreadFunction() == myLaneSpreadFunction
767 : // geometry check a) full overlap geometry
768 4471227 : && ((myLaneSpreadFunction == LaneSpreadFunction::CENTER
769 1600 : && (myPossibleTurnDestination->getGeometry().reverse() == getGeometry()
770 0 : || (checkPotential && getGeometry().size() == 2 && myPossibleTurnDestination->getGeometry().size() == 2)))
771 : // b) TWLT (Two-Way-Left-Turn-lane)
772 4468804 : || (myLanes.back().shape.reverse().almostSame(myPossibleTurnDestination->myLanes.back().shape, POSITION_EPS))
773 4468804 : );
774 :
775 : }
776 :
777 :
778 : bool
779 2696 : NBEdge::isRailDeadEnd() const {
780 2696 : if (!isRailway(getPermissions())) {
781 : return false;
782 : }
783 4201 : for (NBEdge* out : myTo->getOutgoingEdges()) {
784 8028 : if (isRailway(out->getPermissions()) &&
785 3944 : out != getTurnDestination(true)) {
786 : return true;
787 : }
788 : }
789 : return true;
790 : }
791 :
792 :
793 : PositionVector
794 298695 : NBEdge::cutAtIntersection(const PositionVector& old) const {
795 : PositionVector shape = old;
796 597390 : shape = startShapeAt(shape, myFrom, myFromBorder);
797 : #ifdef DEBUG_CUT_LANES
798 : if (DEBUGCOND) {
799 : std::cout << getID() << " cutFrom=" << shape << "\n";
800 : }
801 : #endif
802 298695 : if (shape.size() < 2) {
803 : // only keep the last snippet
804 341 : const double oldLength = old.length();
805 682 : shape = old.getSubpart(oldLength - 2 * POSITION_EPS, oldLength);
806 : #ifdef DEBUG_CUT_LANES
807 : if (DEBUGCOND) {
808 : std::cout << getID() << " cutFromFallback=" << shape << "\n";
809 : }
810 : #endif
811 : }
812 597390 : shape = startShapeAt(shape.reverse(), myTo, myToBorder).reverse();
813 : #ifdef DEBUG_CUT_LANES
814 : if (DEBUGCOND) {
815 : std::cout << getID() << " cutTo=" << shape << "\n";
816 : }
817 : #endif
818 : // sanity checks
819 298695 : if (shape.length() < POSITION_EPS) {
820 388 : if (old.length() < 2 * POSITION_EPS) {
821 : shape = old;
822 : } else {
823 383 : const double midpoint = old.length() / 2;
824 : // EPS*2 because otherwhise shape has only a single point
825 766 : shape = old.getSubpart(midpoint - POSITION_EPS, midpoint + POSITION_EPS);
826 : assert(shape.size() >= 2);
827 : assert(shape.length() > 0);
828 : #ifdef DEBUG_CUT_LANES
829 : if (DEBUGCOND) {
830 : std::cout << getID() << " fallBackShort=" << shape << "\n";
831 : }
832 : #endif
833 : }
834 : } else {
835 : // @note If the node shapes are overlapping we may get a shape which goes in the wrong direction
836 : // in this case the result shape should shortened
837 298307 : if (DEG2RAD(135) < fabs(GeomHelper::angleDiff(shape.beginEndAngle(), old.beginEndAngle()))) {
838 : // eliminate intermediate points
839 27084 : PositionVector tmp;
840 27084 : tmp.push_back(shape[0]);
841 27084 : tmp.push_back(shape[-1]);
842 : shape = tmp;
843 27084 : if (tmp.length() < POSITION_EPS) {
844 : // fall back to original shape
845 48 : if (old.length() < 2 * POSITION_EPS) {
846 : shape = old;
847 : } else {
848 48 : const double midpoint = old.length() / 2;
849 : // EPS*2 because otherwhise shape has only a single point
850 96 : shape = old.getSubpart(midpoint - POSITION_EPS, midpoint + POSITION_EPS);
851 : assert(shape.size() >= 2);
852 : assert(shape.length() > 0);
853 : }
854 : #ifdef DEBUG_CUT_LANES
855 : if (DEBUGCOND) {
856 : std::cout << getID() << " fallBackReversed=" << shape << "\n";
857 : }
858 : #endif
859 : } else {
860 27036 : const double midpoint = shape.length() / 2;
861 : // cut to size and reverse
862 54072 : shape = shape.getSubpart(midpoint - POSITION_EPS, midpoint + POSITION_EPS);
863 27036 : if (shape.length() < POSITION_EPS) {
864 : assert(false);
865 : // the shape has a sharp turn near the midpoint
866 : }
867 54072 : shape = shape.reverse();
868 : #ifdef DEBUG_CUT_LANES
869 : if (DEBUGCOND) {
870 : std::cout << getID() << " fallBackReversed2=" << shape << " mid=" << midpoint << "\n";
871 : }
872 : #endif
873 : }
874 : // make short edge flat (length <= 2 * POSITION_EPS)
875 27084 : const double z = (shape[0].z() + shape[1].z()) / 2;
876 27084 : shape[0].setz(z);
877 27084 : shape[1].setz(z);
878 27084 : }
879 : }
880 298695 : return shape;
881 0 : }
882 :
883 :
884 : void
885 193828 : NBEdge::computeEdgeShape(double smoothElevationThreshold) {
886 193828 : if (smoothElevationThreshold > 0 && myGeom.hasElevation()) {
887 1836 : PositionVector cut = cutAtIntersection(myGeom);
888 : // cutting and patching z-coordinate may cause steep grades which should be smoothed
889 1836 : if (!myFrom->geometryLike()) {
890 1734 : cut[0].setz(myFrom->getPosition().z());
891 1734 : const double d = cut[0].distanceTo2D(cut[1]);
892 1734 : const double dZ = fabs(cut[0].z() - cut[1].z());
893 1734 : if (dZ / smoothElevationThreshold > d) {
894 513 : cut = cut.smoothedZFront(MIN2(cut.length2D() / 2, dZ / smoothElevationThreshold));
895 : }
896 : }
897 1836 : if (!myTo->geometryLike()) {
898 1734 : cut[-1].setz(myTo->getPosition().z());
899 1734 : const double d = cut[-1].distanceTo2D(cut[-2]);
900 1734 : const double dZ = fabs(cut[-1].z() - cut[-2].z());
901 1734 : if (dZ / smoothElevationThreshold > d) {
902 508 : cut = cut.reverse().smoothedZFront(MIN2(cut.length2D() / 2, dZ / smoothElevationThreshold)).reverse();
903 : }
904 : }
905 1836 : cut[0] = myGeom[0];
906 1836 : cut[-1] = myGeom[-1];
907 1836 : if (cut != myGeom) {
908 : myGeom = cut;
909 20 : computeLaneShapes();
910 : }
911 1836 : }
912 446191 : for (int i = 0; i < (int)myLanes.size(); i++) {
913 504726 : myLanes[i].shape = cutAtIntersection(myLanes[i].shape);
914 : }
915 : // recompute edge's length as the average of lane lengths
916 : double avgLength = 0;
917 446191 : for (int i = 0; i < (int)myLanes.size(); i++) {
918 252363 : avgLength += myLanes[i].shape.length();
919 : }
920 193828 : myLength = avgLength / (double) myLanes.size();
921 193828 : computeAngle(); // update angles using the finalized node and lane shapes
922 193828 : }
923 :
924 :
925 : PositionVector
926 597680 : NBEdge::startShapeAt(const PositionVector& laneShape, const NBNode* startNode, PositionVector nodeShape) {
927 597680 : if (nodeShape.size() == 0) {
928 175924 : nodeShape = startNode->getShape();
929 175924 : nodeShape.closePolygon();
930 : }
931 : PositionVector lb = laneShape;
932 597680 : lb.extrapolate2D(100.0);
933 597680 : if (nodeShape.intersects(laneShape)) {
934 : // shape intersects directly
935 419626 : std::vector<double> pbv = laneShape.intersectsAtLengths2D(nodeShape);
936 : assert(pbv.size() > 0);
937 : // ensure that the subpart has at least two points
938 419626 : double pb = MIN2(laneShape.length2D() - POSITION_EPS - NUMERICAL_EPS, VectorHelper<double>::maxValue(pbv));
939 419626 : if (pb < 0) {
940 : return laneShape;
941 : }
942 419608 : PositionVector ns = laneShape.getSubpart2D(pb, laneShape.length2D());
943 : //PositionVector ns = pb < (laneShape.length() - POSITION_EPS) ? laneShape.getSubpart2D(pb, laneShape.length()) : laneShape;
944 419608 : const double delta = ns[0].z() - laneShape[0].z();
945 : //std::cout << "a) startNode=" << startNode->getID() << " z=" << startNode->getPosition().z() << " oldZ=" << laneShape[0].z() << " cutZ=" << ns[0].z() << " delta=" << delta << "\n";
946 419608 : if (fabs(delta) > 2 * POSITION_EPS && (!startNode->geometryLike() || pb < 1)) {
947 : // make "real" intersections and small intersections flat
948 : //std::cout << "a) startNode=" << startNode->getID() << " z=" << startNode->getPosition().z() << " oldZ=" << laneShape[0].z() << " cutZ=" << ns[0].z() << " delta=" << delta << "\n";
949 2837 : ns[0].setz(startNode->getPosition().z());
950 : }
951 : assert(ns.size() >= 2);
952 : return ns;
953 597680 : } else if (nodeShape.intersects(lb)) {
954 : // extension of first segment intersects
955 59752 : std::vector<double> pbv = lb.intersectsAtLengths2D(nodeShape);
956 : assert(pbv.size() > 0);
957 : double pb = VectorHelper<double>::maxValue(pbv);
958 : assert(pb >= 0);
959 59752 : PositionVector result = laneShape.getSubpartByIndex(1, (int)laneShape.size() - 1);
960 59752 : Position np = lb.positionAtOffset2D(pb);
961 59752 : const double delta = np.z() - laneShape[0].z();
962 : //std::cout << "b) startNode=" << startNode->getID() << " z=" << startNode->getPosition().z() << " oldZ=" << laneShape[0].z() << " cutZ=" << np.z() << " delta=" << delta << "\n";
963 59752 : if (fabs(delta) > 2 * POSITION_EPS && !startNode->geometryLike()) {
964 : // avoid z-overshoot when extrapolating
965 : //std::cout << "b) startNode=" << startNode->getID() << " z=" << startNode->getPosition().z() << " oldZ=" << laneShape[0].z() << " cutZ=" << np.z() << " delta=" << delta << "\n";
966 : np.setz(startNode->getPosition().z());
967 : }
968 59752 : result.push_front_noDoublePos(np);
969 : return result;
970 : //if (result.size() >= 2) {
971 : // return result;
972 : //} else {
973 : // WRITE_WARNING(error + " (resulting shape is too short)");
974 : // return laneShape;
975 : //}
976 59752 : } else {
977 : // could not find proper intersection. Probably the edge is very short
978 : // and lies within nodeShape
979 : // @todo enable warning WRITE_WARNING(error + " (laneShape lies within nodeShape)");
980 : return laneShape;
981 : }
982 597680 : }
983 :
984 :
985 : const PositionVector&
986 2469738 : NBEdge::getLaneShape(int i) const {
987 2469738 : return myLanes[i].shape;
988 : }
989 :
990 :
991 : void
992 1217 : NBEdge::setLaneSpreadFunction(LaneSpreadFunction spread) {
993 1217 : myLaneSpreadFunction = spread;
994 1217 : }
995 :
996 :
997 : LaneSpreadFunction
998 238069 : NBEdge::getLaneSpreadFunction() const {
999 238069 : return myLaneSpreadFunction;
1000 : }
1001 :
1002 :
1003 : void
1004 702 : NBEdge::addGeometryPoint(int index, const Position& p) {
1005 702 : if (index >= 0) {
1006 351 : myGeom.insert(myGeom.begin() + index, p);
1007 : } else {
1008 351 : myGeom.insert(myGeom.end() + index, p);
1009 : }
1010 702 : }
1011 :
1012 :
1013 : void
1014 462 : NBEdge::reduceGeometry(const double minDist) {
1015 : // attempt symmetrical removal for forward and backward direction
1016 : // (very important for bidiRail)
1017 462 : if (myFrom->getID() < myTo->getID()) {
1018 232 : PositionVector reverse = myGeom.reverse();
1019 232 : reverse.removeDoublePoints(minDist, true, 0, 0, true);
1020 464 : myGeom = reverse.reverse();
1021 628 : for (Lane& lane : myLanes) {
1022 792 : reverse = lane.customShape.reverse();
1023 396 : reverse.removeDoublePoints(minDist, true, 0, 0, true);
1024 792 : lane.customShape = reverse.reverse();
1025 : }
1026 232 : } else {
1027 230 : myGeom.removeDoublePoints(minDist, true, 0, 0, true);
1028 578 : for (Lane& lane : myLanes) {
1029 348 : lane.customShape.removeDoublePoints(minDist, true, 0, 0, true);
1030 : }
1031 : }
1032 462 : }
1033 :
1034 :
1035 : void
1036 68465 : NBEdge::checkGeometry(const double maxAngle, bool fixAngle, const double minRadius, bool fix, bool silent) {
1037 68465 : if (myGeom.size() < 3) {
1038 37576 : return;
1039 : }
1040 : //std::cout << "checking geometry of " << getID() << " geometry = " << toString(myGeom) << "\n";
1041 : std::vector<double> angles; // absolute segment angles
1042 : //std::cout << " absolute angles:";
1043 179326 : for (int i = 0; i < (int)myGeom.size() - 1; ++i) {
1044 148391 : angles.push_back(myGeom.angleAt2D(i));
1045 : //std::cout << " " << angles.back();
1046 : }
1047 : //std::cout << "\n relative angles: ";
1048 30935 : NBEdge* bidi = const_cast<NBEdge*>(getBidiEdge());
1049 148171 : for (int i = 0; i < (int)angles.size() - 1; ++i) {
1050 117282 : const double relAngle = fabs(GeomHelper::angleDiff(angles[i], angles[i + 1]));
1051 : //std::cout << relAngle << " ";
1052 117282 : if (maxAngle > 0 && relAngle > maxAngle) {
1053 127 : if (fixAngle) {
1054 3 : WRITE_MESSAGEF(TL("Removing sharp angle of % degrees at edge '%', segment %."),
1055 : toString(relAngle), getID(), i);
1056 : myGeom.erase(myGeom.begin() + i + 1);
1057 1 : if (bidi != nullptr) {
1058 0 : bidi->myGeom = myGeom.reverse();
1059 : }
1060 1 : checkGeometry(maxAngle, fixAngle, minRadius, fix, silent);
1061 46 : return;
1062 126 : } else if (!silent) {
1063 378 : WRITE_WARNINGF(TL("Found angle of % degrees at edge '%', segment %."), RAD2DEG(relAngle), getID(), i);
1064 : }
1065 : }
1066 117281 : if (relAngle < DEG2RAD(1)) {
1067 33011 : continue;
1068 : }
1069 84270 : if (i == 0 || i == (int)angles.size() - 2) {
1070 : const bool start = i == 0;
1071 35241 : const double dist = (start ? myGeom[0].distanceTo2D(myGeom[1]) : myGeom[-2].distanceTo2D(myGeom[-1]));
1072 35241 : const double r = tan(0.5 * (M_PI - relAngle)) * dist;
1073 : //std::cout << (start ? " start" : " end") << " length=" << dist << " radius=" << r << " ";
1074 35241 : if (minRadius > 0 && r < minRadius) {
1075 571 : if (fix) {
1076 135 : WRITE_MESSAGEF(TL("Removing sharp turn with radius % at the % of edge '%'."),
1077 : toString(r), start ? TL("start") : TL("end"), getID());
1078 45 : myGeom.erase(myGeom.begin() + (start ? 1 : i + 1));
1079 45 : if (bidi != nullptr) {
1080 0 : bidi->myGeom = myGeom.reverse();
1081 : }
1082 45 : checkGeometry(maxAngle, fixAngle, minRadius, fix, silent);
1083 45 : return;
1084 526 : } else if (!silent) {
1085 1500 : WRITE_WARNINGF(TL("Found sharp turn with radius % at the % of edge '%'."),
1086 : toString(r), start ? TL("start") : TL("end"), getID());
1087 : }
1088 : }
1089 : }
1090 : }
1091 : //std::cout << "\n";
1092 30935 : }
1093 :
1094 :
1095 : // ----------- Setting and getting connections
1096 : bool
1097 56047 : NBEdge::addEdge2EdgeConnection(NBEdge* dest, bool overrideRemoval, SVCPermissions permissions) {
1098 56047 : if (myStep == EdgeBuildingStep::INIT_REJECT_CONNECTIONS) {
1099 : return true;
1100 : }
1101 : // check whether the node was merged and now a connection between
1102 : // not matching edges is tried to be added
1103 : // This happens f.e. within the ptv VISSIM-example "Beijing"
1104 56047 : if (dest != nullptr && myTo != dest->myFrom) {
1105 : return false;
1106 : }
1107 : if (dest == nullptr) {
1108 87 : invalidateConnections();
1109 174 : myConnections.push_back(Connection(-1, dest, -1));
1110 55960 : } else if (find_if(myConnections.begin(), myConnections.end(), connections_toedge_finder(dest)) == myConnections.end()) {
1111 92538 : myConnections.push_back(Connection(-1, dest, -1));
1112 46269 : myConnections.back().permissions = permissions;
1113 : }
1114 56047 : if (overrideRemoval) {
1115 : // override earlier delete decision
1116 937 : for (std::vector<Connection>::iterator it = myConnectionsToDelete.begin(); it != myConnectionsToDelete.end();) {
1117 341 : if (it->toEdge == dest) {
1118 2 : it = myConnectionsToDelete.erase(it);
1119 : } else {
1120 : it++;
1121 : }
1122 : }
1123 : }
1124 56047 : if (myStep < EdgeBuildingStep::EDGE2EDGES) {
1125 25796 : myStep = EdgeBuildingStep::EDGE2EDGES;
1126 : }
1127 : return true;
1128 : }
1129 :
1130 :
1131 : bool
1132 55477 : NBEdge::addLane2LaneConnection(int from, NBEdge* dest,
1133 : int toLane, Lane2LaneInfoType type,
1134 : bool mayUseSameDestination,
1135 : bool mayDefinitelyPass,
1136 : KeepClear keepClear,
1137 : double contPos,
1138 : double visibility,
1139 : double speed,
1140 : double friction,
1141 : double length,
1142 : const PositionVector& customShape,
1143 : bool uncontrolled,
1144 : SVCPermissions permissions,
1145 : bool indirectLeft,
1146 : const std::string& edgeType,
1147 : SVCPermissions changeLeft,
1148 : SVCPermissions changeRight,
1149 : bool postProcess) {
1150 55477 : if (myStep == EdgeBuildingStep::INIT_REJECT_CONNECTIONS) {
1151 : return true;
1152 : }
1153 : // check whether the node was merged and now a connection between
1154 : // not matching edges is tried to be added
1155 : // This happens f.e. within the ptv VISSIM-example "Beijing"
1156 55477 : if (myTo != dest->myFrom) {
1157 : return false;
1158 : }
1159 54857 : if (!addEdge2EdgeConnection(dest)) {
1160 : return false;
1161 : }
1162 54857 : return setConnection(from, dest, toLane, type, mayUseSameDestination, mayDefinitelyPass, keepClear, contPos, visibility, speed, friction, length,
1163 54857 : customShape, uncontrolled, permissions, indirectLeft, edgeType, changeLeft, changeRight, postProcess);
1164 : }
1165 :
1166 :
1167 : bool
1168 1446 : NBEdge::addLane2LaneConnections(int fromLane,
1169 : NBEdge* dest, int toLane,
1170 : int no, Lane2LaneInfoType type,
1171 : bool invalidatePrevious,
1172 : bool mayDefinitelyPass) {
1173 1446 : if (invalidatePrevious) {
1174 781 : invalidateConnections(true);
1175 : }
1176 : bool ok = true;
1177 3328 : for (int i = 0; i < no && ok; i++) {
1178 3764 : ok &= addLane2LaneConnection(fromLane + i, dest, toLane + i, type, false, mayDefinitelyPass);
1179 : }
1180 1446 : return ok;
1181 : }
1182 :
1183 :
1184 : bool
1185 199600 : NBEdge::setConnection(int lane, NBEdge* destEdge,
1186 : int destLane, Lane2LaneInfoType type,
1187 : bool mayUseSameDestination,
1188 : bool mayDefinitelyPass,
1189 : KeepClear keepClear,
1190 : double contPos,
1191 : double visibility,
1192 : double speed,
1193 : double friction,
1194 : double length,
1195 : const PositionVector& customShape,
1196 : bool uncontrolled,
1197 : SVCPermissions permissions,
1198 : bool indirectLeft,
1199 : const std::string& edgeType,
1200 : SVCPermissions changeLeft,
1201 : SVCPermissions changeRight,
1202 : bool postProcess) {
1203 199600 : if (myStep == EdgeBuildingStep::INIT_REJECT_CONNECTIONS) {
1204 : return false;
1205 : }
1206 : // some kind of a misbehaviour which may occure when the junction's outgoing
1207 : // edge priorities were not properly computed, what may happen due to
1208 : // an incomplete or not proper input
1209 : // what happens is that under some circumstances a single lane may set to
1210 : // be approached more than once by the one of our lanes.
1211 : // This must not be!
1212 : // we test whether it is the case and do nothing if so - the connection
1213 : // will be refused
1214 : //
1215 199600 : if (!mayUseSameDestination && hasConnectionTo(destEdge, destLane)) {
1216 : return false;
1217 : }
1218 188583 : if (find_if(myConnections.begin(), myConnections.end(), connections_finder(lane, destEdge, destLane)) != myConnections.end()) {
1219 : return true;
1220 : }
1221 188545 : if ((int)myLanes.size() <= lane || destEdge->getNumLanes() <= (int)destLane) {
1222 : // problem might be corrigible in post-processing
1223 22 : WRITE_WARNINGF(TL("Could not set connection from '%' to '%'."), getLaneID(lane), destEdge->getLaneID(destLane));
1224 11 : return false;
1225 : }
1226 616824 : for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end();) {
1227 428290 : if ((*i).toEdge == destEdge && ((*i).fromLane == -1 || (*i).toLane == -1)) {
1228 141946 : if (permissions == SVC_UNSPECIFIED) {
1229 : // @note: in case we were to add multiple connections from the
1230 : // same lane the second one wouldn't get the special permissions!
1231 141913 : permissions = (*i).permissions;
1232 : }
1233 141946 : i = myConnections.erase(i);
1234 : } else {
1235 : ++i;
1236 : }
1237 : }
1238 377068 : myConnections.push_back(Connection(lane, destEdge, destLane));
1239 188534 : if (mayDefinitelyPass) {
1240 27 : myConnections.back().mayDefinitelyPass = true;
1241 : }
1242 188534 : myConnections.back().keepClear = keepClear;
1243 188534 : myConnections.back().contPos = contPos;
1244 188534 : myConnections.back().visibility = visibility;
1245 188534 : myConnections.back().permissions = permissions;
1246 188534 : myConnections.back().indirectLeft = indirectLeft;
1247 188534 : myConnections.back().edgeType = edgeType;
1248 188534 : myConnections.back().changeLeft = changeLeft;
1249 188534 : myConnections.back().changeRight = changeRight;
1250 188534 : myConnections.back().speed = speed;
1251 188534 : myConnections.back().friction = friction;
1252 188534 : myConnections.back().customLength = length;
1253 : myConnections.back().customShape = customShape;
1254 188534 : myConnections.back().uncontrolled = uncontrolled;
1255 188534 : if (type == Lane2LaneInfoType::USER) {
1256 2868 : myStep = EdgeBuildingStep::LANES2LANES_USER;
1257 : } else {
1258 : // check whether we have to take another look at it later
1259 185666 : if (type == Lane2LaneInfoType::COMPUTED) {
1260 : // yes, the connection was set using an algorithm which requires a recheck
1261 102949 : myStep = EdgeBuildingStep::LANES2LANES_RECHECK;
1262 : } else {
1263 : // ok, let's only not recheck it if we did no add something that has to be rechecked
1264 82717 : if (myStep != EdgeBuildingStep::LANES2LANES_RECHECK) {
1265 53491 : myStep = EdgeBuildingStep::LANES2LANES_DONE;
1266 : }
1267 : }
1268 : }
1269 188534 : if (postProcess) {
1270 : // override earlier delete decision
1271 18 : for (std::vector<Connection>::iterator it = myConnectionsToDelete.begin(); it != myConnectionsToDelete.end();) {
1272 0 : if ((it->fromLane < 0 || it->fromLane == lane)
1273 1 : && (it->toEdge == nullptr || it->toEdge == destEdge)
1274 2 : && (it->toLane < 0 || it->toLane == destLane)) {
1275 1 : it = myConnectionsToDelete.erase(it);
1276 : } else {
1277 : it++;
1278 : }
1279 : }
1280 : }
1281 : return true;
1282 : }
1283 :
1284 :
1285 : std::vector<NBEdge::Connection>
1286 2897436 : NBEdge::getConnectionsFromLane(int lane, const NBEdge* to, int toLane) const {
1287 : std::vector<NBEdge::Connection> ret;
1288 13485689 : for (const Connection& c : myConnections) {
1289 10588253 : if ((lane < 0 || c.fromLane == lane)
1290 6658196 : && (to == nullptr || to == c.toEdge)
1291 6643317 : && (toLane < 0 || toLane == c.toLane)) {
1292 6642180 : ret.push_back(c);
1293 : }
1294 : }
1295 2897436 : return ret;
1296 0 : }
1297 :
1298 :
1299 : const NBEdge::Connection&
1300 364669 : NBEdge::getConnection(int fromLane, const NBEdge* to, int toLane) const {
1301 768113 : for (const Connection& c : myConnections) {
1302 768113 : if (c.fromLane == fromLane && c.toEdge == to && c.toLane == toLane) {
1303 364669 : return c;
1304 : }
1305 : }
1306 0 : throw ProcessError("Connection from " + getID() + "_" + toString(fromLane)
1307 0 : + " to " + to->getID() + "_" + toString(toLane) + " not found");
1308 : }
1309 :
1310 :
1311 : NBEdge::Connection&
1312 6 : NBEdge::getConnectionRef(int fromLane, const NBEdge* to, int toLane) {
1313 14 : for (Connection& c : myConnections) {
1314 14 : if (c.fromLane == fromLane && c.toEdge == to && c.toLane == toLane) {
1315 6 : return c;
1316 : }
1317 : }
1318 0 : throw ProcessError("Connection from " + getID() + "_" + toString(fromLane)
1319 0 : + " to " + to->getID() + "_" + toString(toLane) + " not found");
1320 : }
1321 :
1322 :
1323 : bool
1324 243016 : NBEdge::hasConnectionTo(const NBEdge* destEdge, int destLane, int fromLane) const {
1325 243016 : return destEdge != nullptr && find_if(myConnections.begin(), myConnections.end(), connections_toedgelane_finder(destEdge, destLane, fromLane)) != myConnections.end();
1326 : }
1327 :
1328 :
1329 : bool
1330 800039 : NBEdge::isConnectedTo(const NBEdge* e, const bool ignoreTurnaround) const {
1331 800039 : if (!ignoreTurnaround && (e == myTurnDestination)) {
1332 : return true;
1333 : }
1334 : return
1335 792080 : find_if(myConnections.begin(), myConnections.end(), connections_toedge_finder(e))
1336 : !=
1337 : myConnections.end();
1338 :
1339 : }
1340 :
1341 :
1342 : const EdgeVector*
1343 66473 : NBEdge::getConnectedSorted() {
1344 : // check whether connections exist and if not, use edges from the node
1345 : EdgeVector outgoing;
1346 66473 : if (myConnections.size() == 0) {
1347 21261 : outgoing = myTo->getOutgoingEdges();
1348 : } else {
1349 135040 : for (std::vector<Connection>::const_iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
1350 89828 : if (find(outgoing.begin(), outgoing.end(), (*i).toEdge) == outgoing.end()) {
1351 89517 : outgoing.push_back((*i).toEdge);
1352 : }
1353 : }
1354 : }
1355 73508 : for (std::vector<Connection>::iterator it = myConnectionsToDelete.begin(); it != myConnectionsToDelete.end(); ++it) {
1356 7035 : if (it->fromLane < 0 && it->toLane < 0) {
1357 : // found an edge that shall not be connected
1358 7035 : EdgeVector::iterator forbidden = std::find(outgoing.begin(), outgoing.end(), it->toEdge);
1359 7035 : if (forbidden != outgoing.end()) {
1360 : outgoing.erase(forbidden);
1361 : }
1362 : }
1363 : }
1364 : // allocate the sorted container
1365 66473 : int size = (int) outgoing.size();
1366 66473 : EdgeVector* edges = new EdgeVector();
1367 66473 : edges->reserve(size);
1368 184097 : for (EdgeVector::const_iterator i = outgoing.begin(); i != outgoing.end(); i++) {
1369 117624 : NBEdge* outedge = *i;
1370 117624 : if (outedge != nullptr && outedge != myTurnDestination) {
1371 108316 : edges->push_back(outedge);
1372 : }
1373 : }
1374 66473 : std::sort(edges->begin(), edges->end(), NBContHelper::relative_outgoing_edge_sorter(this));
1375 66473 : return edges;
1376 66473 : }
1377 :
1378 :
1379 : EdgeVector
1380 153680 : NBEdge::getConnectedEdges() const {
1381 : EdgeVector ret;
1382 508386 : for (std::vector<Connection>::const_iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
1383 354706 : if (find(ret.begin(), ret.end(), (*i).toEdge) == ret.end()) {
1384 207409 : ret.push_back((*i).toEdge);
1385 : }
1386 : }
1387 153680 : return ret;
1388 0 : }
1389 :
1390 :
1391 : EdgeVector
1392 6667 : NBEdge::getIncomingEdges() const {
1393 : EdgeVector ret;
1394 6667 : const EdgeVector& candidates = myFrom->getIncomingEdges();
1395 22678 : for (EdgeVector::const_iterator i = candidates.begin(); i != candidates.end(); i++) {
1396 16011 : if ((*i)->isConnectedTo(this)) {
1397 14787 : ret.push_back(*i);
1398 : }
1399 : }
1400 6667 : return ret;
1401 0 : }
1402 :
1403 :
1404 : std::vector<int>
1405 462601 : NBEdge::getConnectionLanes(NBEdge* currentOutgoing, bool withBikes) const {
1406 : std::vector<int> ret;
1407 462601 : if (currentOutgoing != myTurnDestination) {
1408 1383549 : for (const Connection& c : myConnections) {
1409 964449 : if (c.toEdge == currentOutgoing && (withBikes || getPermissions(c.fromLane) != SVC_BICYCLE)) {
1410 377874 : ret.push_back(c.fromLane);
1411 : }
1412 : }
1413 : }
1414 462601 : return ret;
1415 0 : }
1416 :
1417 :
1418 : void
1419 91415 : NBEdge::sortOutgoingConnectionsByAngle() {
1420 91415 : sort(myConnections.begin(), myConnections.end(), connections_relative_edgelane_sorter(this));
1421 91415 : }
1422 :
1423 :
1424 : void
1425 146839 : NBEdge::sortOutgoingConnectionsByIndex() {
1426 146839 : sort(myConnections.begin(), myConnections.end(), connections_sorter);
1427 146839 : }
1428 :
1429 :
1430 : void
1431 0 : NBEdge::remapConnections(const EdgeVector& incoming) {
1432 0 : EdgeVector connected = getConnectedEdges();
1433 0 : for (EdgeVector::const_iterator i = incoming.begin(); i != incoming.end(); i++) {
1434 0 : NBEdge* inc = *i;
1435 : // We have to do this
1436 0 : inc->myStep = EdgeBuildingStep::EDGE2EDGES;
1437 : // add all connections
1438 0 : for (EdgeVector::iterator j = connected.begin(); j != connected.end(); j++) {
1439 0 : inc->addEdge2EdgeConnection(*j);
1440 : }
1441 0 : inc->removeFromConnections(this);
1442 : }
1443 0 : }
1444 :
1445 :
1446 : void
1447 48894 : NBEdge::removeFromConnections(NBEdge* toEdge, int fromLane, int toLane, bool tryLater, const bool adaptToLaneRemoval,
1448 : const bool keepPossibleTurns) {
1449 : // remove from "myConnections"
1450 48894 : const int fromLaneRemoved = adaptToLaneRemoval && fromLane >= 0 ? fromLane : -1;
1451 48894 : const int toLaneRemoved = adaptToLaneRemoval && toLane >= 0 ? toLane : -1;
1452 69347 : for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end();) {
1453 : Connection& c = *i;
1454 20453 : if ((toEdge == nullptr || c.toEdge == toEdge)
1455 1197 : && (fromLane < 0 || c.fromLane == fromLane)
1456 1034 : && (toLane < 0 || c.toLane == toLane)) {
1457 897 : if (myTo->isTLControlled()) {
1458 : std::set<NBTrafficLightDefinition*> tldefs = myTo->getControllingTLS();
1459 362 : for (std::set<NBTrafficLightDefinition*>::iterator it = tldefs.begin(); it != tldefs.end(); it++) {
1460 181 : (*it)->removeConnection(NBConnection(this, c.fromLane, c.toEdge, c.toLane));
1461 : }
1462 : }
1463 897 : i = myConnections.erase(i);
1464 : tryLater = false;
1465 897 : } else {
1466 19556 : if (fromLaneRemoved >= 0 && c.fromLane > fromLaneRemoved) {
1467 128 : if (myTo->isTLControlled()) {
1468 : std::set<NBTrafficLightDefinition*> tldefs = myTo->getControllingTLS();
1469 10 : for (std::set<NBTrafficLightDefinition*>::iterator it = tldefs.begin(); it != tldefs.end(); it++) {
1470 83 : for (NBConnectionVector::iterator tlcon = (*it)->getControlledLinks().begin(); tlcon != (*it)->getControlledLinks().end(); ++tlcon) {
1471 : NBConnection& tc = *tlcon;
1472 78 : if (tc.getTo() == c.toEdge && tc.getFromLane() == c.fromLane && tc.getToLane() == c.toLane) {
1473 12 : tc.shiftLaneIndex(this, -1);
1474 : }
1475 : }
1476 : }
1477 : }
1478 : //std::cout << getID() << " removeFromConnections fromLane=" << fromLane << " to=" << Named::getIDSecure(toEdge) << " toLane=" << toLane << " reduceFromLane=" << c.fromLane << " (to=" << c.toLane << ")\n";
1479 128 : c.fromLane--;
1480 : }
1481 19556 : if (toLaneRemoved >= 0 && c.toLane > toLaneRemoved && (toEdge == nullptr || c.toEdge == toEdge)) {
1482 : //std::cout << getID() << " removeFromConnections fromLane=" << fromLane << " to=" << Named::getIDSecure(toEdge) << " toLane=" << toLane << " reduceToLane=" << c.toLane << " (from=" << c.fromLane << ")\n";
1483 101 : c.toLane--;
1484 : }
1485 : ++i;
1486 : }
1487 : }
1488 : // check whether it was the turn destination
1489 48894 : if (myTurnDestination == toEdge && fromLane < 0) {
1490 2613 : myTurnDestination = nullptr;
1491 : }
1492 48894 : if (myPossibleTurnDestination == toEdge && fromLane < 0 && !keepPossibleTurns) {
1493 2127 : myPossibleTurnDestination = nullptr;
1494 : }
1495 48894 : if (tryLater) {
1496 14272 : myConnectionsToDelete.push_back(Connection(fromLane, toEdge, toLane));
1497 : #ifdef DEBUG_CONNECTION_GUESSING
1498 : if (DEBUGCOND) {
1499 : std::cout << "removeFromConnections " << getID() << "_" << fromLane << "->" << toEdge->getID() << "_" << toLane << "\n";
1500 : for (Connection& c : myConnections) {
1501 : std::cout << " conn " << c.getDescription(this) << "\n";
1502 : }
1503 : for (Connection& c : myConnectionsToDelete) {
1504 : std::cout << " connToDelete " << c.getDescription(this) << "\n";
1505 : }
1506 : }
1507 : #endif
1508 : }
1509 48894 : }
1510 :
1511 :
1512 : bool
1513 10 : NBEdge::removeFromConnections(const NBEdge::Connection& connectionToRemove) {
1514 : // iterate over connections
1515 12 : for (auto i = myConnections.begin(); i != myConnections.end(); i++) {
1516 12 : if ((i->toEdge == connectionToRemove.toEdge) && (i->fromLane == connectionToRemove.fromLane) && (i->toLane == connectionToRemove.toLane)) {
1517 : // remove connection
1518 10 : myConnections.erase(i);
1519 : return true;
1520 : }
1521 : }
1522 : // assert(false);
1523 : return false;
1524 : }
1525 :
1526 :
1527 : void
1528 3499 : NBEdge::invalidateConnections(bool reallowSetting) {
1529 3499 : myTurnDestination = nullptr;
1530 : myConnections.clear();
1531 3499 : if (reallowSetting) {
1532 3397 : myStep = EdgeBuildingStep::INIT;
1533 : } else {
1534 102 : myStep = EdgeBuildingStep::INIT_REJECT_CONNECTIONS;
1535 : }
1536 3499 : }
1537 :
1538 :
1539 : void
1540 918 : NBEdge::replaceInConnections(NBEdge* which, NBEdge* by, int laneOff) {
1541 : // replace in "_connectedEdges"
1542 1636 : for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
1543 718 : if ((*i).toEdge == which) {
1544 499 : (*i).toEdge = by;
1545 499 : (*i).toLane += laneOff;
1546 : }
1547 : }
1548 : // check whether it was the turn destination
1549 918 : if (myTurnDestination == which) {
1550 20 : myTurnDestination = by;
1551 : }
1552 918 : }
1553 :
1554 : void
1555 45635 : NBEdge::replaceInConnections(NBEdge* which, const std::vector<NBEdge::Connection>& origConns) {
1556 : std::map<int, int> laneMap;
1557 : int minLane = -1;
1558 : int maxLane = -1;
1559 : // get lanes used to approach the edge to remap
1560 : bool wasConnected = false;
1561 52457 : for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
1562 6822 : if ((*i).toEdge != which) {
1563 6121 : continue;
1564 : }
1565 : wasConnected = true;
1566 701 : if ((*i).fromLane != -1) {
1567 : int fromLane = (*i).fromLane;
1568 671 : laneMap[(*i).toLane] = fromLane;
1569 671 : if (minLane == -1 || minLane > fromLane) {
1570 : minLane = fromLane;
1571 : }
1572 671 : if (maxLane == -1 || maxLane < fromLane) {
1573 : maxLane = fromLane;
1574 : }
1575 : }
1576 : }
1577 45635 : if (!wasConnected) {
1578 : return;
1579 : }
1580 : // add new connections
1581 495 : std::vector<NBEdge::Connection> conns = origConns;
1582 495 : EdgeVector origTargets = getSuccessors();
1583 2545 : for (std::vector<NBEdge::Connection>::iterator i = conns.begin(); i != conns.end(); ++i) {
1584 2050 : if ((*i).toEdge == which || (*i).toEdge == this
1585 : // if we already have connections to the target edge, do not add new ones as they are probably from a circular replacement
1586 4046 : || std::find(origTargets.begin(), origTargets.end(), (*i).toEdge) != origTargets.end()) {
1587 : #ifdef DEBUG_REPLACECONNECTION
1588 : if (DEBUGCOND) {
1589 : std::cout << " replaceInConnections edge=" << getID() << " which=" << which->getID()
1590 : << " origTargets=" << toString(origTargets) << " newTarget=" << i->toEdge->getID() << " skipped\n";
1591 : }
1592 : #endif
1593 863 : continue;
1594 : }
1595 1190 : if (which->getStep() == EdgeBuildingStep::EDGE2EDGES) {
1596 : // do not set lane-level connections
1597 3 : replaceInConnections(which, (*i).toEdge, 0);
1598 3 : continue;
1599 : }
1600 1187 : int fromLane = (*i).fromLane;
1601 : int toUse = -1;
1602 1187 : if (laneMap.find(fromLane) == laneMap.end()) {
1603 278 : if (fromLane >= 0 && fromLane <= minLane) {
1604 : toUse = minLane;
1605 : // patch laneMap to avoid crossed-over connections
1606 441 : for (auto& item : laneMap) {
1607 241 : if (item.first < fromLane) {
1608 35 : item.second = MIN2(item.second, minLane);
1609 : }
1610 : }
1611 : }
1612 278 : if (fromLane >= 0 && fromLane >= maxLane) {
1613 : toUse = maxLane;
1614 : // patch laneMap to avoid crossed-over connections
1615 320 : for (auto& item : laneMap) {
1616 175 : if (item.first > fromLane) {
1617 62 : item.second = MAX2(item.second, maxLane);
1618 : }
1619 : }
1620 : }
1621 : } else {
1622 909 : toUse = laneMap[fromLane];
1623 : }
1624 1187 : if (toUse == -1) {
1625 : toUse = 0;
1626 : }
1627 : #ifdef DEBUG_REPLACECONNECTION
1628 : if (DEBUGCOND) {
1629 : std::cout << " replaceInConnections edge=" << getID() << " which=" << which->getID() << " origTargets=" << toString(origTargets)
1630 : << " origFrom=" << fromLane << " laneMap=" << joinToString(laneMap, ":", ",") << " minLane=" << minLane << " maxLane=" << maxLane
1631 : << " newTarget=" << i->toEdge->getID() << " fromLane=" << toUse << " toLane=" << i->toLane << "\n";
1632 : }
1633 : #endif
1634 2374 : setConnection(toUse, i->toEdge, i->toLane, Lane2LaneInfoType::COMPUTED, false, i->mayDefinitelyPass, i->keepClear,
1635 1187 : i->contPos, i->visibility, i->speed, i->friction, i->customLength, i->customShape, i->uncontrolled);
1636 : }
1637 : // remove the remapped edge from connections
1638 495 : removeFromConnections(which);
1639 495 : }
1640 :
1641 :
1642 : void
1643 606 : NBEdge::copyConnectionsFrom(NBEdge* src) {
1644 606 : myStep = src->myStep;
1645 606 : myConnections = src->myConnections;
1646 606 : }
1647 :
1648 :
1649 : bool
1650 1102 : NBEdge::canMoveConnection(const Connection& con, int newFromLane) const {
1651 : // only allow using newFromLane if at least 1 vClass is permitted to use
1652 : // this connection. If the connection shall be moved to a sidewalk, only create the connection if there is no walking area
1653 1102 : const SVCPermissions common = (getPermissions(newFromLane) & con.toEdge->getPermissions(con.toLane));
1654 1102 : return (common > 0 && common != SVC_PEDESTRIAN);
1655 : }
1656 :
1657 :
1658 : void
1659 486 : NBEdge::moveConnectionToLeft(int lane) {
1660 : #ifdef DEBUG_CONNECTION_CHECKING
1661 : std::cout << " moveConnectionToLeft " << getID() << " lane=" << lane << "\n";
1662 : #endif
1663 : int index = 0;
1664 2956 : for (int i = 0; i < (int)myConnections.size(); ++i) {
1665 2470 : if (myConnections[i].fromLane == (int)(lane) && canMoveConnection(myConnections[i], lane + 1)) {
1666 : index = i;
1667 : }
1668 : }
1669 : std::vector<Connection>::iterator i = myConnections.begin() + index;
1670 486 : Connection c = *i;
1671 486 : myConnections.erase(i);
1672 486 : setConnection(lane + 1, c.toEdge, c.toLane, Lane2LaneInfoType::VALIDATED, false);
1673 486 : }
1674 :
1675 :
1676 : void
1677 99 : NBEdge::moveConnectionToRight(int lane) {
1678 : #ifdef DEBUG_CONNECTION_CHECKING
1679 : std::cout << " moveConnectionToRight " << getID() << " lane=" << lane << "\n";
1680 : #endif
1681 353 : for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
1682 353 : if ((*i).fromLane == (int)lane && canMoveConnection(*i, lane - 1)) {
1683 99 : Connection c = *i;
1684 99 : i = myConnections.erase(i);
1685 99 : setConnection(lane - 1, c.toEdge, c.toLane, Lane2LaneInfoType::VALIDATED, false);
1686 : return;
1687 99 : }
1688 : }
1689 : }
1690 :
1691 :
1692 : double
1693 48107 : NBEdge::buildInnerEdges(const NBNode& n, int noInternalNoSplits, int& linkIndex, int& splitIndex) {
1694 48107 : const OptionsCont& oc = OptionsCont::getOptions();
1695 48107 : const int numPoints = oc.getInt("junctions.internal-link-detail");
1696 48107 : const bool joinTurns = oc.getBool("junctions.join-turns");
1697 48107 : const double limitTurnSpeed = oc.getFloat("junctions.limit-turn-speed");
1698 48107 : const double limitTurnSpeedMinAngle = DEG2RAD(oc.getFloat("junctions.limit-turn-speed.min-angle"));
1699 48107 : const double limitTurnSpeedMinAngleRail = DEG2RAD(oc.getFloat("junctions.limit-turn-speed.min-angle.railway"));
1700 48107 : const double limitTurnSpeedWarnStraight = oc.getFloat("junctions.limit-turn-speed.warn.straight");
1701 48107 : const double limitTurnSpeedWarnTurn = oc.getFloat("junctions.limit-turn-speed.warn.turn");
1702 48107 : const bool higherSpeed = oc.getBool("junctions.higher-speed");
1703 48107 : const double interalJunctionVehicleWidth = oc.getFloat("internal-junctions.vehicle-width");
1704 48107 : const double defaultContPos = oc.getFloat("default.connection.cont-pos");
1705 48107 : const bool fromRail = isRailway(getPermissions());
1706 48107 : std::string innerID = ":" + n.getID();
1707 : NBEdge* toEdge = nullptr;
1708 48107 : int edgeIndex = linkIndex;
1709 : int internalLaneIndex = 0;
1710 : int numLanes = 0; // number of lanes that share the same edge
1711 : double lengthSum = 0; // total shape length of all lanes that share the same edge
1712 : int avoidedIntersectingLeftOriginLane = std::numeric_limits<int>::max();
1713 : bool averageLength = true;
1714 : double maxCross = 0.;
1715 143958 : for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
1716 : Connection& con = *i;
1717 95851 : con.haveVia = false; // reset first since this may be called multiple times
1718 95851 : if (con.toEdge == nullptr) {
1719 0 : continue;
1720 : }
1721 95851 : LinkDirection dir = n.getDirection(this, con.toEdge);
1722 95851 : const bool isRightTurn = (dir == LinkDirection::RIGHT || dir == LinkDirection::PARTRIGHT);
1723 95851 : const bool isTurn = (isRightTurn || dir == LinkDirection::LEFT || dir == LinkDirection::PARTLEFT);
1724 : // put turning internal lanes on separate edges
1725 95851 : if (con.toEdge != toEdge) {
1726 : // skip indices to keep some correspondence between edge ids and link indices:
1727 : // internalEdgeIndex + internalLaneIndex = linkIndex
1728 86375 : edgeIndex = linkIndex;
1729 : toEdge = con.toEdge;
1730 : internalLaneIndex = 0;
1731 86375 : maxCross = MAX2(maxCross, assignInternalLaneLength(i, numLanes, lengthSum, averageLength));
1732 : numLanes = 0;
1733 : lengthSum = 0;
1734 : }
1735 95851 : averageLength = !isTurn || joinTurns; // legacy behavior
1736 95851 : SVCPermissions conPermissions = getPermissions(con.fromLane) & con.toEdge->getPermissions(con.toLane);
1737 95851 : const int conShapeFlag = (conPermissions & ~SVC_PEDESTRIAN) != 0 ? 0 : NBNode::SCURVE_IGNORE;
1738 95851 : PositionVector shape = n.computeInternalLaneShape(this, con, numPoints, myTo, conShapeFlag);
1739 : std::vector<int> foeInternalLinks;
1740 :
1741 95851 : if (dir != LinkDirection::STRAIGHT && shape.length() < POSITION_EPS && !(isBidiRail() && getTurnDestination(true) == con.toEdge)) {
1742 204 : WRITE_WARNINGF(TL("Connection '%_%->%_%' is only %m short."), getID(), con.fromLane, con.toEdge->getID(), con.toLane, shape.length());
1743 : }
1744 :
1745 : // crossingPosition, list of foe link indices
1746 95851 : std::pair<double, std::vector<int> > crossingPositions(-1, std::vector<int>());
1747 : std::set<std::string> tmpFoeIncomingLanes;
1748 95851 : if (dir != LinkDirection::STRAIGHT || con.contPos != UNSPECIFIED_CONTPOS) {
1749 60805 : int index = 0;
1750 : std::vector<PositionVector> otherShapes;
1751 60805 : const double width1 = MIN2(interalJunctionVehicleWidth / 2, getLaneWidth(con.fromLane) / 2);
1752 : const double width1OppositeLeft = 0; // using width1 changes a lot of curves even though they are rarely responsible for collisions
1753 267681 : for (const NBEdge* i2 : n.getIncomingEdges()) {
1754 964922 : for (const Connection& k2 : i2->getConnections()) {
1755 758046 : if (k2.toEdge == nullptr) {
1756 0 : continue;
1757 : }
1758 : // vehicles are typically less wide than the lane
1759 : // they drive on but but bicycle lanes should be kept clear for their whole width
1760 758046 : double width2 = k2.toEdge->getLaneWidth(k2.toLane);
1761 758046 : if (k2.toEdge->getPermissions(k2.toLane) != SVC_BICYCLE) {
1762 745795 : width2 *= 0.5;
1763 : }
1764 758046 : const bool foes = n.foes(this, con.toEdge, i2, k2.toEdge);
1765 758046 : LinkDirection dir2 = n.getDirection(i2, k2.toEdge);
1766 758046 : bool needsCont = !isRailway(conPermissions) && (n.needsCont(this, i2, con, k2) || (con.contPos != UNSPECIFIED_CONTPOS && !con.indirectLeft));
1767 758046 : const bool avoidIntersectCandidate = !foes && bothLeftTurns(dir, i2, dir2);
1768 14202 : bool oppositeLeftIntersect = avoidIntersectCandidate && haveIntersection(n, shape, i2, k2, numPoints, width1OppositeLeft, width2);
1769 : int shapeFlag = 0;
1770 758046 : SVCPermissions warn = SVCAll & ~(SVC_PEDESTRIAN | SVC_BICYCLE | SVC_DELIVERY | SVC_RAIL_CLASSES);
1771 : // do not warn if only bicycles, pedestrians or delivery vehicles are involved as this is a typical occurrence
1772 : if (con.customShape.size() == 0
1773 757438 : && k2.customShape.size() == 0
1774 757128 : && (oppositeLeftIntersect || (avoidedIntersectingLeftOriginLane < con.fromLane && avoidIntersectCandidate))
1775 761817 : && ((i2->getPermissions(k2.fromLane) & warn) != 0
1776 3264 : && (k2.toEdge->getPermissions(k2.toLane) & warn) != 0)) {
1777 : // recompute with different curve parameters (unless
1778 : // the other connection is "unimportant"
1779 3178 : shapeFlag = NBNode::AVOID_INTERSECTING_LEFT_TURNS;
1780 : PositionVector origShape = shape;
1781 6356 : shape = n.computeInternalLaneShape(this, con, numPoints, myTo, shapeFlag);
1782 3178 : oppositeLeftIntersect = haveIntersection(n, shape, i2, k2, numPoints, width1OppositeLeft, width2, shapeFlag);
1783 3178 : if (oppositeLeftIntersect
1784 2107 : && (conPermissions & (SVCAll & ~(SVC_BICYCLE | SVC_PEDESTRIAN))) == 0) {
1785 : shape = origShape;
1786 : } else {
1787 : // recompute previously computed crossing positions
1788 3130 : if (avoidedIntersectingLeftOriginLane == std::numeric_limits<int>::max()
1789 1759 : || avoidedIntersectingLeftOriginLane < con.fromLane) {
1790 3230 : for (const PositionVector& otherShape : otherShapes) {
1791 1811 : const bool secondIntersection = con.indirectLeft && this == i2 && con.fromLane == k2.fromLane;
1792 1811 : const double minDV = firstIntersection(shape, otherShape, width1OppositeLeft, width2,
1793 1811 : "Could not compute intersection of conflicting internal lanes at node '" + myTo->getID() + "'", secondIntersection);
1794 1811 : if (minDV < shape.length() - POSITION_EPS && minDV > POSITION_EPS) { // !!!?
1795 : assert(minDV >= 0);
1796 1680 : if (crossingPositions.first < 0 || crossingPositions.first > minDV) {
1797 269 : crossingPositions.first = minDV;
1798 : }
1799 : }
1800 : }
1801 : }
1802 : // make sure connections further to the left do not get a wider angle
1803 3130 : avoidedIntersectingLeftOriginLane = con.fromLane;
1804 : }
1805 3178 : }
1806 758046 : const bool bothPrio = getJunctionPriority(&n) > 0 && i2->getJunctionPriority(&n) > 0;
1807 : //std::cout << "n=" << n.getID() << " e1=" << getID() << " prio=" << getJunctionPriority(&n) << " e2=" << i2->getID() << " prio2=" << i2->getJunctionPriority(&n) << " both=" << bothPrio << " bothLeftIntersect=" << bothLeftIntersect(n, shape, dir, i2, k2, numPoints, width2) << " needsCont=" << needsCont << "\n";
1808 : // the following special case might get obsolete once we have solved #9745
1809 758046 : const bool isBicycleLeftTurn = k2.indirectLeft || (dir2 == LinkDirection::LEFT && (i2->getPermissions(k2.fromLane) & k2.toEdge->getPermissions(k2.toLane)) == SVC_BICYCLE);
1810 : // compute the crossing point
1811 758046 : if ((needsCont || (bothPrio && oppositeLeftIntersect && !isRailway(conPermissions))) && (!con.indirectLeft || dir2 == LinkDirection::STRAIGHT) && !isBicycleLeftTurn) {
1812 32332 : crossingPositions.second.push_back(index);
1813 32332 : const PositionVector otherShape = n.computeInternalLaneShape(i2, k2, numPoints, 0, shapeFlag);
1814 32332 : otherShapes.push_back(otherShape);
1815 32332 : const bool secondIntersection = con.indirectLeft && this == i2 && con.fromLane == k2.fromLane;
1816 32332 : const double minDV = firstIntersection(shape, otherShape, width1, width2,
1817 32332 : "Could not compute intersection of conflicting internal lanes at node '" + myTo->getID() + "'", secondIntersection);
1818 32332 : if (minDV < shape.length() - POSITION_EPS && minDV > POSITION_EPS) { // !!!?
1819 : assert(minDV >= 0);
1820 27595 : if (crossingPositions.first < 0 || crossingPositions.first > minDV) {
1821 26962 : crossingPositions.first = minDV;
1822 : }
1823 : }
1824 32332 : }
1825 758046 : const bool rightTurnConflict = NBNode::rightTurnConflict(
1826 758046 : this, con.toEdge, con.fromLane, i2, k2.toEdge, k2.fromLane);
1827 758046 : const bool indirectTurnConflit = con.indirectLeft && this == i2 && dir2 == LinkDirection::STRAIGHT;
1828 758046 : const bool mergeConflict = myTo->mergeConflict(this, con, i2, k2, true);
1829 758046 : const bool mergeResponse = myTo->mergeConflict(this, con, i2, k2, false);
1830 758046 : const bool bidiConflict = myTo->bidiConflict(this, con, i2, k2, true);
1831 : // compute foe internal lanes
1832 758046 : if (foes || rightTurnConflict || oppositeLeftIntersect || mergeConflict || indirectTurnConflit || bidiConflict) {
1833 216133 : foeInternalLinks.push_back(index);
1834 : }
1835 : // only warn once per pair of intersecting turns
1836 2720 : if (oppositeLeftIntersect && getID() > i2->getID()
1837 1359 : && (getPermissions(con.fromLane) & warn) != 0
1838 1146 : && (con.toEdge->getPermissions(con.toLane) & warn) != 0
1839 1111 : && (i2->getPermissions(k2.fromLane) & warn) != 0
1840 1042 : && (k2.toEdge->getPermissions(k2.toLane) & warn) != 0
1841 : // do not warn for unregulated nodes
1842 759073 : && n.getType() != SumoXMLNodeType::NOJUNCTION
1843 : ) {
1844 516 : WRITE_WARNINGF(TL("Intersecting left turns at junction '%' from lane '%' and lane '%' (increase junction radius to avoid this)."),
1845 : n.getID(), getLaneID(con.fromLane), i2->getLaneID(k2.fromLane));
1846 : }
1847 : // compute foe incoming lanes
1848 758046 : const bool signalised = hasSignalisedConnectionTo(con.toEdge);
1849 1386581 : if ((n.forbids(i2, k2.toEdge, this, con.toEdge, signalised) || rightTurnConflict || indirectTurnConflit || mergeResponse)
1850 758671 : && (needsCont || dir == LinkDirection::TURN || (!signalised && this != i2 && !con.indirectLeft))) {
1851 231118 : tmpFoeIncomingLanes.insert(i2->getID() + "_" + toString(k2.fromLane));
1852 : }
1853 758046 : if (bothPrio && oppositeLeftIntersect && getID() < i2->getID()) {
1854 : //std::cout << " c1=" << con.getDescription(this) << " c2=" << k2.getDescription(i2) << " bothPrio=" << bothPrio << " oppositeLeftIntersect=" << oppositeLeftIntersect << "\n";
1855 : // break symmetry using edge id
1856 : // only store link index and resolve actual lane id later (might be multi-lane internal edge)
1857 344 : tmpFoeIncomingLanes.insert(":" + toString(index));
1858 : }
1859 758046 : index++;
1860 : }
1861 : }
1862 60805 : if (dir == LinkDirection::TURN && crossingPositions.first < 0 && crossingPositions.second.size() != 0 && shape.length() > 2. * POSITION_EPS) {
1863 : // let turnarounds wait in the middle if no other crossing point was found and it has a sensible length
1864 : // (if endOffset is used, the crossing point is in the middle of the part within the junction shape)
1865 232 : crossingPositions.first = (double)(shape.length() + getEndOffset(con.fromLane)) / 2.;
1866 : }
1867 : // foe pedestrian crossings
1868 60805 : std::vector<NBNode::Crossing*> crossings = n.getCrossings();
1869 71324 : for (auto c : crossings) {
1870 : const NBNode::Crossing& crossing = *c;
1871 28976 : for (EdgeVector::const_iterator it_e = crossing.edges.begin(); it_e != crossing.edges.end(); ++it_e) {
1872 18457 : const NBEdge* edge = *it_e;
1873 : // compute foe internal lanes
1874 18457 : if ((this == edge || con.toEdge == edge) && !isRailway(conPermissions)) {
1875 4753 : foeInternalLinks.push_back(index);
1876 4753 : if (con.toEdge == edge &&
1877 2378 : ((isRightTurn && getJunctionPriority(&n) > 0) || (isTurn && con.tlID != ""))) {
1878 : // build internal junctions (not for left turns at uncontrolled intersections)
1879 : PositionVector crossingShape = crossing.shape;
1880 1152 : crossingShape.extrapolate(5.0); // sometimes shapes miss each other by a small margin
1881 1152 : const double minDV = firstIntersection(shape, crossingShape, 0, crossing.width / 2);
1882 1152 : if (minDV < shape.length() - POSITION_EPS && minDV > POSITION_EPS) {
1883 : assert(minDV >= 0);
1884 1076 : if (crossingPositions.first < 0 || crossingPositions.first > minDV) {
1885 599 : crossingPositions.first = minDV;
1886 : }
1887 : }
1888 4753 : } else if (this == edge && crossing.priority && !myTo->isTLControlled()) {
1889 12 : crossingPositions.first = 0;
1890 : }
1891 : }
1892 : }
1893 10519 : index++;
1894 : }
1895 :
1896 60805 : }
1897 95851 : if (con.contPos == UNSPECIFIED_CONTPOS) {
1898 95823 : con.contPos = defaultContPos;
1899 : }
1900 95851 : if (con.contPos != UNSPECIFIED_CONTPOS) {
1901 : // apply custom internal junction position
1902 48 : if (con.contPos <= 0 || con.contPos >= shape.length()) {
1903 : // disable internal junction
1904 21 : crossingPositions.first = -1;
1905 : } else {
1906 : // set custom position
1907 27 : crossingPositions.first = con.contPos;
1908 : }
1909 : }
1910 :
1911 : // @todo compute the maximum speed allowed based on angular velocity
1912 : // see !!! for an explanation (with a_lat_mean ~0.3)
1913 : /*
1914 : double vmax = (double) 0.3 * (double) 9.80778 *
1915 : getLaneShape(con.fromLane).back().distanceTo(
1916 : con.toEdge->getLaneShape(con.toLane).front())
1917 : / (double) 2.0 / (double) M_PI;
1918 : vmax = MIN2(vmax, ((getSpeed() + con.toEdge->getSpeed()) / (double) 2.0));
1919 : */
1920 95851 : if (con.speed == UNSPECIFIED_SPEED) {
1921 95700 : if (higherSpeed) {
1922 44 : con.vmax = MAX2(myLanes[con.fromLane].speed, con.toEdge->getLanes()[con.toLane].speed);
1923 : } else {
1924 95676 : con.vmax = (myLanes[con.fromLane].speed + con.toEdge->getLanes()[con.toLane].speed) / (double) 2.0;
1925 : }
1926 95700 : if (limitTurnSpeed > 0) {
1927 : // see [Odhams and Cole, Models of Driver Speed Choice in Curves, 2004]
1928 180630 : const double angleRaw = fabs(GeomHelper::angleDiff(
1929 90315 : getLaneShape(con.fromLane).angleAt2D(-2),
1930 90315 : con.toEdge->getLaneShape(con.toLane).angleAt2D(0)));
1931 177722 : const double angle = MAX2(0.0, angleRaw - (fromRail ? limitTurnSpeedMinAngleRail : limitTurnSpeedMinAngle));
1932 90315 : const double length = shape.length2D();
1933 : // do not trust the radius of tiny junctions
1934 : // formula adapted from [Odhams, Andre and Cole, David, Models of Driver Speed Choice in Curves, 2004]
1935 90315 : if (angle > 0 && length > 1) {
1936 : // permit higher turning speed on wide lanes
1937 60754 : const double radius = length / angle + getLaneWidth(con.fromLane) / 4;
1938 60754 : const double limit = sqrt(limitTurnSpeed * radius);
1939 60754 : const double reduction = con.vmax - limit;
1940 : // always treat connctions at roundabout as turns when warning
1941 60754 : const bool atRoundabout = getJunctionPriority(myTo) == JunctionPriority::ROUNDABOUT || con.toEdge->getJunctionPriority(myFrom) == JunctionPriority::ROUNDABOUT;
1942 : const LinkDirection dir2 = atRoundabout ? LinkDirection::LEFT : dir;
1943 60492 : if ((dir2 == LinkDirection::STRAIGHT && reduction > limitTurnSpeedWarnStraight)
1944 60576 : || (dir2 != LinkDirection::TURN && reduction > limitTurnSpeedWarnTurn)) {
1945 490 : std::string dirType = std::string(dir == LinkDirection::STRAIGHT ? "straight" : "turning");
1946 334 : if (atRoundabout) {
1947 : dirType = "roundabout";
1948 : }
1949 1002 : WRITE_WARNINGF(TL("Speed of % connection '%' reduced by % due to turning radius of % (length=%, angle=%)."),
1950 : dirType, con.getDescription(this), reduction, radius, length, RAD2DEG(angleRaw));
1951 : }
1952 113864 : con.vmax = MIN2(con.vmax, limit);
1953 : // value is saved in <net> attribute. Must be set again when importing from .con.xml
1954 : // con.speed = con.vmax;
1955 : }
1956 : assert(con.vmax > 0);
1957 : //if (getID() == "-1017000.0.00") {
1958 : // std::cout << con.getDescription(this) << " angleRaw=" << angleRaw << " angle=" << RAD2DEG(angle) << " length=" << length << " radius=" << length / angle
1959 : // << " vmaxTurn=" << sqrt(limitTurnSpeed * length / angle) << " vmax=" << con.vmax << "\n";
1960 : //}
1961 5385 : } else if (fromRail && dir == LinkDirection::TURN) {
1962 0 : con.vmax = 0.01;
1963 : }
1964 : } else {
1965 151 : con.vmax = con.speed;
1966 : }
1967 95851 : if (con.friction == UNSPECIFIED_FRICTION) {
1968 95851 : con.friction = (myLanes[con.fromLane].friction + con.toEdge->getLanes()[con.toLane].friction) / 2.;
1969 : }
1970 : //
1971 : assert(shape.size() >= 2);
1972 : // get internal splits if any
1973 191702 : con.id = innerID + "_" + toString(edgeIndex);
1974 95851 : const double shapeLength = shape.length();
1975 : double firstLength = shapeLength;
1976 95851 : if (crossingPositions.first > 0 && crossingPositions.first < shapeLength) {
1977 18186 : std::pair<PositionVector, PositionVector> split = shape.splitAt(crossingPositions.first);
1978 : con.shape = split.first;
1979 18186 : con.foeIncomingLanes = std::vector<std::string>(tmpFoeIncomingLanes.begin(), tmpFoeIncomingLanes.end());
1980 18186 : con.foeInternalLinks = foeInternalLinks; // resolve link indices to lane ids later
1981 18186 : if (i != myConnections.begin() && (i - 1)->toEdge == con.toEdge && (i - 1)->haveVia) {
1982 192 : --splitIndex;
1983 192 : con.internalViaLaneIndex = (i - 1)->internalViaLaneIndex + 1;
1984 : }
1985 36372 : con.viaID = innerID + "_" + toString(splitIndex + noInternalNoSplits);
1986 18186 : ++splitIndex;
1987 : con.viaShape = split.second;
1988 18186 : con.haveVia = true;
1989 18186 : firstLength = con.shape.length();
1990 18186 : } else {
1991 : con.shape = shape;
1992 : }
1993 95851 : con.internalLaneIndex = internalLaneIndex;
1994 95851 : ++internalLaneIndex;
1995 95851 : ++linkIndex;
1996 : ++numLanes;
1997 95851 : if (con.customLength != UNSPECIFIED_LOADED_LENGTH) {
1998 : // split length proportionally
1999 28 : lengthSum += firstLength / shapeLength * con.customLength;
2000 : } else {
2001 95823 : lengthSum += firstLength;
2002 : }
2003 95851 : }
2004 96214 : return MAX2(maxCross, assignInternalLaneLength(myConnections.end(), numLanes, lengthSum, averageLength));
2005 : }
2006 :
2007 :
2008 : double
2009 134482 : NBEdge::assignInternalLaneLength(std::vector<Connection>::iterator i, int numLanes, double lengthSum, bool averageLength) {
2010 : // assign average length to all lanes of the same internal edge if averageLength is set
2011 : // the lengthSum only covers the part up to the first internal junction
2012 : // TODO This code assumes that either all connections in question have a via or none
2013 : double maxCross = 0.;
2014 : assert(i - myConnections.begin() >= numLanes);
2015 230333 : for (int prevIndex = 1; prevIndex <= numLanes; prevIndex++) {
2016 : //std::cout << " con=" << (*(i - prevIndex)).getDescription(this) << " numLanes=" << numLanes << " avgLength=" << lengthSum / numLanes << "\n";
2017 : Connection& c = (*(i - prevIndex));
2018 95851 : const double minLength = c.customLength != UNSPECIFIED_LOADED_LENGTH ? pow(10, -gPrecision) : POSITION_EPS;
2019 95851 : c.length = MAX2(minLength, averageLength ? lengthSum / numLanes : c.shape.length());
2020 95851 : if (c.haveVia) {
2021 36372 : c.viaLength = MAX2(minLength, c.viaShape.length());
2022 : }
2023 95851 : if (c.customLength != UNSPECIFIED_LOADED_LENGTH) {
2024 28 : if (c.haveVia) {
2025 : // split length proportionally
2026 4 : const double a = c.viaLength / (c.shape.length() + c.viaLength);
2027 6 : c.viaLength = MAX2(minLength, a * c.customLength);
2028 : }
2029 28 : if (!averageLength) {
2030 19 : c.length = MAX2(minLength, c.customLength - c.viaLength);
2031 : }
2032 : }
2033 95851 : if (c.haveVia) {
2034 : // we need to be able to leave from the internal junction by accelerating from 0
2035 18186 : maxCross = MAX2(maxCross, sqrt(2. * c.viaLength)); // t = sqrt(2*s/a) and we assume 'a' is at least 1 (default value for tram in SUMOVTypeParameter)
2036 : }
2037 : // we need to be able to cross the junction in one go but not if we have an indirect left turn
2038 95851 : if (c.indirectLeft) {
2039 15 : maxCross = MAX2(maxCross, MAX2(c.length, c.viaLength) / MAX2(c.vmax, NBOwnTLDef::MIN_SPEED_CROSSING_TIME));
2040 : } else {
2041 136870 : maxCross = MAX2(maxCross, (c.length + c.viaLength) / MAX2(c.vmax, NBOwnTLDef::MIN_SPEED_CROSSING_TIME));
2042 : }
2043 : }
2044 134482 : return maxCross;
2045 : }
2046 :
2047 :
2048 : double
2049 74411 : NBEdge::firstIntersection(const PositionVector& v1, const PositionVector& v2, double width1, double width2, const std::string& error, bool secondIntersection) {
2050 : double intersect = std::numeric_limits<double>::max();
2051 74411 : if (v2.length() < POSITION_EPS) {
2052 : return intersect;
2053 : }
2054 : try {
2055 : PositionVector v1Right = v1;
2056 74380 : v1Right.move2side(width1);
2057 :
2058 : PositionVector v1Left = v1;
2059 74380 : v1Left.move2side(-width1);
2060 :
2061 : PositionVector v2Right = v2;
2062 74380 : v2Right.move2side(width2);
2063 :
2064 : PositionVector v2Left = v2;
2065 74380 : v2Left.move2side(-width2);
2066 :
2067 : // intersect all border combinations
2068 : bool skip = secondIntersection;
2069 98054 : for (double cand : v1Left.intersectsAtLengths2D(v2Right)) {
2070 23674 : if (skip) {
2071 : skip = false;
2072 8 : continue;
2073 : }
2074 : intersect = MIN2(intersect, cand);
2075 74380 : }
2076 : skip = secondIntersection;
2077 110854 : for (double cand : v1Left.intersectsAtLengths2D(v2Left)) {
2078 36474 : if (skip) {
2079 : skip = false;
2080 11 : continue;
2081 : }
2082 : intersect = MIN2(intersect, cand);
2083 74380 : }
2084 : skip = secondIntersection;
2085 117383 : for (double cand : v1Right.intersectsAtLengths2D(v2Right)) {
2086 43003 : if (skip) {
2087 : skip = false;
2088 9 : continue;
2089 : }
2090 : intersect = MIN2(intersect, cand);
2091 74380 : }
2092 : skip = secondIntersection;
2093 111563 : for (double cand : v1Right.intersectsAtLengths2D(v2Left)) {
2094 37183 : if (skip) {
2095 : skip = false;
2096 11 : continue;
2097 : }
2098 : intersect = MIN2(intersect, cand);
2099 74380 : }
2100 74380 : } catch (InvalidArgument&) {
2101 0 : if (error != "") {
2102 0 : WRITE_WARNING(error);
2103 : }
2104 0 : }
2105 : //std::cout << " v1=" << v1 << " v2Right=" << v2Right << " v2Left=" << v2Left << "\n";
2106 : //std::cout << " intersectsRight=" << toString(v1.intersectsAtLengths2D(v2Right)) << "\n";
2107 : //std::cout << " intersectsLeft=" << toString(v1.intersectsAtLengths2D(v2Left)) << "\n";
2108 : return intersect;
2109 : }
2110 :
2111 :
2112 : bool
2113 545345 : NBEdge::bothLeftTurns(LinkDirection dir, const NBEdge* otherFrom, LinkDirection dir2) const {
2114 545345 : if (otherFrom == this) {
2115 : // not an opposite pair
2116 : return false;
2117 : }
2118 332549 : return (dir == LinkDirection::LEFT || dir == LinkDirection::PARTLEFT) && (dir2 == LinkDirection::LEFT || dir2 == LinkDirection::PARTLEFT);
2119 : }
2120 :
2121 : bool
2122 17380 : NBEdge::haveIntersection(const NBNode& n, const PositionVector& shape, const NBEdge* otherFrom, const NBEdge::Connection& otherCon, int numPoints,
2123 : double width1, double width2, int shapeFlag) const {
2124 17380 : const PositionVector otherShape = n.computeInternalLaneShape(otherFrom, otherCon, numPoints, 0, shapeFlag);
2125 17380 : const double minDV = firstIntersection(shape, otherShape, width1, width2);
2126 34760 : return minDV < shape.length() - POSITION_EPS && minDV > POSITION_EPS;
2127 17380 : }
2128 :
2129 :
2130 : // -----------
2131 : int
2132 9812839 : NBEdge::getJunctionPriority(const NBNode* const node) const {
2133 9812839 : if (node == myFrom) {
2134 263810 : return myFromJunctionPriority;
2135 : } else {
2136 9549029 : return myToJunctionPriority;
2137 : }
2138 : }
2139 :
2140 :
2141 : void
2142 262160 : NBEdge::setJunctionPriority(const NBNode* const node, int prio) {
2143 262160 : if (node == myFrom) {
2144 129396 : myFromJunctionPriority = prio;
2145 : #ifdef DEBUG_JUNCTIONPRIO
2146 : setParameter("fromPrio", toString(prio));
2147 : #endif
2148 : } else {
2149 132764 : myToJunctionPriority = prio;
2150 : #ifdef DEBUG_JUNCTIONPRIO
2151 : setParameter("toPrio", toString(prio));
2152 : #endif
2153 : }
2154 262160 : }
2155 :
2156 :
2157 : double
2158 15953053 : NBEdge::getAngleAtNode(const NBNode* const atNode) const {
2159 15953053 : if (atNode == myFrom) {
2160 7839360 : return GeomHelper::legacyDegree(myGeom.angleAt2D(0));
2161 : }
2162 : assert(atNode == myTo);
2163 8113693 : return GeomHelper::legacyDegree(myGeom.angleAt2D(-2));
2164 : }
2165 :
2166 :
2167 : double
2168 2856334 : NBEdge::getAngleAtNodeNormalized(const NBNode* const atNode) const {
2169 : double res;
2170 2856334 : if (atNode == myFrom) {
2171 1415908 : res = GeomHelper::legacyDegree(myGeom.angleAt2D(0)) - 180;
2172 : } else {
2173 : assert(atNode == myTo);
2174 1440426 : res = GeomHelper::legacyDegree(myGeom.angleAt2D(-2));
2175 : }
2176 2856334 : if (res < 0) {
2177 2069126 : res += 360;
2178 : }
2179 2856334 : return res;
2180 : }
2181 :
2182 :
2183 : double
2184 4519316 : NBEdge::getAngleAtNodeToCenter(const NBNode* const atNode) const {
2185 4519316 : if (atNode == myFrom) {
2186 2114771 : double res = myStartAngle - 180;
2187 2114771 : if (res < 0) {
2188 908941 : res += 360;
2189 : }
2190 2114771 : return res;
2191 : } else {
2192 : assert(atNode == myTo);
2193 2404545 : return myEndAngle;
2194 : }
2195 : }
2196 :
2197 :
2198 : void
2199 534417 : NBEdge::setTurningDestination(NBEdge* e, bool onlyPossible) {
2200 534417 : if (!onlyPossible) {
2201 506504 : myTurnDestination = e;
2202 : }
2203 534417 : myPossibleTurnDestination = e;
2204 534417 : }
2205 :
2206 :
2207 : double
2208 10225 : NBEdge::getLaneSpeed(int lane) const {
2209 10225 : return myLanes[lane].speed;
2210 : }
2211 :
2212 :
2213 : double
2214 3423 : NBEdge::getLaneFriction(int lane) const {
2215 3423 : return myLanes[lane].friction;
2216 : }
2217 :
2218 :
2219 : void
2220 80 : NBEdge::resetLaneShapes() {
2221 80 : computeLaneShapes();
2222 80 : }
2223 :
2224 :
2225 : void
2226 6 : NBEdge::updateChangeRestrictions(SVCPermissions ignoring) {
2227 24 : for (Lane& lane : myLanes) {
2228 18 : if (lane.changeLeft != SVCAll) {
2229 6 : lane.changeLeft = ignoring;
2230 : }
2231 18 : if (lane.changeRight != SVCAll) {
2232 6 : lane.changeRight = ignoring;
2233 : }
2234 : }
2235 15 : for (Connection& con : myConnections) {
2236 9 : if (con.changeLeft != SVC_UNSPECIFIED && con.changeLeft != SVCAll) {
2237 0 : con.changeLeft = ignoring;
2238 : }
2239 9 : if (con.changeRight != SVC_UNSPECIFIED && con.changeRight != SVCAll) {
2240 0 : con.changeRight = ignoring;
2241 : }
2242 : }
2243 6 : }
2244 :
2245 :
2246 : void
2247 309116 : NBEdge::computeLaneShapes() {
2248 : // vissim needs this
2249 309116 : if (myFrom == myTo) {
2250 0 : return;
2251 : }
2252 : // compute lane offset, first
2253 309116 : std::vector<double> offsets(myLanes.size(), 0.);
2254 : double offset = 0;
2255 401908 : for (int i = (int)myLanes.size() - 2; i >= 0; --i) {
2256 92792 : offset += (getLaneWidth(i) + getLaneWidth(i + 1)) / 2.;
2257 92792 : offsets[i] = offset;
2258 : }
2259 309116 : if (myLaneSpreadFunction == LaneSpreadFunction::CENTER) {
2260 : double width = 0;
2261 304991 : for (int i = 0; i < (int)myLanes.size(); ++i) {
2262 172873 : width += getLaneWidth(i);
2263 : }
2264 132118 : offset = -width / 2. + getLaneWidth((int)myLanes.size() - 1) / 2.;
2265 : } else {
2266 176998 : double laneWidth = myLanes.back().width != UNSPECIFIED_WIDTH ? myLanes.back().width : SUMO_const_laneWidth;
2267 176998 : offset = laneWidth / 2.;
2268 : }
2269 309116 : if (myLaneSpreadFunction == LaneSpreadFunction::ROADCENTER) {
2270 428 : for (NBEdge* e : myTo->getOutgoingEdges()) {
2271 371 : if (e->getToNode() == myFrom && getInnerGeometry().reverse() == e->getInnerGeometry()) {
2272 203 : offset += (e->getTotalWidth() - getTotalWidth()) / 2;
2273 203 : break;
2274 : }
2275 : }
2276 : }
2277 :
2278 711024 : for (int i = 0; i < (int)myLanes.size(); ++i) {
2279 401908 : offsets[i] += offset;
2280 : }
2281 :
2282 : // build the shape of each lane
2283 711024 : for (int i = 0; i < (int)myLanes.size(); ++i) {
2284 401908 : if (myLanes[i].customShape.size() != 0) {
2285 : myLanes[i].shape = myLanes[i].customShape;
2286 18 : continue;
2287 : }
2288 : try {
2289 803780 : myLanes[i].shape = computeLaneShape(i, offsets[i]);
2290 0 : } catch (InvalidArgument& e) {
2291 0 : WRITE_WARNINGF(TL("In lane '%': lane shape could not be determined (%)."), getLaneID(i), e.what());
2292 : myLanes[i].shape = myGeom;
2293 0 : }
2294 : }
2295 309116 : }
2296 :
2297 :
2298 : PositionVector
2299 401890 : NBEdge::computeLaneShape(int lane, double offset) const {
2300 : PositionVector shape = myGeom;
2301 : try {
2302 401890 : shape.move2side(offset);
2303 0 : } catch (InvalidArgument& e) {
2304 0 : WRITE_WARNINGF(TL("In lane '%': Could not build shape (%)."), getLaneID(lane), e.what());
2305 0 : }
2306 401890 : return shape;
2307 0 : }
2308 :
2309 :
2310 : void
2311 388020 : NBEdge::computeAngle() {
2312 : // taking the angle at the first might be unstable, thus we take the angle
2313 : // at a certain distance. (To compare two edges, additional geometry
2314 : // segments are considered to resolve ambiguities)
2315 388020 : const bool hasFromShape = myFrom->getShape().size() > 0;
2316 388020 : const bool hasToShape = myTo->getShape().size() > 0;
2317 388020 : Position fromCenter = (hasFromShape ? myFrom->getShape().getCentroid() : myFrom->getPosition());
2318 388020 : Position toCenter = (hasToShape ? myTo->getShape().getCentroid() : myTo->getPosition());
2319 : PositionVector shape = myGeom;
2320 388020 : if ((hasFromShape || hasToShape) && getNumLanes() > 0) {
2321 183780 : if (myLaneSpreadFunction == LaneSpreadFunction::RIGHT) {
2322 96081 : shape = myLanes[getNumLanes() - 1].shape ;
2323 : } else {
2324 87699 : shape = myLanes[getNumLanes() / 2].shape;
2325 87699 : if (getNumLanes() % 2 == 0) {
2326 : // there is no center lane. shift to get the center
2327 11999 : shape.move2side(getLaneWidth(getNumLanes() / 2) * 0.5);
2328 : }
2329 : }
2330 : }
2331 :
2332 : // if the junction shape is suspicious we cannot trust the angle to the centroid
2333 388020 : const bool suspiciousFromShape = hasFromShape && (myFrom->getShape().distance2D(shape[0]) > 2 * POSITION_EPS
2334 155049 : || myFrom->getShape().around(shape[-1])
2335 154405 : || !(myFrom->getShape().around(fromCenter)));
2336 388020 : const bool suspiciousToShape = hasToShape && (myTo->getShape().distance2D(shape[-1]) > 2 * POSITION_EPS
2337 150805 : || myTo->getShape().around(shape[0])
2338 150259 : || !(myTo->getShape().around(toCenter)));
2339 :
2340 388020 : const double angleLookahead = MIN2(shape.length2D() / 2, ANGLE_LOOKAHEAD);
2341 388020 : const Position referencePosStart = shape.positionAtOffset2D(angleLookahead);
2342 388020 : const Position referencePosEnd = shape.positionAtOffset2D(shape.length2D() - angleLookahead);
2343 :
2344 388020 : myStartAngle = GeomHelper::legacyDegree(fromCenter.angleTo2D(referencePosStart), true);
2345 388020 : const double myStartAngle2 = GeomHelper::legacyDegree(myFrom->getPosition().angleTo2D(referencePosStart), true);
2346 388020 : const double myStartAngle3 = getAngleAtNode(myFrom);
2347 388020 : myEndAngle = GeomHelper::legacyDegree(referencePosEnd.angleTo2D(toCenter), true);
2348 388020 : const double myEndAngle2 = GeomHelper::legacyDegree(referencePosEnd.angleTo2D(myTo->getPosition()), true);
2349 388020 : const double myEndAngle3 = getAngleAtNode(myTo);
2350 :
2351 : #ifdef DEBUG_ANGLES
2352 : if (DEBUGCOND) {
2353 : if (suspiciousFromShape) {
2354 : std::cout << "suspiciousFromShape len=" << shape.length() << " startA=" << myStartAngle << " startA2=" << myStartAngle2 << " startA3=" << myStartAngle3
2355 : << " rel=" << NBHelpers::normRelAngle(myStartAngle, myStartAngle2)
2356 : << " fromCenter=" << fromCenter
2357 : << " fromPos=" << myFrom->getPosition()
2358 : << " refStart=" << referencePosStart
2359 : << "\n";
2360 : }
2361 : if (suspiciousToShape) {
2362 : std::cout << "suspiciousToShape len=" << shape.length() << " endA=" << myEndAngle << " endA2=" << myEndAngle2 << " endA3=" << myEndAngle3
2363 : << " rel=" << NBHelpers::normRelAngle(myEndAngle, myEndAngle2)
2364 : << " toCenter=" << toCenter
2365 : << " toPos=" << myTo->getPosition()
2366 : << " refEnd=" << referencePosEnd
2367 : << "\n";
2368 : }
2369 : }
2370 : #endif
2371 :
2372 388020 : if (suspiciousFromShape && shape.length() > 1) {
2373 15989 : myStartAngle = myStartAngle2;
2374 39061 : } else if (suspiciousToShape && fabs(NBHelpers::normRelAngle(myStartAngle, myStartAngle3)) > 90
2375 : // don't trust footpath angles
2376 375610 : && (getPermissions() & ~SVC_PEDESTRIAN) != 0) {
2377 2354 : myStartAngle = myStartAngle3;
2378 2354 : if (myStartAngle < 0) {
2379 1167 : myStartAngle += 360;
2380 : }
2381 : }
2382 :
2383 388020 : if (suspiciousToShape && shape.length() > 1) {
2384 20932 : myEndAngle = myEndAngle2;
2385 20592 : } else if (suspiciousToShape && fabs(NBHelpers::normRelAngle(myEndAngle, myEndAngle3)) > 90
2386 : // don't trust footpath angles
2387 371481 : && (getPermissions() & ~SVC_PEDESTRIAN) != 0) {
2388 2620 : myEndAngle = myEndAngle3;
2389 2620 : if (myEndAngle < 0) {
2390 1279 : myEndAngle += 360;
2391 : }
2392 : }
2393 :
2394 388020 : myTotalAngle = GeomHelper::legacyDegree(myFrom->getPosition().angleTo2D(myTo->getPosition()), true);
2395 : #ifdef DEBUG_ANGLES
2396 : if (DEBUGCOND) std::cout << "computeAngle edge=" << getID()
2397 : << " fromCenter=" << fromCenter << " toCenter=" << toCenter
2398 : << " refStart=" << referencePosStart << " refEnd=" << referencePosEnd << " shape=" << shape
2399 : << " hasFromShape=" << hasFromShape
2400 : << " hasToShape=" << hasToShape
2401 : << " numLanes=" << getNumLanes()
2402 : << " shapeLane=" << getNumLanes() / 2
2403 : << " startA=" << myStartAngle << " endA=" << myEndAngle << " totA=" << myTotalAngle << "\n";
2404 : #endif
2405 388020 : }
2406 :
2407 :
2408 : double
2409 187542 : NBEdge::getShapeStartAngle() const {
2410 187542 : const double angleLookahead = MIN2(myGeom.length2D() / 2, ANGLE_LOOKAHEAD);
2411 187542 : const Position referencePosStart = myGeom.positionAtOffset2D(angleLookahead);
2412 187542 : return GeomHelper::legacyDegree(myGeom.front().angleTo2D(referencePosStart), true);
2413 : }
2414 :
2415 :
2416 : double
2417 87421 : NBEdge::getShapeEndAngle() const {
2418 87421 : const double angleLookahead = MIN2(myGeom.length2D() / 2, ANGLE_LOOKAHEAD);
2419 87421 : const Position referencePosEnd = myGeom.positionAtOffset2D(myGeom.length2D() - angleLookahead);
2420 87421 : return GeomHelper::legacyDegree(referencePosEnd.angleTo2D(myGeom.back()), true);
2421 : }
2422 :
2423 :
2424 : bool
2425 0 : NBEdge::hasPermissions() const {
2426 0 : for (std::vector<Lane>::const_iterator i = myLanes.begin(); i != myLanes.end(); ++i) {
2427 0 : if ((*i).permissions != SVCAll) {
2428 : return true;
2429 : }
2430 : }
2431 : return false;
2432 : }
2433 :
2434 :
2435 : bool
2436 4694 : NBEdge::hasLaneSpecificPermissions() const {
2437 : std::vector<Lane>::const_iterator i = myLanes.begin();
2438 4694 : SVCPermissions firstLanePermissions = i->permissions;
2439 : i++;
2440 6288 : for (; i != myLanes.end(); ++i) {
2441 2969 : if (i->permissions != firstLanePermissions) {
2442 : return true;
2443 : }
2444 : }
2445 : return false;
2446 : }
2447 :
2448 :
2449 : bool
2450 4449 : NBEdge::hasLaneSpecificSpeed() const {
2451 13524 : for (std::vector<Lane>::const_iterator i = myLanes.begin(); i != myLanes.end(); ++i) {
2452 9090 : if (i->speed != getSpeed()) {
2453 : return true;
2454 : }
2455 : }
2456 : return false;
2457 : }
2458 :
2459 : bool
2460 1813 : NBEdge::hasLaneSpecificFriction() const {
2461 4935 : for (std::vector<Lane>::const_iterator i = myLanes.begin(); i != myLanes.end(); ++i) {
2462 3126 : if (i->friction != myLanes.begin()->friction) {
2463 : return true;
2464 : }
2465 : }
2466 : return false;
2467 : }
2468 :
2469 : bool
2470 25189 : NBEdge::hasLaneSpecificWidth() const {
2471 56730 : for (std::vector<Lane>::const_iterator i = myLanes.begin(); i != myLanes.end(); ++i) {
2472 33248 : if (i->width != myLanes.begin()->width) {
2473 : return true;
2474 : }
2475 : }
2476 : return false;
2477 : }
2478 :
2479 :
2480 : bool
2481 1561 : NBEdge::hasLaneSpecificType() const {
2482 3780 : for (std::vector<Lane>::const_iterator i = myLanes.begin(); i != myLanes.end(); ++i) {
2483 2221 : if (i->type != myLanes.begin()->type) {
2484 : return true;
2485 : }
2486 : }
2487 : return false;
2488 : }
2489 :
2490 :
2491 : bool
2492 24541 : NBEdge::hasLaneSpecificEndOffset() const {
2493 57390 : for (std::vector<Lane>::const_iterator i = myLanes.begin(); i != myLanes.end(); ++i) {
2494 32866 : if (i->endOffset != myLanes.begin()->endOffset) {
2495 : return true;
2496 : }
2497 : }
2498 : return false;
2499 : }
2500 :
2501 :
2502 : bool
2503 26330 : NBEdge::hasLaneSpecificStopOffsets() const {
2504 62258 : for (const auto& lane : myLanes) {
2505 35933 : if (lane.laneStopOffset.isDefined()) {
2506 5 : if (myEdgeStopOffset.isDefined() || (myEdgeStopOffset != lane.laneStopOffset)) {
2507 : return true;
2508 : }
2509 : }
2510 : }
2511 : return false;
2512 : }
2513 :
2514 :
2515 : bool
2516 1553 : NBEdge::hasAccelLane() const {
2517 3749 : for (std::vector<Lane>::const_iterator i = myLanes.begin(); i != myLanes.end(); ++i) {
2518 2197 : if (i->accelRamp) {
2519 : return true;
2520 : }
2521 : }
2522 : return false;
2523 : }
2524 :
2525 :
2526 : bool
2527 1552 : NBEdge::hasCustomLaneShape() const {
2528 3738 : for (std::vector<Lane>::const_iterator i = myLanes.begin(); i != myLanes.end(); ++i) {
2529 2191 : if (i->customShape.size() > 0) {
2530 : return true;
2531 : }
2532 : }
2533 : return false;
2534 : }
2535 :
2536 :
2537 : bool
2538 1547 : NBEdge::hasLaneParams() const {
2539 3729 : for (std::vector<Lane>::const_iterator i = myLanes.begin(); i != myLanes.end(); ++i) {
2540 2184 : if (i->getParametersMap().size() > 0) {
2541 : return true;
2542 : }
2543 : }
2544 : return false;
2545 : }
2546 :
2547 : bool
2548 1545 : NBEdge::prohibitsChanging() const {
2549 3709 : for (const Lane& lane : myLanes) {
2550 2171 : if (lane.changeLeft != SVCAll || lane.changeRight != SVCAll) {
2551 : return true;
2552 : }
2553 : }
2554 : return false;
2555 : }
2556 :
2557 : bool
2558 1813 : NBEdge::needsLaneSpecificOutput() const {
2559 1813 : return (hasLaneSpecificPermissions()
2560 1568 : || hasLaneSpecificSpeed()
2561 1565 : || hasLaneSpecificWidth()
2562 1561 : || hasLaneSpecificType()
2563 1559 : || hasLaneSpecificEndOffset()
2564 1553 : || hasLaneSpecificStopOffsets()
2565 1553 : || hasAccelLane()
2566 1552 : || hasCustomLaneShape()
2567 1547 : || hasLaneParams()
2568 1545 : || prohibitsChanging()
2569 3351 : || (!myLanes.empty() && myLanes.back().oppositeID != ""));
2570 : }
2571 :
2572 :
2573 :
2574 : bool
2575 90804 : NBEdge::computeEdge2Edges(bool noLeftMovers) {
2576 : #ifdef DEBUG_CONNECTION_GUESSING
2577 : if (DEBUGCOND) {
2578 : std::cout << "computeEdge2Edges edge=" << getID() << " step=" << (int)myStep << " noLeftMovers=" << noLeftMovers << "\n";
2579 : for (Connection& c : myConnections) {
2580 : std::cout << " conn " << c.getDescription(this) << "\n";
2581 : }
2582 : for (Connection& c : myConnectionsToDelete) {
2583 : std::cout << " connToDelete " << c.getDescription(this) << "\n";
2584 : }
2585 : }
2586 : #endif
2587 : // return if this relationship has been build in previous steps or
2588 : // during the import
2589 90804 : if (myStep >= EdgeBuildingStep::EDGE2EDGES) {
2590 : return true;
2591 : }
2592 65914 : const bool fromRail = isRailway(getPermissions());
2593 229997 : for (NBEdge* out : myTo->getOutgoingEdges()) {
2594 164083 : if (noLeftMovers && myTo->isLeftMover(this, out)) {
2595 1140 : continue;
2596 : }
2597 : // avoid sharp railway turns
2598 162943 : if (fromRail && isRailway(out->getPermissions())) {
2599 9514 : const double angle = fabs(NBHelpers::normRelAngle(getAngleAtNode(myTo), out->getAngleAtNode(myTo)));
2600 9514 : if (angle > 150) {
2601 3787 : continue;
2602 5727 : } else if (angle > 90) {
2603 : // possibly the junction is large enough to achieve a plausible radius:
2604 124 : const PositionVector& fromShape = myLanes.front().shape;
2605 124 : const PositionVector& toShape = out->getLanes().front().shape;
2606 124 : PositionVector shape = myTo->computeSmoothShape(fromShape, toShape, 5, getTurnDestination() == out, 5, 5);
2607 124 : const double radius = shape.length2D() / DEG2RAD(angle);
2608 124 : const double minRadius = (getPermissions() & SVC_TRAM) != 0 ? 20 : 80;
2609 : //std::cout << getID() << " to=" << out->getID() << " radius=" << radius << " minRadius=" << minRadius << "\n";
2610 124 : if (radius < minRadius) {
2611 : continue;
2612 : }
2613 124 : }
2614 : }
2615 159035 : if (out == myTurnDestination) {
2616 : // will be added by appendTurnaround
2617 41968 : continue;
2618 : }
2619 117067 : if ((getPermissions() & out->getPermissions() & ~SVC_PEDESTRIAN) == 0) {
2620 : // no common permissions
2621 28838 : continue;
2622 : }
2623 176458 : myConnections.push_back(Connection(-1, out, -1));
2624 : }
2625 65914 : myStep = EdgeBuildingStep::EDGE2EDGES;
2626 65914 : return true;
2627 : }
2628 :
2629 :
2630 : bool
2631 90804 : NBEdge::computeLanes2Edges() {
2632 : #ifdef DEBUG_CONNECTION_GUESSING
2633 : if (DEBUGCOND) {
2634 : std::cout << "computeLanes2Edges edge=" << getID() << " step=" << (int)myStep << "\n";
2635 : for (Connection& c : myConnections) {
2636 : std::cout << " conn " << c.getDescription(this) << "\n";
2637 : }
2638 : for (Connection& c : myConnectionsToDelete) {
2639 : std::cout << " connToDelete " << c.getDescription(this) << "\n";
2640 : }
2641 : }
2642 : #endif
2643 : // return if this relationship has been build in previous steps or
2644 : // during the import
2645 90804 : if (myStep >= EdgeBuildingStep::LANES2EDGES) {
2646 : return true;
2647 : }
2648 : assert(myStep == EdgeBuildingStep::EDGE2EDGES);
2649 : // get list of possible outgoing edges sorted by direction clockwise
2650 : // the edge in the backward direction (turnaround) is not in the list
2651 66473 : const EdgeVector* edges = getConnectedSorted();
2652 66473 : if (myConnections.size() != 0 && edges->size() == 0) {
2653 : // dead end per definition!?
2654 : myConnections.clear();
2655 : } else {
2656 : // divide the lanes on reachable edges
2657 66364 : divideOnEdges(edges);
2658 : }
2659 66473 : delete edges;
2660 66473 : myStep = EdgeBuildingStep::LANES2EDGES;
2661 66473 : return true;
2662 : }
2663 :
2664 :
2665 : std::vector<LinkDirection>
2666 358 : NBEdge::decodeTurnSigns(int turnSigns, int shift) {
2667 : std::vector<LinkDirection> result;
2668 3222 : for (int i = 0; i < 8; i++) {
2669 : // see LinkDirection in SUMOXMLDefinitions.h
2670 2864 : if ((turnSigns & (1 << (i + shift))) != 0) {
2671 295 : result.push_back((LinkDirection)(1 << i));
2672 : }
2673 : }
2674 358 : return result;
2675 0 : }
2676 :
2677 : void
2678 252 : NBEdge::updateTurnPermissions(SVCPermissions& perm, LinkDirection dir, SVCPermissions spec, std::vector<LinkDirection> dirs) {
2679 252 : if (dirs.size() > 0) {
2680 71 : if (std::find(dirs.begin(), dirs.end(), dir) == dirs.end()) {
2681 2 : perm &= ~spec;
2682 : } else {
2683 69 : perm |= spec;
2684 : }
2685 : }
2686 252 : }
2687 :
2688 : bool
2689 31 : NBEdge::applyTurnSigns() {
2690 : #ifdef DEBUG_TURNSIGNS
2691 : std::cout << "applyTurnSigns edge=" << getID() << "\n";
2692 : #endif
2693 : // build a map of target edges and lanes
2694 : std::vector<const NBEdge*> targets;
2695 : std::map<const NBEdge*, std::vector<int> > toLaneMap;
2696 126 : for (const Connection& c : myConnections) {
2697 95 : if (myLanes[c.fromLane].turnSigns != 0) {
2698 95 : if (std::find(targets.begin(), targets.end(), c.toEdge) == targets.end()) {
2699 78 : targets.push_back(c.toEdge);
2700 : }
2701 95 : toLaneMap[c.toEdge].push_back(c.toLane);
2702 : }
2703 : }
2704 : // might be unsorted due to bike lane connections
2705 109 : for (auto& item : toLaneMap) {
2706 78 : std::sort(item.second.begin(), item.second.end());
2707 : }
2708 :
2709 : // check number of distinct signed directions and count the number of signs for each direction
2710 : std::map<LinkDirection, int> signCons;
2711 : int allDirs = 0;
2712 103 : for (const Lane& lane : myLanes) {
2713 72 : allDirs |= lane.turnSigns;
2714 162 : for (LinkDirection dir : decodeTurnSigns(lane.turnSigns)) {
2715 90 : signCons[dir]++;
2716 72 : }
2717 : }
2718 31 : allDirs |= allDirs >> TURN_SIGN_SHIFT_BUS;
2719 31 : allDirs |= allDirs >> TURN_SIGN_SHIFT_TAXI;
2720 31 : allDirs |= allDirs >> TURN_SIGN_SHIFT_BICYCLE;
2721 :
2722 31 : if ((allDirs & (int)LinkDirection::NODIR) != 0) {
2723 3 : targets.push_back(nullptr); // dead end
2724 : }
2725 :
2726 : SVCPermissions defaultPermissions = SVC_PASSENGER | SVC_DELIVERY;
2727 : // build a mapping from sign directions to targets
2728 31 : std::vector<LinkDirection> signedDirs = decodeTurnSigns(allDirs);
2729 : std::map<LinkDirection, const NBEdge*> dirMap;
2730 : #ifdef DEBUG_TURNSIGNS
2731 : std::cout << " numDirs=" << signedDirs.size() << " numTargets=" << targets.size() << "\n";
2732 : #endif
2733 31 : if (signedDirs.size() > targets.size()) {
2734 18 : WRITE_WARNINGF(TL("Cannot apply turn sign information for edge '%' because there are % signed directions but only % targets"), getID(), signedDirs.size(), targets.size());
2735 6 : return false;
2736 25 : } else if (signedDirs.size() < targets.size()) {
2737 : // we need to drop some targets (i.e. turn-around)
2738 : // use sumo-directions as a guide
2739 : std::vector<LinkDirection> sumoDirs;
2740 67 : for (const NBEdge* to : targets) {
2741 53 : sumoDirs.push_back(myTo->getDirection(this, to));
2742 : }
2743 : // remove targets to the left
2744 : bool checkMore = true;
2745 29 : while (signedDirs.size() < targets.size() && checkMore) {
2746 : checkMore = false;
2747 : //std::cout << getID() << " sumoDirs=" << joinToString(sumoDirs, ",") << " signedDirs=" << joinToString(signedDirs, ",") << "\n";
2748 15 : if (sumoDirs.back() != signedDirs.back()) {
2749 : targets.pop_back();
2750 : sumoDirs.pop_back();
2751 : checkMore = true;
2752 : }
2753 : }
2754 : // remove targets to the right
2755 : checkMore = true;
2756 16 : while (signedDirs.size() < targets.size() && checkMore) {
2757 : checkMore = false;
2758 2 : if (sumoDirs.front() != signedDirs.front()) {
2759 : targets.erase(targets.begin());
2760 : sumoDirs.erase(sumoDirs.begin());
2761 : checkMore = true;
2762 : }
2763 : }
2764 : // remove targets by permissions
2765 : int i = 0;
2766 19 : while (signedDirs.size() < targets.size() && i < (int)targets.size()) {
2767 5 : if (targets[i] != nullptr && (targets[i]->getPermissions() & defaultPermissions) == 0) {
2768 : targets.erase(targets.begin() + i);
2769 : sumoDirs.erase(sumoDirs.begin() + i);
2770 : } else {
2771 5 : i++;
2772 : }
2773 : }
2774 14 : if (signedDirs.size() != targets.size()) {
2775 6 : WRITE_WARNINGF(TL("Cannot apply turn sign information for edge '%' because there are % signed directions and % targets (after target pruning)"), getID(), signedDirs.size(), targets.size());
2776 : return false;
2777 : }
2778 14 : }
2779 : // directions and connections are both sorted from right to left
2780 80 : for (int i = 0; i < (int)signedDirs.size(); i++) {
2781 57 : dirMap[signedDirs[i]] = targets[i];
2782 : }
2783 : // check whether we have enough target lanes for a each signed direction
2784 76 : for (auto item : signCons) {
2785 55 : const LinkDirection dir = item.first;
2786 55 : if (dir == LinkDirection::NODIR) {
2787 2 : continue;
2788 : }
2789 53 : const NBEdge* to = dirMap[dir];
2790 53 : int candidates = to->getNumLanesThatAllow(defaultPermissions, false);
2791 53 : if (candidates == 0) {
2792 4 : WRITE_WARNINGF(TL("Cannot apply turn sign information for edge '%' because the target edge '%' has no suitable lanes"), getID(), to->getID());
2793 2 : return false;
2794 : }
2795 52 : std::vector<int>& knownTargets = toLaneMap[to];
2796 52 : if ((int)knownTargets.size() < item.second) {
2797 4 : if (candidates < item.second) {
2798 4 : WRITE_WARNINGF(TL("Cannot apply turn sign information for edge '%' because there are % signed connections with directions '%' but target edge '%' has only % suitable lanes"),
2799 : getID(), item.second, toString(dir), to->getID(), candidates);
2800 1 : return false;
2801 : }
2802 : int i;
2803 : int iInc;
2804 : int iEnd;
2805 3 : if (dir > LinkDirection::STRAIGHT) {
2806 : // set more targets on the left
2807 1 : i = to->getNumLanes() - 1;
2808 : iInc = -1;
2809 : iEnd = -1;
2810 : } else {
2811 : // set more targets on the right
2812 2 : i = 0;
2813 : iInc = 1;
2814 2 : iEnd = to->getNumLanes();
2815 : }
2816 8 : while ((int)knownTargets.size() < item.second && i != iEnd) {
2817 5 : if ((to->getPermissions(i) & defaultPermissions) != 0) {
2818 5 : if (std::find(knownTargets.begin(), knownTargets.end(), i) == knownTargets.end()) {
2819 3 : knownTargets.push_back(i);
2820 : }
2821 : }
2822 5 : i += iInc;
2823 : }
2824 3 : if ((int)knownTargets.size() != item.second) {
2825 0 : WRITE_WARNINGF(TL("Cannot apply turn sign information for edge '%' because not enough target lanes could be determined for direction '%'"), getID(), toString(dir));
2826 0 : return false;
2827 : }
2828 3 : std::sort(knownTargets.begin(), knownTargets.end());
2829 : }
2830 : }
2831 : std::map<const NBEdge*, int> toLaneIndex;
2832 72 : for (int i = 0; i < getNumLanes(); i++) {
2833 51 : const int turnSigns = myLanes[i].turnSigns;
2834 : // no turnSigns are given for bicycle lanes and sidewalks
2835 51 : if (turnSigns != 0) {
2836 : // clear existing connections
2837 225 : for (auto it = myConnections.begin(); it != myConnections.end();) {
2838 174 : if (it->fromLane == i) {
2839 70 : it = myConnections.erase(it);
2840 : } else {
2841 : it++;
2842 : }
2843 : }
2844 : // add new connections
2845 51 : int allSigns = (turnSigns
2846 51 : | turnSigns >> TURN_SIGN_SHIFT_BUS
2847 51 : | turnSigns >> TURN_SIGN_SHIFT_TAXI
2848 51 : | turnSigns >> TURN_SIGN_SHIFT_BICYCLE);
2849 51 : std::vector<LinkDirection> all = decodeTurnSigns(turnSigns);
2850 51 : std::vector<LinkDirection> bus = decodeTurnSigns(turnSigns, TURN_SIGN_SHIFT_BUS);
2851 51 : std::vector<LinkDirection> taxi = decodeTurnSigns(turnSigns, TURN_SIGN_SHIFT_TAXI);
2852 51 : std::vector<LinkDirection> bike = decodeTurnSigns(turnSigns, TURN_SIGN_SHIFT_BICYCLE);
2853 : //std::cout << " allSigns=" << allSigns << " turnSigns=" << turnSigns << " bus=" << bus.size() << "\n";
2854 114 : for (LinkDirection dir : decodeTurnSigns(allSigns)) {
2855 63 : SVCPermissions perm = 0;
2856 63 : updateTurnPermissions(perm, dir, SVCAll, all);
2857 63 : updateTurnPermissions(perm, dir, SVC_BUS, bus);
2858 63 : updateTurnPermissions(perm, dir, SVC_TAXI, taxi);
2859 63 : updateTurnPermissions(perm, dir, SVC_BICYCLE, bike);
2860 63 : if (perm == SVCAll) {
2861 61 : perm = SVC_UNSPECIFIED;
2862 : }
2863 : //std::cout << " lane=" << i << " dir=" << toString(dir) << " perm=" << getVehicleClassNames(perm) << "\n";
2864 63 : NBEdge* to = const_cast<NBEdge*>(dirMap[dir]);
2865 63 : if (to != nullptr) {
2866 : if (toLaneIndex.count(to) == 0) {
2867 : // initialize to rightmost feasible lane
2868 50 : SVCPermissions fromP = getPermissions(i);
2869 50 : if ((fromP & SVC_PASSENGER) != 0) {
2870 : // if the source permits passenger traffic, the target should too
2871 : fromP = SVC_PASSENGER;
2872 : }
2873 50 : int toLane = toLaneMap[to][0];
2874 52 : while ((to->getPermissions(toLane) & fromP) == 0 && (toLane + 1 < to->getNumLanes())) {
2875 : toLane++;
2876 : /*
2877 : if (toLane == to->getNumLanes()) {
2878 : SOFT_ASSERT(false);
2879 : #ifdef DEBUG_TURNSIGNS
2880 : std::cout << " could not find passenger lane for target=" << to->getID() << "\n";
2881 : #endif
2882 : return false;
2883 : }
2884 : */
2885 : }
2886 : #ifdef DEBUG_TURNSIGNS
2887 : std::cout << " target=" << to->getID() << " initial toLane=" << toLane << "\n";
2888 : #endif
2889 50 : toLaneIndex[to] = toLane;
2890 : }
2891 61 : setConnection(i, to, toLaneIndex[to], Lane2LaneInfoType::VALIDATED, true,
2892 : false, KEEPCLEAR_UNSPECIFIED, UNSPECIFIED_CONTPOS,
2893 : UNSPECIFIED_VISIBILITY_DISTANCE, UNSPECIFIED_SPEED, UNSPECIFIED_FRICTION,
2894 : myDefaultConnectionLength, PositionVector::EMPTY,
2895 : UNSPECIFIED_CONNECTION_UNCONTROLLED,
2896 : perm);
2897 61 : if (toLaneIndex[to] < to->getNumLanes() - 1) {
2898 13 : toLaneIndex[to]++;
2899 : }
2900 : }
2901 51 : }
2902 51 : }
2903 : }
2904 21 : sortOutgoingConnectionsByAngle();
2905 21 : sortOutgoingConnectionsByIndex();
2906 : return true;
2907 62 : }
2908 :
2909 :
2910 : bool
2911 90804 : NBEdge::recheckLanes() {
2912 : #ifdef DEBUG_CONNECTION_GUESSING
2913 : if (DEBUGCOND) {
2914 : std::cout << "recheckLanes (initial) edge=" << getID() << "\n";
2915 : for (Connection& c : myConnections) {
2916 : std::cout << " conn " << c.getDescription(this) << "\n";
2917 : }
2918 : for (Connection& c : myConnectionsToDelete) {
2919 : std::cout << " connToDelete " << c.getDescription(this) << "\n";
2920 : }
2921 : }
2922 : #endif
2923 : // check delayed removals
2924 97853 : for (std::vector<Connection>::iterator it = myConnectionsToDelete.begin(); it != myConnectionsToDelete.end(); ++it) {
2925 7049 : removeFromConnections(it->toEdge, it->fromLane, it->toLane, false, false, true);
2926 : }
2927 90804 : std::vector<int> connNumbersPerLane(myLanes.size(), 0);
2928 276042 : for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end();) {
2929 185238 : if ((*i).toEdge == nullptr || (*i).fromLane < 0 || (*i).toLane < 0) {
2930 1 : i = myConnections.erase(i);
2931 : } else {
2932 : if ((*i).fromLane >= 0) {
2933 185237 : ++connNumbersPerLane[(*i).fromLane];
2934 : }
2935 : ++i;
2936 : }
2937 : }
2938 90804 : if (myStep != EdgeBuildingStep::LANES2LANES_DONE && myStep != EdgeBuildingStep::LANES2LANES_USER) {
2939 : #ifdef DEBUG_TURNSIGNS
2940 : if (myLanes.back().turnSigns != 0) {
2941 : std::cout << getID() << " hasTurnSigns\n";
2942 : if (myTurnSignTarget != myTo->getID()) {
2943 : std::cout << " tst=" << myTurnSignTarget << " to=" << myTo->getID() << "\n";
2944 : }
2945 : }
2946 : #endif
2947 57118 : if (myLanes.back().turnSigns == 0 || myTurnSignTarget != myTo->getID() || !applyTurnSigns()) {
2948 : // check #1:
2949 : // If there is a lane with no connections and any neighbour lane has
2950 : // more than one connections, try to move one of them.
2951 : // This check is only done for edges which connections were assigned
2952 : // using the standard algorithm.
2953 131221 : for (int i = 0; i < (int)myLanes.size(); i++) {
2954 74124 : if (connNumbersPerLane[i] == 0 && !isForbidden(getPermissions(i) & ~SVC_PEDESTRIAN)) {
2955 : // dead-end lane found
2956 : bool hasDeadEnd = true;
2957 : // find lane with two connections or more to the right of the current lane
2958 3876 : for (int i2 = i - 1; hasDeadEnd && i2 >= 0; i2--) {
2959 2293 : if (getPermissions(i) != getPermissions(i2)) {
2960 : break;
2961 : }
2962 1582 : if (connNumbersPerLane[i2] > 1) {
2963 350 : connNumbersPerLane[i2]--;
2964 836 : for (int i3 = i2; i3 != i; i3++) {
2965 486 : moveConnectionToLeft(i3);
2966 486 : sortOutgoingConnectionsByAngle();
2967 486 : sortOutgoingConnectionsByIndex();
2968 : }
2969 : hasDeadEnd = false;
2970 : }
2971 : }
2972 2294 : if (hasDeadEnd) {
2973 : // find lane with two connections or more to the left of the current lane
2974 3002 : for (int i2 = i + 1; hasDeadEnd && i2 < getNumLanes(); i2++) {
2975 1174 : if (getPermissions(i) != getPermissions(i2)) {
2976 : break;
2977 : }
2978 1058 : if (connNumbersPerLane[i2] > 1) {
2979 74 : connNumbersPerLane[i2]--;
2980 173 : for (int i3 = i2; i3 != i; i3--) {
2981 99 : moveConnectionToRight(i3);
2982 99 : sortOutgoingConnectionsByAngle();
2983 99 : sortOutgoingConnectionsByIndex();
2984 : }
2985 : hasDeadEnd = false;
2986 : }
2987 : }
2988 : }
2989 1944 : if (hasDeadEnd && myTo->getOutgoingEdges().size() > 1) {
2990 : int passengerLanes = 0;
2991 : int passengerTargetLanes = 0;
2992 1061 : for (const Lane& lane : myLanes) {
2993 820 : if ((lane.permissions & SVC_PASSENGER) != 0) {
2994 674 : passengerLanes++;
2995 : }
2996 : }
2997 937 : for (const NBEdge* out : myTo->getOutgoingEdges()) {
2998 696 : if (!isTurningDirectionAt(out)) {
2999 1388 : for (const Lane& lane : out->getLanes()) {
3000 906 : if ((lane.permissions & SVC_PASSENGER) != 0) {
3001 784 : passengerTargetLanes++;
3002 : }
3003 : }
3004 : }
3005 : }
3006 241 : if (passengerLanes > 0 && passengerLanes <= passengerTargetLanes) {
3007 : // no need for dead-ends
3008 69 : if (i > 0) {
3009 : // check if a connection to the right has a usable target to the left of its target
3010 47 : std::vector<Connection> rightCons = getConnectionsFromLane(i - 1);
3011 47 : if (rightCons.size() > 0) {
3012 : const Connection& rc = rightCons.back();
3013 37 : NBEdge* to = rc.toEdge;
3014 37 : int toLane = rc.toLane + 1;
3015 : if (toLane < to->getNumLanes()
3016 0 : && (getPermissions(i) & ~SVC_PEDESTRIAN & to->getPermissions(toLane)) != 0
3017 37 : && !hasConnectionTo(to, toLane)) {
3018 : #ifdef DEBUG_CONNECTION_CHECKING
3019 : std::cout << " recheck1 setConnection " << getID() << "_" << i << "->" << to->getID() << "_" << toLane << "\n";
3020 : #endif
3021 0 : setConnection(i, to, toLane, Lane2LaneInfoType::COMPUTED);
3022 : hasDeadEnd = false;
3023 0 : sortOutgoingConnectionsByAngle();
3024 0 : sortOutgoingConnectionsByIndex();
3025 : }
3026 : if (hasDeadEnd) {
3027 : // check if a connection to the right has a usable target to the right of its target
3028 37 : toLane = rc.toLane - 1;
3029 : if (toLane >= 0
3030 7 : && (getPermissions(i) & ~SVC_PEDESTRIAN & to->getPermissions(rc.toLane)) != 0
3031 7 : && (getPermissions(rc.fromLane) & ~SVC_PEDESTRIAN & to->getPermissions(toLane)) != 0
3032 43 : && !hasConnectionTo(to, toLane)) {
3033 : // shift the right lane connection target right and connect the dead lane to the old target
3034 1 : getConnectionRef(rc.fromLane, to, rc.toLane).toLane = toLane;
3035 : #ifdef DEBUG_CONNECTION_CHECKING
3036 : std::cout << " recheck2 setConnection " << getID() << "_" << i << "->" << to->getID() << "_" << (toLane + 1) << "\n";
3037 : #endif
3038 1 : setConnection(i, to, toLane + 1, Lane2LaneInfoType::COMPUTED);
3039 : hasDeadEnd = false;
3040 1 : sortOutgoingConnectionsByAngle();
3041 1 : sortOutgoingConnectionsByIndex();
3042 : }
3043 : }
3044 : }
3045 47 : }
3046 69 : if (hasDeadEnd && i < getNumLanes() - 1) {
3047 : // check if a connection to the left has a usable target to the right of its target
3048 58 : std::vector<Connection> leftCons = getConnectionsFromLane(i + 1);
3049 58 : if (leftCons.size() > 0) {
3050 48 : NBEdge* to = leftCons.front().toEdge;
3051 48 : int toLane = leftCons.front().toLane - 1;
3052 : if (toLane >= 0
3053 4 : && (getPermissions(i) & ~SVC_PEDESTRIAN & to->getPermissions(toLane)) != 0
3054 52 : && !hasConnectionTo(to, toLane)) {
3055 : #ifdef DEBUG_CONNECTION_CHECKING
3056 : std::cout << " recheck3 setConnection " << getID() << "_" << i << "->" << to->getID() << "_" << toLane << "\n";
3057 : #endif
3058 4 : setConnection(i, to, toLane, Lane2LaneInfoType::COMPUTED);
3059 : hasDeadEnd = false;
3060 4 : sortOutgoingConnectionsByAngle();
3061 4 : sortOutgoingConnectionsByIndex();
3062 : }
3063 : }
3064 58 : }
3065 : #ifdef ADDITIONAL_WARNINGS
3066 : if (hasDeadEnd) {
3067 : WRITE_WARNING("Found dead-end lane " + getLaneID(i));
3068 : }
3069 : #endif
3070 : }
3071 : }
3072 : }
3073 : }
3074 57097 : removeInvalidConnections();
3075 : }
3076 : }
3077 : // check involuntary dead end at "real" junctions
3078 90804 : if (getPermissions() != SVC_PEDESTRIAN) {
3079 77453 : if (myConnections.empty() && myTo->getOutgoingEdges().size() > 1 && (getPermissions() & ~SVC_PEDESTRIAN) != 0) {
3080 168 : WRITE_WARNINGF(TL("Edge '%' is not connected to outgoing edges at junction '%'."), getID(), myTo->getID());
3081 : }
3082 77453 : const EdgeVector& incoming = myFrom->getIncomingEdges();
3083 77453 : if (incoming.size() > 1) {
3084 129755 : for (int i = 0; i < (int)myLanes.size(); i++) {
3085 73025 : if (getPermissions(i) != 0 && getPermissions(i) != SVC_PEDESTRIAN) {
3086 : bool connected = false;
3087 91321 : for (std::vector<NBEdge*>::const_iterator in = incoming.begin(); in != incoming.end(); ++in) {
3088 91205 : if ((*in)->hasConnectionTo(this, i)) {
3089 : connected = true;
3090 : break;
3091 : }
3092 : }
3093 68877 : if (!connected) {
3094 348 : WRITE_WARNINGF(TL("Lane '%' is not connected from any incoming edge at junction '%'."), getLaneID(i), myFrom->getID());
3095 : }
3096 : }
3097 : }
3098 : }
3099 : }
3100 : // avoid deadend due to change prohibitions
3101 90804 : if (getNumLanes() > 1 && myConnections.size() > 0) {
3102 59748 : for (int i = 0; i < (int)myLanes.size(); i++) {
3103 42336 : Lane& lane = myLanes[i];
3104 36205 : if ((connNumbersPerLane[i] == 0 || ((lane.accelRamp || (i > 0 && myLanes[i - 1].accelRamp && connNumbersPerLane[i - 1] > 0))
3105 53 : && getSuccessors(SVC_PASSENGER).size() > 1))
3106 42351 : && getPermissions(i) != SVC_PEDESTRIAN && !isForbidden(getPermissions(i))) {
3107 2228 : const bool forbiddenLeft = lane.changeLeft != SVCAll && lane.changeLeft != SVC_IGNORING && lane.changeLeft != SVC_UNSPECIFIED;
3108 2228 : const bool forbiddenRight = lane.changeRight != SVCAll && lane.changeRight != SVC_IGNORING && lane.changeRight != SVC_UNSPECIFIED;
3109 2228 : if (forbiddenLeft && (i == 0 || forbiddenRight)) {
3110 2 : lane.changeLeft = SVC_UNSPECIFIED;
3111 4 : WRITE_WARNINGF(TL("Ignoring changeLeft prohibition for '%' to avoid dead-end"), getLaneID(i));
3112 2226 : } else if (forbiddenRight && (i == getNumLanes() - 1 || (i > 0 && myLanes[i - 1].accelRamp))) {
3113 1 : lane.changeRight = SVC_UNSPECIFIED;
3114 2 : WRITE_WARNINGF(TL("Ignoring changeRight prohibition for '%' to avoid dead-end"), getLaneID(i));
3115 : }
3116 : }
3117 : }
3118 : }
3119 : #ifdef ADDITIONAL_WARNINGS
3120 : // check for connections with bad access permissions
3121 : for (const Connection& c : myConnections) {
3122 : SVCPermissions fromP = getPermissions(c.fromLane);
3123 : SVCPermissions toP = c.toEdge->getPermissions(c.toLane);
3124 : if ((fromP & SVC_PASSENGER) != 0
3125 : && toP == SVC_BICYCLE) {
3126 : bool hasAlternative = false;
3127 : for (const Connection& c2 : myConnections) {
3128 : if (c.fromLane == c2.fromLane && c.toEdge == c2.toEdge
3129 : && (c.toEdge->getPermissions(c2.toLane) & SVC_PASSENGER) != 0) {
3130 : hasAlternative = true;
3131 : }
3132 : }
3133 : if (!hasAlternative) {
3134 : WRITE_WARNING("Road lane ends on bikeLane for connection " + c.getDescription(this));
3135 : }
3136 : }
3137 : }
3138 :
3139 : #endif
3140 : #ifdef DEBUG_CONNECTION_GUESSING
3141 : if (DEBUGCOND) {
3142 : std::cout << "recheckLanes (final) edge=" << getID() << "\n";
3143 : for (Connection& c : myConnections) {
3144 : std::cout << " conn " << c.getDescription(this) << "\n";
3145 : }
3146 : }
3147 : #endif
3148 90804 : return true;
3149 90804 : }
3150 :
3151 :
3152 57097 : void NBEdge::removeInvalidConnections() {
3153 : // check restrictions
3154 188257 : for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end();) {
3155 : Connection& c = *i;
3156 131160 : const SVCPermissions common = getPermissions(c.fromLane) & c.toEdge->getPermissions(c.toLane);
3157 131160 : if (common == SVC_PEDESTRIAN || getPermissions(c.fromLane) == SVC_PEDESTRIAN) {
3158 : // these are computed in NBNode::buildWalkingAreas
3159 : #ifdef DEBUG_CONNECTION_CHECKING
3160 : std::cout << " remove pedCon " << c.getDescription(this) << "\n";
3161 : #endif
3162 470 : i = myConnections.erase(i);
3163 130690 : } else if (common == 0) {
3164 : // no common permissions.
3165 : // try to find a suitable target lane to the right
3166 83 : const int origToLane = c.toLane;
3167 83 : c.toLane = -1; // ignore this connection when calling hasConnectionTo
3168 : int toLane = origToLane;
3169 83 : while (toLane > 0
3170 45 : && (getPermissions(c.fromLane) & c.toEdge->getPermissions(toLane)) == 0
3171 143 : && !hasConnectionTo(c.toEdge, toLane)
3172 : ) {
3173 30 : toLane--;
3174 : }
3175 83 : if ((getPermissions(c.fromLane) & c.toEdge->getPermissions(toLane)) != 0
3176 83 : && !hasConnectionTo(c.toEdge, toLane)) {
3177 4 : c.toLane = toLane;
3178 : ++i;
3179 : } else {
3180 : // try to find a suitable target lane to the left
3181 : toLane = origToLane;
3182 148 : while (toLane < (int)c.toEdge->getNumLanes() - 1
3183 95 : && (getPermissions(c.fromLane) & c.toEdge->getPermissions(toLane)) == 0
3184 217 : && !hasConnectionTo(c.toEdge, toLane)
3185 : ) {
3186 69 : toLane++;
3187 : }
3188 79 : if ((getPermissions(c.fromLane) & c.toEdge->getPermissions(toLane)) != 0
3189 79 : && !hasConnectionTo(c.toEdge, toLane)) {
3190 0 : c.toLane = toLane;
3191 : ++i;
3192 : } else {
3193 : // no alternative target found
3194 : #ifdef DEBUG_CONNECTION_CHECKING
3195 : std::cout << " remove " << c.getDescription(this) << " with no alternative target\n";
3196 : #endif
3197 79 : i = myConnections.erase(i);
3198 : }
3199 : }
3200 138855 : } else if (isRailway(getPermissions(c.fromLane)) && isRailway(c.toEdge->getPermissions(c.toLane))
3201 138721 : && isTurningDirectionAt(c.toEdge)) {
3202 : // do not allow sharp rail turns
3203 : #ifdef DEBUG_CONNECTION_CHECKING
3204 : std::cout << " remove " << c.getDescription(this) << " (rail turnaround)\n";
3205 : #endif
3206 2617 : i = myConnections.erase(i);
3207 : } else {
3208 : ++i;
3209 : }
3210 : }
3211 57097 : }
3212 :
3213 : void
3214 66364 : NBEdge::divideOnEdges(const EdgeVector* outgoing) {
3215 66364 : if (outgoing->size() == 0) {
3216 : // we have to do this, because the turnaround may have been added before
3217 : myConnections.clear();
3218 10934 : return;
3219 : }
3220 :
3221 : #ifdef DEBUG_CONNECTION_GUESSING
3222 : if (DEBUGCOND) {
3223 : std::cout << " divideOnEdges " << getID() << " outgoing=" << toString(*outgoing) << "\n";
3224 : }
3225 : #endif
3226 :
3227 : // build connections for miv lanes
3228 : std::vector<int> availableLanes;
3229 126340 : for (int i = 0; i < (int)myLanes.size(); ++i) {
3230 70910 : if ((getPermissions(i) & SVC_PASSENGER) != 0) {
3231 45611 : availableLanes.push_back(i);
3232 : }
3233 : }
3234 55430 : if (availableLanes.size() > 0) {
3235 33996 : divideSelectedLanesOnEdges(outgoing, availableLanes);
3236 : }
3237 : // build connections for miscellaneous further modes (more than bike,peds,bus and without passenger)
3238 : availableLanes.clear();
3239 126340 : for (int i = 0; i < (int)myLanes.size(); ++i) {
3240 70910 : const SVCPermissions perms = getPermissions(i);
3241 70910 : if ((perms & ~(SVC_PEDESTRIAN | SVC_BICYCLE | SVC_BUS)) == 0 || (perms & SVC_PASSENGER) != 0 || isForbidden(perms)) {
3242 60849 : continue;
3243 : }
3244 10061 : availableLanes.push_back(i);
3245 : }
3246 55430 : if (availableLanes.size() > 0) {
3247 9990 : divideSelectedLanesOnEdges(outgoing, availableLanes);
3248 : }
3249 : // build connections for busses from lanes that were excluded in the previous step
3250 : availableLanes.clear();
3251 126340 : for (int i = 0; i < (int)myLanes.size(); ++i) {
3252 70910 : const SVCPermissions perms = getPermissions(i);
3253 70910 : if ((perms & SVC_BUS) == 0 || (perms & ~(SVC_PEDESTRIAN | SVC_BICYCLE | SVC_BUS)) != 0 || (perms & SVC_PASSENGER) != 0) {
3254 70662 : continue;
3255 : }
3256 248 : availableLanes.push_back(i);
3257 : }
3258 55430 : if (availableLanes.size() > 0) {
3259 245 : divideSelectedLanesOnEdges(outgoing, availableLanes);
3260 : }
3261 : // build connections for bicycles (possibly combined with pedestrians)
3262 : availableLanes.clear();
3263 126340 : for (int i = 0; i < (int)myLanes.size(); ++i) {
3264 70910 : const SVCPermissions perms = getPermissions(i);
3265 70910 : if (perms != SVC_BICYCLE && perms != (SVC_BICYCLE | SVC_PEDESTRIAN)) {
3266 69212 : continue;
3267 : }
3268 1698 : availableLanes.push_back(i);
3269 : }
3270 55430 : if (availableLanes.size() > 0) {
3271 1673 : divideSelectedLanesOnEdges(outgoing, availableLanes);
3272 : }
3273 : // clean up unassigned fromLanes
3274 : bool explicitTurnaround = false;
3275 55430 : SVCPermissions turnaroundPermissions = SVC_UNSPECIFIED;
3276 243355 : for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end();) {
3277 187925 : if ((*i).fromLane == -1) {
3278 89095 : if ((*i).toEdge == myTurnDestination && myTurnDestination != nullptr) {
3279 : explicitTurnaround = true;
3280 108 : turnaroundPermissions = (*i).permissions;
3281 : }
3282 89095 : if ((*i).permissions != SVC_UNSPECIFIED) {
3283 1542 : for (Connection& c : myConnections) {
3284 1344 : if (c.toLane == -1 && c.toEdge == (*i).toEdge) {
3285 : // carry over loaded edge2edge permissions
3286 357 : c.permissions = (*i).permissions;
3287 : }
3288 : }
3289 : }
3290 89095 : i = myConnections.erase(i);
3291 : } else {
3292 : ++i;
3293 : }
3294 : }
3295 55430 : if (explicitTurnaround) {
3296 216 : myConnections.push_back(Connection((int)myLanes.size() - 1, myTurnDestination, myTurnDestination->getNumLanes() - 1));
3297 108 : myConnections.back().permissions = turnaroundPermissions;
3298 : }
3299 55430 : sortOutgoingConnectionsByIndex();
3300 55430 : }
3301 :
3302 :
3303 : void
3304 45904 : NBEdge::divideSelectedLanesOnEdges(const EdgeVector* outgoing, const std::vector<int>& availableLanes) {
3305 45904 : const std::vector<int>& priorities = prepareEdgePriorities(outgoing, availableLanes);
3306 45904 : if (priorities.empty()) {
3307 : return;
3308 : }
3309 : #ifdef DEBUG_CONNECTION_GUESSING
3310 : if (DEBUGCOND) {
3311 : std::cout << "divideSelectedLanesOnEdges " << getID() << " out=" << toString(*outgoing) << " prios=" << toString(priorities) << " avail=" << toString(availableLanes) << "\n";
3312 : }
3313 : #endif
3314 : // compute the resulting number of lanes that should be used to reach the following edge
3315 45856 : const int numOutgoing = (int)outgoing->size();
3316 : std::vector<int> resultingLanesFactor;
3317 45856 : resultingLanesFactor.reserve(numOutgoing);
3318 : int minResulting = std::numeric_limits<int>::max();
3319 135857 : for (int i = 0; i < numOutgoing; i++) {
3320 : // res / minResulting will be the number of lanes which are meant to reach the current outgoing edge
3321 90001 : const int res = priorities[i] * (int)availableLanes.size();
3322 90001 : resultingLanesFactor.push_back(res);
3323 90001 : if (minResulting > res && res > 0) {
3324 : // prevent minResulting from becoming 0
3325 : minResulting = res;
3326 : }
3327 : }
3328 : // compute the number of virtual edges
3329 : // a virtual edge is used as a replacement for a real edge from now on
3330 : // it shall allow to divide the existing lanes on this structure without
3331 : // regarding the structure of outgoing edges
3332 : int numVirtual = 0;
3333 : // compute the transition from virtual to real edges
3334 : EdgeVector transition;
3335 45856 : transition.reserve(numOutgoing);
3336 135857 : for (int i = 0; i < numOutgoing; i++) {
3337 : // tmpNum will be the number of connections from this edge to the next edge
3338 : assert(i < (int)resultingLanesFactor.size());
3339 90001 : const int tmpNum = (resultingLanesFactor[i] + minResulting - 1) / minResulting; // integer division rounding up
3340 90001 : numVirtual += tmpNum;
3341 506002 : for (int j = 0; j < tmpNum; j++) {
3342 416001 : transition.push_back((*outgoing)[i]);
3343 : }
3344 : }
3345 : #ifdef DEBUG_CONNECTION_GUESSING
3346 : if (DEBUGCOND) {
3347 : std::cout << " minResulting=" << minResulting << " numVirtual=" << numVirtual << " availLanes=" << toString(availableLanes) << " resLanes=" << toString(resultingLanesFactor) << " transition=" << toString(transition) << "\n";
3348 : }
3349 : #endif
3350 :
3351 : // assign lanes to edges
3352 : // (conversion from virtual to real edges is done)
3353 : ToEdgeConnectionsAdder adder(transition);
3354 45856 : Bresenham::compute(&adder, static_cast<int>(availableLanes.size()), numVirtual);
3355 : const std::map<NBEdge*, std::vector<int> >& l2eConns = adder.getBuiltConnections();
3356 135857 : for (NBEdge* const target : *outgoing) {
3357 : assert(l2eConns.find(target) != l2eConns.end());
3358 190555 : for (const int j : l2eConns.find(target)->second) {
3359 100554 : const int fromIndex = availableLanes[j];
3360 100554 : if ((getPermissions(fromIndex) & target->getPermissions()) == 0) {
3361 : // exclude connection if fromLane and toEdge have no common permissions
3362 60 : continue;
3363 : }
3364 100494 : if ((getPermissions(fromIndex) & target->getPermissions()) == SVC_PEDESTRIAN) {
3365 : // exclude connection if the only commonly permitted class are pedestrians
3366 : // these connections are later built in NBNode::buildWalkingAreas
3367 253 : continue;
3368 : }
3369 : // avoid building more connections than the edge has viable lanes (earlier
3370 : // ones have precedence). This is necessary when running divideSelectedLanesOnEdges more than once.
3371 : // @todo To decide which target lanes are still available we need to do a
3372 : // preliminary lane-to-lane assignment in regard to permissions (rather than to ordering)
3373 100241 : const int numConsToTarget = (int)count_if(myConnections.begin(), myConnections.end(), connections_toedge_finder(target, true));
3374 : int targetLanes = target->getNumLanes();
3375 100241 : if (target->getPermissions(0) == SVC_PEDESTRIAN) {
3376 7168 : --targetLanes;
3377 : }
3378 100241 : if (numConsToTarget >= targetLanes) {
3379 2570 : continue;
3380 : }
3381 97671 : if (myLanes[fromIndex].connectionsDone) {
3382 : // we already have complete information about connections from
3383 : // this lane. do not add anything else
3384 : #ifdef DEBUG_CONNECTION_GUESSING
3385 : if (DEBUGCOND) {
3386 : std::cout << " connectionsDone from " << getID() << "_" << fromIndex << ": ";
3387 : for (const Connection& c : getConnectionsFromLane(fromIndex)) {
3388 : std::cout << c.getDescription(this) << ", ";
3389 : }
3390 : std::cout << "\n";
3391 : }
3392 : #endif
3393 38 : continue;
3394 : }
3395 195266 : myConnections.push_back(Connection(fromIndex, target, -1));
3396 : #ifdef DEBUG_CONNECTION_GUESSING
3397 : if (DEBUGCOND) {
3398 : std::cout << " request connection from " << getID() << "_" << fromIndex << " to " << target->getID() << "\n";
3399 : }
3400 : #endif
3401 : }
3402 : }
3403 :
3404 45856 : addStraightConnections(outgoing, availableLanes, priorities);
3405 45904 : }
3406 :
3407 :
3408 : void
3409 45856 : NBEdge::addStraightConnections(const EdgeVector* outgoing, const std::vector<int>& availableLanes, const std::vector<int>& priorities) {
3410 : // ensure sufficient straight connections for the (highest-priority) straight target
3411 45856 : const int numOutgoing = (int) outgoing->size();
3412 : NBEdge* target = nullptr;
3413 : NBEdge* rightOfTarget = nullptr;
3414 : NBEdge* leftOfTarget = nullptr;
3415 : int maxPrio = 0;
3416 135857 : for (int i = 0; i < numOutgoing; i++) {
3417 90001 : if (maxPrio < priorities[i]) {
3418 75214 : const LinkDirection dir = myTo->getDirection(this, (*outgoing)[i]);
3419 75214 : if (dir == LinkDirection::STRAIGHT) {
3420 37720 : maxPrio = priorities[i];
3421 37720 : target = (*outgoing)[i];
3422 37720 : rightOfTarget = i == 0 ? outgoing->back() : (*outgoing)[i - 1];
3423 37720 : leftOfTarget = i + 1 == numOutgoing ? outgoing->front() : (*outgoing)[i + 1];
3424 : }
3425 : }
3426 : }
3427 45856 : if (target == nullptr) {
3428 : return;
3429 : }
3430 37561 : int numConsToTarget = (int)count_if(myConnections.begin(), myConnections.end(), connections_toedge_finder(target, true));
3431 : int targetLanes = (int)target->getNumLanes();
3432 37561 : if (target->getPermissions(0) == SVC_PEDESTRIAN) {
3433 3218 : --targetLanes;
3434 : }
3435 37561 : const int numDesiredConsToTarget = MIN2(targetLanes, (int)availableLanes.size());
3436 : #ifdef DEBUG_CONNECTION_GUESSING
3437 : if (DEBUGCOND) {
3438 : std::cout << " checking extra lanes for target=" << target->getID() << " cons=" << numConsToTarget << " desired=" << numDesiredConsToTarget << "\n";
3439 : }
3440 : #endif
3441 : std::vector<int>::const_iterator it_avail = availableLanes.begin();
3442 38664 : while (numConsToTarget < numDesiredConsToTarget && it_avail != availableLanes.end()) {
3443 1103 : const int fromIndex = *it_avail;
3444 : if (
3445 : // not yet connected
3446 1103 : (count_if(myConnections.begin(), myConnections.end(), connections_finder(fromIndex, target, -1)) == 0)
3447 : // matching permissions
3448 654 : && ((getPermissions(fromIndex) & target->getPermissions()) != 0)
3449 : // more than pedestrians
3450 652 : && ((getPermissions(fromIndex) & target->getPermissions()) != SVC_PEDESTRIAN)
3451 : // lane not yet fully defined
3452 1753 : && !myLanes[fromIndex].connectionsDone
3453 : ) {
3454 : #ifdef DEBUG_CONNECTION_GUESSING
3455 : if (DEBUGCOND) {
3456 : std::cout << " candidate from " << getID() << "_" << fromIndex << " to " << target->getID() << "\n";
3457 : }
3458 : #endif
3459 : // prevent same-edge conflicts
3460 : if (
3461 : // no outgoing connections to the right from further left
3462 320 : ((it_avail + 1) == availableLanes.end() || count_if(myConnections.begin(), myConnections.end(), connections_conflict_finder(fromIndex, rightOfTarget, false)) == 0)
3463 : // no outgoing connections to the left from further right
3464 1267 : && (it_avail == availableLanes.begin() || count_if(myConnections.begin(), myConnections.end(), connections_conflict_finder(fromIndex, leftOfTarget, true)) == 0)) {
3465 : #ifdef DEBUG_CONNECTION_GUESSING
3466 : if (DEBUGCOND) {
3467 : std::cout << " request additional connection from " << getID() << "_" << fromIndex << " to " << target->getID() << "\n";
3468 : }
3469 : #endif
3470 1146 : myConnections.push_back(Connection(fromIndex, target, -1));
3471 573 : numConsToTarget++;
3472 : } else {
3473 : #ifdef DEBUG_CONNECTION_GUESSING
3474 : if (DEBUGCOND) std::cout
3475 : << " fail check1="
3476 : << ((it_avail + 1) == availableLanes.end() || count_if(myConnections.begin(), myConnections.end(), connections_conflict_finder(fromIndex, rightOfTarget, false)) == 0)
3477 : << " check2=" << (it_avail == availableLanes.begin() || count_if(myConnections.begin(), myConnections.end(), connections_conflict_finder(fromIndex, leftOfTarget, true)) == 0)
3478 : << " rightOfTarget=" << rightOfTarget->getID()
3479 : << " leftOfTarget=" << leftOfTarget->getID()
3480 : << "\n";
3481 : #endif
3482 :
3483 : }
3484 : }
3485 : ++it_avail;
3486 : }
3487 : }
3488 :
3489 :
3490 : const std::vector<int>
3491 45904 : NBEdge::prepareEdgePriorities(const EdgeVector* outgoing, const std::vector<int>& availableLanes) {
3492 : std::vector<int> priorities;
3493 45904 : MainDirections mainDirections(*outgoing, this, myTo, availableLanes);
3494 : const int dist = mainDirections.getStraightest();
3495 45904 : if (dist == -1) {
3496 : return priorities;
3497 : }
3498 : // copy the priorities first
3499 45856 : priorities.reserve(outgoing->size());
3500 135857 : for (const NBEdge* const out : *outgoing) {
3501 90001 : int prio = NBNode::isTrafficLight(myTo->getType()) ? 0 : out->getJunctionPriority(myTo);
3502 : assert((prio + 1) * 2 > 0);
3503 90001 : prio = (prio + 1) * 2;
3504 90001 : priorities.push_back(prio);
3505 : }
3506 : // when the right turning direction has not a higher priority, divide
3507 : // the importance by 2 due to the possibility to leave the junction
3508 : // faster from this lane
3509 : #ifdef DEBUG_CONNECTION_GUESSING
3510 : if (DEBUGCOND) std::cout << " prepareEdgePriorities " << getID()
3511 : << " outgoing=" << toString(*outgoing)
3512 : << " priorities1=" << toString(priorities)
3513 : << " dist=" << dist
3514 : << "\n";
3515 : #endif
3516 45856 : if (dist != 0 && !mainDirections.includes(MainDirections::Direction::RIGHTMOST)) {
3517 : assert(priorities.size() > 0);
3518 14544 : priorities[0] /= 2;
3519 : #ifdef DEBUG_CONNECTION_GUESSING
3520 : if (DEBUGCOND) {
3521 : std::cout << " priorities2=" << toString(priorities) << "\n";
3522 : }
3523 : #endif
3524 : }
3525 : // HEURISTIC:
3526 : // when no higher priority exists, let the forward direction be
3527 : // the main direction
3528 45856 : if (mainDirections.empty()) {
3529 : assert(dist < (int)priorities.size());
3530 10303 : priorities[dist] *= 2;
3531 : #ifdef DEBUG_CONNECTION_GUESSING
3532 : if (DEBUGCOND) {
3533 : std::cout << " priorities3=" << toString(priorities) << "\n";
3534 : }
3535 : #endif
3536 : }
3537 45856 : if (NBNode::isTrafficLight(myTo->getType())) {
3538 4280 : priorities[dist] += 1;
3539 : } else {
3540 : // try to ensure separation of left turns
3541 41576 : if (mainDirections.includes(MainDirections::Direction::RIGHTMOST) && mainDirections.includes(MainDirections::Direction::LEFTMOST)) {
3542 807 : priorities[0] /= 4;
3543 807 : priorities[(int)priorities.size() - 1] /= 2;
3544 : #ifdef DEBUG_CONNECTION_GUESSING
3545 : if (DEBUGCOND) {
3546 : std::cout << " priorities6=" << toString(priorities) << "\n";
3547 : }
3548 : #endif
3549 40769 : } else if (mainDirections.includes(MainDirections::Direction::RIGHTMOST)
3550 21352 : && outgoing->size() > 2
3551 4456 : && availableLanes.size() == 2
3552 40950 : && (*outgoing)[dist]->getPriority() == (*outgoing)[0]->getPriority()) {
3553 172 : priorities[0] /= 4;
3554 172 : priorities.back() /= 2;
3555 : #ifdef DEBUG_CONNECTION_GUESSING
3556 : if (DEBUGCOND) {
3557 : std::cout << " priorities7=" << toString(priorities) << "\n";
3558 : }
3559 : #endif
3560 : }
3561 : }
3562 45856 : if (mainDirections.includes(MainDirections::Direction::FORWARD)) {
3563 24194 : if (myLanes.size() > 2) {
3564 2915 : priorities[dist] *= 2;
3565 : #ifdef DEBUG_CONNECTION_GUESSING
3566 : if (DEBUGCOND) {
3567 : std::cout << " priorities4=" << toString(priorities) << "\n";
3568 : }
3569 : #endif
3570 : } else {
3571 21279 : priorities[dist] *= 3;
3572 : #ifdef DEBUG_CONNECTION_GUESSING
3573 : if (DEBUGCOND) {
3574 : std::cout << " priorities5=" << toString(priorities) << "\n";
3575 : }
3576 : #endif
3577 : }
3578 : }
3579 : return priorities;
3580 45904 : }
3581 :
3582 :
3583 : void
3584 65505 : NBEdge::appendTurnaround(bool noTLSControlled, bool noFringe, bool onlyDeadends, bool onlyTurnlane, bool noGeometryLike, bool checkPermissions) {
3585 : // do nothing if no turnaround is known
3586 65505 : if (myTurnDestination == nullptr || myTo->getType() == SumoXMLNodeType::RAIL_CROSSING) {
3587 : return;
3588 : }
3589 : // do nothing if the destination node is controlled by a tls and no turnarounds
3590 : // shall be appended for such junctions
3591 43767 : if (noTLSControlled && myTo->isTLControlled()) {
3592 : return;
3593 : }
3594 43695 : if (noFringe && myTo->getFringeType() == FringeType::OUTER) {
3595 : return;
3596 : }
3597 : bool isDeadEnd = true;
3598 45299 : for (const Connection& c : myConnections) {
3599 36759 : if ((c.toEdge->getPermissions(c.toLane)
3600 36759 : & getPermissions(c.fromLane)
3601 36759 : & SVC_PASSENGER) != 0
3602 36759 : || (c.toEdge->getPermissions() & getPermissions()) == getPermissions()) {
3603 : isDeadEnd = false;
3604 : break;
3605 : }
3606 : }
3607 43681 : if (onlyDeadends && !isDeadEnd) {
3608 : return;
3609 : }
3610 43482 : const int fromLane = getFirstAllowedLaneIndex(NBNode::BACKWARD);
3611 43482 : if (onlyTurnlane) {
3612 90 : for (const Connection& c : getConnectionsFromLane(fromLane)) {
3613 68 : LinkDirection dir = myTo->getDirection(this, c.toEdge);
3614 68 : if (dir != LinkDirection::LEFT && dir != LinkDirection::PARTLEFT) {
3615 : return;
3616 : }
3617 82 : }
3618 : }
3619 43422 : const int toLane = myTurnDestination->getFirstAllowedLaneIndex(NBNode::BACKWARD);
3620 43422 : if (checkPermissions) {
3621 43422 : if ((getPermissions(fromLane) & myTurnDestination->getPermissions(toLane)) == 0) {
3622 : // exclude connection if fromLane and toEdge have no common permissions
3623 : return;
3624 : }
3625 43264 : if ((getPermissions(fromLane) & myTurnDestination->getPermissions(toLane)) == SVC_PEDESTRIAN) {
3626 : // exclude connection if the only commonly permitted class are pedestrians
3627 : // these connections are later built in NBNode::buildWalkingAreas
3628 : return;
3629 : }
3630 : }
3631 : // avoid railway turn-arounds
3632 40672 : if (isRailway(getPermissions() & myTurnDestination->getPermissions())
3633 40672 : && fabs(NBHelpers::normRelAngle(getAngleAtNode(myTo), myTurnDestination->getAngleAtNode(myTo))) > 90) {
3634 : // except at dead-ends on bidi-edges where they model a reversal in train direction
3635 : // @todo #4382: once the network fringe is tagged, it also should not receive turn-arounds)
3636 3025 : if (isBidiRail() && isRailDeadEnd()) {
3637 : // add a slow connection because direction-reversal implies stopping
3638 2696 : setConnection(fromLane, myTurnDestination, toLane, Lane2LaneInfoType::VALIDATED, false, false, KEEPCLEAR_UNSPECIFIED, UNSPECIFIED_CONTPOS, UNSPECIFIED_VISIBILITY_DISTANCE, SUMO_const_haltingSpeed);
3639 2696 : return;
3640 : } else {
3641 329 : return;
3642 : }
3643 : };
3644 37647 : if (noGeometryLike && !isDeadEnd) {
3645 : // ignore paths and service entrances if this edge is for passenger traffic
3646 31898 : if (myTo->geometryLike() || ((getPermissions() & SVC_PASSENGER) != 0
3647 24109 : && !onlyTurnlane
3648 48204 : && myTo->geometryLike(
3649 56000 : NBEdge::filterByPermissions(myTo->getIncomingEdges(), ~(SVC_BICYCLE | SVC_PEDESTRIAN | SVC_DELIVERY)),
3650 56000 : NBEdge::filterByPermissions(myTo->getOutgoingEdges(), ~(SVC_BICYCLE | SVC_PEDESTRIAN | SVC_DELIVERY))))) {
3651 : // make sure the turnDestination has other incoming edges
3652 6038 : EdgeVector turnIncoming = myTurnDestination->getIncomingEdges();
3653 6038 : if (turnIncoming.size() > 1) {
3654 : // this edge is always part of incoming
3655 : return;
3656 : }
3657 6038 : }
3658 : }
3659 63424 : setConnection(fromLane, myTurnDestination, toLane, Lane2LaneInfoType::VALIDATED);
3660 : }
3661 :
3662 :
3663 : bool
3664 12893449 : NBEdge::isTurningDirectionAt(const NBEdge* const edge) const {
3665 : // maybe it was already set as the turning direction
3666 12893449 : if (edge == myTurnDestination) {
3667 : return true;
3668 9998027 : } else if (myTurnDestination != nullptr) {
3669 : // otherwise - it's not if a turning direction exists
3670 : return false;
3671 : }
3672 2951684 : return edge == myPossibleTurnDestination;
3673 : }
3674 :
3675 :
3676 : NBNode*
3677 0 : NBEdge::tryGetNodeAtPosition(double pos, double tolerance) const {
3678 : // return the from-node when the position is at the begin of the edge
3679 0 : if (pos < tolerance) {
3680 0 : return myFrom;
3681 : }
3682 : // return the to-node when the position is at the end of the edge
3683 0 : if (pos > myLength - tolerance) {
3684 0 : return myTo;
3685 : }
3686 : return nullptr;
3687 : }
3688 :
3689 :
3690 : void
3691 22 : NBEdge::moveOutgoingConnectionsFrom(NBEdge* e, int laneOff) {
3692 : int lanes = e->getNumLanes();
3693 49 : for (int i = 0; i < lanes; i++) {
3694 68 : for (const NBEdge::Connection& el : e->getConnectionsFromLane(i)) {
3695 : assert(el.tlID == "");
3696 82 : addLane2LaneConnection(i + laneOff, el.toEdge, el.toLane, Lane2LaneInfoType::COMPUTED);
3697 27 : }
3698 : }
3699 22 : }
3700 :
3701 :
3702 : bool
3703 93 : NBEdge::lanesWereAssigned() const {
3704 93 : return myStep == EdgeBuildingStep::LANES2LANES_DONE || myStep == EdgeBuildingStep::LANES2LANES_USER;
3705 : }
3706 :
3707 :
3708 : double
3709 0 : NBEdge::getMaxLaneOffset() {
3710 0 : return SUMO_const_laneWidth * (double)myLanes.size();
3711 : }
3712 :
3713 :
3714 : bool
3715 193675 : NBEdge::mayBeTLSControlled(int fromLane, NBEdge* toEdge, int toLane) const {
3716 980842 : for (const Connection& c : myConnections) {
3717 787303 : if (c.fromLane == fromLane && c.toEdge == toEdge && c.toLane == toLane && c.uncontrolled) {
3718 : return false;
3719 : }
3720 : }
3721 : return true;
3722 : }
3723 :
3724 :
3725 : bool
3726 30711 : NBEdge::setControllingTLInformation(const NBConnection& c, const std::string& tlID) {
3727 30711 : const int fromLane = c.getFromLane();
3728 30711 : NBEdge* toEdge = c.getTo();
3729 30711 : const int toLane = c.getToLane();
3730 : const int tlIndex = c.getTLIndex();
3731 : const int tlIndex2 = c.getTLIndex2();
3732 : // check whether the connection was not set as not to be controled previously
3733 30711 : if (!mayBeTLSControlled(fromLane, toEdge, toLane)) {
3734 : return false;
3735 : }
3736 :
3737 : assert(fromLane < 0 || fromLane < (int) myLanes.size());
3738 : // try to use information about the connections if given
3739 30711 : if (fromLane >= 0 && toLane >= 0) {
3740 : // find the specified connection
3741 : std::vector<Connection>::iterator i =
3742 30711 : find_if(myConnections.begin(), myConnections.end(), connections_finder(fromLane, toEdge, toLane));
3743 : // ok, we have to test this as on the removal of self-loop edges some connections
3744 : // will be reassigned
3745 30711 : if (i != myConnections.end()) {
3746 : // get the connection
3747 : Connection& connection = *i;
3748 : // set the information about the tl
3749 30708 : connection.tlID = tlID;
3750 30708 : connection.tlLinkIndex = tlIndex;
3751 30708 : connection.tlLinkIndex2 = tlIndex2;
3752 : return true;
3753 : }
3754 : }
3755 : // if the original connection was not found, set the information for all
3756 : // connections
3757 : int no = 0;
3758 : bool hadError = false;
3759 12 : for (std::vector<Connection>::iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
3760 9 : if ((*i).toEdge != toEdge) {
3761 9 : continue;
3762 : }
3763 0 : if (fromLane >= 0 && fromLane != (*i).fromLane) {
3764 0 : continue;
3765 : }
3766 0 : if (toLane >= 0 && toLane != (*i).toLane) {
3767 0 : continue;
3768 : }
3769 0 : if ((*i).tlID == "") {
3770 : (*i).tlID = tlID;
3771 0 : (*i).tlLinkIndex = tlIndex;
3772 0 : (*i).tlLinkIndex2 = tlIndex2;
3773 0 : no++;
3774 : } else {
3775 0 : if ((*i).tlID != tlID && (*i).tlLinkIndex == tlIndex) {
3776 0 : WRITE_WARNINGF(TL("The lane '%' on edge '%' already had a traffic light signal."), i->fromLane, getID());
3777 : hadError = true;
3778 : }
3779 : }
3780 : }
3781 3 : if (hadError && no == 0) {
3782 0 : WRITE_WARNINGF(TL("Could not set any signal of the tlLogic '%' (unknown group)."), tlID);
3783 : }
3784 : return true;
3785 : }
3786 :
3787 :
3788 : void
3789 90870 : NBEdge::clearControllingTLInformation() {
3790 273147 : for (std::vector<Connection>::iterator it = myConnections.begin(); it != myConnections.end(); it++) {
3791 182277 : it->tlID = "";
3792 : }
3793 90870 : }
3794 :
3795 :
3796 : PositionVector
3797 470620 : NBEdge::getCWBoundaryLine(const NBNode& n) const {
3798 470620 : PositionVector ret;
3799 : int lane;
3800 470620 : if (myFrom == (&n)) {
3801 : // outgoing
3802 252174 : lane = getFirstAllowedLaneIndex(NBNode::FORWARD);
3803 252174 : ret = myLanes[lane].shape;
3804 : } else {
3805 : // incoming
3806 218446 : lane = getFirstAllowedLaneIndex(NBNode::BACKWARD);
3807 436892 : ret = myLanes[lane].shape.reverse();
3808 : }
3809 470620 : ret.move2side(getLaneWidth(lane) / 2.);
3810 470620 : return ret;
3811 0 : }
3812 :
3813 :
3814 : PositionVector
3815 468896 : NBEdge::getCCWBoundaryLine(const NBNode& n) const {
3816 468896 : PositionVector ret;
3817 : int lane;
3818 468896 : if (myFrom == (&n)) {
3819 : // outgoing
3820 218434 : lane = getFirstAllowedLaneIndex(NBNode::BACKWARD);
3821 218434 : ret = myLanes[lane].shape;
3822 : } else {
3823 : // incoming
3824 250462 : lane = getFirstAllowedLaneIndex(NBNode::FORWARD);
3825 500924 : ret = myLanes[lane].shape.reverse();
3826 : }
3827 468896 : ret.move2side(-getLaneWidth(lane) / 2.);
3828 468896 : return ret;
3829 0 : }
3830 :
3831 :
3832 : bool
3833 8454 : NBEdge::expandableBy(NBEdge* possContinuation, std::string& reason) const {
3834 : // ok, the number of lanes must match
3835 8454 : if (myLanes.size() != possContinuation->myLanes.size()) {
3836 : reason = "laneNumber";
3837 328 : return false;
3838 : }
3839 : // do not create self loops
3840 8126 : if (myFrom == possContinuation->myTo) {
3841 : reason = "loop";
3842 1117 : return false;
3843 : }
3844 : // conserve bidi-rails
3845 7009 : if (isBidiRail() != possContinuation->isBidiRail()) {
3846 : reason = "bidi-rail";
3847 4 : return false;
3848 : }
3849 : // also, check whether the connections - if any exit do allow to join
3850 : // both edges
3851 : // This edge must have a one-to-one connection to the following lanes
3852 7005 : switch (myStep) {
3853 : case EdgeBuildingStep::INIT_REJECT_CONNECTIONS:
3854 : break;
3855 : case EdgeBuildingStep::INIT:
3856 : break;
3857 14 : case EdgeBuildingStep::EDGE2EDGES: {
3858 : // the following edge must be connected
3859 14 : const EdgeVector& conn = getConnectedEdges();
3860 14 : if (find(conn.begin(), conn.end(), possContinuation) == conn.end()) {
3861 : reason = "disconnected";
3862 : return false;
3863 : }
3864 14 : }
3865 : break;
3866 20 : case EdgeBuildingStep::LANES2EDGES:
3867 : case EdgeBuildingStep::LANES2LANES_RECHECK:
3868 : case EdgeBuildingStep::LANES2LANES_DONE:
3869 : case EdgeBuildingStep::LANES2LANES_USER: {
3870 : // the possible continuation must be connected
3871 20 : if (find_if(myConnections.begin(), myConnections.end(), connections_toedge_finder(possContinuation)) == myConnections.end()) {
3872 : reason = "disconnected";
3873 0 : return false;
3874 : }
3875 : // all lanes must go to the possible continuation
3876 20 : std::vector<int> conns = getConnectionLanes(possContinuation);
3877 20 : const int offset = MAX2(0, getFirstNonPedestrianLaneIndex(NBNode::FORWARD, true));
3878 20 : if (conns.size() < myLanes.size() - offset) {
3879 : reason = "some lanes disconnected";
3880 : return false;
3881 : }
3882 20 : }
3883 : break;
3884 : default:
3885 : break;
3886 : }
3887 7005 : const double minLength = OptionsCont::getOptions().getFloat("geometry.remove.min-length");
3888 7006 : if (minLength > 0 && (possContinuation->getLoadedLength() < minLength || getLoadedLength() < minLength)) {
3889 : return true;
3890 : }
3891 7004 : const double maxJunctionSize = OptionsCont::getOptions().getFloat("geometry.remove.max-junction-size");
3892 7004 : if (maxJunctionSize >= 0) {
3893 4 : const double junctionSize = myGeom.back().distanceTo2D(possContinuation->myGeom.front());
3894 4 : if (junctionSize > maxJunctionSize + POSITION_EPS) {
3895 8 : reason = "junction size (" + toString(junctionSize) + ") > max-junction-size (" + toString(maxJunctionSize) + ")";
3896 2 : return false;
3897 : }
3898 : }
3899 : // the priority, too (?)
3900 7002 : if (getPriority() != possContinuation->getPriority()) {
3901 : reason = "priority";
3902 70 : return false;
3903 : }
3904 : // the speed allowed
3905 6932 : if (mySpeed != possContinuation->mySpeed) {
3906 : reason = "speed";
3907 1066 : return false;
3908 : }
3909 : // spreadtype should match or it will look ugly
3910 5866 : if (myLaneSpreadFunction != possContinuation->myLaneSpreadFunction) {
3911 : reason = "spreadType";
3912 80 : return false;
3913 : }
3914 : // matching lanes must have identical properties
3915 13511 : for (int i = 0; i < (int)myLanes.size(); i++) {
3916 7807 : if (myLanes[i].speed != possContinuation->myLanes[i].speed) {
3917 0 : reason = "lane " + toString(i) + " speed";
3918 82 : return false;
3919 7807 : } else if (myLanes[i].permissions != possContinuation->myLanes[i].permissions) {
3920 112 : reason = "lane " + toString(i) + " permissions";
3921 56 : return false;
3922 7751 : } else if (myLanes[i].changeLeft != possContinuation->myLanes[i].changeLeft || myLanes[i].changeRight != possContinuation->myLanes[i].changeRight) {
3923 14 : reason = "lane " + toString(i) + " change restrictions";
3924 7 : return false;
3925 7822 : } else if (myLanes[i].width != possContinuation->myLanes[i].width &&
3926 7900 : fabs(myLanes[i].width - possContinuation->myLanes[i].width) > OptionsCont::getOptions().getFloat("geometry.remove.width-tolerance")) {
3927 38 : reason = "lane " + toString(i) + " width";
3928 19 : return false;
3929 : }
3930 : }
3931 : // if given identically osm names
3932 15731 : if (!OptionsCont::getOptions().isDefault("output.street-names") && myStreetName != possContinuation->getStreetName()
3933 5813 : && ((myStreetName != "" && possContinuation->getStreetName() != "")
3934 : // only permit merging a short unnamed road with a longer named road
3935 21 : || (myStreetName != "" && myLength <= possContinuation->getLength())
3936 16 : || (myStreetName == "" && myLength >= possContinuation->getLength()))) {
3937 : return false;
3938 : }
3939 :
3940 : return true;
3941 : }
3942 :
3943 :
3944 : void
3945 5416 : NBEdge::append(NBEdge* e) {
3946 : // append geometry
3947 5416 : myGeom.append(e->myGeom);
3948 12717 : for (int i = 0; i < (int)myLanes.size(); i++) {
3949 7301 : myLanes[i].customShape.append(e->myLanes[i].customShape);
3950 9252 : if (myLanes[i].hasParameter(SUMO_PARAM_ORIGID) || e->myLanes[i].hasParameter(SUMO_PARAM_ORIGID)
3951 16553 : || OptionsCont::getOptions().getBool("output.original-names")) {
3952 16062 : const std::string origID = myLanes[i].getParameter(SUMO_PARAM_ORIGID, getID());
3953 16062 : const std::string origID2 = e->myLanes[i].getParameter(SUMO_PARAM_ORIGID, e->getID());
3954 5354 : if (origID != origID2) {
3955 9756 : myLanes[i].setParameter(SUMO_PARAM_ORIGID, origID + " " + origID2);
3956 : }
3957 : }
3958 7301 : myLanes[i].connectionsDone = e->myLanes[i].connectionsDone;
3959 7301 : myLanes[i].turnSigns = e->myLanes[i].turnSigns;
3960 : }
3961 5416 : if (e->getLength() > myLength) {
3962 : // possibly some lane attributes differ (when using option geometry.remove.min-length)
3963 : // make sure to use the attributes from the longer edge
3964 5942 : for (int i = 0; i < (int)myLanes.size(); i++) {
3965 3325 : myLanes[i].width = e->myLanes[i].width;
3966 : }
3967 : // defined name prevails over undefined name of shorter road
3968 2617 : if (myStreetName == "") {
3969 1267 : myStreetName = e->myStreetName;
3970 : }
3971 : }
3972 : // recompute length
3973 5416 : myLength += e->myLength;
3974 5416 : if (myLoadedLength > 0 || e->myLoadedLength > 0) {
3975 1 : myLoadedLength = getFinalLength() + e->getFinalLength();
3976 : }
3977 : // copy the connections and the building step if given
3978 5416 : myStep = e->myStep;
3979 5416 : myConnections = e->myConnections;
3980 5416 : myTurnDestination = e->myTurnDestination;
3981 5416 : myPossibleTurnDestination = e->myPossibleTurnDestination;
3982 5416 : myConnectionsToDelete = e->myConnectionsToDelete;
3983 : // set the node
3984 5416 : myTo = e->myTo;
3985 5416 : myTurnSignTarget = e->myTurnSignTarget;
3986 : myToBorder = e->myToBorder;
3987 10832 : mergeParameters(e->getParametersMap());
3988 : if (e->mySignalPosition != Position::INVALID) {
3989 1147 : mySignalPosition = e->mySignalPosition;
3990 : }
3991 5416 : computeAngle(); // myEndAngle may be different now
3992 5416 : }
3993 :
3994 :
3995 : bool
3996 902226 : NBEdge::hasSignalisedConnectionTo(const NBEdge* const e) const {
3997 3820332 : for (std::vector<Connection>::const_iterator i = myConnections.begin(); i != myConnections.end(); ++i) {
3998 3209535 : if ((*i).toEdge == e && (*i).tlID != "") {
3999 : return true;
4000 : }
4001 : }
4002 : return false;
4003 : }
4004 :
4005 :
4006 : NBEdge*
4007 751051 : NBEdge::getTurnDestination(bool possibleDestination) const {
4008 751051 : if (myTurnDestination == nullptr && possibleDestination) {
4009 39893 : return myPossibleTurnDestination;
4010 : }
4011 : return myTurnDestination;
4012 : }
4013 :
4014 :
4015 : std::string
4016 248718 : NBEdge::getLaneID(int lane) const {
4017 497436 : return myID + "_" + toString(lane);
4018 : }
4019 :
4020 :
4021 : bool
4022 65 : NBEdge::isNearEnough2BeJoined2(NBEdge* e, double threshold) const {
4023 65 : std::vector<double> distances = myGeom.distances(e->getGeometry());
4024 : assert(distances.size() > 0);
4025 130 : return VectorHelper<double>::maxValue(distances) < threshold;
4026 65 : }
4027 :
4028 :
4029 : void
4030 63 : NBEdge::addLane(int index, bool recomputeShape, bool recomputeConnections, bool shiftIndices) {
4031 : assert(index <= (int)myLanes.size());
4032 189 : myLanes.insert(myLanes.begin() + index, Lane(this, ""));
4033 : // copy attributes
4034 63 : if (myLanes.size() > 1) {
4035 63 : int templateIndex = index > 0 ? index - 1 : index + 1;
4036 63 : myLanes[index].speed = myLanes[templateIndex].speed;
4037 63 : myLanes[index].friction = myLanes[templateIndex].friction;
4038 63 : myLanes[index].permissions = myLanes[templateIndex].permissions;
4039 63 : myLanes[index].preferred = myLanes[templateIndex].preferred;
4040 63 : myLanes[index].endOffset = myLanes[templateIndex].endOffset;
4041 63 : myLanes[index].width = myLanes[templateIndex].width;
4042 63 : myLanes[index].updateParameters(myLanes[templateIndex].getParametersMap());
4043 : }
4044 63 : const EdgeVector& incs = myFrom->getIncomingEdges();
4045 63 : if (recomputeShape) {
4046 47 : computeLaneShapes();
4047 : }
4048 63 : if (recomputeConnections) {
4049 121 : for (EdgeVector::const_iterator i = incs.begin(); i != incs.end(); ++i) {
4050 74 : (*i)->invalidateConnections(true);
4051 : }
4052 47 : invalidateConnections(true);
4053 16 : } else if (shiftIndices) {
4054 : // shift outgoing connections above the added lane to the left
4055 0 : for (Connection& c : myConnections) {
4056 0 : if (c.fromLane >= index) {
4057 0 : c.fromLane += 1;
4058 : }
4059 : }
4060 : // shift incoming connections above the added lane to the left
4061 0 : for (NBEdge* inc : myFrom->getIncomingEdges()) {
4062 0 : for (Connection& c : inc->myConnections) {
4063 0 : if (c.toEdge == this && c.toLane >= index) {
4064 0 : c.toLane += 1;
4065 : }
4066 : }
4067 : }
4068 0 : myFrom->shiftTLConnectionLaneIndex(this, +1, index - 1);
4069 0 : myTo->shiftTLConnectionLaneIndex(this, +1, index - 1);
4070 : }
4071 63 : }
4072 :
4073 : void
4074 50 : NBEdge::incLaneNo(int by) {
4075 50 : int newLaneNo = (int)myLanes.size() + by;
4076 113 : while ((int)myLanes.size() < newLaneNo) {
4077 : // recompute shapes on last addition
4078 63 : const bool recompute = ((int)myLanes.size() == newLaneNo - 1) && myStep < EdgeBuildingStep::LANES2LANES_USER;
4079 63 : addLane((int)myLanes.size(), recompute, recompute, false);
4080 : }
4081 50 : }
4082 :
4083 :
4084 : void
4085 68 : NBEdge::deleteLane(int index, bool recompute, bool shiftIndices) {
4086 : assert(index < (int)myLanes.size());
4087 68 : myLanes.erase(myLanes.begin() + index);
4088 68 : if (recompute) {
4089 16 : computeLaneShapes();
4090 16 : const EdgeVector& incs = myFrom->getIncomingEdges();
4091 17 : for (EdgeVector::const_iterator i = incs.begin(); i != incs.end(); ++i) {
4092 1 : (*i)->invalidateConnections(true);
4093 : }
4094 16 : invalidateConnections(true);
4095 52 : } else if (shiftIndices) {
4096 44 : removeFromConnections(nullptr, index, -1, false, true);
4097 120 : for (NBEdge* inc : myFrom->getIncomingEdges()) {
4098 76 : inc->removeFromConnections(this, -1, index, false, true);
4099 : }
4100 : }
4101 68 : }
4102 :
4103 :
4104 : void
4105 39 : NBEdge::decLaneNo(int by) {
4106 39 : int newLaneNo = (int) myLanes.size() - by;
4107 : assert(newLaneNo > 0);
4108 63 : while ((int)myLanes.size() > newLaneNo) {
4109 : // recompute shapes on last removal
4110 24 : const bool recompute = (int)myLanes.size() == newLaneNo + 1 && myStep < EdgeBuildingStep::LANES2LANES_USER;
4111 24 : deleteLane((int)myLanes.size() - 1, recompute, false);
4112 : }
4113 39 : }
4114 :
4115 :
4116 : void
4117 4994 : NBEdge::markAsInLane2LaneState() {
4118 : assert(myTo->getOutgoingEdges().size() == 0);
4119 4994 : myStep = EdgeBuildingStep::LANES2LANES_DONE;
4120 4994 : }
4121 :
4122 :
4123 : void
4124 7879 : NBEdge::allowVehicleClass(int lane, SUMOVehicleClass vclass) {
4125 7879 : if (lane < 0) { // all lanes are meant...
4126 7818 : for (int i = 0; i < (int)myLanes.size(); i++) {
4127 5510 : allowVehicleClass(i, vclass);
4128 : }
4129 : } else {
4130 : assert(lane < (int)myLanes.size());
4131 5571 : myLanes[lane].permissions |= vclass;
4132 : }
4133 7879 : }
4134 :
4135 :
4136 : void
4137 24762 : NBEdge::disallowVehicleClass(int lane, SUMOVehicleClass vclass) {
4138 24762 : if (lane < 0) { // all lanes are meant...
4139 24762 : for (int i = 0; i < (int)myLanes.size(); i++) {
4140 15319 : disallowVehicleClass((int) i, vclass);
4141 : }
4142 : } else {
4143 : assert(lane < (int)myLanes.size());
4144 15319 : myLanes[lane].permissions &= ~vclass;
4145 : }
4146 24762 : }
4147 :
4148 :
4149 : void
4150 60 : NBEdge::preferVehicleClass(int lane, SVCPermissions vclasses) {
4151 60 : if (lane < 0) { // all lanes are meant...
4152 0 : for (int i = 0; i < (int)myLanes.size(); i++) {
4153 0 : preferVehicleClass(i, vclasses);
4154 : }
4155 : } else {
4156 : assert(lane < (int)myLanes.size());
4157 60 : myLanes[lane].permissions |= vclasses;
4158 60 : myLanes[lane].preferred |= vclasses;
4159 : }
4160 60 : }
4161 :
4162 :
4163 : void
4164 37735 : NBEdge::setLaneWidth(int lane, double width) {
4165 37735 : if (lane < 0) {
4166 : // all lanes are meant...
4167 328 : myLaneWidth = width;
4168 677 : for (int i = 0; i < (int)myLanes.size(); i++) {
4169 : // ... do it for each lane
4170 349 : setLaneWidth(i, width);
4171 : }
4172 : return;
4173 : }
4174 : assert(lane < (int)myLanes.size());
4175 37407 : myLanes[lane].width = width;
4176 : }
4177 :
4178 : void
4179 3468 : NBEdge::setLaneType(int lane, const std::string& type) {
4180 3468 : if (lane < 0) {
4181 0 : for (int i = 0; i < (int)myLanes.size(); i++) {
4182 : // ... do it for each lane
4183 0 : setLaneType(i, type);
4184 : }
4185 : return;
4186 : }
4187 : assert(lane < (int)myLanes.size());
4188 3468 : myLanes[lane].type = type;
4189 : }
4190 :
4191 :
4192 : double
4193 3529348 : NBEdge::getLaneWidth(int lane) const {
4194 3529348 : return myLanes[lane].width != UNSPECIFIED_WIDTH
4195 3529348 : ? myLanes[lane].width
4196 2893636 : : getLaneWidth() != UNSPECIFIED_WIDTH ? getLaneWidth() : SUMO_const_laneWidth;
4197 : }
4198 :
4199 : double
4200 108450 : NBEdge::getInternalLaneWidth(
4201 : const NBNode& node,
4202 : const NBEdge::Connection& connection,
4203 : const NBEdge::Lane& successor,
4204 : bool isVia) const {
4205 :
4206 108450 : if (!isVia && node.isConstantWidthTransition() && getNumLanes() > connection.toEdge->getNumLanes()) {
4207 3 : return getLaneWidth(connection.fromLane);
4208 : }
4209 :
4210 108447 : return (isBikepath(getPermissions(connection.fromLane)) && (
4211 108447 : getLaneWidth(connection.fromLane) < successor.width || successor.width == UNSPECIFIED_WIDTH)) ?
4212 9788 : myLanes[connection.fromLane].width : successor.width; // getLaneWidth(connection.fromLane) never returns -1 (UNSPECIFIED_WIDTH)
4213 : }
4214 :
4215 : double
4216 805387 : NBEdge::getTotalWidth() const {
4217 : double result = 0;
4218 1868710 : for (int i = 0; i < (int)myLanes.size(); i++) {
4219 1063323 : result += getLaneWidth(i);
4220 : }
4221 805387 : return result;
4222 : }
4223 :
4224 : double
4225 23193 : NBEdge::getEndOffset(int lane) const {
4226 23193 : return myLanes[lane].endOffset != UNSPECIFIED_OFFSET ? myLanes[lane].endOffset : getEndOffset();
4227 : }
4228 :
4229 :
4230 : const StopOffset&
4231 451666 : NBEdge::getEdgeStopOffset() const {
4232 451666 : return myEdgeStopOffset;
4233 : }
4234 :
4235 :
4236 : const StopOffset&
4237 24 : NBEdge::getLaneStopOffset(int lane) const {
4238 24 : if (lane == -1) {
4239 12 : return myEdgeStopOffset;
4240 : } else {
4241 12 : return myLanes[lane].laneStopOffset;
4242 : }
4243 : }
4244 :
4245 :
4246 : void
4247 31923 : NBEdge::setEndOffset(int lane, double offset) {
4248 31923 : if (lane < 0) {
4249 : // all lanes are meant...
4250 1 : myEndOffset = offset;
4251 4 : for (int i = 0; i < (int)myLanes.size(); i++) {
4252 : // ... do it for each lane
4253 3 : setEndOffset(i, offset);
4254 : }
4255 : return;
4256 : }
4257 : assert(lane < (int)myLanes.size());
4258 31922 : myLanes[lane].endOffset = offset;
4259 : }
4260 :
4261 :
4262 : bool
4263 54883 : NBEdge::setEdgeStopOffset(int lane, const StopOffset& offset, bool overwrite) {
4264 54883 : if (lane < 0) {
4265 22976 : if (!overwrite && myEdgeStopOffset.isDefined()) {
4266 : return false;
4267 : }
4268 : // all lanes are meant...
4269 22972 : if (offset.getOffset() < 0) {
4270 : // Edge length unknown at parsing time, thus check here.
4271 3 : WRITE_WARNINGF(TL("Ignoring invalid stopOffset for edge '%' (negative offset)."), getID());
4272 1 : return false;
4273 : } else {
4274 22971 : myEdgeStopOffset = offset;
4275 : }
4276 31907 : } else if (lane < (int)myLanes.size()) {
4277 31907 : if (!myLanes[lane].laneStopOffset.isDefined() || overwrite) {
4278 31901 : if (offset.getOffset() < 0) {
4279 : // Edge length unknown at parsing time, thus check here.
4280 0 : WRITE_WARNINGF(TL("Ignoring invalid stopOffset for lane '%' (negative offset)."), getLaneID(lane));
4281 : } else {
4282 31901 : myLanes[lane].laneStopOffset = offset;
4283 : }
4284 : }
4285 : } else {
4286 0 : WRITE_WARNINGF(TL("Ignoring invalid stopOffset for lane '%' (invalid lane index)."), toString(lane));
4287 : }
4288 : return true;
4289 : }
4290 :
4291 :
4292 : void
4293 36163 : NBEdge::setSpeed(int lane, double speed) {
4294 36163 : if (lane < 0) {
4295 : // all lanes are meant...
4296 328 : mySpeed = speed;
4297 1046 : for (int i = 0; i < (int)myLanes.size(); i++) {
4298 : // ... do it for each lane
4299 718 : setSpeed(i, speed);
4300 : }
4301 : return;
4302 : }
4303 : assert(lane < (int)myLanes.size());
4304 35835 : myLanes[lane].speed = speed;
4305 : }
4306 :
4307 :
4308 : void
4309 35907 : NBEdge::setFriction(int lane, double friction) {
4310 35907 : if (lane < 0) {
4311 : // all lanes are meant...
4312 606 : myFriction = friction;
4313 1866 : for (int i = 0; i < (int)myLanes.size(); i++) {
4314 : // ... do it for each lane
4315 1260 : setFriction(i, friction);
4316 : }
4317 : return;
4318 : }
4319 : assert(lane < (int)myLanes.size());
4320 35301 : myLanes[lane].friction = friction;
4321 : }
4322 :
4323 :
4324 : void
4325 30691 : NBEdge::setAcceleration(int lane, bool accelRamp) {
4326 : assert(lane >= 0);
4327 : assert(lane < (int)myLanes.size());
4328 30691 : myLanes[lane].accelRamp = accelRamp;
4329 30691 : }
4330 :
4331 :
4332 : void
4333 73 : NBEdge::setLaneShape(int lane, const PositionVector& shape) {
4334 : assert(lane >= 0);
4335 : assert(lane < (int)myLanes.size());
4336 73 : myLanes[lane].customShape = shape;
4337 73 : }
4338 :
4339 :
4340 : void
4341 223218 : NBEdge::setPermissions(SVCPermissions permissions, int lane) {
4342 223218 : if (lane < 0) {
4343 181579 : for (int i = 0; i < (int)myLanes.size(); i++) {
4344 : // ... do it for each lane
4345 100389 : setPermissions(permissions, i);
4346 : }
4347 : } else {
4348 : assert(lane < (int)myLanes.size());
4349 142028 : myLanes[lane].permissions = permissions;
4350 : }
4351 223218 : }
4352 :
4353 :
4354 : void
4355 0 : NBEdge::setPreferredVehicleClass(SVCPermissions permissions, int lane) {
4356 0 : if (lane < 0) {
4357 0 : for (int i = 0; i < (int)myLanes.size(); i++) {
4358 : // ... do it for each lane
4359 0 : setPreferredVehicleClass(permissions, i);
4360 : }
4361 : } else {
4362 : assert(lane < (int)myLanes.size());
4363 0 : myLanes[lane].preferred = permissions;
4364 : }
4365 0 : }
4366 :
4367 :
4368 : void
4369 30920 : NBEdge::setPermittedChanging(int lane, SVCPermissions changeLeft, SVCPermissions changeRight) {
4370 : assert(lane >= 0);
4371 : assert(lane < (int)myLanes.size());
4372 30920 : myLanes[lane].changeLeft = changeLeft;
4373 30920 : myLanes[lane].changeRight = changeRight;
4374 30920 : }
4375 :
4376 :
4377 : SVCPermissions
4378 74243333 : NBEdge::getPermissions(int lane) const {
4379 74243333 : if (lane < 0) {
4380 : SVCPermissions result = 0;
4381 66592538 : for (int i = 0; i < (int)myLanes.size(); i++) {
4382 40100444 : result |= getPermissions(i);
4383 : }
4384 26492094 : return result;
4385 : } else {
4386 : assert(lane < (int)myLanes.size());
4387 47751239 : return myLanes[lane].permissions;
4388 : }
4389 : }
4390 :
4391 :
4392 : void
4393 41653 : NBEdge::setLoadedLength(double val) {
4394 41653 : myLoadedLength = val;
4395 41653 : }
4396 :
4397 : void
4398 4 : NBEdge::setAverageLengthWithOpposite(double val) {
4399 4 : myLength = val;
4400 4 : }
4401 :
4402 :
4403 : void
4404 200 : NBEdge::dismissVehicleClassInformation() {
4405 647 : for (std::vector<Lane>::iterator i = myLanes.begin(); i != myLanes.end(); ++i) {
4406 447 : (*i).permissions = SVCAll;
4407 447 : (*i).preferred = 0;
4408 : }
4409 200 : }
4410 :
4411 :
4412 : bool
4413 331741 : NBEdge::connections_sorter(const Connection& c1, const Connection& c2) {
4414 331741 : if (c1.fromLane != c2.fromLane) {
4415 81614 : return c1.fromLane < c2.fromLane;
4416 : }
4417 250127 : if (c1.toEdge != c2.toEdge) {
4418 : return false; // do not change ordering among toEdges as this is determined by angle in an earlier step
4419 : }
4420 5010 : return c1.toLane < c2.toLane;
4421 : }
4422 :
4423 :
4424 : double
4425 9828 : NBEdge::getSignalOffset() const {
4426 : if (mySignalPosition == Position::INVALID) {
4427 : return UNSPECIFIED_SIGNAL_OFFSET;
4428 : } else {
4429 665 : Position laneEnd = myLaneSpreadFunction == LaneSpreadFunction::RIGHT ?
4430 665 : myLanes.back().shape.back() : myLanes[getNumLanes() / 2].shape.back();
4431 : //std::cout << getID() << " signalPos=" << mySignalPosition << " laneEnd=" << laneEnd << " toShape=" << myTo->getShape() << " toBorder=" << myToBorder << "\n";
4432 : return mySignalPosition.distanceTo2D(laneEnd);
4433 : }
4434 : }
4435 :
4436 :
4437 : int
4438 26629 : NBEdge::getFirstNonPedestrianLaneIndex(int direction, bool exclusive) const {
4439 : assert(direction == NBNode::FORWARD || direction == NBNode::BACKWARD);
4440 26629 : const int start = (direction == NBNode::FORWARD ? 0 : (int)myLanes.size() - 1);
4441 26629 : const int end = (direction == NBNode::FORWARD ? (int)myLanes.size() : - 1);
4442 34701 : for (int i = start; i != end; i += direction) {
4443 : // SVCAll, does not count as a sidewalk, green verges (permissions = 0) do not count as road
4444 : // in the exclusive case, lanes that allow pedestrians along with any other class also count as road
4445 23369 : if ((exclusive && myLanes[i].permissions != SVC_PEDESTRIAN && myLanes[i].permissions != 0)
4446 34690 : || ((myLanes[i].permissions & SVC_PEDESTRIAN) == 0 && myLanes[i].permissions != 0)) {
4447 21267 : return i;
4448 : }
4449 : }
4450 : return -1;
4451 : }
4452 :
4453 : int
4454 45863 : NBEdge::getFirstNonPedestrianNonBicycleLaneIndex(int direction, bool exclusive) const {
4455 : assert(direction == NBNode::FORWARD || direction == NBNode::BACKWARD);
4456 45863 : const int start = (direction == NBNode::FORWARD ? 0 : (int)myLanes.size() - 1);
4457 45863 : const int end = (direction == NBNode::FORWARD ? (int)myLanes.size() : - 1);
4458 61440 : for (int i = start; i != end; i += direction) {
4459 : // SVCAll, does not count as a sidewalk, green verges (permissions = 0) do not count as road
4460 : // in the exclusive case, lanes that allow pedestrians along with any other class also count as road
4461 47702 : SVCPermissions p = myLanes[i].permissions;
4462 47702 : if ((exclusive && p != SVC_PEDESTRIAN && p != SVC_BICYCLE && p != (SVC_PEDESTRIAN | SVC_BICYCLE) && p != 0)
4463 15577 : || (p == SVCAll || ((p & (SVC_PEDESTRIAN | SVC_BICYCLE)) == 0 && p != 0))) {
4464 32125 : return i;
4465 : }
4466 : }
4467 : return -1;
4468 : }
4469 :
4470 : int
4471 82056 : NBEdge::getSpecialLane(SVCPermissions permissions) const {
4472 186365 : for (int i = 0; i < (int)myLanes.size(); i++) {
4473 105332 : if (myLanes[i].permissions == permissions) {
4474 1023 : return i;
4475 : }
4476 : }
4477 : return -1;
4478 : }
4479 :
4480 : int
4481 1026420 : NBEdge::getFirstAllowedLaneIndex(int direction) const {
4482 : assert(direction == NBNode::FORWARD || direction == NBNode::BACKWARD);
4483 1026420 : const int start = (direction == NBNode::FORWARD ? 0 : (int)myLanes.size() - 1);
4484 1026420 : const int end = (direction == NBNode::FORWARD ? (int)myLanes.size() : - 1);
4485 1026844 : for (int i = start; i != end; i += direction) {
4486 1026655 : if (myLanes[i].permissions != 0) {
4487 1026231 : return i;
4488 : }
4489 : }
4490 189 : return end - direction;
4491 : }
4492 :
4493 :
4494 : std::set<SVCPermissions>
4495 3497 : NBEdge::getPermissionVariants(int iStart, int iEnd) const {
4496 : std::set<SVCPermissions> result;
4497 3497 : if (iStart < 0 || iStart >= getNumLanes() || iEnd > getNumLanes()) {
4498 0 : throw ProcessError("invalid indices iStart " + toString(iStart) + " iEnd " + toString(iEnd) + " for edge with " + toString(getNumLanes()) + " lanes.");
4499 : }
4500 7714 : for (int i = iStart; i < iEnd; ++i) {
4501 4217 : result.insert(getPermissions(i));
4502 : }
4503 3497 : return result;
4504 : }
4505 :
4506 : int
4507 5695214 : NBEdge::getNumLanesThatAllow(SVCPermissions permissions, bool allPermissions) const {
4508 : int result = 0;
4509 14776931 : for (const Lane& lane : myLanes) {
4510 9081717 : if ((allPermissions && (lane.permissions & permissions) == permissions)
4511 70 : || (!allPermissions && (lane.permissions & permissions) != 0)) {
4512 7906864 : result++;
4513 : }
4514 : }
4515 5695214 : return result;
4516 : }
4517 :
4518 : bool
4519 0 : NBEdge::allowsChangingLeft(int lane, SUMOVehicleClass vclass) const {
4520 : assert(lane >= 0 && lane < getNumLanes());
4521 0 : return myLanes[lane].changeLeft == SVC_UNSPECIFIED ? true : (myLanes[lane].changeLeft & vclass) == vclass;
4522 : }
4523 :
4524 : bool
4525 0 : NBEdge::allowsChangingRight(int lane, SUMOVehicleClass vclass) const {
4526 : assert(lane >= 0 && lane < getNumLanes());
4527 0 : return myLanes[lane].changeRight == SVC_UNSPECIFIED ? true : (myLanes[lane].changeRight & vclass) == vclass;
4528 : }
4529 :
4530 : double
4531 5704 : NBEdge::getCrossingAngle(NBNode* node) {
4532 5704 : double angle = getAngleAtNode(node) + (getFromNode() == node ? 180.0 : 0.0);
4533 5704 : if (angle < 0) {
4534 1470 : angle += 360.0;
4535 : }
4536 5704 : if (angle >= 360) {
4537 0 : angle -= 360.0;
4538 : }
4539 5704 : if (gDebugFlag1) {
4540 0 : std::cout << getID() << " angle=" << getAngleAtNode(node) << " convAngle=" << angle << "\n";
4541 : }
4542 5704 : return angle;
4543 : }
4544 :
4545 :
4546 : NBEdge::Lane
4547 0 : NBEdge::getFirstNonPedestrianLane(int direction) const {
4548 0 : int index = getFirstNonPedestrianLaneIndex(direction);
4549 0 : if (index < 0) {
4550 0 : throw ProcessError(TLF("Edge % allows pedestrians on all lanes", getID()));
4551 : }
4552 0 : return myLanes[index];
4553 : }
4554 :
4555 : std::string
4556 10973 : NBEdge::getSidewalkID() {
4557 : // see IntermodalEdge::getSidewalk()
4558 13461 : for (int i = 0; i < (int)myLanes.size(); i++) {
4559 11024 : if (myLanes[i].permissions == SVC_PEDESTRIAN) {
4560 8536 : return getLaneID(i);
4561 : }
4562 : }
4563 2437 : for (int i = 0; i < (int)myLanes.size(); i++) {
4564 2437 : if ((myLanes[i].permissions & SVC_PEDESTRIAN) != 0) {
4565 2437 : return getLaneID(i);
4566 : }
4567 : }
4568 0 : return getLaneID(0);
4569 : }
4570 :
4571 : void
4572 3172 : NBEdge::addSidewalk(double width) {
4573 3172 : addRestrictedLane(width, SVC_PEDESTRIAN);
4574 3172 : }
4575 :
4576 :
4577 : void
4578 0 : NBEdge::restoreSidewalk(std::vector<NBEdge::Lane> oldLanes, PositionVector oldGeometry, std::vector<NBEdge::Connection> oldConnections) {
4579 0 : restoreRestrictedLane(SVC_PEDESTRIAN, oldLanes, oldGeometry, oldConnections);
4580 0 : }
4581 :
4582 :
4583 : void
4584 584 : NBEdge::addBikeLane(double width) {
4585 584 : addRestrictedLane(width, SVC_BICYCLE);
4586 584 : }
4587 :
4588 :
4589 : void
4590 0 : NBEdge::restoreBikelane(std::vector<NBEdge::Lane> oldLanes, PositionVector oldGeometry, std::vector<NBEdge::Connection> oldConnections) {
4591 0 : restoreRestrictedLane(SVC_BICYCLE, oldLanes, oldGeometry, oldConnections);
4592 0 : }
4593 :
4594 : bool
4595 4415 : NBEdge::hasRestrictedLane(SUMOVehicleClass vclass) const {
4596 11288 : for (const Lane& lane : myLanes) {
4597 6995 : if (lane.permissions == vclass) {
4598 : return true;
4599 : }
4600 : }
4601 : return false;
4602 : }
4603 :
4604 :
4605 : void
4606 3998 : NBEdge::addRestrictedLane(double width, SUMOVehicleClass vclass) {
4607 3998 : if (hasRestrictedLane(vclass)) {
4608 12 : WRITE_WARNINGF(TL("Edge '%' already has a dedicated lane for %s. Not adding another one."), getID(), toString(vclass));
4609 4 : return;
4610 : }
4611 3994 : if (myLaneSpreadFunction == LaneSpreadFunction::CENTER) {
4612 1137 : myGeom.move2side(width / 2);
4613 : }
4614 : // disallow the designated vclass on all "old" lanes
4615 3994 : disallowVehicleClass(-1, vclass);
4616 : // don't create a restricted vehicle lane to the right of a sidewalk
4617 3994 : const int newIndex = (vclass != SVC_PEDESTRIAN && myLanes[0].permissions == SVC_PEDESTRIAN) ? 1 : 0;
4618 : if (newIndex == 0) {
4619 : // disallow pedestrians on all "higher" lanes to ensure that sidewalk remains the rightmost lane
4620 3953 : disallowVehicleClass(-1, SVC_PEDESTRIAN);
4621 : }
4622 : // add new lane
4623 11982 : myLanes.insert(myLanes.begin() + newIndex, Lane(this, myLanes[0].getParameter(SUMO_PARAM_ORIGID)));
4624 3994 : myLanes[newIndex].permissions = vclass;
4625 3994 : myLanes[newIndex].width = fabs(width);
4626 : // shift outgoing connections to the left
4627 4020 : for (std::vector<Connection>::iterator it = myConnections.begin(); it != myConnections.end(); ++it) {
4628 : Connection& c = *it;
4629 26 : if (c.fromLane >= newIndex) {
4630 26 : c.fromLane += 1;
4631 : }
4632 : }
4633 : // shift incoming connections to the left
4634 3994 : const EdgeVector& incoming = myFrom->getIncomingEdges();
4635 8992 : for (EdgeVector::const_iterator it = incoming.begin(); it != incoming.end(); ++it) {
4636 4998 : (*it)->shiftToLanesToEdge(this, 1);
4637 : }
4638 3994 : myFrom->shiftTLConnectionLaneIndex(this, 1);
4639 3994 : myTo->shiftTLConnectionLaneIndex(this, 1);
4640 3994 : computeLaneShapes();
4641 : }
4642 :
4643 :
4644 : void
4645 0 : NBEdge::restoreRestrictedLane(SUMOVehicleClass vclass, std::vector<NBEdge::Lane> oldLanes, PositionVector oldGeometry, std::vector<NBEdge::Connection> oldConnections) {
4646 : // check that previously lane was transformed
4647 0 : if (myLanes[0].permissions != vclass) {
4648 0 : WRITE_WARNINGF(TL("Edge '%' doesn't have a dedicated lane for %s. Cannot be restored."), getID(), toString(vclass));
4649 0 : return;
4650 : }
4651 : // restore old values
4652 : myGeom = oldGeometry;
4653 0 : myLanes = oldLanes;
4654 0 : myConnections = oldConnections;
4655 : // shift incoming connections to the right
4656 0 : const EdgeVector& incoming = myFrom->getIncomingEdges();
4657 0 : for (EdgeVector::const_iterator it = incoming.begin(); it != incoming.end(); ++it) {
4658 0 : (*it)->shiftToLanesToEdge(this, 0);
4659 : }
4660 : // Shift TL conections
4661 0 : myFrom->shiftTLConnectionLaneIndex(this, 0);
4662 0 : myTo->shiftTLConnectionLaneIndex(this, 0);
4663 0 : computeLaneShapes();
4664 : }
4665 :
4666 :
4667 : void
4668 4998 : NBEdge::shiftToLanesToEdge(NBEdge* to, int laneOff) {
4669 : /// XXX could we repurpose the function replaceInConnections ?
4670 5106 : for (std::vector<Connection>::iterator it = myConnections.begin(); it != myConnections.end(); ++it) {
4671 108 : if ((*it).toEdge == to && (*it).toLane >= 0) {
4672 26 : (*it).toLane += laneOff;
4673 : }
4674 : }
4675 4998 : }
4676 :
4677 :
4678 : void
4679 77506 : NBEdge::shiftPositionAtNode(NBNode* node, NBEdge* other) {
4680 77506 : if (myLaneSpreadFunction == LaneSpreadFunction::CENTER && !isRailway(getPermissions()) && getBidiEdge() == nullptr) {
4681 11314 : const int i = (node == myTo ? -1 : 0);
4682 11314 : const int i2 = (node == myTo ? 0 : -1);
4683 11314 : const double dist = myGeom[i].distanceTo2D(node->getPosition());
4684 11314 : const double neededOffset = getTotalWidth() / 2;
4685 11314 : const double dist2 = MIN2(myGeom.distance2D(other->getGeometry()[i2]),
4686 11314 : other->getGeometry().distance2D(myGeom[i]));
4687 11314 : const double neededOffset2 = neededOffset + (other->getTotalWidth()) / 2;
4688 11314 : if (dist < neededOffset && dist2 < neededOffset2) {
4689 : PositionVector tmp = myGeom;
4690 : // @note this doesn't work well for vissim networks
4691 : //tmp.move2side(MIN2(neededOffset - dist, neededOffset2 - dist2));
4692 : try {
4693 8994 : tmp.move2side(neededOffset - dist);
4694 8994 : myGeom[i] = tmp[i];
4695 0 : } catch (InvalidArgument&) {
4696 0 : WRITE_WARNINGF(TL("Could not avoid overlapping shape at node '%' for edge '%'."), node->getID(), getID());
4697 0 : }
4698 8994 : }
4699 : }
4700 77506 : }
4701 :
4702 :
4703 : Position
4704 72 : NBEdge::geometryPositionAtOffset(double offset) const {
4705 72 : if (myLoadedLength > 0) {
4706 2 : return myGeom.positionAtOffset(offset * myLength / myLoadedLength);
4707 : } else {
4708 70 : return myGeom.positionAtOffset(offset);
4709 : }
4710 : }
4711 :
4712 :
4713 : double
4714 102283 : NBEdge::getFinalLength() const {
4715 : double result = getLoadedLength();
4716 204566 : if (OptionsCont::getOptions().getBool("no-internal-links") && !hasLoadedLength()) {
4717 : // use length to junction center even if a modified geometry was given
4718 44496 : PositionVector geom = cutAtIntersection(myGeom);
4719 44496 : geom.push_back_noDoublePos(getToNode()->getCenter());
4720 44496 : geom.push_front_noDoublePos(getFromNode()->getCenter());
4721 44496 : result = geom.length();
4722 44496 : }
4723 : double avgEndOffset = 0;
4724 233870 : for (const Lane& lane : myLanes) {
4725 131587 : avgEndOffset += lane.endOffset;
4726 : }
4727 102283 : if (isBidiRail()) {
4728 8520 : avgEndOffset += myPossibleTurnDestination->getEndOffset();
4729 : }
4730 102283 : avgEndOffset /= (double)myLanes.size();
4731 102287 : return MAX2(result - avgEndOffset, POSITION_EPS);
4732 : }
4733 :
4734 :
4735 : void
4736 12665 : NBEdge::setOrigID(const std::string origID, const bool append, const int laneIdx) {
4737 12665 : if (laneIdx == -1) {
4738 12608 : for (int i = 0; i < (int)myLanes.size(); i++) {
4739 14138 : setOrigID(origID, append, i);
4740 : }
4741 : } else {
4742 7126 : if (origID != "") {
4743 7126 : if (append) {
4744 114 : std::vector<std::string> oldIDs = StringTokenizer(myLanes[laneIdx].getParameter(SUMO_PARAM_ORIGID)).getVector();
4745 57 : if (std::find(oldIDs.begin(), oldIDs.end(), origID) == oldIDs.end()) {
4746 57 : oldIDs.push_back(origID);
4747 : }
4748 57 : myLanes[laneIdx].setParameter(SUMO_PARAM_ORIGID, toString(oldIDs));
4749 57 : } else {
4750 7069 : myLanes[laneIdx].setParameter(SUMO_PARAM_ORIGID, origID);
4751 : }
4752 : } else {
4753 : // do not record empty origID parameter
4754 0 : myLanes[laneIdx].unsetParameter(SUMO_PARAM_ORIGID);
4755 : }
4756 : }
4757 12665 : }
4758 :
4759 :
4760 : const EdgeVector&
4761 548 : NBEdge::getSuccessors(SUMOVehicleClass vClass) const {
4762 : // @todo cache successors instead of recomputing them every time
4763 : mySuccessors.clear();
4764 : //std::cout << "getSuccessors edge=" << getID() << " svc=" << toString(vClass) << " cons=" << myConnections.size() << "\n";
4765 2934 : for (const Connection& con : myConnections) {
4766 2348 : if (con.fromLane >= 0 && con.toLane >= 0 && con.toEdge != nullptr &&
4767 159 : (vClass == SVC_IGNORING || (getPermissions(con.fromLane)
4768 159 : & con.toEdge->getPermissions(con.toLane) & vClass) != 0)
4769 4734 : && std::find(mySuccessors.begin(), mySuccessors.end(), con.toEdge) == mySuccessors.end()) {
4770 1592 : mySuccessors.push_back(con.toEdge);
4771 : //std::cout << " succ=" << con.toEdge->getID() << "\n";
4772 : }
4773 : }
4774 548 : return mySuccessors;
4775 : }
4776 :
4777 :
4778 : const ConstRouterEdgePairVector&
4779 41313 : NBEdge::getViaSuccessors(SUMOVehicleClass vClass, bool /*ignoreTransientPermissions*/) const {
4780 : // @todo cache successors instead of recomputing them every time
4781 : myViaSuccessors.clear();
4782 84859 : for (const Connection& con : myConnections) {
4783 : std::pair<const NBEdge*, const Connection*> pair(con.toEdge, nullptr);
4784 : // special case for Persons in Netedit
4785 43546 : if (vClass == SVC_PEDESTRIAN) {
4786 0 : myViaSuccessors.push_back(pair); // Pedestrians have complete freedom of movement in all sucessors
4787 43546 : } else if ((con.fromLane >= 0) && (con.toLane >= 0) &&
4788 43546 : (con.toEdge != nullptr) &&
4789 43546 : ((getPermissions(con.fromLane) & con.toEdge->getPermissions(con.toLane) & vClass) == vClass)) {
4790 : // ignore duplicates
4791 43101 : if (con.getLength() > 0) {
4792 : pair.second = &con;
4793 : }
4794 86202 : myViaSuccessors.push_back(pair);
4795 : }
4796 : }
4797 41313 : return myViaSuccessors;
4798 : }
4799 :
4800 :
4801 : void
4802 0 : NBEdge::debugPrintConnections(bool outgoing, bool incoming) const {
4803 0 : if (outgoing) {
4804 0 : for (const Connection& c : myConnections) {
4805 0 : std::cout << " " << getID() << "_" << c.fromLane << "->" << c.toEdge->getID() << "_" << c.toLane << "\n";
4806 : }
4807 : }
4808 0 : if (incoming) {
4809 0 : for (NBEdge* inc : myFrom->getIncomingEdges()) {
4810 0 : for (Connection& c : inc->myConnections) {
4811 0 : if (c.toEdge == this) {
4812 0 : std::cout << " " << inc->getID() << "_" << c.fromLane << "->" << c.toEdge->getID() << "_" << c.toLane << "\n";
4813 : }
4814 : }
4815 : }
4816 : }
4817 0 : }
4818 :
4819 :
4820 : int
4821 77 : NBEdge::getLaneIndexFromLaneID(const std::string laneID) {
4822 154 : return StringUtils::toInt(laneID.substr(laneID.rfind("_") + 1));
4823 : }
4824 :
4825 : bool
4826 36 : NBEdge::joinLanes(SVCPermissions perms) {
4827 : bool haveJoined = false;
4828 : int i = 0;
4829 181 : while (i < getNumLanes() - 1) {
4830 145 : if ((getPermissions(i) == perms) && (getPermissions(i + 1) == perms)) {
4831 37 : const double newWidth = getLaneWidth(i) + getLaneWidth(i + 1);
4832 37 : const std::string newType = myLanes[i].type + "|" + myLanes[i + 1].type;
4833 37 : deleteLane(i, false, true);
4834 37 : setLaneWidth(i, newWidth);
4835 37 : setLaneType(i, newType);
4836 : haveJoined = true;
4837 : } else {
4838 108 : i++;
4839 : }
4840 : }
4841 36 : return haveJoined;
4842 : }
4843 :
4844 :
4845 : EdgeVector
4846 61469 : NBEdge::filterByPermissions(const EdgeVector& edges, SVCPermissions permissions) {
4847 : EdgeVector result;
4848 264972 : for (NBEdge* edge : edges) {
4849 203503 : if ((edge->getPermissions() & permissions) != 0) {
4850 188412 : result.push_back(edge);
4851 : }
4852 : }
4853 61469 : return result;
4854 0 : }
4855 :
4856 : NBEdge*
4857 2777 : NBEdge::getStraightContinuation(SVCPermissions permissions) const {
4858 2777 : EdgeVector cands = filterByPermissions(myTo->getOutgoingEdges(), permissions);
4859 2777 : if (cands.size() == 0) {
4860 : return nullptr;
4861 : }
4862 2773 : sort(cands.begin(), cands.end(), NBContHelper::edge_similar_direction_sorter(this));
4863 2773 : NBEdge* best = cands.front();
4864 2773 : if (isTurningDirectionAt(best)) {
4865 : return nullptr;
4866 : } else {
4867 : return best;
4868 : }
4869 2777 : }
4870 :
4871 : NBEdge*
4872 124 : NBEdge::getStraightPredecessor(SVCPermissions permissions) const {
4873 124 : EdgeVector cands = filterByPermissions(myFrom->getIncomingEdges(), permissions);
4874 124 : if (cands.size() == 0) {
4875 : return nullptr;
4876 : }
4877 112 : sort(cands.begin(), cands.end(), NBContHelper::edge_similar_direction_sorter(this, false));
4878 112 : NBEdge* best = cands.front();
4879 112 : if (best->isTurningDirectionAt(this)) {
4880 : return nullptr;
4881 : } else {
4882 : return best;
4883 : }
4884 124 : }
4885 :
4886 :
4887 : NBEdge*
4888 41 : NBEdge::guessOpposite(bool reguess) {
4889 : NBEdge* opposite = nullptr;
4890 41 : if (getNumLanes() > 0) {
4891 : NBEdge::Lane& lastLane = myLanes.back();
4892 41 : const double lastWidth = getLaneWidth(getNumLanes() - 1);
4893 41 : if (lastLane.oppositeID == "" || reguess) {
4894 64 : for (NBEdge* cand : getToNode()->getOutgoingEdges()) {
4895 38 : if (cand->getToNode() == getFromNode() && !cand->getLanes().empty()) {
4896 26 : const double lastWidthCand = cand->getLaneWidth(cand->getNumLanes() - 1);
4897 : // in sharp corners, the difference may be higher
4898 : // factor (sqrt(2) for 90 degree corners
4899 26 : const double threshold = 1.42 * 0.5 * (lastWidth + lastWidthCand) + 0.5;
4900 52 : const double distance = VectorHelper<double>::maxValue(lastLane.shape.distances(cand->getLanes().back().shape));
4901 : //std::cout << " distance=" << distance << " threshold=" << threshold << " distances=" << toString(lastLane.shape.distances(cand->getLanes().back().shape)) << "\n";
4902 26 : if (distance < threshold) {
4903 : opposite = cand;
4904 : }
4905 : }
4906 : }
4907 26 : if (opposite != nullptr) {
4908 48 : lastLane.oppositeID = opposite->getLaneID(opposite->getNumLanes() - 1);
4909 : }
4910 : }
4911 : }
4912 41 : return opposite;
4913 : }
4914 :
4915 : double
4916 0 : NBEdge::getDistancAt(double pos) const {
4917 : // negative values of myDistances indicate descending kilometrage
4918 0 : return fabs(myDistance + pos);
4919 : }
4920 :
4921 : /****************************************************************************/
|