diff --git a/kstars/indi/clientmanagerlite.h b/kstars/indi/clientmanagerlite.h index fd14c04cb..8f397715c 100644 --- a/kstars/indi/clientmanagerlite.h +++ b/kstars/indi/clientmanagerlite.h @@ -1,263 +1,275 @@ /** ************************************************************************* clientmanagerlite.h - K Desktop Planetarium ------------------- begin : 10/07/2016 copyright : (C) 2016 by Artem Fedoskin email : afedoskin3@gmail.com ***************************************************************************/ /** ************************************************************************* * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #pragma once #include "baseclientqt.h" #include "indicommon.h" #include "indistd.h" #include #include #include #include class QFileDialog; class QQmlContext; using namespace INDI; class TelescopeLite; struct DeviceInfoLite { explicit DeviceInfoLite(INDI::BaseDevice *dev); ~DeviceInfoLite(); INDI::BaseDevice *device { nullptr }; /// Motion control std::unique_ptr telescope; }; /** * @class ClientManagerLite * * @author Artem Fedoskin * @version 1.0 */ class ClientManagerLite : public INDI::BaseClientQt { - Q_OBJECT - Q_PROPERTY(QString connectedHost READ connectedHost WRITE setConnectedHost NOTIFY connectedHostChanged) - Q_PROPERTY(bool connected READ isConnected WRITE setConnected NOTIFY connectedChanged) - - /** - * A wrapper for Options::lastServer(). Used to store last used server if user successfully - * connected to some server at least once. - **/ - Q_PROPERTY(QString lastUsedServer READ getLastUsedServer WRITE setLastUsedServer NOTIFY lastUsedServerChanged) - - /** - * A wrapper for Options::lastServer(). Used to store last used port if user successfully - * connected to some server at least once. - **/ - Q_PROPERTY(int lastUsedPort READ getLastUsedPort WRITE setLastUsedPort NOTIFY lastUsedPortChanged) - - /** - * A wrapper for Options::lastServer(). Used to store last Web Manager used port if user successfully - * connected at least once. - **/ - Q_PROPERTY(int lastUsedWebManagerPort READ getLastUsedWebManagerPort WRITE setLastUsedWebManagerPort - NOTIFY lastUsedWebManagerPortChanged) - public: - typedef enum { UPLOAD_CLIENT, UPLOAD_LOCAL, UPLOAD_BOTH } UploadMode; - - explicit ClientManagerLite(QQmlContext& main_context); - virtual ~ClientManagerLite(); - - Q_INVOKABLE bool setHost(const QString &ip, unsigned int port); - Q_INVOKABLE void disconnectHost(); - - /** - * Get the profiles from Web Manager - * - * @param ip IP address - * @param port Port number - * - * The process is async and the results are stored in @a webMProfiles. Once this - * request finishes, the server status is queried from the server. - */ - Q_INVOKABLE void getWebManagerProfiles(const QString &ip, unsigned int port); - - /** - * Start an INDI server with a Web Manager profile - * - * @param profile Profile name - */ - Q_INVOKABLE void startWebManagerProfile(const QString &profile); - - /** Stop the INDI server with an active Web Manager profile */ - Q_INVOKABLE void stopWebManagerProfile(); - - /** Handle the errors of the async Web Manager requests */ - Q_INVOKABLE void webManagerReplyError(QNetworkReply::NetworkError code); - - /** Do actions when async Web Manager requests are finished */ - Q_INVOKABLE void webManagerReplyFinished(); - - Q_INVOKABLE TelescopeLite *getTelescope(); - - QString connectedHost() { return m_connectedHost; } - void setConnectedHost(const QString &connectedHost); - void setConnected(bool connected); - - /** - * Set the INDI Control Page - * - * @param page Reference to the QML page - */ - void setIndiControlPage(QObject &page) { indiControlPage = &page; }; - - /** - * @brief syncLED - * @param device device name - * @param property property name - * @param name of Light which LED needs to be synced - * @return color of state - */ - Q_INVOKABLE QString syncLED(const QString &device, const QString &property, const QString &name = ""); - - void buildTextGUI(INDI::Property *property); - void buildNumberGUI(INDI::Property *property); - void buildMenuGUI(INDI::Property *property); - void buildSwitchGUI(INDI::Property *property, PGui guiType); - void buildSwitch(bool buttonGroup, ISwitch *sw, INDI::Property *property, bool exclusive = false, - PGui guiType = PG_BUTTONS); - void buildLightGUI(INDI::Property *property); - //void buildBLOBGUI(INDI::Property *property); - - Q_INVOKABLE void sendNewINDISwitch(const QString &deviceName, const QString &propName, const QString &name); - Q_INVOKABLE void sendNewINDISwitch(const QString &deviceName, const QString &propName, int index); - - Q_INVOKABLE void sendNewINDINumber(const QString &deviceName, const QString &propName, const QString &numberName, - double value); - Q_INVOKABLE void sendNewINDIText(const QString &deviceName, const QString &propName, const QString &fieldName, - const QString &text); - - bool isConnected() { return m_connected; } - Q_INVOKABLE bool isDeviceConnected(const QString &deviceName); - - QList getDevices() { return m_devices; } - - Q_INVOKABLE QString getLastUsedServer(); - Q_INVOKABLE void setLastUsedServer(const QString &server); - - Q_INVOKABLE int getLastUsedPort(); - Q_INVOKABLE void setLastUsedPort(int port); - - Q_INVOKABLE int getLastUsedWebManagerPort(); - Q_INVOKABLE void setLastUsedWebManagerPort(int port); - - /** - * @brief saveDisplayImage - * @return true if image was saved false otherwise - */ - Q_INVOKABLE bool saveDisplayImage(); - - void clearDevices(); - - private slots: - - void connectNewDevice(const QString& device_name); - - protected: - virtual void newDevice(INDI::BaseDevice *dp); - virtual void removeDevice(INDI::BaseDevice *dp); - virtual void newProperty(INDI::Property *property); - virtual void removeProperty(INDI::Property *property); - virtual void newBLOB(IBLOB *bp); - virtual void newSwitch(ISwitchVectorProperty *svp); - virtual void newNumber(INumberVectorProperty *nvp); - virtual void newMessage(INDI::BaseDevice *dp, int messageID); - virtual void newText(ITextVectorProperty *tvp); - virtual void newLight(ILightVectorProperty *lvp); - virtual void serverConnected() {} - virtual void serverDisconnected(int exit_code); - signals: - //Device - void newINDIDevice(QString deviceName); - void removeINDIDevice(QString deviceName); - void deviceConnected(QString deviceName, bool isConnected); - - void newINDIProperty(QString deviceName, QString propName, QString groupName, QString type, QString label); - - void createINDIText(QString deviceName, QString propName, QString propLabel, QString fieldName, QString propText, - bool read, bool write); - - void createINDINumber(QString deviceName, QString propName, QString propLabel, QString numberName, QString propText, - bool read, bool write, bool scale); - - void createINDIButton(QString deviceName, QString propName, QString propText, QString switchName, bool read, - bool write, bool exclusive, bool checked, bool checkable); - void createINDIRadio(QString deviceName, QString propName, QString propText, QString switchName, bool read, - bool write, bool exclusive, bool checked, bool enabled); - - void createINDIMenu(QString deviceName, QString propName, QString switchLabel, QString switchName, bool isSelected); - - void createINDILight(QString deviceName, QString propName, QString label, QString lightName); - - void removeINDIProperty(QString deviceName, QString groupName, QString propName); - - //Update signals - void newINDISwitch(QString deviceName, QString propName, QString switchName, bool isOn); - void newINDINumber(QString deviceName, QString propName, QString numberName, QString value); - void newINDIText(QString deviceName, QString propName, QString fieldName, QString text); - void newINDIMessage(QString message); - void newINDILight(QString deviceName, QString propName); - void newINDIBLOBImage(QString deviceName, bool isLoaded); - void newLEDState(QString deviceName, QString propName); // to sync LED for properties - - void connectedHostChanged(QString); - void connectedChanged(bool); - void telescopeAdded(TelescopeLite *newTelescope); - void telescopeRemoved(TelescopeLite *delTelescope); - void telescopeConnected(TelescopeLite *telescope); - void telescopeDisconnected(); - - void lastUsedServerChanged(); - void lastUsedPortChanged(); - void lastUsedWebManagerPortChanged(); - - private: - bool processBLOBasCCD(IBLOB *bp); - - /// Qml context - QQmlContext& context; - QList m_devices; - QString m_connectedHost; - bool m_connected { false }; - char BLOBFilename[MAXINDIFILENAME]; - QImage displayImage; - /// INDI Control Page - QObject* indiControlPage; - /// Manager for the JSON requests to the Web Manager - QNetworkAccessManager manager; - /// Network reply for querying profiles from the Web Manager - std::unique_ptr webMProfilesReply; - /// Network reply for Web Manager status - std::unique_ptr webMStatusReply; - /// Network reply to stop the active profile in the Web Manager - std::unique_ptr webMStopProfileReply; - /// Network reply to start a profile in the Web Manager - std::unique_ptr webMStartProfileReply; - /// Web Manager profiles - QStringList webMProfiles; - TelescopeLite *m_telescope { nullptr }; + Q_OBJECT + Q_PROPERTY(QString connectedHost READ connectedHost WRITE setConnectedHost NOTIFY connectedHostChanged) + Q_PROPERTY(bool connected READ isConnected WRITE setConnected NOTIFY connectedChanged) + + /** + * A wrapper for Options::lastServer(). Used to store last used server if user successfully + * connected to some server at least once. + **/ + Q_PROPERTY(QString lastUsedServer READ getLastUsedServer WRITE setLastUsedServer NOTIFY lastUsedServerChanged) + + /** + * A wrapper for Options::lastServer(). Used to store last used port if user successfully + * connected to some server at least once. + **/ + Q_PROPERTY(int lastUsedPort READ getLastUsedPort WRITE setLastUsedPort NOTIFY lastUsedPortChanged) + + /** + * A wrapper for Options::lastServer(). Used to store last Web Manager used port if user successfully + * connected at least once. + **/ + Q_PROPERTY(int lastUsedWebManagerPort READ getLastUsedWebManagerPort WRITE setLastUsedWebManagerPort + NOTIFY lastUsedWebManagerPortChanged) + public: + typedef enum { UPLOAD_CLIENT, UPLOAD_LOCAL, UPLOAD_BOTH } UploadMode; + + explicit ClientManagerLite(QQmlContext &main_context); + virtual ~ClientManagerLite(); + + Q_INVOKABLE bool setHost(const QString &ip, unsigned int port); + Q_INVOKABLE void disconnectHost(); + + /** + * Get the profiles from Web Manager + * + * @param ip IP address + * @param port Port number + * + * The process is async and the results are stored in @a webMProfiles. Once this + * request finishes, the server status is queried from the server. + */ + Q_INVOKABLE void getWebManagerProfiles(const QString &ip, unsigned int port); + + /** + * Start an INDI server with a Web Manager profile + * + * @param profile Profile name + */ + Q_INVOKABLE void startWebManagerProfile(const QString &profile); + + /** Stop the INDI server with an active Web Manager profile */ + Q_INVOKABLE void stopWebManagerProfile(); + + /** Handle the errors of the async Web Manager requests */ + Q_INVOKABLE void webManagerReplyError(QNetworkReply::NetworkError code); + + /** Do actions when async Web Manager requests are finished */ + Q_INVOKABLE void webManagerReplyFinished(); + + Q_INVOKABLE TelescopeLite *getTelescope(); + + QString connectedHost() + { + return m_connectedHost; + } + void setConnectedHost(const QString &connectedHost); + void setConnected(bool connected); + + /** + * Set the INDI Control Page + * + * @param page Reference to the QML page + */ + void setIndiControlPage(QObject &page) + { + indiControlPage = &page; + }; + + /** + * @brief syncLED + * @param device device name + * @param property property name + * @param name of Light which LED needs to be synced + * @return color of state + */ + Q_INVOKABLE QString syncLED(const QString &device, const QString &property, const QString &name = ""); + + void buildTextGUI(INDI::Property *property); + void buildNumberGUI(INDI::Property *property); + void buildMenuGUI(INDI::Property *property); + void buildSwitchGUI(INDI::Property *property, PGui guiType); + void buildSwitch(bool buttonGroup, ISwitch *sw, INDI::Property *property, bool exclusive = false, + PGui guiType = PG_BUTTONS); + void buildLightGUI(INDI::Property *property); + //void buildBLOBGUI(INDI::Property *property); + + Q_INVOKABLE void sendNewINDISwitch(const QString &deviceName, const QString &propName, const QString &name); + Q_INVOKABLE void sendNewINDISwitch(const QString &deviceName, const QString &propName, int index); + + Q_INVOKABLE void sendNewINDINumber(const QString &deviceName, const QString &propName, const QString &numberName, + double value); + Q_INVOKABLE void sendNewINDIText(const QString &deviceName, const QString &propName, const QString &fieldName, + const QString &text); + + bool isConnected() + { + return m_connected; + } + Q_INVOKABLE bool isDeviceConnected(const QString &deviceName); + + QList getDevices() + { + return m_devices; + } + + Q_INVOKABLE QString getLastUsedServer(); + Q_INVOKABLE void setLastUsedServer(const QString &server); + + Q_INVOKABLE int getLastUsedPort(); + Q_INVOKABLE void setLastUsedPort(int port); + + Q_INVOKABLE int getLastUsedWebManagerPort(); + Q_INVOKABLE void setLastUsedWebManagerPort(int port); + + /** + * @brief saveDisplayImage + * @return true if image was saved false otherwise + */ + Q_INVOKABLE bool saveDisplayImage(); + + void clearDevices(); + + private slots: + + void connectNewDevice(const QString &device_name); + + protected: + virtual void newDevice(INDI::BaseDevice *dp) override; + virtual void removeDevice(INDI::BaseDevice *dp) override; + virtual void newProperty(INDI::Property *property) override; + virtual void removeProperty(INDI::Property *property) override; + virtual void newBLOB(IBLOB *bp) override; + virtual void newSwitch(ISwitchVectorProperty *svp) override; + virtual void newNumber(INumberVectorProperty *nvp) override; + virtual void newMessage(INDI::BaseDevice *dp, int messageID) override; + virtual void newText(ITextVectorProperty *tvp) override; + virtual void newLight(ILightVectorProperty *lvp) override; + virtual void serverConnected() override {} + virtual void serverDisconnected(int exit_code) override; + signals: + //Device + void newINDIDevice(QString deviceName); + void removeINDIDevice(QString deviceName); + void deviceConnected(QString deviceName, bool isConnected); + + void newINDIProperty(QString deviceName, QString propName, QString groupName, QString type, QString label); + + void createINDIText(QString deviceName, QString propName, QString propLabel, QString fieldName, QString propText, + bool read, bool write); + + void createINDINumber(QString deviceName, QString propName, QString propLabel, QString numberName, QString propText, + bool read, bool write, bool scale); + + void createINDIButton(QString deviceName, QString propName, QString propText, QString switchName, bool read, + bool write, bool exclusive, bool checked, bool checkable); + void createINDIRadio(QString deviceName, QString propName, QString propText, QString switchName, bool read, + bool write, bool exclusive, bool checked, bool enabled); + + void createINDIMenu(QString deviceName, QString propName, QString switchLabel, QString switchName, bool isSelected); + + void createINDILight(QString deviceName, QString propName, QString label, QString lightName); + + void removeINDIProperty(QString deviceName, QString groupName, QString propName); + + //Update signals + void newINDISwitch(QString deviceName, QString propName, QString switchName, bool isOn); + void newINDINumber(QString deviceName, QString propName, QString numberName, QString value); + void newINDIText(QString deviceName, QString propName, QString fieldName, QString text); + void newINDIMessage(QString message); + void newINDILight(QString deviceName, QString propName); + void newINDIBLOBImage(QString deviceName, bool isLoaded); + void newLEDState(QString deviceName, QString propName); // to sync LED for properties + + void connectedHostChanged(QString); + void connectedChanged(bool); + void telescopeAdded(TelescopeLite *newTelescope); + void telescopeRemoved(TelescopeLite *delTelescope); + void telescopeConnected(TelescopeLite *telescope); + void telescopeDisconnected(); + + void lastUsedServerChanged(); + void lastUsedPortChanged(); + void lastUsedWebManagerPortChanged(); + + private: + bool processBLOBasCCD(IBLOB *bp); + + /// Qml context + QQmlContext &context; + QList m_devices; + QString m_connectedHost; + bool m_connected { false }; + char BLOBFilename[MAXINDIFILENAME]; + QImage displayImage; + /// INDI Control Page + QObject* indiControlPage; + /// Manager for the JSON requests to the Web Manager + QNetworkAccessManager manager; + /// Network reply for querying profiles from the Web Manager + std::unique_ptr webMProfilesReply; + /// Network reply for Web Manager status + std::unique_ptr webMStatusReply; + /// Network reply to stop the active profile in the Web Manager + std::unique_ptr webMStopProfileReply; + /// Network reply to start a profile in the Web Manager + std::unique_ptr webMStartProfileReply; + /// Web Manager profiles + QStringList webMProfiles; + TelescopeLite *m_telescope { nullptr }; #ifdef ANDROID - QString defaultImageType; - QString defaultImagesLocation; + QString defaultImageType; + QString defaultImagesLocation; #endif }; diff --git a/kstars/kstarslite/imageprovider.h b/kstars/kstarslite/imageprovider.h index ab89eb32a..6a9429cd0 100644 --- a/kstars/kstarslite/imageprovider.h +++ b/kstars/kstarslite/imageprovider.h @@ -1,44 +1,44 @@ /** ************************************************************************* imageprovider.h - K Desktop Planetarium ------------------- begin : 22/07/2016 copyright : (C) 2016 by Artem Fedoskin email : afedoskin3@gmail.com ***************************************************************************/ /** ************************************************************************* * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef IMAGEPROVIDER_H_ #define IMAGEPROVIDER_H_ #include /** * @class ImageProvider * This class makes it possible to use QImages from C++ in QML * * @author Artem Fedoskin * @version 1.0 */ class ImageProvider : public QQuickImageProvider { - public: - ImageProvider(); - /** @short Get image by id - * @return image of size requestedSize - **/ - virtual QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize); - /** - * @short Add image to the list of images with the given id - */ - void addImage(const QString &id, QImage image); + public: + ImageProvider(); + /** @short Get image by id + * @return image of size requestedSize + **/ + virtual QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize) override; + /** + * @short Add image to the list of images with the given id + */ + void addImage(const QString &id, QImage image); - private: - QHash images; + private: + QHash images; }; #endif diff --git a/kstars/skymaplite.cpp b/kstars/skymaplite.cpp index 6712620af..416d83934 100644 --- a/kstars/skymaplite.cpp +++ b/kstars/skymaplite.cpp @@ -1,1101 +1,1107 @@ /** ************************************************************************* skymaplite.cpp - K Desktop Planetarium ------------------- begin : 30/04/2016 copyright : (C) 2016 by Artem Fedoskin email : afedoskin3@gmail.com ***************************************************************************/ /** ************************************************************************* * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "skymaplite.h" #include "kstarsdata.h" #include "kstarslite.h" #include "indi/inditelescopelite.h" #include "indi/clientmanagerlite.h" #include "kstarslite/skyitems/telescopesymbolsitem.h" #include "projections/projector.h" #include "projections/lambertprojector.h" #include "projections/gnomonicprojector.h" #include "projections/stereographicprojector.h" #include "projections/orthographicprojector.h" #include "projections/azimuthalequidistantprojector.h" #include "projections/equirectangularprojector.h" #include "kstarslite/skypointlite.h" #include "kstarslite/skyobjectlite.h" #include "skylabeler.h" #include "Options.h" #include "skymesh.h" #include "kstarslite/skyitems/rootnode.h" #include "kstarslite/skyitems/skynodes/skynode.h" #include "ksplanetbase.h" #include "ksutils.h" #include //#include #include #include #include #include #include #include #include "kstarslite/deviceorientation.h" namespace { // Draw bitmap for zoom cursor. Width is size of pen to draw with. QBitmap zoomCursorBitmap(int width) { QBitmap b(32, 32); b.fill(Qt::color0); int mx = 16, my = 16; // Begin drawing QPainter p; p.begin(&b); p.setPen(QPen(Qt::color1, width)); p.drawEllipse(mx - 7, my - 7, 14, 14); p.drawLine(mx + 5, my + 5, mx + 11, my + 11); p.end(); return b; } // Draw bitmap for default cursor. Width is size of pen to draw with. QBitmap defaultCursorBitmap(int width) { QBitmap b(32, 32); b.fill(Qt::color0); int mx = 16, my = 16; // Begin drawing QPainter p; p.begin(&b); p.setPen(QPen(Qt::color1, width)); // 1. diagonal p.drawLine(mx - 2, my - 2, mx - 8, mx - 8); p.drawLine(mx + 2, my + 2, mx + 8, mx + 8); // 2. diagonal p.drawLine(mx - 2, my + 2, mx - 8, mx + 8); p.drawLine(mx + 2, my - 2, mx + 8, mx - 8); p.end(); return b; } } -SkyMapLite *SkyMapLite::pinstance = 0; +SkyMapLite *SkyMapLite::pinstance = nullptr; RootNode *SkyMapLite::m_rootNode = nullptr; int SkyMapLite::starColorMode = 0; SkyMapLite::SkyMapLite() : data(KStarsData::Instance()) #if defined(Q_OS_ANDROID) - , + , m_deviceOrientation(new DeviceOrientation(this)) #endif { setAcceptHoverEvents(true); setAcceptedMouseButtons(Qt::AllButtons); setFlag(ItemHasContents, true); m_rootNode = nullptr; m_magLim = 2.222 * log10(static_cast(Options::starDensity())) + 0.35; setSlewing(false); m_ClickedObjectLite = new SkyObjectLite; m_ClickedPointLite = new SkyPointLite; qmlRegisterType("KStarsLite", 1, 0, "SkyObjectLite"); qmlRegisterType("KStarsLite", 1, 0, "SkyPointLite"); m_tapBeganTimer.setSingleShot(true); setupProjector(); // Set pinstance to yourself pinstance = this; connect(this, SIGNAL(destinationChanged()), this, SLOT(slewFocus())); connect(KStarsData::Instance(), SIGNAL(skyUpdate(bool)), this, SLOT(slotUpdateSky(bool))); ClientManagerLite *clientMng = KStarsLite::Instance()->clientManagerLite(); connect(clientMng, &ClientManagerLite::telescopeAdded, - [this](TelescopeLite *newTelescope) { this->m_newTelescopes.append(newTelescope->getDevice()); }); + [this](TelescopeLite * newTelescope) + { + this->m_newTelescopes.append(newTelescope->getDevice()); + }); connect(clientMng, &ClientManagerLite::telescopeRemoved, - [this](TelescopeLite *newTelescope) { this->m_delTelescopes.append(newTelescope->getDevice()); }); + [this](TelescopeLite * newTelescope) + { + this->m_delTelescopes.append(newTelescope->getDevice()); + }); #if defined(Q_OS_ANDROID) //Automatic mode automaticModeTimer.setInterval(5); connect(&automaticModeTimer, SIGNAL(timeout()), this, SLOT(updateAutomaticMode())); setAutomaticMode(false); #endif } QSGNode *SkyMapLite::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData) { Q_UNUSED(updatePaintNodeData); RootNode *n = static_cast(oldNode); /* This code deletes all nodes that are representing dynamic stars and not needed anymore (under construction) */ //qDeleteAll(m_deleteNodes); //m_deleteNodes.clear(); if (m_loadingFinished && isInitialized) { if (!n) { n = new RootNode(); m_rootNode = n; } /** Add or delete telescope crosshairs **/ if (m_newTelescopes.count() > 0) { foreach (INDI::BaseDevice *telescope, m_newTelescopes) { n->telescopeSymbolsItem()->addTelescope(telescope); } m_newTelescopes.clear(); } if (m_delTelescopes.count() > 0) { foreach (INDI::BaseDevice *telescope, m_delTelescopes) { n->telescopeSymbolsItem()->removeTelescope(telescope); } m_delTelescopes.clear(); } //Notify RootNode that textures for point node should be recreated n->update(clearTextures); clearTextures = false; } //Memory Leaks test /*if(m_loadingFinished) { if(!n) { n = new RootNode(); } n->testLeakAdd(); n->update(); m_loadingFinished = false; } else { if (n) { n->testLeakDelete(); } m_loadingFinished = true; }*/ return n; } double SkyMapLite::deleteLimit() { double lim = (MAXZOOM / MINZOOM) / sqrt(Options::zoomFactor()) / 3; //(MAXZOOM/MINZOOM - Options::zoomFactor())/130; return lim; } void SkyMapLite::deleteSkyNode(SkyNode *skyNode) { m_deleteNodes.append(skyNode); } QSGTexture *SkyMapLite::getCachedTexture(int size, char spType) { return textureCache[harvardToIndex(spType)][size]; } SkyMapLite *SkyMapLite::createInstance() { delete pinstance; pinstance = new SkyMapLite(); return pinstance; } void SkyMapLite::initialize(QQuickItem *parent) { if (parent) { setParentItem(parent); // Whenever the wrapper's(parent) dimensions changed, change SkyMapLite too connect(parent, &QQuickItem::widthChanged, this, &SkyMapLite::resizeItem); connect(parent, &QQuickItem::heightChanged, this, &SkyMapLite::resizeItem); isInitialized = true; } resizeItem(); /* Set initial size pf SkyMapLite. Without it on Android SkyMapLite is not displayed until screen orientation is not changed*/ //Initialize images for stars initStarImages(); } SkyMapLite::~SkyMapLite() { // Delete image cache for (auto &imgCache : imageCache) qDeleteAll(imgCache); // Delete textures generated from image cache for (auto &tCache : textureCache) qDeleteAll(tCache); } void SkyMapLite::setFocus(SkyPoint *p) { setFocus(p->ra(), p->dec()); } void SkyMapLite::setFocus(const dms &ra, const dms &dec) { Options::setFocusRA(ra.Hours()); Options::setFocusDec(dec.Degrees()); focus()->set(ra, dec); focus()->EquatorialToHorizontal(data->lst(), data->geo()->lat()); } void SkyMapLite::setFocusAltAz(const dms &alt, const dms &az) { Options::setFocusRA(focus()->ra().Hours()); Options::setFocusDec(focus()->dec().Degrees()); focus()->setAlt(alt); focus()->setAz(az); focus()->HorizontalToEquatorial(data->lst(), data->geo()->lat()); setSlewing(false); forceUpdate(); //need a total update, or slewing with the arrow keys doesn't work. } void SkyMapLite::setDestination(const SkyPoint &p) { setDestination(p.ra(), p.dec()); } void SkyMapLite::setDestination(const dms &ra, const dms &dec) { destination()->set(ra, dec); destination()->EquatorialToHorizontal(data->lst(), data->geo()->lat()); emit destinationChanged(); } void SkyMapLite::setDestinationAltAz(const dms &alt, const dms &az) { destination()->setAlt(alt); destination()->setAz(az); destination()->HorizontalToEquatorial(data->lst(), data->geo()->lat()); emit destinationChanged(); } void SkyMapLite::setClickedPoint(SkyPoint *f) { ClickedPoint = *f; m_ClickedPointLite->setPoint(f); } void SkyMapLite::setClickedObject(SkyObject *o) { ClickedObject = o; m_ClickedObjectLite->setObject(o); } void SkyMapLite::setFocusObject(SkyObject *o) { FocusObject = o; if (FocusObject) Options::setFocusObject(FocusObject->name()); else Options::setFocusObject(i18n("nothing")); } void SkyMapLite::slotCenter() { /*KStars* kstars = KStars::Instance(); TrailObject* trailObj = dynamic_cast( focusObject() );*/ setFocusPoint(clickedPoint()); if (Options::useAltAz()) { focusPoint()->updateCoords(data->updateNum(), true, data->geo()->lat(), data->lst(), false); focusPoint()->EquatorialToHorizontal(data->lst(), data->geo()->lat()); } else { focusPoint()->updateCoords(data->updateNum(), true, data->geo()->lat(), data->lst(), false); } qDebug() << "Centering on " << focusPoint()->ra().toHMSString() << " " << focusPoint()->dec().toDMSString(); //clear the planet trail of old focusObject, if it was temporary /*if( trailObj && data->temporaryTrail ) { trailObj->clearTrail(); data->temporaryTrail = false; }*/ //If the requested object is below the opaque horizon, issue a warning message //(unless user is already pointed below the horizon) if (Options::useAltAz() && Options::showGround() && focus()->alt().Degrees() > -1.0 && - focusPoint()->alt().Degrees() < -1.0) + focusPoint()->alt().Degrees() < -1.0) { QString caption = i18n("Requested Position Below Horizon"); QString message = i18n("The requested position is below the horizon.\nWould you like to go there anyway?"); /*if ( KMessageBox::warningYesNo( this, message, caption, KGuiItem(i18n("Go Anyway")), KGuiItem(i18n("Keep Position")), "dag_focus_below_horiz" )==KMessageBox::No ) { setClickedObject( nullptr ); setFocusObject( nullptr ); Options::setIsTracking( false ); return; }*/ } //set FocusObject before slewing. Otherwise, KStarsData::updateTime() can reset //destination to previous object... setFocusObject(ClickedObject); Options::setIsTracking(true); /*if ( kstars ) { kstars->actionCollection()->action("track_object")->setIcon( QIcon::fromTheme("document-encrypt") ); kstars->actionCollection()->action("track_object")->setText( i18n( "Stop &Tracking" ) ); }*/ //If focusObject is a SS body and doesn't already have a trail, set the temporaryTrail /*if( Options::useAutoTrail() && trailObj && trailObj->hasTrail() ) { trailObj->addToTrail(); data->temporaryTrail = true; }*/ //update the destination to the selected coordinates if (Options::useAltAz()) { setDestinationAltAz(focusPoint()->altRefracted(), focusPoint()->az()); } else { setDestination(*focusPoint()); } focusPoint()->EquatorialToHorizontal(data->lst(), data->geo()->lat()); //display coordinates in statusBar emit mousePointChanged(focusPoint()); //showFocusCoords(); //update FocusBox //Lock center so that user could only zoom on touch-enabled devices } void SkyMapLite::slewFocus() { //Don't slew if the mouse button is pressed //Also, no animated slews if the Manual Clock is active //08/2002: added possibility for one-time skipping of slew with snapNextFocus if (!mouseButtonDown) { bool goSlew = (Options::useAnimatedSlewing() && !data->snapNextFocus()) && !(data->clock()->isManualMode() && data->clock()->isActive()); if (goSlew) { double dX, dY; double maxstep = 10.0; if (Options::useAltAz()) { dX = destination()->az().Degrees() - focus()->az().Degrees(); dY = destination()->alt().Degrees() - focus()->alt().Degrees(); } else { dX = destination()->ra().Degrees() - focus()->ra().Degrees(); dY = destination()->dec().Degrees() - focus()->dec().Degrees(); } //switch directions to go the short way around the celestial sphere, if necessary. dX = KSUtils::reduceAngle(dX, -180.0, 180.0); double r0 = sqrt(dX * dX + dY * dY); if (r0 < 20.0) //smaller slews have smaller maxstep { maxstep *= (10.0 + 0.5 * r0) / 20.0; } double step = 0.1; double r = r0; while (r > step) { //DEBUG //qDebug() << step << ": " << r << ": " << r0 << endl; double fX = dX / r; double fY = dY / r; if (Options::useAltAz()) { focus()->setAlt(focus()->alt().Degrees() + fY * step); focus()->setAz(dms(focus()->az().Degrees() + fX * step).reduce()); focus()->HorizontalToEquatorial(data->lst(), data->geo()->lat()); } else { fX = fX / 15.; //convert RA degrees to hours SkyPoint newFocus(focus()->ra().Hours() + fX * step, focus()->dec().Degrees() + fY * step); setFocus(&newFocus); focus()->EquatorialToHorizontal(data->lst(), data->geo()->lat()); } setSlewing(true); forceUpdate(); qApp->processEvents(); //keep up with other stuff if (Options::useAltAz()) { dX = destination()->az().Degrees() - focus()->az().Degrees(); dY = destination()->alt().Degrees() - focus()->alt().Degrees(); } else { dX = destination()->ra().Degrees() - focus()->ra().Degrees(); dY = destination()->dec().Degrees() - focus()->dec().Degrees(); } //switch directions to go the short way around the celestial sphere, if necessary. dX = KSUtils::reduceAngle(dX, -180.0, 180.0); r = sqrt(dX * dX + dY * dY); //Modify step according to a cosine-shaped profile //centered on the midpoint of the slew //NOTE: don't allow the full range from -PI/2 to PI/2 //because the slew will never reach the destination as //the speed approaches zero at the end! double t = dms::PI * (r - 0.5 * r0) / (1.05 * r0); step = cos(t) * maxstep; } } //Either useAnimatedSlewing==false, or we have slewed, and are within one step of destination //set focus=destination. if (Options::useAltAz()) { setFocusAltAz(destination()->alt(), destination()->az()); focus()->HorizontalToEquatorial(data->lst(), data->geo()->lat()); } else { setFocus(destination()); focus()->EquatorialToHorizontal(data->lst(), data->geo()->lat()); } setSlewing(false); //Turn off snapNextFocus, we only want it to happen once if (data->snapNextFocus()) { data->setSnapNextFocus(false); } //Start the HoverTimer. if the user leaves the mouse in place after a slew, //we want to attach a label to the nearest object. if (Options::useHoverLabel()) m_HoverTimer.start(HOVER_INTERVAL); forceUpdate(); } } void SkyMapLite::slotClockSlewing() { //If the current timescale exceeds slewTimeScale, set clockSlewing=true, and stop the clock. if ((fabs(data->clock()->scale()) > Options::slewTimeScale()) ^ clockSlewing) { data->clock()->setManualMode(!clockSlewing); clockSlewing = !clockSlewing; // don't change automatically the DST status KStarsLite *kstars = KStarsLite::Instance(); if (kstars) kstars->updateTime(false); } } /*void SkyMapLite::updateFocus() { if( slewing ) return; //Tracking on an object if ( Options::isTracking() && focusObject() != nullptr ) { if ( Options::useAltAz() ) { //Tracking any object in Alt/Az mode requires focus updates focusObject()->EquatorialToHorizontal(data->lst(), data->geo()->lat()); setFocusAltAz( focusObject()->altRefracted(), focusObject()->az() ); focus()->HorizontalToEquatorial( data->lst(), data->geo()->lat() ); setDestination( *focus() ); } else { //Tracking in equatorial coords setFocus( focusObject() ); focus()->EquatorialToHorizontal( data->lst(), data->geo()->lat() ); setDestination( *focus() ); } //Tracking on empty sky } else if ( Options::isTracking() && focusPoint() != nullptr ) { if ( Options::useAltAz() ) { //Tracking on empty sky in Alt/Az mode setFocus( focusPoint() ); focus()->EquatorialToHorizontal( data->lst(), data->geo()->lat() ); setDestination( *focus() ); } // Not tracking and not slewing, let sky drift by // This means that horizontal coordinates are constant. } else { focus()->HorizontalToEquatorial(data->lst(), data->geo()->lat() ); } }*/ void SkyMapLite::resizeItem() { if (parentItem()) { setWidth(parentItem()->width()); setHeight(parentItem()->height()); } forceUpdate(); } void SkyMapLite::slotZoomIn() { setZoomFactor(Options::zoomFactor() * DZOOM); } void SkyMapLite::slotZoomOut() { setZoomFactor(Options::zoomFactor() / DZOOM); } void SkyMapLite::slotZoomDefault() { setZoomFactor(DEFAULTZOOM); } void SkyMapLite::slotSelectObject(SkyObject *skyObj) { ClickedPoint = *skyObj; ClickedObject = skyObj; /*if ( Options::useAltAz() ) { setDestinationAltAz( skyObj->altRefracted(), skyObj->az() ); } else { setDestination( *skyObj ); }*/ //Update selected SkyObject (used in FindDialog, DetailDialog) m_ClickedObjectLite->setObject(skyObj); emit objectLiteChanged(); slotCenter(); } void SkyMapLite::setSkyRotation(double skyRotation) { if (m_skyRotation != skyRotation) { m_skyRotation = skyRotation; emit skyRotationChanged(skyRotation); if (skyRotation >= 0 && skyRotation < 90) { m_skyMapOrientation = SkyMapOrientation::Top0; } else if (skyRotation >= 90 && skyRotation < 180) { m_skyMapOrientation = SkyMapOrientation::Right90; } else if (skyRotation >= 180 && skyRotation < 270) { m_skyMapOrientation = SkyMapOrientation::Bottom180; } else if (skyRotation >= 270 && skyRotation < 360) { m_skyMapOrientation = SkyMapOrientation::Left270; } } } void SkyMapLite::setZoomFactor(double factor) { Options::setZoomFactor(KSUtils::clamp(factor, MINZOOM, MAXZOOM)); forceUpdate(); emit zoomChanged(); } void SkyMapLite::forceUpdate() { setupProjector(); // We delay one draw cycle before re-indexing // we MUST ensure CLines do not get re-indexed while we use DRAW_BUF // so we do it here. //m_CLines->reindex( &m_reindexNum ); // This queues re-indexing for the next draw cycle //m_reindexNum = KSNumbers( data->updateNum()->julianDay() ); // This ensures that the JIT updates are synchronized for the entire draw // cycle so the sky moves as a single sheet. May not be needed. data->syncUpdateIDs(); SkyMesh *m_skyMesh = SkyMesh::Instance(3); if (m_skyMesh) { // prepare the aperture // FIXME_FOV: We may want to rejigger this to allow // wide-angle views --hdevalence double radius = m_proj->fov(); if (radius > 180.0) radius = 180.0; if (m_skyMesh->inDraw()) { printf("Warning: aborting concurrent SkyMapComposite::draw()\n"); return; } //m_skyMesh->inDraw( true ); m_skyMesh->aperture(&Focus, radius + 1.0, DRAW_BUF); // divide by 2 for testing // create the no-precess aperture if needed if (Options::showEquatorialGrid() || Options::showHorizontalGrid() || Options::showCBounds() || - Options::showEquator()) + Options::showEquator()) { m_skyMesh->index(&Focus, radius + 1.0, NO_PRECESS_BUF); } } update(); } void SkyMapLite::slotUpdateSky(bool now) { Q_UNUSED(now); updateFocus(); forceUpdate(); } void SkyMapLite::updateFocus() { if (getSlewing()) return; //Tracking on an object if (Options::isTracking() && focusObject() != nullptr) { if (Options::useAltAz()) { //Tracking any object in Alt/Az mode requires focus updates focusObject()->EquatorialToHorizontal(data->lst(), data->geo()->lat()); setFocusAltAz(focusObject()->altRefracted(), focusObject()->az()); focus()->HorizontalToEquatorial(data->lst(), data->geo()->lat()); setDestination(*focus()); } else { //Tracking in equatorial coords setFocus(focusObject()); focus()->EquatorialToHorizontal(data->lst(), data->geo()->lat()); setDestination(*focus()); } //Tracking on empty sky } else if (Options::isTracking() && focusPoint() != nullptr) { if (Options::useAltAz()) { //Tracking on empty sky in Alt/Az mode setFocus(focusPoint()); focus()->EquatorialToHorizontal(data->lst(), data->geo()->lat()); setDestination(*focus()); } // Not tracking and not slewing, let sky drift by // This means that horizontal coordinates are constant. } else { focus()->HorizontalToEquatorial(data->lst(), data->geo()->lat()); } } void SkyMapLite::setupProjector() { //Update View Parameters for projection ViewParams p; p.focus = focus(); p.height = height(); p.width = width(); p.useAltAz = Options::useAltAz(); p.useRefraction = Options::useRefraction(); p.zoomFactor = Options::zoomFactor(); p.fillGround = Options::showGround(); //Check if we need a new projector if (m_proj && Options::projection() == m_proj->type()) m_proj->setViewParams(p); else { delete m_proj; switch (Options::projection()) { case Projector::Gnomonic: m_proj = new GnomonicProjector(p); break; case Projector::Stereographic: m_proj = new StereographicProjector(p); break; case Projector::Orthographic: m_proj = new OrthographicProjector(p); break; case Projector::AzimuthalEquidistant: m_proj = new AzimuthalEquidistantProjector(p); break; case Projector::Equirectangular: m_proj = new EquirectangularProjector(p); break; case Projector::Lambert: default: //TODO: implement other projection classes m_proj = new LambertProjector(p); break; } } } void SkyMapLite::setZoomMouseCursor() { mouseMoveCursor = false; // no mousemove cursor QBitmap cursor = zoomCursorBitmap(2); QBitmap mask = zoomCursorBitmap(4); setCursor(QCursor(cursor, mask)); } void SkyMapLite::setDefaultMouseCursor() { mouseMoveCursor = false; // no mousemove cursor QBitmap cursor = defaultCursorBitmap(2); QBitmap mask = defaultCursorBitmap(3); setCursor(QCursor(cursor, mask)); } void SkyMapLite::setMouseMoveCursor() { if (mouseButtonDown) { setCursor(Qt::SizeAllCursor); // cursor shape defined in qt mouseMoveCursor = true; } } bool SkyMapLite::isSlewing() const { return (getSlewing() || (clockSlewing && data->clock()->isActive())); } int SkyMapLite::harvardToIndex(char c) { // Convert spectral class to numerical index. // If spectral class is invalid return index for white star (A class) switch (c) { case 'o': case 'O': return 0; case 'b': case 'B': return 1; case 'a': case 'A': return 2; case 'f': case 'F': return 3; case 'g': case 'G': return 4; case 'k': case 'K': return 5; case 'm': case 'M': return 6; // For unknown spectral class assume A class (white star) default: return 2; } } QVector> SkyMapLite::getImageCache() { return imageCache; } QSGTexture *SkyMapLite::textToTexture(QString text, QColor color, bool zoomFont) { if (isInitialized) { QFont f; if (zoomFont) { f = SkyLabeler::Instance()->drawFont(); } else { f = SkyLabeler::Instance()->stdFont(); } qreal ratio = window()->effectiveDevicePixelRatio(); QFontMetrics fm(f); int width = fm.width(text); int height = fm.height(); // double rotation = 0; //// switch(m_skyMapOrientation) { //// case(SkyMapOrientation::Top0): //// width = fm.width(text); //// height = fm.height(); //// rotation = 0; //// break; //// case(SkyMapOrientation::Right90): //// width = fm.height(); //// height = fm.width(text); //// rotation = 90; //// case(SkyMapOrientation::Bottom180): ////// width = ; ////// height = ; //// rotation = 180; //// case(SkyMapOrientation::Left270): ////// width = ; ////// height; //// rotation = 270; //// } f.setPointSizeF(f.pointSizeF() * ratio); QImage label((width)*ratio, (height)*ratio, QImage::Format_ARGB32_Premultiplied); label.fill(Qt::transparent); m_painter.begin(&label); m_painter.setFont(f); m_painter.setPen(color); // m_painter.drawRect(0,0, label.width(), label.height()); // m_painter.rotate(getSkyRotation()); m_painter.drawText(0, (height - fm.descent()) * ratio, text); m_painter.end(); QSGTexture *texture = window()->createTextureFromImage(label, QQuickWindow::TextureCanUseAtlas); return texture; } else { return nullptr; } } void SkyMapLite::addFOVSymbol(const QString &FOVName, bool initialState) { m_FOVSymbols.append(FOVName); //Emit signal whenever new value was added emit symbolsFOVChanged(m_FOVSymbols); m_FOVSymVisible.append(initialState); } bool SkyMapLite::isFOVVisible(int index) { return m_FOVSymVisible.value(index); } void SkyMapLite::setFOVVisible(int index, bool visible) { if (index >= 0 && index < m_FOVSymVisible.size()) { m_FOVSymVisible[index] = visible; forceUpdate(); } } void SkyMapLite::setSlewing(bool newSlewing) { if (m_slewing != newSlewing) { m_slewing = newSlewing; emit slewingChanged(newSlewing); } } void SkyMapLite::setCenterLocked(bool centerLocked) { m_centerLocked = centerLocked; emit centerLockedChanged(centerLocked); } void SkyMapLite::setAutomaticMode(bool automaticMode) { #if defined(Q_OS_ANDROID) if (m_automaticMode != automaticMode) { m_automaticMode = automaticMode; if (automaticMode) { m_deviceOrientation->startSensors(); automaticModeTimer.start(); } else { automaticModeTimer.stop(); m_deviceOrientation->stopSensors(); } } #else Q_UNUSED(automaticMode); #endif } void SkyMapLite::updateAutomaticMode() { #if defined(Q_OS_ANDROID) m_deviceOrientation->getOrientation(); setFocusAltAz(dms(m_deviceOrientation->getAltitude()), dms(m_deviceOrientation->getAzimuth())); setSkyRotation(-1 * m_deviceOrientation->getRoll()); #endif } void SkyMapLite::initStarImages() { if (isInitialized) { //Delete all existing pixmaps if (imageCache.length() != 0) { foreach (QVector vec, imageCache) { qDeleteAll(vec.begin(), vec.end()); } clearTextures = true; } imageCache = QVector>(nSPclasses); QMap ColorMap; const int starColorIntensity = Options::starColorIntensity(); //On high-dpi screens star will look pixelized if don't multiply scaling factor by this ratio //Check PointNode::setNode() to see how it works qreal ratio = window()->effectiveDevicePixelRatio(); switch (Options::starColorMode()) { case 1: // Red stars. ColorMap.insert('O', QColor::fromRgb(255, 0, 0)); ColorMap.insert('B', QColor::fromRgb(255, 0, 0)); ColorMap.insert('A', QColor::fromRgb(255, 0, 0)); ColorMap.insert('F', QColor::fromRgb(255, 0, 0)); ColorMap.insert('G', QColor::fromRgb(255, 0, 0)); ColorMap.insert('K', QColor::fromRgb(255, 0, 0)); ColorMap.insert('M', QColor::fromRgb(255, 0, 0)); break; case 2: // Black stars. ColorMap.insert('O', QColor::fromRgb(0, 0, 0)); ColorMap.insert('B', QColor::fromRgb(0, 0, 0)); ColorMap.insert('A', QColor::fromRgb(0, 0, 0)); ColorMap.insert('F', QColor::fromRgb(0, 0, 0)); ColorMap.insert('G', QColor::fromRgb(0, 0, 0)); ColorMap.insert('K', QColor::fromRgb(0, 0, 0)); ColorMap.insert('M', QColor::fromRgb(0, 0, 0)); break; case 3: // White stars ColorMap.insert('O', QColor::fromRgb(255, 255, 255)); ColorMap.insert('B', QColor::fromRgb(255, 255, 255)); ColorMap.insert('A', QColor::fromRgb(255, 255, 255)); ColorMap.insert('F', QColor::fromRgb(255, 255, 255)); ColorMap.insert('G', QColor::fromRgb(255, 255, 255)); ColorMap.insert('K', QColor::fromRgb(255, 255, 255)); ColorMap.insert('M', QColor::fromRgb(255, 255, 255)); case 0: // Real color default: // And use real color for everything else ColorMap.insert('O', QColor::fromRgb(0, 0, 255)); ColorMap.insert('B', QColor::fromRgb(0, 200, 255)); ColorMap.insert('A', QColor::fromRgb(0, 255, 255)); ColorMap.insert('F', QColor::fromRgb(200, 255, 100)); ColorMap.insert('G', QColor::fromRgb(255, 255, 0)); ColorMap.insert('K', QColor::fromRgb(255, 100, 0)); ColorMap.insert('M', QColor::fromRgb(255, 0, 0)); } for (char color : ColorMap.keys()) { //Add new spectral class QPixmap BigImage(15, 15); BigImage.fill(Qt::transparent); QPainter p; p.begin(&BigImage); if (Options::starColorMode() == 0) { qreal h, s, v, a; p.setRenderHint(QPainter::Antialiasing, false); QColor starColor = ColorMap[color]; starColor.getHsvF(&h, &s, &v, &a); for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { qreal x = i - 7; qreal y = j - 7; qreal dist = sqrt(x * x + y * y) / 7.0; starColor.setHsvF(h, qMin(qreal(1), dist < (10 - starColorIntensity) / 10.0 ? 0 : dist), v, qMax(qreal(0), dist < (10 - starColorIntensity) / 20.0 ? 1 : 1 - dist)); p.setPen(starColor); p.drawPoint(i, j); p.drawPoint((14 - i), j); p.drawPoint(i, (14 - j)); p.drawPoint((14 - i), (14 - j)); } } } else { p.setRenderHint(QPainter::Antialiasing, true); p.setPen(QPen(ColorMap[color], 2.0)); p.setBrush(p.pen().color()); p.drawEllipse(QRectF(2, 2, 10, 10)); } p.end(); //[nSPclasses][nStarSizes]; // Cache array slice QVector *pmap = &imageCache[harvardToIndex(color)]; pmap->append(new QPixmap(BigImage)); for (int size = 1; size < nStarSizes; size++) { pmap->append(new QPixmap( - BigImage.scaled(size * ratio, size * ratio, Qt::KeepAspectRatio, Qt::SmoothTransformation))); + BigImage.scaled(size * ratio, size * ratio, Qt::KeepAspectRatio, Qt::SmoothTransformation))); } } //} starColorMode = Options::starColorMode(); } } diff --git a/kstars/skymaplite.h b/kstars/skymaplite.h index 609c9457b..98a80fda4 100644 --- a/kstars/skymaplite.h +++ b/kstars/skymaplite.h @@ -1,694 +1,763 @@ /** ************************************************************************* skymaplite.h - K Desktop Planetarium ------------------- begin : 30/04/2016 copyright : (C) 2016 by Artem Fedoskin email : afedoskin3@gmail.com ***************************************************************************/ /** ************************************************************************* * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #pragma once #include "skyobjects/skypoint.h" #include "skyobjects/skyline.h" #include #include #include #include #include #include #include "kstarsdata.h" #include "kstarslite/skyitems/rootnode.h" #include class DeviceOrientation; class dms; class KStarsData; class SkyObject; class Projector; class SolarSystemSingleComponent; class PlanetsItem; class AsteroidsItem; class CometsItem; class PlanetMoonsComponent; class HorizonItem; class LinesItem; class SkyNode; class RootNode; class TelescopeLite; class SkyObjectLite; class SkyPointLite; class QSGTexture; /** @class SkyMapLite * *This is the main item that displays all SkyItems. After its instantiation it is reparanted *to an object with objectName SkyMapLiteWrapper in main.qml. To display SkyItems they are reparanted *to instance of SkyMapLite. * *SkyMapLite handles most user interaction events (both mouse and keyboard). * *@short Item for displaying sky objects; also handles user interaction events. *@author Artem Fedoskin *@version 1.0 */ class SkyMapLite : public QQuickItem { - Q_OBJECT - /** magnitude limit. Used in QML **/ - Q_PROPERTY(double magLim READ getMagLim WRITE setMagLim NOTIFY magLimChanged) - - /** wrappers for clickedPoint and clickedObject. Used to set clicked object and point from QML **/ - Q_PROPERTY(SkyPointLite *clickedPointLite READ getClickedPointLite NOTIFY pointLiteChanged) - Q_PROPERTY(SkyObjectLite *clickedObjectLite READ getClickedObjectLite NOTIFY objectLiteChanged) - /** list of FOVSymbols that are currently available **/ - Q_PROPERTY(QStringList FOVSymbols READ getFOVSymbols NOTIFY symbolsFOVChanged) - /** true if SkyMapLite is being panned **/ - Q_PROPERTY(bool slewing READ getSlewing WRITE setSlewing NOTIFY slewingChanged) - /** - * @short true if SkyMapLite is centered on an object and only pinch-to-zoom needs to be available - **/ - Q_PROPERTY(bool centerLocked READ getCenterLocked WRITE setCenterLocked NOTIFY centerLockedChanged) - Q_PROPERTY(bool automaticMode READ getAutomaticMode WRITE setAutomaticMode NOTIFY automaticModeChanged) - Q_PROPERTY(double skyRotation READ getSkyRotation WRITE setSkyRotation NOTIFY skyRotationChanged) - - enum class SkyMapOrientation - { - Top0, - Right90, - Bottom180, - Left270 - }; - - protected: - SkyMapLite(); - - /** Updates SkyMapLite by calling RootNode::update(), which in turn initiates update of all child nodes. **/ - virtual QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData); - - public: - /** Creates instance of SkyMapLite (delete the old one if any) **/ - static SkyMapLite *createInstance(); - - /** Bind size to parent's size and initialize star images **/ - void initialize(QQuickItem *parent); - - static SkyMapLite *Instance() { return pinstance; } - - static bool IsSlewing() { return pinstance->isSlewing(); } - - /** Destructor. Clear star images.*/ - ~SkyMapLite(); - - /** - * @short skyNode will be deleted on the next call to updatePaintNode (currently used only in - * StarNode(struct in StarBlock)) - */ - void deleteSkyNode(SkyNode *skyNode); - - /** @short Update the focus position according to current options. */ - void updateFocus(); - - /** @short Retrieve the Focus point; the position on the sky at the - *center of the skymap. - *@return a pointer to the central focus point of the sky map - */ - SkyPoint *focus() { return &Focus; } - - /** @short retrieve the Destination position. - * - *The Destination is the point on the sky to which the focus will be moved. - *@return a pointer to the destination point of the sky map - */ - SkyPoint *destination() { return &Destination; } - - /** @short retrieve the FocusPoint position. - * - *The FocusPoint stores the position on the sky that is to be - *focused next. This is not exactly the same as the Destination - *point, because when the Destination is set, it will begin slewing - *immediately. - * - *@return a pointer to the sky point which is to be focused next. - */ - SkyPoint *focusPoint() { return &FocusPoint; } - - /** @short sets the central focus point of the sky map. - *@param f a pointer to the SkyPoint the map should be centered on - */ - void setFocus(SkyPoint *f); - - /** @short sets the focus point of the skymap, using ra/dec coordinates - * - *@note This function behaves essentially like the above function. - *It differs only in the data types of its arguments. - * - *@param ra the new right ascension - *@param dec the new declination - */ - void setFocus(const dms &ra, const dms &dec); - - /** @short sets the focus point of the sky map, using its alt/az coordinates - *@param alt the new altitude - *@param az the new azimuth - */ - void setFocusAltAz(const dms &alt, const dms &az); - - /** @short sets the destination point of the sky map. - *@note setDestination() emits the destinationChanged() SIGNAL, - *which triggers the SLOT function SkyMap::slewFocus(). This - *function iteratively steps the Focus point toward Destination, - *repainting the sky at each step (if Options::useAnimatedSlewing()==true). - *@param f a pointer to the SkyPoint the map should slew to - */ - void setDestination(const SkyPoint &f); - - /** @short sets the destination point of the skymap, using ra/dec coordinates. - * - *@note This function behaves essentially like the above function. - *It differs only in the data types of its arguments. - * - *@param ra the new right ascension - *@param dec the new declination - */ - void setDestination(const dms &ra, const dms &dec); - - /** @short sets the destination point of the sky map, using its alt/az coordinates. - *@param alt the new altitude - *@param az the new azimuth - */ - void setDestinationAltAz(const dms &alt, const dms &az); - - /** @short set the FocusPoint; the position that is to be the next Destination. - *@param f a pointer to the FocusPoint SkyPoint. - */ - void setFocusPoint(SkyPoint *f) - { - if (f) - FocusPoint = *f; - } - - /** @short Retrieve the ClickedPoint position. - * - *When the user clicks on a point in the sky map, the sky coordinates of the mouse - *cursor are stored in the private member ClickedPoint. This function retrieves - *a pointer to ClickedPoint. - *@return a pointer to ClickedPoint, the sky coordinates where the user clicked. - */ - SkyPoint *clickedPoint() { return &ClickedPoint; } - - /** @short Set the ClickedPoint to the skypoint given as an argument. - *@param f pointer to the new ClickedPoint. - */ - void setClickedPoint(SkyPoint *f); - - /** @short Retrieve the object nearest to a mouse click event. - * - *If the user clicks on the sky map, a pointer to the nearest SkyObject is stored in - *the private member ClickedObject. This function returns the ClickedObject pointer, - *or nullptr if there is no CLickedObject. - *@return a pointer to the object nearest to a user mouse click. - */ - SkyObject *clickedObject() const { return ClickedObject; } - - /** @short Set the ClickedObject pointer to the argument. - *@param o pointer to the SkyObject to be assigned as the ClickedObject - */ - void setClickedObject(SkyObject *o); - - /** @short Retrieve the object which is centered in the sky map. - * - *If the user centers the sky map on an object (by double-clicking or using the - *Find Object dialog), a pointer to the "focused" object is stored in - *the private member FocusObject. This function returns a pointer to the - *FocusObject, or nullptr if there is not FocusObject. - *@return a pointer to the object at the center of the sky map. - */ - SkyObject *focusObject() const { return FocusObject; } - - /** @short Set the FocusObject pointer to the argument. - *@param o pointer to the SkyObject to be assigned as the FocusObject - */ - void setFocusObject(SkyObject *o); - - /** @ Set zoom factor. - *@param factor zoom factor - */ - void setZoomFactor(double factor); - - /** @short Call to set up the projector before update of SkyItems positions begins. */ - void setupProjector(); - - /** @short Returns index for a Harvard spectral classification */ - int harvardToIndex(char c); - - /** @short returns cache of star images - * @return star images cache - */ - QVector> getImageCache(); - - /** - * @short creates QImage from text and converts it to QSGTexture - * @param text the text string - * @param color text color - * @param zoomFont if true zoom-dependent font from SkyLabeler will be used else standart - * font is used - * @return QSGTexture with text - * @note font size is set in SkyLabeler::SkyLabeler() by initializing m_stdFont with default font - */ - QSGTexture *textToTexture(QString text, QColor color = QColor(255, 255, 255), bool zoomFont = false); - - /** - * @short returns cached texture from textureCache. - * - * Use outside of scene graph rendering thread (e.g. not during call to updatePaintNode) - * is prohibited! - * @param size size of the star - * @param spType spectral class - * @return cached QSGTexture from textureCache - */ - QSGTexture *getCachedTexture(int size, char spType); - - /** @short called when SkyMapComposite finished loading all SkyComponents */ - inline void loadingFinished() { m_loadingFinished = true; } - - /** @return true if the map is in slewing mode or clock is active **/ - bool isSlewing() const; - - /** @return current magnitude limit **/ - inline double getMagLim() { return m_magLim; } - - /** @short set magnitude limit **/ - void setMagLim(double magLim); - - /** @short Convenience function for shutting off tracking mode. Just calls KStars::slotTrack() **/ - void stopTracking(); - - /** Get the current projector. - @return a pointer to the current projector. */ - inline const Projector *projector() const { return m_proj; } - - /** - * @short used in QML - * @return type of current projection system - */ - Q_INVOKABLE uint projType() const; - - /** Set magnitude limit for size of stars. Used in StarItem **/ - inline void setSizeMagLim(float sizeMagLim) { m_sizeMagLim = sizeMagLim; } - - /** Used in PointSourceNode **/ - inline float sizeMagLim() const { return m_sizeMagLim; } - - static inline RootNode *rootNode() { return m_rootNode; } - - static inline void setRootNode(RootNode *root) { m_rootNode = root; } - - /** return limit of hides for the node to delete it **/ - static double deleteLimit(); - - /** - * @short adds FOV symbol to m_FOVSymbols - * @param FOVName name of a FOV symbol - * @param initialState defines whether the state is initial - */ - Q_INVOKABLE void addFOVSymbol(const QString &FOVName, bool initialState = false); - - /** - * @param index of FOVSymbol in m_FOVSymbols - * @return true if FOV symbol with name FOVName should be drawn. - */ - bool isFOVVisible(int index); - - /** - * @param index of FOVSymbol in m_FOVSymbols - * @param visible defines whether the FOV symbol should be visible - * @short updates visibility of FOV symbol according to visible - */ - Q_INVOKABLE void setFOVVisible(int index, bool visible); - - /** - * @short this QList should be used as a model in QML to switch on/off FOV symbols - **/ - Q_INVOKABLE inline QStringList getFOVSymbols() { return m_FOVSymbols; } - - /** @short Initializes images of Stars and puts them in cache (copied from SkyQPainter)*/ - void initStarImages(); - - /** - * @short getter for clickedPointLite - */ - SkyPointLite *getClickedPointLite() { return m_ClickedPointLite; } - - /** - * @short getter for clickedObjectLite - */ - SkyObjectLite *getClickedObjectLite() { return m_ClickedObjectLite; } - - /** - * @short getter for centerLocked - */ - bool getCenterLocked() { return m_centerLocked; } - - /** - * @short Proxy method for SkyMapDrawAbstract::drawObjectLabels() - */ - //inline void drawObjectLabels( QList< SkyObject* >& labelObjects ) { dynamic_cast(m_SkyMapDraw)->drawObjectLabels( labelObjects ); } - - /** - * @return true if SkyMapLite is being slewed - */ - bool getSlewing() const { return m_slewing; } - - /** - * @short sets whether SkyMapLite is being slewed - */ - void setSlewing(bool newSlewing); - - /** - * @short sets whether SkyMapLite is centered on an object and locked(olny pinch-to-zoom is available) - */ - void setCenterLocked(bool centerLocked); - - /** True if automatic mode is on (SkyMapLite is controlled by smartphones accelerometer magnetometer) **/ - bool getAutomaticMode() const { return m_automaticMode; } - - /** - * @short switch automatic mode on/off according to isOn parameter - */ - Q_INVOKABLE void setAutomaticMode(bool automaticMode); - - double getSkyRotation() const { return m_skyRotation; } - - public slots: - /** Called whenever wrappers' width or height are changed. Probably will be used to - * update positions of items. - */ - void resizeItem(); - - /** Recalculates the positions of objects in the sky, and then repaints the sky map. - */ - void forceUpdate(); - - /** @short Left for compatibility reasons - * @see forceUpdate() - */ - void forceUpdateNow() { forceUpdate(); } - - /** - * @short Update the focus point and call forceUpdate() - * @param now is saved for compatibility reasons - */ - void slotUpdateSky(bool now); - - /** Step the Focus point toward the Destination point. Do this iteratively, redrawing the Sky - * Map after each step, until the Focus point is within 1 step of the Destination point. - * For the final step, snap directly to Destination, and redraw the map. - */ - void slewFocus(); - - /** @short Center the display at the point ClickedPoint. - * - * The essential part of the function is to simply set the Destination point, which will emit - * the destinationChanged() SIGNAL, which triggers the slewFocus() SLOT. Additionally, this - * function performs some bookkeeping tasks, such updating whether we are tracking the new - * object/position, adding a Planet Trail if required, etc. - * - * @see destinationChanged() - * @see slewFocus() - */ - void slotCenter(); - - /** Checks whether the timestep exceeds a threshold value. If so, sets - * ClockSlewing=true and sets the SimClock to ManualMode. - */ - void slotClockSlewing(); - - /** Zoom in one step. */ - void slotZoomIn(); - - /** Zoom out one step. */ - void slotZoomOut(); - - /** Set default zoom. */ - void slotZoomDefault(); - /** - * @short centres skyObj in SkyMap and opens context drawer with skyObj - * Used in FindDialogLite - */ - void slotSelectObject(SkyObject *skyObj); - - /** @short updates focus of SkyMapLite according to data from DeviceOrientation - (Smartphone's sensors)*/ - void updateAutomaticMode(); - - void setSkyRotation(double skyRotation); - - signals: - /** Emitted by setDestination(), and connected to slewFocus(). Whenever the Destination - * point is changed, slewFocus() will iteratively step the Focus toward Destination - * until it is reached. - * @see SkyMap::setDestination() - * @see SkyMap::slewFocus() - */ - void destinationChanged(); - - /** Emitted when zoom level is changed. */ - void zoomChanged(); - - /** Emitted when current object changed. */ - void objectChanged(); - - /** Wrapper of ClickedObject for QML **/ - void objectLiteChanged(); - - /** Wrapper of ClickedPoint for QML **/ - void pointLiteChanged(); - - /** Emitted when pointing changed. (At least should) */ - void positionChanged(); - - /** Emitted when position under mouse changed. */ - void mousePointChanged(SkyPoint *); - - /** Emitted when a position is clicked */ - void positionClicked(SkyPoint *); - - /** Emitted when user clicks on SkyMapLite (analogous to positionClicked but sends QPoint) */ - void posClicked(QPointF pos); - - /** Emitted when magnitude limit is changed */ - void magLimChanged(double magLim); - - /** Emitted when FOVSymbols list was changed (new value appended) **/ - void symbolsFOVChanged(QStringList); - - /** Emitted when SkyMapLite is being slewed or slewing is finished **/ - void slewingChanged(bool); - - void centerLockedChanged(bool); - - void automaticModeChanged(bool); - - /** Emitted when skyRotation used to rotate coordinates of SkyPoints is changed **/ - void skyRotationChanged(double skyRotation); - - protected: - /** Process keystrokes: - * @li arrow keys Slew the map - * @li +/- keys Zoom in and out - * @li Space Toggle between Horizontal and Equatorial coordinate systems - * @li 0-9 Go to a major Solar System body (0=Sun; 1-9 are the major planets, except 3=Moon) - * @li [ Place starting point for measuring an angular distance - * @li ] End point for Angular Distance; display measurement. - * @li Escape Cancel Angular measurement - * @li ,/< Step backward one time step - * @li ./> Step forward one time step - */ - //virtual void keyPressEvent( QKeyEvent *e ); - - /** When keyRelease is triggered, just set the "slewing" flag to false, - * and update the display (to draw objects that are hidden when slewing==true). */ - //virtual void keyReleaseEvent( QKeyEvent *e ); - - /** Determine RA, Dec coordinates of clicked location. Find the SkyObject - * which is nearest to the clicked location. - * - * If left-clicked: Set set mouseButtonDown==true, slewing==true; display - * nearest object name in status bar. - * If right-clicked: display popup menu appropriate for nearest object. - */ - virtual void mousePressEvent(QMouseEvent *e); - - /** set mouseButtonDown==false, slewing==false */ - virtual void mouseReleaseEvent(QMouseEvent *e); - - /** Center SkyMap at double-clicked location */ - virtual void mouseDoubleClickEvent(QMouseEvent *e); - - /** This function does several different things depending on the state of the program: - * @li If Angle-measurement mode is active, update the end-ruler point to the mouse cursor, - * and continue this function. - * @li If we are defining a ZoomBox, update the ZoomBox rectangle, redraw the screen, - * and return. - * @li If dragging the mouse in the map, update focus such that RA, Dec under the mouse - * cursor remains constant. - * @li If just moving the mouse, simply update the curso coordinates in the status bar. - */ - virtual void mouseMoveEvent(QMouseEvent *e); - - /** Zoom in and out with the mouse wheel. */ - virtual void wheelEvent(QWheelEvent *e); - - /** - * @short this function handles zooming in and out using "pinch to zoom" gesture - */ - virtual void touchEvent(QTouchEvent *e); - - private slots: - /** @short display tooltip for object under cursor. It's called by m_HoverTimer. - * if mouse didn't moved for last HOVER_INTERVAL milliseconds. - */ - //void slotTransientLabel(); - - /** Set the shape of mouse cursor to a cross with 4 arrows. */ - void setMouseMoveCursor(); - - private: - /** @short Sets the shape of the default mouse cursor to a cross. */ - void setDefaultMouseCursor(); - - /** @short Sets the shape of the mouse cursor to a magnifying glass. */ - void setZoomMouseCursor(); - - /** Calculate the zoom factor for the given keyboard modifier - */ - double zoomFactor(const int modifier); - - /** calculate the magnitude factor (1, .5, .2, or .1) for the given - * keyboard modifier. - */ - double magFactor(const int modifier); - - /** Decrease the magnitude limit by a step size determined by the - * keyboard modifier. - * @param modifier - */ - void decMagLimit(const int modifier); - - /** Increase the magnitude limit by a step size determined by the - * keyboard modifier. - * @param modifier - */ - void incMagLimit(const int modifier); - - /** Convenience routine to either zoom in or increase mag limit - * depending on the Alt modifier. The Shift and Control modifiers - * will adjust the size of the zoom or the mag step. - * @param modifier - */ - void zoomInOrMagStep(const int modifier); - - /** Convenience routine to either zoom out or decrease mag limit - * depending on the Alt modifier. The Shift and Control modifiers - * will adjust the size of the zoom or the mag step. - * @param modifier - */ - void zoomOutOrMagStep(const int modifier); - - /** - * pointer to RootNode. Use it to universally access RootNode - * @warning RootNode should be used solely during updatePaintNode! See Qt Quick Scene Graph documentation. - **/ - static RootNode *m_rootNode; - static SkyMapLite *pinstance; - static int starColorMode; - - /// True if SkyMapLite was initialized (star images were initialized etc.) - bool isInitialized { false }; - bool mouseButtonDown { false }; - bool midMouseButtonDown { false }; - /// True if mouseMoveEvent; needed by setMouseMoveCursor - bool mouseMoveCursor { false }; - bool m_slewing { false }; - bool clockSlewing { false }; - /// True if pinch to zoom or pinch to rotate is performed - bool pinch { false }; - /// If false only old pixmap will repainted with bitBlt() to save a lot of CPU usage - bool computeSkymap { false }; - double y0 { 0 }; - int count { 0 }; - KStarsData *data { nullptr }; - /// True if SkyMapComposite has finished loading of SkyComponents - bool m_loadingFinished { false }; - /// Coordinates of point under cursor. It's update in function mouseMoveEvent - SkyPoint m_MousePoint; - SkyPoint Focus, ClickedPoint, FocusPoint, Destination; - SkyObject *ClickedObject { nullptr }; - SkyObject *FocusObject { nullptr }; - SkyPointLite *m_ClickedPointLite { nullptr }; - SkyObjectLite *m_ClickedObjectLite { nullptr }; - bool m_centerLocked { false }; - //SkyLine AngularRuler; //The line for measuring angles in the map - QRect ZoomRect; //The manual-focus circle. - /// Mouse should not move for that interval to display tooltip - static const int HOVER_INTERVAL = 500; - /// Timer for tooltips - QTimer m_HoverTimer; - bool m_objPointingMode { false }; - bool m_fovCaptureMode { false }; - Projector *m_proj { nullptr }; - QQuickItem *m_SkyMapLiteWrapper { nullptr }; - /// Holds SkyNodes that need to be deleted - QLinkedList m_deleteNodes; - /// Used in PointSourceNode - float m_sizeMagLim { 10 }; - /// Mag limit for all objects - double m_magLim { 0 }; - /// Used to notify zoom-dependent labels about font size change - bool m_fontSizeChanged { false }; - /// Used for drawing labels - QPainter m_painter; - /** - * This timer is triggered every time user touches the screen with one finger. - * If touch was released within 500 milliseconds than it is a tap, otherwise we pan. - **/ - QTimer m_tapBeganTimer; - /// Good to keep the original ruler start-point for purposes of dynamic_cast - const SkyPoint *m_rulerStartPoint; - QStringList m_FOVSymbols; - QList m_FOVSymVisible; - /// Total number of sizes of stars. - const int nStarSizes { 15 }; - /// Total number of spectral classes (N.B. Must be in sync with harvardToIndex) - const int nSPclasses { 7 }; - /// Cache for star images. - QVector> imageCache; - /// Textures created from cached star images - QVector> textureCache; - bool clearTextures { false }; - bool tapBegan { false }; - QList m_newTelescopes; - QList m_delTelescopes; - bool m_automaticMode { false }; - double m_skyRotation { 0 }; - SkyMapOrientation m_skyMapOrientation { SkyMapOrientation::Top0 }; + Q_OBJECT + /** magnitude limit. Used in QML **/ + Q_PROPERTY(double magLim READ getMagLim WRITE setMagLim NOTIFY magLimChanged) + + /** wrappers for clickedPoint and clickedObject. Used to set clicked object and point from QML **/ + Q_PROPERTY(SkyPointLite *clickedPointLite READ getClickedPointLite NOTIFY pointLiteChanged) + Q_PROPERTY(SkyObjectLite *clickedObjectLite READ getClickedObjectLite NOTIFY objectLiteChanged) + /** list of FOVSymbols that are currently available **/ + Q_PROPERTY(QStringList FOVSymbols READ getFOVSymbols NOTIFY symbolsFOVChanged) + /** true if SkyMapLite is being panned **/ + Q_PROPERTY(bool slewing READ getSlewing WRITE setSlewing NOTIFY slewingChanged) + /** + * @short true if SkyMapLite is centered on an object and only pinch-to-zoom needs to be available + **/ + Q_PROPERTY(bool centerLocked READ getCenterLocked WRITE setCenterLocked NOTIFY centerLockedChanged) + Q_PROPERTY(bool automaticMode READ getAutomaticMode WRITE setAutomaticMode NOTIFY automaticModeChanged) + Q_PROPERTY(double skyRotation READ getSkyRotation WRITE setSkyRotation NOTIFY skyRotationChanged) + + enum class SkyMapOrientation + { + Top0, + Right90, + Bottom180, + Left270 + }; + + protected: + SkyMapLite(); + + /** Updates SkyMapLite by calling RootNode::update(), which in turn initiates update of all child nodes. **/ + virtual QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData) override; + + public: + /** Creates instance of SkyMapLite (delete the old one if any) **/ + static SkyMapLite *createInstance(); + + /** Bind size to parent's size and initialize star images **/ + void initialize(QQuickItem *parent); + + static SkyMapLite *Instance() + { + return pinstance; + } + + static bool IsSlewing() + { + return pinstance->isSlewing(); + } + + /** Destructor. Clear star images.*/ + ~SkyMapLite(); + + /** + * @short skyNode will be deleted on the next call to updatePaintNode (currently used only in + * StarNode(struct in StarBlock)) + */ + void deleteSkyNode(SkyNode *skyNode); + + /** @short Update the focus position according to current options. */ + void updateFocus(); + + /** @short Retrieve the Focus point; the position on the sky at the + *center of the skymap. + *@return a pointer to the central focus point of the sky map + */ + SkyPoint *focus() + { + return &Focus; + } + + /** @short retrieve the Destination position. + * + *The Destination is the point on the sky to which the focus will be moved. + *@return a pointer to the destination point of the sky map + */ + SkyPoint *destination() + { + return &Destination; + } + + /** @short retrieve the FocusPoint position. + * + *The FocusPoint stores the position on the sky that is to be + *focused next. This is not exactly the same as the Destination + *point, because when the Destination is set, it will begin slewing + *immediately. + * + *@return a pointer to the sky point which is to be focused next. + */ + SkyPoint *focusPoint() + { + return &FocusPoint; + } + + /** @short sets the central focus point of the sky map. + *@param f a pointer to the SkyPoint the map should be centered on + */ + void setFocus(SkyPoint *f); + + /** @short sets the focus point of the skymap, using ra/dec coordinates + * + *@note This function behaves essentially like the above function. + *It differs only in the data types of its arguments. + * + *@param ra the new right ascension + *@param dec the new declination + */ + void setFocus(const dms &ra, const dms &dec); + + /** @short sets the focus point of the sky map, using its alt/az coordinates + *@param alt the new altitude + *@param az the new azimuth + */ + void setFocusAltAz(const dms &alt, const dms &az); + + /** @short sets the destination point of the sky map. + *@note setDestination() emits the destinationChanged() SIGNAL, + *which triggers the SLOT function SkyMap::slewFocus(). This + *function iteratively steps the Focus point toward Destination, + *repainting the sky at each step (if Options::useAnimatedSlewing()==true). + *@param f a pointer to the SkyPoint the map should slew to + */ + void setDestination(const SkyPoint &f); + + /** @short sets the destination point of the skymap, using ra/dec coordinates. + * + *@note This function behaves essentially like the above function. + *It differs only in the data types of its arguments. + * + *@param ra the new right ascension + *@param dec the new declination + */ + void setDestination(const dms &ra, const dms &dec); + + /** @short sets the destination point of the sky map, using its alt/az coordinates. + *@param alt the new altitude + *@param az the new azimuth + */ + void setDestinationAltAz(const dms &alt, const dms &az); + + /** @short set the FocusPoint; the position that is to be the next Destination. + *@param f a pointer to the FocusPoint SkyPoint. + */ + void setFocusPoint(SkyPoint *f) + { + if (f) + FocusPoint = *f; + } + + /** @short Retrieve the ClickedPoint position. + * + *When the user clicks on a point in the sky map, the sky coordinates of the mouse + *cursor are stored in the private member ClickedPoint. This function retrieves + *a pointer to ClickedPoint. + *@return a pointer to ClickedPoint, the sky coordinates where the user clicked. + */ + SkyPoint *clickedPoint() + { + return &ClickedPoint; + } + + /** @short Set the ClickedPoint to the skypoint given as an argument. + *@param f pointer to the new ClickedPoint. + */ + void setClickedPoint(SkyPoint *f); + + /** @short Retrieve the object nearest to a mouse click event. + * + *If the user clicks on the sky map, a pointer to the nearest SkyObject is stored in + *the private member ClickedObject. This function returns the ClickedObject pointer, + *or nullptr if there is no CLickedObject. + *@return a pointer to the object nearest to a user mouse click. + */ + SkyObject *clickedObject() const + { + return ClickedObject; + } + + /** @short Set the ClickedObject pointer to the argument. + *@param o pointer to the SkyObject to be assigned as the ClickedObject + */ + void setClickedObject(SkyObject *o); + + /** @short Retrieve the object which is centered in the sky map. + * + *If the user centers the sky map on an object (by double-clicking or using the + *Find Object dialog), a pointer to the "focused" object is stored in + *the private member FocusObject. This function returns a pointer to the + *FocusObject, or nullptr if there is not FocusObject. + *@return a pointer to the object at the center of the sky map. + */ + SkyObject *focusObject() const + { + return FocusObject; + } + + /** @short Set the FocusObject pointer to the argument. + *@param o pointer to the SkyObject to be assigned as the FocusObject + */ + void setFocusObject(SkyObject *o); + + /** @ Set zoom factor. + *@param factor zoom factor + */ + void setZoomFactor(double factor); + + /** @short Call to set up the projector before update of SkyItems positions begins. */ + void setupProjector(); + + /** @short Returns index for a Harvard spectral classification */ + int harvardToIndex(char c); + + /** @short returns cache of star images + * @return star images cache + */ + QVector> getImageCache(); + + /** + * @short creates QImage from text and converts it to QSGTexture + * @param text the text string + * @param color text color + * @param zoomFont if true zoom-dependent font from SkyLabeler will be used else standart + * font is used + * @return QSGTexture with text + * @note font size is set in SkyLabeler::SkyLabeler() by initializing m_stdFont with default font + */ + QSGTexture *textToTexture(QString text, QColor color = QColor(255, 255, 255), bool zoomFont = false); + + /** + * @short returns cached texture from textureCache. + * + * Use outside of scene graph rendering thread (e.g. not during call to updatePaintNode) + * is prohibited! + * @param size size of the star + * @param spType spectral class + * @return cached QSGTexture from textureCache + */ + QSGTexture *getCachedTexture(int size, char spType); + + /** @short called when SkyMapComposite finished loading all SkyComponents */ + inline void loadingFinished() + { + m_loadingFinished = true; + } + + /** @return true if the map is in slewing mode or clock is active **/ + bool isSlewing() const; + + /** @return current magnitude limit **/ + inline double getMagLim() + { + return m_magLim; + } + + /** @short set magnitude limit **/ + void setMagLim(double magLim); + + /** @short Convenience function for shutting off tracking mode. Just calls KStars::slotTrack() **/ + void stopTracking(); + + /** Get the current projector. + @return a pointer to the current projector. */ + inline const Projector *projector() const + { + return m_proj; + } + + /** + * @short used in QML + * @return type of current projection system + */ + Q_INVOKABLE uint projType() const; + + /** Set magnitude limit for size of stars. Used in StarItem **/ + inline void setSizeMagLim(float sizeMagLim) + { + m_sizeMagLim = sizeMagLim; + } + + /** Used in PointSourceNode **/ + inline float sizeMagLim() const + { + return m_sizeMagLim; + } + + static inline RootNode *rootNode() + { + return m_rootNode; + } + + static inline void setRootNode(RootNode *root) + { + m_rootNode = root; + } + + /** return limit of hides for the node to delete it **/ + static double deleteLimit(); + + /** + * @short adds FOV symbol to m_FOVSymbols + * @param FOVName name of a FOV symbol + * @param initialState defines whether the state is initial + */ + Q_INVOKABLE void addFOVSymbol(const QString &FOVName, bool initialState = false); + + /** + * @param index of FOVSymbol in m_FOVSymbols + * @return true if FOV symbol with name FOVName should be drawn. + */ + bool isFOVVisible(int index); + + /** + * @param index of FOVSymbol in m_FOVSymbols + * @param visible defines whether the FOV symbol should be visible + * @short updates visibility of FOV symbol according to visible + */ + Q_INVOKABLE void setFOVVisible(int index, bool visible); + + /** + * @short this QList should be used as a model in QML to switch on/off FOV symbols + **/ + Q_INVOKABLE inline QStringList getFOVSymbols() + { + return m_FOVSymbols; + } + + /** @short Initializes images of Stars and puts them in cache (copied from SkyQPainter)*/ + void initStarImages(); + + /** + * @short getter for clickedPointLite + */ + SkyPointLite *getClickedPointLite() + { + return m_ClickedPointLite; + } + + /** + * @short getter for clickedObjectLite + */ + SkyObjectLite *getClickedObjectLite() + { + return m_ClickedObjectLite; + } + + /** + * @short getter for centerLocked + */ + bool getCenterLocked() + { + return m_centerLocked; + } + + /** + * @short Proxy method for SkyMapDrawAbstract::drawObjectLabels() + */ + //inline void drawObjectLabels( QList< SkyObject* >& labelObjects ) { dynamic_cast(m_SkyMapDraw)->drawObjectLabels( labelObjects ); } + + /** + * @return true if SkyMapLite is being slewed + */ + bool getSlewing() const + { + return m_slewing; + } + + /** + * @short sets whether SkyMapLite is being slewed + */ + void setSlewing(bool newSlewing); + + /** + * @short sets whether SkyMapLite is centered on an object and locked(olny pinch-to-zoom is available) + */ + void setCenterLocked(bool centerLocked); + + /** True if automatic mode is on (SkyMapLite is controlled by smartphones accelerometer magnetometer) **/ + bool getAutomaticMode() const + { + return m_automaticMode; + } + + /** + * @short switch automatic mode on/off according to isOn parameter + */ + Q_INVOKABLE void setAutomaticMode(bool automaticMode); + + double getSkyRotation() const + { + return m_skyRotation; + } + + public slots: + /** Called whenever wrappers' width or height are changed. Probably will be used to + * update positions of items. + */ + void resizeItem(); + + /** Recalculates the positions of objects in the sky, and then repaints the sky map. + */ + void forceUpdate(); + + /** @short Left for compatibility reasons + * @see forceUpdate() + */ + void forceUpdateNow() + { + forceUpdate(); + } + + /** + * @short Update the focus point and call forceUpdate() + * @param now is saved for compatibility reasons + */ + void slotUpdateSky(bool now); + + /** Step the Focus point toward the Destination point. Do this iteratively, redrawing the Sky + * Map after each step, until the Focus point is within 1 step of the Destination point. + * For the final step, snap directly to Destination, and redraw the map. + */ + void slewFocus(); + + /** @short Center the display at the point ClickedPoint. + * + * The essential part of the function is to simply set the Destination point, which will emit + * the destinationChanged() SIGNAL, which triggers the slewFocus() SLOT. Additionally, this + * function performs some bookkeeping tasks, such updating whether we are tracking the new + * object/position, adding a Planet Trail if required, etc. + * + * @see destinationChanged() + * @see slewFocus() + */ + void slotCenter(); + + /** Checks whether the timestep exceeds a threshold value. If so, sets + * ClockSlewing=true and sets the SimClock to ManualMode. + */ + void slotClockSlewing(); + + /** Zoom in one step. */ + void slotZoomIn(); + + /** Zoom out one step. */ + void slotZoomOut(); + + /** Set default zoom. */ + void slotZoomDefault(); + /** + * @short centres skyObj in SkyMap and opens context drawer with skyObj + * Used in FindDialogLite + */ + void slotSelectObject(SkyObject *skyObj); + + /** @short updates focus of SkyMapLite according to data from DeviceOrientation + (Smartphone's sensors)*/ + void updateAutomaticMode(); + + void setSkyRotation(double skyRotation); + + signals: + /** Emitted by setDestination(), and connected to slewFocus(). Whenever the Destination + * point is changed, slewFocus() will iteratively step the Focus toward Destination + * until it is reached. + * @see SkyMap::setDestination() + * @see SkyMap::slewFocus() + */ + void destinationChanged(); + + /** Emitted when zoom level is changed. */ + void zoomChanged(); + + /** Emitted when current object changed. */ + void objectChanged(); + + /** Wrapper of ClickedObject for QML **/ + void objectLiteChanged(); + + /** Wrapper of ClickedPoint for QML **/ + void pointLiteChanged(); + + /** Emitted when pointing changed. (At least should) */ + void positionChanged(); + + /** Emitted when position under mouse changed. */ + void mousePointChanged(SkyPoint *); + + /** Emitted when a position is clicked */ + void positionClicked(SkyPoint *); + + /** Emitted when user clicks on SkyMapLite (analogous to positionClicked but sends QPoint) */ + void posClicked(QPointF pos); + + /** Emitted when magnitude limit is changed */ + void magLimChanged(double magLim); + + /** Emitted when FOVSymbols list was changed (new value appended) **/ + void symbolsFOVChanged(QStringList); + + /** Emitted when SkyMapLite is being slewed or slewing is finished **/ + void slewingChanged(bool); + + void centerLockedChanged(bool); + + void automaticModeChanged(bool); + + /** Emitted when skyRotation used to rotate coordinates of SkyPoints is changed **/ + void skyRotationChanged(double skyRotation); + + protected: + /** Process keystrokes: + * @li arrow keys Slew the map + * @li +/- keys Zoom in and out + * @li Space Toggle between Horizontal and Equatorial coordinate systems + * @li 0-9 Go to a major Solar System body (0=Sun; 1-9 are the major planets, except 3=Moon) + * @li [ Place starting point for measuring an angular distance + * @li ] End point for Angular Distance; display measurement. + * @li Escape Cancel Angular measurement + * @li ,/< Step backward one time step + * @li ./> Step forward one time step + */ + //virtual void keyPressEvent( QKeyEvent *e ); + + /** When keyRelease is triggered, just set the "slewing" flag to false, + * and update the display (to draw objects that are hidden when slewing==true). */ + //virtual void keyReleaseEvent( QKeyEvent *e ); + + /** Determine RA, Dec coordinates of clicked location. Find the SkyObject + * which is nearest to the clicked location. + * + * If left-clicked: Set set mouseButtonDown==true, slewing==true; display + * nearest object name in status bar. + * If right-clicked: display popup menu appropriate for nearest object. + */ + virtual void mousePressEvent(QMouseEvent *e) override; + + /** set mouseButtonDown==false, slewing==false */ + virtual void mouseReleaseEvent(QMouseEvent *e) override; + + /** Center SkyMap at double-clicked location */ + virtual void mouseDoubleClickEvent(QMouseEvent *e) override; + + /** This function does several different things depending on the state of the program: + * @li If Angle-measurement mode is active, update the end-ruler point to the mouse cursor, + * and continue this function. + * @li If we are defining a ZoomBox, update the ZoomBox rectangle, redraw the screen, + * and return. + * @li If dragging the mouse in the map, update focus such that RA, Dec under the mouse + * cursor remains constant. + * @li If just moving the mouse, simply update the curso coordinates in the status bar. + */ + virtual void mouseMoveEvent(QMouseEvent *e) override; + + /** Zoom in and out with the mouse wheel. */ + virtual void wheelEvent(QWheelEvent *e) override; + + /** + * @short this function handles zooming in and out using "pinch to zoom" gesture + */ + virtual void touchEvent(QTouchEvent *e) override; + + private slots: + /** @short display tooltip for object under cursor. It's called by m_HoverTimer. + * if mouse didn't moved for last HOVER_INTERVAL milliseconds. + */ + //void slotTransientLabel(); + + /** Set the shape of mouse cursor to a cross with 4 arrows. */ + void setMouseMoveCursor(); + + private: + /** @short Sets the shape of the default mouse cursor to a cross. */ + void setDefaultMouseCursor(); + + /** @short Sets the shape of the mouse cursor to a magnifying glass. */ + void setZoomMouseCursor(); + + /** Calculate the zoom factor for the given keyboard modifier + */ + double zoomFactor(const int modifier); + + /** calculate the magnitude factor (1, .5, .2, or .1) for the given + * keyboard modifier. + */ + double magFactor(const int modifier); + + /** Decrease the magnitude limit by a step size determined by the + * keyboard modifier. + * @param modifier + */ + void decMagLimit(const int modifier); + + /** Increase the magnitude limit by a step size determined by the + * keyboard modifier. + * @param modifier + */ + void incMagLimit(const int modifier); + + /** Convenience routine to either zoom in or increase mag limit + * depending on the Alt modifier. The Shift and Control modifiers + * will adjust the size of the zoom or the mag step. + * @param modifier + */ + void zoomInOrMagStep(const int modifier); + + /** Convenience routine to either zoom out or decrease mag limit + * depending on the Alt modifier. The Shift and Control modifiers + * will adjust the size of the zoom or the mag step. + * @param modifier + */ + void zoomOutOrMagStep(const int modifier); + + /** + * pointer to RootNode. Use it to universally access RootNode + * @warning RootNode should be used solely during updatePaintNode! See Qt Quick Scene Graph documentation. + **/ + static RootNode *m_rootNode; + static SkyMapLite *pinstance; + static int starColorMode; + + /// True if SkyMapLite was initialized (star images were initialized etc.) + bool isInitialized { false }; + bool mouseButtonDown { false }; + bool midMouseButtonDown { false }; + /// True if mouseMoveEvent; needed by setMouseMoveCursor + bool mouseMoveCursor { false }; + bool m_slewing { false }; + bool clockSlewing { false }; + /// True if pinch to zoom or pinch to rotate is performed + bool pinch { false }; + /// If false only old pixmap will repainted with bitBlt() to save a lot of CPU usage + bool computeSkymap { false }; + double y0 { 0 }; + int count { 0 }; + KStarsData *data { nullptr }; + /// True if SkyMapComposite has finished loading of SkyComponents + bool m_loadingFinished { false }; + /// Coordinates of point under cursor. It's update in function mouseMoveEvent + SkyPoint m_MousePoint; + SkyPoint Focus, ClickedPoint, FocusPoint, Destination; + SkyObject *ClickedObject { nullptr }; + SkyObject *FocusObject { nullptr }; + SkyPointLite *m_ClickedPointLite { nullptr }; + SkyObjectLite *m_ClickedObjectLite { nullptr }; + bool m_centerLocked { false }; + //SkyLine AngularRuler; //The line for measuring angles in the map + QRect ZoomRect; //The manual-focus circle. + /// Mouse should not move for that interval to display tooltip + static const int HOVER_INTERVAL = 500; + /// Timer for tooltips + QTimer m_HoverTimer; + bool m_objPointingMode { false }; + bool m_fovCaptureMode { false }; + Projector *m_proj { nullptr }; + QQuickItem *m_SkyMapLiteWrapper { nullptr }; + /// Holds SkyNodes that need to be deleted + QLinkedList m_deleteNodes; + /// Used in PointSourceNode + float m_sizeMagLim { 10 }; + /// Mag limit for all objects + double m_magLim { 0 }; + /// Used to notify zoom-dependent labels about font size change + bool m_fontSizeChanged { false }; + /// Used for drawing labels + QPainter m_painter; + /** + * This timer is triggered every time user touches the screen with one finger. + * If touch was released within 500 milliseconds than it is a tap, otherwise we pan. + **/ + QTimer m_tapBeganTimer; + /// Good to keep the original ruler start-point for purposes of dynamic_cast + const SkyPoint *m_rulerStartPoint; + QStringList m_FOVSymbols; + QList m_FOVSymVisible; + /// Total number of sizes of stars. + const int nStarSizes { 15 }; + /// Total number of spectral classes (N.B. Must be in sync with harvardToIndex) + const int nSPclasses { 7 }; + /// Cache for star images. + QVector> imageCache; + /// Textures created from cached star images + QVector> textureCache; + bool clearTextures { false }; + bool tapBegan { false }; + QList m_newTelescopes; + QList m_delTelescopes; + bool m_automaticMode { false }; + double m_skyRotation { 0 }; + SkyMapOrientation m_skyMapOrientation { SkyMapOrientation::Top0 }; #if defined(Q_OS_ANDROID) - QTimer automaticModeTimer; - DeviceOrientation *m_deviceOrientation { nullptr }; + QTimer automaticModeTimer; + DeviceOrientation *m_deviceOrientation { nullptr }; #endif };