QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
GeoMapProjectedPath.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 "GeoMapProjectedPath.h"
11
12#include <cmath>
13
14#include "GeoMapCamera.h"
15#include "GeoScene.h"
16#include "SurfacePatchModel.h"
17#include "TileMath.h"
18
19GeoMapProjectedPath::GeoMapProjectedPath(QObject* parent) : QObject(parent) {}
20
21void GeoMapProjectedPath::setCoordinates(const QVariantList& coordinates)
22{
23 if (coordinates == _coordinates) {
24 return;
25 }
26 _coordinates = coordinates;
27 _rebuild();
28 emit coordinatesChanged();
29}
30
32{
33 if (scene == _scene) {
34 return;
35 }
36 if (_scene) {
37 disconnect(_scene, nullptr, this, nullptr);
38 }
39 _scene = scene;
40 if (_scene) {
41 connect(_scene, &GeoScene::sceneOriginChanged, this, &GeoMapProjectedPath::_rebuild);
42 connect(_scene, &GeoScene::terrainScaleChanged, this, &GeoMapProjectedPath::_rebuild);
43 connect(_scene, &GeoScene::cameraChanged, this, &GeoMapProjectedPath::_connectCamera);
44 connect(_scene, &QObject::destroyed, this, [this] {
45 _scene = nullptr;
46 _connectCamera();
47 emit sceneChanged();
48 });
49 }
50 _connectCamera();
51 emit sceneChanged();
52}
53
55{
56 if (surfaceModel == _surfaceModel) {
57 return;
58 }
59 if (_surfaceModel) {
60 disconnect(_surfaceModel, nullptr, this, nullptr);
61 }
62 _surfaceModel = surfaceModel;
63 if (_surfaceModel) {
64 connect(_surfaceModel, &SurfacePatchModel::terrainHeightsChanged, this,
65 &GeoMapProjectedPath::_terrainHeightsChanged);
66 connect(_surfaceModel, &QObject::destroyed, this, [this] {
67 _surfaceModel = nullptr;
68 _rebuild();
70 });
71 }
72 _rebuild();
74}
75
77{
78 if (mode == _altitudeMode) {
79 return;
80 }
81 _altitudeMode = mode;
82 _rebuild();
84}
85
86void GeoMapProjectedPath::_connectCamera()
87{
88 GeoMapCamera* const camera = _scene ? _scene->camera() : nullptr;
89 if (camera == _connectedCamera) {
90 _rebuild();
91 return;
92 }
93 if (_connectedCamera) {
94 disconnect(_connectedCamera, nullptr, this, nullptr);
95 }
96 _connectedCamera = camera;
97 if (_connectedCamera) {
98 connect(_connectedCamera, &GeoMapCamera::scenePoseChanged, this, &GeoMapProjectedPath::_rebuild);
99 connect(_connectedCamera, &GeoMapCamera::viewportSizeChanged, this, &GeoMapProjectedPath::_rebuild);
100 connect(_connectedCamera, &GeoMapCamera::fieldOfViewChanged, this, &GeoMapProjectedPath::_rebuild);
101 connect(_connectedCamera, &QObject::destroyed, this, [this] {
102 _connectedCamera = nullptr;
103 _rebuild();
104 });
105 }
106 _rebuild();
107}
108
109void GeoMapProjectedPath::_terrainHeightsChanged()
110{
111 if (_altitudeMode == GeoMapItem::AltitudeMode::ClampToGround) {
112 _rebuild();
113 }
114}
115
116void GeoMapProjectedPath::_rebuild()
117{
118 QVariantList points;
119 points.reserve(_coordinates.size());
120 bool allProjected = !_coordinates.isEmpty();
121
122 GeoMapCamera* const camera = _scene ? _scene->camera() : nullptr;
123
124 for (const QVariant& variant : std::as_const(_coordinates)) {
125 const QGeoCoordinate coordinate = variant.value<QGeoCoordinate>();
126 if (!_scene || !camera || !coordinate.isValid()) {
127 allProjected = false;
128 continue;
129 }
130
131 double altitude = 0.0;
132 if (_altitudeMode == GeoMapItem::AltitudeMode::Absolute) {
133 altitude = std::isfinite(coordinate.altitude()) ? coordinate.altitude() : 0.0;
134 } else if (_surfaceModel) {
135 altitude = _surfaceModel->terrainHeightAt(coordinate);
136 }
137
138 const QPointF world = TileMath::geoToWorld(coordinate);
139 const double sceneZ = altitude * _scene->verticalScale() * _scene->terrainScale();
140 const auto screen = camera->worldToScreen(world, sceneZ);
141 if (!screen) {
142 allProjected = false;
143 continue;
144 }
145 points.append(*screen);
146 }
147
148 if (points != _screenPoints) {
149 _screenPoints = points;
150 emit screenPointsChanged();
151 }
152 if (allProjected != _projected) {
153 _projected = allProjected;
154 emit projectedChanged();
155 }
156}
157
158QVariantList GeoMapProjectedPath::circleCoordinates(const QGeoCoordinate& center, double radiusMeters, int segments)
159{
160 QVariantList coordinates;
161 if (!center.isValid() || radiusMeters <= 0.0 || segments < 3) {
162 return coordinates;
163 }
164 coordinates.reserve(segments + 1);
165 for (int i = 0; i <= segments; ++i) {
166 const double azimuth = (360.0 * i) / segments;
167 coordinates.append(QVariant::fromValue(center.atDistanceAndAzimuth(radiusMeters, azimuth)));
168 }
169 return coordinates;
170}
std::optional< QPointF > worldToScreen(const QPointF &worldGround, double worldZ=0.0) const
void scenePoseChanged()
void fieldOfViewChanged()
void viewportSizeChanged()
AltitudeMode
How the coordinate's vertical position is resolved.
Definition GeoMapItem.h:60
@ ClampToGround
sit on the rendered terrain surface (default)
@ Absolute
use coordinate.altitude (NaN treated as 0)
GeoMapProjectedPath(QObject *parent=nullptr)
void setScene(GeoScene *scene)
GeoScene * scene() const
QVariantList coordinates() const
SurfacePatchModel * surfaceModel() const
void setCoordinates(const QVariantList &coordinates)
static Q_INVOKABLE QVariantList circleCoordinates(const QGeoCoordinate &center, double radiusMeters, int segments=32)
void setSurfaceModel(SurfacePatchModel *surfaceModel)
void setAltitudeMode(GeoMapItem::AltitudeMode mode)
qreal verticalScale() const
Definition GeoScene.cc:48
void sceneOriginChanged()
qreal terrainScale() const
Definition GeoScene.h:67
void terrainScaleChanged()
void cameraChanged()
GeoMapCamera * camera() const
Definition GeoScene.h:49
void terrainHeightsChanged()
terrainHeightAt answers changed somewhere: consumers re-query
Q_INVOKABLE double terrainHeightAt(const QGeoCoordinate &coordinate) const
std::optional< double > coordinate(std::string_view field, std::string_view hemisphere, bool latitude)
QPointF geoToWorld(const QGeoCoordinate &coord)
Geo -> world meters. Latitude is clamped to +/-kMaxLatitude.
Definition TileMath.cc:23