Commit f19e281f authored by Jasem Mutlaq's avatar Jasem Mutlaq
Browse files

Moving all align module files to their own dedicated directly. GUI is simplified even more

parent 37fecee9
This diff is collapsed.
/* Astrometry.net Parser
Copyright (C) 2012 Jasem Mutlaq <mutlaqja@ikarustech.com>
This application is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
*/
#include "astrometryparser.h"
namespace Ekos
{
AstrometryParser::AstrometryParser()
{
}
AstrometryParser::~AstrometryParser()
{
}
}
/* Astrometry.net Parser
Copyright (C) 2012 Jasem Mutlaq <mutlaqja@ikarustech.com>
This application is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
*/
#ifndef ASTROMETRYPARSER_H
#define ASTROMETRYPARSER_H
#include <QObject>
namespace Ekos
{
class Align;
/**
* @class AstrometryParser
* AstrometryParser is an interface for online and offline astrometry parsers.
*
* @authro Jasem Mutlaq
*/
class AstrometryParser : public QObject
{
Q_OBJECT
public:
AstrometryParser();
virtual ~AstrometryParser();
virtual void setAlign(Align *align) = 0;
virtual bool init() = 0;
virtual void verifyIndexFiles(double fov_x, double fov_y) =0;
virtual bool startSovler(const QString &filename, const QStringList &args, bool generated=true) =0;
virtual bool stopSolver() = 0;
signals:
void solverFinished(double orientation, double ra, double dec, double pixscale);
void solverFailed();
};
}
#endif // ASTROMETRYPARSER_H
/* Astrometry.net Parser
Copyright (C) 2012 Jasem Mutlaq <mutlaqja@ikarustech.com>
This application is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
*/
#include <QDir>
#include <QFileInfo>
#include <KMessageBox>
#include <KLocalizedString>
#include "Options.h"
#include "offlineastrometryparser.h"
#include "align.h"
namespace Ekos
{
OfflineAstrometryParser::OfflineAstrometryParser() : AstrometryParser()
{
astrometryIndex[2.8] = "index-4200";
astrometryIndex[4.0] = "index-4201";
astrometryIndex[5.6] = "index-4202";
astrometryIndex[8] = "index-4203";
astrometryIndex[11] = "index-4204";
astrometryIndex[16] = "index-4205";
astrometryIndex[22] = "index-4206";
astrometryIndex[30] = "index-4207";
astrometryIndex[42] = "index-4208";
astrometryIndex[60] = "index-4209";
astrometryIndex[85] = "index-4210";
astrometryIndex[120] = "index-4211";
astrometryIndex[170] = "index-4212";
astrometryIndex[240] = "index-4213";
astrometryIndex[340] = "index-4214";
astrometryIndex[480] = "index-4215";
astrometryIndex[680] = "index-4216";
astrometryIndex[1000] = "index-4217";
astrometryIndex[1400] = "index-4218";
astrometryIndex[2000] = "index-4219";
astrometryFilesOK = false;
}
OfflineAstrometryParser::~OfflineAstrometryParser()
{
}
bool OfflineAstrometryParser::init()
{
if (astrometryFilesOK)
return true;
if (astrometryNetOK() == false)
{
if (align && align->isEnabled())
KMessageBox::information(NULL, i18n("Failed to find astrometry.net binaries. Please ensure astrometry.net is installed and try again."),
i18n("Missing astrometry files"), "missing_astrometry_binaries_warning");
return false;
}
astrometryFilesOK = true;
return true;
}
bool OfflineAstrometryParser::astrometryNetOK()
{
bool solverOK=false, wcsinfoOK=false;
QFileInfo solver(Options::astrometrySolver());
solverOK = solver.exists() && solver.isFile();
QFileInfo wcsinfo(Options::astrometryWCSInfo());
wcsinfoOK = wcsinfo.exists() && wcsinfo.isFile();
return (solverOK && wcsinfoOK);
}
void OfflineAstrometryParser::verifyIndexFiles(double fov_x, double fov_y)
{
static double last_fov_x=0, last_fov_y=0;
if (last_fov_x == fov_x && last_fov_y == fov_y)
return;
last_fov_x = fov_x;
last_fov_y = fov_y;
double fov_lower = 0.10 * fov_x;
double fov_upper = fov_x;
QStringList indexFiles;
QString astrometryDataDir;
bool indexesOK = true;
if (getAstrometryDataDir(astrometryDataDir) == false)
return;
QStringList nameFilter("*.fits");
QDir directory(astrometryDataDir);
QStringList indexList = directory.entryList(nameFilter);
QString indexSearch = indexList.join(" ");
QString startIndex, lastIndex;
unsigned int missingIndexes=0;
foreach(float skymarksize, astrometryIndex.keys())
{
if (skymarksize >= fov_lower && skymarksize <= fov_upper)
{
indexFiles << astrometryIndex.value(skymarksize);
if (indexSearch.contains(astrometryIndex.value(skymarksize)) == false)
{
if (startIndex.isEmpty())
startIndex = astrometryIndex.value(skymarksize);
lastIndex = astrometryIndex.value(skymarksize);
indexesOK = false;
missingIndexes++;
}
}
}
if (indexesOK == false)
{
if (missingIndexes == 1)
align->appendLogText(i18n("Index file %1 is missing. Astrometry.net would not be able to adequately solve plates until you install the missing index files. Download the index files from http://www.astrometry.net",
startIndex));
else
align->appendLogText(i18n("Index files %1 to %2 are missing. Astrometry.net would not be able to adequately solve plates until you install the missing index files. Download the index files from http://www.astrometry.net",
startIndex, lastIndex));
}
}
bool OfflineAstrometryParser::getAstrometryDataDir(QString &dataDir)
{
QFile confFile(Options::astrometryConfFile());
if (confFile.open(QIODevice::ReadOnly) == false)
{
KMessageBox::error(0, i18n("Astrometry configuration file corrupted or missing: %1\nPlease set the configuration file full path in INDI options.", Options::astrometryConfFile()));
return false;
}
QTextStream in(&confFile);
QString line;
QStringList confOptions;
while ( !in.atEnd() )
{
line = in.readLine();
if (line.startsWith("#"))
continue;
confOptions = line.split(" ");
if (confOptions.size() == 2)
{
if (confOptions[0] == "add_path")
{
dataDir = confOptions[1];
return true;
}
}
}
KMessageBox::error(0, i18n("Unable to find data dir in astrometry configuration file."));
return false;
}
bool OfflineAstrometryParser::startSovler(const QString &filename, const QStringList &args, bool generated)
{
INDI_UNUSED(generated);
QStringList solverArgs = args;
solverArgs << "-W" << "/tmp/solution.wcs" << filename;
connect(&solver, SIGNAL(finished(int)), this, SLOT(solverComplete(int)));
connect(&solver, SIGNAL(readyReadStandardOutput()), this, SLOT(logSolver()));
fitsFile = filename;
solverTimer.start();
solver.start(Options::astrometrySolver(), solverArgs);
align->appendLogText(i18n("Starting solver..."));
if (Options::solverVerbose())
{
QString command = Options::astrometrySolver() + " " + solverArgs.join(" ");
align->appendLogText(command);
}
return true;
}
bool OfflineAstrometryParser::stopSolver()
{
solver.terminate();
solver.disconnect();
return true;
}
void OfflineAstrometryParser::solverComplete(int exist_status)
{
solver.disconnect();
// TODO use QTemporaryFile later
QFileInfo solution("/tmp/solution.wcs");
if (exist_status != 0 || solution.exists() == false)
{
align->appendLogText(i18n("Solver failed. Try again."));
emit solverFailed();
return;
}
connect(&wcsinfo, SIGNAL(finished(int)), this, SLOT(wcsinfoComplete(int)));
wcsinfo.start(Options::astrometryWCSInfo(), QStringList("/tmp/solution.wcs"));
}
void OfflineAstrometryParser::wcsinfoComplete(int exist_status)
{
wcsinfo.disconnect();
if (exist_status != 0)
{
align->appendLogText(i18n("WCS header missing or corrupted. Solver failed."));
emit solverFailed();
return;
}
QString wcsinfo_stdout = wcsinfo.readAllStandardOutput();
QStringList wcskeys = wcsinfo_stdout.split(QRegExp("[\n]"));
QStringList key_value;
double ra=0, dec=0, orientation=0, pixscale=0;
foreach(QString key, wcskeys)
{
key_value = key.split(" ");
if (key_value.size() > 1)
{
if (key_value[0] == "ra_center")
ra = key_value[1].toDouble();
else if (key_value[0] == "dec_center")
dec = key_value[1].toDouble();
else if (key_value[0] == "orientation_center")
orientation = key_value[1].toDouble();
else if (key_value[0] == "pixscale")
pixscale = key_value[1].toDouble();
}
}
int elapsed = (int) round(solverTimer.elapsed()/1000.0);
align->appendLogText(i18np("Solver completed in %1 second.", "Solver completed in %1 seconds.", elapsed));
emit solverFinished(orientation,ra,dec, pixscale);
// Remove files left over by the solver
QDir dir("/tmp");
dir.setNameFilters(QStringList() << "fits*" << "tmp.*");
dir.setFilter(QDir::Files);
foreach(QString dirFile, dir.entryList())
dir.remove(dirFile);
}
void OfflineAstrometryParser::logSolver()
{
if (Options::solverVerbose())
align->appendLogText(solver.readAll().trimmed());
}
}
/* Astrometry.net Parser
Copyright (C) 2012 Jasem Mutlaq <mutlaqja@ikarustech.com>
This application is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
*/
#ifndef OFFLINEASTROMETRYPARSER_H
#define OFFLINEASTROMETRYPARSER_H
#include <QMap>
#include <QProcess>
#include <QTime>
#include "astrometryparser.h"
namespace Ekos
{
class Align;
/**
* @class OfflineAstrometryParser
* OfflineAstrometryParser invokes the offline astrometry.net solver to find solutions to captured images.
*
* @authro Jasem Mutlaq
*/
class OfflineAstrometryParser: public AstrometryParser
{
Q_OBJECT
public:
OfflineAstrometryParser();
virtual ~OfflineAstrometryParser();
virtual void setAlign(Align *_align) { align = _align; }
virtual bool init();
virtual void verifyIndexFiles(double fov_x, double fov_y);
virtual bool startSovler(const QString &filename, const QStringList &args, bool generated=true);
virtual bool stopSolver();
public slots:
void solverComplete(int exist_status);
void wcsinfoComplete(int exist_status);
void logSolver();
private:
bool astrometryNetOK();
bool getAstrometryDataDir(QString &dataDir);
QMap<float, QString> astrometryIndex;
QProcess solver;
QProcess wcsinfo;
QTime solverTimer;
QString fitsFile;
bool astrometryFilesOK;
Align *align;
};
}
#endif // OFFLINEASTROMETRYPARSER_H
/* Astrometry.net Parser
Copyright (C) 2012 Jasem Mutlaq <mutlaqja@ikarustech.com>
This application is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
*/
#include <QtNetwork/QNetworkReply>
#include <QtNetwork/QNetworkRequest>
#include <QUrl>
#include <QVariantMap>
#include <QDebug>
#include <QHttpMultiPart>
#include <QFile>
#include <QJsonObject>
#include <QJsonDocument>
#include <KLocalizedString>
#include "onlineastrometryparser.h"
#include "align.h"
#include "Options.h"
#include "fitsviewer/fitsdata.h"
#define JOB_RETRY_DURATION 2000 /* 2000 ms */
#define JOB_RETRY_ATTEMPTS 15
#define SOLVER_RETRY_DURATION 2000 /* 2000 ms */
#define SOLVER_RETRY_ATTEMPTS 90
namespace Ekos
{
OnlineAstrometryParser::OnlineAstrometryParser() : AstrometryParser()
{
job_retries=0;
solver_retries=0;
networkManager = new QNetworkAccessManager(this);
connect(this, SIGNAL(authenticateFinished()), this, SLOT(uploadFile()));
connect(this, SIGNAL(uploadFinished()), this, SLOT(getJobID()));
connect(this, SIGNAL(jobIDFinished()), this, SLOT(checkJobs()));
connect(this, SIGNAL(jobFinished()), this, SLOT(checkJobCalibration()));
connect(this, SIGNAL(solverFailed()), this, SLOT(resetSolver()));
connect(this, SIGNAL(solverFinished(double,double,double, double)), this, SLOT(resetSolver()));
downsample_factor = 0;
isGenerated = true;
}
OnlineAstrometryParser::~OnlineAstrometryParser()
{
}
bool OnlineAstrometryParser::init()
{
return true;
}
void OnlineAstrometryParser::verifyIndexFiles(double fov_x, double fov_y)
{
(void)fov_x;
(void)fov_y;
}
bool OnlineAstrometryParser::startSovler(const QString &in_filename, const QStringList &args, bool generated)
{
bool ok;
isGenerated = generated;
job_retries=0;
if (networkManager->networkAccessible() == false)
{
align->appendLogText(i18n("Error: No connection to the internet."));
emit solverFailed();
return false;
}
QString finalFileName(in_filename);
if (Options::astrometryUseJPEG() && in_filename.endsWith(".jpg") == false && in_filename.endsWith(".jpeg") == false)
{
QFile fitsFile(in_filename);
bool rc = fitsFile.open(QIODevice::ReadOnly);
if (rc == false)
{
align->appendLogText(i18n("Failed to open file %1. %2", filename, fitsFile.errorString()));
emit solverFailed();
return false;
}
FITSData *image_data = new FITSData();
rc = image_data->loadFITS(in_filename);
if (rc)
{
double image_width,image_height;
double bscale, bzero;
double min, max;
int val;
image_data->getDimensions(&image_width, &image_height);
QImage *display_image = new QImage(image_width, image_height, QImage::Format_Indexed8);
display_image->setColorCount(256);
for (int i=0; i < 256; i++)
display_image->setColor(i, qRgb(i,i,i));
image_data->getMinMax(&min, &max);
float *image_buffer = image_data->getImageBuffer();
bscale = 255. / (max - min);
bzero = (-min) * (255. / (max - min));
int w = image_width;
int h = image_height;
/* Fill in pixel values using indexed map, linear scale */
for (int j = 0; j < h; j++)
for (int i = 0; i < w; i++)
{
val = image_buffer[j * w + i];
display_image->setPixel(i, j, ((int) (val * bscale + bzero)));
}
finalFileName.remove(finalFileName.lastIndexOf('.'), finalFileName.length());
finalFileName.append(".jpg");
bool isFileSaved = display_image->save(finalFileName, "JPG");
if (isFileSaved == false)
{
align->appendLogText(i18n("Warning: Converting FITS to JPEG failed. Uploading original FITS image."));
finalFileName = in_filename;
}
else
{
if (isGenerated)
QFile::remove(in_filename);
else
isGenerated = true;
}
delete (display_image);
}
else
{
align->appendLogText(i18n("Warning: Converting FITS to JPEG failed. Uploading original FITS image."));
}
delete (image_data);
}
filename = finalFileName;
for (int i=0; i < args.count(); i++)
{
if (args[i] == "-L")
lowerScale = args[i+1].toDouble(&ok);
else if (args[i] == <