LCOV - code coverage report
Current view: top level - src/utils/gui/windows - GUIDanielPerspectiveChanger.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 43 180 23.9 %
Date: 2024-05-03 15:29:52 Functions: 14 27 51.9 %

          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    GUIDanielPerspectiveChanger.cpp
      15             : /// @author  Daniel Krajzewicz
      16             : /// @author  Jakob Erdmann
      17             : /// @author  Michael Behrisch
      18             : /// @date    Sept 2002
      19             : ///
      20             : // A class that allows to steer the visual output in dependence to
      21             : /****************************************************************************/
      22             : #include <config.h>
      23             : 
      24             : #include <fxkeys.h>
      25             : #include <utils/geom/Boundary.h>
      26             : #include <utils/geom/Position.h>
      27             : #include <utils/geom/GeomHelper.h>
      28             : #include <utils/gui/settings/GUICompleteSchemeStorage.h>
      29             : #include "GUIPerspectiveChanger.h"
      30             : #include "GUIDanielPerspectiveChanger.h"
      31             : 
      32             : 
      33             : // ===========================================================================
      34             : // method definitions
      35             : // ===========================================================================
      36        6836 : GUIDanielPerspectiveChanger::GUIDanielPerspectiveChanger(
      37        6836 :     GUISUMOAbstractView& callBack, const Boundary& viewPort) :
      38             :     GUIPerspectiveChanger(callBack, viewPort),
      39       13672 :     myOrigWidth(viewPort.getWidth()),
      40        6836 :     myOrigHeight(viewPort.getHeight()),
      41        6836 :     myRotation(0),
      42        6836 :     myMouseButtonState(MOUSEBTN_NONE),
      43        6836 :     myMoveOnClick(false),
      44        6836 :     myZoomBase(viewPort.getCenter()),
      45        6836 :     myDragDelay(0) {
      46        6836 : }
      47             : 
      48             : 
      49       13640 : GUIDanielPerspectiveChanger::~GUIDanielPerspectiveChanger() {}
      50             : 
      51             : 
      52             : void
      53           0 : GUIDanielPerspectiveChanger::move(int xdiff, int ydiff) {
      54           0 :     myViewPort.moveby(myCallback.p2m(xdiff), -myCallback.p2m(ydiff));
      55           0 :     myCallback.update();
      56           0 : }
      57             : 
      58             : 
      59             : void
      60           0 : GUIDanielPerspectiveChanger::zoom(double factor) {
      61           0 :     if (myCallback.getApp()->reg().readIntEntry("gui", "zoomAtCenter", 0)) {
      62           0 :         myZoomBase = myViewPort.getCenter();
      63             :     }
      64           0 :     if (factor > 0) {
      65           0 :         myViewPort = Boundary(
      66           0 :                          myZoomBase.x() - (myZoomBase.x() - myViewPort.xmin()) / factor,
      67           0 :                          myZoomBase.y() - (myZoomBase.y() - myViewPort.ymin()) / factor,
      68           0 :                          myZoomBase.x() - (myZoomBase.x() - myViewPort.xmax()) / factor,
      69           0 :                          myZoomBase.y() - (myZoomBase.y() - myViewPort.ymax()) / factor);
      70           0 :         myCallback.update();
      71             :     }
      72           0 : }
      73             : 
      74             : 
      75             : void
      76           0 : GUIDanielPerspectiveChanger::rotate(int /* diff */) {
      77             :     /*
      78             :     if (myCallback.allowRotation()) {
      79             :         myRotation += (double) diff / (double) 10.0;
      80             :         myCallback.update();
      81             :     }
      82             :     */
      83           0 : }
      84             : 
      85             : 
      86             : double
      87      960407 : GUIDanielPerspectiveChanger::getRotation() const {
      88      960407 :     return myRotation;
      89             : }
      90             : 
      91             : 
      92             : double
      93        7018 : GUIDanielPerspectiveChanger::getXPos() const {
      94        7018 :     return myViewPort.getCenter().x();
      95             : }
      96             : 
      97             : 
      98             : double
      99        7018 : GUIDanielPerspectiveChanger::getYPos() const {
     100        7018 :     return myViewPort.getCenter().y();
     101             : }
     102             : 
     103             : 
     104             : double
     105           4 : GUIDanielPerspectiveChanger::getZoom() const {
     106           4 :     return myOrigWidth / myViewPort.getWidth() * 100;
     107             : }
     108             : 
     109             : 
     110             : double
     111        6429 : GUIDanielPerspectiveChanger::getZPos() const {
     112        6429 :     return myViewPort.getWidth();
     113             : }
     114             : 
     115             : 
     116             : double
     117          10 : GUIDanielPerspectiveChanger::zoom2ZPos(double zoom) const {
     118          10 :     return myOrigWidth / (zoom / 100);
     119             : }
     120             : 
     121             : 
     122             : double
     123          19 : GUIDanielPerspectiveChanger::zPos2Zoom(double zPos) const {
     124          19 :     return (myOrigWidth / zPos) * 100;
     125             : }
     126             : 
     127             : 
     128             : void
     129         580 : GUIDanielPerspectiveChanger::centerTo(const Position& pos, double radius,
     130             :                                       bool applyZoom) {
     131         580 :     if (applyZoom) {
     132           0 :         myViewPort = Boundary();
     133           0 :         myViewPort.add(pos);
     134           0 :         myViewPort.grow(radius);
     135             :     } else {
     136         580 :         myViewPort.moveby(pos.x() - getXPos(), pos.y() - getYPos());
     137             :     }
     138         580 : }
     139             : 
     140             : 
     141             : void
     142           0 : GUIDanielPerspectiveChanger::onLeftBtnPress(void* data) {
     143           0 :     myMouseButtonState |= MOUSEBTN_LEFT;
     144             :     FXEvent* e = (FXEvent*) data;
     145           0 :     myMouseXPosition = e->win_x;
     146           0 :     myMouseYPosition = e->win_y;
     147           0 :     myMoveOnClick = false;
     148           0 :     myMouseDownTime = FXThread::time();
     149           0 : }
     150             : 
     151             : 
     152             : bool
     153           0 : GUIDanielPerspectiveChanger::onLeftBtnRelease(void* data) {
     154           0 :     myMouseButtonState &= ~MOUSEBTN_LEFT;
     155             :     FXEvent* e = (FXEvent*) data;
     156           0 :     myMouseXPosition = e->win_x;
     157           0 :     myMouseYPosition = e->win_y;
     158           0 :     return myMoveOnClick;
     159             : }
     160             : 
     161             : 
     162             : void
     163           0 : GUIDanielPerspectiveChanger::onMiddleBtnPress(void* data) {
     164           0 :     myMouseButtonState |= MOUSEBTN_MIDDLE;
     165             :     FXEvent* e = (FXEvent*) data;
     166           0 :     myMouseXPosition = e->win_x;
     167           0 :     myMouseYPosition = e->win_y;
     168           0 :     myMoveOnClick = false;
     169           0 :     myMouseDownTime = FXThread::time();
     170           0 :     myZoomBase = myCallback.getPositionInformation();
     171           0 : }
     172             : 
     173             : 
     174             : bool
     175           0 : GUIDanielPerspectiveChanger::onMiddleBtnRelease(void* data) {
     176           0 :     myMouseButtonState &= ~MOUSEBTN_MIDDLE;
     177             :     FXEvent* e = (FXEvent*) data;
     178           0 :     myMouseXPosition = e->win_x;
     179           0 :     myMouseYPosition = e->win_y;
     180           0 :     return myMoveOnClick;
     181             : }
     182             : 
     183             : 
     184             : void
     185           0 : GUIDanielPerspectiveChanger::onRightBtnPress(void* data) {
     186           0 :     myMouseButtonState |= MOUSEBTN_RIGHT;
     187             :     FXEvent* e = (FXEvent*) data;
     188           0 :     myMouseXPosition = e->win_x;
     189           0 :     myMouseYPosition = e->win_y;
     190           0 :     myMoveOnClick = false;
     191           0 :     myMouseDownTime = FXThread::time();
     192           0 :     myZoomBase = myCallback.getPositionInformation();
     193           0 : }
     194             : 
     195             : 
     196             : bool
     197           0 : GUIDanielPerspectiveChanger::onRightBtnRelease(void* data) {
     198           0 :     myMouseButtonState &= ~MOUSEBTN_RIGHT;
     199           0 :     if (data != nullptr) {
     200             :         FXEvent* e = (FXEvent*) data;
     201           0 :         myMouseXPosition = e->win_x;
     202           0 :         myMouseYPosition = e->win_y;
     203             :     }
     204           0 :     return myMoveOnClick;
     205             : }
     206             : 
     207             : 
     208             : void
     209           0 : GUIDanielPerspectiveChanger::onMouseWheel(void* data) {
     210             :     FXEvent* e = (FXEvent*) data;
     211             :     // catch empty ghost events after scroll (seem to occur only on Ubuntu)
     212           0 :     if (e->code == 0) {
     213             :         return;
     214             :     }
     215             :     // zoom scale relative delta and its inverse; is optimized (all literals)
     216             :     const double zScale_rDelta_norm = 0.1;
     217             :     const double zScale_rDelta_inv = -zScale_rDelta_norm / (1. + zScale_rDelta_norm);
     218             :     double zScale_rDelta = zScale_rDelta_norm ;
     219           0 :     if (e->code < 0) {
     220             :         // for inverse zooming direction
     221             :         zScale_rDelta = zScale_rDelta_inv;
     222             :     }
     223             :     // keyboard modifier: slow, fast mouse-zoom
     224           0 :     if ((e->state & CONTROLMASK) != 0) {
     225           0 :         zScale_rDelta /= 4;
     226           0 :     } else if ((e->state & SHIFTMASK) != 0) {
     227           0 :         zScale_rDelta *= 4;
     228             :     }
     229           0 :     myZoomBase = myCallback.getPositionInformation();
     230           0 :     zoom(1.0 + zScale_rDelta);
     231           0 :     myCallback.updateToolTip();
     232             : }
     233             : 
     234             : 
     235             : void
     236           0 : GUIDanielPerspectiveChanger::onMouseMove(void* data) {
     237             :     FXEvent* e = (FXEvent*) data;
     238           0 :     myCallback.setWindowCursorPosition(e->win_x, e->win_y);
     239           0 :     const int xdiff = myMouseXPosition - e->win_x;
     240           0 :     const int ydiff = myMouseYPosition - e->win_y;
     241           0 :     const bool moved = xdiff != 0 || ydiff != 0;
     242           0 :     const bool pastDelay = !gSchemeStorage.getDefault().gaming && FXThread::time() > (myMouseDownTime + myDragDelay);
     243           0 :     switch (myMouseButtonState) {
     244           0 :         case MOUSEBTN_LEFT:
     245             :         case MOUSEBTN_MIDDLE:
     246           0 :             if (pastDelay) {
     247           0 :                 if (myRotation != 0) {
     248           0 :                     Position diffRot = Position(xdiff, ydiff).rotateAround2D(
     249           0 :                                            DEG2RAD(myRotation), Position(0, 0));
     250           0 :                     move((int)diffRot.x(), (int)diffRot.y());
     251             :                 } else {
     252           0 :                     move(xdiff, ydiff);
     253             :                 }
     254           0 :                 if (moved) {
     255           0 :                     myMoveOnClick = true;
     256             :                 }
     257             :             }
     258             :             break;
     259           0 :         case MOUSEBTN_RIGHT:
     260           0 :             if (pastDelay) {
     261           0 :                 zoom(1 + 10.0 * ydiff / myCallback.getWidth());
     262           0 :                 rotate(xdiff);
     263           0 :                 if (moved) {
     264           0 :                     myMoveOnClick = true;
     265             :                 }
     266             :             }
     267             :             break;
     268           0 :         default:
     269           0 :             if (moved) {
     270           0 :                 myCallback.updateToolTip();
     271             :             }
     272             :             break;
     273             :     }
     274           0 :     myMouseXPosition = e->win_x;
     275           0 :     myMouseYPosition = e->win_y;
     276           0 : }
     277             : 
     278             : 
     279             : void
     280          19 : GUIDanielPerspectiveChanger::setViewport(double zoom,
     281             :         double xPos, double yPos) {
     282          19 :     const double zoomFactor = zoom / 50; // /100 to normalize, *2 because growth is added on both sides
     283          19 :     myViewPort = Boundary();
     284          19 :     myViewPort.add(Position(xPos, yPos));
     285          19 :     myViewPort.growHeight(myOrigHeight / zoomFactor);
     286          19 :     myViewPort.growWidth(myOrigWidth / zoomFactor);
     287          19 :     myCallback.update();
     288          19 : }
     289             : 
     290             : 
     291             : void
     292          19 : GUIDanielPerspectiveChanger::setViewportFrom(double xPos, double yPos, double zPos) {
     293          19 :     setViewport(zPos2Zoom(zPos), xPos, yPos);
     294          19 : }
     295             : 
     296             : 
     297             : void
     298          19 : GUIDanielPerspectiveChanger::setRotation(double rotation) {
     299          19 :     myRotation = rotation;
     300          19 : }
     301             : 
     302             : void
     303           0 : GUIDanielPerspectiveChanger::changeCanvasSizeLeft(int change) {
     304           0 :     myViewPort = Boundary(
     305           0 :                      myViewPort.xmin() - myCallback.p2m(change),
     306             :                      myViewPort.ymin(),
     307             :                      myViewPort.xmax(),
     308             :                      myViewPort.ymax());
     309           0 : }
     310             : 
     311             : 
     312             : long
     313           0 : GUIDanielPerspectiveChanger::onKeyPress(void* data) {
     314             :     // ignore key events in gaming mode
     315           0 :     if (gSchemeStorage.getDefault().gaming) {
     316             :         return 0;
     317             :     }
     318             :     FXEvent* e = (FXEvent*) data;
     319             :     double zoomDiff = 0.1;
     320             :     double moveX = 0;
     321             :     double moveY = 0;
     322             :     double moveFactor = 1;
     323           0 :     if (e->state & CONTROLMASK) {
     324             :         zoomDiff /= 2;
     325             :         moveFactor /= 10;
     326           0 :     } else if (e->state & SHIFTMASK) {
     327             :         zoomDiff *= 2;
     328           0 :     } else if (e->state & ALTMASK) {
     329             :         moveFactor *= 10;
     330             :     }
     331           0 :     switch (e->code) {
     332           0 :         case FX::KEY_Left:
     333             :             moveX = -1;
     334           0 :             moveFactor /= 10;
     335           0 :             break;
     336           0 :         case FX::KEY_Right:
     337             :             moveX = 1;
     338           0 :             moveFactor /= 10;
     339           0 :             break;
     340           0 :         case FX::KEY_Up:
     341             :             moveY = -1;
     342           0 :             moveFactor /= 10;
     343           0 :             break;
     344           0 :         case FX::KEY_Down:
     345             :             moveY = 1;
     346           0 :             moveFactor /= 10;
     347           0 :             break;
     348           0 :         case FX::KEY_plus:
     349             :         case FX::KEY_KP_Add:
     350           0 :             myZoomBase = myCallback.getPositionInformation();
     351           0 :             zoom(1.0 + zoomDiff);
     352           0 :             myCallback.updateToolTip();
     353           0 :             return 1;
     354           0 :         case FX::KEY_minus:
     355             :         case FX::KEY_KP_Subtract:
     356             :             zoomDiff = -zoomDiff;
     357           0 :             myZoomBase = myCallback.getPositionInformation();
     358           0 :             zoom(1.0 + zoomDiff);
     359           0 :             myCallback.updateToolTip();
     360           0 :             return 1;
     361           0 :         case FX::KEY_Home:
     362             :         case FX::KEY_KP_Home:
     363           0 :             myCallback.recenterView();
     364           0 :             myCallback.update();
     365           0 :             return 1;
     366             :         default:
     367             :             return 0;
     368             :     }
     369           0 :     myViewPort.moveby(moveX * moveFactor * myViewPort.getWidth(),
     370           0 :                       -moveY * moveFactor * myViewPort.getHeight());
     371           0 :     myCallback.update();
     372           0 :     return 1;
     373             : }
     374             : 
     375             : 
     376             : /****************************************************************************/

Generated by: LCOV version 1.14