32 #include <QDomDocument> 33 #include <QDomElement> 48 mValues.resize( context.
painter()->device()->width() * context.
painter()->device()->height() / ( mRenderQuality * mRenderQuality ) );
50 mCalculatedMaxValue = 0;
51 mFeaturesRendered = 0;
52 mRadiusPixels = std::round( context.
convertToPainterUnits( mRadius, mRadiusUnit, mRadiusMapUnitScale ) / mRenderQuality );
53 mRadiusSquared = mRadiusPixels * mRadiusPixels;
66 mWeightAttrNum = fields.
lookupField( mWeightExpressionString );
67 if ( mWeightAttrNum == -1 )
69 mWeightExpression.reset(
new QgsExpression( mWeightExpressionString ) );
73 initializeValues( context );
95 Q_UNUSED( drawVertexMarker )
109 if ( !mWeightExpressionString.isEmpty() )
112 if ( mWeightAttrNum == -1 )
114 Q_ASSERT( mWeightExpression.get() );
120 value = attrs.value( mWeightAttrNum );
123 double evalWeight = value.toDouble( &ok );
130 int width = context.
painter()->device()->width() / mRenderQuality;
131 int height = context.
painter()->device()->height() / mRenderQuality;
145 for ( QgsMultiPointXY::const_iterator pointIt = multiPoint.constBegin(); pointIt != multiPoint.constEnd(); ++pointIt )
148 int pointX = pixel.
x() / mRenderQuality;
149 int pointY = pixel.
y() / mRenderQuality;
150 for (
int x = std::max( pointX - mRadiusPixels, 0 ); x < std::min( pointX + mRadiusPixels, width ); ++x )
155 for (
int y = std::max( pointY - mRadiusPixels, 0 ); y < std::min( pointY + mRadiusPixels, height ); ++y )
157 int index = y * width + x;
158 if ( index >= mValues.count() )
162 double distanceSquared = std::pow( pointX - x, 2.0 ) + std::pow( pointY - y, 2.0 );
163 if ( distanceSquared > mRadiusSquared )
168 double score = weight * quarticKernel( std::sqrt( distanceSquared ), mRadiusPixels );
169 double value = mValues.at( index ) + score;
170 if ( value > mCalculatedMaxValue )
172 mCalculatedMaxValue = value;
174 mValues[ index ] = value;
182 if ( mFeaturesRendered % 200 == 0 )
184 renderImage( context );
191 double QgsHeatmapRenderer::uniformKernel(
const double distance,
const int bandwidth )
const 194 Q_UNUSED( bandwidth )
198 double QgsHeatmapRenderer::quarticKernel(
const double distance,
const int bandwidth )
const 200 return std::pow( 1. - std::pow( distance / static_cast< double >( bandwidth ), 2 ), 2 );
203 double QgsHeatmapRenderer::triweightKernel(
const double distance,
const int bandwidth )
const 205 return std::pow( 1. - std::pow( distance / static_cast< double >( bandwidth ), 2 ), 3 );
208 double QgsHeatmapRenderer::epanechnikovKernel(
const double distance,
const int bandwidth )
const 210 return ( 1. - std::pow( distance / static_cast< double >( bandwidth ), 2 ) );
213 double QgsHeatmapRenderer::triangularKernel(
const double distance,
const int bandwidth )
const 215 return ( 1. - ( distance / static_cast< double >( bandwidth ) ) );
222 renderImage( context );
223 mWeightExpression.reset();
233 QImage image( context.
painter()->device()->width() / mRenderQuality,
234 context.
painter()->device()->height() / mRenderQuality,
235 QImage::Format_ARGB32 );
236 image.fill( Qt::transparent );
238 double scaleMax = mExplicitMax > 0 ? mExplicitMax : mCalculatedMaxValue;
243 for (
int heightIndex = 0; heightIndex < image.height(); ++heightIndex )
248 QRgb *scanLine =
reinterpret_cast< QRgb *
>( image.scanLine( heightIndex ) );
249 for (
int widthIndex = 0; widthIndex < image.width(); ++widthIndex )
252 pixVal = mValues.at( idx ) > 0 ? std::min( ( mValues.at( idx ) / scaleMax ), 1.0 ) : 0;
255 pixColor = mGradientRamp->
color( pixVal );
257 scanLine[widthIndex] = pixColor.rgba();
262 if ( mRenderQuality > 1 )
264 QImage resized = image.scaled( context.
painter()->device()->width(),
265 context.
painter()->device()->height() );
266 context.
painter()->drawImage( 0, 0, resized );
270 context.
painter()->drawImage( 0, 0, image );
276 return QStringLiteral(
"[HEATMAP]" );
301 double extension = context.
convertToMapUnits( mRadius, mRadiusUnit, mRadiusMapUnitScale );
312 r->
setRadius( element.attribute( QStringLiteral(
"radius" ), QStringLiteral(
"50.0" ) ).toFloat() );
313 r->
setRadiusUnit( static_cast< QgsUnitTypes::RenderUnit >( element.attribute( QStringLiteral(
"radius_unit" ), QStringLiteral(
"0" ) ).toInt() ) );
315 r->
setMaximumValue( element.attribute( QStringLiteral(
"max_value" ), QStringLiteral(
"0.0" ) ).toFloat() );
316 r->
setRenderQuality( element.attribute( QStringLiteral(
"quality" ), QStringLiteral(
"0" ) ).toInt() );
319 QDomElement sourceColorRampElem = element.firstChildElement( QStringLiteral(
"colorramp" ) );
320 if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( QStringLiteral(
"name" ) ) == QLatin1String(
"[source]" ) )
331 rendererElem.setAttribute( QStringLiteral(
"type" ), QStringLiteral(
"heatmapRenderer" ) );
332 rendererElem.setAttribute( QStringLiteral(
"radius" ), QString::number( mRadius ) );
333 rendererElem.setAttribute( QStringLiteral(
"radius_unit" ), QString::number( mRadiusUnit ) );
335 rendererElem.setAttribute( QStringLiteral(
"max_value" ), QString::number( mExplicitMax ) );
336 rendererElem.setAttribute( QStringLiteral(
"quality" ), QString::number( mRenderQuality ) );
337 rendererElem.setAttribute( QStringLiteral(
"weight_expression" ), mWeightExpressionString );
341 rendererElem.appendChild( colorRampElem );
343 rendererElem.setAttribute( QStringLiteral(
"forceraster" ), (
mForceRaster ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) ) );
350 QDomElement
orderBy = doc.createElement( QStringLiteral(
"orderby" ) );
352 rendererElem.appendChild( orderBy );
354 rendererElem.setAttribute( QStringLiteral(
"enableorderby" ), (
mOrderByEnabled ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) ) );
372 QSet<QString> attributes;
378 attributes << mWeightExpressionString;
389 if ( renderer->
type() == QLatin1String(
"heatmapRenderer" ) )
412 delete mGradientRamp;
413 mGradientRamp = ramp;
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Class for parsing and evaluation of expressions (formerly called "search strings").
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
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.
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.
Abstract base class for all rendered symbols.
OperationResult transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection direction=QgsCoordinateTransform::ForwardTransform, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
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.
QgsSymbolList symbols(QgsRenderContext &context) const override
virtual QgsColorRamp * clone() const =0
Creates a clone of the color ramp.
A class to represent a 2D point.
QgsFeatureRequest::OrderBy orderBy() const
Gets the order in which features shall be processed by this renderer.
bool renderFeature(const QgsFeature &feature, QgsRenderContext &context, int layer=-1, bool selected=false, bool drawVertexMarker=false) override SIP_THROW(QgsCsException)
Render a feature using this renderer in the given context.
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.
bool renderingStopped() const
Returns true if the rendering operation has been stopped and any ongoing rendering should be canceled...
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
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
An interface for classes which can visit style entity (e.g.
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
Returns a list of attributes required by this renderer.
static QgsFeatureRenderer * create(QDomElement &element, const QgsReadWriteContext &context)
Creates a new heatmap renderer instance from XML.
virtual bool visit(const QgsStyleEntityVisitorInterface::StyleLeaf &entity)
Called when the visitor will visit a style entity.
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.
bool accept(QgsStyleEntityVisitorInterface *visitor) const override
Accepts the specified symbology visitor, causing it to visit all symbols associated with the renderer...
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.
void startRender(QgsRenderContext &context, const QgsFields &fields) override
Must be called when a new render cycle is started.
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.
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
QgsSymbol * symbolForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
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
Returns the context's map to pixel transform, which transforms between map coordinates and device coo...
QgsPointXY asPoint() const
Returns the contents of the geometry as a 2-dimensional point.
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).
QgsWkbTypes::GeometryType type
QgsMultiPointXY asMultiPoint() const
Returns the contents of the geometry as a multi-point.
A color ramp entity for QgsStyle databases.
~QgsHeatmapRenderer() override
Gradient color ramp, which smoothly interpolates between two colors and also supports optional extra ...
Contains information relating to the style entity currently being visited.
void setMaximumValue(const double value)
Sets the maximum value used for shading the heatmap.
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.