Kstars

solverutils.cpp
1/*
2 SPDX-FileCopyrightText: 2022 Hy Murveit <hy@murveit.com>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7#include "solverutils.h"
8
9#include "fitsviewer/fitsdata.h"
10#include "Options.h"
11#include <QRegularExpression>
12#include <QUuid>
13
14SolverUtils::SolverUtils(const SSolver::Parameters &parameters, double timeoutSeconds,
15 SSolver::ProcessType type) :
16 m_Parameters(parameters), m_TimeoutMilliseconds(timeoutSeconds * 1000.0), m_Type(type)
17{
18 connect(&m_Watcher, &QFutureWatcher<bool>::finished, this, &SolverUtils::executeSolver, Qt::UniqueConnection);
19 connect(&m_SolverTimer, &QTimer::timeout, this, &SolverUtils::solverTimeout, Qt::UniqueConnection);
20
21 m_StellarSolver.reset(new StellarSolver());
22 // connect(m_StellarSolver.get(), &StellarSolver::logOutput, this, &SolverUtils::newLog);
23}
24
25SolverUtils::~SolverUtils()
26{
27 disconnect(&m_Watcher, &QFutureWatcher<bool>::finished, this, &SolverUtils::executeSolver);
28 disconnect(&m_SolverTimer, &QTimer::timeout, this, &SolverUtils::solverTimeout);
29 if (m_StellarSolver.get())
30 {
31 // disconnect(m_StellarSolver.get(), &StellarSolver::logOutput, this, &SolverUtils::newLog);
32 disconnect(m_StellarSolver.get(), &StellarSolver::finished, this, &SolverUtils::solverDone);
33 }
34}
35
36void SolverUtils::executeSolver()
37{
38 runSolver(m_ImageData);
39}
40
41void SolverUtils::runSolver(const QString &filename)
42{
43 m_ImageData.reset(new FITSData(), &QObject::deleteLater);
44 QFuture<bool> response = m_ImageData->loadFromFile(filename);
45 m_Watcher.setFuture(response);
46}
47
48void SolverUtils::setHealpix(int indexToUse, int healpixToUse)
49{
50 m_IndexToUse = indexToUse;
51 m_HealpixToUse = healpixToUse;
52}
53
54void SolverUtils::abort()
55{
56 if (m_StellarSolver.get()) m_StellarSolver->abort();
57}
58
59bool SolverUtils::isRunning() const
60{
61 if (!m_StellarSolver.get()) return false;
62 return m_StellarSolver->isRunning();
63}
64
65void SolverUtils::getSolutionHealpix(int *indexUsed, int *healpixUsed) const
66{
67 *indexUsed = m_StellarSolver->getSolutionIndexNumber();
68 *healpixUsed = m_StellarSolver->getSolutionHealpix();
69}
70
71
72void SolverUtils::prepareSolver()
73{
74 if (m_StellarSolver->isRunning())
75 m_StellarSolver->abort();
76 m_StellarSolver->setProperty("ProcessType", m_Type);
77 m_StellarSolver->loadNewImageBuffer(m_ImageData->getStatistics(), m_ImageData->getImageBuffer());
78 m_StellarSolver->setProperty("ExtractorType", Options::solveSextractorType());
79 m_StellarSolver->setProperty("SolverType", Options::solverType());
80 connect(m_StellarSolver.get(), &StellarSolver::finished, this, &SolverUtils::solverDone, Qt::UniqueConnection);
81
82 if (m_IndexToUse >= 0)
83 {
84 // The would only have an effect if Options::solverType() == SOLVER_STELLARSOLVER
85 QStringList indexFiles = StellarSolver::getIndexFiles(
86 Options::astrometryIndexFolderList(), m_IndexToUse, m_HealpixToUse);
87 m_StellarSolver->setIndexFilePaths(indexFiles);
88 }
89 else
90 m_StellarSolver->setIndexFolderPaths(Options::astrometryIndexFolderList());
91
92 // External program paths
93 ExternalProgramPaths externalPaths;
94 externalPaths.sextractorBinaryPath = Options::sextractorBinary();
95 externalPaths.solverPath = Options::astrometrySolverBinary();
96 externalPaths.astapBinaryPath = Options::aSTAPExecutable();
97 externalPaths.watneyBinaryPath = Options::watneyBinary();
98 externalPaths.wcsPath = Options::astrometryWCSInfo();
99 m_StellarSolver->setExternalFilePaths(externalPaths);
100
101 //No need for a conf file this way.
102 m_StellarSolver->setProperty("AutoGenerateAstroConfig", true);
103
104 auto params = m_Parameters;
105 params.partition = Options::stellarSolverPartition();
106 m_StellarSolver->setParameters(params);
107
108 m_TemporaryFilename.clear();
109
110 const SSolver::SolverType type = static_cast<SSolver::SolverType>(m_StellarSolver->property("SolverType").toInt());
111 if(type == SSolver::SOLVER_LOCALASTROMETRY || type == SSolver::SOLVER_ASTAP || type == SSolver::SOLVER_WATNEYASTROMETRY)
112 {
113 m_TemporaryFilename = QDir::tempPath() + QString("/solver%1.fits").arg(QUuid::createUuid().toString().remove(
114 QRegularExpression("[-{}]")));
115 m_ImageData->saveImage(m_TemporaryFilename);
116 m_StellarSolver->setProperty("FileToProcess", m_TemporaryFilename);
117 }
118 else if (type == SSolver::SOLVER_ONLINEASTROMETRY )
119 {
120 m_TemporaryFilename = QDir::tempPath() + QString("/solver%1.fits").arg(QUuid::createUuid().toString().remove(
121 QRegularExpression("[-{}]")));
122 m_ImageData->saveImage(m_TemporaryFilename);
123 m_StellarSolver->setProperty("FileToProcess", m_TemporaryFilename);
124 m_StellarSolver->setProperty("AstrometryAPIKey", Options::astrometryAPIKey());
125 m_StellarSolver->setProperty("AstrometryAPIURL", Options::astrometryAPIURL());
126 }
127
128 if (m_UseScale)
129 {
130 // Extend search scale from 80% to 120%
131 m_StellarSolver->setSearchScale(m_ScaleLowArcsecPerPixel * 0.8,
132 m_ScaleHighArcsecPerPixel * 1.2,
133 ARCSEC_PER_PIX);
134 }
135 else
136 m_StellarSolver->setProperty("UseScale", false);
137
138 if (m_UsePosition)
139 m_StellarSolver->setSearchPositionInDegrees(m_raDegrees, m_decDegrees);
140 else
141 m_StellarSolver->setProperty("UsePosition", false);
142
143 // LOG_ALL is crashy now
144 m_StellarSolver->setLogLevel(SSolver::LOG_NONE);
145 m_StellarSolver->setSSLogLevel(SSolver::LOG_OFF);
146
147 patchMultiAlgorithm(m_StellarSolver.get());
148}
149
150void SolverUtils::runSolver(const QSharedPointer<FITSData> &data)
151{
152 // Limit the time the solver can run.
153 m_SolverTimer.setSingleShot(true);
154 m_SolverTimer.setInterval(m_TimeoutMilliseconds);
155 m_SolverTimer.start();
156 // Somehow m_SolverTimer's elapsed time can be greater than the interval,
157 // so using this to get more exact times.
158 m_StartTime = QDateTime::currentMSecsSinceEpoch();
159
160 m_ImageData = data;
161 prepareSolver();
162 m_StellarSolver->start();
163}
164
165SolverUtils &SolverUtils::useScale(bool useIt, double scaleLowArcsecPerPixel, double scaleHighArcsecPerPixel)
166{
167 m_UseScale = useIt;
168 m_ScaleLowArcsecPerPixel = scaleLowArcsecPerPixel;
169 m_ScaleHighArcsecPerPixel = scaleHighArcsecPerPixel;
170 return *this;
171}
172
173SolverUtils &SolverUtils::usePosition(bool useIt, double raDegrees, double decDegrees)
174{
175 m_UsePosition = useIt;
176 m_raDegrees = raDegrees;
177 m_decDegrees = decDegrees;
178 return *this;
179}
180
181void SolverUtils::solverDone()
182{
183 const double elapsed = (QDateTime::currentMSecsSinceEpoch() - m_StartTime) / 1000.0;
184 m_SolverTimer.stop();
185
186 if (m_Type == SSolver::SOLVE)
187 {
188 FITSImage::Solution solution;
189 const bool success = m_StellarSolver->solvingDone() && !m_StellarSolver->failed();
190 if (success)
191 solution = m_StellarSolver->getSolution();
192 emit done(false, success, solution, elapsed);
193 }
194 else
195 {
196 const bool success = m_StellarSolver->extractionDone() && !m_StellarSolver->failed();
197 emit done(false, success, FITSImage::Solution(), elapsed);
198 }
199 if (!m_TemporaryFilename.isEmpty())
200 QFile::remove(m_TemporaryFilename);
201 m_TemporaryFilename.clear();
202}
203
204void SolverUtils::solverTimeout()
205{
206 m_SolverTimer.stop();
207
208 disconnect(m_StellarSolver.get(), &StellarSolver::finished, this, &SolverUtils::solverDone);
209 abort();
210
211 FITSImage::Solution empty;
212 emit done(true, false, empty, m_TimeoutMilliseconds / 1000.0);
213 if (!m_TemporaryFilename.isEmpty())
214 QFile::remove(m_TemporaryFilename);
215 m_TemporaryFilename.clear();
216}
217
218// We don't trust StellarSolver's mutli-processing algorithm MULTI_DEPTHS which is used
219// with multiAlgorithm==MULTI_AUTO && use_scale && !use_position.
220void SolverUtils::patchMultiAlgorithm(StellarSolver *solver)
221{
222 if (solver && solver->property("UseScale").toBool() && !solver->property("UsePosition").toBool())
223 {
224 auto currentParameters = solver->getCurrentParameters();
225 currentParameters.multiAlgorithm = NOT_MULTI;
226 solver->setParameters(currentParameters);
227 }
228}
Type type(const QSqlDatabase &db)
char * toString(const EngineQuery &query)
KGuiItem remove()
qint64 currentMSecsSinceEpoch()
QString tempPath()
bool remove()
void setFuture(const QFuture< T > &future)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void deleteLater()
bool disconnect(const QMetaObject::Connection &connection)
QString arg(Args &&... args) const const
void clear()
bool isEmpty() const const
UniqueConnection
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
void setInterval(int msec)
void setSingleShot(bool singleShot)
void start()
void stop()
void timeout()
QUuid createUuid()
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Dec 6 2024 12:09:51 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.