QGIS API Documentation  2.5.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgsgraduatedsymbolrendererv2.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsgraduatedsymbolrendererv2.cpp
3  ---------------------
4  begin : November 2009
5  copyright : (C) 2009 by Martin Dobias
6  email : wonder dot sk at gmail dot com
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  ***************************************************************************/
16 
17 #include "qgssymbolv2.h"
18 #include "qgssymbollayerv2utils.h"
19 #include "qgsvectorcolorrampv2.h"
20 
21 #include "qgsfeature.h"
22 #include "qgsvectorlayer.h"
23 #include "qgslogger.h"
24 #include "qgsvectordataprovider.h"
25 #include "qgsexpression.h"
26 #include <QDomDocument>
27 #include <QDomElement>
28 #include <QSettings> // for legend
29 #include <limits> // for jenks classification
30 #include <cmath> // for pretty classification
31 #include <ctime>
32 
34  : mLowerValue( 0 ), mUpperValue( 0 ), mSymbol( 0 ), mLabel()
35 {
36 }
37 
38 QgsRendererRangeV2::QgsRendererRangeV2( double lowerValue, double upperValue, QgsSymbolV2* symbol, QString label, bool render )
39  : mLowerValue( lowerValue )
40  , mUpperValue( upperValue )
41  , mSymbol( symbol )
42  , mLabel( label )
43  , mRender( render )
44 {
45 }
46 
48  : mLowerValue( range.mLowerValue )
49  , mUpperValue( range.mUpperValue )
50  , mSymbol( range.mSymbol.data() ? range.mSymbol->clone() : NULL )
51  , mLabel( range.mLabel )
52  , mRender( range.mRender )
53 {
54 }
55 
56 // cpy and swap idiom, note that the cpy is done with 'pass by value'
58 {
59  swap( range );
60  return *this;
61 }
62 
64 {
65  qSwap( mLowerValue, other.mLowerValue );
66  qSwap( mUpperValue, other.mUpperValue );
67  qSwap( mSymbol, other.mSymbol );
68  std::swap( mLabel, other.mLabel );
69 }
70 
72 {
73  return mLowerValue;
74 }
75 
77 {
78  return mUpperValue;
79 }
80 
82 {
83  return mSymbol.data();
84 }
85 
87 {
88  return mLabel;
89 }
90 
92 {
93  if ( mSymbol.data() != s ) mSymbol.reset( s );
94 }
95 
96 void QgsRendererRangeV2::setLabel( QString label )
97 {
98  mLabel = label;
99 }
100 
101 void QgsRendererRangeV2::setUpperValue( double upperValue )
102 {
104 }
105 
106 void QgsRendererRangeV2::setLowerValue( double lowerValue )
107 {
109 }
110 
112 {
113  return mRender;
114 }
115 
117 {
118  mRender = render;
119 }
120 
122 {
123  return QString( "%1 - %2::%3::%4\n" ).arg( mLowerValue ).arg( mUpperValue ).arg( mLabel ).arg( mSymbol->dump() );
124 }
125 
126 void QgsRendererRangeV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
127 {
128  if ( !mSymbol.data() || props.value( "attribute", "" ).isEmpty() )
129  return;
130 
131  QString attrName = props[ "attribute" ];
132 
133  QDomElement ruleElem = doc.createElement( "se:Rule" );
134  element.appendChild( ruleElem );
135 
136  QDomElement nameElem = doc.createElement( "se:Name" );
137  nameElem.appendChild( doc.createTextNode( mLabel ) );
138  ruleElem.appendChild( nameElem );
139 
140  QDomElement descrElem = doc.createElement( "se:Description" );
141  QDomElement titleElem = doc.createElement( "se:Title" );
142  QString descrStr = QString( "range: %1 - %2" ).arg( mLowerValue ).arg( mUpperValue );
143  titleElem.appendChild( doc.createTextNode( !mLabel.isEmpty() ? mLabel : descrStr ) );
144  descrElem.appendChild( titleElem );
145  ruleElem.appendChild( descrElem );
146 
147  // create the ogc:Filter for the range
148  QString filterFunc = QString( "%1 > %2 AND %1 <= %3" )
149  .arg( attrName.replace( "\"", "\"\"" ) )
150  .arg( mLowerValue ).arg( mUpperValue );
151  QgsSymbolLayerV2Utils::createFunctionElement( doc, ruleElem, filterFunc );
152 
153  mSymbol->toSld( doc, ruleElem, props );
154 }
155 
157 
159  : QgsFeatureRendererV2( "graduatedSymbol" ),
160  mAttrName( attrName ),
161  mRanges( ranges ),
162  mMode( Custom ),
163  mInvertedColorRamp( false ),
164  mScaleMethod( DEFAULT_SCALE_METHOD )
165 {
166  // TODO: check ranges for sanity (NULL symbols, invalid ranges)
167 }
168 
170 {
171  mRanges.clear(); // should delete all the symbols
172 }
173 
175 {
176  for ( QgsRangeList::iterator it = mRanges.begin(); it != mRanges.end(); ++it )
177  {
178  if ( it->lowerValue() <= value && it->upperValue() >= value )
179  {
180  if ( it->renderState() || mCounting )
181  return it->symbol();
182  else
183  return NULL;
184  }
185  }
186  // the value is out of the range: return NULL instead of symbol
187  return NULL;
188 }
189 
191 {
192  const QgsAttributes& attrs = feature.attributes();
193  QVariant value;
194  if ( mAttrNum < 0 || mAttrNum >= attrs.count() )
195  {
196  value = mExpression->evaluate( &feature );
197  }
198  else
199  {
200  value = attrs[mAttrNum];
201  }
202 
203  // Null values should not be categorized
204  if ( value.isNull() )
205  return NULL;
206 
207  // find the right category
208  QgsSymbolV2* symbol = symbolForValue( value.toDouble() );
209  if ( symbol == NULL )
210  return NULL;
211 
212  if ( !mRotation.data() && !mSizeScale.data() )
213  return symbol; // no data-defined rotation/scaling - just return the symbol
214 
215  // find out rotation, size scale
216  const double rotation = mRotation.data() ? mRotation->evaluate( feature ).toDouble() : 0;
217  const double sizeScale = mSizeScale.data() ? mSizeScale->evaluate( feature ).toDouble() : 1.;
218 
219  // take a temporary symbol (or create it if doesn't exist)
220  QgsSymbolV2* tempSymbol = mTempSymbols[symbol];
221 
222  // modify the temporary symbol and return it
223  if ( tempSymbol->type() == QgsSymbolV2::Marker )
224  {
225  QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( tempSymbol );
226  if ( mRotation.data() ) markerSymbol->setAngle( rotation );
227  markerSymbol->setSize( sizeScale * static_cast<QgsMarkerSymbolV2*>( symbol )->size() );
228  markerSymbol->setScaleMethod( mScaleMethod );
229  }
230  else if ( tempSymbol->type() == QgsSymbolV2::Line )
231  {
232  QgsLineSymbolV2* lineSymbol = static_cast<QgsLineSymbolV2*>( tempSymbol );
233  lineSymbol->setWidth( sizeScale * static_cast<QgsLineSymbolV2*>( symbol )->width() );
234  }
235  return tempSymbol;
236 }
237 
239 {
240  mCounting = context.rendererScale() == 0.0;
241 
242  // find out classification attribute index from name
243  mAttrNum = fields.fieldNameIndex( mAttrName );
244 
245  if ( mAttrNum == -1 )
246  {
247  mExpression.reset( new QgsExpression( mAttrName ) );
248  mExpression->prepare( fields );
249  }
250 
251  QgsRangeList::iterator it = mRanges.begin();
252  for ( ; it != mRanges.end(); ++it )
253  {
254  it->symbol()->startRender( context, &fields );
255 
256  if ( mRotation.data() || mSizeScale.data() )
257  {
258  QgsSymbolV2* tempSymbol = it->symbol()->clone();
259  tempSymbol->setRenderHints(( mRotation.data() ? QgsSymbolV2::DataDefinedRotation : 0 ) |
261  tempSymbol->startRender( context, &fields );
262  mTempSymbols[ it->symbol()] = tempSymbol;
263  }
264  }
265 }
266 
268 {
269  QgsRangeList::iterator it = mRanges.begin();
270  for ( ; it != mRanges.end(); ++it )
271  it->symbol()->stopRender( context );
272 
273  // cleanup mTempSymbols
274  QHash<QgsSymbolV2*, QgsSymbolV2*>::iterator it2 = mTempSymbols.begin();
275  for ( ; it2 != mTempSymbols.end(); ++it2 )
276  {
277  it2.value()->stopRender( context );
278  delete it2.value();
279  }
280  mTempSymbols.clear();
281 }
282 
284 {
285  QSet<QString> attributes;
286 
287  // mAttrName can contain either attribute name or an expression.
288  // Sometimes it is not possible to distinguish between those two,
289  // e.g. "a - b" can be both a valid attribute name or expression.
290  // Since we do not have access to fields here, try both options.
291  attributes << mAttrName;
292 
293  QgsExpression testExpr( mAttrName );
294  if ( !testExpr.hasParserError() )
295  attributes.unite( testExpr.referencedColumns().toSet() );
296 
297  if ( mRotation.data() ) attributes.unite( mRotation->referencedColumns().toSet() );
298  if ( mSizeScale.data() ) attributes.unite( mSizeScale->referencedColumns().toSet() );
299 
300  QgsRangeList::const_iterator range_it = mRanges.constBegin();
301  for ( ; range_it != mRanges.constEnd(); ++range_it )
302  {
303  QgsSymbolV2* symbol = range_it->symbol();
304  if ( symbol )
305  {
306  attributes.unite( symbol->usedAttributes() );
307  }
308  }
309  return attributes.toList();
310 }
311 
313 {
314  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
315  return false;
316  mRanges[rangeIndex].setSymbol( symbol );
317  return true;
318 }
319 
320 bool QgsGraduatedSymbolRendererV2::updateRangeLabel( int rangeIndex, QString label )
321 {
322  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
323  return false;
324  mRanges[rangeIndex].setLabel( label );
325  return true;
326 }
327 
328 bool QgsGraduatedSymbolRendererV2::updateRangeUpperValue( int rangeIndex, double value )
329 {
330  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
331  return false;
332  mRanges[rangeIndex].setUpperValue( value );
333  return true;
334 }
335 
336 bool QgsGraduatedSymbolRendererV2::updateRangeLowerValue( int rangeIndex, double value )
337 {
338  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
339  return false;
340  mRanges[rangeIndex].setLowerValue( value );
341  return true;
342 }
343 
345 {
346  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
347  return false;
348  mRanges[rangeIndex].setRenderState( value );
349  return true;
350 }
351 
353 {
354  QString s = QString( "GRADUATED: attr %1\n" ).arg( mAttrName );
355  for ( int i = 0; i < mRanges.count(); i++ )
356  s += mRanges[i].dump();
357  return s;
358 }
359 
361 {
363  r->setMode( mMode );
364  if ( mSourceSymbol.data() )
365  r->setSourceSymbol( mSourceSymbol->clone() );
366  if ( mSourceColorRamp.data() )
367  {
368  r->setSourceColorRamp( mSourceColorRamp->clone() );
370  }
374  r->setScaleMethod( scaleMethod() );
375  return r;
376 }
377 
378 void QgsGraduatedSymbolRendererV2::toSld( QDomDocument& doc, QDomElement &element ) const
379 {
380  QgsStringMap props;
381  props[ "attribute" ] = mAttrName;
382  if ( mRotation.data() )
383  props[ "angle" ] = mRotation->expression();
384  if ( mSizeScale.data() )
385  props[ "scale" ] = mSizeScale->expression();
386 
387  // create a Rule for each range
388  for ( QgsRangeList::const_iterator it = mRanges.constBegin(); it != mRanges.constEnd(); ++it )
389  {
390  QgsStringMap catProps( props );
391  it->toSld( doc, element, catProps );
392  }
393 }
394 
396 {
397  QgsSymbolV2List lst;
398  for ( int i = 0; i < mRanges.count(); i++ )
399  lst.append( mRanges[i].symbol() );
400  return lst;
401 }
402 
403 static QList<double> _calcEqualIntervalBreaks( double minimum, double maximum, int classes )
404 {
405 
406  // Equal interval algorithm
407  //
408  // Returns breaks based on dividing the range ('minimum' to 'maximum')
409  // into 'classes' parts.
410 
411  double step = ( maximum - minimum ) / classes;
412 
413  QList<double> breaks;
414  double value = minimum;
415  for ( int i = 0; i < classes; i++ )
416  {
417  value += step;
418  breaks.append( value );
419  }
420 
421  // floating point arithmetics is not precise:
422  // set the last break to be exactly maximum so we do not miss it
423  breaks[classes-1] = maximum;
424 
425  return breaks;
426 }
427 
428 static QList<double> _calcQuantileBreaks( QList<double> values, int classes )
429 {
430  // q-th quantile of a data set:
431  // value where q fraction of data is below and (1-q) fraction is above this value
432  // Xq = (1 - r) * X_NI1 + r * X_NI2
433  // NI1 = (int) (q * (n+1))
434  // NI2 = NI1 + 1
435  // r = q * (n+1) - (int) (q * (n+1))
436  // (indices of X: 1...n)
437 
438  // sort the values first
439  qSort( values );
440 
441  QList<double> breaks;
442 
443  // If there are no values to process: bail out
444  if ( !values.count() )
445  return breaks;
446 
447  int n = values.count();
448  double Xq = n > 0 ? values[0] : 0.0;
449 
450  for ( int i = 1; i < classes; i++ )
451  {
452  if ( n > 1 )
453  {
454  double q = i / ( double ) classes;
455  double a = q * ( n - 1 );
456  int aa = ( int )( a );
457 
458  double r = a - aa;
459  Xq = ( 1 - r ) * values[aa] + r * values[aa+1];
460  }
461  breaks.append( Xq );
462  }
463 
464  breaks.append( values[ n-1 ] );
465 
466  return breaks;
467 }
468 
469 static QList<double> _calcPrettyBreaks( double minimum, double maximum, int classes )
470 {
471 
472  // C++ implementation of R's pretty algorithm
473  // Based on code for determining optimal tick placement for statistical graphics
474  // from the R statistical programming language.
475  // Code ported from R implementation from 'labeling' R package
476  //
477  // Computes a sequence of about 'classes' equally spaced round values
478  // which cover the range of values from 'minimum' to 'maximum'.
479  // The values are chosen so that they are 1, 2 or 5 times a power of 10.
480 
481  QList<double> breaks;
482  if ( classes < 1 )
483  {
484  breaks.append( maximum );
485  return breaks;
486  }
487 
488  int minimumCount = ( int ) classes / 3;
489  double shrink = 0.75;
490  double highBias = 1.5;
491  double adjustBias = 0.5 + 1.5 * highBias;
492  int divisions = classes;
493  double h = highBias;
494  double cell;
495  int U;
496  bool small = false;
497  double dx = maximum - minimum;
498 
499  if ( dx == 0 && maximum == 0 )
500  {
501  cell = 1.0;
502  small = true;
503  U = 1;
504  }
505  else
506  {
507  cell = qMax( qAbs( minimum ), qAbs( maximum ) );
508  if ( adjustBias >= 1.5 * h + 0.5 )
509  {
510  U = 1 + ( 1.0 / ( 1 + h ) );
511  }
512  else
513  {
514  U = 1 + ( 1.5 / ( 1 + adjustBias ) );
515  }
516  small = dx < ( cell * U * qMax( 1, divisions ) * 1e-07 * 3.0 );
517  }
518 
519  if ( small )
520  {
521  if ( cell > 10 )
522  {
523  cell = 9 + cell / 10;
524  cell = cell * shrink;
525  }
526  if ( minimumCount > 1 )
527  {
528  cell = cell / minimumCount;
529  }
530  }
531  else
532  {
533  cell = dx;
534  if ( divisions > 1 )
535  {
536  cell = cell / divisions;
537  }
538  }
539  if ( cell < 20 * 1e-07 )
540  {
541  cell = 20 * 1e-07;
542  }
543 
544  double base = pow( 10.0, floor( log10( cell ) ) );
545  double unit = base;
546  if (( 2 * base ) - cell < h *( cell - unit ) )
547  {
548  unit = 2.0 * base;
549  if (( 5 * base ) - cell < adjustBias *( cell - unit ) )
550  {
551  unit = 5.0 * base;
552  if (( 10.0 * base ) - cell < h *( cell - unit ) )
553  {
554  unit = 10.0 * base;
555  }
556  }
557  }
558  // Maybe used to correct for the epsilon here??
559  int start = floor( minimum / unit + 1e-07 );
560  int end = ceil( maximum / unit - 1e-07 );
561 
562  // Extend the range out beyond the data. Does this ever happen??
563  while ( start * unit > minimum + ( 1e-07 * unit ) )
564  {
565  start = start - 1;
566  }
567  while ( end * unit < maximum - ( 1e-07 * unit ) )
568  {
569  end = end + 1;
570  }
571  QgsDebugMsg( QString( "pretty classes: %1" ).arg( end ) );
572 
573  // If we don't have quite enough labels, extend the range out
574  // to make more (these labels are beyond the data :( )
575  int k = floor( 0.5 + end - start );
576  if ( k < minimumCount )
577  {
578  k = minimumCount - k;
579  if ( start >= 0 )
580  {
581  end = end + k / 2;
582  start = start - k / 2 + k % 2;
583  }
584  else
585  {
586  start = start - k / 2;
587  end = end + k / 2 + k % 2;
588  }
589  }
590  double minimumBreak = start * unit;
591  //double maximumBreak = end * unit;
592  int count = end - start;
593 
594  for ( int i = 1; i < count + 1; i++ )
595  {
596  breaks.append( minimumBreak + i * unit );
597  }
598 
599  if ( breaks.isEmpty() )
600  return breaks;
601 
602  if ( breaks.first() < minimum )
603  {
604  breaks[0] = minimum;
605  }
606  if ( breaks.last() > maximum )
607  {
608  breaks[breaks.count()-1] = maximum;
609  }
610 
611  return breaks;
612 } // _calcPrettyBreaks
613 
614 
615 static QList<double> _calcStdDevBreaks( QList<double> values, int classes, QList<int> &labels )
616 {
617 
618  // C++ implementation of the standard deviation class interval algorithm
619  // as implemented in the 'classInt' package available for the R statistical
620  // prgramming language.
621 
622  // Returns breaks based on '_calcPrettyBreaks' of the centred and scaled
623  // values of 'values', and may have a number of classes different from 'classes'.
624 
625  // If there are no values to process: bail out
626  if ( !values.count() )
627  return QList<double>();
628 
629  double mean = 0.0;
630  double stdDev = 0.0;
631  int n = values.count();
632  double minimum = values[0];
633  double maximum = values[0];
634 
635  for ( int i = 0; i < n; i++ )
636  {
637  mean += values[i];
638  minimum = qMin( values[i], minimum ); // could use precomputed max and min
639  maximum = qMax( values[i], maximum ); // but have to go through entire list anyway
640  }
641  mean = mean / ( double ) n;
642 
643  double sd = 0.0;
644  for ( int i = 0; i < n; i++ )
645  {
646  sd = values[i] - mean;
647  stdDev += sd * sd;
648  }
649  stdDev = sqrt( stdDev / n );
650 
651  QList<double> breaks = _calcPrettyBreaks(( minimum - mean ) / stdDev, ( maximum - mean ) / stdDev, classes );
652  for ( int i = 0; i < breaks.count(); i++ )
653  {
654  labels.append(( int ) breaks[i] );
655  breaks[i] = ( breaks[i] * stdDev ) + mean;
656  }
657 
658  return breaks;
659 } // _calcStdDevBreaks
660 
661 static QList<double> _calcJenksBreaks( QList<double> values, int classes,
662  double minimum, double maximum,
663  int maximumSize = 1000 )
664 {
665  // Jenks Optimal (Natural Breaks) algorithm
666  // Based on the Jenks algorithm from the 'classInt' package available for
667  // the R statistical prgramming language, and from Python code from here:
668  // http://danieljlewis.org/2010/06/07/jenks-natural-breaks-algorithm-in-python/
669  // and is based on a JAVA and Fortran code available here:
670  // https://stat.ethz.ch/pipermail/r-sig-geo/2006-March/000811.html
671 
672  // Returns class breaks such that classes are internally homogeneous while
673  // assuring heterogeneity among classes.
674 
675  if ( !values.count() )
676  return QList<double>();
677 
678  if ( classes <= 1 )
679  {
680  return QList<double>() << maximum;
681  }
682 
683  if ( classes >= values.size() )
684  {
685  return values;
686  }
687 
688  QVector<double> sample;
689 
690  // if we have lots of values, we need to take a random sample
691  if ( values.size() > maximumSize )
692  {
693  // for now, sample at least maximumSize values or a 10% sample, whichever
694  // is larger. This will produce a more representative sample for very large
695  // layers, but could end up being computationally intensive...
696 
697  qsrand( time( 0 ) );
698 
699  sample.resize( qMax( maximumSize, values.size() / 10 ) );
700 
701  QgsDebugMsg( QString( "natural breaks (jenks) sample size: %1" ).arg( sample.size() ) );
702  QgsDebugMsg( QString( "values:%1" ).arg( values.size() ) );
703 
704  sample[ 0 ] = minimum;
705  sample[ 1 ] = maximum;;
706  for ( int i = 2; i < sample.size(); i++ )
707  {
708  // pick a random integer from 0 to n
709  double r = qrand();
710  int j = floor( r / RAND_MAX * ( values.size() - 1 ) );
711  sample[ i ] = values[ j ];
712  }
713  }
714  else
715  {
716  sample = values.toVector();
717  }
718 
719  int n = sample.size();
720 
721  // sort the sample values
722  qSort( sample );
723 
724  QVector< QVector<int> > matrixOne( n + 1 );
725  QVector< QVector<double> > matrixTwo( n + 1 );
726 
727  for ( int i = 0; i <= n; i++ )
728  {
729  matrixOne[i].resize( classes + 1 );
730  matrixTwo[i].resize( classes + 1 );
731  }
732 
733  for ( int i = 1; i <= classes; i++ )
734  {
735  matrixOne[0][i] = 1;
736  matrixOne[1][i] = 1;
737  matrixTwo[0][i] = 0.0;
738  for ( int j = 2; j <= n; j++ )
739  {
740  matrixTwo[j][i] = std::numeric_limits<double>::max();
741  }
742  }
743 
744  for ( int l = 2; l <= n; l++ )
745  {
746  double s1 = 0.0;
747  double s2 = 0.0;
748  int w = 0;
749 
750  double v = 0.0;
751 
752  for ( int m = 1; m <= l; m++ )
753  {
754  int i3 = l - m + 1;
755 
756  double val = sample[ i3 - 1 ];
757 
758  s2 += val * val;
759  s1 += val;
760  w++;
761 
762  v = s2 - ( s1 * s1 ) / ( double ) w;
763  int i4 = i3 - 1;
764  if ( i4 != 0 )
765  {
766  for ( int j = 2; j <= classes; j++ )
767  {
768  if ( matrixTwo[l][j] >= v + matrixTwo[i4][j - 1] )
769  {
770  matrixOne[l][j] = i4;
771  matrixTwo[l][j] = v + matrixTwo[i4][j - 1];
772  }
773  }
774  }
775  }
776  matrixOne[l][1] = 1;
777  matrixTwo[l][1] = v;
778  }
779 
780  QVector<double> breaks( classes );
781  breaks[classes-1] = sample[n-1];
782 
783  for ( int j = classes, k = n; j >= 2; j-- )
784  {
785  int id = matrixOne[k][j] - 1;
786  breaks[j - 2] = sample[id];
787  k = matrixOne[k][j] - 1;
788  }
789 
790  return breaks.toList();
791 } //_calcJenksBreaks
792 
793 
795  QgsVectorLayer* vlayer,
796  QString attrName,
797  int classes,
798  Mode mode,
799  QgsSymbolV2* symbol,
800  QgsVectorColorRampV2* ramp,
801  bool inverted )
802 {
803  if ( classes < 1 )
804  return NULL;
805 
806  int attrNum = vlayer->fieldNameIndex( attrName );
807  double minimum;
808  double maximum;
809 
810  QScopedPointer<QgsExpression> expression;
811 
812  if ( attrNum == -1 )
813  {
814  // try to use expression
815  expression.reset( new QgsExpression( attrName ) );
816  if ( expression->hasParserError() || !expression->prepare( vlayer->pendingFields() ) )
817  return 0; // should have a means to report errors
818 
819  QList<double> values;
820  QgsFeatureIterator fit = vlayer->getFeatures();
821  QgsFeature feature;
822  while ( fit.nextFeature( feature ) )
823  {
824  values << expression->evaluate( feature ).toDouble();
825  }
826  qSort( values );
827  minimum = values.first();
828  maximum = values.last();
829  }
830  else
831  {
832  minimum = vlayer->minimumValue( attrNum ).toDouble();
833  maximum = vlayer->maximumValue( attrNum ).toDouble();
834  }
835 
836  QgsDebugMsg( QString( "min %1 // max %2" ).arg( minimum ).arg( maximum ) );
837  QList<double> breaks;
838  QList<int> labels;
839  if ( mode == EqualInterval )
840  {
841  breaks = _calcEqualIntervalBreaks( minimum, maximum, classes );
842  }
843  else if ( mode == Pretty )
844  {
845  breaks = _calcPrettyBreaks( minimum, maximum, classes );
846  }
847  else if ( mode == Quantile || mode == Jenks || mode == StdDev )
848  {
849  // get values from layer
850  QList<double> values;
851  QgsFeature f;
852  QStringList lst;
853  if ( expression.isNull() )
854  lst.append( attrName );
855  else
856  lst = expression->referencedColumns();
857 
858  QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFlags( QgsFeatureRequest::NoGeometry ).setSubsetOfAttributes( lst, vlayer->pendingFields() ) );
859 
860  // create list of non-null attribute values
861  while ( fit.nextFeature( f ) )
862  {
863  QVariant v = expression.isNull() ? f.attribute( attrNum ) : expression->evaluate( f );
864  if ( !v.isNull() )
865  values.append( v.toDouble() );
866  }
867 
868  // calculate the breaks
869  if ( mode == Quantile )
870  {
871  breaks = _calcQuantileBreaks( values, classes );
872  }
873  else if ( mode == Jenks )
874  {
875  breaks = _calcJenksBreaks( values, classes, minimum, maximum );
876  }
877  else if ( mode == StdDev )
878  {
879  breaks = _calcStdDevBreaks( values, classes, labels );
880  }
881  }
882  else
883  {
884  Q_ASSERT( false );
885  }
886 
888  double lower, upper = minimum;
889  QString label;
890 
891  // "breaks" list contains all values at class breaks plus maximum as last break
892  int i = 0;
893  for ( QList<double>::iterator it = breaks.begin(); it != breaks.end(); ++it, ++i )
894  {
895  lower = upper; // upper border from last interval
896  upper = *it;
897  if ( mode == StdDev )
898  {
899  if ( i == 0 )
900  {
901  label = "< " + QString::number( labels[i], 'i', 0 ) + " Std Dev";
902  }
903  else if ( i == labels.count() - 1 )
904  {
905  label = ">= " + QString::number( labels[i-1], 'i', 0 ) + " Std Dev";
906  }
907  else
908  {
909  label = QString::number( labels[i-1], 'i', 0 ) + " Std Dev" + " - " + QString::number( labels[i], 'i', 0 ) + " Std Dev";
910  }
911  }
912  else
913  {
914  label = QString::number( lower, 'f', 4 ) + " - " + QString::number( upper, 'f', 4 );
915  }
916 
917  QgsSymbolV2* newSymbol = symbol->clone();
918  double colorValue;
919  if ( inverted ) colorValue = ( breaks.count() > 1 ? ( double )( breaks.count() - i - 1 ) / ( breaks.count() - 1 ) : 0 );
920  else colorValue = ( breaks.count() > 1 ? ( double ) i / ( breaks.count() - 1 ) : 0 );
921  newSymbol->setColor( ramp->color( colorValue ) ); // color from (0 / cl-1) to (cl-1 / cl-1)
922 
923  ranges.append( QgsRendererRangeV2( lower, upper, newSymbol, label ) );
924  }
925 
926  QgsGraduatedSymbolRendererV2* r = new QgsGraduatedSymbolRendererV2( attrName, ranges );
927  r->setSourceSymbol( symbol->clone() );
928  r->setSourceColorRamp( ramp->clone() );
929  r->setInvertedColorRamp( inverted );
930  r->setMode( mode );
931  return r;
932 }
933 
935 {
936  QDomElement symbolsElem = element.firstChildElement( "symbols" );
937  if ( symbolsElem.isNull() )
938  return NULL;
939 
940  QDomElement rangesElem = element.firstChildElement( "ranges" );
941  if ( rangesElem.isNull() )
942  return NULL;
943 
944  QgsSymbolV2Map symbolMap = QgsSymbolLayerV2Utils::loadSymbols( symbolsElem );
946 
947  QDomElement rangeElem = rangesElem.firstChildElement();
948  while ( !rangeElem.isNull() )
949  {
950  if ( rangeElem.tagName() == "range" )
951  {
952  double lowerValue = rangeElem.attribute( "lower" ).toDouble();
953  double upperValue = rangeElem.attribute( "upper" ).toDouble();
954  QString symbolName = rangeElem.attribute( "symbol" );
955  QString label = rangeElem.attribute( "label" );
956  if ( symbolMap.contains( symbolName ) )
957  {
958  QgsSymbolV2* symbol = symbolMap.take( symbolName );
959  ranges.append( QgsRendererRangeV2( lowerValue, upperValue, symbol, label ) );
960  }
961  }
962  rangeElem = rangeElem.nextSiblingElement();
963  }
964 
965  QString attrName = element.attribute( "attr" );
966 
967  QgsGraduatedSymbolRendererV2* r = new QgsGraduatedSymbolRendererV2( attrName, ranges );
968 
969  // delete symbols if there are any more
971 
972  // try to load source symbol (optional)
973  QDomElement sourceSymbolElem = element.firstChildElement( "source-symbol" );
974  if ( !sourceSymbolElem.isNull() )
975  {
976  QgsSymbolV2Map sourceSymbolMap = QgsSymbolLayerV2Utils::loadSymbols( sourceSymbolElem );
977  if ( sourceSymbolMap.contains( "0" ) )
978  {
979  r->setSourceSymbol( sourceSymbolMap.take( "0" ) );
980  }
981  QgsSymbolLayerV2Utils::clearSymbolMap( sourceSymbolMap );
982  }
983 
984  // try to load color ramp (optional)
985  QDomElement sourceColorRampElem = element.firstChildElement( "colorramp" );
986  if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( "name" ) == "[source]" )
987  {
988  r->setSourceColorRamp( QgsSymbolLayerV2Utils::loadColorRamp( sourceColorRampElem ) );
989  QDomElement invertedColorRampElem = element.firstChildElement( "invertedcolorramp" );
990  if ( !invertedColorRampElem.isNull() )
991  r->setInvertedColorRamp( invertedColorRampElem.attribute( "value" ) == "1" );
992  }
993 
994  // try to load mode
995  QDomElement modeElem = element.firstChildElement( "mode" );
996  if ( !modeElem.isNull() )
997  {
998  QString modeString = modeElem.attribute( "name" );
999  if ( modeString == "equal" )
1000  r->setMode( EqualInterval );
1001  else if ( modeString == "quantile" )
1002  r->setMode( Quantile );
1003  else if ( modeString == "jenks" )
1004  r->setMode( Jenks );
1005  else if ( modeString == "stddev" )
1006  r->setMode( StdDev );
1007  else if ( modeString == "pretty" )
1008  r->setMode( Pretty );
1009  }
1010 
1011  QDomElement rotationElem = element.firstChildElement( "rotation" );
1012  if ( !rotationElem.isNull() )
1013  r->setRotationField( rotationElem.attribute( "field" ) );
1014 
1015  QDomElement sizeScaleElem = element.firstChildElement( "sizescale" );
1016  if ( !sizeScaleElem.isNull() )
1017  r->setSizeScaleField( sizeScaleElem.attribute( "field" ) );
1018  r->setScaleMethod( QgsSymbolLayerV2Utils::decodeScaleMethod( sizeScaleElem.attribute( "scalemethod" ) ) );
1019 
1020  // TODO: symbol levels
1021  return r;
1022 }
1023 
1024 QDomElement QgsGraduatedSymbolRendererV2::save( QDomDocument& doc )
1025 {
1026  QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
1027  rendererElem.setAttribute( "type", "graduatedSymbol" );
1028  rendererElem.setAttribute( "symbollevels", ( mUsingSymbolLevels ? "1" : "0" ) );
1029  rendererElem.setAttribute( "attr", mAttrName );
1030 
1031  // ranges
1032  int i = 0;
1034  QDomElement rangesElem = doc.createElement( "ranges" );
1035  QgsRangeList::const_iterator it = mRanges.constBegin();
1036  for ( ; it != mRanges.constEnd(); ++it )
1037  {
1038  const QgsRendererRangeV2& range = *it;
1039  QString symbolName = QString::number( i );
1040  symbols.insert( symbolName, range.symbol() );
1041 
1042  QDomElement rangeElem = doc.createElement( "range" );
1043  rangeElem.setAttribute( "lower", QString::number( range.lowerValue(), 'f' ) );
1044  rangeElem.setAttribute( "upper", QString::number( range.upperValue(), 'f' ) );
1045  rangeElem.setAttribute( "symbol", symbolName );
1046  rangeElem.setAttribute( "label", range.label() );
1047  rangeElem.setAttribute( "render", range.renderState() ? "true" : "false" );
1048  rangesElem.appendChild( rangeElem );
1049  i++;
1050  }
1051 
1052  rendererElem.appendChild( rangesElem );
1053 
1054  // save symbols
1055  QDomElement symbolsElem = QgsSymbolLayerV2Utils::saveSymbols( symbols, "symbols", doc );
1056  rendererElem.appendChild( symbolsElem );
1057 
1058  // save source symbol
1059  if ( mSourceSymbol.data() )
1060  {
1061  QgsSymbolV2Map sourceSymbols;
1062  sourceSymbols.insert( "0", mSourceSymbol.data() );
1063  QDomElement sourceSymbolElem = QgsSymbolLayerV2Utils::saveSymbols( sourceSymbols, "source-symbol", doc );
1064  rendererElem.appendChild( sourceSymbolElem );
1065  }
1066 
1067  // save source color ramp
1068  if ( mSourceColorRamp.data() )
1069  {
1070  QDomElement colorRampElem = QgsSymbolLayerV2Utils::saveColorRamp( "[source]", mSourceColorRamp.data(), doc );
1071  rendererElem.appendChild( colorRampElem );
1072  QDomElement invertedElem = doc.createElement( "invertedcolorramp" );
1073  invertedElem.setAttribute( "value", mInvertedColorRamp );
1074  rendererElem.appendChild( invertedElem );
1075  }
1076 
1077  // save mode
1078  QString modeString;
1079  if ( mMode == EqualInterval )
1080  modeString = "equal";
1081  else if ( mMode == Quantile )
1082  modeString = "quantile";
1083  else if ( mMode == Jenks )
1084  modeString = "jenks";
1085  else if ( mMode == StdDev )
1086  modeString = "stddev";
1087  else if ( mMode == Pretty )
1088  modeString = "pretty";
1089  if ( !modeString.isEmpty() )
1090  {
1091  QDomElement modeElem = doc.createElement( "mode" );
1092  modeElem.setAttribute( "name", modeString );
1093  rendererElem.appendChild( modeElem );
1094  }
1095 
1096  QDomElement rotationElem = doc.createElement( "rotation" );
1097  if ( mRotation.data() )
1098  rotationElem.setAttribute( "field", QgsSymbolLayerV2Utils::fieldOrExpressionFromExpression( mRotation.data() ) );
1099  rendererElem.appendChild( rotationElem );
1100 
1101  QDomElement sizeScaleElem = doc.createElement( "sizescale" );
1102  if ( mSizeScale.data() )
1103  sizeScaleElem.setAttribute( "field", QgsSymbolLayerV2Utils::fieldOrExpressionFromExpression( mSizeScale.data() ) );
1104  sizeScaleElem.setAttribute( "scalemethod", QgsSymbolLayerV2Utils::encodeScaleMethod( mScaleMethod ) );
1105  rendererElem.appendChild( sizeScaleElem );
1106 
1107  return rendererElem;
1108 }
1109 
1111 {
1113  int count = ranges().count();
1114  for ( int i = 0; i < count; i++ )
1115  {
1116  const QgsRendererRangeV2& range = ranges()[i];
1117  QPixmap pix = QgsSymbolLayerV2Utils::symbolPreviewPixmap( range.symbol(), iconSize );
1118  lst << qMakePair( range.label(), pix );
1119  }
1120  return lst;
1121 }
1122 
1124 {
1125  Q_UNUSED( scaleDenominator );
1126  QgsLegendSymbolList lst;
1127 
1128  foreach ( const QgsRendererRangeV2& range, mRanges )
1129  {
1130  if ( rule.isEmpty() || range.label() == rule )
1131  {
1132  lst << qMakePair( range.label(), range.symbol() );
1133  }
1134  }
1135  return lst;
1136 }
1137 
1139 {
1140  return mSourceSymbol.data();
1141 }
1143 {
1144  mSourceSymbol.reset( sym );
1145 }
1146 
1148 {
1149  return mSourceColorRamp.data();
1150 }
1151 
1153 {
1154  mSourceColorRamp.reset( ramp );
1155 }
1156 
1158 {
1159  int i = 0;
1160  foreach ( QgsRendererRangeV2 range, mRanges )
1161  {
1162  QgsSymbolV2* symbol = range.symbol()->clone();
1163  double colorValue;
1164  if ( inverted ) colorValue = ( mRanges.count() > 1 ? ( double )( mRanges.count() - i - 1 ) / ( mRanges.count() - 1 ) : 0 );
1165  else colorValue = ( mRanges.count() > 1 ? ( double ) i / ( mRanges.count() - 1 ) : 0 );
1166  symbol->setColor( ramp->color( colorValue ) );
1167  updateRangeSymbol( i, symbol );
1168  ++i;
1169  }
1170  this->setSourceColorRamp( ramp );
1171  this->setInvertedColorRamp( inverted );
1172 }
1173 
1175 {
1176  int i = 0;
1177  foreach ( QgsRendererRangeV2 range, mRanges )
1178  {
1179  QgsSymbolV2* symbol = sym->clone();
1180  symbol->setColor( range.symbol()->color() );
1181  updateRangeSymbol( i, symbol );
1182  ++i;
1183  }
1184  this->setSourceSymbol( sym->clone() );
1185 }
1186 
1187 void QgsGraduatedSymbolRendererV2::setRotationField( QString fieldOrExpression )
1188 {
1190 }
1191 
1193 {
1194  return mRotation.data() ? QgsSymbolLayerV2Utils::fieldOrExpressionFromExpression( mRotation.data() ) : QString();
1195 }
1196 
1197 void QgsGraduatedSymbolRendererV2::setSizeScaleField( QString fieldOrExpression )
1198 {
1200 }
1201 
1203 {
1205 }
1206 
1208 {
1210  for ( QgsRangeList::iterator it = mRanges.begin(); it != mRanges.end(); ++it )
1211  {
1212  setScaleMethodToSymbol( it->symbol(), scaleMethod );
1213  }
1214 }
1215 
1217 {
1218  return true;
1219 }
1220 
1222 {
1223  bool ok;
1224  int index = key.toInt( &ok );
1225  if ( ok && index >= 0 && index < mRanges.size() )
1226  return mRanges[ index ].renderState();
1227  else
1228  return true;
1229 }
1230 
1232 {
1233  bool ok;
1234  int index = key.toInt( &ok );
1235  if ( ok )
1236  updateRangeRenderState( index, state );
1237 }
1238 
1239 
1241 {
1242  QgsSymbolV2* newSymbol = symbol->clone();
1243  QString label = "0.0 - 0.0";
1244  mRanges.insert( 0, QgsRendererRangeV2( 0.0, 0.0, newSymbol, label ) );
1245 
1246 }
1247 
1249 {
1250  mRanges.append( range );
1251 }
1252 
1254 {
1255  mRanges.removeAt( idx );
1256 }
1257 
1259 {
1260  mRanges.clear();
1261 }
1262 
1264 {
1265  if ( from < 0 || from >= mRanges.size() || to < 0 || to >= mRanges.size() ) return;
1266  mRanges.move( from, to );
1267 }
1268 
1270 {
1271  return r1.lowerValue() < r2.lowerValue();
1272 }
1273 
1275 {
1276  return !valueLessThan( r1, r2 );
1277 }
1278 
1280 {
1281  QgsDebugMsg( "Entered" );
1282  if ( order == Qt::AscendingOrder )
1283  {
1284  qSort( mRanges.begin(), mRanges.end(), valueLessThan );
1285  }
1286  else
1287  {
1288  qSort( mRanges.begin(), mRanges.end(), valueGreaterThan );
1289  }
1290 }
1291 
1293 {
1294  return QString::localeAwareCompare( r1.label(), r2.label() ) < 0;
1295 }
1296 
1298 {
1299  return !labelLessThan( r1, r2 );
1300 }
1301 
1303 {
1304  if ( order == Qt::AscendingOrder )
1305  {
1306  qSort( mRanges.begin(), mRanges.end(), labelLessThan );
1307  }
1308  else
1309  {
1310  qSort( mRanges.begin(), mRanges.end(), labelGreaterThan );
1311  }
1312 }
1313 
QMap< QString, QgsSymbolV2 * > QgsSymbolV2Map
Definition: qgsrendererv2.h:38
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:89
QList< QgsRendererRangeV2 > QgsRangeList
Wrapper for iterator of features from vector data provider or vector layer.
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:46
static unsigned index
void setLowerValue(double lowerValue)
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
Definition: qgsexpression.h:96
virtual QDomElement save(QDomDocument &doc)
store renderer info to XML element
bool labelLessThan(const QgsRendererRangeV2 &r1, const QgsRendererRangeV2 &r2)
static QgsVectorColorRampV2 * loadColorRamp(QDomElement &element)
bool updateRangeLabel(int rangeIndex, QString label)
QList< QgsSymbolV2 * > QgsSymbolV2List
Definition: qgsrendererv2.h:37
static QList< double > _calcPrettyBreaks(double minimum, double maximum, int classes)
SymbolType type() const
Definition: qgssymbolv2.h:79
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 the all symbols but leave breaks and colors.
#define QgsDebugMsg(str)
Definition: qgslogger.h:36
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:186
double rendererScale() const
virtual QgsSymbolV2 * clone() const =0
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())
Query the provider for features specified in request.
void updateColorRamp(QgsVectorColorRampV2 *ramp, bool inverted=false)
Update the color ramp used.
bool updateRangeRenderState(int rangeIndex, bool render)
static QgsGraduatedSymbolRendererV2 * createRenderer(QgsVectorLayer *vlayer, QString attrName, int classes, Mode mode, QgsSymbolV2 *symbol, QgsVectorColorRampV2 *ramp, bool inverted=false)
void setSizeScaleField(QString fieldOrExpression)
virtual QString dump() const
for debugging
Container of fields for a vector layer.
Definition: qgsfield.h:163
virtual QgsSymbolV2 * symbolForFeature(QgsFeature &feature)
to be overridden
virtual QgsLegendSymbolList legendSymbolItems(double scaleDenominator=-1, QString rule=QString())
return a list of item text / symbol
QHash< QgsSymbolV2 *, QgsSymbolV2 * > mTempSymbols
temporary symbols, used for data-defined rotation and scaling
virtual bool legendSymbolItemChecked(QString key)
item in symbology was checked
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 QgsSymbolV2List symbols()
for symbol levels
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:416
void setWidth(double width)
QScopedPointer< QgsSymbolV2 > mSymbol
void setRotationField(QString fieldOrExpression)
QScopedPointer< QgsExpression > mExpression
void setColor(const QColor &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)
void startRender(QgsRenderContext &context, const QgsFields *fields=0)
#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)
QStringList referencedColumns()
Get list of columns referenced by the expression.
QgsSymbolV2 * symbol() const
void setAngle(double angle)
This class wraps a request for features to a vector layer (or directly its vector data provider)...
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
QgsGraduatedSymbolRendererV2(QString attrName=QString(), QgsRangeList ranges=QgsRangeList())
void setUpperValue(double upperValue)
QgsSymbolV2 * symbolForValue(double value)
bool labelGreaterThan(const QgsRendererRangeV2 &r1, const QgsRendererRangeV2 &r2)
QList< QPair< QString, QPixmap > > QgsLegendSymbologyList
virtual QColor color(double value) const =0
bool valueLessThan(const QgsRendererRangeV2 &r1, const QgsRendererRangeV2 &r2)
void sortByValue(Qt::SortOrder order=Qt::AscendingOrder)
void setUsingSymbolLevels(bool usingSymbolLevels)
static QList< double > _calcEqualIntervalBreaks(double minimum, double maximum, int classes)
virtual QgsLegendSymbologyList legendSymbologyItems(QSize iconSize)
return a list of symbology items for the legend
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.
int mAttrNum
attribute index (derived from attribute name in startRender)
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:230
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
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)
virtual bool legendSymbolItemsCheckable() const
items of symbology items in legend should be checkable
virtual void stopRender(QgsRenderContext &context)
virtual void startRender(QgsRenderContext &context, const QgsFields &fields)
bool updateRangeSymbol(int rangeIndex, QgsSymbolV2 *symbol)
void setSourceColorRamp(QgsVectorColorRampV2 *ramp)
static QPixmap symbolPreviewPixmap(QgsSymbolV2 *symbol, QSize size)
QScopedPointer< QgsSymbolV2 > mSourceSymbol
void setRenderHints(int hints)
Definition: qgssymbolv2.h:133
static void clearSymbolMap(QgsSymbolV2Map &symbols)
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
const QgsFields & pendingFields() const
returns field list in the to-be-committed state
QScopedPointer< QgsExpression > mSizeScale
bool nextFeature(QgsFeature &f)
QgsRendererRangeV2 & operator=(QgsRendererRangeV2 range)
Geometry is not required. It may still be returned if e.g. required for a filter condition.
virtual void toSld(QDomDocument &doc, QDomElement &element) const
used from subclasses to create SLD Rule elements following SLD v1.1 specs
static QList< double > _calcStdDevBreaks(QList< double > values, int classes, QList< int > &labels)
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:41
virtual QgsFeatureRendererV2 * clone()
int max(int a, int b)
Definition: util.h:87
virtual void checkLegendSymbolItem(QString key, bool state=true)
item in symbology was checked
void setScaleMethod(QgsSymbolV2::ScaleMethod scaleMethod)
bool valueGreaterThan(const QgsRendererRangeV2 &r1, const QgsRendererRangeV2 &r2)
QColor color() const