QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
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 mDestinationRasterProvider = provider.get();
98 mDestinationRasterProvider->setEditable( true );
99 const qgssize layerSize = static_cast< qgssize >( mLayerWidth ) * static_cast< qgssize >( mLayerHeight );
100
101 fuzzify( feedback );
102
103 QVariantMap outputs;
104 outputs.insert( QStringLiteral( "EXTENT" ), mExtent.toString() );
105 outputs.insert( QStringLiteral( "CRS_AUTHID" ), mCrs.authid() );
106 outputs.insert( QStringLiteral( "WIDTH_IN_PIXELS" ), mLayerWidth );
107 outputs.insert( QStringLiteral( "HEIGHT_IN_PIXELS" ), mLayerHeight );
108 outputs.insert( QStringLiteral( "TOTAL_PIXEL_COUNT" ), layerSize );
109 outputs.insert( QStringLiteral( "OUTPUT" ), outputFile );
110 return outputs;
111}
112
113
114//
115// QgsFuzzfiyRasterLinearMembershipAlgorithm
116//
117
118QString QgsFuzzifyRasterLinearMembershipAlgorithm::name() const
119{
120 return QStringLiteral( "fuzzifyrasterlinearmembership" );
121}
122
123QString QgsFuzzifyRasterLinearMembershipAlgorithm::displayName() const
124{
125 return QObject::tr( "Fuzzify raster (linear membership)" );
126}
127
128QStringList QgsFuzzifyRasterLinearMembershipAlgorithm::tags() const
129{
130 return QObject::tr( "fuzzy logic,fuzzify,fuzzy,logic,linear,membership" ).split( ',' );
131}
132
133
134QString QgsFuzzifyRasterLinearMembershipAlgorithm::shortHelpString() const
135{
136 return QObject::tr( "The Fuzzify raster (linear membership) algorithm transforms an input raster "
137 "to a fuzzified raster and thereby assigns values between 0 and 1 following a "
138 "linear fuzzy membership function. The value of 0 implies no membership with the "
139 "defined fuzzy set, a value of 1 depicts full membership. In between, the degree "
140 "of membership of raster values follows a linear membership function.\n\n"
141 "The linear function is constructed using two user-defined input raster values "
142 "which set the point of full membership (high bound, results to 1) and no membership "
143 "(low bound, results to 0) respectively. The fuzzy set in between those values is defined as a "
144 "linear function.\n\n"
145 "Both increasing and decreasing fuzzy sets can be modeled by "
146 "swapping the high and low bound parameters." );
147}
148
149QgsFuzzifyRasterLinearMembershipAlgorithm *QgsFuzzifyRasterLinearMembershipAlgorithm::createInstance() const
150{
151 return new QgsFuzzifyRasterLinearMembershipAlgorithm();
152}
153
154void QgsFuzzifyRasterLinearMembershipAlgorithm::addAlgorithmParams( )
155{
156 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYLOWBOUND" ), QStringLiteral( "Low fuzzy membership bound" ), QgsProcessingParameterNumber::Double, 0 ) );
157 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYHIGHBOUND" ), QStringLiteral( "High fuzzy membership bound" ), QgsProcessingParameterNumber::Double, 1 ) );
158}
159
160bool QgsFuzzifyRasterLinearMembershipAlgorithm::prepareAlgorithmFuzzificationParameters( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
161{
162 Q_UNUSED( feedback )
163 mFuzzifyHighBound = parameterAsDouble( parameters, QStringLiteral( "FUZZYHIGHBOUND" ), context );
164 mFuzzifyLowBound = parameterAsDouble( parameters, QStringLiteral( "FUZZYLOWBOUND" ), context );
165 return true;
166}
167
168void QgsFuzzifyRasterLinearMembershipAlgorithm::fuzzify( QgsProcessingFeedback *feedback )
169{
172 const int nbBlocksWidth = static_cast< int >( std::ceil( 1.0 * mLayerWidth / maxWidth ) );
173 const int nbBlocksHeight = static_cast< int >( std::ceil( 1.0 * mLayerHeight / maxHeight ) );
174 const int nbBlocks = nbBlocksWidth * nbBlocksHeight;
175
176 QgsRasterIterator iter( mInterface.get() );
177 iter.startRasterRead( mBand, mLayerWidth, mLayerHeight, mExtent );
178 int iterLeft = 0;
179 int iterTop = 0;
180 int iterCols = 0;
181 int iterRows = 0;
182 bool isNoData = false;
183 std::unique_ptr< QgsRasterBlock > rasterBlock;
184 while ( iter.readNextRasterPart( mBand, iterCols, iterRows, rasterBlock, iterLeft, iterTop ) )
185 {
186 if ( feedback )
187 feedback->setProgress( 100 * ( ( iterTop / maxHeight * nbBlocksWidth ) + iterLeft / maxWidth ) / nbBlocks );
188 std::unique_ptr< QgsRasterBlock > fuzzifiedBlock = std::make_unique< QgsRasterBlock >( mDestinationRasterProvider->dataType( 1 ), iterCols, iterRows );
189
190 for ( int row = 0; row < iterRows; row++ )
191 {
192 if ( feedback && feedback->isCanceled() )
193 break;
194 for ( int column = 0; column < iterCols; column++ )
195 {
196 if ( feedback && feedback->isCanceled() )
197 break;
198
199 const double value = rasterBlock->valueAndNoData( row, column, isNoData );
200 double fuzzifiedValue;
201
202 if ( isNoData )
203 {
204 fuzzifiedValue = mNoDataValue;
205 }
206 else if ( mFuzzifyLowBound < mFuzzifyHighBound )
207 {
208 if ( value <= mFuzzifyLowBound )
209 fuzzifiedValue = 0;
210 else if ( value >= mFuzzifyHighBound )
211 fuzzifiedValue = 1;
212 else
213 fuzzifiedValue = ( ( value - mFuzzifyLowBound ) / ( mFuzzifyHighBound - mFuzzifyLowBound ) );
214 }
215 else if ( mFuzzifyLowBound > mFuzzifyHighBound )
216 {
217 if ( value >= mFuzzifyLowBound )
218 fuzzifiedValue = 0;
219 else if ( value <= mFuzzifyHighBound )
220 fuzzifiedValue = 1;
221 else
222 fuzzifiedValue = ( ( value - mFuzzifyLowBound ) / ( mFuzzifyHighBound - mFuzzifyLowBound ) );
223 }
224 else
225 {
226 throw QgsProcessingException( QObject::tr( "Please choose varying values for the high and low membership parameters" ) );
227 }
228
229 fuzzifiedBlock->setValue( row, column, fuzzifiedValue );
230 }
231 }
232 mDestinationRasterProvider->writeBlock( fuzzifiedBlock.get(), mBand, iterLeft, iterTop );
233 }
234 mDestinationRasterProvider->setEditable( false );
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" ), QgsProcessingParameterNumber::Double, 0 ) );
282 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYHIGHBOUND" ), QStringLiteral( "High fuzzy membership bound" ), QgsProcessingParameterNumber::Double, 1 ) );
283 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYEXPONENT" ), QStringLiteral( "Membership function exponent" ), QgsProcessingParameterNumber::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( 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 >( mDestinationRasterProvider->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 mDestinationRasterProvider->writeBlock( fuzzifiedBlock.get(), mBand, iterLeft, iterTop );
360 }
361 mDestinationRasterProvider->setEditable( false );
362}
363
364//
365// QgsFuzzfiyRasterLargeMembershipAlgorithm
366//
367
368QString QgsFuzzifyRasterLargeMembershipAlgorithm::name() const
369{
370 return QStringLiteral( "fuzzifyrasterlargemembership" );
371}
372
373QString QgsFuzzifyRasterLargeMembershipAlgorithm::displayName() const
374{
375 return QObject::tr( "Fuzzify raster (large membership)" );
376}
377
378QStringList QgsFuzzifyRasterLargeMembershipAlgorithm::tags() const
379{
380 return QObject::tr( "fuzzy logic,fuzzify,fuzzy,logic,large,membership" ).split( ',' );
381}
382
383
384QString QgsFuzzifyRasterLargeMembershipAlgorithm::shortHelpString() const
385{
386 return QObject::tr( "The Fuzzify raster (large membership) algorithm transforms an input raster "
387 "to a fuzzified raster and thereby assigns values between 0 and 1 following the "
388 "'large' fuzzy membership function. The value of 0 implies no membership with the "
389 "defined fuzzy set, a value of 1 depicts full membership. In between, the degree "
390 "of membership of raster values follows the 'large' membership function.\n\n"
391 "The 'large' function is constructed using two user-defined input raster values "
392 "which set the point of half membership (midpoint, results to 0.5) and a predefined "
393 "function spread which controls the function uptake.\n\n"
394 "This function is typically used when larger input raster values should become members "
395 "of the fuzzy set more easily than smaller values." );
396}
397
398QgsFuzzifyRasterLargeMembershipAlgorithm *QgsFuzzifyRasterLargeMembershipAlgorithm::createInstance() const
399{
400 return new QgsFuzzifyRasterLargeMembershipAlgorithm();
401}
402
403void QgsFuzzifyRasterLargeMembershipAlgorithm::addAlgorithmParams( )
404{
405 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYMIDPOINT" ), QStringLiteral( "Function midpoint" ), QgsProcessingParameterNumber::Double, 50 ) );
406 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYSPREAD" ), QStringLiteral( "Function spread" ), QgsProcessingParameterNumber::Double, 5 ) );
407}
408
409bool QgsFuzzifyRasterLargeMembershipAlgorithm::prepareAlgorithmFuzzificationParameters( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
410{
411 Q_UNUSED( feedback )
412 mFuzzifyMidpoint = parameterAsDouble( parameters, QStringLiteral( "FUZZYMIDPOINT" ), context );
413 mFuzzifySpread = parameterAsDouble( parameters, QStringLiteral( "FUZZYSPREAD" ), context );
414 return true;
415}
416
417void QgsFuzzifyRasterLargeMembershipAlgorithm::fuzzify( QgsProcessingFeedback *feedback )
418{
421 const int nbBlocksWidth = static_cast< int >( std::ceil( 1.0 * mLayerWidth / maxWidth ) );
422 const int nbBlocksHeight = static_cast< int >( std::ceil( 1.0 * mLayerHeight / maxHeight ) );
423 const int nbBlocks = nbBlocksWidth * nbBlocksHeight;
424
425 QgsRasterIterator iter( mInterface.get() );
426 iter.startRasterRead( mBand, mLayerWidth, mLayerHeight, mExtent );
427 int iterLeft = 0;
428 int iterTop = 0;
429 int iterCols = 0;
430 int iterRows = 0;
431 bool isNoData = false;
432 std::unique_ptr< QgsRasterBlock > rasterBlock;
433 while ( iter.readNextRasterPart( mBand, iterCols, iterRows, rasterBlock, iterLeft, iterTop ) )
434 {
435 if ( feedback )
436 feedback->setProgress( 100 * ( ( iterTop / maxHeight * nbBlocksWidth ) + iterLeft / maxWidth ) / nbBlocks );
437 std::unique_ptr< QgsRasterBlock > fuzzifiedBlock = std::make_unique< QgsRasterBlock >( mDestinationRasterProvider->dataType( 1 ), iterCols, iterRows );
438
439 for ( int row = 0; row < iterRows; row++ )
440 {
441 if ( feedback && feedback->isCanceled() )
442 break;
443 for ( int column = 0; column < iterCols; column++ )
444 {
445 if ( feedback && feedback->isCanceled() )
446 break;
447
448 const double value = rasterBlock->valueAndNoData( row, column, isNoData );
449 double fuzzifiedValue;
450
451 if ( isNoData )
452 {
453 fuzzifiedValue = mNoDataValue;
454 }
455 else
456 {
457 fuzzifiedValue = 1 / ( 1 + std::pow( value / mFuzzifyMidpoint, -mFuzzifySpread ) );
458 }
459
460 fuzzifiedBlock->setValue( row, column, fuzzifiedValue );
461 }
462 }
463 mDestinationRasterProvider->writeBlock( fuzzifiedBlock.get(), mBand, iterLeft, iterTop );
464 }
465 mDestinationRasterProvider->setEditable( false );
466}
467
468
469//
470// QgsFuzzfiyRasterSmallMembershipAlgorithm
471//
472
473QString QgsFuzzifyRasterSmallMembershipAlgorithm::name() const
474{
475 return QStringLiteral( "fuzzifyrastersmallmembership" );
476}
477
478QString QgsFuzzifyRasterSmallMembershipAlgorithm::displayName() const
479{
480 return QObject::tr( "Fuzzify raster (small membership)" );
481}
482
483QStringList QgsFuzzifyRasterSmallMembershipAlgorithm::tags() const
484{
485 return QObject::tr( "fuzzy logic,fuzzify,fuzzy,logic,small,membership" ).split( ',' );
486}
487
488
489QString QgsFuzzifyRasterSmallMembershipAlgorithm::shortHelpString() const
490{
491 return QObject::tr( "The Fuzzify raster (small membership) algorithm transforms an input raster "
492 "to a fuzzified raster and thereby assigns values between 0 and 1 following the "
493 "'small' fuzzy membership function. The value of 0 implies no membership with the "
494 "defined fuzzy set, a value of 1 depicts full membership. In between, the degree "
495 "of membership of raster values follows the 'small' membership function.\n\n"
496 "The 'small' function is constructed using two user-defined input raster values "
497 "which set the point of half membership (midpoint, results to 0.5) and a predefined "
498 "function spread which controls the function uptake.\n\n"
499 "This function is typically used when smaller input raster values should become members "
500 "of the fuzzy set more easily than higher values." );
501}
502
503QgsFuzzifyRasterSmallMembershipAlgorithm *QgsFuzzifyRasterSmallMembershipAlgorithm::createInstance() const
504{
505 return new QgsFuzzifyRasterSmallMembershipAlgorithm();
506}
507
508void QgsFuzzifyRasterSmallMembershipAlgorithm::addAlgorithmParams( )
509{
510 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYMIDPOINT" ), QStringLiteral( "Function midpoint" ), QgsProcessingParameterNumber::Double, 50 ) );
511 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYSPREAD" ), QStringLiteral( "Function spread" ), QgsProcessingParameterNumber::Double, 5 ) );
512}
513
514bool QgsFuzzifyRasterSmallMembershipAlgorithm::prepareAlgorithmFuzzificationParameters( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
515{
516 Q_UNUSED( feedback )
517 mFuzzifyMidpoint = parameterAsDouble( parameters, QStringLiteral( "FUZZYMIDPOINT" ), context );
518 mFuzzifySpread = parameterAsDouble( parameters, QStringLiteral( "FUZZYSPREAD" ), context );
519 return true;
520}
521
522void QgsFuzzifyRasterSmallMembershipAlgorithm::fuzzify( QgsProcessingFeedback *feedback )
523{
526 const int nbBlocksWidth = static_cast< int >( std::ceil( 1.0 * mLayerWidth / maxWidth ) );
527 const int nbBlocksHeight = static_cast< int >( std::ceil( 1.0 * mLayerHeight / maxHeight ) );
528 const int nbBlocks = nbBlocksWidth * nbBlocksHeight;
529
530 QgsRasterIterator iter( mInterface.get() );
531 iter.startRasterRead( mBand, mLayerWidth, mLayerHeight, mExtent );
532 int iterLeft = 0;
533 int iterTop = 0;
534 int iterCols = 0;
535 int iterRows = 0;
536 bool isNoData = false;
537 std::unique_ptr< QgsRasterBlock > rasterBlock;
538 while ( iter.readNextRasterPart( mBand, iterCols, iterRows, rasterBlock, iterLeft, iterTop ) )
539 {
540 if ( feedback )
541 feedback->setProgress( 100 * ( ( iterTop / maxHeight * nbBlocksWidth ) + iterLeft / maxWidth ) / nbBlocks );
542 std::unique_ptr< QgsRasterBlock > fuzzifiedBlock = std::make_unique< QgsRasterBlock >( mDestinationRasterProvider->dataType( 1 ), iterCols, iterRows );
543
544 for ( int row = 0; row < iterRows; row++ )
545 {
546 if ( feedback && feedback->isCanceled() )
547 break;
548 for ( int column = 0; column < iterCols; column++ )
549 {
550 if ( feedback && feedback->isCanceled() )
551 break;
552
553 const double value = rasterBlock->valueAndNoData( row, column, isNoData );
554 double fuzzifiedValue;
555
556 if ( isNoData )
557 {
558 fuzzifiedValue = mNoDataValue;
559 }
560 else
561 {
562 fuzzifiedValue = 1 / ( 1 + std::pow( value / mFuzzifyMidpoint, mFuzzifySpread ) );
563 }
564
565 fuzzifiedBlock->setValue( row, column, fuzzifiedValue );
566 }
567 }
568 mDestinationRasterProvider->writeBlock( fuzzifiedBlock.get(), mBand, iterLeft, iterTop );
569 }
570 mDestinationRasterProvider->setEditable( false );
571}
572
573
574//
575// QgsFuzzfiyRasterGaussianMembershipAlgorithm
576//
577
578QString QgsFuzzifyRasterGaussianMembershipAlgorithm::name() const
579{
580 return QStringLiteral( "fuzzifyrastergaussianmembership" );
581}
582
583QString QgsFuzzifyRasterGaussianMembershipAlgorithm::displayName() const
584{
585 return QObject::tr( "Fuzzify raster (gaussian membership)" );
586}
587
588QStringList QgsFuzzifyRasterGaussianMembershipAlgorithm::tags() const
589{
590 return QObject::tr( "fuzzy logic,fuzzify,fuzzy,logic,gaussian,membership" ).split( ',' );
591}
592
593
594QString QgsFuzzifyRasterGaussianMembershipAlgorithm::shortHelpString() const
595{
596 return QObject::tr( "The Fuzzify raster (gaussian membership) algorithm transforms an input raster "
597 "to a fuzzified raster and thereby assigns values between 0 and 1 following a "
598 "gaussian fuzzy membership function. The value of 0 implies no membership with the "
599 "defined fuzzy set, a value of 1 depicts full membership. In between, the degree "
600 "of membership of raster values follows a gaussian membership function.\n\n"
601 "The gaussian function is constructed using two user-defined input values "
602 "which set the midpoint of the gaussian function (midpoint, results to 1) and a "
603 "predefined function spread which controls the function spread.\n\n"
604 "This function is typically used when a certain range of raster values around a "
605 "predefined function midpoint should become members of the fuzzy set." );
606}
607
608QgsFuzzifyRasterGaussianMembershipAlgorithm *QgsFuzzifyRasterGaussianMembershipAlgorithm::createInstance() const
609{
610 return new QgsFuzzifyRasterGaussianMembershipAlgorithm();
611}
612
613void QgsFuzzifyRasterGaussianMembershipAlgorithm::addAlgorithmParams( )
614{
615 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYMIDPOINT" ), QStringLiteral( "Function midpoint" ), QgsProcessingParameterNumber::Double, 10 ) );
616 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYSPREAD" ), QStringLiteral( "Function spread" ), QgsProcessingParameterNumber::Double, 0.01 ) );
617}
618
619bool QgsFuzzifyRasterGaussianMembershipAlgorithm::prepareAlgorithmFuzzificationParameters( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
620{
621 Q_UNUSED( feedback )
622 mFuzzifyMidpoint = parameterAsDouble( parameters, QStringLiteral( "FUZZYMIDPOINT" ), context );
623 mFuzzifySpread = parameterAsDouble( parameters, QStringLiteral( "FUZZYSPREAD" ), context );
624 return true;
625}
626
627void QgsFuzzifyRasterGaussianMembershipAlgorithm::fuzzify( QgsProcessingFeedback *feedback )
628{
631 const int nbBlocksWidth = static_cast< int >( std::ceil( 1.0 * mLayerWidth / maxWidth ) );
632 const int nbBlocksHeight = static_cast< int >( std::ceil( 1.0 * mLayerHeight / maxHeight ) );
633 const int nbBlocks = nbBlocksWidth * nbBlocksHeight;
634
635 QgsRasterIterator iter( mInterface.get() );
636 iter.startRasterRead( mBand, mLayerWidth, mLayerHeight, mExtent );
637 int iterLeft = 0;
638 int iterTop = 0;
639 int iterCols = 0;
640 int iterRows = 0;
641 bool isNoData = false;
642 std::unique_ptr< QgsRasterBlock > rasterBlock;
643 while ( iter.readNextRasterPart( mBand, iterCols, iterRows, rasterBlock, iterLeft, iterTop ) )
644 {
645 if ( feedback )
646 feedback->setProgress( 100 * ( ( iterTop / maxHeight * nbBlocksWidth ) + iterLeft / maxWidth ) / nbBlocks );
647 std::unique_ptr< QgsRasterBlock > fuzzifiedBlock = std::make_unique< QgsRasterBlock >( mDestinationRasterProvider->dataType( 1 ), iterCols, iterRows );
648
649 for ( int row = 0; row < iterRows; row++ )
650 {
651 if ( feedback && feedback->isCanceled() )
652 break;
653 for ( int column = 0; column < iterCols; column++ )
654 {
655 if ( feedback && feedback->isCanceled() )
656 break;
657
658 const double value = rasterBlock->valueAndNoData( row, column, isNoData );
659 double fuzzifiedValue;
660
661 if ( isNoData )
662 {
663 fuzzifiedValue = mNoDataValue;
664 }
665 else
666 {
667 fuzzifiedValue = std::exp( -mFuzzifySpread * std::pow( value - mFuzzifyMidpoint, 2 ) );
668 }
669
670 fuzzifiedBlock->setValue( row, column, fuzzifiedValue );
671 }
672 }
673 mDestinationRasterProvider->writeBlock( fuzzifiedBlock.get(), mBand, iterLeft, iterTop );
674 }
675 mDestinationRasterProvider->setEditable( false );
676}
677
678
679//
680// QgsFuzzfiyRasterNearMembershipAlgorithm
681//
682
683QString QgsFuzzifyRasterNearMembershipAlgorithm::name() const
684{
685 return QStringLiteral( "fuzzifyrasternearmembership" );
686}
687
688QString QgsFuzzifyRasterNearMembershipAlgorithm::displayName() const
689{
690 return QObject::tr( "Fuzzify raster (near membership)" );
691}
692
693QStringList QgsFuzzifyRasterNearMembershipAlgorithm::tags() const
694{
695 return QObject::tr( "fuzzy logic,fuzzify,fuzzy,logic,near,membership" ).split( ',' );
696}
697
698
699QString QgsFuzzifyRasterNearMembershipAlgorithm::shortHelpString() const
700{
701 return QObject::tr( "The Fuzzify raster (near membership) algorithm transforms an input raster "
702 "to a fuzzified raster and thereby assigns values between 0 and 1 following the "
703 "'near' fuzzy membership function. The value of 0 implies no membership with the "
704 "defined fuzzy set, a value of 1 depicts full membership. In between, the degree "
705 "of membership of raster values follows the 'near' membership function.\n\n"
706 "The 'near' function is constructed using two user-defined input values "
707 "which set the midpoint of the 'near' function (midpoint, results to 1) and a "
708 "predefined function spread which controls the function spread.\n\n"
709 "This function is typically used when a certain range of raster values near a "
710 "predefined function midpoint should become members of the fuzzy set. The function"
711 " generally shows a higher rate of decay than the gaussian membership function." );
712}
713
714QgsFuzzifyRasterNearMembershipAlgorithm *QgsFuzzifyRasterNearMembershipAlgorithm::createInstance() const
715{
716 return new QgsFuzzifyRasterNearMembershipAlgorithm();
717}
718
719void QgsFuzzifyRasterNearMembershipAlgorithm::addAlgorithmParams( )
720{
721 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYMIDPOINT" ), QStringLiteral( "Function midpoint" ), QgsProcessingParameterNumber::Double, 50 ) );
722 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYSPREAD" ), QStringLiteral( "Function spread" ), QgsProcessingParameterNumber::Double, 0.01 ) );
723}
724
725bool QgsFuzzifyRasterNearMembershipAlgorithm::prepareAlgorithmFuzzificationParameters( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
726{
727 Q_UNUSED( feedback )
728 mFuzzifyMidpoint = parameterAsDouble( parameters, QStringLiteral( "FUZZYMIDPOINT" ), context );
729 mFuzzifySpread = parameterAsDouble( parameters, QStringLiteral( "FUZZYSPREAD" ), context );
730 return true;
731}
732
733void QgsFuzzifyRasterNearMembershipAlgorithm::fuzzify( QgsProcessingFeedback *feedback )
734{
737 const int nbBlocksWidth = static_cast< int >( std::ceil( 1.0 * mLayerWidth / maxWidth ) );
738 const int nbBlocksHeight = static_cast< int >( std::ceil( 1.0 * mLayerHeight / maxHeight ) );
739 const int nbBlocks = nbBlocksWidth * nbBlocksHeight;
740
741 QgsRasterIterator iter( mInterface.get() );
742 iter.startRasterRead( mBand, mLayerWidth, mLayerHeight, mExtent );
743 int iterLeft = 0;
744 int iterTop = 0;
745 int iterCols = 0;
746 int iterRows = 0;
747 bool isNoData = false;
748 std::unique_ptr< QgsRasterBlock > rasterBlock;
749 while ( iter.readNextRasterPart( mBand, iterCols, iterRows, rasterBlock, iterLeft, iterTop ) )
750 {
751 if ( feedback )
752 feedback->setProgress( 100 * ( ( iterTop / maxHeight * nbBlocksWidth ) + iterLeft / maxWidth ) / nbBlocks );
753 std::unique_ptr< QgsRasterBlock > fuzzifiedBlock = std::make_unique< QgsRasterBlock >( mDestinationRasterProvider->dataType( 1 ), iterCols, iterRows );
754
755 for ( int row = 0; row < iterRows; row++ )
756 {
757 if ( feedback && feedback->isCanceled() )
758 break;
759 for ( int column = 0; column < iterCols; column++ )
760 {
761 if ( feedback && feedback->isCanceled() )
762 break;
763
764 const double value = rasterBlock->valueAndNoData( row, column, isNoData );
765 double fuzzifiedValue;
766
767 if ( isNoData )
768 {
769 fuzzifiedValue = mNoDataValue;
770 }
771 else
772 {
773 fuzzifiedValue = 1 / ( 1 + mFuzzifySpread * std::pow( value - mFuzzifyMidpoint, 2 ) );
774 }
775
776 fuzzifiedBlock->setValue( row, column, fuzzifiedValue );
777 }
778 }
779 mDestinationRasterProvider->writeBlock( fuzzifiedBlock.get(), mBand, iterLeft, iterTop );
780 }
781 mDestinationRasterProvider->setEditable( false );
782}
783
784
786
787
788
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:54
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition: qgsfeedback.h:63
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.
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:3032