Commit 030e4855 authored by Jasem Mutlaq's avatar Jasem Mutlaq
Browse files

Moving common Ekos files to the auxiliary directory for better organization

parent ab7cc640
/*
*
* This file is part of QProgressIndicator,
* an open-source recent files menu widget
*
* Copyright (C) 2009 - 2010 Morgan Leborgne
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with QRecentFilesMenu. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "QProgressIndicator.h"
#include <QPainter>
QProgressIndicator::QProgressIndicator(QWidget* parent)
: QWidget(parent),
m_angle(0),
m_timerId(-1),
m_delay(40),
m_displayedWhenStopped(false),
m_color(Qt::black)
{
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
setFocusPolicy(Qt::NoFocus);
}
bool QProgressIndicator::isAnimated () const
{
return (m_timerId != -1);
}
void QProgressIndicator::setDisplayedWhenStopped(bool state)
{
m_displayedWhenStopped = state;
update();
}
bool QProgressIndicator::isDisplayedWhenStopped() const
{
return m_displayedWhenStopped;
}
void QProgressIndicator::startAnimation()
{
m_angle = 0;
if (m_timerId == -1)
m_timerId = startTimer(m_delay);
}
void QProgressIndicator::stopAnimation()
{
if (m_timerId != -1)
killTimer(m_timerId);
m_timerId = -1;
update();
}
void QProgressIndicator::setAnimationDelay(int delay)
{
if (m_timerId != -1)
killTimer(m_timerId);
m_delay = delay;
if (m_timerId != -1)
m_timerId = startTimer(m_delay);
}
void QProgressIndicator::setColor(const QColor & color)
{
m_color = color;
update();
}
QSize QProgressIndicator::sizeHint() const
{
return QSize(20,20);
}
int QProgressIndicator::heightForWidth(int w) const
{
return w;
}
void QProgressIndicator::timerEvent(QTimerEvent * /*event*/)
{
m_angle = (m_angle+30)%360;
update();
}
void QProgressIndicator::paintEvent(QPaintEvent * /*event*/)
{
if (!m_displayedWhenStopped && !isAnimated())
return;
int width = qMin(this->width(), this->height());
QPainter p(this);
p.setRenderHint(QPainter::Antialiasing);
int outerRadius = (width-1)*0.5;
int innerRadius = (width-1)*0.5*0.38;
int capsuleHeight = outerRadius - innerRadius;
int capsuleWidth = (width > 32 ) ? capsuleHeight *.23 : capsuleHeight *.35;
int capsuleRadius = capsuleWidth/2;
for (int i=0; i<12; i++)
{
QColor color = m_color;
color.setAlphaF(1.0f - (i/12.0f));
p.setPen(Qt::NoPen);
p.setBrush(color);
p.save();
p.translate(rect().center());
p.rotate(m_angle - i*30.0f);
p.drawRoundedRect(-capsuleWidth*0.5, -(innerRadius+capsuleHeight), capsuleWidth, capsuleHeight, capsuleRadius, capsuleRadius);
p.restore();
}
}
/*
*
* This file is part of QProgressIndicator,
* an open-source recent files menu widget
*
* Copyright (C) 2009 - 2010 Morgan Leborgne
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with QRecentFilesMenu. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef QPROGRESSINDICATOR_H
#define QPROGRESSINDICATOR_H
#include <QWidget>
#include <QColor>
/*!
\class QProgressIndicator
\brief The QProgressIndicator class lets an application display a progress indicator to show that a lengthy task is under way.
Progress indicators are indeterminate and do nothing more than spin to show that the application is busy.
\sa QProgressBar
*/
class QProgressIndicator : public QWidget
{
Q_OBJECT
Q_PROPERTY(int delay READ animationDelay WRITE setAnimationDelay)
Q_PROPERTY(bool displayedWhenStopped READ isDisplayedWhenStopped WRITE setDisplayedWhenStopped)
Q_PROPERTY(QColor color READ color WRITE setColor)
public:
explicit QProgressIndicator(QWidget* parent = 0);
/*! Returns the delay between animation steps.
\return The number of milliseconds between animation steps. By default, the animation delay is set to 40 milliseconds.
\sa setAnimationDelay
*/
int animationDelay() const { return m_delay; }
/*! Returns a Boolean value indicating whether the component is currently animated.
\return Animation state.
\sa startAnimation stopAnimation
*/
bool isAnimated () const;
/*! Returns a Boolean value indicating whether the receiver shows itself even when it is not animating.
\return Return true if the progress indicator shows itself even when it is not animating. By default, it returns false.
\sa setDisplayedWhenStopped
*/
bool isDisplayedWhenStopped() const;
/*! Returns the color of the component.
\sa setColor
*/
const QColor & color() const { return m_color; }
virtual QSize sizeHint() const;
int heightForWidth(int w) const;
public slots:
/*! Starts the spin animation.
\sa stopAnimation isAnimated
*/
void startAnimation();
/*! Stops the spin animation.
\sa startAnimation isAnimated
*/
void stopAnimation();
/*! Sets the delay between animation steps.
Setting the \a delay to a value larger than 40 slows the animation, while setting the \a delay to a smaller value speeds it up.
\param delay The delay, in milliseconds.
\sa animationDelay
*/
void setAnimationDelay(int delay);
/*! Sets whether the component hides itself when it is not animating.
\param state The animation state. Set false to hide the progress indicator when it is not animating; otherwise true.
\sa isDisplayedWhenStopped
*/
void setDisplayedWhenStopped(bool state);
/*! Sets the color of the components to the given color.
\sa color
*/
void setColor(const QColor & color);
protected:
virtual void timerEvent(QTimerEvent * event);
virtual void paintEvent(QPaintEvent * event);
private:
int m_angle;
int m_timerId;
int m_delay;
bool m_displayedWhenStopped;
QColor m_color;
};
#endif // QPROGRESSINDICATOR_H
/* Ekos Dark Library Handler
Copyright (C) 2016 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 <QVariantMap>
#include "darklibrary.h"
#include "Options.h"
#include "kstars.h"
#include "kspaths.h"
#include "kstarsdata.h"
#include "fitsviewer/fitsview.h"
#include "fitsviewer/fitsdata.h"
#include "auxiliary/ksuserdb.h"
namespace Ekos
{
DarkLibrary * DarkLibrary::_DarkLibrary = NULL;
DarkLibrary * DarkLibrary::Instance()
{
if (_DarkLibrary == NULL)
_DarkLibrary = new DarkLibrary(KStars::Instance());
return _DarkLibrary;
}
DarkLibrary::DarkLibrary(QObject *parent) : QObject(parent)
{
KStarsData::Instance()->userdb()->GetAllDarkFrames(darkFrames);
subtractParams.duration=0;
subtractParams.offsetX=0;
subtractParams.offsetY=0;
subtractParams.targetChip=0;
subtractParams.targetImage=0;
QDir writableDir;
writableDir.mkdir(KSPaths::writableLocation(QStandardPaths::GenericDataLocation) + "darks");
}
DarkLibrary::~DarkLibrary()
{
qDeleteAll(darkFiles);
}
FITSData * DarkLibrary::getDarkFrame(ISD::CCDChip *targetChip, double duration)
{
foreach(QVariantMap map, darkFrames)
{
// First check CCD name matches
if (map["ccd"].toString() == targetChip->getCCD()->getDeviceName())
{
// Then check we are on the correct chip
if (map["chip"].toInt() == static_cast<int>(targetChip->getType()))
{
int binX, binY;
targetChip->getBinning(&binX, &binY);
// Then check if binning is the same
if (map["binX"].toInt() == binX && map["binY"].toInt() == binY)
{
// Then check for temperature
if (targetChip->getCCD()->hasCooler())
{
double temperature=0;
targetChip->getCCD()->getTemperature(&temperature);
// TODO make this configurable value, the threshold
if (fabs(map["temperature"].toDouble()-temperature) > Options::maxDarkTemperatureDiff())
continue;
}
// Then check for duration
// TODO make this value configurable
if (fabs(map["duration"].toDouble() - duration) > 0.05)
continue;
// Finaly check if the duration is acceptable
QDateTime frameTime = QDateTime::fromString(map["timestamp"].toString(), Qt::ISODate);
if (frameTime.daysTo(QDateTime::currentDateTime()) > Options::darkLibraryDuration())
continue;
QString filename = map["filename"].toString();
if (darkFiles.contains(filename))
return darkFiles[filename];
// Finally we made it, let's put it in the hash
bool rc = loadDarkFile(filename);
if (rc)
return darkFiles[filename];
else
return NULL;
}
}
}
}
return NULL;
}
bool DarkLibrary::loadDarkFile(const QString &filename)
{
FITSData *darkData = new FITSData();
bool rc = darkData->loadFITS(filename);
if (rc)
darkFiles[filename] = darkData;
else
{
emit newLog(i18n("Failed to load dark frame file %1", filename));
delete (darkData);
}
return rc;
}
bool DarkLibrary::saveDarkFile(FITSData *darkData)
{
QDateTime ts = QDateTime::currentDateTime();
QString path = KSPaths::writableLocation(QStandardPaths::GenericDataLocation) + "darks/darkframe_" + ts.toString(Qt::ISODate) + ".fits";
if (darkData->saveFITS(path) != 0)
return false;
darkFiles[path] = darkData;
QVariantMap map;
int binX, binY;
double temperature=0;
subtractParams.targetChip->getBinning(&binX, &binY);
subtractParams.targetChip->getCCD()->getTemperature(&temperature);
map["ccd"] = subtractParams.targetChip->getCCD()->getDeviceName();
map["chip"] = static_cast<int>(subtractParams.targetChip->getType());
map["binX"] = binX;
map["binY"] = binY;
map["temperature"] = temperature;
map["duration"] = subtractParams.duration;
map["filename"] = path;
darkFrames.append(map);
emit newLog(i18n("Dark frame saved to %1", path));
KStarsData::Instance()->userdb()->AddDarkFrame(map);
return true;
}
bool DarkLibrary::subtract(FITSData *darkData, FITSView *lightImage, FITSScale filter, uint16_t offsetX, uint16_t offsetY)
{
Q_ASSERT(darkData);
Q_ASSERT(lightImage);
FITSData *lightData = lightImage->getImageData();
float *darkBuffer = darkData->getImageBuffer();
float *lightBuffer = lightData->getImageBuffer();
int darkoffset = offsetX + offsetY * darkData->getWidth();
int darkW = darkData->getWidth();
int lightOffset = 0;
int lightW = lightData->getWidth();
int lightH = lightData->getHeight();
for (int i=0; i < lightH; i++)
{
for (int j=0; j < lightW; j++)
{
lightBuffer[j+lightOffset] -= darkBuffer[j+darkoffset];
if (lightBuffer[j+lightOffset] < 0)
lightBuffer[j+lightOffset] = 0;
}
lightOffset += lightW;
darkoffset += darkW;
}
lightData->applyFilter(filter);
lightImage->rescale(ZOOM_KEEP_LEVEL);
lightImage->updateFrame();
emit darkFrameCompleted(true);
return true;
}
void DarkLibrary::captureAndSubtract(ISD::CCDChip *targetChip, FITSView*targetImage, double duration, uint16_t offsetX, uint16_t offsetY)
{
QStringList shutterfulCCDs = Options::shutterfulCCDs();
QStringList shutterlessCCDs = Options::shutterlessCCDs();
QString deviceName = targetChip->getCCD()->getDeviceName();
bool hasShutter = shutterfulCCDs.contains(deviceName);
bool hasNoShutter = shutterlessCCDs.contains(deviceName);
// If no information is available either way, then ask the user
if (hasShutter == false && hasNoShutter == false)
{
if (KMessageBox::questionYesNo(NULL, i18n("Does %1 have mechanical or electronic shutter?", deviceName), i18n("Dark Exposure")) == KMessageBox::Yes)
{
hasShutter = true;
hasNoShutter = false;
shutterfulCCDs.append(deviceName);
Options::setShutterfulCCDs(shutterfulCCDs);
}
else
{
hasShutter = false;
hasNoShutter = true;
shutterlessCCDs.append(deviceName);
Options::setShutterlessCCDs(shutterlessCCDs);
}
}
if (hasNoShutter)
{
KMessageBox::information(NULL, i18n("Cover the telescope or camera in order to take a dark exposure."), i18n("Dark Exposure"), "dark_exposure_dialog_notification");
}
targetChip->resetFrame();
targetChip->setCaptureMode(FITS_CALIBRATE);
targetChip->setFrameType(FRAME_DARK);
subtractParams.targetChip = targetChip;
subtractParams.targetImage= targetImage;
subtractParams.duration = duration;
subtractParams.offsetX = offsetX;
subtractParams.offsetY = offsetY;
connect(targetChip->getCCD(), SIGNAL(BLOBUpdated(IBLOB*)), this, SLOT(newFITS(IBLOB*)));
emit newLog(i18n("Capturing dark frame..."));
targetChip->capture(duration);
}
void DarkLibrary::newFITS(IBLOB *bp)
{
INDI_UNUSED(bp);
Q_ASSERT(subtractParams.targetChip);
disconnect(subtractParams.targetChip->getCCD(), SIGNAL(BLOBUpdated(IBLOB*)), this, SLOT(newFITS(IBLOB*)));
FITSView *calibrationView = subtractParams.targetChip->getImage(FITS_CALIBRATE);
emit newLog(i18n("Dark frame received."));
FITSData *calibrationData = new FITSData();
// Deep copy of the data
if (calibrationData->loadFITS(calibrationView->getImageData()->getFilename()))
{
saveDarkFile(calibrationData);
subtract(calibrationData, subtractParams.targetImage, subtractParams.targetChip->getCaptureFilter(), subtractParams.offsetX, subtractParams.offsetY);
}
else
{
emit darkFrameCompleted(false);
emit newLog(i18n("Warning: Cannot load calibration file %1", calibrationView->getImageData()->getFilename()));
}
}
}
/* Ekos Dark Library Handler
Copyright (C) 2016 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 DARKLIBRARY_H
#define DARKLIBRARY_H
#include <QObject>
#include "indi/indiccd.h"
namespace Ekos
{
/**
*@class DarkLibrary
*@short Handles aquisition & loading of dark frames for cameras. If a suitable dark frame exists, it is loaded from disk, otherwise it gets captured and saved
* for later use.
*@author Jasem Mutlaq
*@version 1.0
*/
class DarkLibrary : public QObject
{
Q_OBJECT
public:
static DarkLibrary *Instance();
FITSData * getDarkFrame(ISD::CCDChip *targetChip, double duration);
bool subtract(FITSData *darkData, FITSView *lightImage, FITSScale filter, uint16_t offsetX, uint16_t offsetY);
void captureAndSubtract(ISD::CCDChip *targetChip, FITSView*targetImage, double duration, uint16_t offsetX, uint16_t offsetY);
signals:
void darkFrameCompleted(bool);
void newLog(const QString &message);
public slots:
/**
* @brief newFITS A new FITS blob is received by the CCD driver.
* @param bp pointer to blob data
*/
void newFITS(IBLOB *bp);
private:
DarkLibrary(QObject *parent);
~DarkLibrary();
static DarkLibrary * _DarkLibrary;
bool loadDarkFile(const QString &filename);
bool saveDarkFile(FITSData *darkData);
QList<QVariantMap> darkFrames;
QHash<QString, FITSData *> darkFiles;
struct
{
ISD::CCDChip *targetChip;
double duration;
uint16_t offsetX;
uint16_t offsetY;
FITSView *targetImage;
FITSScale filter;
} subtractParams;
};
}
#endif // DARKLIBRARY_H
/* Ekos
Copyright (C) 2012 Jasem Mutlaq <mutlaqja@ikarustech.com>