Skip to content

Commit b567a6d

Browse files
committed
Refactor to avoid creating multiple QgsDistanceArea objects and recalculation of static or unused variables. Results in massive speed increase and fixes #6756, #6691 and #6692.
1 parent d628c2c commit b567a6d

File tree

2 files changed

+57
-30
lines changed

2 files changed

+57
-30
lines changed

src/plugins/heatmap/heatmap.cpp

Lines changed: 54 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -159,17 +159,35 @@ void Heatmap::run()
159159
QgsAttributeList myAttrList;
160160
int rField = 0;
161161
int wField = 0;
162+
163+
// Handle different radius options
164+
float radius;
165+
float radiusToMapUnits = 1;
166+
int myBuffer;
162167
if ( d.variableRadius() )
163168
{
164169
rField = d.radiusField();
165170
myAttrList.append( rField );
166171
QgsDebugMsg( QString( "Radius Field index received: %1" ).arg( rField ) );
172+
173+
// If not using map units, then calculate a conversion factor to convert the radii to map units
174+
if ( d.radiusUnit() == HeatmapGui::Meters )
175+
{
176+
radiusToMapUnits = mapUnitsOf( 1, inputLayer->crs() );
177+
}
178+
}
179+
else
180+
{
181+
radius = d.radius(); // radius returned by d.radius() is already in map units
182+
myBuffer = bufferSize( radius, cellsize );
167183
}
184+
168185
if ( d.weighted() )
169186
{
170187
wField = d.weightField();
171188
myAttrList.append( wField );
172189
}
190+
173191
// This might have attributes or mightnot have attibutes at all
174192
// based on the variableRadius() and weighted()
175193
QgsFeatureIterator fit = inputLayer->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( myAttrList ) );
@@ -201,26 +219,14 @@ void Heatmap::run()
201219
{
202220
continue;
203221
}
204-
float radius;
222+
223+
// If radius is variable then fetch it and calculate new pixel buffer size
205224
if ( d.variableRadius() )
206225
{
207-
radius = myFeature.attribute( rField ).toFloat();
208-
}
209-
else
210-
{
211-
radius = d.radius();
212-
}
213-
//convert the radius to map units if it is in meters
214-
if ( d.radiusUnit() == HeatmapGui::Meters )
215-
{
216-
radius = mapUnitsOf( radius, inputLayer->crs() );
217-
}
218-
// convert radius in map units to pixel count
219-
int myBuffer = radius / cellsize;
220-
if ( radius - ( cellsize * myBuffer ) > 0.5 )
221-
{
222-
++myBuffer;
226+
radius = myFeature.attribute( rField ).toFloat() * radiusToMapUnits;
227+
myBuffer = bufferSize( radius, cellsize );
223228
}
229+
224230
int blockSize = 2 * myBuffer + 1; //Block SIDE would be more appropriate
225231
// calculate the pixel position
226232
unsigned int xPosition, yPosition;
@@ -243,6 +249,13 @@ void Heatmap::run()
243249
for ( int yp = 0; yp <= myBuffer; yp++ )
244250
{
245251
float distance = sqrt( pow( xp, 2.0 ) + pow( yp, 2.0 ) );
252+
253+
// is pixel outside search bandwidth of feature?
254+
if ( distance > myBuffer )
255+
{
256+
continue;
257+
}
258+
246259
float pixelValue = weight * ( 1 - (( 1 - myDecay ) * distance / myBuffer ) );
247260

248261
// clearing anamolies along the axes
@@ -255,21 +268,18 @@ void Heatmap::run()
255268
pixelValue /= 2;
256269
}
257270

258-
if ( distance <= myBuffer )
271+
int pos[4];
272+
pos[0] = ( myBuffer + xp ) * blockSize + ( myBuffer + yp );
273+
pos[1] = ( myBuffer + xp ) * blockSize + ( myBuffer - yp );
274+
pos[2] = ( myBuffer - xp ) * blockSize + ( myBuffer + yp );
275+
pos[3] = ( myBuffer - xp ) * blockSize + ( myBuffer - yp );
276+
for ( int p = 0; p < 4; p++ )
259277
{
260-
int pos[4];
261-
pos[0] = ( myBuffer + xp ) * blockSize + ( myBuffer + yp );
262-
pos[1] = ( myBuffer + xp ) * blockSize + ( myBuffer - yp );
263-
pos[2] = ( myBuffer - xp ) * blockSize + ( myBuffer + yp );
264-
pos[3] = ( myBuffer - xp ) * blockSize + ( myBuffer - yp );
265-
for ( int p = 0; p < 4; p++ )
278+
if ( dataBuffer[ pos[p] ] == NO_DATA )
266279
{
267-
if ( dataBuffer[ pos[p] ] == NO_DATA )
268-
{
269-
dataBuffer[ pos[p] ] = 0;
270-
}
271-
dataBuffer[ pos[p] ] += pixelValue;
280+
dataBuffer[ pos[p] ] = 0;
272281
}
282+
dataBuffer[ pos[p] ] += pixelValue;
273283
}
274284
}
275285
}
@@ -278,7 +288,7 @@ void Heatmap::run()
278288
dataBuffer, blockSize, blockSize, GDT_Float32, 0, 0 );
279289
CPLFree( dataBuffer );
280290
}
281-
//Finally close the dataset
291+
// Finally close the dataset
282292
GDALClose(( GDALDatasetH ) heatmapDS );
283293

284294
// Open the file in QGIS window
@@ -291,6 +301,7 @@ void Heatmap::run()
291301
* Local functions
292302
*
293303
*/
304+
294305
float Heatmap::mapUnitsOf( float meters, QgsCoordinateReferenceSystem layerCrs )
295306
{
296307
// Worker to transform metres input to mapunits
@@ -304,6 +315,19 @@ float Heatmap::mapUnitsOf( float meters, QgsCoordinateReferenceSystem layerCrs )
304315
return meters / da.measureLine( QgsPoint( 0.0, 0.0 ), QgsPoint( 0.0, 1.0 ) );
305316
}
306317

318+
int Heatmap::bufferSize( float radius, float cellsize )
319+
{
320+
// Calculate the buffer size in pixels
321+
322+
int buffer = radius / cellsize;
323+
if ( radius - ( cellsize * buffer ) > 0.5 )
324+
{
325+
++buffer;
326+
}
327+
return buffer;
328+
}
329+
330+
307331
// Unload the plugin by cleaning up the GUI
308332
void Heatmap::unload()
309333
{

src/plugins/heatmap/heatmap.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ class Heatmap: public QObject, public QgisPlugin
8383
private:
8484
//! Worker to convert meters to map units
8585
float mapUnitsOf( float meters, QgsCoordinateReferenceSystem crs );
86+
//! Worker to calculate buffer size in pixels
87+
int bufferSize( float radius, float cellsize );
88+
8689
// MANDATORY PLUGIN PROPERTY DECLARATIONS .....
8790

8891
int mPluginType;

0 commit comments

Comments
 (0)