Skip to content
Permalink
Browse files
[FEATURE] Add option to select kernel shape (quartic, triangular or u…
…niform) in heatmap plugin
  • Loading branch information
nyalldawson committed Mar 12, 2013
1 parent 7bd89ce commit a05747c40d0f992b7f6c7e0f3f7fd9546f812843
Showing with 96 additions and 10 deletions.
  1. +40 −2 src/plugins/heatmap/heatmap.cpp
  2. +7 −0 src/plugins/heatmap/heatmap.h
  3. +5 −0 src/plugins/heatmap/heatmapgui.cpp
  4. +10 −0 src/plugins/heatmap/heatmapgui.h
  5. +34 −8 src/plugins/heatmap/heatmapguibase.ui
@@ -43,6 +43,9 @@

#define NO_DATA -9999

#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif

static const QString sName = QObject::tr( "Heatmap" );
static const QString sDescription = QObject::tr( "Creates a Heatmap raster for the input point vector" );
@@ -109,7 +112,8 @@ void Heatmap::run()
int rows = d.rows();
float cellsize = d.cellSizeX(); // or d.cellSizeY(); both have the same value
float myDecay = d.decayRatio();

int kernelShape = d.kernelShape();

// Start working on the input vector
QgsVectorLayer* inputLayer = d.inputVectorLayer();

@@ -259,7 +263,7 @@ void Heatmap::run()
continue;
}

float pixelValue = weight * ( 1 - (( 1 - myDecay ) * distance / myBuffer ) );
float pixelValue = weight * calculateKernelValue( distance, myBuffer, kernelShape );

// clearing anamolies along the axes
if ( xp == 0 && yp == 0 )
@@ -330,6 +334,40 @@ int Heatmap::bufferSize( float radius, float cellsize )
return buffer;
}

float Heatmap::calculateKernelValue( float distance, int bandwidth, int kernelShape )
{
switch (kernelShape) {
case HeatmapGui::Triangular:
return ( 1 - ( distance / bandwidth ) );

case HeatmapGui::Uniform:
return uniformKernel( distance, bandwidth );

case HeatmapGui::Quartic:
return quarticKernel( distance, bandwidth );
}
return 0;

}

float Heatmap::uniformKernel( float distance, int bandwidth )
{
// Normalizing constant. Calculated by polar double integrating the kernel function
// with radius of 0 to bandwidth and equating area to 1.
float k = 2. / (M_PI * (float)bandwidth);

// Derived from Wand and Jones (1995), p. 175
return k * ( 0.5 / (float)bandwidth);
}

float Heatmap::quarticKernel( float distance, int bandwidth )
{
// Normalizing constant
float k = 16. / (5. * M_PI * pow((float)bandwidth, 2));

// Derived from Wand and Jones (1995), p. 175
return k * (15. / 16. ) * pow( 1. - pow( distance / (float)bandwidth, 2), 2);
}

// Unload the plugin by cleaning up the GUI
void Heatmap::unload()
@@ -85,6 +85,13 @@ class Heatmap: public QObject, public QgisPlugin
float mapUnitsOf( float meters, QgsCoordinateReferenceSystem crs );
//! Worker to calculate buffer size in pixels
int bufferSize( float radius, float cellsize );
//! Calculate the value given to a point width a given distance for a specified kernel shape
float calculateKernelValue( float distance, int bandwidth, int kernelShape );
//! Uniform kernel function
float uniformKernel( float distance, int bandwidth );
//! Quartic kernel function
float quarticKernel( float distance, int bandwidth );


// MANDATORY PLUGIN PROPERTY DECLARATIONS .....

@@ -375,6 +375,11 @@ int HeatmapGui::radiusUnit()
return mRadiusUnitCombo->currentIndex();
}

int HeatmapGui::kernelShape()
{
return kernelShapeCombo->currentIndex();
}

float HeatmapGui::decayRatio()
{
return mDecayLineEdit->text().toFloat();
@@ -35,6 +35,13 @@ class HeatmapGui : public QDialog, private Ui::HeatmapGuiBase
Meters,
MapUnits
};

enum kernelShape
{
Triangular,
Uniform,
Quartic
};

/** Returns whether to apply weighted heat */
bool weighted();
@@ -47,6 +54,9 @@ class HeatmapGui : public QDialog, private Ui::HeatmapGuiBase

/** Return the radius Unit (meters/map units) */
int radiusUnit();

/** Return the selected kernel shape */
int kernelShape();

/** Return the decay ratio */
float decayRatio();
@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>460</width>
<height>382</height>
<height>415</height>
</rect>
</property>
<property name="sizePolicy">
@@ -180,21 +180,21 @@
</item>
<item row="1" column="0">
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<item row="1" column="0">
<widget class="QCheckBox" name="useRadius">
<property name="text">
<string>Use Radius from field</string>
</property>
</widget>
</item>
<item row="0" column="1">
<item row="1" column="1">
<widget class="QComboBox" name="radiusFieldCombo">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
<item row="0" column="2">
<item row="1" column="2">
<widget class="QComboBox" name="radiusFieldUnitCombo">
<property name="enabled">
<bool>false</bool>
@@ -211,34 +211,60 @@
</item>
</widget>
</item>
<item row="1" column="0">
<item row="2" column="0">
<widget class="QCheckBox" name="useWeight">
<property name="text">
<string>Use Weight from field</string>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<item row="2" column="1" colspan="2">
<widget class="QComboBox" name="weightFieldCombo">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
<item row="2" column="1" colspan="2">
<item row="3" column="1" colspan="2">
<widget class="QLineEdit" name="mDecayLineEdit">
<property name="text">
<string>0.0</string>
</property>
</widget>
</item>
<item row="2" column="0">
<item row="3" column="0">
<widget class="QLabel" name="mDecayLabel">
<property name="text">
<string>Decay Ratio</string>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<widget class="QComboBox" name="kernelShapeCombo">
<item>
<property name="text">
<string>Triangular</string>
</property>
</item>
<item>
<property name="text">
<string>Uniform</string>
</property>
</item>
<item>
<property name="text">
<string>Quartic</string>
</property>
</item>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="kernelShapeLable">
<property name="text">
<string>Kernel Shape</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>

0 comments on commit a05747c

Please sign in to comment.