File indexing completed on 2024-04-21 14:45:52

0001 /*
0002     SPDX-FileCopyrightText: 2003-2017 Jasem Mutlaq <mutlaqja@ikarustech.com>
0003     SPDX-FileCopyrightText: 2016-2017 Robert Lancaster <rlancaste@gmail.com>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #pragma once
0009 
0010 #include "fitscommon.h"
0011 #include "auxiliary/imagemask.h"
0012 
0013 #include <config-kstars.h>
0014 #include "stretch.h"
0015 
0016 #ifdef HAVE_DATAVISUALIZATION
0017 #include "starprofileviewer.h"
0018 #endif
0019 
0020 #include <QFutureWatcher>
0021 #include <QPixmap>
0022 #include <QScrollArea>
0023 #include <QStack>
0024 #include <QTimer>
0025 #include <QPointer>
0026 
0027 #ifdef WIN32
0028 // avoid compiler warning when windows.h is included after fitsio.h
0029 #include <windows.h>
0030 #endif
0031 
0032 #include <fitsio.h>
0033 
0034 #include <memory>
0035 
0036 class QAction;
0037 class QEvent;
0038 class QGestureEvent;
0039 class QImage;
0040 class QLabel;
0041 class QPinchGesture;
0042 class QResizeEvent;
0043 class QToolBar;
0044 
0045 class FITSData;
0046 class FITSLabel;
0047 
0048 class FITSView : public QScrollArea
0049 {
0050         Q_OBJECT
0051         Q_PROPERTY(bool suspended MEMBER m_Suspended)
0052 
0053     public:
0054         explicit FITSView(QWidget *parent = nullptr, FITSMode fitsMode = FITS_NORMAL, FITSScale filterType = FITS_NONE);
0055         virtual ~FITSView() override;
0056 
0057         typedef enum {dragCursor, selectCursor, scopeCursor, crosshairCursor } CursorMode;
0058 
0059         /**
0060          * @brief loadFITS Loads FITS data and displays it in a FITSView frame
0061          * @param inFilename FITS File name
0062          * @note If image is successfully, loaded() signal is emitted, otherwise failed() signal is emitted.
0063          * Obtain error by calling lastError()
0064          */
0065         void loadFile(const QString &inFilename);
0066 
0067         /**
0068          * @brief loadFITSFromData Takes ownership of the FITSData instance passed in and displays it in a FITSView frame
0069          * @param data pointer to FITSData objects
0070          */
0071         bool loadData(const QSharedPointer<FITSData> &data);
0072 
0073         /**
0074          * @brief clearView Reset view to NO IMAGE
0075          */
0076         void clearData();
0077 
0078         // Save FITS
0079         bool saveImage(const QString &newFilename);
0080         // Rescale image lineary from image_buffer, fit to window if desired
0081         bool rescale(FITSZoom type);
0082 
0083         const QSharedPointer<FITSData> &imageData() const
0084         {
0085             return m_ImageData;
0086         }
0087 
0088         double getCurrentZoom() const
0089         {
0090             return currentZoom;
0091         }
0092         const QImage &getDisplayImage() const
0093         {
0094             return rawImage;
0095         }
0096         const QPixmap &getDisplayPixmap() const
0097         {
0098             return displayPixmap;
0099         }
0100 
0101         // Tracking square
0102         void setTrackingBoxEnabled(bool enable);
0103         bool isTrackingBoxEnabled() const
0104         {
0105             return trackingBoxEnabled;
0106         }
0107         QPixmap &getTrackingBoxPixmap(uint8_t margin = 0);
0108         void setTrackingBox(const QRect &rect);
0109         const QRect &getTrackingBox() const
0110         {
0111             return trackingBox;
0112         }
0113 
0114         // last error
0115         const QString &lastError() const
0116         {
0117             return m_LastError;
0118         }
0119 
0120         // Overlay
0121         virtual void drawOverlay(QPainter *, double scale);
0122 
0123         // Overlay objects
0124         void drawStarRingFilter(QPainter *, double scale, ImageRingMask *ringMask);
0125         void drawStarCentroid(QPainter *, double scale);
0126         void drawClipping(QPainter *);
0127         void drawTrackingBox(QPainter *, double scale);
0128         void drawMarker(QPainter *, double scale);
0129         void drawCrosshair(QPainter *, double scale);
0130 
0131 #if !defined(KSTARS_LITE) && defined(HAVE_WCSLIB)
0132         void drawEQGrid(QPainter *, double scale);
0133         void drawHiPSOverlay(QPainter *painter, double scale);
0134 #endif
0135         void drawObjectNames(QPainter *painter, double scale);
0136         void drawPixelGrid(QPainter *painter, double scale);
0137         void drawMagnifyingGlass(QPainter *painter, double scale);
0138 
0139         bool isImageStretched();
0140         bool isCrosshairShown();
0141         bool isClippingShown();
0142         bool areObjectsShown();
0143         bool isEQGridShown();
0144         bool isSelectionRectShown();
0145         bool isPixelGridShown();
0146         bool isHiPSOverlayShown();
0147         bool imageHasWCS();
0148 
0149         // Setup the graphics.
0150         void updateFrame(bool now = false);
0151 
0152         // Telescope
0153         bool isTelescopeActive();
0154         void updateScopeButton();
0155         void setScopeButton(QAction *action)
0156         {
0157             centerTelescopeAction = action;
0158         }
0159 
0160         // Events Management
0161         void enterEvent(QEvent *event) override;
0162         void leaveEvent(QEvent *event) override;
0163         CursorMode getCursorMode();
0164         void setCursorMode(CursorMode mode);
0165         void updateMouseCursor();
0166 
0167         // Zoom related
0168         void cleanUpZoom(QPoint viewCenter = QPoint());
0169         QPoint getImagePoint(QPoint viewPortPoint);
0170         uint16_t zoomedWidth()
0171         {
0172             return currentWidth;
0173         }
0174         uint16_t zoomedHeight()
0175         {
0176             return currentHeight;
0177         }
0178         double ZoomFactor() const
0179         {
0180             return m_ZoomFactor;
0181         }
0182 
0183         // Star Detection
0184         QFuture<bool> findStars(StarAlgorithm algorithm = ALGORITHM_CENTROID, const QRect &searchBox = QRect());
0185         void toggleStars(bool enable);
0186         void searchStars();
0187         void setStarsEnabled(bool enable);
0188         void setStarsHFREnabled(bool enable);
0189         int filterStars();
0190 
0191         // image masks
0192         QSharedPointer<ImageMask> imageMask() { return m_ImageMask; }
0193         void setImageMask(ImageMask *mask);
0194 
0195         // FITS Mode
0196         void updateMode(FITSMode fmode);
0197         FITSMode getMode()
0198         {
0199             return mode;
0200         }
0201 
0202         void setFilter(FITSScale newFilter)
0203         {
0204             filter = newFilter;
0205         }
0206 
0207         void setFirstLoad(bool value);
0208 
0209         void pushFilter(FITSScale value)
0210         {
0211             filterStack.push(value);
0212         }
0213         FITSScale popFilter()
0214         {
0215             return filterStack.pop();
0216         }
0217 
0218         CursorMode lastMouseMode { selectCursor };
0219         bool isStarProfileShown()
0220         {
0221             return showStarProfile;
0222         }
0223         // Floating toolbar
0224         void createFloatingToolBar();
0225 
0226         //void setLoadWCSEnabled(bool value);
0227 
0228         // Returns the params set to stretch the image.
0229         StretchParams getStretchParams() const
0230         {
0231             return stretchParams;
0232         }
0233 
0234         // Returns true if we're automatically generating stretch parameters.
0235         // Note: this is not whether we're stretching, that's controlled by stretchImage.
0236         bool getAutoStretch() const
0237         {
0238             return autoStretch;
0239         }
0240 
0241         // Sets the params for stretching. Will also stretch and re-display the image.
0242         // This only sets the first channel stretch params. For RGB images, the G&B channel
0243         // stretch parameters are a function of the Red input param and the existing RGB params.
0244         void setStretchParams(const StretchParams &params);
0245 
0246         // Sets whether to stretch the image or not.
0247         // Will also re-display the image if onOff != stretchImage.
0248         void setStretch(bool onOff);
0249 
0250         // Automatically generates stretch parameters and use them to re-display the image.
0251         void setAutoStretchParams();
0252 
0253         // When sampling is > 1, we will display the image at a lower resolution.
0254         // When sampling = 0, reset to the adaptive sampling value
0255         void setPreviewSampling(uint8_t value)
0256         {
0257             if (value == 0)
0258             {
0259                 m_PreviewSampling = m_AdaptiveSampling;
0260                 m_StretchingInProgress = false;
0261             }
0262             else
0263             {
0264                 m_PreviewSampling = value * m_AdaptiveSampling;
0265                 m_StretchingInProgress = true;
0266             }
0267         }
0268 
0269         // Returns the number of clipped pixels, if that's being computed.
0270         int getNumClipped()
0271         {
0272             return m_NumClipped;
0273         }
0274 
0275         QRect getSelectionRegion() const
0276         {
0277             return selectionRectangleRaw;
0278         }
0279 
0280     public slots:
0281         void wheelEvent(QWheelEvent *event) override;
0282         void resizeEvent(QResizeEvent *event) override;
0283         void ZoomIn();
0284         void ZoomOut();
0285         void ZoomDefault();
0286         void ZoomToFit();
0287         void updateMagnifyingGlass(int x, int y);
0288 
0289         // Grids
0290         void toggleEQGrid();
0291         void toggleObjects();
0292         void togglePixelGrid();
0293         void toggleCrosshair();
0294 
0295         // HiPS
0296         void toggleHiPSOverlay();
0297 
0298         //Selection Rectngle
0299         void toggleSelectionMode();
0300 
0301         // Stars
0302         void toggleStars();
0303         void toggleStarProfile();
0304         void viewStarProfile();
0305 
0306         void centerTelescope();
0307 
0308         void toggleStretch();
0309         void toggleClipping();
0310 
0311         virtual void processPointSelection(int x, int y);
0312         virtual void processMarkerSelection(int x, int y);
0313 
0314         void move3DTrackingBox(int x, int y);
0315         void resizeTrackingBox(int newSize);
0316         void processRectangle(QPoint p1, QPoint p2, bool refreshCenter = false);
0317         void processRectangleFixed(int s);
0318 
0319     protected slots:
0320         /**
0321              * @brief syncWCSState Update toolbar and actions depending on whether WCS is available or not
0322              */
0323         void syncWCSState();
0324 
0325         bool event(QEvent *event) override;
0326         bool gestureEvent(QGestureEvent *event);
0327         void pinchTriggered(QPinchGesture *gesture);
0328 
0329     protected:
0330         double average();
0331         double stddev();
0332         void calculateMaxPixel(double min, double max);
0333         void initDisplayImage();
0334 
0335         QPointF getPointForGridLabel(QPainter *painter, const QString &str, double scale);
0336         bool pointIsInImage(QPointF pt, double scale);
0337 
0338         void loadInFrame();
0339 
0340         double getScale();
0341 
0342         /// selectionRectangleRaw is used to do the calculations, this rectangle remains the same when user changes the zoom
0343         QRect selectionRectangleRaw;
0344         /// Floating toolbar
0345         QToolBar *floatingToolBar { nullptr };
0346         /// WCS Future Watcher
0347         QFutureWatcher<bool> wcsWatcher;
0348         /// FITS Future Watcher
0349         QFutureWatcher<bool> fitsWatcher;
0350         /// Cross hair
0351         QPointF markerCrosshair;
0352         /// Pointer to FITSData object
0353         QSharedPointer<FITSData> m_ImageData;
0354         /// Current zoom level
0355         double currentZoom { 0 };
0356         // The maximum percent zoom. The value is recalculated in the constructor
0357         // based on the amount of physical memory.
0358         int zoomMax { 400 };
0359         /// Image Buffer if Selection is to be done
0360         uint8_t *m_ImageRoiBuffer { nullptr };
0361         /// Above buffer size in bytes
0362         uint32_t m_ImageRoiBufferSize { 0 };
0363 
0364     private:
0365         bool processData();
0366         void doStretch(QImage *outputImage);
0367         double scaleSize(double size);
0368         bool isLargeImage();
0369         bool initDisplayPixmap(QImage &image, float space);
0370         void updateFrameLargeImage();
0371         void updateFrameSmallImage();
0372         bool drawHFR(QPainter * painter, const QString &hfr, int x, int y);
0373 
0374         QPointer<QLabel> noImageLabel;
0375         QPixmap noImage;
0376         QPointer<FITSLabel> m_ImageFrame;
0377         QVector<QPointF> eqGridPoints;
0378 
0379         /// Current width due to zoom
0380         uint16_t currentWidth { 0 };
0381         /// Current height due to zoom
0382         uint16_t currentHeight { 0 };
0383         /// Image zoom factor
0384         const double m_ZoomFactor;
0385 
0386         // Original full-size image
0387         QImage rawImage;
0388         // Actual pixmap after all the overlays
0389         QPixmap displayPixmap;
0390 
0391         bool firstLoad { true };
0392         bool markStars { false };
0393         bool showStarProfile { false };
0394         bool showCrosshair { false };
0395         bool showObjects { false };
0396         bool showEQGrid { false };
0397         bool showPixelGrid { false };
0398         bool showHiPSOverlay { false };
0399         bool showStarsHFR { false };
0400         bool showClipping { false };
0401 
0402         int m_NumClipped { 0 };
0403 
0404         bool showSelectionRect { false };
0405 
0406         // Should the image be displayed in linear (false) or stretched (true).
0407         // Initial value controlled by Options::autoStretch.
0408         bool stretchImage { false };
0409 
0410         // When stretching, should we automatically compute parameters.
0411         // When first displaying, this should be true, but may be set to false
0412         // if the user has overridden the automatically set parameters.
0413         bool autoStretch { true };
0414 
0415         // Params for stretching image.
0416         StretchParams stretchParams;
0417 
0418         // Resolution for display. Sampling=2 means display every other sample.
0419         uint8_t m_PreviewSampling { 1 };
0420         bool m_StretchingInProgress { false};
0421         // Adaptive sampling is based on available RAM
0422         uint8_t m_AdaptiveSampling {1};
0423 
0424         // mask for star detection
0425         QSharedPointer<ImageMask> m_ImageMask;
0426 
0427         CursorMode cursorMode { selectCursor };
0428         bool zooming { false };
0429         int zoomTime { 0 };
0430         QPoint zoomLocation;
0431 
0432         QString filename;
0433         FITSMode mode;
0434         FITSScale filter;
0435         QString m_LastError;
0436         QTimer m_UpdateFrameTimer;
0437 
0438         QStack<FITSScale> filterStack;
0439 
0440         // Tracking box
0441         bool trackingBoxEnabled { false };
0442         QRect trackingBox;
0443         QPixmap trackingBoxPixmap;
0444         QPixmap m_HiPSOverlayPixmap;
0445 
0446         // Scope pixmap
0447         QPixmap redScopePixmap;
0448         // Magenta Scope Pixmap
0449         QPixmap magentaScopePixmap;
0450 
0451         QAction *centerTelescopeAction { nullptr };
0452         QAction *toggleEQGridAction { nullptr };
0453         QAction *toggleObjectsAction { nullptr };
0454         QAction *toggleStarsAction { nullptr };
0455         QAction *toggleProfileAction { nullptr };
0456         QAction *toggleStretchAction { nullptr };
0457         QAction *toggleHiPSOverlayAction { nullptr };
0458 
0459         // State for the magnifying glass overlay.
0460         int magnifyingGlassX { -1 };
0461         int magnifyingGlassY { -1 };
0462         bool showMagnifyingGlass { false };
0463         bool m_Suspended {false};
0464         // Schedule updated when we have changes that adds
0465         // information to the view (not just zoom)
0466         bool m_QueueUpdate {false};
0467 
0468         QMutex updateMutex;
0469 
0470         //Star Profile Viewer
0471 #ifdef HAVE_DATAVISUALIZATION
0472         QPointer<StarProfileViewer> starProfileWidget;
0473 #endif
0474 
0475     signals:
0476         void newStatus(const QString &msg, FITSBar id);
0477         void newStretch(const StretchParams &params);
0478         void debayerToggled(bool);
0479         void wcsToggled(bool);
0480         void actionUpdated(const QString &name, bool enable);
0481         void trackingStarSelected(int x, int y);
0482         void loaded();
0483         void updated();
0484         void failed(const QString &error);
0485         void starProfileWindowClosed();
0486         void rectangleUpdated(QRect roi);
0487         void setRubberBand(QRect rect);
0488         void showRubberBand(bool on = false);
0489         void zoomRubberBand(double scale);
0490         void mouseOverPixel(int x, int y);
0491 
0492         friend class FITSLabel;
0493 };