Skip to content
Permalink
Browse files

Improve documentation for raster pyramid creation methods/classes

The PyQGIS documentation for this workflow was very poorly documented
  • Loading branch information
nyalldawson committed Mar 31, 2021
1 parent 6bc879f commit c4c8aab7b4b00f24e6d24cfbd9f21b1d59e313dd
@@ -236,23 +236,55 @@ Returns a new image downloader for the raster legend.
const QStringList &configOptions = QStringList(),
QgsRasterBlockFeedback *feedback = 0 );
%Docstring
Create pyramid overviews
Creates pyramid overviews.

:param pyramidList: a list of :py:class:`QgsRasterPryamids` to create overviews for. The :py:func:`QgsRasterPryamid.setBuild()` flag
should be set to ``True`` for every layer where pyramids are desired.
:param resamplingMethod: resampling method to use when creating the pyramids. The :py:func:`~QgsRasterDataProvider.pyramidResamplingMethods` method
can be used to retrieve a list of valid resampling methods available for specific raster data providers.
:param format: raster pyramid format.
:param configOptions: optional configuration options which are passed to the specific data provider
for use during pyramid creation.
:param feedback: optional feedback argument for progress reports and cancelation support.

.. seealso:: :py:func:`buildPyramidList`

.. seealso:: :py:func:`hasPyramids`

.. seealso:: :py:func:`pyramidResamplingMethods`
%End

virtual QList<QgsRasterPyramid> buildPyramidList( QList<int> overviewList = QList<int>() );
virtual QList<QgsRasterPyramid> buildPyramidList( const QList<int> &overviewList = QList<int>() );
%Docstring
Returns the raster layers pyramid list.

This method returns a list of pyramid layers which are valid for the data provider. The returned list
is a complete list of all possible layers, and includes both pyramids layers which currently exist and
layers which have not yet been constructed. To know which of the pyramid layers
ACTUALLY exists you need to look at the :py:func:`QgsRasterPyramid.getExists()` member for each value in the
list.

The returned list is suitable for passing to the :py:func:`~QgsRasterDataProvider.buildPyramids` method. First, modify the returned list
by calling `QgsRasterPryamid.setBuild( ``True`` )` for every layer you want to create pyramids for, and then
pass the modified list to :py:func:`~QgsRasterDataProvider.buildPryamids`.

:param overviewList: used to construct the pyramid list (optional), when empty the list is defined by the provider.
A pyramid list defines the
POTENTIAL pyramids that can be in a raster. To know which of the pyramid layers
ACTUALLY exists you need to look at the existsFlag member in each struct stored in the
list.

.. seealso:: :py:func:`buildPyramids`

.. seealso:: :py:func:`hasPyramids`
%End

bool hasPyramids();
%Docstring
Returns ``True`` if raster has at least one populated histogram.
Returns ``True`` if raster has at least one existing pyramid.

The :py:func:`~QgsRasterDataProvider.buildPyramidList` method can be used to retrieve additional details about potential and existing
pryamid layers.

.. seealso:: :py:func:`buildPyramidList`

.. seealso:: :py:func:`buildPyramids`
%End

virtual QString htmlMetadata() = 0;
@@ -18,13 +18,100 @@ This struct is used to store pyramid info for the raster layer.
#include "qgsrasterpyramid.h"
%End
public:
int level;
int xDim;
int yDim;
bool exists;
bool build;

QgsRasterPyramid();

int getLevel() const;
%Docstring
Returns the pyramid level.

Pyramid levels are as defined by GDAL, eg
level 2 is half the original raster size.

.. versionadded:: 3.20
%End

void setLevel( int level );
%Docstring
Sets the pyramid ``level``.

Pyramid levels are as defined by GDAL, eg
level 2 is half the original raster size.

.. versionadded:: 3.20
%End

%Property( name = level, get = getLevel, set = setLevel )

void setXDim( int dimension );
%Docstring
Sets the x ``dimension`` for this pyramid layer.

.. versionadded:: 3.20
%End

int getXDim() const;
%Docstring
Returns the x dimension for this pyramid layer.

.. versionadded:: 3.20
%End

%Property( name = xDim, get = getXDim, set = setXDim )

void setYDim( int dimension );
%Docstring
Sets the y ``dimension`` for this pyramid layer.

.. versionadded:: 3.20
%End

int getYDim() const;
%Docstring
Returns the y dimension for this pyramid layer.

.. versionadded:: 3.20
%End

%Property( name = yDim, get = getYDim, set = setYDim )

bool getExists() const;
%Docstring
Returns ``True`` if the pyramid layer currently exists.

.. versionadded:: 3.20
%End

void setExists( bool exists );
%Docstring
Sets whether the pyramid layer currently exists.

.. versionadded:: 3.20
%End

%Property( name = exists, get = getExists, set = setExists )

bool getBuild() const;
%Docstring
Returns ``True`` if the pyramid layer will be built.

When used with :py:func:`QgsRasterDataProvider.buildPyramids()` this flag controls
whether pyramids will be built for the layer.

.. versionadded:: 3.20
%End

void setBuild( bool build );
%Docstring
Sets whether the pyramid layer will be built.

When used with :py:func:`QgsRasterDataProvider.buildPyramids()` this flag controls
whether pyramids will be built for the layer. Set to ``True`` to build
the pyramids.

.. versionadded:: 3.20
%End

%Property( name = build, get = getBuild, set = setBuild )

};
/************************************************************************
@@ -2038,16 +2038,16 @@ QString QgsGdalProvider::buildPyramids( const QList<QgsRasterPyramid> &rasterPyr
++myRasterPyramidIterator )
{
#ifdef QGISDEBUG
QgsDebugMsgLevel( QStringLiteral( "Build pyramids:: Level %1" ).arg( myRasterPyramidIterator->level ), 2 );
QgsDebugMsgLevel( QStringLiteral( "x:%1" ).arg( myRasterPyramidIterator->xDim ), 2 );
QgsDebugMsgLevel( QStringLiteral( "y:%1" ).arg( myRasterPyramidIterator->yDim ), 2 );
QgsDebugMsgLevel( QStringLiteral( "exists : %1" ).arg( myRasterPyramidIterator->exists ), 2 );
QgsDebugMsgLevel( QStringLiteral( "Build pyramids:: Level %1" ).arg( myRasterPyramidIterator->getLevel() ), 2 );
QgsDebugMsgLevel( QStringLiteral( "x:%1" ).arg( myRasterPyramidIterator->getXDim() ), 2 );
QgsDebugMsgLevel( QStringLiteral( "y:%1" ).arg( myRasterPyramidIterator->getYDim() ), 2 );
QgsDebugMsgLevel( QStringLiteral( "exists : %1" ).arg( myRasterPyramidIterator->getExists() ), 2 );
#endif
if ( myRasterPyramidIterator->build )
if ( myRasterPyramidIterator->getBuild() )
{
QgsDebugMsgLevel( QStringLiteral( "adding overview at level %1 to list"
).arg( myRasterPyramidIterator->level ), 2 );
myOverviewLevelsVector.append( myRasterPyramidIterator->level );
).arg( myRasterPyramidIterator->getLevel() ), 2 );
myOverviewLevelsVector.append( myRasterPyramidIterator->getLevel() );
}
}
/* From : http://www.gdal.org/classGDALDataset.html#a2aa6f88b3bbc840a5696236af11dde15
@@ -2226,8 +2226,9 @@ QList<QgsRasterPyramid> QgsGdalProvider::buildPyramidList()
}
#endif

QList<QgsRasterPyramid> QgsGdalProvider::buildPyramidList( QList<int> overviewList )
QList<QgsRasterPyramid> QgsGdalProvider::buildPyramidList( const QList<int> &list )
{
QList< int > overviewList = list;
QMutexLocker locker( mpMutex );

int myWidth = mWidth;
@@ -2260,12 +2261,12 @@ QList<QgsRasterPyramid> QgsGdalProvider::buildPyramidList( QList<int> overviewLi
//

QgsRasterPyramid myRasterPyramid;
myRasterPyramid.level = myDivisor;
myRasterPyramid.xDim = ( int )( 0.5 + ( myWidth / static_cast<double>( myDivisor ) ) ); // NOLINT
myRasterPyramid.yDim = ( int )( 0.5 + ( myHeight / static_cast<double>( myDivisor ) ) ); // NOLINT
myRasterPyramid.exists = false;
myRasterPyramid.setLevel( myDivisor );
myRasterPyramid.setXDim( ( int )( 0.5 + ( myWidth / static_cast<double>( myDivisor ) ) ) ); // NOLINT
myRasterPyramid.setYDim( ( int )( 0.5 + ( myHeight / static_cast<double>( myDivisor ) ) ) ); // NOLINT
myRasterPyramid.setExists( false );

QgsDebugMsgLevel( QStringLiteral( "Pyramid %1 xDim %2 yDim %3" ).arg( myRasterPyramid.level ).arg( myRasterPyramid.xDim ).arg( myRasterPyramid.yDim ), 2 );
QgsDebugMsgLevel( QStringLiteral( "Pyramid %1 xDim %2 yDim %3" ).arg( myRasterPyramid.getLevel() ).arg( myRasterPyramid.getXDim() ).arg( myRasterPyramid.getYDim() ), 2 );

//
// Now we check if it actually exists in the raster layer
@@ -2288,20 +2289,20 @@ QList<QgsRasterPyramid> QgsGdalProvider::buildPyramidList( QList<int> overviewLi
// here is where we check if its a near match:
// we will see if its within 5 cells either side of
//
QgsDebugMsgLevel( "Checking whether " + QString::number( myRasterPyramid.xDim ) + " x " +
QString::number( myRasterPyramid.yDim ) + " matches " +
QgsDebugMsgLevel( "Checking whether " + QString::number( myRasterPyramid.getXDim() ) + " x " +
QString::number( myRasterPyramid.getYDim() ) + " matches " +
QString::number( myOverviewXDim ) + " x " + QString::number( myOverviewYDim ), 2 );


if ( ( myOverviewXDim <= ( myRasterPyramid.xDim + myNearMatchLimit ) ) &&
( myOverviewXDim >= ( myRasterPyramid.xDim - myNearMatchLimit ) ) &&
( myOverviewYDim <= ( myRasterPyramid.yDim + myNearMatchLimit ) ) &&
( myOverviewYDim >= ( myRasterPyramid.yDim - myNearMatchLimit ) ) )
if ( ( myOverviewXDim <= ( myRasterPyramid.getXDim() + myNearMatchLimit ) ) &&
( myOverviewXDim >= ( myRasterPyramid.getXDim() - myNearMatchLimit ) ) &&
( myOverviewYDim <= ( myRasterPyramid.getYDim() + myNearMatchLimit ) ) &&
( myOverviewYDim >= ( myRasterPyramid.getYDim() - myNearMatchLimit ) ) )
{
//right we have a match so adjust the a / y before they get added to the list
myRasterPyramid.xDim = myOverviewXDim;
myRasterPyramid.yDim = myOverviewYDim;
myRasterPyramid.exists = true;
myRasterPyramid.setXDim( myOverviewXDim );
myRasterPyramid.setYDim( myOverviewYDim );
myRasterPyramid.setExists( true );
QgsDebugMsgLevel( QStringLiteral( ".....YES!" ), 2 );
}
else
@@ -189,7 +189,7 @@ class QgsGdalProvider final: public QgsRasterDataProvider, QgsGdalProviderBase
QgsRaster::RasterPyramidsFormat format = QgsRaster::PyramidsGTiff,
const QStringList &createOptions = QStringList(),
QgsRasterBlockFeedback *feedback = nullptr ) override;
QList<QgsRasterPyramid> buildPyramidList( QList<int> overviewList = QList<int>() ) override;
QList<QgsRasterPyramid> buildPyramidList( const QList<int> &overviewList = QList<int>() ) override;

static QMap<QString, QString> supportedMimes();

@@ -374,22 +374,8 @@ QList<QPair<QString, QString> > QgsRasterDataProvider::pyramidResamplingMethods(

bool QgsRasterDataProvider::hasPyramids()
{
QList<QgsRasterPyramid> myPyramidList = buildPyramidList();

if ( myPyramidList.isEmpty() )
return false;

QList<QgsRasterPyramid>::iterator myRasterPyramidIterator;
for ( myRasterPyramidIterator = myPyramidList.begin();
myRasterPyramidIterator != myPyramidList.end();
++myRasterPyramidIterator )
{
if ( myRasterPyramidIterator->exists )
{
return true;
}
}
return false;
const QList<QgsRasterPyramid> pyramidList = buildPyramidList();
return std::any_of( pyramidList.constBegin(), pyramidList.constEnd(), []( QgsRasterPyramid pyramid ) { return pyramid.getExists(); } );
}

void QgsRasterDataProvider::setUserNoDataValue( int bandNo, const QgsRasterRangeList &noData )
@@ -309,7 +309,22 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast
return nullptr;
}

//! \brief Create pyramid overviews
/**
* Creates pyramid overviews.
*
* \param pyramidList a list of QgsRasterPryamids to create overviews for. The QgsRasterPryamid::setBuild() flag
* should be set to TRUE for every layer where pyramids are desired.
* \param resamplingMethod resampling method to use when creating the pyramids. The pyramidResamplingMethods() method
* can be used to retrieve a list of valid resampling methods available for specific raster data providers.
* \param format raster pyramid format.
* \param configOptions optional configuration options which are passed to the specific data provider
* for use during pyramid creation.
* \param feedback optional feedback argument for progress reports and cancelation support.
*
* \see buildPyramidList()
* \see hasPyramids()
* \see pyramidResamplingMethods()
*/
virtual QString buildPyramids( const QList<QgsRasterPyramid> &pyramidList,
const QString &resamplingMethod = "NEAREST",
QgsRaster::RasterPyramidsFormat format = QgsRaster::PyramidsGTiff,
@@ -326,16 +341,34 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast

/**
* Returns the raster layers pyramid list.
* \param overviewList used to construct the pyramid list (optional), when empty the list is defined by the provider.
* A pyramid list defines the
* POTENTIAL pyramids that can be in a raster. To know which of the pyramid layers
* ACTUALLY exists you need to look at the existsFlag member in each struct stored in the
*
* This method returns a list of pyramid layers which are valid for the data provider. The returned list
* is a complete list of all possible layers, and includes both pyramids layers which currently exist and
* layers which have not yet been constructed. To know which of the pyramid layers
* ACTUALLY exists you need to look at the QgsRasterPyramid::getExists() member for each value in the
* list.
*
* The returned list is suitable for passing to the buildPyramids() method. First, modify the returned list
* by calling `QgsRasterPryamid::setBuild( TRUE )` for every layer you want to create pyramids for, and then
* pass the modified list to buildPryamids().
*
* \param overviewList used to construct the pyramid list (optional), when empty the list is defined by the provider.
*
* \see buildPyramids()
* \see hasPyramids()
*/
virtual QList<QgsRasterPyramid> buildPyramidList( QList<int> overviewList = QList<int>() ) // clazy:exclude=function-args-by-ref
virtual QList<QgsRasterPyramid> buildPyramidList( const QList<int> &overviewList = QList<int>() )
{ Q_UNUSED( overviewList ) return QList<QgsRasterPyramid>(); }

//! \brief Returns TRUE if raster has at least one populated histogram.
/**
* Returns TRUE if raster has at least one existing pyramid.
*
* The buildPyramidList() method can be used to retrieve additional details about potential and existing
* pryamid layers.
*
* \see buildPyramidList()
* \see buildPyramids()
*/
bool hasPyramids();

/**
@@ -818,7 +818,7 @@ void QgsRasterFileWriter::buildPyramids( const QString &filename, QgsRasterDataP
myPyramidList = destProvider->buildPyramidList( mPyramidsList );
for ( int myCounterInt = 0; myCounterInt < myPyramidList.count(); myCounterInt++ )
{
myPyramidList[myCounterInt].build = true;
myPyramidList[myCounterInt].setBuild( true );
}

QgsDebugMsgLevel( QStringLiteral( "building pyramids : %1 pyramids, %2 resampling, %3 format, %4 options" ).arg( myPyramidList.count() ).arg( mPyramidsResampling ).arg( mPyramidsFormat ).arg( mPyramidsConfigOptions.count() ), 4 );

0 comments on commit c4c8aab

Please sign in to comment.