• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Stellarium / stellarium / 13258187680

11 Feb 2025 07:50AM UTC coverage: 12.127% (+0.03%) from 12.101%
13258187680

Pull #3751

github

10110111
converter: fix a crash
Pull Request #3751: Switch skycultures to the new format

14613 of 120497 relevant lines covered (12.13%)

18620.32 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/core/StelMovementMgr.cpp
1
/*
2
 * Stellarium
3
 * Copyright (C) 2007 Fabien Chereau
4
 * Copyright (C) 2015 Georg Zotti (offset view adaptations, Up vector fixes)
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 2
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335, USA.
19
 *
20
 * TODO: Rewrite this class. It has been much of the easy feel of Stellarium, but is terribly complicated to maintain.
21
 * Very likely some things can be  made clearer, more efficient, use modern Qt things instead of manual solutions, etc.
22
 * Esp. the up-vector requirements for zenith views cause lots of headache.
23
 * In case we want to have other mount modes (ecliptical, galactical, ...), several parts have to be extended.
24
*/
25

26
#include "StelMovementMgr.hpp"
27
#include "StelObjectMgr.hpp"
28
#include "StelModuleMgr.hpp"
29
#include "StelApp.hpp"
30
#include "StelCore.hpp"
31
#include "StelUtils.hpp"
32
#include "StelTranslator.hpp"
33
#include "StelPainter.hpp"
34
#include "StelProjector.hpp"
35
#include "LabelMgr.hpp"
36
#include "Planet.hpp"
37
#include "Orbit.hpp"
38
#include "StelActionMgr.hpp"
39

40
#include <cmath>
41
#include <QString>
42
#include <QTextStream>
43
#include <QSettings>
44
#include <QKeyEvent>
45
#include <QDebug>
46
#include <QFont>
47
#include <QFontMetrics>
48

49
double Smoother::getValue() const
×
50
{
51
        double k = easingCurve.valueForProgress(progress / duration);
×
52
        return start * (1 - k) + aim * k;
×
53
}
54

55
void Smoother::setTarget(double start, double aim, double duration)
×
56
{
57
        this->start = start;
×
58
        this->aim = aim;
×
59
        if (duration>0.001) // duration cannot be zero!
×
60
                this->duration = duration;
×
61
        else
62
                this->duration = 0.001;
×
63
        this->progress = 0.;
×
64
        // Compute best easing curve depending on the speed of animation.
65
        if (duration >= 1.0)
×
66
                easingCurve = QEasingCurve(QEasingCurve::InOutQuart);
×
67
        else
68
                easingCurve = QEasingCurve(QEasingCurve::OutQuad);
×
69
}
×
70

71
void Smoother::update(double dt)
×
72
{
73
        progress = qMin(progress + dt, duration);
×
74
}
×
75

76
bool Smoother::finished() const
×
77
{
78
        return progress >= duration;
×
79
}
80

81
StelMovementMgr::StelMovementMgr(StelCore* acore)
×
82
        : currentFov(60.)
×
83
        , initFov(60.)
×
84
        , minFov(0.001389)
×
85
        , maxFov(100.)
×
86
        , userMaxFov(360.)
×
87
        , deltaFov(0.0)
×
88
        , core(acore)
×
89
        , objectMgr(Q_NULLPTR)
×
90
        , flagLockEquPos(false)
×
91
        , flagTracking(false)
×
92
        , flagInhibitAllAutomoves(false)
×
93
        , isMouseMovingHoriz(false)
×
94
        , isMouseMovingVert(false)
×
95
        , flagEnableMoveAtScreenEdge(false)
×
96
        , flagEnableMouseNavigation(true)
×
97
        , flagEnableMouseZooming(true)
×
98
        , mouseZoomSpeed(30)
×
99
        , flagEnableZoomKeys(true)
×
100
        , flagEnableMoveKeys(true)
×
101
        , keyMoveSpeed(0.00025)
×
102
        , keyZoomSpeed(0.00025)
×
103
        , flagMoveSlow(false)
×
104
        , flagCustomPan(false)
×
105
        , rateX(0.0)
×
106
        , rateY(0.0)
×
107
        , movementsSpeedFactor(1.0)
×
108
        , move()
×
109
        , flagAutoMove(false)
×
110
        , zoomingMode(ZoomNone)
×
111
        , deltaAlt(0.0)
×
112
        , deltaAz(0.0)
×
113
        , flagManualZoom(false)
×
114
        , autoMoveDuration(1.5)
×
115
        , isDragging(false)
×
116
        , hasDragged(false)
×
117
        , previousX(0)
×
118
        , previousY(0)
×
119
        , beforeTimeDragTimeRate(0.0)
×
120
        , dragTimeMode(false)
×
121
        , zoomMove()
×
122
        , flagAutoZoom(false)
×
123
        , flagAutoZoomOutResetsDirection(false)
×
124
        , mountMode(MountAltAzimuthal)
×
125
        , initViewPos(1., 0., 0.)
×
126
        , initViewUp(0., 0., 1.)
×
127
        , viewDirectionJ2000(0., 1., 0.)
×
128
        , viewDirectionMountFrame(0., 1., 0.)
×
129
        , upVectorMountFrame(0.,0.,1.)
×
130
        , dragTriggerDistance(4.f)
×
131
        , viewportOffsetTimeline(Q_NULLPTR)
×
132
        , oldViewportOffset(0.0, 0.0)
×
133
        , targetViewportOffset(0.0, 0.0)
×
134
        , flagIndicationMountMode(false)
×
135
        , lastMessageID(0)
×
136
{
137
        setObjectName("StelMovementMgr");
×
138
}
×
139

140
StelMovementMgr::~StelMovementMgr()
×
141
{
142
        if (viewportOffsetTimeline)
×
143
        {
144
                delete viewportOffsetTimeline;
×
145
                viewportOffsetTimeline=Q_NULLPTR;
×
146
        }
147
}
×
148

149
void StelMovementMgr::init()
×
150
{
151
        conf = StelApp::getInstance().getSettings();
×
152
        objectMgr = GETSTELMODULE(StelObjectMgr);
×
153
        Q_ASSERT(conf);
×
154
        Q_ASSERT(objectMgr);
×
155
        connect(objectMgr, SIGNAL(selectedObjectChanged(StelModule::StelModuleSelectAction)),
×
156
                this, SLOT(selectedObjectChange(StelModule::StelModuleSelectAction)));
157
        connect(&StelApp::getInstance(), SIGNAL(languageChanged()), this, SLOT(bindingFOVActions()));
×
158

159
        flagEnableMoveAtScreenEdge = conf->value("navigation/flag_enable_move_at_screen_edge",false).toBool();
×
160
        mouseZoomSpeed = conf->value("navigation/mouse_zoom",30).toInt();
×
161
        flagEnableZoomKeys = conf->value("navigation/flag_enable_zoom_keys", true).toBool();
×
162
        flagEnableMoveKeys = conf->value("navigation/flag_enable_move_keys", true).toBool();
×
163
        keyMoveSpeed = conf->value("navigation/move_speed",0.0004).toDouble();
×
164
        keyZoomSpeed = conf->value("navigation/zoom_speed", 0.0004).toDouble();
×
165
        autoMoveDuration = conf->value ("navigation/auto_move_duration",1.5f).toFloat();
×
166
        flagManualZoom = conf->value("navigation/flag_manual_zoom").toBool();
×
167
        flagAutoZoomOutResetsDirection = conf->value("navigation/auto_zoom_out_resets_direction", true).toBool();
×
168
        flagEnableMouseNavigation = conf->value("navigation/flag_enable_mouse_navigation",true).toBool();
×
169
        flagEnableMouseZooming = conf->value("navigation/flag_enable_mouse_zooming",true).toBool();
×
170
        flagIndicationMountMode = conf->value("gui/flag_indication_mount_mode", false).toBool();
×
171

172
        minFov = conf->value("navigation/min_fov",0.001389).toDouble(); // default: minimal FOV = 5"
×
173
        userMaxFov = conf->value("navigation/max_fov",360.).toDouble(); // default: 360°=no real limit. maxFov then depends on projection only.
×
174
        initFov = conf->value("navigation/init_fov",60.0).toDouble();
×
175
        currentFov = initFov;
×
176

177
        // we must set mount mode before potentially loading zenith views etc.
178
        QString tmpstr = conf->value("navigation/viewing_mode", "horizon").toString();
×
179
        if (tmpstr.contains("equator", Qt::CaseInsensitive))
×
180
                setMountMode(StelMovementMgr::MountEquinoxEquatorial);
×
181
        else
182
        {
183
                if (tmpstr.contains("horizon", Qt::CaseInsensitive))
×
184
                        setMountMode(StelMovementMgr::MountAltAzimuthal);
×
185
                else
186
                {
187
                        qWarning() << "ERROR: Unknown viewing mode type: " << tmpstr;
×
188
                        setMountMode(StelMovementMgr::MountEquinoxEquatorial);
×
189
                }
190
        }
191
        resetInitViewPos();
×
192

193
        QString movementGroup = N_("Movement and Selection");
×
194
        addAction("actionSwitch_Equatorial_Mount", N_("Miscellaneous"), N_("Switch between equatorial and azimuthal mount"), "equatorialMount", "Ctrl+M");
×
195
        addAction("actionGoto_Selected_Object", movementGroup, N_("Center on selected object"), "tracking", "Space");
×
196
        addAction("actionGoto_Deselection", movementGroup, N_("Deselect the selected object"), "deselection()", "Ctrl+Space");
×
197
        addAction("actionZoom_In_Auto", movementGroup, N_("Zoom in on selected object"), "autoZoomIn()", "/");
×
198
        addAction("actionZoom_Out_Auto", movementGroup, N_("Zoom out"), "autoZoomOut()", "\\");
×
199
        // AW: Same behaviour has action "actionGoto_Selected_Object" by the fact (Is it for backward compatibility?)
200
        addAction("actionSet_Tracking", movementGroup, N_("Track object"), "tracking", "T");
×
201
        // Implementation of quick turning to different directions (examples: CdC, HNSKY)
202
        addAction("actionLook_Towards_East", movementGroup, N_("Look towards East"), "lookEast()", "Shift+E");
×
203
        addAction("actionLook_Towards_West", movementGroup, N_("Look towards West"), "lookWest()", "Shift+W");
×
204
        addAction("actionLook_Towards_North", movementGroup, N_("Look towards North"), "lookNorth()", "Shift+N");
×
205
        addAction("actionLook_Towards_South", movementGroup, N_("Look towards South"), "lookSouth()", "Shift+S");
×
206
        addAction("actionLook_Towards_Zenith", movementGroup, N_("Look towards Zenith"), "lookZenith()", "Shift+Z");
×
207
        // Additional hooks
208
        addAction("actionLook_Towards_NCP", movementGroup, N_("Look towards North Celestial pole"), "lookTowardsNCP()", "Alt+Shift+N");
×
209
        addAction("actionLook_Towards_SCP", movementGroup, N_("Look towards South Celestial pole"), "lookTowardsSCP()", "Alt+Shift+S");
×
210
        // Field of view
211
        // The feature was moved from FOV plugin        
212
        bindingFOVActions();
×
213

214
        viewportOffsetTimeline=new QTimeLine(1000, this);
×
215
        viewportOffsetTimeline->setFrameRange(0, 100);
×
216
        connect(viewportOffsetTimeline, SIGNAL(valueChanged(qreal)), this, SLOT(handleViewportOffsetMovement(qreal)));
×
217
        targetViewportOffset.set(core->getViewportHorizontalOffset(), core->getViewportVerticalOffset());
×
218
}
×
219

220
void StelMovementMgr::resetInitViewPos()
×
221
{
222
        // With a special code of init_view_position=x/y/1 (or actually, anything equal or larger to 1) you can set zenith into the center and atan2(x/y) to bottom of screen.
223
        // examples:  1/0   ->0     NORTH is bottom
224
        //           -1/0   ->180   SOUTH is bottom
225
        //            0/-1  -> 90   EAST is bottom
226
        //            0/1   ->270   WEST is bottom
227
        Vec3f tmp(conf->value("navigation/init_view_pos", "1,0,0").toString());
×
228
        //qDebug() << "initViewPos" << tmp[0] << "/" << tmp[1] << "/" << tmp[2];
229
        if (tmp[2]>=1)
×
230
        {
231
                //qDebug() << "Special zenith setup:";
232
                setViewDirectionJ2000(mountFrameToJ2000(Vec3d(0., 0., 1.)));
×
233
                initViewPos.set(0., 0., 1.);
×
234

235
                // It is not good to code 0/0/1 as view vector: bottom azimuth is undefined. Use default-south:
236
                if ((tmp[0]==0.f) && (tmp[1]==0.f))
×
237
                        tmp[0]=-1.;
×
238

239
                upVectorMountFrame.set(static_cast<double>(tmp[0]), static_cast<double>(tmp[1]), 0.);
×
240
                upVectorMountFrame.normalize();
×
241
                initViewUp=upVectorMountFrame;
×
242
                //qDebug() << "InitViewUp: " << initViewUp;
243
        }
244
        else
245
        {
246
                //qDebug() << "simpler view vectors...";
247
                //qDebug() << "   initViewPos becomes " << tmp[0] << "/" << tmp[1] << "/" << tmp[2];
248
                initViewPos = tmp.toVec3d();
×
249
                //qDebug() << "   initViewPos is " << initViewPos[0] << "/" << initViewPos[1] << "/" << initViewPos[2];
250
                viewDirectionJ2000 = core->altAzToJ2000(initViewPos, StelCore::RefractionOff);
×
251
                //qDebug() << "viewDirectionJ2000: " << viewDirectionJ2000[0] << "/" << viewDirectionJ2000[1] << "/" << viewDirectionJ2000[2];
252
                setViewDirectionJ2000(viewDirectionJ2000);
×
253
                //qDebug() << "   up2000 initViewUp becomes " << initViewUp[0] << "/" << initViewUp[1] << "/" << initViewUp[2];
254
                setViewUpVector(initViewUp);
×
255

256
                //qDebug() << "   upVectorMountFrame becomes " << upVectorMountFrame[0] << "/" << upVectorMountFrame[1] << "/" << upVectorMountFrame[2];
257
        }
258
}
×
259

260
void StelMovementMgr::bindingFOVActions()
×
261
{
262
        StelActionMgr* actionMgr = StelApp::getInstance().getStelActionManager();
×
263
        QString confval, tfov, fovGroup = N_("Field of View"), fovText = q_("Set predefined FOV");
×
264
        QList<float> defaultFOV = { 0.5f, 180.f, 90.f, 60.f, 45.f, 20.f, 10.f, 5.f, 2.f, 1.f };
×
265
        for (int i = 0; i < defaultFOV.size(); ++i)
×
266
        {
267
                confval = QString("fov/quick_fov_%1").arg(i);
×
268
                const double cfov = conf->value(confval, defaultFOV.at(i)).toDouble();
×
269
                tfov = QString::number(cfov, 'f', 2);
×
270
                QString actionName = QString("actionSet_FOV_%1").arg(i);
×
271
                QString actionDescription = QString("%1 #%2 (%3%4)").arg(fovText, QString::number(i), tfov, QChar(0x00B0));
×
272
                StelAction* action = actionMgr->findAction(actionName);
×
273
                if (action!=Q_NULLPTR)
×
274
                        actionMgr->findAction(actionName)->setText(actionDescription);
×
275
                else
276
                        addAction(actionName, fovGroup, actionDescription, this, [=](){setFOVDeg(static_cast<float>(cfov));}, QString("Ctrl+Alt+%1").arg(i));
×
277
        }
×
278
}
×
279

280
void StelMovementMgr::setEquatorialMount(bool b)
×
281
{
282
        setMountMode(b ? MountEquinoxEquatorial : MountAltAzimuthal);
×
283
        StelApp::immediateSave("navigation/viewing_mode", b ? "equator" : "horizon");
×
284

285
        if (getFlagIndicationMountMode())
×
286
        {
287
                QString mode = qc_("Equatorial mount", "mount mode");
×
288
                if (!b)
×
289
                        mode = qc_("Alt-azimuth mount", "mount mode");
×
290

291
                if (lastMessageID)
×
292
                        GETSTELMODULE(LabelMgr)->deleteLabel(lastMessageID);
×
293

294
                StelProjector::StelProjectorParams projectorParams = StelApp::getInstance().getCore()->getCurrentStelProjectorParams();
×
295
                StelPainter painter(StelApp::getInstance().getCore()->getProjection2d());
×
296
                int yPositionOffset = qRound(projectorParams.viewportXywh[3]*projectorParams.viewportCenterOffset[1]);
×
297
                int xPosition = qRound(projectorParams.viewportCenter[0] - painter.getFontMetrics().boundingRect(mode).width()/2);
×
298
                int yPosition = qRound(projectorParams.viewportCenter[1] - yPositionOffset - painter.getFontMetrics().height()/2);
×
299
                lastMessageID = GETSTELMODULE(LabelMgr)->labelScreen(mode, xPosition, yPosition, true, StelApp::getInstance().getScreenFontSize() + 3, "#99FF99", true, 2000);
×
300
        }
×
301
}
×
302

303
void StelMovementMgr::setMountMode(MountMode m)
×
304
{
305
        mountMode = m;
×
306
        setViewDirectionJ2000(viewDirectionJ2000);
×
307
        // TODO: Decide whether re-setting Up-vector is required here.
308
        //setViewUpVector(Vec3d(0., 0., 1.));
309
        //setViewUpVectorJ2000(Vec3d(0., 0., 1.)); // Looks wrong on start.
310
        emit equatorialMountChanged(m==MountEquinoxEquatorial);
×
311
}
×
312

313
void StelMovementMgr::setFlagLockEquPos(bool b)
×
314
{
315
        flagLockEquPos=b;
×
316
}
×
317

318
void StelMovementMgr::setViewUpVectorJ2000(const Vec3d& up)
×
319
{
320
        //GETSTELMODULE(StelObjectMgr)->setExtraInfoString(StelObject::DebugAid, QString("setViewUpvectorJ2000(): setting upVectorMountFrame to ").append(j2000ToMountFrame(up).toString()));
321
        upVectorMountFrame = j2000ToMountFrame(up);
×
322
}
×
323

324
// For simplicity you can set this directly. Take care when looking into poles like zenith in altaz mode:
325
// We have a problem if alt=+/-90degrees: view and up angles are ill-defined (actually, angle between them=0 and therefore we saw shaky rounding effects), therefore Bug LP:1068529
326
void StelMovementMgr::setViewUpVector(const Vec3d& up)
×
327
{
328
        //qDebug() << "setViewUpvector(): setting upVectorMountFrame to " << up;
329
        upVectorMountFrame = up;
×
330
}
×
331

332
Vec3d StelMovementMgr::getViewUpVectorJ2000() const
×
333
{
334
        return mountFrameToJ2000(upVectorMountFrame);
×
335
}
336

337
bool StelMovementMgr::handleMouseMoves(int x, int y, Qt::MouseButtons)
×
338
{
339
        // Turn if the mouse is at the edge of the screen unless config asks otherwise
340
        if (flagEnableMoveAtScreenEdge)
×
341
        {
342
                if (x <= 1)
×
343
                {
344
                        turnLeft(true);
×
345
                        isMouseMovingHoriz = true;
×
346
                }
347
                else if (x >= core->getProjection2d()->getViewportWidth() - 2)
×
348
                {
349
                        turnRight(true);
×
350
                        isMouseMovingHoriz = true;
×
351
                }
352
                else if (isMouseMovingHoriz)
×
353
                {
354
                        turnLeft(false);
×
355
                        isMouseMovingHoriz = false;
×
356
                }
357

358
                if (y <= 1)
×
359
                {
360
                        turnUp(true);
×
361
                        isMouseMovingVert = true;
×
362
                }
363
                else if (y >= core->getProjection2d()->getViewportHeight() - 2)
×
364
                {
365
                        turnDown(true);
×
366
                        isMouseMovingVert = true;
×
367
                }
368
                else if (isMouseMovingVert)
×
369
                {
370
                        turnUp(false);
×
371
                        isMouseMovingVert = false;
×
372
                }
373
        }
374

375

376
        if (isDragging && flagEnableMouseNavigation)
×
377
        {
378
                if (hasDragged || (sqrtf(static_cast<float>((x-previousX)*(x-previousX) +(y-previousY)*(y-previousY)))>dragTriggerDistance))
×
379
                {
380
                        hasDragged = true;
×
381
                        setFlagTracking(false);
×
382
                        dragView(previousX, previousY, x, y);
×
383
                        previousX = x;
×
384
                        previousY = y;
×
385
                        // We can hardly use the mouse exactly enough to go to the zenith/pole. Any mouse motion can safely reset the simplified up vector.
386
                        //qDebug() << "handleMouseMoves: resetting Up vector.";
387
                        setViewUpVector(Vec3d(0., 0., 1.));
×
388
                        return true;
×
389
                }
390
        }
391
        return false;
×
392
}
393

394
double StelMovementMgr::getCallOrder(StelModuleActionName actionName) const
×
395
{
396
        // allow plugins to intercept keys by using a lower number than this!
397
        if (actionName == StelModule::ActionHandleKeys)
×
398
                return 5;
×
399
        return 0;
×
400
}
401

402

403

404
void StelMovementMgr::handleKeys(QKeyEvent* event)
×
405
{
406
        GimbalOrbit *gimbal=Q_NULLPTR;
×
407
#ifdef USE_GIMBAL_ORBIT
408
        StelCore *core=StelApp::getInstance().getCore();
×
409
        Planet* obsPlanet= core->getCurrentPlanet().data();
×
410
        if (obsPlanet->getPlanetType()==Planet::isObserver)
×
411
        {
412
                gimbal=static_cast<GimbalOrbit*>(obsPlanet->getOrbit());
×
413
        }
414
#endif
415
        if (event->type() == QEvent::KeyPress)
×
416
        {
417
                // qDebug() << "Modifiers:" << event->modifiers();
418
                // FIXME: Alt modifier seems problematic. The keys to modify distance in an observer gimbal seem to
419
                // collide with operating system hotkeys. Using Alt5/Alt6 is experimental just to have "some" working solution.
420
                // Direction and zoom deplacements
421
                switch (event->key())
×
422
                {
423
                        case Qt::Key_Left:
×
424
                                if (gimbal && event->modifiers().testFlag(Qt::AltModifier)){
×
425
                                        gimbal->addToLongitude(-5.);
×
426
                                } else {
427
                                        turnLeft(true);
×
428
                                }
429
                                break;
×
430
                        case Qt::Key_Right:
×
431
                                if (gimbal && event->modifiers().testFlag(Qt::AltModifier)){
×
432
                                        gimbal->addToLongitude(5.);
×
433
                                } else
434
                                turnRight(true);
×
435
                                break;
×
436
                        case Qt::Key_Up:
×
437
                                if (gimbal && event->modifiers().testFlag(Qt::AltModifier)){
×
438
                                        gimbal->addToLatitude(5.);
×
439
                                }
440
                                else if (event->modifiers().testFlag(Qt::ControlModifier)){
×
441
                                        zoomIn(true);
×
442
                                } else {
443
                                        turnUp(true);
×
444
                                }
445
                                break;
×
446
                        case Qt::Key_Down:
×
447
                                if (gimbal && event->modifiers().testFlag(Qt::AltModifier)){
×
448
                                        gimbal->addToLatitude(-5.);
×
449
                                }
450
                                else if (event->modifiers().testFlag(Qt::ControlModifier)) {
×
451
                                        zoomOut(true);
×
452
                                } else {
453
                                        turnDown(true);
×
454
                                }
455
                                break;
×
456
                        case Qt::Key_PageUp:
×
457
                        case Qt::Key_multiply:
458
                                zoomIn(true);
×
459
                                break;
×
460
                        case Qt::Key_PageDown:
×
461
                        case Qt::Key_division:
462
                                zoomOut(true);
×
463
                                break;
×
464
                        case Qt::Key_End:
×
465
                                if (gimbal && event->modifiers().testFlag(Qt::AltModifier))
×
466
                                {
467
                                        gimbal->addToDistance(gimbal->getDistance()*0.05);
×
468
                                }
469
                                break;
×
470
                        case Qt::Key_Home:
×
471
                                if (gimbal && event->modifiers().testFlag(Qt::AltModifier))
×
472
                                {
473
                                        gimbal->addToDistance(-gimbal->getDistance()*0.05);
×
474
                                }
475
                                break;
×
476
                        case Qt::Key_Shift:
×
477
                                moveSlow(true); break;
×
478
                        default:
×
479
                                return;
×
480
                }
481
        }
482
        else
483
        {
484
                // When a deplacement key is released stop moving
485
                switch (event->key())
×
486
                {
487
                        case Qt::Key_Left:
×
488
                                turnLeft(false); break;
×
489
                        case Qt::Key_Right:
×
490
                                turnRight(false); break;
×
491
                        case Qt::Key_Up:
×
492
                                zoomIn(false);
×
493
                                turnUp(false);
×
494
                                break;
×
495
                        case Qt::Key_Down:
×
496
                                zoomOut(false);
×
497
                                turnDown(false);
×
498
                                break;
×
499
                        case Qt::Key_PageUp:
×
500
                                zoomIn(false); break;
×
501
                        case Qt::Key_PageDown:
×
502
                                zoomOut(false); break;
×
503
                        case Qt::Key_Shift:
×
504
                                moveSlow(false); break;
×
505
                        case Qt::Key_Control:
×
506
                                // This can be all that is seen for anything with control, so stop them all.
507
                                // This is true for 4.8.1
508
                                turnRight(false);
×
509
                                turnLeft(false);
×
510
                                zoomIn(false);
×
511
                                zoomOut(false);
×
512
                                turnDown(false);
×
513
                                turnUp(false);
×
514
                                dragTimeMode=false;
×
515
                                break;
×
516
                        default:
×
517
                                return;
×
518
                }
519
        }
520
        event->accept();
×
521
}
522

523
//! Handle mouse wheel events.
524
void StelMovementMgr::handleMouseWheel(QWheelEvent* event)
×
525
{
526
        if (flagEnableMouseZooming==false)
×
527
                return;
×
528

529
        // This managed only vertical wheel events.
530
        // However, Alt-wheel switches this to horizontal, so allow alt-wheel and handle angles properly!
531
        const double numSteps = (event->angleDelta().x() + event->angleDelta().y()) / 120.;
×
532

533
        if (event->modifiers() & Qt::ControlModifier)
×
534
        {
535
                if ((event->modifiers() & Qt::AltModifier) && (event->modifiers() & Qt::ShiftModifier))
×
536
                {
537
                        // move time by years
538
                        double jdNow=core->getJD();
×
539
                        int year, month, day, hour, min, sec, millis;
540
                        StelUtils::getDateTimeFromJulianDay(jdNow, &year, &month, &day, &hour, &min, &sec, &millis);
×
541
                        year+=qRound(numSteps);
×
542
                        double jdNew;
543
                        StelUtils::getJDFromDate(&jdNew, year, month, day, hour, min, static_cast<float>(sec));
×
544
                        core->setJD(jdNew);
×
545
                        emit core->dateChanged();                        
×
546
                        emit core->dateChangedByYear(year);
×
547
                }
548
                else if (event->modifiers() & Qt::AltModifier)
×
549
                {
550
                        // move time by days
551
                        core->setJD(core->getJD()+qRound(numSteps));
×
552
                        emit core->dateChanged();
×
553
                }
554
                else if (event->modifiers() & Qt::ShiftModifier)
×
555
                {
556
                        // move time by hours
557
                        core->setJD(core->getJD()+qRound(numSteps)/(24.));
×
558
                }
559
                else
560
                {
561
                        // move time by minutes
562
                        core->setJD(core->getJD()+qRound(numSteps)/(24.*60.));
×
563
                }
564
        }
565
        else
566
        {
567
                const double zoomFactor = exp(-mouseZoomSpeed * numSteps / 60.);
×
568
                const float zoomDuration = 0.2f;
×
569
                zoomTo(getAimFov() * zoomFactor, zoomDuration);
×
570
        }
571
        event->accept();
×
572
}
573

574
void StelMovementMgr::addTimeDragPoint(int x, int y)
×
575
{
576
        DragHistoryEntry e;
577
        e.runTime=StelApp::getInstance().getTotalRunTime();
×
578
        e.jd=core->getJD();
×
579
        e.x=x;
×
580
        e.y=y;
×
581
        timeDragHistory.append(e);
×
582
        if (timeDragHistory.size()>3)
×
583
                timeDragHistory.removeFirst();
×
584
}
×
585

586
bool StelMovementMgr::handlePinch(qreal scale, bool started)
×
587
{
588
#ifdef Q_OS_WIN
589
        if (flagEnableMouseNavigation == false || flagEnableMouseZooming==false)
590
                return true;
591
#endif
592

593
        static double previousFov = 0;
594
        if (started)
×
595
                previousFov = getAimFov();
×
596
        if (scale>0)
×
597
                zoomTo(previousFov/scale, 0);
×
598
        return true;
×
599
}
600

601
void StelMovementMgr::handleMouseClicks(QMouseEvent* event)
×
602
{
603
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
604
        const auto eventPosX = event->position().x();
×
605
        const auto eventPosY = event->position().y();
×
606
#else
607
        const auto eventPosX = event->x();
608
        const auto eventPosY = event->y();
609
#endif
610
        switch (event->button())
×
611
        {
612
                case Qt::RightButton:
×
613
                {
614
                        if (event->type()==QEvent::MouseButtonRelease)
×
615
                        {
616
                                // The code for deselect the selected object was moved into separate method.
617
                                deselection();
×
618
                                event->accept();
×
619
                                return;
×
620
                        }
621
                        break;
×
622
                }
623
                case Qt::LeftButton :
×
624
                        if (event->type()==QEvent::MouseButtonDblClick)
×
625
                        {
626
                                if (objectMgr->getWasSelected())
×
627
                                {
628
                                        moveToObject(objectMgr->getSelectedObject()[0],autoMoveDuration);
×
629
                                        setFlagTracking(true);
×
630
                                }
631
                                event->accept();
×
632
                                return;
×
633
                        }
634
                        else if (event->type()==QEvent::MouseButtonPress)
×
635
                        {
636
                                const auto modifiers = event->modifiers() & (Qt::ControlModifier|Qt::ShiftModifier|Qt::AltModifier);
×
637
                                if (modifiers == Qt::ControlModifier)
×
638
                                {
639
                                        dragTimeMode=true;
×
640
                                        beforeTimeDragTimeRate=core->getTimeRate();
×
641
                                        timeDragHistory.clear();
×
642
                                        addTimeDragPoint(eventPosX, eventPosY);
×
643
                                }
644
                                isDragging = true;
×
645
                                hasDragged = false;
×
646
                                previousX = eventPosX;
×
647
                                previousY = eventPosY;
×
648
                                event->accept();
×
649
                                return;
×
650
                        }
651
                        else if (event->type()==QEvent::MouseButtonRelease)
×
652
                        {
653
                                isDragging = false;
×
654
                                if (hasDragged)
×
655
                                {
656
                                        event->accept();
×
657
                                        if (dragTimeMode)
×
658
                                        {
659
                                                if (timeDragHistory.size()>=3)
×
660
                                                {
661
                                                        const double deltaT = timeDragHistory.last().runTime-timeDragHistory.first().runTime;
×
662
                                                        Vec2f d(timeDragHistory.last().x-timeDragHistory.first().x, timeDragHistory.last().y-timeDragHistory.first().y);
×
663
                                                        if (d.norm()/static_cast<float>(deltaT) < dragTriggerDistance)
×
664
                                                        {
665
                                                                core->setTimeRate(StelCore::JD_SECOND);
×
666
                                                        }
667
                                                        else
668
                                                        {
669
                                                                const double deltaJd = timeDragHistory.last().jd-timeDragHistory.first().jd;
×
670
                                                                const double newTimeRate = deltaJd/deltaT;
×
671
                                                                if (deltaT>0.00000001)
×
672
                                                                {
673
                                                                        if (newTimeRate>=0)
×
674
                                                                                core->setTimeRate(qMax(newTimeRate, StelCore::JD_SECOND));
×
675
                                                                        else
676
                                                                                core->setTimeRate(qMin(newTimeRate, -StelCore::JD_SECOND));
×
677
                                                                }
678
                                                                else
679
                                                                        core->setTimeRate(beforeTimeDragTimeRate);
×
680
                                                        }
681
                                                }
682
                                                else
683
                                                        core->setTimeRate(beforeTimeDragTimeRate);
×
684
                                        }
685
                                        return;
×
686
                                }
687
                                else // has not dragged...
688
                                {
689
                                        // It's a normal click release
690
                                        // TODO: Leave time dragging in Natural speed or zero speed (config option?) if mouse was resting
691
                        #ifdef Q_OS_MACOS
692
                                        // CTRL + left click = right click for 1 button mouse
693
                                        if (event->modifiers().testFlag(Qt::ControlModifier))
694
                                        {
695
                                                objectMgr->unSelect();
696
                                                event->accept();
697
                                                return;
698
                                        }
699

700
                                        // Try to select object at that position
701
                                        objectMgr->findAndSelect(core, eventPosX, eventPosY, event->modifiers().testFlag(Qt::MetaModifier) ? StelModule::AddToSelection : StelModule::ReplaceSelection);
702
                        #else
703
                                        objectMgr->findAndSelect(core, eventPosX, eventPosY, event->modifiers().testFlag(Qt::ControlModifier) ? StelModule::AddToSelection : StelModule::ReplaceSelection);
×
704
                        #endif
705
                                        if (objectMgr->getWasSelected())
×
706
                                                setFlagTracking(false);
×
707
                                        //GZ: You must comment out this line for testing Landscape transparency debug prints.
708
                                        //event->accept();
709
                                        return;
×
710
                                }
711
                        }
712
                        else
713
                        {
714
                                qDebug() << "StelMovementMgr::handleMouseClicks: unknown mouse event type, skipping: " << event->type();
×
715
                        }
716
                        break;
×
717
                case Qt::MiddleButton :
×
718
                        if (event->type()==QEvent::MouseButtonRelease)
×
719
                        {
720
                                if (objectMgr->getWasSelected())
×
721
                                {
722
                                        moveToObject(objectMgr->getSelectedObject()[0],autoMoveDuration);
×
723
                                        setFlagTracking(true);
×
724
                                }
725
                        }
726
                        break;
×
727
                default: break;
×
728
        }
729
        return;
×
730
}
731

732
void StelMovementMgr::setInitFov(double fov)
×
733
{
734
        initFov=fov;
×
735
        StelApp::getInstance().getSettings()->setValue("navigation/init_fov", fov);
×
736
}
×
737

738
void StelMovementMgr::setInitViewDirectionToCurrent()
×
739
{
740
        // 2016-12 TODO: Create azimuth indication for zenith views.
741
        initViewPos = core->j2000ToAltAz(viewDirectionJ2000, StelCore::RefractionOff);
×
742
        QString dirStr = QString("%1,%2,%3").arg(initViewPos[0]).arg(initViewPos[1]).arg(initViewPos[2]);
×
743
        StelApp::getInstance().getSettings()->setValue("navigation/init_view_pos", dirStr);
×
744
}
×
745

746
/*************************************************************************
747
 The selected objects changed, follow it if we were already following another one
748
*************************************************************************/
749
void StelMovementMgr::selectedObjectChange(StelModule::StelModuleSelectAction)
×
750
{
751
        // If an object was selected keep the earth following
752
        if (objectMgr->getWasSelected())
×
753
        {
754
                if (getFlagTracking())
×
755
                        setFlagLockEquPos(true);
×
756
                setFlagTracking(false);
×
757
        }
758
}
×
759

760
void StelMovementMgr::turnRight(bool s)
×
761
{
762
        if (s && flagEnableMoveKeys)
×
763
        {
764
                deltaAz = 1;
×
765
                setFlagTracking(false);
×
766
                setFlagLockEquPos(false);
×
767
        }
768
        else
769
                deltaAz = 0;
×
770
}
×
771

772
void StelMovementMgr::turnLeft(bool s)
×
773
{
774
        if (s && flagEnableMoveKeys)
×
775
        {
776
                deltaAz = -1;
×
777
                setFlagTracking(false);
×
778
                setFlagLockEquPos(false);
×
779
        }
780
        else
781
                deltaAz = 0;
×
782
}
×
783

784
void StelMovementMgr::turnUp(bool s)
×
785
{
786
        if (s && flagEnableMoveKeys)
×
787
        {
788
                deltaAlt = 1;
×
789
                setFlagTracking(false);
×
790
                setFlagLockEquPos(false);
×
791
        }
792
        else
793
                deltaAlt = 0;
×
794
}
×
795

796
void StelMovementMgr::turnDown(bool s)
×
797
{
798
        if (s && flagEnableMoveKeys)
×
799
        {
800
                deltaAlt = -1;
×
801
                setFlagTracking(false);
×
802
                setFlagLockEquPos(false);
×
803
        }
804
        else
805
                deltaAlt = 0;
×
806
}
×
807

808

809
void StelMovementMgr::zoomIn(bool s)
×
810
{
811
        if (flagEnableZoomKeys)
×
812
                deltaFov = -1*(s!=0);
×
813
}
×
814

815
void StelMovementMgr::zoomOut(bool s)
×
816
{
817
        if (flagEnableZoomKeys)
×
818
                deltaFov = (s!=0);
×
819
}
×
820

821
void StelMovementMgr::lookEast(bool zero)
×
822
{
823
        float alt, cy;
824
        Vec3f dir;
×
825

826
        if (zero)
×
827
        {
828
                alt = 0.0f;
×
829
                cy = M_PI_2f;
×
830
                StelUtils::spheToRect(cy, alt, dir);
×
831

832
                setViewDirectionJ2000(core->altAzToJ2000(dir.toVec3d(), StelCore::RefractionOff));
×
833
                setViewUpVector(Vec3d(0., 0., 1.));
×
834
                return;
×
835
        }
836

837
        StelUtils::rectToSphe(&cy,&alt,core->j2000ToAltAz(getViewDirectionJ2000(), StelCore::RefractionOff));
×
838
        cy = M_PI_2f;
×
839
        StelUtils::spheToRect(cy, alt, dir);
×
840
        setViewDirectionJ2000(core->altAzToJ2000(dir.toVec3d(), StelCore::RefractionOff));
×
841
        //qDebug() << "Setting East at Alt:" << alt*M_180_PIf;
842
        if ((mountMode==MountAltAzimuthal) && (fabsf(alt)>M_PI_2f-0.0001f) && (fabs(upVectorMountFrame[2])<0.001))
×
843
        {
844
                // Special case: we already look into zenith (with rounding tolerance). Bring East to bottom of screen.
845
                upVectorMountFrame.set(0., -1.*StelUtils::sign(alt), 0.);
×
846
                //qDebug() << "lookEast: better Up is " << upVectorMountFrame[0] << "/" << upVectorMountFrame[1] << "/" << upVectorMountFrame[2];
847
        }
848
}
849

850
void StelMovementMgr::lookWest(bool zero)
×
851
{
852
        float alt, cy;
853
        Vec3f dir;
×
854

855
        if (zero)
×
856
        {
857
                alt = 0.0f;
×
858
                cy = 3.f*M_PI_2f;
×
859
                StelUtils::spheToRect(cy, alt, dir);
×
860

861
                setViewDirectionJ2000(core->altAzToJ2000(dir.toVec3d(), StelCore::RefractionOff));
×
862
                setViewUpVector(Vec3d(0., 0., 1.));
×
863
                return;
×
864
        }
865

866
        StelUtils::rectToSphe(&cy,&alt,core->j2000ToAltAz(getViewDirectionJ2000(), StelCore::RefractionOff));
×
867
        cy = 3.f*M_PI_2f;
×
868
        StelUtils::spheToRect(cy, alt, dir);
×
869
        setViewDirectionJ2000(core->altAzToJ2000(dir.toVec3d(), StelCore::RefractionOff));
×
870
        //qDebug() << "Setting West at Alt:" << alt*M_180_PIf;
871
        if ((mountMode==MountAltAzimuthal) &&  (fabsf(alt)>M_PI_2f-0.0001f) && (fabs(upVectorMountFrame[2])<0.001))
×
872
        {
873
                // Special case: we already look into zenith (with rounding tolerance). Bring West to bottom of screen.
874
                upVectorMountFrame.set(0., StelUtils::sign(alt), 0.);
×
875
                //qDebug() << "lookEast: better Up is " << upVectorMountFrame[0] << "/" << upVectorMountFrame[1] << "/" << upVectorMountFrame[2];
876
        }
877
}
878

879
void StelMovementMgr::lookNorth(bool zero)
×
880
{
881
        float alt, cy;
882
        Vec3f dir;
×
883

884
        if (zero)
×
885
        {
886
                alt = 0.0f;
×
887
                cy = M_PIf;
×
888
                StelUtils::spheToRect(cy, alt, dir);
×
889

890
                setViewDirectionJ2000(core->altAzToJ2000(dir.toVec3d(), StelCore::RefractionOff));
×
891
                setViewUpVector(Vec3d(0., 0., 1.));
×
892
                return;
×
893
        }
894

895
        StelUtils::rectToSphe(&cy,&alt,core->j2000ToAltAz(getViewDirectionJ2000(), StelCore::RefractionOff));
×
896
        cy = static_cast<float>(M_PI);
×
897
        StelUtils::spheToRect(cy, alt, dir);
×
898
        setViewDirectionJ2000(core->altAzToJ2000(dir.toVec3d(), StelCore::RefractionOff));
×
899

900
        //qDebug() << "Setting North at Alt:" << alt*M_180_PIf;
901
        if ((mountMode==MountAltAzimuthal) &&  (fabsf(alt)>M_PI_2f-0.0001f) && (fabs(upVectorMountFrame[2])<0.001))
×
902
        {
903
                // Special case: we already look into zenith (with rounding tolerance). Bring North to bottom of screen.
904
                upVectorMountFrame.set(StelUtils::sign(alt), 0., 0.);
×
905
                //qDebug() << "lookNorth: better Up is " << upVectorMountFrame[0] << "/" << upVectorMountFrame[1] << "/" << upVectorMountFrame[2];
906
        }
907
}
908

909
void StelMovementMgr::lookSouth(bool zero)
×
910
{
911
        float alt, cy;
912
        Vec3f dir;
×
913

914
        if (zero)
×
915
        {
916
                alt = 0.0f;
×
917
                cy = 0.0f;
×
918
                StelUtils::spheToRect(cy, alt, dir);
×
919

920
                setViewDirectionJ2000(core->altAzToJ2000(dir.toVec3d(), StelCore::RefractionOff));
×
921
                setViewUpVector(Vec3d(0., 0., 1.));
×
922
                return;
×
923
        }
924

925
        StelUtils::rectToSphe(&cy,&alt,core->j2000ToAltAz(getViewDirectionJ2000(), StelCore::RefractionOff));
×
926
        cy = 0.f;
×
927
        StelUtils::spheToRect(cy, alt, dir);
×
928
        setViewDirectionJ2000(core->altAzToJ2000(dir.toVec3d(), StelCore::RefractionOff));
×
929

930
        //qDebug() << "Setting South at Alt:" << alt*M_180_PIf;
931
        if ((mountMode==MountAltAzimuthal) &&  (fabsf(alt)>M_PI_2f-0.0001f) && (fabs(upVectorMountFrame[2])<0.001))
×
932
        {
933
                // Special case: we already look into zenith (with rounding tolerance). Bring South to bottom of screen.
934
                upVectorMountFrame.set(-1.*StelUtils::sign(alt), 0., 0.);
×
935
                //qDebug() << "lookSouth: better Up is " << upVectorMountFrame[0] << "/" << upVectorMountFrame[1] << "/" << upVectorMountFrame[2];
936
        }
937
}
938

939
void StelMovementMgr::lookZenith(void)
×
940
{
941
        Vec3f dir;
×
942
        StelUtils::spheToRect(M_PIf, M_PI_2f, dir);
×
943
        //qDebug() << "lookZenith: Up is " << upVectorMountFrame[0] << "/" << upVectorMountFrame[1] << "/" << upVectorMountFrame[2];
944
        setViewDirectionJ2000(core->altAzToJ2000(dir.toVec3d(), StelCore::RefractionOff));
×
945
        //qDebug() << "lookZenith: View is " << viewDirectionMountFrame[0] << "/" << viewDirectionMountFrame[1] << "/" << viewDirectionMountFrame[2];
946
        if (mountMode==MountAltAzimuthal)
×
947
        {        // ensure a stable up vector that makes the bottom of the screen point south.
948
                upVectorMountFrame.set(-1., 0., 0.);
×
949
                //qDebug() << "lookZenith: better Up is " << upVectorMountFrame[0] << "/" << upVectorMountFrame[1] << "/" << upVectorMountFrame[2];
950
        }
951
}
×
952

953
void StelMovementMgr::lookNadir(void)
×
954
{
955
        Vec3f dir;
×
956
        StelUtils::spheToRect(M_PIf, -M_PI_2f, dir);
×
957
        //qDebug() << "lookNadir: Up is " << upVectorMountFrame[0] << "/" << upVectorMountFrame[1] << "/" << upVectorMountFrame[2];
958
        setViewDirectionJ2000(core->altAzToJ2000(dir.toVec3d(), StelCore::RefractionOff));
×
959
        //qDebug() << "lookNadir: View is " << viewDirectionMountFrame[0] << "/" << viewDirectionMountFrame[1] << "/" << viewDirectionMountFrame[2];
960
        if (mountMode==MountAltAzimuthal)
×
961
        {        // ensure a stable up vector that makes the top of the screen point south.
962
                upVectorMountFrame.set(-1., 0., 0.);
×
963
                //qDebug() << "lookNadir: better Up is " << upVectorMountFrame[0] << "/" << upVectorMountFrame[1] << "/" << upVectorMountFrame[2];
964
        }
965
}
×
966

967
void StelMovementMgr::lookTowardsNCP(void)
×
968
{
969
        if (mountMode==StelMovementMgr::MountEquinoxEquatorial)
×
970
        {
971
                Vec3d viewVector=core->j2000ToEquinoxEqu(getViewDirectionJ2000(), StelCore::RefractionOff);
×
972
                if (qFuzzyCompare(viewVector[2], 1.)) // Already looking to north pole. Do nothing.
×
973
                {
974
                        return;
×
975
                }
976
                else if (qFuzzyCompare(viewVector[2], -1.)) // Stress test! We are looing to the south pole and just want to flip over.
×
977
                {
978
                        viewDirectionMountFrame[2]*=-1;
×
979
                        upVectorMountFrame *= -1;
×
980
                        return;
×
981
                }
982

983
                double RA, dec;
984
                StelUtils::rectToSphe(&RA, &dec, viewVector);
×
985
                Vec3d safeUp(-viewVector[0], -viewVector[1], 0.);
×
986
                safeUp.normalize();
×
987
                setViewUpVector(safeUp);
×
988
        }
989
        setViewDirectionJ2000(core->equinoxEquToJ2000(Vec3d(0,0,1), StelCore::RefractionOff));
×
990
}
991

992
void StelMovementMgr::lookTowardsSCP(void)
×
993
{
994
        if (mountMode==StelMovementMgr::MountEquinoxEquatorial)
×
995
        {
996
                Vec3d viewVector=core->j2000ToEquinoxEqu(getViewDirectionJ2000(), StelCore::RefractionOff);
×
997
                if (qFuzzyCompare(viewVector[2], -1.)) // Already looking to south pole. Do nothing.
×
998
                {
999
                        return;
×
1000
                }
1001
                else if (qFuzzyCompare(viewVector[2], 1.)) // Stress test! We are looing to the north pole and just want to flip over.
×
1002
                {
1003
                        viewDirectionMountFrame[2]*=-1;
×
1004
                        upVectorMountFrame *= -1;
×
1005
                        return;
×
1006
                }
1007

1008
                double RA, dec;
1009
                StelUtils::rectToSphe(&RA, &dec, viewVector);
×
1010
                Vec3d safeUp(viewVector[0], viewVector[1], 0.);
×
1011
                safeUp.normalize();
×
1012
                setViewUpVector(safeUp);
×
1013
        }
1014
        setViewDirectionJ2000(core->equinoxEquToJ2000(Vec3d(0,0,-1), StelCore::RefractionOff));
×
1015
}
1016

1017
void StelMovementMgr::setFOVDeg(float fov)
×
1018
{
1019
        zoomTo(fov, 1.f);
×
1020
}
×
1021

1022
// Increment/decrement smoothly the vision field and position
1023
void StelMovementMgr::updateMotion(double deltaTime)
×
1024
{
1025
        updateVisionVector(deltaTime);
×
1026

1027
        const StelProjectorP proj = core->getProjection(StelCore::FrameJ2000);
×
1028
        // the more it is zoomed, the lower the moving speed is (in angle)
1029
        double depl=keyMoveSpeed*deltaTime*1000*currentFov;
×
1030
        double deplzoom=keyZoomSpeed*deltaTime*1000*static_cast<double>(proj->deltaZoom(static_cast<float>(currentFov)*(M_PIf/360.0f)))*(360.0/M_PI);
×
1031

1032
        if (flagMoveSlow)
×
1033
        {
1034
                depl *= 0.2;
×
1035
                deplzoom *= 0.2;
×
1036
        }
1037

1038
        if (deltaAz<0)
×
1039
        {
1040
                deltaAz = -depl/30;
×
1041
                if (deltaAz<-0.2)
×
1042
                        deltaAz = -0.2;
×
1043
        }
1044
        else if (deltaAz>0)
×
1045
        {
1046
                deltaAz = (depl/30);
×
1047
                if (deltaAz>0.2)
×
1048
                        deltaAz = 0.2;
×
1049
        }
1050

1051
        if (deltaAlt<0)
×
1052
        {
1053
                deltaAlt = -depl/30;
×
1054
                if (deltaAlt<-0.2)
×
1055
                        deltaAlt = -0.2;
×
1056
        }
1057
        else if (deltaAlt>0)
×
1058
        {
1059
                deltaAlt = depl/30;
×
1060
                if (deltaAlt>0.2)
×
1061
                        deltaAlt = 0.2;
×
1062
        }
1063

1064
        if (deltaFov<0)
×
1065
        {
1066
                deltaFov=qMax(-0.15*currentFov, -deplzoom*5);
×
1067
                changeFov(deltaFov);
×
1068
        }
1069
        else if (deltaFov>0)
×
1070
        {
1071
                deltaFov = qMin(20., deplzoom*5.);
×
1072
                changeFov(deltaFov);
×
1073
        }
1074

1075
        if (flagCustomPan)
×
1076
        {
1077
                deltaAz  = rateX*M_PI_180*deltaTime;
×
1078
                deltaAlt = rateY*M_PI_180*deltaTime;
×
1079
        }
1080

1081
        panView(deltaAz, deltaAlt);
×
1082
        updateAutoZoom(deltaTime);
×
1083
}
×
1084

1085
// called at begin of updateMotion()
1086
void StelMovementMgr::updateVisionVector(double deltaTime)
×
1087
{
1088
        // Specialized setups cannot use this functionality!
1089
        if (flagInhibitAllAutomoves)
×
1090
                return;
×
1091

1092
        if (flagAutoMove)
×
1093
        {
1094
                if (!move.targetObject.isNull())
×
1095
                {
1096
                        // if zooming in, object may be moving so be sure to zoom to latest position
1097
                        // In case we have offset center, we want object still visible in center.
1098
                        // Note that if we do not center on an object, we set view direction of the potentially offset screen center!
1099
                        // This is by design, to allow accurate setting of display coordinates.
1100
                        Vec3d v;
×
1101
                        switch (mountMode)
×
1102
                        {
1103
                                case MountAltAzimuthal:
×
1104
                                        v = move.targetObject->getAltAzPosAuto(core);
×
1105
                                        break;
×
1106
                                case MountEquinoxEquatorial:
×
1107
                                        v = move.targetObject->getEquinoxEquatorialPosAuto(core); //  ..Auto! Fix Bug LP:#1484976
×
1108
                                        break;
×
1109
                                case MountGalactic:
×
1110
                                        v = move.targetObject->getGalacticPos(core);
×
1111
                                        break;
×
1112
                                case MountSupergalactic:
×
1113
                                        v = move.targetObject->getSupergalacticPos(core);
×
1114
                                        break;
×
1115
                                default:
×
1116
                                        qWarning() << "StelMovementMgr: unexpected mountMode" << mountMode;
×
1117
                                        Q_ASSERT(0);
×
1118
                                        v = move.targetObject->getAltAzPosAuto(core); // still do something useful
1119
                        }
1120

1121
                        double lat, lon;
1122
                        StelUtils::rectToSphe(&lon, &lat, v);
×
1123
                        double altOffset=core->getCurrentStelProjectorParams().viewportCenterOffset[1]*currentFov*M_PI_180;
×
1124
                        lat+=altOffset;
×
1125
                        StelUtils::spheToRect(lon, lat, v);
×
1126
                        move.aim=mountFrameToJ2000(v);
×
1127
                        move.aim.normalize();
×
1128
                        move.aim*=2.;
×
1129
                        // For aiming at objects, we can assume simple up vector.
1130
                        move.startUp=getViewUpVectorJ2000();
×
1131
                        move.aimUp=mountFrameToJ2000(Vec3d(0., 0., 1.));
×
1132
                        //move.aimUp=Vec3d(0., 0., 1.);
1133
                        move.aimUpCopy=move.aimUp;
×
1134
                }
1135
                else // no targetObject:
1136
                {
1137
                        move.startUp=getViewUpVectorJ2000();
×
1138
                        move.aimUp=mountFrameToJ2000(Vec3d(0., 0., 1.));
×
1139
                }
1140
                move.coef+=move.speed*static_cast<float>(deltaTime)*1000;
×
1141
                //setViewUpVectorJ2000(mountFrameToJ2000(move.aimUp)); // Is this the little flicker? --> NO This would show tited view.
1142
                setViewUpVectorJ2000(move.aimUp);
×
1143
                //qDebug() << "transitional upVectorMountFrame=" << upVectorMountFrame;
1144

1145
                if (move.coef>=1.f)
×
1146
                {
1147
                        //qDebug() << "AutoMove finished. Setting Up vector (in mount frame) to " << upVectorMountFrame.v[0] << "/" << upVectorMountFrame.v[1] << "/" << upVectorMountFrame.v[2];
1148
                        flagAutoMove=false;
×
1149
                        move.coef=1.f;
×
1150

1151
                        //qDebug() << "Mount/Pole difference =" << fabs((fabs(viewDirectionMountFrame.v[2]) - 1.));
1152
                        if (fabs((fabs(viewDirectionMountFrame.v[2]) - 1.)) < 0.00001 )
×
1153
                        {
1154
                                //qDebug() << "ATTENTION: View towards or near the pole of the mount frame. This would cause black screen or orientation jitter.";
1155
                                //qDebug() << "\tviewDirectionMountFrame=" << viewDirectionMountFrame;
1156
                                //qDebug() << "\tviewDirectionJ2000=" << viewDirectionJ2000;
1157
                                //qDebug() << "\tupVectorMountFrame=" << upVectorMountFrame;
1158
                                //qDebug() << "\tmove.aimUpCopy=" << move.aimUpCopy;
1159

1160
                                //qDebug() << "Recreating up vector from stored copy." << move.aimUpCopy;
1161
                                setViewUpVector(move.aimUpCopy);
×
1162

1163
                                //qDebug() << "NEW VECTORS";
1164
                                //qDebug() << "\tviewDirectionMountFrame=" << viewDirectionMountFrame;
1165
                                //qDebug() << "\tviewDirectionJ2000=" << viewDirectionJ2000;
1166
                                //qDebug() << "\tupVectorMountFrame=" << upVectorMountFrame;
1167
                        }
1168
                }
1169

1170
                // Use a smooth function
1171
                const float smooth = 4.f; // (empirically tested)
×
1172
                double c;
1173
                switch (zoomingMode){
×
1174
                        case ZoomIn:
×
1175
                                c=(move.coef>.9f ? 1. : 1. - static_cast<double>(powf(1.f-1.11f*move.coef,3.f))); break;
×
1176
                        case ZoomOut:
×
1177
                                // keep in view at first as zoom out
1178
                                c=(move.coef<0.1f ? 0. : static_cast<double>(powf(1.11f*(move.coef-.1f),3.f))); break;
×
1179
                        default:
×
1180
                                c = static_cast<double>(std::atan(smooth * 2.f*move.coef-smooth)/std::atan(smooth)/2+0.5f);
×
1181
                }
1182

1183
                // In case of azimuthal moves, it is not useful to compute anything from J2000 coordinates.
1184
                // Imagine a slow AltAz move during speedy timelapse: Aim will move!
1185
                // TODO: all variants...
1186
                Vec3d tmpStart;
×
1187
                Vec3d tmpAim;
×
1188
                if (move.mountMode==MountAltAzimuthal)
×
1189
                {
1190
                        tmpStart=move.start;
×
1191
                        tmpAim=move.aim;
×
1192
                }
1193
                else
1194
                {
1195
                        tmpStart = j2000ToMountFrame(move.start);
×
1196
                        tmpAim   = j2000ToMountFrame(move.aim);
×
1197
                }
1198
                double ra_aim, de_aim, ra_start, de_start;
1199
                StelUtils::rectToSphe(&ra_start, &de_start, tmpStart);
×
1200
                StelUtils::rectToSphe(&ra_aim, &de_aim, tmpAim);
×
1201

1202
                // Make sure the position of the object to be aimed at is defined...
1203
                Q_ASSERT(!qIsNaN(move.aim[0]) && !qIsNaN(move.aim[1]) && !qIsNaN(move.aim[2]));
×
1204
                // Trick to choose the good moving direction and never travel on a distance > PI
1205
                if (ra_aim-ra_start > M_PI)
×
1206
                {
1207
                        ra_aim -= 2.*M_PI;
×
1208
                }
1209
                else if (ra_aim-ra_start < -M_PI)
×
1210
                {
1211
                        ra_aim += 2.*M_PI;
×
1212
                }
1213
                const double de_now = de_aim*c + de_start*(1.-c);
×
1214
                const double ra_now = ra_aim*c + ra_start*(1.-c);
×
1215
                Vec3d tmp;
×
1216
                StelUtils::spheToRect(ra_now, de_now, tmp);
×
1217
                setViewDirectionJ2000(mountFrameToJ2000(tmp));
×
1218
        }
1219
        else // no autoMove
1220
        {
1221
                if (flagTracking && objectMgr->getWasSelected()) // Equatorial vision vector locked on selected object
×
1222
                {
1223
                        Vec3d v;
×
1224
                        switch (mountMode)
×
1225
                        {
1226
                                case MountAltAzimuthal:
×
1227
                                        v = objectMgr->getSelectedObject()[0]->getAltAzPosAuto(core);
×
1228
                                        break;
×
1229
                                case MountEquinoxEquatorial:
×
1230
                                        v = objectMgr->getSelectedObject()[0]->getEquinoxEquatorialPosAuto(core);
×
1231
                                        break;
×
1232
                                case MountGalactic:
×
1233
                                        v = objectMgr->getSelectedObject()[0]->getGalacticPos(core);
×
1234
                                        break;
×
1235
                                case MountSupergalactic:
×
1236
                                        v = objectMgr->getSelectedObject()[0]->getSupergalacticPos(core);
×
1237
                                        break;
×
1238
                                default:
×
1239
                                        qWarning() << "StelMovementMgr: unexpected mountMode" << mountMode;
×
1240
                                        Q_ASSERT(0);
×
1241
                                        v = move.targetObject->getAltAzPosAuto(core); // still do something useful in release build
1242
                        }
1243

1244
                        double lat, lon; // general: longitudinal, latitudinal
1245
                        StelUtils::rectToSphe(&lon, &lat, v);
×
1246
                        double latOffset=static_cast<double>(core->getCurrentStelProjectorParams().viewportCenterOffset[1]) * currentFov*M_PI_180;
×
1247
                        lat+=latOffset;
×
1248
                        StelUtils::spheToRect(lon, lat, v);
×
1249

1250
                        setViewDirectionJ2000(mountFrameToJ2000(v));
×
1251
                        setViewUpVectorJ2000(mountFrameToJ2000(Vec3d(0., 0., 1.))); // Does not disturb to reassure this former default.
×
1252
                }
1253
                else // not tracking or no selection
1254
                {
1255
                        if (flagLockEquPos) // Equatorial vision vector locked
×
1256
                        {
1257
                                // Recalc local vision vector
1258
                                setViewDirectionJ2000(viewDirectionJ2000);
×
1259
                        }
1260
                        else
1261
                        {
1262
                                // Vision vector locked to its position in the mountFrame
1263
                                setViewDirectionJ2000(mountFrameToJ2000(viewDirectionMountFrame));
×
1264
                                // After setting time, moveToAltAz broke the up vector without this:
1265
                                // Make sure this does not now break zenith views!
1266
                                // Or make sure to call moveToAltAz twice.
1267
                                setViewUpVectorJ2000(mountFrameToJ2000(upVectorMountFrame));
×
1268
                        }
1269
                }
1270
        }
1271
        //GETSTELMODULE(StelObjectMgr)->setExtraInfoString(StelObject::DebugAid, QString("upVectorMountFrame: %1<br/>").arg(upVectorMountFrame.toString()));
1272
}
1273

1274
void StelMovementMgr::deselection(void)
×
1275
{
1276
        // Deselect the selected object
1277
        StelApp::getInstance().getStelObjectMgr().unSelect();
×
1278
        setFlagLockEquPos(false);        
×
1279
        return;
×
1280
}
1281

1282
// Go and zoom to the selected object. (Action linked to key, default "/")
1283
void StelMovementMgr::autoZoomIn(float moveDuration, bool allowManualZoom)
×
1284
{
1285
        if (!objectMgr->getWasSelected())
×
1286
                return;
×
1287

1288
        moveDuration /= movementsSpeedFactor;
×
1289

1290
        float manualMoveDuration;
1291
        if (!getFlagTracking())
×
1292
        {
1293
                setFlagTracking(true); // includes a call to moveToObject(), but without zooming=1!
×
1294
                moveToObject(objectMgr->getSelectedObject()[0], moveDuration, ZoomIn);
×
1295
                manualMoveDuration = moveDuration;
×
1296
        }
1297
        else
1298
        {
1299
                // faster zoom in manual zoom mode once object is centered
1300
                manualMoveDuration = moveDuration*.66f;
×
1301
        }
1302

1303
        if( allowManualZoom && flagManualZoom )
×
1304
        {
1305
                // if manual zoom mode, user can zoom in incrementally
1306
                double newfov = currentFov*0.5;
×
1307
                zoomTo(newfov, manualMoveDuration);
×
1308
        }
×
1309
        else
1310
        {
1311
                double satfov = objectMgr->getSelectedObject()[0]->getSatellitesFov(core);
×
1312

1313
                if (satfov>0.0 && currentFov*0.9>satfov)
×
1314
                        zoomTo(satfov, moveDuration);
×
1315
                else
1316
                {
1317
                        double closefov = objectMgr->getSelectedObject()[0]->getCloseViewFov(core);
×
1318
                        if (currentFov>closefov)
×
1319
                                zoomTo(closefov, moveDuration);
×
1320
                }
1321
        }
1322
}
1323

1324

1325
// Unzoom and go to the init position
1326
void StelMovementMgr::autoZoomOut(float moveDuration, bool full)
×
1327
{
1328
        moveDuration /= movementsSpeedFactor;
×
1329

1330
        if (objectMgr->getWasSelected() && !full)
×
1331
        {
1332
                // If the selected object has satellites, unzoom to satellites view
1333
                // unless specified otherwise
1334
                double satfov = objectMgr->getSelectedObject()[0]->getSatellitesFov(core);
×
1335

1336
                if (satfov>0.0 && currentFov<=satfov*0.9)
×
1337
                {
1338
                        zoomTo(satfov, moveDuration);
×
1339
                        return;
×
1340
                }
1341

1342
                // If the selected object is part of a Planet subsystem (other than sun),
1343
                // unzoom to subsystem view
1344
                satfov = objectMgr->getSelectedObject()[0]->getParentSatellitesFov((core));
×
1345
                if (satfov>0.0 && currentFov<=satfov*0.9)
×
1346
                {
1347
                        zoomTo(satfov, moveDuration);
×
1348
                        return;
×
1349
                }
1350
        }
1351

1352
        zoomTo(initFov, moveDuration);
×
1353
        if (flagAutoZoomOutResetsDirection)
×
1354
        {
1355
                moveToJ2000(core->altAzToJ2000(getInitViewingDirection(), StelCore::RefractionOff), mountFrameToJ2000(initViewUp), moveDuration, ZoomOut);
×
1356
                setFlagTracking(false);
×
1357
                setFlagLockEquPos(false);
×
1358
        }
1359
}
1360

1361
// This is called when you press SPACEBAR: slowly centering&tracking object
1362
void StelMovementMgr::setFlagTracking(bool b)
×
1363
{
1364
        if (!b || !objectMgr->getWasSelected())
×
1365
        {
1366
                if(b!=flagTracking)
×
1367
                {
1368
                        flagTracking=false;
×
1369
                        emit flagTrackingChanged(b);
×
1370
                }
1371
        }
1372
        else
1373
        {
1374
                moveToObject(objectMgr->getSelectedObject()[0], getAutoMoveDuration());
×
1375
                if(b!=flagTracking)
×
1376
                {
1377
                        flagTracking=true;
×
1378
                        emit flagTrackingChanged(b);
×
1379
                }
1380
        }
1381
}
×
1382

1383

1384
////////////////////////////////////////////////////////////////////////////////
1385
// Move to the given J2000 equatorial position
1386

1387
// aim and aimUp must be in J2000 frame!
1388
void StelMovementMgr::moveToJ2000(const Vec3d& aim, const Vec3d& aimUp, float moveDuration, ZoomingMode zooming)
×
1389
{
1390
        moveDuration /= movementsSpeedFactor;
×
1391

1392
        zoomingMode = zooming;
×
1393
        move.aim=aim;
×
1394
        move.aim.normalize();
×
1395
        move.aim*=2.;
×
1396
        move.aimUp=aimUp; // the new up vector. We cannot simply keep vertical axis, there may be the intention to look into the pole or so.
×
1397
        move.aimUp.normalize();
×
1398
        move.aimUpCopy=move.aimUp;
×
1399
        move.start=viewDirectionJ2000;        
×
1400
        move.start.normalize();
×
1401
        move.startUp=getViewUpVectorJ2000();
×
1402
        move.startUp.normalize();
×
1403
        move.speed=1.f/(moveDuration*1000);
×
1404
        move.coef=0.;
×
1405
        move.targetObject.clear();
×
1406
        //move.mountMode=mountMode; // Maybe better to have MountEquinoxEquatorial here? ==> YES, fixed orientation problem.
1407
        move.mountMode=MountEquinoxEquatorial;
×
1408
        flagAutoMove = true;
×
1409
}
×
1410

1411
void StelMovementMgr::moveToObject(const StelObjectP& target, float moveDuration, ZoomingMode zooming)
×
1412
{
1413
        moveDuration /= movementsSpeedFactor;
×
1414

1415
        zoomingMode = zooming;
×
1416
        move.aim=Vec3d(0.);
×
1417
        move.aimUp=mountFrameToJ2000(Vec3d(0., 0., 1.)); // the new up vector. We try simply vertical axis here. (Should be same as pre-0.15)
×
1418
        move.aimUp.normalize();
×
1419
        move.aimUpCopy=move.aimUp;
×
1420
        move.start=viewDirectionJ2000;
×
1421
        move.start.normalize();
×
1422
        move.startUp=getViewUpVectorJ2000();
×
1423
        move.startUp.normalize();
×
1424
        move.speed=1.f/(moveDuration*1000);
×
1425
        move.coef=0.;
×
1426
        move.targetObject = target;
×
1427
        //move.mountMode=mountMode;  // Maybe better to have MountEquinoxEquatorial here? ==> YES, fixed orientation problem.
1428
        move.mountMode=MountEquinoxEquatorial;
×
1429
        flagAutoMove = true;
×
1430
}
×
1431

1432
// This call does nothing when mount frame is not AltAzi! (TODO later: rethink&fix.)
1433
void StelMovementMgr::moveToAltAzi(const Vec3d& aim, const Vec3d &aimUp, float moveDuration, ZoomingMode zooming)
×
1434
{
1435
        if (mountMode!=StelMovementMgr::MountAltAzimuthal)
×
1436
        {
1437
                qDebug() << "StelMovementMgr: called moveToAltAzi, but not in AltAz mount frame. Ignoring.";
×
1438
                return;
×
1439
        }
1440

1441
        moveDuration /= movementsSpeedFactor;
×
1442

1443
        // Specify start and aim vectors in AltAz system! Then the auto functions can work it out properly.
1444
        zoomingMode = zooming;
×
1445
        move.aim=aim;
×
1446
        move.aim.normalize();
×
1447
        move.aim*=2.;
×
1448
        move.aimUp=aimUp; // the new up vector. We cannot simply keep vertical axis, there may be the intention to look into the zenith or so.
×
1449
        move.aimUp.normalize();
×
1450
        move.aimUpCopy=move.aimUp;
×
1451
        move.start=core->j2000ToAltAz(viewDirectionJ2000, StelCore::RefractionOff);
×
1452
        move.start.normalize();
×
1453
        //qDebug() << "move.start=" << move.start;
1454

1455
        // In the rare case that we currently sit in the zenith, the current up vector cannot be 0/0/1.
1456
        // The only way to come here would have been a previously programmed moveToAltAzi(zenith), and optional move around zenith/nadir by left/right keys.
1457
        // We decode view azimuth from the current up vector and set our move.start direction to the same azimuth, just off the zenith/nadir.
1458
        Vec3d currentUp=upVectorMountFrame; // j2000ToMountFrame(getViewUpVectorJ2000());
×
1459
        if (fabs(currentUp[2]) < 1.e-12)
×
1460
        {
1461
                //qDebug() << "Start a programmed move out of the zenith! Decode azimuth from the up vector." << currentUp;
1462
                // CurrentUp reported as -1/0/0 when looking towards zenith/south
1463
                double az=StelUtils::fmodpos(-atan2(currentUp[1], currentUp[0]), 2.*M_PI); // or some permutation! 0/1 seems wrong.
×
1464
                double alt=acos(qBound(-1.,currentUp[2],1.)); // Ambiguous - One of the poles! We still need info from the view vector.
×
1465
                Vec3d currentAim=core->j2000ToAltAz(viewDirectionJ2000, StelCore::RefractionOff);
×
1466
                //qDebug() << "current pre-move view vector is" << currentAim;
1467
                if (currentAim[2]<0)
×
1468
                {
1469
                        alt*=-1;
×
1470
                        az+=M_PI;
×
1471
                }
1472
                //qDebug() << "current pre-move view decoded as az=" << az*M_180_PI << " alt=" << alt*M_180_PI;
1473
                // Compare with current view direction. Take this (presumably looking into 0/0/1 or 0/0/-1), reduce by 1e-4 degrees
1474
                // reduce altitude, build new view vector, set move.start.
1475
                Vec3d safeAltAz;
×
1476
                alt-=1e-4*M_PI_180*StelUtils::sign(alt);
×
1477
                StelUtils::spheToRect(M_PI-az, alt, safeAltAz);
×
1478
                //qDebug() << "pre-move view vector reduced to az=" << az*M_180_PI << "alt=" << alt*M_180_PI << "-->" << safeAltAz;
1479
                move.start=safeAltAz; //core->altAzToJ2000(safeAltAz, StelCore::RefractionOff);
×
1480
                viewDirectionJ2000=core->altAzToJ2000(move.start, StelCore::RefractionOff);
×
1481
                upVectorMountFrame.set(0,0,1);
×
1482
        }
1483
        move.startUp=aimUp; // we must put this to the target up vector immediately.
×
1484
        move.speed=1.f/(moveDuration*1000);
×
1485
        move.coef=0.;
×
1486
        move.targetObject.clear();
×
1487
        move.mountMode=MountAltAzimuthal; // This signals: start and aim are given in AltAz coordinates.
×
1488
        flagAutoMove = true;
×
1489
        // debug output if required
1490
        //double currAlt, currAzi, newAlt, newAzi;
1491
        //StelUtils::rectToSphe(&currAzi, &currAlt, move.start);
1492
        //StelUtils::rectToSphe(&newAzi, &newAlt, move.aim);
1493
        //qDebug() << "StelMovementMgr::moveToAltAzi() from alt:" << currAlt*(180./M_PI) << "/azi" << currAzi*(180./M_PI)  << "to alt:" << newAlt*(180./M_PI)  << "azi" << newAzi*(180./M_PI) ;
1494
}
1495

1496
Vec3d StelMovementMgr::j2000ToMountFrame(const Vec3d& v) const
×
1497
{
1498
        switch (mountMode)
×
1499
        {
1500
                case MountAltAzimuthal:
×
1501
                        return core->j2000ToAltAz(v, StelCore::RefractionOff); // TODO: Decide if RefractionAuto?
×
1502
                case MountEquinoxEquatorial:
×
1503
                        return core->j2000ToEquinoxEqu(v, StelCore::RefractionOff);
×
1504
                case MountGalactic:
×
1505
                        return core->j2000ToGalactic(v);
×
1506
                case MountSupergalactic:
×
1507
                        return core->j2000ToSupergalactic(v);
×
1508
        }
1509
        Q_ASSERT(0);
×
1510
        return Vec3d(0.);
1511
}
1512

1513
Vec3d StelMovementMgr::mountFrameToJ2000(const Vec3d& v) const
×
1514
{
1515
        switch (mountMode)
×
1516
        {
1517
                case MountAltAzimuthal:
×
1518
                        return core->altAzToJ2000(v, StelCore::RefractionOff); // TODO: Decide if RefractionAuto?
×
1519
                case MountEquinoxEquatorial:
×
1520
                        return core->equinoxEquToJ2000(v, StelCore::RefractionOff);
×
1521
                case MountGalactic:
×
1522
                        return core->galacticToJ2000(v);
×
1523
                case MountSupergalactic:
×
1524
                        return core->supergalacticToJ2000(v);
×
1525
        }
1526
        Q_ASSERT(0);
×
1527
        return Vec3d(0.);
1528
}
1529

1530
void StelMovementMgr::setViewDirectionJ2000(const Vec3d& v)
×
1531
{
1532
        core->lookAtJ2000(v, getViewUpVectorJ2000());
×
1533
        viewDirectionJ2000 = v;
×
1534
        viewDirectionMountFrame = j2000ToMountFrame(v);
×
1535
}
×
1536

1537
void StelMovementMgr::panView(const double deltaAz, const double deltaAlt)
×
1538
{
1539
        if (core->getCurrentProjectionType()==StelCore::ProjectionCylinderFill) // Inhibit any motion in this projection!
×
1540
        {
1541
                Vec3d tmp;
×
1542
                switch (mountMode){
×
1543
                        case MountEquinoxEquatorial:
×
1544
                                StelUtils::spheToRect(M_PI, 0., tmp);
×
1545
                                break;
×
1546
                        default:
×
1547
                                StelUtils::spheToRect(0., 0., tmp);
×
1548
                                break;
×
1549
                }
1550

1551
                setViewDirectionJ2000(mountFrameToJ2000(tmp));
×
1552
                setViewUpVector(Vec3d(0., 0., 1.));
×
1553

1554
                return;
×
1555
        }
1556

1557
        // DONE 2016-12 FIX UP VECTOR PROBLEM
1558
        // The function is called in update loops, so make a quick check for exit.
1559
        if ((deltaAz==0.) && (deltaAlt==0.))
×
1560
                return;
×
1561

1562
        double azVision, altVision;
1563
        StelUtils::rectToSphe(&azVision,&altVision,j2000ToMountFrame(viewDirectionJ2000));
×
1564
        // Az is counted from South, eastward.
1565

1566
         //qDebug() << "Azimuth:" << azVision * 180./M_PI << "Altitude:" << altVision * 180./M_PI << "Up.X=" << upVectorMountFrame.v[0] << "Up.Y=" << upVectorMountFrame.v[1] << "Up.Z=" << upVectorMountFrame.v[2];
1567

1568
        // if we are just looking into the pole, azimuth can hopefully be recovered from the customized up vector!
1569
        // When programmatically centering on a pole, we should have set a better up vector for |alt|>0.9*M_PI/2.
1570
        if (fabs(altVision)> 0.95* M_PI_2)
×
1571
        {
1572
                if (upVectorMountFrame.v[2] < 0.9)
×
1573
                {
1574
                         //qDebug() << "panView: Recovering azimuth...";
1575
                        azVision=atan2(-upVectorMountFrame.v[1], -upVectorMountFrame.v[0]);
×
1576
                        if (altVision < 0.)
×
1577
                                azVision+=M_PI;
×
1578
                }
1579
                // Remove these lines if all is OK.
1580
//                else
1581
//                {
1582
//                         qDebug() << "panView: UpVector:" << upVectorMountFrame.v[0] << "/" << upVectorMountFrame.v[1] << "/" << upVectorMountFrame.v[2] << "Cannot recover azimuth. Hope it's OK";
1583
//                }
1584
        }
1585

1586
        // if we are moving in the Azimuthal angle (left/right)
1587
        if (fabs(deltaAz)>1e-10)
×
1588
                azVision-=deltaAz;
×
1589
        if (fabs(deltaAlt)>1e-10)
×
1590
        {
1591
                //if (altVision+deltaAlt <= M_PI_2 && altVision+deltaAlt >= -M_PI_2)
1592
                        altVision+=deltaAlt;
×
1593
                //if (altVision+deltaAlt >  M_PI_2) altVision =  M_PI_2 - 0.000001; // Prevent bug: manual pans (keyboard or mouse!) can never really reach the zenith, but we can accept this.
1594
                //if (altVision+deltaAlt < -M_PI_2) altVision = -M_PI_2 + 0.000001;
1595
                if (altVision >  M_PI_2) altVision =  M_PI_2 - 0.000001; // Prevent bug: manual pans (keyboard or mouse!) can never really reach the zenith, but we can accept this.
×
1596
                if (altVision < -M_PI_2) altVision = -M_PI_2 + 0.000001;
×
1597
        }
1598

1599
        // recalc all the position variables
1600
        if ((fabs(deltaAz)>1e-10) || (fabs(deltaAlt)>1e-10))
×
1601
        {
1602
                setFlagTracking(false);
×
1603
                Vec3d tmp;
×
1604
                StelUtils::spheToRect(azVision, altVision, tmp);
×
1605
                setViewDirectionJ2000(mountFrameToJ2000(tmp));
×
1606
                if (fabs(altVision)>0.95*M_PI_2)
×
1607
                { // do something about zenith
1608
                        setViewUpVector(Vec3d(-cos(azVision), -sin(azVision), 0.) * (altVision>0. ? 1. : -1. ));
×
1609
                }
1610
                else
1611
                {
1612
                        setViewUpVector(Vec3d(0., 0., 1.));
×
1613
                }
1614
                emit currentDirectionChanged();
×
1615
        }
1616
}
1617

1618

1619
// Make the first screen position correspond to the second (useful for mouse dragging)
1620
void StelMovementMgr::dragView(int x1, int y1, int x2, int y2)
×
1621
{
1622
        if (dragTimeMode)
×
1623
        {
1624
                core->setTimeRate(0);
×
1625
                Vec3d v1, v2;
×
1626
                const StelProjectorP prj = core->getProjection(StelCore::FrameEquinoxEqu);
×
1627
                prj->unProject(x2,y2, v2);
×
1628
                prj->unProject(x1,y1, v1);
×
1629
                v1[2]=0; v1.normalize();
×
1630
                v2[2]=0; v2.normalize();
×
1631
                double angle = (v2^v1)[2];
×
1632
                double deltaDay = angle/(2.*M_PI)*core->getLocalSiderealDayLength();
×
1633
                core->setJD(core->getJD()+deltaDay);
×
1634
                addTimeDragPoint(x2, y2);
×
1635
        }
×
1636
        else
1637
        {
1638
                Vec3d tempvec1, tempvec2;
×
1639
                const StelProjectorP prj = core->getProjection(StelCore::FrameJ2000);
×
1640
                prj->unProject(x2,y2, tempvec2);
×
1641
                prj->unProject(x1,y1, tempvec1);
×
1642
                double az1, alt1, az2, alt2;
1643
                StelUtils::rectToSphe(&az1, &alt1, j2000ToMountFrame(tempvec1));
×
1644
                StelUtils::rectToSphe(&az2, &alt2, j2000ToMountFrame(tempvec2));
×
1645
                panView(az2-az1, alt1-alt2);
×
1646
        }
×
1647
        setFlagTracking(false);
×
1648
        setFlagLockEquPos(false);
×
1649
}
×
1650

1651

1652
// Update autoZoom if activated
1653
void StelMovementMgr::updateAutoZoom(double deltaTime)
×
1654
{
1655
        if (flagAutoZoom)
×
1656
        {
1657
                zoomMove.update(deltaTime);
×
1658
                double newFov = zoomMove.getValue();
×
1659
                if (zoomMove.finished())
×
1660
                        flagAutoZoom = 0;
×
1661
                setFov(newFov); // updates currentFov->don't use newFov later!
×
1662

1663
                // In case we have offset center, we want object still visible in center.
1664
                if (flagTracking && objectMgr->getWasSelected()) // vision vector locked on selected object
×
1665
                {
1666
                        Vec3d v, vUp;
×
1667
                        switch (mountMode)
×
1668
                        {
1669
                                case MountAltAzimuthal:
×
1670
                                        v = objectMgr->getSelectedObject()[0]->getAltAzPosAuto(core);
×
1671
                                        break;
×
1672
                                case MountEquinoxEquatorial:
×
1673
                                        v = objectMgr->getSelectedObject()[0]->getEquinoxEquatorialPosAuto(core);
×
1674
                                        break;
×
1675
                                case MountGalactic:
×
1676
                                        v = objectMgr->getSelectedObject()[0]->getGalacticPos(core);
×
1677
                                        break;
×
1678
                                case MountSupergalactic:
×
1679
                                        v = objectMgr->getSelectedObject()[0]->getSupergalacticPos(core);
×
1680
                                        break;
×
1681
                                default:
×
1682
                                        qWarning() << "StelMovementMgr: unexpected mountMode" << mountMode;
×
1683
                                        Q_ASSERT(0);
×
1684
                        }
1685

1686
                        double lat, lon; // general: longitudinal, latitudinal
1687
                        StelUtils::rectToSphe(&lon, &lat, v); // guaranteed to be normalized.
×
1688
                        // vUp could usually be (0/0/1) in most cases, unless |lat|==pi/2. We MUST build an adequate Up vector!
1689
                        if (fabs(lat)>0.9*M_PI_2)
×
1690
                        {
1691
                                vUp = Vec3d(-cos(lon), -sin(lon), 0.) * (lat>0. ? 1. : -1. );
×
1692
                        }
1693
                        else
1694
                                vUp.set(0.,0.,1.);
×
1695
                        double latOffset=static_cast<double>(core->getCurrentStelProjectorParams().viewportCenterOffset[1])*currentFov*M_PI_180;
×
1696
                        lat+=latOffset;
×
1697
                        StelUtils::spheToRect(lon, lat, v);
×
1698

1699
                        if (flagAutoMove)
×
1700
                        {
1701
                                move.aim=mountFrameToJ2000(v);
×
1702
                                move.aim.normalize();
×
1703
                                move.aim*=2.;
×
1704
                                move.aimUp=mountFrameToJ2000(vUp);
×
1705
                                move.aimUp.normalize();
×
1706
                        }
1707
                        else
1708
                        {
1709
                                setViewDirectionJ2000(mountFrameToJ2000(v));
×
1710
                                setViewUpVectorJ2000(mountFrameToJ2000(vUp));
×
1711
                        }
1712
                }
1713
        }
1714
}
×
1715

1716
// Zoom to the given field of view
1717
void StelMovementMgr::zoomTo(double aim_fov, float zoomDuration)
×
1718
{
1719
        zoomDuration /= movementsSpeedFactor;
×
1720
        zoomMove.setTarget(currentFov, aim_fov, zoomDuration);
×
1721
        flagAutoZoom = true;
×
1722
}
×
1723

1724
void StelMovementMgr::changeFov(double deltaFov)
×
1725
{
1726
        // if we are zooming in or out
1727
        if (fabs(deltaFov)>0)
×
1728
                setFov(currentFov + deltaFov);
×
1729
}
×
1730

1731
double StelMovementMgr::getAimFov(void) const
×
1732
{
1733
        return (flagAutoZoom ? zoomMove.getAim() : currentFov);
×
1734
}
1735

1736
// This is called e.g. when projection changes.
1737
// We clamp this to the user-set user_maxFov (e.g. for planetarium: 180°; GH #1836)
1738
void StelMovementMgr::setMaxFov(double max)
×
1739
{
1740
        maxFov = qMin(max, userMaxFov);
×
1741
        if (currentFov > maxFov)
×
1742
        {
1743
                setFov(maxFov);
×
1744
        }
1745
}
×
1746

1747
void StelMovementMgr::setUserMaxFov(double max)
×
1748
{
1749
        userMaxFov = qMin(360., max);
×
1750
        if (maxFov>userMaxFov)
×
1751
                setMaxFov(userMaxFov);
×
1752
        else
1753
        {
1754
                const float prjMaxFov = StelApp::getInstance().getCore()->getProjection(StelProjector::ModelViewTranformP(new StelProjector::Mat4dTransform(Mat4d::identity(),Mat4d::identity())))->getMaxFov();
×
1755
                setMaxFov(qMin(userMaxFov, static_cast<double>(prjMaxFov)));
×
1756
        }
1757
        StelApp::immediateSave("navigation/max_fov", userMaxFov);
×
1758
        emit userMaxFovChanged(userMaxFov);
×
1759
}
×
1760

1761
void StelMovementMgr::moveViewport(double offsetX, double offsetY, const float duration)
×
1762
{
1763
        //clamp to valid range
1764
        offsetX = qBound(-50., offsetX, 50.);
×
1765
        offsetY = qBound(-50., offsetY, 50.);
×
1766

1767
        Vec2d oldTargetViewportOffset = targetViewportOffset;
×
1768
        targetViewportOffset.set(offsetX, offsetY);
×
1769

1770
        if(fabs(offsetX - oldTargetViewportOffset[0]) > 1e-10)
×
1771
        {
1772
                StelApp::immediateSave("projection/viewport_center_offset_x", offsetX);
×
1773
                emit viewportHorizontalOffsetTargetChanged(offsetX);
×
1774
        }
1775
        if(fabs(offsetY - oldTargetViewportOffset[1]) > 1e-10)
×
1776
        {
1777
                StelApp::immediateSave("projection/viewport_center_offset_y", offsetY);
×
1778
                emit viewportVerticalOffsetTargetChanged(offsetY);
×
1779
        }
1780

1781
        if (duration<=0.0f)
×
1782
        {
1783
                //avoid using the timeline to minimize overhead
1784
                core->setViewportOffset(offsetX, offsetY);
×
1785
                return;
×
1786
        }
1787

1788
        // Frame will now be 0..100, and we must interpolate in handleViewportOffsetMovement(frame) between old and new offsets.
1789
        oldViewportOffset.set(core->getViewportHorizontalOffset(), core->getViewportVerticalOffset());
×
1790

1791
        viewportOffsetTimeline->stop();
×
1792
        viewportOffsetTimeline->setDuration(static_cast<int>(1000.f*duration));
×
1793

1794
        viewportOffsetTimeline->start();
×
1795
}
1796

1797
// slot which is connected to the viewportOffsetTimeline and does the actual updates.
1798
void StelMovementMgr::handleViewportOffsetMovement(qreal value)
×
1799
{
1800
        // value is always 0...1
1801
        double offsetX=oldViewportOffset.v[0] + (targetViewportOffset.v[0]-oldViewportOffset.v[0])*value;
×
1802
        double offsetY=oldViewportOffset.v[1] + (targetViewportOffset.v[1]-oldViewportOffset.v[1])*value;
×
1803
        core->setViewportOffset(offsetX, offsetY);
×
1804
}
×
1805

1806
void StelMovementMgr::smoothPan(double deltaX, double deltaY, double ptime, bool s)
×
1807
{
1808
        flagCustomPan = s;
×
1809
        if (s)
×
1810
        {
1811
                rateX = deltaX/ptime; // degrees per second
×
1812
                rateY = deltaY/ptime; // degrees per second
×
1813
                setFlagTracking(false);
×
1814
                setFlagLockEquPos(false);
×
1815
        }
1816
        else
1817
                deltaAz = deltaAlt = 0.0;
×
1818
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc