Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2012-2024 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 Vehicle.cpp
15 : /// @author Jakob Erdmann
16 : /// @author Mirko Barthauer
17 : /// @date 15.03.2017
18 : ///
19 : // C++ Vehicle API
20 : /****************************************************************************/
21 : #include <config.h>
22 :
23 : #include <foreign/tcpip/storage.h>
24 : #include <utils/geom/GeomHelper.h>
25 : #include <utils/common/MsgHandler.h>
26 : #include <utils/common/StringTokenizer.h>
27 : #include <utils/common/StringUtils.h>
28 : #include <utils/gui/globjects/GUIGlObjectTypes.h>
29 : #include <utils/emissions/PollutantsInterface.h>
30 : #include <utils/vehicle/SUMOVehicleParserHelper.h>
31 : #include <microsim/traffic_lights/MSTrafficLightLogic.h>
32 : #include <microsim/lcmodels/MSAbstractLaneChangeModel.h>
33 : #include <microsim/devices/MSDevice.h>
34 : #include <microsim/MSEdgeWeightsStorage.h>
35 : #include <microsim/MSStop.h>
36 : #include <microsim/MSVehicle.h>
37 : #include <microsim/MSVehicleControl.h>
38 : #include <microsim/MSVehicleTransfer.h>
39 : #include <microsim/MSVehicleType.h>
40 : #include <microsim/MSInsertionControl.h>
41 : #include <microsim/MSNet.h>
42 : #include <microsim/MSEdge.h>
43 : #include <microsim/MSLane.h>
44 : #include <microsim/MSParkingArea.h>
45 : #include <microsim/MSJunctionLogic.h>
46 : #include <microsim/devices/MSDevice_Taxi.h>
47 : #include <microsim/devices/MSDispatch_TraCI.h>
48 : #include <mesosim/MEVehicle.h>
49 : #include <libsumo/TraCIDefs.h>
50 : #include <libsumo/TraCIConstants.h>
51 : #include "Helper.h"
52 : #include "Route.h"
53 : #include "Polygon.h"
54 : #include "Vehicle.h"
55 :
56 : #define CALL_MICRO_FUN(veh, fun, mesoResult) ((dynamic_cast<MSVehicle*>(veh) == nullptr ? (mesoResult) : dynamic_cast<MSVehicle*>(veh)->fun))
57 :
58 :
59 : // ===========================================================================
60 : // debug defines
61 : // ===========================================================================
62 : //#define DEBUG_NEIGHBORS
63 : //#define DEBUG_DYNAMIC_SHAPES
64 : //#define DEBUG_MOVEXY
65 : #define DEBUG_COND (veh->isSelected())
66 :
67 :
68 :
69 : namespace libsumo {
70 : // ===========================================================================
71 : // static member initializations
72 : // ===========================================================================
73 : SubscriptionResults Vehicle::mySubscriptionResults;
74 : ContextSubscriptionResults Vehicle::myContextSubscriptionResults;
75 :
76 :
77 : // ===========================================================================
78 : // static member definitions
79 : // ===========================================================================
80 : bool
81 12615003 : Vehicle::isVisible(const SUMOVehicle* veh) {
82 12615003 : return veh->isOnRoad() || veh->isParking() || veh->wasRemoteControlled();
83 : }
84 :
85 :
86 : bool
87 43521 : Vehicle::isOnInit(const std::string& vehID) {
88 43521 : SUMOVehicle* sumoVehicle = MSNet::getInstance()->getVehicleControl().getVehicle(vehID);
89 43521 : return sumoVehicle == nullptr || sumoVehicle->getLane() == nullptr;
90 : }
91 :
92 :
93 : std::vector<std::string>
94 240009 : Vehicle::getIDList() {
95 : std::vector<std::string> ids;
96 240009 : MSVehicleControl& c = MSNet::getInstance()->getVehicleControl();
97 2267658 : for (MSVehicleControl::constVehIt i = c.loadedVehBegin(); i != c.loadedVehEnd(); ++i) {
98 2027651 : if (isVisible((*i).second)) {
99 1999957 : ids.push_back((*i).first);
100 : }
101 : }
102 240007 : return ids;
103 2 : }
104 :
105 : int
106 280 : Vehicle::getIDCount() {
107 280 : return (int)getIDList().size();
108 : }
109 :
110 :
111 : double
112 296630 : Vehicle::getSpeed(const std::string& vehID) {
113 296630 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
114 296601 : return isVisible(veh) ? veh->getSpeed() : INVALID_DOUBLE_VALUE;
115 : }
116 :
117 : double
118 92 : Vehicle::getLateralSpeed(const std::string& vehID) {
119 92 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
120 92 : return isVisible(veh) ? CALL_MICRO_FUN(veh, getLaneChangeModel().getSpeedLat(), 0) : INVALID_DOUBLE_VALUE;
121 : }
122 :
123 :
124 : double
125 6297 : Vehicle::getAcceleration(const std::string& vehID) {
126 6297 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
127 6297 : return isVisible(veh) ? CALL_MICRO_FUN(veh, getAcceleration(), 0) : INVALID_DOUBLE_VALUE;
128 : }
129 :
130 :
131 : double
132 5151 : Vehicle::getSpeedWithoutTraCI(const std::string& vehID) {
133 5151 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
134 5151 : return isVisible(veh) ? CALL_MICRO_FUN(veh, getSpeedWithoutTraciInfluence(), veh->getSpeed()) : INVALID_DOUBLE_VALUE;
135 : }
136 :
137 :
138 : TraCIPosition
139 2088944 : Vehicle::getPosition(const std::string& vehID, const bool includeZ) {
140 2088944 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
141 2088938 : if (isVisible(veh)) {
142 2088798 : return Helper::makeTraCIPosition(veh->getPosition(), includeZ);
143 : }
144 : return TraCIPosition();
145 : }
146 :
147 :
148 : TraCIPosition
149 798 : Vehicle::getPosition3D(const std::string& vehID) {
150 798 : return getPosition(vehID, true);
151 : }
152 :
153 :
154 : double
155 493 : Vehicle::getAngle(const std::string& vehID) {
156 493 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
157 493 : return isVisible(veh) ? GeomHelper::naviDegree(veh->getAngle()) : INVALID_DOUBLE_VALUE;
158 : }
159 :
160 :
161 : double
162 11 : Vehicle::getSlope(const std::string& vehID) {
163 11 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
164 11 : return (veh->isOnRoad() || veh->isParking()) ? veh->getSlope() : INVALID_DOUBLE_VALUE;
165 : }
166 :
167 :
168 : std::string
169 8188164 : Vehicle::getRoadID(const std::string& vehID) {
170 8188164 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
171 8188164 : return isVisible(veh) ? CALL_MICRO_FUN(veh, getLane()->getEdge().getID(), veh->getEdge()->getID()) : "";
172 : }
173 :
174 :
175 : std::string
176 52567 : Vehicle::getLaneID(const std::string& vehID) {
177 52567 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
178 52549 : return veh->isOnRoad() ? CALL_MICRO_FUN(veh, getLane()->getID(), "") : "";
179 : }
180 :
181 :
182 : int
183 45283 : Vehicle::getLaneIndex(const std::string& vehID) {
184 45283 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
185 45278 : return veh->isOnRoad() ? CALL_MICRO_FUN(veh, getLane()->getIndex(), INVALID_INT_VALUE) : INVALID_INT_VALUE;
186 : }
187 :
188 :
189 : std::string
190 27746 : Vehicle::getTypeID(const std::string& vehID) {
191 27746 : return Helper::getVehicleType(vehID).getID();
192 : }
193 :
194 :
195 : std::string
196 141 : Vehicle::getRouteID(const std::string& vehID) {
197 141 : return Helper::getVehicle(vehID)->getRoute().getID();
198 : }
199 :
200 :
201 : double
202 91 : Vehicle::getDeparture(const std::string& vehID) {
203 91 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
204 91 : return veh->hasDeparted() ? STEPS2TIME(veh->getDeparture()) : INVALID_DOUBLE_VALUE;
205 : }
206 :
207 :
208 : double
209 91 : Vehicle::getDepartDelay(const std::string& vehID) {
210 91 : return STEPS2TIME(Helper::getVehicle(vehID)->getDepartDelay());
211 : }
212 :
213 :
214 : int
215 4670 : Vehicle::getRouteIndex(const std::string& vehID) {
216 4670 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
217 4670 : return veh->hasDeparted() ? veh->getRoutePosition() : INVALID_INT_VALUE;
218 : }
219 :
220 :
221 : TraCIColor
222 1208 : Vehicle::getColor(const std::string& vehID) {
223 1208 : return Helper::makeTraCIColor(Helper::getVehicle(vehID)->getParameter().color);
224 : }
225 :
226 : double
227 8165328 : Vehicle::getLanePosition(const std::string& vehID) {
228 8165328 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
229 8165323 : return veh->isOnRoad() ? veh->getPositionOnLane() : INVALID_DOUBLE_VALUE;
230 : }
231 :
232 : double
233 4352 : Vehicle::getLateralLanePosition(const std::string& vehID) {
234 4352 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
235 4352 : return veh->isOnRoad() ? CALL_MICRO_FUN(veh, getLateralPositionOnLane(), 0) : INVALID_DOUBLE_VALUE;
236 : }
237 :
238 : double
239 493 : Vehicle::getCO2Emission(const std::string& vehID) {
240 493 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
241 493 : return isVisible(veh) ? veh->getEmissions<PollutantsInterface::CO2>() : INVALID_DOUBLE_VALUE;
242 : }
243 :
244 : double
245 93 : Vehicle::getCOEmission(const std::string& vehID) {
246 93 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
247 93 : return isVisible(veh) ? veh->getEmissions<PollutantsInterface::CO>() : INVALID_DOUBLE_VALUE;
248 : }
249 :
250 : double
251 93 : Vehicle::getHCEmission(const std::string& vehID) {
252 93 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
253 93 : return isVisible(veh) ? veh->getEmissions<PollutantsInterface::HC>() : INVALID_DOUBLE_VALUE;
254 : }
255 :
256 : double
257 93 : Vehicle::getPMxEmission(const std::string& vehID) {
258 93 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
259 93 : return isVisible(veh) ? veh->getEmissions<PollutantsInterface::PM_X>() : INVALID_DOUBLE_VALUE;
260 : }
261 :
262 : double
263 93 : Vehicle::getNOxEmission(const std::string& vehID) {
264 93 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
265 93 : return isVisible(veh) ? veh->getEmissions<PollutantsInterface::NO_X>() : INVALID_DOUBLE_VALUE;
266 : }
267 :
268 : double
269 93 : Vehicle::getFuelConsumption(const std::string& vehID) {
270 93 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
271 93 : return isVisible(veh) ? veh->getEmissions<PollutantsInterface::FUEL>() : INVALID_DOUBLE_VALUE;
272 : }
273 :
274 : double
275 93 : Vehicle::getNoiseEmission(const std::string& vehID) {
276 93 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
277 93 : return isVisible(veh) ? veh->getHarmonoise_NoiseEmissions() : INVALID_DOUBLE_VALUE;
278 : }
279 :
280 : double
281 191 : Vehicle::getElectricityConsumption(const std::string& vehID) {
282 191 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
283 191 : return isVisible(veh) ? veh->getEmissions<PollutantsInterface::ELEC>() : INVALID_DOUBLE_VALUE;
284 : }
285 :
286 : int
287 545 : Vehicle::getPersonNumber(const std::string& vehID) {
288 545 : return Helper::getVehicle(vehID)->getPersonNumber();
289 : }
290 :
291 : int
292 602 : Vehicle::getPersonCapacity(const std::string& vehID) {
293 602 : return Helper::getVehicleType(vehID).getPersonCapacity();
294 : }
295 :
296 :
297 : double
298 91 : Vehicle::getBoardingDuration(const std::string& vehID) {
299 91 : return STEPS2TIME(Helper::getVehicleType(vehID).getLoadingDuration(true));
300 : }
301 :
302 :
303 : std::vector<std::string>
304 224 : Vehicle::getPersonIDList(const std::string& vehID) {
305 224 : return Helper::getVehicle(vehID)->getPersonIDList();
306 : }
307 :
308 : std::pair<std::string, double>
309 51378 : Vehicle::getLeader(const std::string& vehID, double dist) {
310 51378 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
311 51378 : if (veh->isOnRoad()) {
312 51285 : std::pair<const MSVehicle* const, double> leaderInfo = veh->getLeader(dist);
313 51285 : const std::string leaderID = leaderInfo.first != nullptr ? leaderInfo.first->getID() : "";
314 51285 : double gap = leaderInfo.second;
315 : if (leaderInfo.first != nullptr
316 40747 : && leaderInfo.first->getLane() != nullptr
317 40747 : && leaderInfo.first->getLane()->isInternal()
318 202 : && veh->getLane() != nullptr
319 51487 : && (!veh->getLane()->isInternal()
320 7 : || (veh->getLane()->getLinkCont().front()->getIndex() != leaderInfo.first->getLane()->getLinkCont().front()->getIndex()))) {
321 : // leader is a linkLeader (see MSLink::getLeaderInfo)
322 : // avoid internal gap values which may be negative (or -inf)
323 : gap = MAX2(0.0, gap);
324 : }
325 : return std::make_pair(leaderID, gap);
326 : } else {
327 : return std::make_pair("", -1);
328 : }
329 : }
330 :
331 :
332 : std::pair<std::string, double>
333 294 : Vehicle::getFollower(const std::string& vehID, double dist) {
334 294 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
335 289 : if (veh->isOnRoad()) {
336 279 : std::pair<const MSVehicle* const, double> leaderInfo = veh->getFollower(dist);
337 : return std::make_pair(
338 558 : leaderInfo.first != nullptr ? leaderInfo.first->getID() : "",
339 : leaderInfo.second);
340 : } else {
341 : return std::make_pair("", -1);
342 : }
343 : }
344 :
345 :
346 : std::vector<TraCIJunctionFoe>
347 180 : Vehicle::getJunctionFoes(const std::string& vehID, double dist) {
348 : std::vector<TraCIJunctionFoe> result;
349 180 : MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
350 180 : MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
351 180 : if (veh == nullptr) {
352 60 : WRITE_WARNING("getJunctionFoes not applicable for meso");
353 150 : } else if (veh->isOnRoad()) {
354 150 : if (dist == 0) {
355 0 : dist = veh->getCarFollowModel().brakeGap(veh->getSpeed()) + veh->getVehicleType().getMinGap();
356 : }
357 : const std::vector<const MSLane*> internalLanes;
358 : // distance to the end of the lane
359 150 : double curDist = -veh->getPositionOnLane();
360 455 : for (const MSLane* lane : veh->getUpcomingLanesUntil(dist)) {
361 305 : curDist += lane->getLength();
362 305 : if (lane->isInternal()) {
363 145 : const MSLink* exitLink = lane->getLinkCont().front();
364 : int foeIndex = 0;
365 : const std::vector<MSLink::ConflictInfo>& conflicts = exitLink->getConflicts();
366 145 : const MSJunctionLogic* logic = exitLink->getJunction()->getLogic();
367 360 : for (const MSLane* foeLane : exitLink->getFoeLanes()) {
368 215 : const MSLink::ConflictInfo& ci = conflicts[foeIndex];
369 215 : if (ci.flag == MSLink::CONFLICT_NO_INTERSECTION) {
370 140 : continue;
371 : }
372 75 : const double distBehindCrossing = ci.lengthBehindCrossing;
373 75 : const MSLink* foeExitLink = foeLane->getLinkCont().front();
374 75 : const double distToCrossing = curDist - distBehindCrossing;
375 75 : const double foeDistBehindCrossing = ci.getFoeLengthBehindCrossing(foeExitLink);
376 300 : for (auto item : foeExitLink->getApproaching()) {
377 : const SUMOVehicle* foe = item.first;
378 : TraCIJunctionFoe jf;
379 : jf.foeId = foe->getID();
380 225 : jf.egoDist = distToCrossing;
381 : // approach information is from the start of the previous step
382 : // but the foe vehicle then moved within that steop
383 225 : const double prevFoeDist = SPEED2DIST(MSGlobals::gSemiImplicitEulerUpdate
384 : ? foe->getSpeed()
385 : : (foe->getSpeed() + foe->getPreviousSpeed()) / 2);
386 225 : jf.foeDist = item.second.dist - foeDistBehindCrossing - prevFoeDist;
387 225 : jf.egoExitDist = jf.egoDist + ci.conflictSize;
388 225 : jf.foeExitDist = jf.foeDist + ci.getFoeConflictSize(foeExitLink);
389 : jf.egoLane = lane->getID();
390 : jf.foeLane = foeLane->getID();
391 225 : jf.egoResponse = logic->getResponseFor(exitLink->getIndex()).test(foeExitLink->getIndex());
392 225 : jf.foeResponse = logic->getResponseFor(foeExitLink->getIndex()).test(exitLink->getIndex());
393 225 : result.push_back(jf);
394 225 : }
395 75 : foeIndex++;
396 : }
397 : }
398 : }
399 : }
400 180 : return result;
401 0 : }
402 :
403 :
404 : double
405 277 : Vehicle::getWaitingTime(const std::string& vehID) {
406 277 : return STEPS2TIME(Helper::getVehicle(vehID)->getWaitingTime());
407 : }
408 :
409 :
410 : double
411 133 : Vehicle::getAccumulatedWaitingTime(const std::string& vehID) {
412 133 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
413 133 : return CALL_MICRO_FUN(veh, getAccumulatedWaitingSeconds(), INVALID_DOUBLE_VALUE);
414 : }
415 :
416 :
417 : double
418 125 : Vehicle::getAdaptedTraveltime(const std::string& vehID, double time, const std::string& edgeID) {
419 125 : MSEdge* edge = Helper::getEdge(edgeID);
420 125 : double value = INVALID_DOUBLE_VALUE;
421 125 : Helper::getVehicle(vehID)->getWeightsStorage().retrieveExistingTravelTime(edge, time, value);
422 125 : return value;
423 : }
424 :
425 :
426 : double
427 119 : Vehicle::getEffort(const std::string& vehID, double time, const std::string& edgeID) {
428 119 : MSEdge* edge = Helper::getEdge(edgeID);
429 119 : double value = INVALID_DOUBLE_VALUE;
430 119 : Helper::getVehicle(vehID)->getWeightsStorage().retrieveExistingEffort(edge, time, value);
431 119 : return value;
432 : }
433 :
434 :
435 : bool
436 92 : Vehicle::isRouteValid(const std::string& vehID) {
437 : std::string msg;
438 184 : return Helper::getVehicle(vehID)->hasValidRoute(msg);
439 : }
440 :
441 :
442 : std::vector<std::string>
443 4980 : Vehicle::getRoute(const std::string& vehID) {
444 : std::vector<std::string> result;
445 4980 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
446 4980 : const MSRoute& r = veh->getRoute();
447 16535 : for (MSRouteIterator i = r.begin(); i != r.end(); ++i) {
448 11555 : result.push_back((*i)->getID());
449 : }
450 4980 : return result;
451 0 : }
452 :
453 :
454 : int
455 94 : Vehicle::getSignals(const std::string& vehID) {
456 94 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
457 94 : return CALL_MICRO_FUN(veh, getSignals(), MSVehicle::VEH_SIGNAL_NONE);
458 : }
459 :
460 :
461 : std::vector<TraCIBestLanesData>
462 101 : Vehicle::getBestLanes(const std::string& vehID) {
463 : std::vector<TraCIBestLanesData> result;
464 101 : MSVehicle* veh = dynamic_cast<MSVehicle*>(Helper::getVehicle(vehID));
465 101 : if (veh != nullptr && veh->isOnRoad()) {
466 136 : for (const MSVehicle::LaneQ& lq : veh->getBestLanes()) {
467 : TraCIBestLanesData bld;
468 86 : bld.laneID = lq.lane->getID();
469 86 : bld.length = lq.length;
470 86 : bld.occupation = lq.nextOccupation;
471 86 : bld.bestLaneOffset = lq.bestLaneOffset;
472 86 : bld.allowsContinuation = lq.allowsContinuation;
473 372 : for (const MSLane* const lane : lq.bestContinuations) {
474 286 : if (lane != nullptr) {
475 286 : bld.continuationLanes.push_back(lane->getID());
476 : }
477 : }
478 86 : result.emplace_back(bld);
479 86 : }
480 : }
481 101 : return result;
482 0 : }
483 :
484 :
485 : std::vector<TraCINextTLSData>
486 1415 : Vehicle::getNextTLS(const std::string& vehID) {
487 : std::vector<TraCINextTLSData> result;
488 1415 : MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
489 1411 : MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
490 1411 : if (!vehicle->isOnRoad()) {
491 : return result;
492 : }
493 1406 : if (veh != nullptr) {
494 1195 : const MSLane* lane = veh->getLane();
495 1195 : const std::vector<MSLane*>& bestLaneConts = veh->getBestLanesContinuation(lane);
496 1195 : double seen = lane->getLength() - veh->getPositionOnLane();
497 : int view = 1;
498 1195 : std::vector<MSLink*>::const_iterator linkIt = MSLane::succLinkSec(*veh, view, *lane, bestLaneConts);
499 3479 : while (!lane->isLinkEnd(linkIt)) {
500 2284 : if (!lane->getEdge().isInternal()) {
501 1115 : if ((*linkIt)->isTLSControlled()) {
502 : TraCINextTLSData ntd;
503 807 : ntd.id = (*linkIt)->getTLLogic()->getID();
504 807 : ntd.tlIndex = (*linkIt)->getTLIndex();
505 807 : ntd.dist = seen;
506 807 : ntd.state = (char)(*linkIt)->getState();
507 807 : result.push_back(ntd);
508 : }
509 : }
510 2284 : lane = (*linkIt)->getViaLaneOrLane();
511 2284 : if (!lane->getEdge().isInternal()) {
512 1169 : view++;
513 : }
514 2284 : seen += lane->getLength();
515 2284 : linkIt = MSLane::succLinkSec(*veh, view, *lane, bestLaneConts);
516 : }
517 : // consider edges beyond bestLanes
518 1195 : const int remainingEdges = (int)(veh->getRoute().end() - veh->getCurrentRouteEdge()) - view;
519 : //std::cout << SIMTIME << " remainingEdges=" << remainingEdges << " seen=" << seen << " view=" << view << " best=" << toString(bestLaneConts) << "\n";
520 2533 : for (int i = 0; i < remainingEdges; i++) {
521 1338 : const MSEdge* prev = *(veh->getCurrentRouteEdge() + view + i - 1);
522 1338 : const MSEdge* next = *(veh->getCurrentRouteEdge() + view + i);
523 1338 : const std::vector<MSLane*>* allowed = prev->allowedLanes(*next, veh->getVClass());
524 1338 : if (allowed != nullptr && allowed->size() != 0) {
525 1394 : for (const MSLink* const link : allowed->front()->getLinkCont()) {
526 1394 : if (&link->getLane()->getEdge() == next) {
527 1338 : if (link->isTLSControlled()) {
528 : TraCINextTLSData ntd;
529 : ntd.id = link->getTLLogic()->getID();
530 830 : ntd.tlIndex = link->getTLIndex();
531 830 : ntd.dist = seen;
532 830 : ntd.state = (char)link->getState();
533 830 : result.push_back(ntd);
534 : }
535 1338 : seen += next->getLength() + link->getInternalLengthsAfter();
536 1338 : break;
537 : }
538 : }
539 : } else {
540 : // invalid route, cannot determine nextTLS
541 : break;
542 : }
543 : }
544 :
545 : } else {
546 422 : WRITE_WARNING("getNextTLS not yet implemented for meso");
547 : }
548 : return result;
549 4 : }
550 :
551 : std::vector<TraCINextStopData>
552 52 : Vehicle::getNextStops(const std::string& vehID) {
553 52 : return getStops(vehID, 0);
554 : }
555 :
556 : std::vector<libsumo::TraCIConnection>
557 0 : Vehicle::getNextLinks(const std::string& vehID) {
558 : std::vector<libsumo::TraCIConnection> result;
559 0 : MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
560 0 : MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
561 0 : if (!vehicle->isOnRoad()) {
562 : return result;
563 : }
564 0 : if (veh != nullptr) {
565 0 : const MSLane* lane = veh->getLane();
566 0 : const std::vector<MSLane*>& bestLaneConts = veh->getBestLanesContinuation(lane);
567 : int view = 1;
568 0 : const SUMOTime currTime = MSNet::getInstance()->getCurrentTimeStep();
569 0 : std::vector<MSLink*>::const_iterator linkIt = MSLane::succLinkSec(*veh, view, *lane, bestLaneConts);
570 0 : while (!lane->isLinkEnd(linkIt)) {
571 0 : if (!lane->getEdge().isInternal()) {
572 0 : const MSLink* link = (*linkIt);
573 0 : const std::string approachedLane = link->getLane() != nullptr ? link->getLane()->getID() : "";
574 : const bool hasPrio = link->havePriority();
575 : const double speed = MIN2(lane->getSpeedLimit(), link->getLane()->getSpeedLimit());
576 0 : const bool isOpen = link->opened(currTime, speed, speed, SUMOVTypeParameter::getDefault().length,
577 0 : SUMOVTypeParameter::getDefault().impatience, SUMOVTypeParameter::getDefaultDecel(), 0);
578 0 : const bool hasFoe = link->hasApproachingFoe(currTime, currTime, 0, SUMOVTypeParameter::getDefaultDecel());
579 0 : const std::string approachedInternal = link->getViaLane() != nullptr ? link->getViaLane()->getID() : "";
580 0 : const std::string state = SUMOXMLDefinitions::LinkStates.getString(link->getState());
581 0 : const std::string direction = SUMOXMLDefinitions::LinkDirections.getString(link->getDirection());
582 : const double length = link->getLength();
583 0 : result.push_back(TraCIConnection(approachedLane, hasPrio, isOpen, hasFoe, approachedInternal, state, direction, length));
584 : }
585 0 : lane = (*linkIt)->getViaLaneOrLane();
586 0 : if (!lane->getEdge().isInternal()) {
587 0 : view++;
588 : }
589 0 : linkIt = MSLane::succLinkSec(*veh, view, *lane, bestLaneConts);
590 : }
591 : // consider edges beyond bestLanes
592 0 : const int remainingEdges = (int)(veh->getRoute().end() - veh->getCurrentRouteEdge()) - view;
593 0 : for (int i = 0; i < remainingEdges; i++) {
594 0 : const MSEdge* prev = *(veh->getCurrentRouteEdge() + view + i - 1);
595 0 : const MSEdge* next = *(veh->getCurrentRouteEdge() + view + i);
596 0 : const std::vector<MSLane*>* allowed = prev->allowedLanes(*next, veh->getVClass());
597 0 : if (allowed != nullptr && allowed->size() != 0) {
598 0 : for (const MSLink* const link : allowed->front()->getLinkCont()) {
599 0 : if (&link->getLane()->getEdge() == next) {
600 : const std::string approachedLane = link->getLane() != nullptr ? link->getLane()->getID() : "";
601 : const bool hasPrio = link->havePriority();
602 : const double speed = MIN2(lane->getSpeedLimit(), link->getLane()->getSpeedLimit());
603 0 : const bool isOpen = link->opened(currTime, speed, speed, SUMOVTypeParameter::getDefault().length,
604 0 : SUMOVTypeParameter::getDefault().impatience, SUMOVTypeParameter::getDefaultDecel(), 0);
605 0 : const bool hasFoe = link->hasApproachingFoe(currTime, currTime, 0, SUMOVTypeParameter::getDefaultDecel());
606 0 : const std::string approachedInternal = link->getViaLane() != nullptr ? link->getViaLane()->getID() : "";
607 0 : const std::string state = SUMOXMLDefinitions::LinkStates.getString(link->getState());
608 0 : const std::string direction = SUMOXMLDefinitions::LinkDirections.getString(link->getDirection());
609 : const double length = link->getLength();
610 0 : result.push_back(TraCIConnection(approachedLane, hasPrio, isOpen, hasFoe, approachedInternal, state, direction, length));
611 : }
612 : }
613 : } else {
614 : // invalid route, cannot determine nextTLS
615 : break;
616 : }
617 : }
618 : } else {
619 0 : WRITE_WARNING("getNextLinks not yet implemented for meso");
620 : }
621 : return result;
622 0 : }
623 :
624 : std::vector<TraCINextStopData>
625 4153 : Vehicle::getStops(const std::string& vehID, int limit) {
626 : std::vector<TraCINextStopData> result;
627 4153 : MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
628 4151 : if (limit < 0) {
629 : // return past stops up to the given limit
630 : const std::vector<SUMOVehicleParameter::Stop>& pastStops = vehicle->getPastStops();
631 499 : const int n = (int)pastStops.size();
632 1478 : for (int i = MAX2(0, n + limit); i < n; i++) {
633 1958 : result.push_back(Helper::buildStopData(pastStops[i]));
634 : }
635 : } else {
636 12887 : for (const MSStop& stop : vehicle->getStops()) {
637 9823 : if (!stop.pars.collision) {
638 9823 : TraCINextStopData nsd = Helper::buildStopData(stop.pars);
639 9823 : nsd.duration = STEPS2TIME(stop.duration);
640 9823 : result.push_back(nsd);
641 9823 : if (limit > 0 && (int)result.size() >= limit) {
642 : break;
643 : }
644 9823 : }
645 : }
646 : }
647 4151 : return result;
648 2 : }
649 :
650 :
651 : int
652 1623 : Vehicle::getStopState(const std::string& vehID) {
653 1623 : MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
654 1623 : MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
655 1623 : if (veh == nullptr) {
656 215 : WRITE_WARNING("getStopState not yet implemented for meso");
657 215 : return 0;
658 : }
659 : int result = 0;
660 1408 : if (veh->isStopped()) {
661 193 : const MSStop& stop = veh->getNextStop();
662 193 : result = stop.getStateFlagsOld();
663 : }
664 : return result;
665 : }
666 :
667 :
668 : double
669 734 : Vehicle::getDistance(const std::string& vehID) {
670 734 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
671 728 : if (veh->isOnRoad()) {
672 678 : return veh->getOdometer();
673 : } else {
674 : return INVALID_DOUBLE_VALUE;
675 : }
676 : }
677 :
678 :
679 : double
680 3743 : Vehicle::getDrivingDistance(const std::string& vehID, const std::string& edgeID, double pos, int /* laneIndex */) {
681 3743 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
682 3743 : MSVehicle* microVeh = dynamic_cast<MSVehicle*>(veh);
683 3743 : if (veh->isOnRoad()) {
684 3693 : const MSEdge* edge = microVeh != nullptr ? &veh->getLane()->getEdge() : veh->getEdge();
685 7386 : double distance = veh->getRoute().getDistanceBetween(veh->getPositionOnLane(), pos,
686 3693 : edge, Helper::getEdge(edgeID), veh->getRoutePosition());
687 3693 : if (distance == std::numeric_limits<double>::max()) {
688 : return INVALID_DOUBLE_VALUE;
689 : }
690 2605 : return distance;
691 : } else {
692 : return INVALID_DOUBLE_VALUE;
693 : }
694 : }
695 :
696 :
697 : double
698 94 : Vehicle::getDrivingDistance2D(const std::string& vehID, double x, double y) {
699 94 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
700 94 : if (veh == nullptr) {
701 : return INVALID_DOUBLE_VALUE;
702 : }
703 94 : if (veh->isOnRoad()) {
704 44 : std::pair<MSLane*, double> roadPos = Helper::convertCartesianToRoadMap(Position(x, y), veh->getVehicleType().getVehicleClass());
705 88 : double distance = veh->getRoute().getDistanceBetween(veh->getPositionOnLane(), roadPos.second,
706 44 : veh->getEdge(), &roadPos.first->getEdge(), veh->getRoutePosition());
707 44 : if (distance == std::numeric_limits<double>::max()) {
708 : return INVALID_DOUBLE_VALUE;
709 : }
710 32 : return distance;
711 : } else {
712 : return INVALID_DOUBLE_VALUE;
713 : }
714 : }
715 :
716 :
717 : double
718 91 : Vehicle::getAllowedSpeed(const std::string& vehID) {
719 91 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
720 91 : return veh->isOnRoad() ? CALL_MICRO_FUN(veh, getLane()->getVehicleMaxSpeed(veh), veh->getEdge()->getVehicleMaxSpeed(veh)) : INVALID_DOUBLE_VALUE;
721 : }
722 :
723 :
724 : double
725 235 : Vehicle::getSpeedFactor(const std::string& vehID) {
726 235 : return Helper::getVehicle(vehID)->getChosenSpeedFactor();
727 : }
728 :
729 :
730 : int
731 76 : Vehicle::getSpeedMode(const std::string& vehID) {
732 76 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
733 76 : return CALL_MICRO_FUN(veh, getInfluencer().getSpeedMode(), INVALID_INT_VALUE);
734 : }
735 :
736 :
737 : int
738 259 : Vehicle::getLaneChangeMode(const std::string& vehID) {
739 259 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
740 259 : return CALL_MICRO_FUN(veh, getInfluencer().getLaneChangeMode(), INVALID_INT_VALUE);
741 : }
742 :
743 :
744 : int
745 237 : Vehicle::getRoutingMode(const std::string& vehID) {
746 237 : return Helper::getVehicle(vehID)->getRoutingMode();
747 : }
748 :
749 :
750 : std::string
751 92 : Vehicle::getLine(const std::string& vehID) {
752 92 : return Helper::getVehicle(vehID)->getParameter().line;
753 : }
754 :
755 :
756 : std::vector<std::string>
757 92 : Vehicle::getVia(const std::string& vehID) {
758 92 : return Helper::getVehicle(vehID)->getParameter().via;
759 : }
760 :
761 :
762 : std::pair<int, int>
763 19808 : Vehicle::getLaneChangeState(const std::string& vehID, int direction) {
764 19808 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
765 19808 : auto undefined = std::make_pair((int)LCA_UNKNOWN, (int)LCA_UNKNOWN);
766 19808 : return veh->isOnRoad() ? CALL_MICRO_FUN(veh, getLaneChangeModel().getSavedState(direction), undefined) : undefined;
767 : }
768 :
769 :
770 : std::string
771 93551 : Vehicle::getParameter(const std::string& vehID, const std::string& key) {
772 93551 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
773 : std::string error;
774 93551 : std::string result = veh->getPrefixedParameter(key, error);
775 93551 : if (error != "") {
776 146 : throw TraCIException(error);
777 : }
778 93478 : return result;
779 : }
780 :
781 :
782 62 : LIBSUMO_GET_PARAMETER_WITH_KEY_IMPLEMENTATION(Vehicle)
783 :
784 :
785 : std::vector<std::pair<std::string, double> >
786 5136 : Vehicle::getNeighbors(const std::string& vehID, const int mode) {
787 5136 : int dir = (1 & mode) != 0 ? -1 : 1;
788 5136 : bool queryLeaders = (2 & mode) != 0;
789 5136 : bool blockersOnly = (4 & mode) != 0;
790 5136 : MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
791 5136 : MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
792 : std::vector<std::pair<std::string, double> > result;
793 5136 : if (veh == nullptr) {
794 : return result;
795 : }
796 : #ifdef DEBUG_NEIGHBORS
797 : if (DEBUG_COND) {
798 : std::cout << "getNeighbors() for veh '" << vehID << "': dir=" << dir
799 : << ", queryLeaders=" << queryLeaders
800 : << ", blockersOnly=" << blockersOnly << std::endl;
801 : }
802 : #endif
803 5136 : if (veh->getLaneChangeModel().isOpposite()) {
804 : // getParallelLane works relative to lane forward direction
805 144 : dir *= -1;
806 : }
807 :
808 5136 : MSLane* targetLane = veh->getLane()->getParallelLane(dir);
809 5136 : if (targetLane == nullptr) {
810 : return result;
811 : }
812 : // need to recompute leaders and followers (#8119)
813 4440 : const bool opposite = &veh->getLane()->getEdge() != &targetLane->getEdge();
814 4440 : MSLeaderDistanceInfo neighbors(targetLane->getWidth(), nullptr, 0.);
815 4440 : if (queryLeaders) {
816 2220 : if (opposite) {
817 348 : double pos = targetLane->getOppositePos(veh->getPositionOnLane());
818 348 : neighbors = targetLane->getFollowersOnConsecutive(veh, pos, true);
819 : } else {
820 1872 : targetLane->addLeaders(veh, veh->getPositionOnLane(), neighbors);
821 : }
822 : } else {
823 2220 : if (opposite) {
824 348 : double pos = targetLane->getOppositePos(veh->getPositionOnLane());
825 348 : targetLane->addLeaders(veh, pos, neighbors);
826 348 : neighbors.fixOppositeGaps(true);
827 : } else {
828 1872 : neighbors = targetLane->getFollowersOnConsecutive(veh, veh->getBackPositionOnLane(), true);
829 : }
830 : }
831 4440 : if (blockersOnly) {
832 : // filter out vehicles that aren't blocking
833 2220 : MSLeaderDistanceInfo blockers(targetLane->getWidth(), nullptr, 0.);
834 7248 : for (int i = 0; i < neighbors.numSublanes(); i++) {
835 5028 : CLeaderDist n = neighbors[i];
836 5028 : if (n.first != nullptr) {
837 : const MSVehicle* follower = veh;
838 : const MSVehicle* leader = n.first;
839 3198 : if (!queryLeaders) {
840 : std::swap(follower, leader);
841 : }
842 6396 : const double secureGap = (follower->getCarFollowModel().getSecureGap(
843 3198 : follower, leader, follower->getSpeed(), leader->getSpeed(), leader->getCarFollowModel().getMaxDecel())
844 3198 : * follower->getLaneChangeModel().getSafetyFactor());
845 3198 : if (n.second < secureGap) {
846 1404 : blockers.addLeader(n.first, n.second, 0, i);
847 : }
848 : }
849 : }
850 2220 : neighbors = blockers;
851 2220 : }
852 :
853 4440 : if (neighbors.hasVehicles()) {
854 7890 : for (int i = 0; i < neighbors.numSublanes(); i++) {
855 5664 : CLeaderDist n = neighbors[i];
856 5664 : if (n.first != nullptr &&
857 : // avoid duplicates
858 2394 : (result.size() == 0 || result.back().first != n.first->getID())) {
859 2832 : result.push_back(std::make_pair(n.first->getID(), n.second));
860 : }
861 : }
862 : }
863 : return result;
864 4440 : }
865 :
866 :
867 : double
868 711 : Vehicle::getFollowSpeed(const std::string& vehID, double speed, double gap, double leaderSpeed, double leaderMaxDecel, const std::string& leaderID) {
869 711 : MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
870 711 : MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
871 711 : if (veh == nullptr) {
872 0 : WRITE_ERROR("getFollowSpeed not applicable for meso");
873 0 : return INVALID_DOUBLE_VALUE;
874 : }
875 711 : MSVehicle* leader = dynamic_cast<MSVehicle*>(MSNet::getInstance()->getVehicleControl().getVehicle(leaderID));
876 711 : return veh->getCarFollowModel().followSpeed(veh, speed, gap, leaderSpeed, leaderMaxDecel, leader, MSCFModel::CalcReason::FUTURE);
877 : }
878 :
879 :
880 : double
881 11 : Vehicle::getSecureGap(const std::string& vehID, double speed, double leaderSpeed, double leaderMaxDecel, const std::string& leaderID) {
882 11 : MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
883 11 : MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
884 11 : if (veh == nullptr) {
885 0 : WRITE_ERROR("getSecureGap not applicable for meso");
886 0 : return INVALID_DOUBLE_VALUE;
887 : }
888 11 : MSVehicle* leader = dynamic_cast<MSVehicle*>(MSNet::getInstance()->getVehicleControl().getVehicle(leaderID));
889 11 : return veh->getCarFollowModel().getSecureGap(veh, leader, speed, leaderSpeed, leaderMaxDecel);
890 : }
891 :
892 :
893 : double
894 11 : Vehicle::getStopSpeed(const std::string& vehID, const double speed, double gap) {
895 11 : MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
896 11 : MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
897 11 : if (veh == nullptr) {
898 0 : WRITE_ERROR("getStopSpeed not applicable for meso");
899 0 : return INVALID_DOUBLE_VALUE;
900 : }
901 11 : return veh->getCarFollowModel().stopSpeed(veh, speed, gap, MSCFModel::CalcReason::FUTURE);
902 : }
903 :
904 : double
905 2252 : Vehicle::getStopDelay(const std::string& vehID) {
906 2252 : return Helper::getVehicle(vehID)->getStopDelay();
907 : }
908 :
909 :
910 : double
911 121 : Vehicle::getImpatience(const std::string& vehID) {
912 121 : return Helper::getVehicle(vehID)->getImpatience();
913 : }
914 :
915 :
916 : double
917 2251 : Vehicle::getStopArrivalDelay(const std::string& vehID) {
918 2251 : double result = Helper::getVehicle(vehID)->getStopArrivalDelay();
919 2251 : if (result == INVALID_DOUBLE) {
920 : return INVALID_DOUBLE_VALUE;
921 : } else {
922 1715 : return result;
923 : }
924 : }
925 :
926 : double
927 91 : Vehicle::getTimeLoss(const std::string& vehID) {
928 91 : return Helper::getVehicle(vehID)->getTimeLossSeconds();
929 : }
930 :
931 : std::vector<std::string>
932 10195 : Vehicle::getTaxiFleet(int taxiState) {
933 : std::vector<std::string> result;
934 26051 : for (MSDevice_Taxi* taxi : MSDevice_Taxi::getFleet()) {
935 15856 : if (taxi->getHolder().hasDeparted()) {
936 : if (taxiState == -1
937 10147 : || (taxiState == 0 && taxi->getState() == 0)
938 25208 : || (taxiState != 0 && (taxi->getState() & taxiState) == taxiState)) {
939 8155 : result.push_back(taxi->getHolder().getID());
940 : }
941 : }
942 : }
943 10195 : return result;
944 0 : }
945 :
946 : std::vector<std::string>
947 204 : Vehicle::getLoadedIDList() {
948 : std::vector<std::string> ids;
949 204 : MSVehicleControl& c = MSNet::getInstance()->getVehicleControl();
950 673 : for (MSVehicleControl::constVehIt i = c.loadedVehBegin(); i != c.loadedVehEnd(); ++i) {
951 469 : ids.push_back(i->first);
952 : }
953 204 : return ids;
954 0 : }
955 :
956 : std::vector<std::string>
957 204 : Vehicle::getTeleportingIDList() {
958 : std::vector<std::string> ids;
959 204 : MSVehicleControl& c = MSNet::getInstance()->getVehicleControl();
960 673 : for (MSVehicleControl::constVehIt i = c.loadedVehBegin(); i != c.loadedVehEnd(); ++i) {
961 469 : SUMOVehicle* veh = i->second;
962 469 : if (veh->hasDeparted() && !isVisible(veh)) {
963 100 : ids.push_back(veh->getID());
964 : }
965 : }
966 204 : return ids;
967 0 : }
968 :
969 : std::string
970 76 : Vehicle::getEmissionClass(const std::string& vehID) {
971 76 : return PollutantsInterface::getName(Helper::getVehicleType(vehID).getEmissionClass());
972 : }
973 :
974 : std::string
975 36 : Vehicle::getShapeClass(const std::string& vehID) {
976 36 : return getVehicleShapeName(Helper::getVehicleType(vehID).getGuiShape());
977 : }
978 :
979 :
980 : double
981 38 : Vehicle::getLength(const std::string& vehID) {
982 38 : return Helper::getVehicleType(vehID).getLength();
983 : }
984 :
985 :
986 : double
987 38 : Vehicle::getAccel(const std::string& vehID) {
988 38 : return Helper::getVehicleType(vehID).getCarFollowModel().getMaxAccel();
989 : }
990 :
991 :
992 : double
993 225 : Vehicle::getDecel(const std::string& vehID) {
994 225 : return Helper::getVehicleType(vehID).getCarFollowModel().getMaxDecel();
995 : }
996 :
997 :
998 42 : double Vehicle::getEmergencyDecel(const std::string& vehID) {
999 42 : return Helper::getVehicleType(vehID).getCarFollowModel().getEmergencyDecel();
1000 : }
1001 :
1002 :
1003 38 : double Vehicle::getApparentDecel(const std::string& vehID) {
1004 38 : return Helper::getVehicleType(vehID).getCarFollowModel().getApparentDecel();
1005 : }
1006 :
1007 :
1008 38 : double Vehicle::getActionStepLength(const std::string& vehID) {
1009 38 : return Helper::getVehicleType(vehID).getActionStepLengthSecs();
1010 : }
1011 :
1012 :
1013 91 : double Vehicle::getLastActionTime(const std::string& vehID) {
1014 91 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
1015 91 : MSVehicle* microVeh = dynamic_cast<MSVehicle*>(veh);
1016 91 : if (microVeh != nullptr) {
1017 90 : return STEPS2TIME(microVeh->getLastActionTime());
1018 : } else {
1019 1 : MEVehicle* mesoVeh = dynamic_cast<MEVehicle*>(veh);
1020 1 : return STEPS2TIME(mesoVeh->getEventTime());
1021 : }
1022 : }
1023 :
1024 :
1025 : double
1026 38 : Vehicle::getTau(const std::string& vehID) {
1027 38 : return Helper::getVehicleType(vehID).getCarFollowModel().getHeadwayTime();
1028 : }
1029 :
1030 :
1031 : double
1032 40 : Vehicle::getImperfection(const std::string& vehID) {
1033 40 : return Helper::getVehicleType(vehID).getCarFollowModel().getImperfection();
1034 : }
1035 :
1036 :
1037 : double
1038 36 : Vehicle::getSpeedDeviation(const std::string& vehID) {
1039 36 : return Helper::getVehicleType(vehID).getSpeedFactor().getParameter()[1];
1040 : }
1041 :
1042 :
1043 : std::string
1044 36 : Vehicle::getVehicleClass(const std::string& vehID) {
1045 36 : return toString(Helper::getVehicleType(vehID).getVehicleClass());
1046 : }
1047 :
1048 :
1049 : double
1050 92 : Vehicle::getMinGap(const std::string& vehID) {
1051 92 : return Helper::getVehicleType(vehID).getMinGap();
1052 : }
1053 :
1054 :
1055 : double
1056 91 : Vehicle::getMinGapLat(const std::string& vehID) {
1057 : try {
1058 181 : return StringUtils::toDouble(getParameter(vehID, "laneChangeModel.minGapLat"));
1059 46 : } catch (const TraCIException&) {
1060 : // legacy behavior
1061 46 : return Helper::getVehicleType(vehID).getMinGapLat();
1062 46 : }
1063 : }
1064 :
1065 :
1066 : double
1067 38 : Vehicle::getMaxSpeed(const std::string& vehID) {
1068 38 : return Helper::getVehicleType(vehID).getMaxSpeed();
1069 : }
1070 :
1071 :
1072 : double
1073 36 : Vehicle::getMaxSpeedLat(const std::string& vehID) {
1074 36 : return Helper::getVehicleType(vehID).getMaxSpeedLat();
1075 : }
1076 :
1077 :
1078 : std::string
1079 36 : Vehicle::getLateralAlignment(const std::string& vehID) {
1080 36 : return toString(Helper::getVehicleType(vehID).getPreferredLateralAlignment());
1081 : }
1082 :
1083 :
1084 : double
1085 38 : Vehicle::getWidth(const std::string& vehID) {
1086 38 : return Helper::getVehicleType(vehID).getWidth();
1087 : }
1088 :
1089 :
1090 : double
1091 36 : Vehicle::getHeight(const std::string& vehID) {
1092 36 : return Helper::getVehicleType(vehID).getHeight();
1093 : }
1094 :
1095 :
1096 : void
1097 88713 : Vehicle::setStop(const std::string& vehID,
1098 : const std::string& edgeID,
1099 : double pos,
1100 : int laneIndex,
1101 : double duration,
1102 : int flags,
1103 : double startPos,
1104 : double until) {
1105 88713 : MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
1106 : SUMOVehicleParameter::Stop stopPars = Helper::buildStopParameters(edgeID,
1107 88711 : pos, laneIndex, startPos, flags, duration, until);
1108 : std::string error;
1109 88725 : if (!vehicle->addTraciStop(stopPars, error)) {
1110 28 : throw TraCIException(error);
1111 : }
1112 88711 : }
1113 :
1114 :
1115 : void
1116 260 : Vehicle::replaceStop(const std::string& vehID,
1117 : int nextStopIndex,
1118 : const std::string& edgeID,
1119 : double pos,
1120 : int laneIndex,
1121 : double duration,
1122 : int flags,
1123 : double startPos,
1124 : double until,
1125 : int teleport) {
1126 260 : MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
1127 : std::string error;
1128 260 : if (edgeID == "") {
1129 : // only remove stop
1130 108 : const bool ok = vehicle->abortNextStop(nextStopIndex);
1131 108 : if (teleport != 0) {
1132 145 : if (!vehicle->rerouteBetweenStops(nextStopIndex, "traci:replaceStop", (teleport & 1), error)) {
1133 0 : throw TraCIException("Stop replacement failed for vehicle '" + vehID + "' (" + error + ").");
1134 : }
1135 : } else {
1136 45 : MSVehicle* msVeh = dynamic_cast<MSVehicle*>(vehicle);
1137 45 : if (msVeh->getLane() != nullptr) {
1138 35 : msVeh->updateBestLanes(true);
1139 : }
1140 : }
1141 108 : if (!ok) {
1142 0 : throw TraCIException("Stop replacement failed for vehicle '" + vehID + "' (invalid nextStopIndex).");
1143 : }
1144 : } else {
1145 : SUMOVehicleParameter::Stop stopPars = Helper::buildStopParameters(edgeID,
1146 152 : pos, laneIndex, startPos, flags, duration, until);
1147 :
1148 304 : if (!vehicle->replaceStop(nextStopIndex, stopPars, "traci:replaceStop", teleport != 0, error)) {
1149 38 : throw TraCIException("Stop replacement failed for vehicle '" + vehID + "' (" + error + ").");
1150 : }
1151 152 : }
1152 241 : }
1153 :
1154 :
1155 : void
1156 153 : Vehicle::insertStop(const std::string& vehID,
1157 : int nextStopIndex,
1158 : const std::string& edgeID,
1159 : double pos,
1160 : int laneIndex,
1161 : double duration,
1162 : int flags,
1163 : double startPos,
1164 : double until,
1165 : int teleport) {
1166 153 : MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
1167 : SUMOVehicleParameter::Stop stopPars = Helper::buildStopParameters(edgeID,
1168 153 : pos, laneIndex, startPos, flags, duration, until);
1169 :
1170 : std::string error;
1171 316 : if (!vehicle->insertStop(nextStopIndex, stopPars, "traci:insertStop", teleport != 0, error)) {
1172 40 : throw TraCIException("Stop insertion failed for vehicle '" + vehID + "' (" + error + ").");
1173 : }
1174 148 : }
1175 :
1176 :
1177 : std::string
1178 524 : Vehicle::getStopParameter(const std::string& vehID, int nextStopIndex, const std::string& param, bool customParam) {
1179 524 : MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
1180 : try {
1181 524 : if (nextStopIndex >= (int)vehicle->getStops().size() || (nextStopIndex < 0 && -nextStopIndex > (int)vehicle->getPastStops().size())) {
1182 0 : throw ProcessError("Invalid stop index " + toString(nextStopIndex)
1183 0 : + " (has " + toString(vehicle->getPastStops().size()) + " past stops and " + toString(vehicle->getStops().size()) + " remaining stops)");
1184 :
1185 : }
1186 : const SUMOVehicleParameter::Stop& pars = (nextStopIndex >= 0
1187 524 : ? vehicle->getStop(nextStopIndex).pars
1188 242 : : vehicle->getPastStops()[vehicle->getPastStops().size() + nextStopIndex]);
1189 524 : if (customParam) {
1190 : // custom user parameter
1191 24 : return pars.getParameter(param, "");
1192 : }
1193 :
1194 512 : if (param == toString(SUMO_ATTR_EDGE)) {
1195 : return pars.edge;
1196 489 : } else if (param == toString(SUMO_ATTR_LANE)) {
1197 58 : return toString(SUMOXMLDefinitions::getIndexFromLane(pars.lane));
1198 920 : } else if (param == toString(SUMO_ATTR_BUS_STOP)
1199 920 : || param == toString(SUMO_ATTR_TRAIN_STOP)) {
1200 : return pars.busstop;
1201 460 : } else if (param == toString(SUMO_ATTR_CONTAINER_STOP)) {
1202 : return pars.containerstop;
1203 460 : } else if (param == toString(SUMO_ATTR_CHARGING_STATION)) {
1204 : return pars.chargingStation;
1205 460 : } else if (param == toString(SUMO_ATTR_PARKING_AREA)) {
1206 : return pars.parkingarea;
1207 460 : } else if (param == toString(SUMO_ATTR_STARTPOS)) {
1208 23 : return toString(pars.startPos);
1209 437 : } else if (param == toString(SUMO_ATTR_ENDPOS)) {
1210 23 : return toString(pars.endPos);
1211 414 : } else if (param == toString(SUMO_ATTR_POSITION_LAT)) {
1212 23 : return toString(pars.posLat == INVALID_DOUBLE ? INVALID_DOUBLE_VALUE : pars.posLat);
1213 391 : } else if (param == toString(SUMO_ATTR_ARRIVAL)) {
1214 23 : return pars.arrival < 0 ? "-1" : time2string(pars.arrival);
1215 368 : } else if (param == toString(SUMO_ATTR_DURATION)) {
1216 23 : return pars.duration < 0 ? "-1" : time2string(pars.duration);
1217 345 : } else if (param == toString(SUMO_ATTR_UNTIL)) {
1218 23 : return pars.until < 0 ? "-1" : time2string(pars.until);
1219 322 : } else if (param == toString(SUMO_ATTR_EXTENSION)) {
1220 23 : return pars.extension < 0 ? "-1" : time2string(pars.extension);
1221 299 : } else if (param == toString(SUMO_ATTR_INDEX)) {
1222 23 : return toString(nextStopIndex + vehicle->getPastStops().size());
1223 276 : } else if (param == toString(SUMO_ATTR_PARKING)) {
1224 23 : return toString(pars.parking);
1225 253 : } else if (param == toString(SUMO_ATTR_TRIGGERED)) {
1226 23 : return joinToString(pars.getTriggers(), " ");
1227 230 : } else if (param == toString(SUMO_ATTR_EXPECTED)) {
1228 23 : return joinToString(pars.awaitedPersons, " ");
1229 414 : } else if (param == toString(SUMO_ATTR_EXPECTED_CONTAINERS)) {
1230 0 : return joinToString(pars.awaitedContainers, " ");
1231 207 : } else if (param == toString(SUMO_ATTR_PERMITTED)) {
1232 23 : return joinToString(pars.permitted, " ");
1233 184 : } else if (param == toString(SUMO_ATTR_ACTTYPE)) {
1234 : return pars.actType;
1235 161 : } else if (param == toString(SUMO_ATTR_TRIP_ID)) {
1236 : return pars.tripId;
1237 138 : } else if (param == toString(SUMO_ATTR_SPLIT)) {
1238 : return pars.split;
1239 115 : } else if (param == toString(SUMO_ATTR_JOIN)) {
1240 : return pars.join;
1241 92 : } else if (param == toString(SUMO_ATTR_LINE)) {
1242 : return pars.line;
1243 69 : } else if (param == toString(SUMO_ATTR_SPEED)) {
1244 23 : return toString(pars.speed);
1245 46 : } else if (param == toString(SUMO_ATTR_STARTED)) {
1246 23 : return pars.started < 0 ? "-1" : time2string(pars.started);
1247 23 : } else if (param == toString(SUMO_ATTR_ENDED)) {
1248 23 : return pars.ended < 0 ? "-1" : time2string(pars.ended);
1249 0 : } else if (param == toString(SUMO_ATTR_ONDEMAND)) {
1250 0 : return toString(pars.onDemand);
1251 : } else {
1252 0 : throw ProcessError(TLF("Unsupported parameter '%'", param));
1253 : }
1254 0 : } catch (ProcessError& e) {
1255 0 : throw TraCIException("Could not get stop parameter for vehicle '" + vehID + "' (" + e.what() + ")");
1256 0 : }
1257 : }
1258 :
1259 :
1260 :
1261 : void
1262 196 : Vehicle::setStopParameter(const std::string& vehID, int nextStopIndex,
1263 : const std::string& param, const std::string& value,
1264 : bool customParam) {
1265 196 : MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
1266 : try {
1267 196 : MSStop& stop = vehicle->getStop(nextStopIndex);
1268 196 : SUMOVehicleParameter::Stop& pars = const_cast<SUMOVehicleParameter::Stop&>(stop.pars);
1269 196 : if (customParam) {
1270 12 : pars.setParameter(param, value);
1271 12 : return;
1272 : }
1273 : std::string error;
1274 368 : if (param == toString(SUMO_ATTR_EDGE)
1275 362 : || param == toString(SUMO_ATTR_BUS_STOP)
1276 357 : || param == toString(SUMO_ATTR_TRAIN_STOP)
1277 357 : || param == toString(SUMO_ATTR_CONTAINER_STOP)
1278 357 : || param == toString(SUMO_ATTR_CHARGING_STATION)
1279 357 : || param == toString(SUMO_ATTR_PARKING_AREA)
1280 541 : || param == toString(SUMO_ATTR_LANE)
1281 : ) {
1282 17 : int laneIndex = stop.lane->getIndex();
1283 17 : int flags = pars.getFlags() & 3;
1284 : std::string edgeOrStopID = value;
1285 17 : if (param == toString(SUMO_ATTR_LANE)) {
1286 6 : laneIndex = StringUtils::toInt(value);
1287 6 : edgeOrStopID = pars.edge;
1288 22 : } else if (param == toString(SUMO_ATTR_BUS_STOP)
1289 17 : || param == toString(SUMO_ATTR_TRAIN_STOP)) {
1290 5 : flags |= 8;
1291 6 : } else if (param == toString(SUMO_ATTR_CONTAINER_STOP)) {
1292 0 : flags |= 16;
1293 6 : } else if (param == toString(SUMO_ATTR_CHARGING_STATION)) {
1294 0 : flags |= 32;
1295 6 : } else if (param == toString(SUMO_ATTR_PARKING_AREA)) {
1296 0 : flags |= 64;
1297 : }
1298 : // special case: replace stop
1299 17 : replaceStop(vehID, nextStopIndex, edgeOrStopID, pars.endPos, laneIndex, STEPS2TIME(pars.duration),
1300 17 : flags, pars.startPos, STEPS2TIME(pars.until), 0);
1301 :
1302 167 : } else if (param == toString(SUMO_ATTR_STARTPOS)) {
1303 6 : pars.startPos = StringUtils::toDouble(value);
1304 6 : pars.parametersSet |= STOP_START_SET;
1305 161 : } else if (param == toString(SUMO_ATTR_ENDPOS)) {
1306 6 : pars.endPos = StringUtils::toDouble(value);
1307 6 : pars.parametersSet |= STOP_END_SET;
1308 155 : } else if (param == toString(SUMO_ATTR_POSITION_LAT)) {
1309 6 : pars.posLat = StringUtils::toDouble(value);
1310 6 : pars.parametersSet |= STOP_POSLAT_SET;
1311 149 : } else if (param == toString(SUMO_ATTR_ARRIVAL)) {
1312 6 : pars.arrival = string2time(value);
1313 6 : pars.parametersSet |= STOP_ARRIVAL_SET;
1314 143 : } else if (param == toString(SUMO_ATTR_DURATION)) {
1315 12 : pars.duration = string2time(value);
1316 12 : pars.parametersSet |= STOP_DURATION_SET;
1317 : // also update dynamic value
1318 12 : stop.initPars(pars);
1319 131 : } else if (param == toString(SUMO_ATTR_UNTIL)) {
1320 6 : pars.until = string2time(value);
1321 6 : pars.parametersSet |= STOP_UNTIL_SET;
1322 125 : } else if (param == toString(SUMO_ATTR_EXTENSION)) {
1323 12 : pars.extension = string2time(value);
1324 12 : pars.parametersSet |= STOP_EXTENSION_SET;
1325 113 : } else if (param == toString(SUMO_ATTR_INDEX)) {
1326 0 : throw TraCIException("Changing stop index is not supported");
1327 113 : } else if (param == toString(SUMO_ATTR_PARKING)) {
1328 6 : pars.parking = SUMOVehicleParameter::parseParkingType(value);
1329 6 : pars.parametersSet |= STOP_PARKING_SET;
1330 107 : } else if (param == toString(SUMO_ATTR_TRIGGERED)) {
1331 12 : if (pars.speed > 0 && value != "") {
1332 0 : throw ProcessError(TLF("Waypoint (speed = %) at index % does not support triggers", pars.speed, nextStopIndex));
1333 : }
1334 12 : SUMOVehicleParameter::parseStopTriggers(StringTokenizer(value).getVector(), false, pars);
1335 12 : pars.parametersSet |= STOP_TRIGGER_SET;
1336 : // also update dynamic value
1337 12 : stop.initPars(pars);
1338 95 : } else if (param == toString(SUMO_ATTR_EXPECTED)) {
1339 24 : pars.awaitedPersons = StringTokenizer(value).getSet();
1340 12 : pars.parametersSet |= STOP_EXPECTED_SET;
1341 166 : } else if (param == toString(SUMO_ATTR_EXPECTED_CONTAINERS)) {
1342 0 : pars.awaitedContainers = StringTokenizer(value).getSet();
1343 0 : pars.parametersSet |= STOP_EXPECTED_CONTAINERS_SET;
1344 : // also update dynamic value
1345 0 : stop.initPars(pars);
1346 83 : } else if (param == toString(SUMO_ATTR_PERMITTED)) {
1347 12 : pars.permitted = StringTokenizer(value).getSet();
1348 6 : pars.parametersSet |= STOP_PERMITTED_SET;
1349 77 : } else if (param == toString(SUMO_ATTR_ACTTYPE)) {
1350 6 : pars.actType = value;
1351 71 : } else if (param == toString(SUMO_ATTR_TRIP_ID)) {
1352 6 : pars.tripId = value;
1353 6 : pars.parametersSet |= STOP_TRIP_ID_SET;
1354 65 : } else if (param == toString(SUMO_ATTR_SPLIT)) {
1355 6 : pars.split = value;
1356 6 : pars.parametersSet |= STOP_SPLIT_SET;
1357 59 : } else if (param == toString(SUMO_ATTR_JOIN)) {
1358 6 : pars.join = value;
1359 6 : pars.parametersSet |= STOP_JOIN_SET;
1360 53 : } else if (param == toString(SUMO_ATTR_LINE)) {
1361 6 : pars.line = value;
1362 6 : pars.parametersSet |= STOP_LINE_SET;
1363 47 : } else if (param == toString(SUMO_ATTR_SPEED)) {
1364 12 : const double speed = StringUtils::toDouble(value);
1365 12 : if (speed > 0 && pars.getTriggers().size() > 0) {
1366 18 : throw ProcessError(TLF("Triggered stop at index % cannot be changed into a waypoint by setting speed to %", nextStopIndex, speed));
1367 : }
1368 6 : pars.speed = speed;
1369 6 : pars.parametersSet |= STOP_SPEED_SET;
1370 35 : } else if (param == toString(SUMO_ATTR_STARTED)) {
1371 6 : pars.started = string2time(value);
1372 6 : pars.parametersSet |= STOP_STARTED_SET;
1373 29 : } else if (param == toString(SUMO_ATTR_ENDED)) {
1374 6 : pars.ended = string2time(value);
1375 6 : pars.parametersSet |= STOP_ENDED_SET;
1376 23 : } else if (param == toString(SUMO_ATTR_ONDEMAND)) {
1377 6 : pars.onDemand = StringUtils::toBool(value);
1378 6 : pars.parametersSet |= STOP_ONDEMAND_SET;
1379 23 : } else if (param == toString(SUMO_ATTR_JUMP)) {
1380 17 : pars.jump = string2time(value);
1381 17 : pars.parametersSet |= STOP_JUMP_SET;
1382 : } else {
1383 0 : throw ProcessError(TLF("Unsupported parameter '%'", param));
1384 : }
1385 6 : } catch (ProcessError& e) {
1386 12 : throw TraCIException("Could not set stop parameter for vehicle '" + vehID + "' (" + e.what() + ")");
1387 6 : }
1388 : }
1389 :
1390 :
1391 : void
1392 18 : Vehicle::rerouteParkingArea(const std::string& vehID, const std::string& parkingAreaID) {
1393 18 : MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
1394 18 : MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
1395 18 : if (veh == nullptr) {
1396 0 : WRITE_WARNING("rerouteParkingArea not yet implemented for meso");
1397 0 : return;
1398 : }
1399 : std::string error;
1400 : // Forward command to vehicle
1401 18 : if (!veh->rerouteParkingArea(parkingAreaID, error)) {
1402 0 : throw TraCIException(error);
1403 : }
1404 : }
1405 :
1406 : void
1407 8 : Vehicle::resume(const std::string& vehID) {
1408 8 : MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
1409 8 : MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
1410 8 : if (veh == nullptr) {
1411 1 : WRITE_WARNING("resume not yet implemented for meso");
1412 1 : return;
1413 : }
1414 7 : if (!veh->hasStops()) {
1415 0 : throw TraCIException("Failed to resume vehicle '" + veh->getID() + "', it has no stops.");
1416 : }
1417 7 : if (!veh->resumeFromStopping()) {
1418 0 : MSStop& sto = veh->getNextStop();
1419 0 : std::ostringstream strs;
1420 0 : strs << "reached: " << sto.reached;
1421 0 : strs << ", duration:" << sto.duration;
1422 0 : strs << ", edge:" << (*sto.edge)->getID();
1423 0 : strs << ", startPos: " << sto.pars.startPos;
1424 : std::string posStr = strs.str();
1425 0 : throw TraCIException("Failed to resume from stopping for vehicle '" + veh->getID() + "', " + posStr);
1426 0 : }
1427 : }
1428 :
1429 :
1430 : void
1431 43074 : Vehicle::changeTarget(const std::string& vehID, const std::string& edgeID) {
1432 43074 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
1433 43074 : const MSEdge* destEdge = MSEdge::dictionary(edgeID);
1434 43074 : const bool onInit = isOnInit(vehID);
1435 43074 : if (destEdge == nullptr) {
1436 2 : throw TraCIException("Destination edge '" + edgeID + "' is not known.");
1437 : }
1438 : // build a new route between the vehicle's current edge and destination edge
1439 : ConstMSEdgeVector newRoute;
1440 43073 : const MSEdge* currentEdge = *veh->getRerouteOrigin();
1441 43073 : veh->getRouterTT().compute(
1442 : currentEdge, destEdge, veh, MSNet::getInstance()->getCurrentTimeStep(), newRoute);
1443 : // replace the vehicle's route by the new one (cost is updated by call to reroute())
1444 : std::string errorMsg;
1445 86157 : if (!veh->replaceRouteEdges(newRoute, -1, 0, "traci:changeTarget", onInit, false, true, &errorMsg)) {
1446 22 : throw TraCIException("Route replacement failed for vehicle '" + veh->getID() + "' (" + errorMsg + ").");
1447 : }
1448 : // route again to ensure usage of via/stops
1449 : try {
1450 86124 : veh->reroute(MSNet::getInstance()->getCurrentTimeStep(), "traci:changeTarget",
1451 : veh->getRouterTT(), onInit);
1452 0 : } catch (ProcessError& e) {
1453 0 : throw TraCIException(e.what());
1454 0 : }
1455 43062 : }
1456 :
1457 :
1458 : void
1459 10393 : Vehicle::changeLane(const std::string& vehID, int laneIndex, double duration) {
1460 10393 : MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
1461 10393 : MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
1462 10393 : if (veh == nullptr) {
1463 0 : WRITE_ERROR("changeLane not applicable for meso");
1464 0 : return;
1465 : }
1466 :
1467 : std::vector<std::pair<SUMOTime, int> > laneTimeLine;
1468 10393 : laneTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep(), laneIndex));
1469 10393 : laneTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep() + TIME2STEPS(duration), laneIndex));
1470 10393 : veh->getInfluencer().setLaneTimeLine(laneTimeLine);
1471 : }
1472 :
1473 : void
1474 322 : Vehicle::changeLaneRelative(const std::string& vehID, int indexOffset, double duration) {
1475 322 : MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
1476 322 : MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
1477 322 : if (veh == nullptr) {
1478 0 : WRITE_ERROR("changeLaneRelative not applicable for meso");
1479 0 : return;
1480 : }
1481 :
1482 : std::vector<std::pair<SUMOTime, int> > laneTimeLine;
1483 322 : int laneIndex = veh->getLaneIndex() + indexOffset;
1484 322 : if (laneIndex < 0 && !veh->getLaneChangeModel().isOpposite()) {
1485 24 : if (veh->getLaneIndex() == -1) {
1486 0 : WRITE_WARNINGF(TL("Ignoring changeLaneRelative for vehicle '%' that isn't on the road"), vehID);
1487 : } else {
1488 72 : WRITE_WARNINGF(TL("Ignoring indexOffset % for vehicle '%' on laneIndex %."), indexOffset, vehID, veh->getLaneIndex());
1489 : }
1490 : } else {
1491 298 : laneTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep(), laneIndex));
1492 298 : laneTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep() + TIME2STEPS(duration), laneIndex));
1493 298 : veh->getInfluencer().setLaneTimeLine(laneTimeLine);
1494 : }
1495 : }
1496 :
1497 :
1498 : void
1499 412 : Vehicle::changeSublane(const std::string& vehID, double latDist) {
1500 412 : MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
1501 412 : MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
1502 412 : if (veh == nullptr) {
1503 1 : WRITE_ERROR("changeSublane not applicable for meso");
1504 1 : return;
1505 : }
1506 :
1507 411 : veh->getInfluencer().setSublaneChange(latDist);
1508 : }
1509 :
1510 :
1511 : void
1512 37580 : Vehicle::add(const std::string& vehID,
1513 : const std::string& routeID,
1514 : const std::string& typeID,
1515 : const std::string& depart,
1516 : const std::string& departLane,
1517 : const std::string& departPos,
1518 : const std::string& departSpeed,
1519 : const std::string& arrivalLane,
1520 : const std::string& arrivalPos,
1521 : const std::string& arrivalSpeed,
1522 : const std::string& fromTaz,
1523 : const std::string& toTaz,
1524 : const std::string& line,
1525 : int /*personCapacity*/,
1526 : int personNumber) {
1527 37580 : SUMOVehicle* veh = MSNet::getInstance()->getVehicleControl().getVehicle(vehID);
1528 37580 : if (veh != nullptr) {
1529 2 : throw TraCIException("The vehicle '" + vehID + "' to add already exists.");
1530 : }
1531 :
1532 37579 : SUMOVehicleParameter vehicleParams;
1533 : vehicleParams.id = vehID;
1534 37579 : MSVehicleType* vehicleType = MSNet::getInstance()->getVehicleControl().getVType(typeID);
1535 37579 : if (!vehicleType) {
1536 2 : throw TraCIException("Invalid type '" + typeID + "' for vehicle '" + vehID + "'.");
1537 : }
1538 37578 : if (typeID != "DEFAULT_VEHTYPE") {
1539 : vehicleParams.vtypeid = typeID;
1540 36334 : vehicleParams.parametersSet |= VEHPARS_VTYPE_SET;
1541 : }
1542 37578 : if (SUMOVehicleParserHelper::isInternalRouteID(routeID)) {
1543 0 : WRITE_WARNINGF(TL("Internal routes receive an ID starting with '!' and must not be referenced in other vehicle or flow definitions. Please remove all references to route '%' in case it is internal."), routeID);
1544 : }
1545 37578 : ConstMSRoutePtr route = MSRoute::dictionary(routeID);
1546 37578 : if (!route) {
1547 41 : if (routeID == "") {
1548 : // assume, route was intentionally left blank because the caller
1549 : // intends to control the vehicle remotely
1550 : SUMOVehicleClass vclass = vehicleType->getVehicleClass();
1551 40 : const std::string dummyRouteID = "DUMMY_ROUTE_" + SumoVehicleClassStrings.getString(vclass);
1552 80 : route = MSRoute::dictionary(dummyRouteID);
1553 40 : if (route == nullptr) {
1554 5140 : for (MSEdge* e : MSEdge::getAllEdges()) {
1555 5140 : if (e->getFunction() == SumoXMLEdgeFunc::NORMAL && (e->getPermissions() & vclass) == vclass) {
1556 : std::vector<std::string> edges;
1557 40 : edges.push_back(e->getID());
1558 40 : libsumo::Route::add(dummyRouteID, edges);
1559 : break;
1560 40 : }
1561 : }
1562 : }
1563 80 : route = MSRoute::dictionary(dummyRouteID);
1564 40 : if (!route) {
1565 0 : throw TraCIException("Could not build dummy route for vehicle class: '" + SumoVehicleClassStrings.getString(vehicleType->getVehicleClass()) + "'");
1566 : }
1567 : } else {
1568 2 : throw TraCIException("Invalid route '" + routeID + "' for vehicle '" + vehID + "'.");
1569 : }
1570 : }
1571 : // check if the route implies a trip
1572 37577 : if (route->getEdges().size() == 2) {
1573 37054 : const MSEdgeVector& succ = route->getEdges().front()->getSuccessors();
1574 37054 : if (std::find(succ.begin(), succ.end(), route->getEdges().back()) == succ.end()) {
1575 64 : vehicleParams.parametersSet |= VEHPARS_FORCE_REROUTE;
1576 : }
1577 : }
1578 75142 : if (fromTaz != "" || toTaz != "") {
1579 18 : vehicleParams.parametersSet |= VEHPARS_FORCE_REROUTE;
1580 : }
1581 : std::string error;
1582 75154 : if (!SUMOVehicleParameter::parseDepart(depart, "vehicle", vehID, vehicleParams.depart, vehicleParams.departProcedure, error)) {
1583 0 : throw TraCIException(error);
1584 : }
1585 37577 : if (vehicleParams.departProcedure == DepartDefinition::GIVEN && vehicleParams.depart < MSNet::getInstance()->getCurrentTimeStep()) {
1586 10 : vehicleParams.depart = MSNet::getInstance()->getCurrentTimeStep();
1587 30 : WRITE_WARNINGF(TL("Departure time for vehicle '%' is in the past; using current time instead."), vehID);
1588 37567 : } else if (vehicleParams.departProcedure == DepartDefinition::NOW) {
1589 37515 : vehicleParams.depart = MSNet::getInstance()->getCurrentTimeStep();
1590 : }
1591 75154 : if (!SUMOVehicleParameter::parseDepartLane(departLane, "vehicle", vehID, vehicleParams.departLane, vehicleParams.departLaneProcedure, error)) {
1592 10 : throw TraCIException(error);
1593 : }
1594 75144 : if (!SUMOVehicleParameter::parseDepartPos(departPos, "vehicle", vehID, vehicleParams.departPos, vehicleParams.departPosProcedure, error)) {
1595 0 : throw TraCIException(error);
1596 : }
1597 75144 : if (!SUMOVehicleParameter::parseDepartSpeed(departSpeed, "vehicle", vehID, vehicleParams.departSpeed, vehicleParams.departSpeedProcedure, error)) {
1598 0 : throw TraCIException(error);
1599 : }
1600 75144 : if (!SUMOVehicleParameter::parseArrivalLane(arrivalLane, "vehicle", vehID, vehicleParams.arrivalLane, vehicleParams.arrivalLaneProcedure, error)) {
1601 0 : throw TraCIException(error);
1602 : }
1603 75144 : if (!SUMOVehicleParameter::parseArrivalPos(arrivalPos, "vehicle", vehID, vehicleParams.arrivalPos, vehicleParams.arrivalPosProcedure, error)) {
1604 0 : throw TraCIException(error);
1605 : }
1606 75169 : if (!SUMOVehicleParameter::parseArrivalSpeed(arrivalSpeed, "vehicle", vehID, vehicleParams.arrivalSpeed, vehicleParams.arrivalSpeedProcedure, error)) {
1607 0 : throw TraCIException(error);
1608 : }
1609 : // mark non-default attributes
1610 37572 : if (departLane != "first") {
1611 36377 : vehicleParams.parametersSet |= VEHPARS_DEPARTLANE_SET;
1612 : }
1613 37572 : if (departPos != "base") {
1614 36600 : vehicleParams.parametersSet |= VEHPARS_DEPARTPOS_SET;
1615 : }
1616 37572 : if (departSpeed != "0") {
1617 36324 : vehicleParams.parametersSet |= VEHPARS_DEPARTSPEED_SET;
1618 : }
1619 37572 : if (arrivalLane != "current") {
1620 18 : vehicleParams.parametersSet |= VEHPARS_ARRIVALLANE_SET;
1621 : }
1622 37572 : if (arrivalPos != "max") {
1623 12 : vehicleParams.parametersSet |= VEHPARS_ARRIVALPOS_SET;
1624 : }
1625 37572 : if (arrivalSpeed != "current") {
1626 6 : vehicleParams.parametersSet |= VEHPARS_ARRIVALSPEED_SET;
1627 : }
1628 37572 : if (fromTaz != "") {
1629 12 : vehicleParams.parametersSet |= VEHPARS_FROM_TAZ_SET;
1630 : }
1631 37572 : if (toTaz != "") {
1632 12 : vehicleParams.parametersSet |= VEHPARS_TO_TAZ_SET;
1633 : }
1634 37572 : if (line != "") {
1635 24 : vehicleParams.parametersSet |= VEHPARS_LINE_SET;
1636 : }
1637 37572 : if (personNumber != 0) {
1638 0 : vehicleParams.parametersSet |= VEHPARS_PERSON_NUMBER_SET;
1639 : }
1640 : // build vehicle
1641 : vehicleParams.fromTaz = fromTaz;
1642 : vehicleParams.toTaz = toTaz;
1643 : vehicleParams.line = line;
1644 : //vehicleParams.personCapacity = personCapacity;
1645 37572 : vehicleParams.personNumber = personNumber;
1646 :
1647 37572 : SUMOVehicleParameter* params = new SUMOVehicleParameter(vehicleParams);
1648 : SUMOVehicle* vehicle = nullptr;
1649 : try {
1650 75144 : vehicle = MSNet::getInstance()->getVehicleControl().buildVehicle(params, route, vehicleType, true, false);
1651 37572 : if (fromTaz == "" && !route->getEdges().front()->validateDepartSpeed(*vehicle)) {
1652 6 : MSNet::getInstance()->getVehicleControl().deleteVehicle(vehicle, true);
1653 12 : throw TraCIException("Departure speed for vehicle '" + vehID + "' is too high for the departure edge '" + route->getEdges().front()->getID() + "'.");
1654 : }
1655 : std::string msg;
1656 37566 : if (vehicle->getRouteValidity(true, true, &msg) != MSBaseVehicle::ROUTE_VALID) {
1657 6 : MSNet::getInstance()->getVehicleControl().deleteVehicle(vehicle, true);
1658 12 : throw TraCIException("Vehicle '" + vehID + "' has no valid route (" + msg + "). ");
1659 : }
1660 37552 : MSNet::getInstance()->getVehicleControl().addVehicle(vehicleParams.id, vehicle);
1661 37552 : if (vehicleParams.departProcedure != DepartDefinition::TRIGGERED && vehicleParams.departProcedure != DepartDefinition::CONTAINER_TRIGGERED) {
1662 37528 : MSNet::getInstance()->getInsertionControl().add(vehicle);
1663 : }
1664 20 : } catch (ProcessError& e) {
1665 8 : if (vehicle != nullptr) {
1666 8 : MSNet::getInstance()->getVehicleControl().deleteVehicle(vehicle, true);
1667 : }
1668 16 : throw TraCIException(e.what());
1669 8 : }
1670 37579 : }
1671 :
1672 :
1673 : void
1674 8780 : Vehicle::moveToXY(const std::string& vehID, const std::string& edgeID, const int laneIndex,
1675 : const double x, const double y, double angle, const int keepRoute, double matchThreshold) {
1676 8780 : MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
1677 8780 : MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
1678 8780 : if (veh == nullptr) {
1679 3 : WRITE_WARNING("moveToXY not yet implemented for meso");
1680 3 : return;
1681 : }
1682 14389 : const bool doKeepRoute = (keepRoute & 1) != 0 && veh->getID() != "VTD_EGO";
1683 8777 : const bool mayLeaveNetwork = (keepRoute & 2) != 0;
1684 8777 : const bool ignorePermissions = (keepRoute & 4) != 0;
1685 8777 : const bool setLateralPos = (MSGlobals::gLateralResolution > 0 || mayLeaveNetwork);
1686 8777 : SUMOVehicleClass vClass = ignorePermissions ? SVC_IGNORING : veh->getVClass();
1687 : // process
1688 17554 : const std::string origID = edgeID + "_" + toString(laneIndex);
1689 : // @todo add an interpretation layer for OSM derived origID values (without lane index)
1690 : Position pos(x, y);
1691 : #ifdef DEBUG_MOVEXY
1692 : const double origAngle = angle;
1693 : #endif
1694 : // angle must be in [0,360] because it will be compared against those returned by naviDegree()
1695 : // angle set to INVALID_DOUBLE_VALUE is ignored in the evaluated and later set to the angle of the matched lane
1696 8777 : if (angle != INVALID_DOUBLE_VALUE) {
1697 2768 : while (angle >= 360.) {
1698 0 : angle -= 360.;
1699 : }
1700 2773 : while (angle < 0.) {
1701 5 : angle += 360.;
1702 : }
1703 : }
1704 :
1705 : #ifdef DEBUG_MOVEXY
1706 : std::cout << std::endl << SIMTIME << " moveToXY veh=" << veh->getID() << " vehPos=" << veh->getPosition()
1707 : << " lane=" << Named::getIDSecure(veh->getLane()) << " lanePos=" << vehicle->getPositionOnLane() << std::endl;
1708 : std::cout << " wantedPos=" << pos << " origID=" << origID << " laneIndex=" << laneIndex << " origAngle=" << origAngle << " angle=" << angle << " keepRoute=" << keepRoute << std::endl;
1709 : #endif
1710 :
1711 : ConstMSEdgeVector edges;
1712 8777 : MSLane* lane = nullptr;
1713 : double lanePos;
1714 : double lanePosLat = 0;
1715 8777 : double bestDistance = std::numeric_limits<double>::max();
1716 8777 : int routeOffset = 0;
1717 : bool found;
1718 8777 : double maxRouteDistance = matchThreshold;
1719 : /* EGO vehicle is known to have a fixed route. @todo make this into a parameter of the TraCI call */
1720 8777 : if (doKeepRoute) {
1721 : // case a): vehicle is on its earlier route
1722 : // we additionally assume it is moving forward (SUMO-limit);
1723 : // note that the route ("edges") is not changed in this case
1724 :
1725 5603 : found = Helper::moveToXYMap_matchingRoutePosition(pos, origID,
1726 5603 : veh->getRoute().getEdges(), veh->getRoutePosition(),
1727 : vClass, setLateralPos,
1728 : bestDistance, &lane, lanePos, routeOffset);
1729 : // @note silenty ignoring mapping failure
1730 : } else {
1731 3174 : const double speed = pos.distanceTo2D(veh->getPosition()); // !!!veh->getSpeed();
1732 3174 : found = Helper::moveToXYMap(pos, maxRouteDistance, mayLeaveNetwork, origID, angle,
1733 3174 : speed, veh->getRoute().getEdges(), veh->getRoutePosition(), veh->getLane(), veh->getPositionOnLane(), veh->isOnRoad(),
1734 : vClass, setLateralPos,
1735 : bestDistance, &lane, lanePos, routeOffset, edges);
1736 : }
1737 8777 : if ((found && bestDistance <= maxRouteDistance) || mayLeaveNetwork) {
1738 : // optionally compute lateral offset
1739 8769 : pos.setz(veh->getPosition().z());
1740 8769 : if (found && setLateralPos) {
1741 5513 : const double perpDist = lane->getShape().distance2D(pos, false);
1742 5513 : if (perpDist != GeomHelper::INVALID_OFFSET) {
1743 : lanePosLat = perpDist;
1744 5513 : if (!mayLeaveNetwork) {
1745 67 : lanePosLat = MIN2(lanePosLat, 0.5 * (lane->getWidth() + veh->getVehicleType().getWidth() - MSGlobals::gLateralResolution));
1746 : }
1747 : // figure out whether the offset is to the left or to the right
1748 5513 : PositionVector tmp = lane->getShape();
1749 : try {
1750 5513 : tmp.move2side(-lanePosLat); // moved to left
1751 0 : } catch (ProcessError&) {
1752 0 : WRITE_WARNINGF(TL("Could not determine position on lane '%' at lateral position %."), lane->getID(), toString(-lanePosLat));
1753 0 : }
1754 : //std::cout << " lane=" << lane->getID() << " posLat=" << lanePosLat << " shape=" << lane->getShape() << " tmp=" << tmp << " tmpDist=" << tmp.distance2D(pos) << "\n";
1755 5513 : if (tmp.distance2D(pos) > perpDist) {
1756 : lanePosLat = -lanePosLat;
1757 : }
1758 5513 : }
1759 5513 : pos.setz(lane->geometryPositionAtOffset(lanePos).z());
1760 : }
1761 8769 : if (found && !mayLeaveNetwork && MSGlobals::gLateralResolution < 0) {
1762 : // mapped position may differ from pos
1763 3087 : pos = lane->geometryPositionAtOffset(lanePos, -lanePosLat);
1764 : }
1765 : assert((found && lane != 0) || (!found && lane == 0));
1766 : assert(!std::isnan(lanePos));
1767 8769 : if (angle == INVALID_DOUBLE_VALUE) {
1768 6003 : if (lane != nullptr) {
1769 5835 : angle = GeomHelper::naviDegree(lane->getShape().rotationAtOffset(lanePos));
1770 : } else {
1771 : // compute angle outside road network from old and new position
1772 168 : angle = GeomHelper::naviDegree(veh->getPosition().angleTo2D(pos));
1773 : }
1774 : }
1775 : // use the best we have
1776 : #ifdef DEBUG_MOVEXY
1777 : std::cout << SIMTIME << " veh=" << vehID + " moveToXYResult lane='" << Named::getIDSecure(lane) << "' lanePos=" << lanePos << " lanePosLat=" << lanePosLat << "\n";
1778 : #endif
1779 8777 : Helper::setRemoteControlled(veh, pos, lane, lanePos, lanePosLat, angle, routeOffset, edges, MSNet::getInstance()->getCurrentTimeStep());
1780 8769 : if (!veh->isOnRoad()) {
1781 229 : MSNet::getInstance()->getInsertionControl().alreadyDeparted(veh);
1782 : }
1783 : } else {
1784 8 : if (lane == nullptr) {
1785 2 : throw TraCIException("Could not map vehicle '" + vehID + "', no road found within " + toString(maxRouteDistance) + "m.");
1786 : } else {
1787 14 : throw TraCIException("Could not map vehicle '" + vehID + "', distance to road is " + toString(bestDistance) + ".");
1788 : }
1789 : }
1790 : }
1791 :
1792 : void
1793 58 : Vehicle::slowDown(const std::string& vehID, double speed, double duration) {
1794 58 : MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
1795 58 : MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
1796 58 : if (veh == nullptr) {
1797 6 : WRITE_ERROR("slowDown not applicable for meso");
1798 6 : return;
1799 : }
1800 :
1801 : std::vector<std::pair<SUMOTime, double> > speedTimeLine;
1802 52 : speedTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep(), veh->getSpeed()));
1803 52 : speedTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep() + TIME2STEPS(duration), speed));
1804 52 : veh->getInfluencer().setSpeedTimeLine(speedTimeLine);
1805 : }
1806 :
1807 : void
1808 76 : Vehicle::openGap(const std::string& vehID, double newTimeHeadway, double newSpaceHeadway, double duration, double changeRate, double maxDecel, const std::string& referenceVehID) {
1809 76 : MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
1810 76 : MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
1811 76 : if (veh == nullptr) {
1812 0 : WRITE_ERROR("openGap not applicable for meso");
1813 0 : return;
1814 : }
1815 :
1816 : MSVehicle* refVeh = nullptr;
1817 76 : if (referenceVehID != "") {
1818 16 : refVeh = dynamic_cast<MSVehicle*>(Helper::getVehicle(referenceVehID));
1819 : }
1820 76 : const double originalTau = veh->getVehicleType().getCarFollowModel().getHeadwayTime();
1821 76 : if (newTimeHeadway == -1) {
1822 : newTimeHeadway = originalTau;
1823 : }
1824 76 : if (originalTau > newTimeHeadway) {
1825 5 : WRITE_WARNING("Ignoring openGap(). New time headway must not be smaller than the original.");
1826 5 : return;
1827 : }
1828 71 : veh->getInfluencer().activateGapController(originalTau, newTimeHeadway, newSpaceHeadway, duration, changeRate, maxDecel, refVeh);
1829 : }
1830 :
1831 : void
1832 10 : Vehicle::deactivateGapControl(const std::string& vehID) {
1833 10 : MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
1834 10 : MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
1835 10 : if (veh == nullptr) {
1836 0 : WRITE_ERROR("deactivateGapControl not applicable for meso");
1837 0 : return;
1838 : }
1839 :
1840 10 : if (veh->hasInfluencer()) {
1841 10 : veh->getInfluencer().deactivateGapController();
1842 : }
1843 : }
1844 :
1845 : void
1846 0 : Vehicle::requestToC(const std::string& vehID, double leadTime) {
1847 0 : setParameter(vehID, "device.toc.requestToC", toString(leadTime));
1848 0 : }
1849 :
1850 : void
1851 6070 : Vehicle::setSpeed(const std::string& vehID, double speed) {
1852 6070 : MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
1853 6070 : MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
1854 6070 : if (veh == nullptr) {
1855 5 : WRITE_WARNING("setSpeed not yet implemented for meso");
1856 5 : return;
1857 : }
1858 :
1859 : std::vector<std::pair<SUMOTime, double> > speedTimeLine;
1860 6065 : if (speed >= 0) {
1861 6023 : speedTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep(), speed));
1862 6023 : speedTimeLine.push_back(std::make_pair(SUMOTime_MAX - DELTA_T, speed));
1863 : }
1864 6065 : veh->getInfluencer().setSpeedTimeLine(speedTimeLine);
1865 : }
1866 :
1867 : void
1868 15 : Vehicle::setAcceleration(const std::string& vehID, double acceleration, double duration) {
1869 15 : MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
1870 15 : MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
1871 15 : if (veh == nullptr) {
1872 3 : WRITE_WARNING("setAcceleration not yet implemented for meso");
1873 3 : return;
1874 : }
1875 :
1876 16 : double targetSpeed = std::max(veh->getSpeed() + acceleration * duration, 0.0);
1877 : std::vector<std::pair<SUMOTime, double>> speedTimeLine;
1878 12 : speedTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep(), veh->getSpeed()));
1879 12 : speedTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep() + TIME2STEPS(duration), targetSpeed));
1880 12 : veh->getInfluencer().setSpeedTimeLine(speedTimeLine);
1881 : }
1882 :
1883 : void
1884 290 : Vehicle::setPreviousSpeed(const std::string& vehID, double prevSpeed, double prevAcceleration) {
1885 290 : MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
1886 290 : MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
1887 290 : if (veh == nullptr) {
1888 0 : WRITE_WARNING("setPreviousSpeed not yet implemented for meso");
1889 0 : return;
1890 : }
1891 290 : if (prevAcceleration == INVALID_DOUBLE_VALUE) {
1892 : prevAcceleration = std::numeric_limits<double>::min();
1893 : }
1894 290 : veh->setPreviousSpeed(prevSpeed, prevAcceleration);
1895 : }
1896 :
1897 : void
1898 2354 : Vehicle::setSpeedMode(const std::string& vehID, int speedMode) {
1899 2354 : MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
1900 2354 : MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
1901 2354 : if (veh == nullptr) {
1902 1 : WRITE_WARNING("setSpeedMode not yet implemented for meso");
1903 1 : return;
1904 : }
1905 :
1906 2353 : veh->getInfluencer().setSpeedMode(speedMode);
1907 : }
1908 :
1909 : void
1910 602 : Vehicle::setLaneChangeMode(const std::string& vehID, int laneChangeMode) {
1911 602 : MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
1912 602 : MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
1913 602 : if (veh == nullptr) {
1914 0 : WRITE_ERROR("setLaneChangeMode not applicable for meso");
1915 0 : return;
1916 : }
1917 :
1918 602 : veh->getInfluencer().setLaneChangeMode(laneChangeMode);
1919 : }
1920 :
1921 : void
1922 302 : Vehicle::setRoutingMode(const std::string& vehID, int routingMode) {
1923 302 : Helper::getVehicle(vehID)->setRoutingMode(routingMode);
1924 302 : }
1925 :
1926 : void
1927 345 : Vehicle::setType(const std::string& vehID, const std::string& typeID) {
1928 345 : MSVehicleType* vehicleType = MSNet::getInstance()->getVehicleControl().getVType(typeID);
1929 345 : if (vehicleType == nullptr) {
1930 0 : throw TraCIException("Vehicle type '" + typeID + "' is not known");
1931 : }
1932 345 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
1933 345 : veh->replaceVehicleType(vehicleType);
1934 345 : MSVehicle* microVeh = dynamic_cast<MSVehicle*>(veh);
1935 345 : if (microVeh != nullptr && microVeh->isOnRoad()) {
1936 325 : microVeh->updateBestLanes(true);
1937 : }
1938 345 : }
1939 :
1940 : void
1941 32 : Vehicle::setRouteID(const std::string& vehID, const std::string& routeID) {
1942 32 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
1943 32 : ConstMSRoutePtr r = MSRoute::dictionary(routeID);
1944 32 : if (r == nullptr) {
1945 2 : throw TraCIException("The route '" + routeID + "' is not known.");
1946 : }
1947 31 : if (SUMOVehicleParserHelper::isInternalRouteID(routeID)) {
1948 3 : WRITE_WARNINGF(TL("Internal routes receive an ID starting with '!' and must not be referenced in other vehicle or flow definitions. Please remove all references to route '%' in case it is internal."), routeID);
1949 : }
1950 : std::string msg;
1951 62 : if (!veh->hasValidRoute(msg, r)) {
1952 5 : WRITE_WARNINGF(TL("Invalid route replacement for vehicle '%'. %"), veh->getID(), msg);
1953 1 : if (MSGlobals::gCheckRoutes) {
1954 2 : throw TraCIException("Route replacement failed for " + veh->getID());
1955 : }
1956 : }
1957 :
1958 : std::string errorMsg;
1959 121 : if (!veh->replaceRoute(r, "traci:setRouteID", veh->getLane() == nullptr, 0, true, true, &errorMsg)) {
1960 2 : throw TraCIException("Route replacement failed for vehicle '" + veh->getID() + "' (" + errorMsg + ").");
1961 : }
1962 29 : }
1963 :
1964 : void
1965 1 : Vehicle::setRoute(const std::string& vehID, const std::string& edgeID) {
1966 3 : setRoute(vehID, std::vector<std::string>({edgeID}));
1967 0 : }
1968 :
1969 :
1970 : void
1971 46 : Vehicle::setRoute(const std::string& vehID, const std::vector<std::string>& edgeIDs) {
1972 46 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
1973 : ConstMSEdgeVector edges;
1974 46 : const bool onInit = veh->getLane() == nullptr;
1975 : try {
1976 86 : MSEdge::parseEdgesList(edgeIDs, edges, "<unknown>");
1977 40 : if (edges.size() > 0 && edges.front()->isInternal()) {
1978 11 : if (edges.size() == 1) {
1979 : // avoid crashing due to lack of normal edges in route (#5390)
1980 6 : edges.push_back(edges.back()->getLanes()[0]->getNextNormal());
1981 : } else {
1982 : // avoid internal edge in final route
1983 5 : if (edges.front() == &veh->getLane()->getEdge()) {
1984 : edges.erase(edges.begin());
1985 : }
1986 : }
1987 : }
1988 6 : } catch (ProcessError& e) {
1989 12 : throw TraCIException("Invalid edge list for vehicle '" + veh->getID() + "' (" + e.what() + ")");
1990 6 : }
1991 : std::string errorMsg;
1992 83 : if (!veh->replaceRouteEdges(edges, -1, 0, "traci:setRoute", onInit, true, true, &errorMsg)) {
1993 6 : throw TraCIException("Route replacement failed for vehicle '" + veh->getID() + "' (" + errorMsg + ").");
1994 : }
1995 37 : }
1996 :
1997 :
1998 : void
1999 10 : Vehicle::setLateralLanePosition(const std::string& vehID, double posLat) {
2000 10 : MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
2001 10 : MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
2002 10 : if (veh != nullptr) {
2003 : veh->setLateralPositionOnLane(posLat);
2004 : } else {
2005 0 : WRITE_ERROR("setLateralLanePosition not applicable for meso");
2006 : }
2007 10 : }
2008 :
2009 :
2010 : void
2011 340 : Vehicle::updateBestLanes(const std::string& vehID) {
2012 340 : MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
2013 340 : MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
2014 340 : if (veh == nullptr) {
2015 0 : WRITE_ERROR("updateBestLanes not applicable for meso");
2016 0 : return;
2017 : }
2018 340 : if (veh->isOnRoad()) {
2019 330 : veh->updateBestLanes(true);
2020 : }
2021 : }
2022 :
2023 :
2024 : void
2025 236 : Vehicle::setAdaptedTraveltime(const std::string& vehID, const std::string& edgeID,
2026 : double time, double begSeconds, double endSeconds) {
2027 236 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
2028 236 : MSEdge* edge = MSEdge::dictionary(edgeID);
2029 236 : if (edge == nullptr) {
2030 0 : throw TraCIException("Edge '" + edgeID + "' is not known.");
2031 : }
2032 236 : if (time != INVALID_DOUBLE_VALUE) {
2033 : // add time
2034 226 : if (begSeconds == 0 && endSeconds == std::numeric_limits<double>::max()) {
2035 : // clean up old values before setting whole range
2036 190 : while (veh->getWeightsStorage().knowsTravelTime(edge)) {
2037 0 : veh->getWeightsStorage().removeTravelTime(edge);
2038 : }
2039 : }
2040 226 : veh->getWeightsStorage().addTravelTime(edge, begSeconds, endSeconds, time);
2041 : } else {
2042 : // remove time
2043 20 : while (veh->getWeightsStorage().knowsTravelTime(edge)) {
2044 10 : veh->getWeightsStorage().removeTravelTime(edge);
2045 : }
2046 : }
2047 236 : }
2048 :
2049 :
2050 : void
2051 38 : Vehicle::setEffort(const std::string& vehID, const std::string& edgeID,
2052 : double effort, double begSeconds, double endSeconds) {
2053 38 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
2054 38 : MSEdge* edge = MSEdge::dictionary(edgeID);
2055 38 : if (edge == nullptr) {
2056 0 : throw TraCIException("Edge '" + edgeID + "' is not known.");
2057 : }
2058 38 : if (effort != INVALID_DOUBLE_VALUE) {
2059 : // add effort
2060 28 : if (begSeconds == 0 && endSeconds == std::numeric_limits<double>::max()) {
2061 : // clean up old values before setting whole range
2062 10 : while (veh->getWeightsStorage().knowsEffort(edge)) {
2063 0 : veh->getWeightsStorage().removeEffort(edge);
2064 : }
2065 : }
2066 28 : veh->getWeightsStorage().addEffort(edge, begSeconds, endSeconds, effort);
2067 : } else {
2068 : // remove effort
2069 20 : while (veh->getWeightsStorage().knowsEffort(edge)) {
2070 10 : veh->getWeightsStorage().removeEffort(edge);
2071 : }
2072 : }
2073 38 : }
2074 :
2075 :
2076 : void
2077 435 : Vehicle::rerouteTraveltime(const std::string& vehID, const bool currentTravelTimes) {
2078 435 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
2079 435 : const int routingMode = veh->getRoutingMode();
2080 435 : if (currentTravelTimes && routingMode == ROUTING_MODE_DEFAULT) {
2081 : veh->setRoutingMode(ROUTING_MODE_AGGREGATED_CUSTOM);
2082 : }
2083 435 : veh->reroute(MSNet::getInstance()->getCurrentTimeStep(), "traci:rerouteTraveltime",
2084 435 : veh->getRouterTT(), isOnInit(vehID));
2085 435 : if (currentTravelTimes && routingMode == ROUTING_MODE_DEFAULT) {
2086 : veh->setRoutingMode(routingMode);
2087 : }
2088 435 : }
2089 :
2090 :
2091 : void
2092 12 : Vehicle::rerouteEffort(const std::string& vehID) {
2093 12 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
2094 24 : veh->reroute(MSNet::getInstance()->getCurrentTimeStep(), "traci:rerouteEffort",
2095 12 : MSNet::getInstance()->getRouterEffort(veh->getRNGIndex()), isOnInit(vehID));
2096 12 : }
2097 :
2098 :
2099 : void
2100 26 : Vehicle::setSignals(const std::string& vehID, int signals) {
2101 26 : MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
2102 26 : MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
2103 26 : if (veh == nullptr) {
2104 1 : WRITE_ERROR("setSignals not applicable for meso");
2105 1 : return;
2106 : }
2107 :
2108 : // set influencer to make the change persistent
2109 25 : veh->getInfluencer().setSignals(signals);
2110 : // set them now so that getSignals returns the correct value
2111 : veh->switchOffSignal(0x0fffffff);
2112 25 : if (signals >= 0) {
2113 : veh->switchOnSignal(signals);
2114 : }
2115 : }
2116 :
2117 :
2118 : void
2119 604 : Vehicle::moveTo(const std::string& vehID, const std::string& laneID, double position, int reason) {
2120 604 : MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
2121 604 : MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
2122 604 : if (veh == nullptr) {
2123 4 : WRITE_WARNING("moveTo not yet implemented for meso");
2124 442 : return;
2125 : }
2126 :
2127 600 : MSLane* l = MSLane::dictionary(laneID);
2128 600 : if (l == nullptr) {
2129 2 : throw TraCIException("Unknown lane '" + laneID + "'.");
2130 : }
2131 599 : if (veh->getLane() == l) {
2132 438 : veh->setTentativeLaneAndPosition(l, position, veh->getLateralPositionOnLane());
2133 438 : return;
2134 : }
2135 : MSEdge* destinationEdge = &l->getEdge();
2136 161 : const MSEdge* destinationRouteEdge = destinationEdge->getNormalBefore();
2137 161 : if (!veh->isOnRoad() && veh->getParameter().wasSet(VEHPARS_FORCE_REROUTE) && veh->getRoute().getEdges().size() == 2) {
2138 : // it's a trip that wasn't routeted yet (likely because the vehicle was added in this step. Find a route now
2139 12 : veh->reroute(MSNet::getInstance()->getCurrentTimeStep(), "traci:moveTo-tripInsertion",
2140 : veh->getRouterTT(), true);
2141 : }
2142 : // find edge in the remaining route
2143 161 : MSRouteIterator it = std::find(veh->getCurrentRouteEdge(), veh->getRoute().end(), destinationRouteEdge);
2144 161 : if (it == veh->getRoute().end()) {
2145 : // find edge in the edges that were already passed
2146 46 : it = std::find(veh->getRoute().begin(), veh->getRoute().end(), destinationRouteEdge);
2147 : }
2148 161 : if (it == veh->getRoute().end() ||
2149 : // internal edge must continue the route
2150 12 : (destinationEdge->isInternal() &&
2151 12 : ((it + 1) == veh->getRoute().end()
2152 12 : || l->getNextNormal() != *(it + 1)))) {
2153 38 : throw TraCIException("Lane '" + laneID + "' is not on the route of vehicle '" + vehID + "'.");
2154 : }
2155 142 : Position oldPos = vehicle->getPosition();
2156 142 : veh->onRemovalFromNet(MSMoveReminder::NOTIFICATION_TELEPORT);
2157 142 : if (veh->getLane() != nullptr) {
2158 : // correct odometer which gets incremented via onRemovalFromNet->leaveLane
2159 105 : veh->addToOdometer(-veh->getLane()->getLength());
2160 105 : veh->getMutableLane()->removeVehicle(veh, MSMoveReminder::NOTIFICATION_TELEPORT, false);
2161 : } else {
2162 37 : veh->setTentativeLaneAndPosition(l, position);
2163 : }
2164 142 : const int oldRouteIndex = veh->getRoutePosition();
2165 142 : const int newRouteIndex = (int)(it - veh->getRoute().begin());
2166 142 : if (oldRouteIndex > newRouteIndex) {
2167 : // more odometer correction needed
2168 : veh->addToOdometer(-l->getLength());
2169 : }
2170 142 : veh->resetRoutePosition(newRouteIndex, veh->getParameter().departLaneProcedure);
2171 142 : if (!veh->isOnRoad()) {
2172 142 : MSNet::getInstance()->getInsertionControl().alreadyDeparted(veh);
2173 142 : MSVehicleTransfer::getInstance()->remove(veh);
2174 : }
2175 : MSMoveReminder::Notification moveReminderReason;
2176 142 : if (veh->hasDeparted()) {
2177 105 : if (reason == MOVE_TELEPORT) {
2178 : moveReminderReason = MSMoveReminder::NOTIFICATION_TELEPORT;
2179 100 : } else if (reason == MOVE_NORMAL) {
2180 : moveReminderReason = MSMoveReminder::NOTIFICATION_JUNCTION;
2181 95 : } else if (reason == MOVE_AUTOMATIC) {
2182 : Position newPos = l->geometryPositionAtOffset(position);
2183 : const double dist = newPos.distanceTo2D(oldPos);
2184 95 : if (dist < SPEED2DIST(veh->getMaxSpeed())) {
2185 : moveReminderReason = MSMoveReminder::NOTIFICATION_JUNCTION;
2186 : } else {
2187 : moveReminderReason = MSMoveReminder::NOTIFICATION_TELEPORT;
2188 : }
2189 : } else {
2190 0 : throw TraCIException("Invalid moveTo reason '" + toString(reason) + "' for vehicle '" + vehID + "'.");
2191 : }
2192 : } else {
2193 : moveReminderReason = MSMoveReminder::NOTIFICATION_DEPARTED;
2194 : }
2195 142 : l->forceVehicleInsertion(veh, position, moveReminderReason);
2196 : }
2197 :
2198 :
2199 : void
2200 21 : Vehicle::setActionStepLength(const std::string& vehID, double actionStepLength, bool resetActionOffset) {
2201 21 : if (actionStepLength < 0.0) {
2202 0 : WRITE_ERROR("Invalid action step length (<0). Ignoring command setActionStepLength().");
2203 0 : return;
2204 : }
2205 21 : MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
2206 21 : MSVehicle* veh = dynamic_cast<MSVehicle*>(vehicle);
2207 21 : if (veh == nullptr) {
2208 3 : WRITE_ERROR("setActionStepLength not applicable for meso");
2209 3 : return;
2210 : }
2211 :
2212 18 : if (actionStepLength == 0.) {
2213 0 : veh->resetActionOffset();
2214 : } else {
2215 18 : veh->setActionStepLength(actionStepLength, resetActionOffset);
2216 : }
2217 : }
2218 :
2219 :
2220 : void
2221 4 : Vehicle::setBoardingDuration(const std::string& vehID, double boardingDuration) {
2222 4 : Helper::getVehicle(vehID)->getSingularType().setBoardingDuration(TIME2STEPS(boardingDuration));
2223 4 : }
2224 :
2225 :
2226 : void
2227 31 : Vehicle::setImpatience(const std::string& vehID, double impatience) {
2228 31 : MSBaseVehicle* vehicle = Helper::getVehicle(vehID);
2229 31 : const double normalImpatience = vehicle->getImpatience();
2230 31 : vehicle->getBaseInfluencer().setExtraImpatience(impatience - normalImpatience);
2231 31 : }
2232 :
2233 :
2234 : void
2235 33 : Vehicle::remove(const std::string& vehID, char reason) {
2236 33 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
2237 : MSMoveReminder::Notification n = MSMoveReminder::NOTIFICATION_ARRIVED;
2238 : switch (reason) {
2239 : case REMOVE_TELEPORT:
2240 : // XXX semantics unclear
2241 : // n = MSMoveReminder::NOTIFICATION_TELEPORT;
2242 : n = MSMoveReminder::NOTIFICATION_TELEPORT_ARRIVED;
2243 : break;
2244 : case REMOVE_PARKING:
2245 : // XXX semantics unclear
2246 : // n = MSMoveReminder::NOTIFICATION_PARKING;
2247 : n = MSMoveReminder::NOTIFICATION_ARRIVED;
2248 : break;
2249 : case REMOVE_ARRIVED:
2250 : n = MSMoveReminder::NOTIFICATION_ARRIVED;
2251 : break;
2252 : case REMOVE_VAPORIZED:
2253 : n = MSMoveReminder::NOTIFICATION_VAPORIZED_TRACI;
2254 : break;
2255 : case REMOVE_TELEPORT_ARRIVED:
2256 : n = MSMoveReminder::NOTIFICATION_TELEPORT_ARRIVED;
2257 : break;
2258 0 : default:
2259 0 : throw TraCIException("Unknown removal status.");
2260 : }
2261 33 : if (veh->hasDeparted()) {
2262 28 : veh->onRemovalFromNet(n);
2263 28 : MSVehicle* microVeh = dynamic_cast<MSVehicle*>(veh);
2264 28 : if (microVeh != nullptr) {
2265 27 : if (veh->getLane() != nullptr) {
2266 27 : microVeh->getMutableLane()->removeVehicle(dynamic_cast<MSVehicle*>(veh), n);
2267 : }
2268 27 : MSNet::getInstance()->getVehicleControl().scheduleVehicleRemoval(veh);
2269 : }
2270 28 : MSNet::getInstance()->getVehicleControl().removePending();
2271 : } else {
2272 5 : MSNet::getInstance()->getInsertionControl().alreadyDeparted(veh);
2273 5 : MSNet::getInstance()->getVehicleControl().deleteVehicle(veh, true);
2274 : }
2275 33 : }
2276 :
2277 :
2278 : void
2279 223 : Vehicle::setColor(const std::string& vehID, const TraCIColor& col) {
2280 223 : const SUMOVehicleParameter& p = Helper::getVehicle(vehID)->getParameter();
2281 223 : p.color.set((unsigned char)col.r, (unsigned char)col.g, (unsigned char)col.b, (unsigned char)col.a);
2282 223 : p.parametersSet |= VEHPARS_COLOR_SET;
2283 223 : }
2284 :
2285 :
2286 : void
2287 9055 : Vehicle::setSpeedFactor(const std::string& vehID, double factor) {
2288 9055 : Helper::getVehicle(vehID)->setChosenSpeedFactor(factor);
2289 9055 : }
2290 :
2291 :
2292 : void
2293 18 : Vehicle::setLine(const std::string& vehID, const std::string& line) {
2294 18 : Helper::getVehicle(vehID)->getParameter().line = line;
2295 18 : }
2296 :
2297 :
2298 : void
2299 22 : Vehicle::setVia(const std::string& vehID, const std::vector<std::string>& edgeList) {
2300 22 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
2301 : try {
2302 : // ensure edges exist
2303 : ConstMSEdgeVector edges;
2304 44 : MSEdge::parseEdgesList(edgeList, edges, "<via-edges>");
2305 0 : } catch (ProcessError& e) {
2306 0 : throw TraCIException(e.what());
2307 0 : }
2308 22 : veh->getParameter().via = edgeList;
2309 22 : }
2310 :
2311 :
2312 : void
2313 45 : Vehicle::setLength(const std::string& vehID, double length) {
2314 45 : Helper::getVehicle(vehID)->getSingularType().setLength(length);
2315 45 : }
2316 :
2317 :
2318 : void
2319 17 : Vehicle::setMaxSpeed(const std::string& vehID, double speed) {
2320 17 : Helper::getVehicle(vehID)->getSingularType().setMaxSpeed(speed);
2321 17 : }
2322 :
2323 :
2324 : void
2325 4 : Vehicle::setVehicleClass(const std::string& vehID, const std::string& clazz) {
2326 4 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
2327 4 : veh->getSingularType().setVClass(getVehicleClassID(clazz));
2328 4 : MSVehicle* microVeh = dynamic_cast<MSVehicle*>(veh);
2329 4 : if (microVeh != nullptr && microVeh->isOnRoad()) {
2330 4 : microVeh->updateBestLanes(true);
2331 : }
2332 4 : }
2333 :
2334 :
2335 : void
2336 4 : Vehicle::setShapeClass(const std::string& vehID, const std::string& clazz) {
2337 4 : Helper::getVehicle(vehID)->getSingularType().setShape(getVehicleShapeID(clazz));
2338 4 : }
2339 :
2340 :
2341 : void
2342 8 : Vehicle::setEmissionClass(const std::string& vehID, const std::string& clazz) {
2343 8 : Helper::getVehicle(vehID)->getSingularType().setEmissionClass(PollutantsInterface::getClassByName(clazz));
2344 8 : }
2345 :
2346 :
2347 : void
2348 5 : Vehicle::setWidth(const std::string& vehID, double width) {
2349 5 : Helper::getVehicle(vehID)->getSingularType().setWidth(width);
2350 5 : }
2351 :
2352 :
2353 : void
2354 4 : Vehicle::setHeight(const std::string& vehID, double height) {
2355 4 : Helper::getVehicle(vehID)->getSingularType().setHeight(height);
2356 4 : }
2357 :
2358 :
2359 : void
2360 5 : Vehicle::setMinGap(const std::string& vehID, double minGap) {
2361 5 : Helper::getVehicle(vehID)->getSingularType().setMinGap(minGap);
2362 5 : }
2363 :
2364 :
2365 : void
2366 8 : Vehicle::setAccel(const std::string& vehID, double accel) {
2367 8 : Helper::getVehicle(vehID)->getSingularType().setAccel(accel);
2368 7 : }
2369 :
2370 :
2371 : void
2372 5 : Vehicle::setDecel(const std::string& vehID, double decel) {
2373 5 : VehicleType::setDecel(Helper::getVehicle(vehID)->getSingularType().getID(), decel);
2374 5 : }
2375 :
2376 :
2377 : void
2378 9 : Vehicle::setEmergencyDecel(const std::string& vehID, double decel) {
2379 9 : VehicleType::setEmergencyDecel(Helper::getVehicle(vehID)->getSingularType().getID(), decel);
2380 9 : }
2381 :
2382 :
2383 : void
2384 5 : Vehicle::setApparentDecel(const std::string& vehID, double decel) {
2385 5 : Helper::getVehicle(vehID)->getSingularType().setApparentDecel(decel);
2386 5 : }
2387 :
2388 :
2389 : void
2390 7 : Vehicle::setImperfection(const std::string& vehID, double imperfection) {
2391 7 : Helper::getVehicle(vehID)->getSingularType().setImperfection(imperfection);
2392 7 : }
2393 :
2394 :
2395 : void
2396 5 : Vehicle::setTau(const std::string& vehID, double tau) {
2397 5 : Helper::getVehicle(vehID)->getSingularType().setTau(tau);
2398 5 : }
2399 :
2400 :
2401 : void
2402 11 : Vehicle::setMinGapLat(const std::string& vehID, double minGapLat) {
2403 : try {
2404 22 : setParameter(vehID, "laneChangeModel.minGapLat", toString(minGapLat));
2405 6 : } catch (TraCIException&) {
2406 : // legacy behavior
2407 6 : Helper::getVehicle(vehID)->getSingularType().setMinGapLat(minGapLat);
2408 6 : }
2409 11 : }
2410 :
2411 :
2412 : void
2413 4 : Vehicle::setMaxSpeedLat(const std::string& vehID, double speed) {
2414 4 : Helper::getVehicle(vehID)->getSingularType().setMaxSpeedLat(speed);
2415 4 : }
2416 :
2417 :
2418 : void
2419 4 : Vehicle::setLateralAlignment(const std::string& vehID, const std::string& latAlignment) {
2420 : double lao;
2421 : LatAlignmentDefinition lad;
2422 4 : if (SUMOVTypeParameter::parseLatAlignment(latAlignment, lao, lad)) {
2423 4 : Helper::getVehicle(vehID)->getSingularType().setPreferredLateralAlignment(lad, lao);
2424 : } else {
2425 0 : throw TraCIException("Unknown value '" + latAlignment + "' when setting latAlignment for vehID '" + vehID + "';\n must be one of (\"right\", \"center\", \"arbitrary\", \"nice\", \"compact\", \"left\" or a float)");
2426 : }
2427 4 : }
2428 :
2429 :
2430 : void
2431 627 : Vehicle::setParameter(const std::string& vehID, const std::string& key, const std::string& value) {
2432 627 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
2433 626 : MSVehicle* microVeh = dynamic_cast<MSVehicle*>(veh);
2434 1252 : if (StringUtils::startsWith(key, "device.")) {
2435 1086 : StringTokenizer tok(key, ".");
2436 362 : if (tok.size() < 3) {
2437 0 : throw TraCIException("Invalid device parameter '" + key + "' for vehicle '" + vehID + "'");
2438 : }
2439 : try {
2440 758 : veh->setDeviceParameter(tok.get(1), key.substr(tok.get(0).size() + tok.get(1).size() + 2), value);
2441 0 : } catch (InvalidArgument& e) {
2442 0 : throw TraCIException("Vehicle '" + vehID + "' does not support device parameter '" + key + "' (" + e.what() + ").");
2443 0 : }
2444 890 : } else if (StringUtils::startsWith(key, "laneChangeModel.")) {
2445 28 : if (microVeh == nullptr) {
2446 4 : throw TraCIException("Meso Vehicle '" + vehID + "' does not support laneChangeModel parameters.");
2447 : }
2448 26 : const std::string attrName = key.substr(16);
2449 : try {
2450 26 : microVeh->getLaneChangeModel().setParameter(attrName, value);
2451 5 : } catch (InvalidArgument& e) {
2452 10 : throw TraCIException("Vehicle '" + vehID + "' does not support laneChangeModel parameter '" + key + "' (" + e.what() + ").");
2453 5 : }
2454 472 : } else if (StringUtils::startsWith(key, "carFollowModel.")) {
2455 26 : if (microVeh == nullptr) {
2456 0 : throw TraCIException("Meso Vehicle '" + vehID + "' does not support carFollowModel parameters.");
2457 : }
2458 : try {
2459 26 : veh->setCarFollowModelParameter(key, value);
2460 6 : } catch (InvalidArgument& e) {
2461 12 : throw TraCIException("Vehicle '" + vehID + "' does not support carFollowModel parameter '" + key + "' (" + e.what() + ").");
2462 6 : }
2463 420 : } else if (StringUtils::startsWith(key, "junctionModel.")) {
2464 : try {
2465 : // use the whole key (including junctionModel prefix)
2466 12 : veh->setJunctionModelParameter(key, value);
2467 6 : } catch (InvalidArgument& e) {
2468 : // error message includes id since it is also used for xml input
2469 12 : throw TraCIException(e.what());
2470 6 : }
2471 208 : } else if (StringUtils::startsWith(key, "has.") && StringUtils::endsWith(key, ".device")) {
2472 30 : StringTokenizer tok(key, ".");
2473 10 : if (tok.size() != 3) {
2474 0 : throw TraCIException("Invalid request for device status change. Expected format is 'has.DEVICENAME.device'");
2475 : }
2476 10 : const std::string deviceName = tok.get(1);
2477 : bool create;
2478 : try {
2479 10 : create = StringUtils::toBool(value);
2480 0 : } catch (BoolFormatException&) {
2481 0 : throw TraCIException("Changing device status requires a 'true' or 'false'");
2482 0 : }
2483 10 : if (!create) {
2484 0 : throw TraCIException("Device removal is not supported for device of type '" + deviceName + "'");
2485 : }
2486 : try {
2487 10 : veh->createDevice(deviceName);
2488 0 : } catch (InvalidArgument& e) {
2489 0 : throw TraCIException("Cannot create vehicle device (" + std::string(e.what()) + ").");
2490 0 : }
2491 10 : } else {
2492 188 : ((SUMOVehicleParameter&)veh->getParameter()).setParameter(key, value);
2493 : }
2494 607 : }
2495 :
2496 :
2497 : void
2498 50 : Vehicle::highlight(const std::string& vehID, const TraCIColor& col, double size, const int alphaMax, const double duration, const int type) {
2499 : // NOTE: Code is duplicated in large parts in POI.cpp
2500 50 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
2501 :
2502 : // Center of the highlight circle
2503 50 : Position center = veh->getPosition();
2504 50 : const double l2 = veh->getLength() * 0.5;
2505 50 : center.sub(cos(veh->getAngle())*l2, sin(veh->getAngle())*l2);
2506 : // Size of the highlight circle
2507 50 : if (size <= 0) {
2508 50 : size = veh->getLength() * 0.7;
2509 : }
2510 : // Make polygon shape
2511 : const unsigned int nPoints = 34;
2512 50 : const PositionVector circlePV = GeomHelper::makeRing(size, size + 1., center, nPoints);
2513 50 : TraCIPositionVector circle = Helper::makeTraCIPositionVector(circlePV);
2514 :
2515 : #ifdef DEBUG_DYNAMIC_SHAPES
2516 : std::cout << SIMTIME << " Vehicle::highlight() for vehicle '" << vehID << "'\n"
2517 : << " circle: " << circlePV << std::endl;
2518 : #endif
2519 :
2520 : // Find a free polygon id
2521 50 : int i = 0;
2522 100 : std::string polyID = veh->getID() + "_hl" + toString(i);
2523 170 : while (Polygon::exists(polyID)) {
2524 20 : polyID = veh->getID() + "_hl" + toString(++i);
2525 : }
2526 : // Line width
2527 : double lw = 0.;
2528 : // Layer
2529 : double lyr = 0.;
2530 50 : if (MSNet::getInstance()->isGUINet()) {
2531 : lyr = GLO_VEHICLE + 0.01;
2532 19 : lyr += (type + 1) / 257.;
2533 : }
2534 : // Make Polygon
2535 100 : Polygon::addHighlightPolygon(vehID, type, polyID, circle, col, true, "highlight", (int)lyr, lw);
2536 :
2537 : // Animation time line
2538 : double maxAttack = 1.0; // maximal fade-in time
2539 : std::vector<double> timeSpan;
2540 50 : if (duration > 0.) {
2541 80 : timeSpan = {0, MIN2(maxAttack, duration / 3.), 2.*duration / 3., duration};
2542 : }
2543 : // Alpha time line
2544 : std::vector<double> alphaSpan;
2545 50 : if (alphaMax > 0.) {
2546 60 : alphaSpan = {0., (double) alphaMax, (double)(alphaMax) / 3., 0.};
2547 : }
2548 : // Attach dynamics
2549 50 : Polygon::addDynamics(polyID, vehID, timeSpan, alphaSpan, false, true);
2550 50 : }
2551 :
2552 : void
2553 285 : Vehicle::dispatchTaxi(const std::string& vehID, const std::vector<std::string>& reservations) {
2554 285 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
2555 285 : MSDevice_Taxi* taxi = static_cast<MSDevice_Taxi*>(veh->getDevice(typeid(MSDevice_Taxi)));
2556 : if (taxi == nullptr) {
2557 0 : throw TraCIException("Vehicle '" + vehID + "' is not a taxi");
2558 : }
2559 : MSDispatch* dispatcher = MSDevice_Taxi::getDispatchAlgorithm();
2560 285 : if (dispatcher == nullptr) {
2561 0 : throw TraCIException("Cannot dispatch taxi because no reservations have been made");
2562 : }
2563 285 : MSDispatch_TraCI* traciDispatcher = dynamic_cast<MSDispatch_TraCI*>(dispatcher);
2564 285 : if (traciDispatcher == nullptr) {
2565 0 : throw TraCIException("device.taxi.dispatch-algorithm 'traci' has not been loaded");
2566 : }
2567 285 : if (reservations.size() == 0) {
2568 0 : throw TraCIException("No reservations have been specified for vehicle '" + vehID + "'");
2569 : }
2570 : try {
2571 285 : traciDispatcher->interpretDispatch(taxi, reservations);
2572 5 : } catch (InvalidArgument& e) {
2573 10 : throw TraCIException("Could not interpret reservations for vehicle '" + vehID + "' (" + e.what() + ").");
2574 5 : }
2575 280 : }
2576 :
2577 31268 : LIBSUMO_SUBSCRIPTION_IMPLEMENTATION(Vehicle, VEHICLE)
2578 :
2579 :
2580 : void
2581 34 : Vehicle::subscribeLeader(const std::string& vehID, double dist, double begin, double end) {
2582 68 : subscribe(vehID, std::vector<int>({ libsumo::VAR_LEADER }), begin, end,
2583 102 : libsumo::TraCIResults({ {libsumo::VAR_LEADER, std::make_shared<libsumo::TraCIDouble>(dist)} }));
2584 34 : }
2585 :
2586 :
2587 : void
2588 86 : Vehicle::addSubscriptionFilterLanes(const std::vector<int>& lanes, bool noOpposite, double downstreamDist, double upstreamDist) {
2589 86 : Subscription* s = Helper::addSubscriptionFilter(SUBS_FILTER_LANES);
2590 86 : if (s != nullptr) {
2591 86 : s->filterLanes = lanes;
2592 : }
2593 86 : if (noOpposite) {
2594 2 : addSubscriptionFilterNoOpposite();
2595 : }
2596 86 : if (downstreamDist != INVALID_DOUBLE_VALUE) {
2597 4 : addSubscriptionFilterDownstreamDistance(downstreamDist);
2598 : }
2599 86 : if (upstreamDist != INVALID_DOUBLE_VALUE) {
2600 4 : addSubscriptionFilterUpstreamDistance(upstreamDist);
2601 : }
2602 86 : }
2603 :
2604 :
2605 : void
2606 28 : Vehicle::addSubscriptionFilterNoOpposite() {
2607 28 : Helper::addSubscriptionFilter(SUBS_FILTER_NOOPPOSITE);
2608 28 : }
2609 :
2610 :
2611 : void
2612 102 : Vehicle::addSubscriptionFilterDownstreamDistance(double dist) {
2613 102 : Subscription* s = Helper::addSubscriptionFilter(SUBS_FILTER_DOWNSTREAM_DIST);
2614 102 : if (s != nullptr) {
2615 102 : s->filterDownstreamDist = dist;
2616 : }
2617 102 : }
2618 :
2619 :
2620 : void
2621 86 : Vehicle::addSubscriptionFilterUpstreamDistance(double dist) {
2622 86 : Subscription* s = Helper::addSubscriptionFilter(SUBS_FILTER_UPSTREAM_DIST);
2623 86 : if (s != nullptr) {
2624 86 : s->filterUpstreamDist = dist;
2625 : }
2626 86 : }
2627 :
2628 :
2629 : void
2630 2 : Vehicle::addSubscriptionFilterCFManeuver(double downstreamDist, double upstreamDist) {
2631 2 : addSubscriptionFilterLeadFollow(std::vector<int>({0}));
2632 2 : if (downstreamDist != INVALID_DOUBLE_VALUE) {
2633 0 : addSubscriptionFilterDownstreamDistance(downstreamDist);
2634 : }
2635 2 : if (upstreamDist != INVALID_DOUBLE_VALUE) {
2636 0 : addSubscriptionFilterUpstreamDistance(upstreamDist);
2637 : }
2638 :
2639 2 : }
2640 :
2641 :
2642 : void
2643 8 : Vehicle::addSubscriptionFilterLCManeuver(int direction, bool noOpposite, double downstreamDist, double upstreamDist) {
2644 : std::vector<int> lanes;
2645 8 : if (direction == INVALID_INT_VALUE) {
2646 : // Using default: both directions
2647 4 : lanes = std::vector<int>({-1, 0, 1});
2648 6 : } else if (direction != -1 && direction != 1) {
2649 0 : WRITE_WARNINGF(TL("Ignoring lane change subscription filter with non-neighboring lane offset direction=%."), direction);
2650 : } else {
2651 12 : lanes = std::vector<int>({0, direction});
2652 : }
2653 8 : addSubscriptionFilterLeadFollow(lanes);
2654 8 : if (noOpposite) {
2655 0 : addSubscriptionFilterNoOpposite();
2656 : }
2657 8 : if (downstreamDist != INVALID_DOUBLE_VALUE) {
2658 0 : addSubscriptionFilterDownstreamDistance(downstreamDist);
2659 : }
2660 8 : if (upstreamDist != INVALID_DOUBLE_VALUE) {
2661 0 : addSubscriptionFilterUpstreamDistance(upstreamDist);
2662 : }
2663 8 : }
2664 :
2665 :
2666 : void
2667 10 : Vehicle::addSubscriptionFilterLeadFollow(const std::vector<int>& lanes) {
2668 10 : Helper::addSubscriptionFilter(SUBS_FILTER_LEAD_FOLLOW);
2669 10 : addSubscriptionFilterLanes(lanes);
2670 10 : }
2671 :
2672 :
2673 : void
2674 16 : Vehicle::addSubscriptionFilterTurn(double downstreamDist, double foeDistToJunction) {
2675 16 : Subscription* s = Helper::addSubscriptionFilter(SUBS_FILTER_TURN);
2676 16 : if (downstreamDist != INVALID_DOUBLE_VALUE) {
2677 16 : addSubscriptionFilterDownstreamDistance(downstreamDist);
2678 : }
2679 16 : if (foeDistToJunction != INVALID_DOUBLE_VALUE) {
2680 16 : s->filterFoeDistToJunction = foeDistToJunction;
2681 : }
2682 16 : }
2683 :
2684 :
2685 : void
2686 6 : Vehicle::addSubscriptionFilterVClass(const std::vector<std::string>& vClasses) {
2687 6 : Subscription* s = Helper::addSubscriptionFilter(SUBS_FILTER_VCLASS);
2688 6 : if (s != nullptr) {
2689 6 : s->filterVClasses = parseVehicleClasses(vClasses);
2690 : }
2691 6 : }
2692 :
2693 :
2694 : void
2695 6 : Vehicle::addSubscriptionFilterVType(const std::vector<std::string>& vTypes) {
2696 6 : Subscription* s = Helper::addSubscriptionFilter(SUBS_FILTER_VTYPE);
2697 6 : if (s != nullptr) {
2698 : s->filterVTypes.insert(vTypes.begin(), vTypes.end());
2699 : }
2700 6 : }
2701 :
2702 :
2703 : void
2704 16 : Vehicle::addSubscriptionFilterFieldOfVision(double openingAngle) {
2705 16 : Subscription* s = Helper::addSubscriptionFilter(SUBS_FILTER_FIELD_OF_VISION);
2706 16 : if (s != nullptr) {
2707 16 : s->filterFieldOfVisionOpeningAngle = openingAngle;
2708 : }
2709 16 : }
2710 :
2711 :
2712 : void
2713 15 : Vehicle::addSubscriptionFilterLateralDistance(double lateralDist, double downstreamDist, double upstreamDist) {
2714 15 : Subscription* s = Helper::addSubscriptionFilter(SUBS_FILTER_LATERAL_DIST);
2715 14 : if (s != nullptr) {
2716 14 : s->filterLateralDist = lateralDist;
2717 : }
2718 14 : if (downstreamDist != INVALID_DOUBLE_VALUE) {
2719 14 : addSubscriptionFilterDownstreamDistance(downstreamDist);
2720 : }
2721 14 : if (upstreamDist != INVALID_DOUBLE_VALUE) {
2722 14 : addSubscriptionFilterUpstreamDistance(upstreamDist);
2723 : }
2724 14 : }
2725 :
2726 :
2727 : void
2728 21199 : Vehicle::storeShape(const std::string& id, PositionVector& shape) {
2729 21199 : shape.push_back(Helper::getVehicle(id)->getPosition());
2730 21199 : }
2731 :
2732 :
2733 : std::shared_ptr<VariableWrapper>
2734 267 : Vehicle::makeWrapper() {
2735 267 : return std::make_shared<Helper::SubscriptionWrapper>(handleVariable, mySubscriptionResults, myContextSubscriptionResults);
2736 : }
2737 :
2738 :
2739 : bool
2740 18557625 : Vehicle::handleVariable(const std::string& objID, const int variable, VariableWrapper* wrapper, tcpip::Storage* paramData) {
2741 18557625 : switch (variable) {
2742 208769 : case TRACI_ID_LIST:
2743 208769 : return wrapper->wrapStringList(objID, variable, getIDList());
2744 106 : case ID_COUNT:
2745 106 : return wrapper->wrapInt(objID, variable, getIDCount());
2746 1424187 : case VAR_POSITION:
2747 1424187 : return wrapper->wrapPosition(objID, variable, getPosition(objID));
2748 1641 : case VAR_POSITION3D:
2749 1641 : return wrapper->wrapPosition(objID, variable, getPosition(objID, true));
2750 297 : case VAR_ANGLE:
2751 297 : return wrapper->wrapDouble(objID, variable, getAngle(objID));
2752 290160 : case VAR_SPEED:
2753 290160 : return wrapper->wrapDouble(objID, variable, getSpeed(objID));
2754 56 : case VAR_SPEED_LAT:
2755 56 : return wrapper->wrapDouble(objID, variable, getLateralSpeed(objID));
2756 8186601 : case VAR_ROAD_ID:
2757 16373202 : return wrapper->wrapString(objID, variable, getRoadID(objID));
2758 3095 : case VAR_SPEED_WITHOUT_TRACI:
2759 3095 : return wrapper->wrapDouble(objID, variable, getSpeedWithoutTraCI(objID));
2760 7 : case VAR_SLOPE:
2761 7 : return wrapper->wrapDouble(objID, variable, getSlope(objID));
2762 48544 : case VAR_LANE_ID:
2763 97076 : return wrapper->wrapString(objID, variable, getLaneID(objID));
2764 42824 : case VAR_LANE_INDEX:
2765 42824 : return wrapper->wrapInt(objID, variable, getLaneIndex(objID));
2766 352 : case VAR_TYPE:
2767 699 : return wrapper->wrapString(objID, variable, getTypeID(objID));
2768 89 : case VAR_ROUTE_ID:
2769 173 : return wrapper->wrapString(objID, variable, getRouteID(objID));
2770 55 : case VAR_DEPARTURE:
2771 55 : return wrapper->wrapDouble(objID, variable, getDeparture(objID));
2772 55 : case VAR_DEPART_DELAY:
2773 55 : return wrapper->wrapDouble(objID, variable, getDepartDelay(objID));
2774 3012 : case VAR_ROUTE_INDEX:
2775 3012 : return wrapper->wrapInt(objID, variable, getRouteIndex(objID));
2776 1128 : case VAR_COLOR:
2777 1128 : return wrapper->wrapColor(objID, variable, getColor(objID));
2778 8158280 : case VAR_LANEPOSITION:
2779 8158280 : return wrapper->wrapDouble(objID, variable, getLanePosition(objID));
2780 2756 : case VAR_LANEPOSITION_LAT:
2781 2756 : return wrapper->wrapDouble(objID, variable, getLateralLanePosition(objID));
2782 297 : case VAR_CO2EMISSION:
2783 297 : return wrapper->wrapDouble(objID, variable, getCO2Emission(objID));
2784 57 : case VAR_COEMISSION:
2785 57 : return wrapper->wrapDouble(objID, variable, getCOEmission(objID));
2786 57 : case VAR_HCEMISSION:
2787 57 : return wrapper->wrapDouble(objID, variable, getHCEmission(objID));
2788 57 : case VAR_PMXEMISSION:
2789 57 : return wrapper->wrapDouble(objID, variable, getPMxEmission(objID));
2790 57 : case VAR_NOXEMISSION:
2791 57 : return wrapper->wrapDouble(objID, variable, getNOxEmission(objID));
2792 57 : case VAR_FUELCONSUMPTION:
2793 57 : return wrapper->wrapDouble(objID, variable, getFuelConsumption(objID));
2794 57 : case VAR_NOISEEMISSION:
2795 57 : return wrapper->wrapDouble(objID, variable, getNoiseEmission(objID));
2796 115 : case VAR_ELECTRICITYCONSUMPTION:
2797 115 : return wrapper->wrapDouble(objID, variable, getElectricityConsumption(objID));
2798 509 : case VAR_PERSON_NUMBER:
2799 509 : return wrapper->wrapInt(objID, variable, getPersonNumber(objID));
2800 566 : case VAR_PERSON_CAPACITY:
2801 566 : return wrapper->wrapInt(objID, variable, getPersonCapacity(objID));
2802 55 : case VAR_BOARDING_DURATION:
2803 55 : return wrapper->wrapDouble(objID, variable, getBoardingDuration(objID));
2804 144 : case LAST_STEP_PERSON_ID_LIST:
2805 144 : return wrapper->wrapStringList(objID, variable, getPersonIDList(objID));
2806 177 : case VAR_WAITING_TIME:
2807 177 : return wrapper->wrapDouble(objID, variable, getWaitingTime(objID));
2808 83 : case VAR_ACCUMULATED_WAITING_TIME:
2809 83 : return wrapper->wrapDouble(objID, variable, getAccumulatedWaitingTime(objID));
2810 56 : case VAR_ROUTE_VALID:
2811 56 : return wrapper->wrapInt(objID, variable, isRouteValid(objID));
2812 3225 : case VAR_EDGES:
2813 3225 : return wrapper->wrapStringList(objID, variable, getRoute(objID));
2814 58 : case VAR_SIGNALS:
2815 58 : return wrapper->wrapInt(objID, variable, getSignals(objID));
2816 1079 : case VAR_STOPSTATE:
2817 1079 : return wrapper->wrapInt(objID, variable, getStopState(objID));
2818 488 : case VAR_DISTANCE:
2819 488 : return wrapper->wrapDouble(objID, variable, getDistance(objID));
2820 55 : case VAR_ALLOWED_SPEED:
2821 55 : return wrapper->wrapDouble(objID, variable, getAllowedSpeed(objID));
2822 150 : case VAR_SPEED_FACTOR:
2823 150 : return wrapper->wrapDouble(objID, variable, getSpeedFactor(objID));
2824 48 : case VAR_SPEEDSETMODE:
2825 48 : return wrapper->wrapInt(objID, variable, getSpeedMode(objID));
2826 231 : case VAR_LANECHANGE_MODE:
2827 231 : return wrapper->wrapInt(objID, variable, getLaneChangeMode(objID));
2828 201 : case VAR_ROUTING_MODE:
2829 201 : return wrapper->wrapInt(objID, variable, getRoutingMode(objID));
2830 56 : case VAR_LINE:
2831 112 : return wrapper->wrapString(objID, variable, getLine(objID));
2832 56 : case VAR_VIA:
2833 56 : return wrapper->wrapStringList(objID, variable, getVia(objID));
2834 3997 : case VAR_ACCELERATION:
2835 3997 : return wrapper->wrapDouble(objID, variable, getAcceleration(objID));
2836 55 : case VAR_LASTACTIONTIME:
2837 55 : return wrapper->wrapDouble(objID, variable, getLastActionTime(objID));
2838 2002 : case VAR_STOP_DELAY:
2839 2002 : return wrapper->wrapDouble(objID, variable, getStopDelay(objID));
2840 73 : case VAR_IMPATIENCE:
2841 73 : return wrapper->wrapDouble(objID, variable, getImpatience(objID));
2842 2001 : case VAR_STOP_ARRIVALDELAY:
2843 2001 : return wrapper->wrapDouble(objID, variable, getStopArrivalDelay(objID));
2844 55 : case VAR_TIMELOSS:
2845 55 : return wrapper->wrapDouble(objID, variable, getTimeLoss(objID));
2846 55 : case VAR_MINGAP_LAT:
2847 55 : return wrapper->wrapDouble(objID, variable, getMinGapLat(objID));
2848 41857 : case VAR_LEADER: {
2849 41857 : paramData->readUnsignedByte();
2850 41857 : const double dist = paramData->readDouble();
2851 83714 : return wrapper->wrapStringDoublePair(objID, variable, getLeader(objID, dist));
2852 : }
2853 235 : case VAR_FOLLOWER: {
2854 235 : paramData->readUnsignedByte();
2855 235 : const double dist = paramData->readDouble();
2856 466 : return wrapper->wrapStringDoublePair(objID, variable, getFollower(objID, dist));
2857 : }
2858 132 : case VAR_LOADED_LIST:
2859 132 : return wrapper->wrapStringList(objID, variable, getLoadedIDList());
2860 132 : case VAR_TELEPORTING_LIST:
2861 132 : return wrapper->wrapStringList(objID, variable, getTeleportingIDList());
2862 91923 : case libsumo::VAR_PARAMETER:
2863 91923 : paramData->readUnsignedByte();
2864 275269 : return wrapper->wrapString(objID, variable, getParameter(objID, paramData->readString()));
2865 25 : case libsumo::VAR_PARAMETER_WITH_KEY:
2866 25 : paramData->readUnsignedByte();
2867 25 : return wrapper->wrapStringPair(objID, variable, getParameterWithKey(objID, paramData->readString()));
2868 : case VAR_TAXI_FLEET:
2869 : // we cannot use the general fall through here because we do not have an object id
2870 : return false;
2871 27254 : default:
2872 54496 : return VehicleType::handleVariableWithID(objID, getTypeID(objID), variable, wrapper, paramData);
2873 : }
2874 : }
2875 :
2876 :
2877 : }
2878 :
2879 :
2880 : /****************************************************************************/
|