Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/microsim/MSBaseVehicle.cpp
185785 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-2025 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 MSBaseVehicle.cpp
15
/// @author Michael Behrisch
16
/// @author Daniel Krajzewicz
17
/// @author Jakob Erdmann
18
/// @author Mirko Barthauer
19
/// @date Mon, 8 Nov 2010
20
///
21
// A base class for vehicle implementations
22
/****************************************************************************/
23
#include <config.h>
24
25
#include <iostream>
26
#include <cassert>
27
#include <algorithm>
28
#include <functional>
29
#include <utils/common/StdDefs.h>
30
#include <utils/common/MsgHandler.h>
31
#include <utils/options/OptionsCont.h>
32
#include <utils/iodevices/OutputDevice.h>
33
#include <utils/emissions/PollutantsInterface.h>
34
#include <utils/emissions/HelpersHarmonoise.h>
35
#include <libsumo/TraCIConstants.h>
36
#include <mesosim/MELoop.h>
37
#include <mesosim/MEVehicle.h>
38
#include <microsim/devices/MSRoutingEngine.h>
39
#include <microsim/devices/MSDevice_Transportable.h>
40
#include <microsim/devices/MSDevice_Emissions.h>
41
#include <microsim/devices/MSDevice_Battery.h>
42
#include <microsim/devices/MSDevice_ElecHybrid.h>
43
#include <microsim/devices/MSDevice_Taxi.h>
44
#include <microsim/devices/MSDevice_Routing.h>
45
#include <microsim/lcmodels/MSAbstractLaneChangeModel.h>
46
#include <microsim/transportables/MSPerson.h>
47
#include <microsim/transportables/MSStageDriving.h>
48
#include <microsim/trigger/MSChargingStation.h>
49
#include <microsim/trigger/MSStoppingPlaceRerouter.h>
50
#include <microsim/trigger/MSTriggeredRerouter.h>
51
#include <microsim/traffic_lights/MSRailSignalConstraint.h>
52
#include <microsim/traffic_lights/MSRailSignalControl.h>
53
#include "MSEventControl.h"
54
#include "MSGlobals.h"
55
#include "MSVehicleControl.h"
56
#include "MSVehicleType.h"
57
#include "MSEdge.h"
58
#include "MSLane.h"
59
#include "MSMoveReminder.h"
60
#include "MSEdgeWeightsStorage.h"
61
#include "MSNet.h"
62
#include "MSStop.h"
63
#include "MSParkingArea.h"
64
#include "MSInsertionControl.h"
65
#include "MSStopOptimizer.h"
66
#include "MSBaseVehicle.h"
67
68
//#define DEBUG_REROUTE
69
//#define DEBUG_ADD_STOP
70
//#define DEBUG_COND (getID() == "")
71
//#define DEBUG_COND (true)
72
//#define DEBUG_REPLACE_ROUTE
73
#define DEBUG_COND (isSelected())
74
75
// ===========================================================================
76
// static members
77
// ===========================================================================
78
const SUMOTime MSBaseVehicle::NOT_YET_DEPARTED = SUMOTime_MAX;
79
std::vector<MSTransportable*> MSBaseVehicle::myEmptyTransportableVector;
80
#ifdef _DEBUG
81
std::set<std::string> MSBaseVehicle::myShallTraceMoveReminders;
82
#endif
83
SUMOTrafficObject::NumericalID MSBaseVehicle::myCurrentNumericalIndex = 0;
84
85
// ===========================================================================
86
// Influencer method definitions
87
// ===========================================================================
88
89
MSBaseVehicle::BaseInfluencer::BaseInfluencer()
90
{}
91
92
// ===========================================================================
93
// method definitions
94
// ===========================================================================
95
96
double
97
MSBaseVehicle::getPreviousSpeed() const {
98
throw ProcessError("getPreviousSpeed() is not available for non-MSVehicles.");
99
}
100
101
102
MSBaseVehicle::MSBaseVehicle(SUMOVehicleParameter* pars, ConstMSRoutePtr route,
103
MSVehicleType* type, const double speedFactor) :
104
SUMOVehicle(pars->id),
105
myParameter(pars),
106
myRoute(route),
107
myType(type),
108
myCurrEdge(route->begin()),
109
myChosenSpeedFactor(pars->speedFactor < 0 ? speedFactor : pars->speedFactor),
110
myMoveReminders(0),
111
myPersonDevice(nullptr),
112
myContainerDevice(nullptr),
113
myEnergyParams(nullptr),
114
myDeparture(NOT_YET_DEPARTED),
115
myDepartPos(-1),
116
myArrivalPos(-1),
117
myArrivalLane(-1),
118
myNumberReroutes(0),
119
myStopUntilOffset(0),
120
myOdometer(0.),
121
myRouteValidity(ROUTE_UNCHECKED),
122
myRoutingMode(libsumo::ROUTING_MODE_DEFAULT),
123
myNumericalID(myCurrentNumericalIndex++),
124
myRandomSeed(RandHelper::murmur3_32(pars->id, RandHelper::getSeed())),
125
myEdgeWeights(nullptr)
126
#ifdef _DEBUG
127
, myTraceMoveReminders(myShallTraceMoveReminders.count(pars->id) > 0)
128
#endif
129
{
130
if ((*myRoute->begin())->isTazConnector() || myRoute->getLastEdge()->isTazConnector()) {
131
pars->parametersSet |= VEHPARS_FORCE_REROUTE;
132
}
133
if ((pars->parametersSet & VEHPARS_FORCE_REROUTE) == 0) {
134
setDepartAndArrivalEdge();
135
}
136
calculateArrivalParams(true);
137
initTransientModelParams();
138
}
139
140
141
MSBaseVehicle::~MSBaseVehicle() {
142
delete myEdgeWeights;
143
if (myParameter->repetitionNumber == -1) {
144
// this is not a flow (flows call checkDist in MSInsertionControl::determineCandidates)
145
MSRoute::checkDist(myParameter->routeid);
146
}
147
for (MSVehicleDevice* dev : myDevices) {
148
delete dev;
149
}
150
delete myEnergyParams;
151
delete myParkingMemory;
152
delete myChargingMemory;
153
checkRouteRemoval();
154
delete myParameter;
155
}
156
157
158
void
159
MSBaseVehicle::checkRouteRemoval() {
160
// the check for an instance is needed for the unit tests which do not construct a network
161
// TODO Optimize for speed and there should be a better way to check whether a vehicle is part of a flow
162
if (MSNet::hasInstance() && !MSNet::getInstance()->hasFlow(getFlowID())) {
163
myRoute->checkRemoval();
164
}
165
}
166
167
168
std::string
169
MSBaseVehicle::getFlowID() const {
170
return getID().substr(0, getID().rfind('.'));
171
}
172
173
174
void
175
MSBaseVehicle::initDevices() {
176
MSDevice::buildVehicleDevices(*this, myDevices);
177
for (MSVehicleDevice* dev : myDevices) {
178
myMoveReminders.push_back(std::make_pair(dev, 0.));
179
}
180
if (MSGlobals::gHaveEmissions) {
181
// ensure we have the emission parameters even if we don't have the device
182
getEmissionParameters();
183
}
184
}
185
186
187
void
188
MSBaseVehicle::setID(const std::string& /*newID*/) {
189
throw ProcessError(TL("Changing a vehicle ID is not permitted"));
190
}
191
192
const SUMOVehicleParameter&
193
MSBaseVehicle::getParameter() const {
194
return *myParameter;
195
}
196
197
198
void
199
MSBaseVehicle::replaceParameter(const SUMOVehicleParameter* newParameter) {
200
delete myParameter;
201
myParameter = newParameter;
202
}
203
204
205
bool
206
MSBaseVehicle::ignoreTransientPermissions() const {
207
return (getRoutingMode() & libsumo::ROUTING_MODE_IGNORE_TRANSIENT_PERMISSIONS) != 0;
208
}
209
210
double
211
MSBaseVehicle::getMaxSpeed() const {
212
return MIN2(myType->getMaxSpeed(), myType->getDesiredMaxSpeed() * myChosenSpeedFactor);
213
}
214
215
216
const MSEdge*
217
MSBaseVehicle::succEdge(int nSuccs) const {
218
if (myCurrEdge + nSuccs < myRoute->end() && std::distance(myCurrEdge, myRoute->begin()) <= nSuccs) {
219
return *(myCurrEdge + nSuccs);
220
} else {
221
return nullptr;
222
}
223
}
224
225
226
const MSEdge*
227
MSBaseVehicle::getEdge() const {
228
return *myCurrEdge;
229
}
230
231
232
const std::set<SUMOTrafficObject::NumericalID>
233
MSBaseVehicle::getUpcomingEdgeIDs() const {
234
std::set<SUMOTrafficObject::NumericalID> result;
235
for (auto e = myCurrEdge; e != myRoute->end(); ++e) {
236
result.insert((*e)->getNumericalID());
237
}
238
return result;
239
}
240
241
242
bool
243
MSBaseVehicle::stopsAt(MSStoppingPlace* stop) const {
244
if (stop == nullptr) {
245
return false;
246
}
247
for (const MSStop& s : myStops) {
248
if (s.busstop == stop
249
|| s.containerstop == stop
250
|| s.parkingarea == stop
251
|| s.chargingStation == stop) {
252
return true;
253
}
254
}
255
return false;
256
}
257
258
bool
259
MSBaseVehicle::stopsAtEdge(const MSEdge* edge) const {
260
for (const MSStop& s : myStops) {
261
if (&s.lane->getEdge() == edge) {
262
return true;
263
}
264
}
265
return myRoute->getLastEdge() == edge;
266
}
267
268
269
bool
270
MSBaseVehicle::reroute(SUMOTime t, const std::string& info, SUMOAbstractRouter<MSEdge, SUMOVehicle>& router, const bool onInit, const bool withTaz, const bool silent, const MSEdge* sink) {
271
// check whether to reroute
272
const MSEdge* source = withTaz && onInit ? MSEdge::dictionary(myParameter->fromTaz + "-source") : *getRerouteOrigin();
273
if (source == nullptr) {
274
source = *getRerouteOrigin();
275
}
276
if (sink == nullptr) {
277
sink = withTaz ? MSEdge::dictionary(myParameter->toTaz + "-sink") : myRoute->getLastEdge();
278
if (sink == nullptr) {
279
sink = myRoute->getLastEdge();
280
}
281
}
282
ConstMSEdgeVector oldEdgesRemaining(source == *myCurrEdge ? myCurrEdge : myCurrEdge + 1, myRoute->end());
283
ConstMSEdgeVector edges;
284
if (source != sink || !sink->prohibits(this)) {
285
edges.push_back(source);
286
}
287
std::vector<StopEdgeInfo> stops;
288
std::set<int> jumps;
289
290
291
double sourcePos = getPositionOnLane();
292
#ifdef DEBUG_REROUTE
293
if (DEBUG_COND) {
294
std::cout << " sourcePos=" << sourcePos << " lane=" << Named::getIDSecure(getLane()) << " departPos=" << myParameter->departPos << "\n";
295
}
296
#endif
297
if (onInit && myParameter->departPosProcedure == DepartPosDefinition::GIVEN) {
298
sourcePos = myParameter->departPos;
299
} else if (getLane() != nullptr && source != &getLane()->getEdge()) {
300
// routing starts on the next edge
301
sourcePos = 0;
302
}
303
if (myParameter->via.size() == 0) {
304
double firstPos = INVALID_DOUBLE;
305
double lastPos = INVALID_DOUBLE;
306
stops = getStopEdges(firstPos, lastPos, jumps);
307
if (stops.size() > 0) {
308
if (MSGlobals::gUseMesoSim && isStopped()) {
309
sourcePos = getNextStop().pars.endPos;
310
}
311
if (/*!MSGlobals::gUseMesoSim &&*/ !isStopped() && myStops.front().pars.speed == 0) {
312
sourcePos += getBrakeGap();
313
}
314
// avoid superfluous waypoints for first and last edge
315
const bool skipFirst = stops.front().edge == source && (source != getEdge() || sourcePos <= firstPos + NUMERICAL_EPS);
316
#ifdef DEBUG_REROUTE
317
if (DEBUG_COND) {
318
std::cout << SIMTIME << " reroute " << info << " veh=" << getID() << " lane=" << Named::getIDSecure(getLane())
319
<< " source=" << source->getID() << " sourcePos=" << sourcePos << " firstPos=" << firstPos << " arrivalPos=" << myArrivalPos << " lastPos=" << lastPos
320
<< " route=" << toString(myRoute->getEdges()) << " skipFirst=" << skipFirst << "\n";
321
}
322
#endif
323
if (stops.size() == 1 && skipFirst) {
324
stops.clear();
325
} else if (skipFirst) {
326
sourcePos = stops.front().pos;
327
stops.erase(stops.begin());
328
}
329
}
330
} else {
331
std::set<const MSEdge*> jumpEdges;
332
std::map<const MSEdge*, StopEdgeInfo> stopsOnVia;
333
for (const MSStop& stop : myStops) {
334
if (stop.pars.jump >= 0) {
335
jumpEdges.insert(*stop.edge);
336
}
337
auto itsov = stopsOnVia.find(*stop.edge);
338
if (itsov == stopsOnVia.end()) {
339
stopsOnVia.insert({*stop.edge, StopEdgeInfo(*stop.edge, stop.pars.priority, stop.getArrivalFallback(), stop.getEndPos(*this))});
340
} else {
341
itsov->second.priority = addStopPriority(itsov->second.priority, stop.pars.priority);
342
}
343
}
344
// via takes precedence over stop edges
345
// there is a consistency check in MSRouteHandler::addStop that warns when a stop edge is not part of the via edges
346
for (std::vector<std::string>::const_iterator it = myParameter->via.begin(); it != myParameter->via.end(); ++it) {
347
MSEdge* viaEdge = MSEdge::dictionary(*it);
348
if ((viaEdge == source && it == myParameter->via.begin()) || (viaEdge == sink && myParameter->via.end() - it == 1)) {
349
continue;
350
}
351
assert(viaEdge != 0);
352
if (!viaEdge->isTazConnector() && viaEdge->allowedLanes(getVClass()) == nullptr) {
353
throw ProcessError(TLF("Vehicle '%' is not allowed on any lane of via edge '%'.", getID(), viaEdge->getID()));
354
}
355
auto itsov = stopsOnVia.find(viaEdge);
356
const double priority = (itsov == stopsOnVia.end() ? -1 : itsov->second.priority);
357
const SUMOTime arrival = (itsov == stopsOnVia.end() ? -1 : itsov->second.arrival);
358
const double pos = (itsov == stopsOnVia.end() ? 0 : itsov->second.pos);
359
stops.push_back(StopEdgeInfo(viaEdge, priority, arrival, pos));
360
// @todo determine wether the viaEdge is also used by a stop and then use the stop priority here
361
if (jumpEdges.count(viaEdge) != 0) {
362
jumps.insert((int)stops.size());
363
}
364
}
365
}
366
if ((stops.size() == 0 && (source != sink || sourcePos > myArrivalPos))
367
|| ((stops.size() != 0) && (stops.back().edge != sink || myArrivalPos < stops.back().pos))) {
368
stops.push_back(StopEdgeInfo(sink, -1, -1, myArrivalPos, true));
369
}
370
#ifdef DEBUG_REROUTE
371
if (DEBUG_COND) {
372
std::cout << SIMTIME << " stops: veh=" << getID() << " source=" << source->getID() << " sink=" << sink->getID() << " sourcePos=" << sourcePos << " arrivalPos=" << myArrivalPos << "\n";
373
for (auto item : stops) {
374
std::cout << " e=" << item.edge->getID() << " pos=" << item.pos << "\n";
375
}
376
}
377
#endif
378
int stopIndex = -1;
379
auto stopIt = myStops.begin();
380
SUMOTime startTime = t;
381
bool hasSkipped = false;
382
const double origSourcePos = sourcePos;
383
const MSEdge* origSource = source;
384
const SUMOTime maxDelay = TIME2STEPS(getFloatParam(toString(SUMO_TAG_CLOSING_REROUTE) + ".maxDelay", false, MSTriggeredRerouter::DEFAULT_MAXDELAY, false));
385
for (auto& stopEdgeInfo : stops) {
386
const MSEdge* const stopEdge = stopEdgeInfo.edge;
387
const double priority = stopEdgeInfo.priority;
388
stopIndex++;
389
ConstMSEdgeVector into;
390
if (jumps.count(stopIndex) != 0) {
391
edges.push_back(stopEdge);
392
source = stopEdge;
393
continue;
394
}
395
// !!! need to adapt t here
396
router.compute(source, sourcePos, stopEdge, stopEdgeInfo.pos, this, t, into, silent || priority >= 0);
397
#ifdef DEBUG_REROUTE
398
if (DEBUG_COND) {
399
std::cout << SIMTIME << " reroute veh=" << getID() << " source=" << source->getID() << " sourcePos=" << sourcePos << " target=" << stopEdgeInfo.edge->getID() << " targetPos=" << stopEdgeInfo.pos << " edges=" << toString(into) << "\n";
400
}
401
#endif
402
if (into.size() > 0) {
403
while (stopIt != myStops.end() && stopIt->pars.edge != stopEdge->getID()) {
404
stopIt++;
405
}
406
407
startTime += TIME2STEPS(router.recomputeCostsPos(into, this, sourcePos, stopEdgeInfo.pos, startTime));
408
if (stopIt != myStops.end()) {
409
if (stopIt->pars.priority >= 0 && info != "device.rerouting") {
410
// consider skipping this stop if it cannot be reached in a timely manner
411
if (stopIt != myStops.end()) {
412
SUMOTime arrival = stopEdgeInfo.arrival;
413
if (arrival > 0) {
414
SUMOTime delay = startTime - arrival;
415
//std::cout << " t=" << time2string(t) << " veh=" << getID() << " info=" << info << " stopIndex=" << stopIndex
416
// << " into=" << toString(into) << " sourcePos=" << sourcePos << " stopPos=" << stopPos
417
// << " startTime=" << time2string(startTime) << " arrival=" << time2string(arrival) << " delay=" << time2string(delay) << "\n";
418
if (delay > 0) {
419
if (delay > maxDelay) {
420
stopEdgeInfo.skipped = true;
421
stopEdgeInfo.delay = delay;
422
hasSkipped = true;
423
continue;
424
}
425
}
426
}
427
}
428
}
429
sourcePos = stopEdgeInfo.pos;
430
startTime += stopIt->getMinDuration(startTime);
431
}
432
edges.pop_back();
433
edges.insert(edges.end(), into.begin(), into.end());
434
if (edges.back()->isTazConnector()) {
435
edges.pop_back();
436
}
437
source = edges.back();
438
stopEdgeInfo.routeIndex = (int)edges.size() - 1;
439
} else {
440
if (priority >= 0) {
441
stopEdgeInfo.skipped = true;
442
hasSkipped = true;
443
continue;
444
} else if (stopEdgeInfo.isSink) {
445
//error = TLF("Vehicle '%' has no valid route from edge '%' to destination edge '%'.", getID(), source->getID(), stopEdge->getID());
446
edges.clear();
447
} else if (source == stopEdge && stopEdgeInfo.stopPar != nullptr && stopEdgeInfo.stopPar->endPos >= sourcePos) {
448
// special case: no failure on dynamically computed stop position
449
edges.clear();
450
} else {
451
std::string error = TLF("Vehicle '%' has no valid route from edge '%' to stop edge '%'.", getID(), source->getID(), stopEdge->getID());
452
if (MSGlobals::gCheckRoutes || silent) {
453
throw ProcessError(error);
454
} else {
455
WRITE_WARNING(error);
456
edges.push_back(source);
457
source = stopEdge;
458
}
459
}
460
}
461
}
462
if (hasSkipped) {
463
MSStopOptimizer opti(this, router, t, maxDelay);
464
edges = opti.optimizeSkipped(origSource, origSourcePos, stops, edges);
465
for (auto stop : stops) {
466
if (stop.skipped || stop.origEdge != nullptr) {
467
const MSEdge* origEdge = stop.origEdge == nullptr ? stop.edge : stop.origEdge;
468
if (stop.delay > 0) {
469
WRITE_WARNING(TLF("Vehicle '%' skips stop on edge '%' with delay % at time %.", getID(), origEdge->getID(), time2string(stop.delay), time2string(SIMSTEP)));
470
} else if (stop.backtracked) {
471
WRITE_WARNING(TLF("Vehicle '%' skips stop on edge '%' with priority % at time %.", getID(), origEdge->getID(), stop.priority, time2string(SIMSTEP)));
472
} else {
473
WRITE_WARNING(TLF("Vehicle '%' skips unreachable stop on edge '%' with priority % at time %.", getID(), origEdge->getID(), stop.priority, time2string(SIMSTEP)));
474
}
475
}
476
}
477
}
478
479
// router.setHint(myCurrEdge, myRoute->end(), this, t);
480
if (edges.empty() && silent) {
481
return false;
482
}
483
if (!edges.empty() && edges.front()->isTazConnector()) {
484
edges.erase(edges.begin());
485
}
486
if (!edges.empty() && edges.back()->isTazConnector()) {
487
edges.pop_back();
488
}
489
const double routeCost = router.recomputeCosts(edges, this, t);
490
const double previousCost = onInit ? routeCost : router.recomputeCosts(oldEdgesRemaining, this, t);
491
const double savings = previousCost - routeCost;
492
bool savingsOk = onInit || info != "device.rerouting" || gWeightsRandomFactor != 1;
493
if (!savingsOk) {
494
MSDevice_Routing* routingDevice = static_cast<MSDevice_Routing*>(getDevice(typeid(MSDevice_Routing)));
495
assert(routingDevice != 0);
496
savingsOk = routingDevice->sufficientSaving(previousCost, routeCost);
497
if (!savingsOk) {
498
std::string dummyMsg;
499
if (!hasValidRoute(dummyMsg, oldEdgesRemaining.begin(), oldEdgesRemaining.end(), true)) {
500
// the old route is prohibted (i.e. due to temporary permission changes)
501
savingsOk = true;
502
}
503
}
504
}
505
//if (getID() == "43") std::cout << SIMTIME << " pCost=" << previousCost << " cost=" << routeCost
506
// << " onInit=" << onInit
507
// << " prevEdges=" << toString(oldEdgesRemaining)
508
// << " newEdges=" << toString(edges)
509
// << "\n";
510
if (savingsOk) {
511
replaceRouteEdges(edges, routeCost, savings, info, onInit);
512
}
513
// this must be called even if the route could not be replaced
514
if (onInit) {
515
if (edges.empty()) {
516
if (MSGlobals::gCheckRoutes) {
517
throw ProcessError(TLF("Vehicle '%' has no valid route.", getID()));
518
} else if (source->isTazConnector()) {
519
WRITE_WARNINGF(TL("Removing vehicle '%' which has no valid route."), getID());
520
MSNet::getInstance()->getInsertionControl().descheduleDeparture(this);
521
return false;
522
}
523
}
524
setDepartAndArrivalEdge();
525
calculateArrivalParams(onInit);
526
}
527
return !edges.empty();
528
}
529
530
531
bool
532
MSBaseVehicle::replaceRouteEdges(ConstMSEdgeVector& edges, double cost, double savings, const std::string& info, bool onInit, bool check, bool removeStops, std::string* msgReturn) {
533
if (edges.empty()) {
534
WRITE_WARNINGF(TL("No route for vehicle '%' found."), getID());
535
if (msgReturn != nullptr) {
536
*msgReturn = "No route found";
537
}
538
return false;
539
}
540
// build a new id, first
541
std::string id = getID();
542
if (id[0] != '!') {
543
id = "!" + id;
544
}
545
const std::string idSuffix = id + "!var#";
546
int varIndex = 1;
547
id = idSuffix + toString(varIndex);
548
while (MSRoute::hasRoute(id)) {
549
id = idSuffix + toString(++varIndex);
550
}
551
int oldSize = (int)edges.size();
552
if (!onInit) {
553
const MSEdge* const origin = *getRerouteOrigin();
554
if (origin != *myCurrEdge && edges.front() == origin) {
555
edges.insert(edges.begin(), *myCurrEdge);
556
oldSize = (int)edges.size();
557
}
558
edges.insert(edges.begin(), myRoute->begin(), myCurrEdge);
559
}
560
if (edges == myRoute->getEdges() && haveValidStopEdges(true)) {
561
// re-assign stop iterators when rerouting to a new parkingArea / insertStop
562
return true;
563
}
564
const RGBColor& c = myRoute->getColor();
565
MSRoute* newRoute = new MSRoute(id, edges, false, &c == &RGBColor::DEFAULT_COLOR ? nullptr : new RGBColor(c), StopParVector());
566
newRoute->setCosts(cost);
567
newRoute->setSavings(savings);
568
ConstMSRoutePtr constRoute = std::shared_ptr<MSRoute>(newRoute);
569
if (!MSRoute::dictionary(id, constRoute)) {
570
delete newRoute;
571
if (msgReturn != nullptr) {
572
*msgReturn = "duplicate routeID '" + id + "'";
573
}
574
return false;
575
}
576
577
std::string msg;
578
if (check && !hasValidRoute(msg, constRoute)) {
579
WRITE_WARNINGF(TL("Invalid route replacement for vehicle '%'. %"), getID(), msg);
580
if (MSGlobals::gCheckRoutes) {
581
if (msgReturn != nullptr) {
582
*msgReturn = msg;
583
}
584
return false;
585
}
586
}
587
if (!replaceRoute(constRoute, info, onInit, (int)edges.size() - oldSize, false, removeStops, msgReturn)) {
588
return false;
589
}
590
return true;
591
}
592
593
594
bool
595
MSBaseVehicle::replaceRoute(ConstMSRoutePtr newRoute, const std::string& info, bool onInit, int offset, bool addRouteStops, bool removeStops, std::string* msgReturn) {
596
const ConstMSEdgeVector& edges = newRoute->getEdges();
597
// rebuild in-vehicle route information
598
if (onInit) {
599
myCurrEdge = newRoute->begin();
600
} else {
601
MSRouteIterator newCurrEdge = std::find(edges.begin() + offset, edges.end(), *myCurrEdge);
602
if (newCurrEdge == edges.end()) {
603
if (msgReturn != nullptr) {
604
*msgReturn = TLF("current edge '%' not found in new route", (*myCurrEdge)->getID());
605
}
606
#ifdef DEBUG_REPLACE_ROUTE
607
if (DEBUG_COND) {
608
std::cout << " newCurrEdge not found\n";
609
}
610
#endif
611
return false;
612
}
613
if (getLane() != nullptr) {
614
if (getLane()->getEdge().isInternal() && (
615
(newCurrEdge + 1) == edges.end() || (*(newCurrEdge + 1)) != &(getLane()->getOutgoingViaLanes().front().first->getEdge()))) {
616
if (msgReturn != nullptr) {
617
*msgReturn = TL("Vehicle is on junction-internal edge leading elsewhere");
618
}
619
#ifdef DEBUG_REPLACE_ROUTE
620
if (DEBUG_COND) {
621
std::cout << " Vehicle is on junction-internal edge leading elsewhere\n";
622
}
623
#endif
624
return false;
625
} else if (getPositionOnLane() > getLane()->getLength()
626
&& (myCurrEdge + 1) != myRoute->end()
627
&& (newCurrEdge + 1) != edges.end()
628
&& *(myCurrEdge + 1) != *(newCurrEdge + 1)) {
629
if (msgReturn != nullptr) {
630
*msgReturn = TL("Vehicle is moving past junction and committed to move to another successor edge");
631
}
632
#ifdef DEBUG_REPLACE_ROUTE
633
if (DEBUG_COND) {
634
std::cout << " Vehicle is moving past junction and committed to move to another successor edge\n";
635
}
636
#endif
637
return false;
638
}
639
}
640
myCurrEdge = newCurrEdge;
641
}
642
const bool stopsFromScratch = onInit && myRoute->getStops().empty();
643
// assign new route
644
checkRouteRemoval();
645
myRoute = newRoute;
646
// update arrival definition
647
calculateArrivalParams(onInit);
648
// save information that the vehicle was rerouted
649
myNumberReroutes++;
650
myStopUntilOffset += myRoute->getPeriod();
651
MSNet::getInstance()->informVehicleStateListener(this, MSNet::VehicleState::NEWROUTE, info);
652
if (!onInit && isRail() && MSRailSignalControl::hasInstance()) {
653
// we need to update driveways (add/remove reminders) before the next call to MSRailSignalControl::updateSignals
654
//
655
// rerouting may be triggered through
656
// - MoveReminders (executeMove->activateReminders)
657
// - rerouters
658
// - devices (MSDevice_Stationfinder)
659
// - TraCI (changeTarget, replaceStop, ...
660
// - events (MSDevice_Routing::myRerouteCommand, MSDevice_Taxi::triggerDispatch)
661
//
662
// Since activateReminders actively modifies reminders, adding/deleting reminders would create a mess
663
// hence, we use an event to be safe for all case
664
665
MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(new WrappingCommand<MSBaseVehicle>(this,
666
&MSBaseVehicle::activateRemindersOnReroute), SIMSTEP);
667
}
668
#ifdef DEBUG_REPLACE_ROUTE
669
if (DEBUG_COND) {
670
std::cout << SIMTIME << " veh=" << getID() << " replaceRoute info=" << info << " on " << (*myCurrEdge)->getID()
671
<< " lane=" << Named::getIDSecure(getLane())
672
<< " stopsFromScratch=" << stopsFromScratch
673
<< " newSize=" << newRoute->getEdges().size()
674
<< " newIndex=" << (myCurrEdge - newRoute->begin())
675
<< " edges=" << toString(newRoute->getEdges())
676
<< "\n";
677
}
678
#endif
679
// remove past stops which are not on the route anymore
680
for (StopParVector::iterator it = myPastStops.begin(); it != myPastStops.end();) {
681
const MSEdge* stopEdge = (it->edge.empty()) ? &MSLane::dictionary(it->lane)->getEdge() : MSEdge::dictionary(it->edge);
682
if (std::find(myRoute->begin(), myRoute->end(), stopEdge) == myRoute->end()) {
683
it = myPastStops.erase(it);
684
} else {
685
++it;
686
}
687
}
688
// if we did not drive yet it may be best to simply reassign the stops from scratch
689
if (stopsFromScratch) {
690
myStops.clear();
691
addStops(!MSGlobals::gCheckRoutes);
692
} else {
693
// recheck old stops
694
MSRouteIterator searchStart = myCurrEdge;
695
double lastPos = getPositionOnLane() + getBrakeGap();
696
if (getLane() != nullptr && getLane()->isInternal()
697
&& myStops.size() > 0 && !myStops.front().lane->isInternal()) {
698
// searchStart is still incoming to the intersection so lastPos
699
// relative to that edge must be adapted
700
lastPos += (*myCurrEdge)->getLength();
701
}
702
int stopIndex = 0;
703
for (std::list<MSStop>::iterator iter = myStops.begin(); iter != myStops.end();) {
704
double endPos = iter->getEndPos(*this);
705
#ifdef DEBUG_REPLACE_ROUTE
706
if (DEBUG_COND) {
707
std::cout << " stopEdge=" << iter->lane->getEdge().getID() << " start=" << (searchStart - myCurrEdge) << " endPos=" << endPos << " lastPos=" << lastPos << "\n";
708
}
709
#endif
710
if (*searchStart != &iter->lane->getEdge()
711
|| endPos + NUMERICAL_EPS < lastPos) {
712
if (searchStart != edges.end() && !iter->reached) {
713
searchStart++;
714
}
715
}
716
lastPos = endPos;
717
718
iter->edge = std::find(searchStart, edges.end(), &iter->lane->getEdge());
719
#ifdef DEBUG_REPLACE_ROUTE
720
if (DEBUG_COND) {
721
std::cout << " foundIndex=" << (iter->edge - myCurrEdge) << " end=" << (edges.end() - myCurrEdge) << "\n";
722
}
723
#endif
724
if (iter->edge == edges.end() && iter->pars.priority >= 0) {
725
const std::string oldEdge = iter->pars.edge;
726
const std::string oldName = iter->getStoppingPlaceName().first;
727
if (replaceWithAlternative(iter, searchStart, edges.end())) {
728
WRITE_WARNINGF(TL("Vehicle '%' replaced stop on edge '%' (named '%') and now stops at '%' instead; after rerouting (%) at time=%."),
729
getID(), oldEdge, oldName, iter->getDescription(true), info, time2string(SIMSTEP));
730
}
731
}
732
if (iter->edge == edges.end()) {
733
if (!removeStops) {
734
WRITE_ERRORF(TL("Vehicle '%' could not assign stop '%' after rerouting (%) at time=%."), getID(), iter->getDescription(), info, time2string(SIMSTEP));
735
}
736
iter = myStops.erase(iter);
737
continue;
738
} else {
739
setSkips(*iter, stopIndex);
740
searchStart = iter->edge;
741
}
742
++iter;
743
stopIndex++;
744
}
745
// add new stops
746
if (addRouteStops) {
747
for (StopParVector::const_iterator i = newRoute->getStops().begin(); i != newRoute->getStops().end(); ++i) {
748
std::string error;
749
addStop(*i, error, myParameter->depart + myStopUntilOffset);
750
if (error != "") {
751
WRITE_WARNING(error);
752
}
753
}
754
}
755
}
756
return true;
757
}
758
759
760
bool
761
MSBaseVehicle::replaceWithAlternative(std::list<MSStop>::iterator iter, const MSRouteIterator searchStart, const MSRouteIterator end) {
762
std::pair<std::string, SumoXMLTag> nameTag = iter->getStoppingPlaceName();
763
if (!nameTag.first.empty()) {
764
const std::vector<MSStoppingPlace*>& alternatives = MSNet::getInstance()->getStoppingPlaceAlternatives(nameTag.first, nameTag.second);
765
for (MSStoppingPlace* alt : alternatives) {
766
//std::cout << SIMTIME << " veh=" << getID() << " name=" << nameTag.first << " alt=" << alt->getID() << "\n";
767
if (&alt->getLane().getEdge() == &iter->lane->getEdge()
768
|| !alt->getLane().allowsVehicleClass(getVClass())) {
769
continue;
770
}
771
iter->edge = std::find(searchStart, end, &alt->getLane().getEdge());
772
if (iter->edge != end) {
773
iter->replaceStoppingPlace(alt);
774
return true;
775
}
776
}
777
}
778
return false;
779
}
780
781
782
double
783
MSBaseVehicle::getAcceleration() const {
784
return 0;
785
}
786
787
788
void
789
MSBaseVehicle::onDepart() {
790
myDeparture = MSNet::getInstance()->getCurrentTimeStep();
791
myDepartPos = getPositionOnLane();
792
MSNet::getInstance()->getVehicleControl().vehicleDeparted(*this);
793
}
794
795
796
SUMOTime
797
MSBaseVehicle:: getDepartDelay() const {
798
const SUMOTime dep = getParameter().depart;
799
if (dep < 0) {
800
return 0;
801
}
802
return hasDeparted() ? getDeparture() - dep : SIMSTEP - dep;
803
}
804
805
806
bool
807
MSBaseVehicle::hasArrived() const {
808
return succEdge(1) == nullptr;
809
}
810
811
812
int
813
MSBaseVehicle::getRoutePosition() const {
814
return (int) std::distance(myRoute->begin(), myCurrEdge);
815
}
816
817
818
int
819
MSBaseVehicle::getNumRemainingEdges() const {
820
if (myParameter->arrivalEdge >= 0) {
821
return myParameter->arrivalEdge - getRoutePosition() + 1;
822
} else {
823
return myRoute->size() - getRoutePosition();
824
}
825
}
826
827
828
void
829
MSBaseVehicle::resetRoutePosition(int index, DepartLaneDefinition departLaneProcedure) {
830
myCurrEdge = myRoute->begin() + index;
831
const_cast<SUMOVehicleParameter*>(myParameter)->departLaneProcedure = departLaneProcedure;
832
// !!! hack
833
myArrivalPos = (*(myRoute->end() - 1))->getLanes()[0]->getLength();
834
}
835
836
double
837
MSBaseVehicle::getOdometer() const {
838
return -myDepartPos + myOdometer + (hasArrived() ? myArrivalPos : getPositionOnLane());
839
}
840
841
bool
842
MSBaseVehicle::allowsBoarding(const MSTransportable* t) const {
843
if (t->isPerson() && getPersonNumber() >= getVehicleType().getPersonCapacity()) {
844
return false;
845
} else if (!t->isPerson() && getContainerNumber() >= getVehicleType().getContainerCapacity()) {
846
return false;
847
}
848
if (isStopped() && myStops.begin()->pars.permitted.size() > 0
849
&& myStops.begin()->pars.permitted.count(t->getID()) == 0) {
850
return false;
851
}
852
MSDevice_Taxi* taxiDevice = static_cast<MSDevice_Taxi*>(getDevice(typeid(MSDevice_Taxi)));
853
if (taxiDevice != nullptr) {
854
return taxiDevice->allowsBoarding(t);
855
}
856
return true;
857
}
858
859
860
void
861
MSBaseVehicle::addTransportable(MSTransportable* transportable) {
862
if (transportable->isPerson()) {
863
if (myPersonDevice == nullptr) {
864
myPersonDevice = MSDevice_Transportable::buildVehicleDevices(*this, myDevices, false);
865
myMoveReminders.insert(myMoveReminders.begin(), std::make_pair(myPersonDevice, 0.));
866
if (myParameter->departProcedure == DepartDefinition::TRIGGERED && myParameter->depart == -1) {
867
const_cast<SUMOVehicleParameter*>(myParameter)->depart = MSNet::getInstance()->getCurrentTimeStep();
868
}
869
}
870
myPersonDevice->addTransportable(transportable);
871
} else {
872
if (myContainerDevice == nullptr) {
873
myContainerDevice = MSDevice_Transportable::buildVehicleDevices(*this, myDevices, true);
874
myMoveReminders.insert(myMoveReminders.begin(), std::make_pair(myContainerDevice, 0.));
875
if (myParameter->departProcedure == DepartDefinition::CONTAINER_TRIGGERED && myParameter->depart == -1) {
876
const_cast<SUMOVehicleParameter*>(myParameter)->depart = MSNet::getInstance()->getCurrentTimeStep();
877
}
878
}
879
myContainerDevice->addTransportable(transportable);
880
}
881
if (myEnergyParams != nullptr) {
882
myEnergyParams->setTransportableMass(myEnergyParams->getTransportableMass() + transportable->getVehicleType().getMass());
883
}
884
}
885
886
887
bool
888
MSBaseVehicle::hasJump(const MSRouteIterator& it) const {
889
for (const MSStop& stop : myStops) {
890
if (stop.edge == it && stop.pars.jump >= 0) {
891
return true;
892
} else if (stop.edge > it) {
893
return false;
894
}
895
}
896
return false;
897
}
898
899
900
bool
901
MSBaseVehicle::hasValidRoute(std::string& msg, ConstMSRoutePtr route) const {
902
MSRouteIterator start = myCurrEdge;
903
if (route == nullptr) {
904
route = myRoute;
905
} else {
906
start = route->begin();
907
}
908
const bool checkJumps = route == myRoute; // the edge iterators in the stops are invalid otherwise
909
return hasValidRoute(msg, start, route->end(), checkJumps);
910
}
911
912
913
bool
914
MSBaseVehicle::hasValidRoute(std::string& msg, MSRouteIterator start, MSRouteIterator last, bool checkJumps) const {
915
MSRouteIterator lastValid = last - 1;
916
// check connectivity, first
917
for (MSRouteIterator e = start; e != lastValid; ++e) {
918
const MSEdge& next = **(e + 1);
919
if ((*e)->allowedLanes(next, myType->getVehicleClass()) == nullptr) {
920
if (!checkJumps || !hasJump(e)) {
921
if ((myRoutingMode & libsumo::ROUTING_MODE_IGNORE_TRANSIENT_PERMISSIONS) == 0
922
|| (!next.hasTransientPermissions() && !(*e)->hasTransientPermissions())) {
923
msg = TLF("No connection between edge '%' and edge '%'.", (*e)->getID(), (*(e + 1))->getID());
924
return false;
925
}
926
}
927
}
928
}
929
// check usable lanes, then
930
for (MSRouteIterator e = start; e != last; ++e) {
931
if ((*e)->prohibits(this)) {
932
msg = TLF("Edge '%' prohibits.", (*e)->getID());
933
return false;
934
}
935
}
936
return true;
937
}
938
939
940
bool
941
MSBaseVehicle::hasValidRouteStart(std::string& msg) {
942
if (!(*myCurrEdge)->isTazConnector()) {
943
if (myParameter->departSpeedProcedure == DepartSpeedDefinition::GIVEN && myParameter->departSpeed > myType->getMaxSpeed() + SPEED_EPS) {
944
msg = TLF("Departure speed for vehicle '%' is too high for the vehicle type '%'.", getID(), myType->getID());
945
myRouteValidity |= ROUTE_START_INVALID_LANE;
946
return false;
947
}
948
}
949
if (myRoute->getEdges().size() > 0 && !(*myCurrEdge)->prohibits(this)) {
950
myRouteValidity &= ~ROUTE_START_INVALID_PERMISSIONS;
951
return true;
952
} else {
953
msg = TLF("Vehicle '%' is not allowed to depart on any lane of edge '%'.", getID(), (*myCurrEdge)->getID());
954
myRouteValidity |= ROUTE_START_INVALID_PERMISSIONS;
955
return false;
956
}
957
}
958
959
960
int
961
MSBaseVehicle::getRouteValidity(bool update, bool silent, std::string* msgReturn) {
962
if (!update) {
963
return myRouteValidity;
964
}
965
// insertion check must be done in any case
966
std::string msg;
967
if (!hasValidRouteStart(msg)) {
968
if (MSGlobals::gCheckRoutes) {
969
throw ProcessError(msg);
970
} else if (!silent) {
971
// vehicle will be discarded
972
WRITE_WARNING(msg);
973
} else if (msgReturn != nullptr) {
974
*msgReturn = msg;
975
}
976
}
977
if ((MSGlobals::gCheckRoutes || myRoute->getFirstEdge()->isInternal())
978
&& (myRouteValidity & ROUTE_UNCHECKED) != 0
979
// we could check after the first rerouting
980
&& (!myParameter->wasSet(VEHPARS_FORCE_REROUTE))) {
981
if (!hasValidRoute(msg, myRoute)) {
982
myRouteValidity |= ROUTE_INVALID;
983
throw ProcessError(TLF("Vehicle '%' has no valid route. %", getID(), msg));
984
}
985
}
986
myRouteValidity &= ~ROUTE_UNCHECKED;
987
return myRouteValidity;
988
}
989
990
991
bool
992
MSBaseVehicle::hasReminder(MSMoveReminder* rem) const {
993
for (auto item : myMoveReminders) {
994
if (item.first == rem) {
995
return true;
996
}
997
}
998
return false;
999
}
1000
1001
1002
void
1003
MSBaseVehicle::addReminder(MSMoveReminder* rem, double pos) {
1004
#ifdef _DEBUG
1005
if (myTraceMoveReminders) {
1006
traceMoveReminder("add", rem, pos, true);
1007
}
1008
#endif
1009
myMoveReminders.push_back(std::make_pair(rem, pos));
1010
}
1011
1012
1013
void
1014
MSBaseVehicle::removeReminder(MSMoveReminder* rem) {
1015
for (MoveReminderCont::iterator r = myMoveReminders.begin(); r != myMoveReminders.end(); ++r) {
1016
if (r->first == rem) {
1017
#ifdef _DEBUG
1018
if (myTraceMoveReminders) {
1019
traceMoveReminder("remove", rem, 0, false);
1020
}
1021
#endif
1022
myMoveReminders.erase(r);
1023
return;
1024
}
1025
}
1026
}
1027
1028
1029
void
1030
MSBaseVehicle::activateReminders(const MSMoveReminder::Notification reason, const MSLane* enteredLane) {
1031
// notifyEnter may cause new reminders to be added so we cannot use an iterator
1032
for (int i = 0; i < (int)myMoveReminders.size();) {
1033
MSMoveReminder* rem = myMoveReminders[i].first;
1034
const double remPos = myMoveReminders[i].second;
1035
// skip the reminder if it is a lane reminder but not for my lane (indicated by rem->second > 0.)
1036
if (rem->getLane() != nullptr && remPos > 0.) {
1037
#ifdef _DEBUG
1038
if (myTraceMoveReminders) {
1039
traceMoveReminder("notifyEnter_skipped", rem, remPos, true);
1040
}
1041
#endif
1042
++i;
1043
} else {
1044
if (rem->notifyEnter(*this, reason, enteredLane)) {
1045
#ifdef _DEBUG
1046
if (myTraceMoveReminders) {
1047
traceMoveReminder("notifyEnter", rem, remPos, true);
1048
}
1049
#endif
1050
++i;
1051
} else {
1052
#ifdef _DEBUG
1053
if (myTraceMoveReminders) {
1054
traceMoveReminder("notifyEnter", rem, remPos, false);
1055
}
1056
#endif
1057
myMoveReminders.erase(myMoveReminders.begin() + i);
1058
}
1059
}
1060
}
1061
}
1062
1063
1064
bool
1065
MSBaseVehicle::isRail() const {
1066
return isRailway(getVClass()) || isRailway(getCurrentEdge()->getPermissions());
1067
}
1068
1069
void
1070
MSBaseVehicle::calculateArrivalParams(bool onInit) {
1071
if (myRoute->getLastEdge()->isTazConnector()) {
1072
return;
1073
}
1074
const int arrivalEdgeIndex = MIN2(myParameter->arrivalEdge, (int)myRoute->getEdges().size() - 1);
1075
if (arrivalEdgeIndex != myParameter->arrivalEdge) {
1076
if (!(onInit && myParameter->wasSet(VEHPARS_FORCE_REROUTE))) {
1077
WRITE_WARNINGF(TL("Vehicle '%' ignores attribute arrivalEdge=% after rerouting at time=% (routeLength=%)"),
1078
getID(), myParameter->arrivalEdge, time2string(SIMSTEP), myRoute->getEdges().size() - 1);
1079
}
1080
}
1081
const MSEdge* arrivalEdge = myParameter->arrivalEdge >= 0 ? myRoute->getEdges()[arrivalEdgeIndex] : myRoute->getLastEdge();
1082
if (!onInit) {
1083
arrivalEdge = myRoute->getLastEdge();
1084
// ignore arrivalEdge parameter after rerouting
1085
const_cast<SUMOVehicleParameter*>(myParameter)->arrivalEdge = -1;
1086
}
1087
const std::vector<MSLane*>& lanes = arrivalEdge->getLanes();
1088
const double lastLaneLength = lanes[0]->getLength();
1089
switch (myParameter->arrivalPosProcedure) {
1090
case ArrivalPosDefinition::GIVEN:
1091
if (fabs(myParameter->arrivalPos) > lastLaneLength) {
1092
WRITE_WARNINGF(TL("Vehicle '%' will not be able to arrive at the given position!"), getID());
1093
}
1094
// Maybe we should warn the user about invalid inputs!
1095
myArrivalPos = MIN2(myParameter->arrivalPos, lastLaneLength);
1096
if (myArrivalPos < 0) {
1097
myArrivalPos = MAX2(myArrivalPos + lastLaneLength, 0.);
1098
}
1099
break;
1100
case ArrivalPosDefinition::RANDOM:
1101
myArrivalPos = RandHelper::rand(lastLaneLength);
1102
break;
1103
case ArrivalPosDefinition::CENTER:
1104
myArrivalPos = lastLaneLength / 2.;
1105
break;
1106
default:
1107
myArrivalPos = lastLaneLength;
1108
break;
1109
}
1110
if (myParameter->arrivalLaneProcedure == ArrivalLaneDefinition::GIVEN) {
1111
if (myParameter->arrivalLane >= (int)lanes.size() || !lanes[myParameter->arrivalLane]->allowsVehicleClass(myType->getVehicleClass())) {
1112
WRITE_WARNINGF(TL("Vehicle '%' will not be able to arrive at the given lane '%_%'!"), getID(), arrivalEdge->getID(), toString(myParameter->arrivalLane));
1113
}
1114
myArrivalLane = MIN2(myParameter->arrivalLane, (int)(lanes.size() - 1));
1115
} else if (myParameter->arrivalLaneProcedure == ArrivalLaneDefinition::FIRST_ALLOWED) {
1116
myArrivalLane = -1;
1117
for (MSLane* lane : lanes) {
1118
if (lane->allowsVehicleClass(myType->getVehicleClass())) {
1119
myArrivalLane = lane->getIndex();
1120
break;
1121
}
1122
}
1123
if (myArrivalLane == -1) {
1124
WRITE_WARNINGF(TL("Vehicle '%' has no usable arrivalLane on edge '%'."), getID(), arrivalEdge->getID());
1125
myArrivalLane = 0;
1126
}
1127
} else if (myParameter->arrivalLaneProcedure == ArrivalLaneDefinition::RANDOM) {
1128
// pick random lane among all usable lanes
1129
std::vector<MSLane*> usable;
1130
for (MSLane* lane : lanes) {
1131
if (lane->allowsVehicleClass(myType->getVehicleClass())) {
1132
usable.push_back(lane);
1133
}
1134
}
1135
if (usable.empty()) {
1136
WRITE_WARNINGF(TL("Vehicle '%' has no usable arrivalLane on edge '%'."), getID(), arrivalEdge->getID());
1137
myArrivalLane = 0;
1138
} else {
1139
myArrivalLane = usable[RandHelper::rand(0, (int)usable.size())]->getIndex();
1140
}
1141
}
1142
if (myParameter->arrivalSpeedProcedure == ArrivalSpeedDefinition::GIVEN) {
1143
for (std::vector<MSLane*>::const_iterator l = lanes.begin(); l != lanes.end(); ++l) {
1144
if (myParameter->arrivalSpeed <= (*l)->getVehicleMaxSpeed(this)) {
1145
return;
1146
}
1147
}
1148
WRITE_WARNINGF(TL("Vehicle '%' will not be able to arrive with the given speed!"), getID());
1149
}
1150
}
1151
1152
void
1153
MSBaseVehicle::setDepartAndArrivalEdge() {
1154
SUMOVehicleParameter* pars = const_cast<SUMOVehicleParameter*>(myParameter);
1155
if (pars->departEdgeProcedure != RouteIndexDefinition::DEFAULT) {
1156
const int routeEdges = (int)myRoute->getEdges().size();
1157
if (pars->departEdgeProcedure == RouteIndexDefinition::RANDOM) {
1158
// write specific edge in vehroute output for reproducibility
1159
pars->departEdge = RandHelper::rand(0, routeEdges);
1160
pars->departEdgeProcedure = RouteIndexDefinition::GIVEN;
1161
}
1162
assert(pars->departEdge >= 0);
1163
if (pars->departEdge >= routeEdges) {
1164
WRITE_WARNINGF(TL("Ignoring departEdge % for vehicle '%' with % route edges"), toString(pars->departEdge), getID(), toString(routeEdges));
1165
} else {
1166
myCurrEdge += pars->departEdge;
1167
}
1168
}
1169
if (pars->arrivalEdgeProcedure == RouteIndexDefinition::RANDOM) {
1170
const int routeEdges = (int)myRoute->getEdges().size();
1171
const int begin = (int)(myCurrEdge - myRoute->begin());
1172
// write specific edge in vehroute output for reproducibility
1173
pars->arrivalEdge = RandHelper::rand(begin, routeEdges);
1174
pars->arrivalEdgeProcedure = RouteIndexDefinition::GIVEN;
1175
assert(pars->arrivalEdge >= begin);
1176
assert(pars->arrivalEdge < routeEdges);
1177
}
1178
}
1179
1180
int
1181
MSBaseVehicle::getDepartEdge() const {
1182
return myParameter->departEdge <= myRoute->size() ? myParameter->departEdge : 0;
1183
}
1184
1185
int
1186
MSBaseVehicle::getInsertionChecks() const {
1187
if (getParameter().wasSet(VEHPARS_INSERTION_CHECKS_SET)) {
1188
return getParameter().insertionChecks;
1189
} else {
1190
return MSGlobals::gInsertionChecks;
1191
}
1192
}
1193
1194
double
1195
MSBaseVehicle::getImpatience() const {
1196
return MAX2(0., MIN2(1., getVehicleType().getImpatience()
1197
+ (hasInfluencer() ? getBaseInfluencer()->getExtraImpatience() : 0)
1198
+ (MSGlobals::gTimeToImpatience > 0 ? (double)getWaitingTime() / (double)MSGlobals::gTimeToImpatience : 0.)));
1199
}
1200
1201
1202
MSDevice*
1203
MSBaseVehicle::getDevice(const std::type_info& type) const {
1204
for (MSVehicleDevice* const dev : myDevices) {
1205
if (typeid(*dev) == type) {
1206
return dev;
1207
}
1208
}
1209
return nullptr;
1210
}
1211
1212
1213
void
1214
MSBaseVehicle::saveState(OutputDevice& out) {
1215
// the parameters may hold the name of a vTypeDistribution but we are interested in the actual type
1216
const std::string& typeID = myParameter->vtypeid != getVehicleType().getID() ? getVehicleType().getID() : "";
1217
myParameter->write(out, OptionsCont::getOptions(), SUMO_TAG_VEHICLE, typeID);
1218
// params and stops must be written in child classes since they may wish to add additional attributes first
1219
out.writeAttr(SUMO_ATTR_ROUTE, myRoute->getID());
1220
std::ostringstream os;
1221
os << myOdometer << " " << myNumberReroutes;
1222
out.writeAttr(SUMO_ATTR_DISTANCE, os.str());
1223
if (myParameter->arrivalPosProcedure == ArrivalPosDefinition::RANDOM) {
1224
out.writeAttr(SUMO_ATTR_ARRIVALPOS_RANDOMIZED, myArrivalPos);
1225
}
1226
if (!myParameter->wasSet(VEHPARS_SPEEDFACTOR_SET)) {
1227
const int precision = out.getPrecision();
1228
out.setPrecision(MAX2(gPrecisionRandom, precision));
1229
out.writeAttr(SUMO_ATTR_SPEEDFACTOR, myChosenSpeedFactor);
1230
out.setPrecision(precision);
1231
}
1232
if (myParameter->wasSet(VEHPARS_FORCE_REROUTE)) {
1233
out.writeAttr(SUMO_ATTR_REROUTE, true);
1234
}
1235
if (!myParameter->wasSet(VEHPARS_LINE_SET) && myParameter->line != "") {
1236
// could be set from stop
1237
out.writeAttr(SUMO_ATTR_LINE, myParameter->line);
1238
}
1239
// here starts the vehicle internal part (see loading)
1240
// @note: remember to close the vehicle tag when calling this in a subclass!
1241
}
1242
1243
1244
bool
1245
MSBaseVehicle::handleCollisionStop(MSStop& stop, const double distToStop) {
1246
UNUSED_PARAMETER(stop);
1247
UNUSED_PARAMETER(distToStop);
1248
return true;
1249
}
1250
1251
1252
bool
1253
MSBaseVehicle::isStopped() const {
1254
return !myStops.empty() && myStops.begin()->reached /*&& myState.mySpeed < SUMO_const_haltingSpeed @todo #1864#*/;
1255
}
1256
1257
1258
bool
1259
MSBaseVehicle::isParking() const {
1260
return (isStopped() && (myStops.begin()->pars.parking == ParkingType::OFFROAD)
1261
&& (myStops.begin()->parkingarea == nullptr || !myStops.begin()->parkingarea->parkOnRoad())
1262
&& (myStops.begin()->getSpeed() == 0 || getSpeed() < SUMO_const_haltingSpeed));
1263
}
1264
1265
1266
bool
1267
MSBaseVehicle::isJumping() const {
1268
return myPastStops.size() > 0 && myPastStops.back().jump >= 0 && getEdge()->getID() == myPastStops.back().edge && myPastStops.back().ended == SIMSTEP;
1269
}
1270
1271
1272
bool
1273
MSBaseVehicle::isStoppedTriggered() const {
1274
return isStopped() && (myStops.begin()->triggered || myStops.begin()->containerTriggered || myStops.begin()->joinTriggered);
1275
}
1276
1277
1278
bool
1279
MSBaseVehicle::isStoppedParking() const {
1280
return isStopped() && (myStops.begin()->pars.parking == ParkingType::OFFROAD);
1281
}
1282
1283
1284
bool
1285
MSBaseVehicle::isStoppedInRange(const double pos, const double tolerance, bool checkFuture) const {
1286
if (isStopped() || (checkFuture && hasStops())) {
1287
const MSStop& stop = myStops.front();
1288
return stop.pars.startPos - tolerance <= pos && stop.pars.endPos + tolerance >= pos;
1289
}
1290
return false;
1291
}
1292
1293
bool
1294
MSBaseVehicle::replaceParkingArea(MSParkingArea* parkingArea, std::string& errorMsg) {
1295
// Check if there is a parking area to be replaced
1296
if (parkingArea == 0) {
1297
errorMsg = "new parkingArea is NULL";
1298
return false;
1299
}
1300
if (myStops.size() == 0) {
1301
errorMsg = "vehicle has no stops";
1302
return false;
1303
}
1304
if (myStops.front().parkingarea == 0) {
1305
errorMsg = "first stop is not at parkingArea";
1306
return false;
1307
}
1308
MSStop& first = myStops.front();
1309
SUMOVehicleParameter::Stop& stopPar = const_cast<SUMOVehicleParameter::Stop&>(first.pars);
1310
std::string oldStopEdgeID = first.lane->getEdge().getID();
1311
// merge subsequent duplicate stops equals to parking area
1312
for (std::list<MSStop>::iterator iter = ++myStops.begin(); iter != myStops.end();) {
1313
if (iter->parkingarea == parkingArea) {
1314
stopPar.duration += iter->duration;
1315
myStops.erase(iter++);
1316
} else {
1317
break;
1318
}
1319
}
1320
stopPar.lane = parkingArea->getLane().getID();
1321
stopPar.parkingarea = parkingArea->getID();
1322
stopPar.startPos = parkingArea->getBeginLanePosition();
1323
stopPar.endPos = parkingArea->getEndLanePosition();
1324
first.edge = myRoute->end(); // will be patched in replaceRoute
1325
first.lane = &parkingArea->getLane();
1326
first.parkingarea = parkingArea;
1327
1328
// patch via edges
1329
std::string newStopEdgeID = parkingArea->getLane().getEdge().getID();
1330
if (myParameter->via.size() > 0 && myParameter->via.front() != newStopEdgeID) {
1331
myParameter->via.erase(myParameter->via.begin());
1332
myParameter->via.insert(myParameter->via.begin(), newStopEdgeID);
1333
}
1334
return true;
1335
}
1336
1337
1338
MSParkingArea*
1339
MSBaseVehicle::getNextParkingArea() {
1340
MSParkingArea* nextParkingArea = nullptr;
1341
if (!myStops.empty()) {
1342
SUMOVehicleParameter::Stop stopPar;
1343
MSStop stop = myStops.front();
1344
if (!stop.reached && stop.parkingarea != nullptr) {
1345
nextParkingArea = stop.parkingarea;
1346
}
1347
}
1348
return nextParkingArea;
1349
}
1350
1351
1352
MSParkingArea*
1353
MSBaseVehicle::getCurrentParkingArea() {
1354
MSParkingArea* currentParkingArea = nullptr;
1355
if (isParking()) {
1356
currentParkingArea = myStops.begin()->parkingarea;
1357
}
1358
return currentParkingArea;
1359
}
1360
1361
1362
const std::vector<std::string>&
1363
MSBaseVehicle::getParkingBadges() const {
1364
if (myParameter->wasSet(VEHPARS_PARKING_BADGES_SET)) {
1365
return myParameter->parkingBadges;
1366
} else {
1367
return getVehicleType().getParkingBadges();
1368
}
1369
}
1370
1371
1372
double
1373
MSBaseVehicle::basePos(const MSEdge* edge) const {
1374
double result = MIN2(getVehicleType().getLength() + POSITION_EPS, edge->getLength());
1375
if (hasStops()
1376
&& myStops.front().edge == myRoute->begin()
1377
&& (&myStops.front().lane->getEdge()) == *myStops.front().edge) {
1378
result = MIN2(result, MAX2(0.0, myStops.front().getEndPos(*this)));
1379
}
1380
return result;
1381
}
1382
1383
1384
MSLane*
1385
MSBaseVehicle::interpretOppositeStop(SUMOVehicleParameter::Stop& stop) {
1386
const std::string edgeID = SUMOXMLDefinitions::getEdgeIDFromLane(stop.lane);
1387
const MSEdge* edge = MSEdge::dictionary(edgeID);
1388
if (edge == nullptr || edge->getOppositeEdge() == nullptr || stop.lane.find("_") == std::string::npos) {
1389
return nullptr;
1390
}
1391
const int laneIndex = SUMOXMLDefinitions::getIndexFromLane(stop.lane);
1392
if (laneIndex < (edge->getNumLanes() + edge->getOppositeEdge()->getNumLanes())) {
1393
const int oppositeIndex = edge->getOppositeEdge()->getNumLanes() + edge->getNumLanes() - 1 - laneIndex;
1394
stop.edge = edgeID;
1395
return edge->getOppositeEdge()->getLanes()[oppositeIndex];
1396
}
1397
return nullptr;
1398
}
1399
1400
1401
bool
1402
MSBaseVehicle::addStop(const SUMOVehicleParameter::Stop& stopPar, std::string& errorMsg, SUMOTime untilOffset,
1403
MSRouteIterator* searchStart) {
1404
MSStop stop(stopPar);
1405
if (stopPar.lane == "") {
1406
MSEdge* e = MSEdge::dictionary(stopPar.edge);
1407
stop.lane = e->getFirstAllowed(getVClass(), getRoutingMode());
1408
if (stop.lane == nullptr) {
1409
errorMsg = "Vehicle '" + myParameter->id + "' is not allowed to stop on any lane of edge '" + stopPar.edge + "'.";
1410
return false;
1411
}
1412
} else {
1413
stop.lane = MSLane::dictionary(stopPar.lane);
1414
if (stop.lane == nullptr) {
1415
// must be an opposite stop
1416
SUMOVehicleParameter::Stop tmp = stopPar;
1417
stop.lane = interpretOppositeStop(tmp);
1418
assert(stop.lane != nullptr);
1419
}
1420
if (!stop.lane->allowsVehicleClass(myType->getVehicleClass(), getRoutingMode())) {
1421
errorMsg = "Vehicle '" + myParameter->id + "' is not allowed to stop on lane '" + stopPar.lane + "'.";
1422
return false;
1423
}
1424
}
1425
if (MSGlobals::gUseMesoSim) {
1426
stop.segment = MSGlobals::gMesoNet->getSegmentForEdge(stop.lane->getEdge(), stop.getEndPos(*this));
1427
if (stop.lane->isInternal()) {
1428
errorMsg = "Mesoscopic simulation does not allow stopping on internal edge '" + stopPar.edge + "' for vehicle '" + myParameter->id + "'.";
1429
return false;
1430
}
1431
}
1432
stop.initPars(stopPar);
1433
if (stopPar.until != -1) {
1434
// !!! it would be much cleaner to invent a constructor for stops which takes "until" as an argument
1435
const_cast<SUMOVehicleParameter::Stop&>(stop.pars).until += untilOffset;
1436
}
1437
if (stopPar.arrival != -1) {
1438
const_cast<SUMOVehicleParameter::Stop&>(stop.pars).arrival += untilOffset;
1439
}
1440
std::string stopType = "stop";
1441
std::string stopID = "";
1442
double parkingLength = stop.pars.endPos - stop.pars.startPos;
1443
if (stop.busstop != nullptr) {
1444
stopType = "busStop";
1445
stopID = stop.busstop->getID();
1446
parkingLength = stop.busstop->getParkingLength();
1447
} else if (stop.containerstop != nullptr) {
1448
stopType = "containerStop";
1449
stopID = stop.containerstop->getID();
1450
parkingLength = stop.containerstop->getParkingLength();
1451
} else if (stop.chargingStation != nullptr) {
1452
stopType = "chargingStation";
1453
stopID = stop.chargingStation->getID();
1454
parkingLength = stop.chargingStation->getParkingLength();
1455
} else if (stop.overheadWireSegment != nullptr) {
1456
stopType = "overheadWireSegment";
1457
stopID = stop.overheadWireSegment->getID();
1458
parkingLength = stop.overheadWireSegment->getParkingLength();
1459
} else if (stop.parkingarea != nullptr) {
1460
stopType = "parkingArea";
1461
stopID = stop.parkingarea->getID();
1462
}
1463
const std::string errorMsgStart = stopID == "" ? stopType : stopType + " '" + stopID + "'";
1464
1465
if (stop.pars.startPos < 0 || stop.pars.endPos > stop.lane->getLength()) {
1466
errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID() + "' has an invalid position.";
1467
return false;
1468
}
1469
if (stopType != "stop" && stopType != "parkingArea" && myType->getLength() / 2. > parkingLength
1470
// do not warn for stops that fill the whole lane
1471
&& parkingLength < stop.lane->getLength()
1472
// do not warn twice for the same stop
1473
&& MSNet::getInstance()->warnOnce(stopType + ":" + stopID)) {
1474
errorMsg = errorMsgStart + " on lane '" + stop.lane->getID() + "' is too short for vehicle '" + myParameter->id + "'.";
1475
}
1476
if (stopType == "parkingArea" && !stop.parkingarea->accepts(this)) {
1477
// forbid access in case the parking requests other badges
1478
errorMsg = errorMsgStart + "on lane '" + stop.lane->getID() + "' forbids access because vehicle '" + myParameter->id + "' does not provide any valid badge.";
1479
return false;
1480
}
1481
const MSEdge* stopLaneEdge = &stop.lane->getEdge();
1482
const MSEdge* stopEdge;
1483
if (stopLaneEdge->getOppositeEdge() != nullptr && stopLaneEdge->getOppositeEdge()->getID() == stopPar.edge) {
1484
// stop lane is on the opposite side
1485
stopEdge = stopLaneEdge->getOppositeEdge();
1486
stop.isOpposite = true;
1487
} else {
1488
// if stop is on an internal edge the normal edge before the intersection is used
1489
stopEdge = stopLaneEdge->getNormalBefore();
1490
}
1491
MSRouteIterator succ = myCurrEdge + 1; // we're using the address but only within the scope of this function (and recursive calls)
1492
if (searchStart == nullptr) {
1493
searchStart = &myCurrEdge;
1494
if (stopLaneEdge->isNormal() && getLane() != nullptr && getLane()->isInternal()) {
1495
// already on the intersection but myCurrEdge is before it
1496
searchStart = &succ;
1497
}
1498
}
1499
#ifdef DEBUG_ADD_STOP
1500
if (DEBUG_COND) {
1501
std::cout << "addStop desc=" << stop.getDescription() << " stopEdge=" << stopEdge->getID()
1502
<< " searchStart=" << ((*searchStart) == myRoute->end() ? "END" : (**searchStart)->getID())
1503
<< " index=" << (int)((*searchStart) - myRoute->begin()) << " route=" << toString(myRoute->getEdges())
1504
<< "\n";
1505
}
1506
#endif
1507
stop.edge = std::find(*searchStart, myRoute->end(), stopEdge);
1508
MSRouteIterator prevStopEdge = myCurrEdge;
1509
const MSEdge* prevEdge = (getLane() == nullptr ? getEdge() : &getLane()->getEdge());
1510
double prevStopPos = getPositionOnLane();
1511
// where to insert the stop
1512
std::list<MSStop>::iterator iter = myStops.begin();
1513
if (stopPar.index == STOP_INDEX_END || stopPar.index >= static_cast<int>(myStops.size()) || stopPar.index == STOP_INDEX_REPEAT) {
1514
iter = myStops.end();
1515
if (myStops.size() > 0 && myStops.back().edge >= *searchStart) {
1516
prevStopEdge = myStops.back().edge;
1517
prevEdge = &myStops.back().lane->getEdge();
1518
prevStopPos = myStops.back().pars.endPos;
1519
stop.edge = std::find(prevStopEdge, myRoute->end(), stopEdge);
1520
if (prevStopEdge == stop.edge // laneEdge check is insufficient for looped routes
1521
&& prevEdge == &stop.lane->getEdge() // route iterator check insufficient for internal lane stops
1522
&& (prevStopPos > stop.pars.endPos ||
1523
(prevStopPos == stop.pars.endPos && stopPar.index == STOP_INDEX_REPEAT))) {
1524
stop.edge = std::find(prevStopEdge + 1, myRoute->end(), stopEdge);
1525
}
1526
#ifdef DEBUG_ADD_STOP
1527
if (DEBUG_COND) {
1528
std::cout << " (@end) prevStopEdge=" << (*prevStopEdge)->getID() << " prevStopPos=" << prevStopPos << " index=" << (int)(prevStopEdge - myRoute->begin())
1529
<< " foundIndex=" << (stop.edge == myRoute->end() ? -1 : (int)(stop.edge - myRoute->begin())) << "\n";
1530
}
1531
#endif
1532
}
1533
// skip a number of occurences of stopEdge in looped route
1534
int skipLooped = stopPar.index - static_cast<int>(myStops.size());
1535
for (int j = 0; j < skipLooped; j++) {
1536
auto nextIt = std::find(stop.edge + 1, myRoute->end(), stopEdge);
1537
if (nextIt == myRoute->end()) {
1538
if (std::find(myRoute->begin(), stop.edge, stopEdge) != stop.edge) {
1539
// only warn if the route loops over the stop edge at least once
1540
errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' could not skip " + toString(skipLooped) + " occurences of stop edge '" + stopEdge->getID() + "' in looped route.";
1541
}
1542
break;
1543
} else {
1544
stop.edge = nextIt;
1545
}
1546
}
1547
} else {
1548
if (stopPar.index == STOP_INDEX_FIT) {
1549
while (iter != myStops.end() && (iter->edge < stop.edge ||
1550
(iter->pars.endPos < stop.pars.endPos && iter->edge == stop.edge) ||
1551
(stop.lane->getEdge().isInternal() && iter->edge == stop.edge))) {
1552
prevStopEdge = iter->edge;
1553
prevStopPos = iter->pars.endPos;
1554
++iter;
1555
}
1556
} else {
1557
int index = stopPar.index;
1558
while (index > 0) {
1559
prevStopEdge = iter->edge;
1560
prevStopPos = iter->pars.endPos;
1561
++iter;
1562
--index;
1563
}
1564
#ifdef DEBUG_ADD_STOP
1565
if (DEBUG_COND) {
1566
std::cout << " (@fit) prevStopEdge=" << (*prevStopEdge)->getID() << " index=" << (int)(prevStopEdge - myRoute->begin()) << "\n";
1567
}
1568
#endif
1569
stop.edge = std::find(prevStopEdge, myRoute->end(), stopEdge);
1570
}
1571
}
1572
const bool wasTooClose = errorMsg != "" && errorMsg.find("too close") != std::string::npos;
1573
if (stop.edge == myRoute->end()) {
1574
if (!wasTooClose) {
1575
errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID() + "' is not downstream the current route.";
1576
}
1577
return false;
1578
}
1579
1580
const bool tooClose = (prevStopEdge == stop.edge && prevEdge == &stop.lane->getEdge() &&
1581
prevStopPos + (iter == myStops.begin() ? getBrakeGap() : 0) > stop.pars.endPos + POSITION_EPS);
1582
1583
if (prevStopEdge > stop.edge ||
1584
// a collision-stop happens after vehicle movement and may move the
1585
// vehicle backwards on its lane (prevStopPos is the vehicle position)
1586
(tooClose && !stop.pars.collision)
1587
|| (stop.lane->getEdge().isInternal() && stop.lane->getNextNormal() != *(stop.edge + 1))) {
1588
// check if the edge occurs again later in the route
1589
//std::cout << " could not add stop " << errorMsgStart << " prevStops=" << myStops.size() << " searchStart=" << (*searchStart - myRoute->begin()) << " route=" << toString(myRoute->getEdges()) << "\n";
1590
if (tooClose && prevStopPos <= stop.pars.endPos + POSITION_EPS) {
1591
errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.pars.lane + "' is too close to brake.";
1592
}
1593
MSRouteIterator next = stop.edge + 1;
1594
return addStop(stopPar, errorMsg, untilOffset, &next);
1595
}
1596
if (wasTooClose) {
1597
errorMsg = "";
1598
}
1599
// David.C:
1600
//if (!stop.parking && (myCurrEdge == stop.edge && myState.myPos > stop.endPos - getCarFollowModel().brakeGap(myState.mySpeed))) {
1601
const double endPosOffset = stop.lane->getEdge().isInternal() ? (*stop.edge)->getLength() : 0;
1602
const double distToStop = stop.pars.endPos + endPosOffset - getPositionOnLane();
1603
if (stop.pars.collision && !handleCollisionStop(stop, distToStop)) {
1604
return false;
1605
}
1606
if (!hasDeparted() && myCurrEdge == stop.edge) {
1607
double pos = -1;
1608
if (myParameter->departPosProcedure == DepartPosDefinition::GIVEN) {
1609
pos = myParameter->departPos;
1610
if (pos < 0.) {
1611
pos += (*myCurrEdge)->getLength();
1612
}
1613
}
1614
if (myParameter->departPosProcedure == DepartPosDefinition::BASE || myParameter->departPosProcedure == DepartPosDefinition::DEFAULT) {
1615
pos = MIN2(stop.pars.endPos + endPosOffset, basePos(*myCurrEdge));
1616
}
1617
if (pos > stop.pars.endPos + endPosOffset) {
1618
if (stop.edge != myRoute->end()) {
1619
// check if the edge occurs again later in the route
1620
MSRouteIterator next = stop.edge + 1;
1621
return addStop(stopPar, errorMsg, untilOffset, &next);
1622
}
1623
errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID() + "' is before departPos.";
1624
return false;
1625
}
1626
}
1627
if (iter != myStops.begin()) {
1628
std::list<MSStop>::iterator iter2 = iter;
1629
iter2--;
1630
if (stop.getUntil() >= 0 && iter2->getUntil() > stop.getUntil()
1631
&& (!MSGlobals::gUseStopEnded || iter2->pars.ended < 0 || stop.pars.ended >= 0)) {
1632
errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
1633
+ "' set to end at " + time2string(stop.getUntil())
1634
+ " earlier than previous stop at " + time2string(iter2->getUntil()) + ".";
1635
}
1636
if (stop.pars.arrival >= 0 && iter2->pars.arrival > stop.pars.arrival) {
1637
errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
1638
+ "' set to start at " + time2string(stop.pars.arrival)
1639
+ " earlier than previous stop end at " + time2string(iter2->getUntil()) + ".";
1640
}
1641
if (stop.pars.arrival >= 0 && iter2->pars.arrival > stop.pars.arrival) {
1642
errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
1643
+ "' set to start at " + time2string(stop.pars.arrival)
1644
+ " earlier than previous stop arrival at " + time2string(iter2->pars.arrival) + ".";
1645
}
1646
} else {
1647
if (stop.getUntil() >= 0 && getParameter().depart > stop.getUntil()
1648
&& (!MSGlobals::gUseStopEnded || stop.pars.ended < 0)) {
1649
errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
1650
+ "' set to end at " + time2string(stop.getUntil())
1651
+ " earlier than departure at " + time2string(getParameter().depart) + ".";
1652
}
1653
}
1654
if (stop.getUntil() >= 0 && stop.getArrival() > stop.getUntil() && errorMsg == "") {
1655
errorMsg = errorMsgStart + " for vehicle '" + myParameter->id + "' on lane '" + stop.lane->getID()
1656
+ "' set to end at " + time2string(stop.getUntil())
1657
+ " earlier than arrival at " + time2string(stop.getArrival()) + ".";
1658
}
1659
setSkips(stop, (int)myStops.size());
1660
myStops.insert(iter, stop);
1661
if (stopPar.tripId != "") {
1662
MSRailSignalConstraint::storeTripId(stopPar.tripId, getID());
1663
}
1664
//std::cout << " added stop " << errorMsgStart << " totalStops=" << myStops.size() << " searchStart=" << (*searchStart - myRoute->begin())
1665
// << " routeIndex=" << (stop.edge - myRoute->begin())
1666
// << " stopIndex=" << std::distance(myStops.begin(), iter)
1667
// << " route=" << toString(myRoute->getEdges()) << "\n";
1668
return true;
1669
}
1670
1671
1672
void
1673
MSBaseVehicle::setSkips(MSStop& stop, int prevActiveStops) {
1674
if (hasDeparted() && stop.edge > myRoute->begin()) {
1675
// if the route is looped we must patch the index to ensure that state
1676
// loading (and vehroute-output) encode the correct number of skips
1677
int foundSkips = 0;
1678
MSRouteIterator itPrev;
1679
double prevEndPos;
1680
if (prevActiveStops > 0) {
1681
assert((int)myStops.size() >= prevActiveStops);
1682
auto prevStopIt = myStops.begin();
1683
std::advance(prevStopIt, prevActiveStops - 1);
1684
const MSStop& prev = *prevStopIt;
1685
itPrev = prev.edge;
1686
prevEndPos = prev.pars.endPos;
1687
} else if (myPastStops.size() > 0) {
1688
itPrev = myRoute->begin() + myPastStops.back().routeIndex;
1689
prevEndPos = myPastStops.back().endPos;
1690
} else {
1691
itPrev = myRoute->begin() + myParameter->departEdge;
1692
prevEndPos = myDepartPos;
1693
}
1694
//auto itPrevOrig = itPrev;
1695
if (*itPrev == *stop.edge && prevEndPos > stop.pars.endPos) {
1696
itPrev++;
1697
}
1698
//std::cout << SIMTIME << " veh=" << getID() << " prevActive=" << prevActiveStops << " edge=" << (*stop.edge)->getID() << " routeIndex=" << (stop.edge - myRoute->begin()) << " prevIndex=" << (itPrev - myRoute->begin()) << "\n";
1699
while (itPrev < stop.edge) {
1700
if (*itPrev == *stop.edge) {
1701
foundSkips++;
1702
}
1703
itPrev++;
1704
}
1705
int newIndex = STOP_INDEX_END;
1706
if (foundSkips > 0) {
1707
//if (getID() == "77_0_0") {
1708
// std::cout << SIMTIME << " veh=" << getID() << " past=" << myPastStops.size() << " prevActive=" << prevActiveStops
1709
// << " edge=" << (*stop.edge)->getID() << " routeIndex=" << (stop.edge - myRoute->begin())
1710
// << " prevEdge=" << (*itPrevOrig)->getID()
1711
// << " prevIndex=" << (itPrevOrig - myRoute->begin())
1712
// << " skips=" << foundSkips << "\n";
1713
//}
1714
newIndex = (int)myPastStops.size() + prevActiveStops + foundSkips;
1715
}
1716
const_cast<SUMOVehicleParameter::Stop&>(stop.pars).index = newIndex;
1717
}
1718
}
1719
1720
1721
SUMOTime
1722
MSBaseVehicle::activateRemindersOnReroute(SUMOTime /*currentTime*/) {
1723
for (int i = 0; i < (int)myMoveReminders.size();) {
1724
auto rem = &myMoveReminders[i];
1725
if (rem->first->notifyReroute(*this)) {
1726
#ifdef _DEBUG
1727
if (myTraceMoveReminders) {
1728
traceMoveReminder("notifyReroute", rem->first, rem->second, true);
1729
}
1730
#endif
1731
++i;
1732
} else {
1733
#ifdef _DEBUG
1734
if (myTraceMoveReminders) {
1735
traceMoveReminder("notifyReroute", rem->first, rem->second, false);
1736
}
1737
#endif
1738
myMoveReminders.erase(myMoveReminders.begin() + i);
1739
}
1740
}
1741
resetApproachOnReroute();
1742
// event only called once
1743
return 0;
1744
}
1745
1746
1747
void
1748
MSBaseVehicle::addStops(const bool ignoreStopErrors, MSRouteIterator* searchStart, bool addRouteStops) {
1749
if (addRouteStops) {
1750
for (const SUMOVehicleParameter::Stop& stop : myRoute->getStops()) {
1751
std::string errorMsg;
1752
if (!addStop(stop, errorMsg, myParameter->depart, searchStart) && !ignoreStopErrors) {
1753
throw ProcessError(errorMsg);
1754
}
1755
if (errorMsg != "") {
1756
WRITE_WARNING(errorMsg);
1757
}
1758
}
1759
}
1760
const SUMOTime untilOffset = myParameter->repetitionOffset > 0 ? myParameter->repetitionsDone * myParameter->repetitionOffset : 0;
1761
for (const SUMOVehicleParameter::Stop& stop : myParameter->stops) {
1762
std::string errorMsg;
1763
if (!addStop(stop, errorMsg, untilOffset, searchStart) && !ignoreStopErrors) {
1764
throw ProcessError(errorMsg);
1765
}
1766
if (errorMsg != "") {
1767
WRITE_WARNING(errorMsg);
1768
}
1769
}
1770
}
1771
1772
1773
bool
1774
MSBaseVehicle::haveValidStopEdges(bool silent) const {
1775
MSRouteIterator start = myCurrEdge;
1776
int i = 0;
1777
bool ok = true;
1778
for (const MSStop& stop : myStops) {
1779
MSRouteIterator it;
1780
if (stop.lane->isInternal()) {
1781
// find the normal predecessor and ensure that the next route edge
1782
// matches the successor of the internal edge successor
1783
it = std::find(start, myRoute->end(), stop.lane->getEdge().getNormalBefore());
1784
if (it != myRoute->end() && (
1785
it + 1 == myRoute->end() || *(it + 1) != stop.lane->getEdge().getNormalSuccessor())) {
1786
it = myRoute->end(); // signal failure
1787
}
1788
} else {
1789
it = std::find(start, myRoute->end(), &stop.lane->getEdge());
1790
}
1791
if (it == myRoute->end()) {
1792
if (!silent) {
1793
WRITE_ERRORF("Stop % on edge '%' is not found after edge '%' (% after current) for vehicle '%' at time=%.",
1794
i, stop.lane->getEdge().getID(), (*start)->getID(), toString(start - myCurrEdge), getID(), time2string(SIMSTEP));
1795
}
1796
ok = false;
1797
} else {
1798
MSRouteIterator it2;
1799
for (it2 = myRoute->begin(); it2 != myRoute->end(); it2++) {
1800
if (it2 == stop.edge) {
1801
break;
1802
}
1803
}
1804
if (it2 == myRoute->end()) {
1805
if (!silent) {
1806
WRITE_ERRORF("Stop % on edge '%' used invalid route index for vehicle '%' at time=%.",
1807
i, stop.lane->getEdge().getID(), getID(), time2string(SIMSTEP));
1808
}
1809
ok = false;
1810
} else if (it2 < start) {
1811
if (!silent) {
1812
WRITE_ERRORF("Stop % on edge '%' used invalid (relative) route index % expected after % for vehicle '%' at time=%.",
1813
i, stop.lane->getEdge().getID(), toString(it2 - myCurrEdge), toString(start - myCurrEdge), getID(), time2string(SIMSTEP));
1814
}
1815
ok = false;
1816
} else {
1817
start = stop.edge;
1818
}
1819
}
1820
i++;
1821
}
1822
return ok;
1823
}
1824
1825
1826
std::vector<MSBaseVehicle::StopEdgeInfo>
1827
MSBaseVehicle::getStopEdges(double& firstPos, double& lastPos, std::set<int>& jumps) const {
1828
assert(haveValidStopEdges());
1829
std::vector<StopEdgeInfo> result;
1830
const MSStop* prev = nullptr;
1831
const MSEdge* internalSuccessor = nullptr;
1832
for (const MSStop& stop : myStops) {
1833
if (stop.reached) {
1834
if (stop.pars.jump >= 0) {
1835
jumps.insert((int)result.size());
1836
}
1837
continue;
1838
}
1839
double stopPos = stop.getEndPos(*this);
1840
if ((prev == nullptr
1841
|| prev->edge != stop.edge
1842
|| (prev->lane == stop.lane && prev->getEndPos(*this) > stopPos))
1843
&& *stop.edge != internalSuccessor) {
1844
if (stop.lane->isInternal()) {
1845
stopPos = (*stop.edge)->getLength();
1846
}
1847
result.push_back(StopEdgeInfo(*stop.edge, stop.pars.priority, stop.getArrivalFallback(), stopPos));
1848
result.back().nameTag = stop.getStoppingPlaceName();
1849
result.back().stopPar = &stop.pars;
1850
if (stop.lane->isInternal()) {
1851
internalSuccessor = stop.lane->getNextNormal();
1852
result.push_back(StopEdgeInfo(internalSuccessor, stop.pars.priority, stop.getArrivalFallback(), 0));
1853
} else {
1854
internalSuccessor = nullptr;
1855
}
1856
} else if (prev != nullptr && prev->edge == stop.edge) {
1857
result.back().priority = addStopPriority(result.back().priority, stop.pars.priority);
1858
}
1859
prev = &stop;
1860
if (firstPos == INVALID_DOUBLE) {
1861
if (stop.parkingarea != nullptr) {
1862
firstPos = MAX2(0., stopPos);
1863
} else {
1864
firstPos = stopPos;
1865
}
1866
}
1867
lastPos = stopPos;
1868
if (stop.pars.jump >= 0) {
1869
jumps.insert((int)result.size() - 1);
1870
}
1871
}
1872
//std::cout << SIMTIME << " getStopEdges veh=" << getID() << "\n";
1873
//for (auto item : result) {
1874
// std::cout << " e=" << item.edge->getID() << " pos=" << item.pos << "\n";
1875
//}
1876
return result;
1877
}
1878
1879
1880
double
1881
MSBaseVehicle::addStopPriority(double p1, double p2) {
1882
if (p1 < 0 || p2 < 0) {
1883
return p1;
1884
}
1885
return p1 + p2;
1886
}
1887
1888
std::vector<std::pair<int, double> >
1889
MSBaseVehicle::getStopIndices() const {
1890
std::vector<std::pair<int, double> > result;
1891
for (std::list<MSStop>::const_iterator iter = myStops.begin(); iter != myStops.end(); ++iter) {
1892
result.push_back(std::make_pair(
1893
(int)(iter->edge - myRoute->begin()),
1894
iter->getEndPos(*this)));
1895
}
1896
return result;
1897
}
1898
1899
1900
const MSStop&
1901
MSBaseVehicle::getNextStop() const {
1902
assert(myStops.size() > 0);
1903
return myStops.front();
1904
}
1905
1906
MSStop&
1907
MSBaseVehicle::getNextStopMutable() {
1908
assert(myStops.size() > 0);
1909
return myStops.front();
1910
}
1911
1912
SUMOTime
1913
MSBaseVehicle::getStopDuration() const {
1914
if (isStopped()) {
1915
return myStops.front().duration;
1916
} else {
1917
return 0;
1918
}
1919
}
1920
1921
1922
MSStop&
1923
MSBaseVehicle::getStop(int nextStopIndex) {
1924
if (nextStopIndex < 0 || (int)myStops.size() <= nextStopIndex) {
1925
throw InvalidArgument(TLF("Invalid stop index % (has % stops).", nextStopIndex, myStops.size()));
1926
}
1927
auto stopIt = myStops.begin();
1928
std::advance(stopIt, nextStopIndex);
1929
return *stopIt;
1930
}
1931
1932
1933
const SUMOVehicleParameter::Stop*
1934
MSBaseVehicle::getNextStopParameter() const {
1935
if (hasStops()) {
1936
return &myStops.front().pars;
1937
}
1938
return nullptr;
1939
}
1940
1941
1942
bool
1943
MSBaseVehicle::addTraciStop(SUMOVehicleParameter::Stop stop, std::string& errorMsg) {
1944
//if the stop exists update the duration
1945
for (std::list<MSStop>::iterator iter = myStops.begin(); iter != myStops.end(); iter++) {
1946
if (iter->lane->getID() == stop.lane && fabs(iter->pars.endPos - stop.endPos) < POSITION_EPS) {
1947
// update existing stop
1948
if (stop.duration == 0 && stop.until < 0 && !iter->reached) {
1949
myStops.erase(iter);
1950
} else {
1951
iter->duration = stop.duration;
1952
iter->triggered = stop.triggered;
1953
iter->containerTriggered = stop.containerTriggered;
1954
const_cast<SUMOVehicleParameter::Stop&>(iter->pars).until = stop.until;
1955
const_cast<SUMOVehicleParameter::Stop&>(iter->pars).parking = stop.parking;
1956
}
1957
return true;
1958
}
1959
}
1960
const bool result = addStop(stop, errorMsg);
1961
if (result) {
1962
/// XXX handle stops added out of order
1963
myParameter->stops.push_back(stop);
1964
}
1965
return result;
1966
}
1967
1968
1969
void
1970
MSBaseVehicle::unregisterWaiting() {
1971
if (myAmRegisteredAsWaiting) {
1972
MSNet::getInstance()->getVehicleControl().unregisterOneWaiting();
1973
myAmRegisteredAsWaiting = false;
1974
}
1975
}
1976
1977
1978
bool
1979
MSBaseVehicle::abortNextStop(int nextStopIndex) {
1980
if (hasStops() && nextStopIndex < (int)myStops.size()) {
1981
if (nextStopIndex == 0 && isStopped()) {
1982
resumeFromStopping();
1983
} else {
1984
auto stopIt = myStops.begin();
1985
std::advance(stopIt, nextStopIndex);
1986
myStops.erase(stopIt);
1987
}
1988
if (!hasDeparted() && (int)myParameter->stops.size() > nextStopIndex) {
1989
// stops will be rebuilt from scratch on rerouting so we must patch the stops in myParameter
1990
auto stopIt2 = myParameter->stops.begin();
1991
std::advance(stopIt2, nextStopIndex);
1992
const_cast<SUMOVehicleParameter*>(myParameter)->stops.erase(stopIt2);
1993
}
1994
return true;
1995
} else {
1996
return false;
1997
}
1998
}
1999
2000
2001
bool
2002
MSBaseVehicle::replaceStop(int nextStopIndex, SUMOVehicleParameter::Stop stop, const std::string& info, bool teleport, std::string& errorMsg) {
2003
const int n = (int)myStops.size();
2004
if (nextStopIndex < 0 || nextStopIndex >= n) {
2005
errorMsg = TLF("invalid nextStopIndex % for % remaining stops", nextStopIndex, n);
2006
return false;
2007
}
2008
if (nextStopIndex == 0 && isStopped()) {
2009
errorMsg = TL("cannot replace reached stop");
2010
return false;
2011
}
2012
const SUMOTime t = MSNet::getInstance()->getCurrentTimeStep();
2013
MSLane* stopLane = MSLane::dictionary(stop.lane);
2014
MSEdge* stopEdge = &stopLane->getEdge();
2015
2016
auto itStop = myStops.begin();
2017
std::advance(itStop, nextStopIndex);
2018
MSStop& replacedStop = *itStop;
2019
2020
// check parking access rights
2021
if (stop.parkingarea != "") {
2022
MSParkingArea* pa = dynamic_cast<MSParkingArea*>(MSNet::getInstance()->getStoppingPlace(stop.parkingarea, SUMO_TAG_PARKING_AREA));
2023
if (pa != nullptr && !pa->accepts(this)) {
2024
errorMsg = TLF("vehicle '%' does not have the right badge to access parkingArea '%'", getID(), stop.parkingarea);
2025
return false;
2026
}
2027
}
2028
2029
if (replacedStop.lane == stopLane && replacedStop.pars.endPos == stop.endPos && !teleport) {
2030
// only replace stop attributes
2031
const_cast<SUMOVehicleParameter::Stop&>(replacedStop.pars) = stop;
2032
replacedStop.initPars(stop);
2033
return true;
2034
}
2035
2036
if (!stopLane->allowsVehicleClass(getVClass(), myRoutingMode)) {
2037
errorMsg = TLF("disallowed stop lane '%'", stopLane->getID());
2038
return false;
2039
}
2040
2041
const ConstMSEdgeVector& oldEdges = getRoute().getEdges();
2042
std::vector<MSStop> stops(myStops.begin(), myStops.end());
2043
const int junctionOffset = getLane() != nullptr && getLane()->isInternal() ? 1 : 0;
2044
MSRouteIterator itStart = nextStopIndex == 0 ? getCurrentRouteEdge() + junctionOffset : stops[nextStopIndex - 1].edge;
2045
double startPos = nextStopIndex == 0 ? getPositionOnLane() : stops[nextStopIndex - 1].pars.endPos;
2046
MSRouteIterator itEnd = nextStopIndex == n - 1 ? oldEdges.end() - 1 : stops[nextStopIndex + 1].edge;
2047
auto endPos = nextStopIndex == n - 1 ? getArrivalPos() : stops[nextStopIndex + 1].pars.endPos;
2048
SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = getRouterTT();
2049
2050
bool newDestination = nextStopIndex == n - 1 && stops[nextStopIndex].edge == oldEdges.end() - 1;
2051
2052
ConstMSEdgeVector toNewStop;
2053
if (!teleport) {
2054
router.compute(*itStart, startPos, stopEdge, stop.endPos, this, t, toNewStop, true);
2055
if (toNewStop.size() == 0) {
2056
errorMsg = TLF("no route found from edge '%' to stop edge '%'", (*itStart)->getID(), stopEdge->getID());
2057
return false;
2058
}
2059
}
2060
2061
ConstMSEdgeVector fromNewStop;
2062
if (!newDestination) {
2063
router.compute(stopEdge, stop.endPos, *itEnd, endPos, this, t, fromNewStop, true);
2064
if (fromNewStop.size() == 0) {
2065
errorMsg = TLF("no route found from stop edge '%' to edge '%'", stopEdge->getID(), (*itEnd)->getID());
2066
return false;
2067
}
2068
}
2069
2070
const_cast<SUMOVehicleParameter::Stop&>(replacedStop.pars) = stop;
2071
replacedStop.initPars(stop);
2072
replacedStop.edge = myRoute->end(); // will be patched in replaceRoute
2073
replacedStop.lane = stopLane;
2074
if (MSGlobals::gUseMesoSim) {
2075
replacedStop.segment = MSGlobals::gMesoNet->getSegmentForEdge(replacedStop.lane->getEdge(), replacedStop.getEndPos(*this));
2076
if (replacedStop.lane->isInternal()) {
2077
errorMsg = TLF("Mesoscopic simulation does not allow stopping on internal edge '%' for vehicle '%'.", stop.edge, getID());
2078
return false;
2079
}
2080
}
2081
2082
ConstMSEdgeVector oldRemainingEdges(myCurrEdge, getRoute().end());
2083
ConstMSEdgeVector newEdges; // only remaining
2084
newEdges.insert(newEdges.end(), myCurrEdge, itStart);
2085
if (!teleport) {
2086
newEdges.insert(newEdges.end(), toNewStop.begin(), toNewStop.end() - 1);
2087
} else {
2088
newEdges.push_back(*itStart);
2089
}
2090
if (!newDestination) {
2091
newEdges.insert(newEdges.end(), fromNewStop.begin(), fromNewStop.end() - 1);
2092
newEdges.insert(newEdges.end(), itEnd, oldEdges.end());
2093
} else {
2094
newEdges.push_back(stopEdge);
2095
}
2096
//std::cout << SIMTIME << " replaceStop veh=" << getID()
2097
// << " teleport=" << teleport
2098
// << " busStop=" << stop.busstop
2099
// << " oldEdges=" << oldRemainingEdges.size()
2100
// << " newEdges=" << newEdges.size()
2101
// << " toNewStop=" << toNewStop.size()
2102
// << " fromNewStop=" << fromNewStop.size()
2103
// << "\n";
2104
2105
const double routeCost = router.recomputeCosts(newEdges, this, t);
2106
const double previousCost = router.recomputeCosts(oldRemainingEdges, this, t);
2107
const double savings = previousCost - routeCost;
2108
if (!hasDeparted() && (int)myParameter->stops.size() > nextStopIndex) {
2109
// stops will be rebuilt from scratch so we must patch the stops in myParameter
2110
const_cast<SUMOVehicleParameter*>(myParameter)->stops[nextStopIndex] = stop;
2111
}
2112
if (teleport) {
2113
// let the vehicle jump rather than teleport
2114
// we add a jump-stop at the end of the edge (unless the vehicle is
2115
// already configure to jump before the replaced stop)
2116
if (!insertJump(nextStopIndex, itStart, errorMsg)) {
2117
return false;
2118
};
2119
}
2120
return replaceRouteEdges(newEdges, routeCost, savings, info, !hasDeparted(), false, false, &errorMsg);
2121
}
2122
2123
2124
bool
2125
MSBaseVehicle::rerouteBetweenStops(int nextStopIndex, const std::string& info, bool teleport, std::string& errorMsg) {
2126
const int n = (int)myStops.size();
2127
if (nextStopIndex < 0 || nextStopIndex > n) {
2128
errorMsg = TLF("invalid nextStopIndex % for % remaining stops", nextStopIndex, n);
2129
return false;
2130
}
2131
if (nextStopIndex == 0 && isStopped()) {
2132
errorMsg = TL("cannot reroute towards reached stop");
2133
return false;
2134
}
2135
const SUMOTime t = MSNet::getInstance()->getCurrentTimeStep();
2136
2137
const ConstMSEdgeVector& oldEdges = getRoute().getEdges();
2138
std::vector<MSStop> stops(myStops.begin(), myStops.end());
2139
const int junctionOffset = getLane() != nullptr && getLane()->isInternal() ? 1 : 0;
2140
MSRouteIterator itStart = nextStopIndex == 0 ? getCurrentRouteEdge() + junctionOffset : stops[nextStopIndex - 1].edge;
2141
double startPos = nextStopIndex == 0 ? getPositionOnLane() : stops[nextStopIndex - 1].pars.endPos;
2142
MSRouteIterator itEnd = nextStopIndex == n ? oldEdges.end() - 1 : stops[nextStopIndex].edge;
2143
auto endPos = nextStopIndex == n ? getArrivalPos() : stops[nextStopIndex].pars.endPos;
2144
SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = getRouterTT();
2145
2146
ConstMSEdgeVector newBetween;
2147
if (!teleport) {
2148
router.compute(*itStart, startPos, *itEnd, endPos, this, t, newBetween, true);
2149
if (newBetween.size() == 0) {
2150
errorMsg = TLF("no route found from edge '%' to stop edge '%'", (*itStart)->getID(), (*itEnd)->getID());
2151
return false;
2152
}
2153
}
2154
2155
ConstMSEdgeVector oldRemainingEdges(myCurrEdge, getRoute().end());
2156
ConstMSEdgeVector newEdges; // only remaining
2157
newEdges.insert(newEdges.end(), myCurrEdge, itStart);
2158
if (!teleport) {
2159
newEdges.insert(newEdges.end(), newBetween.begin(), newBetween.end() - 1);
2160
} else {
2161
newEdges.push_back(*itStart);
2162
}
2163
newEdges.insert(newEdges.end(), itEnd, oldEdges.end());
2164
//std::cout << SIMTIME << " rerouteBetweenStops veh=" << getID()
2165
// << " oldEdges=" << oldRemainingEdges.size()
2166
// << " newEdges=" << newEdges.size()
2167
// << " toNewStop=" << toNewStop.size()
2168
// << " fromNewStop=" << fromNewStop.size()
2169
// << "\n";
2170
2171
const double routeCost = router.recomputeCosts(newEdges, this, t);
2172
const double previousCost = router.recomputeCosts(oldRemainingEdges, this, t);
2173
const double savings = previousCost - routeCost;
2174
2175
if (teleport) {
2176
// let the vehicle jump rather than teleport
2177
// we add a jump-stop at the end of the edge (unless the vehicle is
2178
// already configure to jump before the replaced stop)
2179
if (!insertJump(nextStopIndex, itStart, errorMsg)) {
2180
return false;
2181
};
2182
}
2183
return replaceRouteEdges(newEdges, routeCost, savings, info, !hasDeparted(), false, false, &errorMsg);
2184
}
2185
2186
2187
bool
2188
MSBaseVehicle::insertJump(int nextStopIndex, MSRouteIterator itStart, std::string& errorMsg) {
2189
bool needJump = true;
2190
if (nextStopIndex > 0) {
2191
auto itPriorStop = myStops.begin();
2192
std::advance(itPriorStop, nextStopIndex - 1);
2193
const MSStop& priorStop = *itPriorStop;
2194
if (priorStop.pars.jump >= 0) {
2195
needJump = false;
2196
}
2197
}
2198
if (needJump) {
2199
SUMOVehicleParameter::Stop jumpStopPars;
2200
jumpStopPars.endPos = (*itStart)->getLength();
2201
jumpStopPars.speed = 1000;
2202
jumpStopPars.jump = 0;
2203
jumpStopPars.edge = (*itStart)->getID();
2204
jumpStopPars.parametersSet = STOP_SPEED_SET | STOP_JUMP_SET;
2205
MSLane* jumpStopLane = nullptr;
2206
for (MSLane* cand : (*itStart)->getLanes()) {
2207
if (cand->allowsVehicleClass(getVClass())) {
2208
jumpStopLane = cand;
2209
break;
2210
}
2211
}
2212
if (jumpStopLane == nullptr) {
2213
errorMsg = TL("unable to replace stop with teleporting");
2214
return false;
2215
}
2216
auto itStop = myStops.begin();
2217
std::advance(itStop, nextStopIndex);
2218
MSStop jumpStop(jumpStopPars);
2219
jumpStop.initPars(jumpStopPars);
2220
jumpStop.lane = jumpStopLane;
2221
jumpStop.edge = myRoute->end(); // will be patched in replaceRoute
2222
myStops.insert(itStop, jumpStop);
2223
if (!hasDeparted() && (int)myParameter->stops.size() > nextStopIndex) {
2224
// stops will be rebuilt from scratch so we must patch the stops in myParameter
2225
auto it = myParameter->stops.begin() + nextStopIndex;
2226
const_cast<SUMOVehicleParameter*>(myParameter)->stops.insert(it, jumpStopPars);
2227
}
2228
}
2229
return true;
2230
}
2231
2232
2233
bool
2234
MSBaseVehicle::insertStop(int nextStopIndex, SUMOVehicleParameter::Stop stop, const std::string& info, bool teleport, std::string& errorMsg) {
2235
const int n = (int)myStops.size();
2236
if (nextStopIndex < 0 || nextStopIndex > n) {
2237
errorMsg = TLF("invalid nextStopIndex % for % remaining stops", nextStopIndex, n);
2238
return false;
2239
}
2240
if (nextStopIndex == 0 && isStopped()) {
2241
errorMsg = TL("cannot insert stop before the currently reached stop");
2242
return false;
2243
}
2244
const SUMOTime t = MSNet::getInstance()->getCurrentTimeStep();
2245
MSLane* stopLane = MSLane::dictionary(stop.lane);
2246
MSEdge* stopEdge = &stopLane->getEdge();
2247
2248
if (!stopLane->allowsVehicleClass(getVClass(), myRoutingMode)) {
2249
errorMsg = TLF("disallowed stop lane '%'", stopLane->getID());
2250
return false;
2251
}
2252
2253
// check parking access rights
2254
if (stop.parkingarea != "") {
2255
MSParkingArea* pa = dynamic_cast<MSParkingArea*>(MSNet::getInstance()->getStoppingPlace(stop.parkingarea, SUMO_TAG_PARKING_AREA));
2256
if (pa != nullptr && !pa->accepts(this)) {
2257
errorMsg = TLF("Vehicle '%' does not have the right badge to access parkingArea '%'.", getID(), stop.parkingarea);
2258
return false;
2259
}
2260
}
2261
2262
const ConstMSEdgeVector& oldEdges = getRoute().getEdges();
2263
std::vector<MSStop> stops(myStops.begin(), myStops.end());
2264
const int junctionOffset = getLane() != nullptr && getLane()->isInternal() ? 1 : 0;
2265
MSRouteIterator itStart = nextStopIndex == 0 ? getCurrentRouteEdge() + junctionOffset : stops[nextStopIndex - 1].edge;
2266
double startPos = nextStopIndex == 0 ? getPositionOnLane() : stops[nextStopIndex - 1].pars.endPos;
2267
MSRouteIterator itEnd = nextStopIndex == n ? oldEdges.end() - 1 : stops[nextStopIndex].edge;
2268
auto endPos = nextStopIndex == n ? getArrivalPos() : stops[nextStopIndex].pars.endPos;
2269
SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = getRouterTT();
2270
2271
bool newDestination = nextStopIndex == n && stopEdge == oldEdges.back();
2272
2273
ConstMSEdgeVector toNewStop;
2274
if (!teleport) {
2275
router.compute(*itStart, startPos, stopEdge, stop.endPos, this, t, toNewStop, true);
2276
if (toNewStop.size() == 0) {
2277
errorMsg = TLF("no route found from edge '%' to stop edge '%'", (*itStart)->getID(), stopEdge->getID());
2278
return false;
2279
}
2280
}
2281
2282
ConstMSEdgeVector fromNewStop;
2283
if (!newDestination) {
2284
router.compute(stopEdge, stop.endPos, *itEnd, endPos, this, t, fromNewStop, true);
2285
if (fromNewStop.size() == 0) {
2286
errorMsg = TLF("no route found from stop edge '%' to edge '%'", stopEdge->getID(), (*itEnd)->getID());
2287
return false;
2288
}
2289
}
2290
2291
auto itStop = myStops.begin();
2292
std::advance(itStop, nextStopIndex);
2293
MSStop newStop(stop);
2294
newStop.initPars(stop);
2295
newStop.edge = myRoute->end(); // will be patched in replaceRoute
2296
newStop.lane = stopLane;
2297
if (MSGlobals::gUseMesoSim) {
2298
newStop.segment = MSGlobals::gMesoNet->getSegmentForEdge(newStop.lane->getEdge(), newStop.getEndPos(*this));
2299
if (newStop.lane->isInternal()) {
2300
errorMsg = TLF("Mesoscopic simulation does not allow stopping on internal edge '%' for vehicle '%'.", stop.edge, getID());
2301
return false;
2302
}
2303
}
2304
myStops.insert(itStop, newStop);
2305
2306
ConstMSEdgeVector oldRemainingEdges(myCurrEdge, getRoute().end());
2307
ConstMSEdgeVector newEdges; // only remaining
2308
newEdges.insert(newEdges.end(), myCurrEdge, itStart);
2309
if (!teleport) {
2310
newEdges.insert(newEdges.end(), toNewStop.begin(), toNewStop.end() - 1);
2311
} else {
2312
newEdges.push_back(*itStart);
2313
}
2314
if (!newDestination) {
2315
newEdges.insert(newEdges.end(), fromNewStop.begin(), fromNewStop.end() - 1);
2316
newEdges.insert(newEdges.end(), itEnd, oldEdges.end());
2317
} else {
2318
newEdges.push_back(stopEdge);
2319
}
2320
//std::cout << SIMTIME << " insertStop veh=" << getID()
2321
// << " teleport=" << teleport
2322
// << " busStop=" << stop.busstop
2323
// << " oldEdges=" << oldRemainingEdges.size()
2324
// << " newEdges=" << newEdges.size()
2325
// << " toNewStop=" << toNewStop.size()
2326
// << " fromNewStop=" << fromNewStop.size()
2327
// << "\n";
2328
2329
const double routeCost = router.recomputeCosts(newEdges, this, t);
2330
const double previousCost = router.recomputeCosts(oldRemainingEdges, this, t);
2331
const double savings = previousCost - routeCost;
2332
2333
if (!hasDeparted() && (int)myParameter->stops.size() >= nextStopIndex) {
2334
// stops will be rebuilt from scratch so we must patch the stops in myParameter
2335
auto it = myParameter->stops.begin() + nextStopIndex;
2336
const_cast<SUMOVehicleParameter*>(myParameter)->stops.insert(it, stop);
2337
}
2338
return replaceRouteEdges(newEdges, routeCost, savings, info, !hasDeparted(), false, false, &errorMsg);
2339
}
2340
2341
2342
double
2343
MSBaseVehicle::getStateOfCharge() const {
2344
if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
2345
MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
2346
return batteryOfVehicle->getActualBatteryCapacity();
2347
} else {
2348
if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
2349
MSDevice_ElecHybrid* batteryOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
2350
return batteryOfVehicle->getActualBatteryCapacity();
2351
}
2352
}
2353
return -1;
2354
}
2355
2356
2357
double
2358
MSBaseVehicle::getRelativeStateOfCharge() const {
2359
if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
2360
MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
2361
return batteryOfVehicle->getActualBatteryCapacity() / batteryOfVehicle->getMaximumBatteryCapacity();
2362
} else {
2363
if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
2364
MSDevice_ElecHybrid* batteryOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
2365
return batteryOfVehicle->getActualBatteryCapacity() / batteryOfVehicle->getMaximumBatteryCapacity();
2366
}
2367
}
2368
return -1;
2369
}
2370
2371
2372
double
2373
MSBaseVehicle::getChargedEnergy() const {
2374
if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
2375
MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
2376
return batteryOfVehicle->getEnergyCharged();
2377
} else {
2378
if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
2379
MSDevice_ElecHybrid* batteryOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
2380
return batteryOfVehicle->getEnergyCharged();
2381
}
2382
}
2383
return -1;
2384
}
2385
2386
2387
double
2388
MSBaseVehicle::getMaxChargeRate() const {
2389
if (static_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery))) != 0) {
2390
MSDevice_Battery* batteryOfVehicle = dynamic_cast<MSDevice_Battery*>(getDevice(typeid(MSDevice_Battery)));
2391
return batteryOfVehicle->getMaximumChargeRate();
2392
}
2393
return -1;
2394
}
2395
2396
2397
double
2398
MSBaseVehicle::getElecHybridCurrent() const {
2399
if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
2400
MSDevice_ElecHybrid* elecHybridDevice = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
2401
return elecHybridDevice->getCurrentFromOverheadWire();
2402
}
2403
2404
return NAN;
2405
}
2406
2407
double
2408
MSBaseVehicle::getHarmonoise_NoiseEmissions() const {
2409
if (isOnRoad() || isIdling()) {
2410
return HelpersHarmonoise::computeNoise(myType->getEmissionClass(), getSpeed(), getAcceleration());
2411
} else {
2412
return 0.;
2413
}
2414
}
2415
2416
2417
const MSEdgeWeightsStorage&
2418
MSBaseVehicle::getWeightsStorage() const {
2419
return _getWeightsStorage();
2420
}
2421
2422
2423
MSEdgeWeightsStorage&
2424
MSBaseVehicle::getWeightsStorage() {
2425
return _getWeightsStorage();
2426
}
2427
2428
2429
MSEdgeWeightsStorage&
2430
MSBaseVehicle::_getWeightsStorage() const {
2431
if (myEdgeWeights == nullptr) {
2432
myEdgeWeights = new MSEdgeWeightsStorage();
2433
}
2434
return *myEdgeWeights;
2435
}
2436
2437
2438
2439
2440
int
2441
MSBaseVehicle::getPersonNumber() const {
2442
int boarded = myPersonDevice == nullptr ? 0 : myPersonDevice->size();
2443
return boarded + myParameter->personNumber;
2444
}
2445
2446
int
2447
MSBaseVehicle::getLeavingPersonNumber() const {
2448
int leavingPersonNumber = 0;
2449
const std::vector<MSTransportable*>& persons = getPersons();
2450
for (std::vector<MSTransportable*>::const_iterator it_p = persons.begin(); it_p != persons.end(); ++it_p) {
2451
MSStageDriving* const stage = dynamic_cast<MSStageDriving*>((*it_p)->getCurrentStage());
2452
const MSStop* stop = &myStops.front();
2453
const MSVehicle* joinVeh = dynamic_cast<MSVehicle*>(MSNet::getInstance()->getVehicleControl().getVehicle((*stop).pars.join));
2454
if (stop && stage->canLeaveVehicle(*it_p, *this, *stop) && !MSDevice_Transportable::willTransferAtJoin(*it_p, joinVeh)) {
2455
leavingPersonNumber++;
2456
}
2457
}
2458
return leavingPersonNumber;
2459
}
2460
2461
std::vector<std::string>
2462
MSBaseVehicle::getPersonIDList() const {
2463
std::vector<std::string> ret;
2464
const std::vector<MSTransportable*>& persons = getPersons();
2465
for (std::vector<MSTransportable*>::const_iterator it_p = persons.begin(); it_p != persons.end(); ++it_p) {
2466
ret.push_back((*it_p)->getID());
2467
}
2468
return ret;
2469
}
2470
2471
int
2472
MSBaseVehicle::getContainerNumber() const {
2473
int loaded = myContainerDevice == nullptr ? 0 : myContainerDevice->size();
2474
return loaded + myParameter->containerNumber;
2475
}
2476
2477
2478
void
2479
MSBaseVehicle::removeTransportable(MSTransportable* t) {
2480
// this might be called from the MSTransportable destructor so we cannot do a dynamic cast to determine the type
2481
if (myPersonDevice != nullptr) {
2482
myPersonDevice->removeTransportable(t);
2483
}
2484
if (myContainerDevice != nullptr) {
2485
myContainerDevice->removeTransportable(t);
2486
}
2487
if (myEnergyParams != nullptr) {
2488
myEnergyParams->setTransportableMass(myEnergyParams->getTransportableMass() - t->getVehicleType().getMass());
2489
}
2490
}
2491
2492
2493
void
2494
MSBaseVehicle::removeTransportableMass(MSTransportable* t) {
2495
if (myEnergyParams != nullptr) {
2496
myEnergyParams->setTransportableMass(myEnergyParams->getTransportableMass() - t->getVehicleType().getMass());
2497
}
2498
}
2499
2500
2501
const std::vector<MSTransportable*>&
2502
MSBaseVehicle::getPersons() const {
2503
if (myPersonDevice == nullptr) {
2504
return myEmptyTransportableVector;
2505
} else {
2506
return myPersonDevice->getTransportables();
2507
}
2508
}
2509
2510
2511
const std::vector<MSTransportable*>&
2512
MSBaseVehicle::getContainers() const {
2513
if (myContainerDevice == nullptr) {
2514
return myEmptyTransportableVector;
2515
} else {
2516
return myContainerDevice->getTransportables();
2517
}
2518
}
2519
2520
2521
bool
2522
MSBaseVehicle::isLineStop(double position) const {
2523
if (myParameter->line == "") {
2524
// not a public transport line
2525
return false;
2526
}
2527
for (const SUMOVehicleParameter::Stop& stop : myParameter->stops) {
2528
if (stop.startPos <= position && position <= stop.endPos) {
2529
return true;
2530
}
2531
}
2532
for (const SUMOVehicleParameter::Stop& stop : myRoute->getStops()) {
2533
if (stop.startPos <= position && position <= stop.endPos) {
2534
return true;
2535
}
2536
}
2537
return false;
2538
}
2539
2540
2541
bool
2542
MSBaseVehicle::hasDevice(const std::string& deviceName) const {
2543
for (MSDevice* const dev : myDevices) {
2544
if (dev->deviceName() == deviceName) {
2545
return true;
2546
}
2547
}
2548
return false;
2549
}
2550
2551
2552
void
2553
MSBaseVehicle::createDevice(const std::string& deviceName) {
2554
if (!hasDevice(deviceName)) {
2555
if (deviceName == "rerouting") {
2556
((SUMOVehicleParameter*)myParameter)->setParameter("has." + deviceName + ".device", "true");
2557
MSDevice_Routing::buildVehicleDevices(*this, myDevices);
2558
if (hasDeparted()) {
2559
// vehicle already departed: disable pre-insertion rerouting and enable regular routing behavior
2560
MSDevice_Routing* routingDevice = static_cast<MSDevice_Routing*>(getDevice(typeid(MSDevice_Routing)));
2561
assert(routingDevice != 0);
2562
routingDevice->notifyEnter(*this, MSMoveReminder::NOTIFICATION_DEPARTED);
2563
}
2564
} else {
2565
throw InvalidArgument(TLF("creating device of type '%' is not supported", deviceName));
2566
}
2567
}
2568
}
2569
2570
2571
std::string
2572
MSBaseVehicle::getDeviceParameter(const std::string& deviceName, const std::string& key) const {
2573
for (MSVehicleDevice* const dev : myDevices) {
2574
if (dev->deviceName() == deviceName) {
2575
return dev->getParameter(key);
2576
}
2577
}
2578
throw InvalidArgument(TLF("no device of type '%' exists", deviceName));
2579
}
2580
2581
2582
void
2583
MSBaseVehicle::setDeviceParameter(const std::string& deviceName, const std::string& key, const std::string& value) {
2584
for (MSVehicleDevice* const dev : myDevices) {
2585
if (dev->deviceName() == deviceName) {
2586
dev->setParameter(key, value);
2587
return;
2588
}
2589
}
2590
throw InvalidArgument(TLF("no device of type '%' exists", deviceName));
2591
}
2592
2593
2594
void
2595
MSBaseVehicle::setJunctionModelParameter(const std::string& key, const std::string& value) {
2596
if (key == toString(SUMO_ATTR_JM_IGNORE_IDS) || key == toString(SUMO_ATTR_JM_IGNORE_TYPES)) {
2597
getParameter().parametersSet |= VEHPARS_JUNCTIONMODEL_PARAMS_SET;
2598
const_cast<SUMOVehicleParameter&>(getParameter()).setParameter(key, value);
2599
// checked in MSLink::ignoreFoe
2600
} else {
2601
throw InvalidArgument(TLF("Vehicle '%' does not support junctionModel parameter '%'.", getID(), key));
2602
}
2603
}
2604
2605
2606
void
2607
MSBaseVehicle::setCarFollowModelParameter(const std::string& key, const std::string& value) {
2608
// handle some generic params first and then delegate to the carFollowModel itself
2609
if (key == toString(SUMO_ATTR_CF_IGNORE_IDS) || key == toString(SUMO_ATTR_CF_IGNORE_TYPES)) {
2610
getParameter().parametersSet |= VEHPARS_CFMODEL_PARAMS_SET;
2611
const_cast<SUMOVehicleParameter&>(getParameter()).setParameter(key, value);
2612
// checked in MSVehicle::planMove
2613
} else {
2614
MSVehicle* microVeh = dynamic_cast<MSVehicle*>(this);
2615
if (microVeh) {
2616
// remove 'carFollowModel.' prefix
2617
const std::string attrName = key.substr(15);
2618
microVeh->getCarFollowModel().setParameter(microVeh, attrName, value);
2619
}
2620
}
2621
}
2622
2623
2624
void
2625
MSBaseVehicle::initTransientModelParams() {
2626
/* Design idea for additional junction model parameters:
2627
We can distinguish between 3 levels of parameters
2628
1. typically shared by multiple vehicles -> vType parameter
2629
2. specific to one vehicle but stays constant throughout the simulation -> vehicle parameter
2630
3. specific to one vehicle and expected to change during simulation -> prefixed generic vehicle parameter
2631
*/
2632
for (auto item : getParameter().getParametersMap()) {
2633
if (StringUtils::startsWith(item.first, "junctionModel.")) {
2634
setJunctionModelParameter(item.first, item.second);
2635
} else if (StringUtils::startsWith(item.first, "carFollowModel.")) {
2636
setCarFollowModelParameter(item.first, item.second);
2637
}
2638
}
2639
const std::string routingModeStr = getStringParam("device.rerouting.mode");
2640
try {
2641
int routingMode = StringUtils::toInt(routingModeStr);
2642
if (routingMode != libsumo::ROUTING_MODE_DEFAULT) {
2643
setRoutingMode(routingMode);
2644
}
2645
} catch (NumberFormatException&) {
2646
// @todo interpret symbolic constants
2647
throw ProcessError(TLF("could not interpret routing.mode '%'", routingModeStr));
2648
}
2649
}
2650
2651
2652
SUMOAbstractRouter<MSEdge, SUMOVehicle>&
2653
MSBaseVehicle::getRouterTT() const {
2654
if (myRoutingMode == libsumo::ROUTING_MODE_AGGREGATED) {
2655
return MSRoutingEngine::getRouterTT(getRNGIndex(), getVClass());
2656
} else {
2657
return MSNet::getInstance()->getRouterTT(getRNGIndex());
2658
}
2659
}
2660
2661
2662
void
2663
MSBaseVehicle::replaceVehicleType(const MSVehicleType* type) {
2664
assert(type != nullptr);
2665
// save old parameters before possible type deletion
2666
const double oldMu = myType->getSpeedFactor().getParameter(0);
2667
const double oldDev = myType->getSpeedFactor().getParameter(1);
2668
if (myType->isVehicleSpecific() && type != myType) {
2669
MSNet::getInstance()->getVehicleControl().removeVType(myType);
2670
}
2671
// adapt myChosenSpeedFactor to the new type
2672
if (oldDev == 0.) {
2673
// old type had speedDev 0, reroll
2674
myChosenSpeedFactor = type->computeChosenSpeedDeviation(getRNG());
2675
} else {
2676
// map old speedFactor onto new distribution
2677
const double distPoint = (myChosenSpeedFactor - oldMu) / oldDev;
2678
const double newMu = type->getSpeedFactor().getParameter(0);
2679
const double newDev = type->getSpeedFactor().getParameter(1);
2680
myChosenSpeedFactor = newMu + distPoint * newDev;
2681
// respect distribution limits
2682
myChosenSpeedFactor = MIN2(myChosenSpeedFactor, type->getSpeedFactor().getMax());
2683
myChosenSpeedFactor = MAX2(myChosenSpeedFactor, type->getSpeedFactor().getMin());
2684
}
2685
myType = type;
2686
if (myEnergyParams != nullptr) {
2687
myEnergyParams->setSecondary(type->getEmissionParameters());
2688
}
2689
}
2690
2691
2692
MSVehicleType&
2693
MSBaseVehicle::getSingularType() {
2694
if (myType->isVehicleSpecific()) {
2695
return *const_cast<MSVehicleType*>(myType);
2696
}
2697
MSVehicleType* type = myType->buildSingularType(myType->getID() + "@" + getID());
2698
replaceVehicleType(type);
2699
return *type;
2700
}
2701
2702
2703
int
2704
MSBaseVehicle::getRNGIndex() const {
2705
const MSLane* const lane = getLane();
2706
if (lane == nullptr) {
2707
return getEdge()->getLanes()[0]->getRNGIndex();
2708
} else {
2709
return lane->getRNGIndex();
2710
}
2711
}
2712
2713
2714
SumoRNG*
2715
MSBaseVehicle::getRNG() const {
2716
const MSLane* lane = getLane();
2717
if (lane == nullptr) {
2718
return getEdge()->getLanes()[0]->getRNG();
2719
} else {
2720
return lane->getRNG();
2721
}
2722
}
2723
2724
std::string
2725
MSBaseVehicle::getPrefixedParameter(const std::string& key, std::string& error) const {
2726
const MSVehicle* microVeh = dynamic_cast<const MSVehicle*>(this);
2727
if (StringUtils::startsWith(key, "device.")) {
2728
StringTokenizer tok(key, ".");
2729
if (tok.size() < 3) {
2730
error = TLF("Invalid device parameter '%' for vehicle '%'.", key, getID());
2731
return "";
2732
}
2733
try {
2734
return getDeviceParameter(tok.get(1), key.substr(tok.get(0).size() + tok.get(1).size() + 2));
2735
} catch (InvalidArgument& e) {
2736
error = TLF("Vehicle '%' does not support device parameter '%' (%).", getID(), key, e.what());
2737
return "";
2738
}
2739
} else if (StringUtils::startsWith(key, "laneChangeModel.")) {
2740
if (microVeh == nullptr) {
2741
error = TLF("Mesoscopic vehicle '%' does not support laneChangeModel parameters.", getID());
2742
return "";
2743
}
2744
const std::string attrName = key.substr(16);
2745
try {
2746
return microVeh->getLaneChangeModel().getParameter(attrName);
2747
} catch (InvalidArgument& e) {
2748
error = TLF("Vehicle '%' does not support laneChangeModel parameter '%' (%).", getID(), key, e.what());
2749
return "";
2750
}
2751
} else if (StringUtils::startsWith(key, "carFollowModel.")) {
2752
if (microVeh == nullptr) {
2753
error = TLF("Mesoscopic vehicle '%' does not support carFollowModel parameters.", getID());
2754
return "";
2755
}
2756
const std::string attrName = key.substr(15);
2757
try {
2758
return microVeh->getCarFollowModel().getParameter(microVeh, attrName);
2759
} catch (InvalidArgument& e) {
2760
error = TLF("Vehicle '%' does not support carFollowModel parameter '%' (%).", getID(), key, e.what());
2761
return "";
2762
}
2763
} else if (StringUtils::startsWith(key, "has.") && StringUtils::endsWith(key, ".device")) {
2764
StringTokenizer tok(key, ".");
2765
if (tok.size() != 3) {
2766
error = TL("Invalid check for device. Expected format is 'has.DEVICENAME.device'.");
2767
return "";
2768
}
2769
return hasDevice(tok.get(1)) ? "true" : "false";
2770
// parking related parameters start here
2771
} else if (key == "parking.rerouteCount") {
2772
return toString(getNumberParkingReroutes());
2773
} else if (StringUtils::startsWith(key, "parking.memory.")) {
2774
std::vector<std::string> values;
2775
if (getParkingMemory()) {
2776
if (key == "parking.memory.IDList") {
2777
for (const auto& item : *getParkingMemory()) {
2778
values.push_back(item.first->getID());
2779
}
2780
} else if (key == "parking.memory.score") {
2781
for (const auto& item : *getParkingMemory()) {
2782
values.push_back(item.second.score);
2783
}
2784
} else if (key == "parking.memory.blockedAtTime") {
2785
for (const auto& item : *getParkingMemory()) {
2786
values.push_back(toString(STEPS2TIME(item.second.blockedAtTime)));
2787
}
2788
} else if (key == "parking.memory.blockedAtTimeLocal") {
2789
for (const auto& item : *getParkingMemory()) {
2790
values.push_back(toString(STEPS2TIME(item.second.blockedAtTimeLocal)));
2791
}
2792
} else {
2793
error = TLF("Unsupported parking parameter '%' for vehicle '%'.", key, getID());
2794
}
2795
}
2796
return toString(values);
2797
} else {
2798
// default: custom user parameter
2799
return getParameter().getParameter(key, "");
2800
}
2801
}
2802
2803
2804
void
2805
MSBaseVehicle::rememberBlockedParkingArea(const MSStoppingPlace* pa, bool local) {
2806
if (myParkingMemory == nullptr) {
2807
myParkingMemory = new StoppingPlaceMemory();
2808
}
2809
myParkingMemory->rememberBlockedStoppingPlace(pa, local);
2810
}
2811
2812
2813
void
2814
MSBaseVehicle::resetParkingAreaScores() {
2815
if (myParkingMemory != nullptr) {
2816
myParkingMemory->resetStoppingPlaceScores();
2817
}
2818
}
2819
2820
2821
void
2822
MSBaseVehicle::rememberChargingStationScore(const MSStoppingPlace* cs, const std::string& score) {
2823
if (myChargingMemory == nullptr) {
2824
myChargingMemory = new StoppingPlaceMemory();
2825
}
2826
myChargingMemory->rememberStoppingPlaceScore(cs, score);
2827
}
2828
2829
2830
void
2831
MSBaseVehicle::resetChargingStationScores() {
2832
if (myChargingMemory != nullptr) {
2833
myChargingMemory->resetStoppingPlaceScores();
2834
}
2835
}
2836
2837
2838
void
2839
MSBaseVehicle::rememberParkingAreaScore(const MSStoppingPlace* pa, const std::string& score) {
2840
if (myParkingMemory == nullptr) {
2841
myParkingMemory = new StoppingPlaceMemory();
2842
}
2843
myParkingMemory->rememberStoppingPlaceScore(pa, score);
2844
}
2845
2846
2847
SUMOTime
2848
MSBaseVehicle::sawBlockedParkingArea(const MSStoppingPlace* pa, bool local) const {
2849
if (myParkingMemory == nullptr) {
2850
return -1;
2851
}
2852
return myParkingMemory->sawBlockedStoppingPlace(pa, local);
2853
}
2854
2855
2856
void MSBaseVehicle::rememberBlockedChargingStation(const MSStoppingPlace* cs, bool local) {
2857
if (myChargingMemory == nullptr) {
2858
myChargingMemory = new StoppingPlaceMemory();
2859
}
2860
myChargingMemory->rememberBlockedStoppingPlace(cs, local);
2861
}
2862
2863
2864
SUMOTime
2865
MSBaseVehicle::sawBlockedChargingStation(const MSStoppingPlace* cs, bool local) const {
2866
if (myChargingMemory == nullptr) {
2867
return -1;
2868
}
2869
return myChargingMemory->sawBlockedStoppingPlace(cs, local);
2870
}
2871
2872
2873
#ifdef _DEBUG
2874
void
2875
MSBaseVehicle::initMoveReminderOutput(const OptionsCont& oc) {
2876
if (oc.isSet("movereminder-output.vehicles")) {
2877
const std::vector<std::string> vehicles = oc.getStringVector("movereminder-output.vehicles");
2878
myShallTraceMoveReminders.insert(vehicles.begin(), vehicles.end());
2879
}
2880
}
2881
2882
2883
void
2884
MSBaseVehicle::traceMoveReminder(const std::string& type, MSMoveReminder* rem, double pos, bool keep) const {
2885
OutputDevice& od = OutputDevice::getDeviceByOption("movereminder-output");
2886
od.openTag("movereminder");
2887
od.writeAttr(SUMO_ATTR_TIME, STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep()));
2888
od.writeAttr("veh", getID());
2889
od.writeAttr(SUMO_ATTR_ID, rem->getDescription());
2890
od.writeAttr("type", type);
2891
od.writeAttr("pos", toString(pos));
2892
od.writeAttr("keep", toString(keep));
2893
od.closeTag();
2894
}
2895
#endif
2896
2897
2898
/****************************************************************************/
2899
2900