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 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 2141 : NBPTLineCont::~NBPTLineCont() {
52 3289 : for (auto& myPTLine : myPTLines) {
53 1148 : delete myPTLine.second;
54 : }
55 : myPTLines.clear();
56 2141 : }
57 :
58 :
59 : bool
60 1154 : NBPTLineCont::insert(NBPTLine* ptLine) {
61 : if (myPTLines.count(ptLine->getLineID()) == 0) {
62 1148 : myPTLines[ptLine->getLineID()] = ptLine;
63 1148 : 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 145 : NBPTLineCont::process(NBEdgeCont& ec, NBPTStopCont& sc, bool routeOnly) {
80 1441 : for (auto& item : myPTLines) {
81 1296 : NBPTLine* line = item.second;
82 1296 : 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 1235 : constructRoute(line, ec);
86 1235 : if (!routeOnly) {
87 : // map stops to ways, using the constructed route for loose stops
88 1103 : reviseStops(line, ec, sc);
89 : }
90 : }
91 : // fix circular line if necessary
92 1296 : if (line->getStops().size() > 1
93 869 : && line->getStops().front() == line->getStops().back()
94 7 : && line->getRoute().size() > 1
95 1302 : && 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 1296 : line->deleteInvalidStops(ec, sc);
108 : //line->deleteDuplicateStops();
109 : }
110 145 : }
111 :
112 :
113 : void
114 1103 : NBPTLineCont::reviseStops(NBPTLine* line, const NBEdgeCont& ec, NBPTStopCont& sc) {
115 : const std::vector<std::string>& waysIds = line->getWays();
116 1103 : if (waysIds.size() == 1 && line->getStops().size() > 1) {
117 33 : reviseSingleWayStops(line, ec, sc);
118 124 : return;
119 : }
120 1070 : if (waysIds.size() <= 1) {
121 144 : WRITE_WARNINGF(TL("Cannot revise pt stop localization for pt line '%', which consist of one way only. Ignoring!"), line->getLineID());
122 48 : return;
123 : }
124 1022 : 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 979 : std::vector<std::shared_ptr<NBPTStop> > stops = line->getStops();
129 : std::vector<bool> stopsRevised;
130 3730 : for (std::shared_ptr<NBPTStop> stop : stops) {
131 2751 : stopsRevised.push_back(false);
132 : //get the corresponding and one of the two adjacent ways
133 2751 : stop = findWay(line, stop, ec, sc);
134 2751 : if (stop == nullptr) {
135 : // warning already given
136 1 : continue;
137 : }
138 2750 : auto waysIdsIt = std::find(waysIds.begin(), waysIds.end(), stop->getOrigEdgeId());
139 2750 : if (waysIdsIt == waysIds.end()) {
140 : // warning already given
141 42 : continue;
142 : }
143 : // find directional edge (OSM ways are bidirectional)
144 2708 : const std::vector<long long int>* const way = line->getWayNodes(stop->getOrigEdgeId());
145 2708 : if (way == nullptr) {
146 0 : WRITE_WARNINGF(TL("Cannot assign stop '%' on edge '%' to pt line '%' (wayNodes not found). Ignoring!"),
147 : stop->getID(), stop->getOrigEdgeId(), line->getLineID());
148 0 : continue;
149 : }
150 :
151 : int dir;
152 : const std::vector<long long int>* wayPrev = nullptr;
153 2708 : if (waysIdsIt != waysIds.begin()) {
154 4284 : wayPrev = line->getWayNodes(*(waysIdsIt - 1));
155 : }
156 : const std::vector<long long int>* wayNext = nullptr;
157 2708 : if (waysIdsIt != (waysIds.end() - 1)) {
158 4338 : wayNext = line->getWayNodes(*(waysIdsIt + 1));
159 : }
160 2708 : if (wayPrev == nullptr && wayNext == nullptr) {
161 0 : WRITE_WARNINGF(TL("Cannot revise pt stop localization for incomplete pt line '%'. Ignoring!"), line->getLineID());
162 0 : continue;
163 : }
164 2708 : const long long int wayEnds = way->back();
165 2708 : const long long int wayBegins = way->front();
166 2708 : const long long int wayPrevEnds = wayPrev != nullptr ? wayPrev->back() : 0;
167 2142 : const long long int wayPrevBegins = wayPrev != nullptr ? wayPrev->front() : 0;
168 2708 : const long long int wayNextEnds = wayNext != nullptr ? wayNext->back() : 0;
169 2169 : const long long int wayNextBegins = wayNext != nullptr ? wayNext->front() : 0;
170 2708 : if (wayBegins == wayPrevEnds || wayBegins == wayPrevBegins || wayEnds == wayNextBegins || wayEnds == wayNextEnds) {
171 : dir = FWD;
172 480 : } else if (wayEnds == wayPrevBegins || wayEnds == wayPrevEnds || wayBegins == wayNextEnds || wayBegins == wayNextBegins) {
173 : dir = BWD;
174 : } else {
175 30 : WRITE_WARNINGF(TL("Cannot revise pt stop localization for incomplete pt line '%'. Ignoring!"), line->getLineID());
176 10 : continue;
177 : }
178 :
179 2698 : std::string edgeId = stop->getEdgeId();
180 2698 : NBEdge* current = ec.getByID(edgeId);
181 2698 : int assignedDir = edgeId.at(0) == '-' ? BWD : FWD;
182 :
183 2698 : if (dir != assignedDir) {
184 257 : NBEdge* reverse = NBPTStopCont::getReverseEdge(current);
185 257 : if (reverse == nullptr) {
186 78 : const OptionsCont& oc = OptionsCont::getOptions();
187 118 : if (!oc.getBool("railway.topology.repair") && oc.getBool("ptstop-output.no-bidi")) {
188 0 : WRITE_WARNINGF(TL("Could not re-assign PT stop '%'. May need option --railway.topology.repair"), stop->getID());
189 : }
190 : continue;
191 78 : }
192 179 : if (stop->getLines().size() > 0) {
193 98 : std::shared_ptr<NBPTStop> reverseStop = sc.getReverseStop(stop, ec);
194 98 : sc.insert(reverseStop);
195 147 : line->replaceStop(stop, reverseStop);
196 : stop = reverseStop;
197 : } else {
198 390 : WRITE_WARNINGF(TL("PT stop '%' has been moved to edge '%'."), stop->getID(), reverse->getID());
199 : }
200 537 : stop->setEdgeId(reverse->getID(), ec);
201 : }
202 2620 : stop->addLine(line->getRef());
203 : stopsRevised.back() = true;
204 : }
205 1958 : line->setRevised(stopsRevised);
206 979 : }
207 :
208 :
209 33 : void NBPTLineCont::reviseSingleWayStops(NBPTLine* line, const NBEdgeCont& ec, NBPTStopCont& sc) {
210 : const std::vector<std::string>& waysIds = line->getWays();
211 134 : for (std::shared_ptr<NBPTStop> stop : line->getStops()) {
212 : //get the corresponding and one of the two adjacent ways
213 101 : stop = findWay(line, stop, ec, sc);
214 101 : if (stop == nullptr) {
215 : // warning already given
216 4 : continue;
217 : }
218 97 : auto waysIdsIt = std::find(waysIds.begin(), waysIds.end(), stop->getOrigEdgeId());
219 97 : if (waysIdsIt == waysIds.end()) {
220 : // warning already given
221 0 : continue;
222 : }
223 97 : stop->addLine(line->getRef());
224 : }
225 33 : }
226 :
227 :
228 : std::shared_ptr<NBPTStop>
229 2852 : NBPTLineCont::findWay(NBPTLine* line, std::shared_ptr<NBPTStop> stop, const NBEdgeCont& ec, NBPTStopCont& sc) const {
230 : const std::vector<std::string>& waysIds = line->getWays();
231 : #ifdef DEBUG_FIND_WAY
232 : if (stop->getID() == DEBUGSTOPID) {
233 : std::cout << " stop=" << stop->getID() << " line=" << line->getLineID() << " edgeID=" << stop->getEdgeId() << " origID=" << stop->getOrigEdgeId() << "\n";
234 : }
235 : #endif
236 2852 : if (stop->isLoose()) {
237 : // find closest edge in route
238 : double minDist = std::numeric_limits<double>::max();
239 : NBEdge* best = nullptr;
240 1361 : for (NBEdge* edge : line->getRoute()) {
241 1280 : const double dist = edge->getLaneShape(0).distance2D(stop->getPosition());
242 1280 : if (dist < minDist) {
243 : best = edge;
244 : minDist = dist;
245 : }
246 : }
247 : #ifdef DEBUG_FIND_WAY
248 : if (stop->getID() == DEBUGSTOPID) {
249 : std::cout << " best=" << Named::getIDSecure(best) << " minDist=" << minDist << " wayID=" << getWayID(best->getID())
250 : << " found=" << (std::find(waysIds.begin(), waysIds.end(), getWayID(best->getID())) != waysIds.end())
251 : << " wayIDs=" << toString(waysIds) << "\n";
252 : }
253 : #endif
254 162 : if (minDist < OptionsCont::getOptions().getFloat("ptline.match-dist")) {
255 76 : const std::string wayID = getWayID(best->getID());
256 76 : if (stop->getEdgeId() == "") {
257 105 : stop->setEdgeId(best->getID(), ec);
258 : stop->setOrigEdgeId(wayID);
259 41 : } else if (stop->getEdgeId() != best->getID()) {
260 : // stop is used by multiple lines and mapped to different edges.
261 : // check if an alternative stop already exists
262 5 : std::shared_ptr<NBPTStop> newStop = sc.findStop(wayID, stop->getPosition());
263 5 : if (newStop == nullptr) {
264 12 : newStop = std::make_shared<NBPTStop>(stop->getElement(), stop->getID() + "@" + line->getLineID(), stop->getPosition(), best->getID(), wayID, stop->getLength(), stop->getName(), stop->getPermissions());
265 9 : newStop->setEdgeId(best->getID(), ec); // trigger lane assignment
266 6 : sc.insert(newStop);
267 : }
268 15 : line->replaceStop(stop, newStop);
269 : stop = newStop;
270 : }
271 : } else {
272 20 : WRITE_WARNINGF(TL("Could not assign stop '%' to pt line '%' (closest edge '%', distance %). Ignoring!"),
273 : stop->getID(), line->getLineID(), Named::getIDSecure(best), minDist);
274 : return nullptr;
275 : }
276 : } else {
277 : // if the stop is part of an edge, find that edge among the line edges
278 : auto waysIdsIt = waysIds.begin();
279 33619 : for (; waysIdsIt != waysIds.end(); waysIdsIt++) {
280 33527 : if ((*waysIdsIt) == stop->getOrigEdgeId()) {
281 : break;
282 : }
283 : }
284 :
285 2771 : if (waysIdsIt == waysIds.end()) {
286 : // stop edge not found, try additional edges
287 119 : for (auto& edgeCand : stop->getAdditionalEdgeCandidates()) {
288 : bool found = false;
289 : waysIdsIt = waysIds.begin();
290 629 : for (; waysIdsIt != waysIds.end(); waysIdsIt++) {
291 602 : if ((*waysIdsIt) == edgeCand.first) {
292 100 : if (stop->setEdgeId(edgeCand.second, ec)) {
293 : stop->setOrigEdgeId(edgeCand.first);
294 : found = true;
295 : break;
296 : }
297 : }
298 : }
299 : if (found) {
300 : break;
301 : }
302 : }
303 92 : if (waysIdsIt == waysIds.end()) {
304 126 : WRITE_WARNINGF(TL("Cannot assign stop % on edge '%' to pt line '%'. Ignoring!"), stop->getID(), stop->getOrigEdgeId(), line->getLineID());
305 : }
306 : }
307 : }
308 : return stop;
309 : }
310 :
311 :
312 1235 : void NBPTLineCont::constructRoute(NBPTLine* pTLine, const NBEdgeCont& cont) {
313 : std::vector<NBEdge*> edges;
314 :
315 : NBNode* first = nullptr;
316 : NBNode* last = nullptr;
317 : std::vector<NBEdge*> prevWayEdges;
318 : std::vector<NBEdge*> prevWayMinusEdges;
319 : std::vector<NBEdge*> currentWayEdges;
320 : std::vector<NBEdge*> currentWayMinusEdges;
321 15467 : for (auto it3 = pTLine->getWays().begin(); it3 != pTLine->getWays().end(); it3++) {
322 :
323 : int foundForward = 0;
324 14232 : if (cont.retrieve(*it3, false) != nullptr) {
325 7228 : currentWayEdges.push_back(cont.retrieve(*it3, false));
326 : foundForward++;
327 : } else {
328 : int i = 0;
329 57672 : while (cont.retrieve(*it3 + "#" + std::to_string(i), true) != nullptr) {
330 43664 : if (cont.retrieve(*it3 + "#" + std::to_string(i), false)) {
331 43664 : currentWayEdges.push_back(cont.retrieve(*it3 + "#" + std::to_string(i), false));
332 21832 : foundForward++;
333 : }
334 21832 : i++;
335 : }
336 : }
337 :
338 : int foundReverse = 0;
339 28464 : if (cont.retrieve("-" + *it3, false) != nullptr) {
340 5112 : currentWayMinusEdges.push_back(cont.retrieve("-" + *it3, false));
341 : foundReverse++;
342 : } else {
343 : int i = 0;
344 61020 : while (cont.retrieve("-" + *it3 + "#" + std::to_string(i), true) != nullptr) {
345 25992 : if (cont.retrieve("-" + *it3 + "#" + std::to_string(i), false)) {
346 8664 : currentWayMinusEdges.insert(currentWayMinusEdges.end() - foundReverse,
347 25992 : cont.retrieve("-" + *it3 + "#" + std::to_string(i), false));
348 8664 : foundReverse++;
349 : }
350 8664 : i++;
351 : }
352 : }
353 : bool fakeMinus = false;
354 14232 : if (foundReverse == 0 && foundForward > 0 && isRailway(pTLine->getVClass())) {
355 : // rail tracks may be used in both directions and are often not tagged as such.
356 : // This can be repaired later with option --railway.topology.repair
357 5508 : currentWayMinusEdges.insert(currentWayMinusEdges.begin(), currentWayEdges.rbegin(), currentWayEdges.rbegin() + foundForward);
358 : fakeMinus = true;
359 : }
360 : #ifdef DEBUG_CONSTRUCT_ROUTE
361 : if (pTLine->getLineID() == DEBUGLINEID) {
362 : std::cout << " way=" << (*it3)
363 : << " done=" << toString(edges)
364 : << " first=" << Named::getIDSecure(first)
365 : << " last=" << Named::getIDSecure(last)
366 : << "\n +=" << toString(currentWayEdges)
367 : << "\n -=" << toString(currentWayMinusEdges)
368 : << "\n p+=" << toString(prevWayEdges)
369 : << "\n p-=" << toString(prevWayMinusEdges)
370 : << "\n";
371 : }
372 : #endif
373 14232 : if (currentWayEdges.empty()) {
374 194 : continue;
375 : }
376 14038 : if (last == currentWayEdges.front()->getFromNode() && last != nullptr) {
377 10848 : if (!prevWayEdges.empty()) {
378 894 : edges.insert(edges.end(), prevWayEdges.begin(), prevWayEdges.end());
379 : prevWayEdges.clear();
380 : prevWayMinusEdges.clear();
381 : }
382 10848 : edges.insert(edges.end(), currentWayEdges.begin(), currentWayEdges.end());
383 10848 : last = currentWayEdges.back()->getToNode();
384 3190 : } else if (last == currentWayEdges.back()->getToNode() && last != nullptr) {
385 1692 : if (!prevWayEdges.empty()) {
386 64 : edges.insert(edges.end(), prevWayEdges.begin(), prevWayEdges.end());
387 : prevWayEdges.clear();
388 : prevWayMinusEdges.clear();
389 : }
390 1692 : if (currentWayMinusEdges.empty()) {
391 : currentWayEdges.clear();
392 : last = nullptr;
393 3 : continue;
394 : } else {
395 1689 : edges.insert(edges.end(), currentWayMinusEdges.begin(), currentWayMinusEdges.end());
396 1689 : if (fakeMinus) {
397 172 : last = currentWayMinusEdges.back()->getFromNode();
398 : } else {
399 1517 : last = currentWayMinusEdges.back()->getToNode();
400 : }
401 : }
402 1498 : } else if (first == currentWayEdges.front()->getFromNode() && first != nullptr) {
403 28 : edges.insert(edges.end(), prevWayMinusEdges.begin(), prevWayMinusEdges.end());
404 28 : edges.insert(edges.end(), currentWayEdges.begin(), currentWayEdges.end());
405 28 : last = currentWayEdges.back()->getToNode();
406 : prevWayEdges.clear();
407 : prevWayMinusEdges.clear();
408 1470 : } else if (first == currentWayEdges.back()->getToNode() && first != nullptr) {
409 177 : edges.insert(edges.end(), prevWayMinusEdges.begin(), prevWayMinusEdges.end());
410 177 : if (currentWayMinusEdges.empty()) {
411 : currentWayEdges.clear();
412 : last = nullptr;
413 : prevWayEdges.clear();
414 : prevWayMinusEdges.clear();
415 1 : continue;
416 : } else {
417 176 : edges.insert(edges.end(), currentWayMinusEdges.begin(), currentWayMinusEdges.end());
418 176 : last = currentWayMinusEdges.back()->getToNode();
419 : prevWayEdges.clear();
420 : prevWayMinusEdges.clear();
421 : }
422 : } else {
423 1293 : if (it3 != pTLine->getWays().begin()) {
424 : #ifdef DEBUG_CONSTRUCT_ROUTE
425 : if (pTLine->getLineID() == DEBUGLINEID) {
426 : std::cout << " way " << (*it3)
427 : << " is not the start of ptline " << pTLine->getLineID()
428 : << " (" + pTLine->getName() + ")\n";
429 : }
430 : #endif
431 1155 : } else if (pTLine->getWays().size() == 1) {
432 : if (currentWayEdges.size() > 0) {
433 71 : edges.insert(edges.end(), currentWayEdges.begin(), currentWayEdges.end());
434 : } else {
435 : edges.insert(edges.end(), currentWayMinusEdges.begin(), currentWayMinusEdges.end());
436 : }
437 : }
438 1293 : prevWayEdges = currentWayEdges;
439 1293 : prevWayMinusEdges = currentWayMinusEdges;
440 1293 : if (!prevWayEdges.empty()) {
441 1293 : first = prevWayEdges.front()->getFromNode();
442 1293 : last = prevWayEdges.back()->getToNode();
443 : } else {
444 : first = nullptr;
445 : last = nullptr;
446 : }
447 : }
448 : currentWayEdges.clear();
449 : currentWayMinusEdges.clear();
450 : }
451 1235 : pTLine->setEdges(edges);
452 1235 : }
453 :
454 :
455 : void
456 5570 : NBPTLineCont::replaceEdge(const std::string& edgeID, const EdgeVector& replacement) {
457 : //std::cout << " replaceEdge " << edgeID << " replacement=" << toString(replacement) << "\n";
458 5570 : if (myPTLines.size() > 0 && myPTLineLookup.size() == 0) {
459 : // init lookup once
460 1148 : for (auto& item : myPTLines) {
461 18579 : for (const NBEdge* e : item.second->getRoute()) {
462 17531 : myPTLineLookup[e->getID()].insert(item.second);
463 : }
464 : }
465 : }
466 10731 : for (NBPTLine* line : myPTLineLookup[edgeID]) {
467 5161 : line->replaceEdge(edgeID, replacement);
468 10824 : for (const NBEdge* e : replacement) {
469 5663 : myPTLineLookup[e->getID()].insert(line);
470 : }
471 : }
472 : myPTLineLookup.erase(edgeID);
473 5570 : }
474 :
475 :
476 : std::set<std::string>
477 4 : NBPTLineCont::getServedPTStops() {
478 : std::set<std::string> result;
479 118 : for (auto& item : myPTLines) {
480 114 : NBPTLine* line = item.second;
481 484 : for (std::shared_ptr<NBPTStop> stop : line->getStops()) {
482 740 : result.insert(stop->getID());
483 : }
484 : }
485 4 : return result;
486 : }
487 :
488 :
489 : void
490 76 : NBPTLineCont::fixBidiStops(const NBEdgeCont& ec) {
491 : std::map<std::string, SUMOVehicleClass> types;
492 76 : types["bus"] = SVC_BUS;
493 76 : types["minibus"] = SVC_BUS;
494 76 : types["trolleybus"] = SVC_BUS;
495 76 : types["tram"] = SVC_TRAM;
496 76 : types["train"] = SVC_RAIL;
497 76 : types["subway"] = SVC_RAIL_URBAN;
498 76 : types["light_rail"] = SVC_RAIL_URBAN;
499 76 : types["monorail"] = SVC_RAIL_URBAN;
500 76 : types["aerialway"] = SVC_RAIL_URBAN;
501 76 : types["ferry"] = SVC_SHIP;
502 :
503 : SUMOAbstractRouter<NBRouterEdge, NBVehicle>* const router = new DijkstraRouter<NBRouterEdge, NBVehicle>(
504 76 : ec.getAllRouterEdges(), true, &NBRouterEdge::getTravelTimeStatic, nullptr, true);
505 :
506 752 : for (auto& item : myPTLines) {
507 676 : NBPTLine* line = item.second;
508 676 : std::vector<std::shared_ptr<NBPTStop> > stops = line->getStops();
509 676 : if (stops.size() < 2) {
510 169 : continue;
511 : }
512 0 : if (types.count(line->getType()) == 0) {
513 0 : WRITE_WARNINGF(TL("Could not determine vehicle class for public transport line of type '%'."), line->getType());
514 0 : continue;
515 : }
516 507 : NBVehicle veh(line->getRef(), types[line->getType()]);
517 : std::vector<std::shared_ptr<NBPTStop> > newStops;
518 : std::shared_ptr<NBPTStop> from = nullptr;
519 507 : std::vector<NBPTLine::PTStopInfo> stopInfos = line->getStopEdges(ec);
520 : assert(stopInfos.size() == stops.size());
521 2532 : for (auto it = stops.begin(); it != stops.end(); ++it) {
522 : std::shared_ptr<NBPTStop> to = *it;
523 : std::shared_ptr<NBPTStop> used = *it;
524 2025 : bool isRevised = stopInfos[it - stops.begin()].revised;
525 4050 : if (to->getBidiStop() != nullptr && !isRevised) {
526 : double best = std::numeric_limits<double>::max();
527 : std::shared_ptr<NBPTStop> to2 = to->getBidiStop();
528 82 : if (from == nullptr) {
529 24 : if ((it + 1) != stops.end()) {
530 : from = to;
531 : std::shared_ptr<NBPTStop> from2 = to2;
532 : to = *(it + 1);
533 72 : const double c1 = getCost(ec, *router, from, to, &veh);
534 72 : const double c2 = getCost(ec, *router, from2, to, &veh);
535 : //std::cout << " from=" << from->getID() << " to=" << to->getID() << " c1=" << MIN2(10000.0, c1) << "\n";
536 : //std::cout << " from2=" << from2->getID() << " to=" << to->getID() << " c2=" << MIN2(10000.0, c2) << "\n";
537 : best = c1;
538 24 : if (to->getBidiStop() != nullptr) {
539 20 : to2 = to->getBidiStop();
540 60 : const double c3 = getCost(ec, *router, from, to2, &veh);
541 40 : const double c4 = getCost(ec, *router, from2, to2, &veh);
542 : //std::cout << " from=" << from->getID() << " to2=" << to2->getID() << " c3=" << MIN2(10000.0, c3) << "\n";
543 : //std::cout << " from2=" << from2->getID() << " to2=" << to2->getID() << " c4=" << MIN2(10000.0, c4) << "\n";
544 20 : if (c2 < best) {
545 : used = from2;
546 : best = c2;
547 : }
548 20 : if (c3 < best) {
549 : used = from;
550 : best = c3;
551 : }
552 20 : if (c4 < best) {
553 : used = from2;
554 : best = c4;
555 : }
556 : } else {
557 4 : if (c2 < c1) {
558 : used = from2;
559 : best = c2;
560 : } else {
561 : best = c1;
562 : }
563 : }
564 : }
565 : } else {
566 174 : const double c1 = getCost(ec, *router, from, to, &veh);
567 116 : const double c2 = getCost(ec, *router, from, to2, &veh);
568 : //std::cout << " from=" << from->getID() << " to=" << to->getID() << " c1=" << MIN2(10000.0, c1) << "\n";
569 : //std::cout << " from=" << from->getID() << " t2o=" << to2->getID() << " c2=" << MIN2(10000.0, c2) << "\n";
570 58 : if (c2 < c1) {
571 : used = to2;
572 : best = c2;
573 : } else {
574 : best = c1;
575 : }
576 :
577 : }
578 82 : if (best < std::numeric_limits<double>::max()) {
579 : from = used;
580 : } else {
581 12 : WRITE_WARNINGF(TL("Could not determine direction for line '%' at stop '%'."), line->getLineID(), used->getID());
582 : }
583 : }
584 : from = used;
585 2025 : newStops.push_back(used);
586 : }
587 : assert(stops.size() == newStops.size());
588 1014 : line->replaceStops(newStops);
589 1690 : }
590 76 : delete router;
591 76 : }
592 :
593 :
594 : void
595 1840 : NBPTLineCont::removeInvalidEdges(const NBEdgeCont& ec) {
596 2987 : for (auto& item : myPTLines) {
597 1147 : item.second->removeInvalidEdges(ec);
598 : }
599 1840 : }
600 :
601 :
602 : void
603 1840 : NBPTLineCont::fixPermissions() {
604 2987 : for (auto& item : myPTLines) {
605 1147 : NBPTLine* line = item.second;
606 1147 : const std::vector<NBEdge*>& route = line->getRoute();
607 : const SUMOVehicleClass svc = line->getVClass();
608 17038 : for (int i = 1; i < (int)route.size(); i++) {
609 15891 : NBEdge* e1 = route[i - 1];
610 15891 : NBEdge* e2 = route[i];
611 15891 : std::vector<NBEdge::Connection> cons = e1->getConnectionsFromLane(-1, e2, -1);
612 15891 : if (cons.size() == 0) {
613 : //WRITE_WARNINGF(TL("Disconnected ptline '%' between edge '%' and edge '%'"), line->getLineID(), e1->getID(), e2->getID());
614 : } else {
615 : bool ok = false;
616 16227 : for (const auto& c : cons) {
617 16225 : if ((e1->getPermissions(c.fromLane) & svc) == svc) {
618 : ok = true;
619 : break;
620 : }
621 : }
622 15579 : if (!ok) {
623 2 : int lane = cons[0].fromLane;
624 2 : e1->setPermissions(e1->getPermissions(lane) | svc, lane);
625 : }
626 : }
627 15891 : }
628 : }
629 1840 : }
630 :
631 :
632 : double
633 204 : NBPTLineCont::getCost(const NBEdgeCont& ec, SUMOAbstractRouter<NBRouterEdge, NBVehicle>& router,
634 : const std::shared_ptr<NBPTStop> from, const std::shared_ptr<NBPTStop> to, const NBVehicle* veh) {
635 204 : NBEdge* fromEdge = ec.getByID(from->getEdgeId());
636 204 : NBEdge* toEdge = ec.getByID(to->getEdgeId());
637 204 : if (fromEdge == nullptr || toEdge == nullptr) {
638 : return std::numeric_limits<double>::max();
639 204 : } else if (fromEdge == toEdge) {
640 33 : if (from->getEndPos() <= to->getEndPos()) {
641 27 : return to->getEndPos() - from->getEndPos();
642 : } else {
643 : return std::numeric_limits<double>::max();
644 : }
645 171 : } else if (fromEdge->getBidiEdge() == toEdge) {
646 : return std::numeric_limits<double>::max();
647 : }
648 : std::vector<const NBRouterEdge*> route;
649 142 : router.compute(fromEdge, toEdge, veh, 0, route);
650 142 : if (route.size() == 0) {
651 : return std::numeric_limits<double>::max();
652 : } else {
653 120 : return router.recomputeCosts(route, veh, 0);
654 : }
655 142 : }
656 :
657 :
658 : std::string
659 76 : NBPTLineCont::getWayID(const std::string& edgeID) {
660 : std::size_t found = edgeID.rfind("#");
661 : std::string result = edgeID;
662 76 : if (found != std::string::npos) {
663 124 : result = edgeID.substr(0, found);
664 : }
665 76 : if (result[0] == '-') {
666 46 : result = result.substr(1);
667 : }
668 76 : return result;
669 : }
670 :
671 :
672 : /****************************************************************************/
|