LCOV - code coverage report
Current view: top level - src/netimport - NIXMLEdgesHandler.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 91.8 % 416 382
Test Date: 2025-11-13 15:38:19 Functions: 92.3 % 13 12

            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    NIXMLEdgesHandler.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Jakob Erdmann
      17              : /// @author  Michael Behrisch
      18              : /// @author  Walter Bamberger
      19              : /// @author  Laura Bieker
      20              : /// @author  Leonhard Luecken
      21              : /// @date    Tue, 20 Nov 2001
      22              : ///
      23              : // Importer for network edges stored in XML
      24              : /****************************************************************************/
      25              : #include <config.h>
      26              : 
      27              : #include <string>
      28              : #include <iostream>
      29              : #include <map>
      30              : #include <cmath>
      31              : #include <utils/xml/SUMOSAXHandler.h>
      32              : #include <netbuild/NBNodeCont.h>
      33              : #include <netbuild/NBTypeCont.h>
      34              : #include <netbuild/NBNetBuilder.h>
      35              : #include <utils/xml/SUMOXMLDefinitions.h>
      36              : #include <utils/common/MsgHandler.h>
      37              : #include <utils/common/StringUtils.h>
      38              : #include <utils/common/StringTokenizer.h>
      39              : #include <utils/geom/GeomConvHelper.h>
      40              : #include <utils/common/ToString.h>
      41              : #include <utils/options/OptionsCont.h>
      42              : #include <utils/geom/GeoConvHelper.h>
      43              : #include "NIXMLNodesHandler.h"
      44              : #include "NIXMLEdgesHandler.h"
      45              : #include "NIImporter_SUMO.h"
      46              : 
      47              : 
      48              : // ===========================================================================
      49              : // method definitions
      50              : // ===========================================================================
      51         2001 : NIXMLEdgesHandler::NIXMLEdgesHandler(NBNodeCont& nc,
      52              :                                      NBEdgeCont& ec,
      53              :                                      NBTypeCont& tc,
      54              :                                      NBDistrictCont& dc,
      55              :                                      NBTrafficLightLogicCont& tlc,
      56         2001 :                                      OptionsCont& options) :
      57              :     SUMOSAXHandler("xml-edges - file"),
      58         2001 :     myOptions(options),
      59         2001 :     myNodeCont(nc),
      60         2001 :     myEdgeCont(ec),
      61         2001 :     myTypeCont(tc),
      62         2001 :     myDistrictCont(dc),
      63         2001 :     myTLLogicCont(tlc),
      64         2001 :     myCurrentEdge(nullptr),
      65         2001 :     myCurrentLaneIndex(-1),
      66         2001 :     myHaveReportedAboutOverwriting(false),
      67         2001 :     myHaveReportedAboutTypeOverride(false),
      68         2001 :     myHaveWarnedAboutDeprecatedLaneId(false),
      69         4002 :     myKeepEdgeShape(!options.getBool("plain.extend-edge-shape")) {
      70         2001 : }
      71              : 
      72              : 
      73         2001 : NIXMLEdgesHandler::~NIXMLEdgesHandler() {
      74         2001 :     delete myLocation;
      75         2001 : }
      76              : 
      77              : 
      78              : void
      79        28459 : NIXMLEdgesHandler::myStartElement(int element,
      80              :                                   const SUMOSAXAttributes& attrs) {
      81        28459 :     switch (element) {
      82              :         case SUMO_TAG_VIEWSETTINGS_EDGES:
      83              :             // infer location for legacy networks that don't have location information
      84         1132 :             myLocation = GeoConvHelper::getLoadedPlain(getFileName());
      85         1132 :             break;
      86           26 :         case SUMO_TAG_LOCATION:
      87           26 :             delete myLocation;
      88           26 :             myLocation = NIImporter_SUMO::loadLocation(attrs, false);
      89           26 :             break;
      90        18982 :         case SUMO_TAG_EDGE:
      91        18982 :             addEdge(attrs);
      92        18981 :             break;
      93         5888 :         case SUMO_TAG_LANE:
      94         5888 :             addLane(attrs);
      95         5888 :             break;
      96           16 :         case SUMO_TAG_NEIGH:
      97           16 :             myCurrentEdge->getLaneStruct((int)myCurrentEdge->getNumLanes() - 1).oppositeID = attrs.getString(SUMO_ATTR_LANE);
      98           16 :             break;
      99          216 :         case SUMO_TAG_SPLIT:
     100          216 :             addSplit(attrs);
     101          216 :             break;
     102           31 :         case SUMO_TAG_DEL:
     103           31 :             deleteEdge(attrs);
     104           31 :             break;
     105           11 :         case SUMO_TAG_ROUNDABOUT:
     106           11 :             addRoundabout(attrs);
     107           11 :             break;
     108         2132 :         case SUMO_TAG_PARAM:
     109         2132 :             if (myLastParameterised.size() != 0 && myCurrentEdge != nullptr) {
     110         2090 :                 bool ok = true;
     111         2090 :                 const std::string key = attrs.get<std::string>(SUMO_ATTR_KEY, nullptr, ok);
     112              :                 // circumventing empty string test
     113         2090 :                 const std::string val = attrs.hasAttribute(SUMO_ATTR_VALUE) ? attrs.getString(SUMO_ATTR_VALUE) : "";
     114         2090 :                 myLastParameterised.back()->setParameter(key, val);
     115              :             }
     116              :             break;
     117           25 :         case SUMO_TAG_STOPOFFSET: {
     118           25 :             bool ok = true;
     119           25 :             const StopOffset stopOffset(attrs, ok);
     120           25 :             if (!ok) {
     121            1 :                 std::stringstream ss;
     122            2 :                 ss << "(Error encountered at lane " << myCurrentLaneIndex << " of edge '" << myCurrentID << "' while parsing stopOffsets.)";
     123            1 :                 WRITE_ERROR(ss.str());
     124            1 :             } else {
     125           24 :                 if (myCurrentEdge->getLaneStopOffset(myCurrentLaneIndex).isDefined()) {
     126            3 :                     std::stringstream ss;
     127            3 :                     ss << "Duplicate definition of stopOffset for ";
     128            3 :                     if (myCurrentLaneIndex != -1) {
     129            1 :                         ss << "lane " << myCurrentLaneIndex << " on ";
     130              :                     }
     131            6 :                     ss << "edge " << myCurrentEdge->getID() << ". Ignoring duplicate specification.";
     132            3 :                     WRITE_WARNING(ss.str());
     133           24 :                 } else if ((stopOffset.getOffset() > myCurrentEdge->getLength()) || (stopOffset.getOffset() < 0)) {
     134            4 :                     std::stringstream ss;
     135            4 :                     ss << "Ignoring invalid stopOffset for ";
     136            4 :                     if (myCurrentLaneIndex != -1) {
     137            2 :                         ss << "lane " << myCurrentLaneIndex << " on ";
     138              :                     }
     139            4 :                     ss << "edge " << myCurrentEdge->getID();
     140            4 :                     if (stopOffset.getOffset() > myCurrentEdge->getLength()) {
     141            2 :                         ss << " (offset larger than the edge length).";
     142              :                     } else {
     143            2 :                         ss << " (negative offset).";
     144              :                     }
     145            4 :                     WRITE_WARNING(ss.str());
     146            4 :                 } else {
     147           17 :                     myCurrentEdge->setEdgeStopOffset(myCurrentLaneIndex, stopOffset);
     148              :                 }
     149              :             }
     150              :         }
     151           25 :         break;
     152              :         default:
     153              :             break;
     154              :     }
     155        28458 : }
     156              : 
     157              : 
     158              : void
     159        18982 : NIXMLEdgesHandler::addEdge(const SUMOSAXAttributes& attrs) {
     160        18982 :     myIsUpdate = false;
     161        18982 :     bool ok = true;
     162              :     // initialise the edge
     163        18982 :     myCurrentEdge = nullptr;
     164              :     mySplits.clear();
     165              :     // get the id, report an error if not given or empty...
     166        18982 :     myCurrentID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
     167        18982 :     if (!ok) {
     168           59 :         return;
     169              :     }
     170        18978 :     myCurrentEdge = myEdgeCont.retrieve(myCurrentID);
     171              :     // check deprecated (unused) attributes
     172              :     // use default values, first
     173        18978 :     myCurrentType = myOptions.getString("default.type");
     174        18978 :     myCurrentPriority = myTypeCont.getEdgeTypePriority(myCurrentType);
     175        18978 :     myCurrentLaneNo = myTypeCont.getEdgeTypeNumLanes(myCurrentType);
     176        18978 :     myCurrentEndOffset = NBEdge::UNSPECIFIED_OFFSET;
     177        18978 :     if (myCurrentEdge != nullptr) {
     178              :         // update existing edge. only update lane-specific settings when explicitly requested
     179         2124 :         myIsUpdate = true;
     180         2124 :         myCurrentSpeed = NBEdge::UNSPECIFIED_SPEED;
     181         2124 :         myCurrentFriction = NBEdge::UNSPECIFIED_FRICTION;
     182         2124 :         myPermissions = SVC_UNSPECIFIED;
     183         2124 :         myCurrentWidth = NBEdge::UNSPECIFIED_WIDTH;
     184              :         myCurrentType = myCurrentEdge->getTypeID();
     185         4248 :         myLanesSpread = SUMOXMLDefinitions::LaneSpreadFunctions.get(myOptions.getString("default.spreadtype"));
     186              :     } else {
     187              :         // this is a completely new edge. get the type specific defaults
     188        16854 :         myCurrentSpeed = myTypeCont.getEdgeTypeSpeed(myCurrentType);
     189        16854 :         myCurrentFriction = myTypeCont.getEdgeTypeFriction(myCurrentType);
     190        16854 :         myPermissions = myTypeCont.getEdgeTypePermissions(myCurrentType);
     191        16854 :         myCurrentWidth = myTypeCont.getEdgeTypeWidth(myCurrentType);
     192        16854 :         myLanesSpread = myTypeCont.getEdgeTypeSpreadType(myCurrentType);
     193              :     }
     194        37956 :     myShape = PositionVector();
     195        18978 :     myLength = NBEdge::UNSPECIFIED_LOADED_LENGTH;
     196        18978 :     myCurrentStreetName = "";
     197        18978 :     myReinitKeepEdgeShape = false;
     198        18978 :     mySidewalkWidth = NBEdge::UNSPECIFIED_WIDTH;
     199        18978 :     myBikeLaneWidth = NBEdge::UNSPECIFIED_WIDTH;
     200              :     // check whether a type's values shall be used
     201        18978 :     if (attrs.hasAttribute(SUMO_ATTR_TYPE)) {
     202         3189 :         myCurrentType = attrs.get<std::string>(SUMO_ATTR_TYPE, myCurrentID.c_str(), ok);
     203         3189 :         if (!ok) {
     204              :             return;
     205              :         }
     206         8702 :         if (!myTypeCont.knows(myCurrentType) && !myOptions.getBool("ignore-errors.edge-type")) {
     207           81 :             WRITE_ERRORF("Type '%' used by edge '%' was not defined (ignore with option --ignore-errors.edge-type).", myCurrentType, myCurrentID);
     208           27 :             return;
     209              :         }
     210         3160 :         myCurrentSpeed = myTypeCont.getEdgeTypeSpeed(myCurrentType);
     211         3160 :         myCurrentPriority = myTypeCont.getEdgeTypePriority(myCurrentType);
     212         3160 :         myCurrentLaneNo = myTypeCont.getEdgeTypeNumLanes(myCurrentType);
     213         3160 :         myPermissions = myTypeCont.getEdgeTypePermissions(myCurrentType);
     214         3160 :         myCurrentWidth = myTypeCont.getEdgeTypeWidth(myCurrentType);
     215         3160 :         myLanesSpread = myTypeCont.getEdgeTypeSpreadType(myCurrentType);
     216         3160 :         mySidewalkWidth = myTypeCont.getEdgeTypeSidewalkWidth(myCurrentType);
     217         3160 :         myBikeLaneWidth = myTypeCont.getEdgeTypeBikeLaneWidth(myCurrentType);
     218              :     }
     219              :     // use values from the edge to overwrite if existing, then
     220        18949 :     if (myIsUpdate) {
     221         2124 :         if (!myHaveReportedAboutOverwriting) {
     222          273 :             WRITE_MESSAGEF(TL("Duplicate edge id occurred ('%'); assuming overwriting is wished."), myCurrentID);
     223           91 :             myHaveReportedAboutOverwriting = true;
     224              :         }
     225         2124 :         if (attrs.hasAttribute(SUMO_ATTR_TYPE) && myCurrentType != myCurrentEdge->getTypeID()) {
     226            3 :             if (!myHaveReportedAboutTypeOverride) {
     227            6 :                 WRITE_MESSAGEF(TL("Edge '%' changed its type; assuming type override is wished."), myCurrentID);
     228            2 :                 myHaveReportedAboutTypeOverride = true;
     229              :             }
     230              :         }
     231         2124 :         if (attrs.getOpt<bool>(SUMO_ATTR_REMOVE, myCurrentID.c_str(), ok, false)) {
     232            0 :             myEdgeCont.erase(myDistrictCont, myCurrentEdge);
     233            0 :             myCurrentEdge = nullptr;
     234            0 :             return;
     235              :         }
     236         2124 :         myCurrentPriority = myCurrentEdge->getPriority();
     237         2124 :         myCurrentLaneNo = myCurrentEdge->getNumLanes();
     238         2124 :         if (!myCurrentEdge->hasDefaultGeometry()) {
     239         1652 :             myShape = myCurrentEdge->getGeometry();
     240         1652 :             myReinitKeepEdgeShape = true;
     241              :         }
     242         2124 :         myLanesSpread = myCurrentEdge->getLaneSpreadFunction();
     243         2124 :         if (myCurrentEdge->hasLoadedLength()) {
     244            1 :             myLength = myCurrentEdge->getLoadedLength();
     245              :         }
     246              :         myCurrentStreetName = myCurrentEdge->getStreetName();
     247              :     }
     248              :     // speed, priority and the number of lanes have now default values;
     249              :     // try to read the real values from the file
     250        18949 :     if (attrs.hasAttribute(SUMO_ATTR_SPEED)) {
     251        12498 :         myCurrentSpeed = attrs.get<double>(SUMO_ATTR_SPEED, myCurrentID.c_str(), ok);
     252              :     }
     253        37898 :     if (myOptions.getBool("speed-in-kmh") && myCurrentSpeed != NBEdge::UNSPECIFIED_SPEED) {
     254          689 :         myCurrentSpeed = myCurrentSpeed / (double) 3.6;
     255              :     }
     256              :     // try to read the friction value from file
     257        18949 :     if (attrs.hasAttribute(SUMO_ATTR_FRICTION)) {
     258            3 :         myCurrentFriction = attrs.get<double>(SUMO_ATTR_FRICTION, myCurrentID.c_str(), ok);
     259              :     }
     260              :     // try to get the number of lanes
     261        18949 :     if (attrs.hasAttribute(SUMO_ATTR_NUMLANES)) {
     262        12944 :         myCurrentLaneNo = attrs.get<int>(SUMO_ATTR_NUMLANES, myCurrentID.c_str(), ok);
     263              :     }
     264              :     // try to get the priority
     265        18949 :     if (attrs.hasAttribute(SUMO_ATTR_PRIORITY)) {
     266        10636 :         myCurrentPriority = attrs.get<int>(SUMO_ATTR_PRIORITY, myCurrentID.c_str(), ok);
     267              :     }
     268              :     // try to get the width
     269        18949 :     if (attrs.hasAttribute(SUMO_ATTR_WIDTH)) {
     270          647 :         myCurrentWidth = attrs.get<double>(SUMO_ATTR_WIDTH, myCurrentID.c_str(), ok);
     271              :     }
     272              :     // try to get the offset of the stop line from the intersection
     273        18949 :     if (attrs.hasAttribute(SUMO_ATTR_ENDOFFSET)) {
     274            9 :         myCurrentEndOffset = attrs.get<double>(SUMO_ATTR_ENDOFFSET, myCurrentID.c_str(), ok);
     275              :     }
     276              :     // try to get the street name
     277        18949 :     if (attrs.hasAttribute(SUMO_ATTR_NAME)) {
     278         1938 :         myCurrentStreetName = attrs.get<std::string>(SUMO_ATTR_NAME, myCurrentID.c_str(), ok);
     279         1938 :         if (myCurrentStreetName != "" && myOptions.isDefault("output.street-names")) {
     280          106 :             myOptions.set("output.street-names", "true");
     281              :         }
     282              :     }
     283              : 
     284              :     // try to get the allowed/disallowed classes
     285        18949 :     if (attrs.hasAttribute(SUMO_ATTR_ALLOW) || attrs.hasAttribute(SUMO_ATTR_DISALLOW)) {
     286         4759 :         std::string allowS = attrs.hasAttribute(SUMO_ATTR_ALLOW) ? attrs.getStringSecure(SUMO_ATTR_ALLOW, "") : "";
     287         4759 :         std::string disallowS = attrs.hasAttribute(SUMO_ATTR_DISALLOW) ? attrs.getStringSecure(SUMO_ATTR_DISALLOW, "") : "";
     288              :         // XXX matter of interpretation: should updated permissions replace or extend previously set permissions?
     289         4759 :         myPermissions = parseVehicleClasses(allowS, disallowS);
     290              :     }
     291              :     // try to set the nodes
     292        18949 :     if (!setNodes(attrs)) {
     293              :         // return if this failed
     294           13 :         myCurrentEdge = nullptr;
     295           13 :         return;
     296              :     }
     297              :     // try to get the shape
     298        37872 :     myShape = tryGetShape(attrs);
     299              :     // try to get the spread type
     300        18936 :     myLanesSpread = tryGetLaneSpread(attrs);
     301              :     // try to get the length
     302        18936 :     myLength = attrs.getOpt<double>(SUMO_ATTR_LENGTH, myCurrentID.c_str(), ok, myLength);
     303              :     // try to get the sidewalkWidth
     304        18936 :     mySidewalkWidth = attrs.getOpt<double>(SUMO_ATTR_SIDEWALKWIDTH, myCurrentID.c_str(), ok, mySidewalkWidth);
     305              :     // try to get the bikeLaneWidth
     306        18936 :     myBikeLaneWidth = attrs.getOpt<double>(SUMO_ATTR_BIKELANEWIDTH, myCurrentID.c_str(), ok, myBikeLaneWidth);
     307              :     // insert the parsed edge into the edges map
     308        18936 :     if (!ok) {
     309           10 :         myCurrentEdge = nullptr;
     310           10 :         return;
     311              :     }
     312        18926 :     if (myFromNode == myToNode) {
     313              :         // this might as well be an error. We make this a warning mostly for
     314              :         // backward compatibility
     315            9 :         WRITE_WARNINGF(TL("Ignoring self-looped edge '%' at junction '%'"), myCurrentID, myFromNode->getID());
     316            3 :         myCurrentEdge = nullptr;
     317            3 :         return;
     318              :     }
     319              :     // check whether a previously defined edge shall be overwritten
     320        18923 :     const bool applyLaneType = myCurrentEdge == nullptr;
     321        18923 :     if (myCurrentEdge != nullptr) {
     322         2123 :         myCurrentEdge->reinit(myFromNode, myToNode, myCurrentType, myCurrentSpeed, myCurrentFriction,
     323              :                               myCurrentLaneNo, myCurrentPriority, myShape,
     324              :                               myCurrentWidth, myCurrentEndOffset,
     325              :                               myCurrentStreetName, myLanesSpread,
     326         2123 :                               myReinitKeepEdgeShape);
     327              :     } else {
     328              :         // the edge must be allocated in dependence to whether a shape is given
     329        16800 :         if (myShape.size() == 0) {
     330        14219 :             myCurrentEdge = new NBEdge(myCurrentID, myFromNode, myToNode, myCurrentType, myCurrentSpeed, myCurrentFriction,
     331              :                                        myCurrentLaneNo, myCurrentPriority, myCurrentWidth, myCurrentEndOffset,
     332        42657 :                                        myLanesSpread, myCurrentStreetName);
     333              :         } else {
     334         2580 :             myCurrentEdge = new NBEdge(myCurrentID, myFromNode, myToNode, myCurrentType, myCurrentSpeed, myCurrentFriction,
     335              :                                        myCurrentLaneNo, myCurrentPriority, myCurrentWidth, myCurrentEndOffset,
     336              :                                        myShape, myLanesSpread, myCurrentStreetName, "",
     337         7745 :                                        myKeepEdgeShape);
     338              :         }
     339              :     }
     340        18922 :     myCurrentEdge->setLoadedLength(myLength);
     341        18922 :     if (myPermissions != SVC_UNSPECIFIED) {
     342        16822 :         myCurrentEdge->setPermissions(myPermissions);
     343              :     }
     344              :     // apply laneType if given
     345        18922 :     if (applyLaneType && myCurrentType != "" && myTypeCont.knows(myCurrentType)) {
     346          432 :         const NBTypeCont::EdgeTypeDefinition* eType = myTypeCont.getEdgeType(myCurrentType);
     347          432 :         if (eType->needsLaneType()) {
     348              :             int lane = 0;
     349          340 :             for (const NBTypeCont::LaneTypeDefinition& laneType : eType->laneTypeDefinitions) {
     350          236 :                 if (lane >= myCurrentLaneNo) {
     351              :                     break;
     352              :                 }
     353              :                 if (laneType.attrs.count(SUMO_ATTR_SPEED) > 0) {
     354          139 :                     myCurrentEdge->setSpeed(lane, laneType.speed);
     355              :                 }
     356              :                 if (laneType.attrs.count(SUMO_ATTR_FRICTION) > 0) {
     357            0 :                     myCurrentEdge->setFriction(lane, laneType.friction);
     358              :                 }
     359              :                 if (laneType.attrs.count(SUMO_ATTR_DISALLOW) > 0 || laneType.attrs.count(SUMO_ATTR_ALLOW) > 0) {
     360           54 :                     myCurrentEdge->setPermissions(laneType.permissions, lane);
     361              :                 }
     362              :                 if (laneType.attrs.count(SUMO_ATTR_WIDTH) > 0) {
     363          169 :                     myCurrentEdge->setLaneWidth(lane, laneType.width);
     364              :                 }
     365          236 :                 lane++;
     366              :             }
     367              :         }
     368              :     }
     369              :     // try to get the kilometrage/mileage
     370        18922 :     myCurrentEdge->setDistance(attrs.getOpt<double>(SUMO_ATTR_DISTANCE, myCurrentID.c_str(), ok, myCurrentEdge->getDistance()));
     371        18922 :     myCurrentEdge->setRoutingType(attrs.getOpt<std::string>(SUMO_ATTR_ROUTINGTYPE, myCurrentID.c_str(), ok, myCurrentEdge->getRoutingType()));
     372              :     // preserve bidi edge (only as bool, the actual edge will be recomputed)
     373        18922 :     const std::string bidi = attrs.getOpt<std::string>(SUMO_ATTR_BIDI, myCurrentID.c_str(), ok, "");
     374        18922 :     myCurrentEdge->setBidi(myCurrentEdge->getBidiEdge() != nullptr || myCurrentEdge->isBidi() || bidi != "");
     375              : 
     376        18922 :     myLastParameterised.push_back(myCurrentEdge);
     377              : }
     378              : 
     379              : 
     380              : void
     381         5888 : NIXMLEdgesHandler::addLane(const SUMOSAXAttributes& attrs) {
     382         5888 :     if (myCurrentEdge == nullptr) {
     383           58 :         if (!OptionsCont::getOptions().isInStringVector("remove-edges.explicit", myCurrentID)) {
     384           87 :             WRITE_ERRORF("Additional lane information could not be set - the edge with id '%s' is not known.", myCurrentID);
     385              :         }
     386           30 :         return;
     387              :     }
     388         5859 :     bool ok = true;
     389              :     int lane;
     390         5859 :     if (attrs.hasAttribute(SUMO_ATTR_ID)) {
     391            0 :         lane = attrs.get<int>(SUMO_ATTR_ID, myCurrentID.c_str(), ok);
     392            0 :         if (!myHaveWarnedAboutDeprecatedLaneId) {
     393            0 :             myHaveWarnedAboutDeprecatedLaneId = true;
     394            0 :             WRITE_WARNINGF(TL("'%' is deprecated, please use '%' instead."), toString(SUMO_ATTR_ID), toString(SUMO_ATTR_INDEX));
     395              :         }
     396              :     } else {
     397         5859 :         lane = attrs.get<int>(SUMO_ATTR_INDEX, myCurrentID.c_str(), ok);
     398              :     }
     399         5859 :     if (!ok) {
     400              :         return;
     401              :     }
     402              :     // check whether this lane exists
     403         5859 :     if (lane >= myCurrentEdge->getNumLanes()) {
     404            3 :         WRITE_ERRORF(TL("Lane index is larger than number of lanes (edge '%')."), myCurrentID);
     405            1 :         return;
     406              :     }
     407         5858 :     myCurrentLaneIndex = lane;
     408              :     // set information about allowed / disallowed vehicle classes (if specified)
     409         5858 :     if (attrs.hasAttribute(SUMO_ATTR_ALLOW) || attrs.hasAttribute(SUMO_ATTR_DISALLOW)) {
     410         4763 :         const std::string allowed = attrs.getOpt<std::string>(SUMO_ATTR_ALLOW, nullptr, ok, "");
     411         4763 :         const std::string disallowed = attrs.getOpt<std::string>(SUMO_ATTR_DISALLOW, nullptr, ok, "");
     412         4763 :         myCurrentEdge->setPermissions(parseVehicleClasses(allowed, disallowed), lane);
     413              :     }
     414         5858 :     if (attrs.hasAttribute(SUMO_ATTR_PREFER)) {
     415            0 :         const std::string preferred  = attrs.get<std::string>(SUMO_ATTR_PREFER, nullptr, ok);
     416            0 :         myCurrentEdge->setPreferredVehicleClass(parseVehicleClasses(preferred), lane);
     417              :     }
     418         5858 :     if (attrs.hasAttribute(SUMO_ATTR_CHANGE_LEFT) || attrs.hasAttribute(SUMO_ATTR_CHANGE_RIGHT)) {
     419           47 :         const std::string changeLeft = attrs.getOpt<std::string>(SUMO_ATTR_CHANGE_LEFT, nullptr, ok, "");
     420           47 :         const std::string changeRight = attrs.getOpt<std::string>(SUMO_ATTR_CHANGE_RIGHT, nullptr, ok, "");
     421           94 :         myCurrentEdge->setPermittedChanging(lane, parseVehicleClasses(changeLeft, ""), parseVehicleClasses(changeRight, ""));
     422              :     }
     423              :     // try to get the width
     424         5858 :     if (attrs.hasAttribute(SUMO_ATTR_WIDTH)) {
     425         1947 :         myCurrentEdge->setLaneWidth(lane, attrs.get<double>(SUMO_ATTR_WIDTH, myCurrentID.c_str(), ok));
     426              :     }
     427              :     // try to get the end-offset (lane shortened due to pedestrian crossing etc..)
     428         5858 :     if (attrs.hasAttribute(SUMO_ATTR_ENDOFFSET)) {
     429           18 :         myCurrentEdge->setEndOffset(lane, attrs.get<double>(SUMO_ATTR_ENDOFFSET, myCurrentID.c_str(), ok));
     430              :     }
     431              :     // try to get lane specific speed (should not occur for german networks)
     432         5858 :     if (attrs.hasAttribute(SUMO_ATTR_SPEED)) {
     433            9 :         myCurrentEdge->setSpeed(lane, attrs.get<double>(SUMO_ATTR_SPEED, myCurrentID.c_str(), ok));
     434              :     }
     435              :     // try to get lane specific friction
     436         5858 :     if (attrs.hasAttribute(SUMO_ATTR_FRICTION)) {
     437            4 :         myCurrentEdge->setFriction(lane, attrs.get<double>(SUMO_ATTR_FRICTION, myCurrentID.c_str(), ok));
     438              :     }
     439              :     // check whether this is an acceleration lane
     440         5858 :     if (attrs.hasAttribute(SUMO_ATTR_ACCELERATION)) {
     441            4 :         myCurrentEdge->setAcceleration(lane, attrs.get<bool>(SUMO_ATTR_ACCELERATION, myCurrentID.c_str(), ok));
     442              :     }
     443              :     // check whether this lane has a custom shape
     444         5858 :     if (attrs.hasAttribute(SUMO_ATTR_SHAPE)) {
     445           72 :         PositionVector shape = attrs.get<PositionVector>(SUMO_ATTR_SHAPE, myCurrentID.c_str(), ok);
     446           72 :         if (!NBNetBuilder::transformCoordinates(shape, true, myLocation)) {
     447            0 :             const std::string laneID = myCurrentID + "_" + toString(lane);
     448            0 :             WRITE_ERRORF(TL("Unable to project coordinates for lane '%'."), laneID);
     449              :         }
     450           72 :         if (shape.size() == 1) {
     451              :             // lane shape of length 1 is not permitted
     452            1 :             shape.push_front(myCurrentEdge->getFromNode()->getPosition());
     453            1 :             shape.push_back(myCurrentEdge->getToNode()->getPosition());
     454              :         }
     455           72 :         shape.removeDoublePoints();
     456           72 :         if (shape.size() < 2) {
     457              :             // ignore lane shape for very short lanes
     458              :             shape.clear();
     459              :         }
     460           72 :         myCurrentEdge->setLaneShape(lane, shape);
     461           72 :     }
     462              :     // set custom lane type
     463         5858 :     if (attrs.hasAttribute(SUMO_ATTR_TYPE)) {
     464           16 :         myCurrentEdge->setLaneType(lane, attrs.get<std::string>(SUMO_ATTR_TYPE, myCurrentID.c_str(), ok));
     465              :     }
     466         5858 :     myLastParameterised.push_back(&myCurrentEdge->getLaneStruct(lane));
     467              : }
     468              : 
     469              : 
     470          216 : void NIXMLEdgesHandler::addSplit(const SUMOSAXAttributes& attrs) {
     471          216 :     if (myCurrentEdge == nullptr) {
     472            0 :         if (!OptionsCont::getOptions().isInStringVector("remove-edges.explicit", myCurrentID)) {
     473            0 :             WRITE_WARNING(TL("Ignoring 'split' because it cannot be assigned to an edge"));
     474              :         }
     475            4 :         return;
     476              :     }
     477          216 :     bool ok = true;
     478              :     NBEdgeCont::Split e;
     479          216 :     e.pos = attrs.get<double>(SUMO_ATTR_POSITION, nullptr, ok);
     480          216 :     if (ok) {
     481          428 :         if (fabs(e.pos) > myCurrentEdge->getLoadedLength()) {
     482            3 :             WRITE_ERRORF(TL("Edge '%' has a split at invalid position %."), myCurrentID, toString(e.pos));
     483            1 :             return;
     484              :         }
     485          215 :         std::vector<NBEdgeCont::Split>::iterator i = find_if(mySplits.begin(), mySplits.end(), split_by_pos_finder(e.pos));
     486          215 :         if (i != mySplits.end()) {
     487            6 :             WRITE_ERRORF(TL("Edge '%' has already a split at position %."), myCurrentID, toString(e.pos));
     488            2 :             return;
     489              :         }
     490              :         // XXX rounding to int may duplicate the id of another split
     491          426 :         e.nameID = myCurrentID + "." + toString((int)e.pos);
     492          213 :         if (e.pos < 0) {
     493           35 :             e.pos += myCurrentEdge->getGeometry().length();
     494              :         }
     495          529 :         for (const std::string& id : attrs.getOpt<std::vector<std::string> >(SUMO_ATTR_LANES, myCurrentID.c_str(), ok)) {
     496              :             try {
     497          316 :                 int lane = StringUtils::toInt(id);
     498          314 :                 e.lanes.push_back(lane);
     499            2 :             } catch (NumberFormatException&) {
     500            6 :                 WRITE_ERRORF(TL("Error on parsing a split (edge '%')."), myCurrentID);
     501            2 :             } catch (EmptyData&) {
     502            0 :                 WRITE_ERRORF(TL("Error on parsing a split (edge '%')."), myCurrentID);
     503            0 :             }
     504          213 :         }
     505          213 :         if (e.lanes.empty()) {
     506          177 :             for (int l = 0; l < myCurrentEdge->getNumLanes(); ++l) {
     507          110 :                 e.lanes.push_back(l);
     508              :             }
     509              :         }
     510          213 :         e.speed = attrs.getOpt(SUMO_ATTR_SPEED, nullptr, ok, myCurrentEdge->getSpeed());
     511          217 :         if (attrs.hasAttribute(SUMO_ATTR_SPEED) && myOptions.getBool("speed-in-kmh")) {
     512            0 :             e.speed /= 3.6;
     513              :         }
     514          213 :         e.idBefore = attrs.getOpt(SUMO_ATTR_ID_BEFORE, nullptr, ok, std::string(""));
     515          213 :         e.idAfter = attrs.getOpt(SUMO_ATTR_ID_AFTER, nullptr, ok, std::string(""));
     516          213 :         if (!ok) {
     517              :             return;
     518              :         }
     519          213 :         const std::string nodeID = attrs.getOpt(SUMO_ATTR_ID, nullptr, ok, e.nameID);
     520          213 :         if (nodeID == myCurrentEdge->getFromNode()->getID() || nodeID == myCurrentEdge->getToNode()->getID()) {
     521            3 :             WRITE_ERRORF(TL("Invalid split node id for edge '%' (from- and to-node are forbidden)"), myCurrentEdge->getID());
     522              :             return;
     523              :         }
     524          212 :         e.node = myNodeCont.retrieve(nodeID);
     525          212 :         e.offset = attrs.getOpt(SUMO_ATTR_OFFSET, nullptr, ok, 0.0);
     526          423 :         e.offsetFactor = OptionsCont::getOptions().getBool("lefthand") ? -1 : 1;
     527          212 :         if (e.node == nullptr) {
     528          202 :             double geomPos = e.pos;
     529          202 :             if (myCurrentEdge->hasLoadedLength()) {
     530            4 :                 geomPos *= myCurrentEdge->getGeometry().length() / myCurrentEdge->getLoadedLength();
     531              :             }
     532          202 :             e.node = new NBNode(nodeID, myCurrentEdge->getGeometry().positionAtOffset(geomPos));
     533          202 :             myNodeCont.insert(e.node);
     534              :         }
     535          212 :         NIXMLNodesHandler::processNodeType(attrs, e.node, e.node->getID(), e.node->getPosition(), false,
     536              :                                            myNodeCont, myEdgeCont, myTLLogicCont, myLocation);
     537          212 :         mySplits.push_back(e);
     538              :     }
     539          216 : }
     540              : 
     541              : 
     542              : bool
     543        18949 : NIXMLEdgesHandler::setNodes(const SUMOSAXAttributes& attrs) {
     544              :     // the names and the coordinates of the beginning and the end node
     545              :     // may be found, try
     546        18949 :     bool ok = true;
     547        18949 :     if (myIsUpdate) {
     548         2124 :         myFromNode = myCurrentEdge->getFromNode();
     549         2124 :         myToNode = myCurrentEdge->getToNode();
     550              :     }
     551        18949 :     if (attrs.hasAttribute(SUMO_ATTR_FROM)) {
     552        16853 :         const std::string begNodeID = attrs.get<std::string>(SUMO_ATTR_FROM, nullptr, ok);
     553        16853 :         if (begNodeID != "") {
     554        16851 :             myFromNode = myNodeCont.retrieve(begNodeID);
     555        16851 :             if (myFromNode == nullptr) {
     556           12 :                 WRITE_ERRORF(TL("Edge's '%' from-node '%' is not known."), myCurrentID, begNodeID);
     557              :             }
     558              :         }
     559         2096 :     } else if (!myIsUpdate) {
     560            9 :         WRITE_ERRORF(TL("The from-node is not given for edge '%'."), myCurrentID);
     561            3 :         ok = false;
     562              :     }
     563        18949 :     if (attrs.hasAttribute(SUMO_ATTR_TO)) {
     564        16852 :         const std::string endNodeID = attrs.get<std::string>(SUMO_ATTR_TO, nullptr, ok);
     565        16852 :         if (endNodeID != "") {
     566        16850 :             myToNode = myNodeCont.retrieve(endNodeID);
     567        16850 :             if (myToNode == nullptr) {
     568           12 :                 WRITE_ERRORF(TL("Edge's '%' to-node '%' is not known."), myCurrentID, endNodeID);
     569              :             }
     570              :         }
     571         2097 :     } else if (!myIsUpdate) {
     572            9 :         WRITE_ERRORF(TL("The to-node is not given for edge '%'."), myCurrentID);
     573            3 :         ok = false;
     574              :     }
     575        18962 :     return ok && myFromNode != nullptr && myToNode != nullptr;
     576              : }
     577              : 
     578              : 
     579              : PositionVector
     580        18936 : NIXMLEdgesHandler::tryGetShape(const SUMOSAXAttributes& attrs) {
     581        18936 :     if (!attrs.hasAttribute(SUMO_ATTR_SHAPE) && myShape.size() > 0) {
     582              :         return myShape;
     583              :     }
     584              :     // try to build shape
     585        18924 :     bool ok = true;
     586        18924 :     if (!attrs.hasAttribute(SUMO_ATTR_SHAPE)) {
     587        14296 :         const double maxSegmentLength = OptionsCont::getOptions().getFloat("geometry.max-segment-length");
     588        14296 :         if (maxSegmentLength > 0) {
     589            1 :             PositionVector shape;
     590            1 :             shape.push_back(myFromNode->getPosition());
     591            1 :             shape.push_back(myToNode->getPosition());
     592              :             // shape is already cartesian but we must use a copy because the original will be modified
     593            1 :             NBNetBuilder::addGeometrySegments(shape, PositionVector(shape), maxSegmentLength);
     594              :             return shape;
     595            1 :         } else {
     596        14295 :             myReinitKeepEdgeShape = false;
     597        14295 :             return PositionVector();
     598              :         }
     599              :     }
     600         4628 :     PositionVector shape = attrs.getOpt<PositionVector>(SUMO_ATTR_SHAPE, nullptr, ok, PositionVector());
     601         4628 :     if (!NBNetBuilder::transformCoordinates(shape, true, myLocation)) {
     602            0 :         WRITE_ERRORF(TL("Unable to project coordinates for edge '%'."), myCurrentID);
     603              :     }
     604         4628 :     myReinitKeepEdgeShape = myKeepEdgeShape;
     605              :     return shape;
     606         4628 : }
     607              : 
     608              : 
     609              : LaneSpreadFunction
     610        18936 : NIXMLEdgesHandler::tryGetLaneSpread(const SUMOSAXAttributes& attrs) {
     611        18936 :     bool ok = true;
     612        18936 :     LaneSpreadFunction result = myLanesSpread;
     613        18936 :     std::string lsfS = toString(result);
     614        37872 :     lsfS = attrs.getOpt<std::string>(SUMO_ATTR_SPREADTYPE, myCurrentID.c_str(), ok, lsfS);
     615              :     if (SUMOXMLDefinitions::LaneSpreadFunctions.hasString(lsfS)) {
     616        18936 :         result = SUMOXMLDefinitions::LaneSpreadFunctions.get(lsfS);
     617              :     } else {
     618            0 :         WRITE_WARNINGF(TL("Ignoring unknown spreadType '%' for edge '%'."), lsfS, myCurrentID);
     619              :     }
     620        18936 :     return result;
     621              : }
     622              : 
     623              : 
     624              : void
     625           31 : NIXMLEdgesHandler::deleteEdge(const SUMOSAXAttributes& attrs) {
     626           31 :     bool ok = true;
     627           31 :     myCurrentID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
     628           31 :     if (!ok) {
     629            0 :         return;
     630              :     }
     631           31 :     NBEdge* edge = myEdgeCont.retrieve(myCurrentID);
     632           31 :     if (edge == nullptr) {
     633            0 :         WRITE_WARNING("Ignoring tag '" + toString(SUMO_TAG_DEL) + "' for unknown edge '" +
     634              :                       myCurrentID + "'");
     635            0 :         return;
     636              :     }
     637           31 :     const int lane = attrs.getOpt<int>(SUMO_ATTR_INDEX, myCurrentID.c_str(), ok, -1);
     638           31 :     if (lane < 0) {
     639           28 :         myEdgeCont.extract(myDistrictCont, edge, true);
     640              :     } else {
     641            3 :         edge->deleteLane(lane, false, true);
     642              :     }
     643              : }
     644              : 
     645              : 
     646              : void
     647        28457 : NIXMLEdgesHandler::myEndElement(int element) {
     648        28457 :     if (element == SUMO_TAG_VIEWSETTINGS_EDGES) {
     649         1131 :         delete myLocation;
     650         1131 :         myLocation = nullptr;
     651         1131 :         return;
     652              :     }
     653        27326 :     if (myCurrentEdge == nullptr) {
     654              :         return;
     655              :     }
     656        27128 :     if (element == SUMO_TAG_EDGE) {
     657              :         myLastParameterised.pop_back();
     658              :         // add bike lane, wait until lanes are loaded to avoid building if it already exists
     659        18922 :         if (myBikeLaneWidth != NBEdge::UNSPECIFIED_WIDTH) {
     660            7 :             myCurrentEdge->addBikeLane(myBikeLaneWidth);
     661              :         }
     662              :         // add sidewalk, wait until lanes are loaded to avoid building if it already exists
     663        18922 :         if (mySidewalkWidth != NBEdge::UNSPECIFIED_WIDTH) {
     664           44 :             myCurrentEdge->addSidewalk(mySidewalkWidth);
     665              :         }
     666              :         // apply default stopOffsets of edge to all lanes without specified stopOffset.
     667        18922 :         const StopOffset stopOffsets = myCurrentEdge->getEdgeStopOffset();
     668        18922 :         if (stopOffsets.isDefined()) {
     669           32 :             for (int i = 0; i < (int)myCurrentEdge->getLanes().size(); i++) {
     670           24 :                 myCurrentEdge->setEdgeStopOffset(i, stopOffsets, false);
     671              :             }
     672              :         }
     673        18922 :         if (!myIsUpdate) {
     674              :             try {
     675        16799 :                 if (!myEdgeCont.insert(myCurrentEdge)) {
     676            0 :                     WRITE_ERRORF(TL("Duplicate edge '%' occurred."), myCurrentID);
     677            0 :                     delete myCurrentEdge;
     678            0 :                     myCurrentEdge = nullptr;
     679            0 :                     return;
     680              :                 }
     681            0 :             } catch (InvalidArgument& e) {
     682            0 :                 WRITE_ERROR(e.what());
     683            0 :                 throw;
     684            0 :             } catch (...) {
     685            0 :                 WRITE_ERRORF(TL("An important information is missing in edge '%'."), myCurrentID);
     686            0 :             }
     687              :         }
     688        18922 :         myEdgeCont.processSplits(myCurrentEdge, mySplits, myNodeCont, myDistrictCont, myTLLogicCont);
     689        18922 :         myCurrentEdge = nullptr;
     690         8206 :     } else if (element == SUMO_TAG_LANE && myCurrentLaneIndex != -1) {
     691              :         myLastParameterised.pop_back();
     692         5858 :         myCurrentLaneIndex = -1;
     693              :     }
     694              : }
     695              : 
     696              : 
     697              : void
     698           11 : NIXMLEdgesHandler::addRoundabout(const SUMOSAXAttributes& attrs) {
     699           11 :     bool ok = true;
     700           11 :     const std::vector<std::string>& edgeIDs = attrs.get<std::vector<std::string> >(SUMO_ATTR_EDGES, nullptr, ok);
     701           11 :     if (ok) {
     702              :         EdgeSet roundabout;
     703           77 :         for (const std::string& eID : edgeIDs) {
     704           66 :             NBEdge* edge = myEdgeCont.retrieve(eID);
     705           66 :             if (edge == nullptr) {
     706            0 :                 if (!myEdgeCont.wasIgnored(eID)) {
     707            0 :                     WRITE_ERRORF(TL("Unknown edge '%' in roundabout."), eID);
     708              :                 }
     709              :             } else {
     710              :                 roundabout.insert(edge);
     711              :             }
     712              :         }
     713           11 :         myEdgeCont.addRoundabout(roundabout);
     714              :     }
     715           11 : }
     716              : 
     717              : 
     718              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1