Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgsclassificationlogarithmic.h 3 : : --------------------- 4 : : begin : September 2019 5 : : copyright : (C) 2019 by Denis Rouzaud 6 : : email : denis@opengis.ch 7 : : *************************************************************************** 8 : : * * 9 : : * This program is free software; you can redistribute it and/or modify * 10 : : * it under the terms of the GNU General Public License as published by * 11 : : * the Free Software Foundation; either version 2 of the License, or * 12 : : * (at your option) any later version. * 13 : : * * 14 : : ***************************************************************************/ 15 : : 16 : : #include <QObject> 17 : : 18 : : #include "qgsclassificationlogarithmic.h" 19 : : #include "qgssymbollayerutils.h" 20 : : #include "qgsapplication.h" 21 : : #include "qgsprocessingcontext.h" 22 : : 23 : : 24 : 5 : QgsClassificationLogarithmic::QgsClassificationLogarithmic() 25 : 5 : : QgsClassificationMethod( NoFlag, 0 ) 26 : 10 : { 27 : 10 : QgsProcessingParameterEnum *param = new QgsProcessingParameterEnum( QStringLiteral( "ZERO_NEG_VALUES_HANDLE" ), QObject::tr( "Handling of 0 or negative values" ), QStringList() << QObject::tr( "no handling (faster)" ) << QObject::tr( "discard (slower)" ) << QObject::tr( "prepend range (slower)" ), false, 0 ); 28 : 5 : addParameter( param ); 29 : 5 : } 30 : : 31 : : 32 : 0 : QgsClassificationMethod *QgsClassificationLogarithmic::clone() const 33 : : { 34 : 0 : QgsClassificationLogarithmic *c = new QgsClassificationLogarithmic(); 35 : 0 : copyBase( c ); 36 : 0 : return c; 37 : 0 : } 38 : : 39 : 0 : QString QgsClassificationLogarithmic::name() const 40 : : { 41 : 0 : return QObject::tr( "Logarithmic scale" ); 42 : : } 43 : : 44 : 10 : QString QgsClassificationLogarithmic::id() const 45 : : { 46 : 20 : return QStringLiteral( "Logarithmic" ); 47 : : } 48 : : 49 : 0 : QIcon QgsClassificationLogarithmic::icon() const 50 : : { 51 : 0 : return QgsApplication::getThemeIcon( "classification_methods/mClassificationLogarithmic.svg" ); 52 : 0 : } 53 : : 54 : 0 : QList<double> QgsClassificationLogarithmic::calculateBreaks( double &minimum, double &maximum, const QList<double> &values, int nclasses ) 55 : : { 56 : 0 : QgsProcessingContext context; 57 : 0 : const QgsProcessingParameterDefinition *def = parameterDefinition( QStringLiteral( "ZERO_NEG_VALUES_HANDLE" ) ); 58 : 0 : NegativeValueHandling nvh = static_cast< NegativeValueHandling >( QgsProcessingParameters::parameterAsEnum( def, parameterValues(), context ) ); 59 : : 60 : 0 : double positiveMinimum = std::numeric_limits<double>::max(); 61 : 0 : if ( nvh != NegativeValueHandling::NoHandling && minimum <= 0 ) 62 : : { 63 : : Q_ASSERT( values.count() ); 64 : 0 : if ( maximum > 0 ) 65 : : { 66 : 0 : for ( int i = 0; i < values.count(); i++ ) 67 : : { 68 : 0 : if ( values.at( i ) > 0 ) 69 : 0 : positiveMinimum = std::min( positiveMinimum, values.at( i ) ); 70 : 0 : } 71 : 0 : } 72 : 0 : if ( positiveMinimum == std::numeric_limits<double>::max() ) 73 : : { 74 : : // there is no usable values 75 : 0 : if ( nvh == NegativeValueHandling::PrependBreak ) 76 : 0 : return QList<double>( {0} ); 77 : : else 78 : 0 : return QList<double>(); 79 : : } 80 : 0 : } 81 : : 82 : 0 : QList<double> breaks; 83 : : 84 : 0 : if ( positiveMinimum != std::numeric_limits<double>::max() ) 85 : : { 86 : 0 : if ( nvh == NegativeValueHandling::PrependBreak ) 87 : 0 : breaks << std::floor( std::log10( positiveMinimum ) ); 88 : 0 : else if ( nvh == NegativeValueHandling::Discard ) 89 : 0 : minimum = positiveMinimum; // the minimum gets updated 90 : 0 : } 91 : : else 92 : : { 93 : 0 : positiveMinimum = minimum; 94 : : } 95 : : 96 : : // get the min/max in log10 scale 97 : 0 : double logMin = std::floor( std::log10( positiveMinimum ) ); 98 : 0 : double logMax = std::ceil( std::log10( maximum ) ); 99 : : 100 : : // calculate pretty breaks 101 : 0 : breaks.append( QgsSymbolLayerUtils::prettyBreaks( logMin, logMax, nclasses ) ); 102 : : 103 : : // create the value 104 : 0 : for ( int i = 0; i < breaks.count(); i++ ) 105 : 0 : breaks[i] = std::pow( 10, breaks.at( i ) ); 106 : : 107 : 0 : return breaks; 108 : 0 : } 109 : : 110 : 0 : QString QgsClassificationLogarithmic::valueToLabel( double value ) const 111 : : { 112 : 0 : if ( value <= 0 ) 113 : : { 114 : 0 : return QString::number( value ); 115 : : } 116 : : else 117 : : { 118 : 0 : if ( std::isnan( value ) ) 119 : : { 120 : 0 : return QObject::tr( "invalid (0 or negative values in the data)" ); 121 : : } 122 : : else 123 : : { 124 : 0 : return QString( QStringLiteral( "10^%1" ) ).arg( std::log10( value ) ); 125 : : } 126 : : } 127 : 0 : } 128 : : 129 : 0 : QString QgsClassificationLogarithmic::labelForRange( double lowerValue, double upperValue, QgsClassificationMethod::ClassPosition position ) const 130 : : { 131 : 0 : QString lowerLabel; 132 : 0 : const QString upperLabel = valueToLabel( upperValue ); 133 : : 134 : 0 : switch ( position ) 135 : : { 136 : : case LowerBound: 137 : 0 : lowerLabel = formatNumber( lowerValue ); // avoid to have float exponent for the minimum value 138 : 0 : break; 139 : : case Inner: 140 : : case UpperBound: 141 : 0 : lowerLabel = valueToLabel( lowerValue ); 142 : 0 : break; 143 : : } 144 : : 145 : 0 : return labelFormat().arg( lowerLabel ).arg( upperLabel ); 146 : 0 : } 147 : : 148 : 0 : bool QgsClassificationLogarithmic::valuesRequired() const 149 : : { 150 : 0 : QgsProcessingContext context; 151 : 0 : const QgsProcessingParameterDefinition *def = parameterDefinition( QStringLiteral( "ZERO_NEG_VALUES_HANDLE" ) ); 152 : 0 : NegativeValueHandling nvh = static_cast< NegativeValueHandling >( QgsProcessingParameters::parameterAsEnum( def, parameterValues(), context ) ); 153 : : 154 : 0 : return nvh != NegativeValueHandling::NoHandling; 155 : 0 : }