LCOV - code coverage report
Current view: top level - src/gui - GUITLLogicPhasesTrackerWindow.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 0.0 % 585 0
Test Date: 2024-11-20 15:55:46 Functions: 0.0 % 28 0

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-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    GUITLLogicPhasesTrackerWindow.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Jakob Erdmann
      17              : /// @author  Michael Behrisch
      18              : /// @date    Oct/Nov 2003
      19              : ///
      20              : // A window displaying the phase diagram of a tl-logic
      21              : /****************************************************************************/
      22              : #include <config.h>
      23              : 
      24              : #include <vector>
      25              : #include <iostream>
      26              : #include <utils/gui/windows/GUIMainWindow.h>
      27              : #include <utils/gui/div/GLHelper.h>
      28              : #include "GUITLLogicPhasesTrackerWindow.h"
      29              : #include <microsim/traffic_lights/MSTrafficLightLogic.h>
      30              : #include <microsim/output/MSInductLoop.h>
      31              : #include <microsim/MSLink.h>
      32              : #include <utils/common/ToString.h>
      33              : #include <utils/common/MsgHandler.h>
      34              : #include <guisim/GUITrafficLightLogicWrapper.h>
      35              : #include <utils/gui/windows/GUIAppEnum.h>
      36              : #include <utils/gui/images/GUIIconSubSys.h>
      37              : #include <utils/gui/settings/GUIVisualizationSettings.h>
      38              : #include <utils/gui/div/GUIDesigns.h>
      39              : #include <foreign/fontstash/fontstash.h>
      40              : #include <utils/gui/globjects/GLIncludes.h>
      41              : 
      42              : 
      43              : // ===========================================================================
      44              : // static member initialisation
      45              : // ===========================================================================
      46              : int GUITLLogicPhasesTrackerWindow::myLastY(-1);
      47              : 
      48              : // ===========================================================================
      49              : // member method definitions
      50              : // ===========================================================================
      51              : /* -------------------------------------------------------------------------
      52              :  * GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel-callbacks
      53              :  * ----------------------------------------------------------------------- */
      54              : FXDEFMAP(GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel) GUITLLogicPhasesTrackerPanelMap[] = {
      55              :     FXMAPFUNC(SEL_CONFIGURE, 0, GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel::onConfigure),
      56              :     FXMAPFUNC(SEL_PAINT,     0, GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel::onPaint),
      57              :     FXMAPFUNC(SEL_MOTION,    0, GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel::onMouseMove),
      58              : 
      59              : };
      60              : 
      61              : // Macro for the GLTestApp class hierarchy implementation
      62            0 : FXIMPLEMENT(GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel, FXGLCanvas, GUITLLogicPhasesTrackerPanelMap, ARRAYNUMBER(GUITLLogicPhasesTrackerPanelMap))
      63              : 
      64              : 
      65              : 
      66              : /* -------------------------------------------------------------------------
      67              :  * GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel-methods
      68              :  * ----------------------------------------------------------------------- */
      69            0 : GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel::GUITLLogicPhasesTrackerPanel(
      70              :     FXComposite* c, GUIMainWindow& app,
      71            0 :     GUITLLogicPhasesTrackerWindow& parent) :
      72            0 :     FXGLCanvas(c, app.getGLVisual(), app.getBuildGLCanvas(), (FXObject*) nullptr, (FXSelector) 0, LAYOUT_SIDE_TOP | LAYOUT_FILL_X | LAYOUT_FILL_Y/*, 0, 0, 300, 200*/),
      73            0 :     myParent(&parent)
      74            0 : {}
      75              : 
      76              : 
      77            0 : GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel::~GUITLLogicPhasesTrackerPanel() {}
      78              : 
      79              : 
      80              : long
      81            0 : GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel::onConfigure(FXObject*, FXSelector, void*) {
      82            0 :     if (makeCurrent()) {
      83              :         int widthInPixels = getWidth();
      84              :         int heightInPixels = getHeight();
      85            0 :         if (widthInPixels != 0 && heightInPixels != 0) {
      86            0 :             glViewport(0, 0, widthInPixels - 1, heightInPixels - 1);
      87            0 :             glClearColor(0, 0, 0, 1);
      88            0 :             glDisable(GL_DEPTH_TEST);
      89            0 :             glDisable(GL_LIGHTING);
      90            0 :             glDisable(GL_LINE_SMOOTH);
      91            0 :             glEnable(GL_BLEND);
      92            0 :             glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
      93            0 :             glEnable(GL_ALPHA_TEST);
      94            0 :             glDisable(GL_COLOR_MATERIAL);
      95            0 :             glLineWidth(1);
      96            0 :             glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
      97              :         }
      98              :     }
      99            0 :     return 1;
     100              : }
     101              : 
     102              : 
     103              : long
     104            0 : GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel::onPaint(
     105              :     FXObject*, FXSelector, void*) {
     106            0 :     if (!isEnabled()) {
     107              :         return 1;
     108              :     }
     109            0 :     if (makeCurrent()) {
     110              :         int widthInPixels = getWidth();
     111              :         int heightInPixels = getHeight();
     112            0 :         if (widthInPixels != 0 && heightInPixels != 0) {
     113            0 :             glViewport(0, 0, widthInPixels - 1, heightInPixels - 1);
     114            0 :             glClearColor(0, 0, 0, 1);
     115            0 :             glDisable(GL_DEPTH_TEST);
     116            0 :             glDisable(GL_LIGHTING);
     117            0 :             glDisable(GL_LINE_SMOOTH);
     118            0 :             glEnable(GL_BLEND);
     119            0 :             glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
     120            0 :             glEnable(GL_ALPHA_TEST);
     121            0 :             glDisable(GL_COLOR_MATERIAL);
     122            0 :             glLineWidth(1);
     123            0 :             glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
     124              :             // draw
     125            0 :             glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
     126            0 :             myParent->drawValues(*this);
     127            0 :             swapBuffers();
     128              :         }
     129            0 :         makeNonCurrent();
     130              :     }
     131              :     return 1;
     132              : }
     133              : 
     134              : 
     135              : long
     136            0 : GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel::onMouseMove(FXObject*, FXSelector, void* ptr) {
     137              :     FXEvent* event = (FXEvent*) ptr;
     138            0 :     myMousePos.setx(event->win_x);
     139            0 :     myMousePos.sety(event->win_y);
     140            0 :     onPaint(nullptr, 0, nullptr);
     141            0 :     return 1;
     142              : }
     143              : 
     144              : /* -------------------------------------------------------------------------
     145              :  * GUITLLogicPhasesTrackerWindow - FOX callback mapping
     146              :  * ----------------------------------------------------------------------- */
     147              : FXDEFMAP(GUITLLogicPhasesTrackerWindow) GUITLLogicPhasesTrackerWindowMap[] = {
     148              :     FXMAPFUNC(SEL_CONFIGURE, 0,           GUITLLogicPhasesTrackerWindow::onConfigure),
     149              :     FXMAPFUNC(SEL_PAINT,     0,           GUITLLogicPhasesTrackerWindow::onPaint),
     150              :     FXMAPFUNC(SEL_COMMAND,   MID_SIMSTEP, GUITLLogicPhasesTrackerWindow::onSimStep),
     151              : 
     152              : };
     153              : 
     154            0 : FXIMPLEMENT(GUITLLogicPhasesTrackerWindow, FXMainWindow, GUITLLogicPhasesTrackerWindowMap, ARRAYNUMBER(GUITLLogicPhasesTrackerWindowMap))
     155              : 
     156              : 
     157              : /* -------------------------------------------------------------------------
     158              :  * GUITLLogicPhasesTrackerWindow-methods
     159              :  * ----------------------------------------------------------------------- */
     160            0 : GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerWindow(
     161              :     GUIMainWindow& app,
     162              :     MSTrafficLightLogic& logic, GUITrafficLightLogicWrapper& wrapper,
     163            0 :     ValueSource<std::pair<SUMOTime, MSPhaseDefinition> >* src) :
     164              :     FXMainWindow(app.getApp(), "TLS-Tracker", nullptr, nullptr, DECOR_ALL, 20, 20, 300, 200),
     165            0 :     myApplication(&app),
     166            0 :     myTLLogic(&logic),
     167            0 :     myAmInTrackingMode(true) {
     168            0 :     initToolBar();
     169            0 :     myConnector = new GLObjectValuePassConnector<std::pair<SUMOTime, MSPhaseDefinition> >(wrapper, src, this);
     170            0 :     app.addChild(this);
     171            0 :     for (int i = 0; i < (int)myTLLogic->getLinks().size(); ++i) {
     172            0 :         myLinkNames.push_back(toString<int>(i));
     173              :     }
     174            0 :     for (auto item : myTLLogic->getDetectorStates()) {
     175              :         std::string detID = item.first;
     176            0 :         if (detID.size() > 4) {
     177            0 :             detID = detID.substr(detID.size() - 4);
     178              :         }
     179            0 :         myDetectorNames.push_back(detID);
     180              :     }
     181            0 :     for (auto item : myTLLogic->getConditions()) {
     182            0 :         myConditionNames.push_back(item.first);
     183              :     }
     184            0 :     loadSettings();
     185            0 :     const int newHeight = computeHeight();
     186            0 :     FXScrollWindow* scrollWindow = new FXScrollWindow(this, LAYOUT_FILL_X | LAYOUT_FILL_Y | HSCROLLER_NEVER | FRAME_NONE);
     187            0 :     FXHorizontalFrame* spacerFrame = new FXHorizontalFrame(scrollWindow, LAYOUT_SIDE_TOP | LAYOUT_FILL_X | LAYOUT_FILL_Y | FRAME_NONE);
     188            0 :     new FXScrollWindow(spacerFrame, LAYOUT_FIX_WIDTH | LAYOUT_FIX_HEIGHT | FRAME_NONE, 0, 0, 0, newHeight - 40);
     189              :     FXVerticalFrame* glcanvasFrame =
     190              :         new FXVerticalFrame(spacerFrame,
     191              :                             FRAME_SUNKEN | LAYOUT_SIDE_TOP | LAYOUT_FILL_X | LAYOUT_FILL_Y,
     192            0 :                             0, 0, 0, 0, 0, 0, 0, 0);
     193            0 :     myPanel = new GUITLLogicPhasesTrackerPanel(glcanvasFrame, *myApplication, *this);
     194            0 :     setTitle((logic.getID() + " - " + logic.getProgramID() + " - tracker").c_str());
     195            0 :     setIcon(GUIIconSubSys::getIcon(GUIIcon::APP_TLSTRACKER));
     196            0 :     setHeight(newHeight);
     197            0 : }
     198              : 
     199              : 
     200            0 : GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerWindow(
     201              :     GUIMainWindow& app,
     202              :     MSTrafficLightLogic& logic, GUITrafficLightLogicWrapper& /*wrapper*/,
     203            0 :     const MSSimpleTrafficLightLogic::Phases& /*phases*/) :
     204              :     FXMainWindow(app.getApp(), "TLS-Tracker", nullptr, nullptr, DECOR_ALL, 20, 20, 300, 200),
     205            0 :     myApplication(&app),
     206            0 :     myTLLogic(&logic),
     207            0 :     myAmInTrackingMode(false),
     208            0 :     myToolBarDrag(nullptr),
     209            0 :     myBeginOffset(nullptr) {
     210            0 :     myConnector = nullptr;
     211            0 :     initToolBar();
     212            0 :     app.addChild(this);
     213            0 :     for (int i = 0; i < (int)myTLLogic->getLinks().size(); ++i) {
     214            0 :         myLinkNames.push_back(toString<int>(i));
     215              :     }
     216            0 :     int newHeight = computeHeight();
     217            0 :     FXScrollWindow* scrollWindow = new FXScrollWindow(this, LAYOUT_FILL_X | LAYOUT_FILL_Y | HSCROLLER_NEVER | FRAME_NONE);
     218            0 :     FXHorizontalFrame* spacerFrame = new FXHorizontalFrame(scrollWindow, LAYOUT_SIDE_TOP | LAYOUT_FILL_X | LAYOUT_FILL_Y | FRAME_NONE);
     219            0 :     new FXScrollWindow(spacerFrame, LAYOUT_FIX_WIDTH | LAYOUT_FIX_HEIGHT | FRAME_NONE, 0, 0, 0, newHeight - 40);
     220              :     FXVerticalFrame* glcanvasFrame =
     221              :         new FXVerticalFrame(spacerFrame,
     222              :                             FRAME_SUNKEN | LAYOUT_SIDE_TOP | LAYOUT_FILL_X | LAYOUT_FILL_Y,
     223            0 :                             0, 0, 0, 0, 0, 0, 0, 0);
     224            0 :     myPanel = new GUITLLogicPhasesTrackerPanel(glcanvasFrame, *myApplication, *this);
     225            0 :     setTitle((logic.getID() + " - " + logic.getProgramID() + " - phases").c_str());
     226            0 :     setIcon(GUIIconSubSys::getIcon(GUIIcon::APP_TLSTRACKER));
     227            0 :     setHeight(newHeight);
     228            0 :     setWidth(700);
     229            0 : }
     230              : 
     231              : 
     232            0 : GUITLLogicPhasesTrackerWindow::~GUITLLogicPhasesTrackerWindow() {
     233            0 :     if (myAmInTrackingMode) {
     234            0 :         saveSettings();
     235            0 :         myLastY = -1;
     236              :     }
     237            0 :     myApplication->removeChild(this);
     238            0 :     delete myConnector;
     239              :     // just to quit cleanly on a failure
     240            0 :     if (myLock.locked()) {
     241            0 :         myLock.unlock();
     242              :     }
     243            0 :     delete myToolBarDrag;
     244            0 : }
     245              : 
     246              : void
     247            0 : GUITLLogicPhasesTrackerWindow::initToolBar() {
     248            0 :     myToolBarDrag = new FXToolBarShell(this, GUIDesignToolBar);
     249            0 :     myToolBar = new FXToolBar(this, myToolBarDrag, LAYOUT_SIDE_TOP | LAYOUT_FILL_X | FRAME_RAISED);
     250            0 :     new FXToolBarGrip(myToolBar, myToolBar, FXToolBar::ID_TOOLBARGRIP, GUIDesignToolBarGrip);
     251              : 
     252            0 :     if (myAmInTrackingMode) {
     253              :         // interval manipulation
     254            0 :         new FXLabel(myToolBar, "range (s):", nullptr, LAYOUT_CENTER_Y);
     255            0 :         myBeginOffset = new FXRealSpinner(myToolBar, 4, this, MID_SIMSTEP, LAYOUT_TOP | FRAME_SUNKEN | FRAME_THICK);
     256              :         //myBeginOffset->setFormatString("%.0f");
     257              :         //myBeginOffset->setIncrements(1, 10, 100);
     258            0 :         myBeginOffset->setIncrement(10);
     259            0 :         myBeginOffset->setRange(60, 3600);
     260            0 :         myBeginOffset->setValue(240);
     261              :     }
     262              : 
     263            0 :     new FXLabel(myToolBar, "time style:", nullptr, LAYOUT_CENTER_Y);
     264            0 :     myTimeMode = new MFXComboBoxIcon(myToolBar, 11, false, GUIDesignComboBoxVisibleItemsMedium,
     265            0 :                                      this, MID_SIMSTEP, GUIDesignViewSettingsComboBox1);
     266            0 :     myTimeMode->appendIconItem("seconds");
     267            0 :     myTimeMode->appendIconItem("MM:SS");
     268            0 :     myTimeMode->appendIconItem("time in cycle");
     269              : 
     270            0 :     new FXLabel(myToolBar, "green time", nullptr, LAYOUT_CENTER_Y);
     271            0 :     myGreenMode = new MFXComboBoxIcon(myToolBar, 6, false, GUIDesignComboBoxVisibleItemsMedium,
     272            0 :                                       this, MID_SIMSTEP, GUIDesignViewSettingsComboBox1);
     273            0 :     myGreenMode->appendIconItem("off");
     274            0 :     myGreenMode->appendIconItem("phase");
     275            0 :     myGreenMode->appendIconItem("running");
     276              : 
     277            0 :     myIndexMode = new FXCheckButton(myToolBar, TL("phase names"), this, MID_SIMSTEP);
     278              : 
     279            0 :     if (myAmInTrackingMode) {
     280            0 :         myDetectorMode = new FXCheckButton(myToolBar, TL("detectors"), this, MID_SIMSTEP);
     281            0 :         myConditionMode = new FXCheckButton(myToolBar, TL("conditions"), this, MID_SIMSTEP);
     282              :     } else {
     283            0 :         myDetectorMode = nullptr;
     284            0 :         myConditionMode = nullptr;
     285              :     }
     286            0 : }
     287              : 
     288              : 
     289              : void
     290            0 : GUITLLogicPhasesTrackerWindow::create() {
     291            0 :     FXMainWindow::create();
     292            0 :     if (myToolBarDrag != nullptr) {
     293            0 :         myToolBarDrag->create();
     294              :     }
     295            0 : }
     296              : 
     297              : int
     298            0 : GUITLLogicPhasesTrackerWindow::computeHeight() {
     299            0 :     int newHeight = (int)myTLLogic->getLinks().size() * 20 + 30 + 8 + 30 + 60;
     300            0 :     if (myAmInTrackingMode) {
     301              :         newHeight += 20; // time bar
     302            0 :         newHeight += 10; // something extra caused by the scroll frames
     303            0 :         if (myDetectorMode->getCheck()) {
     304            0 :             newHeight += (int)myTLLogic->getDetectorStates().size() * 20 + 5;
     305              :         }
     306            0 :         if (myConditionMode->getCheck()) {
     307            0 :             newHeight += (int)myTLLogic->getConditions().size() * 20 + 5;
     308              :         }
     309              :     }
     310            0 :     return newHeight;
     311              : }
     312              : 
     313              : void
     314            0 : GUITLLogicPhasesTrackerWindow::drawValues(GUITLLogicPhasesTrackerPanel& caller) {
     315              :     // compute what shall be shown (what is visible)
     316            0 :     myFirstPhase2Show = 0;
     317            0 :     myFirstPhaseOffset = 0;
     318              :     SUMOTime leftOffset = 0;
     319            0 :     myFirstDet2Show = 0;
     320            0 :     myFirstDetOffset = 0;
     321            0 :     myFirstCond2Show = 0;
     322            0 :     myFirstCondOffset = 0;
     323            0 :     myFirstTime2Show = 0;
     324            0 :     if (!myAmInTrackingMode) {
     325              :         myPhases.clear();
     326              :         myDurations.clear();
     327              :         myTimeInCycle.clear();
     328              :         myPhaseIndex.clear();
     329              :         // insert phases
     330            0 :         MSSimpleTrafficLightLogic* simpleTLLogic = dynamic_cast<MSSimpleTrafficLightLogic*>(myTLLogic);
     331            0 :         if (simpleTLLogic == nullptr) {
     332            0 :             return;
     333              :         }
     334            0 :         myLastTime = 0;
     335            0 :         myBeginTime = 0;
     336              :         int idx = 0;
     337            0 :         for (MSPhaseDefinition* const phase : simpleTLLogic->getPhases()) {
     338            0 :             myPhases.push_back(*phase);
     339            0 :             myDurations.push_back(phase->duration);
     340            0 :             myTimeInCycle.push_back(myLastTime);
     341            0 :             myPhaseIndex.push_back(idx++);
     342            0 :             myLastTime += phase->duration;
     343              :         }
     344            0 :         if (myLastTime <= myBeginTime) {
     345            0 :             WRITE_ERROR(TL("Overflow in time computation occurred."));
     346            0 :             return;
     347              :         }
     348              :     } else {
     349            0 :         SUMOTime beginOffset = TIME2STEPS(myBeginOffset->getValue());
     350            0 :         myBeginTime = myLastTime - beginOffset;
     351            0 :         myFirstTime2Show = myBeginTime;
     352              :         // check whether no phases are known at all
     353            0 :         if (myDurations.size() != 0) {
     354              :             SUMOTime durs = 0;
     355            0 :             int phaseOffset = (int)myDurations.size() - 1;
     356              :             DurationsVector::reverse_iterator i = myDurations.rbegin();
     357            0 :             while (i != myDurations.rend()) {
     358            0 :                 if (durs + (*i) > beginOffset) {
     359            0 :                     myFirstPhase2Show = phaseOffset;
     360            0 :                     myFirstPhaseOffset = (durs + (*i)) - beginOffset;
     361            0 :                     break;
     362              :                 }
     363              :                 durs += (*i);
     364            0 :                 phaseOffset--;
     365              :                 ++i;
     366              :             }
     367            0 :             if (i == myDurations.rend()) {
     368              :                 // there are too few information stored;
     369            0 :                 myFirstPhase2Show = 0;
     370            0 :                 myFirstPhaseOffset = 0;
     371            0 :                 leftOffset = beginOffset - durs;
     372              :             }
     373              :         }
     374            0 :         if (myDetectorDurations.size() != 0) {
     375              :             SUMOTime durs = 0;
     376            0 :             int phaseOffset = (int)myDetectorDurations.size() - 1;
     377              :             DurationsVector::reverse_iterator i = myDetectorDurations.rbegin();
     378            0 :             while (i != myDetectorDurations.rend()) {
     379            0 :                 if (durs + (*i) > beginOffset) {
     380            0 :                     myFirstDet2Show = phaseOffset;
     381            0 :                     myFirstDetOffset = (durs + (*i)) - beginOffset;
     382            0 :                     break;
     383              :                 }
     384              :                 durs += (*i);
     385            0 :                 phaseOffset--;
     386              :                 ++i;
     387              :             }
     388            0 :             if (i == myDetectorDurations.rend()) {
     389              :                 // there are too few information stored;
     390            0 :                 myFirstDet2Show = 0;
     391            0 :                 myFirstDetOffset = 0;
     392              :             }
     393              :         }
     394            0 :         if (myConditionDurations.size() != 0) {
     395              :             SUMOTime durs = 0;
     396            0 :             int phaseOffset = (int)myConditionDurations.size() - 1;
     397              :             DurationsVector::reverse_iterator i = myConditionDurations.rbegin();
     398            0 :             while (i != myConditionDurations.rend()) {
     399            0 :                 if (durs + (*i) > beginOffset) {
     400            0 :                     myFirstCond2Show = phaseOffset;
     401            0 :                     myFirstCondOffset = (durs + (*i)) - beginOffset;
     402            0 :                     break;
     403              :                 }
     404              :                 durs += (*i);
     405            0 :                 phaseOffset--;
     406              :                 ++i;
     407              :             }
     408            0 :             if (i == myConditionDurations.rend()) {
     409              :                 // there are too few information stored;
     410            0 :                 myFirstCond2Show = 0;
     411            0 :                 myFirstCondOffset = 0;
     412              :             }
     413              :         }
     414              :     }
     415              :     // begin drawing
     416            0 :     glMatrixMode(GL_PROJECTION);
     417            0 :     glLoadIdentity();
     418            0 :     glMatrixMode(GL_MODELVIEW);
     419            0 :     glLoadIdentity();
     420            0 :     glTranslated(-1, -1, 0);
     421            0 :     glScaled(2, 2, 1);
     422            0 :     glDisable(GL_TEXTURE_2D);
     423              :     // draw the horizontal lines dividing the signal groups
     424            0 :     glColor3d(1, 1, 1);
     425              :     // compute some values needed more than once
     426            0 :     const double panelHeight = (double) caller.getHeight();
     427            0 :     const double panelWidth = (double) caller.getWidth();
     428            0 :     const double barWidth = MAX2(1.0, panelWidth - 31);
     429            0 :     const double fontHeight = 0.06 * 300. / panelHeight;
     430            0 :     const double fontWidth = 0.06 * 300. / panelWidth;
     431            0 :     const double h9 = 9. / panelHeight;
     432            0 :     const double hTop = 20. / panelHeight;
     433            0 :     const double h11 = 11. / panelHeight;
     434            0 :     const double stateHeight = 16. / panelHeight;
     435              :     const double h20 = 20. / panelHeight;
     436            0 :     const double h30 = 15. / panelHeight;
     437            0 :     const double h35 = 34. / panelHeight;
     438            0 :     const double h60 = 70. / panelHeight;
     439            0 :     const double h75 = 73. / panelHeight;
     440            0 :     const double h80 = 90. / panelHeight;
     441            0 :     const double w30 = 30 / panelWidth;
     442            0 :     double h = 1. - hTop;
     443              :     // draw the line below indices
     444            0 :     glColor3d(1, 1, 1);
     445            0 :     glBegin(GL_LINES);
     446            0 :     glVertex2d(0, h);
     447            0 :     glVertex2d(1, h);
     448            0 :     glEnd();
     449              :     // draw the link names and the lines dividing them
     450            0 :     drawNames(myLinkNames, fontHeight, fontWidth, h20, w30, h, 0);
     451            0 :     glBegin(GL_LINES);
     452            0 :     glVertex2d(0, h + h20);
     453            0 :     glVertex2d(1.0, h + h20);
     454            0 :     glEnd();
     455              : 
     456              :     // draw the names closure (vertical line)
     457            0 :     h += h20;
     458            0 :     glColor3d(1, 1, 1);
     459            0 :     glBegin(GL_LINES);
     460            0 :     glVertex2d(w30, 1.);
     461            0 :     glVertex2d(w30, h);
     462            0 :     glEnd();
     463              : 
     464            0 :     if (myAmInTrackingMode) {
     465              :         // optionally draw detector names
     466            0 :         h -= h60;
     467            0 :         if (myDetectorMode->getCheck()) {
     468              :             const double top = h;
     469            0 :             glBegin(GL_LINES);
     470            0 :             glVertex2d(0, h);
     471            0 :             glVertex2d(1.0, h);
     472            0 :             glEnd();
     473            0 :             drawNames(myDetectorNames, fontHeight * 0.7, fontWidth * 0.7, h20, w30, h, 3);
     474            0 :             glBegin(GL_LINES);
     475            0 :             glVertex2d(0, h + h20);
     476            0 :             glVertex2d(1.0, h + h20);
     477            0 :             glEnd();
     478              :             // draw the names closure (vertical line)
     479            0 :             glColor3d(1, 1, 1);
     480            0 :             glBegin(GL_LINES);
     481            0 :             glVertex2d(30. / panelWidth, top);
     482            0 :             glVertex2d(30. / panelWidth, h + h20);
     483            0 :             glEnd();
     484            0 :             h -= h30;
     485              :         }
     486              :         // optionally draw condition names
     487            0 :         if (myConditionMode->getCheck()) {
     488            0 :             const double top = h;
     489            0 :             glBegin(GL_LINES);
     490            0 :             glVertex2d(0, h);
     491            0 :             glVertex2d(1.0, h);
     492            0 :             glEnd();
     493            0 :             drawNames(myConditionNames, fontHeight * 0.7, fontWidth * 0.7, h20, w30, h, 3);
     494            0 :             glBegin(GL_LINES);
     495            0 :             glVertex2d(0, h + h20);
     496            0 :             glVertex2d(1.0, h + h20);
     497            0 :             glEnd();
     498              :             // draw the names closure (vertical line)
     499            0 :             glColor3d(1, 1, 1);
     500            0 :             glBegin(GL_LINES);
     501            0 :             glVertex2d(30. / panelWidth, top);
     502            0 :             glVertex2d(30. / panelWidth, h + h20);
     503            0 :             glEnd();
     504              :         }
     505              :     }
     506              : 
     507              :     // draw the phases
     508              :     // disable value addition while drawing
     509            0 :     myLock.lock();
     510              :     // determine the initial offset
     511            0 :     double x = 31. / panelWidth;
     512            0 :     double ta = (double) leftOffset / panelWidth;
     513            0 :     ta *= barWidth / ((double)(myLastTime - myBeginTime));
     514            0 :     x += ta;
     515              : 
     516              :     // and the initial phase information
     517            0 :     PhasesVector::iterator pi = myPhases.begin() + myFirstPhase2Show;
     518              :     IndexVector::iterator ii = myPhaseIndex.begin() + myFirstPhase2Show;
     519              : 
     520            0 :     SUMOTime fpo = myFirstPhaseOffset;
     521            0 :     const bool phaseNames = myIndexMode->getCheck() == TRUE;
     522            0 :     std::string lastName = "";
     523              :     double spaceForName = 0;
     524              : 
     525              :     // start drawing
     526            0 :     std::vector<SUMOTime> runningGreen(myTLLogic->getLinks().size(), 0);
     527            0 :     for (DurationsVector::iterator pd = myDurations.begin() + myFirstPhase2Show; pd != myDurations.end(); ++pd) {
     528              :         // the first phase may be drawn incompletely
     529            0 :         SUMOTime duration = *pd - fpo;
     530              :         // compute the height and the width of the phase
     531            0 :         h = 1. - hTop;
     532            0 :         double a = (double) duration / panelWidth;
     533            0 :         a *= barWidth / ((double)(myLastTime - myBeginTime));
     534            0 :         const double x2 = x + a;
     535              : 
     536              :         // go through the links
     537            0 :         for (int j = 0; j < (int) myTLLogic->getLinks().size(); ++j) {
     538              :             // determine the current link's color
     539            0 :             LinkState state = pi->getSignalState(j);
     540              :             // draw the bar (red is drawn as a line)
     541            0 :             GLHelper::setColor(GUIVisualizationSettings::getLinkColor(state));
     542            0 :             switch (state) {
     543            0 :                 case LINKSTATE_TL_RED:
     544              :                 case LINKSTATE_TL_REDYELLOW:
     545              :                     // draw a thin line
     546            0 :                     glBegin(GL_QUADS);
     547            0 :                     glVertex2d(x, h - h11);
     548            0 :                     glVertex2d(x, h - h9);
     549            0 :                     glVertex2d(x2, h - h9);
     550            0 :                     glVertex2d(x2, h - h11);
     551            0 :                     glEnd();
     552              :                     break;
     553            0 :                 default:
     554              :                     // draw a thick block
     555            0 :                     glBegin(GL_QUADS);
     556            0 :                     glVertex2d(x, h - stateHeight);
     557            0 :                     glVertex2d(x, h);
     558            0 :                     glVertex2d(x2, h);
     559            0 :                     glVertex2d(x2, h - stateHeight);
     560            0 :                     glEnd();
     561              :                     break;
     562              :             }
     563            0 :             if (myGreenMode->getCurrentItem() != 0) {
     564              :                 SUMOTime drawnDuration = 0;
     565              :                 double xOffset = 0;
     566            0 :                 if (state == LINKSTATE_TL_GREEN_MINOR || state == LINKSTATE_TL_GREEN_MAJOR) {
     567            0 :                     if (myGreenMode->getCurrentItem() == 1) {
     568            0 :                         drawnDuration = *pd;
     569              :                     } else {
     570            0 :                         runningGreen[j] += *pd;
     571            0 :                         if (pd + 1 == myDurations.end()) {
     572              :                             drawnDuration = runningGreen[j];
     573            0 :                             xOffset =  -(double)(drawnDuration - *pd) / panelWidth * (barWidth / ((double)(myLastTime - myBeginTime)));
     574              :                         }
     575              :                     }
     576              :                 } else {
     577            0 :                     if (runningGreen[j] > 0) {
     578              :                         drawnDuration = runningGreen[j];
     579            0 :                         xOffset =  -(double)drawnDuration / panelWidth * (barWidth / ((double)(myLastTime - myBeginTime)));
     580              :                     }
     581            0 :                     runningGreen[j] = 0;
     582              :                 }
     583            0 :                 if (drawnDuration > 0) {
     584            0 :                     GLHelper::drawText(toString((int)STEPS2TIME(drawnDuration)),
     585            0 :                                        Position(x + xOffset, h - h9),
     586              :                                        0, fontHeight, RGBColor::BLACK, 0, FONS_ALIGN_LEFT | FONS_ALIGN_MIDDLE, fontWidth);
     587              :                 }
     588              :             }
     589              :             // proceed to next link
     590            0 :             h -= h20;
     591              :         }
     592              : 
     593              :         // draw phase index / name (no names for intermediate)
     594            0 :         std::string name = phaseNames ? pi->getName() : toString(*ii);
     595            0 :         if (name != lastName) {
     596            0 :             const double lastNameWidth = GLHelper::getTextWidth(lastName, fontWidth);
     597            0 :             if (spaceForName < lastNameWidth) {
     598              :                 // clear space to avoid overdrawn text
     599            0 :                 glColor3d(0, 0, 0);
     600            0 :                 glBegin(GL_QUADS);
     601            0 :                 glVertex2d(x, 1 - fontHeight);
     602            0 :                 glVertex2d(x, 1);
     603            0 :                 glVertex2d(1, 1);
     604            0 :                 glVertex2d(1, 1 - fontHeight);
     605            0 :                 glEnd();
     606              :             }
     607              :             spaceForName = a;
     608            0 :             GLHelper::drawText(name, Position(x, 1 - hTop), 0, fontHeight, RGBColor::WHITE, 0, FONS_ALIGN_LEFT | FONS_ALIGN_BOTTOM, fontWidth);
     609              :         } else {
     610            0 :             spaceForName += a;
     611              :         }
     612              :         lastName = name;
     613              :         // proceed to next phase
     614              :         ++pi;
     615              :         ++ii;
     616              :         x = x2;
     617              :         // all further phases are drawn in full
     618              :         fpo = 0;
     619              :     }
     620              : 
     621            0 :     if (myAmInTrackingMode) {
     622            0 :         h -= h75;
     623            0 :         if (myDetectorMode->getCheck()) {
     624            0 :             glColor3d(0.7, 0.7, 1.0);
     625            0 :             drawAdditionalStates(caller, myDetectorStates, myDetectorDurations, myFirstDetOffset, myFirstDet2Show, h,
     626              :                                  panelWidth, (double)leftOffset, barWidth, stateHeight, h20, h);
     627            0 :             h -= h35;
     628              :         }
     629            0 :         if (myConditionMode->getCheck()) {
     630            0 :             glColor3d(0.9, 0.6, 0.9);
     631            0 :             drawAdditionalStates(caller, myConditionStates, myConditionDurations, myFirstCondOffset, myFirstCond2Show, h,
     632              :                                  panelWidth, (double)leftOffset, barWidth, stateHeight, h20, h);
     633              :         }
     634              :     }
     635              :     // allow value addition
     636            0 :     myLock.unlock();
     637              : 
     638            0 :     if (myPhases.size() != 0) {
     639            0 :         const double timeRange = STEPS2TIME(myLastTime - myBeginTime);
     640              :         SUMOTime tickDist = TIME2STEPS(10);
     641              :         // patch distances - hack
     642            0 :         double t = myBeginOffset != nullptr ? myBeginOffset->getValue() : timeRange;
     643            0 :         while (t > barWidth / 4.) {
     644              :             tickDist += TIME2STEPS(10);
     645            0 :             t -= barWidth / 4.;
     646              :         }
     647              :         // draw time information
     648              :         //h = (double)(myTLLogic->getLinks().size() * 20 + 12);
     649            0 :         double glh = 1. - (double)myTLLogic->getLinks().size() * h20 - hTop;
     650              :         // current begin time
     651              :         // time ticks
     652            0 :         SUMOTime currTime = myFirstTime2Show;
     653              :         double glpos = 31. / panelWidth;
     654            0 :         const double ticSize = 4. / panelHeight;
     655            0 :         if (leftOffset > 0) {
     656            0 :             const double a = STEPS2TIME(leftOffset) * barWidth / timeRange;
     657            0 :             glpos += a / panelWidth;
     658            0 :             currTime += leftOffset;
     659            0 :         } else if (myFirstPhaseOffset > 0) {
     660            0 :             const double a = STEPS2TIME(-myFirstPhaseOffset) * barWidth / timeRange;
     661            0 :             glpos += a / panelWidth;
     662            0 :             currTime -= myFirstPhaseOffset;
     663              :         }
     664            0 :         int ticShift = myFirstPhase2Show;
     665            0 :         const bool mmSS = myTimeMode->getCurrentItem() == 1;
     666            0 :         const bool cycleTime = myTimeMode->getCurrentItem() == 2;
     667              :         SUMOTime lastTimeInCycle = -1;
     668              :         lastName = "";
     669            0 :         pi = myPhases.begin() + myFirstPhase2Show;
     670            0 :         for (DurationsVector::iterator pd = myDurations.begin() + myFirstPhase2Show; pd != myDurations.end(); ++pd) {
     671            0 :             const SUMOTime timeInCycle = myTimeInCycle[pd - myDurations.begin()];
     672              :             // draw times at different heights
     673            0 :             ticShift = (ticShift % 3) + 1;
     674              :             const std::string timeStr = (mmSS
     675            0 :                                          ? StringUtils::padFront(toString((currTime % 3600000) / 60000), 2, '0') + ":"
     676            0 :                                          + StringUtils::padFront(toString((currTime % 60000) / 1000), 2, '0')
     677            0 :                                          : toString((int)STEPS2TIME(cycleTime ? timeInCycle : currTime)));
     678            0 :             const double w = 10 * (double)timeStr.size() / panelWidth;
     679            0 :             glTranslated(glpos - w / 2., glh - h20 * ticShift, 0);
     680            0 :             GLHelper::drawText(timeStr, Position(0, 0), 1, fontHeight, RGBColor::WHITE, 0, FONS_ALIGN_LEFT | FONS_ALIGN_MIDDLE, fontWidth);
     681            0 :             glTranslated(-glpos + w / 2., -glh + h20 * ticShift, 0);
     682              : 
     683              :             // draw tic
     684            0 :             glColor3d(1, 1, 1);
     685            0 :             glBegin(GL_LINES);
     686            0 :             glVertex2d(glpos, glh);
     687            0 :             glVertex2d(glpos, glh - ticSize * ticShift);
     688            0 :             glEnd();
     689              : 
     690              :             // draw vertical lines for names, detectors and conditions on each phase switch
     691            0 :             if (myAmInTrackingMode) {
     692              :                 double hStart = 1;
     693            0 :                 if (!phaseNames || (pi->getName() != lastName)) {
     694            0 :                     glColor3d(0.4, 0.4, 0.4);
     695            0 :                     glBegin(GL_LINES);
     696            0 :                     glVertex2d(glpos, hStart);
     697              :                     hStart -= h20;
     698            0 :                     glVertex2d(glpos, hStart);
     699            0 :                     glEnd();
     700              :                 }
     701              :                 lastName = pi->getName();
     702              : 
     703            0 :                 hStart = glh - h60;
     704            0 :                 if (myDetectorMode->getCheck() && glpos >= w30) {
     705            0 :                     glColor3d(0.4, 0.4, 0.4);
     706            0 :                     glBegin(GL_LINES);
     707            0 :                     glVertex2d(glpos, hStart);
     708            0 :                     hStart -= (double)myDetectorNames.size() * h20;
     709            0 :                     glVertex2d(glpos, hStart);
     710            0 :                     glEnd();
     711            0 :                     hStart -= h35;
     712              :                 }
     713            0 :                 if (myConditionMode->getCheck() && glpos >= w30) {
     714            0 :                     glColor3d(0.4, 0.4, 0.4);
     715            0 :                     glBegin(GL_LINES);
     716            0 :                     glVertex2d(glpos, hStart);
     717            0 :                     glVertex2d(glpos, hStart - (double)myConditionNames.size() * h20);
     718            0 :                     glEnd();
     719              :                 }
     720              :             }
     721              : 
     722              :             // draw vertical line for cycle reset
     723            0 :             if (timeInCycle == 0 || timeInCycle < lastTimeInCycle) {
     724            0 :                 const double cycle0pos = glpos - STEPS2TIME(timeInCycle) * barWidth / timeRange / panelWidth;
     725            0 :                 if (cycle0pos >= 31 / panelWidth) {
     726            0 :                     glColor3d(0.6, 0.6, 0.6);
     727            0 :                     glBegin(GL_LINES);
     728            0 :                     glVertex2d(cycle0pos, 1);
     729            0 :                     glVertex2d(cycle0pos, glh);
     730            0 :                     glEnd();
     731            0 :                     glColor3d(1, 1, 1);
     732              :                 }
     733              :             }
     734              : 
     735              :             lastTimeInCycle = timeInCycle;
     736            0 :             tickDist = *pd;
     737            0 :             const double a = STEPS2TIME(tickDist) * barWidth / timeRange;
     738            0 :             glpos += a / panelWidth;
     739            0 :             currTime += tickDist;
     740              :             ++pi;
     741              :         }
     742              : 
     743              :         // draw bottom time bar with fixed spacing
     744            0 :         if (myAmInTrackingMode && (myDetectorMode->getCheck() || myConditionMode->getCheck()) && glpos >= w30) {
     745            0 :             glColor3d(1, 1, 1);
     746              :             tickDist = TIME2STEPS(10);
     747              :             // patch distances - hack
     748            0 :             t = myBeginOffset != nullptr ? myBeginOffset->getValue() : STEPS2TIME(myLastTime - myBeginTime);
     749            0 :             while (t > barWidth / 4.) {
     750            0 :                 tickDist += TIME2STEPS(10);
     751            0 :                 t -= barWidth / 4.;
     752              :             }
     753            0 :             glh = 1. - (double)myLinkNames.size() * h20 - h80;
     754            0 :             glh -= h20 * (double)(myDetectorMode->getCheck() ? myDetectorNames.size() : myConditionNames.size());
     755            0 :             currTime = myFirstTime2Show;
     756              :             int pos = 31;
     757              :             glpos = (double) pos / panelWidth;
     758            0 :             if (leftOffset > 0) {
     759            0 :                 const double a = STEPS2TIME(leftOffset) * barWidth / timeRange;
     760            0 :                 pos += (int)a;
     761            0 :                 glpos += a / panelWidth;
     762            0 :                 currTime += leftOffset;
     763            0 :             } else if (myFirstPhaseOffset > 0) {
     764            0 :                 const double a = -STEPS2TIME(myBeginTime % tickDist) * barWidth / timeRange;
     765            0 :                 pos += (int)a;
     766            0 :                 glpos += a / panelWidth;
     767            0 :                 currTime = myBeginTime - (myBeginTime % tickDist);
     768              :             }
     769            0 :             while (pos < panelWidth + 50.) {
     770              :                 const std::string timeStr = (mmSS
     771            0 :                                              ? StringUtils::padFront(toString((currTime % 3600000) / 60000), 2, '0') + ":"
     772            0 :                                              + StringUtils::padFront(toString((currTime % 60000) / 1000), 2, '0')
     773            0 :                                              : toString((int)STEPS2TIME(cycleTime ? findTimeInCycle(currTime) : currTime)));
     774            0 :                 const double w = 10. * (double)timeStr.size() / panelWidth;
     775            0 :                 glTranslated(glpos - w / 2., glh - h20, 0);
     776            0 :                 GLHelper::drawText(timeStr, Position(0, 0), 1, fontHeight, RGBColor::WHITE, 0, FONS_ALIGN_LEFT | FONS_ALIGN_MIDDLE, fontWidth);
     777            0 :                 glTranslated(-glpos + w / 2., -glh + h20, 0);
     778              : 
     779            0 :                 glBegin(GL_LINES);
     780            0 :                 glVertex2d(glpos, glh);
     781            0 :                 glVertex2d(glpos, glh - ticSize);
     782            0 :                 glEnd();
     783              : 
     784            0 :                 const double a = STEPS2TIME(tickDist) * barWidth / STEPS2TIME(myLastTime - myBeginTime);
     785            0 :                 pos += (int) a;
     786            0 :                 glpos += a / panelWidth;
     787            0 :                 currTime += tickDist;
     788              :             }
     789              :         }
     790              :     }
     791            0 : }
     792              : 
     793              : 
     794              : void
     795            0 : GUITLLogicPhasesTrackerWindow::drawNames(const std::vector<std::string>& names, double fontHeight, double fontWidth, double divHeight, double divWidth, double& h, int extraLines) {
     796              :     int i = 0;
     797            0 :     for (const std::string& name : names) {
     798              :         // draw the bar
     799            0 :         glBegin(GL_LINES);
     800            0 :         glVertex2d(0, h);
     801            0 :         glVertex2d(divWidth, h);
     802            0 :         glEnd();
     803              :         // draw the name
     804            0 :         glTranslated(0, h - divHeight, 0);
     805            0 :         GLHelper::drawText(name, Position(0, 0), 1, fontHeight, RGBColor::WHITE, 0, FONS_ALIGN_LEFT | FONS_ALIGN_BOTTOM, fontWidth);
     806            0 :         glTranslated(0, -h + divHeight, 0);
     807              : 
     808            0 :         if (extraLines > 0 && i > 0 && i % extraLines == 0) {
     809            0 :             glColor3d(0.4, 0.4, 0.4);
     810            0 :             glBegin(GL_LINES);
     811            0 :             glVertex2d(divWidth, h);
     812            0 :             glVertex2d(1.0, h);
     813            0 :             glEnd();
     814            0 :             glColor3d(1, 1, 1);
     815              :         }
     816            0 :         h -= divHeight;
     817            0 :         i++;
     818              :     }
     819            0 :     h -= divHeight;
     820            0 : }
     821              : 
     822              : 
     823              : void
     824            0 : GUITLLogicPhasesTrackerWindow::drawAdditionalStates(GUITLLogicPhasesTrackerPanel& caller,
     825              :         const AdditionalStatesVector& states,
     826              :         const DurationsVector& durations, SUMOTime firstOffset, int first2Show, double hStart,
     827              :         double panelWidth, double leftOffset, double barWidth, double stateHeight, double h20, double& h) {
     828            0 :     double x = 31. / panelWidth;
     829            0 :     double ta = leftOffset / panelWidth;
     830            0 :     ta *= barWidth / ((double)(myLastTime - myBeginTime));
     831            0 :     x += ta;
     832              :     auto di = states.begin() + first2Show;
     833              :     SUMOTime fpo = firstOffset;
     834              : 
     835            0 :     double mx = caller.getMousePos().x() / caller.getWidth();
     836            0 :     double my = 1 - caller.getMousePos().y() / caller.getHeight();
     837            0 :     std::string tooltip = "";
     838              :     // start drawing
     839            0 :     for (auto pd = durations.begin() + first2Show; pd != durations.end(); ++pd) {
     840              :         // the first phase may be drawn incompletely
     841            0 :         SUMOTime duration = *pd - fpo;
     842              :         // compute the height and the width of the phase
     843            0 :         h = hStart;
     844            0 :         double a = (double) duration / panelWidth;
     845            0 :         a *= barWidth / ((double)(myLastTime - myBeginTime));
     846            0 :         const double x2 = x + a;
     847            0 :         const bool tooltipX = x < mx && mx < x2;
     848              :         //std::cout << SIMTIME << " detStates=" << toString(*di) << "\n";
     849              :         // go through the detectors
     850            0 :         for (double j : *di) {
     851            0 :             if (j != 0) {
     852              :                 // draw a thick block
     853            0 :                 glBegin(GL_QUADS);
     854            0 :                 glVertex2d(x, h - stateHeight);
     855            0 :                 glVertex2d(x, h);
     856            0 :                 glVertex2d(x2, h);
     857            0 :                 glVertex2d(x2, h - stateHeight);
     858            0 :                 glEnd();
     859            0 :                 if (tooltipX) {
     860            0 :                     const bool tooltipY = (h - stateHeight) < my && my < h;
     861              :                     if (tooltipY) {
     862            0 :                         tooltip = toString((int)j);
     863              :                     }
     864              :                 }
     865              :             }
     866              :             // proceed to next link
     867            0 :             h -= h20;
     868              :         }
     869              :         // proceed to next phase
     870              :         ++di;
     871              :         x = x2;
     872              :         // all further phases are drawn in full
     873              :         fpo = 0;
     874              :     }
     875            0 :     if (tooltip != "") {
     876              :         // delay tool tip drawing until all bars are drawn to prevent overwriting
     877            0 :         GLHelper::drawText(tooltip, Position(mx, my), 0, h20, RGBColor::YELLOW, 0, FONS_ALIGN_LEFT | FONS_ALIGN_MIDDLE, 20 / caller.getWidth());
     878              :     }
     879            0 : }
     880              : 
     881              : SUMOTime
     882            0 : GUITLLogicPhasesTrackerWindow::findTimeInCycle(SUMOTime t) {
     883              :     // find latest cycle reset before t
     884            0 :     int i = (int)myPhases.size() - 1;
     885            0 :     SUMOTime lookBack = myLastTime - t - myDurations.back();
     886              :     //std::cout << SIMTIME << " findTimeInCycle t=" << STEPS2TIME(t)
     887              :     //    << " last=" << STEPS2TIME(myLastTime)
     888              :     //    << " lastDur=" << STEPS2TIME(myDurations.back())
     889              :     //    << " lookBack=" << STEPS2TIME(lookBack)
     890              :     //    << " i0=" << i;
     891              :     // look backwards through the phases until to the first cycle crossing before t
     892            0 :     while (lookBack > 0 && i > 1) {
     893            0 :         i--;
     894            0 :         lookBack -= myDurations[i];
     895              :     }
     896            0 :     SUMOTime timeInCycle = myTimeInCycle[i < 0 ? 0 : i];
     897              :     //std::cout << " iF=" << i << " lookBack2=" << STEPS2TIME(lookBack) << " tic=" << STEPS2TIME(timeInCycle) << "\n";
     898            0 :     if (lookBack <= 0) {
     899            0 :         return timeInCycle - lookBack;
     900              :     }
     901            0 :     return myTLLogic->mapTimeInCycle(t);
     902              : }
     903              : 
     904              : void
     905            0 : GUITLLogicPhasesTrackerWindow::addValue(std::pair<SUMOTime, MSPhaseDefinition> def) {
     906              :     // do not draw while adding
     907            0 :     myLock.lock();
     908              :     // set the first time if not set before
     909            0 :     if (myPhases.size() == 0) {
     910            0 :         myBeginTime = def.first;
     911              :     }
     912              :     // append or set the phase
     913            0 :     if (myPhases.size() == 0 || myPhases.back() != def.second) {
     914            0 :         myPhases.push_back(def.second);
     915            0 :         myDurations.push_back(DELTA_T);
     916            0 :         myTimeInCycle.push_back(myTLLogic->mapTimeInCycle(def.first - DELTA_T));
     917            0 :         myPhaseIndex.push_back(myTLLogic->getCurrentPhaseIndex());
     918              :     } else {
     919            0 :         myDurations.back() += DELTA_T;
     920              :     }
     921              :     // updated detector states
     922              :     std::vector<double> detectorStates;
     923            0 :     for (auto item : myTLLogic->getDetectorStates()) {
     924            0 :         detectorStates.push_back(item.second);
     925              :     }
     926            0 :     if (myDetectorStates.size() == 0 || myDetectorStates.back() != detectorStates) {
     927            0 :         myDetectorStates.push_back(detectorStates);
     928            0 :         myDetectorDurations.push_back(DELTA_T);
     929              :     } else {
     930            0 :         myDetectorDurations.back() += DELTA_T;
     931              :     }
     932              :     // updated condition states
     933              :     std::vector<double> conditionStates;
     934            0 :     for (auto item : myTLLogic->getConditions()) {
     935            0 :         conditionStates.push_back(item.second);
     936              :     }
     937            0 :     if (myConditionStates.size() == 0 || myConditionStates.back() != conditionStates) {
     938            0 :         myConditionStates.push_back(conditionStates);
     939            0 :         myConditionDurations.push_back(DELTA_T);
     940              :     } else {
     941            0 :         myConditionDurations.back() += DELTA_T;
     942              :     }
     943              :     // set the last time a phase was added at
     944            0 :     myLastTime = def.first;
     945              :     // allow drawing
     946            0 :     myLock.unlock();
     947            0 : }
     948              : 
     949              : 
     950              : long
     951            0 : GUITLLogicPhasesTrackerWindow::onConfigure(FXObject* sender, FXSelector sel, void* ptr) {
     952            0 :     myPanel->onConfigure(sender, sel, ptr);
     953            0 :     return FXMainWindow::onConfigure(sender, sel, ptr);
     954              : }
     955              : 
     956              : 
     957              : long
     958            0 : GUITLLogicPhasesTrackerWindow::onPaint(FXObject* sender, FXSelector sel, void* ptr) {
     959            0 :     myPanel->onPaint(sender, sel, ptr);
     960            0 :     return FXMainWindow::onPaint(sender, sel, ptr);
     961              : }
     962              : 
     963              : 
     964              : long
     965            0 : GUITLLogicPhasesTrackerWindow::onSimStep(FXObject* sender, FXSelector, void*) {
     966            0 :     if (sender == myDetectorMode || sender == myConditionMode) {
     967            0 :         resize(getWidth(), computeHeight());
     968              :     }
     969            0 :     update();
     970            0 :     return 1;
     971              : }
     972              : 
     973              : 
     974              : void
     975            0 : GUITLLogicPhasesTrackerWindow::setBeginTime(SUMOTime time) {
     976            0 :     myBeginTime = time;
     977            0 : }
     978              : 
     979              : 
     980              : void
     981            0 : GUITLLogicPhasesTrackerWindow::saveSettings() {
     982            0 :     getApp()->reg().writeIntEntry("TL_TRACKER", "x", getX());
     983            0 :     getApp()->reg().writeIntEntry("TL_TRACKER", "y", getY());
     984            0 :     getApp()->reg().writeIntEntry("TL_TRACKER", "width", getWidth());
     985            0 :     getApp()->reg().writeIntEntry("TL_TRACKER", "timeRange", (int)myBeginOffset->getValue());
     986            0 :     getApp()->reg().writeIntEntry("TL_TRACKER", "timeMode", myTimeMode->getCurrentItem());
     987            0 :     getApp()->reg().writeIntEntry("TL_TRACKER", "greenMode", (myGreenMode->getCurrentItem()));
     988            0 :     getApp()->reg().writeIntEntry("TL_TRACKER", "indexMode", (int)(myIndexMode->getCheck()));
     989            0 :     getApp()->reg().writeIntEntry("TL_TRACKER", "detectorMode", (int)(myDetectorMode->getCheck()));
     990            0 :     getApp()->reg().writeIntEntry("TL_TRACKER", "conditionMode", (int)(myConditionMode->getCheck()));
     991            0 : }
     992              : 
     993              : 
     994              : void
     995            0 : GUITLLogicPhasesTrackerWindow::loadSettings() {
     996              :     // ensure window is visible after switching screen resolutions
     997              :     const FXint minSize = 400;
     998              :     const FXint minTitlebarHeight = 20;
     999            0 :     setX(MAX2(0, MIN2(getApp()->reg().readIntEntry("TL_TRACKER", "x", 150),
    1000              :                       getApp()->getRootWindow()->getWidth() - minSize)));
    1001            0 :     if (myLastY == -1) {
    1002            0 :         myLastY = MAX2(minTitlebarHeight,
    1003              :                        MIN2(getApp()->reg().readIntEntry("TL_TRACKER", "y", 150),
    1004              :                             getApp()->getRootWindow()->getHeight() - minSize));
    1005              :     } else {
    1006            0 :         myLastY += getHeight() + 20;
    1007              :     }
    1008            0 :     setY(myLastY);
    1009            0 :     setWidth(MAX2(getApp()->reg().readIntEntry("TL_TRACKER", "width", 700), minSize));
    1010            0 :     myBeginOffset->setValue(getApp()->reg().readIntEntry("TL_TRACKER", "timeRange", (int)myBeginOffset->getValue()));
    1011            0 :     myTimeMode->setCurrentItem(getApp()->reg().readIntEntry("TL_TRACKER", "timeMode", myTimeMode->getCurrentItem()));
    1012            0 :     myGreenMode->setCurrentItem(getApp()->reg().readIntEntry("TL_TRACKER", "greenMode", myGreenMode->getCurrentItem()));
    1013            0 :     myIndexMode->setCheck((FXbool)getApp()->reg().readIntEntry("TL_TRACKER", "indexMode", (int)(myIndexMode->getCheck())));
    1014            0 :     myDetectorMode->setCheck((FXbool)getApp()->reg().readIntEntry("TL_TRACKER", "detectorMode", (int)(myDetectorMode->getCheck())));
    1015            0 :     myConditionMode->setCheck((FXbool)getApp()->reg().readIntEntry("TL_TRACKER", "conditionMode", (int)(myConditionMode->getCheck())));
    1016            0 : }
    1017              : 
    1018              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1