QGIS API Documentation  2.11.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties 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 #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 );
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( feature ).toDouble() : 0;
330  const double sizeScale = mSizeScale.data() ? mSizeScale->evaluate( feature ).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  QgsAttributes attrs = feature.attributes();
354  QVariant value;
355  if ( mAttrNum < 0 || mAttrNum >= attrs.count() )
356  {
357  value = mExpression->evaluate( &feature );
358  }
359  else
360  {
361  value = attrs[mAttrNum];
362  }
363 
364  // Null values should not be categorized
365  if ( value.isNull() )
366  return NULL;
367 
368  // find the right category
369  return symbolForValue( value.toDouble() );
370 }
371 
373 {
374  mCounting = context.rendererScale() == 0.0;
375 
376  // find out classification attribute index from name
377  mAttrNum = fields.fieldNameIndex( mAttrName );
378 
379  if ( mAttrNum == -1 )
380  {
382  mExpression->prepare( fields );
383  }
384 
386  for ( ; it != mRanges.end(); ++it )
387  {
388  if ( !it->symbol() )
389  continue;
390 
391  it->symbol()->startRender( context, &fields );
392 
393  if ( mRotation.data() || mSizeScale.data() )
394  {
395  QgsSymbolV2* tempSymbol = it->symbol()->clone();
398  tempSymbol->startRender( context, &fields );
399  mTempSymbols[ it->symbol()] = tempSymbol;
400  }
401  }
402  return;
403 }
404 
406 {
408  for ( ; it != mRanges.end(); ++it )
409  {
410  if ( !it->symbol() )
411  continue;
412 
413  it->symbol()->stopRender( context );
414  }
415 
416  // cleanup mTempSymbols
418  for ( ; it2 != mTempSymbols.end(); ++it2 )
419  {
420  it2.value()->stopRender( context );
421  delete it2.value();
422  }
424 }
425 
427 {
428  QSet<QString> attributes;
429 
430  // mAttrName can contain either attribute name or an expression.
431  // Sometimes it is not possible to distinguish between those two,
432  // e.g. "a - b" can be both a valid attribute name or expression.
433  // Since we do not have access to fields here, try both options.
434  attributes << mAttrName;
435 
436  QgsExpression testExpr( mAttrName );
437  if ( !testExpr.hasParserError() )
438  attributes.unite( testExpr.referencedColumns().toSet() );
439 
440  if ( mRotation.data() ) attributes.unite( mRotation->referencedColumns().toSet() );
441  if ( mSizeScale.data() ) attributes.unite( mSizeScale->referencedColumns().toSet() );
442 
444  for ( ; range_it != mRanges.constEnd(); ++range_it )
445  {
446  QgsSymbolV2* symbol = range_it->symbol();
447  if ( symbol )
448  {
449  attributes.unite( symbol->usedAttributes() );
450  }
451  }
452  return attributes.toList();
453 }
454 
456 {
457  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
458  return false;
459  mRanges[rangeIndex].setSymbol( symbol );
460  return true;
461 }
462 
464 {
465  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
466  return false;
467  mRanges[rangeIndex].setLabel( label );
468  return true;
469 }
470 
471 bool QgsGraduatedSymbolRendererV2::updateRangeUpperValue( int rangeIndex, double value )
472 {
473  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
474  return false;
475  QgsRendererRangeV2 &range = mRanges[rangeIndex];
476  bool isDefaultLabel = range.label() == mLabelFormat.labelForRange( range );
477  range.setUpperValue( value );
478  if ( isDefaultLabel ) range.setLabel( mLabelFormat.labelForRange( range ) );
479  return true;
480 }
481 
482 bool QgsGraduatedSymbolRendererV2::updateRangeLowerValue( int rangeIndex, double value )
483 {
484  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
485  return false;
486  QgsRendererRangeV2 &range = mRanges[rangeIndex];
487  bool isDefaultLabel = range.label() == mLabelFormat.labelForRange( range );
488  range.setLowerValue( value );
489  if ( isDefaultLabel ) range.setLabel( mLabelFormat.labelForRange( range ) );
490  return true;
491 }
492 
494 {
495  if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
496  return false;
497  mRanges[rangeIndex].setRenderState( value );
498  return true;
499 }
500 
502 {
503  QString s = QString( "GRADUATED: attr %1\n" ).arg( mAttrName );
504  for ( int i = 0; i < mRanges.count(); i++ )
505  s += mRanges[i].dump();
506  return s;
507 }
508 
510 {
512  r->setMode( mMode );
513  if ( mSourceSymbol.data() )
514  r->setSourceSymbol( mSourceSymbol->clone() );
515  if ( mSourceColorRamp.data() )
516  {
517  r->setSourceColorRamp( mSourceColorRamp->clone() );
519  }
523  //r->setScaleMethod( scaleMethod() );
524  r->setLabelFormat( labelFormat() );
526  copyPaintEffect( r );
527  return r;
528 }
529 
531 {
532  QgsStringMap props;
533  props[ "attribute" ] = mAttrName;
534  props[ "method" ] = graduatedMethodStr( mGraduatedMethod );
535  if ( mRotation.data() )
536  props[ "angle" ] = mRotation->expression();
537  if ( mSizeScale.data() )
538  props[ "scale" ] = mSizeScale->expression();
539 
540  // create a Rule for each range
541  for ( QgsRangeList::const_iterator it = mRanges.constBegin(); it != mRanges.constEnd(); ++it )
542  {
543  QgsStringMap catProps( props );
544  it->toSld( doc, element, catProps );
545  }
546 }
547 
549 {
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 {
1369 }
1370 
1372 {
1374 }
1375 
1377 {
1379 }
1380 
1382 {
1384 }
1385 
1387 {
1389  for ( QgsRangeList::iterator it = mRanges.begin(); it != mRanges.end(); ++it )
1390  {
1391  if ( it->symbol() )
1392  setScaleMethodToSymbol( it->symbol(), scaleMethod );
1393  }
1394 }
1395 
1397 {
1398  return true;
1399 }
1400 
1402 {
1403  bool ok;
1404  int index = key.toInt( &ok );
1405  if ( ok && index >= 0 && index < mRanges.size() )
1406  return mRanges[ index ].renderState();
1407  else
1408  return true;
1409 }
1410 
1412 {
1413  bool ok;
1414  int index = key.toInt( &ok );
1415  if ( ok )
1416  updateRangeRenderState( index, state );
1417 }
1418 
1419 
1421 {
1422  QgsSymbolV2* newSymbol = symbol->clone();
1423  QString label = "0.0 - 0.0";
1424  mRanges.insert( 0, QgsRendererRangeV2( 0.0, 0.0, newSymbol, label ) );
1425 }
1426 
1427 void QgsGraduatedSymbolRendererV2::addClass( double lower, double upper )
1428 {
1429  QgsSymbolV2* newSymbol = mSourceSymbol->clone();
1430  QString label = mLabelFormat.labelForRange( lower, upper );
1431  mRanges.append( QgsRendererRangeV2( lower, upper, newSymbol, label ) );
1432 }
1433 
1434 void QgsGraduatedSymbolRendererV2::addBreak( double breakValue, bool updateSymbols )
1435 {
1437  while ( it.hasNext() )
1438  {
1439  QgsRendererRangeV2 range = it.next();
1440  if ( range.lowerValue() < breakValue && range.upperValue() > breakValue )
1441  {
1443  newRange.setLowerValue( breakValue );
1444  newRange.setUpperValue( range.upperValue() );
1445  newRange.setLabel( mLabelFormat.labelForRange( newRange ) );
1446  newRange.setSymbol( mSourceSymbol->clone() );
1447 
1448  //update old range
1449  bool isDefaultLabel = range.label() == mLabelFormat.labelForRange( range );
1450  range.setUpperValue( breakValue );
1451  if ( isDefaultLabel ) range.setLabel( mLabelFormat.labelForRange( range.lowerValue(), breakValue ) );
1452  it.setValue( range );
1453 
1454  it.insert( newRange );
1455  break;
1456  }
1457  }
1458 
1459  if ( updateSymbols )
1460  {
1461  switch ( mGraduatedMethod )
1462  {
1463  case GraduatedColor:
1465  break;
1466  case GraduatedSize:
1468  break;
1469  }
1470  }
1471 }
1472 
1474 {
1475  mRanges.append( range );
1476 }
1477 
1479 {
1480  mRanges.removeAt( idx );
1481 }
1482 
1484 {
1485  mRanges.clear();
1486 }
1487 
1489 {
1490  if ( updateRanges && labelFormat != mLabelFormat )
1491  {
1492  for ( QgsRangeList::iterator it = mRanges.begin(); it != mRanges.end(); ++it )
1493  {
1494  it->setLabel( labelFormat.labelForRange( *it ) );
1495  }
1496  }
1498 }
1499 
1500 
1502 {
1503  // Find the minimum size of a class
1504  double minClassRange = 0.0;
1505  for ( QgsRangeList::iterator it = mRanges.begin(); it != mRanges.end(); ++it )
1506  {
1507  double range = it->upperValue() - it->lowerValue();
1508  if ( range <= 0.0 )
1509  continue;
1510  if ( minClassRange == 0.0 || range < minClassRange )
1511  minClassRange = range;
1512  }
1513  if ( minClassRange <= 0.0 )
1514  return;
1515 
1516  // Now set the number of decimal places to ensure no more than 20% error in
1517  // representing this range (up to 10% at upper and lower end)
1518 
1519  int ndp = 10;
1520  double nextDpMinRange = 0.0000000099;
1521  while ( ndp > 0 && nextDpMinRange < minClassRange )
1522  {
1523  ndp--;
1524  nextDpMinRange *= 10.0;
1525  }
1526  mLabelFormat.setPrecision( ndp );
1527  if ( updateRanges ) setLabelFormat( mLabelFormat, true );
1528 }
1529 
1531 {
1532  if ( from < 0 || from >= mRanges.size() || to < 0 || to >= mRanges.size() )
1533  return;
1534  mRanges.move( from, to );
1535 }
1536 
1538 {
1539  return r1 < r2;
1540 }
1541 
1543 {
1544  return !valueLessThan( r1, r2 );
1545 }
1546 
1548 {
1549  QgsDebugMsg( "Entered" );
1550  if ( order == Qt::AscendingOrder )
1551  {
1552  qSort( mRanges.begin(), mRanges.end(), valueLessThan );
1553  }
1554  else
1555  {
1556  qSort( mRanges.begin(), mRanges.end(), valueGreaterThan );
1557  }
1558 }
1559 
1561 {
1562  QgsRangeList sortedRanges = mRanges;
1563  qSort( sortedRanges.begin(), sortedRanges.end(), valueLessThan );
1564 
1565  QgsRangeList::const_iterator it = sortedRanges.constBegin();
1566  if ( it == sortedRanges.constEnd() )
1567  return false;
1568 
1569  if (( *it ).upperValue() < ( *it ).lowerValue() )
1570  return true;
1571 
1572  double prevMax = ( *it ).upperValue();
1573  it++;
1574 
1575  for ( ; it != sortedRanges.constEnd(); ++it )
1576  {
1577  if (( *it ).upperValue() < ( *it ).lowerValue() )
1578  return true;
1579 
1580  if (( *it ).lowerValue() < prevMax )
1581  return true;
1582 
1583  prevMax = ( *it ).upperValue();
1584  }
1585  return false;
1586 }
1587 
1589 {
1590  QgsRangeList sortedRanges = mRanges;
1591  qSort( sortedRanges.begin(), sortedRanges.end(), valueLessThan );
1592 
1593  QgsRangeList::const_iterator it = sortedRanges.constBegin();
1594  if ( it == sortedRanges.constEnd() )
1595  return false;
1596 
1597  double prevMax = ( *it ).upperValue();
1598  it++;
1599 
1600  for ( ; it != sortedRanges.constEnd(); ++it )
1601  {
1602  if ( !qgsDoubleNear(( *it ).lowerValue(), prevMax ) )
1603  return true;
1604 
1605  prevMax = ( *it ).upperValue();
1606  }
1607  return false;
1608 }
1609 
1611 {
1612  return QString::localeAwareCompare( r1.label(), r2.label() ) < 0;
1613 }
1614 
1616 {
1617  return !labelLessThan( r1, r2 );
1618 }
1619 
1621 {
1622  if ( order == Qt::AscendingOrder )
1623  {
1624  qSort( mRanges.begin(), mRanges.end(), labelLessThan );
1625  }
1626  else
1627  {
1628  qSort( mRanges.begin(), mRanges.end(), labelGreaterThan );
1629  }
1630 }
1631 
1633 {
1634  if ( renderer->type() == "graduatedSymbol" )
1635  {
1636  return dynamic_cast<QgsGraduatedSymbolRendererV2*>( renderer->clone() );
1637  }
1638  if ( renderer->type() == "pointDisplacement" )
1639  {
1640  const QgsPointDisplacementRenderer* pointDisplacementRenderer = dynamic_cast<const QgsPointDisplacementRenderer*>( renderer );
1641  if ( pointDisplacementRenderer )
1642  return convertFromRenderer( pointDisplacementRenderer->embeddedRenderer() );
1643  }
1644  if ( renderer->type() == "invertedPolygonRenderer" )
1645  {
1646  const QgsInvertedPolygonRenderer* invertedPolygonRenderer = dynamic_cast<const QgsInvertedPolygonRenderer*>( renderer );
1647  if ( invertedPolygonRenderer )
1648  return convertFromRenderer( invertedPolygonRenderer->embeddedRenderer() );
1649  }
1650 
1651  // If not one of the specifically handled renderers, then just grab the symbol from the renderer
1652  // Could have applied this to specific renderer types (singleSymbol, graduatedSymbo)
1653 
1655  QgsSymbolV2List symbols = const_cast<QgsFeatureRendererV2 *>( renderer )->symbols();
1656  if ( symbols.size() > 0 )
1657  {
1658  r->setSourceSymbol( symbols.at( 0 )->clone() );
1659  }
1660 
1661  return r;
1662 }
1663 
1665 {
1666  switch ( method )
1667  {
1668  case GraduatedColor: return "GraduatedColor";
1669  case GraduatedSize: return "GraduatedSize";
1670  }
1671  return "";
1672 }
1673 
1674 
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:86
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:93
QStringList referencedColumns() const
Get list of columns referenced by the expression.
void setRotationField(QString fieldOrExpression) override
sets rotation field of renderer (if supported by the renderer)
void addBreak(double breakValue, bool updateSymbols=true)
Add a breakpoint by splitting existing classes so that the specified value becomes a break between tw...
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 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:354
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)
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:173
virtual QgsSymbolV2 * originalSymbolForFeature(QgsFeature &feature) override
Return symbol for feature.
QString expressionString() const
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)
virtual QgsSymbolV2 * symbolForFeature(QgsFeature &feature) override
To be overridden.
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
virtual QgsSymbolV2List symbols() override
for symbol levels
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()
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()
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
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
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
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
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