QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
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 
28 QString QgsFuzzifyRasterAlgorithmBase::group() const
29 {
30  return QObject::tr( "Raster analysis" );
31 }
32 
33 QString QgsFuzzifyRasterAlgorithmBase::groupId() const
34 {
35  return QStringLiteral( "rasteranalysis" );
36 }
37 
38 void 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 
55 bool 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 
81 QVariantMap 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 
118 QString QgsFuzzifyRasterLinearMembershipAlgorithm::name() const
119 {
120  return QStringLiteral( "fuzzifyrasterlinearmembership" );
121 }
122 
123 QString QgsFuzzifyRasterLinearMembershipAlgorithm::displayName() const
124 {
125  return QObject::tr( "Fuzzify raster (linear membership)" );
126 }
127 
128 QStringList QgsFuzzifyRasterLinearMembershipAlgorithm::tags() const
129 {
130  return QObject::tr( "fuzzy logic,fuzzify,fuzzy,logic,linear,membership" ).split( ',' );
131 }
132 
133 
134 QString 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 
149 QgsFuzzifyRasterLinearMembershipAlgorithm *QgsFuzzifyRasterLinearMembershipAlgorithm::createInstance() const
150 {
151  return new QgsFuzzifyRasterLinearMembershipAlgorithm();
152 }
153 
154 void 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 
160 bool 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 
168 void 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 
242 QString QgsFuzzifyRasterPowerMembershipAlgorithm::name() const
243 {
244  return QStringLiteral( "fuzzifyrasterpowermembership" );
245 }
246 
247 QString QgsFuzzifyRasterPowerMembershipAlgorithm::displayName() const
248 {
249  return QObject::tr( "Fuzzify raster (power membership)" );
250 }
251 
252 QStringList QgsFuzzifyRasterPowerMembershipAlgorithm::tags() const
253 {
254  return QObject::tr( "fuzzy logic,fuzzify,fuzzy,logic,power,non-linear,membership,exponent" ).split( ',' );
255 }
256 
257 
258 QString 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 
274 QgsFuzzifyRasterPowerMembershipAlgorithm *QgsFuzzifyRasterPowerMembershipAlgorithm::createInstance() const
275 {
276  return new QgsFuzzifyRasterPowerMembershipAlgorithm();
277 }
278 
279 void 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 
286 bool 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 
295 void 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 
368 QString QgsFuzzifyRasterLargeMembershipAlgorithm::name() const
369 {
370  return QStringLiteral( "fuzzifyrasterlargemembership" );
371 }
372 
373 QString QgsFuzzifyRasterLargeMembershipAlgorithm::displayName() const
374 {
375  return QObject::tr( "Fuzzify raster (large membership)" );
376 }
377 
378 QStringList QgsFuzzifyRasterLargeMembershipAlgorithm::tags() const
379 {
380  return QObject::tr( "fuzzy logic,fuzzify,fuzzy,logic,large,membership" ).split( ',' );
381 }
382 
383 
384 QString 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 
398 QgsFuzzifyRasterLargeMembershipAlgorithm *QgsFuzzifyRasterLargeMembershipAlgorithm::createInstance() const
399 {
400  return new QgsFuzzifyRasterLargeMembershipAlgorithm();
401 }
402 
403 void 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 
409 bool 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 
417 void 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 
473 QString QgsFuzzifyRasterSmallMembershipAlgorithm::name() const
474 {
475  return QStringLiteral( "fuzzifyrastersmallmembership" );
476 }
477 
478 QString QgsFuzzifyRasterSmallMembershipAlgorithm::displayName() const
479 {
480  return QObject::tr( "Fuzzify raster (small membership)" );
481 }
482 
483 QStringList QgsFuzzifyRasterSmallMembershipAlgorithm::tags() const
484 {
485  return QObject::tr( "fuzzy logic,fuzzify,fuzzy,logic,small,membership" ).split( ',' );
486 }
487 
488 
489 QString 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 
503 QgsFuzzifyRasterSmallMembershipAlgorithm *QgsFuzzifyRasterSmallMembershipAlgorithm::createInstance() const
504 {
505  return new QgsFuzzifyRasterSmallMembershipAlgorithm();
506 }
507 
508 void 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 
514 bool 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 
522 void 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 
578 QString QgsFuzzifyRasterGaussianMembershipAlgorithm::name() const
579 {
580  return QStringLiteral( "fuzzifyrastergaussianmembership" );
581 }
582 
583 QString QgsFuzzifyRasterGaussianMembershipAlgorithm::displayName() const
584 {
585  return QObject::tr( "Fuzzify raster (gaussian membership)" );
586 }
587 
588 QStringList QgsFuzzifyRasterGaussianMembershipAlgorithm::tags() const
589 {
590  return QObject::tr( "fuzzy logic,fuzzify,fuzzy,logic,gaussian,membership" ).split( ',' );
591 }
592 
593 
594 QString 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 
608 QgsFuzzifyRasterGaussianMembershipAlgorithm *QgsFuzzifyRasterGaussianMembershipAlgorithm::createInstance() const
609 {
610  return new QgsFuzzifyRasterGaussianMembershipAlgorithm();
611 }
612 
613 void 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 
619 bool 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 
627 void 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 
683 QString QgsFuzzifyRasterNearMembershipAlgorithm::name() const
684 {
685  return QStringLiteral( "fuzzifyrasternearmembership" );
686 }
687 
688 QString QgsFuzzifyRasterNearMembershipAlgorithm::displayName() const
689 {
690  return QObject::tr( "Fuzzify raster (near membership)" );
691 }
692 
693 QStringList QgsFuzzifyRasterNearMembershipAlgorithm::tags() const
694 {
695  return QObject::tr( "fuzzy logic,fuzzify,fuzzy,logic,near,membership" ).split( ',' );
696 }
697 
698 
699 QString 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 
714 QgsFuzzifyRasterNearMembershipAlgorithm *QgsFuzzifyRasterNearMembershipAlgorithm::createInstance() const
715 {
716  return new QgsFuzzifyRasterNearMembershipAlgorithm();
717 }
718 
719 void 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 
725 bool 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 
733 void 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 
QgsFeedback::setProgress
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition: qgsfeedback.h:76
QgsProcessingParameterNumber::Double
@ Double
Double/float values.
Definition: qgsprocessingparameters.h:2187
QgsProcessingParameterNumber
A numeric parameter for processing algorithms.
Definition: qgsprocessingparameters.h:2179
QgsProcessingFeedback
Base class for providing feedback from a processing algorithm.
Definition: qgsprocessingfeedback.h:37
QgsRasterFileWriter::driverForExtension
static QString driverForExtension(const QString &extension)
Returns the GDAL driver name for a specified file extension.
Definition: qgsrasterfilewriter.cpp:1066
qgsstringutils.h
QgsProcessingParameterRasterDestination
A raster layer destination parameter, for specifying the destination path for a raster layer created ...
Definition: qgsprocessingparameters.h:3390
QgsFeedback::isCanceled
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:67
qgsalgorithmfuzzifyraster.h
QgsProcessingOutputNumber
A numeric output for processing algorithms.
Definition: qgsprocessingoutputs.h:312
qgsrasterfilewriter.h
QgsProcessingContext
Contains information about the context in which a processing algorithm is executed.
Definition: qgsprocessingcontext.h:46
QgsRasterIterator::DEFAULT_MAXIMUM_TILE_HEIGHT
static const int DEFAULT_MAXIMUM_TILE_HEIGHT
Default maximum tile height.
Definition: qgsrasteriterator.h:170
QgsProcessingParameterRasterLayer
A raster layer parameter for processing algorithms.
Definition: qgsprocessingparameters.h:2495
QgsProcessingOutputString
A string output for processing algorithms.
Definition: qgsprocessingoutputs.h:334
QgsRasterIterator
Iterator for sequentially processing raster cells.
Definition: qgsrasteriterator.h:34
QgsRasterIterator::DEFAULT_MAXIMUM_TILE_WIDTH
static const int DEFAULT_MAXIMUM_TILE_WIDTH
Default maximum tile width.
Definition: qgsrasteriterator.h:167
QgsErrorMessage::Text
@ Text
Definition: qgserror.h:38
QgsProcessingParameterBand
A raster band parameter for Processing algorithms.
Definition: qgsprocessingparameters.h:3548
QgsProcessingException
Custom exception class for processing related exceptions.
Definition: qgsexception.h:82
qgssize
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:2791