|
SUMO - Simulation of Urban MObility
|
00001 /****************************************************************************/ 00007 // The base class for a view 00008 /****************************************************************************/ 00009 // SUMO, Simulation of Urban MObility; see http://sumo.sourceforge.net/ 00010 // Copyright (C) 2001-2011 DLR (http://www.dlr.de/) and contributors 00011 /****************************************************************************/ 00012 // 00013 // This program is free software; you can redistribute it and/or modify 00014 // it under the terms of the GNU General Public License as published by 00015 // the Free Software Foundation; either version 2 of the License, or 00016 // (at your option) any later version. 00017 // 00018 /****************************************************************************/ 00019 00020 00021 // =========================================================================== 00022 // included modules 00023 // =========================================================================== 00024 #ifdef _MSC_VER 00025 #include <windows_config.h> 00026 #else 00027 #include <config.h> 00028 #endif 00029 00030 #ifdef _WIN32 00031 #include <windows.h> 00032 #endif 00033 00034 #include <iostream> 00035 #include <utility> 00036 #include <cmath> 00037 #include <cassert> 00038 #include <fxkeys.h> 00039 #include <GL/gl.h> 00040 #include <GL/glu.h> 00041 #include <foreign/polyfonts/polyfonts.h> 00042 #include <foreign/gl2ps/gl2ps.h> 00043 #include <utils/foxtools/FXSingleEventThread.h> 00044 #include <utils/foxtools/MFXCheckableButton.h> 00045 #include <utils/foxtools/MFXImageHelper.h> 00046 #include <utils/common/RGBColor.h> 00047 #include <utils/common/ToString.h> 00048 #include <utils/common/StringUtils.h> 00049 #include <utils/common/MsgHandler.h> 00050 #include <utils/gui/windows/GUIAppEnum.h> 00051 #include <utils/gui/globjects/GUIGLObjectPopupMenu.h> 00052 #include <utils/gui/images/GUITexturesHelper.h> 00053 #include <utils/gui/div/GUIGlobalSelection.h> 00054 #include <utils/gui/div/GLHelper.h> 00055 #include <utils/gui/globjects/GUIGlObjectStorage.h> 00056 #include <utils/gui/globjects/GUIGlObject.h> 00057 #include <utils/gui/globjects/GUIGlObjectStorage.h> 00058 #include <utils/shapes/PointOfInterest.h> 00059 #include <utils/gui/globjects/GUIPointOfInterest.h> 00060 #include <utils/gui/globjects/GUIPolygon.h> 00061 #include <utils/gui/windows/GUIDialog_ViewSettings.h> 00062 #include <utils/geom/GeoConvHelper.h> 00063 #include <utils/gui/settings/GUICompleteSchemeStorage.h> 00064 00065 #include "GUISUMOAbstractView.h" 00066 #include "GUIMainWindow.h" 00067 #include "GUIGlChildWindow.h" 00068 #include "GUIDanielPerspectiveChanger.h" 00069 #include "GUIDialog_EditViewport.h" 00070 00071 #ifdef WIN32 00072 #include <windows.h> 00073 #endif 00074 00075 #ifdef CHECK_MEMORY_LEAKS 00076 #include <foreign/nvwa/debug_new.h> 00077 #endif // CHECK_MEMORY_LEAKS 00078 00079 00080 // =========================================================================== 00081 // member method definitions 00082 // =========================================================================== 00083 /* ------------------------------------------------------------------------- 00084 * GUISUMOAbstractView - FOX callback mapping 00085 * ----------------------------------------------------------------------- */ 00086 FXDEFMAP(GUISUMOAbstractView) GUISUMOAbstractViewMap[]= { 00087 FXMAPFUNC(SEL_CONFIGURE, 0, GUISUMOAbstractView::onConfigure), 00088 FXMAPFUNC(SEL_PAINT, 0, GUISUMOAbstractView::onPaint), 00089 FXMAPFUNC(SEL_LEFTBUTTONPRESS, 0, GUISUMOAbstractView::onLeftBtnPress), 00090 FXMAPFUNC(SEL_LEFTBUTTONRELEASE, 0, GUISUMOAbstractView::onLeftBtnRelease), 00091 FXMAPFUNC(SEL_RIGHTBUTTONPRESS, 0, GUISUMOAbstractView::onRightBtnPress), 00092 FXMAPFUNC(SEL_RIGHTBUTTONRELEASE, 0, GUISUMOAbstractView::onRightBtnRelease), 00093 FXMAPFUNC(SEL_MOUSEWHEEL, 0, GUISUMOAbstractView::onMouseWheel), 00094 FXMAPFUNC(SEL_MOTION, 0, GUISUMOAbstractView::onMouseMove), 00095 FXMAPFUNC(SEL_LEAVE, 0, GUISUMOAbstractView::onMouseLeft), 00096 FXMAPFUNC(SEL_KEYPRESS, 0, GUISUMOAbstractView::onKeyPress), 00097 FXMAPFUNC(SEL_KEYRELEASE, 0, GUISUMOAbstractView::onKeyRelease), 00098 00099 }; 00100 00101 00102 FXIMPLEMENT_ABSTRACT(GUISUMOAbstractView,FXGLCanvas,GUISUMOAbstractViewMap,ARRAYNUMBER(GUISUMOAbstractViewMap)) 00103 00104 00105 /* ------------------------------------------------------------------------- 00106 * GUISUMOAbstractView - methods 00107 * ----------------------------------------------------------------------- */ 00108 GUISUMOAbstractView::GUISUMOAbstractView(FXComposite* p, 00109 GUIMainWindow& app, 00110 GUIGlChildWindow* parent, 00111 const SUMORTree& grid, 00112 FXGLVisual* glVis, FXGLCanvas* share) 00113 : FXGLCanvas(p, glVis, share, p, MID_GLCANVAS, 00114 LAYOUT_SIDE_TOP|LAYOUT_FILL_X|LAYOUT_FILL_Y, 0, 0, 0, 0), 00115 myApp(&app), 00116 myParent(parent), 00117 myGrid(&((SUMORTree&)grid)), 00118 myChanger(0), 00119 myMouseHotspotX(app.getDefaultCursor()->getHotX()), 00120 myMouseHotspotY(app.getDefaultCursor()->getHotY()), 00121 myPopup(0), 00122 myUseToolTips(false), 00123 myAmInitialised(false), 00124 myViewportChooser(0), 00125 myVisualizationChanger(0) { 00126 setTarget(this); 00127 enable(); 00128 flags|=FLAG_ENABLED; 00129 myInEditMode=false; 00130 // show the middle at the beginning 00131 myChanger = new GUIDanielPerspectiveChanger(*this, *myGrid); 00132 myVisualizationSettings = &gSchemeStorage.getDefault(); 00133 myVisualizationSettings->gaming = myApp->isGaming(); 00134 gSchemeStorage.setViewport(this); 00135 } 00136 00137 00138 GUISUMOAbstractView::~GUISUMOAbstractView() { 00139 gSchemeStorage.setDefault(myVisualizationSettings->name); 00140 gSchemeStorage.saveViewport(myChanger->getXPos(), myChanger->getYPos(), myChanger->getZoom()); 00141 delete myPopup; 00142 delete myChanger; 00143 delete myViewportChooser; 00144 delete myVisualizationChanger; 00145 } 00146 00147 00148 bool 00149 GUISUMOAbstractView::isInEditMode() { 00150 return myInEditMode; 00151 } 00152 00153 00154 void 00155 GUISUMOAbstractView::updateToolTip() { 00156 if (!myUseToolTips) { 00157 return; 00158 } 00159 update(); 00160 } 00161 00162 00163 Position 00164 GUISUMOAbstractView::getPositionInformation() const { 00165 Boundary bound = myChanger->getViewport(); 00166 SUMOReal x = bound.xmin() + bound.getWidth() * myWindowCursorPositionX / getWidth(); 00167 // cursor origin is in the top-left corner 00168 SUMOReal y = bound.ymin() + bound.getHeight() * (getHeight() - myWindowCursorPositionY) / getHeight(); 00169 return Position(x, y); 00170 } 00171 00172 00173 void 00174 GUISUMOAbstractView::updatePositionInformation() const { 00175 Position pos = getPositionInformation(); 00176 std::string text = "x:" + toString(pos.x()) + ", y:" + toString(pos.y()); 00177 myApp->getCartesianLabel().setText(text.c_str()); 00178 GeoConvHelper::getDefaultInstance().cartesian2geo(pos); 00179 if (GeoConvHelper::getDefaultInstance().usingGeoProjection()) { 00180 text = "lat:" + toString(pos.y(), GEO_OUTPUT_ACCURACY) + ", lon:" + toString(pos.x(), GEO_OUTPUT_ACCURACY); 00181 } else { 00182 text = "x:" + toString(pos.x()) + ", y:" + toString(pos.y()); 00183 } 00184 myApp->getGeoLabel().setText(text.c_str()); 00185 } 00186 00187 00188 Boundary 00189 GUISUMOAbstractView::getVisibleBoundary() const { 00190 return myChanger->getViewport(); 00191 } 00192 00193 void 00194 GUISUMOAbstractView::paintGL() { 00195 if (getWidth()==0||getHeight()==0) { 00196 return; 00197 } 00198 00199 if (getTrackedID()>0) { 00200 centerTo(getTrackedID(), false); 00201 } 00202 00203 unsigned int id = 0; 00204 if (myUseToolTips) { 00205 id = getObjectUnderCursor(); 00206 } 00207 00208 // draw 00209 glClearColor( 00210 myVisualizationSettings->backgroundColor.red(), 00211 myVisualizationSettings->backgroundColor.green(), 00212 myVisualizationSettings->backgroundColor.blue(), 00213 1); 00214 glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); 00215 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 00216 00217 if (myVisualizationSettings->dither) { 00218 glEnable(GL_DITHER); 00219 } else { 00220 glDisable(GL_DITHER); 00221 } 00222 if (myVisualizationSettings->antialiase) { 00223 glEnable(GL_BLEND); 00224 glEnable(GL_POLYGON_SMOOTH); 00225 glEnable(GL_LINE_SMOOTH); 00226 } else { 00227 glDisable(GL_BLEND); 00228 glDisable(GL_POLYGON_SMOOTH); 00229 glDisable(GL_LINE_SMOOTH); 00230 } 00231 00232 applyGLTransform(); 00233 doPaintGL(GL_RENDER, myChanger->getViewport()); 00234 if (myVisualizationSettings->showSizeLegend) { 00235 displayLegend(); 00236 } 00237 // check whether the select mode /tooltips) 00238 // shall be computed, too 00239 if (myUseToolTips&&id!=0) { 00240 showToolTipFor(id); 00241 } 00242 swapBuffers(); 00243 } 00244 00245 00246 GUIGlID 00247 GUISUMOAbstractView::getObjectUnderCursor() { 00248 return getObjectAtPosition(getPositionInformation()); 00249 } 00250 00251 00252 GUIGlID 00253 GUISUMOAbstractView::getObjectAtPosition(Position pos) { 00254 const SUMOReal SENSITIVITY = 0.1; // meters 00255 Boundary selection; 00256 selection.add(pos); 00257 selection.grow(SENSITIVITY); 00258 const std::vector<GUIGlID> ids = getObjectsInBoundary(selection); 00259 // Interpret results 00260 unsigned int idMax = 0; 00261 int prevLayer = -1000; 00262 for (std::vector<GUIGlID>::const_iterator it = ids.begin(); it != ids.end(); it++) { 00263 GUIGlID id = *it; 00264 GUIGlObject* o = GUIGlObjectStorage::gIDStorage.getObjectBlocking(id); 00265 if (o==0) { 00266 continue; 00267 } 00268 if (o->getGlID()==0) { 00269 continue; 00270 } 00271 //std::cout << "point selection hit " << o->getMicrosimID() << "\n"; 00272 GUIGlObjectType type = o->getType(); 00273 if (type!=0) { 00274 int clayer = (int) type; 00275 // determine an "abstract" layer for shapes 00276 // this "layer" resembles the layer of the shape 00277 // taking into account the stac of other objects 00278 if (type==GLO_SHAPE) { 00279 if (dynamic_cast<GUIPolygon*>(o)!=0) { 00280 if (dynamic_cast<GUIPolygon*>(o)->getLayer()>0) { 00281 clayer = GLO_MAX + dynamic_cast<GUIPolygon*>(o)->getLayer(); 00282 } 00283 if (dynamic_cast<GUIPolygon*>(o)->getLayer()<0) { 00284 clayer = dynamic_cast<GUIPolygon*>(o)->getLayer(); 00285 } 00286 } 00287 if (dynamic_cast<GUIPointOfInterest*>(o)!=0) { 00288 if (dynamic_cast<GUIPointOfInterest*>(o)->getLayer()>0) { 00289 clayer = GLO_MAX + dynamic_cast<GUIPointOfInterest*>(o)->getLayer(); 00290 } 00291 if (dynamic_cast<GUIPointOfInterest*>(o)->getLayer()<0) { 00292 clayer = dynamic_cast<GUIPointOfInterest*>(o)->getLayer(); 00293 } 00294 } 00295 } 00296 // check whether the current object is above a previous one 00297 if (prevLayer==-1000||prevLayer<clayer) { 00298 idMax = id; 00299 prevLayer = clayer; 00300 } 00301 } 00302 GUIGlObjectStorage::gIDStorage.unblockObject(id); 00303 } 00304 return idMax; 00305 } 00306 00307 00308 std::vector<GUIGlID> 00309 GUISUMOAbstractView::getObjectsInBoundary(const Boundary& bound) { 00310 const int NB_HITS_MAX = 1024 * 1024; 00311 // Prepare the selection mode 00312 static GUIGlID hits[NB_HITS_MAX]; 00313 static GLint nb_hits = 0; 00314 glSelectBuffer(NB_HITS_MAX, hits); 00315 glInitNames(); 00316 00317 Boundary oldViewPort = myChanger->getViewport(false); // backup the actual viewPort 00318 myChanger->setViewport(bound); 00319 applyGLTransform(false); 00320 00321 // paint in select mode 00322 int hits2 = doPaintGL(GL_SELECT, bound); 00323 // Get the results 00324 nb_hits = glRenderMode(GL_RENDER); 00325 if (nb_hits == -1) { 00326 myApp->setStatusBarText("Selection in boundary failed. Try to select fewer than " + toString(hits2) + " items"); 00327 } 00328 std::vector<GUIGlID> result; 00329 for (int i=0; i<nb_hits; ++i) { 00330 assert(i*4+3<NB_HITS_MAX); 00331 result.push_back(hits[i*4+3]); 00332 } 00333 // switch viewport back to normal 00334 myChanger->setViewport(oldViewPort); 00335 return result; 00336 } 00337 00338 00339 void 00340 GUISUMOAbstractView::showToolTipFor(unsigned int id) { 00341 if (id!=0) { 00342 GUIGlObject* object = GUIGlObjectStorage::gIDStorage.getObjectBlocking(id); 00343 if (object!=0) { 00344 Position pos = getPositionInformation(); 00345 pos.add(0, p2m(15)); 00346 GLHelper::drawTextBox(object->getFullName(), pos, GLO_MAX-1, p2m(20), RGBColor(0,0,0), RGBColor(1, 0.7, 0)); 00347 GUIGlObjectStorage::gIDStorage.unblockObject(id); 00348 } 00349 } 00350 } 00351 00352 00353 void 00354 GUISUMOAbstractView::paintGLGrid() { 00355 glEnable(GL_DEPTH_TEST); 00356 glLineWidth(1); 00357 00358 SUMOReal xmin = myGrid->xmin(); 00359 SUMOReal ymin = myGrid->ymin(); 00360 SUMOReal ypos = ymin; 00361 SUMOReal xpos = xmin; 00362 SUMOReal xend = myGrid->xmax(); 00363 SUMOReal yend = myGrid->ymax(); 00364 00365 glTranslated(0, 0, .55); 00366 glColor3d(0.5, 0.5, 0.5); 00367 // draw horizontal lines 00368 glBegin(GL_LINES); 00369 for (; ypos<yend;) { 00370 glVertex2d(xmin, ypos); 00371 glVertex2d(xend, ypos); 00372 ypos += myVisualizationSettings->gridYSize; 00373 } 00374 // draw vertical lines 00375 for (; xpos<xend;) { 00376 glVertex2d(xpos, ymin); 00377 glVertex2d(xpos, yend); 00378 xpos += myVisualizationSettings->gridXSize; 00379 } 00380 glEnd(); 00381 glTranslated(0, 0, -.55); 00382 } 00383 00384 00385 void 00386 GUISUMOAbstractView::displayLegend() { 00387 // compute the scale bar length 00388 size_t length = 1; 00389 const std::string text("10000000000"); 00390 size_t noDigits = 1; 00391 size_t pixelSize = 0; 00392 while (true) { 00393 pixelSize = (size_t) m2p((SUMOReal) length); 00394 if (pixelSize>20) { 00395 break; 00396 } 00397 length *= 10; 00398 noDigits++; 00399 if (noDigits>text.length()) { 00400 return; 00401 } 00402 } 00403 SUMOReal lineWidth = 1.0; 00404 glLineWidth((SUMOReal) lineWidth); 00405 00406 glMatrixMode(GL_PROJECTION); 00407 glPushMatrix(); 00408 glLoadIdentity(); 00409 glMatrixMode(GL_MODELVIEW); 00410 glPushMatrix(); 00411 glLoadIdentity(); 00412 00413 // draw the scale bar 00414 glDisable(GL_TEXTURE_2D); 00415 glDisable(GL_ALPHA_TEST); 00416 glDisable(GL_BLEND); 00417 glEnable(GL_DEPTH_TEST); 00418 00419 SUMOReal len = (SUMOReal) pixelSize / (SUMOReal)(getWidth()-1) * (SUMOReal) 2.0; 00420 glColor3d(0, 0, 0); 00421 double o = double(15) / double(getHeight()); 00422 double o2 = o + o; 00423 double oo = double(5) / double(getHeight()); 00424 glBegin(GL_LINES); 00425 // vertical 00426 glVertex2d(-.98, -1.+o); 00427 glVertex2d(-.98+len, -1.+o); 00428 // tick at begin 00429 glVertex2d(-.98, -1.+o); 00430 glVertex2d(-.98, -1.+o2); 00431 // tick at end 00432 glVertex2d(-.98+len, -1.+o); 00433 glVertex2d(-.98+len, -1.+o2); 00434 glEnd(); 00435 00436 SUMOReal w = SUMOReal(35) / SUMOReal(getWidth()); 00437 SUMOReal h = SUMOReal(35) / SUMOReal(getHeight()); 00438 pfSetPosition(SUMOReal(-0.99), SUMOReal(1.-o2-oo)); 00439 pfSetScaleXY(w, h); 00440 glRotated(180, 1, 0, 0); 00441 pfDrawString("0m"); 00442 glRotated(-180, 1, 0, 0); 00443 00444 pfSetPosition(SUMOReal(-.99+len), SUMOReal(1.-o2-oo)); 00445 glRotated(180, 1, 0, 0); 00446 pfDrawString((text.substr(0, noDigits) + "m").c_str()); 00447 glRotated(-180, 1, 0, 0); 00448 00449 // restore matrices 00450 glMatrixMode(GL_PROJECTION); 00451 glPopMatrix(); 00452 glMatrixMode(GL_MODELVIEW); 00453 glPopMatrix(); 00454 } 00455 00456 00457 SUMOReal 00458 GUISUMOAbstractView::m2p(SUMOReal meter) const { 00459 return meter * getWidth() / myChanger->getViewport().getWidth(); 00460 } 00461 00462 00463 SUMOReal 00464 GUISUMOAbstractView::p2m(SUMOReal pixel) const { 00465 return pixel * myChanger->getViewport().getWidth() / getWidth(); 00466 } 00467 00468 00469 void 00470 GUISUMOAbstractView::recenterView() { 00471 myChanger->setViewport(*myGrid); 00472 } 00473 00474 00475 void 00476 GUISUMOAbstractView::centerTo(GUIGlID id, bool applyZoom, SUMOReal zoomDist) { 00477 GUIGlObject* o = GUIGlObjectStorage::gIDStorage.getObjectBlocking(id); 00478 if (o!=0 && dynamic_cast<GUIGlObject*>(o)!=0) { 00479 if (applyZoom && zoomDist < 0) { 00480 myChanger->setViewport(o->getCenteringBoundary()); 00481 } else { 00482 myChanger->centerTo(o->getCenteringBoundary().getCenter(), zoomDist, applyZoom); 00483 } 00484 } 00485 GUIGlObjectStorage::gIDStorage.unblockObject(id); 00486 update(); 00487 } 00488 00489 00490 void 00491 GUISUMOAbstractView::centerTo(const Boundary& bound) { 00492 myChanger->setViewport(bound); 00493 update(); 00494 } 00495 00496 /* 00497 bool 00498 GUISUMOAbstractView::allowRotation() const 00499 { 00500 return myParent->allowRotation(); 00501 } 00502 */ 00503 00504 void 00505 GUISUMOAbstractView::setWindowCursorPosition(FXint x, FXint y) { 00506 myWindowCursorPositionX = x + myMouseHotspotX; 00507 myWindowCursorPositionY = y + myMouseHotspotY; 00508 } 00509 00510 00511 FXbool 00512 GUISUMOAbstractView::makeCurrent() { 00513 FXbool ret = FXGLCanvas::makeCurrent(); 00514 return ret; 00515 } 00516 00517 00518 long 00519 GUISUMOAbstractView::onConfigure(FXObject*,FXSelector,void*) { 00520 if (makeCurrent()) { 00521 glViewport(0, 0, getWidth()-1, getHeight()-1); 00522 glClearColor( 00523 myVisualizationSettings->backgroundColor.red(), 00524 myVisualizationSettings->backgroundColor.green(), 00525 myVisualizationSettings->backgroundColor.blue(), 00526 1); 00527 doInit(); 00528 myAmInitialised = true; 00529 makeNonCurrent(); 00530 checkSnapshots(); 00531 } 00532 return 1; 00533 } 00534 00535 00536 long 00537 GUISUMOAbstractView::onPaint(FXObject*,FXSelector,void*) { 00538 if (!isEnabled()||!myAmInitialised) { 00539 return 1; 00540 } 00541 if (makeCurrent()) { 00542 paintGL(); 00543 makeNonCurrent(); 00544 } 00545 return 1; 00546 } 00547 00548 00549 void 00550 GUISUMOAbstractView::destroyPopup() { 00551 delete myPopup; 00552 myPopup = 0; 00553 } 00554 00555 00556 long 00557 GUISUMOAbstractView::onLeftBtnPress(FXObject*,FXSelector ,void* data) { 00558 destroyPopup(); 00559 FXEvent* e = (FXEvent*) data; 00560 // check whether the selection-mode is activated 00561 if (e->state&CONTROLMASK) { 00562 // try to get the object-id if so 00563 if (makeCurrent()) { 00564 unsigned int id = getObjectUnderCursor(); 00565 if (id!=0) { 00566 gSelected.toggleSelection(id); 00567 } 00568 makeNonCurrent(); 00569 if (id!=0) { 00570 // possibly, the selection-colouring is used, 00571 // so we should update the screen again... 00572 update(); 00573 } 00574 } 00575 } 00576 myChanger->onLeftBtnPress(data); 00577 grab(); 00578 return 1; 00579 } 00580 00581 00582 long 00583 GUISUMOAbstractView::onLeftBtnRelease(FXObject*,FXSelector ,void* data) { 00584 destroyPopup(); 00585 myChanger->onLeftBtnRelease(data); 00586 if (myApp->isGaming()) { 00587 onGamingClick(getPositionInformation()); 00588 } 00589 ungrab(); 00590 return 1; 00591 } 00592 00593 00594 long 00595 GUISUMOAbstractView::onRightBtnPress(FXObject*,FXSelector ,void* data) { 00596 destroyPopup(); 00597 myChanger->onRightBtnPress(data); 00598 grab(); 00599 return 1; 00600 } 00601 00602 00603 long 00604 GUISUMOAbstractView::onRightBtnRelease(FXObject*,FXSelector ,void* data) { 00605 destroyPopup(); 00606 if (!myChanger->onRightBtnRelease(data) && !myApp->isGaming()) { 00607 openObjectDialog(); 00608 } 00609 ungrab(); 00610 return 1; 00611 } 00612 00613 00614 long 00615 GUISUMOAbstractView::onMouseWheel(FXObject*,FXSelector ,void* data) { 00616 myChanger->onMouseWheel(data); 00617 return 1; 00618 } 00619 00620 00621 long 00622 GUISUMOAbstractView::onMouseMove(FXObject*,FXSelector ,void* data) { 00623 SUMOReal xpos = myChanger->getXPos(); 00624 SUMOReal ypos = myChanger->getYPos(); 00625 SUMOReal zoom = myChanger->getZoom(); 00626 if (myViewportChooser==0||!myViewportChooser->haveGrabbed()) { 00627 myChanger->onMouseMove(data); 00628 } 00629 if (myViewportChooser!=0 && 00630 (xpos!=myChanger->getXPos()||ypos!=myChanger->getYPos()||zoom!=myChanger->getZoom())) { 00631 00632 myViewportChooser->setValues( 00633 myChanger->getZoom(), myChanger->getXPos(), myChanger->getYPos()); 00634 00635 } 00636 updatePositionInformation(); 00637 return 1; 00638 } 00639 00640 00641 long 00642 GUISUMOAbstractView::onMouseLeft(FXObject*,FXSelector ,void* /*data*/) { 00643 return 1; 00644 } 00645 00646 00647 void 00648 GUISUMOAbstractView::openObjectDialog() { 00649 ungrab(); 00650 if (!isEnabled()||!myAmInitialised) { 00651 return; 00652 } 00653 if (makeCurrent()) { 00654 // initialise the select mode 00655 unsigned int id = getObjectUnderCursor(); 00656 GUIGlObject* o = 0; 00657 if (id!=0) { 00658 o = GUIGlObjectStorage::gIDStorage.getObjectBlocking(id); 00659 } else { 00660 o = GUIGlObjectStorage::gIDStorage.getNetObject(); 00661 } 00662 if (o!=0) { 00663 myPopup = o->getPopUpMenu(*myApp, *this); 00664 int x, y; 00665 FXuint b; 00666 myApp->getCursorPosition(x, y, b); 00667 myPopup->setX(x + myApp->getX()); 00668 myPopup->setY(y + myApp->getY()); 00669 myPopup->create(); 00670 myPopup->show(); 00671 myChanger->onRightBtnRelease(0); 00672 GUIGlObjectStorage::gIDStorage.unblockObject(id); 00673 } 00674 makeNonCurrent(); 00675 } 00676 } 00677 00678 00679 long 00680 GUISUMOAbstractView::onKeyPress(FXObject* o,FXSelector sel,void* data) { 00681 FXEvent* e = (FXEvent*) data; 00682 if ((e->state&ALTMASK)!=0) { 00683 setDefaultCursor(getApp()->getDefaultCursor(DEF_CROSSHAIR_CURSOR)); 00684 grabKeyboard(); 00685 } 00686 /* 00687 switch(e->code) { 00688 case KEY_Left: 00689 myChanger->move((SUMOReal) -p2m((SUMOReal) getWidth()/10), 0); 00690 break; 00691 case KEY_Right: 00692 myChanger->move((SUMOReal) p2m((SUMOReal) getWidth()/10), 0); 00693 break; 00694 case KEY_Up: 00695 myChanger->move(0, (SUMOReal) -p2m((SUMOReal) getHeight()/10)); 00696 break; 00697 case KEY_Down: 00698 myChanger->move(0, (SUMOReal) p2m((SUMOReal) getHeight()/10)); 00699 break; 00700 default: 00701 break; 00702 } 00703 */ 00704 return FXGLCanvas::onKeyPress(o, sel, data); 00705 } 00706 00707 00708 long 00709 GUISUMOAbstractView::onKeyRelease(FXObject* o,FXSelector sel,void* data) { 00710 FXEvent* e = (FXEvent*) data; 00711 if ((e->state&ALTMASK)==0) { 00712 ungrabKeyboard(); 00713 setDefaultCursor(getApp()->getDefaultCursor(DEF_ARROW_CURSOR)); 00714 } 00715 return FXGLCanvas::onKeyRelease(o, sel, data); 00716 } 00717 00718 00719 // ------------ Dealing with snapshots 00720 void 00721 GUISUMOAbstractView::setSnapshots(std::map<SUMOTime, std::string> snaps) { 00722 mySnapshots.insert(snaps.begin(), snaps.end()); 00723 } 00724 00725 00726 std::string 00727 GUISUMOAbstractView::makeSnapshot(const std::string& destFile) { 00728 std::string errorMessage; 00729 FXString ext=FXPath::extension(destFile.c_str()); 00730 bool useGL2PS = ext=="ps"||ext=="eps"||ext=="pdf"||ext=="svg"||ext=="tex"||ext=="pgf"; 00731 00732 for (int i=0; i<10&&!makeCurrent(); ++i) { 00733 FXSingleEventThread::sleep(100); 00734 } 00735 // draw 00736 glClearColor( 00737 myVisualizationSettings->backgroundColor.red(), 00738 myVisualizationSettings->backgroundColor.green(), 00739 myVisualizationSettings->backgroundColor.blue(), 00740 1); 00741 glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); 00742 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 00743 00744 if (myVisualizationSettings->dither) { 00745 glEnable(GL_DITHER); 00746 } else { 00747 glDisable(GL_DITHER); 00748 } 00749 if (myVisualizationSettings->antialiase) { 00750 glEnable(GL_BLEND); 00751 glEnable(GL_POLYGON_SMOOTH); 00752 glEnable(GL_LINE_SMOOTH); 00753 } else { 00754 glDisable(GL_BLEND); 00755 glDisable(GL_POLYGON_SMOOTH); 00756 glDisable(GL_LINE_SMOOTH); 00757 } 00758 00759 applyGLTransform(); 00760 00761 if (useGL2PS) { 00762 GLint format = GL2PS_PS; 00763 if (ext=="ps") { 00764 format = GL2PS_PS; 00765 } else if (ext=="eps") { 00766 format = GL2PS_EPS; 00767 } else if (ext=="pdf") { 00768 format = GL2PS_PDF; 00769 } else if (ext=="tex") { 00770 format = GL2PS_TEX; 00771 } else if (ext=="svg") { 00772 format = GL2PS_SVG; 00773 } else if (ext=="pgf") { 00774 format = GL2PS_PGF; 00775 } else { 00776 return "Could not save '" + destFile + "'.\n Unrecognized format '" + std::string(ext.text()) + "'."; 00777 } 00778 FILE* fp = fopen(destFile.c_str(), "wb"); 00779 if (fp==0) { 00780 return "Could not save '" + destFile + "'.\n Could not open file for writing"; 00781 } 00782 GLint buffsize = 0, state = GL2PS_OVERFLOW; 00783 GLint viewport[4]; 00784 glGetIntegerv(GL_VIEWPORT, viewport); 00785 while (state == GL2PS_OVERFLOW) { 00786 buffsize += 1024*1024; 00787 gl2psBeginPage(destFile.c_str(), "sumo-gui; http://sumo.sf.net", viewport, format, GL2PS_SIMPLE_SORT, 00788 GL2PS_DRAW_BACKGROUND | GL2PS_USE_CURRENT_VIEWPORT, 00789 GL_RGBA, 0, NULL, 0, 0, 0, buffsize, fp, "out.eps"); 00790 glMatrixMode(GL_MODELVIEW); 00791 glPushMatrix(); 00792 glDisable(GL_TEXTURE_2D); 00793 glDisable(GL_ALPHA_TEST); 00794 glDisable(GL_BLEND); 00795 glEnable(GL_DEPTH_TEST); 00796 // compute lane width 00797 // draw decals (if not in grabbing mode) 00798 if (!myUseToolTips) { 00799 drawDecals(); 00800 if (myVisualizationSettings->showGrid) { 00801 paintGLGrid(); 00802 } 00803 } 00804 glLineWidth(1); 00805 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 00806 Boundary viewPort = myChanger->getViewport(); 00807 float minB[2]; 00808 float maxB[2]; 00809 minB[0] = viewPort.xmin(); 00810 minB[1] = viewPort.ymin(); 00811 maxB[0] = viewPort.xmax(); 00812 maxB[1] = viewPort.ymax(); 00813 myVisualizationSettings->scale = m2p(SUMO_const_laneWidth); 00814 glEnable(GL_POLYGON_OFFSET_FILL); 00815 glEnable(GL_POLYGON_OFFSET_LINE); 00816 myGrid->Search(minB, maxB, *myVisualizationSettings); 00817 00818 if (myVisualizationSettings->showSizeLegend) { 00819 displayLegend(); 00820 } 00821 state = gl2psEndPage(); 00822 glFinish(); 00823 } 00824 fclose(fp); 00825 } else { 00826 doPaintGL(GL_RENDER, myChanger->getViewport()); 00827 if (myVisualizationSettings->showSizeLegend) { 00828 displayLegend(); 00829 } 00830 swapBuffers(); 00831 glFinish(); 00832 FXColor* buf; 00833 FXMALLOC(&buf, FXColor, getWidth()*getHeight()); 00834 // read from the back buffer 00835 glReadBuffer(GL_BACK); 00836 // Read the pixels 00837 glReadPixels(0, 0, getWidth(), getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)buf); 00838 makeNonCurrent(); 00839 update(); 00840 // mirror 00841 size_t mwidth = getWidth(); 00842 size_t mheight = getHeight(); 00843 FXColor* paa = buf; 00844 FXColor* pbb = buf + mwidth * (mheight-1); 00845 do { 00846 FXColor* pa=paa; 00847 paa+=mwidth; 00848 FXColor* pb=pbb; 00849 pbb-=mwidth; 00850 do { 00851 FXColor t=*pa; 00852 *pa++=*pb; 00853 *pb++=t; 00854 } while (pa<paa); 00855 } while (paa<pbb); 00856 try { 00857 if (!MFXImageHelper::saveImage(destFile, getWidth(), getHeight(), buf)) { 00858 errorMessage = "Could not save '" + destFile + "'."; 00859 } 00860 } catch (InvalidArgument& e) { 00861 errorMessage = "Could not save '" + destFile + "'.\n" + e.what(); 00862 } 00863 FXFREE(&buf); 00864 } 00865 return errorMessage; 00866 } 00867 00868 00869 void 00870 GUISUMOAbstractView::checkSnapshots() { 00871 std::map<SUMOTime, std::string>::iterator snapIt = mySnapshots.find(getCurrentTimeStep()); 00872 if (snapIt != mySnapshots.end()) { 00873 std::string error = makeSnapshot(snapIt->second); 00874 if (error!="") { 00875 WRITE_WARNING(error); 00876 } 00877 } 00878 } 00879 00880 00881 void 00882 GUISUMOAbstractView::showViewportEditor() { 00883 if (myViewportChooser==0) { 00884 myViewportChooser = 00885 new GUIDialog_EditViewport(this, "Edit Viewport...", 00886 myChanger->getZoom(), myChanger->getXPos(), myChanger->getYPos(), 00887 0, 0); 00888 myViewportChooser->create(); 00889 } 00890 myViewportChooser->setOldValues( 00891 myChanger->getZoom(), myChanger->getXPos(), myChanger->getYPos()); 00892 myViewportChooser->show(); 00893 } 00894 00895 00896 void 00897 GUISUMOAbstractView::setViewport(SUMOReal zoom, SUMOReal xPos, SUMOReal yPos) { 00898 myChanger->setViewport(zoom, xPos, yPos); 00899 update(); 00900 } 00901 00902 00903 void 00904 GUISUMOAbstractView::showToolTips(bool val) { 00905 myUseToolTips = val; 00906 } 00907 00908 00909 00910 SUMOReal 00911 GUISUMOAbstractView::getGridWidth() const { 00912 return myGrid->getWidth(); 00913 } 00914 00915 00916 SUMOReal 00917 GUISUMOAbstractView::getGridHeight() const { 00918 return myGrid->getHeight(); 00919 } 00920 00921 00922 FXComboBox& 00923 GUISUMOAbstractView::getColoringSchemesCombo() { 00924 return myParent->getColoringSchemesCombo(); 00925 } 00926 00927 00928 void 00929 GUISUMOAbstractView::drawDecals() { 00930 glTranslated(0, 0, .99); 00931 myDecalsLock.lock(); 00932 for (std::vector<GUISUMOAbstractView::Decal>::iterator l=myDecals.begin(); l!=myDecals.end();) { 00933 GUISUMOAbstractView::Decal& d = *l; 00934 if (!d.initialised) { 00935 try { 00936 FXImage* i = MFXImageHelper::loadImage(getApp(), d.filename); 00937 if (MFXImageHelper::scalePower2(i)) { 00938 WRITE_WARNING("Scaling '" + d.filename + "'."); 00939 } 00940 d.glID = GUITexturesHelper::add(i); 00941 d.initialised = true; 00942 } catch (InvalidArgument& e) { 00943 WRITE_ERROR("Could not load '" + d.filename + "'.\n" + e.what()); 00944 l = myDecals.erase(l); 00945 continue; 00946 } 00947 } 00948 glPushMatrix(); 00949 glTranslated(d.centerX, d.centerY, 0); 00950 glRotated(d.rot, 0, 0, 1); 00951 glColor3d(1,1,1); 00952 SUMOReal halfWidth((d.width / 2.)); 00953 SUMOReal halfHeight((d.height / 2.)); 00954 GUITexturesHelper::drawTexturedBox(d.glID, -halfWidth, -halfHeight, halfWidth, halfHeight); 00955 glPopMatrix(); 00956 ++l; 00957 } 00958 myDecalsLock.unlock(); 00959 glTranslated(0, 0, -.99); 00960 } 00961 00962 00963 // ------------ Additional visualisations 00964 bool 00965 GUISUMOAbstractView::addAdditionalGLVisualisation(GUIGlObject* const which) { 00966 if (myAdditionallyDrawn.find(which)==myAdditionallyDrawn.end()) { 00967 myAdditionallyDrawn[which] = 1; 00968 } else { 00969 myAdditionallyDrawn[which] = myAdditionallyDrawn[which] + 1; 00970 } 00971 update(); 00972 return true; 00973 } 00974 00975 00976 bool 00977 GUISUMOAbstractView::removeAdditionalGLVisualisation(GUIGlObject* const which) { 00978 if (getTrackedID()==static_cast<int>(which->getGlID())) { 00979 stopTrack(); 00980 } 00981 if (myAdditionallyDrawn.find(which)==myAdditionallyDrawn.end()) { 00982 return false; 00983 } 00984 int cnt = myAdditionallyDrawn[which]; 00985 if (cnt==1) { 00986 myAdditionallyDrawn.erase(which); 00987 } else { 00988 myAdditionallyDrawn[which] = myAdditionallyDrawn[which] - 1; 00989 } 00990 update(); 00991 return true; 00992 } 00993 00994 00995 void 00996 GUISUMOAbstractView::applyGLTransform(bool fixRatio) { 00997 Boundary bound = myChanger->getViewport(fixRatio); 00998 glMatrixMode(GL_PROJECTION); 00999 glLoadIdentity(); 01000 // as a rough rule, each GLObject is drawn at z = -GUIGlObjectType 01001 // thus, objects with a higher value will be closer (drawn on top) 01002 // // @todo last param should be 0 after modifying all glDraw methods 01003 glOrtho(0, getWidth(), 0, getHeight(), -GLO_MAX-1, GLO_MAX+1); 01004 glMatrixMode(GL_MODELVIEW); 01005 glLoadIdentity(); 01006 SUMOReal scaleX = (SUMOReal)getWidth() / bound.getWidth(); 01007 SUMOReal scaleY = (SUMOReal)getHeight() / bound.getHeight(); 01008 glScaled(scaleX, scaleY, 1); 01009 glTranslated(-bound.xmin(), -bound.ymin(), 0); 01010 } 01011 01012 /****************************************************************************/ 01013