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