3
* Copyright (C) 2007 Fabien Chereau
5
* This program is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU General Public License
7
* as published by the Free Software Foundation; either version 2
8
* of the License, or (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20
#include "StelMovementMgr.hpp"
21
#include "StelObjectMgr.hpp"
22
#include "StelApp.hpp"
23
#include "StelCore.hpp"
24
#include "StelNavigator.hpp"
25
#include "StelUtils.hpp"
28
#include <QTextStream>
33
StelMovementMgr::StelMovementMgr(StelCore* acore) : core(acore),
34
flagLockEquPos(false),
36
isMouseMovingHoriz(false),
37
isMouseMovingVert(false),
38
flagEnableMouseNavigation(true),
39
keyMoveSpeed(0.00025),
45
flagAutoZoomOutResetsDirection(0)
47
setObjectName("StelMovementMgr");
51
StelMovementMgr::~StelMovementMgr()
55
void StelMovementMgr::init()
57
QSettings* conf = StelApp::getInstance().getSettings();
60
flagEnableMoveAtScreenEdge = conf->value("navigation/flag_enable_move_at_screen_edge",false).toBool();
61
mouseZoomSpeed = conf->value("navigation/mouse_zoom",30).toInt();
62
flagEnableZoomKeys = conf->value("navigation/flag_enable_zoom_keys").toBool();
63
flagEnableMoveKeys = conf->value("navigation/flag_enable_move_keys").toBool();
64
keyMoveSpeed = conf->value("navigation/move_speed",0.0004).toDouble();
65
keyZoomSpeed = conf->value("navigation/zoom_speed", 0.0004).toDouble();
66
autoMoveDuration = conf->value ("navigation/auto_move_duration",1.5).toDouble();
67
flagManualZoom = conf->value("navigation/flag_manual_zoom").toBool();
68
flagAutoZoomOutResetsDirection = conf->value("navigation/auto_zoom_out_resets_direction", true).toBool();
69
flagEnableMouseNavigation = conf->value("navigation/flag_enable_mouse_navigation",true).toBool();
73
initFov = conf->value("navigation/init_fov",60.).toDouble();
77
bool StelMovementMgr::handleMouseMoves(int x, int y, Qt::MouseButtons b)
79
// Turn if the mouse is at the edge of the screen unless config asks otherwise
80
if (flagEnableMoveAtScreenEdge)
85
isMouseMovingHoriz = true;
87
else if (x >= core->getProjection2d()->getViewportWidth() - 2)
90
isMouseMovingHoriz = true;
92
else if (isMouseMovingHoriz)
95
isMouseMovingHoriz = false;
101
isMouseMovingVert = true;
103
else if (y >= core->getProjection2d()->getViewportHeight() - 2)
106
isMouseMovingVert = true;
108
else if (isMouseMovingVert)
111
isMouseMovingVert = false;
115
if (isDragging && flagEnableMouseNavigation)
117
if (hasDragged || (std::sqrt((double)((x-previousX)*(x-previousX) +(y-previousY)*(y-previousY)))>4.))
120
setFlagTracking(false);
121
dragView(previousX, previousY, x, y);
131
void StelMovementMgr::handleKeys(QKeyEvent* event)
133
if (event->type() == QEvent::KeyPress)
135
// Direction and zoom deplacements
136
switch (event->key())
139
turnLeft(true); break;
141
turnRight(true); break;
143
if (event->modifiers().testFlag(Qt::ControlModifier)) zoomIn(true);
147
if (event->modifiers().testFlag(Qt::ControlModifier)) zoomOut(true);
152
case Qt::Key_PageDown:
153
zoomOut(true); break;
160
// When a deplacement key is released stop mooving
161
switch (event->key())
164
turnLeft(false); break;
166
turnRight(false); break;
176
zoomIn(false); break;
177
case Qt::Key_PageDown:
178
zoomOut(false); break;
186
//! Handle mouse wheel events.
187
void StelMovementMgr::handleMouseWheel(QWheelEvent* event)
189
if (flagEnableMouseNavigation==false)
191
int numDegrees = event->delta() / 8;
192
int numSteps = numDegrees / 15;
193
zoomTo(getAimFov()-mouseZoomSpeed*numSteps*getAimFov()/60., 0.2);
197
void StelMovementMgr::handleMouseClicks(QMouseEvent* event)
199
switch (event->button())
201
case Qt::RightButton : break;
202
case Qt::LeftButton :
203
if (event->type()==QEvent::MouseButtonPress)
207
previousX = event->x();
208
previousY = event->y();
228
if (event->type()==QEvent::MouseButtonRelease)
230
if (StelApp::getInstance().getStelObjectMgr().getWasSelected())
232
moveTo(StelApp::getInstance().getStelObjectMgr().getSelectedObject()[0]->getEquinoxEquatorialPos(core->getNavigator()),autoMoveDuration);
233
setFlagTracking(true);
242
/*************************************************************************
243
The selected objects changed, follow it it we were already following another one
244
*************************************************************************/
245
void StelMovementMgr::selectedObjectChangeCallBack(StelModuleSelectAction action)
247
// If an object was selected keep the earth following
248
if (StelApp::getInstance().getStelObjectMgr().getWasSelected())
250
if (getFlagTracking())
251
setFlagLockEquPos(true);
252
setFlagTracking(false);
256
void StelMovementMgr::turnRight(bool s)
258
if (s && flagEnableMoveKeys)
261
setFlagTracking(false);
262
setFlagLockEquPos(false);
268
void StelMovementMgr::turnLeft(bool s)
270
if (s && flagEnableMoveKeys)
273
setFlagTracking(false);
274
setFlagLockEquPos(false);
280
void StelMovementMgr::turnUp(bool s)
282
if (s && flagEnableMoveKeys)
285
setFlagTracking(false);
286
setFlagLockEquPos(false);
292
void StelMovementMgr::turnDown(bool s)
294
if (s && flagEnableMoveKeys)
297
setFlagTracking(false);
298
setFlagLockEquPos(false);
305
void StelMovementMgr::zoomIn(bool s)
307
if (flagEnableZoomKeys)
308
deltaFov = -1*(s!=0);
311
void StelMovementMgr::zoomOut(bool s)
313
if (flagEnableZoomKeys)
318
// Increment/decrement smoothly the vision field and position
319
void StelMovementMgr::updateMotion(double deltaTime)
321
const StelProjectorP proj = core->getProjection(StelCore::FrameJ2000);
323
updateVisionVector(deltaTime);
325
// the more it is zoomed, the lower the moving speed is (in angle)
326
double depl=keyMoveSpeed*deltaTime*1000*currentFov;
327
double deplzoom=keyZoomSpeed*deltaTime*1000*proj->deltaZoom(currentFov*(M_PI/360.0))*(360.0/M_PI);
362
deltaFov = -deplzoom*5;
363
if (deltaFov<-0.15*currentFov)
364
deltaFov = -0.15*currentFov;
370
deltaFov = deplzoom*5;
380
panView(deltaAz, deltaAlt);
381
updateAutoZoom(deltaTime);
385
// Go and zoom to the selected object.
386
void StelMovementMgr::autoZoomIn(float moveDuration, bool allowManualZoom)
388
if (!StelApp::getInstance().getStelObjectMgr().getWasSelected())
391
float manualMoveDuration;
393
if (!getFlagTracking())
395
setFlagTracking(true);
396
moveTo(StelApp::getInstance().getStelObjectMgr().getSelectedObject()[0]->getEquinoxEquatorialPos(core->getNavigator()), moveDuration, false, 1);
397
manualMoveDuration = moveDuration;
401
// faster zoom in manual zoom mode once object is centered
402
manualMoveDuration = moveDuration*.66f;
405
if( allowManualZoom && flagManualZoom )
407
// if manual zoom mode, user can zoom in incrementally
408
float newfov = currentFov*0.5f;
409
zoomTo(newfov, manualMoveDuration);
413
float satfov = StelApp::getInstance().getStelObjectMgr().getSelectedObject()[0]->getSatellitesFov(core->getNavigator());
415
if (satfov>0.0 && currentFov*0.9>satfov)
416
zoomTo(satfov, moveDuration);
419
float closefov = StelApp::getInstance().getStelObjectMgr().getSelectedObject()[0]->getCloseViewFov(core->getNavigator());
420
if (currentFov>closefov)
421
zoomTo(closefov, moveDuration);
427
// Unzoom and go to the init position
428
void StelMovementMgr::autoZoomOut(float moveDuration, bool full)
430
StelNavigator* nav = core->getNavigator();
432
if (StelApp::getInstance().getStelObjectMgr().getWasSelected() && !full)
434
// If the selected object has satellites, unzoom to satellites view
435
// unless specified otherwise
436
float satfov = StelApp::getInstance().getStelObjectMgr().getSelectedObject()[0]->getSatellitesFov(core->getNavigator());
438
if (satfov>0.0 && currentFov<=satfov*0.9)
440
zoomTo(satfov, moveDuration);
444
// If the selected object is part of a Planet subsystem (other than sun),
445
// unzoom to subsystem view
446
satfov = StelApp::getInstance().getStelObjectMgr().getSelectedObject()[0]->getParentSatellitesFov((core->getNavigator()));
447
if (satfov>0.0 && currentFov<=satfov*0.9)
449
zoomTo(satfov, moveDuration);
454
zoomTo(initFov, moveDuration);
455
if (flagAutoZoomOutResetsDirection)
456
moveTo(nav->getInitViewingDirection(), moveDuration, true, -1);
457
setFlagTracking(false);
458
setFlagLockEquPos(false);
462
void StelMovementMgr::setFlagTracking(bool b)
464
if(!b || !StelApp::getInstance().getStelObjectMgr().getWasSelected())
470
moveTo(StelApp::getInstance().getStelObjectMgr().getSelectedObject()[0]->getEquinoxEquatorialPos(core->getNavigator()), getAutoMoveDuration());
476
////////////////////////////////////////////////////////////////////////////////
477
// Move to the given equatorial position
478
void StelMovementMgr::moveTo(const Vec3d& _aim, float moveDuration, bool _localPos, int zooming)
480
StelNavigator* nav = core->getNavigator();
481
zoomingMode = zooming;
483
move.aim.normalize();
487
move.start=nav->getAltAzVisionDirection();
491
move.start=nav->getEquinoxEquVisionDirection();
493
move.start.normalize();
494
move.speed=1.f/(moveDuration*1000);
496
move.localPos = _localPos;
501
////////////////////////////////////////////////////////////////////////////////
502
void StelMovementMgr::updateVisionVector(double deltaTime)
504
StelNavigator* nav = core->getNavigator();
507
double ra_aim, de_aim, ra_start, de_start, ra_now, de_now;
509
if( zoomingMode == 1 && StelApp::getInstance().getStelObjectMgr().getWasSelected())
511
// if zooming in, object may be moving so be sure to zoom to latest position
512
move.aim = StelApp::getInstance().getStelObjectMgr().getSelectedObject()[0]->getEquinoxEquatorialPos(core->getNavigator());
513
move.aim.normalize();
517
// Use a smooth function
521
if (zoomingMode == 1)
529
c = 1 - pow(1.-1.11*(move.coef),3);
532
else if(zoomingMode == -1)
534
if( move.coef < 0.1 )
536
// keep in view at first as zoom out
539
/* could track as moves too, but would need to know if start was actually
540
a zoomed in view on the object or an extraneous zoom out command
542
move.start=equinoxEquToAltAz(selected.getEquinoxEquatorialPos(this));
544
move.start=selected.getEquinoxEquatorialPos(this);
546
move.start.normalize();
552
c = pow(1.11*(move.coef-.1),3);
555
else c = std::atan(smooth * 2.*move.coef-smooth)/std::atan(smooth)/2+0.5;
560
StelUtils::rectToSphe(&ra_aim, &de_aim, move.aim);
561
StelUtils::rectToSphe(&ra_start, &de_start, move.start);
565
StelUtils::rectToSphe(&ra_aim, &de_aim, nav->equinoxEquToAltAz(move.aim));
566
StelUtils::rectToSphe(&ra_start, &de_start, nav->equinoxEquToAltAz(move.start));
569
// Trick to choose the good moving direction and never travel on a distance > PI
570
if (ra_aim-ra_start > M_PI)
574
else if (ra_aim-ra_start < -M_PI)
579
de_now = de_aim*c + de_start*(1. - c);
580
ra_now = ra_aim*c + ra_start*(1. - c);
583
StelUtils::spheToRect(ra_now, de_now, tmp);
584
nav->setEquinoxEquVisionDirection(nav->altAzToEquinoxEqu(tmp));
586
move.coef+=move.speed*deltaTime*1000;
592
nav->setAltAzVisionDirection(move.aim);
596
nav->setEquinoxEquVisionDirection(move.aim);
602
if (flagTracking && StelApp::getInstance().getStelObjectMgr().getWasSelected()) // Equatorial vision vector locked on selected object
604
nav->setEquinoxEquVisionDirection(StelApp::getInstance().getStelObjectMgr().getSelectedObject()[0]->getEquinoxEquatorialPos(core->getNavigator()));
608
if (flagLockEquPos) // Equatorial vision vector locked
610
// Recalc local vision vector
611
nav->setAltAzVisionDirection(nav->equinoxEquToAltAz(nav->getEquinoxEquVisionDirection()));
613
else // Local vision vector locked
615
// Recalc equatorial vision vector
616
nav->setEquinoxEquVisionDirection(nav->altAzToEquinoxEqu(nav->getAltAzVisionDirection()));
623
////////////////////////////////////////////////////////////////////////////////
624
void StelMovementMgr::panView(double deltaAz, double deltaAlt)
626
StelNavigator* nav = core->getNavigator();
627
double azVision, altVision;
629
if( nav->getViewingMode() == StelNavigator::ViewEquator) StelUtils::rectToSphe(&azVision,&altVision,nav->getEquinoxEquVisionDirection());
630
else StelUtils::rectToSphe(&azVision,&altVision,nav->getAltAzVisionDirection());
632
// if we are moving in the Azimuthal angle (left/right)
633
if (deltaAz) azVision-=deltaAz;
636
if (altVision+deltaAlt <= M_PI_2 && altVision+deltaAlt >= -M_PI_2) altVision+=deltaAlt;
637
if (altVision+deltaAlt > M_PI_2) altVision = M_PI_2 - 0.000001; // Prevent bug
638
if (altVision+deltaAlt < -M_PI_2) altVision = -M_PI_2 + 0.000001; // Prevent bug
641
// recalc all the position variables
642
if (deltaAz || deltaAlt)
644
setFlagTracking(false);
645
if( nav->getViewingMode() == StelNavigator::ViewEquator)
648
StelUtils::spheToRect(azVision, altVision, tmp);
649
nav->setAltAzVisionDirection(nav->equinoxEquToAltAz(tmp));
654
StelUtils::spheToRect(azVision, altVision, tmp);
655
// Calc the equatorial coordinate of the direction of vision wich was in Altazimuthal coordinate
656
nav->setEquinoxEquVisionDirection(nav->altAzToEquinoxEqu(tmp));
662
//! Make the first screen position correspond to the second (useful for mouse dragging)
663
void StelMovementMgr::dragView(int x1, int y1, int x2, int y2)
665
StelNavigator* nav = core->getNavigator();
667
Vec3d tempvec1, tempvec2;
668
double az1, alt1, az2, alt2;
669
const StelProjectorP prj = nav->getViewingMode()==StelNavigator::ViewHorizon ? core->getProjection(StelCore::FrameAltAz) :
670
core->getProjection(StelCore::FrameEquinoxEqu);
672
//johannes: StelApp already gives appropriate x/y coordinates
673
// proj->unProject(x2,proj->getViewportHeight()-y2, tempvec2);
674
// proj->unProject(x1,proj->getViewportHeight()-y1, tempvec1);
675
prj->unProject(x2,y2, tempvec2);
676
prj->unProject(x1,y1, tempvec1);
677
StelUtils::rectToSphe(&az1, &alt1, tempvec1);
678
StelUtils::rectToSphe(&az2, &alt2, tempvec2);
679
panView(az2-az1, alt1-alt2);
680
setFlagTracking(false);
681
setFlagLockEquPos(false);
685
// Update autoZoom if activated
686
void StelMovementMgr::updateAutoZoom(double deltaTime)
690
// Use a smooth function
693
if( zoomMove.start > zoomMove.aim )
695
// slow down as approach final view
696
c = 1 - (1-zoomMove.coef)*(1-zoomMove.coef)*(1-zoomMove.coef);
700
// speed up as leave zoom target
701
c = (zoomMove.coef)*(zoomMove.coef)*(zoomMove.coef);
704
setFov(zoomMove.start + (zoomMove.aim - zoomMove.start) * c);
705
zoomMove.coef+=zoomMove.speed*deltaTime*1000;
706
if (zoomMove.coef>=1.)
709
setFov(zoomMove.aim);
714
// Zoom to the given field of view
715
void StelMovementMgr::zoomTo(double aim_fov, float moveDuration)
717
zoomMove.aim=aim_fov;
718
zoomMove.start=currentFov;
719
zoomMove.speed=1.f/(moveDuration*1000);
724
void StelMovementMgr::changeFov(double deltaFov)
726
// if we are zooming in or out
728
setFov(currentFov + deltaFov);
731
double StelMovementMgr::getAimFov(void) const
733
return (flagAutoZoom ? zoomMove.aim : currentFov);
736
void StelMovementMgr::setMaxFov(double max)
739
if (currentFov > max)