LCOV - code coverage report
Current view: top level - src/netimport - NIXMLEdgesHandler.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 91.8 % 413 379
Test Date: 2024-12-21 15:45:41 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-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    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         1890 : NIXMLEdgesHandler::NIXMLEdgesHandler(NBNodeCont& nc,
      52              :                                      NBEdgeCont& ec,
      53              :                                      NBTypeCont& tc,
      54              :                                      NBDistrictCont& dc,
      55              :                                      NBTrafficLightLogicCont& tlc,
      56         1890 :                                      OptionsCont& options) :
      57              :     SUMOSAXHandler("xml-edges - file"),
      58         1890 :     myOptions(options),
      59         1890 :     myNodeCont(nc),
      60         1890 :     myEdgeCont(ec),
      61         1890 :     myTypeCont(tc),
      62         1890 :     myDistrictCont(dc),
      63         1890 :     myTLLogicCont(tlc),
      64         1890 :     myCurrentEdge(nullptr),
      65         1890 :     myCurrentLaneIndex(-1),
      66         1890 :     myHaveReportedAboutOverwriting(false),
      67         1890 :     myHaveReportedAboutTypeOverride(false),
      68         1890 :     myHaveWarnedAboutDeprecatedLaneId(false),
      69         3780 :     myKeepEdgeShape(!options.getBool("plain.extend-edge-shape")) {
      70         1890 : }
      71              : 
      72              : 
      73         1890 : NIXMLEdgesHandler::~NIXMLEdgesHandler() {
      74         1890 :     delete myLocation;
      75         1890 : }
      76              : 
      77              : 
      78              : void
      79        27465 : NIXMLEdgesHandler::myStartElement(int element,
      80              :                                   const SUMOSAXAttributes& attrs) {
      81        27465 :     switch (element) {
      82              :         case SUMO_TAG_VIEWSETTINGS_EDGES:
      83              :             // infer location for legacy networks that don't have location information
      84         1076 :             myLocation = GeoConvHelper::getLoadedPlain(getFileName());
      85         1076 :             break;
      86           20 :         case SUMO_TAG_LOCATION:
      87           20 :             delete myLocation;
      88           20 :             myLocation = NIImporter_SUMO::loadLocation(attrs, false);
      89           20 :             break;
      90        18438 :         case SUMO_TAG_EDGE:
      91        18438 :             addEdge(attrs);
      92        18437 :             break;
      93         5710 :         case SUMO_TAG_LANE:
      94         5710 :             addLane(attrs);
      95         5710 :             break;
      96           13 :         case SUMO_TAG_NEIGH:
      97           13 :             myCurrentEdge->getLaneStruct((int)myCurrentEdge->getNumLanes() - 1).oppositeID = attrs.getString(SUMO_ATTR_LANE);
      98           13 :             break;
      99          200 :         case SUMO_TAG_SPLIT:
     100          200 :             addSplit(attrs);
     101          200 :             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         1941 :         case SUMO_TAG_PARAM:
     109         1941 :             if (myLastParameterised.size() != 0 && myCurrentEdge != nullptr) {
     110         1899 :                 bool ok = true;
     111         1899 :                 const std::string key = attrs.get<std::string>(SUMO_ATTR_KEY, nullptr, ok);
     112              :                 // circumventing empty string test
     113         1899 :                 const std::string val = attrs.hasAttribute(SUMO_ATTR_VALUE) ? attrs.getString(SUMO_ATTR_VALUE) : "";
     114         1899 :                 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        27464 : }
     156              : 
     157              : 
     158              : void
     159        18438 : NIXMLEdgesHandler::addEdge(const SUMOSAXAttributes& attrs) {
     160        18438 :     myIsUpdate = false;
     161        18438 :     bool ok = true;
     162              :     // initialise the edge
     163        18438 :     myCurrentEdge = nullptr;
     164              :     mySplits.clear();
     165              :     // get the id, report an error if not given or empty...
     166        18438 :     myCurrentID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
     167        18438 :     if (!ok) {
     168           59 :         return;
     169              :     }
     170        18434 :     myCurrentEdge = myEdgeCont.retrieve(myCurrentID);
     171              :     // check deprecated (unused) attributes
     172              :     // use default values, first
     173        18434 :     myCurrentType = myOptions.getString("default.type");
     174        18434 :     myCurrentPriority = myTypeCont.getEdgeTypePriority(myCurrentType);
     175        18434 :     myCurrentLaneNo = myTypeCont.getEdgeTypeNumLanes(myCurrentType);
     176        18434 :     myCurrentEndOffset = NBEdge::UNSPECIFIED_OFFSET;
     177        18434 :     if (myCurrentEdge != nullptr) {
     178              :         // update existing edge. only update lane-specific settings when explicitly requested
     179         1877 :         myIsUpdate = true;
     180         1877 :         myCurrentSpeed = NBEdge::UNSPECIFIED_SPEED;
     181         1877 :         myCurrentFriction = NBEdge::UNSPECIFIED_FRICTION;
     182         1877 :         myPermissions = SVC_UNSPECIFIED;
     183         1877 :         myCurrentWidth = NBEdge::UNSPECIFIED_WIDTH;
     184              :         myCurrentType = myCurrentEdge->getTypeID();
     185         3754 :         myLanesSpread = SUMOXMLDefinitions::LaneSpreadFunctions.get(myOptions.getString("default.spreadtype"));
     186              :     } else {
     187              :         // this is a completely new edge. get the type specific defaults
     188        16557 :         myCurrentSpeed = myTypeCont.getEdgeTypeSpeed(myCurrentType);
     189        16557 :         myCurrentFriction = myTypeCont.getEdgeTypeFriction(myCurrentType);
     190        16557 :         myPermissions = myTypeCont.getEdgeTypePermissions(myCurrentType);
     191        16557 :         myCurrentWidth = myTypeCont.getEdgeTypeWidth(myCurrentType);
     192        16557 :         myLanesSpread = myTypeCont.getEdgeTypeSpreadType(myCurrentType);
     193              :     }
     194        36868 :     myShape = PositionVector();
     195        18434 :     myLength = NBEdge::UNSPECIFIED_LOADED_LENGTH;
     196        18434 :     myCurrentStreetName = "";
     197        18434 :     myReinitKeepEdgeShape = false;
     198        18434 :     mySidewalkWidth = NBEdge::UNSPECIFIED_WIDTH;
     199        18434 :     myBikeLaneWidth = NBEdge::UNSPECIFIED_WIDTH;
     200              :     // check whether a type's values shall be used
     201        18434 :     if (attrs.hasAttribute(SUMO_ATTR_TYPE)) {
     202         3118 :         myCurrentType = attrs.get<std::string>(SUMO_ATTR_TYPE, myCurrentID.c_str(), ok);
     203         3118 :         if (!ok) {
     204              :             return;
     205              :         }
     206         8509 :         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         3089 :         myCurrentSpeed = myTypeCont.getEdgeTypeSpeed(myCurrentType);
     211         3089 :         myCurrentPriority = myTypeCont.getEdgeTypePriority(myCurrentType);
     212         3089 :         myCurrentLaneNo = myTypeCont.getEdgeTypeNumLanes(myCurrentType);
     213         3089 :         myPermissions = myTypeCont.getEdgeTypePermissions(myCurrentType);
     214         3089 :         myCurrentWidth = myTypeCont.getEdgeTypeWidth(myCurrentType);
     215         3089 :         myLanesSpread = myTypeCont.getEdgeTypeSpreadType(myCurrentType);
     216         3089 :         mySidewalkWidth = myTypeCont.getEdgeTypeSidewalkWidth(myCurrentType);
     217         3089 :         myBikeLaneWidth = myTypeCont.getEdgeTypeBikeLaneWidth(myCurrentType);
     218              :     }
     219              :     // use values from the edge to overwrite if existing, then
     220        18405 :     if (myIsUpdate) {
     221         1877 :         if (!myHaveReportedAboutOverwriting) {
     222          246 :             WRITE_MESSAGEF(TL("Duplicate edge id occurred ('%'); assuming overwriting is wished."), myCurrentID);
     223           82 :             myHaveReportedAboutOverwriting = true;
     224              :         }
     225         1877 :         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         1877 :         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         1877 :         myCurrentPriority = myCurrentEdge->getPriority();
     237         1877 :         myCurrentLaneNo = myCurrentEdge->getNumLanes();
     238         1877 :         if (!myCurrentEdge->hasDefaultGeometry()) {
     239         1442 :             myShape = myCurrentEdge->getGeometry();
     240         1442 :             myReinitKeepEdgeShape = true;
     241              :         }
     242         1877 :         myLanesSpread = myCurrentEdge->getLaneSpreadFunction();
     243         1877 :         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        18405 :     if (attrs.hasAttribute(SUMO_ATTR_SPEED)) {
     251        12216 :         myCurrentSpeed = attrs.get<double>(SUMO_ATTR_SPEED, myCurrentID.c_str(), ok);
     252              :     }
     253        36810 :     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        18405 :     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        18405 :     if (attrs.hasAttribute(SUMO_ATTR_NUMLANES)) {
     262        12667 :         myCurrentLaneNo = attrs.get<int>(SUMO_ATTR_NUMLANES, myCurrentID.c_str(), ok);
     263              :     }
     264              :     // try to get the priority
     265        18405 :     if (attrs.hasAttribute(SUMO_ATTR_PRIORITY)) {
     266        10362 :         myCurrentPriority = attrs.get<int>(SUMO_ATTR_PRIORITY, myCurrentID.c_str(), ok);
     267              :     }
     268              :     // try to get the width
     269        18405 :     if (attrs.hasAttribute(SUMO_ATTR_WIDTH)) {
     270          603 :         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        18405 :     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        18405 :     if (attrs.hasAttribute(SUMO_ATTR_NAME)) {
     278         1848 :         myCurrentStreetName = attrs.get<std::string>(SUMO_ATTR_NAME, myCurrentID.c_str(), ok);
     279         1848 :         if (myCurrentStreetName != "" && myOptions.isDefault("output.street-names")) {
     280          100 :             myOptions.set("output.street-names", "true");
     281              :         }
     282              :     }
     283              : 
     284              :     // try to get the allowed/disallowed classes
     285        18405 :     if (attrs.hasAttribute(SUMO_ATTR_ALLOW) || attrs.hasAttribute(SUMO_ATTR_DISALLOW)) {
     286         4647 :         std::string allowS = attrs.hasAttribute(SUMO_ATTR_ALLOW) ? attrs.getStringSecure(SUMO_ATTR_ALLOW, "") : "";
     287         4647 :         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         4647 :         myPermissions = parseVehicleClasses(allowS, disallowS);
     290              :     }
     291              :     // try to set the nodes
     292        18405 :     if (!setNodes(attrs)) {
     293              :         // return if this failed
     294           13 :         myCurrentEdge = nullptr;
     295           13 :         return;
     296              :     }
     297              :     // try to get the shape
     298        36784 :     myShape = tryGetShape(attrs);
     299              :     // try to get the spread type
     300        18392 :     myLanesSpread = tryGetLaneSpread(attrs);
     301              :     // try to get the length
     302        18392 :     myLength = attrs.getOpt<double>(SUMO_ATTR_LENGTH, myCurrentID.c_str(), ok, myLength);
     303              :     // try to get the sidewalkWidth
     304        18392 :     mySidewalkWidth = attrs.getOpt<double>(SUMO_ATTR_SIDEWALKWIDTH, myCurrentID.c_str(), ok, mySidewalkWidth);
     305              :     // try to get the bikeLaneWidth
     306        18392 :     myBikeLaneWidth = attrs.getOpt<double>(SUMO_ATTR_BIKELANEWIDTH, myCurrentID.c_str(), ok, myBikeLaneWidth);
     307              :     // insert the parsed edge into the edges map
     308        18392 :     if (!ok) {
     309           10 :         myCurrentEdge = nullptr;
     310           10 :         return;
     311              :     }
     312        18382 :     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        18379 :     const bool applyLaneType = myCurrentEdge == nullptr;
     321        18379 :     if (myCurrentEdge != nullptr) {
     322         1876 :         myCurrentEdge->reinit(myFromNode, myToNode, myCurrentType, myCurrentSpeed, myCurrentFriction,
     323              :                               myCurrentLaneNo, myCurrentPriority, myShape,
     324              :                               myCurrentWidth, myCurrentEndOffset,
     325              :                               myCurrentStreetName, myLanesSpread,
     326         1876 :                               myReinitKeepEdgeShape);
     327              :     } else {
     328              :         // the edge must be allocated in dependence to whether a shape is given
     329        16503 :         if (myShape.size() == 0) {
     330        14017 :             myCurrentEdge = new NBEdge(myCurrentID, myFromNode, myToNode, myCurrentType, myCurrentSpeed, myCurrentFriction,
     331              :                                        myCurrentLaneNo, myCurrentPriority, myCurrentWidth, myCurrentEndOffset,
     332        42051 :                                        myLanesSpread, myCurrentStreetName);
     333              :         } else {
     334         2485 :             myCurrentEdge = new NBEdge(myCurrentID, myFromNode, myToNode, myCurrentType, myCurrentSpeed, myCurrentFriction,
     335              :                                        myCurrentLaneNo, myCurrentPriority, myCurrentWidth, myCurrentEndOffset,
     336              :                                        myShape, myLanesSpread, myCurrentStreetName, "",
     337         7460 :                                        myKeepEdgeShape);
     338              :         }
     339              :     }
     340        18378 :     myCurrentEdge->setLoadedLength(myLength);
     341        18378 :     if (myPermissions != SVC_UNSPECIFIED) {
     342        16525 :         myCurrentEdge->setPermissions(myPermissions);
     343              :     }
     344              :     // apply laneType if given
     345        18378 :     if (applyLaneType && myCurrentType != "" && myTypeCont.knows(myCurrentType)) {
     346          422 :         const NBTypeCont::EdgeTypeDefinition* eType = myTypeCont.getEdgeType(myCurrentType);
     347          422 :         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        18378 :     myCurrentEdge->setDistance(attrs.getOpt<double>(SUMO_ATTR_DISTANCE, myCurrentID.c_str(), ok, myCurrentEdge->getDistance()));
     371              :     // preserve bidi edge (only as boo, the actual edge will be recomputed)
     372        18378 :     const std::string bidi = attrs.getOpt<std::string>(SUMO_ATTR_BIDI, myCurrentID.c_str(), ok, "");
     373        18378 :     myCurrentEdge->setBidi(myCurrentEdge->getBidiEdge() != nullptr || bidi != "");
     374              : 
     375        18378 :     myLastParameterised.push_back(myCurrentEdge);
     376              : }
     377              : 
     378              : 
     379              : void
     380         5710 : NIXMLEdgesHandler::addLane(const SUMOSAXAttributes& attrs) {
     381         5710 :     if (myCurrentEdge == nullptr) {
     382           58 :         if (!OptionsCont::getOptions().isInStringVector("remove-edges.explicit", myCurrentID)) {
     383           87 :             WRITE_ERRORF("Additional lane information could not be set - the edge with id '%s' is not known.", myCurrentID);
     384              :         }
     385           30 :         return;
     386              :     }
     387         5681 :     bool ok = true;
     388              :     int lane;
     389         5681 :     if (attrs.hasAttribute(SUMO_ATTR_ID)) {
     390            0 :         lane = attrs.get<int>(SUMO_ATTR_ID, myCurrentID.c_str(), ok);
     391            0 :         if (!myHaveWarnedAboutDeprecatedLaneId) {
     392            0 :             myHaveWarnedAboutDeprecatedLaneId = true;
     393            0 :             WRITE_WARNINGF(TL("'%' is deprecated, please use '%' instead."), toString(SUMO_ATTR_ID), toString(SUMO_ATTR_INDEX));
     394              :         }
     395              :     } else {
     396         5681 :         lane = attrs.get<int>(SUMO_ATTR_INDEX, myCurrentID.c_str(), ok);
     397              :     }
     398         5681 :     if (!ok) {
     399              :         return;
     400              :     }
     401              :     // check whether this lane exists
     402         5681 :     if (lane >= myCurrentEdge->getNumLanes()) {
     403            3 :         WRITE_ERRORF(TL("Lane index is larger than number of lanes (edge '%')."), myCurrentID);
     404            1 :         return;
     405              :     }
     406         5680 :     myCurrentLaneIndex = lane;
     407              :     // set information about allowed / disallowed vehicle classes (if specified)
     408         5680 :     if (attrs.hasAttribute(SUMO_ATTR_ALLOW) || attrs.hasAttribute(SUMO_ATTR_DISALLOW)) {
     409         4675 :         const std::string allowed = attrs.getOpt<std::string>(SUMO_ATTR_ALLOW, nullptr, ok, "");
     410         4675 :         const std::string disallowed = attrs.getOpt<std::string>(SUMO_ATTR_DISALLOW, nullptr, ok, "");
     411         4675 :         myCurrentEdge->setPermissions(parseVehicleClasses(allowed, disallowed), lane);
     412              :     }
     413         5680 :     if (attrs.hasAttribute(SUMO_ATTR_PREFER)) {
     414            0 :         const std::string preferred  = attrs.get<std::string>(SUMO_ATTR_PREFER, nullptr, ok);
     415            0 :         myCurrentEdge->setPreferredVehicleClass(parseVehicleClasses(preferred), lane);
     416              :     }
     417         5680 :     if (attrs.hasAttribute(SUMO_ATTR_CHANGE_LEFT) || attrs.hasAttribute(SUMO_ATTR_CHANGE_RIGHT)) {
     418           41 :         const std::string changeLeft = attrs.getOpt<std::string>(SUMO_ATTR_CHANGE_LEFT, nullptr, ok, "");
     419           41 :         const std::string changeRight = attrs.getOpt<std::string>(SUMO_ATTR_CHANGE_RIGHT, nullptr, ok, "");
     420           82 :         myCurrentEdge->setPermittedChanging(lane, parseVehicleClasses(changeLeft, ""), parseVehicleClasses(changeRight, ""));
     421              :     }
     422              :     // try to get the width
     423         5680 :     if (attrs.hasAttribute(SUMO_ATTR_WIDTH)) {
     424         1903 :         myCurrentEdge->setLaneWidth(lane, attrs.get<double>(SUMO_ATTR_WIDTH, myCurrentID.c_str(), ok));
     425              :     }
     426              :     // try to get the end-offset (lane shortened due to pedestrian crossing etc..)
     427         5680 :     if (attrs.hasAttribute(SUMO_ATTR_ENDOFFSET)) {
     428           18 :         myCurrentEdge->setEndOffset(lane, attrs.get<double>(SUMO_ATTR_ENDOFFSET, myCurrentID.c_str(), ok));
     429              :     }
     430              :     // try to get lane specific speed (should not occur for german networks)
     431         5680 :     if (attrs.hasAttribute(SUMO_ATTR_SPEED)) {
     432            9 :         myCurrentEdge->setSpeed(lane, attrs.get<double>(SUMO_ATTR_SPEED, myCurrentID.c_str(), ok));
     433              :     }
     434              :     // try to get lane specific friction
     435         5680 :     if (attrs.hasAttribute(SUMO_ATTR_FRICTION)) {
     436            4 :         myCurrentEdge->setFriction(lane, attrs.get<double>(SUMO_ATTR_FRICTION, myCurrentID.c_str(), ok));
     437              :     }
     438              :     // check whether this is an acceleration lane
     439         5680 :     if (attrs.hasAttribute(SUMO_ATTR_ACCELERATION)) {
     440            2 :         myCurrentEdge->setAcceleration(lane, attrs.get<bool>(SUMO_ATTR_ACCELERATION, myCurrentID.c_str(), ok));
     441              :     }
     442              :     // check whether this lane has a custom shape
     443         5680 :     if (attrs.hasAttribute(SUMO_ATTR_SHAPE)) {
     444           68 :         PositionVector shape = attrs.get<PositionVector>(SUMO_ATTR_SHAPE, myCurrentID.c_str(), ok);
     445           68 :         if (!NBNetBuilder::transformCoordinates(shape, true, myLocation)) {
     446            0 :             const std::string laneID = myCurrentID + "_" + toString(lane);
     447            0 :             WRITE_ERRORF(TL("Unable to project coordinates for lane '%'."), laneID);
     448              :         }
     449           68 :         if (shape.size() == 1) {
     450              :             // lane shape of length 1 is not permitted
     451            1 :             shape.push_front(myCurrentEdge->getFromNode()->getPosition());
     452            1 :             shape.push_back(myCurrentEdge->getToNode()->getPosition());
     453              :         }
     454           68 :         shape.removeDoublePoints();
     455           68 :         if (shape.size() < 2) {
     456              :             // ignore lane shape for very short lanes
     457              :             shape.clear();
     458              :         }
     459           68 :         myCurrentEdge->setLaneShape(lane, shape);
     460           68 :     }
     461              :     // set custom lane type
     462         5680 :     if (attrs.hasAttribute(SUMO_ATTR_TYPE)) {
     463           16 :         myCurrentEdge->setLaneType(lane, attrs.get<std::string>(SUMO_ATTR_TYPE, myCurrentID.c_str(), ok));
     464              :     }
     465         5680 :     myLastParameterised.push_back(&myCurrentEdge->getLaneStruct(lane));
     466              : }
     467              : 
     468              : 
     469          200 : void NIXMLEdgesHandler::addSplit(const SUMOSAXAttributes& attrs) {
     470          200 :     if (myCurrentEdge == nullptr) {
     471            0 :         if (!OptionsCont::getOptions().isInStringVector("remove-edges.explicit", myCurrentID)) {
     472            0 :             WRITE_WARNING(TL("Ignoring 'split' because it cannot be assigned to an edge"));
     473              :         }
     474            4 :         return;
     475              :     }
     476          200 :     bool ok = true;
     477              :     NBEdgeCont::Split e;
     478          200 :     e.pos = attrs.get<double>(SUMO_ATTR_POSITION, nullptr, ok);
     479          200 :     if (ok) {
     480          396 :         if (fabs(e.pos) > myCurrentEdge->getLoadedLength()) {
     481            3 :             WRITE_ERRORF(TL("Edge '%' has a split at invalid position %."), myCurrentID, toString(e.pos));
     482            1 :             return;
     483              :         }
     484          199 :         std::vector<NBEdgeCont::Split>::iterator i = find_if(mySplits.begin(), mySplits.end(), split_by_pos_finder(e.pos));
     485          199 :         if (i != mySplits.end()) {
     486            6 :             WRITE_ERRORF(TL("Edge '%' has already a split at position %."), myCurrentID, toString(e.pos));
     487            2 :             return;
     488              :         }
     489              :         // XXX rounding to int may duplicate the id of another split
     490          394 :         e.nameID = myCurrentID + "." + toString((int)e.pos);
     491          197 :         if (e.pos < 0) {
     492           35 :             e.pos += myCurrentEdge->getGeometry().length();
     493              :         }
     494          501 :         for (const std::string& id : attrs.getOpt<std::vector<std::string> >(SUMO_ATTR_LANES, myCurrentID.c_str(), ok)) {
     495              :             try {
     496          304 :                 int lane = StringUtils::toInt(id);
     497          302 :                 e.lanes.push_back(lane);
     498            2 :             } catch (NumberFormatException&) {
     499            6 :                 WRITE_ERRORF(TL("Error on parsing a split (edge '%')."), myCurrentID);
     500            2 :             } catch (EmptyData&) {
     501            0 :                 WRITE_ERRORF(TL("Error on parsing a split (edge '%')."), myCurrentID);
     502            0 :             }
     503          197 :         }
     504          197 :         if (e.lanes.empty()) {
     505          155 :             for (int l = 0; l < myCurrentEdge->getNumLanes(); ++l) {
     506           99 :                 e.lanes.push_back(l);
     507              :             }
     508              :         }
     509          197 :         e.speed = attrs.getOpt(SUMO_ATTR_SPEED, nullptr, ok, myCurrentEdge->getSpeed());
     510          201 :         if (attrs.hasAttribute(SUMO_ATTR_SPEED) && myOptions.getBool("speed-in-kmh")) {
     511            0 :             e.speed /= 3.6;
     512              :         }
     513          197 :         e.idBefore = attrs.getOpt(SUMO_ATTR_ID_BEFORE, nullptr, ok, std::string(""));
     514          197 :         e.idAfter = attrs.getOpt(SUMO_ATTR_ID_AFTER, nullptr, ok, std::string(""));
     515          197 :         if (!ok) {
     516              :             return;
     517              :         }
     518          197 :         const std::string nodeID = attrs.getOpt(SUMO_ATTR_ID, nullptr, ok, e.nameID);
     519          197 :         if (nodeID == myCurrentEdge->getFromNode()->getID() || nodeID == myCurrentEdge->getToNode()->getID()) {
     520            3 :             WRITE_ERRORF(TL("Invalid split node id for edge '%' (from- and to-node are forbidden)"), myCurrentEdge->getID());
     521              :             return;
     522              :         }
     523          196 :         e.node = myNodeCont.retrieve(nodeID);
     524          391 :         e.offsetFactor = OptionsCont::getOptions().getBool("lefthand") ? -1 : 1;
     525          196 :         if (e.node == nullptr) {
     526          189 :             double geomPos = e.pos;
     527          189 :             if (myCurrentEdge->hasLoadedLength()) {
     528            4 :                 geomPos *= myCurrentEdge->getGeometry().length() / myCurrentEdge->getLoadedLength();
     529              :             }
     530          189 :             e.node = new NBNode(nodeID, myCurrentEdge->getGeometry().positionAtOffset(geomPos));
     531          189 :             myNodeCont.insert(e.node);
     532              :         }
     533          196 :         NIXMLNodesHandler::processNodeType(attrs, e.node, e.node->getID(), e.node->getPosition(), false,
     534              :                                            myNodeCont, myEdgeCont, myTLLogicCont, myLocation);
     535          196 :         mySplits.push_back(e);
     536              :     }
     537          200 : }
     538              : 
     539              : 
     540              : bool
     541        18405 : NIXMLEdgesHandler::setNodes(const SUMOSAXAttributes& attrs) {
     542              :     // the names and the coordinates of the beginning and the end node
     543              :     // may be found, try
     544        18405 :     bool ok = true;
     545        18405 :     if (myIsUpdate) {
     546         1877 :         myFromNode = myCurrentEdge->getFromNode();
     547              :         myToNode = myCurrentEdge->getToNode();
     548              :     }
     549        18405 :     if (attrs.hasAttribute(SUMO_ATTR_FROM)) {
     550        16556 :         const std::string begNodeID = attrs.get<std::string>(SUMO_ATTR_FROM, nullptr, ok);
     551        16556 :         if (begNodeID != "") {
     552        16554 :             myFromNode = myNodeCont.retrieve(begNodeID);
     553        16554 :             if (myFromNode == nullptr) {
     554           12 :                 WRITE_ERRORF(TL("Edge's '%' from-node '%' is not known."), myCurrentID, begNodeID);
     555              :             }
     556              :         }
     557         1849 :     } else if (!myIsUpdate) {
     558            9 :         WRITE_ERRORF(TL("The from-node is not given for edge '%'."), myCurrentID);
     559            3 :         ok = false;
     560              :     }
     561        18405 :     if (attrs.hasAttribute(SUMO_ATTR_TO)) {
     562        16555 :         const std::string endNodeID = attrs.get<std::string>(SUMO_ATTR_TO, nullptr, ok);
     563        16555 :         if (endNodeID != "") {
     564        16553 :             myToNode = myNodeCont.retrieve(endNodeID);
     565        16553 :             if (myToNode == nullptr) {
     566           12 :                 WRITE_ERRORF(TL("Edge's '%' to-node '%' is not known."), myCurrentID, endNodeID);
     567              :             }
     568              :         }
     569         1850 :     } else if (!myIsUpdate) {
     570            9 :         WRITE_ERRORF(TL("The to-node is not given for edge '%'."), myCurrentID);
     571            3 :         ok = false;
     572              :     }
     573        18418 :     return ok && myFromNode != nullptr && myToNode != nullptr;
     574              : }
     575              : 
     576              : 
     577              : PositionVector
     578        18392 : NIXMLEdgesHandler::tryGetShape(const SUMOSAXAttributes& attrs) {
     579        18392 :     if (!attrs.hasAttribute(SUMO_ATTR_SHAPE) && myShape.size() > 0) {
     580              :         return myShape;
     581              :     }
     582              :     // try to build shape
     583        18382 :     bool ok = true;
     584        18382 :     if (!attrs.hasAttribute(SUMO_ATTR_SHAPE)) {
     585        14091 :         const double maxSegmentLength = OptionsCont::getOptions().getFloat("geometry.max-segment-length");
     586        14091 :         if (maxSegmentLength > 0) {
     587            1 :             PositionVector shape;
     588            1 :             shape.push_back(myFromNode->getPosition());
     589            1 :             shape.push_back(myToNode->getPosition());
     590              :             // shape is already cartesian but we must use a copy because the original will be modified
     591            1 :             NBNetBuilder::addGeometrySegments(shape, PositionVector(shape), maxSegmentLength);
     592              :             return shape;
     593            1 :         } else {
     594        14090 :             myReinitKeepEdgeShape = false;
     595        14090 :             return PositionVector();
     596              :         }
     597              :     }
     598         4291 :     PositionVector shape = attrs.getOpt<PositionVector>(SUMO_ATTR_SHAPE, nullptr, ok, PositionVector());
     599         4291 :     if (!NBNetBuilder::transformCoordinates(shape, true, myLocation)) {
     600            0 :         WRITE_ERRORF(TL("Unable to project coordinates for edge '%'."), myCurrentID);
     601              :     }
     602         4291 :     myReinitKeepEdgeShape = myKeepEdgeShape;
     603              :     return shape;
     604         4291 : }
     605              : 
     606              : 
     607              : LaneSpreadFunction
     608        18392 : NIXMLEdgesHandler::tryGetLaneSpread(const SUMOSAXAttributes& attrs) {
     609        18392 :     bool ok = true;
     610        18392 :     LaneSpreadFunction result = myLanesSpread;
     611        18392 :     std::string lsfS = toString(result);
     612        36784 :     lsfS = attrs.getOpt<std::string>(SUMO_ATTR_SPREADTYPE, myCurrentID.c_str(), ok, lsfS);
     613              :     if (SUMOXMLDefinitions::LaneSpreadFunctions.hasString(lsfS)) {
     614        18392 :         result = SUMOXMLDefinitions::LaneSpreadFunctions.get(lsfS);
     615              :     } else {
     616            0 :         WRITE_WARNINGF(TL("Ignoring unknown spreadType '%' for edge '%'."), lsfS, myCurrentID);
     617              :     }
     618        18392 :     return result;
     619              : }
     620              : 
     621              : 
     622              : void
     623           31 : NIXMLEdgesHandler::deleteEdge(const SUMOSAXAttributes& attrs) {
     624           31 :     bool ok = true;
     625           31 :     myCurrentID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
     626           31 :     if (!ok) {
     627            0 :         return;
     628              :     }
     629           31 :     NBEdge* edge = myEdgeCont.retrieve(myCurrentID);
     630           31 :     if (edge == nullptr) {
     631            0 :         WRITE_WARNING("Ignoring tag '" + toString(SUMO_TAG_DEL) + "' for unknown edge '" +
     632              :                       myCurrentID + "'");
     633            0 :         return;
     634              :     }
     635           31 :     const int lane = attrs.getOpt<int>(SUMO_ATTR_INDEX, myCurrentID.c_str(), ok, -1);
     636           31 :     if (lane < 0) {
     637           28 :         myEdgeCont.extract(myDistrictCont, edge, true);
     638              :     } else {
     639            3 :         edge->deleteLane(lane, false, true);
     640              :     }
     641              : }
     642              : 
     643              : 
     644              : void
     645        27463 : NIXMLEdgesHandler::myEndElement(int element) {
     646        27463 :     if (element == SUMO_TAG_VIEWSETTINGS_EDGES) {
     647         1075 :         delete myLocation;
     648         1075 :         myLocation = nullptr;
     649         1075 :         return;
     650              :     }
     651        26388 :     if (myCurrentEdge == nullptr) {
     652              :         return;
     653              :     }
     654        26196 :     if (element == SUMO_TAG_EDGE) {
     655              :         myLastParameterised.pop_back();
     656              :         // add bike lane, wait until lanes are loaded to avoid building if it already exists
     657        18378 :         if (myBikeLaneWidth != NBEdge::UNSPECIFIED_WIDTH) {
     658            7 :             myCurrentEdge->addBikeLane(myBikeLaneWidth);
     659              :         }
     660              :         // add sidewalk, wait until lanes are loaded to avoid building if it already exists
     661        18378 :         if (mySidewalkWidth != NBEdge::UNSPECIFIED_WIDTH) {
     662           44 :             myCurrentEdge->addSidewalk(mySidewalkWidth);
     663              :         }
     664              :         // apply default stopOffsets of edge to all lanes without specified stopOffset.
     665        18378 :         const StopOffset stopOffsets = myCurrentEdge->getEdgeStopOffset();
     666        18378 :         if (stopOffsets.isDefined()) {
     667           32 :             for (int i = 0; i < (int)myCurrentEdge->getLanes().size(); i++) {
     668           24 :                 myCurrentEdge->setEdgeStopOffset(i, stopOffsets, false);
     669              :             }
     670              :         }
     671        18378 :         if (!myIsUpdate) {
     672              :             try {
     673        16502 :                 if (!myEdgeCont.insert(myCurrentEdge)) {
     674            0 :                     WRITE_ERRORF(TL("Duplicate edge '%' occurred."), myCurrentID);
     675            0 :                     delete myCurrentEdge;
     676            0 :                     myCurrentEdge = nullptr;
     677            0 :                     return;
     678              :                 }
     679            0 :             } catch (InvalidArgument& e) {
     680            0 :                 WRITE_ERROR(e.what());
     681            0 :                 throw;
     682            0 :             } catch (...) {
     683            0 :                 WRITE_ERRORF(TL("An important information is missing in edge '%'."), myCurrentID);
     684            0 :             }
     685              :         }
     686        18378 :         myEdgeCont.processSplits(myCurrentEdge, mySplits, myNodeCont, myDistrictCont, myTLLogicCont);
     687        18378 :         myCurrentEdge = nullptr;
     688         7818 :     } else if (element == SUMO_TAG_LANE && myCurrentLaneIndex != -1) {
     689              :         myLastParameterised.pop_back();
     690         5680 :         myCurrentLaneIndex = -1;
     691              :     }
     692              : }
     693              : 
     694              : 
     695              : void
     696           11 : NIXMLEdgesHandler::addRoundabout(const SUMOSAXAttributes& attrs) {
     697           11 :     bool ok = true;
     698           11 :     const std::vector<std::string>& edgeIDs = attrs.get<std::vector<std::string> >(SUMO_ATTR_EDGES, nullptr, ok);
     699           11 :     if (ok) {
     700              :         EdgeSet roundabout;
     701           77 :         for (const std::string& eID : edgeIDs) {
     702           66 :             NBEdge* edge = myEdgeCont.retrieve(eID);
     703           66 :             if (edge == nullptr) {
     704            0 :                 if (!myEdgeCont.wasIgnored(eID)) {
     705            0 :                     WRITE_ERRORF(TL("Unknown edge '%' in roundabout."), eID);
     706              :                 }
     707              :             } else {
     708              :                 roundabout.insert(edge);
     709              :             }
     710              :         }
     711           11 :         myEdgeCont.addRoundabout(roundabout);
     712              :     }
     713           11 : }
     714              : 
     715              : 
     716              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1