Path: blob/main/src/osgview/GUIOSGPerspectiveChanger.cpp
169665 views
/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.3// This program and the accompanying materials are made available under the4// terms of the Eclipse Public License 2.0 which is available at5// https://www.eclipse.org/legal/epl-2.0/6// This Source Code may also be made available under the following Secondary7// Licenses when the conditions for such availability set forth in the Eclipse8// Public License 2.0 are satisfied: GNU General Public License, version 29// or later which is available at10// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html11// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later12/****************************************************************************/13/// @file GUIOSGPerspectiveChanger.cpp14/// @author Mirko Barthauer15/// @date August 202216///17// Implementation of GUIPerspectiveChanger for OSG 3D views18/****************************************************************************/19#include <config.h>2021#include <fxkeys.h>22#include <utils/geom/Boundary.h>23#include <utils/geom/Position.h>24#include <utils/geom/GeomHelper.h>25#include <utils/gui/settings/GUICompleteSchemeStorage.h>26#include "GUIOSGPerspectiveChanger.h"272829// ===========================================================================30// method definitions31// ===========================================================================32GUIOSGPerspectiveChanger::GUIOSGPerspectiveChanger(33GUIOSGView& callBack, const Boundary& viewPort) :34GUIPerspectiveChanger(callBack, viewPort),35myOrigWidth(viewPort.getWidth()),36myOrigHeight(viewPort.getHeight()),37myRotation(0) {38myCameraManipulator = callBack.myCameraManipulator;39}404142GUIOSGPerspectiveChanger::~GUIOSGPerspectiveChanger() {}434445bool46GUIOSGPerspectiveChanger::onLeftBtnRelease(void* /* data */) {47updateViewport();48return false;49}505152bool53GUIOSGPerspectiveChanger::onRightBtnRelease(void* /* data */) {54updateViewport();55return false;56}575859bool60GUIOSGPerspectiveChanger::onMiddleBtnRelease(void* /* data */) {61updateViewport();62return false;63}646566void GUIOSGPerspectiveChanger::onMouseMove(void* /* data */) {67//updateViewport();68}697071double72GUIOSGPerspectiveChanger::getRotation() const {73return myRotation;74}757677double78GUIOSGPerspectiveChanger::getXPos() const {79osg::Vec3d lookFrom, lookAt, up;80myCameraManipulator->getInverseMatrix().getLookAt(lookFrom, lookAt, up);81return lookFrom.x();82}838485double86GUIOSGPerspectiveChanger::getYPos() const {87osg::Vec3d lookFrom, lookAt, up;88myCameraManipulator->getInverseMatrix().getLookAt(lookFrom, lookAt, up);89return lookFrom.y();90}919293double94GUIOSGPerspectiveChanger::getZPos() const {95osg::Vec3d lookFrom, lookAt, up;96myCameraManipulator->getInverseMatrix().getLookAt(lookFrom, lookAt, up);97return lookFrom.z();98}99100101double102GUIOSGPerspectiveChanger::getZoom() const {103return 100.;104}105106107double108GUIOSGPerspectiveChanger::zPos2Zoom(double /* zPos */) const {109return 100.;110}111112113double114GUIOSGPerspectiveChanger::zoom2ZPos(double /* zoom */) const {115return getZPos();116}117118119void120GUIOSGPerspectiveChanger::setRotation(double rotation) {121myRotation = rotation;122}123124125void126GUIOSGPerspectiveChanger::centerTo(const Position& pos, double radius, bool /* applyZoom */) {127// maintain view direction if possible and scale so that the position and the128// radius region around it are visible129osg::Vec3d lookFrom, lookAt, up, dir, orthoDir;130myCameraManipulator->getInverseMatrix().getLookAt(lookFrom, lookAt, up);131dir = lookAt - lookFrom;132// create helper vectors // check if parallel to z133if ((dir ^ osg::Z_AXIS).length() > 0) {134orthoDir[0] = -dir[1];135orthoDir[1] = dir[0];136up = osg::Z_AXIS;137} else {138orthoDir = -osg::X_AXIS;139up = osg::Y_AXIS;140}141orthoDir.normalize();142osg::Vec3d center(pos.x(), pos.y(), pos.z());143osg::Vec3d leftBorder = center + orthoDir * radius;144// construct new camera location which respects the fovy, resets the up vector145double fovy, aspectRatio, zNear, zFar;146dynamic_cast<GUIOSGView&>(myCallback).myViewer->getCamera()->getProjectionMatrixAsPerspective(fovy, aspectRatio, zNear, zFar);147double halfFovy = DEG2RAD(.5 * fovy);148osg::Vec3d outerFov = dir * cos(halfFovy) + orthoDir * sin(halfFovy);149osg::Vec3d radiusVec = leftBorder - center;150int sign = ((outerFov ^ radiusVec) * (outerFov ^ dir) > 0) ? 1 : -1;151osg::Vec3d camUpdate = center + dir * sign * (outerFov ^ radiusVec).length() / (outerFov ^ dir).length();152myCameraManipulator->setHomePosition(camUpdate, center, up);153myRotation = 0.;154dynamic_cast<GUIOSGView&>(myCallback).myViewer->home();155updateViewport(camUpdate);156}157158159void160GUIOSGPerspectiveChanger::setViewport(double /* zoom */, double xPos, double yPos) {161setViewportFrom(xPos, yPos, 0.);162}163164165void166GUIOSGPerspectiveChanger::setViewportFrom(double xPos, double yPos, double /* zPos */) {167// Keep camera orientation if possible and point it to point to (x,y,0) if possible.168// get current camera orientation169osg::Vec3d lookFrom, lookAt, up, dir;170myCameraManipulator->getInverseMatrix().getLookAt(lookFrom, lookAt, up);171dir = lookAt - lookFrom;172if ((dir.z() > 0. && lookFrom.z() >= 0.) || dir.z() == 0.) { // create bird view173lookFrom[0] = xPos;174lookFrom[1] = yPos;175lookAt = lookFrom - osg::Vec3d(0., 0., 1.);176} else { // shift current view to reach (x,y,0)177osg::Vec3d shift;178// compute the point on the ground which is in line with the camera direction (solve for z=0)179double factor = -lookFrom.z() / dir.z();180osg::Vec3d groundTarget = lookFrom + dir * factor;181shift[0] = xPos - groundTarget.x();182shift[1] = yPos - groundTarget.y();183lookFrom += shift;184lookAt += shift;185}186osg::Matrix m;187m.makeLookAt(lookFrom, lookAt, up);188myCameraManipulator->setByInverseMatrix(m);189updateViewport(lookFrom);190}191192193void194GUIOSGPerspectiveChanger::updateViewport() {195osg::Vec3d lookFrom, lookAt, up, dir;196myCameraManipulator->getInverseMatrix().getLookAt(lookFrom, lookAt, up);197updateViewport(lookFrom);198}199200201void202GUIOSGPerspectiveChanger::updateViewport(osg::Vec3d& /* lookFrom */) {203osg::Vec3d bottomLeft = getPositionOnGround(-1., -1.);204osg::Vec3d bottomRight = getPositionOnGround(1., -1.);205osg::Vec3d topLeft = getPositionOnGround(1., -1.);206osg::Vec3d topRight = getPositionOnGround(1., 1.);207double xMin, xMax, yMin, yMax;208xMin = MIN4(bottomLeft.x(), bottomRight.x(), topLeft.x(), topRight.x());209xMax = MAX4(bottomLeft.x(), bottomRight.x(), topLeft.x(), topRight.x());210yMin = MIN4(bottomLeft.y(), bottomRight.y(), topLeft.y(), topRight.y());211yMax = MAX4(bottomLeft.y(), bottomRight.y(), topLeft.y(), topRight.y());212myViewPort.set(xMin, yMin, xMax, yMax);213}214215216osg::Vec3d217GUIOSGPerspectiveChanger::getPositionOnGround(double x, double y) {218osg::Matrix VP = dynamic_cast<GUIOSGView&>(myCallback).myViewer->getCamera()->getViewMatrix() * dynamic_cast<GUIOSGView&>(myCallback).myViewer->getCamera()->getProjectionMatrix();219osg::Matrix inverseVP;220inverseVP.invert(VP);221222// compute world near far223osg::Vec3d nearPoint(x, y, -1.);224osg::Vec3d farPoint(x, y, 1.);225osg::Vec3d nearPointWorld = nearPoint * inverseVP;226osg::Vec3d farPointWorld = farPoint * inverseVP;227228// compute crossing with ground plane229osg::Vec3d ray = farPointWorld - nearPointWorld;230if (abs(ray.z()) > 0) {231return nearPointWorld + ray * (-nearPointWorld.z() / ray.z());232}233return osg::Vec3d(0., 0., 0.);234}235236237void238GUIOSGPerspectiveChanger::changeCanvasSizeLeft(int /* change */) {239}240241242void243GUIOSGPerspectiveChanger::setViewport(const Boundary& viewPort) {244setViewport(100., viewPort.getCenter().x(), viewPort.getCenter().y());245}246247248