Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2025 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 NBPTLineCont.cpp
15 : /// @author Gregor Laemmel
16 : /// @author Nikita Cherednychek
17 : /// @date Tue, 20 Mar 2017
18 : ///
19 : // Container for NBPTLine during netbuild
20 : /****************************************************************************/
21 : #include <config.h>
22 :
23 : #include <iostream>
24 : #include <utils/common/MsgHandler.h>
25 : #include <utils/common/ToString.h>
26 : #include <utils/options/OptionsCont.h>
27 : #include <utils/router/DijkstraRouter.h>
28 : #include "NBPTLineCont.h"
29 : #include "NBPTStop.h"
30 : #include "NBEdge.h"
31 : #include "NBNode.h"
32 : #include "NBVehicle.h"
33 : #include "NBPTStopCont.h"
34 :
35 : //#define DEBUG_FIND_WAY
36 : //#define DEBUG_CONSTRUCT_ROUTE
37 :
38 : #define DEBUGLINEID ""
39 : #define DEBUGSTOPID ""
40 :
41 : // ===========================================================================
42 : // static value definitions
43 : // ===========================================================================
44 : const int NBPTLineCont::FWD(1);
45 : const int NBPTLineCont::BWD(-1);
46 :
47 :
48 : // ===========================================================================
49 : // method definitions
50 : // ===========================================================================
51 2113 : NBPTLineCont::~NBPTLineCont() {
52 3247 : for (auto& myPTLine : myPTLines) {
53 1134 : delete myPTLine.second;
54 : }
55 : myPTLines.clear();
56 2113 : }
57 :
58 :
59 : bool
60 1140 : NBPTLineCont::insert(NBPTLine* ptLine) {
61 : if (myPTLines.count(ptLine->getLineID()) == 0) {
62 1134 : myPTLines[ptLine->getLineID()] = ptLine;
63 1134 : return true;
64 : }
65 : return false;
66 : }
67 :
68 :
69 : NBPTLine*
70 17 : NBPTLineCont::retrieve(const std::string& lineID) {
71 : if (myPTLines.count(lineID) == 0) {
72 16 : return nullptr;
73 : } else {
74 1 : return myPTLines[lineID];
75 : }
76 : }
77 :
78 : void
79 136 : NBPTLineCont::process(NBEdgeCont& ec, NBPTStopCont& sc, bool routeOnly) {
80 1408 : for (auto& item : myPTLines) {
81 1272 : NBPTLine* line = item.second;
82 1272 : if (item.second->getWays().size() > 0) {
83 : // loaded from OSM rather than ptline input. We can use extra
84 : // information to reconstruct route and stops
85 1211 : constructRoute(line, ec);
86 1211 : if (!routeOnly) {
87 : // map stops to ways, using the constructed route for loose stops
88 1089 : reviseStops(line, ec, sc);
89 : }
90 : }
91 : // fix circular line if necessary
92 1272 : if (line->getStops().size() > 1
93 800 : && line->getStops().front() == line->getStops().back()
94 6 : && line->getRoute().size() > 1
95 1278 : && line->getRoute().front() != line->getRoute().back()) {
96 : // we need to duplicate either the first or the last edge depending on the stop locations
97 6 : const std::string firstStopEdge = line->getStops().front()->getEdgeId();
98 6 : const std::string lastStopEdge = line->getStops().back()->getEdgeId();
99 6 : std::vector<NBEdge*> edges = line->getRoute();
100 6 : if (firstStopEdge == edges.back()->getID()) {
101 6 : edges.insert(edges.begin(), edges.back());
102 0 : } else if (lastStopEdge == edges.front()->getID()) {
103 0 : edges.push_back(edges.front());
104 : }
105 6 : line->setEdges(edges);
106 6 : }
107 1272 : line->deleteInvalidStops(ec, sc);
108 : //line->deleteDuplicateStops();
109 : }
110 136 : }
111 :
112 :
113 : void
114 1089 : NBPTLineCont::reviseStops(NBPTLine* line, const NBEdgeCont& ec, NBPTStopCont& sc) {
115 : const std::vector<std::string>& waysIds = line->getWays();
116 1089 : if (waysIds.size() == 1 && line->getStops().size() > 1) {
117 27 : reviseSingleWayStops(line, ec, sc);
118 124 : return;
119 : }
120 1062 : if (waysIds.size() <= 1) {
121 162 : WRITE_WARNINGF(TL("Cannot revise pt stop localization for pt line '%', which consist of one way only. Ignoring!"), line->getLineID());
122 54 : return;
123 : }
124 1008 : if (line->getRoute().size() == 0) {
125 129 : WRITE_WARNINGF(TL("Cannot revise pt stop localization for pt line '%', which has no route edges. Ignoring!"), line->getLineID());
126 43 : return;
127 : }
128 965 : std::vector<std::shared_ptr<NBPTStop> > stops = line->getStops();
129 3575 : for (std::shared_ptr<NBPTStop> stop : stops) {
130 : //get the corresponding and one of the two adjacent ways
131 2610 : stop = findWay(line, stop, ec, sc);
132 2610 : if (stop == nullptr) {
133 : // warning already given
134 1 : continue;
135 : }
136 2609 : auto waysIdsIt = std::find(waysIds.begin(), waysIds.end(), stop->getOrigEdgeId());
137 2609 : if (waysIdsIt == waysIds.end()) {
138 : // warning already given
139 38 : continue;
140 : }
141 : // find directional edge (OSM ways are bidirectional)
142 2571 : const std::vector<long long int>* const way = line->getWayNodes(stop->getOrigEdgeId());
143 2571 : if (way == nullptr) {
144 0 : WRITE_WARNINGF(TL("Cannot assign stop '%' on edge '%' to pt line '%' (wayNodes not found). Ignoring!"),
145 : stop->getID(), stop->getOrigEdgeId(), line->getLineID());
146 0 : continue;
147 : }
148 :
149 : int dir;
150 : const std::vector<long long int>* wayPrev = nullptr;
151 2571 : if (waysIdsIt != waysIds.begin()) {
152 4082 : wayPrev = line->getWayNodes(*(waysIdsIt - 1));
153 : }
154 : const std::vector<long long int>* wayNext = nullptr;
155 2571 : if (waysIdsIt != (waysIds.end() - 1)) {
156 4182 : wayNext = line->getWayNodes(*(waysIdsIt + 1));
157 : }
158 2571 : if (wayPrev == nullptr && wayNext == nullptr) {
159 0 : WRITE_WARNINGF(TL("Cannot revise pt stop localization for incomplete pt line '%'. Ignoring!"), line->getLineID());
160 0 : continue;
161 : }
162 2571 : const long long int wayEnds = way->back();
163 2571 : const long long int wayBegins = way->front();
164 2571 : const long long int wayPrevEnds = wayPrev != nullptr ? wayPrev->back() : 0;
165 2041 : const long long int wayPrevBegins = wayPrev != nullptr ? wayPrev->front() : 0;
166 2571 : const long long int wayNextEnds = wayNext != nullptr ? wayNext->back() : 0;
167 2091 : const long long int wayNextBegins = wayNext != nullptr ? wayNext->front() : 0;
168 2571 : if (wayBegins == wayPrevEnds || wayBegins == wayPrevBegins || wayEnds == wayNextBegins || wayEnds == wayNextEnds) {
169 : dir = FWD;
170 464 : } else if (wayEnds == wayPrevBegins || wayEnds == wayPrevEnds || wayBegins == wayNextEnds || wayBegins == wayNextBegins) {
171 : dir = BWD;
172 : } else {
173 30 : WRITE_WARNINGF(TL("Cannot revise pt stop localization for incomplete pt line '%'. Ignoring!"), line->getLineID());
174 10 : continue;
175 : }
176 :
177 2561 : std::string edgeId = stop->getEdgeId();
178 2561 : NBEdge* current = ec.getByID(edgeId);
179 2561 : int assignedTo = edgeId.at(0) == '-' ? BWD : FWD;
180 :
181 2561 : if (dir != assignedTo) {
182 242 : NBEdge* reverse = NBPTStopCont::getReverseEdge(current);
183 242 : if (reverse == nullptr) {
184 126 : WRITE_WARNINGF(TL("Could not re-assign PT stop '%', probably broken osm file."), stop->getID());
185 : continue;
186 : }
187 179 : if (stop->getLines().size() > 0) {
188 98 : std::shared_ptr<NBPTStop> reverseStop = sc.getReverseStop(stop, ec);
189 98 : sc.insert(reverseStop);
190 147 : line->replaceStop(stop, reverseStop);
191 : stop = reverseStop;
192 : } else {
193 390 : WRITE_WARNINGF(TL("PT stop '%' has been moved to edge '%'."), stop->getID(), reverse->getID());
194 : }
195 537 : stop->setEdgeId(reverse->getID(), ec);
196 : }
197 2498 : stop->addLine(line->getRef());
198 : }
199 965 : }
200 :
201 :
202 27 : void NBPTLineCont::reviseSingleWayStops(NBPTLine* line, const NBEdgeCont& ec, NBPTStopCont& sc) {
203 : const std::vector<std::string>& waysIds = line->getWays();
204 98 : for (std::shared_ptr<NBPTStop> stop : line->getStops()) {
205 : //get the corresponding and one of the two adjacent ways
206 71 : stop = findWay(line, stop, ec, sc);
207 71 : if (stop == nullptr) {
208 : // warning already given
209 4 : continue;
210 : }
211 67 : auto waysIdsIt = std::find(waysIds.begin(), waysIds.end(), stop->getOrigEdgeId());
212 67 : if (waysIdsIt == waysIds.end()) {
213 : // warning already given
214 0 : continue;
215 : }
216 67 : stop->addLine(line->getRef());
217 : }
218 27 : }
219 :
220 :
221 : std::shared_ptr<NBPTStop>
222 2681 : NBPTLineCont::findWay(NBPTLine* line, std::shared_ptr<NBPTStop> stop, const NBEdgeCont& ec, NBPTStopCont& sc) const {
223 : const std::vector<std::string>& waysIds = line->getWays();
224 : #ifdef DEBUG_FIND_WAY
225 : if (stop->getID() == DEBUGSTOPID) {
226 : std::cout << " stop=" << stop->getID() << " line=" << line->getLineID() << " edgeID=" << stop->getEdgeId() << " origID=" << stop->getOrigEdgeId() << "\n";
227 : }
228 : #endif
229 2681 : if (stop->isLoose()) {
230 : // find closest edge in route
231 : double minDist = std::numeric_limits<double>::max();
232 : NBEdge* best = nullptr;
233 1037 : for (NBEdge* edge : line->getRoute()) {
234 967 : const double dist = edge->getLaneShape(0).distance2D(stop->getPosition());
235 967 : if (dist < minDist) {
236 : best = edge;
237 : minDist = dist;
238 : }
239 : }
240 : #ifdef DEBUG_FIND_WAY
241 : if (stop->getID() == DEBUGSTOPID) {
242 : std::cout << " best=" << Named::getIDSecure(best) << " minDist=" << minDist << " wayID=" << getWayID(best->getID())
243 : << " found=" << (std::find(waysIds.begin(), waysIds.end(), getWayID(best->getID())) != waysIds.end())
244 : << " wayIDs=" << toString(waysIds) << "\n";
245 : }
246 : #endif
247 140 : if (minDist < OptionsCont::getOptions().getFloat("ptline.match-dist")) {
248 65 : const std::string wayID = getWayID(best->getID());
249 65 : if (stop->getEdgeId() == "") {
250 90 : stop->setEdgeId(best->getID(), ec);
251 : stop->setOrigEdgeId(wayID);
252 35 : } else if (stop->getEdgeId() != best->getID()) {
253 : // stop is used by multiple lines and mapped to different edges.
254 : // check if an alternative stop already exists
255 5 : std::shared_ptr<NBPTStop> newStop = sc.findStop(wayID, stop->getPosition());
256 5 : if (newStop == nullptr) {
257 6 : newStop = std::make_shared<NBPTStop>(stop->getID() + "@" + line->getLineID(), stop->getPosition(), best->getID(), wayID, stop->getLength(), stop->getName(), stop->getPermissions());
258 9 : newStop->setEdgeId(best->getID(), ec); // trigger lane assignment
259 6 : sc.insert(newStop);
260 : }
261 15 : line->replaceStop(stop, newStop);
262 : stop = newStop;
263 : }
264 : } else {
265 20 : WRITE_WARNINGF(TL("Could not assign stop '%' to pt line '%' (closest edge '%', distance %). Ignoring!"),
266 : stop->getID(), line->getLineID(), Named::getIDSecure(best), minDist);
267 : return nullptr;
268 : }
269 : } else {
270 : // if the stop is part of an edge, find that edge among the line edges
271 : auto waysIdsIt = waysIds.begin();
272 32897 : for (; waysIdsIt != waysIds.end(); waysIdsIt++) {
273 32811 : if ((*waysIdsIt) == stop->getOrigEdgeId()) {
274 : break;
275 : }
276 : }
277 :
278 2611 : if (waysIdsIt == waysIds.end()) {
279 : // stop edge not found, try additional edges
280 109 : for (auto& edgeCand : stop->getAdditionalEdgeCandidates()) {
281 : bool found = false;
282 : waysIdsIt = waysIds.begin();
283 579 : for (; waysIdsIt != waysIds.end(); waysIdsIt++) {
284 556 : if ((*waysIdsIt) == edgeCand.first) {
285 96 : if (stop->setEdgeId(edgeCand.second, ec)) {
286 : stop->setOrigEdgeId(edgeCand.first);
287 : found = true;
288 : break;
289 : }
290 : }
291 : }
292 : if (found) {
293 : break;
294 : }
295 : }
296 86 : if (waysIdsIt == waysIds.end()) {
297 114 : WRITE_WARNINGF(TL("Cannot assign stop % on edge '%' to pt line '%'. Ignoring!"), stop->getID(), stop->getOrigEdgeId(), line->getLineID());
298 : }
299 : }
300 : }
301 : return stop;
302 : }
303 :
304 :
305 1211 : void NBPTLineCont::constructRoute(NBPTLine* pTLine, const NBEdgeCont& cont) {
306 : std::vector<NBEdge*> edges;
307 :
308 : NBNode* first = nullptr;
309 : NBNode* last = nullptr;
310 : std::vector<NBEdge*> prevWayEdges;
311 : std::vector<NBEdge*> prevWayMinusEdges;
312 : std::vector<NBEdge*> currentWayEdges;
313 : std::vector<NBEdge*> currentWayMinusEdges;
314 15293 : for (auto it3 = pTLine->getWays().begin(); it3 != pTLine->getWays().end(); it3++) {
315 :
316 : int foundForward = 0;
317 14082 : if (cont.retrieve(*it3, false) != nullptr) {
318 7091 : currentWayEdges.push_back(cont.retrieve(*it3, false));
319 : foundForward++;
320 : } else {
321 : int i = 0;
322 57582 : while (cont.retrieve(*it3 + "#" + std::to_string(i), true) != nullptr) {
323 43600 : if (cont.retrieve(*it3 + "#" + std::to_string(i), false)) {
324 43600 : currentWayEdges.push_back(cont.retrieve(*it3 + "#" + std::to_string(i), false));
325 21800 : foundForward++;
326 : }
327 21800 : i++;
328 : }
329 : }
330 :
331 : int foundReverse = 0;
332 28164 : if (cont.retrieve("-" + *it3, false) != nullptr) {
333 5014 : currentWayMinusEdges.push_back(cont.retrieve("-" + *it3, false));
334 : foundReverse++;
335 : } else {
336 : int i = 0;
337 60681 : while (cont.retrieve("-" + *it3 + "#" + std::to_string(i), true) != nullptr) {
338 25956 : if (cont.retrieve("-" + *it3 + "#" + std::to_string(i), false)) {
339 8652 : currentWayMinusEdges.insert(currentWayMinusEdges.end() - foundReverse,
340 25956 : cont.retrieve("-" + *it3 + "#" + std::to_string(i), false));
341 8652 : foundReverse++;
342 : }
343 8652 : i++;
344 : }
345 : }
346 : bool fakeMinus = false;
347 14082 : if (foundReverse == 0 && foundForward > 0 && isRailway(pTLine->getVClass())) {
348 : // rail tracks may be used in both directions and are often not tagged as such.
349 : // This can be repaired later with option --railway.topology.repair
350 5412 : currentWayMinusEdges.insert(currentWayMinusEdges.begin(), currentWayEdges.rbegin(), currentWayEdges.rbegin() + foundForward);
351 : fakeMinus = true;
352 : }
353 : #ifdef DEBUG_CONSTRUCT_ROUTE
354 : if (pTLine->getLineID() == DEBUGLINEID) {
355 : std::cout << " way=" << (*it3)
356 : << " done=" << toString(edges)
357 : << " first=" << Named::getIDSecure(first)
358 : << " last=" << Named::getIDSecure(last)
359 : << "\n +=" << toString(currentWayEdges)
360 : << "\n -=" << toString(currentWayMinusEdges)
361 : << "\n p+=" << toString(prevWayEdges)
362 : << "\n p-=" << toString(prevWayMinusEdges)
363 : << "\n";
364 : }
365 : #endif
366 14082 : if (currentWayEdges.empty()) {
367 194 : continue;
368 : }
369 13888 : if (last == currentWayEdges.front()->getFromNode() && last != nullptr) {
370 10743 : if (!prevWayEdges.empty()) {
371 882 : edges.insert(edges.end(), prevWayEdges.begin(), prevWayEdges.end());
372 : prevWayEdges.clear();
373 : prevWayMinusEdges.clear();
374 : }
375 10743 : edges.insert(edges.end(), currentWayEdges.begin(), currentWayEdges.end());
376 10743 : last = currentWayEdges.back()->getToNode();
377 3145 : } else if (last == currentWayEdges.back()->getToNode() && last != nullptr) {
378 1656 : if (!prevWayEdges.empty()) {
379 61 : edges.insert(edges.end(), prevWayEdges.begin(), prevWayEdges.end());
380 : prevWayEdges.clear();
381 : prevWayMinusEdges.clear();
382 : }
383 1656 : if (currentWayMinusEdges.empty()) {
384 : currentWayEdges.clear();
385 : last = nullptr;
386 3 : continue;
387 : } else {
388 1653 : edges.insert(edges.end(), currentWayMinusEdges.begin(), currentWayMinusEdges.end());
389 1653 : if (fakeMinus) {
390 166 : last = currentWayMinusEdges.back()->getFromNode();
391 : } else {
392 1487 : last = currentWayMinusEdges.back()->getToNode();
393 : }
394 : }
395 1489 : } else if (first == currentWayEdges.front()->getFromNode() && first != nullptr) {
396 28 : edges.insert(edges.end(), prevWayMinusEdges.begin(), prevWayMinusEdges.end());
397 28 : edges.insert(edges.end(), currentWayEdges.begin(), currentWayEdges.end());
398 28 : last = currentWayEdges.back()->getToNode();
399 : prevWayEdges.clear();
400 : prevWayMinusEdges.clear();
401 1461 : } else if (first == currentWayEdges.back()->getToNode() && first != nullptr) {
402 171 : edges.insert(edges.end(), prevWayMinusEdges.begin(), prevWayMinusEdges.end());
403 171 : if (currentWayMinusEdges.empty()) {
404 : currentWayEdges.clear();
405 : last = nullptr;
406 : prevWayEdges.clear();
407 : prevWayMinusEdges.clear();
408 1 : continue;
409 : } else {
410 170 : edges.insert(edges.end(), currentWayMinusEdges.begin(), currentWayMinusEdges.end());
411 170 : last = currentWayMinusEdges.back()->getToNode();
412 : prevWayEdges.clear();
413 : prevWayMinusEdges.clear();
414 : }
415 : } else {
416 1290 : if (it3 != pTLine->getWays().begin()) {
417 : #ifdef DEBUG_CONSTRUCT_ROUTE
418 : if (pTLine->getLineID() == DEBUGLINEID) {
419 : std::cout << " way " << (*it3)
420 : << " is not the start of ptline " << pTLine->getLineID()
421 : << " (" + pTLine->getName() + ")\n";
422 : }
423 : #endif
424 1131 : } else if (pTLine->getWays().size() == 1) {
425 : if (currentWayEdges.size() > 0) {
426 71 : edges.insert(edges.end(), currentWayEdges.begin(), currentWayEdges.end());
427 : } else {
428 : edges.insert(edges.end(), currentWayMinusEdges.begin(), currentWayMinusEdges.end());
429 : }
430 : }
431 1290 : prevWayEdges = currentWayEdges;
432 1290 : prevWayMinusEdges = currentWayMinusEdges;
433 1290 : if (!prevWayEdges.empty()) {
434 1290 : first = prevWayEdges.front()->getFromNode();
435 1290 : last = prevWayEdges.back()->getToNode();
436 : } else {
437 : first = nullptr;
438 : last = nullptr;
439 : }
440 : }
441 : currentWayEdges.clear();
442 : currentWayMinusEdges.clear();
443 : }
444 1211 : pTLine->setEdges(edges);
445 1211 : }
446 :
447 :
448 : void
449 5567 : NBPTLineCont::replaceEdge(const std::string& edgeID, const EdgeVector& replacement) {
450 : //std::cout << " replaceEdge " << edgeID << " replacement=" << toString(replacement) << "\n";
451 5567 : if (myPTLines.size() > 0 && myPTLineLookup.size() == 0) {
452 : // init lookup once
453 1148 : for (auto& item : myPTLines) {
454 18531 : for (const NBEdge* e : item.second->getRoute()) {
455 17483 : myPTLineLookup[e->getID()].insert(item.second);
456 : }
457 : }
458 : }
459 10710 : for (NBPTLine* line : myPTLineLookup[edgeID]) {
460 5143 : line->replaceEdge(edgeID, replacement);
461 10788 : for (const NBEdge* e : replacement) {
462 5645 : myPTLineLookup[e->getID()].insert(line);
463 : }
464 : }
465 : myPTLineLookup.erase(edgeID);
466 5567 : }
467 :
468 :
469 : std::set<std::string>
470 4 : NBPTLineCont::getServedPTStops() {
471 : std::set<std::string> result;
472 118 : for (auto& item : myPTLines) {
473 114 : NBPTLine* line = item.second;
474 484 : for (std::shared_ptr<NBPTStop> stop : line->getStops()) {
475 740 : result.insert(stop->getID());
476 : }
477 : }
478 4 : return result;
479 : }
480 :
481 :
482 : void
483 65 : NBPTLineCont::fixBidiStops(const NBEdgeCont& ec) {
484 : std::map<std::string, SUMOVehicleClass> types;
485 65 : types["bus"] = SVC_BUS;
486 65 : types["minibus"] = SVC_BUS;
487 65 : types["trolleybus"] = SVC_BUS;
488 65 : types["tram"] = SVC_TRAM;
489 65 : types["train"] = SVC_RAIL;
490 65 : types["subway"] = SVC_RAIL_URBAN;
491 65 : types["light_rail"] = SVC_RAIL_URBAN;
492 65 : types["monorail"] = SVC_RAIL_URBAN;
493 65 : types["aerialway"] = SVC_RAIL_URBAN;
494 65 : types["ferry"] = SVC_SHIP;
495 :
496 : SUMOAbstractRouter<NBRouterEdge, NBVehicle>* const router = new DijkstraRouter<NBRouterEdge, NBVehicle>(
497 65 : ec.getAllRouterEdges(), true, &NBRouterEdge::getTravelTimeStatic, nullptr, true);
498 :
499 729 : for (auto& item : myPTLines) {
500 664 : NBPTLine* line = item.second;
501 664 : std::vector<std::shared_ptr<NBPTStop> > stops = line->getStops();
502 664 : if (stops.size() < 2) {
503 212 : continue;
504 : }
505 0 : if (types.count(line->getType()) == 0) {
506 0 : WRITE_WARNINGF(TL("Could not determine vehicle class for public transport line of type '%'."), line->getType());
507 0 : continue;
508 : }
509 452 : NBVehicle veh(line->getRef(), types[line->getType()]);
510 : std::vector<std::shared_ptr<NBPTStop> > newStops;
511 : std::shared_ptr<NBPTStop> from = nullptr;
512 2248 : for (auto it = stops.begin(); it != stops.end(); ++it) {
513 : std::shared_ptr<NBPTStop> to = *it;
514 : std::shared_ptr<NBPTStop> used = *it;
515 1796 : if (to->getBidiStop() != nullptr) {
516 : double best = std::numeric_limits<double>::max();
517 : std::shared_ptr<NBPTStop> to2 = to->getBidiStop();
518 235 : if (from == nullptr) {
519 52 : if ((it + 1) != stops.end()) {
520 : from = to;
521 : std::shared_ptr<NBPTStop> from2 = to2;
522 : to = *(it + 1);
523 156 : const double c1 = getCost(ec, *router, from, to, &veh);
524 156 : const double c2 = getCost(ec, *router, from2, to, &veh);
525 : //std::cout << " from=" << from->getID() << " to=" << to->getID() << " c1=" << MIN2(10000.0, c1) << "\n";
526 : //std::cout << " from2=" << from2->getID() << " to=" << to->getID() << " c2=" << MIN2(10000.0, c2) << "\n";
527 : best = c1;
528 52 : if (to->getBidiStop() != nullptr) {
529 39 : to2 = to->getBidiStop();
530 117 : const double c3 = getCost(ec, *router, from, to2, &veh);
531 78 : const double c4 = getCost(ec, *router, from2, to2, &veh);
532 : //std::cout << " from=" << from->getID() << " to2=" << to2->getID() << " c3=" << MIN2(10000.0, c3) << "\n";
533 : //std::cout << " from2=" << from2->getID() << " to2=" << to2->getID() << " c4=" << MIN2(10000.0, c4) << "\n";
534 39 : if (c2 < best) {
535 : used = from2;
536 : best = c2;
537 : }
538 39 : if (c3 < best) {
539 : used = from;
540 : best = c3;
541 : }
542 39 : if (c4 < best) {
543 : used = from2;
544 : best = c4;
545 : }
546 : } else {
547 13 : if (c2 < c1) {
548 : used = from2;
549 : best = c2;
550 : } else {
551 : best = c1;
552 : }
553 : }
554 : }
555 : } else {
556 549 : const double c1 = getCost(ec, *router, from, to, &veh);
557 366 : const double c2 = getCost(ec, *router, from, to2, &veh);
558 : //std::cout << " from=" << from->getID() << " to=" << to->getID() << " c1=" << MIN2(10000.0, c1) << "\n";
559 : //std::cout << " from=" << from->getID() << " t2o=" << to2->getID() << " c2=" << MIN2(10000.0, c2) << "\n";
560 183 : if (c2 < c1) {
561 : used = to2;
562 : best = c2;
563 : } else {
564 : best = c1;
565 : }
566 :
567 : }
568 235 : if (best < std::numeric_limits<double>::max()) {
569 : from = used;
570 : } else {
571 12 : WRITE_WARNINGF(TL("Could not determine direction for line '%' at stop '%'."), line->getLineID(), used->getID());
572 : }
573 : }
574 : from = used;
575 1796 : newStops.push_back(used);
576 : }
577 : assert(stops.size() == newStops.size());
578 904 : line->replaceStops(newStops);
579 1116 : }
580 65 : delete router;
581 65 : }
582 :
583 :
584 : void
585 1812 : NBPTLineCont::removeInvalidEdges(const NBEdgeCont& ec) {
586 2945 : for (auto& item : myPTLines) {
587 1133 : item.second->removeInvalidEdges(ec);
588 : }
589 1812 : }
590 :
591 :
592 : void
593 1812 : NBPTLineCont::fixPermissions() {
594 2945 : for (auto& item : myPTLines) {
595 1133 : NBPTLine* line = item.second;
596 1133 : const std::vector<NBEdge*>& route = line->getRoute();
597 : const SUMOVehicleClass svc = line->getVClass();
598 16924 : for (int i = 1; i < (int)route.size(); i++) {
599 15791 : NBEdge* e1 = route[i - 1];
600 15791 : NBEdge* e2 = route[i];
601 15791 : std::vector<NBEdge::Connection> cons = e1->getConnectionsFromLane(-1, e2, -1);
602 15791 : if (cons.size() == 0) {
603 : //WRITE_WARNINGF(TL("Disconnected ptline '%' between edge '%' and edge '%'"), line->getLineID(), e1->getID(), e2->getID());
604 : } else {
605 : bool ok = false;
606 16121 : for (const auto& c : cons) {
607 16119 : if ((e1->getPermissions(c.fromLane) & svc) == svc) {
608 : ok = true;
609 : break;
610 : }
611 : }
612 15473 : if (!ok) {
613 2 : int lane = cons[0].fromLane;
614 2 : e1->setPermissions(e1->getPermissions(lane) | svc, lane);
615 : }
616 : }
617 15791 : }
618 : }
619 1812 : }
620 :
621 :
622 : double
623 548 : NBPTLineCont::getCost(const NBEdgeCont& ec, SUMOAbstractRouter<NBRouterEdge, NBVehicle>& router,
624 : const std::shared_ptr<NBPTStop> from, const std::shared_ptr<NBPTStop> to, const NBVehicle* veh) {
625 548 : NBEdge* fromEdge = ec.getByID(from->getEdgeId());
626 548 : NBEdge* toEdge = ec.getByID(to->getEdgeId());
627 548 : if (fromEdge == nullptr || toEdge == nullptr) {
628 : return std::numeric_limits<double>::max();
629 548 : } else if (fromEdge == toEdge) {
630 34 : if (from->getEndPos() <= to->getEndPos()) {
631 29 : return to->getEndPos() - from->getEndPos();
632 : } else {
633 : return std::numeric_limits<double>::max();
634 : }
635 514 : } else if (fromEdge->getBidiEdge() == toEdge) {
636 : return std::numeric_limits<double>::max();
637 : }
638 : std::vector<const NBRouterEdge*> route;
639 484 : router.compute(fromEdge, toEdge, veh, 0, route);
640 484 : if (route.size() == 0) {
641 : return std::numeric_limits<double>::max();
642 : } else {
643 388 : return router.recomputeCosts(route, veh, 0);
644 : }
645 484 : }
646 :
647 :
648 : std::string
649 65 : NBPTLineCont::getWayID(const std::string& edgeID) {
650 : std::size_t found = edgeID.rfind("#");
651 : std::string result = edgeID;
652 65 : if (found != std::string::npos) {
653 102 : result = edgeID.substr(0, found);
654 : }
655 65 : if (result[0] == '-') {
656 44 : result = result.substr(1);
657 : }
658 65 : return result;
659 : }
660 :
661 :
662 : /****************************************************************************/
|