LCOV - code coverage report
Current view: top level - src/netimport - NIImporter_MATSim.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 72.7 % 132 96
Test Date: 2024-12-21 15:45:41 Functions: 81.8 % 11 9

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2024 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    NIImporter_MATSim.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Jakob Erdmann
      17              : /// @author  Michael Behrisch
      18              : /// @date    Tue, 26.04.2011
      19              : ///
      20              : // Importer for networks stored in MATSim format
      21              : /****************************************************************************/
      22              : #include <config.h>
      23              : #include <set>
      24              : #include <functional>
      25              : #include <sstream>
      26              : #include <utils/xml/SUMOSAXHandler.h>
      27              : #include <utils/common/ToString.h>
      28              : #include <utils/common/MsgHandler.h>
      29              : #include <netbuild/NBEdge.h>
      30              : #include <netbuild/NBEdgeCont.h>
      31              : #include <netbuild/NBNode.h>
      32              : #include <netbuild/NBNodeCont.h>
      33              : #include <netbuild/NBNetBuilder.h>
      34              : #include <utils/geom/GeoConvHelper.h>
      35              : #include <utils/options/OptionsCont.h>
      36              : #include <utils/common/FileHelpers.h>
      37              : #include <utils/common/StringTokenizer.h>
      38              : #include <utils/common/StringUtils.h>
      39              : #include <utils/common/SUMOVehicleClass.h>
      40              : #include <utils/xml/XMLSubSys.h>
      41              : #include "NILoader.h"
      42              : #include "NIImporter_MATSim.h"
      43              : 
      44              : 
      45              : 
      46              : // ===========================================================================
      47              : // static variables
      48              : // ===========================================================================
      49              : SequentialStringBijection::Entry NIImporter_MATSim::matsimTags[] = {
      50              :     { "network",          NIImporter_MATSim::MATSIM_TAG_NETWORK },
      51              :     { "node",             NIImporter_MATSim::MATSIM_TAG_NODE },
      52              :     { "link",             NIImporter_MATSim::MATSIM_TAG_LINK },
      53              :     { "links",            NIImporter_MATSim::MATSIM_TAG_LINKS },
      54              :     { "",                 NIImporter_MATSim::MATSIM_TAG_NOTHING }
      55              : };
      56              : 
      57              : 
      58              : SequentialStringBijection::Entry NIImporter_MATSim::matsimAttrs[] = {
      59              :     { "id",             NIImporter_MATSim::MATSIM_ATTR_ID },
      60              :     { "x",              NIImporter_MATSim::MATSIM_ATTR_X },
      61              :     { "y",              NIImporter_MATSim::MATSIM_ATTR_Y },
      62              :     { "from",           NIImporter_MATSim::MATSIM_ATTR_FROM },
      63              :     { "to",             NIImporter_MATSim::MATSIM_ATTR_TO },
      64              :     { "length",         NIImporter_MATSim::MATSIM_ATTR_LENGTH },
      65              :     { "freespeed",      NIImporter_MATSim::MATSIM_ATTR_FREESPEED },
      66              :     { "capacity",       NIImporter_MATSim::MATSIM_ATTR_CAPACITY },
      67              :     { "permlanes",      NIImporter_MATSim::MATSIM_ATTR_PERMLANES },
      68              :     { "oneway",         NIImporter_MATSim::MATSIM_ATTR_ONEWAY },
      69              :     { "modes",          NIImporter_MATSim::MATSIM_ATTR_MODES },
      70              :     { "origid",         NIImporter_MATSim::MATSIM_ATTR_ORIGID },
      71              :     { "capperiod",      NIImporter_MATSim::MATSIM_ATTR_CAPPERIOD },
      72              :     { "capDivider",     NIImporter_MATSim::MATSIM_ATTR_CAPDIVIDER },
      73              : 
      74              :     { "",               NIImporter_MATSim::MATSIM_ATTR_NOTHING }
      75              : };
      76              : 
      77              : 
      78              : // ===========================================================================
      79              : // method definitions
      80              : // ===========================================================================
      81              : // ---------------------------------------------------------------------------
      82              : // static methods
      83              : // ---------------------------------------------------------------------------
      84              : void
      85         1892 : NIImporter_MATSim::loadNetwork(const OptionsCont& oc, NBNetBuilder& nb) {
      86              :     // check whether the option is set properly and all files exist
      87         3784 :     if (!oc.isUsableFileList("matsim-files")) {
      88         1883 :         return;
      89              :     }
      90              :     /* Parse file(s)
      91              :      * Each file is parsed twice: first for nodes, second for edges. */
      92           18 :     const std::vector<std::string> files = oc.getStringVector("matsim-files");
      93              :     // load nodes, first
      94            9 :     NodesHandler nodesHandler(nb.getNodeCont());
      95           18 :     for (const std::string& file : files) {
      96            9 :         nodesHandler.setFileName(file);
      97           27 :         PROGRESS_BEGIN_MESSAGE("Parsing nodes from matsim-file '" + file + "'");
      98            9 :         if (!XMLSubSys::runParser(nodesHandler, file, false, false, true)) {
      99              :             return;
     100              :         }
     101            9 :         PROGRESS_DONE_MESSAGE();
     102              :     }
     103              :     // load edges, then
     104           18 :     EdgesHandler edgesHandler(nb.getNodeCont(), nb.getEdgeCont(), oc.getBool("matsim.keep-length"),
     105           27 :                               oc.getBool("matsim.lanes-from-capacity"), NBCapacity2Lanes(oc.getFloat("lanes-from-capacity.norm")));
     106           18 :     for (const std::string& file : files) {
     107            9 :         edgesHandler.setFileName(file);
     108           27 :         PROGRESS_BEGIN_MESSAGE("Parsing edges from matsim-file '" + file + "'");
     109            9 :         XMLSubSys::runParser(edgesHandler, file, false, false, true);
     110            9 :         PROGRESS_DONE_MESSAGE();
     111              :     }
     112            9 : }
     113              : 
     114              : 
     115              : // ---------------------------------------------------------------------------
     116              : // definitions of NIImporter_MATSim::NodesHandler-methods
     117              : // ---------------------------------------------------------------------------
     118            9 : NIImporter_MATSim::NodesHandler::NodesHandler(NBNodeCont& toFill)
     119              :     : GenericSAXHandler(matsimTags, MATSIM_TAG_NOTHING,
     120              :                         matsimAttrs, MATSIM_ATTR_NOTHING,
     121           18 :                         "matsim - file"), myNodeCont(toFill) {
     122            9 : }
     123              : 
     124              : 
     125            9 : NIImporter_MATSim::NodesHandler::~NodesHandler() {}
     126              : 
     127              : 
     128              : void
     129          599 : NIImporter_MATSim::NodesHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {
     130          599 :     if (element != MATSIM_TAG_NODE) {
     131          404 :         return;
     132              :     }
     133              :     // get the id, report a warning if not given or empty...
     134          195 :     bool ok = true;
     135          390 :     const std::string id = SUMOXMLDefinitions::makeValidID(attrs.get<std::string>(MATSIM_ATTR_ID, nullptr, ok));
     136          195 :     const double x = attrs.get<double>(MATSIM_ATTR_X, id.c_str(), ok);
     137          195 :     const double y = attrs.get<double>(MATSIM_ATTR_Y, id.c_str(), ok);
     138          195 :     if (!ok) {
     139              :         return;
     140              :     }
     141              :     Position pos(x, y);
     142          195 :     if (!NBNetBuilder::transformCoordinate(pos)) {
     143            0 :         WRITE_ERRORF(TL("Unable to project coordinates for node '%'."), id);
     144              :     }
     145          195 :     NBNode* node = new NBNode(id, pos);
     146          195 :     if (!myNodeCont.insert(node)) {
     147            0 :         delete node;
     148            0 :         WRITE_ERRORF(TL("Could not add node '%'. Probably declared twice."), id);
     149              :     }
     150              : }
     151              : 
     152              : 
     153              : 
     154              : // ---------------------------------------------------------------------------
     155              : // definitions of NIImporter_MATSim::EdgesHandler-methods
     156              : // ---------------------------------------------------------------------------
     157            9 : NIImporter_MATSim::EdgesHandler::EdgesHandler(NBNodeCont& nc, NBEdgeCont& toFill,
     158              :         bool keepEdgeLengths, bool lanesFromCapacity,
     159            9 :         NBCapacity2Lanes capacity2Lanes)
     160              :     : GenericSAXHandler(matsimTags, MATSIM_TAG_NOTHING,
     161              :                         matsimAttrs, MATSIM_ATTR_NOTHING, "matsim - file"),
     162            9 :       myNodeCont(nc), myEdgeCont(toFill), myCapacityNorm(3600),
     163            9 :       myKeepEdgeLengths(keepEdgeLengths), myLanesFromCapacity(lanesFromCapacity),
     164           18 :       myCapacity2Lanes(capacity2Lanes) {
     165            9 : }
     166              : 
     167              : 
     168            9 : NIImporter_MATSim::EdgesHandler::~EdgesHandler() {
     169            9 : }
     170              : 
     171              : 
     172              : void
     173          378 : NIImporter_MATSim::EdgesHandler::insertEdge(const std::string& id, NBNode* fromNode, NBNode* toNode, double freeSpeed, int numLanes, double capacity, double length, SVCPermissions perm) {
     174          756 :     NBEdge* edge = new NBEdge(id, fromNode, toNode, "", freeSpeed, NBEdge::UNSPECIFIED_FRICTION, numLanes, -1, NBEdge::UNSPECIFIED_WIDTH, NBEdge::UNSPECIFIED_OFFSET, LaneSpreadFunction::RIGHT);
     175          756 :     edge->setParameter("capacity", toString(capacity));
     176          378 :     edge->setPermissions(perm, -1);
     177          378 :     if (myKeepEdgeLengths) {
     178           46 :         edge->setLoadedLength(length);
     179              :     }
     180          378 :     if (!myEdgeCont.insert(edge)) {
     181            0 :         delete edge;
     182            0 :         WRITE_ERRORF(TL("Could not add edge '%'. Probably declared twice."), id);
     183              :     }
     184          378 : }
     185              : 
     186              : 
     187              : SVCPermissions
     188          378 : NIImporter_MATSim::EdgesHandler::computePermission(std::string modes) {
     189              :     // using the MATSim modes from org.matsim.api.core.v01.TransportMode
     190          378 :     if (modes.size() == 0) {
     191          355 :         return SVCAll;
     192              :     }
     193              :     SVCPermissions result(SVC_IGNORING);
     194           69 :     for (StringTokenizer st(modes); st.hasNext();) {
     195           23 :         std::string mode = st.next();
     196           23 :         if (mode == "car") {
     197           23 :             result |= SVC_PASSENGER;
     198            0 :         } else if (mode == "bike") {
     199            0 :             result |= SVC_BICYCLE;
     200            0 :         } else if (mode == "motorcycle") {
     201            0 :             result |= SVC_MOTORCYCLE | SVC_MOPED;
     202            0 :         } else if (mode == "truck") {
     203            0 :             result |= SVC_TRUCK | SVC_TRAILER;
     204            0 :         } else if (mode == "pt") {
     205            0 :             result |= SVC_BUS | SVC_TRAM;
     206            0 :         } else if (mode == "drt" || mode == "taxi") {
     207            0 :             result |= SVC_TAXI;
     208            0 :         } else if (mode == "walk" || mode == "transit_walk") {
     209            0 :             result |= SVC_PEDESTRIAN;
     210            0 :         } else if (mode == "train") {
     211            0 :             result |= SVC_RAIL_CLASSES;
     212            0 :         } else if (mode == "ship") {
     213            0 :             result |= SVC_SHIP;
     214              :         }
     215           23 :     }
     216           23 :     return result;
     217              : }
     218              : 
     219              : 
     220              : void
     221          599 : NIImporter_MATSim::EdgesHandler::myStartElement(int element,
     222              :         const SUMOSAXAttributes& attrs) {
     223          599 :     if (element == MATSIM_TAG_NETWORK) {
     224            9 :         if (attrs.hasAttribute(MATSIM_ATTR_CAPDIVIDER)) {
     225            0 :             bool ok = true;
     226            0 :             int capDivider = attrs.get<int>(MATSIM_ATTR_CAPDIVIDER, "network", ok);
     227            0 :             if (ok) {
     228            0 :                 myCapacityNorm = (double)(capDivider * 3600);
     229              :             }
     230              :         }
     231              :     }
     232          599 :     if (element == MATSIM_TAG_LINKS) {
     233            9 :         bool ok = true;
     234            9 :         std::string capperiod = attrs.get<std::string>(MATSIM_ATTR_CAPPERIOD, "links", ok);
     235           27 :         StringTokenizer st(capperiod, ":");
     236            9 :         if (st.size() != 3) {
     237            0 :             WRITE_ERROR(TL("Bogus capacity period format; requires 'hh:mm:ss'."));
     238            0 :             return;
     239              :         }
     240              :         try {
     241            9 :             int hours = StringUtils::toInt(st.next());
     242            9 :             int minutes = StringUtils::toInt(st.next());
     243            9 :             int seconds = StringUtils::toInt(st.next());
     244            9 :             myCapacityNorm = (double)(hours * 3600 + minutes * 60 + seconds);
     245            0 :         } catch (NumberFormatException&) {
     246            0 :         } catch (EmptyData&) {
     247            0 :         }
     248            9 :         return;
     249            9 :     }
     250              : 
     251              :     // parse "link" elements
     252          590 :     if (element != MATSIM_TAG_LINK) {
     253              :         return;
     254              :     }
     255          377 :     bool ok = true;
     256          754 :     const std::string id = SUMOXMLDefinitions::makeValidID(attrs.get<std::string>(MATSIM_ATTR_ID, nullptr, ok));
     257          754 :     const std::string fromNodeID = SUMOXMLDefinitions::makeValidID(attrs.get<std::string>(MATSIM_ATTR_FROM, id.c_str(), ok));
     258          754 :     const std::string toNodeID = SUMOXMLDefinitions::makeValidID(attrs.get<std::string>(MATSIM_ATTR_TO, id.c_str(), ok));
     259          377 :     const double length = attrs.get<double>(MATSIM_ATTR_LENGTH, id.c_str(), ok); // override computed?
     260          377 :     const double freeSpeed = attrs.get<double>(MATSIM_ATTR_FREESPEED, id.c_str(), ok); //
     261          377 :     const double capacity = attrs.get<double>(MATSIM_ATTR_CAPACITY, id.c_str(), ok); // override permLanes?
     262          377 :     double permLanes = attrs.get<double>(MATSIM_ATTR_PERMLANES, id.c_str(), ok);
     263              :     //bool oneWay = attrs.getOpt<bool>(MATSIM_ATTR_ONEWAY, id.c_str(), ok, true); // mandatory?
     264          377 :     const std::string modes = attrs.getOpt<std::string>(MATSIM_ATTR_MODES, id.c_str(), ok, "");
     265          377 :     const std::string origid = attrs.getOpt<std::string>(MATSIM_ATTR_ORIGID, id.c_str(), ok, "");
     266          377 :     NBNode* fromNode = myNodeCont.retrieve(fromNodeID);
     267          377 :     NBNode* toNode = myNodeCont.retrieve(toNodeID);
     268          377 :     if (fromNode == nullptr) {
     269            0 :         WRITE_ERRORF(TL("Could not find from-node for edge '%'."), id);
     270              :     }
     271          377 :     if (toNode == nullptr) {
     272            0 :         WRITE_ERRORF(TL("Could not find to-node for edge '%'."), id);
     273              :     }
     274          377 :     if (fromNode == nullptr || toNode == nullptr) {
     275              :         return;
     276              :     }
     277          377 :     if (myLanesFromCapacity) {
     278           46 :         permLanes = myCapacity2Lanes.get(capacity);
     279              :     }
     280          377 :     if (permLanes < 0.5) {
     281            0 :         WRITE_WARNINGF(TL("Ignoring edge % which has no lanes."), id);
     282            0 :         return;
     283              :     }
     284          377 :     if (fromNode == toNode) {
     285              :         // adding node and edge with a different naming scheme to keep the original edge id for easier route repair
     286            2 :         NBNode* intermediate = new NBNode(id + ".0", toNode->getPosition() + Position(POSITION_EPS, POSITION_EPS));
     287            1 :         if (myNodeCont.insert(intermediate)) {
     288            2 :             insertEdge(id + ".0", intermediate, toNode, freeSpeed, (int)(permLanes + 0.5), capacity, length, computePermission(modes));
     289              :             toNode = intermediate;
     290              :         } else {
     291            0 :             delete intermediate;
     292            0 :             WRITE_ERRORF(TL("Could not add intermediate node to split loop edge '%'."), id);
     293              :         }
     294              :     }
     295          754 :     insertEdge(id, fromNode, toNode, freeSpeed, (int)(permLanes + 0.5), capacity, length, computePermission(modes));
     296              : }
     297              : 
     298              : 
     299              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1