1 /* 2 SPDX-FileCopyrightText: 2003-2017 Jasem Mutlaq <mutlaqja@ikarustech.com> 3 SPDX-FileCopyrightText: 2016-2017 Robert Lancaster <rlancaste@gmail.com> 4 5 SPDX-License-Identifier: GPL-2.0-or-later 6 */ 7 8 #pragma once 9 10 #include "fitscommon.h" 11 12 #include <config-kstars.h> 13 #include "stretch.h" 14 15 #ifdef HAVE_DATAVISUALIZATION 16 #include "starprofileviewer.h" 17 #endif 18 19 #include <QFutureWatcher> 20 #include <QPixmap> 21 #include <QScrollArea> 22 #include <QStack> 23 #include <QTimer> 24 #include <QPointer> 25 26 #ifdef WIN32 27 // avoid compiler warning when windows.h is included after fitsio.h 28 #include <windows.h> 29 #endif 30 31 #include <fitsio.h> 32 33 #include <memory> 34 35 class QAction; 36 class QEvent; 37 class QGestureEvent; 38 class QImage; 39 class QLabel; 40 class QPinchGesture; 41 class QResizeEvent; 42 class QToolBar; 43 44 class FITSData; 45 class FITSLabel; 46 47 class FITSView : public QScrollArea 48 { 49 Q_OBJECT 50 public: 51 explicit FITSView(QWidget *parent = nullptr, FITSMode fitsMode = FITS_NORMAL, FITSScale filterType = FITS_NONE); 52 virtual ~FITSView() override; 53 54 typedef enum {dragCursor, selectCursor, scopeCursor, crosshairCursor } CursorMode; 55 56 /** 57 * @brief loadFITS Loads FITS data and displays it in a FITSView frame 58 * @param inFilename FITS File name 59 * @param silent if set, error popups are suppressed. 60 * @note If image is successfully, loaded() signal is emitted, otherwise failed() signal is emitted. 61 * Obtain error by calling lastError() 62 */ 63 void loadFile(const QString &inFilename, bool silent = true); 64 65 /** 66 * @brief loadFITSFromData Takes ownership of the FITSData instance passed in and displays it in a FITSView frame 67 * @param data pointer to FITSData objects 68 */ 69 bool loadData(const QSharedPointer<FITSData> &data); 70 71 /** 72 * @brief clearView Reset view to NO IMAGE 73 */ 74 void clearData(); 75 76 // Save FITS 77 bool saveImage(const QString &newFilename); 78 // Rescale image lineary from image_buffer, fit to window if desired 79 bool rescale(FITSZoom type); 80 imageData()81 const QSharedPointer<FITSData> &imageData() const 82 { 83 return m_ImageData; 84 } 85 getCurrentZoom()86 double getCurrentZoom() const 87 { 88 return currentZoom; 89 } getDisplayImage()90 const QImage &getDisplayImage() const 91 { 92 return rawImage; 93 } getDisplayPixmap()94 const QPixmap &getDisplayPixmap() const 95 { 96 return displayPixmap; 97 } 98 99 // Tracking square 100 void setTrackingBoxEnabled(bool enable); isTrackingBoxEnabled()101 bool isTrackingBoxEnabled() const 102 { 103 return trackingBoxEnabled; 104 } 105 QPixmap &getTrackingBoxPixmap(uint8_t margin = 0); 106 void setTrackingBox(const QRect &rect); getTrackingBox()107 const QRect &getTrackingBox() const 108 { 109 return trackingBox; 110 } 111 112 // last error lastError()113 const QString &lastError() const 114 { 115 return m_LastError; 116 } 117 118 // Overlay 119 virtual void drawOverlay(QPainter *, double scale); 120 121 // Overlay objects 122 void drawStarFilter(QPainter *, double scale); 123 void drawStarCentroid(QPainter *, double scale); 124 void drawClipping(QPainter *); 125 void drawTrackingBox(QPainter *, double scale); 126 void drawMarker(QPainter *, double scale); 127 void drawCrosshair(QPainter *, double scale); 128 129 #if !defined(KSTARS_LITE) && defined(HAVE_WCSLIB) 130 void drawEQGrid(QPainter *, double scale); 131 #endif 132 void drawObjectNames(QPainter *painter, double scale); 133 void drawPixelGrid(QPainter *painter, double scale); 134 void drawMagnifyingGlass(QPainter *painter, double scale); 135 136 bool isImageStretched(); 137 bool isCrosshairShown(); 138 bool isClippingShown(); 139 bool areObjectsShown(); 140 bool isEQGridShown(); 141 bool isPixelGridShown(); 142 bool imageHasWCS(); 143 144 // Setup the graphics. 145 void updateFrame(bool now = false); 146 147 bool isTelescopeActive(); 148 149 void enterEvent(QEvent *event) override; 150 void leaveEvent(QEvent *event) override; 151 CursorMode getCursorMode(); 152 void setCursorMode(CursorMode mode); 153 void updateMouseCursor(); 154 155 void updateScopeButton(); setScopeButton(QAction * action)156 void setScopeButton(QAction *action) 157 { 158 centerTelescopeAction = action; 159 } 160 161 // Zoom related 162 void cleanUpZoom(QPoint viewCenter = QPoint()); 163 QPoint getImagePoint(QPoint viewPortPoint); zoomedWidth()164 uint16_t zoomedWidth() 165 { 166 return currentWidth; 167 } zoomedHeight()168 uint16_t zoomedHeight() 169 { 170 return currentHeight; 171 } ZoomFactor()172 double ZoomFactor() const 173 { 174 return m_ZoomFactor; 175 } 176 177 178 // Star Detection 179 QFuture<bool> findStars(StarAlgorithm algorithm = ALGORITHM_CENTROID, const QRect &searchBox = QRect()); 180 void toggleStars(bool enable); 181 void searchStars(); 182 void setStarsEnabled(bool enable); 183 void setStarsHFREnabled(bool enable); 184 void setStarFilterRange(float const innerRadius, float const outerRadius); 185 int filterStars(); 186 187 // FITS Mode 188 void updateMode(FITSMode fmode); getMode()189 FITSMode getMode() 190 { 191 return mode; 192 } 193 setFilter(FITSScale newFilter)194 void setFilter(FITSScale newFilter) 195 { 196 filter = newFilter; 197 } 198 199 void setFirstLoad(bool value); 200 pushFilter(FITSScale value)201 void pushFilter(FITSScale value) 202 { 203 filterStack.push(value); 204 } popFilter()205 FITSScale popFilter() 206 { 207 return filterStack.pop(); 208 } 209 210 CursorMode lastMouseMode { selectCursor }; isStarProfileShown()211 bool isStarProfileShown() 212 { 213 return showStarProfile; 214 } 215 // Floating toolbar 216 void createFloatingToolBar(); 217 218 //void setLoadWCSEnabled(bool value); 219 220 // Returns the params set to stretch the image. getStretchParams()221 StretchParams getStretchParams() const 222 { 223 return stretchParams; 224 } 225 226 // Returns true if we're automatically generating stretch parameters. 227 // Note: this is not whether we're stretching, that's controlled by stretchImage. getAutoStretch()228 bool getAutoStretch() const 229 { 230 return autoStretch; 231 } 232 233 // Sets the params for stretching. Will also stretch and re-display the image. 234 // This only sets the first channel stretch params. For RGB images, the G&B channel 235 // stretch parameters are a function of the Red input param and the existing RGB params. 236 void setStretchParams(const StretchParams ¶ms); 237 238 // Sets whether to stretch the image or not. 239 // Will also re-display the image if onOff != stretchImage. 240 void setStretch(bool onOff); 241 242 // Automatically generates stretch parameters and use them to re-display the image. 243 void setAutoStretchParams(); 244 245 // When sampling is > 1, we will display the image at a lower resolution. 246 // When sampling = 0, reset to the adaptive sampling value setPreviewSampling(uint8_t value)247 void setPreviewSampling(uint8_t value) 248 { 249 if (value == 0) 250 { 251 m_PreviewSampling = m_AdaptiveSampling; 252 m_StretchingInProgress = false; 253 } 254 else 255 { 256 m_PreviewSampling = value * m_AdaptiveSampling; 257 m_StretchingInProgress = true; 258 } 259 } 260 261 public slots: 262 void wheelEvent(QWheelEvent *event) override; 263 void resizeEvent(QResizeEvent *event) override; 264 void ZoomIn(); 265 void ZoomOut(); 266 void ZoomDefault(); 267 void ZoomToFit(); 268 void updateMagnifyingGlass(int x, int y); 269 270 // Grids 271 void toggleEQGrid(); 272 void toggleObjects(); 273 void togglePixelGrid(); 274 void toggleCrosshair(); 275 276 // Stars 277 void toggleStars(); 278 void toggleStarProfile(); 279 void viewStarProfile(); 280 281 void centerTelescope(); 282 283 void toggleStretch(); 284 void toggleClipping(); 285 286 virtual void processPointSelection(int x, int y); 287 virtual void processMarkerSelection(int x, int y); 288 void move3DTrackingBox(int x, int y); 289 void resizeTrackingBox(int newSize); 290 291 protected slots: 292 /** 293 * @brief syncWCSState Update toolbar and actions depending on whether WCS is available or not 294 */ 295 void syncWCSState(); 296 297 bool event(QEvent *event) override; 298 bool gestureEvent(QGestureEvent *event); 299 void pinchTriggered(QPinchGesture *gesture); 300 301 protected: 302 double average(); 303 double stddev(); 304 void calculateMaxPixel(double min, double max); 305 void initDisplayImage(); 306 307 QPointF getPointForGridLabel(QPainter *painter, const QString &str, double scale); 308 bool pointIsInImage(QPointF pt, double scale); 309 310 void loadInFrame(); 311 312 double getScale(); 313 314 /// Floating toolbar 315 QToolBar *floatingToolBar { nullptr }; 316 /// WCS Future Watcher 317 QFutureWatcher<bool> wcsWatcher; 318 /// FITS Future Watcher 319 QFutureWatcher<bool> fitsWatcher; 320 /// Cross hair 321 QPointF markerCrosshair; 322 /// Pointer to FITSData object 323 QSharedPointer<FITSData> m_ImageData; 324 /// Current zoom level 325 double currentZoom { 0 }; 326 // The maximum percent zoom. The value is recalculated in the constructor 327 // based on the amount of physical memory. 328 int zoomMax { 400 }; 329 330 private: 331 bool processData(); 332 void doStretch(QImage *outputImage); 333 double scaleSize(double size); 334 bool isLargeImage(); 335 void updateFrameLargeImage(); 336 void updateFrameSmallImage(); 337 bool drawHFR(QPainter * painter, const QString &hfr, int x, int y); 338 339 QPointer<QLabel> noImageLabel; 340 QPixmap noImage; 341 QPointer<FITSLabel> m_ImageFrame; 342 QVector<QPointF> eqGridPoints; 343 344 /// Current width due to zoom 345 uint16_t currentWidth { 0 }; 346 /// Current height due to zoom 347 uint16_t currentHeight { 0 }; 348 /// Image zoom factor 349 const double m_ZoomFactor; 350 351 // Original full-size image 352 QImage rawImage; 353 // Actual pixmap after all the overlays 354 QPixmap displayPixmap; 355 356 bool firstLoad { true }; 357 bool markStars { false }; 358 bool showStarProfile { false }; 359 bool showCrosshair { false }; 360 bool showObjects { false }; 361 bool showEQGrid { false }; 362 bool showPixelGrid { false }; 363 bool showStarsHFR { false }; 364 bool showClipping { false }; 365 366 // Should the image be displayed in linear (false) or stretched (true). 367 // Initial value controlled by Options::autoStretch. 368 bool stretchImage { false }; 369 370 // When stretching, should we automatically compute parameters. 371 // When first displaying, this should be true, but may be set to false 372 // if the user has overridden the automatically set parameters. 373 bool autoStretch { true }; 374 375 // Params for stretching image. 376 StretchParams stretchParams; 377 378 // Resolution for display. Sampling=2 means display every other sample. 379 uint8_t m_PreviewSampling { 1 }; 380 bool m_StretchingInProgress { false}; 381 // Adaptive sampling is based on available RAM 382 uint8_t m_AdaptiveSampling {1}; 383 384 struct 385 { used__anonf5e7b99c0208386 bool used() const 387 { 388 return innerRadius != 0.0f || outerRadius != 1.0f; 389 } 390 float innerRadius { 0.0f }; 391 float outerRadius { 1.0f }; 392 } starFilter; 393 394 CursorMode cursorMode { selectCursor }; 395 bool zooming { false }; 396 int zoomTime { 0 }; 397 QPoint zoomLocation; 398 399 QString filename; 400 FITSMode mode; 401 FITSScale filter; 402 QString m_LastError; 403 QTimer m_UpdateFrameTimer; 404 405 QStack<FITSScale> filterStack; 406 407 // Tracking box 408 bool trackingBoxEnabled { false }; 409 QRect trackingBox; 410 QPixmap trackingBoxPixmap; 411 412 // Scope pixmap 413 QPixmap redScopePixmap; 414 // Magenta Scope Pixmap 415 QPixmap magentaScopePixmap; 416 417 QAction *centerTelescopeAction { nullptr }; 418 QAction *toggleEQGridAction { nullptr }; 419 QAction *toggleObjectsAction { nullptr }; 420 QAction *toggleStarsAction { nullptr }; 421 QAction *toggleProfileAction { nullptr }; 422 QAction *toggleStretchAction { nullptr }; 423 424 // State for the magnifying glass overlay. 425 int magnifyingGlassX { -1 }; 426 int magnifyingGlassY { -1 }; 427 bool showMagnifyingGlass { false }; 428 429 //Star Profile Viewer 430 #ifdef HAVE_DATAVISUALIZATION 431 QPointer<StarProfileViewer> starProfileWidget; 432 #endif 433 434 signals: 435 void newStatus(const QString &msg, FITSBar id); 436 void debayerToggled(bool); 437 void wcsToggled(bool); 438 void actionUpdated(const QString &name, bool enable); 439 void trackingStarSelected(int x, int y); 440 void loaded(); 441 void failed(); 442 void starProfileWindowClosed(); 443 444 friend class FITSLabel; 445 }; 446