339 changes: 339 additions & 0 deletions src/plugins/heatmap/heatmap.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,339 @@
/***************************************************************************
heatmap.cpp
Creates a Heatmap raster for the input point vector
-------------------
begin : January 2012
copyright : [(C) Arunmozhi]
email : [aruntheguy at gmail dot com]
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

// GDAL includes
#include "gdal_priv.h"
#include "cpl_string.h"
#include "cpl_conv.h"

// QGIS Specific includes
#include <qgisinterface.h>
#include <qgisgui.h>

#include "heatmap.h"
#include "heatmapgui.h"

#include "qgsgeometry.h"
#include "qgsvectorlayer.h"
#include "qgsvectordataprovider.h"

// Qt4 Related Includes
#include <QAction>
#include <QToolBar>
#include <QMessageBox>
#include <QFileInfo>
#include <QProgressDialog>

#define NO_DATA -9999


static const QString sName = QObject::tr( "Heatmap" );
static const QString sDescription = QObject::tr( "Creates a Heatmap raster for the input point vector" );
static const QString sCategory = QObject::tr( "Raster" );
static const QString sPluginVersion = QObject::tr( "Version 0.1" );
static const QgisPlugin::PLUGINTYPE sPluginType = QgisPlugin::UI;
static const QString sPluginIcon = ":/heatmap/heatmap.png";

/**
* Constructor for the plugin. The plugin is passed a pointer
* an interface object that provides access to exposed functions in QGIS.
* @param theQGisInterface - Pointer to the QGIS interface object
*/
Heatmap::Heatmap( QgisInterface * theQgisInterface ):
QgisPlugin( sName, sDescription, sCategory, sPluginVersion, sPluginType ),
mQGisIface( theQgisInterface )
{
}

Heatmap::~Heatmap()
{

}

/*
* Initialize the GUI interface for the plugin - this is only called once when the plugin is
* added to the plugin registry in the QGIS application.
*/
void Heatmap::initGui()
{

// Create the action for tool
mQActionPointer = new QAction( QIcon( ":/heatmap/heatmap.png" ), tr( "Heatmap" ), this );
// Set the what's this text
mQActionPointer->setWhatsThis( tr( "Creats a heatmap raster for the input point vector." ) );
// Connect the action to the run
connect( mQActionPointer, SIGNAL( triggered() ), this, SLOT( run() ) );
// Add the icon to the toolbar
mQGisIface->addToolBarIcon( mQActionPointer );
mQGisIface->addPluginToRasterMenu( tr( "&Heatmap" ), mQActionPointer );

}
//method defined in interface
void Heatmap::help()
{
//implement me!
}

// Slot called when the menu item is triggered
// If you created more menu items / toolbar buttons in initiGui, you should
// create a separate handler for each action - this single run() method will
// not be enough
void Heatmap::run()
{
HeatmapGui *myPluginGui = new HeatmapGui( mQGisIface->mainWindow(), QgisGui::ModalDialogFlags );
myPluginGui->setAttribute( Qt::WA_DeleteOnClose );

// Connect the createRaster signal to createRaster Slot
connect( myPluginGui, SIGNAL( createRaster( QgsVectorLayer*, int, float, QString, QString ) ),
this, SLOT( createRaster( QgsVectorLayer*, int, float, QString, QString ) ) );

myPluginGui->show();
}

// Unload the plugin by cleaning up the GUI
void Heatmap::unload()
{
// remove the GUI
mQGisIface->removePluginMenu( "&Heatmap", mQActionPointer );
mQGisIface->removeToolBarIcon( mQActionPointer );
delete mQActionPointer;
}

// The worker
void Heatmap::createRaster( QgsVectorLayer* theVectorLayer, int theBuffer, float theDecay, QString theOutputFilename, QString theOutputFormat )
{
// generic variables
int xSize, ySize;
double xResolution, yResolution;
double rasterX, rasterY;

// Getting the rasterdataset in place
GDALAllRegister();

GDALDataset *emptyDataset;
GDALDriver *myDriver;

myDriver = GetGDALDriverManager()->GetDriverByName( theOutputFormat.toUtf8() );
if( myDriver == NULL )
{
QMessageBox::information( 0, tr("Error in GDAL Driver!"), tr("Cannot open the driver for the format specified") );
return;
}

// bounding box info
QgsRectangle myBBox = theVectorLayer->extent();
// fixing a base width of 500 px/cells
xSize = 500;
xResolution = myBBox.width()/xSize;
yResolution = xResolution;
ySize = myBBox.height()/yResolution;
// add extra extend to cover the corner points' heat region
xSize = xSize + ( theBuffer * 2 ) + 10 ;
ySize = ySize + ( theBuffer * 2 ) + 10 ;
// Define the new lat,lon for the buffered raster area
rasterX = myBBox.xMinimum() - ( theBuffer + 5 ) * xResolution;
rasterY = myBBox.yMinimum() - ( theBuffer + 5 ) * yResolution;

double geoTransform[6] = { rasterX, xResolution, 0, rasterY, 0, yResolution };

emptyDataset = myDriver->Create( theOutputFilename.toUtf8(), xSize, ySize, 1, GDT_Float32, NULL );

emptyDataset->SetGeoTransform( geoTransform );

GDALRasterBand *poBand;
poBand = emptyDataset->GetRasterBand(1);
poBand->SetNoDataValue( NO_DATA );

float* line = ( float * ) CPLMalloc( sizeof( float ) * xSize );
std::fill_n( line, xSize, NO_DATA );
// Write the empty raster
for ( int i = 0; i < ySize ; i += 1 )
{
poBand->RasterIO( GF_Write, 0, 0, xSize, 1, line, xSize, 1, GDT_Float32, 0, 0 );
}

CPLFree( line );
//close the dataset
GDALClose( (GDALDatasetH) emptyDataset );

// open the raster in GA_Update mode
GDALDataset *heatmapDS;
heatmapDS = ( GDALDataset * ) GDALOpen( theOutputFilename.toUtf8(), GA_Update );
if( !heatmapDS )
{
QMessageBox::information( 0, tr("Error in Updating Raster!"), tr("Couldnot open the created raster for updation. The Heatmap was not generated.") );
return;
}
poBand = heatmapDS->GetRasterBand( 1 );
// Get the data buffer ready
int blockSize = 2 * theBuffer + 1; // block SIDE would have been more appropriate
// Open the vector features
QgsVectorDataProvider* myVectorProvider = theVectorLayer->dataProvider();
if( !myVectorProvider )
{
QMessageBox::information( 0, tr( "Error in Point Layer!"), tr("Couldnot identify the vector data provider.") );
return;
}
QgsAttributeList dummyList;
myVectorProvider->select( dummyList );

int totalFeatures = myVectorProvider->featureCount();
int counter = 0;

QProgressDialog p( "Creating Heatmap ... ", "Abort", 0, totalFeatures );
p.setWindowModality(Qt::WindowModal);

QgsFeature myFeature;

while( myVectorProvider->nextFeature( myFeature ) )
{
counter += 1;
p.setValue( counter );
if( p.wasCanceled() )
{
QMessageBox::information( 0, tr("Heatmap Generation Aborted!"), tr("QGIS will now load the partially-computed raster.") );
break;
}

QgsGeometry* myPointGeometry;
myPointGeometry = myFeature.geometry();
// convert the geometry to point
QgsPoint myPoint;
myPoint = myPointGeometry->asPoint();
// avoiding any empty points or out of extent points
if( ( myPoint.x() < rasterX ) || ( myPoint.y() < rasterY ) )
{
continue;
}
// calculate the pixel position
unsigned int xPosition, yPosition;
xPosition = (( myPoint.x() - rasterX )/ xResolution ) - theBuffer;
yPosition = (( myPoint.y() - rasterY )/ yResolution ) - theBuffer;

// get the data
float *dataBuffer = ( float * ) CPLMalloc( sizeof( float ) * blockSize * blockSize );
poBand->RasterIO( GF_Read, xPosition, yPosition, blockSize, blockSize, dataBuffer, blockSize, blockSize, GDT_Float32, 0, 0 );

for( int xp = 0; xp <= theBuffer; xp += 1 )
{
for( int yp = 0; yp <= theBuffer; yp += 1 )
{
float distance = sqrt( pow( xp, 2 ) + pow( yp, 2 ) );
float pixelValue = 1 - ( (1-theDecay) * distance / theBuffer );

// clearing anamolies along the axes
if( xp == 0 && yp == 0 )
{
pixelValue /= 4;
}
else if( xp == 0 || yp == 0 )
{
pixelValue /= 2;
}

if( distance <= theBuffer )
{
int pos[4];
pos[0] = ( theBuffer + xp ) * blockSize + ( theBuffer + yp );
pos[1] = ( theBuffer + xp ) * blockSize + ( theBuffer - yp );
pos[2] = ( theBuffer - xp ) * blockSize + ( theBuffer + yp );
pos[3] = ( theBuffer - xp ) * blockSize + ( theBuffer - yp );
for( int p = 0; p < 4; p += 1 )
{
if( dataBuffer[ pos[p] ] == NO_DATA )
{
dataBuffer[ pos[p] ] = 0;
}
dataBuffer[ pos[p] ] += pixelValue;
}
}
}
}

poBand->RasterIO( GF_Write, xPosition, yPosition, blockSize, blockSize, dataBuffer, blockSize, blockSize, GDT_Float32, 0, 0 );
CPLFree( dataBuffer );
}

//Finally close the dataset
GDALClose( (GDALDatasetH) heatmapDS );

// Open the file in QGIS window
mQGisIface->addRasterLayer( theOutputFilename, QFileInfo( theOutputFilename ).baseName() );
}

//////////////////////////////////////////////////////////////////////////
//
//
// THE FOLLOWING CODE IS AUTOGENERATED BY THE PLUGIN BUILDER SCRIPT
// YOU WOULD NORMALLY NOT NEED TO MODIFY THIS, AND YOUR PLUGIN
// MAY NOT WORK PROPERLY IF YOU MODIFY THIS INCORRECTLY
//
//
//////////////////////////////////////////////////////////////////////////


/**
* Required extern functions needed for every plugin
* These functions can be called prior to creating an instance
* of the plugin class
*/
// Class factory to return a new instance of the plugin class
QGISEXTERN QgisPlugin * classFactory( QgisInterface * theQgisInterfacePointer )
{
return new Heatmap( theQgisInterfacePointer );
}
// Return the name of the plugin - note that we do not user class members as
// the class may not yet be insantiated when this method is called.
QGISEXTERN QString name()
{
return sName;
}

// Return the description
QGISEXTERN QString description()
{
return sDescription;
}

// Return the category
QGISEXTERN QString category()
{
return sCategory;
}

// Return the type (either UI or MapLayer plugin)
QGISEXTERN int type()
{
return sPluginType;
}

// Return the version number for the plugin
QGISEXTERN QString version()
{
return sPluginVersion;
}

QGISEXTERN QString icon()
{
return sPluginIcon;
}

// Delete ourself
QGISEXTERN void unload( QgisPlugin * thePluginPointer )
{
delete thePluginPointer;
}
105 changes: 105 additions & 0 deletions src/plugins/heatmap/heatmap.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/***************************************************************************
heatmap.h
-------------------
begin : Jan 21, 2004
copyright : (C) 2004 by Tim Sutton
email : tim@linfiniti.com
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
/***************************************************************************
* QGIS Programming conventions:
*
* mVariableName - a class level member variable
* sVariableName - a static class level member variable
* variableName() - accessor for a class member (no 'get' in front of name)
* setVariableName() - mutator for a class member (prefix with 'set')
*
* Additional useful conventions:
*
* theVariableName - a method parameter (prefix with 'the')
* myVariableName - a locally declared variable within a method ('my' prefix)
*
* DO: Use mixed case variable names - myVariableName
* DON'T: separate variable names using underscores: my_variable_name (NO!)
*
* **************************************************************************/
#ifndef Heatmap_H
#define Heatmap_H

//QT4 includes
#include <QObject>

//QGIS includes
#include "../qgisplugin.h"
#include "qgsvectorlayer.h"

//forward declarations
class QAction;
class QToolBar;

class QgisInterface;

/**
* \class Plugin
* \brief heatmap plugin for QGIS
* \description generates a heatmap raster for the input point vector
*/
class Heatmap: public QObject, public QgisPlugin
{
Q_OBJECT
public:

// MANDATORY PLUGIN METHODS FOLLOW

/**
* Constructor for a plugin. The QgisInterface pointer is passed by
* QGIS when it attempts to instantiate the plugin.
* @param theInterface Pointer to the QgisInterface object.
*/
Heatmap( QgisInterface * theInterface );
//! Destructor
virtual ~Heatmap();

public slots:
//! init the gui
virtual void initGui();
//! Show the dialog box
void run();
//! unload the plugin
void unload();
//! show the help document
void help();
//! the worker slot to create heatmap
/*
* Signal: createRaster
* Params:
* QgsVectorLayer* -> Input point layer
* int -> Buffer distance
* float -> Decay ratio
* QString -> Output filename
* QString -> Output Format Short Name
*/
void createRaster( QgsVectorLayer*, int, float, QString, QString );

private:

// MANDATORY PLUGIN PROPERTY DECLARATIONS .....

int mPluginType;
//! Pointer to the QGIS interface object
QgisInterface *mQGisIface;
//!pointer to the qaction for this plugin
QAction * mQActionPointer;

};

#endif //Heatmap_H
Binary file added src/plugins/heatmap/heatmap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions src/plugins/heatmap/heatmap.qrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/heatmap/" >
<file>heatmap.png</file>
</qresource>
</RCC>
143 changes: 143 additions & 0 deletions src/plugins/heatmap/heatmap.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
207 changes: 207 additions & 0 deletions src/plugins/heatmap/heatmapgui.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
/***************************************************************************
* Copyright (C) 2003 by Tim Sutton *
* tim@linfiniti.com *
* *
* This is a plugin generated from the QGIS plugin template *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
***************************************************************************/
// qgis includes
#include "qgis.h"
#include "heatmapgui.h"
#include "qgscontexthelp.h"
#include "qgsmaplayer.h"
#include "qgsmaplayerregistry.h"
#include "qgsvectorlayer.h"

// GDAL includes
#include "gdal_priv.h"
#include "cpl_string.h"
#include "cpl_conv.h"

//qt includes
#include <QComboBox>
#include <QFileDialog>
#include <QSettings>
#include <QMessageBox>

//standard includes

HeatmapGui::HeatmapGui( QWidget* parent, Qt::WFlags fl )
: QDialog( parent, fl )
{
setupUi( this );

// Adding point layers to the mInputVectorCombo
QMap<QString, QgsMapLayer*> mapLayers = QgsMapLayerRegistry::instance()->mapLayers();
QMapIterator<QString, QgsMapLayer*> layers(mapLayers);

while( layers.hasNext() )
{
layers.next();
QgsVectorLayer* vl = qobject_cast<QgsVectorLayer *>(layers.value());
if( ( vl ) && ( vl->geometryType() == QGis::Point ) )
{
mInputVectorCombo->addItem( vl->name(), QVariant( vl->id() ) );
}
}

// Adding GDAL drivers with CREATE to the mFormatCombo
int myTiffIndex = -1;
int myIndex = -1;
GDALAllRegister();
int nDrivers = GDALGetDriverCount();
for( int i = 0; i < nDrivers; i +=1 )
{
GDALDriver* nthDriver = GetGDALDriverManager()->GetDriver( i );
char** driverMetadata = nthDriver->GetMetadata();
if( CSLFetchBoolean( driverMetadata, GDAL_DCAP_CREATE, false ) )
{
++myIndex;
QString myLongName = nthDriver->GetMetadataItem( GDAL_DMD_LONGNAME );
// Add LongName text, shortname variant; GetDescription actually gets the shortname
mFormatCombo->addItem( myLongName, QVariant( nthDriver->GetDescription() ) );
// Add the drivers and their extensions to a map for filename correction
mExtensionMap.insert( nthDriver->GetDescription(), nthDriver->GetMetadataItem( GDAL_DMD_EXTENSION ) );
if ( myLongName == "GeoTIFF" )
{
myTiffIndex = myIndex;
}
}
}
mFormatCombo->setCurrentIndex(myTiffIndex);

//finally set right the ok button
enableOrDisableOkButton();
}

HeatmapGui::~HeatmapGui()
{
}

void HeatmapGui::on_mButtonBox_accepted()
{
// Variables to be emitted with the createRaster signal
QgsVectorLayer* inputLayer;
int bufferDistance;
float decayRatio;
QString outputFileName;
QString outputFormat;

QString dummyText;

// The input vector layer
int myLayerId = mInputVectorCombo->itemData( mInputVectorCombo->currentIndex() ).toInt();

QMap<QString, QgsMapLayer*> mapLayers = QgsMapLayerRegistry::instance()->mapLayers();
QMapIterator<QString, QgsMapLayer*> layers(mapLayers);

while( layers.hasNext() )
{
layers.next();
QgsVectorLayer* vl = qobject_cast<QgsVectorLayer *>(layers.value());
if ( vl )
{
dummyText = vl->id();
if( dummyText.toInt() == myLayerId )
{
inputLayer = vl;
}
}
}

// The buffer distance
dummyText = mBufferLineEdit->text();
bufferDistance = dummyText.toInt();
if( bufferDistance == NULL )
{
QMessageBox::information( 0, tr("Invalid Buffer Value!"), tr("Buffer distance cannot be NULL, kindly enter a valid value.") );
return;
}
// The decay ratio
dummyText = mDecayLineEdit->text();
decayRatio = dummyText.toFloat();

// The output filename
outputFileName = mOutputRasterLineEdit->text();
QFileInfo myFileInfo( outputFileName );
if( outputFileName.isEmpty() || !myFileInfo.dir().exists() )
{
QMessageBox::information( 0, tr("Output filename is invalid!"), tr("Kindly enter a valid output file path and name.") );
return;
}

// The output format
outputFormat = mFormatCombo->itemData( mFormatCombo->currentIndex() ).toString();

// append the file format if the suffix is empty
QString suffix = myFileInfo.suffix();
if( suffix.isEmpty() )
{
QMap<QString, QString>::const_iterator it = mExtensionMap.find( outputFormat );
if( it != mExtensionMap.end() && it.key() == outputFormat )
{
// making sure that there is really a extension value available
// Some drivers donot seem to have any extension at all
if( it.value() != NULL || it.value() != "" )
{
outputFileName.append(".");
outputFileName.append( it.value() );
}
}
}

emit createRaster( inputLayer, bufferDistance, decayRatio, outputFileName, outputFormat );
//and finally
accept();
}

void HeatmapGui::on_mButtonBox_rejected()
{
reject();
}

void HeatmapGui::on_mButtonBox_helpRequested()
{
QgsContextHelp::run( metaObject()->className() );
}

void HeatmapGui::on_mBrowseButton_clicked()
{
QSettings s;
QString lastDir = s.value( "/Heatmap/lastOutputDir", "" ).toString();

QString outputFilename = QFileDialog::getSaveFileName( 0, tr( "Save Heatmap as: "), lastDir );
if( !outputFilename.isEmpty() )
{
mOutputRasterLineEdit->setText( outputFilename );
QFileInfo outputFileInfo( outputFilename );
QDir outputDir = outputFileInfo.absoluteDir();
if( outputDir.exists() )
{
s.setValue( "/Heatmap/lastOutputDir", outputFileInfo.absolutePath() );
}
}

enableOrDisableOkButton();
}

void HeatmapGui::on_mOutputRasterLineEdit_editingFinished()
{
enableOrDisableOkButton();
}

void HeatmapGui::enableOrDisableOkButton()
{
bool enabled = true;
QString filename = mOutputRasterLineEdit->text();
QFileInfo theFileInfo( filename );
if( filename.isEmpty() || !theFileInfo.dir().exists() || ( mInputVectorCombo->count() == 0 ) )
{
enabled = false;
}
mButtonBox->button( QDialogButtonBox::Ok )->setEnabled( enabled );
}
54 changes: 54 additions & 0 deletions src/plugins/heatmap/heatmapgui.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/***************************************************************************
* Copyright (C) 2003 by Tim Sutton *
* tim@linfiniti.com *
* *
* This is a plugin generated from the QGIS plugin template *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
***************************************************************************/
#ifndef HeatmapGUI_H
#define HeatmapGUI_H

#include <QDialog>
#include <ui_heatmapguibase.h>

#include "qgsvectorlayer.h"
/**
@author Tim Sutton
*/
class HeatmapGui : public QDialog, private Ui::HeatmapGuiBase
{
Q_OBJECT
public:
HeatmapGui( QWidget* parent = 0, Qt::WFlags fl = 0 );
~HeatmapGui();

private:
QMap<QString, QString> mExtensionMap;
void enableOrDisableOkButton();

private slots:
void on_mButtonBox_accepted();
void on_mButtonBox_rejected();
void on_mButtonBox_helpRequested();
void on_mBrowseButton_clicked(); // Function to open the file dialog
void on_mOutputRasterLineEdit_editingFinished();

signals:
/*
* Signal: createRaster
* Params:
* QgsVectorLayer* -> Input point layer
* int -> Buffer distance
* float -> Decay ratio
* QString -> Output filename
* QString -> Output Format Short Name
*/
void createRaster( QgsVectorLayer*, int, float, QString, QString );

};

#endif
221 changes: 221 additions & 0 deletions src/plugins/heatmap/heatmapguibase.ui
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>HeatmapGuiBase</class>
<widget class="QDialog" name="HeatmapGuiBase">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>260</height>
</rect>
</property>
<property name="windowTitle">
<string>Heatmap Plugin</string>
</property>
<property name="locale">
<locale language="English" country="UnitedStates"/>
</property>
<widget class="QLabel" name="mInputLabel">
<property name="geometry">
<rect>
<x>10</x>
<y>20</y>
<width>110</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Input Point Vector</string>
</property>
</widget>
<widget class="QComboBox" name="mInputVectorCombo">
<property name="geometry">
<rect>
<x>125</x>
<y>20</y>
<width>260</width>
<height>25</height>
</rect>
</property>
</widget>
<widget class="QLabel" name="mOutputLabel">
<property name="geometry">
<rect>
<x>10</x>
<y>65</y>
<width>110</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string>Output Raster</string>
</property>
</widget>
<widget class="QLineEdit" name="mOutputRasterLineEdit">
<property name="geometry">
<rect>
<x>125</x>
<y>60</y>
<width>230</width>
<height>25</height>
</rect>
</property>
</widget>
<widget class="QPushButton" name="mBrowseButton">
<property name="geometry">
<rect>
<x>355</x>
<y>60</y>
<width>30</width>
<height>25</height>
</rect>
</property>
<property name="focusPolicy">
<enum>Qt::ClickFocus</enum>
</property>
<property name="text">
<string>...</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
<widget class="QDialogButtonBox" name="mButtonBox">
<property name="geometry">
<rect>
<x>10</x>
<y>225</y>
<width>375</width>
<height>30</height>
</rect>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::Ok</set>
</property>
</widget>
<widget class="QGroupBox" name="mPointAttributeBox">
<property name="geometry">
<rect>
<x>10</x>
<y>140</y>
<width>370</width>
<height>80</height>
</rect>
</property>
<property name="title">
<string>Heatmap Point Attributes</string>
</property>
<widget class="QLabel" name="mBufferLabel">
<property name="geometry">
<rect>
<x>10</x>
<y>27</y>
<width>101</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string>Buffer Radius</string>
</property>
</widget>
<widget class="QLabel" name="mDecayLabel">
<property name="geometry">
<rect>
<x>10</x>
<y>56</y>
<width>101</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string>Decay Ratio</string>
</property>
</widget>
<widget class="QLineEdit" name="mBufferLineEdit">
<property name="geometry">
<rect>
<x>110</x>
<y>20</y>
<width>113</width>
<height>25</height>
</rect>
</property>
<property name="text">
<string>10</string>
</property>
</widget>
<widget class="QLineEdit" name="mDecayLineEdit">
<property name="geometry">
<rect>
<x>110</x>
<y>50</y>
<width>113</width>
<height>25</height>
</rect>
</property>
<property name="text">
<string>0.5</string>
</property>
</widget>
</widget>
<widget class="QLabel" name="mFormatLabel">
<property name="geometry">
<rect>
<x>10</x>
<y>105</y>
<width>110</width>
<height>15</height>
</rect>
</property>
<property name="text">
<string>Output Format</string>
</property>
</widget>
<widget class="QComboBox" name="mFormatCombo">
<property name="geometry">
<rect>
<x>125</x>
<y>100</y>
<width>260</width>
<height>25</height>
</rect>
</property>
</widget>
</widget>
<resources/>
<connections>
<connection>
<sender>mButtonBox</sender>
<signal>accepted()</signal>
<receiver>HeatmapGuiBase</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>195</x>
<y>123</y>
</hint>
<hint type="destinationlabel">
<x>199</x>
<y>79</y>
</hint>
</hints>
</connection>
<connection>
<sender>mButtonBox</sender>
<signal>rejected()</signal>
<receiver>HeatmapGuiBase</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>195</x>
<y>123</y>
</hint>
<hint type="destinationlabel">
<x>199</x>
<y>79</y>
</hint>
</hints>
</connection>
</connections>
</ui>