KHolidays

astroseasons.cpp
1/*
2 This file is part of the kholidays library.
3
4 SPDX-FileCopyrightText: 2004, 2006-2007 Allen Winter <winter@kde.org>
5 SPDX-FileCopyrightText: 2018 Daniel Vrátil <dvratil@kde.org>
6
7 SPDX-License-Identifier: LGPL-2.0-or-later
8*/
9
10#include "astroseasons.h"
11
12#include <cmath>
13#include <numeric>
14
15#include <QCoreApplication>
16#include <QDate>
17
18using namespace KHolidays;
19
20/* Correction tables and calculation algorithms below are based on the book
21 * Astronomical Algorithms by Jean Meeus, (c) 1991 by Willman-Bell, Inc.,
22 *
23 * The correction tables are precise for years -1000 to +3000, but according
24 * to the book, they can be used for several centuries before and after that
25 * period with the error still being quite small. As we only care about date
26 * and not the time, the precision of the algorithm is good enough even for
27 * a greater time span, therefore no checks for the given year are performed
28 * anywhere in the code.
29 */
30namespace
31{
32double meanJDE(AstroSeasons::Season season, int year)
33{
34 if (year <= 1000) {
35 // Astronomical Algorithms, Jean Meeus, chapter 26, table 26.A
36 // mean season Julian dates for years -1000 to 1000
37 const double y = year / 1000.0;
38 switch (season) {
39 case AstroSeasons::MarchEquinox:
40 return 1721139.29189 + (365242.13740 * y) + (0.06134 * std::pow(y, 2)) + (0.00111 * std::pow(y, 3)) - (0.00071 * std::pow(y, 4));
41 case AstroSeasons::JuneSolstice:
42 return 1721233.25401 + (365241.72562 * y) - (0.05323 * std::pow(y, 2)) + (0.00907 * std::pow(y, 3)) + (0.00025 * std::pow(y, 4));
43 case AstroSeasons::SeptemberEquinox:
44 return 1721325.70455 + (365242.49558 * y) - (0.11677 * std::pow(y, 2)) - (0.00297 * std::pow(y, 3)) + (0.00074 * std::pow(y, 4));
45 case AstroSeasons::DecemberSolstice:
46 return 1721414.39987 + (365242.88257 * y) - (0.00769 * std::pow(y, 2)) - (0.00933 * std::pow(y, 3)) - (0.00006 * std::pow(y, 4));
47 case AstroSeasons::None:
48 Q_ASSERT(false);
49 return 0;
50 }
51 } else {
52 // Astronomical Algorithms, Jean Meeus, chapter 26, table 26.B
53 // mean season Julian dates for years 1000 to 3000
54 const double y = (year - 2000) / 1000.0;
55 switch (season) {
56 case AstroSeasons::MarchEquinox:
57 return 2451623.80984 + (365242.37404 * y) + (0.05169 * std::pow(y, 2)) - (0.00411 * std::pow(y, 3)) - (0.00057 * std::pow(y, 4));
58 case AstroSeasons::JuneSolstice:
59 return 2451716.56767 + (365241.62603 * y) + (0.00325 * std::pow(y, 2)) + (0.00888 * std::pow(y, 3)) - (0.00030 * std::pow(y, 4));
60 case AstroSeasons::SeptemberEquinox:
61 return 2451810.21715 + (365242.01767 * y) - (0.11575 * std::pow(y, 2)) + (0.00337 * std::pow(y, 3)) + (0.00078 * std::pow(y, 4));
62 case AstroSeasons::DecemberSolstice:
63 return 2451900.05952 + (365242.74049 * y) - (0.06223 * std::pow(y, 2)) - (0.00823 * std::pow(y, 3)) + (0.00032 * std::pow(y, 4));
64 case AstroSeasons::None:
65 Q_ASSERT(false);
66 return 0;
67 }
68 }
69
70 return 0;
71}
72
73double periodicTerms(double t)
74{
75 // Astronomical Algorithms, Jean Meeus, chapter 26, table 26.C
76 // The table gives the periodic terms in degrees, but the values are converted to radians
77 // at compile time so that they can be passed to std::cos()
78 struct Periodic {
79 constexpr Periodic(int a, double b_deg, double c_deg)
80 : a(a)
81 , b_rad(b_deg * (M_PI / 180.0))
82 , c_rad(c_deg * (M_PI / 180.0))
83 {
84 }
85
86 int a;
87 double b_rad;
88 double c_rad;
89 }
90 // clang-format off
91 periodic[] = {
92 {485, 324.96, 1934.136}, {203, 337.23, 32964.467}, {199, 342.08, 20.186}, {182, 27.85, 445267.112},
93 {156, 73.14, 45036.886}, {136, 171.52, 22518.443}, { 77, 222.54, 65928.934}, { 74, 296.72, 3034.906},
94 { 70, 243.58, 9037.513}, { 58, 119.81, 33718.147}, { 52, 297.17, 150.678}, { 50, 21.02, 2281.226},
95 { 45, 247.54, 29929.562}, { 44, 325.15, 31555.956}, { 29, 60.93, 4443.417}, { 18, 155.12, 67555.328},
96 { 17, 288.79, 4562.452}, { 16, 198.04, 62894.029}, { 14, 199.76, 31436.921}, { 12, 95.39, 14577.848},
97 { 12, 287.11, 31931.756}, { 12, 320.81, 34777.259}, { 9, 227.73, 1222.114}, { 8, 15.45, 16859.074}
98 };
99 // clang-format on
100
101 return std::accumulate(std::begin(periodic), std::end(periodic), 0.0, [t](double s, const Periodic &p) {
102 return s + p.a * std::cos(p.b_rad + p.c_rad * t);
103 });
104}
105
106// Returns julian date of given season in given year
107double seasonJD(AstroSeasons::Season season, int year)
108{
109 // Astronimical Algorithms, Jean Meeus, chapter 26
110 const auto jde0 = meanJDE(season, year);
111 const auto T = (jde0 - 2451545.0) / 36525;
112 const auto W_deg = 35999.373 * T + 2.47;
113 const auto W_rad = W_deg * (M_PI / 180.0);
114 const auto dLambda = 1 + (0.0334 * std::cos(W_rad)) + (0.0007 * std::cos(2 * W_rad));
115 const auto S = periodicTerms(T);
116 return jde0 + (0.00001 * S) / dLambda;
117}
118
119}
120
121QDate AstroSeasons::seasonDate(Season season, int year)
122{
123 if (season == None) {
124 return {};
125 }
126 const qint64 jd = round(seasonJD(season, year));
127 return QDate::fromJulianDay(jd);
128}
129
131{
132 return seasonName(seasonAtDate(date));
133}
134
135QString AstroSeasons::seasonName(AstroSeasons::Season season)
136{
137 switch (season) {
138 case JuneSolstice:
139 return QCoreApplication::translate("AstroSeasons", "June Solstice");
140 case DecemberSolstice:
141 return QCoreApplication::translate("AstroSeasons", "December Solstice");
142 case MarchEquinox:
143 return QCoreApplication::translate("AstroSeasons", "March Equinox");
144 case SeptemberEquinox:
145 return QCoreApplication::translate("AstroSeasons", "September Equinox");
146 case None:
147 return QString();
148 }
149 return QString();
150}
151
152AstroSeasons::Season AstroSeasons::seasonAtDate(const QDate &date)
153{
154 for (auto season : {JuneSolstice, DecemberSolstice, MarchEquinox, SeptemberEquinox}) {
155 if (seasonDate(season, date.year()) == date) {
156 return season;
157 }
158 }
159 return None;
160}
static Season seasonAtDate(const QDate &date)
Return the season for the specified Gregorian date.
static QString seasonNameAtDate(const QDate &date)
Return the season as a text string for the specified date.
static QString seasonName(Season season)
Return the string representation of season.
static QDate seasonDate(Season season, int year)
Return the Gregorian date on which the season occurs in given year.
QString translate(const char *context, const char *sourceText, const char *disambiguation, int n)
QDate fromJulianDay(qint64 jd)
int year() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Nov 8 2024 11:59:30 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.