Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/router/RORouteDef.cpp
193863 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2002-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 RORouteDef.cpp
15
/// @author Daniel Krajzewicz
16
/// @author Michael Behrisch
17
/// @author Jakob Erdmann
18
/// @date Sept 2002
19
///
20
// Base class for a vehicle's route definition
21
/****************************************************************************/
22
#include <config.h>
23
24
#include <string>
25
#include <iterator>
26
#include <algorithm>
27
#include <utils/common/StringUtils.h>
28
#include <utils/common/ToString.h>
29
#include <utils/common/Named.h>
30
#include <utils/common/StringUtils.h>
31
#include <utils/common/MsgHandler.h>
32
#include <utils/common/RandHelper.h>
33
#include <utils/iodevices/OutputDevice.h>
34
#include <utils/options/OptionsCont.h>
35
#include "ROEdge.h"
36
#include "RORoute.h"
37
#include <utils/router/SUMOAbstractRouter.h>
38
#include <utils/router/RouteCostCalculator.h>
39
#include "RORouteDef.h"
40
#include "ROVehicle.h"
41
42
// ===========================================================================
43
// static members
44
// ===========================================================================
45
bool RORouteDef::myUsingJTRR(false);
46
bool RORouteDef::mySkipNewRoutes(false);
47
48
// ===========================================================================
49
// method definitions
50
// ===========================================================================
51
RORouteDef::RORouteDef(const std::string& id, const int lastUsed,
52
const bool tryRepair, const bool mayBeDisconnected) :
53
Named(StringUtils::convertUmlaute(id)),
54
myPrecomputed(nullptr), myLastUsed(lastUsed), myTryRepair(tryRepair),
55
myMayBeDisconnected(mayBeDisconnected),
56
myDiscardSilent(false) {
57
}
58
59
60
RORouteDef::~RORouteDef() {
61
for (std::vector<RORoute*>::iterator i = myAlternatives.begin(); i != myAlternatives.end(); i++) {
62
if (myRouteRefs.count(*i) == 0) {
63
delete *i;
64
}
65
}
66
}
67
68
69
void
70
RORouteDef::addLoadedAlternative(RORoute* alt) {
71
myAlternatives.push_back(alt);
72
}
73
74
75
void
76
RORouteDef::addAlternativeDef(const RORouteDef* alt) {
77
std::copy(alt->myAlternatives.begin(), alt->myAlternatives.end(),
78
back_inserter(myAlternatives));
79
std::copy(alt->myAlternatives.begin(), alt->myAlternatives.end(),
80
std::inserter(myRouteRefs, myRouteRefs.end()));
81
}
82
83
84
RORoute*
85
RORouteDef::buildCurrentRoute(SUMOAbstractRouter<ROEdge, ROVehicle>& router,
86
SUMOTime begin, const ROVehicle& veh) const {
87
if (myPrecomputed == nullptr) {
88
preComputeCurrentRoute(router, begin, veh);
89
}
90
return myPrecomputed;
91
}
92
93
94
void
95
RORouteDef::validateAlternatives(const ROVehicle* veh, MsgHandler* errorHandler) {
96
for (int i = 0; i < (int)myAlternatives.size();) {
97
if (i != myLastUsed || mySkipNewRoutes) {
98
if (myAlternatives[i]->isPermitted(veh, errorHandler)) {
99
i++;
100
} else {
101
myAlternatives.erase(myAlternatives.begin() + i);
102
if (myLastUsed > i) {
103
myLastUsed--;
104
}
105
}
106
} else {
107
i++;
108
}
109
}
110
}
111
112
113
void
114
RORouteDef::preComputeCurrentRoute(SUMOAbstractRouter<ROEdge, ROVehicle>& router,
115
SUMOTime begin, const ROVehicle& veh) const {
116
myNewRoute = false;
117
const OptionsCont& oc = OptionsCont::getOptions();
118
const bool ignoreErrors = oc.getBool("ignore-errors");
119
const bool hasRestrictions = RONet::getInstance()->hasParamRestrictions();
120
assert(myAlternatives[0]->getEdgeVector().size() > 0);
121
MsgHandler* mh = ignoreErrors ? MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance();
122
if (myAlternatives[0]->getFirst()->prohibits(&veh, hasRestrictions) && (!oc.getBool("repair.from")
123
// do not try to reassign starting edge for trip input
124
|| myMayBeDisconnected || myAlternatives[0]->getEdgeVector().size() < 2)) {
125
mh->inform("Vehicle '" + veh.getID() + "' is not allowed to depart on edge '" +
126
myAlternatives[0]->getFirst()->getID() + "'.");
127
return;
128
} else if (myAlternatives[0]->getLast()->prohibits(&veh, hasRestrictions) && (!oc.getBool("repair.to")
129
// do not try to reassign destination edge for trip input
130
|| myMayBeDisconnected || myAlternatives[0]->getEdgeVector().size() < 2)) {
131
// this check is not strictly necessary unless myTryRepair is set.
132
// However, the error message is more helpful than "no connection found"
133
mh->inform("Vehicle '" + veh.getID() + "' is not allowed to arrive on edge '" +
134
myAlternatives[0]->getLast()->getID() + "'.");
135
return;
136
}
137
const bool skipTripRouting = (oc.exists("write-trips") && oc.getBool("write-trips")
138
&& RouteCostCalculator<RORoute, ROEdge, ROVehicle>::getCalculator().skipRouteCalculation());
139
if ((myTryRepair && !skipTripRouting) || myUsingJTRR) {
140
ConstROEdgeVector newEdges;
141
if (repairCurrentRoute(router, begin, veh, myAlternatives[0]->getEdgeVector(), newEdges)) {
142
if (myAlternatives[0]->getEdgeVector() != newEdges) {
143
if (!myMayBeDisconnected) {
144
WRITE_WARNINGF(TL("Repaired route of vehicle '%'."), veh.getID());
145
}
146
myNewRoute = true;
147
RGBColor* col = myAlternatives[0]->getColor() != nullptr ? new RGBColor(*myAlternatives[0]->getColor()) : nullptr;
148
myPrecomputed = new RORoute(myID, 0, myAlternatives[0]->getProbability(), newEdges, col, myAlternatives[0]->getStops());
149
} else {
150
myPrecomputed = myAlternatives[0];
151
}
152
}
153
return;
154
}
155
if ((RouteCostCalculator<RORoute, ROEdge, ROVehicle>::getCalculator().skipRouteCalculation()
156
|| OptionsCont::getOptions().getBool("remove-loops"))
157
&& (skipTripRouting || myAlternatives[myLastUsed]->isValid(veh, ignoreErrors))) {
158
myPrecomputed = myAlternatives[myLastUsed];
159
} else {
160
// build a new route to test whether it is better
161
ConstROEdgeVector oldEdges({getOrigin(), getDestination()});
162
ConstROEdgeVector edges;
163
if (repairCurrentRoute(router, begin, veh, oldEdges, edges, true)) {
164
if (edges.front()->isTazConnector()) {
165
edges.erase(edges.begin());
166
}
167
if (edges.back()->isTazConnector()) {
168
edges.pop_back();
169
}
170
// check whether the same route was already used
171
int existing = -1;
172
for (int i = 0; i < (int)myAlternatives.size(); i++) {
173
if (edges == myAlternatives[i]->getEdgeVector()) {
174
existing = i;
175
break;
176
}
177
}
178
if (existing >= 0) {
179
myPrecomputed = myAlternatives[existing];
180
} else {
181
RGBColor* col = myAlternatives[0]->getColor() != nullptr ? new RGBColor(*myAlternatives[0]->getColor()) : nullptr;
182
myPrecomputed = new RORoute(myID, 0, 1, edges, col, myAlternatives[0]->getStops());
183
myNewRoute = true;
184
}
185
}
186
}
187
}
188
189
190
bool
191
RORouteDef::repairCurrentRoute(SUMOAbstractRouter<ROEdge, ROVehicle>& router,
192
SUMOTime begin, const ROVehicle& veh,
193
ConstROEdgeVector oldEdges, ConstROEdgeVector& newEdges,
194
bool isTrip) const {
195
MsgHandler* mh = (OptionsCont::getOptions().getBool("ignore-errors") ?
196
MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance());
197
RONet* net = RONet::getInstance();
198
const int initialSize = (int)oldEdges.size();
199
const bool hasRestrictions = RONet::getInstance()->hasParamRestrictions();
200
if (net->getProhibitions().size() > 0 && !router.hasProhibitions()) {
201
router.prohibit(net->getProhibitions());
202
}
203
net->updateLaneProhibitions(begin);
204
if (initialSize == 1) {
205
if (myUsingJTRR) {
206
/// only ROJTRRouter is supposed to handle this type of input
207
bool ok = router.compute(oldEdges.front(), nullptr, &veh, begin, newEdges);
208
myDiscardSilent = ok && newEdges.size() == 0;
209
} else {
210
newEdges = oldEdges;
211
}
212
} else {
213
if (oldEdges.front()->prohibits(&veh, hasRestrictions)) {
214
// option repair.from is in effect
215
const std::string& frontID = oldEdges.front()->getID();
216
for (ConstROEdgeVector::iterator i = oldEdges.begin(); i != oldEdges.end();) {
217
if ((*i)->prohibits(&veh, hasRestrictions) || (*i)->isInternal()) {
218
i = oldEdges.erase(i);
219
} else {
220
WRITE_MESSAGE("Changing invalid starting edge '" + frontID
221
+ "' to '" + (*i)->getID() + "' for vehicle '" + veh.getID() + "'.");
222
break;
223
}
224
}
225
}
226
if (oldEdges.size() == 0) {
227
mh->inform("Could not find new starting edge for vehicle '" + veh.getID() + "'.");
228
return false;
229
}
230
if (oldEdges.back()->prohibits(&veh, hasRestrictions)) {
231
// option repair.to is in effect
232
const std::string& backID = oldEdges.back()->getID();
233
// oldEdges cannot get empty here, otherwise we would have left the stage when checking "from"
234
while (oldEdges.back()->prohibits(&veh, hasRestrictions) || oldEdges.back()->isInternal()) {
235
oldEdges.pop_back();
236
}
237
WRITE_MESSAGE("Changing invalid destination edge '" + backID
238
+ "' to edge '" + oldEdges.back()->getID() + "' for vehicle '" + veh.getID() + "'.");
239
}
240
std::vector<ROVehicle::Mandatory> mandatory = veh.getMandatoryEdges(oldEdges.front(), oldEdges.back());
241
assert(mandatory.size() >= 2);
242
// removed prohibited
243
for (ConstROEdgeVector::iterator i = oldEdges.begin(); i != oldEdges.end();) {
244
if ((*i)->prohibits(&veh, hasRestrictions) || (*i)->isInternal()) {
245
// no need to check the mandatories here, this was done before
246
WRITE_MESSAGEF(TL("Removing invalid edge '%' from route for vehicle '%'."), (*i)->getID(), veh.getID());
247
i = oldEdges.erase(i);
248
} else {
249
++i;
250
}
251
}
252
// reconnect remaining edges
253
if (mandatory.size() > oldEdges.size() && initialSize > 2) {
254
WRITE_MESSAGEF(TL("There are stop edges which were not part of the original route for vehicle '%'."), veh.getID());
255
}
256
ConstROEdgeVector targets;
257
bool checkPositions = false;
258
if (mandatory.size() >= oldEdges.size()) {
259
for (auto m : mandatory) {
260
targets.push_back(m.edge);
261
checkPositions |= m.pos >= 0;
262
}
263
} else {
264
targets = oldEdges;
265
}
266
newEdges.push_back(targets.front());
267
auto nextMandatory = mandatory.begin() + 1;
268
int lastMandatory = 0;
269
for (ConstROEdgeVector::const_iterator i = targets.begin() + 1;
270
i != targets.end() && nextMandatory != mandatory.end(); ++i) {
271
const ROEdge* prev = *(i - 1);
272
const ROEdge* cur = *i;
273
if (prev->isConnectedTo(*cur, veh.getVClass()) && (!isRailway(veh.getVClass()) || prev->getBidiEdge() != cur)) {
274
newEdges.push_back(cur);
275
} else {
276
if (initialSize > 2) {
277
// only inform if the input is (probably) not a trip
278
WRITE_MESSAGEF(TL("Edge '%' not connected to edge '%' for vehicle '%'."), (*(i - 1))->getID(), (*i)->getID(), veh.getID());
279
}
280
const ROEdge* last = newEdges.back();
281
newEdges.pop_back();
282
if (last->isTazConnector() && newEdges.size() > 1) {
283
// assume this was a viaTaz
284
last = newEdges.back();
285
newEdges.pop_back();
286
}
287
if (veh.hasJumps() && (nextMandatory - 1)->isJump) {
288
while (*i != nextMandatory->edge) {
289
++i;
290
}
291
newEdges.push_back(last);
292
newEdges.push_back(*i);
293
//std::cout << " skipJump mIndex=" << (nextMandatory - 1 - mandatory.begin()) << " last=" << last->getID() << " next=" << (*i)->getID() << " newEdges=" << toString(newEdges) << "\n";
294
} else {
295
296
int numEdgesBefore = (int)newEdges.size();
297
// router.setHint(targets.begin(), i, &veh, begin);
298
if (myTryRepair && lastMandatory < (int)newEdges.size() && last != newEdges[lastMandatory]) {
299
router.setMsgHandler(MsgHandler::getWarningInstance());
300
}
301
bool ok;
302
if (checkPositions
303
&& mandatory[i - targets.begin() - 1].pos >= 0
304
&& mandatory[i - targets.begin()].pos >= 0) {
305
ok = router.compute(
306
last, mandatory[i - targets.begin() - 1].pos,
307
*i, mandatory[i - targets.begin()].pos,
308
&veh, begin, newEdges);
309
} else {
310
ok = router.compute(last, *i, &veh, begin, newEdges);
311
}
312
router.setMsgHandler(mh);
313
if (!ok) {
314
// backtrack: try to route from last mandatory edge to next mandatory edge
315
// XXX add option for backtracking in smaller increments
316
// (i.e. previous edge to edge after *i)
317
// we would then need to decide whether we have found a good
318
// tradeoff between faithfulness to the input data and detour-length
319
if (lastMandatory >= (int)newEdges.size() || last == newEdges[lastMandatory] || !backTrack(router, i, lastMandatory, nextMandatory->edge, newEdges, veh, begin)) {
320
mh->inform("Mandatory edge '" + (*i)->getID() + "' not reachable by vehicle '" + veh.getID() + "'.");
321
return false;
322
}
323
} else if (!myMayBeDisconnected && !isTrip && last != (*i)) {
324
double airDist = last->getToJunction()->getPosition().distanceTo(
325
(*i)->getFromJunction()->getPosition());
326
double repairDist = 0;
327
for (auto it2 = (newEdges.begin() + numEdgesBefore + 1); it2 != newEdges.end() && it2 != newEdges.end() - 1; it2++) {
328
repairDist += (*it2)->getLength();
329
}
330
const double detourFactor = repairDist / MAX2(airDist, 1.0);
331
const double detour = MAX2(0.0, repairDist - airDist);
332
const double maxDetourFactor = OptionsCont::getOptions().getFloat("repair.max-detour-factor");
333
if (detourFactor > maxDetourFactor) {
334
WRITE_MESSAGEF(" Backtracking to avoid detour of %m for gap of %m)", detour, airDist);
335
backTrack(router, i, lastMandatory, nextMandatory->edge, newEdges, veh, begin);
336
} else if (detourFactor > 1.1) {
337
WRITE_MESSAGEF(" Taking detour of %m to avoid gap of %m)", detour, airDist);
338
}
339
}
340
}
341
}
342
if (*i == nextMandatory->edge) {
343
nextMandatory++;
344
lastMandatory = (int)newEdges.size() - 1;
345
}
346
}
347
if (veh.getParameter().via.size() > 0 && veh.getParameter().stops.size() > 0) {
348
// check consistency of stops and vias
349
auto it = newEdges.begin();
350
for (const auto& stop : veh.getParameter().stops) {
351
const ROEdge* e = net->getEdge(stop.edge);
352
it = std::find(it, newEdges.end(), e);
353
if (it == newEdges.end()) {
354
mh->inform("Stop edge '" + e->getID() + "' is inconsistent with via edges for vehicle '" + veh.getID() + "'.");
355
return false;
356
}
357
}
358
}
359
}
360
return true;
361
}
362
363
364
bool
365
RORouteDef::backTrack(SUMOAbstractRouter<ROEdge, ROVehicle>& router,
366
ConstROEdgeVector::const_iterator& i, int lastMandatory, const ROEdge* nextMandatory,
367
ConstROEdgeVector& newEdges, const ROVehicle& veh, SUMOTime begin) {
368
ConstROEdgeVector edges;
369
bool ok = router.compute(newEdges[lastMandatory], nextMandatory, &veh, begin, edges, true);
370
if (!ok) {
371
return false;
372
}
373
374
while (*i != nextMandatory) {
375
++i;
376
}
377
newEdges.erase(newEdges.begin() + lastMandatory + 1, newEdges.end());
378
std::copy(edges.begin() + 1, edges.end(), back_inserter(newEdges));
379
return true;
380
}
381
382
383
void
384
RORouteDef::addAlternative(SUMOAbstractRouter<ROEdge, ROVehicle>& router,
385
const ROVehicle* const veh, RORoute* current, SUMOTime begin,
386
MsgHandler* errorHandler) {
387
if (myTryRepair || myUsingJTRR) {
388
if (myNewRoute) {
389
delete myAlternatives[0];
390
myAlternatives[0] = current;
391
}
392
if (!router.isValid(current->getEdgeVector(), veh, STEPS2TIME(begin))) {
393
throw ProcessError("Route '" + getID() + "' (vehicle '" + veh->getID() + "') is not valid.");
394
}
395
double costs = router.recomputeCosts(current->getEdgeVector(), veh, begin);
396
if (veh->hasJumps()) {
397
// @todo: jumpTime should be applied in recomputeCost to ensure the
398
// correctness of time-dependent traveltimes
399
costs += STEPS2TIME(veh->getJumpTime());
400
}
401
current->setCosts(costs);
402
return;
403
}
404
// add the route when it's new
405
if (myAlternatives.back()->getProbability() < 0 || !myAlternatives.back()->isPermitted(veh, errorHandler)) {
406
if (myAlternatives.back()->getProbability() >= 0 && errorHandler == MsgHandler::getErrorInstance()) {
407
throw ProcessError("Route '" + current->getID() + "' (vehicle '" + veh->getID() + "') is not valid.");
408
}
409
delete myAlternatives.back();
410
myAlternatives.pop_back();
411
}
412
if (myNewRoute) {
413
myAlternatives.push_back(current);
414
}
415
// recompute the costs and (when a new route was added) scale the probabilities
416
const double scale = double(myAlternatives.size() - 1) / double(myAlternatives.size());
417
for (RORoute* const alt : myAlternatives) {
418
if (!router.isValid(alt->getEdgeVector(), veh, STEPS2TIME(begin))) {
419
throw ProcessError("Route '" + current->getID() + "' (vehicle '" + veh->getID() + "') is not valid.");
420
}
421
// recompute the costs for all routes
422
const double newCosts = router.recomputeCosts(alt->getEdgeVector(), veh, begin);
423
assert(myAlternatives.size() != 0);
424
if (myNewRoute) {
425
if (alt == current) {
426
// set initial probability and costs
427
alt->setProbability(1. / (double) myAlternatives.size());
428
alt->setCosts(newCosts);
429
} else {
430
// rescale probs for all others
431
alt->setProbability(alt->getProbability() * scale);
432
}
433
}
434
RouteCostCalculator<RORoute, ROEdge, ROVehicle>::getCalculator().setCosts(alt, newCosts, alt == myAlternatives[myLastUsed]);
435
}
436
assert(myAlternatives.size() != 0);
437
RouteCostCalculator<RORoute, ROEdge, ROVehicle>::getCalculator().calculateProbabilities(myAlternatives, veh, veh->getDepartureTime());
438
const bool keepRoute = RouteCostCalculator<RORoute, ROEdge, ROVehicle>::getCalculator().keepRoute();
439
if (!RouteCostCalculator<RORoute, ROEdge, ROVehicle>::getCalculator().keepAllRoutes() && !keepRoute) {
440
// remove with probability of 0 (not mentioned in Gawron)
441
for (std::vector<RORoute*>::iterator i = myAlternatives.begin(); i != myAlternatives.end();) {
442
if ((*i)->getProbability() == 0) {
443
delete *i;
444
i = myAlternatives.erase(i);
445
} else {
446
i++;
447
}
448
}
449
}
450
int maxNumber = RouteCostCalculator<RORoute, ROEdge, ROVehicle>::getCalculator().getMaxRouteNumber();
451
if ((int)myAlternatives.size() > maxNumber) {
452
const RORoute* last = myAlternatives[myLastUsed];
453
// only keep the routes with highest probability
454
sort(myAlternatives.begin(), myAlternatives.end(), [](const RORoute * const a, const RORoute * const b) {
455
return a->getProbability() > b->getProbability();
456
});
457
if (keepRoute) {
458
for (int i = 0; i < (int)myAlternatives.size(); i++) {
459
if (myAlternatives[i] == last) {
460
myLastUsed = i;
461
break;
462
}
463
}
464
if (myLastUsed >= maxNumber) {
465
std::swap(myAlternatives[maxNumber - 1], myAlternatives[myLastUsed]);
466
myLastUsed = maxNumber - 1;
467
}
468
}
469
for (std::vector<RORoute*>::iterator i = myAlternatives.begin() + maxNumber; i != myAlternatives.end(); i++) {
470
delete *i;
471
}
472
myAlternatives.erase(myAlternatives.begin() + maxNumber, myAlternatives.end());
473
}
474
// rescale probabilities
475
double newSum = 0.;
476
for (const RORoute* const alt : myAlternatives) {
477
newSum += alt->getProbability();
478
}
479
assert(newSum > 0);
480
// @note newSum may be larger than 1 for numerical reasons
481
for (RORoute* const alt : myAlternatives) {
482
alt->setProbability(alt->getProbability() / newSum);
483
}
484
485
// find the route to use
486
if (!keepRoute) {
487
double chosen = RandHelper::rand();
488
myLastUsed = 0;
489
for (const RORoute* const alt : myAlternatives) {
490
chosen -= alt->getProbability();
491
if (chosen <= 0) {
492
return;
493
}
494
myLastUsed++;
495
}
496
}
497
}
498
499
const ROEdge*
500
RORouteDef::getOrigin() const {
501
return myAlternatives.back()->getFirst();
502
}
503
504
505
const ROEdge*
506
RORouteDef::getDestination() const {
507
return myAlternatives.back()->getLast();
508
}
509
510
511
OutputDevice&
512
RORouteDef::writeXMLDefinition(OutputDevice& dev, const ROVehicle* const veh,
513
bool asAlternatives, bool withExitTimes, bool withCost, bool withLength) const {
514
if (asAlternatives) {
515
dev.openTag(SUMO_TAG_ROUTE_DISTRIBUTION).writeAttr(SUMO_ATTR_LAST, myLastUsed);
516
for (int i = 0; i != (int)myAlternatives.size(); i++) {
517
myAlternatives[i]->writeXMLDefinition(dev, veh, true, true, withExitTimes, withLength);
518
}
519
dev.closeTag();
520
return dev;
521
} else {
522
return myAlternatives[myLastUsed]->writeXMLDefinition(dev, veh, withCost, false, withExitTimes, withLength);
523
}
524
}
525
526
527
RORouteDef*
528
RORouteDef::copy(const std::string& id, const SUMOTime stopOffset) const {
529
RORouteDef* result = new RORouteDef(id, 0, myTryRepair, myMayBeDisconnected);
530
for (const RORoute* const route : myAlternatives) {
531
RGBColor* col = route->getColor() != nullptr ? new RGBColor(*route->getColor()) : nullptr;
532
RORoute* newRoute = new RORoute(id, route->getCosts(), route->getProbability(), route->getEdgeVector(), col, route->getStops());
533
newRoute->addStopOffset(stopOffset);
534
result->addLoadedAlternative(newRoute);
535
}
536
return result;
537
}
538
539
540
double
541
RORouteDef::getOverallProb() const {
542
double sum = 0.;
543
for (std::vector<RORoute*>::const_iterator i = myAlternatives.begin(); i != myAlternatives.end(); i++) {
544
sum += (*i)->getProbability();
545
}
546
return sum;
547
}
548
549
550
/****************************************************************************/
551
552