1# -*- coding: utf-8 -*-
2# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3# Copyright (C) 2011-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.py
11# @author  Michael Behrisch
12# @author  Lena Kalleske
13# @author  Mario Krumnow
14# @author  Lena Kalleske
15# @author  Jakob Erdmann
16# @author  Laura Bieker
17# @author  Daniel Krajzewicz
18# @author  Leonhard Luecken
19# @date    2011-03-09
20# @version $Id$
21
22from __future__ import absolute_import
23import struct
24import warnings
25from .domain import Domain
26from .storage import Storage
27from . import constants as tc
28from .exceptions import TraCIException
29
30
31def _readBestLanes(result):
32    result.read("!iB")
33    nbLanes = result.read("!i")[0]  # Length
34    lanes = []
35    for i in range(nbLanes):
36        result.read("!B")
37        laneID = result.readString()
38        length, occupation, offset = result.read("!BdBdBb")[1::2]
39        allowsContinuation = bool(result.read("!BB")[1])
40        nextLanesNo = result.read("!Bi")[1]
41        nextLanes = []
42        for j in range(nextLanesNo):
43            nextLanes.append(result.readString())
44        lanes.append((laneID, length, occupation, offset, allowsContinuation, tuple(nextLanes)))
45    return tuple(lanes)
46
47
48def _readLeader(result):
49    result.read("!iB")
50    vehicleID = result.readString()
51    result.read("!B")
52    dist = result.readDouble()
53    if vehicleID:
54        return vehicleID, dist
55    return None
56
57
58def _readNeighbors(result):
59    """ result has structure:
60    byte(TYPE_COMPOUND) | length(neighList) | Per list entry: string(vehID) | double(dist)
61    """
62    N = result.readInt()  # length of the vehicle list
63    neighs = []
64    for i in range(N):
65        vehID = result.readString()
66        dist = result.readDouble()
67        neighs.append((vehID, dist))
68    return neighs
69
70
71def _readNextTLS(result):
72    result.read("!iB")  # numCompounds, TYPE_INT
73    numTLS = result.read("!i")[0]
74    nextTLS = []
75    for i in range(numTLS):
76        result.read("!B")
77        tlsID = result.readString()
78        tlsIndex, dist, state = result.read("!BiBdBB")[1::2]
79        nextTLS.append((tlsID, tlsIndex, dist, chr(state)))
80    return tuple(nextTLS)
81
82
83def _readNextStops(result):
84    result.read("!iB")  # numCompounds, TYPE_INT
85    numStops = result.read("!i")[0]
86    nextStop = []
87    for i in range(numStops):
88        result.read("!B")
89        lane = result.readString()
90        result.read("!B")
91        endPos = result.readDouble()
92        result.read("!B")
93        stoppingPlaceID = result.readString()
94        result.read("!B")
95        stopFlags = result.readInt()
96        result.read("!B")
97        duration = result.readDouble()
98        result.read("!B")
99        until = result.readDouble()
100        nextStop.append((lane, endPos, stoppingPlaceID, stopFlags, duration, until))
101    return tuple(nextStop)
102
103
104_RETURN_VALUE_FUNC = {tc.VAR_SPEED: Storage.readDouble,
105                      tc.VAR_SPEED_WITHOUT_TRACI: Storage.readDouble,
106                      tc.VAR_ACCELERATION: Storage.readDouble,
107                      tc.VAR_POSITION: lambda result: result.read("!dd"),
108                      tc.VAR_POSITION3D: lambda result: result.read("!ddd"),
109                      tc.VAR_ANGLE: Storage.readDouble,
110                      tc.VAR_ROAD_ID: Storage.readString,
111                      tc.VAR_LANE_ID: Storage.readString,
112                      tc.VAR_LANE_INDEX: Storage.readInt,
113                      tc.VAR_TYPE: Storage.readString,
114                      tc.VAR_ROUTE_ID: Storage.readString,
115                      tc.VAR_ROUTE_INDEX: Storage.readInt,
116                      tc.VAR_COLOR: lambda result: result.read("!BBBB"),
117                      tc.VAR_LANEPOSITION: Storage.readDouble,
118                      tc.VAR_CO2EMISSION: Storage.readDouble,
119                      tc.VAR_COEMISSION: Storage.readDouble,
120                      tc.VAR_HCEMISSION: Storage.readDouble,
121                      tc.VAR_PMXEMISSION: Storage.readDouble,
122                      tc.VAR_NOXEMISSION: Storage.readDouble,
123                      tc.VAR_FUELCONSUMPTION: Storage.readDouble,
124                      tc.VAR_NOISEEMISSION: Storage.readDouble,
125                      tc.VAR_ELECTRICITYCONSUMPTION: Storage.readDouble,
126                      tc.VAR_PERSON_NUMBER: Storage.readInt,
127                      tc.LAST_STEP_PERSON_ID_LIST: Storage.readStringList,
128                      tc.VAR_EDGE_TRAVELTIME: Storage.readDouble,
129                      tc.VAR_EDGE_EFFORT: Storage.readDouble,
130                      tc.VAR_ROUTE_VALID: lambda result: bool(result.read("!i")[0]),
131                      tc.VAR_EDGES: Storage.readStringList,
132                      tc.VAR_SIGNALS: Storage.readInt,
133                      tc.VAR_LENGTH: Storage.readDouble,
134                      tc.VAR_MAXSPEED: Storage.readDouble,
135                      tc.VAR_ALLOWED_SPEED: Storage.readDouble,
136                      tc.VAR_VEHICLECLASS: Storage.readString,
137                      tc.VAR_SPEED_FACTOR: Storage.readDouble,
138                      tc.VAR_SPEED_DEVIATION: Storage.readDouble,
139                      tc.VAR_EMISSIONCLASS: Storage.readString,
140                      tc.VAR_WAITING_TIME: Storage.readDouble,
141                      tc.VAR_ACCUMULATED_WAITING_TIME: Storage.readDouble,
142                      tc.VAR_LANECHANGE_MODE: Storage.readInt,
143                      tc.VAR_SPEEDSETMODE: Storage.readInt,
144                      tc.VAR_SLOPE: Storage.readDouble,
145                      tc.VAR_WIDTH: Storage.readDouble,
146                      tc.VAR_HEIGHT: Storage.readDouble,
147                      tc.VAR_LINE: Storage.readString,
148                      tc.VAR_VIA: Storage.readStringList,
149                      tc.VAR_MINGAP: Storage.readDouble,
150                      tc.VAR_SHAPECLASS: Storage.readString,
151                      tc.VAR_ACCEL: Storage.readDouble,
152                      tc.VAR_DECEL: Storage.readDouble,
153                      tc.VAR_EMERGENCY_DECEL: Storage.readDouble,
154                      tc.VAR_APPARENT_DECEL: Storage.readDouble,
155                      tc.VAR_ACTIONSTEPLENGTH: Storage.readDouble,
156                      tc.VAR_LASTACTIONTIME: Storage.readDouble,
157                      tc.VAR_IMPERFECTION: Storage.readDouble,
158                      tc.VAR_TAU: Storage.readDouble,
159                      tc.VAR_BEST_LANES: _readBestLanes,
160                      tc.VAR_LEADER: _readLeader,
161                      tc.VAR_NEIGHBORS: _readNeighbors,
162                      tc.VAR_NEXT_TLS: _readNextTLS,
163                      tc.VAR_NEXT_STOPS: _readNextStops,
164                      tc.VAR_LANEPOSITION_LAT: Storage.readDouble,
165                      tc.VAR_MAXSPEED_LAT: Storage.readDouble,
166                      tc.VAR_MINGAP_LAT: Storage.readDouble,
167                      tc.VAR_LATALIGNMENT: Storage.readString,
168                      tc.DISTANCE_REQUEST: Storage.readDouble,
169                      tc.VAR_ROUTING_MODE: Storage.readInt,
170                      tc.VAR_STOPSTATE: Storage.readInt,
171                      tc.VAR_DISTANCE: Storage.readDouble}
172
173
174class VehicleDomain(Domain):
175    # imported for backwards compatibility
176    STOP_DEFAULT = tc.STOP_DEFAULT
177    STOP_PARKING = tc.STOP_PARKING
178    STOP_TRIGGERED = tc.STOP_TRIGGERED
179    STOP_CONTAINER_TRIGGERED = tc.STOP_CONTAINER_TRIGGERED
180    STOP_BUS_STOP = tc.STOP_BUS_STOP
181    STOP_CONTAINER_STOP = tc.STOP_CONTAINER_STOP
182    STOP_CHARGING_STATION = tc.STOP_CHARGING_STATION
183    STOP_PARKING_AREA = tc.STOP_PARKING_AREA
184    DEPART_TRIGGERED = tc.DEPARTFLAG_TRIGGERED
185    DEPART_CONTAINER_TRIGGERED = tc.DEPARTFLAG_CONTAINER_TRIGGERED
186    DEPART_NOW = tc.DEPARTFLAG_NOW
187    DEPART_SPEED_RANDOM = tc.DEPARTFLAG_SPEED_RANDOM
188    DEPART_SPEED_MAX = tc.DEPARTFLAG_SPEED_MAX
189    DEPART_LANE_RANDOM = tc.DEPARTFLAG_LANE_RANDOM
190    DEPART_LANE_FREE = tc.DEPARTFLAG_LANE_FREE
191    DEPART_LANE_ALLOWED_FREE = tc.DEPARTFLAG_LANE_ALLOWED_FREE
192    DEPART_LANE_BEST_FREE = tc.DEPARTFLAG_LANE_BEST_FREE
193    DEPART_LANE_FIRST_ALLOWED = tc.DEPARTFLAG_LANE_FIRST_ALLOWED
194
195    def __init__(self):
196        Domain.__init__(self, "vehicle", tc.CMD_GET_VEHICLE_VARIABLE, tc.CMD_SET_VEHICLE_VARIABLE,
197                        tc.CMD_SUBSCRIBE_VEHICLE_VARIABLE, tc.RESPONSE_SUBSCRIBE_VEHICLE_VARIABLE,
198                        tc.CMD_SUBSCRIBE_VEHICLE_CONTEXT, tc.RESPONSE_SUBSCRIBE_VEHICLE_CONTEXT,
199                        _RETURN_VALUE_FUNC)
200
201    def getSpeed(self, vehID):
202        """getSpeed(string) -> double
203
204        Returns the speed in m/s of the named vehicle within the last step.
205        """
206        return self._getUniversal(tc.VAR_SPEED, vehID)
207
208    def getAcceleration(self, vehID):
209        """getAcceleration(string) -> double
210
211        Returns the acceleration in m/s^2 of the named vehicle within the last step.
212        """
213        return self._getUniversal(tc.VAR_ACCELERATION, vehID)
214
215    def getSpeedWithoutTraCI(self, vehID):
216        """getSpeedWithoutTraCI(string) -> double
217        Returns the speed that the vehicle would drive if not speed-influencing
218        command such as setSpeed or slowDown was given.
219        """
220        return self._getUniversal(tc.VAR_SPEED_WITHOUT_TRACI, vehID)
221
222    def getPosition(self, vehID):
223        """getPosition(string) -> (double, double)
224
225        Returns the position of the named vehicle within the last step [m,m].
226        """
227        return self._getUniversal(tc.VAR_POSITION, vehID)
228
229    def getPosition3D(self, vehID):
230        """getPosition3D(string) -> (double, double, double)
231
232        Returns the position of the named vehicle within the last step [m,m,m].
233        """
234        return self._getUniversal(tc.VAR_POSITION3D, vehID)
235
236    def getAngle(self, vehID):
237        """getAngle(string) -> double
238
239        Returns the angle in degrees of the named vehicle within the last step.
240        """
241        return self._getUniversal(tc.VAR_ANGLE, vehID)
242
243    def getRoadID(self, vehID):
244        """getRoadID(string) -> string
245
246        Returns the id of the edge the named vehicle was at within the last step.
247        """
248        return self._getUniversal(tc.VAR_ROAD_ID, vehID)
249
250    def getLaneID(self, vehID):
251        """getLaneID(string) -> string
252
253        Returns the id of the lane the named vehicle was at within the last step.
254        """
255        return self._getUniversal(tc.VAR_LANE_ID, vehID)
256
257    def getLaneIndex(self, vehID):
258        """getLaneIndex(string) -> integer
259
260        Returns the index of the lane the named vehicle was at within the last step.
261        """
262        return self._getUniversal(tc.VAR_LANE_INDEX, vehID)
263
264    def getTypeID(self, vehID):
265        """getTypeID(string) -> string
266
267        Returns the id of the type of the named vehicle.
268        """
269        return self._getUniversal(tc.VAR_TYPE, vehID)
270
271    def getRouteID(self, vehID):
272        """getRouteID(string) -> string
273
274        Returns the id of the route of the named vehicle.
275        """
276        return self._getUniversal(tc.VAR_ROUTE_ID, vehID)
277
278    def getRouteIndex(self, vehID):
279        """getRouteIndex(string) -> int
280
281        Returns the index of the current edge within the vehicles route or -1 if the
282        vehicle has not yet departed
283        """
284        return self._getUniversal(tc.VAR_ROUTE_INDEX, vehID)
285
286    def getRoute(self, vehID):
287        """getRoute(string) -> list(string)
288
289        Returns the ids of the edges the vehicle's route is made of.
290        """
291        return self._getUniversal(tc.VAR_EDGES, vehID)
292
293    def getLanePosition(self, vehID):
294        """getLanePosition(string) -> double
295
296        The position of the vehicle along the lane measured in m.
297        """
298        return self._getUniversal(tc.VAR_LANEPOSITION, vehID)
299
300    def getColor(self, vehID):
301        """getColor(string) -> (integer, integer, integer, integer)
302
303        Returns the vehicle's rgba color.
304        """
305        return self._getUniversal(tc.VAR_COLOR, vehID)
306
307    def getCO2Emission(self, vehID):
308        """getCO2Emission(string) -> double
309
310        Returns the CO2 emission in mg for the last time step.
311        """
312        return self._getUniversal(tc.VAR_CO2EMISSION, vehID)
313
314    def getCOEmission(self, vehID):
315        """getCOEmission(string) -> double
316
317        Returns the CO emission in mg for the last time step.
318        """
319        return self._getUniversal(tc.VAR_COEMISSION, vehID)
320
321    def getHCEmission(self, vehID):
322        """getHCEmission(string) -> double
323
324        Returns the HC emission in mg for the last time step.
325        """
326        return self._getUniversal(tc.VAR_HCEMISSION, vehID)
327
328    def getPMxEmission(self, vehID):
329        """getPMxEmission(string) -> double
330
331        Returns the particular matter emission in mg for the last time step.
332        """
333        return self._getUniversal(tc.VAR_PMXEMISSION, vehID)
334
335    def getNOxEmission(self, vehID):
336        """getNOxEmission(string) -> double
337
338        Returns the NOx emission in mg for the last time step.
339        """
340        return self._getUniversal(tc.VAR_NOXEMISSION, vehID)
341
342    def getFuelConsumption(self, vehID):
343        """getFuelConsumption(string) -> double
344
345        Returns the fuel consumption in ml for the last time step.
346        """
347        return self._getUniversal(tc.VAR_FUELCONSUMPTION, vehID)
348
349    def getNoiseEmission(self, vehID):
350        """getNoiseEmission(string) -> double
351
352        Returns the noise emission in db for the last time step.
353        """
354        return self._getUniversal(tc.VAR_NOISEEMISSION, vehID)
355
356    def getElectricityConsumption(self, vehID):
357        """getElectricityConsumption(string) -> double
358
359        Returns the electricity consumption in Wh for the last time step.
360        """
361        return self._getUniversal(tc.VAR_ELECTRICITYCONSUMPTION, vehID)
362
363    def getPersonNumber(self, vehID):
364        """getPersonNumber(string) -> integer
365        Returns the total number of persons which includes those defined
366        using attribute 'personNumber' as well as <person>-objects which are riding in
367        this vehicle.
368        """
369        return self._getUniversal(tc.VAR_PERSON_NUMBER, vehID)
370
371    def getPersonIDList(self, vehID):
372        """getPersonIDList(string) -> integer
373        Returns the list of persons which includes those defined using attribute 'personNumber'
374        as well as <person>-objects which are riding in this vehicle.
375        """
376        return self._getUniversal(tc.LAST_STEP_PERSON_ID_LIST, vehID)
377
378    def getAdaptedTraveltime(self, vehID, time, edgeID):
379        """getAdaptedTraveltime(string, double, string) -> double
380
381        .
382        """
383        self._connection._beginMessage(tc.CMD_GET_VEHICLE_VARIABLE,
384                                       tc.VAR_EDGE_TRAVELTIME, vehID, 1 + 4 + 1 + 8 + 1 + 4 + len(edgeID))
385        self._connection._string += struct.pack(
386            "!BiBd", tc.TYPE_COMPOUND, 2, tc.TYPE_DOUBLE, time)
387        self._connection._packString(edgeID)
388        return self._connection._checkResult(tc.CMD_GET_VEHICLE_VARIABLE, tc.VAR_EDGE_TRAVELTIME, vehID).readDouble()
389
390    def getEffort(self, vehID, time, edgeID):
391        """getEffort(string, double, string) -> double
392
393        .
394        """
395        self._connection._beginMessage(tc.CMD_GET_VEHICLE_VARIABLE,
396                                       tc.VAR_EDGE_EFFORT, vehID, 1 + 4 + 1 + 8 + 1 + 4 + len(edgeID))
397        self._connection._string += struct.pack(
398            "!BiBd", tc.TYPE_COMPOUND, 2, tc.TYPE_DOUBLE, time)
399        self._connection._packString(edgeID)
400        return self._connection._checkResult(tc.CMD_GET_VEHICLE_VARIABLE, tc.VAR_EDGE_EFFORT, vehID).readDouble()
401
402    def isRouteValid(self, vehID):
403        """isRouteValid(string) -> bool
404        Returns whether the current vehicle route is connected for the vehicle
405        class of the given vehicle.
406        """
407        return self._getUniversal(tc.VAR_ROUTE_VALID, vehID)
408
409    def getSignals(self, vehID):
410        """getSignals(string) -> integer
411
412        Returns an integer encoding the state of a vehicle's signals.
413        """
414        return self._getUniversal(tc.VAR_SIGNALS, vehID)
415
416    def getLength(self, vehID):
417        """getLength(string) -> double
418
419        Returns the length in m of the given vehicle.
420        """
421        return self._getUniversal(tc.VAR_LENGTH, vehID)
422
423    def getMaxSpeed(self, vehID):
424        """getMaxSpeed(string) -> double
425
426        Returns the maximum speed in m/s of this vehicle.
427        """
428        return self._getUniversal(tc.VAR_MAXSPEED, vehID)
429
430    def getLateralLanePosition(self, vehID):
431        """getLateralLanePosition(string) -> double
432
433        Returns The lateral position of the vehicle on its current lane measured in m.
434        """
435        return self._getUniversal(tc.VAR_LANEPOSITION_LAT, vehID)
436
437    def getMaxSpeedLat(self, vehID):
438        """getMaxSpeedLat(string) -> double
439
440        Returns the maximum lateral speed in m/s of this vehicle.
441        """
442        return self._getUniversal(tc.VAR_MAXSPEED_LAT, vehID)
443
444    def getLateralAlignment(self, vehID):
445        """getLateralAlignment(string) -> string
446
447        Returns The preferred lateral alignment of the vehicle
448        """
449        return self._getUniversal(tc.VAR_LATALIGNMENT, vehID)
450
451    def getMinGapLat(self, vehID):
452        """getMinGapLat(string) -> double
453
454        Returns The desired lateral gap of this vehicle at 50km/h in m
455        """
456        return self._getUniversal(tc.VAR_MINGAP_LAT, vehID)
457
458    def getAllowedSpeed(self, vehID):
459        """getAllowedSpeed(string) -> double
460
461        Returns the maximum allowed speed on the current lane regarding speed factor in m/s for this vehicle.
462        """
463        return self._getUniversal(tc.VAR_ALLOWED_SPEED, vehID)
464
465    def getVehicleClass(self, vehID):
466        """getVehicleClass(string) -> string
467
468        Returns the vehicle class of this vehicle.
469        """
470        return self._getUniversal(tc.VAR_VEHICLECLASS, vehID)
471
472    def getSpeedFactor(self, vehID):
473        """getSpeedFactor(string) -> double
474
475        Returns the chosen speed factor for this vehicle.
476        """
477        return self._getUniversal(tc.VAR_SPEED_FACTOR, vehID)
478
479    def getSpeedDeviation(self, vehID):
480        """getSpeedDeviation(string) -> double
481
482        Returns the standard deviation for the speed factor of the vehicle type.
483        """
484        return self._getUniversal(tc.VAR_SPEED_DEVIATION, vehID)
485
486    def getEmissionClass(self, vehID):
487        """getEmissionClass(string) -> string
488
489        Returns the emission class of this vehicle.
490        """
491        return self._getUniversal(tc.VAR_EMISSIONCLASS, vehID)
492
493    def getWaitingTime(self, vehID):
494        """getWaitingTime() -> double
495        The waiting time of a vehicle is defined as the time (in seconds) spent with a
496        speed below 0.1m/s since the last time it was faster than 0.1m/s.
497        (basically, the waiting time of a vehicle is reset to 0 every time it moves).
498        A vehicle that is stopping intentionally with a <stop> does not accumulate waiting time.
499        """
500        return self._getUniversal(tc.VAR_WAITING_TIME, vehID)
501
502    def getAccumulatedWaitingTime(self, vehID):
503        """getAccumulatedWaitingTime() -> double
504        The accumulated waiting time of a vehicle collects the vehicle's waiting time
505        over a certain time interval (interval length is set per option '--waiting-time-memory')
506        """
507        return self._getUniversal(tc.VAR_ACCUMULATED_WAITING_TIME, vehID)
508
509    def getLaneChangeMode(self, vehID):
510        """getLaneChangeMode(string) -> integer
511
512        Gets the vehicle's lane change mode as a bitset.
513        """
514        return self._getUniversal(tc.VAR_LANECHANGE_MODE, vehID)
515
516    def getSpeedMode(self, vehID):
517        """getSpeedMode -> int
518        The speed mode of a vehicle
519        """
520        return self._getUniversal(tc.VAR_SPEEDSETMODE, vehID)
521
522    def getSlope(self, vehID):
523        """getSlope -> double
524        The slope at the current position of the vehicle in degrees
525        """
526        return self._getUniversal(tc.VAR_SLOPE, vehID)
527
528    def getWidth(self, vehID):
529        """getWidth(string) -> double
530
531        Returns the width in m of this vehicle.
532        """
533        return self._getUniversal(tc.VAR_WIDTH, vehID)
534
535    def getHeight(self, vehID):
536        """getHeight(string) -> double
537
538        Returns the height in m of this vehicle.
539        """
540        return self._getUniversal(tc.VAR_HEIGHT, vehID)
541
542    def getLine(self, vehID):
543        """getLine(string) -> string
544
545        Returns the line information of this vehicle.
546        """
547        return self._getUniversal(tc.VAR_LINE, vehID)
548
549    def getVia(self, vehID):
550        """getVia(string) -> list(string)
551
552        Returns the ids of via edges for this vehicle
553        """
554        return self._getUniversal(tc.VAR_VIA, vehID)
555
556    def getMinGap(self, vehID):
557        """getMinGap(string) -> double
558
559        Returns the offset (gap to front vehicle if halting) of this vehicle.
560        """
561        return self._getUniversal(tc.VAR_MINGAP, vehID)
562
563    def getShapeClass(self, vehID):
564        """getShapeClass(string) -> string
565
566        Returns the shape class of this vehicle.
567        """
568        return self._getUniversal(tc.VAR_SHAPECLASS, vehID)
569
570    def getAccel(self, vehID):
571        """getAccel(string) -> double
572
573        Returns the maximum acceleration possibility in m/s^2 of this vehicle.
574        """
575        return self._getUniversal(tc.VAR_ACCEL, vehID)
576
577    def getDecel(self, vehID):
578        """getDecel(string) -> double
579
580        Returns the preferred maximal deceleration possibility in m/s^2 of this vehicle.
581        """
582        return self._getUniversal(tc.VAR_DECEL, vehID)
583
584    def getEmergencyDecel(self, vehID):
585        """getEmergencyDecel(string) -> double
586
587        Returns the maximal physically possible deceleration in m/s^2 of this vehicle.
588        """
589        return self._getUniversal(tc.VAR_EMERGENCY_DECEL, vehID)
590
591    def getApparentDecel(self, vehID):
592        """getApparentDecel(string) -> double
593
594        Returns the apparent deceleration in m/s^2 of this vehicle.
595        """
596        return self._getUniversal(tc.VAR_APPARENT_DECEL, vehID)
597
598    def getActionStepLength(self, vehID):
599        """getActionStepLength(string) -> double
600
601        Returns the action step length for this vehicle.
602        """
603        return self._getUniversal(tc.VAR_ACTIONSTEPLENGTH, vehID)
604
605    def getLastActionTime(self, vehID):
606        """getLastActionTime(string) -> double
607
608        Returns the time of last action point for this vehicle.
609        """
610        return self._getUniversal(tc.VAR_LASTACTIONTIME, vehID)
611
612    def getImperfection(self, vehID):
613        """getImperfection(string) -> double
614
615        .
616        """
617        return self._getUniversal(tc.VAR_IMPERFECTION, vehID)
618
619    def getTau(self, vehID):
620        """getTau(string) -> double
621
622        Returns the driver's reaction time in s for this vehicle.
623        """
624        return self._getUniversal(tc.VAR_TAU, vehID)
625
626    def getBestLanes(self, vehID):
627        """getBestLanes(string) ->
628
629        Information about the wish to use subsequent edges' lanes.
630        """
631        return self._getUniversal(tc.VAR_BEST_LANES, vehID)
632
633    def getLeader(self, vehID, dist=0.):
634        """getLeader(string, double) -> (string, double)
635
636        Return the leading vehicle id together with the distance. The distance
637        is measured from the front + minGap to the back of the leader, so it does not include the
638        minGap of the vehicle.
639        The dist parameter defines the maximum lookahead, 0 calculates a lookahead from the brake gap.
640        Note that the returned leader may be farther away than the given dist.
641        """
642        self._connection._beginMessage(
643            tc.CMD_GET_VEHICLE_VARIABLE, tc.VAR_LEADER, vehID, 1 + 8)
644        self._connection._string += struct.pack("!Bd", tc.TYPE_DOUBLE, dist)
645        return _readLeader(self._connection._checkResult(tc.CMD_GET_VEHICLE_VARIABLE, tc.VAR_LEADER, vehID))
646
647    def getRightFollowers(self, vehID, blockingOnly=False):
648        """ bool -> list(pair(string, double))
649        Convenience method, see getNeighbors()
650        """
651        if blockingOnly:
652            mode = 5
653        else:
654            mode = 1
655        return self.getNeighbors(vehID, mode)
656
657    def getRightLeaders(self, vehID, blockingOnly=False):
658        """ bool -> list(pair(string, double))
659        Convenience method, see getNeighbors()
660        """
661        if blockingOnly:
662            mode = 7
663        else:
664            mode = 3
665        return self.getNeighbors(vehID, mode)
666
667    def getLeftFollowers(self, vehID, blockingOnly=False):
668        """ bool -> list(pair(string, double))
669        Convenience method, see getNeighbors()
670        """
671        if blockingOnly:
672            mode = 4
673        else:
674            mode = 0
675        return self.getNeighbors(vehID, mode)
676
677    def getLeftLeaders(self, vehID, blockingOnly=False):
678        """ bool -> list(pair(string, double))
679        Convenience method, see getNeighbors()
680        """
681        if blockingOnly:
682            mode = 6
683        else:
684            mode = 2
685        return self.getNeighbors(vehID, mode)
686
687    def getNeighbors(self, vehID, mode):
688        """ byte -> list(pair(string, double))
689
690        The parameter mode is a bitset (UBYTE), specifying the following:
691        bit 1: query lateral direction (left:0, right:1)
692        bit 2: query longitudinal direction (followers:0, leaders:1)
693        bit 3: blocking (return all:0, return only blockers:1)
694
695        The returned list contains pairs (ID, dist) for all lane change relevant neighboring leaders, resp. followers,
696        along with their longitudinal distance to the ego vehicle (egoFront - egoMinGap to leaderBack, resp.
697        followerFront - followerMinGap to egoBack. The value can be negative for overlapping neighs).
698        For the non-sublane case, the lists will contain at most one entry.
699
700        Note: The exact set of blockers in case blocking==1 is not determined for the sublane model,
701        but either all neighboring vehicles are returned (in case LCA_BLOCKED) or
702        none is returned (in case !LCA_BLOCKED).
703        """
704        self._connection._beginMessage(tc.CMD_GET_VEHICLE_VARIABLE, tc.VAR_NEIGHBORS, vehID, 2)
705        self._connection._string += struct.pack("!BB", tc.TYPE_UBYTE, mode)
706        return _readNeighbors(self._connection._checkResult(tc.CMD_GET_VEHICLE_VARIABLE, tc.VAR_NEIGHBORS, vehID))
707
708    def getNextTLS(self, vehID):
709        """getNextTLS(string) ->
710
711        Return list of upcoming traffic lights [(tlsID, tlsIndex, distance, state), ...]
712        """
713        return self._getUniversal(tc.VAR_NEXT_TLS, vehID)
714
715    def getNextStops(self, vehID):
716        """getNextStop(string) -> [(string, double, string, int, int, int)], ...
717
718        Return list of upcoming stops [(lane, endPos, stoppingPlaceID, stopFlags, duration, until), ...]
719        where integer stopFlag is defined as:
720               1 * stopped +
721               2 * parking +
722               4 * personTriggered +
723               8 * containerTriggered +
724              16 * isBusStop +
725              32 * isContainerStop +
726              64 * chargingStation +
727             128 * parkingarea
728        with each of these flags defined as 0 or 1.
729        """
730        return self._getUniversal(tc.VAR_NEXT_STOPS, vehID)
731
732    def subscribeLeader(self, vehID, dist=0., begin=0, end=2**31 - 1):
733        """subscribeLeader(string, double) -> None
734
735        Subscribe for the leading vehicle id together with the distance.
736        The dist parameter defines the maximum lookahead, 0 calculates a lookahead from the brake gap.
737        """
738        self._connection._subscribe(tc.CMD_SUBSCRIBE_VEHICLE_VARIABLE, begin, end, vehID,
739                                    (tc.VAR_LEADER,), {tc.VAR_LEADER: struct.pack("!Bd", tc.TYPE_DOUBLE, dist)})
740
741    def getDrivingDistance(self, vehID, edgeID, pos, laneIndex=0):
742        """getDrivingDistance(string, string, double, integer) -> double
743
744        Return the distance to the given edge and position along the vehicles route.
745        """
746        self._connection._beginMessage(tc.CMD_GET_VEHICLE_VARIABLE, tc.DISTANCE_REQUEST,
747                                       vehID, 1 + 4 + 1 + 4 + len(edgeID) + 8 + 1 + 1)
748        self._connection._string += struct.pack("!Bi", tc.TYPE_COMPOUND, 2)
749        self._connection._packString(edgeID, tc.POSITION_ROADMAP)
750        self._connection._string += struct.pack("!dBB",
751                                                pos, laneIndex, tc.REQUEST_DRIVINGDIST)
752        return self._connection._checkResult(tc.CMD_GET_VEHICLE_VARIABLE, tc.DISTANCE_REQUEST, vehID).readDouble()
753
754    def getDrivingDistance2D(self, vehID, x, y):
755        """getDrivingDistance2D(string, double, double) -> integer
756
757        Return the distance to the given network position along the vehicles route.
758        """
759        self._connection._beginMessage(
760            tc.CMD_GET_VEHICLE_VARIABLE, tc.DISTANCE_REQUEST, vehID, 1 + 4 + 1 + 8 + 8 + 1)
761        self._connection._string += struct.pack("!BiBddB", tc.TYPE_COMPOUND, 2,
762                                                tc.POSITION_2D, x, y, tc.REQUEST_DRIVINGDIST)
763        return self._connection._checkResult(tc.CMD_GET_VEHICLE_VARIABLE, tc.DISTANCE_REQUEST, vehID).readDouble()
764
765    def getDistance(self, vehID):
766        """getDistance(string) -> double
767
768        Returns the distance to the starting point like an odometer
769        """
770        return self._getUniversal(tc.VAR_DISTANCE, vehID)
771
772    def getStopState(self, vehID):
773        """getStopState(string) -> integer
774
775        Returns information in regard to stopping:
776        The returned integer is defined as 1 * stopped + 2 * parking
777        + 4 * personTriggered + 8 * containerTriggered + 16 * isBusStop
778        + 32 * isContainerStop
779        with each of these flags defined as 0 or 1
780        """
781        return self._getUniversal(tc.VAR_STOPSTATE, vehID)
782
783    def isStopped(self, vehID):
784        """isStopped(string) -> bool
785        Return whether the vehicle is stopped
786        """
787        return (self.getStopState(vehID) & 1) == 1
788
789    def isStoppedParking(self, vehID):
790        """isStoppedParking(string) -> bool
791        Return whether the vehicle is parking (implies stopped)
792        """
793        return (self.getStopState(vehID) & 2) == 2
794
795    def isStoppedTriggered(self, vehID):
796        """isStoppedTriggered(string) -> bool
797        Return whether the vehicle is stopped and waiting for a person or container
798        """
799        return (self.getStopState(vehID) & 12) > 0
800
801    def isAtBusStop(self, vehID):
802        """isAtBusStop(string) -> bool
803        Return whether the vehicle is stopped at a bus stop
804        """
805        return (self.getStopState(vehID) & 16) == 16
806
807    def isAtContainerStop(self, vehID):
808        """isAtContainerStop(string) -> bool
809        Return whether the vehicle is stopped at a container stop
810        """
811        return (self.getStopState(vehID) & 32) == 32
812
813    def getLaneChangeState(self, vehID, direction):
814        """getLaneChangeState(string, int) -> (int, int)
815        Return the lane change state for the vehicle
816        """
817        self._connection._beginMessage(
818            tc.CMD_GET_VEHICLE_VARIABLE, tc.CMD_CHANGELANE, vehID, 1 + 4)
819        self._connection._string += struct.pack("!Bi", tc.TYPE_INTEGER, direction)
820        result = self._connection._checkResult(tc.CMD_GET_VEHICLE_VARIABLE, tc.CMD_CHANGELANE, vehID)
821        return result.read("!iBiBi")[2::2]  # ignore num compounds and type int
822
823    def getLaneChangeStatePretty(self, vehID, direction):
824        """getLaneChangeState(string, int) -> ([string, ...], [string, ...])
825        Return the lane change state for the vehicle as a list of string constants
826        """
827        constants = {
828            0: 'stay',
829            1: 'left',
830            2: 'right',
831            3: 'strategic',
832            4: 'cooperative',
833            5: 'speedGain',
834            6: 'keepRight',
835            7: 'TraCI',
836            8: 'urgent',
837            9: 'blocked by left leader',
838            10: 'blocked by left follower',
839            11: 'blocked by right leader',
840            12: 'bloecked by right follower',
841            13: 'overlapping',
842            14: 'insufficient space',
843            15: 'sublane',
844        }
845
846        def prettifyBitstring(intval):
847            return [v for k, v in constants.items() if (intval & 2**k)]
848
849        state, stateTraCI = self.getLaneChangeState(vehID, direction)
850        return prettifyBitstring(state), prettifyBitstring(stateTraCI)
851
852    def couldChangeLane(self, vehID, direction, state=None):
853        """couldChangeLane(string, int) -> bool
854        Return whether the vehicle could change lanes in the specified direction
855        """
856        if state is None:
857            state, stateTraCI = self.getLaneChangeState(vehID, direction)
858            if self.wantsAndCouldChangeLane(vehID, direction, stateTraCI):
859                # vehicle changed in the last step. state is no longer applicable
860                return False
861        return state != tc.LCA_UNKNOWN and (state & tc.LCA_BLOCKED == 0)
862
863    def wantsAndCouldChangeLane(self, vehID, direction, state=None):
864        """wantsAndCouldChangeLane(string, int) -> bool
865        Return whether the vehicle wants to and could change lanes in the specified direction
866        """
867        if state is None:
868            state, stateTraCI = self.getLaneChangeState(vehID, direction)
869            if self.wantsAndCouldChangeLane(vehID, direction, stateTraCI):
870                # vehicle changed in the last step. state is no longer applicable
871                return False
872        if state & tc.LCA_BLOCKED == 0:
873            if direction == -1:
874                return state & tc.LCA_RIGHT != 0
875            if direction == 1:
876                return state & tc.LCA_LEFT != 0
877        return False
878
879    def getRoutingMode(self, vehID):
880        """returns the current routing mode:
881        tc.ROUTING_MODE_DEFAULT    : use weight storages and fall-back to edge speeds (default)
882        tc.ROUTING_MODE_AGGREGATED : use global smoothed travel times from device.rerouting
883        """
884        return self._getUniversal(tc.VAR_ROUTING_MODE, vehID)
885
886    def setMaxSpeed(self, vehID, speed):
887        """setMaxSpeed(string, double) -> None
888
889        Sets the maximum speed in m/s for this vehicle.
890        """
891        self._connection._sendDoubleCmd(
892            tc.CMD_SET_VEHICLE_VARIABLE, tc.VAR_MAXSPEED, vehID, speed)
893
894    def setMaxSpeedLat(self, vehID, speed):
895        """setMaxSpeedLat(string, double) -> None
896
897        Sets the maximum lateral speed in m/s for this vehicle.
898        """
899        self._connection._sendDoubleCmd(
900            tc.CMD_SET_VEHICLE_VARIABLE, tc.VAR_MAXSPEED_LAT, vehID, speed)
901
902    def rerouteParkingArea(self, vehID, parkingAreaID):
903        """rerouteParkingArea(string, string)
904
905        Changes the next parking area in parkingAreaID, updates the vehicle route,
906        and preserve consistency in case of passengers/containers on board.
907        """
908        self._connection._beginMessage(tc.CMD_SET_VEHICLE_VARIABLE, tc.CMD_REROUTE_TO_PARKING, vehID,
909                                       1 + 4 +  # compound
910                                       1 + 4 + len(parkingAreaID))
911        self._connection._string += struct.pack("!Bi", tc.TYPE_COMPOUND, 1)
912        self._connection._packString(parkingAreaID)
913        self._connection._sendExact()
914
915    def setStop(self, vehID, edgeID, pos=1., laneIndex=0, duration=tc.INVALID_DOUBLE_VALUE,
916                flags=tc.STOP_DEFAULT, startPos=tc.INVALID_DOUBLE_VALUE, until=tc.INVALID_DOUBLE_VALUE):
917        """setStop(string, string, double, integer, double, integer, double, double) -> None
918
919        Adds or modifies a stop with the given parameters. The duration and the until attribute are
920        in seconds.
921        """
922        if type(duration) is int and duration >= 1000 and duration % 1000 == 0:
923            warnings.warn("API change now handles duration as floating point seconds", stacklevel=2)
924        self._connection._beginMessage(tc.CMD_SET_VEHICLE_VARIABLE, tc.CMD_STOP,
925                                       vehID, (1 + 4 + 1 + 4 + len(edgeID) + 1 + 8 + 1 + 1 +
926                                               1 + 8 + 1 + 1 + 1 + 8 + 1 + 8))
927        self._connection._string += struct.pack("!Bi", tc.TYPE_COMPOUND, 7)
928        self._connection._packString(edgeID)
929        self._connection._string += struct.pack("!BdBBBdBB", tc.TYPE_DOUBLE, pos,
930                                                tc.TYPE_BYTE, laneIndex, tc.TYPE_DOUBLE, duration, tc.TYPE_BYTE, flags)
931        self._connection._string += struct.pack("!BdBd",
932                                                tc.TYPE_DOUBLE, startPos, tc.TYPE_DOUBLE, until)
933        self._connection._sendExact()
934
935    def setBusStop(self, vehID, stopID, duration=tc.INVALID_DOUBLE_VALUE,
936                   until=tc.INVALID_DOUBLE_VALUE, flags=tc.STOP_DEFAULT):
937        """setBusStop(string, string, double, double, integer) -> None
938
939        Adds or modifies a bus stop with the given parameters. The duration and the until attribute are
940        in seconds.
941        """
942        self.setStop(vehID, stopID, duration=duration,
943                     until=until, flags=flags | tc.STOP_BUS_STOP)
944
945    def setContainerStop(self, vehID, stopID, duration=tc.INVALID_DOUBLE_VALUE,
946                         until=tc.INVALID_DOUBLE_VALUE, flags=tc.STOP_DEFAULT):
947        """setContainerStop(string, string, double, double, integer) -> None
948
949        Adds or modifies a container stop with the given parameters. The duration and the until attribute are
950        in seconds.
951        """
952        self.setStop(vehID, stopID, duration=duration, until=until,
953                     flags=flags | tc.STOP_CONTAINER_STOP)
954
955    def setChargingStationStop(self, vehID, stopID, duration=tc.INVALID_DOUBLE_VALUE,
956                               until=tc.INVALID_DOUBLE_VALUE, flags=tc.STOP_DEFAULT):
957        """setChargingStationStop(string, string, double, double, integer) -> None
958
959        Adds or modifies a stop at a chargingStation with the given parameters. The duration and the until attribute are
960        in seconds.
961        """
962        self.setStop(vehID, stopID, duration=duration, until=until,
963                     flags=flags | tc.STOP_CHARGING_STATION)
964
965    def setParkingAreaStop(self, vehID, stopID, duration=tc.INVALID_DOUBLE_VALUE,
966                           until=tc.INVALID_DOUBLE_VALUE, flags=tc.STOP_PARKING):
967        """setParkingAreaStop(string, string, double, double, integer) -> None
968
969        Adds or modifies a stop at a parkingArea with the given parameters. The duration and the until attribute are
970        in seconds.
971        """
972        self.setStop(vehID, stopID, duration=duration, until=until,
973                     flags=flags | tc.STOP_PARKING_AREA)
974
975    def resume(self, vehID):
976        """resume(string) -> None
977
978        Resumes the vehicle from the current stop (throws an error if the vehicle is not stopped).
979        """
980        self._connection._beginMessage(
981            tc.CMD_SET_VEHICLE_VARIABLE, tc.CMD_RESUME, vehID, 1 + 4)
982        self._connection._string += struct.pack("!Bi", tc.TYPE_COMPOUND, 0)
983        self._connection._sendExact()
984
985    def changeLane(self, vehID, laneIndex, duration):
986        """changeLane(string, int, double) -> None
987
988        Forces a lane change to the lane with the given index; if successful,
989        the lane will be chosen for the given amount of time (in s).
990        """
991        if type(duration) is int and duration >= 1000:
992            warnings.warn("API change now handles duration as floating point seconds", stacklevel=2)
993        self._connection._beginMessage(
994            tc.CMD_SET_VEHICLE_VARIABLE, tc.CMD_CHANGELANE, vehID, 1 + 4 + 1 + 1 + 1 + 8)
995        self._connection._string += struct.pack(
996            "!BiBBBd", tc.TYPE_COMPOUND, 2, tc.TYPE_BYTE, laneIndex, tc.TYPE_DOUBLE, duration)
997        self._connection._sendExact()
998
999    def changeLaneRelative(self, vehID, indexOffset, duration):
1000        """changeLaneRelative(string, int, double) -> None
1001
1002        Forces a relative lane change; if successful,
1003        the lane will be chosen for the given amount of time (in s).
1004        The indexOffset specifies the target lane relative to the vehicles current lane
1005        """
1006        if type(duration) is int and duration >= 1000:
1007            warnings.warn("API change now handles duration as floating point seconds", stacklevel=2)
1008        self._connection._beginMessage(
1009            tc.CMD_SET_VEHICLE_VARIABLE, tc.CMD_CHANGELANE, vehID, 1 + 4 + 1 + 1 + 1 + 8 + 1 + 1)
1010        self._connection._string += struct.pack(
1011            "!BiBBBdBB", tc.TYPE_COMPOUND, 3, tc.TYPE_BYTE, indexOffset, tc.TYPE_DOUBLE, duration, tc.TYPE_BYTE, 1)
1012        self._connection._sendExact()
1013
1014    def changeSublane(self, vehID, latDist):
1015        """changeLane(string, double) -> None
1016        Forces a lateral change by the given amount (negative values indicate changing to the right, positive
1017        to the left). This will override any other lane change motivations but conform to
1018        safety-constraints as configured by laneChangeMode.
1019        """
1020        self._connection._sendDoubleCmd(
1021            tc.CMD_SET_VEHICLE_VARIABLE, tc.CMD_CHANGESUBLANE, vehID, latDist)
1022
1023    def slowDown(self, vehID, speed, duration):
1024        """slowDown(string, double, double) -> None
1025
1026        Changes the speed smoothly to the given value over the given amount
1027        of time in seconds (can also be used to increase speed).
1028        """
1029        if type(duration) is int and duration >= 1000:
1030            warnings.warn("API change now handles duration as floating point seconds", stacklevel=2)
1031        self._connection._beginMessage(
1032            tc.CMD_SET_VEHICLE_VARIABLE, tc.CMD_SLOWDOWN, vehID, 1 + 4 + 1 + 8 + 1 + 8)
1033        self._connection._string += struct.pack(
1034            "!BiBdBd", tc.TYPE_COMPOUND, 2, tc.TYPE_DOUBLE, speed, tc.TYPE_DOUBLE, duration)
1035        self._connection._sendExact()
1036
1037    def openGap(self, vehID, newTimeHeadway, newSpaceHeadway, duration, changeRate, maxDecel=-1, referenceVehID=None):
1038        """openGap(string, double, double, double, double, double, string) -> None
1039
1040        Changes the vehicle's desired time headway (cf-parameter tau) smoothly to the given new value
1041        using the given change rate. Similarly, the given space headway is applied gradually
1042        to achieve a minimal spatial gap.
1043        The vehicle is commanded to keep the increased headway for
1044        the given duration once its target value is attained. The maximal value for the
1045        deceleration can be given to prevent harsh braking due to the change of tau. If maxDecel=-1,
1046        the limit determined by the CF model is used.
1047        A vehicle ID for a reference vehicle can optionally be given, otherwise, the gap is created with
1048        respect to the current leader on the ego vehicle's current lane.
1049        Note that this does only affect the following behavior regarding the current leader and does
1050        not influence the gap acceptance during lane change, etc.
1051        """
1052        if type(duration) is int and duration >= 1000:
1053            warnings.warn("API change now handles duration as floating point seconds", stacklevel=2)
1054        nParams = 5
1055        # compoundType, nParams, float params (2 newHeadways, duration, changeRate, maxDecel)
1056        msgLength = 1 + 4 + (1 + 8) * nParams
1057        if referenceVehID is not None:
1058            nParams = 6
1059            msgLength += 1 + 4 + len(referenceVehID)  # TYPE_STRING, len, referenceVehID
1060        self._connection._beginMessage(tc.CMD_SET_VEHICLE_VARIABLE, tc.CMD_OPENGAP, vehID, msgLength)
1061        self._connection._string += struct.pack("!BiBdBdBdBdBd", tc.TYPE_COMPOUND, nParams,
1062                                                tc.TYPE_DOUBLE, newTimeHeadway, tc.TYPE_DOUBLE, newSpaceHeadway,
1063                                                tc.TYPE_DOUBLE, duration, tc.TYPE_DOUBLE, changeRate,
1064                                                tc.TYPE_DOUBLE, maxDecel)
1065        if nParams == 6:
1066            self._connection._packString(referenceVehID)
1067        self._connection._sendExact()
1068
1069    def deactivateGapControl(self, vehID):
1070        """deactivateGapControl(string) -> None
1071
1072        Deactivate the vehicle's gap control
1073        """
1074        self.openGap(vehID, -1, -1, -1, -1)
1075
1076    def requestToC(self, vehID, leadTime):
1077        """ requestToC(string, double) -> None
1078
1079        Interface for triggering a transition of control for a vehicle equipped with a ToC device.
1080        """
1081        self.setParameter(vehID, "device.toc.requestToC", str(leadTime))
1082
1083    def changeTarget(self, vehID, edgeID):
1084        """changeTarget(string, string) -> None
1085
1086        The vehicle's destination edge is set to the given edge id. The route is rebuilt.
1087        """
1088        self._connection._sendStringCmd(
1089            tc.CMD_SET_VEHICLE_VARIABLE, tc.CMD_CHANGETARGET, vehID, edgeID)
1090
1091    def setType(self, vehID, typeID):
1092        """setType(string, string) -> None
1093
1094        Sets the id of the type for the named vehicle.
1095        """
1096        self._connection._sendStringCmd(
1097            tc.CMD_SET_VEHICLE_VARIABLE, tc.VAR_TYPE, vehID, typeID)
1098
1099    def setRouteID(self, vehID, routeID):
1100        """setRouteID(string, string) -> None
1101
1102        Changes the vehicles route to the route with the given id.
1103        """
1104        self._connection._sendStringCmd(
1105            tc.CMD_SET_VEHICLE_VARIABLE, tc.VAR_ROUTE_ID, vehID, routeID)
1106
1107    def setRoute(self, vehID, edgeList):
1108        """
1109        setRoute(string, list) ->  None
1110
1111        changes the vehicle route to given edges list.
1112        The first edge in the list has to be the one that the vehicle is at at the moment.
1113
1114        example usage:
1115        setRoute('1', ['1', '2', '4', '6', '7'])
1116
1117        this changes route for vehicle id 1 to edges 1-2-4-6-7
1118        """
1119        if isinstance(edgeList, str):
1120            edgeList = [edgeList]
1121        self._connection._beginMessage(tc.CMD_SET_VEHICLE_VARIABLE, tc.VAR_ROUTE, vehID,
1122                                       1 + 4 + sum(map(len, edgeList)) + 4 * len(edgeList))
1123        self._connection._packStringList(edgeList)
1124        self._connection._sendExact()
1125
1126    def updateBestLanes(self, vehID):
1127        """ updateBestLanes(string) -> None
1128        Triggers an update of the vehicle's bestLanes (structure determining the lane preferences used by LC models)
1129        It may be called after modifying the vClass for instance.
1130        """
1131        self._connection._beginMessage(tc.CMD_SET_VEHICLE_VARIABLE, tc.VAR_UPDATE_BESTLANES, vehID)
1132
1133    def setAdaptedTraveltime(self, vehID, edgeID, time=None, begTime=None, endTime=None):
1134        """setAdaptedTraveltime(string, string, double, double, double) -> None
1135        Inserts the information about the travel time of edge "edgeID" valid
1136        from begin time to end time into the vehicle's internal edge weights
1137        container.
1138        If the time is not specified, any previously set values for that edge
1139        are removed.
1140        If begTime or endTime are not specified the value is set for the whole
1141        simulation duration.
1142        """
1143        if type(edgeID) != str and type(begTime) == str:
1144            # legacy handling
1145            warnings.warn(
1146                "Parameter order has changed for setAdaptedTraveltime(). Attempting legacy ordering. " +
1147                "Please update your code.", stacklevel=2)
1148            return self.setAdaptedTraveltime(vehID, begTime, endTime, edgeID, time)
1149        if time is None:
1150            # reset
1151            self._connection._beginMessage(tc.CMD_SET_VEHICLE_VARIABLE, tc.VAR_EDGE_TRAVELTIME,
1152                                           vehID, 1 + 4 + 1 + 4 + len(edgeID))
1153            self._connection._string += struct.pack("!Bi", tc.TYPE_COMPOUND, 1)
1154            self._connection._packString(edgeID)
1155            self._connection._sendExact()
1156        elif begTime is None:
1157            # set value for the whole simulation
1158            self._connection._beginMessage(tc.CMD_SET_VEHICLE_VARIABLE, tc.VAR_EDGE_TRAVELTIME,
1159                                           vehID, 1 + 4 + 1 + 4 + len(edgeID) + 1 + 8)
1160            self._connection._string += struct.pack("!Bi", tc.TYPE_COMPOUND, 2)
1161            self._connection._packString(edgeID)
1162            self._connection._string += struct.pack("!Bd", tc.TYPE_DOUBLE, time)
1163            self._connection._sendExact()
1164        else:
1165            self._connection._beginMessage(tc.CMD_SET_VEHICLE_VARIABLE, tc.VAR_EDGE_TRAVELTIME,
1166                                           vehID, 1 + 4 + 1 + 8 + 1 + 8 + 1 + 4 + len(edgeID) + 1 + 8)
1167            self._connection._string += struct.pack("!BiBdBd", tc.TYPE_COMPOUND, 4, tc.TYPE_DOUBLE, begTime,
1168                                                    tc.TYPE_DOUBLE, endTime)
1169            self._connection._packString(edgeID)
1170            self._connection._string += struct.pack("!Bd", tc.TYPE_DOUBLE, time)
1171            self._connection._sendExact()
1172
1173    def setEffort(self, vehID, edgeID, effort=None, begTime=None, endTime=None):
1174        """setEffort(string, string, double, double, double) -> None
1175        Inserts the information about the effort of edge "edgeID" valid from
1176        begin time to end time into the vehicle's internal edge weights
1177        container.
1178        If the time is not specified, any previously set values for that edge
1179        are removed.
1180        If begTime or endTime are not specified the value is set for the whole
1181        simulation duration.
1182        """
1183        if type(edgeID) != str and type(begTime) == str:
1184            # legacy handling
1185            warnings.warn(
1186                "Parameter order has changed for setEffort(). Attempting legacy ordering. Please update your code.",
1187                stacklevel=2)
1188            return self.setEffort(vehID, begTime, endTime, edgeID, effort)
1189        if effort is None:
1190            # reset
1191            self._connection._beginMessage(tc.CMD_SET_VEHICLE_VARIABLE, tc.VAR_EDGE_EFFORT,
1192                                           vehID, 1 + 4 + 1 + 4 + len(edgeID))
1193            self._connection._string += struct.pack("!Bi", tc.TYPE_COMPOUND, 1)
1194            self._connection._packString(edgeID)
1195            self._connection._sendExact()
1196        elif begTime is None:
1197            # set value for the whole simulation
1198            self._connection._beginMessage(tc.CMD_SET_VEHICLE_VARIABLE, tc.VAR_EDGE_EFFORT,
1199                                           vehID, 1 + 4 + 1 + 4 + len(edgeID) + 1 + 8)
1200            self._connection._string += struct.pack("!Bi", tc.TYPE_COMPOUND, 2)
1201            self._connection._packString(edgeID)
1202            self._connection._string += struct.pack("!Bd", tc.TYPE_DOUBLE, effort)
1203            self._connection._sendExact()
1204        else:
1205            self._connection._beginMessage(tc.CMD_SET_VEHICLE_VARIABLE, tc.VAR_EDGE_EFFORT,
1206                                           vehID, 1 + 4 + 1 + 8 + 1 + 8 + 1 + 4 + len(edgeID) + 1 + 8)
1207            self._connection._string += struct.pack("!BiBdBd", tc.TYPE_COMPOUND, 4, tc.TYPE_DOUBLE, begTime,
1208                                                    tc.TYPE_DOUBLE, endTime)
1209            self._connection._packString(edgeID)
1210            self._connection._string += struct.pack("!Bd", tc.TYPE_DOUBLE, effort)
1211            self._connection._sendExact()
1212
1213    LAST_TRAVEL_TIME_UPDATE = -1
1214
1215    def setRoutingMode(self, vehID, routingMode):
1216        """sets the current routing mode:
1217        tc.ROUTING_MODE_DEFAULT    : use weight storages and fall-back to edge speeds (default)
1218        tc.ROUTING_MODE_AGGREGATED : use global smoothed travel times from device.rerouting
1219        """
1220        self._connection._sendIntCmd(
1221            tc.CMD_SET_VEHICLE_VARIABLE, tc.VAR_ROUTING_MODE, vehID, routingMode)
1222
1223    def rerouteTraveltime(self, vehID, currentTravelTimes=True):
1224        """rerouteTraveltime(string, bool) -> None Reroutes a vehicle. If
1225        currentTravelTimes is True (default) then the current traveltime of the
1226        edges is loaded and used for rerouting. If currentTravelTimes is False
1227        custom travel times are used. The various functions and options for
1228        customizing travel times are described at https://sumo.dlr.de/wiki/Simulation/Routing
1229
1230        When rerouteTraveltime has been called once with option
1231        currentTravelTimes=True, all edge weights are set to the current travel
1232        times at the time of that call (even for subsequent simulation steps).
1233        """
1234        if currentTravelTimes:
1235            time = self._connection.simulation.getTime()
1236            if time != self.LAST_TRAVEL_TIME_UPDATE:
1237                self.LAST_TRAVEL_TIME_UPDATE = time
1238                for edge in self._connection.edge.getIDList():
1239                    self._connection.edge.adaptTraveltime(
1240                        edge, self._connection.edge.getTraveltime(edge))
1241        self._connection._beginMessage(
1242            tc.CMD_SET_VEHICLE_VARIABLE, tc.CMD_REROUTE_TRAVELTIME, vehID, 1 + 4)
1243        self._connection._string += struct.pack("!Bi", tc.TYPE_COMPOUND, 0)
1244        self._connection._sendExact()
1245
1246    def rerouteEffort(self, vehID):
1247        self._connection._beginMessage(
1248            tc.CMD_SET_VEHICLE_VARIABLE, tc.CMD_REROUTE_EFFORT, vehID, 1 + 4)
1249        self._connection._string += struct.pack("!Bi", tc.TYPE_COMPOUND, 0)
1250        self._connection._sendExact()
1251
1252    def setSignals(self, vehID, signals):
1253        """setSignals(string, integer) -> None
1254
1255        Sets an integer encoding the state of the vehicle's signals.
1256        """
1257        self._connection._sendIntCmd(
1258            tc.CMD_SET_VEHICLE_VARIABLE, tc.VAR_SIGNALS, vehID, signals)
1259
1260    def moveTo(self, vehID, laneID, pos):
1261        self._connection._beginMessage(tc.CMD_SET_VEHICLE_VARIABLE,
1262                                       tc.VAR_MOVE_TO, vehID, 1 + 4 + 1 + 4 + len(laneID) + 1 + 8)
1263        self._connection._string += struct.pack("!Bi", tc.TYPE_COMPOUND, 2)
1264        self._connection._packString(laneID)
1265        self._connection._string += struct.pack("!Bd", tc.TYPE_DOUBLE, pos)
1266        self._connection._sendExact()
1267
1268    def setSpeed(self, vehID, speed):
1269        """setSpeed(string, double) -> None
1270
1271        Sets the speed in m/s for the named vehicle within the last step.
1272        Calling with speed=-1 hands the vehicle control back to SUMO.
1273        """
1274        self._connection._sendDoubleCmd(
1275            tc.CMD_SET_VEHICLE_VARIABLE, tc.VAR_SPEED, vehID, speed)
1276
1277    def setColor(self, vehID, color):
1278        """setColor(string, (integer, integer, integer, integer))
1279
1280        Sets the color for the vehicle with the given ID, i.e. (255,0,0) for the color red.
1281        The fourth component (alpha) is optional.
1282        """
1283        self._connection._beginMessage(
1284            tc.CMD_SET_VEHICLE_VARIABLE, tc.VAR_COLOR, vehID, 1 + 1 + 1 + 1 + 1)
1285        self._connection._string += struct.pack("!BBBBB", tc.TYPE_COLOR, int(color[0]), int(color[1]), int(color[2]),
1286                                                int(color[3]) if len(color) > 3 else 255)
1287        self._connection._sendExact()
1288
1289    def setLength(self, vehID, length):
1290        """setLength(string, double) -> None
1291
1292        Sets the length in m for the given vehicle.
1293        """
1294        self._connection._sendDoubleCmd(
1295            tc.CMD_SET_VEHICLE_VARIABLE, tc.VAR_LENGTH, vehID, length)
1296
1297    def setVehicleClass(self, vehID, clazz):
1298        """setVehicleClass(string, string) -> None
1299
1300        Sets the vehicle class for this vehicle.
1301        """
1302        self._connection._sendStringCmd(
1303            tc.CMD_SET_VEHICLE_VARIABLE, tc.VAR_VEHICLECLASS, vehID, clazz)
1304
1305    def setSpeedFactor(self, vehID, factor):
1306        """setSpeedFactor(string, double) -> None
1307
1308        .
1309        """
1310        self._connection._sendDoubleCmd(
1311            tc.CMD_SET_VEHICLE_VARIABLE, tc.VAR_SPEED_FACTOR, vehID, factor)
1312
1313    def setEmissionClass(self, vehID, clazz):
1314        """setEmissionClass(string, string) -> None
1315
1316        Sets the emission class for this vehicle.
1317        """
1318        self._connection._sendStringCmd(
1319            tc.CMD_SET_VEHICLE_VARIABLE, tc.VAR_EMISSIONCLASS, vehID, clazz)
1320
1321    def setWidth(self, vehID, width):
1322        """setWidth(string, double) -> None
1323
1324        Sets the width in m for this vehicle.
1325        """
1326        self._connection._sendDoubleCmd(
1327            tc.CMD_SET_VEHICLE_VARIABLE, tc.VAR_WIDTH, vehID, width)
1328
1329    def setHeight(self, vehID, height):
1330        """setHeight(string, double) -> None
1331
1332        Sets the height in m for this vehicle.
1333        """
1334        self._connection._sendDoubleCmd(
1335            tc.CMD_SET_VEHICLE_VARIABLE, tc.VAR_HEIGHT, vehID, height)
1336
1337    def setLine(self, vehID, line):
1338        """setHeight(string, string) -> None
1339
1340        Sets the line information for this vehicle.
1341        """
1342        self._connection._sendStringCmd(
1343            tc.CMD_SET_VEHICLE_VARIABLE, tc.VAR_LINE, vehID, line)
1344
1345    def setVia(self, vehID, edgeList):
1346        """
1347        setVia(string, list) ->  None
1348
1349        changes the via edges to the given edges list (to be used during
1350        subsequent rerouting calls).
1351
1352        Note: a single edgeId as argument is allowed as shorthand for a list of length 1
1353        """
1354        if isinstance(edgeList, str):
1355            edgeList = [edgeList]
1356        self._connection._beginMessage(tc.CMD_SET_VEHICLE_VARIABLE, tc.VAR_VIA, vehID,
1357                                       1 + 4 + sum(map(len, edgeList)) + 4 * len(edgeList))
1358        self._connection._packStringList(edgeList)
1359        self._connection._sendExact()
1360
1361    def setMinGap(self, vehID, minGap):
1362        """setMinGap(string, double) -> None
1363
1364        Sets the offset (gap to front vehicle if halting) for this vehicle.
1365        """
1366        self._connection._sendDoubleCmd(
1367            tc.CMD_SET_VEHICLE_VARIABLE, tc.VAR_MINGAP, vehID, minGap)
1368
1369    def setMinGapLat(self, vehID, minGapLat):
1370        """setMinGapLat(string, double) -> None
1371
1372        Sets the minimum lateral gap of the vehicle at 50km/h in m
1373        """
1374        self._connection._sendDoubleCmd(
1375            tc.CMD_SET_VEHICLE_VARIABLE, tc.VAR_MINGAP_LAT, vehID, minGapLat)
1376
1377    def setLateralAlignment(self, vehID, align):
1378        """setLateralAlignment(string, string) -> None
1379
1380        Sets the preferred lateral alignment for this vehicle.
1381        """
1382        self._connection._sendStringCmd(
1383            tc.CMD_SET_VEHICLE_VARIABLE, tc.VAR_LATALIGNMENT, vehID, align)
1384
1385    def setShapeClass(self, vehID, clazz):
1386        """setShapeClass(string, string) -> None
1387
1388        Sets the shape class for this vehicle.
1389        """
1390        self._connection._sendStringCmd(
1391            tc.CMD_SET_VEHICLE_VARIABLE, tc.VAR_SHAPECLASS, vehID, clazz)
1392
1393    def setAccel(self, vehID, accel):
1394        """setAccel(string, double) -> None
1395
1396        Sets the maximum acceleration in m/s^2 for this vehicle.
1397        """
1398        self._connection._sendDoubleCmd(
1399            tc.CMD_SET_VEHICLE_VARIABLE, tc.VAR_ACCEL, vehID, accel)
1400
1401    def setDecel(self, vehID, decel):
1402        """setDecel(string, double) -> None
1403
1404        Sets the preferred maximal deceleration in m/s^2 for this vehicle.
1405        """
1406        self._connection._sendDoubleCmd(
1407            tc.CMD_SET_VEHICLE_VARIABLE, tc.VAR_DECEL, vehID, decel)
1408
1409    def setEmergencyDecel(self, vehID, decel):
1410        """setEmergencyDecel(string, double) -> None
1411
1412        Sets the maximal physically possible deceleration in m/s^2 for this vehicle.
1413        """
1414        self._connection._sendDoubleCmd(
1415            tc.CMD_SET_VEHICLE_VARIABLE, tc.VAR_EMERGENCY_DECEL, vehID, decel)
1416
1417    def setApparentDecel(self, vehID, decel):
1418        """setApparentDecel(string, double) -> None
1419
1420        Sets the apparent deceleration in m/s^2 for this vehicle.
1421        """
1422        self._connection._sendDoubleCmd(
1423            tc.CMD_SET_VEHICLE_VARIABLE, tc.VAR_APPARENT_DECEL, vehID, decel)
1424
1425    def setActionStepLength(self, vehID, actionStepLength, resetActionOffset=True):
1426        """setActionStepLength(string, double, bool) -> None
1427
1428        Sets the action step length for this vehicle. If resetActionOffset == True (default), the
1429        next action point is scheduled immediately. if If resetActionOffset == False, the interval
1430        between the last and the next action point is updated to match the given value, or if the latter
1431        is smaller than the time since the last action point, the next action follows immediately.
1432        """
1433        if actionStepLength < 0:
1434            raise TraCIException("Invalid value for actionStepLength. Given value must be non-negative.")
1435        # Use negative value to indicate resetActionOffset == False
1436        if not resetActionOffset:
1437            actionStepLength *= -1
1438        self._connection._sendDoubleCmd(
1439            tc.CMD_SET_VEHICLE_VARIABLE, tc.VAR_ACTIONSTEPLENGTH, vehID, actionStepLength)
1440
1441    def highlight(self, vehID, color=(255, 0, 0, 255), size=-1, alphaMax=-1, duration=-1, type=0):
1442        """ highlight(string, color, float, ubyte) -> void
1443            Adds a circle of the given color tracking the vehicle.
1444            If a positive size [in m] is given the size of the highlight is chosen accordingly,
1445            otherwise the length of the vehicle is used as reference.
1446            If alphaMax and duration are positive, the circle fades in and out within the given duration,
1447            otherwise it permanently follows the vehicle.
1448        """
1449        if (type > 255):
1450            raise TraCIException("poi.highlight(): maximal value for type is 255")
1451        if (alphaMax > 255):
1452            raise TraCIException("vehicle.highlight(): maximal value for alphaMax is 255")
1453        if (alphaMax <= 0 and duration > 0):
1454            raise TraCIException("vehicle.highlight(): duration>0 requires alphaMax>0")
1455        if (alphaMax > 0 and duration <= 0):
1456            raise TraCIException("vehicle.highlight(): alphaMax>0 requires duration>0")
1457
1458        if (type > 0):
1459            compoundLength = 5
1460        elif (alphaMax > 0):
1461            compoundLength = 4
1462        elif (size > 0):
1463            compoundLength = 2
1464        elif color:
1465            compoundLength = 1
1466        else:
1467            compoundLength = 0
1468
1469        msg_length = 1 + 1
1470        if compoundLength >= 1:
1471            msg_length += 1 + 4
1472        if compoundLength >= 2:
1473            msg_length += 1 + 8
1474        if compoundLength >= 3:
1475            msg_length += 1 + 8 + 1 + 1
1476        if compoundLength >= 5:
1477            msg_length += 1 + 1
1478        if not color:
1479            # Send red as highlight standard
1480            color = (255, 0, 0, 255)
1481
1482        self._connection._beginMessage(tc.CMD_SET_VEHICLE_VARIABLE, tc.VAR_HIGHLIGHT, vehID, msg_length)
1483        self._connection._string += struct.pack("!BB", tc.TYPE_COMPOUND, compoundLength)
1484        if (compoundLength >= 1):
1485            self._connection._string += struct.pack("!BBBBB", tc.TYPE_COLOR, int(color[0]), int(color[1]),
1486                                                    int(color[2]), int(color[3]) if len(color) > 3 else 255)
1487        if (compoundLength >= 2):
1488            self._connection._string += struct.pack("!Bd", tc.TYPE_DOUBLE, size)
1489        if (compoundLength >= 3):
1490            self._connection._string += struct.pack("!BB", tc.TYPE_UBYTE, alphaMax)
1491            self._connection._string += struct.pack("!Bd", tc.TYPE_DOUBLE, duration)
1492        if (compoundLength >= 5):
1493            self._connection._string += struct.pack("!BB", tc.TYPE_UBYTE, type)
1494        self._connection._sendExact()
1495
1496    def setImperfection(self, vehID, imperfection):
1497        """setImperfection(string, double) -> None
1498
1499        Sets the driver imperfection sigma.
1500        """
1501        self._connection._sendDoubleCmd(
1502            tc.CMD_SET_VEHICLE_VARIABLE, tc.VAR_IMPERFECTION, vehID, imperfection)
1503
1504    def setTau(self, vehID, tau):
1505        """setTau(string, double) -> None
1506
1507        Sets the driver's tau-parameter (reaction time or anticipation time depending on the car-following model) in s
1508        for this vehicle.
1509        """
1510        self._connection._sendDoubleCmd(
1511            tc.CMD_SET_VEHICLE_VARIABLE, tc.VAR_TAU, vehID, tau)
1512
1513    def setLaneChangeMode(self, vehID, lcm):
1514        """setLaneChangeMode(string, integer) -> None
1515
1516        Sets the vehicle's lane change mode as a bitset.
1517        """
1518        self._connection._sendIntCmd(
1519            tc.CMD_SET_VEHICLE_VARIABLE, tc.VAR_LANECHANGE_MODE, vehID, lcm)
1520
1521    def setSpeedMode(self, vehID, sm):
1522        """setSpeedMode(string, integer) -> None
1523
1524        Sets the vehicle's speed mode as a bitset.
1525        """
1526        self._connection._sendIntCmd(
1527            tc.CMD_SET_VEHICLE_VARIABLE, tc.VAR_SPEEDSETMODE, vehID, sm)
1528
1529    def addLegacy(self, vehID, routeID, depart=tc.DEPARTFLAG_NOW, pos=0, speed=0,
1530                  lane=tc.DEPARTFLAG_LANE_FIRST_ALLOWED, typeID="DEFAULT_VEHTYPE"):
1531        """
1532        Add a new vehicle (old style)
1533        """
1534        if depart == tc.DEPARTFLAG_NOW:
1535            depart = "now"
1536        elif depart == tc.DEPARTFLAG_TRIGGERED:
1537            depart = "triggered"
1538        else:
1539            depart = str(depart)
1540        if pos < 0:
1541            print("Invalid departure position.")
1542            return
1543        if lane == tc.DEPARTFLAG_LANE_FIRST_ALLOWED:
1544            lane = "first"
1545        elif lane == tc.DEPARTFLAG_LANE_FREE:
1546            lane = "free"
1547        else:
1548            lane = str(lane)
1549        self.addFull(vehID, routeID, typeID, depart, lane, str(pos), str(speed))
1550
1551    def add(self, vehID, routeID, typeID="DEFAULT_VEHTYPE", depart=None,
1552            departLane="first", departPos="base", departSpeed="0",
1553            arrivalLane="current", arrivalPos="max", arrivalSpeed="current",
1554            fromTaz="", toTaz="", line="", personCapacity=0, personNumber=0):
1555        """
1556        Add a new vehicle (new style with all possible parameters)
1557        """
1558        messageString = struct.pack("!Bi", tc.TYPE_COMPOUND, 14)
1559        if depart is None:
1560            depart = str(self._connection.simulation.getTime())
1561        for val in (routeID, typeID, depart, departLane, departPos, departSpeed,
1562                    arrivalLane, arrivalPos, arrivalSpeed, fromTaz, toTaz, line):
1563            val = str(val)
1564            messageString += struct.pack("!Bi", tc.TYPE_STRING, len(val)) + val.encode("latin1")
1565        messageString += struct.pack("!Bi", tc.TYPE_INTEGER, personCapacity)
1566        messageString += struct.pack("!Bi", tc.TYPE_INTEGER, personNumber)
1567
1568        self._connection._beginMessage(
1569            tc.CMD_SET_VEHICLE_VARIABLE, tc.ADD_FULL, vehID, len(messageString))
1570        self._connection._string += messageString
1571        self._connection._sendExact()
1572
1573    addFull = add
1574
1575    def remove(self, vehID, reason=tc.REMOVE_VAPORIZED):
1576        '''Remove vehicle with the given ID for the give reason.
1577           Reasons are defined in module constants and start with REMOVE_'''
1578        self._connection._sendByteCmd(
1579            tc.CMD_SET_VEHICLE_VARIABLE, tc.REMOVE, vehID, reason)
1580
1581    def moveToXY(self, vehID, edgeID, lane, x, y, angle=tc.INVALID_DOUBLE_VALUE, keepRoute=1):
1582        '''Place vehicle at the given x,y coordinates and force it's angle to
1583        the given value (for drawing).
1584        If the angle is set to INVALID_DOUBLE_VALUE, the vehicle assumes the
1585        natural angle of the edge on which it is driving.
1586        If keepRoute is set to 1, the closest position
1587        within the existing route is taken. If keepRoute is set to 0, the vehicle may move to
1588        any edge in the network but it's route then only consists of that edge.
1589        If keepRoute is set to 2 the vehicle has all the freedom of keepRoute=0
1590        but in addition to that may even move outside the road network.
1591        edgeID and lane are optional placement hints to resolve ambiguities'''
1592        self._connection._beginMessage(tc.CMD_SET_VEHICLE_VARIABLE, tc.MOVE_TO_XY,
1593                                       vehID, 1 + 4 + 1 + 4 + len(edgeID) + 1 + 4 + 1 + 8 + 1 + 8 + 1 + 8 + 1 + 1)
1594        self._connection._string += struct.pack("!Bi", tc.TYPE_COMPOUND, 6)
1595        self._connection._packString(edgeID)
1596        self._connection._string += struct.pack("!Bi", tc.TYPE_INTEGER, lane)
1597        self._connection._string += struct.pack("!Bd", tc.TYPE_DOUBLE, x)
1598        self._connection._string += struct.pack("!Bd", tc.TYPE_DOUBLE, y)
1599        self._connection._string += struct.pack("!Bd", tc.TYPE_DOUBLE, angle)
1600        self._connection._string += struct.pack("!BB", tc.TYPE_BYTE, keepRoute)
1601        self._connection._sendExact()
1602
1603    def subscribe(self, objectID, varIDs=(tc.VAR_ROAD_ID, tc.VAR_LANEPOSITION), begin=0, end=2**31 - 1):
1604        """subscribe(string, list(integer), int, int) -> None
1605
1606        Subscribe to one or more object values for the given interval.
1607        """
1608        Domain.subscribe(self, objectID, varIDs, begin, end)
1609
1610    def subscribeContext(self, objectID, domain, dist, varIDs=(
1611            tc.VAR_ROAD_ID, tc.VAR_LANEPOSITION), begin=0, end=2**31 - 1):
1612        """subscribe(string, int, double, list(integer), int, int) -> None
1613
1614        Subscribe to one or more object values of the given domain around the
1615        given objectID in a given radius
1616        """
1617        Domain.subscribeContext(
1618            self, objectID, domain, dist, varIDs, begin, end)
1619
1620    def addSubscriptionFilterLanes(self, lanes, noOpposite=False, downstreamDist=None, upstreamDist=None):
1621        """addSubscriptionFilterLanes(list(integer), bool, double, double) -> None
1622
1623        Adds a lane-filter to the last modified vehicle context subscription (call it just after subscribing).
1624        lanes is a list of relative lane indices (-1 -> right neighboring lane of the ego, 0 -> ego lane, etc.)
1625        noOpposite specifies whether vehicles on opposite direction lanes shall be returned
1626        downstreamDist and upstreamDist specify the range of the search for surrounding vehicles along the road net.
1627        """
1628        self._connection._addSubscriptionFilter(tc.FILTER_TYPE_LANES, lanes)
1629        if noOpposite:
1630            self.addSubscriptionFilterNoOpposite()
1631        if downstreamDist is not None:
1632            self.addSubscriptionFilterDownstreamDistance(downstreamDist)
1633        if upstreamDist is not None:
1634            self.addSubscriptionFilterUpstreamDistance(upstreamDist)
1635
1636    def addSubscriptionFilterNoOpposite(self):
1637        """addSubscriptionFilterNoOpposite() -> None
1638
1639        Omits vehicles on other edges than the ego's for the last modified vehicle context subscription
1640        (call it just after subscribing).
1641        """
1642        self._connection._addSubscriptionFilter(tc.FILTER_TYPE_NOOPPOSITE)
1643
1644    def addSubscriptionFilterDownstreamDistance(self, dist):
1645        """addSubscriptionFilterDownstreamDist(float) -> None
1646
1647        Sets the downstream distance along the network for vehicles to be returned by the last modified
1648        vehicle context subscription (call it just after subscribing).
1649        """
1650        self._connection._addSubscriptionFilter(tc.FILTER_TYPE_DOWNSTREAM_DIST, dist)
1651
1652    def addSubscriptionFilterUpstreamDistance(self, dist):
1653        """addSubscriptionFilterUpstreamDist(float) -> None
1654
1655        Sets the upstream distance along the network for vehicles to be returned by the last modified
1656        vehicle context subscription (call it just after subscribing).
1657        """
1658        self._connection._addSubscriptionFilter(tc.FILTER_TYPE_UPSTREAM_DIST, dist)
1659
1660    def addSubscriptionFilterCFManeuver(self, downstreamDist=None, upstreamDist=None):
1661        """addSubscriptionFilterCFManeuver() -> None
1662
1663        Restricts vehicles returned by the last modified vehicle context subscription to leader and follower of the ego.
1664        downstreamDist and upstreamDist specify the range of the search for leader and follower along the road net.
1665        """
1666        self.addSubscriptionFilterLeadFollow([0])
1667        if downstreamDist is not None:
1668            self.addSubscriptionFilterDownstreamDistance(downstreamDist)
1669        if upstreamDist is not None:
1670            self.addSubscriptionFilterUpstreamDistance(upstreamDist)
1671
1672    def addSubscriptionFilterLCManeuver(self, direction, noOpposite=False, downstreamDist=None, upstreamDist=None):
1673        """addSubscriptionFilterLCManeuver(int) -> None
1674
1675        Restricts vehicles returned by the last modified vehicle context subscription to neighbor and ego-lane leader
1676        and follower of the ego.
1677        direction - lane change direction (in {-1=right, 1=left})
1678        noOpposite specifies whether vehicles on opposite direction lanes shall be returned
1679        downstreamDist and upstreamDist specify the range of the search for leader and follower along the road net.
1680        Combine with: distance filters; vClass/vType filter.
1681        """
1682        if direction is None:
1683            # Using default: both directions
1684            lanes = [-1, 0, 1]
1685        elif not (direction == -1 or direction == 1):
1686            warnings.warn("Ignoring lane change subscription filter " +
1687                          "with non-neighboring lane offset direction=%s." % direction)
1688            return
1689        else:
1690            lanes = [0, direction]
1691        self.addSubscriptionFilterLeadFollow(lanes)
1692        if noOpposite:
1693            self.addSubscriptionFilterNoOpposite()
1694        if downstreamDist is not None:
1695            self.addSubscriptionFilterDownstreamDistance(downstreamDist)
1696        if upstreamDist is not None:
1697            self.addSubscriptionFilterUpstreamDistance(upstreamDist)
1698
1699    def addSubscriptionFilterLeadFollow(self, lanes):
1700        """addSubscriptionFilterLCManeuver() -> None
1701
1702        Restricts vehicles returned by the last modified vehicle context subscription to neighbor and ego-lane leader
1703        and follower of the ego.
1704        Combine with: lanes-filter to restrict to one direction; distance filters; vClass/vType filter.
1705        """
1706        self._connection._addSubscriptionFilter(tc.FILTER_TYPE_LEAD_FOLLOW)
1707        self._connection._addSubscriptionFilter(tc.FILTER_TYPE_LANES, lanes)
1708
1709    def addSubscriptionFilterTurn(self, downstreamDist=None, upstreamDist=None):
1710        """addSubscriptionFilterTurn() -> None
1711
1712        Restricts vehicles returned by the last modified vehicle context subscription to foes on an upcoming junction
1713        """
1714        self._connection._addSubscriptionFilter(tc.FILTER_TYPE_TURN)
1715        if downstreamDist is not None:
1716            self.addSubscriptionFilterDownstreamDistance(downstreamDist)
1717        if upstreamDist is not None:
1718            self.addSubscriptionFilterUpstreamDistance(upstreamDist)
1719
1720    def addSubscriptionFilterVClass(self, vClasses):
1721        """addSubscriptionFilterVClass(list(String)) -> None
1722
1723        Restricts vehicles returned by the last modified vehicle context subscription to vehicles of the given classes
1724        """
1725        self._connection._addSubscriptionFilter(tc.FILTER_TYPE_VCLASS, vClasses)
1726
1727    def addSubscriptionFilterVType(self, vTypes):
1728        """addSubscriptionFilterVType(list(String)) -> None
1729
1730        Restricts vehicles returned by the last modified vehicle context subscription to vehicles of the given types
1731        """
1732        self._connection._addSubscriptionFilter(tc.FILTER_TYPE_VTYPE, vTypes)
1733
1734
1735VehicleDomain()
1736