11 #include <config-kstars.h>
20 #include <KMessageBox>
30 #include <basedevice.h>
36 const double Align::RAMotion = 0.5;
38 const float Align::SIDRATE = 0.004178;
45 currentTelescope = NULL;
46 ccd_hor_pixel = ccd_ver_pixel = focal_length = aperture = -1;
47 decDeviation = azDeviation = altDeviation = 0;
51 connect(solveB, SIGNAL(clicked()),
this, SLOT(
capture()));
52 connect(stopB, SIGNAL(clicked()),
this, SLOT(
stopSolving()));
54 connect(measureAzB, SIGNAL(clicked()),
this, SLOT(
measureAzError()));
56 connect(raBox, SIGNAL(textChanged(
const QString & ) ),
this, SLOT(
checkLineEdits() ) );
57 connect(decBox, SIGNAL(textChanged(
const QString & ) ),
this, SLOT(
checkLineEdits() ) );
60 connect(CCDCaptureCombo, SIGNAL(activated(
int)),
this, SLOT(
checkCCD(
int)));
62 connect(correctAzB, SIGNAL(clicked()),
this, SLOT(
correctAzError()));
64 syncBoxesB->setIcon(KIcon(
"edit-copy"));
65 clearBoxesB->setIcon(KIcon(
"edit-clear"));
67 raBox->setDegType(
false);
73 controlLayout->addWidget(pi, 0, 2, 1, 1);
80 astrometryIndex[2.8] =
"index-4200";
81 astrometryIndex[4.0] =
"index-4201";
82 astrometryIndex[5.6] =
"index-4202";
83 astrometryIndex[8] =
"index-4203";
84 astrometryIndex[11] =
"index-4204";
85 astrometryIndex[16] =
"index-4205";
86 astrometryIndex[22] =
"index-4206";
87 astrometryIndex[30] =
"index-4207";
88 astrometryIndex[42] =
"index-4208";
89 astrometryIndex[60] =
"index-4209";
90 astrometryIndex[85] =
"index-4210";
91 astrometryIndex[120] =
"index-4211";
92 astrometryIndex[170] =
"index-4212";
93 astrometryIndex[240] =
"index-4213";
94 astrometryIndex[340] =
"index-4214";
95 astrometryIndex[480] =
"index-4215";
96 astrometryIndex[680] =
"index-4216";
97 astrometryIndex[1000] =
"index-4217";
98 astrometryIndex[1400] =
"index-4218";
99 astrometryIndex[2000] =
"index-4219";
111 if (ccdNum <= CCDs.count())
112 currentCCD = CCDs.at(ccdNum);
122 CCDs.append(static_cast<ISD::CCD *>(newCCD));
126 CCDCaptureCombo->setCurrentIndex(0);
133 connect(currentTelescope, SIGNAL(numberUpdated(INumberVectorProperty*)),
this, SLOT(
updateScopeCoords(INumberVectorProperty*)));
140 INumberVectorProperty * nvp = currentTelescope->
getBaseDevice()->getNumber(
"TELESCOPE_INFO");
144 INumber *np = IUFindNumber(nvp,
"TELESCOPE_APERTURE");
146 if (np && np->value > 0)
147 aperture = np->value;
150 np = IUFindNumber(nvp,
"GUIDER_APERTURE");
151 if (np && np->value > 0)
152 aperture = np->value;
155 np = IUFindNumber(nvp,
"TELESCOPE_FOCAL_LENGTH");
156 if (np && np->value > 0)
157 focal_length = np->value;
160 np = IUFindNumber(nvp,
"GUIDER_FOCAL_LENGTH");
161 if (np && np->value > 0)
162 focal_length = np->value;
166 if (focal_length == -1 || aperture == -1)
168 controlBox->setEnabled(
false);
169 modeBox->setEnabled(
false);
170 KMessageBox::error(0, i18n(
"Telescope aperture and focal length are missing. Please check your driver settings and try again."));
174 if (ccd_hor_pixel != -1 && ccd_ver_pixel != -1 && focal_length != -1 && aperture != -1)
176 controlBox->setEnabled(
true);
177 modeBox->setEnabled(
true);
182 if (currentCCD && currentTelescope)
185 if (syncR->isEnabled() && (canSync = currentTelescope->
canSync()) ==
false)
187 syncR->setEnabled(
false);
188 slewR->setChecked(
true);
196 INumberVectorProperty * nvp = NULL;
199 if (currentCCD == NULL)
209 INumber *np = IUFindNumber(nvp,
"CCD_PIXEL_SIZE_X");
210 if (np && np->value >0)
211 ccd_hor_pixel = ccd_ver_pixel = np->value;
213 np = IUFindNumber(nvp,
"CCD_PIXEL_SIZE_Y");
214 if (np && np->value >0)
215 ccd_ver_pixel = np->value;
217 np = IUFindNumber(nvp,
"CCD_PIXEL_SIZE_Y");
218 if (np && np->value >0)
219 ccd_ver_pixel = np->value;
224 targetChip->
getFrame(&x,&y,&ccd_width,&ccd_height);
226 if (ccd_hor_pixel == -1 || ccd_ver_pixel == -1)
228 controlBox->setEnabled(
false);
229 modeBox->setEnabled(
false);
230 KMessageBox::error(0, i18n(
"CCD pixel size is missing. Please check your driver settings and try again."));
234 if (ccd_hor_pixel != -1 && ccd_ver_pixel != -1 && focal_length != -1 && aperture != -1)
236 controlBox->setEnabled(
true);
237 modeBox->setEnabled(
true);
241 if (currentCCD && currentTelescope)
247 void Align::calculateFOV()
250 fov_x = 206264.8062470963552 * ccd_width * ccd_hor_pixel / 1000.0 / focal_length;
251 fov_y = 206264.8062470963552 * ccd_height * ccd_ver_pixel / 1000.0 / focal_length;
256 FOVOut->setText(QString(
"%1' x %2'").arg(fov_x, 0,
'g', 3).arg(fov_y, 0,
'g', 3));
262 bool Align::getAstrometryDataDir(QString &dataDir)
266 if (confFile.open(QIODevice::ReadOnly) ==
false)
268 KMessageBox::error(0, i18n(
"Astrometry configuration file corrupted or missing: %1\nPlease set the configuration file full path in INDI options.",
Options::astrometryConfFile()));
274 QStringList confOptions;
275 while ( !in.atEnd() )
277 line = in.readLine();
278 if (line.startsWith(
"#"))
281 confOptions = line.split(
" ");
282 if (confOptions.size() == 2)
284 if (confOptions[0] ==
"add_path")
286 dataDir = confOptions[1];
292 KMessageBox::error(0, i18n(
"Unable to find data dir in astrometry configuration file."));
296 void Align::verifyIndexFiles()
298 static double last_fov_x=0, last_fov_y=0;
300 if (last_fov_x == fov_x && last_fov_y == fov_y)
305 double fov_lower = 0.10 * fov_x;
306 double fov_upper = fov_x;
307 QStringList indexFiles;
308 QString astrometryDataDir;
309 bool indexesOK =
true;
311 if (getAstrometryDataDir(astrometryDataDir) ==
false)
314 QStringList nameFilter(
"*.fits");
315 QDir directory(astrometryDataDir);
316 QStringList indexList = directory.entryList(nameFilter);
317 QString indexSearch = indexList.join(
" ");
318 QString startIndex, lastIndex;
319 unsigned int missingIndexes=0;
321 foreach(
float skymarksize, astrometryIndex.keys())
323 if (skymarksize >= fov_lower && skymarksize <= fov_upper)
325 indexFiles << astrometryIndex.value(skymarksize);
327 if (indexSearch.contains(astrometryIndex.value(skymarksize)) ==
false)
329 if (startIndex.isEmpty())
330 startIndex = astrometryIndex.value(skymarksize);
332 lastIndex = astrometryIndex.value(skymarksize);
342 if (indexesOK ==
false)
344 if (missingIndexes == 1)
345 KMessageBox::information(0, 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",
346 startIndex), i18n(
"Missing index files"),
"ekos_missingindexes");
348 KMessageBox::information(0, 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",
349 startIndex, lastIndex), i18n(
"Missing index files"),
"ekos_missingindexes");
367 double ra=0,dec=0, fov_lower, fov_upper;
368 QString ra_dms, dec_dms;
369 QString fov_low,fov_high;
370 QStringList solver_args;
373 fov_lower = ((fov_x < fov_y) ? (fov_x *0.95) : (fov_y *0.95));
374 fov_upper = ((fov_x > fov_y) ? (fov_x * 1.05) : (fov_y * 1.05));
378 fov_low = QString(
"%1").arg(fov_lower);
379 fov_high = QString(
"%1").arg(fov_upper);
381 getFormattedCoords(ra, dec, ra_dms, dec_dms);
383 solver_args <<
"--no-verify" <<
"--no-plots" <<
"--no-fits2fits" <<
"--resort"
384 <<
"-O" <<
"-L" << fov_low <<
"-H" << fov_high <<
"-u" <<
"aw";
386 if (raBox->isEmpty() ==
false && decBox->isEmpty() ==
false)
388 bool raOk(
false), decOk(
false), radiusOk(
false);
389 dms ra( raBox->createDms(
false, &raOk ) );
390 dms dec( decBox->createDms(
true, &decOk ) );
397 if ( ra.Hours() < 0.0 || ra.Hours() > 24.0 )
398 message = i18n(
"The Right Ascension value must be between 0.0 and 24.0." );
399 if ( dec.Degrees() < -90.0 || dec.Degrees() > 90.0 )
400 message +=
'\n' + i18n(
"The Declination value must be between -90.0 and 90.0." );
401 if ( ! message.isEmpty() )
403 KMessageBox::sorry( 0, message, i18n(
"Invalid Coordinate Data" ) );
408 if (radiusBox->text().isEmpty() ==
false)
409 radius = radiusBox->text().toInt(&radiusOk);
411 if (radiusOk ==
false)
413 KMessageBox::sorry( 0, message, i18n(
"Invalid radius value" ) );
417 solver_args <<
"-3" << QString().setNum(ra.Degrees()) <<
"-4" << QString().setNum(dec.Degrees()) <<
"-5" << QString().setNum(radius);
420 solverOptions->setText(solver_args.join(
" "));
425 bool raOk(
false), decOk(
false);
426 raBox->createDms(
false, &raOk );
427 decBox->createDms(
true, &decOk );
434 raBox->setText(ScopeRAOut->text());
435 decBox->setText(ScopeDecOut->text());
450 if (currentCCD == NULL)
453 double seqExpose = exposureSpin->value();
465 connect(currentCCD, SIGNAL(BLOBUpdated(IBLOB*)),
this, SLOT(
newFITS(IBLOB*)));
471 targetChip->
capture(seqExpose);
475 solveB->setEnabled(
false);
476 stopB->setEnabled(
true);
487 if (!strcmp(bp->name,
"CCD2"))
490 currentCCD->disconnect(
this);
499 QStringList solverArgs;
506 targetCoord.
setRA(ra);
509 QString command =
"solve-field";
511 solverArgs = solverOptions->text().split(
" ");
512 solverArgs <<
"-W" <<
"/tmp/solution.wcs" << filename;
514 connect(&solver, SIGNAL(finished(
int)),
this, SLOT(
solverComplete(
int)));
515 connect(&solver, SIGNAL(readyReadStandardOutput()),
this, SLOT(
logSolver()));
519 solver.start(command, solverArgs);
530 stopB->setEnabled(
false);
531 solveB->setEnabled(
true);
546 int elapsed = (int) round(solverTimer.elapsed()/1000.0);
547 appendLogText(i18np(
"Solver aborted after %1 second.",
"Solver aborted after %1 seconds", elapsed));
556 stopB->setEnabled(
false);
557 solveB->setEnabled(
true);
559 if (exist_status != 0 || access(
"/tmp/solution.wcs", F_OK)==-1)
567 connect(&wcsinfo, SIGNAL(finished(
int)),
this, SLOT(
wcsinfoComplete(
int)));
569 wcsinfo.start(
"wcsinfo", QStringList(
"/tmp/solution.wcs"));
576 wcsinfo.disconnect();
578 if (exist_status != 0)
580 appendLogText(i18n(
"WCS header missing or corrupted. Solver failed."));
586 QString wcsinfo_stdout = wcsinfo.readAllStandardOutput();
588 QStringList wcskeys = wcsinfo_stdout.split(QRegExp(
"[\n]"));
590 QStringList key_value;
592 foreach(QString key, wcskeys)
594 key_value = key.split(
" ");
596 if (key_value.size() > 1)
598 if (key_value[0] ==
"ra_center")
599 alignCoord.
setRA0(key_value[1].toDouble()/15.0);
600 else if (key_value[0] ==
"dec_center")
601 alignCoord.
setDec0(key_value[1].toDouble());
602 else if (key_value[0] ==
"orientation_center")
603 RotOut->setText(key_value[1]);
611 QString ra_dms, dec_dms;
612 getFormattedCoords(alignCoord.
ra().
Hours(), alignCoord.
dec().
Degrees(), ra_dms, dec_dms);
614 SolverRAOut->setText(ra_dms);
615 SolverDecOut->setText(dec_dms);
617 int elapsed = (int) round(solverTimer.elapsed()/1000.0);
618 appendLogText(i18np(
"Solver completed in %1 second.",
"Solver completed in %1 seconds.", elapsed));
623 int fitsLoc = fitsFile.indexOf(
"fits");
624 QString tmpDir = fitsFile.left(fitsLoc);
625 QString tmpFITS = fitsFile.remove(tmpDir);
627 tmpFITS.replace(
".tmp",
"*.*");
630 dir.setNameFilters(QStringList() << tmpFITS);
631 dir.setFilter(QDir::Files);
632 foreach(QString dirFile, dir.entryList())
639 qDebug() << solver.readAll() << endl;
644 logText.insert(0,
i18nc(
"log entry; %1 is the date, %2 is the text",
"%1 %2", QDateTime::currentDateTime().toString(
"yyyy-MM-ddThh:mm:ss"), text));
657 QString ra_dms, dec_dms;
659 if (!strcmp(coord->name,
"EQUATORIAL_EOD_COORD"))
661 getFormattedCoords(coord->np[0].value, coord->np[1].value, ra_dms, dec_dms);
663 telescopeCoord.
setRA(coord->np[0].value);
664 telescopeCoord.
setDec(coord->np[1].value);
666 ScopeRAOut->setText(ra_dms);
667 ScopeDecOut->setText(dec_dms);
677 if (currentTelescope->
isSlewing() ==
false)
685 if (currentTelescope->
isSlewing() ==
false)
687 if(decDeviation > 0){
688 appendLogText(i18n(
"Slew complete. Please adjust your mount's' azimuth knob eastward until the target is in the center of the view."));
691 appendLogText(i18n(
"Slew complete. Please adjust your mount's' azimuth knob westward until the target is in the center of the view."));
709 if (currentTelescope->
isSlewing() ==
false)
717 if (currentTelescope->
isSlewing() ==
false)
719 if(decDeviation > 0){
720 appendLogText(i18n(
"Slew complete. Please lower the altitude knob on your mount until the target is in the center of the view."));
723 appendLogText(i18n(
"Slew complete. Please raise the altitude knob on your mount until the target is in the center of the view."));
735 if (!strcmp(coord->name,
"TELESCOPE_INFO"))
740 void Align::executeMode()
742 if (gotoR->isChecked())
749 void Align::executeGOTO()
751 if (syncR->isChecked())
753 else if (slewR->isChecked())
759 if (currentTelescope->
Sync(&alignCoord))
766 void Align::SlewToTarget()
771 currentTelescope->
Slew(&targetCoord);
778 if (polarR->isChecked())
780 measureAltB->setEnabled(
true);
781 measureAzB->setEnabled(
true);
782 gotoBox->setEnabled(
false);
786 measureAltB->setEnabled(
false);
787 measureAzB->setEnabled(
false);
788 gotoBox->setEnabled(
true);
792 void Align::executePolarAlign()
794 appendLogText(i18n(
"Processing solution for polar alignment..."));
822 static double initRA=0, initDEC=0, finalRA=0, finalDEC=0;
830 if (KMessageBox::warningContinueCancel( 0, hemisphereCombo->currentIndex() == 0
831 ? i18n(
"Point the telescope at the southern meridian. Press continue when ready.")
832 : i18n(
"Point the telescope at the northern meridian. Press continue when ready.")
833 , i18n(
"Polar Alignment Measurement"), KStandardGuiItem::cont(), KStandardGuiItem::cancel(),
834 "ekos_measure_az_error")!=KMessageBox::Continue)
837 appendLogText(i18n(
"Solving first frame near the meridian."));
839 polarR->setChecked(
true);
852 currentTelescope->
Sync(initRA/15.0, initDEC);
853 currentTelescope->
Slew((initRA - RAMotion)/15.0, initDEC);
868 appendLogText(i18n(
"Solving second frame near the meridian."));
870 polarR->setChecked(
true);
879 appendLogText(i18n(
"Calculating azimuth alignment error..."));
885 currentTelescope->
Slew(initRA/15.0, initDEC);
893 calculatePolarError(initRA, initDEC, finalRA, finalDEC);
907 static double initRA=0, initDEC=0, finalRA=0, finalDEC=0;
915 if (KMessageBox::warningContinueCancel( 0, altDirCombo->currentIndex() == 0
916 ? i18n(
"Point the telescope to the east with a minimum altitude of 20 degrees. Press continue when ready.")
917 : i18n(
"Point the telescope to the west with a minimum altitude of 20 degrees. Press continue when ready.")
918 , i18n(
"Polar Alignment Measurement"), KStandardGuiItem::cont(), KStandardGuiItem::cancel(),
919 "ekos_measure_alt_error")!=KMessageBox::Continue)
924 polarR->setChecked(
true);
937 currentTelescope->
Sync(initRA/15.0, initDEC);
938 currentTelescope->
Slew((initRA - RAMotion)/15.0, initDEC);
957 polarR->setChecked(
true);
965 appendLogText(i18n(
"Calculating altitude alignment error..."));
971 currentTelescope->
Slew(initRA/15.0, initDEC);
980 calculatePolarError(initRA, initDEC, finalRA, finalDEC);
992 void Align::calculatePolarError(
double initRA,
double initDEC,
double finalRA,
double finalDEC)
994 double raMotion = finalRA - initRA;
995 decDeviation = finalDEC - initDEC;
998 double RATime = fabs(raMotion / SIDRATE) / 60.0;
1000 qDebug() <<
"initRA " << initRA <<
" initDEC " << initDEC <<
" finalRA " << finalRA <<
" finalDEC " << finalDEC << endl;
1001 qDebug() <<
"decDeviation " << decDeviation*3600 <<
" arcsec " <<
" RATime " << RATime << endl;
1005 double deviation = (3.81 * (decDeviation * 3600) ) / ( RATime * cos(initDEC * dms::DegToRad)) / 60.0;
1007 KLocalizedString deviationDirection;
1009 switch (hemisphereCombo->currentIndex())
1015 if (decDeviation > 0)
1016 deviationDirection = ki18n(
"%1° too far west");
1018 deviationDirection = ki18n(
"%1° too far east");
1022 switch (altDirCombo->currentIndex())
1026 if (decDeviation > 0)
1027 deviationDirection = ki18n(
"%1° too far high");
1029 deviationDirection = ki18n(
"%1° too far low");
1034 if (decDeviation > 0)
1035 deviationDirection = ki18n(
"%1° too far low");
1037 deviationDirection = ki18n(
"%1° too far high");
1050 if (decDeviation > 0)
1051 deviationDirection = ki18n(
"%1° too far east");
1053 deviationDirection = ki18n(
"%1° too far west");
1057 switch (altDirCombo->currentIndex())
1061 if (decDeviation > 0)
1062 deviationDirection = ki18n(
"%1° too far low");
1064 deviationDirection = ki18n(
"%1° too far high");
1069 if (decDeviation > 0)
1070 deviationDirection = ki18n(
"%1° too far high");
1072 deviationDirection = ki18n(
"%1° too far low");
1088 azError->setText(deviationDirection.subs(QString(
"%1").arg(fabs(deviation), 0,
'g', 3)).toString());
1089 azDeviation = deviation * (decDeviation > 0 ? 1 : -1);
1090 correctAzB->setEnabled(
true);
1094 altError->setText(deviationDirection.subs(QString(
"%1").arg(fabs(deviation), 0,
'g', 3)).toString());
1095 altDeviation = deviation * (decDeviation > 0 ? 1 : -1);
1096 correctAltB->setEnabled(
true);
1102 double newRA, newDEC, currentAlt, currentAz;
1104 SkyPoint currentCoord (telescopeCoord);
1112 currentAz = currentCoord.
az().
Degrees();
1114 currentCoord.
setAlt(currentAlt);
1115 currentCoord.
setAz(currentAz);
1119 newRA = currentCoord.
ra().
Hours();
1124 currentTelescope->
Slew(newRA, newDEC);
1126 appendLogText(i18n(
"Slewing to calibration position, please wait until telescope is finished slewing."));
1132 double newRA, newDEC, currentAlt, currentAz;
1134 SkyPoint currentCoord (telescopeCoord);
1139 currentAz = currentCoord.
az().
Degrees() + azDeviation;
1141 currentCoord.
setAlt(currentAlt);
1142 currentCoord.
setAz(currentAz);
1146 newRA = currentCoord.
ra().
Hours();
1151 currentTelescope->
Slew(newRA, newDEC);
1153 appendLogText(i18n(
"Slewing to calibration position, please wait until telescope is finished slewing."));
1157 void Align::getFormattedCoords(
double ra,
double dec, QString &ra_str, QString &dec_str)
1163 ra_str = QString(
"%1:%2:%3").arg(ra_s.
hour(), 2, 10, QChar(
'0')).arg(ra_s.
minute(), 2, 10, QChar(
'0')).arg(ra_s.
second(), 2, 10, QChar(
'0'));
1165 dec_str = QString(
"-%1:%2:%3").arg(abs(dec_s.
degree()), 2, 10, QChar(
'0')).arg(abs(dec_s.
arcmin()), 2, 10, QChar(
'0')).arg(dec_s.
arcsec(), 2, 10, QChar(
'0'));
1167 dec_str = QString(
"%1:%2:%3").arg(dec_s.
degree(), 2, 10, QChar(
'0')).arg(dec_s.
arcmin(), 2, 10, QChar(
'0')).arg(dec_s.
arcsec(), 2, 10, QChar(
'0'));
1172 #include "align.moc"
void checkCCD(int CCDNum)
static QString astrometryConfFile()
Get astrometry.net configuration file.
CCDChip * getChip(CCDChip::ChipType cType)
void apparentCoord(long double jd0, long double jdf)
Computes the apparent coordinates for this SkyPoint for any epoch, accounting for the effects of prec...
void setAz(dms az)
Sets Az, the Azimuth.
const double & Degrees() const
virtual const char * getDeviceName()=0
void setCCD(ISD::GDInterface *newCCD)
static KStars * Instance()
void startSovling(const QString &filename)
static double alignExposure()
Get Default alignment exposure value.
The QProgressIndicator class lets an application display a progress indicator to show that a lengthy ...
bool capture(double exposure)
The sky coordinates of a point in the sky.
bool setFrameType(CCDFrameType fType)
bool Sync(SkyPoint *ScopeTarget)
i18nc("string from libindi, used in the config dialog","100x")
void HorizontalToEquatorial(const dms *LST, const dms *lat)
Determine the (RA, Dec) coordinates of the SkyPoint from its (Altitude, Azimuth) coordinates, given the local sidereal time and the observer's latitude.
void setTelescope(ISD::GDInterface *newTelescope)
An angle, stored as degrees, but expressible in many ways.
bool getFrame(int *x, int *y, int *w, int *h)
void checkPolarAlignment()
void wcsinfoComplete(int exist_status)
void EquatorialToHorizontal(const dms *LST, const dms *lat)
Determine the (Altitude, Azimuth) coordinates of the SkyPoint from its (RA, Dec) coordinates, given the local sidereal time and the observer's latitude.
void updateScopeCoords(INumberVectorProperty *coord)
void setRA0(dms r)
Sets RA0, the catalog Right Ascension.
bool Slew(SkyPoint *ScopeTarget)
static void setAlignExposure(double v)
Set Default alignment exposure value.
void appendLogText(const QString &)
void setCaptureMode(FITSMode mode)
virtual bool isConnected()
virtual INDI::BaseDevice * getBaseDevice()
void setAlt(dms alt)
Sets Alt, the Altitude.
void setRA(dms r)
Sets RA, the current Right Ascension.
void setDec(dms d)
Sets Dec, the current Declination.
void setDec0(dms d)
Sets Dec0, the catalog Declination.
void setD(const double &x)
Sets floating-point value of angle, in degrees.
bool getEqCoords(double *ra, double *dec)
void solverComplete(int exist_status)