1 /*  StellarSolver, StellarSolver Intenal Library developed by Robert Lancaster, 2020
2 
3     This application is free software; you can redistribute it and/or
4     modify it under the terms of the GNU General Public
5     License as published by the Free Software Foundation; either
6     version 2 of the License, or (at your option) any later version.
7 */
8 #pragma once
9 
10 //Includes for this project
11 #include "structuredefinitions.h"
12 #include "sextractorsolver.h"
13 #include "parameters.h"
14 #include "version.h"
15 
16 //QT Includes
17 #include <QDir>
18 #include <QThread>
19 #include <QMap>
20 #include <QVariant>
21 #include <QVector>
22 #include <QRect>
23 #include <QPointer>
24 
25 using namespace SSolver;
26 
27 class StellarSolver : public QObject
28 {
29         Q_OBJECT
30         Q_PROPERTY(QString BasePath MEMBER m_BasePath)
31         Q_PROPERTY(QString FileToProcess MEMBER m_FileToProcess)
32         Q_PROPERTY(QString ASTAPBinaryPath MEMBER m_ASTAPBinaryPath)
33         Q_PROPERTY(QString SextractorBinaryPath MEMBER m_SextractorBinaryPath)
34         Q_PROPERTY(QString ConfPath MEMBER m_ConfPath)
35         Q_PROPERTY(QString SolverPath MEMBER m_SolverPath)
36         Q_PROPERTY(QString WCSPath MEMBER m_WCSPath)
37         Q_PROPERTY(QString AstrometryAPIKey MEMBER m_AstrometryAPIKey)
38         Q_PROPERTY(QString AstrometryAPIURL MEMBER m_AstrometryAPIURL)
39         Q_PROPERTY(QString LogFileName MEMBER m_LogFileName)
40         Q_PROPERTY(bool UsePosition MEMBER m_UsePosition)
41         Q_PROPERTY(bool UseScale MEMBER m_UseScale)
42         Q_PROPERTY(bool AutoGenerateAstroConfig MEMBER m_AutoGenerateAstroConfig)
43         Q_PROPERTY(bool CleanupTemporaryFiles MEMBER m_CleanupTemporaryFiles)
44         Q_PROPERTY(bool OnlySendFITSFiles MEMBER m_OnlySendFITSFiles)
45         Q_PROPERTY(bool LogToFile MEMBER m_LogToFile)
46         Q_PROPERTY(SolverType SolverType MEMBER m_SolverType)
47         Q_PROPERTY(ProcessType ProcessType MEMBER m_ProcessType)
48         Q_PROPERTY(ExtractorType ExtractorType MEMBER m_SextractorType)
49 
50     public:
51         //The constructor and destructor foe the StellarSolver Object
52         explicit StellarSolver(ProcessType type, const FITSImage::Statistic &imagestats, uint8_t const *imageBuffer,
53                                QObject *parent = nullptr);
54         explicit StellarSolver(const FITSImage::Statistic &imagestats,  uint8_t const *imageBuffer, QObject *parent = nullptr);
55         ~StellarSolver();
56 
57         //Methods to get default file paths
58         static ExternalProgramPaths getLinuxDefaultPaths();
59         static ExternalProgramPaths getLinuxInternalPaths();
60         static ExternalProgramPaths getMacHomebrewPaths();
61         static ExternalProgramPaths getMacInternalPaths();
62         static ExternalProgramPaths getWinANSVRPaths();
63         static ExternalProgramPaths getWinCygwinPaths();
64 
65         //This gets the processType as a string explaining the command StellarSolver is Running
getCommandString()66         QString getCommandString()
67         {
68             return SSolver::getCommandString(m_ProcessType, m_SextractorType, m_SolverType);
69         }
70 
71         //This gets the scale unit string for astrometry.net input
72         //This should NOT be translated
getScaleUnitString()73         QString getScaleUnitString()
74         {
75             return SSolver::getScaleUnitString(m_ScaleUnit);
76         }
77 
78         //This gets a string for the Sextractor setting for calculating Flux using ellipses or circles
getShapeString()79         QString getShapeString()
80         {
81             return SSolver::getShapeString(params.apertureShape);
82         }
83 
84         //This gets a string for which Parallel Solving Algorithm we are using
getMultiAlgoString()85         QString getMultiAlgoString()
86         {
87             return SSolver::getMultiAlgoString(params.multiAlgorithm);
88         }
89 
getLogLevelString()90         QString getLogLevelString()
91         {
92             return SSolver::getLogLevelString(m_AstrometryLogLevel);
93         }
94 
getVersion()95         static QString getVersion()
96         {
97             return QString("StellarSolver Library Version: %1, build: %2").arg(StellarSolver_VERSION).arg(StellarSolver_BUILD_TS);
98         }
99 
getVersionNumber()100         static QString getVersionNumber()
101         {
102             return StellarSolver_VERSION;
103         }
104 
105         //Logging Settings for Astrometry
106         bool m_LogToFile {false};             //This determines whether or not to save the output from Astrometry.net to a file
107         QString m_LogFileName;                //This is the path to the log file that it will save.
108         logging_level m_AstrometryLogLevel {LOG_NONE};   //This is the level of astrometry logging.  Beware, setting this too high can severely affect performance
109         SSolverLogLevel m_SSLogLevel {LOG_NORMAL};   //This is the level for the StellarSolver Logging
110 
111         //These are for creating temporary files
112         //This is the base name used for all temporary files.  It uses a random name based on the type of solver/sextractor.
113         QString m_BaseName;
114         //This is the path used for saving any temporary files.  They are by default saved to the default temp directory, you can change it if you want to.
115         QString m_BasePath {QDir::tempPath()};
116 
117         //STELLARSOLVER METHODS
118         //The public methods here are for you to start, stop, setup, and get results from the StellarSolver
119 
120         //These are the most important methods that you can use for the StellarSolver
121 
122         /**
123          * @brief sextract Extracts stars from the image.
124          * @param calculateHFR If true, it will also calculated Half-Flux Radius for each detected star. HFR calculations can be very CPU-intensive.
125          * @param frame If set, it will only extract stars within this rectangular region of the image.
126          */
127         void extract(bool calculateHFR = false, QRect frame = QRect());
128 
129         void solve();
130         void start();
131         void releaseSextractorSolver(SextractorSolver *solver);
132         void abort();
133 
134         //These set the settings for the StellarSolver
setParameters(Parameters parameters)135         void setParameters(Parameters parameters)
136         {
137             params = parameters;
138         };
139         void setParameterProfile(SSolver::Parameters::ParametersProfile profile);
setIndexFolderPaths(QStringList indexPaths)140         void setIndexFolderPaths(QStringList indexPaths)
141         {
142             indexFolderPaths = indexPaths;
143         };
144         void setSearchScale(double fov_low, double fov_high, const QString &scaleUnits);
145         //This sets the scale range for the image to speed up the solver
146         void setSearchScale(double fov_low, double fov_high, ScaleUnits units);
147         void setSearchPositionRaDec(double ra,
148                                     double dec);                                                    //This sets the search RA/DEC/Radius to speed up the solver
149         void setSearchPositionInDegrees(double ra, double dec);
setLogLevel(logging_level level)150         void setLogLevel(logging_level level)
151         {
152             m_AstrometryLogLevel = level;
153         };
setSSLogLevel(SSolverLogLevel level)154         void setSSLogLevel(SSolverLogLevel level)
155         {
156             m_SSLogLevel = level;
157         };
158 
159         //These static methods can be used by classes to configure parameters or paths
160         //This creates the conv filter from a fwhm
161         static void createConvFilterFromFWHM(Parameters *params, double fwhm);
162         static QList<Parameters> getBuiltInProfiles();
163         static QList<SSolver::Parameters> loadSavedOptionsProfiles(QString savedOptionsProfiles);
164         static QStringList getDefaultIndexFolderPaths();
165 
166 
167         //Accessor Method for external classes
getNumStarsFound()168         int getNumStarsFound() const
169         {
170             return numStars;
171         }
getStarList()172         const QList<FITSImage::Star> &getStarList() const
173         {
174             return m_ExtractorStars;
175         }
getBackground()176         const FITSImage::Background &getBackground() const
177         {
178             return background;
179         }
getStarListFromSolve()180         const QList<FITSImage::Star> &getStarListFromSolve() const
181         {
182             return m_SolverStars;
183         }
getSolution()184         const FITSImage::Solution &getSolution() const
185         {
186             return solution;
187         }
188 
sextractionDone()189         bool sextractionDone() const
190         {
191             return m_HasExtracted;
192         }
solvingDone()193         bool solvingDone() const
194         {
195             return m_HasSolved;
196         }
197 
failed()198         bool failed() const
199         {
200             return m_HasFailed;
201         }
setLoadWCS(bool set)202         void setLoadWCS(bool set)
203         {
204             loadWCS = set;
205         }
hasWCSData()206         bool hasWCSData() const
207         {
208             return hasWCS;
209         };
getNumThreads()210         int getNumThreads() const
211         {
212             if(parallelSolvers.size() == 0) return 1;
213             else return parallelSolvers.size();
214         }
215 
getCurrentParameters()216         const Parameters &getCurrentParameters()
217         {
218             return params;
219         }
isCalculatingHFR()220         bool isCalculatingHFR()
221         {
222             return m_CalculateHFR;
223         }
224 
225         void setUseSubframe(QRect frame);
clearSubFrame()226         void clearSubFrame()
227         {
228             useSubframe = false;
229             m_Subframe = QRect(0, 0, m_Statistics.width, m_Statistics.height);
230         };
231 
232         bool isRunning() const;
233 
raString(double ra)234         inline static QString raString(double ra)
235         {
236             char rastr[32];
237             ra2hmsstring(ra, rastr);
238             return rastr;
239         }
240 
decString(double dec)241         inline static QString decString(double dec)
242         {
243             char decstr[32];
244             dec2dmsstring(dec, decstr);
245             return decstr;
246         }
247 
248         virtual FITSImage::wcs_point *getWCSCoord();
249 
250         bool pixelToWCS(const QPointF &pixelPoint, FITSImage::wcs_point &skyPoint);
251         bool wcsToPixel(const FITSImage::wcs_point &skyPoint, QPointF &pixelPoint);
252 
253 
254     public slots:
255         void processFinished(int code);
256         void parallelSolve();
257         void finishParallelSolve(int success);
258         void finishWCS();
259 
260     private:
261         int whichSolver(SextractorSolver *solver);
262         //Static Utility
263         static double snr(const FITSImage::Background &background,
264                           const FITSImage::Star &star, double gain = 0.5);
265 
266 
267         bool appendStarsRAandDEC(QList<FITSImage::Star> &stars);
268 
269         bool checkParameters();
270         SextractorSolver* createSextractorSolver();
271 
272         //This finds out the amount of available RAM on the system
273         bool getAvailableRAM(double &availableRAM, double &totalRAM);
274         //This determines if there is enough RAM for the selected index files so that we don't try to load indexes inParallel unless it can handle it.
275         bool enoughRAMisAvailableFor(QStringList indexFolders);
276 
277         //This defines the type of process to perform.
278         ProcessType m_ProcessType { EXTRACT };
279         ExtractorType m_SextractorType { EXTRACTOR_INTERNAL };
280         SolverType m_SolverType {SOLVER_STELLARSOLVER};
281 
282         //External Options
283         QString m_FileToProcess;
284         bool m_CleanupTemporaryFiles {true};
285         bool m_AutoGenerateAstroConfig {true};
286         bool m_OnlySendFITSFiles {true};
287 
288         //System File Paths
289         QStringList m_IndexFilePaths;
290         QString m_ASTAPBinaryPath;
291         QString m_SextractorBinaryPath;
292         QString m_ConfPath;
293         QString m_SolverPath;
294         QString m_WCSPath;
295 
296         //Online Options
297         QString m_AstrometryAPIKey;
298         QString m_AstrometryAPIURL;
299 
300         bool useSubframe {false};
301         QRect m_Subframe;
302         bool m_isRunning {false};
303         QList<SextractorSolver*> parallelSolvers;
304         QPointer<SextractorSolver> m_SextractorSolver;
305         QPointer<SextractorSolver> solverWithWCS;
306         int m_ParallelSolversFinishedCount {0};
307         bool parallelSolversAreRunning() const;
308 
309         //The currently set parameters for StellarSolver
310         Parameters params;
311         //This is the list of folder paths that the solver will use to search for index files
312         QStringList indexFolderPaths {getDefaultIndexFolderPaths()};
313 
314         //Astrometry Scale Parameters, These are not saved parameters and change for each image, use the methods to set them
315         bool m_UseScale {false};               //Whether or not to use the image scale parameters
316         double m_ScaleLow {0};                 //Lower bound of image scale estimate
317         double m_ScaleHigh {0};                //Upper bound of image scale estimate
318         ScaleUnits m_ScaleUnit {ARCMIN_WIDTH}; //In what units are the lower and upper bounds?
319 
320         //Astrometry Position Parameters, These are not saved parameters and change for each image, use the methods to set them
321         bool m_UsePosition = false;          //Whether or not to use initial information about the position
322         double m_SearchRA = HUGE_VAL;        //RA of field center for search, format: decimal degrees
323         double m_SearchDE = HUGE_VAL;       //DEC of field center for search, format: decimal degrees
324 
325         //StellarSolver Internal settings that are needed by ExternalSextractorSolver as well
326         bool m_CalculateHFR {false};          //Whether or not the HFR of the image should be calculated using sep_flux_radius.  Don't do it unless you need HFR
327         bool m_HasExtracted {false};         //This boolean is set when the sextraction is done
328         bool m_HasSolved {false};             //This boolean is set when the solving is done
329         bool m_HasFailed {false};
330         FITSImage::Statistic m_Statistics;                    //This is information about the image
331 
332         const uint8_t *m_ImageBuffer { nullptr }; //The generic data buffer containing the image data
333 
334         //The Results
335         FITSImage::Background background;      //This is a report on the background levels found during sextraction
336         //This is the list of stars that get extracted from the image, saved to the file, and then solved by astrometry.net
337         QList<FITSImage::Star> m_ExtractorStars;
338         //This is the list of stars that were extracted for the last successful solve
339         QList<FITSImage::Star> m_SolverStars;
340         //The number of stars found in the last operation
341         int numStars;
342         FITSImage::Solution solution;          //This is the solution that comes back from the Solver
343         bool loadWCS {true};
344         bool hasWCS {false};        //This boolean gets set if the StellarSolver has WCS data to retrieve
345         bool hasWCSCoord{false};    //This boolean gets set if the Stellrsolver has already computed WCS Coordinates
346         FITSImage::wcs_point * wcs_coord {nullptr};
347 
348         bool wasAborted {false};
349         // This is the cancel file path that astrometry.net monitors.  If it detects this file, it aborts the solve
350         QString cancelfn;           //Filename whose creation signals the process to stop
351         QString solvedfn;           //Filename whose creation tells astrometry.net it already solved the field.
352 
353         bool m_isBlocking = false;              //This boolean determines whether to run in a blocking way.
354 
355     signals:
356         //This signals that there is infomation that should be printed to a log file or log window
357         void logOutput(QString logText);
358 
359         // Extraction and/or solving complete.
360         // If can be completed successfully or in failure, but it's done.
361         void ready();
362 
363         void wcsReady();
364 
365         void finished();
366 
367 };
368 
369