Path: blob/main/src/guisim/GUITrafficLightLogicWrapper.cpp
193808 views
/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2001-2026 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(GUIMainWindow* app) {213if (app != nullptr) {214myApp = app;215}216assert(myApp != nullptr);217GUITLLogicPhasesTrackerWindow* window =218new GUITLLogicPhasesTrackerWindow(*myApp, myTLLogic, *this,219new FuncBinding_StringParam<MSTLLogicControl, std::pair<SUMOTime, MSPhaseDefinition> >220(&MSNet::getInstance()->getTLSControl(), &MSTLLogicControl::getPhaseDef, myTLLogic.getID()));221window->create();222window->show();223}224225226void227GUITrafficLightLogicWrapper::showPhases() {228GUITLLogicPhasesTrackerWindow* window =229new GUITLLogicPhasesTrackerWindow(*myApp, myTLLogic, *this,230static_cast<MSSimpleTrafficLightLogic&>(myTLLogic).getPhases());231window->setBeginTime(0);232window->create();233window->show();234}235236237GUIParameterTableWindow*238GUITrafficLightLogicWrapper::getParameterWindow(GUIMainWindow& app,239GUISUMOAbstractView&) {240GUIParameterTableWindow* ret = new GUIParameterTableWindow(app, *this);241ret->mkItem(TL("tlLogic [id]"), false, myTLLogic.getID());242ret->mkItem(TL("type"), false, toString(myTLLogic.getLogicType()));243ret->mkItem(TL("program"), false, myTLLogic.getProgramID());244ret->mkItem(TL("phase"), true, new FunctionBinding<GUITrafficLightLogicWrapper, int>(this, &GUITrafficLightLogicWrapper::getCurrentPhase));245ret->mkItem(TL("phase name"), true, new FunctionBindingString<GUITrafficLightLogicWrapper>(this, &GUITrafficLightLogicWrapper::getCurrentPhaseName));246ret->mkItem(TL("duration"), true, new FunctionBinding<GUITrafficLightLogicWrapper, int>(this, &GUITrafficLightLogicWrapper::getCurrentDurationSeconds));247ret->mkItem(TL("minDur"), true, new FunctionBinding<GUITrafficLightLogicWrapper, int>(this, &GUITrafficLightLogicWrapper::getCurrentMinDurSeconds));248ret->mkItem(TL("maxDur"), true, new FunctionBinding<GUITrafficLightLogicWrapper, int>(this, &GUITrafficLightLogicWrapper::getCurrentMaxDurSeconds));249ret->mkItem(TL("running duration"), true, new FunctionBinding<GUITrafficLightLogicWrapper, int>(this, &GUITrafficLightLogicWrapper::getRunningDurationSeconds));250ret->mkItem(TL("earliestEnd"), true, new FunctionBinding<GUITrafficLightLogicWrapper, int>(this, &GUITrafficLightLogicWrapper::getCurrentEarliestEndSeconds));251ret->mkItem(TL("latestEnd"), true, new FunctionBinding<GUITrafficLightLogicWrapper, int>(this, &GUITrafficLightLogicWrapper::getCurrentLatestEndSeconds));252ret->mkItem(TL("time in cycle"), true, new FunctionBinding<GUITrafficLightLogicWrapper, int>(this, &GUITrafficLightLogicWrapper::getCurrentTimeInCycleSeconds));253ret->mkItem(TL("cycle time"), true, new FunctionBinding<GUITrafficLightLogicWrapper, int>(this, &GUITrafficLightLogicWrapper::getDefaultCycleTimeSeconds));254MSRailSignal* rs = dynamic_cast<MSRailSignal*>(&myTLLogic);255if (rs != nullptr) {256ret->mkItem(TL("req driveway"), true, new FunctionBindingString<MSRailSignal>(rs, &MSRailSignal::getRequestedDriveWay));257ret->mkItem(TL("blocking"), true, new FunctionBindingString<MSRailSignal>(rs, &MSRailSignal::getBlockingVehicleIDs));258ret->mkItem(TL("blocking driveways"), true, new FunctionBindingString<MSRailSignal>(rs, &MSRailSignal::getBlockingDriveWayIDs));259ret->mkItem(TL("rival"), true, new FunctionBindingString<MSRailSignal>(rs, &MSRailSignal::getRivalVehicleIDs));260ret->mkItem(TL("priority"), true, new FunctionBindingString<MSRailSignal>(rs, &MSRailSignal::getPriorityVehicleIDs));261ret->mkItem(TL("constraint"), true, new FunctionBindingString<MSRailSignal>(rs, &MSRailSignal::getConstraintInfo));262}263// close building264ret->closeBuilding(&myTLLogic);265return ret;266}267268269Boundary270GUITrafficLightLogicWrapper::getCenteringBoundary() const {271Boundary ret;272const MSTrafficLightLogic::LaneVectorVector& lanes = myTLLogic.getLaneVectors();273for (MSTrafficLightLogic::LaneVectorVector::const_iterator i = lanes.begin(); i != lanes.end(); ++i) {274const MSTrafficLightLogic::LaneVector& lanes2 = (*i);275for (MSTrafficLightLogic::LaneVector::const_iterator j = lanes2.begin(); j != lanes2.end(); ++j) {276ret.add((*j)->getShape()[-1]);277}278}279ret.grow(20);280return ret;281}282283const std::string284GUITrafficLightLogicWrapper::getOptionalName() const {285return myTLLogic.getParameter("name", "");286}287288289void290GUITrafficLightLogicWrapper::switchTLSLogic(int to) {291if (to == -1) {292myTLLogicControl.switchTo(myTLLogic.getID(), "off");293GUINet::getGUIInstance()->createTLWrapper(getActiveTLLogic());294} else {295const MSTLLogicControl::TLSLogicVariants& vars = myTLLogicControl.get(myTLLogic.getID());296std::vector<MSTrafficLightLogic*> logics = vars.getAllLogics();297myTLLogicControl.switchTo(myTLLogic.getID(), logics[to]->getProgramID());298}299}300301302int303GUITrafficLightLogicWrapper::getLinkIndex(const MSLink* const link) const {304return myTLLogic.getLinkIndex(link);305}306307308void309GUITrafficLightLogicWrapper::drawGL(const GUIVisualizationSettings& s) const {310if (s.gaming) {311if (!MSNet::getInstance()->getTLSControl().isActive(&myTLLogic) || myTLLogic.getPhases().size() == 0) {312return;313}314const std::string& curState = myTLLogic.getCurrentPhaseDef().getState();315if (curState.find_first_of("gG") == std::string::npos) {316// no link is 'green' at the moment. find those that turn green next317const MSTrafficLightLogic::Phases& phases = myTLLogic.getPhases();318int curPhaseIdx = myTLLogic.getCurrentPhaseIndex();319int phaseIdx = (curPhaseIdx + 1) % phases.size();320std::vector<int> nextGreen;321while (phaseIdx != curPhaseIdx) {322const std::string& state = phases[phaseIdx]->getState();323for (int linkIdx = 0; linkIdx < (int)state.size(); linkIdx++) {324if ((LinkState)state[linkIdx] == LINKSTATE_TL_GREEN_MINOR ||325(LinkState)state[linkIdx] == LINKSTATE_TL_GREEN_MAJOR) {326nextGreen.push_back(linkIdx);327}328}329if (nextGreen.size() > 0) {330break;331}332phaseIdx = (phaseIdx + 1) % phases.size();333}334// highlight nextGreen links335for (const int idx : nextGreen) {336for (const MSLane* const lane : myTLLogic.getLanesAt(idx)) {337GLHelper::pushMatrix();338// split circle in red and yellow339const Position& pos = lane->getShape().back();340glTranslated(pos.x(), pos.y(), GLO_MAX);341double rot = RAD2DEG(lane->getShape().angleAt2D((int)lane->getShape().size() - 2)) - 90;342glRotated(rot, 0, 0, 1);343GLHelper::setColor(s.getLinkColor(LINKSTATE_TL_RED));344GLHelper::drawFilledCircle(lane->getWidth() / 2., 8, -90, 90);345if (!isRailway(lane->getPermissions())) {346// no yellow half-cirlce in railway game347GLHelper::setColor(s.getLinkColor(LINKSTATE_TL_YELLOW_MAJOR));348GLHelper::drawFilledCircle(lane->getWidth() / 2., 8, 90, 270);349}350GLHelper::popMatrix();351}352}353}354}355}356357MSTrafficLightLogic*358GUITrafficLightLogicWrapper::getActiveTLLogic() const {359return myTLLogicControl.getActive(myTLLogic.getID());360}361362int363GUITrafficLightLogicWrapper::getCurrentPhase() const {364return getActiveTLLogic()->getCurrentPhaseIndex();365}366367std::string368GUITrafficLightLogicWrapper::getCurrentPhaseName() const {369return getActiveTLLogic()->getCurrentPhaseDef().getName();370}371372int373GUITrafficLightLogicWrapper::getCurrentDurationSeconds() const {374return (int)STEPS2TIME(getActiveTLLogic()->getCurrentPhaseDef().duration);375}376377int378GUITrafficLightLogicWrapper::getCurrentMinDurSeconds() const {379return (int)STEPS2TIME(getActiveTLLogic()->getMinDur());380}381382int383GUITrafficLightLogicWrapper::getCurrentMaxDurSeconds() const {384return (int)STEPS2TIME(getActiveTLLogic()->getMaxDur());385}386387int388GUITrafficLightLogicWrapper::getCurrentEarliestEndSeconds() const {389const SUMOTime earliestEnd = getActiveTLLogic()->getEarliestEnd();390return earliestEnd == MSPhaseDefinition::UNSPECIFIED_DURATION ? -1 : (int)STEPS2TIME(earliestEnd);391}392393int394GUITrafficLightLogicWrapper::getCurrentLatestEndSeconds() const {395const SUMOTime latestEnd = getActiveTLLogic()->getLatestEnd();396return latestEnd == MSPhaseDefinition::UNSPECIFIED_DURATION ? -1 : (int)STEPS2TIME(latestEnd);397}398399int400GUITrafficLightLogicWrapper::getDefaultCycleTimeSeconds() const {401return (int)STEPS2TIME(getActiveTLLogic()->getDefaultCycleTime());402}403404int405GUITrafficLightLogicWrapper::getCurrentTimeInCycleSeconds() const {406return (int)STEPS2TIME(getActiveTLLogic()->getTimeInCycle());407}408409int410GUITrafficLightLogicWrapper::getRunningDurationSeconds() const {411return (int)STEPS2TIME(getActiveTLLogic()->getSpentDuration());412}413414415/****************************************************************************/416417418