Quantum GIS API Documentation  1.8
src/core/symbology-ng/qgsgraduatedsymbolrendererv2.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002     qgsgraduatedsymbolrendererv2.cpp
00003     ---------------------
00004     begin                : November 2009
00005     copyright            : (C) 2009 by Martin Dobias
00006     email                : wonder.sk at gmail.com
00007  ***************************************************************************
00008  *                                                                         *
00009  *   This program is free software; you can redistribute it and/or modify  *
00010  *   it under the terms of the GNU General Public License as published by  *
00011  *   the Free Software Foundation; either version 2 of the License, or     *
00012  *   (at your option) any later version.                                   *
00013  *                                                                         *
00014  ***************************************************************************/
00015 #include "qgsgraduatedsymbolrendererv2.h"
00016 
00017 #include "qgssymbolv2.h"
00018 #include "qgssymbollayerv2utils.h"
00019 #include "qgsvectorcolorrampv2.h"
00020 
00021 #include "qgsfeature.h"
00022 #include "qgsvectorlayer.h"
00023 #include "qgslogger.h"
00024 #include "qgsvectordataprovider.h"
00025 
00026 #include <QDomDocument>
00027 #include <QDomElement>
00028 #include <QSettings> // for legend
00029 #include <limits> // for jenks classification
00030 #include <cmath> // for pretty classification
00031 #include <ctime>
00032 
00033 QgsRendererRangeV2::QgsRendererRangeV2( double lowerValue, double upperValue, QgsSymbolV2* symbol, QString label )
00034     : mLowerValue( lowerValue )
00035     , mUpperValue( upperValue )
00036     , mSymbol( symbol )
00037     , mLabel( label )
00038 {
00039 }
00040 
00041 QgsRendererRangeV2::QgsRendererRangeV2( const QgsRendererRangeV2& range )
00042     : mLowerValue( range.mLowerValue )
00043     , mUpperValue( range.mUpperValue )
00044     , mLabel( range.mLabel )
00045 {
00046   mSymbol = range.mSymbol->clone();
00047 }
00048 
00049 QgsRendererRangeV2::~QgsRendererRangeV2()
00050 {
00051   delete mSymbol;
00052 }
00053 
00054 double QgsRendererRangeV2::lowerValue() const
00055 {
00056   return mLowerValue;
00057 }
00058 
00059 double QgsRendererRangeV2::upperValue() const
00060 {
00061   return mUpperValue;
00062 }
00063 
00064 QgsSymbolV2* QgsRendererRangeV2::symbol() const
00065 {
00066   return mSymbol;
00067 }
00068 
00069 QString QgsRendererRangeV2::label() const
00070 {
00071   return mLabel;
00072 }
00073 
00074 void QgsRendererRangeV2::setSymbol( QgsSymbolV2* s )
00075 {
00076   if ( mSymbol == s )
00077     return;
00078   delete mSymbol;
00079   mSymbol = s;
00080 }
00081 
00082 void QgsRendererRangeV2::setLabel( QString label )
00083 {
00084   mLabel = label;
00085 }
00086 
00087 void QgsRendererRangeV2::setUpperValue( double upperValue )
00088 {
00089   mUpperValue = upperValue;
00090 }
00091 
00092 void QgsRendererRangeV2::setLowerValue( double lowerValue )
00093 {
00094   mLowerValue = lowerValue;
00095 }
00096 
00097 QString QgsRendererRangeV2::dump()
00098 {
00099   return QString( "%1 - %2::%3::%4\n" ).arg( mLowerValue ).arg( mUpperValue ).arg( mLabel ).arg( mSymbol->dump() );
00100 }
00101 
00102 void QgsRendererRangeV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
00103 {
00104   if ( !mSymbol || props.value( "attribute", "" ).isEmpty() )
00105     return;
00106 
00107   QString attrName = props[ "attribute" ];
00108 
00109   QDomElement ruleElem = doc.createElement( "se:Rule" );
00110   element.appendChild( ruleElem );
00111 
00112   QDomElement nameElem = doc.createElement( "se:Name" );
00113   nameElem.appendChild( doc.createTextNode( mLabel ) );
00114   ruleElem.appendChild( nameElem );
00115 
00116   QDomElement descrElem = doc.createElement( "se:Description" );
00117   QString descrStr = QString( "range: %1 - %2" ).arg( mLowerValue ).arg( mUpperValue );
00118   descrElem.appendChild( doc.createTextNode( !mLabel.isEmpty() ? mLabel : descrStr ) );
00119   ruleElem.appendChild( descrElem );
00120 
00121   // create the ogc:Filter for the range
00122   QDomElement filterElem = doc.createElement( "ogc:Filter" );
00123   QString filterFunc = QString( "%1 > %2 AND %1 <= %3" )
00124                        .arg( attrName.replace( "\"", "\"\"" ) )
00125                        .arg( mLowerValue ).arg( mUpperValue );
00126   QgsSymbolLayerV2Utils::createFunctionElement( doc, filterElem, filterFunc );
00127 
00128   mSymbol->toSld( doc, ruleElem, props );
00129 }
00130 
00132 
00133 QgsGraduatedSymbolRendererV2::QgsGraduatedSymbolRendererV2( QString attrName, QgsRangeList ranges )
00134     : QgsFeatureRendererV2( "graduatedSymbol" ),
00135     mAttrName( attrName ),
00136     mRanges( ranges ),
00137     mMode( Custom ),
00138     mSourceSymbol( NULL ),
00139     mSourceColorRamp( NULL ),
00140     mRotationFieldIdx( -1 ),
00141     mSizeScaleFieldIdx( -1 )
00142 {
00143   // TODO: check ranges for sanity (NULL symbols, invalid ranges)
00144 }
00145 
00146 QgsGraduatedSymbolRendererV2::~QgsGraduatedSymbolRendererV2()
00147 {
00148   mRanges.clear(); // should delete all the symbols
00149   delete mSourceSymbol;
00150   delete mSourceColorRamp;
00151 }
00152 
00153 QgsSymbolV2* QgsGraduatedSymbolRendererV2::symbolForValue( double value )
00154 {
00155   for ( QgsRangeList::iterator it = mRanges.begin(); it != mRanges.end(); ++it )
00156   {
00157     if ( it->lowerValue() <= value && it->upperValue() >= value )
00158       return it->symbol();
00159   }
00160   // the value is out of the range: return NULL instead of symbol
00161   return NULL;
00162 }
00163 
00164 QgsSymbolV2* QgsGraduatedSymbolRendererV2::symbolForFeature( QgsFeature& feature )
00165 {
00166   const QgsAttributeMap& attrMap = feature.attributeMap();
00167   QgsAttributeMap::const_iterator ita = attrMap.find( mAttrNum );
00168   if ( ita == attrMap.end() )
00169   {
00170     QgsDebugMsg( "attribute required by renderer not found: " + mAttrName + "(index " + QString::number( mAttrNum ) + ")" );
00171     return NULL;
00172   }
00173 
00174   // find the right category
00175   QgsSymbolV2* symbol = symbolForValue( ita->toDouble() );
00176   if ( symbol == NULL )
00177     return NULL;
00178 
00179   if ( mRotationFieldIdx == -1 && mSizeScaleFieldIdx == -1 )
00180     return symbol; // no data-defined rotation/scaling - just return the symbol
00181 
00182   // find out rotation, size scale
00183   double rotation = 0;
00184   double sizeScale = 1;
00185   if ( mRotationFieldIdx != -1 )
00186     rotation = attrMap[mRotationFieldIdx].toDouble();
00187   if ( mSizeScaleFieldIdx != -1 )
00188     sizeScale = attrMap[mSizeScaleFieldIdx].toDouble();
00189 
00190   // take a temporary symbol (or create it if doesn't exist)
00191   QgsSymbolV2* tempSymbol = mTempSymbols[symbol];
00192 
00193   // modify the temporary symbol and return it
00194   if ( tempSymbol->type() == QgsSymbolV2::Marker )
00195   {
00196     QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( tempSymbol );
00197     if ( mRotationFieldIdx != -1 )
00198       markerSymbol->setAngle( rotation );
00199     if ( mSizeScaleFieldIdx != -1 )
00200       markerSymbol->setSize( sizeScale * static_cast<QgsMarkerSymbolV2*>( symbol )->size() );
00201   }
00202   else if ( tempSymbol->type() == QgsSymbolV2::Line )
00203   {
00204     QgsLineSymbolV2* lineSymbol = static_cast<QgsLineSymbolV2*>( tempSymbol );
00205     if ( mSizeScaleFieldIdx != -1 )
00206       lineSymbol->setWidth( sizeScale * static_cast<QgsLineSymbolV2*>( symbol )->width() );
00207   }
00208   return tempSymbol;
00209 }
00210 
00211 void QgsGraduatedSymbolRendererV2::startRender( QgsRenderContext& context, const QgsVectorLayer *vlayer )
00212 {
00213   // find out classification attribute index from name
00214   mAttrNum = vlayer ? vlayer->fieldNameIndex( mAttrName ) : -1;
00215 
00216   mRotationFieldIdx  = ( mRotationField.isEmpty()  ? -1 : vlayer->fieldNameIndex( mRotationField ) );
00217   mSizeScaleFieldIdx = ( mSizeScaleField.isEmpty() ? -1 : vlayer->fieldNameIndex( mSizeScaleField ) );
00218 
00219   QgsRangeList::iterator it = mRanges.begin();
00220   for ( ; it != mRanges.end(); ++it )
00221   {
00222     it->symbol()->startRender( context, vlayer );
00223 
00224     if ( mRotationFieldIdx != -1 || mSizeScaleFieldIdx != -1 )
00225     {
00226       QgsSymbolV2* tempSymbol = it->symbol()->clone();
00227       tempSymbol->setRenderHints(( mRotationFieldIdx != -1 ? QgsSymbolV2::DataDefinedRotation : 0 ) |
00228                                  ( mSizeScaleFieldIdx != -1 ? QgsSymbolV2::DataDefinedSizeScale : 0 ) );
00229       tempSymbol->startRender( context, vlayer );
00230       mTempSymbols[ it->symbol()] = tempSymbol;
00231     }
00232   }
00233 }
00234 
00235 void QgsGraduatedSymbolRendererV2::stopRender( QgsRenderContext& context )
00236 {
00237   QgsRangeList::iterator it = mRanges.begin();
00238   for ( ; it != mRanges.end(); ++it )
00239     it->symbol()->stopRender( context );
00240 
00241   // cleanup mTempSymbols
00242 #if QT_VERSION < 0x40600
00243   QMap<QgsSymbolV2*, QgsSymbolV2*>::iterator it2 = mTempSymbols.begin();
00244 #else
00245   QHash<QgsSymbolV2*, QgsSymbolV2*>::iterator it2 = mTempSymbols.begin();
00246 #endif
00247   for ( ; it2 != mTempSymbols.end(); ++it2 )
00248   {
00249     it2.value()->stopRender( context );
00250     delete it2.value();
00251   }
00252   mTempSymbols.clear();
00253 }
00254 
00255 QList<QString> QgsGraduatedSymbolRendererV2::usedAttributes()
00256 {
00257   QSet<QString> attributes;
00258   attributes.insert( mAttrName );
00259   if ( !mRotationField.isEmpty() )
00260   {
00261     attributes.insert( mRotationField );
00262   }
00263   if ( !mSizeScaleField.isEmpty() )
00264   {
00265     attributes.insert( mSizeScaleField );
00266   }
00267 
00268   QgsSymbolV2* symbol = 0;
00269   QgsRangeList::const_iterator range_it = mRanges.constBegin();
00270   for ( ; range_it != mRanges.constEnd(); ++range_it )
00271   {
00272     symbol = range_it->symbol();
00273     if ( symbol )
00274     {
00275       attributes.unite( symbol->usedAttributes() );
00276     }
00277   }
00278   return attributes.toList();
00279 }
00280 
00281 bool QgsGraduatedSymbolRendererV2::updateRangeSymbol( int rangeIndex, QgsSymbolV2* symbol )
00282 {
00283   if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
00284     return false;
00285   mRanges[rangeIndex].setSymbol( symbol );
00286   return true;
00287 }
00288 
00289 bool QgsGraduatedSymbolRendererV2::updateRangeLabel( int rangeIndex, QString label )
00290 {
00291   if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
00292     return false;
00293   mRanges[rangeIndex].setLabel( label );
00294   return true;
00295 }
00296 
00297 bool QgsGraduatedSymbolRendererV2::updateRangeUpperValue( int rangeIndex, double value )
00298 {
00299   if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
00300     return false;
00301   mRanges[rangeIndex].setUpperValue( value );
00302   return true;
00303 }
00304 
00305 bool QgsGraduatedSymbolRendererV2::updateRangeLowerValue( int rangeIndex, double value )
00306 {
00307   if ( rangeIndex < 0 || rangeIndex >= mRanges.size() )
00308     return false;
00309   mRanges[rangeIndex].setLowerValue( value );
00310   return true;
00311 }
00312 
00313 QString QgsGraduatedSymbolRendererV2::dump()
00314 {
00315   QString s = QString( "GRADUATED: attr %1\n" ).arg( mAttrName );
00316   for ( int i = 0; i < mRanges.count(); i++ )
00317     s += mRanges[i].dump();
00318   return s;
00319 }
00320 
00321 QgsFeatureRendererV2* QgsGraduatedSymbolRendererV2::clone()
00322 {
00323   QgsGraduatedSymbolRendererV2* r = new QgsGraduatedSymbolRendererV2( mAttrName, mRanges );
00324   r->setMode( mMode );
00325   if ( mSourceSymbol )
00326     r->setSourceSymbol( mSourceSymbol->clone() );
00327   if ( mSourceColorRamp )
00328     r->setSourceColorRamp( mSourceColorRamp->clone() );
00329   r->setUsingSymbolLevels( usingSymbolLevels() );
00330   r->setRotationField( rotationField() );
00331   r->setSizeScaleField( sizeScaleField() );
00332   return r;
00333 }
00334 
00335 void QgsGraduatedSymbolRendererV2::toSld( QDomDocument& doc, QDomElement &element ) const
00336 {
00337   QgsStringMap props;
00338   props[ "attribute" ] = mAttrName;
00339   if ( !mRotationField.isEmpty() )
00340     props[ "angle" ] = QString( mRotationField ).append( "\"" ).prepend( "\"" );
00341   if ( !mSizeScaleField.isEmpty() )
00342     props[ "scale" ] = QString( mSizeScaleField ).append( "\"" ).prepend( "\"" );
00343 
00344   // create a Rule for each range
00345   for ( QgsRangeList::const_iterator it = mRanges.constBegin(); it != mRanges.constEnd(); it++ )
00346   {
00347     QgsStringMap catProps( props );
00348     it->toSld( doc, element, catProps );
00349   }
00350 }
00351 
00352 QgsSymbolV2List QgsGraduatedSymbolRendererV2::symbols()
00353 {
00354   QgsSymbolV2List lst;
00355   for ( int i = 0; i < mRanges.count(); i++ )
00356     lst.append( mRanges[i].symbol() );
00357   return lst;
00358 }
00359 
00360 static QList<double> _calcEqualIntervalBreaks( double minimum, double maximum, int classes )
00361 {
00362 
00363   // Equal interval algorithm
00364   //
00365   // Returns breaks based on dividing the range ('minimum' to 'maximum')
00366   // into 'classes' parts.
00367 
00368   double step = ( maximum - minimum ) / classes;
00369 
00370   QList<double> breaks;
00371   double value = minimum;
00372   for ( int i = 0; i < classes; i++ )
00373   {
00374     value += step;
00375     breaks.append( value );
00376   }
00377 
00378   // floating point arithmetics is not precise:
00379   // set the last break to be exactly maximum so we do not miss it
00380   breaks[classes-1] = maximum;
00381 
00382   return breaks;
00383 }
00384 
00385 static QList<double> _calcQuantileBreaks( QList<double> values, int classes )
00386 {
00387 
00388   // q-th quantile of a data set:
00389   // value where q fraction of data is below and (1-q) fraction is above this value
00390   // Xq = (1 - r) * X_NI1 + r * X_NI2
00391   //   NI1 = (int) (q * (n+1))
00392   //   NI2 = NI1 + 1
00393   //   r = q * (n+1) - (int) (q * (n+1))
00394   // (indices of X: 1...n)
00395 
00396   // sort the values first
00397   qSort( values );
00398 
00399   QList<double> breaks;
00400 
00401   int n = values.count();
00402   double Xq = n > 0 ? values[0] : 0.0;
00403 
00404   for ( int i = 1; i < classes; i++ )
00405   {
00406     if ( n > 1 )
00407     {
00408       double q = i  / ( double ) classes;
00409       double a = q * ( n - 1 );
00410       int aa = ( int )( a );
00411 
00412       double r = a - aa;
00413       Xq = ( 1 - r ) * values[aa] + r * values[aa+1];
00414     }
00415     breaks.append( Xq );
00416   }
00417 
00418   breaks.append( values[ n-1 ] );
00419 
00420   return breaks;
00421 }
00422 
00423 static QList<double> _calcPrettyBreaks( double minimum, double maximum, int classes )
00424 {
00425 
00426   // C++ implementation of R's pretty algorithm
00427   // Based on code for determining optimal tick placement for statistical graphics
00428   // from the R statistical programming language.
00429   // Code ported from R implementation from 'labeling' R package
00430   //
00431   // Computes a sequence of about 'classes' equally spaced round values
00432   // which cover the range of values from 'minimum' to 'maximum'.
00433   // The values are chosen so that they are 1, 2 or 5 times a power of 10.
00434 
00435   QList<double> breaks;
00436   if ( classes < 1 )
00437   {
00438     breaks.append( maximum );
00439     return breaks;
00440   }
00441 
00442   int minimumCount = ( int ) classes / 3;
00443   double shrink = 0.75;
00444   double highBias = 1.5;
00445   double adjustBias = 0.5 + 1.5 * highBias;
00446   int divisions = classes;
00447   double h = highBias;
00448   double cell;
00449   int U;
00450   bool small = false;
00451   double dx = maximum - minimum;
00452 
00453   if ( dx == 0 && maximum == 0 )
00454   {
00455     cell = 1.0;
00456     small = true;
00457     U = 1;
00458   }
00459   else
00460   {
00461     cell = qMax( qAbs( minimum ), qAbs( maximum ) );
00462     if ( adjustBias >= 1.5 * h + 0.5 )
00463     {
00464       U = 1 + ( 1.0 / ( 1 + h ) );
00465     }
00466     else
00467     {
00468       U = 1 + ( 1.5 / ( 1 + adjustBias ) );
00469     }
00470     small = dx < ( cell * U * qMax( 1, divisions ) * 1e-07 * 3.0 );
00471   }
00472 
00473   if ( small )
00474   {
00475     if ( cell > 10 )
00476     {
00477       cell = 9 + cell / 10;
00478       cell = cell * shrink;
00479     }
00480     if ( minimumCount > 1 )
00481     {
00482       cell = cell / minimumCount;
00483     }
00484   }
00485   else
00486   {
00487     cell = dx;
00488     if ( divisions > 1 )
00489     {
00490       cell = cell / divisions;
00491     }
00492   }
00493   if ( cell < 20 * 1e-07 )
00494   {
00495     cell = 20 * 1e-07;
00496   }
00497 
00498   double base = pow( 10.0, floor( log10( cell ) ) );
00499   double unit = base;
00500   if (( 2 * base ) - cell < h *( cell - unit ) )
00501   {
00502     unit = 2.0 * base;
00503     if (( 5 * base ) - cell < adjustBias *( cell - unit ) )
00504     {
00505       unit = 5.0 * base;
00506       if (( 10.0 * base ) - cell < h *( cell - unit ) )
00507       {
00508         unit = 10.0 * base;
00509       }
00510     }
00511   }
00512   // Maybe used to correct for the epsilon here??
00513   int start = floor( minimum / unit + 1e-07 );
00514   int end = ceil( maximum / unit - 1e-07 );
00515 
00516   // Extend the range out beyond the data. Does this ever happen??
00517   while ( start * unit > minimum + ( 1e-07 * unit ) )
00518   {
00519     start = start - 1;
00520   }
00521   while ( end * unit < maximum - ( 1e-07 * unit ) )
00522   {
00523     end = end + 1;
00524   }
00525   QgsDebugMsg( QString( "pretty classes: %1" ).arg( end ) );
00526 
00527   // If we don't have quite enough labels, extend the range out
00528   // to make more (these labels are beyond the data :( )
00529   int k = floor( 0.5 + end - start );
00530   if ( k < minimumCount )
00531   {
00532     k = minimumCount - k;
00533     if ( start >= 0 )
00534     {
00535       end = end + k / 2;
00536       start = start - k / 2 + k % 2;
00537     }
00538     else
00539     {
00540       start = start - k / 2;
00541       end = end + k / 2 + k % 2;
00542     }
00543     divisions = minimumCount;
00544   }
00545   else
00546   {
00547     divisions = k;
00548   }
00549   double minimumBreak = start * unit;
00550   double maximumBreak = end * unit;
00551   int count = ceil( maximumBreak - minimumBreak ) / unit;
00552 
00553   for ( int i = 1; i < count + 1; i++ )
00554   {
00555     breaks.append( minimumBreak + i * unit );
00556   }
00557 
00558   if ( breaks.isEmpty() )
00559     return breaks;
00560 
00561   if ( breaks.first() < minimum )
00562   {
00563     breaks[0] = minimum;
00564   }
00565   if ( breaks.last() > maximum )
00566   {
00567     breaks[breaks.count()-1] = maximum;
00568   }
00569 
00570   return breaks;
00571 } // _calcPrettyBreaks
00572 
00573 
00574 static QList<double> _calcStdDevBreaks( QList<double> values, int classes, QList<int> &labels )
00575 {
00576 
00577   // C++ implementation of the standard deviation class interval algorithm
00578   // as implemented in the 'classInt' package available for the R statistical
00579   // prgramming language.
00580 
00581   // Returns breaks based on '_calcPrettyBreaks' of the centred and scaled
00582   // values of 'values', and may have a number of classes different from 'classes'.
00583 
00584   double mean = 0.0;
00585   double stdDev = 0.0;
00586   int n = values.count();
00587   double minimum = values[0];
00588   double maximum = values[0];
00589 
00590   for ( int i = 0; i < n; i++ )
00591   {
00592     mean += values[i];
00593     minimum = qMin( values[i], minimum ); // could use precomputed max and min
00594     maximum = qMax( values[i], maximum ); // but have to go through entire list anyway
00595   }
00596   mean = mean / ( double ) n;
00597 
00598   double sd = 0.0;
00599   for ( int i = 0; i < n; i++ )
00600   {
00601     sd = values[i] - mean;
00602     stdDev += sd * sd;
00603   }
00604   stdDev = sqrt( stdDev / n );
00605 
00606   QList<double> breaks = _calcPrettyBreaks(( minimum - mean ) / stdDev, ( maximum - mean ) / stdDev, classes );
00607   for ( int i = 0; i < breaks.count(); i++ )
00608   {
00609     labels.append(( int ) breaks[i] );
00610     breaks[i] = ( breaks[i] * stdDev ) + mean;
00611   }
00612 
00613   return breaks;
00614 } // _calcStdDevBreaks
00615 
00616 static QList<double> _calcJenksBreaks( QList<double> values, int classes,
00617                                        double minimum, double maximum,
00618                                        int maximumSize = 1000 )
00619 {
00620   // Jenks Optimal (Natural Breaks) algorithm
00621   // Based on the Jenks algorithm from the 'classInt' package available for
00622   // the R statistical prgramming language, and from Python code from here:
00623   // http://danieljlewis.org/2010/06/07/jenks-natural-breaks-algorithm-in-python/
00624   // and is based on a JAVA and Fortran code available here:
00625   // https://stat.ethz.ch/pipermail/r-sig-geo/2006-March/000811.html
00626 
00627   // Returns class breaks such that classes are internally homogeneous while
00628   // assuring heterogeneity among classes.
00629 
00630   if ( classes <= 1 )
00631   {
00632     return QList<double>() << maximum;
00633   }
00634 
00635   if ( classes >= values.size() )
00636   {
00637     return values;
00638   }
00639 
00640   QVector<double> sample;
00641 
00642   // if we have lots of values, we need to take a random sample
00643   if ( values.size() > maximumSize )
00644   {
00645     // for now, sample at least maximumSize values or a 10% sample, whichever
00646     // is larger. This will produce a more representative sample for very large
00647     // layers, but could end up being computationally intensive...
00648 
00649     qsrand( time( 0 ) );
00650 
00651     sample.resize( qMax( maximumSize, values.size() / 10 ) );
00652 
00653     QgsDebugMsg( QString( "natural breaks (jenks) sample size: %1" ).arg( sample.size() ) );
00654     QgsDebugMsg( QString( "values:%1" ).arg( values.size() ) );
00655 
00656     sample[ 0 ] = minimum;
00657     sample[ 1 ] = maximum;;
00658     for ( int i = 2; i < sample.size(); i++ )
00659     {
00660       // pick a random integer from 0 to n
00661       double r = qrand();
00662       int j = floor( r / RAND_MAX * ( values.size() - 1 ) );
00663       sample[ i ] = values[ j ];
00664     }
00665   }
00666   else
00667   {
00668     sample = values.toVector();
00669   }
00670 
00671   int n = sample.size();
00672 
00673   // sort the sample values
00674   qSort( sample );
00675 
00676   QVector< QVector<int> > matrixOne( n + 1 );
00677   QVector< QVector<double> > matrixTwo( n + 1 );
00678 
00679   for ( int i = 0; i <= n; i++ )
00680   {
00681     matrixOne[i].resize( classes + 1 );
00682     matrixTwo[i].resize( classes + 1 );
00683   }
00684 
00685   for ( int i = 1; i <= classes; i++ )
00686   {
00687     matrixOne[0][i] = 1;
00688     matrixOne[1][i] = 1;
00689     matrixTwo[0][i] = 0.0;
00690     for ( int j = 2; j <= n; j++ )
00691     {
00692       matrixTwo[j][i] = std::numeric_limits<double>::max();
00693     }
00694   }
00695 
00696   for ( int l = 2; l <= n; l++ )
00697   {
00698     double s1 = 0.0;
00699     double s2 = 0.0;
00700     int w = 0;
00701 
00702     double v = 0.0;
00703 
00704     for ( int m = 1; m <= l; m++ )
00705     {
00706       int i3 = l - m + 1;
00707 
00708       double val = sample[ i3 - 1 ];
00709 
00710       s2 += val * val;
00711       s1 += val;
00712       w++;
00713 
00714       v = s2 - ( s1 * s1 ) / ( double ) w;
00715       int i4 = i3 - 1;
00716       if ( i4 != 0 )
00717       {
00718         for ( int j = 2; j <= classes; j++ )
00719         {
00720           if ( matrixTwo[l][j] >= v + matrixTwo[i4][j - 1] )
00721           {
00722             matrixOne[l][j] = i4;
00723             matrixTwo[l][j] = v + matrixTwo[i4][j - 1];
00724           }
00725         }
00726       }
00727     }
00728     matrixOne[l][1] = 1;
00729     matrixTwo[l][1] = v;
00730   }
00731 
00732   QVector<double> breaks( classes );
00733   breaks[classes-1] = sample[n-1];
00734 
00735   for ( int j = classes, k = n; j >= 2; j-- )
00736   {
00737     int id = matrixOne[k][j] - 1;
00738     breaks[j - 2] = sample[id];
00739     k = matrixOne[k][j] - 1;
00740   }
00741 
00742   return breaks.toList();
00743 } //_calcJenksBreaks
00744 
00745 
00746 QgsGraduatedSymbolRendererV2* QgsGraduatedSymbolRendererV2::createRenderer(
00747   QgsVectorLayer* vlayer,
00748   QString attrName,
00749   int classes,
00750   Mode mode,
00751   QgsSymbolV2* symbol,
00752   QgsVectorColorRampV2* ramp )
00753 {
00754   if ( classes < 1 )
00755     return NULL;
00756 
00757   int attrNum = vlayer->fieldNameIndex( attrName );
00758 
00759   double minimum = vlayer->minimumValue( attrNum ).toDouble();
00760   double maximum = vlayer->maximumValue( attrNum ).toDouble();
00761   QgsDebugMsg( QString( "min %1 // max %2" ).arg( minimum ).arg( maximum ) );
00762 
00763   QList<double> breaks;
00764   QList<int> labels;
00765   if ( mode == EqualInterval )
00766   {
00767     breaks = _calcEqualIntervalBreaks( minimum, maximum, classes );
00768   }
00769   else if ( mode == Pretty )
00770   {
00771     breaks = _calcPrettyBreaks( minimum, maximum, classes );
00772   }
00773   else if ( mode == Quantile || mode == Jenks || mode == StdDev )
00774   {
00775     // get values from layer
00776     QList<double> values;
00777     QgsFeature f;
00778     QgsAttributeList lst;
00779     lst.append( attrNum );
00780     vlayer->select( lst, QgsRectangle(), false );
00781     while ( vlayer->nextFeature( f ) )
00782       values.append( f.attributeMap()[attrNum].toDouble() );
00783     // calculate the breaks
00784     if ( mode == Quantile )
00785     {
00786       breaks = _calcQuantileBreaks( values, classes );
00787     }
00788     else if ( mode == Jenks )
00789     {
00790       breaks = _calcJenksBreaks( values, classes, minimum, maximum );
00791     }
00792     else if ( mode == StdDev )
00793     {
00794       breaks = _calcStdDevBreaks( values, classes, labels );
00795     }
00796   }
00797   else
00798   {
00799     Q_ASSERT( false );
00800   }
00801 
00802   QgsRangeList ranges;
00803   double lower, upper = minimum;
00804   QString label;
00805 
00806   // "breaks" list contains all values at class breaks plus maximum as last break
00807   int i = 0;
00808   for ( QList<double>::iterator it = breaks.begin(); it != breaks.end(); ++it, ++i )
00809   {
00810     lower = upper; // upper border from last interval
00811     upper = *it;
00812     if ( mode == StdDev )
00813     {
00814       if ( i == 0 )
00815       {
00816         label = "< " + QString::number( labels[i], 'i', 0 ) + " Std Dev";
00817       }
00818       else if ( i == labels.count() - 1 )
00819       {
00820         label = ">= " + QString::number( labels[i-1], 'i', 0 ) + " Std Dev";
00821       }
00822       else
00823       {
00824         label = QString::number( labels[i-1], 'i', 0 ) + " Std Dev" + " - " + QString::number( labels[i], 'i', 0 ) + " Std Dev";
00825       }
00826     }
00827     else
00828     {
00829       label = QString::number( lower, 'f', 4 ) + " - " + QString::number( upper, 'f', 4 );
00830     }
00831 
00832     QgsSymbolV2* newSymbol = symbol->clone();
00833     double colorValue = ( breaks.count() > 1 ? ( double ) i / ( breaks.count() - 1 ) : 0 );
00834     newSymbol->setColor( ramp->color( colorValue ) ); // color from (0 / cl-1) to (cl-1 / cl-1)
00835 
00836     ranges.append( QgsRendererRangeV2( lower, upper, newSymbol, label ) );
00837   }
00838 
00839   QgsGraduatedSymbolRendererV2* r = new QgsGraduatedSymbolRendererV2( attrName, ranges );
00840   r->setSourceSymbol( symbol->clone() );
00841   r->setSourceColorRamp( ramp->clone() );
00842   r->setMode( mode );
00843   return r;
00844 }
00845 
00846 QgsFeatureRendererV2* QgsGraduatedSymbolRendererV2::create( QDomElement& element )
00847 {
00848   QDomElement symbolsElem = element.firstChildElement( "symbols" );
00849   if ( symbolsElem.isNull() )
00850     return NULL;
00851 
00852   QDomElement rangesElem = element.firstChildElement( "ranges" );
00853   if ( rangesElem.isNull() )
00854     return NULL;
00855 
00856   QgsSymbolV2Map symbolMap = QgsSymbolLayerV2Utils::loadSymbols( symbolsElem );
00857   QgsRangeList ranges;
00858 
00859   QDomElement rangeElem = rangesElem.firstChildElement();
00860   while ( !rangeElem.isNull() )
00861   {
00862     if ( rangeElem.tagName() == "range" )
00863     {
00864       double lowerValue = rangeElem.attribute( "lower" ).toDouble();
00865       double upperValue = rangeElem.attribute( "upper" ).toDouble();
00866       QString symbolName = rangeElem.attribute( "symbol" );
00867       QString label = rangeElem.attribute( "label" );
00868       if ( symbolMap.contains( symbolName ) )
00869       {
00870         QgsSymbolV2* symbol = symbolMap.take( symbolName );
00871         ranges.append( QgsRendererRangeV2( lowerValue, upperValue, symbol, label ) );
00872       }
00873     }
00874     rangeElem = rangeElem.nextSiblingElement();
00875   }
00876 
00877   QString attrName = element.attribute( "attr" );
00878 
00879   QgsGraduatedSymbolRendererV2* r = new QgsGraduatedSymbolRendererV2( attrName, ranges );
00880 
00881   // delete symbols if there are any more
00882   QgsSymbolLayerV2Utils::clearSymbolMap( symbolMap );
00883 
00884   // try to load source symbol (optional)
00885   QDomElement sourceSymbolElem = element.firstChildElement( "source-symbol" );
00886   if ( !sourceSymbolElem.isNull() )
00887   {
00888     QgsSymbolV2Map sourceSymbolMap = QgsSymbolLayerV2Utils::loadSymbols( sourceSymbolElem );
00889     if ( sourceSymbolMap.contains( "0" ) )
00890     {
00891       r->setSourceSymbol( sourceSymbolMap.take( "0" ) );
00892     }
00893     QgsSymbolLayerV2Utils::clearSymbolMap( sourceSymbolMap );
00894   }
00895 
00896   // try to load color ramp (optional)
00897   QDomElement sourceColorRampElem = element.firstChildElement( "colorramp" );
00898   if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( "name" ) == "[source]" )
00899   {
00900     r->setSourceColorRamp( QgsSymbolLayerV2Utils::loadColorRamp( sourceColorRampElem ) );
00901   }
00902 
00903   // try to load mode
00904   QDomElement modeElem = element.firstChildElement( "mode" );
00905   if ( !modeElem.isNull() )
00906   {
00907     QString modeString = modeElem.attribute( "name" );
00908     if ( modeString == "equal" )
00909       r->setMode( EqualInterval );
00910     else if ( modeString == "quantile" )
00911       r->setMode( Quantile );
00912     else if ( modeString == "jenks" )
00913       r->setMode( Jenks );
00914     else if ( modeString == "stddev" )
00915       r->setMode( StdDev );
00916     else if ( modeString == "pretty" )
00917       r->setMode( Pretty );
00918   }
00919 
00920   QDomElement rotationElem = element.firstChildElement( "rotation" );
00921   if ( !rotationElem.isNull() )
00922     r->setRotationField( rotationElem.attribute( "field" ) );
00923 
00924   QDomElement sizeScaleElem = element.firstChildElement( "sizescale" );
00925   if ( !sizeScaleElem.isNull() )
00926     r->setSizeScaleField( sizeScaleElem.attribute( "field" ) );
00927 
00928   // TODO: symbol levels
00929   return r;
00930 }
00931 
00932 QDomElement QgsGraduatedSymbolRendererV2::save( QDomDocument& doc )
00933 {
00934   QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
00935   rendererElem.setAttribute( "type", "graduatedSymbol" );
00936   rendererElem.setAttribute( "symbollevels", ( mUsingSymbolLevels ? "1" : "0" ) );
00937   rendererElem.setAttribute( "attr", mAttrName );
00938 
00939   // ranges
00940   int i = 0;
00941   QgsSymbolV2Map symbols;
00942   QDomElement rangesElem = doc.createElement( "ranges" );
00943   QgsRangeList::const_iterator it = mRanges.constBegin();
00944   for ( ; it != mRanges.end(); it++ )
00945   {
00946     const QgsRendererRangeV2& range = *it;
00947     QString symbolName = QString::number( i );
00948     symbols.insert( symbolName, range.symbol() );
00949 
00950     QDomElement rangeElem = doc.createElement( "range" );
00951     rangeElem.setAttribute( "lower", QString::number( range.lowerValue() ) );
00952     rangeElem.setAttribute( "upper", QString::number( range.upperValue() ) );
00953     rangeElem.setAttribute( "symbol", symbolName );
00954     rangeElem.setAttribute( "label", range.label() );
00955     rangesElem.appendChild( rangeElem );
00956     i++;
00957   }
00958 
00959   rendererElem.appendChild( rangesElem );
00960 
00961   // save symbols
00962   QDomElement symbolsElem = QgsSymbolLayerV2Utils::saveSymbols( symbols, "symbols", doc );
00963   rendererElem.appendChild( symbolsElem );
00964 
00965   // save source symbol
00966   if ( mSourceSymbol )
00967   {
00968     QgsSymbolV2Map sourceSymbols;
00969     sourceSymbols.insert( "0", mSourceSymbol );
00970     QDomElement sourceSymbolElem = QgsSymbolLayerV2Utils::saveSymbols( sourceSymbols, "source-symbol", doc );
00971     rendererElem.appendChild( sourceSymbolElem );
00972   }
00973 
00974   // save source color ramp
00975   if ( mSourceColorRamp )
00976   {
00977     QDomElement colorRampElem = QgsSymbolLayerV2Utils::saveColorRamp( "[source]", mSourceColorRamp, doc );
00978     rendererElem.appendChild( colorRampElem );
00979   }
00980 
00981   // save mode
00982   QString modeString;
00983   if ( mMode == EqualInterval )
00984     modeString = "equal";
00985   else if ( mMode == Quantile )
00986     modeString = "quantile";
00987   else if ( mMode == Jenks )
00988     modeString = "jenks";
00989   else if ( mMode == StdDev )
00990     modeString = "stddev";
00991   else if ( mMode == Pretty )
00992     modeString = "pretty";
00993   if ( !modeString.isEmpty() )
00994   {
00995     QDomElement modeElem = doc.createElement( "mode" );
00996     modeElem.setAttribute( "name", modeString );
00997     rendererElem.appendChild( modeElem );
00998   }
00999 
01000   QDomElement rotationElem = doc.createElement( "rotation" );
01001   rotationElem.setAttribute( "field", mRotationField );
01002   rendererElem.appendChild( rotationElem );
01003 
01004   QDomElement sizeScaleElem = doc.createElement( "sizescale" );
01005   sizeScaleElem.setAttribute( "field", mSizeScaleField );
01006   rendererElem.appendChild( sizeScaleElem );
01007 
01008   return rendererElem;
01009 }
01010 
01011 QgsLegendSymbologyList QgsGraduatedSymbolRendererV2::legendSymbologyItems( QSize iconSize )
01012 {
01013   QSettings settings;
01014   bool showClassifiers = settings.value( "/qgis/showLegendClassifiers", false ).toBool();
01015 
01016   QgsLegendSymbologyList lst;
01017   if ( showClassifiers )
01018   {
01019     lst << qMakePair( classAttribute(), QPixmap() );
01020   }
01021 
01022   int count = ranges().count();
01023   for ( int i = 0; i < count; i++ )
01024   {
01025     const QgsRendererRangeV2& range = ranges()[i];
01026     QPixmap pix = QgsSymbolLayerV2Utils::symbolPreviewPixmap( range.symbol(), iconSize );
01027     lst << qMakePair( range.label(), pix );
01028   }
01029   return lst;
01030 }
01031 
01032 QgsLegendSymbolList QgsGraduatedSymbolRendererV2::legendSymbolItems()
01033 {
01034   QSettings settings;
01035   bool showClassifiers = settings.value( "/qgis/showLegendClassifiers", false ).toBool();
01036 
01037   QgsLegendSymbolList lst;
01038   if ( showClassifiers )
01039   {
01040     lst << qMakePair( classAttribute(), ( QgsSymbolV2* )0 );
01041   }
01042 
01043   QgsRangeList::const_iterator rangeIt = mRanges.constBegin();
01044   for ( ; rangeIt != mRanges.constEnd(); ++rangeIt )
01045   {
01046     lst << qMakePair( rangeIt->label(), rangeIt->symbol() );
01047   }
01048   return lst;
01049 }
01050 
01051 QgsSymbolV2* QgsGraduatedSymbolRendererV2::sourceSymbol()
01052 {
01053   return mSourceSymbol;
01054 }
01055 void QgsGraduatedSymbolRendererV2::setSourceSymbol( QgsSymbolV2* sym )
01056 {
01057   delete mSourceSymbol;
01058   mSourceSymbol = sym;
01059 }
01060 
01061 QgsVectorColorRampV2* QgsGraduatedSymbolRendererV2::sourceColorRamp()
01062 {
01063   return mSourceColorRamp;
01064 }
01065 void QgsGraduatedSymbolRendererV2::setSourceColorRamp( QgsVectorColorRampV2* ramp )
01066 {
01067   delete mSourceColorRamp;
01068   mSourceColorRamp = ramp;
01069 }
01070 
01071 void QgsGraduatedSymbolRendererV2::updateColorRamp( QgsVectorColorRampV2 *ramp )
01072 {
01073   int i = 0;
01074   foreach( QgsRendererRangeV2 range, mRanges )
01075   {
01076     QgsSymbolV2* symbol = range.symbol()->clone();
01077     double colorValue = ( mRanges.count() > 1 ? ( double ) i / ( mRanges.count() - 1 ) : 0 );
01078     symbol->setColor( ramp->color( colorValue ) );
01079     updateRangeSymbol( i, symbol );
01080     ++i;
01081   }
01082   this->setSourceColorRamp( ramp );
01083 }
01084 
01085 void QgsGraduatedSymbolRendererV2::updateSymbols( QgsSymbolV2 *sym )
01086 {
01087   int i = 0;
01088   foreach( QgsRendererRangeV2 range, mRanges )
01089   {
01090     QgsSymbolV2* symbol = sym->clone();
01091     symbol->setColor( range.symbol()->color() );
01092     updateRangeSymbol( i, symbol );
01093     ++i;
01094   }
01095   this->setSourceSymbol( sym->clone() );
01096 }
01097 
01098 void QgsGraduatedSymbolRendererV2::addClass( QgsSymbolV2* symbol )
01099 {
01100   QgsSymbolV2* newSymbol = symbol->clone();
01101   QString label = "0.0 - 0.0";
01102   mRanges.insert( 0, QgsRendererRangeV2( 0.0, 0.0, newSymbol, label ) );
01103 
01104 }
01105 
01106 void QgsGraduatedSymbolRendererV2::deleteClass( int idx )
01107 {
01108   mRanges.removeAt( idx );
01109 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines