Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2024 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file MSInductLoop.cpp
15 : /// @author Christian Roessel
16 : /// @author Daniel Krajzewicz
17 : /// @author Jakob Erdmann
18 : /// @author Sascha Krieg
19 : /// @author Michael Behrisch
20 : /// @author Laura Bieker
21 : /// @author Mirko Barthauer
22 : /// @date 2004-11-23
23 : ///
24 : // An unextended detector measuring at a fixed position on a fixed lane.
25 : /****************************************************************************/
26 : #include <config.h>
27 :
28 : #include "MSInductLoop.h"
29 : #include <cassert>
30 : #include <numeric>
31 : #include <utility>
32 : #ifdef HAVE_FOX
33 : #include <utils/common/ScopedLocker.h>
34 : #endif
35 : #include <utils/common/WrappingCommand.h>
36 : #include <utils/common/ToString.h>
37 : #include <microsim/MSEventControl.h>
38 : #include <microsim/MSLane.h>
39 : #include <microsim/MSEdge.h>
40 : #include <microsim/MSVehicle.h>
41 : #include <microsim/MSNet.h>
42 : #include <microsim/transportables/MSTransportable.h>
43 : #include <microsim/transportables/MSPModel.h>
44 : #include <utils/common/MsgHandler.h>
45 : #include <utils/common/UtilExceptions.h>
46 : #include <utils/common/StringUtils.h>
47 : #include <utils/iodevices/OutputDevice.h>
48 :
49 : #define HAS_NOT_LEFT_DETECTOR -1
50 :
51 : //#define DEBUG_E1_NOTIFY_MOVE
52 :
53 : #define DEBUG_COND (true)
54 : //#define DEBUG_COND (isSelected())
55 : //#define DEBUG_COND (getID()=="")
56 :
57 : // ===========================================================================
58 : // method definitions
59 : // ===========================================================================
60 23599 : MSInductLoop::MSInductLoop(const std::string& id, MSLane* const lane,
61 : double positionInMeters,
62 : double length, std::string name,
63 : const std::string& vTypes,
64 : const std::string& nextEdges,
65 : int detectPersons,
66 23599 : const bool needLocking) :
67 : MSMoveReminder(id, lane),
68 : MSDetectorFileOutput(id, vTypes, nextEdges, detectPersons),
69 23595 : myName(name),
70 23595 : myPosition(positionInMeters),
71 23595 : myEndPosition(myPosition + length),
72 23595 : myNeedLock(needLocking || MSGlobals::gNumSimThreads > 1),
73 : // initialize in a way which doesn't impact actualted traffic lights at simulation start (yet doesn't look ugly in the outputs)
74 23595 : myLastLeaveTime(-3600),
75 23595 : myOverrideTime(-1),
76 23595 : myOverrideEntryTime(-1),
77 : myVehicleDataCont(),
78 : myVehiclesOnDet(),
79 23599 : myLastIntervalEnd(-1) {
80 : assert(length >= 0);
81 : assert(myPosition >= 0 && myEndPosition <= myLane->getLength());
82 23595 : reset();
83 23599 : }
84 :
85 :
86 45873 : MSInductLoop::~MSInductLoop() {
87 45873 : }
88 :
89 :
90 : void
91 333561 : MSInductLoop::reset() {
92 : #ifdef HAVE_FOX
93 333561 : ScopedLocker<> lock(myNotificationMutex, myNeedLock);
94 : #endif
95 333561 : myEnteredVehicleNumber = 0;
96 333561 : myLastVehicleDataCont = myVehicleDataCont;
97 : myVehicleDataCont.clear();
98 333561 : myLastIntervalBegin = myLastIntervalEnd;
99 333561 : myLastIntervalEnd = SIMSTEP;
100 333561 : }
101 :
102 :
103 : bool
104 848604 : MSInductLoop::notifyEnter(SUMOTrafficObject& veh, Notification reason, const MSLane* /* enteredLane */) {
105 : // vehicles must be kept if the "inductionloop" wants to detect passeengers
106 848604 : if (!vehicleApplies(veh) && (veh.isPerson() || myDetectPersons <= (int)PersonMode::WALK)) {
107 : return false;
108 : }
109 846434 : if (reason != NOTIFICATION_JUNCTION) { // the junction case is handled in notifyMove
110 177986 : if (veh.getBackPositionOnLane(myLane) >= myPosition) {
111 : return false;
112 : }
113 175443 : if (veh.getPositionOnLane() >= myPosition) {
114 : #ifdef HAVE_FOX
115 1123 : ScopedLocker<> lock(myNotificationMutex, myNeedLock);
116 : #endif
117 1123 : myVehiclesOnDet[&veh] = SIMTIME;
118 1123 : myEnteredVehicleNumber++;
119 : }
120 : }
121 : return true;
122 : }
123 :
124 :
125 : bool
126 17776111 : MSInductLoop::notifyMove(SUMOTrafficObject& veh, double oldPos,
127 : double newPos, double newSpeed) {
128 17776111 : if (newPos < myPosition) {
129 : // detector not reached yet
130 : return true;
131 : }
132 1829840 : if (myDetectPersons > (int)PersonMode::WALK && !veh.isPerson()) {
133 : bool keep = false;
134 38 : MSBaseVehicle& v = dynamic_cast<MSBaseVehicle&>(veh);
135 76 : for (MSTransportable* p : v.getPersons()) {
136 38 : keep = notifyMove(*p, oldPos, newPos, newSpeed);
137 : }
138 38 : return keep;
139 : }
140 : #ifdef HAVE_FOX
141 1829802 : ScopedLocker<> lock(myNotificationMutex, myNeedLock);
142 : #endif
143 1829802 : const double oldSpeed = veh.getPreviousSpeed();
144 1829802 : if (newPos >= myPosition && oldPos < myPosition) {
145 : // entered the detector by move
146 818053 : const double timeBeforeEnter = MSCFModel::passingTime(oldPos, myPosition, newPos, oldSpeed, newSpeed);
147 818053 : myVehiclesOnDet[&veh] = SIMTIME + timeBeforeEnter;
148 818053 : myEnteredVehicleNumber++;
149 : #ifdef DEBUG_E1_NOTIFY_MOVE
150 : if (DEBUG_COND) {
151 : std::cout << SIMTIME << " det=" << getID() << " enteredVeh=" << veh.getID() << "\n";
152 : }
153 : #endif
154 : }
155 1829802 : double oldBackPos = oldPos - veh.getVehicleType().getLength();
156 1829802 : double newBackPos = newPos - veh.getVehicleType().getLength();
157 1829802 : if (newBackPos > myEndPosition) {
158 : // vehicle passed the detector (it may have changed onto this lane somewhere past the detector)
159 : // assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed > 0 || myVehiclesOnDet.find(&veh) == myVehiclesOnDet.end());
160 : // assertion is invalid in case of teleportation
161 815913 : if (oldBackPos <= myEndPosition) {
162 : const std::map<SUMOTrafficObject*, double>::iterator it = myVehiclesOnDet.find(&veh);
163 815913 : if (it != myVehiclesOnDet.end()) {
164 815913 : const double entryTime = it->second;
165 815913 : const double leaveTime = SIMTIME + MSCFModel::passingTime(oldBackPos, myEndPosition, newBackPos, oldSpeed, newSpeed);
166 : myVehiclesOnDet.erase(it);
167 : assert(entryTime <= leaveTime);
168 815913 : myVehicleDataCont.push_back(VehicleData(veh, entryTime, leaveTime, false, myEndPosition - myPosition));
169 815913 : myLastLeaveTime = leaveTime;
170 : #ifdef DEBUG_E1_NOTIFY_MOVE
171 : if (DEBUG_COND) {
172 : std::cout << SIMTIME << " det=" << getID() << " leftVeh=" << veh.getID() << " oldBackPos=" << oldBackPos << " newBackPos=" << newBackPos << "\n";
173 : }
174 : #endif
175 : } else {
176 : #ifdef DEBUG_E1_NOTIFY_MOVE
177 : if (DEBUG_COND) {
178 : std::cout << SIMTIME << " det=" << getID() << " leftVeh=" << veh.getID() << " oldBackPos=" << oldBackPos << " newBackPos=" << newBackPos << " (notFound)\n";
179 : }
180 : #endif
181 : }
182 : } else {
183 : // vehicle is already beyond the detector...
184 : // This can happen even if it is still registered in myVehiclesOnDet, e.g., after teleport.
185 0 : myVehiclesOnDet.erase(&veh);
186 : #ifdef DEBUG_E1_NOTIFY_MOVE
187 : if (DEBUG_COND) {
188 : std::cout << SIMTIME << " det=" << getID() << " leftVeh=" << veh.getID() << " oldBackPos=" << oldBackPos << " newBackPos=" << newBackPos << " (unusual)\n";
189 : }
190 : #endif
191 : }
192 815913 : return false;
193 : }
194 : // vehicle stays on the detector
195 : return true;
196 : }
197 :
198 :
199 : bool
200 612087 : MSInductLoop::notifyLeave(SUMOTrafficObject& veh, double lastPos, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
201 612087 : if (veh.isPerson() && myDetectPersons != (int)PersonMode::NONE) {
202 3204 : const int lastDir = lastPos < 0 ? MSPModel::BACKWARD : MSPModel::FORWARD;
203 3204 : notifyMovePerson(dynamic_cast<MSTransportable*>(&veh), lastDir, lastPos);
204 : }
205 612087 : if (reason != MSMoveReminder::NOTIFICATION_JUNCTION || (veh.isPerson() && myDetectPersons != (int)PersonMode::NONE)) {
206 : #ifdef HAVE_FOX
207 27869 : ScopedLocker<> lock(myNotificationMutex, myNeedLock);
208 : #endif
209 : const std::map<SUMOTrafficObject*, double>::iterator it = myVehiclesOnDet.find(&veh);
210 27869 : if (it != myVehiclesOnDet.end()) {
211 2938 : const double entryTime = it->second;
212 2938 : const double leaveTime = SIMTIME + TS;
213 : myVehiclesOnDet.erase(it);
214 2938 : myVehicleDataCont.push_back(VehicleData(veh, entryTime, leaveTime, true));
215 2938 : myLastLeaveTime = leaveTime;
216 : }
217 : return false;
218 : }
219 : return true;
220 : }
221 :
222 :
223 : double
224 140 : MSInductLoop::getSpeed(const int offset) const {
225 140 : const std::vector<VehicleData>& d = collectVehiclesOnDet(SIMSTEP - offset);
226 169 : return d.empty() ? -1. : std::accumulate(d.begin(), d.end(), 0.0, speedSum) / (double) d.size();
227 140 : }
228 :
229 :
230 : double
231 140 : MSInductLoop::getVehicleLength(const int offset) const {
232 140 : const std::vector<VehicleData>& d = collectVehiclesOnDet(SIMSTEP - offset);
233 169 : return d.empty() ? -1. : std::accumulate(d.begin(), d.end(), 0.0, lengthSum) / (double)d.size();
234 140 : }
235 :
236 :
237 : double
238 30496 : MSInductLoop::getOccupancy() const {
239 30496 : if (myOverrideTime >= 0) {
240 48 : return myOverrideTime < TS ? (TS - myOverrideTime) / TS * 100 : 0;
241 : }
242 30448 : const SUMOTime tbeg = SIMSTEP - DELTA_T;
243 : double occupancy = 0;
244 30448 : const double csecond = SIMTIME;
245 33617 : for (const VehicleData& i : collectVehiclesOnDet(tbeg, false, false, true)) {
246 3169 : const double leaveTime = i.leaveTimeM == HAS_NOT_LEFT_DETECTOR ? csecond : MIN2(i.leaveTimeM, csecond);
247 3169 : const double entryTime = MAX2(i.entryTimeM, STEPS2TIME(tbeg));
248 4657 : occupancy += MIN2(leaveTime - entryTime, TS);
249 30448 : }
250 30448 : return occupancy / TS * 100.;
251 : }
252 :
253 :
254 : double
255 3343 : MSInductLoop::getEnteredNumber(const int offset) const {
256 3343 : if (myOverrideTime >= 0) {
257 48 : return myOverrideTime < TS ? 1 : 0;
258 : }
259 3295 : return (double)collectVehiclesOnDet(SIMSTEP - offset, true, true).size();
260 : }
261 :
262 :
263 : std::vector<std::string>
264 1004 : MSInductLoop::getVehicleIDs(const int offset) const {
265 : std::vector<std::string> ret;
266 1275 : for (const VehicleData& i : collectVehiclesOnDet(SIMSTEP - offset, true, true)) {
267 271 : ret.push_back(i.idM);
268 1004 : }
269 1004 : return ret;
270 0 : }
271 :
272 :
273 : double
274 424017 : MSInductLoop::getTimeSinceLastDetection() const {
275 424017 : if (myOverrideTime >= 0) {
276 : return myOverrideTime;
277 : }
278 423969 : if (myVehiclesOnDet.size() != 0) {
279 : // detector is occupied
280 : return 0;
281 : }
282 389566 : return SIMTIME - myLastLeaveTime;
283 : }
284 :
285 :
286 : double
287 155793 : MSInductLoop::getOccupancyTime() const {
288 : #ifdef HAVE_FOX
289 155793 : ScopedLocker<> lock(myNotificationMutex, myNeedLock);
290 : #endif
291 155793 : if (myOverrideTime >= 0) {
292 0 : return SIMTIME - myOverrideEntryTime;
293 : }
294 155793 : if (myVehiclesOnDet.size() == 0) {
295 : // detector is unoccupied
296 : return 0;
297 : } else {
298 : double minEntry = std::numeric_limits<double>::max();
299 3220 : for (const auto& i : myVehiclesOnDet) {
300 1610 : minEntry = MIN2(i.second, minEntry);
301 : }
302 1610 : return SIMTIME - minEntry;
303 : }
304 : }
305 :
306 :
307 :
308 : SUMOTime
309 128060 : MSInductLoop::getLastDetectionTime() const {
310 128060 : if (myOverrideTime >= 0) {
311 0 : return SIMSTEP - TIME2STEPS(myOverrideTime);
312 : }
313 128060 : if (myVehiclesOnDet.size() != 0) {
314 5285 : return MSNet::getInstance()->getCurrentTimeStep();
315 : }
316 169984 : return TIME2STEPS(myLastLeaveTime);
317 : }
318 :
319 :
320 : double
321 960 : MSInductLoop::getIntervalOccupancy(bool lastInterval) const {
322 : double occupancy = 0;
323 960 : const double csecond = lastInterval ? STEPS2TIME(myLastIntervalEnd) : SIMTIME;
324 960 : const double aggTime = csecond - STEPS2TIME(lastInterval ? myLastIntervalBegin : myLastIntervalEnd);
325 960 : if (aggTime == 0) {
326 : return 0;
327 : }
328 3908 : for (const VehicleData& i : collectVehiclesOnDet(myLastIntervalEnd, false, false, true, lastInterval)) {
329 2952 : const double leaveTime = i.leaveTimeM == HAS_NOT_LEFT_DETECTOR ? csecond : MIN2(i.leaveTimeM, csecond);
330 2952 : const double entryTime = MAX2(i.entryTimeM, STEPS2TIME(lastInterval ? myLastIntervalBegin : myLastIntervalEnd));
331 2952 : occupancy += MIN2(leaveTime - entryTime, aggTime);
332 956 : }
333 956 : return occupancy / aggTime * 100.;
334 : }
335 :
336 :
337 : double
338 960 : MSInductLoop::getIntervalMeanSpeed(bool lastInterval) const {
339 960 : const std::vector<VehicleData>& d = collectVehiclesOnDet(myLastIntervalEnd, false, false, false, lastInterval);
340 1632 : return d.empty() ? -1. : std::accumulate(d.begin(), d.end(), 0.0, speedSum) / (double) d.size();
341 960 : }
342 :
343 :
344 : int
345 960 : MSInductLoop::getIntervalVehicleNumber(bool lastInterval) const {
346 960 : return (int)collectVehiclesOnDet(myLastIntervalEnd, false, false, false, lastInterval).size();
347 : }
348 :
349 :
350 : std::vector<std::string>
351 960 : MSInductLoop::getIntervalVehicleIDs(bool lastInterval) const {
352 : std::vector<std::string> ret;
353 3912 : for (const VehicleData& i : collectVehiclesOnDet(myLastIntervalEnd, false, false, false, lastInterval)) {
354 2952 : ret.push_back(i.idM);
355 960 : }
356 960 : return ret;
357 0 : }
358 :
359 :
360 : void
361 20 : MSInductLoop::overrideTimeSinceDetection(double time) {
362 20 : myOverrideTime = time;
363 20 : if (time < 0) {
364 4 : myOverrideEntryTime = -1;
365 : } else {
366 16 : const double entryTime = MAX2(0.0, SIMTIME - time);
367 16 : if (myOverrideEntryTime >= 0) {
368 : // maintain earlier entry time to achive continous detection
369 12 : myOverrideEntryTime = MIN2(myOverrideEntryTime, entryTime);
370 : } else {
371 4 : myOverrideEntryTime = entryTime;
372 : }
373 : }
374 20 : }
375 :
376 : void
377 23591 : MSInductLoop::writeXMLDetectorProlog(OutputDevice& dev) const {
378 47182 : dev.writeXMLHeader("detector", "det_e1_file.xsd");
379 23591 : }
380 :
381 :
382 : void
383 309966 : MSInductLoop::writeXMLOutput(OutputDevice& dev, SUMOTime startTime, SUMOTime stopTime) {
384 309966 : if (dev.isNull()) {
385 16886 : reset();
386 16886 : return;
387 : }
388 293080 : const double t(STEPS2TIME(stopTime - startTime));
389 293080 : double occupancy = 0.;
390 : double speedSum = 0.;
391 : double lengthSum = 0.;
392 293080 : int contrib = 0;
393 : // to approximate the space mean speed
394 : double inverseSpeedSum = 0.;
395 1001047 : for (const VehicleData& vData : myVehicleDataCont) {
396 1410004 : const double timeOnDetDuringInterval = vData.leaveTimeM - MAX2(STEPS2TIME(startTime), vData.entryTimeM);
397 707967 : occupancy += MIN2(timeOnDetDuringInterval, t);
398 707967 : if (!vData.leftEarlyM) {
399 705548 : speedSum += vData.speedM;
400 : assert(vData.speedM > 0.);
401 705548 : inverseSpeedSum += 1. / vData.speedM;
402 705548 : lengthSum += vData.lengthM;
403 705548 : contrib++;
404 : }
405 : }
406 293080 : const double flow = (double)contrib / t * 3600.;
407 300006 : for (std::map< SUMOTrafficObject*, double >::const_iterator i = myVehiclesOnDet.begin(); i != myVehiclesOnDet.end(); ++i) {
408 13328 : occupancy += STEPS2TIME(stopTime) - MAX2(STEPS2TIME(startTime), i->second);
409 : }
410 293080 : occupancy *= 100. / t;
411 293080 : const double meanSpeed = contrib != 0 ? speedSum / (double)contrib : -1;
412 293080 : const double harmonicMeanSpeed = contrib != 0 ? (double)contrib / inverseSpeedSum : -1;
413 293080 : const double meanLength = contrib != 0 ? lengthSum / (double)contrib : -1;
414 879240 : dev.openTag(SUMO_TAG_INTERVAL).writeAttr(SUMO_ATTR_BEGIN, STEPS2TIME(startTime)).writeAttr(SUMO_ATTR_END, STEPS2TIME(stopTime));
415 879240 : dev.writeAttr(SUMO_ATTR_ID, StringUtils::escapeXML(getID())).writeAttr("nVehContrib", contrib);
416 1465400 : dev.writeAttr("flow", flow).writeAttr("occupancy", occupancy).writeAttr("speed", meanSpeed).writeAttr("harmonicMeanSpeed", harmonicMeanSpeed);
417 1172320 : dev.writeAttr("length", meanLength).writeAttr("nVehEntered", myEnteredVehicleNumber).closeTag();
418 293080 : reset();
419 : }
420 :
421 :
422 : void
423 66846076 : MSInductLoop::detectorUpdate(const SUMOTime /* step */) {
424 66846076 : if (myDetectPersons == (int)PersonMode::NONE) {
425 : return;
426 : }
427 78616 : if (myLane->hasPedestrians()) {
428 202640 : for (MSTransportable* p : myLane->getEdge().getPersons()) {
429 183844 : if (p->getLane() != myLane || !vehicleApplies(*p)) {
430 28504 : continue;
431 : }
432 155340 : notifyMovePerson(p, p->getDirection(), p->getPositionOnLane());
433 : }
434 : }
435 : }
436 :
437 :
438 : void
439 158544 : MSInductLoop::notifyMovePerson(MSTransportable* p, int dir, double pos) {
440 158544 : if (personApplies(*p, dir)) {
441 114112 : const double newSpeed = p->getSpeed();
442 114112 : const double newPos = (dir == MSPModel::FORWARD
443 114112 : ? pos
444 : // position relative to detector
445 31992 : : myPosition - (pos - myPosition));
446 114112 : const double oldPos = newPos - SPEED2DIST(newSpeed);
447 114112 : if (oldPos - p->getVehicleType().getLength() <= myPosition) {
448 80988 : notifyMove(*p, oldPos, newPos, newSpeed);
449 : }
450 : }
451 158544 : }
452 :
453 :
454 : std::vector<MSInductLoop::VehicleData>
455 81363 : MSInductLoop::collectVehiclesOnDet(SUMOTime tMS, bool includeEarly, bool leaveTime, bool forOccupancy, bool lastInterval) const {
456 : #ifdef HAVE_FOX
457 81363 : ScopedLocker<> lock(myNotificationMutex, myNeedLock);
458 : #endif
459 81363 : const double t = STEPS2TIME(tMS);
460 : std::vector<VehicleData> ret;
461 1061743 : for (const VehicleData& i : myVehicleDataCont) {
462 980380 : if ((includeEarly || !i.leftEarlyM) && (!lastInterval || i.entryTimeM < t)) {
463 976612 : if (i.entryTimeM >= t || (leaveTime && i.leaveTimeM >= t)) {
464 5624 : ret.push_back(i);
465 : }
466 : }
467 : }
468 558254 : for (const VehicleData& i : myLastVehicleDataCont) {
469 476891 : if (includeEarly || !i.leftEarlyM) {
470 476891 : if ((!lastInterval && (i.entryTimeM >= t || (leaveTime && i.leaveTimeM >= t)))
471 8160 : || (lastInterval && i.leaveTimeM <= t)) {
472 8209 : ret.push_back(i);
473 : }
474 : }
475 : }
476 89930 : for (const auto& i : myVehiclesOnDet) {
477 8567 : if ((!lastInterval && (i.second >= t || leaveTime || forOccupancy))
478 96 : || (lastInterval && i.second < t)) { // no need to check leave time, they are still on the detector
479 8463 : SUMOTrafficObject* const v = i.first;
480 8463 : VehicleData d(*v, i.second, HAS_NOT_LEFT_DETECTOR, false);
481 8463 : d.speedM = v->getSpeed();
482 8463 : ret.push_back(d);
483 : }
484 : }
485 81363 : return ret;
486 0 : }
487 :
488 :
489 827314 : MSInductLoop::VehicleData::VehicleData(const SUMOTrafficObject& v, double entryTimestep,
490 827314 : double leaveTimestep, const bool leftEarly, const double detLength)
491 827314 : : idM(v.getID()), lengthM(v.getVehicleType().getLength()), entryTimeM(entryTimestep), leaveTimeM(leaveTimestep),
492 835777 : speedM((v.getVehicleType().getLength() + detLength) / MAX2(leaveTimestep - entryTimestep, NUMERICAL_EPS)), typeIDM(v.getVehicleType().getID()),
493 827314 : leftEarlyM(leftEarly) {}
494 :
495 :
496 : void
497 20 : MSInductLoop::clearState(SUMOTime time) {
498 20 : myLastLeaveTime = STEPS2TIME(time);
499 20 : myEnteredVehicleNumber = 0;
500 20 : myLastVehicleDataCont.clear();
501 20 : myVehicleDataCont.clear();
502 : myVehiclesOnDet.clear();
503 20 : }
504 :
505 : /****************************************************************************/
|