QGIS API Documentation 3.99.0-Master (752b475928d)
Loading...
Searching...
No Matches
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
20#include "qgsrasterfilewriter.h"
21#include "qgsstringutils.h"
22
24
25//
26// QgsFuzzifyRasterAlgorithmBase
27//
28
29QString QgsFuzzifyRasterAlgorithmBase::group() const
30{
31 return QObject::tr( "Raster analysis" );
32}
33
34QString QgsFuzzifyRasterAlgorithmBase::groupId() const
35{
36 return QStringLiteral( "rasteranalysis" );
37}
38
39void QgsFuzzifyRasterAlgorithmBase::initAlgorithm( const QVariantMap & )
40{
41 addParameter( new QgsProcessingParameterRasterLayer( QStringLiteral( "INPUT" ), QObject::tr( "Input Raster" ) ) );
42 addParameter( new QgsProcessingParameterBand( QStringLiteral( "BAND" ), QObject::tr( "Band Number" ), 1, QStringLiteral( "INPUT" ) ) );
43
44 //add specific fuzzification parameters from subclass alg
45 addAlgorithmParams();
46
47 addOutput( new QgsProcessingOutputString( QStringLiteral( "EXTENT" ), QObject::tr( "Extent" ) ) );
48 addOutput( new QgsProcessingOutputString( QStringLiteral( "CRS_AUTHID" ), QObject::tr( "CRS authority identifier" ) ) );
49 addOutput( new QgsProcessingOutputNumber( QStringLiteral( "WIDTH_IN_PIXELS" ), QObject::tr( "Width in pixels" ) ) );
50 addOutput( new QgsProcessingOutputNumber( QStringLiteral( "HEIGHT_IN_PIXELS" ), QObject::tr( "Height in pixels" ) ) );
51 addOutput( new QgsProcessingOutputNumber( QStringLiteral( "TOTAL_PIXEL_COUNT" ), QObject::tr( "Total pixel count" ) ) );
52
53 // backwards compatibility parameter
54 // TODO QGIS 4: remove parameter and related logic
55 auto createOptsParam = std::make_unique<QgsProcessingParameterString>( QStringLiteral( "CREATE_OPTIONS" ), QObject::tr( "Creation options" ), QVariant(), false, true );
56 createOptsParam->setMetadata( QVariantMap( { { QStringLiteral( "widget_wrapper" ), QVariantMap( { { QStringLiteral( "widget_type" ), QStringLiteral( "rasteroptions" ) } } ) } } ) );
57 createOptsParam->setFlags( createOptsParam->flags() | Qgis::ProcessingParameterFlag::Hidden );
58 addParameter( createOptsParam.release() );
59
60 auto creationOptsParam = std::make_unique<QgsProcessingParameterString>( QStringLiteral( "CREATION_OPTIONS" ), QObject::tr( "Creation options" ), QVariant(), false, true );
61 creationOptsParam->setMetadata( QVariantMap( { { QStringLiteral( "widget_wrapper" ), QVariantMap( { { QStringLiteral( "widget_type" ), QStringLiteral( "rasteroptions" ) } } ) } } ) );
62 creationOptsParam->setFlags( creationOptsParam->flags() | Qgis::ProcessingParameterFlag::Advanced );
63 addParameter( creationOptsParam.release() );
64
65 addParameter( new QgsProcessingParameterRasterDestination( QStringLiteral( "OUTPUT" ), QObject::tr( "Fuzzified raster" ) ) );
66}
67
68bool QgsFuzzifyRasterAlgorithmBase::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
69{
70 mInputRaster = parameterAsRasterLayer( parameters, QStringLiteral( "INPUT" ), context );
71
72 if ( !mInputRaster )
73 throw QgsProcessingException( invalidRasterError( parameters, QStringLiteral( "INPUT" ) ) );
74
75 mBand = parameterAsInt( parameters, QStringLiteral( "BAND" ), context );
76 if ( mBand < 1 || mBand > mInputRaster->bandCount() )
77 throw QgsProcessingException( QObject::tr( "Invalid band number for BAND (%1): Valid values for input raster are 1 to %2" ).arg( mBand ).arg( mInputRaster->bandCount() ) );
78
79 mInterface.reset( mInputRaster->dataProvider()->clone() );
80 mExtent = mInputRaster->extent();
81 mLayerWidth = mInputRaster->width();
82 mLayerHeight = mInputRaster->height();
83 mCrs = mInputRaster->crs();
84 mNbCellsXProvider = mInterface->xSize();
85 mNbCellsYProvider = mInterface->ySize();
86
87 //prepare fuzzifcation parameters from subclass alg
88 prepareAlgorithmFuzzificationParameters( parameters, context, feedback );
89
90 return true;
91}
92
93QVariantMap QgsFuzzifyRasterAlgorithmBase::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
94{
95 QString creationOptions = parameterAsString( parameters, QStringLiteral( "CREATION_OPTIONS" ), context ).trimmed();
96 // handle backwards compatibility parameter CREATE_OPTIONS
97 const QString optionsString = parameterAsString( parameters, QStringLiteral( "CREATE_OPTIONS" ), context );
98 if ( !optionsString.isEmpty() )
99 creationOptions = optionsString;
100
101 const QString outputFile = parameterAsOutputLayer( parameters, QStringLiteral( "OUTPUT" ), context );
102 const QString outputFormat = parameterAsOutputRasterFormat( parameters, QStringLiteral( "OUTPUT" ), context );
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.
Definition qgis.h:3764
@ Advanced
Parameter is an advanced parameter which should be hidden from users by default.
Definition qgis.h:3763
@ Double
Double/float values.
Definition qgis.h:3804
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:130
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.
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:7142