29 #include <QDomDocument>
30 #include <QDomElement>
34 , mCalculatedMaxValue( 0 )
39 , mWeightAttrNum( -1 )
41 , mInvertRamp( false )
44 , mFeaturesRendered( 0 )
57 mValues.resize( context.
painter()->device()->width() * context.
painter()->device()->height() / ( mRenderQuality * mRenderQuality ) );
59 mCalculatedMaxValue = 0;
60 mFeaturesRendered = 0;
62 mRadiusSquared = mRadiusPixels * mRadiusPixels;
75 if ( mWeightAttrNum == -1 )
77 mWeightExpression.reset(
new QgsExpression( mWeightExpressionString ) );
78 mWeightExpression->prepare( fields );
81 initializeValues( context );
102 Q_UNUSED( selected );
103 Q_UNUSED( drawVertexMarker );
117 if ( !mWeightExpressionString.isEmpty() )
120 if ( mWeightAttrNum == -1 )
122 Q_ASSERT( mWeightExpression.data() );
123 value = mWeightExpression->evaluate( &feature );
128 value = attrs.value( mWeightAttrNum );
131 double evalWeight = value.toDouble( &ok );
138 int width = context.
painter()->device()->width() / mRenderQuality;
139 int height = context.
painter()->device()->height() / mRenderQuality;
143 bool createdGeom =
false;
165 for ( QgsMultiPoint::const_iterator pointIt = multiPoint.constBegin(); pointIt != multiPoint.constEnd(); ++pointIt )
168 int pointX = pixel.
x() / mRenderQuality;
169 int pointY = pixel.
y() / mRenderQuality;
170 for (
int x = qMax( pointX - mRadiusPixels, 0 ); x < qMin( pointX + mRadiusPixels, width ); ++x )
172 for (
int y = qMax( pointY - mRadiusPixels, 0 ); y < qMin( pointY + mRadiusPixels, height ); ++y )
174 int index = y * width + x;
175 if ( index >= mValues.count( ) )
179 double distanceSquared = pow( pointX - x, 2.0 ) + pow( pointY - y, 2.0 );
180 if ( distanceSquared > mRadiusSquared )
185 double score = weight * quarticKernel( sqrt( distanceSquared ), mRadiusPixels );
186 double value = mValues[
index ] + score;
187 if ( value > mCalculatedMaxValue )
189 mCalculatedMaxValue = value;
191 mValues[
index ] = value;
199 if ( mFeaturesRendered % 200 == 0 )
201 renderImage( context );
208 double QgsHeatmapRenderer::uniformKernel(
const double distance,
const int bandwidth )
const
210 Q_UNUSED( distance );
211 Q_UNUSED( bandwidth );
215 double QgsHeatmapRenderer::quarticKernel(
const double distance,
const int bandwidth )
const
217 return pow( 1. - pow( distance / (
double )bandwidth, 2 ), 2 );
220 double QgsHeatmapRenderer::triweightKernel(
const double distance,
const int bandwidth )
const
222 return pow( 1. - pow( distance / (
double )bandwidth, 2 ), 3 );
225 double QgsHeatmapRenderer::epanechnikovKernel(
const double distance,
const int bandwidth )
const
227 return ( 1. - pow( distance / (
double )bandwidth, 2 ) );
230 double QgsHeatmapRenderer::triangularKernel(
const double distance,
const int bandwidth )
const
232 return ( 1. - ( distance / (
double )bandwidth ) );
237 renderImage( context );
238 mWeightExpression.reset();
243 if ( !context.
painter() || !mGradientRamp )
248 QImage image( context.
painter()->device()->width() / mRenderQuality,
249 context.
painter()->device()->height() / mRenderQuality,
250 QImage::Format_ARGB32 );
251 image.fill( Qt::transparent );
253 double scaleMax = mExplicitMax > 0 ? mExplicitMax : mCalculatedMaxValue;
258 for (
int heightIndex = 0; heightIndex < image.height(); ++heightIndex )
260 QRgb* scanLine = ( QRgb* )image.scanLine( heightIndex );
261 for (
int widthIndex = 0; widthIndex < image.width(); ++widthIndex )
264 pixVal = mValues.at( idx ) > 0 ? qMin(( mValues.at( idx ) / scaleMax ), 1.0 ) : 0;
267 pixColor = mGradientRamp->
color( mInvertRamp ? 1 - pixVal : pixVal );
269 scanLine[widthIndex] = pixColor.rgba();
274 if ( mRenderQuality > 1 )
276 QImage resized = image.scaled( context.
painter()->device()->width(),
277 context.
painter()->device()->height() );
278 context.
painter()->drawImage( 0, 0, resized );
282 context.
painter()->drawImage( 0, 0, image );
313 double extension = 0.0;
336 r->
setRadius( element.attribute(
"radius",
"50.0" ).toFloat() );
339 r->
setMaximumValue( element.attribute(
"max_value",
"0.0" ).toFloat() );
343 QDomElement sourceColorRampElem = element.firstChildElement(
"colorramp" );
344 if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute(
"name" ) ==
"[source]" )
348 r->
setInvertRamp( element.attribute(
"invert_ramp",
"0" ).toInt() );
355 rendererElem.setAttribute(
"type",
"heatmapRenderer" );
356 rendererElem.setAttribute(
"radius", QString::number( mRadius ) );
357 rendererElem.setAttribute(
"radius_unit", QString::number( mRadiusUnit ) );
359 rendererElem.setAttribute(
"max_value", QString::number( mExplicitMax ) );
360 rendererElem.setAttribute(
"quality", QString::number( mRenderQuality ) );
361 rendererElem.setAttribute(
"weight_expression", mWeightExpressionString );
365 rendererElem.appendChild( colorRampElem );
367 rendererElem.setAttribute(
"invert_ramp", QString::number( mInvertRamp ) );
385 QSet<QString> attributes;
391 attributes << mWeightExpressionString;
397 return attributes.toList();
402 if ( renderer->
type() ==
"heatmapRenderer" )
414 delete mGradientRamp;
415 mGradientRamp = ramp;