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 )
154 for (
int y = std::max( pointY - mRadiusPixels, 0 ); y < std::min( pointY + mRadiusPixels, height ); ++y )
156 int index = y * width + x;
157 if ( index >= mValues.count() )
161 double distanceSquared = std::pow( pointX - x, 2.0 ) + std::pow( pointY - y, 2.0 );
162 if ( distanceSquared > mRadiusSquared )
167 double score = weight * quarticKernel( std::sqrt( distanceSquared ), mRadiusPixels );
168 double value = mValues.at( index ) + score;
169 if ( value > mCalculatedMaxValue )
171 mCalculatedMaxValue = value;
173 mValues[ index ] = value;
181 if ( mFeaturesRendered % 200 == 0 )
183 renderImage( context );
190 double QgsHeatmapRenderer::uniformKernel(
const double distance,
const int bandwidth )
const 192 Q_UNUSED( distance );
193 Q_UNUSED( bandwidth );
197 double QgsHeatmapRenderer::quarticKernel(
const double distance,
const int bandwidth )
const 199 return std::pow( 1. - std::pow( distance / static_cast< double >( bandwidth ), 2 ), 2 );
202 double QgsHeatmapRenderer::triweightKernel(
const double distance,
const int bandwidth )
const 204 return std::pow( 1. - std::pow( distance / static_cast< double >( bandwidth ), 2 ), 3 );
207 double QgsHeatmapRenderer::epanechnikovKernel(
const double distance,
const int bandwidth )
const 209 return ( 1. - std::pow( distance / static_cast< double >( bandwidth ), 2 ) );
212 double QgsHeatmapRenderer::triangularKernel(
const double distance,
const int bandwidth )
const 214 return ( 1. - ( distance / static_cast< double >( bandwidth ) ) );
221 renderImage( context );
222 mWeightExpression.reset();
232 QImage image( context.
painter()->device()->width() / mRenderQuality,
233 context.
painter()->device()->height() / mRenderQuality,
234 QImage::Format_ARGB32 );
235 image.fill( Qt::transparent );
237 double scaleMax = mExplicitMax > 0 ? mExplicitMax : mCalculatedMaxValue;
242 for (
int heightIndex = 0; heightIndex < image.height(); ++heightIndex )
247 QRgb *scanLine =
reinterpret_cast< QRgb *
>( image.scanLine( heightIndex ) );
248 for (
int widthIndex = 0; widthIndex < image.width(); ++widthIndex )
251 pixVal = mValues.at( idx ) > 0 ? std::min( ( mValues.at( idx ) / scaleMax ), 1.0 ) : 0;
254 pixColor = mGradientRamp->
color( pixVal );
256 scanLine[widthIndex] = pixColor.rgba();
261 if ( mRenderQuality > 1 )
263 QImage resized = image.scaled( context.
painter()->device()->width(),
264 context.
painter()->device()->height() );
265 context.
painter()->drawImage( 0, 0, resized );
269 context.
painter()->drawImage( 0, 0, image );
275 return QStringLiteral(
"[HEATMAP]" );
300 double extension = context.
convertToMapUnits( mRadius, mRadiusUnit, mRadiusMapUnitScale );
311 r->
setRadius( element.attribute( QStringLiteral(
"radius" ), QStringLiteral(
"50.0" ) ).toFloat() );
312 r->
setRadiusUnit( static_cast< QgsUnitTypes::RenderUnit >( element.attribute( QStringLiteral(
"radius_unit" ), QStringLiteral(
"0" ) ).toInt() ) );
314 r->
setMaximumValue( element.attribute( QStringLiteral(
"max_value" ), QStringLiteral(
"0.0" ) ).toFloat() );
315 r->
setRenderQuality( element.attribute( QStringLiteral(
"quality" ), QStringLiteral(
"0" ) ).toInt() );
318 QDomElement sourceColorRampElem = element.firstChildElement( QStringLiteral(
"colorramp" ) );
319 if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( QStringLiteral(
"name" ) ) == QLatin1String(
"[source]" ) )
330 rendererElem.setAttribute( QStringLiteral(
"type" ), QStringLiteral(
"heatmapRenderer" ) );
331 rendererElem.setAttribute( QStringLiteral(
"radius" ), QString::number( mRadius ) );
332 rendererElem.setAttribute( QStringLiteral(
"radius_unit" ), QString::number( mRadiusUnit ) );
334 rendererElem.setAttribute( QStringLiteral(
"max_value" ), QString::number( mExplicitMax ) );
335 rendererElem.setAttribute( QStringLiteral(
"quality" ), QString::number( mRenderQuality ) );
336 rendererElem.setAttribute( QStringLiteral(
"weight_expression" ), mWeightExpressionString );
340 rendererElem.appendChild( colorRampElem );
342 rendererElem.setAttribute( QStringLiteral(
"forceraster" ), (
mForceRaster ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) ) );
349 QDomElement
orderBy = doc.createElement( QStringLiteral(
"orderby" ) );
351 rendererElem.appendChild( orderBy );
353 rendererElem.setAttribute( QStringLiteral(
"enableorderby" ), (
mOrderByEnabled ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) ) );
371 QSet<QString> attributes;
377 attributes << mWeightExpressionString;
388 if ( renderer->
type() == QLatin1String(
"heatmapRenderer" ) )
400 delete mGradientRamp;
401 mGradientRamp = ramp;
Class for parsing and evaluation of expressions (formerly called "search strings").
The class is used as a container of context for various read/write operations on other objects...
void CORE_EXPORT save(QDomElement &elem) const
Serialize to XML.
A rectangle specified with double values.
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
QgsFeatureRequest::OrderBy mOrderBy
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.
double yMaximum() const
Returns the y maximum value (top side of rectangle).
QgsSymbolList symbols(QgsRenderContext &context) const override
virtual QgsColorRamp * clone() const =0
Creates a clone of the color ramp.
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to painter units (pixels).
A class to represent a 2D point.
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
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.
double convertToMapUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to map units.
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
QgsPointXY asPoint() const
Returns the contents of the geometry as a 2-dimensional point.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
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.
QList< QgsSymbol * > QgsSymbolList
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
double xMaximum() const
Returns the x maximum value (right side of rectangle).
A renderer which draws points as a live heatmap.
bool renderingStopped() const
Returns TRUE if the rendering operation has been stopped and any ongoing rendering should be canceled...
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.
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
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.
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.
QgsHeatmapRenderer * clone() const override
Create a deep copy of this renderer.
virtual bool saveProperties(QDomDocument &doc, QDomElement &element) const
Saves the current state of the effect to a DOM element.
Contains information about the context of a rendering operation.
QPainter * painter()
Returns the destination QPainter for the render operation.
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.
bool isMultipart() const
Returns true if WKB of the geometry is of WKBMulti* type.
void copyRendererData(QgsFeatureRenderer *destRenderer) const
Clones generic renderer data to another renderer.
bool hasGeometry() const
Returns true if the feature has an associated geometry.
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)
const QgsMapToPixel & mapToPixel() const
Returns the context's map to pixel transform, which transforms between map coordinates and device coo...
QgsMultiPointXY asMultiPoint() const
Returns contents of the geometry as a multi point if wkbType is WKBMultiPoint, otherwise an empty lis...
QgsFeatureRequest::OrderBy orderBy() const
Gets the order in which features shall be processed by this renderer.
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
~QgsHeatmapRenderer() override
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.
Gradient color ramp, which smoothly interpolates between two colors and also supports optional extra ...
QgsPointXY transform(const QgsPointXY &p) const
Transform the point from map (world) coordinates to device coordinates.
QgsWkbTypes::GeometryType type() const
Returns type of the geometry as a QgsWkbTypes::GeometryType.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
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.