16 #include <QRegularExpression>
34 values.reserve(
classes.count() );
35 for (
int i = 0 ; i <
classes.count(); i++ )
36 values <<
classes.at( i ).upperBound();
41 : mFlags( properties )
42 , mCodeComplexity( codeComplexity )
43 , mLabelFormat( QStringLiteral(
"%1 - %2" ) )
49 qDeleteAll( mParameters );
54 c->setSymmetricMode( mSymmetricEnabled, mSymmetryPoint, mSymmetryAstride );
55 c->setLabelFormat( mLabelFormat );
56 c->setLabelPrecision( mLabelPrecision );
57 c->setLabelTrimTrailingZeroes( mLabelTrimTrailingZeroes );
58 c->setParameterValues( mParameterValues );
63 const QString methodId = element.attribute( QStringLiteral(
"id" ) );
67 QDomElement symmetricModeElem = element.firstChildElement( QStringLiteral(
"symmetricMode" ) );
68 if ( !symmetricModeElem.isNull() )
70 bool symmetricEnabled = symmetricModeElem.attribute( QStringLiteral(
"enabled" ) ).toInt() == 1;
71 double symmetricPoint = symmetricModeElem.attribute( QStringLiteral(
"symmetrypoint" ) ).toDouble();
72 bool astride = symmetricModeElem.attribute( QStringLiteral(
"astride" ) ).toInt() == 1;
77 QDomElement labelFormatElem = element.firstChildElement( QStringLiteral(
"labelformat" ) );
78 if ( !labelFormatElem.isNull() )
80 QString format = labelFormatElem.attribute( QStringLiteral(
"format" ),
"%1" + QStringLiteral(
" - " ) +
"%2" );
81 int precision = labelFormatElem.attribute( QStringLiteral(
"labelprecision" ), QStringLiteral(
"4" ) ).toInt();
82 bool trimTrailingZeroes = labelFormatElem.attribute( QStringLiteral(
"trimtrailingzeroes" ), QStringLiteral(
"false" ) ) == QLatin1String(
"true" );
89 QDomElement parametersElem = element.firstChildElement( QStringLiteral(
"parameters" ) );
94 QDomElement extraElem = element.firstChildElement( QStringLiteral(
"extraInformation" ) );
95 if ( !extraElem.isNull() )
96 method->
readXml( extraElem, context );
103 QDomElement methodElem = doc.createElement( QStringLiteral(
"classificationMethod" ) );
105 methodElem.setAttribute( QStringLiteral(
"id" ),
id() );
108 QDomElement symmetricModeElem = doc.createElement( QStringLiteral(
"symmetricMode" ) );
110 symmetricModeElem.setAttribute( QStringLiteral(
"symmetrypoint" ),
symmetryPoint() );
111 symmetricModeElem.setAttribute( QStringLiteral(
"astride" ), mSymmetryAstride ? 1 : 0 );
112 methodElem.appendChild( symmetricModeElem );
115 QDomElement labelFormatElem = doc.createElement( QStringLiteral(
"labelFormat" ) );
116 labelFormatElem.setAttribute( QStringLiteral(
"format" ),
labelFormat() );
117 labelFormatElem.setAttribute( QStringLiteral(
"labelprecision" ),
labelPrecision() );
119 methodElem.appendChild( labelFormatElem );
122 QDomElement parametersElem = doc.createElement( QStringLiteral(
"parameters" ) );
124 methodElem.appendChild( parametersElem );
127 QDomElement extraElem = doc.createElement( QStringLiteral(
"extraInformation" ) );
129 methodElem.appendChild( extraElem );
137 mSymmetricEnabled = enabled;
139 mSymmetryAstride = astride;
147 mLabelNumberScale = 1.0;
148 mLabelNumberSuffix.clear();
152 mLabelNumberScale /= 10.0;
153 mLabelNumberSuffix.append(
'0' );
159 static const QRegularExpression RE_TRAILING_ZEROES = QRegularExpression(
"[.,]?0*$" );
160 static const QRegularExpression RE_NEGATIVE_ZERO = QRegularExpression(
"^\\-0(?:[.,]0*)?$" );
161 if ( mLabelPrecision > 0 )
163 QString valueStr = QLocale().toString( value,
'f', mLabelPrecision );
164 if ( mLabelTrimTrailingZeroes )
165 valueStr = valueStr.remove( RE_TRAILING_ZEROES );
166 if ( RE_NEGATIVE_ZERO.match( valueStr ).hasMatch() )
167 valueStr = valueStr.mid( 1 );
172 QString valueStr = QLocale().toString( value * mLabelNumberScale,
'f', 0 );
173 if ( valueStr == QLatin1String(
"-0" ) )
175 if ( valueStr != QLatin1String(
"0" ) )
176 valueStr = valueStr + mLabelNumberSuffix;
183 mParameters.append( definition );
190 if ( def->name() == parameterName )
199 mParameterValues = values;
200 for (
auto it = mParameterValues.constBegin(); it != mParameterValues.constEnd(); ++it )
211 if ( expression.isEmpty() )
212 return QList<QgsClassificationRange>();
217 QList<double> values;
228 if ( !ok || values.isEmpty() )
229 return QList<QgsClassificationRange>();
231 auto result = std::minmax_element( values.begin(), values.end() );
232 minimum = *result.first;
233 maximum = *result.second;
242 QList<double> breaks = calculateBreaks( minimum, maximum, values, nclasses );
243 breaks.insert( 0, minimum );
245 return breaksToClasses( breaks );
250 auto result = std::minmax_element( values.begin(), values.end() );
251 double minimum = *result.first;
252 double maximum = *result.second;
255 QList<double> breaks = calculateBreaks( minimum, maximum, values, nclasses );
256 breaks.insert( 0, minimum );
258 return breaksToClasses( breaks );
265 QgsDebugMsg( QStringLiteral(
"The classification method %1 tries to calculate classes without values while they are required." ).arg(
name() ) );
269 QList<double> breaks = calculateBreaks( minimum, maximum, QList<double>(), nclasses );
270 breaks.insert( 0, minimum );
272 return breaksToClasses( breaks );
275 QList<QgsClassificationRange> QgsClassificationMethod::breaksToClasses(
const QList<double> &breaks )
const
277 QList<QgsClassificationRange>
classes;
279 for (
int i = 1; i < breaks.count(); i++ )
282 const double lowerValue = breaks.at( i - 1 );
283 const double upperValue = breaks.at( i );
288 else if ( i == breaks.count() - 1 )
291 QString label =
labelForRange( lowerValue, upperValue, pos );
305 if ( breaks.count() < 2 )
308 std::sort( breaks.begin(), breaks.end() );
310 double distBelowSymmetricValue = std::fabs( breaks[0] -
symmetryPoint );
311 double distAboveSymmetricValue = std::fabs( breaks[ breaks.size() - 2 ] -
symmetryPoint ) ;
312 double absMin = std::min( distAboveSymmetricValue, distBelowSymmetricValue );
315 for (
int i = 0; i <= breaks.size() - 2; ++i )
318 if ( std::fabs( breaks.at( i ) -
symmetryPoint ) >= ( absMin - std::fabs( breaks[0] - breaks[1] ) / 100. ) )
320 breaks.removeAt( i );
340 const QString lowerLabel = valueToLabel( lowerValue );
341 const QString upperLabel = valueToLabel( upperValue );
343 return labelFormat().arg( lowerLabel ).arg( upperLabel );