File indexing completed on 2024-04-21 14:43:59

0001 /*
0002     SPDX-FileCopyrightText: 2001-2005 Jason Harris <jharris@30doradus.org>
0003     SPDX-FileCopyrightText: 2003-2005 Pablo de Vicente <p.devicente@wanadoo.es>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "geolocation.h"
0009 
0010 #include "timezonerule.h"
0011 
0012 GeoLocation::GeoLocation(const dms &lng, const dms &lat, const QString &name, const QString &province, const QString &country,
0013                          double tz, TimeZoneRule *tzrule, double elevation, bool readOnly, int iEllips) :
0014     Longitude(lng), Latitude(lat)
0015 {
0016     Name           = name;
0017     Province       = province;
0018     Country        = country;
0019     TimeZone       = tz;
0020     TZrule         = tzrule;
0021     Elevation      = elevation;
0022     indexEllipsoid = iEllips;
0023     ReadOnly       = readOnly;
0024     setEllipsoid(indexEllipsoid);
0025     geodToCart();
0026 }
0027 
0028 GeoLocation::GeoLocation(double x, double y, double z, const QString &name, const QString &province,
0029                          const QString &country, double TZ, TimeZoneRule *tzrule, double elevation, bool readOnly, int iEllips)
0030 {
0031     PosCartX       = x;
0032     PosCartY       = y;
0033     PosCartZ       = z;
0034     Name           = name;
0035     Province       = province;
0036     Country        = country;
0037     TimeZone       = TZ;
0038     TZrule         = tzrule;
0039     Elevation      = elevation;
0040     indexEllipsoid = iEllips;
0041     ReadOnly       = readOnly;
0042     setEllipsoid(indexEllipsoid);
0043     cartToGeod();
0044 }
0045 
0046 QString GeoLocation::fullName() const
0047 {
0048     if (country().isEmpty())
0049         return translatedName();
0050     else if (province().isEmpty())
0051     {
0052         return QString("%1, %2").arg(translatedName(), translatedCountry());
0053     }
0054     else
0055     {
0056         return QString("%1, %2, %3").arg(translatedName(), translatedProvince(), translatedCountry());
0057     }
0058 }
0059 
0060 void GeoLocation::setEllipsoid(int i)
0061 {
0062     static const double A[] = { 6378140.0, 6378137.0, 6378137.0, 6378137.0, 6378136.0 };
0063     static const double F[] = { 0.0033528131779, 0.0033528106812, 0.0033528131779, 0.00335281066474, 0.0033528131779 };
0064 
0065     Q_ASSERT(i >= 0 && (unsigned int)i < sizeof(A) / sizeof(A[0]) && "Index must be in bounds");
0066     axis       = A[i];
0067     flattening = F[i];
0068 }
0069 
0070 void GeoLocation::changeEllipsoid(int index)
0071 {
0072     setEllipsoid(index);
0073     cartToGeod();
0074 }
0075 
0076 QString GeoLocation::translatedName() const
0077 {
0078     QString context;
0079     if (province().isEmpty())
0080     {
0081         context = QString("City in %1").arg(country());
0082     }
0083     else
0084     {
0085         context = QString("City in %1 %2").arg(province(), country());
0086     }
0087     return Name.isEmpty() ? QString() : i18nc(context.toUtf8().data(), Name.toUtf8().data());
0088 }
0089 
0090 QString GeoLocation::translatedProvince() const
0091 {
0092     return Province.isEmpty() ?
0093            QString() :
0094            i18nc(QString("Region/state in " + country()).toUtf8().data(), Province.toUtf8().data());
0095 }
0096 
0097 QString GeoLocation::translatedCountry() const
0098 {
0099     return Country.isEmpty() ? QString() : i18nc("Country name", Country.toUtf8().data());
0100 }
0101 
0102 void GeoLocation::cartToGeod()
0103 {
0104     static const double RIT = 2.7778e-6;
0105     double e2, rpro, lat1, xn, sqrtP2, latd, sinl;
0106 
0107     e2 = 2 * flattening - flattening * flattening;
0108 
0109     sqrtP2 = sqrt(PosCartX * PosCartX + PosCartY * PosCartY);
0110 
0111     rpro = PosCartZ / sqrtP2;
0112     latd = atan2(rpro, (1 - e2));
0113     lat1 = 0.;
0114 
0115     while (fabs(latd - lat1) > RIT)
0116     {
0117         double s1 = sin(latd);
0118 
0119         lat1 = latd;
0120         xn   = axis / (sqrt(1 - e2 * s1 * s1));
0121         latd = atan2(static_cast<long double>(rpro) * (1 + e2 * xn * s1), PosCartZ);
0122     }
0123 
0124     sinl = sin(latd);
0125     xn   = axis / (sqrt(1 - e2 * sinl * sinl));
0126 
0127     Elevation = sqrtP2 / cos(latd) - xn;
0128     Longitude.setRadians(atan2(PosCartY, PosCartX));
0129     Latitude.setRadians(latd);
0130 }
0131 
0132 void GeoLocation::geodToCart()
0133 {
0134     double e2, xn;
0135     double sinLong, cosLong, sinLat, cosLat;
0136 
0137     e2 = 2 * flattening - flattening * flattening;
0138 
0139     Longitude.SinCos(sinLong, cosLong);
0140     Latitude.SinCos(sinLat, cosLat);
0141 
0142     xn       = axis / (sqrt(1 - e2 * sinLat * sinLat));
0143     PosCartX = (xn + Elevation) * cosLat * cosLong;
0144     PosCartY = (xn + Elevation) * cosLat * sinLong;
0145     PosCartZ = (xn * (1 - e2) + Elevation) * sinLat;
0146 }
0147 
0148 void GeoLocation::TopocentricVelocity(double vtopo[], const dms &gst)
0149 {
0150     double Wearth = 7.29211510e-5; // rads/s
0151     dms angularVEarth;
0152 
0153     dms time = GSTtoLST(gst);
0154     // angularVEarth.setRadians(time.Hours()*Wearth*3600.);
0155     double se, ce;
0156     // angularVEarth.SinCos(se,ce);
0157     time.SinCos(se, ce);
0158 
0159     double d0 = sqrt(PosCartX * PosCartX + PosCartY * PosCartY);
0160     // km/s
0161     vtopo[0] = -d0 * Wearth * se / 1000.;
0162     vtopo[1] = d0 * Wearth * ce / 1000.;
0163     vtopo[2] = 0.;
0164 }
0165 
0166 double GeoLocation::LMST(double jd)
0167 {
0168     int divresult;
0169     double ut, tu, gmst, theta;
0170 
0171     ut = (jd + 0.5) - floor(jd + 0.5);
0172     jd -= ut;
0173     tu = (jd - 2451545.) / 36525.;
0174 
0175     gmst      = 24110.54841 + tu * (8640184.812866 + tu * (0.093104 - tu * 6.2e-6));
0176     divresult = (int)((gmst + 8.6400e4 * 1.00273790934 * ut) / 8.6400e4);
0177     gmst      = (gmst + 8.6400e4 * 1.00273790934 * ut) - (double)divresult * 8.6400e4;
0178     theta     = 2. * dms::PI * gmst / (24. * 60. * 60.);
0179     divresult = (int)((theta + Longitude.radians()) / (2. * dms::PI));
0180     return ((theta + Longitude.radians()) - (double)divresult * 2. * dms::PI);
0181 }
0182 
0183 bool GeoLocation::isReadOnly() const
0184 {
0185     return ReadOnly;
0186 }
0187 
0188 void GeoLocation::setReadOnly(bool value)
0189 {
0190     ReadOnly = value;
0191 }
0192 
0193 KStarsDateTime GeoLocation::UTtoLT(const KStarsDateTime &ut) const
0194 {
0195     KStarsDateTime lt = ut.addSecs(int(3600. * TZ()));
0196     // 2017-08-11 (Jasem): setUtcOffset is deprecated
0197     //lt.setUtcOffset(int(3600. * TZ()));
0198     lt.setTimeSpec(Qt::LocalTime);
0199 
0200     return lt;
0201 }
0202 
0203 KStarsDateTime GeoLocation::LTtoUT(const KStarsDateTime &lt) const
0204 {
0205     KStarsDateTime ut = lt.addSecs(int(-3600. * TZ()));
0206     ut.setTimeSpec(Qt::UTC);
0207     // 2017-08-11 (Jasem): setUtcOffset is deprecated
0208     //ut.setUtcOffset(0);
0209 
0210     return ut;
0211 }
0212 
0213 double GeoLocation::distanceTo(const dms &longitude, const dms &latitude)
0214 {
0215     const double R = 6378.135;
0216 
0217     double diffLongitude = (Longitude - longitude).radians();
0218     double diffLatitude  = (Latitude - latitude).radians();
0219 
0220     double a = sin(diffLongitude / 2) * sin(diffLongitude / 2) + cos(Longitude.radians()) * cos(longitude.radians()) *
0221                sin(diffLatitude / 2) * sin(diffLatitude / 2);
0222     double c = 2 * atan2(sqrt(a), sqrt(1 - a));
0223 
0224     double distance = R * c;
0225 
0226     return distance;
0227 }