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