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