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