LCOV - code coverage report
Current view: top level - src/router - RONet.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 91.2 % 521 475
Test Date: 2026-09-23 15:43:02 Functions: 100.0 % 49 49

            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    RONet.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Jakob Erdmann
      17              : /// @author  Michael Behrisch
      18              : /// @date    Sept 2002
      19              : ///
      20              : // The router's network representation
      21              : /****************************************************************************/
      22              : #include <config.h>
      23              : 
      24              : #include <algorithm>
      25              : #include <utils/router/RouteCostCalculator.h>
      26              : #include <utils/vehicle/SUMOVTypeParameter.h>
      27              : #include <utils/router/SUMOAbstractRouter.h>
      28              : #include <utils/options/OptionsCont.h>
      29              : #include <utils/common/UtilExceptions.h>
      30              : #include <utils/common/ToString.h>
      31              : #include <utils/common/StringUtils.h>
      32              : #include <utils/common/RandHelper.h>
      33              : #include <utils/common/SUMOVehicleClass.h>
      34              : #include <utils/iodevices/OutputDevice.h>
      35              : #include "ROEdge.h"
      36              : #include "ROLane.h"
      37              : #include "RONode.h"
      38              : #include "ROPerson.h"
      39              : #include "RORoute.h"
      40              : #include "RORouteDef.h"
      41              : #include "ROVehicle.h"
      42              : #include "ROAbstractEdgeBuilder.h"
      43              : #include "RONet.h"
      44              : 
      45              : 
      46              : // ===========================================================================
      47              : // static member definitions
      48              : // ===========================================================================
      49              : RONet* RONet::myInstance = nullptr;
      50              : 
      51              : 
      52              : // ===========================================================================
      53              : // method definitions
      54              : // ===========================================================================
      55              : RONet*
      56      5944790 : RONet::getInstance(void) {
      57      5944790 :     if (myInstance != nullptr) {
      58      5944790 :         return myInstance;
      59              :     }
      60            0 :     throw ProcessError(TL("A network was not yet constructed."));
      61              : }
      62              : 
      63              : 
      64         5032 : RONet::RONet() :
      65         5032 :     myVehicleTypes(), myDefaultVTypeMayBeDeleted(true),
      66         5032 :     myDefaultPedTypeMayBeDeleted(true),
      67         5032 :     myDefaultBikeTypeMayBeDeleted(true),
      68         5032 :     myDefaultTaxiTypeMayBeDeleted(true),
      69         5032 :     myDefaultRailTypeMayBeDeleted(true),
      70         5032 :     myHaveActiveFlows(true),
      71         5032 :     myRoutesOutput(nullptr), myRouteAlternativesOutput(nullptr), myTypesOutput(nullptr),
      72         5032 :     myReadRouteNo(0), myDiscardedRouteNo(0), myWrittenRouteNo(0),
      73         5032 :     myHavePermissions(false),
      74         5032 :     myHaveParamRestrictions(false),
      75         5032 :     myNumInternalEdges(0),
      76         5032 :     myErrorHandler(OptionsCont::getOptions().exists("ignore-errors")
      77         9617 :                    && OptionsCont::getOptions().getBool("ignore-errors") ? MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance()),
      78         5032 :     myKeepVTypeDist(OptionsCont::getOptions().exists("keep-vtype-distributions")
      79         9617 :                     && OptionsCont::getOptions().getBool("keep-vtype-distributions")),
      80         5032 :     myDoPTRouting(!OptionsCont::getOptions().exists("ptline-routing")
      81         9147 :                   || OptionsCont::getOptions().getBool("ptline-routing")),
      82         5032 :     myKeepFlows(OptionsCont::getOptions().exists("keep-flows")
      83         9147 :                 && OptionsCont::getOptions().getBool("keep-flows")),
      84         5032 :     myHasBidiEdges(false),
      85        18294 :     myMaxTraveltime(OptionsCont::getOptions().exists("max-traveltime") ? STEPS2TIME(string2time(OptionsCont::getOptions().getString("max-traveltime"))) : -1) {
      86         5032 :     if (myInstance != nullptr) {
      87            0 :         throw ProcessError(TL("A network was already constructed."));
      88              :     }
      89         5032 :     SUMOVTypeParameter* type = new SUMOVTypeParameter(DEFAULT_VTYPE_ID, SVC_PASSENGER);
      90         5032 :     type->onlyReferenced = true;
      91         5032 :     myVehicleTypes.add(type->id, type);
      92              : 
      93         5032 :     SUMOVTypeParameter* defPedType = new SUMOVTypeParameter(DEFAULT_PEDTYPE_ID, SVC_PEDESTRIAN);
      94         5032 :     defPedType->onlyReferenced = true;
      95         5032 :     defPedType->parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
      96         5032 :     myVehicleTypes.add(defPedType->id, defPedType);
      97              : 
      98         5032 :     SUMOVTypeParameter* defBikeType = new SUMOVTypeParameter(DEFAULT_BIKETYPE_ID, SVC_BICYCLE);
      99         5032 :     defBikeType->onlyReferenced = true;
     100         5032 :     defBikeType->parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
     101         5032 :     myVehicleTypes.add(defBikeType->id, defBikeType);
     102              : 
     103         5032 :     SUMOVTypeParameter* defTaxiType = new SUMOVTypeParameter(DEFAULT_TAXITYPE_ID, SVC_TAXI);
     104         5032 :     defTaxiType->onlyReferenced = true;
     105         5032 :     defTaxiType->parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
     106         5032 :     myVehicleTypes.add(defTaxiType->id, defTaxiType);
     107              : 
     108         5032 :     SUMOVTypeParameter* defRailType = new SUMOVTypeParameter(DEFAULT_RAILTYPE_ID, SVC_RAIL);
     109         5032 :     defRailType->onlyReferenced = true;
     110         5032 :     defRailType->parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
     111         5032 :     myVehicleTypes.add(defRailType->id, defRailType);
     112              : 
     113         5032 :     myInstance = this;
     114         5032 : }
     115              : 
     116              : 
     117         9607 : RONet::~RONet() {
     118         5280 :     for (const auto& routables : myRoutables) {
     119          516 :         for (RORoutable* const r : routables.second) {
     120          258 :             const ROVehicle* const veh = dynamic_cast<const ROVehicle*>(r);
     121              :             // delete routes and the vehicle
     122          258 :             if (veh != nullptr && veh->getRouteDefinition()->getID()[0] == '!') {
     123          248 :                 if (!myRoutes.remove(veh->getRouteDefinition()->getID())) {
     124           95 :                     delete veh->getRouteDefinition();
     125              :                 }
     126              :             }
     127          258 :             delete r;
     128              :         }
     129              :     }
     130         5067 :     for (const RORoutable* const r : myPTVehicles) {
     131           45 :         const ROVehicle* const veh = dynamic_cast<const ROVehicle*>(r);
     132              :         // delete routes and the vehicle
     133           45 :         if (veh != nullptr && veh->getRouteDefinition()->getID()[0] == '!') {
     134           45 :             if (!myRoutes.remove(veh->getRouteDefinition()->getID())) {
     135           10 :                 delete veh->getRouteDefinition();
     136              :             }
     137              :         }
     138           45 :         delete r;
     139              :     }
     140              :     myRoutables.clear();
     141         5127 :     for (const auto& vTypeDist : myVTypeDistDict) {
     142          210 :         delete vTypeDist.second;
     143              :     }
     144        34717 : }
     145              : 
     146              : 
     147              : void
     148           21 : RONet::addSpeedRestriction(const std::string& id, const SUMOVehicleClass svc, const double speed) {
     149           21 :     mySpeedRestrictions[id][svc] = speed;
     150           21 : }
     151              : 
     152              : 
     153              : double
     154         1680 : RONet::getPreference(const std::string& routingType, const SUMOVTypeParameter& pars) const {
     155         1680 :     if (gRoutingPreferences) {
     156         1680 :         auto it = myVTypePreferences.find(pars.id);
     157         1680 :         if (it != myVTypePreferences.end()) {
     158              :             auto it2 = it->second.find(routingType);
     159          114 :             if (it2 != it->second.end()) {
     160           30 :                 return it2->second;
     161              :             }
     162              :         }
     163              :         auto it3 = myVClassPreferences.find(pars.vehicleClass);
     164         1650 :         if (it3 != myVClassPreferences.end()) {
     165              :             auto it4 = it3->second.find(routingType);
     166          228 :             if (it4 != it3->second.end()) {
     167           60 :                 return it4->second;
     168              :             }
     169              :         }
     170              :         // fallback to generel preferences
     171         1590 :         it = myVTypePreferences.find("");
     172         1590 :         if (it != myVTypePreferences.end()) {
     173              :             auto it2 = it->second.find(routingType);
     174         1011 :             if (it2 != it->second.end()) {
     175          180 :                 return it2->second;
     176              :             }
     177              :         }
     178              :     }
     179              :     return 1;
     180              : }
     181              : 
     182              : 
     183              : void
     184           30 : RONet::addPreference(const std::string& routingType, SUMOVehicleClass svc, double prio) {
     185           30 :     myVClassPreferences[svc][routingType] = prio;
     186           30 :     gRoutingPreferences = true;
     187           30 : }
     188              : 
     189              : 
     190              : void
     191           40 : RONet::addPreference(const std::string& routingType, std::string vType, double prio) {
     192           40 :     myVTypePreferences[vType][routingType] = prio;
     193           40 :     gRoutingPreferences = true;
     194           40 : }
     195              : 
     196              : 
     197              : 
     198              : const std::map<SUMOVehicleClass, double>*
     199           80 : RONet::getRestrictions(const std::string& id) const {
     200              :     std::map<std::string, std::map<SUMOVehicleClass, double> >::const_iterator i = mySpeedRestrictions.find(id);
     201           80 :     if (i == mySpeedRestrictions.end()) {
     202              :         return nullptr;
     203              :     }
     204           30 :     return &i->second;
     205              : }
     206              : 
     207              : 
     208              : bool
     209       349987 : RONet::addEdge(ROEdge* edge) {
     210       349987 :     if (!myEdges.add(edge->getID(), edge)) {
     211           36 :         WRITE_ERRORF(TL("The edge '%' occurs at least twice."), edge->getID());
     212           12 :         delete edge;
     213           12 :         return false;
     214              :     }
     215       349975 :     if (edge->isInternal()) {
     216       170699 :         myNumInternalEdges += 1;
     217              :     }
     218              :     return true;
     219              : }
     220              : 
     221              : 
     222              : bool
     223         2184 : RONet::addDistrict(const std::string id, ROEdge* source, ROEdge* sink) {
     224              :     if (myDistricts.count(id) > 0) {
     225            0 :         WRITE_ERRORF(TL("The TAZ '%' occurs at least twice."), id);
     226            0 :         delete source;
     227            0 :         delete sink;
     228            0 :         return false;
     229              :     }
     230              :     sink->setFunction(SumoXMLEdgeFunc::CONNECTOR);
     231         2184 :     if (!addEdge(sink)) {
     232              :         return false;
     233              :     }
     234              :     source->setFunction(SumoXMLEdgeFunc::CONNECTOR);
     235         2184 :     if (!addEdge(source)) {
     236              :         return false;
     237              :     }
     238              :     sink->setOtherTazConnector(source);
     239              :     source->setOtherTazConnector(sink);
     240         4368 :     myDistricts[id] = std::make_pair(std::vector<std::string>(), std::vector<std::string>());
     241         2184 :     return true;
     242              : }
     243              : 
     244              : 
     245              : bool
     246         1510 : RONet::addDistrictEdge(const std::string tazID, const std::string edgeID, const bool isSource) {
     247              :     if (myDistricts.count(tazID) == 0) {
     248            0 :         WRITE_ERRORF(TL("The TAZ '%' is unknown."), tazID);
     249            0 :         return false;
     250              :     }
     251              :     ROEdge* edge = getEdge(edgeID);
     252         1510 :     if (edge == nullptr) {
     253            0 :         WRITE_ERRORF(TL("The edge '%' for TAZ '%' is unknown."), edgeID, tazID);
     254            0 :         return false;
     255              :     }
     256         1510 :     if (isSource) {
     257         2265 :         getEdge(tazID + "-source")->addSuccessor(edge);
     258          755 :         myDistricts[tazID].first.push_back(edgeID);
     259              :     } else {
     260         2265 :         edge->addSuccessor(getEdge(tazID + "-sink"));
     261          755 :         myDistricts[tazID].second.push_back(edgeID);
     262              :     }
     263              :     return true;
     264              : }
     265              : 
     266              : 
     267              : void
     268          121 : RONet::addJunctionTaz(ROAbstractEdgeBuilder& eb) {
     269         1888 :     for (auto item : myNodes) {
     270              :         const std::string tazID = item.first;
     271           10 :         if (myDistricts.count(tazID) != 0) {
     272           30 :             WRITE_WARNINGF(TL("A TAZ with id '%' already exists. Not building junction TAZ."), tazID);
     273           10 :             continue;
     274              :         }
     275         1757 :         const std::string sourceID = tazID + "-source";
     276         1757 :         const std::string sinkID = tazID + "-sink";
     277              :         // sink must be added before source
     278         3514 :         ROEdge* sink = eb.buildEdge(sinkID, nullptr, nullptr, 0, "", "");
     279         3514 :         ROEdge* source = eb.buildEdge(sourceID, nullptr, nullptr, 0, "", "");
     280              :         sink->setOtherTazConnector(source);
     281              :         source->setOtherTazConnector(sink);
     282         3514 :         if (!addDistrict(tazID, source, sink)) {
     283              :             continue;
     284              :         }
     285         1757 :         auto& district = myDistricts[tazID];
     286         1757 :         const RONode* junction = item.second;
     287        15478 :         for (const ROEdge* edge : junction->getIncoming()) {
     288        13721 :             if (!edge->isInternal()) {
     289         3864 :                 const_cast<ROEdge*>(edge)->addSuccessor(sink);
     290         3864 :                 district.second.push_back(edge->getID());
     291              :             }
     292              :         }
     293        15478 :         for (const ROEdge* edge : junction->getOutgoing()) {
     294        13721 :             if (!edge->isInternal()) {
     295         3864 :                 source->addSuccessor(const_cast<ROEdge*>(edge));
     296         3864 :                 district.first.push_back(edge->getID());
     297              :             }
     298              :         }
     299              :     }
     300          121 : }
     301              : 
     302              : 
     303              : void
     304         4298 : RONet::setBidiEdges(const std::map<ROEdge*, std::string>& bidiMap) {
     305        17256 :     for (const auto& item : bidiMap) {
     306        12958 :         ROEdge* bidi = myEdges.get(item.second);
     307        12958 :         if (bidi == nullptr) {
     308            0 :             WRITE_ERRORF(TL("The bidi edge '%' is not known."), item.second);
     309              :         }
     310        12958 :         item.first->setBidiEdge(bidi);
     311        12958 :         myHasBidiEdges = true;
     312              :     }
     313         4298 : }
     314              : 
     315              : 
     316              : void
     317        81043 : RONet::addNode(RONode* node) {
     318        81043 :     if (!myNodes.add(node->getID(), node)) {
     319            0 :         WRITE_ERRORF(TL("The node '%' occurs at least twice."), node->getID());
     320            0 :         delete node;
     321              :     }
     322        81043 : }
     323              : 
     324              : 
     325              : void
     326         2335 : RONet::addStoppingPlace(const std::string& id, const SumoXMLTag category, SUMOVehicleParameter::Stop* stop) {
     327         4260 :     if (!myStoppingPlaces[category == SUMO_TAG_TRAIN_STOP ? SUMO_TAG_BUS_STOP : category].add(id, stop)) {
     328           15 :         WRITE_ERRORF(TL("The % '%' occurs at least twice."), toString(category), id);
     329            5 :         delete stop;
     330              :     }
     331         2335 : }
     332              : 
     333              : 
     334              : bool
     335       285042 : RONet::addRouteDef(RORouteDef* def) {
     336       285042 :     return myRoutes.add(def->getID(), def);
     337              : }
     338              : 
     339              : 
     340              : void
     341         3484 : RONet::openOutput(const OptionsCont& options) {
     342        10450 :     if (options.isSet("output-file") && options.getString("output-file") != "") {
     343         3483 :         myRoutesOutput = &OutputDevice::getDevice(options.getString("output-file"));
     344         3476 :         if (myRoutesOutput->isNull()) {
     345            1 :             myRoutesOutput = nullptr;
     346              :         } else {
     347         6950 :             myRoutesOutput->writeXMLHeader("routes", "routes_file.xsd");
     348              :         }
     349              :     }
     350        10241 :     if (options.exists("alternatives-output") && options.isSet("alternatives-output")
     351        16408 :             && !(options.exists("write-trips") && options.getBool("write-trips"))) {
     352         3072 :         myRouteAlternativesOutput = &OutputDevice::getDevice(options.getString("alternatives-output"));
     353         3072 :         if (myRouteAlternativesOutput->isNull()) {
     354          180 :             myRouteAlternativesOutput = nullptr;
     355              :         } else {
     356         5784 :             myRouteAlternativesOutput->writeXMLHeader("routes", "routes_file.xsd");
     357              :         }
     358              :     }
     359         6954 :     if (options.isSet("vtype-output")) {
     360           34 :         myTypesOutput = &OutputDevice::getDevice(options.getString("vtype-output"));
     361           68 :         myTypesOutput->writeXMLHeader("routes", "routes_file.xsd");
     362              :     }
     363         3477 : }
     364              : 
     365              : 
     366              : void
     367         3247 : RONet::writeIntermodal(const OptionsCont& options, ROIntermodalRouter& router) const {
     368         6494 :     if (options.exists("intermodal-network-output") && options.isSet("intermodal-network-output")) {
     369           40 :         OutputDevice::createDeviceByOption("intermodal-network-output", "intermodal");
     370           40 :         router.writeNetwork(OutputDevice::getDevice(options.getString("intermodal-network-output")));
     371              :     }
     372         6494 :     if (options.exists("intermodal-weight-output") && options.isSet("intermodal-weight-output")) {
     373           20 :         OutputDevice::createDeviceByOption("intermodal-weight-output", "weights", "meandata_file.xsd");
     374           10 :         OutputDevice& dev = OutputDevice::getDeviceByOption("intermodal-weight-output");
     375           10 :         dev.openTag(SUMO_TAG_INTERVAL);
     376           10 :         dev.writeAttr(SUMO_ATTR_ID, "intermodalweights");
     377           10 :         dev.writeAttr(SUMO_ATTR_BEGIN, 0);
     378           10 :         dev.writeAttr(SUMO_ATTR_END, SUMOTime_MAX);
     379           10 :         router.writeWeights(dev);
     380           20 :         dev.closeTag();
     381              :     }
     382         3247 : }
     383              : 
     384              : 
     385              : void
     386         3483 : RONet::cleanup() {
     387              :     // end writing
     388         3483 :     if (myRoutesOutput != nullptr) {
     389         3475 :         myRoutesOutput->close();
     390              :     }
     391              :     // only if opened
     392         3483 :     if (myRouteAlternativesOutput != nullptr) {
     393         2892 :         myRouteAlternativesOutput->close();
     394              :     }
     395              :     // only if opened
     396         3483 :     if (myTypesOutput != nullptr) {
     397           34 :         myTypesOutput->close();
     398              :     }
     399              :     RouteCostCalculator<RORoute, ROEdge, ROVehicle>::cleanup();
     400              : #ifdef HAVE_FOX
     401         3483 :     if (myThreadPool.size() > 0) {
     402          242 :         myThreadPool.clear();
     403              :     }
     404              : #endif
     405         3483 : }
     406              : 
     407              : 
     408              : 
     409              : SUMOVTypeParameter*
     410       506403 : RONet::getVehicleTypeSecure(const std::string& id) {
     411              :     // check whether the type was already known
     412              :     SUMOVTypeParameter* type = myVehicleTypes.get(id);
     413       506403 :     if (id == DEFAULT_VTYPE_ID) {
     414       461359 :         myDefaultVTypeMayBeDeleted = false;
     415        45044 :     } else if (id == DEFAULT_PEDTYPE_ID) {
     416         6293 :         myDefaultPedTypeMayBeDeleted = false;
     417        38751 :     } else if (id == DEFAULT_BIKETYPE_ID) {
     418           69 :         myDefaultBikeTypeMayBeDeleted = false;
     419        38682 :     } else if (id == DEFAULT_TAXITYPE_ID) {
     420          105 :         myDefaultTaxiTypeMayBeDeleted = false;
     421        38577 :     } else if (id == DEFAULT_RAILTYPE_ID) {
     422            0 :         myDefaultRailTypeMayBeDeleted = false;
     423              :     }
     424       506403 :     if (type != nullptr) {
     425              :         return type;
     426              :     }
     427              :     VTypeDistDictType::iterator it2 = myVTypeDistDict.find(id);
     428         3074 :     if (it2 != myVTypeDistDict.end()) {
     429         2665 :         return it2->second->get();
     430              :     }
     431          409 :     if (id == "") {
     432              :         // ok, no vehicle type or an unknown type was given within the user input
     433              :         //  return the default type
     434            0 :         myDefaultVTypeMayBeDeleted = false;
     435              :         return myVehicleTypes.get(DEFAULT_VTYPE_ID);
     436              :     }
     437              :     return type;
     438              : }
     439              : 
     440              : 
     441              : bool
     442         2701 : RONet::checkVType(const std::string& id) {
     443         2701 :     if (id == DEFAULT_VTYPE_ID) {
     444           81 :         if (myDefaultVTypeMayBeDeleted) {
     445           81 :             myVehicleTypes.remove(id);
     446           81 :             myDefaultVTypeMayBeDeleted = false;
     447              :         } else {
     448              :             return false;
     449              :         }
     450         2620 :     } else if (id == DEFAULT_PEDTYPE_ID) {
     451            0 :         if (myDefaultPedTypeMayBeDeleted) {
     452            0 :             myVehicleTypes.remove(id);
     453            0 :             myDefaultPedTypeMayBeDeleted = false;
     454              :         } else {
     455              :             return false;
     456              :         }
     457         2620 :     } else if (id == DEFAULT_BIKETYPE_ID) {
     458            0 :         if (myDefaultBikeTypeMayBeDeleted) {
     459            0 :             myVehicleTypes.remove(id);
     460            0 :             myDefaultBikeTypeMayBeDeleted = false;
     461              :         } else {
     462              :             return false;
     463              :         }
     464         2620 :     } else if (id == DEFAULT_TAXITYPE_ID) {
     465            0 :         if (myDefaultTaxiTypeMayBeDeleted) {
     466            0 :             myVehicleTypes.remove(id);
     467            0 :             myDefaultTaxiTypeMayBeDeleted = false;
     468              :         } else {
     469              :             return false;
     470              :         }
     471         2620 :     } else if (id == DEFAULT_RAILTYPE_ID) {
     472            0 :         if (myDefaultRailTypeMayBeDeleted) {
     473            0 :             myVehicleTypes.remove(id);
     474            0 :             myDefaultRailTypeMayBeDeleted = false;
     475              :         } else {
     476              :             return false;
     477              :         }
     478              :     } else {
     479         2620 :         if (myVehicleTypes.get(id) != 0 || myVTypeDistDict.find(id) != myVTypeDistDict.end()) {
     480            0 :             return false;
     481              :         }
     482              :     }
     483              :     return true;
     484              : }
     485              : 
     486              : 
     487              : bool
     488         2596 : RONet::addVehicleType(SUMOVTypeParameter* type) {
     489         2596 :     if (checkVType(type->id)) {
     490         2596 :         myVehicleTypes.add(type->id, type);
     491              :     } else {
     492            0 :         WRITE_ERRORF(TL("The vehicle type '%' occurs at least twice."), type->id);
     493            0 :         delete type;
     494            0 :         return false;
     495              :     }
     496         2596 :     return true;
     497              : }
     498              : 
     499              : 
     500              : bool
     501          105 : RONet::addVTypeDistribution(const std::string& id, RandomDistributor<SUMOVTypeParameter*>* vehTypeDistribution) {
     502          105 :     if (checkVType(id)) {
     503          105 :         myVTypeDistDict[id] = vehTypeDistribution;
     504          105 :         return true;
     505              :     }
     506            0 :     delete vehTypeDistribution;
     507              :     return false;
     508              : }
     509              : 
     510              : 
     511              : bool
     512       303139 : RONet::addVehicle(const std::string& id, ROVehicle* veh) {
     513       303139 :     if (myVehIDs.find(id) == myVehIDs.end()) {
     514       606230 :         myVehIDs[id] = veh->getParameter().departProcedure == DepartDefinition::TRIGGERED ? -1 : veh->getDepartureTime();
     515              : 
     516       303134 :         if (veh->isPublicTransport()) {
     517           55 :             if (!veh->isPartOfFlow()) {
     518           45 :                 myPTVehicles.push_back(veh);
     519              :             }
     520           55 :             if (!myDoPTRouting) {
     521              :                 return true;
     522              :             }
     523              :         }
     524       303089 :         myRoutables[veh->getDepart()].push_back(veh);
     525       303089 :         return true;
     526              :     }
     527           15 :     WRITE_ERRORF(TL("Another vehicle with the id '%' exists."), id);
     528            5 :     delete veh;
     529              :     return false;
     530              : }
     531              : 
     532              : 
     533              : bool
     534          318 : RONet::knowsVehicle(const std::string& id) const {
     535          318 :     return myVehIDs.find(id) != myVehIDs.end();
     536              : }
     537              : 
     538              : 
     539              : bool
     540           20 : RONet::knowsVType(const std::string& id) const {
     541           20 :     return myVehicleTypes.get(id) != nullptr || myVTypeDistDict.find(id) != myVTypeDistDict.end();
     542              : }
     543              : 
     544              : 
     545              : SUMOTime
     546           35 : RONet::getDeparture(const std::string& vehID) const {
     547              :     auto it = myVehIDs.find(vehID);
     548           35 :     if (it != myVehIDs.end()) {
     549           35 :         return it->second;
     550              :     } else {
     551            0 :         throw ProcessError(TLF("Requesting departure time for unknown vehicle '%'", vehID));
     552              :     }
     553              : }
     554              : 
     555              : 
     556              : bool
     557         2797 : RONet::addFlow(SUMOVehicleParameter* flow, const bool randomize) {
     558         2797 :     if (randomize && flow->repetitionOffset >= 0) {
     559           12 :         myDepartures[flow->id].reserve(flow->repetitionNumber);
     560          132 :         for (int i = 0; i < flow->repetitionNumber; ++i) {
     561          120 :             myDepartures[flow->id].push_back(flow->depart + RandHelper::rand(flow->repetitionNumber * flow->repetitionOffset));
     562              :         }
     563           12 :         std::sort(myDepartures[flow->id].begin(), myDepartures[flow->id].end());
     564           12 :         std::reverse(myDepartures[flow->id].begin(), myDepartures[flow->id].end());
     565         2785 :     } else if (flow->repetitionOffset < 0) {
     566              :         // init poisson flow (but only the timing)
     567          354 :         flow->incrementFlow(1);
     568          354 :         flow->repetitionsDone--;
     569              :     }
     570         2797 :     const bool added = myFlows.add(flow->id, flow);
     571         2797 :     if (added) {
     572         2792 :         myHaveActiveFlows = true;
     573              :     }
     574         2797 :     return added;
     575              : }
     576              : 
     577              : 
     578              : bool
     579         3862 : RONet::addPerson(ROPerson* person) {
     580              :     if (myPersonIDs.count(person->getID()) == 0) {
     581              :         myPersonIDs.insert(person->getID());
     582         3862 :         myRoutables[person->getDepart()].push_back(person);
     583         3862 :         return true;
     584              :     }
     585            0 :     WRITE_ERRORF(TL("Another person with the id '%' exists."), person->getID());
     586            0 :     return false;
     587              : }
     588              : 
     589              : 
     590              : void
     591           70 : RONet::addContainer(const SUMOTime depart, const std::string desc) {
     592           70 :     myContainers.insert(std::pair<const SUMOTime, const std::string>(depart, desc));
     593           70 : }
     594              : 
     595              : 
     596              : void
     597        16514 : RONet::checkFlows(SUMOTime time, MsgHandler* errorHandler) {
     598        16514 :     myHaveActiveFlows = false;
     599        63353 :     for (const auto& i : myFlows) {
     600        46839 :         SUMOVehicleParameter* const pars = i.second;
     601        46839 :         if (pars->line != "" && !myDoPTRouting) {
     602          842 :             continue;
     603              :         }
     604        45997 :         if (myKeepFlows) {
     605          798 :             if (pars->repetitionsDone < pars->repetitionNumber) {
     606              :                 // each each flow only once
     607          792 :                 pars->repetitionsDone = pars->repetitionNumber;
     608          792 :                 const SUMOVTypeParameter* type = getVehicleTypeSecure(pars->vtypeid);
     609          792 :                 if (type == nullptr) {
     610            0 :                     type = getVehicleTypeSecure(DEFAULT_VTYPE_ID);
     611              :                 } else {
     612              :                     auto dist = getVTypeDistribution(pars->vtypeid);
     613            0 :                     if (dist != nullptr) {
     614            0 :                         WRITE_WARNINGF("Keeping flow '%' with a vTypeDistribution can lead to invalid routes if the distribution contains different vClasses", pars->id);
     615              :                     }
     616              :                 }
     617         1584 :                 RORouteDef* route = getRouteDef(pars->routeid)->copy(pars->routeid, pars->depart);
     618          792 :                 ROVehicle* veh = new ROVehicle(*pars, route, type, this, errorHandler);
     619          792 :                 addVehicle(pars->id, veh);
     620              :             }
     621        45199 :         } else if (pars->repetitionProbability > 0) {
     622          135 :             if (pars->repetitionEnd > pars->depart && pars->repetitionsDone < pars->repetitionNumber) {
     623          120 :                 myHaveActiveFlows = true;
     624              :             }
     625              :             const SUMOTime origDepart = pars->depart;
     626         1275 :             while (pars->depart < time && pars->repetitionsDone < pars->repetitionNumber) {
     627         1160 :                 if (pars->repetitionEnd <= pars->depart) {
     628              :                     break;
     629              :                 }
     630              :                 // only call rand if all other conditions are met
     631         1140 :                 if (RandHelper::rand() < (pars->repetitionProbability * TS)) {
     632          210 :                     SUMOVehicleParameter* newPars = new SUMOVehicleParameter(*pars);
     633          420 :                     newPars->id = pars->id + "." + toString(pars->repetitionsDone);
     634          210 :                     newPars->depart = pars->depart;
     635          210 :                     for (StopParVector::iterator stop = newPars->stops.begin(); stop != newPars->stops.end(); ++stop) {
     636            0 :                         if (stop->until >= 0) {
     637            0 :                             stop->until += pars->depart - origDepart;
     638              :                         }
     639              :                     }
     640          210 :                     pars->repetitionsDone++;
     641              :                     // try to build the vehicle
     642          210 :                     const SUMOVTypeParameter* type = getVehicleTypeSecure(pars->vtypeid);
     643          210 :                     if (type == nullptr) {
     644           40 :                         type = getVehicleTypeSecure(DEFAULT_VTYPE_ID);
     645          170 :                     } else if (!myKeepVTypeDist) {
     646              :                         // fix the type id in case we used a distribution
     647          170 :                         newPars->vtypeid = type->id;
     648              :                     }
     649          210 :                     const SUMOTime stopOffset = pars->routeid[0] == '!' ? pars->depart - origDepart : pars->depart;
     650          420 :                     RORouteDef* route = getRouteDef(pars->routeid)->copy("!" + newPars->id, stopOffset);
     651          210 :                     ROVehicle* veh = new ROVehicle(*newPars, route, type, this, errorHandler);
     652          210 :                     addVehicle(newPars->id, veh);
     653          210 :                     delete newPars;
     654              :                 }
     655         1140 :                 pars->depart += DELTA_T;
     656              :             }
     657              :         } else {
     658        45064 :             SUMOTime depart = static_cast<SUMOTime>(pars->depart + pars->repetitionTotalOffset);
     659        65206 :             while (pars->repetitionsDone < pars->repetitionNumber && pars->repetitionEnd >= depart) {
     660        33456 :                 myHaveActiveFlows = true;
     661        33456 :                 depart = static_cast<SUMOTime>(pars->depart + pars->repetitionTotalOffset);
     662        33456 :                 if (myDepartures.find(pars->id) != myDepartures.end()) {
     663          132 :                     depart = myDepartures[pars->id].back();
     664              :                 }
     665        33456 :                 if (depart >= time + DELTA_T) {
     666              :                     break;
     667              :                 }
     668        20142 :                 if (myDepartures.find(pars->id) != myDepartures.end()) {
     669          120 :                     myDepartures[pars->id].pop_back();
     670              :                 }
     671        20142 :                 SUMOVehicleParameter* newPars = new SUMOVehicleParameter(*pars);
     672        40284 :                 newPars->id = pars->id + "." + toString(pars->repetitionsDone);
     673        20142 :                 newPars->depart = depart;
     674        20342 :                 for (StopParVector::iterator stop = newPars->stops.begin(); stop != newPars->stops.end(); ++stop) {
     675          200 :                     if (stop->until >= 0) {
     676           50 :                         stop->until += depart - pars->depart;
     677              :                     }
     678          200 :                     if (stop->arrival >= 0) {
     679           50 :                         stop->arrival += depart - pars->depart;
     680              :                     }
     681              :                 }
     682        20142 :                 pars->incrementFlow(1);
     683              :                 // try to build the vehicle
     684        20142 :                 const SUMOVTypeParameter* type = getVehicleTypeSecure(pars->vtypeid);
     685        20142 :                 if (type == nullptr) {
     686           75 :                     type = getVehicleTypeSecure(DEFAULT_VTYPE_ID);
     687        20067 :                 } else if (!myKeepVTypeDist) {
     688              :                     // fix the type id in case we used a distribution
     689        20017 :                     newPars->vtypeid = type->id;
     690              :                 }
     691        20142 :                 const SUMOTime stopOffset = pars->routeid[0] == '!' ? depart - pars->depart : depart;
     692        40284 :                 RORouteDef* route = getRouteDef(pars->routeid)->copy("!" + newPars->id, stopOffset);
     693        20142 :                 ROVehicle* veh = new ROVehicle(*newPars, route, type, this, errorHandler);
     694        20142 :                 addVehicle(newPars->id, veh);
     695        20142 :                 delete newPars;
     696              :             }
     697              :         }
     698              :     }
     699        16514 : }
     700              : 
     701              : 
     702              : void
     703           86 : RONet::createBulkRouteRequests(const RORouterProvider& provider, const SUMOTime time, const bool removeLoops) {
     704              :     std::map<const int, std::vector<RORoutable*> > bulkVehs;
     705              :     int numBulked = 0;
     706          129 :     for (RoutablesMap::const_iterator i = myRoutables.begin(); i != myRoutables.end(); ++i) {
     707           86 :         if (i->first >= time) {
     708              :             break;
     709              :         }
     710          785 :         for (RORoutable* const routable : i->second) {
     711          742 :             const ROEdge* const depEdge = routable->getDepartEdge();
     712          742 :             bulkVehs[depEdge->getNumericalID()].push_back(routable);
     713          742 :             RORoutable* const first = bulkVehs[depEdge->getNumericalID()].front();
     714          742 :             numBulked++;
     715          742 :             if (first->getMaxSpeed() != routable->getMaxSpeed()) {
     716            9 :                 WRITE_WARNINGF(TL("Bulking different maximum speeds ('%' and '%') may lead to suboptimal routes."), first->getID(), routable->getID());
     717              :             }
     718          742 :             if (first->getVClass() != routable->getVClass()) {
     719            9 :                 WRITE_WARNINGF(TL("Bulking different vehicle classes ('%' and '%') may lead to invalid routes."), first->getID(), routable->getID());
     720              :             }
     721              :         }
     722              :     }
     723              : #ifdef HAVE_FOX
     724              :     int workerIndex = 0;
     725              : #endif
     726           86 :     if ((int)bulkVehs.size() < numBulked) {
     727           84 :         WRITE_MESSAGE(TLF("Using bulk-mode for % entities from % origins", numBulked, bulkVehs.size()));
     728              :     }
     729          257 :     for (std::map<const int, std::vector<RORoutable*> >::const_iterator i = bulkVehs.begin(); i != bulkVehs.end(); ++i) {
     730              : #ifdef HAVE_FOX
     731          171 :         if (myThreadPool.size() > 0) {
     732              :             bool bulk = true;
     733          198 :             for (RORoutable* const r : i->second) {
     734          180 :                 myThreadPool.add(new RoutingTask(r, removeLoops, myErrorHandler), workerIndex);
     735          180 :                 if (bulk) {
     736           18 :                     myThreadPool.add(new BulkmodeTask(true), workerIndex);
     737              :                     bulk = false;
     738              :                 }
     739              :             }
     740           18 :             myThreadPool.add(new BulkmodeTask(false), workerIndex);
     741           18 :             workerIndex++;
     742           18 :             if (workerIndex == (int)myThreadPool.size()) {
     743              :                 workerIndex = 0;
     744              :             }
     745           18 :             continue;
     746           18 :         }
     747              : #endif
     748          715 :         for (RORoutable* const r : i->second) {
     749          562 :             r->computeRoute(provider, removeLoops, myErrorHandler);
     750          562 :             provider.setBulkMode(true);
     751              :         }
     752          153 :         provider.setBulkMode(false);
     753              :     }
     754           86 : }
     755              : 
     756              : 
     757              : SUMOTime
     758        23641 : RONet::saveAndRemoveRoutesUntil(OptionsCont& options, const RORouterProvider& provider,
     759              :                                 SUMOTime time) {
     760        23641 :     MsgHandler* mh = (options.getBool("ignore-errors") ?
     761        23641 :                       MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance());
     762        23641 :     if (myHaveActiveFlows) {
     763        16514 :         checkFlows(time, mh);
     764              :     }
     765              :     SUMOTime lastTime = -1;
     766        23641 :     const bool removeLoops = options.getBool("remove-loops");
     767              : #ifdef HAVE_FOX
     768        47282 :     const int maxNumThreads = options.getInt("routing-threads");
     769              : #endif
     770        23641 :     if (myRoutables.size() != 0) {
     771        22212 :         if (options.getBool("bulk-routing")) {
     772              : #ifdef HAVE_FOX
     773           98 :             while ((int)myThreadPool.size() < maxNumThreads) {
     774           12 :                 new WorkerThread(myThreadPool, provider);
     775              :             }
     776              : #endif
     777           86 :             createBulkRouteRequests(provider, time, removeLoops);
     778              :         } else {
     779       257622 :             for (RoutablesMap::const_iterator i = myRoutables.begin(); i != myRoutables.end(); ++i) {
     780       254248 :                 if (i->first >= time) {
     781              :                     break;
     782              :                 }
     783       552573 :                 for (RORoutable* const routable : i->second) {
     784              : #ifdef HAVE_FOX
     785              :                     // add task
     786       305971 :                     if (maxNumThreads > 0) {
     787              :                         const int numThreads = (int)myThreadPool.size();
     788       179945 :                         if (numThreads == 0) {
     789              :                             // This is the very first routing. Since at least the CHRouter needs initialization
     790              :                             // before it gets cloned, we do not do this in parallel
     791          231 :                             routable->computeRoute(provider, removeLoops, myErrorHandler);
     792          231 :                             new WorkerThread(myThreadPool, provider);
     793              :                         } else {
     794              :                             // add thread if necessary
     795       179714 :                             if (numThreads < maxNumThreads && myThreadPool.isFull()) {
     796         1202 :                                 new WorkerThread(myThreadPool, provider);
     797              :                             }
     798       179714 :                             myThreadPool.add(new RoutingTask(routable, removeLoops, myErrorHandler));
     799              :                         }
     800       179945 :                         continue;
     801       179945 :                     }
     802              : #endif
     803       126026 :                     routable->computeRoute(provider, removeLoops, myErrorHandler);
     804              :                 }
     805              :             }
     806              :         }
     807              : #ifdef HAVE_FOX
     808        11086 :         myThreadPool.waitAll();
     809              : #endif
     810              :     }
     811        46970 :     const double scale = options.exists("scale-suffix") ? options.getFloat("scale") : 1;
     812              :     // write all vehicles (and additional structures)
     813       270326 :     while (myRoutables.size() != 0 || myContainers.size() != 0) {
     814              :         // get the next vehicle, person or container
     815              :         RoutablesMap::iterator routables = myRoutables.begin();
     816       254384 :         const SUMOTime routableTime = routables == myRoutables.end() ? SUMOTime_MAX : routables->first;
     817              :         ContainerMap::iterator container = myContainers.begin();
     818       254384 :         const SUMOTime containerTime = container == myContainers.end() ? SUMOTime_MAX : container->first;
     819              :         // check whether it shall not yet be computed
     820       254384 :         if (routableTime >= time && containerTime >= time) {
     821              :             lastTime = MIN2(routableTime, containerTime);
     822              :             break;
     823              :         }
     824              :         const SUMOTime minTime = MIN2(routableTime, containerTime);
     825       246705 :         if (routableTime == minTime) {
     826              :             // check whether to print the output
     827       246645 :             if (lastTime != routableTime && lastTime != -1) {
     828              :                 // report writing progress
     829       239358 :                 if (options.getInt("stats-period") >= 0 && ((int)routableTime % options.getInt("stats-period")) == 0) {
     830            0 :                     WRITE_MESSAGE("Read: " + toString(myVehIDs.size()) + ",  Discarded: " + toString(myDiscardedRouteNo) + ",  Written: " + toString(myWrittenRouteNo));
     831              :                 }
     832              :             }
     833              :             lastTime = routableTime;
     834       553338 :             for (const RORoutable* const r : routables->second) {
     835              :                 // ok, check whether it has been routed
     836       306693 :                 if (r->getRoutingSuccess()) {
     837              :                     // write the route
     838       287251 :                     int quota = getScalingQuota(scale, myWrittenRouteNo);
     839       287251 :                     r->write(myRoutesOutput, myRouteAlternativesOutput, myTypesOutput, options, quota);
     840       287251 :                     myWrittenRouteNo++;
     841              :                 } else {
     842        19442 :                     myDiscardedRouteNo++;
     843              :                 }
     844              :                 // we need to keep individual public transport vehicles but not the flows
     845       306693 :                 if (!r->isPublicTransport() || r->isPartOfFlow()) {
     846              :                     // delete routes and the vehicle
     847       306693 :                     const ROVehicle* const veh = dynamic_cast<const ROVehicle*>(r);
     848       306693 :                     if (veh != nullptr && veh->getRouteDefinition()->getID()[0] == '!') {
     849       302841 :                         if (r->isPartOfFlow() || !myRoutes.remove(veh->getRouteDefinition()->getID())) {
     850        22642 :                             delete veh->getRouteDefinition();
     851              :                         }
     852              :                     }
     853       306693 :                     delete r;
     854              :                 }
     855              :             }
     856              :             myRoutables.erase(routables);
     857              :         }
     858       246705 :         if (containerTime == minTime) {
     859           60 :             myRoutesOutput->writePreformattedTag(container->second);
     860           60 :             if (myRouteAlternativesOutput != nullptr) {
     861              :                 myRouteAlternativesOutput->writePreformattedTag(container->second);
     862              :             }
     863              :             myContainers.erase(container);
     864              :         }
     865              :     }
     866        23621 :     return lastTime;
     867              : }
     868              : 
     869              : 
     870              : bool
     871        50897 : RONet::furtherStored() {
     872        50897 :     return myRoutables.size() > 0 || (myFlows.size() > 0 && myHaveActiveFlows) || myContainers.size() > 0;
     873              : }
     874              : 
     875              : 
     876              : int
     877          123 : RONet::getEdgeNumber() const {
     878          123 :     return myEdges.size();
     879              : }
     880              : 
     881              : 
     882              : int
     883            1 : RONet::getInternalEdgeNumber() const {
     884            1 :     return myNumInternalEdges;
     885              : }
     886              : 
     887              : 
     888              : ROEdge*
     889        10292 : RONet::getEdgeForLaneID(const std::string& laneID) const {
     890        20584 :     return getEdge(SUMOXMLDefinitions::getEdgeIDFromLane(laneID));
     891              : }
     892              : 
     893              : 
     894              : ROLane*
     895         1425 : RONet::getLane(const std::string& laneID) const {
     896         1425 :     int laneIndex = SUMOXMLDefinitions::getIndexFromLane(laneID);
     897         1425 :     return getEdgeForLaneID(laneID)->getLanes()[laneIndex];
     898              : }
     899              : 
     900              : 
     901              : void
     902          893 : RONet::adaptIntermodalRouter(ROIntermodalRouter& router) {
     903          893 :     double taxiWait = STEPS2TIME(string2time(OptionsCont::getOptions().getString("persontrip.taxi.waiting-time")));
     904         1252 :     for (const auto& stopType : myInstance->myStoppingPlaces) {
     905              :         // add access to all stopping places
     906          359 :         const SumoXMLTag element = stopType.first;
     907         2453 :         for (const auto& stop : stopType.second) {
     908         2094 :             router.getNetwork()->addAccess(stop.first, myInstance->getEdgeForLaneID(stop.second->lane),
     909         2094 :                                            stop.second->startPos, stop.second->endPos, 0., element, false, taxiWait);
     910              :             // add access to all public transport stops
     911         2094 :             if (element == SUMO_TAG_BUS_STOP) {
     912         4288 :                 for (const auto& a : stop.second->accessPos) {
     913         2219 :                     router.getNetwork()->addAccess(stop.first, myInstance->getEdgeForLaneID(std::get<0>(a)),
     914              :                                                    std::get<1>(a), std::get<1>(a), std::get<2>(a), SUMO_TAG_BUS_STOP, true, taxiWait);
     915              :                 }
     916              :             }
     917              :         }
     918              :     }
     919              :     // fill the public transport router with pre-parsed public transport lines
     920         2459 :     for (const auto& i : myInstance->myFlows) {
     921         1566 :         if (i.second->line != "") {
     922          847 :             const RORouteDef* const route = myInstance->getRouteDef(i.second->routeid);
     923              :             const StopParVector* addStops = nullptr;
     924         2541 :             if (route != nullptr && route->getFirstRoute() != nullptr) {
     925          847 :                 addStops = &route->getFirstRoute()->getStops();
     926              :             }
     927          847 :             router.getNetwork()->addSchedule(*i.second, addStops);
     928              :         }
     929              :     }
     930          938 :     for (const RORoutable* const veh : myInstance->myPTVehicles) {
     931              :         // add single vehicles with line attribute which are not part of a flow
     932              :         // no need to add route stops here, they have been added to the vehicle before
     933           45 :         router.getNetwork()->addSchedule(veh->getParameter());
     934              :     }
     935              :     // add access to transfer from walking to taxi-use
     936          893 :     if ((router.getCarWalkTransfer() & ModeChangeOptions::TAXI_PICKUP_ANYWHERE) != 0) {
     937       230143 :         for (const ROEdge* edge : ROEdge::getAllEdges()) {
     938       229265 :             if (!edge->isTazConnector() && (edge->getPermissions() & SVC_PEDESTRIAN) != 0 && (edge->getPermissions() & SVC_TAXI) != 0) {
     939        40257 :                 router.getNetwork()->addCarAccess(edge, SVC_TAXI, taxiWait);
     940              :             }
     941              :         }
     942              :     }
     943          893 : }
     944              : 
     945              : 
     946              : bool
     947      4186489 : RONet::hasPermissions() const {
     948      4186489 :     return myHavePermissions;
     949              : }
     950              : 
     951              : 
     952              : void
     953       259711 : RONet::setPermissionsFound() {
     954       259711 :     myHavePermissions = true;
     955       259711 : }
     956              : 
     957              : bool
     958           12 : RONet::hasLoadedEffort() const {
     959           38 :     for (const auto& item : myEdges) {
     960           35 :         if (item.second->hasStoredEffort()) {
     961              :             return true;
     962              :         }
     963              :     }
     964              :     return false;
     965              : }
     966              : 
     967              : const std::string
     968         1787 : RONet::getStoppingPlaceName(const std::string& id) const {
     969         2027 :     for (const auto& mapItem : myStoppingPlaces) {
     970              :         SUMOVehicleParameter::Stop* stop = mapItem.second.get(id);
     971         1787 :         if (stop != nullptr) {
     972              :             // see RONetHandler::parseStoppingPlace
     973              :             return stop->busstop;
     974              :         }
     975              :     }
     976            0 :     return "";
     977              : }
     978              : 
     979              : const std::string
     980         1647 : RONet::getStoppingPlaceElement(const std::string& id) const {
     981         1827 :     for (const auto& mapItem : myStoppingPlaces) {
     982              :         SUMOVehicleParameter::Stop* stop = mapItem.second.get(id);
     983         1647 :         if (stop != nullptr) {
     984              :             // see RONetHandler::parseStoppingPlace
     985              :             return stop->actType;
     986              :         }
     987              :     }
     988            0 :     return toString(SUMO_TAG_BUS_STOP);
     989              : }
     990              : 
     991              : 
     992              : void
     993            5 : RONet::addProhibition(const ROEdge* edge, const RouterProhibition& prohibition) {
     994              :     if (myProhibitions.count(edge) != 0) {
     995            0 :         throw ProcessError(TLF("Already loaded prohibition for edge '%'. (Only one prohibition per edge is supported)", edge->getID()));
     996              :     }
     997            5 :     myProhibitions[edge] = prohibition;
     998            5 :     myHavePermissions = true;
     999            5 : }
    1000              : 
    1001              : 
    1002              : void
    1003            5 : RONet::addLaneProhibition(const ROLane* lane, const RouterProhibition& prohibition) {
    1004              :     if (myLaneProhibitions.count(lane) != 0) {
    1005            0 :         throw ProcessError(TLF("Already loaded prohibition for lane '%'. (Only one prohibition per lane is supported)", lane->getID()));
    1006              :     }
    1007              :     assert(prohibition.end > prohibition.begin);
    1008            5 :     myLaneProhibitions[lane] = prohibition;
    1009            5 :     myLaneProhibitionTimes[prohibition.begin].insert(lane);
    1010            5 :     myHavePermissions = true;
    1011            5 : }
    1012              : 
    1013              : 
    1014              : void
    1015           30 : RONet::updateLaneProhibitions(SUMOTime begin) {
    1016           30 :     const double beginS = STEPS2TIME(begin);
    1017           36 :     while (myLaneProhibitionTimes.size() > 0 && myLaneProhibitionTimes.begin()->first <= beginS) {
    1018              :         const double t = myLaneProhibitionTimes.begin()->first;
    1019           12 :         for (const ROLane* const lane : myLaneProhibitionTimes.begin()->second) {
    1020              :             const SVCPermissions orig = lane->getPermissions();
    1021              :             assert(myLaneProhibitions.count(lane) != 0);
    1022            6 :             RouterProhibition& rp = myLaneProhibitions[lane];
    1023            6 :             const_cast<ROLane*>(lane)->setPermissions(rp.permissions);
    1024            6 :             lane->getEdge().resetSuccessors();
    1025            6 :             for (ROEdge* pred : lane->getEdge().getPredecessors()) {
    1026            0 :                 pred->resetSuccessors();
    1027              :             }
    1028            6 :             if (t == rp.begin) {
    1029              :                 // schedule restoration of original permissions. This works
    1030              :                 // without a stack because there is at most one prohibition per lane
    1031            3 :                 myLaneProhibitionTimes[rp.end].insert(lane);
    1032            3 :                 rp.permissions = orig;
    1033              :             }
    1034              :         }
    1035              :         myLaneProhibitionTimes.erase(myLaneProhibitionTimes.begin());
    1036              :     }
    1037           30 : }
    1038              : 
    1039              : 
    1040              : #ifdef HAVE_FOX
    1041              : // ---------------------------------------------------------------------------
    1042              : // RONet::RoutingTask-methods
    1043              : // ---------------------------------------------------------------------------
    1044              : void
    1045       179894 : RONet::RoutingTask::run(MFXWorkerThread* context) {
    1046       179894 :     myRoutable->computeRoute(*static_cast<WorkerThread*>(context), myRemoveLoops, myErrorHandler);
    1047       179894 : }
    1048              : #endif
    1049              : 
    1050              : 
    1051              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1