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