31 #include <QDomDocument> 32 #include <QDomElement> 47 mValues.resize( context.
painter()->device()->width() * context.
painter()->device()->height() / ( mRenderQuality * mRenderQuality ) );
49 mCalculatedMaxValue = 0;
50 mFeaturesRendered = 0;
51 mRadiusPixels = std::round( context.
convertToPainterUnits( mRadius, mRadiusUnit, mRadiusMapUnitScale ) / mRenderQuality );
52 mRadiusSquared = mRadiusPixels * mRadiusPixels;
65 mWeightAttrNum = fields.
lookupField( mWeightExpressionString );
66 if ( mWeightAttrNum == -1 )
68 mWeightExpression.reset(
new QgsExpression( mWeightExpressionString ) );
72 initializeValues( context );
94 Q_UNUSED( drawVertexMarker );
108 if ( !mWeightExpressionString.isEmpty() )
111 if ( mWeightAttrNum == -1 )
113 Q_ASSERT( mWeightExpression.get() );
119 value = attrs.value( mWeightAttrNum );
122 double evalWeight = value.toDouble( &ok );
129 int width = context.
painter()->device()->width() / mRenderQuality;
130 int height = context.
painter()->device()->height() / mRenderQuality;
144 for ( QgsMultiPointXY::const_iterator pointIt = multiPoint.constBegin(); pointIt != multiPoint.constEnd(); ++pointIt )
147 int pointX = pixel.
x() / mRenderQuality;
148 int pointY = pixel.
y() / mRenderQuality;
149 for (
int x = std::max( pointX - mRadiusPixels, 0 ); x < std::min( pointX + mRadiusPixels, width ); ++x )
151 for (
int y = std::max( pointY - mRadiusPixels, 0 ); y < std::min( pointY + mRadiusPixels, height ); ++y )
153 int index = y * width + x;
154 if ( index >= mValues.count() )
158 double distanceSquared = std::pow( pointX - x, 2.0 ) + std::pow( pointY - y, 2.0 );
159 if ( distanceSquared > mRadiusSquared )
164 double score = weight * quarticKernel( std::sqrt( distanceSquared ), mRadiusPixels );
165 double value = mValues.at( index ) + score;
166 if ( value > mCalculatedMaxValue )
168 mCalculatedMaxValue = value;
170 mValues[ index ] = value;
178 if ( mFeaturesRendered % 200 == 0 )
180 renderImage( context );
187 double QgsHeatmapRenderer::uniformKernel(
const double distance,
const int bandwidth )
const 189 Q_UNUSED( distance );
190 Q_UNUSED( bandwidth );
194 double QgsHeatmapRenderer::quarticKernel(
const double distance,
const int bandwidth )
const 196 return std::pow( 1. - std::pow( distance / static_cast< double >( bandwidth ), 2 ), 2 );
199 double QgsHeatmapRenderer::triweightKernel(
const double distance,
const int bandwidth )
const 201 return std::pow( 1. - std::pow( distance / static_cast< double >( bandwidth ), 2 ), 3 );
204 double QgsHeatmapRenderer::epanechnikovKernel(
const double distance,
const int bandwidth )
const 206 return ( 1. - std::pow( distance / static_cast< double >( bandwidth ), 2 ) );
209 double QgsHeatmapRenderer::triangularKernel(
const double distance,
const int bandwidth )
const 211 return ( 1. - ( distance / static_cast< double >( bandwidth ) ) );
218 renderImage( context );
219 mWeightExpression.reset();
224 if ( !context.
painter() || !mGradientRamp )
229 QImage image( context.
painter()->device()->width() / mRenderQuality,
230 context.
painter()->device()->height() / mRenderQuality,
231 QImage::Format_ARGB32 );
232 image.fill( Qt::transparent );
234 double scaleMax = mExplicitMax > 0 ? mExplicitMax : mCalculatedMaxValue;
239 for (
int heightIndex = 0; heightIndex < image.height(); ++heightIndex )
241 QRgb *scanLine =
reinterpret_cast< QRgb *
>( image.scanLine( heightIndex ) );
242 for (
int widthIndex = 0; widthIndex < image.width(); ++widthIndex )
245 pixVal = mValues.at( idx ) > 0 ? std::min( ( mValues.at( idx ) / scaleMax ), 1.0 ) : 0;
248 pixColor = mGradientRamp->
color( pixVal );
250 scanLine[widthIndex] = pixColor.rgba();
255 if ( mRenderQuality > 1 )
257 QImage resized = image.scaled( context.
painter()->device()->width(),
258 context.
painter()->device()->height() );
259 context.
painter()->drawImage( 0, 0, resized );
263 context.
painter()->drawImage( 0, 0, image );
269 return QStringLiteral(
"[HEATMAP]" );
294 double extension = context.
convertToMapUnits( mRadius, mRadiusUnit, mRadiusMapUnitScale );
305 r->
setRadius( element.attribute( QStringLiteral(
"radius" ), QStringLiteral(
"50.0" ) ).toFloat() );
306 r->
setRadiusUnit( static_cast< QgsUnitTypes::RenderUnit >( element.attribute( QStringLiteral(
"radius_unit" ), QStringLiteral(
"0" ) ).toInt() ) );
308 r->
setMaximumValue( element.attribute( QStringLiteral(
"max_value" ), QStringLiteral(
"0.0" ) ).toFloat() );
309 r->
setRenderQuality( element.attribute( QStringLiteral(
"quality" ), QStringLiteral(
"0" ) ).toInt() );
312 QDomElement sourceColorRampElem = element.firstChildElement( QStringLiteral(
"colorramp" ) );
313 if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( QStringLiteral(
"name" ) ) == QLatin1String(
"[source]" ) )
324 rendererElem.setAttribute( QStringLiteral(
"type" ), QStringLiteral(
"heatmapRenderer" ) );
325 rendererElem.setAttribute( QStringLiteral(
"radius" ), QString::number( mRadius ) );
326 rendererElem.setAttribute( QStringLiteral(
"radius_unit" ), QString::number( mRadiusUnit ) );
328 rendererElem.setAttribute( QStringLiteral(
"max_value" ), QString::number( mExplicitMax ) );
329 rendererElem.setAttribute( QStringLiteral(
"quality" ), QString::number( mRenderQuality ) );
330 rendererElem.setAttribute( QStringLiteral(
"weight_expression" ), mWeightExpressionString );
334 rendererElem.appendChild( colorRampElem );
336 rendererElem.setAttribute( QStringLiteral(
"forceraster" ), (
mForceRaster ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) ) );
343 QDomElement
orderBy = doc.createElement( QStringLiteral(
"orderby" ) );
345 rendererElem.appendChild( orderBy );
347 rendererElem.setAttribute( QStringLiteral(
"enableorderby" ), (
mOrderByEnabled ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) ) );
365 QSet<QString> attributes;
371 attributes << mWeightExpressionString;
373 QgsExpression testExpr( mWeightExpressionString );
374 if ( !testExpr.hasParserError() )
375 attributes.unite( testExpr.referencedColumns() );
382 if ( renderer->
type() == QLatin1String(
"heatmapRenderer" ) )
394 delete mGradientRamp;
395 mGradientRamp = ramp;
int lookupField(const QString &fieldName) const
Look up field's index from the field name.
The class is used as a container of context for various read/write operations on other objects...
double convertToMapUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to map units.
A rectangle specified with double values.
bool renderFeature(QgsFeature &feature, QgsRenderContext &context, int layer=-1, bool selected=false, bool drawVertexMarker=false) override
Render a feature using this renderer in the given context.
QgsFeatureRequest::OrderBy mOrderBy
bool isMultipart() const
Returns true if WKB of the geometry is of WKBMulti* type.
QString dump() const override
Returns debug information about this renderer.
void setColorRamp(QgsColorRamp *ramp)
Sets the color ramp to use for shading the heatmap.
void setXMaximum(double x)
Set the maximum x value.
void modifyRequestExtent(QgsRectangle &extent, QgsRenderContext &context) override
Allows for a renderer to modify the extent of a feature request prior to rendering.
virtual QgsColorRamp * clone() const =0
Creates a clone of the color ramp.
A class to represent a 2D point.
QgsFeatureRequest::OrderBy orderBy() const
Get the order in which features shall be processed by this renderer.
Abstract base class for color ramps.
static bool isDefaultStack(QgsPaintEffect *effect)
Tests whether a paint effect matches the default effects stack.
static QDomElement saveColorRamp(const QString &name, QgsColorRamp *ramp, QDomDocument &doc)
Encodes a color ramp's settings to an XML element.
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
Container of fields for a vector layer.
A geometry is the spatial representation of a feature.
#define RENDERER_TAG_NAME
void setWeightExpression(const QString &expression)
Sets the expression used for weighting points when generating the heatmap.
QVector< QgsPointXY > QgsMultiPointXY
A collection of QgsPoints that share a common collection of attributes.
QgsPaintEffect * mPaintEffect
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
bool hasGeometry() const
Returns true if the feature has an associated geometry.
virtual QColor color(double value) const =0
Returns the color corresponding to a specified value.
QSet< QString > usedAttributes(const QgsRenderContext &context) const override
Return a list of attributes required by this renderer.
static QgsFeatureRenderer * create(QDomElement &element, const QgsReadWriteContext &context)
Creates a new heatmap renderer instance from XML.
QgsPointXY transform(const QgsPointXY &p) const
Transform the point from map (world) coordinates to device coordinates.
QList< QgsSymbol * > QgsSymbolList
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.
void setYMinimum(double y)
Set the minimum y value.
static QgsColorRamp * loadColorRamp(QDomElement &element)
Creates a color ramp from the settings encoded in an XML element.
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context, or an invalid transform is no coordinate tr...
QgsGeometry geometry() const
Returns the geometry associated with this feature.
void startRender(QgsRenderContext &context, const QgsFields &fields) override
Must be called when a new render cycle is started.
QgsWkbTypes::GeometryType type() const
Returns type of the geometry as a QgsWkbTypes::GeometryType.
void setRenderQuality(const int quality)
Sets the render quality used for drawing the heatmap.
void setRadiusUnit(const QgsUnitTypes::RenderUnit unit)
Sets the units used for the heatmap's radius.
OperationResult transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection direction=QgsCoordinateTransform::ForwardTransform, bool transformZ=false)
Transforms this geometry as described by the coordinate transform ct.
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
QDomElement save(QDomDocument &doc, const QgsReadWriteContext &context) override
store renderer info to XML element
QgsExpressionContext & expressionContext()
Gets the expression context.
void setRadius(const double radius)
Sets the radius for the heatmap.
double xMaximum() const
Returns the x maximum value (right side of rectangle).
QgsHeatmapRenderer * clone() const override
Create a deep copy of this renderer.
Contains information about the context of a rendering operation.
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to painter units (pixels).
QPainter * painter()
Returns the destination QPainter for the render operation.
const QgsMapToPixel & mapToPixel() const
QgsPointXY asPoint() const
Returns contents of the geometry as a point if wkbType is WKBPoint, otherwise returns [0...
virtual void startRender(QgsRenderContext &context, const QgsFields &fields)
Must be called when a new render cycle is started.
void setYMaximum(double y)
Set the maximum y value.
void CORE_EXPORT save(QDomElement &elem) const
Serialize to XML.
void stopRender(QgsRenderContext &context) override
Must be called when a render cycle has finished, to allow the renderer to clean up.
virtual void stopRender(QgsRenderContext &context)
Must be called when a render cycle has finished, to allow the renderer to clean up.
static QgsHeatmapRenderer * convertFromRenderer(const QgsFeatureRenderer *renderer)
void copyRendererData(QgsFeatureRenderer *destRenderer) const
Clones generic renderer data to another renderer.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
double yMaximum() const
Returns the y maximum value (top side of rectangle).
QgsSymbolList symbols(QgsRenderContext &context) override
QgsMultiPointXY asMultiPoint() const
Returns contents of the geometry as a multi point if wkbType is WKBMultiPoint, otherwise an empty lis...
~QgsHeatmapRenderer() override
Gradient color ramp, which smoothly interpolates between two colors and also supports optional extra ...
void setMaximumValue(const double value)
Sets the maximum value used for shading the heatmap.
QgsSymbol * symbolForFeature(QgsFeature &feature, QgsRenderContext &context) override
virtual QgsFeatureRenderer * clone() const =0
Create a deep copy of this renderer.
void setXMinimum(double x)
Set the minimum x value.
virtual bool saveProperties(QDomDocument &doc, QDomElement &element) const
Saves the current state of the effect to a DOM element.