1 /*
2 * Copyright (C) 2020 Georg Zotti
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
17 */
18
19 #include "StelTranslator.hpp"
20 #include "RomanCalendar.hpp"
21 #include "StelUtils.hpp"
22 #include "StelApp.hpp"
23 #include "StelCore.hpp"
24
RomanCalendar(double jd)25 RomanCalendar::RomanCalendar(double jd): JulianCalendar(jd)
26 {
27 RomanCalendar::retranslate();
28 }
29
30 QMap<int, QString> RomanCalendar::monthGen;
31
retranslate()32 void RomanCalendar::retranslate()
33 {
34 // fill the name lists with translated month names
35 monthGen={
36 { 1, qc_("Ianuarii" , "Roman month name (genitive)")},
37 { 2, qc_("Februarii" , "Roman month name (genitive)")},
38 { 3, qc_("Martii" , "Roman month name (genitive)")},
39 { 4, qc_("Aprilis" , "Roman month name (genitive)")},
40 { 5, qc_("Maii" , "Roman month name (genitive)")},
41 { 6, qc_("Iunii" , "Roman month name (genitive)")},
42 { 7, qc_("Iulii" , "Roman month name (genitive)")},
43 { 8, qc_("Augusti" , "Roman month name (genitive)")},
44 { 9, qc_("Septembris" , "Roman month name (genitive)")},
45 {10, qc_("Octobris" , "Roman month name (genitive)")},
46 {11, qc_("Novembris" , "Roman month name (genitive)")},
47 {12, qc_("Decembris" , "Roman month name (genitive)")}};
48 }
49
50 // Set a calendar date from the Julian day number
setJD(double JD)51 void RomanCalendar::setJD(double JD)
52 {
53 this->JD=JD;
54
55 int rd=fixedFromJD(JD, true);
56 parts=romanFromFixed(rd);
57
58 emit partsChanged(parts);
59 }
60
61 // get a stringlist of calendar date elements sorted from the largest to the smallest.
62 // AUCYear, Month, MonthName(genitive), event, DayName
getDateStrings() const63 QStringList RomanCalendar::getDateStrings() const
64 {
65 QStringList events={qc_("Kalendae", "Roman calendar term"),
66 qc_("Nones", "Roman calendar term"),
67 qc_("Ides", "Roman calendar term")};
68 QStringList eventsShort={qc_("Kal.", "Roman calendar term"),
69 qc_("Non.", "Roman calendar term"),
70 qc_("Id." , "Roman calendar term")};
71
72 QStringList list;
73 list << QString::number(aucYearFromJulian(parts.at(0))); // 0:AUC year
74 list << QString::number(parts.at(1)); // 1:Month (numeric)
75 list << monthGen.value(parts.at(1)); // 2:Month (genitive form)
76 // 3:event:
77 if (parts.at(3)==1)
78 list << events.at(parts.at(2)-1);
79 else
80 list << eventsShort.at(parts.at(2)-1);
81
82 // 4:day
83 if (parts.at(3)==1)
84 list << "";
85 else if (parts.at(3)==2)
86 list << qc_("pridie", "Roman calendar term");
87 else {
88 const QString bisTerm=QString(" %1").arg(parts.at(4)? qc_("bis", "Roman calendar term") : "");
89 list << QString("%1%2 %3").arg(qc_("ante diem", "Roman calendar term"), bisTerm, romanNumber(parts.at(3)));
90 }
91
92 return list;
93 }
94
95 // get a formatted complete string for a date
getFormattedDateString() const96 QString RomanCalendar::getFormattedDateString() const
97 {
98 QStringList str=getDateStrings();
99
100 QString day;
101 return QString("%1 %2 %3 %4 %5")
102 .arg(str.at(4))
103 .arg(str.at(3))
104 .arg(str.at(2))
105 .arg(str.at(0))
106 .arg(qc_("A.U.C.", "ab urbe condita"));// year AUC
107 }
108
109 // set date from a vector of calendar date elements sorted from the largest to the smallest.
110 // JulianYear-Month[1...12]-event-count-leap
111 // Time is not changed!
setDate(QVector<int> parts)112 void RomanCalendar::setDate(QVector<int> parts)
113 {
114 this->parts=parts;
115
116 double rd=fixedFromRoman(parts);
117 // restore time from JD!
118 double frac=StelUtils::fmodpos(JD+0.5+StelApp::getInstance().getCore()->getUTCOffset(JD)/24., 1.);
119 JD=jdFromFixed(rd+frac, true);
120
121 emit jdChanged(JD);
122 }
123
124 // returns 13 or 15, the day of "idae"
idesOfMonth(int month)125 int RomanCalendar::idesOfMonth(int month)
126 {
127 static const QVector<int> cand={JulianCalendar::march, JulianCalendar::may, JulianCalendar::july, JulianCalendar::october};
128 if (cand.contains(month))
129 return 15;
130 else
131 return 13;
132 }
133
134 // returns the day of "nones"
nonesOfMonth(int month)135 int RomanCalendar::nonesOfMonth(int month)
136 {
137 return idesOfMonth(month)-8;
138 }
139
140 // Convert between AUC and Julian year numbers
julianYearFromAUC(int aucYear)141 int RomanCalendar::julianYearFromAUC(int aucYear)
142 {
143 if ((1<=aucYear) && (aucYear<=-yearRomeFounded))
144 return aucYear + yearRomeFounded - 1;
145 else
146 return aucYear + yearRomeFounded;
147 }
148
fixedFromRoman(QVector<int> roman)149 int RomanCalendar::fixedFromRoman(QVector<int> roman)
150 {
151 const int year=roman.at(0);
152 const int month=roman.at(1);
153 const events event=static_cast<events>(roman.at(2));
154 const int count=roman.at(3);
155 const int leap=roman.at(4);
156
157 int rd = 0; // Suppress warning
158 switch (event)
159 {
160 case kalends:
161 rd=fixedFromJulian({year, month, 1});
162 break;
163 case nones:
164 rd=fixedFromJulian({year, month, nonesOfMonth(month)});
165 break;
166 case ides:
167 rd=fixedFromJulian({year, month, idesOfMonth(month)});
168 break;
169 }
170 rd-=count;
171 if (!(JulianCalendar::isLeap(year) && (month==JulianCalendar::march) && (event==kalends) && (16>=count) && (count>=6)))
172 rd+=1;
173 rd+=leap;
174 return rd;
175 }
176
romanFromFixed(int rd)177 QVector<int> RomanCalendar::romanFromFixed(int rd)
178 {
179 const QVector<int>jdate=julianFromFixed(rd);
180 const int year=jdate.at(0);
181 const int month=jdate.at(1);
182 const int day=jdate.at(2);
183 const int monthP=StelUtils::amod(month+1, 12);
184 const int yearP=(monthP!=1 ? year : (year!=-1 ? year+1 : 1 ));
185 const int kalends1=fixedFromRoman({yearP, monthP, kalends, 1, false});
186
187 if (day==1)
188 return {year, month, kalends, 1, false};
189 else if (day<=nonesOfMonth(month))
190 return {year, month, nones, nonesOfMonth(month)-day+1, false};
191 else if (day<=idesOfMonth(month))
192 return {year, month, ides, idesOfMonth(month)-day+1, false};
193 else if (month!=february || !isLeap(year))
194 return {yearP, monthP, kalends, kalends1-rd+1, false};
195 else if (day<25)
196 return {year, march, kalends, 30-day, false};
197 else return {year, march, kalends, 31-day, day==25};
198 }
199
200 // Convert between AUC and Julian year numbers
aucYearFromJulian(int julianYear)201 int RomanCalendar::aucYearFromJulian(int julianYear)
202 {
203 if ((yearRomeFounded<=julianYear) && (julianYear<=-1))
204 return julianYear - yearRomeFounded + 1;
205 else
206 return julianYear - yearRomeFounded;
207 }
208
209 // return a Roman number (1...19)
romanNumber(const int num)210 QString RomanCalendar::romanNumber(const int num)
211 {
212 QStringList roman={"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX",
213 "X", "XI", "XII", "XIII", "XIV", "XV", "XVI", "XVII", "XVIII", "XIX"};
214 if (num>19) return QString::number(num); // "bogus";
215 if (num<1) return QString::number(num); // "bogus";
216 return roman.at(num);
217 }
218