Path: blob/main/src/guisim/GUITrafficLightLogicWrapper.cpp
169666 views
/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2001-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 GUITrafficLightLogicWrapper.cpp14/// @author Daniel Krajzewicz15/// @author Jakob Erdmann16/// @author Michael Behrisch17/// @author Laura Bieker18/// @date Oct/Nov 200319///20// A wrapper for tl-logics to allow their visualisation and interaction21/****************************************************************************/22#include <config.h>2324#include <cassert>25#include <utils/common/MsgHandler.h>26#include <utils/geom/GeomHelper.h>27#include <utils/gui/globjects/GUIGlObject.h>28#include <utils/gui/div/GLObjectValuePassConnector.h>29#include <utils/gui/windows/GUIAppEnum.h>30#include <utils/gui/images/GUIIconSubSys.h>31#include <utils/gui/div/GLHelper.h>32#include <utils/gui/div/GUIParameterTableWindow.h>33#include <utils/gui/globjects/GUIGLObjectPopupMenu.h>34#include <utils/gui/div/GUIGlobalSelection.h>35#include <microsim/MSLane.h>36#include <microsim/traffic_lights/MSTrafficLightLogic.h>37#include <microsim/traffic_lights/MSTLLogicControl.h>38#include <microsim/traffic_lights/MSOffTrafficLightLogic.h>39#include <microsim/traffic_lights/MSActuatedTrafficLightLogic.h>40#include <microsim/traffic_lights/MSDelayBasedTrafficLightLogic.h>41#include <microsim/traffic_lights/NEMAController.h>42#include <microsim/traffic_lights/MSRailSignal.h>43#include <microsim/logging/FunctionBinding.h>44#include <microsim/logging/FuncBinding_StringParam.h>45#include <gui/GUIApplicationWindow.h>46#include <gui/GUITLLogicPhasesTrackerWindow.h>47#include <gui/GUIGlobals.h>48#include <utils/gui/globjects/GLIncludes.h>49#include <utils/gui/div/GUIDesigns.h>5051#include "GUITrafficLightLogicWrapper.h"52#include "GUINet.h"5354// ===========================================================================55// FOX callback mapping56// ===========================================================================57FXDEFMAP(GUITrafficLightLogicWrapper::GUITrafficLightLogicWrapperPopupMenu)58GUITrafficLightLogicWrapperPopupMenuMap[] = {59FXMAPFUNC(SEL_COMMAND, MID_SHOWPHASES, GUITrafficLightLogicWrapper::GUITrafficLightLogicWrapperPopupMenu::onCmdShowPhases),60FXMAPFUNC(SEL_COMMAND, MID_TRACKPHASES, GUITrafficLightLogicWrapper::GUITrafficLightLogicWrapperPopupMenu::onCmdBegin2TrackPhases),61FXMAPFUNC(SEL_COMMAND, MID_SHOW_DETECTORS, GUITrafficLightLogicWrapper::GUITrafficLightLogicWrapperPopupMenu::onCmdShowDetectors),62FXMAPFUNC(SEL_COMMAND, MID_SWITCH_OFF, GUITrafficLightLogicWrapper::GUITrafficLightLogicWrapperPopupMenu::onCmdSwitchTLS2Off),63FXMAPFUNCS(SEL_COMMAND, MID_SWITCH, MID_SWITCH + 20, GUITrafficLightLogicWrapper::GUITrafficLightLogicWrapperPopupMenu::onCmdSwitchTLSLogic),64};6566// Object implementation67FXIMPLEMENT(GUITrafficLightLogicWrapper::GUITrafficLightLogicWrapperPopupMenu, GUIGLObjectPopupMenu, GUITrafficLightLogicWrapperPopupMenuMap, ARRAYNUMBER(GUITrafficLightLogicWrapperPopupMenuMap))686970// ===========================================================================71// method definitions72// ===========================================================================73/* -------------------------------------------------------------------------74* GUITrafficLightLogicWrapper::GUITrafficLightLogicWrapperPopupMenu - methods75* ----------------------------------------------------------------------- */76GUITrafficLightLogicWrapper::GUITrafficLightLogicWrapperPopupMenu::GUITrafficLightLogicWrapperPopupMenu(77GUIMainWindow& app, GUISUMOAbstractView& parent, GUIGlObject* o) :78GUIGLObjectPopupMenu(app, parent, o) {}798081GUITrafficLightLogicWrapper::GUITrafficLightLogicWrapperPopupMenu::~GUITrafficLightLogicWrapperPopupMenu() {}82838485long86GUITrafficLightLogicWrapper::GUITrafficLightLogicWrapperPopupMenu::onCmdBegin2TrackPhases(87FXObject*, FXSelector, void*) {88assert(myObject->getType() == GLO_TLLOGIC);89static_cast<GUITrafficLightLogicWrapper*>(myObject)->begin2TrackPhases();90return 1;91}929394long95GUITrafficLightLogicWrapper::GUITrafficLightLogicWrapperPopupMenu::onCmdShowPhases(96FXObject*, FXSelector, void*) {97assert(myObject->getType() == GLO_TLLOGIC);98static_cast<GUITrafficLightLogicWrapper*>(myObject)->showPhases();99return 1;100}101102long103GUITrafficLightLogicWrapper::GUITrafficLightLogicWrapperPopupMenu::onCmdShowDetectors(104FXObject*, FXSelector, void*) {105assert(myObject->getType() == GLO_TLLOGIC);106GUITrafficLightLogicWrapper* w = static_cast<GUITrafficLightLogicWrapper*>(myObject);107MSActuatedTrafficLightLogic* act = dynamic_cast<MSActuatedTrafficLightLogic*>(&w->getTLLogic());108if (act != nullptr) {109act->setShowDetectors(!act->showDetectors());110} else {111MSDelayBasedTrafficLightLogic* db = dynamic_cast<MSDelayBasedTrafficLightLogic*>(&w->getTLLogic());112if (db != nullptr) {113db->setShowDetectors(!db->showDetectors());114} else {115NEMALogic* nema = dynamic_cast<NEMALogic*>(&w->getTLLogic());116if (nema != nullptr) {117nema->setShowDetectors(!nema->showDetectors());118}119}120}121myParent->update();122return 1;123}124125long126GUITrafficLightLogicWrapper::GUITrafficLightLogicWrapperPopupMenu::onCmdSwitchTLS2Off(127FXObject*, FXSelector /*sel*/, void*) {128assert(myObject->getType() == GLO_TLLOGIC);129static_cast<GUITrafficLightLogicWrapper*>(myObject)->switchTLSLogic(-1);130myParent->update();131return 1;132}133134135long136GUITrafficLightLogicWrapper::GUITrafficLightLogicWrapperPopupMenu::onCmdSwitchTLSLogic(137FXObject*, FXSelector sel, void*) {138assert(myObject->getType() == GLO_TLLOGIC);139static_cast<GUITrafficLightLogicWrapper*>(myObject)->switchTLSLogic(FXSELID(sel) - MID_SWITCH);140myParent->update();141return 1;142}143144145146/* -------------------------------------------------------------------------147* GUITrafficLightLogicWrapper - methods148* ----------------------------------------------------------------------- */149GUITrafficLightLogicWrapper::GUITrafficLightLogicWrapper(MSTLLogicControl& control, MSTrafficLightLogic& tll) :150GUIGlObject(GLO_TLLOGIC, tll.getID(), GUIIconSubSys::getIcon(GUIIcon::LOCATETLS)),151myTLLogicControl(control), myTLLogic(tll) {152}153154155GUITrafficLightLogicWrapper::~GUITrafficLightLogicWrapper() {}156157158GUIGLObjectPopupMenu*159GUITrafficLightLogicWrapper::getPopUpMenu(GUIMainWindow& app, GUISUMOAbstractView& parent) {160myApp = &app;161GUIGLObjectPopupMenu* ret = new GUITrafficLightLogicWrapperPopupMenu(app, parent, this);162buildPopupHeader(ret, app);163buildCenterPopupEntry(ret);164const MSTLLogicControl::TLSLogicVariants& vars = myTLLogicControl.get(myTLLogic.getID());165std::vector<MSTrafficLightLogic*> logics = vars.getAllLogics();166if (logics.size() > 1) {167std::vector<MSTrafficLightLogic*>::const_iterator i;168int index = 0;169for (i = logics.begin(); i != logics.end(); ++i, ++index) {170if (!vars.isActive(*i) && dynamic_cast<MSOffTrafficLightLogic*>(*i) == nullptr) {171GUIDesigns::buildFXMenuCommand(ret, TLF("Switch to '%'", (*i)->getProgramID()),172GUIIconSubSys::getIcon(GUIIcon::FLAG_MINUS), ret, (FXSelector)(MID_SWITCH + index));173}174}175new FXMenuSeparator(ret);176}177MSOffTrafficLightLogic* offLogic = dynamic_cast<MSOffTrafficLightLogic*>(vars.getActive());178if (offLogic == nullptr) {179GUIDesigns::buildFXMenuCommand(ret, TL("Switch off"), GUIIconSubSys::getIcon(GUIIcon::FLAG_MINUS), ret, MID_SWITCH_OFF);180}181GUIDesigns::buildFXMenuCommand(ret, TL("Track Phases"), nullptr, ret, MID_TRACKPHASES);182GUIDesigns::buildFXMenuCommand(ret, TL("Show Phases"), nullptr, ret, MID_SHOWPHASES);183MSActuatedTrafficLightLogic* act = dynamic_cast<MSActuatedTrafficLightLogic*>(&myTLLogic);184if (act != nullptr) {185GUIDesigns::buildFXMenuCommand(ret, act->showDetectors() ? TL("Hide Detectors") : TL("Show Detectors"), nullptr, ret, MID_SHOW_DETECTORS);186}187MSDelayBasedTrafficLightLogic* db = dynamic_cast<MSDelayBasedTrafficLightLogic*>(&myTLLogic);188if (db != nullptr) {189GUIDesigns::buildFXMenuCommand(ret, db->showDetectors() ? TL("Hide Detectors") : TL("Show Detectors"), nullptr, ret, MID_SHOW_DETECTORS);190}191NEMALogic* nema = dynamic_cast<NEMALogic*>(&myTLLogic);192if (nema != nullptr) {193GUIDesigns::buildFXMenuCommand(ret, nema->showDetectors() ? TL("Hide Detectors") : TL("Show Detectors"), nullptr, ret, MID_SHOW_DETECTORS);194}195new FXMenuSeparator(ret);196MSTrafficLightLogic* tll = getActiveTLLogic();197buildNameCopyPopupEntry(ret);198buildSelectionPopupEntry(ret);199GUIDesigns::buildFXMenuCommand(ret, TLF("Phase: %", toString(tll->getCurrentPhaseIndex())), nullptr, nullptr, 0);200const std::string& name = tll->getCurrentPhaseDef().getName();201if (name != "") {202GUIDesigns::buildFXMenuCommand(ret, TLF("Phase name: %", name), nullptr, nullptr, 0);203}204new FXMenuSeparator(ret);205buildShowParamsPopupEntry(ret, false);206buildPositionCopyEntry(ret, app);207return ret;208}209210211void212GUITrafficLightLogicWrapper::begin2TrackPhases() {213GUITLLogicPhasesTrackerWindow* window =214new GUITLLogicPhasesTrackerWindow(*myApp, myTLLogic, *this,215new FuncBinding_StringParam<MSTLLogicControl, std::pair<SUMOTime, MSPhaseDefinition> >216(&MSNet::getInstance()->getTLSControl(), &MSTLLogicControl::getPhaseDef, myTLLogic.getID()));217window->create();218window->show();219}220221222void223GUITrafficLightLogicWrapper::showPhases() {224GUITLLogicPhasesTrackerWindow* window =225new GUITLLogicPhasesTrackerWindow(*myApp, myTLLogic, *this,226static_cast<MSSimpleTrafficLightLogic&>(myTLLogic).getPhases());227window->setBeginTime(0);228window->create();229window->show();230}231232233GUIParameterTableWindow*234GUITrafficLightLogicWrapper::getParameterWindow(GUIMainWindow& app,235GUISUMOAbstractView&) {236GUIParameterTableWindow* ret = new GUIParameterTableWindow(app, *this);237ret->mkItem(TL("tlLogic [id]"), false, myTLLogic.getID());238ret->mkItem(TL("type"), false, toString(myTLLogic.getLogicType()));239ret->mkItem(TL("program"), false, myTLLogic.getProgramID());240ret->mkItem(TL("phase"), true, new FunctionBinding<GUITrafficLightLogicWrapper, int>(this, &GUITrafficLightLogicWrapper::getCurrentPhase));241ret->mkItem(TL("phase name"), true, new FunctionBindingString<GUITrafficLightLogicWrapper>(this, &GUITrafficLightLogicWrapper::getCurrentPhaseName));242ret->mkItem(TL("duration"), true, new FunctionBinding<GUITrafficLightLogicWrapper, int>(this, &GUITrafficLightLogicWrapper::getCurrentDurationSeconds));243ret->mkItem(TL("minDur"), true, new FunctionBinding<GUITrafficLightLogicWrapper, int>(this, &GUITrafficLightLogicWrapper::getCurrentMinDurSeconds));244ret->mkItem(TL("maxDur"), true, new FunctionBinding<GUITrafficLightLogicWrapper, int>(this, &GUITrafficLightLogicWrapper::getCurrentMaxDurSeconds));245ret->mkItem(TL("running duration"), true, new FunctionBinding<GUITrafficLightLogicWrapper, int>(this, &GUITrafficLightLogicWrapper::getRunningDurationSeconds));246ret->mkItem(TL("earliestEnd"), true, new FunctionBinding<GUITrafficLightLogicWrapper, int>(this, &GUITrafficLightLogicWrapper::getCurrentEarliestEndSeconds));247ret->mkItem(TL("latestEnd"), true, new FunctionBinding<GUITrafficLightLogicWrapper, int>(this, &GUITrafficLightLogicWrapper::getCurrentLatestEndSeconds));248ret->mkItem(TL("time in cycle"), true, new FunctionBinding<GUITrafficLightLogicWrapper, int>(this, &GUITrafficLightLogicWrapper::getCurrentTimeInCycleSeconds));249ret->mkItem(TL("cycle time"), true, new FunctionBinding<GUITrafficLightLogicWrapper, int>(this, &GUITrafficLightLogicWrapper::getDefaultCycleTimeSeconds));250MSRailSignal* rs = dynamic_cast<MSRailSignal*>(&myTLLogic);251if (rs != nullptr) {252ret->mkItem(TL("req driveway"), true, new FunctionBindingString<MSRailSignal>(rs, &MSRailSignal::getRequestedDriveWay));253ret->mkItem(TL("blocking"), true, new FunctionBindingString<MSRailSignal>(rs, &MSRailSignal::getBlockingVehicleIDs));254ret->mkItem(TL("blocking driveways"), true, new FunctionBindingString<MSRailSignal>(rs, &MSRailSignal::getBlockingDriveWayIDs));255ret->mkItem(TL("rival"), true, new FunctionBindingString<MSRailSignal>(rs, &MSRailSignal::getRivalVehicleIDs));256ret->mkItem(TL("priority"), true, new FunctionBindingString<MSRailSignal>(rs, &MSRailSignal::getPriorityVehicleIDs));257ret->mkItem(TL("constraint"), true, new FunctionBindingString<MSRailSignal>(rs, &MSRailSignal::getConstraintInfo));258}259// close building260ret->closeBuilding(&myTLLogic);261return ret;262}263264265Boundary266GUITrafficLightLogicWrapper::getCenteringBoundary() const {267Boundary ret;268const MSTrafficLightLogic::LaneVectorVector& lanes = myTLLogic.getLaneVectors();269for (MSTrafficLightLogic::LaneVectorVector::const_iterator i = lanes.begin(); i != lanes.end(); ++i) {270const MSTrafficLightLogic::LaneVector& lanes2 = (*i);271for (MSTrafficLightLogic::LaneVector::const_iterator j = lanes2.begin(); j != lanes2.end(); ++j) {272ret.add((*j)->getShape()[-1]);273}274}275ret.grow(20);276return ret;277}278279const std::string280GUITrafficLightLogicWrapper::getOptionalName() const {281return myTLLogic.getParameter("name", "");282}283284285void286GUITrafficLightLogicWrapper::switchTLSLogic(int to) {287if (to == -1) {288myTLLogicControl.switchTo(myTLLogic.getID(), "off");289GUINet::getGUIInstance()->createTLWrapper(getActiveTLLogic());290} else {291const MSTLLogicControl::TLSLogicVariants& vars = myTLLogicControl.get(myTLLogic.getID());292std::vector<MSTrafficLightLogic*> logics = vars.getAllLogics();293myTLLogicControl.switchTo(myTLLogic.getID(), logics[to]->getProgramID());294}295}296297298int299GUITrafficLightLogicWrapper::getLinkIndex(const MSLink* const link) const {300return myTLLogic.getLinkIndex(link);301}302303304void305GUITrafficLightLogicWrapper::drawGL(const GUIVisualizationSettings& s) const {306if (s.gaming) {307if (!MSNet::getInstance()->getTLSControl().isActive(&myTLLogic) || myTLLogic.getPhases().size() == 0) {308return;309}310const std::string& curState = myTLLogic.getCurrentPhaseDef().getState();311if (curState.find_first_of("gG") == std::string::npos) {312// no link is 'green' at the moment. find those that turn green next313const MSTrafficLightLogic::Phases& phases = myTLLogic.getPhases();314int curPhaseIdx = myTLLogic.getCurrentPhaseIndex();315int phaseIdx = (curPhaseIdx + 1) % phases.size();316std::vector<int> nextGreen;317while (phaseIdx != curPhaseIdx) {318const std::string& state = phases[phaseIdx]->getState();319for (int linkIdx = 0; linkIdx < (int)state.size(); linkIdx++) {320if ((LinkState)state[linkIdx] == LINKSTATE_TL_GREEN_MINOR ||321(LinkState)state[linkIdx] == LINKSTATE_TL_GREEN_MAJOR) {322nextGreen.push_back(linkIdx);323}324}325if (nextGreen.size() > 0) {326break;327}328phaseIdx = (phaseIdx + 1) % phases.size();329}330// highlight nextGreen links331for (const int idx : nextGreen) {332for (const MSLane* const lane : myTLLogic.getLanesAt(idx)) {333GLHelper::pushMatrix();334// split circle in red and yellow335const Position& pos = lane->getShape().back();336glTranslated(pos.x(), pos.y(), GLO_MAX);337double rot = RAD2DEG(lane->getShape().angleAt2D((int)lane->getShape().size() - 2)) - 90;338glRotated(rot, 0, 0, 1);339GLHelper::setColor(s.getLinkColor(LINKSTATE_TL_RED));340GLHelper::drawFilledCircle(lane->getWidth() / 2., 8, -90, 90);341if (!isRailway(lane->getPermissions())) {342// no yellow half-cirlce in railway game343GLHelper::setColor(s.getLinkColor(LINKSTATE_TL_YELLOW_MAJOR));344GLHelper::drawFilledCircle(lane->getWidth() / 2., 8, 90, 270);345}346GLHelper::popMatrix();347}348}349}350}351}352353MSTrafficLightLogic*354GUITrafficLightLogicWrapper::getActiveTLLogic() const {355return myTLLogicControl.getActive(myTLLogic.getID());356}357358int359GUITrafficLightLogicWrapper::getCurrentPhase() const {360return getActiveTLLogic()->getCurrentPhaseIndex();361}362363std::string364GUITrafficLightLogicWrapper::getCurrentPhaseName() const {365return getActiveTLLogic()->getCurrentPhaseDef().getName();366}367368int369GUITrafficLightLogicWrapper::getCurrentDurationSeconds() const {370return (int)STEPS2TIME(getActiveTLLogic()->getCurrentPhaseDef().duration);371}372373int374GUITrafficLightLogicWrapper::getCurrentMinDurSeconds() const {375return (int)STEPS2TIME(getActiveTLLogic()->getMinDur());376}377378int379GUITrafficLightLogicWrapper::getCurrentMaxDurSeconds() const {380return (int)STEPS2TIME(getActiveTLLogic()->getMaxDur());381}382383int384GUITrafficLightLogicWrapper::getCurrentEarliestEndSeconds() const {385const SUMOTime earliestEnd = getActiveTLLogic()->getEarliestEnd();386return earliestEnd == MSPhaseDefinition::UNSPECIFIED_DURATION ? -1 : (int)STEPS2TIME(earliestEnd);387}388389int390GUITrafficLightLogicWrapper::getCurrentLatestEndSeconds() const {391const SUMOTime latestEnd = getActiveTLLogic()->getLatestEnd();392return latestEnd == MSPhaseDefinition::UNSPECIFIED_DURATION ? -1 : (int)STEPS2TIME(latestEnd);393}394395int396GUITrafficLightLogicWrapper::getDefaultCycleTimeSeconds() const {397return (int)STEPS2TIME(getActiveTLLogic()->getDefaultCycleTime());398}399400int401GUITrafficLightLogicWrapper::getCurrentTimeInCycleSeconds() const {402return (int)STEPS2TIME(getActiveTLLogic()->getTimeInCycle());403}404405int406GUITrafficLightLogicWrapper::getRunningDurationSeconds() const {407return (int)STEPS2TIME(getActiveTLLogic()->getSpentDuration());408}409410411/****************************************************************************/412413414