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()
138 auto parameters = getSSolverParametersList(
static_cast<Ekos::ProfileGroup
>(Options::fitsSolverModule())).at(
139 kcfg_FitsSolverProfile->currentIndex());
140 parameters.search_radius = kcfg_FitsSolverRadius->value();
143 if (!kcfg_FitsSolverLinear->isChecked())
148 double offset = imageData->getAverageMedian();
150 offset = imageData->getAverageMean();
151 parameters.threshold_offset = offset;
154 m_Solver.reset(
new SolverUtils(parameters, parameters.solverTimeLimit, SSolver::EXTRACT), &
QObject::deleteLater);
161 if (m_Solver && !kcfg_FitsSolverLinear->isChecked())
162 parameters.threshold_offset = m_Solver->getBackground().global;
164 m_Solver.reset(
new SolverUtils(parameters, parameters.solverTimeLimit, SSolver::SOLVE), &
QObject::deleteLater);
168 const int imageWidth = imageData->width();
169 const int imageHeight = imageData->height();
170 if (kcfg_FitsSolverUseScale->isChecked() && imageWidth != 0 && imageHeight != 0)
172 const double scale = kcfg_FitsSolverScale->value();
173 double lowScale = scale * 0.8;
174 double highScale = scale * 1.2;
177 const int units = kcfg_FitsSolverImageScaleUnits->currentIndex();
178 if (units == SSolver::DEG_WIDTH)
180 lowScale = (lowScale * 3600) / std::max(imageWidth, imageHeight);
181 highScale = (highScale * 3600) / std::min(imageWidth, imageHeight);
183 else if (units == SSolver::ARCMIN_WIDTH)
185 lowScale = (lowScale * 60) / std::max(imageWidth, imageHeight);
186 highScale = (highScale * 60) / std::min(imageWidth, imageHeight);
189 m_Solver->useScale(kcfg_FitsSolverUseScale->isChecked(), lowScale, highScale);
191 else m_Solver->useScale(
false, 0, 0);
193 if (kcfg_FitsSolverUsePosition->isChecked())
196 const dms ra = FitsSolverEstRA->createDms(&ok);
198 const dms
dec = FitsSolverEstDec->createDms(&ok2);
200 m_Solver->usePosition(
true, ra.
Degrees(),
dec.Degrees());
202 m_Solver->usePosition(
false, 0, 0);
204 else m_Solver->usePosition(
false, 0, 0);
211 m_imageData = imageData;
212 if (m_Solver.get() && m_Solver->isRunning())
214 SolveButton->setText(
i18n(
"Aborting..."));
218 SolveButton->setText(
i18n(
"Cancel"));
220 setupSolver(imageData,
true);
222 FitsSolverAngle->setText(
"");
223 FitsSolverIndexfile->setText(
"");
224 Solution1->setText(
i18n(
"Extracting..."));
225 Solution2->setText(
"");
227 m_Solver->runSolver(imageData);
230void PlateSolve::solveImage(
const QString &filename)
235 QFuture<bool> response = m_imageData->loadFromFile(filename);
236 m_Watcher.setFuture(response);
239void PlateSolve::loadFileDone()
241 solveImage(m_imageData);
247 m_imageData = imageData;
248 if (m_Solver.get() && m_Solver->isRunning())
250 SolveButton->setText(
i18n(
"Aborting..."));
254 SolveButton->setText(
i18n(
"Cancel"));
256 setupSolver(imageData,
false);
258 Solution2->setText(
i18n(
"Solving..."));
260 m_Solver->runSolver(imageData);
263void PlateSolve::extractorDone(
bool timedOut,
bool success,
const FITSImage::Solution &solution,
double elapsedSeconds)
266 disconnect(m_Solver.get(), &SolverUtils::done,
this, &PlateSolve::extractorDone);
267 Solution2->setText(
"");
271 const QString
result =
i18n(
"Extractor timed out: %1s", QString(
"%L1").arg(elapsedSeconds, 0,
'f', 1));
272 Solution1->setText(
result);
275 SolveButton->setText(
"Solve");
276 emit extractorFailed();
281 const QString
result =
i18n(
"Extractor failed: %1s", QString(
"%L1").arg(elapsedSeconds, 0,
'f', 1));
282 Solution1->setText(
result);
285 SolveButton->setText(
i18n(
"Solve"));
286 emit extractorFailed();
291 const QString starStr =
i18n(
"Extracted %1 stars (%2 unfiltered) in %3s",
292 m_Solver->getNumStarsFound(),
293 m_Solver->getBackground().num_stars_detected,
294 QString(
"%1").arg(elapsedSeconds, 0,
'f', 1));
295 Solution1->setText(starStr);
298 const QList<FITSImage::Star> &starList = m_Solver->getStarList();
299 QList<Edge*> starCenters;
301 for (
int i = 0; i < starList.
size(); i++)
303 const auto &star = starList[i];
307 oneEdge->val = star.peak;
308 oneEdge->sum = star.flux;
309 oneEdge->HFR = star.HFR;
310 oneEdge->width = star.a;
311 oneEdge->numPixels = star.numPixels;
315 oneEdge->ellipticity = 1 - star.b / star.a;
317 oneEdge->ellipticity = 0;
319 starCenters.
append(oneEdge);
321 m_imageData->setStarCenters(starCenters);
322 emit extractorSuccess();
326void PlateSolve::solverDone(
bool timedOut,
bool success,
const FITSImage::Solution &solution,
double elapsedSeconds)
328 m_Solution = FITSImage::Solution();
329 disconnect(m_Solver.get(), &SolverUtils::done,
this, &PlateSolve::solverDone);
330 SolveButton->setText(
"Solve");
332 if (m_Solver->isRunning())
333 qCDebug(KSTARS_FITS) <<
"solverDone called, but it is still running.";
337 const QString
result =
i18n(
"Solver timed out: %1s", QString(
"%L1").arg(elapsedSeconds, 0,
'f', 1));
338 Solution2->setText(
result);
343 const QString
result =
i18n(
"Solver failed: %1s", QString(
"%L1").arg(elapsedSeconds, 0,
'f', 1));
344 Solution2->setText(
result);
349 m_Solution = solution;
350 const bool eastToTheRight = solution.parity == FITSImage::POSITIVE ? false :
true;
351 m_imageData->injectWCS(solution.orientation, solution.ra, solution.dec, solution.pixscale, eastToTheRight);
352 m_imageData->loadWCS();
354 const QString
result = QString(
"Solved in %1s").arg(elapsedSeconds, 0,
'f', 1);
355 const double solverPA = KSUtils::rotationToPositionAngle(solution.orientation);
356 FitsSolverAngle->setText(QString(
"%1ยบ").arg(solverPA, 0,
'f', 2));
358 int indexUsed = -1, healpixUsed = -1;
359 m_Solver->getSolutionHealpix(&indexUsed, &healpixUsed);
361 FitsSolverIndexfile->setText(
"");
363 FitsSolverIndexfile->setText(
366 .arg(healpixUsed >= 0 ? QString(
"-%1").arg(healpixUsed) : QString(
"")));;
369 const int imageWidth = m_imageData->width();
370 const int units = kcfg_FitsSolverImageScaleUnits->currentIndex();
371 if (units == SSolver::DEG_WIDTH)
372 kcfg_FitsSolverScale->setValue(solution.pixscale * imageWidth / 3600.0);
373 else if (units == SSolver::ARCMIN_WIDTH)
374 kcfg_FitsSolverScale->setValue(solution.pixscale * imageWidth / 60.0);
376 kcfg_FitsSolverScale->setValue(solution.pixscale);
379 FitsSolverEstRA->show(dms(solution.ra));
380 FitsSolverEstDec->show(dms(solution.dec));
382 Solution2->setText(
result);
383 emit solverSuccess();
389int PlateSolve::getProfileIndex(
int moduleIndex)
391 if (moduleIndex < 0 || moduleIndex >= Ekos::ProfileGroupNames.
size())
393 const QString moduleName = Ekos::ProfileGroupNames[moduleIndex].toString();
394 const QString str = Options::fitsSolverProfileIndeces();
398 const QJsonObject indeces = doc.
object();
399 return indeces[moduleName].toString().toInt();
402void PlateSolve::setProfileIndex(
int moduleIndex,
int profileIndex)
404 if (moduleIndex < 0 || moduleIndex >= Ekos::ProfileGroupNames.
size())
406 QString str = Options::fitsSolverProfileIndeces();
410 QJsonObject initialIndeces;
411 for (
int i = 0; i < Ekos::ProfileGroupNames.size(); i++)
413 QString
name = Ekos::ProfileGroupNames[i].toString();
416 else if (name ==
"Guide")
418 else if (name ==
"HFR")
421 initialIndeces[
name] =
"0";
423 doc = QJsonDocument(initialIndeces);
426 QJsonObject indeces = doc.
object();
427 indeces[Ekos::ProfileGroupNames[moduleIndex].toString()] =
QString::number(profileIndex);
428 doc = QJsonDocument(indeces);
429 Options::setFitsSolverProfileIndeces(QString(doc.
toJson()));
432void PlateSolve::setupProfiles(
int moduleIndex)
434 if (moduleIndex < 0 || moduleIndex >= Ekos::ProfileGroupNames.
size())
436 Ekos::ProfileGroup profileGroup =
static_cast<Ekos::ProfileGroup
>(moduleIndex);
437 Options::setFitsSolverModule(moduleIndex);
440 const QList<SSolver::Parameters> optionsList = getSSolverParametersList(profileGroup);
441 kcfg_FitsSolverProfile->clear();
442 for(
auto ¶m : optionsList)
443 kcfg_FitsSolverProfile->addItem(param.listName);
445 m_ProfileEditor->setProfileGroup(profileGroup,
false);
448 kcfg_FitsSolverProfile->setCurrentIndex(getProfileIndex(Options::fitsSolverModule()));
450 m_ProfileEditorPage->setHeader(QString(
"FITS Viewer Solver %1 Profiles Editor")
451 .arg(Ekos::ProfileGroupNames[moduleIndex].
toString()));
454void PlateSolve::setPosition(
const SkyPoint &p)
456 FitsSolverEstRA->show(p.
ra());
457 FitsSolverEstDec->show(p.
dec());
459void PlateSolve::setUsePosition(
bool yesNo)
461 kcfg_FitsSolverUsePosition->setChecked(yesNo);
463void PlateSolve::setScale(
double scale)
465 kcfg_FitsSolverScale->setValue(scale);
467void PlateSolve::setScaleUnits(
int units)
469 kcfg_FitsSolverImageScaleUnits->setCurrentIndex(units);
471void PlateSolve::setUseScale(
bool yesNo)
473 kcfg_FitsSolverUseScale->setChecked(yesNo);
475void PlateSolve::setLinear(
bool yesNo)
477 kcfg_FitsSolverLinear->setChecked(yesNo);
480void PlateSolve::initSolverUI()
483 kcfg_FitsSolverModule->clear();
484 for (
int i = 0; i < Ekos::ProfileGroupNames.size(); i++)
485 kcfg_FitsSolverModule->addItem(Ekos::ProfileGroupNames[i].toString());
486 kcfg_FitsSolverModule->setCurrentIndex(Options::fitsSolverModule());
488 setupProfiles(Options::fitsSolverModule());
494 kcfg_FitsSolverUseScale->setChecked(Options::fitsSolverUseScale());
495 kcfg_FitsSolverScale->setValue(Options::fitsSolverScale());
496 kcfg_FitsSolverImageScaleUnits->setCurrentIndex(Options::fitsSolverImageScaleUnits());
498 kcfg_FitsSolverUsePosition->setChecked(Options::fitsSolverUsePosition());
499 kcfg_FitsSolverRadius->setValue(Options::fitsSolverRadius());
501 FitsSolverEstRA->setUnits(dmsBox::HOURS);
502 FitsSolverEstDec->setUnits(dmsBox::DEGREES);
507 setProfileIndex(kcfg_FitsSolverModule->currentIndex(), index);
512 Options::setFitsSolverUseScale(state);
516 Options::setFitsSolverScale(value);
520 Options::setFitsSolverImageScaleUnits(index);
525 Options::setFitsSolverUsePosition(state);
530 Options::setFitsSolverRadius(value);
534 const auto center = SkyMap::Instance()->getCenterPoint();
535 FitsSolverEstRA->show(
center.ra());
536 FitsSolverEstDec->show(
center.dec());
540 const SSolver::SolverType
type =
static_cast<SSolver::SolverType
>(Options::solverType());
541 if(type != SSolver::SOLVER_STELLARSOLVER)
543 Solution2->setText(
i18n(
"Warning! This tool only supports the internal StellarSolver solver."));
544 Solution1->setText(
i18n(
"Change to that in the Ekos Align options menu."));
548void PlateSolve::setImageDisplay(
const QImage &image)
551 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)