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
getValue() const49 double Smoother::getValue() const
50 {
51 double k = easingCurve.valueForProgress(progress / duration);
52 return start * (1 - k) + aim * k;
53 }
54
setTarget(double start,double aim,double duration)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
update(double dt)71 void Smoother::update(double dt)
72 {
73 progress = qMin(progress + dt, duration);
74 }
75
finished() const76 bool Smoother::finished() const
77 {
78 return progress >= duration;
79 }
80
StelMovementMgr(StelCore * acore)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
~StelMovementMgr()140 StelMovementMgr::~StelMovementMgr()
141 {
142 if (viewportOffsetTimeline)
143 {
144 delete viewportOffsetTimeline;
145 viewportOffsetTimeline=Q_NULLPTR;
146 }
147 }
148
init()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
192 // 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.
193 // examples: 1/0 ->0 NORTH is bottom
194 // -1/0 ->180 SOUTH is bottom
195 // 0/-1 -> 90 EAST is bottom
196 // 0/1 ->270 WEST is bottom
197 Vec3f tmp(conf->value("navigation/init_view_pos", "1,0,0").toString());
198 //qDebug() << "initViewPos" << tmp[0] << "/" << tmp[1] << "/" << tmp[2];
199 if (tmp[2]>=1)
200 {
201 //qDebug() << "Special zenith setup:";
202 setViewDirectionJ2000(mountFrameToJ2000(Vec3d(0., 0., 1.)));
203 initViewPos.set(0., 0., 1.);
204
205 // It is not good to code 0/0/1 as view vector: bottom azimuth is undefined. Use default-south:
206 if ((tmp[0]==0.f) && (tmp[1]==0.f))
207 tmp[0]=-1.;
208
209 upVectorMountFrame.set(static_cast<double>(tmp[0]), static_cast<double>(tmp[1]), 0.);
210 upVectorMountFrame.normalize();
211 initViewUp=upVectorMountFrame;
212 //qDebug() << "InitViewUp: " << initViewUp;
213 }
214 else
215 {
216 //qDebug() << "simpler view vectors...";
217 //qDebug() << " initViewPos becomes " << tmp[0] << "/" << tmp[1] << "/" << tmp[2];
218 initViewPos = tmp.toVec3d();
219 //qDebug() << " initViewPos is " << initViewPos[0] << "/" << initViewPos[1] << "/" << initViewPos[2];
220 viewDirectionJ2000 = core->altAzToJ2000(initViewPos, StelCore::RefractionOff);
221 //qDebug() << "viewDirectionJ2000: " << viewDirectionJ2000[0] << "/" << viewDirectionJ2000[1] << "/" << viewDirectionJ2000[2];
222 setViewDirectionJ2000(viewDirectionJ2000);
223 //qDebug() << " up2000 initViewUp becomes " << initViewUp[0] << "/" << initViewUp[1] << "/" << initViewUp[2];
224 setViewUpVector(initViewUp);
225
226 //qDebug() << " upVectorMountFrame becomes " << upVectorMountFrame[0] << "/" << upVectorMountFrame[1] << "/" << upVectorMountFrame[2];
227 }
228
229
230 QString movementGroup = N_("Movement and Selection");
231 addAction("actionSwitch_Equatorial_Mount", N_("Miscellaneous"), N_("Switch between equatorial and azimuthal mount"), "equatorialMount", "Ctrl+M");
232 addAction("actionGoto_Selected_Object", movementGroup, N_("Center on selected object"), "tracking", "Space");
233 addAction("actionGoto_Deselection", movementGroup, N_("Deselect the selected object"), "deselection()", "Ctrl+Space");
234 addAction("actionZoom_In_Auto", movementGroup, N_("Zoom in on selected object"), "autoZoomIn()", "/");
235 addAction("actionZoom_Out_Auto", movementGroup, N_("Zoom out"), "autoZoomOut()", "\\");
236 // AW: Same behaviour has action "actionGoto_Selected_Object" by the fact (Is it for backward compatibility?)
237 addAction("actionSet_Tracking", movementGroup, N_("Track object"), "tracking", "T");
238 // Implementation of quick turning to different directions (examples: CdC, HNSKY)
239 addAction("actionLook_Towards_East", movementGroup, N_("Look towards East"), "lookEast()", "Shift+E");
240 addAction("actionLook_Towards_West", movementGroup, N_("Look towards West"), "lookWest()", "Shift+W");
241 addAction("actionLook_Towards_North", movementGroup, N_("Look towards North"), "lookNorth()", "Shift+N");
242 addAction("actionLook_Towards_South", movementGroup, N_("Look towards South"), "lookSouth()", "Shift+S");
243 addAction("actionLook_Towards_Zenith", movementGroup, N_("Look towards Zenith"), "lookZenith()", "Shift+Z");
244 // Additional hooks
245 addAction("actionLook_Towards_NCP", movementGroup, N_("Look towards North Celestial pole"), "lookTowardsNCP()", "Alt+Shift+N");
246 addAction("actionLook_Towards_SCP", movementGroup, N_("Look towards South Celestial pole"), "lookTowardsSCP()", "Alt+Shift+S");
247 // Field of view
248 // The feature was moved from FOV plugin
249 bindingFOVActions();
250
251 viewportOffsetTimeline=new QTimeLine(1000, this);
252 viewportOffsetTimeline->setFrameRange(0, 100);
253 connect(viewportOffsetTimeline, SIGNAL(valueChanged(qreal)), this, SLOT(handleViewportOffsetMovement(qreal)));
254 targetViewportOffset.set(core->getViewportHorizontalOffset(), core->getViewportVerticalOffset());
255 }
256
bindingFOVActions()257 void StelMovementMgr::bindingFOVActions()
258 {
259 StelActionMgr* actionMgr = StelApp::getInstance().getStelActionManager();
260 QString confval, tfov, fovGroup = N_("Field of View"), fovText = q_("Set predefined FOV");
261 QList<float> defaultFOV = { 0.5f, 180.f, 90.f, 60.f, 45.f, 20.f, 10.f, 5.f, 2.f, 1.f };
262 for (int i = 0; i < defaultFOV.size(); ++i)
263 {
264 confval = QString("fov/quick_fov_%1").arg(i);
265 const double cfov = conf->value(confval, defaultFOV.at(i)).toDouble();
266 tfov = QString::number(cfov, 'f', 2);
267 QString actionName = QString("actionSet_FOV_%1").arg(i);
268 QString actionDescription = QString("%1 #%2 (%3%4)").arg(fovText, QString::number(i), tfov, QChar(0x00B0));
269 StelAction* action = actionMgr->findAction(actionName);
270 if (action!=Q_NULLPTR)
271 actionMgr->findAction(actionName)->setText(actionDescription);
272 else
273 addAction(actionName, fovGroup, actionDescription, this, [=](){setFOVDeg(static_cast<float>(cfov));}, QString("Ctrl+Alt+%1").arg(i));
274 }
275 }
276
setEquatorialMount(bool b)277 void StelMovementMgr::setEquatorialMount(bool b)
278 {
279 setMountMode(b ? MountEquinoxEquatorial : MountAltAzimuthal);
280
281 if (getFlagIndicationMountMode())
282 {
283 QString mode = qc_("Equatorial mount", "mount mode");
284 if (!b)
285 mode = qc_("Alt-azimuth mount", "mount mode");
286
287 if (lastMessageID)
288 GETSTELMODULE(LabelMgr)->deleteLabel(lastMessageID);
289
290 StelProjector::StelProjectorParams projectorParams = StelApp::getInstance().getCore()->getCurrentStelProjectorParams();
291 StelPainter painter(StelApp::getInstance().getCore()->getProjection2d());
292 int yPositionOffset = qRound(projectorParams.viewportXywh[3]*projectorParams.viewportCenterOffset[1]);
293 int xPosition = qRound(projectorParams.viewportCenter[0] - painter.getFontMetrics().boundingRect(mode).width()/2);
294 int yPosition = qRound(projectorParams.viewportCenter[1] - yPositionOffset - painter.getFontMetrics().height()/2);
295 lastMessageID = GETSTELMODULE(LabelMgr)->labelScreen(mode, xPosition, yPosition, true, StelApp::getInstance().getScreenFontSize() + 3, "#99FF99", true, 2000);
296 }
297 }
298
setMountMode(MountMode m)299 void StelMovementMgr::setMountMode(MountMode m)
300 {
301 mountMode = m;
302 setViewDirectionJ2000(viewDirectionJ2000);
303 // TODO: Decide whether re-setting Up-vector is required here.
304 //setViewUpVector(Vec3d(0., 0., 1.));
305 //setViewUpVectorJ2000(Vec3d(0., 0., 1.)); // Looks wrong on start.
306 emit equatorialMountChanged(m==MountEquinoxEquatorial);
307 }
308
setFlagLockEquPos(bool b)309 void StelMovementMgr::setFlagLockEquPos(bool b)
310 {
311 flagLockEquPos=b;
312 }
313
setViewUpVectorJ2000(const Vec3d & up)314 void StelMovementMgr::setViewUpVectorJ2000(const Vec3d& up)
315 {
316 //qDebug() << "setViewUpvectorJ2000()";
317 upVectorMountFrame = j2000ToMountFrame(up);
318 }
319
320 // For simplicity you can set this directly. Take care when looking into poles like zenith in altaz mode:
321 // 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
setViewUpVector(const Vec3d & up)322 void StelMovementMgr::setViewUpVector(const Vec3d& up)
323 {
324 //qDebug() << "setViewUpvector()";
325 upVectorMountFrame = up;
326 }
327
getViewUpVectorJ2000() const328 Vec3d StelMovementMgr::getViewUpVectorJ2000() const
329 {
330 return mountFrameToJ2000(upVectorMountFrame);
331 }
332
handleMouseMoves(int x,int y,Qt::MouseButtons)333 bool StelMovementMgr::handleMouseMoves(int x, int y, Qt::MouseButtons)
334 {
335 // Turn if the mouse is at the edge of the screen unless config asks otherwise
336 if (flagEnableMoveAtScreenEdge)
337 {
338 if (x <= 1)
339 {
340 turnLeft(true);
341 isMouseMovingHoriz = true;
342 }
343 else if (x >= core->getProjection2d()->getViewportWidth() - 2)
344 {
345 turnRight(true);
346 isMouseMovingHoriz = true;
347 }
348 else if (isMouseMovingHoriz)
349 {
350 turnLeft(false);
351 isMouseMovingHoriz = false;
352 }
353
354 if (y <= 1)
355 {
356 turnUp(true);
357 isMouseMovingVert = true;
358 }
359 else if (y >= core->getProjection2d()->getViewportHeight() - 2)
360 {
361 turnDown(true);
362 isMouseMovingVert = true;
363 }
364 else if (isMouseMovingVert)
365 {
366 turnUp(false);
367 isMouseMovingVert = false;
368 }
369 }
370
371
372 if (isDragging && flagEnableMouseNavigation)
373 {
374 if (hasDragged || (sqrtf(static_cast<float>((x-previousX)*(x-previousX) +(y-previousY)*(y-previousY)))>dragTriggerDistance))
375 {
376 hasDragged = true;
377 setFlagTracking(false);
378 dragView(previousX, previousY, x, y);
379 previousX = x;
380 previousY = y;
381 // We can hardly use the mouse exactly enough to go to the zenith/pole. Any mouse motion can safely reset the simplified up vector.
382 //qDebug() << "handleMouseMoves: resetting Up vector.";
383 setViewUpVector(Vec3d(0., 0., 1.));
384 return true;
385 }
386 }
387 return false;
388 }
389
getCallOrder(StelModuleActionName actionName) const390 double StelMovementMgr::getCallOrder(StelModuleActionName actionName) const
391 {
392 // allow plugins to intercept keys by using a lower number than this!
393 if (actionName == StelModule::ActionHandleKeys)
394 return 5;
395 return 0;
396 }
397
398
399
handleKeys(QKeyEvent * event)400 void StelMovementMgr::handleKeys(QKeyEvent* event)
401 {
402 GimbalOrbit *gimbal=Q_NULLPTR;
403 #ifdef USE_GIMBAL_ORBIT
404 StelCore *core=StelApp::getInstance().getCore();
405 Planet* obsPlanet= core->getCurrentPlanet().data();
406 if (obsPlanet->getPlanetType()==Planet::isObserver)
407 {
408 gimbal=static_cast<GimbalOrbit*>(obsPlanet->getOrbit());
409 }
410 #endif
411 if (event->type() == QEvent::KeyPress)
412 {
413 // qDebug() << "Modifiers:" << event->modifiers();
414 // FIXME: Alt modifier seems problematic. The keys to modify distance in an observer gimbal seem to
415 // collide with operating system hotkeys. Using Alt5/Alt6 is experimental just to have "some" working solution.
416 // Direction and zoom deplacements
417 switch (event->key())
418 {
419 case Qt::Key_Left:
420 if (gimbal && event->modifiers().testFlag(Qt::AltModifier)){
421 gimbal->addToLongitude(-5.);
422 } else {
423 turnLeft(true);
424 }
425 break;
426 case Qt::Key_Right:
427 if (gimbal && event->modifiers().testFlag(Qt::AltModifier)){
428 gimbal->addToLongitude(5.);
429 } else
430 turnRight(true);
431 break;
432 case Qt::Key_Up:
433 if (gimbal && event->modifiers().testFlag(Qt::AltModifier)){
434 gimbal->addToLatitude(5.);
435 }
436 else if (event->modifiers().testFlag(Qt::ControlModifier)){
437 zoomIn(true);
438 } else {
439 turnUp(true);
440 }
441 break;
442 case Qt::Key_Down:
443 if (gimbal && event->modifiers().testFlag(Qt::AltModifier)){
444 gimbal->addToLatitude(-5.);
445 }
446 else if (event->modifiers().testFlag(Qt::ControlModifier)) {
447 zoomOut(true);
448 } else {
449 turnDown(true);
450 }
451 break;
452 case Qt::Key_PageUp:
453 case Qt::Key_multiply:
454 zoomIn(true);
455 break;
456 case Qt::Key_PageDown:
457 case Qt::Key_division:
458 zoomOut(true);
459 break;
460 case Qt::Key_End:
461 if (gimbal && event->modifiers().testFlag(Qt::AltModifier))
462 {
463 gimbal->addToDistance(gimbal->getDistance()*0.05);
464 }
465 break;
466 case Qt::Key_Home:
467 if (gimbal && event->modifiers().testFlag(Qt::AltModifier))
468 {
469 gimbal->addToDistance(-gimbal->getDistance()*0.05);
470 }
471 break;
472 case Qt::Key_Shift:
473 moveSlow(true); break;
474 default:
475 return;
476 }
477 }
478 else
479 {
480 // When a deplacement key is released stop moving
481 switch (event->key())
482 {
483 case Qt::Key_Left:
484 turnLeft(false); break;
485 case Qt::Key_Right:
486 turnRight(false); break;
487 case Qt::Key_Up:
488 zoomIn(false);
489 turnUp(false);
490 break;
491 case Qt::Key_Down:
492 zoomOut(false);
493 turnDown(false);
494 break;
495 case Qt::Key_PageUp:
496 zoomIn(false); break;
497 case Qt::Key_PageDown:
498 zoomOut(false); break;
499 case Qt::Key_Shift:
500 moveSlow(false); break;
501 case Qt::Key_Control:
502 // This can be all that is seen for anything with control, so stop them all.
503 // This is true for 4.8.1
504 turnRight(false);
505 turnLeft(false);
506 zoomIn(false);
507 zoomOut(false);
508 turnDown(false);
509 turnUp(false);
510 dragTimeMode=false;
511 break;
512 default:
513 return;
514 }
515 }
516 event->accept();
517 }
518
519 //! Handle mouse wheel events.
handleMouseWheel(QWheelEvent * event)520 void StelMovementMgr::handleMouseWheel(QWheelEvent* event)
521 {
522 if (flagEnableMouseZooming==false)
523 return;
524
525 // This managed only vertical wheel events.
526 // However, Alt-wheel switches this to horizontal, so allow alt-wheel and handle angles properly!
527 const double numSteps = (event->angleDelta().x() + event->angleDelta().y()) / 120.;
528
529 if (event->modifiers() & Qt::ControlModifier)
530 {
531 if ((event->modifiers() & Qt::AltModifier) && (event->modifiers() & Qt::ShiftModifier))
532 {
533 // move time by years
534 double jdNow=core->getJD();
535 int year, month, day, hour, min, sec, millis;
536 StelUtils::getDateFromJulianDay(jdNow, &year, &month, &day);
537 StelUtils::getTimeFromJulianDay(jdNow, &hour, &min, &sec, &millis);
538 double jdNew;
539 StelUtils::getJDFromDate(&jdNew, year+qRound(numSteps), month, day, hour, min, sec);
540 core->setJD(jdNew);
541 emit core->dateChanged();
542 emit core->dateChangedByYear();
543 }
544 else if (event->modifiers() & Qt::AltModifier)
545 {
546 // move time by days
547 core->setJD(core->getJD()+qRound(numSteps));
548 emit core->dateChanged();
549 }
550 else if (event->modifiers() & Qt::ShiftModifier)
551 {
552 // move time by hours
553 core->setJD(core->getJD()+qRound(numSteps)/(24.));
554 }
555 else
556 {
557 // move time by minutes
558 core->setJD(core->getJD()+qRound(numSteps)/(24.*60.));
559 }
560 }
561 else
562 {
563 const double zoomFactor = exp(-mouseZoomSpeed * numSteps / 60.);
564 const float zoomDuration = 0.2f;
565 zoomTo(getAimFov() * zoomFactor, zoomDuration);
566 }
567 event->accept();
568 }
569
addTimeDragPoint(int x,int y)570 void StelMovementMgr::addTimeDragPoint(int x, int y)
571 {
572 DragHistoryEntry e;
573 e.runTime=StelApp::getInstance().getTotalRunTime();
574 e.jd=core->getJD();
575 e.x=x;
576 e.y=y;
577 timeDragHistory.append(e);
578 if (timeDragHistory.size()>3)
579 timeDragHistory.removeFirst();
580 }
581
handlePinch(qreal scale,bool started)582 bool StelMovementMgr::handlePinch(qreal scale, bool started)
583 {
584 #ifdef Q_OS_WIN
585 if (flagEnableMouseNavigation == false || flagEnableMouseZooming==false)
586 return true;
587 #endif
588
589 static double previousFov = 0;
590 if (started)
591 previousFov = getAimFov();
592 if (scale>0)
593 zoomTo(previousFov/scale, 0);
594 return true;
595 }
596
handleMouseClicks(QMouseEvent * event)597 void StelMovementMgr::handleMouseClicks(QMouseEvent* event)
598 {
599 switch (event->button())
600 {
601 case Qt::RightButton:
602 {
603 if (event->type()==QEvent::MouseButtonRelease)
604 {
605 // The code for deselect the selected object was moved into separate method.
606 deselection();
607 event->accept();
608 return;
609 }
610 break;
611 }
612 case Qt::LeftButton :
613 if (event->type()==QEvent::MouseButtonDblClick)
614 {
615 if (objectMgr->getWasSelected())
616 {
617 moveToObject(objectMgr->getSelectedObject()[0],autoMoveDuration);
618 setFlagTracking(true);
619 }
620 event->accept();
621 return;
622 }
623 else if (event->type()==QEvent::MouseButtonPress)
624 {
625 if (event->modifiers() & Qt::ControlModifier)
626 {
627 dragTimeMode=true;
628 beforeTimeDragTimeRate=core->getTimeRate();
629 timeDragHistory.clear();
630 addTimeDragPoint(event->x(), event->y());
631 }
632 isDragging = true;
633 hasDragged = false;
634 previousX = event->x();
635 previousY = event->y();
636 event->accept();
637 return;
638 }
639 else if (event->type()==QEvent::MouseButtonRelease)
640 {
641 isDragging = false;
642 if (hasDragged)
643 {
644 event->accept();
645 if (dragTimeMode)
646 {
647 if (timeDragHistory.size()>=3)
648 {
649 const double deltaT = timeDragHistory.last().runTime-timeDragHistory.first().runTime;
650 Vec2f d(timeDragHistory.last().x-timeDragHistory.first().x, timeDragHistory.last().y-timeDragHistory.first().y);
651 if (d.length()/static_cast<float>(deltaT) < dragTriggerDistance)
652 {
653 core->setTimeRate(StelCore::JD_SECOND);
654 }
655 else
656 {
657 const double deltaJd = timeDragHistory.last().jd-timeDragHistory.first().jd;
658 const double newTimeRate = deltaJd/deltaT;
659 if (deltaT>0.00000001)
660 {
661 if (newTimeRate>=0)
662 core->setTimeRate(qMax(newTimeRate, StelCore::JD_SECOND));
663 else
664 core->setTimeRate(qMin(newTimeRate, -StelCore::JD_SECOND));
665 }
666 else
667 core->setTimeRate(beforeTimeDragTimeRate);
668 }
669 }
670 else
671 core->setTimeRate(beforeTimeDragTimeRate);
672 }
673 return;
674 }
675 else // has not dragged...
676 {
677 // It's a normal click release
678 // TODO: Leave time dragging in Natural speed or zero speed (config option?) if mouse was resting
679 #ifdef Q_OS_MAC
680 // CTRL + left click = right click for 1 button mouse
681 if (event->modifiers().testFlag(Qt::ControlModifier))
682 {
683 objectMgr->unSelect();
684 event->accept();
685 return;
686 }
687
688 // Try to select object at that position
689 objectMgr->findAndSelect(core, event->x(), event->y(), event->modifiers().testFlag(Qt::MetaModifier) ? StelModule::AddToSelection : StelModule::ReplaceSelection);
690 #else
691 objectMgr->findAndSelect(core, event->x(), event->y(), event->modifiers().testFlag(Qt::ControlModifier) ? StelModule::AddToSelection : StelModule::ReplaceSelection);
692 #endif
693 if (objectMgr->getWasSelected())
694 setFlagTracking(false);
695 //GZ: You must comment out this line for testing Landscape transparency debug prints.
696 //event->accept();
697 return;
698 }
699 }
700 else
701 {
702 qDebug() << "StelMovementMgr::handleMouseClicks: unknown mouse event type, skipping: " << event->type();
703 }
704 break;
705 case Qt::MidButton :
706 if (event->type()==QEvent::MouseButtonRelease)
707 {
708 if (objectMgr->getWasSelected())
709 {
710 moveToObject(objectMgr->getSelectedObject()[0],autoMoveDuration);
711 setFlagTracking(true);
712 }
713 }
714 break;
715 default: break;
716 }
717 return;
718 }
719
setInitFov(double fov)720 void StelMovementMgr::setInitFov(double fov)
721 {
722 initFov=fov;
723 StelApp::getInstance().getSettings()->setValue("navigation/init_fov", fov);
724 }
725
setInitViewDirectionToCurrent()726 void StelMovementMgr::setInitViewDirectionToCurrent()
727 {
728 // 2016-12 TODO: Create azimuth indication for zenith views.
729 initViewPos = core->j2000ToAltAz(viewDirectionJ2000, StelCore::RefractionOff);
730 QString dirStr = QString("%1,%2,%3").arg(initViewPos[0]).arg(initViewPos[1]).arg(initViewPos[2]);
731 StelApp::getInstance().getSettings()->setValue("navigation/init_view_pos", dirStr);
732 }
733
734 /*************************************************************************
735 The selected objects changed, follow it if we were already following another one
736 *************************************************************************/
selectedObjectChange(StelModule::StelModuleSelectAction)737 void StelMovementMgr::selectedObjectChange(StelModule::StelModuleSelectAction)
738 {
739 // If an object was selected keep the earth following
740 if (objectMgr->getWasSelected())
741 {
742 if (getFlagTracking())
743 setFlagLockEquPos(true);
744 setFlagTracking(false);
745 }
746 }
747
turnRight(bool s)748 void StelMovementMgr::turnRight(bool s)
749 {
750 if (s && flagEnableMoveKeys)
751 {
752 deltaAz = 1;
753 setFlagTracking(false);
754 setFlagLockEquPos(false);
755 }
756 else
757 deltaAz = 0;
758 }
759
turnLeft(bool s)760 void StelMovementMgr::turnLeft(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
turnUp(bool s)772 void StelMovementMgr::turnUp(bool s)
773 {
774 if (s && flagEnableMoveKeys)
775 {
776 deltaAlt = 1;
777 setFlagTracking(false);
778 setFlagLockEquPos(false);
779 }
780 else
781 deltaAlt = 0;
782 }
783
turnDown(bool s)784 void StelMovementMgr::turnDown(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
zoomIn(bool s)797 void StelMovementMgr::zoomIn(bool s)
798 {
799 if (flagEnableZoomKeys)
800 deltaFov = -1*(s!=0);
801 }
802
zoomOut(bool s)803 void StelMovementMgr::zoomOut(bool s)
804 {
805 if (flagEnableZoomKeys)
806 deltaFov = (s!=0);
807 }
808
lookEast(bool zero)809 void StelMovementMgr::lookEast(bool zero)
810 {
811 float alt, cy;
812 Vec3f dir;
813
814 if (zero)
815 {
816 alt = 0.0f;
817 cy = M_PI_2f;
818 StelUtils::spheToRect(cy, alt, dir);
819
820 setViewDirectionJ2000(core->altAzToJ2000(dir.toVec3d(), StelCore::RefractionOff));
821 setViewUpVector(Vec3d(0., 0., 1.));
822 return;
823 }
824
825 StelUtils::rectToSphe(&cy,&alt,core->j2000ToAltAz(getViewDirectionJ2000(), StelCore::RefractionOff));
826 cy = M_PI_2f;
827 StelUtils::spheToRect(cy, alt, dir);
828 setViewDirectionJ2000(core->altAzToJ2000(dir.toVec3d(), StelCore::RefractionOff));
829 //qDebug() << "Setting East at Alt:" << alt*M_180_PIf;
830 if ((mountMode==MountAltAzimuthal) && (fabsf(alt)>M_PI_2f-0.0001f) && (fabs(upVectorMountFrame[2])<0.001))
831 {
832 // Special case: we already look into zenith (with rounding tolerance). Bring East to bottom of screen.
833 upVectorMountFrame.set(0., -1.*StelUtils::sign(alt), 0.);
834 //qDebug() << "lookEast: better Up is " << upVectorMountFrame[0] << "/" << upVectorMountFrame[1] << "/" << upVectorMountFrame[2];
835 }
836 }
837
lookWest(bool zero)838 void StelMovementMgr::lookWest(bool zero)
839 {
840 float alt, cy;
841 Vec3f dir;
842
843 if (zero)
844 {
845 alt = 0.0f;
846 cy = 3.f*M_PI_2f;
847 StelUtils::spheToRect(cy, alt, dir);
848
849 setViewDirectionJ2000(core->altAzToJ2000(dir.toVec3d(), StelCore::RefractionOff));
850 setViewUpVector(Vec3d(0., 0., 1.));
851 return;
852 }
853
854 StelUtils::rectToSphe(&cy,&alt,core->j2000ToAltAz(getViewDirectionJ2000(), StelCore::RefractionOff));
855 cy = 3.f*M_PI_2f;
856 StelUtils::spheToRect(cy, alt, dir);
857 setViewDirectionJ2000(core->altAzToJ2000(dir.toVec3d(), StelCore::RefractionOff));
858 //qDebug() << "Setting West at Alt:" << alt*M_180_PIf;
859 if ((mountMode==MountAltAzimuthal) && (fabsf(alt)>M_PI_2f-0.0001f) && (fabs(upVectorMountFrame[2])<0.001))
860 {
861 // Special case: we already look into zenith (with rounding tolerance). Bring West to bottom of screen.
862 upVectorMountFrame.set(0., StelUtils::sign(alt), 0.);
863 //qDebug() << "lookEast: better Up is " << upVectorMountFrame[0] << "/" << upVectorMountFrame[1] << "/" << upVectorMountFrame[2];
864 }
865 }
866
lookNorth(bool zero)867 void StelMovementMgr::lookNorth(bool zero)
868 {
869 float alt, cy;
870 Vec3f dir;
871
872 if (zero)
873 {
874 alt = 0.0f;
875 cy = M_PIf;
876 StelUtils::spheToRect(cy, alt, dir);
877
878 setViewDirectionJ2000(core->altAzToJ2000(dir.toVec3d(), StelCore::RefractionOff));
879 setViewUpVector(Vec3d(0., 0., 1.));
880 return;
881 }
882
883 StelUtils::rectToSphe(&cy,&alt,core->j2000ToAltAz(getViewDirectionJ2000(), StelCore::RefractionOff));
884 cy = static_cast<float>(M_PI);
885 StelUtils::spheToRect(cy, alt, dir);
886 setViewDirectionJ2000(core->altAzToJ2000(dir.toVec3d(), StelCore::RefractionOff));
887
888 //qDebug() << "Setting North at Alt:" << alt*M_180_PIf;
889 if ((mountMode==MountAltAzimuthal) && (fabsf(alt)>M_PI_2f-0.0001f) && (fabs(upVectorMountFrame[2])<0.001))
890 {
891 // Special case: we already look into zenith (with rounding tolerance). Bring North to bottom of screen.
892 upVectorMountFrame.set(StelUtils::sign(alt), 0., 0.);
893 //qDebug() << "lookNorth: better Up is " << upVectorMountFrame[0] << "/" << upVectorMountFrame[1] << "/" << upVectorMountFrame[2];
894 }
895 }
896
lookSouth(bool zero)897 void StelMovementMgr::lookSouth(bool zero)
898 {
899 float alt, cy;
900 Vec3f dir;
901
902 if (zero)
903 {
904 alt = 0.0f;
905 cy = 0.0f;
906 StelUtils::spheToRect(cy, alt, dir);
907
908 setViewDirectionJ2000(core->altAzToJ2000(dir.toVec3d(), StelCore::RefractionOff));
909 setViewUpVector(Vec3d(0., 0., 1.));
910 return;
911 }
912
913 StelUtils::rectToSphe(&cy,&alt,core->j2000ToAltAz(getViewDirectionJ2000(), StelCore::RefractionOff));
914 cy = 0.f;
915 StelUtils::spheToRect(cy, alt, dir);
916 setViewDirectionJ2000(core->altAzToJ2000(dir.toVec3d(), StelCore::RefractionOff));
917
918 //qDebug() << "Setting South at Alt:" << alt*M_180_PIf;
919 if ((mountMode==MountAltAzimuthal) && (fabsf(alt)>M_PI_2f-0.0001f) && (fabs(upVectorMountFrame[2])<0.001))
920 {
921 // Special case: we already look into zenith (with rounding tolerance). Bring South to bottom of screen.
922 upVectorMountFrame.set(-1.*StelUtils::sign(alt), 0., 0.);
923 //qDebug() << "lookSouth: better Up is " << upVectorMountFrame[0] << "/" << upVectorMountFrame[1] << "/" << upVectorMountFrame[2];
924 }
925 }
926
lookZenith(void)927 void StelMovementMgr::lookZenith(void)
928 {
929 Vec3f dir;
930 StelUtils::spheToRect(M_PIf, M_PI_2f, dir);
931 //qDebug() << "lookZenith: Up is " << upVectorMountFrame[0] << "/" << upVectorMountFrame[1] << "/" << upVectorMountFrame[2];
932 setViewDirectionJ2000(core->altAzToJ2000(dir.toVec3d(), StelCore::RefractionOff));
933 //qDebug() << "lookZenith: View is " << viewDirectionMountFrame[0] << "/" << viewDirectionMountFrame[1] << "/" << viewDirectionMountFrame[2];
934 if (mountMode==MountAltAzimuthal)
935 { // ensure a stable up vector that makes the bottom of the screen point south.
936 upVectorMountFrame.set(-1., 0., 0.);
937 //qDebug() << "lookZenith: better Up is " << upVectorMountFrame[0] << "/" << upVectorMountFrame[1] << "/" << upVectorMountFrame[2];
938 }
939 }
940
lookNadir(void)941 void StelMovementMgr::lookNadir(void)
942 {
943 Vec3f dir;
944 StelUtils::spheToRect(M_PIf, -M_PI_2f, dir);
945 //qDebug() << "lookNadir: Up is " << upVectorMountFrame[0] << "/" << upVectorMountFrame[1] << "/" << upVectorMountFrame[2];
946 setViewDirectionJ2000(core->altAzToJ2000(dir.toVec3d(), StelCore::RefractionOff));
947 //qDebug() << "lookNadir: View is " << viewDirectionMountFrame[0] << "/" << viewDirectionMountFrame[1] << "/" << viewDirectionMountFrame[2];
948 if (mountMode==MountAltAzimuthal)
949 { // ensure a stable up vector that makes the top of the screen point south.
950 upVectorMountFrame.set(-1., 0., 0.);
951 //qDebug() << "lookNadir: better Up is " << upVectorMountFrame[0] << "/" << upVectorMountFrame[1] << "/" << upVectorMountFrame[2];
952 }
953 }
954
lookTowardsNCP(void)955 void StelMovementMgr::lookTowardsNCP(void)
956 {
957 setViewDirectionJ2000(core->equinoxEquToJ2000(Vec3d(0,0,1), StelCore::RefractionOff));
958 }
959
lookTowardsSCP(void)960 void StelMovementMgr::lookTowardsSCP(void)
961 {
962 setViewDirectionJ2000(core->equinoxEquToJ2000(Vec3d(0,0,-1), StelCore::RefractionOff));
963 }
964
setFOVDeg(float fov)965 void StelMovementMgr::setFOVDeg(float fov)
966 {
967 zoomTo(fov, 1.f);
968 }
969
970 // Increment/decrement smoothly the vision field and position
updateMotion(double deltaTime)971 void StelMovementMgr::updateMotion(double deltaTime)
972 {
973 updateVisionVector(deltaTime);
974
975 const StelProjectorP proj = core->getProjection(StelCore::FrameJ2000);
976 // the more it is zoomed, the lower the moving speed is (in angle)
977 double depl=keyMoveSpeed*deltaTime*1000*currentFov;
978 double deplzoom=keyZoomSpeed*deltaTime*1000*static_cast<double>(proj->deltaZoom(static_cast<float>(currentFov)*(M_PIf/360.0f)))*(360.0/M_PI);
979
980 if (flagMoveSlow)
981 {
982 depl *= 0.2;
983 deplzoom *= 0.2;
984 }
985
986 if (deltaAz<0)
987 {
988 deltaAz = -depl/30;
989 if (deltaAz<-0.2)
990 deltaAz = -0.2;
991 }
992 else if (deltaAz>0)
993 {
994 deltaAz = (depl/30);
995 if (deltaAz>0.2)
996 deltaAz = 0.2;
997 }
998
999 if (deltaAlt<0)
1000 {
1001 deltaAlt = -depl/30;
1002 if (deltaAlt<-0.2)
1003 deltaAlt = -0.2;
1004 }
1005 else if (deltaAlt>0)
1006 {
1007 deltaAlt = depl/30;
1008 if (deltaAlt>0.2)
1009 deltaAlt = 0.2;
1010 }
1011
1012 if (deltaFov<0)
1013 {
1014 deltaFov=qMax(-0.15*currentFov, -deplzoom*5);
1015 changeFov(deltaFov);
1016 }
1017 else if (deltaFov>0)
1018 {
1019 deltaFov = qMin(20., deplzoom*5.);
1020 changeFov(deltaFov);
1021 }
1022
1023 if (flagCustomPan)
1024 {
1025 deltaAz = rateX*M_PI_180*deltaTime;
1026 deltaAlt = rateY*M_PI_180*deltaTime;
1027 }
1028
1029 panView(deltaAz, deltaAlt);
1030 updateAutoZoom(deltaTime);
1031 }
1032
1033 // called at begin of updateMotion()
updateVisionVector(double deltaTime)1034 void StelMovementMgr::updateVisionVector(double deltaTime)
1035 {
1036 // Specialized setups cannot use this functionality!
1037 if (flagInhibitAllAutomoves)
1038 return;
1039
1040 if (flagAutoMove)
1041 {
1042 if (!move.targetObject.isNull())
1043 {
1044 // if zooming in, object may be moving so be sure to zoom to latest position
1045 // In case we have offset center, we want object still visible in center.
1046 // Note that if we do not center on an object, we set view direction of the potentially offset screen center!
1047 // This is by design, to allow accurate setting of display coordinates.
1048 Vec3d v;
1049 switch (mountMode)
1050 {
1051 case MountAltAzimuthal:
1052 v = move.targetObject->getAltAzPosAuto(core);
1053 break;
1054 case MountEquinoxEquatorial:
1055 v = move.targetObject->getEquinoxEquatorialPosAuto(core); // ..Auto! Fix Bug LP:#1484976
1056 break;
1057 case MountGalactic:
1058 v = move.targetObject->getGalacticPos(core);
1059 break;
1060 case MountSupergalactic:
1061 v = move.targetObject->getSupergalacticPos(core);
1062 break;
1063 default:
1064 qWarning() << "StelMovementMgr: unexpected mountMode" << mountMode;
1065 Q_ASSERT(0);
1066 v = move.targetObject->getAltAzPosAuto(core); // still do something useful
1067 }
1068
1069 double lat, lon;
1070 StelUtils::rectToSphe(&lon, &lat, v);
1071 double altOffset=core->getCurrentStelProjectorParams().viewportCenterOffset[1]*currentFov*M_PI_180;
1072 lat+=altOffset;
1073 StelUtils::spheToRect(lon, lat, v);
1074 move.aim=mountFrameToJ2000(v);
1075 move.aim.normalize();
1076 move.aim*=2.;
1077 // For aiming at objects, we can assume simple up vector.
1078 move.startUp=getViewUpVectorJ2000();
1079 move.aimUp=mountFrameToJ2000(Vec3d(0., 0., 1.));
1080 }
1081 else // no targetObject:
1082 {
1083 // if (move.mountMode == MountAltAzimuthal)
1084 // {
1085 // move.startUp=Vec3d(0., 0., 1.);
1086 // move.aimUp=Vec3d(0., 0., 1.);
1087 // }
1088 // else
1089 // { // March 2016
1090 move.startUp=getViewUpVectorJ2000();
1091 move.aimUp=mountFrameToJ2000(Vec3d(0., 0., 1.));
1092 // }
1093 }
1094 move.coef+=move.speed*static_cast<float>(deltaTime)*1000;
1095 //qDebug() << "updateVisionVector: setViewUpvectorJ2000 L813";
1096 setViewUpVectorJ2000(move.aimUp);
1097 if (move.coef>=1.f)
1098 {
1099 //qDebug() << "AutoMove finished. Setting Up vector (in mount frame) to " << upVectorMountFrame.v[0] << "/" << upVectorMountFrame.v[1] << "/" << upVectorMountFrame.v[2];
1100 flagAutoMove=false;
1101 move.coef=1.f;
1102 }
1103
1104 // Use a smooth function
1105 const float smooth = 4.f; // (empirically tested)
1106 double c;
1107 switch (zoomingMode){
1108 case ZoomIn:
1109 c=(move.coef>.9f ? 1. : 1. - static_cast<double>(powf(1.f-1.11f*move.coef,3.f))); break;
1110 case ZoomOut:
1111 // keep in view at first as zoom out
1112 c=(move.coef<0.1f ? 0. : static_cast<double>(powf(1.11f*(move.coef-.1f),3.f))); break;
1113 default:
1114 c = static_cast<double>(std::atan(smooth * 2.f*move.coef-smooth)/std::atan(smooth)/2+0.5f);
1115 }
1116
1117 // 2016-03: In case of azimuthal moves, it is not useful to compute anything from J2000 coordinates.
1118 // Imagine a slow AltAz move during speedy timelapse: Aim will move!
1119 // TODO: all variants...
1120 Vec3d tmpStart;
1121 Vec3d tmpAim;
1122 if (move.mountMode==MountAltAzimuthal)
1123 {
1124 tmpStart=move.start;
1125 tmpAim=move.aim;
1126 }
1127 else
1128 {
1129 tmpStart = j2000ToMountFrame(move.start);
1130 tmpAim = j2000ToMountFrame(move.aim);
1131 }
1132 double ra_aim, de_aim, ra_start, de_start;
1133 StelUtils::rectToSphe(&ra_start, &de_start, tmpStart);
1134 StelUtils::rectToSphe(&ra_aim, &de_aim, tmpAim);
1135
1136 // Make sure the position of the object to be aimed at is defined...
1137 Q_ASSERT(!qIsNaN(move.aim[0]) && !qIsNaN(move.aim[1]) && !qIsNaN(move.aim[2]));
1138 // Trick to choose the good moving direction and never travel on a distance > PI
1139 if (ra_aim-ra_start > M_PI)
1140 {
1141 ra_aim -= 2.*M_PI;
1142 }
1143 else if (ra_aim-ra_start < -M_PI)
1144 {
1145 ra_aim += 2.*M_PI;
1146 }
1147 const double de_now = de_aim*c + de_start*(1.-c);
1148 const double ra_now = ra_aim*c + ra_start*(1.-c);
1149 Vec3d tmp;
1150 StelUtils::spheToRect(ra_now, de_now, tmp);
1151 // now tmp is either Mountframe or AltAz interpolated vector.
1152 // if (move.mountMode==MountAltAzimuthal)
1153 // { // Actually, Altaz moves work in Altaz coords only. Maybe we are here?
1154 // }
1155 // else
1156 setViewDirectionJ2000(mountFrameToJ2000(tmp));
1157 // if (move.mountMode==MountAltAzimuthal)
1158 // {
1159 // setViewUpVector(Vec3d(0., 0., 1.));
1160 // qDebug() << "We do indeed set this";
1161 // }
1162 // qDebug() << "setting view direction to " << tmp.v[0] << "/" << tmp.v[1] << "/" << tmp.v[2];
1163 }
1164 else // no autoMove
1165 {
1166 if (flagTracking && objectMgr->getWasSelected()) // Equatorial vision vector locked on selected object
1167 {
1168 Vec3d v;
1169 switch (mountMode)
1170 {
1171 case MountAltAzimuthal:
1172 v = objectMgr->getSelectedObject()[0]->getAltAzPosAuto(core);
1173 break;
1174 case MountEquinoxEquatorial:
1175 v = objectMgr->getSelectedObject()[0]->getEquinoxEquatorialPosAuto(core);
1176 break;
1177 case MountGalactic:
1178 v = objectMgr->getSelectedObject()[0]->getGalacticPos(core);
1179 break;
1180 case MountSupergalactic:
1181 v = objectMgr->getSelectedObject()[0]->getSupergalacticPos(core);
1182 break;
1183 default:
1184 qWarning() << "StelMovementMgr: unexpected mountMode" << mountMode;
1185 Q_ASSERT(0);
1186 v = move.targetObject->getAltAzPosAuto(core); // still do something useful in release build
1187 }
1188
1189 double lat, lon; // general: longitudinal, latitudinal
1190 StelUtils::rectToSphe(&lon, &lat, v);
1191 double latOffset=static_cast<double>(core->getCurrentStelProjectorParams().viewportCenterOffset[1]) * currentFov*M_PI_180;
1192 lat+=latOffset;
1193 StelUtils::spheToRect(lon, lat, v);
1194
1195 setViewDirectionJ2000(mountFrameToJ2000(v));
1196 //qDebug() << "setViewUpVector() L930";
1197 setViewUpVectorJ2000(mountFrameToJ2000(Vec3d(0., 0., 1.))); // Does not disturb to reassure this former default.
1198 }
1199 else // not tracking or no selection
1200 {
1201 if (flagLockEquPos) // Equatorial vision vector locked
1202 {
1203 // Recalc local vision vector
1204 setViewDirectionJ2000(viewDirectionJ2000);
1205 }
1206 else
1207 {
1208 // Vision vector locked to its position in the mountFrame
1209 setViewDirectionJ2000(mountFrameToJ2000(viewDirectionMountFrame));
1210 // After setting time, moveToAltAz broke the up vector without this:
1211 // Make sure this does not now break zenith views!
1212 // Or make sure to call moveToAltAz twice.
1213 //qDebug() << "setUpVectorJ2000 woe L947";
1214 //setViewUpVectorJ2000(mountFrameToJ2000(Vec3d(0.,0.,1.)));
1215 setViewUpVectorJ2000(mountFrameToJ2000(upVectorMountFrame)); // maybe fixes? / < < < < < < < < < < THIS WAS THE BIG ONE
1216 }
1217 }
1218 }
1219 }
1220
deselection(void)1221 void StelMovementMgr::deselection(void)
1222 {
1223 // Deselect the selected object
1224 StelApp::getInstance().getStelObjectMgr().unSelect();
1225 setFlagLockEquPos(false);
1226 return;
1227 }
1228
1229 // Go and zoom to the selected object. (Action linked to key, default "/")
autoZoomIn(float moveDuration,bool allowManualZoom)1230 void StelMovementMgr::autoZoomIn(float moveDuration, bool allowManualZoom)
1231 {
1232 if (!objectMgr->getWasSelected())
1233 return;
1234
1235 moveDuration /= movementsSpeedFactor;
1236
1237 float manualMoveDuration;
1238 if (!getFlagTracking())
1239 {
1240 setFlagTracking(true); // includes a call to moveToObject(), but without zooming=1!
1241 moveToObject(objectMgr->getSelectedObject()[0], moveDuration, ZoomIn);
1242 manualMoveDuration = moveDuration;
1243 }
1244 else
1245 {
1246 // faster zoom in manual zoom mode once object is centered
1247 manualMoveDuration = moveDuration*.66f;
1248 }
1249
1250 if( allowManualZoom && flagManualZoom )
1251 {
1252 // if manual zoom mode, user can zoom in incrementally
1253 double newfov = currentFov*0.5;
1254 zoomTo(newfov, manualMoveDuration);
1255 }
1256 else
1257 {
1258 double satfov = objectMgr->getSelectedObject()[0]->getSatellitesFov(core);
1259
1260 if (satfov>0.0 && currentFov*0.9>satfov)
1261 zoomTo(satfov, moveDuration);
1262 else
1263 {
1264 double closefov = objectMgr->getSelectedObject()[0]->getCloseViewFov(core);
1265 if (currentFov>closefov)
1266 zoomTo(closefov, moveDuration);
1267 }
1268 }
1269 }
1270
1271
1272 // Unzoom and go to the init position
autoZoomOut(float moveDuration,bool full)1273 void StelMovementMgr::autoZoomOut(float moveDuration, bool full)
1274 {
1275 moveDuration /= movementsSpeedFactor;
1276
1277 if (objectMgr->getWasSelected() && !full)
1278 {
1279 // If the selected object has satellites, unzoom to satellites view
1280 // unless specified otherwise
1281 double satfov = objectMgr->getSelectedObject()[0]->getSatellitesFov(core);
1282
1283 if (satfov>0.0 && currentFov<=satfov*0.9)
1284 {
1285 zoomTo(satfov, moveDuration);
1286 return;
1287 }
1288
1289 // If the selected object is part of a Planet subsystem (other than sun),
1290 // unzoom to subsystem view
1291 satfov = objectMgr->getSelectedObject()[0]->getParentSatellitesFov((core));
1292 if (satfov>0.0 && currentFov<=satfov*0.9)
1293 {
1294 zoomTo(satfov, moveDuration);
1295 return;
1296 }
1297 }
1298
1299 zoomTo(initFov, moveDuration);
1300 if (flagAutoZoomOutResetsDirection)
1301 {
1302 moveToJ2000(core->altAzToJ2000(getInitViewingDirection(), StelCore::RefractionOff), mountFrameToJ2000(initViewUp), moveDuration, ZoomOut);
1303 setFlagTracking(false);
1304 setFlagLockEquPos(false);
1305 }
1306 }
1307
1308 // This is called when you press SPACEBAR: slowly centering&tracking object
setFlagTracking(bool b)1309 void StelMovementMgr::setFlagTracking(bool b)
1310 {
1311 if (!b || !objectMgr->getWasSelected())
1312 {
1313 if(b!=flagTracking)
1314 {
1315 flagTracking=false;
1316 emit flagTrackingChanged(b);
1317 }
1318 }
1319 else
1320 {
1321 moveToObject(objectMgr->getSelectedObject()[0], getAutoMoveDuration());
1322 if(b!=flagTracking)
1323 {
1324 flagTracking=true;
1325 emit flagTrackingChanged(b);
1326 }
1327 }
1328 }
1329
1330
1331 ////////////////////////////////////////////////////////////////////////////////
1332 // Move to the given J2000 equatorial position
1333
1334 // aim and aimUp must be in J2000 frame!
moveToJ2000(const Vec3d & aim,const Vec3d & aimUp,float moveDuration,ZoomingMode zooming)1335 void StelMovementMgr::moveToJ2000(const Vec3d& aim, const Vec3d& aimUp, float moveDuration, ZoomingMode zooming)
1336 {
1337 moveDuration /= movementsSpeedFactor;
1338
1339 zoomingMode = zooming;
1340 move.aim=aim;
1341 move.aim.normalize();
1342 move.aim*=2.;
1343 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.
1344 move.aimUp.normalize();
1345 move.start=viewDirectionJ2000;
1346 move.start.normalize();
1347 move.startUp=getViewUpVectorJ2000();
1348 move.startUp.normalize();
1349 move.speed=1.f/(moveDuration*1000);
1350 move.coef=0.;
1351 move.targetObject.clear();
1352 //move.mountMode=mountMode; // Maybe better to have MountEquinoxEquatorial here? ==> YES, fixed orientation problem.
1353 move.mountMode=MountEquinoxEquatorial;
1354 flagAutoMove = true;
1355 }
1356
moveToObject(const StelObjectP & target,float moveDuration,ZoomingMode zooming)1357 void StelMovementMgr::moveToObject(const StelObjectP& target, float moveDuration, ZoomingMode zooming)
1358 {
1359 moveDuration /= movementsSpeedFactor;
1360
1361 zoomingMode = zooming;
1362 move.aim=Vec3d(0.);
1363 move.aimUp=mountFrameToJ2000(Vec3d(0., 0., 1.)); // the new up vector. We try simply vertical axis here. (Should be same as pre-0.15)
1364 move.aimUp.normalize();
1365 move.start=viewDirectionJ2000;
1366 move.start.normalize();
1367 move.startUp=getViewUpVectorJ2000();
1368 move.startUp.normalize();
1369 move.speed=1.f/(moveDuration*1000);
1370 move.coef=0.;
1371 move.targetObject = target;
1372 //move.mountMode=mountMode; // Maybe better to have MountEquinoxEquatorial here? ==> YES, fixed orientation problem.
1373 move.mountMode=MountEquinoxEquatorial;
1374 flagAutoMove = true;
1375 }
1376
1377 // March 2016: This call does nothing when mount frame is not AltAzi! (TODO later: rethink&fix.)
moveToAltAzi(const Vec3d & aim,const Vec3d & aimUp,float moveDuration,ZoomingMode zooming)1378 void StelMovementMgr::moveToAltAzi(const Vec3d& aim, const Vec3d &aimUp, float moveDuration, ZoomingMode zooming)
1379 {
1380 if (mountMode!=StelMovementMgr::MountAltAzimuthal)
1381 {
1382 qDebug() << "StelMovementMgr: called moveToAltAzi, but not in AltAz mount frame. Ignoring.";
1383 return;
1384 }
1385
1386 moveDuration /= movementsSpeedFactor;
1387
1388 // Specify start and aim vectors in AltAz system! Then the auto functions can work it out properly.
1389 zoomingMode = zooming;
1390 move.aim=aim;
1391 move.aim.normalize();
1392 move.aim*=2.;
1393 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.
1394 move.aimUp.normalize();
1395 move.start=core->j2000ToAltAz(viewDirectionJ2000, StelCore::RefractionOff);
1396 move.start.normalize();
1397 move.startUp.set(0., 0., 1.);
1398 move.speed=1.f/(moveDuration*1000);
1399 move.coef=0.;
1400 move.targetObject.clear();
1401 move.mountMode=MountAltAzimuthal; // This signals: start and aim are given in AltAz coordinates.
1402 flagAutoMove = true;
1403 // // debug output if required
1404 // double currAlt, currAzi, newAlt, newAzi;
1405 // StelUtils::rectToSphe(&currAzi, &currAlt, move.start);
1406 // StelUtils::rectToSphe(&newAzi, &newAlt, move.aim);
1407 // 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) ;
1408 }
1409
1410
j2000ToMountFrame(const Vec3d & v) const1411 Vec3d StelMovementMgr::j2000ToMountFrame(const Vec3d& v) const
1412 {
1413 switch (mountMode)
1414 {
1415 case MountAltAzimuthal:
1416 return core->j2000ToAltAz(v, StelCore::RefractionOff); // TODO: Decide if RefractionAuto?
1417 case MountEquinoxEquatorial:
1418 return core->j2000ToEquinoxEqu(v, StelCore::RefractionOff);
1419 case MountGalactic:
1420 return core->j2000ToGalactic(v);
1421 case MountSupergalactic:
1422 return core->j2000ToSupergalactic(v);
1423 }
1424 Q_ASSERT(0);
1425 return Vec3d(0.);
1426 }
1427
mountFrameToJ2000(const Vec3d & v) const1428 Vec3d StelMovementMgr::mountFrameToJ2000(const Vec3d& v) const
1429 {
1430 switch (mountMode)
1431 {
1432 case MountAltAzimuthal:
1433 return core->altAzToJ2000(v, StelCore::RefractionOff); // TODO: Decide if RefractionAuto?
1434 case MountEquinoxEquatorial:
1435 return core->equinoxEquToJ2000(v, StelCore::RefractionOff);
1436 case MountGalactic:
1437 return core->galacticToJ2000(v);
1438 case MountSupergalactic:
1439 return core->supergalacticToJ2000(v);
1440 }
1441 Q_ASSERT(0);
1442 return Vec3d(0.);
1443 }
1444
setViewDirectionJ2000(const Vec3d & v)1445 void StelMovementMgr::setViewDirectionJ2000(const Vec3d& v)
1446 {
1447 core->lookAtJ2000(v, getViewUpVectorJ2000());
1448 viewDirectionJ2000 = v;
1449 viewDirectionMountFrame = j2000ToMountFrame(v);
1450 }
1451
panView(const double deltaAz,const double deltaAlt)1452 void StelMovementMgr::panView(const double deltaAz, const double deltaAlt)
1453 {
1454 // DONE 2016-12 FIX UP VECTOR PROBLEM
1455 // The function is called in update loops, so make a quick check for exit.
1456 if ((deltaAz==0.) && (deltaAlt==0.))
1457 return;
1458
1459 double azVision, altVision;
1460 StelUtils::rectToSphe(&azVision,&altVision,j2000ToMountFrame(viewDirectionJ2000));
1461 // Az is counted from South, eastward.
1462
1463 //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];
1464
1465 // if we are just looking into the pole, azimuth can hopefully be recovered from the customized up vector!
1466 // When programmatically centering on a pole, we should have set a better up vector for |alt|>0.9*M_PI/2.
1467 if (fabs(altVision)> 0.95* M_PI_2)
1468 {
1469 if (upVectorMountFrame.v[2] < 0.9)
1470 {
1471 //qDebug() << "panView: Recovering azimuth...";
1472 azVision=atan2(-upVectorMountFrame.v[1], -upVectorMountFrame.v[0]);
1473 if (altVision < 0.)
1474 azVision+=M_PI;
1475 }
1476 // Remove these lines if all is OK.
1477 // else
1478 // {
1479 // qDebug() << "panView: UpVector:" << upVectorMountFrame.v[0] << "/" << upVectorMountFrame.v[1] << "/" << upVectorMountFrame.v[2] << "Cannot recover azimuth. Hope it's OK";
1480 // }
1481 }
1482
1483 // if we are moving in the Azimuthal angle (left/right)
1484 if (fabs(deltaAz)>1e-10)
1485 azVision-=deltaAz;
1486 if (fabs(deltaAlt)>1e-10)
1487 {
1488 //if (altVision+deltaAlt <= M_PI_2 && altVision+deltaAlt >= -M_PI_2)
1489 altVision+=deltaAlt;
1490 //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.
1491 //if (altVision+deltaAlt < -M_PI_2) altVision = -M_PI_2 + 0.000001;
1492 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.
1493 if (altVision < -M_PI_2) altVision = -M_PI_2 + 0.000001;
1494 }
1495
1496 // recalc all the position variables
1497 if ((fabs(deltaAz)>1e-10) || (fabs(deltaAlt)>1e-10))
1498 {
1499 setFlagTracking(false);
1500 Vec3d tmp;
1501 StelUtils::spheToRect(azVision, altVision, tmp);
1502 setViewDirectionJ2000(mountFrameToJ2000(tmp));
1503 if (fabs(altVision)>0.95*M_PI_2)
1504 { // do something about zenith
1505 setViewUpVector(Vec3d(-cos(azVision), -sin(azVision), 0.) * (altVision>0. ? 1. : -1. ));
1506 }
1507 else
1508 {
1509 setViewUpVector(Vec3d(0., 0., 1.));
1510 }
1511 }
1512 }
1513
1514
1515 // Make the first screen position correspond to the second (useful for mouse dragging)
dragView(int x1,int y1,int x2,int y2)1516 void StelMovementMgr::dragView(int x1, int y1, int x2, int y2)
1517 {
1518 if (dragTimeMode)
1519 {
1520 core->setTimeRate(0);
1521 Vec3d v1, v2;
1522 const StelProjectorP prj = core->getProjection(StelCore::FrameEquinoxEqu);
1523 prj->unProject(x2,y2, v2);
1524 prj->unProject(x1,y1, v1);
1525 v1[2]=0; v1.normalize();
1526 v2[2]=0; v2.normalize();
1527 double angle = (v2^v1)[2];
1528 double deltaDay = angle/(2.*M_PI)*core->getLocalSiderealDayLength();
1529 core->setJD(core->getJD()+deltaDay);
1530 addTimeDragPoint(x2, y2);
1531 }
1532 else
1533 {
1534 Vec3d tempvec1, tempvec2;
1535 const StelProjectorP prj = core->getProjection(StelCore::FrameJ2000);
1536 prj->unProject(x2,y2, tempvec2);
1537 prj->unProject(x1,y1, tempvec1);
1538 double az1, alt1, az2, alt2;
1539 StelUtils::rectToSphe(&az1, &alt1, j2000ToMountFrame(tempvec1));
1540 StelUtils::rectToSphe(&az2, &alt2, j2000ToMountFrame(tempvec2));
1541 panView(az2-az1, alt1-alt2);
1542 }
1543 setFlagTracking(false);
1544 setFlagLockEquPos(false);
1545 }
1546
1547
1548 // Update autoZoom if activated
updateAutoZoom(double deltaTime)1549 void StelMovementMgr::updateAutoZoom(double deltaTime)
1550 {
1551 if (flagAutoZoom)
1552 {
1553 zoomMove.update(deltaTime);
1554 double newFov = zoomMove.getValue();
1555 if (zoomMove.finished())
1556 flagAutoZoom = 0;
1557 setFov(newFov); // updates currentFov->don't use newFov later!
1558
1559 // In case we have offset center, we want object still visible in center.
1560 if (flagTracking && objectMgr->getWasSelected()) // vision vector locked on selected object
1561 {
1562 Vec3d v, vUp;
1563 switch (mountMode)
1564 {
1565 case MountAltAzimuthal:
1566 v = objectMgr->getSelectedObject()[0]->getAltAzPosAuto(core);
1567 break;
1568 case MountEquinoxEquatorial:
1569 v = objectMgr->getSelectedObject()[0]->getEquinoxEquatorialPosAuto(core);
1570 break;
1571 case MountGalactic:
1572 v = objectMgr->getSelectedObject()[0]->getGalacticPos(core);
1573 break;
1574 case MountSupergalactic:
1575 v = objectMgr->getSelectedObject()[0]->getSupergalacticPos(core);
1576 break;
1577 default:
1578 qWarning() << "StelMovementMgr: unexpected mountMode" << mountMode;
1579 Q_ASSERT(0);
1580 }
1581
1582 double lat, lon; // general: longitudinal, latitudinal
1583 StelUtils::rectToSphe(&lon, &lat, v); // guaranteed to be normalized.
1584 // vUp could usually be (0/0/1) in most cases, unless |lat|==pi/2. We MUST build an adequate Up vector!
1585 if (fabs(lat)>0.9*M_PI_2)
1586 {
1587 vUp = Vec3d(-cos(lon), -sin(lon), 0.) * (lat>0. ? 1. : -1. );
1588 }
1589 else
1590 vUp.set(0.,0.,1.);
1591 double latOffset=static_cast<double>(core->getCurrentStelProjectorParams().viewportCenterOffset[1])*currentFov*M_PI_180;
1592 lat+=latOffset;
1593 StelUtils::spheToRect(lon, lat, v);
1594
1595 if (flagAutoMove)
1596 {
1597 move.aim=mountFrameToJ2000(v);
1598 move.aim.normalize();
1599 move.aim*=2.;
1600 move.aimUp=mountFrameToJ2000(vUp);
1601 move.aimUp.normalize();
1602 }
1603 else
1604 {
1605 setViewDirectionJ2000(mountFrameToJ2000(v));
1606 //qDebug() << "setViewUpVector L1501";
1607 setViewUpVectorJ2000(mountFrameToJ2000(vUp));
1608 }
1609 }
1610 }
1611 }
1612
1613 // Zoom to the given field of view
zoomTo(double aim_fov,float zoomDuration)1614 void StelMovementMgr::zoomTo(double aim_fov, float zoomDuration)
1615 {
1616 zoomDuration /= movementsSpeedFactor;
1617 zoomMove.setTarget(currentFov, aim_fov, zoomDuration);
1618 flagAutoZoom = true;
1619 }
1620
changeFov(double deltaFov)1621 void StelMovementMgr::changeFov(double deltaFov)
1622 {
1623 // if we are zooming in or out
1624 if (fabs(deltaFov)>0)
1625 setFov(currentFov + deltaFov);
1626 }
1627
getAimFov(void) const1628 double StelMovementMgr::getAimFov(void) const
1629 {
1630 return (flagAutoZoom ? zoomMove.getAim() : currentFov);
1631 }
1632
1633 // This is called e.g. when projection changes.
1634 // We clamp this to the user-set user_maxFov (e.g. for planetarium: 180°; GH #1836)
setMaxFov(double max)1635 void StelMovementMgr::setMaxFov(double max)
1636 {
1637 maxFov = qMin(max, userMaxFov);
1638 if (currentFov > maxFov)
1639 {
1640 setFov(maxFov);
1641 }
1642 }
1643
setUserMaxFov(double max)1644 void StelMovementMgr::setUserMaxFov(double max)
1645 {
1646 userMaxFov = qMin(360., max);
1647 if (maxFov>userMaxFov)
1648 setMaxFov(userMaxFov);
1649 else
1650 {
1651 const float prjMaxFov = StelApp::getInstance().getCore()->getProjection(StelProjector::ModelViewTranformP(new StelProjector::Mat4dTransform(Mat4d::identity())))->getMaxFov();
1652 setMaxFov(qMin(userMaxFov, static_cast<double>(prjMaxFov)));
1653 }
1654 emit userMaxFovChanged(userMaxFov);
1655 }
1656
moveViewport(double offsetX,double offsetY,const float duration)1657 void StelMovementMgr::moveViewport(double offsetX, double offsetY, const float duration)
1658 {
1659 //clamp to valid range
1660 offsetX = qBound(-50., offsetX, 50.);
1661 offsetY = qBound(-50., offsetY, 50.);
1662
1663 Vec2d oldTargetViewportOffset = targetViewportOffset;
1664 targetViewportOffset.set(offsetX, offsetY);
1665
1666 if(fabs(offsetX - oldTargetViewportOffset[0]) > 1e-10)
1667 emit viewportHorizontalOffsetTargetChanged(offsetX);
1668 if(fabs(offsetY - oldTargetViewportOffset[1]) > 1e-10)
1669 emit viewportVerticalOffsetTargetChanged(offsetY);
1670
1671 if (duration<=0.0f)
1672 {
1673 //avoid using the timeline to minimize overhead
1674 core->setViewportOffset(offsetX, offsetY);
1675 return;
1676 }
1677
1678 // Frame will now be 0..100, and we must interpolate in handleViewportOffsetMovement(frame) between old and new offsets.
1679 oldViewportOffset.set(core->getViewportHorizontalOffset(), core->getViewportVerticalOffset());
1680
1681 viewportOffsetTimeline->stop();
1682 viewportOffsetTimeline->setDuration(static_cast<int>(1000.f*duration));
1683
1684 //qDebug() << "moveViewport() started, from " << oldViewportOffset.v[0] << "/" << oldViewportOffset.v[1] << " towards " << offsetX << "/" << offsetY;
1685 viewportOffsetTimeline->start();
1686 }
1687
1688 // slot which is connected to the viewportOffsetTimeline and does the actual updates.
handleViewportOffsetMovement(qreal value)1689 void StelMovementMgr::handleViewportOffsetMovement(qreal value)
1690 {
1691 // value is always 0...1
1692 double offsetX=oldViewportOffset.v[0] + (targetViewportOffset.v[0]-oldViewportOffset.v[0])*value;
1693 double offsetY=oldViewportOffset.v[1] + (targetViewportOffset.v[1]-oldViewportOffset.v[1])*value;
1694 //qDebug() << "handleViewportOffsetMovement(" << value << "): Setting viewport offset to " << offsetX << "/" << offsetY;
1695 core->setViewportOffset(offsetX, offsetY);
1696 }
1697
smoothPan(double deltaX,double deltaY,double ptime,bool s)1698 void StelMovementMgr::smoothPan(double deltaX, double deltaY, double ptime, bool s)
1699 {
1700 flagCustomPan = s;
1701 if (s)
1702 {
1703 rateX = deltaX/ptime; // degrees per second
1704 rateY = deltaY/ptime; // degrees per second
1705 setFlagTracking(false);
1706 setFlagLockEquPos(false);
1707 }
1708 else
1709 deltaAz = deltaAlt = 0.0;
1710 }
1711
1712