LCOV - code coverage report
Current view: top level - src/netimport - NIImporter_MATSim.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 95 129 73.6 %
Date: 2024-05-02 15:31:40 Functions: 9 11 81.8 %

          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             : StringBijection<int>::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             : StringBijection<int>::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        2224 : NIImporter_MATSim::loadNetwork(const OptionsCont& oc, NBNetBuilder& nb) {
      86             :     // check whether the option is set properly and all files exist
      87        4448 :     if (!oc.isUsableFileList("matsim-files")) {
      88        2214 :         return;
      89             :     }
      90             :     /* Parse file(s)
      91             :      * Each file is parsed twice: first for nodes, second for edges. */
      92          20 :     const std::vector<std::string> files = oc.getStringVector("matsim-files");
      93             :     // load nodes, first
      94          10 :     NodesHandler nodesHandler(nb.getNodeCont());
      95          20 :     for (const std::string& file : files) {
      96          10 :         nodesHandler.setFileName(file);
      97          20 :         PROGRESS_BEGIN_MESSAGE("Parsing nodes from matsim-file '" + file + "'");
      98          10 :         if (!XMLSubSys::runParser(nodesHandler, file, false, false, true)) {
      99             :             return;
     100             :         }
     101          10 :         PROGRESS_DONE_MESSAGE();
     102             :     }
     103             :     // load edges, then
     104          20 :     EdgesHandler edgesHandler(nb.getNodeCont(), nb.getEdgeCont(), oc.getBool("matsim.keep-length"),
     105          40 :                               oc.getBool("matsim.lanes-from-capacity"), NBCapacity2Lanes(oc.getFloat("lanes-from-capacity.norm")));
     106          20 :     for (const std::string& file : files) {
     107          10 :         edgesHandler.setFileName(file);
     108          20 :         PROGRESS_BEGIN_MESSAGE("Parsing edges from matsim-file '" + file + "'");
     109          10 :         XMLSubSys::runParser(edgesHandler, file, false, false, true);
     110          10 :         PROGRESS_DONE_MESSAGE();
     111             :     }
     112          10 : }
     113             : 
     114             : 
     115             : // ---------------------------------------------------------------------------
     116             : // definitions of NIImporter_MATSim::NodesHandler-methods
     117             : // ---------------------------------------------------------------------------
     118          10 : NIImporter_MATSim::NodesHandler::NodesHandler(NBNodeCont& toFill)
     119             :     : GenericSAXHandler(matsimTags, MATSIM_TAG_NOTHING,
     120             :                         matsimAttrs, MATSIM_ATTR_NOTHING,
     121          20 :                         "matsim - file"), myNodeCont(toFill) {
     122          10 : }
     123             : 
     124             : 
     125          10 : NIImporter_MATSim::NodesHandler::~NodesHandler() {}
     126             : 
     127             : 
     128             : void
     129         868 : NIImporter_MATSim::NodesHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {
     130         868 :     if (element != MATSIM_TAG_NODE) {
     131         598 :         return;
     132             :     }
     133             :     // get the id, report a warning if not given or empty...
     134         270 :     bool ok = true;
     135         270 :     std::string id = attrs.get<std::string>(MATSIM_ATTR_ID, nullptr, ok);
     136         270 :     double x = attrs.get<double>(MATSIM_ATTR_X, id.c_str(), ok);
     137         270 :     double y = attrs.get<double>(MATSIM_ATTR_Y, id.c_str(), ok);
     138         270 :     if (!ok) {
     139             :         return;
     140             :     }
     141             :     Position pos(x, y);
     142         270 :     if (!NBNetBuilder::transformCoordinate(pos)) {
     143           0 :         WRITE_ERRORF(TL("Unable to project coordinates for node '%'."), id);
     144             :     }
     145         270 :     NBNode* node = new NBNode(id, pos);
     146         270 :     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          10 : NIImporter_MATSim::EdgesHandler::EdgesHandler(NBNodeCont& nc, NBEdgeCont& toFill,
     158             :         bool keepEdgeLengths, bool lanesFromCapacity,
     159          10 :         NBCapacity2Lanes capacity2Lanes)
     160             :     : GenericSAXHandler(matsimTags, MATSIM_TAG_NOTHING,
     161             :                         matsimAttrs, MATSIM_ATTR_NOTHING, "matsim - file"),
     162          10 :       myNodeCont(nc), myEdgeCont(toFill), myCapacityNorm(3600),
     163          10 :       myKeepEdgeLengths(keepEdgeLengths), myLanesFromCapacity(lanesFromCapacity),
     164          20 :       myCapacity2Lanes(capacity2Lanes) {
     165          10 : }
     166             : 
     167             : 
     168          10 : NIImporter_MATSim::EdgesHandler::~EdgesHandler() {
     169          10 : }
     170             : 
     171             : 
     172             : void
     173         569 : NIImporter_MATSim::EdgesHandler::insertEdge(const std::string& id, NBNode* fromNode, NBNode* toNode, double freeSpeed, int numLanes, double capacity, double length, SVCPermissions perm) {
     174        1138 :     NBEdge* edge = new NBEdge(id, fromNode, toNode, "", freeSpeed, NBEdge::UNSPECIFIED_FRICTION, numLanes, -1, NBEdge::UNSPECIFIED_WIDTH, NBEdge::UNSPECIFIED_OFFSET, LaneSpreadFunction::RIGHT);
     175        1138 :     edge->setParameter("capacity", toString(capacity));
     176         569 :     edge->setPermissions(perm, -1);
     177         569 :     if (myKeepEdgeLengths) {
     178          46 :         edge->setLoadedLength(length);
     179             :     }
     180         569 :     if (!myEdgeCont.insert(edge)) {
     181           0 :         delete edge;
     182           0 :         WRITE_ERRORF(TL("Could not add edge '%'. Probably declared twice."), id);
     183             :     }
     184         569 : }
     185             : 
     186             : 
     187             : SVCPermissions
     188         569 : NIImporter_MATSim::EdgesHandler::computePermission(std::string modes) {
     189             :     // using the MATSim modes from org.matsim.api.core.v01.TransportMode
     190         569 :     if (modes.size() == 0) {
     191         546 :         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         868 : NIImporter_MATSim::EdgesHandler::myStartElement(int element,
     222             :         const SUMOSAXAttributes& attrs) {
     223         868 :     if (element == MATSIM_TAG_NETWORK) {
     224          10 :         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         868 :     if (element == MATSIM_TAG_LINKS) {
     233          10 :         bool ok = true;
     234          10 :         std::string capperiod = attrs.get<std::string>(MATSIM_ATTR_CAPPERIOD, "links", ok);
     235          30 :         StringTokenizer st(capperiod, ":");
     236          10 :         if (st.size() != 3) {
     237           0 :             WRITE_ERROR(TL("Bogus capacity period format; requires 'hh:mm:ss'."));
     238           0 :             return;
     239             :         }
     240             :         try {
     241          10 :             int hours = StringUtils::toInt(st.next());
     242          10 :             int minutes = StringUtils::toInt(st.next());
     243          10 :             int seconds = StringUtils::toInt(st.next());
     244          10 :             myCapacityNorm = (double)(hours * 3600 + minutes * 60 + seconds);
     245           0 :         } catch (NumberFormatException&) {
     246           0 :         } catch (EmptyData&) {
     247           0 :         }
     248          10 :         return;
     249          10 :     }
     250             : 
     251             :     // parse "link" elements
     252         858 :     if (element != MATSIM_TAG_LINK) {
     253             :         return;
     254             :     }
     255         568 :     bool ok = true;
     256         568 :     std::string id = attrs.get<std::string>(MATSIM_ATTR_ID, nullptr, ok);
     257         568 :     std::string fromNodeID = attrs.get<std::string>(MATSIM_ATTR_FROM, id.c_str(), ok);
     258         568 :     std::string toNodeID = attrs.get<std::string>(MATSIM_ATTR_TO, id.c_str(), ok);
     259         568 :     double length = attrs.get<double>(MATSIM_ATTR_LENGTH, id.c_str(), ok); // override computed?
     260         568 :     double freeSpeed = attrs.get<double>(MATSIM_ATTR_FREESPEED, id.c_str(), ok); //
     261         568 :     double capacity = attrs.get<double>(MATSIM_ATTR_CAPACITY, id.c_str(), ok); // override permLanes?
     262         568 :     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         568 :     std::string modes = attrs.getOpt<std::string>(MATSIM_ATTR_MODES, id.c_str(), ok, "");
     265         568 :     std::string origid = attrs.getOpt<std::string>(MATSIM_ATTR_ORIGID, id.c_str(), ok, "");
     266         568 :     NBNode* fromNode = myNodeCont.retrieve(fromNodeID);
     267         568 :     NBNode* toNode = myNodeCont.retrieve(toNodeID);
     268         568 :     if (fromNode == nullptr) {
     269           0 :         WRITE_ERRORF(TL("Could not find from-node for edge '%'."), id);
     270             :     }
     271         568 :     if (toNode == nullptr) {
     272           0 :         WRITE_ERRORF(TL("Could not find to-node for edge '%'."), id);
     273             :     }
     274         568 :     if (fromNode == nullptr || toNode == nullptr) {
     275             :         return;
     276             :     }
     277         568 :     if (myLanesFromCapacity) {
     278          46 :         permLanes = myCapacity2Lanes.get(capacity);
     279             :     }
     280         568 :     if (fromNode == toNode) {
     281             :         // adding node and edge with a different naming scheme to keep the original edge id for easier route repair
     282           1 :         NBNode* intermediate = new NBNode(id + ".0", toNode->getPosition() + Position(POSITION_EPS, POSITION_EPS));
     283           1 :         if (myNodeCont.insert(intermediate)) {
     284           2 :             insertEdge(id + ".0", intermediate, toNode, freeSpeed, (int)(permLanes + 0.5), capacity, length, computePermission(modes));
     285             :             toNode = intermediate;
     286             :         } else {
     287           0 :             delete intermediate;
     288           0 :             WRITE_ERRORF(TL("Could not add intermediate node to split loop edge '%'."), id);
     289             :         }
     290             :     }
     291        1136 :     insertEdge(id, fromNode, toNode, freeSpeed, (int)(permLanes + 0.5), capacity, length, computePermission(modes));
     292             : }
     293             : 
     294             : 
     295             : /****************************************************************************/

Generated by: LCOV version 1.14