Skip to content

Commit fc8b0c4

Browse files
Arunmozhijef-n
Arunmozhi
authored andcommittedMar 24, 2012
merge pull request #104:
- redesigned the dialog, added a options for - weighted buffer - raster size - moved the advanced stuff under advancedGroupBox - finished the GUI code - finally heatmap hits v0.2 Users can now - specify the rows and columns for the raster - specify the cell size of the raster - Choose a field as weight for each point - Choose a field to act as the buffer radius for each point - Buffer radius can be specified in real-world units like meters & mapunits - indentation updated
1 parent aa2d0b8 commit fc8b0c4

File tree

5 files changed

+893
-287
lines changed

5 files changed

+893
-287
lines changed
 

‎src/plugins/heatmap/heatmap.cpp

Lines changed: 193 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@
3030
#include "qgsgeometry.h"
3131
#include "qgsvectorlayer.h"
3232
#include "qgsvectordataprovider.h"
33+
#include "qgsdistancearea.h"
34+
#include "qgscoordinatereferencesystem.h"
35+
#include "qgslogger.h"
3336

3437
// Qt4 Related Includes
3538
#include <QAction>
@@ -44,7 +47,7 @@
4447
static const QString sName = QObject::tr( "Heatmap" );
4548
static const QString sDescription = QObject::tr( "Creates a Heatmap raster for the input point vector" );
4649
static const QString sCategory = QObject::tr( "Raster" );
47-
static const QString sPluginVersion = QObject::tr( "Version 0.1" );
50+
static const QString sPluginVersion = QObject::tr( "Version 0.2" );
4851
static const QgisPlugin::PLUGINTYPE sPluginType = QgisPlugin::UI;
4952
static const QString sPluginIcon = ":/heatmap/heatmap.png";
5053

@@ -94,186 +97,228 @@ void Heatmap::help()
9497
// not be enough
9598
void Heatmap::run()
9699
{
97-
HeatmapGui *myPluginGui = new HeatmapGui( mQGisIface->mainWindow(), QgisGui::ModalDialogFlags );
98-
myPluginGui->setAttribute( Qt::WA_DeleteOnClose );
100+
HeatmapGui d( mQGisIface->mainWindow(), QgisGui::ModalDialogFlags );
99101

100-
// Connect the createRaster signal to createRaster Slot
101-
connect( myPluginGui, SIGNAL( createRaster( QgsVectorLayer*, int, float, QString, QString ) ),
102-
this, SLOT( createRaster( QgsVectorLayer*, int, float, QString, QString ) ) );
103-
104-
myPluginGui->show();
105-
}
106-
107-
// Unload the plugin by cleaning up the GUI
108-
void Heatmap::unload()
109-
{
110-
// remove the GUI
111-
mQGisIface->removePluginRasterMenu( tr( "&Heatmap" ), mQActionPointer );
112-
mQGisIface->removeRasterToolBarIcon( mQActionPointer );
113-
delete mQActionPointer;
114-
}
115-
116-
// The worker
117-
void Heatmap::createRaster( QgsVectorLayer* theVectorLayer, int theBuffer, float theDecay, QString theOutputFilename, QString theOutputFormat )
118-
{
119-
// generic variables
120-
int xSize, ySize;
121-
double xResolution, yResolution;
122-
double rasterX, rasterY;
123-
124-
// Getting the rasterdataset in place
125-
GDALAllRegister();
102+
if ( d.exec() == QDialog::Accepted )
103+
{
104+
// everything runs here
126105

127-
GDALDataset *emptyDataset;
128-
GDALDriver *myDriver;
106+
// Get the required data from the dialog
107+
QgsRectangle myBBox = d.bbox();
108+
int columns = d.columns();
109+
int rows = d.rows();
110+
float cellsize = d.cellSizeX(); // or d.cellSizeY(); both have the same value
111+
float myDecay = d.decayRatio();
129112

130-
myDriver = GetGDALDriverManager()->GetDriverByName( theOutputFormat.toUtf8() );
131-
if ( myDriver == NULL )
132-
{
133-
QMessageBox::information( 0, tr( "GDAL driver error" ), tr( "Cannot open the driver for the specified format" ) );
134-
return;
135-
}
113+
// Getting the rasterdataset in place
114+
GDALAllRegister();
136115

137-
// bounding box info
138-
QgsRectangle myBBox = theVectorLayer->extent();
139-
// fixing a base width of 500 px/cells
140-
xSize = 500;
141-
xResolution = myBBox.width() / xSize;
142-
yResolution = xResolution;
143-
ySize = myBBox.height() / yResolution;
144-
// add extra extend to cover the corner points' heat region
145-
xSize = xSize + ( theBuffer * 2 ) + 10 ;
146-
ySize = ySize + ( theBuffer * 2 ) + 10 ;
147-
// Define the new lat,lon for the buffered raster area
148-
rasterX = myBBox.xMinimum() - ( theBuffer + 5 ) * xResolution;
149-
rasterY = myBBox.yMinimum() - ( theBuffer + 5 ) * yResolution;
150-
151-
double geoTransform[6] = { rasterX, xResolution, 0, rasterY, 0, yResolution };
152-
153-
emptyDataset = myDriver->Create( theOutputFilename.toUtf8(), xSize, ySize, 1, GDT_Float32, NULL );
154-
155-
emptyDataset->SetGeoTransform( geoTransform );
156-
157-
GDALRasterBand *poBand;
158-
poBand = emptyDataset->GetRasterBand( 1 );
159-
poBand->SetNoDataValue( NO_DATA );
160-
161-
float* line = ( float * ) CPLMalloc( sizeof( float ) * xSize );
162-
for ( int i = 0; i < xSize; i++ )
163-
line[i] = NO_DATA;
164-
// Write the empty raster
165-
for ( int i = 0; i < ySize ; i++ )
166-
{
167-
poBand->RasterIO( GF_Write, 0, 0, xSize, 1, line, xSize, 1, GDT_Float32, 0, 0 );
168-
}
116+
GDALDataset *emptyDataset;
117+
GDALDriver *myDriver;
169118

170-
CPLFree( line );
171-
//close the dataset
172-
GDALClose(( GDALDatasetH ) emptyDataset );
119+
myDriver = GetGDALDriverManager()->GetDriverByName( d.outputFormat().toUtf8() );
120+
if ( myDriver == NULL )
121+
{
122+
QMessageBox::information( 0, tr( "GDAL driver error" ), tr( "Cannot open the driver for the specified format" ) );
123+
return;
124+
}
173125

174-
// open the raster in GA_Update mode
175-
GDALDataset *heatmapDS;
176-
heatmapDS = ( GDALDataset * ) GDALOpen( theOutputFilename.toUtf8(), GA_Update );
177-
if ( !heatmapDS )
178-
{
179-
QMessageBox::information( 0, tr( "Raster update error" ), tr( "Could not open the created raster for updating. The heatmap was not generated." ) );
180-
return;
181-
}
182-
poBand = heatmapDS->GetRasterBand( 1 );
183-
// Get the data buffer ready
184-
int blockSize = 2 * theBuffer + 1; // block SIDE would have been more appropriate
185-
// Open the vector features
186-
QgsVectorDataProvider* myVectorProvider = theVectorLayer->dataProvider();
187-
if ( !myVectorProvider )
188-
{
189-
QMessageBox::information( 0, tr( "Point layer error" ), tr( "Could not identify the vector data provider." ) );
190-
return;
191-
}
192-
QgsAttributeList dummyList;
193-
myVectorProvider->select( dummyList );
126+
double geoTransform[6] = { myBBox.xMinimum(), cellsize, 0, myBBox.yMinimum(), 0, cellsize };
127+
emptyDataset = myDriver->Create( d.outputFilename().toUtf8(), columns, rows, 1, GDT_Float32, NULL );
128+
emptyDataset->SetGeoTransform( geoTransform );
194129

195-
int totalFeatures = myVectorProvider->featureCount();
196-
int counter = 0;
130+
GDALRasterBand *poBand;
131+
poBand = emptyDataset->GetRasterBand( 1 );
132+
poBand->SetNoDataValue( NO_DATA );
197133

198-
QProgressDialog p( "Creating Heatmap ... ", "Abort", 0, totalFeatures );
199-
p.setWindowModality( Qt::WindowModal );
134+
float* line = ( float * ) CPLMalloc( sizeof( float ) * columns );
135+
for ( int i = 0; i < columns ; i++ )
136+
line[i] = NO_DATA;
137+
// Write the empty raster
138+
for ( int i = 0; i < rows ; i++ )
139+
{
140+
poBand->RasterIO( GF_Write, 0, 0, columns, 1, line, columns, 1, GDT_Float32, 0, 0 );
141+
}
200142

201-
QgsFeature myFeature;
143+
CPLFree( line );
144+
//close the dataset
145+
GDALClose(( GDALDatasetH ) emptyDataset );
202146

203-
while ( myVectorProvider->nextFeature( myFeature ) )
204-
{
205-
counter++;
206-
p.setValue( counter );
207-
if ( p.wasCanceled() )
147+
// open the raster in GA_Update mode
148+
GDALDataset *heatmapDS;
149+
heatmapDS = ( GDALDataset * ) GDALOpen( d.outputFilename().toUtf8(), GA_Update );
150+
if ( !heatmapDS )
151+
{
152+
QMessageBox::information( 0, tr( "Raster update error" ), tr( "Could not open the created raster for updating. The heatmap was not generated." ) );
153+
return;
154+
}
155+
poBand = heatmapDS->GetRasterBand( 1 );
156+
// Start working on the input vector
157+
QgsVectorLayer* inputLayer = d.inputVectorLayer();
158+
QgsVectorDataProvider* myVectorProvider = inputLayer->dataProvider();
159+
if ( !myVectorProvider )
208160
{
209-
QMessageBox::information( 0, tr( "Heatmap generation aborted" ), tr( "QGIS will now load the partially-computed raster." ) );
210-
break;
161+
QMessageBox::information( 0, tr( "Point layer error" ), tr( "Could not identify the vector data provider." ) );
162+
return;
211163
}
212164

213-
QgsGeometry* myPointGeometry;
214-
myPointGeometry = myFeature.geometry();
215-
// convert the geometry to point
216-
QgsPoint myPoint;
217-
myPoint = myPointGeometry->asPoint();
218-
// avoiding any empty points or out of extent points
219-
if (( myPoint.x() < rasterX ) || ( myPoint.y() < rasterY ) )
165+
QgsAttributeList myAttrList;
166+
int rField = 0;
167+
int wField = 0;
168+
if ( d.variableRadius() )
169+
{
170+
rField = d.radiusField();
171+
myAttrList.append( rField );
172+
QgsDebugMsg( tr( "Radius Field index received: %1" ).arg( rField ) );
173+
}
174+
if ( d.weighted() )
220175
{
221-
continue;
176+
wField = d.weightField();
177+
myAttrList.append( wField );
222178
}
223-
// calculate the pixel position
224-
unsigned int xPosition, yPosition;
225-
xPosition = (( myPoint.x() - rasterX ) / xResolution ) - theBuffer;
226-
yPosition = (( myPoint.y() - rasterY ) / yResolution ) - theBuffer;
179+
// This might have attributes or mightnot have attibutes at all
180+
// based on the variableRadius() and weighted()
181+
myVectorProvider->select( myAttrList );
182+
int totalFeatures = myVectorProvider->featureCount();
183+
int counter = 0;
227184

228-
// get the data
229-
float *dataBuffer = ( float * ) CPLMalloc( sizeof( float ) * blockSize * blockSize );
230-
poBand->RasterIO( GF_Read, xPosition, yPosition, blockSize, blockSize, dataBuffer, blockSize, blockSize, GDT_Float32, 0, 0 );
185+
QProgressDialog p( "Creating Heatmap ... ", "Abort", 0, totalFeatures );
186+
p.setWindowModality( Qt::WindowModal );
231187

232-
for ( int xp = 0; xp <= theBuffer; xp++ )
188+
QgsFeature myFeature;
189+
190+
while ( myVectorProvider->nextFeature( myFeature ) )
233191
{
234-
for ( int yp = 0; yp <= theBuffer; yp++ )
192+
counter++;
193+
p.setValue( counter );
194+
if ( p.wasCanceled() )
235195
{
236-
float distance = sqrt( pow( xp, 2.0 ) + pow( yp, 2.0 ) );
237-
float pixelValue = 1 - (( 1 - theDecay ) * distance / theBuffer );
196+
QMessageBox::information( 0, tr( "Heatmap generation aborted" ), tr( "QGIS will now load the partially-computed raster." ) );
197+
break;
198+
}
238199

239-
// clearing anamolies along the axes
240-
if ( xp == 0 && yp == 0 )
241-
{
242-
pixelValue /= 4;
243-
}
244-
else if ( xp == 0 || yp == 0 )
245-
{
246-
pixelValue /= 2;
247-
}
200+
QgsGeometry* myPointGeometry;
201+
myPointGeometry = myFeature.geometry();
202+
// convert the geometry to point
203+
QgsPoint myPoint;
204+
myPoint = myPointGeometry->asPoint();
205+
// avoiding any empty points or out of extent points
206+
if (( myPoint.x() < myBBox.xMinimum() ) || ( myPoint.y() < myBBox.yMinimum() ) )
207+
{
208+
continue;
209+
}
210+
float radius;
211+
if ( d.variableRadius() )
212+
{
213+
QgsAttributeMap myAttrMap = myFeature.attributeMap();
214+
radius = myAttrMap.value( rField ).toFloat();
215+
}
216+
else
217+
{
218+
radius = d.radius();
219+
}
220+
//convert the radius to map units if it is in meters
221+
if ( d.radiusUnit() == HeatmapGui::Meters )
222+
{
223+
radius = mapUnitsOf( radius, inputLayer->crs() );
224+
}
225+
// convert radius in map units to pixel count
226+
int myBuffer = radius / cellsize;
227+
if ( radius - ( cellsize * myBuffer ) > 0.5 )
228+
{
229+
++myBuffer;
230+
}
231+
int blockSize = 2 * myBuffer + 1; //Block SIDE would be more appropriate
232+
// calculate the pixel position
233+
unsigned int xPosition, yPosition;
234+
xPosition = (( myPoint.x() - myBBox.xMinimum() ) / cellsize ) - myBuffer;
235+
yPosition = (( myPoint.y() - myBBox.yMinimum() ) / cellsize ) - myBuffer;
236+
237+
// get the data
238+
float *dataBuffer = ( float * ) CPLMalloc( sizeof( float ) * blockSize * blockSize );
239+
poBand->RasterIO( GF_Read, xPosition, yPosition, blockSize, blockSize,
240+
dataBuffer, blockSize, blockSize, GDT_Float32, 0, 0 );
241+
242+
float weight = 1.0;
243+
if ( d.weighted() )
244+
{
245+
QgsAttributeMap myAttrMap = myFeature.attributeMap();
246+
weight = myAttrMap.value( wField ).toFloat();
247+
}
248248

249-
if ( distance <= theBuffer )
249+
for ( int xp = 0; xp <= myBuffer; xp++ )
250+
{
251+
for ( int yp = 0; yp <= myBuffer; yp++ )
250252
{
251-
int pos[4];
252-
pos[0] = ( theBuffer + xp ) * blockSize + ( theBuffer + yp );
253-
pos[1] = ( theBuffer + xp ) * blockSize + ( theBuffer - yp );
254-
pos[2] = ( theBuffer - xp ) * blockSize + ( theBuffer + yp );
255-
pos[3] = ( theBuffer - xp ) * blockSize + ( theBuffer - yp );
256-
for ( int p = 0; p < 4; p++ )
253+
float distance = sqrt( pow( xp, 2.0 ) + pow( yp, 2.0 ) );
254+
float pixelValue = weight * ( 1 - (( 1 - myDecay ) * distance / myBuffer ) );
255+
256+
// clearing anamolies along the axes
257+
if ( xp == 0 && yp == 0 )
258+
{
259+
pixelValue /= 4;
260+
}
261+
else if ( xp == 0 || yp == 0 )
257262
{
258-
if ( dataBuffer[ pos[p] ] == NO_DATA )
263+
pixelValue /= 2;
264+
}
265+
266+
if ( distance <= myBuffer )
267+
{
268+
int pos[4];
269+
pos[0] = ( myBuffer + xp ) * blockSize + ( myBuffer + yp );
270+
pos[1] = ( myBuffer + xp ) * blockSize + ( myBuffer - yp );
271+
pos[2] = ( myBuffer - xp ) * blockSize + ( myBuffer + yp );
272+
pos[3] = ( myBuffer - xp ) * blockSize + ( myBuffer - yp );
273+
for ( int p = 0; p < 4; p++ )
259274
{
260-
dataBuffer[ pos[p] ] = 0;
275+
if ( dataBuffer[ pos[p] ] == NO_DATA )
276+
{
277+
dataBuffer[ pos[p] ] = 0;
278+
}
279+
dataBuffer[ pos[p] ] += pixelValue;
261280
}
262-
dataBuffer[ pos[p] ] += pixelValue;
263281
}
264282
}
265283
}
284+
285+
poBand->RasterIO( GF_Write, xPosition, yPosition, blockSize, blockSize,
286+
dataBuffer, blockSize, blockSize, GDT_Float32, 0, 0 );
287+
CPLFree( dataBuffer );
266288
}
289+
//Finally close the dataset
290+
GDALClose(( GDALDatasetH ) heatmapDS );
267291

268-
poBand->RasterIO( GF_Write, xPosition, yPosition, blockSize, blockSize, dataBuffer, blockSize, blockSize, GDT_Float32, 0, 0 );
269-
CPLFree( dataBuffer );
292+
// Open the file in QGIS window
293+
mQGisIface->addRasterLayer( d.outputFilename(), QFileInfo( d.outputFilename() ).baseName() );
270294
}
295+
}
271296

272-
//Finally close the dataset
273-
GDALClose(( GDALDatasetH ) heatmapDS );
297+
/*
298+
*
299+
* Local functions
300+
*
301+
*/
302+
float Heatmap::mapUnitsOf( float meters, QgsCoordinateReferenceSystem layerCrs )
303+
{
304+
// Worker to transform metres input to mapunits
305+
QgsDistanceArea da;
306+
da.setSourceCrs( layerCrs.srsid() );
307+
da.setEllipsoid( layerCrs.ellipsoidAcronym() );
308+
if ( da.geographic() )
309+
{
310+
da.setProjectionsEnabled( true );
311+
}
312+
return meters / da.measureLine( QgsPoint( 0.0, 0.0 ), QgsPoint( 0.0, 1.0 ) );
313+
}
274314

275-
// Open the file in QGIS window
276-
mQGisIface->addRasterLayer( theOutputFilename, QFileInfo( theOutputFilename ).baseName() );
315+
// Unload the plugin by cleaning up the GUI
316+
void Heatmap::unload()
317+
{
318+
// remove the GUI
319+
mQGisIface->removePluginRasterMenu( tr( "&Heatmap" ), mQActionPointer );
320+
mQGisIface->removeRasterToolBarIcon( mQActionPointer );
321+
delete mQActionPointer;
277322
}
278323

279324
//////////////////////////////////////////////////////////////////////////

‎src/plugins/heatmap/heatmap.h

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
//QGIS includes
4242
#include "../qgisplugin.h"
4343
#include "qgsvectorlayer.h"
44+
#include "qgscoordinatereferencesystem.h"
4445

4546
//forward declarations
4647
class QAction;
@@ -78,20 +79,10 @@ class Heatmap: public QObject, public QgisPlugin
7879
void unload();
7980
//! show the help document
8081
void help();
81-
//! the worker slot to create heatmap
82-
/*
83-
* Signal: createRaster
84-
* Params:
85-
* QgsVectorLayer* -> Input point layer
86-
* int -> Buffer distance
87-
* float -> Decay ratio
88-
* QString -> Output filename
89-
* QString -> Output Format Short Name
90-
*/
91-
void createRaster( QgsVectorLayer*, int, float, QString, QString );
9282

9383
private:
94-
84+
//! Worker to convert meters to map units
85+
float mapUnitsOf( float meters, QgsCoordinateReferenceSystem crs );
9586
// MANDATORY PLUGIN PROPERTY DECLARATIONS .....
9687

9788
int mPluginType;

‎src/plugins/heatmap/heatmapgui.cpp

Lines changed: 311 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@
1616
#include "qgsmaplayer.h"
1717
#include "qgsmaplayerregistry.h"
1818
#include "qgsvectorlayer.h"
19+
#include "qgsvectordataprovider.h"
20+
#include "qgslogger.h"
21+
#include "qgsgeometry.h"
22+
#include "qgscoordinatereferencesystem.h"
23+
#include "qgsdistancearea.h"
1924

2025
// GDAL includes
2126
#include "gdal_priv.h"
@@ -35,6 +40,8 @@ HeatmapGui::HeatmapGui( QWidget* parent, Qt::WFlags fl )
3540
{
3641
setupUi( this );
3742

43+
QgsDebugMsg( tr( "Creating Heatmap Dialog" ) );
44+
3845
// Adding point layers to the mInputVectorCombo
3946
foreach( QgsMapLayer *l, QgsMapLayerRegistry::instance()->mapLayers() )
4047
{
@@ -70,6 +77,7 @@ HeatmapGui::HeatmapGui( QWidget* parent, Qt::WFlags fl )
7077
}
7178
mFormatCombo->setCurrentIndex( myTiffIndex );
7279

80+
updateBBox();
7381
//finally set right the ok button
7482
enableOrDisableOkButton();
7583
}
@@ -78,70 +86,13 @@ HeatmapGui::~HeatmapGui()
7886
{
7987
}
8088

89+
/*
90+
*
91+
* Private Slots
92+
*
93+
*/
8194
void HeatmapGui::on_mButtonBox_accepted()
8295
{
83-
// Variables to be emitted with the createRaster signal
84-
int bufferDistance;
85-
float decayRatio;
86-
QString outputFileName;
87-
QString outputFormat;
88-
89-
QString dummyText;
90-
91-
// The input vector layer
92-
QString myLayerId = mInputVectorCombo->itemData( mInputVectorCombo->currentIndex() ).toString();
93-
94-
QgsVectorLayer* inputLayer = qobject_cast<QgsVectorLayer *>( QgsMapLayerRegistry::instance()->mapLayer( myLayerId ) );
95-
if ( !inputLayer )
96-
{
97-
QMessageBox::information( 0, tr( "Layer not found" ), tr( "Layer %1 not found." ).arg( myLayerId ) );
98-
return;
99-
}
100-
101-
// The buffer distance
102-
dummyText = mBufferLineEdit->text();
103-
bufferDistance = dummyText.toInt();
104-
if ( bufferDistance == 0 )
105-
{
106-
QMessageBox::information( 0, tr( "Invalid buffer value" ), tr( "Buffer distance cannot be zero. Please enter a valid value." ) );
107-
return;
108-
}
109-
// The decay ratio
110-
dummyText = mDecayLineEdit->text();
111-
decayRatio = dummyText.toFloat();
112-
113-
// The output filename
114-
outputFileName = mOutputRasterLineEdit->text();
115-
QFileInfo myFileInfo( outputFileName );
116-
if ( outputFileName.isEmpty() || !myFileInfo.dir().exists() )
117-
{
118-
QMessageBox::information( 0, tr( "Invalid output filename" ), tr( "Please enter a valid output file path and name." ) );
119-
return;
120-
}
121-
122-
// The output format
123-
outputFormat = mFormatCombo->itemData( mFormatCombo->currentIndex() ).toString();
124-
125-
// append the file format if the suffix is empty
126-
QString suffix = myFileInfo.suffix();
127-
if ( suffix.isEmpty() )
128-
{
129-
QMap<QString, QString>::const_iterator it = mExtensionMap.find( outputFormat );
130-
if ( it != mExtensionMap.end() && it.key() == outputFormat )
131-
{
132-
// making sure that there is really a extension value available
133-
// Some drivers donot seem to have any extension at all
134-
if ( it.value() != NULL || it.value() != "" )
135-
{
136-
outputFileName.append( "." );
137-
outputFileName.append( it.value() );
138-
}
139-
}
140-
}
141-
142-
emit createRaster( inputLayer, bufferDistance, decayRatio, outputFileName, outputFormat );
143-
144-
//and finally
14596
accept();
14697
}
14798

@@ -180,6 +131,101 @@ void HeatmapGui::on_mOutputRasterLineEdit_editingFinished()
180131
enableOrDisableOkButton();
181132
}
182133

134+
void HeatmapGui::on_advancedGroupBox_toggled( bool enabled )
135+
{
136+
if ( enabled )
137+
{
138+
// if there are no layers point layers then show error dialog and toggle
139+
if ( mInputVectorCombo->count() == 0 )
140+
{
141+
QMessageBox::information( 0, tr( "No valid layers found!" ), tr( "Advanced options cannot be enabled." ) );
142+
advancedGroupBox->setChecked( false );
143+
return;
144+
}
145+
// if there are layers then populate fields
146+
populateFields();
147+
updateBBox();
148+
}
149+
}
150+
151+
void HeatmapGui::on_rowLineEdit_editingFinished()
152+
{
153+
mRows = rowLineEdit->text().toInt();
154+
mYcellsize = mBBox.height() / mRows;
155+
mXcellsize = mYcellsize;
156+
mColumns = mBBox.width() / mXcellsize + 1;
157+
158+
updateSize();
159+
}
160+
161+
void HeatmapGui::on_columnLineEdit_editingFinished()
162+
{
163+
mColumns = columnLineEdit->text().toInt();
164+
mXcellsize = mBBox.width() / mColumns;
165+
mYcellsize = mXcellsize;
166+
mRows = mBBox.height() / mYcellsize + 1;
167+
168+
updateSize();
169+
}
170+
171+
void HeatmapGui::on_cellXLineEdit_editingFinished()
172+
{
173+
mXcellsize = cellXLineEdit->text().toFloat();
174+
mYcellsize = mXcellsize;
175+
mRows = mBBox.height() / mYcellsize + 1;
176+
mColumns = mBBox.width() / mXcellsize + 1;
177+
178+
updateSize();
179+
}
180+
181+
void HeatmapGui::on_cellYLineEdit_editingFinished()
182+
{
183+
mYcellsize = cellYLineEdit->text().toFloat();
184+
mXcellsize = mYcellsize;
185+
mRows = mBBox.height() / mYcellsize + 1;
186+
mColumns = mBBox.width() / mXcellsize + 1;
187+
188+
updateSize();
189+
}
190+
191+
void HeatmapGui::on_radiusFieldUnitCombo_currentIndexChanged( int index )
192+
{
193+
updateBBox();
194+
// DebugMsg to avoid index not used warning
195+
QgsDebugMsg( tr( "Unit index set to %1" ).arg( index ) );
196+
}
197+
198+
void HeatmapGui::on_mRadiusUnitCombo_currentIndexChanged( int index )
199+
{
200+
QgsDebugMsg( tr( "Unit index set to %1" ).arg( index ) );
201+
updateBBox();
202+
}
203+
204+
void HeatmapGui::on_mInputVectorCombo_currentIndexChanged( int index )
205+
{
206+
if ( advancedGroupBox->isChecked() )
207+
{
208+
populateFields();
209+
updateBBox();
210+
}
211+
QgsDebugMsg( tr( "Input vector index changed to %1" ).arg( index ) );
212+
}
213+
214+
void HeatmapGui::on_radiusFieldCombo_currentIndexChanged( int index )
215+
{
216+
updateBBox();
217+
QgsDebugMsg( tr( "Radius Field index changed to %1" ).arg( index ) );
218+
}
219+
220+
void HeatmapGui::on_mBufferLineEdit_editingFinished()
221+
{
222+
updateBBox();
223+
}
224+
/*
225+
*
226+
* Private Functions
227+
*
228+
*/
183229
void HeatmapGui::enableOrDisableOkButton()
184230
{
185231
bool enabled = true;
@@ -191,3 +237,206 @@ void HeatmapGui::enableOrDisableOkButton()
191237
}
192238
mButtonBox->button( QDialogButtonBox::Ok )->setEnabled( enabled );
193239
}
240+
241+
void HeatmapGui::populateFields()
242+
{
243+
QgsVectorLayer* inputLayer = inputVectorLayer();
244+
// The fields
245+
QgsVectorDataProvider* provider = inputLayer->dataProvider();
246+
QgsFieldMap fieldMap = provider->fields();
247+
// Populate fields
248+
radiusFieldCombo->clear();
249+
weightFieldCombo->clear();
250+
251+
QMap<int, QgsField>::const_iterator i = fieldMap.constBegin();
252+
while ( i != fieldMap.constEnd() )
253+
{
254+
radiusFieldCombo->addItem( i.value().name(), QVariant( i.key() ) );
255+
weightFieldCombo->addItem( i.value().name(), QVariant( i.key() ) );
256+
++i;
257+
}
258+
259+
}
260+
261+
void HeatmapGui::updateSize()
262+
{
263+
rowLineEdit->setText( QString::number( mRows ) );
264+
columnLineEdit->setText( QString::number( mColumns ) );
265+
cellXLineEdit->setText( QString::number( mXcellsize ) );
266+
cellYLineEdit->setText( QString::number( mYcellsize ) );
267+
}
268+
269+
void HeatmapGui::updateBBox()
270+
{
271+
// Set the row/cols and cell sizes here
272+
QgsVectorLayer *inputLayer = inputVectorLayer();
273+
274+
mBBox = inputLayer->extent();
275+
QgsCoordinateReferenceSystem layerCrs = inputLayer->crs();
276+
277+
float radiusInMapUnits;
278+
if ( useRadius->isChecked() )
279+
{
280+
float maxInField = inputLayer->maximumValue( radiusFieldCombo->itemData( radiusFieldCombo->currentIndex() ).toInt() ).toFloat();
281+
282+
if ( radiusFieldUnitCombo->currentIndex() == HeatmapGui::Meters )
283+
{
284+
radiusInMapUnits = mapUnitsOf( maxInField, layerCrs );
285+
}
286+
else if ( radiusFieldUnitCombo->currentIndex() == HeatmapGui::MapUnits )
287+
{
288+
radiusInMapUnits = maxInField;
289+
}
290+
}
291+
else
292+
{
293+
float radiusValue = mBufferLineEdit->text().toFloat();
294+
if ( mRadiusUnitCombo->currentIndex() == HeatmapGui::Meters )
295+
{
296+
radiusInMapUnits = mapUnitsOf( radiusValue, layerCrs );
297+
}
298+
else if ( mRadiusUnitCombo->currentIndex() == HeatmapGui::MapUnits )
299+
{
300+
radiusInMapUnits = radiusValue;
301+
}
302+
}
303+
// get the distance converted into map units
304+
mBBox.setXMinimum( mBBox.xMinimum() - radiusInMapUnits );
305+
mBBox.setYMinimum( mBBox.yMinimum() - radiusInMapUnits );
306+
mBBox.setXMaximum( mBBox.xMaximum() + radiusInMapUnits );
307+
mBBox.setYMaximum( mBBox.yMaximum() + radiusInMapUnits );
308+
mRows = 500;
309+
mYcellsize = mBBox.height() / mRows;
310+
mXcellsize = mYcellsize;
311+
// +1 should be added wherever a fractional part of cell might occur
312+
mColumns = mBBox.width() / mXcellsize + 1;
313+
mRows += 1;
314+
315+
if ( advancedGroupBox->isChecked() )
316+
{
317+
updateSize();
318+
}
319+
}
320+
321+
float HeatmapGui::mapUnitsOf( float meters, QgsCoordinateReferenceSystem layerCrs )
322+
{
323+
// converter function to transform metres input to mapunits
324+
// so that bounding box can be updated
325+
QgsDistanceArea da;
326+
da.setSourceCrs( layerCrs.srsid() );
327+
da.setEllipsoid( layerCrs.ellipsoidAcronym() );
328+
if ( da.geographic() )
329+
{
330+
da.setProjectionsEnabled( true );
331+
}
332+
double unitDistance = da.measureLine( QgsPoint( 0.0, 0.0 ), QgsPoint( 0.0, 1.0 ) );
333+
QgsDebugMsg( tr( "Converted %1 meters to %2 mapunits" ).arg( meters ).arg( meters / unitDistance ) );
334+
return meters / unitDistance;
335+
}
336+
/*
337+
*
338+
* Public functions
339+
*
340+
*/
341+
342+
bool HeatmapGui::weighted()
343+
{
344+
return useWeight->isChecked();
345+
}
346+
347+
bool HeatmapGui::variableRadius()
348+
{
349+
return useRadius->isChecked();
350+
}
351+
352+
float HeatmapGui::radius()
353+
{
354+
float radius = mBufferLineEdit->text().toInt();
355+
if ( mRadiusUnitCombo->currentIndex() == HeatmapGui::Meters )
356+
{
357+
radius = mapUnitsOf( radius, inputVectorLayer()->crs() );
358+
}
359+
return radius;
360+
}
361+
362+
int HeatmapGui::radiusUnit()
363+
{
364+
if ( useRadius->isChecked() )
365+
{
366+
return radiusFieldUnitCombo->currentIndex();
367+
}
368+
return mRadiusUnitCombo->currentIndex();
369+
}
370+
371+
float HeatmapGui::decayRatio()
372+
{
373+
return mDecayLineEdit->text().toFloat();
374+
}
375+
376+
int HeatmapGui::radiusField()
377+
{
378+
int radiusindex;
379+
radiusindex = radiusFieldCombo->currentIndex();
380+
return radiusFieldCombo->itemData( radiusindex ).toInt();
381+
}
382+
383+
int HeatmapGui::weightField()
384+
{
385+
int weightindex;
386+
weightindex = weightFieldCombo->currentIndex();
387+
return weightFieldCombo->itemData( weightindex ).toInt();
388+
}
389+
390+
QString HeatmapGui::outputFilename()
391+
{
392+
QString outputFileName;
393+
QString outputFormat;
394+
395+
outputFileName = mOutputRasterLineEdit->text();
396+
QFileInfo myFileInfo( outputFileName );
397+
if ( outputFileName.isEmpty() || !myFileInfo.dir().exists() )
398+
{
399+
QMessageBox::information( 0, tr( "Invalid output filename" ), tr( "Please enter a valid output file path and name." ) );
400+
return NULL;
401+
}
402+
403+
// The output format
404+
outputFormat = mFormatCombo->itemData( mFormatCombo->currentIndex() ).toString();
405+
// append the file format if the suffix is empty
406+
QString suffix = myFileInfo.suffix();
407+
if ( suffix.isEmpty() )
408+
{
409+
QMap<QString, QString>::const_iterator it = mExtensionMap.find( outputFormat );
410+
if ( it != mExtensionMap.end() && it.key() == outputFormat )
411+
{
412+
// making sure that there is really a extension value available
413+
// Some drivers donot seem to have any extension at all
414+
if ( it.value() != NULL || it.value() != "" )
415+
{
416+
outputFileName.append( "." );
417+
outputFileName.append( it.value() );
418+
}
419+
}
420+
}
421+
422+
return outputFileName;
423+
}
424+
425+
QString HeatmapGui::outputFormat()
426+
{
427+
return mFormatCombo->itemData( mFormatCombo->currentIndex() ).toString();
428+
}
429+
430+
QgsVectorLayer* HeatmapGui::inputVectorLayer()
431+
{
432+
QString myLayerId = mInputVectorCombo->itemData( mInputVectorCombo->currentIndex() ).toString();
433+
434+
QgsVectorLayer* inputLayer = qobject_cast<QgsVectorLayer *>( QgsMapLayerRegistry::instance()->mapLayer( myLayerId ) );
435+
if ( !inputLayer )
436+
{
437+
QMessageBox::information( 0, tr( "Layer not found" ), tr( "Layer %1 not found." ).arg( myLayerId ) );
438+
return NULL;
439+
}
440+
return inputLayer;
441+
}
442+

‎src/plugins/heatmap/heatmapgui.h

Lines changed: 86 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@
1616
#include <ui_heatmapguibase.h>
1717

1818
#include "qgsvectorlayer.h"
19+
#include "qgscoordinatereferencesystem.h"
20+
#include "qgsgeometry.h"
1921
/**
20-
@author Tim Sutton
22+
@author Arunmozhi
2123
*/
2224
class HeatmapGui : public QDialog, private Ui::HeatmapGuiBase
2325
{
@@ -26,29 +28,98 @@ class HeatmapGui : public QDialog, private Ui::HeatmapGuiBase
2628
HeatmapGui( QWidget* parent = 0, Qt::WFlags fl = 0 );
2729
~HeatmapGui();
2830

31+
// Buffer unit type
32+
// Should have been private, made public to be used in heatmap.cpp
33+
enum mBufferType
34+
{
35+
Meters,
36+
MapUnits
37+
};
38+
39+
/** Returns whether to apply weighted heat */
40+
bool weighted();
41+
42+
/** Returns whether the radius is static or based on a field */
43+
bool variableRadius();
44+
45+
/** Returns the fixed radius value */
46+
float radius();
47+
48+
/** Return the radius Unit (meters/map units) */
49+
int radiusUnit();
50+
51+
/** Return the decay ratio */
52+
float decayRatio();
53+
54+
/** Return the attribute field for variable radius */
55+
int radiusField();
56+
57+
/** Returns the attrinute field for weighted heat */
58+
int weightField();
59+
60+
/** Returns the output filename/path */
61+
QString outputFilename();
62+
63+
/** Returns the GDAL Format for output raster */
64+
QString outputFormat();
65+
66+
/** Returns the input Vector layer */
67+
QgsVectorLayer* inputVectorLayer();
68+
69+
/** Returns the no of rows for the raster */
70+
int rows() { return mRows; }
71+
72+
/** Returns the no of columns in the raster */
73+
int columns() { return mColumns; }
74+
75+
/** Returns the cell size X value */
76+
float cellSizeX() { return mXcellsize; }
77+
78+
/** Returns the cell size Y valuue */
79+
float cellSizeY() { return mYcellsize; }
80+
81+
/** Return the BBox */
82+
QgsRectangle bbox() { return mBBox; }
83+
2984
private:
3085
QMap<QString, QString> mExtensionMap;
86+
87+
// bbox of layer for lineedit changes
88+
QgsRectangle mBBox;
89+
float mXcellsize, mYcellsize;
90+
int mRows, mColumns;
91+
92+
/** Function to check wether all constrains are satisfied and enable the OK button */
3193
void enableOrDisableOkButton();
3294

95+
/** Populate the attribute fields from selected vector for radius&weight */
96+
void populateFields();
97+
98+
/** Set the mBBox value - mainly used for updation purpose */
99+
void updateBBox();
100+
101+
/** Update the LineEdits cellsize and row&col values */
102+
void updateSize();
103+
104+
/** Convert Maters value to the corresponding map units based on Layer projection */
105+
float mapUnitsOf( float meters, QgsCoordinateReferenceSystem layerCrs );
106+
33107
private slots:
34108
void on_mButtonBox_accepted();
35109
void on_mButtonBox_rejected();
36110
void on_mButtonBox_helpRequested();
37-
void on_mBrowseButton_clicked(); // Function to open the file dialog
111+
void on_mBrowseButton_clicked();
38112
void on_mOutputRasterLineEdit_editingFinished();
39-
40-
signals:
41-
/*
42-
* Signal: createRaster
43-
* Params:
44-
* QgsVectorLayer* -> Input point layer
45-
* int -> Buffer distance
46-
* float -> Decay ratio
47-
* QString -> Output filename
48-
* QString -> Output Format Short Name
49-
*/
50-
void createRaster( QgsVectorLayer*, int, float, QString, QString );
51-
113+
void on_advancedGroupBox_toggled( bool enabled );
114+
void on_rowLineEdit_editingFinished();
115+
void on_columnLineEdit_editingFinished();
116+
void on_cellXLineEdit_editingFinished();
117+
void on_cellYLineEdit_editingFinished();
118+
void on_radiusFieldCombo_currentIndexChanged( int index );
119+
void on_radiusFieldUnitCombo_currentIndexChanged( int index );
120+
void on_mRadiusUnitCombo_currentIndexChanged( int index );
121+
void on_mInputVectorCombo_currentIndexChanged( int index );
122+
void on_mBufferLineEdit_editingFinished();
52123
};
53124

54125
#endif

‎src/plugins/heatmap/heatmapguibase.ui

Lines changed: 300 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,16 @@
66
<rect>
77
<x>0</x>
88
<y>0</y>
9-
<width>428</width>
10-
<height>254</height>
9+
<width>430</width>
10+
<height>380</height>
1111
</rect>
1212
</property>
13+
<property name="maximumSize">
14+
<size>
15+
<width>430</width>
16+
<height>380</height>
17+
</size>
18+
</property>
1319
<property name="windowTitle">
1420
<string>Heatmap Plugin</string>
1521
</property>
@@ -37,6 +43,19 @@
3743
<item row="1" column="1">
3844
<widget class="QLineEdit" name="mOutputRasterLineEdit"/>
3945
</item>
46+
<item row="1" column="2">
47+
<widget class="QPushButton" name="mBrowseButton">
48+
<property name="focusPolicy">
49+
<enum>Qt::ClickFocus</enum>
50+
</property>
51+
<property name="text">
52+
<string>...</string>
53+
</property>
54+
<property name="autoDefault">
55+
<bool>false</bool>
56+
</property>
57+
</widget>
58+
</item>
4059
<item row="3" column="0">
4160
<widget class="QLabel" name="mFormatLabel">
4261
<property name="text">
@@ -47,61 +66,196 @@
4766
<item row="3" column="1" colspan="2">
4867
<widget class="QComboBox" name="mFormatCombo"/>
4968
</item>
50-
<item row="4" column="0" colspan="3">
51-
<widget class="QGroupBox" name="mPointAttributeBox">
52-
<property name="title">
53-
<string>Heatmap Point Attributes</string>
54-
</property>
55-
<layout class="QGridLayout" name="gridLayout_2">
56-
<item row="0" column="0">
57-
<widget class="QLabel" name="mBufferLabel">
58-
<property name="text">
59-
<string>Buffer Radius</string>
60-
</property>
61-
</widget>
62-
</item>
63-
<item row="0" column="1">
64-
<widget class="QLineEdit" name="mBufferLineEdit">
65-
<property name="text">
66-
<string>10</string>
67-
</property>
68-
</widget>
69-
</item>
70-
<item row="1" column="0">
71-
<widget class="QLabel" name="mDecayLabel">
72-
<property name="text">
73-
<string>Decay Ratio</string>
74-
</property>
75-
</widget>
76-
</item>
77-
<item row="1" column="1">
78-
<widget class="QLineEdit" name="mDecayLineEdit">
79-
<property name="text">
80-
<string>0.5</string>
81-
</property>
82-
</widget>
83-
</item>
84-
</layout>
85-
</widget>
86-
</item>
87-
<item row="5" column="0" colspan="3">
69+
<item row="9" column="0" colspan="3">
8870
<widget class="QDialogButtonBox" name="mButtonBox">
8971
<property name="standardButtons">
9072
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::Ok</set>
9173
</property>
9274
</widget>
9375
</item>
94-
<item row="1" column="2">
95-
<widget class="QPushButton" name="mBrowseButton">
96-
<property name="focusPolicy">
97-
<enum>Qt::ClickFocus</enum>
76+
<item row="4" column="0">
77+
<widget class="QLabel" name="mRadiusLabel">
78+
<property name="text">
79+
<string>Radius</string>
9880
</property>
81+
</widget>
82+
</item>
83+
<item row="4" column="1">
84+
<widget class="QLineEdit" name="mBufferLineEdit">
9985
<property name="text">
100-
<string>...</string>
86+
<string>10</string>
10187
</property>
102-
<property name="autoDefault">
88+
</widget>
89+
</item>
90+
<item row="4" column="2">
91+
<widget class="QComboBox" name="mRadiusUnitCombo">
92+
<item>
93+
<property name="text">
94+
<string>meters</string>
95+
</property>
96+
</item>
97+
<item>
98+
<property name="text">
99+
<string>map units</string>
100+
</property>
101+
</item>
102+
</widget>
103+
</item>
104+
<item row="5" column="0">
105+
<widget class="QLabel" name="mDecayLabel">
106+
<property name="text">
107+
<string>Decay Ratio</string>
108+
</property>
109+
</widget>
110+
</item>
111+
<item row="5" column="1" colspan="2">
112+
<widget class="QLineEdit" name="mDecayLineEdit">
113+
<property name="text">
114+
<string>0.1</string>
115+
</property>
116+
</widget>
117+
</item>
118+
<item row="6" column="0" colspan="3">
119+
<widget class="QGroupBox" name="advancedGroupBox">
120+
<property name="sizePolicy">
121+
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
122+
<horstretch>0</horstretch>
123+
<verstretch>0</verstretch>
124+
</sizepolicy>
125+
</property>
126+
<property name="title">
127+
<string>Advanced</string>
128+
</property>
129+
<property name="checkable">
130+
<bool>true</bool>
131+
</property>
132+
<property name="checked">
103133
<bool>false</bool>
104134
</property>
135+
<widget class="QWidget" name="gridLayoutWidget">
136+
<property name="geometry">
137+
<rect>
138+
<x>10</x>
139+
<y>30</y>
140+
<width>391</width>
141+
<height>61</height>
142+
</rect>
143+
</property>
144+
<layout class="QGridLayout" name="advancedGrid">
145+
<property name="sizeConstraint">
146+
<enum>QLayout::SetFixedSize</enum>
147+
</property>
148+
<item row="0" column="0">
149+
<widget class="QLabel" name="rowLabel">
150+
<property name="text">
151+
<string>Row</string>
152+
</property>
153+
<property name="buddy">
154+
<cstring>rowLineEdit</cstring>
155+
</property>
156+
</widget>
157+
</item>
158+
<item row="1" column="0">
159+
<widget class="QLabel" name="cellsizeXLabel">
160+
<property name="text">
161+
<string>Cell Size X</string>
162+
</property>
163+
<property name="buddy">
164+
<cstring>cellXLineEdit</cstring>
165+
</property>
166+
</widget>
167+
</item>
168+
<item row="0" column="2">
169+
<widget class="QLabel" name="columnLabel">
170+
<property name="text">
171+
<string>Column</string>
172+
</property>
173+
<property name="buddy">
174+
<cstring>columnLineEdit</cstring>
175+
</property>
176+
</widget>
177+
</item>
178+
<item row="1" column="2">
179+
<widget class="QLabel" name="cellsizeYLabel">
180+
<property name="text">
181+
<string>Cell Size Y</string>
182+
</property>
183+
<property name="buddy">
184+
<cstring>cellYLineEdit</cstring>
185+
</property>
186+
</widget>
187+
</item>
188+
<item row="0" column="1">
189+
<widget class="QLineEdit" name="rowLineEdit"/>
190+
</item>
191+
<item row="0" column="3">
192+
<widget class="QLineEdit" name="columnLineEdit"/>
193+
</item>
194+
<item row="1" column="1">
195+
<widget class="QLineEdit" name="cellXLineEdit"/>
196+
</item>
197+
<item row="1" column="3">
198+
<widget class="QLineEdit" name="cellYLineEdit"/>
199+
</item>
200+
</layout>
201+
</widget>
202+
<widget class="QWidget" name="gridLayoutWidget_4">
203+
<property name="geometry">
204+
<rect>
205+
<x>10</x>
206+
<y>90</y>
207+
<width>391</width>
208+
<height>61</height>
209+
</rect>
210+
</property>
211+
<layout class="QGridLayout" name="gridLayout_2">
212+
<item row="0" column="0">
213+
<widget class="QCheckBox" name="useRadius">
214+
<property name="text">
215+
<string>Use Radius from field</string>
216+
</property>
217+
</widget>
218+
</item>
219+
<item row="0" column="1">
220+
<widget class="QComboBox" name="radiusFieldCombo">
221+
<property name="enabled">
222+
<bool>false</bool>
223+
</property>
224+
</widget>
225+
</item>
226+
<item row="0" column="2">
227+
<widget class="QComboBox" name="radiusFieldUnitCombo">
228+
<property name="enabled">
229+
<bool>false</bool>
230+
</property>
231+
<item>
232+
<property name="text">
233+
<string>meters</string>
234+
</property>
235+
</item>
236+
<item>
237+
<property name="text">
238+
<string>map units</string>
239+
</property>
240+
</item>
241+
</widget>
242+
</item>
243+
<item row="1" column="0">
244+
<widget class="QCheckBox" name="useWeight">
245+
<property name="text">
246+
<string>Use Weight from field</string>
247+
</property>
248+
</widget>
249+
</item>
250+
<item row="1" column="1" colspan="2">
251+
<widget class="QComboBox" name="weightFieldCombo">
252+
<property name="enabled">
253+
<bool>false</bool>
254+
</property>
255+
</widget>
256+
</item>
257+
</layout>
258+
</widget>
105259
</widget>
106260
</item>
107261
</layout>
@@ -115,8 +269,8 @@
115269
<slot>accept()</slot>
116270
<hints>
117271
<hint type="sourcelabel">
118-
<x>195</x>
119-
<y>123</y>
272+
<x>213</x>
273+
<y>370</y>
120274
</hint>
121275
<hint type="destinationlabel">
122276
<x>199</x>
@@ -131,14 +285,110 @@
131285
<slot>reject()</slot>
132286
<hints>
133287
<hint type="sourcelabel">
134-
<x>195</x>
135-
<y>123</y>
288+
<x>213</x>
289+
<y>370</y>
136290
</hint>
137291
<hint type="destinationlabel">
138292
<x>199</x>
139293
<y>79</y>
140294
</hint>
141295
</hints>
142296
</connection>
297+
<connection>
298+
<sender>useWeight</sender>
299+
<signal>toggled(bool)</signal>
300+
<receiver>weightFieldCombo</receiver>
301+
<slot>setEnabled(bool)</slot>
302+
<hints>
303+
<hint type="sourcelabel">
304+
<x>109</x>
305+
<y>315</y>
306+
</hint>
307+
<hint type="destinationlabel">
308+
<x>408</x>
309+
<y>318</y>
310+
</hint>
311+
</hints>
312+
</connection>
313+
<connection>
314+
<sender>useRadius</sender>
315+
<signal>toggled(bool)</signal>
316+
<receiver>radiusFieldCombo</receiver>
317+
<slot>setEnabled(bool)</slot>
318+
<hints>
319+
<hint type="sourcelabel">
320+
<x>108</x>
321+
<y>283</y>
322+
</hint>
323+
<hint type="destinationlabel">
324+
<x>294</x>
325+
<y>286</y>
326+
</hint>
327+
</hints>
328+
</connection>
329+
<connection>
330+
<sender>useRadius</sender>
331+
<signal>toggled(bool)</signal>
332+
<receiver>radiusFieldUnitCombo</receiver>
333+
<slot>setEnabled(bool)</slot>
334+
<hints>
335+
<hint type="sourcelabel">
336+
<x>108</x>
337+
<y>283</y>
338+
</hint>
339+
<hint type="destinationlabel">
340+
<x>408</x>
341+
<y>286</y>
342+
</hint>
343+
</hints>
344+
</connection>
345+
<connection>
346+
<sender>useRadius</sender>
347+
<signal>toggled(bool)</signal>
348+
<receiver>mBufferLineEdit</receiver>
349+
<slot>setDisabled(bool)</slot>
350+
<hints>
351+
<hint type="sourcelabel">
352+
<x>108</x>
353+
<y>283</y>
354+
</hint>
355+
<hint type="destinationlabel">
356+
<x>325</x>
357+
<y>131</y>
358+
</hint>
359+
</hints>
360+
</connection>
361+
<connection>
362+
<sender>useRadius</sender>
363+
<signal>toggled(bool)</signal>
364+
<receiver>mRadiusUnitCombo</receiver>
365+
<slot>setDisabled(bool)</slot>
366+
<hints>
367+
<hint type="sourcelabel">
368+
<x>108</x>
369+
<y>283</y>
370+
</hint>
371+
<hint type="destinationlabel">
372+
<x>420</x>
373+
<y>131</y>
374+
</hint>
375+
</hints>
376+
</connection>
377+
<connection>
378+
<sender>useRadius</sender>
379+
<signal>toggled(bool)</signal>
380+
<receiver>mRadiusLabel</receiver>
381+
<slot>setDisabled(bool)</slot>
382+
<hints>
383+
<hint type="sourcelabel">
384+
<x>83</x>
385+
<y>275</y>
386+
</hint>
387+
<hint type="destinationlabel">
388+
<x>58</x>
389+
<y>116</y>
390+
</hint>
391+
</hints>
392+
</connection>
143393
</connections>
144394
</ui>

0 commit comments

Comments
 (0)
Please sign in to comment.