37 case Qgis::VectorTemporalMode::FixedTemporalRange:
38 return range.isInfinite() || mFixedRange.isInfinite() || mFixedRange.overlaps( range );
40 case Qgis::VectorTemporalMode::FeatureDateTimeInstantFromField:
41 case Qgis::VectorTemporalMode::FeatureDateTimeStartAndEndFromFields:
42 case Qgis::VectorTemporalMode::RedrawLayerOnly:
43 case Qgis::VectorTemporalMode::FeatureDateTimeStartAndDurationFromFields:
44 case Qgis::VectorTemporalMode::FeatureDateTimeStartAndEndFromExpressions:
52 QgsVectorLayer *vectorLayer = qobject_cast<QgsVectorLayer *>( layer );
54 return QgsDateTimeRange();
58 case Qgis::VectorTemporalMode::FixedTemporalRange:
61 case Qgis::VectorTemporalMode::FeatureDateTimeInstantFromField:
64 if ( fieldIndex >= 0 )
70 const QDateTime min = minVal.toDateTime();
71 const QDateTime maxStartTime = maxVal.toDateTime();
73 return QgsDateTimeRange( min, maxStartTime + eventDuration );
78 case Qgis::VectorTemporalMode::FeatureDateTimeStartAndDurationFromFields:
81 const int durationFieldIndex = vectorLayer->
fields().
lookupField( mDurationFieldName );
82 if ( fieldIndex >= 0 && durationFieldIndex >= 0 )
84 const QDateTime minTime = vectorLayer->
minimumValue( fieldIndex ).toDateTime();
92 const QDateTime start = f.
attribute( fieldIndex ).toDateTime();
93 if ( start.isValid() )
95 const QVariant durationValue = f.
attribute( durationFieldIndex );
96 if ( durationValue.isValid() )
98 const double duration = durationValue.toDouble();
99 const QDateTime end = start.addMSecs(
QgsInterval( duration, mDurationUnit ).seconds() * 1000.0 );
101 maxTime = maxTime.isValid() ? std::max( maxTime, end ) : end;
105 return QgsDateTimeRange( minTime, maxTime );
110 case Qgis::VectorTemporalMode::FeatureDateTimeStartAndEndFromFields:
112 const int startFieldIndex = vectorLayer->
fields().
lookupField( mStartFieldName );
114 if ( startFieldIndex >= 0 && endFieldIndex >= 0 )
116 QVariant startMinVal;
117 QVariant startMaxVal;
123 return QgsDateTimeRange( std::min( startMinVal.toDateTime(),
124 endMinVal.toDateTime() ),
125 std::max( startMaxVal.toDateTime(),
126 endMaxVal.toDateTime() ) );
128 else if ( startFieldIndex >= 0 )
130 QVariant startMinVal;
131 QVariant startMaxVal;
133 return QgsDateTimeRange( startMinVal.toDateTime(),
134 startMaxVal.toDateTime() );
136 else if ( endFieldIndex >= 0 )
141 return QgsDateTimeRange( endMinVal.toDateTime(),
142 endMaxVal.toDateTime() );
147 case Qgis::VectorTemporalMode::FeatureDateTimeStartAndEndFromExpressions:
149 const bool hasStartExpression = !mStartExpression.isEmpty();
150 const bool hasEndExpression = !mEndExpression.isEmpty();
151 if ( !hasStartExpression && !hasEndExpression )
152 return QgsDateTimeRange();
162 if ( hasStartExpression )
169 if ( hasEndExpression )
175 QSet< QString > fields;
176 if ( hasStartExpression )
178 if ( hasEndExpression )
194 const QDateTime start = hasStartExpression ?
startExpression.evaluate( &context ).toDateTime() : QDateTime();
195 const QDateTime end = hasEndExpression ?
endExpression.evaluate( &context ).toDateTime() : QDateTime();
197 if ( start.isValid() )
199 minTime = minTime.isValid() ? std::min( minTime, start ) : start;
200 if ( !hasEndExpression )
201 maxTime = maxTime.isValid() ? std::max( maxTime, start ) : start;
205 maxTime = maxTime.isValid() ? std::max( maxTime, end ) : end;
206 if ( !hasStartExpression )
207 minTime = minTime.isValid() ? std::min( minTime, end ) : end;
210 return QgsDateTimeRange( minTime, maxTime );
213 case Qgis::VectorTemporalMode::RedrawLayerOnly:
217 return QgsDateTimeRange();
263 const QDomElement temporalNode = element.firstChildElement( QStringLiteral(
"temporal" ) );
265 setIsActive( temporalNode.attribute( QStringLiteral(
"enabled" ), QStringLiteral(
"0" ) ).toInt() );
267 mMode =
static_cast< Qgis::VectorTemporalMode >( temporalNode.attribute( QStringLiteral(
"mode" ), QStringLiteral(
"0" ) ). toInt() );
269 mLimitMode =
static_cast< Qgis::VectorTemporalLimitMode >( temporalNode.attribute( QStringLiteral(
"limitMode" ), QStringLiteral(
"0" ) ). toInt() );
270 mStartFieldName = temporalNode.attribute( QStringLiteral(
"startField" ) );
271 mEndFieldName = temporalNode.attribute( QStringLiteral(
"endField" ) );
272 mStartExpression = temporalNode.attribute( QStringLiteral(
"startExpression" ) );
273 mEndExpression = temporalNode.attribute( QStringLiteral(
"endExpression" ) );
274 mDurationFieldName = temporalNode.attribute( QStringLiteral(
"durationField" ) );
276 mFixedDuration = temporalNode.attribute( QStringLiteral(
"fixedDuration" ) ).toDouble();
277 mAccumulateFeatures = temporalNode.attribute( QStringLiteral(
"accumulate" ), QStringLiteral(
"0" ) ).toInt();
279 const QDomNode rangeElement = temporalNode.namedItem( QStringLiteral(
"fixedRange" ) );
281 const QDomNode begin = rangeElement.namedItem( QStringLiteral(
"start" ) );
282 const QDomNode end = rangeElement.namedItem( QStringLiteral(
"end" ) );
284 const QDateTime beginDate = QDateTime::fromString( begin.toElement().text(), Qt::ISODate );
285 const QDateTime endDate = QDateTime::fromString( end.toElement().text(), Qt::ISODate );
287 const QgsDateTimeRange range = QgsDateTimeRange( beginDate, endDate );
296 if ( element.isNull() )
297 return QDomElement();
299 QDomElement temporalElement = document.createElement( QStringLiteral(
"temporal" ) );
300 temporalElement.setAttribute( QStringLiteral(
"enabled" ),
isActive() ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
301 temporalElement.setAttribute( QStringLiteral(
"mode" ), QString::number(
static_cast< int >( mMode ) ) );
303 temporalElement.setAttribute( QStringLiteral(
"limitMode" ), QString::number(
static_cast< int >( mLimitMode ) ) );
304 temporalElement.setAttribute( QStringLiteral(
"startField" ), mStartFieldName );
305 temporalElement.setAttribute( QStringLiteral(
"endField" ), mEndFieldName );
306 temporalElement.setAttribute( QStringLiteral(
"startExpression" ), mStartExpression );
307 temporalElement.setAttribute( QStringLiteral(
"endExpression" ), mEndExpression );
308 temporalElement.setAttribute( QStringLiteral(
"durationField" ), mDurationFieldName );
310 temporalElement.setAttribute( QStringLiteral(
"fixedDuration" ),
qgsDoubleToString( mFixedDuration ) );
311 temporalElement.setAttribute( QStringLiteral(
"accumulate" ), mAccumulateFeatures ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
313 QDomElement rangeElement = document.createElement( QStringLiteral(
"fixedRange" ) );
315 QDomElement startElement = document.createElement( QStringLiteral(
"start" ) );
316 QDomElement endElement = document.createElement( QStringLiteral(
"end" ) );
318 const QDomText startText = document.createTextNode( mFixedRange.begin().toTimeSpec( Qt::OffsetFromUTC ).toString( Qt::ISODate ) );
319 const QDomText endText = document.createTextNode( mFixedRange.end().toTimeSpec( Qt::OffsetFromUTC ).toString( Qt::ISODate ) );
320 startElement.appendChild( startText );
321 endElement.appendChild( endText );
322 rangeElement.appendChild( startElement );
323 rangeElement.appendChild( endElement );
325 temporalElement.appendChild( rangeElement );
327 element.appendChild( temporalElement );
336 setIsActive( vectorCaps->hasTemporalCapabilities() );
340 switch ( vectorCaps->mode() )
342 case Qgis::VectorDataProviderTemporalMode::HasFixedTemporalRange:
343 setMode( Qgis::VectorTemporalMode::FixedTemporalRange );
345 case Qgis::VectorDataProviderTemporalMode::StoresFeatureDateTimeInstantInField:
346 setMode( Qgis::VectorTemporalMode::FeatureDateTimeInstantFromField );
348 case Qgis::VectorDataProviderTemporalMode::StoresFeatureDateTimeStartAndEndInSeparateFields:
349 setMode( Qgis::VectorTemporalMode::FeatureDateTimeStartAndEndFromFields );
357 return mStartExpression;
367 return mEndExpression;
377 return mAccumulateFeatures;
387 return mFixedDuration;
397 return mStartFieldName;
402 mStartFieldName = startFieldName;
407 return mEndFieldName;
412 mEndFieldName =
field;
417 return mDurationFieldName;
422 mDurationFieldName =
field;
427 return mDurationUnit;
432 mDurationUnit = units;
437 return QStringLiteral(
"make_datetime(%1,%2,%3,%4,%5,%6)" ).arg( datetime.date().year() )
438 .arg( datetime.date().month() )
439 .arg( datetime.date().day() )
440 .arg( datetime.time().hour() )
441 .arg( datetime.time().minute() )
442 .arg( datetime.time().second() + datetime.time().msec() / 1000.0 );
450 auto dateTimefieldCast = [ &context ](
const QString & fieldName ) -> QString
463 case Qgis::VectorTemporalMode::FixedTemporalRange:
464 case Qgis::VectorTemporalMode::RedrawLayerOnly:
467 case Qgis::VectorTemporalMode::FeatureDateTimeInstantFromField:
469 if ( mAccumulateFeatures )
471 return QStringLiteral(
"(%1 %2 %3) OR %1 IS NULL" ).arg( dateTimefieldCast( mStartFieldName ),
472 filterRange.includeEnd() ? QStringLiteral(
"<=" ) : QStringLiteral(
"<" ),
477 return QStringLiteral(
"(%1 %2 %3 AND %1 %4 %5) OR %1 IS NULL" ).arg( dateTimefieldCast( mStartFieldName ),
478 filterRange.includeBeginning() ? QStringLiteral(
">=" ) : QStringLiteral(
">" ),
480 filterRange.includeEnd() ? QStringLiteral(
"<=" ) : QStringLiteral(
"<" ),
486 return QStringLiteral(
"(%1 %2 %3 AND %1 %4 %5) OR %1 IS NULL" ).arg( dateTimefieldCast( mStartFieldName ),
489 filterRange.includeEnd() ? QStringLiteral(
"<=" ) : QStringLiteral(
"<" ),
494 case Qgis::VectorTemporalMode::FeatureDateTimeStartAndDurationFromFields:
496 QString intervalExpression;
497 switch ( mDurationUnit )
543 return QStringLiteral(
"(%1 %2 %3 OR %1 IS NULL) AND ((%1 + %4 %5 %6) OR %7 IS NULL)" ).arg( dateTimefieldCast( mStartFieldName ),
544 filterRange.includeEnd() ? QStringLiteral(
"<=" ) : QStringLiteral(
"<" ),
552 case Qgis::VectorTemporalMode::FeatureDateTimeStartAndEndFromFields:
554 if ( !mStartFieldName.isEmpty() && !mEndFieldName.isEmpty() )
556 return QStringLiteral(
"(%1 %2 %3 OR %1 IS NULL) AND (%4 %5 %6 OR %4 IS NULL)" ).arg( dateTimefieldCast( mStartFieldName ),
557 filterRange.includeEnd() ? QStringLiteral(
"<=" ) : QStringLiteral(
"<" ),
559 dateTimefieldCast( mEndFieldName ),
564 else if ( !mStartFieldName.isEmpty() )
566 return QStringLiteral(
"%1 %2 %3 OR %1 IS NULL" ).arg( dateTimefieldCast( mStartFieldName ),
567 filterRange.includeEnd() ? QStringLiteral(
"<=" ) : QStringLiteral(
"<" ),
570 else if ( !mEndFieldName.isEmpty() )
572 return QStringLiteral(
"%1 %2 %3 OR %1 IS NULL" ).arg( dateTimefieldCast( mEndFieldName ),
579 case Qgis::VectorTemporalMode::FeatureDateTimeStartAndEndFromExpressions:
581 if ( !mStartExpression.isEmpty() && !mEndExpression.isEmpty() )
583 return QStringLiteral(
"((%1) %2 %3) AND ((%4) %5 %6)" ).arg( mStartExpression,
584 filterRange.includeEnd() ? QStringLiteral(
"<=" ) : QStringLiteral(
"<" ),
590 else if ( !mStartExpression.isEmpty() )
592 return QStringLiteral(
"(%1) %2 %3" ).arg( mStartExpression,
593 filterRange.includeEnd() ? QStringLiteral(
"<=" ) : QStringLiteral(
"<" ),
596 else if ( !mEndExpression.isEmpty() )
598 return QStringLiteral(
"(%1) %2 %3" ).arg( mEndExpression,
618 static const QStringList sStartCandidates{ QStringLiteral(
"start" ),
619 QStringLiteral(
"begin" ),
620 QStringLiteral(
"from" )};
622 static const QStringList sEndCandidates{ QStringLiteral(
"end" ),
623 QStringLiteral(
"last" ),
624 QStringLiteral(
"to" )};
626 static const QStringList sSingleFieldCandidates{ QStringLiteral(
"event" ) };
629 bool foundStart =
false;
630 bool foundEnd =
false;
639 for (
const QString &candidate : sStartCandidates )
642 if ( fldName.indexOf( candidate, 0, Qt::CaseInsensitive ) > -1 )
644 mStartFieldName = fldName;
652 for (
const QString &candidate : sEndCandidates )
655 if ( fldName.indexOf( candidate, 0, Qt::CaseInsensitive ) > -1 )
657 mEndFieldName = fldName;
663 if ( foundStart && foundEnd )
675 for (
const QString &candidate : sSingleFieldCandidates )
678 if ( fldName.indexOf( candidate, 0, Qt::CaseInsensitive ) > -1 )
680 mStartFieldName = fldName;
690 if ( foundStart && foundEnd )
691 mMode = Qgis::VectorTemporalMode::FeatureDateTimeStartAndEndFromFields;
692 else if ( foundStart )
693 mMode = Qgis::VectorTemporalMode::FeatureDateTimeInstantFromField;
VectorTemporalMode
Vector layer temporal feature modes.
VectorTemporalLimitMode
Mode for the handling of the limits of the filtering timeframe for vector features.
@ IncludeBeginIncludeEnd
Mode to include both limits of the filtering timeframe.
Base class for handling properties relating to a data provider's temporal capabilities.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
void appendScopes(const QList< QgsExpressionContextScope * > &scopes)
Appends a list of scopes to the end of the context.
Class for parsing and evaluation of expressions (formerly called "search strings").
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
This class wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Encapsulate a field in an attribute table or data source.
Container of fields for a vector layer.
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
A representation of the interval between two datetime values.
Base class for storage of map layer temporal properties.
Base class for all map layer types.
The class is used as a container of context for various read/write operations on other objects.
bool isActive() const
Returns true if the temporal property is active.
void setIsActive(bool active)
Sets whether the temporal property is active.
@ FlagDontInvalidateCachedRendersWhenRangeChanges
Any cached rendering will not be invalidated when temporal range context is modified.
static Q_INVOKABLE QString encodeUnit(QgsUnitTypes::DistanceUnit unit)
Encodes a distance unit to a string.
TemporalUnit
Temporal units.
@ TemporalUnknownUnit
Unknown time unit.
@ TemporalMilliseconds
Milliseconds.
@ TemporalIrregularStep
Special "irregular step" time unit, used for temporal data which uses irregular, non-real-world unit ...
@ TemporalDecades
Decades.
@ TemporalCenturies
Centuries.
@ TemporalSeconds
Seconds.
@ TemporalMinutes
Minutes.
static Q_INVOKABLE QgsUnitTypes::TemporalUnit decodeTemporalUnit(const QString &string, bool *ok=nullptr)
Decodes a temporal unit from a string.
Implementation of data provider temporal properties for QgsVectorDataProviders.
Encapsulates the context in which a QgsVectorLayer's temporal capabilities will be applied.
QgsVectorLayer * layer() const
Returns the associated layer.
void setLayer(QgsVectorLayer *layer)
Sets the associated layer.
void guessDefaultsFromFields(const QgsFields &fields)
Attempts to setup the temporal properties by scanning a set of fields and looking for standard naming...
QString endExpression() const
Returns the expression for the end time for the feature's time spans.
void setDurationField(const QString &field)
Sets the name of the duration field, which contains the duration of the event.
void setMode(Qgis::VectorTemporalMode mode)
Sets the temporal properties mode.
QgsVectorLayerTemporalProperties(QObject *parent=nullptr, bool enabled=false)
Constructor for QgsVectorLayerTemporalProperties, with the specified parent object.
void setStartExpression(const QString &expression)
Sets the expression to use for the start time for the feature's time spans.
bool isVisibleInTemporalRange(const QgsDateTimeRange &range) const override
Returns true if the layer should be visible and rendered for the specified time range.
Qgis::VectorTemporalLimitMode limitMode() const
Returns the temporal limit mode (to include or exclude begin/end limits).
void setLimitMode(Qgis::VectorTemporalLimitMode mode)
Sets the temporal limit mode (to include or exclude begin/end limits).
const QgsDateTimeRange & fixedTemporalRange() const
Returns the fixed temporal range for the layer.
double fixedDuration() const
Returns the fixed duration length, which contains the duration of the event.
bool accumulateFeatures() const
Returns true if features will be accumulated over time (i.e.
QgsTemporalProperty::Flags flags() const override
Returns flags associated to the temporal property.
void setFixedTemporalRange(const QgsDateTimeRange &range)
Sets a temporal range to apply to the whole layer.
QgsUnitTypes::TemporalUnit durationUnits() const
Returns the units of the event's duration.
bool readXml(const QDomElement &element, const QgsReadWriteContext &context) override
Reads temporal properties from a DOM element previously written by writeXml().
void setEndExpression(const QString &endExpression)
Sets the expression to use for the end time for the feature's time spans.
QString durationField() const
Returns the name of the duration field, which contains the duration of the event.
QString endField() const
Returns the name of the end datetime field, which contains the end time for the feature's time spans.
QString createFilterString(const QgsVectorLayerTemporalContext &context, const QgsDateTimeRange &range) const
Creates a QGIS expression filter string for filtering features within the specified context to those ...
void setDurationUnits(QgsUnitTypes::TemporalUnit units)
Sets the units of the event's duration.
QDomElement writeXml(QDomElement &element, QDomDocument &doc, const QgsReadWriteContext &context) override
Writes the properties to a DOM element, to be used later with readXml().
void setAccumulateFeatures(bool accumulate)
Sets whether features will be accumulated over time (i.e.
void setFixedDuration(double duration)
Sets the fixed event duration, which contains the duration of the event.
void setEndField(const QString &field)
Sets the name of the end datetime field, which contains the end time for the feature's time spans.
QgsDateTimeRange calculateTemporalExtent(QgsMapLayer *layer) const override
Attempts to calculate the overall temporal extent for the specified layer, using the settings defined...
void setDefaultsFromDataProviderTemporalCapabilities(const QgsDataProviderTemporalCapabilities *capabilities) override
Sets the layers temporal settings to appropriate defaults based on a provider's temporal capabilities...
Qgis::VectorTemporalMode mode() const
Returns the temporal properties mode.
QString startField() const
Returns the name of the start datetime field, which contains the start time for the feature's time sp...
void setStartField(const QString &field)
Sets the name of the start datetime field, which contains the start time for the feature's time spans...
QString startExpression() const
Returns the expression for the start time for the feature's time spans.
Represents a vector layer which manages a vector based data sets.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
QVariant minimumValue(int index) const FINAL
Returns the minimum value for an attribute column or an invalid variant in case of error.
void minimumAndMaximumValue(int index, QVariant &minimum, QVariant &maximum) const
Calculates both the minimum and maximum value for an attribute column.
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
QList< int > QgsAttributeList
QString dateTimeExpressionLiteral(const QDateTime &datetime)