8#include "ui_platesolve.h"
10#include "auxiliary/kspaths.h"
12#include <KConfigDialog>
15#include <fits_debug.h>
28 case Ekos::AlignProfiles:
30 savedProfiles =
QDir(KSPaths::writableLocation(
33 StellarSolver::loadSavedOptionsProfiles(savedProfiles) :
34 Ekos::getDefaultAlignOptionsProfiles();
36 case Ekos::FocusProfiles:
37 savedProfiles =
QDir(KSPaths::writableLocation(
40 StellarSolver::loadSavedOptionsProfiles(savedProfiles) :
41 Ekos::getDefaultFocusOptionsProfiles();
43 case Ekos::GuideProfiles:
44 savedProfiles =
QDir(KSPaths::writableLocation(
47 StellarSolver::loadSavedOptionsProfiles(savedProfiles) :
48 Ekos::getDefaultGuideOptionsProfiles();
50 case Ekos::HFRProfiles:
51 savedProfiles =
QDir(KSPaths::writableLocation(
54 StellarSolver::loadSavedOptionsProfiles(savedProfiles) :
55 Ekos::getDefaultHFROptionsProfiles();
67void PlateSolve::setup()
73 const QString EditorID =
"FITSSolverProfileEditor";
77 m_EditorDialog =
new KConfigDialog(
nullptr, EditorID, Options::self());
78 m_ProfileEditor =
new Ekos::StellarSolverProfileEditor(
nullptr, Ekos::AlignProfiles, m_EditorDialog.data());
79 m_ProfileEditorPage = m_EditorDialog->addPage(m_ProfileEditor.data(),
80 i18n(
"FITS Viewer Solver Profiles Editor"));
85 m_ProfileEditor->loadProfile(kcfg_FitsSolverProfile->currentText());
89 d->setCurrentPage(m_ProfileEditorPage);
95 if (m_Solver.get() && m_Solver->isRunning())
97 SolveButton->setText(
i18n(
"Aborting..."));
108void PlateSolve::enableAuxButton(
const QString &label,
const QString &toolTip)
110 auxButton->setText(label);
111 auxButton->setToolTip(
toolTip);
112 auxButton->setVisible(
true);
120void PlateSolve::disableAuxButton()
122 auxButton->setVisible(
false);
126void PlateSolve::abort()
135 auto parameters = getSSolverParametersList(
static_cast<Ekos::ProfileGroup
>(Options::fitsSolverModule())).at(
136 kcfg_FitsSolverProfile->currentIndex());
137 parameters.search_radius = kcfg_FitsSolverRadius->value();
140 if (!kcfg_FitsSolverLinear->isChecked())
145 double offset = imageData->getAverageMedian();
147 offset = imageData->getAverageMean();
148 parameters.threshold_offset = offset;
151 m_Solver.reset(
new SolverUtils(parameters, parameters.solverTimeLimit, SSolver::EXTRACT), &
QObject::deleteLater);
158 if (m_Solver && !kcfg_FitsSolverLinear->isChecked())
159 parameters.threshold_offset = m_Solver->getBackground().global;
161 m_Solver.reset(
new SolverUtils(parameters, parameters.solverTimeLimit, SSolver::SOLVE), &
QObject::deleteLater);
165 const int imageWidth = imageData->width();
166 const int imageHeight = imageData->height();
167 if (kcfg_FitsSolverUseScale->isChecked() && imageWidth != 0 && imageHeight != 0)
169 const double scale = kcfg_FitsSolverScale->value();
170 double lowScale = scale * 0.8;
171 double highScale = scale * 1.2;
174 const int units = kcfg_FitsSolverImageScaleUnits->currentIndex();
175 if (units == SSolver::DEG_WIDTH)
177 lowScale = (lowScale * 3600) / std::max(imageWidth, imageHeight);
178 highScale = (highScale * 3600) / std::min(imageWidth, imageHeight);
180 else if (units == SSolver::ARCMIN_WIDTH)
182 lowScale = (lowScale * 60) / std::max(imageWidth, imageHeight);
183 highScale = (highScale * 60) / std::min(imageWidth, imageHeight);
186 m_Solver->useScale(kcfg_FitsSolverUseScale->isChecked(), lowScale, highScale);
188 else m_Solver->useScale(
false, 0, 0);
190 if (kcfg_FitsSolverUsePosition->isChecked())
193 const dms ra = FitsSolverEstRA->createDms(&ok);
195 const dms
dec = FitsSolverEstDec->createDms(&ok2);
197 m_Solver->usePosition(
true, ra.
Degrees(),
dec.Degrees());
199 m_Solver->usePosition(
false, 0, 0);
201 else m_Solver->usePosition(
false, 0, 0);
208 m_imageData = imageData;
209 if (m_Solver.get() && m_Solver->isRunning())
211 SolveButton->setText(
i18n(
"Aborting..."));
215 SolveButton->setText(
i18n(
"Cancel"));
217 setupSolver(imageData,
true);
219 FitsSolverAngle->setText(
"");
220 FitsSolverIndexfile->setText(
"");
221 Solution1->setText(
i18n(
"Extracting..."));
222 Solution2->setText(
"");
224 m_Solver->runSolver(imageData);
227void PlateSolve::solveImage(
const QString &filename)
232 QFuture<bool> response = m_imageData->loadFromFile(filename);
233 m_Watcher.setFuture(response);
236void PlateSolve::loadFileDone()
238 solveImage(m_imageData);
244 m_imageData = imageData;
245 if (m_Solver.get() && m_Solver->isRunning())
247 SolveButton->setText(
i18n(
"Aborting..."));
251 SolveButton->setText(
i18n(
"Cancel"));
253 setupSolver(imageData,
false);
255 Solution2->setText(
i18n(
"Solving..."));
257 m_Solver->runSolver(imageData);
260void PlateSolve::extractorDone(
bool timedOut,
bool success,
const FITSImage::Solution &solution,
double elapsedSeconds)
263 disconnect(m_Solver.get(), &SolverUtils::done,
this, &PlateSolve::extractorDone);
264 Solution2->setText(
"");
268 const QString
result =
i18n(
"Extractor timed out: %1s", QString(
"%L1").arg(elapsedSeconds, 0,
'f', 1));
269 Solution1->setText(
result);
272 SolveButton->setText(
"Solve");
273 emit extractorFailed();
278 const QString
result =
i18n(
"Extractor failed: %1s", QString(
"%L1").arg(elapsedSeconds, 0,
'f', 1));
279 Solution1->setText(
result);
282 SolveButton->setText(
i18n(
"Solve"));
283 emit extractorFailed();
288 const QString starStr =
i18n(
"Extracted %1 stars (%2 unfiltered) in %3s",
289 m_Solver->getNumStarsFound(),
290 m_Solver->getBackground().num_stars_detected,
291 QString(
"%1").arg(elapsedSeconds, 0,
'f', 1));
292 Solution1->setText(starStr);
295 const QList<FITSImage::Star> &starList = m_Solver->getStarList();
296 QList<Edge*> starCenters;
298 for (
int i = 0; i < starList.
size(); i++)
300 const auto &star = starList[i];
304 oneEdge->val = star.peak;
305 oneEdge->sum = star.flux;
306 oneEdge->HFR = star.HFR;
307 oneEdge->width = star.a;
308 oneEdge->numPixels = star.numPixels;
312 oneEdge->ellipticity = 1 - star.b / star.a;
314 oneEdge->ellipticity = 0;
316 starCenters.
append(oneEdge);
318 m_imageData->setStarCenters(starCenters);
319 emit extractorSuccess();
323void PlateSolve::solverDone(
bool timedOut,
bool success,
const FITSImage::Solution &solution,
double elapsedSeconds)
325 m_Solution = FITSImage::Solution();
326 disconnect(m_Solver.get(), &SolverUtils::done,
this, &PlateSolve::solverDone);
327 SolveButton->setText(
"Solve");
329 if (m_Solver->isRunning())
330 qCDebug(KSTARS_FITS) <<
"solverDone called, but it is still running.";
334 const QString
result =
i18n(
"Solver timed out: %1s", QString(
"%L1").arg(elapsedSeconds, 0,
'f', 1));
335 Solution2->setText(
result);
340 const QString
result =
i18n(
"Solver failed: %1s", QString(
"%L1").arg(elapsedSeconds, 0,
'f', 1));
341 Solution2->setText(
result);
346 m_Solution = solution;
347 const bool eastToTheRight = solution.parity == FITSImage::POSITIVE ? false :
true;
348 m_imageData->injectWCS(solution.orientation, solution.ra, solution.dec, solution.pixscale, eastToTheRight);
349 m_imageData->loadWCS();
351 const QString
result = QString(
"Solved in %1s").arg(elapsedSeconds, 0,
'f', 1);
352 const double solverPA = KSUtils::rotationToPositionAngle(solution.orientation);
353 FitsSolverAngle->setText(QString(
"%1ยบ").arg(solverPA, 0,
'f', 2));
355 int indexUsed = -1, healpixUsed = -1;
356 m_Solver->getSolutionHealpix(&indexUsed, &healpixUsed);
358 FitsSolverIndexfile->setText(
"");
360 FitsSolverIndexfile->setText(
363 .arg(healpixUsed >= 0 ? QString(
"-%1").arg(healpixUsed) : QString(
"")));;
366 const int imageWidth = m_imageData->width();
367 const int units = kcfg_FitsSolverImageScaleUnits->currentIndex();
368 if (units == SSolver::DEG_WIDTH)
369 kcfg_FitsSolverScale->setValue(solution.pixscale * imageWidth / 3600.0);
370 else if (units == SSolver::ARCMIN_WIDTH)
371 kcfg_FitsSolverScale->setValue(solution.pixscale * imageWidth / 60.0);
373 kcfg_FitsSolverScale->setValue(solution.pixscale);
376 FitsSolverEstRA->show(dms(solution.ra));
377 FitsSolverEstDec->show(dms(solution.dec));
379 Solution2->setText(
result);
380 emit solverSuccess();
386int PlateSolve::getProfileIndex(
int moduleIndex)
388 if (moduleIndex < 0 || moduleIndex >= Ekos::ProfileGroupNames.
size())
390 const QString moduleName = Ekos::ProfileGroupNames[moduleIndex].toString();
391 const QString str = Options::fitsSolverProfileIndeces();
395 const QJsonObject indeces = doc.
object();
396 return indeces[moduleName].toString().toInt();
399void PlateSolve::setProfileIndex(
int moduleIndex,
int profileIndex)
401 if (moduleIndex < 0 || moduleIndex >= Ekos::ProfileGroupNames.
size())
403 QString str = Options::fitsSolverProfileIndeces();
407 QJsonObject initialIndeces;
408 for (
int i = 0; i < Ekos::ProfileGroupNames.size(); i++)
410 QString
name = Ekos::ProfileGroupNames[i].toString();
413 else if (name ==
"Guide")
415 else if (name ==
"HFR")
418 initialIndeces[
name] =
"0";
420 doc = QJsonDocument(initialIndeces);
423 QJsonObject indeces = doc.
object();
424 indeces[Ekos::ProfileGroupNames[moduleIndex].toString()] =
QString::number(profileIndex);
425 doc = QJsonDocument(indeces);
426 Options::setFitsSolverProfileIndeces(QString(doc.
toJson()));
429void PlateSolve::setupProfiles(
int moduleIndex)
431 if (moduleIndex < 0 || moduleIndex >= Ekos::ProfileGroupNames.
size())
433 Ekos::ProfileGroup profileGroup =
static_cast<Ekos::ProfileGroup
>(moduleIndex);
434 Options::setFitsSolverModule(moduleIndex);
437 const QList<SSolver::Parameters> optionsList = getSSolverParametersList(profileGroup);
438 kcfg_FitsSolverProfile->clear();
439 for(
auto ¶m : optionsList)
440 kcfg_FitsSolverProfile->addItem(param.listName);
442 m_ProfileEditor->setProfileGroup(profileGroup,
false);
445 kcfg_FitsSolverProfile->setCurrentIndex(getProfileIndex(Options::fitsSolverModule()));
447 m_ProfileEditorPage->setHeader(QString(
"FITS Viewer Solver %1 Profiles Editor")
448 .arg(Ekos::ProfileGroupNames[moduleIndex].
toString()));
451void PlateSolve::setPosition(
const SkyPoint &p)
453 FitsSolverEstRA->show(p.
ra());
454 FitsSolverEstDec->show(p.
dec());
456void PlateSolve::setUsePosition(
bool yesNo)
458 kcfg_FitsSolverUsePosition->setChecked(yesNo);
460void PlateSolve::setScale(
double scale)
462 kcfg_FitsSolverScale->setValue(scale);
464void PlateSolve::setScaleUnits(
int units)
466 kcfg_FitsSolverImageScaleUnits->setCurrentIndex(units);
468void PlateSolve::setUseScale(
bool yesNo)
470 kcfg_FitsSolverUseScale->setChecked(yesNo);
472void PlateSolve::setLinear(
bool yesNo)
474 kcfg_FitsSolverLinear->setChecked(yesNo);
477void PlateSolve::initSolverUI()
480 kcfg_FitsSolverModule->clear();
481 for (
int i = 0; i < Ekos::ProfileGroupNames.size(); i++)
482 kcfg_FitsSolverModule->addItem(Ekos::ProfileGroupNames[i].toString());
483 kcfg_FitsSolverModule->setCurrentIndex(Options::fitsSolverModule());
485 setupProfiles(Options::fitsSolverModule());
491 kcfg_FitsSolverUseScale->setChecked(Options::fitsSolverUseScale());
492 kcfg_FitsSolverScale->setValue(Options::fitsSolverScale());
493 kcfg_FitsSolverImageScaleUnits->setCurrentIndex(Options::fitsSolverImageScaleUnits());
495 kcfg_FitsSolverUsePosition->setChecked(Options::fitsSolverUsePosition());
496 kcfg_FitsSolverRadius->setValue(Options::fitsSolverRadius());
498 FitsSolverEstRA->setUnits(dmsBox::HOURS);
499 FitsSolverEstDec->setUnits(dmsBox::DEGREES);
504 setProfileIndex(kcfg_FitsSolverModule->currentIndex(), index);
509 Options::setFitsSolverUseScale(state);
513 Options::setFitsSolverScale(value);
517 Options::setFitsSolverImageScaleUnits(index);
522 Options::setFitsSolverUsePosition(state);
527 Options::setFitsSolverRadius(value);
531 const auto center = SkyMap::Instance()->getCenterPoint();
532 FitsSolverEstRA->show(
center.ra());
533 FitsSolverEstDec->show(
center.dec());
537 const SSolver::SolverType
type =
static_cast<SSolver::SolverType
>(Options::solverType());
538 if(type != SSolver::SOLVER_STELLARSOLVER)
540 Solution2->setText(
i18n(
"Warning! This tool only supports the internal StellarSolver solver."));
541 Solution1->setText(
i18n(
"Change to that in the Ekos Align options menu."));
545void PlateSolve::setImageDisplay(
const QImage &image)
548 plateSolveImage->setVisible(
true);
static KConfigDialog * exists(const QString &name)
The sky coordinates of a point in the sky.
const CachingDms & dec() const
const CachingDms & ra() const
const double & Degrees() const
QString i18n(const char *text, const TYPE &arg...)
Type type(const QSqlDatabase &db)
char * toString(const EngineQuery &query)
Ekos is an advanced Astrophotography tool for Linux.
QString name(StandardAction id)
void stateChanged(int state)
void activated(int index)
QString filePath(const QString &fileName) const const
void valueChanged(double d)
bool exists(const QString &fileName)
QIcon fromTheme(const QString &name)
QImage scaledToHeight(int height, Qt::TransformationMode mode) const const
QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error)
bool isNull() const const
bool isObject() const const
QJsonObject object() const const
QByteArray toJson(JsonFormat format) const const
void append(QList< T > &&value)
void reserve(qsizetype size)
qsizetype size() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool disconnect(const QMetaObject::Connection &connection)
QPixmap fromImage(QImage &&image, Qt::ImageConversionFlags flags)
QString number(double n, char format, int precision)
QByteArray toUtf8() const const
QTextStream & center(QTextStream &stream)
QTextStream & dec(QTextStream &stream)