Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2026 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file NBPTStopCont.cpp
15 : /// @author Gregor Laemmel
16 : /// @date Tue, 20 Mar 2017
17 : ///
18 : // Container for pt stops during the netbuilding process
19 : /****************************************************************************/
20 : #include <config.h>
21 : #include <utils/common/MsgHandler.h>
22 : #include <utils/geom/Boundary.h>
23 : #include <utils/geom/Position.h>
24 : #include <utils/options/OptionsCont.h>
25 : #include <microsim/MSLane.h>
26 : #include "NBEdgeCont.h"
27 : #include "NBEdge.h"
28 : #include "NBNode.h"
29 : #include "NBPTPlatform.h"
30 : #include "NBPTStop.h"
31 : #include "NBPTStopCont.h"
32 :
33 :
34 : // ===========================================================================
35 : // static members
36 : // ===========================================================================
37 : std::set<std::string> NBPTStopCont::myIgnoredStops;
38 :
39 :
40 : // ===========================================================================
41 : // method definitions
42 : // ===========================================================================
43 2141 : NBPTStopCont::~NBPTStopCont() {
44 : myPTStops.clear();
45 2141 : }
46 :
47 :
48 : bool
49 2191 : NBPTStopCont::insert(std::shared_ptr<NBPTStop> ptStop, bool floating) {
50 2191 : std::string id = ptStop->getID();
51 : auto i = myPTStops.find(id);
52 2191 : if (i != myPTStops.end()) {
53 : return false;
54 : }
55 2145 : myPTStops[id] = ptStop;
56 2145 : if (floating) {
57 139 : myFloatingStops.push_back(ptStop);
58 : }
59 : return true;
60 : }
61 :
62 :
63 : std::shared_ptr<NBPTStop>
64 10126 : NBPTStopCont::get(std::string id) const {
65 10126 : if (myPTStops.find(id) != myPTStops.end()) {
66 : return myPTStops.find(id)->second;
67 : }
68 : return nullptr;
69 : }
70 :
71 :
72 : void
73 121 : NBPTStopCont::localizePTStops(NBEdgeCont& cont) {
74 : std::vector<std::shared_ptr<NBPTStop> > reverseStops;
75 : //first pass localize pt stop at correct side of the street; create stop for opposite side if needed
76 1285 : for (const auto& ptStopIt : myPTStops) {
77 : std::shared_ptr<NBPTStop> const stop = ptStopIt.second;
78 1164 : bool multipleStopPositions = stop->getIsMultipleStopPositions();
79 1164 : bool platformsDefined = !stop->getPlatformCands().empty();
80 1164 : if (!platformsDefined) {
81 : //create pt stop for reverse edge if edge exists
82 1754 : std::shared_ptr<NBPTStop> reverseStop = getReverseStop(stop, cont);
83 877 : if (reverseStop != nullptr) {
84 212 : reverseStops.push_back(reverseStop);
85 : }
86 287 : } else if (multipleStopPositions) {
87 : //create pt stop for closest platform at corresponding edge
88 540 : assignPTStopToEdgeOfClosestPlatform(stop, cont);
89 : } else {
90 : //create pt stop for each side of the street where a platform is defined (create additional pt stop as needed)
91 34 : std::shared_ptr<NBPTStop> additionalStop = assignAndCreatNewPTStopAsNeeded(stop, cont);
92 17 : if (additionalStop != nullptr) {
93 0 : reverseStops.push_back(additionalStop);
94 : }
95 : }
96 : }
97 : //insert new stops if any
98 333 : for (std::shared_ptr<NBPTStop>& reverseStop : reverseStops) {
99 424 : insert(reverseStop);
100 : }
101 121 : }
102 :
103 :
104 : void
105 337 : NBPTStopCont::assignLanes(NBEdgeCont& cont) {
106 : //scnd pass set correct lane
107 4145 : for (auto i = myPTStops.begin(); i != myPTStops.end();) {
108 : std::shared_ptr<NBPTStop> stop = i->second;
109 3808 : if (!stop->findLaneAndComputeBusStopExtent(cont)) {
110 6 : WRITE_WARNINGF(TL("Could not find corresponding edge or compatible lane for pt stop '%' (%). Thus, it will be removed!"),
111 : i->first, i->second->getName());
112 : //EdgeVector edgeVector = cont.getGeneratedFrom((*i).second->getOrigEdgeId());
113 : //std::cout << edgeVector.size() << std::endl;
114 : myPTStops.erase(i++);
115 : } else {
116 : i++;
117 : }
118 : }
119 337 : }
120 :
121 :
122 : int
123 160 : NBPTStopCont::generateBidiStops(NBEdgeCont& ec) {
124 : int existingBidiStops = 0;
125 : std::vector<std::shared_ptr<NBPTStop> > toAdd;
126 2082 : for (auto i = myPTStops.begin(); i != myPTStops.end(); i++) {
127 : std::shared_ptr<NBPTStop> stop = i->second;
128 1922 : NBEdge* edge = ec.getByID(stop->getEdgeId());
129 1922 : if (edge != nullptr && edge->isBidiRail()) {
130 337 : NBEdge* bidiEdge = edge->getTurnDestination(true);
131 : assert(bidiEdge != 0);
132 674 : const std::string id = getReverseID(stop->getID());
133 230 : if (myPTStops.count(id) > 0) {
134 230 : if (myPTStops[id]->getEdgeId() != bidiEdge->getID()) {
135 0 : WRITE_WARNINGF(TL("Could not create reverse-direction stop for superposed edge '%' (origStop '%'). Stop id '%' already in use by stop on edge '%'."),
136 : bidiEdge->getID(), i->first, id, myPTStops[id]->getEdgeId());
137 : } else {
138 230 : existingBidiStops++;
139 : }
140 : continue;
141 : }
142 107 : std::shared_ptr<NBPTStop> bidiStop = std::make_shared<NBPTStop>(stop->getElement(), id,
143 : stop->getPosition(),
144 107 : bidiEdge->getID(),
145 214 : stop->getOrigEdgeId(),
146 214 : stop->getLength(),
147 214 : stop->getName(),
148 321 : stop->getPermissions());
149 107 : if (bidiStop->findLaneAndComputeBusStopExtent(ec)) {
150 107 : toAdd.push_back(bidiStop);
151 107 : stop->setBidiStop(bidiStop);
152 107 : bidiStop->setBidiStop(stop);
153 : } else {
154 : // should not happen
155 : assert(false);
156 : }
157 1585 : } else if (edge != nullptr) {
158 1475 : NBEdge* bidiEdge = edge->getTurnDestination(true);
159 1475 : if (bidiEdge != nullptr) {
160 1380 : const std::string id = getReverseID(stop->getID());
161 : if (myPTStops.count(id) > 0) {
162 335 : existingBidiStops++;
163 : }
164 : }
165 : }
166 : }
167 267 : for (std::shared_ptr<NBPTStop> newStop : toAdd) {
168 214 : myPTStops[newStop->getID()] = newStop;
169 : }
170 160 : if (toAdd.size() > 0) {
171 22 : WRITE_MESSAGEF(TL("Added % stops for superposed rail edges."), toString(toAdd.size()));
172 : }
173 160 : return (int)toAdd.size() + existingBidiStops;
174 160 : }
175 :
176 :
177 : int
178 4 : NBPTStopCont::countBidiStops(NBEdgeCont& ec) const {
179 : int existingBidiStops = 0;
180 32 : for (auto item : myPTStops) {
181 : auto stop = item.second;
182 28 : NBEdge* edge = ec.getByID(stop->getEdgeId());
183 28 : if (edge != nullptr && edge->isBidiRail()) {
184 24 : NBEdge* bidiEdge = edge->getTurnDestination(true);
185 : assert(bidiEdge != 0);
186 48 : const std::string id = getReverseID(stop->getID());
187 : // @note loaded pairs of bidi-stops might have arbitrary ids and we should rather search through all stops on bidiEdge
188 : auto it = myPTStops.find(id);
189 24 : if (it != myPTStops.end() && it->second->getEdgeId() == bidiEdge->getID()) {
190 20 : existingBidiStops++;
191 : }
192 : }
193 28 : }
194 4 : return existingBidiStops;
195 : }
196 :
197 :
198 : std::shared_ptr<NBPTStop>
199 1006 : NBPTStopCont::getReverseStop(std::shared_ptr<NBPTStop> pStop, const NBEdgeCont& ec) {
200 1006 : std::string edgeId = pStop->getEdgeId();
201 1006 : NBEdge* edge = ec.getByID(edgeId);
202 1006 : NBEdge* reverse = NBPTStopCont::getReverseEdge(edge);
203 1006 : if (reverse != nullptr) {
204 662 : const std::string reverseID = getReverseID(pStop->getID());
205 : if (myPTStops.count(reverseID) == 0) {
206 570 : return std::make_shared<NBPTStop>(pStop->getElement(), reverseID, pStop->getPosition(), reverse->getID(), reverse->getID(),
207 855 : pStop->getLength(), pStop->getName(), pStop->getPermissions());
208 : } else {
209 46 : return myPTStops[reverseID];
210 : }
211 : }
212 : return nullptr;
213 : }
214 :
215 :
216 : std::shared_ptr<NBPTStop>
217 17 : NBPTStopCont::assignAndCreatNewPTStopAsNeeded(std::shared_ptr<NBPTStop> pStop, NBEdgeCont& cont) {
218 17 : std::string edgeId = pStop->getEdgeId();
219 17 : NBEdge* edge = cont.getByID(edgeId);
220 17 : if (edge == nullptr) {
221 : return nullptr;
222 : }
223 : bool rightOfEdge = false;
224 : bool leftOfEdge = false;
225 : const NBPTPlatform* left = nullptr;
226 33 : for (const NBPTPlatform& platform : pStop->getPlatformCands()) {
227 17 : double crossProd = computeCrossProductEdgePosition(edge, platform.getPos());
228 : //TODO consider driving on the left!!! [GL May '17]
229 17 : if (crossProd > 0) {
230 : leftOfEdge = true;
231 : left = &platform;
232 : } else {
233 : rightOfEdge = true;
234 16 : pStop->setPTStopLength(platform.getLength());
235 : }
236 : }
237 :
238 16 : if (leftOfEdge && rightOfEdge) {
239 2 : std::shared_ptr<NBPTStop> leftStop = getReverseStop(pStop, cont);
240 1 : if (leftStop) {
241 0 : leftStop->setPTStopLength(left->getLength());
242 : }
243 : return leftStop;
244 15 : } else if (leftOfEdge) {
245 0 : NBEdge* reverse = getReverseEdge(edge);
246 0 : if (reverse != nullptr) {
247 0 : pStop->setEdgeId(reverse->getID(), cont);
248 0 : pStop->setPTStopLength(left->getLength());
249 : }
250 : }
251 :
252 : return nullptr;
253 : }
254 :
255 :
256 : void
257 270 : NBPTStopCont::assignPTStopToEdgeOfClosestPlatform(std::shared_ptr<NBPTStop> pStop, NBEdgeCont& cont) {
258 270 : std::string edgeId = pStop->getEdgeId();
259 270 : NBEdge* edge = cont.getByID(edgeId);
260 270 : NBEdge* reverse = NBPTStopCont::getReverseEdge(edge);
261 540 : const NBPTPlatform* closestPlatform = getClosestPlatformToPTStopPosition(pStop);
262 270 : pStop->setPTStopLength(closestPlatform->getLength());
263 270 : if (reverse != nullptr) {
264 :
265 : //TODO make isLeft in PositionVector static [GL May '17]
266 : // if (PositionVector::isLeft(edge->getFromNode()->getPosition(),edge->getToNode()->getPosition(),closestPlatform)){
267 : //
268 : // }
269 99 : double crossProd = computeCrossProductEdgePosition(edge, closestPlatform->getPos());
270 :
271 : //TODO consider driving on the left!!! [GL May '17]
272 99 : if (crossProd > 0) { //pt stop is on the left of the orig edge
273 123 : pStop->setEdgeId(reverse->getID(), cont);
274 : }
275 : }
276 270 : }
277 :
278 :
279 : double
280 116 : NBPTStopCont::computeCrossProductEdgePosition(const NBEdge* edge, const Position& closestPlatform) const {
281 : PositionVector geom = edge->getGeometry();
282 116 : int idxTmp = geom.indexOfClosest(closestPlatform);
283 116 : double offset = geom.nearest_offset_to_point2D(closestPlatform, true);
284 116 : double offset2 = geom.offsetAtIndex2D(idxTmp);
285 : int idx1, idx2;
286 116 : if (offset2 < offset) {
287 : idx1 = idxTmp;
288 41 : idx2 = idx1 + 1;
289 : } else {
290 : idx2 = idxTmp;
291 75 : idx1 = idxTmp - 1;
292 : }
293 116 : if (idx1 < 0 || idx1 >= (int) geom.size() || idx2 < 0 || idx2 >= (int) geom.size()) {
294 63 : WRITE_WARNINGF(TL("Could not determine cross product for edge '%'."), edge->getID());
295 21 : return 0;
296 : }
297 95 : Position p1 = geom[idx1];
298 95 : Position p2 = geom[idx2];
299 :
300 : double x0 = p1.x();
301 : double y0 = p1.y();
302 : double x1 = p2.x();
303 : double y1 = p2.y();
304 : double x2 = closestPlatform.x();
305 : double y2 = closestPlatform.y();
306 95 : double crossProd = (x1 - x0) * (y2 - y0) - (y1 - y0) * (x2 - x0);
307 95 : return crossProd;
308 116 : }
309 :
310 :
311 : const NBPTPlatform*
312 270 : NBPTStopCont::getClosestPlatformToPTStopPosition(std::shared_ptr<NBPTStop> pStop) {
313 270 : Position stopPosition = pStop->getPosition();
314 : const NBPTPlatform* closest = nullptr;
315 : double minSqrDist = std::numeric_limits<double>::max();
316 999 : for (const NBPTPlatform& platform : pStop->getPlatformCands()) {
317 729 : double sqrDist = stopPosition.distanceSquaredTo2D(platform.getPos());
318 729 : if (sqrDist < minSqrDist) {
319 : minSqrDist = sqrDist;
320 : closest = &platform;
321 : }
322 : }
323 270 : return closest;
324 : }
325 :
326 : //static functions
327 :
328 : NBEdge*
329 1533 : NBPTStopCont::getReverseEdge(NBEdge* edge) {
330 1533 : if (edge != nullptr) {
331 1343 : const PositionVector rGeom = edge->getGeometry().reverse();
332 1343 : for (auto it = edge->getToNode()->getOutgoingEdges().begin();
333 2388 : it != edge->getToNode()->getOutgoingEdges().end();
334 : it++) {
335 1654 : if ((*it)->getToNode() == edge->getFromNode() && (*it)->getGeometry() == rGeom) {
336 609 : return (*it);
337 : }
338 : }
339 1343 : }
340 : return nullptr;
341 : }
342 :
343 :
344 : int
345 2024 : NBPTStopCont::cleanupDeleted(NBEdgeCont& cont) {
346 : int numDeleted = 0;
347 5381 : for (auto i = myPTStops.begin(); i != myPTStops.end();) {
348 3357 : if (cont.getByID(i->second->getEdgeId()) == nullptr) {
349 522 : WRITE_WARNINGF(TL("Removing pt stop '%' on non existing edge '%'."), i->first, i->second->getEdgeId());
350 : i = myPTStops.erase(i);
351 174 : numDeleted++;
352 : } else {
353 : i++;
354 : }
355 : }
356 2024 : return numDeleted;
357 : }
358 :
359 :
360 : void
361 1754 : NBPTStopCont::addEdges2Keep(const OptionsCont& /* oc */, std::set<std::string>& into) {
362 3716 : for (auto stop : myPTStops) {
363 1962 : into.insert(stop.second->getEdgeId());
364 1962 : }
365 1754 : }
366 :
367 :
368 : void
369 5570 : NBPTStopCont::replaceEdge(const std::string& edgeID, const EdgeVector& replacement) {
370 5570 : if (myPTStops.size() > 0 && myPTStopLookup.size() == 0) {
371 : // init lookup once
372 1179 : for (auto& item : myPTStops) {
373 1124 : myPTStopLookup[item.second->getEdgeId()].push_back(item.second);
374 : }
375 : }
376 : // make a copy because the vector gets modified
377 5570 : const std::vector<std::shared_ptr<NBPTStop> > stops = myPTStopLookup[edgeID];
378 6043 : for (std::shared_ptr<NBPTStop> stop : stops) {
379 473 : if (!stop->replaceEdge(edgeID, replacement)) {
380 0 : WRITE_WARNINGF(TL("Could not re-assign pt stop '%' after replacing edge '%'."), stop->getID(), edgeID);
381 : } else {
382 473 : myPTStopLookup[stop->getEdgeId()].push_back(stop);
383 : }
384 : }
385 : myPTStopLookup.erase(edgeID);
386 5570 : }
387 :
388 :
389 : void
390 4 : NBPTStopCont::postprocess(std::set<std::string>& usedStops) {
391 192 : for (auto i = myPTStops.begin(); i != myPTStops.end();) {
392 376 : if (usedStops.find(i->second->getID()) == usedStops.end()) {
393 : myPTStops.erase(i++);
394 : } else {
395 : i++;
396 : }
397 : }
398 4 : }
399 :
400 : std::string
401 1544 : NBPTStopCont::getReverseID(const std::string& id) {
402 1544 : return id.size() > 0 && id[0] == '-' ? id.substr(1) : "-" + id;
403 : }
404 :
405 : void
406 160 : NBPTStopCont::alignIdSigns() {
407 : PTStopsCont stops = myPTStops;
408 2024 : for (auto& i : stops) {
409 : std::shared_ptr<NBPTStop> s = i.second;
410 1864 : const std::string& stopId = s->getID();
411 1864 : if (s->getEdgeId() == "" || s->wasLoaded()) {
412 186 : continue;
413 : }
414 3356 : const char edgeSign = s->getEdgeId().at(0);
415 1678 : const char stopSign = stopId.at(0);
416 1678 : if (edgeSign != stopSign && (edgeSign == '-' || stopSign == '-')) {
417 162 : const std::string reverseID = getReverseID(stopId);
418 324 : std::shared_ptr<NBPTStop> rs = get(reverseID);
419 162 : if (rs != nullptr && rs->wasLoaded()) {
420 : continue;
421 : }
422 160 : s->setPTStopId(reverseID);
423 : myPTStops.erase(stopId);
424 160 : myPTStops[reverseID] = s;
425 160 : if (rs != nullptr) {
426 0 : rs->setPTStopId(stopId);
427 55 : myPTStops[stopId] = rs;
428 : }
429 : }
430 : }
431 160 : }
432 :
433 : void
434 173 : NBPTStopCont::assignEdgeForFloatingStops(NBEdgeCont& cont, double maxRadius) {
435 : NamedRTree r;
436 : SVCPermissions publicPermissions = SVC_BUS | SVC_TRAM | SVC_RAIL | SVC_RAIL_URBAN | SVC_TAXI;
437 40394 : for (const auto& item : cont) {
438 40221 : NBEdge* edge = item.second;
439 40221 : if ((edge->getPermissions() & publicPermissions) == 0) {
440 18808 : continue;
441 : }
442 21413 : const Boundary& bound = edge->getGeometry().getBoxBoundary();
443 21413 : float min[2] = { static_cast<float>(bound.xmin()), static_cast<float>(bound.ymin()) };
444 21413 : float max[2] = { static_cast<float>(bound.xmax()), static_cast<float>(bound.ymax()) };
445 42826 : r.Insert(min, max, edge);
446 : }
447 312 : for (std::shared_ptr<NBPTStop> ptStop : myFloatingStops) {
448 : std::set<const Named*> edges;
449 : Named::StoringVisitor visitor(edges);
450 139 : const Position& pos = ptStop->getPosition();
451 139 : float min[2] = {static_cast<float>(pos.x() - maxRadius), static_cast<float>(pos.y() - maxRadius)};
452 139 : float max[2] = {static_cast<float>(pos.x() + maxRadius), static_cast<float>(pos.y() + maxRadius)};
453 : r.Search(min, max, visitor);
454 : std::vector<NBEdge*> nearby;
455 304 : for (const Named* namedEdge : edges) {
456 165 : NBEdge* e = const_cast<NBEdge*>(dynamic_cast<const NBEdge*>(namedEdge));
457 165 : if ((e->getPermissions() & ptStop->getPermissions()) != 0) {
458 81 : nearby.push_back(e);
459 : }
460 : }
461 278 : std::sort(nearby.begin(), nearby.end(), [pos](NBEdge * a, NBEdge * b) {
462 148 : return a->getLaneShape(0).distance2D(pos, false) < b->getLaneShape(0).distance2D(pos, false);
463 : });
464 :
465 139 : for (NBEdge* e : nearby) {
466 60 : ptStop->setEdgeId(e->getID(), cont);
467 20 : if (ptStop->getLaneId() != "") {
468 : break;
469 : }
470 : }
471 139 : if (ptStop->getLaneId() == "") {
472 238 : WRITE_WARNINGF(TL("Could not find corresponding edge or compatible lane for free-floating pt stop '%' (%). Thus, it will be removed!"),
473 : ptStop->getID(), ptStop->getName());
474 238 : myPTStops.erase(ptStop->getID());
475 : }
476 139 : }
477 173 : }
478 :
479 : void
480 164 : NBPTStopCont::findAccessEdgesForRailStops(NBEdgeCont& cont, double maxRadius, int maxCount, double accessFactor) {
481 : NamedRTree r;
482 33363 : for (auto edge : cont) {
483 33199 : const Boundary& bound = edge.second->getGeometry().getBoxBoundary();
484 33199 : float min[2] = { static_cast<float>(bound.xmin()), static_cast<float>(bound.ymin()) };
485 33199 : float max[2] = { static_cast<float>(bound.xmax()), static_cast<float>(bound.ymax()) };
486 66398 : r.Insert(min, max, edge.second);
487 : }
488 2221 : for (auto& ptStop : myPTStops) {
489 2057 : const std::string& stopEdgeID = ptStop.second->getEdgeId();
490 2057 : NBEdge* stopEdge = cont.getByID(stopEdgeID);
491 : //std::cout << "findAccessEdgesForRailStops edge=" << stopEdgeID << " exists=" << (stopEdge != 0) << "\n";
492 2057 : if (stopEdge != nullptr && (stopEdge->getPermissions() & SVC_PEDESTRIAN) == 0) {
493 : //if (stopEdge != 0 && isRailway(stopEdge->getPermissions())) {
494 : std::set<const Named*> edges;
495 : Named::StoringVisitor visitor(edges);
496 1141 : const Position& pos = ptStop.second->getPosition();
497 1141 : float min[2] = {static_cast<float>(pos.x() - maxRadius), static_cast<float>(pos.y() - maxRadius)};
498 1141 : float max[2] = {static_cast<float>(pos.x() + maxRadius), static_cast<float>(pos.y() + maxRadius)};
499 : r.Search(min, max, visitor);
500 : std::vector<NBEdge*> edgCants;
501 107492 : for (const Named* namedEdge : edges) {
502 106351 : NBEdge* e = const_cast<NBEdge*>(dynamic_cast<const NBEdge*>(namedEdge));
503 106351 : edgCants.push_back(e);
504 : }
505 2282 : std::sort(edgCants.begin(), edgCants.end(), [pos](NBEdge * a, NBEdge * b) {
506 978331 : return a->getLaneShape(0).distance2D(pos, false) < b->getLaneShape(0).distance2D(pos, false);
507 : });
508 : int cnt = 0;
509 12722 : for (auto edge : edgCants) {
510 : int laneIdx = 0;
511 23085 : for (auto lane : edge->getLanes()) {
512 13764 : if ((lane.permissions & SVC_PEDESTRIAN) != 0) {
513 2806 : double offset = lane.shape.nearest_offset_to_point2D(pos, false);
514 2806 : double finalLength = edge->getFinalLength();
515 2806 : double laneLength = lane.shape.length();
516 2806 : double accessLength = pos.distanceTo2D(lane.shape.positionAtOffset2D(offset)) * accessFactor;
517 2806 : ptStop.second->addAccess(edge->getLaneID(laneIdx), offset * finalLength / laneLength, accessLength);
518 2806 : cnt++;
519 : break;
520 : }
521 10958 : laneIdx++;
522 13764 : }
523 12127 : if (cnt == maxCount) {
524 : break;
525 : }
526 : }
527 1141 : }
528 : }
529 164 : }
530 :
531 :
532 : std::shared_ptr<NBPTStop>
533 5 : NBPTStopCont::findStop(const std::string& origEdgeID, Position pos, double threshold) const {
534 123 : for (auto& item : myPTStops) {
535 245 : if (item.second->getOrigEdgeId() == origEdgeID &&
536 5 : item.second->getPosition().distanceTo2D(pos) < threshold) {
537 : return item.second;
538 : }
539 : }
540 : return nullptr;
541 : }
542 :
543 :
544 : /****************************************************************************/
|