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/MSVehicleControl.h>
43 : #include <microsim/transportables/MSTransportable.h>
44 : #include <microsim/transportables/MSPModel.h>
45 : #include <utils/common/MsgHandler.h>
46 : #include <utils/common/UtilExceptions.h>
47 : #include <utils/common/StringUtils.h>
48 : #include <utils/iodevices/OutputDevice.h>
49 :
50 : #define HAS_NOT_LEFT_DETECTOR -1
51 :
52 : //#define DEBUG_E1_NOTIFY_MOVE
53 :
54 : #define DEBUG_COND (true)
55 : //#define DEBUG_COND (isSelected())
56 : //#define DEBUG_COND (getID()=="")
57 :
58 : // ===========================================================================
59 : // method definitions
60 : // ===========================================================================
61 28256 : MSInductLoop::MSInductLoop(const std::string& id, MSLane* const lane,
62 : double positionInMeters,
63 : double length, std::string name,
64 : const std::string& vTypes,
65 : const std::string& nextEdges,
66 : int detectPersons,
67 28256 : const bool needLocking) :
68 : MSMoveReminder(id, lane),
69 : MSDetectorFileOutput(id, vTypes, nextEdges, detectPersons),
70 28252 : myName(name),
71 28252 : myPosition(positionInMeters),
72 28252 : myEndPosition(myPosition + length),
73 28252 : myNeedLock(needLocking || MSGlobals::gNumSimThreads > 1),
74 : // initialize in a way which doesn't impact actualted traffic lights at simulation start (yet doesn't look ugly in the outputs)
75 28252 : myLastLeaveTime(-3600),
76 28252 : myOverrideTime(-1),
77 28252 : myOverrideEntryTime(-1),
78 : myVehicleDataCont(),
79 : myVehiclesOnDet(),
80 28256 : myLastIntervalEnd(-1) {
81 : assert(length >= 0);
82 : assert(myPosition >= 0 && myEndPosition <= myLane->getLength());
83 28252 : reset();
84 28256 : }
85 :
86 :
87 54865 : MSInductLoop::~MSInductLoop() {
88 54865 : }
89 :
90 :
91 : void
92 152298 : MSInductLoop::reset() {
93 : #ifdef HAVE_FOX
94 152298 : ScopedLocker<> lock(myNotificationMutex, myNeedLock);
95 : #endif
96 152298 : myEnteredVehicleNumber = 0;
97 152298 : myLastVehicleDataCont = myVehicleDataCont;
98 : myVehicleDataCont.clear();
99 152298 : myLastIntervalBegin = myLastIntervalEnd;
100 152298 : myLastIntervalEnd = SIMSTEP;
101 152298 : }
102 :
103 :
104 : bool
105 1206691 : MSInductLoop::notifyEnter(SUMOTrafficObject& veh, Notification reason, const MSLane* /* enteredLane */) {
106 : // vehicles must be kept if the "inductionloop" wants to detect passeengers
107 1206691 : if (!vehicleApplies(veh) && (veh.isPerson() || myDetectPersons <= (int)PersonMode::WALK)) {
108 : return false;
109 : }
110 1202306 : if (reason != NOTIFICATION_JUNCTION) { // the junction case is handled in notifyMove
111 232806 : if (veh.getBackPositionOnLane(myLane) >= myPosition) {
112 : return false;
113 : }
114 229859 : if (veh.getPositionOnLane() >= myPosition) {
115 : #ifdef HAVE_FOX
116 1288 : ScopedLocker<> lock(myNotificationMutex, myNeedLock);
117 : #endif
118 1288 : myVehiclesOnDet[&veh] = SIMTIME;
119 1288 : myEnteredVehicleNumber++;
120 : }
121 : }
122 : return true;
123 : }
124 :
125 :
126 : bool
127 23044285 : MSInductLoop::notifyMove(SUMOTrafficObject& veh, double oldPos,
128 : double newPos, double newSpeed) {
129 23044285 : if (newPos < myPosition) {
130 : // detector not reached yet
131 : return true;
132 : }
133 2742213 : if (myDetectPersons > (int)PersonMode::WALK && !veh.isPerson()) {
134 : bool keep = false;
135 38 : MSBaseVehicle& v = dynamic_cast<MSBaseVehicle&>(veh);
136 76 : for (MSTransportable* p : v.getPersons()) {
137 38 : keep = notifyMove(*p, oldPos, newPos, newSpeed);
138 : }
139 38 : return keep;
140 : }
141 : #ifdef HAVE_FOX
142 2742175 : ScopedLocker<> lock(myNotificationMutex, myNeedLock);
143 : #endif
144 2742175 : const double oldSpeed = veh.getPreviousSpeed();
145 2742175 : if (newPos >= myPosition && oldPos < myPosition) {
146 : // entered the detector by move
147 1169998 : const double timeBeforeEnter = MSCFModel::passingTime(oldPos, myPosition, newPos, oldSpeed, newSpeed);
148 1169998 : myVehiclesOnDet[&veh] = SIMTIME + timeBeforeEnter;
149 1169998 : myEnteredVehicleNumber++;
150 : #ifdef DEBUG_E1_NOTIFY_MOVE
151 : if (DEBUG_COND) {
152 : std::cout << SIMTIME << " det=" << getID() << " enteredVeh=" << veh.getID() << "\n";
153 : }
154 : #endif
155 : }
156 2742175 : double oldBackPos = oldPos - veh.getVehicleType().getLength();
157 2742175 : double newBackPos = newPos - veh.getVehicleType().getLength();
158 2742175 : if (newBackPos > myEndPosition) {
159 : // vehicle passed the detector (it may have changed onto this lane somewhere past the detector)
160 : // assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed > 0 || myVehiclesOnDet.find(&veh) == myVehiclesOnDet.end());
161 : // assertion is invalid in case of teleportation
162 1167628 : if (oldBackPos <= myEndPosition) {
163 : const std::map<SUMOTrafficObject*, double>::iterator it = myVehiclesOnDet.find(&veh);
164 1167628 : if (it != myVehiclesOnDet.end()) {
165 1167628 : const double entryTime = it->second;
166 1167628 : const double leaveTime = SIMTIME + MSCFModel::passingTime(oldBackPos, myEndPosition, newBackPos, oldSpeed, newSpeed);
167 : myVehiclesOnDet.erase(it);
168 : assert(entryTime <= leaveTime);
169 1167628 : myVehicleDataCont.push_back(VehicleData(veh, entryTime, leaveTime, false, myEndPosition - myPosition));
170 1167628 : myLastLeaveTime = leaveTime;
171 : #ifdef DEBUG_E1_NOTIFY_MOVE
172 : if (DEBUG_COND) {
173 : std::cout << SIMTIME << " det=" << getID() << " leftVeh=" << veh.getID() << " oldBackPos=" << oldBackPos << " newBackPos=" << newBackPos << "\n";
174 : }
175 : #endif
176 : } else {
177 : #ifdef DEBUG_E1_NOTIFY_MOVE
178 : if (DEBUG_COND) {
179 : std::cout << SIMTIME << " det=" << getID() << " leftVeh=" << veh.getID() << " oldBackPos=" << oldBackPos << " newBackPos=" << newBackPos << " (notFound)\n";
180 : }
181 : #endif
182 : }
183 : } else {
184 : // vehicle is already beyond the detector...
185 : // This can happen even if it is still registered in myVehiclesOnDet, e.g., after teleport.
186 0 : myVehiclesOnDet.erase(&veh);
187 : #ifdef DEBUG_E1_NOTIFY_MOVE
188 : if (DEBUG_COND) {
189 : std::cout << SIMTIME << " det=" << getID() << " leftVeh=" << veh.getID() << " oldBackPos=" << oldBackPos << " newBackPos=" << newBackPos << " (unusual)\n";
190 : }
191 : #endif
192 : }
193 1167628 : return false;
194 : }
195 : // vehicle stays on the detector
196 : return true;
197 : }
198 :
199 :
200 : bool
201 858942 : MSInductLoop::notifyLeave(SUMOTrafficObject& veh, double lastPos, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
202 858942 : if (veh.isPerson() && myDetectPersons != (int)PersonMode::NONE) {
203 3203 : const int lastDir = lastPos < 0 ? MSPModel::BACKWARD : MSPModel::FORWARD;
204 3203 : notifyMovePerson(dynamic_cast<MSTransportable*>(&veh), lastDir, lastPos);
205 : }
206 858942 : if (reason != MSMoveReminder::NOTIFICATION_JUNCTION || (veh.isPerson() && myDetectPersons != (int)PersonMode::NONE)) {
207 : #ifdef HAVE_FOX
208 32193 : ScopedLocker<> lock(myNotificationMutex, myNeedLock);
209 : #endif
210 : const std::map<SUMOTrafficObject*, double>::iterator it = myVehiclesOnDet.find(&veh);
211 32193 : if (it != myVehiclesOnDet.end()) {
212 3643 : const double entryTime = it->second;
213 3643 : const double leaveTime = SIMTIME + TS;
214 : myVehiclesOnDet.erase(it);
215 3643 : myVehicleDataCont.push_back(VehicleData(veh, entryTime, leaveTime, true));
216 3643 : myLastLeaveTime = leaveTime;
217 : }
218 : return false;
219 : }
220 : return true;
221 : }
222 :
223 :
224 : double
225 145 : MSInductLoop::getSpeed(const int offset) const {
226 145 : const std::vector<VehicleData>& d = collectVehiclesOnDet(SIMSTEP - offset);
227 174 : return d.empty() ? -1. : std::accumulate(d.begin(), d.end(), 0.0, speedSum) / (double) d.size();
228 145 : }
229 :
230 :
231 : double
232 145 : MSInductLoop::getVehicleLength(const int offset) const {
233 145 : const std::vector<VehicleData>& d = collectVehiclesOnDet(SIMSTEP - offset);
234 174 : return d.empty() ? -1. : std::accumulate(d.begin(), d.end(), 0.0, lengthSum) / (double)d.size();
235 145 : }
236 :
237 :
238 : double
239 54403 : MSInductLoop::getOccupancy() const {
240 54403 : if (myOverrideTime >= 0) {
241 48 : return myOverrideTime < TS ? (TS - myOverrideTime) / TS * 100 : 0;
242 : }
243 54355 : const SUMOTime tbeg = SIMSTEP - DELTA_T;
244 : double occupancy = 0;
245 54355 : const double csecond = SIMTIME;
246 60199 : for (const VehicleData& i : collectVehiclesOnDet(tbeg, false, false, true)) {
247 5844 : const double leaveTime = i.leaveTimeM == HAS_NOT_LEFT_DETECTOR ? csecond : MIN2(i.leaveTimeM, csecond);
248 5844 : const double entryTime = MAX2(i.entryTimeM, STEPS2TIME(tbeg));
249 8615 : occupancy += MIN2(leaveTime - entryTime, TS);
250 54355 : }
251 54355 : return occupancy / TS * 100.;
252 : }
253 :
254 :
255 : double
256 3024 : MSInductLoop::getEnteredNumber(const int offset) const {
257 3024 : if (myOverrideTime >= 0) {
258 48 : return myOverrideTime < TS ? 1 : 0;
259 : }
260 2976 : return (double)collectVehiclesOnDet(SIMSTEP - offset, true, true).size();
261 : }
262 :
263 :
264 : std::vector<std::string>
265 875 : MSInductLoop::getVehicleIDs(const int offset) const {
266 : std::vector<std::string> ret;
267 1101 : for (const VehicleData& i : collectVehiclesOnDet(SIMSTEP - offset, true, true)) {
268 226 : ret.push_back(i.idM);
269 875 : }
270 875 : return ret;
271 0 : }
272 :
273 :
274 : double
275 645556 : MSInductLoop::getTimeSinceLastDetection() const {
276 645556 : if (myOverrideTime >= 0) {
277 : return myOverrideTime;
278 : }
279 645508 : if (myVehiclesOnDet.size() != 0) {
280 : // detector is occupied
281 : return 0;
282 : }
283 589433 : return SIMTIME - myLastLeaveTime;
284 : }
285 :
286 :
287 : void
288 8 : MSInductLoop::loadTimeSinceLastDetection(double time) {
289 8 : myLastLeaveTime = SIMTIME - time;
290 8 : }
291 :
292 :
293 : double
294 163074 : MSInductLoop::getOccupancyTime() const {
295 : #ifdef HAVE_FOX
296 163074 : ScopedLocker<> lock(myNotificationMutex, myNeedLock);
297 : #endif
298 163074 : if (myOverrideTime >= 0) {
299 0 : return SIMTIME - myOverrideEntryTime;
300 : }
301 163074 : if (myVehiclesOnDet.size() == 0) {
302 : // detector is unoccupied
303 : return 0;
304 : } else {
305 : double minEntry = std::numeric_limits<double>::max();
306 4490 : for (const auto& i : myVehiclesOnDet) {
307 2245 : minEntry = MIN2(i.second, minEntry);
308 : }
309 2245 : return SIMTIME - minEntry;
310 : }
311 : }
312 :
313 :
314 : double
315 1044 : MSInductLoop::getArrivalDelay() const {
316 : #ifdef HAVE_FOX
317 1044 : ScopedLocker<> lock(myNotificationMutex, myNeedLock);
318 : #endif
319 1044 : MSVehicleControl& vc = MSNet::getInstance()->getVehicleControl();
320 : double result = -INVALID_DOUBLE;
321 1072 : for (const auto& item : collectVehiclesOnDet(SIMSTEP - DELTA_T)) {
322 28 : SUMOVehicle* v = vc.getVehicle(item.idM);
323 28 : if (v != nullptr) {
324 28 : MSBaseVehicle* veh = dynamic_cast<MSBaseVehicle*>(v);
325 28 : double ad = veh->getStopArrivalDelay();
326 28 : if (ad != INVALID_DOUBLE) {
327 : result = MAX2(result, ad);
328 : }
329 : }
330 1044 : }
331 1044 : return result;
332 : }
333 :
334 :
335 : SUMOTime
336 270098 : MSInductLoop::getLastDetectionTime() const {
337 270098 : if (myOverrideTime >= 0) {
338 0 : return SIMSTEP - TIME2STEPS(myOverrideTime);
339 : }
340 270098 : if (myVehiclesOnDet.size() != 0) {
341 12676 : return MSNet::getInstance()->getCurrentTimeStep();
342 : }
343 361705 : return TIME2STEPS(myLastLeaveTime);
344 : }
345 :
346 :
347 : double
348 972 : MSInductLoop::getIntervalOccupancy(bool lastInterval) const {
349 : double occupancy = 0;
350 972 : const double csecond = lastInterval ? STEPS2TIME(myLastIntervalEnd) : SIMTIME;
351 972 : const double aggTime = csecond - STEPS2TIME(lastInterval ? myLastIntervalBegin : myLastIntervalEnd);
352 972 : if (aggTime == 0) {
353 : return 0;
354 : }
355 4040 : for (const VehicleData& i : collectVehiclesOnDet(myLastIntervalEnd, false, false, true, lastInterval)) {
356 3072 : const double leaveTime = i.leaveTimeM == HAS_NOT_LEFT_DETECTOR ? csecond : MIN2(i.leaveTimeM, csecond);
357 3072 : const double entryTime = MAX2(i.entryTimeM, STEPS2TIME(lastInterval ? myLastIntervalBegin : myLastIntervalEnd));
358 3072 : occupancy += MIN2(leaveTime - entryTime, aggTime);
359 968 : }
360 968 : return occupancy / aggTime * 100.;
361 : }
362 :
363 :
364 : double
365 972 : MSInductLoop::getIntervalMeanSpeed(bool lastInterval) const {
366 972 : const std::vector<VehicleData>& d = collectVehiclesOnDet(myLastIntervalEnd, false, false, false, lastInterval);
367 1644 : return d.empty() ? -1. : std::accumulate(d.begin(), d.end(), 0.0, speedSum) / (double) d.size();
368 972 : }
369 :
370 :
371 : int
372 972 : MSInductLoop::getIntervalVehicleNumber(bool lastInterval) const {
373 972 : return (int)collectVehiclesOnDet(myLastIntervalEnd, false, false, false, lastInterval).size();
374 : }
375 :
376 :
377 : std::vector<std::string>
378 972 : MSInductLoop::getIntervalVehicleIDs(bool lastInterval) const {
379 : std::vector<std::string> ret;
380 4044 : for (const VehicleData& i : collectVehiclesOnDet(myLastIntervalEnd, false, false, false, lastInterval)) {
381 3072 : ret.push_back(i.idM);
382 972 : }
383 972 : return ret;
384 0 : }
385 :
386 :
387 : void
388 20 : MSInductLoop::overrideTimeSinceDetection(double time) {
389 20 : myOverrideTime = time;
390 20 : if (time < 0) {
391 4 : myOverrideEntryTime = -1;
392 : } else {
393 16 : const double entryTime = MAX2(0.0, SIMTIME - time);
394 16 : if (myOverrideEntryTime >= 0) {
395 : // maintain earlier entry time to achive continous detection
396 12 : myOverrideEntryTime = MIN2(myOverrideEntryTime, entryTime);
397 : } else {
398 4 : myOverrideEntryTime = entryTime;
399 : }
400 : }
401 20 : }
402 :
403 : void
404 28248 : MSInductLoop::writeXMLDetectorProlog(OutputDevice& dev) const {
405 56496 : dev.writeXMLHeader("detector", "det_e1_file.xsd");
406 28248 : }
407 :
408 :
409 : void
410 124046 : MSInductLoop::writeXMLOutput(OutputDevice& dev, SUMOTime startTime, SUMOTime stopTime) {
411 124046 : if (dev.isNull()) {
412 21018 : reset();
413 21018 : return;
414 : }
415 103028 : const double t(STEPS2TIME(stopTime - startTime));
416 103028 : double occupancy = 0.;
417 : double speedSum = 0.;
418 : double lengthSum = 0.;
419 103028 : int contrib = 0;
420 : // to approximate the space mean speed
421 : double inverseSpeedSum = 0.;
422 1093520 : for (const VehicleData& vData : myVehicleDataCont) {
423 1977055 : const double timeOnDetDuringInterval = vData.leaveTimeM - MAX2(STEPS2TIME(startTime), vData.entryTimeM);
424 990492 : occupancy += MIN2(timeOnDetDuringInterval, t);
425 990492 : if (!vData.leftEarlyM) {
426 987476 : speedSum += vData.speedM;
427 : assert(vData.speedM > 0.);
428 987476 : inverseSpeedSum += 1. / vData.speedM;
429 987476 : lengthSum += vData.lengthM;
430 987476 : contrib++;
431 : }
432 : }
433 103028 : const double flow = (double)contrib / t * 3600.;
434 107199 : for (std::map< SUMOTrafficObject*, double >::const_iterator i = myVehiclesOnDet.begin(); i != myVehiclesOnDet.end(); ++i) {
435 8261 : occupancy += STEPS2TIME(stopTime) - MAX2(STEPS2TIME(startTime), i->second);
436 : }
437 103028 : occupancy *= 100. / t;
438 103028 : const double meanSpeed = contrib != 0 ? speedSum / (double)contrib : -1;
439 103028 : const double harmonicMeanSpeed = contrib != 0 ? (double)contrib / inverseSpeedSum : -1;
440 103028 : const double meanLength = contrib != 0 ? lengthSum / (double)contrib : -1;
441 206056 : dev.openTag(SUMO_TAG_INTERVAL).writeTime(SUMO_ATTR_BEGIN, startTime).writeTime(SUMO_ATTR_END, stopTime);
442 103028 : dev.writeAttr(SUMO_ATTR_ID, StringUtils::escapeXML(getID())).writeAttr("nVehContrib", contrib);
443 103028 : dev.writeAttr("flow", flow).writeAttr("occupancy", occupancy).writeAttr("speed", meanSpeed).writeAttr("harmonicMeanSpeed", harmonicMeanSpeed);
444 103028 : dev.writeAttr("length", meanLength).writeAttr("nVehEntered", myEnteredVehicleNumber).closeTag();
445 103028 : reset();
446 : }
447 :
448 :
449 : void
450 25345037 : MSInductLoop::detectorUpdate(const SUMOTime /* step */) {
451 25345037 : if (myDetectPersons == (int)PersonMode::NONE) {
452 : return;
453 : }
454 78492 : if (myLane->hasPedestrians()) {
455 202544 : for (MSTransportable* p : myLane->getEdge().getPersons()) {
456 183796 : if (p->getLane() != myLane || !vehicleApplies(*p)) {
457 28500 : continue;
458 : }
459 155296 : notifyMovePerson(p, p->getDirection(), p->getPositionOnLane());
460 : }
461 : }
462 : }
463 :
464 :
465 : void
466 158499 : MSInductLoop::notifyMovePerson(MSTransportable* p, int dir, double pos) {
467 158499 : if (personApplies(*p, dir)) {
468 114067 : const double newSpeed = p->getSpeed();
469 114067 : const double newPos = (dir == MSPModel::FORWARD
470 114067 : ? pos
471 : // position relative to detector
472 31992 : : myPosition - (pos - myPosition));
473 114067 : const double oldPos = newPos - SPEED2DIST(newSpeed);
474 114067 : if (oldPos - p->getVehicleType().getLength() <= myPosition) {
475 80986 : notifyMove(*p, oldPos, newPos, newSpeed);
476 : }
477 : }
478 158499 : }
479 :
480 :
481 : std::vector<MSInductLoop::VehicleData>
482 115835 : MSInductLoop::collectVehiclesOnDet(SUMOTime tMS, bool includeEarly, bool leaveTime, bool forOccupancy, bool lastInterval) const {
483 : #ifdef HAVE_FOX
484 115835 : ScopedLocker<> lock(myNotificationMutex, myNeedLock);
485 : #endif
486 115835 : const double t = STEPS2TIME(tMS);
487 : std::vector<VehicleData> ret;
488 1194968 : for (const VehicleData& i : myVehicleDataCont) {
489 1079133 : if ((includeEarly || !i.leftEarlyM) && (!lastInterval || i.entryTimeM < t)) {
490 1075419 : if (i.entryTimeM >= t || (leaveTime && i.leaveTimeM >= t)) {
491 6570 : ret.push_back(i);
492 : }
493 : }
494 : }
495 713366 : for (const VehicleData& i : myLastVehicleDataCont) {
496 597531 : if (includeEarly || !i.leftEarlyM) {
497 597531 : if ((!lastInterval && (i.entryTimeM >= t || (leaveTime && i.leaveTimeM >= t)))
498 8160 : || (lastInterval && i.leaveTimeM <= t + STEPS2TIME(myLastIntervalEnd - myLastIntervalBegin))) { // TODO: check duration of last interval
499 8689 : ret.push_back(i);
500 : }
501 : }
502 : }
503 125979 : for (const auto& i : myVehiclesOnDet) {
504 10144 : if ((!lastInterval && (i.second >= t || leaveTime || forOccupancy))
505 96 : || (lastInterval && i.second < t && t - i.second < STEPS2TIME(DELTA_T))) { // no need to check leave time, they are still on the detector
506 10042 : SUMOTrafficObject* const v = i.first;
507 10042 : VehicleData d(*v, i.second, HAS_NOT_LEFT_DETECTOR, false);
508 10042 : d.speedM = v->getSpeed();
509 10042 : ret.push_back(d);
510 : }
511 : }
512 115835 : return ret;
513 0 : }
514 :
515 :
516 1181313 : MSInductLoop::VehicleData::VehicleData(const SUMOTrafficObject& v, double entryTimestep,
517 1181313 : double leaveTimestep, const bool leftEarly, const double detLength)
518 1181313 : : idM(v.getID()), lengthM(v.getVehicleType().getLength()), entryTimeM(entryTimestep), leaveTimeM(leaveTimestep),
519 1191358 : speedM((v.getVehicleType().getLength() + detLength) / MAX2(leaveTimestep - entryTimestep, NUMERICAL_EPS)), typeIDM(v.getVehicleType().getID()),
520 1181313 : leftEarlyM(leftEarly) {}
521 :
522 :
523 : void
524 16 : MSInductLoop::clearState(SUMOTime time) {
525 16 : myLastLeaveTime = STEPS2TIME(time);
526 16 : myEnteredVehicleNumber = 0;
527 16 : myLastVehicleDataCont.clear();
528 16 : myVehicleDataCont.clear();
529 : myVehiclesOnDet.clear();
530 16 : }
531 :
532 : /****************************************************************************/
|