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;
Class for parsing and evaluation of expressions (formerly called "search strings").
void setInvertRamp(const bool invert)
Sets whether the ramp is inverted.
#define RENDERER_TAG_NAME
A rectangle specified with double values.
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
virtual ~QgsHeatmapRenderer()
QStringList referencedColumns() const
Get list of columns referenced by the expression.
virtual bool renderFeature(QgsFeature &feature, QgsRenderContext &context, int layer=-1, bool selected=false, bool drawVertexMarker=false) override
static QgsVectorColorRampV2 * loadColorRamp(QDomElement &element)
virtual QString dump() const override
for debugging
static QgsFeatureRendererV2 * create(QDomElement &element)
virtual QList< QString > usedAttributes() override
QList< QgsSymbolV2 * > QgsSymbolV2List
void setXMaximum(double x)
Set the maximum x value.
virtual void modifyRequestExtent(QgsRectangle &extent, QgsRenderContext &context) override
Allows for a renderer to modify the extent of a feature request prior to rendering.
double yMaximum() const
Get the y maximum value (top side of rectangle)
int fieldNameIndex(const QString &fieldName) const
Look up field's index from name also looks up case-insensitive if there is no match otherwise...
QgsGeometry * geometry() const
Get the geometry object associated with this feature.
QgsPoint transform(const QgsPoint &p) const
QGis::GeometryType type() const
Returns type of the vector.
Container of fields for a vector layer.
void setWeightExpression(const QString &expression)
Sets the expression used for weighting points when generating the heatmap.
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
const QgsCoordinateTransform * coordinateTransform() const
void setRadiusUnit(const QgsSymbolV2::OutputUnit unit)
Sets the units used for the heatmap's radius.
static double pixelSizeScaleFactor(const QgsRenderContext &c, QgsSymbolV2::OutputUnit u, const QgsMapUnitScale &scale=QgsMapUnitScale())
Returns scale factor painter units -> pixel dimensions.
virtual QgsSymbolV2List symbols() override
for symbol levels
virtual QgsFeatureRendererV2 * clone() const =0
static QDomElement saveColorRamp(QString name, QgsVectorColorRampV2 *ramp, QDomDocument &doc)
double yMinimum() const
Get the y minimum value (bottom side of rectangle)
double xMaximum() const
Get the x maximum value (right side of rectangle)
A renderer which draws points as a live heatmap.
void setRadiusMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale used for the heatmap's radius.
virtual QgsVectorColorRampV2 * clone() const =0
void setYMinimum(double y)
Set the minimum y value.
QVector< QgsPoint > QgsMultiPoint
a collection of QgsPoints that share a common collection of attributes
const QgsAttributes & attributes() const
virtual QDomElement save(QDomDocument &doc) override
store renderer info to XML element
virtual void startRender(QgsRenderContext &context, const QgsFields &fields) override
virtual QgsFeatureRendererV2 * clone() const override
A class to represent a point.
void setRenderQuality(const int quality)
Sets the render quality used for drawing the heatmap.
virtual QColor color(double value) const =0
virtual QgsSymbolV2 * symbolForFeature(QgsFeature &feature) override
to be overridden
void setRadius(const double radius)
Sets the radius for the heatmap.
void setColorRamp(QgsVectorColorRampV2 *ramp)
Sets the color ramp to use for shading the heatmap.
Contains information about the context of a rendering operation.
Struct for storing maximum and minimum scales for measurements in map units.
static QgsHeatmapRenderer * convertFromRenderer(const QgsFeatureRendererV2 *renderer)
void setYMaximum(double y)
Set the maximum y value.
QgsMultiPoint asMultiPoint() const
return contents of the geometry as a multi point if wkbType is WKBMultiPoint, otherwise an empty list...
bool isMultipart() const
Returns true if wkb of the geometry is of WKBMulti* type.
virtual void stopRender(QgsRenderContext &context) override
int transform(const QgsCoordinateTransform &ct)
Transform this geometry as described by CoordinateTransform ct.
const QgsMapToPixel & mapToPixel() const
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
QgsPoint asPoint() const
return contents of the geometry as a point if wkbType is WKBPoint, otherwise returns [0...
double xMinimum() const
Get the x minimum value (left side of rectangle)
void setMaximumValue(const double value)
Sets the maximum value used for shading the heatmap.
void setXMinimum(double x)
Set the minimum x value.