29 #include <QDomDocument>
30 #include <QDomElement>
46 : mLowerValue( lowerValue )
47 , mUpperValue( upperValue )
55 : mLowerValue( range.mLowerValue )
56 , mUpperValue( range.mUpperValue )
57 , mSymbol( range.mSymbol.data() ? range.mSymbol->clone() : NULL )
58 , mLabel( range.mLabel )
59 , mRender( range.mRender )
143 if ( !
mSymbol.data() || props.value(
"attribute",
"" ).isEmpty() )
146 QString attrName = props[
"attribute" ];
148 QDomElement ruleElem = doc.createElement(
"se:Rule" );
149 element.appendChild( ruleElem );
151 QDomElement nameElem = doc.createElement(
"se:Name" );
152 nameElem.appendChild( doc.createTextNode(
mLabel ) );
153 ruleElem.appendChild( nameElem );
155 QDomElement descrElem = doc.createElement(
"se:Description" );
156 QDomElement titleElem = doc.createElement(
"se:Title" );
158 titleElem.appendChild( doc.createTextNode( !
mLabel.isEmpty() ?
mLabel : descrStr ) );
159 descrElem.appendChild( titleElem );
160 ruleElem.appendChild( descrElem );
163 QString filterFunc = QString(
"%1 > %2 AND %1 <= %3" )
164 .arg( attrName.replace(
"\"",
"\"\"" ) )
168 mSymbol->toSld( doc, ruleElem, props );
177 mFormat(
" %1 - %2 " ),
179 mTrimTrailingZeroes( false ),
182 mReTrailingZeroes(
"[.,]?0*$" ),
183 mReNegativeZero(
"^\\-0(?:[.,]0*)?$" )
188 mReTrailingZeroes(
"[.,]?0*$" ),
189 mReNegativeZero(
"^\\-0(?:[.,]0*)?$" )
207 return !( *
this == other );
217 while ( precision < 0 )
234 QString valueStr = QString::number( value,
'f',
mPrecision );
238 valueStr = valueStr.mid( 1 );
243 QString valueStr = QString::number( value *
mNumberScale,
'f', 0 );
244 if ( valueStr ==
"-0" )
246 if ( valueStr !=
"0" )
258 return legend.replace(
"%1", lowerStr ).replace(
"%2", upperStr );
263 mFormat = element.attribute(
"format",
264 element.attribute(
"prefix",
" " ) +
"%1" +
265 element.attribute(
"separator",
" - " ) +
"%2" +
266 element.attribute(
"suffix",
" " )
268 setPrecision( element.attribute(
"decimalplaces",
"4" ).toInt() );
274 element.setAttribute(
"format",
mFormat );
275 element.setAttribute(
"decimalplaces",
mPrecision );
283 , mAttrName( attrName )
286 , mInvertedColorRamp( false )
302 for ( QgsRangeList::iterator it =
mRanges.begin(); it !=
mRanges.end(); ++it )
304 if ( it->lowerValue() <= value && it->upperValue() >= value )
319 if ( symbol == NULL )
326 const double rotation =
mRotation.data() ?
mRotation->evaluate( feature ).toDouble() : 0;
337 markerSymbol->
setSize( sizeScale * static_cast<QgsMarkerSymbolV2*>( symbol )->
size() );
343 lineSymbol->
setWidth( sizeScale * static_cast<QgsLineSymbolV2*>( symbol )->width() );
352 if ( mAttrNum < 0 || mAttrNum >= attrs.count() )
362 if ( value.isNull() )
382 QgsRangeList::iterator it =
mRanges.begin();
383 for ( ; it !=
mRanges.end(); ++it )
388 it->symbol()->startRender( context, &fields );
403 QgsRangeList::iterator it =
mRanges.begin();
404 for ( ; it !=
mRanges.end(); ++it )
409 it->symbol()->stopRender( context );
413 QHash<QgsSymbolV2*, QgsSymbolV2*>::iterator it2 =
mTempSymbols.begin();
416 it2.value()->stopRender( context );
424 QSet<QString> attributes;
439 QgsRangeList::const_iterator range_it =
mRanges.constBegin();
440 for ( ; range_it !=
mRanges.constEnd(); ++range_it )
448 return attributes.toList();
453 if ( rangeIndex < 0 || rangeIndex >=
mRanges.size() )
455 mRanges[rangeIndex].setSymbol( symbol );
461 if ( rangeIndex < 0 || rangeIndex >=
mRanges.size() )
463 mRanges[rangeIndex].setLabel( label );
469 if ( rangeIndex < 0 || rangeIndex >=
mRanges.size() )
480 if ( rangeIndex < 0 || rangeIndex >=
mRanges.size() )
491 if ( rangeIndex < 0 || rangeIndex >=
mRanges.size() )
493 mRanges[rangeIndex].setRenderState( value );
499 QString s = QString(
"GRADUATED: attr %1\n" ).arg(
mAttrName );
500 for (
int i = 0; i <
mRanges.count(); i++ )
529 props[
"angle" ] =
mRotation->expression();
534 for ( QgsRangeList::const_iterator it =
mRanges.constBegin(); it !=
mRanges.constEnd(); ++it )
537 it->toSld( doc, element, catProps );
544 for (
int i = 0; i <
mRanges.count(); i++ )
545 lst.append(
mRanges[i].symbol() );
557 double step = ( maximum - minimum ) / classes;
559 QList<double> breaks;
560 double value = minimum;
561 for (
int i = 0; i < classes; i++ )
564 breaks.append( value );
569 breaks[classes-1] = maximum;
587 QList<double> breaks;
590 if ( !values.count() )
593 int n = values.count();
594 double Xq = n > 0 ? values[0] : 0.0;
596 for (
int i = 1; i < classes; i++ )
600 double q = i / ( double ) classes;
601 double a = q * ( n - 1 );
602 int aa = ( int )( a );
605 Xq = ( 1 - r ) * values[aa] + r * values[aa+1];
610 breaks.append( values[ n-1 ] );
627 QList<double> breaks;
630 breaks.append( maximum );
634 int minimumCount = ( int ) classes / 3;
635 double shrink = 0.75;
636 double highBias = 1.5;
637 double adjustBias = 0.5 + 1.5 * highBias;
638 int divisions = classes;
643 double dx = maximum - minimum;
645 if ( dx == 0 && maximum == 0 )
653 cell = qMax( qAbs( minimum ), qAbs( maximum ) );
654 if ( adjustBias >= 1.5 * h + 0.5 )
656 U = 1 + ( 1.0 / ( 1 + h ) );
660 U = 1 + ( 1.5 / ( 1 + adjustBias ) );
662 small = dx < ( cell * U * qMax( 1, divisions ) * 1e-07 * 3.0 );
669 cell = 9 + cell / 10;
670 cell = cell * shrink;
672 if ( minimumCount > 1 )
674 cell = cell / minimumCount;
682 cell = cell / divisions;
685 if ( cell < 20 * 1e-07 )
690 double base = pow( 10.0, floor( log10( cell ) ) );
692 if (( 2 * base ) - cell < h *( cell - unit ) )
695 if (( 5 * base ) - cell < adjustBias *( cell - unit ) )
698 if (( 10.0 * base ) - cell < h *( cell - unit ) )
705 int start = floor( minimum / unit + 1e-07 );
706 int end = ceil( maximum / unit - 1e-07 );
709 while ( start * unit > minimum + ( 1e-07 * unit ) )
713 while ( end * unit < maximum - ( 1e-07 * unit ) )
717 QgsDebugMsg( QString(
"pretty classes: %1" ).arg( end ) );
721 int k = floor( 0.5 + end - start );
722 if ( k < minimumCount )
724 k = minimumCount - k;
728 start = start - k / 2 + k % 2;
732 start = start - k / 2;
733 end = end + k / 2 + k % 2;
736 double minimumBreak = start * unit;
738 int count = end - start;
740 for (
int i = 1; i < count + 1; i++ )
742 breaks.append( minimumBreak + i * unit );
745 if ( breaks.isEmpty() )
748 if ( breaks.first() < minimum )
752 if ( breaks.last() > maximum )
754 breaks[breaks.count()-1] = maximum;
761 static QList<double>
_calcStdDevBreaks( QList<double> values,
int classes, QList<double> &labels )
772 if ( !values.count() )
773 return QList<double>();
777 int n = values.count();
778 double minimum = values[0];
779 double maximum = values[0];
781 for (
int i = 0; i < n; i++ )
784 minimum = qMin( values[i], minimum );
785 maximum = qMax( values[i], maximum );
787 mean = mean / ( double ) n;
790 for (
int i = 0; i < n; i++ )
792 sd = values[i] - mean;
795 stdDev = sqrt( stdDev / n );
797 QList<double> breaks =
_calcPrettyBreaks(( minimum - mean ) / stdDev, ( maximum - mean ) / stdDev, classes );
798 for (
int i = 0; i < breaks.count(); i++ )
800 labels.append( breaks[i] );
801 breaks[i] = ( breaks[i] * stdDev ) + mean;
808 double minimum,
double maximum,
809 int maximumSize = 1000 )
821 if ( !values.count() )
822 return QList<double>();
826 return QList<double>() << maximum;
829 if ( classes >= values.size() )
834 QVector<double> sample;
837 if ( values.size() > maximumSize )
843 sample.resize( qMax( maximumSize, values.size() / 10 ) );
845 QgsDebugMsg( QString(
"natural breaks (jenks) sample size: %1" ).arg( sample.size() ) );
846 QgsDebugMsg( QString(
"values:%1" ).arg( values.size() ) );
848 sample[ 0 ] = minimum;
849 sample[ 1 ] = maximum;;
850 for (
int i = 2; i < sample.size(); i++ )
854 int j = floor( r / RAND_MAX * ( values.size() - 1 ) );
855 sample[ i ] = values[ j ];
860 sample = values.toVector();
863 int n = sample.size();
868 QVector< QVector<int> > matrixOne( n + 1 );
869 QVector< QVector<double> > matrixTwo( n + 1 );
871 for (
int i = 0; i <= n; i++ )
873 matrixOne[i].resize( classes + 1 );
874 matrixTwo[i].resize( classes + 1 );
877 for (
int i = 1; i <= classes; i++ )
881 matrixTwo[0][i] = 0.0;
882 for (
int j = 2; j <= n; j++ )
888 for (
int l = 2; l <= n; l++ )
896 for (
int m = 1; m <= l; m++ )
900 double val = sample[ i3 - 1 ];
906 v = s2 - ( s1 * s1 ) / (
double ) w;
910 for (
int j = 2; j <= classes; j++ )
912 if ( matrixTwo[l][j] >= v + matrixTwo[i4][j - 1] )
914 matrixOne[l][j] = i4;
915 matrixTwo[l][j] = v + matrixTwo[i4][j - 1];
924 QVector<double> breaks( classes );
925 breaks[classes-1] = sample[n-1];
927 for (
int j = classes, k = n; j >= 2; j-- )
929 int id = matrixOne[k][j] - 1;
930 breaks[j - 2] = sample[id];
931 k = matrixOne[k][j] - 1;
934 return breaks.toList();
962 QList<double> values;
963 QScopedPointer<QgsExpression> expression;
970 if ( expression->hasParserError() || !expression->prepare( vlayer->
pendingFields() ) )
976 if ( expression.isNull() )
979 lst = expression->referencedColumns();
982 .setFlags(( expression && expression->needsGeometry() ) ?
990 QVariant v = expression ? expression->evaluate( f ) : f.
attribute( attrNum );
992 values.append( v.toDouble() );
1010 QList<double> values;
1011 bool valuesLoaded =
false;
1017 if ( attrNum == -1 )
1020 if ( values.isEmpty() )
1024 minimum = values.first();
1025 maximum = values.last();
1026 valuesLoaded =
true;
1034 QgsDebugMsg( QString(
"min %1 // max %2" ).arg( minimum ).arg( maximum ) );
1035 QList<double> breaks;
1036 QList<double> labels;
1041 else if ( mode ==
Pretty )
1048 if ( !valuesLoaded )
1058 else if ( mode ==
Jenks )
1062 else if ( mode ==
StdDev )
1072 double lower, upper = minimum;
1079 for ( QList<double>::iterator it = breaks.begin(); it != breaks.end(); ++it, ++i )
1089 label =
"< " + QString::number( labels[i],
'f', 2 ) +
" Std Dev";
1091 else if ( i == labels.count() - 1 )
1093 label =
">= " + QString::number( labels[i-1],
'f', 2 ) +
" Std Dev";
1097 label = QString::number( labels[i-1],
'f', 2 ) +
" Std Dev" +
" - " + QString::number( labels[i],
'f', 2 ) +
" Std Dev";
1113 QDomElement symbolsElem = element.firstChildElement(
"symbols" );
1114 if ( symbolsElem.isNull() )
1117 QDomElement rangesElem = element.firstChildElement(
"ranges" );
1118 if ( rangesElem.isNull() )
1124 QDomElement rangeElem = rangesElem.firstChildElement();
1125 while ( !rangeElem.isNull() )
1127 if ( rangeElem.tagName() ==
"range" )
1129 double lowerValue = rangeElem.attribute(
"lower" ).toDouble();
1130 double upperValue = rangeElem.attribute(
"upper" ).toDouble();
1131 QString symbolName = rangeElem.attribute(
"symbol" );
1132 QString label = rangeElem.attribute(
"label" );
1133 bool render = rangeElem.attribute(
"render",
"true" ) !=
"false";
1134 if ( symbolMap.contains( symbolName ) )
1136 QgsSymbolV2* symbol = symbolMap.take( symbolName );
1137 ranges.append(
QgsRendererRangeV2( lowerValue, upperValue, symbol, label, render ) );
1140 rangeElem = rangeElem.nextSiblingElement();
1143 QString attrName = element.attribute(
"attr" );
1151 QDomElement sourceSymbolElem = element.firstChildElement(
"source-symbol" );
1152 if ( !sourceSymbolElem.isNull() )
1155 if ( sourceSymbolMap.contains(
"0" ) )
1163 QDomElement sourceColorRampElem = element.firstChildElement(
"colorramp" );
1164 if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute(
"name" ) ==
"[source]" )
1167 QDomElement invertedColorRampElem = element.firstChildElement(
"invertedcolorramp" );
1168 if ( !invertedColorRampElem.isNull() )
1173 QDomElement modeElem = element.firstChildElement(
"mode" );
1174 if ( !modeElem.isNull() )
1176 QString modeString = modeElem.attribute(
"name" );
1177 if ( modeString ==
"equal" )
1179 else if ( modeString ==
"quantile" )
1181 else if ( modeString ==
"jenks" )
1183 else if ( modeString ==
"stddev" )
1185 else if ( modeString ==
"pretty" )
1189 QDomElement rotationElem = element.firstChildElement(
"rotation" );
1190 if ( !rotationElem.isNull() )
1193 QDomElement sizeScaleElem = element.firstChildElement(
"sizescale" );
1194 if ( !sizeScaleElem.isNull() )
1198 QDomElement labelFormatElem = element.firstChildElement(
"labelformat" );
1199 if ( ! labelFormatElem.isNull() )
1212 rendererElem.setAttribute(
"type",
"graduatedSymbol" );
1214 rendererElem.setAttribute(
"attr",
mAttrName );
1219 QDomElement rangesElem = doc.createElement(
"ranges" );
1220 QgsRangeList::const_iterator it =
mRanges.constBegin();
1221 for ( ; it !=
mRanges.constEnd(); ++it )
1224 QString symbolName = QString::number( i );
1225 symbols.insert( symbolName, range.
symbol() );
1227 QDomElement rangeElem = doc.createElement(
"range" );
1228 rangeElem.setAttribute(
"lower", QString::number( range.
lowerValue(),
'f' ) );
1229 rangeElem.setAttribute(
"upper", QString::number( range.
upperValue(),
'f' ) );
1230 rangeElem.setAttribute(
"symbol", symbolName );
1231 rangeElem.setAttribute(
"label", range.
label() );
1232 rangeElem.setAttribute(
"render", range.
renderState() ?
"true" :
"false" );
1233 rangesElem.appendChild( rangeElem );
1237 rendererElem.appendChild( rangesElem );
1241 rendererElem.appendChild( symbolsElem );
1249 rendererElem.appendChild( sourceSymbolElem );
1256 rendererElem.appendChild( colorRampElem );
1257 QDomElement invertedElem = doc.createElement(
"invertedcolorramp" );
1259 rendererElem.appendChild( invertedElem );
1265 modeString =
"equal";
1267 modeString =
"quantile";
1269 modeString =
"jenks";
1271 modeString =
"stddev";
1273 modeString =
"pretty";
1274 if ( !modeString.isEmpty() )
1276 QDomElement modeElem = doc.createElement(
"mode" );
1277 modeElem.setAttribute(
"name", modeString );
1278 rendererElem.appendChild( modeElem );
1281 QDomElement rotationElem = doc.createElement(
"rotation" );
1284 rendererElem.appendChild( rotationElem );
1286 QDomElement sizeScaleElem = doc.createElement(
"sizescale" );
1290 rendererElem.appendChild( sizeScaleElem );
1292 QDomElement labelFormatElem = doc.createElement(
"labelformat" );
1294 rendererElem.appendChild( labelFormatElem );
1296 return rendererElem;
1302 int count =
ranges().count();
1303 for (
int i = 0; i < count; i++ )
1307 lst << qMakePair( range.
label(), pix );
1314 Q_UNUSED( scaleDenominator );
1319 if ( rule.isEmpty() || range.
label() == rule )
1321 lst << qMakePair( range.
label(), range.
symbol() );
1364 colorValue = (
mRanges.count() > 1 ? ( double )(
mRanges.count() - i - 1 ) / (
mRanges.count() - 1 ) : 0 );
1366 colorValue = (
mRanges.count() > 1 ? ( double ) i / (
mRanges.count() - 1 ) : 0 );
1415 for ( QgsRangeList::iterator it =
mRanges.begin(); it !=
mRanges.end(); ++it )
1430 int index = key.toInt( &ok );
1431 if ( ok && index >= 0 && index <
mRanges.size() )
1432 return mRanges[ index ].renderState();
1440 int index = key.toInt( &ok );
1449 QString label =
"0.0 - 0.0";
1479 for ( QgsRangeList::iterator it =
mRanges.begin(); it !=
mRanges.end(); ++it )
1491 double minClassRange = 0.0;
1492 for ( QgsRangeList::iterator it =
mRanges.begin(); it !=
mRanges.end(); ++it )
1494 double range = it->upperValue() - it->lowerValue();
1497 if ( minClassRange == 0.0 || range < minClassRange )
1498 minClassRange = range;
1500 if ( minClassRange <= 0.0 )
1507 double nextDpMinRange = 0.0000000099;
1508 while ( ndp > 0 && nextDpMinRange < minClassRange )
1511 nextDpMinRange *= 10.0;
1519 if ( from < 0 || from >=
mRanges.size() || to < 0 || to >=
mRanges.size() )
1537 if ( order == Qt::AscendingOrder )
1549 return QString::localeAwareCompare( r1.
label(), r2.
label() ) < 0;
1559 if ( order == Qt::AscendingOrder )
1571 if ( renderer->
type() ==
"graduatedSymbol" )
1575 if ( renderer->
type() ==
"pointDisplacement" )
1578 if ( pointDisplacementRenderer )
1581 if ( renderer->
type() ==
"invertedPolygonRenderer" )
1584 if ( invertedPolygonRenderer )
1593 if ( symbols.size() > 0 )