QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
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 
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 
47 // cpy and swap idiom, note that the cpy is done with 'pass by value'
49 {
50  swap( range );
51  return *this;
52 }
53 
55 {
56  return
57  lowerValue() < other.lowerValue() ||
58  ( qgsDoubleNear( lowerValue(), other.lowerValue() ) && upperValue() < other.upperValue() );
59 }
60 
61 
63 {
64  std::swap( mLowerValue, other.mLowerValue );
65  std::swap( mUpperValue, other.mUpperValue );
66  std::swap( mSymbol, other.mSymbol );
67  std::swap( mLabel, other.mLabel );
68 }
69 
71 {
72  return mLowerValue;
73 }
74 
76 {
77  return mUpperValue;
78 }
79 
81 {
82  return mSymbol.get();
83 }
84 
85 QString QgsRendererRange::label() const
86 {
87  return mLabel;
88 }
89 
91 {
92  if ( mSymbol.get() != s ) mSymbol.reset( s );
93 }
94 
95 void QgsRendererRange::setLabel( const QString &label )
96 {
97  mLabel = label;
98 }
99 
100 void QgsRendererRange::setUpperValue( double upperValue )
101 {
103 }
104 
105 void QgsRendererRange::setLowerValue( double lowerValue )
106 {
108 }
109 
111 {
112  return mRender;
113 }
114 
116 {
117  mRender = render;
118 }
119 
120 QString QgsRendererRange::dump() const
121 {
122  return QStringLiteral( "%1 - %2::%3::%4\n" ).arg( mLowerValue ).arg( mUpperValue ).arg( mLabel, mSymbol ? mSymbol->dump() : QStringLiteral( "(no symbol)" ) );
123 }
124 
125 void QgsRendererRange::toSld( QDomDocument &doc, QDomElement &element, QVariantMap props, bool firstRange ) const
126 {
127  if ( !mSymbol || props.value( QStringLiteral( "attribute" ), QString() ).toString().isEmpty() )
128  return;
129 
130  QString attrName = props[ QStringLiteral( "attribute" )].toString();
131 
132  QDomElement ruleElem = doc.createElement( QStringLiteral( "se:Rule" ) );
133  element.appendChild( ruleElem );
134 
135  QDomElement nameElem = doc.createElement( QStringLiteral( "se:Name" ) );
136  nameElem.appendChild( doc.createTextNode( mLabel ) );
137  ruleElem.appendChild( nameElem );
138 
139  QDomElement descrElem = doc.createElement( QStringLiteral( "se:Description" ) );
140  QDomElement titleElem = doc.createElement( QStringLiteral( "se:Title" ) );
141  QString descrStr = QStringLiteral( "range: %1 - %2" ).arg( qgsDoubleToString( mLowerValue ), qgsDoubleToString( mUpperValue ) );
142  titleElem.appendChild( doc.createTextNode( !mLabel.isEmpty() ? mLabel : descrStr ) );
143  descrElem.appendChild( titleElem );
144  ruleElem.appendChild( descrElem );
145 
146  // create the ogc:Filter for the range
147  QString filterFunc = QStringLiteral( "\"%1\" %2 %3 AND \"%1\" <= %4" )
148  .arg( attrName.replace( '\"', QLatin1String( "\"\"" ) ),
149  firstRange ? QStringLiteral( ">=" ) : QStringLiteral( ">" ),
152  QgsSymbolLayerUtils::createFunctionElement( doc, ruleElem, filterFunc );
153 
154  mSymbol->toSld( doc, ruleElem, props );
155 }
156 
158 
159 
162 
164  : mFormat( QStringLiteral( "%1 - %2" ) )
165  , mReTrailingZeroes( "[.,]?0*$" )
166  , mReNegativeZero( "^\\-0(?:[.,]0*)?$" )
167 {
168 }
169 
170 QgsRendererRangeLabelFormat::QgsRendererRangeLabelFormat( const QString &format, int precision, bool trimTrailingZeroes )
171  : mReTrailingZeroes( "[.,]?0*$" )
172  , mReNegativeZero( "^\\-0(?:[.,]0*)?$" )
173 {
174  setFormat( format );
177 }
178 
179 
181 {
182  return
183  format() == other.format() &&
184  precision() == other.precision() &&
186 }
187 
189 {
190  return !( *this == other );
191 }
192 
194 {
195  // Limit the range of decimal places to a reasonable range
198  mNumberScale = 1.0;
199  mNumberSuffix.clear();
200  while ( precision < 0 )
201  {
202  precision++;
203  mNumberScale /= 10.0;
204  mNumberSuffix.append( '0' );
205  }
206 }
207 
209 {
210  return labelForRange( range.lowerValue(), range.upperValue() );
211 }
212 
213 QString QgsRendererRangeLabelFormat::formatNumber( double value ) const
214 {
215  if ( mPrecision > 0 )
216  {
217  QString valueStr = QLocale().toString( value, 'f', mPrecision );
218  if ( mTrimTrailingZeroes )
219  valueStr = valueStr.remove( mReTrailingZeroes );
220  if ( mReNegativeZero.exactMatch( valueStr ) )
221  valueStr = valueStr.mid( 1 );
222  return valueStr;
223  }
224  else
225  {
226  QString valueStr = QLocale().toString( value * mNumberScale, 'f', 0 );
227  if ( valueStr == QLatin1String( "-0" ) )
228  valueStr = '0';
229  if ( valueStr != QLatin1String( "0" ) )
230  valueStr = valueStr + mNumberSuffix;
231  return valueStr;
232  }
233 }
234 
235 QString QgsRendererRangeLabelFormat::labelForRange( double lower, double upper ) const
236 {
237  QString lowerStr = formatNumber( lower );
238  QString upperStr = formatNumber( upper );
239 
240  QString legend( mFormat );
241  return legend.replace( QLatin1String( "%1" ), lowerStr ).replace( QLatin1String( "%2" ), upperStr );
242 }
243 
245 {
246  mFormat = element.attribute( QStringLiteral( "format" ),
247  element.attribute( QStringLiteral( "prefix" ), QStringLiteral( " " ) ) + "%1" +
248  element.attribute( QStringLiteral( "separator" ), QStringLiteral( " - " ) ) + "%2" +
249  element.attribute( QStringLiteral( "suffix" ), QStringLiteral( " " ) )
250  );
251  setPrecision( element.attribute( QStringLiteral( "decimalplaces" ), QStringLiteral( "4" ) ).toInt() );
252  mTrimTrailingZeroes = element.attribute( QStringLiteral( "trimtrailingzeroes" ), QStringLiteral( "false" ) ) == QLatin1String( "true" );
253 }
254 
256 {
257  element.setAttribute( QStringLiteral( "format" ), mFormat );
258  element.setAttribute( QStringLiteral( "decimalplaces" ), mPrecision );
259  element.setAttribute( QStringLiteral( "trimtrailingzeroes" ), mTrimTrailingZeroes ? QStringLiteral( "true" ) : QStringLiteral( "false" ) );
260 }
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:65
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:276
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:316
int precision