Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgsreclassifyutils.cpp 3 : : --------------------- 4 : : begin : June, 2018 5 : : copyright : (C) 2018 by Nyall Dawson 6 : : email : nyall dot dawson 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 "qgsreclassifyutils.h" 19 : : #include "qgsrasterinterface.h" 20 : : #include "qgsrasteriterator.h" 21 : : #include "qgsrasterblock.h" 22 : : #include "qgsprocessingfeedback.h" 23 : : #include "qgsrasterdataprovider.h" 24 : : 25 : : #include "qgis.h" 26 : : 27 : : ///@cond PRIVATE 28 : : 29 : 0 : void QgsReclassifyUtils::reportClasses( const QVector<QgsReclassifyUtils::RasterClass> &classes, QgsProcessingFeedback *feedback ) 30 : : { 31 : 0 : int i = 1; 32 : 0 : feedback->pushInfo( QObject::tr( "Using classes:" ) ); 33 : 0 : for ( const RasterClass &c : classes ) 34 : : { 35 : 0 : feedback->pushInfo( QStringLiteral( " %1) %2 %3 %4" ).arg( i ) 36 : 0 : .arg( c.asText() ) 37 : 0 : .arg( QChar( 0x2192 ) ) 38 : 0 : .arg( c.value ) ); 39 : 0 : i++; 40 : : } 41 : 0 : } 42 : : 43 : 0 : void QgsReclassifyUtils::checkForOverlaps( const QVector<QgsReclassifyUtils::RasterClass> &classes, QgsProcessingFeedback *feedback ) 44 : : { 45 : : // test each class against each other class 46 : 0 : for ( int i = 0; i < classes.count() - 1; i++ ) 47 : : { 48 : 0 : for ( int j = i + 1; j < classes.count(); j++ ) 49 : : { 50 : 0 : const QgsReclassifyUtils::RasterClass &class1 = classes.at( i ); 51 : 0 : const QgsReclassifyUtils::RasterClass &class2 = classes.at( j ); 52 : 0 : if ( class1.overlaps( class2 ) ) 53 : : { 54 : 0 : feedback->reportError( QObject::tr( "Warning: Class %1 (%2) overlaps with class %3 (%4)" ).arg( i + 1 ) 55 : 0 : .arg( class1.asText() ) 56 : 0 : .arg( j + 1 ) 57 : 0 : .arg( class2.asText() ) ); 58 : 0 : } 59 : 0 : } 60 : 0 : } 61 : 0 : } 62 : : 63 : 0 : void QgsReclassifyUtils::reclassify( const QVector<QgsReclassifyUtils::RasterClass> &classes, QgsRasterInterface *sourceRaster, int band, 64 : : const QgsRectangle &extent, int sourceWidthPixels, int sourceHeightPixels, 65 : : QgsRasterDataProvider *destinationRaster, double destNoDataValue, bool useNoDataForMissingValues, 66 : : QgsProcessingFeedback *feedback ) 67 : : { 68 : 0 : int maxWidth = QgsRasterIterator::DEFAULT_MAXIMUM_TILE_WIDTH; 69 : 0 : int maxHeight = QgsRasterIterator::DEFAULT_MAXIMUM_TILE_HEIGHT; 70 : : 71 : 0 : QgsRasterIterator iter( sourceRaster ); 72 : 0 : iter.startRasterRead( band, sourceWidthPixels, sourceHeightPixels, extent ); 73 : : 74 : 0 : int nbBlocksWidth = static_cast< int >( std::ceil( 1.0 * sourceWidthPixels / maxWidth ) ); 75 : 0 : int nbBlocksHeight = static_cast< int >( std::ceil( 1.0 * sourceHeightPixels / maxHeight ) ); 76 : 0 : int nbBlocks = nbBlocksWidth * nbBlocksHeight; 77 : : 78 : 0 : int iterLeft = 0; 79 : 0 : int iterTop = 0; 80 : 0 : int iterCols = 0; 81 : 0 : int iterRows = 0; 82 : 0 : destinationRaster->setEditable( true ); 83 : 0 : std::unique_ptr< QgsRasterBlock > rasterBlock; 84 : 0 : bool reclassed = false; 85 : 0 : bool isNoData = false; 86 : 0 : while ( iter.readNextRasterPart( band, iterCols, iterRows, rasterBlock, iterLeft, iterTop ) ) 87 : : { 88 : 0 : if ( feedback ) 89 : 0 : feedback->setProgress( 100 * ( ( iterTop / maxHeight * nbBlocksWidth ) + iterLeft / maxWidth ) / nbBlocks ); 90 : 0 : if ( feedback && feedback->isCanceled() ) 91 : 0 : break; 92 : 0 : std::unique_ptr< QgsRasterBlock > reclassifiedBlock = std::make_unique< QgsRasterBlock >( destinationRaster->dataType( 1 ), iterCols, iterRows ); 93 : : 94 : 0 : for ( int row = 0; row < iterRows; row++ ) 95 : : { 96 : 0 : if ( feedback && feedback->isCanceled() ) 97 : 0 : break; 98 : 0 : for ( int column = 0; column < iterCols; column++ ) 99 : : { 100 : 0 : const double value = rasterBlock->valueAndNoData( row, column, isNoData ); 101 : 0 : if ( isNoData ) 102 : 0 : reclassifiedBlock->setValue( row, column, destNoDataValue ); 103 : : else 104 : : { 105 : 0 : double newValue = reclassifyValue( classes, value, reclassed ); 106 : 0 : if ( reclassed ) 107 : 0 : reclassifiedBlock->setValue( row, column, newValue ); 108 : : else 109 : 0 : reclassifiedBlock->setValue( row, column, useNoDataForMissingValues ? destNoDataValue : value ); 110 : : } 111 : 0 : } 112 : 0 : } 113 : 0 : destinationRaster->writeBlock( reclassifiedBlock.get(), 1, iterLeft, iterTop ); 114 : 0 : } 115 : 0 : destinationRaster->setEditable( false ); 116 : 0 : } 117 : : 118 : : 119 : : 120 : : ///@endcond 121 : : 122 : : 123 : :