QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
qgsalgorithmfuzzifyraster.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsalgorithmrasterlayeruniquevalues.cpp
3 ---------------------
4 begin : October 2019
5 copyright : (C) 2019 by Clemens Raffler
6 email : clemens dot raffler at gmail dot com
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
19#include "qgsrasterfilewriter.h"
20#include "qgsstringutils.h"
21
23
24//
25// QgsFuzzifyRasterAlgorithmBase
26//
27
28QString QgsFuzzifyRasterAlgorithmBase::group() const
29{
30 return QObject::tr( "Raster analysis" );
31}
32
33QString QgsFuzzifyRasterAlgorithmBase::groupId() const
34{
35 return QStringLiteral( "rasteranalysis" );
36}
37
38void QgsFuzzifyRasterAlgorithmBase::initAlgorithm( const QVariantMap & )
39{
40 addParameter( new QgsProcessingParameterRasterLayer( QStringLiteral( "INPUT" ), QObject::tr( "Input Raster" ) ) );
41 addParameter( new QgsProcessingParameterBand( QStringLiteral( "BAND" ), QObject::tr( "Band Number" ), 1, QStringLiteral( "INPUT" ) ) );
42
43 //add specific fuzzification parameters from subclass alg
44 addAlgorithmParams();
45
46 addOutput( new QgsProcessingOutputString( QStringLiteral( "EXTENT" ), QObject::tr( "Extent" ) ) );
47 addOutput( new QgsProcessingOutputString( QStringLiteral( "CRS_AUTHID" ), QObject::tr( "CRS authority identifier" ) ) );
48 addOutput( new QgsProcessingOutputNumber( QStringLiteral( "WIDTH_IN_PIXELS" ), QObject::tr( "Width in pixels" ) ) );
49 addOutput( new QgsProcessingOutputNumber( QStringLiteral( "HEIGHT_IN_PIXELS" ), QObject::tr( "Height in pixels" ) ) );
50 addOutput( new QgsProcessingOutputNumber( QStringLiteral( "TOTAL_PIXEL_COUNT" ), QObject::tr( "Total pixel count" ) ) );
51
52 addParameter( new QgsProcessingParameterRasterDestination( QStringLiteral( "OUTPUT" ), QObject::tr( "Fuzzified raster" ) ) );
53}
54
55bool QgsFuzzifyRasterAlgorithmBase::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
56{
57 mInputRaster = parameterAsRasterLayer( parameters, QStringLiteral( "INPUT" ), context );
58
59 if ( !mInputRaster )
60 throw QgsProcessingException( invalidRasterError( parameters, QStringLiteral( "INPUT" ) ) );
61
62 mBand = parameterAsInt( parameters, QStringLiteral( "BAND" ), context );
63 if ( mBand < 1 || mBand > mInputRaster->bandCount() )
64 throw QgsProcessingException( QObject::tr( "Invalid band number for BAND (%1): Valid values for input raster are 1 to %2" ).arg( mBand ).arg( mInputRaster->bandCount() ) );
65
66 mInterface.reset( mInputRaster->dataProvider()->clone() );
67 mExtent = mInputRaster->extent();
68 mLayerWidth = mInputRaster->width();
69 mLayerHeight = mInputRaster->height();
70 mCrs = mInputRaster->crs();
71 mNbCellsXProvider = mInterface->xSize();
72 mNbCellsYProvider = mInterface->ySize();
73
74 //prepare fuzzifcation parameters from subclass alg
75 prepareAlgorithmFuzzificationParameters( parameters, context, feedback );
76
77 return true;
78}
79
80
81QVariantMap QgsFuzzifyRasterAlgorithmBase::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
82{
83 const QString outputFile = parameterAsOutputLayer( parameters, QStringLiteral( "OUTPUT" ), context );
84 const QFileInfo fi( outputFile );
85 const QString outputFormat = QgsRasterFileWriter::driverForExtension( fi.suffix() );
86
87 std::unique_ptr< QgsRasterFileWriter > writer = std::make_unique< QgsRasterFileWriter >( outputFile );
88 writer->setOutputProviderKey( QStringLiteral( "gdal" ) );
89 writer->setOutputFormat( outputFormat );
90 std::unique_ptr<QgsRasterDataProvider > provider( writer->createOneBandRaster( mDataType, mNbCellsXProvider, mNbCellsYProvider, mExtent, mCrs ) );
91 if ( !provider )
92 throw QgsProcessingException( QObject::tr( "Could not create raster output: %1" ).arg( outputFile ) );
93 if ( !provider->isValid() )
94 throw QgsProcessingException( QObject::tr( "Could not create raster output %1: %2" ).arg( outputFile, provider->error().message( QgsErrorMessage::Text ) ) );
95
96 provider->setNoDataValue( 1, mNoDataValue );
97 provider->setEditable( true );
98 const qgssize layerSize = static_cast< qgssize >( mLayerWidth ) * static_cast< qgssize >( mLayerHeight );
99
100 fuzzify( provider.get(), feedback );
101
102 provider->setEditable( false );
103
104 QVariantMap outputs;
105 outputs.insert( QStringLiteral( "EXTENT" ), mExtent.toString() );
106 outputs.insert( QStringLiteral( "CRS_AUTHID" ), mCrs.authid() );
107 outputs.insert( QStringLiteral( "WIDTH_IN_PIXELS" ), mLayerWidth );
108 outputs.insert( QStringLiteral( "HEIGHT_IN_PIXELS" ), mLayerHeight );
109 outputs.insert( QStringLiteral( "TOTAL_PIXEL_COUNT" ), layerSize );
110 outputs.insert( QStringLiteral( "OUTPUT" ), outputFile );
111 return outputs;
112}
113
114
115//
116// QgsFuzzfiyRasterLinearMembershipAlgorithm
117//
118
119QString QgsFuzzifyRasterLinearMembershipAlgorithm::name() const
120{
121 return QStringLiteral( "fuzzifyrasterlinearmembership" );
122}
123
124QString QgsFuzzifyRasterLinearMembershipAlgorithm::displayName() const
125{
126 return QObject::tr( "Fuzzify raster (linear membership)" );
127}
128
129QStringList QgsFuzzifyRasterLinearMembershipAlgorithm::tags() const
130{
131 return QObject::tr( "fuzzy logic,fuzzify,fuzzy,logic,linear,membership" ).split( ',' );
132}
133
134
135QString QgsFuzzifyRasterLinearMembershipAlgorithm::shortHelpString() const
136{
137 return QObject::tr( "The Fuzzify raster (linear membership) algorithm transforms an input raster "
138 "to a fuzzified raster and thereby assigns values between 0 and 1 following a "
139 "linear fuzzy membership function. The value of 0 implies no membership with the "
140 "defined fuzzy set, a value of 1 depicts full membership. In between, the degree "
141 "of membership of raster values follows a linear membership function.\n\n"
142 "The linear function is constructed using two user-defined input raster values "
143 "which set the point of full membership (high bound, results to 1) and no membership "
144 "(low bound, results to 0) respectively. The fuzzy set in between those values is defined as a "
145 "linear function.\n\n"
146 "Both increasing and decreasing fuzzy sets can be modeled by "
147 "swapping the high and low bound parameters." );
148}
149
150QgsFuzzifyRasterLinearMembershipAlgorithm *QgsFuzzifyRasterLinearMembershipAlgorithm::createInstance() const
151{
152 return new QgsFuzzifyRasterLinearMembershipAlgorithm();
153}
154
155void QgsFuzzifyRasterLinearMembershipAlgorithm::addAlgorithmParams( )
156{
157 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYLOWBOUND" ), QStringLiteral( "Low fuzzy membership bound" ), Qgis::ProcessingNumberParameterType::Double, 0 ) );
158 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYHIGHBOUND" ), QStringLiteral( "High fuzzy membership bound" ), Qgis::ProcessingNumberParameterType::Double, 1 ) );
159}
160
161bool QgsFuzzifyRasterLinearMembershipAlgorithm::prepareAlgorithmFuzzificationParameters( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
162{
163 Q_UNUSED( feedback )
164 mFuzzifyHighBound = parameterAsDouble( parameters, QStringLiteral( "FUZZYHIGHBOUND" ), context );
165 mFuzzifyLowBound = parameterAsDouble( parameters, QStringLiteral( "FUZZYLOWBOUND" ), context );
166 return true;
167}
168
169void QgsFuzzifyRasterLinearMembershipAlgorithm::fuzzify( QgsRasterDataProvider *destinationProvider, QgsProcessingFeedback *feedback )
170{
173 const int nbBlocksWidth = static_cast< int >( std::ceil( 1.0 * mLayerWidth / maxWidth ) );
174 const int nbBlocksHeight = static_cast< int >( std::ceil( 1.0 * mLayerHeight / maxHeight ) );
175 const int nbBlocks = nbBlocksWidth * nbBlocksHeight;
176
177 QgsRasterIterator iter( mInterface.get() );
178 iter.startRasterRead( mBand, mLayerWidth, mLayerHeight, mExtent );
179 int iterLeft = 0;
180 int iterTop = 0;
181 int iterCols = 0;
182 int iterRows = 0;
183 bool isNoData = false;
184 std::unique_ptr< QgsRasterBlock > rasterBlock;
185 while ( iter.readNextRasterPart( mBand, iterCols, iterRows, rasterBlock, iterLeft, iterTop ) )
186 {
187 if ( feedback )
188 feedback->setProgress( 100 * ( ( iterTop / maxHeight * nbBlocksWidth ) + iterLeft / maxWidth ) / nbBlocks );
189 std::unique_ptr< QgsRasterBlock > fuzzifiedBlock = std::make_unique< QgsRasterBlock >( destinationProvider->dataType( 1 ), iterCols, iterRows );
190
191 for ( int row = 0; row < iterRows; row++ )
192 {
193 if ( feedback && feedback->isCanceled() )
194 break;
195 for ( int column = 0; column < iterCols; column++ )
196 {
197 if ( feedback && feedback->isCanceled() )
198 break;
199
200 const double value = rasterBlock->valueAndNoData( row, column, isNoData );
201 double fuzzifiedValue;
202
203 if ( isNoData )
204 {
205 fuzzifiedValue = mNoDataValue;
206 }
207 else if ( mFuzzifyLowBound < mFuzzifyHighBound )
208 {
209 if ( value <= mFuzzifyLowBound )
210 fuzzifiedValue = 0;
211 else if ( value >= mFuzzifyHighBound )
212 fuzzifiedValue = 1;
213 else
214 fuzzifiedValue = ( ( value - mFuzzifyLowBound ) / ( mFuzzifyHighBound - mFuzzifyLowBound ) );
215 }
216 else if ( mFuzzifyLowBound > mFuzzifyHighBound )
217 {
218 if ( value >= mFuzzifyLowBound )
219 fuzzifiedValue = 0;
220 else if ( value <= mFuzzifyHighBound )
221 fuzzifiedValue = 1;
222 else
223 fuzzifiedValue = ( ( value - mFuzzifyLowBound ) / ( mFuzzifyHighBound - mFuzzifyLowBound ) );
224 }
225 else
226 {
227 throw QgsProcessingException( QObject::tr( "Please choose varying values for the high and low membership parameters" ) );
228 }
229
230 fuzzifiedBlock->setValue( row, column, fuzzifiedValue );
231 }
232 }
233 destinationProvider->writeBlock( fuzzifiedBlock.get(), mBand, iterLeft, iterTop );
234 }
235}
236
237
238//
239// QgsFuzzfiyRasterPowerMembershipAlgorithm
240//
241
242QString QgsFuzzifyRasterPowerMembershipAlgorithm::name() const
243{
244 return QStringLiteral( "fuzzifyrasterpowermembership" );
245}
246
247QString QgsFuzzifyRasterPowerMembershipAlgorithm::displayName() const
248{
249 return QObject::tr( "Fuzzify raster (power membership)" );
250}
251
252QStringList QgsFuzzifyRasterPowerMembershipAlgorithm::tags() const
253{
254 return QObject::tr( "fuzzy logic,fuzzify,fuzzy,logic,power,non-linear,membership,exponent" ).split( ',' );
255}
256
257
258QString QgsFuzzifyRasterPowerMembershipAlgorithm::shortHelpString() const
259{
260 return QObject::tr( "The Fuzzify raster (power membership) algorithm transforms an input raster "
261 "to a fuzzified raster and thereby assigns values between 0 and 1 following a "
262 "power function. The value of 0 implies no membership with the "
263 "defined fuzzy set, a value of 1 depicts full membership. In between, the degree "
264 "of membership of raster values follows a power function.\n\n"
265 "The power function is constructed using three user-defined input raster values "
266 "which set the point of full membership (high bound, results to 1), no membership "
267 "(low bound, results to 0) and function exponent (only positive) respectively. "
268 "The fuzzy set in between those the upper and lower bounds values is then defined as "
269 "a power function.\n\n"
270 "Both increasing and decreasing fuzzy sets can be modeled by "
271 "swapping the high and low bound parameters." );
272}
273
274QgsFuzzifyRasterPowerMembershipAlgorithm *QgsFuzzifyRasterPowerMembershipAlgorithm::createInstance() const
275{
276 return new QgsFuzzifyRasterPowerMembershipAlgorithm();
277}
278
279void QgsFuzzifyRasterPowerMembershipAlgorithm::addAlgorithmParams( )
280{
281 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYLOWBOUND" ), QStringLiteral( "Low fuzzy membership bound" ), Qgis::ProcessingNumberParameterType::Double, 0 ) );
282 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYHIGHBOUND" ), QStringLiteral( "High fuzzy membership bound" ), Qgis::ProcessingNumberParameterType::Double, 1 ) );
283 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYEXPONENT" ), QStringLiteral( "Membership function exponent" ), Qgis::ProcessingNumberParameterType::Double, 2, false, 0 ) );
284}
285
286bool QgsFuzzifyRasterPowerMembershipAlgorithm::prepareAlgorithmFuzzificationParameters( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
287{
288 Q_UNUSED( feedback )
289 mFuzzifyHighBound = parameterAsDouble( parameters, QStringLiteral( "FUZZYHIGHBOUND" ), context );
290 mFuzzifyLowBound = parameterAsDouble( parameters, QStringLiteral( "FUZZYLOWBOUND" ), context );
291 mFuzzifyExponent = parameterAsDouble( parameters, QStringLiteral( "FUZZYEXPONENT" ), context );
292 return true;
293}
294
295void QgsFuzzifyRasterPowerMembershipAlgorithm::fuzzify( QgsRasterDataProvider *destinationProvider, QgsProcessingFeedback *feedback )
296{
299 const int nbBlocksWidth = static_cast< int >( std::ceil( 1.0 * mLayerWidth / maxWidth ) );
300 const int nbBlocksHeight = static_cast< int >( std::ceil( 1.0 * mLayerHeight / maxHeight ) );
301 const int nbBlocks = nbBlocksWidth * nbBlocksHeight;
302
303 QgsRasterIterator iter( mInterface.get() );
304 iter.startRasterRead( mBand, mLayerWidth, mLayerHeight, mExtent );
305 int iterLeft = 0;
306 int iterTop = 0;
307 int iterCols = 0;
308 int iterRows = 0;
309 bool isNoData = false;
310 std::unique_ptr< QgsRasterBlock > rasterBlock;
311 while ( iter.readNextRasterPart( mBand, iterCols, iterRows, rasterBlock, iterLeft, iterTop ) )
312 {
313 if ( feedback )
314 feedback->setProgress( 100 * ( ( iterTop / maxHeight * nbBlocksWidth ) + iterLeft / maxWidth ) / nbBlocks );
315 std::unique_ptr< QgsRasterBlock > fuzzifiedBlock = std::make_unique< QgsRasterBlock >( destinationProvider->dataType( 1 ), iterCols, iterRows );
316
317 for ( int row = 0; row < iterRows; row++ )
318 {
319 if ( feedback && feedback->isCanceled() )
320 break;
321 for ( int column = 0; column < iterCols; column++ )
322 {
323 if ( feedback && feedback->isCanceled() )
324 break;
325
326 const double value = rasterBlock->valueAndNoData( row, column, isNoData );
327 double fuzzifiedValue;
328
329 if ( isNoData )
330 {
331 fuzzifiedValue = mNoDataValue;
332 }
333 else if ( mFuzzifyLowBound < mFuzzifyHighBound )
334 {
335 if ( value <= mFuzzifyLowBound )
336 fuzzifiedValue = 0;
337 else if ( value >= mFuzzifyHighBound )
338 fuzzifiedValue = 1;
339 else
340 fuzzifiedValue = std::pow( ( value - mFuzzifyLowBound ) / ( mFuzzifyHighBound - mFuzzifyLowBound ), mFuzzifyExponent );
341 }
342 else if ( mFuzzifyLowBound > mFuzzifyHighBound )
343 {
344 if ( value >= mFuzzifyLowBound )
345 fuzzifiedValue = 0;
346 else if ( value <= mFuzzifyHighBound )
347 fuzzifiedValue = 1;
348 else
349 fuzzifiedValue = std::pow( ( value - mFuzzifyLowBound ) / ( mFuzzifyHighBound - mFuzzifyLowBound ), mFuzzifyExponent );
350 }
351 else
352 {
353 throw QgsProcessingException( QObject::tr( "Please choose varying values for the high and low membership parameters" ) );
354 }
355
356 fuzzifiedBlock->setValue( row, column, fuzzifiedValue );
357 }
358 }
359 destinationProvider->writeBlock( fuzzifiedBlock.get(), mBand, iterLeft, iterTop );
360 }
361}
362
363//
364// QgsFuzzfiyRasterLargeMembershipAlgorithm
365//
366
367QString QgsFuzzifyRasterLargeMembershipAlgorithm::name() const
368{
369 return QStringLiteral( "fuzzifyrasterlargemembership" );
370}
371
372QString QgsFuzzifyRasterLargeMembershipAlgorithm::displayName() const
373{
374 return QObject::tr( "Fuzzify raster (large membership)" );
375}
376
377QStringList QgsFuzzifyRasterLargeMembershipAlgorithm::tags() const
378{
379 return QObject::tr( "fuzzy logic,fuzzify,fuzzy,logic,large,membership" ).split( ',' );
380}
381
382
383QString QgsFuzzifyRasterLargeMembershipAlgorithm::shortHelpString() const
384{
385 return QObject::tr( "The Fuzzify raster (large membership) algorithm transforms an input raster "
386 "to a fuzzified raster and thereby assigns values between 0 and 1 following the "
387 "'large' fuzzy membership function. The value of 0 implies no membership with the "
388 "defined fuzzy set, a value of 1 depicts full membership. In between, the degree "
389 "of membership of raster values follows the 'large' membership function.\n\n"
390 "The 'large' function is constructed using two user-defined input raster values "
391 "which set the point of half membership (midpoint, results to 0.5) and a predefined "
392 "function spread which controls the function uptake.\n\n"
393 "This function is typically used when larger input raster values should become members "
394 "of the fuzzy set more easily than smaller values." );
395}
396
397QgsFuzzifyRasterLargeMembershipAlgorithm *QgsFuzzifyRasterLargeMembershipAlgorithm::createInstance() const
398{
399 return new QgsFuzzifyRasterLargeMembershipAlgorithm();
400}
401
402void QgsFuzzifyRasterLargeMembershipAlgorithm::addAlgorithmParams( )
403{
404 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYMIDPOINT" ), QStringLiteral( "Function midpoint" ), Qgis::ProcessingNumberParameterType::Double, 50 ) );
405 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYSPREAD" ), QStringLiteral( "Function spread" ), Qgis::ProcessingNumberParameterType::Double, 5 ) );
406}
407
408bool QgsFuzzifyRasterLargeMembershipAlgorithm::prepareAlgorithmFuzzificationParameters( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
409{
410 Q_UNUSED( feedback )
411 mFuzzifyMidpoint = parameterAsDouble( parameters, QStringLiteral( "FUZZYMIDPOINT" ), context );
412 mFuzzifySpread = parameterAsDouble( parameters, QStringLiteral( "FUZZYSPREAD" ), context );
413 return true;
414}
415
416void QgsFuzzifyRasterLargeMembershipAlgorithm::fuzzify( QgsRasterDataProvider *destinationProvider, QgsProcessingFeedback *feedback )
417{
420 const int nbBlocksWidth = static_cast< int >( std::ceil( 1.0 * mLayerWidth / maxWidth ) );
421 const int nbBlocksHeight = static_cast< int >( std::ceil( 1.0 * mLayerHeight / maxHeight ) );
422 const int nbBlocks = nbBlocksWidth * nbBlocksHeight;
423
424 QgsRasterIterator iter( mInterface.get() );
425 iter.startRasterRead( mBand, mLayerWidth, mLayerHeight, mExtent );
426 int iterLeft = 0;
427 int iterTop = 0;
428 int iterCols = 0;
429 int iterRows = 0;
430 bool isNoData = false;
431 std::unique_ptr< QgsRasterBlock > rasterBlock;
432 while ( iter.readNextRasterPart( mBand, iterCols, iterRows, rasterBlock, iterLeft, iterTop ) )
433 {
434 if ( feedback )
435 feedback->setProgress( 100 * ( ( iterTop / maxHeight * nbBlocksWidth ) + iterLeft / maxWidth ) / nbBlocks );
436 std::unique_ptr< QgsRasterBlock > fuzzifiedBlock = std::make_unique< QgsRasterBlock >( destinationProvider->dataType( 1 ), iterCols, iterRows );
437
438 for ( int row = 0; row < iterRows; row++ )
439 {
440 if ( feedback && feedback->isCanceled() )
441 break;
442 for ( int column = 0; column < iterCols; column++ )
443 {
444 if ( feedback && feedback->isCanceled() )
445 break;
446
447 const double value = rasterBlock->valueAndNoData( row, column, isNoData );
448 double fuzzifiedValue;
449
450 if ( isNoData )
451 {
452 fuzzifiedValue = mNoDataValue;
453 }
454 else
455 {
456 fuzzifiedValue = 1 / ( 1 + std::pow( value / mFuzzifyMidpoint, -mFuzzifySpread ) );
457 }
458
459 fuzzifiedBlock->setValue( row, column, fuzzifiedValue );
460 }
461 }
462 destinationProvider->writeBlock( fuzzifiedBlock.get(), mBand, iterLeft, iterTop );
463 }
464}
465
466
467//
468// QgsFuzzfiyRasterSmallMembershipAlgorithm
469//
470
471QString QgsFuzzifyRasterSmallMembershipAlgorithm::name() const
472{
473 return QStringLiteral( "fuzzifyrastersmallmembership" );
474}
475
476QString QgsFuzzifyRasterSmallMembershipAlgorithm::displayName() const
477{
478 return QObject::tr( "Fuzzify raster (small membership)" );
479}
480
481QStringList QgsFuzzifyRasterSmallMembershipAlgorithm::tags() const
482{
483 return QObject::tr( "fuzzy logic,fuzzify,fuzzy,logic,small,membership" ).split( ',' );
484}
485
486
487QString QgsFuzzifyRasterSmallMembershipAlgorithm::shortHelpString() const
488{
489 return QObject::tr( "The Fuzzify raster (small membership) algorithm transforms an input raster "
490 "to a fuzzified raster and thereby assigns values between 0 and 1 following the "
491 "'small' fuzzy membership function. The value of 0 implies no membership with the "
492 "defined fuzzy set, a value of 1 depicts full membership. In between, the degree "
493 "of membership of raster values follows the 'small' membership function.\n\n"
494 "The 'small' function is constructed using two user-defined input raster values "
495 "which set the point of half membership (midpoint, results to 0.5) and a predefined "
496 "function spread which controls the function uptake.\n\n"
497 "This function is typically used when smaller input raster values should become members "
498 "of the fuzzy set more easily than higher values." );
499}
500
501QgsFuzzifyRasterSmallMembershipAlgorithm *QgsFuzzifyRasterSmallMembershipAlgorithm::createInstance() const
502{
503 return new QgsFuzzifyRasterSmallMembershipAlgorithm();
504}
505
506void QgsFuzzifyRasterSmallMembershipAlgorithm::addAlgorithmParams( )
507{
508 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYMIDPOINT" ), QStringLiteral( "Function midpoint" ), Qgis::ProcessingNumberParameterType::Double, 50 ) );
509 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYSPREAD" ), QStringLiteral( "Function spread" ), Qgis::ProcessingNumberParameterType::Double, 5 ) );
510}
511
512bool QgsFuzzifyRasterSmallMembershipAlgorithm::prepareAlgorithmFuzzificationParameters( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
513{
514 Q_UNUSED( feedback )
515 mFuzzifyMidpoint = parameterAsDouble( parameters, QStringLiteral( "FUZZYMIDPOINT" ), context );
516 mFuzzifySpread = parameterAsDouble( parameters, QStringLiteral( "FUZZYSPREAD" ), context );
517 return true;
518}
519
520void QgsFuzzifyRasterSmallMembershipAlgorithm::fuzzify( QgsRasterDataProvider *destinationProvider, QgsProcessingFeedback *feedback )
521{
524 const int nbBlocksWidth = static_cast< int >( std::ceil( 1.0 * mLayerWidth / maxWidth ) );
525 const int nbBlocksHeight = static_cast< int >( std::ceil( 1.0 * mLayerHeight / maxHeight ) );
526 const int nbBlocks = nbBlocksWidth * nbBlocksHeight;
527
528 QgsRasterIterator iter( mInterface.get() );
529 iter.startRasterRead( mBand, mLayerWidth, mLayerHeight, mExtent );
530 int iterLeft = 0;
531 int iterTop = 0;
532 int iterCols = 0;
533 int iterRows = 0;
534 bool isNoData = false;
535 std::unique_ptr< QgsRasterBlock > rasterBlock;
536 while ( iter.readNextRasterPart( mBand, iterCols, iterRows, rasterBlock, iterLeft, iterTop ) )
537 {
538 if ( feedback )
539 feedback->setProgress( 100 * ( ( iterTop / maxHeight * nbBlocksWidth ) + iterLeft / maxWidth ) / nbBlocks );
540 std::unique_ptr< QgsRasterBlock > fuzzifiedBlock = std::make_unique< QgsRasterBlock >( destinationProvider->dataType( 1 ), iterCols, iterRows );
541
542 for ( int row = 0; row < iterRows; row++ )
543 {
544 if ( feedback && feedback->isCanceled() )
545 break;
546 for ( int column = 0; column < iterCols; column++ )
547 {
548 if ( feedback && feedback->isCanceled() )
549 break;
550
551 const double value = rasterBlock->valueAndNoData( row, column, isNoData );
552 double fuzzifiedValue;
553
554 if ( isNoData )
555 {
556 fuzzifiedValue = mNoDataValue;
557 }
558 else
559 {
560 fuzzifiedValue = 1 / ( 1 + std::pow( value / mFuzzifyMidpoint, mFuzzifySpread ) );
561 }
562
563 fuzzifiedBlock->setValue( row, column, fuzzifiedValue );
564 }
565 }
566 destinationProvider->writeBlock( fuzzifiedBlock.get(), mBand, iterLeft, iterTop );
567 }
568}
569
570
571//
572// QgsFuzzfiyRasterGaussianMembershipAlgorithm
573//
574
575QString QgsFuzzifyRasterGaussianMembershipAlgorithm::name() const
576{
577 return QStringLiteral( "fuzzifyrastergaussianmembership" );
578}
579
580QString QgsFuzzifyRasterGaussianMembershipAlgorithm::displayName() const
581{
582 return QObject::tr( "Fuzzify raster (gaussian membership)" );
583}
584
585QStringList QgsFuzzifyRasterGaussianMembershipAlgorithm::tags() const
586{
587 return QObject::tr( "fuzzy logic,fuzzify,fuzzy,logic,gaussian,membership" ).split( ',' );
588}
589
590
591QString QgsFuzzifyRasterGaussianMembershipAlgorithm::shortHelpString() const
592{
593 return QObject::tr( "The Fuzzify raster (gaussian membership) algorithm transforms an input raster "
594 "to a fuzzified raster and thereby assigns values between 0 and 1 following a "
595 "gaussian fuzzy membership function. The value of 0 implies no membership with the "
596 "defined fuzzy set, a value of 1 depicts full membership. In between, the degree "
597 "of membership of raster values follows a gaussian membership function.\n\n"
598 "The gaussian function is constructed using two user-defined input values "
599 "which set the midpoint of the gaussian function (midpoint, results to 1) and a "
600 "predefined function spread which controls the function spread.\n\n"
601 "This function is typically used when a certain range of raster values around a "
602 "predefined function midpoint should become members of the fuzzy set." );
603}
604
605QgsFuzzifyRasterGaussianMembershipAlgorithm *QgsFuzzifyRasterGaussianMembershipAlgorithm::createInstance() const
606{
607 return new QgsFuzzifyRasterGaussianMembershipAlgorithm();
608}
609
610void QgsFuzzifyRasterGaussianMembershipAlgorithm::addAlgorithmParams( )
611{
612 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYMIDPOINT" ), QStringLiteral( "Function midpoint" ), Qgis::ProcessingNumberParameterType::Double, 10 ) );
613 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYSPREAD" ), QStringLiteral( "Function spread" ), Qgis::ProcessingNumberParameterType::Double, 0.01 ) );
614}
615
616bool QgsFuzzifyRasterGaussianMembershipAlgorithm::prepareAlgorithmFuzzificationParameters( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
617{
618 Q_UNUSED( feedback )
619 mFuzzifyMidpoint = parameterAsDouble( parameters, QStringLiteral( "FUZZYMIDPOINT" ), context );
620 mFuzzifySpread = parameterAsDouble( parameters, QStringLiteral( "FUZZYSPREAD" ), context );
621 return true;
622}
623
624void QgsFuzzifyRasterGaussianMembershipAlgorithm::fuzzify( QgsRasterDataProvider *destinationProvider, QgsProcessingFeedback *feedback )
625{
628 const int nbBlocksWidth = static_cast< int >( std::ceil( 1.0 * mLayerWidth / maxWidth ) );
629 const int nbBlocksHeight = static_cast< int >( std::ceil( 1.0 * mLayerHeight / maxHeight ) );
630 const int nbBlocks = nbBlocksWidth * nbBlocksHeight;
631
632 QgsRasterIterator iter( mInterface.get() );
633 iter.startRasterRead( mBand, mLayerWidth, mLayerHeight, mExtent );
634 int iterLeft = 0;
635 int iterTop = 0;
636 int iterCols = 0;
637 int iterRows = 0;
638 bool isNoData = false;
639 std::unique_ptr< QgsRasterBlock > rasterBlock;
640 while ( iter.readNextRasterPart( mBand, iterCols, iterRows, rasterBlock, iterLeft, iterTop ) )
641 {
642 if ( feedback )
643 feedback->setProgress( 100 * ( ( iterTop / maxHeight * nbBlocksWidth ) + iterLeft / maxWidth ) / nbBlocks );
644 std::unique_ptr< QgsRasterBlock > fuzzifiedBlock = std::make_unique< QgsRasterBlock >( destinationProvider->dataType( 1 ), iterCols, iterRows );
645
646 for ( int row = 0; row < iterRows; row++ )
647 {
648 if ( feedback && feedback->isCanceled() )
649 break;
650 for ( int column = 0; column < iterCols; column++ )
651 {
652 if ( feedback && feedback->isCanceled() )
653 break;
654
655 const double value = rasterBlock->valueAndNoData( row, column, isNoData );
656 double fuzzifiedValue;
657
658 if ( isNoData )
659 {
660 fuzzifiedValue = mNoDataValue;
661 }
662 else
663 {
664 fuzzifiedValue = std::exp( -mFuzzifySpread * std::pow( value - mFuzzifyMidpoint, 2 ) );
665 }
666
667 fuzzifiedBlock->setValue( row, column, fuzzifiedValue );
668 }
669 }
670 destinationProvider->writeBlock( fuzzifiedBlock.get(), mBand, iterLeft, iterTop );
671 }
672}
673
674
675//
676// QgsFuzzfiyRasterNearMembershipAlgorithm
677//
678
679QString QgsFuzzifyRasterNearMembershipAlgorithm::name() const
680{
681 return QStringLiteral( "fuzzifyrasternearmembership" );
682}
683
684QString QgsFuzzifyRasterNearMembershipAlgorithm::displayName() const
685{
686 return QObject::tr( "Fuzzify raster (near membership)" );
687}
688
689QStringList QgsFuzzifyRasterNearMembershipAlgorithm::tags() const
690{
691 return QObject::tr( "fuzzy logic,fuzzify,fuzzy,logic,near,membership" ).split( ',' );
692}
693
694
695QString QgsFuzzifyRasterNearMembershipAlgorithm::shortHelpString() const
696{
697 return QObject::tr( "The Fuzzify raster (near membership) algorithm transforms an input raster "
698 "to a fuzzified raster and thereby assigns values between 0 and 1 following the "
699 "'near' fuzzy membership function. The value of 0 implies no membership with the "
700 "defined fuzzy set, a value of 1 depicts full membership. In between, the degree "
701 "of membership of raster values follows the 'near' membership function.\n\n"
702 "The 'near' function is constructed using two user-defined input values "
703 "which set the midpoint of the 'near' function (midpoint, results to 1) and a "
704 "predefined function spread which controls the function spread.\n\n"
705 "This function is typically used when a certain range of raster values near a "
706 "predefined function midpoint should become members of the fuzzy set. The function"
707 " generally shows a higher rate of decay than the gaussian membership function." );
708}
709
710QgsFuzzifyRasterNearMembershipAlgorithm *QgsFuzzifyRasterNearMembershipAlgorithm::createInstance() const
711{
712 return new QgsFuzzifyRasterNearMembershipAlgorithm();
713}
714
715void QgsFuzzifyRasterNearMembershipAlgorithm::addAlgorithmParams( )
716{
717 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYMIDPOINT" ), QStringLiteral( "Function midpoint" ), Qgis::ProcessingNumberParameterType::Double, 50 ) );
718 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYSPREAD" ), QStringLiteral( "Function spread" ), Qgis::ProcessingNumberParameterType::Double, 0.01 ) );
719}
720
721bool QgsFuzzifyRasterNearMembershipAlgorithm::prepareAlgorithmFuzzificationParameters( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
722{
723 Q_UNUSED( feedback )
724 mFuzzifyMidpoint = parameterAsDouble( parameters, QStringLiteral( "FUZZYMIDPOINT" ), context );
725 mFuzzifySpread = parameterAsDouble( parameters, QStringLiteral( "FUZZYSPREAD" ), context );
726 return true;
727}
728
729void QgsFuzzifyRasterNearMembershipAlgorithm::fuzzify( QgsRasterDataProvider *destinationProvider, QgsProcessingFeedback *feedback )
730{
733 const int nbBlocksWidth = static_cast< int >( std::ceil( 1.0 * mLayerWidth / maxWidth ) );
734 const int nbBlocksHeight = static_cast< int >( std::ceil( 1.0 * mLayerHeight / maxHeight ) );
735 const int nbBlocks = nbBlocksWidth * nbBlocksHeight;
736
737 QgsRasterIterator iter( mInterface.get() );
738 iter.startRasterRead( mBand, mLayerWidth, mLayerHeight, mExtent );
739 int iterLeft = 0;
740 int iterTop = 0;
741 int iterCols = 0;
742 int iterRows = 0;
743 bool isNoData = false;
744 std::unique_ptr< QgsRasterBlock > rasterBlock;
745 while ( iter.readNextRasterPart( mBand, iterCols, iterRows, rasterBlock, iterLeft, iterTop ) )
746 {
747 if ( feedback )
748 feedback->setProgress( 100 * ( ( iterTop / maxHeight * nbBlocksWidth ) + iterLeft / maxWidth ) / nbBlocks );
749 std::unique_ptr< QgsRasterBlock > fuzzifiedBlock = std::make_unique< QgsRasterBlock >( destinationProvider->dataType( 1 ), iterCols, iterRows );
750
751 for ( int row = 0; row < iterRows; row++ )
752 {
753 if ( feedback && feedback->isCanceled() )
754 break;
755 for ( int column = 0; column < iterCols; column++ )
756 {
757 if ( feedback && feedback->isCanceled() )
758 break;
759
760 const double value = rasterBlock->valueAndNoData( row, column, isNoData );
761 double fuzzifiedValue;
762
763 if ( isNoData )
764 {
765 fuzzifiedValue = mNoDataValue;
766 }
767 else
768 {
769 fuzzifiedValue = 1 / ( 1 + mFuzzifySpread * std::pow( value - mFuzzifyMidpoint, 2 ) );
770 }
771
772 fuzzifiedBlock->setValue( row, column, fuzzifiedValue );
773 }
774 }
775 destinationProvider->writeBlock( fuzzifiedBlock.get(), mBand, iterLeft, iterTop );
776 }
777}
778
779
781
782
783
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:53
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition: qgsfeedback.h:61
Contains information about the context in which a processing algorithm is executed.
Custom exception class for processing related exceptions.
Definition: qgsexception.h:83
Base class for providing feedback from a processing algorithm.
A numeric output for processing algorithms.
A string output for processing algorithms.
A raster band parameter for Processing algorithms.
A numeric parameter for processing algorithms.
A raster layer destination parameter, for specifying the destination path for a raster layer created ...
A raster layer parameter for processing algorithms.
Base class for raster data providers.
bool writeBlock(QgsRasterBlock *block, int band, int xOffset=0, int yOffset=0)
Writes pixel data from a raster block into the provider data source.
Qgis::DataType dataType(int bandNo) const override=0
Returns data type for the band specified by number.
static QString driverForExtension(const QString &extension)
Returns the GDAL driver name for a specified file extension.
Iterator for sequentially processing raster cells.
static const int DEFAULT_MAXIMUM_TILE_WIDTH
Default maximum tile width.
static const int DEFAULT_MAXIMUM_TILE_HEIGHT
Default maximum tile height.
unsigned long long qgssize
Qgssize is used instead of size_t, because size_t is stdlib type, unknown by SIP, and it would be har...
Definition: qgis.h:5747