LCOV - code coverage report
Current view: top level - src/microsim/output - MSInductLoop.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 97.4 % 235 229
Test Date: 2026-05-24 16:29:35 Functions: 100.0 % 29 29

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

Generated by: LCOV version 2.0-1