Path: blob/main/src/netimport/NIXMLTrafficLightsHandler.cpp
169665 views
/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2011-2025 German Aerospace Center (DLR) and others.3// This program and the accompanying materials are made available under the4// terms of the Eclipse Public License 2.0 which is available at5// https://www.eclipse.org/legal/epl-2.0/6// This Source Code may also be made available under the following Secondary7// Licenses when the conditions for such availability set forth in the Eclipse8// Public License 2.0 are satisfied: GNU General Public License, version 29// or later which is available at10// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html11// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later12/****************************************************************************/13/// @file NIXMLTrafficLightsHandler.cpp14/// @author Daniel Krajzewicz15/// @author Michael Behrisch16/// @author Jakob Erdmann17/// @date 2011-10-0518///19// Importer for traffic lights stored in XML20/****************************************************************************/21#include <config.h>2223#include <string>24#include <iostream>25#include <utils/common/StringTokenizer.h>26#include <utils/xml/SUMOSAXHandler.h>27#include <utils/xml/SUMOXMLDefinitions.h>28#include <utils/common/ToString.h>29#include <utils/common/StringUtils.h>30#include <utils/common/UtilExceptions.h>31#include <utils/common/MsgHandler.h>32#include <utils/options/OptionsCont.h>33#include <netbuild/NBEdge.h>34#include <netbuild/NBEdgeCont.h>35#include <netbuild/NBNode.h>36#include <netbuild/NBOwnTLDef.h>37#include <netbuild/NBLoadedSUMOTLDef.h>38#include <netbuild/NBTrafficLightLogicCont.h>39#include "NIImporter_SUMO.h"40#include "NIXMLTrafficLightsHandler.h"414243// ===========================================================================44// method definitions45// ===========================================================================46NIXMLTrafficLightsHandler::NIXMLTrafficLightsHandler(47NBTrafficLightLogicCont& tlCont, NBEdgeCont& ec, bool ignoreUnknown) :48SUMOSAXHandler("xml-tllogics"),49myTLLCont(tlCont),50myEdgeCont(ec),51myCurrentTL(nullptr),52myResetPhases(false),53myIgnoreUnknown(ignoreUnknown)54{ }555657NIXMLTrafficLightsHandler::~NIXMLTrafficLightsHandler() {}585960void61NIXMLTrafficLightsHandler::myStartElement(62int element, const SUMOSAXAttributes& attrs) {63switch (element) {64case SUMO_TAG_TLLOGIC:65myCurrentTL = initTrafficLightLogic(attrs, myCurrentTL);66break;67case SUMO_TAG_PHASE:68if (myCurrentTL != nullptr) {69if (myResetPhases) {70myCurrentTL->getLogic()->resetPhases();71myResetPhases = false;72}73NIImporter_SUMO::addPhase(attrs, myCurrentTL);74myCurrentTL->phasesLoaded();75}76break;77case SUMO_TAG_CONNECTION:78addTlConnection(attrs);79break;80case SUMO_TAG_DEL:81removeTlConnection(attrs);82break;83case SUMO_TAG_PARAM:84if (myCurrentTL != nullptr) {85bool ok = true;86const std::string key = attrs.get<std::string>(SUMO_ATTR_KEY, nullptr, ok);87// circumventing empty string test88const std::string val = attrs.hasAttribute(SUMO_ATTR_VALUE) ? attrs.getString(SUMO_ATTR_VALUE) : "";89myCurrentTL->setParameter(key, val);90}91break;92default:93break;94}95}969798void99NIXMLTrafficLightsHandler::myEndElement(int element) {100switch (element) {101case SUMO_TAG_TLLOGIC:102myCurrentTL = nullptr;103break;104default:105break;106}107}108109110NBLoadedSUMOTLDef*111NIXMLTrafficLightsHandler::initTrafficLightLogic(const SUMOSAXAttributes& attrs, NBLoadedSUMOTLDef* currentTL) {112if (currentTL) {113WRITE_ERRORF(TL("Definition of tlLogic '%' was not finished."), currentTL->getID());114return nullptr;115}116bool ok = true;117std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);118std::string programID = attrs.getOpt<std::string>(SUMO_ATTR_PROGRAMID, id.c_str(), ok, "UNKNOWN_PROGRAM");119const SUMOTime offset = attrs.getOptOffsetReporting(SUMO_ATTR_OFFSET, id.c_str(), ok, 0);120std::string typeS = attrs.getOpt<std::string>(SUMO_ATTR_TYPE, nullptr, ok,121OptionsCont::getOptions().getString("tls.default-type"));122TrafficLightType type;123if (SUMOXMLDefinitions::TrafficLightTypes.hasString(typeS)) {124type = SUMOXMLDefinitions::TrafficLightTypes.get(typeS);125} else {126WRITE_ERRORF(TL("Unknown traffic light type '%' for tlLogic '%'."), typeS, id);127return nullptr;128}129// there are three scenarios to consider130// 1) the tll.xml is loaded to update traffic lights defined in a net.xml:131// simply retrieve the loaded definitions and update them132// 2) the tll.xml is loaded to define new traffic lights133// nod.xml will have triggered building of NBOwnTLDef. Replace it with NBLoadedSUMOTLDef134// 3) the tll.xml is loaded to define new programs for a defined traffic light135// there should be a definition with the same id but different programID136const std::map<std::string, NBTrafficLightDefinition*>& programs = myTLLCont.getPrograms(id);137if (programs.size() == 0) {138if (!myIgnoreUnknown) {139WRITE_ERRORF(TL("Cannot load traffic light program for unknown id '%', programID '%'."), id, programID);140}141return nullptr;142}143const std::string existingProgram = programs.begin()->first; // arbitrary for our purpose144NBLoadedSUMOTLDef* loadedDef = dynamic_cast<NBLoadedSUMOTLDef*>(myTLLCont.getDefinition(id, programID));145if (loadedDef == nullptr) {146NBLoadedSUMOTLDef* oldDef = dynamic_cast<NBLoadedSUMOTLDef*>(myTLLCont.getDefinition(id, existingProgram));147if (oldDef == nullptr) {148// case 2149NBTrafficLightDefinition* newDef = dynamic_cast<NBOwnTLDef*>(myTLLCont.getDefinition(150id, NBTrafficLightDefinition::DefaultProgramID));151bool deleteDefault = false;152if (newDef == nullptr) {153// the default program may have already been replaced with a loaded program154newDef = dynamic_cast<NBLoadedSUMOTLDef*>(myTLLCont.getDefinition(155id, NBTrafficLightDefinition::DefaultProgramID));156if (newDef == nullptr) {157WRITE_ERRORF(TL("Cannot load traffic light program for unknown id '%', programID '%'."), id, programID);158return nullptr;159}160} else {161deleteDefault = true;162}163assert(newDef != nullptr);164loadedDef = new NBLoadedSUMOTLDef(id, programID, offset, type);165// copy nodes and controlled inner edges166for (NBNode* const n : newDef->getNodes()) {167loadedDef->addNode(n);168}169loadedDef->addControlledInnerEdges(newDef->getControlledInnerEdges());170if (deleteDefault) {171// make a copy because the vector is modified in the loop172const std::vector<NBNode*> nodes = newDef->getNodes();173// replace default Program174for (NBNode* const n : nodes) {175n->removeTrafficLight(newDef);176}177myTLLCont.removeProgram(id, NBTrafficLightDefinition::DefaultProgramID);178}179myTLLCont.insert(loadedDef);180} else {181// case 3182NBTrafficLightLogic* oldLogic = oldDef->getLogic();183NBTrafficLightLogic newLogic(id, programID, oldLogic->getNumLinks(), offset, type);184loadedDef = new NBLoadedSUMOTLDef(*oldDef, newLogic);185// copy nodes186std::vector<NBNode*> nodes = oldDef->getNodes();187for (std::vector<NBNode*>::iterator it = nodes.begin(); it != nodes.end(); it++) {188loadedDef->addNode(*it);189}190//std::cout << " case3 oldDef=" << oldDef->getDescription() << " loadedDef=" << loadedDef->getDescription() << "\n";191myTLLCont.insert(loadedDef);192}193} else {194// case 1195if (attrs.hasAttribute(SUMO_ATTR_OFFSET)) {196loadedDef->setOffset(offset);197}198if (attrs.hasAttribute(SUMO_ATTR_TYPE)) {199loadedDef->setType(type);200}201}202if (ok) {203myResetPhases = true;204mySeenIDs.insert(id);205return loadedDef;206} else {207return nullptr;208}209}210211212void213NIXMLTrafficLightsHandler::addTlConnection(const SUMOSAXAttributes& attrs) {214bool ok = true;215// parse identifying attributes216NBEdge* from = retrieveEdge(attrs, SUMO_ATTR_FROM, ok);217NBEdge* to = retrieveEdge(attrs, SUMO_ATTR_TO, ok);218if (!ok) {219return;220}221int fromLane = retrieveLaneIndex(attrs, SUMO_ATTR_FROM_LANE, from, ok);222int toLane = retrieveLaneIndex(attrs, SUMO_ATTR_TO_LANE, to, ok);223if (!ok) {224return;225}226// retrieve connection227const std::vector<NBEdge::Connection>& connections = from->getConnections();228std::vector<NBEdge::Connection>::const_iterator con_it;229con_it = find_if(connections.begin(), connections.end(),230NBEdge::connections_finder(fromLane, to, toLane));231if (con_it == connections.end()) {232WRITE_ERROR("Connection from=" + from->getID() + " to=" + to->getID() +233" fromLane=" + toString(fromLane) + " toLane=" + toString(toLane) + " not found");234return;235}236NBEdge::Connection c = *con_it;237// read other attributes238std::string tlID = attrs.getOpt<std::string>(SUMO_ATTR_TLID, nullptr, ok, "");239if (tlID == "") {240// we are updating an existing tl-controlled connection241tlID = (*(from->getToNode()->getControllingTLS().begin()))->getID();242assert(tlID != "");243}244int tlIndex = attrs.getOpt<int>(SUMO_ATTR_TLLINKINDEX, nullptr, ok, -1);245if (tlIndex == -1) {246// we are updating an existing tl-controlled connection247tlIndex = c.tlLinkIndex;248}249int tlIndex2 = attrs.getOpt<int>(SUMO_ATTR_TLLINKINDEX2, nullptr, ok, -1);250if (tlIndex2 == -1) {251// we are updating an existing tl-controlled connection or index2 is not used252tlIndex2 = c.tlLinkIndex2;253}254255// register the connection with all definitions256const std::map<std::string, NBTrafficLightDefinition*>& programs = myTLLCont.getPrograms(tlID);257if (programs.size() > 0) {258std::map<std::string, NBTrafficLightDefinition*>::const_iterator it;259for (it = programs.begin(); it != programs.end(); it++) {260NBLoadedSUMOTLDef* tlDef = dynamic_cast<NBLoadedSUMOTLDef*>(it->second);261if (tlDef) {262tlDef->addConnection(from, c.toEdge, c.fromLane, c.toLane, tlIndex, tlIndex2, false);263} else {264throw ProcessError("Corrupt traffic light definition '"265+ tlID + "' (program '" + it->first + "')");266}267}268} else {269SumoXMLNodeType type = from->getToNode()->getType();270if (type != SumoXMLNodeType::RAIL_CROSSING && type != SumoXMLNodeType::RAIL_SIGNAL) {271WRITE_ERRORF(TL("The traffic light '%' is not known."), tlID);272}273}274}275276277void278NIXMLTrafficLightsHandler::removeTlConnection(const SUMOSAXAttributes& attrs) {279bool ok = true;280std::string tlID = attrs.get<std::string>(SUMO_ATTR_TLID, nullptr, ok);281// does the traffic light still exist?282const std::map<std::string, NBTrafficLightDefinition*>& programs = myTLLCont.getPrograms(tlID);283if (programs.size() > 0) {284// parse identifying attributes285NBEdge* from = retrieveEdge(attrs, SUMO_ATTR_FROM, ok);286NBEdge* to = retrieveEdge(attrs, SUMO_ATTR_TO, ok);287int fromLane = -1;288int toLane = -1;289if (ok) {290fromLane = retrieveLaneIndex(attrs, SUMO_ATTR_FROM_LANE, from, ok, true);291toLane = retrieveLaneIndex(attrs, SUMO_ATTR_TO_LANE, to, ok, true);292}293int tlIndex = attrs.get<int>(SUMO_ATTR_TLLINKINDEX, nullptr, ok);294295NBConnection conn(from, fromLane, to, toLane, tlIndex);296// remove the connection from all definitions297std::map<std::string, NBTrafficLightDefinition*>::const_iterator it;298for (it = programs.begin(); it != programs.end(); it++) {299NBLoadedSUMOTLDef* tlDef = dynamic_cast<NBLoadedSUMOTLDef*>(it->second);300if (tlDef) {301tlDef->removeConnection(conn, false);302} else {303throw ProcessError("Corrupt traffic light definition '"304+ tlID + "' (program '" + it->first + "')");305}306}307}308}309310311NBEdge*312NIXMLTrafficLightsHandler::retrieveEdge(313const SUMOSAXAttributes& attrs, SumoXMLAttr attr, bool& ok) {314std::string edgeID = attrs.get<std::string>(attr, nullptr, ok);315NBEdge* edge = myEdgeCont.retrieve(edgeID, true);316if (edge == nullptr) {317WRITE_ERRORF(TL("Unknown edge '%' given in connection."), edgeID);318ok = false;319}320return edge;321}322323324int325NIXMLTrafficLightsHandler::retrieveLaneIndex(326const SUMOSAXAttributes& attrs, SumoXMLAttr attr, NBEdge* edge, bool& ok, bool isDelete) {327int laneIndex = attrs.get<int>(attr, nullptr, ok);328if (edge->getNumLanes() <= laneIndex) {329if (!isDelete) {330WRITE_ERRORF(TL("Invalid lane index '%' for edge '%'."), toString(laneIndex), edge->getID());331}332ok = false;333}334return laneIndex;335}336337338/****************************************************************************/339340341