diff --git a/Tests/skyobjects/test_skypoint.h b/Tests/skyobjects/test_skypoint.h --- a/Tests/skyobjects/test_skypoint.h +++ b/Tests/skyobjects/test_skypoint.h @@ -24,6 +24,7 @@ #define UNIT_TEST #include "skyobjects/skypoint.h" +#include /** * @class TestSkyPoint @@ -33,14 +34,45 @@ class TestSkyPoint : public QObject { - Q_OBJECT + Q_OBJECT - public: - TestSkyPoint() : QObject(){}; - ~TestSkyPoint() override = default; + public: + TestSkyPoint(); + ~TestSkyPoint() override; - private slots: - void testPrecession(); + private: + void compare(QString msg, double ra1, double dec1, double ra2, double dec2, double err = 0.0001); + void compare(QString msg, SkyPoint * sp); + void compare(QString msg, SkyPoint * sp, SkyPoint * sp1); + void compare(QString msg, SkyPoint * sp, ln_equ_posn * lnp); + void ln_get_equ_nut(ln_equ_posn * posn, double jd, bool reverse = false); + + private slots: + void testPrecession(); + + void compareNovas(); + + void testPrecess_data(); + void testPrecess(); + + void testPrecessFromAnyEpoch_data(); + void testPrecessFromAnyEpoch(); + + void testNutate_data(); + void testNutate(); + + void testAberrate_data(); + void testAberrate(); + + void testApparentCatalogue_data(); + void testApparentCatalogue(); + + void compareSkyPointLibNova_data(); + void compareSkyPointLibNova(); + + private: + bool useRelativistic {false}; }; + #endif diff --git a/Tests/skyobjects/test_skypoint.cpp b/Tests/skyobjects/test_skypoint.cpp --- a/Tests/skyobjects/test_skypoint.cpp +++ b/Tests/skyobjects/test_skypoint.cpp @@ -20,15 +20,32 @@ #include "ksnumbers.h" #include "time/kstarsdatetime.h" #include "auxiliary/dms.h" +#include "Options.h" +//#include +//#include +//#include +//#include +#include + +TestSkyPoint::TestSkyPoint() : QObject() +{ + useRelativistic = Options::useRelativistic(); +} + +TestSkyPoint::~TestSkyPoint() +{ + Options::setUseRelativistic(useRelativistic); +} void TestSkyPoint::testPrecession() { /* * NOTE: These test cases were picked randomly and generated using * https://ned.ipac.caltech.edu/forms/calculator.html */ - auto verify = [](const SkyPoint &p, const double targetRA, const double targetDec, const double tolerance) { + auto verify = [](const SkyPoint & p, const double targetRA, const double targetDec, const double tolerance) + { qDebug() << p.ra().toHMSString() << " " << p.dec().toDMSString(); QVERIFY(fabs(p.ra().Degrees() - targetRA) < tolerance * 15.); QVERIFY(fabs(p.dec().Degrees() - targetDec) < tolerance); @@ -93,4 +110,445 @@ verify(p, 169.71785991, 45.30132855, arcsecPrecision); } +void TestSkyPoint::compareNovas() +{ + Options::setUseRelativistic(false); + + KStarsDateTime kdt = KStarsDateTime::currentDateTimeUtc(); + long double jd = kdt.djd(); + + double lnJd = ln_get_julian_from_sys(); + // compare JD provided by KStarsDateTime and libnova + qDebug() << "KDT JD " << static_cast(jd) << " LN JD " << lnJd << " Diff " << (static_cast + (jd) - lnJd) * 86400 << "secs"; + QVERIFY(fabs(static_cast(jd) - lnJd) * 86400 < 1); + + qDebug() << "Check conversion in Align"; + // the align process is a bit like this: + // Catalogue position + SkyPoint target(4, 20); // ra in hours, dec in degrees + + // transform to JNow in EKOS + // this is wrong because aberration and nutation are handled incorrectly + target.apparentCoord(static_cast(J2000), jd); + double raN = target.ra().Degrees(); + double decN = target.dec().Degrees(); + qDebug() << "SkyPoint J2000 to JNow " << raN << ", " << decN; + + // should be: + // remove aberration + + // remove nutation + + // this is passed to the CCD simulator where it is transformed to J2K using libnova + ln_equ_posn JnowPos { 0, 0 }, J2kPos { 0, 0 }; + JnowPos.ra = raN; + JnowPos.dec = decN; + ln_get_equ_prec2(&JnowPos, lnJd, JD2000, &J2kPos); + double ra0 = J2kPos.ra; + double dec0 = J2kPos.dec; + qDebug() << "Libnova JNow to J2000" << ra0 << ", " << dec0; + + // this is used to generate a star image which is solved + // assume this solve is perfect + + // Align converts this J2000 position back to JNow: + SkyPoint ac(ra0 / 15., dec0); + ac.apparentCoord(static_cast(J2000), jd); + double ran2 = ac.ra().Degrees(); + double decn2 = ac.dec().Degrees(); + qDebug() << "SkyPoint J2000 to JNow" << ran2 << ", " << decn2; + // get the error, this appears as the align error + qDebug() << "Error " << (raN - ran2) * 3600 << ", " << (decN - decn2) * 3600; + + // check the difference + //QVERIFY(fabs(decN - decn2) * 3600. < 1); + //QVERIFY(fabs(raN - ran2) * 3600. < 1); + + qDebug(); + qDebug() << "Using libnova throughout"; + J2kPos.ra = 60; + J2kPos.dec = 20; + // convert to JNow + ln_get_equ_prec2(&J2kPos, JD2000, lnJd, &JnowPos); + qDebug() << "libnova J2000 to JNow " << JnowPos.ra << ", " << JnowPos.dec; + // convert to J2000 + ln_get_equ_prec2(&JnowPos, lnJd, JD2000, &J2kPos); + qDebug() << " libnova JNow to J2000" << J2kPos.ra << ", " << J2kPos.dec; + + // 'solve' + + // convert back to Jnow + ln_equ_posn Jnow2Pos { 0, 0 }; + ln_get_equ_prec2(&J2kPos, JD2000, lnJd, &Jnow2Pos); + qDebug() << "libnova J2000 to JNow " << Jnow2Pos.ra << ", " << Jnow2Pos.dec; + + qDebug() << "Error " << (JnowPos.ra - Jnow2Pos.ra) * 3600 << ", " << (JnowPos.dec - Jnow2Pos.dec) * 3600; + + // Using SkyPoint won't help: + qDebug(); + qDebug() << "using SkyPoint both ways"; + // do the conversion from the previously computed JNow position + SkyPoint ccd; + ccd.setRA(raN / 15.); + ccd.setDec(decN); + KSNumbers num(jd); + ccd.deprecess(&num); + qDebug() << "SkyPoint Jnow to J2000 " << ccd.ra0().Degrees() << ", " << ccd.dec0().Degrees(); + // and to Jnow + ccd.apparentCoord(static_cast(J2000), jd); + qDebug() << "SkyPoint J2000 to JNow " << ccd.ra().Degrees() << ", " << ccd.dec().Degrees(); + + qDebug() << "Error " << (raN - ccd.ra().Degrees()) * 3600 << ", " << (decN - ccd.dec().Degrees()) * 3600; + + //QVERIFY(fabs(p.ra().Degrees() - targetRA) < tolerance * 15.); + //QVERIFY(fabs(p.dec().Degrees() - targetDec) < tolerance); + + //qCDebug(KSTARS_EKOS_ALIGN) << "libnova errors " << + // (epochPos.ra - targetCoord.ra().Degrees()) * 3600. << "as, " << (epochPos.dec - targetCoord.dec().Degrees()) * 3600. << "as"; + + + Options::setUseRelativistic(useRelativistic); +} + +void TestSkyPoint::testPrecess_data() +{ + QTest::addColumn("Ra"); + QTest::addColumn("Dec"); + + QTest::newRow("normal") << 4.0 << 20.0; + QTest::newRow("south") << 15.0 << -35.0; + QTest::newRow("near Pole") << 22.0 << 85.0; + QTest::newRow("near S Pole") << 22.0 << -85.0; +} + +void TestSkyPoint::testPrecess() +{ + auto jd = KStarsDateTime::currentDateTimeUtc().djd(); + KSNumbers now(jd); + SkyPoint sp; + QFETCH(double, Ra); + QFETCH(double, Dec); + + sp = SkyPoint(Ra, Dec); + + sp.precess(&now); + + qDebug() << "precess dRa " << sp.ra0().Degrees() - sp.ra().Degrees() << ", dDec " << sp.dec0().Degrees() - + sp.dec().Degrees(); + + SkyPoint spn = sp.deprecess(&now); + + compare("precess-deprecess ", sp.ra0().Degrees(), sp.dec0().Degrees(), spn.ra().Degrees(), spn.dec().Degrees()); +} + +void TestSkyPoint::testPrecessFromAnyEpoch_data() +{ + QTest::addColumn("Ra"); + QTest::addColumn("Dec"); + + QTest::newRow("normal") << 4.0 << 20.0; + QTest::newRow("south") << 15.0 << -35.0; + QTest::newRow("near Pole") << 22.0 << 85.0; + QTest::newRow("near S Pole") << 22.0 << -85.0; +} + +void TestSkyPoint::testPrecessFromAnyEpoch() +{ + auto jd = KStarsDateTime::currentDateTimeUtc().djd(); + KSNumbers now(jd); + + SkyPoint sp; + QFETCH(double, Ra); + QFETCH(double, Dec); + sp = SkyPoint(Ra, Dec); + + sp.precessFromAnyEpoch(J2000L, jd); + + qDebug() << "PFAE dRa " << sp.ra0().Degrees() - sp.ra().Degrees() << ", dDec " << sp.dec0().Degrees() - sp.dec().Degrees(); + + SkyPoint spn = SkyPoint(sp.ra(), sp.dec()); + spn.precessFromAnyEpoch(jd, J2000L); + + compare("dePFAE ", sp.ra0().Degrees(), sp.dec0().Degrees(), spn.ra().Degrees(), spn.dec().Degrees()); +} + +void TestSkyPoint::testNutate_data() +{ + QTest::addColumn("Ra"); + QTest::addColumn("Dec"); + + QTest::newRow("normal") << 4.0 << 20.0; + QTest::newRow("south") << 15.0 << -35.0; + QTest::newRow("near Pole") << 22.0 << 85.0; + QTest::newRow("near S Pole") << 22.0 << -85.0; +} + +void TestSkyPoint::testNutate() +{ + long double jd = KStarsDateTime::currentDateTimeUtc().djd(); + KSNumbers now(jd); + + SkyPoint sp; + QFETCH(double, Ra); + QFETCH(double, Dec); + sp = SkyPoint(Ra, Dec); + + sp.nutate(&now); + + qDebug() << "nutate dRa " << sp.ra0().Degrees() - sp.ra().Degrees() << ", dDec " << sp.dec0().Degrees() - + sp.dec().Degrees(); + + sp.nutate(&now, true); + + compare("nutate-denutate", &sp); +} + +void TestSkyPoint::testAberrate_data() +{ + QTest::addColumn("Ra"); + QTest::addColumn("Dec"); + + QTest::newRow("normal") << 4.0 << 20.0; + QTest::newRow("south") << 15.0 << -35.0; + QTest::newRow("near Pole") << 22.0 << 85.0; + QTest::newRow("near S Pole") << 22.0 << -85.0; +} + +void TestSkyPoint::testAberrate() +{ + long double jd = KStarsDateTime::epochToJd(2028.3); + KSNumbers now(jd); + + SkyPoint sp; + QFETCH(double, Ra); + QFETCH(double, Dec); + sp = SkyPoint(Ra, Dec); + + sp.aberrate(&now); + + // deaberrate + sp.aberrate(&now, true); + + compare("aberrate-deaberrate", &sp); +} + +// test results obtained using the ASCOM Transform component +// to convert from J2000 to Apparent +// this uses SOFA so should be fairly good +void TestSkyPoint::testApparentCatalogue_data() +{ + QTest::addColumn("Ra"); + QTest::addColumn("Dec"); + QTest::addColumn("RaOut"); + QTest::addColumn("DecOut"); + + QTest::newRow("Apparent") << 4.0 << 20.0 << 4.0274 << 20.0791; + QTest::newRow("south") << 10.0 << -35.0 << 10.0208 << -35.1418; + QTest::newRow("south") << 10.0 << -55.0 << 10.01698 << -55.14256; + QTest::newRow("near Pole") << 22.0 << 85.0 << 21.9601 << 85.1317; + QTest::newRow("near S Pole") << 15.0 << -85.0 << 15.1159 << -85.1112; +} + +void TestSkyPoint::testApparentCatalogue() +{ + Options::setUseRelativistic(false); + + //long double jd = KStarsDateTime::currentDateTimeUtc().djd(); + auto dt = KStarsDateTime::fromString("2028-04-27T06:30"); + long double jd = dt.djd(); + + double rjd = static_cast(jd - J2000L); + //qDebug() << "DT " << dt.toString() << " JD " << static_cast(jd) << " RJD " << rjd; + + QVERIFY(fabs(rjd - 10343.771) < 0.1); + + SkyPoint sp; + QFETCH(double, Ra); + QFETCH(double, Dec); + sp = SkyPoint(Ra, Dec); + + // J2000 catalogue to Apparent + sp.apparentCoord(J2000L, jd); + // qDebug() << "apparent ra0 " << sp.ra0().Hours() << ", dec0 " << sp.dec0().Degrees() << + // " ra " << sp.ra().Hours() << ", dec " << sp.dec().Degrees(); + QFETCH(double, RaOut); + QFETCH(double, DecOut); + + // error relaxed as we are comparing with an extermal catalogue - suspicous! + compare("J2000 to aparrent", RaOut, DecOut, sp.ra().Hours(), sp.dec().Degrees(), 0.0015); + + SkyPoint spn = SkyPoint(sp.ra(), sp.dec()); + qDebug() << "spn ra0 " << spn.ra0().Degrees() << ", dec0 " << spn.dec0().Degrees() << + " ra " << spn.ra().Degrees() << ", dec " << spn.dec().Degrees(); + + // apparent on jd to J2000Catalogue + spn.catalogueCoord(jd); + + compare("J2K to app to catalogue", sp.ra0().Degrees(), sp.dec0().Degrees(), spn.ra0().Degrees(), spn.dec0().Degrees()); +} + +void TestSkyPoint::compareSkyPointLibNova_data() +{ + QTest::addColumn("Ra"); + QTest::addColumn("Dec"); + QTest::addColumn("RaOut"); + QTest::addColumn("DecOut"); + + QTest::newRow("Apparent") << 4.0 << 20.0 << 4.0274 << 20.0791; + QTest::newRow("south") << 10.0 << -35.0 << 10.0208 << -35.1418; + QTest::newRow("south") << 10.0 << -55.0 << 10.01698 << -55.14256; + QTest::newRow("near Pole") << 22.0 << 85.0 << 21.9601 << 85.1317; + QTest::newRow("near S Pole") << 15.0 << -85.0 << 15.1159 << -85.1112; +} +void TestSkyPoint::compareSkyPointLibNova() +{ + // skypoint JD + auto dt = KStarsDateTime::fromString("2028-04-27T06:30"); + long double ljd = dt.djd(); + double jd = static_cast(ljd); + + SkyPoint sp; + QFETCH(double, Ra); + QFETCH(double, Dec); + sp = SkyPoint(Ra, Dec); + ln_equ_posn LnPos { Ra * 15.0, Dec }, observed { 0, 0 }, J2000Pos { 0, 0 }; + + ln_equ_posn tempPosn; + + KSNumbers num(ljd); + + // apply precession from J2000 to jd + ln_get_equ_prec2(&LnPos, JD2000, jd, &tempPosn); + SkyPoint spp = sp; + spp.precessFromAnyEpoch(J2000L, ljd); + compare("precess", spp.ra().Degrees(), spp.dec().Degrees(), tempPosn.ra, tempPosn.dec); + + // apply nutation (needs new function) + ln_get_equ_nut(&tempPosn, jd); + SkyPoint spn = spp; + spn.nutate(&num); + compare("nutate", spn.ra().Degrees(), spn.dec().Degrees(), tempPosn.ra, tempPosn.dec); + + // apply aberration + ln_get_equ_aber(&tempPosn, jd, &observed); + SkyPoint spa = spn; + spa.aberrate(&num); + compare("aberrate", spa.ra().Degrees(), spa.dec().Degrees(), observed.ra, observed.dec); + + sp.apparentCoord(J2000L, ljd); + + // compare sp and observed with each other + compare("sp and LN ", sp.ra().Degrees(), sp.dec().Degrees(), observed.ra, observed.dec); + QFETCH(double, RaOut); + QFETCH(double, DecOut); + // compare sp with expected, use degrees + compare("sp expected ", RaOut * 15., DecOut, sp.ra().Degrees(), sp.Dec.Degrees(), 0.0005); + // compare ln with expected + compare("ln expected ", RaOut * 15, DecOut, observed.ra, observed.dec, 0.0005); + + // now to J2000 + + // remove the aberration + ln_get_equ_aber(&observed, jd, &tempPosn); + // this conversion has added the aberration, we want to subtract it + tempPosn.ra = observed.ra - (tempPosn.ra - observed.ra); + tempPosn.dec = observed.dec * 2 - tempPosn.dec; + //sp.aberrate(&num, true); + + + // remove the nutation + ln_get_equ_nut(&tempPosn, jd, true); + + //sp.nutate(&num, true); + + // precess from now to J2000 + ln_get_equ_prec2(&tempPosn, jd, JD2000, &J2000Pos); + + // the start position needs to be in RA0,Dec0 + //sp.RA0 = sp.RA; + //sp.Dec0 = sp.Dec; + // from now to J2000 + //sp.precessFromAnyEpoch(jd, J2000L); + // the J2000 position is in RA,Dec, move to RA0, Dec0 + //sp.RA0 = sp.RA; + //sp.Dec0 = sp.Dec; + //sp.lastPrecessJD = J2000; + + sp.catalogueCoord(ljd); + + //compare sp and the j2000Pos with each other and the original + compare("Round trip ", &sp, &J2000Pos); + compare("original", Ra, Dec, sp.RA0.Hours(), sp.Dec0.Degrees()); +} + +void TestSkyPoint::compare(QString msg, SkyPoint *sp, SkyPoint *sp1) +{ + compare(msg, sp->ra0().Degrees(), sp->dec0().Degrees(), sp1->ra().Degrees(), sp1->dec().Degrees()); +} + +void TestSkyPoint::compare(QString msg, SkyPoint *sp, ln_equ_posn *lnp) +{ + compare(msg, sp->ra0().Degrees(), sp->dec0().Degrees(), lnp->ra, lnp->dec); +} + +void TestSkyPoint::compare(QString msg, SkyPoint *sp) +{ + compare(msg, sp->ra0().Degrees(), sp->dec0().Degrees(), sp->ra().Degrees(), sp->dec().Degrees()); +} + +void TestSkyPoint::compare(QString msg, double ra1, double dec1, double ra2, double dec2, double err) +{ + qDebug(qPrintable(QString("%1 pos1 %2, %3 pos2 %4, %5 errors %6, %7 secs").arg(msg) + .arg(ra1).arg(dec1).arg(ra2).arg(dec2) + .arg((ra1 - ra2) * 3600.0, 6, 'f', 1).arg((dec1 - dec2) * 3600., 6, 'f', 1))); + //QString str; + //str.sprintf("%s pos1 %f, %f pos2 %f, %f errors %.1f, %.1f sec", msg.data(), ra1, dec1, ra2, dec2, (ra1 - ra2) *3600, (dec1 - dec2) * 3600 ); + //qDebug() << str;// << msg << "SP " << ra1 << ", " << dec1 << " Sp0 " << ra2 << ", " << dec2 + //<< " errors " << ((ra1 - ra2) * 3600) << ", " << ((dec1 - dec2) * 3600) << " arcsec"; + + double errRa = err / cos(dec1 * M_PI / 180.0); + + QVERIFY2(fabs(ra1 - ra2) < errRa, qPrintable(QString("Ra %1, %2 error %3").arg(ra1).arg(ra2).arg(((ra1 - ra2) * 3600.0), 6, + 'f', 1))); + QVERIFY2(fabs(dec1 - dec2) < err, qPrintable(QString("Dec %1, %2 error %3").arg(dec1).arg(dec2).arg((dec1 - dec2) * 3600., + 6, 'f', 1))); +} + +// apply or remove nutation +void TestSkyPoint::ln_get_equ_nut(ln_equ_posn *posn, double jd, bool reverse) +{ + // code lifted from libnova ln_get_equ_nut + // with the option to add or remove nutation + struct ln_nutation nut; + ln_get_nutation (jd, &nut); + + double mean_ra, mean_dec, delta_ra, delta_dec; + + mean_ra = ln_deg_to_rad(posn->ra); + mean_dec = ln_deg_to_rad(posn->dec); + + // Equ 22.1 + + double nut_ecliptic = ln_deg_to_rad(nut.ecliptic + nut.obliquity); + double sin_ecliptic = sin(nut_ecliptic); + + double sin_ra = sin(mean_ra); + double cos_ra = cos(mean_ra); + + double tan_dec = tan(mean_dec); + + delta_ra = (cos (nut_ecliptic) + sin_ecliptic * sin_ra * tan_dec) * nut.longitude - cos_ra * tan_dec * nut.obliquity; + delta_dec = (sin_ecliptic * cos_ra) * nut.longitude + sin_ra * nut.obliquity; + + // the sign changed to remove nutation + if (reverse) + { + delta_ra = -delta_ra; + delta_dec = -delta_dec; + } + posn->ra += delta_ra; + posn->dec += delta_dec; +} + QTEST_GUILESS_MAIN(TestSkyPoint) diff --git a/kstars/dialogs/focusdialog.cpp b/kstars/dialogs/focusdialog.cpp --- a/kstars/dialogs/focusdialog.cpp +++ b/kstars/dialogs/focusdialog.cpp @@ -81,7 +81,8 @@ if (center) { - center->deprecess(KStarsData::Instance()->updateNum()); + //center->deprecess(KStarsData::Instance()->updateNum()); + center->catalogueCoord(KStarsData::Instance()->updateNum()->julianDay()); fd->raBox->setDMS(center->ra().toHMSString()); fd->decBox->setDMS(center->dec().toDMSString()); @@ -152,7 +153,8 @@ { Point->setRA(ra); Point->setDec(dec); - Point->deprecess(KStarsData::Instance()->updateNum()); + //Point->deprecess(KStarsData::Instance()->updateNum()); + Point->catalogueCoord(KStarsData::Instance()->updateNum()->julianDay()); } else { diff --git a/kstars/ekos/mount/mount.cpp b/kstars/ekos/mount/mount.cpp --- a/kstars/ekos/mount/mount.cpp +++ b/kstars/ekos/mount/mount.cpp @@ -516,7 +516,7 @@ if (currentTelescope->isJ2000() == false) { SkyPoint J2000Coord(telescopeCoord.ra(), telescopeCoord.dec()); - J2000Coord.apparentCoord(KStars::Instance()->data()->ut().djd(), static_cast(J2000)); + J2000Coord.catalogueCoord(KStars::Instance()->data()->ut().djd()); //J2000Coord.precessFromAnyEpoch(KStars::Instance()->data()->ut().djd(), static_cast(J2000)); telescopeCoord.setRA0(J2000Coord.ra()); telescopeCoord.setDec0(J2000Coord.dec()); diff --git a/kstars/ekos/scheduler/scheduler.cpp b/kstars/ekos/scheduler/scheduler.cpp --- a/kstars/ekos/scheduler/scheduler.cpp +++ b/kstars/ekos/scheduler/scheduler.cpp @@ -225,7 +225,8 @@ connect(copySkyCenterB, &QPushButton::clicked, this, [this]() { SkyPoint center = SkyMap::Instance()->getCenterPoint(); - center.deprecess(KStarsData::Instance()->updateNum()); + //center.deprecess(KStarsData::Instance()->updateNum()); + center.catalogueCoord(KStarsData::Instance()->updateNum()->julianDay()); raBox->setDMS(center.ra0().toHMSString()); decBox->setDMS(center.dec0().toDMSString()); }); diff --git a/kstars/hips/hipsrenderer.cpp b/kstars/hips/hipsrenderer.cpp --- a/kstars/hips/hipsrenderer.cpp +++ b/kstars/hips/hipsrenderer.cpp @@ -58,7 +58,8 @@ m_size = 0; SkyPoint center = SkyMap::Instance()->getCenterPoint(); - center.deprecess(KStarsData::Instance()->updateNum()); + //center.deprecess(KStarsData::Instance()->updateNum()); + center.catalogueCoord(KStarsData::Instance()->updateNum()->julianDay()); double ra = center.ra0().radians(); double de = center.dec0().radians(); diff --git a/kstars/indi/inditelescope.cpp b/kstars/indi/inditelescope.cpp --- a/kstars/indi/inditelescope.cpp +++ b/kstars/indi/inditelescope.cpp @@ -573,7 +573,7 @@ case INDI_FIND_TELESCOPE: { SkyPoint J2000Coord(currentCoord.ra(), currentCoord.dec()); - J2000Coord.apparentCoord(KStars::Instance()->data()->ut().djd(), static_cast(J2000)); + J2000Coord.catalogueCoord(KStars::Instance()->data()->ut().djd()); currentCoord.setRA0(J2000Coord.ra()); currentCoord.setDec0(J2000Coord.dec()); double maxrad = 1000.0 / Options::zoomFactor(); @@ -590,7 +590,7 @@ currentCoord.angularDistanceTo(KStars::Instance()->map()->focus()).Degrees() > 0.5) { SkyPoint J2000Coord(currentCoord.ra(), currentCoord.dec()); - J2000Coord.apparentCoord(KStars::Instance()->data()->ut().djd(), static_cast(J2000)); + J2000Coord.catalogueCoord(KStars::Instance()->data()->ut().djd()); currentCoord.setRA0(J2000Coord.ra()); currentCoord.setDec0(J2000Coord.dec()); //KStars::Instance()->map()->setClickedPoint(¤tCoord); @@ -768,7 +768,7 @@ { ScopeTarget->setRA0(ScopeTarget->ra()); ScopeTarget->setDec0(ScopeTarget->dec()); - ScopeTarget->apparentCoord( KStars::Instance()->data()->ut().djd(), static_cast(J2000)); + ScopeTarget->catalogueCoord( KStars::Instance()->data()->ut().djd()); ra = ScopeTarget->ra(); de = ScopeTarget->dec(); } diff --git a/kstars/kstarsactions.cpp b/kstars/kstarsactions.cpp --- a/kstars/kstarsactions.cpp +++ b/kstars/kstarsactions.cpp @@ -1895,7 +1895,8 @@ if (Options::showJ2000RADecField()) { SkyPoint p0; - p0 = p->deprecess(KStarsData::Instance()->updateNum()); // deprecess to update RA0/Dec0 from RA/Dec + //p0 = p->deprecess(KStarsData::Instance()->updateNum()); // deprecess to update RA0/Dec0 from RA/Dec + p0 = p->catalogueCoord(KStarsData::Instance()->updateNum()->julianDay()); QString s = QString("%1, %2 (J2000)") .arg(p0.ra().toHMSString(), p0.dec().toDMSString(true)); //true: force +/- symbol diff --git a/kstars/skycomponents/flagcomponent.cpp b/kstars/skycomponents/flagcomponent.cpp --- a/kstars/skycomponents/flagcomponent.cpp +++ b/kstars/skycomponents/flagcomponent.cpp @@ -358,7 +358,7 @@ if (dt.djd() == J2000) return; - p->apparentCoord(dt.djd(), J2000); + p->catalogueCoord(dt.djd()); // Store J2000 coords in RA0, DEC0 p->setRA0(p->ra()); diff --git a/kstars/skycomponents/skymesh.cpp b/kstars/skycomponents/skymesh.cpp --- a/kstars/skycomponents/skymesh.cpp +++ b/kstars/skycomponents/skymesh.cpp @@ -68,7 +68,7 @@ // FIXME: simple copying leads to incorrect results because RA0 && dec0 are both zero sometimes SkyPoint p1(p0->ra(), p0->dec()); long double now = data->updateNum()->julianDay(); - p1.apparentCoord(now, J2000); + p1.catalogueCoord(now); if (radius == 1.0) { diff --git a/kstars/skymap.cpp b/kstars/skymap.cpp --- a/kstars/skymap.cpp +++ b/kstars/skymap.cpp @@ -463,7 +463,8 @@ } else { - SkyPoint deprecessedPoint = clickedPoint()->deprecess(data->updateNum()); + //SkyPoint deprecessedPoint = clickedPoint()->deprecess(data->updateNum()); + SkyPoint deprecessedPoint = clickedPoint()->catalogueCoord(data->updateNum()->julianDay()); ra = deprecessedPoint.ra(); dec = deprecessedPoint.dec(); urlstring = KSDssDownloader::getDSSURL(ra, dec); // Use default size for non-objects @@ -495,7 +496,9 @@ } else { - SkyPoint deprecessedPoint = clickedPoint()->deprecess(data->updateNum()); + //SkyPoint deprecessedPoint = clickedPoint()->deprecess(data->updateNum()); + SkyPoint deprecessedPoint = clickedPoint()->catalogueCoord(data->updateNum()->julianDay()); + deprecessedPoint.catalogueCoord(data->updateNum()->julianDay()); deprecessedPoint.EquatorialToHorizontal(data->lst(), data->geo()->lat()); J2000RA = deprecessedPoint.ra0(); @@ -535,7 +538,9 @@ } else { - SkyPoint deprecessedPoint = clickedPoint()->deprecess(data->updateNum()); + //SkyPoint deprecessedPoint = clickedPoint()->deprecess(data->updateNum()); + SkyPoint deprecessedPoint = clickedPoint()->catalogueCoord(data->updateNum()->julianDay()); + deprecessedPoint.catalogueCoord(data->updateNum()->julianDay()); ra = deprecessedPoint.ra(); dec = deprecessedPoint.dec(); } @@ -729,7 +734,9 @@ } else { - SkyPoint deprecessedPoint = clickedPoint()->deprecess(data->updateNum()); + //SkyPoint deprecessedPoint = clickedPoint()->deprecess(data->updateNum()); + SkyPoint deprecessedPoint = clickedPoint()->catalogueCoord(data->updateNum()->julianDay()); + deprecessedPoint.catalogueCoord(data->updateNum()->julianDay()); J2000RA = deprecessedPoint.ra(); J2000DE = deprecessedPoint.dec(); } diff --git a/kstars/skyobjects/jupitermoons.cpp b/kstars/skyobjects/jupitermoons.cpp --- a/kstars/skyobjects/jupitermoons.cpp +++ b/kstars/skyobjects/jupitermoons.cpp @@ -330,8 +330,9 @@ Moon[i]->setRA(Jupiter->ra().Hours() - 0.011 * (XP[i] * cos(pa) - YP[i] * sin(pa)) / 15.0); Moon[i]->setDec(Jupiter->dec().Degrees() - 0.011 * (XP[i] * sin(pa) + YP[i] * cos(pa))); - SkyPoint p = Moon[i]->deprecess( - num); // FIXME: Really, we should also denutate. Actually, we should also be aberrating these above, right? + //SkyPoint p = Moon[i]->deprecess( + // num); // FIXME: Really, we should also denutate. Actually, we should also be aberrating these above, right? + SkyPoint p = Moon[i]->catalogueCoord(num->julianDay()); Moon[i]->setRA0( p.ra()); // Just to be sure, in case deprecess doesn't set it already because RA0 was not NaN or something. Moon[i]->setDec0(p.dec()); diff --git a/kstars/skyobjects/skypoint.h b/kstars/skyobjects/skypoint.h --- a/kstars/skyobjects/skypoint.h +++ b/kstars/skyobjects/skypoint.h @@ -19,8 +19,13 @@ #pragma once +#define USE_LIBNOVA + #include "cachingdms.h" #include "kstarsdatetime.h" +#ifdef USE_LIBNOVA +#include +#endif #include #ifndef KSTARS_LITE @@ -318,12 +323,26 @@ void apparentCoord(long double jd0, long double jdf); /** - * Determine the effects of nutation for this SkyPoint. + * Computes the J2000.0 catalogue coordinates for this SkyPoint using the epoch + * removing aberration, nutation and precession + * Catalogue coordinates are in Ra0, Dec0 + * + * @brief catalogueCoord converts observed to J2000 using epoch jdf + * @param jdf Julian Day which identifies the current epoch + * @return SpyPoint containing J2000 coordinates + */ + + SkyPoint catalogueCoord(long double jdf); + + + /** + * Apply the effects of nutation to this SkyPoint. * * @param num pointer to KSNumbers object containing current values of * time-dependent variables. + * @param reverse bool, if true the nutation is removed */ - void nutate(const KSNumbers *num); + void nutate(const KSNumbers *num, const bool reverse = false); /** * @short Check if this sky point is close enough to the sun for @@ -355,8 +374,9 @@ * * @param num pointer to KSNumbers object containing current values of * time-dependent variables. + * @param reverse bool, if true the aberration is removed. */ - void aberrate(const KSNumbers *num); + void aberrate(const KSNumbers *num, bool reverse = false); /** * General case of precession. It precess from an original epoch to a @@ -648,7 +668,12 @@ dms Alt, Az; static KSSun *m_Sun; - protected: + + // long version of these epochs +#define J2000L 2451545.0L //Julian Date for noon on Jan 1, 2000 (epoch J2000) +#define B1950L 2433282.4235L // Julian date for Jan 0.9235, 1950 + +protected: double lastPrecessJD { 0 }; // JD at which the last coordinate (see updateCoords) for this SkyPoint was done }; diff --git a/kstars/skyobjects/skypoint.cpp b/kstars/skyobjects/skypoint.cpp --- a/kstars/skyobjects/skypoint.cpp +++ b/kstars/skyobjects/skypoint.cpp @@ -251,17 +251,50 @@ (!std::isnan(Dec0.Degrees()) && fabs(Dec0.Degrees()) > 90.0)) { // We have invalid RA0 and Dec0, so set them if epoch = J2000. Otherwise, do not touch. - if (epoch == J2000) + if (epoch == J2000L) { RA0 = p1.ra(); Dec0 = p1.dec(); } } return p1; } -void SkyPoint::nutate(const KSNumbers *num) +void SkyPoint::nutate(const KSNumbers *num, const bool reverse) { +#ifdef USE_LIBNOVA + // code lifted from libnova ln_get_equ_nut + // with the option to add or remove nutation + struct ln_nutation nut; + ln_get_nutation (num->julianDay(), &nut); + + double mean_ra, mean_dec, delta_ra, delta_dec; + + mean_ra = RA.radians(); + mean_dec = Dec.radians(); + + // Equ 22.1 + + double nut_ecliptic = ln_deg_to_rad(nut.ecliptic + nut.obliquity); + double sin_ecliptic = sin(nut_ecliptic); + + double sin_ra = sin(mean_ra); + double cos_ra = cos(mean_ra); + + double tan_dec = tan(mean_dec); + + delta_ra = (cos (nut_ecliptic) + sin_ecliptic * sin_ra * tan_dec) * nut.longitude - cos_ra * tan_dec * nut.obliquity; + delta_dec = (sin_ecliptic * cos_ra) * nut.longitude + sin_ra * nut.obliquity; + + // the sign changed to remove nutation + if (reverse) + { + delta_ra = -delta_ra; + delta_dec = -delta_dec; + } + RA.setD(RA.Degrees() + delta_ra); + Dec.setD(Dec.Degrees() + delta_dec); +#else double cosRA, sinRA, cosDec, sinDec, tanDec; double cosOb, sinOb; @@ -278,18 +311,34 @@ double dRA = num->dEcLong() * (cosOb + sinOb * sinRA * tanDec) - num->dObliq() * cosRA * tanDec; double dDec = num->dEcLong() * (sinOb * cosRA) + num->dObliq() * sinRA; + if (reverse) + { + dRA = -dRA; + dDec = -dDec; + } RA.setD(RA.Degrees() + dRA); Dec.setD(Dec.Degrees() + dDec); } else //exact method { + // TODO apply reverse test above 80 degrees dms EcLong, EcLat; findEcliptic(num->obliquity(), EcLong, EcLat); - //Add dEcLong to the Ecliptic Longitude - dms newLong(EcLong.Degrees() + num->dEcLong()); - setFromEcliptic(num->obliquity(), newLong, EcLat); + if (reverse) + { + //Subtract dEcLong from the Ecliptic Longitude + dms newLong(EcLong.Degrees() - num->dEcLong()); + setFromEcliptic(num->obliquity(), newLong, EcLat); + } + else + { + //Add dEcLong to the Ecliptic Longitude + dms newLong(EcLong.Degrees() + num->dEcLong()); + setFromEcliptic(num->obliquity(), newLong, EcLat); + } } +#endif } SkyPoint SkyPoint::moveAway(const SkyPoint &from, double dist) const @@ -375,8 +424,24 @@ return true; } -void SkyPoint::aberrate(const KSNumbers *num) +void SkyPoint::aberrate(const KSNumbers *num, bool reverse) { +#ifdef USE_LIBNOVA + ln_equ_posn pos { RA.Degrees(), Dec.Degrees() }; + ln_equ_posn abPos { 0, 0 }; + ln_get_equ_aber(&pos, num->julianDay(),&abPos); + if (reverse) + { + RA.setD(RA.Degrees() * 2 - abPos.ra); + Dec.setD(Dec.Degrees() * 2 - abPos.dec); + } + else + { + RA.setD(abPos.ra); + Dec.setD(abPos.dec); + } + +#else double cosRA, sinRA, cosDec, sinDec; double cosOb, sinOb, cosL, sinL, cosP, sinP; @@ -403,8 +468,14 @@ double dDec = K * (sinRA * (sinOb * cosDec - cosOb * sinDec) * (e * cosP - cosL) + cosRA * sinDec * (e * sinP - sinL)); + if (reverse) + { + dRA = -dRA; + dDec = -dDec; + } RA.setD(RA.Degrees() + dRA); Dec.setD(Dec.Degrees() + dDec); +#endif } // Note: This method is one of the major rate determining factors in how fast the map pans / zooms in or out @@ -465,19 +536,19 @@ RA.SinCos(sinRA, cosRA); Dec.SinCos(sinDec, cosDec); - if (jd0 == B1950) + if (jd0 == B1950L) { B1950ToJ2000(); - jd0 = J2000; + jd0 = J2000L; RA.SinCos(sinRA, cosRA); Dec.SinCos(sinDec, cosDec); } if (jd0 != jdf) { // The original coordinate is referred to the FK5 system and // is NOT J2000. - if (jd0 != J2000) + if (jd0 != J2000L) { //v is a column vector representing input coordinates. v[0] = cosRA * cosDec; @@ -502,7 +573,7 @@ s[2] = sinDec; } - if (jdf == B1950) + if (jdf == B1950L) { RA.setRadians(atan2(s[1], s[0])); Dec.setRadians(asin(s[2])); @@ -536,6 +607,31 @@ aberrate(&num); } +SkyPoint SkyPoint::catalogueCoord(long double jdf) +{ + KSNumbers num(jdf); + + // remove abberation + aberrate(&num, true); + + // remove nutation + nutate(&num, true); + + // remove precession + // the start position needs to be in RA0,Dec0 + RA0 = RA; + Dec0 = Dec; + // from now to J2000 + precessFromAnyEpoch(jdf, static_cast(J2000)); + // the J2000 position is in RA,Dec, move to RA0, Dec0 + RA0 = RA; + Dec0 = Dec; + lastPrecessJD = J2000; + + SkyPoint sp(RA0, Dec0); + return sp; +} + void SkyPoint::Equatorial1950ToGalactic(dms &galLong, dms &galLat) { double a = 192.25; @@ -581,7 +677,7 @@ double v[3], s[3]; // 1984 January 1 0h - KSNumbers num(2445700.5); + KSNumbers num(2445700.5L); // Eterms due to aberration addEterms(); @@ -627,7 +723,7 @@ double v[3], s[3]; // 1984 January 1 0h - KSNumbers num(2445700.5); + KSNumbers num(2445700.5L); RA.SinCos(sinRA, cosRA); Dec.SinCos(sinDec, cosDec); @@ -757,7 +853,7 @@ SkyPoint aux; aux.set(RA0, Dec0); - aux.precessFromAnyEpoch(jd0, J2000); + aux.precessFromAnyEpoch(jd0, J2000L); aux.ra().SinCos(sinRA, cosRA); aux.dec().SinCos(sinDec, cosDec); @@ -803,7 +899,7 @@ SkyPoint aux(RA0, Dec0); - aux.precessFromAnyEpoch(jd0, J2000); + aux.precessFromAnyEpoch(jd0, J2000L); aux.ra().SinCos(sinRA, cosRA); aux.dec().SinCos(sinDec, cosDec); diff --git a/kstars/tools/altvstime.cpp b/kstars/tools/altvstime.cpp --- a/kstars/tools/altvstime.cpp +++ b/kstars/tools/altvstime.cpp @@ -303,7 +303,8 @@ if (jd != J2000) { SkyPoint ptest(newRA, newDec); - ptest.precessFromAnyEpoch(jd, J2000); + //ptest.precessFromAnyEpoch(jd, J2000); + ptest.catalogueCoord(jd); newRA.setH(ptest.ra().Hours()); newDec.setD(ptest.dec().Degrees()); } diff --git a/kstars/tools/starhopper.cpp b/kstars/tools/starhopper.cpp --- a/kstars/tools/starhopper.cpp +++ b/kstars/tools/starhopper.cpp @@ -154,7 +154,8 @@ // needs a lot of fixing to handle unprecessed and precessed, // equatorial and horizontal coordinates nicely SkyPoint *CurrentNode = const_cast(curr_node); - CurrentNode->deprecess(KStarsData::Instance()->updateNum()); + //CurrentNode->deprecess(KStarsData::Instance()->updateNum()); + CurrentNode->catalogueCoord(KStarsData::Instance()->updateNum()->julianDay()); //qCDebug(KSTARS) << "Calling starsInAperture"; StarComponent::Instance()->starsInAperture(neighbors, *curr_node, fov, maglim); qCDebug(KSTARS) << "Choosing next node from a set of " << neighbors.count();