LCOV - code coverage report
Current view: top level - src/netimport - NIXMLNodesHandler.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 92.5 % 173 160
Test Date: 2024-11-20 15:55:46 Functions: 90.9 % 11 10

            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         1884 : NIXMLNodesHandler::NIXMLNodesHandler(NBNodeCont& nc, NBEdgeCont& ec,
      47              :                                      NBTrafficLightLogicCont& tlc,
      48         1884 :                                      OptionsCont& options) :
      49              :     SUMOSAXHandler("xml-nodes - file"),
      50         1884 :     myOptions(options),
      51         1884 :     myNodeCont(nc),
      52         1884 :     myEdgeCont(ec),
      53         1884 :     myTLLogicCont(tlc),
      54         1884 :     myLocation(nullptr),
      55         3768 :     myLastParameterised(nullptr) {
      56         1884 : }
      57              : 
      58              : 
      59         1884 : NIXMLNodesHandler::~NIXMLNodesHandler() {
      60         1884 :     delete myLocation;
      61         1884 : }
      62              : 
      63              : 
      64              : void
      65        13125 : NIXMLNodesHandler::myStartElement(int element,
      66              :                                   const SUMOSAXAttributes& attrs) {
      67        13125 :     switch (element) {
      68          522 :         case SUMO_TAG_LOCATION:
      69          522 :             myLocation = NIImporter_SUMO::loadLocation(attrs);
      70          522 :             if (myLocation) {
      71          522 :                 GeoConvHelper::setLoadedPlain(getFileName(), *myLocation);
      72              :             }
      73              :             break;
      74        11407 :         case SUMO_TAG_NODE:
      75        11407 :             addNode(attrs);
      76        11406 :             break;
      77            9 :         case SUMO_TAG_JOIN:
      78            9 :             addJoinCluster(attrs);
      79            9 :             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          149 :         case SUMO_TAG_PARAM:
      87          149 :             if (myLastParameterised != nullptr) {
      88          149 :                 bool ok = true;
      89          149 :                 const std::string key = attrs.get<std::string>(SUMO_ATTR_KEY, nullptr, ok);
      90              :                 // circumventing empty string test
      91          149 :                 const std::string val = attrs.hasAttribute(SUMO_ATTR_VALUE) ? attrs.getString(SUMO_ATTR_VALUE) : "";
      92          149 :                 myLastParameterised->setParameter(key, val);
      93              :             }
      94              :             break;
      95              :         default:
      96              :             break;
      97              :     }
      98        13124 : }
      99              : 
     100              : 
     101              : void
     102        13123 : NIXMLNodesHandler::myEndElement(int element) {
     103        13123 :     switch (element) {
     104        11406 :         case SUMO_TAG_NODE:
     105        11406 :             myLastParameterised = nullptr;
     106        11406 :             break;
     107              :         default:
     108              :             break;
     109              :     }
     110        13123 : }
     111              : 
     112              : 
     113              : void
     114        11407 : NIXMLNodesHandler::addNode(const SUMOSAXAttributes& attrs) {
     115        11407 :     bool ok = true;
     116              :     // get the id, report a warning if not given or empty...
     117        11407 :     myID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
     118        11407 :     if (!ok) {
     119            0 :         return;
     120              :     }
     121        11407 :     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        11407 :     if (node != nullptr) {
     127         1332 :         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        11407 :     if (attrs.hasAttribute(SUMO_ATTR_X)) {
     134        11382 :         myPosition.set(attrs.get<double>(SUMO_ATTR_X, myID.c_str(), ok), myPosition.y());
     135              :         xOk = true;
     136              :         needConversion = true;
     137              :     }
     138        11407 :     if (attrs.hasAttribute(SUMO_ATTR_Y)) {
     139        11383 :         myPosition.set(myPosition.x(), attrs.get<double>(SUMO_ATTR_Y, myID.c_str(), ok));
     140              :         yOk = true;
     141              :         needConversion = true;
     142              :     }
     143        11407 :     if (attrs.hasAttribute(SUMO_ATTR_Z)) {
     144           37 :         myPosition.set(myPosition.x(), myPosition.y(), attrs.get<double>(SUMO_ATTR_Z, myID.c_str(), ok));
     145              :     }
     146        11407 :     if (xOk && yOk) {
     147        11407 :         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        11407 :     bool updateEdgeGeometries = node != nullptr && myPosition != node->getPosition();
     154        11407 :     node = processNodeType(attrs, node, myID, myPosition, updateEdgeGeometries, myNodeCont, myEdgeCont, myTLLogicCont, myLocation);
     155        11406 :     myLastParameterised = node;
     156              : }
     157              : 
     158              : 
     159              : NBNode*
     160        11612 : 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              :                                    GeoConvHelper* from_srs) {
     164        11612 :     bool ok = true;
     165              :     // get the type
     166              :     SumoXMLNodeType type = SumoXMLNodeType::UNKNOWN;
     167        11612 :     if (node != nullptr) {
     168              :         type = node->getType();
     169              :     }
     170        23224 :     std::string typeS = attrs.getOpt<std::string>(SUMO_ATTR_TYPE, nodeID.c_str(), ok, "");
     171              :     if (SUMOXMLDefinitions::NodeTypes.hasString(typeS)) {
     172         5977 :         type = SUMOXMLDefinitions::NodeTypes.get(typeS);
     173         5977 :         if (type == SumoXMLNodeType::DEAD_END_DEPRECATED || type == SumoXMLNodeType::DEAD_END) {
     174              :             // dead end is a computed status. Reset this to unknown so it will
     175              :             // be corrected if additional connections are loaded
     176              :             type = SumoXMLNodeType::UNKNOWN;
     177              :         }
     178              :     }
     179              :     std::set<NBTrafficLightDefinition*> oldTLS;
     180              :     // check whether a prior node shall be modified
     181              :     const bool isPatch = node != nullptr;
     182        11612 :     if (node == nullptr) {
     183        10084 :         node = new NBNode(nodeID, position, type);
     184        10083 :         if (!nc.insert(node)) {
     185            0 :             throw ProcessError(TLF("Could not insert node though checked this before (id='%').", nodeID));
     186              :         }
     187              :     } else {
     188              :         // patch information
     189              :         oldTLS = node->getControllingTLS();
     190              :         if (node->getType() == SumoXMLNodeType::PRIORITY
     191         1528 :                 && (type == SumoXMLNodeType::RIGHT_BEFORE_LEFT || type == SumoXMLNodeType::LEFT_BEFORE_RIGHT)) {
     192            4 :             ec.removeRoundabout(node);
     193              :         }
     194         1528 :         node->reinit(position, type, updateEdgeGeometries);
     195              :     }
     196              :     // process traffic light definition
     197        11611 :     if (NBNode::isTrafficLight(type)) {
     198          571 :         processTrafficLightDefinitions(attrs, node, tlc);
     199        11040 :     } else if (isPatch && typeS != "") {
     200           21 :         nc.markAsNotTLS(node);
     201              :     }
     202              :     // remove previously set tls if this node is not controlled by them
     203        11630 :     for (std::set<NBTrafficLightDefinition*>::iterator i = oldTLS.begin(); i != oldTLS.end(); ++i) {
     204           19 :         if ((*i)->getNodes().size() == 0) {
     205           29 :             tlc.removeFully((*i)->getID());
     206              :         }
     207              :     }
     208              : 
     209              :     // set optional shape
     210        11611 :     PositionVector shape;
     211        11611 :     if (attrs.hasAttribute(SUMO_ATTR_SHAPE)) {
     212           36 :         shape = attrs.getOpt<PositionVector>(SUMO_ATTR_SHAPE, nodeID.c_str(), ok, PositionVector());
     213           18 :         if (!NBNetBuilder::transformCoordinates(shape, true, from_srs)) {
     214            0 :             WRITE_ERRORF(TL("Unable to project node shape at node '%'."), node->getID());
     215              :         }
     216           18 :         if (shape.size() > 2) {
     217           17 :             shape.closePolygon();
     218              :         }
     219           18 :         node->setCustomShape(shape);
     220              :     }
     221              :     // set optional radius
     222        11611 :     if (attrs.hasAttribute(SUMO_ATTR_RADIUS)) {
     223              :         node->setRadius(attrs.get<double>(SUMO_ATTR_RADIUS, nodeID.c_str(), ok));
     224              :     }
     225              :     // set optional keepClear flag
     226        11611 :     if (attrs.hasAttribute(SUMO_ATTR_KEEP_CLEAR)) {
     227            1 :         node->setKeepClear(attrs.get<bool>(SUMO_ATTR_KEEP_CLEAR, nodeID.c_str(), ok));
     228              :     }
     229        11611 :     node->setRightOfWay(attrs.getOpt<RightOfWay>(SUMO_ATTR_RIGHT_OF_WAY, nodeID.c_str(), ok, node->getRightOfWay()));
     230        11611 :     node->setFringeType(attrs.getOpt<FringeType>(SUMO_ATTR_FRINGE, nodeID.c_str(), ok, node->getFringeType()));
     231              :     // set optional name
     232        11611 :     if (attrs.hasAttribute(SUMO_ATTR_NAME)) {
     233            4 :         node->setName(attrs.get<std::string>(SUMO_ATTR_NAME, nodeID.c_str(), ok));
     234              :     }
     235        11611 :     return node;
     236        11611 : }
     237              : 
     238              : 
     239              : void
     240           11 : NIXMLNodesHandler::deleteNode(const SUMOSAXAttributes& attrs) {
     241           11 :     bool ok = true;
     242              :     // get the id, report a warning if not given or empty...
     243           11 :     myID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
     244           11 :     if (!ok) {
     245            0 :         return;
     246              :     }
     247           11 :     NBNode* node = myNodeCont.retrieve(myID);
     248           11 :     if (node == nullptr) {
     249            0 :         WRITE_WARNING("Ignoring tag '" + toString(SUMO_TAG_DEL) + "' for unknown node '" +
     250              :                       myID + "'");
     251            0 :         return;
     252              :     } else {
     253           11 :         myNodeCont.extract(node, true);
     254              :     }
     255              : }
     256              : 
     257              : 
     258              : void
     259            9 : NIXMLNodesHandler::addJoinCluster(const SUMOSAXAttributes& attrs) {
     260            9 :     bool ok = true;
     261            9 :     const std::string clusterString = attrs.get<std::string>(SUMO_ATTR_NODES, nullptr, ok);
     262            9 :     const std::set<std::string>& cluster = StringTokenizer(clusterString).getSet();
     263              : 
     264            9 :     myID = attrs.getOpt<std::string>(SUMO_ATTR_ID, nullptr, ok, myNodeCont.createClusterId(cluster));
     265              : 
     266            9 :     Position pos = Position::INVALID;
     267            9 :     if (attrs.hasAttribute(SUMO_ATTR_X)) {
     268            1 :         pos.setx(attrs.get<double>(SUMO_ATTR_X, myID.c_str(), ok));
     269              :     }
     270            9 :     if (attrs.hasAttribute(SUMO_ATTR_Y)) {
     271            1 :         pos.sety(attrs.get<double>(SUMO_ATTR_Y, myID.c_str(), ok));
     272              :     }
     273            9 :     if (attrs.hasAttribute(SUMO_ATTR_Z)) {
     274            1 :         pos.setz(attrs.get<double>(SUMO_ATTR_Z, myID.c_str(), ok));
     275              :     }
     276              : 
     277            9 :     NBNode* node = processNodeType(attrs, nullptr, myID, pos, false, myNodeCont, myEdgeCont, myTLLogicCont, myLocation);
     278            9 :     if (ok) {
     279            9 :         myNodeCont.addCluster2Join(cluster, node);
     280              :     }
     281            9 : }
     282              : 
     283              : 
     284              : void
     285            1 : NIXMLNodesHandler::addJoinExclusion(const SUMOSAXAttributes& attrs) {
     286            1 :     bool ok = true;
     287            2 :     const std::vector<std::string> ids = StringTokenizer(
     288            2 :             attrs.get<std::string>(SUMO_ATTR_NODES, nullptr, ok)).getVector();
     289            1 :     if (ok) {
     290            1 :         myNodeCont.addJoinExclusion(ids);
     291              :     }
     292            1 : }
     293              : 
     294              : 
     295              : void
     296          571 : NIXMLNodesHandler::processTrafficLightDefinitions(const SUMOSAXAttributes& attrs,
     297              :         NBNode* currentNode, NBTrafficLightLogicCont& tlc) {
     298              :     // try to get the tl-id
     299              :     // if a tl-id is given, we will look whether this tl already exists
     300              :     //  if so, we will add the node to it (and to all programs with this id), otherwise allocate a new one with this id
     301              :     // if no tl-id exists, we will build a tl with the node's id
     302              :     std::set<NBTrafficLightDefinition*> tlDefs;
     303          571 :     bool ok = true;
     304              : 
     305          571 :     std::string oldTlID = "";
     306         1142 :     std::string oldTypeS = OptionsCont::getOptions().getString("tls.default-type");
     307              : 
     308          571 :     if (currentNode->isTLControlled()) {
     309           17 :         NBTrafficLightDefinition* oldDef = *(currentNode->getControllingTLS().begin());
     310              :         oldTlID = oldDef->getID();
     311           34 :         oldTypeS = toString(oldDef->getType());
     312              :     }
     313         1142 :     std::string tlID = attrs.getOpt<std::string>(SUMO_ATTR_TLID, nullptr, ok, oldTlID);
     314         1142 :     std::string typeS = attrs.getOpt<std::string>(SUMO_ATTR_TLTYPE, nullptr, ok, oldTypeS);
     315          571 :     if (tlID != oldTlID || typeS != oldTypeS) {
     316          358 :         currentNode->removeTrafficLights();
     317              :     }
     318              :     TrafficLightType type;
     319              :     if (SUMOXMLDefinitions::TrafficLightTypes.hasString(typeS)) {
     320          571 :         type = SUMOXMLDefinitions::TrafficLightTypes.get(typeS);
     321              :     } else {
     322            0 :         WRITE_ERRORF(TL("Unknown traffic light type '%' for node '%'."), typeS, currentNode->getID());
     323            0 :         return;
     324              :     }
     325              :     TrafficLightLayout layout = TrafficLightLayout::DEFAULT;
     326          571 :     if (attrs.hasAttribute(SUMO_ATTR_TLLAYOUT)) {
     327           19 :         std::string layoutS = attrs.get<std::string>(SUMO_ATTR_TLLAYOUT, nullptr, ok);
     328              :         if (SUMOXMLDefinitions::TrafficLightLayouts.hasString(layoutS)) {
     329           19 :             layout = SUMOXMLDefinitions::TrafficLightLayouts.get(layoutS);
     330              :         } else {
     331            0 :             WRITE_ERRORF(TL("Unknown traffic light layout '%' for node '%'."), typeS, currentNode->getID());
     332              :             return;
     333              :         }
     334              :     }
     335          571 :     if (tlID != "" && tlc.getPrograms(tlID).size() > 0) {
     336              :         // we already have definitions for this tlID
     337          110 :         for (auto item : tlc.getPrograms(tlID)) {
     338           55 :             NBTrafficLightDefinition* def = item.second;
     339              :             tlDefs.insert(def);
     340           55 :             def->addNode(currentNode);
     341           55 :             if (def->getType() != type && attrs.hasAttribute(SUMO_ATTR_TLTYPE)) {
     342            3 :                 WRITE_WARNINGF(TL("Changing traffic light type '%' to '%' for tl '%'."), toString(def->getType()), typeS, tlID);
     343            1 :                 def->setType(type);
     344            1 :                 if (type != TrafficLightType::STATIC && dynamic_cast<NBLoadedSUMOTLDef*>(def) != nullptr) {
     345            1 :                     dynamic_cast<NBLoadedSUMOTLDef*>(def)->guessMinMaxDuration();
     346              :                 }
     347              :             }
     348           55 :             if (layout != TrafficLightLayout::DEFAULT && dynamic_cast<NBOwnTLDef*>(def) != nullptr) {
     349              :                 dynamic_cast<NBOwnTLDef*>(def)->setLayout(layout);
     350              :             }
     351              :         }
     352              :     } else {
     353              :         // we need to add a new defition
     354          516 :         tlID = (tlID == "" ? currentNode->getID() : tlID);
     355          516 :         NBOwnTLDef* tlDef = new NBOwnTLDef(tlID, currentNode, 0, type);
     356          516 :         if (!tlc.insert(tlDef)) {
     357              :             // actually, nothing should fail here
     358            0 :             delete tlDef;
     359            0 :             throw ProcessError(TLF("Could not allocate tls '%'.", currentNode->getID()));
     360              :         }
     361              :         tlDef->setLayout(layout);
     362          516 :         tlDefs.insert(tlDef);
     363              :     }
     364              :     // process inner edges which shall be controlled
     365          571 :     const std::vector<std::string>& controlledInner = attrs.getOpt<std::vector<std::string> >(SUMO_ATTR_CONTROLLED_INNER, nullptr, ok);
     366          571 :     if (controlledInner.size() != 0) {
     367           48 :         for (std::set<NBTrafficLightDefinition*>::iterator it = tlDefs.begin(); it != tlDefs.end(); it++) {
     368           24 :             (*it)->addControlledInnerEdges(controlledInner);
     369              :         }
     370              :     }
     371          571 : }
     372              : 
     373              : 
     374              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1