1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2012-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
10 /// @file Vehicle.cpp
11 /// @author Jakob Erdmann
12 /// @date 15.03.2017
13 /// @version $Id$
14 ///
15 // C++ Vehicle API
16 /****************************************************************************/
17
18 // ===========================================================================
19 // included modules
20 // ===========================================================================
21 #include <config.h>
22
23 #include <utils/geom/GeomHelper.h>
24 #include <utils/common/StringTokenizer.h>
25 #include <utils/common/StringUtils.h>
26 #include <utils/gui/globjects/GUIGlObjectTypes.h>
27 #include <utils/emissions/PollutantsInterface.h>
28 #include <utils/vehicle/SUMOVehicleParserHelper.h>
29 #include <microsim/traffic_lights/MSTrafficLightLogic.h>
30 #include <microsim/lcmodels/MSAbstractLaneChangeModel.h>
31 #include <microsim/devices/MSDevice.h>
32 #include <microsim/MSEdgeWeightsStorage.h>
33 #include <microsim/MSVehicle.h>
34 #include <microsim/MSVehicleControl.h>
35 #include <microsim/MSVehicleType.h>
36 #include <microsim/MSInsertionControl.h>
37 #include <microsim/MSNet.h>
38 #include <microsim/MSEdge.h>
39 #include <microsim/MSLane.h>
40 #include <microsim/MSParkingArea.h>
41 #include <libsumo/TraCIDefs.h>
42 #include <libsumo/TraCIConstants.h>
43 #include "Helper.h"
44 #include "Route.h"
45 #include "Polygon.h"
46 #include "Vehicle.h"
47
48
49 // ===========================================================================
50 // debug defines
51 // ===========================================================================
52 //#define DEBUG_NEIGHBORS
53 //#define DEBUG_DYNAMIC_SHAPES
54 #define DEBUG_COND (veh->isSelected())
55
56
57
58 namespace libsumo {
59 // ===========================================================================
60 // static member initializations
61 // ===========================================================================
62 SubscriptionResults Vehicle::mySubscriptionResults;
63 ContextSubscriptionResults Vehicle::myContextSubscriptionResults;
64
65
66 // ===========================================================================
67 // static member definitions
68 // ===========================================================================
69 MSVehicle*
getVehicle(const std::string & id)70 Vehicle::getVehicle(const std::string& id) {
71 SUMOVehicle* sumoVehicle = MSNet::getInstance()->getVehicleControl().getVehicle(id);
72 if (sumoVehicle == nullptr) {
73 throw TraCIException("Vehicle '" + id + "' is not known");
74 }
75 MSVehicle* v = dynamic_cast<MSVehicle*>(sumoVehicle);
76 if (v == nullptr) {
77 throw TraCIException("Vehicle '" + id + "' is not a micro-simulation vehicle");
78 }
79 return v;
80 }
81
82
83 bool
isVisible(const SUMOVehicle * veh)84 Vehicle::isVisible(const SUMOVehicle* veh) {
85 return veh->isOnRoad() || veh->isParking() || veh->wasRemoteControlled();
86 }
87
88
89 bool
isOnInit(const std::string & vehicleID)90 Vehicle::isOnInit(const std::string& vehicleID) {
91 SUMOVehicle* sumoVehicle = MSNet::getInstance()->getVehicleControl().getVehicle(vehicleID);
92 return sumoVehicle == nullptr || sumoVehicle->getLane() == nullptr;
93 }
94
95 std::vector<std::string>
getIDList()96 Vehicle::getIDList() {
97 std::vector<std::string> ids;
98 MSVehicleControl& c = MSNet::getInstance()->getVehicleControl();
99 for (MSVehicleControl::constVehIt i = c.loadedVehBegin(); i != c.loadedVehEnd(); ++i) {
100 if (isVisible((*i).second)) {
101 ids.push_back((*i).first);
102 }
103 }
104 return ids;
105 }
106
107 int
getIDCount()108 Vehicle::getIDCount() {
109 return (int)getIDList().size();
110 }
111
112
113 double
getSpeed(const std::string & vehicleID)114 Vehicle::getSpeed(const std::string& vehicleID) {
115 MSVehicle* veh = getVehicle(vehicleID);
116 return isVisible(veh) ? veh->getSpeed() : INVALID_DOUBLE_VALUE;
117 }
118
119
120 double
getAcceleration(const std::string & vehicleID)121 Vehicle::getAcceleration(const std::string& vehicleID) {
122 MSVehicle* veh = getVehicle(vehicleID);
123 return isVisible(veh) ? veh->getAcceleration() : INVALID_DOUBLE_VALUE;
124 }
125
126
127 double
getSpeedWithoutTraCI(const std::string & vehicleID)128 Vehicle::getSpeedWithoutTraCI(const std::string& vehicleID) {
129 MSVehicle* veh = getVehicle(vehicleID);
130 return isVisible(veh) ? veh->getSpeedWithoutTraciInfluence() : INVALID_DOUBLE_VALUE;
131 }
132
133
134 TraCIPosition
getPosition(const std::string & vehicleID,const bool includeZ)135 Vehicle::getPosition(const std::string& vehicleID, const bool includeZ) {
136 MSVehicle* veh = getVehicle(vehicleID);
137 if (isVisible(veh)) {
138 return Helper::makeTraCIPosition(veh->getPosition(), includeZ);
139 }
140 return TraCIPosition();
141 }
142
143
144 TraCIPosition
getPosition3D(const std::string & vehicleID)145 Vehicle::getPosition3D(const std::string& vehicleID) {
146 return getPosition(vehicleID, true);
147 }
148
149
150 double
getAngle(const std::string & vehicleID)151 Vehicle::getAngle(const std::string& vehicleID) {
152 MSVehicle* veh = getVehicle(vehicleID);
153 return isVisible(veh) ? GeomHelper::naviDegree(veh->getAngle()) : INVALID_DOUBLE_VALUE;
154 }
155
156
157 double
getSlope(const std::string & vehicleID)158 Vehicle::getSlope(const std::string& vehicleID) {
159 MSVehicle* veh = getVehicle(vehicleID);
160 return veh->isOnRoad() ? veh->getSlope() : INVALID_DOUBLE_VALUE;
161 }
162
163
164 std::string
getRoadID(const std::string & vehicleID)165 Vehicle::getRoadID(const std::string& vehicleID) {
166 MSVehicle* veh = getVehicle(vehicleID);
167 return isVisible(veh) ? veh->getLane()->getEdge().getID() : "";
168 }
169
170
171 std::string
getLaneID(const std::string & vehicleID)172 Vehicle::getLaneID(const std::string& vehicleID) {
173 MSVehicle* veh = getVehicle(vehicleID);
174 return veh->isOnRoad() ? veh->getLane()->getID() : "";
175 }
176
177
178 int
getLaneIndex(const std::string & vehicleID)179 Vehicle::getLaneIndex(const std::string& vehicleID) {
180 MSVehicle* veh = getVehicle(vehicleID);
181 return veh->isOnRoad() ? veh->getLane()->getIndex() : INVALID_INT_VALUE;
182 }
183
184
185 std::string
getTypeID(const std::string & vehicleID)186 Vehicle::getTypeID(const std::string& vehicleID) {
187 return getVehicle(vehicleID)->getVehicleType().getID();
188 }
189
190
191 std::string
getRouteID(const std::string & vehicleID)192 Vehicle::getRouteID(const std::string& vehicleID) {
193 return getVehicle(vehicleID)->getRoute().getID();
194 }
195
196
197 int
getRouteIndex(const std::string & vehicleID)198 Vehicle::getRouteIndex(const std::string& vehicleID) {
199 MSVehicle* veh = getVehicle(vehicleID);
200 return veh->hasDeparted() ? veh->getRoutePosition() : INVALID_INT_VALUE;
201 }
202
203
204 TraCIColor
getColor(const std::string & vehicleID)205 Vehicle::getColor(const std::string& vehicleID) {
206 return Helper::makeTraCIColor(getVehicle(vehicleID)->getParameter().color);
207 }
208
209 double
getLanePosition(const std::string & vehicleID)210 Vehicle::getLanePosition(const std::string& vehicleID) {
211 MSVehicle* veh = getVehicle(vehicleID);
212 return veh->isOnRoad() ? veh->getPositionOnLane() : INVALID_DOUBLE_VALUE;
213 }
214
215 double
getLateralLanePosition(const std::string & vehicleID)216 Vehicle::getLateralLanePosition(const std::string& vehicleID) {
217 MSVehicle* veh = getVehicle(vehicleID);
218 return veh->isOnRoad() ? veh->getLateralPositionOnLane() : INVALID_DOUBLE_VALUE;
219 }
220
221 double
getCO2Emission(const std::string & vehicleID)222 Vehicle::getCO2Emission(const std::string& vehicleID) {
223 MSVehicle* veh = getVehicle(vehicleID);
224 return isVisible(veh) ? veh->getCO2Emissions() : INVALID_DOUBLE_VALUE;
225 }
226
227 double
getCOEmission(const std::string & vehicleID)228 Vehicle::getCOEmission(const std::string& vehicleID) {
229 MSVehicle* veh = getVehicle(vehicleID);
230 return isVisible(veh) ? veh->getCOEmissions() : INVALID_DOUBLE_VALUE;
231 }
232
233 double
getHCEmission(const std::string & vehicleID)234 Vehicle::getHCEmission(const std::string& vehicleID) {
235 MSVehicle* veh = getVehicle(vehicleID);
236 return isVisible(veh) ? veh->getHCEmissions() : INVALID_DOUBLE_VALUE;
237 }
238
239 double
getPMxEmission(const std::string & vehicleID)240 Vehicle::getPMxEmission(const std::string& vehicleID) {
241 MSVehicle* veh = getVehicle(vehicleID);
242 return isVisible(veh) ? veh->getPMxEmissions() : INVALID_DOUBLE_VALUE;
243 }
244
245 double
getNOxEmission(const std::string & vehicleID)246 Vehicle::getNOxEmission(const std::string& vehicleID) {
247 MSVehicle* veh = getVehicle(vehicleID);
248 return isVisible(veh) ? veh->getNOxEmissions() : INVALID_DOUBLE_VALUE;
249 }
250
251 double
getFuelConsumption(const std::string & vehicleID)252 Vehicle::getFuelConsumption(const std::string& vehicleID) {
253 MSVehicle* veh = getVehicle(vehicleID);
254 return isVisible(veh) ? veh->getFuelConsumption() : INVALID_DOUBLE_VALUE;
255 }
256
257 double
getNoiseEmission(const std::string & vehicleID)258 Vehicle::getNoiseEmission(const std::string& vehicleID) {
259 MSVehicle* veh = getVehicle(vehicleID);
260 return isVisible(veh) ? veh->getHarmonoise_NoiseEmissions() : INVALID_DOUBLE_VALUE;
261 }
262
263 double
getElectricityConsumption(const std::string & vehicleID)264 Vehicle::getElectricityConsumption(const std::string& vehicleID) {
265 MSVehicle* veh = getVehicle(vehicleID);
266 return isVisible(veh) ? veh->getElectricityConsumption() : INVALID_DOUBLE_VALUE;
267 }
268
269 int
getPersonNumber(const std::string & vehicleID)270 Vehicle::getPersonNumber(const std::string& vehicleID) {
271 return getVehicle(vehicleID)->getPersonNumber();
272 }
273
274 std::vector<std::string>
getPersonIDList(const std::string & vehicleID)275 Vehicle::getPersonIDList(const std::string& vehicleID) {
276 return getVehicle(vehicleID)->getPersonIDList();
277 }
278
279 std::pair<std::string, double>
getLeader(const std::string & vehicleID,double dist)280 Vehicle::getLeader(const std::string& vehicleID, double dist) {
281 MSVehicle* veh = getVehicle(vehicleID);
282 if (veh->isOnRoad()) {
283 std::pair<const MSVehicle* const, double> leaderInfo = veh->getLeader(dist);
284 return std::make_pair(
285 leaderInfo.first != nullptr ? leaderInfo.first->getID() : "",
286 leaderInfo.second);
287 } else {
288 return std::make_pair("", -1);
289 }
290 }
291
292
293 double
getWaitingTime(const std::string & vehicleID)294 Vehicle::getWaitingTime(const std::string& vehicleID) {
295 return getVehicle(vehicleID)->getWaitingSeconds();
296 }
297
298
299 double
getAccumulatedWaitingTime(const std::string & vehicleID)300 Vehicle::getAccumulatedWaitingTime(const std::string& vehicleID) {
301 return getVehicle(vehicleID)->getAccumulatedWaitingSeconds();
302 }
303
304
305 double
getAdaptedTraveltime(const std::string & vehicleID,double time,const std::string & edgeID)306 Vehicle::getAdaptedTraveltime(const std::string& vehicleID, double time, const std::string& edgeID) {
307 MSEdge* edge = Helper::getEdge(edgeID);
308 double value = INVALID_DOUBLE_VALUE;
309 getVehicle(vehicleID)->getWeightsStorage().retrieveExistingTravelTime(edge, time, value);
310 return value;
311 }
312
313
314 double
getEffort(const std::string & vehicleID,double time,const std::string & edgeID)315 Vehicle::getEffort(const std::string& vehicleID, double time, const std::string& edgeID) {
316 MSEdge* edge = Helper::getEdge(edgeID);
317 double value = INVALID_DOUBLE_VALUE;
318 getVehicle(vehicleID)->getWeightsStorage().retrieveExistingEffort(edge, time, value);
319 return value;
320 }
321
322
323 bool
isRouteValid(const std::string & vehicleID)324 Vehicle::isRouteValid(const std::string& vehicleID) {
325 std::string msg;
326 return getVehicle(vehicleID)->hasValidRoute(msg);
327 }
328
329
330 std::vector<std::string>
getRoute(const std::string & vehicleID)331 Vehicle::getRoute(const std::string& vehicleID) {
332 std::vector<std::string> result;
333 MSVehicle* veh = getVehicle(vehicleID);
334 const MSRoute& r = veh->getRoute();
335 for (MSRouteIterator i = r.begin(); i != r.end(); ++i) {
336 result.push_back((*i)->getID());
337 }
338 return result;
339 }
340
341
342 int
getSignals(const std::string & vehicleID)343 Vehicle::getSignals(const std::string& vehicleID) {
344 return getVehicle(vehicleID)->getSignals();
345 }
346
347
348 std::vector<TraCIBestLanesData>
getBestLanes(const std::string & vehicleID)349 Vehicle::getBestLanes(const std::string& vehicleID) {
350 std::vector<TraCIBestLanesData> result;
351 MSVehicle* veh = getVehicle(vehicleID);
352 if (veh->isOnRoad()) {
353 const std::vector<MSVehicle::LaneQ>& bestLanes = veh->getBestLanes();
354 for (std::vector<MSVehicle::LaneQ>::const_iterator i = bestLanes.begin(); i != bestLanes.end(); ++i) {
355 TraCIBestLanesData bld;
356 const MSVehicle::LaneQ& lq = *i;
357 bld.laneID = lq.lane->getID();
358 bld.length = lq.length;
359 bld.occupation = lq.nextOccupation;
360 bld.bestLaneOffset = lq.bestLaneOffset;
361 bld.allowsContinuation = lq.allowsContinuation;
362 for (std::vector<MSLane*>::const_iterator j = lq.bestContinuations.begin(); j != lq.bestContinuations.end(); ++j) {
363 if ((*j) != nullptr) {
364 bld.continuationLanes.push_back((*j)->getID());
365 }
366 }
367 result.push_back(bld);
368 }
369 }
370 return result;
371 }
372
373
374 std::vector<TraCINextTLSData>
getNextTLS(const std::string & vehicleID)375 Vehicle::getNextTLS(const std::string& vehicleID) {
376 std::vector<TraCINextTLSData> result;
377 MSVehicle* veh = getVehicle(vehicleID);
378 if (veh->isOnRoad()) {
379 const MSLane* lane = veh->getLane();
380 const std::vector<MSLane*>& bestLaneConts = veh->getBestLanesContinuation(lane);
381 double seen = veh->getLane()->getLength() - veh->getPositionOnLane();
382 int view = 1;
383 MSLinkCont::const_iterator link = MSLane::succLinkSec(*veh, view, *lane, bestLaneConts);
384 while (!lane->isLinkEnd(link)) {
385 if (!lane->getEdge().isInternal()) {
386 if ((*link)->isTLSControlled()) {
387 TraCINextTLSData ntd;
388 ntd.id = (*link)->getTLLogic()->getID();
389 ntd.tlIndex = (*link)->getTLIndex();
390 ntd.dist = seen;
391 ntd.state = (char)(*link)->getState();
392 result.push_back(ntd);
393 }
394 }
395 lane = (*link)->getViaLaneOrLane();
396 if (!lane->getEdge().isInternal()) {
397 view++;
398 }
399 seen += lane->getLength();
400 link = MSLane::succLinkSec(*veh, view, *lane, bestLaneConts);
401 }
402 // consider edges beyond bestLanes
403 const int remainingEdges = (int)(veh->getRoute().end() - veh->getCurrentRouteEdge()) - view;
404 //std::cout << "remainingEdges=" << remainingEdges << " view=" << view << " best=" << toString(bestLaneConts) << "\n";
405 for (int i = 0; i < remainingEdges; i++) {
406 const MSEdge* prev = *(veh->getCurrentRouteEdge() + view + i - 1);
407 const MSEdge* next = *(veh->getCurrentRouteEdge() + view + i);
408 const std::vector<MSLane*>* allowed = prev->allowedLanes(*next, veh->getVClass());
409 if (allowed != nullptr && allowed->size() != 0) {
410 for (MSLink* link : allowed->front()->getLinkCont()) {
411 if (&link->getLane()->getEdge() == next && link->isTLSControlled()) {
412 TraCINextTLSData ntd;
413 ntd.id = link->getTLLogic()->getID();
414 ntd.tlIndex = link->getTLIndex();
415 ntd.dist = seen;
416 ntd.state = (char)link->getState();
417 result.push_back(ntd);
418 }
419 }
420 } else {
421 // invalid route, cannot determine nextTLS
422 break;
423 }
424 }
425 }
426 return result;
427 }
428
429
430 std::vector<TraCINextStopData>
getNextStops(const std::string & vehicleID)431 Vehicle::getNextStops(const std::string& vehicleID) {
432 std::vector<TraCINextStopData> result;
433 MSVehicle* veh = getVehicle(vehicleID);
434 std::list<MSVehicle::Stop> stops = veh->getMyStops();
435 for (std::list<MSVehicle::Stop>::iterator it = stops.begin(); it != stops.end(); ++it) {
436 if (!it->reached && !it->collision) {
437 TraCINextStopData nsd;
438 nsd.lane = it->lane->getID();
439 nsd.endPos = it->getEndPos(*veh);
440 // all optionals, only one can be set
441 if (it->busstop != nullptr) {
442 nsd.stoppingPlaceID = it->busstop->getID();
443 }
444 if (it->containerstop != nullptr) {
445 nsd.stoppingPlaceID = it->containerstop->getID();
446 }
447 if (it->parkingarea != nullptr) {
448 nsd.stoppingPlaceID = it->parkingarea->getID();
449 }
450 if (it->chargingStation != nullptr) {
451 nsd.stoppingPlaceID = it->chargingStation->getID();
452 }
453 nsd.stopFlags = ((it->reached ? 1 : 0) +
454 (it->pars.parking ? 2 : 0) +
455 (it->pars.triggered ? 4 : 0) +
456 (it->pars.containerTriggered ? 8 : 0) +
457 (it->busstop != nullptr ? 16 : 0) +
458 (it->containerstop != nullptr ? 32 : 0) +
459 (it->chargingStation != nullptr ? 64 : 0) +
460 (it->parkingarea != nullptr ? 128 : 0));
461 nsd.duration = STEPS2TIME(it->pars.duration);
462 nsd.until = STEPS2TIME(it->pars.until);
463 result.push_back(nsd);
464 }
465 }
466 return result;
467 }
468
469
470 int
getStopState(const std::string & vehicleID)471 Vehicle::getStopState(const std::string& vehicleID) {
472 MSVehicle* veh = getVehicle(vehicleID);
473 int result = 0;
474 if (veh->isStopped()) {
475 const MSVehicle::Stop& stop = veh->getNextStop();
476 result = ((stop.reached ? 1 : 0) +
477 (stop.pars.parking ? 2 : 0) +
478 (stop.pars.triggered ? 4 : 0) +
479 (stop.pars.containerTriggered ? 8 : 0) +
480 (stop.busstop != nullptr ? 16 : 0) +
481 (stop.containerstop != nullptr ? 32 : 0) +
482 (stop.chargingStation != nullptr ? 64 : 0) +
483 (stop.parkingarea != nullptr ? 128 : 0));
484 }
485 return result;
486 }
487
488 double
getDistance(const std::string & vehicleID)489 Vehicle::getDistance(const std::string& vehicleID) {
490 MSVehicle* veh = getVehicle(vehicleID);
491 if (veh->isOnRoad()) {
492 double distance;
493 if (veh->getLane()->isInternal()) {
494 // route edge still points to the edge before the intersection
495 const double normalEnd = (*veh->getCurrentRouteEdge())->getLength();
496 distance = (veh->getRoute().getDistanceBetween(veh->getDepartPos(), normalEnd,
497 veh->getRoute().begin(), veh->getCurrentRouteEdge())
498 + veh->getRoute().getDistanceBetween(normalEnd, veh->getPositionOnLane(),
499 *veh->getCurrentRouteEdge(), &veh->getLane()->getEdge()));
500 } else {
501 distance = veh->getRoute().getDistanceBetween(veh->getDepartPos(), veh->getPositionOnLane(),
502 veh->getRoute().begin(), veh->getCurrentRouteEdge());
503 }
504 if (distance == std::numeric_limits<double>::max()) {
505 return INVALID_DOUBLE_VALUE;
506 } else {
507 return distance;
508 }
509 } else {
510 return INVALID_DOUBLE_VALUE;
511 }
512 }
513
514
515 double
getDrivingDistance(const std::string & vehicleID,const std::string & edgeID,double position,int)516 Vehicle::getDrivingDistance(const std::string& vehicleID, const std::string& edgeID, double position, int /* laneIndex */) {
517 MSVehicle* veh = getVehicle(vehicleID);
518 if (veh->isOnRoad()) {
519 double distance = veh->getRoute().getDistanceBetween(veh->getPositionOnLane(), position,
520 &veh->getLane()->getEdge(), Helper::getEdge(edgeID), true, veh->getRoutePosition());
521 if (distance == std::numeric_limits<double>::max()) {
522 return INVALID_DOUBLE_VALUE;
523 }
524 return distance;
525 } else {
526 return INVALID_DOUBLE_VALUE;
527 }
528 }
529
530
531 double
getDrivingDistance2D(const std::string & vehicleID,double x,double y)532 Vehicle::getDrivingDistance2D(const std::string& vehicleID, double x, double y) {
533 MSVehicle* veh = getVehicle(vehicleID);
534 if (veh->isOnRoad()) {
535 std::pair<MSLane*, double> roadPos = Helper::convertCartesianToRoadMap(Position(x, y), veh->getVehicleType().getVehicleClass());
536 double distance = veh->getRoute().getDistanceBetween(veh->getPositionOnLane(), roadPos.second,
537 veh->getEdge(), &roadPos.first->getEdge(), true, veh->getRoutePosition());
538 if (distance == std::numeric_limits<double>::max()) {
539 return INVALID_DOUBLE_VALUE;
540 }
541 return distance;
542 } else {
543 return INVALID_DOUBLE_VALUE;
544 }
545 }
546
547
548
549 double
getAllowedSpeed(const std::string & vehicleID)550 Vehicle::getAllowedSpeed(const std::string& vehicleID) {
551 MSVehicle* veh = getVehicle(vehicleID);
552 if (veh->isOnRoad()) {
553 return veh->getLane()->getVehicleMaxSpeed(veh);
554 } else {
555 return INVALID_DOUBLE_VALUE;
556 }
557 }
558
559
560 double
getSpeedFactor(const std::string & vehicleID)561 Vehicle::getSpeedFactor(const std::string& vehicleID) {
562 return getVehicle(vehicleID)->getChosenSpeedFactor();
563 }
564
565
566 int
getSpeedMode(const std::string & vehicleID)567 Vehicle::getSpeedMode(const std::string& vehicleID) {
568 return getVehicle(vehicleID)->getInfluencer().getSpeedMode();
569 }
570
571 int
getLaneChangeMode(const std::string & vehicleID)572 Vehicle::getLaneChangeMode(const std::string& vehicleID) {
573 return getVehicle(vehicleID)->getInfluencer().getLaneChangeMode();
574 }
575
576 int
getRoutingMode(const std::string & vehicleID)577 Vehicle::getRoutingMode(const std::string& vehicleID) {
578 return getVehicle(vehicleID)->getInfluencer().getRoutingMode();
579 }
580
581 std::string
getLine(const std::string & vehicleID)582 Vehicle::getLine(const std::string& vehicleID) {
583 return getVehicle(vehicleID)->getParameter().line;
584 }
585
586 std::vector<std::string>
getVia(const std::string & vehicleID)587 Vehicle::getVia(const std::string& vehicleID) {
588 return getVehicle(vehicleID)->getParameter().via;
589 }
590
591
592 std::pair<int, int>
getLaneChangeState(const std::string & vehicleID,int direction)593 Vehicle::getLaneChangeState(const std::string& vehicleID, int direction) {
594 MSVehicle* veh = getVehicle(vehicleID);
595 if (veh->isOnRoad()) {
596 return veh->getLaneChangeModel().getSavedState(direction);
597 } else {
598 return std::make_pair((int)LCA_UNKNOWN, (int)LCA_UNKNOWN);
599 }
600 }
601
602
603 std::string
getParameter(const std::string & vehicleID,const std::string & key)604 Vehicle::getParameter(const std::string& vehicleID, const std::string& key) {
605 MSVehicle* veh = getVehicle(vehicleID);
606 if (StringUtils::startsWith(key, "device.")) {
607 StringTokenizer tok(key, ".");
608 if (tok.size() < 3) {
609 throw TraCIException("Invalid device parameter '" + key + "' for vehicle '" + vehicleID + "'");
610 }
611 try {
612 return veh->getDeviceParameter(tok.get(1), key.substr(tok.get(0).size() + tok.get(1).size() + 2));
613 } catch (InvalidArgument& e) {
614 throw TraCIException("Vehicle '" + vehicleID + "' does not support device parameter '" + key + "' (" + e.what() + ").");
615 }
616 } else if (StringUtils::startsWith(key, "laneChangeModel.")) {
617 const std::string attrName = key.substr(16);
618 try {
619 return veh->getLaneChangeModel().getParameter(attrName);
620 } catch (InvalidArgument& e) {
621 throw TraCIException("Vehicle '" + vehicleID + "' does not support laneChangeModel parameter '" + key + "' (" + e.what() + ").");
622 }
623 } else if (StringUtils::startsWith(key, "carFollowModel.")) {
624 const std::string attrName = key.substr(15);
625 try {
626 return veh->getCarFollowModel().getParameter(veh, attrName);
627 } catch (InvalidArgument& e) {
628 throw TraCIException("Vehicle '" + vehicleID + "' does not support carFollowModel parameter '" + key + "' (" + e.what() + ").");
629 }
630 } else if (StringUtils::startsWith(key, "has.") && StringUtils::endsWith(key, ".device")) {
631 StringTokenizer tok(key, ".");
632 if (tok.size() != 3) {
633 throw TraCIException("Invalid check for device. Expected format is 'has.DEVICENAME.device'");
634 }
635 return veh->hasDevice(tok.get(1)) ? "true" : "false";
636 } else {
637 return veh->getParameter().getParameter(key, "");
638 }
639 }
640
641
642 std::map<const MSVehicle*, double>
getNeighbors(const std::string & vehicleID,const int mode)643 Vehicle::getNeighbors(const std::string& vehicleID, const int mode) {
644 int dir = (1 & mode) != 0 ? -1 : 1;
645 bool queryLeaders = (2 & mode) != 0;
646 bool blockersOnly = (4 & mode) != 0;
647
648 MSVehicle* veh = getVehicle(vehicleID);
649 std::map<const MSVehicle*, double> neighs;
650 auto& lcm = veh->getLaneChangeModel();
651
652 #ifdef DEBUG_NEIGHBORS
653 if DEBUG_COND {
654 std::cout << "getNeighbors() for veh '" << vehicleID << "': dir=" << dir
655 << ", queryLeaders=" << queryLeaders
656 << ", blockersOnly=" << blockersOnly << std::endl;
657 }
658 #endif
659
660
661
662 if (blockersOnly) {
663 // Check if a blocking neigh exists in the given direction
664 bool blocked = false;
665 if (dir == -1) {
666 if (queryLeaders) {
667 blocked = (lcm.getOwnState() & LCA_BLOCKED_BY_RIGHT_LEADER) != 0;
668 } else {
669 blocked = (lcm.getOwnState() & LCA_BLOCKED_BY_RIGHT_FOLLOWER) != 0;
670 }
671 } else {
672 if (queryLeaders) {
673 blocked = (lcm.getOwnState() & LCA_BLOCKED_BY_LEFT_LEADER) != 0;
674 } else {
675 blocked = (lcm.getOwnState() & LCA_BLOCKED_BY_LEFT_FOLLOWER) != 0;
676 }
677 }
678
679 #ifdef DEBUG_NEIGHBORS
680 if DEBUG_COND {
681 std::cout << " blocked=" << blocked << std::endl;
682 }
683 #endif
684
685 if (!blocked) {
686 // Not blocked => return empty vector
687 return neighs;
688 }
689 }
690
691 const std::shared_ptr<MSLeaderDistanceInfo> res = queryLeaders ? lcm.getLeaders(dir) : lcm.getFollowers(dir);
692 if (res != nullptr && res->hasVehicles()) {
693 auto distIt = begin(res->getDistances());
694 auto vehIt = begin(res->getVehicles());
695 while (distIt != end(res->getDistances())) {
696 if (*vehIt != nullptr) {
697 neighs[*vehIt] = *distIt;
698 }
699 ++vehIt;
700 ++distIt;
701 }
702 }
703 return neighs;
704 }
705
706
707 std::map<const MSVehicle*, double>
708 Vehicle::getRightFollowers(const std::string& vehicleID, bool blockingOnly) {
709 if (blockingOnly) {
710 return getNeighbors(vehicleID, 5);
711 } else {
712 return getNeighbors(vehicleID, 1);
713 }
714 }
715
716
717 std::map<const MSVehicle*, double>
718 Vehicle::getRightLeaders(const std::string& vehicleID, bool blockingOnly) {
719 if (blockingOnly) {
720 return getNeighbors(vehicleID, 7);
721 } else {
722 return getNeighbors(vehicleID, 3);
723 }
724 }
725
726
727 std::map<const MSVehicle*, double>
728 Vehicle::getLeftFollowers(const std::string& vehicleID, bool blockingOnly) {
729 if (blockingOnly) {
730 return getNeighbors(vehicleID, 4);
731 } else {
732 return getNeighbors(vehicleID, 0);
733 }
734 }
735
736
737 std::map<const MSVehicle*, double>
738 Vehicle::getLeftLeaders(const std::string& vehicleID, bool blockingOnly) {
739 if (blockingOnly) {
740 return getNeighbors(vehicleID, 6);
741 } else {
742 return getNeighbors(vehicleID, 2);
743 }
744 }
745
746
747 const MSVehicleType&
748 Vehicle::getVehicleType(const std::string& vehicleID) {
749 return getVehicle(vehicleID)->getVehicleType();
750 }
751
752
753 std::string
754 Vehicle::getEmissionClass(const std::string& vehicleID) {
755 return PollutantsInterface::getName(getVehicleType(vehicleID).getEmissionClass());
756 }
757
758 std::string
759 Vehicle::getShapeClass(const std::string& vehicleID) {
760 return getVehicleShapeName(getVehicleType(vehicleID).getGuiShape());
761 }
762
763
764 double
765 Vehicle::getLength(const std::string& vehicleID) {
766 return getVehicleType(vehicleID).getLength();
767 }
768
769
770 double
771 Vehicle::getAccel(const std::string& vehicleID) {
772 return getVehicleType(vehicleID).getCarFollowModel().getMaxAccel();
773 }
774
775
776 double
777 Vehicle::getDecel(const std::string& vehicleID) {
778 return getVehicleType(vehicleID).getCarFollowModel().getMaxDecel();
779 }
780
781
782 double Vehicle::getEmergencyDecel(const std::string& vehicleID) {
783 return getVehicleType(vehicleID).getCarFollowModel().getEmergencyDecel();
784 }
785
786
787 double Vehicle::getApparentDecel(const std::string& vehicleID) {
788 return getVehicleType(vehicleID).getCarFollowModel().getApparentDecel();
789 }
790
791
792 double Vehicle::getActionStepLength(const std::string& vehicleID) {
793 return getVehicleType(vehicleID).getActionStepLengthSecs();
794 }
795
796
797 double Vehicle::getLastActionTime(const std::string& vehicleID) {
798 return STEPS2TIME(getVehicle(vehicleID)->getLastActionTime());
799 }
800
801
802 double
803 Vehicle::getTau(const std::string& vehicleID) {
804 return getVehicleType(vehicleID).getCarFollowModel().getHeadwayTime();
805 }
806
807
808 double
809 Vehicle::getImperfection(const std::string& vehicleID) {
810 return getVehicleType(vehicleID).getCarFollowModel().getImperfection();
811 }
812
813
814 double
815 Vehicle::getSpeedDeviation(const std::string& vehicleID) {
816 return getVehicleType(vehicleID).getSpeedFactor().getParameter()[1];
817 }
818
819
820 std::string
821 Vehicle::getVehicleClass(const std::string& vehicleID) {
822 return toString(getVehicleType(vehicleID).getVehicleClass());
823 }
824
825
826 double
827 Vehicle::getMinGap(const std::string& vehicleID) {
828 return getVehicleType(vehicleID).getMinGap();
829 }
830
831
832 double
833 Vehicle::getMinGapLat(const std::string& vehicleID) {
834 return getVehicleType(vehicleID).getMinGapLat();
835 }
836
837
838 double
839 Vehicle::getMaxSpeed(const std::string& vehicleID) {
840 return getVehicleType(vehicleID).getMaxSpeed();
841 }
842
843
844 double
845 Vehicle::getMaxSpeedLat(const std::string& vehicleID) {
846 return getVehicleType(vehicleID).getMaxSpeedLat();
847 }
848
849
850 std::string
851 Vehicle::getLateralAlignment(const std::string& vehicleID) {
852 return toString(getVehicleType(vehicleID).getPreferredLateralAlignment());
853 }
854
855
856 double
857 Vehicle::getWidth(const std::string& vehicleID) {
858 return getVehicleType(vehicleID).getWidth();
859 }
860
861
862 double
863 Vehicle::getHeight(const std::string& vehicleID) {
864 return getVehicleType(vehicleID).getHeight();
865 }
866
867
868 void
869 Vehicle::setStop(const std::string& vehicleID,
870 const std::string& edgeID,
871 double pos,
872 int laneIndex,
873 double duration,
874 int flags,
875 double startPos,
876 double until) {
877 MSVehicle* veh = getVehicle(vehicleID);
878 // optional stop flags
879 bool parking = false;
880 bool triggered = false;
881 bool containerTriggered = false;
882 SumoXMLTag stoppingPlaceType = SUMO_TAG_NOTHING;
883
884 parking = ((flags & 1) != 0);
885 triggered = ((flags & 2) != 0);
886 containerTriggered = ((flags & 4) != 0);
887 if ((flags & 8) != 0) {
888 stoppingPlaceType = SUMO_TAG_BUS_STOP;
889 }
890 if ((flags & 16) != 0) {
891 stoppingPlaceType = SUMO_TAG_CONTAINER_STOP;
892 }
893 if ((flags & 32) != 0) {
894 stoppingPlaceType = SUMO_TAG_CHARGING_STATION;
895 }
896 if ((flags & 64) != 0) {
897 stoppingPlaceType = SUMO_TAG_PARKING_AREA;
898 }
899 const SUMOTime durationSteps = duration == INVALID_DOUBLE_VALUE ? SUMOTime_MAX : TIME2STEPS(duration);
900 const SUMOTime untilStep = until == INVALID_DOUBLE_VALUE ? -1 : TIME2STEPS(until);
901
902 std::string error;
903 if (stoppingPlaceType != SUMO_TAG_NOTHING) {
904 // Forward command to vehicle
905 if (!veh->addTraciStopAtStoppingPlace(edgeID, durationSteps, untilStep, parking, triggered, containerTriggered, stoppingPlaceType, error)) {
906 throw TraCIException(error);
907 }
908 } else {
909 // check
910 if (startPos == INVALID_DOUBLE_VALUE) {
911 startPos = pos - POSITION_EPS;
912 }
913 if (startPos < 0.) {
914 throw TraCIException("Position on lane must not be negative.");
915 }
916 if (pos < startPos) {
917 throw TraCIException("End position on lane must be after start position.");
918 }
919 // get the actual lane that is referenced by laneIndex
920 MSEdge* road = MSEdge::dictionary(edgeID);
921 if (road == nullptr) {
922 throw TraCIException("Unable to retrieve road with given id.");
923 }
924 const std::vector<MSLane*>& allLanes = road->getLanes();
925 if ((laneIndex < 0) || laneIndex >= (int)(allLanes.size())) {
926 throw TraCIException("No lane with index '" + toString(laneIndex) + "' on road '" + edgeID + "'.");
927 }
928 // Forward command to vehicle
929 if (!veh->addTraciStop(allLanes[laneIndex], startPos, pos, durationSteps, untilStep, parking, triggered, containerTriggered, error)) {
930 throw TraCIException(error);
931 }
932 }
933 }
934
935 void
936 Vehicle::rerouteParkingArea(const std::string& vehicleID, const std::string& parkingAreaID) {
937 MSVehicle* veh = getVehicle(vehicleID);
938 std::string error;
939 // Forward command to vehicle
940 if (!veh->rerouteParkingArea(parkingAreaID, error)) {
941 throw TraCIException(error);
942 }
943 }
944
945 void
946 Vehicle::resume(const std::string& vehicleID) {
947 MSVehicle* veh = getVehicle(vehicleID);
948 if (!veh->hasStops()) {
949 throw TraCIException("Failed to resume vehicle '" + veh->getID() + "', it has no stops.");
950 }
951 if (!veh->resumeFromStopping()) {
952 MSVehicle::Stop& sto = veh->getNextStop();
953 std::ostringstream strs;
954 strs << "reached: " << sto.reached;
955 strs << ", duration:" << sto.duration;
956 strs << ", edge:" << (*sto.edge)->getID();
957 strs << ", startPos: " << sto.pars.startPos;
958 std::string posStr = strs.str();
959 throw TraCIException("Failed to resume from stoppingfor vehicle '" + veh->getID() + "', " + posStr);
960 }
961 }
962
963
964 void
965 Vehicle::changeTarget(const std::string& vehicleID, const std::string& edgeID) {
966 MSVehicle* veh = getVehicle(vehicleID);
967 const MSEdge* destEdge = MSEdge::dictionary(edgeID);
968 const bool onInit = isOnInit(vehicleID);
969 if (destEdge == nullptr) {
970 throw TraCIException("Can not retrieve road with ID " + edgeID);
971 }
972 // build a new route between the vehicle's current edge and destination edge
973 ConstMSEdgeVector newRoute;
974 const MSEdge* currentEdge = veh->getRerouteOrigin();
975 veh->getInfluencer().getRouterTT().compute(
976 currentEdge, destEdge, (const MSVehicle * const)veh, MSNet::getInstance()->getCurrentTimeStep(), newRoute);
977 // replace the vehicle's route by the new one (cost is updated by call to reroute())
978 if (!veh->replaceRouteEdges(newRoute, -1, 0, "traci:changeTarget", onInit)) {
979 throw TraCIException("Route replacement failed for " + veh->getID());
980 }
981 // route again to ensure usage of via/stops
982 try {
983 veh->reroute(MSNet::getInstance()->getCurrentTimeStep(), "traci:changeTarget", veh->getInfluencer().getRouterTT(), onInit);
984 } catch (ProcessError& e) {
985 throw TraCIException(e.what());
986 }
987 }
988
989
990 void
991 Vehicle::changeLane(const std::string& vehicleID, int laneIndex, double duration) {
992 std::vector<std::pair<SUMOTime, int> > laneTimeLine;
993 laneTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep(), laneIndex));
994 laneTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep() + TIME2STEPS(duration), laneIndex));
995 getVehicle(vehicleID)->getInfluencer().setLaneTimeLine(laneTimeLine);
996 }
997
998 void
999 Vehicle::changeLaneRelative(const std::string& vehicleID, int indexOffset, double duration) {
1000 std::vector<std::pair<SUMOTime, int> > laneTimeLine;
1001 int laneIndex = getVehicle(vehicleID)->getLaneIndex() + indexOffset;
1002 laneTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep(), laneIndex));
1003 laneTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep() + TIME2STEPS(duration), laneIndex));
1004 getVehicle(vehicleID)->getInfluencer().setLaneTimeLine(laneTimeLine);
1005 }
1006
1007
1008 void
1009 Vehicle::changeSublane(const std::string& vehicleID, double latDist) {
1010 getVehicle(vehicleID)->getInfluencer().setSublaneChange(latDist);
1011 }
1012
1013
1014 void
1015 Vehicle::add(const std::string& vehicleID,
1016 const std::string& routeID,
1017 const std::string& typeID,
1018 const std::string& depart,
1019 const std::string& departLane,
1020 const std::string& departPos,
1021 const std::string& departSpeed,
1022 const std::string& arrivalLane,
1023 const std::string& arrivalPos,
1024 const std::string& arrivalSpeed,
1025 const std::string& fromTaz,
1026 const std::string& toTaz,
1027 const std::string& line,
1028 int /*personCapacity*/,
1029 int personNumber) {
1030 SUMOVehicle* veh = MSNet::getInstance()->getVehicleControl().getVehicle(vehicleID);
1031 if (veh != nullptr) {
1032 throw TraCIException("The vehicle " + vehicleID + " to add already exists.");
1033 }
1034
1035 SUMOVehicleParameter vehicleParams;
1036 vehicleParams.id = vehicleID;
1037 MSVehicleType* vehicleType = MSNet::getInstance()->getVehicleControl().getVType(typeID);
1038 if (!vehicleType) {
1039 throw TraCIException("Invalid type '" + typeID + "' for vehicle '" + vehicleID + "'");
1040 }
1041 const MSRoute* route = MSRoute::dictionary(routeID);
1042 if (!route) {
1043 if (routeID == "") {
1044 // assume, route was intentionally left blank because the caller
1045 // intends to control the vehicle remotely
1046 SUMOVehicleClass vclass = vehicleType->getVehicleClass();
1047 const std::string dummyRouteID = "DUMMY_ROUTE_" + SumoVehicleClassStrings.getString(vclass);
1048 route = MSRoute::dictionary(dummyRouteID);
1049 if (route == nullptr) {
1050 for (MSEdge* e : MSEdge::getAllEdges()) {
1051 if (e->getFunction() == EDGEFUNC_NORMAL && (e->getPermissions() & vclass) == vclass) {
1052 std::vector<std::string> edges;
1053 edges.push_back(e->getID());
1054 libsumo::Route::add(dummyRouteID, edges);
1055 break;
1056 }
1057 }
1058 }
1059 route = MSRoute::dictionary(dummyRouteID);
1060 if (!route) {
1061 throw TraCIException("Could not build dummy route for vehicle class: '" + SumoVehicleClassStrings.getString(vehicleType->getVehicleClass()) + "'");
1062 }
1063 } else {
1064 throw TraCIException("Invalid route '" + routeID + "' for vehicle: '" + vehicleID + "'");
1065 }
1066 }
1067 // check if the route implies a trip
1068 if (route->getEdges().size() == 2) {
1069 const MSEdgeVector& succ = route->getEdges().front()->getSuccessors();
1070 if (std::find(succ.begin(), succ.end(), route->getEdges().back()) == succ.end()) {
1071 vehicleParams.parametersSet |= VEHPARS_FORCE_REROUTE;
1072 }
1073 }
1074 if (fromTaz != "" || toTaz != "") {
1075 vehicleParams.parametersSet |= VEHPARS_FORCE_REROUTE;
1076 }
1077 std::string error;
1078 if (!SUMOVehicleParameter::parseDepart(depart, "vehicle", vehicleID, vehicleParams.depart, vehicleParams.departProcedure, error)) {
1079 throw TraCIException(error);
1080 }
1081 if (vehicleParams.departProcedure == DEPART_GIVEN && vehicleParams.depart < MSNet::getInstance()->getCurrentTimeStep()) {
1082 vehicleParams.depart = MSNet::getInstance()->getCurrentTimeStep();
1083 WRITE_WARNING("Departure time for vehicle '" + vehicleID + "' is in the past; using current time instead.");
1084 } else if (vehicleParams.departProcedure == DEPART_NOW) {
1085 vehicleParams.depart = MSNet::getInstance()->getCurrentTimeStep();
1086 }
1087 if (!SUMOVehicleParameter::parseDepartLane(departLane, "vehicle", vehicleID, vehicleParams.departLane, vehicleParams.departLaneProcedure, error)) {
1088 throw TraCIException(error);
1089 }
1090 if (!SUMOVehicleParameter::parseDepartPos(departPos, "vehicle", vehicleID, vehicleParams.departPos, vehicleParams.departPosProcedure, error)) {
1091 throw TraCIException(error);
1092 }
1093 if (!SUMOVehicleParameter::parseDepartSpeed(departSpeed, "vehicle", vehicleID, vehicleParams.departSpeed, vehicleParams.departSpeedProcedure, error)) {
1094 throw TraCIException(error);
1095 }
1096 if (!SUMOVehicleParameter::parseArrivalLane(arrivalLane, "vehicle", vehicleID, vehicleParams.arrivalLane, vehicleParams.arrivalLaneProcedure, error)) {
1097 throw TraCIException(error);
1098 }
1099 if (!SUMOVehicleParameter::parseArrivalPos(arrivalPos, "vehicle", vehicleID, vehicleParams.arrivalPos, vehicleParams.arrivalPosProcedure, error)) {
1100 throw TraCIException(error);
1101 }
1102 if (!SUMOVehicleParameter::parseArrivalSpeed(arrivalSpeed, "vehicle", vehicleID, vehicleParams.arrivalSpeed, vehicleParams.arrivalSpeedProcedure, error)) {
1103 throw TraCIException(error);
1104 }
1105 vehicleParams.fromTaz = fromTaz;
1106 vehicleParams.toTaz = toTaz;
1107 vehicleParams.line = line;
1108 //vehicleParams.personCapacity = personCapacity;
1109 vehicleParams.personNumber = personNumber;
1110
1111 SUMOVehicleParameter* params = new SUMOVehicleParameter(vehicleParams);
1112 try {
1113 SUMOVehicle* vehicle = MSNet::getInstance()->getVehicleControl().buildVehicle(params, route, vehicleType, true, false);
1114 MSNet::getInstance()->getVehicleControl().addVehicle(vehicleParams.id, vehicle);
1115 MSNet::getInstance()->getInsertionControl().add(vehicle);
1116 } catch (ProcessError& e) {
1117 throw TraCIException(e.what());
1118 }
1119 }
1120
1121
1122 void
1123 Vehicle::moveToXY(const std::string& vehicleID, const std::string& edgeID, const int laneIndex, const double x, const double y, double angle, const int keepRoute) {
1124 MSVehicle* veh = getVehicle(vehicleID);
1125 const bool doKeepRoute = (keepRoute == 1) && veh->getID() != "VTD_EGO";
1126 const bool mayLeaveNetwork = (keepRoute == 2);
1127 // process
1128 const std::string origID = edgeID + "_" + toString(laneIndex);
1129 // @todo add an interpretation layer for OSM derived origID values (without lane index)
1130 Position pos(x, y);
1131 #ifdef DEBUG_MOVEXY
1132 const double origAngle = angle;
1133 #endif
1134 // angle must be in [0,360] because it will be compared against those returned by naviDegree()
1135 // angle set to INVALID_DOUBLE_VALUE is ignored in the evaluated and later set to the angle of the matched lane
1136 if (angle != INVALID_DOUBLE_VALUE) {
1137 while (angle >= 360.) {
1138 angle -= 360.;
1139 }
1140 while (angle < 0.) {
1141 angle += 360.;
1142 }
1143 }
1144
1145 Position vehPos = veh->getPosition();
1146 #ifdef DEBUG_MOVEXY
1147 std::cout << std::endl << "begin vehicle " << veh->getID() << " vehPos:" << vehPos << " lane:" << Named::getIDSecure(veh->getLane()) << std::endl;
1148 std::cout << " want pos:" << pos << " origID:" << origID << " laneIndex:" << laneIndex << " origAngle:" << origAngle << " angle:" << angle << " keepRoute:" << keepRoute << std::endl;
1149 #endif
1150
1151 ConstMSEdgeVector edges;
1152 MSLane* lane = nullptr;
1153 double lanePos;
1154 double lanePosLat = 0;
1155 double bestDistance = std::numeric_limits<double>::max();
1156 int routeOffset = 0;
1157 bool found;
1158 double maxRouteDistance = 100;
1159 /* EGO vehicle is known to have a fixed route. @todo make this into a parameter of the TraCI call */
1160 if (doKeepRoute) {
1161 // case a): vehicle is on its earlier route
1162 // we additionally assume it is moving forward (SUMO-limit);
1163 // note that the route ("edges") is not changed in this case
1164
1165 found = Helper::moveToXYMap_matchingRoutePosition(pos, origID,
1166 veh->getRoute().getEdges(), (int)(veh->getCurrentRouteEdge() - veh->getRoute().begin()),
1167 bestDistance, &lane, lanePos, routeOffset);
1168 // @note silenty ignoring mapping failure
1169 } else {
1170 double speed = pos.distanceTo2D(veh->getPosition()); // !!!veh->getSpeed();
1171 found = Helper::moveToXYMap(pos, maxRouteDistance, mayLeaveNetwork, origID, angle,
1172 speed, veh->getRoute().getEdges(), veh->getRoutePosition(), veh->getLane(), veh->getPositionOnLane(), veh->isOnRoad(),
1173 bestDistance, &lane, lanePos, routeOffset, edges);
1174 }
1175 if ((found && bestDistance <= maxRouteDistance) || mayLeaveNetwork) {
1176 // optionally compute lateral offset
1177 pos.setz(veh->getPosition().z());
1178 if (found && (MSGlobals::gLateralResolution > 0 || mayLeaveNetwork)) {
1179 const double perpDist = lane->getShape().distance2D(pos, false);
1180 if (perpDist != GeomHelper::INVALID_OFFSET) {
1181 lanePosLat = perpDist;
1182 if (!mayLeaveNetwork) {
1183 lanePosLat = MIN2(lanePosLat, 0.5 * (lane->getWidth() + veh->getVehicleType().getWidth() - MSGlobals::gLateralResolution));
1184 }
1185 // figure out whether the offset is to the left or to the right
1186 PositionVector tmp = lane->getShape();
1187 try {
1188 tmp.move2side(-lanePosLat); // moved to left
1189 } catch (ProcessError&) {
1190 WRITE_WARNING("Could not determine position on lane '" + lane->getID() + " at lateral position " + toString(-lanePosLat) + ".");
1191 }
1192 //std::cout << " lane=" << lane->getID() << " posLat=" << lanePosLat << " shape=" << lane->getShape() << " tmp=" << tmp << " tmpDist=" << tmp.distance2D(pos) << "\n";
1193 if (tmp.distance2D(pos) > perpDist) {
1194 lanePosLat = -lanePosLat;
1195 }
1196 }
1197 pos.setz(lane->geometryPositionAtOffset(lanePos).z());
1198 }
1199 if (found && !mayLeaveNetwork && MSGlobals::gLateralResolution < 0) {
1200 // mapped position may differ from pos
1201 pos = lane->geometryPositionAtOffset(lanePos, -lanePosLat);
1202 }
1203 assert((found && lane != 0) || (!found && lane == 0));
1204 if (angle == INVALID_DOUBLE_VALUE) {
1205 if (lane != nullptr) {
1206 angle = GeomHelper::naviDegree(lane->getShape().rotationAtOffset(lanePos));
1207 } else {
1208 // compute angle outside road network from old and new position
1209 angle = GeomHelper::naviDegree(veh->getPosition().angleTo2D(pos));
1210 }
1211 }
1212 // use the best we have
1213 Helper::setRemoteControlled(veh, pos, lane, lanePos, lanePosLat, angle, routeOffset, edges, MSNet::getInstance()->getCurrentTimeStep());
1214 if (!veh->isOnRoad()) {
1215 MSNet::getInstance()->getInsertionControl().alreadyDeparted(veh);
1216 }
1217 } else {
1218 if (lane == nullptr) {
1219 throw TraCIException("Could not map vehicle '" + vehicleID + "' no road found within " + toString(maxRouteDistance) + "m.");
1220 } else {
1221 throw TraCIException("Could not map vehicle '" + vehicleID + "' distance to road is " + toString(bestDistance) + ".");
1222 }
1223 }
1224 }
1225
1226 void
1227 Vehicle::slowDown(const std::string& vehicleID, double speed, double duration) {
1228 MSVehicle* veh = getVehicle(vehicleID);
1229 std::vector<std::pair<SUMOTime, double> > speedTimeLine;
1230 speedTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep(), veh->getSpeed()));
1231 speedTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep() + TIME2STEPS(duration), speed));
1232 veh->getInfluencer().setSpeedTimeLine(speedTimeLine);
1233 }
1234
1235 void
1236 Vehicle::openGap(const std::string& vehicleID, double newTimeHeadway, double newSpaceHeadway, double duration, double changeRate, double maxDecel, const std::string& referenceVehID) {
1237 MSVehicle* veh = getVehicle(vehicleID);
1238 MSVehicle* refVeh = nullptr;
1239 if (referenceVehID != "") {
1240 refVeh = getVehicle(referenceVehID);
1241 }
1242 const double originalTau = veh->getVehicleType().getCarFollowModel().getHeadwayTime();
1243 if (newTimeHeadway == -1) {
1244 newTimeHeadway = originalTau;
1245 }
1246 if (originalTau > newTimeHeadway) {
1247 WRITE_WARNING("Ignoring openGap(). New time headway must not be smaller than the original.");
1248 return;
1249 }
1250 veh->getInfluencer().activateGapController(originalTau, newTimeHeadway, newSpaceHeadway, duration, changeRate, maxDecel, refVeh);
1251 }
1252
1253 void
1254 Vehicle::deactivateGapControl(const std::string& vehicleID) {
1255 MSVehicle* veh = getVehicle(vehicleID);
1256 if (veh->hasInfluencer()) {
1257 veh->getInfluencer().deactivateGapController();
1258 }
1259 }
1260
1261 void
1262 Vehicle::requestToC(const std::string& vehID, double leadTime) {
1263 setParameter(vehID, "device.toc.requestToC", toString(leadTime));
1264 }
1265
1266 void
1267 Vehicle::setSpeed(const std::string& vehicleID, double speed) {
1268 MSVehicle* veh = getVehicle(vehicleID);
1269 std::vector<std::pair<SUMOTime, double> > speedTimeLine;
1270 if (speed >= 0) {
1271 speedTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep(), speed));
1272 speedTimeLine.push_back(std::make_pair(SUMOTime_MAX - DELTA_T, speed));
1273 }
1274 veh->getInfluencer().setSpeedTimeLine(speedTimeLine);
1275 }
1276
1277 void
1278 Vehicle::setSpeedMode(const std::string& vehicleID, int speedMode) {
1279 getVehicle(vehicleID)->getInfluencer().setSpeedMode(speedMode);
1280 }
1281
1282 void
1283 Vehicle::setLaneChangeMode(const std::string& vehicleID, int laneChangeMode) {
1284 getVehicle(vehicleID)->getInfluencer().setLaneChangeMode(laneChangeMode);
1285 }
1286
1287 void
1288 Vehicle::setRoutingMode(const std::string& vehicleID, int routingMode) {
1289 getVehicle(vehicleID)->getInfluencer().setRoutingMode(routingMode);
1290 }
1291
1292 void
1293 Vehicle::setType(const std::string& vehicleID, const std::string& typeID) {
1294 MSVehicleType* vehicleType = MSNet::getInstance()->getVehicleControl().getVType(typeID);
1295 if (vehicleType == nullptr) {
1296 throw TraCIException("Vehicle type '" + typeID + "' is not known");
1297 }
1298 getVehicle(vehicleID)->replaceVehicleType(vehicleType);
1299 }
1300
1301 void
1302 Vehicle::setRouteID(const std::string& vehicleID, const std::string& routeID) {
1303 MSVehicle* veh = getVehicle(vehicleID);
1304 const MSRoute* r = MSRoute::dictionary(routeID);
1305 if (r == nullptr) {
1306 throw TraCIException("The route '" + routeID + "' is not known.");
1307 }
1308 std::string msg;
1309 if (!veh->hasValidRoute(msg, r)) {
1310 WRITE_WARNING("Invalid route replacement for vehicle '" + veh->getID() + "'. " + msg);
1311 if (MSGlobals::gCheckRoutes) {
1312 throw TraCIException("Route replacement failed for " + veh->getID());
1313 }
1314 }
1315
1316 if (!veh->replaceRoute(r, "traci:setRouteID", veh->getLane() == nullptr)) {
1317 throw TraCIException("Route replacement failed for " + veh->getID());
1318 }
1319 }
1320
1321 void
1322 Vehicle::setRoute(const std::string& vehicleID, const std::vector<std::string>& edgeIDs) {
1323 MSVehicle* veh = getVehicle(vehicleID);
1324 ConstMSEdgeVector edges;
1325 try {
1326 MSEdge::parseEdgesList(edgeIDs, edges, "<unknown>");
1327 if (edges.size() > 0 && edges.back()->isInternal()) {
1328 edges.push_back(edges.back()->getLanes()[0]->getNextNormal());
1329 }
1330 } catch (ProcessError& e) {
1331 throw TraCIException("Invalid edge list for vehicle '" + veh->getID() + "' (" + e.what() + ")");
1332 }
1333 if (!veh->replaceRouteEdges(edges, -1, 0, "traci:setRoute", veh->getLane() == nullptr, true)) {
1334 throw TraCIException("Route replacement failed for " + veh->getID());
1335 }
1336 }
1337
1338 void
1339 Vehicle::updateBestLanes(const std::string& vehicleID) {
1340 MSVehicle* veh = getVehicle(vehicleID);
1341 veh->updateBestLanes(true);
1342 }
1343
1344
1345 void
1346 Vehicle::setAdaptedTraveltime(const std::string& vehicleID, const std::string& edgeID,
1347 double time, double begSeconds, double endSeconds) {
1348 MSVehicle* veh = getVehicle(vehicleID);
1349 MSEdge* edge = MSEdge::dictionary(edgeID);
1350 if (edge == nullptr) {
1351 throw TraCIException("Referended edge '" + edgeID + "' is not known.");
1352 }
1353 if (time != INVALID_DOUBLE_VALUE) {
1354 // add time
1355 if (begSeconds == 0 && endSeconds == std::numeric_limits<double>::max()) {
1356 // clean up old values before setting whole range
1357 while (veh->getWeightsStorage().knowsTravelTime(edge)) {
1358 veh->getWeightsStorage().removeTravelTime(edge);
1359 }
1360 }
1361 veh->getWeightsStorage().addTravelTime(edge, begSeconds, endSeconds, time);
1362 } else {
1363 // remove time
1364 while (veh->getWeightsStorage().knowsTravelTime(edge)) {
1365 veh->getWeightsStorage().removeTravelTime(edge);
1366 }
1367 }
1368 }
1369
1370
1371 void
1372 Vehicle::setEffort(const std::string& vehicleID, const std::string& edgeID,
1373 double effort, double begSeconds, double endSeconds) {
1374 MSVehicle* veh = getVehicle(vehicleID);
1375 MSEdge* edge = MSEdge::dictionary(edgeID);
1376 if (edge == nullptr) {
1377 throw TraCIException("Referended edge '" + edgeID + "' is not known.");
1378 }
1379 if (effort != INVALID_DOUBLE_VALUE) {
1380 // add effort
1381 if (begSeconds == 0 && endSeconds == std::numeric_limits<double>::max()) {
1382 // clean up old values before setting whole range
1383 while (veh->getWeightsStorage().knowsEffort(edge)) {
1384 veh->getWeightsStorage().removeEffort(edge);
1385 }
1386 }
1387 veh->getWeightsStorage().addEffort(edge, begSeconds, endSeconds, effort);
1388 } else {
1389 // remove effort
1390 while (veh->getWeightsStorage().knowsEffort(edge)) {
1391 veh->getWeightsStorage().removeEffort(edge);
1392 }
1393 }
1394 }
1395
1396
1397 void
1398 Vehicle::rerouteTraveltime(const std::string& vehicleID) {
1399 MSVehicle* veh = getVehicle(vehicleID);
1400 veh->reroute(MSNet::getInstance()->getCurrentTimeStep(), "traci:rerouteTraveltime",
1401 veh->getInfluencer().getRouterTT(), isOnInit(vehicleID));
1402 }
1403
1404
1405 void
1406 Vehicle::rerouteEffort(const std::string& vehicleID) {
1407 MSVehicle* veh = getVehicle(vehicleID);
1408 veh->reroute(MSNet::getInstance()->getCurrentTimeStep(), "traci:rerouteEffort", MSNet::getInstance()->getRouterEffort(), isOnInit(vehicleID));
1409 }
1410
1411
1412 void
1413 Vehicle::setSignals(const std::string& vehicleID, int signals) {
1414 MSVehicle* veh = getVehicle(vehicleID);
1415 // set influencer to make the change persistent
1416 veh->getInfluencer().setSignals(signals);
1417 // set them now so that getSignals returns the correct value
1418 veh->switchOffSignal(0x0fffffff);
1419 if (signals >= 0) {
1420 veh->switchOnSignal(signals);
1421 }
1422 }
1423
1424
1425 void
1426 Vehicle::moveTo(const std::string& vehicleID, const std::string& laneID, double position) {
1427 MSVehicle* veh = getVehicle(vehicleID);
1428 MSLane* l = MSLane::dictionary(laneID);
1429 if (l == nullptr) {
1430 throw TraCIException("Unknown lane '" + laneID + "'.");
1431 }
1432 MSEdge& destinationEdge = l->getEdge();
1433 if (!veh->willPass(&destinationEdge)) {
1434 throw TraCIException("Vehicle '" + laneID + "' may be set onto an edge to pass only.");
1435 }
1436 veh->onRemovalFromNet(MSMoveReminder::NOTIFICATION_TELEPORT);
1437 if (veh->getLane() != nullptr) {
1438 veh->getLane()->removeVehicle(veh, MSMoveReminder::NOTIFICATION_TELEPORT);
1439 } else {
1440 veh->setTentativeLaneAndPosition(l, position);
1441 }
1442 while (veh->getEdge() != &destinationEdge) {
1443 const MSEdge* nextEdge = veh->succEdge(1);
1444 // let the vehicle move to the next edge
1445 if (veh->enterLaneAtMove(nextEdge->getLanes()[0], true)) {
1446 MSNet::getInstance()->getVehicleControl().scheduleVehicleRemoval(veh);
1447 continue;
1448 }
1449 }
1450 if (!veh->isOnRoad()) {
1451 MSNet::getInstance()->getInsertionControl().alreadyDeparted(veh);
1452
1453 }
1454 l->forceVehicleInsertion(veh, position,
1455 veh->hasDeparted() ? MSMoveReminder::NOTIFICATION_TELEPORT : MSMoveReminder::NOTIFICATION_DEPARTED);
1456 }
1457
1458
1459 void
1460 Vehicle::setActionStepLength(const std::string& vehicleID, double actionStepLength, bool resetActionOffset) {
1461 if (actionStepLength < 0.0) {
1462 WRITE_ERROR("Invalid action step length (<0). Ignoring command setActionStepLength().");
1463 return;
1464 }
1465 MSVehicle* veh = getVehicle(vehicleID);
1466 if (actionStepLength == 0.) {
1467 veh->resetActionOffset();
1468 } else {
1469 veh->setActionStepLength(actionStepLength, resetActionOffset);
1470 }
1471 }
1472
1473
1474 void
1475 Vehicle::remove(const std::string& vehicleID, char reason) {
1476 MSVehicle* veh = getVehicle(vehicleID);
1477 MSMoveReminder::Notification n = MSMoveReminder::NOTIFICATION_ARRIVED;
1478 switch (reason) {
1479 case REMOVE_TELEPORT:
1480 // XXX semantics unclear
1481 // n = MSMoveReminder::NOTIFICATION_TELEPORT;
1482 n = MSMoveReminder::NOTIFICATION_TELEPORT_ARRIVED;
1483 break;
1484 case REMOVE_PARKING:
1485 // XXX semantics unclear
1486 // n = MSMoveReminder::NOTIFICATION_PARKING;
1487 n = MSMoveReminder::NOTIFICATION_ARRIVED;
1488 break;
1489 case REMOVE_ARRIVED:
1490 n = MSMoveReminder::NOTIFICATION_ARRIVED;
1491 break;
1492 case REMOVE_VAPORIZED:
1493 n = MSMoveReminder::NOTIFICATION_VAPORIZED;
1494 break;
1495 case REMOVE_TELEPORT_ARRIVED:
1496 n = MSMoveReminder::NOTIFICATION_TELEPORT_ARRIVED;
1497 break;
1498 default:
1499 throw TraCIException("Unknown removal status.");
1500 }
1501 if (veh->hasDeparted()) {
1502 veh->onRemovalFromNet(n);
1503 if (veh->getLane() != nullptr) {
1504 veh->getLane()->removeVehicle(veh, n);
1505 }
1506 MSNet::getInstance()->getVehicleControl().scheduleVehicleRemoval(veh);
1507 } else {
1508 MSNet::getInstance()->getInsertionControl().alreadyDeparted(veh);
1509 MSNet::getInstance()->getVehicleControl().deleteVehicle(veh, true);
1510 }
1511 }
1512
1513
1514 void
1515 Vehicle::setColor(const std::string& vehicleID, const TraCIColor& col) {
1516 const SUMOVehicleParameter& p = getVehicle(vehicleID)->getParameter();
1517 p.color.set((unsigned char)col.r, (unsigned char)col.g, (unsigned char)col.b, (unsigned char)col.a);
1518 p.parametersSet |= VEHPARS_COLOR_SET;
1519 }
1520
1521
1522 void
1523 Vehicle::setSpeedFactor(const std::string& vehicleID, double factor) {
1524 getVehicle(vehicleID)->setChosenSpeedFactor(factor);
1525 }
1526
1527
1528 void
1529 Vehicle::setLine(const std::string& vehicleID, const std::string& line) {
1530 getVehicle(vehicleID)->getParameter().line = line;
1531 }
1532
1533
1534 void
1535 Vehicle::setVia(const std::string& vehicleID, const std::vector<std::string>& via) {
1536 MSVehicle* veh = getVehicle(vehicleID);
1537 try {
1538 // ensure edges exist
1539 ConstMSEdgeVector edges;
1540 MSEdge::parseEdgesList(via, edges, "<via-edges>");
1541 } catch (ProcessError& e) {
1542 throw TraCIException(e.what());
1543 }
1544 veh->getParameter().via = via;
1545 }
1546
1547
1548 void
1549 Vehicle::setLength(const std::string& vehicleID, double length) {
1550 getVehicle(vehicleID)->getSingularType().setLength(length);
1551 }
1552
1553
1554 void
1555 Vehicle::setMaxSpeed(const std::string& vehicleID, double speed) {
1556 getVehicle(vehicleID)->getSingularType().setMaxSpeed(speed);
1557 }
1558
1559
1560 void
1561 Vehicle::setVehicleClass(const std::string& vehicleID, const std::string& clazz) {
1562 getVehicle(vehicleID)->getSingularType().setVClass(getVehicleClassID(clazz));
1563 }
1564
1565
1566 void
1567 Vehicle::setShapeClass(const std::string& vehicleID, const std::string& clazz) {
1568 getVehicle(vehicleID)->getSingularType().setShape(getVehicleShapeID(clazz));
1569 }
1570
1571
1572 void
1573 Vehicle::setEmissionClass(const std::string& vehicleID, const std::string& clazz) {
1574 getVehicle(vehicleID)->getSingularType().setEmissionClass(PollutantsInterface::getClassByName(clazz));
1575 }
1576
1577
1578 void
1579 Vehicle::setWidth(const std::string& vehicleID, double width) {
1580 getVehicle(vehicleID)->getSingularType().setWidth(width);
1581 }
1582
1583
1584 void
1585 Vehicle::setHeight(const std::string& vehicleID, double height) {
1586 getVehicle(vehicleID)->getSingularType().setHeight(height);
1587 }
1588
1589
1590 void
1591 Vehicle::setMinGap(const std::string& vehicleID, double minGap) {
1592 getVehicle(vehicleID)->getSingularType().setMinGap(minGap);
1593 }
1594
1595
1596 void
1597 Vehicle::setAccel(const std::string& vehicleID, double accel) {
1598 getVehicle(vehicleID)->getSingularType().setAccel(accel);
1599 }
1600
1601
1602 void
1603 Vehicle::setDecel(const std::string& vehicleID, double decel) {
1604 VehicleType::setDecel(getVehicle(vehicleID)->getSingularType().getID(), decel);
1605 }
1606
1607
1608 void
1609 Vehicle::setEmergencyDecel(const std::string& vehicleID, double decel) {
1610 VehicleType::setEmergencyDecel(getVehicle(vehicleID)->getSingularType().getID(), decel);
1611 }
1612
1613
1614 void
1615 Vehicle::setApparentDecel(const std::string& vehicleID, double decel) {
1616 getVehicle(vehicleID)->getSingularType().setApparentDecel(decel);
1617 }
1618
1619
1620 void
1621 Vehicle::setImperfection(const std::string& vehicleID, double imperfection) {
1622 getVehicle(vehicleID)->getSingularType().setImperfection(imperfection);
1623 }
1624
1625
1626 void
1627 Vehicle::setTau(const std::string& vehicleID, double tau) {
1628 getVehicle(vehicleID)->getSingularType().setTau(tau);
1629 }
1630
1631
1632 void
1633 Vehicle::setMinGapLat(const std::string& vehicleID, double minGapLat) {
1634 getVehicle(vehicleID)->getSingularType().setMinGapLat(minGapLat);
1635 }
1636
1637
1638 void
1639 Vehicle::setMaxSpeedLat(const std::string& vehicleID, double speed) {
1640 getVehicle(vehicleID)->getSingularType().setMaxSpeedLat(speed);
1641 }
1642
1643
1644 void
1645 Vehicle::setLateralAlignment(const std::string& vehicleID, const std::string& latAlignment) {
1646 getVehicle(vehicleID)->getSingularType().setPreferredLateralAlignment(SUMOXMLDefinitions::LateralAlignments.get(latAlignment));
1647 }
1648
1649
1650 void
1651 Vehicle::setParameter(const std::string& vehicleID, const std::string& key, const std::string& value) {
1652 MSVehicle* veh = getVehicle(vehicleID);
1653 if (StringUtils::startsWith(key, "device.")) {
1654 StringTokenizer tok(key, ".");
1655 if (tok.size() < 3) {
1656 throw TraCIException("Invalid device parameter '" + key + "' for vehicle '" + vehicleID + "'");
1657 }
1658 try {
1659 veh->setDeviceParameter(tok.get(1), key.substr(tok.get(0).size() + tok.get(1).size() + 2), value);
1660 } catch (InvalidArgument& e) {
1661 throw TraCIException("Vehicle '" + vehicleID + "' does not support device parameter '" + key + "' (" + e.what() + ").");
1662 }
1663 } else if (StringUtils::startsWith(key, "laneChangeModel.")) {
1664 const std::string attrName = key.substr(16);
1665 try {
1666 veh->getLaneChangeModel().setParameter(attrName, value);
1667 } catch (InvalidArgument& e) {
1668 throw TraCIException("Vehicle '" + vehicleID + "' does not support laneChangeModel parameter '" + key + "' (" + e.what() + ").");
1669 }
1670 } else if (StringUtils::startsWith(key, "carFollowModel.")) {
1671 const std::string attrName = key.substr(15);
1672 try {
1673 veh->getCarFollowModel().setParameter(veh, attrName, value);
1674 } catch (InvalidArgument& e) {
1675 throw TraCIException("Vehicle '" + vehicleID + "' does not support carFollowModel parameter '" + key + "' (" + e.what() + ").");
1676 }
1677 } else if (StringUtils::startsWith(key, "has.") && StringUtils::endsWith(key, ".device")) {
1678 StringTokenizer tok(key, ".");
1679 if (tok.size() != 3) {
1680 throw TraCIException("Invalid request for device status change. Expected format is 'has.DEVICENAME.device'");
1681 }
1682 const std::string deviceName = tok.get(1);
1683 bool create;
1684 try {
1685 create = StringUtils::toBool(value);
1686 } catch (BoolFormatException&) {
1687 throw TraCIException("Changing device status requires a 'true' or 'false'");
1688 }
1689 if (!create) {
1690 throw TraCIException("Device removal is not supported for device of type '" + deviceName + "'");
1691 }
1692 try {
1693 veh->createDevice(deviceName);
1694 } catch (InvalidArgument& e) {
1695 throw TraCIException("Cannot create vehicle device (" + std::string(e.what()) + ").");
1696 }
1697 } else {
1698 ((SUMOVehicleParameter&)veh->getParameter()).setParameter(key, value);
1699 }
1700 }
1701
1702
1703 void
1704 Vehicle::highlight(const std::string& vehicleID, const TraCIColor& col, double size, const int alphaMax, const double duration, const int type) {
1705 // NOTE: Code is duplicated in large parts in POI.cpp
1706 MSVehicle* veh = getVehicle(vehicleID);
1707
1708 // Center of the highlight circle
1709 Position center = veh->getPosition();
1710 const double l2 = veh->getLength() * 0.5;
1711 center.sub(cos(veh->getAngle())*l2, sin(veh->getAngle())*l2);
1712 // Size of the highlight circle
1713 if (size <= 0) {
1714 size = veh->getLength() * 0.7;
1715 }
1716 // Make polygon shape
1717 const unsigned int nPoints = 34;
1718 const PositionVector circlePV = GeomHelper::makeRing(size, size + 1., center, nPoints);
1719 TraCIPositionVector circle = Helper::makeTraCIPositionVector(circlePV);
1720
1721 #ifdef DEBUG_DYNAMIC_SHAPES
1722 std::cout << SIMTIME << " Vehicle::highlight() for vehicle '" << vehicleID << "'\n"
1723 << " circle: " << circlePV << std::endl;
1724 #endif
1725
1726 // Find a free polygon id
1727 int i = 0;
1728 std::string polyID = veh->getID() + "_hl" + toString(i);
1729 while (Polygon::exists(polyID)) {
1730 polyID = veh->getID() + "_hl" + toString(++i);
1731 }
1732 // Line width
1733 double lw = 0.;
1734 // Layer
1735 double lyr = 0.;
1736 if (MSNet::getInstance()->isGUINet()) {
1737 lyr = GLO_VEHICLE + 0.01;
1738 lyr += (type + 1) / 257.;
1739 }
1740 // Make Polygon
1741 Polygon::addHighlightPolygon(vehicleID, type, polyID, circle, col, true, lw, "highlight", (int)lyr);
1742
1743 // Animation time line
1744 double maxAttack = 1.0; // maximal fade-in time
1745 std::vector<double> timeSpan;
1746 if (duration > 0.) {
1747 timeSpan = {0, MIN2(maxAttack, duration / 3.), 2.*duration / 3., duration};
1748 }
1749 // Alpha time line
1750 std::vector<double> alphaSpan;
1751 if (alphaMax > 0.) {
1752 alphaSpan = {0., (double) alphaMax, (double)(alphaMax) / 3., 0.};
1753 }
1754 // Attach dynamics
1755 Polygon::addDynamics(polyID, vehicleID, timeSpan, alphaSpan, false, true);
1756 }
1757
1758
1759 LIBSUMO_SUBSCRIPTION_IMPLEMENTATION(Vehicle, VEHICLE)
1760
1761
1762 void
1763 Vehicle::subscribeLeader(const std::string& vehicleID, double /* dist */, double beginTime, double endTime) {
1764 // TODO handle dist correctly
1765 Vehicle::subscribe(vehicleID, std::vector<int>({libsumo::VAR_LEADER}), beginTime, endTime);
1766 }
1767
1768
1769 void
1770 Vehicle::storeShape(const std::string& id, PositionVector& shape) {
1771 shape.push_back(getVehicle(id)->getPosition());
1772 }
1773
1774
1775 std::shared_ptr<VariableWrapper>
1776 Vehicle::makeWrapper() {
1777 return std::make_shared<Helper::SubscriptionWrapper>(handleVariable, mySubscriptionResults, myContextSubscriptionResults);
1778 }
1779
1780
1781 bool
1782 Vehicle::handleVariable(const std::string& objID, const int variable, VariableWrapper* wrapper) {
1783 switch (variable) {
1784 case TRACI_ID_LIST:
1785 return wrapper->wrapStringList(objID, variable, getIDList());
1786 case ID_COUNT:
1787 return wrapper->wrapInt(objID, variable, getIDCount());
1788 case VAR_POSITION:
1789 return wrapper->wrapPosition(objID, variable, getPosition(objID));
1790 case VAR_POSITION3D:
1791 return wrapper->wrapPosition(objID, variable, getPosition(objID, true));
1792 case VAR_ANGLE:
1793 return wrapper->wrapDouble(objID, variable, getAngle(objID));
1794 case VAR_SPEED:
1795 return wrapper->wrapDouble(objID, variable, getSpeed(objID));
1796 case VAR_ROAD_ID:
1797 return wrapper->wrapString(objID, variable, getRoadID(objID));
1798 case VAR_SPEED_WITHOUT_TRACI:
1799 return wrapper->wrapDouble(objID, variable, getSpeedWithoutTraCI(objID));
1800 case VAR_SLOPE:
1801 return wrapper->wrapDouble(objID, variable, getSlope(objID));
1802 case VAR_LANE_ID:
1803 return wrapper->wrapString(objID, variable, getLaneID(objID));
1804 case VAR_LANE_INDEX:
1805 return wrapper->wrapInt(objID, variable, getLaneIndex(objID));
1806 case VAR_TYPE:
1807 return wrapper->wrapString(objID, variable, getTypeID(objID));
1808 case VAR_ROUTE_ID:
1809 return wrapper->wrapString(objID, variable, getRouteID(objID));
1810 case VAR_ROUTE_INDEX:
1811 return wrapper->wrapInt(objID, variable, getRouteIndex(objID));
1812 case VAR_COLOR:
1813 return wrapper->wrapColor(objID, variable, getColor(objID));
1814 case VAR_LANEPOSITION:
1815 return wrapper->wrapDouble(objID, variable, getLanePosition(objID));
1816 case VAR_LANEPOSITION_LAT:
1817 return wrapper->wrapDouble(objID, variable, getLateralLanePosition(objID));
1818 case VAR_CO2EMISSION:
1819 return wrapper->wrapDouble(objID, variable, getCO2Emission(objID));
1820 case VAR_COEMISSION:
1821 return wrapper->wrapDouble(objID, variable, getCOEmission(objID));
1822 case VAR_HCEMISSION:
1823 return wrapper->wrapDouble(objID, variable, getHCEmission(objID));
1824 case VAR_PMXEMISSION:
1825 return wrapper->wrapDouble(objID, variable, getPMxEmission(objID));
1826 case VAR_NOXEMISSION:
1827 return wrapper->wrapDouble(objID, variable, getNOxEmission(objID));
1828 case VAR_FUELCONSUMPTION:
1829 return wrapper->wrapDouble(objID, variable, getFuelConsumption(objID));
1830 case VAR_NOISEEMISSION:
1831 return wrapper->wrapDouble(objID, variable, getNoiseEmission(objID));
1832 case VAR_ELECTRICITYCONSUMPTION:
1833 return wrapper->wrapDouble(objID, variable, getElectricityConsumption(objID));
1834 case VAR_PERSON_NUMBER:
1835 return wrapper->wrapInt(objID, variable, getPersonNumber(objID));
1836 case LAST_STEP_PERSON_ID_LIST:
1837 return wrapper->wrapStringList(objID, variable, getPersonIDList(objID));
1838 case VAR_WAITING_TIME:
1839 return wrapper->wrapDouble(objID, variable, getWaitingTime(objID));
1840 case VAR_ACCUMULATED_WAITING_TIME:
1841 return wrapper->wrapDouble(objID, variable, getAccumulatedWaitingTime(objID));
1842 case VAR_ROUTE_VALID:
1843 return wrapper->wrapInt(objID, variable, isRouteValid(objID));
1844 case VAR_EDGES:
1845 return wrapper->wrapStringList(objID, variable, getRoute(objID));
1846 case VAR_SIGNALS:
1847 return wrapper->wrapInt(objID, variable, getSignals(objID));
1848 case VAR_STOPSTATE:
1849 return wrapper->wrapInt(objID, variable, getStopState(objID));
1850 case VAR_DISTANCE:
1851 return wrapper->wrapDouble(objID, variable, getDistance(objID));
1852 case VAR_ALLOWED_SPEED:
1853 return wrapper->wrapDouble(objID, variable, getAllowedSpeed(objID));
1854 case VAR_SPEED_FACTOR:
1855 return wrapper->wrapDouble(objID, variable, getSpeedFactor(objID));
1856 case VAR_SPEEDSETMODE:
1857 return wrapper->wrapInt(objID, variable, getSpeedMode(objID));
1858 case VAR_LANECHANGE_MODE:
1859 return wrapper->wrapInt(objID, variable, getLaneChangeMode(objID));
1860 case VAR_ROUTING_MODE:
1861 return wrapper->wrapInt(objID, variable, getRoutingMode(objID));
1862 case VAR_LINE:
1863 return wrapper->wrapString(objID, variable, getLine(objID));
1864 case VAR_VIA:
1865 return wrapper->wrapStringList(objID, variable, getVia(objID));
1866 case VAR_ACCELERATION:
1867 return wrapper->wrapDouble(objID, variable, getAcceleration(objID));
1868 case VAR_LASTACTIONTIME:
1869 return wrapper->wrapDouble(objID, variable, getLastActionTime(objID));
1870 case VAR_LEADER: {
1871 const auto& lead = getLeader(objID);
1872 TraCIRoadPosition rp;
1873 rp.edgeID = lead.first;
1874 rp.pos = lead.second;
1875 return wrapper->wrapRoadPosition(objID, variable, rp);
1876 }
1877 default:
1878 return false;
1879 }
1880 }
1881
1882
1883 }
1884
1885 /****************************************************************************/
1886