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 ¶ms); 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 ¶ms); 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 };