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: 2026-03-02 16:00:03 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-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        28213 : 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        28213 :                            const bool needLocking) :
      67              :     MSMoveReminder(id, lane),
      68              :     MSDetectorFileOutput(id, vTypes, nextEdges, detectPersons),
      69        28209 :     myName(name),
      70        28209 :     myPosition(positionInMeters),
      71        28209 :     myEndPosition(myPosition + length),
      72        28209 :     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        28209 :     myLastLeaveTime(-3600),
      75        28209 :     myOverrideTime(-1),
      76        28209 :     myOverrideEntryTime(-1),
      77              :     myVehicleDataCont(),
      78              :     myVehiclesOnDet(),
      79        28213 :     myLastIntervalEnd(-1) {
      80              :     assert(length >= 0);
      81              :     assert(myPosition >= 0 && myEndPosition <= myLane->getLength());
      82        28209 :     reset();
      83        28213 : }
      84              : 
      85              : 
      86        54794 : MSInductLoop::~MSInductLoop() {
      87        54794 : }
      88              : 
      89              : 
      90              : void
      91       160094 : MSInductLoop::reset() {
      92              : #ifdef HAVE_FOX
      93       160094 :     ScopedLocker<> lock(myNotificationMutex, myNeedLock);
      94              : #endif
      95       160094 :     myEnteredVehicleNumber = 0;
      96       160094 :     myLastVehicleDataCont = myVehicleDataCont;
      97              :     myVehicleDataCont.clear();
      98       160094 :     myLastIntervalBegin = myLastIntervalEnd;
      99       160094 :     myLastIntervalEnd = SIMSTEP;
     100       160094 : }
     101              : 
     102              : 
     103              : bool
     104      1484532 : MSInductLoop::notifyEnter(SUMOTrafficObject& veh, Notification reason, const MSLane* /* enteredLane */) {
     105              :     // vehicles must be kept if the "inductionloop" wants to detect passeengers
     106      1484532 :     if (!vehicleApplies(veh) && (veh.isPerson() || myDetectPersons <= (int)PersonMode::WALK)) {
     107              :         return false;
     108              :     }
     109      1480195 :     if (reason != NOTIFICATION_JUNCTION) { // the junction case is handled in notifyMove
     110       235333 :         if (veh.getBackPositionOnLane(myLane) >= myPosition) {
     111              :             return false;
     112              :         }
     113       232348 :         if (veh.getPositionOnLane() >= myPosition) {
     114              : #ifdef HAVE_FOX
     115         1495 :             ScopedLocker<> lock(myNotificationMutex, myNeedLock);
     116              : #endif
     117         1495 :             myVehiclesOnDet[&veh] = SIMTIME;
     118         1495 :             myEnteredVehicleNumber++;
     119              :         }
     120              :     }
     121              :     return true;
     122              : }
     123              : 
     124              : 
     125              : bool
     126     23798484 : MSInductLoop::notifyMove(SUMOTrafficObject& veh, double oldPos,
     127              :                          double newPos, double newSpeed) {
     128     23798484 :     if (newPos < myPosition) {
     129              :         // detector not reached yet
     130              :         return true;
     131              :     }
     132      3254631 :     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      3254593 :     ScopedLocker<> lock(myNotificationMutex, myNeedLock);
     142              : #endif
     143      3254593 :     const double oldSpeed = veh.getPreviousSpeed();
     144      3254593 :     if (newPos >= myPosition && oldPos < myPosition) {
     145              :         // entered the detector by move
     146      1447678 :         const double timeBeforeEnter = MSCFModel::passingTime(oldPos, myPosition, newPos, oldSpeed, newSpeed);
     147      1447678 :         myVehiclesOnDet[&veh] = SIMTIME + timeBeforeEnter;
     148      1447678 :         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      3254593 :     double oldBackPos = oldPos - veh.getVehicleType().getLength();
     156      3254593 :     double newBackPos = newPos - veh.getVehicleType().getLength();
     157      3254593 :     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      1445512 :         if (oldBackPos <= myEndPosition) {
     162              :             const std::map<SUMOTrafficObject*, double>::iterator it = myVehiclesOnDet.find(&veh);
     163      1445512 :             if (it != myVehiclesOnDet.end()) {
     164      1445512 :                 const double entryTime = it->second;
     165      1445512 :                 const double leaveTime = SIMTIME + MSCFModel::passingTime(oldBackPos, myEndPosition, newBackPos, oldSpeed, newSpeed);
     166              :                 myVehiclesOnDet.erase(it);
     167              :                 assert(entryTime <= leaveTime);
     168      1445512 :                 myVehicleDataCont.push_back(VehicleData(veh, entryTime, leaveTime, false, myEndPosition - myPosition));
     169      1445512 :                 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      1445512 :         return false;
     193              :     }
     194              :     // vehicle stays on the detector
     195              :     return true;
     196              : }
     197              : 
     198              : 
     199              : bool
     200      1077556 : MSInductLoop::notifyLeave(SUMOTrafficObject& veh, double lastPos, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
     201      1077556 :     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      1077556 :     if (reason != MSMoveReminder::NOTIFICATION_JUNCTION || (veh.isPerson() && myDetectPersons != (int)PersonMode::NONE)) {
     206              : #ifdef HAVE_FOX
     207        32300 :         ScopedLocker<> lock(myNotificationMutex, myNeedLock);
     208              : #endif
     209              :         const std::map<SUMOTrafficObject*, double>::iterator it = myVehiclesOnDet.find(&veh);
     210        32300 :         if (it != myVehiclesOnDet.end()) {
     211         3644 :             const double entryTime = it->second;
     212         3644 :             const double leaveTime = SIMTIME + TS;
     213              :             myVehiclesOnDet.erase(it);
     214         3644 :             myVehicleDataCont.push_back(VehicleData(veh, entryTime, leaveTime, true));
     215         3644 :             myLastLeaveTime = leaveTime;
     216              :         }
     217              :         return false;
     218              :     }
     219              :     return true;
     220              : }
     221              : 
     222              : 
     223              : double
     224          130 : MSInductLoop::getSpeed(const int offset) const {
     225          130 :     const std::vector<VehicleData>& d = collectVehiclesOnDet(SIMSTEP - offset);
     226          159 :     return d.empty() ? -1. : std::accumulate(d.begin(), d.end(), 0.0, speedSum) / (double) d.size();
     227          130 : }
     228              : 
     229              : 
     230              : double
     231          130 : MSInductLoop::getVehicleLength(const int offset) const {
     232          130 :     const std::vector<VehicleData>& d = collectVehiclesOnDet(SIMSTEP - offset);
     233          159 :     return d.empty() ? -1. : std::accumulate(d.begin(), d.end(), 0.0, lengthSum) / (double)d.size();
     234          130 : }
     235              : 
     236              : 
     237              : double
     238        54482 : MSInductLoop::getOccupancy() const {
     239        54482 :     if (myOverrideTime >= 0) {
     240           36 :         return myOverrideTime < TS ? (TS - myOverrideTime) / TS * 100 : 0;
     241              :     }
     242        54446 :     const SUMOTime tbeg = SIMSTEP - DELTA_T;
     243              :     double occupancy = 0;
     244        54446 :     const double csecond = SIMTIME;
     245        60331 :     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        54446 :     }
     250        54446 :     return occupancy / TS * 100.;
     251              : }
     252              : 
     253              : 
     254              : double
     255         3333 : MSInductLoop::getEnteredNumber(const int offset) const {
     256         3333 :     if (myOverrideTime >= 0) {
     257           36 :         return myOverrideTime < TS ? 1 : 0;
     258              :     }
     259         3297 :     return (double)collectVehiclesOnDet(SIMSTEP - offset, true, true).size();
     260              : }
     261              : 
     262              : 
     263              : std::vector<std::string>
     264          994 : MSInductLoop::getVehicleIDs(const int offset) const {
     265              :     std::vector<std::string> ret;
     266         1265 :     for (const VehicleData& i : collectVehiclesOnDet(SIMSTEP - offset, true, true)) {
     267          271 :         ret.push_back(i.idM);
     268          994 :     }
     269          994 :     return ret;
     270            0 : }
     271              : 
     272              : 
     273              : double
     274       638092 : MSInductLoop::getTimeSinceLastDetection() const {
     275       638092 :     if (myOverrideTime >= 0) {
     276              :         return myOverrideTime;
     277              :     }
     278       638056 :     if (myVehiclesOnDet.size() != 0) {
     279              :         // detector is occupied
     280              :         return 0;
     281              :     }
     282       583609 :     return SIMTIME - myLastLeaveTime;
     283              : }
     284              : 
     285              : 
     286              : double
     287       150640 : MSInductLoop::getOccupancyTime() const {
     288              : #ifdef HAVE_FOX
     289       150640 :     ScopedLocker<> lock(myNotificationMutex, myNeedLock);
     290              : #endif
     291       150640 :     if (myOverrideTime >= 0) {
     292            0 :         return SIMTIME - myOverrideEntryTime;
     293              :     }
     294       150640 :     if (myVehiclesOnDet.size() == 0) {
     295              :         // detector is unoccupied
     296              :         return 0;
     297              :     } else {
     298              :         double minEntry = std::numeric_limits<double>::max();
     299         4584 :         for (const auto& i : myVehiclesOnDet) {
     300         2292 :             minEntry = MIN2(i.second, minEntry);
     301              :         }
     302         2292 :         return SIMTIME - minEntry;
     303              :     }
     304              : }
     305              : 
     306              : 
     307              : 
     308              : SUMOTime
     309       265454 : MSInductLoop::getLastDetectionTime() const {
     310       265454 :     if (myOverrideTime >= 0) {
     311            0 :         return SIMSTEP - TIME2STEPS(myOverrideTime);
     312              :     }
     313       265454 :     if (myVehiclesOnDet.size() != 0) {
     314        12612 :         return MSNet::getInstance()->getCurrentTimeStep();
     315              :     }
     316       353830 :     return TIME2STEPS(myLastLeaveTime);
     317              : }
     318              : 
     319              : 
     320              : double
     321          976 : MSInductLoop::getIntervalOccupancy(bool lastInterval) const {
     322              :     double occupancy = 0;
     323          976 :     const double csecond = lastInterval ? STEPS2TIME(myLastIntervalEnd) : SIMTIME;
     324          976 :     const double aggTime = csecond - STEPS2TIME(lastInterval ? myLastIntervalBegin : myLastIntervalEnd);
     325          976 :     if (aggTime == 0) {
     326              :         return 0;
     327              :     }
     328         4044 :     for (const VehicleData& i : collectVehiclesOnDet(myLastIntervalEnd, false, false, true, lastInterval)) {
     329         3072 :         const double leaveTime = i.leaveTimeM == HAS_NOT_LEFT_DETECTOR ? csecond : MIN2(i.leaveTimeM, csecond);
     330         3072 :         const double entryTime = MAX2(i.entryTimeM, STEPS2TIME(lastInterval ? myLastIntervalBegin : myLastIntervalEnd));
     331         3072 :         occupancy += MIN2(leaveTime - entryTime, aggTime);
     332          972 :     }
     333          972 :     return occupancy / aggTime * 100.;
     334              : }
     335              : 
     336              : 
     337              : double
     338          976 : MSInductLoop::getIntervalMeanSpeed(bool lastInterval) const {
     339          976 :     const std::vector<VehicleData>& d = collectVehiclesOnDet(myLastIntervalEnd, false, false, false, lastInterval);
     340         1648 :     return d.empty() ? -1. : std::accumulate(d.begin(), d.end(), 0.0, speedSum) / (double) d.size();
     341          976 : }
     342              : 
     343              : 
     344              : int
     345          976 : MSInductLoop::getIntervalVehicleNumber(bool lastInterval) const {
     346          976 :     return (int)collectVehiclesOnDet(myLastIntervalEnd, false, false, false, lastInterval).size();
     347              : }
     348              : 
     349              : 
     350              : std::vector<std::string>
     351          976 : MSInductLoop::getIntervalVehicleIDs(bool lastInterval) const {
     352              :     std::vector<std::string> ret;
     353         4048 :     for (const VehicleData& i : collectVehiclesOnDet(myLastIntervalEnd, false, false, false, lastInterval)) {
     354         3072 :         ret.push_back(i.idM);
     355          976 :     }
     356          976 :     return ret;
     357            0 : }
     358              : 
     359              : 
     360              : void
     361           15 : MSInductLoop::overrideTimeSinceDetection(double time) {
     362           15 :     myOverrideTime = time;
     363           15 :     if (time < 0) {
     364            3 :         myOverrideEntryTime = -1;
     365              :     } else {
     366           12 :         const double entryTime = MAX2(0.0, SIMTIME - time);
     367           12 :         if (myOverrideEntryTime >= 0) {
     368              :             // maintain earlier entry time to achive continous detection
     369            9 :             myOverrideEntryTime = MIN2(myOverrideEntryTime, entryTime);
     370              :         } else {
     371            3 :             myOverrideEntryTime = entryTime;
     372              :         }
     373              :     }
     374           15 : }
     375              : 
     376              : void
     377        28205 : MSInductLoop::writeXMLDetectorProlog(OutputDevice& dev) const {
     378        56410 :     dev.writeXMLHeader("detector", "det_e1_file.xsd");
     379        28205 : }
     380              : 
     381              : 
     382              : void
     383       131885 : MSInductLoop::writeXMLOutput(OutputDevice& dev, SUMOTime startTime, SUMOTime stopTime) {
     384       131885 :     if (dev.isNull()) {
     385        21212 :         reset();
     386        21212 :         return;
     387              :     }
     388       110673 :     const double t(STEPS2TIME(stopTime - startTime));
     389       110673 :     double occupancy = 0.;
     390              :     double speedSum = 0.;
     391              :     double lengthSum = 0.;
     392       110673 :     int contrib = 0;
     393              :     // to approximate the space mean speed
     394              :     double inverseSpeedSum = 0.;
     395      1380296 :     for (const VehicleData& vData : myVehicleDataCont) {
     396      2532802 :         const double timeOnDetDuringInterval = vData.leaveTimeM - MAX2(STEPS2TIME(startTime), vData.entryTimeM);
     397      1269623 :         occupancy += MIN2(timeOnDetDuringInterval, t);
     398      1269623 :         if (!vData.leftEarlyM) {
     399      1266557 :             speedSum += vData.speedM;
     400              :             assert(vData.speedM > 0.);
     401      1266557 :             inverseSpeedSum += 1. / vData.speedM;
     402      1266557 :             lengthSum += vData.lengthM;
     403      1266557 :             contrib++;
     404              :         }
     405              :     }
     406       110673 :     const double flow = (double)contrib / t * 3600.;
     407       117360 :     for (std::map< SUMOTrafficObject*, double >::const_iterator i = myVehiclesOnDet.begin(); i != myVehiclesOnDet.end(); ++i) {
     408        13294 :         occupancy += STEPS2TIME(stopTime) - MAX2(STEPS2TIME(startTime), i->second);
     409              :     }
     410       110673 :     occupancy *= 100. / t;
     411       110673 :     const double meanSpeed = contrib != 0 ? speedSum / (double)contrib : -1;
     412       110673 :     const double harmonicMeanSpeed = contrib != 0 ? (double)contrib / inverseSpeedSum : -1;
     413       110673 :     const double meanLength = contrib != 0 ? lengthSum / (double)contrib : -1;
     414       110673 :     dev.openTag(SUMO_TAG_INTERVAL).writeAttr(SUMO_ATTR_BEGIN, STEPS2TIME(startTime)).writeAttr(SUMO_ATTR_END, STEPS2TIME(stopTime));
     415       221346 :     dev.writeAttr(SUMO_ATTR_ID, StringUtils::escapeXML(getID())).writeAttr("nVehContrib", contrib);
     416       221346 :     dev.writeAttr("flow", flow).writeAttr("occupancy", occupancy).writeAttr("speed", meanSpeed).writeAttr("harmonicMeanSpeed", harmonicMeanSpeed);
     417       221346 :     dev.writeAttr("length", meanLength).writeAttr("nVehEntered", myEnteredVehicleNumber).closeTag();
     418       110673 :     reset();
     419              : }
     420              : 
     421              : 
     422              : void
     423     27535008 : MSInductLoop::detectorUpdate(const SUMOTime /* step */) {
     424     27535008 :     if (myDetectPersons == (int)PersonMode::NONE) {
     425              :         return;
     426              :     }
     427        78628 :     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       115387 : MSInductLoop::collectVehiclesOnDet(SUMOTime tMS, bool includeEarly, bool leaveTime, bool forOccupancy, bool lastInterval) const {
     456              : #ifdef HAVE_FOX
     457       115387 :     ScopedLocker<> lock(myNotificationMutex, myNeedLock);
     458              : #endif
     459       115387 :     const double t = STEPS2TIME(tMS);
     460              :     std::vector<VehicleData> ret;
     461      1186924 :     for (const VehicleData& i : myVehicleDataCont) {
     462      1071537 :         if ((includeEarly || !i.leftEarlyM) && (!lastInterval || i.entryTimeM < t)) {
     463      1067769 :             if (i.entryTimeM >= t || (leaveTime && i.leaveTimeM >= t)) {
     464         6585 :                 ret.push_back(i);
     465              :             }
     466              :         }
     467              :     }
     468       712948 :     for (const VehicleData& i : myLastVehicleDataCont) {
     469       597561 :         if (includeEarly || !i.leftEarlyM) {
     470       597561 :             if ((!lastInterval && (i.entryTimeM >= t || (leaveTime && i.leaveTimeM >= t)))
     471         8160 :                     || (lastInterval && i.leaveTimeM <= t + STEPS2TIME(myLastIntervalEnd - myLastIntervalBegin))) { // TODO: check duration of last interval
     472         8690 :                 ret.push_back(i);
     473              :             }
     474              :         }
     475              :     }
     476       125708 :     for (const auto& i : myVehiclesOnDet) {
     477        10321 :         if ((!lastInterval && (i.second >= t || leaveTime || forOccupancy))
     478           96 :                 || (lastInterval && i.second < t && t - i.second < STEPS2TIME(DELTA_T))) { // no need to check leave time, they are still on the detector
     479        10217 :             SUMOTrafficObject* const v = i.first;
     480        10217 :             VehicleData d(*v, i.second, HAS_NOT_LEFT_DETECTOR, false);
     481        10217 :             d.speedM = v->getSpeed();
     482        10217 :             ret.push_back(d);
     483              :         }
     484              :     }
     485       115387 :     return ret;
     486            0 : }
     487              : 
     488              : 
     489      1459373 : MSInductLoop::VehicleData::VehicleData(const SUMOTrafficObject& v, double entryTimestep,
     490      1459373 :                                        double leaveTimestep, const bool leftEarly, const double detLength)
     491      1459373 :     : idM(v.getID()), lengthM(v.getVehicleType().getLength()), entryTimeM(entryTimestep), leaveTimeM(leaveTimestep),
     492      1469590 :       speedM((v.getVehicleType().getLength() + detLength) / MAX2(leaveTimestep - entryTimestep, NUMERICAL_EPS)), typeIDM(v.getVehicleType().getID()),
     493      1459373 :       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