SUMO - Simulation of Urban MObility
|
00001 /****************************************************************************/ 00009 // A window displaying the phase diagram of a tl-logic 00010 /****************************************************************************/ 00011 // SUMO, Simulation of Urban MObility; see http://sumo.sourceforge.net/ 00012 // Copyright (C) 2001-2012 DLR (http://www.dlr.de/) and contributors 00013 /****************************************************************************/ 00014 // 00015 // This file is part of SUMO. 00016 // SUMO is free software: you can redistribute it and/or modify 00017 // it under the terms of the GNU General Public License as published by 00018 // the Free Software Foundation, either version 3 of the License, or 00019 // (at your option) any later version. 00020 // 00021 /****************************************************************************/ 00022 00023 00024 // =========================================================================== 00025 // included modules 00026 // =========================================================================== 00027 #ifdef _MSC_VER 00028 #include <windows_config.h> 00029 #else 00030 #include <config.h> 00031 #endif 00032 00033 #include <cassert> 00034 #include <vector> 00035 #include <iostream> 00036 #include <utils/gui/windows/GUIMainWindow.h> 00037 #include "GUITLLogicPhasesTrackerWindow.h" 00038 #include <microsim/traffic_lights/MSTrafficLightLogic.h> 00039 #include <microsim/MSLink.h> 00040 #include <utils/common/ToString.h> 00041 #include <guisim/GUITrafficLightLogicWrapper.h> 00042 #include <utils/gui/images/GUITexturesHelper.h> 00043 #include <utils/gui/windows/GUIAppEnum.h> 00044 #include <utils/gui/images/GUIIconSubSys.h> 00045 #include <foreign/polyfonts/polyfonts.h> 00046 00047 #ifdef _WIN32 00048 #include <windows.h> 00049 #endif 00050 00051 #include <GL/gl.h> 00052 00053 #ifdef CHECK_MEMORY_LEAKS 00054 #include <foreign/nvwa/debug_new.h> 00055 #endif // CHECK_MEMORY_LEAKS 00056 00057 00058 // =========================================================================== 00059 // member method definitions 00060 // =========================================================================== 00061 /* ------------------------------------------------------------------------- 00062 * GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel-callbacks 00063 * ----------------------------------------------------------------------- */ 00064 FXDEFMAP(GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel) GUITLLogicPhasesTrackerPanelMap[] = { 00065 FXMAPFUNC(SEL_CONFIGURE, 0, GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel::onConfigure), 00066 FXMAPFUNC(SEL_PAINT, 0, GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel::onPaint), 00067 00068 }; 00069 00070 // Macro for the GLTestApp class hierarchy implementation 00071 FXIMPLEMENT(GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel, FXGLCanvas, GUITLLogicPhasesTrackerPanelMap, ARRAYNUMBER(GUITLLogicPhasesTrackerPanelMap)) 00072 00073 00074 00075 /* ------------------------------------------------------------------------- 00076 * GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel-methods 00077 * ----------------------------------------------------------------------- */ 00078 GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel::GUITLLogicPhasesTrackerPanel( 00079 FXComposite* c, GUIMainWindow& app, 00080 GUITLLogicPhasesTrackerWindow& parent) 00081 : FXGLCanvas(c, app.getGLVisual(), app.getBuildGLCanvas(), (FXObject*) 0, (FXSelector) 0, LAYOUT_SIDE_TOP | LAYOUT_FILL_X | LAYOUT_FILL_Y/*, 0, 0, 300, 200*/), 00082 myParent(&parent), myApplication(&app) {} 00083 00084 00085 GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel::~GUITLLogicPhasesTrackerPanel() {} 00086 00087 00088 long 00089 GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel::onConfigure( 00090 FXObject*, FXSelector, void*) { 00091 if (makeCurrent()) { 00092 int widthInPixels = getWidth(); 00093 int heightInPixels = getHeight(); 00094 if (widthInPixels != 0 && heightInPixels != 0) { 00095 glViewport(0, 0, widthInPixels - 1, heightInPixels - 1); 00096 glClearColor(0, 0, 0, 1); 00097 glDisable(GL_DEPTH_TEST); 00098 glDisable(GL_LIGHTING); 00099 glDisable(GL_LINE_SMOOTH); 00100 glEnable(GL_BLEND); 00101 glEnable(GL_ALPHA_TEST); 00102 glDisable(GL_COLOR_MATERIAL); 00103 glLineWidth(1); 00104 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 00105 } 00106 } 00107 return 1; 00108 } 00109 00110 00111 long 00112 GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel::onPaint( 00113 FXObject*, FXSelector, void*) { 00114 if (!isEnabled()) { 00115 return 1; 00116 } 00117 if (makeCurrent()) { 00118 int widthInPixels = getWidth(); 00119 int heightInPixels = getHeight(); 00120 if (widthInPixels != 0 && heightInPixels != 0) { 00121 glViewport(0, 0, widthInPixels - 1, heightInPixels - 1); 00122 glClearColor(0, 0, 0, 1); 00123 glDisable(GL_DEPTH_TEST); 00124 glDisable(GL_LIGHTING); 00125 glDisable(GL_LINE_SMOOTH); 00126 glEnable(GL_BLEND); 00127 glEnable(GL_ALPHA_TEST); 00128 glDisable(GL_COLOR_MATERIAL); 00129 glLineWidth(1); 00130 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 00131 // draw 00132 glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); 00133 myParent->drawValues(*this); 00134 swapBuffers(); 00135 } 00136 makeNonCurrent(); 00137 } 00138 return 1; 00139 } 00140 00141 00142 00143 /* ------------------------------------------------------------------------- 00144 * GUITLLogicPhasesTrackerWindow - FOX callback mapping 00145 * ----------------------------------------------------------------------- */ 00146 FXDEFMAP(GUITLLogicPhasesTrackerWindow) GUITLLogicPhasesTrackerWindowMap[] = { 00147 FXMAPFUNC(SEL_CONFIGURE, 0, GUITLLogicPhasesTrackerWindow::onConfigure), 00148 FXMAPFUNC(SEL_PAINT, 0, GUITLLogicPhasesTrackerWindow::onPaint), 00149 FXMAPFUNC(SEL_COMMAND, MID_SIMSTEP, GUITLLogicPhasesTrackerWindow::onSimStep), 00150 00151 }; 00152 00153 FXIMPLEMENT(GUITLLogicPhasesTrackerWindow, FXMainWindow, GUITLLogicPhasesTrackerWindowMap, ARRAYNUMBER(GUITLLogicPhasesTrackerWindowMap)) 00154 00155 00156 /* ------------------------------------------------------------------------- 00157 * GUITLLogicPhasesTrackerWindow-methods 00158 * ----------------------------------------------------------------------- */ 00159 GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerWindow( 00160 GUIMainWindow& app, 00161 MSTrafficLightLogic& logic, GUITrafficLightLogicWrapper& wrapper, 00162 ValueSource<std::pair<SUMOTime, MSPhaseDefinition> > *src) 00163 : FXMainWindow(app.getApp(), "TLS-Tracker", NULL, NULL, DECOR_ALL, 00164 20, 20, 300, 200), 00165 myApplication(&app), myTLLogic(&logic), myAmInTrackingMode(true) { 00166 // build the toolbar 00167 myToolBarDrag = new FXToolBarShell(this, FRAME_NORMAL); 00168 myToolBar = new FXToolBar(this, myToolBarDrag, LAYOUT_SIDE_TOP | LAYOUT_FILL_X | FRAME_RAISED); 00169 new FXToolBarGrip(myToolBar, myToolBar, FXToolBar::ID_TOOLBARGRIP, TOOLBARGRIP_DOUBLE); 00170 // interval manipulation 00171 myBeginOffset = new FXRealSpinDial(myToolBar, 10, this, MID_SIMSTEP, LAYOUT_TOP | FRAME_SUNKEN | FRAME_THICK); 00172 myBeginOffset->setFormatString("%.0f"); 00173 myBeginOffset->setIncrements(1, 10, 100); 00174 myBeginOffset->setRange(60, 3600); 00175 myBeginOffset->setValue(240); 00176 new FXLabel(myToolBar, "(s)", 0, LAYOUT_CENTER_Y); 00177 // 00178 myConnector = new GLObjectValuePassConnector<std::pair<SUMOTime, MSPhaseDefinition> >(wrapper, src, this); 00179 FXint height = (FXint)(myTLLogic->getLinks().size() * 20 + 30 + 8 + 30); 00180 app.addChild(this, true); 00181 for (size_t i = 0; i < myTLLogic->getLinks().size(); i++) { 00182 myLinkNames.push_back(toString<size_t>(i)); 00183 } 00184 FXVerticalFrame* glcanvasFrame = 00185 new FXVerticalFrame(this, 00186 FRAME_SUNKEN | LAYOUT_SIDE_TOP | LAYOUT_FILL_X | LAYOUT_FILL_Y, 00187 0, 0, 0, 0, 0, 0, 0, 0); 00188 myPanel = new 00189 GUITLLogicPhasesTrackerPanel(glcanvasFrame, *myApplication, *this); 00190 setTitle((logic.getID() + " - " + logic.getProgramID() + " - tracker").c_str()); 00191 setIcon(GUIIconSubSys::getIcon(ICON_APP_TLSTRACKER)); 00192 setHeight(height); 00193 } 00194 00195 00196 GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerWindow( 00197 GUIMainWindow& app, 00198 MSTrafficLightLogic& logic, GUITrafficLightLogicWrapper& /*wrapper*/, 00199 const MSSimpleTrafficLightLogic::Phases& /*phases*/) 00200 : FXMainWindow(app.getApp(), "TLS-Tracker", NULL, NULL, DECOR_ALL, 00201 20, 20, 300, 200), 00202 myApplication(&app), myTLLogic(&logic), myAmInTrackingMode(false), 00203 myToolBarDrag(0), myBeginOffset(0) { 00204 myConnector = 0; 00205 FXint height = (FXint)(myTLLogic->getLinks().size() * 20 + 30 + 8); 00206 setTitle("TLS-Tracker"); 00207 app.addChild(this, true); 00208 for (size_t i = 0; i < myTLLogic->getLinks().size(); i++) { 00209 myLinkNames.push_back(toString<size_t>(i)); 00210 } 00211 FXVerticalFrame* glcanvasFrame = 00212 new FXVerticalFrame(this, 00213 FRAME_SUNKEN | LAYOUT_SIDE_TOP | LAYOUT_FILL_X | LAYOUT_FILL_Y, 00214 0, 0, 0, 0, 0, 0, 0, 0); 00215 myPanel = new 00216 GUITLLogicPhasesTrackerPanel(glcanvasFrame, *myApplication, *this); 00217 setTitle((logic.getID() + " - " + logic.getProgramID() + " - tracker").c_str()); 00218 setIcon(GUIIconSubSys::getIcon(ICON_APP_TLSTRACKER)); 00219 setHeight(height); 00220 } 00221 00222 00223 GUITLLogicPhasesTrackerWindow::~GUITLLogicPhasesTrackerWindow() { 00224 myApplication->removeChild(this); 00225 delete myConnector; 00226 // just to quit cleanly on a failure 00227 if (myLock.locked()) { 00228 myLock.unlock(); 00229 } 00230 delete myToolBarDrag; 00231 } 00232 00233 00234 void 00235 GUITLLogicPhasesTrackerWindow::create() { 00236 FXMainWindow::create(); 00237 if (myToolBarDrag != 0) { 00238 myToolBarDrag->create(); 00239 } 00240 } 00241 00242 00243 void 00244 GUITLLogicPhasesTrackerWindow::drawValues(GUITLLogicPhasesTrackerPanel& caller) { 00245 // compute what shall be shown (what is visible) 00246 myFirstPhase2Show = 0; 00247 myFirstPhaseOffset = 0; 00248 size_t leftOffset = 0; 00249 myFirstTime2Show = 0; 00250 if (!myAmInTrackingMode) { 00251 myPhases.clear(); 00252 myDurations.clear(); 00253 // insert phases 00254 const MSSimpleTrafficLightLogic::Phases& phases = static_cast<MSSimpleTrafficLightLogic*>(myTLLogic)->getPhases(); 00255 MSSimpleTrafficLightLogic::Phases::const_iterator j; 00256 myLastTime = 0; 00257 myBeginTime = 0; 00258 for (j = phases.begin(); j != phases.end(); ++j) { 00259 myPhases.push_back(*(*j)); 00260 myDurations.push_back((*j)->duration); 00261 myLastTime += (*j)->duration; 00262 } 00263 } else { 00264 SUMOTime beginOffset = TIME2STEPS(myBeginOffset->getValue()); 00265 myBeginTime = myLastTime - beginOffset; 00266 myFirstTime2Show = myBeginTime; 00267 // check whether no phases are known at all 00268 if (myDurations.size() != 0) { 00269 SUMOTime durs = 0; 00270 size_t phaseOffset = myDurations.size() - 1; 00271 DurationsVector::reverse_iterator i = myDurations.rbegin(); 00272 while (i != myDurations.rend()) { 00273 if (durs + (*i) > beginOffset) { 00274 myFirstPhase2Show = phaseOffset; 00275 myFirstPhaseOffset = (durs + (*i)) - beginOffset; 00276 break; 00277 } 00278 durs += (*i); 00279 phaseOffset--; 00280 ++i; 00281 } 00282 if (i == myDurations.rend()) { 00283 // there are too few information stored; 00284 myFirstPhase2Show = 0; 00285 myFirstPhaseOffset = 0; 00286 leftOffset = beginOffset - durs; 00287 } 00288 } 00289 } 00290 // begin drawing 00291 glMatrixMode(GL_PROJECTION); 00292 glLoadIdentity(); 00293 glMatrixMode(GL_MODELVIEW); 00294 glLoadIdentity(); 00295 glTranslated(-1, -1, 0); 00296 glScaled(2, 2, 1); 00297 glDisable(GL_TEXTURE_2D); 00298 // draw the horizontal lines dividing the signal groups 00299 glColor3d(1, 1, 1); 00300 // compute some values needed more than once 00301 const SUMOReal height = (SUMOReal) caller.getHeight(); 00302 const SUMOReal width = (SUMOReal) caller.getWidth(); 00303 pfSetScaleXY((SUMOReal)(.08 * 300. / width), (SUMOReal)(.08 * 300. / height)); 00304 const SUMOReal h4 = ((SUMOReal) 4 / height); 00305 const SUMOReal h10 = ((SUMOReal) 10 / height); 00306 const SUMOReal h16 = ((SUMOReal) 16 / height); 00307 const SUMOReal h20 = ((SUMOReal) 20 / height); 00308 // draw the link names and the lines dividing them 00309 SUMOReal h = (SUMOReal)(1.0 - h10); 00310 SUMOReal h2 = 12; 00311 for (size_t i = 0; i < myTLLogic->getLinks().size() + 1; i++) { 00312 // draw the bar 00313 glBegin(GL_LINES); 00314 glVertex2d(0, h); 00315 glVertex2d((SUMOReal)(30. / width), h); 00316 glEnd(); 00317 // draw the name 00318 if (i < myTLLogic->getLinks().size()) { 00319 glRotated(180, 1, 0, 0); 00320 pfSetPosition(0, 0); 00321 glTranslated(0.0, -h + h20 - h4, 0); 00322 pfDrawString(myLinkNames[i].c_str()); 00323 glTranslated(-0.0, h - h20 + h4, 0); 00324 glRotated(-180, 1, 0, 0); 00325 h2 += 20; 00326 } 00327 h -= h20; 00328 } 00329 glBegin(GL_LINES); 00330 glVertex2d(0, h + h20); 00331 glVertex2d(1.0, h + h20); 00332 glEnd(); 00333 00334 // draw the names closure (vertical line) 00335 h += (SUMOReal) 20 / height; 00336 glColor3d(1, 1, 1); 00337 glBegin(GL_LINES); 00338 glVertex2d((SUMOReal) 30 / width, 1.0); 00339 glVertex2d((SUMOReal) 30 / width, h); 00340 glEnd(); 00341 00342 00343 // draw the phases 00344 // disable value addition while drawing 00345 myLock.lock(); 00346 // determine the initial offset 00347 SUMOReal x = ((SUMOReal) 31. / width) ; 00348 SUMOReal ta = (SUMOReal) leftOffset / width; 00349 ta *= (SUMOReal)(((width - 31.0) / ((SUMOReal)(myLastTime - myBeginTime)))); 00350 x += ta; 00351 00352 // and the initial phase information 00353 PhasesVector::iterator pi = myPhases.begin() + myFirstPhase2Show; 00354 DurationsVector::iterator pd = myDurations.begin() + myFirstPhase2Show; 00355 size_t fpo = myFirstPhaseOffset; 00356 00357 // start drawing 00358 for (size_t i = 30; pd != myDurations.end();) { 00359 // the first phase may be drawn incompletely 00360 size_t duration = *pd - fpo; 00361 // compute the heigh and the width of the phase 00362 h = (SUMOReal)(1.0 - h10); 00363 SUMOReal a = (SUMOReal) duration / width; 00364 a *= (SUMOReal)(((width - 31.0) / ((SUMOReal)(myLastTime - myBeginTime)))); 00365 SUMOReal x2 = x + a; 00366 00367 // go through the links 00368 for (unsigned int j = 0; j < (unsigned int) myTLLogic->getLinks().size(); j++) { 00369 // determine the current link's color 00370 LinkState state = (*pi).getSignalState(j); 00371 // draw the bar (red is drawn as a line) 00372 switch (state) { 00373 case LINKSTATE_TL_GREEN_MAJOR: 00374 case LINKSTATE_TL_GREEN_MINOR: 00375 glColor3d(0, 1.0, 0); 00376 glBegin(GL_QUADS); 00377 glVertex2d(x, h - h16); 00378 glVertex2d(x, h - h4); 00379 glVertex2d(x2, h - h4); 00380 glVertex2d(x2, h - h16); 00381 glEnd(); 00382 break; 00383 case LINKSTATE_TL_YELLOW_MAJOR: 00384 case LINKSTATE_TL_YELLOW_MINOR: 00385 glColor3d(1.0, 1.0, 0); 00386 glBegin(GL_QUADS); 00387 glVertex2d(x, h - h16); 00388 glVertex2d(x, h - h4); 00389 glVertex2d(x2, h - h4); 00390 glVertex2d(x2, h - h16); 00391 glEnd(); 00392 break; 00393 case LINKSTATE_TL_RED: 00394 glColor3d(1.0, 0, 0); 00395 glBegin(GL_LINES); 00396 glVertex2d(x, h - h10); 00397 glVertex2d(x2, h - h10); 00398 glEnd(); 00399 break; 00400 default: 00401 break; 00402 } 00403 // proceed to next link 00404 h -= h20; 00405 } 00406 // proceed to next phase 00407 i += duration; 00408 pi++; 00409 pd++; 00410 x = x2; 00411 // all further phases are drawn in full 00412 fpo = 0; 00413 } 00414 // allow value addition 00415 myLock.unlock(); 00416 00417 glColor3d(1, 1, 1); 00418 if (myPhases.size() != 0) { 00419 SUMOTime tickDist = TIME2STEPS(10); 00420 // patch distances - hack 00421 SUMOReal t = myBeginOffset != 0 ? (SUMOReal) myBeginOffset->getValue() : STEPS2TIME(myLastTime - myBeginTime); 00422 while (t > (width - 31.) / 4.) { 00423 tickDist += TIME2STEPS(10); 00424 t -= (SUMOReal)((width - 31.) / 4.); 00425 } 00426 // draw time information 00427 h = (SUMOReal)(myTLLogic->getLinks().size() * 20 + 12); 00428 SUMOReal glh = (SUMOReal)(1.0 - myTLLogic->getLinks().size() * h20 - h10); 00429 // current begin time 00430 pfSetScaleXY((SUMOReal)(.05 * 300. / width), (SUMOReal)(.05 * 300. / height)); 00431 // time ticks 00432 SUMOTime currTime = myFirstTime2Show; 00433 int pos = 31;// + /*!!!currTime*/ - myFirstTime2Show; 00434 SUMOReal glpos = (SUMOReal) pos / width; 00435 while (pos < width + 50) { 00436 const std::string timeStr = time2string(currTime); 00437 const SUMOReal w = pfdkGetStringWidth(timeStr.c_str()); 00438 glRotated(180, 1, 0, 0); 00439 pfSetPosition(0, 0); 00440 glTranslated(glpos - w / 2., -glh + h20 - h4, 0); 00441 pfDrawString(timeStr.c_str()); 00442 glTranslated(-glpos + w / 2., glh - h20 + h4, 0); 00443 glRotated(-180, 1, 0, 0); 00444 00445 glBegin(GL_LINES); 00446 glVertex2d(glpos, glh); 00447 glVertex2d(glpos, glh - h4); 00448 glEnd(); 00449 00450 const SUMOReal a = STEPS2TIME(tickDist) * (width - 31.0) / STEPS2TIME(myLastTime - myBeginTime); 00451 pos += (int) a; 00452 glpos += a / width; 00453 currTime += tickDist; 00454 } 00455 } 00456 } 00457 00458 00459 void 00460 GUITLLogicPhasesTrackerWindow::addValue(std::pair<SUMOTime, MSPhaseDefinition> def) { 00461 // do not draw while adding 00462 myLock.lock(); 00463 // set the first time if not set before 00464 if (myPhases.size() == 0) { 00465 myBeginTime = def.first; 00466 } 00467 // append or set the phase 00468 if (myPhases.size() == 0 || *(myPhases.end() - 1) != def.second) { 00469 myPhases.push_back(def.second); 00470 myDurations.push_back(DELTA_T); 00471 } else { 00472 *(myDurations.end() - 1) += DELTA_T; 00473 } 00474 // set the last time a phase was added at 00475 myLastTime = def.first; 00476 // allow drawing 00477 myLock.unlock(); 00478 } 00479 00480 00481 long 00482 GUITLLogicPhasesTrackerWindow::onConfigure(FXObject* sender, 00483 FXSelector sel, void* data) { 00484 myPanel->onConfigure(sender, sel, data); 00485 return FXMainWindow::onConfigure(sender, sel, data); 00486 } 00487 00488 00489 long 00490 GUITLLogicPhasesTrackerWindow::onPaint(FXObject* sender, 00491 FXSelector sel, void* data) { 00492 myPanel->onPaint(sender, sel, data); 00493 return FXMainWindow::onPaint(sender, sel, data); 00494 } 00495 00496 00497 long 00498 GUITLLogicPhasesTrackerWindow::onSimStep(FXObject*, 00499 FXSelector, void*) { 00500 update(); 00501 return 1; 00502 } 00503 00504 00505 void 00506 GUITLLogicPhasesTrackerWindow::setBeginTime(SUMOTime time) { 00507 myBeginTime = time; 00508 } 00509 00510 00511 /****************************************************************************/ 00512