33#include <QDomDocument> 
   49  mValues.resize( context.
painter()->device()->width() * context.
painter()->device()->height() / ( mRenderQuality * mRenderQuality ) );
 
   51  mCalculatedMaxValue = 0;
 
   52  mFeaturesRendered = 0;
 
   53  mRadiusPixels = std::round( context.
convertToPainterUnits( mRadius, mRadiusUnit, mRadiusMapUnitScale ) / mRenderQuality );
 
   54  mRadiusSquared = mRadiusPixels * mRadiusPixels;
 
   67  mWeightAttrNum = fields.
lookupField( mWeightExpressionString );
 
   68  if ( mWeightAttrNum == -1 )
 
   70    mWeightExpression.reset( 
new QgsExpression( mWeightExpressionString ) );
 
   74  initializeValues( context );
 
   96  Q_UNUSED( drawVertexMarker )
 
  110  if ( !mWeightExpressionString.isEmpty() )
 
  113    if ( mWeightAttrNum == -1 )
 
  115      Q_ASSERT( mWeightExpression.get() );
 
  121      value = attrs.value( mWeightAttrNum );
 
  124    const double evalWeight = value.toDouble( &ok );
 
  131  const int width = context.
painter()->device()->width() / mRenderQuality;
 
  132  const int height = context.
painter()->device()->height() / mRenderQuality;
 
  146  for ( QgsMultiPointXY::const_iterator pointIt = multiPoint.constBegin(); pointIt != multiPoint.constEnd(); ++pointIt )
 
  149    const int pointX = pixel.
x() / mRenderQuality;
 
  150    const int pointY = pixel.
y() / mRenderQuality;
 
  151    for ( 
int x = std::max( pointX - mRadiusPixels, 0 ); x < std::min( pointX + mRadiusPixels, width ); ++x )
 
  156      for ( 
int y = std::max( pointY - mRadiusPixels, 0 ); y < std::min( pointY + mRadiusPixels, height ); ++y )
 
  158        const int index = y * width + x;
 
  159        if ( index >= mValues.count() )
 
  163        const double distanceSquared = std::pow( pointX - x, 2.0 ) + std::pow( pointY - y, 2.0 );
 
  164        if ( distanceSquared > mRadiusSquared )
 
  169        const double score = weight * quarticKernel( std::sqrt( distanceSquared ), mRadiusPixels );
 
  170        const double value = mValues.at( index ) + score;
 
  171        if ( value > mCalculatedMaxValue )
 
  173          mCalculatedMaxValue = value;
 
  175        mValues[ index ] = value;
 
  183  if ( mFeaturesRendered % 200  == 0 )
 
  185    renderImage( context );
 
  192double QgsHeatmapRenderer::uniformKernel( 
const double distance, 
const int bandwidth )
 const 
  195  Q_UNUSED( bandwidth )
 
  199double QgsHeatmapRenderer::quarticKernel( 
const double distance, 
const int bandwidth )
 const 
  201  return std::pow( 1. - std::pow( distance / 
static_cast< double >( bandwidth ), 2 ), 2 );
 
  204double QgsHeatmapRenderer::triweightKernel( 
const double distance, 
const int bandwidth )
 const 
  206  return std::pow( 1. - std::pow( distance / 
static_cast< double >( bandwidth ), 2 ), 3 );
 
  209double QgsHeatmapRenderer::epanechnikovKernel( 
const double distance, 
const int bandwidth )
 const 
  211  return ( 1. - std::pow( distance / 
static_cast< double >( bandwidth ), 2 ) );
 
  214double QgsHeatmapRenderer::triangularKernel( 
const double distance, 
const int bandwidth )
 const 
  216  return ( 1. - ( distance / 
static_cast< double >( bandwidth ) ) );
 
  223  renderImage( context );
 
  224  mWeightExpression.reset();
 
  234  QImage image( context.
painter()->device()->width() / mRenderQuality,
 
  235                context.
painter()->device()->height() / mRenderQuality,
 
  236                QImage::Format_ARGB32 );
 
  237  image.fill( Qt::transparent );
 
  239  const double scaleMax = mExplicitMax > 0 ? mExplicitMax : mCalculatedMaxValue;
 
  244  for ( 
int heightIndex = 0; heightIndex < image.height(); ++heightIndex )
 
  249    QRgb *scanLine = 
reinterpret_cast< QRgb * 
>( image.scanLine( heightIndex ) );
 
  250    for ( 
int widthIndex = 0; widthIndex < image.width(); ++widthIndex )
 
  253      pixVal = mValues.at( idx ) > 0 ? std::min( ( mValues.at( idx ) / scaleMax ), 1.0 ) : 0;
 
  256      pixColor = mGradientRamp->
color( pixVal );
 
  258      scanLine[widthIndex] = pixColor.rgba();
 
  263  if ( mRenderQuality > 1 )
 
  265    const QImage resized = image.scaled( context.
painter()->device()->width(),
 
  266                                         context.
painter()->device()->height() );
 
  267    context.
painter()->drawImage( 0, 0, resized );
 
  271    context.
painter()->drawImage( 0, 0, image );
 
  277  return QStringLiteral( 
"[HEATMAP]" );
 
  302  const double extension = context.
convertToMapUnits( mRadius, mRadiusUnit, mRadiusMapUnitScale );
 
  313  r->
setRadius( element.attribute( QStringLiteral( 
"radius" ), QStringLiteral( 
"50.0" ) ).toFloat() );
 
  316  r->
setMaximumValue( element.attribute( QStringLiteral( 
"max_value" ), QStringLiteral( 
"0.0" ) ).toFloat() );
 
  317  r->
setRenderQuality( element.attribute( QStringLiteral( 
"quality" ), QStringLiteral( 
"0" ) ).toInt() );
 
  320  QDomElement sourceColorRampElem = element.firstChildElement( QStringLiteral( 
"colorramp" ) );
 
  321  if ( !sourceColorRampElem.isNull() && sourceColorRampElem.attribute( QStringLiteral( 
"name" ) ) == QLatin1String( 
"[source]" ) )
 
  332  rendererElem.setAttribute( QStringLiteral( 
"type" ), QStringLiteral( 
"heatmapRenderer" ) );
 
  333  rendererElem.setAttribute( QStringLiteral( 
"radius" ), QString::number( mRadius ) );
 
  334  rendererElem.setAttribute( QStringLiteral( 
"radius_unit" ), QString::number( mRadiusUnit ) );
 
  336  rendererElem.setAttribute( QStringLiteral( 
"max_value" ), QString::number( mExplicitMax ) );
 
  337  rendererElem.setAttribute( QStringLiteral( 
"quality" ), QString::number( mRenderQuality ) );
 
  338  rendererElem.setAttribute( QStringLiteral( 
"weight_expression" ), mWeightExpressionString );
 
  343    rendererElem.appendChild( colorRampElem );
 
  364  QSet<QString> attributes;
 
  370  attributes << mWeightExpressionString;
 
  381  if ( renderer->
type() == QLatin1String( 
"heatmapRenderer" ) )
 
  387    std::unique_ptr< QgsHeatmapRenderer > res = std::make_unique< QgsHeatmapRenderer >();
 
  389    return res.release();
 
  406  delete mGradientRamp;
 
  407  mGradientRamp = ramp;
 
Abstract base class for color ramps.
 
virtual QColor color(double value) const =0
Returns the color corresponding to a specified value.
 
virtual QgsColorRamp * clone() const =0
Creates a clone of the color ramp.
 
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.
 
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
 
virtual void stopRender(QgsRenderContext &context)
Must be called when a render cycle has finished, to allow the renderer to clean up.
 
void copyRendererData(QgsFeatureRenderer *destRenderer) const
Clones generic renderer data to another renderer.
 
void saveRendererData(QDomDocument &doc, QDomElement &element, const QgsReadWriteContext &context)
Saves generic renderer data into the specified element.
 
virtual void startRender(QgsRenderContext &context, const QgsFields &fields)
Must be called when a new render cycle is started.
 
virtual QgsFeatureRenderer * clone() const =0
Create a deep copy of this renderer.
 
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
 
bool hasGeometry() const
Returns true if the feature has an associated geometry.
 
Container of fields for a vector layer.
 
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
 
A geometry is the spatial representation of a feature.
 
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
 
QgsMultiPointXY asMultiPoint() const
Returns the contents of the geometry as a multi-point.
 
bool isMultipart() const SIP_HOLDGIL
Returns true if WKB of the geometry is of WKBMulti* type.
 
QgsPointXY asPoint() const
Returns the contents of the geometry as a 2-dimensional point.
 
QgsWkbTypes::GeometryType type
 
Gradient color ramp, which smoothly interpolates between two colors and also supports optional extra ...
 
A renderer which draws points as a live heatmap.
 
void setColorRamp(QgsColorRamp *ramp)
Sets the color ramp to use for shading the heatmap.
 
QgsSymbol * symbolForFeature(const QgsFeature &feature, QgsRenderContext &context) const override
 
void modifyRequestExtent(QgsRectangle &extent, QgsRenderContext &context) override
Allows for a renderer to modify the extent of a feature request prior to rendering.
 
void startRender(QgsRenderContext &context, const QgsFields &fields) override
Must be called when a new render cycle is started.
 
QSet< QString > usedAttributes(const QgsRenderContext &context) const override
Returns a list of attributes required by this renderer.
 
void setRadius(const double radius)
Sets the radius for the heatmap.
 
static QgsFeatureRenderer * create(QDomElement &element, const QgsReadWriteContext &context)
Creates a new heatmap renderer instance from XML.
 
void setRenderQuality(const int quality)
Sets the render quality used for drawing the heatmap.
 
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.
 
~QgsHeatmapRenderer() override
 
static QgsHeatmapRenderer * convertFromRenderer(const QgsFeatureRenderer *renderer)
 
void setWeightExpression(const QString &expression)
Sets the expression used for weighting points when generating the heatmap.
 
void setMaximumValue(const double value)
Sets the maximum value used for shading the heatmap.
 
void stopRender(QgsRenderContext &context) override
Must be called when a render cycle has finished, to allow the renderer to clean up.
 
QString dump() const override
Returns debug information about this renderer.
 
QDomElement save(QDomDocument &doc, const QgsReadWriteContext &context) override
Stores renderer properties to an XML element.
 
void setRadiusUnit(const QgsUnitTypes::RenderUnit unit)
Sets the units used for the heatmap's radius.
 
QgsHeatmapRenderer * clone() const override
Create a deep copy of this renderer.
 
bool accept(QgsStyleEntityVisitorInterface *visitor) const override
Accepts the specified symbology visitor, causing it to visit all symbols associated with the renderer...
 
void setRadiusMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale used for the heatmap's radius.
 
QgsSymbolList symbols(QgsRenderContext &context) const override
 
QgsPointXY transform(const QgsPointXY &p) const
Transforms a point p from map (world) coordinates to device coordinates.
 
A class to represent a 2D point.
 
The class is used as a container of context for various read/write operations on other objects.
 
A rectangle specified with double values.
 
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
 
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
 
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
 
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
 
void setYMinimum(double y) SIP_HOLDGIL
Set the minimum y value.
 
void setXMaximum(double x) SIP_HOLDGIL
Set the maximum x value.
 
void setXMinimum(double x) SIP_HOLDGIL
Set the minimum x value.
 
void setYMaximum(double y) SIP_HOLDGIL
Set the maximum y value.
 
Contains information about the context of a rendering operation.
 
QPainter * painter()
Returns the destination QPainter for the render operation.
 
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::RenderSubcomponentProperty property=Qgis::RenderSubcomponentProperty::Generic) const
Converts a size from the specified units to painter units (pixels).
 
QgsExpressionContext & expressionContext()
Gets the expression context.
 
const QgsMapToPixel & mapToPixel() const
Returns the context's map to pixel transform, which transforms between map coordinates and device coo...
 
double convertToMapUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to map units.
 
bool renderingStopped() const
Returns true if the rendering operation has been stopped and any ongoing rendering should be canceled...
 
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.
 
A color ramp entity for QgsStyle databases.
 
An interface for classes which can visit style entity (e.g.
 
virtual bool visit(const QgsStyleEntityVisitorInterface::StyleLeaf &entity)
Called when the visitor will visit a style entity.
 
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
 
static QgsColorRamp * loadColorRamp(QDomElement &element)
Creates a color ramp from the settings encoded in an XML element.
 
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
 
static QDomElement saveColorRamp(const QString &name, QgsColorRamp *ramp, QDomDocument &doc)
Encodes a color ramp's settings to an XML element.
 
Abstract base class for all rendered symbols.
 
RenderUnit
Rendering size units.
 
QVector< QgsPointXY > QgsMultiPointXY
A collection of QgsPoints that share a common collection of attributes.
 
#define RENDERER_TAG_NAME
 
QList< QgsSymbol * > QgsSymbolList
 
Contains information relating to the style entity currently being visited.