27static const double sNoValue = std::numeric_limits<double>::quiet_NaN();
30static double cellValue(
const QgsRasterBlock *block,
int row,
int column )
32 if ( !block || row < 0 || column < 0 || row >= block->
height() || column >= block->
width() )
35 bool isNoData =
false;
36 const double value = block->
valueAndNoData( row, column, isNoData );
37 if ( isNoData || std::isnan( value ) )
48QgsRasterVectorFieldValueSourceBase::QgsRasterVectorFieldValueSourceBase(
const QgsRectangle &blockExtent,
const QgsRectangle &dataExtent,
int columns,
int rows )
49 : mBlockExtent( blockExtent )
50 , mDataExtent( dataExtent )
54 if ( mColumns > 0 && mRows > 0 && !mBlockExtent.isEmpty() )
56 mXResolution = mBlockExtent.width() / mColumns;
57 mYResolution = mBlockExtent.height() / mRows;
61bool QgsRasterVectorFieldValueSourceBase::isValid()
const
63 return mColumns > 0 && mRows > 0 && mXResolution > 0 && mYResolution > 0;
66QgsRectangle QgsRasterVectorFieldValueSourceBase::extent()
const
71bool QgsRasterVectorFieldValueSourceBase::nativeLayout(
QgsPointXY &origin,
double &spacingX,
double &spacingY )
const
77 spacingX = mXResolution;
78 spacingY = mYResolution;
79 origin =
QgsPointXY( mBlockExtent.xMinimum() + spacingX / 2, mBlockExtent.yMaximum() - spacingY / 2 );
83QVector<QgsPointXY> QgsRasterVectorFieldValueSourceBase::seedPoints(
const QgsRectangle &extent )
const
85 QVector<QgsPointXY> points;
94 const int firstColumn = std::max( 0,
static_cast<int>( std::ceil( ( seedExtent.
xMinimum() - mBlockExtent.xMinimum() ) / mXResolution - 0.5 ) ) );
95 const int lastColumn = std::min( mColumns - 1,
static_cast<int>( std::floor( ( seedExtent.
xMaximum() - mBlockExtent.xMinimum() ) / mXResolution - 0.5 ) ) );
96 const int firstRow = std::max( 0,
static_cast<int>( std::ceil( ( mBlockExtent.yMaximum() - seedExtent.
yMaximum() ) / mYResolution - 0.5 ) ) );
97 const int lastRow = std::min( mRows - 1,
static_cast<int>( std::floor( ( mBlockExtent.yMaximum() - seedExtent.
yMinimum() ) / mYResolution - 0.5 ) ) );
99 if ( firstColumn > lastColumn || firstRow > lastRow )
103 const qint64 candidates =
static_cast<qint64
>( lastColumn - firstColumn + 1 ) * ( lastRow - firstRow + 1 );
105 if ( candidates > MAXIMUM_SEED_POINTS )
106 step =
static_cast<int>( std::ceil( std::sqrt(
static_cast<double>( candidates ) / MAXIMUM_SEED_POINTS ) ) );
108 points.reserve(
static_cast<int>( candidates / (
static_cast<qint64
>( step ) * step ) ) + 1 );
109 for (
int row = firstRow; row <= lastRow; row += step )
111 const double y = mBlockExtent.yMaximum() - ( row + 0.5 ) * mYResolution;
112 for (
int column = firstColumn; column <= lastColumn; column += step )
114 if ( !cellHasValue( row, column ) )
117 points.append(
QgsPointXY( mBlockExtent.xMinimum() + ( column + 0.5 ) * mXResolution, y ) );
130static int commonColumns(
const std::shared_ptr<const QgsRasterBlock> &first,
const std::shared_ptr<const QgsRasterBlock> &second )
132 return first && second ? std::min( first->width(), second->width() ) : 0;
136static int commonRows(
const std::shared_ptr<const QgsRasterBlock> &first,
const std::shared_ptr<const QgsRasterBlock> &second )
138 return first && second ? std::min( first->height(), second->height() ) : 0;
141QgsRasterVectorFieldValueSource::QgsRasterVectorFieldValueSource(
142 std::shared_ptr<const QgsRasterBlock> xValues, std::shared_ptr<const QgsRasterBlock> yValues,
const QgsRectangle &blockExtent,
const QgsRectangle &dataExtent,
double maximumMagnitude
144 : QgsRasterVectorFieldValueSourceBase( blockExtent, dataExtent, commonColumns( xValues, yValues ), commonRows( xValues, yValues ) )
145 , mXValues( std::move( xValues ) )
146 , mYValues( std::move( yValues ) )
147 , mMaximumMagnitude( maximumMagnitude )
150bool QgsRasterVectorFieldValueSource::cellHasValue(
int row,
int column )
const
152 return !std::isnan( cellValue( mXValues.get(), row, column ) ) && !std::isnan( cellValue( mYValues.get(), row, column ) );
155QgsRasterVectorFieldValueSource *QgsRasterVectorFieldValueSource::clone()
const
158 return new QgsRasterVectorFieldValueSource( *
this );
164 const double x = ( point.
x() - mBlockExtent.xMinimum() ) / mXResolution - 0.5;
165 const double y = ( mBlockExtent.yMaximum() - point.
y() ) / mYResolution - 0.5;
167 const int column =
static_cast<int>( std::floor( x ) );
168 const int row =
static_cast<int>( std::floor( y ) );
170 const double v00 = cellValue( block, row, column );
171 const double v01 = cellValue( block, row, column + 1 );
172 const double v10 = cellValue( block, row + 1, column );
173 const double v11 = cellValue( block, row + 1, column + 1 );
175 if ( std::isnan( v00 ) || std::isnan( v01 ) || std::isnan( v10 ) || std::isnan( v11 ) )
179 return cellValue( block,
static_cast<int>( std::floor( y + 0.5 ) ),
static_cast<int>( std::floor( x + 0.5 ) ) );
182 const double dx = x - column;
183 const double dy = y - row;
185 return v00 * ( 1 - dx ) * ( 1 - dy ) + v01 * dx * ( 1 - dy ) + v10 * ( 1 - dx ) * dy + v11 * dx * dy;
190 if ( !isValid() || !mBlockExtent.contains( point ) )
193 const double x = sampledValue( mXValues.get(), point );
194 const double y = sampledValue( mYValues.get(), point );
195 if ( std::isnan( x ) || std::isnan( y ) )
201double QgsRasterVectorFieldValueSource::maximumMagnitude()
const
203 return mMaximumMagnitude;
206std::unique_ptr<QgsRasterInterface> QgsRasterVectorFieldValueSource::magnitudeSource(
const QgsRenderContext &, QSize )
const
211 return std::make_unique<QgsRasterVectorFieldMagnitudeInterface>( mXValues, mYValues, mBlockExtent );
219QgsRasterVectorFieldEncodedDirectionValueSource::QgsRasterVectorFieldEncodedDirectionValueSource(
222 : QgsRasterVectorFieldValueSourceBase( blockExtent, dataExtent, values ? values->width() : 0, values ? values->height() : 0 )
223 , mValues( std::move( values ) )
224 , mEncoding( encoding )
227QgsRasterVectorFieldEncodedDirectionValueSource *QgsRasterVectorFieldEncodedDirectionValueSource::clone()
const
230 return new QgsRasterVectorFieldEncodedDirectionValueSource( *
this );
235 if ( std::isnan( value ) )
239 const double rounded = std::round( value );
240 if ( std::abs( value - rounded ) > 1e-6 || std::abs( rounded ) > std::numeric_limits<int>::max() )
243 int code =
static_cast<int>( rounded );
277 code = std::abs( code );
305 return code >= 0 && code <= 7 ? code : -1;
337QgsVector QgsRasterVectorFieldEncodedDirectionValueSource::ordinalVector(
int ordinal )
339 constexpr double D = M_SQRT1_2;
364void QgsRasterVectorFieldEncodedDirectionValueSource::setSamplingWindow(
double width,
double height )
366 mWindowWidth = std::max( 0.0, width );
367 mWindowHeight = std::max( 0.0, height );
370bool QgsRasterVectorFieldEncodedDirectionValueSource::cellHasValue(
int row,
int column )
const
372 return directionOrdinal( mEncoding, cellValue( mValues.get(), row, column ) ) >= 0;
375int QgsRasterVectorFieldEncodedDirectionValueSource::nearestOrdinal(
const QgsPointXY &point )
const
377 const int column =
static_cast<int>( std::floor( ( point.
x() - mBlockExtent.xMinimum() ) / mXResolution ) );
378 const int row =
static_cast<int>( std::floor( ( mBlockExtent.yMaximum() - point.
y() ) / mYResolution ) );
380 return directionOrdinal( mEncoding, cellValue( mValues.get(), row, column ) );
383int QgsRasterVectorFieldEncodedDirectionValueSource::majorityOrdinal(
const QgsPointXY &point )
const
386 const double xMinimum = point.
x() - mWindowWidth / 2;
387 const double xMaximum = point.
x() + mWindowWidth / 2;
388 const double yMinimum = point.
y() - mWindowHeight / 2;
389 const double yMaximum = point.
y() + mWindowHeight / 2;
391 const int firstColumn = std::max( 0,
static_cast<int>( std::ceil( ( xMinimum - mBlockExtent.xMinimum() ) / mXResolution - 0.5 ) ) );
392 const int lastColumn = std::min( mColumns - 1,
static_cast<int>( std::floor( ( xMaximum - mBlockExtent.xMinimum() ) / mXResolution - 0.5 ) ) );
393 const int firstRow = std::max( 0,
static_cast<int>( std::ceil( ( mBlockExtent.yMaximum() - yMaximum ) / mYResolution - 0.5 ) ) );
394 const int lastRow = std::min( mRows - 1,
static_cast<int>( std::floor( ( mBlockExtent.yMaximum() - yMinimum ) / mYResolution - 0.5 ) ) );
397 if ( firstColumn > lastColumn || firstRow > lastRow )
398 return nearestOrdinal( point );
400 int counts[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
404 for (
int row = firstRow; row <= lastRow; ++row )
406 for (
int column = firstColumn; column <= lastColumn; ++column )
408 const int ordinal = directionOrdinal( mEncoding, cellValue( mValues.get(), row, column ) );
412 best = std::max( best, ++counts[ordinal] );
413 resultant += ordinalVector( ordinal );
423 double bestProjection = std::numeric_limits<double>::lowest();
424 for (
int ordinal = 0; ordinal < 8; ++ordinal )
426 if ( counts[ordinal] != best )
429 const double projection = resultant * ordinalVector( ordinal );
430 if ( projection > bestProjection )
432 bestProjection = projection;
440QgsVector QgsRasterVectorFieldEncodedDirectionValueSource::vectorValue(
const QgsPointXY &point )
const
442 if ( !isValid() || !mBlockExtent.contains( point ) )
445 const bool hasWindow = mWindowWidth > 0 && mWindowHeight > 0;
446 return ordinalVector( hasWindow ? majorityOrdinal( point ) : nearestOrdinal( point ) );
449double QgsRasterVectorFieldEncodedDirectionValueSource::maximumMagnitude()
const
459QgsRasterVectorFieldMagnitudeInterface::QgsRasterVectorFieldMagnitudeInterface( std::shared_ptr<const QgsRasterBlock> xValues, std::shared_ptr<const QgsRasterBlock> yValues,
const QgsRectangle &blockExtent )
460 : mXValues( std::move( xValues ) )
461 , mYValues( std::move( yValues ) )
462 , mBlockExtent( blockExtent )
467 return new QgsRasterVectorFieldMagnitudeInterface( mXValues, mYValues, mBlockExtent );
470Qgis::DataType QgsRasterVectorFieldMagnitudeInterface::dataType(
int )
const
475int QgsRasterVectorFieldMagnitudeInterface::bandCount()
const
480QgsRectangle QgsRasterVectorFieldMagnitudeInterface::extent()
const
489 outputBlock->setNoDataValue( std::numeric_limits<double>::quiet_NaN() );
491 if ( !mXValues || !mYValues || width <= 0 || height <= 0 || extent.
isEmpty() || mBlockExtent.isEmpty() )
492 return outputBlock.release();
494 const int columns = std::min( mXValues->width(), mYValues->width() );
495 const int rows = std::min( mXValues->height(), mYValues->height() );
496 if ( columns <= 0 || rows <= 0 )
497 return outputBlock.release();
501 const double xResolution = mBlockExtent.width() / columns;
502 const double yResolution = mBlockExtent.height() / rows;
503 const double outputXResolution = extent.
width() / width;
504 const double outputYResolution = extent.
height() / height;
506 for (
int row = 0; row < height; ++row )
511 const double y = extent.
yMaximum() - ( row + 0.5 ) * outputYResolution;
512 const int sourceRow =
static_cast<int>( std::floor( ( mBlockExtent.yMaximum() - y ) / yResolution ) );
514 for (
int column = 0; column < width; ++column )
516 const double x = extent.
xMinimum() + ( column + 0.5 ) * outputXResolution;
517 const int sourceColumn =
static_cast<int>( std::floor( ( x - mBlockExtent.xMinimum() ) / xResolution ) );
519 const double xValue = cellValue( mXValues.get(), sourceRow, sourceColumn );
520 const double yValue = cellValue( mYValues.get(), sourceRow, sourceColumn );
522 outputBlock->setValue( row, column, std::hypot( xValue, yValue ) );
526 return outputBlock.release();
DataType
Raster data types.
@ Float64
Sixty four bit floating point (double).
RasterDirectionEncoding
Schemes used to encode a compass direction as an integer raster value.
@ PcRaster
PCRaster: 1=SW, 2=S, 3=SE, 4=W, 6=E, 7=NW, 8=N, 9=NE.
@ Esri
Esri: 1=E, 2=SE, 4=S, 8=SW, 16=W, 32=NW, 64=N, 128=NE.
@ Saga
SAGA: 0=N, 1=NE, 2=E, 3=SE, 4=S, 5=SW, 6=W, 7=NW.
@ Grass
GRASS: 1=NE, 2=N, 3=NW, 4=W, 5=SW, 6=S, 7=SE, 8=E.
bool isCanceled() const
Tells whether the operation has been canceled already.
Feedback object tailored for raster block reading.
int height() const
Returns the height (number of rows) of the raster block.
double valueAndNoData(int row, int column, bool &isNoData) const
Reads a single value from the pixel at row and column, if type of block is numeric.
int width() const
Returns the width (number of columns) of the raster block.
Base class for processing filters like renderers, reprojector, resampler etc.
A rectangle specified with double values.
QgsRectangle intersect(const QgsRectangle &rect) const
Returns the intersection with the given rectangle.
Contains information about the context of a rendering operation.
Represent a 2-dimensional vector.