12#include <QtCore/QByteArray>
13#include <QtCore/QPointF>
14#include <QtCore/qminmax.h>
15#include <QtCore/qnumeric.h>
16#include <QtGui/QVector3D>
30 if (
scene == _scene) {
34 disconnect(_scene,
nullptr,
this,
nullptr);
40 connect(_scene, &QObject::destroyed,
this, [
this] {
54 _points.reserve(coordinates.size());
55 _highlights.reserve(coordinates.size());
56 for (qsizetype i = 0; i < coordinates.size(); i++) {
57 const QGeoCoordinate coordinate = coordinates[i].value<QGeoCoordinate>();
58 if (coordinate.isValid()) {
59 _points.append(coordinate);
60 _highlights.append((i < highlights.size()) && highlights[i].toBool());
70 if (!coordinate.isValid()) {
73 _points.append(coordinate);
74 _highlights.append(
false);
75 if (_points.size() == 1) {
79 if (!_scene || (_points.size() < 3)) {
85 const qsizetype last = _points.size() - 1;
86 _positions.append(_positionFor(coordinate));
87 _segmentDirections.append(_segmentDirection(last - 1));
88 _vertexData.resize(_vertexData.size() + (2 *
kFloatsPerVertex *
static_cast<qsizetype
>(
sizeof(
float))));
89 _writeVertexPair(last - 1, _tangentAt(last - 1));
90 _writeVertexPair(last, _tangentAt(last));
91 _growBounds(_positions.last());
92 setVertexData(_vertexData);
93 setBounds(_minBounds, _maxBounds);
99 if (!coordinate.isValid() || _points.isEmpty()) {
102 _points.last() = coordinate;
103 if (_points.size() == 1) {
106 if (!_scene || (_points.size() < 2)) {
112 const qsizetype last = _points.size() - 1;
113 _positions.last() = _positionFor(coordinate);
114 _segmentDirections.last() = _segmentDirection(last - 1);
115 _writeVertexPair(last - 1, _tangentAt(last - 1));
116 _writeVertexPair(last, _tangentAt(last));
117 _growBounds(_positions.last());
118 const qsizetype offset = (last - 1) * 2 *
kFloatsPerVertex *
static_cast<qsizetype
>(
sizeof(
float));
119 const qsizetype length = 4 *
kFloatsPerVertex *
static_cast<qsizetype
>(
sizeof(float));
120 setVertexData(
static_cast<int>(offset), QByteArray(_vertexData.constData() + offset, length));
121 setBounds(_minBounds, _maxBounds);
127 if (_points.isEmpty()) {
137void FlightPathGeometry::_rebuild()
140 _segmentDirections.clear();
143 if (!_scene || (_points.size() < 2)) {
146 setVertexData(QByteArray());
147 setPrimitiveType(QQuick3DGeometry::PrimitiveType::TriangleStrip);
148 setBounds(QVector3D(), QVector3D());
153 _positions.reserve(_points.size());
154 for (
const QGeoCoordinate& point : _points) {
155 _positions.append(_positionFor(point));
158 _segmentDirections.reserve(_positions.size() - 1);
159 for (qsizetype i = 0; i < _positions.size() - 1; i++) {
160 _segmentDirections.append(_segmentDirection(i));
163 _vertexData.resize(_positions.size() * 2 *
kFloatsPerVertex *
static_cast<qsizetype
>(
sizeof(
float)));
164 _minBounds = _positions.first();
165 _maxBounds = _positions.first();
166 for (qsizetype i = 0; i < _positions.size(); i++) {
167 _writeVertexPair(i, _tangentAt(i));
168 _growBounds(_positions[i]);
173 setVertexData(_vertexData);
174 setPrimitiveType(QQuick3DGeometry::PrimitiveType::TriangleStrip);
175 addAttribute(QQuick3DGeometry::Attribute::PositionSemantic, 0, QQuick3DGeometry::Attribute::F32Type);
176 addAttribute(QQuick3DGeometry::Attribute::NormalSemantic, 3 *
sizeof(
float), QQuick3DGeometry::Attribute::F32Type);
177 addAttribute(QQuick3DGeometry::Attribute::TexCoord0Semantic, 6 *
sizeof(
float),
178 QQuick3DGeometry::Attribute::F32Type);
179 setBounds(_minBounds, _maxBounds);
184QVector3D FlightPathGeometry::_positionFor(
const QGeoCoordinate& coordinate)
const
186 const QGeoCoordinate& anchor = _points.first();
188 const double anchorAltitude = std::isfinite(anchor.altitude()) ? anchor.altitude() : 0.0;
191 return QVector3D(
static_cast<float>(world.x() - anchorWorld.x()),
static_cast<float>(world.y() - anchorWorld.y()),
192 static_cast<float>((altitude - anchorAltitude) * _scene->
verticalScale()));
197QVector3D FlightPathGeometry::_segmentDirection(qsizetype index)
const
199 const QVector3D direction = _positions[index + 1] - _positions[index];
200 if (!qFuzzyIsNull(direction.lengthSquared())) {
201 return direction.normalized();
203 return (index > 0) ? _segmentDirections[index - 1] : QVector3D(0.0f, 1.0f, 0.0f);
207QVector3D FlightPathGeometry::_tangentAt(qsizetype index)
const
211 direction = _segmentDirections.first();
212 }
else if (index == _positions.size() - 1) {
213 direction = _segmentDirections.last();
215 direction = _segmentDirections[index - 1] + _segmentDirections[index];
217 if (qFuzzyIsNull(direction.lengthSquared())) {
218 direction = _segmentDirections[index - 1];
220 direction.normalize();
224void FlightPathGeometry::_writeVertexPair(qsizetype index,
const QVector3D& tangent)
226 const QVector3D&
position = _positions[index];
227 const float highlight = _highlights[index] ? 1.0f : 0.0f;
228 float* vertex =
reinterpret_cast<float*
>(_vertexData.data()) + (index * 2 *
kFloatsPerVertex);
229 for (
const float side : {-1.0f, 1.0f}) {
233 *vertex++ = tangent.x();
234 *vertex++ = tangent.y();
235 *vertex++ = tangent.z();
237 *vertex++ = highlight;
241void FlightPathGeometry::_growBounds(
const QVector3D& position)
243 _minBounds = QVector3D(qMin(_minBounds.x(),
position.x()), qMin(_minBounds.y(),
position.y()),
244 qMin(_minBounds.z(),
position.z()));
245 _maxBounds = QVector3D(qMax(_maxBounds.x(),
position.x()), qMax(_maxBounds.y(),
position.y()),
246 qMax(_maxBounds.z(),
position.z()));
static constexpr int kFloatsPerVertex
position 3, tangent 3, side flag, highlight flag
FlightPathGeometry(QQuick3DObject *parent=nullptr)
void setScene(GeoScene *scene)
Q_INVOKABLE void setPath(const QVariantList &coordinates, const QVariantList &highlights=QVariantList())
Q_INVOKABLE void clearPath()
void anchorCoordinateChanged()
Q_INVOKABLE void appendPoint(const QGeoCoordinate &coordinate)
Q_INVOKABLE void updateLastPoint(const QGeoCoordinate &coordinate)
Replace the last point (TrajectoryPoints emits this for colinear motion)
qreal verticalScale() const
void sceneOriginChanged()
GPSPositionReport position(const GPSDecodedPosition &source, const GPSIntegrityReport &diagnostic, uint64_t nowUs)
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.