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 GUIOSGManipulator.cpp
15 : /// @author Mirko Barthauer
16 : /// @date 27.11.2022
17 : ///
18 : // A custom camera manipulator to interact with the OSG view directly
19 : /****************************************************************************/
20 : #include <config.h>
21 :
22 : #include <utils/geom/GeomHelper.h>
23 : #include <utils/common/MsgHandler.h>
24 : #include <utils/common/StringBijection.h>
25 :
26 : #include "GUIOSGManipulator.h"
27 : #include "GUIOSGView.h"
28 :
29 : #ifdef HAVE_OSG
30 :
31 : #define DEFAULT_MOVESPEED_MIN 1.0
32 : //#define DEFAULT_MOVESPEED_MAX 30.0
33 : //#define DEFAULT_MOVEACCEL 2.0
34 :
35 : static StringBijection<ManipulatorMode>::Entry ModeTextInitializer[] = {
36 : {"Ego", MODE_EGO},
37 : {"Walk", MODE_WALK},
38 : {"Terrain", MODE_TERRAIN}
39 : };
40 :
41 : StringBijection<ManipulatorMode> ModeText(ModeTextInitializer, MODE_TERRAIN, false);
42 :
43 :
44 : // ===========================================================================
45 : // method definitions
46 : // ===========================================================================
47 411 : GUIOSGManipulator::GUIOSGManipulator(GUIOSGView* parent, ManipulatorMode initMode, bool verticalFixed, double /* eyeHeight */) :
48 411 : myParent(parent), myCurrentMode(initMode), /*myWalkEyeHeight(eyeHeight),*/ myMoveSpeed(DEFAULT_MOVESPEED_MIN) {
49 411 : setAllowThrow(false);
50 411 : setVerticalAxisFixed(verticalFixed);
51 411 : }
52 :
53 :
54 822 : GUIOSGManipulator::~GUIOSGManipulator() {
55 822 : }
56 :
57 :
58 : bool
59 0 : GUIOSGManipulator::performMovementLeftMouseButton(const double eventTimeDelta, const double dx, const double dy) {
60 0 : if (myCurrentMode == MODE_TERRAIN) {
61 0 : return osgGA::TerrainManipulator::performMovementMiddleMouseButton(eventTimeDelta, dx, dy);
62 : }
63 : return false;
64 : }
65 :
66 :
67 : bool
68 0 : GUIOSGManipulator::performMovementMiddleMouseButton(const double eventTimeDelta, const double dx, const double dy) {
69 0 : if (myCurrentMode == MODE_TERRAIN) {
70 0 : return osgGA::TerrainManipulator::performMovementLeftMouseButton(eventTimeDelta, dx, dy);
71 : }
72 : return false;
73 : }
74 :
75 :
76 : bool
77 0 : GUIOSGManipulator::performMovementRightMouseButton(const double eventTimeDelta, const double dx, const double dy) {
78 0 : if (myCurrentMode == MODE_TERRAIN) {
79 0 : return osgGA::TerrainManipulator::performMovementRightMouseButton(eventTimeDelta, dx, -dy);
80 : }
81 : return false;
82 : }
83 :
84 :
85 : bool
86 0 : GUIOSGManipulator::handleMouseMove(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) {
87 0 : if (myCurrentMode == MODE_EGO || myCurrentMode == MODE_WALK) {
88 0 : return handleMouseDeltaMovement(ea, aa);
89 : }
90 : return false;
91 : }
92 :
93 :
94 : bool
95 0 : GUIOSGManipulator::handleMouseDrag(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) {
96 0 : if (myCurrentMode == MODE_TERRAIN) {
97 0 : return osgGA::TerrainManipulator::handleMouseDrag(ea, aa);
98 : }
99 0 : return handleMouseDeltaMovement(ea, aa);
100 : }
101 :
102 :
103 : bool
104 0 : GUIOSGManipulator::handleMousePush(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) {
105 0 : if (myCurrentMode == MODE_TERRAIN) {
106 0 : return osgGA::TerrainManipulator::handleMousePush(ea, aa);
107 : }
108 0 : return handleMouseDeltaMovement(ea, aa);
109 : }
110 :
111 :
112 : bool
113 0 : GUIOSGManipulator::handleMouseRelease(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) {
114 0 : if (myCurrentMode == MODE_TERRAIN) {
115 0 : return osgGA::TerrainManipulator::handleMouseRelease(ea, aa);
116 : }
117 : return false;
118 : }
119 :
120 :
121 : bool
122 0 : GUIOSGManipulator::handleMouseDeltaMovement(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) {
123 0 : addMouseEvent(ea);
124 0 : if (_ga_t0.get() == NULL || _ga_t1.get() == NULL) {
125 : return false;
126 : }
127 0 : float dt = static_cast<float>(_ga_t0->getTime() - _ga_t1->getTime());
128 0 : if (dt > 0.1) { // wait until the mouse movement is sufficiently smooth
129 : return false;
130 : }
131 : float intensity = 50.;
132 0 : float dx = _ga_t0->getXnormalized() * intensity * dt;
133 0 : float dy = _ga_t0->getYnormalized() * intensity * dt;
134 0 : if (dx == 0. && dy == 0.) {
135 : return false;
136 : }
137 0 : centerMousePointer(ea, aa);
138 : // calculate delta angles from dx and dy movements
139 0 : if (performMouseDeltaMovement(dx, dy)) {
140 0 : aa.requestRedraw();
141 : }
142 : return true;
143 : }
144 :
145 :
146 : bool
147 0 : GUIOSGManipulator::performMouseDeltaMovement(const float dx, const float dy) {
148 0 : rotateYawPitch(_rotation, dx, dy, osg::Z_AXIS);
149 0 : return true;
150 : }
151 :
152 :
153 0 : void GUIOSGManipulator::centerMousePointer(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) {
154 0 : _mouseCenterX = (ea.getXmin() + ea.getXmax()) / 2.0f;
155 0 : _mouseCenterY = (ea.getYmin() + ea.getYmax()) / 2.0f;
156 0 : aa.requestWarpPointer(_mouseCenterX, _mouseCenterY);
157 0 : }
158 :
159 :
160 : void
161 0 : GUIOSGManipulator::rotateYawPitch(osg::Quat& rotation, const double yaw, const double pitch, const osg::Vec3d& localUp) {
162 : bool verticalAxisFixed = (localUp != osg::Vec3d(0., 0., 0.));
163 :
164 : // fix current rotation
165 : if (verticalAxisFixed) {
166 0 : fixVerticalAxis(rotation, localUp, true);
167 : }
168 :
169 : // rotations
170 0 : osg::Quat rotateYaw(-yaw, verticalAxisFixed ? localUp : rotation * osg::Vec3d(0., 1., 0.));
171 : osg::Quat rotatePitch;
172 : osg::Quat newRotation;
173 0 : osg::Vec3d cameraRight(rotation * osg::Vec3d(1., 0., 0.));
174 :
175 : double my_dy = pitch;
176 : int i = 0;
177 0 : osg::Vec3f eye = _center - _rotation * osg::Vec3d(0., 0., -_distance);
178 : do {
179 : // rotations
180 0 : rotatePitch.makeRotate(my_dy, cameraRight);
181 0 : newRotation = rotation * rotateYaw * rotatePitch;
182 :
183 : // update vertical axis
184 0 : if (verticalAxisFixed) {
185 0 : fixVerticalAxis(newRotation, localUp, false);
186 : }
187 :
188 : // check for viewer's up vector to be more than 90 degrees from "up" axis
189 0 : osg::Vec3d newCameraUp = newRotation * osg::Vec3d(0., 1., 0.);
190 0 : if (newCameraUp * localUp > 0.) {
191 : // apply new rotation
192 0 : setByMatrix(osg::Matrixd::rotate(newRotation) * osg::Matrixd::translate(eye));
193 0 : return;
194 : }
195 0 : my_dy /= 2.;
196 0 : if (++i == 20) {
197 0 : setByMatrix(osg::Matrixd::rotate(rotation) * osg::Matrixd::rotate(rotateYaw) * osg::Matrixd::translate(eye));
198 0 : return;
199 : }
200 0 : } while (true);
201 : }
202 :
203 :
204 : bool
205 0 : GUIOSGManipulator::handleKeyDown(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& /* aa */) {
206 : bool result = false;
207 0 : switch (ea.getKey()) {
208 0 : case osgGA::GUIEventAdapter::KEY_Up:
209 0 : myMove.z() -= myMoveSpeed;
210 : result = true;
211 0 : break;
212 0 : case osgGA::GUIEventAdapter::KEY_Down:
213 0 : myMove.z() += myMoveSpeed;
214 : result = true;
215 0 : break;
216 0 : case osgGA::GUIEventAdapter::KEY_Right:
217 0 : myMove.x() += myMoveSpeed;
218 : result = true;
219 0 : break;
220 0 : case osgGA::GUIEventAdapter::KEY_Left:
221 0 : myMove.x() -= myMoveSpeed;
222 : result = true;
223 0 : break;
224 : }
225 0 : _center += getMatrix().getRotate() * myMove;
226 0 : return result;
227 : }
228 :
229 :
230 : bool
231 0 : GUIOSGManipulator::handleKeyUp(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& /* aa */) {
232 : bool result = false;
233 0 : switch (ea.getKey()) {
234 0 : case osgGA::GUIEventAdapter::KEY_Up:
235 : case osgGA::GUIEventAdapter::KEY_Down:
236 : case osgGA::GUIEventAdapter::KEY_Right:
237 : case osgGA::GUIEventAdapter::KEY_Left:
238 : myMove.set(0, 0, 0);
239 0 : return true;
240 0 : case osgGA::GUIEventAdapter::KEY_F:
241 0 : if (myCurrentMode == MODE_EGO) {
242 0 : myCurrentMode = MODE_TERRAIN; // MODE_WALK disabled until it's fully implemented
243 0 : } else if (myCurrentMode == MODE_WALK) {
244 0 : myCurrentMode = MODE_TERRAIN;
245 : } else {
246 0 : myCurrentMode = MODE_EGO;
247 : }
248 0 : updateHUDText();
249 0 : return true;
250 : }
251 : return result;
252 : }
253 :
254 :
255 : void
256 411 : GUIOSGManipulator::updateHUDText() {
257 1233 : myParent->updateHUDText(TLF("Currently in % camera mode. Press [F] to switch.", ModeText.getString(myCurrentMode)));
258 411 : }
259 :
260 :
261 : void
262 0 : GUIOSGManipulator::setByMatrix(const osg::Matrixd& matrix) {
263 0 : _center = osg::Vec3d(0., 0., -_distance) * matrix;
264 0 : _rotation = matrix.getRotate();
265 :
266 : // fix current rotation
267 0 : if (getVerticalAxisFixed()) {
268 0 : fixVerticalAxis(_center, _rotation, true);
269 : }
270 0 : }
271 :
272 :
273 0 : osg::Matrixd GUIOSGManipulator::getMatrix() const {
274 0 : if (myCurrentMode == MODE_TERRAIN) {
275 0 : return osg::Matrixd::translate(0., 0., _distance) *
276 0 : osg::Matrixd::rotate(_rotation) *
277 0 : osg::Matrixd::translate(_center);
278 : } else {
279 0 : osg::Vec3f eye = _center - _rotation * osg::Vec3d(0., 0., -_distance);
280 0 : return osg::Matrixd::rotate(_rotation) * osg::Matrixd::translate(eye);
281 : }
282 : }
283 :
284 :
285 21662 : osg::Matrixd GUIOSGManipulator::getInverseMatrix() const {
286 21662 : if (myCurrentMode == MODE_TERRAIN) {
287 21662 : return osg::Matrixd::translate(-_center) *
288 21662 : osg::Matrixd::rotate(_rotation.inverse()) *
289 43324 : osg::Matrixd::translate(0.0, 0.0, -_distance);
290 : } else {
291 0 : osg::Vec3f eye = _center - _rotation * osg::Vec3d(0., 0., -_distance);
292 0 : return osg::Matrixd::translate(-eye) * osg::Matrixd::rotate(_rotation.inverse());
293 : }
294 : }
295 :
296 : #endif
|