Kstars

ksmoon.cpp
1/*
2 SPDX-FileCopyrightText: 2001 Jason Harris <kstars@30doradus.org>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7#include "ksmoon.h"
8
9#include "ksnumbers.h"
10#include "ksutils.h"
11#include "kssun.h"
12#include "kstarsdata.h"
13#ifndef KSTARS_LITE
14#include "kspopupmenu.h"
15#endif
16#include "skycomponents/skymapcomposite.h"
17#include "skycomponents/solarsystemcomposite.h"
18#include "texturemanager.h"
19
20#include <QFile>
21#include <QTextStream>
22
23#include <cstdlib>
24#include <cmath>
25#if defined(_MSC_VER)
26#include <float.h>
27#endif
28
29#include <typeinfo>
30
31// Qt version calming
32#include <qtskipemptyparts.h>
33
34using namespace std;
35
36namespace
37{
38// Convert degrees to radians and put it into [0,2*pi] range
39double degToRad(double x)
40{
41 return dms::DegToRad * KSUtils::reduceAngle(x, 0.0, 360.0);
42}
43
44/*
45 * Data used to calculate moon magnitude.
46 *
47 * Formula and data were obtained from SkyChart v3.x Beta
48 *
49 */
50// intensities in Table 1 of M. Minnaert (1961),
51// Phase Frac. Phase Frac. Phase Frac.
52// angle ill. Mag angle ill. Mag angle ill. Mag
53// 0 1.00 -12.7 60 0.75 -11.0 120 0.25 -8.7
54// 10 0.99 -12.4 70 0.67 -10.8 130 0.18 -8.2
55// 20 0.97 -12.1 80 0.59 -10.4 140 0.12 -7.6
56// 30 0.93 -11.8 90 0.50 -10.0 150 0.07 -6.7
57// 40 0.88 -11.5 100 0.41 -9.6 160 0.03 -3.4
58// 50 0.82 -11.2 110 0.33 -9.2
59static const double MagArray[19] = { -12.7, -12.4, -12.1, -11.8, -11.5, -11.2, -11.0, -10.8, -10.4, -10.0,
60 -9.6, -9.2, -8.7, -8.2, -7.6, -6.7, -3.4, 0, 0
61 };
62}
63
64KSMoon::KSMoon() : KSPlanetBase(i18n("Moon"), QString(), QColor("white"), 3474.8 /*diameter in km*/)
65{
66 instance_count++;
67 //Reset object type
68 setType(SkyObject::MOON);
69}
70
72{
73 instance_count++;
74}
75
77{
78 Q_ASSERT(typeid(this) == typeid(static_cast<const KSMoon *>(this))); // Ensure we are not slicing a derived class
79 return new KSMoon(*this);
80}
81
82KSMoon::~KSMoon()
83{
84 instance_count--;
85 if (instance_count <= 0)
86 {
87 LRData.clear();
88 BData.clear();
89 data_loaded = false;
90 }
91}
92
93bool KSMoon::data_loaded = false;
94int KSMoon::instance_count = 0;
95QList<KSMoon::MoonLRData> KSMoon::LRData;
96QList<KSMoon::MoonBData> KSMoon::BData;
97
99{
100 if (data_loaded)
101 return true;
102
103 QStringList fields;
104 QFile f;
105
106 if (KSUtils::openDataFile(f, "moonLR.dat"))
107 {
108 QTextStream stream(&f);
109 while (!stream.atEnd())
110 {
111 fields = stream.readLine().split(' ', Qt::SkipEmptyParts);
112
113 if (fields.size() == 6)
114 {
115 LRData.append(MoonLRData());
116 LRData.last().nd = fields[0].toInt();
117 LRData.last().nm = fields[1].toInt();
118 LRData.last().nm1 = fields[2].toInt();
119 LRData.last().nf = fields[3].toInt();
120 LRData.last().Li = fields[4].toDouble();
121 LRData.last().Ri = fields[5].toDouble();
122 }
123 }
124 f.close();
125 }
126 else
127 return false;
128
129 if (KSUtils::openDataFile(f, "moonB.dat"))
130 {
131 QTextStream stream(&f);
132 while (!stream.atEnd())
133 {
134 fields = stream.readLine().split(' ', Qt::SkipEmptyParts);
135
136 if (fields.size() == 5)
137 {
138 BData.append(MoonBData());
139 BData.last().nd = fields[0].toInt();
140 BData.last().nm = fields[1].toInt();
141 BData.last().nm1 = fields[2].toInt();
142 BData.last().nf = fields[3].toInt();
143 BData.last().Bi = fields[4].toDouble();
144 }
145 }
146 f.close();
147 }
148
149 data_loaded = true;
150 return true;
151}
152
154{
155 //Algorithms in this subroutine are taken from Chapter 45 of "Astronomical Algorithms"
156 //by Jean Meeus (1991, Willmann-Bell, Inc. ISBN 0-943396-35-2. https://www.willbell.com/math/mc1.htm)
157 //updated to Jean Messus (1998, Willmann-Bell, http://www.naughter.com/aa.html )
158
159 double T, L, D, M, M1, F, A1, A2, A3;
160 double sumL, sumR, sumB;
161
162 //Julian centuries since J2000
163 T = num->julianCenturies();
164
165 double Et = 1.0 - 0.002516 * T - 0.0000074 * T * T;
166
167 //Moon's mean longitude
168 L = degToRad(218.3164477 + 481267.88123421 * T - 0.0015786 * T * T + T * T * T / 538841.0 -
169 T * T * T * T / 65194000.0);
170 //Moon's mean elongation
171 D = degToRad(297.8501921 + 445267.1114034 * T - 0.0018819 * T * T + T * T * T / 545868.0 -
172 T * T * T * T / 113065000.0);
173 //Sun's mean anomaly
174 M = degToRad(357.5291092 + 35999.0502909 * T - 0.0001536 * T * T + T * T * T / 24490000.0);
175 //Moon's mean anomaly
176 M1 = degToRad(134.9633964 + 477198.8675055 * T + 0.0087414 * T * T + T * T * T / 69699.0 -
177 T * T * T * T / 14712000.0);
178 //Moon's argument of latitude (angle from ascending node)
179 F = degToRad(93.2720950 + 483202.0175233 * T - 0.0036539 * T * T - T * T * T / 3526000.0 +
180 T * T * T * T / 863310000.0);
181
182 A1 = degToRad(119.75 + 131.849 * T);
183 A2 = degToRad(53.09 + 479264.290 * T);
184 A3 = degToRad(313.45 + 481266.484 * T);
185
186 //Calculate the series expansions stored in moonLR.txt and moonB.txt.
187 //
188 sumL = 0.0;
189 sumR = 0.0;
190
191 if (!loadData())
192 return false;
193
194 for (const auto &mlrd : LRData)
195 {
196 double E = 1.0;
197
198 if (mlrd.nm) //if M != 0, include changing eccentricity of Earth's orbit
199 {
200 E = Et;
201 if (abs(mlrd.nm) == 2)
202 E = E * E; //use E^2
203 }
204 sumL += E * mlrd.Li * sin(mlrd.nd * D + mlrd.nm * M + mlrd.nm1 * M1 + mlrd.nf * F);
205 sumR += E * mlrd.Ri * cos(mlrd.nd * D + mlrd.nm * M + mlrd.nm1 * M1 + mlrd.nf * F);
206 }
207
208 sumB = 0.0;
209 for (const auto &mbd : BData)
210 {
211 double E = 1.0;
212
213 if (mbd.nm) //if M != 0, include changing eccentricity of Earth's orbit
214 {
215 E = Et;
216 if (abs(mbd.nm) == 2)
217 E = E * E; //use E^2
218 }
219 sumB += E * mbd.Bi * sin(mbd.nd * D + mbd.nm * M + mbd.nm1 * M1 + mbd.nf * F);
220 }
221
222 //Additive terms for sumL and sumB
223 sumL += (3958.0 * sin(A1) + 1962.0 * sin(L - F) + 318.0 * sin(A2));
224 sumB += (-2235.0 * sin(L) + 382.0 * sin(A3) + 175.0 * sin(A1 - F) + 175.0 * sin(A1 + F) + 127.0 * sin(L - M1) -
225 115.0 * sin(L + M1));
226
227 //Geocentric coordinates
228 setEcLong(dms(sumL / 1000000.0 + L * 180.0 / dms::PI)); //convert radians to degrees
229 setEcLat(dms(sumB / 1000000.0));
230 Rearth = (385000.56 + sumR / 1000.0) / AU_KM; //distance from Earth, in AU
231
233
234 //Determine position angle
235 findPA(num);
236
237 return true;
238}
239
240void KSMoon::findMagnitude(const KSNumbers *)
241{
242 // This block of code to compute Moon magnitude (and the
243 // relevant data put into ksplanetbase.h) was taken from
244 // SkyChart v3 Beta
245 double phd = phase().Degrees();
246
247 if (std::isnan(phd)) // Avoid nanny phases.
248 {
249 findPhase(nullptr);
250 phd = phase().Degrees();
251 if (std::isnan(phd))
252 return;
253 }
254 int p = floor(phd);
255 if (p > 180)
256 p = p - 360;
257 int i = p / 10;
258 int k = p % 10;
259 int j = (i + 1 > 18) ? 18 : i + 1;
260 i = 18 - abs(i);
261 j = 18 - abs(j);
262 if (i >= 0 && j >= 0 && i <= 18 && j <= 18)
263 {
264 setMag(MagArray[i] + (MagArray[j] - MagArray[i]) * k / 10);
265 }
266}
267
269{
270 if (Sun == nullptr)
271 {
272 if (defaultSun == nullptr)
273 defaultSun = KStarsData::Instance()->skyComposite()->solarSystemComposite()->sun();
274 Sun = defaultSun;
275 }
276
277 Q_ASSERT(Sun != nullptr);
278
279 // This is an approximation justified by the small Earth-Moon distance in relation
280 // to the great Earth-Sun distance
281 Phase = (ecLong() - Sun->ecLong()).Degrees(); // Phase is obviously in degrees
282 double DegPhase = dms(Phase).reduce().Degrees();
283 iPhase = int(0.1 * DegPhase + 0.5) % 36; // iPhase must be in [0,36) range
284
285 m_image = TextureManager::getImage(QString("moon%1").arg(iPhase, 2, 10, QChar('0')));
286}
287
289{
290 double f = illum();
291 double p = abs(dms(Phase).reduce().Degrees());
292
293 //First, handle the major phases
294 if (f > 0.99)
295 return i18nc("moon phase, 100 percent illuminated", "Full moon");
296 if (f < 0.01)
297 return i18nc("moon phase, 0 percent illuminated", "New moon");
298 if (fabs(f - 0.50) < 0.06)
299 {
300 if (p < 180.0)
301 return i18nc("moon phase, half-illuminated and growing", "First quarter");
302 else
303 return i18nc("moon phase, half-illuminated and shrinking", "Third quarter");
304 }
305
306 //Next, handle the more general cases
307 if (p < 90.0)
308 return i18nc("moon phase between new moon and 1st quarter", "Waxing crescent");
309 else if (p < 180.0)
310 return i18nc("moon phase between 1st quarter and full moon", "Waxing gibbous");
311 else if (p < 270.0)
312 return i18nc("moon phase between full moon and 3rd quarter", "Waning gibbous");
313 else if (p < 360.0)
314 return i18nc("moon phase between 3rd quarter and new moon", "Waning crescent");
315
316 else
317 return i18n("unknown");
318}
319
321{
322#ifdef KSTARS_LITE
323 Q_UNUSED(pmenu)
324#else
325 pmenu->createMoonMenu(this);
326#endif
327}
328
330{
331 return solarsysUID(UID_SOL_BIGOBJ) | 10;
332}
Provides necessary information about the Moon.
Definition ksmoon.h:26
bool findGeocentricPosition(const KSNumbers *num, const KSPlanetBase *) override
Reimplemented from KSPlanetBase, this function employs unique algorithms for estimating the lunar coo...
Definition ksmoon.cpp:153
KSMoon()
Default constructor.
Definition ksmoon.cpp:64
QString phaseName() const
Definition ksmoon.cpp:288
SkyObject::UID getUID() const override
Return UID for object.
Definition ksmoon.cpp:329
bool loadData() override
reimplemented from KSPlanetBase
Definition ksmoon.cpp:98
void initPopupMenu(KSPopupMenu *pmenu) override
Initialize the popup menut.
Definition ksmoon.cpp:320
double illum() const
Definition ksmoon.h:49
KSMoon * clone() const override
Create copy of object.
Definition ksmoon.cpp:76
virtual void findPhase()
Determine the phase of the planet.
There are several time-dependent values used in position calculations, that are not specific to an ob...
Definition ksnumbers.h:43
const CachingDms * obliquity() const
Definition ksnumbers.h:56
double julianCenturies() const
Definition ksnumbers.h:88
A subclass of TrailObject that provides additional information needed for most solar system objects.
UID solarsysUID(UID type) const
Compute high 32-bits of UID.
static const UID UID_SOL_BIGOBJ
Big object.
void findPA(const KSNumbers *num)
Determine the position angle of the planet for a given date (used internally by findPosition() )
void setEcLong(dms elong)
Set Ecliptic Geocentric Longitude according to argument.
const dms & ecLong() const
void EclipticToEquatorial(const CachingDms *Obliquity)
Convert Ecliptic longitude/latitude to Right Ascension/Declination.
void setEcLat(dms elat)
Set Ecliptic Geocentric Latitude according to argument.
The KStars Popup Menu.
Definition kspopupmenu.h:35
Child class of KSPlanetBase; encapsulates information about the Sun.
Definition kssun.h:24
void setMag(float m)
Set the object's sorting magnitude.
Definition skyobject.h:403
qint64 UID
Type for Unique object IDenticator.
Definition skyobject.h:49
void setType(int t)
Set the object's type identifier to the argument.
Definition skyobject.h:195
static const QImage & getImage(const QString &name)
Return texture image.
An angle, stored as degrees, but expressible in many ways.
Definition dms.h:38
const dms reduce() const
return the equivalent angle between 0 and 360 degrees.
Definition dms.cpp:251
static constexpr double PI
PI is a const static member; it's public so that it can be used anywhere, as long as dms....
Definition dms.h:385
const double & Degrees() const
Definition dms.h:141
static constexpr double DegToRad
DegToRad is a const static member equal to the number of radians in one degree (dms::PI/180....
Definition dms.h:390
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
constexpr double degToRad(double deg)
Int toInt() const const
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
SkipEmptyParts
bool atEnd() const const
QString readLine(qint64 maxlen)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:19:04 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.