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

Generated by: LCOV version 2.0-1