QGIS API Documentation 3.43.0-Master (261ee7da134)
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
155QString QgsFuzzifyRasterLinearMembershipAlgorithm::shortDescription() const
156{
157 return QObject::tr( "Transforms an input raster to a fuzzified raster where values range from 0 to 1 following a "
158 "linear fuzzy membership function." );
159}
160
161QString QgsFuzzifyRasterLinearMembershipAlgorithm::shortHelpString() const
162{
163 return QObject::tr( "This algorithm transforms an input raster "
164 "to a fuzzified raster and thereby assigns values between 0 and 1 following a "
165 "linear fuzzy membership function. The value of 0 implies no membership with the "
166 "defined fuzzy set, a value of 1 depicts full membership. In between, the degree "
167 "of membership of raster values follows a linear membership function.\n\n"
168 "The linear function is constructed using two user-defined input raster values "
169 "which set the point of full membership (high bound, results to 1) and no membership "
170 "(low bound, results to 0) respectively. The fuzzy set in between those values is defined as a "
171 "linear function.\n\n"
172 "Both increasing and decreasing fuzzy sets can be modeled by "
173 "swapping the high and low bound parameters." );
174}
175
176QgsFuzzifyRasterLinearMembershipAlgorithm *QgsFuzzifyRasterLinearMembershipAlgorithm::createInstance() const
177{
178 return new QgsFuzzifyRasterLinearMembershipAlgorithm();
179}
180
181void QgsFuzzifyRasterLinearMembershipAlgorithm::addAlgorithmParams()
182{
183 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYLOWBOUND" ), QStringLiteral( "Low fuzzy membership bound" ), Qgis::ProcessingNumberParameterType::Double, 0 ) );
184 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYHIGHBOUND" ), QStringLiteral( "High fuzzy membership bound" ), Qgis::ProcessingNumberParameterType::Double, 1 ) );
185}
186
187bool QgsFuzzifyRasterLinearMembershipAlgorithm::prepareAlgorithmFuzzificationParameters( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
188{
189 Q_UNUSED( feedback )
190 mFuzzifyHighBound = parameterAsDouble( parameters, QStringLiteral( "FUZZYHIGHBOUND" ), context );
191 mFuzzifyLowBound = parameterAsDouble( parameters, QStringLiteral( "FUZZYLOWBOUND" ), context );
192 return true;
193}
194
195void QgsFuzzifyRasterLinearMembershipAlgorithm::fuzzify( QgsRasterDataProvider *destinationProvider, QgsProcessingFeedback *feedback )
196{
199 const int nbBlocksWidth = static_cast<int>( std::ceil( 1.0 * mLayerWidth / maxWidth ) );
200 const int nbBlocksHeight = static_cast<int>( std::ceil( 1.0 * mLayerHeight / maxHeight ) );
201 const int nbBlocks = nbBlocksWidth * nbBlocksHeight;
202
203 QgsRasterIterator iter( mInterface.get() );
204 iter.startRasterRead( mBand, mLayerWidth, mLayerHeight, mExtent );
205 int iterLeft = 0;
206 int iterTop = 0;
207 int iterCols = 0;
208 int iterRows = 0;
209 bool isNoData = false;
210 std::unique_ptr<QgsRasterBlock> rasterBlock;
211 while ( iter.readNextRasterPart( mBand, iterCols, iterRows, rasterBlock, iterLeft, iterTop ) )
212 {
213 if ( feedback )
214 feedback->setProgress( 100 * ( ( iterTop / maxHeight * nbBlocksWidth ) + iterLeft / maxWidth ) / nbBlocks );
215 auto fuzzifiedBlock = std::make_unique<QgsRasterBlock>( destinationProvider->dataType( 1 ), iterCols, iterRows );
216
217 for ( int row = 0; row < iterRows; row++ )
218 {
219 if ( feedback && feedback->isCanceled() )
220 break;
221 for ( int column = 0; column < iterCols; column++ )
222 {
223 if ( feedback && feedback->isCanceled() )
224 break;
225
226 const double value = rasterBlock->valueAndNoData( row, column, isNoData );
227 double fuzzifiedValue;
228
229 if ( isNoData )
230 {
231 fuzzifiedValue = mNoDataValue;
232 }
233 else if ( mFuzzifyLowBound < mFuzzifyHighBound )
234 {
235 if ( value <= mFuzzifyLowBound )
236 fuzzifiedValue = 0;
237 else if ( value >= mFuzzifyHighBound )
238 fuzzifiedValue = 1;
239 else
240 fuzzifiedValue = ( ( value - mFuzzifyLowBound ) / ( mFuzzifyHighBound - mFuzzifyLowBound ) );
241 }
242 else if ( mFuzzifyLowBound > mFuzzifyHighBound )
243 {
244 if ( value >= mFuzzifyLowBound )
245 fuzzifiedValue = 0;
246 else if ( value <= mFuzzifyHighBound )
247 fuzzifiedValue = 1;
248 else
249 fuzzifiedValue = ( ( value - mFuzzifyLowBound ) / ( mFuzzifyHighBound - mFuzzifyLowBound ) );
250 }
251 else
252 {
253 throw QgsProcessingException( QObject::tr( "Please choose varying values for the high and low membership parameters" ) );
254 }
255
256 fuzzifiedBlock->setValue( row, column, fuzzifiedValue );
257 }
258 }
259 if ( !destinationProvider->writeBlock( fuzzifiedBlock.get(), mBand, iterLeft, iterTop ) )
260 {
261 throw QgsProcessingException( QObject::tr( "Could not write raster block: %1" ).arg( destinationProvider->error().summary() ) );
262 }
263 }
264}
265
266
267//
268// QgsFuzzfiyRasterPowerMembershipAlgorithm
269//
270
271QString QgsFuzzifyRasterPowerMembershipAlgorithm::name() const
272{
273 return QStringLiteral( "fuzzifyrasterpowermembership" );
274}
275
276QString QgsFuzzifyRasterPowerMembershipAlgorithm::displayName() const
277{
278 return QObject::tr( "Fuzzify raster (power membership)" );
279}
280
281QStringList QgsFuzzifyRasterPowerMembershipAlgorithm::tags() const
282{
283 return QObject::tr( "fuzzy logic,fuzzify,fuzzy,logic,power,non-linear,membership,exponent" ).split( ',' );
284}
285
286QString QgsFuzzifyRasterPowerMembershipAlgorithm::shortDescription() const
287{
288 return QObject::tr( "Transforms an input raster to a fuzzified raster where values range from 0 to 1 following a "
289 "power function." );
290}
291
292QString QgsFuzzifyRasterPowerMembershipAlgorithm::shortHelpString() const
293{
294 return QObject::tr( "This algorithm transforms an input raster "
295 "to a fuzzified raster and thereby assigns values between 0 and 1 following a "
296 "power function. The value of 0 implies no membership with the "
297 "defined fuzzy set, a value of 1 depicts full membership. In between, the degree "
298 "of membership of raster values follows a power function.\n\n"
299 "The power function is constructed using three user-defined input raster values "
300 "which set the point of full membership (high bound, results to 1), no membership "
301 "(low bound, results to 0) and function exponent (only positive) respectively. "
302 "The fuzzy set in between those the upper and lower bounds values is then defined as "
303 "a power function.\n\n"
304 "Both increasing and decreasing fuzzy sets can be modeled by "
305 "swapping the high and low bound parameters." );
306}
307
308QgsFuzzifyRasterPowerMembershipAlgorithm *QgsFuzzifyRasterPowerMembershipAlgorithm::createInstance() const
309{
310 return new QgsFuzzifyRasterPowerMembershipAlgorithm();
311}
312
313void QgsFuzzifyRasterPowerMembershipAlgorithm::addAlgorithmParams()
314{
315 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYLOWBOUND" ), QStringLiteral( "Low fuzzy membership bound" ), Qgis::ProcessingNumberParameterType::Double, 0 ) );
316 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYHIGHBOUND" ), QStringLiteral( "High fuzzy membership bound" ), Qgis::ProcessingNumberParameterType::Double, 1 ) );
317 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYEXPONENT" ), QStringLiteral( "Membership function exponent" ), Qgis::ProcessingNumberParameterType::Double, 2, false, 0 ) );
318}
319
320bool QgsFuzzifyRasterPowerMembershipAlgorithm::prepareAlgorithmFuzzificationParameters( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
321{
322 Q_UNUSED( feedback )
323 mFuzzifyHighBound = parameterAsDouble( parameters, QStringLiteral( "FUZZYHIGHBOUND" ), context );
324 mFuzzifyLowBound = parameterAsDouble( parameters, QStringLiteral( "FUZZYLOWBOUND" ), context );
325 mFuzzifyExponent = parameterAsDouble( parameters, QStringLiteral( "FUZZYEXPONENT" ), context );
326 return true;
327}
328
329void QgsFuzzifyRasterPowerMembershipAlgorithm::fuzzify( QgsRasterDataProvider *destinationProvider, QgsProcessingFeedback *feedback )
330{
333 const int nbBlocksWidth = static_cast<int>( std::ceil( 1.0 * mLayerWidth / maxWidth ) );
334 const int nbBlocksHeight = static_cast<int>( std::ceil( 1.0 * mLayerHeight / maxHeight ) );
335 const int nbBlocks = nbBlocksWidth * nbBlocksHeight;
336
337 QgsRasterIterator iter( mInterface.get() );
338 iter.startRasterRead( mBand, mLayerWidth, mLayerHeight, mExtent );
339 int iterLeft = 0;
340 int iterTop = 0;
341 int iterCols = 0;
342 int iterRows = 0;
343 bool isNoData = false;
344 std::unique_ptr<QgsRasterBlock> rasterBlock;
345 while ( iter.readNextRasterPart( mBand, iterCols, iterRows, rasterBlock, iterLeft, iterTop ) )
346 {
347 if ( feedback )
348 feedback->setProgress( 100 * ( ( iterTop / maxHeight * nbBlocksWidth ) + iterLeft / maxWidth ) / nbBlocks );
349 auto fuzzifiedBlock = std::make_unique<QgsRasterBlock>( destinationProvider->dataType( 1 ), iterCols, iterRows );
350
351 for ( int row = 0; row < iterRows; row++ )
352 {
353 if ( feedback && feedback->isCanceled() )
354 break;
355 for ( int column = 0; column < iterCols; column++ )
356 {
357 if ( feedback && feedback->isCanceled() )
358 break;
359
360 const double value = rasterBlock->valueAndNoData( row, column, isNoData );
361 double fuzzifiedValue;
362
363 if ( isNoData )
364 {
365 fuzzifiedValue = mNoDataValue;
366 }
367 else if ( mFuzzifyLowBound < mFuzzifyHighBound )
368 {
369 if ( value <= mFuzzifyLowBound )
370 fuzzifiedValue = 0;
371 else if ( value >= mFuzzifyHighBound )
372 fuzzifiedValue = 1;
373 else
374 fuzzifiedValue = std::pow( ( value - mFuzzifyLowBound ) / ( mFuzzifyHighBound - mFuzzifyLowBound ), mFuzzifyExponent );
375 }
376 else if ( mFuzzifyLowBound > mFuzzifyHighBound )
377 {
378 if ( value >= mFuzzifyLowBound )
379 fuzzifiedValue = 0;
380 else if ( value <= mFuzzifyHighBound )
381 fuzzifiedValue = 1;
382 else
383 fuzzifiedValue = std::pow( ( value - mFuzzifyLowBound ) / ( mFuzzifyHighBound - mFuzzifyLowBound ), mFuzzifyExponent );
384 }
385 else
386 {
387 throw QgsProcessingException( QObject::tr( "Please choose varying values for the high and low membership parameters" ) );
388 }
389
390 fuzzifiedBlock->setValue( row, column, fuzzifiedValue );
391 }
392 }
393 if ( !destinationProvider->writeBlock( fuzzifiedBlock.get(), mBand, iterLeft, iterTop ) )
394 {
395 throw QgsProcessingException( QObject::tr( "Could not write raster block: %1" ).arg( destinationProvider->error().summary() ) );
396 }
397 }
398}
399
400//
401// QgsFuzzfiyRasterLargeMembershipAlgorithm
402//
403
404QString QgsFuzzifyRasterLargeMembershipAlgorithm::name() const
405{
406 return QStringLiteral( "fuzzifyrasterlargemembership" );
407}
408
409QString QgsFuzzifyRasterLargeMembershipAlgorithm::displayName() const
410{
411 return QObject::tr( "Fuzzify raster (large membership)" );
412}
413
414QStringList QgsFuzzifyRasterLargeMembershipAlgorithm::tags() const
415{
416 return QObject::tr( "fuzzy logic,fuzzify,fuzzy,logic,large,membership" ).split( ',' );
417}
418
419QString QgsFuzzifyRasterLargeMembershipAlgorithm::shortDescription() const
420{
421 return QObject::tr( "Transforms an input raster to a fuzzified raster where values range from 0 to 1 following the "
422 "'large' fuzzy membership function." );
423}
424
425QString QgsFuzzifyRasterLargeMembershipAlgorithm::shortHelpString() const
426{
427 return QObject::tr( "This algorithm transforms an input raster "
428 "to a fuzzified raster and thereby assigns values between 0 and 1 following the "
429 "'large' fuzzy membership function. The value of 0 implies no membership with the "
430 "defined fuzzy set, a value of 1 depicts full membership. In between, the degree "
431 "of membership of raster values follows the 'large' membership function.\n\n"
432 "The 'large' function is constructed using two user-defined input raster values "
433 "which set the point of half membership (midpoint, results to 0.5) and a predefined "
434 "function spread which controls the function uptake.\n\n"
435 "This function is typically used when larger input raster values should become members "
436 "of the fuzzy set more easily than smaller values." );
437}
438
439QgsFuzzifyRasterLargeMembershipAlgorithm *QgsFuzzifyRasterLargeMembershipAlgorithm::createInstance() const
440{
441 return new QgsFuzzifyRasterLargeMembershipAlgorithm();
442}
443
444void QgsFuzzifyRasterLargeMembershipAlgorithm::addAlgorithmParams()
445{
446 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYMIDPOINT" ), QStringLiteral( "Function midpoint" ), Qgis::ProcessingNumberParameterType::Double, 50 ) );
447 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYSPREAD" ), QStringLiteral( "Function spread" ), Qgis::ProcessingNumberParameterType::Double, 5 ) );
448}
449
450bool QgsFuzzifyRasterLargeMembershipAlgorithm::prepareAlgorithmFuzzificationParameters( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
451{
452 Q_UNUSED( feedback )
453 mFuzzifyMidpoint = parameterAsDouble( parameters, QStringLiteral( "FUZZYMIDPOINT" ), context );
454 mFuzzifySpread = parameterAsDouble( parameters, QStringLiteral( "FUZZYSPREAD" ), context );
455 return true;
456}
457
458void QgsFuzzifyRasterLargeMembershipAlgorithm::fuzzify( QgsRasterDataProvider *destinationProvider, QgsProcessingFeedback *feedback )
459{
462 const int nbBlocksWidth = static_cast<int>( std::ceil( 1.0 * mLayerWidth / maxWidth ) );
463 const int nbBlocksHeight = static_cast<int>( std::ceil( 1.0 * mLayerHeight / maxHeight ) );
464 const int nbBlocks = nbBlocksWidth * nbBlocksHeight;
465
466 QgsRasterIterator iter( mInterface.get() );
467 iter.startRasterRead( mBand, mLayerWidth, mLayerHeight, mExtent );
468 int iterLeft = 0;
469 int iterTop = 0;
470 int iterCols = 0;
471 int iterRows = 0;
472 bool isNoData = false;
473 std::unique_ptr<QgsRasterBlock> rasterBlock;
474 while ( iter.readNextRasterPart( mBand, iterCols, iterRows, rasterBlock, iterLeft, iterTop ) )
475 {
476 if ( feedback )
477 feedback->setProgress( 100 * ( ( iterTop / maxHeight * nbBlocksWidth ) + iterLeft / maxWidth ) / nbBlocks );
478 auto fuzzifiedBlock = std::make_unique<QgsRasterBlock>( destinationProvider->dataType( 1 ), iterCols, iterRows );
479
480 for ( int row = 0; row < iterRows; row++ )
481 {
482 if ( feedback && feedback->isCanceled() )
483 break;
484 for ( int column = 0; column < iterCols; column++ )
485 {
486 if ( feedback && feedback->isCanceled() )
487 break;
488
489 const double value = rasterBlock->valueAndNoData( row, column, isNoData );
490 double fuzzifiedValue;
491
492 if ( isNoData )
493 {
494 fuzzifiedValue = mNoDataValue;
495 }
496 else
497 {
498 fuzzifiedValue = 1 / ( 1 + std::pow( value / mFuzzifyMidpoint, -mFuzzifySpread ) );
499 }
500
501 fuzzifiedBlock->setValue( row, column, fuzzifiedValue );
502 }
503 }
504 if ( !destinationProvider->writeBlock( fuzzifiedBlock.get(), mBand, iterLeft, iterTop ) )
505 {
506 throw QgsProcessingException( QObject::tr( "Could not write raster block: %1" ).arg( destinationProvider->error().summary() ) );
507 }
508 }
509}
510
511
512//
513// QgsFuzzfiyRasterSmallMembershipAlgorithm
514//
515
516QString QgsFuzzifyRasterSmallMembershipAlgorithm::name() const
517{
518 return QStringLiteral( "fuzzifyrastersmallmembership" );
519}
520
521QString QgsFuzzifyRasterSmallMembershipAlgorithm::displayName() const
522{
523 return QObject::tr( "Fuzzify raster (small membership)" );
524}
525
526QStringList QgsFuzzifyRasterSmallMembershipAlgorithm::tags() const
527{
528 return QObject::tr( "fuzzy logic,fuzzify,fuzzy,logic,small,membership" ).split( ',' );
529}
530
531QString QgsFuzzifyRasterSmallMembershipAlgorithm::shortDescription() const
532{
533 return QObject::tr( "Transforms an input raster to a fuzzified raster where values range from 0 to 1 following the "
534 "'small' fuzzy membership function." );
535}
536
537QString QgsFuzzifyRasterSmallMembershipAlgorithm::shortHelpString() const
538{
539 return QObject::tr( "The Fuzzify raster (small membership) algorithm transforms an input raster "
540 "to a fuzzified raster and thereby assigns values between 0 and 1 following the "
541 "'small' fuzzy membership function. The value of 0 implies no membership with the "
542 "defined fuzzy set, a value of 1 depicts full membership. In between, the degree "
543 "of membership of raster values follows the 'small' membership function.\n\n"
544 "The 'small' function is constructed using two user-defined input raster values "
545 "which set the point of half membership (midpoint, results to 0.5) and a predefined "
546 "function spread which controls the function uptake.\n\n"
547 "This function is typically used when smaller input raster values should become members "
548 "of the fuzzy set more easily than higher values." );
549}
550
551QgsFuzzifyRasterSmallMembershipAlgorithm *QgsFuzzifyRasterSmallMembershipAlgorithm::createInstance() const
552{
553 return new QgsFuzzifyRasterSmallMembershipAlgorithm();
554}
555
556void QgsFuzzifyRasterSmallMembershipAlgorithm::addAlgorithmParams()
557{
558 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYMIDPOINT" ), QStringLiteral( "Function midpoint" ), Qgis::ProcessingNumberParameterType::Double, 50 ) );
559 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYSPREAD" ), QStringLiteral( "Function spread" ), Qgis::ProcessingNumberParameterType::Double, 5 ) );
560}
561
562bool QgsFuzzifyRasterSmallMembershipAlgorithm::prepareAlgorithmFuzzificationParameters( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
563{
564 Q_UNUSED( feedback )
565 mFuzzifyMidpoint = parameterAsDouble( parameters, QStringLiteral( "FUZZYMIDPOINT" ), context );
566 mFuzzifySpread = parameterAsDouble( parameters, QStringLiteral( "FUZZYSPREAD" ), context );
567 return true;
568}
569
570void QgsFuzzifyRasterSmallMembershipAlgorithm::fuzzify( QgsRasterDataProvider *destinationProvider, QgsProcessingFeedback *feedback )
571{
574 const int nbBlocksWidth = static_cast<int>( std::ceil( 1.0 * mLayerWidth / maxWidth ) );
575 const int nbBlocksHeight = static_cast<int>( std::ceil( 1.0 * mLayerHeight / maxHeight ) );
576 const int nbBlocks = nbBlocksWidth * nbBlocksHeight;
577
578 QgsRasterIterator iter( mInterface.get() );
579 iter.startRasterRead( mBand, mLayerWidth, mLayerHeight, mExtent );
580 int iterLeft = 0;
581 int iterTop = 0;
582 int iterCols = 0;
583 int iterRows = 0;
584 bool isNoData = false;
585 std::unique_ptr<QgsRasterBlock> rasterBlock;
586 while ( iter.readNextRasterPart( mBand, iterCols, iterRows, rasterBlock, iterLeft, iterTop ) )
587 {
588 if ( feedback )
589 feedback->setProgress( 100 * ( ( iterTop / maxHeight * nbBlocksWidth ) + iterLeft / maxWidth ) / nbBlocks );
590 auto fuzzifiedBlock = std::make_unique<QgsRasterBlock>( destinationProvider->dataType( 1 ), iterCols, iterRows );
591
592 for ( int row = 0; row < iterRows; row++ )
593 {
594 if ( feedback && feedback->isCanceled() )
595 break;
596 for ( int column = 0; column < iterCols; column++ )
597 {
598 if ( feedback && feedback->isCanceled() )
599 break;
600
601 const double value = rasterBlock->valueAndNoData( row, column, isNoData );
602 double fuzzifiedValue;
603
604 if ( isNoData )
605 {
606 fuzzifiedValue = mNoDataValue;
607 }
608 else
609 {
610 fuzzifiedValue = 1 / ( 1 + std::pow( value / mFuzzifyMidpoint, mFuzzifySpread ) );
611 }
612
613 fuzzifiedBlock->setValue( row, column, fuzzifiedValue );
614 }
615 }
616 if ( !destinationProvider->writeBlock( fuzzifiedBlock.get(), mBand, iterLeft, iterTop ) )
617 {
618 throw QgsProcessingException( QObject::tr( "Could not write raster block: %1" ).arg( destinationProvider->error().summary() ) );
619 }
620 }
621}
622
623
624//
625// QgsFuzzfiyRasterGaussianMembershipAlgorithm
626//
627
628QString QgsFuzzifyRasterGaussianMembershipAlgorithm::name() const
629{
630 return QStringLiteral( "fuzzifyrastergaussianmembership" );
631}
632
633QString QgsFuzzifyRasterGaussianMembershipAlgorithm::displayName() const
634{
635 return QObject::tr( "Fuzzify raster (gaussian membership)" );
636}
637
638QStringList QgsFuzzifyRasterGaussianMembershipAlgorithm::tags() const
639{
640 return QObject::tr( "fuzzy logic,fuzzify,fuzzy,logic,gaussian,membership" ).split( ',' );
641}
642
643QString QgsFuzzifyRasterGaussianMembershipAlgorithm::shortDescription() const
644{
645 return QObject::tr( "Transforms an input raster to a fuzzified raster where values range from 0 to 1 following a "
646 "gaussian fuzzy membership function." );
647}
648
649QString QgsFuzzifyRasterGaussianMembershipAlgorithm::shortHelpString() const
650{
651 return QObject::tr( "This algorithm transforms an input raster "
652 "to a fuzzified raster and thereby assigns values between 0 and 1 following a "
653 "gaussian fuzzy membership function. The value of 0 implies no membership with the "
654 "defined fuzzy set, a value of 1 depicts full membership. In between, the degree "
655 "of membership of raster values follows a gaussian membership function.\n\n"
656 "The gaussian function is constructed using two user-defined input values "
657 "which set the midpoint of the gaussian function (midpoint, results to 1) and a "
658 "predefined function spread which controls the function spread.\n\n"
659 "This function is typically used when a certain range of raster values around a "
660 "predefined function midpoint should become members of the fuzzy set." );
661}
662
663QgsFuzzifyRasterGaussianMembershipAlgorithm *QgsFuzzifyRasterGaussianMembershipAlgorithm::createInstance() const
664{
665 return new QgsFuzzifyRasterGaussianMembershipAlgorithm();
666}
667
668void QgsFuzzifyRasterGaussianMembershipAlgorithm::addAlgorithmParams()
669{
670 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYMIDPOINT" ), QStringLiteral( "Function midpoint" ), Qgis::ProcessingNumberParameterType::Double, 10 ) );
671 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYSPREAD" ), QStringLiteral( "Function spread" ), Qgis::ProcessingNumberParameterType::Double, 0.01 ) );
672}
673
674bool QgsFuzzifyRasterGaussianMembershipAlgorithm::prepareAlgorithmFuzzificationParameters( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
675{
676 Q_UNUSED( feedback )
677 mFuzzifyMidpoint = parameterAsDouble( parameters, QStringLiteral( "FUZZYMIDPOINT" ), context );
678 mFuzzifySpread = parameterAsDouble( parameters, QStringLiteral( "FUZZYSPREAD" ), context );
679 return true;
680}
681
682void QgsFuzzifyRasterGaussianMembershipAlgorithm::fuzzify( QgsRasterDataProvider *destinationProvider, QgsProcessingFeedback *feedback )
683{
686 const int nbBlocksWidth = static_cast<int>( std::ceil( 1.0 * mLayerWidth / maxWidth ) );
687 const int nbBlocksHeight = static_cast<int>( std::ceil( 1.0 * mLayerHeight / maxHeight ) );
688 const int nbBlocks = nbBlocksWidth * nbBlocksHeight;
689
690 QgsRasterIterator iter( mInterface.get() );
691 iter.startRasterRead( mBand, mLayerWidth, mLayerHeight, mExtent );
692 int iterLeft = 0;
693 int iterTop = 0;
694 int iterCols = 0;
695 int iterRows = 0;
696 bool isNoData = false;
697 std::unique_ptr<QgsRasterBlock> rasterBlock;
698 while ( iter.readNextRasterPart( mBand, iterCols, iterRows, rasterBlock, iterLeft, iterTop ) )
699 {
700 if ( feedback )
701 feedback->setProgress( 100 * ( ( iterTop / maxHeight * nbBlocksWidth ) + iterLeft / maxWidth ) / nbBlocks );
702 auto fuzzifiedBlock = std::make_unique<QgsRasterBlock>( destinationProvider->dataType( 1 ), iterCols, iterRows );
703
704 for ( int row = 0; row < iterRows; row++ )
705 {
706 if ( feedback && feedback->isCanceled() )
707 break;
708 for ( int column = 0; column < iterCols; column++ )
709 {
710 if ( feedback && feedback->isCanceled() )
711 break;
712
713 const double value = rasterBlock->valueAndNoData( row, column, isNoData );
714 double fuzzifiedValue;
715
716 if ( isNoData )
717 {
718 fuzzifiedValue = mNoDataValue;
719 }
720 else
721 {
722 fuzzifiedValue = std::exp( -mFuzzifySpread * std::pow( value - mFuzzifyMidpoint, 2 ) );
723 }
724
725 fuzzifiedBlock->setValue( row, column, fuzzifiedValue );
726 }
727 }
728 if ( !destinationProvider->writeBlock( fuzzifiedBlock.get(), mBand, iterLeft, iterTop ) )
729 {
730 throw QgsProcessingException( QObject::tr( "Could not write raster block: %1" ).arg( destinationProvider->error().summary() ) );
731 }
732 }
733}
734
735
736//
737// QgsFuzzfiyRasterNearMembershipAlgorithm
738//
739
740QString QgsFuzzifyRasterNearMembershipAlgorithm::name() const
741{
742 return QStringLiteral( "fuzzifyrasternearmembership" );
743}
744
745QString QgsFuzzifyRasterNearMembershipAlgorithm::displayName() const
746{
747 return QObject::tr( "Fuzzify raster (near membership)" );
748}
749
750QStringList QgsFuzzifyRasterNearMembershipAlgorithm::tags() const
751{
752 return QObject::tr( "fuzzy logic,fuzzify,fuzzy,logic,near,membership" ).split( ',' );
753}
754
755QString QgsFuzzifyRasterNearMembershipAlgorithm::shortDescription() const
756{
757 return QObject::tr( "Transforms an input raster to a fuzzified raster where values range from 0 to 1 following the "
758 "'near' fuzzy membership function." );
759}
760
761QString QgsFuzzifyRasterNearMembershipAlgorithm::shortHelpString() const
762{
763 return QObject::tr( "The Fuzzify raster (near membership) algorithm transforms an input raster "
764 "to a fuzzified raster and thereby assigns values between 0 and 1 following the "
765 "'near' fuzzy membership function. The value of 0 implies no membership with the "
766 "defined fuzzy set, a value of 1 depicts full membership. In between, the degree "
767 "of membership of raster values follows the 'near' membership function.\n\n"
768 "The 'near' function is constructed using two user-defined input values "
769 "which set the midpoint of the 'near' function (midpoint, results to 1) and a "
770 "predefined function spread which controls the function spread.\n\n"
771 "This function is typically used when a certain range of raster values near a "
772 "predefined function midpoint should become members of the fuzzy set. The function"
773 " generally shows a higher rate of decay than the gaussian membership function." );
774}
775
776QgsFuzzifyRasterNearMembershipAlgorithm *QgsFuzzifyRasterNearMembershipAlgorithm::createInstance() const
777{
778 return new QgsFuzzifyRasterNearMembershipAlgorithm();
779}
780
781void QgsFuzzifyRasterNearMembershipAlgorithm::addAlgorithmParams()
782{
783 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYMIDPOINT" ), QStringLiteral( "Function midpoint" ), Qgis::ProcessingNumberParameterType::Double, 50 ) );
784 addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FUZZYSPREAD" ), QStringLiteral( "Function spread" ), Qgis::ProcessingNumberParameterType::Double, 0.01 ) );
785}
786
787bool QgsFuzzifyRasterNearMembershipAlgorithm::prepareAlgorithmFuzzificationParameters( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
788{
789 Q_UNUSED( feedback )
790 mFuzzifyMidpoint = parameterAsDouble( parameters, QStringLiteral( "FUZZYMIDPOINT" ), context );
791 mFuzzifySpread = parameterAsDouble( parameters, QStringLiteral( "FUZZYSPREAD" ), context );
792 return true;
793}
794
795void QgsFuzzifyRasterNearMembershipAlgorithm::fuzzify( QgsRasterDataProvider *destinationProvider, QgsProcessingFeedback *feedback )
796{
799 const int nbBlocksWidth = static_cast<int>( std::ceil( 1.0 * mLayerWidth / maxWidth ) );
800 const int nbBlocksHeight = static_cast<int>( std::ceil( 1.0 * mLayerHeight / maxHeight ) );
801 const int nbBlocks = nbBlocksWidth * nbBlocksHeight;
802
803 QgsRasterIterator iter( mInterface.get() );
804 iter.startRasterRead( mBand, mLayerWidth, mLayerHeight, mExtent );
805 int iterLeft = 0;
806 int iterTop = 0;
807 int iterCols = 0;
808 int iterRows = 0;
809 bool isNoData = false;
810 std::unique_ptr<QgsRasterBlock> rasterBlock;
811 while ( iter.readNextRasterPart( mBand, iterCols, iterRows, rasterBlock, iterLeft, iterTop ) )
812 {
813 if ( feedback )
814 feedback->setProgress( 100 * ( ( iterTop / maxHeight * nbBlocksWidth ) + iterLeft / maxWidth ) / nbBlocks );
815 auto fuzzifiedBlock = std::make_unique<QgsRasterBlock>( destinationProvider->dataType( 1 ), iterCols, iterRows );
816
817 for ( int row = 0; row < iterRows; row++ )
818 {
819 if ( feedback && feedback->isCanceled() )
820 break;
821 for ( int column = 0; column < iterCols; column++ )
822 {
823 if ( feedback && feedback->isCanceled() )
824 break;
825
826 const double value = rasterBlock->valueAndNoData( row, column, isNoData );
827 double fuzzifiedValue;
828
829 if ( isNoData )
830 {
831 fuzzifiedValue = mNoDataValue;
832 }
833 else
834 {
835 fuzzifiedValue = 1 / ( 1 + mFuzzifySpread * std::pow( value - mFuzzifyMidpoint, 2 ) );
836 }
837
838 fuzzifiedBlock->setValue( row, column, fuzzifiedValue );
839 }
840 }
841 if ( !destinationProvider->writeBlock( fuzzifiedBlock.get(), mBand, iterLeft, iterTop ) )
842 {
843 throw QgsProcessingException( QObject::tr( "Could not write raster block: %1" ).arg( destinationProvider->error().summary() ) );
844 }
845 }
846}
847
848
@ 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:6826