QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
GeoScene.cc
Go to the documentation of this file.
1/****************************************************************************
2 *
3 * (c) 2009-2024 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
4 *
5 * QGroundControl is licensed according to the terms in the file
6 * COPYING.md in the root of the source code directory.
7 *
8 ****************************************************************************/
9
10#include "GeoScene.h"
11
12#include <cmath>
13
14#include "GeoMapCamera.h"
15#include "QGCLoggingCategory.h"
16#include "TileMath.h"
17
18QGC_LOGGING_CATEGORY(GeoMapGeoSceneLog, "GeoMap.GeoScene")
19
20GeoScene::GeoScene(QObject* parent) : QObject(parent) {}
21
23{
24 if (camera == _camera) {
25 return;
26 }
27 qCDebug(GeoMapGeoSceneLog) << "camera" << (camera ? "set" : "cleared");
28 if (_camera) {
29 disconnect(_camera, nullptr, this, nullptr);
30 }
31 _camera = camera;
32 _originSet = false; // new camera anchors fresh; a stale origin breaks float precision silently
33
34 if (_camera) {
35 connect(_camera, &GeoMapCamera::centerChanged, this, &GeoScene::_maybeReanchor);
36 connect(_camera, &QObject::destroyed, this, [this] {
37 _camera = nullptr;
38 _originSet = false;
39 emit cameraChanged();
40 });
41 // Anchor before announcing: cameraChanged listeners must never see an
42 // origin inconsistent with the new camera
43 _maybeReanchor();
44 }
45 emit cameraChanged();
46}
47
49{
50 return TileMath::mercatorScale(TileMath::worldToGeo(_origin).latitude());
51}
52
54{
55 if (qFuzzyCompare(scale, _terrainScale)) {
56 return;
57 }
58 _terrainScale = scale;
60}
61
62void GeoScene::setContent3D(QObject* node)
63{
64 if (node == _content3D) {
65 return;
66 }
67 qCDebug(GeoMapGeoSceneLog) << "content3D" << (node ? "set" : "cleared");
68 if (_content3D) {
69 disconnect(_content3D, nullptr, this, nullptr);
70 }
71 _content3D = node;
72 if (_content3D) {
73 connect(_content3D, &QObject::destroyed, this, [this] {
74 _content3D = nullptr;
75 emit content3DChanged();
76 });
77 }
78 emit content3DChanged();
79}
80
81QVector3D GeoScene::scenePositionFor(const QGeoCoordinate& coordinate) const
82{
83 const QPointF world = TileMath::geoToWorld(coordinate);
84 const double altitude = std::isfinite(coordinate.altitude()) ? coordinate.altitude() : 0.0;
85 return QVector3D(static_cast<float>(world.x() - _origin.x()), static_cast<float>(world.y() - _origin.y()),
86 static_cast<float>(altitude * verticalScale()));
87}
88
89QVariant GeoScene::screenPositionFor(const QGeoCoordinate& coordinate) const
90{
91 if (!_camera) {
92 return {};
93 }
94 const QPointF world = TileMath::geoToWorld(coordinate);
95 const double altitude = std::isfinite(coordinate.altitude()) ? coordinate.altitude() : 0.0;
96 const auto screen = _camera->worldToScreen(world, altitude * verticalScale() * _terrainScale);
97 return screen ? QVariant(*screen) : QVariant();
98}
99
100QGeoCoordinate GeoScene::centerForCoordinateAtScreenPoint(const QGeoCoordinate& coordinate, const QPointF& screenPos,
101 double centerElevation) const
102{
103 if (!_camera) {
104 return {};
105 }
106 const double altitude = std::isfinite(coordinate.altitude()) ? coordinate.altitude() : 0.0;
107 const double pivotElevation =
108 std::isfinite(centerElevation) ? centerElevation * verticalScale() * _terrainScale : centerElevation;
109 return _camera->centerForCoordinateAtScreenPoint(coordinate, screenPos, altitude * verticalScale() * _terrainScale,
110 pivotElevation);
111}
112
113void GeoScene::_maybeReanchor()
114{
115 if (!_camera) {
116 return;
117 }
118 const QPointF cameraWorld = TileMath::geoToWorld(_camera->center());
119 if (_originSet) {
120 const QPointF offset = cameraWorld - _origin;
121 if (QPointF::dotProduct(offset, offset) < (kReanchorDistance * kReanchorDistance)) {
122 return;
123 }
124 }
125 _origin = cameraWorld;
126 _originSet = true;
127 qCDebug(GeoMapGeoSceneLog) << "scene origin re-anchored to" << _origin;
128 emit sceneOriginChanged();
129}
#define QGC_LOGGING_CATEGORY(name, categoryStr)
std::optional< QPointF > worldToScreen(const QPointF &worldGround, double worldZ=0.0) const
void centerChanged()
Q_INVOKABLE QGeoCoordinate centerForCoordinateAtScreenPoint(const QGeoCoordinate &coordinate, const QPointF &screenPos, double worldZ=0.0, double centerElevation=qQNaN()) const
QGeoCoordinate center() const
Q_INVOKABLE QGeoCoordinate centerForCoordinateAtScreenPoint(const QGeoCoordinate &coordinate, const QPointF &screenPos, double centerElevation=qQNaN()) const
Definition GeoScene.cc:100
qreal verticalScale() const
Definition GeoScene.cc:48
void sceneOriginChanged()
void terrainScaleChanged()
void setTerrainScale(qreal scale)
Definition GeoScene.cc:53
static constexpr double kReanchorDistance
scene-origin re-anchor threshold (m)
Definition GeoScene.h:47
Q_INVOKABLE QVector3D scenePositionFor(const QGeoCoordinate &coordinate) const
Definition GeoScene.cc:81
void cameraChanged()
void setContent3D(QObject *node)
Definition GeoScene.cc:62
GeoMapCamera * camera() const
Definition GeoScene.h:49
void content3DChanged()
void setCamera(GeoMapCamera *camera)
Definition GeoScene.cc:22
Q_INVOKABLE QVariant screenPositionFor(const QGeoCoordinate &coordinate) const
Definition GeoScene.cc:89
QPointF geoToWorld(const QGeoCoordinate &coord)
Geo -> world meters. Latitude is clamped to +/-kMaxLatitude.
Definition TileMath.cc:23
double mercatorScale(double latitude)
Definition TileMath.cc:38
QGeoCoordinate worldToGeo(const QPointF &world)
World meters -> geo (altitude 0)
Definition TileMath.cc:31