File: Geodesic.h

package info (click to toggle)
js8call 2.5.2%2Bds-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 24,720 kB
  • sloc: cpp: 562,651; sh: 898; python: 132; ansic: 102; makefile: 4
file content (158 lines) | stat: -rw-r--r-- 4,996 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#include <QString>
#include <QStringView>
#include <cmath>
#include <utility>

namespace Geodesic {
// Azimuth class, describes an azimuth in degrees. Created via
// interpolation of Maidenhead grid coordinates, and as such
// will be invalid if interpolation failed, typically due to
// bad coordinates.

class Azimuth {
    // Data members

    float m_value = NAN;

    // Constructors

    Azimuth() = default;
    Azimuth(float const value) : m_value{value} {}

    // Allow construction only by Vector.

    friend class Vector;

  public:
    // Allow copying, moving, and assignment by anyone.

    Azimuth(Azimuth const &) = default;
    Azimuth &operator=(Azimuth const &) = default;
    Azimuth(Azimuth &&) noexcept = default;
    Azimuth &operator=(Azimuth &&) noexcept = default;

    // Inline Accessors

    auto isValid() const { return !std::isnan(m_value); }

    // Conversion operators; return validity and value. These
    // are all we need to implement an ordering relation, but
    // we do so elsewhere.

    explicit operator bool() const noexcept { return isValid(); }
    operator float() const noexcept { return m_value; }

    // Return as a directional arrow and cardinal direction, if
    // valid, an empty string if invalid.

    QStringView compass() const;

    // String conversion, to the nearest whole degree; always
    // succeeds, returning an empty string if invalid. Caller
    // must specify if they want units or just a bare value.

    QString toString(bool units) const;
};

// Distance class, describes a distance in kilometers. Created via
// interpolation of Maidenhead grid coordinates, and as such will
// be invalid if interpolation failed, typically due to bad coordinates.
//
// May additionally be defined as 'close', meaning that either of the
// grids provided was only 4 characters and the computed distance was
// short, so we know it's close, but not just how close. In this case,
// the value will be a non-zero minimum constant, and string conversion
// will prepend a '<'.
//
// While distances are stored internally only in kilometers, caller may
// request string conversion in terms of statute miles.

class Distance {
    // Value, in kilometers, that we consider to be the close limit, so
    // if we're informed that we should consider the value for closeness,
    // i.e., one of the grids that gave rise to use is of at best square
    // magnitude, we'd consider any value at or under the limit to be of
    // only the limit in terms of precision.

    static constexpr float CLOSE = 120.0f;

    // Data members

    float m_value = NAN;

    // Constructors

    Distance() = default;
    Distance(float const value, bool const close)
        : m_value{close && CLOSE > value ? INFINITY : value} {}

    // Allow construction only by Vector.

    friend class Vector;

  public:
    // Allow copying, moving, and assignment by anyone.

    Distance(Distance const &) = default;
    Distance &operator=(Distance const &) = default;
    Distance(Distance &&) noexcept = default;
    Distance &operator=(Distance &&) noexcept = default;

    // Inline Accessors

    auto isValid() const { return !std::isnan(m_value); }
    auto isClose() const { return std::isinf(m_value); }

    // Conversion operators; return validity and value. These
    // are all we need to implement an ordering relation, but
    // we do so elsewhere.

    explicit operator bool() const noexcept { return isValid(); }
    operator float() const noexcept { return isClose() ? CLOSE : m_value; }

    // String conversion, to the nearest whole kilometer or mile,
    // always succeeds, returning an empty string if invalid. Caller
    // must specify if they want units or just the bare value.

    QString toString(bool miles, bool units) const;
};

// Vector class, aggregate of azimuth and distance from an
// origin grid to a remote grid.

class Vector {
    // Data members

    Azimuth m_azimuth;
    Distance m_distance;

    // Constructors; disallow creation without going through
    // the vector() function.

    Vector() = default;
    Vector(std::pair<float, float> const &azdist, bool const square)
        : m_azimuth{azdist.first}, m_distance{azdist.second, square} {}

    friend Vector vector(QStringView, QStringView);

  public:
    // Allow copying, moving, and assignment by anyone.

    Vector(Vector const &) = default;
    Vector &operator=(Vector const &) = default;
    Vector(Vector &&) noexcept = default;
    Vector &operator=(Vector &&) noexcept = default;

    // Inline accessors

    Azimuth const &azimuth() const { return m_azimuth; }
    Distance const &distance() const { return m_distance; }
};

// Creation method; manages a cache, returning cached data
// if possible. This gets called just a lot; performing the
// calculations needed to make a vector are not cheap, so
// we want to reuse results as much as possible.

Vector vector(QStringView origin, QStringView remote);
} // namespace Geodesic