Kstars

skymapliteevents.cpp
1/*
2 SPDX-FileCopyrightText: 2016 Artem Fedoskin <afedoskin3@gmail.com>
3 SPDX-License-Identifier: GPL-2.0-or-later
4*/
5#include "skymaplite.h"
6#include "kstarsdata.h"
7#include "kstarslite.h"
8
9#include <QtMath>
10
11#include "kstarslite/skypointlite.h"
12#include "kstarslite/skyobjectlite.h"
13
14#include "kstarslite/skyitems/planetsitem.h"
15#include "Options.h"
16#include "projections/projector.h"
17#include "skymapcomposite.h"
18#include "ksutils.h"
19//#include <QTapSensor>
20
22{
23 if ((e->modifiers() & Qt::ControlModifier) && (e->button() == Qt::LeftButton))
24 {
25 ZoomRect.moveCenter(e->pos());
26 setZoomMouseCursor();
27 update(); //refresh without redrawing skymap
28 return;
29 }
30 // if button is down and cursor is not moved set the move cursor after 500 ms
31 QTimer::singleShot(500, this, SLOT(setMouseMoveCursor()));
32
33 // break if point is unusable
34 if (projector()->unusablePoint(e->pos()))
35 return;
36
37 if (!midMouseButtonDown && e->button() == Qt::MidButton)
38 {
39 y0 = 0.5 * height() - e->y(); //record y pixel coordinate for middle-button zooming
40 midMouseButtonDown = true;
41 }
42 if (!mouseButtonDown)
43 {
44 if (e->button() == Qt::LeftButton)
45 {
46 mouseButtonDown = true;
47 }
48
49 //determine RA, Dec of mouse pointer
50 m_MousePoint = projector()->fromScreen(e->pos(), data->lst(), data->geo()->lat());
51 setClickedPoint(&m_MousePoint);
52
53 //Find object nearest to clickedPoint()
54 double maxrad = 1000.0 / Options::zoomFactor();
55 SkyObject *obj = data->skyComposite()->objectNearest(clickedPoint(), maxrad);
57 if (obj)
58 setClickedPoint(obj);
59
60 switch (e->button())
61 {
62 case Qt::LeftButton:
63 {
64 /*QString name;
65 if( clickedObject() )
66 //name = clickedObject()->translatedLongName();
67 else
68 //name = i18n( "Empty sky" );
69 //kstars->statusBar()->changeItem(name, 0 );
70 //kstars->statusBar()->showMessage(name, 0 );
71
72 emit positionClicked(&m_MousePoint);*/
73 }
74
75 break;
76 case Qt::RightButton:
77 /*if( rulerMode ) {
78 // Compute angular distance.
79 slotEndRulerMode();
80 } else {*/
81 // Show popup menu
82 if (clickedObject())
83 {
84 emit objectLiteChanged();
85 }
86 else
87 {
88 emit pointLiteChanged();
89 /* pmenu->createEmptyMenu( clickedPoint() );
90 pmenu->popup( QCursor::pos() );*/
91 }
92 //}
93 break;
94 default:
95 ;
96 }
97 }
98}
99
101{
102 /*if ( ZoomRect.isValid() ) {
103 stopTracking();
104 SkyPoint newcenter = projector()->fromScreen( ZoomRect.center(), data->lst(), data->geo()->lat() );
105 setFocus( &newcenter );
106 setDestination( newcenter );
107
108 //Zoom in on center of Zoom Circle, by a factor equal to the ratio
109 //of the sky pixmap's width to the Zoom Circle's diameter
110 float factor = float(width()) / float(ZoomRect.width());
111 setZoomFactor( Options::zoomFactor() * factor );
112 }*/
113 setDefaultMouseCursor();
114 ZoomRect = QRect(); //invalidate ZoomRect
115
116 /*if(m_previewLegend) {
117 slotCancelLegendPreviewMode();
118 }*/
119
120 //false if double-clicked, because it's unset there.
121 if (mouseButtonDown)
122 {
123 mouseButtonDown = false;
124 if (getSlewing())
125 {
126 setSlewing(false);
127 if (Options::useAltAz())
128 setDestinationAltAz(focus()->alt(), focus()->az(), false);
129 else
131 }
132 forceUpdate(); // is needed because after moving the sky not all stars are shown
133 }
134 // if middle button was pressed unset here
135 midMouseButtonDown = false;
136}
137
139{
140 if (e->button() == Qt::LeftButton && !projector()->unusablePoint(e->pos()))
141 {
142 mouseButtonDown = false;
143 if (e->x() != width() / 2 || e->y() != height() / 2)
144 slotCenter();
145 }
146}
147
149{
150 if (Options::useHoverLabel())
151 {
152 //Start a single-shot timer to monitor whether we are currently hovering.
153 //The idea is that whenever a moveEvent occurs, the timer is reset. It
154 //will only timeout if there are no move events for HOVER_INTERVAL ms
155 m_HoverTimer.start(HOVER_INTERVAL);
156 //DELETE? QToolTip::hideText();
157 }
158
159 //Are we defining a ZoomRect?
160 /*if ( ZoomRect.center().x() > 0 && ZoomRect.center().y() > 0 ) {
161 //cancel operation if the user let go of CTRL
162 if ( !( e->modifiers() & Qt::ControlModifier ) ) {
163 ZoomRect = QRect(); //invalidate ZoomRect
164 update();
165 } else {
166 //Resize the rectangle so that it passes through the cursor position
167 QPoint pcenter = ZoomRect.center();
168 int dx = abs(e->x() - pcenter.x());
169 int dy = abs(e->y() - pcenter.y());
170 if ( dx == 0 || float(dy)/float(dx) > float(height())/float(width()) ) {
171 //Size rect by height
172 ZoomRect.setHeight( 2*dy );
173 ZoomRect.setWidth( 2*dy*width()/height() );
174 } else {
175 //Size rect by height
176 ZoomRect.setWidth( 2*dx );
177 ZoomRect.setHeight( 2*dx*height()/width() );
178 }
179 ZoomRect.moveCenter( pcenter ); //reset center
180
181 update();
182 return;
183 }
184 }
185 */
186 if (projector()->unusablePoint(e->pos()))
187 return; // break if point is unusable
188
189 //determine RA, Dec of mouse pointer
190 m_MousePoint = projector()->fromScreen(e->pos(), data->lst(), data->geo()->lat());
191 double dyPix = 0.5 * height() - e->y();
192 if (midMouseButtonDown) //zoom according to y-offset
193 {
194 float yoff = dyPix - y0;
195 if (yoff > 10)
196 {
197 y0 = dyPix;
198 slotZoomIn();
199 }
200 if (yoff < -10)
201 {
202 y0 = dyPix;
203 slotZoomOut();
204 }
205 }
206 if (mouseButtonDown)
207 {
208 // set the mouseMoveCursor and set slewing to true, if they are not set yet
209 if (!mouseMoveCursor)
210 setMouseMoveCursor();
211 if (!getSlewing())
212 {
213 setSlewing(true);
214 stopTracking(); //toggle tracking off
215 }
216
217 //Update focus such that the sky coords at mouse cursor remain approximately constant
218 if (Options::useAltAz())
219 {
220 m_MousePoint.EquatorialToHorizontal(data->lst(), data->geo()->lat());
221 clickedPoint()->EquatorialToHorizontal(data->lst(), data->geo()->lat());
222 dms dAz = m_MousePoint.az() - clickedPoint()->az();
223 dms dAlt = m_MousePoint.altRefracted() - clickedPoint()->altRefracted();
224 focus()->setAz(focus()->az().Degrees() - dAz.Degrees()); //move focus in opposite direction
225 focus()->setAz(focus()->az().reduce());
226 focus()->setAltRefracted(KSUtils::clamp(focus()->altRefracted().Degrees() - dAlt.Degrees(), -90.0, 90.0));
227 focus()->HorizontalToEquatorial(data->lst(), data->geo()->lat());
228 }
229 else
230 {
231 dms dRA = m_MousePoint.ra() - clickedPoint()->ra();
232 dms dDec = m_MousePoint.dec() - clickedPoint()->dec();
233 focus()->setRA(focus()->ra().Hours() - dRA.Hours()); //move focus in opposite direction
234 focus()->setRA(focus()->ra().reduce());
235 focus()->setDec(KSUtils::clamp(focus()->dec().Degrees() - dDec.Degrees(), -90.0, 90.0));
236 focus()->EquatorialToHorizontal(data->lst(), data->geo()->lat());
237 }
238 //showFocusCoords();
239
240 //redetermine RA, Dec of mouse pointer, using new focus
241 m_MousePoint = projector()->fromScreen(e->pos(), data->lst(), data->geo()->lat());
242 setClickedPoint(&m_MousePoint);
243
244 forceUpdate(); // must be new computed
245 }
246 else //mouse button not down
247 {
248 if (Options::useAltAz())
249 m_MousePoint.EquatorialToHorizontal(data->lst(), data->geo()->lat());
250 emit mousePointChanged(&m_MousePoint);
251 }
252}
253
255{
256 if (e->delta() > 0)
257 {
258 zoomInOrMagStep(e->modifiers());
259 //setRotation(rotation() + 0.1); TEST
260 }
261 else if (e->delta() < 0)
262 {
263 zoomOutOrMagStep(e->modifiers());
264 //setRotation(rotation() - 0.1); TEST
265 }
266}
267
269{
271
272 bool autoMode = false; //Always false for devices that doesn't support automatic mode
273#if defined(Q_OS_ANDROID)
274 autoMode = getAutomaticMode();
275#endif
276
277 if (points.length() == 2)
278 {
279 //Set tapBegan to false because user doesn't tap but either pans or pinches to zoom
280 tapBegan = false;
281 if (projector()->unusablePoint(points[0].pos()) || projector()->unusablePoint(points[1].pos()))
282 return;
283
284 //Pinch to zoom
285 double x_old_diff = qFabs(points[1].lastPos().x() - points[0].lastPos().x());
286 double y_old_diff = qFabs(points[1].lastPos().y() - points[0].lastPos().y());
287
288 //Manhattan distance of old points
289 double md_old = x_old_diff + y_old_diff;
290
291 double x_diff = qFabs(points[1].pos().x() - points[0].pos().x());
292 double y_diff = qFabs(points[1].pos().y() - points[0].pos().y());
293
294 //Manhattan distance of new points
295 double md_new = x_diff + y_diff;
296
297 int zoomThreshold = 5;
298
299 if (md_old - md_new < -zoomThreshold)
300 zoomInOrMagStep(Qt::MetaModifier);
301 else if (md_old - md_new > zoomThreshold)
302 zoomOutOrMagStep(Qt::MetaModifier);
303
304 double x_min = points[1].pos().x() < points[0].pos().x() ? points[1].pos().x() : points[0].pos().x();
305 double y_min = points[1].pos().y() < points[0].pos().y() ? points[1].pos().y() : points[0].pos().y();
306
307 //Center point on the line between 2 touch points used for moveEvent
308 QPointF pinchCenter(x_min + x_diff / 2, y_min + y_diff / 2);
309
310 //Pinch(turn) to rotate
311 QPointF old_vec = points[1].lastPos() - points[0].lastPos();
312 QPointF new_vec = points[1].pos() - points[0].pos();
313
314 double old_vec_len = sqrt((old_vec.x() * old_vec.x()) + (old_vec.y() * old_vec.y()));
315 double new_vec_len = sqrt((new_vec.x() * new_vec.x()) + (new_vec.y() * new_vec.y()));
316
317 //Normalize vectors
318 old_vec = QPointF(old_vec.x() / old_vec_len, old_vec.y() / old_vec_len);
319 new_vec = QPointF(new_vec.x() / new_vec_len, new_vec.y() / new_vec_len);
320
321 double old_atan = qAtan2(old_vec.y(), old_vec.x());
322 double new_atan = qAtan2(new_vec.y(), new_vec.x());
323
324 /*Workaround to solve the strange bug when sometimes signs of qAtan2 results
325 for 2 vectors are different*/
326 if ((new_atan > 0 && old_atan < 0) || (new_atan < 0 && old_atan > 0))
327 {
328 old_atan *= -1;
329 }
330
331 //Get the angle between two vectors
332 /*double delta = new_atan - old_atan;
333
334 //Rotation is under construction
335 if(rotation() > 360) {
336 setRotation(0);
337 } else if(rotation() < 0) {
338 setRotation(360);
339 }
340
341 //Scale the angle to speed up the rotation
342 delta *= 100;
343 setRotation(rotation() + delta);
344 //update(); //Apply rotation*/
345
346 //Allow movement of SkyMapLite while rotating or zooming
347 if (!getCenterLocked() && !autoMode)
348 {
351 if (!pinch)
352 {
353 m_MousePoint = projector()->fromScreen(pinchCenter, data->lst(), data->geo()->lat());
354 setClickedPoint(&m_MousePoint);
355 mouseButtonDown = true;
356 pinch = true;
357 }
359 delete event;
360 }
361
363 {
364 setSlewing(false);
365 if (pinch)
366 {
367 pinch = false;
368 mouseButtonDown = false;
369 }
370 }
371 }
372 else if (points.length() == 1 && !pinch && !autoMode)
373 {
374 QPointF point = points[0].screenPos();
375 //Set clicked point (needed for pan)
376 if (e->type() == QEvent::TouchBegin)
377 {
378 m_MousePoint = projector()->fromScreen(point, data->lst(), data->geo()->lat());
379 setClickedPoint(&m_MousePoint);
380 mouseButtonDown = true;
381 }
382 else if (e->type() == QEvent::TouchEnd)
383 {
384 mouseButtonDown = false;
385 if (getSlewing())
386 {
387 setSlewing(false);
388 if (Options::useAltAz())
389 setDestinationAltAz(focus()->alt(), focus()->az(), false);
390 else
392 }
393 }
394
395 if (!projector()->unusablePoint(points[0].screenPos()))
396 {
397 if (!tapBegan && (e->touchPointStates() & Qt::TouchPointPressed))
398 {
399 //We set tapBegan to true whenever user tapped on the screen
400 tapBegan = true;
401 m_tapBeganTimer.start(100);
402 }
403 else if ((e->touchPointStates() & Qt::TouchPointMoved) || getSlewing())
404 {
405 //Set tapBegan to false because user doesn't tap but either pans or pinches to zoom
406 if (m_tapBeganTimer.remainingTime() > 0)
407 {
408 return;
409 }
410 else
411 {
412 m_tapBeganTimer.stop();
413 }
414 tapBegan = false;
415
419 delete event;
420
421 //If user didn't pan and pinch to zoom tapBegan will be true
422 }
423 else if ((e->touchPointStates() & Qt::TouchPointReleased) && tapBegan)
424 {
425 if (getSlewing())
426 setSlewing(false);
427 tapBegan = false;
428 //Show tap animation
429 emit posClicked(point);
430 //determine RA, Dec of touch
431 m_MousePoint = projector()->fromScreen(point, data->lst(), data->geo()->lat());
432 setClickedPoint(&m_MousePoint);
433
434 //Find object nearest to clickedPoint()
435 double maxrad =
436 1000.0 /
437 Options::
438 zoomFactor(); /* On high zoom-level it is very hard to select the object using touch screen.
439 That's why radius remains constant*/
440 maxrad = qMax(maxrad, 2.5);
441 SkyObject *obj = data->skyComposite()->objectNearest(clickedPoint(), maxrad);
442 setClickedObject(obj);
443 if (obj)
444 setClickedPoint(obj);
445
446 if (clickedObject())
447 {
448 emit objectLiteChanged();
449 }
450 else
451 {
452 emit pointLiteChanged();
453 }
454 }
455 }
456 }
457}
458
459double SkyMapLite::zoomFactor(const int modifier)
460{
461 double factor = (modifier & Qt::ControlModifier) ? DZOOM : 2.0;
462 if (modifier & Qt::ShiftModifier)
463 factor = sqrt(factor);
464 return factor;
465}
466
467void SkyMapLite::zoomInOrMagStep(const int modifier)
468{
469 if (modifier & Qt::AltModifier)
470 incMagLimit(modifier);
471 else if (modifier & Qt::MetaModifier) //Used in pinch-to-zoom gesture
472 {
473 setZoomFactor(Options::zoomFactor() + Options::zoomFactor() * 0.05);
474 }
475 else
476 setZoomFactor(Options::zoomFactor() * zoomFactor(modifier));
477}
478
479void SkyMapLite::zoomOutOrMagStep(const int modifier)
480{
481 if (modifier & Qt::AltModifier)
482 decMagLimit(modifier);
483 else if (modifier & Qt::MetaModifier) //Used in pinch-to-zoom gesture
484 {
485 setZoomFactor(Options::zoomFactor() - Options::zoomFactor() * 0.05);
486 }
487 else
488 setZoomFactor(Options::zoomFactor() / zoomFactor(modifier));
489}
490
491double SkyMapLite::magFactor(const int modifier)
492{
493 double factor = (modifier & Qt::ControlModifier) ? 0.1 : 0.5;
494 if (modifier & Qt::ShiftModifier)
495 factor *= 2.0;
496 return factor;
497}
498
499void SkyMapLite::setMagLim(double magLim)
500{
501 if (m_magLim != magLim)
502 {
503 m_magLim = magLim;
504 if (m_magLim > 5.75954)
505 m_magLim = 5.75954;
506 if (m_magLim < 1.18778)
507 m_magLim = 1.18778;
508 emit magLimChanged(m_magLim);
509
510 Options::setStarDensity(pow(10, (m_magLim - 0.35) / 2.222));
511 //printf("maglim set to %3.1f\n", m_magLim);
512 forceUpdate();
513 }
514}
515
517{
519 emit positionChanged();
520 if (kstars && Options::isTracking())
521 kstars->slotTrack();
522}
523
525{
526 return m_proj->type();
527}
528
529void SkyMapLite::incMagLimit(const int modifier)
530{
531 m_magLim = 2.222 * log10(static_cast<double>(Options::starDensity())) + 0.35;
532 m_magLim += magFactor(modifier);
533 if (m_magLim > 5.75954)
534 m_magLim = 5.75954;
535 emit magLimChanged(m_magLim);
536 Options::setStarDensity(pow(10, (m_magLim - 0.35) / 2.222));
537 //printf("maglim set to %3.1f\n", m_magLim);
538 forceUpdate();
539}
540
541void SkyMapLite::decMagLimit(const int modifier)
542{
543 m_magLim = 2.222 * log10(static_cast<double>(Options::starDensity())) + 0.35;
544 m_magLim -= magFactor(modifier);
545 if (m_magLim < 1.18778)
546 m_magLim = 1.18778;
547 emit magLimChanged(m_magLim);
548 Options::setStarDensity(pow(10, (m_magLim - 0.35) / 2.222));
549 //printf("maglim set to %3.1f\n", m_magLim);
550 forceUpdate();
551}
const CachingDms * lat() const
Definition geolocation.h:70
CachingDms * lst()
Definition kstarsdata.h:226
GeoLocation * geo()
Definition kstarsdata.h:232
SkyMapComposite * skyComposite()
Definition kstarsdata.h:168
This class loads QML files and connects SkyMapLite and KStarsData Unlike KStars class it is not a mai...
Definition kstarslite.h:47
static KStarsLite * Instance()
Definition kstarslite.h:77
void slotTrack()
start tracking clickedPoint or stop tracking if we are already tracking some object
virtual SkyPoint fromScreen(const QPointF &p, dms *LST, const dms *lat, bool onlyAltAz=false) const
Determine RA, Dec coordinates of the pixel at (dx, dy), which are the screen pixel coordinate offsets...
virtual Q_INVOKABLE Projection type() const =0
Return the type of this projection.
SkyObject * objectNearest(SkyPoint *p, double &maxrad) override
void setZoomFactor(double factor)
@ Set zoom factor.
void slotCenter()
Center the display at the point ClickedPoint.
const Projector * projector() const
Get the current projector.
Definition skymaplite.h:323
Q_INVOKABLE uint projType() const
used in QML
SkyPoint * focus()
Retrieve the Focus point; the position on the sky at the center of the skymap.
Definition skymaplite.h:125
void setDestination(const SkyPoint &f)
sets the destination point of the sky map.
void forceUpdate()
Recalculates the positions of objects in the sky, and then repaints the sky map.
virtual void mousePressEvent(QMouseEvent *e) override
Process keystrokes:
void setClickedObject(SkyObject *o)
Set the ClickedObject pointer to the argument.
void slotZoomIn()
Zoom in one step.
virtual void mouseDoubleClickEvent(QMouseEvent *e) override
Center SkyMap at double-clicked location
void setMagLim(double magLim)
set magnitude limit
SkyObject * clickedObject() const
Retrieve the object nearest to a mouse click event.
Definition skymaplite.h:234
virtual void touchEvent(QTouchEvent *e) override
this function handles zooming in and out using "pinch to zoom" gesture
void magLimChanged(double magLim)
Emitted when magnitude limit is changed.
virtual void mouseReleaseEvent(QMouseEvent *e) override
set mouseButtonDown==false, slewing==false
bool getSlewing() const
Proxy method for SkyMapDrawAbstract::drawObjectLabels()
Definition skymaplite.h:422
void objectLiteChanged()
Wrapper of ClickedObject for QML.
void mousePointChanged(SkyPoint *)
Emitted when position under mouse changed.
void posClicked(QPointF pos)
Emitted when user clicks on SkyMapLite (analogous to positionClicked but sends QPoint)
void setDestinationAltAz(const dms &alt, const dms &az, bool altIsRefracted)
sets the destination point of the sky map, using its alt/az coordinates.
void pointLiteChanged()
Wrapper of ClickedPoint for QML.
SkyPoint * clickedPoint()
Retrieve the ClickedPoint position.
Definition skymaplite.h:217
void setClickedPoint(SkyPoint *f)
Set the ClickedPoint to the skypoint given as an argument.
virtual void mouseMoveEvent(QMouseEvent *e) override
This function does several different things depending on the state of the program:
void positionChanged()
Emitted when pointing changed.
virtual void wheelEvent(QWheelEvent *e) override
Zoom in and out with the mouse wheel.
void stopTracking()
Convenience function for shutting off tracking mode.
bool getAutomaticMode() const
True if automatic mode is on (SkyMapLite is controlled by smartphones accelerometer magnetometer)
Definition skymaplite.h:438
void setSlewing(bool newSlewing)
sets whether SkyMapLite is being slewed
double magLim
magnitude limit.
Definition skymaplite.h:62
void slotZoomOut()
Zoom out one step.
bool getCenterLocked()
getter for centerLocked
Definition skymaplite.h:409
Provides all necessary information about an object in the sky: its coordinates, name(s),...
Definition skyobject.h:42
MouseButtonPress
Type type() const const
Qt::KeyboardModifiers modifiers() const const
qsizetype length() const const
QPoint pos() const const
int x() const const
int y() const const
qreal x() const const
qreal y() const const
virtual bool event(QEvent *ev) override
void update()
void moveCenter(const QPoint &position)
Qt::MouseButton button() const const
ControlModifier
LeftButton
TouchPointReleased
void start()
void stop()
const QList< QEventPoint > & touchPoints() const const
QEventPoint::States touchPointStates() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:16:41 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.