QGIS API Documentation  2.11.0-Master
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 #include "qgspainteffect.h"
24 #include "qgsscaleexpression.h"
25 #include "qgsdatadefined.h"
26 
27 #include "qgsfeature.h"
28 #include "qgsvectorlayer.h"
29 #include "qgslogger.h"
30 #include "qgsvectordataprovider.h"
31 #include "qgsexpression.h"
32 #include <QDomDocument>
33 #include <QDomElement>
34 #include <QSettings> // for legend
35 #include <limits> // for jenks classification
36 #include <ctime>
37 
39  : mLowerValue( 0 )
40  , mUpperValue( 0 )
41  , mSymbol( 0 )
42  , mLabel()
43  , mRender( true )
44 {
45 }
46 
47 QgsRendererRangeV2::QgsRendererRangeV2( double lowerValue, double upperValue, QgsSymbolV2* symbol, QString label, bool render )
48  : mLowerValue( lowerValue )
49  , mUpperValue( upperValue )
50  , mSymbol( symbol )
51  , mLabel( label )
52  , mRender( render )
53 {
54 }
55 
57  : mLowerValue( range.mLowerValue )
58  , mUpperValue( range.mUpperValue )
59  , mSymbol( range.mSymbol.data() ? range.mSymbol->clone() : NULL )
60  , mLabel( range.mLabel )
61  , mRender( range.mRender )
62 {
63 }
64 
65 // cpy and swap idiom, note that the cpy is done with 'pass by value'
67 {
68  swap( range );
69  return *this;
70 }
71 
73 {
74  return
75  lowerValue() < other.lowerValue() ||
76  ( lowerValue() == other.lowerValue() && upperValue() < other.upperValue() );
77 }
78 
79 
81 {
82  qSwap( mLowerValue, other.mLowerValue );
83  qSwap( mUpperValue, other.mUpperValue );
84  qSwap( mSymbol, other.mSymbol );
85  std::swap( mLabel, other.mLabel );
86 }
87 
89 {
90  return mLowerValue;
91 }
92 
94 {
95  return mUpperValue;
96 }
97 
99 {
100  return mSymbol.data();
101 }
102 
104 {
105  return mLabel;
106 }
107 
109 {
110  if ( mSymbol.data() != s ) mSymbol.reset( s );
111 }
112 
114 {
115  mLabel = label;
116 }
117 
118 void QgsRendererRangeV2::setUpperValue( double upperValue )
119 {
121 }
122 
123 void QgsRendererRangeV2::setLowerValue( double lowerValue )
124 {
126 }
127 
129 {
130  return mRender;
131 }
132 
134 {
135  mRender = render;
136 }
137 
139 {
140  return QString( "%1 - %2::%3::%4\n" ).arg( mLowerValue ).arg( mUpperValue ).arg( mLabel ).arg( mSymbol.data() ? mSymbol->dump() : "(no symbol)" );
141 }
142 
144 {
145  if ( !mSymbol.data() || props.value( "attribute", "" ).isEmpty() )
146  return;
147 
148  QString attrName = props[ "attribute" ];
149 
150  QDomElement ruleElem = doc.createElement( "se:Rule" );
151  element.appendChild( ruleElem );
152 
153  QDomElement nameElem = doc.createElement( "se:Name" );
154  nameElem.appendChild( doc.createTextNode( mLabel ) );
155  ruleElem.appendChild( nameElem );
156 
157  QDomElement descrElem = doc.createElement( "se:Description" );
158  QDomElement titleElem = doc.createElement( "se:Title" );
159  QString descrStr = QString( "range: %1 - %2" ).arg( mLowerValue ).arg( mUpperValue );
160  titleElem.appendChild( doc.createTextNode( !mLabel.isEmpty() ? mLabel : descrStr ) );
161  descrElem.appendChild( titleElem );
162  ruleElem.appendChild( descrElem );
163 
164  // create the ogc:Filter for the range
165  QString filterFunc = QString( "%1 > %2 AND %1 <= %3" )
166  .arg( attrName.replace( "\"", "\"\"" ) )
167  .arg( mLowerValue ).arg( mUpperValue );
168  QgsSymbolLayerV2Utils::createFunctionElement( doc, ruleElem, filterFunc );
169 
170  mSymbol->toSld( doc, ruleElem, props );
171 }
172 
174 
177 
179  mFormat( " %1 - %2 " ),
180  mPrecision( 4 ),
181  mTrimTrailingZeroes( false ),
182  mNumberScale( 1.0 ),
183  mNumberSuffix( "" ),
184  mReTrailingZeroes( "[.,]?0*$" ),
185  mReNegativeZero( "^\\-0(?:[.,]0*)?$" )
186 {
187 }
188 
189 QgsRendererRangeV2LabelFormat::QgsRendererRangeV2LabelFormat( QString format, int precision, bool trimTrailingZeroes ):
190  mReTrailingZeroes( "[.,]?0*$" ),
191  mReNegativeZero( "^\\-0(?:[.,]0*)?$" )
192 {
193  setFormat( format );
194  setPrecision( precision );
195  setTrimTrailingZeroes( trimTrailingZeroes );
196 }
197 
198 
200 {
201  return
202  format() == other.format() &&
203  precision() == other.precision() &&
205 }
206 
208 {
209  return !( *this == other );
210 }
211 
213 {
214  // Limit the range of decimal places to a reasonable range
215  precision = qBound( MinPrecision, precision, MaxPrecision );
217  mNumberScale = 1.0;
218  mNumberSuffix = "";
219  while ( precision < 0 )
220  {
221  precision++;
222  mNumberScale /= 10.0;
223  mNumberSuffix.append( '0' );
224  }
225 }
226 
228 {
229  return labelForRange( range.lowerValue(), range.upperValue() );
230 }
231 
233 {
234  if ( mPrecision > 0 )
235  {
236  QString valueStr = QString::number( value, 'f', mPrecision );
237  if ( mTrimTrailingZeroes )
238  valueStr = valueStr.replace( mReTrailingZeroes, "" );
239  if ( mReNegativeZero.exactMatch( valueStr ) )
240  valueStr = valueStr.mid( 1 );
241  return valueStr;
242  }
243  else
244  {
245  QString valueStr = QString::number( value * mNumberScale, 'f', 0 );
246  if ( valueStr == "-0" )
247  valueStr = "0";
248  if ( valueStr != "0" )
249  valueStr = valueStr + mNumberSuffix;
250  return valueStr;
251  }
252 }
253 
255 {
256  QString lowerStr = formatNumber( lower );
257  QString upperStr = formatNumber( upper );
258 
259  QString legend( mFormat );
260  return legend.replace( "%1", lowerStr ).replace( "%2", upperStr );
261 }
262 
264 {
265  mFormat = element.attribute( "format",
266  element.attribute( "prefix", " " ) + "%1" +
267  element.attribute( "separator", " - " ) + "%2" +
268  element.attribute( "suffix", " " )
269  );
270  setPrecision( element.attribute( "decimalplaces", "4" ).toInt() );
271  mTrimTrailingZeroes = element.attribute( "trimtrailingzeroes", "false" ) == "true";
272 }
273 
275 {
276  element.setAttribute( "format", mFormat );
277  element.setAttribute( "decimalplaces", mPrecision );
278  element.setAttribute( "trimtrailingzeroes", mTrimTrailingZeroes ? "true" : "false" );
279 }
280 
282 
284  : QgsFeatureRendererV2( "graduatedSymbol" )
285  , mAttrName( attrName )
286  , mRanges( ranges )
287  , mMode( Custom )
288  , mInvertedColorRamp( false )
289  , mScaleMethod( DEFAULT_SCALE_METHOD )
290  , mGraduatedMethod( GraduatedColor )
291  , mAttrNum( -1 )
292  , mCounting( false )
293 
294 {
295  // TODO: check ranges for sanity (NULL symbols, invalid ranges)
296 }
297 
299 {
300  mRanges.clear(); // should delete all the symbols
301 }
302 
304 {
305  for ( QgsRangeList::iterator it = mRanges.begin(); it != mRanges.end(); ++it )
306  {
307  if ( it->lowerValue() <= value && it->upperValue() >= value )
308  {
309  if ( it->renderState() || mCounting )
310  return it->symbol();
311  else
312  return NULL;
313  }
314  }
315  // the value is out of the range: return NULL instead of symbol
316  return NULL;
317 }
318 
320 {
321  QgsSymbolV2* symbol = originalSymbolForFeature( feature, context );
322  if ( symbol == NULL )
323  return NULL;
324 
325  if ( !mRotation.data() && !mSizeScale.data() )
326  return symbol; // no data-defined rotation/scaling - just return the symbol
327 
328  // find out rotation, size scale
329  const double rotation = mRotation.data() ? mRotation->evaluate( &context.expressionContext() ).toDouble() : 0;
330  const double sizeScale = mSizeScale.data() ? mSizeScale->evaluate( &context.expressionContext() ).toDouble() : 1.;
331 
332  // take a temporary symbol (or create it if doesn't exist)
333  QgsSymbolV2* tempSymbol = mTempSymbols[symbol];
334 
335  // modify the temporary symbol and return it
336  if ( tempSymbol->type() == QgsSymbolV2::Marker )
337  {
338  QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( tempSymbol );
339  if ( mRotation.data() ) markerSymbol->setAngle( rotation );
340  markerSymbol->setSize( sizeScale * static_cast<QgsMarkerSymbolV2*>( symbol )->size() );
341  markerSymbol->setScaleMethod( mScaleMethod );
342  }
343  else if ( tempSymbol->type() == QgsSymbolV2::Line )
344  {
345  QgsLineSymbolV2* lineSymbol = static_cast<QgsLineSymbolV2*>( tempSymbol );
346  lineSymbol->setWidth( sizeScale * static_cast<QgsLineSymbolV2*>( symbol )->width() );
347  }
348  return tempSymbol;
349 }
350 
352 {
353  Q_UNUSED( context );
354  QgsAttributes attrs = feature.attributes();
355  QVariant value;
356  if ( mAttrNum < 0 || mAttrNum >= attrs.count() )
357  {
358  value = mExpression->evaluate( &context.expressionContext() );
359  }
360  else
361  {
362  value = attrs[mAttrNum];
363  }
364 
365  // Null values should not be categorized
366  if ( value.isNull() )
367  return NULL;
368 
369  // find the right category
370  return symbolForValue( value.toDouble() );
371 }
372 
374 {
375  mCounting = context.rendererScale() == 0.0;
376 
377  // find out classification attribute index from name
378  mAttrNum = fields.fieldNameIndex( mAttrName );
379 
380  if ( mAttrNum == -1 )
381  {
383  mExpression->prepare( &context.expressionContext() );
384  }
385 
387  for ( ; it != mRanges.end(); ++it )
388  {
389  if ( !it->symbol() )
390  continue;
391 
392  it->symbol()->startRender( context, &fields );
393 
394  if ( mRotation.data() || mSizeScale.data() )
395  {
396  QgsSymbolV2* tempSymbol = it->symbol()->clone();
399  tempSymbol->startRender( context, &fields );
400  mTempSymbols[ it->symbol()] = tempSymbol;
401  }
402  }
403  return;
404 }
405 
407 {
409  for ( ; it != mRanges.end(); ++it )
410  {
411  if ( !it->symbol() )
412  continue;
413 
414  it->symbol()->stopRender( context );
415  }
416 
417  // cleanup mTempSymbols
419  for ( ; it2 != mTempSymbols.end(); ++it2 )
420  {
421  it2.value()->stopRender( context );
422  delete it2.value();
423  }
425 }
426 
428 {
429  QSet<QString> attributes;
430 
431  // mAttrName can contain either attribute name or an expression.
432  // Sometimes it is not possible to distinguish between those two,
433  // e.g. "a - b" can be both a valid attribute name or expression.
434  // Since we do not have access to fields here, try both options.
435  attributes << mAttrName;
436 
437  QgsExpression testExpr( mAttrName );
438  if ( !testExpr.hasParserError() )
439  attributes.unite( testExpr.referencedColumns().toSet() );
440 
441  if ( mRotation.data() ) attributes.unite( mRotation->referencedColumns().toSet() );
442  if ( mSizeScale.data() ) attributes.unite( mSizeScale->referencedColumns().toSet() );
443 
445  for ( ; range_it != mRanges.constEnd(); ++range_it )
446  {
447  QgsSymbolV2* symbol = range_it->symbol();
448  if ( symbol )
449  {
450  attributes.unite( symbol->usedAttributes() );
451  }
452  }
453  return attributes.toList();
454 }
455 
457 {
458  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
459  return false;
460  mRanges[rangeIndex].setSymbol( symbol );
461  return true;
462 }
463 
465 {
466  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
467  return false;
468  mRanges[rangeIndex].setLabel( label );
469  return true;
470 }
471 
472 bool QgsGraduatedSymbolRendererV2::updateRangeUpperValue( int rangeIndex, double value )
473 {
474  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
475  return false;
476  QgsRendererRangeV2 &range = mRanges[rangeIndex];
477  bool isDefaultLabel = range.label() == mLabelFormat.labelForRange( range );
478  range.setUpperValue( value );
479  if ( isDefaultLabel ) range.setLabel( mLabelFormat.labelForRange( range ) );
480  return true;
481 }
482 
483 bool QgsGraduatedSymbolRendererV2::updateRangeLowerValue( int rangeIndex, double value )
484 {
485  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
486  return false;
487  QgsRendererRangeV2 &range = mRanges[rangeIndex];
488  bool isDefaultLabel = range.label() == mLabelFormat.labelForRange( range );
489  range.setLowerValue( value );
490  if ( isDefaultLabel ) range.setLabel( mLabelFormat.labelForRange( range ) );
491  return true;
492 }
493 
495 {
496  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
497  return false;
498  mRanges[rangeIndex].setRenderState( value );
499  return true;
500 }
501 
503 {
504  QString s = QString( "GRADUATED: attr %1\n" ).arg( mAttrName );
505  for ( int i = 0; i < mRanges.count(); i++ )
506  s += mRanges[i].dump();
507  return s;
508 }
509 
511 {
513  r->setMode( mMode );
514  if ( mSourceSymbol.data() )
515  r->setSourceSymbol( mSourceSymbol->clone() );
516  if ( mSourceColorRamp.data() )
517  {
518  r->setSourceColorRamp( mSourceColorRamp->clone() );
520  }
523  r->setLabelFormat( labelFormat() );
525  copyPaintEffect( r );
526  return r;
527 }
528 
530 {
531  QgsStringMap props;
532  props[ "attribute" ] = mAttrName;
533  props[ "method" ] = graduatedMethodStr( mGraduatedMethod );
534  if ( mRotation.data() )
535  props[ "angle" ] = mRotation->expression();
536  if ( mSizeScale.data() )
537  props[ "scale" ] = mSizeScale->expression();
538 
539  // create a Rule for each range
540  for ( QgsRangeList::const_iterator it = mRanges.constBegin(); it != mRanges.constEnd(); ++it )
541  {
542  QgsStringMap catProps( props );
543  it->toSld( doc, element, catProps );
544  }
545 }
546 
548 {
549  Q_UNUSED( context );
550  QgsSymbolV2List lst;
551  for ( int i = 0; i < mRanges.count(); i++ )
552  lst.append( mRanges[i].symbol() );
553  return lst;
554 }
555 
556 static QList<double> _calcEqualIntervalBreaks( double minimum, double maximum, int classes )
557 {
558 
559  // Equal interval algorithm
560  //
561  // Returns breaks based on dividing the range ('minimum' to 'maximum')
562  // into 'classes' parts.
563 
564  double step = ( maximum - minimum ) / classes;
565 
566  QList<double> breaks;
567  double value = minimum;
568  for ( int i = 0; i < classes; i++ )
569  {
570  value += step;
571  breaks.append( value );
572  }
573 
574  // floating point arithmetics is not precise:
575  // set the last break to be exactly maximum so we do not miss it
576  breaks[classes-1] = maximum;
577 
578  return breaks;
579 }
580 
581 static QList<double> _calcQuantileBreaks( QList<double> values, int classes )
582 {
583  // q-th quantile of a data set:
584  // value where q fraction of data is below and (1-q) fraction is above this value
585  // Xq = (1 - r) * X_NI1 + r * X_NI2
586  // NI1 = (int) (q * (n+1))
587  // NI2 = NI1 + 1
588  // r = q * (n+1) - (int) (q * (n+1))
589  // (indices of X: 1...n)
590 
591  // sort the values first
592  qSort( values );
593 
594  QList<double> breaks;
595 
596  // If there are no values to process: bail out
597  if ( !values.count() )
598  return breaks;
599 
600  int n = values.count();
601  double Xq = n > 0 ? values[0] : 0.0;
602 
603  for ( int i = 1; i < classes; i++ )
604  {
605  if ( n > 1 )
606  {
607  double q = i / ( double ) classes;
608  double a = q * ( n - 1 );
609  int aa = ( int )( a );
610 
611  double r = a - aa;
612  Xq = ( 1 - r ) * values[aa] + r * values[aa+1];
613  }
614  breaks.append( Xq );
615  }
616 
617  breaks.append( values[ n-1 ] );
618 
619  return breaks;
620 }
621 
622 static QList<double> _calcStdDevBreaks( QList<double> values, int classes, QList<double> &labels )
623 {
624 
625  // C++ implementation of the standard deviation class interval algorithm
626  // as implemented in the 'classInt' package available for the R statistical
627  // prgramming language.
628 
629  // Returns breaks based on 'prettyBreaks' of the centred and scaled
630  // values of 'values', and may have a number of classes different from 'classes'.
631 
632  // If there are no values to process: bail out
633  if ( !values.count() )
634  return QList<double>();
635 
636  double mean = 0.0;
637  double stdDev = 0.0;
638  int n = values.count();
639  double minimum = values[0];
640  double maximum = values[0];
641 
642  for ( int i = 0; i < n; i++ )
643  {
644  mean += values[i];
645  minimum = qMin( values[i], minimum ); // could use precomputed max and min
646  maximum = qMax( values[i], maximum ); // but have to go through entire list anyway
647  }
648  mean = mean / ( double ) n;
649 
650  double sd = 0.0;
651  for ( int i = 0; i < n; i++ )
652  {
653  sd = values[i] - mean;
654  stdDev += sd * sd;
655  }
656  stdDev = sqrt( stdDev / n );
657 
658  QList<double> breaks = QgsSymbolLayerV2Utils::prettyBreaks(( minimum - mean ) / stdDev, ( maximum - mean ) / stdDev, classes );
659  for ( int i = 0; i < breaks.count(); i++ )
660  {
661  labels.append( breaks[i] );
662  breaks[i] = ( breaks[i] * stdDev ) + mean;
663  }
664 
665  return breaks;
666 } // _calcStdDevBreaks
667 
668 static QList<double> _calcJenksBreaks( QList<double> values, int classes,
669  double minimum, double maximum,
670  int maximumSize = 1000 )
671 {
672  // Jenks Optimal (Natural Breaks) algorithm
673  // Based on the Jenks algorithm from the 'classInt' package available for
674  // the R statistical prgramming language, and from Python code from here:
675  // http://danieljlewis.org/2010/06/07/jenks-natural-breaks-algorithm-in-python/
676  // and is based on a JAVA and Fortran code available here:
677  // https://stat.ethz.ch/pipermail/r-sig-geo/2006-March/000811.html
678 
679  // Returns class breaks such that classes are internally homogeneous while
680  // assuring heterogeneity among classes.
681 
682  if ( !values.count() )
683  return QList<double>();
684 
685  if ( classes <= 1 )
686  {
687  return QList<double>() << maximum;
688  }
689 
690  if ( classes >= values.size() )
691  {
692  return values;
693  }
694 
695  QVector<double> sample;
696 
697  // if we have lots of values, we need to take a random sample
698  if ( values.size() > maximumSize )
699  {
700  // for now, sample at least maximumSize values or a 10% sample, whichever
701  // is larger. This will produce a more representative sample for very large
702  // layers, but could end up being computationally intensive...
703 
704  sample.resize( qMax( maximumSize, values.size() / 10 ) );
705 
706  QgsDebugMsg( QString( "natural breaks (jenks) sample size: %1" ).arg( sample.size() ) );
707  QgsDebugMsg( QString( "values:%1" ).arg( values.size() ) );
708 
709  sample[ 0 ] = minimum;
710  sample[ 1 ] = maximum;;
711  for ( int i = 2; i < sample.size(); i++ )
712  {
713  // pick a random integer from 0 to n
714  double r = qrand();
715  int j = floor( r / RAND_MAX * ( values.size() - 1 ) );
716  sample[ i ] = values[ j ];
717  }
718  }
719  else
720  {
721  sample = values.toVector();
722  }
723 
724  int n = sample.size();
725 
726  // sort the sample values
727  qSort( sample );
728 
729  QVector< QVector<int> > matrixOne( n + 1 );
730  QVector< QVector<double> > matrixTwo( n + 1 );
731 
732  for ( int i = 0; i <= n; i++ )
733  {
734  matrixOne[i].resize( classes + 1 );
735  matrixTwo[i].resize( classes + 1 );
736  }
737 
738  for ( int i = 1; i <= classes; i++ )
739  {
740  matrixOne[0][i] = 1;
741  matrixOne[1][i] = 1;
742  matrixTwo[0][i] = 0.0;
743  for ( int j = 2; j <= n; j++ )
744  {
745  matrixTwo[j][i] = std::numeric_limits<double>::max();
746  }
747  }
748 
749  for ( int l = 2; l <= n; l++ )
750  {
751  double s1 = 0.0;
752  double s2 = 0.0;
753  int w = 0;
754 
755  double v = 0.0;
756 
757  for ( int m = 1; m <= l; m++ )
758  {
759  int i3 = l - m + 1;
760 
761  double val = sample[ i3 - 1 ];
762 
763  s2 += val * val;
764  s1 += val;
765  w++;
766 
767  v = s2 - ( s1 * s1 ) / ( double ) w;
768  int i4 = i3 - 1;
769  if ( i4 != 0 )
770  {
771  for ( int j = 2; j <= classes; j++ )
772  {
773  if ( matrixTwo[l][j] >= v + matrixTwo[i4][j - 1] )
774  {
775  matrixOne[l][j] = i4;
776  matrixTwo[l][j] = v + matrixTwo[i4][j - 1];
777  }
778  }
779  }
780  }
781  matrixOne[l][1] = 1;
782  matrixTwo[l][1] = v;
783  }
784 
785  QVector<double> breaks( classes );
786  breaks[classes-1] = sample[n-1];
787 
788  for ( int j = classes, k = n; j >= 2; j-- )
789  {
790  int id = matrixOne[k][j] - 1;
791  breaks[j - 2] = sample[id];
792  k = matrixOne[k][j] - 1;
793  }
794 
795  return breaks.toList();
796 } //_calcJenksBreaks
797 
798 
800  QgsVectorLayer* vlayer,
801  QString attrName,
802  int classes,
803  Mode mode,
804  QgsSymbolV2* symbol,
805  QgsVectorColorRampV2* ramp,
806  bool inverted,
808 )
809 {
811  QgsGraduatedSymbolRendererV2* r = new QgsGraduatedSymbolRendererV2( attrName, ranges );
812  r->setSourceSymbol( symbol->clone() );
813  r->setSourceColorRamp( ramp->clone() );
814  r->setInvertedColorRamp( inverted );
815  r->setMode( mode );
816  r->setLabelFormat( labelFormat );
817  r->updateClasses( vlayer, mode, classes );
818  return r;
819 }
820 
822 {
823  bool ok;
824  return vlayer->getDoubleValues( mAttrName, ok );
825 }
826 
828 {
829  if ( mAttrName.isEmpty() )
830  return;
831 
832  setMode( mode );
833  // Custom classes are not recalculated
834  if ( mode == Custom )
835  return;
836 
837  if ( nclasses < 1 )
838  nclasses = 1;
839 
840  QList<double> values;
841  bool valuesLoaded = false;
842  double minimum;
843  double maximum;
844 
845  int attrNum = vlayer->fieldNameIndex( mAttrName );
846 
847  bool ok;
848  if ( attrNum == -1 )
849  {
850  values = vlayer->getDoubleValues( mAttrName, ok );
851  if ( !ok || values.isEmpty() )
852  return;
853 
854  qSort( values ); // vmora: is wondering if O( n log(n) ) is really necessary here, min and max are O( n )
855  minimum = values.first();
856  maximum = values.last();
857  valuesLoaded = true;
858  }
859  else
860  {
861  minimum = vlayer->minimumValue( attrNum ).toDouble();
862  maximum = vlayer->maximumValue( attrNum ).toDouble();
863  }
864 
865  QgsDebugMsg( QString( "min %1 // max %2" ).arg( minimum ).arg( maximum ) );
866  QList<double> breaks;
867  QList<double> labels;
868  if ( mode == EqualInterval )
869  {
870  breaks = _calcEqualIntervalBreaks( minimum, maximum, nclasses );
871  }
872  else if ( mode == Pretty )
873  {
874  breaks = QgsSymbolLayerV2Utils::prettyBreaks( minimum, maximum, nclasses );
875  }
876  else if ( mode == Quantile || mode == Jenks || mode == StdDev )
877  {
878  // get values from layer
879  if ( !valuesLoaded )
880  {
881  values = vlayer->getDoubleValues( mAttrName, ok );
882  }
883 
884  // calculate the breaks
885  if ( mode == Quantile )
886  {
887  breaks = _calcQuantileBreaks( values, nclasses );
888  }
889  else if ( mode == Jenks )
890  {
891  breaks = _calcJenksBreaks( values, nclasses, minimum, maximum );
892  }
893  else if ( mode == StdDev )
894  {
895  breaks = _calcStdDevBreaks( values, nclasses, labels );
896  }
897  }
898  else
899  {
900  Q_ASSERT( false );
901  }
902 
903  double lower, upper = minimum;
904  QString label;
906 
907  // "breaks" list contains all values at class breaks plus maximum as last break
908 
909  int i = 0;
910  for ( QList<double>::iterator it = breaks.begin(); it != breaks.end(); ++it, ++i )
911  {
912  lower = upper; // upper border from last interval
913  upper = *it;
914 
915  // Label - either StdDev label or default label for a range
916  if ( mode == StdDev )
917  {
918  if ( i == 0 )
919  {
920  label = "< " + QString::number( labels[i], 'f', 2 ) + " Std Dev";
921  }
922  else if ( i == labels.count() - 1 )
923  {
924  label = ">= " + QString::number( labels[i-1], 'f', 2 ) + " Std Dev";
925  }
926  else
927  {
928  label = QString::number( labels[i-1], 'f', 2 ) + " Std Dev" + " - " + QString::number( labels[i], 'f', 2 ) + " Std Dev";
929  }
930  }
931  else
932  {
933  label = mLabelFormat.labelForRange( lower, upper );
934  }
935  QgsSymbolV2* newSymbol = mSourceSymbol ? mSourceSymbol->clone() : QgsSymbolV2::defaultSymbol( vlayer->geometryType() );
936  addClass( QgsRendererRangeV2( lower, upper, newSymbol, label ) );
937  }
939 }
940 
942 {
943  QDomElement symbolsElem = element.firstChildElement( "symbols" );
944  if ( symbolsElem.isNull() )
945  return NULL;
946 
947  QDomElement rangesElem = element.firstChildElement( "ranges" );
948  if ( rangesElem.isNull() )
949  return NULL;
950 
951  QgsSymbolV2Map symbolMap = QgsSymbolLayerV2Utils::loadSymbols( symbolsElem );
953 
954  QDomElement rangeElem = rangesElem.firstChildElement();
955  while ( !rangeElem.isNull() )
956  {
957  if ( rangeElem.tagName() == "range" )
958  {
959  double lowerValue = rangeElem.attribute( "lower" ).toDouble();
960  double upperValue = rangeElem.attribute( "upper" ).toDouble();
961  QString symbolName = rangeElem.attribute( "symbol" );
962  QString label = rangeElem.attribute( "label" );
963  bool render = rangeElem.attribute( "render", "true" ) != "false";
964  if ( symbolMap.contains( symbolName ) )
965  {
966  QgsSymbolV2* symbol = symbolMap.take( symbolName );
967  ranges.append( QgsRendererRangeV2( lowerValue, upperValue, symbol, label, render ) );
968  }
969  }
970  rangeElem = rangeElem.nextSiblingElement();
971  }
972 
973  QString attrName = element.attribute( "attr" );
974 
975  QgsGraduatedSymbolRendererV2* r = new QgsGraduatedSymbolRendererV2( attrName, ranges );
976 
977  QString attrMethod = element.attribute( "graduatedMethod" );
978  if ( attrMethod.length() )
979  {
980  if ( attrMethod == graduatedMethodStr( GraduatedColor ) )
982  else if ( attrMethod == graduatedMethodStr( GraduatedSize ) )
984  }
985 
986 
987  // delete symbols if there are any more
989 
990  // try to load source symbol (optional)
991  QDomElement sourceSymbolElem = element.firstChildElement( "source-symbol" );
992  if ( !sourceSymbolElem.isNull() )
993  {
994  QgsSymbolV2Map sourceSymbolMap = QgsSymbolLayerV2Utils::loadSymbols( sourceSymbolElem );
995  if ( sourceSymbolMap.contains( "0" ) )
996  {
997  r->setSourceSymbol( sourceSymbolMap.take( "0" ) );
998  }
999  QgsSymbolLayerV2Utils::clearSymbolMap( sourceSymbolMap );
1000  }
1001 
1002  // try to load color ramp (optional)
1003  QDomElement sourceColorRampElem = element.firstChildElement( "colorramp" );
1004  if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( "name" ) == "[source]" )
1005  {
1006  r->setSourceColorRamp( QgsSymbolLayerV2Utils::loadColorRamp( sourceColorRampElem ) );
1007  QDomElement invertedColorRampElem = element.firstChildElement( "invertedcolorramp" );
1008  if ( !invertedColorRampElem.isNull() )
1009  r->setInvertedColorRamp( invertedColorRampElem.attribute( "value" ) == "1" );
1010  }
1011 
1012  // try to load mode
1013  QDomElement modeElem = element.firstChildElement( "mode" );
1014  if ( !modeElem.isNull() )
1015  {
1016  QString modeString = modeElem.attribute( "name" );
1017  if ( modeString == "equal" )
1018  r->setMode( EqualInterval );
1019  else if ( modeString == "quantile" )
1020  r->setMode( Quantile );
1021  else if ( modeString == "jenks" )
1022  r->setMode( Jenks );
1023  else if ( modeString == "stddev" )
1024  r->setMode( StdDev );
1025  else if ( modeString == "pretty" )
1026  r->setMode( Pretty );
1027  }
1028 
1029  QDomElement rotationElem = element.firstChildElement( "rotation" );
1030  if ( !rotationElem.isNull() && !rotationElem.attribute( "field" ).isEmpty() )
1031  {
1032  for ( QgsRangeList::iterator it = r->mRanges.begin(); it != r->mRanges.end(); ++it )
1033  {
1034  convertSymbolRotation( it->symbol(), rotationElem.attribute( "field" ) );
1035  }
1036  if ( r->mSourceSymbol.data() )
1037  {
1038  convertSymbolRotation( r->mSourceSymbol.data(), rotationElem.attribute( "field" ) );
1039  }
1040  }
1041 
1042  QDomElement sizeScaleElem = element.firstChildElement( "sizescale" );
1043  if ( !sizeScaleElem.isNull() && !sizeScaleElem.attribute( "field" ).isEmpty() )
1044  {
1045  for ( QgsRangeList::iterator it = r->mRanges.begin(); it != r->mRanges.end(); ++it )
1046  {
1047  convertSymbolSizeScale( it->symbol(),
1048  QgsSymbolLayerV2Utils::decodeScaleMethod( sizeScaleElem.attribute( "scalemethod" ) ),
1049  sizeScaleElem.attribute( "field" ) );
1050  }
1051  if ( r->mSourceSymbol.data() && r->mSourceSymbol->type() == QgsSymbolV2::Marker )
1052  {
1054  QgsSymbolLayerV2Utils::decodeScaleMethod( sizeScaleElem.attribute( "scalemethod" ) ),
1055  sizeScaleElem.attribute( "field" ) );
1056  }
1057  }
1058 
1059  QDomElement labelFormatElem = element.firstChildElement( "labelformat" );
1060  if ( ! labelFormatElem.isNull() )
1061  {
1063  labelFormat.setFromDomElement( labelFormatElem );
1064  r->setLabelFormat( labelFormat );
1065  }
1066  // TODO: symbol levels
1067  return r;
1068 }
1069 
1071 {
1072  QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
1073  rendererElem.setAttribute( "type", "graduatedSymbol" );
1074  rendererElem.setAttribute( "symbollevels", ( mUsingSymbolLevels ? "1" : "0" ) );
1075  rendererElem.setAttribute( "forceraster", ( mForceRaster ? "1" : "0" ) );
1076  rendererElem.setAttribute( "attr", mAttrName );
1077  rendererElem.setAttribute( "graduatedMethod", graduatedMethodStr( mGraduatedMethod ) );
1078 
1079  // ranges
1080  int i = 0;
1082  QDomElement rangesElem = doc.createElement( "ranges" );
1084  for ( ; it != mRanges.constEnd(); ++it )
1085  {
1086  const QgsRendererRangeV2& range = *it;
1087  QString symbolName = QString::number( i );
1088  symbols.insert( symbolName, range.symbol() );
1089 
1090  QDomElement rangeElem = doc.createElement( "range" );
1091  rangeElem.setAttribute( "lower", QString::number( range.lowerValue(), 'f' ) );
1092  rangeElem.setAttribute( "upper", QString::number( range.upperValue(), 'f' ) );
1093  rangeElem.setAttribute( "symbol", symbolName );
1094  rangeElem.setAttribute( "label", range.label() );
1095  rangeElem.setAttribute( "render", range.renderState() ? "true" : "false" );
1096  rangesElem.appendChild( rangeElem );
1097  i++;
1098  }
1099 
1100  rendererElem.appendChild( rangesElem );
1101 
1102  // save symbols
1103  QDomElement symbolsElem = QgsSymbolLayerV2Utils::saveSymbols( symbols, "symbols", doc );
1104  rendererElem.appendChild( symbolsElem );
1105 
1106  // save source symbol
1107  if ( mSourceSymbol.data() )
1108  {
1109  QgsSymbolV2Map sourceSymbols;
1110  sourceSymbols.insert( "0", mSourceSymbol.data() );
1111  QDomElement sourceSymbolElem = QgsSymbolLayerV2Utils::saveSymbols( sourceSymbols, "source-symbol", doc );
1112  rendererElem.appendChild( sourceSymbolElem );
1113  }
1114 
1115  // save source color ramp
1116  if ( mSourceColorRamp.data() )
1117  {
1118  QDomElement colorRampElem = QgsSymbolLayerV2Utils::saveColorRamp( "[source]", mSourceColorRamp.data(), doc );
1119  rendererElem.appendChild( colorRampElem );
1120  QDomElement invertedElem = doc.createElement( "invertedcolorramp" );
1121  invertedElem.setAttribute( "value", mInvertedColorRamp );
1122  rendererElem.appendChild( invertedElem );
1123  }
1124 
1125  // save mode
1126  QString modeString;
1127  if ( mMode == EqualInterval )
1128  modeString = "equal";
1129  else if ( mMode == Quantile )
1130  modeString = "quantile";
1131  else if ( mMode == Jenks )
1132  modeString = "jenks";
1133  else if ( mMode == StdDev )
1134  modeString = "stddev";
1135  else if ( mMode == Pretty )
1136  modeString = "pretty";
1137  if ( !modeString.isEmpty() )
1138  {
1139  QDomElement modeElem = doc.createElement( "mode" );
1140  modeElem.setAttribute( "name", modeString );
1141  rendererElem.appendChild( modeElem );
1142  }
1143 
1144  QDomElement rotationElem = doc.createElement( "rotation" );
1145  if ( mRotation.data() )
1147  rendererElem.appendChild( rotationElem );
1148 
1149  QDomElement sizeScaleElem = doc.createElement( "sizescale" );
1150  if ( mSizeScale.data() )
1152  sizeScaleElem.setAttribute( "scalemethod", QgsSymbolLayerV2Utils::encodeScaleMethod( mScaleMethod ) );
1153  rendererElem.appendChild( sizeScaleElem );
1154 
1155  QDomElement labelFormatElem = doc.createElement( "labelformat" );
1156  mLabelFormat.saveToDomElement( labelFormatElem );
1157  rendererElem.appendChild( labelFormatElem );
1158 
1159  if ( mPaintEffect )
1160  mPaintEffect->saveProperties( doc, rendererElem );
1161 
1162  return rendererElem;
1163 }
1164 
1166 {
1168  int count = ranges().count();
1169  for ( int i = 0; i < count; i++ )
1170  {
1171  const QgsRendererRangeV2& range = ranges()[i];
1172  QPixmap pix = QgsSymbolLayerV2Utils::symbolPreviewPixmap( range.symbol(), iconSize );
1173  lst << qMakePair( range.label(), pix );
1174  }
1175  return lst;
1176 }
1177 
1179 {
1180  QgsLegendSymbolListV2 list;
1181  if ( mSourceSymbol.data() && mSourceSymbol->type() == QgsSymbolV2::Marker )
1182  {
1183  // check that all symbols that have the same size expression
1184  QgsDataDefined ddSize;
1185  foreach ( QgsRendererRangeV2 range, mRanges )
1186  {
1187  const QgsMarkerSymbolV2 * symbol = static_cast<const QgsMarkerSymbolV2 *>( range.symbol() );
1188  if ( !ddSize.hasDefaultValues() && symbol->dataDefinedSize() != ddSize )
1189  {
1190  // no common size expression
1192  }
1193  else
1194  {
1195  ddSize = symbol->dataDefinedSize();
1196  }
1197  }
1198 
1199  if ( !ddSize.isActive() || !ddSize.useExpression() )
1200  {
1202  }
1203 
1204  QgsScaleExpression exp( ddSize.expressionString() );
1205  if ( exp.type() != QgsScaleExpression::Unknown )
1206  {
1207  QgsLegendSymbolItemV2 title( NULL, exp.baseExpression(), "" );
1208  list << title;
1209  foreach ( double v, QgsSymbolLayerV2Utils::prettyBreaks( exp.minValue(), exp.maxValue(), 4 ) )
1210  {
1212  QgsMarkerSymbolV2 * s = static_cast<QgsMarkerSymbolV2 *>( si.symbol() );
1214  s->setSize( exp.size( v ) );
1215  list << si;
1216  }
1217  // now list the graduated symbols
1219  foreach ( QgsLegendSymbolItemV2 item, list2 )
1220  list << item;
1221  return list;
1222  }
1223  }
1224 
1226 }
1227 
1229 {
1230  Q_UNUSED( scaleDenominator );
1231  QgsLegendSymbolList lst;
1232 
1233  foreach ( const QgsRendererRangeV2& range, mRanges )
1234  {
1235  if ( rule.isEmpty() || range.label() == rule )
1236  {
1237  lst << qMakePair( range.label(), range.symbol() );
1238  }
1239  }
1240  return lst;
1241 }
1242 
1244 {
1245  return mSourceSymbol.data();
1246 }
1248 {
1249  mSourceSymbol.reset( sym );
1250 }
1251 
1253 {
1254  return mSourceColorRamp.data();
1255 }
1256 
1258 {
1259  mSourceColorRamp.reset( ramp );
1260 }
1261 
1263 {
1264  double min = DBL_MAX;
1265  for ( int i = 0; i < mRanges.count(); i++ )
1266  {
1267  double sz = 0;
1268  if ( mRanges[i].symbol()->type() == QgsSymbolV2::Marker )
1269  sz = static_cast< QgsMarkerSymbolV2 * >( mRanges[i].symbol() )->size();
1270  else if ( mRanges[i].symbol()->type() == QgsSymbolV2::Line )
1271  sz = static_cast< QgsLineSymbolV2 * >( mRanges[i].symbol() )->width();
1272  min = qMin( sz, min );
1273  }
1274  return min;
1275 }
1276 
1278 {
1279  double max = DBL_MIN;
1280  for ( int i = 0; i < mRanges.count(); i++ )
1281  {
1282  double sz = 0;
1283  if ( mRanges[i].symbol()->type() == QgsSymbolV2::Marker )
1284  sz = static_cast< QgsMarkerSymbolV2 * >( mRanges[i].symbol() )->size();
1285  else if ( mRanges[i].symbol()->type() == QgsSymbolV2::Line )
1286  sz = static_cast< QgsLineSymbolV2 * >( mRanges[i].symbol() )->width();
1287  max = qMax( sz, max );
1288  }
1289  return max;
1290 }
1291 
1292 void QgsGraduatedSymbolRendererV2::setSymbolSizes( double minSize, double maxSize )
1293 {
1294  for ( int i = 0; i < mRanges.count(); i++ )
1295  {
1296  QScopedPointer<QgsSymbolV2> symbol( mRanges[i].symbol() ? mRanges[i].symbol()->clone() : 0 );
1297  const double size = mRanges.count() > 1
1298  ? minSize + i * ( maxSize - minSize ) / ( mRanges.count() - 1 )
1299  : .5 * ( maxSize + minSize );
1300  if ( symbol->type() == QgsSymbolV2::Marker )
1301  static_cast< QgsMarkerSymbolV2 * >( symbol.data() )->setSize( size );
1302  if ( symbol->type() == QgsSymbolV2::Line )
1303  static_cast< QgsLineSymbolV2 * >( symbol.data() )->setWidth( size );
1304  updateRangeSymbol( i, symbol.take() );
1305  }
1306 }
1307 
1309 {
1310  int i = 0;
1311  if ( ramp )
1312  {
1313  setSourceColorRamp( ramp );
1314  setInvertedColorRamp( inverted );
1315  }
1316 
1317  if ( mSourceColorRamp )
1318  {
1319  foreach ( QgsRendererRangeV2 range, mRanges )
1320  {
1321  QgsSymbolV2 *symbol = range.symbol() ? range.symbol()->clone() : 0;
1322  if ( symbol )
1323  {
1324  double colorValue;
1325  if ( inverted )
1326  colorValue = ( mRanges.count() > 1 ? ( double )( mRanges.count() - i - 1 ) / ( mRanges.count() - 1 ) : 0 );
1327  else
1328  colorValue = ( mRanges.count() > 1 ? ( double ) i / ( mRanges.count() - 1 ) : 0 );
1329  symbol->setColor( mSourceColorRamp->color( colorValue ) );
1330  }
1331  updateRangeSymbol( i, symbol );
1332  ++i;
1333  }
1334  }
1335 
1336 }
1337 
1339 {
1340  if ( !sym )
1341  return;
1342 
1343  int i = 0;
1344  foreach ( QgsRendererRangeV2 range, mRanges )
1345  {
1346  QScopedPointer<QgsSymbolV2> symbol( sym->clone() );
1348  {
1349  symbol->setColor( range.symbol()->color() );
1350  }
1351  else if ( mGraduatedMethod == GraduatedSize )
1352  {
1353  if ( symbol->type() == QgsSymbolV2::Marker )
1354  static_cast<QgsMarkerSymbolV2 *>( symbol.data() )->setSize(
1355  static_cast<QgsMarkerSymbolV2 *>( range.symbol() )->size() );
1356  else if ( symbol->type() == QgsSymbolV2::Line )
1357  static_cast<QgsLineSymbolV2 *>( symbol.data() )->setWidth(
1358  static_cast<QgsLineSymbolV2 *>( range.symbol() )->width() );
1359  }
1360  updateRangeSymbol( i, symbol.take() );
1361  ++i;
1362  }
1363  setSourceSymbol( sym->clone() );
1364 }
1365 
1367 {
1368  if ( mSourceSymbol->type() == QgsSymbolV2::Marker )
1369  {
1370  QgsMarkerSymbolV2 * s = static_cast<QgsMarkerSymbolV2 *>( mSourceSymbol.data() );
1371  s->setDataDefinedAngle( QgsDataDefined( fieldOrExpression ) );
1372  }
1373 
1374 }
1375 
1377 {
1378  if ( mSourceSymbol->type() == QgsSymbolV2::Marker )
1379  {
1380  QgsMarkerSymbolV2 * s = static_cast<QgsMarkerSymbolV2 *>( mSourceSymbol.data() );
1381  QgsDataDefined ddAngle = s->dataDefinedAngle();
1382  return ddAngle.useExpression() ? ddAngle.expressionString() : ddAngle.field();
1383  }
1384 
1385  return QString();
1386 }
1387 
1389 {
1391 }
1392 
1394 {
1396 }
1397 
1399 {
1401  for ( QgsRangeList::iterator it = mRanges.begin(); it != mRanges.end(); ++it )
1402  {
1403  if ( it->symbol() )
1404  setScaleMethodToSymbol( it->symbol(), scaleMethod );
1405  }
1406 }
1407 
1409 {
1410  return true;
1411 }
1412 
1414 {
1415  bool ok;
1416  int index = key.toInt( &ok );
1417  if ( ok && index >= 0 && index < mRanges.size() )
1418  return mRanges[ index ].renderState();
1419  else
1420  return true;
1421 }
1422 
1424 {
1425  bool ok;
1426  int index = key.toInt( &ok );
1427  if ( ok )
1428  updateRangeRenderState( index, state );
1429 }
1430 
1431 
1433 {
1434  QgsSymbolV2* newSymbol = symbol->clone();
1435  QString label = "0.0 - 0.0";
1436  mRanges.insert( 0, QgsRendererRangeV2( 0.0, 0.0, newSymbol, label ) );
1437 }
1438 
1439 void QgsGraduatedSymbolRendererV2::addClass( double lower, double upper )
1440 {
1441  QgsSymbolV2* newSymbol = mSourceSymbol->clone();
1442  QString label = mLabelFormat.labelForRange( lower, upper );
1443  mRanges.append( QgsRendererRangeV2( lower, upper, newSymbol, label ) );
1444 }
1445 
1446 void QgsGraduatedSymbolRendererV2::addBreak( double breakValue, bool updateSymbols )
1447 {
1449  while ( it.hasNext() )
1450  {
1451  QgsRendererRangeV2 range = it.next();
1452  if ( range.lowerValue() < breakValue && range.upperValue() > breakValue )
1453  {
1455  newRange.setLowerValue( breakValue );
1456  newRange.setUpperValue( range.upperValue() );
1457  newRange.setLabel( mLabelFormat.labelForRange( newRange ) );
1458  newRange.setSymbol( mSourceSymbol->clone() );
1459 
1460  //update old range
1461  bool isDefaultLabel = range.label() == mLabelFormat.labelForRange( range );
1462  range.setUpperValue( breakValue );
1463  if ( isDefaultLabel ) range.setLabel( mLabelFormat.labelForRange( range.lowerValue(), breakValue ) );
1464  it.setValue( range );
1465 
1466  it.insert( newRange );
1467  break;
1468  }
1469  }
1470 
1471  if ( updateSymbols )
1472  {
1473  switch ( mGraduatedMethod )
1474  {
1475  case GraduatedColor:
1477  break;
1478  case GraduatedSize:
1480  break;
1481  }
1482  }
1483 }
1484 
1486 {
1487  mRanges.append( range );
1488 }
1489 
1491 {
1492  mRanges.removeAt( idx );
1493 }
1494 
1496 {
1497  mRanges.clear();
1498 }
1499 
1501 {
1502  if ( updateRanges && labelFormat != mLabelFormat )
1503  {
1504  for ( QgsRangeList::iterator it = mRanges.begin(); it != mRanges.end(); ++it )
1505  {
1506  it->setLabel( labelFormat.labelForRange( *it ) );
1507  }
1508  }
1510 }
1511 
1512 
1514 {
1515  // Find the minimum size of a class
1516  double minClassRange = 0.0;
1517  for ( QgsRangeList::iterator it = mRanges.begin(); it != mRanges.end(); ++it )
1518  {
1519  double range = it->upperValue() - it->lowerValue();
1520  if ( range <= 0.0 )
1521  continue;
1522  if ( minClassRange == 0.0 || range < minClassRange )
1523  minClassRange = range;
1524  }
1525  if ( minClassRange <= 0.0 )
1526  return;
1527 
1528  // Now set the number of decimal places to ensure no more than 20% error in
1529  // representing this range (up to 10% at upper and lower end)
1530 
1531  int ndp = 10;
1532  double nextDpMinRange = 0.0000000099;
1533  while ( ndp > 0 && nextDpMinRange < minClassRange )
1534  {
1535  ndp--;
1536  nextDpMinRange *= 10.0;
1537  }
1538  mLabelFormat.setPrecision( ndp );
1539  if ( updateRanges ) setLabelFormat( mLabelFormat, true );
1540 }
1541 
1543 {
1544  if ( from < 0 || from >= mRanges.size() || to < 0 || to >= mRanges.size() )
1545  return;
1546  mRanges.move( from, to );
1547 }
1548 
1550 {
1551  return r1 < r2;
1552 }
1553 
1555 {
1556  return !valueLessThan( r1, r2 );
1557 }
1558 
1560 {
1561  QgsDebugMsg( "Entered" );
1562  if ( order == Qt::AscendingOrder )
1563  {
1564  qSort( mRanges.begin(), mRanges.end(), valueLessThan );
1565  }
1566  else
1567  {
1568  qSort( mRanges.begin(), mRanges.end(), valueGreaterThan );
1569  }
1570 }
1571 
1573 {
1574  QgsRangeList sortedRanges = mRanges;
1575  qSort( sortedRanges.begin(), sortedRanges.end(), valueLessThan );
1576 
1577  QgsRangeList::const_iterator it = sortedRanges.constBegin();
1578  if ( it == sortedRanges.constEnd() )
1579  return false;
1580 
1581  if (( *it ).upperValue() < ( *it ).lowerValue() )
1582  return true;
1583 
1584  double prevMax = ( *it ).upperValue();
1585  it++;
1586 
1587  for ( ; it != sortedRanges.constEnd(); ++it )
1588  {
1589  if (( *it ).upperValue() < ( *it ).lowerValue() )
1590  return true;
1591 
1592  if (( *it ).lowerValue() < prevMax )
1593  return true;
1594 
1595  prevMax = ( *it ).upperValue();
1596  }
1597  return false;
1598 }
1599 
1601 {
1602  QgsRangeList sortedRanges = mRanges;
1603  qSort( sortedRanges.begin(), sortedRanges.end(), valueLessThan );
1604 
1605  QgsRangeList::const_iterator it = sortedRanges.constBegin();
1606  if ( it == sortedRanges.constEnd() )
1607  return false;
1608 
1609  double prevMax = ( *it ).upperValue();
1610  it++;
1611 
1612  for ( ; it != sortedRanges.constEnd(); ++it )
1613  {
1614  if ( !qgsDoubleNear(( *it ).lowerValue(), prevMax ) )
1615  return true;
1616 
1617  prevMax = ( *it ).upperValue();
1618  }
1619  return false;
1620 }
1621 
1623 {
1624  return QString::localeAwareCompare( r1.label(), r2.label() ) < 0;
1625 }
1626 
1628 {
1629  return !labelLessThan( r1, r2 );
1630 }
1631 
1633 {
1634  if ( order == Qt::AscendingOrder )
1635  {
1636  qSort( mRanges.begin(), mRanges.end(), labelLessThan );
1637  }
1638  else
1639  {
1640  qSort( mRanges.begin(), mRanges.end(), labelGreaterThan );
1641  }
1642 }
1643 
1645 {
1646  if ( renderer->type() == "graduatedSymbol" )
1647  {
1648  return dynamic_cast<QgsGraduatedSymbolRendererV2*>( renderer->clone() );
1649  }
1650  if ( renderer->type() == "pointDisplacement" )
1651  {
1652  const QgsPointDisplacementRenderer* pointDisplacementRenderer = dynamic_cast<const QgsPointDisplacementRenderer*>( renderer );
1653  if ( pointDisplacementRenderer )
1654  return convertFromRenderer( pointDisplacementRenderer->embeddedRenderer() );
1655  }
1656  if ( renderer->type() == "invertedPolygonRenderer" )
1657  {
1658  const QgsInvertedPolygonRenderer* invertedPolygonRenderer = dynamic_cast<const QgsInvertedPolygonRenderer*>( renderer );
1659  if ( invertedPolygonRenderer )
1660  return convertFromRenderer( invertedPolygonRenderer->embeddedRenderer() );
1661  }
1662 
1663  // If not one of the specifically handled renderers, then just grab the symbol from the renderer
1664  // Could have applied this to specific renderer types (singleSymbol, graduatedSymbo)
1665 
1667  QgsRenderContext context;
1668  QgsSymbolV2List symbols = const_cast<QgsFeatureRendererV2 *>( renderer )->symbols( context );
1669  if ( symbols.size() > 0 )
1670  {
1671  r->setSourceSymbol( symbols.at( 0 )->clone() );
1672  }
1673 
1674  return r;
1675 }
1676 
1678 {
1679  switch ( method )
1680  {
1681  case GraduatedColor: return "GraduatedColor";
1682  case GraduatedSize: return "GraduatedSize";
1683  }
1684  return "";
1685 }
1686 
1687 
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:88
QList< QgsRendererRangeV2 > QgsRangeList
void clear()
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:48
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
QString & append(QChar ch)
void setLowerValue(double lowerValue)
void setSymbolSizes(double minSize, double maxSize)
set varying symbol size for classes
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
Definition: qgsexpression.h:95
QStringList referencedColumns() const
Get list of columns referenced by the expression.
Q_DECL_DEPRECATED void setRotationField(QString fieldOrExpression) override
sets rotation field of renderer (if supported by the renderer)
void addBreak(double breakValue, bool updateSymbols=true)
Add a breakpoint by splitting existing classes so that the specified value becomes a break between tw...
void setDataDefinedAngle(const QgsDataDefined &dd)
Set data defined angle for whole symbol (including all symbol layers).
A container class for data source field mapping or expression.
void setLabelFormat(const QgsRendererRangeV2LabelFormat &labelFormat, bool updateRanges=false)
Set the label format used to generate default classification labels.
static QList< double > prettyBreaks(double minimum, double maximum, int classes)
Computes a sequence of about 'classes' equally spaced round values which cover the range of values fr...
bool labelLessThan(const QgsRendererRangeV2 &r1, const QgsRendererRangeV2 &r2)
bool contains(const Key &key) const
static QgsGraduatedSymbolRendererV2 * convertFromRenderer(const QgsFeatureRendererV2 *renderer)
creates a QgsGraduatedSymbolRendererV2 from an existing renderer.
static QgsVectorColorRampV2 * loadColorRamp(QDomElement &element)
int localeAwareCompare(const QString &other) const
void updateClasses(QgsVectorLayer *vlayer, Mode mode, int nclasses)
Recalculate classes for a layer.
bool updateRangeLabel(int rangeIndex, QString label)
static QList< double > _calcStdDevBreaks(QList< double > values, int classes, QList< double > &labels)
virtual QString dump() const override
for debugging
QDomNode appendChild(const QDomNode &newChild)
SymbolType type() const
Definition: qgssymbolv2.h:86
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
QString field() const
Get the field which this QgsDataDefined represents.
QString attribute(const QString &name, const QString &defValue) const
void updateSymbols(QgsSymbolV2 *sym)
Update all the symbols but leave breaks and colors.
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
void setDataDefinedSize(const QgsDataDefined &dd)
Set data defined size for whole symbol (including all symbol layers).
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:356
double rendererScale() const
virtual QgsSymbolV2 * clone() const =0
Class storing parameters of a scale expression, which is a subclass of QgsExpression for expressions ...
virtual QgsFeatureRendererV2 * clone() const override
QgsDataDefined dataDefinedSize() const
Returns data defined size for whole symbol (including all symbol layers).
bool updateRangeRenderState(int rangeIndex, bool render)
virtual QgsSymbolV2 * symbolForFeature(QgsFeature &feature, QgsRenderContext &context) override
To be overridden.
const T & at(int i) const
void removeAt(int i)
QString labelForRange(double lower, double upper) const
void setSizeScaleField(QString fieldOrExpression)
QDomElement nextSiblingElement(const QString &tagName) const
double minSymbolSize() const
return the min symbol size when graduated by size
Container of fields for a vector layer.
Definition: qgsfield.h:177
QString expressionString() const
Returns the expression string of this QgsDataDefined.
void move(int from, int to)
QVector< T > toVector() const
QHash< QgsSymbolV2 *, QgsSymbolV2 * > mTempSymbols
temporary symbols, used for data-defined rotation and scaling
QSet< T > toSet() const
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:162
void setScaleMethod(QgsSymbolV2::ScaleMethod scaleMethod)
double toDouble(bool *ok) const
QVariant minimumValue(int index)
Returns minimum value for an attribute column or invalid variant in case of error.
void setValue(const T &value) const
virtual bool legendSymbolItemChecked(QString key) override
item in symbology was checked
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Definition: qgis.h:350
static const char * graduatedMethodStr(GraduatedMethod method)
QgsPaintEffect * mPaintEffect
void setWidth(double width)
int size() const
void reset(T *other)
Q_DECL_DEPRECATED 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:82
double ANALYSIS_EXPORT max(double x, double y)
Returns the maximum of two doubles or the first argument if both are equal.
virtual void stopRender(QgsRenderContext &context) override
QScopedPointer< QgsExpression > mExpression
void setColor(const QColor &color)
bool rangesHaveGaps() const
Tests whether classes assigned to the renderer have gaps between the ranges.
virtual QgsFeatureRendererV2 * clone() const =0
QString number(int n, int base)
int count(const T &value) const
void setGraduatedMethod(GraduatedMethod method)
set the method used for graduation (either size or color)
void append(const T &value)
static QDomElement saveColorRamp(QString name, QgsVectorColorRampV2 *ramp, QDomDocument &doc)
QgsSymbolV2::ScaleMethod scaleMethod() const
void resize(int size)
void sortByLabel(Qt::SortOrder order=Qt::AscendingOrder)
bool isNull() const
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
QgsAttributes attributes() const
Returns the feature's attributes.
Definition: qgsfeature.cpp:90
void setAttribute(const QString &name, const QString &value)
#define DEFAULT_SCALE_METHOD
virtual QgsVectorColorRampV2 * clone() const =0
void swap(QgsRendererRangeV2 &other)
static bool createFunctionElement(QDomDocument &doc, QDomElement &element, QString function)
int toInt(bool *ok, int base) const
bool isEmpty() const
static QDomElement saveSymbols(QgsSymbolV2Map &symbols, QString tagName, QDomDocument &doc)
bool isEmpty() const
iterator begin()
Q_DECL_DEPRECATED QString rotationField() const override
return rotation field name (or empty string if not set or not supported by renderer) ...
QgsSymbolV2 * symbol() const
GraduatedMethod graduatedMethod() const
return the method used for graduation (either size or color)
void setAngle(double angle)
bool updateRangeLowerValue(int rangeIndex, double value)
void setSize(double size)
void toSld(QDomDocument &doc, QDomElement &element, QgsStringMap props) const
QgsRendererRangeV2LabelFormat mLabelFormat
QGis::GeometryType geometryType() const
Returns point, line or polygon.
T & first()
virtual Q_DECL_DEPRECATED QgsSymbolV2List symbols()
for symbol levels
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)
static void convertSymbolSizeScale(QgsSymbolV2 *symbol, QgsSymbolV2::ScaleMethod method, const QString &field)
bool labelGreaterThan(const QgsRendererRangeV2 &r1, const QgsRendererRangeV2 &r2)
QgsFeatureRendererV2 * embeddedRenderer() const
bool useExpression() const
Returns if the field or the expression part is active.
QDomText createTextNode(const QString &value)
T * data() const
void clear()
bool valueLessThan(const QgsRendererRangeV2 &r1, const QgsRendererRangeV2 &r2)
iterator end()
const T value(const Key &key) const
QList< double > getDoubleValues(const QString &fieldOrExpression, bool &ok, bool selectedOnly=false, int *nullCount=0)
Fetches all double values from a specified field name or expression.
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)
bool hasNext() const
QgsExpressionContext & expressionContext()
Gets the expression context.
A renderer that automatically displaces points with the same position.
virtual bool legendSymbolItemsCheckable() const override
items of symbology items in legend should be checkable
bool isNull() const
void setUsingSymbolLevels(bool usingSymbolLevels)
QString & replace(int position, int n, QChar after)
bool rangesOverlap() const
Tests whether classes assigned to the renderer have ranges which overlap.
static QList< double > _calcEqualIntervalBreaks(double minimum, double maximum, int classes)
virtual bool saveProperties(QDomDocument &doc, QDomElement &element) const
Saves the current state of the effect to a DOM element.
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)
QList< T > toList() const
QgsDataDefined dataDefinedAngle() const
Returns data defined angle for whole symbol (including all symbol layers).
QString mid(int position, int n) const
void copyPaintEffect(QgsFeatureRendererV2 *destRenderer) const
Copies paint effect of this renderer to another renderer.
QSet< T > & unite(const QSet< T > &other)
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.
void insert(int i, const T &value)
double maxSymbolSize() const
return the max symbol size when graduated by size
const QgsRangeList & ranges() const
virtual QgsLegendSymbolListV2 legendSymbolItemsV2() const
Return a list of symbology items for the legend.
bool operator!=(const QgsRendererRangeV2LabelFormat &other) const
static QString encodeScaleMethod(QgsSymbolV2::ScaleMethod scaleMethod)
QDomElement firstChildElement(const QString &tagName) const
static QString fieldOrExpressionFromExpression(QgsExpression *expression)
Return a field name if the whole expression is just a name of the field .
bool usingSymbolLevels() const
T & last()
void setScaleMethodToSymbol(QgsSymbolV2 *symbol, int scaleMethod)
int count(const T &value) const
bool updateRangeSymbol(int rangeIndex, QgsSymbolV2 *symbol)
int length() const
void setSourceColorRamp(QgsVectorColorRampV2 *ramp)
QScopedPointer< QgsSymbolV2 > mSourceSymbol
QList< T > toList() const
void setRenderHints(int hints)
Definition: qgssymbolv2.h:182
static void clearSymbolMap(QgsSymbolV2Map &symbols)
void setTrimTrailingZeroes(bool trimTrailingZeroes)
bool updateRangeUpperValue(int rangeIndex, double value)
static QgsSymbolV2::ScaleMethod decodeScaleMethod(QString str)
QScopedPointer< QgsExpression > mRotation
double toDouble(bool *ok) const
virtual QgsSymbolV2 * originalSymbolForFeature(QgsFeature &feature, QgsRenderContext &context) override
Return symbol for feature.
iterator insert(const Key &key, const T &value)
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
QString tagName() const
bool hasDefaultValues() const
Returns whether the data defined container is set to all the default values, ie, disabled, with empty expression and no assigned field.
virtual QList< QString > usedAttributes() override
double ANALYSIS_EXPORT min(double x, double y)
Returns the minimum of two doubles or the first argument if both are equal.
iterator end()
const_iterator constEnd() const
QScopedPointer< QgsExpression > mSizeScale
QDomElement createElement(const QString &tagName)
const_iterator constBegin() const
QgsRendererRangeV2 & operator=(QgsRendererRangeV2 range)
static QPixmap symbolPreviewPixmap(QgsSymbolV2 *symbol, QSize size, QgsRenderContext *customContext=0)
A vector of attributes.
Definition: qgsfeature.h:109
void insert(const T &value)
int size() const
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.
bool exactMatch(const QString &str) const
The class stores information about one class/rule of a vector layer renderer in a unified way that ca...
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
bool isActive() const
virtual void checkLegendSymbolItem(QString key, bool state=true) override
item in symbology was checked
iterator begin()
T take(const Key &key)
void setScaleMethod(QgsSymbolV2::ScaleMethod scaleMethod)
QgsLegendSymbolListV2 legendSymbolItemsV2() const override
void updateColorRamp(QgsVectorColorRampV2 *ramp=0, bool inverted=false)
Update the color ramp used.
bool valueGreaterThan(const QgsRendererRangeV2 &r1, const QgsRendererRangeV2 &r2)
const T value(const Key &key) const
virtual void startRender(QgsRenderContext &context, const QgsFields &fields) override
Needs to be called when a new render cycle is started.
static void convertSymbolRotation(QgsSymbolV2 *symbol, const QString &field)
QColor color() const