LCOV - code coverage report
Current view: top level - src/microsim/output - MSInductLoop.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 97.3 % 224 218
Test Date: 2026-04-16 16:39:47 Functions: 100.0 % 28 28

            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              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1