QGIS API Documentation 3.43.0-Master (69d1901085b)
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
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 "qgsrendererrange.h"
18#include "qgssymbol.h"
19#include "qgssldexportcontext.h"
20
21#include <QLocale>
22#include <QUuid>
23
24
25QgsRendererRange::QgsRendererRange( const QgsClassificationRange &range, QgsSymbol *symbol, bool render, const QString &uuid )
26 : mLowerValue( range.lowerBound() )
27 , mUpperValue( range.upperBound() )
28 , mSymbol( symbol )
29 , mLabel( range.label() )
30 , mRender( render )
31{
32 mUuid = !uuid.isEmpty() ? uuid : QUuid::createUuid().toString();
33}
34
35QgsRendererRange::QgsRendererRange( double lowerValue, double upperValue, QgsSymbol *symbol, const QString &label, bool render, const QString &uuid )
36 : mLowerValue( lowerValue )
37 , mUpperValue( upperValue )
38 , mSymbol( symbol )
39 , mLabel( label )
40 , mRender( render )
41{
42 mUuid = !uuid.isEmpty() ? uuid : QUuid::createUuid().toString();
43}
44
46 : mLowerValue( range.mLowerValue )
47 , mUpperValue( range.mUpperValue )
48 , mSymbol( range.mSymbol ? range.mSymbol->clone() : nullptr )
49 , mLabel( range.mLabel )
50 , mRender( range.mRender )
51 , mUuid( range.mUuid )
52{}
53
55
57{
60 mSymbol.reset( range.mSymbol ? range.mSymbol->clone() : nullptr );
61 mLabel = range.mLabel;
62 mRender = range.mRender;
63 mUuid = range.mUuid;
64 return *this;
65}
66
68{
69 return
70 lowerValue() < other.lowerValue() ||
71 ( qgsDoubleNear( lowerValue(), other.lowerValue() ) && upperValue() < other.upperValue() );
72}
73
75{
76 return mUuid;
77}
78
80{
81 return mLowerValue;
82}
83
85{
86 return mUpperValue;
87}
88
90{
91 return mSymbol.get();
92}
93
95{
96 return mLabel;
97}
98
100{
101 if ( mSymbol.get() != s ) mSymbol.reset( s );
102}
103
104void QgsRendererRange::setLabel( const QString &label )
105{
106 mLabel = label;
107}
108
109void QgsRendererRange::setUpperValue( double upperValue )
110{
112}
113
114void QgsRendererRange::setLowerValue( double lowerValue )
115{
117}
118
120{
121 return mRender;
122}
123
125{
126 mRender = render;
127}
128
130{
131 return QStringLiteral( "%1 - %2::%3::%4\n" ).arg( mLowerValue ).arg( mUpperValue ).arg( mLabel, mSymbol ? mSymbol->dump() : QStringLiteral( "(no symbol)" ) );
132}
133
134void QgsRendererRange::toSld( QDomDocument &doc, QDomElement &element, QVariantMap props, bool firstRange ) const
135{
136 QgsSldExportContext context;
137 context.setExtraProperties( props );
138 toSld( doc, element, props.value( QStringLiteral( "attribute" ), QString() ).toString(), context, firstRange );
139}
140
141bool QgsRendererRange::toSld( QDomDocument &doc, QDomElement &element, const QString &classAttribute, QgsSldExportContext &context, bool firstRange ) const
142{
143 if ( !mSymbol || classAttribute.isEmpty() )
144 return false;
145
146 QString attrName = classAttribute;
147
148 QDomElement ruleElem = doc.createElement( QStringLiteral( "se:Rule" ) );
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, context );
168
169 mSymbol->toSld( doc, ruleElem, context );
170 if ( !QgsSymbolLayerUtils::hasSldSymbolizer( ruleElem ) )
171 {
172 // symbol could not be converted to SLD, or is an "empty" symbol. In this case we do not generate a rule, as
173 // SLD spec requires a Symbolizer element to be present
174 return false;
175 }
176
177 element.appendChild( ruleElem );
178 return true;
179}
180
182
183
186
188 : mFormat( QStringLiteral( "%1 - %2" ) )
189 , mReTrailingZeroes( "[.,]?0*$" )
190 , mReNegativeZero( "^\\-0(?:[.,]0*)?$" )
191{
192}
193
194QgsRendererRangeLabelFormat::QgsRendererRangeLabelFormat( const QString &format, int precision, bool trimTrailingZeroes )
195 : mReTrailingZeroes( "[.,]?0*$" )
196 , mReNegativeZero( "^\\-0(?:[.,]0*)?$" )
197{
198 setFormat( format );
201}
202
203
205{
206 return
207 format() == other.format() &&
208 precision() == other.precision() &&
210}
211
213{
214 return !( *this == other );
215}
216
218{
219 // Limit the range of decimal places to a reasonable range
222 mNumberScale = 1.0;
223 mNumberSuffix.clear();
224 while ( precision < 0 )
225 {
226 precision++;
227 mNumberScale /= 10.0;
228 mNumberSuffix.append( '0' );
229 }
230}
231
233{
234 return labelForRange( range.lowerValue(), range.upperValue() );
235}
236
237QString QgsRendererRangeLabelFormat::formatNumber( double value ) const
238{
239 if ( mPrecision > 0 )
240 {
241 QString valueStr = QLocale().toString( value, 'f', mPrecision );
243 valueStr = valueStr.remove( mReTrailingZeroes );
244 if ( mReNegativeZero.match( valueStr ).hasMatch() )
245 valueStr = valueStr.mid( 1 );
246 return valueStr;
247 }
248 else
249 {
250 QString valueStr = QLocale().toString( value * mNumberScale, 'f', 0 );
251 if ( valueStr == QLatin1String( "-0" ) )
252 valueStr = '0';
253 if ( valueStr != QLatin1String( "0" ) )
254 valueStr = valueStr + mNumberSuffix;
255 return valueStr;
256 }
257}
258
259QString QgsRendererRangeLabelFormat::labelForRange( double lower, double upper ) const
260{
261 QString lowerStr = formatNumber( lower );
262 QString upperStr = formatNumber( upper );
263
264 QString legend( mFormat );
265 return legend.replace( QLatin1String( "%1" ), lowerStr ).replace( QLatin1String( "%2" ), upperStr );
266}
267
269{
270 mFormat = element.attribute( QStringLiteral( "format" ),
271 element.attribute( QStringLiteral( "prefix" ), QStringLiteral( " " ) ) + "%1" +
272 element.attribute( QStringLiteral( "separator" ), QStringLiteral( " - " ) ) + "%2" +
273 element.attribute( QStringLiteral( "suffix" ), QStringLiteral( " " ) )
274 );
275 setPrecision( element.attribute( QStringLiteral( "decimalplaces" ), QStringLiteral( "4" ) ).toInt() );
276 mTrimTrailingZeroes = element.attribute( QStringLiteral( "trimtrailingzeroes" ), QStringLiteral( "false" ) ) == QLatin1String( "true" );
277}
278
280{
281 element.setAttribute( QStringLiteral( "format" ), mFormat );
282 element.setAttribute( QStringLiteral( "decimalplaces" ), mPrecision );
283 element.setAttribute( QStringLiteral( "trimtrailingzeroes" ), mTrimTrailingZeroes ? QStringLiteral( "true" ) : QStringLiteral( "false" ) );
284}
285
Contains the information about a classification range.
Encapsulates the formatting for a QgsRendererRange label.
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
Returns the label to use for a range with the specified lower and upper bounds.
QRegularExpression mReTrailingZeroes
QRegularExpression mReNegativeZero
void setTrimTrailingZeroes(bool trimTrailingZeroes)
QString formatNumber(double value) const
bool operator==(const QgsRendererRangeLabelFormat &other) const
Represents a value range for a QgsGraduatedSymbolRenderer.
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
Q_DECL_DEPRECATED 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
Holds SLD export options and other information related to SLD export of a QGIS layer style.
void setExtraProperties(const QVariantMap &properties)
Sets the open ended set of properties that can drive/inform the SLD encoding.
static Q_DECL_DEPRECATED bool createFunctionElement(QDomDocument &doc, QDomElement &element, const QString &function)
Creates an OGC function element.
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:6219
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition qgis.h:6302
int precision