QGIS API Documentation  2.7.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 {
42 }
43 
44 QgsRendererRangeV2::QgsRendererRangeV2( double lowerValue, double upperValue, QgsSymbolV2* symbol, QString label, bool render )
45  : mLowerValue( lowerValue )
46  , mUpperValue( upperValue )
47  , mSymbol( symbol )
48  , mLabel( label )
49  , mRender( render )
50 {
51 }
52 
54  : mLowerValue( range.mLowerValue )
55  , mUpperValue( range.mUpperValue )
56  , mSymbol( range.mSymbol.data() ? range.mSymbol->clone() : NULL )
57  , mLabel( range.mLabel )
58  , mRender( range.mRender )
59 {
60 }
61 
62 // cpy and swap idiom, note that the cpy is done with 'pass by value'
64 {
65  swap( range );
66  return *this;
67 }
68 
70 {
71  return
72  lowerValue() < other.lowerValue() ||
73  ( lowerValue() == other.lowerValue() && upperValue() < other.upperValue() );
74 }
75 
76 
78 {
79  qSwap( mLowerValue, other.mLowerValue );
80  qSwap( mUpperValue, other.mUpperValue );
81  qSwap( mSymbol, other.mSymbol );
82  std::swap( mLabel, other.mLabel );
83 }
84 
86 {
87  return mLowerValue;
88 }
89 
91 {
92  return mUpperValue;
93 }
94 
96 {
97  return mSymbol.data();
98 }
99 
101 {
102  return mLabel;
103 }
104 
106 {
107  if ( mSymbol.data() != s ) mSymbol.reset( s );
108 }
109 
110 void QgsRendererRangeV2::setLabel( QString label )
111 {
112  mLabel = label;
113 }
114 
115 void QgsRendererRangeV2::setUpperValue( double upperValue )
116 {
118 }
119 
120 void QgsRendererRangeV2::setLowerValue( double lowerValue )
121 {
123 }
124 
126 {
127  return mRender;
128 }
129 
131 {
132  mRender = render;
133 }
134 
136 {
137  return QString( "%1 - %2::%3::%4\n" ).arg( mLowerValue ).arg( mUpperValue ).arg( mLabel ).arg( mSymbol.data() ? mSymbol->dump() : "(no symbol)" );
138 }
139 
140 void QgsRendererRangeV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
141 {
142  if ( !mSymbol.data() || props.value( "attribute", "" ).isEmpty() )
143  return;
144 
145  QString attrName = props[ "attribute" ];
146 
147  QDomElement ruleElem = doc.createElement( "se:Rule" );
148  element.appendChild( ruleElem );
149 
150  QDomElement nameElem = doc.createElement( "se:Name" );
151  nameElem.appendChild( doc.createTextNode( mLabel ) );
152  ruleElem.appendChild( nameElem );
153 
154  QDomElement descrElem = doc.createElement( "se:Description" );
155  QDomElement titleElem = doc.createElement( "se:Title" );
156  QString descrStr = QString( "range: %1 - %2" ).arg( mLowerValue ).arg( mUpperValue );
157  titleElem.appendChild( doc.createTextNode( !mLabel.isEmpty() ? mLabel : descrStr ) );
158  descrElem.appendChild( titleElem );
159  ruleElem.appendChild( descrElem );
160 
161  // create the ogc:Filter for the range
162  QString filterFunc = QString( "%1 > %2 AND %1 <= %3" )
163  .arg( attrName.replace( "\"", "\"\"" ) )
164  .arg( mLowerValue ).arg( mUpperValue );
165  QgsSymbolLayerV2Utils::createFunctionElement( doc, ruleElem, filterFunc );
166 
167  mSymbol->toSld( doc, ruleElem, props );
168 }
169 
171 
174 
176  mFormat( " %1 - %2 " ),
177  mPrecision( 4 ),
178  mTrimTrailingZeroes( false ),
179  mNumberScale( 1.0 ),
180  mNumberSuffix( "" ),
181  mReTrailingZeroes( "[.,]?0*$" ),
182  mReNegativeZero( "^\\-0(?:[.,]0*)?$" )
183 {
184 }
185 
186 QgsRendererRangeV2LabelFormat::QgsRendererRangeV2LabelFormat( QString format, int precision, bool trimTrailingZeroes ):
187  mReTrailingZeroes( "[.,]?0*$" ),
188  mReNegativeZero( "^\\-0(?:[.,]0*)?$" )
189 {
190  setFormat( format );
191  setPrecision( precision );
192  setTrimTrailingZeroes( trimTrailingZeroes );
193 }
194 
195 
197 {
198  return
199  format() == other.format() &&
200  precision() == other.precision() &&
202 }
203 
205 {
206  return !( *this == other );
207 }
208 
210 {
211  // Limit the range of decimal places to a reasonable range
212  precision = qBound( MinPrecision, precision, MaxPrecision );
214  mNumberScale = 1.0;
215  mNumberSuffix = "";
216  while ( precision < 0 )
217  {
218  precision++;
219  mNumberScale /= 10.0;
220  mNumberSuffix.append( '0' );
221  }
222 }
223 
225 {
226  return labelForRange( range.lowerValue(), range.upperValue() );
227 }
228 
229 QString QgsRendererRangeV2LabelFormat::formatNumber( double value ) const
230 {
231  if ( mPrecision > 0 )
232  {
233  QString valueStr = QString::number( value, 'f', mPrecision );
234  if ( mTrimTrailingZeroes )
235  valueStr = valueStr.replace( mReTrailingZeroes, "" );
236  if ( mReNegativeZero.exactMatch( valueStr ) )
237  valueStr = valueStr.mid( 1 );
238  return valueStr;
239  }
240  else
241  {
242  QString valueStr = QString::number( value * mNumberScale, 'f', 0 );
243  if ( valueStr == "-0" )
244  valueStr = "0";
245  if ( valueStr != "0" )
246  valueStr = valueStr + mNumberSuffix;
247  return valueStr;
248  }
249 }
250 
251 QString QgsRendererRangeV2LabelFormat::labelForRange( double lower, double upper ) const
252 {
253  QString lowerStr = formatNumber( lower );
254  QString upperStr = formatNumber( upper );
255 
256  QString legend( mFormat );
257  return legend.replace( "%1", lowerStr ).replace( "%2", upperStr );
258 }
259 
261 {
262  mFormat = element.attribute( "format",
263  element.attribute( "prefix", " " ) + "%1" +
264  element.attribute( "separator", " - " ) + "%2" +
265  element.attribute( "suffix", " " )
266  );
267  setPrecision( element.attribute( "decimalplaces", "4" ).toInt() );
268  mTrimTrailingZeroes = element.attribute( "trimtrailingzeroes", "false" ) == "true";
269 }
270 
272 {
273  element.setAttribute( "format", mFormat );
274  element.setAttribute( "decimalplaces", mPrecision );
275  element.setAttribute( "trimtrailingzeroes", mTrimTrailingZeroes ? "true" : "false" );
276 }
277 
279 
281  : QgsFeatureRendererV2( "graduatedSymbol" )
282  , mAttrName( attrName )
283  , mRanges( ranges )
284  , mMode( Custom )
285  , mInvertedColorRamp( false )
286  , mScaleMethod( DEFAULT_SCALE_METHOD )
287 {
288  // TODO: check ranges for sanity (NULL symbols, invalid ranges)
289 }
290 
292 {
293  mRanges.clear(); // should delete all the symbols
294 }
295 
297 {
298  for ( QgsRangeList::iterator it = mRanges.begin(); it != mRanges.end(); ++it )
299  {
300  if ( it->lowerValue() <= value && it->upperValue() >= value )
301  {
302  if ( it->renderState() || mCounting )
303  return it->symbol();
304  else
305  return NULL;
306  }
307  }
308  // the value is out of the range: return NULL instead of symbol
309  return NULL;
310 }
311 
313 {
314  QgsSymbolV2* symbol = originalSymbolForFeature( feature );
315  if ( symbol == NULL )
316  return NULL;
317 
318  if ( !mRotation.data() && !mSizeScale.data() )
319  return symbol; // no data-defined rotation/scaling - just return the symbol
320 
321  // find out rotation, size scale
322  const double rotation = mRotation.data() ? mRotation->evaluate( feature ).toDouble() : 0;
323  const double sizeScale = mSizeScale.data() ? mSizeScale->evaluate( feature ).toDouble() : 1.;
324 
325  // take a temporary symbol (or create it if doesn't exist)
326  QgsSymbolV2* tempSymbol = mTempSymbols[symbol];
327 
328  // modify the temporary symbol and return it
329  if ( tempSymbol->type() == QgsSymbolV2::Marker )
330  {
331  QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( tempSymbol );
332  if ( mRotation.data() ) markerSymbol->setAngle( rotation );
333  markerSymbol->setSize( sizeScale * static_cast<QgsMarkerSymbolV2*>( symbol )->size() );
334  markerSymbol->setScaleMethod( mScaleMethod );
335  }
336  else if ( tempSymbol->type() == QgsSymbolV2::Line )
337  {
338  QgsLineSymbolV2* lineSymbol = static_cast<QgsLineSymbolV2*>( tempSymbol );
339  lineSymbol->setWidth( sizeScale * static_cast<QgsLineSymbolV2*>( symbol )->width() );
340  }
341  return tempSymbol;
342 }
343 
345 {
346  const QgsAttributes& attrs = feature.attributes();
347  QVariant value;
348  if ( mAttrNum < 0 || mAttrNum >= attrs.count() )
349  {
350  value = mExpression->evaluate( &feature );
351  }
352  else
353  {
354  value = attrs[mAttrNum];
355  }
356 
357  // Null values should not be categorized
358  if ( value.isNull() )
359  return NULL;
360 
361  // find the right category
362  return symbolForValue( value.toDouble() );
363 }
364 
366 {
367  mCounting = context.rendererScale() == 0.0;
368 
369  // find out classification attribute index from name
370  mAttrNum = fields.fieldNameIndex( mAttrName );
371 
372  if ( mAttrNum == -1 )
373  {
374  mExpression.reset( new QgsExpression( mAttrName ) );
375  mExpression->prepare( fields );
376  }
377 
378  QgsRangeList::iterator it = mRanges.begin();
379  for ( ; it != mRanges.end(); ++it )
380  {
381  if ( !it->symbol() )
382  continue;
383 
384  it->symbol()->startRender( context, &fields );
385 
386  if ( mRotation.data() || mSizeScale.data() )
387  {
388  QgsSymbolV2* tempSymbol = it->symbol()->clone();
389  tempSymbol->setRenderHints(( mRotation.data() ? QgsSymbolV2::DataDefinedRotation : 0 ) |
391  tempSymbol->startRender( context, &fields );
392  mTempSymbols[ it->symbol()] = tempSymbol;
393  }
394  }
395 }
396 
398 {
399  QgsRangeList::iterator it = mRanges.begin();
400  for ( ; it != mRanges.end(); ++it )
401  {
402  if ( !it->symbol() )
403  continue;
404 
405  it->symbol()->stopRender( context );
406  }
407 
408  // cleanup mTempSymbols
409  QHash<QgsSymbolV2*, QgsSymbolV2*>::iterator it2 = mTempSymbols.begin();
410  for ( ; it2 != mTempSymbols.end(); ++it2 )
411  {
412  it2.value()->stopRender( context );
413  delete it2.value();
414  }
415  mTempSymbols.clear();
416 }
417 
419 {
420  QSet<QString> attributes;
421 
422  // mAttrName can contain either attribute name or an expression.
423  // Sometimes it is not possible to distinguish between those two,
424  // e.g. "a - b" can be both a valid attribute name or expression.
425  // Since we do not have access to fields here, try both options.
426  attributes << mAttrName;
427 
428  QgsExpression testExpr( mAttrName );
429  if ( !testExpr.hasParserError() )
430  attributes.unite( testExpr.referencedColumns().toSet() );
431 
432  if ( mRotation.data() ) attributes.unite( mRotation->referencedColumns().toSet() );
433  if ( mSizeScale.data() ) attributes.unite( mSizeScale->referencedColumns().toSet() );
434 
435  QgsRangeList::const_iterator range_it = mRanges.constBegin();
436  for ( ; range_it != mRanges.constEnd(); ++range_it )
437  {
438  QgsSymbolV2* symbol = range_it->symbol();
439  if ( symbol )
440  {
441  attributes.unite( symbol->usedAttributes() );
442  }
443  }
444  return attributes.toList();
445 }
446 
448 {
449  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
450  return false;
451  mRanges[rangeIndex].setSymbol( symbol );
452  return true;
453 }
454 
455 bool QgsGraduatedSymbolRendererV2::updateRangeLabel( int rangeIndex, QString label )
456 {
457  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
458  return false;
459  mRanges[rangeIndex].setLabel( label );
460  return true;
461 }
462 
463 bool QgsGraduatedSymbolRendererV2::updateRangeUpperValue( int rangeIndex, double value )
464 {
465  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
466  return false;
467  QgsRendererRangeV2 &range = mRanges[rangeIndex];
468  bool isDefaultLabel = range.label() == mLabelFormat.labelForRange( range );
469  range.setUpperValue( value );
470  if ( isDefaultLabel ) range.setLabel( mLabelFormat.labelForRange( range ) );
471  return true;
472 }
473 
474 bool QgsGraduatedSymbolRendererV2::updateRangeLowerValue( int rangeIndex, double value )
475 {
476  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
477  return false;
478  QgsRendererRangeV2 &range = mRanges[rangeIndex];
479  bool isDefaultLabel = range.label() == mLabelFormat.labelForRange( range );
480  range.setLowerValue( value );
481  if ( isDefaultLabel ) range.setLabel( mLabelFormat.labelForRange( range ) );
482  return true;
483 }
484 
486 {
487  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
488  return false;
489  mRanges[rangeIndex].setRenderState( value );
490  return true;
491 }
492 
494 {
495  QString s = QString( "GRADUATED: attr %1\n" ).arg( mAttrName );
496  for ( int i = 0; i < mRanges.count(); i++ )
497  s += mRanges[i].dump();
498  return s;
499 }
500 
502 {
504  r->setMode( mMode );
505  if ( mSourceSymbol.data() )
506  r->setSourceSymbol( mSourceSymbol->clone() );
507  if ( mSourceColorRamp.data() )
508  {
509  r->setSourceColorRamp( mSourceColorRamp->clone() );
511  }
515  r->setScaleMethod( scaleMethod() );
516  r->setLabelFormat( labelFormat() );
517  return r;
518 }
519 
520 void QgsGraduatedSymbolRendererV2::toSld( QDomDocument& doc, QDomElement &element ) const
521 {
522  QgsStringMap props;
523  props[ "attribute" ] = mAttrName;
524  if ( mRotation.data() )
525  props[ "angle" ] = mRotation->expression();
526  if ( mSizeScale.data() )
527  props[ "scale" ] = mSizeScale->expression();
528 
529  // create a Rule for each range
530  for ( QgsRangeList::const_iterator it = mRanges.constBegin(); it != mRanges.constEnd(); ++it )
531  {
532  QgsStringMap catProps( props );
533  it->toSld( doc, element, catProps );
534  }
535 }
536 
538 {
539  QgsSymbolV2List lst;
540  for ( int i = 0; i < mRanges.count(); i++ )
541  lst.append( mRanges[i].symbol() );
542  return lst;
543 }
544 
545 static QList<double> _calcEqualIntervalBreaks( double minimum, double maximum, int classes )
546 {
547 
548  // Equal interval algorithm
549  //
550  // Returns breaks based on dividing the range ('minimum' to 'maximum')
551  // into 'classes' parts.
552 
553  double step = ( maximum - minimum ) / classes;
554 
555  QList<double> breaks;
556  double value = minimum;
557  for ( int i = 0; i < classes; i++ )
558  {
559  value += step;
560  breaks.append( value );
561  }
562 
563  // floating point arithmetics is not precise:
564  // set the last break to be exactly maximum so we do not miss it
565  breaks[classes-1] = maximum;
566 
567  return breaks;
568 }
569 
570 static QList<double> _calcQuantileBreaks( QList<double> values, int classes )
571 {
572  // q-th quantile of a data set:
573  // value where q fraction of data is below and (1-q) fraction is above this value
574  // Xq = (1 - r) * X_NI1 + r * X_NI2
575  // NI1 = (int) (q * (n+1))
576  // NI2 = NI1 + 1
577  // r = q * (n+1) - (int) (q * (n+1))
578  // (indices of X: 1...n)
579 
580  // sort the values first
581  qSort( values );
582 
583  QList<double> breaks;
584 
585  // If there are no values to process: bail out
586  if ( !values.count() )
587  return breaks;
588 
589  int n = values.count();
590  double Xq = n > 0 ? values[0] : 0.0;
591 
592  for ( int i = 1; i < classes; i++ )
593  {
594  if ( n > 1 )
595  {
596  double q = i / ( double ) classes;
597  double a = q * ( n - 1 );
598  int aa = ( int )( a );
599 
600  double r = a - aa;
601  Xq = ( 1 - r ) * values[aa] + r * values[aa+1];
602  }
603  breaks.append( Xq );
604  }
605 
606  breaks.append( values[ n-1 ] );
607 
608  return breaks;
609 }
610 
611 static QList<double> _calcPrettyBreaks( double minimum, double maximum, int classes )
612 {
613 
614  // C++ implementation of R's pretty algorithm
615  // Based on code for determining optimal tick placement for statistical graphics
616  // from the R statistical programming language.
617  // Code ported from R implementation from 'labeling' R package
618  //
619  // Computes a sequence of about 'classes' equally spaced round values
620  // which cover the range of values from 'minimum' to 'maximum'.
621  // The values are chosen so that they are 1, 2 or 5 times a power of 10.
622 
623  QList<double> breaks;
624  if ( classes < 1 )
625  {
626  breaks.append( maximum );
627  return breaks;
628  }
629 
630  int minimumCount = ( int ) classes / 3;
631  double shrink = 0.75;
632  double highBias = 1.5;
633  double adjustBias = 0.5 + 1.5 * highBias;
634  int divisions = classes;
635  double h = highBias;
636  double cell;
637  int U;
638  bool small = false;
639  double dx = maximum - minimum;
640 
641  if ( dx == 0 && maximum == 0 )
642  {
643  cell = 1.0;
644  small = true;
645  U = 1;
646  }
647  else
648  {
649  cell = qMax( qAbs( minimum ), qAbs( maximum ) );
650  if ( adjustBias >= 1.5 * h + 0.5 )
651  {
652  U = 1 + ( 1.0 / ( 1 + h ) );
653  }
654  else
655  {
656  U = 1 + ( 1.5 / ( 1 + adjustBias ) );
657  }
658  small = dx < ( cell * U * qMax( 1, divisions ) * 1e-07 * 3.0 );
659  }
660 
661  if ( small )
662  {
663  if ( cell > 10 )
664  {
665  cell = 9 + cell / 10;
666  cell = cell * shrink;
667  }
668  if ( minimumCount > 1 )
669  {
670  cell = cell / minimumCount;
671  }
672  }
673  else
674  {
675  cell = dx;
676  if ( divisions > 1 )
677  {
678  cell = cell / divisions;
679  }
680  }
681  if ( cell < 20 * 1e-07 )
682  {
683  cell = 20 * 1e-07;
684  }
685 
686  double base = pow( 10.0, floor( log10( cell ) ) );
687  double unit = base;
688  if (( 2 * base ) - cell < h *( cell - unit ) )
689  {
690  unit = 2.0 * base;
691  if (( 5 * base ) - cell < adjustBias *( cell - unit ) )
692  {
693  unit = 5.0 * base;
694  if (( 10.0 * base ) - cell < h *( cell - unit ) )
695  {
696  unit = 10.0 * base;
697  }
698  }
699  }
700  // Maybe used to correct for the epsilon here??
701  int start = floor( minimum / unit + 1e-07 );
702  int end = ceil( maximum / unit - 1e-07 );
703 
704  // Extend the range out beyond the data. Does this ever happen??
705  while ( start * unit > minimum + ( 1e-07 * unit ) )
706  {
707  start = start - 1;
708  }
709  while ( end * unit < maximum - ( 1e-07 * unit ) )
710  {
711  end = end + 1;
712  }
713  QgsDebugMsg( QString( "pretty classes: %1" ).arg( end ) );
714 
715  // If we don't have quite enough labels, extend the range out
716  // to make more (these labels are beyond the data :( )
717  int k = floor( 0.5 + end - start );
718  if ( k < minimumCount )
719  {
720  k = minimumCount - k;
721  if ( start >= 0 )
722  {
723  end = end + k / 2;
724  start = start - k / 2 + k % 2;
725  }
726  else
727  {
728  start = start - k / 2;
729  end = end + k / 2 + k % 2;
730  }
731  }
732  double minimumBreak = start * unit;
733  //double maximumBreak = end * unit;
734  int count = end - start;
735 
736  for ( int i = 1; i < count + 1; i++ )
737  {
738  breaks.append( minimumBreak + i * unit );
739  }
740 
741  if ( breaks.isEmpty() )
742  return breaks;
743 
744  if ( breaks.first() < minimum )
745  {
746  breaks[0] = minimum;
747  }
748  if ( breaks.last() > maximum )
749  {
750  breaks[breaks.count()-1] = maximum;
751  }
752 
753  return breaks;
754 } // _calcPrettyBreaks
755 
756 
757 static QList<double> _calcStdDevBreaks( QList<double> values, int classes, QList<double> &labels )
758 {
759 
760  // C++ implementation of the standard deviation class interval algorithm
761  // as implemented in the 'classInt' package available for the R statistical
762  // prgramming language.
763 
764  // Returns breaks based on '_calcPrettyBreaks' of the centred and scaled
765  // values of 'values', and may have a number of classes different from 'classes'.
766 
767  // If there are no values to process: bail out
768  if ( !values.count() )
769  return QList<double>();
770 
771  double mean = 0.0;
772  double stdDev = 0.0;
773  int n = values.count();
774  double minimum = values[0];
775  double maximum = values[0];
776 
777  for ( int i = 0; i < n; i++ )
778  {
779  mean += values[i];
780  minimum = qMin( values[i], minimum ); // could use precomputed max and min
781  maximum = qMax( values[i], maximum ); // but have to go through entire list anyway
782  }
783  mean = mean / ( double ) n;
784 
785  double sd = 0.0;
786  for ( int i = 0; i < n; i++ )
787  {
788  sd = values[i] - mean;
789  stdDev += sd * sd;
790  }
791  stdDev = sqrt( stdDev / n );
792 
793  QList<double> breaks = _calcPrettyBreaks(( minimum - mean ) / stdDev, ( maximum - mean ) / stdDev, classes );
794  for ( int i = 0; i < breaks.count(); i++ )
795  {
796  labels.append( breaks[i] );
797  breaks[i] = ( breaks[i] * stdDev ) + mean;
798  }
799 
800  return breaks;
801 } // _calcStdDevBreaks
802 
803 static QList<double> _calcJenksBreaks( QList<double> values, int classes,
804  double minimum, double maximum,
805  int maximumSize = 1000 )
806 {
807  // Jenks Optimal (Natural Breaks) algorithm
808  // Based on the Jenks algorithm from the 'classInt' package available for
809  // the R statistical prgramming language, and from Python code from here:
810  // http://danieljlewis.org/2010/06/07/jenks-natural-breaks-algorithm-in-python/
811  // and is based on a JAVA and Fortran code available here:
812  // https://stat.ethz.ch/pipermail/r-sig-geo/2006-March/000811.html
813 
814  // Returns class breaks such that classes are internally homogeneous while
815  // assuring heterogeneity among classes.
816 
817  if ( !values.count() )
818  return QList<double>();
819 
820  if ( classes <= 1 )
821  {
822  return QList<double>() << maximum;
823  }
824 
825  if ( classes >= values.size() )
826  {
827  return values;
828  }
829 
830  QVector<double> sample;
831 
832  // if we have lots of values, we need to take a random sample
833  if ( values.size() > maximumSize )
834  {
835  // for now, sample at least maximumSize values or a 10% sample, whichever
836  // is larger. This will produce a more representative sample for very large
837  // layers, but could end up being computationally intensive...
838 
839  qsrand( time( 0 ) );
840 
841  sample.resize( qMax( maximumSize, values.size() / 10 ) );
842 
843  QgsDebugMsg( QString( "natural breaks (jenks) sample size: %1" ).arg( sample.size() ) );
844  QgsDebugMsg( QString( "values:%1" ).arg( values.size() ) );
845 
846  sample[ 0 ] = minimum;
847  sample[ 1 ] = maximum;;
848  for ( int i = 2; i < sample.size(); i++ )
849  {
850  // pick a random integer from 0 to n
851  double r = qrand();
852  int j = floor( r / RAND_MAX * ( values.size() - 1 ) );
853  sample[ i ] = values[ j ];
854  }
855  }
856  else
857  {
858  sample = values.toVector();
859  }
860 
861  int n = sample.size();
862 
863  // sort the sample values
864  qSort( sample );
865 
866  QVector< QVector<int> > matrixOne( n + 1 );
867  QVector< QVector<double> > matrixTwo( n + 1 );
868 
869  for ( int i = 0; i <= n; i++ )
870  {
871  matrixOne[i].resize( classes + 1 );
872  matrixTwo[i].resize( classes + 1 );
873  }
874 
875  for ( int i = 1; i <= classes; i++ )
876  {
877  matrixOne[0][i] = 1;
878  matrixOne[1][i] = 1;
879  matrixTwo[0][i] = 0.0;
880  for ( int j = 2; j <= n; j++ )
881  {
882  matrixTwo[j][i] = std::numeric_limits<double>::max();
883  }
884  }
885 
886  for ( int l = 2; l <= n; l++ )
887  {
888  double s1 = 0.0;
889  double s2 = 0.0;
890  int w = 0;
891 
892  double v = 0.0;
893 
894  for ( int m = 1; m <= l; m++ )
895  {
896  int i3 = l - m + 1;
897 
898  double val = sample[ i3 - 1 ];
899 
900  s2 += val * val;
901  s1 += val;
902  w++;
903 
904  v = s2 - ( s1 * s1 ) / ( double ) w;
905  int i4 = i3 - 1;
906  if ( i4 != 0 )
907  {
908  for ( int j = 2; j <= classes; j++ )
909  {
910  if ( matrixTwo[l][j] >= v + matrixTwo[i4][j - 1] )
911  {
912  matrixOne[l][j] = i4;
913  matrixTwo[l][j] = v + matrixTwo[i4][j - 1];
914  }
915  }
916  }
917  }
918  matrixOne[l][1] = 1;
919  matrixTwo[l][1] = v;
920  }
921 
922  QVector<double> breaks( classes );
923  breaks[classes-1] = sample[n-1];
924 
925  for ( int j = classes, k = n; j >= 2; j-- )
926  {
927  int id = matrixOne[k][j] - 1;
928  breaks[j - 2] = sample[id];
929  k = matrixOne[k][j] - 1;
930  }
931 
932  return breaks.toList();
933 } //_calcJenksBreaks
934 
935 
937  QgsVectorLayer* vlayer,
938  QString attrName,
939  int classes,
940  Mode mode,
941  QgsSymbolV2* symbol,
942  QgsVectorColorRampV2* ramp,
943  bool inverted,
945 )
946 {
948  QgsGraduatedSymbolRendererV2* r = new QgsGraduatedSymbolRendererV2( attrName, ranges );
949  r->setSourceSymbol( symbol->clone() );
950  r->setSourceColorRamp( ramp->clone() );
951  r->setInvertedColorRamp( inverted );
952  r->setMode( mode );
953  r->setLabelFormat( labelFormat );
954  r->updateClasses( vlayer, mode, classes );
955  return r;
956 }
957 
959 {
960  QList<double> values;
961  QScopedPointer<QgsExpression> expression;
962  int attrNum = vlayer->fieldNameIndex( mAttrName );
963 
964  if ( attrNum == -1 )
965  {
966  // try to use expression
967  expression.reset( new QgsExpression( mAttrName ) );
968  if ( expression->hasParserError() || !expression->prepare( vlayer->pendingFields() ) )
969  return values; // should have a means to report errors
970  }
971 
972  QgsFeature f;
973  QStringList lst;
974  if ( expression.isNull() )
975  lst.append( mAttrName );
976  else
977  lst = expression->referencedColumns();
978 
980  .setFlags(( expression && expression->needsGeometry() ) ?
983  .setSubsetOfAttributes( lst, vlayer->pendingFields() ) );
984 
985  // create list of non-null attribute values
986  while ( fit.nextFeature( f ) )
987  {
988  QVariant v = expression ? expression->evaluate( f ) : f.attribute( attrNum );
989  if ( !v.isNull() )
990  values.append( v.toDouble() );
991  }
992  return values;
993 }
994 
996 {
997  if ( mAttrName.isEmpty() )
998  return;
999 
1000  setMode( mode );
1001  // Custom classes are not recalculated
1002  if ( mode == Custom )
1003  return;
1004 
1005  if ( nclasses < 1 )
1006  nclasses = 1;
1007 
1008  QList<double> values;
1009  bool valuesLoaded = false;
1010  double minimum;
1011  double maximum;
1012 
1013  int attrNum = vlayer->fieldNameIndex( mAttrName );
1014 
1015  if ( attrNum == -1 )
1016  {
1017  values = getDataValues( vlayer );
1018  if ( values.isEmpty() )
1019  return;
1020 
1021  qSort( values );
1022  minimum = values.first();
1023  maximum = values.last();
1024  valuesLoaded = true;
1025  }
1026  else
1027  {
1028  minimum = vlayer->minimumValue( attrNum ).toDouble();
1029  maximum = vlayer->maximumValue( attrNum ).toDouble();
1030  }
1031 
1032  QgsDebugMsg( QString( "min %1 // max %2" ).arg( minimum ).arg( maximum ) );
1033  QList<double> breaks;
1034  QList<double> labels;
1035  if ( mode == EqualInterval )
1036  {
1037  breaks = _calcEqualIntervalBreaks( minimum, maximum, nclasses );
1038  }
1039  else if ( mode == Pretty )
1040  {
1041  breaks = _calcPrettyBreaks( minimum, maximum, nclasses );
1042  }
1043  else if ( mode == Quantile || mode == Jenks || mode == StdDev )
1044  {
1045  // get values from layer
1046  if ( !valuesLoaded )
1047  {
1048  values = getDataValues( vlayer );
1049  }
1050 
1051  // calculate the breaks
1052  if ( mode == Quantile )
1053  {
1054  breaks = _calcQuantileBreaks( values, nclasses );
1055  }
1056  else if ( mode == Jenks )
1057  {
1058  breaks = _calcJenksBreaks( values, nclasses, minimum, maximum );
1059  }
1060  else if ( mode == StdDev )
1061  {
1062  breaks = _calcStdDevBreaks( values, nclasses, labels );
1063  }
1064  }
1065  else
1066  {
1067  Q_ASSERT( false );
1068  }
1069 
1070  double lower, upper = minimum;
1071  QString label;
1072  deleteAllClasses();
1073 
1074  // "breaks" list contains all values at class breaks plus maximum as last break
1075 
1076  int i = 0;
1077  for ( QList<double>::iterator it = breaks.begin(); it != breaks.end(); ++it, ++i )
1078  {
1079  lower = upper; // upper border from last interval
1080  upper = *it;
1081 
1082  // Label - either StdDev label or default label for a range
1083  if ( mode == StdDev )
1084  {
1085  if ( i == 0 )
1086  {
1087  label = "< " + QString::number( labels[i], 'f', 2 ) + " Std Dev";
1088  }
1089  else if ( i == labels.count() - 1 )
1090  {
1091  label = ">= " + QString::number( labels[i-1], 'f', 2 ) + " Std Dev";
1092  }
1093  else
1094  {
1095  label = QString::number( labels[i-1], 'f', 2 ) + " Std Dev" + " - " + QString::number( labels[i], 'f', 2 ) + " Std Dev";
1096  }
1097  }
1098  else
1099  {
1100  label = mLabelFormat.labelForRange( lower, upper );
1101  }
1102  QgsSymbolV2* newSymbol = mSourceSymbol ? mSourceSymbol->clone() : QgsSymbolV2::defaultSymbol( vlayer->geometryType() );
1103  addClass( QgsRendererRangeV2( lower, upper, newSymbol, label ) );
1104  }
1106 }
1107 
1108 
1110 {
1111  QDomElement symbolsElem = element.firstChildElement( "symbols" );
1112  if ( symbolsElem.isNull() )
1113  return NULL;
1114 
1115  QDomElement rangesElem = element.firstChildElement( "ranges" );
1116  if ( rangesElem.isNull() )
1117  return NULL;
1118 
1119  QgsSymbolV2Map symbolMap = QgsSymbolLayerV2Utils::loadSymbols( symbolsElem );
1121 
1122  QDomElement rangeElem = rangesElem.firstChildElement();
1123  while ( !rangeElem.isNull() )
1124  {
1125  if ( rangeElem.tagName() == "range" )
1126  {
1127  double lowerValue = rangeElem.attribute( "lower" ).toDouble();
1128  double upperValue = rangeElem.attribute( "upper" ).toDouble();
1129  QString symbolName = rangeElem.attribute( "symbol" );
1130  QString label = rangeElem.attribute( "label" );
1131  bool render = rangeElem.attribute( "render", "true" ) != "false";
1132  if ( symbolMap.contains( symbolName ) )
1133  {
1134  QgsSymbolV2* symbol = symbolMap.take( symbolName );
1135  ranges.append( QgsRendererRangeV2( lowerValue, upperValue, symbol, label, render ) );
1136  }
1137  }
1138  rangeElem = rangeElem.nextSiblingElement();
1139  }
1140 
1141  QString attrName = element.attribute( "attr" );
1142 
1143  QgsGraduatedSymbolRendererV2* r = new QgsGraduatedSymbolRendererV2( attrName, ranges );
1144 
1145  // delete symbols if there are any more
1147 
1148  // try to load source symbol (optional)
1149  QDomElement sourceSymbolElem = element.firstChildElement( "source-symbol" );
1150  if ( !sourceSymbolElem.isNull() )
1151  {
1152  QgsSymbolV2Map sourceSymbolMap = QgsSymbolLayerV2Utils::loadSymbols( sourceSymbolElem );
1153  if ( sourceSymbolMap.contains( "0" ) )
1154  {
1155  r->setSourceSymbol( sourceSymbolMap.take( "0" ) );
1156  }
1157  QgsSymbolLayerV2Utils::clearSymbolMap( sourceSymbolMap );
1158  }
1159 
1160  // try to load color ramp (optional)
1161  QDomElement sourceColorRampElem = element.firstChildElement( "colorramp" );
1162  if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( "name" ) == "[source]" )
1163  {
1164  r->setSourceColorRamp( QgsSymbolLayerV2Utils::loadColorRamp( sourceColorRampElem ) );
1165  QDomElement invertedColorRampElem = element.firstChildElement( "invertedcolorramp" );
1166  if ( !invertedColorRampElem.isNull() )
1167  r->setInvertedColorRamp( invertedColorRampElem.attribute( "value" ) == "1" );
1168  }
1169 
1170  // try to load mode
1171  QDomElement modeElem = element.firstChildElement( "mode" );
1172  if ( !modeElem.isNull() )
1173  {
1174  QString modeString = modeElem.attribute( "name" );
1175  if ( modeString == "equal" )
1176  r->setMode( EqualInterval );
1177  else if ( modeString == "quantile" )
1178  r->setMode( Quantile );
1179  else if ( modeString == "jenks" )
1180  r->setMode( Jenks );
1181  else if ( modeString == "stddev" )
1182  r->setMode( StdDev );
1183  else if ( modeString == "pretty" )
1184  r->setMode( Pretty );
1185  }
1186 
1187  QDomElement rotationElem = element.firstChildElement( "rotation" );
1188  if ( !rotationElem.isNull() )
1189  r->setRotationField( rotationElem.attribute( "field" ) );
1190 
1191  QDomElement sizeScaleElem = element.firstChildElement( "sizescale" );
1192  if ( !sizeScaleElem.isNull() )
1193  r->setSizeScaleField( sizeScaleElem.attribute( "field" ) );
1194  r->setScaleMethod( QgsSymbolLayerV2Utils::decodeScaleMethod( sizeScaleElem.attribute( "scalemethod" ) ) );
1195 
1196  QDomElement labelFormatElem = element.firstChildElement( "labelformat" );
1197  if ( ! labelFormatElem.isNull() )
1198  {
1200  labelFormat.setFromDomElement( labelFormatElem );
1201  r->setLabelFormat( labelFormat );
1202  }
1203  // TODO: symbol levels
1204  return r;
1205 }
1206 
1207 QDomElement QgsGraduatedSymbolRendererV2::save( QDomDocument& doc )
1208 {
1209  QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
1210  rendererElem.setAttribute( "type", "graduatedSymbol" );
1211  rendererElem.setAttribute( "symbollevels", ( mUsingSymbolLevels ? "1" : "0" ) );
1212  rendererElem.setAttribute( "attr", mAttrName );
1213 
1214  // ranges
1215  int i = 0;
1217  QDomElement rangesElem = doc.createElement( "ranges" );
1218  QgsRangeList::const_iterator it = mRanges.constBegin();
1219  for ( ; it != mRanges.constEnd(); ++it )
1220  {
1221  const QgsRendererRangeV2& range = *it;
1222  QString symbolName = QString::number( i );
1223  symbols.insert( symbolName, range.symbol() );
1224 
1225  QDomElement rangeElem = doc.createElement( "range" );
1226  rangeElem.setAttribute( "lower", QString::number( range.lowerValue(), 'f' ) );
1227  rangeElem.setAttribute( "upper", QString::number( range.upperValue(), 'f' ) );
1228  rangeElem.setAttribute( "symbol", symbolName );
1229  rangeElem.setAttribute( "label", range.label() );
1230  rangeElem.setAttribute( "render", range.renderState() ? "true" : "false" );
1231  rangesElem.appendChild( rangeElem );
1232  i++;
1233  }
1234 
1235  rendererElem.appendChild( rangesElem );
1236 
1237  // save symbols
1238  QDomElement symbolsElem = QgsSymbolLayerV2Utils::saveSymbols( symbols, "symbols", doc );
1239  rendererElem.appendChild( symbolsElem );
1240 
1241  // save source symbol
1242  if ( mSourceSymbol.data() )
1243  {
1244  QgsSymbolV2Map sourceSymbols;
1245  sourceSymbols.insert( "0", mSourceSymbol.data() );
1246  QDomElement sourceSymbolElem = QgsSymbolLayerV2Utils::saveSymbols( sourceSymbols, "source-symbol", doc );
1247  rendererElem.appendChild( sourceSymbolElem );
1248  }
1249 
1250  // save source color ramp
1251  if ( mSourceColorRamp.data() )
1252  {
1253  QDomElement colorRampElem = QgsSymbolLayerV2Utils::saveColorRamp( "[source]", mSourceColorRamp.data(), doc );
1254  rendererElem.appendChild( colorRampElem );
1255  QDomElement invertedElem = doc.createElement( "invertedcolorramp" );
1256  invertedElem.setAttribute( "value", mInvertedColorRamp );
1257  rendererElem.appendChild( invertedElem );
1258  }
1259 
1260  // save mode
1261  QString modeString;
1262  if ( mMode == EqualInterval )
1263  modeString = "equal";
1264  else if ( mMode == Quantile )
1265  modeString = "quantile";
1266  else if ( mMode == Jenks )
1267  modeString = "jenks";
1268  else if ( mMode == StdDev )
1269  modeString = "stddev";
1270  else if ( mMode == Pretty )
1271  modeString = "pretty";
1272  if ( !modeString.isEmpty() )
1273  {
1274  QDomElement modeElem = doc.createElement( "mode" );
1275  modeElem.setAttribute( "name", modeString );
1276  rendererElem.appendChild( modeElem );
1277  }
1278 
1279  QDomElement rotationElem = doc.createElement( "rotation" );
1280  if ( mRotation.data() )
1281  rotationElem.setAttribute( "field", QgsSymbolLayerV2Utils::fieldOrExpressionFromExpression( mRotation.data() ) );
1282  rendererElem.appendChild( rotationElem );
1283 
1284  QDomElement sizeScaleElem = doc.createElement( "sizescale" );
1285  if ( mSizeScale.data() )
1286  sizeScaleElem.setAttribute( "field", QgsSymbolLayerV2Utils::fieldOrExpressionFromExpression( mSizeScale.data() ) );
1287  sizeScaleElem.setAttribute( "scalemethod", QgsSymbolLayerV2Utils::encodeScaleMethod( mScaleMethod ) );
1288  rendererElem.appendChild( sizeScaleElem );
1289 
1290  QDomElement labelFormatElem = doc.createElement( "labelformat" );
1291  mLabelFormat.saveToDomElement( labelFormatElem );
1292  rendererElem.appendChild( labelFormatElem );
1293 
1294  return rendererElem;
1295 }
1296 
1298 {
1300  int count = ranges().count();
1301  for ( int i = 0; i < count; i++ )
1302  {
1303  const QgsRendererRangeV2& range = ranges()[i];
1304  QPixmap pix = QgsSymbolLayerV2Utils::symbolPreviewPixmap( range.symbol(), iconSize );
1305  lst << qMakePair( range.label(), pix );
1306  }
1307  return lst;
1308 }
1309 
1311 {
1312  Q_UNUSED( scaleDenominator );
1313  QgsLegendSymbolList lst;
1314 
1315  foreach ( const QgsRendererRangeV2& range, mRanges )
1316  {
1317  if ( rule.isEmpty() || range.label() == rule )
1318  {
1319  lst << qMakePair( range.label(), range.symbol() );
1320  }
1321  }
1322  return lst;
1323 }
1324 
1326 {
1327  return mSourceSymbol.data();
1328 }
1330 {
1331  mSourceSymbol.reset( sym );
1332 }
1333 
1335 {
1336  return mSourceColorRamp.data();
1337 }
1338 
1340 {
1341  mSourceColorRamp.reset( ramp );
1342 }
1343 
1345 {
1346  int i = 0;
1347  if ( ramp )
1348  {
1349  setSourceColorRamp( ramp );
1350  setInvertedColorRamp( inverted );
1351  }
1352 
1353  if ( mSourceColorRamp )
1354  {
1355  foreach ( QgsRendererRangeV2 range, mRanges )
1356  {
1357  QgsSymbolV2 *symbol = range.symbol() ? range.symbol()->clone() : 0;
1358  if ( symbol )
1359  {
1360  double colorValue;
1361  if ( inverted )
1362  colorValue = ( mRanges.count() > 1 ? ( double )( mRanges.count() - i - 1 ) / ( mRanges.count() - 1 ) : 0 );
1363  else
1364  colorValue = ( mRanges.count() > 1 ? ( double ) i / ( mRanges.count() - 1 ) : 0 );
1365  symbol->setColor( mSourceColorRamp->color( colorValue ) );
1366  }
1367  updateRangeSymbol( i, symbol );
1368  ++i;
1369  }
1370  }
1371 
1372 }
1373 
1375 {
1376  if ( !sym )
1377  return;
1378 
1379  int i = 0;
1380  foreach ( QgsRendererRangeV2 range, mRanges )
1381  {
1382  QgsSymbolV2 *symbol = sym->clone();
1383  symbol->setColor( range.symbol()->color() );
1384  updateRangeSymbol( i, symbol );
1385  ++i;
1386  }
1387  setSourceSymbol( sym->clone() );
1388 }
1389 
1390 void QgsGraduatedSymbolRendererV2::setRotationField( QString fieldOrExpression )
1391 {
1393 }
1394 
1396 {
1397  return mRotation.data() ? QgsSymbolLayerV2Utils::fieldOrExpressionFromExpression( mRotation.data() ) : QString();
1398 }
1399 
1400 void QgsGraduatedSymbolRendererV2::setSizeScaleField( QString fieldOrExpression )
1401 {
1403 }
1404 
1406 {
1408 }
1409 
1411 {
1413  for ( QgsRangeList::iterator it = mRanges.begin(); it != mRanges.end(); ++it )
1414  {
1415  if ( it->symbol() )
1416  setScaleMethodToSymbol( it->symbol(), scaleMethod );
1417  }
1418 }
1419 
1421 {
1422  return true;
1423 }
1424 
1426 {
1427  bool ok;
1428  int index = key.toInt( &ok );
1429  if ( ok && index >= 0 && index < mRanges.size() )
1430  return mRanges[ index ].renderState();
1431  else
1432  return true;
1433 }
1434 
1436 {
1437  bool ok;
1438  int index = key.toInt( &ok );
1439  if ( ok )
1440  updateRangeRenderState( index, state );
1441 }
1442 
1443 
1445 {
1446  QgsSymbolV2* newSymbol = symbol->clone();
1447  QString label = "0.0 - 0.0";
1448  mRanges.insert( 0, QgsRendererRangeV2( 0.0, 0.0, newSymbol, label ) );
1449 }
1450 
1451 void QgsGraduatedSymbolRendererV2::addClass( double lower, double upper )
1452 {
1453  QgsSymbolV2* newSymbol = mSourceSymbol->clone();
1454  QString label = mLabelFormat.labelForRange( lower, upper );
1455  mRanges.append( QgsRendererRangeV2( lower, upper, newSymbol, label ) );
1456 }
1457 
1459 {
1460  mRanges.append( range );
1461 }
1462 
1464 {
1465  mRanges.removeAt( idx );
1466 }
1467 
1469 {
1470  mRanges.clear();
1471 }
1472 
1474 {
1475  if ( updateRanges && labelFormat != mLabelFormat )
1476  {
1477  for ( QgsRangeList::iterator it = mRanges.begin(); it != mRanges.end(); ++it )
1478  {
1479  it->setLabel( labelFormat.labelForRange( *it ) );
1480  }
1481  }
1483 }
1484 
1485 
1487 {
1488  // Find the minimum size of a class
1489  double minClassRange = 0.0;
1490  for ( QgsRangeList::iterator it = mRanges.begin(); it != mRanges.end(); ++it )
1491  {
1492  double range = it->upperValue() - it->lowerValue();
1493  if ( range <= 0.0 )
1494  continue;
1495  if ( minClassRange == 0.0 || range < minClassRange )
1496  minClassRange = range;
1497  }
1498  if ( minClassRange <= 0.0 )
1499  return;
1500 
1501  // Now set the number of decimal places to ensure no more than 20% error in
1502  // representing this range (up to 10% at upper and lower end)
1503 
1504  int ndp = 10;
1505  double nextDpMinRange = 0.0000000099;
1506  while ( ndp > 0 && nextDpMinRange < minClassRange )
1507  {
1508  ndp--;
1509  nextDpMinRange *= 10.0;
1510  }
1511  mLabelFormat.setPrecision( ndp );
1512  if ( updateRanges ) setLabelFormat( mLabelFormat, true );
1513 }
1514 
1516 {
1517  if ( from < 0 || from >= mRanges.size() || to < 0 || to >= mRanges.size() )
1518  return;
1519  mRanges.move( from, to );
1520 }
1521 
1523 {
1524  return r1 < r2;
1525 }
1526 
1528 {
1529  return !valueLessThan( r1, r2 );
1530 }
1531 
1533 {
1534  QgsDebugMsg( "Entered" );
1535  if ( order == Qt::AscendingOrder )
1536  {
1537  qSort( mRanges.begin(), mRanges.end(), valueLessThan );
1538  }
1539  else
1540  {
1541  qSort( mRanges.begin(), mRanges.end(), valueGreaterThan );
1542  }
1543 }
1544 
1546 {
1547  return QString::localeAwareCompare( r1.label(), r2.label() ) < 0;
1548 }
1549 
1551 {
1552  return !labelLessThan( r1, r2 );
1553 }
1554 
1556 {
1557  if ( order == Qt::AscendingOrder )
1558  {
1559  qSort( mRanges.begin(), mRanges.end(), labelLessThan );
1560  }
1561  else
1562  {
1563  qSort( mRanges.begin(), mRanges.end(), labelGreaterThan );
1564  }
1565 }
1566 
1568 {
1569  if ( renderer->type() == "graduatedSymbol" )
1570  {
1571  return dynamic_cast<QgsGraduatedSymbolRendererV2*>( renderer->clone() );
1572  }
1573  if ( renderer->type() == "pointDisplacement" )
1574  {
1575  const QgsPointDisplacementRenderer* pointDisplacementRenderer = dynamic_cast<const QgsPointDisplacementRenderer*>( renderer );
1576  return convertFromRenderer( pointDisplacementRenderer->embeddedRenderer() );
1577  }
1578  if ( renderer->type() == "invertedPolygonRenderer" )
1579  {
1580  const QgsInvertedPolygonRenderer* invertedPolygonRenderer = dynamic_cast<const QgsInvertedPolygonRenderer*>( renderer );
1581  return convertFromRenderer( invertedPolygonRenderer->embeddedRenderer() );
1582  }
1583 
1584  // If not one of the specifically handled renderers, then just grab the symbol from the renderer
1585  // Could have applied this to specific renderer types (singleSymbol, graduatedSymbo)
1586 
1588  QgsSymbolV2List symbols = const_cast<QgsFeatureRendererV2 *>( renderer )->symbols();
1589  if ( symbols.size() > 0 )
1590  {
1591  r->setSourceSymbol( symbols.at( 0 )->clone() );
1592  }
1593 
1594  return r;
1595 }
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:208
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:416
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