Marble

GeoDataTrack.cpp
1// SPDX-License-Identifier: LGPL-2.1-or-later
2//
3// SPDX-FileCopyrightText: 2011 Guillaume Martres <smarter@ubuntu.com>
4//
5
6#include "GeoDataTrack.h"
7#include "GeoDataGeometry_p.h"
8
9#include "GeoDataLatLonAltBox.h"
10#include "GeoDataTypes.h"
11#include "MarbleDebug.h"
12
13#include "GeoDataExtendedData.h"
14#include "GeoDataLineString.h"
15
16#include <QDateTime>
17#include <QMap>
18
19namespace Marble
20{
21
22class GeoDataTrackPrivate : public GeoDataGeometryPrivate
23{
24public:
25 GeoDataTrackPrivate()
26 : m_lineStringNeedsUpdate(false)
27 , m_interpolate(false)
28 {
29 }
30
31 GeoDataGeometryPrivate *copy() const override
32 {
33 return new GeoDataTrackPrivate(*this);
34 }
35
36 void equalizeWhenSize()
37 {
38 m_when.reserve(m_coordinates.size());
39 while (m_when.size() < m_coordinates.size()) {
40 // fill coordinates without time information with null QDateTime
41 m_when.append(QDateTime());
42 }
43 }
44
45 mutable GeoDataLineString m_lineString;
46 mutable bool m_lineStringNeedsUpdate;
47
48 bool m_interpolate;
49
50 QList<QDateTime> m_when;
51 QList<GeoDataCoordinates> m_coordinates;
52
53 GeoDataExtendedData m_extendedData;
54};
55
56GeoDataTrack::GeoDataTrack()
57 : GeoDataGeometry(new GeoDataTrackPrivate())
58{
59}
60
61GeoDataTrack::GeoDataTrack(const GeoDataTrack &other)
62
63 = default;
64
65GeoDataTrack &GeoDataTrack::operator=(const GeoDataTrack &other) = default;
66
67const char *GeoDataTrack::nodeType() const
68{
69 return GeoDataTypes::GeoDataTrackType;
70}
71
72EnumGeometryId GeoDataTrack::geometryId() const
73{
74 return GeoDataTrackId;
75}
76
77GeoDataGeometry *GeoDataTrack::copy() const
78{
79 return new GeoDataTrack(*this);
80}
81
82bool GeoDataTrack::operator==(const GeoDataTrack &other) const
83{
84 Q_D(const GeoDataTrack);
85 const GeoDataTrackPrivate *const otherD = other.d_func();
86
87 return equals(other) && d->m_when == otherD->m_when && d->m_coordinates == otherD->m_coordinates && d->m_extendedData == otherD->m_extendedData
88 && d->m_interpolate == otherD->m_interpolate;
89}
90
91bool GeoDataTrack::operator!=(const GeoDataTrack &other) const
92{
93 return !this->operator==(other);
94}
95
96int GeoDataTrack::size() const
97{
98 Q_D(const GeoDataTrack);
99 return d->m_coordinates.size();
100}
101
102bool GeoDataTrack::interpolate() const
103{
104 Q_D(const GeoDataTrack);
105 return d->m_interpolate;
106}
107
108void GeoDataTrack::setInterpolate(bool on)
109{
110 detach();
111
113 d->m_interpolate = on;
114}
115
116QDateTime GeoDataTrack::firstWhen() const
117{
118 Q_D(const GeoDataTrack);
119
120 if (d->m_when.isEmpty()) {
121 return {};
122 }
123
124 return d->m_when.first();
125}
126
127QDateTime GeoDataTrack::lastWhen() const
128{
129 Q_D(const GeoDataTrack);
130
131 if (d->m_when.isEmpty()) {
132 return {};
133 }
134
135 return d->m_when.last();
136}
137
138QList<GeoDataCoordinates> GeoDataTrack::coordinatesList() const
139{
140 Q_D(const GeoDataTrack);
141 return d->m_coordinates;
142}
143
144QList<QDateTime> GeoDataTrack::whenList() const
145{
146 Q_D(const GeoDataTrack);
147 return d->m_when;
148}
149
150GeoDataCoordinates GeoDataTrack::coordinatesAt(const QDateTime &when) const
151{
152 Q_D(const GeoDataTrack);
153
154 if (d->m_when.isEmpty()) {
155 return {};
156 }
157
158 if (d->m_when.contains(when)) {
159 // exact match found
160 const int index = d->m_when.indexOf(when);
161 if (index < d->m_coordinates.size()) {
162 return d->m_coordinates.at(index);
163 }
164 }
165
166 if (!interpolate()) {
167 return {};
168 }
169
171 PointMap pointMap;
172 for (int i = 0; i < qMin(d->m_when.size(), d->m_coordinates.size()); ++i) {
173 if (d->m_when.at(i).isValid()) {
174 pointMap[d->m_when.at(i)] = d->m_coordinates.at(i);
175 }
176 }
177
178 QMap<QDateTime, GeoDataCoordinates>::const_iterator nextEntry = const_cast<const PointMap &>(pointMap).upperBound(when);
179
180 // No tracked point happened before "when"
181 if (nextEntry == pointMap.constBegin()) {
182 mDebug() << "No tracked point before " << when;
183 return {};
184 }
185
186 if (nextEntry == pointMap.constEnd()) {
187 mDebug() << "No track point after" << when;
188 return {};
189 }
190
191 QMap<QDateTime, GeoDataCoordinates>::const_iterator previousEntry = nextEntry - 1;
192 GeoDataCoordinates previousCoord = previousEntry.value();
193
194 QDateTime previousWhen = previousEntry.key();
195 QDateTime nextWhen = nextEntry.key();
196 GeoDataCoordinates nextCoord = nextEntry.value();
197
198 int interval = previousWhen.msecsTo(nextWhen);
199 int position = previousWhen.msecsTo(when);
200 qreal t = (qreal)position / (qreal)interval;
201
202 return previousCoord.interpolate(nextCoord, t);
203}
204
205GeoDataCoordinates GeoDataTrack::coordinatesAt(int index) const
206{
207 Q_D(const GeoDataTrack);
208 return d->m_coordinates.at(index);
209}
210
211void GeoDataTrack::addPoint(const QDateTime &when, const GeoDataCoordinates &coord)
212{
213 detach();
214
216 d->equalizeWhenSize();
217 d->m_lineStringNeedsUpdate = true;
218 int i = 0;
219 while (i < d->m_when.size()) {
220 if (d->m_when.at(i) > when) {
221 break;
222 }
223 ++i;
224 }
225 d->m_when.insert(i, when);
226 d->m_coordinates.insert(i, coord);
227}
228
229void GeoDataTrack::appendCoordinates(const GeoDataCoordinates &coord)
230{
231 detach();
232
234 d->equalizeWhenSize();
235 d->m_lineStringNeedsUpdate = true;
236 d->m_coordinates.append(coord);
237}
238
239void GeoDataTrack::appendAltitude(qreal altitude)
240{
241 detach();
242
244 d->m_lineStringNeedsUpdate = true;
245 Q_ASSERT(!d->m_coordinates.isEmpty());
246 if (d->m_coordinates.isEmpty()) {
247 return;
248 }
249 GeoDataCoordinates coordinates = d->m_coordinates.takeLast();
250 coordinates.setAltitude(altitude);
251 d->m_coordinates.append(coordinates);
252}
253
254void GeoDataTrack::appendWhen(const QDateTime &when)
255{
256 detach();
257
259 d->m_when.append(when);
260}
261
262void GeoDataTrack::clear()
263{
264 detach();
265
267 d->m_when.clear();
268 d->m_coordinates.clear();
269 d->m_lineStringNeedsUpdate = true;
270}
271
272void GeoDataTrack::removeBefore(const QDateTime &when)
273{
274 detach();
275
277 Q_ASSERT(d->m_coordinates.size() == d->m_when.size());
278 if (d->m_when.isEmpty()) {
279 return;
280 }
281 d->equalizeWhenSize();
282
283 while (!d->m_when.isEmpty() && d->m_when.first() < when) {
284 d->m_when.takeFirst();
285 d->m_coordinates.takeFirst();
286 }
287}
288
289void GeoDataTrack::removeAfter(const QDateTime &when)
290{
291 detach();
292
294 Q_ASSERT(d->m_coordinates.size() == d->m_when.size());
295 if (d->m_when.isEmpty()) {
296 return;
297 }
298 d->equalizeWhenSize();
299 while (!d->m_when.isEmpty() && d->m_when.last() > when) {
300 d->m_when.takeLast();
301 d->m_coordinates.takeLast();
302 }
303}
304
305const GeoDataLineString *GeoDataTrack::lineString() const
306{
307 Q_D(const GeoDataTrack);
308 if (d->m_lineStringNeedsUpdate) {
309 d->m_lineString = GeoDataLineString();
310 d->m_lineString.append(coordinatesList());
311 d->m_lineStringNeedsUpdate = false;
312 }
313 return &d->m_lineString;
314}
315
316GeoDataExtendedData &GeoDataTrack::extendedData()
317{
318 detach();
319
321 return d->m_extendedData;
322}
323
324const GeoDataExtendedData &GeoDataTrack::extendedData() const
325{
326 Q_D(const GeoDataTrack);
327 return d->m_extendedData;
328}
329
330void GeoDataTrack::setExtendedData(const GeoDataExtendedData &extendedData)
331{
332 detach();
333
335 d->m_extendedData = extendedData;
336}
337
338const GeoDataLatLonAltBox &GeoDataTrack::latLonAltBox() const
339{
340 return lineString()->latLonAltBox();
341}
342
343// TODO
344void GeoDataTrack::pack(QDataStream &stream) const
345{
346 GeoDataGeometry::pack(stream);
347}
348// TODO
349void GeoDataTrack::unpack(QDataStream &stream)
350{
351 GeoDataGeometry::unpack(stream);
352}
353
354}
A 3d point representation.
void setAltitude(const qreal altitude)
set the altitude of the Point in meters
GeoDataCoordinates interpolate(const GeoDataCoordinates &target, double t) const
slerp (spherical linear) interpolation between this coordinate and the given target coordinate
a class which allows to add custom data to KML Feature.
A class that defines a 3D bounding box for geographic data.
A LineString that allows to store a contiguous set of line segments.
A geometry for tracking objects made of (time, coordinates) pairs.
Binds a QML item to a specific geodetic location in screen coordinates.
qint64 msecsTo(const QDateTime &other) const const
void append(QList< T > &&value)
void reserve(qsizetype size)
qsizetype size() const const
Q_D(Todo)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 4 2024 16:37:03 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.