LCOV - code coverage report
Current view: top level - src/netimport - NIXMLNodesHandler.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 164 177 92.7 %
Date: 2024-05-02 15:31:40 Functions: 10 11 90.9 %

          Line data    Source code
       1             : /****************************************************************************/
       2             : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3             : // Copyright (C) 2001-2024 German Aerospace Center (DLR) and others.
       4             : // This program and the accompanying materials are made available under the
       5             : // terms of the Eclipse Public License 2.0 which is available at
       6             : // https://www.eclipse.org/legal/epl-2.0/
       7             : // This Source Code may also be made available under the following Secondary
       8             : // Licenses when the conditions for such availability set forth in the Eclipse
       9             : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10             : // or later which is available at
      11             : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12             : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13             : /****************************************************************************/
      14             : /// @file    NIXMLNodesHandler.cpp
      15             : /// @author  Daniel Krajzewicz
      16             : /// @author  Jakob Erdmann
      17             : /// @author  Sascha Krieg
      18             : /// @author  Michael Behrisch
      19             : /// @date    Tue, 20 Nov 2001
      20             : ///
      21             : // Importer for network nodes stored in XML
      22             : /****************************************************************************/
      23             : #include <config.h>
      24             : 
      25             : #include <string>
      26             : #include <iostream>
      27             : #include <utils/xml/SUMOSAXHandler.h>
      28             : #include <utils/xml/SUMOXMLDefinitions.h>
      29             : #include <utils/common/MsgHandler.h>
      30             : #include <utils/common/StringUtils.h>
      31             : #include <utils/common/ToString.h>
      32             : #include <utils/common/StringTokenizer.h>
      33             : #include <utils/options/OptionsCont.h>
      34             : #include <utils/geom/GeoConvHelper.h>
      35             : #include <netbuild/NBNodeCont.h>
      36             : #include <netbuild/NBTrafficLightLogicCont.h>
      37             : #include <netbuild/NBOwnTLDef.h>
      38             : #include <netbuild/NBNetBuilder.h>
      39             : #include "NIXMLNodesHandler.h"
      40             : #include "NIImporter_SUMO.h"
      41             : 
      42             : 
      43             : // ===========================================================================
      44             : // method definitions
      45             : // ===========================================================================
      46        2224 : NIXMLNodesHandler::NIXMLNodesHandler(NBNodeCont& nc, NBEdgeCont& ec,
      47             :                                      NBTrafficLightLogicCont& tlc,
      48        2224 :                                      OptionsCont& options) :
      49             :     SUMOSAXHandler("xml-nodes - file"),
      50        2224 :     myOptions(options),
      51        2224 :     myNodeCont(nc),
      52        2224 :     myEdgeCont(ec),
      53        2224 :     myTLLogicCont(tlc),
      54        2224 :     myLocation(nullptr),
      55        4448 :     myLastParameterised(nullptr) {
      56        2224 : }
      57             : 
      58             : 
      59        2224 : NIXMLNodesHandler::~NIXMLNodesHandler() {
      60        2224 :     delete myLocation;
      61        2224 : }
      62             : 
      63             : 
      64             : void
      65       15536 : NIXMLNodesHandler::myStartElement(int element,
      66             :                                   const SUMOSAXAttributes& attrs) {
      67       15536 :     switch (element) {
      68         497 :         case SUMO_TAG_LOCATION:
      69         497 :             myLocation = NIImporter_SUMO::loadLocation(attrs);
      70         497 :             if (myLocation) {
      71         497 :                 GeoConvHelper::setLoadedPlain(getFileName(), *myLocation);
      72             :             }
      73             :             break;
      74       13838 :         case SUMO_TAG_NODE:
      75       13838 :             addNode(attrs);
      76       13837 :             break;
      77          10 :         case SUMO_TAG_JOIN:
      78          10 :             addJoinCluster(attrs);
      79          10 :             break;
      80           1 :         case SUMO_TAG_JOINEXCLUDE:
      81           1 :             addJoinExclusion(attrs);
      82           1 :             break;
      83          11 :         case SUMO_TAG_DEL:
      84          11 :             deleteNode(attrs);
      85          11 :             break;
      86         133 :         case SUMO_TAG_PARAM:
      87         133 :             if (myLastParameterised != nullptr) {
      88         133 :                 bool ok = true;
      89         133 :                 const std::string key = attrs.get<std::string>(SUMO_ATTR_KEY, nullptr, ok);
      90             :                 // circumventing empty string test
      91         133 :                 const std::string val = attrs.hasAttribute(SUMO_ATTR_VALUE) ? attrs.getString(SUMO_ATTR_VALUE) : "";
      92         133 :                 myLastParameterised->setParameter(key, val);
      93             :             }
      94             :             break;
      95             :         default:
      96             :             break;
      97             :     }
      98       15535 : }
      99             : 
     100             : 
     101             : void
     102       15534 : NIXMLNodesHandler::myEndElement(int element) {
     103       15534 :     switch (element) {
     104       13837 :         case SUMO_TAG_NODE:
     105       13837 :             myLastParameterised = nullptr;
     106       13837 :             break;
     107             :         default:
     108             :             break;
     109             :     }
     110       15534 : }
     111             : 
     112             : 
     113             : void
     114       13838 : NIXMLNodesHandler::addNode(const SUMOSAXAttributes& attrs) {
     115       13838 :     bool ok = true;
     116             :     // get the id, report a warning if not given or empty...
     117       13838 :     myID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
     118       13838 :     if (!ok) {
     119           0 :         return;
     120             :     }
     121       13838 :     NBNode* node = myNodeCont.retrieve(myID);
     122             :     // retrieve the position of the node
     123             :     bool xOk = false;
     124             :     bool yOk = false;
     125             :     bool needConversion = true;
     126       13838 :     if (node != nullptr) {
     127        1337 :         myPosition = node->getPosition();
     128             :         xOk = yOk = true;
     129             :         needConversion = false;
     130             :     } else {
     131             :         myPosition.set(0, 0, 0); // better to reset than to reuse the previous (z)-value
     132             :     }
     133       13838 :     if (attrs.hasAttribute(SUMO_ATTR_X)) {
     134       13813 :         myPosition.set(attrs.get<double>(SUMO_ATTR_X, myID.c_str(), ok), myPosition.y());
     135             :         xOk = true;
     136             :         needConversion = true;
     137             :     }
     138       13838 :     if (attrs.hasAttribute(SUMO_ATTR_Y)) {
     139       13814 :         myPosition.set(myPosition.x(), attrs.get<double>(SUMO_ATTR_Y, myID.c_str(), ok));
     140             :         yOk = true;
     141             :         needConversion = true;
     142             :     }
     143       13838 :     if (attrs.hasAttribute(SUMO_ATTR_Z)) {
     144          48 :         myPosition.set(myPosition.x(), myPosition.y(), attrs.get<double>(SUMO_ATTR_Z, myID.c_str(), ok));
     145             :     }
     146       13838 :     if (xOk && yOk) {
     147       13838 :         if (needConversion && !NBNetBuilder::transformCoordinate(myPosition, true, myLocation)) {
     148           0 :             WRITE_ERRORF(TL("Unable to project coordinates for node '%'."), myID);
     149             :         }
     150             :     } else {
     151           0 :         WRITE_ERRORF(TL("Missing position (at node ID='%')."), myID);
     152             :     }
     153       13838 :     bool updateEdgeGeometries = node != nullptr && myPosition != node->getPosition();
     154       13838 :     node = processNodeType(attrs, node, myID, myPosition, updateEdgeGeometries, myNodeCont, myEdgeCont, myTLLogicCont);
     155       13837 :     myLastParameterised = node;
     156             : }
     157             : 
     158             : 
     159             : NBNode*
     160       14090 : NIXMLNodesHandler::processNodeType(const SUMOSAXAttributes& attrs, NBNode* node, const std::string& nodeID, const Position& position,
     161             :                                    bool updateEdgeGeometries,
     162             :                                    NBNodeCont& nc, NBEdgeCont& ec, NBTrafficLightLogicCont& tlc) {
     163       14090 :     bool ok = true;
     164             :     // get the type
     165             :     SumoXMLNodeType type = SumoXMLNodeType::UNKNOWN;
     166       14090 :     if (node != nullptr) {
     167             :         type = node->getType();
     168             :     }
     169       28180 :     std::string typeS = attrs.getOpt<std::string>(SUMO_ATTR_TYPE, nodeID.c_str(), ok, "");
     170       14090 :     if (SUMOXMLDefinitions::NodeTypes.hasString(typeS)) {
     171        5965 :         type = SUMOXMLDefinitions::NodeTypes.get(typeS);
     172        5965 :         if (type == SumoXMLNodeType::DEAD_END_DEPRECATED || type == SumoXMLNodeType::DEAD_END) {
     173             :             // dead end is a computed status. Reset this to unknown so it will
     174             :             // be corrected if additional connections are loaded
     175             :             type = SumoXMLNodeType::UNKNOWN;
     176             :         }
     177             :     }
     178             :     std::set<NBTrafficLightDefinition*> oldTLS;
     179             :     // check whether a prior node shall be modified
     180             :     const bool isPatch = node != nullptr;
     181       14090 :     if (node == nullptr) {
     182       12511 :         node = new NBNode(nodeID, position, type);
     183       12510 :         if (!nc.insert(node)) {
     184           0 :             throw ProcessError(TLF("Could not insert node though checked this before (id='%').", nodeID));
     185             :         }
     186             :     } else {
     187             :         // patch information
     188             :         oldTLS = node->getControllingTLS();
     189             :         if (node->getType() == SumoXMLNodeType::PRIORITY
     190        1579 :                 && (type == SumoXMLNodeType::RIGHT_BEFORE_LEFT || type == SumoXMLNodeType::LEFT_BEFORE_RIGHT)) {
     191           4 :             ec.removeRoundabout(node);
     192             :         }
     193        1579 :         node->reinit(position, type, updateEdgeGeometries);
     194             :     }
     195             :     // process traffic light definition
     196       14089 :     if (NBNode::isTrafficLight(type)) {
     197         613 :         processTrafficLightDefinitions(attrs, node, tlc);
     198       15033 :     } else if (isPatch && typeS != "") {
     199          21 :         nc.markAsNotTLS(node);
     200             :     }
     201             :     // remove previously set tls if this node is not controlled by them
     202       14109 :     for (std::set<NBTrafficLightDefinition*>::iterator i = oldTLS.begin(); i != oldTLS.end(); ++i) {
     203          20 :         if ((*i)->getNodes().size() == 0) {
     204          29 :             tlc.removeFully((*i)->getID());
     205             :         }
     206             :     }
     207             : 
     208             :     // set optional shape
     209       14089 :     PositionVector shape;
     210       14089 :     if (attrs.hasAttribute(SUMO_ATTR_SHAPE)) {
     211          34 :         shape = attrs.getOpt<PositionVector>(SUMO_ATTR_SHAPE, nodeID.c_str(), ok, PositionVector());
     212          17 :         if (!NBNetBuilder::transformCoordinates(shape)) {
     213           0 :             WRITE_ERRORF(TL("Unable to project node shape at node '%'."), node->getID());
     214             :         }
     215          17 :         if (shape.size() > 2) {
     216          16 :             shape.closePolygon();
     217             :         }
     218          17 :         node->setCustomShape(shape);
     219             :     }
     220             :     // set optional radius
     221       14089 :     if (attrs.hasAttribute(SUMO_ATTR_RADIUS)) {
     222          34 :         node->setRadius(attrs.get<double>(SUMO_ATTR_RADIUS, nodeID.c_str(), ok));
     223             :     }
     224             :     // set optional keepClear flag
     225       14089 :     if (attrs.hasAttribute(SUMO_ATTR_KEEP_CLEAR)) {
     226           1 :         node->setKeepClear(attrs.get<bool>(SUMO_ATTR_KEEP_CLEAR, nodeID.c_str(), ok));
     227             :     }
     228       14089 :     node->setRightOfWay(attrs.getOpt<RightOfWay>(SUMO_ATTR_RIGHT_OF_WAY, nodeID.c_str(), ok, node->getRightOfWay()));
     229       14089 :     node->setFringeType(attrs.getOpt<FringeType>(SUMO_ATTR_FRINGE, nodeID.c_str(), ok, node->getFringeType()));
     230             :     // set optional name
     231       14089 :     if (attrs.hasAttribute(SUMO_ATTR_NAME)) {
     232           4 :         node->setName(attrs.get<std::string>(SUMO_ATTR_NAME, nodeID.c_str(), ok));
     233             :     }
     234       14089 :     return node;
     235       14089 : }
     236             : 
     237             : 
     238             : void
     239          11 : NIXMLNodesHandler::deleteNode(const SUMOSAXAttributes& attrs) {
     240          11 :     bool ok = true;
     241             :     // get the id, report a warning if not given or empty...
     242          11 :     myID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
     243          11 :     if (!ok) {
     244           0 :         return;
     245             :     }
     246          11 :     NBNode* node = myNodeCont.retrieve(myID);
     247          11 :     if (node == nullptr) {
     248           0 :         WRITE_WARNING("Ignoring tag '" + toString(SUMO_TAG_DEL) + "' for unknown node '" +
     249             :                       myID + "'");
     250           0 :         return;
     251             :     } else {
     252          11 :         myNodeCont.extract(node, true);
     253             :     }
     254             : }
     255             : 
     256             : 
     257             : void
     258          10 : NIXMLNodesHandler::addJoinCluster(const SUMOSAXAttributes& attrs) {
     259          10 :     bool ok = true;
     260          10 :     const std::string clusterString = attrs.get<std::string>(SUMO_ATTR_NODES, nullptr, ok);
     261          10 :     const std::set<std::string>& cluster = StringTokenizer(clusterString).getSet();
     262             : 
     263          22 :     myID = attrs.getOpt<std::string>(SUMO_ATTR_ID, nullptr, ok, myNodeCont.createClusterId(cluster));
     264             : 
     265          10 :     Position pos = Position::INVALID;
     266          10 :     if (attrs.hasAttribute(SUMO_ATTR_X)) {
     267           1 :         pos.setx(attrs.get<double>(SUMO_ATTR_X, myID.c_str(), ok));
     268             :     }
     269          10 :     if (attrs.hasAttribute(SUMO_ATTR_Y)) {
     270           1 :         pos.sety(attrs.get<double>(SUMO_ATTR_Y, myID.c_str(), ok));
     271             :     }
     272          10 :     if (attrs.hasAttribute(SUMO_ATTR_Z)) {
     273           1 :         pos.setz(attrs.get<double>(SUMO_ATTR_Z, myID.c_str(), ok));
     274             :     }
     275             : 
     276          10 :     NBNode* node = processNodeType(attrs, nullptr, myID, pos, false, myNodeCont, myEdgeCont, myTLLogicCont);
     277          10 :     if (ok) {
     278          10 :         myNodeCont.addCluster2Join(cluster, node);
     279             :     }
     280          10 : }
     281             : 
     282             : 
     283             : void
     284           1 : NIXMLNodesHandler::addJoinExclusion(const SUMOSAXAttributes& attrs) {
     285           1 :     bool ok = true;
     286           2 :     const std::vector<std::string> ids = StringTokenizer(
     287           2 :             attrs.get<std::string>(SUMO_ATTR_NODES, nullptr, ok)).getVector();
     288           1 :     if (ok) {
     289           1 :         myNodeCont.addJoinExclusion(ids);
     290             :     }
     291           1 : }
     292             : 
     293             : 
     294             : void
     295         613 : NIXMLNodesHandler::processTrafficLightDefinitions(const SUMOSAXAttributes& attrs,
     296             :         NBNode* currentNode, NBTrafficLightLogicCont& tlc) {
     297             :     // try to get the tl-id
     298             :     // if a tl-id is given, we will look whether this tl already exists
     299             :     //  if so, we will add the node to it (and to all programs with this id), otherwise allocate a new one with this id
     300             :     // if no tl-id exists, we will build a tl with the node's id
     301             :     std::set<NBTrafficLightDefinition*> tlDefs;
     302         613 :     bool ok = true;
     303             : 
     304         613 :     std::string oldTlID = "";
     305        1226 :     std::string oldTypeS = OptionsCont::getOptions().getString("tls.default-type");
     306             : 
     307         613 :     if (currentNode->isTLControlled()) {
     308          18 :         NBTrafficLightDefinition* oldDef = *(currentNode->getControllingTLS().begin());
     309             :         oldTlID = oldDef->getID();
     310          36 :         oldTypeS = toString(oldDef->getType());
     311             :     }
     312        1226 :     std::string tlID = attrs.getOpt<std::string>(SUMO_ATTR_TLID, nullptr, ok, oldTlID);
     313        1226 :     std::string typeS = attrs.getOpt<std::string>(SUMO_ATTR_TLTYPE, nullptr, ok, oldTypeS);
     314         613 :     if (tlID != oldTlID || typeS != oldTypeS) {
     315         329 :         currentNode->removeTrafficLights();
     316             :     }
     317             :     TrafficLightType type;
     318         613 :     if (SUMOXMLDefinitions::TrafficLightTypes.hasString(typeS)) {
     319         613 :         type = SUMOXMLDefinitions::TrafficLightTypes.get(typeS);
     320             :     } else {
     321           0 :         WRITE_ERRORF(TL("Unknown traffic light type '%' for node '%'."), typeS, currentNode->getID());
     322           0 :         return;
     323             :     }
     324             :     TrafficLightLayout layout = TrafficLightLayout::DEFAULT;
     325         613 :     if (attrs.hasAttribute(SUMO_ATTR_TLLAYOUT)) {
     326           9 :         std::string layoutS = attrs.get<std::string>(SUMO_ATTR_TLLAYOUT, nullptr, ok);
     327           9 :         if (SUMOXMLDefinitions::TrafficLightLayouts.hasString(layoutS)) {
     328           9 :             layout = SUMOXMLDefinitions::TrafficLightLayouts.get(layoutS);
     329             :         } else {
     330           0 :             WRITE_ERRORF(TL("Unknown traffic light layout '%' for node '%'."), typeS, currentNode->getID());
     331             :             return;
     332             :         }
     333             :     }
     334         613 :     if (tlID != "" && tlc.getPrograms(tlID).size() > 0) {
     335             :         // we already have definitions for this tlID
     336          96 :         for (auto item : tlc.getPrograms(tlID)) {
     337          48 :             NBTrafficLightDefinition* def = item.second;
     338             :             tlDefs.insert(def);
     339          48 :             def->addNode(currentNode);
     340          48 :             if (def->getType() != type && attrs.hasAttribute(SUMO_ATTR_TLTYPE)) {
     341           3 :                 WRITE_WARNINGF(TL("Changing traffic light type '%' to '%' for tl '%'."), toString(def->getType()), typeS, tlID);
     342           1 :                 def->setType(type);
     343           1 :                 if (type != TrafficLightType::STATIC && dynamic_cast<NBLoadedSUMOTLDef*>(def) != nullptr) {
     344           1 :                     dynamic_cast<NBLoadedSUMOTLDef*>(def)->guessMinMaxDuration();
     345             :                 }
     346             :             }
     347          48 :             if (layout != TrafficLightLayout::DEFAULT && dynamic_cast<NBOwnTLDef*>(def) != nullptr) {
     348             :                 dynamic_cast<NBOwnTLDef*>(def)->setLayout(layout);
     349             :             }
     350             :         }
     351             :     } else {
     352             :         // we need to add a new defition
     353         565 :         tlID = (tlID == "" ? currentNode->getID() : tlID);
     354         565 :         NBOwnTLDef* tlDef = new NBOwnTLDef(tlID, currentNode, 0, type);
     355         565 :         if (!tlc.insert(tlDef)) {
     356             :             // actually, nothing should fail here
     357           0 :             delete tlDef;
     358           0 :             throw ProcessError(TLF("Could not allocate tls '%'.", currentNode->getID()));
     359             :         }
     360             :         tlDef->setLayout(layout);
     361         565 :         tlDefs.insert(tlDef);
     362             :     }
     363             :     // process inner edges which shall be controlled
     364         613 :     const std::vector<std::string>& controlledInner = attrs.getOpt<std::vector<std::string> >(SUMO_ATTR_CONTROLLED_INNER, nullptr, ok);
     365         613 :     if (controlledInner.size() != 0) {
     366          44 :         for (std::set<NBTrafficLightDefinition*>::iterator it = tlDefs.begin(); it != tlDefs.end(); it++) {
     367          22 :             (*it)->addControlledInnerEdges(controlledInner);
     368             :         }
     369             :     }
     370         613 : }
     371             : 
     372             : 
     373             : /****************************************************************************/

Generated by: LCOV version 1.14