LCOV - code coverage report
Current view: top level - src/router - RONet.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 90.9 % 493 448
Test Date: 2026-01-01 15:49:29 Functions: 100.0 % 46 46

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2025 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      5611855 : RONet::getInstance(void) {
      57      5611855 :     if (myInstance != nullptr) {
      58      5611855 :         return myInstance;
      59              :     }
      60            0 :     throw ProcessError(TL("A network was not yet constructed."));
      61              : }
      62              : 
      63              : 
      64         4271 : RONet::RONet() :
      65         4271 :     myVehicleTypes(), myDefaultVTypeMayBeDeleted(true),
      66         4271 :     myDefaultPedTypeMayBeDeleted(true),
      67         4271 :     myDefaultBikeTypeMayBeDeleted(true),
      68         4271 :     myDefaultTaxiTypeMayBeDeleted(true),
      69         4271 :     myDefaultRailTypeMayBeDeleted(true),
      70         4271 :     myHaveActiveFlows(true),
      71         4271 :     myRoutesOutput(nullptr), myRouteAlternativesOutput(nullptr), myTypesOutput(nullptr),
      72         4271 :     myReadRouteNo(0), myDiscardedRouteNo(0), myWrittenRouteNo(0),
      73         4271 :     myHavePermissions(false),
      74         4271 :     myHaveParamRestrictions(false),
      75         4271 :     myNumInternalEdges(0),
      76         4271 :     myErrorHandler(OptionsCont::getOptions().exists("ignore-errors")
      77         8095 :                    && OptionsCont::getOptions().getBool("ignore-errors") ? MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance()),
      78         4271 :     myKeepVTypeDist(OptionsCont::getOptions().exists("keep-vtype-distributions")
      79         8095 :                     && OptionsCont::getOptions().getBool("keep-vtype-distributions")),
      80         4271 :     myDoPTRouting(!OptionsCont::getOptions().exists("ptline-routing")
      81         7635 :                   || OptionsCont::getOptions().getBool("ptline-routing")),
      82         4271 :     myKeepFlows(OptionsCont::getOptions().exists("keep-flows")
      83         7635 :                   && OptionsCont::getOptions().getBool("keep-flows")),
      84         4271 :     myHasBidiEdges(false),
      85        15270 :     myMaxTraveltime(OptionsCont::getOptions().exists("max-traveltime") ? STEPS2TIME(string2time(OptionsCont::getOptions().getString("max-traveltime"))) : -1)
      86              : {
      87         4271 :     if (myInstance != nullptr) {
      88            0 :         throw ProcessError(TL("A network was already constructed."));
      89              :     }
      90         4271 :     SUMOVTypeParameter* type = new SUMOVTypeParameter(DEFAULT_VTYPE_ID, SVC_PASSENGER);
      91         4271 :     type->onlyReferenced = true;
      92         4271 :     myVehicleTypes.add(type->id, type);
      93              : 
      94         4271 :     SUMOVTypeParameter* defPedType = new SUMOVTypeParameter(DEFAULT_PEDTYPE_ID, SVC_PEDESTRIAN);
      95         4271 :     defPedType->onlyReferenced = true;
      96         4271 :     defPedType->parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
      97         4271 :     myVehicleTypes.add(defPedType->id, defPedType);
      98              : 
      99         4271 :     SUMOVTypeParameter* defBikeType = new SUMOVTypeParameter(DEFAULT_BIKETYPE_ID, SVC_BICYCLE);
     100         4271 :     defBikeType->onlyReferenced = true;
     101         4271 :     defBikeType->parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
     102         4271 :     myVehicleTypes.add(defBikeType->id, defBikeType);
     103              : 
     104         4271 :     SUMOVTypeParameter* defTaxiType = new SUMOVTypeParameter(DEFAULT_TAXITYPE_ID, SVC_TAXI);
     105         4271 :     defTaxiType->onlyReferenced = true;
     106         4271 :     defTaxiType->parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
     107         4271 :     myVehicleTypes.add(defTaxiType->id, defTaxiType);
     108              : 
     109         4271 :     SUMOVTypeParameter* defRailType = new SUMOVTypeParameter(DEFAULT_RAILTYPE_ID, SVC_RAIL);
     110         4271 :     defRailType->onlyReferenced = true;
     111         4271 :     defRailType->parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
     112         4271 :     myVehicleTypes.add(defRailType->id, defRailType);
     113              : 
     114         4271 :     myInstance = this;
     115         4271 : }
     116              : 
     117              : 
     118         8085 : RONet::~RONet() {
     119         4474 :     for (const auto& routables : myRoutables) {
     120          426 :         for (RORoutable* const r : routables.second) {
     121          213 :             const ROVehicle* const veh = dynamic_cast<const ROVehicle*>(r);
     122              :             // delete routes and the vehicle
     123          213 :             if (veh != nullptr && veh->getRouteDefinition()->getID()[0] == '!') {
     124          204 :                 if (!myRoutes.remove(veh->getRouteDefinition()->getID())) {
     125           76 :                     delete veh->getRouteDefinition();
     126              :                 }
     127              :             }
     128          213 :             delete r;
     129              :         }
     130              :     }
     131         4297 :     for (const RORoutable* const r : myPTVehicles) {
     132           36 :         const ROVehicle* const veh = dynamic_cast<const ROVehicle*>(r);
     133              :         // delete routes and the vehicle
     134           36 :         if (veh != nullptr && veh->getRouteDefinition()->getID()[0] == '!') {
     135           36 :             if (!myRoutes.remove(veh->getRouteDefinition()->getID())) {
     136            8 :                 delete veh->getRouteDefinition();
     137              :             }
     138              :         }
     139           36 :         delete r;
     140              :     }
     141              :     myRoutables.clear();
     142         4305 :     for (const auto& vTypeDist : myVTypeDistDict) {
     143           88 :         delete vTypeDist.second;
     144              :     }
     145        29390 : }
     146              : 
     147              : 
     148              : void
     149           17 : RONet::addSpeedRestriction(const std::string& id, const SUMOVehicleClass svc, const double speed) {
     150           17 :     mySpeedRestrictions[id][svc] = speed;
     151           17 : }
     152              : 
     153              : 
     154              : double
     155         1286 : RONet::getPreference(const std::string& routingType, const SUMOVTypeParameter& pars) const {
     156         1286 :     if (gRoutingPreferences) {
     157         1286 :         auto it = myVTypePreferences.find(pars.id);
     158         1286 :         if (it != myVTypePreferences.end()) {
     159              :             auto it2 = it->second.find(routingType);
     160           86 :             if (it2 != it->second.end()) {
     161           22 :                 return it2->second;
     162              :             }
     163              :         }
     164              :         auto it3 = myVClassPreferences.find(pars.vehicleClass);
     165         1264 :         if (it3 != myVClassPreferences.end()) {
     166              :             auto it4 = it3->second.find(routingType);
     167          176 :             if (it4 != it3->second.end()) {
     168           47 :                 return it4->second;
     169              :             }
     170              :         }
     171              :         // fallback to generel preferences
     172         1217 :         it = myVTypePreferences.find("");
     173         1217 :         if (it != myVTypePreferences.end()) {
     174              :             auto it2 = it->second.find(routingType);
     175          774 :             if (it2 != it->second.end()) {
     176          140 :                 return it2->second;
     177              :             }
     178              :         }
     179              :     }
     180              :     return 1;
     181              : }
     182              : 
     183              : 
     184              : void
     185           24 : RONet::addPreference(const std::string& routingType, SUMOVehicleClass svc, double prio) {
     186           24 :     myVClassPreferences[svc][routingType] = prio;
     187           24 :     gRoutingPreferences = true;
     188           24 : }
     189              : 
     190              : 
     191              : void
     192           32 : RONet::addPreference(const std::string& routingType, std::string vType, double prio) {
     193           32 :     myVTypePreferences[vType][routingType] = prio;
     194           32 :     gRoutingPreferences = true;
     195           32 : }
     196              : 
     197              : 
     198              : 
     199              : const std::map<SUMOVehicleClass, double>*
     200           66 : RONet::getRestrictions(const std::string& id) const {
     201              :     std::map<std::string, std::map<SUMOVehicleClass, double> >::const_iterator i = mySpeedRestrictions.find(id);
     202           66 :     if (i == mySpeedRestrictions.end()) {
     203              :         return nullptr;
     204              :     }
     205           26 :     return &i->second;
     206              : }
     207              : 
     208              : 
     209              : bool
     210       286950 : RONet::addEdge(ROEdge* edge) {
     211       286950 :     if (!myEdges.add(edge->getID(), edge)) {
     212           36 :         WRITE_ERRORF(TL("The edge '%' occurs at least twice."), edge->getID());
     213           12 :         delete edge;
     214           12 :         return false;
     215              :     }
     216       286938 :     if (edge->isInternal()) {
     217       142144 :         myNumInternalEdges += 1;
     218              :     }
     219              :     return true;
     220              : }
     221              : 
     222              : 
     223              : bool
     224         1816 : RONet::addDistrict(const std::string id, ROEdge* source, ROEdge* sink) {
     225              :     if (myDistricts.count(id) > 0) {
     226            0 :         WRITE_ERRORF(TL("The TAZ '%' occurs at least twice."), id);
     227            0 :         delete source;
     228            0 :         delete sink;
     229            0 :         return false;
     230              :     }
     231              :     sink->setFunction(SumoXMLEdgeFunc::CONNECTOR);
     232         1816 :     if (!addEdge(sink)) {
     233              :         return false;
     234              :     }
     235              :     source->setFunction(SumoXMLEdgeFunc::CONNECTOR);
     236         1816 :     if (!addEdge(source)) {
     237              :         return false;
     238              :     }
     239              :     sink->setOtherTazConnector(source);
     240              :     source->setOtherTazConnector(sink);
     241         3632 :     myDistricts[id] = std::make_pair(std::vector<std::string>(), std::vector<std::string>());
     242         1816 :     return true;
     243              : }
     244              : 
     245              : 
     246              : bool
     247         1379 : RONet::addDistrictEdge(const std::string tazID, const std::string edgeID, const bool isSource) {
     248              :     if (myDistricts.count(tazID) == 0) {
     249            0 :         WRITE_ERRORF(TL("The TAZ '%' is unknown."), tazID);
     250            0 :         return false;
     251              :     }
     252              :     ROEdge* edge = getEdge(edgeID);
     253         1379 :     if (edge == nullptr) {
     254            0 :         WRITE_ERRORF(TL("The edge '%' for TAZ '%' is unknown."), edgeID, tazID);
     255            0 :         return false;
     256              :     }
     257         1379 :     if (isSource) {
     258         2067 :         getEdge(tazID + "-source")->addSuccessor(edge);
     259          689 :         myDistricts[tazID].first.push_back(edgeID);
     260              :     } else {
     261         2070 :         edge->addSuccessor(getEdge(tazID + "-sink"));
     262          690 :         myDistricts[tazID].second.push_back(edgeID);
     263              :     }
     264              :     return true;
     265              : }
     266              : 
     267              : 
     268              : void
     269          101 : RONet::addJunctionTaz(ROAbstractEdgeBuilder& eb) {
     270         1544 :     for (auto item : myNodes) {
     271              :         const std::string tazID = item.first;
     272            8 :         if (myDistricts.count(tazID) != 0) {
     273           24 :             WRITE_WARNINGF(TL("A TAZ with id '%' already exists. Not building junction TAZ."), tazID);
     274            8 :             continue;
     275              :         }
     276         1435 :         const std::string sourceID = tazID + "-source";
     277         1435 :         const std::string sinkID = tazID + "-sink";
     278              :         // sink must be added before source
     279         2870 :         ROEdge* sink = eb.buildEdge(sinkID, nullptr, nullptr, 0, "", "");
     280         2870 :         ROEdge* source = eb.buildEdge(sourceID, nullptr, nullptr, 0, "", "");
     281              :         sink->setOtherTazConnector(source);
     282              :         source->setOtherTazConnector(sink);
     283         2870 :         if (!addDistrict(tazID, source, sink)) {
     284              :             continue;
     285              :         }
     286         1435 :         auto& district = myDistricts[tazID];
     287         1435 :         const RONode* junction = item.second;
     288        12452 :         for (const ROEdge* edge : junction->getIncoming()) {
     289        11017 :             if (!edge->isInternal()) {
     290         3129 :                 const_cast<ROEdge*>(edge)->addSuccessor(sink);
     291         3129 :                 district.second.push_back(edge->getID());
     292              :             }
     293              :         }
     294        12452 :         for (const ROEdge* edge : junction->getOutgoing()) {
     295        11017 :             if (!edge->isInternal()) {
     296         3129 :                 source->addSuccessor(const_cast<ROEdge*>(edge));
     297         3129 :                 district.first.push_back(edge->getID());
     298              :             }
     299              :         }
     300              :     }
     301          101 : }
     302              : 
     303              : 
     304              : void
     305         3540 : RONet::setBidiEdges(const std::map<ROEdge*, std::string>& bidiMap) {
     306        13446 :     for (const auto& item : bidiMap) {
     307         9906 :         ROEdge* bidi = myEdges.get(item.second);
     308         9906 :         if (bidi == nullptr) {
     309            0 :             WRITE_ERRORF(TL("The bidi edge '%' is not known."), item.second);
     310              :         }
     311         9906 :         item.first->setBidiEdge(bidi);
     312         9906 :         myHasBidiEdges = true;
     313              :     }
     314         3540 : }
     315              : 
     316              : 
     317              : void
     318        66157 : RONet::addNode(RONode* node) {
     319        66157 :     if (!myNodes.add(node->getID(), node)) {
     320            0 :         WRITE_ERRORF(TL("The node '%' occurs at least twice."), node->getID());
     321            0 :         delete node;
     322              :     }
     323        66157 : }
     324              : 
     325              : 
     326              : void
     327         1599 : RONet::addStoppingPlace(const std::string& id, const SumoXMLTag category, SUMOVehicleParameter::Stop* stop) {
     328         3078 :     if (!myStoppingPlaces[category == SUMO_TAG_TRAIN_STOP ? SUMO_TAG_BUS_STOP : category].add(id, stop)) {
     329           12 :         WRITE_ERRORF(TL("The % '%' occurs at least twice."), toString(category), id);
     330            4 :         delete stop;
     331              :     }
     332         1599 : }
     333              : 
     334              : 
     335              : bool
     336       280731 : RONet::addRouteDef(RORouteDef* def) {
     337       280731 :     return myRoutes.add(def->getID(), def);
     338              : }
     339              : 
     340              : 
     341              : void
     342         2841 : RONet::openOutput(const OptionsCont& options) {
     343         8521 :     if (options.isSet("output-file") && options.getString("output-file") != "") {
     344         2840 :         myRoutesOutput = &OutputDevice::getDevice(options.getString("output-file"));
     345         2834 :         if (myRoutesOutput->isNull()) {
     346            1 :             myRoutesOutput = nullptr;
     347              :         } else {
     348         5666 :             myRoutesOutput->writeXMLHeader("routes", "routes_file.xsd");
     349              :         }
     350              :     }
     351         8325 :     if (options.exists("alternatives-output") && options.isSet("alternatives-output")
     352        13261 :             && !(options.exists("write-trips") && options.getBool("write-trips"))) {
     353         2463 :         myRouteAlternativesOutput = &OutputDevice::getDevice(options.getString("alternatives-output"));
     354         2463 :         if (myRouteAlternativesOutput->isNull()) {
     355          131 :             myRouteAlternativesOutput = nullptr;
     356              :         } else {
     357         4664 :             myRouteAlternativesOutput->writeXMLHeader("routes", "routes_file.xsd");
     358              :         }
     359              :     }
     360         5670 :     if (options.isSet("vtype-output")) {
     361           32 :         myTypesOutput = &OutputDevice::getDevice(options.getString("vtype-output"));
     362           64 :         myTypesOutput->writeXMLHeader("routes", "routes_file.xsd");
     363              :     }
     364         2835 : }
     365              : 
     366              : 
     367              : void
     368         2623 : RONet::writeIntermodal(const OptionsCont& options, ROIntermodalRouter& router) const {
     369         5246 :     if (options.exists("intermodal-network-output") && options.isSet("intermodal-network-output")) {
     370           32 :         OutputDevice::createDeviceByOption("intermodal-network-output", "intermodal");
     371           32 :         router.writeNetwork(OutputDevice::getDevice(options.getString("intermodal-network-output")));
     372              :     }
     373         5246 :     if (options.exists("intermodal-weight-output") && options.isSet("intermodal-weight-output")) {
     374           16 :         OutputDevice::createDeviceByOption("intermodal-weight-output", "weights", "meandata_file.xsd");
     375            8 :         OutputDevice& dev = OutputDevice::getDeviceByOption("intermodal-weight-output");
     376            8 :         dev.openTag(SUMO_TAG_INTERVAL);
     377            8 :         dev.writeAttr(SUMO_ATTR_ID, "intermodalweights");
     378            8 :         dev.writeAttr(SUMO_ATTR_BEGIN, 0);
     379            8 :         dev.writeAttr(SUMO_ATTR_END, SUMOTime_MAX);
     380            8 :         router.writeWeights(dev);
     381           16 :         dev.closeTag();
     382              :     }
     383         2623 : }
     384              : 
     385              : 
     386              : void
     387         2840 : RONet::cleanup() {
     388              :     // end writing
     389         2840 :     if (myRoutesOutput != nullptr) {
     390         2833 :         myRoutesOutput->close();
     391              :     }
     392              :     // only if opened
     393         2840 :     if (myRouteAlternativesOutput != nullptr) {
     394         2332 :         myRouteAlternativesOutput->close();
     395              :     }
     396              :     // only if opened
     397         2840 :     if (myTypesOutput != nullptr) {
     398           32 :         myTypesOutput->close();
     399              :     }
     400              :     RouteCostCalculator<RORoute, ROEdge, ROVehicle>::cleanup();
     401              : #ifdef HAVE_FOX
     402         2840 :     if (myThreadPool.size() > 0) {
     403           30 :         myThreadPool.clear();
     404              :     }
     405              : #endif
     406         2840 : }
     407              : 
     408              : 
     409              : 
     410              : SUMOVTypeParameter*
     411       494455 : RONet::getVehicleTypeSecure(const std::string& id) {
     412              :     // check whether the type was already known
     413              :     SUMOVTypeParameter* type = myVehicleTypes.get(id);
     414       494455 :     if (id == DEFAULT_VTYPE_ID) {
     415       455168 :         myDefaultVTypeMayBeDeleted = false;
     416        39287 :     } else if (id == DEFAULT_PEDTYPE_ID) {
     417         5340 :         myDefaultPedTypeMayBeDeleted = false;
     418        33947 :     } else if (id == DEFAULT_BIKETYPE_ID) {
     419           54 :         myDefaultBikeTypeMayBeDeleted = false;
     420        33893 :     } else if (id == DEFAULT_TAXITYPE_ID) {
     421           93 :         myDefaultTaxiTypeMayBeDeleted = false;
     422        33800 :     } else if (id == DEFAULT_RAILTYPE_ID) {
     423            0 :         myDefaultRailTypeMayBeDeleted = false;
     424              :     }
     425       494455 :     if (type != nullptr) {
     426              :         return type;
     427              :     }
     428              :     VTypeDistDictType::iterator it2 = myVTypeDistDict.find(id);
     429         1478 :     if (it2 != myVTypeDistDict.end()) {
     430         1148 :         return it2->second->get();
     431              :     }
     432          330 :     if (id == "") {
     433              :         // ok, no vehicle type or an unknown type was given within the user input
     434              :         //  return the default type
     435            0 :         myDefaultVTypeMayBeDeleted = false;
     436              :         return myVehicleTypes.get(DEFAULT_VTYPE_ID);
     437              :     }
     438              :     return type;
     439              : }
     440              : 
     441              : 
     442              : bool
     443         2073 : RONet::checkVType(const std::string& id) {
     444         2073 :     if (id == DEFAULT_VTYPE_ID) {
     445           68 :         if (myDefaultVTypeMayBeDeleted) {
     446           68 :             myVehicleTypes.remove(id);
     447           68 :             myDefaultVTypeMayBeDeleted = false;
     448              :         } else {
     449              :             return false;
     450              :         }
     451         2005 :     } else if (id == DEFAULT_PEDTYPE_ID) {
     452            0 :         if (myDefaultPedTypeMayBeDeleted) {
     453            0 :             myVehicleTypes.remove(id);
     454            0 :             myDefaultPedTypeMayBeDeleted = false;
     455              :         } else {
     456              :             return false;
     457              :         }
     458         2005 :     } else if (id == DEFAULT_BIKETYPE_ID) {
     459            0 :         if (myDefaultBikeTypeMayBeDeleted) {
     460            0 :             myVehicleTypes.remove(id);
     461            0 :             myDefaultBikeTypeMayBeDeleted = false;
     462              :         } else {
     463              :             return false;
     464              :         }
     465         2005 :     } else if (id == DEFAULT_TAXITYPE_ID) {
     466            0 :         if (myDefaultTaxiTypeMayBeDeleted) {
     467            0 :             myVehicleTypes.remove(id);
     468            0 :             myDefaultTaxiTypeMayBeDeleted = false;
     469              :         } else {
     470              :             return false;
     471              :         }
     472         2005 :     } else if (id == DEFAULT_RAILTYPE_ID) {
     473            0 :         if (myDefaultRailTypeMayBeDeleted) {
     474            0 :             myVehicleTypes.remove(id);
     475            0 :             myDefaultRailTypeMayBeDeleted = false;
     476              :         } else {
     477              :             return false;
     478              :         }
     479              :     } else {
     480         2005 :         if (myVehicleTypes.get(id) != 0 || myVTypeDistDict.find(id) != myVTypeDistDict.end()) {
     481            0 :             return false;
     482              :         }
     483              :     }
     484              :     return true;
     485              : }
     486              : 
     487              : 
     488              : bool
     489         2029 : RONet::addVehicleType(SUMOVTypeParameter* type) {
     490         2029 :     if (checkVType(type->id)) {
     491         2029 :         myVehicleTypes.add(type->id, type);
     492              :     } else {
     493            0 :         WRITE_ERRORF(TL("The vehicle type '%' occurs at least twice."), type->id);
     494            0 :         delete type;
     495            0 :         return false;
     496              :     }
     497         2029 :     return true;
     498              : }
     499              : 
     500              : 
     501              : bool
     502           44 : RONet::addVTypeDistribution(const std::string& id, RandomDistributor<SUMOVTypeParameter*>* vehTypeDistribution) {
     503           44 :     if (checkVType(id)) {
     504           44 :         myVTypeDistDict[id] = vehTypeDistribution;
     505           44 :         return true;
     506              :     }
     507            0 :     delete vehTypeDistribution;
     508              :     return false;
     509              : }
     510              : 
     511              : 
     512              : bool
     513       296921 : RONet::addVehicle(const std::string& id, ROVehicle* veh) {
     514       296921 :     if (myVehIDs.find(id) == myVehIDs.end()) {
     515       593802 :         myVehIDs[id] = veh->getParameter().departProcedure == DepartDefinition::TRIGGERED ? -1 : veh->getDepartureTime();
     516              : 
     517       296917 :         if (veh->isPublicTransport()) {
     518           44 :             if (!veh->isPartOfFlow()) {
     519           36 :                 myPTVehicles.push_back(veh);
     520              :             }
     521           44 :             if (!myDoPTRouting) {
     522              :                 return true;
     523              :             }
     524              :         }
     525       296881 :         myRoutables[veh->getDepart()].push_back(veh);
     526       296881 :         return true;
     527              :     }
     528           12 :     WRITE_ERRORF(TL("Another vehicle with the id '%' exists."), id);
     529            4 :     delete veh;
     530              :     return false;
     531              : }
     532              : 
     533              : 
     534              : bool
     535          256 : RONet::knowsVehicle(const std::string& id) const {
     536          256 :     return myVehIDs.find(id) != myVehIDs.end();
     537              : }
     538              : 
     539              : SUMOTime
     540           28 : RONet::getDeparture(const std::string& vehID) const {
     541              :     auto it = myVehIDs.find(vehID);
     542           28 :     if (it != myVehIDs.end()) {
     543           28 :         return it->second;
     544              :     } else {
     545            0 :         throw ProcessError(TLF("Requesting departure time for unknown vehicle '%'", vehID));
     546              :     }
     547              : }
     548              : 
     549              : 
     550              : bool
     551         2292 : RONet::addFlow(SUMOVehicleParameter* flow, const bool randomize) {
     552         2292 :     if (randomize && flow->repetitionOffset >= 0) {
     553           10 :         myDepartures[flow->id].reserve(flow->repetitionNumber);
     554          110 :         for (int i = 0; i < flow->repetitionNumber; ++i) {
     555          100 :             myDepartures[flow->id].push_back(flow->depart + RandHelper::rand(flow->repetitionNumber * flow->repetitionOffset));
     556              :         }
     557           10 :         std::sort(myDepartures[flow->id].begin(), myDepartures[flow->id].end());
     558           10 :         std::reverse(myDepartures[flow->id].begin(), myDepartures[flow->id].end());
     559              :     }
     560         2292 :     const bool added = myFlows.add(flow->id, flow);
     561         2292 :     if (added) {
     562         2288 :         myHaveActiveFlows = true;
     563              :     }
     564         2292 :     return added;
     565              : }
     566              : 
     567              : 
     568              : bool
     569         2919 : RONet::addPerson(ROPerson* person) {
     570              :     if (myPersonIDs.count(person->getID()) == 0) {
     571              :         myPersonIDs.insert(person->getID());
     572         2919 :         myRoutables[person->getDepart()].push_back(person);
     573         2919 :         return true;
     574              :     }
     575            0 :     WRITE_ERRORF(TL("Another person with the id '%' exists."), person->getID());
     576            0 :     return false;
     577              : }
     578              : 
     579              : 
     580              : void
     581           56 : RONet::addContainer(const SUMOTime depart, const std::string desc) {
     582           56 :     myContainers.insert(std::pair<const SUMOTime, const std::string>(depart, desc));
     583           56 : }
     584              : 
     585              : 
     586              : void
     587        13267 : RONet::checkFlows(SUMOTime time, MsgHandler* errorHandler) {
     588        13267 :     myHaveActiveFlows = false;
     589        50941 :     for (const auto& i : myFlows) {
     590        37674 :         SUMOVehicleParameter* const pars = i.second;
     591        37674 :         if (pars->line != "" && !myDoPTRouting) {
     592          479 :             continue;
     593              :         }
     594        37195 :         if (myKeepFlows) {
     595          796 :             if (pars->repetitionsDone < pars->repetitionNumber) {
     596              :                 // each each flow only once
     597          790 :                 pars->repetitionsDone = pars->repetitionNumber;
     598          790 :                 const SUMOVTypeParameter* type = getVehicleTypeSecure(pars->vtypeid);
     599          790 :                 if (type == nullptr) {
     600            0 :                     type = getVehicleTypeSecure(DEFAULT_VTYPE_ID);
     601              :                 } else {
     602              :                     auto dist = getVTypeDistribution(pars->vtypeid);
     603            0 :                     if (dist != nullptr) {
     604            0 :                         WRITE_WARNINGF("Keeping flow '%' with a vTypeDistribution can lead to invalid routes if the distribution contains different vClasses", pars->id);
     605              :                     }
     606              :                 }
     607         1580 :                 RORouteDef* route = getRouteDef(pars->routeid)->copy(pars->routeid, pars->depart);
     608          790 :                 ROVehicle* veh = new ROVehicle(*pars, route, type, this, errorHandler);
     609          790 :                 addVehicle(pars->id, veh);
     610              :             }
     611        36399 :         } else if (pars->repetitionProbability > 0) {
     612          108 :             if (pars->repetitionEnd > pars->depart && pars->repetitionsDone < pars->repetitionNumber) {
     613           96 :                 myHaveActiveFlows = true;
     614              :             }
     615              :             const SUMOTime origDepart = pars->depart;
     616         1020 :             while (pars->depart < time && pars->repetitionsDone < pars->repetitionNumber) {
     617          928 :                 if (pars->repetitionEnd <= pars->depart) {
     618              :                     break;
     619              :                 }
     620              :                 // only call rand if all other conditions are met
     621          912 :                 if (RandHelper::rand() < (pars->repetitionProbability * TS)) {
     622          168 :                     SUMOVehicleParameter* newPars = new SUMOVehicleParameter(*pars);
     623          336 :                     newPars->id = pars->id + "." + toString(pars->repetitionsDone);
     624          168 :                     newPars->depart = pars->depart;
     625          168 :                     for (StopParVector::iterator stop = newPars->stops.begin(); stop != newPars->stops.end(); ++stop) {
     626            0 :                         if (stop->until >= 0) {
     627            0 :                             stop->until += pars->depart - origDepart;
     628              :                         }
     629              :                     }
     630          168 :                     pars->repetitionsDone++;
     631              :                     // try to build the vehicle
     632          168 :                     const SUMOVTypeParameter* type = getVehicleTypeSecure(pars->vtypeid);
     633          168 :                     if (type == nullptr) {
     634           32 :                         type = getVehicleTypeSecure(DEFAULT_VTYPE_ID);
     635          136 :                     } else if (!myKeepVTypeDist) {
     636              :                         // fix the type id in case we used a distribution
     637          136 :                         newPars->vtypeid = type->id;
     638              :                     }
     639          168 :                     const SUMOTime stopOffset = pars->routeid[0] == '!' ? pars->depart - origDepart : pars->depart;
     640          336 :                     RORouteDef* route = getRouteDef(pars->routeid)->copy("!" + newPars->id, stopOffset);
     641          168 :                     ROVehicle* veh = new ROVehicle(*newPars, route, type, this, errorHandler);
     642          168 :                     addVehicle(newPars->id, veh);
     643          168 :                     delete newPars;
     644              :                 }
     645          912 :                 pars->depart += DELTA_T;
     646              :             }
     647              :         } else {
     648        36291 :             SUMOTime depart = static_cast<SUMOTime>(pars->depart + pars->repetitionTotalOffset);
     649        54019 :             while (pars->repetitionsDone < pars->repetitionNumber && pars->repetitionEnd >= depart) {
     650        28450 :                 myHaveActiveFlows = true;
     651        28450 :                 depart = static_cast<SUMOTime>(pars->depart + pars->repetitionTotalOffset);
     652        28450 :                 if (myDepartures.find(pars->id) != myDepartures.end()) {
     653          110 :                     depart = myDepartures[pars->id].back();
     654              :                 }
     655        28450 :                 if (depart >= time + DELTA_T) {
     656              :                     break;
     657              :                 }
     658        17728 :                 if (myDepartures.find(pars->id) != myDepartures.end()) {
     659          100 :                     myDepartures[pars->id].pop_back();
     660              :                 }
     661        17728 :                 SUMOVehicleParameter* newPars = new SUMOVehicleParameter(*pars);
     662        35456 :                 newPars->id = pars->id + "." + toString(pars->repetitionsDone);
     663        17728 :                 newPars->depart = depart;
     664        17848 :                 for (StopParVector::iterator stop = newPars->stops.begin(); stop != newPars->stops.end(); ++stop) {
     665          120 :                     if (stop->until >= 0) {
     666            0 :                         stop->until += depart - pars->depart;
     667              :                     }
     668              :                 }
     669        17728 :                 pars->incrementFlow(1);
     670              :                 // try to build the vehicle
     671        17728 :                 const SUMOVTypeParameter* type = getVehicleTypeSecure(pars->vtypeid);
     672        17728 :                 if (type == nullptr) {
     673           62 :                     type = getVehicleTypeSecure(DEFAULT_VTYPE_ID);
     674        17666 :                 } else if (!myKeepVTypeDist) {
     675              :                     // fix the type id in case we used a distribution
     676        17626 :                     newPars->vtypeid = type->id;
     677              :                 }
     678        17728 :                 const SUMOTime stopOffset = pars->routeid[0] == '!' ? depart - pars->depart : depart;
     679        35456 :                 RORouteDef* route = getRouteDef(pars->routeid)->copy("!" + newPars->id, stopOffset);
     680        17728 :                 ROVehicle* veh = new ROVehicle(*newPars, route, type, this, errorHandler);
     681        17728 :                 addVehicle(newPars->id, veh);
     682        17728 :                 delete newPars;
     683              :             }
     684              :         }
     685              :     }
     686        13267 : }
     687              : 
     688              : 
     689              : void
     690           56 : RONet::createBulkRouteRequests(const RORouterProvider& provider, const SUMOTime time, const bool removeLoops) {
     691              :     std::map<const int, std::vector<RORoutable*> > bulkVehs;
     692              :     int numBulked = 0;
     693           84 :     for (RoutablesMap::const_iterator i = myRoutables.begin(); i != myRoutables.end(); ++i) {
     694           56 :         if (i->first >= time) {
     695              :             break;
     696              :         }
     697          539 :         for (RORoutable* const routable : i->second) {
     698          511 :             const ROEdge* const depEdge = routable->getDepartEdge();
     699          511 :             bulkVehs[depEdge->getNumericalID()].push_back(routable);
     700          511 :             RORoutable* const first = bulkVehs[depEdge->getNumericalID()].front();
     701          511 :             numBulked++;
     702          511 :             if (first->getMaxSpeed() != routable->getMaxSpeed()) {
     703            6 :                 WRITE_WARNINGF(TL("Bulking different maximum speeds ('%' and '%') may lead to suboptimal routes."), first->getID(), routable->getID());
     704              :             }
     705          511 :             if (first->getVClass() != routable->getVClass()) {
     706            6 :                 WRITE_WARNINGF(TL("Bulking different vehicle classes ('%' and '%') may lead to invalid routes."), first->getID(), routable->getID());
     707              :             }
     708              :         }
     709              :     }
     710              : #ifdef HAVE_FOX
     711              :     int workerIndex = 0;
     712              : #endif
     713           56 :     if ((int)bulkVehs.size() < numBulked) {
     714           56 :         WRITE_MESSAGE(TLF("Using bulk-mode for % entities from % origins", numBulked, bulkVehs.size()));
     715              :     }
     716          157 :     for (std::map<const int, std::vector<RORoutable*> >::const_iterator i = bulkVehs.begin(); i != bulkVehs.end(); ++i) {
     717              : #ifdef HAVE_FOX
     718          101 :         if (myThreadPool.size() > 0) {
     719              :             bool bulk = true;
     720          132 :             for (RORoutable* const r : i->second) {
     721          120 :                 myThreadPool.add(new RoutingTask(r, removeLoops, myErrorHandler), workerIndex);
     722          120 :                 if (bulk) {
     723           12 :                     myThreadPool.add(new BulkmodeTask(true), workerIndex);
     724              :                     bulk = false;
     725              :                 }
     726              :             }
     727           12 :             myThreadPool.add(new BulkmodeTask(false), workerIndex);
     728           12 :             workerIndex++;
     729           12 :             if (workerIndex == (int)myThreadPool.size()) {
     730              :                 workerIndex = 0;
     731              :             }
     732           12 :             continue;
     733           12 :         }
     734              : #endif
     735          480 :         for (RORoutable* const r : i->second) {
     736          391 :             r->computeRoute(provider, removeLoops, myErrorHandler);
     737          391 :             provider.setBulkMode(true);
     738              :         }
     739           89 :         provider.setBulkMode(false);
     740              :     }
     741           56 : }
     742              : 
     743              : 
     744              : SUMOTime
     745        19306 : RONet::saveAndRemoveRoutesUntil(OptionsCont& options, const RORouterProvider& provider,
     746              :                                 SUMOTime time) {
     747        19306 :     MsgHandler* mh = (options.getBool("ignore-errors") ?
     748        19306 :                       MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance());
     749        19306 :     if (myHaveActiveFlows) {
     750        13267 :         checkFlows(time, mh);
     751              :     }
     752              :     SUMOTime lastTime = -1;
     753        19306 :     const bool removeLoops = options.getBool("remove-loops");
     754              : #ifdef HAVE_FOX
     755        38612 :     const int maxNumThreads = options.getInt("routing-threads");
     756              : #endif
     757        19306 :     if (myRoutables.size() != 0) {
     758        18586 :         if (options.getBool("bulk-routing")) {
     759              : #ifdef HAVE_FOX
     760           64 :             while ((int)myThreadPool.size() < maxNumThreads) {
     761            8 :                 new WorkerThread(myThreadPool, provider);
     762              :             }
     763              : #endif
     764           56 :             createBulkRouteRequests(provider, time, removeLoops);
     765              :         } else {
     766       250656 :             for (RoutablesMap::const_iterator i = myRoutables.begin(); i != myRoutables.end(); ++i) {
     767       247890 :                 if (i->first >= time) {
     768              :                     break;
     769              :                 }
     770       540511 :                 for (RORoutable* const routable : i->second) {
     771              : #ifdef HAVE_FOX
     772              :                     // add task
     773       299092 :                     if (maxNumThreads > 0) {
     774              :                         const int numThreads = (int)myThreadPool.size();
     775          827 :                         if (numThreads == 0) {
     776              :                             // This is the very first routing. Since at least the CHRouter needs initialization
     777              :                             // before it gets cloned, we do not do this in parallel
     778           24 :                             routable->computeRoute(provider, removeLoops, myErrorHandler);
     779           24 :                             new WorkerThread(myThreadPool, provider);
     780              :                         } else {
     781              :                             // add thread if necessary
     782          803 :                             if (numThreads < maxNumThreads && myThreadPool.isFull()) {
     783           18 :                                 new WorkerThread(myThreadPool, provider);
     784              :                             }
     785          803 :                             myThreadPool.add(new RoutingTask(routable, removeLoops, myErrorHandler));
     786              :                         }
     787          827 :                         continue;
     788          827 :                     }
     789              : #endif
     790       298265 :                     routable->computeRoute(provider, removeLoops, myErrorHandler);
     791              :                 }
     792              :             }
     793              :         }
     794              : #ifdef HAVE_FOX
     795         9277 :         myThreadPool.waitAll();
     796              : #endif
     797              :     }
     798        38308 :     const double scale = options.exists("scale-suffix") ? options.getFloat("scale") : 1;
     799              :     // write all vehicles (and additional structures)
     800       260785 :     while (myRoutables.size() != 0 || myContainers.size() != 0) {
     801              :         // get the next vehicle, person or container
     802              :         RoutablesMap::iterator routables = myRoutables.begin();
     803       247986 :         const SUMOTime routableTime = routables == myRoutables.end() ? SUMOTime_MAX : routables->first;
     804              :         ContainerMap::iterator container = myContainers.begin();
     805       247986 :         const SUMOTime containerTime = container == myContainers.end() ? SUMOTime_MAX : container->first;
     806              :         // check whether it shall not yet be computed
     807       247986 :         if (routableTime >= time && containerTime >= time) {
     808              :             lastTime = MIN2(routableTime, containerTime);
     809              :             break;
     810              :         }
     811              :         const SUMOTime minTime = MIN2(routableTime, containerTime);
     812       241495 :         if (routableTime == minTime) {
     813              :             // check whether to print the output
     814       241447 :             if (lastTime != routableTime && lastTime != -1) {
     815              :                 // report writing progress
     816       235254 :                 if (options.getInt("stats-period") >= 0 && ((int)routableTime % options.getInt("stats-period")) == 0) {
     817            0 :                     WRITE_MESSAGE("Read: " + toString(myVehIDs.size()) + ",  Discarded: " + toString(myDiscardedRouteNo) + ",  Written: " + toString(myWrittenRouteNo));
     818              :                 }
     819              :             }
     820              :             lastTime = routableTime;
     821       541034 :             for (const RORoutable* const r : routables->second) {
     822              :                 // ok, check whether it has been routed
     823       299587 :                 if (r->getRoutingSuccess()) {
     824              :                     // write the route
     825       280396 :                     int quota = getScalingQuota(scale, myWrittenRouteNo);
     826       280396 :                     r->write(myRoutesOutput, myRouteAlternativesOutput, myTypesOutput, options, quota);
     827       280396 :                     myWrittenRouteNo++;
     828              :                 } else {
     829        19191 :                     myDiscardedRouteNo++;
     830              :                 }
     831              :                 // we need to keep individual public transport vehicles but not the flows
     832       299587 :                 if (!r->isPublicTransport() || r->isPartOfFlow()) {
     833              :                     // delete routes and the vehicle
     834       299587 :                     const ROVehicle* const veh = dynamic_cast<const ROVehicle*>(r);
     835       299587 :                     if (veh != nullptr && veh->getRouteDefinition()->getID()[0] == '!') {
     836       296677 :                         if (r->isPartOfFlow() || !myRoutes.remove(veh->getRouteDefinition()->getID())) {
     837        19877 :                             delete veh->getRouteDefinition();
     838              :                         }
     839              :                     }
     840       299587 :                     delete r;
     841              :                 }
     842              :             }
     843              :             myRoutables.erase(routables);
     844              :         }
     845       241495 :         if (containerTime == minTime) {
     846           48 :             myRoutesOutput->writePreformattedTag(container->second);
     847           48 :             if (myRouteAlternativesOutput != nullptr) {
     848              :                 myRouteAlternativesOutput->writePreformattedTag(container->second);
     849              :             }
     850              :             myContainers.erase(container);
     851              :         }
     852              :     }
     853        19290 :     return lastTime;
     854              : }
     855              : 
     856              : 
     857              : bool
     858        41363 : RONet::furtherStored() {
     859        41363 :     return myRoutables.size() > 0 || (myFlows.size() > 0 && myHaveActiveFlows) || myContainers.size() > 0;
     860              : }
     861              : 
     862              : 
     863              : int
     864          123 : RONet::getEdgeNumber() const {
     865          123 :     return myEdges.size();
     866              : }
     867              : 
     868              : 
     869              : int
     870            1 : RONet::getInternalEdgeNumber() const {
     871            1 :     return myNumInternalEdges;
     872              : }
     873              : 
     874              : 
     875              : ROEdge*
     876         6097 : RONet::getEdgeForLaneID(const std::string& laneID) const {
     877        12194 :     return getEdge(SUMOXMLDefinitions::getEdgeIDFromLane(laneID));
     878              : }
     879              : 
     880              : 
     881              : ROLane*
     882         1136 : RONet::getLane(const std::string& laneID) const {
     883         1136 :     int laneIndex = SUMOXMLDefinitions::getIndexFromLane(laneID);
     884         1136 :     return getEdgeForLaneID(laneID)->getLanes()[laneIndex];
     885              : }
     886              : 
     887              : 
     888              : void
     889          594 : RONet::adaptIntermodalRouter(ROIntermodalRouter& router) {
     890          594 :     double taxiWait = STEPS2TIME(string2time(OptionsCont::getOptions().getString("persontrip.taxi.waiting-time")));
     891          878 :     for (const auto& stopType : myInstance->myStoppingPlaces) {
     892              :         // add access to all stopping places
     893          284 :         const SumoXMLTag element = stopType.first;
     894         1690 :         for (const auto& stop : stopType.second) {
     895         1406 :             router.getNetwork()->addAccess(stop.first, myInstance->getEdgeForLaneID(stop.second->lane),
     896         1406 :                                            stop.second->startPos, stop.second->endPos, 0., element, false, taxiWait);
     897              :             // add access to all public transport stops
     898         1406 :             if (element == SUMO_TAG_BUS_STOP) {
     899         2364 :                 for (const auto& a : stop.second->accessPos) {
     900          978 :                     router.getNetwork()->addAccess(stop.first, myInstance->getEdgeForLaneID(std::get<0>(a)),
     901              :                                                    std::get<1>(a), std::get<1>(a), std::get<2>(a), SUMO_TAG_BUS_STOP, true, taxiWait);
     902              :                 }
     903              :             }
     904              :         }
     905              :     }
     906              :     // fill the public transport router with pre-parsed public transport lines
     907         1089 :     for (const auto& i : myInstance->myFlows) {
     908          495 :         if (i.second->line != "") {
     909          483 :             const RORouteDef* const route = myInstance->getRouteDef(i.second->routeid);
     910              :             const StopParVector* addStops = nullptr;
     911          966 :             if (route != nullptr && route->getFirstRoute() != nullptr) {
     912              :                 addStops = &route->getFirstRoute()->getStops();
     913              :             }
     914          483 :             router.getNetwork()->addSchedule(*i.second, addStops);
     915              :         }
     916              :     }
     917          630 :     for (const RORoutable* const veh : myInstance->myPTVehicles) {
     918              :         // add single vehicles with line attribute which are not part of a flow
     919              :         // no need to add route stops here, they have been added to the vehicle before
     920           36 :         router.getNetwork()->addSchedule(veh->getParameter());
     921              :     }
     922              :     // add access to transfer from walking to taxi-use
     923          594 :     if ((router.getCarWalkTransfer() & ModeChangeOptions::TAXI_PICKUP_ANYWHERE) != 0) {
     924        41181 :         for (const ROEdge* edge : ROEdge::getAllEdges()) {
     925        40599 :             if (!edge->isTazConnector() && (edge->getPermissions() & SVC_PEDESTRIAN) != 0 && (edge->getPermissions() & SVC_TAXI) != 0) {
     926        19706 :                 router.getNetwork()->addCarAccess(edge, SVC_TAXI, taxiWait);
     927              :             }
     928              :         }
     929              :     }
     930          594 : }
     931              : 
     932              : 
     933              : bool
     934      4186684 : RONet::hasPermissions() const {
     935      4186684 :     return myHavePermissions;
     936              : }
     937              : 
     938              : 
     939              : void
     940       206556 : RONet::setPermissionsFound() {
     941       206556 :     myHavePermissions = true;
     942       206556 : }
     943              : 
     944              : bool
     945           12 : RONet::hasLoadedEffort() const {
     946           38 :     for (const auto& item : myEdges) {
     947           35 :         if (item.second->hasStoredEffort()) {
     948              :             return true;
     949              :         }
     950              :     }
     951              :     return false;
     952              : }
     953              : 
     954              : const std::string
     955         1147 : RONet::getStoppingPlaceName(const std::string& id) const {
     956         1339 :     for (const auto& mapItem : myStoppingPlaces) {
     957              :         SUMOVehicleParameter::Stop* stop = mapItem.second.get(id);
     958         1147 :         if (stop != nullptr) {
     959              :             // see RONetHandler::parseStoppingPlace
     960              :             return stop->busstop;
     961              :         }
     962              :     }
     963            0 :     return "";
     964              : }
     965              : 
     966              : const std::string
     967         1027 : RONet::getStoppingPlaceElement(const std::string& id) const {
     968         1171 :     for (const auto& mapItem : myStoppingPlaces) {
     969              :         SUMOVehicleParameter::Stop* stop = mapItem.second.get(id);
     970         1027 :         if (stop != nullptr) {
     971              :             // see RONetHandler::parseStoppingPlace
     972              :             return stop->actType;
     973              :         }
     974              :     }
     975            0 :     return toString(SUMO_TAG_BUS_STOP);
     976              : }
     977              : 
     978              : 
     979              : void
     980            4 : RONet::addProhibition(const ROEdge* edge, const RouterProhibition& prohibition) {
     981              :     if (myProhibitions.count(edge) != 0) {
     982            0 :         throw ProcessError(TLF("Already loaded prohibition for edge '%'. (Only one prohibition per edge is supported)", edge->getID()));
     983              :     }
     984            4 :     myProhibitions[edge] = prohibition;
     985            4 : }
     986              : 
     987              : 
     988              : #ifdef HAVE_FOX
     989              : // ---------------------------------------------------------------------------
     990              : // RONet::RoutingTask-methods
     991              : // ---------------------------------------------------------------------------
     992              : void
     993          923 : RONet::RoutingTask::run(MFXWorkerThread* context) {
     994          923 :     myRoutable->computeRoute(*static_cast<WorkerThread*>(context), myRemoveLoops, myErrorHandler);
     995          923 : }
     996              : #endif
     997              : 
     998              : 
     999              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1