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(m_ImageFrame, &FITSLabel::highlightSelected,
this, &FITSView::processHighlight);
228 connect(m_ImageFrame, &FITSLabel::circleSelected,
this, &FITSView::processCircle);
229 connect(
this, &FITSView::setRubberBand, m_ImageFrame, &FITSLabel::setRubberBand);
230 connect(
this, &FITSView::showRubberBand, m_ImageFrame, &FITSLabel::showRubberBand);
231 connect(
this, &FITSView::zoomRubberBand, m_ImageFrame, &FITSLabel::zoomRubberBand);
233 connect(Options::self(), &Options::HIPSOpacityChanged,
this, [
this]()
237 m_QueueUpdate =
true;
241 connect(Options::self(), &Options::HIPSOffsetXChanged,
this, [
this]()
245 m_QueueUpdate =
true;
246 m_HiPSOverlayPixmap =
QPixmap();
250 connect(Options::self(), &Options::HIPSOffsetYChanged,
this, [
this]()
254 m_QueueUpdate =
true;
255 m_HiPSOverlayPixmap =
QPixmap();
262 m_UpdateFrameTimer.setInterval(50);
263 m_UpdateFrameTimer.setSingleShot(
true);
266 this->updateFrame(
true);
274 noImageLabel =
new QLabel();
275 noImage.load(
":/images/noimage.png");
276 noImageLabel->setPixmap(noImage);
278 setWidget(noImageLabel);
292 m_UpdateFrameTimer.
stop();
302void FITSView::updateMouseCursor()
304 if (cursorMode == dragCursor)
308 if (!m_ImageFrame->getMouseButtonDown())
316 else if (cursorMode == selectCursor)
320 else if (cursorMode == scopeCursor)
324 else if (cursorMode == crosshairCursor)
338void FITSView::setCursorMode(CursorMode mode)
343 if (mode == scopeCursor && imageHasWCS())
345 if (m_ImageData->getWCSState() == FITSData::Idle && !wcsWatcher.
isRunning())
347#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
359 if (m_ImageData ==
nullptr && noImageLabel !=
nullptr)
361 noImageLabel->setPixmap(
363 noImageLabel->setFixedSize(
width() - 5,
height() - 5);
370void FITSView::loadFile(
const QString &inFilename)
372 if (floatingToolBar !=
nullptr)
377 bool setBayerParams =
false;
380 if ((m_ImageData !=
nullptr) && m_ImageData->hasDebayer())
382 setBayerParams =
true;
383 m_ImageData->getBayerParams(¶m);
395 filterStack.
push(FITS_NONE);
396 if (filter != FITS_NONE)
397 filterStack.
push(filter);
402 m_ImageData->setBayerParams(¶m);
404 fitsWatcher.
setFuture(m_ImageData->loadFromFile(inFilename));
407void FITSView::clearData()
411 noImageLabel =
new QLabel();
412 noImage.
load(
":/images/noimage.png");
413 noImageLabel->setPixmap(noImage);
424 if (floatingToolBar !=
nullptr)
433 filterStack.
push(FITS_NONE);
434 if (filter != FITS_NONE)
435 filterStack.
push(filter);
437 m_HiPSOverlayPixmap =
QPixmap();
442 if (m_ImageMask !=
nullptr)
443 m_ImageMask->setImageGeometry(data->width(), data->height());
452 emit failed(m_LastError);
457bool FITSView::processData()
463 connect(m_ImageData.
data(), &FITSData::dataChanged,
this, [
this]()
465 rescale(ZOOM_KEEP_LEVEL);
469 connect(m_ImageData.
data(), &FITSData::headerChanged,
this, [
this]()
471 emit headerChanged();
474 connect(m_ImageData.
data(), &FITSData::loadingCatalogData,
this, [
this]()
481 emit catQueryFailed(text);
484 connect(m_ImageData.
data(), &FITSData::loadedCatalogData,
this, [
this]()
489 rescale(ZOOM_KEEP_LEVEL);
493 currentWidth = m_ImageData->width();
494 currentHeight = m_ImageData->height();
496 int image_width = currentWidth;
497 int image_height = currentHeight;
501 m_ImageFrame =
new FITSLabel(
this);
502 m_ImageFrame->setMouseTracking(
true);
503 connect(m_ImageFrame, &FITSLabel::newStatus,
this, &FITSView::newStatus);
504 connect(m_ImageFrame, &FITSLabel::pointSelected,
this, &FITSView::processPointSelection);
505 connect(m_ImageFrame, &FITSLabel::markerSelected,
this, &FITSView::processMarkerSelection);
506 connect(m_ImageFrame, &FITSLabel::highlightSelected,
this, &FITSView::processHighlight);
507 connect(m_ImageFrame, &FITSLabel::circleSelected,
this, &FITSView::processCircle);
509 m_ImageFrame->setSize(image_width, image_height);
515 m_ImageData->applyFilter(filter);
517 double availableRAM = 0;
518 if (Options::adaptiveSampling() && (availableRAM = KSUtils::getAvailableRAM()) > 0)
521 double max_size = image_width * image_height * 4;
523 double ratio = max_size / availableRAM;
527 m_AdaptiveSampling = 1;
528 else if (ratio < 0.2)
529 m_AdaptiveSampling = 2;
531 m_AdaptiveSampling = 4;
533 m_PreviewSampling = m_AdaptiveSampling;
541 if (rescale(ZOOM_FIT_WINDOW) ==
false)
543 m_LastError =
i18n(
"Rescaling image failed.");
551 if (rescale(ZOOM_KEEP_LEVEL) ==
false)
553 m_LastError =
i18n(
"Rescaling image failed.");
561 if ((mode == FITS_NORMAL || mode == FITS_ALIGN) &&
562 m_ImageData->hasWCS() && m_ImageData->getWCSState() == FITSData::Idle &&
563 Options::autoWCS() &&
566#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
577 emit newStatus(
QString(
"%1x%2").arg(image_width).arg(image_height), FITS_RESOLUTION);
581 if(floatingToolBar !=
nullptr)
588 m_QueueUpdate =
true;
593void FITSView::loadInFrame()
598 emit failed(
"No image file.");
602 m_LastError = m_ImageData->getLastError();
605 if (fitsWatcher.
result() ==
false)
607 emit failed(m_LastError);
612 emit debayerToggled(m_ImageData->hasDebayer());
617 emit failed(m_LastError);
620bool FITSView::saveImage(
const QString &newFilename)
629 return m_ImageData->saveImage(newFilename);
632FITSView::CursorMode FITSView::getCursorMode()
637#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
640void FITSView::enterEvent(
QEvent * event)
645 if (floatingToolBar && m_ImageData)
648 floatingToolBar->setGraphicsEffect(eff);
651 a->setStartValue(0.2);
658void FITSView::leaveEvent(
QEvent * event)
662 if (floatingToolBar && m_ImageData)
675bool FITSView::rescale(FITSZoom type)
680 int image_width = m_ImageData->width();
681 int image_height = m_ImageData->height();
682 currentWidth = image_width;
683 currentHeight = image_height;
686 emit newStatus(
QString(
"%1x%2").arg(image_width).arg(image_height), FITS_RESOLUTION);
690 case ZOOM_FIT_WINDOW:
691 if ((image_width >
width() || image_height >
height()))
693 double w =
baseSize().width() - BASE_OFFSET;
694 double h =
baseSize().height() - BASE_OFFSET;
703 double zoomX = (w /
static_cast<double>(currentWidth)) * 100.0;
704 double zoomY = (h /
static_cast<double>(currentHeight)) * 100.0;
706 (zoomX < zoomY) ? currentZoom = zoomX : currentZoom = zoomY;
708 currentWidth = image_width * (currentZoom / ZOOM_DEFAULT);
709 currentHeight = image_height * (currentZoom / ZOOM_DEFAULT);
711 if (currentZoom <= ZOOM_MIN)
712 emit actionUpdated(
"view_zoom_out",
false);
717 currentWidth = image_width;
718 currentHeight = image_height;
722 case ZOOM_KEEP_LEVEL:
724 currentWidth = image_width * (currentZoom / ZOOM_DEFAULT);
725 currentHeight = image_height * (currentZoom / ZOOM_DEFAULT);
736 m_ImageFrame->setScaledContents(
true);
737 doStretch(&rawImage);
745void FITSView::emitZoom()
748 double zoom = std::round(currentZoom * 100.0) / 100.0;
749 emit newStatus(
i18nc(
"%1 is the value, % is the percent sign",
"%1%", zoom), FITS_ZOOM);
752void FITSView::ZoomIn()
757 if (currentZoom >= ZOOM_DEFAULT && Options::limitedResourcesMode())
759 emit newStatus(
i18n(
"Cannot zoom in further due to active limited resources mode."), FITS_MESSAGE);
763 if (currentZoom < ZOOM_DEFAULT)
764 currentZoom += ZOOM_LOW_INCR;
766 currentZoom += ZOOM_HIGH_INCR;
768 emit actionUpdated(
"view_zoom_out",
true);
769 if (currentZoom >= zoomMax)
771 currentZoom = zoomMax;
772 emit actionUpdated(
"view_zoom_in",
false);
775 currentWidth = m_ImageData->width() * (currentZoom / ZOOM_DEFAULT);
776 currentHeight = m_ImageData->height() * (currentZoom / ZOOM_DEFAULT);
783 emit zoomRubberBand(getCurrentZoom() / ZOOM_DEFAULT);
786void FITSView::ZoomOut()
791 if (currentZoom <= ZOOM_DEFAULT)
792 currentZoom -= ZOOM_LOW_INCR;
794 currentZoom -= ZOOM_HIGH_INCR;
796 if (currentZoom <= ZOOM_MIN)
798 currentZoom = ZOOM_MIN;
799 emit actionUpdated(
"view_zoom_out",
false);
802 emit actionUpdated(
"view_zoom_in",
true);
804 currentWidth = m_ImageData->width() * (currentZoom / ZOOM_DEFAULT);
805 currentHeight = m_ImageData->height() * (currentZoom / ZOOM_DEFAULT);
812 emit zoomRubberBand(getCurrentZoom() / ZOOM_DEFAULT);
815void FITSView::ZoomToFit()
820 if (rawImage.
isNull() ==
false)
822 rescale(ZOOM_FIT_WINDOW);
825 emit zoomRubberBand(getCurrentZoom() / ZOOM_DEFAULT);
830int FITSView::filterStars()
832 return ((m_ImageMask.
isNull() ==
false
833 && m_ImageMask->active()) ? m_ImageData->filterStars(m_ImageMask) : m_ImageData->getStarCenters().count());
836void FITSView::setImageMask(ImageMask *mask)
838 if (m_ImageMask.
isNull() ==
false)
842 mask->setImageGeometry(m_ImageMask->width(), m_ImageMask->height());
850bool FITSView::isLargeImage()
852 constexpr int largeImageNumPixels = 1000 * 1000;
853 return rawImage.
width() * rawImage.
height() >= largeImageNumPixels;
861double FITSView::getScale()
863 return (isLargeImage() ? 1.0 : currentZoom / ZOOM_DEFAULT) / m_PreviewSampling;
869double FITSView::scaleSize(
double size)
873 return (currentZoom > 100.0 ?
size : std::round(
size * 100.0 / currentZoom)) / m_PreviewSampling;
876void FITSView::updateFrame(
bool now)
890 if (toggleStretchAction)
891 toggleStretchAction->
setChecked(stretchImage);
898 updateFrameLargeImage();
900 updateFrameSmallImage();
902 if (m_QueueUpdate && m_StretchingInProgress ==
false)
904 m_QueueUpdate =
false;
909 m_UpdateFrameTimer.
start();
913bool FITSView::initDisplayPixmap(
QImage &image,
float scale)
915 ImageMosaicMask *
mask =
dynamic_cast<ImageMosaicMask *
>(m_ImageMask.
get());
924 int space =
mask->space();
926 displayPixmap =
QPixmap((3 *
width + 2 * space) * scale, (3 *
width + 2 * space) * scale);
934 const int posx =
pos % 3;
935 const int posy =
pos++ / 3;
936 const int tilewidth =
width * scale;
937 QRectF source(tile.x() * scale, tile.y()*scale, tilewidth, tilewidth);
939 painter.drawImage(target, image, source);
944void FITSView::updateFrameLargeImage()
946 if (!initDisplayPixmap(rawImage, 1.0 / m_PreviewSampling))
952 painter.setFont(
font);
954 drawStarRingFilter(&painter, 1.0 / m_PreviewSampling,
dynamic_cast<ImageRingMask *
>(m_ImageMask.
get()));
955 drawOverlay(&painter, 1.0 / m_PreviewSampling);
956 m_ImageFrame->setPixmap(displayPixmap);
957 m_ImageFrame->resize(((m_PreviewSampling * currentZoom) / 100.0) * displayPixmap.
size());
960void FITSView::updateFrameSmallImage()
963 if (!initDisplayPixmap(scaledImage, currentZoom / ZOOM_DEFAULT))
969 drawStarRingFilter(&painter, currentZoom / ZOOM_DEFAULT,
dynamic_cast<ImageRingMask *
>(m_ImageMask.
get()));
970 drawOverlay(&painter, currentZoom / ZOOM_DEFAULT);
971 m_ImageFrame->setPixmap(displayPixmap);
972 m_ImageFrame->resize(currentWidth, currentHeight);
975void FITSView::drawStarRingFilter(
QPainter *painter,
double scale, ImageRingMask *ringMask)
977 if (ringMask ==
nullptr || !ringMask->active())
980 const double w = m_ImageData->width() * scale;
981 const double h = m_ImageData->height() * scale;
982 double const diagonal = std::sqrt(w * w + h * h) / 2;
983 int const innerRadius = std::lround(diagonal * ringMask->innerRadius());
984 int const outerRadius = std::lround(diagonal * ringMask->outerRadius());
990 painter->
drawEllipse(center, outerRadius, outerRadius);
992 painter->
drawEllipse(center, innerRadius, innerRadius);
1000int drawClippingOneChannel(T *inputBuffer,
QPainter *painter,
int width,
int height,
double clipVal,
double scale)
1005 const T clipping = clipVal;
1006 constexpr int timeoutMilliseconds = 3 * 1000;
1010 for (
int y = 0; y < height; y++)
1012 auto inputLine = inputBuffer + y * width;
1014 for (
int x = 0; x < width; x++)
1016 if (*inputLine++ > clipping)
1019 const int start = x;
1026 painter->
drawLine(start, y, width - 1, y);
1029 if (*inputLine++ > clipping)
1039 painter->
drawLine(start, y, x - 1, y);
1045 if (timer.elapsed() > timeoutMilliseconds)
1055template <
typename T>
1056int drawClippingThreeChannels(T *inputBuffer,
QPainter *painter,
int width,
int height,
double clipVal,
double scale)
1061 const T clipping = clipVal;
1062 constexpr int timeoutMilliseconds = 3 * 1000;
1066 const int size = width * height;
1067 for (
int y = 0; y < height; y++)
1070 const T * inputLineR = inputBuffer + y * width;
1071 const T * inputLineG = inputLineR + size;
1072 const T * inputLineB = inputLineG + size;
1075 for (
int x = 0; x < width; x++)
1077 T inputR = inputLineR[x];
1078 T inputG = inputLineG[x];
1079 T inputB = inputLineB[x];
1081 if (inputR > clipping || inputG > clipping || inputB > clipping)
1084 const int start = x;
1092 painter->
drawLine(start, y, width - 1, y);
1095 T inputR2 = inputLineR[x];
1096 T inputG2 = inputLineG[x];
1097 T inputB2 = inputLineB[x];
1098 if (inputR2 > clipping || inputG2 > clipping || inputB2 > clipping)
1108 painter->
drawLine(start, y, x - 1, y);
1114 if (timer.elapsed() > timeoutMilliseconds)
1124template <
typename T>
1125int drawClip(T *input_buffer,
int num_channels,
QPainter *painter,
int width,
int height,
double clipVal,
double scale)
1127 if (num_channels == 1)
1128 return drawClippingOneChannel(input_buffer, painter, width, height, clipVal, scale);
1129 else if (num_channels == 3)
1130 return drawClippingThreeChannels(input_buffer, painter, width, height, clipVal, scale);
1136void FITSView::drawClipping(
QPainter *painter)
1138 auto input = m_ImageData->getImageBuffer();
1139 const int height = m_ImageData->height();
1140 const int width = m_ImageData->width();
1141 const double FLOAT_CLIP = Options::clipping64KValue();
1142 const double SHORT_CLIP = Options::clipping64KValue();
1143 const double USHORT_CLIP = Options::clipping64KValue();
1144 const double BYTE_CLIP = Options::clipping256Value();
1145 switch (m_ImageData->dataType())
1148 m_NumClipped = drawClip(
reinterpret_cast<uint8_t const*
>(input), m_ImageData->channels(), painter,
width,
height, BYTE_CLIP,
1152 m_NumClipped = drawClip(
reinterpret_cast<short const*
>(input), m_ImageData->channels(), painter,
width,
height, SHORT_CLIP,
1156 m_NumClipped = drawClip(
reinterpret_cast<unsigned short const*
>(input), m_ImageData->channels(), painter,
width,
height,
1161 m_NumClipped = drawClip(
reinterpret_cast<long const*
>(input), m_ImageData->channels(), painter,
width,
height, USHORT_CLIP,
1165 m_NumClipped = drawClip(
reinterpret_cast<float const*
>(input), m_ImageData->channels(), painter,
width,
height, FLOAT_CLIP,
1169 m_NumClipped = drawClip(
reinterpret_cast<long long const*
>(input), m_ImageData->channels(), painter,
width,
height,
1174 m_NumClipped = drawClip(
reinterpret_cast<double const*
>(input), m_ImageData->channels(), painter,
width,
height, FLOAT_CLIP,
1181 if (m_NumClipped < 0)
1182 emit newStatus(
QString(
"Clip:failed"), FITS_CLIP);
1184 emit newStatus(
QString(
"Clip:%1").arg(m_NumClipped), FITS_CLIP);
1187void FITSView::ZoomDefault()
1191 emit actionUpdated(
"view_zoom_out",
true);
1192 emit actionUpdated(
"view_zoom_in",
true);
1194 currentZoom = ZOOM_DEFAULT;
1195 currentWidth = m_ImageData->width();
1196 currentHeight = m_ImageData->height();
1206void FITSView::drawOverlay(
QPainter * painter,
double scale)
1210#if !defined(KSTARS_LITE) && defined(HAVE_WCSLIB)
1211 if (showHiPSOverlay)
1212 drawHiPSOverlay(painter, scale);
1215 if (trackingBoxEnabled && getCursorMode() != FITSView::scopeCursor)
1216 drawTrackingBox(painter, scale);
1218 if (!markerCrosshair.
isNull())
1219 drawMarker(painter, scale);
1222 drawCrosshair(painter, scale);
1225 drawObjectNames(painter, scale);
1227#if !defined(KSTARS_LITE) && defined(HAVE_WCSLIB)
1229 drawEQGrid(painter, scale);
1233 drawPixelGrid(painter, scale);
1236 drawStarCentroid(painter, scale);
1239 drawClipping(painter);
1241 if (showMagnifyingGlass)
1242 drawMagnifyingGlass(painter, scale);
1246void FITSView::drawMagnifyingGlass(
QPainter *painter,
double scale)
1248 if (magnifyingGlassX >= 0 && magnifyingGlassY >= 0 &&
1249 magnifyingGlassX < m_ImageData->
width() &&
1250 magnifyingGlassY < m_ImageData->
height())
1253 constexpr double magAmount = 8;
1255 constexpr int magWindowSize = 130;
1257 const int winXOffset = magWindowSize * 10.0 / currentZoom;
1258 const int winYOffset = magWindowSize * 10.0 / currentZoom;
1260 const int inputDimension = magWindowSize * 100 / currentZoom;
1263 const int outputDimension = inputDimension * scale + .99;
1266 int imgLeft = magnifyingGlassX - inputDimension / (2 * magAmount);
1267 int imgTop = magnifyingGlassY - inputDimension / (2 * magAmount);
1270 int winLeft = magnifyingGlassX + winXOffset;
1271 int winTop = magnifyingGlassY + winYOffset;
1275 int w = rawImage.
width();
1276 int h = rawImage.
height();
1277 const int rightLimit = std::min(w,
static_cast<int>((
horizontalScrollBar()->value() +
width()) * 100 / currentZoom));
1278 const int bottomLimit = std::min(h,
static_cast<int>((
verticalScrollBar()->value() +
height()) * 100 / currentZoom));
1279 if (winLeft + winXOffset + inputDimension > rightLimit)
1280 winLeft -= (2 * winXOffset + inputDimension);
1281 if (winTop + winYOffset + inputDimension > bottomLimit)
1282 winTop -= (2 * winYOffset + inputDimension);
1285 if ((imgLeft < 0 ) ||
1286 (imgLeft + inputDimension / magAmount >= w) ||
1288 (imgTop + inputDimension / magAmount > h))
1291 painter->
drawRect(winLeft * scale, winTop * scale, outputDimension, outputDimension);
1296 painter->
drawPixmap(
QRect(winLeft * scale, winTop * scale, outputDimension, outputDimension),
1298 QRect(imgLeft, imgTop, inputDimension / magAmount, inputDimension / magAmount));
1301 painter->
drawRect(winLeft * scale, winTop * scale, outputDimension, outputDimension);
1306void FITSView::updateMagnifyingGlass(
int x,
int y)
1311 magnifyingGlassX =
x;
1312 magnifyingGlassY =
y;
1313 if (magnifyingGlassX == -1 && magnifyingGlassY == -1)
1315 if (showMagnifyingGlass)
1317 showMagnifyingGlass =
false;
1321 showMagnifyingGlass =
true;
1326void FITSView::updateMode(FITSMode fmode)
1331void FITSView::drawMarker(
QPainter * painter,
double scale)
1333 painter->
setPen(
QPen(
QColor(KStarsData::Instance()->colorScheme()->colorNamed(
"TargetColor")),
1336 const float pxperdegree = scale * (57.3 / 1.8);
1338 const float s1 = 0.5 * pxperdegree;
1339 const float s2 = pxperdegree;
1340 const float s3 = 2.0 * pxperdegree;
1342 const float x0 = scale * markerCrosshair.
x();
1343 const float y0 = scale * markerCrosshair.
y();
1344 const float x1 = x0 - 0.5 * s1;
1345 const float y1 = y0 - 0.5 * s1;
1346 const float x2 = x0 - 0.5 * s2;
1347 const float y2 = y0 - 0.5 * s2;
1348 const float x3 = x0 - 0.5 * s3;
1349 const float y3 = y0 - 0.5 * s3;
1361bool FITSView::drawHFR(
QPainter * painter,
const QString &hfr,
int x,
int y)
1368 QRect const hfrRect(hfrBottomLeft.x(), hfrBottomLeft.y() - hfrSize.
height(), hfrSize.
width(), hfrSize.
height());
1371 if (boundingRect.contains(hfrRect))
1374 painter->
drawText(hfrBottomLeft, hfr);
1382void FITSView::drawStarCentroid(
QPainter * painter,
double scale)
1385 double fontSize = painterFont.
pointSizeF() * 2;
1391 fontSize = scaleSize(painterFont.
pointSizeF());
1393 painter->
setFont(painterFont);
1397 ImageMosaicMask *
mask =
dynamic_cast<ImageMosaicMask *
>(m_ImageMask.
get());
1399 for (
auto const &starCenter : m_ImageData->getStarCenters())
1401 int const w = std::round(starCenter->width) * scale;
1408 const double xCoord =
center.x() - 0.5;
1409 const double yCoord =
center.y() - 0.5;
1410 const int xc = std::round((xCoord - starCenter->width / 2.0f) * scale);
1411 const int yc = std::round((yCoord - starCenter->width / 2.0f) * scale);
1412 const int hw = w / 2;
1414 BahtinovEdge* bEdge =
dynamic_cast<BahtinovEdge*
>(starCenter);
1415 if (bEdge !=
nullptr)
1419 painter->
drawLine(bEdge->line[0].x1() * scale, bEdge->line[0].y1() * scale,
1420 bEdge->line[0].x2() * scale, bEdge->line[0].y2() * scale);
1422 painter->
drawLine(bEdge->line[1].x1() * scale, bEdge->line[1].y1() * scale,
1423 bEdge->line[1].x2() * scale, bEdge->line[1].y2() * scale);
1425 painter->
drawLine(bEdge->line[2].x1() * scale, bEdge->line[2].y1() * scale,
1426 bEdge->line[2].x2() * scale, bEdge->line[2].y2() * scale);
1433 double factor = 15.0;
1435 int const xo = std::round((
center.x() + offsetVector.
x() - starCenter->width / 2.0f) * scale);
1436 int const yo = std::round((
center.y() + offsetVector.
y() - starCenter->width / 2.0f) * scale);
1442 painter->
drawLine(xc + hw, yc + hw, xo + hw, yo + hw);
1448 const double radius = starCenter->HFR > 0 ? 2.0f * starCenter->HFR * scale : w;
1457 if (!drawHFR(painter, hfr, xc + w + 5, yc + w / 2))
1460 for (
int i = 0; i < 10; ++i)
1462 const double tempFontSize = painterFont.
pointSizeF() - 2;
1463 if (tempFontSize <= 0)
break;
1465 painter->
setFont(painterFont);
1466 if (drawHFR(painter, hfr, xc + w + 5, yc + w / 2))
1471 painter->
setFont(painterFont);
1477void FITSView::drawTrackingBox(
QPainter * painter,
double scale)
1481 if (trackingBox.
isNull())
1484 const int x1 = trackingBox.
x() * scale;
1485 const int y1 = trackingBox.
y() * scale;
1486 const int w = trackingBox.
width() * scale;
1487 const int h = trackingBox.
height() * scale;
1496void FITSView::drawCrosshair(
QPainter * painter,
double scale)
1498 if (!m_ImageData)
return;
1499 const int image_width = m_ImageData->width();
1500 const int image_height = m_ImageData->height();
1501 const QPointF c =
QPointF((qreal)image_width / 2 * scale, (qreal)image_height / 2 * scale);
1502 const float midX = (float)image_width / 2 * scale;
1503 const float midY = (float)image_height / 2 * scale;
1504 const float maxX = (float)image_width * scale;
1505 const float maxY = (float)image_height * scale;
1506 const float r = 50 * scale;
1508 painter->
setPen(
QPen(
QColor(KStarsData::Instance()->colorScheme()->colorNamed(
"TargetColor")), scaleSize(1)));
1511 painter->
drawLine(0, midY, midX - r, midY);
1514 painter->
drawLine(midX + r, midY, maxX, midY);
1517 painter->
drawLine(midX, 0, midX, midY - r);
1520 painter->
drawLine(midX, midY + r, midX, maxY);
1535void FITSView::drawPixelGrid(
QPainter * painter,
double scale)
1537 const float width = m_ImageData->width() * scale;
1538 const float height = m_ImageData->height() * scale;
1539 const float cX =
width / 2;
1540 const float cY =
height / 2;
1541 const float deltaX =
width / 10;
1542 const float deltaY =
height / 10;
1549#if QT_VERSION < QT_VERSION_CHECK(5,11,0)
1550 painter->
drawText(
width - (fm.width(str) + 10), cY - 5, str);
1552 painter->
drawText(
width - (fm.horizontalAdvance(str) + 10), cY - 5, str);
1561 for (
int x = deltaX;
x < cX - deltaX;
x += deltaX)
1569 for (
int y = deltaY;
y < cY - deltaY;
y += deltaY)
1572#if QT_VERSION < QT_VERSION_CHECK(5,11,0)
1573 painter->
drawText(
width - (fm.width(str) + 10), cY +
y - 5, str);
1575 painter->
drawText(
width - (fm.horizontalAdvance(str) + 10), cY +
y - 5, str);
1578#if QT_VERSION < QT_VERSION_CHECK(5,11,0)
1579 painter->
drawText(
width - (fm.width(str) + 10), cY -
y - 5, str);
1581 painter->
drawText(
width - (fm.horizontalAdvance(str) + 10), cY -
y - 5, str);
1587bool FITSView::imageHasWCS()
1589 if (m_ImageData !=
nullptr)
1590 return m_ImageData->hasWCS();
1594void FITSView::drawObjectNames(
QPainter * painter,
double scale)
1596 if (Options::fitsCatalog() != CAT_SKYMAP)
1598#if !defined(KSTARS_LITE) && defined(HAVE_WCSLIB)
1599 drawCatObjectNames(painter, scale);
1604 painter->
setPen(
QPen(
QColor(KStarsData::Instance()->colorScheme()->colorNamed(
"FITSObjectLabelColor"))));
1605 for (
const auto &listObject : m_ImageData->getSkyObjects())
1607 painter->
drawRect(listObject->x() * scale - 5, listObject->y() * scale - 5, 10, 10);
1608 painter->
drawText(listObject->x() * scale + 10, listObject->y() * scale + 10, listObject->skyObject()->name());
1612#if !defined(KSTARS_LITE) && defined(HAVE_WCSLIB)
1613void FITSView::drawCatObjectNames(
QPainter * painter,
double scale)
1618 drawCatROI(painter, scale);
1619 bool showNames = Options::fitsCatObjShowNames();
1620 for (
const auto &catObject : m_ImageData->getCatObjects())
1622 if (!catObject.show)
1624 if (catObject.highlight)
1625 painter->
setPen(
QPen(
QColor(KStarsData::Instance()->colorScheme()->colorNamed(
"FITSObjectHighlightLabelColor"))));
1627 painter->
setPen(
QPen(
QColor(KStarsData::Instance()->colorScheme()->colorNamed(
"FITSObjectLabelColor"))));
1629 painter->
drawRect(catObject.x * scale - 5.0, catObject.y * scale - 5.0, 10, 10);
1631 painter->
drawText(catObject.x * scale + 10.0, catObject.y * scale + 10.0, catObject.name);
1636#if !defined(KSTARS_LITE) && defined(HAVE_WCSLIB)
1637void FITSView::drawCatROI(
QPainter * painter,
double scale)
1640 const QPoint pt = m_ImageData->catROIPt();
1641 const int radius = m_ImageData->catROIRadius();
1644 painter->
setPen(
QPen(
QColor(KStarsData::Instance()->colorScheme()->colorNamed(
"FITSObjectLabelColor"))));
1650#if !defined(KSTARS_LITE) && defined(HAVE_WCSLIB)
1651void FITSView::drawHiPSOverlay(
QPainter * painter,
double scale)
1653 if (m_HiPSOverlayPixmap.
isNull())
1655 auto width = m_ImageData->width();
1656 auto height = m_ImageData->height();
1662 m_ImageData->pixelToWCS(
QPointF(0, 0), startPoint);
1664 m_ImageData->pixelToWCS(
QPointF( (
width - Options::hIPSOffsetX()) / 2.0, (
height - Options::hIPSOffsetY()) / 2.0),
1673 m_ImageData->getRecordValue(
"CROTA1", PA);
1675 auto rotation = 180 - PA.toDouble();
1679 if (HIPSFinder::Instance()->renderFOV(¢erPoint, fov_radius, rotation, &image) ==
false)
1686 painter->
drawPixmap(0, 0, m_HiPSOverlayPixmap);
1698#if !defined(KSTARS_LITE) && defined(HAVE_WCSLIB)
1699void FITSView::drawEQGrid(
QPainter * painter,
double scale)
1701 const int image_width = m_ImageData->width();
1702 const int image_height = m_ImageData->height();
1704 if (m_ImageData->hasWCS())
1706 double maxRA = -1000;
1707 double minRA = 1000;
1708 double maxDec = -1000;
1709 double minDec = 1000;
1710 m_ImageData->findWCSBounds(minRA, maxRA, minDec, maxDec);
1712 auto minDecMinutes = (int)(minDec * 12);
1713 auto maxDecMinutes = (int)(maxDec * 12);
1716 (int)(minRA / 15.0 *
1718 auto maxRAMinutes = (int)(maxRA / 15.0 * 120.0);
1720 double raConvert = 15 / 120.0;
1721 double decConvert = 1.0 / 12.0;
1723 if (maxDec > 50 || minDec < -50)
1726 (int)(minRA / 15.0 * 60.0);
1727 maxRAMinutes = (int)(maxRA / 15.0 * 60.0);
1728 raConvert = 15 / 60.0;
1731 if (maxDec > 80 || minDec < -80)
1734 (int)(minRA / 15.0 * 30);
1735 maxRAMinutes = (int)(maxRA / 15.0 * 30);
1736 raConvert = 15 / 30.0;
1738 if (maxDec > 85 || minDec < -85)
1741 (int)(minRA / 15.0 * 6);
1742 maxRAMinutes = (int)(maxRA / 15.0 * 6);
1743 raConvert = 15 / 6.0;
1745 if (maxDec >= 89.25 || minDec <= -89.25)
1750 maxRAMinutes = (int)(maxRA / 15);
1756 QPointF pixelPoint, imagePoint, pPoint;
1760 for (
int targetRA = minRAMinutes; targetRA <= maxRAMinutes; targetRA++)
1763 double target = targetRA * raConvert;
1765 if (eqGridPoints.count() != 0)
1766 eqGridPoints.clear();
1768 double increment = std::abs((maxDec - minDec) /
1771 for (
double targetDec = minDec; targetDec <= maxDec; targetDec += increment)
1773 SkyPoint pointToGet(target / 15.0, targetDec);
1774 bool inImage = m_ImageData->wcsToPixel(pointToGet, pixelPoint, imagePoint);
1777 QPointF pt(pixelPoint.
x() * scale, pixelPoint.
y() * scale);
1778 eqGridPoints.append(pt);
1782 if (eqGridPoints.count() > 1)
1784 for (
int i = 1; i < eqGridPoints.count(); i++)
1785 painter->
drawLine(eqGridPoints.value(i - 1), eqGridPoints.value(i));
1788 if (maxDec <= 50 && maxDec >= -50)
1790 QPointF pt = getPointForGridLabel(painter, str, scale);
1798 for (
int targetDec = minDecMinutes; targetDec <= maxDecMinutes; targetDec++)
1800 if (eqGridPoints.count() != 0)
1801 eqGridPoints.clear();
1803 double increment = std::abs((maxRA - minRA) /
1805 double target = targetDec * decConvert;
1807 for (
double targetRA = minRA; targetRA <= maxRA; targetRA += increment)
1809 SkyPoint pointToGet(targetRA / 15, targetDec * decConvert);
1810 bool inImage = m_ImageData->wcsToPixel(pointToGet, pixelPoint, imagePoint);
1813 QPointF pt(pixelPoint.
x() * scale, pixelPoint.
y() * scale);
1814 eqGridPoints.append(pt);
1817 if (eqGridPoints.count() > 1)
1819 for (
int i = 1; i < eqGridPoints.count(); i++)
1820 painter->
drawLine(eqGridPoints.value(i - 1), eqGridPoints.value(i));
1822 QPointF pt = getPointForGridLabel(painter, str, scale);
1831 bool NCPtest = m_ImageData->wcsToPixel(NCP, pPoint, imagePoint);
1835 (pPoint.
x() > 0 && pPoint.
x() < image_width) && (pPoint.
y() > 0 && pPoint.
y() < image_height);
1838 painter->
fillRect(pPoint.
x() * scale - 2, pPoint.
y() * scale - 2, 4, 4,
1839 KStarsData::Instance()->colorScheme()->colorNamed(
"TargetColor"));
1840 painter->
drawText(pPoint.
x() * scale + 15, pPoint.
y() * scale + 15,
1841 i18nc(
"North Celestial Pole",
"NCP"));
1848 bool SCPtest = m_ImageData->wcsToPixel(SCP, pPoint, imagePoint);
1852 (pPoint.
x() > 0 && pPoint.
x() < image_width) && (pPoint.
y() > 0 && pPoint.
y() < image_height);
1855 painter->
fillRect(pPoint.
x() * scale - 2, pPoint.
y() * scale - 2, 4, 4,
1856 KStarsData::Instance()->colorScheme()->colorNamed(
"TargetColor"));
1857 painter->
drawText(pPoint.
x() * scale + 15, pPoint.
y() * scale + 15,
1858 i18nc(
"South Celestial Pole",
"SCP"));
1865bool FITSView::pointIsInImage(
QPointF pt,
double scale)
1867 int image_width = m_ImageData->width();
1868 int image_height = m_ImageData->height();
1869 return pt.
x() < image_width * scale && pt.
y() < image_height * scale && pt.
x() > 0 && pt.
y() > 0;
1875#if QT_VERSION < QT_VERSION_CHECK(5,11,0)
1876 int strWidth = fm.width(str);
1878 int strWidth = fm.horizontalAdvance(str);
1880 int strHeight = fm.height();
1881 int image_width = m_ImageData->width();
1882 int image_height = m_ImageData->height();
1885 QPointF maxXPt(image_width * scale / 2, image_height * scale / 2);
1886 for (
auto &p : eqGridPoints)
1888 if (p.
x() > maxXPt.x() && pointIsInImage(p, scale))
1891 QPointF maxYPt(image_width * scale / 2, image_height * scale / 2);
1893 for (
auto &p : eqGridPoints)
1895 if (p.
y() > maxYPt.y() && pointIsInImage(p, scale))
1898 QPointF minXPt(image_width * scale / 2, image_height * scale / 2);
1900 for (
auto &p : eqGridPoints)
1902 if (p.
x() < minXPt.x() && pointIsInImage(p, scale))
1905 QPointF minYPt(image_width * scale / 2, image_height * scale / 2);
1907 for (
auto &p : eqGridPoints)
1909 if (p.
y() < minYPt.y() && pointIsInImage(p, scale))
1918 if (image_width * scale - maxXPt.x() < strWidth)
1921 image_width * scale - (strWidth + 10),
1925 if (image_height * scale - maxYPt.y() < strHeight)
1927 maxYPt.x() - (strWidth + 10),
1928 image_height * scale -
1930 if (minYPt.y() < strHeight)
1932 minYPt.x() * scale + 10,
1934 if (minXPt.x() < strWidth)
1937 minXPt.y() * scale +
1940 if (maxXPt.x() == image_width * scale / 2 && maxXPt.y() == image_height * scale / 2)
1943 return QPoint(maxXPt.x() - (strWidth + 10), maxXPt.y() - (strHeight + 10));
1946void FITSView::setFirstLoad(
bool value)
1951QPixmap &FITSView::getTrackingBoxPixmap(uint8_t margin)
1953 if (trackingBox.
isNull())
1954 return trackingBoxPixmap;
1957 const float scale = getScale();
1959 int x1 = (trackingBox.
x() - margin) * scale;
1960 int y1 = (trackingBox.
y() - margin) * scale;
1961 int w = (trackingBox.
width() + margin * 2) * scale;
1962 int h = (trackingBox.
height() + margin * 2) * scale;
1964 trackingBoxPixmap = m_ImageFrame->grab(
QRect(x1, y1, w, h));
1965 return trackingBoxPixmap;
1968void FITSView::setTrackingBox(
const QRect &rect)
1970 if (
rect != trackingBox)
1979void FITSView::resizeTrackingBox(
int newSize)
1981 int x = trackingBox.
x() + trackingBox.
width() / 2;
1982 int y = trackingBox.
y() + trackingBox.
height() / 2;
1983 int delta = newSize / 2;
1984 setTrackingBox(
QRect(
x - delta,
y - delta, newSize, newSize));
1987void FITSView::processRectangleFixed(
int s)
1989 int w = m_ImageData->width();
1990 int h = m_ImageData->height();
1993 c.
setX(qMax((
int)round(s / 2.0), c.
x()));
1994 c.
setX(qMin(w - (
int)round(s / 2.0), c.
x()));
1995 c.
setY(qMax((
int)round(s / 2.0), c.
y()));
1996 c.
setY(qMin(h - (
int)round(s / 2.0), c.
y()));
1998 QPoint topLeft, botRight;
1999 topLeft =
QPoint(c.
x() - round(s / 2.0), c.
y() - round(s / 2.0));
2000 botRight =
QPoint(c.
x() + round(s / 2.0), c.
y() + round(s / 2.0));
2002 emit setRubberBand(
QRect(topLeft, botRight));
2003 processRectangle(topLeft, botRight,
true);
2006void FITSView::processRectangle(
QPoint p1,
QPoint p2,
bool calculate)
2008 if(!isSelectionRectShown())
2022 topLeft.
setX(qMax(1, topLeft.
x()));
2023 topLeft.
setY(qMax(1, topLeft.
y()));
2024 botRight.
setX(qMin((
int)m_ImageData->width(), botRight.
x()));
2025 botRight.
setY(qMin((
int)m_ImageData->height(), botRight.
y()));
2034 m_ImageData->makeRoiBuffer(selectionRectangleRaw);
2035 emit rectangleUpdated(selectionRectangleRaw);
2044bool FITSView::isImageStretched()
2046 return stretchImage;
2049bool FITSView::isClippingShown()
2051 return showClipping;
2054bool FITSView::isCrosshairShown()
2056 return showCrosshair;
2059bool FITSView::isEQGridShown()
2064bool FITSView::isSelectionRectShown()
2066 return showSelectionRect;
2068bool FITSView::areObjectsShown()
2073bool FITSView::isPixelGridShown()
2075 return showPixelGrid;
2078bool FITSView::isHiPSOverlayShown()
2080 return showHiPSOverlay;
2083void FITSView::toggleCrosshair()
2085 showCrosshair = !showCrosshair;
2089void FITSView::toggleClipping()
2091 showClipping = !showClipping;
2095void FITSView::toggleEQGrid()
2097 showEQGrid = !showEQGrid;
2099 if (m_ImageData->getWCSState() == FITSData::Idle && !wcsWatcher.
isRunning())
2101#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
2114void FITSView::toggleHiPSOverlay()
2116 showHiPSOverlay = !showHiPSOverlay;
2118 if (m_ImageData->getWCSState() == FITSData::Idle && !wcsWatcher.
isRunning())
2120#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
2131 m_QueueUpdate =
true;
2136void FITSView::toggleSelectionMode()
2138 showSelectionRect = !showSelectionRect;
2139 if (!showSelectionRect)
2140 emit rectangleUpdated(
QRect());
2141 else if (m_ImageData)
2143 m_ImageData->makeRoiBuffer(selectionRectangleRaw);
2144 emit rectangleUpdated(selectionRectangleRaw);
2147 emit showRubberBand(showSelectionRect);
2152void FITSView::toggleObjects()
2154 showObjects = !showObjects;
2156 if (m_ImageData->getWCSState() == FITSData::Idle && !wcsWatcher.
isRunning())
2158#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
2169#if !defined(KSTARS_LITE) && defined(HAVE_WCSLIB)
2171 m_ImageData->searchObjects();
2179void FITSView::toggleStars()
2181 toggleStars(!markStars);
2186void FITSView::toggleStretch()
2188 stretchImage = !stretchImage;
2189 if (m_ImageFrame && rescale(ZOOM_KEEP_LEVEL))
2193void FITSView::toggleStarProfile()
2195#ifdef HAVE_DATAVISUALIZATION
2196 showStarProfile = !showStarProfile;
2197 if(showStarProfile && trackingBoxEnabled)
2199 if(toggleProfileAction)
2200 toggleProfileAction->
setChecked(showStarProfile);
2206 if(mode == FITS_NORMAL || mode == FITS_ALIGN)
2208 setCursorMode(selectCursor);
2209 connect(
this, SIGNAL(trackingStarSelected(
int,
int)),
this, SLOT(move3DTrackingBox(
int,
int)));
2210 trackingBox =
QRect(0, 0, 128, 128);
2211 setTrackingBoxEnabled(
true);
2212 if(starProfileWidget)
2213 connect(starProfileWidget, SIGNAL(sampleSizeUpdated(
int)),
this, SLOT(resizeTrackingBox(
int)));
2215 if(starProfileWidget)
2216 connect(starProfileWidget, SIGNAL(rejected()),
this, SLOT(toggleStarProfile()));
2222 if(mode == FITS_NORMAL || mode == FITS_ALIGN)
2224 if(getCursorMode() == selectCursor)
2225 setCursorMode(dragCursor);
2226 disconnect(
this, SIGNAL(trackingStarSelected(
int,
int)),
this, SLOT(move3DTrackingBox(
int,
int)));
2227 setTrackingBoxEnabled(
false);
2228 if(starProfileWidget)
2229 disconnect(starProfileWidget, SIGNAL(sampleSizeUpdated(
int)),
this, SLOT(resizeTrackingBox(
int)));
2231 if(starProfileWidget)
2233 disconnect(starProfileWidget, SIGNAL(rejected()),
this, SLOT(toggleStarProfile()));
2234 starProfileWidget->close();
2235 starProfileWidget =
nullptr;
2237 emit starProfileWindowClosed();
2243void FITSView::move3DTrackingBox(
int x,
int y)
2245 int boxSize = trackingBox.
width();
2246 QRect starRect =
QRect(
x - boxSize / 2,
y - boxSize / 2, boxSize, boxSize);
2247 setTrackingBox(starRect);
2250void FITSView::viewStarProfile()
2252#ifdef HAVE_DATAVISUALIZATION
2253 if(!trackingBoxEnabled)
2255 setTrackingBoxEnabled(
true);
2256 setTrackingBox(
QRect(0, 0, 128, 128));
2258 if(!starProfileWidget)
2260 starProfileWidget =
new StarProfileViewer(
this);
2271 connect(starProfileWidget, SIGNAL(rejected()),
this, SLOT(toggleStarProfile()));
2272 if(mode == FITS_ALIGN || mode == FITS_NORMAL)
2274 starProfileWidget->enableTrackingBox(
true);
2275 m_ImageData->setStarAlgorithm(ALGORITHM_CENTROID);
2276 connect(starProfileWidget, SIGNAL(sampleSizeUpdated(
int)),
this, SLOT(resizeTrackingBox(
int)));
2279 QList<Edge *> starCenters = m_ImageData->getStarCentersInSubFrame(trackingBox);
2280 if(starCenters.
size() == 0)
2285 m_ImageData->findStars(ALGORITHM_CENTROID, trackingBox).waitForFinished();
2286 starCenters = m_ImageData->getStarCentersInSubFrame(trackingBox);
2289 starProfileWidget->loadData(m_ImageData, trackingBox, starCenters);
2290 starProfileWidget->show();
2291 starProfileWidget->raise();
2298void FITSView::togglePixelGrid()
2300 showPixelGrid = !showPixelGrid;
2306 if(trackingBoxEnabled)
2307 return m_ImageData->findStars(algorithm, trackingBox);
2309 return m_ImageData->findStars(algorithm, searchBox);
2312void FITSView::toggleStars(
bool enable)
2320void FITSView::searchStars()
2323 if (m_ImageData->areStarsSearched() || !m_ImageData || (m_ImageData->getRecordValue(
"FRAME", frameType)
2324 && frameType.
toString() !=
"Light"))
2328 emit newStatus(
i18n(
"Finding stars..."), FITS_MESSAGE);
2329 qApp->processEvents();
2331#ifdef HAVE_STELLARSOLVER
2332 QVariantMap extractionSettings;
2333 extractionSettings[
"optionsProfileIndex"] = Options::hFROptionsProfile();
2334 extractionSettings[
"optionsProfileGroup"] =
static_cast<int>(Ekos::HFRProfiles);
2335 imageData()->setSourceExtractorSettings(extractionSettings);
2342 emit newStatus(
"", FITS_MESSAGE);
2347void FITSView::processPointSelection(
int x,
int y)
2349 emit trackingStarSelected(
x,
y);
2352void FITSView::processMarkerSelection(
int x,
int y)
2354 markerCrosshair.
setX(
x);
2355 markerCrosshair.
setY(
y);
2360void FITSView::processHighlight(
int x,
int y)
2367 double candidateDist = -1.0;
2369 for (
int i = 0; i < objs.
size(); i++)
2375 const QRect rect =
QRect(objs[i].
x - (CAT_OBJ_BOX_SIZE / 2), objs[i].
y - (CAT_OBJ_BOX_SIZE / 2),
2376 CAT_OBJ_BOX_SIZE, CAT_OBJ_BOX_SIZE);
2377 if (
rect.contains(pt))
2385 const QRect bigRect =
QRect(objs[i].
x - 20, objs[i].
y - 20, 40, 40);
2388 double distance = std::hypot(
x - objs[i].
x,
y - objs[i].
y);
2389 if (candidate < 0 || distance < candidateDist)
2398 m_ImageData->highlightCatObject(candidate, -1);
2399 emit catHighlightChanged(candidate);
2406#if !defined(KSTARS_LITE) && defined(HAVE_WCSLIB)
2407 const double x = p1.
x() - p2.
x();
2408 const double y = p1.
y() - p2.
y();
2409 const int radius = std::hypot(
x,
y);
2410 m_ImageData->setCatSearchROI(p1, radius);
2411 m_ImageData->searchCatObjects();
2419void FITSView::setTrackingBoxEnabled(
bool enable)
2421 if (enable != trackingBoxEnabled)
2423 trackingBoxEnabled = enable;
2438#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
2441 QPoint mouseCenter = getImagePoint(
event->position().toPoint());
2443 if (
event->angleDelta().y() > 0)
2448 cleanUpZoom(mouseCenter);
2450 emit zoomRubberBand(getCurrentZoom() / ZOOM_DEFAULT);
2459void FITSView::cleanUpZoom(
QPoint viewCenter)
2463 double scale = (currentZoom / ZOOM_DEFAULT);
2464 if (!markerCrosshair.
isNull())
2466 x0 = markerCrosshair.
x() * scale;
2467 y0 = markerCrosshair.
y() * scale;
2469 else if (trackingBoxEnabled)
2471 x0 = trackingBox.
center().
x() * scale;
2472 y0 = trackingBox.
center().
y() * scale;
2474 else if (!viewCenter.
isNull())
2476 x0 = viewCenter.
x() * scale;
2477 y0 = viewCenter.
y() * scale;
2479 if ((x0 != 0) || (y0 != 0))
2481 updateMouseCursor();
2496 double scale = (currentZoom / ZOOM_DEFAULT);
2498 QPoint imagePoint =
QPoint(widgetPoint.
x() / scale, widgetPoint.
y() / scale);
2502void FITSView::initDisplayImage()
2506 int w = (m_ImageData->width() + m_PreviewSampling - 1) / m_PreviewSampling;
2507 int h = (m_ImageData->height() + m_PreviewSampling - 1) / m_PreviewSampling;
2509 if (m_ImageData->channels() == 1)
2514 for (
int i = 0; i < 256; i++)
2515 rawImage.
setColor(i, qRgb(i, i, i));
2530bool FITSView::event(
QEvent * event)
2561 if (zoomTime > 10000)
2563 if (zooming && (zoomTime % 10 == 0))
2570 cleanUpZoom(zoomLocation);
2581void FITSView::syncWCSState()
2583 bool hasWCS = m_ImageData->hasWCS();
2584 bool wcsLoaded = m_ImageData->getWCSState() == FITSData::Success;
2586#if !defined(KSTARS_LITE) && defined(HAVE_WCSLIB)
2588 m_ImageData->searchObjects();
2591 if (hasWCS && wcsLoaded)
2592 this->updateFrame();
2594 emit wcsToggled(hasWCS);
2596 if (toggleEQGridAction !=
nullptr)
2598 if (toggleObjectsAction !=
nullptr)
2600 if (centerTelescopeAction !=
nullptr)
2602 if (toggleHiPSOverlayAction !=
nullptr)
2606void FITSView::createFloatingToolBar()
2608 if (floatingToolBar !=
nullptr)
2611 floatingToolBar =
new QToolBar(
this);
2614 eff->setOpacity(0.2);
2617 "QToolBar{background: rgba(150, 150, 150, 210); border:none; color: yellow}"
2618 "QToolButton{background: transparent; border:none; color: yellow}"
2619 "QToolButton:hover{background: rgba(200, 200, 200, 255);border:solid; color: yellow}"
2620 "QToolButton:checked{background: rgba(110, 110, 110, 255);border:solid; color: yellow}");
2628 i18n(
"Zoom In"),
this, SLOT(ZoomIn()));
2631 i18n(
"Zoom Out"),
this, SLOT(ZoomOut()));
2634 i18n(
"Default Zoom"),
this, SLOT(ZoomDefault()));
2637 i18n(
"Zoom to Fit"),
this, SLOT(ZoomToFit()));
2640 i18n(
"Toggle Stretch"),
2641 this, SLOT(toggleStretch()));
2648 i18n(
"Show Cross Hairs"),
this, SLOT(toggleCrosshair()));
2652 i18n(
"Show Pixel Gridlines"),
this, SLOT(togglePixelGrid()));
2657 i18n(
"Detect Stars in Image"),
this, SLOT(toggleStars()));
2660#ifdef HAVE_DATAVISUALIZATION
2661 toggleProfileAction =
2663 i18n(
"View Star Profile..."),
this, SLOT(toggleStarProfile()));
2667 if (mode == FITS_NORMAL || mode == FITS_ALIGN)
2671 toggleEQGridAction =
2673 i18n(
"Show Equatorial Gridlines"),
this, &FITSView::toggleEQGrid);
2677 toggleObjectsAction =
2679 i18n(
"Show Objects in Image"),
this, &FITSView::toggleObjects);
2683 centerTelescopeAction =
2685 i18n(
"Center Telescope"),
this, &FITSView::centerTelescope);
2689 toggleHiPSOverlayAction =
2691 i18n(
"Show HiPS Overlay"),
this, &FITSView::toggleHiPSOverlay);
2702void FITSView::centerTelescope()
2706 if (getCursorMode() == FITSView::scopeCursor)
2708 setCursorMode(lastMouseMode);
2712 lastMouseMode = getCursorMode();
2713 setCursorMode(FITSView::scopeCursor);
2717 updateScopeButton();
2720void FITSView::updateScopeButton()
2722 if (centerTelescopeAction !=
nullptr)
2724 if (getCursorMode() == FITSView::scopeCursor)
2739bool FITSView::isTelescopeActive()
2742 if (INDIListener::Instance()->
size() == 0)
2747 for (
auto &oneDevice : INDIListener::devices())
2749 if (!(oneDevice->getDriverInterface() & INDI::BaseDevice::TELESCOPE_INTERFACE))
2751 return oneDevice->isConnected();
2759void FITSView::setStarsEnabled(
bool enable)
2762 if (floatingToolBar !=
nullptr)
2766 if (action->
text() ==
i18n(
"Detect Stars in Image"))
2775void FITSView::setStarsHFREnabled(
bool enable)
2777 showStarsHFR = enable;
2780void FITSView::setStretchValues(
double shadows,
double midtones,
double highlights)
2782 StretchParams params = getStretchParams();
2783 params.grey_red.shadows = shadows;
2784 params.grey_red.midtones = midtones;
2785 params.grey_red.highlights = highlights;
2787 setStretchParams(params);
2790void FITSView::setAutoStretch()
2792 if (!getAutoStretch())
2793 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.
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)
KOSM_EXPORT double distance(const std::vector< const OSM::Node * > &path, Coordinate coord)
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 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 contains(const QPoint &point, bool proper) 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