Skip to content
Permalink
Browse files
Adding the possibility to include the end of the temporal filtering T…
…imeRange

Default temporal filtering (of vector features) in most software will
INclude the begin/start of the filtering range, but EXclude the end of it.
So: if you filter with say a filter of 1900-1910, by default features with
1900 will be selected, but with 1910 will NOT (exclude end).

This commit adds the possibility (in the Temporal Features tab of the
vector layer properties) to choose the 'limitMode'.
The limitmode can now also be set to INclude begin AND INclude end.
So in the above example, also the features with 1910 will be selected.

The limitMode is written to the xml project file as temporal attribute.
  • Loading branch information
rduivenvoorde authored and nyalldawson committed Sep 8, 2021
1 parent eabc0a7 commit 47bf9e31770fc4e893ad9094aded611ff01971c8
@@ -229,6 +229,18 @@ void QgsVectorLayerTemporalProperties::setMode( QgsVectorLayerTemporalProperties
mMode = mode;
}

QgsVectorLayerTemporalProperties::LimitMode QgsVectorLayerTemporalProperties::limitMode() const
{
return mLimitMode;
}

void QgsVectorLayerTemporalProperties::setLimitMode( QgsVectorLayerTemporalProperties::LimitMode limitMode )
{
if ( mLimitMode == limitMode )
return;
mLimitMode = limitMode;
}

QgsTemporalProperty::Flags QgsVectorLayerTemporalProperties::flags() const
{
return mode() == ModeFixedTemporalRange ? QgsTemporalProperty::FlagDontInvalidateCachedRendersWhenRangeChanges : QgsTemporalProperty::Flags();
@@ -254,6 +266,7 @@ bool QgsVectorLayerTemporalProperties::readXml( const QDomElement &element, cons

mMode = static_cast< TemporalMode >( temporalNode.attribute( QStringLiteral( "mode" ), QStringLiteral( "0" ) ). toInt() );

mLimitMode = static_cast< LimitMode >( temporalNode.attribute( QStringLiteral( "limitMode" ), QStringLiteral( "0" ) ). toInt() );
mStartFieldName = temporalNode.attribute( QStringLiteral( "startField" ) );
mEndFieldName = temporalNode.attribute( QStringLiteral( "endField" ) );
mStartExpression = temporalNode.attribute( QStringLiteral( "startExpression" ) );
@@ -287,6 +300,7 @@ QDomElement QgsVectorLayerTemporalProperties::writeXml( QDomElement &element, QD
temporalElement.setAttribute( QStringLiteral( "enabled" ), isActive() ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
temporalElement.setAttribute( QStringLiteral( "mode" ), QString::number( mMode ) );

temporalElement.setAttribute( QStringLiteral( "limitMode" ), QString::number( mLimitMode ) );
temporalElement.setAttribute( QStringLiteral( "startField" ), mStartFieldName );
temporalElement.setAttribute( QStringLiteral( "endField" ), mEndFieldName );
temporalElement.setAttribute( QStringLiteral( "startExpression" ), mStartExpression );
@@ -433,6 +447,16 @@ QString QgsVectorLayerTemporalProperties::createFilterString( QgsVectorLayerTemp
if ( !isActive() )
return QString();

QgsDateTimeRange filter;
if ( limitMode() == QgsVectorLayerTemporalProperties::ModeIncludeBeginIncludeEnd )
{
filter = QgsDateTimeRange(filterRange.begin(), filterRange.end(), true, true);
}
else
{
filter = QgsDateTimeRange(filterRange.begin(), filterRange.end(), true, false); // default is include begin, exclude end of filter
}

switch ( mMode )
{
case ModeFixedTemporalRange:
@@ -444,24 +468,24 @@ QString QgsVectorLayerTemporalProperties::createFilterString( QgsVectorLayerTemp
if ( mAccumulateFeatures )
{
return QStringLiteral( "(%1 %2 %3) OR %1 IS NULL" ).arg( QgsExpression::quotedColumnRef( mStartFieldName ),
filterRange.includeEnd() ? QStringLiteral( "<=" ) : QStringLiteral( "<" ),
dateTimeExpressionLiteral( filterRange.end() ) );
filter.includeEnd() ? QStringLiteral( "<=" ) : QStringLiteral( "<" ),
dateTimeExpressionLiteral( filter.end() ) );
}
else if ( qgsDoubleNear( mFixedDuration, 0.0 ) )
{
return QStringLiteral( "(%1 %2 %3 AND %1 %4 %5) OR %1 IS NULL" ).arg( QgsExpression::quotedColumnRef( mStartFieldName ),
filterRange.includeBeginning() ? QStringLiteral( ">=" ) : QStringLiteral( ">" ),
dateTimeExpressionLiteral( filterRange.begin() ),
filterRange.includeEnd() ? QStringLiteral( "<=" ) : QStringLiteral( "<" ),
dateTimeExpressionLiteral( filterRange.end() ) );
filter.includeBeginning() ? QStringLiteral( ">=" ) : QStringLiteral( ">" ),
dateTimeExpressionLiteral( filter.begin() ),
filter.includeEnd() ? QStringLiteral( "<=" ) : QStringLiteral( "<" ),
dateTimeExpressionLiteral( filter.end() ) );
}
else
{
// Working with features with events with a duration, so taking this duration into account (+ QgsInterval( -mFixedDuration, mDurationUnit ) ))
return QStringLiteral( "(%1 > %2 AND %1 %3 %4) OR %1 IS NULL" ).arg( QgsExpression::quotedColumnRef( mStartFieldName ),
dateTimeExpressionLiteral( filterRange.begin() + QgsInterval( -mFixedDuration, mDurationUnit ) ),
filterRange.includeEnd() ? QStringLiteral( "<=" ) : QStringLiteral( "<" ),
dateTimeExpressionLiteral( filterRange.end() ) );
dateTimeExpressionLiteral( filter.begin() + QgsInterval( -mFixedDuration, mDurationUnit ) ),
filter.includeEnd() ? QStringLiteral( "<=" ) : QStringLiteral( "<" ),
dateTimeExpressionLiteral( filter.end() ) );
}
}

@@ -515,10 +539,10 @@ QString QgsVectorLayerTemporalProperties::createFilterString( QgsVectorLayerTemp
return QString();
}
return QStringLiteral( "(%1 %2 %3 OR %1 IS NULL) AND ((%1 + %4 > %5) OR %6 IS NULL)" ).arg( QgsExpression::quotedColumnRef( mStartFieldName ),
filterRange.includeEnd() ? QStringLiteral( "<=" ) : QStringLiteral( "<" ),
dateTimeExpressionLiteral( filterRange.end() ),
filter.includeEnd() ? QStringLiteral( "<=" ) : QStringLiteral( "<" ),
dateTimeExpressionLiteral( filter.end() ),
intervalExpression,
dateTimeExpressionLiteral( filterRange.begin() ),
dateTimeExpressionLiteral( filter.begin() ),
QgsExpression::quotedColumnRef( mDurationFieldName ) );
}

@@ -527,21 +551,21 @@ QString QgsVectorLayerTemporalProperties::createFilterString( QgsVectorLayerTemp
if ( !mStartFieldName.isEmpty() && !mEndFieldName.isEmpty() )
{
return QStringLiteral( "(%1 %2 %3 OR %1 IS NULL) AND (%4 > %5 OR %4 IS NULL)" ).arg( QgsExpression::quotedColumnRef( mStartFieldName ),
filterRange.includeEnd() ? QStringLiteral( "<=" ) : QStringLiteral( "<" ),
dateTimeExpressionLiteral( filterRange.end() ),
filter.includeEnd() ? QStringLiteral( "<=" ) : QStringLiteral( "<" ),
dateTimeExpressionLiteral( filter.end() ),
QgsExpression::quotedColumnRef( mEndFieldName ),
dateTimeExpressionLiteral( filterRange.begin() ) );
dateTimeExpressionLiteral( filter.begin() ) );
}
else if ( !mStartFieldName.isEmpty() )
{
return QStringLiteral( "%1 %2 %3 OR %1 IS NULL" ).arg( QgsExpression::quotedColumnRef( mStartFieldName ),
filterRange.includeEnd() ? QStringLiteral( "<=" ) : QStringLiteral( "<" ),
dateTimeExpressionLiteral( filterRange.end() ) );
filter.includeEnd() ? QStringLiteral( "<=" ) : QStringLiteral( "<" ),
dateTimeExpressionLiteral( filter.end() ) );
}
else if ( !mEndFieldName.isEmpty() )
{
return QStringLiteral( "%1 > %2 OR %1 IS NULL" ).arg( QgsExpression::quotedColumnRef( mEndFieldName ),
dateTimeExpressionLiteral( filterRange.begin() ) );
dateTimeExpressionLiteral( filter.begin() ) );
}
break;
}
@@ -551,21 +575,21 @@ QString QgsVectorLayerTemporalProperties::createFilterString( QgsVectorLayerTemp
if ( !mStartExpression.isEmpty() && !mEndExpression.isEmpty() )
{
return QStringLiteral( "((%1) %2 %3) AND ((%4) > %5)" ).arg( mStartExpression,
filterRange.includeEnd() ? QStringLiteral( "<=" ) : QStringLiteral( "<" ),
dateTimeExpressionLiteral( filterRange.end() ),
filter.includeEnd() ? QStringLiteral( "<=" ) : QStringLiteral( "<" ),
dateTimeExpressionLiteral( filter.end() ),
mEndExpression,
dateTimeExpressionLiteral( filterRange.begin() ) );
dateTimeExpressionLiteral( filter.begin() ) );
}
else if ( !mStartExpression.isEmpty() )
{
return QStringLiteral( "(%1) %2 %3" ).arg( mStartExpression,
filterRange.includeEnd() ? QStringLiteral( "<=" ) : QStringLiteral( "<" ),
dateTimeExpressionLiteral( filterRange.end() ) );
filter.includeEnd() ? QStringLiteral( "<=" ) : QStringLiteral( "<" ),
dateTimeExpressionLiteral( filter.end() ) );
}
else if ( !mEndExpression.isEmpty() )
{
return QStringLiteral( "(%1) > %2" ).arg( mEndExpression,
dateTimeExpressionLiteral( filterRange.begin() ) );
dateTimeExpressionLiteral( filter.begin() ) );
}
break;
}
@@ -96,6 +96,15 @@ class CORE_EXPORT QgsVectorLayerTemporalProperties : public QgsMapLayerTemporalP
ModeRedrawLayerOnly, //!< Redraw the layer when temporal range changes, but don't apply any filtering. Useful when symbology or rule based renderer expressions depend on the time range.
};

/**
* Mode for the handling of the limits of the filtering timeframe
*/
enum LimitMode
{
ModeIncludeBeginExcludeEnd = 0, //!< Default mode: include the Begin limit, but exclude the End limit
ModeIncludeBeginIncludeEnd, //!< Mode to include both limits of the filtering timeframe
};

/**
* Returns the temporal properties mode.
*
@@ -110,6 +119,20 @@ class CORE_EXPORT QgsVectorLayerTemporalProperties : public QgsMapLayerTemporalP
*/
void setMode( TemporalMode mode );

/**
* Returns the temporal limit mode (to include or exclude begin/end limits).
*
*\see setLimitMode()
*/
LimitMode limitMode() const;

/**
* Sets the temporal \a limit mode (to include or exclude begin/end limits).
*
*\see limitMode()
*/
void setLimitMode( LimitMode mode );

/**
* Returns flags associated to the temporal property.
*/
@@ -342,6 +365,9 @@ class CORE_EXPORT QgsVectorLayerTemporalProperties : public QgsMapLayerTemporalP
//! Temporal layer mode.
TemporalMode mMode = ModeFixedTemporalRange;

//! How to handle the limits of the timeframe (include or exclude)
LimitMode mLimitMode = ModeIncludeBeginExcludeEnd;

//! Represents fixed temporal range.
QgsDateTimeRange mFixedRange;

@@ -41,6 +41,9 @@ QgsVectorLayerTemporalPropertiesWidget::QgsVectorLayerTemporalPropertiesWidget(

connect( mModeComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), mStackedWidget, &QStackedWidget::setCurrentIndex );

mLimitsComboBox->addItem( tr( "Include Start, Exclude End (default)" ), QgsVectorLayerTemporalProperties::ModeIncludeBeginExcludeEnd );
mLimitsComboBox->addItem( tr( "Include Start, Include End" ), QgsVectorLayerTemporalProperties::ModeIncludeBeginIncludeEnd );

mStartTemporalDateTimeEdit->setDisplayFormat( "yyyy-MM-dd HH:mm:ss" );
mEndTemporalDateTimeEdit->setDisplayFormat( "yyyy-MM-dd HH:mm:ss" );

@@ -104,6 +107,7 @@ void QgsVectorLayerTemporalPropertiesWidget::saveTemporalProperties()

properties->setIsActive( mTemporalGroupBox->isChecked() );
properties->setMode( static_cast< QgsVectorLayerTemporalProperties::TemporalMode >( mModeComboBox->currentData().toInt() ) );
properties->setLimitMode(static_cast< QgsVectorLayerTemporalProperties::LimitMode >( mLimitsComboBox->currentData().toInt() ));

const QgsDateTimeRange normalRange = QgsDateTimeRange( mStartTemporalDateTimeEdit->dateTime(),
mEndTemporalDateTimeEdit->dateTime() );
@@ -154,6 +158,8 @@ void QgsVectorLayerTemporalPropertiesWidget::syncToLayer()
mModeComboBox->setCurrentIndex( mModeComboBox->findData( properties->mode() ) );
mStackedWidget->setCurrentIndex( static_cast< int >( properties->mode() ) );

mLimitsComboBox->setCurrentIndex( mLimitsComboBox->findData( properties->limitMode() ) );

mStartTemporalDateTimeEdit->setDateTime( properties->fixedTemporalRange().begin() );
mEndTemporalDateTimeEdit->setDateTime( properties->fixedTemporalRange().end() );

@@ -94,7 +94,7 @@ background: white;QgsCollapsibleGroupBoxBasic::title, QgsCollapsibleGroupBox::ti
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<item row="2" column="0" colspan="2">
<widget class="QStackedWidget" name="mStackedWidget">
<property name="currentIndex">
<number>0</number>
@@ -424,7 +424,7 @@ background: white;QgsCollapsibleGroupBoxBasic::title, QgsCollapsibleGroupBox::ti
</widget>
</widget>
</item>
<item row="2" column="0">
<item row="3" column="0">
<widget class="QFrame" name="mFixedTimeRangeFrame">
<property name="enabled">
<bool>false</bool>
@@ -448,6 +448,16 @@ background: white;QgsCollapsibleGroupBoxBasic::title, QgsCollapsibleGroupBox::ti
</layout>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="mLimitsComboBox"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_15">
<property name="text">
<string>Limits</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>

0 comments on commit 47bf9e3

Please sign in to comment.