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