1 /*
2 * Stellarium
3 * Copyright (C) 2002 Fabien Chereau (some old code from the Planet class)
4 * Copyright (C) 2010 Bogdan Marinov
5 * Copyright (C) 2013-14 Georg Zotti (accuracy&speedup)
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
20 */
21
22 #include "MinorPlanet.hpp"
23 #include "Orbit.hpp"
24
25 #include "StelApp.hpp"
26 #include "StelCore.hpp"
27 #include "StelObserver.hpp"
28
29 #include "StelTexture.hpp"
30 #include "StelTextureMgr.hpp"
31 #include "StelTranslator.hpp"
32 #include "StelUtils.hpp"
33 #include "StelFileMgr.hpp"
34 #include "RefractionExtinction.hpp"
35 #include "Orbit.hpp"
36
37 #include <QRegularExpression>
38 #include <QDebug>
39 #include <QElapsedTimer>
40
MinorPlanet(const QString & englishName,double radius,double oblateness,Vec3f halocolor,float albedo,float roughness,const QString & atexMapName,const QString & anormalMapName,const QString & aobjModelName,posFuncType coordFunc,KeplerOrbit * orbitPtr,OsculatingFunctType * osculatingFunc,bool acloseOrbit,bool hidden,const QString & pTypeStr)41 MinorPlanet::MinorPlanet(const QString& englishName,
42 double radius,
43 double oblateness,
44 Vec3f halocolor,
45 float albedo,
46 float roughness,
47 const QString& atexMapName,
48 const QString& anormalMapName,
49 const QString& aobjModelName,
50 posFuncType coordFunc,
51 KeplerOrbit* orbitPtr,
52 OsculatingFunctType *osculatingFunc,
53 bool acloseOrbit,
54 bool hidden,
55 const QString &pTypeStr)
56 : Planet (englishName,
57 radius,
58 oblateness,
59 halocolor,
60 albedo,
61 roughness,
62 atexMapName,
63 anormalMapName,
64 aobjModelName,
65 coordFunc,
66 orbitPtr,
67 osculatingFunc,
68 acloseOrbit,
69 hidden,
70 false, //No atmosphere
71 true, //Halo
72 pTypeStr),
73 minorPlanetNumber(0),
74 slopeParameter(-10.0f), // -10 == mark as uninitialized: used in getVMagnitude()
75 nameIsProvisionalDesignation(false),
76 properName(englishName),
77 b_v(99.f),
78 specT(""),
79 specB("")
80 {
81 //Try to handle an occasional naming conflict between a moon and asteroid. Conflicting names are also shown with appended *.
82 if (englishName.endsWith('*'))
83 properName = englishName.left(englishName.count() - 1);
84
85 //Try to detect provisional designation
86 QString provisionalDesignation = renderProvisionalDesignationinHtml(englishName);
87 if (!provisionalDesignation.isEmpty())
88 {
89 nameIsProvisionalDesignation = true;
90 provisionalDesignationHtml = provisionalDesignation;
91 }
92 }
93
~MinorPlanet()94 MinorPlanet::~MinorPlanet()
95 {
96 //Do nothing for the moment
97 }
98
setSpectralType(QString sT,QString sB)99 void MinorPlanet::setSpectralType(QString sT, QString sB)
100 {
101 specT = sT;
102 specB = sB;
103 }
104
setColorIndexBV(float bv)105 void MinorPlanet::setColorIndexBV(float bv)
106 {
107 b_v = bv;
108 }
109
setMinorPlanetNumber(int number)110 void MinorPlanet::setMinorPlanetNumber(int number)
111 {
112 if (minorPlanetNumber)
113 return;
114
115 minorPlanetNumber = number;
116 }
117
setAbsoluteMagnitudeAndSlope(const float magnitude,const float slope)118 void MinorPlanet::setAbsoluteMagnitudeAndSlope(const float magnitude, const float slope)
119 {
120 if (slope < -1.0f || slope > 2.0f)
121 {
122 // G "should" be between 0 and 1, but may be somewhat outside.
123 qDebug() << "MinorPlanet::setAbsoluteMagnitudeAndSlope(): Invalid slope parameter value (must be between -1 and 2, mostly [0..1])";
124 return;
125 }
126 absoluteMagnitude = magnitude;
127 slopeParameter = slope;
128 }
129
setProvisionalDesignation(QString designation)130 void MinorPlanet::setProvisionalDesignation(QString designation)
131 {
132 //TODO: This feature has to be implemented better, anyway.
133 if (!designation.isEmpty())
134 {
135 provisionalDesignationHtml = renderProvisionalDesignationinHtml(designation);
136 nameIsProvisionalDesignation = false;
137 }
138 }
139
getEnglishName() const140 QString MinorPlanet::getEnglishName() const
141 {
142 return (minorPlanetNumber ? QString("(%1) %2").arg(minorPlanetNumber).arg(englishName) : englishName);
143 }
144
getNameI18n() const145 QString MinorPlanet::getNameI18n() const
146 {
147 return (minorPlanetNumber ? QString("(%1) %2").arg(minorPlanetNumber).arg(nameI18) : nameI18);
148 }
149
getInfoStringName(const StelCore * core,const InfoStringGroup & flags) const150 QString MinorPlanet::getInfoStringName(const StelCore *core, const InfoStringGroup& flags) const
151 {
152 Q_UNUSED(core) Q_UNUSED(flags)
153 QString str;
154 QTextStream oss(&str);
155
156 oss << "<h2>";
157 if (nameIsProvisionalDesignation)
158 {
159 if (minorPlanetNumber)
160 oss << QString("(%1) ").arg(minorPlanetNumber);
161 oss << provisionalDesignationHtml;
162 }
163 else
164 oss << getNameI18n(); // UI translation can differ from sky translation
165 oss.setRealNumberNotation(QTextStream::FixedNotation);
166 oss.setRealNumberPrecision(1);
167 if (sphereScale != 1.)
168 oss << QString::fromUtf8(" (\xC3\x97") << sphereScale << ")";
169 oss << "</h2>";
170 if (!nameIsProvisionalDesignation && !provisionalDesignationHtml.isEmpty())
171 {
172 oss << QString(q_("Provisional designation: %1")).arg(provisionalDesignationHtml);
173 oss << "<br>";
174 }
175 return str;
176 }
177
getInfoStringExtraMag(const StelCore * core,const InfoStringGroup & flags) const178 QString MinorPlanet::getInfoStringExtraMag(const StelCore *core, const InfoStringGroup& flags) const
179 {
180 Q_UNUSED(core)
181 if (flags&Extra && b_v<99.f)
182 return QString("%1: <b>%2</b><br/>").arg(q_("Color Index (B-V)"), QString::number(b_v, 'f', 2));
183 else
184 return "";
185 }
186
getInfoStringExtra(const StelCore * core,const InfoStringGroup & flags) const187 QString MinorPlanet::getInfoStringExtra(const StelCore *core, const InfoStringGroup& flags) const
188 {
189 Q_UNUSED(core)
190 QString str;
191 QTextStream oss(&str);
192 if (flags&Extra)
193 {
194 if (!specT.isEmpty())
195 {
196 // TRANSLATORS: Tholen spectral taxonomic classification of asteroids
197 oss << QString("%1: %2<br/>").arg(q_("Tholen spectral type"), specT);
198 }
199
200 if (!specB.isEmpty())
201 {
202 // TRANSLATORS: SMASSII spectral taxonomic classification of asteroids
203 oss << QString("%1: %2<br/>").arg(q_("SMASSII spectral type"), specB);
204 }
205 }
206 return str;
207 }
208
getSiderealPeriod() const209 double MinorPlanet::getSiderealPeriod() const
210 {
211 return static_cast<KeplerOrbit*>(orbitPtr)->calculateSiderealPeriod();
212 }
213
getVMagnitude(const StelCore * core) const214 float MinorPlanet::getVMagnitude(const StelCore* core) const
215 {
216 //If the H-G system is not used, use the default radius/albedo mechanism
217 if (slopeParameter < -9.99f) // G can be somewhat <0! Set to -10 to mark invalid.
218 {
219 return Planet::getVMagnitude(core);
220 }
221
222 //Calculate phase angle
223 //(Code copied from Planet::getVMagnitude())
224 //(this is actually vector subtraction + the cosine theorem :))
225 const Vec3d& observerHelioPos = core->getObserverHeliocentricEclipticPos();
226 const float observerRq = static_cast<float>(observerHelioPos.lengthSquared());
227 const Vec3d& planetHelioPos = getHeliocentricEclipticPos();
228 const float planetRq = static_cast<float>(planetHelioPos.lengthSquared());
229 const float observerPlanetRq = static_cast<float>((observerHelioPos - planetHelioPos).lengthSquared());
230 const float cos_chi = (observerPlanetRq + planetRq - observerRq)/(2.0f*std::sqrt(observerPlanetRq*planetRq));
231 const float phaseAngle = std::acos(cos_chi);
232
233 //Calculate reduced magnitude (magnitude without the influence of distance)
234 //Source of the formulae: http://www.britastro.org/asteroids/dymock4.pdf
235 // Same model as in Explanatory Supplement 2013, p.423
236 const float tanPhaseAngleHalf=std::tan(phaseAngle*0.5f);
237 const float phi1 = std::exp(-3.33f * std::pow(tanPhaseAngleHalf, 0.63f));
238 const float phi2 = std::exp(-1.87f * std::pow(tanPhaseAngleHalf, 1.22f));
239 float reducedMagnitude = absoluteMagnitude - 2.5f * std::log10( (1.0f - slopeParameter) * phi1 + slopeParameter * phi2 );
240
241 //Calculate apparent magnitude
242 float apparentMagnitude = reducedMagnitude + 5.0f * std::log10(std::sqrt(planetRq * observerPlanetRq));
243
244 return apparentMagnitude;
245 }
246
translateName(const StelTranslator & translator)247 void MinorPlanet::translateName(const StelTranslator &translator)
248 {
249 nameI18 = translator.qtranslate(properName, "minor planet");
250 if (englishName.endsWith('*'))
251 {
252 nameI18.append('*');
253 }
254 }
255
renderProvisionalDesignationinHtml(QString plainTextName)256 QString MinorPlanet::renderProvisionalDesignationinHtml(QString plainTextName)
257 {
258 QRegularExpression provisionalDesignationPattern("^(\\d{4}\\s[A-Z]{2})(\\d*)$");
259 QRegularExpressionMatch match=provisionalDesignationPattern.match(plainTextName);
260 if (plainTextName.indexOf(provisionalDesignationPattern) == 0)
261 {
262 QString main = match.captured(1);
263 QString suffix = match.captured(2);
264 if (!suffix.isEmpty())
265 {
266 return (QString("%1<sub>%2</sub>").arg(main).arg(suffix));
267 }
268 else
269 {
270 return main;
271 }
272 }
273 else
274 {
275 return QString();
276 }
277 }
278
279