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 GUIOSGPerspectiveChanger.cpp
15 : /// @author Mirko Barthauer
16 : /// @date August 2022
17 : ///
18 : // Implementation of GUIPerspectiveChanger for OSG 3D views
19 : /****************************************************************************/
20 : #include <config.h>
21 :
22 : #include <fxkeys.h>
23 : #include <utils/geom/Boundary.h>
24 : #include <utils/geom/Position.h>
25 : #include <utils/geom/GeomHelper.h>
26 : #include <utils/gui/settings/GUICompleteSchemeStorage.h>
27 : #include "GUIOSGPerspectiveChanger.h"
28 :
29 :
30 : // ===========================================================================
31 : // method definitions
32 : // ===========================================================================
33 412 : GUIOSGPerspectiveChanger::GUIOSGPerspectiveChanger(
34 412 : GUIOSGView& callBack, const Boundary& viewPort) :
35 : GUIPerspectiveChanger(callBack, viewPort),
36 824 : myOrigWidth(viewPort.getWidth()),
37 412 : myOrigHeight(viewPort.getHeight()),
38 824 : myRotation(0) {
39 412 : myCameraManipulator = callBack.myCameraManipulator;
40 412 : }
41 :
42 :
43 1236 : GUIOSGPerspectiveChanger::~GUIOSGPerspectiveChanger() {}
44 :
45 :
46 : bool
47 0 : GUIOSGPerspectiveChanger::onLeftBtnRelease(void* /* data */) {
48 0 : updateViewport();
49 0 : return false;
50 : }
51 :
52 :
53 : bool
54 0 : GUIOSGPerspectiveChanger::onRightBtnRelease(void* /* data */) {
55 0 : updateViewport();
56 0 : return false;
57 : }
58 :
59 :
60 : bool
61 0 : GUIOSGPerspectiveChanger::onMiddleBtnRelease(void* /* data */) {
62 0 : updateViewport();
63 0 : return false;
64 : }
65 :
66 :
67 0 : void GUIOSGPerspectiveChanger::onMouseMove(void* /* data */) {
68 : //updateViewport();
69 0 : }
70 :
71 :
72 : double
73 412 : GUIOSGPerspectiveChanger::getRotation() const {
74 412 : return myRotation;
75 : }
76 :
77 :
78 : double
79 412 : GUIOSGPerspectiveChanger::getXPos() const {
80 : osg::Vec3d lookFrom, lookAt, up;
81 412 : myCameraManipulator->getInverseMatrix().getLookAt(lookFrom, lookAt, up);
82 412 : return lookFrom.x();
83 : }
84 :
85 :
86 : double
87 412 : GUIOSGPerspectiveChanger::getYPos() const {
88 : osg::Vec3d lookFrom, lookAt, up;
89 412 : myCameraManipulator->getInverseMatrix().getLookAt(lookFrom, lookAt, up);
90 412 : return lookFrom.y();
91 : }
92 :
93 :
94 : double
95 412 : GUIOSGPerspectiveChanger::getZPos() const {
96 : osg::Vec3d lookFrom, lookAt, up;
97 412 : myCameraManipulator->getInverseMatrix().getLookAt(lookFrom, lookAt, up);
98 412 : return lookFrom.z();
99 : }
100 :
101 :
102 : double
103 0 : GUIOSGPerspectiveChanger::getZoom() const {
104 0 : return 100.;
105 : }
106 :
107 :
108 : double
109 0 : GUIOSGPerspectiveChanger::zPos2Zoom(double /* zPos */) const {
110 0 : return 100.;
111 : }
112 :
113 :
114 : double
115 0 : GUIOSGPerspectiveChanger::zoom2ZPos(double /* zoom */) const {
116 0 : return getZPos();
117 : }
118 :
119 :
120 : void
121 0 : GUIOSGPerspectiveChanger::setRotation(double rotation) {
122 0 : myRotation = rotation;
123 0 : }
124 :
125 :
126 : void
127 412 : GUIOSGPerspectiveChanger::centerTo(const Position& pos, double radius, bool /* applyZoom */) {
128 : // maintain view direction if possible and scale so that the position and the
129 : // radius region around it are visible
130 : osg::Vec3d lookFrom, lookAt, up, dir, orthoDir;
131 412 : myCameraManipulator->getInverseMatrix().getLookAt(lookFrom, lookAt, up);
132 : dir = lookAt - lookFrom;
133 : // create helper vectors // check if parallel to z
134 412 : if ((dir ^ osg::Z_AXIS).length() > 0) {
135 0 : orthoDir[0] = -dir[1];
136 0 : orthoDir[1] = dir[0];
137 0 : up = osg::Z_AXIS;
138 : } else {
139 412 : orthoDir = -osg::X_AXIS;
140 412 : up = osg::Y_AXIS;
141 : }
142 412 : orthoDir.normalize();
143 : osg::Vec3d center(pos.x(), pos.y(), pos.z());
144 : osg::Vec3d leftBorder = center + orthoDir * radius;
145 : // construct new camera location which respects the fovy, resets the up vector
146 : double fovy, aspectRatio, zNear, zFar;
147 412 : dynamic_cast<GUIOSGView&>(myCallback).myViewer->getCamera()->getProjectionMatrixAsPerspective(fovy, aspectRatio, zNear, zFar);
148 412 : double halfFovy = DEG2RAD(.5 * fovy);
149 412 : osg::Vec3d outerFov = dir * cos(halfFovy) + orthoDir * sin(halfFovy);
150 : osg::Vec3d radiusVec = leftBorder - center;
151 412 : int sign = ((outerFov ^ radiusVec) * (outerFov ^ dir) > 0) ? 1 : -1;
152 412 : osg::Vec3d camUpdate = center + dir * sign * (outerFov ^ radiusVec).length() / (outerFov ^ dir).length();
153 412 : myCameraManipulator->setHomePosition(camUpdate, center, up);
154 412 : myRotation = 0.;
155 412 : dynamic_cast<GUIOSGView&>(myCallback).myViewer->home();
156 412 : updateViewport(camUpdate);
157 412 : }
158 :
159 :
160 : void
161 0 : GUIOSGPerspectiveChanger::setViewport(double /* zoom */, double xPos, double yPos) {
162 0 : setViewportFrom(xPos, yPos, 0.);
163 0 : }
164 :
165 :
166 : void
167 0 : GUIOSGPerspectiveChanger::setViewportFrom(double xPos, double yPos, double /* zPos */) {
168 : // Keep camera orientation if possible and point it to point to (x,y,0) if possible.
169 : // get current camera orientation
170 : osg::Vec3d lookFrom, lookAt, up, dir;
171 0 : myCameraManipulator->getInverseMatrix().getLookAt(lookFrom, lookAt, up);
172 : dir = lookAt - lookFrom;
173 0 : if ((dir.z() > 0. && lookFrom.z() >= 0.) || dir.z() == 0.) { // create bird view
174 0 : lookFrom[0] = xPos;
175 0 : lookFrom[1] = yPos;
176 0 : lookAt = lookFrom - osg::Vec3d(0., 0., 1.);
177 : } else { // shift current view to reach (x,y,0)
178 : osg::Vec3d shift;
179 : // compute the point on the ground which is in line with the camera direction (solve for z=0)
180 0 : double factor = -lookFrom.z() / dir.z();
181 : osg::Vec3d groundTarget = lookFrom + dir * factor;
182 0 : shift[0] = xPos - groundTarget.x();
183 0 : shift[1] = yPos - groundTarget.y();
184 : lookFrom += shift;
185 : lookAt += shift;
186 : }
187 : osg::Matrix m;
188 0 : m.makeLookAt(lookFrom, lookAt, up);
189 0 : myCameraManipulator->setByInverseMatrix(m);
190 0 : updateViewport(lookFrom);
191 0 : }
192 :
193 :
194 : void
195 0 : GUIOSGPerspectiveChanger::updateViewport() {
196 : osg::Vec3d lookFrom, lookAt, up, dir;
197 0 : myCameraManipulator->getInverseMatrix().getLookAt(lookFrom, lookAt, up);
198 0 : updateViewport(lookFrom);
199 0 : }
200 :
201 :
202 : void
203 412 : GUIOSGPerspectiveChanger::updateViewport(osg::Vec3d& /* lookFrom */) {
204 412 : osg::Vec3d bottomLeft = getPositionOnGround(-1., -1.);
205 412 : osg::Vec3d bottomRight = getPositionOnGround(1., -1.);
206 412 : osg::Vec3d topLeft = getPositionOnGround(1., -1.);
207 412 : osg::Vec3d topRight = getPositionOnGround(1., 1.);
208 : double xMin, xMax, yMin, yMax;
209 : xMin = MIN4(bottomLeft.x(), bottomRight.x(), topLeft.x(), topRight.x());
210 : xMax = MAX4(bottomLeft.x(), bottomRight.x(), topLeft.x(), topRight.x());
211 : yMin = MIN4(bottomLeft.y(), bottomRight.y(), topLeft.y(), topRight.y());
212 : yMax = MAX4(bottomLeft.y(), bottomRight.y(), topLeft.y(), topRight.y());
213 412 : myViewPort.set(xMin, yMin, xMax, yMax);
214 412 : }
215 :
216 :
217 : osg::Vec3d
218 1648 : GUIOSGPerspectiveChanger::getPositionOnGround(double x, double y) {
219 1648 : osg::Matrix VP = dynamic_cast<GUIOSGView&>(myCallback).myViewer->getCamera()->getViewMatrix() * dynamic_cast<GUIOSGView&>(myCallback).myViewer->getCamera()->getProjectionMatrix();
220 : osg::Matrix inverseVP;
221 1648 : inverseVP.invert(VP);
222 :
223 : // compute world near far
224 : osg::Vec3d nearPoint(x, y, -1.);
225 : osg::Vec3d farPoint(x, y, 1.);
226 : osg::Vec3d nearPointWorld = nearPoint * inverseVP;
227 : osg::Vec3d farPointWorld = farPoint * inverseVP;
228 :
229 : // compute crossing with ground plane
230 : osg::Vec3d ray = farPointWorld - nearPointWorld;
231 1648 : if (abs(ray.z()) > 0) {
232 1648 : return nearPointWorld + ray * (-nearPointWorld.z() / ray.z());
233 : }
234 : return osg::Vec3d(0., 0., 0.);
235 : }
236 :
237 :
238 : void
239 0 : GUIOSGPerspectiveChanger::changeCanvasSizeLeft(int /* change */) {
240 0 : }
241 :
242 :
243 : void
244 0 : GUIOSGPerspectiveChanger::setViewport(const Boundary& viewPort) {
245 0 : setViewport(100., viewPort.getCenter().x(), viewPort.getCenter().y());
246 0 : }
|