LCOV - code coverage report
Current view: top level - src/netimport - NIXMLTrafficLightsHandler.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 86.6 % 157 136
Test Date: 2024-11-20 15:55:46 Functions: 90.0 % 10 9

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2011-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    NIXMLTrafficLightsHandler.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Michael Behrisch
      17              : /// @author  Jakob Erdmann
      18              : /// @date    2011-10-05
      19              : ///
      20              : // Importer for traffic lights stored in XML
      21              : /****************************************************************************/
      22              : #include <config.h>
      23              : 
      24              : #include <string>
      25              : #include <iostream>
      26              : #include <utils/common/StringTokenizer.h>
      27              : #include <utils/xml/SUMOSAXHandler.h>
      28              : #include <utils/xml/SUMOXMLDefinitions.h>
      29              : #include <utils/common/ToString.h>
      30              : #include <utils/common/StringUtils.h>
      31              : #include <utils/common/UtilExceptions.h>
      32              : #include <utils/common/MsgHandler.h>
      33              : #include <utils/options/OptionsCont.h>
      34              : #include <netbuild/NBEdge.h>
      35              : #include <netbuild/NBEdgeCont.h>
      36              : #include <netbuild/NBNode.h>
      37              : #include <netbuild/NBOwnTLDef.h>
      38              : #include <netbuild/NBLoadedSUMOTLDef.h>
      39              : #include <netbuild/NBTrafficLightLogicCont.h>
      40              : #include "NIImporter_SUMO.h"
      41              : #include "NIXMLTrafficLightsHandler.h"
      42              : 
      43              : 
      44              : // ===========================================================================
      45              : // method definitions
      46              : // ===========================================================================
      47         1826 : NIXMLTrafficLightsHandler::NIXMLTrafficLightsHandler(
      48         1826 :     NBTrafficLightLogicCont& tlCont, NBEdgeCont& ec, bool ignoreUnknown) :
      49              :     SUMOSAXHandler("xml-tllogics"),
      50         1826 :     myTLLCont(tlCont),
      51         1826 :     myEdgeCont(ec),
      52         1826 :     myCurrentTL(nullptr),
      53         1826 :     myResetPhases(false),
      54         3652 :     myIgnoreUnknown(ignoreUnknown)
      55         1826 : { }
      56              : 
      57              : 
      58         1826 : NIXMLTrafficLightsHandler::~NIXMLTrafficLightsHandler() {}
      59              : 
      60              : 
      61              : void
      62          496 : NIXMLTrafficLightsHandler::myStartElement(
      63              :     int element, const SUMOSAXAttributes& attrs) {
      64          496 :     switch (element) {
      65           44 :         case SUMO_TAG_TLLOGIC:
      66           44 :             myCurrentTL = initTrafficLightLogic(attrs, myCurrentTL);
      67           44 :             break;
      68          236 :         case SUMO_TAG_PHASE:
      69          236 :             if (myCurrentTL != nullptr) {
      70          236 :                 if (myResetPhases) {
      71           42 :                     myCurrentTL->getLogic()->resetPhases();
      72           42 :                     myResetPhases = false;
      73              :                 }
      74          236 :                 NIImporter_SUMO::addPhase(attrs, myCurrentTL);
      75          235 :                 myCurrentTL->phasesLoaded();
      76              :             }
      77              :             break;
      78          128 :         case SUMO_TAG_CONNECTION:
      79          128 :             addTlConnection(attrs);
      80          128 :             break;
      81           50 :         case SUMO_TAG_DEL:
      82           50 :             removeTlConnection(attrs);
      83           50 :             break;
      84            1 :         case SUMO_TAG_PARAM:
      85            1 :             if (myCurrentTL != nullptr) {
      86            1 :                 bool ok = true;
      87            1 :                 const std::string key = attrs.get<std::string>(SUMO_ATTR_KEY, nullptr, ok);
      88              :                 // circumventing empty string test
      89            1 :                 const std::string val = attrs.hasAttribute(SUMO_ATTR_VALUE) ? attrs.getString(SUMO_ATTR_VALUE) : "";
      90            1 :                 myCurrentTL->setParameter(key, val);
      91              :             }
      92              :             break;
      93              :         default:
      94              :             break;
      95              :     }
      96          495 : }
      97              : 
      98              : 
      99              : void
     100          493 : NIXMLTrafficLightsHandler::myEndElement(int element) {
     101          493 :     switch (element) {
     102           43 :         case SUMO_TAG_TLLOGIC:
     103           43 :             myCurrentTL = nullptr;
     104           43 :             break;
     105              :         default:
     106              :             break;
     107              :     }
     108          493 : }
     109              : 
     110              : 
     111              : NBLoadedSUMOTLDef*
     112           44 : NIXMLTrafficLightsHandler::initTrafficLightLogic(const SUMOSAXAttributes& attrs, NBLoadedSUMOTLDef* currentTL) {
     113           44 :     if (currentTL) {
     114            0 :         WRITE_ERRORF(TL("Definition of tlLogic '%' was not finished."), currentTL->getID());
     115            0 :         return nullptr;
     116              :     }
     117           44 :     bool ok = true;
     118           44 :     std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
     119           88 :     std::string programID = attrs.getOpt<std::string>(SUMO_ATTR_PROGRAMID, id.c_str(), ok, "UNKNOWN_PROGRAM");
     120           44 :     const SUMOTime offset = attrs.getOptOffsetReporting(SUMO_ATTR_OFFSET, id.c_str(), ok, 0);
     121              :     std::string typeS = attrs.getOpt<std::string>(SUMO_ATTR_TYPE, nullptr, ok,
     122           88 :                         OptionsCont::getOptions().getString("tls.default-type"));
     123              :     TrafficLightType type;
     124              :     if (SUMOXMLDefinitions::TrafficLightTypes.hasString(typeS)) {
     125           44 :         type = SUMOXMLDefinitions::TrafficLightTypes.get(typeS);
     126              :     } else {
     127            0 :         WRITE_ERRORF(TL("Unknown traffic light type '%' for tlLogic '%'."), typeS, id);
     128            0 :         return nullptr;
     129              :     }
     130              :     // there are three scenarios to consider
     131              :     // 1) the tll.xml is loaded to update traffic lights defined in a net.xml:
     132              :     //   simply retrieve the loaded definitions and update them
     133              :     // 2) the tll.xml is loaded to define new traffic lights
     134              :     //   nod.xml will have triggered building of NBOwnTLDef. Replace it with NBLoadedSUMOTLDef
     135              :     // 3) the tll.xml is loaded to define new programs for a defined traffic light
     136              :     //   there should be a definition with the same id but different programID
     137           44 :     const std::map<std::string, NBTrafficLightDefinition*>& programs = myTLLCont.getPrograms(id);
     138           44 :     if (programs.size() == 0) {
     139            0 :         if (!myIgnoreUnknown) {
     140            0 :             WRITE_ERRORF(TL("Cannot load traffic light program for unknown id '%', programID '%'."), id, programID);
     141              :         }
     142            0 :         return nullptr;
     143              :     }
     144              :     const std::string existingProgram = programs.begin()->first; // arbitrary for our purpose
     145           44 :     NBLoadedSUMOTLDef* loadedDef = dynamic_cast<NBLoadedSUMOTLDef*>(myTLLCont.getDefinition(id, programID));
     146           29 :     if (loadedDef == nullptr) {
     147           33 :         NBLoadedSUMOTLDef* oldDef = dynamic_cast<NBLoadedSUMOTLDef*>(myTLLCont.getDefinition(id, existingProgram));
     148           33 :         if (oldDef == nullptr) {
     149              :             // case 2
     150           22 :             NBTrafficLightDefinition* newDef = dynamic_cast<NBOwnTLDef*>(myTLLCont.getDefinition(
     151              :                                                    id, NBTrafficLightDefinition::DefaultProgramID));
     152              :             bool deleteDefault = false;
     153           22 :             if (newDef == nullptr) {
     154              :                 // the default program may have already been replaced with a loaded program
     155            0 :                 newDef = dynamic_cast<NBLoadedSUMOTLDef*>(myTLLCont.getDefinition(
     156              :                              id, NBTrafficLightDefinition::DefaultProgramID));
     157            0 :                 if (newDef == nullptr) {
     158            0 :                     WRITE_ERRORF(TL("Cannot load traffic light program for unknown id '%', programID '%'."), id, programID);
     159            0 :                     return nullptr;
     160              :                 }
     161              :             } else {
     162              :                 deleteDefault = true;
     163              :             }
     164              :             assert(newDef != nullptr);
     165           22 :             loadedDef = new NBLoadedSUMOTLDef(id, programID, offset, type);
     166              :             // copy nodes and controlled inner edges
     167           44 :             for (NBNode* const n : newDef->getNodes()) {
     168           22 :                 loadedDef->addNode(n);
     169              :             }
     170           22 :             loadedDef->addControlledInnerEdges(newDef->getControlledInnerEdges());
     171           22 :             if (deleteDefault) {
     172              :                 // make a copy because the vector is modified in the loop
     173           22 :                 const std::vector<NBNode*> nodes = newDef->getNodes();
     174              :                 // replace default Program
     175           44 :                 for (NBNode* const n : nodes) {
     176           22 :                     n->removeTrafficLight(newDef);
     177              :                 }
     178           66 :                 myTLLCont.removeProgram(id, NBTrafficLightDefinition::DefaultProgramID);
     179           22 :             }
     180           22 :             myTLLCont.insert(loadedDef);
     181              :         } else {
     182              :             // case 3
     183              :             NBTrafficLightLogic* oldLogic = oldDef->getLogic();
     184           11 :             NBTrafficLightLogic newLogic(id, programID, oldLogic->getNumLinks(), offset, type);
     185           11 :             loadedDef = new NBLoadedSUMOTLDef(*oldDef, newLogic);
     186              :             // copy nodes
     187           11 :             std::vector<NBNode*> nodes = oldDef->getNodes();
     188           23 :             for (std::vector<NBNode*>::iterator it = nodes.begin(); it != nodes.end(); it++) {
     189           12 :                 loadedDef->addNode(*it);
     190              :             }
     191              :             //std::cout << " case3 oldDef=" << oldDef->getDescription() << " loadedDef=" << loadedDef->getDescription() << "\n";
     192           11 :             myTLLCont.insert(loadedDef);
     193           11 :         }
     194              :     } else {
     195              :         // case 1
     196           11 :         if (attrs.hasAttribute(SUMO_ATTR_OFFSET)) {
     197            6 :             loadedDef->setOffset(offset);
     198              :         }
     199           11 :         if (attrs.hasAttribute(SUMO_ATTR_TYPE)) {
     200            6 :             loadedDef->setType(type);
     201              :         }
     202              :     }
     203           44 :     if (ok) {
     204           44 :         myResetPhases = true;
     205              :         mySeenIDs.insert(id);
     206              :         return loadedDef;
     207              :     } else {
     208              :         return nullptr;
     209              :     }
     210              : }
     211              : 
     212              : 
     213              : void
     214          128 : NIXMLTrafficLightsHandler::addTlConnection(const SUMOSAXAttributes& attrs) {
     215          128 :     bool ok = true;
     216              :     // parse identifying attributes
     217          128 :     NBEdge* from = retrieveEdge(attrs, SUMO_ATTR_FROM, ok);
     218          128 :     NBEdge* to = retrieveEdge(attrs, SUMO_ATTR_TO, ok);
     219          128 :     if (!ok) {
     220            6 :         return;
     221              :     }
     222          128 :     int fromLane = retrieveLaneIndex(attrs, SUMO_ATTR_FROM_LANE, from, ok);
     223          128 :     int toLane = retrieveLaneIndex(attrs, SUMO_ATTR_TO_LANE, to, ok);
     224          128 :     if (!ok) {
     225              :         return;
     226              :     }
     227              :     // retrieve connection
     228              :     const std::vector<NBEdge::Connection>& connections = from->getConnections();
     229              :     std::vector<NBEdge::Connection>::const_iterator con_it;
     230          128 :     con_it = find_if(connections.begin(), connections.end(),
     231              :                      NBEdge::connections_finder(fromLane, to, toLane));
     232          128 :     if (con_it == connections.end()) {
     233           30 :         WRITE_ERROR("Connection from=" + from->getID() + " to=" + to->getID() +
     234              :                     " fromLane=" + toString(fromLane) + " toLane=" + toString(toLane) + " not found");
     235            6 :         return;
     236              :     }
     237          122 :     NBEdge::Connection c = *con_it;
     238              :     // read other  attributes
     239          122 :     std::string tlID = attrs.getOpt<std::string>(SUMO_ATTR_TLID, nullptr, ok, "");
     240          122 :     if (tlID == "") {
     241              :         // we are updating an existing tl-controlled connection
     242            8 :         tlID = (*(from->getToNode()->getControllingTLS().begin()))->getID();
     243              :         assert(tlID != "");
     244              :     }
     245          122 :     int tlIndex = attrs.getOpt<int>(SUMO_ATTR_TLLINKINDEX, nullptr, ok, -1);
     246          122 :     if (tlIndex == -1) {
     247              :         // we are updating an existing tl-controlled connection
     248            0 :         tlIndex = c.tlLinkIndex;
     249              :     }
     250          122 :     int tlIndex2 = attrs.getOpt<int>(SUMO_ATTR_TLLINKINDEX2, nullptr, ok, -1);
     251          122 :     if (tlIndex2 == -1) {
     252              :         // we are updating an existing tl-controlled connection or index2 is not used
     253          122 :         tlIndex2 = c.tlLinkIndex2;
     254              :     }
     255              : 
     256              :     // register the connection with all definitions
     257          122 :     const std::map<std::string, NBTrafficLightDefinition*>& programs = myTLLCont.getPrograms(tlID);
     258          122 :     if (programs.size() > 0) {
     259              :         std::map<std::string, NBTrafficLightDefinition*>::const_iterator it;
     260          253 :         for (it = programs.begin(); it != programs.end(); it++) {
     261          131 :             NBLoadedSUMOTLDef* tlDef = dynamic_cast<NBLoadedSUMOTLDef*>(it->second);
     262          131 :             if (tlDef) {
     263          131 :                 tlDef->addConnection(from, c.toEdge, c.fromLane, c.toLane, tlIndex, tlIndex2,  false);
     264              :             } else {
     265              :                 throw ProcessError("Corrupt traffic light definition '"
     266            0 :                                    + tlID + "' (program '" + it->first + "')");
     267              :             }
     268              :         }
     269              :     } else {
     270              :         SumoXMLNodeType type = from->getToNode()->getType();
     271            0 :         if (type != SumoXMLNodeType::RAIL_CROSSING && type != SumoXMLNodeType::RAIL_SIGNAL) {
     272            0 :             WRITE_ERRORF(TL("The traffic light '%' is not known."), tlID);
     273              :         }
     274              :     }
     275          122 : }
     276              : 
     277              : 
     278              : void
     279           50 : NIXMLTrafficLightsHandler::removeTlConnection(const SUMOSAXAttributes& attrs) {
     280           50 :     bool ok = true;
     281           50 :     std::string tlID = attrs.get<std::string>(SUMO_ATTR_TLID, nullptr, ok);
     282              :     // does the traffic light still exist?
     283           50 :     const std::map<std::string, NBTrafficLightDefinition*>& programs = myTLLCont.getPrograms(tlID);
     284           50 :     if (programs.size() > 0) {
     285              :         // parse identifying attributes
     286           31 :         NBEdge* from = retrieveEdge(attrs, SUMO_ATTR_FROM, ok);
     287           31 :         NBEdge* to = retrieveEdge(attrs, SUMO_ATTR_TO, ok);
     288              :         int fromLane = -1;
     289              :         int toLane = -1;
     290           31 :         if (ok) {
     291           31 :             fromLane = retrieveLaneIndex(attrs, SUMO_ATTR_FROM_LANE, from, ok, true);
     292           31 :             toLane = retrieveLaneIndex(attrs, SUMO_ATTR_TO_LANE, to, ok, true);
     293              :         }
     294           31 :         int tlIndex = attrs.get<int>(SUMO_ATTR_TLLINKINDEX, nullptr, ok);
     295              : 
     296           31 :         NBConnection conn(from, fromLane, to, toLane, tlIndex);
     297              :         // remove the connection from all definitions
     298              :         std::map<std::string, NBTrafficLightDefinition*>::const_iterator it;
     299           62 :         for (it = programs.begin(); it != programs.end(); it++) {
     300           31 :             NBLoadedSUMOTLDef* tlDef = dynamic_cast<NBLoadedSUMOTLDef*>(it->second);
     301           31 :             if (tlDef) {
     302           31 :                 tlDef->removeConnection(conn, false);
     303              :             } else {
     304              :                 throw ProcessError("Corrupt traffic light definition '"
     305            0 :                                    + tlID + "' (program '" + it->first + "')");
     306              :             }
     307              :         }
     308           31 :     }
     309           50 : }
     310              : 
     311              : 
     312              : NBEdge*
     313          318 : NIXMLTrafficLightsHandler::retrieveEdge(
     314              :     const SUMOSAXAttributes& attrs, SumoXMLAttr attr, bool& ok) {
     315          318 :     std::string edgeID = attrs.get<std::string>(attr, nullptr, ok);
     316          318 :     NBEdge* edge = myEdgeCont.retrieve(edgeID, true);
     317          318 :     if (edge == nullptr) {
     318            0 :         WRITE_ERRORF(TL("Unknown edge '%' given in connection."), edgeID);
     319            0 :         ok = false;
     320              :     }
     321          318 :     return edge;
     322              : }
     323              : 
     324              : 
     325              : int
     326          318 : NIXMLTrafficLightsHandler::retrieveLaneIndex(
     327              :     const SUMOSAXAttributes& attrs, SumoXMLAttr attr, NBEdge* edge, bool& ok, bool isDelete) {
     328          318 :     int laneIndex = attrs.get<int>(attr, nullptr, ok);
     329          318 :     if (edge->getNumLanes() <= laneIndex) {
     330            0 :         if (!isDelete) {
     331            0 :             WRITE_ERRORF(TL("Invalid lane index '%' for edge '%'."), toString(laneIndex), edge->getID());
     332              :         }
     333            0 :         ok = false;
     334              :     }
     335          318 :     return laneIndex;
     336              : }
     337              : 
     338              : 
     339              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1