Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netbuild/NBPTLineCont.cpp
193833 views
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
NBPTLineCont::~NBPTLineCont() {
52
for (auto& myPTLine : myPTLines) {
53
delete myPTLine.second;
54
}
55
myPTLines.clear();
56
}
57
58
59
bool
60
NBPTLineCont::insert(NBPTLine* ptLine) {
61
if (myPTLines.count(ptLine->getLineID()) == 0) {
62
myPTLines[ptLine->getLineID()] = ptLine;
63
return true;
64
}
65
return false;
66
}
67
68
69
NBPTLine*
70
NBPTLineCont::retrieve(const std::string& lineID) {
71
if (myPTLines.count(lineID) == 0) {
72
return nullptr;
73
} else {
74
return myPTLines[lineID];
75
}
76
}
77
78
void
79
NBPTLineCont::process(NBEdgeCont& ec, NBPTStopCont& sc, bool routeOnly) {
80
for (auto& item : myPTLines) {
81
NBPTLine* line = item.second;
82
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
constructRoute(line, ec);
86
if (!routeOnly) {
87
// map stops to ways, using the constructed route for loose stops
88
reviseStops(line, ec, sc);
89
}
90
}
91
// fix circular line if necessary
92
if (line->getStops().size() > 1
93
&& line->getStops().front() == line->getStops().back()
94
&& line->getRoute().size() > 1
95
&& line->getRoute().front() != line->getRoute().back()) {
96
// we need to duplicate either the first or the last edge depending on the stop locations
97
const std::string firstStopEdge = line->getStops().front()->getEdgeId();
98
const std::string lastStopEdge = line->getStops().back()->getEdgeId();
99
std::vector<NBEdge*> edges = line->getRoute();
100
if (firstStopEdge == edges.back()->getID()) {
101
edges.insert(edges.begin(), edges.back());
102
} else if (lastStopEdge == edges.front()->getID()) {
103
edges.push_back(edges.front());
104
}
105
line->setEdges(edges);
106
}
107
line->deleteInvalidStops(ec, sc);
108
//line->deleteDuplicateStops();
109
}
110
}
111
112
113
void
114
NBPTLineCont::reviseStops(NBPTLine* line, const NBEdgeCont& ec, NBPTStopCont& sc) {
115
const std::vector<std::string>& waysIds = line->getWays();
116
if (waysIds.size() == 1 && line->getStops().size() > 1) {
117
reviseSingleWayStops(line, ec, sc);
118
return;
119
}
120
if (waysIds.size() <= 1) {
121
WRITE_WARNINGF(TL("Cannot revise pt stop localization for pt line '%', which consist of one way only. Ignoring!"), line->getLineID());
122
return;
123
}
124
if (line->getRoute().size() == 0) {
125
WRITE_WARNINGF(TL("Cannot revise pt stop localization for pt line '%', which has no route edges. Ignoring!"), line->getLineID());
126
return;
127
}
128
std::vector<std::shared_ptr<NBPTStop> > stops = line->getStops();
129
std::vector<bool> stopsRevised;
130
for (std::shared_ptr<NBPTStop> stop : stops) {
131
stopsRevised.push_back(false);
132
//get the corresponding and one of the two adjacent ways
133
stop = findWay(line, stop, ec, sc);
134
if (stop == nullptr) {
135
// warning already given
136
continue;
137
}
138
auto waysIdsIt = std::find(waysIds.begin(), waysIds.end(), stop->getOrigEdgeId());
139
if (waysIdsIt == waysIds.end()) {
140
// warning already given
141
continue;
142
}
143
// find directional edge (OSM ways are bidirectional)
144
const std::vector<long long int>* const way = line->getWayNodes(stop->getOrigEdgeId());
145
if (way == nullptr) {
146
WRITE_WARNINGF(TL("Cannot assign stop '%' on edge '%' to pt line '%' (wayNodes not found). Ignoring!"),
147
stop->getID(), stop->getOrigEdgeId(), line->getLineID());
148
continue;
149
}
150
151
int dir;
152
const std::vector<long long int>* wayPrev = nullptr;
153
if (waysIdsIt != waysIds.begin()) {
154
wayPrev = line->getWayNodes(*(waysIdsIt - 1));
155
}
156
const std::vector<long long int>* wayNext = nullptr;
157
if (waysIdsIt != (waysIds.end() - 1)) {
158
wayNext = line->getWayNodes(*(waysIdsIt + 1));
159
}
160
if (wayPrev == nullptr && wayNext == nullptr) {
161
WRITE_WARNINGF(TL("Cannot revise pt stop localization for incomplete pt line '%'. Ignoring!"), line->getLineID());
162
continue;
163
}
164
const long long int wayEnds = way->back();
165
const long long int wayBegins = way->front();
166
const long long int wayPrevEnds = wayPrev != nullptr ? wayPrev->back() : 0;
167
const long long int wayPrevBegins = wayPrev != nullptr ? wayPrev->front() : 0;
168
const long long int wayNextEnds = wayNext != nullptr ? wayNext->back() : 0;
169
const long long int wayNextBegins = wayNext != nullptr ? wayNext->front() : 0;
170
if (wayBegins == wayPrevEnds || wayBegins == wayPrevBegins || wayEnds == wayNextBegins || wayEnds == wayNextEnds) {
171
dir = FWD;
172
} else if (wayEnds == wayPrevBegins || wayEnds == wayPrevEnds || wayBegins == wayNextEnds || wayBegins == wayNextBegins) {
173
dir = BWD;
174
} else {
175
WRITE_WARNINGF(TL("Cannot revise pt stop localization for incomplete pt line '%'. Ignoring!"), line->getLineID());
176
continue;
177
}
178
179
std::string edgeId = stop->getEdgeId();
180
NBEdge* current = ec.getByID(edgeId);
181
int assignedDir = edgeId.at(0) == '-' ? BWD : FWD;
182
183
if (dir != assignedDir) {
184
NBEdge* reverse = NBPTStopCont::getReverseEdge(current);
185
if (reverse == nullptr) {
186
const OptionsCont& oc = OptionsCont::getOptions();
187
if (!oc.getBool("railway.topology.repair") && oc.getBool("ptstop-output.no-bidi")) {
188
WRITE_WARNINGF(TL("Could not re-assign PT stop '%'. May need option --railway.topology.repair"), stop->getID());
189
}
190
continue;
191
}
192
if (stop->getLines().size() > 0) {
193
std::shared_ptr<NBPTStop> reverseStop = sc.getReverseStop(stop, ec);
194
sc.insert(reverseStop);
195
line->replaceStop(stop, reverseStop);
196
stop = reverseStop;
197
} else {
198
WRITE_WARNINGF(TL("PT stop '%' has been moved to edge '%'."), stop->getID(), reverse->getID());
199
}
200
stop->setEdgeId(reverse->getID(), ec);
201
}
202
stop->addLine(line->getRef());
203
stopsRevised.back() = true;
204
}
205
line->setRevised(stopsRevised);
206
}
207
208
209
void NBPTLineCont::reviseSingleWayStops(NBPTLine* line, const NBEdgeCont& ec, NBPTStopCont& sc) {
210
const std::vector<std::string>& waysIds = line->getWays();
211
for (std::shared_ptr<NBPTStop> stop : line->getStops()) {
212
//get the corresponding and one of the two adjacent ways
213
stop = findWay(line, stop, ec, sc);
214
if (stop == nullptr) {
215
// warning already given
216
continue;
217
}
218
auto waysIdsIt = std::find(waysIds.begin(), waysIds.end(), stop->getOrigEdgeId());
219
if (waysIdsIt == waysIds.end()) {
220
// warning already given
221
continue;
222
}
223
stop->addLine(line->getRef());
224
}
225
}
226
227
228
std::shared_ptr<NBPTStop>
229
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
if (stop->isLoose()) {
237
// find closest edge in route
238
double minDist = std::numeric_limits<double>::max();
239
NBEdge* best = nullptr;
240
for (NBEdge* edge : line->getRoute()) {
241
const double dist = edge->getLaneShape(0).distance2D(stop->getPosition());
242
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
if (minDist < OptionsCont::getOptions().getFloat("ptline.match-dist")) {
255
const std::string wayID = getWayID(best->getID());
256
if (stop->getEdgeId() == "") {
257
stop->setEdgeId(best->getID(), ec);
258
stop->setOrigEdgeId(wayID);
259
} 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
std::shared_ptr<NBPTStop> newStop = sc.findStop(wayID, stop->getPosition());
263
if (newStop == nullptr) {
264
newStop = std::make_shared<NBPTStop>(stop->getElement(), stop->getID() + "@" + line->getLineID(), stop->getPosition(), best->getID(), wayID, stop->getLength(), stop->getName(), stop->getPermissions());
265
newStop->setEdgeId(best->getID(), ec); // trigger lane assignment
266
sc.insert(newStop);
267
}
268
line->replaceStop(stop, newStop);
269
stop = newStop;
270
}
271
} else {
272
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
for (; waysIdsIt != waysIds.end(); waysIdsIt++) {
280
if ((*waysIdsIt) == stop->getOrigEdgeId()) {
281
break;
282
}
283
}
284
285
if (waysIdsIt == waysIds.end()) {
286
// stop edge not found, try additional edges
287
for (auto& edgeCand : stop->getAdditionalEdgeCandidates()) {
288
bool found = false;
289
waysIdsIt = waysIds.begin();
290
for (; waysIdsIt != waysIds.end(); waysIdsIt++) {
291
if ((*waysIdsIt) == edgeCand.first) {
292
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
if (waysIdsIt == waysIds.end()) {
304
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
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
for (auto it3 = pTLine->getWays().begin(); it3 != pTLine->getWays().end(); it3++) {
322
323
int foundForward = 0;
324
if (cont.retrieve(*it3, false) != nullptr) {
325
currentWayEdges.push_back(cont.retrieve(*it3, false));
326
foundForward++;
327
} else {
328
int i = 0;
329
while (cont.retrieve(*it3 + "#" + std::to_string(i), true) != nullptr) {
330
if (cont.retrieve(*it3 + "#" + std::to_string(i), false)) {
331
currentWayEdges.push_back(cont.retrieve(*it3 + "#" + std::to_string(i), false));
332
foundForward++;
333
}
334
i++;
335
}
336
}
337
338
int foundReverse = 0;
339
if (cont.retrieve("-" + *it3, false) != nullptr) {
340
currentWayMinusEdges.push_back(cont.retrieve("-" + *it3, false));
341
foundReverse++;
342
} else {
343
int i = 0;
344
while (cont.retrieve("-" + *it3 + "#" + std::to_string(i), true) != nullptr) {
345
if (cont.retrieve("-" + *it3 + "#" + std::to_string(i), false)) {
346
currentWayMinusEdges.insert(currentWayMinusEdges.end() - foundReverse,
347
cont.retrieve("-" + *it3 + "#" + std::to_string(i), false));
348
foundReverse++;
349
}
350
i++;
351
}
352
}
353
bool fakeMinus = false;
354
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
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
if (currentWayEdges.empty()) {
374
continue;
375
}
376
if (last == currentWayEdges.front()->getFromNode() && last != nullptr) {
377
if (!prevWayEdges.empty()) {
378
edges.insert(edges.end(), prevWayEdges.begin(), prevWayEdges.end());
379
prevWayEdges.clear();
380
prevWayMinusEdges.clear();
381
}
382
edges.insert(edges.end(), currentWayEdges.begin(), currentWayEdges.end());
383
last = currentWayEdges.back()->getToNode();
384
} else if (last == currentWayEdges.back()->getToNode() && last != nullptr) {
385
if (!prevWayEdges.empty()) {
386
edges.insert(edges.end(), prevWayEdges.begin(), prevWayEdges.end());
387
prevWayEdges.clear();
388
prevWayMinusEdges.clear();
389
}
390
if (currentWayMinusEdges.empty()) {
391
currentWayEdges.clear();
392
last = nullptr;
393
continue;
394
} else {
395
edges.insert(edges.end(), currentWayMinusEdges.begin(), currentWayMinusEdges.end());
396
if (fakeMinus) {
397
last = currentWayMinusEdges.back()->getFromNode();
398
} else {
399
last = currentWayMinusEdges.back()->getToNode();
400
}
401
}
402
} else if (first == currentWayEdges.front()->getFromNode() && first != nullptr) {
403
edges.insert(edges.end(), prevWayMinusEdges.begin(), prevWayMinusEdges.end());
404
edges.insert(edges.end(), currentWayEdges.begin(), currentWayEdges.end());
405
last = currentWayEdges.back()->getToNode();
406
prevWayEdges.clear();
407
prevWayMinusEdges.clear();
408
} else if (first == currentWayEdges.back()->getToNode() && first != nullptr) {
409
edges.insert(edges.end(), prevWayMinusEdges.begin(), prevWayMinusEdges.end());
410
if (currentWayMinusEdges.empty()) {
411
currentWayEdges.clear();
412
last = nullptr;
413
prevWayEdges.clear();
414
prevWayMinusEdges.clear();
415
continue;
416
} else {
417
edges.insert(edges.end(), currentWayMinusEdges.begin(), currentWayMinusEdges.end());
418
last = currentWayMinusEdges.back()->getToNode();
419
prevWayEdges.clear();
420
prevWayMinusEdges.clear();
421
}
422
} else {
423
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
} else if (pTLine->getWays().size() == 1) {
432
if (currentWayEdges.size() > 0) {
433
edges.insert(edges.end(), currentWayEdges.begin(), currentWayEdges.end());
434
} else {
435
edges.insert(edges.end(), currentWayMinusEdges.begin(), currentWayMinusEdges.end());
436
}
437
}
438
prevWayEdges = currentWayEdges;
439
prevWayMinusEdges = currentWayMinusEdges;
440
if (!prevWayEdges.empty()) {
441
first = prevWayEdges.front()->getFromNode();
442
last = prevWayEdges.back()->getToNode();
443
} else {
444
first = nullptr;
445
last = nullptr;
446
}
447
}
448
currentWayEdges.clear();
449
currentWayMinusEdges.clear();
450
}
451
pTLine->setEdges(edges);
452
}
453
454
455
void
456
NBPTLineCont::replaceEdge(const std::string& edgeID, const EdgeVector& replacement) {
457
//std::cout << " replaceEdge " << edgeID << " replacement=" << toString(replacement) << "\n";
458
if (myPTLines.size() > 0 && myPTLineLookup.size() == 0) {
459
// init lookup once
460
for (auto& item : myPTLines) {
461
for (const NBEdge* e : item.second->getRoute()) {
462
myPTLineLookup[e->getID()].insert(item.second);
463
}
464
}
465
}
466
for (NBPTLine* line : myPTLineLookup[edgeID]) {
467
line->replaceEdge(edgeID, replacement);
468
for (const NBEdge* e : replacement) {
469
myPTLineLookup[e->getID()].insert(line);
470
}
471
}
472
myPTLineLookup.erase(edgeID);
473
}
474
475
476
std::set<std::string>
477
NBPTLineCont::getServedPTStops() {
478
std::set<std::string> result;
479
for (auto& item : myPTLines) {
480
NBPTLine* line = item.second;
481
for (std::shared_ptr<NBPTStop> stop : line->getStops()) {
482
result.insert(stop->getID());
483
}
484
}
485
return result;
486
}
487
488
489
void
490
NBPTLineCont::fixBidiStops(const NBEdgeCont& ec) {
491
std::map<std::string, SUMOVehicleClass> types;
492
types["bus"] = SVC_BUS;
493
types["minibus"] = SVC_BUS;
494
types["trolleybus"] = SVC_BUS;
495
types["tram"] = SVC_TRAM;
496
types["train"] = SVC_RAIL;
497
types["subway"] = SVC_RAIL_URBAN;
498
types["light_rail"] = SVC_RAIL_URBAN;
499
types["monorail"] = SVC_RAIL_URBAN;
500
types["aerialway"] = SVC_RAIL_URBAN;
501
types["ferry"] = SVC_SHIP;
502
503
SUMOAbstractRouter<NBRouterEdge, NBVehicle>* const router = new DijkstraRouter<NBRouterEdge, NBVehicle>(
504
ec.getAllRouterEdges(), true, &NBRouterEdge::getTravelTimeStatic, nullptr, true);
505
506
for (auto& item : myPTLines) {
507
NBPTLine* line = item.second;
508
std::vector<std::shared_ptr<NBPTStop> > stops = line->getStops();
509
if (stops.size() < 2) {
510
continue;
511
}
512
if (types.count(line->getType()) == 0) {
513
WRITE_WARNINGF(TL("Could not determine vehicle class for public transport line of type '%'."), line->getType());
514
continue;
515
}
516
NBVehicle veh(line->getRef(), types[line->getType()]);
517
std::vector<std::shared_ptr<NBPTStop> > newStops;
518
std::shared_ptr<NBPTStop> from = nullptr;
519
std::vector<NBPTLine::PTStopInfo> stopInfos = line->getStopEdges(ec);
520
assert(stopInfos.size() == stops.size());
521
for (auto it = stops.begin(); it != stops.end(); ++it) {
522
std::shared_ptr<NBPTStop> to = *it;
523
std::shared_ptr<NBPTStop> used = *it;
524
bool isRevised = stopInfos[it - stops.begin()].revised;
525
if (to->getBidiStop() != nullptr && !isRevised) {
526
double best = std::numeric_limits<double>::max();
527
std::shared_ptr<NBPTStop> to2 = to->getBidiStop();
528
if (from == nullptr) {
529
if ((it + 1) != stops.end()) {
530
from = to;
531
std::shared_ptr<NBPTStop> from2 = to2;
532
to = *(it + 1);
533
const double c1 = getCost(ec, *router, from, to, &veh);
534
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
if (to->getBidiStop() != nullptr) {
539
to2 = to->getBidiStop();
540
const double c3 = getCost(ec, *router, from, to2, &veh);
541
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
if (c2 < best) {
545
used = from2;
546
best = c2;
547
}
548
if (c3 < best) {
549
used = from;
550
best = c3;
551
}
552
if (c4 < best) {
553
used = from2;
554
best = c4;
555
}
556
} else {
557
if (c2 < c1) {
558
used = from2;
559
best = c2;
560
} else {
561
best = c1;
562
}
563
}
564
}
565
} else {
566
const double c1 = getCost(ec, *router, from, to, &veh);
567
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
if (c2 < c1) {
571
used = to2;
572
best = c2;
573
} else {
574
best = c1;
575
}
576
577
}
578
if (best < std::numeric_limits<double>::max()) {
579
from = used;
580
} else {
581
WRITE_WARNINGF(TL("Could not determine direction for line '%' at stop '%'."), line->getLineID(), used->getID());
582
}
583
}
584
from = used;
585
newStops.push_back(used);
586
}
587
assert(stops.size() == newStops.size());
588
line->replaceStops(newStops);
589
}
590
delete router;
591
}
592
593
594
void
595
NBPTLineCont::removeInvalidEdges(const NBEdgeCont& ec) {
596
for (auto& item : myPTLines) {
597
item.second->removeInvalidEdges(ec);
598
}
599
}
600
601
602
void
603
NBPTLineCont::fixPermissions() {
604
for (auto& item : myPTLines) {
605
NBPTLine* line = item.second;
606
const std::vector<NBEdge*>& route = line->getRoute();
607
const SUMOVehicleClass svc = line->getVClass();
608
for (int i = 1; i < (int)route.size(); i++) {
609
NBEdge* e1 = route[i - 1];
610
NBEdge* e2 = route[i];
611
std::vector<NBEdge::Connection> cons = e1->getConnectionsFromLane(-1, e2, -1);
612
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
for (const auto& c : cons) {
617
if ((e1->getPermissions(c.fromLane) & svc) == svc) {
618
ok = true;
619
break;
620
}
621
}
622
if (!ok) {
623
int lane = cons[0].fromLane;
624
e1->setPermissions(e1->getPermissions(lane) | svc, lane);
625
}
626
}
627
}
628
}
629
}
630
631
632
double
633
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
NBEdge* fromEdge = ec.getByID(from->getEdgeId());
636
NBEdge* toEdge = ec.getByID(to->getEdgeId());
637
if (fromEdge == nullptr || toEdge == nullptr) {
638
return std::numeric_limits<double>::max();
639
} else if (fromEdge == toEdge) {
640
if (from->getEndPos() <= to->getEndPos()) {
641
return to->getEndPos() - from->getEndPos();
642
} else {
643
return std::numeric_limits<double>::max();
644
}
645
} else if (fromEdge->getBidiEdge() == toEdge) {
646
return std::numeric_limits<double>::max();
647
}
648
std::vector<const NBRouterEdge*> route;
649
router.compute(fromEdge, toEdge, veh, 0, route);
650
if (route.size() == 0) {
651
return std::numeric_limits<double>::max();
652
} else {
653
return router.recomputeCosts(route, veh, 0);
654
}
655
}
656
657
658
std::string
659
NBPTLineCont::getWayID(const std::string& edgeID) {
660
std::size_t found = edgeID.rfind("#");
661
std::string result = edgeID;
662
if (found != std::string::npos) {
663
result = edgeID.substr(0, found);
664
}
665
if (result[0] == '-') {
666
result = result.substr(1);
667
}
668
return result;
669
}
670
671
672
/****************************************************************************/
673
674