File indexing completed on 2024-12-08 06:35:35
0001 // SPDX-License-Identifier: LGPL-2.1-or-later 0002 // 0003 // SPDX-FileCopyrightText: 2011-2012 Florian Eßer <f.esser@rwth-aachen.de> 0004 // SPDX-FileCopyrightText: 2012 Bernhard Beschow <bbeschow@cs.tu-berlin.de> 0005 // SPDX-FileCopyrightText: 2013 Roman Karlstetter <roman.karlstetter@googlemail.com> 0006 // 0007 #include "ElevationProfileDataSource.h" 0008 0009 #include "ElevationModel.h" 0010 0011 #include "GeoDataDocument.h" 0012 #include "GeoDataLineString.h" 0013 #include "GeoDataObject.h" 0014 #include "GeoDataMultiGeometry.h" 0015 #include "GeoDataPlacemark.h" 0016 #include "GeoDataTrack.h" 0017 #include "GeoDataTreeModel.h" 0018 #include "MarbleDebug.h" 0019 #include "MarbleModel.h" 0020 #include "routing/Route.h" 0021 #include "routing/RoutingModel.h" 0022 0023 #include <QFileInfo> 0024 0025 namespace Marble 0026 { 0027 0028 ElevationProfileDataSource::ElevationProfileDataSource( QObject *parent ) : 0029 QObject( parent ) 0030 { 0031 // nothing to do 0032 } 0033 0034 QVector<QPointF> ElevationProfileDataSource::calculateElevationData(const GeoDataLineString &lineString) const 0035 { 0036 // TODO: Don't re-calculate the whole route if only a small part of it was changed 0037 QVector<QPointF> result; 0038 qreal distance = 0; 0039 0040 //GeoDataLineString path; 0041 for ( int i = 0; i < lineString.size(); i++ ) { 0042 const qreal ele = getElevation( lineString[i] ); 0043 0044 if ( i ) { 0045 distance += EARTH_RADIUS * lineString[i-1].sphericalDistanceTo(lineString[i]); 0046 } 0047 0048 if ( ele != invalidElevationData ) { // skip no data 0049 result.append( QPointF( distance, ele ) ); 0050 } 0051 } 0052 0053 return result; 0054 } 0055 // end of impl of ElevationProfileDataSource 0056 0057 ElevationProfileTrackDataSource::ElevationProfileTrackDataSource( const GeoDataTreeModel *treeModel, QObject *parent ) : 0058 ElevationProfileDataSource( parent ), 0059 m_currentSourceIndex( -1 ) 0060 { 0061 if ( treeModel ) { 0062 connect( treeModel, SIGNAL(added(GeoDataObject*)), SLOT(handleObjectAdded(GeoDataObject*)) ); 0063 connect( treeModel, SIGNAL(removed(GeoDataObject*)), SLOT(handleObjectRemoved(GeoDataObject*)) ); 0064 } 0065 } 0066 0067 QStringList ElevationProfileTrackDataSource::sourceDescriptions() const 0068 { 0069 return m_trackChooserList; 0070 } 0071 0072 void ElevationProfileTrackDataSource::setSourceIndex(int index) 0073 { 0074 if (m_currentSourceIndex != index) { 0075 m_currentSourceIndex = index; 0076 requestUpdate(); 0077 } 0078 } 0079 0080 int ElevationProfileTrackDataSource::currentSourceIndex() const 0081 { 0082 return m_currentSourceIndex; 0083 } 0084 0085 void ElevationProfileTrackDataSource::requestUpdate() 0086 { 0087 if ( m_currentSourceIndex < 0 ) { 0088 return; 0089 } 0090 0091 if ( m_currentSourceIndex >= m_trackList.size() ) { 0092 return; 0093 } 0094 0095 const GeoDataLineString *routePoints = m_trackList[m_currentSourceIndex]->lineString(); 0096 0097 emit dataUpdated(*routePoints, calculateElevationData(*routePoints)); 0098 } 0099 0100 bool ElevationProfileTrackDataSource::isDataAvailable() const 0101 { 0102 return !m_trackHash.isEmpty(); 0103 } 0104 0105 qreal ElevationProfileTrackDataSource::getElevation(const GeoDataCoordinates &coordinates) const 0106 { 0107 return coordinates.altitude(); 0108 } 0109 0110 void ElevationProfileTrackDataSource::handleObjectAdded(GeoDataObject *object) 0111 { 0112 const GeoDataDocument *document = dynamic_cast<const GeoDataDocument *>(object); 0113 if (!document) { 0114 return;// don't know what to do if not a document 0115 } 0116 QList<const GeoDataTrack *> trackList; 0117 0118 for (int i = 0; i<document->size(); ++i) { 0119 const GeoDataFeature *feature = document->child(i); 0120 const GeoDataPlacemark *placemark = dynamic_cast<const GeoDataPlacemark*>(feature); 0121 if (!placemark) { 0122 continue; 0123 } 0124 const GeoDataMultiGeometry *multiGeometry = dynamic_cast<const GeoDataMultiGeometry *>(placemark->geometry()); 0125 if (!multiGeometry) { 0126 continue; 0127 } 0128 for (int i = 0; i<multiGeometry->size(); i++) { 0129 const GeoDataTrack *track = dynamic_cast<const GeoDataTrack *>(multiGeometry->child(i)); 0130 if (track && track->size() > 1) { 0131 mDebug() << "new GeoDataTrack for ElevationProfile detected"; 0132 trackList.append(track); 0133 } 0134 } 0135 } 0136 0137 if (trackList.isEmpty()) { 0138 return; 0139 } 0140 0141 // update internal datastructures 0142 m_trackHash.insert(document->fileName(), trackList); 0143 0144 const GeoDataTrack *selectedTrack = nullptr; 0145 if ( 0 <= m_currentSourceIndex && m_currentSourceIndex < m_trackList.size() ) { 0146 selectedTrack = m_trackList[m_currentSourceIndex]; 0147 } 0148 0149 m_trackChooserList.clear(); 0150 m_trackList.clear(); 0151 QHashIterator<QString, QList<const GeoDataTrack *> > i(m_trackHash); 0152 while (i.hasNext()) { 0153 i.next(); 0154 mDebug() << i.key() << ": " << i.value() << endl; 0155 QFileInfo info(i.key()); 0156 QString filename = info.fileName(); 0157 QList<const GeoDataTrack *> list = i.value(); 0158 for (int i = 0; i<list.size(); ++i) { 0159 m_trackList << list[i]; 0160 m_trackChooserList << QString(filename + QLatin1String(": ") + QString::number(i)); 0161 } 0162 } 0163 if (selectedTrack) { 0164 m_currentSourceIndex = m_trackList.indexOf(selectedTrack); 0165 } 0166 0167 emit sourceCountChanged(); 0168 } 0169 0170 void ElevationProfileTrackDataSource::handleObjectRemoved(GeoDataObject *object) 0171 { 0172 if (m_trackList.size() == 0) { 0173 // no track loaded, nothing to remove 0174 return; 0175 } 0176 0177 const GeoDataDocument *topLevelDoc = dynamic_cast<const GeoDataDocument*>(object); 0178 if (!topLevelDoc) { 0179 return;// don't know what to do if not a document 0180 } 0181 0182 const QString key = topLevelDoc->fileName(); 0183 if ( !m_trackHash.contains( key ) ) { 0184 return; 0185 } 0186 0187 const QList<const GeoDataTrack *> list = m_trackHash.value(key); 0188 const GeoDataTrack *const selectedTrack = m_currentSourceIndex == -1 ? 0 : m_trackList[m_currentSourceIndex]; 0189 for (int i = 0; i<list.size(); i++) { 0190 int idx = m_trackList.indexOf(list[i]); 0191 m_trackList.removeAt(idx); 0192 m_trackChooserList.removeAt(idx); 0193 } 0194 m_trackHash.remove(key); 0195 0196 m_currentSourceIndex = m_trackList.indexOf(selectedTrack); 0197 if (m_currentSourceIndex == -1) { 0198 m_currentSourceIndex = 0; 0199 } 0200 0201 emit sourceCountChanged(); 0202 requestUpdate(); 0203 } 0204 0205 // end of impl of ElevationProfileTrackDataSource 0206 0207 ElevationProfileRouteDataSource::ElevationProfileRouteDataSource( const RoutingModel *routingModel, const ElevationModel *elevationModel, QObject *parent ) : 0208 ElevationProfileDataSource( parent ), 0209 m_routingModel( routingModel ), 0210 m_elevationModel( elevationModel ), 0211 m_routeAvailable( false ) 0212 { 0213 } 0214 0215 void ElevationProfileRouteDataSource::requestUpdate() 0216 { 0217 if (m_routeAvailable != isDataAvailable()) { 0218 // availability of route changed 0219 emit sourceCountChanged(); 0220 m_routeAvailable = isDataAvailable(); 0221 } 0222 0223 const GeoDataLineString routePoints = m_routingModel->route().path(); 0224 const QVector<QPointF> elevationData = calculateElevationData(routePoints); 0225 emit dataUpdated( routePoints, elevationData ); 0226 } 0227 0228 bool ElevationProfileRouteDataSource::isDataAvailable() const 0229 { 0230 return m_routingModel && m_routingModel->rowCount() > 0; 0231 } 0232 0233 qreal ElevationProfileRouteDataSource::getElevation(const GeoDataCoordinates &coordinates) const 0234 { 0235 const qreal lat = coordinates.latitude ( GeoDataCoordinates::Degree ); 0236 const qreal lon = coordinates.longitude( GeoDataCoordinates::Degree ); 0237 qreal ele = m_elevationModel->height( lon, lat ); 0238 return ele; 0239 } 0240 // end of impl of ElevationProfileRouteDataSource 0241 0242 } 0243 0244 #include "moc_ElevationProfileDataSource.cpp" 0245