File indexing completed on 2024-04-21 14:46:43
0001 /* 0002 SPDX-FileCopyrightText: 2001 Jason Harris <jharris@30doradus.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "ksplanetbase.h" 0008 0009 #include "ksnumbers.h" 0010 #include "kstarsdata.h" 0011 #include "ksutils.h" 0012 #include "Options.h" 0013 #include "skymap.h" 0014 #include "ksasteroid.h" 0015 #include "kscomet.h" 0016 #include "ksmoon.h" 0017 #include "ksplanet.h" 0018 #include "kssun.h" 0019 #include "texturemanager.h" 0020 #include "skycomponents/skymapcomposite.h" 0021 0022 QVector<QColor> KSPlanetBase::planetColor = QVector<QColor>() << QColor("slateblue") << //Mercury 0023 QColor("lightgreen") << //Venus 0024 QColor("red") << //Mars 0025 QColor("goldenrod") << //Jupiter 0026 QColor("khaki") << //Saturn 0027 QColor("lightseagreen") << //Uranus 0028 QColor("skyblue") << //Neptune 0029 QColor("grey") << //Pluto 0030 QColor("yellow") << //Sun 0031 QColor("white"); //Moon 0032 0033 const SkyObject::UID KSPlanetBase::UID_SOL_BIGOBJ = 0; 0034 const SkyObject::UID KSPlanetBase::UID_SOL_ASTEROID = 1; 0035 const SkyObject::UID KSPlanetBase::UID_SOL_COMET = 2; 0036 0037 KSPlanetBase::KSPlanetBase(const QString &s, const QString &image_file, const QColor &c, double pSize) 0038 : TrailObject(2, 0.0, 0.0, 0.0, s) 0039 { 0040 init(s, image_file, c, pSize); 0041 } 0042 0043 void KSPlanetBase::init(const QString &s, const QString &image_file, const QColor &c, double pSize) 0044 { 0045 m_image = TextureManager::getImage(image_file); 0046 PositionAngle = 0.0; 0047 PhysicalSize = pSize; 0048 m_Color = c; 0049 setName(s); 0050 setLongName(s); 0051 } 0052 0053 KSPlanetBase *KSPlanetBase::createPlanet(int n) 0054 { 0055 switch (n) 0056 { 0057 case KSPlanetBase::MERCURY: 0058 case KSPlanetBase::VENUS: 0059 case KSPlanetBase::MARS: 0060 case KSPlanetBase::JUPITER: 0061 case KSPlanetBase::SATURN: 0062 case KSPlanetBase::URANUS: 0063 case KSPlanetBase::NEPTUNE: 0064 return new KSPlanet(n); 0065 /*case KSPlanetBase::PLUTO: 0066 return new KSPluto(); 0067 break;*/ 0068 case KSPlanetBase::SUN: 0069 return new KSSun(); 0070 case KSPlanetBase::MOON: 0071 return new KSMoon(); 0072 } 0073 return nullptr; 0074 } 0075 0076 void KSPlanetBase::EquatorialToEcliptic(const CachingDms *Obliquity) 0077 { 0078 findEcliptic(Obliquity, ep.longitude, ep.latitude); 0079 } 0080 0081 void KSPlanetBase::EclipticToEquatorial(const CachingDms *Obliquity) 0082 { 0083 setFromEcliptic(Obliquity, ep.longitude, ep.latitude); 0084 } 0085 0086 void KSPlanetBase::updateCoords(const KSNumbers *num, bool includePlanets, const CachingDms *lat, const CachingDms *LST, 0087 bool) 0088 { 0089 KStarsData *kd = KStarsData::Instance(); 0090 0091 if (kd == nullptr || !includePlanets) 0092 return; 0093 0094 kd->skyComposite()->earth()->findPosition(num); //since we don't pass lat & LST, localizeCoords will be skipped 0095 0096 if (lat && LST) 0097 { 0098 findPosition(num, lat, LST, kd->skyComposite()->earth()); 0099 // Don't add to the trail this time 0100 if (hasTrail()) 0101 Trail.takeLast(); 0102 } 0103 else 0104 { 0105 findGeocentricPosition(num, kd->skyComposite()->earth()); 0106 } 0107 } 0108 0109 void KSPlanetBase::findPosition(const KSNumbers *num, const CachingDms *lat, const CachingDms *LST, 0110 const KSPlanetBase *Earth) 0111 { 0112 0113 lastPrecessJD = num->julianDay(); 0114 0115 findGeocentricPosition(num, Earth); //private function, reimplemented in each subclass 0116 findPhase(); 0117 setAngularSize(findAngularSize()); //angular size in arcmin 0118 0119 if (lat && LST) 0120 localizeCoords(num, lat, LST); //correct for figure-of-the-Earth 0121 0122 if (hasTrail()) 0123 { 0124 addToTrail(KStarsDateTime(num->getJD()).toString("yyyy.MM.dd hh:mm") + 0125 i18nc("Universal time", "UT")); // TODO: Localize date/time format? 0126 if (Trail.size() > TrailObject::MaxTrail) 0127 clipTrail(); 0128 } 0129 0130 findMagnitude(num); 0131 0132 if (type() == SkyObject::COMET) 0133 { 0134 // Compute tail size 0135 KSComet *me = static_cast<KSComet *>(this); 0136 double comaAngSize; 0137 // Convert the tail size in km to angular tail size (degrees) 0138 comaAngSize = asin(physicalSize() / Rearth / AU_KM) * 60.0 * 180.0 / dms::PI; 0139 // Find the apparent length as projected on the celestial sphere (the comet's tail points away from the sun) 0140 me->setComaAngSize(comaAngSize * fabs(sin(phase().radians()))); 0141 } 0142 } 0143 0144 bool KSPlanetBase::isMajorPlanet() const 0145 { 0146 if (name() == i18n("Mercury") || name() == i18n("Venus") || name() == i18n("Mars") || name() == i18n("Jupiter") || 0147 name() == i18n("Saturn") || name() == i18n("Uranus") || name() == i18n("Neptune")) 0148 return true; 0149 return false; 0150 } 0151 0152 void KSPlanetBase::localizeCoords(const KSNumbers *num, const CachingDms *lat, const CachingDms *LST) 0153 { 0154 //convert geocentric coordinates to local apparent coordinates (topocentric coordinates) 0155 dms HA, HA2; //Hour Angle, before and after correction 0156 double rsinp, rcosp, u, sinHA, cosHA, sinDec, cosDec, D; 0157 double cosHA2; 0158 double r = Rearth * AU_KM; //distance from Earth, in km 0159 u = atan(0.996647 * tan(lat->radians())); 0160 rsinp = 0.996647 * sin(u); 0161 rcosp = cos(u); 0162 HA.setD(LST->Degrees() - ra().Degrees()); 0163 HA.SinCos(sinHA, cosHA); 0164 dec().SinCos(sinDec, cosDec); 0165 0166 D = atan2(rcosp * sinHA, r * cosDec / 6378.14 - rcosp * cosHA); 0167 dms temp; 0168 temp.setRadians(ra().radians() - D); 0169 setRA(temp); 0170 0171 HA2.setD(LST->Degrees() - ra().Degrees()); 0172 cosHA2 = cos(HA2.radians()); 0173 0174 //temp.setRadians( atan2( cosHA2*( r*sinDec/6378.14 - rsinp ), r*cosDec*cosHA/6378.14 - rcosp ) ); 0175 // The atan2() version above makes the planets move crazy in the htm branch -jbb 0176 temp.setRadians(atan(cosHA2 * (r * sinDec / 6378.14 - rsinp) / (r * cosDec * cosHA / 6378.14 - rcosp))); 0177 0178 setDec(temp); 0179 0180 //Make sure Dec is between -90 and +90 0181 if (dec().Degrees() > 90.0) 0182 { 0183 setDec(180.0 - dec().Degrees()); 0184 setRA(ra().Hours() + 12.0); 0185 ra().reduce(); 0186 } 0187 if (dec().Degrees() < -90.0) 0188 { 0189 setDec(180.0 + dec().Degrees()); 0190 setRA(ra().Hours() + 12.0); 0191 ra().reduce(); 0192 } 0193 0194 EquatorialToEcliptic(num->obliquity()); 0195 } 0196 0197 void KSPlanetBase::setRearth(const KSPlanetBase *Earth) 0198 { 0199 double sinL, sinB, sinL0, sinB0; 0200 double cosL, cosB, cosL0, cosB0; 0201 double x, y, z; 0202 0203 //The Moon's Rearth is set in its findGeocentricPosition()... 0204 if (name() == i18n("Moon")) 0205 { 0206 return; 0207 } 0208 0209 if (name() == i18n("Earth")) 0210 { 0211 Rearth = 0.0; 0212 return; 0213 } 0214 0215 if (!Earth) 0216 { 0217 qDebug() << Q_FUNC_INFO << "KSPlanetBase::setRearth(): Error: Need an Earth pointer. (" << name() << ")"; 0218 Rearth = 1.0; 0219 return; 0220 } 0221 0222 Earth->ecLong().SinCos(sinL0, cosL0); 0223 Earth->ecLat().SinCos(sinB0, cosB0); 0224 double eX = Earth->rsun() * cosB0 * cosL0; 0225 double eY = Earth->rsun() * cosB0 * sinL0; 0226 double eZ = Earth->rsun() * sinB0; 0227 0228 helEcLong().SinCos(sinL, cosL); 0229 helEcLat().SinCos(sinB, cosB); 0230 x = rsun() * cosB * cosL - eX; 0231 y = rsun() * cosB * sinL - eY; 0232 z = rsun() * sinB - eZ; 0233 0234 Rearth = sqrt(x * x + y * y + z * z); 0235 0236 //Set angular size, in arcmin 0237 AngularSize = asin(PhysicalSize / Rearth / AU_KM) * 60. * 180. / dms::PI; 0238 } 0239 0240 void KSPlanetBase::findPA(const KSNumbers *num) 0241 { 0242 //Determine position angle of planet (assuming that it is aligned with 0243 //the Ecliptic, which is only roughly correct). 0244 //Displace a point along +Ecliptic Latitude by 1 degree 0245 SkyPoint test; 0246 dms newELat(ecLat().Degrees() + 1.0); 0247 test.setFromEcliptic(num->obliquity(), ecLong(), newELat); 0248 double dx = ra().Degrees() - test.ra().Degrees(); 0249 double dy = test.dec().Degrees() - dec().Degrees(); 0250 double pa; 0251 if (dy) 0252 { 0253 pa = atan2(dx, dy) * 180.0 / dms::PI; 0254 } 0255 else 0256 { 0257 pa = dx < 0 ? 90.0 : -90.0; 0258 } 0259 setPA(pa); 0260 } 0261 0262 double KSPlanetBase::labelOffset() const 0263 { 0264 double size = angSize() * dms::PI * Options::zoomFactor() / 10800.0; 0265 0266 //Determine minimum size for offset 0267 double minsize = 4.; 0268 if (type() == SkyObject::ASTEROID || type() == SkyObject::COMET) 0269 minsize = 2.; 0270 if (name() == i18n("Sun") || name() == i18n("Moon")) 0271 minsize = 8.; 0272 if (size < minsize) 0273 size = minsize; 0274 0275 //Inflate offset for Saturn 0276 if (name() == i18n("Saturn")) 0277 size = int(2.5 * size); 0278 0279 return 0.5 * size + 4.; 0280 } 0281 0282 void KSPlanetBase::findPhase() 0283 { 0284 if (2 * rsun()*rearth() == 0) 0285 { 0286 Phase = std::numeric_limits<double>::quiet_NaN(); 0287 return; 0288 } 0289 /* Compute the phase of the planet in degrees */ 0290 double earthSun = KStarsData::Instance()->skyComposite()->earth()->rsun(); 0291 double cosPhase = (rsun() * rsun() + rearth() * rearth() - earthSun * earthSun) / (2 * rsun() * rearth()); 0292 0293 Phase = acos(cosPhase) * 180.0 / dms::PI; 0294 /* More elegant way of doing it, but requires the Sun. 0295 TODO: Switch to this if and when we make KSSun a singleton */ 0296 // Phase = ecLong()->Degrees() - Sun->ecLong()->Degrees(); 0297 }