QGIS API Documentation  3.20.0-Odense (decaadbb31)
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 : [email protected]
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 <QLocale>
20 
21 
23  : mLowerValue( range.lowerBound() )
24  , mUpperValue( range.upperBound() )
25  , mSymbol( symbol )
26  , mLabel( range.label() )
27  , mRender( render )
28 {
29 }
30 
31 QgsRendererRange::QgsRendererRange( double lowerValue, double upperValue, QgsSymbol *symbol, const QString &label, bool render )
32  : mLowerValue( lowerValue )
33  , mUpperValue( upperValue )
34  , mSymbol( symbol )
35  , mLabel( label )
36  , mRender( render )
37 {}
38 
40  : mLowerValue( range.mLowerValue )
41  , mUpperValue( range.mUpperValue )
42  , mSymbol( range.mSymbol ? range.mSymbol->clone() : nullptr )
43  , mLabel( range.mLabel )
44  , mRender( range.mRender )
45 {}
46 
48 
49 
50 // cpy and swap idiom, note that the cpy is done with 'pass by value'
52 {
53  swap( range );
54  return *this;
55 }
56 
58 {
59  return
60  lowerValue() < other.lowerValue() ||
61  ( qgsDoubleNear( lowerValue(), other.lowerValue() ) && upperValue() < other.upperValue() );
62 }
63 
64 
66 {
67  std::swap( mLowerValue, other.mLowerValue );
68  std::swap( mUpperValue, other.mUpperValue );
69  std::swap( mSymbol, other.mSymbol );
70  std::swap( mLabel, other.mLabel );
71 }
72 
74 {
75  return mLowerValue;
76 }
77 
79 {
80  return mUpperValue;
81 }
82 
84 {
85  return mSymbol.get();
86 }
87 
88 QString QgsRendererRange::label() const
89 {
90  return mLabel;
91 }
92 
94 {
95  if ( mSymbol.get() != s ) mSymbol.reset( s );
96 }
97 
98 void QgsRendererRange::setLabel( const QString &label )
99 {
100  mLabel = label;
101 }
102 
103 void QgsRendererRange::setUpperValue( double upperValue )
104 {
106 }
107 
108 void QgsRendererRange::setLowerValue( double lowerValue )
109 {
111 }
112 
114 {
115  return mRender;
116 }
117 
119 {
120  mRender = render;
121 }
122 
123 QString QgsRendererRange::dump() const
124 {
125  return QStringLiteral( "%1 - %2::%3::%4\n" ).arg( mLowerValue ).arg( mUpperValue ).arg( mLabel, mSymbol ? mSymbol->dump() : QStringLiteral( "(no symbol)" ) );
126 }
127 
128 void QgsRendererRange::toSld( QDomDocument &doc, QDomElement &element, QVariantMap props, bool firstRange ) const
129 {
130  if ( !mSymbol || props.value( QStringLiteral( "attribute" ), QString() ).toString().isEmpty() )
131  return;
132 
133  QString attrName = props[ QStringLiteral( "attribute" )].toString();
134 
135  QDomElement ruleElem = doc.createElement( QStringLiteral( "se:Rule" ) );
136  element.appendChild( ruleElem );
137 
138  QDomElement nameElem = doc.createElement( QStringLiteral( "se:Name" ) );
139  nameElem.appendChild( doc.createTextNode( mLabel ) );
140  ruleElem.appendChild( nameElem );
141 
142  QDomElement descrElem = doc.createElement( QStringLiteral( "se:Description" ) );
143  QDomElement titleElem = doc.createElement( QStringLiteral( "se:Title" ) );
144  QString descrStr = QStringLiteral( "range: %1 - %2" ).arg( qgsDoubleToString( mLowerValue ), qgsDoubleToString( mUpperValue ) );
145  titleElem.appendChild( doc.createTextNode( !mLabel.isEmpty() ? mLabel : descrStr ) );
146  descrElem.appendChild( titleElem );
147  ruleElem.appendChild( descrElem );
148 
149  // create the ogc:Filter for the range
150  QString filterFunc = QStringLiteral( "\"%1\" %2 %3 AND \"%1\" <= %4" )
151  .arg( attrName.replace( '\"', QLatin1String( "\"\"" ) ),
152  firstRange ? QStringLiteral( ">=" ) : QStringLiteral( ">" ),
155  QgsSymbolLayerUtils::createFunctionElement( doc, ruleElem, filterFunc );
156 
157  mSymbol->toSld( doc, ruleElem, props );
158 }
159 
161 
162 
165 
167  : mFormat( QStringLiteral( "%1 - %2" ) )
168  , mReTrailingZeroes( "[.,]?0*$" )
169  , mReNegativeZero( "^\\-0(?:[.,]0*)?$" )
170 {
171 }
172 
173 QgsRendererRangeLabelFormat::QgsRendererRangeLabelFormat( const QString &format, int precision, bool trimTrailingZeroes )
174  : mReTrailingZeroes( "[.,]?0*$" )
175  , mReNegativeZero( "^\\-0(?:[.,]0*)?$" )
176 {
177  setFormat( format );
180 }
181 
182 
184 {
185  return
186  format() == other.format() &&
187  precision() == other.precision() &&
189 }
190 
192 {
193  return !( *this == other );
194 }
195 
197 {
198  // Limit the range of decimal places to a reasonable range
201  mNumberScale = 1.0;
202  mNumberSuffix.clear();
203  while ( precision < 0 )
204  {
205  precision++;
206  mNumberScale /= 10.0;
207  mNumberSuffix.append( '0' );
208  }
209 }
210 
212 {
213  return labelForRange( range.lowerValue(), range.upperValue() );
214 }
215 
216 QString QgsRendererRangeLabelFormat::formatNumber( double value ) const
217 {
218  if ( mPrecision > 0 )
219  {
220  QString valueStr = QLocale().toString( value, 'f', mPrecision );
221  if ( mTrimTrailingZeroes )
222  valueStr = valueStr.remove( mReTrailingZeroes );
223  if ( mReNegativeZero.exactMatch( valueStr ) )
224  valueStr = valueStr.mid( 1 );
225  return valueStr;
226  }
227  else
228  {
229  QString valueStr = QLocale().toString( value * mNumberScale, 'f', 0 );
230  if ( valueStr == QLatin1String( "-0" ) )
231  valueStr = '0';
232  if ( valueStr != QLatin1String( "0" ) )
233  valueStr = valueStr + mNumberSuffix;
234  return valueStr;
235  }
236 }
237 
238 QString QgsRendererRangeLabelFormat::labelForRange( double lower, double upper ) const
239 {
240  QString lowerStr = formatNumber( lower );
241  QString upperStr = formatNumber( upper );
242 
243  QString legend( mFormat );
244  return legend.replace( QLatin1String( "%1" ), lowerStr ).replace( QLatin1String( "%2" ), upperStr );
245 }
246 
248 {
249  mFormat = element.attribute( QStringLiteral( "format" ),
250  element.attribute( QStringLiteral( "prefix" ), QStringLiteral( " " ) ) + "%1" +
251  element.attribute( QStringLiteral( "separator" ), QStringLiteral( " - " ) ) + "%2" +
252  element.attribute( QStringLiteral( "suffix" ), QStringLiteral( " " ) )
253  );
254  setPrecision( element.attribute( QStringLiteral( "decimalplaces" ), QStringLiteral( "4" ) ).toInt() );
255  mTrimTrailingZeroes = element.attribute( QStringLiteral( "trimtrailingzeroes" ), QStringLiteral( "false" ) ) == QLatin1String( "true" );
256 }
257 
259 {
260  element.setAttribute( QStringLiteral( "format" ), mFormat );
261  element.setAttribute( QStringLiteral( "decimalplaces" ), mPrecision );
262  element.setAttribute( QStringLiteral( "trimtrailingzeroes" ), mTrimTrailingZeroes ? QStringLiteral( "true" ) : QStringLiteral( "false" ) );
263 }
264 
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
void setTrimTrailingZeroes(bool trimTrailingZeroes)
QString formatNumber(double value) const
bool operator==(const QgsRendererRangeLabelFormat &other) const
void setUpperValue(double upperValue)
QgsRendererRange()=default
Constructor for QgsRendererRange.
QString label() const
void setSymbol(QgsSymbol *s)
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
void setLabel(const QString &label)
bool renderState() const
void setRenderState(bool render)
QString dump() const
double upperValue() const
void setLowerValue(double lowerValue)
double lowerValue() const
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:38
int ANALYSIS_EXPORT lower(int n, int i)
Lower function.
Definition: MathUtils.cpp:407
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:550
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:598
int precision