File indexing completed on 2024-05-05 15:57:12

0001 /*
0002     SPDX-FileCopyrightText: 2018 Valentin Boettcher <valentin@boettcher.cf>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "lunareclipsehandler.h"
0008 #include "skymapcomposite.h"
0009 #include "solarsystemcomposite.h"
0010 #include "dms.h"
0011 
0012 LunarEclipseHandler::LunarEclipseHandler(QObject * parent) : EclipseHandler(parent),
0013     m_sun(), m_moon(), m_shadow(&m_moon, &m_sun, &m_Earth)
0014 {
0015 }
0016 
0017 EclipseHandler::EclipseVector LunarEclipseHandler::computeEclipses(long double startJD, long double endJD)
0018 {
0019     m_mode = CLOSEST_APPROACH;
0020 
0021     const long double SEARCH_INTERVAL = 5.l; // Days
0022 
0023     QVector<EclipseEvent_s> eclipses;
0024     QVector<long double> fullMoons = getFullMoons(startJD, endJD);
0025 
0026     int total = fullMoons.length();
0027     if (total == 0)
0028         return eclipses;
0029 
0030     float step = 1 / total;
0031     float progress = 0;
0032 
0033     connect(this, &ApproachSolver::solverMadeProgress, this, [ &, this] (int dProgress)
0034     {
0035         float tmpProgress = roundf(progress + step * dProgress);
0036         if (tmpProgress > progress)
0037         {
0038             progress = tmpProgress;
0039             emit signalProgress(static_cast<int>(progress));
0040         }
0041     });
0042 
0043     for(auto date : fullMoons)
0044     {
0045         findClosestApproach(date, date + SEARCH_INTERVAL, [&eclipses, this] (long double JD, dms)
0046         {
0047             EclipseEvent::ECLIPSE_TYPE type;
0048             updatePositions(JD);
0049 
0050             KSEarthShadow::ECLIPSE_TYPE extended_type = m_shadow.getEclipseType();
0051             switch (extended_type)
0052             {
0053                 case KSEarthShadow::FULL_PENUMBRA:
0054                 case KSEarthShadow::FULL_UMBRA:
0055                     type = EclipseEvent::FULL;
0056                     break;
0057                 case KSEarthShadow::NONE:
0058                     return;
0059                 default:
0060                     type = EclipseEvent::PARTIAL;
0061                     break;
0062             }
0063 
0064             EclipseEvent_s event = std::make_shared<LunarEclipseEvent>(JD, *getGeoLocation(), type, extended_type);
0065             emit signalEventFound(event);
0066             eclipses.append(event);
0067         });
0068 
0069         progress++;
0070         emit signalProgress(static_cast<int>(roundf(100 * (progress / total))));
0071     }
0072 
0073     emit signalProgress(100);
0074     emit signalComputationFinished();
0075     return eclipses;
0076 }
0077 
0078 // FIXME: (Valentin) This doesn't work for now. We need another method.
0079 LunarEclipseDetails LunarEclipseHandler::findEclipseDetails(LunarEclipseEvent *event)
0080 {
0081     Q_UNUSED(event);
0082     //    const long double INTERVAL = 1.l;
0083 
0084     //    const long double JD = event->getJD();
0085     //    const long double start = JD - INTERVAL;
0086     //    const long double stop = JD + INTERVAL;
0087 
0088     LunarEclipseDetails details;
0089     //    details.available = true;
0090     //    details.eclipseTimes.insert(JD, LunarEclipseDetails::CLOSEST_APPROACH);
0091 
0092     //    auto type = event->getDetailedType();
0093     //    auto findBoth = [&](LunarEclipseDetails::EVENT ev1 /* first (temporal) */, LunarEclipseDetails::EVENT ev2) {
0094     //        QMap<long double, dms> tmpApproaches;
0095 
0096     //        QPair<long double, dms> out;
0097     //        findPrecise(&out, JD, 0.001, -1);
0098     //        details.eclipseTimes.insert(out.first, ev1);
0099 
0100     //        findPrecise(&out, JD, 0.001, 1);
0101     //        details.eclipseTimes.insert(out.first, ev2);
0102     //    };
0103 
0104     //    // waterfall method...
0105 
0106     //    if(type == KSEarthShadow::NONE) {
0107     //        details.available = false;
0108     //       return details;
0109     //    }
0110 
0111     //    if(type == KSEarthShadow::FULL_UMBRA) {
0112     //        m_mode = UMBRA_IMMERSION;
0113     //        findBoth(LunarEclipseDetails::BEGIN_FULL_PENUMRA, LunarEclipseDetails::END_FULL_PENUMRA);
0114 
0115     //        m_mode = UMBRA_CONTACT;
0116     //        findBoth(LunarEclipseDetails::BEGIN_UMBRA_CONTACT, LunarEclipseDetails::END_UMBRA_CONTACT);
0117     //    }
0118 
0119     ////    if(type == KSEarthShadow::FULL_PENUMBRA || type == KSEarthShadow::FULL_UMBRA) {
0120 
0121     ////        m_mode = UMR
0122     ////    };
0123     return details;
0124 
0125 }
0126 
0127 LunarEclipseHandler::~LunarEclipseHandler()
0128 {
0129 
0130 }
0131 
0132 void LunarEclipseHandler::updatePositions(long double jd)
0133 {
0134     KStarsDateTime t(jd);
0135     KSNumbers num(jd);
0136     CachingDms LST(getGeoLocation()->GSTtoLST(t.gst()));
0137     const CachingDms * LAT = getGeoLocation()->lat();
0138 
0139     m_Earth.findPosition(&num);
0140     m_sun.findPosition(&num, LAT, &LST, &m_Earth);
0141     m_moon.findPosition(&num, LAT, &LST, &m_Earth);
0142     m_shadow.findPosition(&num, LAT, &LST, &m_Earth);
0143 }
0144 
0145 dms LunarEclipseHandler::findDistance()
0146 {
0147     dms moon_rad = dms(m_moon.angSize() / 120);
0148     dms pen_rad = dms(m_shadow.getPenumbraAngSize() / 60);
0149     dms um_rad = dms(m_shadow.getUmbraAngSize() / 60);
0150 
0151     dms dist = findSkyPointDistance(&m_shadow, &m_moon);
0152     switch (m_mode)
0153     {
0154         case CLOSEST_APPROACH:
0155             return dist;
0156         case PENUMBRA_CONTACT:
0157             return dist - (moon_rad + pen_rad);
0158         case PUNUMBRA_IMMERSION:
0159             return dist + moon_rad - pen_rad;
0160         case UMBRA_CONTACT:
0161             return dist - (moon_rad + um_rad);
0162         case UMBRA_IMMERSION:
0163             return dist + moon_rad - um_rad;
0164     }
0165 
0166     return dms();
0167 }
0168 
0169 double LunarEclipseHandler::getMaxSeparation()
0170 {
0171     const double SEP_QUALITY = 0.1;
0172 
0173     // we use the penumbra as measure :)
0174     if(m_mode == CLOSEST_APPROACH)
0175         return (m_shadow.getPenumbraAngSize() + m_moon.angSize()) / 60;
0176     else
0177         return SEP_QUALITY;
0178 }
0179 
0180 QVector<long double> LunarEclipseHandler::getFullMoons(long double startJD, long double endJD)
0181 {
0182     const long double NEXT_STEP = 0.5l;
0183     const long double INTERVAL = 26.5l;
0184     long double &currentJD = startJD;
0185 
0186     QVector<long double> fullMoons;
0187     while(currentJD <= endJD)
0188     {
0189         KStarsDateTime t(currentJD);
0190         KSNumbers num(currentJD);
0191         CachingDms LST = getGeoLocation()->GSTtoLST(t.gst());
0192 
0193         m_sun.updateCoords(&num, true, getGeoLocation()->lat(), &LST, true);
0194         m_moon.updateCoords(&num, true, getGeoLocation()->lat(), &LST, true);
0195         m_moon.findPhase(&m_sun);
0196 
0197         if(m_moon.illum() > 0.9)
0198         {
0199             fullMoons.append(currentJD);
0200             currentJD += INTERVAL;
0201             continue;
0202         }
0203 
0204         currentJD += NEXT_STEP;
0205     }
0206 
0207     return fullMoons;
0208 }
0209 
0210 LunarEclipseEvent::LunarEclipseEvent(long double jd, GeoLocation geoPlace, EclipseEvent::ECLIPSE_TYPE type, KSEarthShadow::ECLIPSE_TYPE detailed_type)
0211     : EclipseEvent (jd, geoPlace, type), m_detailedType { detailed_type }
0212 {
0213     m_details.available = false;
0214 }
0215 
0216 QString LunarEclipseEvent::getExtraInfo()
0217 {
0218     switch(m_detailedType)
0219     {
0220         case KSEarthShadow::FULL_UMBRA:
0221             return "Full Umbral";
0222         case KSEarthShadow::FULL_PENUMBRA:
0223             return "Full Penumbral";
0224         case KSEarthShadow::PARTIAL:
0225         case KSEarthShadow::NONE:
0226             return "";
0227     }
0228     return "";
0229 }
0230 
0231 SkyObject *LunarEclipseEvent::getEclipsingObjectFromSkyComposite()
0232 {
0233     return KStarsData::Instance()->skyComposite()->solarSystemComposite()->moon();
0234 }
0235 
0236 void LunarEclipseEvent::slotShowDetails()
0237 {
0238     if(!m_details.available)
0239     {
0240         LunarEclipseHandler handler;
0241         GeoLocation loc = getGeolocation();
0242         handler.setGeoLocation(&loc);
0243         handler.findEclipseDetails(this);
0244     }
0245 }