@@ -107,8 +107,11 @@ void Heatmap::run()
107
107
QgsRectangle myBBox = d.bbox ();
108
108
int columns = d.columns ();
109
109
int rows = d.rows ();
110
- float cellsize = d.cellSizeX (); // or d.cellSizeY(); both have the same value
111
- float myDecay = d.decayRatio ();
110
+ double cellsize = d.cellSizeX (); // or d.cellSizeY(); both have the same value
111
+ double myDecay = d.decayRatio ();
112
+
113
+ // Start working on the input vector
114
+ QgsVectorLayer* inputLayer = d.inputVectorLayer ();
112
115
113
116
// Getting the rasterdataset in place
114
117
GDALAllRegister ();
@@ -126,6 +129,8 @@ void Heatmap::run()
126
129
double geoTransform[6 ] = { myBBox.xMinimum (), cellsize, 0 , myBBox.yMinimum (), 0 , cellsize };
127
130
emptyDataset = myDriver->Create ( d.outputFilename ().toUtf8 (), columns, rows, 1 , GDT_Float32, NULL );
128
131
emptyDataset->SetGeoTransform ( geoTransform );
132
+ // Set the projection on the raster destination to match the input layer
133
+ emptyDataset->SetProjection ( inputLayer->crs ().toWkt ().toLocal8Bit ().data () );
129
134
130
135
GDALRasterBand *poBand;
131
136
poBand = emptyDataset->GetRasterBand ( 1 );
@@ -153,23 +158,39 @@ void Heatmap::run()
153
158
return ;
154
159
}
155
160
poBand = heatmapDS->GetRasterBand ( 1 );
156
- // Start working on the input vector
157
- QgsVectorLayer* inputLayer = d.inputVectorLayer ();
158
161
159
162
QgsAttributeList myAttrList;
160
163
int rField = 0 ;
161
164
int wField = 0 ;
165
+
166
+ // Handle different radius options
167
+ double radius;
168
+ double radiusToMapUnits = 1 ;
169
+ int myBuffer;
162
170
if ( d.variableRadius () )
163
171
{
164
172
rField = d.radiusField ();
165
173
myAttrList.append ( rField );
166
174
QgsDebugMsg ( QString ( " Radius Field index received: %1" ).arg ( rField ) );
175
+
176
+ // If not using map units, then calculate a conversion factor to convert the radii to map units
177
+ if ( d.radiusUnit () == HeatmapGui::Meters )
178
+ {
179
+ radiusToMapUnits = mapUnitsOf ( 1 , inputLayer->crs () );
180
+ }
181
+ }
182
+ else
183
+ {
184
+ radius = d.radius (); // radius returned by d.radius() is already in map units
185
+ myBuffer = bufferSize ( radius, cellsize );
167
186
}
187
+
168
188
if ( d.weighted () )
169
189
{
170
190
wField = d.weightField ();
171
191
myAttrList.append ( wField );
172
192
}
193
+
173
194
// This might have attributes or mightnot have attibutes at all
174
195
// based on the variableRadius() and weighted()
175
196
QgsFeatureIterator fit = inputLayer->getFeatures ( QgsFeatureRequest ().setSubsetOfAttributes ( myAttrList ) );
@@ -201,26 +222,14 @@ void Heatmap::run()
201
222
{
202
223
continue ;
203
224
}
204
- float radius;
225
+
226
+ // If radius is variable then fetch it and calculate new pixel buffer size
205
227
if ( d.variableRadius () )
206
228
{
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;
229
+ radius = myFeature.attribute ( rField ).toDouble () * radiusToMapUnits;
230
+ myBuffer = bufferSize ( radius, cellsize );
223
231
}
232
+
224
233
int blockSize = 2 * myBuffer + 1 ; // Block SIDE would be more appropriate
225
234
// calculate the pixel position
226
235
unsigned int xPosition, yPosition;
@@ -232,18 +241,25 @@ void Heatmap::run()
232
241
poBand->RasterIO ( GF_Read, xPosition, yPosition, blockSize, blockSize,
233
242
dataBuffer, blockSize, blockSize, GDT_Float32, 0 , 0 );
234
243
235
- float weight = 1.0 ;
244
+ double weight = 1.0 ;
236
245
if ( d.weighted () )
237
246
{
238
- weight = myFeature.attribute ( wField ).toFloat ();
247
+ weight = myFeature.attribute ( wField ).toDouble ();
239
248
}
240
249
241
250
for ( int xp = 0 ; xp <= myBuffer; xp++ )
242
251
{
243
252
for ( int yp = 0 ; yp <= myBuffer; yp++ )
244
253
{
245
- float distance = sqrt ( pow ( xp, 2.0 ) + pow ( yp, 2.0 ) );
246
- float pixelValue = weight * ( 1 - (( 1 - myDecay ) * distance / myBuffer ) );
254
+ double distance = sqrt ( pow ( xp, 2.0 ) + pow ( yp, 2.0 ) );
255
+
256
+ // is pixel outside search bandwidth of feature?
257
+ if ( distance > myBuffer )
258
+ {
259
+ continue ;
260
+ }
261
+
262
+ double pixelValue = weight * ( 1 - (( 1 - myDecay ) * distance / myBuffer ) );
247
263
248
264
// clearing anamolies along the axes
249
265
if ( xp == 0 && yp == 0 )
@@ -255,21 +271,18 @@ void Heatmap::run()
255
271
pixelValue /= 2 ;
256
272
}
257
273
258
- if ( distance <= myBuffer )
274
+ int pos[4 ];
275
+ pos[0 ] = ( myBuffer + xp ) * blockSize + ( myBuffer + yp );
276
+ pos[1 ] = ( myBuffer + xp ) * blockSize + ( myBuffer - yp );
277
+ pos[2 ] = ( myBuffer - xp ) * blockSize + ( myBuffer + yp );
278
+ pos[3 ] = ( myBuffer - xp ) * blockSize + ( myBuffer - yp );
279
+ for ( int p = 0 ; p < 4 ; p++ )
259
280
{
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++ )
281
+ if ( dataBuffer[ pos[p] ] == NO_DATA )
266
282
{
267
- if ( dataBuffer[ pos[p] ] == NO_DATA )
268
- {
269
- dataBuffer[ pos[p] ] = 0 ;
270
- }
271
- dataBuffer[ pos[p] ] += pixelValue;
283
+ dataBuffer[ pos[p] ] = 0 ;
272
284
}
285
+ dataBuffer[ pos[p] ] += pixelValue;
273
286
}
274
287
}
275
288
}
@@ -278,7 +291,7 @@ void Heatmap::run()
278
291
dataBuffer, blockSize, blockSize, GDT_Float32, 0 , 0 );
279
292
CPLFree ( dataBuffer );
280
293
}
281
- // Finally close the dataset
294
+ // Finally close the dataset
282
295
GDALClose (( GDALDatasetH ) heatmapDS );
283
296
284
297
// Open the file in QGIS window
@@ -291,7 +304,8 @@ void Heatmap::run()
291
304
* Local functions
292
305
*
293
306
*/
294
- float Heatmap::mapUnitsOf ( float meters, QgsCoordinateReferenceSystem layerCrs )
307
+
308
+ double Heatmap::mapUnitsOf ( double meters, QgsCoordinateReferenceSystem layerCrs )
295
309
{
296
310
// Worker to transform metres input to mapunits
297
311
QgsDistanceArea da;
@@ -304,6 +318,19 @@ float Heatmap::mapUnitsOf( float meters, QgsCoordinateReferenceSystem layerCrs )
304
318
return meters / da.measureLine ( QgsPoint ( 0.0 , 0.0 ), QgsPoint ( 0.0 , 1.0 ) );
305
319
}
306
320
321
+ int Heatmap::bufferSize ( double radius, double cellsize )
322
+ {
323
+ // Calculate the buffer size in pixels
324
+
325
+ int buffer = radius / cellsize;
326
+ if ( radius - ( cellsize * buffer ) > 0.5 )
327
+ {
328
+ ++buffer;
329
+ }
330
+ return buffer;
331
+ }
332
+
333
+
307
334
// Unload the plugin by cleaning up the GUI
308
335
void Heatmap::unload ()
309
336
{
0 commit comments