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:38
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:46
static unsigned index
virtual QgsSymbolV2 * originalSymbolForFeature(QgsFeature &feature)
Return symbol for feature.
void setLowerValue(double lowerValue)
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
Definition: qgsexpression.h:94
void setLabelFormat(const QgsRendererRangeV2LabelFormat &labelFormat, bool updateRanges=false)
Set the label format used to generate default classification labels.
virtual QDomElement save(QDomDocument &doc)
store renderer info to XML element
bool labelLessThan(const QgsRendererRangeV2 &r1, const QgsRendererRangeV2 &r2)
QString rotationField() const
return rotation field name (or empty string if not set or not supported by renderer) ...
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:37
static QList< double > _calcPrettyBreaks(double minimum, double maximum, int classes)
static QList< double > _calcStdDevBreaks(QList< double > values, int classes, QList< double > &labels)
SymbolType type() const
Definition: qgssymbolv2.h:78
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.
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.
virtual QString dump() const
for debugging
Container of fields for a vector layer.
Definition: qgsfield.h:172
virtual QgsSymbolV2 * symbolForFeature(QgsFeature &feature)
to be overridden
virtual QgsLegendSymbolList legendSymbolItems(double scaleDenominator=-1, QString rule=QString())
return a list of item text / symbol
QHash< QgsSymbolV2 *, QgsSymbolV2 * > mTempSymbols
temporary symbols, used for data-defined rotation and scaling
void calculateLabelPrecision(bool updateRanges=true)
Reset the label decimal places to a numberbased on the minimum class interval.
virtual bool legendSymbolItemChecked(QString key)
item in symbology was checked
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:113
void setScaleMethod(QgsSymbolV2::ScaleMethod scaleMethod)
virtual QgsSymbolV2List symbols()
for symbol levels
virtual QgsFeatureRendererV2 * clone() const
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:412
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:80
void setRotationField(QString fieldOrExpression)
sets rotation field of renderer (if supported by the renderer)
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)
QStringList referencedColumns()
Get list of columns referenced by the expression.
QgsSymbolV2 * symbol() const
void setAngle(double angle)
This class wraps a request for features to a vector layer (or directly its vector data provider)...
bool updateRangeLowerValue(int rangeIndex, double value)
const QgsAttributes & attributes() const
Definition: qgsfeature.h:142
void setSize(double size)
void toSld(QDomDocument &doc, QDomElement &element, QgsStringMap props) const
QgsRendererRangeV2LabelFormat mLabelFormat
QGis::GeometryType geometryType() const
Returns point, line or polygon.
QgsGraduatedSymbolRendererV2(QString attrName=QString(), QgsRangeList ranges=QgsRangeList())
void setUpperValue(double upperValue)
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.
void setUsingSymbolLevels(bool usingSymbolLevels)
static QList< double > _calcEqualIntervalBreaks(double minimum, double maximum, int classes)
virtual QgsLegendSymbologyList legendSymbologyItems(QSize iconSize)
return a list of symbology items for the legend
int ANALYSIS_EXPORT lower(int n, int i)
lower function
void moveClass(int from, int to)
Moves the category at index position from to index position to.
Contains information about the context of a rendering operation.
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)
virtual bool legendSymbolItemsCheckable() const
items of symbology items in legend should be checkable
virtual void stopRender(QgsRenderContext &context)
virtual void startRender(QgsRenderContext &context, const QgsFields &fields)
bool updateRangeSymbol(int rangeIndex, QgsSymbolV2 *symbol)
void setSourceColorRamp(QgsVectorColorRampV2 *ramp)
QScopedPointer< QgsSymbolV2 > mSourceSymbol
void setRenderHints(int hints)
Definition: qgssymbolv2.h:133
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
const QgsFields & pendingFields() const
returns field list in the to-be-committed state
QScopedPointer< QgsExpression > mSizeScale
bool nextFeature(QgsFeature &f)
QgsRendererRangeV2 & operator=(QgsRendererRangeV2 range)
Geometry is not required. It may still be returned if e.g. required for a filter condition.
virtual void toSld(QDomDocument &doc, QDomElement &element) const
used from subclasses to create SLD Rule elements following SLD v1.1 specs
static 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:41
int max(int a, int b)
Definition: util.h:87
virtual void checkLegendSymbolItem(QString key, bool state=true)
item in symbology was checked
void setScaleMethod(QgsSymbolV2::ScaleMethod scaleMethod)
void updateColorRamp(QgsVectorColorRampV2 *ramp=0, bool inverted=false)
Update the color ramp used.
bool valueGreaterThan(const QgsRendererRangeV2 &r1, const QgsRendererRangeV2 &r2)
QColor color() const