26#include <QRegularExpression>
30 const QMap<QString, QgsMapLayer *> mapLayers = project->
mapLayers();
34 for (
auto it = mapLayers.constBegin(); it != mapLayers.constEnd(); ++it )
42 if ( layerRange.
begin().isValid() && ( !minDate.isValid() || layerRange.
begin() < minDate ) )
43 minDate = layerRange.
begin();
44 if ( layerRange.
end().isValid() && ( !maxDate.isValid() || layerRange.
end() > maxDate ) )
45 maxDate = layerRange.
end();
53 const QMap<QString, QgsMapLayer *> mapLayers = project->
mapLayers();
55 QList< QgsDateTimeRange > ranges;
56 for (
auto it = mapLayers.constBegin(); it != mapLayers.constEnd(); ++it )
73 error = QObject::tr(
"Filename template is empty" );
76 const int numberOfDigits = settings.
fileNameTemplate.count( QLatin1Char(
'#' ) );
77 if ( numberOfDigits < 0 )
79 error = QObject::tr(
"Wrong filename template format (must contain #)" );
82 const QString token( numberOfDigits, QLatin1Char(
'#' ) );
85 error = QObject::tr(
"Filename template must contain all # placeholders in one continuous group." );
90 error = QObject::tr(
"Output directory creation failure." );
108 long long currentFrame = 0;
110 while ( currentFrame < totalFrames )
116 error = QObject::tr(
"Export canceled" );
119 feedback->
setProgress( currentFrame /
static_cast<double>( totalFrames ) * 100 );
134 const QString frameNoPaddedLeft( QStringLiteral(
"%1" ).arg( currentFrame, numberOfDigits, 10, QChar(
'0' ) ) );
135 fileName.replace( token, frameNoPaddedLeft );
136 const QString path = QDir( settings.
outputDirectory ).filePath( fileName );
140 img.setDotsPerMeterX( 1000 * ms.
outputDpi() / 25.4 );
141 img.setDotsPerMeterY( 1000 * ms.
outputDpi() / 25.4 );
152 const auto constMDecorations = settings.
decorations;
155 decoration->render( ms, context );
177 const double duration = interval.
seconds();
178 return start.addMSecs( frame * duration * 1000 );
222 if ( timeDuration.
years == 0 && timeDuration.
months == 0 && timeDuration.
weeks == 0 && timeDuration.
days == 0
233 QList<QDateTime> res;
234 QDateTime current = start;
235 maxValuesExceeded =
false;
236 while ( current <= end )
240 if ( maxValues >= 0 && res.size() > maxValues )
242 maxValuesExceeded =
true;
246 if ( timeDuration.
years )
247 current = current.addYears( timeDuration.
years );
248 if ( timeDuration.
months )
249 current = current.addMonths( timeDuration.
months );
250 if ( timeDuration.
weeks || timeDuration.
days )
251 current = current.addDays( timeDuration.
weeks * 7 + timeDuration.
days );
253 current = current.addSecs( timeDuration.
hours * 60LL * 60 + timeDuration.
minutes * 60 + timeDuration.
seconds );
261 maxValuesExceeded =
false;
262 const QStringList parts =
string.split(
'/' );
263 if ( parts.length() != 3 )
268 const QDateTime start = QDateTime::fromString( parts.at( 0 ), Qt::ISODate );
269 if ( !start.isValid() )
271 const QDateTime end = QDateTime::fromString( parts.at( 1 ), Qt::ISODate );
272 if ( !end.isValid() )
293 text.append( QString::number(
years ) );
298 text.append( QString::number(
months ) );
303 text.append( QString::number(
days ) );
309 if ( !text.contains(
'T' ) )
311 text.append( QString::number(
hours ) );
316 if ( !text.contains(
'T' ) )
318 text.append( QString::number(
minutes ) );
323 if ( !text.contains(
'T' ) )
325 text.append( QString::number(
seconds ) );
333 long long secs = 0.0;
353 QDateTime resultDateTime = dateTime;
356 resultDateTime = resultDateTime.addYears(
years );
358 resultDateTime = resultDateTime.addMonths(
months );
360 resultDateTime = resultDateTime.addDays(
weeks * 7 +
days );
364 return resultDateTime;
370 thread_local const QRegularExpression sRx( QStringLiteral( R
"(P(?:([\d]+)Y)?(?:([\d]+)M)?(?:([\d]+)W)?(?:([\d]+)D)?(?:T(?:([\d]+)H)?(?:([\d]+)M)?(?:([\d\.]+)S)?)?$)" ) );
372 const QRegularExpressionMatch match = sRx.match(
string );
374 if ( match.hasMatch() )
377 duration.
years = match.captured( 1 ).toInt();
378 duration.
months = match.captured( 2 ).toInt();
379 duration.
weeks = match.captured( 3 ).toInt();
380 duration.
days = match.captured( 4 ).toInt();
381 duration.
hours = match.captured( 5 ).toInt();
382 duration.
minutes = match.captured( 6 ).toInt();
383 duration.
seconds = match.captured( 7 ).toDouble();
@ IrregularStep
Special 'irregular step' time unit, used for temporal data which uses irregular, non-real-world unit ...
@ Milliseconds
Milliseconds.
@ Unknown
Unknown time unit.
static QgsExpressionContextScope * mapSettingsScope(const QgsMapSettings &mapSettings)
Creates a new scope which contains variables and functions relating to a QgsMapSettings object.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
bool isCanceled() const
Tells whether the operation has been canceled already.
void setProgress(double progress)
Sets the current progress for the feedback object.
A representation of the interval between two datetime values.
static const int MINUTE
Seconds per minute.
double originalDuration() const
Returns the original interval duration.
static const int MONTHS
Seconds per month, based on 30 day month.
double seconds() const
Returns the interval duration in seconds.
Qgis::TemporalUnit originalUnit() const
Returns the original interval temporal unit.
static const int HOUR
Seconds per hour.
static const int DAY
Seconds per day.
static const int YEARS
Seconds per year (average).
Interface for map decorations.
virtual QgsDateTimeRange calculateTemporalExtent(QgsMapLayer *layer) const
Attempts to calculate the overall temporal extent for the specified layer, using the settings defined...
virtual QList< QgsDateTimeRange > allTemporalRanges(QgsMapLayer *layer) const
Attempts to calculate the overall list of all temporal extents which are contained in the specified l...
Base class for all map layer types.
virtual QgsMapLayerTemporalProperties * temporalProperties()
Returns the layer's temporal properties.
Job implementation that renders everything sequentially using a custom painter.
void waitForFinished() override
Block until the job has finished.
void start()
Start the rendering job and immediately return.
Contains configuration for rendering maps.
void setFrameRate(double rate)
Sets the frame rate of the map (in frames per second), for maps which are part of an animation.
QColor backgroundColor() const
Returns the background color of the map.
float devicePixelRatio() const
Returns the device pixel ratio.
QSize outputSize() const
Returns the size of the resulting map image, in pixels.
QImage::Format outputImageFormat() const
format of internal QImage, default QImage::Format_ARGB32_Premultiplied
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context.
void setCurrentFrame(long long frame)
Sets the current frame of the map, for maps which are part of an animation.
double outputDpi() const
Returns the DPI (dots per inch) used for conversion between real world units (e.g.
const QgsExpressionContext & expressionContext() const
Gets the expression context.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
QMap< QString, QgsMapLayer * > mapLayers(const bool validOnly=false) const
Returns a map of all registered layers by layer ID.
Contains information about the context of a rendering operation.
void setPainter(QPainter *p)
Sets the destination QPainter for the render operation.
static QgsRenderContext fromMapSettings(const QgsMapSettings &mapSettings)
create initialized QgsRenderContext instance from given QgsMapSettings
Implements a temporal controller based on a frame by frame navigation and animation.
void setAvailableTemporalRanges(const QList< QgsDateTimeRange > &ranges)
Sets the list of all available temporal ranges which have data available.
void setFrameDuration(const QgsInterval &duration)
Sets the frame duration, which dictates the temporal length of each frame in the animation.
QgsExpressionContextScope * createExpressionContextScope() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
void setCurrentFrameNumber(long long frame)
Sets the current animation frame number.
long long totalFrameCount() const
Returns the total number of frames for the navigation.
QgsDateTimeRange dateTimeRangeForFrameNumber(long long frame) const
Calculates the temporal range associated with a particular animation frame.
void setTemporalExtents(const QgsDateTimeRange &extents)
Sets the navigation temporal extents, which dictate the earliest and latest date time possible in the...
void setTemporalRangeCumulative(bool state)
Sets the animation temporal range as cumulative.
bool isActive() const
Returns true if the temporal property is active.
void setIsTemporal(bool enabled)
Sets whether the temporal range is enabled (i.e.
void setTemporalRange(const QgsDateTimeRange &range)
Sets the temporal range for the object.
T begin() const
Returns the beginning of the range.
T end() const
Returns the upper bound of the range.
static QList< QgsTemporalRange< QDateTime > > mergeRanges(const QList< QgsTemporalRange< QDateTime > > &ranges)
static QList< QDateTime > calculateDateTimesUsingDuration(const QDateTime &start, const QDateTime &end, const QString &duration, bool &ok, bool &maxValuesExceeded, int maxValues=-1)
Calculates a complete list of datetimes between start and end, using the specified ISO8601 duration s...
static QgsDateTimeRange calculateTemporalRangeForProject(QgsProject *project)
Calculates the temporal range for a project.
static bool exportAnimation(const QgsMapSettings &mapSettings, const AnimationExportSettings &settings, QString &error, QgsFeedback *feedback=nullptr)
Exports animation frames by rendering the map to multiple destination images.
static QList< QgsDateTimeRange > usedTemporalRangesForProject(QgsProject *project)
Calculates all temporal ranges which are in use for a project.
static QDateTime calculateFrameTime(const QDateTime &start, const long long frame, const QgsInterval &interval)
Calculates the frame time for an animation.
static QList< QDateTime > calculateDateTimesFromISO8601(const QString &string, bool &ok, bool &maxValuesExceeded, int maxValues=-1)
Calculates a complete list of datetimes from a ISO8601 string containing a duration (eg "2021-03-23T0...
Contains utility methods for working with temporal layers and projects.
QDateTime addToDateTime(const QDateTime &dateTime) const
Adds this duration to a starting dateTime value.
long long toSeconds() const
Returns the total duration in seconds.
QString toString() const
Converts the duration to an ISO8601 duration string.
static QgsTimeDuration fromString(const QString &string, bool &ok)
Creates a QgsTimeDuration from a string value.
QgsInterval toInterval() const
Converts the duration to an interval value.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
QgsTemporalRange< QDateTime > QgsDateTimeRange
QgsRange which stores a range of date times.
Contains settings relating to exporting animations.
double frameRate
Target animation frame rate in frames per second.
bool temporalRangeCumulative
The animation temporal range cumulative settings.
QgsDateTimeRange animationRange
Dictates the overall temporal range of the animation.
QList< QgsDateTimeRange > availableTemporalRanges
Contains the list of all available temporal ranges which have data available.
QgsInterval frameDuration
Duration of individual export frames.
QString fileNameTemplate
The filename template for exporting the frames.
QString outputDirectory
Destination directory for created image files.
QList< QgsMapDecoration * > decorations
List of decorations to draw onto exported frames.