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