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