swift
earthangle.cpp
1 // SPDX-FileCopyrightText: Copyright (C) 2013 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
4 #include "misc/geo/earthangle.h"
5 
6 #include <QRegularExpression>
7 #include <Qt>
8 #include <QtGlobal>
9 
10 #include "misc/geo/latitude.h"
11 #include "misc/geo/longitude.h"
12 #include "misc/pq/units.h"
13 
14 using namespace swift::misc::physical_quantities;
15 
16 namespace swift::misc::geo
17 {
18  template <class LATorLON>
20  {
22  return *this;
23  }
24 
25  template <class LATorLON>
27  {
29  return *this;
30  }
31 
32  template <class LATorLON>
34  {
36  return *this;
37  }
38 
39  template <class LATorLON>
40  LATorLON CEarthAngle<LATorLON>::operator+(const CEarthAngle &latOrLon) const
41  {
42  LATorLON l(*this);
43  l += latOrLon;
44  return l;
45  }
46 
47  template <class LATorLON>
48  LATorLON CEarthAngle<LATorLON>::operator-(const CEarthAngle &latOrLon) const
49  {
50  LATorLON l(*this);
51  l -= latOrLon;
52  return l;
53  }
54 
55  template <class LATorLON>
56  LATorLON CEarthAngle<LATorLON>::operator*(double multiply) const
57  {
58  LATorLON l(*this);
59  l *= multiply;
60  return l;
61  }
62 
63  template <class LATorLON>
64  LATorLON CEarthAngle<LATorLON>::fromWgs84(const QString &wgsCoordinate)
65  {
66  const QString wgs = wgsCoordinate.simplified().trimmed();
67  if (wgs.isEmpty()) { return LATorLON(); }
68 
69  // support for 5deg, 1.2rad
70  if (CAngleUnit::deg().endsStringWithNameOrSymbol(wgs) || CAngleUnit::rad().endsStringWithNameOrSymbol(wgs))
71  {
72  LATorLON latOrLon;
73  latOrLon.parseFromString(wgs);
74  return latOrLon;
75  }
76 
77  // number only -> parsed as degrees
78  bool isDouble;
79  const double valueDegrees = wgs.toDouble(&isDouble);
80  if (isDouble)
81  {
82  CAngle a(valueDegrees, CAngleUnit::deg());
83  return LATorLON(a);
84  }
85 
86  // http://www.regular-expressions.info/floatingpoint.html
87  thread_local const QRegularExpression rx("[+-]?\\d+(?:\\.\\d+)?");
88  int deg = 0;
89  int min = 0;
90  double sec = 0.0;
91  int c = 0;
92  QRegularExpressionMatchIterator i = rx.globalMatch(wgs);
93  while (i.hasNext() && c < 3)
94  {
95  const QRegularExpressionMatch match = i.next();
96  bool ok;
97  if (match.hasMatch())
98  {
99  const QString cap = match.captured(0);
100  switch (c++)
101  {
102  case 0: deg = cap.toInt(&ok); break;
103  case 1: min = cap.toInt(&ok); break;
104  case 2: sec = cap.toDouble(&ok); break;
105  default: break;
106  }
107  }
108  Q_UNUSED(ok); // ok for debugging purposes
109  }
110 
111  if (wgs.contains('S', Qt::CaseInsensitive) || wgs.contains('W', Qt::CaseInsensitive))
112  {
113  deg *= -1;
114  min *= -1;
115  sec *= -1;
116  }
117 
118  physical_quantities::CAngle a(deg, min, sec);
119  return LATorLON(a);
120  }
121 
122  template <class LATorLON>
124  : physical_quantities::CAngle(0.0, swift::misc::physical_quantities::CAngleUnit::deg())
125  {}
126 
127  template <class LATorLON>
129  : physical_quantities::CAngle(value, unit)
130  {}
131 
132  template <class LATorLON>
134  : physical_quantities::CAngle(angle)
135  {}
136 
137  template <class LATorLON>
139  {
140  return this->valueRoundedWithUnit(swift::misc::physical_quantities::CAngleUnit::deg(), 6, i18n);
141  }
142 
143  template <class LATorLON>
144  LATorLON const *CEarthAngle<LATorLON>::derived() const
145  {
146  return static_cast<LATorLON const *>(this);
147  }
148 
149  template <class LATorLON>
150  LATorLON *CEarthAngle<LATorLON>::derived()
151  {
152  return static_cast<LATorLON *>(this);
153  }
154 
155  template <class LATorLON>
157  {
158  return CIcons::GeoPosition;
159  }
160 
161  template <class LATorLON>
162  QString CEarthAngle<LATorLON>::toWgs84(const QChar pos, const QChar neg, int fractionalDigits) const
163  {
164  const CAngle::DegMinSecFractionalSec v = this->asSexagesimalDegMinSec(true);
165  const QChar pn = v.sign < 0 ? neg : pos;
166 
167  static const QString vs("%1° %2' %3\" %4");
168  if (fractionalDigits < 1) { return vs.arg(v.deg).arg(v.min).arg(v.sec).arg(pn); }
169 
170  static const QString vsf("%1° %2' %3.%4\" %5");
171  return vsf.arg(v.deg).arg(v.min).arg(v.sec).arg(v.fractionalSecAsString(fractionalDigits)).arg(pn);
172  }
173 
174  // see here for the reason of thess forward instantiations
175  // https://isocpp.org/wiki/faq/templates#separate-template-fn-defn-from-decl
177  template class CEarthAngle<CLatitude>;
178  template class CEarthAngle<CLongitude>;
180 
181 } // namespace swift::misc::geo
IconIndex
Index for each icon, allows to send them via DBus, efficiently store them, etc.
Definition: icons.h:32
Base class for latitude / longitude.
Definition: earthangle.h:21
CIcons::IconIndex toIcon() const
As icon, not implemented by all classes.
Definition: earthangle.cpp:156
QString toWgs84(const QChar pos, const QChar neg, int fractionalDigits=3) const
To WGS84 string.
Definition: earthangle.cpp:162
CEarthAngle()
Default constructor.
Definition: earthangle.cpp:123
QString convertToQString(bool i18n=false) const
Cast as QString.
Definition: earthangle.cpp:138
Physical unit angle (radians, degrees)
Definition: angle.h:23
Specialized class for angles (degrees, radian).
Definition: units.h:233
static CAngleUnit rad()
Radians.
Definition: units.h:270
static CAngleUnit deg()
Degrees.
Definition: units.h:278
CPhysicalQuantity & operator+=(const CPhysicalQuantity &other)
Plus operator +=.
CPhysicalQuantity & operator-=(const CPhysicalQuantity &other)
Minus operator-=.
CPhysicalQuantity & operator*=(double multiply)
Multiply operator *=.
QString fractionalSecAsString(int width=-1) const
Fractional seconds as string.
Definition: angle.h:53