QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
qgsrendererrange.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsrendererrange.cpp
3 ---------------------
4 begin : September 2019
5 copyright : (C) 2019 by Denis Rouzaud
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 "qgsrendererrange.h"
18#include "qgssymbol.h"
19
20#include <QLocale>
21#include <QUuid>
22
23
24QgsRendererRange::QgsRendererRange( const QgsClassificationRange &range, QgsSymbol *symbol, bool render, const QString &uuid )
25 : mLowerValue( range.lowerBound() )
26 , mUpperValue( range.upperBound() )
27 , mSymbol( symbol )
28 , mLabel( range.label() )
29 , mRender( render )
30{
31 mUuid = !uuid.isEmpty() ? uuid : QUuid::createUuid().toString();
32}
33
34QgsRendererRange::QgsRendererRange( double lowerValue, double upperValue, QgsSymbol *symbol, const QString &label, bool render, const QString &uuid )
35 : mLowerValue( lowerValue )
36 , mUpperValue( upperValue )
37 , mSymbol( symbol )
38 , mLabel( label )
39 , mRender( render )
40{
41 mUuid = !uuid.isEmpty() ? uuid : QUuid::createUuid().toString();
42}
43
45 : mLowerValue( range.mLowerValue )
46 , mUpperValue( range.mUpperValue )
47 , mSymbol( range.mSymbol ? range.mSymbol->clone() : nullptr )
48 , mLabel( range.mLabel )
49 , mRender( range.mRender )
50 , mUuid( range.mUuid )
51{}
52
54
55
56// cpy and swap idiom, note that the cpy is done with 'pass by value'
58{
59 swap( range );
60 return *this;
61}
62
64{
65 return
66 lowerValue() < other.lowerValue() ||
67 ( qgsDoubleNear( lowerValue(), other.lowerValue() ) && upperValue() < other.upperValue() );
68}
69
70
72{
73 std::swap( mLowerValue, other.mLowerValue );
74 std::swap( mUpperValue, other.mUpperValue );
75 std::swap( mSymbol, other.mSymbol );
76 std::swap( mLabel, other.mLabel );
77 std::swap( mUuid, other.mUuid );
78}
79
81{
82 return mUuid;
83}
84
86{
87 return mLowerValue;
88}
89
91{
92 return mUpperValue;
93}
94
96{
97 return mSymbol.get();
98}
99
101{
102 return mLabel;
103}
104
106{
107 if ( mSymbol.get() != s ) mSymbol.reset( s );
108}
109
110void QgsRendererRange::setLabel( const QString &label )
111{
112 mLabel = label;
113}
114
115void QgsRendererRange::setUpperValue( double upperValue )
116{
118}
119
120void QgsRendererRange::setLowerValue( double lowerValue )
121{
123}
124
126{
127 return mRender;
128}
129
131{
132 mRender = render;
133}
134
136{
137 return QStringLiteral( "%1 - %2::%3::%4\n" ).arg( mLowerValue ).arg( mUpperValue ).arg( mLabel, mSymbol ? mSymbol->dump() : QStringLiteral( "(no symbol)" ) );
138}
139
140void QgsRendererRange::toSld( QDomDocument &doc, QDomElement &element, QVariantMap props, bool firstRange ) const
141{
142 if ( !mSymbol || props.value( QStringLiteral( "attribute" ), QString() ).toString().isEmpty() )
143 return;
144
145 QString attrName = props[ QStringLiteral( "attribute" )].toString();
146
147 QDomElement ruleElem = doc.createElement( QStringLiteral( "se:Rule" ) );
148 element.appendChild( ruleElem );
149
150 QDomElement nameElem = doc.createElement( QStringLiteral( "se:Name" ) );
151 nameElem.appendChild( doc.createTextNode( mLabel ) );
152 ruleElem.appendChild( nameElem );
153
154 QDomElement descrElem = doc.createElement( QStringLiteral( "se:Description" ) );
155 QDomElement titleElem = doc.createElement( QStringLiteral( "se:Title" ) );
156 QString descrStr = QStringLiteral( "range: %1 - %2" ).arg( qgsDoubleToString( mLowerValue ), qgsDoubleToString( mUpperValue ) );
157 titleElem.appendChild( doc.createTextNode( !mLabel.isEmpty() ? mLabel : descrStr ) );
158 descrElem.appendChild( titleElem );
159 ruleElem.appendChild( descrElem );
160
161 // create the ogc:Filter for the range
162 QString filterFunc = QStringLiteral( "\"%1\" %2 %3 AND \"%1\" <= %4" )
163 .arg( attrName.replace( '\"', QLatin1String( "\"\"" ) ),
164 firstRange ? QStringLiteral( ">=" ) : QStringLiteral( ">" ),
167 QgsSymbolLayerUtils::createFunctionElement( doc, ruleElem, filterFunc );
168
169 mSymbol->toSld( doc, ruleElem, props );
170}
171
173
174
177
179 : mFormat( QStringLiteral( "%1 - %2" ) )
180 , mReTrailingZeroes( "[.,]?0*$" )
181 , mReNegativeZero( "^\\-0(?:[.,]0*)?$" )
182{
183}
184
185QgsRendererRangeLabelFormat::QgsRendererRangeLabelFormat( const QString &format, int precision, bool trimTrailingZeroes )
186 : mReTrailingZeroes( "[.,]?0*$" )
187 , mReNegativeZero( "^\\-0(?:[.,]0*)?$" )
188{
189 setFormat( format );
192}
193
194
196{
197 return
198 format() == other.format() &&
199 precision() == other.precision() &&
201}
202
204{
205 return !( *this == other );
206}
207
209{
210 // Limit the range of decimal places to a reasonable range
213 mNumberScale = 1.0;
214 mNumberSuffix.clear();
215 while ( precision < 0 )
216 {
217 precision++;
218 mNumberScale /= 10.0;
219 mNumberSuffix.append( '0' );
220 }
221}
222
224{
225 return labelForRange( range.lowerValue(), range.upperValue() );
226}
227
228QString QgsRendererRangeLabelFormat::formatNumber( double value ) const
229{
230 if ( mPrecision > 0 )
231 {
232 QString valueStr = QLocale().toString( value, 'f', mPrecision );
234 valueStr = valueStr.remove( mReTrailingZeroes );
235 if ( mReNegativeZero.match( valueStr ).hasMatch() )
236 valueStr = valueStr.mid( 1 );
237 return valueStr;
238 }
239 else
240 {
241 QString valueStr = QLocale().toString( value * mNumberScale, 'f', 0 );
242 if ( valueStr == QLatin1String( "-0" ) )
243 valueStr = '0';
244 if ( valueStr != QLatin1String( "0" ) )
245 valueStr = valueStr + mNumberSuffix;
246 return valueStr;
247 }
248}
249
250QString QgsRendererRangeLabelFormat::labelForRange( double lower, double upper ) const
251{
252 QString lowerStr = formatNumber( lower );
253 QString upperStr = formatNumber( upper );
254
255 QString legend( mFormat );
256 return legend.replace( QLatin1String( "%1" ), lowerStr ).replace( QLatin1String( "%2" ), upperStr );
257}
258
260{
261 mFormat = element.attribute( QStringLiteral( "format" ),
262 element.attribute( QStringLiteral( "prefix" ), QStringLiteral( " " ) ) + "%1" +
263 element.attribute( QStringLiteral( "separator" ), QStringLiteral( " - " ) ) + "%2" +
264 element.attribute( QStringLiteral( "suffix" ), QStringLiteral( " " ) )
265 );
266 setPrecision( element.attribute( QStringLiteral( "decimalplaces" ), QStringLiteral( "4" ) ).toInt() );
267 mTrimTrailingZeroes = element.attribute( QStringLiteral( "trimtrailingzeroes" ), QStringLiteral( "false" ) ) == QLatin1String( "true" );
268}
269
271{
272 element.setAttribute( QStringLiteral( "format" ), mFormat );
273 element.setAttribute( QStringLiteral( "decimalplaces" ), mPrecision );
274 element.setAttribute( QStringLiteral( "trimtrailingzeroes" ), mTrimTrailingZeroes ? QStringLiteral( "true" ) : QStringLiteral( "false" ) );
275}
276
QgsClassificationRange contains the information about a classification range.
void saveToDomElement(QDomElement &element)
void setFromDomElement(QDomElement &element)
bool operator!=(const QgsRendererRangeLabelFormat &other) const
void setFormat(const QString &format)
void setPrecision(int precision)
QString labelForRange(double lower, double upper) const
QRegularExpression mReTrailingZeroes
QRegularExpression mReNegativeZero
void setTrimTrailingZeroes(bool trimTrailingZeroes)
QString formatNumber(double value) const
bool operator==(const QgsRendererRangeLabelFormat &other) const
void setUpperValue(double upperValue)
Sets the upper bound of the range.
QgsRendererRange()=default
Constructor for QgsRendererRange.
QString label() const
Returns the label used for the range.
void setSymbol(QgsSymbol *s)
Sets the symbol used for the range.
std::unique_ptr< QgsSymbol > mSymbol
void toSld(QDomDocument &doc, QDomElement &element, QVariantMap props, bool firstRange=false) const
Creates a DOM element representing the range in SLD format.
QgsRendererRange & operator=(QgsRendererRange range)
QgsSymbol * symbol() const
Returns the symbol used for the range.
void setLabel(const QString &label)
Sets the label used for the range.
bool renderState() const
Returns true if the range should be rendered.
void setRenderState(bool render)
Sets whether the range should be rendered.
QString dump() const
Dumps a string representation of the range.
double upperValue() const
Returns the upper bound of the range.
void setLowerValue(double lowerValue)
Sets the lower bound of the range.
QString uuid() const
Returns the unique identifier for this range.
double lowerValue() const
Returns the lower bound of the range.
bool operator<(const QgsRendererRange &other) const
void swap(QgsRendererRange &other)
static bool createFunctionElement(QDomDocument &doc, QDomElement &element, const QString &function)
Abstract base class for all rendered symbols.
Definition: qgssymbol.h:94
int ANALYSIS_EXPORT lower(int n, int i)
Lower function.
Definition: MathUtils.cpp:337
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:5124
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:5207
int precision