Marble

GeoDataTrack.cpp
1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 //
3 // SPDX-FileCopyrightText: 2011 Guillaume Martres <[email protected]>
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 
19 namespace Marble {
20 
21 class GeoDataTrackPrivate : public GeoDataGeometryPrivate
22 {
23 public:
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 
52 GeoDataTrack::GeoDataTrack() :
53  GeoDataGeometry( new GeoDataTrackPrivate() )
54 {
55 
56 }
57 
58 GeoDataTrack::GeoDataTrack( const GeoDataTrack &other )
59  : GeoDataGeometry( other )
60 {
61 
62 }
63 
64 GeoDataTrack &GeoDataTrack::operator=( const GeoDataTrack &other )
65 {
66  GeoDataGeometry::operator=( other );
67 
68  return *this;
69 }
70 
71 const char *GeoDataTrack::nodeType() const
72 {
73  return GeoDataTypes::GeoDataTrackType;
74 }
75 
76 EnumGeometryId GeoDataTrack::geometryId() const
77 {
78  return GeoDataTrackId;
79 }
80 
81 GeoDataGeometry *GeoDataTrack::copy() const
82 {
83  return new GeoDataTrack(*this);
84 }
85 
86 
87 bool 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 
99 bool GeoDataTrack::operator!=( const GeoDataTrack& other ) const
100 {
101  return !this->operator==( other );
102 }
103 
105 {
106  Q_D(const GeoDataTrack);
107  return d->m_coordinates.size();
108 }
109 
111 {
112  Q_D(const GeoDataTrack);
113  return d->m_interpolate;
114 }
115 
117 {
118  detach();
119 
120  Q_D(GeoDataTrack);
121  d->m_interpolate = on;
122 }
123 
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 
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 
147 {
148  Q_D(const GeoDataTrack);
149  return d->m_coordinates;
150 }
151 
153 {
154  Q_D(const GeoDataTrack);
155  return d->m_when;
156 }
157 
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 
178  typedef QMap<QDateTime, GeoDataCoordinates> PointMap;
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 
214 {
215  Q_D(const GeoDataTrack);
216  return d->m_coordinates.at(index);
217 }
218 
219 void GeoDataTrack::addPoint( const QDateTime &when, const GeoDataCoordinates &coord )
220 {
221  detach();
222 
223  Q_D(GeoDataTrack);
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 
238 {
239  detach();
240 
241  Q_D(GeoDataTrack);
242  d->equalizeWhenSize();
243  d->m_lineStringNeedsUpdate = true;
244  d->m_coordinates.append(coord);
245 }
246 
247 void GeoDataTrack::appendAltitude( qreal altitude )
248 {
249  detach();
250 
251  Q_D(GeoDataTrack);
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 
263 {
264  detach();
265 
266  Q_D(GeoDataTrack);
267  d->m_when.append(when);
268 }
269 
271 {
272  detach();
273 
274  Q_D(GeoDataTrack);
275  d->m_when.clear();
276  d->m_coordinates.clear();
277  d->m_lineStringNeedsUpdate = true;
278 }
279 
281 {
282  detach();
283 
284  Q_D(GeoDataTrack);
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 
298 {
299  detach();
300 
301  Q_D(GeoDataTrack);
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 
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 
325 {
326  detach();
327 
328  Q_D(GeoDataTrack);
329  return d->m_extendedData;
330 }
331 
333 {
334  Q_D(const GeoDataTrack);
335  return d->m_extendedData;
336 }
337 
339 {
340  detach();
341 
342  Q_D(GeoDataTrack);
343  d->m_extendedData = extendedData;
344 }
345 
346 const GeoDataLatLonAltBox& GeoDataTrack::latLonAltBox() const
347 {
348  return lineString()->latLonAltBox();
349 }
350 
351 //TODO
352 void GeoDataTrack::pack( QDataStream& stream ) const
353 {
354  GeoDataGeometry::pack( stream );
355 }
356 //TODO
357 void GeoDataTrack::unpack( QDataStream& stream )
358 {
359  GeoDataGeometry::unpack( stream );
360 }
361 
362 }
A 3d point representation.
const char * nodeType() const override
Provides type information for downcasting a GeoNode.
A class that defines a 3D bounding box for geographic data.
void clear()
Remove all the points contained in the track.
bool interpolate() const
Returns true if coordinatesAt() should use interpolation, false otherwise.
QVector< GeoDataCoordinates > coordinatesList() const
Returns the coordinates of all the points in the map, sorted by their time value.
a class which allows to add custom data to KML Feature.
void appendCoordinates(const GeoDataCoordinates &coord)
Add the coordinates part for a new point.
QVector< QDateTime > whenList() const
Returns the time value of all the points in the map, in chronological order.
bool operator==(const GeoDataTrack &other) const
: Equality operators.
void unpack(QDataStream &stream) override
Unserialize the contents of the feature from stream.
QAction * copy(const QObject *recvr, const char *slot, QObject *parent)
A LineString that allows to store a contiguous set of line segments.
void addPoint(const QDateTime &when, const GeoDataCoordinates &coord)
Add a new point with coordinates coord associated with the time value when.
const GeoDataLatLonAltBox & latLonAltBox() const override
Returns the smallest latLonAltBox that contains the LineString.
int size() const
Returns the number of points in the track.
void setExtendedData(const GeoDataExtendedData &extendedData)
Sets the ExtendedData of the feature.
void removeBefore(const QDateTime &when)
Remove all points from the track whose time value is less than when.
void appendWhen(const QDateTime &when)
Add the time value part for a new point.
void removeAfter(const QDateTime &when)
Remove all points from the track whose time value is greater than when.
Binds a QML item to a specific geodetic location in screen coordinates.
A geometry for tracking objects made of (time, coordinates) pairs.
Definition: GeoDataTrack.h:50
const GeoDataExtendedData & extendedData() const
Return the ExtendedData assigned to the feature.
GeoDataCoordinates interpolate(const GeoDataCoordinates &target, double t) const
slerp (spherical linear) interpolation between this coordinate and the given target coordinate
void appendAltitude(qreal altitude)
Add altitude information to the last appended coordinates.
QDateTime firstWhen() const
Return the time value of the first point in the track, or an invalid QDateTime if the track is empty.
void setAltitude(const qreal altitude)
set the altitude of the Point in meters
const GeoDataLineString * lineString() const
Return the GeoDataLineString representing the current track.
QDateTime lastWhen() const
Return the time value of the last point in the track, or an invalid QDateTime if the track is empty.
void pack(QDataStream &stream) const override
Serialize the contents of the feature to stream.
Q_D(Todo)
QDebug mDebug()
a function to replace qDebug() in Marble library code
Definition: MarbleDebug.cpp:31
GeoDataCoordinates coordinatesAt(const QDateTime &when) const
If interpolate() is true, return the coordinates interpolated from the time values before and after w...
qint64 msecsTo(const QDateTime &other) const const
void setInterpolate(bool on)
Set whether coordinatesAt() should use interpolation.
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Wed Oct 4 2023 04:09:41 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.