File indexing completed on 2023-10-01 07:41:14
0001 /* 0002 SPDX-FileCopyrightText: 2009 Prakash Mohan <prakash.mohan@kdemail.net> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "ksalmanac.h" 0008 0009 #include "geolocation.h" 0010 #include "ksnumbers.h" 0011 #include "kstarsdata.h" 0012 0013 KSAlmanac::KSAlmanac() 0014 { 0015 KStarsData *data = KStarsData::Instance(); 0016 0017 /*dt = KStarsDateTime::currentDateTime(); 0018 geo = data->geo(); 0019 dt.setTime(QTime()); 0020 dt = geo->LTtoUT(dt);*/ 0021 0022 // Jasem 2015-08-24 Do NOT use KStarsDataTime for local time, it is only for UTC 0023 QDateTime midnight = QDateTime(data->lt().date(), QTime()); 0024 geo = data->geo(); 0025 dt = geo->LTtoUT(KStarsDateTime(midnight)); 0026 update(); 0027 } 0028 0029 KSAlmanac::KSAlmanac(const KStarsDateTime &midnight, const GeoLocation *g) 0030 { 0031 geo = g ? g : KStarsData::Instance()->geo(); 0032 0033 dt = midnight.isValid() ? 0034 midnight.timeSpec() == Qt::LocalTime ? 0035 geo->LTtoUT(midnight) : 0036 midnight : 0037 KStarsData::Instance()->ut(); 0038 0039 update(); 0040 } 0041 0042 void KSAlmanac::update() 0043 { 0044 RiseSetTime(&m_Sun, &SunRise, &SunSet, &SunRiseT, &SunSetT); 0045 RiseSetTime(&m_Moon, &MoonRise, &MoonSet, &MoonRiseT, &MoonSetT); 0046 // qDebug() << Q_FUNC_INFO << "Sun rise: " << SunRiseT.toString() << " Sun set: " << SunSetT.toString() << " Moon rise: " << MoonRiseT.toString() << " Moon set: " << MoonSetT.toString(); 0047 findDawnDusk(); 0048 findMoonPhase(); 0049 } 0050 0051 void KSAlmanac::RiseSetTime(SkyObject *o, double *riseTime, double *setTime, QTime *RiseTime, QTime *SetTime) 0052 { 0053 // Compute object rise and set times 0054 const KStarsDateTime today = dt; 0055 const GeoLocation *_geo = geo; 0056 *RiseTime = o->riseSetTime( 0057 today, _geo, 0058 true); // FIXME: Should we add a day here so that we report future rise time? Not doing so produces the right results for the moon. Not sure about the sun. 0059 *SetTime = o->riseSetTime(today, _geo, false); 0060 *riseTime = -1.0 * RiseTime->secsTo(QTime(0, 0, 0, 0)) / 86400.0; 0061 *setTime = -1.0 * SetTime->secsTo(QTime(0, 0, 0, 0)) / 86400.0; 0062 0063 // Check to see if the object is circumpolar 0064 // NOTE: Since we are working on a local copy of the Sun / Moon, 0065 // we freely change the geolocation / time without setting 0066 // them back. 0067 0068 KSNumbers num(dt.djd()); 0069 CachingDms LST = geo->GSTtoLST(dt.gst()); 0070 o->updateCoords(&num, true, geo->lat(), &LST, true); 0071 if (o->checkCircumpolar(geo->lat())) 0072 { 0073 if (o->alt().Degrees() > 0.0) 0074 { 0075 //Circumpolar, signal it this way: 0076 *riseTime = 0.0; 0077 *setTime = 1.0; 0078 } 0079 else 0080 { 0081 //never rises, signal it this way: 0082 *riseTime = 0.0; 0083 *setTime = -1.0; 0084 } 0085 } 0086 } 0087 0088 void KSAlmanac::findDawnDusk(double altitude) 0089 { 0090 KStarsDateTime today = dt; 0091 KSNumbers num(today.djd()); 0092 CachingDms LST = geo->GSTtoLST(today.gst()); 0093 0094 // Relocate our local Sun to this almanac time - local midnight 0095 m_Sun.updateCoords(&num, true, geo->lat(), &LST, true); 0096 0097 // Granularity 0098 int const h_inc = 5; 0099 0100 // Compute the altitude of the Sun twelve hours before this almanac time 0101 int const start_h = -1200, end_h = +1200; 0102 double last_alt = findAltitude(&m_Sun, start_h/100.0); 0103 0104 int dawn = -1300, dusk = -1300, min_alt_time = -1300; 0105 double max_alt = -100.0, min_alt = +100.0; 0106 0107 // Compute the dawn and dusk times in a [-12,+12] hours around the day midnight of this almanac as well as min and max altitude 0108 // See the header comment about dawn and dusk positions 0109 for (int h = start_h + h_inc; h <= end_h; h += h_inc) 0110 { 0111 // Compute the Sun's altitude in an increasing hour interval 0112 double const alt = findAltitude(&m_Sun, h/100.0); 0113 0114 // Deduce whether the Sun is rising or setting 0115 bool const rising = alt - last_alt > 0; 0116 0117 // Extend min/max altitude interval, push minimum time down 0118 if (max_alt < alt) 0119 { 0120 max_alt = alt; 0121 } 0122 else if (alt < min_alt) 0123 { 0124 min_alt = alt; 0125 min_alt_time = h; 0126 } 0127 0128 // Dawn is when the Sun is rising and crosses an altitude of -18 degrees 0129 if (dawn < 0) 0130 if (rising) 0131 if (last_alt <= altitude && altitude <= alt) 0132 dawn = h - h_inc * (alt == last_alt ? 0 : (alt - altitude)/(alt - last_alt)); 0133 0134 // Dusk is when the Sun is setting and crosses an altitude of -18 degrees 0135 if (dusk < 0) 0136 if (!rising) 0137 if (last_alt >= altitude && altitude >= alt) 0138 dusk = h - h_inc * (alt == last_alt ? 0 : (alt - altitude)/(alt - last_alt)); 0139 0140 last_alt = alt; 0141 } 0142 0143 // If the Sun did not cross the astronomical twilight altitude, use the minimal altitude 0144 if (dawn < start_h || dusk < start_h) 0145 { 0146 DawnAstronomicalTwilight = static_cast <double> (min_alt_time) / 2400.0; 0147 DuskAstronomicalTwilight = static_cast <double> (min_alt_time) / 2400.0; 0148 } 0149 // If the Sun did cross the astronomical twilight, use the computed time offsets 0150 else 0151 { 0152 DawnAstronomicalTwilight = static_cast <double> (dawn) / 2400.0; 0153 DuskAstronomicalTwilight = static_cast <double> (dusk) / 2400.0; 0154 } 0155 0156 SunMaxAlt = max_alt; 0157 SunMinAlt = min_alt; 0158 } 0159 0160 void KSAlmanac::findMoonPhase() 0161 { 0162 const KStarsDateTime today = dt; 0163 KSNumbers num(today.djd()); 0164 CachingDms LST = geo->GSTtoLST(today.gst()); 0165 0166 m_Sun.updateCoords(&num, true, geo->lat(), &LST, true); // We can abuse our own copy of the sun and/or moon 0167 m_Moon.updateCoords(&num, true, geo->lat(), &LST, true); 0168 m_Moon.findPhase(&m_Sun); 0169 MoonPhase = m_Moon.phase().Degrees(); 0170 } 0171 0172 void KSAlmanac::setDate(const KStarsDateTime &utc_midnight) 0173 { 0174 dt = utc_midnight; 0175 update(); 0176 } 0177 0178 void KSAlmanac::setLocation(const GeoLocation *geo_) 0179 { 0180 geo = geo_; 0181 update(); 0182 } 0183 0184 double KSAlmanac::sunZenithAngleToTime(double z) const 0185 { 0186 // TODO: Correct for movement of the sun 0187 double HA = acos((cos(z * dms::DegToRad) - m_Sun.dec().sin() * geo->lat()->sin()) / 0188 (m_Sun.dec().cos() * geo->lat()->cos())); 0189 double HASunset = acos((-m_Sun.dec().sin() * geo->lat()->sin()) / (m_Sun.dec().cos() * geo->lat()->cos())); 0190 return SunSet + (HA - HASunset) / 24.0; 0191 } 0192 0193 double KSAlmanac::findAltitude(const SkyPoint *p, double hour) 0194 { 0195 return SkyPoint::findAltitude(p, dt, geo, hour).Degrees(); 0196 }