6#include <QtCore/QDateTime>
7#include <QtCore/QTimeZone>
8#include <QtCore/QtMath>
25 const QDateTime timestamp =
27 ? QDateTime::fromMSecsSinceEpoch(
static_cast<qint64
>(navigation.
utcTimeUs / 1000), QTimeZone::UTC)
28 : QDateTime::currentDateTimeUtc();
31 const auto setAttribute = [&observation](QGeoPositionInfo::Attribute attribute,
double value,
bool allowZero) {
32 if (qIsFinite(value) && (value > 0 || (allowZero && value == 0))) {
33 observation.
position.setAttribute(attribute, value);
37 const auto accuracy = [](
float meters,
float dop) {
38 return qIsFinite(meters) && meters > 0 ? meters : (qIsFinite(dop) && dop > 0 ?
accuracyFromDop(dop) : qQNaN());
40 setAttribute(QGeoPositionInfo::HorizontalAccuracy,
42 setAttribute(QGeoPositionInfo::VerticalAccuracy,
46 const double degrees = std::fmod(qRadiansToDegrees(
static_cast<double>(navigation.
courseRadians)), 360.0);
47 observation.
position.setAttribute(QGeoPositionInfo::Direction, degrees < 0 ? degrees + 360.0 : degrees);
65 constexpr double MINIMUM_ACCURACY_METERS = 0.01;
70 if (qIsFinite(
position.latitudeDegrees) && qIsFinite(
position.longitudeDegrees) && qIsFinite(accuracyMeters)) {
73 QDateTime::currentDateTimeUtc());
74 observation.
position.setAttribute(QGeoPositionInfo::HorizontalAccuracy,
75 (std::max) (accuracyMeters, MINIMUM_ACCURACY_METERS));
77 if (qIsFinite(
position.altitudeMeters)) {
85 constexpr double USER_EQUIVALENT_RANGE_ERROR_METERS = 5.1;
86 constexpr double CONFIDENCE_SCALE = 2.0;
87 return dop * USER_EQUIVALENT_RANGE_ERROR_METERS * CONFIDENCE_SCALE;
102 if (accepted.
position.coordinate().type() != QGeoCoordinate::Coordinate3D) {
103 accepted.
position.removeAttribute(QGeoPositionInfo::VerticalAccuracy);
108 auto ellipsoidCoordinate = accepted.
position.coordinate();
110 accepted.
position.setCoordinate(ellipsoidCoordinate);
112 }
else if (!qIsFinite(accepted.
position.coordinate().altitude())) {
113 auto horizontalCoordinate = accepted.
position.coordinate();
114 horizontalCoordinate.setAltitude(qQNaN());
115 accepted.
position.setCoordinate(horizontalCoordinate);
116 accepted.
position.removeAttribute(QGeoPositionInfo::VerticalAccuracy);
123 const double course =
heading();
124 if (qIsFinite(course)) {
125 accepted.
position.setAttribute(QGeoPositionInfo::Direction, course);
127 accepted.
position.removeAttribute(QGeoPositionInfo::Direction);
128 accepted.
position.removeAttribute(QGeoPositionInfo::DirectionAccuracy);
141 const double accuracy =
position.attribute(QGeoPositionInfo::HorizontalAccuracy);
143 qIsFinite(accuracy) && accuracy > 0 && accuracy <= 100;
152 const double accuracy =
position.attribute(QGeoPositionInfo::VerticalAccuracy);
153 if (
position.hasAttribute(QGeoPositionInfo::VerticalAccuracy) && qIsFinite(accuracy) && accuracy > 0 &&
154 accuracy <= 10 && qIsFinite(
position.coordinate().altitude())) {
162 const double direction =
position.attribute(QGeoPositionInfo::Direction);
163 const double speed =
position.attribute(QGeoPositionInfo::GroundSpeed);
164 const double accuracy =
position.attribute(QGeoPositionInfo::DirectionAccuracy);
165 const bool accuracyAcceptable = !
position.hasAttribute(QGeoPositionInfo::DirectionAccuracy) ||
166 (qIsFinite(accuracy) && accuracy >= 0 && accuracy <= 30);
168 if (!
usable() || !
position.hasAttribute(QGeoPositionInfo::Direction) || !qIsFinite(direction) || direction < 0 ||
169 direction > 360 || !
position.hasAttribute(QGeoPositionInfo::GroundSpeed) || !qIsFinite(speed) || speed < 0.5 ||
170 !accuracyAcceptable) {
173 return direction == 360 ? 0 : direction;
WGS84 geodetic position with ellipsoid height, not mean-sea-level altitude.
std::optional< uint8_t > satellitesUsed
float verticalAccuracyMeters
float speedMetersPerSecond
float horizontalAccuracyMeters
double altitudeEllipsoidMeters
Receiver-independent data. Unknown metadata remains absent, never a manufactured zero.
std::optional< double > altitudeEllipsoidMeters
QGeoPositionInfo position
static GPSObservation fromSurveyedPosition(const GPSEllipsoidPosition &position, double accuracyMeters, quint64 receivedAtUs)
A known antenna position, such as a fixed or surveyed RTK base, which receivers report as a time-only...
static GPSObservation fromNavigation(const GPSNavigationValues &navigation, quint64 receivedAtUs)
Converts a native receiver solution that arrived at receivedAtUs on the monotonic clock.
QGeoCoordinate coordinate() const
std::optional< GPSObservation > projected(PositionUse use) const
The owner separately enforces freshness and session authorization.
std::optional< int > satellitesUsed
bool hasNavigationSolution() const
quint64 monotonicTimestampUs
GPSAltitudeDatum altitudeDatum
std::optional< bool > receiverFixValid
static double accuracyFromDop(double dop)
Nominal accuracy in meters for receivers that report only DOP (DOP x 5.1 m UERE x 2).
std::optional< double > horizontalDop