LCOV - code coverage report
Current view: top level - src/netimport - NIXMLTrafficLightsHandler.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 137 158 86.7 %
Date: 2024-05-02 15:31:40 Functions: 9 10 90.0 %

          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        2165 : NIXMLTrafficLightsHandler::NIXMLTrafficLightsHandler(
      48        2165 :     NBTrafficLightLogicCont& tlCont, NBEdgeCont& ec, bool ignoreUnknown) :
      49             :     SUMOSAXHandler("xml-tllogics"),
      50        2165 :     myTLLCont(tlCont),
      51        2165 :     myEdgeCont(ec),
      52        2165 :     myCurrentTL(nullptr),
      53        2165 :     myResetPhases(false),
      54        4330 :     myIgnoreUnknown(ignoreUnknown)
      55        2165 : { }
      56             : 
      57             : 
      58        2165 : NIXMLTrafficLightsHandler::~NIXMLTrafficLightsHandler() {}
      59             : 
      60             : 
      61             : void
      62         486 : NIXMLTrafficLightsHandler::myStartElement(
      63             :     int element, const SUMOSAXAttributes& attrs) {
      64         486 :     switch (element) {
      65          43 :         case SUMO_TAG_TLLOGIC:
      66          43 :             myCurrentTL = initTrafficLightLogic(attrs, myCurrentTL);
      67          43 :             break;
      68         228 :         case SUMO_TAG_PHASE:
      69         228 :             if (myCurrentTL != nullptr) {
      70         228 :                 if (myResetPhases) {
      71          41 :                     myCurrentTL->getLogic()->resetPhases();
      72          41 :                     myResetPhases = false;
      73             :                 }
      74         228 :                 NIImporter_SUMO::addPhase(attrs, myCurrentTL);
      75         227 :                 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         485 : }
      97             : 
      98             : 
      99             : void
     100         483 : NIXMLTrafficLightsHandler::myEndElement(int element) {
     101         483 :     switch (element) {
     102          42 :         case SUMO_TAG_TLLOGIC:
     103          42 :             myCurrentTL = nullptr;
     104          42 :             break;
     105             :         default:
     106             :             break;
     107             :     }
     108         483 : }
     109             : 
     110             : 
     111             : NBLoadedSUMOTLDef*
     112          43 : NIXMLTrafficLightsHandler::initTrafficLightLogic(const SUMOSAXAttributes& attrs, NBLoadedSUMOTLDef* currentTL) {
     113          43 :     if (currentTL) {
     114           0 :         WRITE_ERRORF(TL("Definition of tlLogic '%' was not finished."), currentTL->getID());
     115           0 :         return nullptr;
     116             :     }
     117          43 :     bool ok = true;
     118          43 :     std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
     119          43 :     std::string programID = attrs.getOpt<std::string>(SUMO_ATTR_PROGRAMID, id.c_str(), ok, "UNKNOWN_PROGRAM");
     120          43 :     SUMOTime offset = attrs.hasAttribute(SUMO_ATTR_OFFSET) ? TIME2STEPS(attrs.get<double>(SUMO_ATTR_OFFSET, id.c_str(), ok)) : 0;
     121             :     std::string typeS = attrs.getOpt<std::string>(SUMO_ATTR_TYPE, nullptr, ok,
     122         129 :                         OptionsCont::getOptions().getString("tls.default-type"));
     123             :     TrafficLightType type;
     124          43 :     if (SUMOXMLDefinitions::TrafficLightTypes.hasString(typeS)) {
     125          43 :         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          43 :     const std::map<std::string, NBTrafficLightDefinition*>& programs = myTLLCont.getPrograms(id);
     138          43 :     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          43 :     NBLoadedSUMOTLDef* loadedDef = dynamic_cast<NBLoadedSUMOTLDef*>(myTLLCont.getDefinition(id, programID));
     146          28 :     if (loadedDef == nullptr) {
     147          32 :         NBLoadedSUMOTLDef* oldDef = dynamic_cast<NBLoadedSUMOTLDef*>(myTLLCont.getDefinition(id, existingProgram));
     148          32 :         if (oldDef == nullptr) {
     149             :             // case 2
     150          21 :             NBTrafficLightDefinition* newDef = dynamic_cast<NBOwnTLDef*>(myTLLCont.getDefinition(
     151             :                                                    id, NBTrafficLightDefinition::DefaultProgramID));
     152             :             bool deleteDefault = false;
     153          21 :             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          21 :             loadedDef = new NBLoadedSUMOTLDef(id, programID, offset, type);
     166             :             // copy nodes and controlled inner edges
     167          42 :             for (NBNode* const n : newDef->getNodes()) {
     168          21 :                 loadedDef->addNode(n);
     169             :             }
     170          21 :             loadedDef->addControlledInnerEdges(newDef->getControlledInnerEdges());
     171          21 :             if (deleteDefault) {
     172             :                 // make a copy because the vector is modified in the loop
     173          21 :                 const std::vector<NBNode*> nodes = newDef->getNodes();
     174             :                 // replace default Program
     175          42 :                 for (NBNode* const n : nodes) {
     176          21 :                     n->removeTrafficLight(newDef);
     177             :                 }
     178          63 :                 myTLLCont.removeProgram(id, NBTrafficLightDefinition::DefaultProgramID);
     179             :             }
     180          21 :             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          43 :     if (ok) {
     204          43 :         myResetPhases = true;
     205             :         mySeenIDs.insert(id);
     206          43 :         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          12 :         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         244 :     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 1.14