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