LCOV - code coverage report
Current view: top level - src/microsim/output - MSInductLoop.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 97.3 % 221 215
Test Date: 2024-11-20 15:55:46 Functions: 100.0 % 27 27

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

Generated by: LCOV version 2.0-1