Working solver

This commit is contained in:
2024-09-20 14:34:21 +02:00
parent c8898387fe
commit dccb2e88da
9 changed files with 506 additions and 50 deletions
+4 -1
View File
@@ -98,7 +98,10 @@ if(STELLARSOLVER_INCLUDE AND STELLARSOLVER_LIB)
target_include_directories(tenmon PRIVATE ${STELLARSOLVER_INCLUDE}) target_include_directories(tenmon PRIVATE ${STELLARSOLVER_INCLUDE})
target_link_libraries(tenmon PRIVATE ${STELLARSOLVER_LIB}) target_link_libraries(tenmon PRIVATE ${STELLARSOLVER_LIB})
target_compile_definitions(tenmon PRIVATE "PLATESOLVER") target_compile_definitions(tenmon PRIVATE "PLATESOLVER")
target_sources(tenmon PRIVATE solver.cpp solver.h) target_sources(tenmon PRIVATE
solver.cpp solver.h
platesolving.cpp platesolving.h platesolving.ui
)
endif(STELLARSOLVER_INCLUDE AND STELLARSOLVER_LIB) endif(STELLARSOLVER_INCLUDE AND STELLARSOLVER_LIB)
option(FLATPAK "Flatpak build" OFF) option(FLATPAK "Flatpak build" OFF)
+4 -7
View File
@@ -2,8 +2,7 @@
#include <QNetworkReply> #include <QNetworkReply>
#include <QDebug> #include <QDebug>
#include <QRegularExpression> #include <QRegularExpression>
#include <QStandardPaths> #include "solver.h"
#include <QDir>
// filename arcseconds range // filename arcseconds range
// index-4119.fits 14002000 // index-4119.fits 14002000
@@ -415,15 +414,13 @@ HttpDownloader::HttpDownloader(QObject *parent) : QObject(parent)
,_manager(new QNetworkAccessManager(this)) ,_manager(new QNetworkAccessManager(this))
{ {
connect(_manager, &QNetworkAccessManager::finished, this, &HttpDownloader::finished); connect(_manager, &QNetworkAccessManager::finished, this, &HttpDownloader::finished);
QDir dir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)); QDir dir(Solver::getTenmonIndexPath());
if(!dir.exists("astrometry")) if(!dir.exists())
{ {
if(dir.mkpath("astrometry")) if(dir.mkpath("."))
qDebug() << "Failed to create astrometry directory"; qDebug() << "Failed to create astrometry directory";
} }
dir.cd("astrometry");
_indexPath = dir.absolutePath(); _indexPath = dir.absolutePath();
} }
+6 -1
View File
@@ -108,6 +108,9 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
m_databaseView = new DataBaseView(m_database, this); m_databaseView = new DataBaseView(m_database, this);
connect(m_databaseView, SIGNAL(loadFile(QString)), this, SLOT(loadFile(QString))); connect(m_databaseView, SIGNAL(loadFile(QString)), this, SLOT(loadFile(QString)));
_plateSolving = new PlateSolving(this);
addDockWidget(Qt::RightDockWidgetArea, _plateSolving);
addToolBar(Qt::TopToolBarArea, m_stretchPanel); addToolBar(Qt::TopToolBarArea, m_stretchPanel);
QDockWidget *filesystemDock = new QDockWidget(tr("Filesystem"), this); QDockWidget *filesystemDock = new QDockWidget(tr("Filesystem"), this);
@@ -143,6 +146,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
connect(m_ringList, &ImageRingList::thumbnailLoaded, m_image, &ImageScrollArea::thumbnailLoaded); connect(m_ringList, &ImageRingList::thumbnailLoaded, m_image, &ImageScrollArea::thumbnailLoaded);
connect(m_ringList, &ImageRingList::pixmapLoaded, m_stretchPanel, &StretchToolbar::imageLoaded); connect(m_ringList, &ImageRingList::pixmapLoaded, m_stretchPanel, &StretchToolbar::imageLoaded);
connect(m_ringList, &ImageRingList::pixmapLoaded, histogram, &Histogram::imageLoaded); connect(m_ringList, &ImageRingList::pixmapLoaded, histogram, &Histogram::imageLoaded);
connect(m_ringList, &ImageRingList::pixmapLoaded, _plateSolving, &PlateSolving::imageLoaded);
connect(m_image, &ImageScrollArea::fileDropped, this, static_cast<void (MainWindow::*)(const QString &)>(&MainWindow::loadFile)); connect(m_image, &ImageScrollArea::fileDropped, this, static_cast<void (MainWindow::*)(const QString &)>(&MainWindow::loadFile));
QMenu *fileMenu = new QMenu(tr("File"), this); QMenu *fileMenu = new QMenu(tr("File"), this);
@@ -251,6 +255,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
dockMenu->addAction(databaseViewDock->toggleViewAction()); dockMenu->addAction(databaseViewDock->toggleViewAction());
dockMenu->addAction(filetreeDock->toggleViewAction()); dockMenu->addAction(filetreeDock->toggleViewAction());
dockMenu->addAction(histogramDock->toggleViewAction()); dockMenu->addAction(histogramDock->toggleViewAction());
dockMenu->addAction(_plateSolving->toggleViewAction());
menuBar()->addMenu(dockMenu); menuBar()->addMenu(dockMenu);
QMenu *helpMenu = menuBar()->addMenu(tr("Help")); QMenu *helpMenu = menuBar()->addMenu(tr("Help"));
@@ -709,7 +714,7 @@ void MainWindow::checkNewVersion()
{ {
QString tag = json.object().value("tag_name").toString(); QString tag = json.object().value("tag_name").toString();
QString version = getVersion(); QString version = getVersion();
if(version < tag) if(version >= tag)
QMessageBox::information(this, tr("Update check"), tr("You have newest version")); QMessageBox::information(this, tr("Update check"), tr("You have newest version"));
else else
{ {
+2
View File
@@ -10,6 +10,7 @@
#include "filesystemwidget.h" #include "filesystemwidget.h"
#include "stretchtoolbar.h" #include "stretchtoolbar.h"
#include "databaseview.h" #include "databaseview.h"
#include "platesolving.h"
class MainWindow : public QMainWindow class MainWindow : public QMainWindow
{ {
@@ -22,6 +23,7 @@ class MainWindow : public QMainWindow
FilesystemWidget *m_filesystem; FilesystemWidget *m_filesystem;
Filetree *m_filetree; Filetree *m_filetree;
DataBaseView *m_databaseView; DataBaseView *m_databaseView;
PlateSolving *_plateSolving;
static int socketPair[2]; static int socketPair[2];
QSocketNotifier *socketNotifier; QSocketNotifier *socketNotifier;
QString _lastDir; QString _lastDir;
+109
View File
@@ -0,0 +1,109 @@
#include "platesolving.h"
#include "ui_platesolving.h"
#include "solver.h"
#include "imageringlist.h"
PlateSolving::PlateSolving(QWidget *parent)
: QDockWidget(parent)
, ui(new Ui::PlateSolving)
{
ui->setupUi(this);
_solver = new Solver(this);
auto profiles = StellarSolver::getBuiltInProfiles();
for(auto &profile : profiles)
{
ui->profileComboBox->addItem(profile.listName);
}
connect(ui->profileComboBox, &QComboBox::currentIndexChanged, [this](int index){
auto profiles = StellarSolver::getBuiltInProfiles();
_solver->setParameters(profiles[index]);
});
connect(ui->extractButton, &QPushButton::clicked, this, &PlateSolving::extract);
connect(ui->solveButton, &QPushButton::clicked, this, &PlateSolving::solve);
connect(_solver, &Solver::solvingDone, this, &PlateSolving::solvingDone);
connect(_solver, &Solver::extractionDone, this, &PlateSolving::extractionDone);
}
PlateSolving::~PlateSolving()
{
delete ui;
}
void PlateSolving::extract()
{
ui->solveButton->setDisabled(true);
ui->extractButton->setDisabled(true);
_solver->loadImage(_rawImage, _path);
_solver->extractSources(ui->withHFR->isChecked());
}
void PlateSolving::extractionDone()
{
auto stars = _solver->getStars();
float a = 0;
float b = 0;
float hfr = 0;
for(auto &star : stars)
{
a += star.a;
b += star.b;
hfr += star.HFR;
}
if(size_t size = stars.size())
{
a /= size;
b /= size;
hfr /= size;
}
ui->stars->setText(QString::number(stars.size()));
ui->hfr->setText(QString("%1 %2x%3").arg(hfr).arg(a).arg(b));
ui->solveButton->setDisabled(false);
ui->extractButton->setDisabled(false);
}
void PlateSolving::solve()
{
ui->solveButton->setDisabled(true);
ui->extractButton->setDisabled(true);
_solver->loadImage(_rawImage, _path);
_solver->solveImage();
}
void PlateSolving::solvingDone()
{
ui->solveButton->setDisabled(false);
ui->extractButton->setDisabled(false);
auto solution = _solver->getSolution();
ui->ra->setText(QString::number(solution.ra));
ui->dec->setText(QString::number(solution.dec));
ui->orientation->setText(QString::number(solution.orientation));
ui->fieldWidth->setText(QString::number(solution.fieldWidth));
ui->fieldHeight->setText(QString::number(solution.fieldHeight));
ui->pixelScale->setText(QString::number(solution.pixscale));
}
void PlateSolving::imageLoaded(Image *image)
{
if(image)
{
_rawImage = image->rawImage();
_path = image->name();
ui->ra->clear();
ui->dec->clear();
ui->orientation->clear();
ui->fieldWidth->clear();
ui->fieldHeight->clear();
ui->pixelScale->clear();
ui->hfr->clear();
ui->stars->clear();
}
}
+34
View File
@@ -0,0 +1,34 @@
#ifndef PLATESOLVING_H
#define PLATESOLVING_H
#include <QDockWidget>
class Solver;
class RawImage;
class Image;
namespace Ui {
class PlateSolving;
}
class PlateSolving : public QDockWidget
{
Q_OBJECT
Solver *_solver;
std::shared_ptr<RawImage> _rawImage;
QString _path;
public:
explicit PlateSolving(QWidget *parent = nullptr);
~PlateSolving();
public slots:
void extract();
void extractionDone();
void solve();
void solvingDone();
void imageLoaded(Image *image);
private:
Ui::PlateSolving *ui;
};
#endif // PLATESOLVING_H
+185
View File
@@ -0,0 +1,185 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PlateSolving</class>
<widget class="QDockWidget" name="PlateSolving">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>571</width>
<height>472</height>
</rect>
</property>
<property name="windowTitle">
<string>Plate Solving</string>
</property>
<widget class="QWidget" name="dockWidgetContents">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Profile</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="profileComboBox"/>
</item>
</layout>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="2">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Field height</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Pixel scale</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>RA</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="orientation">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Orientation</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label_5">
<property name="text">
<string>DEC</string>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QLineEdit" name="pixelScale">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="ra">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Field width</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QLineEdit" name="dec">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="fieldWidth">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QLineEdit" name="fieldHeight">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Stars</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="stars">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QLabel" name="label_9">
<property name="text">
<string>HFR</string>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QLineEdit" name="hfr">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="0">
<widget class="QPushButton" name="extractButton">
<property name="text">
<string>Extract</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="solveButton">
<property name="text">
<string>Solve</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="withHFR">
<property name="text">
<string>Extract with HFR</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="settingsButton">
<property name="text">
<string>Settings</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>
+112 -14
View File
@@ -1,5 +1,8 @@
#include "solver.h" #include "solver.h"
#include <QJsonObject>
#include <QJsonDocument>
#include <fitsio.h> #include <fitsio.h>
#include <QStandardPaths>
#include <wcslib/wcshdr.h> #include <wcslib/wcshdr.h>
#include <wcslib/wcsutil.h> #include <wcslib/wcsutil.h>
#include "rawimage.h" #include "rawimage.h"
@@ -8,27 +11,42 @@
Solver::Solver(QObject *parent) : QObject(parent) Solver::Solver(QObject *parent) : QObject(parent)
{ {
_solver = std::make_unique<StellarSolver>(); _solver = new StellarSolver(this);
QStringList indexFolder = StellarSolver::getDefaultIndexFolderPaths(); QStringList indexFolder = getIndexPaths();
_solver->setProperty("ProcessType", SSolver::SOLVE); _solver->setProperty("ProcessType", SSolver::SOLVE);
_solver->setIndexFolderPaths(indexFolder); _solver->setIndexFolderPaths(indexFolder);
_solver->setParameterProfile(SSolver::Parameters::ALL_STARS); _solver->setParameterProfile(SSolver::Parameters::ALL_STARS);
connect(_solver, &StellarSolver::finished, this, &Solver::finished);
} }
Solver::~Solver() Solver::~Solver()
{ {
} }
bool Solver::solveImage(const QString &path) void Solver::setIndexFolders(const QStringList &indexPaths)
{ {
_solver->setIndexFolderPaths(indexPaths);
}
bool Solver::loadImage(const QString &path)
{
_loaded = false;
std::shared_ptr<RawImage> image;
ImageInfoData info; ImageInfoData info;
std::shared_ptr<RawImage> rawImage; if(::loadImage(path, info, image, true))
if(loadImage(path, info, rawImage, true))
{ {
_path = path; loadImage(image, path);
switch(rawImage->type()) }
return false;
}
bool Solver::loadImage(std::shared_ptr<RawImage> &image, const QString &path)
{
_rawImage = image;
switch(_rawImage->type())
{ {
case RawImage::UINT8: case RawImage::UINT8:
_stats.dataType = TBYTE; _stats.dataType = TBYTE;
@@ -50,23 +68,64 @@ bool Solver::solveImage(const QString &path)
return false; return false;
break; break;
} }
_stats.bytesPerPixel = rawImage->typeSize(rawImage->type()); _stats.bytesPerPixel = _rawImage->typeSize(_rawImage->type());
_stats.channels = rawImage->channels(); _stats.channels = _rawImage->channels();
_stats.width = rawImage->width(); _stats.width = _rawImage->width();
_stats.height = rawImage->height(); _stats.height = _rawImage->height();
_stats.samples_per_channel = _stats.width * _stats.height; _stats.samples_per_channel = _stats.width * _stats.height;
_solver->loadNewImageBuffer(_stats, (const uint8_t*)rawImage->data()); _loaded = _solver->loadNewImageBuffer(_stats, (const uint8_t*)_rawImage->data());
return _solver->solve(); _path = path;
return _loaded;
}
bool Solver::solveImage()
{
if(_loaded && !_solver->isRunning())
{
_process = SSolver::ProcessType::SOLVE;
_solver->setProperty("ProcessType", _process);
_solver->start();
return true;
} }
return false; return false;
} }
FITSImage::Solution Solver::getSolution() const bool Solver::extractSources(bool hfr)
{
if(_loaded && !_solver->isRunning())
{
_process = hfr ? SSolver::ProcessType::EXTRACT_WITH_HFR : SSolver::ProcessType::EXTRACT;
_solver->setProperty("ProcessType", _process);
_solver->start();
return true;
}
return false;
}
const FITSImage::Solution& Solver::getSolution() const
{ {
return _solver->getSolution(); return _solver->getSolution();
} }
const QList<FITSImage::Star>& Solver::getStars() const
{
return _solver->getStarList();
}
double Solver::getHFR() const
{
double hfr = 0.0;
auto stars = getStars();
if(stars.empty())return -1.0;
for(auto &star : stars)
{
hfr += star.HFR;
}
return hfr / stars.size();
}
QString Solver::errorMessage() const QString Solver::errorMessage() const
{ {
return _error; return _error;
@@ -74,6 +133,8 @@ QString Solver::errorMessage() const
void Solver::updateHeader() void Solver::updateHeader()
{ {
if(!_solver->solvingDone())return;
FITSImage::Solution solution = getSolution(); FITSImage::Solution solution = getSolution();
qDebug() << "RA" << solution.ra << "DEC" << solution.dec << "Orient" << solution.orientation << "field wxh" << solution.fieldWidth << solution.fieldHeight << solution.pixscale; qDebug() << "RA" << solution.ra << "DEC" << solution.dec << "Orient" << solution.orientation << "field wxh" << solution.fieldWidth << solution.fieldHeight << solution.pixscale;
qDebug() << "error" << solution.raError << solution.decError; qDebug() << "error" << solution.raError << solution.decError;
@@ -105,3 +166,40 @@ void Solver::updateHeader()
modify.updateKeyword("EQUINOX", 2000, QByteArray("Equinox of coordinates")); modify.updateKeyword("EQUINOX", 2000, QByteArray("Equinox of coordinates"));
file.modifyFITSRecords(&modify); file.modifyFITSRecords(&modify);
} }
void Solver::setParameters(Parameters::ParametersProfile profile)
{
_solver->setParameterProfile(profile);
}
void Solver::setParameters(const Parameters &parameters)
{
_solver->setParameters(parameters);
}
QStringList Solver::getIndexPaths()
{
QStringList paths;// = StellarSolver::getDefaultIndexFolderPaths();
paths.prepend(getTenmonIndexPath());
return paths;
}
QString Solver::getTenmonIndexPath()
{
return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/astrometry";
}
void Solver::finished()
{
switch(_process)
{
case SSolver::ProcessType::SOLVE:
emit solvingDone();
break;
case SSolver::ProcessType::EXTRACT_WITH_HFR:
case SSolver::ProcessType::EXTRACT:
emit extractionDone();
break;
}
}
+26 -3
View File
@@ -3,20 +3,43 @@
#include <stellarsolver.h> #include <stellarsolver.h>
class RawImage;
class Solver : public QObject class Solver : public QObject
{ {
Q_OBJECT Q_OBJECT
std::unique_ptr<StellarSolver> _solver; StellarSolver *_solver;
FITSImage::Statistic _stats; FITSImage::Statistic _stats;
SSolver::ProcessType _process = SSolver::SOLVE;
bool _loaded = false;
QString _path; QString _path;
QString _error; QString _error;
std::shared_ptr<RawImage> _rawImage;
public: public:
explicit Solver(QObject *parent = nullptr); explicit Solver(QObject *parent = nullptr);
~Solver(); ~Solver();
bool solveImage(const QString &path); void setIndexFolders(const QStringList &list);
FITSImage::Solution getSolution() const;
bool loadImage(const QString &path);
bool loadImage(std::shared_ptr<RawImage> &image, const QString &path);
bool solveImage();
bool extractSources(bool hfr);
const FITSImage::Solution& getSolution() const;
const QList<FITSImage::Star>& getStars() const;
double getHFR() const;
QString errorMessage() const; QString errorMessage() const;
void updateHeader(); void updateHeader();
void setParameters(SSolver::Parameters::ParametersProfile profile);
void setParameters(const SSolver::Parameters &parameters);
static QStringList getIndexPaths();
static QString getTenmonIndexPath();
public slots:
void finished();
signals:
void solvingDone();
void extractionDone();
}; };
#endif // SOLVER_H #endif // SOLVER_H