11#include "kstarsdata.h"
12#include "flagcomponent.h"
13#include "ksnotification.h"
16#include "starobject.h"
17#include "skymapcomposite.h"
19#include "starobject.h"
20#include "dialogs/finddialog.h"
21#include "QProgressIndicator.h"
23#include <ekos_align_debug.h>
25#define AL_FORMAT_VERSION 1.0
32MountModel::MountModel(Align *parent) :
QDialog(parent)
36 m_AlignInstance = parent;
38 setWindowTitle(
"Mount Model Tool");
40 alignTable->setColumnWidth(0, 70);
41 alignTable->setColumnWidth(1, 75);
42 alignTable->setColumnWidth(2, 130);
43 alignTable->setColumnWidth(3, 30);
45 wizardAlignB->setIcon(
49 clearAllAlignB->setIcon(
62 alignTable->verticalHeader()->setDragDropOverwriteMode(
false);
63 alignTable->verticalHeader()->setSectionsMovable(
true);
64 alignTable->verticalHeader()->setDragEnabled(
true);
66 connect(alignTable->verticalHeader(), SIGNAL(sectionMoved(
int,
int,
int)),
this,
67 SLOT(moveAlignPoint(
int,
int,
int)));
79 previewB->setCheckable(
true);
94 &Ekos::MountModel::alignTypeChanged);
97 &Ekos::MountModel::slotStarSelected);
100 &Ekos::MountModel::slotStarSelected);
114 generateAlignStarList();
118MountModel::~MountModel()
123void MountModel::generateAlignStarList()
126 starListBox->clear();
127 greekStarListBox->clear();
132 for (
int i = 0; i < listStars.
size(); i++)
134 QPair<QString, const SkyObject *> pair = listStars.
value(i);
140 alignStars.append(alignStar);
147 for (
int i = 0; i < alignStars.size(); i++)
152 if (!isVisible(star))
154 alignStars.remove(i);
160 boxNames << star->
name();
175 QStringList aParts = a.split(
' ');
176 QStringList bParts = b.split(
' ');
177 if (aParts.length() < 2 || bParts.length() < 2)
179 if (aParts[1] == bParts[1])
181 return aParts[0] < bParts[0];
184 return aParts[1] < bParts[1];
187 starListBox->addItem(
"Select one:");
188 greekStarListBox->addItem(
"Select one:");
189 for (
int i = 0; i < boxNames.
size(); i++)
190 starListBox->addItem(boxNames.
at(i));
191 for (
int i = 0; i < greekBoxNames.
size(); i++)
192 greekStarListBox->addItem(greekBoxNames.
at(i));
195bool MountModel::isVisible(
const SkyObject *so)
197 return (getAltitude(so) > 30);
200double MountModel::getAltitude(
const SkyObject *so)
211void MountModel::togglePreviewAlignPoints()
213 previewShowing = !previewShowing;
214 previewB->setChecked(previewShowing);
215 updatePreviewAlignPoints();
218void MountModel::updatePreviewAlignPoints()
221 for (
int i = 0; i < flags->
size(); i++)
231 for (
int i = 0; i < alignTable->rowCount(); i++)
237 if (raCell && deCell && objNameCell)
247 flags->
add(flagPoint,
"J2000",
"Default",
"Align " +
QString::number(i + 1) +
' ' + objString,
"white");
254void MountModel::slotLoadAlignmentPoints()
258 "Ekos AlignmentList (*.eal)");
262 if (fileURL.
isValid() ==
false)
265 KSNotification::sorry(message,
i18n(
"Invalid URL"));
273 updatePreviewAlignPoints();
276bool MountModel::loadAlignmentPoints(
const QString &fileURL)
283 QString message =
i18n(
"Unable to open file %1", fileURL);
284 KSNotification::sorry(message,
i18n(
"Could Not Open File"));
288 alignTable->setRowCount(0);
290 LilXML *xmlParser = newLilXML();
292 char errmsg[MAXRBUF];
293 XMLEle *root =
nullptr;
298 root = readXMLEle(xmlParser, c, errmsg);
302 double sqVersion = atof(findXMLAttValu(root,
"version"));
303 if (sqVersion < AL_FORMAT_VERSION)
305 emit newLog(
i18n(
"Deprecated sequence file format version %1. Please construct a new sequence file.",
310 XMLEle *ep =
nullptr;
311 XMLEle *subEP =
nullptr;
315 for (ep = nextXMLEle(root, 1); ep !=
nullptr; ep = nextXMLEle(root, 0))
317 if (!strcmp(tagXMLEle(ep),
"AlignmentPoint"))
319 alignTable->insertRow(currentRow);
321 subEP = findXMLEle(ep,
"RA");
325 RAReport->
setText(pcdataXMLEle(subEP));
327 alignTable->setItem(currentRow, 0, RAReport);
331 subEP = findXMLEle(ep,
"DE");
335 DEReport->
setText(pcdataXMLEle(subEP));
337 alignTable->setItem(currentRow, 1, DEReport);
341 subEP = findXMLEle(ep,
"NAME");
345 ObjReport->
setText(pcdataXMLEle(subEP));
347 alignTable->setItem(currentRow, 2, ObjReport);
360void MountModel::slotSaveAlignmentPoints()
362 QUrl backupCurrent = alignURL;
364 if (alignURL.toLocalFile().startsWith(
QLatin1String(
"/tmp/")) || alignURL.toLocalFile().contains(
"/Temp"))
368 "Ekos Alignment List (*.eal)");
370 if (alignURL.isEmpty())
372 alignURL = backupCurrent;
376 if (alignURL.toLocalFile().endsWith(
QLatin1String(
".eal")) ==
false)
377 alignURL.
setPath(alignURL.toLocalFile() +
".eal");
380 if (alignURL.isValid())
382 if ((saveAlignmentPoints(alignURL.toLocalFile())) ==
false)
384 KSNotification::error(
i18n(
"Failed to save alignment list"),
i18n(
"Save"));
390 QString message =
i18n(
"Invalid URL: %1", alignURL.url());
391 KSNotification::sorry(message,
i18n(
"Invalid URL"));
395bool MountModel::saveAlignmentPoints(
const QString &path)
401 QString message =
i18n(
"Unable to write to file %1", path);
402 KSNotification::sorry(message,
i18n(
"Could Not Open File"));
408 outstream <<
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" <<
Qt::endl;
409 outstream <<
"<AlignmentList version='" << AL_FORMAT_VERSION <<
"'>" <<
Qt::endl;
411 for (
int i = 0; i < alignTable->rowCount(); i++)
417 if (!raCell || !deCell || !objNameCell)
423 outstream <<
"<AlignmentPoint>" <<
Qt::endl;
424 outstream <<
"<RA>" << raString <<
"</RA>" <<
Qt::endl;
425 outstream <<
"<DE>" << deString <<
"</DE>" <<
Qt::endl;
426 outstream <<
"<NAME>" << objString <<
"</NAME>" <<
Qt::endl;
427 outstream <<
"</AlignmentPoint>" <<
Qt::endl;
429 outstream <<
"</AlignmentList>" <<
Qt::endl;
430 emit newLog(
i18n(
"Alignment List saved to %1", path));
435void MountModel::slotSortAlignmentPoints()
437 int firstAlignmentPt = findClosestAlignmentPointToTelescope();
438 if (firstAlignmentPt != -1)
440 swapAlignPoints(firstAlignmentPt, 0);
443 for (
int i = 0; i < alignTable->rowCount() - 1; i++)
445 int nextAlignmentPoint = findNextAlignmentPointAfter(i);
446 if (nextAlignmentPoint != -1)
448 swapAlignPoints(nextAlignmentPoint, i + 1);
452 updatePreviewAlignPoints();
455int MountModel::findClosestAlignmentPointToTelescope()
460 for (
int i = 0; i < alignTable->rowCount(); i++)
465 if (raCell && deCell)
471 dms thisDiff = telescopeCoord.angularDistanceTo(&sk);
482int MountModel::findNextAlignmentPointAfter(
int currentSpot)
487 if (currentRACell && currentDECell)
492 SkyPoint thisPt(thisRADMS, thisDEDMS);
497 for (
int i = currentSpot + 1; i < alignTable->rowCount(); i++)
502 if (raCell && deCell)
507 dms thisDiff = thisPt.angularDistanceTo(&point);
522void MountModel::slotWizardAlignmentPoints()
524 int points = alignPtNum->value();
529 int minAlt = minAltBox->value();
532 double lat =
geo->lat()->Degrees();
534 if (alignTypeBox->currentIndex() == OBJECT_FIXED_DEC)
536 double decAngle = alignDec->value();
540 if (decAngle < lat - 90 + minAlt)
542 KSNotification::sorry(
i18n(
"DEC is below the altitude limit"));
548 if (decAngle > lat + 90 - minAlt)
550 KSNotification::sorry(
i18n(
"DEC is below the altitude limit"));
560 numRAperDEC = qSqrt(points);
563 int decPoints = (points - 1) / numRAperDEC + 1;
564 int lastSetRAPoints = (points - 1) % numRAperDEC + 1;
566 double decIncrement = -1;
570 if (alignTypeBox->currentIndex() == OBJECT_FIXED_DEC)
573 initDEC = alignDec->value();
576 else if (decPoints == 1)
594 decIncrement = (80 - initDEC) / (decPoints);
596 decIncrement = (initDEC - 80) / (decPoints);
599 for (
int d = 0; d < decPoints; d++)
602 double raPoints = -1;
603 double raIncrement = -1;
607 dec = initDEC + d * decIncrement;
609 dec = initDEC - d * decIncrement;
611 if (alignTypeBox->currentIndex() == OBJECT_FIXED_DEC)
615 else if (d == decPoints - 1)
617 raPoints = lastSetRAPoints;
621 raPoints = numRAperDEC;
625 calculateAngleForRALine(raIncrement, initRA, dec, lat, raPoints, minAlt);
627 if (raIncrement == -1 || decIncrement == -1)
629 KSNotification::sorry(
i18n(
"Point calculation error."));
633 for (
int i = 0; i < raPoints; i++)
635 double ra = initRA + i * raIncrement;
637 const SkyObject *original = getWizardAlignObject(ra, dec);
650 getFormattedCoords(
dms(ra).Hours(), dec, ra_report, dec_report);
654 int currentRow = alignTable->rowCount();
655 alignTable->insertRow(currentRow);
660 alignTable->setItem(currentRow, 0, RAReport);
663 DECReport->
setText(dec_report);
665 alignTable->setItem(currentRow, 1, DECReport);
670 alignTable->setItem(currentRow, 2, ObjNameReport);
674 alignTable->setItem(currentRow, 3, disabledBox);
678 updatePreviewAlignPoints();
681void MountModel::calculateAngleForRALine(
double &raIncrement,
double &initRA,
double initDEC,
double lat,
double raPoints,
688 if (fabs(initDEC) > (90 - fabs(lat) + minAlt))
691 raIncrement = 360 / (raPoints - 1);
699 calculateAZPointsForDEC(
dms(initDEC),
dms(minAlt), AZEast, AZWest);
713 raIncrement = fabs(angleSep.
Degrees() / (raPoints - 1));
719void MountModel::calculateAZPointsForDEC(
dms dec,
dms alt,
dms &AZEast,
dms &AZWest)
725 double sindec, cosdec, sinlat, coslat;
726 double sinAlt, cosAlt;
728 geo->lat()->SinCos(sinlat, coslat);
729 dec.SinCos(sindec, cosdec);
730 alt.
SinCos(sinAlt, cosAlt);
732 double arg = (sindec - sinlat * sinAlt) / (coslat * cosAlt);
738const SkyObject *MountModel::getWizardAlignObject(
double ra,
double dec)
740 double maxSearch = 5.0;
741 switch (alignTypeBox->currentIndex())
743 case OBJECT_ANY_OBJECT:
745 case OBJECT_FIXED_DEC:
746 case OBJECT_FIXED_GRID:
749 case OBJECT_ANY_STAR:
757 for (
int i = 0; i < alignStars.size(); i++)
765 dms thisDiff = thisPt.angularDistanceTo(star);
776 return alignStars.value(index);
779void MountModel::alignTypeChanged(
int alignType)
781 if (alignType == OBJECT_FIXED_DEC)
782 alignDec->setEnabled(
true);
784 alignDec->setEnabled(
false);
787void MountModel::slotStarSelected(
const QString selectedStar)
789 for (
int i = 0; i < alignStars.size(); i++)
796 int currentRow = alignTable->rowCount();
797 alignTable->insertRow(currentRow);
805 alignTable->setItem(currentRow, 0, RAReport);
808 DECReport->
setText(dec_report);
810 alignTable->setItem(currentRow, 1, DECReport);
815 alignTable->setItem(currentRow, 2, ObjNameReport);
819 alignTable->setItem(currentRow, 3, disabledBox);
821 starListBox->setCurrentIndex(0);
822 greekStarListBox->setCurrentIndex(0);
828 updatePreviewAlignPoints();
832void MountModel::getFormattedCoords(
double ra,
double dec,
QString &ra_str,
QString &dec_str)
854void MountModel::slotClearAllAlignPoints()
856 if (alignTable->rowCount() == 0)
859 if (KMessageBox::questionYesNo(
this,
i18n(
"Are you sure you want to clear all the alignment points?"),
860 i18n(
"Clear Align Points")) == KMessageBox::Yes)
861 alignTable->setRowCount(0);
864 updatePreviewAlignPoints();
867void MountModel::slotRemoveAlignPoint()
869 alignTable->removeRow(alignTable->currentRow());
871 updatePreviewAlignPoints();
874void MountModel::moveAlignPoint(
int logicalIndex,
int oldVisualIndex,
int newVisualIndex)
876 Q_UNUSED(logicalIndex)
878 for (
int i = 0; i < alignTable->columnCount(); i++)
883 alignTable->setItem(newVisualIndex, i, oldItem);
884 alignTable->setItem(oldVisualIndex, i, newItem);
886 alignTable->verticalHeader()->blockSignals(
true);
887 alignTable->verticalHeader()->moveSection(newVisualIndex, oldVisualIndex);
888 alignTable->verticalHeader()->blockSignals(
false);
891 updatePreviewAlignPoints();
894void MountModel::swapAlignPoints(
int firstPt,
int secondPt)
896 for (
int i = 0; i < alignTable->columnCount(); i++)
901 alignTable->setItem(firstPt, i, secondPtItem);
902 alignTable->setItem(secondPt, i, firstPtItem);
906void MountModel::slotAddAlignPoint()
908 int currentRow = alignTable->rowCount();
909 alignTable->insertRow(currentRow);
913 alignTable->setItem(currentRow, 3, disabledBox);
916void MountModel::slotFindAlignObject()
921 if (
object !=
nullptr)
923 KStarsData *
const data = KStarsData::Instance();
927 int currentRow = alignTable->rowCount();
928 alignTable->insertRow(currentRow);
936 alignTable->setItem(currentRow, 0, RAReport);
939 DECReport->
setText(dec_report);
941 alignTable->setItem(currentRow, 1, DECReport);
946 alignTable->setItem(currentRow, 2, ObjNameReport);
950 alignTable->setItem(currentRow, 3, disabledBox);
954 updatePreviewAlignPoints();
957void MountModel::resetAlignmentProcedure()
959 alignTable->setCellWidget(currentAlignmentPoint, 3,
new QWidget());
962 statusReport->
setIcon(
QIcon(
":/icons/AlignWarning.svg"));
963 alignTable->setItem(currentAlignmentPoint, 3, statusReport);
965 emit newLog(
i18n(
"The Mount Model Tool is Reset."));
966 startAlignB->setIcon(
969 currentAlignmentPoint = 0;
973bool MountModel::alignmentPointsAreBad()
975 for (
int i = 0; i < alignTable->rowCount(); i++)
981 if (
dms().setFromString(raString,
false) ==
false)
988 if (
dms().setFromString(decString,
true) ==
false)
994void MountModel::startStopAlignmentProcedure()
998 if (alignTable->rowCount() > 0)
1000 if (alignmentPointsAreBad())
1002 KSNotification::error(
i18n(
"Please Check the Alignment Points."));
1005 if (m_AlignInstance->currentGOTOMode() == Align::GOTO_NOTHING)
1009 i18n(
"In the Align Module, \"Nothing\" is Selected for the Solver Action. This means that the "
1010 "mount model tool will not sync/align your mount but will only report the pointing model "
1011 "errors. Do you wish to continue?"),
1013 "nothing_selected_warning");
1017 if (currentAlignmentPoint == 0)
1019 for (
int row = 0; row < alignTable->rowCount(); row++)
1023 alignTable->setItem(row, 3, statusReport);
1026 startAlignB->setIcon(
1029 emit newLog(
i18n(
"The Mount Model Tool is Starting."));
1030 startAlignmentPoint();
1035 startAlignB->setIcon(
1037 alignTable->setCellWidget(currentAlignmentPoint, 3,
new QWidget());
1038 emit newLog(
i18n(
"The Mount Model Tool is Paused."));
1040 m_IsRunning =
false;
1044 statusReport->
setIcon(
QIcon(
":/icons/AlignWarning.svg"));
1045 alignTable->setItem(currentAlignmentPoint, 3, statusReport);
1049void MountModel::startAlignmentPoint()
1051 if (m_IsRunning && currentAlignmentPoint >= 0 && currentAlignmentPoint < alignTable->rowCount())
1056 double raDeg = raDMS.
Degrees();
1064 alignTable->setCellWidget(currentAlignmentPoint, 3, alignIndicator);
1067 const SkyObject *target = getWizardAlignObject(raDeg, dec);
1068 m_AlignInstance->setTarget(*target);
1069 m_AlignInstance->Slew();
1073void MountModel::finishAlignmentPoint(
bool solverSucceeded)
1075 if (m_IsRunning && currentAlignmentPoint >= 0 && currentAlignmentPoint < alignTable->rowCount())
1077 alignTable->setCellWidget(currentAlignmentPoint, 3,
new QWidget());
1080 if (solverSucceeded)
1081 statusReport->
setIcon(
QIcon(
":/icons/AlignSuccess.svg"));
1083 statusReport->
setIcon(
QIcon(
":/icons/AlignFailure.svg"));
1084 alignTable->setItem(currentAlignmentPoint, 3, statusReport);
1086 currentAlignmentPoint++;
1088 if (currentAlignmentPoint < alignTable->rowCount())
1090 startAlignmentPoint();
1094 m_IsRunning =
false;
1095 startAlignB->setIcon(
1097 emit newLog(
i18n(
"The Mount Model Tool is Finished."));
1098 currentAlignmentPoint = 0;
1109 finishAlignmentPoint(
true);
1114 finishAlignmentPoint(
false);
SkyObject * targetObject()
Represents a flag on the sky map.
int size()
Return the numbers of flags.
void remove(int index)
Remove a flag.
QString label(int index)
Get label.
void add(const SkyPoint &flagPoint, QString epoch, QString image, QString label, QColor labelColor)
Add a flag.
Contains all relevant information for specifying a location on Earth: City Name, State/Province name,...
const CachingDms * lat() const
KStarsData is the backbone of KStars.
const KStarsDateTime & ut() const
SkyMapComposite * skyComposite()
static KStars * Instance()
KStarsData * data() const
The QProgressIndicator class lets an application display a progress indicator to show that a long tas...
void startAnimation()
Starts the spin animation.
SkyObject * starNearest(SkyPoint *p, double &maxrad)
SkyObject * objectNearest(SkyPoint *p, double &maxrad) override
void forceUpdate(bool now=false)
Recalculates the positions of objects in the sky, and then repaints the sky map.
Provides all necessary information about an object in the sky: its coordinates, name(s),...
virtual SkyObject * clone() const
Create copy of object.
virtual QString longname(void) const
SkyPoint recomputeCoords(const KStarsDateTime &dt, const GeoLocation *geo=nullptr) const
The equatorial coordinates for the object on date dt are computed and returned, but the object's inte...
The sky coordinates of a point in the sky.
const CachingDms & dec() const
const CachingDms & ra0() const
const CachingDms & ra() const
void EquatorialToHorizontal(const CachingDms *LST, const CachingDms *lat)
Determine the (Altitude, Azimuth) coordinates of the SkyPoint from its (RA, Dec) coordinates,...
virtual void updateCoords(const KSNumbers *num, bool includePlanets=true, const CachingDms *lat=nullptr, const CachingDms *LST=nullptr, bool forceRecompute=false)
Determine the current coordinates (RA, Dec) from the catalog coordinates (RA0, Dec0),...
void setAlt(dms alt)
Sets Alt, the Altitude.
void HorizontalToEquatorial(const dms *LST, const dms *lat)
Determine the (RA, Dec) coordinates of the SkyPoint from its (Altitude, Azimuth) coordinates,...
void setAz(dms az)
Sets Az, the Azimuth.
const CachingDms & dec0() const
This is a subclass of SkyObject.
StarObject * clone() const override
Create copy of object.
QString name(void) const override
If star is unnamed return "star" otherwise return the name.
void updateCoords(const KSNumbers *num, bool includePlanets=true, const CachingDms *lat=nullptr, const CachingDms *LST=nullptr, bool forceRecompute=false) override
Determine the current coordinates (RA, Dec) from the catalog coordinates (RA0, Dec0),...
QString longname(void) const override
If star is unnamed return "star" otherwise return the longname.
bool hasLatinName() const
QString gname(bool useGreekChars=true) const
Returns the genetive name of the star.
An angle, stored as degrees, but expressible in many ways.
static dms fromString(const QString &s, bool deg)
Static function to create a DMS object from a QString.
virtual void setH(const double &x)
Sets floating-point value of angle, in hours.
void SinCos(double &s, double &c) const
Compute Sine and Cosine of the angle simultaneously.
static constexpr double PI
PI is a const static member; it's public so that it can be used anywhere, as long as dms....
const dms deltaAngle(dms angle) const
deltaAngle Return the shortest difference (path) between this angle and the supplied angle.
virtual void setRadians(const double &Rad)
Set angle according to the argument, in radians.
virtual void setD(const double &x)
Sets floating-point value of angle, in degrees.
const double & Degrees() const
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
Ekos is an advanced Astrophotography tool for Linux.
@ ALIGN_FAILED
Alignment failed.
@ ALIGN_COMPLETE
Alignment successfully completed.
QString name(GameStandardAction id)
GeoCoordinates geo(const QVariant &location)
ButtonCode warningContinueCancel(QWidget *parent, const QString &text, const QString &title=QString(), const KGuiItem &buttonContinue=KStandardGuiItem::cont(), const KGuiItem &buttonCancel=KStandardGuiItem::cancel(), const QString &dontAskAgainName=QString(), Options options=Notify)
void currentIndexChanged(int index)
void currentTextChanged(const QString &text)
bool open(FILE *fh, OpenMode mode, FileHandleFlags handleFlags)
void setFileName(const QString &name)
virtual void close() override
QUrl getOpenFileUrl(QWidget *parent, const QString &caption, const QUrl &dir, const QString &filter, QString *selectedFilter, Options options, const QStringList &supportedSchemes)
QUrl getSaveFileUrl(QWidget *parent, const QString &caption, const QUrl &dir, const QString &filter, QString *selectedFilter, Options options, const QStringList &supportedSchemes)
QIcon fromTheme(const QString &name)
void append(QList< T > &&value)
const_reference at(qsizetype i) const const
qsizetype size() const const
T value(qsizetype i) const const
QString arg(Args &&... args) const const
bool isEmpty() const const
QString number(double n, char format, int precision)
QString simplified() const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
qsizetype removeDuplicates()
void sort(Qt::CaseSensitivity cs)
QTextStream & dec(QTextStream &stream)
QTextStream & endl(QTextStream &stream)
void setText(const QString &text)
void setTextAlignment(Qt::Alignment alignment)
QString text() const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
bool isEmpty() const const
bool isValid() const const
void setPath(const QString &path, ParsingMode mode)
QString toLocalFile() const const