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