8#include "config-kstars.h"
13#include "hips/hipsfinder.h"
14#include "kstarsdata.h"
22#ifdef HAVE_STELLARSOLVER
23#include "ekos/auxiliary/stellarsolverprofileeditor.h"
27#include "basedevice.h"
28#include "indi/indilistener.h"
31#include <KActionCollection>
32#include <KLocalizedString>
34#include <QtConcurrent>
37#include <QGraphicsOpacityEffect>
38#include <QApplication>
39#include <QImageReader>
40#include <QGestureEvent>
41#include <QMutexLocker>
42#include <QElapsedTimer>
49#define ZOOM_DEFAULT 100.0f
53#define ZOOM_LOW_INCR 10
54#define ZOOM_HIGH_INCR 50
63void ComputeGBStretchParams(
const StretchParams &newParams, StretchParams* params)
65 float shadow_diff = newParams.grey_red.shadows - params->grey_red.shadows;
66 float highlight_diff = newParams.grey_red.highlights - params->grey_red.highlights;
67 float midtones_diff = newParams.grey_red.midtones - params->grey_red.midtones;
69 params->green.shadows = params->green.shadows + shadow_diff;
70 params->green.shadows = KSUtils::clamp(params->green.shadows, 0.0f, 1.0f);
71 params->green.highlights = params->green.highlights + highlight_diff;
72 params->green.highlights = KSUtils::clamp(params->green.highlights, 0.0f, 1.0f);
73 params->green.midtones = params->green.midtones + midtones_diff;
74 params->green.midtones = std::max(params->green.midtones, 0.0f);
76 params->blue.shadows = params->blue.shadows + shadow_diff;
77 params->blue.shadows = KSUtils::clamp(params->blue.shadows, 0.0f, 1.0f);
78 params->blue.highlights = params->blue.highlights + highlight_diff;
79 params->blue.highlights = KSUtils::clamp(params->blue.highlights, 0.0f, 1.0f);
80 params->blue.midtones = params->blue.midtones + midtones_diff;
81 params->blue.midtones = std::max(params->blue.midtones, 0.0f);
90void FITSView::doStretch(
QImage *outputImage)
94 Stretch stretch(
static_cast<int>(m_ImageData->width()),
95 static_cast<int>(m_ImageData->height()),
96 m_ImageData->channels(), m_ImageData->dataType());
98 StretchParams tempParams;
100 tempParams = StretchParams();
101 else if (autoStretch)
104 stretchParams = stretch.computeParams(m_ImageData->getImageBuffer());
105 emit newStretch(stretchParams);
106 tempParams = stretchParams;
110 tempParams = stretchParams;
112 stretch.setParams(tempParams);
113 stretch.run(m_ImageData->getImageBuffer(), outputImage, m_PreviewSampling);
117void FITSView::setStretchParams(
const StretchParams ¶ms)
119 if (m_ImageData->channels() == 3)
120 ComputeGBStretchParams(params, &stretchParams);
122 stretchParams.grey_red = params.grey_red;
123 stretchParams.grey_red.shadows = std::max(stretchParams.grey_red.shadows, 0.0f);
124 stretchParams.grey_red.highlights = std::max(stretchParams.grey_red.highlights, 0.0f);
125 stretchParams.grey_red.midtones = std::max(stretchParams.grey_red.midtones, 0.0f);
130 if (m_ImageFrame && rescale(ZOOM_KEEP_LEVEL))
132 m_QueueUpdate =
true;
138void FITSView::setStretch(
bool onOff)
140 if (stretchImage != onOff)
142 stretchImage = onOff;
143 if (m_ImageFrame && rescale(ZOOM_KEEP_LEVEL))
145 m_QueueUpdate =
true;
152void FITSView::setAutoStretchParams()
156 if (m_ImageFrame && rescale(ZOOM_KEEP_LEVEL))
158 m_QueueUpdate =
true;
163FITSView::FITSView(
QWidget * parent, FITSMode fitsMode, FITSScale filterType) :
QScrollArea(parent), m_ZoomFactor(1.2)
174 stretchImage = Options::autoStretch();
185#if defined (Q_OS_LINUX) || defined (Q_OS_MACOS)
186 const long numPages = sysconf(_SC_PAGESIZE);
187 const long pageSize = sysconf(_SC_PHYS_PAGES);
191 if (numPages > 0 && pageSize > 0)
194 const int memoryMb = numPages * (
static_cast<double>(
pageSize) / 1e6);
197 else if (memoryMb < 4000)
199 else if (memoryMb < 8000)
201 else if (memoryMb < 16000)
215 markerCrosshair.setX(0);
216 markerCrosshair.setY(0);
218 setBaseSize(740, 530);
220 m_ImageFrame =
new FITSLabel(
this);
221 m_ImageFrame->setMouseTracking(
true);
222 connect(m_ImageFrame, &FITSLabel::newStatus,
this, &FITSView::newStatus);
223 connect(m_ImageFrame, &FITSLabel::mouseOverPixel,
this, &FITSView::mouseOverPixel);
224 connect(m_ImageFrame, &FITSLabel::pointSelected,
this, &FITSView::processPointSelection);
225 connect(m_ImageFrame, &FITSLabel::markerSelected,
this, &FITSView::processMarkerSelection);
226 connect(m_ImageFrame, &FITSLabel::rectangleSelected,
this, &FITSView::processRectangle);
227 connect(
this, &FITSView::setRubberBand, m_ImageFrame, &FITSLabel::setRubberBand);
228 connect(
this, &FITSView::showRubberBand, m_ImageFrame, &FITSLabel::showRubberBand);
229 connect(
this, &FITSView::zoomRubberBand, m_ImageFrame, &FITSLabel::zoomRubberBand);
231 connect(Options::self(), &Options::HIPSOpacityChanged,
this, [
this]()
235 m_QueueUpdate =
true;
239 connect(Options::self(), &Options::HIPSOffsetXChanged,
this, [
this]()
243 m_QueueUpdate =
true;
244 m_HiPSOverlayPixmap =
QPixmap();
248 connect(Options::self(), &Options::HIPSOffsetYChanged,
this, [
this]()
252 m_QueueUpdate =
true;
253 m_HiPSOverlayPixmap =
QPixmap();
260 m_UpdateFrameTimer.setInterval(50);
261 m_UpdateFrameTimer.setSingleShot(
true);
264 this->updateFrame(
true);
272 noImageLabel =
new QLabel();
273 noImage.load(
":/images/noimage.png");
274 noImageLabel->setPixmap(noImage);
276 setWidget(noImageLabel);
290 m_UpdateFrameTimer.
stop();
300void FITSView::updateMouseCursor()
302 if (cursorMode == dragCursor)
306 if (!m_ImageFrame->getMouseButtonDown())
314 else if (cursorMode == selectCursor)
318 else if (cursorMode == scopeCursor)
322 else if (cursorMode == crosshairCursor)
336void FITSView::setCursorMode(CursorMode mode)
341 if (mode == scopeCursor && imageHasWCS())
343 if (m_ImageData->getWCSState() == FITSData::Idle && !wcsWatcher.
isRunning())
345#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
357 if (m_ImageData ==
nullptr && noImageLabel !=
nullptr)
359 noImageLabel->setPixmap(
361 noImageLabel->setFixedSize(
width() - 5,
height() - 5);
368void FITSView::loadFile(
const QString &inFilename)
370 if (floatingToolBar !=
nullptr)
375 bool setBayerParams =
false;
378 if ((m_ImageData !=
nullptr) && m_ImageData->hasDebayer())
380 setBayerParams =
true;
381 m_ImageData->getBayerParams(¶m);
393 filterStack.
push(FITS_NONE);
394 if (filter != FITS_NONE)
395 filterStack.
push(filter);
400 m_ImageData->setBayerParams(¶m);
402 fitsWatcher.
setFuture(m_ImageData->loadFromFile(inFilename));
405void FITSView::clearData()
409 noImageLabel =
new QLabel();
410 noImage.
load(
":/images/noimage.png");
411 noImageLabel->setPixmap(noImage);
422 if (floatingToolBar !=
nullptr)
431 filterStack.
push(FITS_NONE);
432 if (filter != FITS_NONE)
433 filterStack.
push(filter);
435 m_HiPSOverlayPixmap =
QPixmap();
440 if (m_ImageMask !=
nullptr)
441 m_ImageMask->setImageGeometry(data->width(), data->height());
450 emit failed(m_LastError);
455bool FITSView::processData()
461 connect(m_ImageData.
data(), &FITSData::dataChanged,
this, [
this]()
463 rescale(ZOOM_KEEP_LEVEL);
467 currentWidth = m_ImageData->width();
468 currentHeight = m_ImageData->height();
470 int image_width = currentWidth;
471 int image_height = currentHeight;
475 m_ImageFrame =
new FITSLabel(
this);
476 m_ImageFrame->setMouseTracking(
true);
477 connect(m_ImageFrame, &FITSLabel::newStatus,
this, &FITSView::newStatus);
478 connect(m_ImageFrame, &FITSLabel::pointSelected,
this, &FITSView::processPointSelection);
479 connect(m_ImageFrame, &FITSLabel::markerSelected,
this, &FITSView::processMarkerSelection);
481 m_ImageFrame->setSize(image_width, image_height);
487 m_ImageData->applyFilter(filter);
489 double availableRAM = 0;
490 if (Options::adaptiveSampling() && (availableRAM = KSUtils::getAvailableRAM()) > 0)
493 double max_size = image_width * image_height * 4;
495 double ratio = max_size / availableRAM;
499 m_AdaptiveSampling = 1;
500 else if (ratio < 0.2)
501 m_AdaptiveSampling = 2;
503 m_AdaptiveSampling = 4;
505 m_PreviewSampling = m_AdaptiveSampling;
513 if (rescale(ZOOM_FIT_WINDOW) ==
false)
515 m_LastError =
i18n(
"Rescaling image failed.");
523 if (rescale(ZOOM_KEEP_LEVEL) ==
false)
525 m_LastError =
i18n(
"Rescaling image failed.");
533 if ((mode == FITS_NORMAL || mode == FITS_ALIGN) &&
534 m_ImageData->hasWCS() && m_ImageData->getWCSState() == FITSData::Idle &&
535 Options::autoWCS() &&
538#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
549 emit newStatus(
QString(
"%1x%2").arg(image_width).arg(image_height), FITS_RESOLUTION);
553 if(floatingToolBar !=
nullptr)
560 m_QueueUpdate =
true;
565void FITSView::loadInFrame()
570 emit failed(
"No image file.");
574 m_LastError = m_ImageData->getLastError();
577 if (fitsWatcher.
result() ==
false)
579 emit failed(m_LastError);
584 emit debayerToggled(m_ImageData->hasDebayer());
589 emit failed(m_LastError);
592bool FITSView::saveImage(
const QString &newFilename)
601 return m_ImageData->saveImage(newFilename);
604FITSView::CursorMode FITSView::getCursorMode()
609#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
612void FITSView::enterEvent(
QEvent * event)
617 if (floatingToolBar && m_ImageData)
620 floatingToolBar->setGraphicsEffect(eff);
623 a->setStartValue(0.2);
630void FITSView::leaveEvent(
QEvent * event)
634 if (floatingToolBar && m_ImageData)
647bool FITSView::rescale(FITSZoom type)
652 int image_width = m_ImageData->width();
653 int image_height = m_ImageData->height();
654 currentWidth = image_width;
655 currentHeight = image_height;
658 emit newStatus(
QString(
"%1x%2").arg(image_width).arg(image_height), FITS_RESOLUTION);
662 case ZOOM_FIT_WINDOW:
663 if ((image_width >
width() || image_height >
height()))
665 double w =
baseSize().width() - BASE_OFFSET;
666 double h =
baseSize().height() - BASE_OFFSET;
675 double zoomX = (w /
static_cast<double>(currentWidth)) * 100.0;
676 double zoomY = (h /
static_cast<double>(currentHeight)) * 100.0;
678 (zoomX < zoomY) ? currentZoom = zoomX : currentZoom = zoomY;
680 currentWidth = image_width * (currentZoom / ZOOM_DEFAULT);
681 currentHeight = image_height * (currentZoom / ZOOM_DEFAULT);
683 if (currentZoom <= ZOOM_MIN)
684 emit actionUpdated(
"view_zoom_out",
false);
689 currentWidth = image_width;
690 currentHeight = image_height;
694 case ZOOM_KEEP_LEVEL:
696 currentWidth = image_width * (currentZoom / ZOOM_DEFAULT);
697 currentHeight = image_height * (currentZoom / ZOOM_DEFAULT);
708 m_ImageFrame->setScaledContents(
true);
709 doStretch(&rawImage);
717void FITSView::emitZoom()
720 double zoom = std::round(currentZoom * 100.0) / 100.0;
721 emit newStatus(
i18nc(
"%1 is the value, % is the percent sign",
"%1%", zoom), FITS_ZOOM);
724void FITSView::ZoomIn()
729 if (currentZoom >= ZOOM_DEFAULT && Options::limitedResourcesMode())
731 emit newStatus(
i18n(
"Cannot zoom in further due to active limited resources mode."), FITS_MESSAGE);
735 if (currentZoom < ZOOM_DEFAULT)
736 currentZoom += ZOOM_LOW_INCR;
738 currentZoom += ZOOM_HIGH_INCR;
740 emit actionUpdated(
"view_zoom_out",
true);
741 if (currentZoom >= zoomMax)
743 currentZoom = zoomMax;
744 emit actionUpdated(
"view_zoom_in",
false);
747 currentWidth = m_ImageData->width() * (currentZoom / ZOOM_DEFAULT);
748 currentHeight = m_ImageData->height() * (currentZoom / ZOOM_DEFAULT);
755 emit zoomRubberBand(getCurrentZoom() / ZOOM_DEFAULT);
758void FITSView::ZoomOut()
763 if (currentZoom <= ZOOM_DEFAULT)
764 currentZoom -= ZOOM_LOW_INCR;
766 currentZoom -= ZOOM_HIGH_INCR;
768 if (currentZoom <= ZOOM_MIN)
770 currentZoom = ZOOM_MIN;
771 emit actionUpdated(
"view_zoom_out",
false);
774 emit actionUpdated(
"view_zoom_in",
true);
776 currentWidth = m_ImageData->width() * (currentZoom / ZOOM_DEFAULT);
777 currentHeight = m_ImageData->height() * (currentZoom / ZOOM_DEFAULT);
784 emit zoomRubberBand(getCurrentZoom() / ZOOM_DEFAULT);
787void FITSView::ZoomToFit()
792 if (rawImage.
isNull() ==
false)
794 rescale(ZOOM_FIT_WINDOW);
797 emit zoomRubberBand(getCurrentZoom() / ZOOM_DEFAULT);
802int FITSView::filterStars()
804 return ((m_ImageMask.
isNull() ==
false
805 && m_ImageMask->active()) ? m_ImageData->filterStars(m_ImageMask) : m_ImageData->getStarCenters().count());
808void FITSView::setImageMask(ImageMask *mask)
810 if (m_ImageMask.
isNull() ==
false)
814 mask->setImageGeometry(m_ImageMask->width(), m_ImageMask->height());
822bool FITSView::isLargeImage()
824 constexpr int largeImageNumPixels = 1000 * 1000;
825 return rawImage.
width() * rawImage.
height() >= largeImageNumPixels;
833double FITSView::getScale()
835 return (isLargeImage() ? 1.0 : currentZoom / ZOOM_DEFAULT) / m_PreviewSampling;
841double FITSView::scaleSize(
double size)
845 return (currentZoom > 100.0 ?
size : std::round(
size * 100.0 / currentZoom)) / m_PreviewSampling;
848void FITSView::updateFrame(
bool now)
862 if (toggleStretchAction)
863 toggleStretchAction->
setChecked(stretchImage);
870 updateFrameLargeImage();
872 updateFrameSmallImage();
874 if (m_QueueUpdate && m_StretchingInProgress ==
false)
876 m_QueueUpdate =
false;
881 m_UpdateFrameTimer.
start();
885bool FITSView::initDisplayPixmap(
QImage &image,
float scale)
887 ImageMosaicMask *
mask =
dynamic_cast<ImageMosaicMask *
>(m_ImageMask.
get());
896 int space =
mask->space();
898 displayPixmap =
QPixmap((3 *
width + 2 * space) * scale, (3 *
width + 2 * space) * scale);
906 const int posx =
pos % 3;
907 const int posy =
pos++ / 3;
908 const int tilewidth =
width * scale;
909 QRectF source(tile.x() * scale, tile.y()*scale, tilewidth, tilewidth);
911 painter.drawImage(target, image, source);
916void FITSView::updateFrameLargeImage()
918 if (!initDisplayPixmap(rawImage, 1.0 / m_PreviewSampling))
924 painter.setFont(
font);
926 drawStarRingFilter(&painter, 1.0 / m_PreviewSampling,
dynamic_cast<ImageRingMask *
>(m_ImageMask.
get()));
927 drawOverlay(&painter, 1.0 / m_PreviewSampling);
928 m_ImageFrame->setPixmap(displayPixmap);
929 m_ImageFrame->resize(((m_PreviewSampling * currentZoom) / 100.0) * displayPixmap.
size());
932void FITSView::updateFrameSmallImage()
935 if (!initDisplayPixmap(scaledImage, currentZoom / ZOOM_DEFAULT))
941 drawStarRingFilter(&painter, currentZoom / ZOOM_DEFAULT,
dynamic_cast<ImageRingMask *
>(m_ImageMask.
get()));
942 drawOverlay(&painter, currentZoom / ZOOM_DEFAULT);
943 m_ImageFrame->setPixmap(displayPixmap);
944 m_ImageFrame->resize(currentWidth, currentHeight);
947void FITSView::drawStarRingFilter(
QPainter *painter,
double scale, ImageRingMask *ringMask)
949 if (ringMask ==
nullptr || !ringMask->active())
952 const double w = m_ImageData->width() * scale;
953 const double h = m_ImageData->height() * scale;
954 double const diagonal = std::sqrt(w * w + h * h) / 2;
955 int const innerRadius = std::lround(diagonal * ringMask->innerRadius());
956 int const outerRadius = std::lround(diagonal * ringMask->outerRadius());
962 painter->
drawEllipse(center, outerRadius, outerRadius);
964 painter->
drawEllipse(center, innerRadius, innerRadius);
972int drawClippingOneChannel(T *inputBuffer,
QPainter *painter,
int width,
int height,
double clipVal,
double scale)
977 const T clipping = clipVal;
978 constexpr int timeoutMilliseconds = 3 * 1000;
982 for (
int y = 0; y < height; y++)
984 auto inputLine = inputBuffer + y * width;
986 for (
int x = 0; x < width; x++)
988 if (*inputLine++ > clipping)
998 painter->
drawLine(start, y, width - 1, y);
1001 if (*inputLine++ > clipping)
1011 painter->
drawLine(start, y, x - 1, y);
1017 if (timer.elapsed() > timeoutMilliseconds)
1027template <
typename T>
1028int drawClippingThreeChannels(T *inputBuffer,
QPainter *painter,
int width,
int height,
double clipVal,
double scale)
1033 const T clipping = clipVal;
1034 constexpr int timeoutMilliseconds = 3 * 1000;
1038 const int size = width * height;
1039 for (
int y = 0; y < height; y++)
1042 const T * inputLineR = inputBuffer + y * width;
1043 const T * inputLineG = inputLineR + size;
1044 const T * inputLineB = inputLineG + size;
1047 for (
int x = 0; x < width; x++)
1049 T inputR = inputLineR[x];
1050 T inputG = inputLineG[x];
1051 T inputB = inputLineB[x];
1053 if (inputR > clipping || inputG > clipping || inputB > clipping)
1056 const int start = x;
1064 painter->
drawLine(start, y, width - 1, y);
1067 T inputR2 = inputLineR[x];
1068 T inputG2 = inputLineG[x];
1069 T inputB2 = inputLineB[x];
1070 if (inputR2 > clipping || inputG2 > clipping || inputB2 > clipping)
1080 painter->
drawLine(start, y, x - 1, y);
1086 if (timer.elapsed() > timeoutMilliseconds)
1096template <
typename T>
1097int drawClip(T *input_buffer,
int num_channels,
QPainter *painter,
int width,
int height,
double clipVal,
double scale)
1099 if (num_channels == 1)
1100 return drawClippingOneChannel(input_buffer, painter, width, height, clipVal, scale);
1101 else if (num_channels == 3)
1102 return drawClippingThreeChannels(input_buffer, painter, width, height, clipVal, scale);
1108void FITSView::drawClipping(
QPainter *painter)
1110 auto input = m_ImageData->getImageBuffer();
1111 const int height = m_ImageData->height();
1112 const int width = m_ImageData->width();
1113 const double FLOAT_CLIP = Options::clipping64KValue();
1114 const double SHORT_CLIP = Options::clipping64KValue();
1115 const double USHORT_CLIP = Options::clipping64KValue();
1116 const double BYTE_CLIP = Options::clipping256Value();
1117 switch (m_ImageData->dataType())
1120 m_NumClipped = drawClip(
reinterpret_cast<uint8_t const*
>(input), m_ImageData->channels(), painter,
width,
height, BYTE_CLIP,
1124 m_NumClipped = drawClip(
reinterpret_cast<short const*
>(input), m_ImageData->channels(), painter,
width,
height, SHORT_CLIP,
1128 m_NumClipped = drawClip(
reinterpret_cast<unsigned short const*
>(input), m_ImageData->channels(), painter,
width,
height,
1133 m_NumClipped = drawClip(
reinterpret_cast<long const*
>(input), m_ImageData->channels(), painter,
width,
height, USHORT_CLIP,
1137 m_NumClipped = drawClip(
reinterpret_cast<float const*
>(input), m_ImageData->channels(), painter,
width,
height, FLOAT_CLIP,
1141 m_NumClipped = drawClip(
reinterpret_cast<long long const*
>(input), m_ImageData->channels(), painter,
width,
height,
1146 m_NumClipped = drawClip(
reinterpret_cast<double const*
>(input), m_ImageData->channels(), painter,
width,
height, FLOAT_CLIP,
1153 if (m_NumClipped < 0)
1154 emit newStatus(
QString(
"Clip:failed"), FITS_CLIP);
1156 emit newStatus(
QString(
"Clip:%1").arg(m_NumClipped), FITS_CLIP);
1159void FITSView::ZoomDefault()
1163 emit actionUpdated(
"view_zoom_out",
true);
1164 emit actionUpdated(
"view_zoom_in",
true);
1166 currentZoom = ZOOM_DEFAULT;
1167 currentWidth = m_ImageData->width();
1168 currentHeight = m_ImageData->height();
1178void FITSView::drawOverlay(
QPainter * painter,
double scale)
1182#if !defined(KSTARS_LITE) && defined(HAVE_WCSLIB)
1183 if (showHiPSOverlay)
1184 drawHiPSOverlay(painter, scale);
1187 if (trackingBoxEnabled && getCursorMode() != FITSView::scopeCursor)
1188 drawTrackingBox(painter, scale);
1190 if (!markerCrosshair.
isNull())
1191 drawMarker(painter, scale);
1194 drawCrosshair(painter, scale);
1197 drawObjectNames(painter, scale);
1199#if !defined(KSTARS_LITE) && defined(HAVE_WCSLIB)
1201 drawEQGrid(painter, scale);
1205 drawPixelGrid(painter, scale);
1208 drawStarCentroid(painter, scale);
1211 drawClipping(painter);
1213 if (showMagnifyingGlass)
1214 drawMagnifyingGlass(painter, scale);
1218void FITSView::drawMagnifyingGlass(
QPainter *painter,
double scale)
1220 if (magnifyingGlassX >= 0 && magnifyingGlassY >= 0 &&
1221 magnifyingGlassX < m_ImageData->
width() &&
1222 magnifyingGlassY < m_ImageData->
height())
1225 constexpr double magAmount = 8;
1227 constexpr int magWindowSize = 130;
1229 const int winXOffset = magWindowSize * 10.0 / currentZoom;
1230 const int winYOffset = magWindowSize * 10.0 / currentZoom;
1232 const int inputDimension = magWindowSize * 100 / currentZoom;
1235 const int outputDimension = inputDimension * scale + .99;
1238 int imgLeft = magnifyingGlassX - inputDimension / (2 * magAmount);
1239 int imgTop = magnifyingGlassY - inputDimension / (2 * magAmount);
1242 int winLeft = magnifyingGlassX + winXOffset;
1243 int winTop = magnifyingGlassY + winYOffset;
1247 int w = rawImage.
width();
1248 int h = rawImage.
height();
1249 const int rightLimit = std::min(w,
static_cast<int>((
horizontalScrollBar()->value() +
width()) * 100 / currentZoom));
1250 const int bottomLimit = std::min(h,
static_cast<int>((
verticalScrollBar()->value() +
height()) * 100 / currentZoom));
1251 if (winLeft + winXOffset + inputDimension > rightLimit)
1252 winLeft -= (2 * winXOffset + inputDimension);
1253 if (winTop + winYOffset + inputDimension > bottomLimit)
1254 winTop -= (2 * winYOffset + inputDimension);
1257 if ((imgLeft < 0 ) ||
1258 (imgLeft + inputDimension / magAmount >= w) ||
1260 (imgTop + inputDimension / magAmount > h))
1263 painter->
drawRect(winLeft * scale, winTop * scale, outputDimension, outputDimension);
1268 painter->
drawImage(
QRect(winLeft * scale, winTop * scale, outputDimension, outputDimension),
1270 QRect(imgLeft, imgTop, inputDimension / magAmount, inputDimension / magAmount));
1273 painter->
drawRect(winLeft * scale, winTop * scale, outputDimension, outputDimension);
1278void FITSView::updateMagnifyingGlass(
int x,
int y)
1283 magnifyingGlassX =
x;
1284 magnifyingGlassY =
y;
1285 if (magnifyingGlassX == -1 && magnifyingGlassY == -1)
1287 if (showMagnifyingGlass)
1289 showMagnifyingGlass =
false;
1293 showMagnifyingGlass =
true;
1298void FITSView::updateMode(FITSMode fmode)
1303void FITSView::drawMarker(
QPainter * painter,
double scale)
1305 painter->
setPen(
QPen(
QColor(KStarsData::Instance()->colorScheme()->colorNamed(
"TargetColor")),
1308 const float pxperdegree = scale * (57.3 / 1.8);
1310 const float s1 = 0.5 * pxperdegree;
1311 const float s2 = pxperdegree;
1312 const float s3 = 2.0 * pxperdegree;
1314 const float x0 = scale * markerCrosshair.
x();
1315 const float y0 = scale * markerCrosshair.
y();
1316 const float x1 = x0 - 0.5 * s1;
1317 const float y1 = y0 - 0.5 * s1;
1318 const float x2 = x0 - 0.5 * s2;
1319 const float y2 = y0 - 0.5 * s2;
1320 const float x3 = x0 - 0.5 * s3;
1321 const float y3 = y0 - 0.5 * s3;
1333bool FITSView::drawHFR(
QPainter * painter,
const QString &hfr,
int x,
int y)
1340 QRect const hfrRect(hfrBottomLeft.x(), hfrBottomLeft.y() - hfrSize.
height(), hfrSize.
width(), hfrSize.
height());
1343 if (boundingRect.contains(hfrRect))
1346 painter->
drawText(hfrBottomLeft, hfr);
1354void FITSView::drawStarCentroid(
QPainter * painter,
double scale)
1357 double fontSize = painterFont.
pointSizeF() * 2;
1363 fontSize = scaleSize(painterFont.
pointSizeF());
1365 painter->
setFont(painterFont);
1369 ImageMosaicMask *
mask =
dynamic_cast<ImageMosaicMask *
>(m_ImageMask.
get());
1371 for (
auto const &starCenter : m_ImageData->getStarCenters())
1373 int const w = std::round(starCenter->width) * scale;
1380 const double xCoord =
center.x() - 0.5;
1381 const double yCoord =
center.y() - 0.5;
1382 const int xc = std::round((xCoord - starCenter->width / 2.0f) * scale);
1383 const int yc = std::round((yCoord - starCenter->width / 2.0f) * scale);
1384 const int hw = w / 2;
1386 BahtinovEdge* bEdge =
dynamic_cast<BahtinovEdge*
>(starCenter);
1387 if (bEdge !=
nullptr)
1391 painter->
drawLine(bEdge->line[0].x1() * scale, bEdge->line[0].y1() * scale,
1392 bEdge->line[0].x2() * scale, bEdge->line[0].y2() * scale);
1394 painter->
drawLine(bEdge->line[1].x1() * scale, bEdge->line[1].y1() * scale,
1395 bEdge->line[1].x2() * scale, bEdge->line[1].y2() * scale);
1397 painter->
drawLine(bEdge->line[2].x1() * scale, bEdge->line[2].y1() * scale,
1398 bEdge->line[2].x2() * scale, bEdge->line[2].y2() * scale);
1405 double factor = 15.0;
1407 int const xo = std::round((
center.x() + offsetVector.
x() - starCenter->width / 2.0f) * scale);
1408 int const yo = std::round((
center.y() + offsetVector.
y() - starCenter->width / 2.0f) * scale);
1414 painter->
drawLine(xc + hw, yc + hw, xo + hw, yo + hw);
1420 const double radius = starCenter->HFR > 0 ? 2.0f * starCenter->HFR * scale : w;
1429 if (!drawHFR(painter, hfr, xc + w + 5, yc + w / 2))
1432 for (
int i = 0; i < 10; ++i)
1434 const double tempFontSize = painterFont.
pointSizeF() - 2;
1435 if (tempFontSize <= 0)
break;
1437 painter->
setFont(painterFont);
1438 if (drawHFR(painter, hfr, xc + w + 5, yc + w / 2))
1443 painter->
setFont(painterFont);
1449void FITSView::drawTrackingBox(
QPainter * painter,
double scale)
1453 if (trackingBox.
isNull())
1456 const int x1 = trackingBox.
x() * scale;
1457 const int y1 = trackingBox.
y() * scale;
1458 const int w = trackingBox.
width() * scale;
1459 const int h = trackingBox.
height() * scale;
1468void FITSView::drawCrosshair(
QPainter * painter,
double scale)
1470 if (!m_ImageData)
return;
1471 const int image_width = m_ImageData->width();
1472 const int image_height = m_ImageData->height();
1473 const QPointF c =
QPointF((qreal)image_width / 2 * scale, (qreal)image_height / 2 * scale);
1474 const float midX = (float)image_width / 2 * scale;
1475 const float midY = (float)image_height / 2 * scale;
1476 const float maxX = (float)image_width * scale;
1477 const float maxY = (float)image_height * scale;
1478 const float r = 50 * scale;
1480 painter->
setPen(
QPen(
QColor(KStarsData::Instance()->colorScheme()->colorNamed(
"TargetColor")), scaleSize(1)));
1483 painter->
drawLine(0, midY, midX - r, midY);
1486 painter->
drawLine(midX + r, midY, maxX, midY);
1489 painter->
drawLine(midX, 0, midX, midY - r);
1492 painter->
drawLine(midX, midY + r, midX, maxY);
1507void FITSView::drawPixelGrid(
QPainter * painter,
double scale)
1509 const float width = m_ImageData->width() * scale;
1510 const float height = m_ImageData->height() * scale;
1511 const float cX =
width / 2;
1512 const float cY =
height / 2;
1513 const float deltaX =
width / 10;
1514 const float deltaY =
height / 10;
1521#if QT_VERSION < QT_VERSION_CHECK(5,11,0)
1522 painter->
drawText(
width - (fm.width(str) + 10), cY - 5, str);
1524 painter->
drawText(
width - (fm.horizontalAdvance(str) + 10), cY - 5, str);
1533 for (
int x = deltaX;
x < cX - deltaX;
x += deltaX)
1541 for (
int y = deltaY;
y < cY - deltaY;
y += deltaY)
1544#if QT_VERSION < QT_VERSION_CHECK(5,11,0)
1545 painter->
drawText(
width - (fm.width(str) + 10), cY +
y - 5, str);
1547 painter->
drawText(
width - (fm.horizontalAdvance(str) + 10), cY +
y - 5, str);
1550#if QT_VERSION < QT_VERSION_CHECK(5,11,0)
1551 painter->
drawText(
width - (fm.width(str) + 10), cY -
y - 5, str);
1553 painter->
drawText(
width - (fm.horizontalAdvance(str) + 10), cY -
y - 5, str);
1559bool FITSView::imageHasWCS()
1561 if (m_ImageData !=
nullptr)
1562 return m_ImageData->hasWCS();
1566void FITSView::drawObjectNames(
QPainter * painter,
double scale)
1568 painter->
setPen(
QPen(
QColor(KStarsData::Instance()->colorScheme()->colorNamed(
"FITSObjectLabelColor"))));
1569 for (
const auto &listObject : m_ImageData->getSkyObjects())
1571 painter->
drawRect(listObject->x() * scale - 5, listObject->y() * scale - 5, 10, 10);
1572 painter->
drawText(listObject->x() * scale + 10, listObject->y() * scale + 10, listObject->skyObject()->name());
1576#if !defined(KSTARS_LITE) && defined(HAVE_WCSLIB)
1577void FITSView::drawHiPSOverlay(
QPainter * painter,
double scale)
1579 if (m_HiPSOverlayPixmap.
isNull())
1581 auto width = m_ImageData->width();
1582 auto height = m_ImageData->height();
1588 m_ImageData->pixelToWCS(
QPointF(0, 0), startPoint);
1590 m_ImageData->pixelToWCS(
QPointF( (
width - Options::hIPSOffsetX()) / 2.0, (
height - Options::hIPSOffsetY()) / 2.0),
1599 m_ImageData->getRecordValue(
"CROTA1", PA);
1601 auto rotation = 180 - PA.toDouble();
1605 if (HIPSFinder::Instance()->renderFOV(¢erPoint, fov_radius, rotation, &image) ==
false)
1612 painter->
drawPixmap(0, 0, m_HiPSOverlayPixmap);
1624#if !defined(KSTARS_LITE) && defined(HAVE_WCSLIB)
1625void FITSView::drawEQGrid(
QPainter * painter,
double scale)
1627 const int image_width = m_ImageData->width();
1628 const int image_height = m_ImageData->height();
1630 if (m_ImageData->hasWCS())
1632 double maxRA = -1000;
1633 double minRA = 1000;
1634 double maxDec = -1000;
1635 double minDec = 1000;
1636 m_ImageData->findWCSBounds(minRA, maxRA, minDec, maxDec);
1638 auto minDecMinutes = (int)(minDec * 12);
1639 auto maxDecMinutes = (int)(maxDec * 12);
1642 (int)(minRA / 15.0 *
1644 auto maxRAMinutes = (int)(maxRA / 15.0 * 120.0);
1646 double raConvert = 15 / 120.0;
1647 double decConvert = 1.0 / 12.0;
1649 if (maxDec > 50 || minDec < -50)
1652 (int)(minRA / 15.0 * 60.0);
1653 maxRAMinutes = (int)(maxRA / 15.0 * 60.0);
1654 raConvert = 15 / 60.0;
1657 if (maxDec > 80 || minDec < -80)
1660 (int)(minRA / 15.0 * 30);
1661 maxRAMinutes = (int)(maxRA / 15.0 * 30);
1662 raConvert = 15 / 30.0;
1664 if (maxDec > 85 || minDec < -85)
1667 (int)(minRA / 15.0 * 6);
1668 maxRAMinutes = (int)(maxRA / 15.0 * 6);
1669 raConvert = 15 / 6.0;
1671 if (maxDec >= 89.25 || minDec <= -89.25)
1676 maxRAMinutes = (int)(maxRA / 15);
1682 QPointF pixelPoint, imagePoint, pPoint;
1686 for (
int targetRA = minRAMinutes; targetRA <= maxRAMinutes; targetRA++)
1689 double target = targetRA * raConvert;
1691 if (eqGridPoints.count() != 0)
1692 eqGridPoints.clear();
1694 double increment = std::abs((maxDec - minDec) /
1697 for (
double targetDec = minDec; targetDec <= maxDec; targetDec += increment)
1699 SkyPoint pointToGet(target / 15.0, targetDec);
1700 bool inImage = m_ImageData->wcsToPixel(pointToGet, pixelPoint, imagePoint);
1703 QPointF pt(pixelPoint.
x() * scale, pixelPoint.
y() * scale);
1704 eqGridPoints.append(pt);
1708 if (eqGridPoints.count() > 1)
1710 for (
int i = 1; i < eqGridPoints.count(); i++)
1711 painter->
drawLine(eqGridPoints.value(i - 1), eqGridPoints.value(i));
1714 if (maxDec <= 50 && maxDec >= -50)
1716 QPointF pt = getPointForGridLabel(painter, str, scale);
1724 for (
int targetDec = minDecMinutes; targetDec <= maxDecMinutes; targetDec++)
1726 if (eqGridPoints.count() != 0)
1727 eqGridPoints.clear();
1729 double increment = std::abs((maxRA - minRA) /
1731 double target = targetDec * decConvert;
1733 for (
double targetRA = minRA; targetRA <= maxRA; targetRA += increment)
1735 SkyPoint pointToGet(targetRA / 15, targetDec * decConvert);
1736 bool inImage = m_ImageData->wcsToPixel(pointToGet, pixelPoint, imagePoint);
1739 QPointF pt(pixelPoint.
x() * scale, pixelPoint.
y() * scale);
1740 eqGridPoints.append(pt);
1743 if (eqGridPoints.count() > 1)
1745 for (
int i = 1; i < eqGridPoints.count(); i++)
1746 painter->
drawLine(eqGridPoints.value(i - 1), eqGridPoints.value(i));
1748 QPointF pt = getPointForGridLabel(painter, str, scale);
1757 bool NCPtest = m_ImageData->wcsToPixel(NCP, pPoint, imagePoint);
1761 (pPoint.
x() > 0 && pPoint.
x() < image_width) && (pPoint.
y() > 0 && pPoint.
y() < image_height);
1764 painter->
fillRect(pPoint.
x() * scale - 2, pPoint.
y() * scale - 2, 4, 4,
1765 KStarsData::Instance()->colorScheme()->colorNamed(
"TargetColor"));
1766 painter->
drawText(pPoint.
x() * scale + 15, pPoint.
y() * scale + 15,
1767 i18nc(
"North Celestial Pole",
"NCP"));
1774 bool SCPtest = m_ImageData->wcsToPixel(SCP, pPoint, imagePoint);
1778 (pPoint.
x() > 0 && pPoint.
x() < image_width) && (pPoint.
y() > 0 && pPoint.
y() < image_height);
1781 painter->
fillRect(pPoint.
x() * scale - 2, pPoint.
y() * scale - 2, 4, 4,
1782 KStarsData::Instance()->colorScheme()->colorNamed(
"TargetColor"));
1783 painter->
drawText(pPoint.
x() * scale + 15, pPoint.
y() * scale + 15,
1784 i18nc(
"South Celestial Pole",
"SCP"));
1791bool FITSView::pointIsInImage(
QPointF pt,
double scale)
1793 int image_width = m_ImageData->width();
1794 int image_height = m_ImageData->height();
1795 return pt.
x() < image_width * scale && pt.
y() < image_height * scale && pt.
x() > 0 && pt.
y() > 0;
1801#if QT_VERSION < QT_VERSION_CHECK(5,11,0)
1802 int strWidth = fm.width(str);
1804 int strWidth = fm.horizontalAdvance(str);
1806 int strHeight = fm.height();
1807 int image_width = m_ImageData->width();
1808 int image_height = m_ImageData->height();
1811 QPointF maxXPt(image_width * scale / 2, image_height * scale / 2);
1812 for (
auto &p : eqGridPoints)
1814 if (p.
x() > maxXPt.x() && pointIsInImage(p, scale))
1817 QPointF maxYPt(image_width * scale / 2, image_height * scale / 2);
1819 for (
auto &p : eqGridPoints)
1821 if (p.
y() > maxYPt.y() && pointIsInImage(p, scale))
1824 QPointF minXPt(image_width * scale / 2, image_height * scale / 2);
1826 for (
auto &p : eqGridPoints)
1828 if (p.
x() < minXPt.x() && pointIsInImage(p, scale))
1831 QPointF minYPt(image_width * scale / 2, image_height * scale / 2);
1833 for (
auto &p : eqGridPoints)
1835 if (p.
y() < minYPt.y() && pointIsInImage(p, scale))
1844 if (image_width * scale - maxXPt.x() < strWidth)
1847 image_width * scale - (strWidth + 10),
1851 if (image_height * scale - maxYPt.y() < strHeight)
1853 maxYPt.x() - (strWidth + 10),
1854 image_height * scale -
1856 if (minYPt.y() < strHeight)
1858 minYPt.x() * scale + 10,
1860 if (minXPt.x() < strWidth)
1863 minXPt.y() * scale +
1866 if (maxXPt.x() == image_width * scale / 2 && maxXPt.y() == image_height * scale / 2)
1869 return QPoint(maxXPt.x() - (strWidth + 10), maxXPt.y() - (strHeight + 10));
1872void FITSView::setFirstLoad(
bool value)
1877QPixmap &FITSView::getTrackingBoxPixmap(uint8_t margin)
1879 if (trackingBox.
isNull())
1880 return trackingBoxPixmap;
1883 const float scale = getScale();
1885 int x1 = (trackingBox.
x() - margin) * scale;
1886 int y1 = (trackingBox.
y() - margin) * scale;
1887 int w = (trackingBox.
width() + margin * 2) * scale;
1888 int h = (trackingBox.
height() + margin * 2) * scale;
1890 trackingBoxPixmap = m_ImageFrame->grab(
QRect(x1, y1, w, h));
1891 return trackingBoxPixmap;
1894void FITSView::setTrackingBox(
const QRect &rect)
1896 if (
rect != trackingBox)
1905void FITSView::resizeTrackingBox(
int newSize)
1907 int x = trackingBox.
x() + trackingBox.
width() / 2;
1908 int y = trackingBox.
y() + trackingBox.
height() / 2;
1909 int delta = newSize / 2;
1910 setTrackingBox(
QRect(
x - delta,
y - delta, newSize, newSize));
1913void FITSView::processRectangleFixed(
int s)
1915 int w = m_ImageData->width();
1916 int h = m_ImageData->height();
1919 c.
setX(qMax((
int)round(s / 2.0), c.
x()));
1920 c.
setX(qMin(w - (
int)round(s / 2.0), c.
x()));
1921 c.
setY(qMax((
int)round(s / 2.0), c.
y()));
1922 c.
setY(qMin(h - (
int)round(s / 2.0), c.
y()));
1924 QPoint topLeft, botRight;
1925 topLeft =
QPoint(c.
x() - round(s / 2.0), c.
y() - round(s / 2.0));
1926 botRight =
QPoint(c.
x() + round(s / 2.0), c.
y() + round(s / 2.0));
1928 emit setRubberBand(
QRect(topLeft, botRight));
1929 processRectangle(topLeft, botRight,
true);
1932void FITSView::processRectangle(
QPoint p1,
QPoint p2,
bool calculate)
1934 if(!isSelectionRectShown())
1948 topLeft.
setX(qMax(1, topLeft.
x()));
1949 topLeft.
setY(qMax(1, topLeft.
y()));
1950 botRight.
setX(qMin((
int)m_ImageData->width(), botRight.
x()));
1951 botRight.
setY(qMin((
int)m_ImageData->height(), botRight.
y()));
1960 m_ImageData->makeRoiBuffer(selectionRectangleRaw);
1961 emit rectangleUpdated(selectionRectangleRaw);
1970bool FITSView::isImageStretched()
1972 return stretchImage;
1975bool FITSView::isClippingShown()
1977 return showClipping;
1980bool FITSView::isCrosshairShown()
1982 return showCrosshair;
1985bool FITSView::isEQGridShown()
1990bool FITSView::isSelectionRectShown()
1992 return showSelectionRect;
1994bool FITSView::areObjectsShown()
1999bool FITSView::isPixelGridShown()
2001 return showPixelGrid;
2004bool FITSView::isHiPSOverlayShown()
2006 return showHiPSOverlay;
2009void FITSView::toggleCrosshair()
2011 showCrosshair = !showCrosshair;
2015void FITSView::toggleClipping()
2017 showClipping = !showClipping;
2021void FITSView::toggleEQGrid()
2023 showEQGrid = !showEQGrid;
2025 if (m_ImageData->getWCSState() == FITSData::Idle && !wcsWatcher.
isRunning())
2027#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
2040void FITSView::toggleHiPSOverlay()
2042 showHiPSOverlay = !showHiPSOverlay;
2044 if (m_ImageData->getWCSState() == FITSData::Idle && !wcsWatcher.
isRunning())
2046#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
2057 m_QueueUpdate =
true;
2062void FITSView::toggleSelectionMode()
2064 showSelectionRect = !showSelectionRect;
2065 if (!showSelectionRect)
2066 emit rectangleUpdated(
QRect());
2067 else if (m_ImageData)
2069 m_ImageData->makeRoiBuffer(selectionRectangleRaw);
2070 emit rectangleUpdated(selectionRectangleRaw);
2073 emit showRubberBand(showSelectionRect);
2078void FITSView::toggleObjects()
2080 showObjects = !showObjects;
2082 if (m_ImageData->getWCSState() == FITSData::Idle && !wcsWatcher.
isRunning())
2084#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
2095#if !defined(KSTARS_LITE) && defined(HAVE_WCSLIB)
2096 m_ImageData->searchObjects();
2102void FITSView::toggleStars()
2104 toggleStars(!markStars);
2109void FITSView::toggleStretch()
2111 stretchImage = !stretchImage;
2112 if (m_ImageFrame && rescale(ZOOM_KEEP_LEVEL))
2116void FITSView::toggleStarProfile()
2118#ifdef HAVE_DATAVISUALIZATION
2119 showStarProfile = !showStarProfile;
2120 if(showStarProfile && trackingBoxEnabled)
2122 if(toggleProfileAction)
2123 toggleProfileAction->
setChecked(showStarProfile);
2129 if(mode == FITS_NORMAL || mode == FITS_ALIGN)
2131 setCursorMode(selectCursor);
2132 connect(
this, SIGNAL(trackingStarSelected(
int,
int)),
this, SLOT(move3DTrackingBox(
int,
int)));
2133 trackingBox =
QRect(0, 0, 128, 128);
2134 setTrackingBoxEnabled(
true);
2135 if(starProfileWidget)
2136 connect(starProfileWidget, SIGNAL(sampleSizeUpdated(
int)),
this, SLOT(resizeTrackingBox(
int)));
2138 if(starProfileWidget)
2139 connect(starProfileWidget, SIGNAL(rejected()),
this, SLOT(toggleStarProfile()));
2145 if(mode == FITS_NORMAL || mode == FITS_ALIGN)
2147 if(getCursorMode() == selectCursor)
2148 setCursorMode(dragCursor);
2149 disconnect(
this, SIGNAL(trackingStarSelected(
int,
int)),
this, SLOT(move3DTrackingBox(
int,
int)));
2150 setTrackingBoxEnabled(
false);
2151 if(starProfileWidget)
2152 disconnect(starProfileWidget, SIGNAL(sampleSizeUpdated(
int)),
this, SLOT(resizeTrackingBox(
int)));
2154 if(starProfileWidget)
2156 disconnect(starProfileWidget, SIGNAL(rejected()),
this, SLOT(toggleStarProfile()));
2157 starProfileWidget->close();
2158 starProfileWidget =
nullptr;
2160 emit starProfileWindowClosed();
2166void FITSView::move3DTrackingBox(
int x,
int y)
2168 int boxSize = trackingBox.
width();
2169 QRect starRect =
QRect(
x - boxSize / 2,
y - boxSize / 2, boxSize, boxSize);
2170 setTrackingBox(starRect);
2173void FITSView::viewStarProfile()
2175#ifdef HAVE_DATAVISUALIZATION
2176 if(!trackingBoxEnabled)
2178 setTrackingBoxEnabled(
true);
2179 setTrackingBox(
QRect(0, 0, 128, 128));
2181 if(!starProfileWidget)
2183 starProfileWidget =
new StarProfileViewer(
this);
2194 connect(starProfileWidget, SIGNAL(rejected()),
this, SLOT(toggleStarProfile()));
2195 if(mode == FITS_ALIGN || mode == FITS_NORMAL)
2197 starProfileWidget->enableTrackingBox(
true);
2198 m_ImageData->setStarAlgorithm(ALGORITHM_CENTROID);
2199 connect(starProfileWidget, SIGNAL(sampleSizeUpdated(
int)),
this, SLOT(resizeTrackingBox(
int)));
2202 QList<Edge *> starCenters = m_ImageData->getStarCentersInSubFrame(trackingBox);
2203 if(starCenters.
size() == 0)
2208 m_ImageData->findStars(ALGORITHM_CENTROID, trackingBox).waitForFinished();
2209 starCenters = m_ImageData->getStarCentersInSubFrame(trackingBox);
2212 starProfileWidget->loadData(m_ImageData, trackingBox, starCenters);
2213 starProfileWidget->show();
2214 starProfileWidget->raise();
2221void FITSView::togglePixelGrid()
2223 showPixelGrid = !showPixelGrid;
2229 if(trackingBoxEnabled)
2230 return m_ImageData->findStars(algorithm, trackingBox);
2232 return m_ImageData->findStars(algorithm, searchBox);
2235void FITSView::toggleStars(
bool enable)
2243void FITSView::searchStars()
2246 if (m_ImageData->areStarsSearched() || !m_ImageData || (m_ImageData->getRecordValue(
"FRAME", frameType)
2247 && frameType.
toString() !=
"Light"))
2251 emit newStatus(
i18n(
"Finding stars..."), FITS_MESSAGE);
2252 qApp->processEvents();
2254#ifdef HAVE_STELLARSOLVER
2255 QVariantMap extractionSettings;
2256 extractionSettings[
"optionsProfileIndex"] = Options::hFROptionsProfile();
2257 extractionSettings[
"optionsProfileGroup"] =
static_cast<int>(Ekos::HFRProfiles);
2258 imageData()->setSourceExtractorSettings(extractionSettings);
2265 emit newStatus(
"", FITS_MESSAGE);
2270void FITSView::processPointSelection(
int x,
int y)
2272 emit trackingStarSelected(
x,
y);
2275void FITSView::processMarkerSelection(
int x,
int y)
2277 markerCrosshair.
setX(
x);
2278 markerCrosshair.
setY(
y);
2283void FITSView::setTrackingBoxEnabled(
bool enable)
2285 if (enable != trackingBoxEnabled)
2287 trackingBoxEnabled = enable;
2302#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
2305 QPoint mouseCenter = getImagePoint(
event->position().toPoint());
2307 if (
event->angleDelta().y() > 0)
2312 cleanUpZoom(mouseCenter);
2314 emit zoomRubberBand(getCurrentZoom() / ZOOM_DEFAULT);
2323void FITSView::cleanUpZoom(
QPoint viewCenter)
2327 double scale = (currentZoom / ZOOM_DEFAULT);
2328 if (!markerCrosshair.
isNull())
2330 x0 = markerCrosshair.
x() * scale;
2331 y0 = markerCrosshair.
y() * scale;
2333 else if (trackingBoxEnabled)
2335 x0 = trackingBox.
center().
x() * scale;
2336 y0 = trackingBox.
center().
y() * scale;
2338 else if (!viewCenter.
isNull())
2340 x0 = viewCenter.
x() * scale;
2341 y0 = viewCenter.
y() * scale;
2343 if ((x0 != 0) || (y0 != 0))
2345 updateMouseCursor();
2360 double scale = (currentZoom / ZOOM_DEFAULT);
2362 QPoint imagePoint =
QPoint(widgetPoint.
x() / scale, widgetPoint.
y() / scale);
2366void FITSView::initDisplayImage()
2370 int w = (m_ImageData->width() + m_PreviewSampling - 1) / m_PreviewSampling;
2371 int h = (m_ImageData->height() + m_PreviewSampling - 1) / m_PreviewSampling;
2373 if (m_ImageData->channels() == 1)
2378 for (
int i = 0; i < 256; i++)
2379 rawImage.
setColor(i, qRgb(i, i, i));
2394bool FITSView::event(
QEvent * event)
2425 if (zoomTime > 10000)
2427 if (zooming && (zoomTime % 10 == 0))
2434 cleanUpZoom(zoomLocation);
2445void FITSView::syncWCSState()
2447 bool hasWCS = m_ImageData->hasWCS();
2448 bool wcsLoaded = m_ImageData->getWCSState() == FITSData::Success;
2450#if !defined(KSTARS_LITE) && defined(HAVE_WCSLIB)
2452 m_ImageData->searchObjects();
2455 if (hasWCS && wcsLoaded)
2456 this->updateFrame();
2458 emit wcsToggled(hasWCS);
2460 if (toggleEQGridAction !=
nullptr)
2462 if (toggleObjectsAction !=
nullptr)
2464 if (centerTelescopeAction !=
nullptr)
2466 if (toggleHiPSOverlayAction !=
nullptr)
2470void FITSView::createFloatingToolBar()
2472 if (floatingToolBar !=
nullptr)
2475 floatingToolBar =
new QToolBar(
this);
2478 eff->setOpacity(0.2);
2481 "QToolBar{background: rgba(150, 150, 150, 210); border:none; color: yellow}"
2482 "QToolButton{background: transparent; border:none; color: yellow}"
2483 "QToolButton:hover{background: rgba(200, 200, 200, 255);border:solid; color: yellow}"
2484 "QToolButton:checked{background: rgba(110, 110, 110, 255);border:solid; color: yellow}");
2492 i18n(
"Zoom In"),
this, SLOT(ZoomIn()));
2495 i18n(
"Zoom Out"),
this, SLOT(ZoomOut()));
2498 i18n(
"Default Zoom"),
this, SLOT(ZoomDefault()));
2501 i18n(
"Zoom to Fit"),
this, SLOT(ZoomToFit()));
2504 i18n(
"Toggle Stretch"),
2505 this, SLOT(toggleStretch()));
2512 i18n(
"Show Cross Hairs"),
this, SLOT(toggleCrosshair()));
2516 i18n(
"Show Pixel Gridlines"),
this, SLOT(togglePixelGrid()));
2521 i18n(
"Detect Stars in Image"),
this, SLOT(toggleStars()));
2524#ifdef HAVE_DATAVISUALIZATION
2525 toggleProfileAction =
2527 i18n(
"View Star Profile..."),
this, SLOT(toggleStarProfile()));
2531 if (mode == FITS_NORMAL || mode == FITS_ALIGN)
2535 toggleEQGridAction =
2537 i18n(
"Show Equatorial Gridlines"),
this, &FITSView::toggleEQGrid);
2541 toggleObjectsAction =
2543 i18n(
"Show Objects in Image"),
this, &FITSView::toggleObjects);
2547 centerTelescopeAction =
2549 i18n(
"Center Telescope"),
this, &FITSView::centerTelescope);
2553 toggleHiPSOverlayAction =
2555 i18n(
"Show HiPS Overlay"),
this, &FITSView::toggleHiPSOverlay);
2566void FITSView::centerTelescope()
2570 if (getCursorMode() == FITSView::scopeCursor)
2572 setCursorMode(lastMouseMode);
2576 lastMouseMode = getCursorMode();
2577 setCursorMode(FITSView::scopeCursor);
2581 updateScopeButton();
2584void FITSView::updateScopeButton()
2586 if (centerTelescopeAction !=
nullptr)
2588 if (getCursorMode() == FITSView::scopeCursor)
2603bool FITSView::isTelescopeActive()
2606 if (INDIListener::Instance()->
size() == 0)
2611 for (
auto &oneDevice : INDIListener::devices())
2613 if (!(oneDevice->getDriverInterface() & INDI::BaseDevice::TELESCOPE_INTERFACE))
2615 return oneDevice->isConnected();
2623void FITSView::setStarsEnabled(
bool enable)
2626 if (floatingToolBar !=
nullptr)
2630 if (action->
text() ==
i18n(
"Detect Stars in Image"))
2639void FITSView::setStarsHFREnabled(
bool enable)
2641 showStarsHFR = enable;
2644void FITSView::setStretchValues(
double shadows,
double midtones,
double highlights)
2646 StretchParams params = getStretchParams();
2647 params.grey_red.shadows = shadows;
2648 params.grey_red.midtones = midtones;
2649 params.grey_red.highlights = highlights;
2651 setStretchParams(params);
2654void FITSView::setAutoStretch()
2656 if (!getAutoStretch())
2657 setAutoStretchParams();
The sky coordinates of a point in the sky.
virtual void updateCoordsNow(const KSNumbers *num)
updateCoordsNow Shortcut for updateCoords( const KSNumbers *num, false, nullptr, nullptr,...
dms angularDistanceTo(const SkyPoint *sp, double *const positionAngle=nullptr) const
Computes the angular distance between two SkyObjects.
An angle, stored as degrees, but expressible in many ways.
const double & Degrees() const
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
AKONADI_CALENDAR_EXPORT KCalendarCore::Event::Ptr event(const Akonadi::Item &item)
KREPORT_EXPORT QPageSize::PageSizeId pageSize(const QString &key)
QAction * zoom(const QObject *recvr, const char *slot, QObject *parent)
const char * constData() const const
QString suffix() const const
qreal pointSizeF() const const
void setPixelSize(int pixelSize)
void setPointSize(int pointSize)
void setPointSizeF(qreal pointSize)
QSize size(int flags, const QString &text, int tabStops, int *tabArray) const const
bool isRunning() const const
void setFuture(const QFuture< T > &future)
void restoreOverrideCursor()
void setOverrideCursor(const QCursor &cursor)
QIcon fromTheme(const QString &name)
bool isNull() const const
bool save(QIODevice *device, const char *format, int quality) const const
QImage scaled(const QSize &size, Qt::AspectRatioMode aspectRatioMode, Qt::TransformationMode transformMode) const const
void setColor(int index, QRgb colorValue)
void setColorCount(int colorCount)
qsizetype size() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool disconnect(const QMetaObject::Connection &connection)
bool inherits(const char *className) const const
QPaintDevice * device() const const
void drawEllipse(const QPoint ¢er, int rx, int ry)
void drawImage(const QPoint &point, const QImage &image)
void drawLine(const QLine &line)
void drawPixmap(const QPoint &point, const QPixmap &pixmap)
void drawPoints(const QPoint *points, int pointCount)
void drawRect(const QRect &rectangle)
void drawText(const QPoint &position, const QString &text)
void fillRect(const QRect &rectangle, QGradient::Preset preset)
const QFont & font() const const
QFontMetrics fontMetrics() const const
void setBrush(Qt::BrushStyle style)
void setFont(const QFont &font)
void setOpacity(qreal opacity)
void setPen(Qt::PenStyle style)
void setRenderHint(RenderHint hint, bool on)
bool convertFromImage(const QImage &image, Qt::ImageConversionFlags flags)
void fill(const QColor &color)
QPixmap fromImage(QImage &&image, Qt::ImageConversionFlags flags)
bool isNull() const const
bool load(const QString &fileName, const char *format, Qt::ImageConversionFlags flags)
QPixmap scaled(const QSize &size, Qt::AspectRatioMode aspectRatioMode, Qt::TransformationMode transformMode) const const
bool isNull() const const
bool isNull() const const
QPoint bottomRight() const const
QPoint center() const const
bool isNull() const const
QRect normalized() const const
void setBottomRight(const QPoint &position)
void setTopLeft(const QPoint &position)
QPoint topLeft() const const
void translate(const QPoint &point)
bool isNull() const const
QString arg(Args &&... args) const const
QString number(double n, char format, int precision)
QString & remove(QChar ch, Qt::CaseSensitivity cs)
QByteArray toLatin1() const const
MouseEventSynthesizedBySystem
QTextStream & center(QTextStream &stream)
QFuture< void > filter(QThreadPool *pool, Sequence &sequence, KeepFunctor &&filterFunction)
QFuture< T > run(Function function,...)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QString toString(StringFormat mode) const const
QString toString() const const