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