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