File indexing completed on 2024-05-12 03:50:18
0001 // SPDX-License-Identifier: LGPL-2.1-or-later 0002 // 0003 // SPDX-FileCopyrightText: 2011 Guillaume Martres <smarter@ubuntu.com> 0004 // 0005 0006 #include "GeoDataTrack.h" 0007 #include "GeoDataGeometry_p.h" 0008 0009 #include "GeoDataLatLonAltBox.h" 0010 #include "GeoDataTypes.h" 0011 #include "MarbleDebug.h" 0012 0013 #include "GeoDataLineString.h" 0014 #include "GeoDataExtendedData.h" 0015 0016 #include <QMap> 0017 #include <QDateTime> 0018 0019 namespace Marble { 0020 0021 class GeoDataTrackPrivate : public GeoDataGeometryPrivate 0022 { 0023 public: 0024 GeoDataTrackPrivate() 0025 : m_lineStringNeedsUpdate( false ), 0026 m_interpolate( false ) 0027 { 0028 } 0029 0030 GeoDataGeometryPrivate *copy() const override { return new GeoDataTrackPrivate( *this ); } 0031 0032 void equalizeWhenSize() 0033 { 0034 m_when.reserve(m_coordinates.size()); 0035 while ( m_when.size() < m_coordinates.size() ) { 0036 //fill coordinates without time information with null QDateTime 0037 m_when.append( QDateTime() ); 0038 } 0039 } 0040 0041 mutable GeoDataLineString m_lineString; 0042 mutable bool m_lineStringNeedsUpdate; 0043 0044 bool m_interpolate; 0045 0046 QVector<QDateTime> m_when; 0047 QVector<GeoDataCoordinates> m_coordinates; 0048 0049 GeoDataExtendedData m_extendedData; 0050 }; 0051 0052 GeoDataTrack::GeoDataTrack() : 0053 GeoDataGeometry( new GeoDataTrackPrivate() ) 0054 { 0055 0056 } 0057 0058 GeoDataTrack::GeoDataTrack( const GeoDataTrack &other ) 0059 : GeoDataGeometry( other ) 0060 { 0061 0062 } 0063 0064 GeoDataTrack &GeoDataTrack::operator=( const GeoDataTrack &other ) 0065 { 0066 GeoDataGeometry::operator=( other ); 0067 0068 return *this; 0069 } 0070 0071 const char *GeoDataTrack::nodeType() const 0072 { 0073 return GeoDataTypes::GeoDataTrackType; 0074 } 0075 0076 EnumGeometryId GeoDataTrack::geometryId() const 0077 { 0078 return GeoDataTrackId; 0079 } 0080 0081 GeoDataGeometry *GeoDataTrack::copy() const 0082 { 0083 return new GeoDataTrack(*this); 0084 } 0085 0086 0087 bool GeoDataTrack::operator==( const GeoDataTrack& other ) const 0088 { 0089 Q_D(const GeoDataTrack); 0090 const GeoDataTrackPrivate * const otherD = other.d_func(); 0091 0092 return equals(other) && 0093 d->m_when == otherD->m_when && 0094 d->m_coordinates == otherD->m_coordinates && 0095 d->m_extendedData == otherD->m_extendedData && 0096 d->m_interpolate == otherD->m_interpolate; 0097 } 0098 0099 bool GeoDataTrack::operator!=( const GeoDataTrack& other ) const 0100 { 0101 return !this->operator==( other ); 0102 } 0103 0104 int GeoDataTrack::size() const 0105 { 0106 Q_D(const GeoDataTrack); 0107 return d->m_coordinates.size(); 0108 } 0109 0110 bool GeoDataTrack::interpolate() const 0111 { 0112 Q_D(const GeoDataTrack); 0113 return d->m_interpolate; 0114 } 0115 0116 void GeoDataTrack::setInterpolate(bool on) 0117 { 0118 detach(); 0119 0120 Q_D(GeoDataTrack); 0121 d->m_interpolate = on; 0122 } 0123 0124 QDateTime GeoDataTrack::firstWhen() const 0125 { 0126 Q_D(const GeoDataTrack); 0127 0128 if (d->m_when.isEmpty()) { 0129 return QDateTime(); 0130 } 0131 0132 return d->m_when.first(); 0133 } 0134 0135 QDateTime GeoDataTrack::lastWhen() const 0136 { 0137 Q_D(const GeoDataTrack); 0138 0139 if (d->m_when.isEmpty()) { 0140 return QDateTime(); 0141 } 0142 0143 return d->m_when.last(); 0144 } 0145 0146 QVector<GeoDataCoordinates> GeoDataTrack::coordinatesList() const 0147 { 0148 Q_D(const GeoDataTrack); 0149 return d->m_coordinates; 0150 } 0151 0152 QVector<QDateTime> GeoDataTrack::whenList() const 0153 { 0154 Q_D(const GeoDataTrack); 0155 return d->m_when; 0156 } 0157 0158 GeoDataCoordinates GeoDataTrack::coordinatesAt( const QDateTime &when ) const 0159 { 0160 Q_D(const GeoDataTrack); 0161 0162 if (d->m_when.isEmpty()) { 0163 return GeoDataCoordinates(); 0164 } 0165 0166 if (d->m_when.contains(when)) { 0167 //exact match found 0168 const int index = d->m_when.indexOf(when); 0169 if (index < d->m_coordinates.size()) { 0170 return d->m_coordinates.at(index); 0171 } 0172 } 0173 0174 if ( !interpolate() ) { 0175 return GeoDataCoordinates(); 0176 } 0177 0178 typedef QMap<QDateTime, GeoDataCoordinates> PointMap; 0179 PointMap pointMap; 0180 for (int i = 0; i < qMin(d->m_when.size(), d->m_coordinates.size()); ++i) { 0181 if (d->m_when.at(i).isValid()) { 0182 pointMap[d->m_when.at(i)] = d->m_coordinates.at(i); 0183 } 0184 } 0185 0186 QMap<QDateTime, GeoDataCoordinates>::const_iterator nextEntry = const_cast<const PointMap&>(pointMap).upperBound( when ); 0187 0188 // No tracked point happened before "when" 0189 if ( nextEntry == pointMap.constBegin() ) { 0190 mDebug() << "No tracked point before " << when; 0191 return GeoDataCoordinates(); 0192 } 0193 0194 if ( nextEntry == pointMap.constEnd() ) { 0195 mDebug() << "No track point after" << when; 0196 return GeoDataCoordinates(); 0197 } 0198 0199 QMap<QDateTime, GeoDataCoordinates>::const_iterator previousEntry = nextEntry - 1; 0200 GeoDataCoordinates previousCoord = previousEntry.value(); 0201 0202 QDateTime previousWhen = previousEntry.key(); 0203 QDateTime nextWhen = nextEntry.key(); 0204 GeoDataCoordinates nextCoord = nextEntry.value(); 0205 0206 int interval = previousWhen.msecsTo( nextWhen ); 0207 int position = previousWhen.msecsTo( when ); 0208 qreal t = (qreal)position / (qreal)interval; 0209 0210 return previousCoord.interpolate(nextCoord, t); 0211 } 0212 0213 GeoDataCoordinates GeoDataTrack::coordinatesAt( int index ) const 0214 { 0215 Q_D(const GeoDataTrack); 0216 return d->m_coordinates.at(index); 0217 } 0218 0219 void GeoDataTrack::addPoint( const QDateTime &when, const GeoDataCoordinates &coord ) 0220 { 0221 detach(); 0222 0223 Q_D(GeoDataTrack); 0224 d->equalizeWhenSize(); 0225 d->m_lineStringNeedsUpdate = true; 0226 int i=0; 0227 while (i < d->m_when.size()) { 0228 if (d->m_when.at(i) > when) { 0229 break; 0230 } 0231 ++i; 0232 } 0233 d->m_when.insert(i, when ); 0234 d->m_coordinates.insert(i, coord ); 0235 } 0236 0237 void GeoDataTrack::appendCoordinates( const GeoDataCoordinates &coord ) 0238 { 0239 detach(); 0240 0241 Q_D(GeoDataTrack); 0242 d->equalizeWhenSize(); 0243 d->m_lineStringNeedsUpdate = true; 0244 d->m_coordinates.append(coord); 0245 } 0246 0247 void GeoDataTrack::appendAltitude( qreal altitude ) 0248 { 0249 detach(); 0250 0251 Q_D(GeoDataTrack); 0252 d->m_lineStringNeedsUpdate = true; 0253 Q_ASSERT(!d->m_coordinates.isEmpty()); 0254 if (d->m_coordinates.isEmpty()) { 0255 return; 0256 } 0257 GeoDataCoordinates coordinates = d->m_coordinates.takeLast(); 0258 coordinates.setAltitude( altitude ); 0259 d->m_coordinates.append(coordinates); 0260 } 0261 0262 void GeoDataTrack::appendWhen( const QDateTime &when ) 0263 { 0264 detach(); 0265 0266 Q_D(GeoDataTrack); 0267 d->m_when.append(when); 0268 } 0269 0270 void GeoDataTrack::clear() 0271 { 0272 detach(); 0273 0274 Q_D(GeoDataTrack); 0275 d->m_when.clear(); 0276 d->m_coordinates.clear(); 0277 d->m_lineStringNeedsUpdate = true; 0278 } 0279 0280 void GeoDataTrack::removeBefore( const QDateTime &when ) 0281 { 0282 detach(); 0283 0284 Q_D(GeoDataTrack); 0285 Q_ASSERT( d->m_coordinates.size() == d->m_when.size()); 0286 if (d->m_when.isEmpty()) { 0287 return; 0288 } 0289 d->equalizeWhenSize(); 0290 0291 while (!d->m_when.isEmpty() && d->m_when.first() < when) { 0292 d->m_when.takeFirst(); 0293 d->m_coordinates.takeFirst(); 0294 } 0295 } 0296 0297 void GeoDataTrack::removeAfter( const QDateTime &when ) 0298 { 0299 detach(); 0300 0301 Q_D(GeoDataTrack); 0302 Q_ASSERT(d->m_coordinates.size() == d->m_when.size()); 0303 if (d->m_when.isEmpty()) { 0304 return; 0305 } 0306 d->equalizeWhenSize(); 0307 while (!d->m_when.isEmpty() && d->m_when.last() > when) { 0308 d->m_when.takeLast(); 0309 d->m_coordinates.takeLast(); 0310 } 0311 } 0312 0313 const GeoDataLineString *GeoDataTrack::lineString() const 0314 { 0315 Q_D(const GeoDataTrack); 0316 if (d->m_lineStringNeedsUpdate) { 0317 d->m_lineString = GeoDataLineString(); 0318 d->m_lineString.append( coordinatesList() ); 0319 d->m_lineStringNeedsUpdate = false; 0320 } 0321 return &d->m_lineString; 0322 } 0323 0324 GeoDataExtendedData& GeoDataTrack::extendedData() 0325 { 0326 detach(); 0327 0328 Q_D(GeoDataTrack); 0329 return d->m_extendedData; 0330 } 0331 0332 const GeoDataExtendedData& GeoDataTrack::extendedData() const 0333 { 0334 Q_D(const GeoDataTrack); 0335 return d->m_extendedData; 0336 } 0337 0338 void GeoDataTrack::setExtendedData( const GeoDataExtendedData& extendedData ) 0339 { 0340 detach(); 0341 0342 Q_D(GeoDataTrack); 0343 d->m_extendedData = extendedData; 0344 } 0345 0346 const GeoDataLatLonAltBox& GeoDataTrack::latLonAltBox() const 0347 { 0348 return lineString()->latLonAltBox(); 0349 } 0350 0351 //TODO 0352 void GeoDataTrack::pack( QDataStream& stream ) const 0353 { 0354 GeoDataGeometry::pack( stream ); 0355 } 0356 //TODO 0357 void GeoDataTrack::unpack( QDataStream& stream ) 0358 { 0359 GeoDataGeometry::unpack( stream ); 0360 } 0361 0362 }