Line data Source code
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 301824 : RORouteDef::RORouteDef(const std::string& id, const int lastUsed,
52 301824 : const bool tryRepair, const bool mayBeDisconnected) :
53 301824 : Named(StringUtils::convertUmlaute(id)),
54 301824 : myPrecomputed(nullptr), myLastUsed(lastUsed), myTryRepair(tryRepair),
55 301824 : myMayBeDisconnected(mayBeDisconnected),
56 301824 : myDiscardSilent(false) {
57 301824 : }
58 :
59 :
60 603648 : RORouteDef::~RORouteDef() {
61 760425 : for (std::vector<RORoute*>::iterator i = myAlternatives.begin(); i != myAlternatives.end(); i++) {
62 : if (myRouteRefs.count(*i) == 0) {
63 458597 : delete *i;
64 : }
65 : }
66 603648 : }
67 :
68 :
69 : void
70 443707 : RORouteDef::addLoadedAlternative(RORoute* alt) {
71 443707 : myAlternatives.push_back(alt);
72 443707 : }
73 :
74 :
75 : void
76 4 : RORouteDef::addAlternativeDef(const RORouteDef* alt) {
77 : std::copy(alt->myAlternatives.begin(), alt->myAlternatives.end(),
78 4 : back_inserter(myAlternatives));
79 : std::copy(alt->myAlternatives.begin(), alt->myAlternatives.end(),
80 4 : std::inserter(myRouteRefs, myRouteRefs.end()));
81 4 : }
82 :
83 :
84 : RORoute*
85 296781 : RORouteDef::buildCurrentRoute(SUMOAbstractRouter<ROEdge, ROVehicle>& router,
86 : SUMOTime begin, const ROVehicle& veh) const {
87 296781 : if (myPrecomputed == nullptr) {
88 296781 : preComputeCurrentRoute(router, begin, veh);
89 : }
90 296781 : return myPrecomputed;
91 : }
92 :
93 :
94 : void
95 296784 : RORouteDef::validateAlternatives(const ROVehicle* veh, MsgHandler* errorHandler) {
96 736094 : for (int i = 0; i < (int)myAlternatives.size();) {
97 439310 : if (i != myLastUsed || mySkipNewRoutes) {
98 143437 : if (myAlternatives[i]->isPermitted(veh, errorHandler)) {
99 143432 : i++;
100 : } else {
101 5 : myAlternatives.erase(myAlternatives.begin() + i);
102 5 : if (myLastUsed > i) {
103 0 : myLastUsed--;
104 : }
105 : }
106 : } else {
107 295873 : i++;
108 : }
109 : }
110 296784 : }
111 :
112 :
113 : void
114 296781 : RORouteDef::preComputeCurrentRoute(SUMOAbstractRouter<ROEdge, ROVehicle>& router,
115 : SUMOTime begin, const ROVehicle& veh) const {
116 296781 : myNewRoute = false;
117 296781 : const OptionsCont& oc = OptionsCont::getOptions();
118 296781 : const bool ignoreErrors = oc.getBool("ignore-errors");
119 296781 : const bool hasRestrictions = RONet::getInstance()->hasParamRestrictions();
120 : assert(myAlternatives[0]->getEdgeVector().size() > 0);
121 296781 : MsgHandler* mh = ignoreErrors ? MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance();
122 296863 : if (myAlternatives[0]->getFirst()->prohibits(&veh, hasRestrictions) && (!oc.getBool("repair.from")
123 : // do not try to reassign starting edge for trip input
124 9 : || myMayBeDisconnected || myAlternatives[0]->getEdgeVector().size() < 2)) {
125 70 : mh->inform("Vehicle '" + veh.getID() + "' is not allowed to depart on edge '" +
126 35 : myAlternatives[0]->getFirst()->getID() + "'.");
127 35 : return;
128 296788 : } else if (myAlternatives[0]->getLast()->prohibits(&veh, hasRestrictions) && (!oc.getBool("repair.to")
129 : // do not try to reassign destination edge for trip input
130 9 : || 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 30 : mh->inform("Vehicle '" + veh.getID() + "' is not allowed to arrive on edge '" +
134 15 : myAlternatives[0]->getLast()->getID() + "'.");
135 15 : return;
136 : }
137 975700 : const bool skipTripRouting = (oc.exists("write-trips") && oc.getBool("write-trips")
138 388429 : && RouteCostCalculator<RORoute, ROEdge, ROVehicle>::getCalculator().skipRouteCalculation());
139 296731 : if ((myTryRepair && !skipTripRouting) || myUsingJTRR) {
140 : ConstROEdgeVector newEdges;
141 202317 : if (repairCurrentRoute(router, begin, veh, myAlternatives[0]->getEdgeVector(), newEdges)) {
142 185176 : if (myAlternatives[0]->getEdgeVector() != newEdges) {
143 156802 : if (!myMayBeDisconnected) {
144 156 : WRITE_WARNINGF(TL("Repaired route of vehicle '%'."), veh.getID());
145 : }
146 156802 : myNewRoute = true;
147 156802 : RGBColor* col = myAlternatives[0]->getColor() != nullptr ? new RGBColor(*myAlternatives[0]->getColor()) : nullptr;
148 156802 : myPrecomputed = new RORoute(myID, 0, myAlternatives[0]->getProbability(), newEdges, col, myAlternatives[0]->getStops());
149 : } else {
150 28374 : myPrecomputed = myAlternatives[0];
151 : }
152 : }
153 : return;
154 202317 : }
155 94414 : if ((RouteCostCalculator<RORoute, ROEdge, ROVehicle>::getCalculator().skipRouteCalculation()
156 187980 : || OptionsCont::getOptions().getBool("remove-loops"))
157 94470 : && (skipTripRouting || myAlternatives[myLastUsed]->isValid(veh, ignoreErrors))) {
158 956 : myPrecomputed = myAlternatives[myLastUsed];
159 : } else {
160 : // build a new route to test whether it is better
161 93458 : ConstROEdgeVector oldEdges({getOrigin(), getDestination()});
162 : ConstROEdgeVector edges;
163 93458 : if (repairCurrentRoute(router, begin, veh, oldEdges, edges, true)) {
164 93455 : if (edges.front()->isTazConnector()) {
165 : edges.erase(edges.begin());
166 : }
167 93455 : if (edges.back()->isTazConnector()) {
168 : edges.pop_back();
169 : }
170 : // check whether the same route was already used
171 : int existing = -1;
172 135130 : for (int i = 0; i < (int)myAlternatives.size(); i++) {
173 120001 : if (edges == myAlternatives[i]->getEdgeVector()) {
174 : existing = i;
175 : break;
176 : }
177 : }
178 93455 : if (existing >= 0) {
179 78326 : myPrecomputed = myAlternatives[existing];
180 : } else {
181 15129 : RGBColor* col = myAlternatives[0]->getColor() != nullptr ? new RGBColor(*myAlternatives[0]->getColor()) : nullptr;
182 15129 : myPrecomputed = new RORoute(myID, 0, 1, edges, col, myAlternatives[0]->getStops());
183 15129 : myNewRoute = true;
184 : }
185 : }
186 93458 : }
187 : }
188 :
189 :
190 : bool
191 295775 : RORouteDef::repairCurrentRoute(SUMOAbstractRouter<ROEdge, ROVehicle>& router,
192 : SUMOTime begin, const ROVehicle& veh,
193 : ConstROEdgeVector oldEdges, ConstROEdgeVector& newEdges,
194 : bool isTrip) const {
195 295775 : MsgHandler* mh = (OptionsCont::getOptions().getBool("ignore-errors") ?
196 295775 : MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance());
197 295775 : RONet* net = RONet::getInstance();
198 295775 : const int initialSize = (int)oldEdges.size();
199 295775 : const bool hasRestrictions = RONet::getInstance()->hasParamRestrictions();
200 295775 : if (net->getProhibitions().size() > 0 && !router.hasProhibitions()) {
201 12 : router.prohibit(net->getProhibitions());
202 : }
203 295775 : net->updateLaneProhibitions(begin);
204 295775 : if (initialSize == 1) {
205 6413 : if (myUsingJTRR) {
206 : /// only ROJTRRouter is supposed to handle this type of input
207 6134 : bool ok = router.compute(oldEdges.front(), nullptr, &veh, begin, newEdges);
208 10343 : myDiscardSilent = ok && newEdges.size() == 0;
209 : } else {
210 279 : newEdges = oldEdges;
211 : }
212 : } else {
213 289362 : if (oldEdges.front()->prohibits(&veh, hasRestrictions)) {
214 : // option repair.from is in effect
215 : const std::string& frontID = oldEdges.front()->getID();
216 18 : for (ConstROEdgeVector::iterator i = oldEdges.begin(); i != oldEdges.end();) {
217 15 : if ((*i)->prohibits(&veh, hasRestrictions) || (*i)->isInternal()) {
218 : i = oldEdges.erase(i);
219 : } else {
220 6 : WRITE_MESSAGE("Changing invalid starting edge '" + frontID
221 : + "' to '" + (*i)->getID() + "' for vehicle '" + veh.getID() + "'.");
222 3 : break;
223 : }
224 : }
225 : }
226 289362 : if (oldEdges.size() == 0) {
227 6 : mh->inform("Could not find new starting edge for vehicle '" + veh.getID() + "'.");
228 17144 : return false;
229 : }
230 289359 : 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 6 : while (oldEdges.back()->prohibits(&veh, hasRestrictions) || oldEdges.back()->isInternal()) {
235 : oldEdges.pop_back();
236 : }
237 9 : WRITE_MESSAGE("Changing invalid destination edge '" + backID
238 : + "' to edge '" + oldEdges.back()->getID() + "' for vehicle '" + veh.getID() + "'.");
239 : }
240 289359 : std::vector<ROVehicle::Mandatory> mandatory = veh.getMandatoryEdges(oldEdges.front(), oldEdges.back());
241 : assert(mandatory.size() >= 2);
242 : // removed prohibited
243 901803 : for (ConstROEdgeVector::iterator i = oldEdges.begin(); i != oldEdges.end();) {
244 612444 : if ((*i)->prohibits(&veh, hasRestrictions) || (*i)->isInternal()) {
245 : // no need to check the mandatories here, this was done before
246 132 : 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 289359 : if (mandatory.size() > oldEdges.size() && initialSize > 2) {
254 504 : 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 289359 : if (mandatory.size() >= oldEdges.size()) {
259 902283 : for (auto m : mandatory) {
260 612962 : targets.push_back(m.edge);
261 612962 : checkPositions |= m.pos >= 0;
262 : }
263 : } else {
264 38 : targets = oldEdges;
265 : }
266 289359 : newEdges.push_back(targets.front());
267 : auto nextMandatory = mandatory.begin() + 1;
268 : int lastMandatory = 0;
269 289359 : for (ConstROEdgeVector::const_iterator i = targets.begin() + 1;
270 595923 : i != targets.end() && nextMandatory != mandatory.end(); ++i) {
271 323701 : const ROEdge* prev = *(i - 1);
272 323701 : const ROEdge* cur = *i;
273 366395 : if (prev->isConnectedTo(*cur, veh.getVClass()) && (!isRailway(veh.getVClass()) || prev->getBidiEdge() != cur)) {
274 42690 : newEdges.push_back(cur);
275 : } else {
276 281011 : if (initialSize > 2) {
277 : // only inform if the input is (probably) not a trip
278 176015 : WRITE_MESSAGEF(TL("Edge '%' not connected to edge '%' for vehicle '%'."), (*(i - 1))->getID(), (*i)->getID(), veh.getID());
279 : }
280 281011 : const ROEdge* last = newEdges.back();
281 : newEdges.pop_back();
282 281011 : if (last->isTazConnector() && newEdges.size() > 1) {
283 : // assume this was a viaTaz
284 28 : last = newEdges.back();
285 : newEdges.pop_back();
286 : }
287 281011 : if (veh.hasJumps() && (nextMandatory - 1)->isJump) {
288 24 : while (*i != nextMandatory->edge) {
289 : ++i;
290 : }
291 24 : newEdges.push_back(last);
292 24 : 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 280987 : int numEdgesBefore = (int)newEdges.size();
297 : // router.setHint(targets.begin(), i, &veh, begin);
298 280987 : if (myTryRepair && lastMandatory < (int)newEdges.size() && last != newEdges[lastMandatory]) {
299 20 : router.setMsgHandler(MsgHandler::getWarningInstance());
300 : }
301 : bool ok;
302 : if (checkPositions
303 280960 : && mandatory[i - targets.begin() - 1].pos >= 0
304 540202 : && mandatory[i - targets.begin()].pos >= 0) {
305 602 : 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 280385 : ok = router.compute(last, *i, &veh, begin, newEdges);
311 : }
312 : router.setMsgHandler(mh);
313 280987 : 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 17143 : if (lastMandatory >= (int)newEdges.size() || last == newEdges[lastMandatory] || !backTrack(router, i, lastMandatory, nextMandatory->edge, newEdges, veh, begin)) {
320 34274 : mh->inform("Mandatory edge '" + (*i)->getID() + "' not reachable by vehicle '" + veh.getID() + "'.");
321 17137 : return false;
322 : }
323 263844 : } else if (!myMayBeDisconnected && !isTrip && last != (*i)) {
324 31 : double airDist = last->getToJunction()->getPosition().distanceTo(
325 : (*i)->getFromJunction()->getPosition());
326 : double repairDist = 0;
327 82 : for (auto it2 = (newEdges.begin() + numEdgesBefore + 1); it2 != newEdges.end() && it2 != newEdges.end() - 1; it2++) {
328 51 : repairDist += (*it2)->getLength();
329 : }
330 31 : const double detourFactor = repairDist / MAX2(airDist, 1.0);
331 31 : const double detour = MAX2(0.0, repairDist - airDist);
332 31 : const double maxDetourFactor = OptionsCont::getOptions().getFloat("repair.max-detour-factor");
333 31 : if (detourFactor > maxDetourFactor) {
334 3 : WRITE_MESSAGEF(" Backtracking to avoid detour of %m for gap of %m)", detour, airDist);
335 3 : backTrack(router, i, lastMandatory, nextMandatory->edge, newEdges, veh, begin);
336 28 : } else if (detourFactor > 1.1) {
337 8 : WRITE_MESSAGEF(" Taking detour of %m to avoid gap of %m)", detour, airDist);
338 : }
339 : }
340 : }
341 : }
342 306564 : if (*i == nextMandatory->edge) {
343 : nextMandatory++;
344 306496 : lastMandatory = (int)newEdges.size() - 1;
345 : }
346 : }
347 272222 : if (veh.getParameter().via.size() > 0 && veh.getParameter().stops.size() > 0) {
348 : // check consistency of stops and vias
349 : auto it = newEdges.begin();
350 12 : for (const auto& stop : veh.getParameter().stops) {
351 16 : const ROEdge* e = net->getEdge(stop.edge);
352 8 : it = std::find(it, newEdges.end(), e);
353 8 : if (it == newEdges.end()) {
354 8 : mh->inform("Stop edge '" + e->getID() + "' is inconsistent with via edges for vehicle '" + veh.getID() + "'.");
355 4 : return false;
356 : }
357 : }
358 : }
359 289359 : }
360 : return true;
361 : }
362 :
363 :
364 : bool
365 9 : 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 9 : bool ok = router.compute(newEdges[lastMandatory], nextMandatory, &veh, begin, edges, true);
370 9 : if (!ok) {
371 : return false;
372 : }
373 :
374 18 : 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 9 : }
381 :
382 :
383 : void
384 277654 : RORouteDef::addAlternative(SUMOAbstractRouter<ROEdge, ROVehicle>& router,
385 : const ROVehicle* const veh, RORoute* current, SUMOTime begin,
386 : MsgHandler* errorHandler) {
387 277654 : if (myTryRepair || myUsingJTRR) {
388 183251 : if (myNewRoute) {
389 154869 : delete myAlternatives[0];
390 154869 : myAlternatives[0] = current;
391 : }
392 366502 : if (!router.isValid(current->getEdgeVector(), veh, STEPS2TIME(begin))) {
393 0 : throw ProcessError("Route '" + getID() + "' (vehicle '" + veh->getID() + "') is not valid.");
394 : }
395 183251 : double costs = router.recomputeCosts(current->getEdgeVector(), veh, begin);
396 183251 : if (veh->hasJumps()) {
397 : // @todo: jumpTime should be applied in recomputeCost to ensure the
398 : // correctness of time-dependent traveltimes
399 20 : costs += STEPS2TIME(veh->getJumpTime());
400 : }
401 183251 : current->setCosts(costs);
402 183251 : return;
403 : }
404 : // add the route when it's new
405 94403 : if (myAlternatives.back()->getProbability() < 0 || !myAlternatives.back()->isPermitted(veh, errorHandler)) {
406 178 : if (myAlternatives.back()->getProbability() >= 0 && errorHandler == MsgHandler::getErrorInstance()) {
407 48 : throw ProcessError("Route '" + current->getID() + "' (vehicle '" + veh->getID() + "') is not valid.");
408 : }
409 162 : delete myAlternatives.back();
410 : myAlternatives.pop_back();
411 : }
412 94387 : if (myNewRoute) {
413 15113 : myAlternatives.push_back(current);
414 : }
415 : // recompute the costs and (when a new route was added) scale the probabilities
416 94387 : const double scale = double(myAlternatives.size() - 1) / double(myAlternatives.size());
417 346246 : for (RORoute* const alt : myAlternatives) {
418 503718 : if (!router.isValid(alt->getEdgeVector(), veh, STEPS2TIME(begin))) {
419 0 : throw ProcessError("Route '" + current->getID() + "' (vehicle '" + veh->getID() + "') is not valid.");
420 : }
421 : // recompute the costs for all routes
422 251859 : const double newCosts = router.recomputeCosts(alt->getEdgeVector(), veh, begin);
423 : assert(myAlternatives.size() != 0);
424 251859 : if (myNewRoute) {
425 36614 : if (alt == current) {
426 : // set initial probability and costs
427 15113 : alt->setProbability(1. / (double) myAlternatives.size());
428 15113 : alt->setCosts(newCosts);
429 : } else {
430 : // rescale probs for all others
431 21501 : alt->setProbability(alt->getProbability() * scale);
432 : }
433 : }
434 251859 : RouteCostCalculator<RORoute, ROEdge, ROVehicle>::getCalculator().setCosts(alt, newCosts, alt == myAlternatives[myLastUsed]);
435 : }
436 : assert(myAlternatives.size() != 0);
437 94387 : RouteCostCalculator<RORoute, ROEdge, ROVehicle>::getCalculator().calculateProbabilities(myAlternatives, veh, veh->getDepartureTime());
438 94387 : const bool keepRoute = RouteCostCalculator<RORoute, ROEdge, ROVehicle>::getCalculator().keepRoute();
439 94387 : if (!RouteCostCalculator<RORoute, ROEdge, ROVehicle>::getCalculator().keepAllRoutes() && !keepRoute) {
440 : // remove with probability of 0 (not mentioned in Gawron)
441 330894 : for (std::vector<RORoute*>::iterator i = myAlternatives.begin(); i != myAlternatives.end();) {
442 240691 : if ((*i)->getProbability() == 0) {
443 0 : delete *i;
444 : i = myAlternatives.erase(i);
445 : } else {
446 : i++;
447 : }
448 : }
449 : }
450 94387 : int maxNumber = RouteCostCalculator<RORoute, ROEdge, ROVehicle>::getCalculator().getMaxRouteNumber();
451 94387 : if ((int)myAlternatives.size() > maxNumber) {
452 56 : const RORoute* last = myAlternatives[myLastUsed];
453 : // only keep the routes with highest probability
454 56 : sort(myAlternatives.begin(), myAlternatives.end(), [](const RORoute * const a, const RORoute * const b) {
455 : return a->getProbability() > b->getProbability();
456 : });
457 56 : if (keepRoute) {
458 18 : for (int i = 0; i < (int)myAlternatives.size(); i++) {
459 18 : if (myAlternatives[i] == last) {
460 12 : myLastUsed = i;
461 12 : break;
462 : }
463 : }
464 12 : if (myLastUsed >= maxNumber) {
465 6 : std::swap(myAlternatives[maxNumber - 1], myAlternatives[myLastUsed]);
466 6 : myLastUsed = maxNumber - 1;
467 : }
468 : }
469 112 : for (std::vector<RORoute*>::iterator i = myAlternatives.begin() + maxNumber; i != myAlternatives.end(); i++) {
470 56 : delete *i;
471 : }
472 : myAlternatives.erase(myAlternatives.begin() + maxNumber, myAlternatives.end());
473 : }
474 : // rescale probabilities
475 : double newSum = 0.;
476 346190 : for (const RORoute* const alt : myAlternatives) {
477 251803 : newSum += alt->getProbability();
478 : }
479 : assert(newSum > 0);
480 : // @note newSum may be larger than 1 for numerical reasons
481 346190 : for (RORoute* const alt : myAlternatives) {
482 251803 : alt->setProbability(alt->getProbability() / newSum);
483 : }
484 :
485 : // find the route to use
486 94387 : if (!keepRoute) {
487 90203 : double chosen = RandHelper::rand();
488 90203 : myLastUsed = 0;
489 156009 : for (const RORoute* const alt : myAlternatives) {
490 156009 : chosen -= alt->getProbability();
491 156009 : if (chosen <= 0) {
492 : return;
493 : }
494 65806 : myLastUsed++;
495 : }
496 : }
497 : }
498 :
499 : const ROEdge*
500 93458 : RORouteDef::getOrigin() const {
501 93458 : return myAlternatives.back()->getFirst();
502 : }
503 :
504 :
505 : const ROEdge*
506 93458 : RORouteDef::getDestination() const {
507 93458 : return myAlternatives.back()->getLast();
508 : }
509 :
510 :
511 : OutputDevice&
512 311434 : RORouteDef::writeXMLDefinition(OutputDevice& dev, const ROVehicle* const veh,
513 : bool asAlternatives, bool withExitTimes, bool withCost, bool withLength) const {
514 311434 : if (asAlternatives) {
515 113005 : dev.openTag(SUMO_TAG_ROUTE_DISTRIBUTION).writeAttr(SUMO_ATTR_LAST, myLastUsed);
516 383429 : for (int i = 0; i != (int)myAlternatives.size(); i++) {
517 540848 : myAlternatives[i]->writeXMLDefinition(dev, veh, true, true, withExitTimes, withLength);
518 : }
519 113005 : dev.closeTag();
520 113005 : return dev;
521 : } else {
522 396858 : return myAlternatives[myLastUsed]->writeXMLDefinition(dev, veh, withCost, false, withExitTimes, withLength);
523 : }
524 : }
525 :
526 :
527 : RORouteDef*
528 20000 : RORouteDef::copy(const std::string& id, const SUMOTime stopOffset) const {
529 20000 : RORouteDef* result = new RORouteDef(id, 0, myTryRepair, myMayBeDisconnected);
530 40880 : for (const RORoute* const route : myAlternatives) {
531 20880 : RGBColor* col = route->getColor() != nullptr ? new RGBColor(*route->getColor()) : nullptr;
532 20880 : RORoute* newRoute = new RORoute(id, route->getCosts(), route->getProbability(), route->getEdgeVector(), col, route->getStops());
533 : newRoute->addStopOffset(stopOffset);
534 20880 : result->addLoadedAlternative(newRoute);
535 : }
536 20000 : return result;
537 : }
538 :
539 :
540 : double
541 91101 : RORouteDef::getOverallProb() const {
542 : double sum = 0.;
543 323700 : for (std::vector<RORoute*>::const_iterator i = myAlternatives.begin(); i != myAlternatives.end(); i++) {
544 232599 : sum += (*i)->getProbability();
545 : }
546 91101 : return sum;
547 : }
548 :
549 :
550 : /****************************************************************************/
|