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