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