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