File indexing completed on 2024-12-08 06:35:36

0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2011-2012 Florian Eßer <f.esser@rwth-aachen.de>
0004 //
0005 
0006 #include "ElevationProfilePlotAxis.h"
0007 
0008 #include "MarbleGlobal.h"
0009 #include "MarbleLocale.h"
0010 
0011 #include <qmath.h>
0012 
0013 namespace Marble
0014 {
0015 
0016 ElevationProfilePlotAxis::ElevationProfilePlotAxis()
0017     : m_minValue( 0.0 ),
0018       m_maxValue ( 0.0 ),
0019       m_displayScale( 1.0 ),
0020       m_pixelLength ( 0 ),
0021       m_minTickCount( 2 ),
0022       m_maxTickCount( 5 ),
0023       m_unitString( QString() )
0024 {
0025     // nothing to do...
0026 }
0027 
0028 void ElevationProfilePlotAxis::setRange(qreal minValue, qreal maxValue)
0029 {
0030     m_minValue = minValue;
0031     m_maxValue = maxValue;
0032     update();
0033 }
0034 
0035 void ElevationProfilePlotAxis::setLength(int length)
0036 {
0037     m_pixelLength = length;
0038     update();
0039 }
0040 
0041 void ElevationProfilePlotAxis::setTickCount( const int min, const int max )
0042 {
0043     m_minTickCount = min;
0044     m_maxTickCount = max;
0045 }
0046 
0047 void ElevationProfilePlotAxis::update()
0048 {
0049     updateTicks();
0050     updateScale();
0051 }
0052 
0053 qreal ElevationProfilePlotAxis::minValue() const
0054 {
0055     return m_minValue;
0056 }
0057 
0058 qreal ElevationProfilePlotAxis::maxValue() const
0059 {
0060     return m_maxValue;
0061 }
0062 
0063 qreal ElevationProfilePlotAxis::range() const
0064 {
0065     return m_maxValue - m_minValue;
0066 }
0067 
0068 qreal ElevationProfilePlotAxis::scale() const
0069 {
0070     return m_displayScale;
0071 }
0072 
0073 QString ElevationProfilePlotAxis::unit() const
0074 {
0075     return m_unitString;
0076 }
0077 
0078 AxisTickList ElevationProfilePlotAxis::ticks() const
0079 {
0080     return m_ticks;
0081 }
0082 
0083 void ElevationProfilePlotAxis::updateTicks()
0084 {
0085     m_ticks.clear();
0086     if( range() == 0 ) {
0087         return;
0088     }
0089 
0090     static QVector<int> niceIntervals = QVector<int>() << 10 << 20 << 25 << 30 << 50;
0091 
0092     const int exponent = qRound( log10( range() ) );
0093     const qreal factor = qPow( 10, 2 - exponent );
0094     const qreal tickRange = range() * factor;
0095 
0096     qreal stepWidth = niceIntervals.last();
0097     qreal error = tickRange;
0098     for ( const int i: niceIntervals ) {
0099         const qreal numTicks = tickRange / i;
0100         if ( numTicks < m_minTickCount || numTicks > m_maxTickCount ) {
0101             continue;
0102         }
0103         const qreal newError = qAbs( numTicks - qRound( numTicks ) );
0104         if ( newError < error ) {
0105             error = newError;
0106             stepWidth = i;
0107         }
0108     }
0109     stepWidth /= factor;
0110 
0111     qreal offset = 0;
0112     if ( fmod( m_minValue, stepWidth ) != 0 ) {
0113         offset = stepWidth - fmod( m_minValue, stepWidth );
0114     }
0115 
0116     qreal val = m_minValue + offset;
0117     int pos = m_pixelLength / range() * offset;
0118     m_ticks << AxisTick( pos, val );
0119     while( val < m_maxValue ) {
0120         val += stepWidth;
0121         pos += m_pixelLength / range() * stepWidth;
0122         if ( pos > m_pixelLength ) {
0123             break;
0124         }
0125         m_ticks << AxisTick( pos, val );
0126     }
0127 }
0128 
0129 void ElevationProfilePlotAxis::updateScale()
0130 {
0131     MarbleLocale::MeasurementSystem measurementSystem;
0132     measurementSystem = MarbleGlobal::getInstance()->locale()->measurementSystem();
0133     switch ( measurementSystem ) {
0134     case MarbleLocale::MetricSystem:
0135         if ( range() >= 10 * KM2METER ) {
0136             m_unitString = tr( "km" );
0137             m_displayScale = METER2KM;
0138         } else {
0139             m_unitString = tr( "m" );
0140             m_displayScale = 1.0;
0141         }
0142         break;
0143     case MarbleLocale::ImperialSystem:
0144         // FIXME: Do these values make sense?
0145         if ( range() >= 10 * KM2METER * MI2KM ) {
0146             m_unitString = tr( "mi" );
0147             m_displayScale = METER2KM * KM2MI;
0148         } else {
0149             m_unitString = tr( "ft" );
0150             m_displayScale = M2FT;
0151         }
0152         break;
0153 
0154     case MarbleLocale::NauticalSystem:
0155         m_unitString = tr("nm");
0156         m_displayScale = METER2KM * KM2NM;
0157         break;
0158     }
0159 }
0160 
0161 }
0162 
0163 #include "moc_ElevationProfilePlotAxis.cpp"