Skip to content
Permalink
Browse files

[FEATURE][temporal] Add off and fixed range modes to temporal navigation

  • Loading branch information
nirvn committed May 14, 2020
1 parent db1062c commit ba5b4166dae84a3d1ce0b397029432cb88633a87
@@ -712,6 +712,9 @@
<file>themes/default/mTaskRunning.svg</file>
<file>themes/default/mTaskTerminated.svg</file>
<file>themes/default/mTaskCancel.svg</file>
<file>themes/default/mTemporalNavigationOff.svg</file>
<file>themes/default/mTemporalNavigationFixedRange.svg</file>
<file>themes/default/mTemporalNavigationAnimated.svg</file>
<file>themes/default/providerGdal.svg</file>
<file>themes/default/providerGrass.svg</file>
<file>themes/default/providerQgis.svg</file>
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 6.35 6.35"><g transform="translate(0 -288.53)" stroke="#000"><circle cx="3.175" cy="291.705" fill="#fff" stroke-width=".482" r="2.669"/><path d="M3.072 291.774v-1.704m.968 2.387l-.967-.68" fill="#888a85" stroke-width=".415" stroke-linecap="round"/><path stroke-linejoin="round" stroke-linecap="round" stroke="#4c734c" fill-rule="evenodd" fill="#5a8c5a" d="M6.051 293.293l-2.215 1.455v-2.91z" stroke-width=".265"/><path fill-rule="evenodd" fill-opacity=".529" fill="#fff" d="M4.226 294.34v-2.091l-.253-.159v2.403z" stroke="none"/></g></svg>
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 6.35 6.35" height="24" width="24"><g stroke="#000" transform="translate(0 -288.53)"><circle cy="291.705" cx="3.175" fill="#fff" stroke-width=".482" r="2.669"/><path d="M3.072 291.774v-1.704m.968 2.387l-.967-.68" fill="#888a85" stroke-width=".415" stroke-linecap="round"/></g></svg>
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 6.35 6.35" height="24" width="24"><g stroke="#000" transform="translate(0 -288.53)"><circle cy="291.705" cx="3.175" opacity=".5" fill="#fff" stroke-width=".482" r="2.669"/><path d="M3.072 291.774v-1.704m.968 2.387l-.967-.68" opacity=".5" fill="#888a85" stroke-width=".415" stroke-linecap="round"/><path d="M.53 294.35l5.29-5.29M.53 289.06l5.29 5.29" fill="none" stroke="#af0000" stroke-width=".529" stroke-linecap="round"/></g></svg>
@@ -30,6 +30,13 @@ Implements a temporal controller based on a frame by frame navigation and animat
Constructor for QgsTemporalNavigationObject, with the specified ``parent`` object.
%End

enum NavigationMode
{
NavigationOff,
Animated,
FixedRange,
};

enum AnimationState
{
Forward,
@@ -49,6 +56,20 @@ Sets the current animation ``state``.
Returns the current animation state.

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

void setNavigationMode( const NavigationMode mode );
%Docstring
Sets the temporal navigation ``mode``.

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

NavigationMode navigationMode() const;
%Docstring
Returns the currenttemporal navigation mode.

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

void setTemporalExtents( const QgsDateTimeRange &extents );
@@ -175,6 +196,11 @@ Sets whether the animation should ``loop`` after hitting the end or start frame.
void stateChanged( AnimationState state );
%Docstring
Emitted whenever the animation ``state`` changes.
%End

void navigationModeChanged( NavigationMode mode );
%Docstring
Emitted whenever the navigation ``mode`` changes.
%End

public slots:
@@ -104,16 +104,50 @@ QgsDateTimeRange QgsTemporalNavigationObject::dateTimeRangeForFrameNumber( long
return QgsDateTimeRange( frameStart, mTemporalExtents.end(), true, false );
}

void QgsTemporalNavigationObject::setNavigationMode( const NavigationMode mode )
{
if ( mNavigationMode == mode )
return;

mNavigationMode = mode;
emit navigationModeChanged( mode );

switch ( mNavigationMode )
{
case Animated:
emit updateTemporalRange( dateTimeRangeForFrameNumber( mCurrentFrameNumber ) );
break;
case FixedRange:
emit updateTemporalRange( mTemporalExtents );
break;
case NavigationOff:
emit updateTemporalRange( QgsDateTimeRange() );
break;
}
}

void QgsTemporalNavigationObject::setTemporalExtents( const QgsDateTimeRange &temporalExtents )
{
mTemporalExtents = temporalExtents;
int currentFrameNmber = mCurrentFrameNumber;
setCurrentFrameNumber( 0 );

//Force to emit signal if the current frame number doesn't change
if ( currentFrameNmber == mCurrentFrameNumber )
emit updateTemporalRange( dateTimeRangeForFrameNumber( 0 ) );

switch ( mNavigationMode )
{
case Animated:
{
int currentFrameNmber = mCurrentFrameNumber;
setCurrentFrameNumber( 0 );

//Force to emit signal if the current frame number doesn't change
if ( currentFrameNmber == mCurrentFrameNumber )
emit updateTemporalRange( dateTimeRangeForFrameNumber( 0 ) );
break;
}
case FixedRange:
emit updateTemporalRange( mTemporalExtents );
break;
case NavigationOff:
break;
}
}

QgsDateTimeRange QgsTemporalNavigationObject::temporalExtents() const
@@ -47,6 +47,13 @@ class CORE_EXPORT QgsTemporalNavigationObject : public QgsTemporalController, pu
*/
QgsTemporalNavigationObject( QObject *parent SIP_TRANSFERTHIS = nullptr );

enum NavigationMode
{
NavigationOff, //!< Temporal navigation is disabled
Animated, //!< Temporal navigation relies on frames within a datetime range
FixedRange, //!< Temporal navigation relies on a fixed datetime range
};

//! Represents the current animation state.
enum AnimationState
{
@@ -69,6 +76,20 @@ class CORE_EXPORT QgsTemporalNavigationObject : public QgsTemporalController, pu
*/
AnimationState animationState() const;

/**
* Sets the temporal navigation \a mode.
*
* \see navigationMode()
*/
void setNavigationMode( const NavigationMode mode );

/**
* Returns the currenttemporal navigation mode.
*
* \see setNavigationMode()
*/
NavigationMode navigationMode() const { return mNavigationMode; }

/**
* Sets the navigation temporal \a extents, which dictate the earliest
* and latest date time possible in the animation.
@@ -190,6 +211,11 @@ class CORE_EXPORT QgsTemporalNavigationObject : public QgsTemporalController, pu
*/
void stateChanged( AnimationState state );

/**
* Emitted whenever the navigation \a mode changes.
*/
void navigationModeChanged( NavigationMode mode );

public slots:

/**
@@ -255,6 +281,8 @@ class CORE_EXPORT QgsTemporalNavigationObject : public QgsTemporalController, pu
//! The controller temporal navigation extent range.
QgsDateTimeRange mTemporalExtents;

NavigationMode mNavigationMode = Animated;

//! The current set frame value
long long mCurrentFrameNumber = 0;

@@ -798,6 +798,7 @@ void QgsMapCanvas::setTemporalRange( const QgsDateTimeRange &dateTimeRange )
return;

mSettings.setTemporalRange( dateTimeRange );
mSettings.setIsTemporal( dateTimeRange.begin().isValid() || dateTimeRange.end().isValid() );

emit temporalRangeChanged();

@@ -19,7 +19,6 @@
#include "qgsgui.h"
#include "qgsproject.h"
#include "qgsprojecttimesettings.h"
#include "qgstemporalnavigationobject.h"
#include "qgstemporalmapsettingswidget.h"
#include "qgstemporalutils.h"
#include "qgsmaplayertemporalproperties.h"
@@ -40,6 +39,12 @@ QgsTemporalControllerWidget::QgsTemporalControllerWidget( QWidget *parent )
connect( mRewindButton, &QPushButton::clicked, mNavigationObject, &QgsTemporalNavigationObject::rewindToStart );
connect( mLoopingCheckBox, &QCheckBox::toggled, this, [ = ]( bool state ) { mNavigationObject->setLooping( state ); } );

setWidgetStateFromNavigationMode( mNavigationObject->navigationMode() );
connect( mNavigationObject, &QgsTemporalNavigationObject::navigationModeChanged, this, &QgsTemporalControllerWidget::setWidgetStateFromNavigationMode );
connect( mNavigationOff, &QPushButton::clicked, this, &QgsTemporalControllerWidget::mNavigationOff_clicked );
connect( mNavigationFixedRange, &QPushButton::clicked, this, &QgsTemporalControllerWidget::mNavigationFixedRange_clicked );
connect( mNavigationAnimated, &QPushButton::clicked, this, &QgsTemporalControllerWidget::mNavigationAnimated_clicked );

connect( mNavigationObject, &QgsTemporalNavigationObject::stateChanged, this, [ = ]( QgsTemporalNavigationObject::AnimationState state )
{
mForwardButton->setChecked( state == QgsTemporalNavigationObject::Forward );
@@ -49,11 +54,11 @@ QgsTemporalControllerWidget::QgsTemporalControllerWidget( QWidget *parent )

connect( mStartDateTime, &QDateTimeEdit::dateTimeChanged, this, &QgsTemporalControllerWidget::startEndDateTime_changed );
connect( mEndDateTime, &QDateTimeEdit::dateTimeChanged, this, &QgsTemporalControllerWidget::startEndDateTime_changed );
connect( mSpinBox, qgis::overload<double>::of( &QDoubleSpinBox::valueChanged ), this, &QgsTemporalControllerWidget::updateFrameDuration );
connect( mStepSpinBox, qgis::overload<double>::of( &QDoubleSpinBox::valueChanged ), this, &QgsTemporalControllerWidget::updateFrameDuration );
connect( mTimeStepsComboBox, qgis::overload<int>::of( &QComboBox::currentIndexChanged ), this, &QgsTemporalControllerWidget::updateFrameDuration );
connect( mSlider, &QSlider::valueChanged, this, &QgsTemporalControllerWidget::timeSlider_valueChanged );

mSpinBox->setClearValue( 1 );
mStepSpinBox->setClearValue( 1 );

connect( mNavigationObject, &QgsTemporalNavigationObject::updateTemporalRange, this, &QgsTemporalControllerWidget::updateSlider );

@@ -101,10 +106,10 @@ QgsTemporalControllerWidget::QgsTemporalControllerWidget( QWidget *parent )
// TODO: might want to choose an appropriate default unit based on the range
mTimeStepsComboBox->setCurrentIndex( mTimeStepsComboBox->findData( QgsUnitTypes::TemporalHours ) );

mSpinBox->setMinimum( 0.0000001 );
mSpinBox->setMaximum( std::numeric_limits<int>::max() );
mSpinBox->setSingleStep( 1 );
mSpinBox->setValue( 1 );
mStepSpinBox->setMinimum( 0.0000001 );
mStepSpinBox->setMaximum( std::numeric_limits<int>::max() );
mStepSpinBox->setSingleStep( 1 );
mStepSpinBox->setValue( 1 );

mForwardButton->setToolTip( tr( "Play" ) );
mBackButton->setToolTip( tr( "Reverse" ) );
@@ -137,7 +142,7 @@ void QgsTemporalControllerWidget::updateFrameDuration()

// save new settings into project
QgsProject::instance()->timeSettings()->setTimeStepUnit( static_cast< QgsUnitTypes::TemporalUnit>( mTimeStepsComboBox->currentData().toInt() ) );
QgsProject::instance()->timeSettings()->setTimeStep( mSpinBox->value() );
QgsProject::instance()->timeSettings()->setTimeStep( mStepSpinBox->value() );

mNavigationObject->setFrameDuration( QgsInterval( QgsProject::instance()->timeSettings()->timeStep(),
QgsProject::instance()->timeSettings()->timeStepUnit() ) );
@@ -148,9 +153,15 @@ void QgsTemporalControllerWidget::setWidgetStateFromProject()
{
mBlockSettingUpdates++;
mTimeStepsComboBox->setCurrentIndex( mTimeStepsComboBox->findData( QgsProject::instance()->timeSettings()->timeStepUnit() ) );
mSpinBox->setValue( QgsProject::instance()->timeSettings()->timeStep() );
mStepSpinBox->setValue( QgsProject::instance()->timeSettings()->timeStep() );
mBlockSettingUpdates--;

bool ok = false;
QgsTemporalNavigationObject::NavigationMode mode = static_cast< QgsTemporalNavigationObject::NavigationMode>( QgsProject::instance()->readNumEntry( QStringLiteral( "TemporalControllerWidget" ),
QStringLiteral( "/NavigationMode" ), 0, &ok ) );
if ( ok )
mNavigationObject->setNavigationMode( mode );

const QString startString = QgsProject::instance()->readEntry( QStringLiteral( "TemporalControllerWidget" ), QStringLiteral( "/StartDateTime" ) );
const QString endString = QgsProject::instance()->readEntry( QStringLiteral( "TemporalControllerWidget" ), QStringLiteral( "/EndDateTime" ) );
if ( !startString.isEmpty() && !endString.isEmpty() )
@@ -169,6 +180,58 @@ void QgsTemporalControllerWidget::setWidgetStateFromProject()
mNavigationObject->setTemporalRangeCumulative( QgsProject::instance()->timeSettings()->isTemporalRangeCumulative() );
}

void QgsTemporalControllerWidget::mNavigationOff_clicked()
{
QgsProject::instance()->writeEntry( QStringLiteral( "TemporalControllerWidget" ), QStringLiteral( "/NavigationMode" ),
static_cast<int>( QgsTemporalNavigationObject::NavigationOff ) );

mNavigationObject->setNavigationMode( QgsTemporalNavigationObject::NavigationOff );
setWidgetStateFromNavigationMode( QgsTemporalNavigationObject::NavigationOff );
}

void QgsTemporalControllerWidget::mNavigationFixedRange_clicked()
{
QgsProject::instance()->writeEntry( QStringLiteral( "TemporalControllerWidget" ), QStringLiteral( "/NavigationMode" ),
static_cast<int>( QgsTemporalNavigationObject::FixedRange ) );

mNavigationObject->setNavigationMode( QgsTemporalNavigationObject::FixedRange );
setWidgetStateFromNavigationMode( QgsTemporalNavigationObject::FixedRange );
}

void QgsTemporalControllerWidget::mNavigationAnimated_clicked()
{
QgsProject::instance()->writeEntry( QStringLiteral( "TemporalControllerWidget" ), QStringLiteral( "/NavigationMode" ),
static_cast<int>( QgsTemporalNavigationObject::Animated ) );

mNavigationObject->setNavigationMode( QgsTemporalNavigationObject::Animated );
setWidgetStateFromNavigationMode( QgsTemporalNavigationObject::Animated );
}

void QgsTemporalControllerWidget::setWidgetStateFromNavigationMode( const QgsTemporalNavigationObject::NavigationMode mode )
{
mNavigationOff->setChecked( mode == QgsTemporalNavigationObject::NavigationOff );
mNavigationFixedRange->setChecked( mode == QgsTemporalNavigationObject::FixedRange );
mNavigationAnimated->setChecked( mode == QgsTemporalNavigationObject::Animated );

mRewindButton->setVisible( mode == QgsTemporalNavigationObject::Animated );
mPreviousButton->setVisible( mode == QgsTemporalNavigationObject::Animated );
mBackButton->setVisible( mode == QgsTemporalNavigationObject::Animated );
mStopButton->setVisible( mode == QgsTemporalNavigationObject::Animated );
mForwardButton->setVisible( mode == QgsTemporalNavigationObject::Animated );
mNextButton->setVisible( mode == QgsTemporalNavigationObject::Animated );
mFastForwardButton->setVisible( mode == QgsTemporalNavigationObject::Animated );
mSlider->setVisible( mode == QgsTemporalNavigationObject::Animated );
mLoopingCheckBox->setVisible( mode == QgsTemporalNavigationObject::Animated );
mStepLabel->setVisible( mode == QgsTemporalNavigationObject::Animated );
mStepSpinBox->setVisible( mode == QgsTemporalNavigationObject::Animated );
mTimeStepsComboBox->setVisible( mode == QgsTemporalNavigationObject::Animated );
mRangeLabel->setVisible( mode == QgsTemporalNavigationObject::FixedRange || mode == QgsTemporalNavigationObject::Animated );
mStartDateTime->setVisible( mode == QgsTemporalNavigationObject::FixedRange || mode == QgsTemporalNavigationObject::Animated );
mRangeToLabel->setVisible( mode == QgsTemporalNavigationObject::FixedRange || mode == QgsTemporalNavigationObject::Animated );
mEndDateTime->setVisible( mode == QgsTemporalNavigationObject::FixedRange || mode == QgsTemporalNavigationObject::Animated );
mSetToProjectTimeButton->setVisible( mode == QgsTemporalNavigationObject::FixedRange || mode == QgsTemporalNavigationObject::Animated );
}

void QgsTemporalControllerWidget::onLayersAdded( const QList<QgsMapLayer *> &layers )
{
if ( !mHasTemporalLayersLoaded )
@@ -215,9 +278,22 @@ void QgsTemporalControllerWidget::updateSlider( const QgsDateTimeRange &range )

void QgsTemporalControllerWidget::updateRangeLabel( const QgsDateTimeRange &range )
{
mCurrentRangeLabel->setText( tr( "%1 to %2" ).arg(
range.begin().toString( "yyyy-MM-dd HH:mm:ss" ),
range.end().toString( "yyyy-MM-dd HH:mm:ss" ) ) );
switch ( mNavigationObject->navigationMode() )
{
case QgsTemporalNavigationObject::Animated:
mCurrentRangeLabel->setText( tr( "Frame: %1 to %2" ).arg(
range.begin().toString( "yyyy-MM-dd HH:mm:ss" ),
range.end().toString( "yyyy-MM-dd HH:mm:ss" ) ) );
break;
case QgsTemporalNavigationObject::FixedRange:
mCurrentRangeLabel->setText( tr( "Range: %1 to %2" ).arg(
range.begin().toString( "yyyy-MM-dd HH:mm:ss" ),
range.end().toString( "yyyy-MM-dd HH:mm:ss" ) ) );
break;
case QgsTemporalNavigationObject::NavigationOff:
mCurrentRangeLabel->setText( tr( "Temporal navigation disabled" ) );
break;
}
}

QgsTemporalController *QgsTemporalControllerWidget::temporalController()
@@ -22,6 +22,7 @@

#include "qgis_gui.h"
#include "qgsrange.h"
#include "qgstemporalnavigationobject.h"

class QgsMapLayer;
class QgsTemporalNavigationObject;
@@ -121,6 +122,11 @@ class GUI_EXPORT QgsTemporalControllerWidget : public QgsPanelWidget, private Ui

void setWidgetStateFromProject();

void mNavigationOff_clicked();
void mNavigationFixedRange_clicked();
void mNavigationAnimated_clicked();
void setWidgetStateFromNavigationMode( const QgsTemporalNavigationObject::NavigationMode mode );

void onLayersAdded( const QList<QgsMapLayer *> &layers );
void onProjectCleared();

0 comments on commit ba5b416

Please sign in to comment.
You can’t perform that action at this time.