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