Skip to content

Commit

Permalink
Tweak API for QgsTemporalUtils::exportAnimation
Browse files Browse the repository at this point in the history
Make it a bit more future-proof
  • Loading branch information
nyalldawson authored and nirvn committed May 18, 2020
1 parent 8a7feed commit 09fda8d
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 53 deletions.
44 changes: 29 additions & 15 deletions python/core/auto_generated/qgstemporalutils.sip.in
Expand Up @@ -31,27 +31,41 @@ This method considers the temporal range available from layers contained within
returns the maximal combined temporal extent of these layers.
%End

static bool exportAnimation( const QgsMapSettings &mapSettings,
const QgsDateTimeRange &animationRange,
QgsInterval frameDuration,
const QString &outputDirectory,
const QString &fileNameTemplate,
QString &error /Out/,
QgsFeedback *feedback );
class AnimationExportSettings
{

%TypeHeaderCode
#include "qgstemporalutils.h"
%End
public:

QgsDateTimeRange animationRange;

QgsInterval frameDuration;

QString outputDirectory;

QString fileNameTemplate;

};

static bool exportAnimation( const QgsMapSettings &mapSettings, const AnimationExportSettings &settings, QString &error /Out/, QgsFeedback *feedback = 0 );
%Docstring
Exports animation frames by rendering the map to multiple destination images.

The ``mapSettings`` argument dictates the overall map settings such as extent
and size.
and size, while animation and export specific settings are specified via the ``settings``
argument.

An optional ``feedback`` argument can be used to provide progress reports and cancelation
support.

The ``animationRange`` argument specifies the overall temporal range of the animation.
Temporal duration of individual frames is given by ``frameDuration``.
:param mapSettings: settings controlling the map render
:param settings: animation and export settings
:param feedback: optional feedback object for progress reports and cancelation checks

An ``outputDirectory`` must be set, which controls where the created image files are
stored. ``fileNameTemplate`` gives the template for exporting the frames.
This must be in format prefix####.format, where number of
# represents how many 0 should be left-padded to the frame number
e.g. my###.jpg will create frames my001.jpg, my002.jpg, etc
:return: - ``True`` if the export was successful.
- error: will be set to a descriptive error message if the export fails
%End
};

Expand Down
11 changes: 7 additions & 4 deletions src/app/qgstemporalcontrollerdockwidget.cpp
Expand Up @@ -81,12 +81,15 @@ void QgsTemporalControllerDockWidget::exportAnimation()

connect( &progressDialog, &QProgressDialog::canceled, &progressFeedback, &QgsFeedback::cancel );

QgsTemporalUtils::AnimationExportSettings animationSettings;
animationSettings.frameDuration = frameDuration;
animationSettings.animationRange = animationRange;
animationSettings.outputDirectory = outputDir;
animationSettings.fileNameTemplate = fileNameExpression;

bool success = QgsTemporalUtils::exportAnimation(
s,
animationRange,
frameDuration,
outputDir,
fileNameExpression,
animationSettings,
error,
&progressFeedback );

Expand Down
38 changes: 19 additions & 19 deletions src/core/qgstemporalutils.cpp
Expand Up @@ -52,31 +52,31 @@ QgsDateTimeRange QgsTemporalUtils::calculateTemporalRangeForProject( QgsProject
return QgsDateTimeRange( minDate, maxDate );
}

bool QgsTemporalUtils::exportAnimation( const QgsMapSettings &mapSettings, const QgsDateTimeRange &animationRange, QgsInterval frameDuration, const QString &outputDirectory, const QString &fileNameTemplate, QString &error, QgsFeedback *feedback )
bool QgsTemporalUtils::exportAnimation( const QgsMapSettings &mapSettings, const QgsTemporalUtils::AnimationExportSettings &settings, QString &error, QgsFeedback *feedback )
{
if ( fileNameTemplate.isEmpty() )
if ( settings.fileNameTemplate.isEmpty() )
{
error = QObject::tr( "Filename template is empty" );
return false;
}
int numberOfDigits = fileNameTemplate.count( QLatin1Char( '#' ) );
int numberOfDigits = settings.fileNameTemplate.count( QLatin1Char( '#' ) );
if ( numberOfDigits < 0 )
{
error = QObject::tr( "Wrong filename template format (must contain #)" );
return false;
}
const QString token( numberOfDigits, QLatin1Char( '#' ) );
if ( !fileNameTemplate.contains( token ) )
if ( !settings.fileNameTemplate.contains( token ) )
{
error = QObject::tr( "Filename template must contain all # placeholders in one continuous group." );
return false;
}

QgsTemporalNavigationObject navigator;
navigator.setTemporalExtents( animationRange );
navigator.setFrameDuration( frameDuration );
QgsMapSettings settings = mapSettings;
const QgsExpressionContext context = settings.expressionContext();
navigator.setTemporalExtents( settings.animationRange );
navigator.setFrameDuration( settings.frameDuration );
QgsMapSettings ms = mapSettings;
const QgsExpressionContext context = ms.expressionContext();

const long long totalFrames = navigator.totalFrameCount();
long long currentFrame = 0;
Expand All @@ -96,26 +96,26 @@ bool QgsTemporalUtils::exportAnimation( const QgsMapSettings &mapSettings, const

navigator.setCurrentFrameNumber( currentFrame );

settings.setIsTemporal( true );
settings.setTemporalRange( navigator.dateTimeRangeForFrameNumber( currentFrame ) );
ms.setIsTemporal( true );
ms.setTemporalRange( navigator.dateTimeRangeForFrameNumber( currentFrame ) );

QgsExpressionContext frameContext = context;
frameContext.appendScope( navigator.createExpressionContextScope() );
frameContext.appendScope( QgsExpressionContextUtils::mapSettingsScope( settings ) );
settings.setExpressionContext( frameContext );
frameContext.appendScope( QgsExpressionContextUtils::mapSettingsScope( ms ) );
ms.setExpressionContext( frameContext );

QString fileName( fileNameTemplate );
QString fileName( settings.fileNameTemplate );
const QString frameNoPaddedLeft( QStringLiteral( "%1" ).arg( currentFrame, numberOfDigits, 10, QChar( '0' ) ) ); // e.g. 0001
fileName.replace( token, frameNoPaddedLeft );
const QString path = QDir( outputDirectory ).filePath( fileName );
const QString path = QDir( settings.outputDirectory ).filePath( fileName );

QImage img = QImage( settings.outputSize(), settings.outputImageFormat() );
img.setDotsPerMeterX( 1000 * settings.outputDpi() / 25.4 );
img.setDotsPerMeterY( 1000 * settings.outputDpi() / 25.4 );
img.fill( settings.backgroundColor().rgb() );
QImage img = QImage( ms.outputSize(), ms.outputImageFormat() );
img.setDotsPerMeterX( 1000 * ms.outputDpi() / 25.4 );
img.setDotsPerMeterY( 1000 * ms.outputDpi() / 25.4 );
img.fill( ms.backgroundColor().rgb() );

QPainter p( &img );
QgsMapRendererCustomPainterJob job( settings, &p );
QgsMapRendererCustomPainterJob job( ms, &p );
job.start();
job.waitForFinished();
p.end();
Expand Down
50 changes: 35 additions & 15 deletions src/core/qgstemporalutils.h
Expand Up @@ -44,28 +44,48 @@ class CORE_EXPORT QgsTemporalUtils
*/
static QgsDateTimeRange calculateTemporalRangeForProject( QgsProject *project );

class AnimationExportSettings
{
public:

//! Dictates the overall temporal range of the animation.
QgsDateTimeRange animationRange;

//! Duration of individual export frames
QgsInterval frameDuration;

//! Destination directory for created image files.
QString outputDirectory;

/**
* The filename template for exporting the frames.
*
* This must be in format prefix####.format, where number of
* \a # characters represents how many 0's should be left-padded to the frame number
* e.g. my###.jpg will create frames my001.jpg, my002.jpg, etc
*/
QString fileNameTemplate;

};

/**
* Exports animation frames by rendering the map to multiple destination images.
*
* The \a mapSettings argument dictates the overall map settings such as extent
* and size.
* and size, while animation and export specific settings are specified via the \a settings
* argument.
*
* An optional \a feedback argument can be used to provide progress reports and cancelation
* support.
*
* The \a animationRange argument specifies the overall temporal range of the animation.
* Temporal duration of individual frames is given by \a frameDuration.
* \param mapSettings settings controlling the map render
* \param settings animation and export settings
* \param error will be set to a descriptive error message if the export fails
* \param feedback optional feedback object for progress reports and cancelation checks
*
* An \a outputDirectory must be set, which controls where the created image files are
* stored. \a fileNameTemplate gives the template for exporting the frames.
* This must be in format prefix####.format, where number of
* # represents how many 0 should be left-padded to the frame number
* e.g. my###.jpg will create frames my001.jpg, my002.jpg, etc
* \returns TRUE if the export was successful.
*/
static bool exportAnimation( const QgsMapSettings &mapSettings,
const QgsDateTimeRange &animationRange,
QgsInterval frameDuration,
const QString &outputDirectory,
const QString &fileNameTemplate,
QString &error SIP_OUT,
QgsFeedback *feedback );
static bool exportAnimation( const QgsMapSettings &mapSettings, const AnimationExportSettings &settings, QString &error SIP_OUT, QgsFeedback *feedback = nullptr );
};


Expand Down

0 comments on commit 09fda8d

Please sign in to comment.