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

KDE's Doxygen guidelines are available online.