Hi,
I'm currently creating some cycling routes with Marble (Really awesome overall
for this task! :)).
One thing that I've found out is that the climb and descend height of the
elevation profile aren't very accurate (Usually to large). I've modified the
averaging algorithm to average over 200 meters (Probably another value would
be even better, not sure) instead of 5 points (Those can be very close
together or really far away from each other).
This approach gives pretty good values for me so far. I've attached the patch
for it to this mail, averageDistance specifies the distance the algorithms
averages over in meters.
Greetings,
Oliver
P.S.: If you specify many waypoints for your route the dock for the route gets
really large vertically - would be nice to have a scrollbar there :)
--- marble-4.13.0/src/plugins/render/elevationprofilefloatitem/ElevationProfileFloatItem.cpp 2014-03-31 09:51:15.000000000 +0200
+++ changes/src/plugins/render/elevationprofilefloatitem/ElevationProfileFloatItem.cpp 2014-05-15 00:38:49.894776466 +0200
@@ -582,26 +582,19 @@ QList<QPointF> ElevationProfileFloatItem
{
// TODO: Don't re-calculate the whole route if only a small part of it was changed
QList<QPointF> result;
+ qreal distance = 0;
- GeoDataLineString path;
for ( int i = 0; i < lineString.size(); i++ ) {
- path.append( lineString[i] );
-
const qreal lat = lineString[i].latitude ( GeoDataCoordinates::Degree );
const qreal lon = lineString[i].longitude( GeoDataCoordinates::Degree );
qreal ele = marbleModel()->elevationModel()->height( lon, lat );
- if ( ele == invalidElevationData ) { // no data
- ele = 0;
- }
- // result.append( QPointF( path.length( EARTH_RADIUS ), ele ) );
- // The code below does the same as the line above, but is much faster - O(1) instead of O(n)
if ( i ) {
- Q_ASSERT( !result.isEmpty() ); // The else part below appended something in the first run
- qreal const distance = EARTH_RADIUS * distanceSphere( lineString[i-1], lineString[i] );
- result.append( QPointF( result.last().x() + distance, ele ) );
- } else {
- result.append( QPointF( 0, ele ) );
+ distance += EARTH_RADIUS * distanceSphere( lineString[i-1], lineString[i] );
+ }
+
+ if ( ele != invalidElevationData ) { // skip no data
+ result.append( QPointF( distance, ele ) );
}
}
@@ -610,33 +603,38 @@ QList<QPointF> ElevationProfileFloatItem
void ElevationProfileFloatItem::calculateStatistics( const QList<QPointF> &eleData )
{
- const int averageOrder = 5;
+ const qreal averageDistance = 200.0;
- qreal lastAverage = 0;
m_maxElevation = 0.0;
m_minElevation = invalidElevationData;
m_gain = 0;
m_loss = 0;
const int start = m_zoomToViewport ? m_firstVisiblePoint : 0;
const int end = m_zoomToViewport ? m_lastVisiblePoint : eleData.size();
- for ( int i = start; i < end; ++i ) {
- m_maxElevation = qMax( m_maxElevation, eleData.value( i ).y() );
- m_minElevation = qMin( m_minElevation, eleData.value( i ).y() );
-
- // Low-pass filtering (moving average) of the elevation profile to calculate gain and loss values
- // not always the best method, see for example
- // http://www.ikg.uni-hannover.de/fileadmin/ikg/staff/thesis/finished/documents/StudArb_Schulze.pdf
- // (German), chapter 4.2
+
+ if( start < end ) {
+ qreal lastAverage = eleData.value( start ).y();
+ m_maxElevation = lastAverage;
+ m_minElevation = lastAverage;
+
+ int averageStart = start;
+ for ( int index = start + 1; index <= end; ++index ) {
+ m_maxElevation = qMax( m_maxElevation, eleData.value( index ).y() );
+ m_minElevation = qMin( m_minElevation, eleData.value( index ).y() );
+
+ // Low-pass filtering (moving average) of the elevation profile to calculate gain and loss values
+ // not always the best method, see for example
+ // http://www.ikg.uni-hannover.de/fileadmin/ikg/staff/thesis/finished/documents/StudArb_Schulze.pdf
+ // (German), chapter 4.2
- if ( i >= averageOrder ) {
qreal average = 0;
- for( int j = 0; j < averageOrder; j++ ) {
- average += eleData.value( i-j ).y();
+ while( eleData.value( index ).x() - eleData.value( averageStart ).x() > averageDistance ) {
+ ++averageStart;
}
- average /= averageOrder;
- if ( i == averageOrder ) {
- lastAverage = average; // else the initial elevation would be counted as gain
+ for( int averageIndex = averageStart; averageIndex <= index; ++averageIndex ) {
+ average += eleData.value( averageIndex ).y();
}
+ average /= (index - averageStart + 1);
if ( average > lastAverage ) {
m_gain += average - lastAverage;
} else {
_______________________________________________
Marble-devel mailing list
[email protected]
https://mail.kde.org/mailman/listinfo/marble-devel