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 2483 : NBPTStopCont::~NBPTStopCont() {
44 : myPTStops.clear();
45 2483 : }
46 :
47 :
48 : bool
49 2189 : NBPTStopCont::insert(std::shared_ptr<NBPTStop> ptStop, bool floating) {
50 2189 : std::string id = ptStop->getID();
51 : auto i = myPTStops.find(id);
52 2189 : 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 10184 : NBPTStopCont::get(std::string id) const {
65 10184 : if (myPTStops.find(id) != myPTStops.end()) {
66 : return myPTStops.find(id)->second;
67 : }
68 : return nullptr;
69 : }
70 :
71 :
72 : void
73 124 : 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 1293 : for (const auto& ptStopIt : myPTStops) {
77 : std::shared_ptr<NBPTStop> const stop = ptStopIt.second;
78 1169 : bool multipleStopPositions = stop->getIsMultipleStopPositions();
79 1169 : bool platformsDefined = !stop->getPlatformCands().empty();
80 1169 : if (!platformsDefined) {
81 : //create pt stop for reverse edge if edge exists
82 1764 : std::shared_ptr<NBPTStop> reverseStop = getReverseStop(stop, cont);
83 882 : if (reverseStop != nullptr) {
84 210 : 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 334 : for (std::shared_ptr<NBPTStop>& reverseStop : reverseStops) {
99 420 : insert(reverseStop);
100 : }
101 124 : }
102 :
103 :
104 : void
105 343 : NBPTStopCont::assignLanes(NBEdgeCont& cont) {
106 : //scnd pass set correct lane
107 4152 : for (auto i = myPTStops.begin(); i != myPTStops.end();) {
108 : std::shared_ptr<NBPTStop> stop = i->second;
109 3809 : 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 343 : }
120 :
121 :
122 : int
123 163 : NBPTStopCont::generateBidiStops(NBEdgeCont& ec) {
124 : int existingBidiStops = 0;
125 : std::vector<std::shared_ptr<NBPTStop> > toAdd;
126 2083 : for (auto i = myPTStops.begin(); i != myPTStops.end(); i++) {
127 : std::shared_ptr<NBPTStop> stop = i->second;
128 1920 : NBEdge* edge = ec.getByID(stop->getEdgeId());
129 1920 : if (edge != nullptr && edge->isBidiRail()) {
130 329 : NBEdge* bidiEdge = edge->getTurnDestination(true);
131 : assert(bidiEdge != 0);
132 658 : const std::string id = getReverseID(stop->getID());
133 222 : if (myPTStops.count(id) > 0) {
134 222 : 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 222 : 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 1591 : } else if (edge != nullptr) {
158 1481 : NBEdge* bidiEdge = edge->getTurnDestination(true);
159 1481 : if (bidiEdge != nullptr) {
160 1374 : const std::string id = getReverseID(stop->getID());
161 : if (myPTStops.count(id) > 0) {
162 329 : existingBidiStops++;
163 : }
164 : }
165 : }
166 : }
167 270 : for (std::shared_ptr<NBPTStop> newStop : toAdd) {
168 214 : myPTStops[newStop->getID()] = newStop;
169 : }
170 163 : if (toAdd.size() > 0) {
171 24 : WRITE_MESSAGEF(TL("Added % stops for superposed rail edges."), toString(toAdd.size()));
172 : }
173 163 : return (int)toAdd.size() + existingBidiStops;
174 163 : }
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 1009 : NBPTStopCont::getReverseStop(std::shared_ptr<NBPTStop> pStop, const NBEdgeCont& ec) {
200 1009 : std::string edgeId = pStop->getEdgeId();
201 1009 : NBEdge* edge = ec.getByID(edgeId);
202 1009 : NBEdge* reverse = NBPTStopCont::getReverseEdge(edge);
203 1009 : if (reverse != nullptr) {
204 644 : const std::string reverseID = getReverseID(pStop->getID());
205 : if (myPTStops.count(reverseID) == 0) {
206 556 : std::shared_ptr<NBPTStop> result = std::make_shared<NBPTStop>(pStop->getElement(), reverseID, pStop->getPosition(), reverse->getID(), reverse->getID(),
207 834 : pStop->getLength(), pStop->getName(), pStop->getPermissions());
208 373 : for (const std::string& line : pStop->getLines()) {
209 95 : result->addLine(line);
210 : }
211 : return result;
212 : } else {
213 44 : return myPTStops[reverseID];
214 : }
215 : }
216 : return nullptr;
217 : }
218 :
219 :
220 : std::shared_ptr<NBPTStop>
221 17 : NBPTStopCont::assignAndCreatNewPTStopAsNeeded(std::shared_ptr<NBPTStop> pStop, NBEdgeCont& cont) {
222 17 : std::string edgeId = pStop->getEdgeId();
223 17 : NBEdge* edge = cont.getByID(edgeId);
224 17 : if (edge == nullptr) {
225 : return nullptr;
226 : }
227 : bool rightOfEdge = false;
228 : bool leftOfEdge = false;
229 : const NBPTPlatform* left = nullptr;
230 33 : for (const NBPTPlatform& platform : pStop->getPlatformCands()) {
231 17 : double crossProd = computeCrossProductEdgePosition(edge, platform.getPos());
232 : //TODO consider driving on the left!!! [GL May '17]
233 17 : if (crossProd > 0) {
234 : leftOfEdge = true;
235 : left = &platform;
236 : } else {
237 : rightOfEdge = true;
238 16 : pStop->setPTStopLength(platform.getLength());
239 : }
240 : }
241 :
242 16 : if (leftOfEdge && rightOfEdge) {
243 2 : std::shared_ptr<NBPTStop> leftStop = getReverseStop(pStop, cont);
244 1 : if (leftStop) {
245 0 : leftStop->setPTStopLength(left->getLength());
246 : }
247 : return leftStop;
248 15 : } else if (leftOfEdge) {
249 0 : NBEdge* reverse = getReverseEdge(edge);
250 0 : if (reverse != nullptr) {
251 0 : pStop->setEdgeId(reverse->getID(), cont);
252 0 : pStop->setPTStopLength(left->getLength());
253 : }
254 : }
255 :
256 : return nullptr;
257 : }
258 :
259 :
260 : void
261 270 : NBPTStopCont::assignPTStopToEdgeOfClosestPlatform(std::shared_ptr<NBPTStop> pStop, NBEdgeCont& cont) {
262 270 : std::string edgeId = pStop->getEdgeId();
263 270 : NBEdge* edge = cont.getByID(edgeId);
264 270 : NBEdge* reverse = NBPTStopCont::getReverseEdge(edge);
265 540 : const NBPTPlatform* closestPlatform = getClosestPlatformToPTStopPosition(pStop);
266 270 : pStop->setPTStopLength(closestPlatform->getLength());
267 270 : if (reverse != nullptr) {
268 :
269 : //TODO make isLeft in PositionVector static [GL May '17]
270 : // if (PositionVector::isLeft(edge->getFromNode()->getPosition(),edge->getToNode()->getPosition(),closestPlatform)){
271 : //
272 : // }
273 99 : double crossProd = computeCrossProductEdgePosition(edge, closestPlatform->getPos());
274 :
275 : //TODO consider driving on the left!!! [GL May '17]
276 99 : if (crossProd > 0) { //pt stop is on the left of the orig edge
277 123 : pStop->setEdgeId(reverse->getID(), cont);
278 : }
279 : }
280 270 : }
281 :
282 :
283 : double
284 116 : NBPTStopCont::computeCrossProductEdgePosition(const NBEdge* edge, const Position& closestPlatform) const {
285 : PositionVector geom = edge->getGeometry();
286 116 : int idxTmp = geom.indexOfClosest(closestPlatform);
287 116 : double offset = geom.nearest_offset_to_point2D(closestPlatform, true);
288 116 : double offset2 = geom.offsetAtIndex2D(idxTmp);
289 : int idx1, idx2;
290 116 : if (offset2 < offset) {
291 : idx1 = idxTmp;
292 41 : idx2 = idx1 + 1;
293 : } else {
294 : idx2 = idxTmp;
295 75 : idx1 = idxTmp - 1;
296 : }
297 116 : if (idx1 < 0 || idx1 >= (int) geom.size() || idx2 < 0 || idx2 >= (int) geom.size()) {
298 63 : WRITE_WARNINGF(TL("Could not determine cross product for edge '%'."), edge->getID());
299 21 : return 0;
300 : }
301 95 : Position p1 = geom[idx1];
302 95 : Position p2 = geom[idx2];
303 :
304 : double x0 = p1.x();
305 : double y0 = p1.y();
306 : double x1 = p2.x();
307 : double y1 = p2.y();
308 : double x2 = closestPlatform.x();
309 : double y2 = closestPlatform.y();
310 95 : double crossProd = (x1 - x0) * (y2 - y0) - (y1 - y0) * (x2 - x0);
311 95 : return crossProd;
312 116 : }
313 :
314 :
315 : const NBPTPlatform*
316 270 : NBPTStopCont::getClosestPlatformToPTStopPosition(std::shared_ptr<NBPTStop> pStop) {
317 270 : Position stopPosition = pStop->getPosition();
318 : const NBPTPlatform* closest = nullptr;
319 : double minSqrDist = std::numeric_limits<double>::max();
320 999 : for (const NBPTPlatform& platform : pStop->getPlatformCands()) {
321 729 : double sqrDist = stopPosition.distanceSquaredTo2D(platform.getPos());
322 729 : if (sqrDist < minSqrDist) {
323 : minSqrDist = sqrDist;
324 : closest = &platform;
325 : }
326 : }
327 270 : return closest;
328 : }
329 :
330 : //static functions
331 :
332 : NBEdge*
333 1536 : NBPTStopCont::getReverseEdge(NBEdge* edge) {
334 1536 : if (edge != nullptr) {
335 1346 : const PositionVector rGeom = edge->getGeometry().reverse();
336 1346 : for (auto it = edge->getToNode()->getOutgoingEdges().begin();
337 2396 : it != edge->getToNode()->getOutgoingEdges().end();
338 : it++) {
339 1644 : if ((*it)->getToNode() == edge->getFromNode() && (*it)->getGeometry() == rGeom) {
340 594 : return (*it);
341 : }
342 : }
343 1346 : }
344 : return nullptr;
345 : }
346 :
347 :
348 : int
349 2690 : NBPTStopCont::cleanupDeleted(NBEdgeCont& cont) {
350 : int numDeleted = 0;
351 6050 : for (auto i = myPTStops.begin(); i != myPTStops.end();) {
352 3360 : if (cont.getByID(i->second->getEdgeId()) == nullptr) {
353 528 : WRITE_WARNINGF(TL("Removing pt stop '%' on non existing edge '%'."), i->first, i->second->getEdgeId());
354 : i = myPTStops.erase(i);
355 176 : numDeleted++;
356 : } else {
357 : i++;
358 : }
359 : }
360 2690 : return numDeleted;
361 : }
362 :
363 :
364 : void
365 2096 : NBPTStopCont::addEdges2Keep(const OptionsCont& /* oc */, std::set<std::string>& into) {
366 4056 : for (auto stop : myPTStops) {
367 1960 : into.insert(stop.second->getEdgeId());
368 1960 : }
369 2096 : }
370 :
371 :
372 : void
373 5566 : NBPTStopCont::replaceEdge(const std::string& edgeID, const EdgeVector& replacement) {
374 5566 : if (myPTStops.size() > 0 && myPTStopLookup.size() == 0) {
375 : // init lookup once
376 1176 : for (auto& item : myPTStops) {
377 1121 : myPTStopLookup[item.second->getEdgeId()].push_back(item.second);
378 : }
379 : }
380 : // make a copy because the vector gets modified
381 5566 : const std::vector<std::shared_ptr<NBPTStop> > stops = myPTStopLookup[edgeID];
382 6039 : for (std::shared_ptr<NBPTStop> stop : stops) {
383 473 : if (!stop->replaceEdge(edgeID, replacement)) {
384 0 : WRITE_WARNINGF(TL("Could not re-assign pt stop '%' after replacing edge '%'."), stop->getID(), edgeID);
385 : } else {
386 473 : myPTStopLookup[stop->getEdgeId()].push_back(stop);
387 : }
388 : }
389 : myPTStopLookup.erase(edgeID);
390 5566 : }
391 :
392 :
393 : void
394 4 : NBPTStopCont::postprocess(std::set<std::string>& usedStops) {
395 192 : for (auto i = myPTStops.begin(); i != myPTStops.end();) {
396 376 : if (usedStops.find(i->second->getID()) == usedStops.end()) {
397 : myPTStops.erase(i++);
398 : } else {
399 : i++;
400 : }
401 : }
402 4 : }
403 :
404 : std::string
405 1525 : NBPTStopCont::getReverseID(const std::string& id) {
406 1525 : return id.size() > 0 && id[0] == '-' ? id.substr(1) : "-" + id;
407 : }
408 :
409 : void
410 163 : NBPTStopCont::alignIdSigns() {
411 : PTStopsCont stops = myPTStops;
412 2024 : for (auto& i : stops) {
413 : std::shared_ptr<NBPTStop> s = i.second;
414 1861 : const std::string& stopId = s->getID();
415 1861 : if (s->getEdgeId() == "" || s->wasLoaded()) {
416 188 : continue;
417 : }
418 3346 : const char edgeSign = s->getEdgeId().at(0);
419 1673 : const char stopSign = stopId.at(0);
420 1673 : if (edgeSign != stopSign && (edgeSign == '-' || stopSign == '-')) {
421 163 : const std::string reverseID = getReverseID(stopId);
422 326 : std::shared_ptr<NBPTStop> rs = get(reverseID);
423 163 : if (rs != nullptr && rs->wasLoaded()) {
424 : continue;
425 : }
426 160 : s->setPTStopId(reverseID);
427 : myPTStops.erase(stopId);
428 160 : myPTStops[reverseID] = s;
429 160 : if (rs != nullptr) {
430 0 : rs->setPTStopId(stopId);
431 55 : myPTStops[stopId] = rs;
432 : }
433 : }
434 : }
435 163 : }
436 :
437 : void
438 176 : NBPTStopCont::assignEdgeForFloatingStops(NBEdgeCont& cont, double maxRadius) {
439 : NamedRTree r;
440 : SVCPermissions publicPermissions = SVC_BUS | SVC_TRAM | SVC_RAIL | SVC_RAIL_URBAN | SVC_TAXI;
441 40358 : for (const auto& item : cont) {
442 40182 : NBEdge* edge = item.second;
443 40182 : if ((edge->getPermissions() & publicPermissions) == 0) {
444 18795 : continue;
445 : }
446 21387 : const Boundary& bound = edge->getGeometry().getBoxBoundary();
447 21387 : float min[2] = { static_cast<float>(bound.xmin()), static_cast<float>(bound.ymin()) };
448 21387 : float max[2] = { static_cast<float>(bound.xmax()), static_cast<float>(bound.ymax()) };
449 42774 : r.Insert(min, max, edge);
450 : }
451 315 : for (std::shared_ptr<NBPTStop> ptStop : myFloatingStops) {
452 : std::set<const Named*> edges;
453 : Named::StoringVisitor visitor(edges);
454 139 : const Position& pos = ptStop->getPosition();
455 139 : float min[2] = {static_cast<float>(pos.x() - maxRadius), static_cast<float>(pos.y() - maxRadius)};
456 139 : float max[2] = {static_cast<float>(pos.x() + maxRadius), static_cast<float>(pos.y() + maxRadius)};
457 : r.Search(min, max, visitor);
458 : std::vector<NBEdge*> nearby;
459 304 : for (const Named* namedEdge : edges) {
460 165 : NBEdge* e = const_cast<NBEdge*>(dynamic_cast<const NBEdge*>(namedEdge));
461 165 : if ((e->getPermissions() & ptStop->getPermissions()) != 0) {
462 81 : nearby.push_back(e);
463 : }
464 : }
465 278 : std::sort(nearby.begin(), nearby.end(), [pos](NBEdge * a, NBEdge * b) {
466 148 : return a->getLaneShape(0).distance2D(pos, false) < b->getLaneShape(0).distance2D(pos, false);
467 : });
468 :
469 139 : for (NBEdge* e : nearby) {
470 60 : ptStop->setEdgeId(e->getID(), cont);
471 20 : if (ptStop->getLaneId() != "") {
472 : break;
473 : }
474 : }
475 139 : if (ptStop->getLaneId() == "") {
476 238 : WRITE_WARNINGF(TL("Could not find corresponding edge or compatible lane for free-floating pt stop '%' (%). Thus, it will be removed!"),
477 : ptStop->getID(), ptStop->getName());
478 238 : myPTStops.erase(ptStop->getID());
479 : }
480 139 : }
481 176 : }
482 :
483 : void
484 167 : NBPTStopCont::findAccessEdgesForRailStops(NBEdgeCont& cont, double maxRadius, int maxCount, double accessFactor) {
485 : NamedRTree r;
486 33373 : for (auto edge : cont) {
487 33206 : const Boundary& bound = edge.second->getGeometry().getBoxBoundary();
488 33206 : float min[2] = { static_cast<float>(bound.xmin()), static_cast<float>(bound.ymin()) };
489 33206 : float max[2] = { static_cast<float>(bound.xmax()), static_cast<float>(bound.ymax()) };
490 66412 : r.Insert(min, max, edge.second);
491 : }
492 2222 : for (auto& ptStop : myPTStops) {
493 2055 : const std::string& stopEdgeID = ptStop.second->getEdgeId();
494 2055 : NBEdge* stopEdge = cont.getByID(stopEdgeID);
495 : //std::cout << "findAccessEdgesForRailStops edge=" << stopEdgeID << " exists=" << (stopEdge != 0) << "\n";
496 2055 : if (stopEdge != nullptr && (stopEdge->getPermissions() & SVC_PEDESTRIAN) == 0) {
497 : //if (stopEdge != 0 && isRailway(stopEdge->getPermissions())) {
498 : std::set<const Named*> edges;
499 : Named::StoringVisitor visitor(edges);
500 1156 : const Position& pos = ptStop.second->getPosition();
501 1156 : float min[2] = {static_cast<float>(pos.x() - maxRadius), static_cast<float>(pos.y() - maxRadius)};
502 1156 : float max[2] = {static_cast<float>(pos.x() + maxRadius), static_cast<float>(pos.y() + maxRadius)};
503 : r.Search(min, max, visitor);
504 : std::vector<NBEdge*> edgCants;
505 108227 : for (const Named* namedEdge : edges) {
506 107071 : NBEdge* e = const_cast<NBEdge*>(dynamic_cast<const NBEdge*>(namedEdge));
507 107071 : edgCants.push_back(e);
508 : }
509 2312 : std::sort(edgCants.begin(), edgCants.end(), [pos](NBEdge * a, NBEdge * b) {
510 979769 : return a->getLaneShape(0).distance2D(pos, false) < b->getLaneShape(0).distance2D(pos, false);
511 : });
512 : int cnt = 0;
513 13136 : for (auto edge : edgCants) {
514 : int laneIdx = 0;
515 23983 : for (auto lane : edge->getLanes()) {
516 14301 : if ((lane.permissions & SVC_PEDESTRIAN) != 0) {
517 2851 : double offset = lane.shape.nearest_offset_to_point2D(pos, false);
518 2851 : double finalLength = edge->getFinalLength();
519 2851 : double laneLength = lane.shape.length();
520 2851 : double accessLength = pos.distanceTo2D(lane.shape.positionAtOffset2D(offset)) * accessFactor;
521 2851 : ptStop.second->addAccess(edge->getLaneID(laneIdx), offset * finalLength / laneLength, accessLength);
522 2851 : cnt++;
523 : break;
524 : }
525 11450 : laneIdx++;
526 14301 : }
527 12533 : if (cnt == maxCount) {
528 : break;
529 : }
530 : }
531 1156 : }
532 : }
533 167 : }
534 :
535 :
536 : std::shared_ptr<NBPTStop>
537 5 : NBPTStopCont::findStop(const std::string& origEdgeID, Position pos, double threshold) const {
538 123 : for (auto& item : myPTStops) {
539 245 : if (item.second->getOrigEdgeId() == origEdgeID &&
540 5 : item.second->getPosition().distanceTo2D(pos) < threshold) {
541 : return item.second;
542 : }
543 : }
544 : return nullptr;
545 : }
546 :
547 :
548 : /****************************************************************************/
|