Kstars

ksmoon.cpp
1 /*
2  SPDX-FileCopyrightText: 2001 Jason Harris <[email protected]>
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 
34 using namespace std;
35 
36 namespace
37 {
38 // Convert degrees to radians and put it into [0,2*pi] range
39 double 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
59 static 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 
64 KSMoon::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 
82 KSMoon::~KSMoon()
83 {
84  instance_count--;
85  if (instance_count <= 0)
86  {
87  LRData.clear();
88  BData.clear();
89  data_loaded = false;
90  }
91 }
92 
93 bool KSMoon::data_loaded = false;
94 int KSMoon::instance_count = 0;
95 QList<KSMoon::MoonLRData> KSMoon::LRData;
96 QList<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 
240 void 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 
268 void KSMoon::findPhase(const KSSun *Sun)
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 }
void append(const T &value)
SkyObject::UID getUID() const override
Return UID for object.
Definition: ksmoon.cpp:329
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
virtual void findPhase()
Determine the phase of the planet.
constexpr double degToRad(double deg)
QStringList split(const QString &sep, QString::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
KSMoon * clone() const override
Create copy of object.
Definition: ksmoon.cpp:76
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 phaseName() const
Definition: ksmoon.cpp:288
void setEcLat(dms elat)
Set Ecliptic Geocentric Latitude according to argument.
Definition: ksplanetbase.h:106
Provides necessary information about the Moon. A subclass of SkyObject that provides information need...
Definition: ksmoon.h:25
qint64 UID
Type for Unique object IDenticator.
Definition: skyobject.h:49
bool loadData() override
reimplemented from KSPlanetBase
Definition: ksmoon.cpp:98
void setEcLong(dms elong)
Set Ecliptic Geocentric Longitude according to argument.
Definition: ksplanetbase.h:100
Provides necessary information about the Sun.
Definition: kssun.h:23
QString i18n(const char *text, const TYPE &arg...)
Store several time-dependent astronomical quantities.
Definition: ksnumbers.h:42
void setMag(float m)
Set the object's sorting magnitude.
Definition: skyobject.h:403
bool atEnd() const const
double illum() const
Definition: ksmoon.h:49
SkipEmptyParts
void initPopupMenu(KSPopupMenu *pmenu) override
Initialize the popup menut.
Definition: ksmoon.cpp:320
const dms & ecLong() const
Definition: ksplanetbase.h:91
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
QString readLine(qint64 maxlen)
T & last()
SkyMapComposite * skyComposite()
Definition: kstarsdata.h:166
UID solarsysUID(UID type) const
Compute high 32-bits of UID.
Definition: ksplanetbase.h:223
An angle, stored as degrees, but expressible in many ways.
Definition: dms.h:37
const CachingDms * obliquity() const
Definition: ksnumbers.h:56
const double & Degrees() const
Definition: dms.h:141
static const QImage & getImage(const QString &name)
Return texture image.
void clear()
QString i18nc(const char *context, const char *text, const TYPE &arg...)
double julianCenturies() const
Definition: ksnumbers.h:88
KSMoon()
Default constructor.
Definition: ksmoon.cpp:64
const dms reduce() const
return the equivalent angle between 0 and 360 degrees.
Definition: dms.cpp:251
void EclipticToEquatorial(const CachingDms *Obliquity)
Convert Ecliptic longitude/latitude to Right Ascension/Declination.
void setType(int t)
Set the object's type identifier to the argument.
Definition: skyobject.h:195
static const UID UID_SOL_BIGOBJ
Big object.
Definition: ksplanetbase.h:216
void findPA(const KSNumbers *num)
Determine the position angle of the planet for a given date (used internally by findPosition() )
Provides necessary information about objects in the solar system.
Definition: ksplanetbase.h:49
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Sun Oct 1 2023 04:02:40 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.