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 
24 #include "qgsfeature.h"
25 #include "qgsvectorlayer.h"
26 #include "qgslogger.h"
27 #include "qgsvectordataprovider.h"
28 #include "qgsexpression.h"
29 #include <QDomDocument>
30 #include <QDomElement>
31 #include <QSettings> // for legend
32 #include <limits> // for jenks classification
33 #include <cmath> // for pretty 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  , mAttrNum( -1 )
289  , mCounting( false )
290 
291 {
292  // TODO: check ranges for sanity (NULL symbols, invalid ranges)
293 }
294 
296 {
297  mRanges.clear(); // should delete all the symbols
298 }
299 
301 {
302  for ( QgsRangeList::iterator it = mRanges.begin(); it != mRanges.end(); ++it )
303  {
304  if ( it->lowerValue() <= value && it->upperValue() >= value )
305  {
306  if ( it->renderState() || mCounting )
307  return it->symbol();
308  else
309  return NULL;
310  }
311  }
312  // the value is out of the range: return NULL instead of symbol
313  return NULL;
314 }
315 
317 {
318  QgsSymbolV2* symbol = originalSymbolForFeature( feature );
319  if ( symbol == NULL )
320  return NULL;
321 
322  if ( !mRotation.data() && !mSizeScale.data() )
323  return symbol; // no data-defined rotation/scaling - just return the symbol
324 
325  // find out rotation, size scale
326  const double rotation = mRotation.data() ? mRotation->evaluate( feature ).toDouble() : 0;
327  const double sizeScale = mSizeScale.data() ? mSizeScale->evaluate( feature ).toDouble() : 1.;
328 
329  // take a temporary symbol (or create it if doesn't exist)
330  QgsSymbolV2* tempSymbol = mTempSymbols[symbol];
331 
332  // modify the temporary symbol and return it
333  if ( tempSymbol->type() == QgsSymbolV2::Marker )
334  {
335  QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( tempSymbol );
336  if ( mRotation.data() ) markerSymbol->setAngle( rotation );
337  markerSymbol->setSize( sizeScale * static_cast<QgsMarkerSymbolV2*>( symbol )->size() );
338  markerSymbol->setScaleMethod( mScaleMethod );
339  }
340  else if ( tempSymbol->type() == QgsSymbolV2::Line )
341  {
342  QgsLineSymbolV2* lineSymbol = static_cast<QgsLineSymbolV2*>( tempSymbol );
343  lineSymbol->setWidth( sizeScale * static_cast<QgsLineSymbolV2*>( symbol )->width() );
344  }
345  return tempSymbol;
346 }
347 
349 {
350  const QgsAttributes& attrs = feature.attributes();
351  QVariant value;
352  if ( mAttrNum < 0 || mAttrNum >= attrs.count() )
353  {
354  value = mExpression->evaluate( &feature );
355  }
356  else
357  {
358  value = attrs[mAttrNum];
359  }
360 
361  // Null values should not be categorized
362  if ( value.isNull() )
363  return NULL;
364 
365  // find the right category
366  return symbolForValue( value.toDouble() );
367 }
368 
370 {
371  mCounting = context.rendererScale() == 0.0;
372 
373  // find out classification attribute index from name
374  mAttrNum = fields.fieldNameIndex( mAttrName );
375 
376  if ( mAttrNum == -1 )
377  {
378  mExpression.reset( new QgsExpression( mAttrName ) );
379  mExpression->prepare( fields );
380  }
381 
382  QgsRangeList::iterator it = mRanges.begin();
383  for ( ; it != mRanges.end(); ++it )
384  {
385  if ( !it->symbol() )
386  continue;
387 
388  it->symbol()->startRender( context, &fields );
389 
390  if ( mRotation.data() || mSizeScale.data() )
391  {
392  QgsSymbolV2* tempSymbol = it->symbol()->clone();
393  tempSymbol->setRenderHints(( mRotation.data() ? QgsSymbolV2::DataDefinedRotation : 0 ) |
395  tempSymbol->startRender( context, &fields );
396  mTempSymbols[ it->symbol()] = tempSymbol;
397  }
398  }
399 }
400 
402 {
403  QgsRangeList::iterator it = mRanges.begin();
404  for ( ; it != mRanges.end(); ++it )
405  {
406  if ( !it->symbol() )
407  continue;
408 
409  it->symbol()->stopRender( context );
410  }
411 
412  // cleanup mTempSymbols
413  QHash<QgsSymbolV2*, QgsSymbolV2*>::iterator it2 = mTempSymbols.begin();
414  for ( ; it2 != mTempSymbols.end(); ++it2 )
415  {
416  it2.value()->stopRender( context );
417  delete it2.value();
418  }
419  mTempSymbols.clear();
420 }
421 
423 {
424  QSet<QString> attributes;
425 
426  // mAttrName can contain either attribute name or an expression.
427  // Sometimes it is not possible to distinguish between those two,
428  // e.g. "a - b" can be both a valid attribute name or expression.
429  // Since we do not have access to fields here, try both options.
430  attributes << mAttrName;
431 
432  QgsExpression testExpr( mAttrName );
433  if ( !testExpr.hasParserError() )
434  attributes.unite( testExpr.referencedColumns().toSet() );
435 
436  if ( mRotation.data() ) attributes.unite( mRotation->referencedColumns().toSet() );
437  if ( mSizeScale.data() ) attributes.unite( mSizeScale->referencedColumns().toSet() );
438 
439  QgsRangeList::const_iterator range_it = mRanges.constBegin();
440  for ( ; range_it != mRanges.constEnd(); ++range_it )
441  {
442  QgsSymbolV2* symbol = range_it->symbol();
443  if ( symbol )
444  {
445  attributes.unite( symbol->usedAttributes() );
446  }
447  }
448  return attributes.toList();
449 }
450 
452 {
453  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
454  return false;
455  mRanges[rangeIndex].setSymbol( symbol );
456  return true;
457 }
458 
459 bool QgsGraduatedSymbolRendererV2::updateRangeLabel( int rangeIndex, QString label )
460 {
461  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
462  return false;
463  mRanges[rangeIndex].setLabel( label );
464  return true;
465 }
466 
467 bool QgsGraduatedSymbolRendererV2::updateRangeUpperValue( int rangeIndex, double value )
468 {
469  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
470  return false;
471  QgsRendererRangeV2 &range = mRanges[rangeIndex];
472  bool isDefaultLabel = range.label() == mLabelFormat.labelForRange( range );
473  range.setUpperValue( value );
474  if ( isDefaultLabel ) range.setLabel( mLabelFormat.labelForRange( range ) );
475  return true;
476 }
477 
478 bool QgsGraduatedSymbolRendererV2::updateRangeLowerValue( int rangeIndex, double value )
479 {
480  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
481  return false;
482  QgsRendererRangeV2 &range = mRanges[rangeIndex];
483  bool isDefaultLabel = range.label() == mLabelFormat.labelForRange( range );
484  range.setLowerValue( value );
485  if ( isDefaultLabel ) range.setLabel( mLabelFormat.labelForRange( range ) );
486  return true;
487 }
488 
490 {
491  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
492  return false;
493  mRanges[rangeIndex].setRenderState( value );
494  return true;
495 }
496 
498 {
499  QString s = QString( "GRADUATED: attr %1\n" ).arg( mAttrName );
500  for ( int i = 0; i < mRanges.count(); i++ )
501  s += mRanges[i].dump();
502  return s;
503 }
504 
506 {
508  r->setMode( mMode );
509  if ( mSourceSymbol.data() )
510  r->setSourceSymbol( mSourceSymbol->clone() );
511  if ( mSourceColorRamp.data() )
512  {
513  r->setSourceColorRamp( mSourceColorRamp->clone() );
515  }
519  r->setScaleMethod( scaleMethod() );
520  r->setLabelFormat( labelFormat() );
521  return r;
522 }
523 
524 void QgsGraduatedSymbolRendererV2::toSld( QDomDocument& doc, QDomElement &element ) const
525 {
526  QgsStringMap props;
527  props[ "attribute" ] = mAttrName;
528  if ( mRotation.data() )
529  props[ "angle" ] = mRotation->expression();
530  if ( mSizeScale.data() )
531  props[ "scale" ] = mSizeScale->expression();
532 
533  // create a Rule for each range
534  for ( QgsRangeList::const_iterator it = mRanges.constBegin(); it != mRanges.constEnd(); ++it )
535  {
536  QgsStringMap catProps( props );
537  it->toSld( doc, element, catProps );
538  }
539 }
540 
542 {
543  QgsSymbolV2List lst;
544  for ( int i = 0; i < mRanges.count(); i++ )
545  lst.append( mRanges[i].symbol() );
546  return lst;
547 }
548 
549 static QList<double> _calcEqualIntervalBreaks( double minimum, double maximum, int classes )
550 {
551 
552  // Equal interval algorithm
553  //
554  // Returns breaks based on dividing the range ('minimum' to 'maximum')
555  // into 'classes' parts.
556 
557  double step = ( maximum - minimum ) / classes;
558 
559  QList<double> breaks;
560  double value = minimum;
561  for ( int i = 0; i < classes; i++ )
562  {
563  value += step;
564  breaks.append( value );
565  }
566 
567  // floating point arithmetics is not precise:
568  // set the last break to be exactly maximum so we do not miss it
569  breaks[classes-1] = maximum;
570 
571  return breaks;
572 }
573 
574 static QList<double> _calcQuantileBreaks( QList<double> values, int classes )
575 {
576  // q-th quantile of a data set:
577  // value where q fraction of data is below and (1-q) fraction is above this value
578  // Xq = (1 - r) * X_NI1 + r * X_NI2
579  // NI1 = (int) (q * (n+1))
580  // NI2 = NI1 + 1
581  // r = q * (n+1) - (int) (q * (n+1))
582  // (indices of X: 1...n)
583 
584  // sort the values first
585  qSort( values );
586 
587  QList<double> breaks;
588 
589  // If there are no values to process: bail out
590  if ( !values.count() )
591  return breaks;
592 
593  int n = values.count();
594  double Xq = n > 0 ? values[0] : 0.0;
595 
596  for ( int i = 1; i < classes; i++ )
597  {
598  if ( n > 1 )
599  {
600  double q = i / ( double ) classes;
601  double a = q * ( n - 1 );
602  int aa = ( int )( a );
603 
604  double r = a - aa;
605  Xq = ( 1 - r ) * values[aa] + r * values[aa+1];
606  }
607  breaks.append( Xq );
608  }
609 
610  breaks.append( values[ n-1 ] );
611 
612  return breaks;
613 }
614 
615 static QList<double> _calcPrettyBreaks( double minimum, double maximum, int classes )
616 {
617 
618  // C++ implementation of R's pretty algorithm
619  // Based on code for determining optimal tick placement for statistical graphics
620  // from the R statistical programming language.
621  // Code ported from R implementation from 'labeling' R package
622  //
623  // Computes a sequence of about 'classes' equally spaced round values
624  // which cover the range of values from 'minimum' to 'maximum'.
625  // The values are chosen so that they are 1, 2 or 5 times a power of 10.
626 
627  QList<double> breaks;
628  if ( classes < 1 )
629  {
630  breaks.append( maximum );
631  return breaks;
632  }
633 
634  int minimumCount = ( int ) classes / 3;
635  double shrink = 0.75;
636  double highBias = 1.5;
637  double adjustBias = 0.5 + 1.5 * highBias;
638  int divisions = classes;
639  double h = highBias;
640  double cell;
641  int U;
642  bool small = false;
643  double dx = maximum - minimum;
644 
645  if ( dx == 0 && maximum == 0 )
646  {
647  cell = 1.0;
648  small = true;
649  U = 1;
650  }
651  else
652  {
653  cell = qMax( qAbs( minimum ), qAbs( maximum ) );
654  if ( adjustBias >= 1.5 * h + 0.5 )
655  {
656  U = 1 + ( 1.0 / ( 1 + h ) );
657  }
658  else
659  {
660  U = 1 + ( 1.5 / ( 1 + adjustBias ) );
661  }
662  small = dx < ( cell * U * qMax( 1, divisions ) * 1e-07 * 3.0 );
663  }
664 
665  if ( small )
666  {
667  if ( cell > 10 )
668  {
669  cell = 9 + cell / 10;
670  cell = cell * shrink;
671  }
672  if ( minimumCount > 1 )
673  {
674  cell = cell / minimumCount;
675  }
676  }
677  else
678  {
679  cell = dx;
680  if ( divisions > 1 )
681  {
682  cell = cell / divisions;
683  }
684  }
685  if ( cell < 20 * 1e-07 )
686  {
687  cell = 20 * 1e-07;
688  }
689 
690  double base = pow( 10.0, floor( log10( cell ) ) );
691  double unit = base;
692  if (( 2 * base ) - cell < h *( cell - unit ) )
693  {
694  unit = 2.0 * base;
695  if (( 5 * base ) - cell < adjustBias *( cell - unit ) )
696  {
697  unit = 5.0 * base;
698  if (( 10.0 * base ) - cell < h *( cell - unit ) )
699  {
700  unit = 10.0 * base;
701  }
702  }
703  }
704  // Maybe used to correct for the epsilon here??
705  int start = floor( minimum / unit + 1e-07 );
706  int end = ceil( maximum / unit - 1e-07 );
707 
708  // Extend the range out beyond the data. Does this ever happen??
709  while ( start * unit > minimum + ( 1e-07 * unit ) )
710  {
711  start = start - 1;
712  }
713  while ( end * unit < maximum - ( 1e-07 * unit ) )
714  {
715  end = end + 1;
716  }
717  QgsDebugMsg( QString( "pretty classes: %1" ).arg( end ) );
718 
719  // If we don't have quite enough labels, extend the range out
720  // to make more (these labels are beyond the data :( )
721  int k = floor( 0.5 + end - start );
722  if ( k < minimumCount )
723  {
724  k = minimumCount - k;
725  if ( start >= 0 )
726  {
727  end = end + k / 2;
728  start = start - k / 2 + k % 2;
729  }
730  else
731  {
732  start = start - k / 2;
733  end = end + k / 2 + k % 2;
734  }
735  }
736  double minimumBreak = start * unit;
737  //double maximumBreak = end * unit;
738  int count = end - start;
739 
740  for ( int i = 1; i < count + 1; i++ )
741  {
742  breaks.append( minimumBreak + i * unit );
743  }
744 
745  if ( breaks.isEmpty() )
746  return breaks;
747 
748  if ( breaks.first() < minimum )
749  {
750  breaks[0] = minimum;
751  }
752  if ( breaks.last() > maximum )
753  {
754  breaks[breaks.count()-1] = maximum;
755  }
756 
757  return breaks;
758 } // _calcPrettyBreaks
759 
760 
761 static QList<double> _calcStdDevBreaks( QList<double> values, int classes, QList<double> &labels )
762 {
763 
764  // C++ implementation of the standard deviation class interval algorithm
765  // as implemented in the 'classInt' package available for the R statistical
766  // prgramming language.
767 
768  // Returns breaks based on '_calcPrettyBreaks' of the centred and scaled
769  // values of 'values', and may have a number of classes different from 'classes'.
770 
771  // If there are no values to process: bail out
772  if ( !values.count() )
773  return QList<double>();
774 
775  double mean = 0.0;
776  double stdDev = 0.0;
777  int n = values.count();
778  double minimum = values[0];
779  double maximum = values[0];
780 
781  for ( int i = 0; i < n; i++ )
782  {
783  mean += values[i];
784  minimum = qMin( values[i], minimum ); // could use precomputed max and min
785  maximum = qMax( values[i], maximum ); // but have to go through entire list anyway
786  }
787  mean = mean / ( double ) n;
788 
789  double sd = 0.0;
790  for ( int i = 0; i < n; i++ )
791  {
792  sd = values[i] - mean;
793  stdDev += sd * sd;
794  }
795  stdDev = sqrt( stdDev / n );
796 
797  QList<double> breaks = _calcPrettyBreaks(( minimum - mean ) / stdDev, ( maximum - mean ) / stdDev, classes );
798  for ( int i = 0; i < breaks.count(); i++ )
799  {
800  labels.append( breaks[i] );
801  breaks[i] = ( breaks[i] * stdDev ) + mean;
802  }
803 
804  return breaks;
805 } // _calcStdDevBreaks
806 
807 static QList<double> _calcJenksBreaks( QList<double> values, int classes,
808  double minimum, double maximum,
809  int maximumSize = 1000 )
810 {
811  // Jenks Optimal (Natural Breaks) algorithm
812  // Based on the Jenks algorithm from the 'classInt' package available for
813  // the R statistical prgramming language, and from Python code from here:
814  // http://danieljlewis.org/2010/06/07/jenks-natural-breaks-algorithm-in-python/
815  // and is based on a JAVA and Fortran code available here:
816  // https://stat.ethz.ch/pipermail/r-sig-geo/2006-March/000811.html
817 
818  // Returns class breaks such that classes are internally homogeneous while
819  // assuring heterogeneity among classes.
820 
821  if ( !values.count() )
822  return QList<double>();
823 
824  if ( classes <= 1 )
825  {
826  return QList<double>() << maximum;
827  }
828 
829  if ( classes >= values.size() )
830  {
831  return values;
832  }
833 
834  QVector<double> sample;
835 
836  // if we have lots of values, we need to take a random sample
837  if ( values.size() > maximumSize )
838  {
839  // for now, sample at least maximumSize values or a 10% sample, whichever
840  // is larger. This will produce a more representative sample for very large
841  // layers, but could end up being computationally intensive...
842 
843  sample.resize( qMax( maximumSize, values.size() / 10 ) );
844 
845  QgsDebugMsg( QString( "natural breaks (jenks) sample size: %1" ).arg( sample.size() ) );
846  QgsDebugMsg( QString( "values:%1" ).arg( values.size() ) );
847 
848  sample[ 0 ] = minimum;
849  sample[ 1 ] = maximum;;
850  for ( int i = 2; i < sample.size(); i++ )
851  {
852  // pick a random integer from 0 to n
853  double r = qrand();
854  int j = floor( r / RAND_MAX * ( values.size() - 1 ) );
855  sample[ i ] = values[ j ];
856  }
857  }
858  else
859  {
860  sample = values.toVector();
861  }
862 
863  int n = sample.size();
864 
865  // sort the sample values
866  qSort( sample );
867 
868  QVector< QVector<int> > matrixOne( n + 1 );
869  QVector< QVector<double> > matrixTwo( n + 1 );
870 
871  for ( int i = 0; i <= n; i++ )
872  {
873  matrixOne[i].resize( classes + 1 );
874  matrixTwo[i].resize( classes + 1 );
875  }
876 
877  for ( int i = 1; i <= classes; i++ )
878  {
879  matrixOne[0][i] = 1;
880  matrixOne[1][i] = 1;
881  matrixTwo[0][i] = 0.0;
882  for ( int j = 2; j <= n; j++ )
883  {
884  matrixTwo[j][i] = std::numeric_limits<double>::max();
885  }
886  }
887 
888  for ( int l = 2; l <= n; l++ )
889  {
890  double s1 = 0.0;
891  double s2 = 0.0;
892  int w = 0;
893 
894  double v = 0.0;
895 
896  for ( int m = 1; m <= l; m++ )
897  {
898  int i3 = l - m + 1;
899 
900  double val = sample[ i3 - 1 ];
901 
902  s2 += val * val;
903  s1 += val;
904  w++;
905 
906  v = s2 - ( s1 * s1 ) / ( double ) w;
907  int i4 = i3 - 1;
908  if ( i4 != 0 )
909  {
910  for ( int j = 2; j <= classes; j++ )
911  {
912  if ( matrixTwo[l][j] >= v + matrixTwo[i4][j - 1] )
913  {
914  matrixOne[l][j] = i4;
915  matrixTwo[l][j] = v + matrixTwo[i4][j - 1];
916  }
917  }
918  }
919  }
920  matrixOne[l][1] = 1;
921  matrixTwo[l][1] = v;
922  }
923 
924  QVector<double> breaks( classes );
925  breaks[classes-1] = sample[n-1];
926 
927  for ( int j = classes, k = n; j >= 2; j-- )
928  {
929  int id = matrixOne[k][j] - 1;
930  breaks[j - 2] = sample[id];
931  k = matrixOne[k][j] - 1;
932  }
933 
934  return breaks.toList();
935 } //_calcJenksBreaks
936 
937 
939  QgsVectorLayer* vlayer,
940  QString attrName,
941  int classes,
942  Mode mode,
943  QgsSymbolV2* symbol,
944  QgsVectorColorRampV2* ramp,
945  bool inverted,
947 )
948 {
950  QgsGraduatedSymbolRendererV2* r = new QgsGraduatedSymbolRendererV2( attrName, ranges );
951  r->setSourceSymbol( symbol->clone() );
952  r->setSourceColorRamp( ramp->clone() );
953  r->setInvertedColorRamp( inverted );
954  r->setMode( mode );
955  r->setLabelFormat( labelFormat );
956  r->updateClasses( vlayer, mode, classes );
957  return r;
958 }
959 
961 {
962  QList<double> values;
963  QScopedPointer<QgsExpression> expression;
964  int attrNum = vlayer->fieldNameIndex( mAttrName );
965 
966  if ( attrNum == -1 )
967  {
968  // try to use expression
969  expression.reset( new QgsExpression( mAttrName ) );
970  if ( expression->hasParserError() || !expression->prepare( vlayer->pendingFields() ) )
971  return values; // should have a means to report errors
972  }
973 
974  QgsFeature f;
975  QStringList lst;
976  if ( expression.isNull() )
977  lst.append( mAttrName );
978  else
979  lst = expression->referencedColumns();
980 
982  .setFlags(( expression && expression->needsGeometry() ) ?
985  .setSubsetOfAttributes( lst, vlayer->pendingFields() ) );
986 
987  // create list of non-null attribute values
988  while ( fit.nextFeature( f ) )
989  {
990  QVariant v = expression ? expression->evaluate( f ) : f.attribute( attrNum );
991  if ( !v.isNull() )
992  values.append( v.toDouble() );
993  }
994  return values;
995 }
996 
998 {
999  if ( mAttrName.isEmpty() )
1000  return;
1001 
1002  setMode( mode );
1003  // Custom classes are not recalculated
1004  if ( mode == Custom )
1005  return;
1006 
1007  if ( nclasses < 1 )
1008  nclasses = 1;
1009 
1010  QList<double> values;
1011  bool valuesLoaded = false;
1012  double minimum;
1013  double maximum;
1014 
1015  int attrNum = vlayer->fieldNameIndex( mAttrName );
1016 
1017  if ( attrNum == -1 )
1018  {
1019  values = getDataValues( vlayer );
1020  if ( values.isEmpty() )
1021  return;
1022 
1023  qSort( values );
1024  minimum = values.first();
1025  maximum = values.last();
1026  valuesLoaded = true;
1027  }
1028  else
1029  {
1030  minimum = vlayer->minimumValue( attrNum ).toDouble();
1031  maximum = vlayer->maximumValue( attrNum ).toDouble();
1032  }
1033 
1034  QgsDebugMsg( QString( "min %1 // max %2" ).arg( minimum ).arg( maximum ) );
1035  QList<double> breaks;
1036  QList<double> labels;
1037  if ( mode == EqualInterval )
1038  {
1039  breaks = _calcEqualIntervalBreaks( minimum, maximum, nclasses );
1040  }
1041  else if ( mode == Pretty )
1042  {
1043  breaks = _calcPrettyBreaks( minimum, maximum, nclasses );
1044  }
1045  else if ( mode == Quantile || mode == Jenks || mode == StdDev )
1046  {
1047  // get values from layer
1048  if ( !valuesLoaded )
1049  {
1050  values = getDataValues( vlayer );
1051  }
1052 
1053  // calculate the breaks
1054  if ( mode == Quantile )
1055  {
1056  breaks = _calcQuantileBreaks( values, nclasses );
1057  }
1058  else if ( mode == Jenks )
1059  {
1060  breaks = _calcJenksBreaks( values, nclasses, minimum, maximum );
1061  }
1062  else if ( mode == StdDev )
1063  {
1064  breaks = _calcStdDevBreaks( values, nclasses, labels );
1065  }
1066  }
1067  else
1068  {
1069  Q_ASSERT( false );
1070  }
1071 
1072  double lower, upper = minimum;
1073  QString label;
1074  deleteAllClasses();
1075 
1076  // "breaks" list contains all values at class breaks plus maximum as last break
1077 
1078  int i = 0;
1079  for ( QList<double>::iterator it = breaks.begin(); it != breaks.end(); ++it, ++i )
1080  {
1081  lower = upper; // upper border from last interval
1082  upper = *it;
1083 
1084  // Label - either StdDev label or default label for a range
1085  if ( mode == StdDev )
1086  {
1087  if ( i == 0 )
1088  {
1089  label = "< " + QString::number( labels[i], 'f', 2 ) + " Std Dev";
1090  }
1091  else if ( i == labels.count() - 1 )
1092  {
1093  label = ">= " + QString::number( labels[i-1], 'f', 2 ) + " Std Dev";
1094  }
1095  else
1096  {
1097  label = QString::number( labels[i-1], 'f', 2 ) + " Std Dev" + " - " + QString::number( labels[i], 'f', 2 ) + " Std Dev";
1098  }
1099  }
1100  else
1101  {
1102  label = mLabelFormat.labelForRange( lower, upper );
1103  }
1104  QgsSymbolV2* newSymbol = mSourceSymbol ? mSourceSymbol->clone() : QgsSymbolV2::defaultSymbol( vlayer->geometryType() );
1105  addClass( QgsRendererRangeV2( lower, upper, newSymbol, label ) );
1106  }
1108 }
1109 
1110 
1112 {
1113  QDomElement symbolsElem = element.firstChildElement( "symbols" );
1114  if ( symbolsElem.isNull() )
1115  return NULL;
1116 
1117  QDomElement rangesElem = element.firstChildElement( "ranges" );
1118  if ( rangesElem.isNull() )
1119  return NULL;
1120 
1121  QgsSymbolV2Map symbolMap = QgsSymbolLayerV2Utils::loadSymbols( symbolsElem );
1123 
1124  QDomElement rangeElem = rangesElem.firstChildElement();
1125  while ( !rangeElem.isNull() )
1126  {
1127  if ( rangeElem.tagName() == "range" )
1128  {
1129  double lowerValue = rangeElem.attribute( "lower" ).toDouble();
1130  double upperValue = rangeElem.attribute( "upper" ).toDouble();
1131  QString symbolName = rangeElem.attribute( "symbol" );
1132  QString label = rangeElem.attribute( "label" );
1133  bool render = rangeElem.attribute( "render", "true" ) != "false";
1134  if ( symbolMap.contains( symbolName ) )
1135  {
1136  QgsSymbolV2* symbol = symbolMap.take( symbolName );
1137  ranges.append( QgsRendererRangeV2( lowerValue, upperValue, symbol, label, render ) );
1138  }
1139  }
1140  rangeElem = rangeElem.nextSiblingElement();
1141  }
1142 
1143  QString attrName = element.attribute( "attr" );
1144 
1145  QgsGraduatedSymbolRendererV2* r = new QgsGraduatedSymbolRendererV2( attrName, ranges );
1146 
1147  // delete symbols if there are any more
1149 
1150  // try to load source symbol (optional)
1151  QDomElement sourceSymbolElem = element.firstChildElement( "source-symbol" );
1152  if ( !sourceSymbolElem.isNull() )
1153  {
1154  QgsSymbolV2Map sourceSymbolMap = QgsSymbolLayerV2Utils::loadSymbols( sourceSymbolElem );
1155  if ( sourceSymbolMap.contains( "0" ) )
1156  {
1157  r->setSourceSymbol( sourceSymbolMap.take( "0" ) );
1158  }
1159  QgsSymbolLayerV2Utils::clearSymbolMap( sourceSymbolMap );
1160  }
1161 
1162  // try to load color ramp (optional)
1163  QDomElement sourceColorRampElem = element.firstChildElement( "colorramp" );
1164  if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( "name" ) == "[source]" )
1165  {
1166  r->setSourceColorRamp( QgsSymbolLayerV2Utils::loadColorRamp( sourceColorRampElem ) );
1167  QDomElement invertedColorRampElem = element.firstChildElement( "invertedcolorramp" );
1168  if ( !invertedColorRampElem.isNull() )
1169  r->setInvertedColorRamp( invertedColorRampElem.attribute( "value" ) == "1" );
1170  }
1171 
1172  // try to load mode
1173  QDomElement modeElem = element.firstChildElement( "mode" );
1174  if ( !modeElem.isNull() )
1175  {
1176  QString modeString = modeElem.attribute( "name" );
1177  if ( modeString == "equal" )
1178  r->setMode( EqualInterval );
1179  else if ( modeString == "quantile" )
1180  r->setMode( Quantile );
1181  else if ( modeString == "jenks" )
1182  r->setMode( Jenks );
1183  else if ( modeString == "stddev" )
1184  r->setMode( StdDev );
1185  else if ( modeString == "pretty" )
1186  r->setMode( Pretty );
1187  }
1188 
1189  QDomElement rotationElem = element.firstChildElement( "rotation" );
1190  if ( !rotationElem.isNull() )
1191  r->setRotationField( rotationElem.attribute( "field" ) );
1192 
1193  QDomElement sizeScaleElem = element.firstChildElement( "sizescale" );
1194  if ( !sizeScaleElem.isNull() )
1195  r->setSizeScaleField( sizeScaleElem.attribute( "field" ) );
1196  r->setScaleMethod( QgsSymbolLayerV2Utils::decodeScaleMethod( sizeScaleElem.attribute( "scalemethod" ) ) );
1197 
1198  QDomElement labelFormatElem = element.firstChildElement( "labelformat" );
1199  if ( ! labelFormatElem.isNull() )
1200  {
1202  labelFormat.setFromDomElement( labelFormatElem );
1203  r->setLabelFormat( labelFormat );
1204  }
1205  // TODO: symbol levels
1206  return r;
1207 }
1208 
1209 QDomElement QgsGraduatedSymbolRendererV2::save( QDomDocument& doc )
1210 {
1211  QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
1212  rendererElem.setAttribute( "type", "graduatedSymbol" );
1213  rendererElem.setAttribute( "symbollevels", ( mUsingSymbolLevels ? "1" : "0" ) );
1214  rendererElem.setAttribute( "attr", mAttrName );
1215 
1216  // ranges
1217  int i = 0;
1219  QDomElement rangesElem = doc.createElement( "ranges" );
1220  QgsRangeList::const_iterator it = mRanges.constBegin();
1221  for ( ; it != mRanges.constEnd(); ++it )
1222  {
1223  const QgsRendererRangeV2& range = *it;
1224  QString symbolName = QString::number( i );
1225  symbols.insert( symbolName, range.symbol() );
1226 
1227  QDomElement rangeElem = doc.createElement( "range" );
1228  rangeElem.setAttribute( "lower", QString::number( range.lowerValue(), 'f' ) );
1229  rangeElem.setAttribute( "upper", QString::number( range.upperValue(), 'f' ) );
1230  rangeElem.setAttribute( "symbol", symbolName );
1231  rangeElem.setAttribute( "label", range.label() );
1232  rangeElem.setAttribute( "render", range.renderState() ? "true" : "false" );
1233  rangesElem.appendChild( rangeElem );
1234  i++;
1235  }
1236 
1237  rendererElem.appendChild( rangesElem );
1238 
1239  // save symbols
1240  QDomElement symbolsElem = QgsSymbolLayerV2Utils::saveSymbols( symbols, "symbols", doc );
1241  rendererElem.appendChild( symbolsElem );
1242 
1243  // save source symbol
1244  if ( mSourceSymbol.data() )
1245  {
1246  QgsSymbolV2Map sourceSymbols;
1247  sourceSymbols.insert( "0", mSourceSymbol.data() );
1248  QDomElement sourceSymbolElem = QgsSymbolLayerV2Utils::saveSymbols( sourceSymbols, "source-symbol", doc );
1249  rendererElem.appendChild( sourceSymbolElem );
1250  }
1251 
1252  // save source color ramp
1253  if ( mSourceColorRamp.data() )
1254  {
1255  QDomElement colorRampElem = QgsSymbolLayerV2Utils::saveColorRamp( "[source]", mSourceColorRamp.data(), doc );
1256  rendererElem.appendChild( colorRampElem );
1257  QDomElement invertedElem = doc.createElement( "invertedcolorramp" );
1258  invertedElem.setAttribute( "value", mInvertedColorRamp );
1259  rendererElem.appendChild( invertedElem );
1260  }
1261 
1262  // save mode
1263  QString modeString;
1264  if ( mMode == EqualInterval )
1265  modeString = "equal";
1266  else if ( mMode == Quantile )
1267  modeString = "quantile";
1268  else if ( mMode == Jenks )
1269  modeString = "jenks";
1270  else if ( mMode == StdDev )
1271  modeString = "stddev";
1272  else if ( mMode == Pretty )
1273  modeString = "pretty";
1274  if ( !modeString.isEmpty() )
1275  {
1276  QDomElement modeElem = doc.createElement( "mode" );
1277  modeElem.setAttribute( "name", modeString );
1278  rendererElem.appendChild( modeElem );
1279  }
1280 
1281  QDomElement rotationElem = doc.createElement( "rotation" );
1282  if ( mRotation.data() )
1283  rotationElem.setAttribute( "field", QgsSymbolLayerV2Utils::fieldOrExpressionFromExpression( mRotation.data() ) );
1284  rendererElem.appendChild( rotationElem );
1285 
1286  QDomElement sizeScaleElem = doc.createElement( "sizescale" );
1287  if ( mSizeScale.data() )
1288  sizeScaleElem.setAttribute( "field", QgsSymbolLayerV2Utils::fieldOrExpressionFromExpression( mSizeScale.data() ) );
1289  sizeScaleElem.setAttribute( "scalemethod", QgsSymbolLayerV2Utils::encodeScaleMethod( mScaleMethod ) );
1290  rendererElem.appendChild( sizeScaleElem );
1291 
1292  QDomElement labelFormatElem = doc.createElement( "labelformat" );
1293  mLabelFormat.saveToDomElement( labelFormatElem );
1294  rendererElem.appendChild( labelFormatElem );
1295 
1296  return rendererElem;
1297 }
1298 
1300 {
1302  int count = ranges().count();
1303  for ( int i = 0; i < count; i++ )
1304  {
1305  const QgsRendererRangeV2& range = ranges()[i];
1306  QPixmap pix = QgsSymbolLayerV2Utils::symbolPreviewPixmap( range.symbol(), iconSize );
1307  lst << qMakePair( range.label(), pix );
1308  }
1309  return lst;
1310 }
1311 
1313 {
1314  Q_UNUSED( scaleDenominator );
1315  QgsLegendSymbolList lst;
1316 
1317  foreach ( const QgsRendererRangeV2& range, mRanges )
1318  {
1319  if ( rule.isEmpty() || range.label() == rule )
1320  {
1321  lst << qMakePair( range.label(), range.symbol() );
1322  }
1323  }
1324  return lst;
1325 }
1326 
1328 {
1329  return mSourceSymbol.data();
1330 }
1332 {
1333  mSourceSymbol.reset( sym );
1334 }
1335 
1337 {
1338  return mSourceColorRamp.data();
1339 }
1340 
1342 {
1343  mSourceColorRamp.reset( ramp );
1344 }
1345 
1347 {
1348  int i = 0;
1349  if ( ramp )
1350  {
1351  setSourceColorRamp( ramp );
1352  setInvertedColorRamp( inverted );
1353  }
1354 
1355  if ( mSourceColorRamp )
1356  {
1357  foreach ( QgsRendererRangeV2 range, mRanges )
1358  {
1359  QgsSymbolV2 *symbol = range.symbol() ? range.symbol()->clone() : 0;
1360  if ( symbol )
1361  {
1362  double colorValue;
1363  if ( inverted )
1364  colorValue = ( mRanges.count() > 1 ? ( double )( mRanges.count() - i - 1 ) / ( mRanges.count() - 1 ) : 0 );
1365  else
1366  colorValue = ( mRanges.count() > 1 ? ( double ) i / ( mRanges.count() - 1 ) : 0 );
1367  symbol->setColor( mSourceColorRamp->color( colorValue ) );
1368  }
1369  updateRangeSymbol( i, symbol );
1370  ++i;
1371  }
1372  }
1373 
1374 }
1375 
1377 {
1378  if ( !sym )
1379  return;
1380 
1381  int i = 0;
1382  foreach ( QgsRendererRangeV2 range, mRanges )
1383  {
1384  QgsSymbolV2 *symbol = sym->clone();
1385  symbol->setColor( range.symbol()->color() );
1386  updateRangeSymbol( i, symbol );
1387  ++i;
1388  }
1389  setSourceSymbol( sym->clone() );
1390 }
1391 
1392 void QgsGraduatedSymbolRendererV2::setRotationField( QString fieldOrExpression )
1393 {
1395 }
1396 
1398 {
1399  return mRotation.data() ? QgsSymbolLayerV2Utils::fieldOrExpressionFromExpression( mRotation.data() ) : QString();
1400 }
1401 
1402 void QgsGraduatedSymbolRendererV2::setSizeScaleField( QString fieldOrExpression )
1403 {
1405 }
1406 
1408 {
1410 }
1411 
1413 {
1415  for ( QgsRangeList::iterator it = mRanges.begin(); it != mRanges.end(); ++it )
1416  {
1417  if ( it->symbol() )
1418  setScaleMethodToSymbol( it->symbol(), scaleMethod );
1419  }
1420 }
1421 
1423 {
1424  return true;
1425 }
1426 
1428 {
1429  bool ok;
1430  int index = key.toInt( &ok );
1431  if ( ok && index >= 0 && index < mRanges.size() )
1432  return mRanges[ index ].renderState();
1433  else
1434  return true;
1435 }
1436 
1438 {
1439  bool ok;
1440  int index = key.toInt( &ok );
1441  if ( ok )
1442  updateRangeRenderState( index, state );
1443 }
1444 
1445 
1447 {
1448  QgsSymbolV2* newSymbol = symbol->clone();
1449  QString label = "0.0 - 0.0";
1450  mRanges.insert( 0, QgsRendererRangeV2( 0.0, 0.0, newSymbol, label ) );
1451 }
1452 
1453 void QgsGraduatedSymbolRendererV2::addClass( double lower, double upper )
1454 {
1455  QgsSymbolV2* newSymbol = mSourceSymbol->clone();
1456  QString label = mLabelFormat.labelForRange( lower, upper );
1457  mRanges.append( QgsRendererRangeV2( lower, upper, newSymbol, label ) );
1458 }
1459 
1461 {
1462  mRanges.append( range );
1463 }
1464 
1466 {
1467  mRanges.removeAt( idx );
1468 }
1469 
1471 {
1472  mRanges.clear();
1473 }
1474 
1476 {
1477  if ( updateRanges && labelFormat != mLabelFormat )
1478  {
1479  for ( QgsRangeList::iterator it = mRanges.begin(); it != mRanges.end(); ++it )
1480  {
1481  it->setLabel( labelFormat.labelForRange( *it ) );
1482  }
1483  }
1485 }
1486 
1487 
1489 {
1490  // Find the minimum size of a class
1491  double minClassRange = 0.0;
1492  for ( QgsRangeList::iterator it = mRanges.begin(); it != mRanges.end(); ++it )
1493  {
1494  double range = it->upperValue() - it->lowerValue();
1495  if ( range <= 0.0 )
1496  continue;
1497  if ( minClassRange == 0.0 || range < minClassRange )
1498  minClassRange = range;
1499  }
1500  if ( minClassRange <= 0.0 )
1501  return;
1502 
1503  // Now set the number of decimal places to ensure no more than 20% error in
1504  // representing this range (up to 10% at upper and lower end)
1505 
1506  int ndp = 10;
1507  double nextDpMinRange = 0.0000000099;
1508  while ( ndp > 0 && nextDpMinRange < minClassRange )
1509  {
1510  ndp--;
1511  nextDpMinRange *= 10.0;
1512  }
1513  mLabelFormat.setPrecision( ndp );
1514  if ( updateRanges ) setLabelFormat( mLabelFormat, true );
1515 }
1516 
1518 {
1519  if ( from < 0 || from >= mRanges.size() || to < 0 || to >= mRanges.size() )
1520  return;
1521  mRanges.move( from, to );
1522 }
1523 
1525 {
1526  return r1 < r2;
1527 }
1528 
1530 {
1531  return !valueLessThan( r1, r2 );
1532 }
1533 
1535 {
1536  QgsDebugMsg( "Entered" );
1537  if ( order == Qt::AscendingOrder )
1538  {
1539  qSort( mRanges.begin(), mRanges.end(), valueLessThan );
1540  }
1541  else
1542  {
1543  qSort( mRanges.begin(), mRanges.end(), valueGreaterThan );
1544  }
1545 }
1546 
1548 {
1549  return QString::localeAwareCompare( r1.label(), r2.label() ) < 0;
1550 }
1551 
1553 {
1554  return !labelLessThan( r1, r2 );
1555 }
1556 
1558 {
1559  if ( order == Qt::AscendingOrder )
1560  {
1561  qSort( mRanges.begin(), mRanges.end(), labelLessThan );
1562  }
1563  else
1564  {
1565  qSort( mRanges.begin(), mRanges.end(), labelGreaterThan );
1566  }
1567 }
1568 
1570 {
1571  if ( renderer->type() == "graduatedSymbol" )
1572  {
1573  return dynamic_cast<QgsGraduatedSymbolRendererV2*>( renderer->clone() );
1574  }
1575  if ( renderer->type() == "pointDisplacement" )
1576  {
1577  const QgsPointDisplacementRenderer* pointDisplacementRenderer = dynamic_cast<const QgsPointDisplacementRenderer*>( renderer );
1578  if ( pointDisplacementRenderer )
1579  return convertFromRenderer( pointDisplacementRenderer->embeddedRenderer() );
1580  }
1581  if ( renderer->type() == "invertedPolygonRenderer" )
1582  {
1583  const QgsInvertedPolygonRenderer* invertedPolygonRenderer = dynamic_cast<const QgsInvertedPolygonRenderer*>( renderer );
1584  if ( invertedPolygonRenderer )
1585  return convertFromRenderer( invertedPolygonRenderer->embeddedRenderer() );
1586  }
1587 
1588  // If not one of the specifically handled renderers, then just grab the symbol from the renderer
1589  // Could have applied this to specific renderer types (singleSymbol, graduatedSymbo)
1590 
1592  QgsSymbolV2List symbols = const_cast<QgsFeatureRendererV2 *>( renderer )->symbols();
1593  if ( symbols.size() > 0 )
1594  {
1595  r->setSourceSymbol( symbols.at( 0 )->clone() );
1596  }
1597 
1598  return r;
1599 }
QMap< QString, QgsSymbolV2 * > QgsSymbolV2Map
Definition: qgsrendererv2.h:39
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:87
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:47
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)
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
Definition: qgsexpression.h:94
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.
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:38
static QList< double > _calcPrettyBreaks(double minimum, double maximum, int classes)
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: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 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:234
double rendererScale() const
virtual QgsSymbolV2 * clone() const =0
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())
Query the provider for features specified in request.
virtual QgsFeatureRendererV2 * clone() const override
bool updateRangeRenderState(int rangeIndex, bool render)
QString labelForRange(double lower, double upper) const
void setSizeScaleField(QString fieldOrExpression)
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
Container of fields for a vector layer.
Definition: qgsfield.h:172
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:418
virtual bool legendSymbolItemChecked(QString key) override
item in symbology was checked
void setWidth(double width)
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:81
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
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
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
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)
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)
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)
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:230
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
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:155
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
const QgsFields & pendingFields() const
returns field list in the to-be-committed state
virtual QList< QString > usedAttributes() override
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.
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:42
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