QGIS API Documentation  2.9.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
qgsgraduatedsymbolrendererv2.cpp
Go to the documentation of this file.
1 
2 /***************************************************************************
3  qgsgraduatedsymbolrendererv2.cpp
4  ---------------------
5  begin : November 2009
6  copyright : (C) 2009 by Martin Dobias
7  email : wonder dot sk at gmail dot com
8  ***************************************************************************
9  * *
10  * This program is free software; you can redistribute it and/or modify *
11  * it under the terms of the GNU General Public License as published by *
12  * the Free Software Foundation; either version 2 of the License, or *
13  * (at your option) any later version. *
14  * *
15  ***************************************************************************/
17 
18 #include "qgssymbolv2.h"
19 #include "qgssymbollayerv2utils.h"
20 #include "qgsvectorcolorrampv2.h"
23 #include "qgspainteffect.h"
24 
25 #include "qgsfeature.h"
26 #include "qgsvectorlayer.h"
27 #include "qgslogger.h"
28 #include "qgsvectordataprovider.h"
29 #include "qgsexpression.h"
30 #include <QDomDocument>
31 #include <QDomElement>
32 #include <QSettings> // for legend
33 #include <limits> // for jenks classification
34 #include <ctime>
35 
37  : mLowerValue( 0 )
38  , mUpperValue( 0 )
39  , mSymbol( 0 )
40  , mLabel()
41  , mRender( true )
42 {
43 }
44 
45 QgsRendererRangeV2::QgsRendererRangeV2( double lowerValue, double upperValue, QgsSymbolV2* symbol, QString label, bool render )
46  : mLowerValue( lowerValue )
47  , mUpperValue( upperValue )
48  , mSymbol( symbol )
49  , mLabel( label )
50  , mRender( render )
51 {
52 }
53 
55  : mLowerValue( range.mLowerValue )
56  , mUpperValue( range.mUpperValue )
57  , mSymbol( range.mSymbol.data() ? range.mSymbol->clone() : NULL )
58  , mLabel( range.mLabel )
59  , mRender( range.mRender )
60 {
61 }
62 
63 // cpy and swap idiom, note that the cpy is done with 'pass by value'
65 {
66  swap( range );
67  return *this;
68 }
69 
71 {
72  return
73  lowerValue() < other.lowerValue() ||
74  ( lowerValue() == other.lowerValue() && upperValue() < other.upperValue() );
75 }
76 
77 
79 {
80  qSwap( mLowerValue, other.mLowerValue );
81  qSwap( mUpperValue, other.mUpperValue );
82  qSwap( mSymbol, other.mSymbol );
83  std::swap( mLabel, other.mLabel );
84 }
85 
87 {
88  return mLowerValue;
89 }
90 
92 {
93  return mUpperValue;
94 }
95 
97 {
98  return mSymbol.data();
99 }
100 
102 {
103  return mLabel;
104 }
105 
107 {
108  if ( mSymbol.data() != s ) mSymbol.reset( s );
109 }
110 
111 void QgsRendererRangeV2::setLabel( QString label )
112 {
113  mLabel = label;
114 }
115 
116 void QgsRendererRangeV2::setUpperValue( double upperValue )
117 {
119 }
120 
121 void QgsRendererRangeV2::setLowerValue( double lowerValue )
122 {
124 }
125 
127 {
128  return mRender;
129 }
130 
132 {
133  mRender = render;
134 }
135 
137 {
138  return QString( "%1 - %2::%3::%4\n" ).arg( mLowerValue ).arg( mUpperValue ).arg( mLabel ).arg( mSymbol.data() ? mSymbol->dump() : "(no symbol)" );
139 }
140 
141 void QgsRendererRangeV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
142 {
143  if ( !mSymbol.data() || props.value( "attribute", "" ).isEmpty() )
144  return;
145 
146  QString attrName = props[ "attribute" ];
147 
148  QDomElement ruleElem = doc.createElement( "se:Rule" );
149  element.appendChild( ruleElem );
150 
151  QDomElement nameElem = doc.createElement( "se:Name" );
152  nameElem.appendChild( doc.createTextNode( mLabel ) );
153  ruleElem.appendChild( nameElem );
154 
155  QDomElement descrElem = doc.createElement( "se:Description" );
156  QDomElement titleElem = doc.createElement( "se:Title" );
157  QString descrStr = QString( "range: %1 - %2" ).arg( mLowerValue ).arg( mUpperValue );
158  titleElem.appendChild( doc.createTextNode( !mLabel.isEmpty() ? mLabel : descrStr ) );
159  descrElem.appendChild( titleElem );
160  ruleElem.appendChild( descrElem );
161 
162  // create the ogc:Filter for the range
163  QString filterFunc = QString( "%1 > %2 AND %1 <= %3" )
164  .arg( attrName.replace( "\"", "\"\"" ) )
165  .arg( mLowerValue ).arg( mUpperValue );
166  QgsSymbolLayerV2Utils::createFunctionElement( doc, ruleElem, filterFunc );
167 
168  mSymbol->toSld( doc, ruleElem, props );
169 }
170 
172 
175 
177  mFormat( " %1 - %2 " ),
178  mPrecision( 4 ),
179  mTrimTrailingZeroes( false ),
180  mNumberScale( 1.0 ),
181  mNumberSuffix( "" ),
182  mReTrailingZeroes( "[.,]?0*$" ),
183  mReNegativeZero( "^\\-0(?:[.,]0*)?$" )
184 {
185 }
186 
187 QgsRendererRangeV2LabelFormat::QgsRendererRangeV2LabelFormat( QString format, int precision, bool trimTrailingZeroes ):
188  mReTrailingZeroes( "[.,]?0*$" ),
189  mReNegativeZero( "^\\-0(?:[.,]0*)?$" )
190 {
191  setFormat( format );
192  setPrecision( precision );
193  setTrimTrailingZeroes( trimTrailingZeroes );
194 }
195 
196 
198 {
199  return
200  format() == other.format() &&
201  precision() == other.precision() &&
203 }
204 
206 {
207  return !( *this == other );
208 }
209 
211 {
212  // Limit the range of decimal places to a reasonable range
213  precision = qBound( MinPrecision, precision, MaxPrecision );
215  mNumberScale = 1.0;
216  mNumberSuffix = "";
217  while ( precision < 0 )
218  {
219  precision++;
220  mNumberScale /= 10.0;
221  mNumberSuffix.append( '0' );
222  }
223 }
224 
226 {
227  return labelForRange( range.lowerValue(), range.upperValue() );
228 }
229 
230 QString QgsRendererRangeV2LabelFormat::formatNumber( double value ) const
231 {
232  if ( mPrecision > 0 )
233  {
234  QString valueStr = QString::number( value, 'f', mPrecision );
235  if ( mTrimTrailingZeroes )
236  valueStr = valueStr.replace( mReTrailingZeroes, "" );
237  if ( mReNegativeZero.exactMatch( valueStr ) )
238  valueStr = valueStr.mid( 1 );
239  return valueStr;
240  }
241  else
242  {
243  QString valueStr = QString::number( value * mNumberScale, 'f', 0 );
244  if ( valueStr == "-0" )
245  valueStr = "0";
246  if ( valueStr != "0" )
247  valueStr = valueStr + mNumberSuffix;
248  return valueStr;
249  }
250 }
251 
252 QString QgsRendererRangeV2LabelFormat::labelForRange( double lower, double upper ) const
253 {
254  QString lowerStr = formatNumber( lower );
255  QString upperStr = formatNumber( upper );
256 
257  QString legend( mFormat );
258  return legend.replace( "%1", lowerStr ).replace( "%2", upperStr );
259 }
260 
262 {
263  mFormat = element.attribute( "format",
264  element.attribute( "prefix", " " ) + "%1" +
265  element.attribute( "separator", " - " ) + "%2" +
266  element.attribute( "suffix", " " )
267  );
268  setPrecision( element.attribute( "decimalplaces", "4" ).toInt() );
269  mTrimTrailingZeroes = element.attribute( "trimtrailingzeroes", "false" ) == "true";
270 }
271 
273 {
274  element.setAttribute( "format", mFormat );
275  element.setAttribute( "decimalplaces", mPrecision );
276  element.setAttribute( "trimtrailingzeroes", mTrimTrailingZeroes ? "true" : "false" );
277 }
278 
280 
282  : QgsFeatureRendererV2( "graduatedSymbol" )
283  , mAttrName( attrName )
284  , mRanges( ranges )
285  , mMode( Custom )
286  , mInvertedColorRamp( false )
287  , mScaleMethod( DEFAULT_SCALE_METHOD )
288  , mGraduatedMethod( GraduatedColor )
289  , mAttrNum( -1 )
290  , mCounting( false )
291 
292 {
293  // TODO: check ranges for sanity (NULL symbols, invalid ranges)
294 }
295 
297 {
298  mRanges.clear(); // should delete all the symbols
299 }
300 
302 {
303  for ( QgsRangeList::iterator it = mRanges.begin(); it != mRanges.end(); ++it )
304  {
305  if ( it->lowerValue() <= value && it->upperValue() >= value )
306  {
307  if ( it->renderState() || mCounting )
308  return it->symbol();
309  else
310  return NULL;
311  }
312  }
313  // the value is out of the range: return NULL instead of symbol
314  return NULL;
315 }
316 
318 {
319  QgsSymbolV2* symbol = originalSymbolForFeature( feature );
320  if ( symbol == NULL )
321  return NULL;
322 
323  if ( !mRotation.data() && !mSizeScale.data() )
324  return symbol; // no data-defined rotation/scaling - just return the symbol
325 
326  // find out rotation, size scale
327  const double rotation = mRotation.data() ? mRotation->evaluate( feature ).toDouble() : 0;
328  const double sizeScale = mSizeScale.data() ? mSizeScale->evaluate( feature ).toDouble() : 1.;
329 
330  // take a temporary symbol (or create it if doesn't exist)
331  QgsSymbolV2* tempSymbol = mTempSymbols[symbol];
332 
333  // modify the temporary symbol and return it
334  if ( tempSymbol->type() == QgsSymbolV2::Marker )
335  {
336  QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( tempSymbol );
337  if ( mRotation.data() ) markerSymbol->setAngle( rotation );
338  markerSymbol->setSize( sizeScale * static_cast<QgsMarkerSymbolV2*>( symbol )->size() );
339  markerSymbol->setScaleMethod( mScaleMethod );
340  }
341  else if ( tempSymbol->type() == QgsSymbolV2::Line )
342  {
343  QgsLineSymbolV2* lineSymbol = static_cast<QgsLineSymbolV2*>( tempSymbol );
344  lineSymbol->setWidth( sizeScale * static_cast<QgsLineSymbolV2*>( symbol )->width() );
345  }
346  return tempSymbol;
347 }
348 
350 {
351  const QgsAttributes& attrs = feature.attributes();
352  QVariant value;
353  if ( mAttrNum < 0 || mAttrNum >= attrs.count() )
354  {
355  value = mExpression->evaluate( &feature );
356  }
357  else
358  {
359  value = attrs[mAttrNum];
360  }
361 
362  // Null values should not be categorized
363  if ( value.isNull() )
364  return NULL;
365 
366  // find the right category
367  return symbolForValue( value.toDouble() );
368 }
369 
371 {
372  mCounting = context.rendererScale() == 0.0;
373 
374  // find out classification attribute index from name
375  mAttrNum = fields.fieldNameIndex( mAttrName );
376 
377  if ( mAttrNum == -1 )
378  {
379  mExpression.reset( new QgsExpression( mAttrName ) );
380  mExpression->prepare( fields );
381  }
382 
383  QgsRangeList::iterator it = mRanges.begin();
384  for ( ; it != mRanges.end(); ++it )
385  {
386  if ( !it->symbol() )
387  continue;
388 
389  it->symbol()->startRender( context, &fields );
390 
391  if ( mRotation.data() || mSizeScale.data() )
392  {
393  QgsSymbolV2* tempSymbol = it->symbol()->clone();
394  tempSymbol->setRenderHints(( mRotation.data() ? QgsSymbolV2::DataDefinedRotation : 0 ) |
396  tempSymbol->startRender( context, &fields );
397  mTempSymbols[ it->symbol()] = tempSymbol;
398  }
399  }
400 }
401 
403 {
404  QgsRangeList::iterator it = mRanges.begin();
405  for ( ; it != mRanges.end(); ++it )
406  {
407  if ( !it->symbol() )
408  continue;
409 
410  it->symbol()->stopRender( context );
411  }
412 
413  // cleanup mTempSymbols
414  QHash<QgsSymbolV2*, QgsSymbolV2*>::iterator it2 = mTempSymbols.begin();
415  for ( ; it2 != mTempSymbols.end(); ++it2 )
416  {
417  it2.value()->stopRender( context );
418  delete it2.value();
419  }
420  mTempSymbols.clear();
421 }
422 
424 {
425  QSet<QString> attributes;
426 
427  // mAttrName can contain either attribute name or an expression.
428  // Sometimes it is not possible to distinguish between those two,
429  // e.g. "a - b" can be both a valid attribute name or expression.
430  // Since we do not have access to fields here, try both options.
431  attributes << mAttrName;
432 
433  QgsExpression testExpr( mAttrName );
434  if ( !testExpr.hasParserError() )
435  attributes.unite( testExpr.referencedColumns().toSet() );
436 
437  if ( mRotation.data() ) attributes.unite( mRotation->referencedColumns().toSet() );
438  if ( mSizeScale.data() ) attributes.unite( mSizeScale->referencedColumns().toSet() );
439 
440  QgsRangeList::const_iterator range_it = mRanges.constBegin();
441  for ( ; range_it != mRanges.constEnd(); ++range_it )
442  {
443  QgsSymbolV2* symbol = range_it->symbol();
444  if ( symbol )
445  {
446  attributes.unite( symbol->usedAttributes() );
447  }
448  }
449  return attributes.toList();
450 }
451 
453 {
454  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
455  return false;
456  mRanges[rangeIndex].setSymbol( symbol );
457  return true;
458 }
459 
460 bool QgsGraduatedSymbolRendererV2::updateRangeLabel( int rangeIndex, QString label )
461 {
462  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
463  return false;
464  mRanges[rangeIndex].setLabel( label );
465  return true;
466 }
467 
468 bool QgsGraduatedSymbolRendererV2::updateRangeUpperValue( int rangeIndex, double value )
469 {
470  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
471  return false;
472  QgsRendererRangeV2 &range = mRanges[rangeIndex];
473  bool isDefaultLabel = range.label() == mLabelFormat.labelForRange( range );
474  range.setUpperValue( value );
475  if ( isDefaultLabel ) range.setLabel( mLabelFormat.labelForRange( range ) );
476  return true;
477 }
478 
479 bool QgsGraduatedSymbolRendererV2::updateRangeLowerValue( int rangeIndex, double value )
480 {
481  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
482  return false;
483  QgsRendererRangeV2 &range = mRanges[rangeIndex];
484  bool isDefaultLabel = range.label() == mLabelFormat.labelForRange( range );
485  range.setLowerValue( value );
486  if ( isDefaultLabel ) range.setLabel( mLabelFormat.labelForRange( range ) );
487  return true;
488 }
489 
491 {
492  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
493  return false;
494  mRanges[rangeIndex].setRenderState( value );
495  return true;
496 }
497 
499 {
500  QString s = QString( "GRADUATED: attr %1\n" ).arg( mAttrName );
501  for ( int i = 0; i < mRanges.count(); i++ )
502  s += mRanges[i].dump();
503  return s;
504 }
505 
507 {
509  r->setMode( mMode );
510  if ( mSourceSymbol.data() )
511  r->setSourceSymbol( mSourceSymbol->clone() );
512  if ( mSourceColorRamp.data() )
513  {
514  r->setSourceColorRamp( mSourceColorRamp->clone() );
516  }
520  r->setScaleMethod( scaleMethod() );
521  r->setLabelFormat( labelFormat() );
523  copyPaintEffect( r );
524  return r;
525 }
526 
527 void QgsGraduatedSymbolRendererV2::toSld( QDomDocument& doc, QDomElement &element ) const
528 {
529  QgsStringMap props;
530  props[ "attribute" ] = mAttrName;
531  props[ "method" ] = graduatedMethodStr( mGraduatedMethod );
532  if ( mRotation.data() )
533  props[ "angle" ] = mRotation->expression();
534  if ( mSizeScale.data() )
535  props[ "scale" ] = mSizeScale->expression();
536 
537  // create a Rule for each range
538  for ( QgsRangeList::const_iterator it = mRanges.constBegin(); it != mRanges.constEnd(); ++it )
539  {
540  QgsStringMap catProps( props );
541  it->toSld( doc, element, catProps );
542  }
543 }
544 
546 {
547  QgsSymbolV2List lst;
548  for ( int i = 0; i < mRanges.count(); i++ )
549  lst.append( mRanges[i].symbol() );
550  return lst;
551 }
552 
553 static QList<double> _calcEqualIntervalBreaks( double minimum, double maximum, int classes )
554 {
555 
556  // Equal interval algorithm
557  //
558  // Returns breaks based on dividing the range ('minimum' to 'maximum')
559  // into 'classes' parts.
560 
561  double step = ( maximum - minimum ) / classes;
562 
563  QList<double> breaks;
564  double value = minimum;
565  for ( int i = 0; i < classes; i++ )
566  {
567  value += step;
568  breaks.append( value );
569  }
570 
571  // floating point arithmetics is not precise:
572  // set the last break to be exactly maximum so we do not miss it
573  breaks[classes-1] = maximum;
574 
575  return breaks;
576 }
577 
578 static QList<double> _calcQuantileBreaks( QList<double> values, int classes )
579 {
580  // q-th quantile of a data set:
581  // value where q fraction of data is below and (1-q) fraction is above this value
582  // Xq = (1 - r) * X_NI1 + r * X_NI2
583  // NI1 = (int) (q * (n+1))
584  // NI2 = NI1 + 1
585  // r = q * (n+1) - (int) (q * (n+1))
586  // (indices of X: 1...n)
587 
588  // sort the values first
589  qSort( values );
590 
591  QList<double> breaks;
592 
593  // If there are no values to process: bail out
594  if ( !values.count() )
595  return breaks;
596 
597  int n = values.count();
598  double Xq = n > 0 ? values[0] : 0.0;
599 
600  for ( int i = 1; i < classes; i++ )
601  {
602  if ( n > 1 )
603  {
604  double q = i / ( double ) classes;
605  double a = q * ( n - 1 );
606  int aa = ( int )( a );
607 
608  double r = a - aa;
609  Xq = ( 1 - r ) * values[aa] + r * values[aa+1];
610  }
611  breaks.append( Xq );
612  }
613 
614  breaks.append( values[ n-1 ] );
615 
616  return breaks;
617 }
618 
619 static QList<double> _calcStdDevBreaks( QList<double> values, int classes, QList<double> &labels )
620 {
621 
622  // C++ implementation of the standard deviation class interval algorithm
623  // as implemented in the 'classInt' package available for the R statistical
624  // prgramming language.
625 
626  // Returns breaks based on 'prettyBreaks' of the centred and scaled
627  // values of 'values', and may have a number of classes different from 'classes'.
628 
629  // If there are no values to process: bail out
630  if ( !values.count() )
631  return QList<double>();
632 
633  double mean = 0.0;
634  double stdDev = 0.0;
635  int n = values.count();
636  double minimum = values[0];
637  double maximum = values[0];
638 
639  for ( int i = 0; i < n; i++ )
640  {
641  mean += values[i];
642  minimum = qMin( values[i], minimum ); // could use precomputed max and min
643  maximum = qMax( values[i], maximum ); // but have to go through entire list anyway
644  }
645  mean = mean / ( double ) n;
646 
647  double sd = 0.0;
648  for ( int i = 0; i < n; i++ )
649  {
650  sd = values[i] - mean;
651  stdDev += sd * sd;
652  }
653  stdDev = sqrt( stdDev / n );
654 
655  QList<double> breaks = QgsSymbolLayerV2Utils::prettyBreaks(( minimum - mean ) / stdDev, ( maximum - mean ) / stdDev, classes );
656  for ( int i = 0; i < breaks.count(); i++ )
657  {
658  labels.append( breaks[i] );
659  breaks[i] = ( breaks[i] * stdDev ) + mean;
660  }
661 
662  return breaks;
663 } // _calcStdDevBreaks
664 
665 static QList<double> _calcJenksBreaks( QList<double> values, int classes,
666  double minimum, double maximum,
667  int maximumSize = 1000 )
668 {
669  // Jenks Optimal (Natural Breaks) algorithm
670  // Based on the Jenks algorithm from the 'classInt' package available for
671  // the R statistical prgramming language, and from Python code from here:
672  // http://danieljlewis.org/2010/06/07/jenks-natural-breaks-algorithm-in-python/
673  // and is based on a JAVA and Fortran code available here:
674  // https://stat.ethz.ch/pipermail/r-sig-geo/2006-March/000811.html
675 
676  // Returns class breaks such that classes are internally homogeneous while
677  // assuring heterogeneity among classes.
678 
679  if ( !values.count() )
680  return QList<double>();
681 
682  if ( classes <= 1 )
683  {
684  return QList<double>() << maximum;
685  }
686 
687  if ( classes >= values.size() )
688  {
689  return values;
690  }
691 
692  QVector<double> sample;
693 
694  // if we have lots of values, we need to take a random sample
695  if ( values.size() > maximumSize )
696  {
697  // for now, sample at least maximumSize values or a 10% sample, whichever
698  // is larger. This will produce a more representative sample for very large
699  // layers, but could end up being computationally intensive...
700 
701  sample.resize( qMax( maximumSize, values.size() / 10 ) );
702 
703  QgsDebugMsg( QString( "natural breaks (jenks) sample size: %1" ).arg( sample.size() ) );
704  QgsDebugMsg( QString( "values:%1" ).arg( values.size() ) );
705 
706  sample[ 0 ] = minimum;
707  sample[ 1 ] = maximum;;
708  for ( int i = 2; i < sample.size(); i++ )
709  {
710  // pick a random integer from 0 to n
711  double r = qrand();
712  int j = floor( r / RAND_MAX * ( values.size() - 1 ) );
713  sample[ i ] = values[ j ];
714  }
715  }
716  else
717  {
718  sample = values.toVector();
719  }
720 
721  int n = sample.size();
722 
723  // sort the sample values
724  qSort( sample );
725 
726  QVector< QVector<int> > matrixOne( n + 1 );
727  QVector< QVector<double> > matrixTwo( n + 1 );
728 
729  for ( int i = 0; i <= n; i++ )
730  {
731  matrixOne[i].resize( classes + 1 );
732  matrixTwo[i].resize( classes + 1 );
733  }
734 
735  for ( int i = 1; i <= classes; i++ )
736  {
737  matrixOne[0][i] = 1;
738  matrixOne[1][i] = 1;
739  matrixTwo[0][i] = 0.0;
740  for ( int j = 2; j <= n; j++ )
741  {
742  matrixTwo[j][i] = std::numeric_limits<double>::max();
743  }
744  }
745 
746  for ( int l = 2; l <= n; l++ )
747  {
748  double s1 = 0.0;
749  double s2 = 0.0;
750  int w = 0;
751 
752  double v = 0.0;
753 
754  for ( int m = 1; m <= l; m++ )
755  {
756  int i3 = l - m + 1;
757 
758  double val = sample[ i3 - 1 ];
759 
760  s2 += val * val;
761  s1 += val;
762  w++;
763 
764  v = s2 - ( s1 * s1 ) / ( double ) w;
765  int i4 = i3 - 1;
766  if ( i4 != 0 )
767  {
768  for ( int j = 2; j <= classes; j++ )
769  {
770  if ( matrixTwo[l][j] >= v + matrixTwo[i4][j - 1] )
771  {
772  matrixOne[l][j] = i4;
773  matrixTwo[l][j] = v + matrixTwo[i4][j - 1];
774  }
775  }
776  }
777  }
778  matrixOne[l][1] = 1;
779  matrixTwo[l][1] = v;
780  }
781 
782  QVector<double> breaks( classes );
783  breaks[classes-1] = sample[n-1];
784 
785  for ( int j = classes, k = n; j >= 2; j-- )
786  {
787  int id = matrixOne[k][j] - 1;
788  breaks[j - 2] = sample[id];
789  k = matrixOne[k][j] - 1;
790  }
791 
792  return breaks.toList();
793 } //_calcJenksBreaks
794 
795 
797  QgsVectorLayer* vlayer,
798  QString attrName,
799  int classes,
800  Mode mode,
801  QgsSymbolV2* symbol,
802  QgsVectorColorRampV2* ramp,
803  bool inverted,
805 )
806 {
808  QgsGraduatedSymbolRendererV2* r = new QgsGraduatedSymbolRendererV2( attrName, ranges );
809  r->setSourceSymbol( symbol->clone() );
810  r->setSourceColorRamp( ramp->clone() );
811  r->setInvertedColorRamp( inverted );
812  r->setMode( mode );
813  r->setLabelFormat( labelFormat );
814  r->updateClasses( vlayer, mode, classes );
815  return r;
816 }
817 
819 {
820  bool ok;
821  return vlayer->getDoubleValues( mAttrName, ok );
822 }
823 
825 {
826  if ( mAttrName.isEmpty() )
827  return;
828 
829  setMode( mode );
830  // Custom classes are not recalculated
831  if ( mode == Custom )
832  return;
833 
834  if ( nclasses < 1 )
835  nclasses = 1;
836 
837  QList<double> values;
838  bool valuesLoaded = false;
839  double minimum;
840  double maximum;
841 
842  int attrNum = vlayer->fieldNameIndex( mAttrName );
843 
844  bool ok;
845  if ( attrNum == -1 )
846  {
847  values = vlayer->getDoubleValues( mAttrName, ok );
848  if ( !ok || values.isEmpty() )
849  return;
850 
851  qSort( values ); // vmora: is wondering if O( n log(n) ) is really necessary here, min and max are O( n )
852  minimum = values.first();
853  maximum = values.last();
854  valuesLoaded = true;
855  }
856  else
857  {
858  minimum = vlayer->minimumValue( attrNum ).toDouble();
859  maximum = vlayer->maximumValue( attrNum ).toDouble();
860  }
861 
862  QgsDebugMsg( QString( "min %1 // max %2" ).arg( minimum ).arg( maximum ) );
863  QList<double> breaks;
864  QList<double> labels;
865  if ( mode == EqualInterval )
866  {
867  breaks = _calcEqualIntervalBreaks( minimum, maximum, nclasses );
868  }
869  else if ( mode == Pretty )
870  {
871  breaks = QgsSymbolLayerV2Utils::prettyBreaks( minimum, maximum, nclasses );
872  }
873  else if ( mode == Quantile || mode == Jenks || mode == StdDev )
874  {
875  // get values from layer
876  if ( !valuesLoaded )
877  {
878  values = vlayer->getDoubleValues( mAttrName, ok );
879  }
880 
881  // calculate the breaks
882  if ( mode == Quantile )
883  {
884  breaks = _calcQuantileBreaks( values, nclasses );
885  }
886  else if ( mode == Jenks )
887  {
888  breaks = _calcJenksBreaks( values, nclasses, minimum, maximum );
889  }
890  else if ( mode == StdDev )
891  {
892  breaks = _calcStdDevBreaks( values, nclasses, labels );
893  }
894  }
895  else
896  {
897  Q_ASSERT( false );
898  }
899 
900  double lower, upper = minimum;
901  QString label;
903 
904  // "breaks" list contains all values at class breaks plus maximum as last break
905 
906  int i = 0;
907  for ( QList<double>::iterator it = breaks.begin(); it != breaks.end(); ++it, ++i )
908  {
909  lower = upper; // upper border from last interval
910  upper = *it;
911 
912  // Label - either StdDev label or default label for a range
913  if ( mode == StdDev )
914  {
915  if ( i == 0 )
916  {
917  label = "< " + QString::number( labels[i], 'f', 2 ) + " Std Dev";
918  }
919  else if ( i == labels.count() - 1 )
920  {
921  label = ">= " + QString::number( labels[i-1], 'f', 2 ) + " Std Dev";
922  }
923  else
924  {
925  label = QString::number( labels[i-1], 'f', 2 ) + " Std Dev" + " - " + QString::number( labels[i], 'f', 2 ) + " Std Dev";
926  }
927  }
928  else
929  {
930  label = mLabelFormat.labelForRange( lower, upper );
931  }
932  QgsSymbolV2* newSymbol = mSourceSymbol ? mSourceSymbol->clone() : QgsSymbolV2::defaultSymbol( vlayer->geometryType() );
933  addClass( QgsRendererRangeV2( lower, upper, newSymbol, label ) );
934  }
936 }
937 
938 
940 {
941  QDomElement symbolsElem = element.firstChildElement( "symbols" );
942  if ( symbolsElem.isNull() )
943  return NULL;
944 
945  QDomElement rangesElem = element.firstChildElement( "ranges" );
946  if ( rangesElem.isNull() )
947  return NULL;
948 
949  QgsSymbolV2Map symbolMap = QgsSymbolLayerV2Utils::loadSymbols( symbolsElem );
951 
952  QDomElement rangeElem = rangesElem.firstChildElement();
953  while ( !rangeElem.isNull() )
954  {
955  if ( rangeElem.tagName() == "range" )
956  {
957  double lowerValue = rangeElem.attribute( "lower" ).toDouble();
958  double upperValue = rangeElem.attribute( "upper" ).toDouble();
959  QString symbolName = rangeElem.attribute( "symbol" );
960  QString label = rangeElem.attribute( "label" );
961  bool render = rangeElem.attribute( "render", "true" ) != "false";
962  if ( symbolMap.contains( symbolName ) )
963  {
964  QgsSymbolV2* symbol = symbolMap.take( symbolName );
965  ranges.append( QgsRendererRangeV2( lowerValue, upperValue, symbol, label, render ) );
966  }
967  }
968  rangeElem = rangeElem.nextSiblingElement();
969  }
970 
971  QString attrName = element.attribute( "attr" );
972 
973  QgsGraduatedSymbolRendererV2* r = new QgsGraduatedSymbolRendererV2( attrName, ranges );
974 
975  QString attrMethod = element.attribute( "graduatedMethod" );
976  if ( attrMethod.length() )
977  {
978  if ( attrMethod == graduatedMethodStr( GraduatedColor ) )
980  else if ( attrMethod == graduatedMethodStr( GraduatedSize ) )
982  }
983 
984 
985  // delete symbols if there are any more
987 
988  // try to load source symbol (optional)
989  QDomElement sourceSymbolElem = element.firstChildElement( "source-symbol" );
990  if ( !sourceSymbolElem.isNull() )
991  {
992  QgsSymbolV2Map sourceSymbolMap = QgsSymbolLayerV2Utils::loadSymbols( sourceSymbolElem );
993  if ( sourceSymbolMap.contains( "0" ) )
994  {
995  r->setSourceSymbol( sourceSymbolMap.take( "0" ) );
996  }
997  QgsSymbolLayerV2Utils::clearSymbolMap( sourceSymbolMap );
998  }
999 
1000  // try to load color ramp (optional)
1001  QDomElement sourceColorRampElem = element.firstChildElement( "colorramp" );
1002  if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( "name" ) == "[source]" )
1003  {
1004  r->setSourceColorRamp( QgsSymbolLayerV2Utils::loadColorRamp( sourceColorRampElem ) );
1005  QDomElement invertedColorRampElem = element.firstChildElement( "invertedcolorramp" );
1006  if ( !invertedColorRampElem.isNull() )
1007  r->setInvertedColorRamp( invertedColorRampElem.attribute( "value" ) == "1" );
1008  }
1009 
1010  // try to load mode
1011  QDomElement modeElem = element.firstChildElement( "mode" );
1012  if ( !modeElem.isNull() )
1013  {
1014  QString modeString = modeElem.attribute( "name" );
1015  if ( modeString == "equal" )
1016  r->setMode( EqualInterval );
1017  else if ( modeString == "quantile" )
1018  r->setMode( Quantile );
1019  else if ( modeString == "jenks" )
1020  r->setMode( Jenks );
1021  else if ( modeString == "stddev" )
1022  r->setMode( StdDev );
1023  else if ( modeString == "pretty" )
1024  r->setMode( Pretty );
1025  }
1026 
1027  QDomElement rotationElem = element.firstChildElement( "rotation" );
1028  if ( !rotationElem.isNull() )
1029  r->setRotationField( rotationElem.attribute( "field" ) );
1030 
1031  QDomElement sizeScaleElem = element.firstChildElement( "sizescale" );
1032  if ( !sizeScaleElem.isNull() )
1033  r->setSizeScaleField( sizeScaleElem.attribute( "field" ) );
1034  r->setScaleMethod( QgsSymbolLayerV2Utils::decodeScaleMethod( sizeScaleElem.attribute( "scalemethod" ) ) );
1035 
1036  QDomElement labelFormatElem = element.firstChildElement( "labelformat" );
1037  if ( ! labelFormatElem.isNull() )
1038  {
1040  labelFormat.setFromDomElement( labelFormatElem );
1041  r->setLabelFormat( labelFormat );
1042  }
1043  // TODO: symbol levels
1044  return r;
1045 }
1046 
1047 QDomElement QgsGraduatedSymbolRendererV2::save( QDomDocument& doc )
1048 {
1049  QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
1050  rendererElem.setAttribute( "type", "graduatedSymbol" );
1051  rendererElem.setAttribute( "symbollevels", ( mUsingSymbolLevels ? "1" : "0" ) );
1052  rendererElem.setAttribute( "attr", mAttrName );
1053  rendererElem.setAttribute( "graduatedMethod", graduatedMethodStr( mGraduatedMethod ) );
1054 
1055  // ranges
1056  int i = 0;
1058  QDomElement rangesElem = doc.createElement( "ranges" );
1059  QgsRangeList::const_iterator it = mRanges.constBegin();
1060  for ( ; it != mRanges.constEnd(); ++it )
1061  {
1062  const QgsRendererRangeV2& range = *it;
1063  QString symbolName = QString::number( i );
1064  symbols.insert( symbolName, range.symbol() );
1065 
1066  QDomElement rangeElem = doc.createElement( "range" );
1067  rangeElem.setAttribute( "lower", QString::number( range.lowerValue(), 'f' ) );
1068  rangeElem.setAttribute( "upper", QString::number( range.upperValue(), 'f' ) );
1069  rangeElem.setAttribute( "symbol", symbolName );
1070  rangeElem.setAttribute( "label", range.label() );
1071  rangeElem.setAttribute( "render", range.renderState() ? "true" : "false" );
1072  rangesElem.appendChild( rangeElem );
1073  i++;
1074  }
1075 
1076  rendererElem.appendChild( rangesElem );
1077 
1078  // save symbols
1079  QDomElement symbolsElem = QgsSymbolLayerV2Utils::saveSymbols( symbols, "symbols", doc );
1080  rendererElem.appendChild( symbolsElem );
1081 
1082  // save source symbol
1083  if ( mSourceSymbol.data() )
1084  {
1085  QgsSymbolV2Map sourceSymbols;
1086  sourceSymbols.insert( "0", mSourceSymbol.data() );
1087  QDomElement sourceSymbolElem = QgsSymbolLayerV2Utils::saveSymbols( sourceSymbols, "source-symbol", doc );
1088  rendererElem.appendChild( sourceSymbolElem );
1089  }
1090 
1091  // save source color ramp
1092  if ( mSourceColorRamp.data() )
1093  {
1094  QDomElement colorRampElem = QgsSymbolLayerV2Utils::saveColorRamp( "[source]", mSourceColorRamp.data(), doc );
1095  rendererElem.appendChild( colorRampElem );
1096  QDomElement invertedElem = doc.createElement( "invertedcolorramp" );
1097  invertedElem.setAttribute( "value", mInvertedColorRamp );
1098  rendererElem.appendChild( invertedElem );
1099  }
1100 
1101  // save mode
1102  QString modeString;
1103  if ( mMode == EqualInterval )
1104  modeString = "equal";
1105  else if ( mMode == Quantile )
1106  modeString = "quantile";
1107  else if ( mMode == Jenks )
1108  modeString = "jenks";
1109  else if ( mMode == StdDev )
1110  modeString = "stddev";
1111  else if ( mMode == Pretty )
1112  modeString = "pretty";
1113  if ( !modeString.isEmpty() )
1114  {
1115  QDomElement modeElem = doc.createElement( "mode" );
1116  modeElem.setAttribute( "name", modeString );
1117  rendererElem.appendChild( modeElem );
1118  }
1119 
1120  QDomElement rotationElem = doc.createElement( "rotation" );
1121  if ( mRotation.data() )
1122  rotationElem.setAttribute( "field", QgsSymbolLayerV2Utils::fieldOrExpressionFromExpression( mRotation.data() ) );
1123  rendererElem.appendChild( rotationElem );
1124 
1125  QDomElement sizeScaleElem = doc.createElement( "sizescale" );
1126  if ( mSizeScale.data() )
1127  sizeScaleElem.setAttribute( "field", QgsSymbolLayerV2Utils::fieldOrExpressionFromExpression( mSizeScale.data() ) );
1128  sizeScaleElem.setAttribute( "scalemethod", QgsSymbolLayerV2Utils::encodeScaleMethod( mScaleMethod ) );
1129  rendererElem.appendChild( sizeScaleElem );
1130 
1131  QDomElement labelFormatElem = doc.createElement( "labelformat" );
1132  mLabelFormat.saveToDomElement( labelFormatElem );
1133  rendererElem.appendChild( labelFormatElem );
1134 
1135  if ( mPaintEffect )
1136  mPaintEffect->saveProperties( doc, rendererElem );
1137 
1138  return rendererElem;
1139 }
1140 
1142 {
1144  int count = ranges().count();
1145  for ( int i = 0; i < count; i++ )
1146  {
1147  const QgsRendererRangeV2& range = ranges()[i];
1148  QPixmap pix = QgsSymbolLayerV2Utils::symbolPreviewPixmap( range.symbol(), iconSize );
1149  lst << qMakePair( range.label(), pix );
1150  }
1151  return lst;
1152 }
1153 
1155 {
1156  Q_UNUSED( scaleDenominator );
1157  QgsLegendSymbolList lst;
1158 
1159  foreach ( const QgsRendererRangeV2& range, mRanges )
1160  {
1161  if ( rule.isEmpty() || range.label() == rule )
1162  {
1163  lst << qMakePair( range.label(), range.symbol() );
1164  }
1165  }
1166  return lst;
1167 }
1168 
1170 {
1171  return mSourceSymbol.data();
1172 }
1174 {
1175  mSourceSymbol.reset( sym );
1176 }
1177 
1179 {
1180  return mSourceColorRamp.data();
1181 }
1182 
1184 {
1185  mSourceColorRamp.reset( ramp );
1186 }
1187 
1189 {
1190  double min = DBL_MAX;
1191  for ( int i = 0; i < mRanges.count(); i++ )
1192  {
1193  double sz = 0;
1194  if ( mRanges[i].symbol()->type() == QgsSymbolV2::Marker )
1195  sz = static_cast< QgsMarkerSymbolV2 * >( mRanges[i].symbol() )->size();
1196  else if ( mRanges[i].symbol()->type() == QgsSymbolV2::Line )
1197  sz = static_cast< QgsLineSymbolV2 * >( mRanges[i].symbol() )->width();
1198  min = qMin( sz, min );
1199  }
1200  return min;
1201 }
1202 
1204 {
1205  double max = DBL_MIN;
1206  for ( int i = 0; i < mRanges.count(); i++ )
1207  {
1208  double sz = 0;
1209  if ( mRanges[i].symbol()->type() == QgsSymbolV2::Marker )
1210  sz = static_cast< QgsMarkerSymbolV2 * >( mRanges[i].symbol() )->size();
1211  else if ( mRanges[i].symbol()->type() == QgsSymbolV2::Line )
1212  sz = static_cast< QgsLineSymbolV2 * >( mRanges[i].symbol() )->width();
1213  max = qMax( sz, max );
1214  }
1215  return max;
1216 }
1217 
1218 void QgsGraduatedSymbolRendererV2::setSymbolSizes( double minSize, double maxSize )
1219 {
1220  for ( int i = 0; i < mRanges.count(); i++ )
1221  {
1222  QScopedPointer<QgsSymbolV2> symbol( mRanges[i].symbol() ? mRanges[i].symbol()->clone() : 0 );
1223  const double size = mRanges.count() > 1
1224  ? minSize + i * ( maxSize - minSize ) / ( mRanges.count() - 1 )
1225  : .5 * ( maxSize + minSize );
1226  if ( symbol->type() == QgsSymbolV2::Marker )
1227  static_cast< QgsMarkerSymbolV2 * >( symbol.data() )->setSize( size );
1228  if ( symbol->type() == QgsSymbolV2::Line )
1229  static_cast< QgsLineSymbolV2 * >( symbol.data() )->setWidth( size );
1230  updateRangeSymbol( i, symbol.take() );
1231  }
1232 }
1233 
1235 {
1236  int i = 0;
1237  if ( ramp )
1238  {
1239  setSourceColorRamp( ramp );
1240  setInvertedColorRamp( inverted );
1241  }
1242 
1243  if ( mSourceColorRamp )
1244  {
1245  foreach ( QgsRendererRangeV2 range, mRanges )
1246  {
1247  QgsSymbolV2 *symbol = range.symbol() ? range.symbol()->clone() : 0;
1248  if ( symbol )
1249  {
1250  double colorValue;
1251  if ( inverted )
1252  colorValue = ( mRanges.count() > 1 ? ( double )( mRanges.count() - i - 1 ) / ( mRanges.count() - 1 ) : 0 );
1253  else
1254  colorValue = ( mRanges.count() > 1 ? ( double ) i / ( mRanges.count() - 1 ) : 0 );
1255  symbol->setColor( mSourceColorRamp->color( colorValue ) );
1256  }
1257  updateRangeSymbol( i, symbol );
1258  ++i;
1259  }
1260  }
1261 
1262 }
1263 
1265 {
1266  if ( !sym )
1267  return;
1268 
1269  int i = 0;
1270  foreach ( QgsRendererRangeV2 range, mRanges )
1271  {
1272  QScopedPointer<QgsSymbolV2> symbol( sym->clone() );
1274  {
1275  symbol->setColor( range.symbol()->color() );
1276  }
1277  else if ( mGraduatedMethod == GraduatedSize )
1278  {
1279  if ( symbol->type() == QgsSymbolV2::Marker )
1280  static_cast<QgsMarkerSymbolV2 *>( symbol.data() )->setSize(
1281  static_cast<QgsMarkerSymbolV2 *>( range.symbol() )->size() );
1282  else if ( symbol->type() == QgsSymbolV2::Line )
1283  static_cast<QgsLineSymbolV2 *>( symbol.data() )->setWidth(
1284  static_cast<QgsLineSymbolV2 *>( range.symbol() )->width() );
1285  }
1286  updateRangeSymbol( i, symbol.take() );
1287  ++i;
1288  }
1289  setSourceSymbol( sym->clone() );
1290 }
1291 
1292 void QgsGraduatedSymbolRendererV2::setRotationField( QString fieldOrExpression )
1293 {
1295 }
1296 
1298 {
1299  return mRotation.data() ? QgsSymbolLayerV2Utils::fieldOrExpressionFromExpression( mRotation.data() ) : QString();
1300 }
1301 
1302 void QgsGraduatedSymbolRendererV2::setSizeScaleField( QString fieldOrExpression )
1303 {
1305 }
1306 
1308 {
1310 }
1311 
1313 {
1315  for ( QgsRangeList::iterator it = mRanges.begin(); it != mRanges.end(); ++it )
1316  {
1317  if ( it->symbol() )
1318  setScaleMethodToSymbol( it->symbol(), scaleMethod );
1319  }
1320 }
1321 
1323 {
1324  return true;
1325 }
1326 
1328 {
1329  bool ok;
1330  int index = key.toInt( &ok );
1331  if ( ok && index >= 0 && index < mRanges.size() )
1332  return mRanges[ index ].renderState();
1333  else
1334  return true;
1335 }
1336 
1338 {
1339  bool ok;
1340  int index = key.toInt( &ok );
1341  if ( ok )
1342  updateRangeRenderState( index, state );
1343 }
1344 
1345 
1347 {
1348  QgsSymbolV2* newSymbol = symbol->clone();
1349  QString label = "0.0 - 0.0";
1350  mRanges.insert( 0, QgsRendererRangeV2( 0.0, 0.0, newSymbol, label ) );
1351 }
1352 
1353 void QgsGraduatedSymbolRendererV2::addClass( double lower, double upper )
1354 {
1355  QgsSymbolV2* newSymbol = mSourceSymbol->clone();
1356  QString label = mLabelFormat.labelForRange( lower, upper );
1357  mRanges.append( QgsRendererRangeV2( lower, upper, newSymbol, label ) );
1358 }
1359 
1361 {
1362  mRanges.append( range );
1363 }
1364 
1366 {
1367  mRanges.removeAt( idx );
1368 }
1369 
1371 {
1372  mRanges.clear();
1373 }
1374 
1376 {
1377  if ( updateRanges && labelFormat != mLabelFormat )
1378  {
1379  for ( QgsRangeList::iterator it = mRanges.begin(); it != mRanges.end(); ++it )
1380  {
1381  it->setLabel( labelFormat.labelForRange( *it ) );
1382  }
1383  }
1385 }
1386 
1387 
1389 {
1390  // Find the minimum size of a class
1391  double minClassRange = 0.0;
1392  for ( QgsRangeList::iterator it = mRanges.begin(); it != mRanges.end(); ++it )
1393  {
1394  double range = it->upperValue() - it->lowerValue();
1395  if ( range <= 0.0 )
1396  continue;
1397  if ( minClassRange == 0.0 || range < minClassRange )
1398  minClassRange = range;
1399  }
1400  if ( minClassRange <= 0.0 )
1401  return;
1402 
1403  // Now set the number of decimal places to ensure no more than 20% error in
1404  // representing this range (up to 10% at upper and lower end)
1405 
1406  int ndp = 10;
1407  double nextDpMinRange = 0.0000000099;
1408  while ( ndp > 0 && nextDpMinRange < minClassRange )
1409  {
1410  ndp--;
1411  nextDpMinRange *= 10.0;
1412  }
1413  mLabelFormat.setPrecision( ndp );
1414  if ( updateRanges ) setLabelFormat( mLabelFormat, true );
1415 }
1416 
1418 {
1419  if ( from < 0 || from >= mRanges.size() || to < 0 || to >= mRanges.size() )
1420  return;
1421  mRanges.move( from, to );
1422 }
1423 
1425 {
1426  return r1 < r2;
1427 }
1428 
1430 {
1431  return !valueLessThan( r1, r2 );
1432 }
1433 
1435 {
1436  QgsDebugMsg( "Entered" );
1437  if ( order == Qt::AscendingOrder )
1438  {
1439  qSort( mRanges.begin(), mRanges.end(), valueLessThan );
1440  }
1441  else
1442  {
1443  qSort( mRanges.begin(), mRanges.end(), valueGreaterThan );
1444  }
1445 }
1446 
1448 {
1449  return QString::localeAwareCompare( r1.label(), r2.label() ) < 0;
1450 }
1451 
1453 {
1454  return !labelLessThan( r1, r2 );
1455 }
1456 
1458 {
1459  if ( order == Qt::AscendingOrder )
1460  {
1461  qSort( mRanges.begin(), mRanges.end(), labelLessThan );
1462  }
1463  else
1464  {
1465  qSort( mRanges.begin(), mRanges.end(), labelGreaterThan );
1466  }
1467 }
1468 
1470 {
1471  if ( renderer->type() == "graduatedSymbol" )
1472  {
1473  return dynamic_cast<QgsGraduatedSymbolRendererV2*>( renderer->clone() );
1474  }
1475  if ( renderer->type() == "pointDisplacement" )
1476  {
1477  const QgsPointDisplacementRenderer* pointDisplacementRenderer = dynamic_cast<const QgsPointDisplacementRenderer*>( renderer );
1478  if ( pointDisplacementRenderer )
1479  return convertFromRenderer( pointDisplacementRenderer->embeddedRenderer() );
1480  }
1481  if ( renderer->type() == "invertedPolygonRenderer" )
1482  {
1483  const QgsInvertedPolygonRenderer* invertedPolygonRenderer = dynamic_cast<const QgsInvertedPolygonRenderer*>( renderer );
1484  if ( invertedPolygonRenderer )
1485  return convertFromRenderer( invertedPolygonRenderer->embeddedRenderer() );
1486  }
1487 
1488  // If not one of the specifically handled renderers, then just grab the symbol from the renderer
1489  // Could have applied this to specific renderer types (singleSymbol, graduatedSymbo)
1490 
1492  QgsSymbolV2List symbols = const_cast<QgsFeatureRendererV2 *>( renderer )->symbols();
1493  if ( symbols.size() > 0 )
1494  {
1495  r->setSourceSymbol( symbols.at( 0 )->clone() );
1496  }
1497 
1498  return r;
1499 }
1500 
1502 {
1503  switch ( method )
1504  {
1505  case GraduatedColor: return "GraduatedColor";
1506  case GraduatedSize: return "GraduatedSize";
1507  }
1508  return "";
1509 }
1510 
1511 
QMap< QString, QgsSymbolV2 * > QgsSymbolV2Map
Definition: qgsrendererv2.h:40
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:86
QList< QgsRendererRangeV2 > QgsRangeList
static QgsSymbolV2Map loadSymbols(QDomElement &element)
static QList< double > _calcJenksBreaks(QList< double > values, int classes, double minimum, double maximum, int maximumSize=1000)
#define RENDERER_TAG_NAME
Definition: qgsrendererv2.h:48
static unsigned index
virtual void toSld(QDomDocument &doc, QDomElement &element) const override
used from subclasses to create SLD Rule elements following SLD v1.1 specs
void setLowerValue(double lowerValue)
void setSymbolSizes(double minSize, double maxSize)
set varying symbol size for classes
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
Definition: qgsexpression.h:93
QStringList referencedColumns() const
Get list of columns referenced by the expression.
void setRotationField(QString fieldOrExpression) override
sets rotation field of renderer (if supported by the renderer)
void setLabelFormat(const QgsRendererRangeV2LabelFormat &labelFormat, bool updateRanges=false)
Set the label format used to generate default classification labels.
static QList< double > prettyBreaks(double minimum, double maximum, int classes)
Computes a sequence of about 'classes' equally spaced round values which cover the range of values fr...
bool labelLessThan(const QgsRendererRangeV2 &r1, const QgsRendererRangeV2 &r2)
static QgsGraduatedSymbolRendererV2 * convertFromRenderer(const QgsFeatureRendererV2 *renderer)
creates a QgsGraduatedSymbolRendererV2 from an existing renderer.
static QgsVectorColorRampV2 * loadColorRamp(QDomElement &element)
void updateClasses(QgsVectorLayer *vlayer, Mode mode, int nclasses)
Recalculate classes for a layer.
bool updateRangeLabel(int rangeIndex, QString label)
QList< QgsSymbolV2 * > QgsSymbolV2List
Definition: qgsrendererv2.h:39
static QList< double > _calcStdDevBreaks(QList< double > values, int classes, QList< double > &labels)
virtual QString dump() const override
for debugging
SymbolType type() const
Definition: qgssymbolv2.h:85
QScopedPointer< QgsVectorColorRampV2 > mSourceColorRamp
QVariant maximumValue(int index)
Returns maximum value for an attribute column or invalid variant in case of error.
QSet< QString > usedAttributes() const
void updateSymbols(QgsSymbolV2 *sym)
Update all the symbols but leave breaks and colors.
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
QString formatNumber(double value) const
int fieldNameIndex(const QString &fieldName) const
Look up field's index from name - case insensitive TODO: sort out case sensitive (indexFromName()) vs...
Definition: qgsfield.cpp:325
double rendererScale() const
virtual QgsSymbolV2 * clone() const =0
virtual QgsFeatureRendererV2 * clone() const override
bool updateRangeRenderState(int rangeIndex, bool render)
QString labelForRange(double lower, double upper) const
void setSizeScaleField(QString fieldOrExpression)
double minSymbolSize() const
return the min symbol size when graduated by size
Container of fields for a vector layer.
Definition: qgsfield.h:167
virtual QgsSymbolV2 * originalSymbolForFeature(QgsFeature &feature) override
Return symbol for feature.
QHash< QgsSymbolV2 *, QgsSymbolV2 * > mTempSymbols
temporary symbols, used for data-defined rotation and scaling
void calculateLabelPrecision(bool updateRanges=true)
Reset the label decimal places to a numberbased on the minimum class interval.
virtual QgsLegendSymbolList legendSymbolItems(double scaleDenominator=-1, QString rule=QString()) override
return a list of item text / symbol
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:113
void setScaleMethod(QgsSymbolV2::ScaleMethod scaleMethod)
virtual QgsSymbolV2 * symbolForFeature(QgsFeature &feature) override
to be overridden
QVariant minimumValue(int index)
Returns minimum value for an attribute column or invalid variant in case of error.
QMap< QString, QString > QgsStringMap
Definition: qgis.h:438
virtual bool legendSymbolItemChecked(QString key) override
item in symbology was checked
static const char * graduatedMethodStr(GraduatedMethod method)
QgsPaintEffect * mPaintEffect
void setWidth(double width)
QList< double > getDoubleValues(const QString &fieldOrExpression, bool &ok)
Fetches all double values from a specified field name or expression.
Q_DECL_DEPRECATED QList< double > getDataValues(QgsVectorLayer *vlayer)
Evaluates the data expression and returns the list of values from the layer.
QScopedPointer< QgsSymbolV2 > mSymbol
QString type() const
Definition: qgsrendererv2.h:82
virtual void stopRender(QgsRenderContext &context) override
virtual QgsSymbolV2List symbols() override
for symbol levels
QScopedPointer< QgsExpression > mExpression
void setColor(const QColor &color)
virtual QgsFeatureRendererV2 * clone() const =0
void setGraduatedMethod(GraduatedMethod method)
set the method used for graduation (either size or color)
static QDomElement saveColorRamp(QString name, QgsVectorColorRampV2 *ramp, QDomDocument &doc)
QgsSymbolV2::ScaleMethod scaleMethod() const
void sortByLabel(Qt::SortOrder order=Qt::AscendingOrder)
static QList< double > _calcQuantileBreaks(QList< double > values, int classes)
QgsInvertedPolygonRenderer is a polygon-only feature renderer used to display features inverted...
void startRender(QgsRenderContext &context, const QgsFields *fields=0)
bool operator==(const QgsRendererRangeV2LabelFormat &other) const
#define DEFAULT_SCALE_METHOD
virtual QgsVectorColorRampV2 * clone() const =0
void swap(QgsRendererRangeV2 &other)
static bool createFunctionElement(QDomDocument &doc, QDomElement &element, QString function)
static QDomElement saveSymbols(QgsSymbolV2Map &symbols, QString tagName, QDomDocument &doc)
QString rotationField() const override
return rotation field name (or empty string if not set or not supported by renderer) ...
QgsSymbolV2 * symbol() const
GraduatedMethod graduatedMethod() const
return the method used for graduation (either size or color)
void setAngle(double angle)
bool updateRangeLowerValue(int rangeIndex, double value)
const QgsAttributes & attributes() const
Definition: qgsfeature.h:142
void setSize(double size)
void toSld(QDomDocument &doc, QDomElement &element, QgsStringMap props) const
QgsRendererRangeV2LabelFormat mLabelFormat
QGis::GeometryType geometryType() const
Returns point, line or polygon.
QgsGraduatedSymbolRendererV2(QString attrName=QString(), QgsRangeList ranges=QgsRangeList())
void setUpperValue(double upperValue)
virtual QDomElement save(QDomDocument &doc) override
store renderer info to XML element
bool operator<(const QgsRendererRangeV2 &other) const
void setFromDomElement(QDomElement &element)
QgsSymbolV2 * symbolForValue(double value)
bool labelGreaterThan(const QgsRendererRangeV2 &r1, const QgsRendererRangeV2 &r2)
QList< QPair< QString, QPixmap > > QgsLegendSymbologyList
QgsFeatureRendererV2 * embeddedRenderer() const
bool valueLessThan(const QgsRendererRangeV2 &r1, const QgsRendererRangeV2 &r2)
int min(int a, int b)
Definition: util.h:93
static QgsGraduatedSymbolRendererV2 * createRenderer(QgsVectorLayer *vlayer, QString attrName, int classes, Mode mode, QgsSymbolV2 *symbol, QgsVectorColorRampV2 *ramp, bool inverted=false, QgsRendererRangeV2LabelFormat legendFormat=QgsRendererRangeV2LabelFormat())
const QgsRendererRangeV2LabelFormat & labelFormat() const
Return the label format used to generate default classification labels.
void sortByValue(Qt::SortOrder order=Qt::AscendingOrder)
A renderer that automatically displaces points with the same position.
virtual bool legendSymbolItemsCheckable() const override
items of symbology items in legend should be checkable
void setUsingSymbolLevels(bool usingSymbolLevels)
static QList< double > _calcEqualIntervalBreaks(double minimum, double maximum, int classes)
virtual bool saveProperties(QDomDocument &doc, QDomElement &element) const
Saves the current state of the effect to a DOM element.
int ANALYSIS_EXPORT lower(int n, int i)
lower function
void moveClass(int from, int to)
Moves the category at index position from to index position to.
Contains information about the context of a rendering operation.
const QgsFeatureRendererV2 * embeddedRenderer() const
int mAttrNum
attribute index (derived from attribute name in startRender)
void copyPaintEffect(QgsFeatureRendererV2 *destRenderer) const
Copies paint effect of this renderer to another renderer.
static QgsSymbolV2 * defaultSymbol(QGis::GeometryType geomType)
return new default symbol for specified geometry type
static QgsExpression * fieldOrExpressionToExpression(const QString &fieldOrExpression)
Return a new valid expression instance for given field or expression string.
QVector< QVariant > QgsAttributes
Definition: qgsfeature.h:100
double maxSymbolSize() const
return the max symbol size when graduated by size
const QgsRangeList & ranges() const
bool operator!=(const QgsRendererRangeV2LabelFormat &other) const
static QString encodeScaleMethod(QgsSymbolV2::ScaleMethod scaleMethod)
static QString fieldOrExpressionFromExpression(QgsExpression *expression)
Return a field name if the whole expression is just a name of the field .
bool usingSymbolLevels() const
void setScaleMethodToSymbol(QgsSymbolV2 *symbol, int scaleMethod)
bool updateRangeSymbol(int rangeIndex, QgsSymbolV2 *symbol)
void setSourceColorRamp(QgsVectorColorRampV2 *ramp)
QScopedPointer< QgsSymbolV2 > mSourceSymbol
void setRenderHints(int hints)
Definition: qgssymbolv2.h:161
static void clearSymbolMap(QgsSymbolV2Map &symbols)
void setTrimTrailingZeroes(bool trimTrailingZeroes)
bool updateRangeUpperValue(int rangeIndex, double value)
static QgsSymbolV2::ScaleMethod decodeScaleMethod(QString str)
QScopedPointer< QgsExpression > mRotation
static QgsFeatureRendererV2 * create(QDomElement &element)
create renderer from XML element
virtual QgsLegendSymbologyList legendSymbologyItems(QSize iconSize) override
return a list of symbology items for the legend
virtual QList< QString > usedAttributes() override
QScopedPointer< QgsExpression > mSizeScale
QgsRendererRangeV2 & operator=(QgsRendererRangeV2 range)
static QPixmap symbolPreviewPixmap(QgsSymbolV2 *symbol, QSize size, QgsRenderContext *customContext=0)
Represents a vector layer which manages a vector based data sets.
int fieldNameIndex(const QString &fieldName) const
Returns the index of a field name or -1 if the field does not exist.
double size
Definition: qgssvgcache.cpp:77
QList< QPair< QString, QgsSymbolV2 * > > QgsLegendSymbolList
Definition: qgsrendererv2.h:43
int max(int a, int b)
Definition: util.h:87
virtual void checkLegendSymbolItem(QString key, bool state=true) override
item in symbology was checked
void setScaleMethod(QgsSymbolV2::ScaleMethod scaleMethod)
void updateColorRamp(QgsVectorColorRampV2 *ramp=0, bool inverted=false)
Update the color ramp used.
bool valueGreaterThan(const QgsRendererRangeV2 &r1, const QgsRendererRangeV2 &r2)
virtual void startRender(QgsRenderContext &context, const QgsFields &fields) override
QColor color() const