Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2026 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file 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 28230 : 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 28230 : const bool needLocking) :
67 : MSMoveReminder(id, lane),
68 : MSDetectorFileOutput(id, vTypes, nextEdges, detectPersons),
69 28226 : myName(name),
70 28226 : myPosition(positionInMeters),
71 28226 : myEndPosition(myPosition + length),
72 28226 : 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 28226 : myLastLeaveTime(-3600),
75 28226 : myOverrideTime(-1),
76 28226 : myOverrideEntryTime(-1),
77 : myVehicleDataCont(),
78 : myVehiclesOnDet(),
79 28230 : myLastIntervalEnd(-1) {
80 : assert(length >= 0);
81 : assert(myPosition >= 0 && myEndPosition <= myLane->getLength());
82 28226 : reset();
83 28230 : }
84 :
85 :
86 54834 : MSInductLoop::~MSInductLoop() {
87 54834 : }
88 :
89 :
90 : void
91 152112 : MSInductLoop::reset() {
92 : #ifdef HAVE_FOX
93 152112 : ScopedLocker<> lock(myNotificationMutex, myNeedLock);
94 : #endif
95 152112 : myEnteredVehicleNumber = 0;
96 152112 : myLastVehicleDataCont = myVehicleDataCont;
97 : myVehicleDataCont.clear();
98 152112 : myLastIntervalBegin = myLastIntervalEnd;
99 152112 : myLastIntervalEnd = SIMSTEP;
100 152112 : }
101 :
102 :
103 : bool
104 1204599 : MSInductLoop::notifyEnter(SUMOTrafficObject& veh, Notification reason, const MSLane* /* enteredLane */) {
105 : // vehicles must be kept if the "inductionloop" wants to detect passeengers
106 1204599 : if (!vehicleApplies(veh) && (veh.isPerson() || myDetectPersons <= (int)PersonMode::WALK)) {
107 : return false;
108 : }
109 1200263 : if (reason != NOTIFICATION_JUNCTION) { // the junction case is handled in notifyMove
110 230746 : if (veh.getBackPositionOnLane(myLane) >= myPosition) {
111 : return false;
112 : }
113 227847 : if (veh.getPositionOnLane() >= myPosition) {
114 : #ifdef HAVE_FOX
115 1223 : ScopedLocker<> lock(myNotificationMutex, myNeedLock);
116 : #endif
117 1223 : myVehiclesOnDet[&veh] = SIMTIME;
118 1223 : myEnteredVehicleNumber++;
119 : }
120 : }
121 : return true;
122 : }
123 :
124 :
125 : bool
126 23014492 : MSInductLoop::notifyMove(SUMOTrafficObject& veh, double oldPos,
127 : double newPos, double newSpeed) {
128 23014492 : if (newPos < myPosition) {
129 : // detector not reached yet
130 : return true;
131 : }
132 2737082 : 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 2737044 : ScopedLocker<> lock(myNotificationMutex, myNeedLock);
142 : #endif
143 2737044 : const double oldSpeed = veh.getPreviousSpeed();
144 2737044 : if (newPos >= myPosition && oldPos < myPosition) {
145 : // entered the detector by move
146 1168980 : const double timeBeforeEnter = MSCFModel::passingTime(oldPos, myPosition, newPos, oldSpeed, newSpeed);
147 1168980 : myVehiclesOnDet[&veh] = SIMTIME + timeBeforeEnter;
148 1168980 : 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 2737044 : double oldBackPos = oldPos - veh.getVehicleType().getLength();
156 2737044 : double newBackPos = newPos - veh.getVehicleType().getLength();
157 2737044 : 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 1166580 : if (oldBackPos <= myEndPosition) {
162 : const std::map<SUMOTrafficObject*, double>::iterator it = myVehiclesOnDet.find(&veh);
163 1166580 : if (it != myVehiclesOnDet.end()) {
164 1166580 : const double entryTime = it->second;
165 1166580 : const double leaveTime = SIMTIME + MSCFModel::passingTime(oldBackPos, myEndPosition, newBackPos, oldSpeed, newSpeed);
166 : myVehiclesOnDet.erase(it);
167 : assert(entryTime <= leaveTime);
168 1166580 : myVehicleDataCont.push_back(VehicleData(veh, entryTime, leaveTime, false, myEndPosition - myPosition));
169 1166580 : 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 1166580 : return false;
193 : }
194 : // vehicle stays on the detector
195 : return true;
196 : }
197 :
198 :
199 : bool
200 858151 : MSInductLoop::notifyLeave(SUMOTrafficObject& veh, double lastPos, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
201 858151 : 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 858151 : if (reason != MSMoveReminder::NOTIFICATION_JUNCTION || (veh.isPerson() && myDetectPersons != (int)PersonMode::NONE)) {
206 : #ifdef HAVE_FOX
207 31246 : ScopedLocker<> lock(myNotificationMutex, myNeedLock);
208 : #endif
209 : const std::map<SUMOTrafficObject*, double>::iterator it = myVehiclesOnDet.find(&veh);
210 31246 : if (it != myVehiclesOnDet.end()) {
211 3608 : const double entryTime = it->second;
212 3608 : const double leaveTime = SIMTIME + TS;
213 : myVehiclesOnDet.erase(it);
214 3608 : myVehicleDataCont.push_back(VehicleData(veh, entryTime, leaveTime, true));
215 3608 : myLastLeaveTime = leaveTime;
216 : }
217 : return false;
218 : }
219 : return true;
220 : }
221 :
222 :
223 : double
224 146 : MSInductLoop::getSpeed(const int offset) const {
225 146 : const std::vector<VehicleData>& d = collectVehiclesOnDet(SIMSTEP - offset);
226 175 : return d.empty() ? -1. : std::accumulate(d.begin(), d.end(), 0.0, speedSum) / (double) d.size();
227 146 : }
228 :
229 :
230 : double
231 146 : MSInductLoop::getVehicleLength(const int offset) const {
232 146 : const std::vector<VehicleData>& d = collectVehiclesOnDet(SIMSTEP - offset);
233 175 : return d.empty() ? -1. : std::accumulate(d.begin(), d.end(), 0.0, lengthSum) / (double)d.size();
234 146 : }
235 :
236 :
237 : double
238 54498 : MSInductLoop::getOccupancy() const {
239 54498 : if (myOverrideTime >= 0) {
240 48 : return myOverrideTime < TS ? (TS - myOverrideTime) / TS * 100 : 0;
241 : }
242 54450 : const SUMOTime tbeg = SIMSTEP - DELTA_T;
243 : double occupancy = 0;
244 54450 : const double csecond = SIMTIME;
245 60335 : for (const VehicleData& i : collectVehiclesOnDet(tbeg, false, false, true)) {
246 5885 : const double leaveTime = i.leaveTimeM == HAS_NOT_LEFT_DETECTOR ? csecond : MIN2(i.leaveTimeM, csecond);
247 5885 : const double entryTime = MAX2(i.entryTimeM, STEPS2TIME(tbeg));
248 8697 : occupancy += MIN2(leaveTime - entryTime, TS);
249 54450 : }
250 54450 : return occupancy / TS * 100.;
251 : }
252 :
253 :
254 : double
255 3217 : MSInductLoop::getEnteredNumber(const int offset) const {
256 3217 : if (myOverrideTime >= 0) {
257 48 : return myOverrideTime < TS ? 1 : 0;
258 : }
259 3169 : return (double)collectVehiclesOnDet(SIMSTEP - offset, true, true).size();
260 : }
261 :
262 :
263 : std::vector<std::string>
264 970 : MSInductLoop::getVehicleIDs(const int offset) const {
265 : std::vector<std::string> ret;
266 1235 : for (const VehicleData& i : collectVehiclesOnDet(SIMSTEP - offset, true, true)) {
267 265 : ret.push_back(i.idM);
268 970 : }
269 970 : return ret;
270 0 : }
271 :
272 :
273 : double
274 638409 : MSInductLoop::getTimeSinceLastDetection() const {
275 638409 : if (myOverrideTime >= 0) {
276 : return myOverrideTime;
277 : }
278 638361 : if (myVehiclesOnDet.size() != 0) {
279 : // detector is occupied
280 : return 0;
281 : }
282 584124 : return SIMTIME - myLastLeaveTime;
283 : }
284 :
285 :
286 : void
287 8 : MSInductLoop::loadTimeSinceLastDetection(double time) {
288 8 : myLastLeaveTime = SIMTIME - time;
289 8 : }
290 :
291 :
292 : double
293 163509 : MSInductLoop::getOccupancyTime() const {
294 : #ifdef HAVE_FOX
295 163509 : ScopedLocker<> lock(myNotificationMutex, myNeedLock);
296 : #endif
297 163509 : if (myOverrideTime >= 0) {
298 0 : return SIMTIME - myOverrideEntryTime;
299 : }
300 163509 : if (myVehiclesOnDet.size() == 0) {
301 : // detector is unoccupied
302 : return 0;
303 : } else {
304 : double minEntry = std::numeric_limits<double>::max();
305 4292 : for (const auto& i : myVehiclesOnDet) {
306 2146 : minEntry = MIN2(i.second, minEntry);
307 : }
308 2146 : return SIMTIME - minEntry;
309 : }
310 : }
311 :
312 :
313 :
314 : SUMOTime
315 265929 : MSInductLoop::getLastDetectionTime() const {
316 265929 : if (myOverrideTime >= 0) {
317 0 : return SIMSTEP - TIME2STEPS(myOverrideTime);
318 : }
319 265929 : if (myVehiclesOnDet.size() != 0) {
320 12612 : return MSNet::getInstance()->getCurrentTimeStep();
321 : }
322 354304 : return TIME2STEPS(myLastLeaveTime);
323 : }
324 :
325 :
326 : double
327 732 : MSInductLoop::getIntervalOccupancy(bool lastInterval) const {
328 : double occupancy = 0;
329 732 : const double csecond = lastInterval ? STEPS2TIME(myLastIntervalEnd) : SIMTIME;
330 732 : const double aggTime = csecond - STEPS2TIME(lastInterval ? myLastIntervalBegin : myLastIntervalEnd);
331 732 : if (aggTime == 0) {
332 : return 0;
333 : }
334 3033 : for (const VehicleData& i : collectVehiclesOnDet(myLastIntervalEnd, false, false, true, lastInterval)) {
335 2304 : const double leaveTime = i.leaveTimeM == HAS_NOT_LEFT_DETECTOR ? csecond : MIN2(i.leaveTimeM, csecond);
336 2304 : const double entryTime = MAX2(i.entryTimeM, STEPS2TIME(lastInterval ? myLastIntervalBegin : myLastIntervalEnd));
337 2304 : occupancy += MIN2(leaveTime - entryTime, aggTime);
338 729 : }
339 729 : return occupancy / aggTime * 100.;
340 : }
341 :
342 :
343 : double
344 732 : MSInductLoop::getIntervalMeanSpeed(bool lastInterval) const {
345 732 : const std::vector<VehicleData>& d = collectVehiclesOnDet(myLastIntervalEnd, false, false, false, lastInterval);
346 1236 : return d.empty() ? -1. : std::accumulate(d.begin(), d.end(), 0.0, speedSum) / (double) d.size();
347 732 : }
348 :
349 :
350 : int
351 732 : MSInductLoop::getIntervalVehicleNumber(bool lastInterval) const {
352 732 : return (int)collectVehiclesOnDet(myLastIntervalEnd, false, false, false, lastInterval).size();
353 : }
354 :
355 :
356 : std::vector<std::string>
357 732 : MSInductLoop::getIntervalVehicleIDs(bool lastInterval) const {
358 : std::vector<std::string> ret;
359 3036 : for (const VehicleData& i : collectVehiclesOnDet(myLastIntervalEnd, false, false, false, lastInterval)) {
360 2304 : ret.push_back(i.idM);
361 732 : }
362 732 : return ret;
363 0 : }
364 :
365 :
366 : void
367 20 : MSInductLoop::overrideTimeSinceDetection(double time) {
368 20 : myOverrideTime = time;
369 20 : if (time < 0) {
370 4 : myOverrideEntryTime = -1;
371 : } else {
372 16 : const double entryTime = MAX2(0.0, SIMTIME - time);
373 16 : if (myOverrideEntryTime >= 0) {
374 : // maintain earlier entry time to achive continous detection
375 12 : myOverrideEntryTime = MIN2(myOverrideEntryTime, entryTime);
376 : } else {
377 4 : myOverrideEntryTime = entryTime;
378 : }
379 : }
380 20 : }
381 :
382 : void
383 28222 : MSInductLoop::writeXMLDetectorProlog(OutputDevice& dev) const {
384 56444 : dev.writeXMLHeader("detector", "det_e1_file.xsd");
385 28222 : }
386 :
387 :
388 : void
389 123886 : MSInductLoop::writeXMLOutput(OutputDevice& dev, SUMOTime startTime, SUMOTime stopTime) {
390 123886 : if (dev.isNull()) {
391 20832 : reset();
392 20832 : return;
393 : }
394 103054 : const double t(STEPS2TIME(stopTime - startTime));
395 103054 : double occupancy = 0.;
396 : double speedSum = 0.;
397 : double lengthSum = 0.;
398 103054 : int contrib = 0;
399 : // to approximate the space mean speed
400 : double inverseSpeedSum = 0.;
401 1093729 : for (const VehicleData& vData : myVehicleDataCont) {
402 1977399 : const double timeOnDetDuringInterval = vData.leaveTimeM - MAX2(STEPS2TIME(startTime), vData.entryTimeM);
403 990675 : occupancy += MIN2(timeOnDetDuringInterval, t);
404 990675 : if (!vData.leftEarlyM) {
405 987630 : speedSum += vData.speedM;
406 : assert(vData.speedM > 0.);
407 987630 : inverseSpeedSum += 1. / vData.speedM;
408 987630 : lengthSum += vData.lengthM;
409 987630 : contrib++;
410 : }
411 : }
412 103054 : const double flow = (double)contrib / t * 3600.;
413 107246 : for (std::map< SUMOTrafficObject*, double >::const_iterator i = myVehiclesOnDet.begin(); i != myVehiclesOnDet.end(); ++i) {
414 8304 : occupancy += STEPS2TIME(stopTime) - MAX2(STEPS2TIME(startTime), i->second);
415 : }
416 103054 : occupancy *= 100. / t;
417 103054 : const double meanSpeed = contrib != 0 ? speedSum / (double)contrib : -1;
418 103054 : const double harmonicMeanSpeed = contrib != 0 ? (double)contrib / inverseSpeedSum : -1;
419 103054 : const double meanLength = contrib != 0 ? lengthSum / (double)contrib : -1;
420 206108 : dev.openTag(SUMO_TAG_INTERVAL).writeTime(SUMO_ATTR_BEGIN, startTime).writeTime(SUMO_ATTR_END, stopTime);
421 103054 : dev.writeAttr(SUMO_ATTR_ID, StringUtils::escapeXML(getID())).writeAttr("nVehContrib", contrib);
422 103054 : dev.writeAttr("flow", flow).writeAttr("occupancy", occupancy).writeAttr("speed", meanSpeed).writeAttr("harmonicMeanSpeed", harmonicMeanSpeed);
423 103054 : dev.writeAttr("length", meanLength).writeAttr("nVehEntered", myEnteredVehicleNumber).closeTag();
424 103054 : reset();
425 : }
426 :
427 :
428 : void
429 25302524 : MSInductLoop::detectorUpdate(const SUMOTime /* step */) {
430 25302524 : if (myDetectPersons == (int)PersonMode::NONE) {
431 : return;
432 : }
433 78592 : if (myLane->hasPedestrians()) {
434 202640 : for (MSTransportable* p : myLane->getEdge().getPersons()) {
435 183844 : if (p->getLane() != myLane || !vehicleApplies(*p)) {
436 28504 : continue;
437 : }
438 155340 : notifyMovePerson(p, p->getDirection(), p->getPositionOnLane());
439 : }
440 : }
441 : }
442 :
443 :
444 : void
445 158544 : MSInductLoop::notifyMovePerson(MSTransportable* p, int dir, double pos) {
446 158544 : if (personApplies(*p, dir)) {
447 114112 : const double newSpeed = p->getSpeed();
448 114112 : const double newPos = (dir == MSPModel::FORWARD
449 114112 : ? pos
450 : // position relative to detector
451 31992 : : myPosition - (pos - myPosition));
452 114112 : const double oldPos = newPos - SPEED2DIST(newSpeed);
453 114112 : if (oldPos - p->getVehicleType().getLength() <= myPosition) {
454 80988 : notifyMove(*p, oldPos, newPos, newSpeed);
455 : }
456 : }
457 158544 : }
458 :
459 :
460 : std::vector<MSInductLoop::VehicleData>
461 114312 : MSInductLoop::collectVehiclesOnDet(SUMOTime tMS, bool includeEarly, bool leaveTime, bool forOccupancy, bool lastInterval) const {
462 : #ifdef HAVE_FOX
463 114312 : ScopedLocker<> lock(myNotificationMutex, myNeedLock);
464 : #endif
465 114312 : const double t = STEPS2TIME(tMS);
466 : std::vector<VehicleData> ret;
467 1184000 : for (const VehicleData& i : myVehicleDataCont) {
468 1069688 : if ((includeEarly || !i.leftEarlyM) && (!lastInterval || i.entryTimeM < t)) {
469 1066808 : if (i.entryTimeM >= t || (leaveTime && i.leaveTimeM >= t)) {
470 5690 : ret.push_back(i);
471 : }
472 : }
473 : }
474 707763 : for (const VehicleData& i : myLastVehicleDataCont) {
475 593451 : if (includeEarly || !i.leftEarlyM) {
476 593451 : if ((!lastInterval && (i.entryTimeM >= t || (leaveTime && i.leaveTimeM >= t)))
477 6120 : || (lastInterval && i.leaveTimeM <= t + STEPS2TIME(myLastIntervalEnd - myLastIntervalBegin))) { // TODO: check duration of last interval
478 6529 : ret.push_back(i);
479 : }
480 : }
481 : }
482 124581 : for (const auto& i : myVehiclesOnDet) {
483 10269 : if ((!lastInterval && (i.second >= t || leaveTime || forOccupancy))
484 72 : || (lastInterval && i.second < t && t - i.second < STEPS2TIME(DELTA_T))) { // no need to check leave time, they are still on the detector
485 10189 : SUMOTrafficObject* const v = i.first;
486 10189 : VehicleData d(*v, i.second, HAS_NOT_LEFT_DETECTOR, false);
487 10189 : d.speedM = v->getSpeed();
488 10189 : ret.push_back(d);
489 : }
490 : }
491 114312 : return ret;
492 0 : }
493 :
494 :
495 1180377 : MSInductLoop::VehicleData::VehicleData(const SUMOTrafficObject& v, double entryTimestep,
496 1180377 : double leaveTimestep, const bool leftEarly, const double detLength)
497 1180377 : : idM(v.getID()), lengthM(v.getVehicleType().getLength()), entryTimeM(entryTimestep), leaveTimeM(leaveTimestep),
498 1190566 : speedM((v.getVehicleType().getLength() + detLength) / MAX2(leaveTimestep - entryTimestep, NUMERICAL_EPS)), typeIDM(v.getVehicleType().getID()),
499 1180377 : leftEarlyM(leftEarly) {}
500 :
501 :
502 : void
503 16 : MSInductLoop::clearState(SUMOTime time) {
504 16 : myLastLeaveTime = STEPS2TIME(time);
505 16 : myEnteredVehicleNumber = 0;
506 16 : myLastVehicleDataCont.clear();
507 16 : myVehicleDataCont.clear();
508 : myVehiclesOnDet.clear();
509 16 : }
510 :
511 : /****************************************************************************/
|