QGIS API Documentation 3.41.0-Master (af5edcb665c)
Loading...
Searching...
No Matches
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
56{
59 mSymbol.reset( range.mSymbol ? range.mSymbol->clone() : nullptr );
60 mLabel = range.mLabel;
61 mRender = range.mRender;
62 mUuid = range.mUuid;
63 return *this;
64}
65
67{
68 return
69 lowerValue() < other.lowerValue() ||
70 ( qgsDoubleNear( lowerValue(), other.lowerValue() ) && upperValue() < other.upperValue() );
71}
72
74{
75 return mUuid;
76}
77
79{
80 return mLowerValue;
81}
82
84{
85 return mUpperValue;
86}
87
89{
90 return mSymbol.get();
91}
92
94{
95 return mLabel;
96}
97
99{
100 if ( mSymbol.get() != s ) mSymbol.reset( s );
101}
102
103void QgsRendererRange::setLabel( const QString &label )
104{
105 mLabel = label;
106}
107
108void QgsRendererRange::setUpperValue( double upperValue )
109{
111}
112
113void QgsRendererRange::setLowerValue( double lowerValue )
114{
116}
117
119{
120 return mRender;
121}
122
124{
125 mRender = render;
126}
127
129{
130 return QStringLiteral( "%1 - %2::%3::%4\n" ).arg( mLowerValue ).arg( mUpperValue ).arg( mLabel, mSymbol ? mSymbol->dump() : QStringLiteral( "(no symbol)" ) );
131}
132
133void QgsRendererRange::toSld( QDomDocument &doc, QDomElement &element, QVariantMap props, bool firstRange ) const
134{
135 if ( !mSymbol || props.value( QStringLiteral( "attribute" ), QString() ).toString().isEmpty() )
136 return;
137
138 QString attrName = props[ QStringLiteral( "attribute" )].toString();
139
140 QDomElement ruleElem = doc.createElement( QStringLiteral( "se:Rule" ) );
141
142 QDomElement nameElem = doc.createElement( QStringLiteral( "se:Name" ) );
143 nameElem.appendChild( doc.createTextNode( mLabel ) );
144 ruleElem.appendChild( nameElem );
145
146 QDomElement descrElem = doc.createElement( QStringLiteral( "se:Description" ) );
147 QDomElement titleElem = doc.createElement( QStringLiteral( "se:Title" ) );
148 QString descrStr = QStringLiteral( "range: %1 - %2" ).arg( qgsDoubleToString( mLowerValue ), qgsDoubleToString( mUpperValue ) );
149 titleElem.appendChild( doc.createTextNode( !mLabel.isEmpty() ? mLabel : descrStr ) );
150 descrElem.appendChild( titleElem );
151 ruleElem.appendChild( descrElem );
152
153 // create the ogc:Filter for the range
154 QString filterFunc = QStringLiteral( "\"%1\" %2 %3 AND \"%1\" <= %4" )
155 .arg( attrName.replace( '\"', QLatin1String( "\"\"" ) ),
156 firstRange ? QStringLiteral( ">=" ) : QStringLiteral( ">" ),
159 QgsSymbolLayerUtils::createFunctionElement( doc, ruleElem, filterFunc );
160
161 mSymbol->toSld( doc, ruleElem, props );
162 if ( !QgsSymbolLayerUtils::hasSldSymbolizer( ruleElem ) )
163 {
164 // symbol could not be converted to SLD, or is an "empty" symbol. In this case we do not generate a rule, as
165 // SLD spec requires a Symbolizer element to be present
166 return;
167 }
168
169 element.appendChild( ruleElem );
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)
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
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
static bool createFunctionElement(QDomDocument &doc, QDomElement &element, const QString &function)
static bool hasSldSymbolizer(const QDomElement &element)
Returns true if a DOM element contains an SLD Symbolizer element.
Abstract base class for all rendered symbols.
Definition qgssymbol.h:231
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition qgis.h:5983
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition qgis.h:6066
int precision