Skip to content

Commit

Permalink
Merge pull request #35511 from elpaso/pgraster-temporal
Browse files Browse the repository at this point in the history
Postgres raster temporal API support
  • Loading branch information
elpaso committed Apr 6, 2020
2 parents 1383cde + 0f2a70a commit 8fa6338
Show file tree
Hide file tree
Showing 24 changed files with 1,139 additions and 183 deletions.
12 changes: 12 additions & 0 deletions python/core/auto_generated/qgsdataprovider.sip.in
Expand Up @@ -102,6 +102,18 @@ connection string
only when needed within a provider
%End

virtual QString dataComment() const;
%Docstring
Returns a short comment for the data that this provider is
providing access to (e.g. the comment for postgres table).

.. note::

The default implementation returns an empty string.

.. versionadded:: 3.14
%End

void setUri( const QgsDataSourceUri &uri );
%Docstring
Set the data source specification.
Expand Down
Expand Up @@ -117,6 +117,13 @@ It makes no sense to set input on provider */
Returns data type for the band specified by number
%End

virtual QgsFields fields() const;
%Docstring
Returns the fields of the raster layer for data providers that expose them,
the default implementation returns an empty list.

.. versionadded:: 3.14
%End
virtual Qgis::DataType sourceDataType( int bandNo ) const = 0;

%Docstring
Expand Down
1 change: 1 addition & 0 deletions scripts/spell_check/.agignore
Expand Up @@ -14,6 +14,7 @@ src/app/gps/qwtpolar-1.0/
src/app/gps/qwtpolar-1.1.1/
src/core/pal
src/plugins/grass/qtermwidget/
tests/testdata/provider/postgresraster/

#Extensions
*.*.orig
Expand Down
12 changes: 11 additions & 1 deletion src/core/qgsdataprovider.h
Expand Up @@ -143,7 +143,7 @@ class CORE_EXPORT QgsDataProvider : public QObject
{
if ( expandAuthConfig && mDataSourceURI.contains( QLatin1String( "authcfg" ) ) )
{
QgsDataSourceUri uri( mDataSourceURI );
const QgsDataSourceUri uri( mDataSourceURI );
return uri.uri( expandAuthConfig );
}
else
Expand All @@ -152,6 +152,16 @@ class CORE_EXPORT QgsDataProvider : public QObject
}
}

/**
* Returns a short comment for the data that this provider is
* providing access to (e.g. the comment for postgres table).
*
* \note The default implementation returns an empty string.
* \since QGIS 3.14
*/
virtual QString dataComment() const { return QString(); };


/**
* Set the data source specification.
*
Expand Down
13 changes: 7 additions & 6 deletions src/core/qgstemporalnavigationobject.cpp
Expand Up @@ -71,19 +71,20 @@ void QgsTemporalNavigationObject::setLooping( bool loopAnimation )

QgsDateTimeRange QgsTemporalNavigationObject::dateTimeRangeForFrameNumber( long long frame ) const
{
QDateTime start = mTemporalExtents.begin();
const QDateTime start = mTemporalExtents.begin();

if ( frame < 0 )
frame = 0;
long long nextFrame = frame + 1;

QDateTime begin = start.addSecs( frame * mFrameDuration.seconds() );
QDateTime end = start.addSecs( nextFrame * mFrameDuration.seconds() );
const long long nextFrame = frame + 1;

const QDateTime begin = start.addSecs( frame * mFrameDuration.seconds() );
const QDateTime end = start.addSecs( nextFrame * mFrameDuration.seconds() );

if ( end <= mTemporalExtents.end() )
return QgsDateTimeRange( begin, end );
return QgsDateTimeRange( begin, end, true, false );

return QgsDateTimeRange( begin, mTemporalExtents.end() );
return QgsDateTimeRange( begin, mTemporalExtents.end(), true, false );
}

void QgsTemporalNavigationObject::setTemporalExtents( const QgsDateTimeRange &temporalExtents )
Expand Down
2 changes: 1 addition & 1 deletion src/core/qgsvectordataprovider.h
Expand Up @@ -198,7 +198,7 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider, public QgsFeat
* Returns a short comment for the data that this provider is
* providing access to (e.g. the comment for postgres table).
*/
virtual QString dataComment() const;
virtual QString dataComment() const override;

/**
* Returns the minimum value of an attribute
Expand Down
2 changes: 1 addition & 1 deletion src/core/raster/qgsrasterdataprovider.cpp
Expand Up @@ -116,7 +116,7 @@ QgsRasterBlock *QgsRasterDataProvider::block( int bandNo, QgsRectangle const &b
return block.release();
}

// If lower source resolution is used, the extent must beS aligned to original
// If lower source resolution is used, the extent must be aligned to original
// resolution to avoid possible shift due to resampling
if ( tmpXRes > xRes )
{
Expand Down
9 changes: 8 additions & 1 deletion src/core/raster/qgsrasterdataprovider.h
Expand Up @@ -33,8 +33,8 @@

#include "qgscolorrampshader.h"
#include "qgsdataprovider.h"
#include "qgsfields.h"
#include "qgsraster.h"
#include "qgsfields.h"
#include "qgsrasterinterface.h"
#include "qgsrasterpyramid.h"
#include "qgsrasterrange.h"
Expand Down Expand Up @@ -134,6 +134,13 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast
//! Returns data type for the band specified by number
Qgis::DataType dataType( int bandNo ) const override = 0;

/**
* Returns the fields of the raster layer for data providers that expose them,
* the default implementation returns an empty list.
* \since QGIS 3.14
*/
virtual QgsFields fields() const { return QgsFields(); };

/**
* Returns source data type for the band specified by number,
* source data type may be shorter than dataType
Expand Down
3 changes: 3 additions & 0 deletions src/core/raster/qgsrasterlayer.cpp
Expand Up @@ -866,6 +866,9 @@ void QgsRasterLayer::setDataSource( const QString &dataSource, const QString &ba

setDataProvider( provider, options );

if ( mDataProvider )
mDataProvider->setDataSourceUri( mDataSource );

if ( mValid )
{
mTemporalProperties->setDefaultsFromDataProviderTemporalCapabilities( mDataProvider->temporalCapabilities() );
Expand Down
90 changes: 82 additions & 8 deletions src/gui/raster/qgsrasterlayerproperties.cpp
Expand Up @@ -59,6 +59,7 @@
#include "qgsmaplayerlegend.h"
#include "qgsfileutils.h"
#include "qgswebview.h"
#include "qgsvectorlayer.h"

#include "qgsrasterlayertemporalpropertieswidget.h"
#include "qgsprojecttimesettings.h"
Expand Down Expand Up @@ -288,6 +289,49 @@ QgsRasterLayerProperties::QgsRasterLayerProperties( QgsMapLayer *lyr, QgsMapCanv
setSourceStaticTimeState();
mWmstGroup->setVisible( mRasterLayer->providerType() == QLatin1String( "wms" ) && mRasterLayer->dataProvider() && mRasterLayer->dataProvider()->temporalCapabilities()->hasTemporalCapabilities() );

// This group is used to define the temporal capabilities of the PG raster layer
if ( mRasterLayer->dataProvider() && mRasterLayer->providerType() == QLatin1String( "postgresraster" ) )
{
mPostgresRasterTemporalGroup->setEnabled( true );
mPostgresRasterTemporalGroup->setVisible( true );
mPostgresRasterTemporalGroup->setChecked( false );
const QgsFields fields { mRasterLayer->dataProvider()->fields() };
mPostgresRasterTemporalFieldComboBox->setFields( fields );
mPostgresRasterTemporalFieldComboBox->setFilters( QgsFieldProxyModel::Filter::Date |
QgsFieldProxyModel::Filter::DateTime |
QgsFieldProxyModel::Filter::String );
mPostgresRasterTemporalFieldComboBox->setAllowEmptyFieldName( true );
connect( mPostgresRasterTemporalFieldComboBox, &QgsFieldComboBox::fieldChanged, this, [ = ]( const QString & fieldName )
{
mPostgresRasterDefaultTime->setEnabled( ! fieldName.isEmpty() );
} );
mPostgresRasterDefaultTime->setAllowNull( true );
mPostgresRasterDefaultTime->setEmpty();
if ( mRasterLayer->dataProvider()->uri().hasParam( QStringLiteral( "temporalFieldIndex" ) ) )
{
bool ok;
const int fieldIdx { mRasterLayer->dataProvider()->uri().param( QStringLiteral( "temporalFieldIndex" ) ).toInt( &ok ) };
if ( ok && fields.exists( fieldIdx ) )
{
mPostgresRasterTemporalGroup->setChecked( true );
mPostgresRasterTemporalFieldComboBox->setField( fields.field( fieldIdx ).name() );
if ( mRasterLayer->dataProvider()->uri().hasParam( QStringLiteral( "temporalDefaultTime" ) ) )
{
const QDateTime defaultDateTime { QDateTime::fromString( mRasterLayer->dataProvider()->uri().param( QStringLiteral( "temporalDefaultTime" ) ), Qt::DateFormat::ISODate ) };
if ( defaultDateTime.isValid() )
{
mPostgresRasterDefaultTime->setDateTime( defaultDateTime );
}
}
}
}
}
else
{
mPostgresRasterTemporalGroup->setEnabled( false );
mPostgresRasterTemporalGroup->setVisible( false );
}

QgsDebugMsg( "Setting crs to " + mRasterLayer->crs().toWkt( QgsCoordinateReferenceSystem::WKT2_2018 ) );
QgsDebugMsg( "Setting crs to " + mRasterLayer->crs().userFriendlyIdentifier() );
mCrsSelector->setCrs( mRasterLayer->crs() );
Expand Down Expand Up @@ -1083,6 +1127,41 @@ void QgsRasterLayerProperties::apply()

updateSourceStaticTime();

// Update temporal field
if ( mRasterLayer->dataProvider() )
{
QgsDataSourceUri uri { mRasterLayer->dataProvider()->uri() };
if ( mPostgresRasterTemporalGroup->isEnabled() &&
mPostgresRasterTemporalGroup->isChecked() &&
! mPostgresRasterTemporalFieldComboBox->currentField().isEmpty() )
{
const QString originaUri { uri.uri() };
const int fieldIdx { mRasterLayer->dataProvider()->fields().lookupField( mPostgresRasterTemporalFieldComboBox->currentField() ) };
uri.removeParam( QStringLiteral( "temporalFieldIndex" ) );
uri.removeParam( QStringLiteral( "temporalDefaultTime" ) );
if ( fieldIdx >= 0 )
{
uri.setParam( QStringLiteral( "temporalFieldIndex" ), QString::number( fieldIdx ) );
if ( mPostgresRasterDefaultTime->dateTime().isValid() )
{
QDateTime defaultDateTime { mPostgresRasterDefaultTime->dateTime() };
const QTime defaultTime { defaultDateTime.time() };
// Set secs to 0
defaultDateTime.setTime( { defaultTime.hour(), defaultTime.minute(), 0 } );
uri.setParam( QStringLiteral( "temporalDefaultTime" ), defaultDateTime.toString( Qt::DateFormat::ISODate ) );
}
if ( uri.uri( ) != originaUri )
mRasterLayer->setDataSource( uri.uri(), mRasterLayer->name(), mRasterLayer->providerType(), QgsDataProvider::ProviderOptions() );
}
}
else if ( uri.hasParam( QStringLiteral( "temporalFieldIndex" ) ) )
{
uri.removeParam( QStringLiteral( "temporalFieldIndex" ) );
uri.removeParam( QStringLiteral( "temporalDefaultTime" ) );
mRasterLayer->setDataSource( uri.uri(), mRasterLayer->name(), mRasterLayer->providerType(), QgsDataProvider::ProviderOptions() );
}
}

// Update temporal properties
mTemporalWidget->saveTemporalProperties();

Expand Down Expand Up @@ -1167,9 +1246,7 @@ void QgsRasterLayerProperties::updateSourceStaticTime()
mRasterLayer->dataProvider() &&
mRasterLayer->dataProvider()->temporalCapabilities()->hasTemporalCapabilities() )
{
QgsDataSourceUri uri;
QString uriString = mRasterLayer->dataProvider()->dataSourceUri();
uri.setEncodedUri( uriString );
QgsDataSourceUri uri { mRasterLayer->dataProvider()->uri() };

if ( mStaticTemporalRange->isChecked() )
{
Expand Down Expand Up @@ -1212,8 +1289,7 @@ void QgsRasterLayerProperties::updateSourceStaticTime()
uri.removeParam( QStringLiteral( "enableTime" ) );
uri.setParam( QStringLiteral( "enableTime" ), enableTime );

mRasterLayer->dataProvider()->setDataSourceUri( uri.encodedUri() );
mRasterLayer->setDataSource( mRasterLayer->dataProvider()->dataSourceUri(), mRasterLayer->name(), mRasterLayer->providerType(), QgsDataProvider::ProviderOptions() );
mRasterLayer->setDataSource( uri.uri(), mRasterLayer->name(), mRasterLayer->providerType(), QgsDataProvider::ProviderOptions() );

mRasterLayer->temporalProperties()->setIntervalHandlingMethod( static_cast< QgsRasterDataProviderTemporalCapabilities::IntervalHandlingMethod >(
mFetchModeComboBox->currentData().toInt() ) );
Expand All @@ -1227,9 +1303,7 @@ void QgsRasterLayerProperties::setSourceStaticTimeState()
const QgsDateTimeRange availableProviderRange = mRasterLayer->dataProvider()->temporalCapabilities()->availableTemporalRange();
const QgsDateTimeRange availableReferenceRange = mRasterLayer->dataProvider()->temporalCapabilities()->availableReferenceTemporalRange();

QgsDataSourceUri uri;
const QString uriString = mRasterLayer->dataProvider()->dataSourceUri() ;
uri.setEncodedUri( uriString );
QgsDataSourceUri uri { mRasterLayer->dataProvider()->uri() };

mStartStaticDateTimeEdit->setDisplayFormat( "yyyy-MM-dd HH:mm:ss" );
mEndStaticDateTimeEdit->setDisplayFormat( "yyyy-MM-dd HH:mm:ss" );
Expand Down

0 comments on commit 8fa6338

Please sign in to comment.