QGIS API Documentation 3.43.0-Master (3ee7834ace6)
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 auto createOptsParam = std::make_unique<QgsProcessingParameterString>( QStringLiteral( "CREATE_OPTIONS" ), QObject::tr( "Creation options" ), QVariant(), false, true );
53 createOptsParam->setMetadata( QVariantMap( { { QStringLiteral( "widget_wrapper" ), QVariantMap( { { QStringLiteral( "widget_type" ), QStringLiteral( "rasteroptions" ) } } ) } } ) );
54 createOptsParam->setFlags( createOptsParam->flags() | Qgis::ProcessingParameterFlag::Advanced );
55 addParameter( createOptsParam.release() );
56
57 addParameter( new QgsProcessingParameterRasterDestination( QStringLiteral( "OUTPUT" ), QObject::tr( "Fuzzified raster" ) ) );
58}
59
60bool QgsFuzzifyRasterAlgorithmBase::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
61{
62 mInputRaster = parameterAsRasterLayer( parameters, QStringLiteral( "INPUT" ), context );
63
64 if ( !mInputRaster )
65 throw QgsProcessingException( invalidRasterError( parameters, QStringLiteral( "INPUT" ) ) );
66
67 mBand = parameterAsInt( parameters, QStringLiteral( "BAND" ), context );
68 if ( mBand < 1 || mBand > mInputRaster->bandCount() )
69 throw QgsProcessingException( QObject::tr( "Invalid band number for BAND (%1): Valid values for input raster are 1 to %2" ).arg( mBand ).arg( mInputRaster->bandCount() ) );
70
71 mInterface.reset( mInputRaster->dataProvider()->clone() );
72 mExtent = mInputRaster->extent();
73 mLayerWidth = mInputRaster->width();
74 mLayerHeight = mInputRaster->height();
75 mCrs = mInputRaster->crs();
76 mNbCellsXProvider = mInterface->xSize();
77 mNbCellsYProvider = mInterface->ySize();
78
79 //prepare fuzzifcation parameters from subclass alg
80 prepareAlgorithmFuzzificationParameters( parameters, context, feedback );
81
82 return true;
83}
84
85QVariantMap QgsFuzzifyRasterAlgorithmBase::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
86{
87 const QString createOptions = parameterAsString( parameters, QStringLiteral( "CREATE_OPTIONS" ), context ).trimmed();
88 const QString outputFile = parameterAsOutputLayer( parameters, QStringLiteral( "OUTPUT" ), context );
89 const QFileInfo fi( outputFile );
90 const QString outputFormat = QgsRasterFileWriter::driverForExtension( fi.suffix() );
91
92 auto writer = std::make_unique<QgsRasterFileWriter>( outputFile );
93 writer->setOutputProviderKey( QStringLiteral( "gdal" ) );
94 if ( !createOptions.isEmpty() )
95 {
96 writer->setCreateOptions( createOptions.split( '|' ) );
97 }
98 writer->setOutputFormat( outputFormat );
99 std::unique_ptr<QgsRasterDataProvider> provider( writer->createOneBandRaster( mDataType, mNbCellsXProvider, mNbCellsYProvider, mExtent, mCrs ) );
100 if ( !provider )
101 throw QgsProcessingException( QObject::tr( "Could not create raster output: %1" ).arg( outputFile ) );
102 if ( !provider->isValid() )
103 throw QgsProcessingException( QObject::tr( "Could not create raster output %1: %2" ).arg( outputFile, provider->error().message( QgsErrorMessage::Text ) ) );
104
105 provider->setNoDataValue( 1, mNoDataValue );
106 provider->setEditable( true );
107 const qgssize layerSize = static_cast<qgssize>( mLayerWidth ) * static_cast<qgssize>( mLayerHeight );
108
109 fuzzify( provider.get(), feedback );
110
111 provider->setEditable( false );
112
113 QVariantMap outputs;
114 outputs.insert( QStringLiteral( "EXTENT" ), mExtent.toString() );
115 outputs.insert( QStringLiteral( "CRS_AUTHID" ), mCrs.authid() );
116 outputs.insert( QStringLiteral( "WIDTH_IN_PIXELS" ), mLayerWidth );
117 outputs.insert( QStringLiteral( "HEIGHT_IN_PIXELS" ), mLayerHeight );
118 outputs.insert( QStringLiteral( "TOTAL_PIXEL_COUNT" ), layerSize );
119 outputs.insert( QStringLiteral( "OUTPUT" ), outputFile );
120 return outputs;
121}
122
123
124//
125// QgsFuzzfiyRasterLinearMembershipAlgorithm
126//
127
128QString QgsFuzzifyRasterLinearMembershipAlgorithm::name() const
129{
130 return QStringLiteral( "fuzzifyrasterlinearmembership" );
131}
132
133QString QgsFuzzifyRasterLinearMembershipAlgorithm::displayName() const
134{
135 return QObject::tr( "Fuzzify raster (linear membership)" );
136}
137
138QStringList QgsFuzzifyRasterLinearMembershipAlgorithm::tags() const
139{
140 return QObject::tr( "fuzzy logic,fuzzify,fuzzy,logic,linear,membership" ).split( ',' );
141}
142
143
144QString QgsFuzzifyRasterLinearMembershipAlgorithm::shortHelpString() const
145{
146 return QObject::tr( "The Fuzzify raster (linear membership) algorithm transforms an input raster "
147 "to a fuzzified raster and thereby assigns values between 0 and 1 following a "
148 "linear fuzzy membership function. The value of 0 implies no membership with the "
149 "defined fuzzy set, a value of 1 depicts full membership. In between, the degree "
150 "of membership of raster values follows a linear membership function.\n\n"
151 "The linear function is constructed using two user-defined input raster values "
152 "which set the point of full membership (high bound, results to 1) and no membership "
153 "(low bound, results to 0) respectively. The fuzzy set in between those values is defined as a "
154 "linear function.\n\n"
155 "Both increasing and decreasing fuzzy sets can be modeled by "
156 "swapping the high and low bound parameters." );
157}
158
159QgsFuzzifyRasterLinearMembershipAlgorithm *QgsFuzzifyRasterLinearMembershipAlgorithm::createInstance() const
160{
161 return new QgsFuzzifyRasterLinearMembershipAlgorithm();
162}
163
164void QgsFuzzifyRasterLinearMembershipAlgorithm::addAlgorithmParams()
165{
166 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYLOWBOUND" ), QStringLiteral( "Low fuzzy membership bound" ), Qgis::ProcessingNumberParameterType::Double, 0 ) );
167 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYHIGHBOUND" ), QStringLiteral( "High fuzzy membership bound" ), Qgis::ProcessingNumberParameterType::Double, 1 ) );
168}
169
170bool QgsFuzzifyRasterLinearMembershipAlgorithm::prepareAlgorithmFuzzificationParameters( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
171{
172 Q_UNUSED( feedback )
173 mFuzzifyHighBound = parameterAsDouble( parameters, QStringLiteral( "FUZZYHIGHBOUND" ), context );
174 mFuzzifyLowBound = parameterAsDouble( parameters, QStringLiteral( "FUZZYLOWBOUND" ), context );
175 return true;
176}
177
178void QgsFuzzifyRasterLinearMembershipAlgorithm::fuzzify( QgsRasterDataProvider *destinationProvider, QgsProcessingFeedback *feedback )
179{
182 const int nbBlocksWidth = static_cast<int>( std::ceil( 1.0 * mLayerWidth / maxWidth ) );
183 const int nbBlocksHeight = static_cast<int>( std::ceil( 1.0 * mLayerHeight / maxHeight ) );
184 const int nbBlocks = nbBlocksWidth * nbBlocksHeight;
185
186 QgsRasterIterator iter( mInterface.get() );
187 iter.startRasterRead( mBand, mLayerWidth, mLayerHeight, mExtent );
188 int iterLeft = 0;
189 int iterTop = 0;
190 int iterCols = 0;
191 int iterRows = 0;
192 bool isNoData = false;
193 std::unique_ptr<QgsRasterBlock> rasterBlock;
194 while ( iter.readNextRasterPart( mBand, iterCols, iterRows, rasterBlock, iterLeft, iterTop ) )
195 {
196 if ( feedback )
197 feedback->setProgress( 100 * ( ( iterTop / maxHeight * nbBlocksWidth ) + iterLeft / maxWidth ) / nbBlocks );
198 auto fuzzifiedBlock = std::make_unique<QgsRasterBlock>( destinationProvider->dataType( 1 ), iterCols, iterRows );
199
200 for ( int row = 0; row < iterRows; row++ )
201 {
202 if ( feedback && feedback->isCanceled() )
203 break;
204 for ( int column = 0; column < iterCols; column++ )
205 {
206 if ( feedback && feedback->isCanceled() )
207 break;
208
209 const double value = rasterBlock->valueAndNoData( row, column, isNoData );
210 double fuzzifiedValue;
211
212 if ( isNoData )
213 {
214 fuzzifiedValue = mNoDataValue;
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 if ( mFuzzifyLowBound > mFuzzifyHighBound )
226 {
227 if ( value >= mFuzzifyLowBound )
228 fuzzifiedValue = 0;
229 else if ( value <= mFuzzifyHighBound )
230 fuzzifiedValue = 1;
231 else
232 fuzzifiedValue = ( ( value - mFuzzifyLowBound ) / ( mFuzzifyHighBound - mFuzzifyLowBound ) );
233 }
234 else
235 {
236 throw QgsProcessingException( QObject::tr( "Please choose varying values for the high and low membership parameters" ) );
237 }
238
239 fuzzifiedBlock->setValue( row, column, fuzzifiedValue );
240 }
241 }
242 if ( !destinationProvider->writeBlock( fuzzifiedBlock.get(), mBand, iterLeft, iterTop ) )
243 {
244 throw QgsProcessingException( QObject::tr( "Could not write raster block: %1" ).arg( destinationProvider->error().summary() ) );
245 }
246 }
247}
248
249
250//
251// QgsFuzzfiyRasterPowerMembershipAlgorithm
252//
253
254QString QgsFuzzifyRasterPowerMembershipAlgorithm::name() const
255{
256 return QStringLiteral( "fuzzifyrasterpowermembership" );
257}
258
259QString QgsFuzzifyRasterPowerMembershipAlgorithm::displayName() const
260{
261 return QObject::tr( "Fuzzify raster (power membership)" );
262}
263
264QStringList QgsFuzzifyRasterPowerMembershipAlgorithm::tags() const
265{
266 return QObject::tr( "fuzzy logic,fuzzify,fuzzy,logic,power,non-linear,membership,exponent" ).split( ',' );
267}
268
269
270QString QgsFuzzifyRasterPowerMembershipAlgorithm::shortHelpString() const
271{
272 return QObject::tr( "The Fuzzify raster (power membership) algorithm transforms an input raster "
273 "to a fuzzified raster and thereby assigns values between 0 and 1 following a "
274 "power function. The value of 0 implies no membership with the "
275 "defined fuzzy set, a value of 1 depicts full membership. In between, the degree "
276 "of membership of raster values follows a power function.\n\n"
277 "The power function is constructed using three user-defined input raster values "
278 "which set the point of full membership (high bound, results to 1), no membership "
279 "(low bound, results to 0) and function exponent (only positive) respectively. "
280 "The fuzzy set in between those the upper and lower bounds values is then defined as "
281 "a power function.\n\n"
282 "Both increasing and decreasing fuzzy sets can be modeled by "
283 "swapping the high and low bound parameters." );
284}
285
286QgsFuzzifyRasterPowerMembershipAlgorithm *QgsFuzzifyRasterPowerMembershipAlgorithm::createInstance() const
287{
288 return new QgsFuzzifyRasterPowerMembershipAlgorithm();
289}
290
291void QgsFuzzifyRasterPowerMembershipAlgorithm::addAlgorithmParams()
292{
293 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYLOWBOUND" ), QStringLiteral( "Low fuzzy membership bound" ), Qgis::ProcessingNumberParameterType::Double, 0 ) );
294 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYHIGHBOUND" ), QStringLiteral( "High fuzzy membership bound" ), Qgis::ProcessingNumberParameterType::Double, 1 ) );
295 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYEXPONENT" ), QStringLiteral( "Membership function exponent" ), Qgis::ProcessingNumberParameterType::Double, 2, false, 0 ) );
296}
297
298bool QgsFuzzifyRasterPowerMembershipAlgorithm::prepareAlgorithmFuzzificationParameters( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
299{
300 Q_UNUSED( feedback )
301 mFuzzifyHighBound = parameterAsDouble( parameters, QStringLiteral( "FUZZYHIGHBOUND" ), context );
302 mFuzzifyLowBound = parameterAsDouble( parameters, QStringLiteral( "FUZZYLOWBOUND" ), context );
303 mFuzzifyExponent = parameterAsDouble( parameters, QStringLiteral( "FUZZYEXPONENT" ), context );
304 return true;
305}
306
307void QgsFuzzifyRasterPowerMembershipAlgorithm::fuzzify( QgsRasterDataProvider *destinationProvider, QgsProcessingFeedback *feedback )
308{
311 const int nbBlocksWidth = static_cast<int>( std::ceil( 1.0 * mLayerWidth / maxWidth ) );
312 const int nbBlocksHeight = static_cast<int>( std::ceil( 1.0 * mLayerHeight / maxHeight ) );
313 const int nbBlocks = nbBlocksWidth * nbBlocksHeight;
314
315 QgsRasterIterator iter( mInterface.get() );
316 iter.startRasterRead( mBand, mLayerWidth, mLayerHeight, mExtent );
317 int iterLeft = 0;
318 int iterTop = 0;
319 int iterCols = 0;
320 int iterRows = 0;
321 bool isNoData = false;
322 std::unique_ptr<QgsRasterBlock> rasterBlock;
323 while ( iter.readNextRasterPart( mBand, iterCols, iterRows, rasterBlock, iterLeft, iterTop ) )
324 {
325 if ( feedback )
326 feedback->setProgress( 100 * ( ( iterTop / maxHeight * nbBlocksWidth ) + iterLeft / maxWidth ) / nbBlocks );
327 auto fuzzifiedBlock = std::make_unique<QgsRasterBlock>( destinationProvider->dataType( 1 ), iterCols, iterRows );
328
329 for ( int row = 0; row < iterRows; row++ )
330 {
331 if ( feedback && feedback->isCanceled() )
332 break;
333 for ( int column = 0; column < iterCols; column++ )
334 {
335 if ( feedback && feedback->isCanceled() )
336 break;
337
338 const double value = rasterBlock->valueAndNoData( row, column, isNoData );
339 double fuzzifiedValue;
340
341 if ( isNoData )
342 {
343 fuzzifiedValue = mNoDataValue;
344 }
345 else if ( mFuzzifyLowBound < mFuzzifyHighBound )
346 {
347 if ( value <= mFuzzifyLowBound )
348 fuzzifiedValue = 0;
349 else if ( value >= mFuzzifyHighBound )
350 fuzzifiedValue = 1;
351 else
352 fuzzifiedValue = std::pow( ( value - mFuzzifyLowBound ) / ( mFuzzifyHighBound - mFuzzifyLowBound ), mFuzzifyExponent );
353 }
354 else if ( mFuzzifyLowBound > mFuzzifyHighBound )
355 {
356 if ( value >= mFuzzifyLowBound )
357 fuzzifiedValue = 0;
358 else if ( value <= mFuzzifyHighBound )
359 fuzzifiedValue = 1;
360 else
361 fuzzifiedValue = std::pow( ( value - mFuzzifyLowBound ) / ( mFuzzifyHighBound - mFuzzifyLowBound ), mFuzzifyExponent );
362 }
363 else
364 {
365 throw QgsProcessingException( QObject::tr( "Please choose varying values for the high and low membership parameters" ) );
366 }
367
368 fuzzifiedBlock->setValue( row, column, fuzzifiedValue );
369 }
370 }
371 if ( !destinationProvider->writeBlock( fuzzifiedBlock.get(), mBand, iterLeft, iterTop ) )
372 {
373 throw QgsProcessingException( QObject::tr( "Could not write raster block: %1" ).arg( destinationProvider->error().summary() ) );
374 }
375 }
376}
377
378//
379// QgsFuzzfiyRasterLargeMembershipAlgorithm
380//
381
382QString QgsFuzzifyRasterLargeMembershipAlgorithm::name() const
383{
384 return QStringLiteral( "fuzzifyrasterlargemembership" );
385}
386
387QString QgsFuzzifyRasterLargeMembershipAlgorithm::displayName() const
388{
389 return QObject::tr( "Fuzzify raster (large membership)" );
390}
391
392QStringList QgsFuzzifyRasterLargeMembershipAlgorithm::tags() const
393{
394 return QObject::tr( "fuzzy logic,fuzzify,fuzzy,logic,large,membership" ).split( ',' );
395}
396
397
398QString QgsFuzzifyRasterLargeMembershipAlgorithm::shortHelpString() const
399{
400 return QObject::tr( "The Fuzzify raster (large membership) algorithm transforms an input raster "
401 "to a fuzzified raster and thereby assigns values between 0 and 1 following the "
402 "'large' fuzzy membership function. The value of 0 implies no membership with the "
403 "defined fuzzy set, a value of 1 depicts full membership. In between, the degree "
404 "of membership of raster values follows the 'large' membership function.\n\n"
405 "The 'large' function is constructed using two user-defined input raster values "
406 "which set the point of half membership (midpoint, results to 0.5) and a predefined "
407 "function spread which controls the function uptake.\n\n"
408 "This function is typically used when larger input raster values should become members "
409 "of the fuzzy set more easily than smaller values." );
410}
411
412QgsFuzzifyRasterLargeMembershipAlgorithm *QgsFuzzifyRasterLargeMembershipAlgorithm::createInstance() const
413{
414 return new QgsFuzzifyRasterLargeMembershipAlgorithm();
415}
416
417void QgsFuzzifyRasterLargeMembershipAlgorithm::addAlgorithmParams()
418{
419 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYMIDPOINT" ), QStringLiteral( "Function midpoint" ), Qgis::ProcessingNumberParameterType::Double, 50 ) );
420 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYSPREAD" ), QStringLiteral( "Function spread" ), Qgis::ProcessingNumberParameterType::Double, 5 ) );
421}
422
423bool QgsFuzzifyRasterLargeMembershipAlgorithm::prepareAlgorithmFuzzificationParameters( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
424{
425 Q_UNUSED( feedback )
426 mFuzzifyMidpoint = parameterAsDouble( parameters, QStringLiteral( "FUZZYMIDPOINT" ), context );
427 mFuzzifySpread = parameterAsDouble( parameters, QStringLiteral( "FUZZYSPREAD" ), context );
428 return true;
429}
430
431void QgsFuzzifyRasterLargeMembershipAlgorithm::fuzzify( QgsRasterDataProvider *destinationProvider, QgsProcessingFeedback *feedback )
432{
435 const int nbBlocksWidth = static_cast<int>( std::ceil( 1.0 * mLayerWidth / maxWidth ) );
436 const int nbBlocksHeight = static_cast<int>( std::ceil( 1.0 * mLayerHeight / maxHeight ) );
437 const int nbBlocks = nbBlocksWidth * nbBlocksHeight;
438
439 QgsRasterIterator iter( mInterface.get() );
440 iter.startRasterRead( mBand, mLayerWidth, mLayerHeight, mExtent );
441 int iterLeft = 0;
442 int iterTop = 0;
443 int iterCols = 0;
444 int iterRows = 0;
445 bool isNoData = false;
446 std::unique_ptr<QgsRasterBlock> rasterBlock;
447 while ( iter.readNextRasterPart( mBand, iterCols, iterRows, rasterBlock, iterLeft, iterTop ) )
448 {
449 if ( feedback )
450 feedback->setProgress( 100 * ( ( iterTop / maxHeight * nbBlocksWidth ) + iterLeft / maxWidth ) / nbBlocks );
451 auto fuzzifiedBlock = std::make_unique<QgsRasterBlock>( destinationProvider->dataType( 1 ), iterCols, iterRows );
452
453 for ( int row = 0; row < iterRows; row++ )
454 {
455 if ( feedback && feedback->isCanceled() )
456 break;
457 for ( int column = 0; column < iterCols; column++ )
458 {
459 if ( feedback && feedback->isCanceled() )
460 break;
461
462 const double value = rasterBlock->valueAndNoData( row, column, isNoData );
463 double fuzzifiedValue;
464
465 if ( isNoData )
466 {
467 fuzzifiedValue = mNoDataValue;
468 }
469 else
470 {
471 fuzzifiedValue = 1 / ( 1 + std::pow( value / mFuzzifyMidpoint, -mFuzzifySpread ) );
472 }
473
474 fuzzifiedBlock->setValue( row, column, fuzzifiedValue );
475 }
476 }
477 if ( !destinationProvider->writeBlock( fuzzifiedBlock.get(), mBand, iterLeft, iterTop ) )
478 {
479 throw QgsProcessingException( QObject::tr( "Could not write raster block: %1" ).arg( destinationProvider->error().summary() ) );
480 }
481 }
482}
483
484
485//
486// QgsFuzzfiyRasterSmallMembershipAlgorithm
487//
488
489QString QgsFuzzifyRasterSmallMembershipAlgorithm::name() const
490{
491 return QStringLiteral( "fuzzifyrastersmallmembership" );
492}
493
494QString QgsFuzzifyRasterSmallMembershipAlgorithm::displayName() const
495{
496 return QObject::tr( "Fuzzify raster (small membership)" );
497}
498
499QStringList QgsFuzzifyRasterSmallMembershipAlgorithm::tags() const
500{
501 return QObject::tr( "fuzzy logic,fuzzify,fuzzy,logic,small,membership" ).split( ',' );
502}
503
504
505QString QgsFuzzifyRasterSmallMembershipAlgorithm::shortHelpString() const
506{
507 return QObject::tr( "The Fuzzify raster (small membership) algorithm transforms an input raster "
508 "to a fuzzified raster and thereby assigns values between 0 and 1 following the "
509 "'small' fuzzy membership function. The value of 0 implies no membership with the "
510 "defined fuzzy set, a value of 1 depicts full membership. In between, the degree "
511 "of membership of raster values follows the 'small' membership function.\n\n"
512 "The 'small' function is constructed using two user-defined input raster values "
513 "which set the point of half membership (midpoint, results to 0.5) and a predefined "
514 "function spread which controls the function uptake.\n\n"
515 "This function is typically used when smaller input raster values should become members "
516 "of the fuzzy set more easily than higher values." );
517}
518
519QgsFuzzifyRasterSmallMembershipAlgorithm *QgsFuzzifyRasterSmallMembershipAlgorithm::createInstance() const
520{
521 return new QgsFuzzifyRasterSmallMembershipAlgorithm();
522}
523
524void QgsFuzzifyRasterSmallMembershipAlgorithm::addAlgorithmParams()
525{
526 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYMIDPOINT" ), QStringLiteral( "Function midpoint" ), Qgis::ProcessingNumberParameterType::Double, 50 ) );
527 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYSPREAD" ), QStringLiteral( "Function spread" ), Qgis::ProcessingNumberParameterType::Double, 5 ) );
528}
529
530bool QgsFuzzifyRasterSmallMembershipAlgorithm::prepareAlgorithmFuzzificationParameters( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
531{
532 Q_UNUSED( feedback )
533 mFuzzifyMidpoint = parameterAsDouble( parameters, QStringLiteral( "FUZZYMIDPOINT" ), context );
534 mFuzzifySpread = parameterAsDouble( parameters, QStringLiteral( "FUZZYSPREAD" ), context );
535 return true;
536}
537
538void QgsFuzzifyRasterSmallMembershipAlgorithm::fuzzify( QgsRasterDataProvider *destinationProvider, QgsProcessingFeedback *feedback )
539{
542 const int nbBlocksWidth = static_cast<int>( std::ceil( 1.0 * mLayerWidth / maxWidth ) );
543 const int nbBlocksHeight = static_cast<int>( std::ceil( 1.0 * mLayerHeight / maxHeight ) );
544 const int nbBlocks = nbBlocksWidth * nbBlocksHeight;
545
546 QgsRasterIterator iter( mInterface.get() );
547 iter.startRasterRead( mBand, mLayerWidth, mLayerHeight, mExtent );
548 int iterLeft = 0;
549 int iterTop = 0;
550 int iterCols = 0;
551 int iterRows = 0;
552 bool isNoData = false;
553 std::unique_ptr<QgsRasterBlock> rasterBlock;
554 while ( iter.readNextRasterPart( mBand, iterCols, iterRows, rasterBlock, iterLeft, iterTop ) )
555 {
556 if ( feedback )
557 feedback->setProgress( 100 * ( ( iterTop / maxHeight * nbBlocksWidth ) + iterLeft / maxWidth ) / nbBlocks );
558 auto fuzzifiedBlock = std::make_unique<QgsRasterBlock>( destinationProvider->dataType( 1 ), iterCols, iterRows );
559
560 for ( int row = 0; row < iterRows; row++ )
561 {
562 if ( feedback && feedback->isCanceled() )
563 break;
564 for ( int column = 0; column < iterCols; column++ )
565 {
566 if ( feedback && feedback->isCanceled() )
567 break;
568
569 const double value = rasterBlock->valueAndNoData( row, column, isNoData );
570 double fuzzifiedValue;
571
572 if ( isNoData )
573 {
574 fuzzifiedValue = mNoDataValue;
575 }
576 else
577 {
578 fuzzifiedValue = 1 / ( 1 + std::pow( value / mFuzzifyMidpoint, mFuzzifySpread ) );
579 }
580
581 fuzzifiedBlock->setValue( row, column, fuzzifiedValue );
582 }
583 }
584 if ( !destinationProvider->writeBlock( fuzzifiedBlock.get(), mBand, iterLeft, iterTop ) )
585 {
586 throw QgsProcessingException( QObject::tr( "Could not write raster block: %1" ).arg( destinationProvider->error().summary() ) );
587 }
588 }
589}
590
591
592//
593// QgsFuzzfiyRasterGaussianMembershipAlgorithm
594//
595
596QString QgsFuzzifyRasterGaussianMembershipAlgorithm::name() const
597{
598 return QStringLiteral( "fuzzifyrastergaussianmembership" );
599}
600
601QString QgsFuzzifyRasterGaussianMembershipAlgorithm::displayName() const
602{
603 return QObject::tr( "Fuzzify raster (gaussian membership)" );
604}
605
606QStringList QgsFuzzifyRasterGaussianMembershipAlgorithm::tags() const
607{
608 return QObject::tr( "fuzzy logic,fuzzify,fuzzy,logic,gaussian,membership" ).split( ',' );
609}
610
611
612QString QgsFuzzifyRasterGaussianMembershipAlgorithm::shortHelpString() const
613{
614 return QObject::tr( "The Fuzzify raster (gaussian membership) algorithm transforms an input raster "
615 "to a fuzzified raster and thereby assigns values between 0 and 1 following a "
616 "gaussian fuzzy membership function. The value of 0 implies no membership with the "
617 "defined fuzzy set, a value of 1 depicts full membership. In between, the degree "
618 "of membership of raster values follows a gaussian membership function.\n\n"
619 "The gaussian function is constructed using two user-defined input values "
620 "which set the midpoint of the gaussian function (midpoint, results to 1) and a "
621 "predefined function spread which controls the function spread.\n\n"
622 "This function is typically used when a certain range of raster values around a "
623 "predefined function midpoint should become members of the fuzzy set." );
624}
625
626QgsFuzzifyRasterGaussianMembershipAlgorithm *QgsFuzzifyRasterGaussianMembershipAlgorithm::createInstance() const
627{
628 return new QgsFuzzifyRasterGaussianMembershipAlgorithm();
629}
630
631void QgsFuzzifyRasterGaussianMembershipAlgorithm::addAlgorithmParams()
632{
633 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYMIDPOINT" ), QStringLiteral( "Function midpoint" ), Qgis::ProcessingNumberParameterType::Double, 10 ) );
634 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYSPREAD" ), QStringLiteral( "Function spread" ), Qgis::ProcessingNumberParameterType::Double, 0.01 ) );
635}
636
637bool QgsFuzzifyRasterGaussianMembershipAlgorithm::prepareAlgorithmFuzzificationParameters( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
638{
639 Q_UNUSED( feedback )
640 mFuzzifyMidpoint = parameterAsDouble( parameters, QStringLiteral( "FUZZYMIDPOINT" ), context );
641 mFuzzifySpread = parameterAsDouble( parameters, QStringLiteral( "FUZZYSPREAD" ), context );
642 return true;
643}
644
645void QgsFuzzifyRasterGaussianMembershipAlgorithm::fuzzify( QgsRasterDataProvider *destinationProvider, QgsProcessingFeedback *feedback )
646{
649 const int nbBlocksWidth = static_cast<int>( std::ceil( 1.0 * mLayerWidth / maxWidth ) );
650 const int nbBlocksHeight = static_cast<int>( std::ceil( 1.0 * mLayerHeight / maxHeight ) );
651 const int nbBlocks = nbBlocksWidth * nbBlocksHeight;
652
653 QgsRasterIterator iter( mInterface.get() );
654 iter.startRasterRead( mBand, mLayerWidth, mLayerHeight, mExtent );
655 int iterLeft = 0;
656 int iterTop = 0;
657 int iterCols = 0;
658 int iterRows = 0;
659 bool isNoData = false;
660 std::unique_ptr<QgsRasterBlock> rasterBlock;
661 while ( iter.readNextRasterPart( mBand, iterCols, iterRows, rasterBlock, iterLeft, iterTop ) )
662 {
663 if ( feedback )
664 feedback->setProgress( 100 * ( ( iterTop / maxHeight * nbBlocksWidth ) + iterLeft / maxWidth ) / nbBlocks );
665 auto fuzzifiedBlock = std::make_unique<QgsRasterBlock>( destinationProvider->dataType( 1 ), iterCols, iterRows );
666
667 for ( int row = 0; row < iterRows; row++ )
668 {
669 if ( feedback && feedback->isCanceled() )
670 break;
671 for ( int column = 0; column < iterCols; column++ )
672 {
673 if ( feedback && feedback->isCanceled() )
674 break;
675
676 const double value = rasterBlock->valueAndNoData( row, column, isNoData );
677 double fuzzifiedValue;
678
679 if ( isNoData )
680 {
681 fuzzifiedValue = mNoDataValue;
682 }
683 else
684 {
685 fuzzifiedValue = std::exp( -mFuzzifySpread * std::pow( value - mFuzzifyMidpoint, 2 ) );
686 }
687
688 fuzzifiedBlock->setValue( row, column, fuzzifiedValue );
689 }
690 }
691 if ( !destinationProvider->writeBlock( fuzzifiedBlock.get(), mBand, iterLeft, iterTop ) )
692 {
693 throw QgsProcessingException( QObject::tr( "Could not write raster block: %1" ).arg( destinationProvider->error().summary() ) );
694 }
695 }
696}
697
698
699//
700// QgsFuzzfiyRasterNearMembershipAlgorithm
701//
702
703QString QgsFuzzifyRasterNearMembershipAlgorithm::name() const
704{
705 return QStringLiteral( "fuzzifyrasternearmembership" );
706}
707
708QString QgsFuzzifyRasterNearMembershipAlgorithm::displayName() const
709{
710 return QObject::tr( "Fuzzify raster (near membership)" );
711}
712
713QStringList QgsFuzzifyRasterNearMembershipAlgorithm::tags() const
714{
715 return QObject::tr( "fuzzy logic,fuzzify,fuzzy,logic,near,membership" ).split( ',' );
716}
717
718
719QString QgsFuzzifyRasterNearMembershipAlgorithm::shortHelpString() const
720{
721 return QObject::tr( "The Fuzzify raster (near membership) algorithm transforms an input raster "
722 "to a fuzzified raster and thereby assigns values between 0 and 1 following the "
723 "'near' fuzzy membership function. The value of 0 implies no membership with the "
724 "defined fuzzy set, a value of 1 depicts full membership. In between, the degree "
725 "of membership of raster values follows the 'near' membership function.\n\n"
726 "The 'near' function is constructed using two user-defined input values "
727 "which set the midpoint of the 'near' function (midpoint, results to 1) and a "
728 "predefined function spread which controls the function spread.\n\n"
729 "This function is typically used when a certain range of raster values near a "
730 "predefined function midpoint should become members of the fuzzy set. The function"
731 " generally shows a higher rate of decay than the gaussian membership function." );
732}
733
734QgsFuzzifyRasterNearMembershipAlgorithm *QgsFuzzifyRasterNearMembershipAlgorithm::createInstance() const
735{
736 return new QgsFuzzifyRasterNearMembershipAlgorithm();
737}
738
739void QgsFuzzifyRasterNearMembershipAlgorithm::addAlgorithmParams()
740{
741 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYMIDPOINT" ), QStringLiteral( "Function midpoint" ), Qgis::ProcessingNumberParameterType::Double, 50 ) );
742 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYSPREAD" ), QStringLiteral( "Function spread" ), Qgis::ProcessingNumberParameterType::Double, 0.01 ) );
743}
744
745bool QgsFuzzifyRasterNearMembershipAlgorithm::prepareAlgorithmFuzzificationParameters( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
746{
747 Q_UNUSED( feedback )
748 mFuzzifyMidpoint = parameterAsDouble( parameters, QStringLiteral( "FUZZYMIDPOINT" ), context );
749 mFuzzifySpread = parameterAsDouble( parameters, QStringLiteral( "FUZZYSPREAD" ), context );
750 return true;
751}
752
753void QgsFuzzifyRasterNearMembershipAlgorithm::fuzzify( QgsRasterDataProvider *destinationProvider, QgsProcessingFeedback *feedback )
754{
757 const int nbBlocksWidth = static_cast<int>( std::ceil( 1.0 * mLayerWidth / maxWidth ) );
758 const int nbBlocksHeight = static_cast<int>( std::ceil( 1.0 * mLayerHeight / maxHeight ) );
759 const int nbBlocks = nbBlocksWidth * nbBlocksHeight;
760
761 QgsRasterIterator iter( mInterface.get() );
762 iter.startRasterRead( mBand, mLayerWidth, mLayerHeight, mExtent );
763 int iterLeft = 0;
764 int iterTop = 0;
765 int iterCols = 0;
766 int iterRows = 0;
767 bool isNoData = false;
768 std::unique_ptr<QgsRasterBlock> rasterBlock;
769 while ( iter.readNextRasterPart( mBand, iterCols, iterRows, rasterBlock, iterLeft, iterTop ) )
770 {
771 if ( feedback )
772 feedback->setProgress( 100 * ( ( iterTop / maxHeight * nbBlocksWidth ) + iterLeft / maxWidth ) / nbBlocks );
773 auto fuzzifiedBlock = std::make_unique<QgsRasterBlock>( destinationProvider->dataType( 1 ), iterCols, iterRows );
774
775 for ( int row = 0; row < iterRows; row++ )
776 {
777 if ( feedback && feedback->isCanceled() )
778 break;
779 for ( int column = 0; column < iterCols; column++ )
780 {
781 if ( feedback && feedback->isCanceled() )
782 break;
783
784 const double value = rasterBlock->valueAndNoData( row, column, isNoData );
785 double fuzzifiedValue;
786
787 if ( isNoData )
788 {
789 fuzzifiedValue = mNoDataValue;
790 }
791 else
792 {
793 fuzzifiedValue = 1 / ( 1 + mFuzzifySpread * std::pow( value - mFuzzifyMidpoint, 2 ) );
794 }
795
796 fuzzifiedBlock->setValue( row, column, fuzzifiedValue );
797 }
798 }
799 if ( !destinationProvider->writeBlock( fuzzifiedBlock.get(), mBand, iterLeft, iterTop ) )
800 {
801 throw QgsProcessingException( QObject::tr( "Could not write raster block: %1" ).arg( destinationProvider->error().summary() ) );
802 }
803 }
804}
805
806
@ Advanced
Parameter is an advanced parameter which should be hidden from users by default.
virtual QgsError error() const
Gets current status error.
QString summary() const
Short error description, usually the first error in chain, the real error.
Definition qgserror.cpp:129
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.
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:6767