[FEATURE][composer] Allow for more than one atlas controlled map in compositions (or none), by moving some atlas properties to map items (fix #9248) (fix #6484)

This commit is contained in:
Nyall Dawson 2014-01-14 22:20:40 +11:00
parent 2cdc89654b
commit 6bb9dfec00
31 changed files with 818 additions and 342 deletions

View File

@ -17,16 +17,34 @@ public:
bool enabled() const;
void setEnabled( bool e );
/**Returns the map used by the atlas
* @deprecated Use QgsComposerMap::atlasDriven() instead
*/
QgsComposerMap* composerMap() const;
/**Sets the map used by the atlas
* @deprecated Use QgsComposerMap::setAtlasDriven( true ) instead
*/
void setComposerMap( QgsComposerMap* map );
bool hideCoverage() const;
void setHideCoverage( bool hide );
/**Returns whether the atlas map uses a fixed scale
* @deprecated Use QgsComposerMap::atlasFixedScale() instead
*/
bool fixedScale() const;
/**Sets whether the atlas map should use a fixed scale
* @deprecated Use QgsComposerMap::setAtlasFixedScale( bool ) instead
*/
void setFixedScale( bool fixed );
/**Returns the margin for the atlas map
* @deprecated Use QgsComposerMap::atlasMargin() instead
*/
float margin() const;
/**Sets the margin for the atlas map
* @deprecated Use QgsComposerMap::setAtlasMargin( double ) instead
*/
void setMargin( float margin );
QString filenamePattern() const;
@ -66,6 +84,21 @@ public:
/** Returns the current filename. Must be called after prepareForFeature( i ) */
const QString& currentFilename() const;
/** Requeries the current atlas coverage layer and applies filtering and sorting. Returns
number of matching features. Must be called after prepareForFeature( i ) */
int updateFeatures();
void nextFeature();
void prevFeature();
void lastFeature();
void firstFeature();
/** Returns the current atlas feature. Must be called after prepareForFeature( i ). */
QgsFeature* currentFeature();
/** Recalculates the bounds of an atlas driven map */
void prepareMap( QgsComposerMap* map );
void writeXML( QDomElement& elem, QDomDocument& doc ) const;
void readXML( const QDomElement& elem, const QDomDocument& doc );

View File

@ -366,7 +366,22 @@ class QgsComposerMap : QgsComposerItem
* @deprecated Use QgsComposerItem::sizeChangedByRotation( double& width, double& height, double rotation )
* instead
*/
void sizeChangedByRotation( double& width, double& height );
void sizeChangedByRotation( double& width, double& height );
/** Returns true if the map extent is set to follow the current atlas feature */
bool atlasDriven() const;
/** Set to true if the map extents should be set by the current atlas feature */
void setAtlasDriven( bool enabled );
/** Returns true if the map uses a fixed scale when in atlas mode */
bool atlasFixedScale() const;
/** Set to true if the map should use a fixed scale when in atlas mode */
void setAtlasFixedScale( bool fixed );
/** Returns the margin size (percentage) used when the map is in atlas mode */
double atlasMargin() const;
/** Sets the margin size (percentage) used when the map is in atlas mode */
void setAtlasMargin( double margin );
signals:
void extentChanged();

View File

@ -49,27 +49,10 @@ QgsAtlasCompositionWidget::QgsAtlasCompositionWidget( QWidget* parent, QgsCompos
connect( layerRegistry, SIGNAL( layerWasAdded( QgsMapLayer* ) ), this, SLOT( onLayerAdded( QgsMapLayer* ) ) );
}
// update the composer map combo box
// populate the map list
mComposerMapComboBox->clear();
QList<const QgsComposerMap*> availableMaps = mComposition->composerMapItems();
QList<const QgsComposerMap*>::const_iterator mapItemIt = availableMaps.constBegin();
for ( ; mapItemIt != availableMaps.constEnd(); ++mapItemIt )
{
mComposerMapComboBox->addItem( tr( "Map %1" ).arg(( *mapItemIt )->id() ), qVariantFromValue(( void* )*mapItemIt ) );
}
// Sort direction
mAtlasSortFeatureDirectionButton->setEnabled( false );
mAtlasSortFeatureKeyComboBox->setEnabled( false );
// Connect to addition / removal of maps
connect( mComposition, SIGNAL( composerMapAdded( QgsComposerMap* ) ), this, SLOT( onComposerMapAdded( QgsComposerMap* ) ) );
connect( mComposition, SIGNAL( itemRemoved( QgsComposerItem* ) ), this, SLOT( onItemRemoved( QgsComposerItem* ) ) );
connect( mAtlasMarginRadio, SIGNAL( toggled( bool ) ), mAtlasMarginSpinBox, SLOT( setEnabled( bool ) ) );
// connect to updates
connect( &mComposition->atlasComposition(), SIGNAL( parameterChanged() ), this, SLOT( updateGuiElements() ) );
@ -90,7 +73,6 @@ void QgsAtlasCompositionWidget::on_mUseAtlasCheckBox_stateChanged( int state )
mVisibilityGroup->setEnabled( true );
mSortingGroup->setEnabled( true );
mFilteringGroup->setEnabled( true );
mScalingGroup->setEnabled( true );
mOutputGroup->setEnabled( true );
}
else
@ -100,7 +82,6 @@ void QgsAtlasCompositionWidget::on_mUseAtlasCheckBox_stateChanged( int state )
mVisibilityGroup->setEnabled( false );
mSortingGroup->setEnabled( false );
mFilteringGroup->setEnabled( false );
mScalingGroup->setEnabled( false );
mOutputGroup->setEnabled( false );
}
}
@ -137,39 +118,10 @@ void QgsAtlasCompositionWidget::onLayerAdded( QgsMapLayer* map )
{
atlasMap->setCoverageLayer( vectorLayer );
updateAtlasFeatures();
checkLayerType( vectorLayer );
}
}
}
void QgsAtlasCompositionWidget::onComposerMapAdded( QgsComposerMap* map )
{
QgsAtlasComposition* atlasMap = &mComposition->atlasComposition();
mComposerMapComboBox->addItem( tr( "Map %1" ).arg( map->id() ), qVariantFromValue(( void* )map ) );
if ( mComposerMapComboBox->count() == 1 )
{
atlasMap->setComposerMap( map );
}
}
void QgsAtlasCompositionWidget::onItemRemoved( QgsComposerItem* item )
{
QgsAtlasComposition* atlasMap = &mComposition->atlasComposition();
QgsComposerMap* map = dynamic_cast<QgsComposerMap*>( item );
if ( map )
{
int idx = mComposerMapComboBox->findData( qVariantFromValue(( void* )map ) );
if ( idx != -1 )
{
mComposerMapComboBox->removeItem( idx );
}
}
if ( mComposerMapComboBox->count() == 0 )
{
atlasMap->setComposerMap( 0 );
}
}
void QgsAtlasCompositionWidget::on_mAtlasCoverageLayerComboBox_currentIndexChanged( int index )
{
QgsAtlasComposition* atlasMap = &mComposition->atlasComposition();
@ -190,7 +142,6 @@ void QgsAtlasCompositionWidget::on_mAtlasCoverageLayerComboBox_currentIndexChang
if ( layer )
{
checkLayerType( layer );
atlasMap->setCoverageLayer( layer );
updateAtlasFeatures();
}
@ -200,44 +151,6 @@ void QgsAtlasCompositionWidget::on_mAtlasCoverageLayerComboBox_currentIndexChang
}
}
void QgsAtlasCompositionWidget::checkLayerType( QgsVectorLayer *layer )
{
// enable or disable fixed scale control based on layer type
if ( !layer ) return;
switch ( layer->wkbType() )
{
case QGis::WKBPoint:
case QGis::WKBPoint25D:
case QGis::WKBMultiPoint:
case QGis::WKBMultiPoint25D:
//For point layers buffer setting makes no sense, so set "fixed scale" on and disable margin control
mAtlasFixedScaleRadio->setChecked( true );
mAtlasMarginRadio->setEnabled( false );
break;
default:
//Not a point layer, so enable changes to fixed scale control
mAtlasMarginRadio->setEnabled( true );
}
}
void QgsAtlasCompositionWidget::on_mComposerMapComboBox_currentIndexChanged( int index )
{
QgsAtlasComposition* atlasMap = &mComposition->atlasComposition();
if ( !atlasMap )
{
return;
}
if ( index == -1 )
{
atlasMap->setComposerMap( 0 );
}
else
{
QgsComposerMap* map = reinterpret_cast<QgsComposerMap*>( mComposerMapComboBox->itemData( index ).value<void*>() );
atlasMap->setComposerMap( map );
}
}
void QgsAtlasCompositionWidget::on_mAtlasFilenamePatternEdit_textChanged( const QString& text )
{
QgsAtlasComposition* atlasMap = &mComposition->atlasComposition();
@ -280,22 +193,6 @@ void QgsAtlasCompositionWidget::on_mAtlasHideCoverageCheckBox_stateChanged( int
atlasMap->setHideCoverage( state == Qt::Checked );
}
void QgsAtlasCompositionWidget::on_mAtlasFixedScaleRadio_toggled( bool checked )
{
QgsAtlasComposition* atlasMap = &mComposition->atlasComposition();
if ( !atlasMap )
{
return;
}
atlasMap->setFixedScale( checked );
}
void QgsAtlasCompositionWidget::on_mAtlasMarginSpinBox_valueChanged( int value )
{
QgsAtlasComposition* atlasMap = &mComposition->atlasComposition();
atlasMap->setMargin( value / 100. );
}
void QgsAtlasCompositionWidget::on_mAtlasSingleFileCheckBox_stateChanged( int state )
{
QgsAtlasComposition* atlasMap = &mComposition->atlasComposition();
@ -487,26 +384,9 @@ void QgsAtlasCompositionWidget::updateGuiElements()
if ( idx != -1 )
{
mAtlasCoverageLayerComboBox->setCurrentIndex( idx );
checkLayerType( atlasMap->coverageLayer() );
}
idx = mComposerMapComboBox->findData( qVariantFromValue(( void* )atlasMap->composerMap() ) );
if ( idx != -1 )
{
mComposerMapComboBox->setCurrentIndex( idx );
}
mAtlasMarginSpinBox->setValue( static_cast<int>( atlasMap->margin() * 100 ) );
mAtlasFilenamePatternEdit->setText( atlasMap->filenamePattern() );
if ( atlasMap->fixedScale() )
{
mAtlasFixedScaleRadio->setChecked( true );
mAtlasMarginSpinBox->setEnabled( false );
}
else
{
mAtlasMarginRadio->setChecked( true );
mAtlasMarginSpinBox->setEnabled( true );
}
mAtlasHideCoverageCheckBox->setCheckState( atlasMap->hideCoverage() ? Qt::Checked : Qt::Unchecked );
mAtlasSingleFileCheckBox->setCheckState( atlasMap->singleFile() ? Qt::Checked : Qt::Unchecked );
mAtlasSortFeatureCheckBox->setCheckState( atlasMap->sortFeatures() ? Qt::Checked : Qt::Unchecked );
@ -523,6 +403,5 @@ void QgsAtlasCompositionWidget::blockAllSignals( bool b )
mVisibilityGroup->blockSignals( b );
mSortingGroup->blockSignals( b );
mFilteringGroup->blockSignals( b );
mScalingGroup->blockSignals( b );
mOutputGroup->blockSignals( b );
}

View File

@ -36,12 +36,10 @@ class QgsAtlasCompositionWidget:
public slots:
void on_mUseAtlasCheckBox_stateChanged( int state );
void on_mComposerMapComboBox_currentIndexChanged( int index );
void on_mAtlasCoverageLayerComboBox_currentIndexChanged( int index );
void on_mAtlasFilenamePatternEdit_textChanged( const QString& text );
void on_mAtlasFilenameExpressionButton_clicked();
void on_mAtlasHideCoverageCheckBox_stateChanged( int state );
void on_mAtlasFixedScaleRadio_toggled( bool checked );
void on_mAtlasSingleFileCheckBox_stateChanged( int state );
void on_mAtlasSortFeatureCheckBox_stateChanged( int state );
@ -50,15 +48,12 @@ class QgsAtlasCompositionWidget:
void on_mAtlasFeatureFilterEdit_editingFinished();
void on_mAtlasFeatureFilterButton_clicked();
void on_mAtlasFeatureFilterCheckBox_stateChanged( int state );
void on_mAtlasMarginSpinBox_valueChanged( int value );
// extract fields from the current coverage layer and populate the corresponding combo box
void fillSortColumns();
private slots:
void onLayerRemoved( QString );
void onLayerAdded( QgsMapLayer* );
void onComposerMapAdded( QgsComposerMap* );
void onItemRemoved( QgsComposerItem* );
void updateGuiElements();

View File

@ -90,9 +90,21 @@ QgsComposerMapWidget::QgsComposerMapWidget( QgsComposerMap* composerMap ): QWidg
connect( mGridCheckBox, SIGNAL( toggled( bool ) ),
mDrawAnnotationCheckableGroupBox, SLOT( setEnabled( bool ) ) );
connect( mAtlasCheckBox, SIGNAL( toggled( bool ) ), this, SLOT( atlasToggled( bool ) ) );
if ( composerMap )
{
connect( composerMap, SIGNAL( itemChanged() ), this, SLOT( setGuiElementValues() ) );
//get composition
QgsComposition* composition = mComposerMap->composition();
if ( composition )
{
QgsAtlasComposition* atlas = &composition->atlasComposition();
connect( atlas, SIGNAL( coverageLayerChanged( QgsVectorLayer* ) ),
this, SLOT( atlasLayerChanged( QgsVectorLayer* ) ) );
connect( atlas, SIGNAL( toggled( bool ) ), this, SLOT( compositionAtlasToggled( bool ) ) );
}
}
updateOverviewSymbolMarker();
@ -106,6 +118,111 @@ QgsComposerMapWidget::~QgsComposerMapWidget()
{
}
void QgsComposerMapWidget::compositionAtlasToggled( bool atlasEnabled )
{
if ( atlasEnabled )
{
mAtlasCheckBox->setEnabled( true );
}
else
{
mAtlasCheckBox->setEnabled( false );
mAtlasCheckBox->setChecked( false );
}
}
void QgsComposerMapWidget::atlasToggled( bool checked )
{
if ( checked && mComposerMap )
{
//check atlas coverage layer type
QgsComposition* composition = mComposerMap->composition();
if ( composition )
{
toggleAtlasMarginByLayerType();
}
else
{
mAtlasMarginRadio->setEnabled( false );
}
}
else
{
mAtlasMarginRadio->setEnabled( false );
}
mAtlasFixedScaleRadio->setEnabled( checked );
if ( mAtlasMarginRadio->isEnabled() && mAtlasMarginRadio->isChecked() )
{
mAtlasMarginSpinBox->setEnabled( true );
}
else
{
mAtlasMarginSpinBox->setEnabled( false );
}
}
void QgsComposerMapWidget::on_mAtlasCheckBox_toggled( bool checked )
{
if ( !mComposerMap )
{
return;
}
mComposerMap->setAtlasDriven( checked );
updateMapForAtlas();
}
void QgsComposerMapWidget::updateMapForAtlas()
{
//update map if in atlas preview mode
QgsComposition* composition = mComposerMap->composition();
if ( !composition )
{
return;
}
if ( composition->atlasMode() == QgsComposition::AtlasOff )
{
return;
}
//update atlas based extent for map
QgsAtlasComposition* atlas = &composition->atlasComposition();
atlas->prepareMap( mComposerMap );
//redraw map
mComposerMap->cache();
mComposerMap->update();
}
void QgsComposerMapWidget::on_mAtlasMarginRadio_toggled( bool checked )
{
mAtlasMarginSpinBox->setEnabled( checked );
}
void QgsComposerMapWidget::on_mAtlasMarginSpinBox_valueChanged( int value )
{
if ( !mComposerMap )
{
return;
}
mComposerMap->setAtlasMargin( value / 100. );
updateMapForAtlas();
}
void QgsComposerMapWidget::on_mAtlasFixedScaleRadio_toggled( bool checked )
{
if ( !mComposerMap )
{
return;
}
mComposerMap->setAtlasFixedScale( checked );
updateMapForAtlas();
}
void QgsComposerMapWidget::on_mPreviewModeComboBox_activated( int i )
{
Q_UNUSED( i );
@ -402,10 +519,73 @@ void QgsComposerMapWidget::updateGuiElements()
mCoordinatePrecisionSpinBox->setValue( mComposerMap->gridAnnotationPrecision() );
//atlas controls
mAtlasCheckBox->setChecked( mComposerMap->atlasDriven() );
mAtlasMarginSpinBox->setValue( static_cast<int>( mComposerMap->atlasMargin() * 100 ) );
if ( mComposerMap->atlasFixedScale() )
{
mAtlasFixedScaleRadio->setChecked( true );
mAtlasMarginSpinBox->setEnabled( false );
}
else
{
mAtlasMarginRadio->setChecked( true );
mAtlasMarginSpinBox->setEnabled( true );
}
if ( !mComposerMap->atlasDriven() )
{
mAtlasMarginSpinBox->setEnabled( false );
mAtlasMarginRadio->setEnabled( false );
mAtlasFixedScaleRadio->setEnabled( false );
}
else
{
mAtlasFixedScaleRadio->setEnabled( true );
toggleAtlasMarginByLayerType();
}
blockAllSignals( false );
}
}
void QgsComposerMapWidget::toggleAtlasMarginByLayerType()
{
if ( !mComposerMap )
{
return;
}
//get composition
QgsComposition* composition = mComposerMap->composition();
if ( !composition )
{
return;
}
QgsAtlasComposition* atlas = &composition->atlasComposition();
QgsVectorLayer* coverageLayer = atlas->coverageLayer();
if ( !coverageLayer )
{
return;
}
switch ( atlas->coverageLayer()->wkbType() )
{
case QGis::WKBPoint:
case QGis::WKBPoint25D:
case QGis::WKBMultiPoint:
case QGis::WKBMultiPoint25D:
//For point layers buffer setting makes no sense, so set "fixed scale" on and disable margin control
mAtlasFixedScaleRadio->setChecked( true );
mAtlasMarginRadio->setEnabled( false );
break;
default:
//Not a point layer, so enable changes to fixed scale control
mAtlasMarginRadio->setEnabled( true );
}
}
void QgsComposerMapWidget::updateComposerExtentFromGui()
{
if ( !mComposerMap )
@ -480,6 +660,10 @@ void QgsComposerMapWidget::blockAllSignals( bool b )
mOverviewBlendModeComboBox->blockSignals( b );
mOverviewInvertCheckbox->blockSignals( b );
mOverviewCenterCheckbox->blockSignals( b );
mAtlasCheckBox->blockSignals( b );
mAtlasMarginSpinBox->blockSignals( b );
mAtlasFixedScaleRadio->blockSignals( b );
mAtlasMarginRadio->blockSignals( b );
}
void QgsComposerMapWidget::on_mUpdatePreviewButton_clicked()
@ -1173,3 +1357,14 @@ void QgsComposerMapWidget::refreshMapComboBox()
mOverviewFrameMapComboBox->blockSignals( false );
}
void QgsComposerMapWidget::atlasLayerChanged( QgsVectorLayer* layer )
{
// enable or disable fixed scale control based on layer type
if ( !layer || !mAtlasCheckBox->isChecked() )
{
return;
}
toggleAtlasMarginByLayerType();
}

View File

@ -90,6 +90,13 @@ class QgsComposerMapWidget: public QWidget, private Ui::QgsComposerMapWidgetBase
void on_mGridFrameFill1ColorButton_colorChanged( const QColor& newColor );
void on_mGridFrameFill2ColorButton_colorChanged( const QColor& newColor );
void atlasToggled( bool checked );
void on_mAtlasMarginRadio_toggled( bool checked );
void on_mAtlasCheckBox_toggled( bool checked );
void on_mAtlasMarginSpinBox_valueChanged( int value );
void on_mAtlasFixedScaleRadio_toggled( bool checked );
protected:
void showEvent( QShowEvent * event );
@ -103,6 +110,12 @@ class QgsComposerMapWidget: public QWidget, private Ui::QgsComposerMapWidgetBase
/**Sets the GUI elements to the values of mPicture*/
void setGuiElementValues();
/**Enables or disables the atlas margin around feature option depending on coverage layer type*/
void atlasLayerChanged( QgsVectorLayer* layer );
/**Enables or disables the atlas controls when composer atlas is toggled on/off*/
void compositionAtlasToggled( bool atlasEnabled );
private:
QgsComposerMap* mComposerMap;
@ -129,6 +142,13 @@ class QgsComposerMapWidget: public QWidget, private Ui::QgsComposerMapWidgetBase
/**Enables/disables grid frame related controls*/
void toggleFrameControls( bool frameEnabled );
/**Enables or disables the atlas margin radio depending on the atlas coverage layer type*/
void toggleAtlasMarginByLayerType();
/**Recalculates the bounds for an atlas map when atlas properties change*/
void updateMapForAtlas();
};
#endif

View File

@ -31,8 +31,7 @@
QgsAtlasComposition::QgsAtlasComposition( QgsComposition* composition ) :
mComposition( composition ),
mEnabled( false ),
mComposerMap( 0 ),
mHideCoverage( false ), mFixedScale( false ), mMargin( 0.10 ), mFilenamePattern( "'output_'||$feature" ),
mHideCoverage( false ), mFilenamePattern( "'output_'||$feature" ),
mCoverageLayer( 0 ), mSingleFile( false ),
mSortFeatures( false ), mSortAscending( true ), mCurrentFeatureNo( 0 ),
mFilterFeatures( false ), mFeatureFilter( "" )
@ -70,6 +69,87 @@ void QgsAtlasComposition::setCoverageLayer( QgsVectorLayer* layer )
layer->getFeatures().nextFeature( fet );
QgsExpression::setSpecialColumn( "$atlasfeatureid", fet.id() );
QgsExpression::setSpecialColumn( "$atlasgeometry", QVariant::fromValue( *fet.geometry() ) );
emit coverageLayerChanged( layer );
}
QgsComposerMap* QgsAtlasComposition::composerMap() const
{
//deprecated method. Until removed just return the first atlas-enabled composer map
//build a list of composer maps
QList<QgsComposerMap*> maps;
mComposition->composerItems( maps );
for ( QList<QgsComposerMap*>::iterator mit = maps.begin(); mit != maps.end(); ++mit )
{
QgsComposerMap* currentMap = ( *mit );
if ( currentMap->atlasDriven() )
{
return currentMap;
}
}
return 0;
}
void QgsAtlasComposition::setComposerMap( QgsComposerMap* map )
{
//deprecated
if ( !map )
{
return;
}
map->setAtlasDriven( true );
}
bool QgsAtlasComposition::fixedScale() const
{
//deprecated method. Until removed just return the property for the first atlas-enabled composer map
QgsComposerMap * map = composerMap();
if ( !map )
{
return false;
}
return map->atlasFixedScale();
}
void QgsAtlasComposition::setFixedScale( bool fixed )
{
//deprecated method. Until removed just set the property for the first atlas-enabled composer map
QgsComposerMap * map = composerMap();
if ( !map )
{
return;
}
map->setAtlasFixedScale( fixed );
}
float QgsAtlasComposition::margin() const
{
//deprecated method. Until removed just return the property for the first atlas-enabled composer map
QgsComposerMap * map = composerMap();
if ( !map )
{
return 0;
}
return map->atlasMargin();
}
void QgsAtlasComposition::setMargin( float margin )
{
//deprecated method. Until removed just set the property for the first atlas-enabled composer map
QgsComposerMap * map = composerMap();
if ( !map )
{
return;
}
map->setAtlasMargin(( double ) margin );
}
//
@ -107,17 +187,11 @@ int QgsAtlasComposition::updateFeatures()
{
//needs to be called when layer, filter, sort changes
if ( !mComposerMap || !mCoverageLayer )
if ( !mCoverageLayer )
{
return 0;
}
const QgsCoordinateReferenceSystem& coverage_crs = mCoverageLayer->crs();
const QgsCoordinateReferenceSystem& destination_crs = mComposerMap->mapRenderer()->destinationCrs();
// transformation needed for feature geometries
mTransform.setSourceCrs( coverage_crs );
mTransform.setDestCRS( destination_crs );
updateFilenameExpression();
// select all features with all attributes
@ -184,7 +258,7 @@ int QgsAtlasComposition::updateFeatures()
bool QgsAtlasComposition::beginRender()
{
if ( !mComposerMap || !mCoverageLayer )
if ( !mCoverageLayer )
{
return false;
}
@ -218,7 +292,7 @@ bool QgsAtlasComposition::beginRender()
void QgsAtlasComposition::endRender()
{
if ( !mComposerMap || !mCoverageLayer )
if ( !mCoverageLayer )
{
return;
}
@ -239,7 +313,24 @@ void QgsAtlasComposition::endRender()
layerSet.push_back( mCoverageLayer->id() );
}
mComposerMap->cache();
updateAtlasMaps();
}
void QgsAtlasComposition::updateAtlasMaps()
{
//update atlas-enabled composer maps
QList<QgsComposerMap*> maps;
mComposition->composerItems( maps );
for ( QList<QgsComposerMap*>::iterator mit = maps.begin(); mit != maps.end(); ++mit )
{
QgsComposerMap* currentMap = ( *mit );
if ( !currentMap->atlasDriven() )
{
continue;
}
currentMap->cache();
}
}
int QgsAtlasComposition::numFeatures() const
@ -283,7 +374,7 @@ void QgsAtlasComposition::lastFeature()
void QgsAtlasComposition::prepareForFeature( int featureI )
{
if ( !mComposerMap || !mCoverageLayer )
if ( !mCoverageLayer )
{
return;
}
@ -304,70 +395,6 @@ void QgsAtlasComposition::prepareForFeature( int featureI )
// generate filename for current feature
evalFeatureFilename();
//
// compute the new extent
// keep the original aspect ratio
// and apply a margin
// QgsGeometry::boundingBox is expressed in the geometry"s native CRS
// We have to transform the grometry to the destination CRS and ask for the bounding box
// Note: we cannot directly take the transformation of the bounding box, since transformations are not linear
QgsGeometry tgeom( *mCurrentFeature.geometry() );
tgeom.transform( mTransform );
QgsRectangle geom_rect = tgeom.boundingBox();
double xa1 = geom_rect.xMinimum();
double xa2 = geom_rect.xMaximum();
double ya1 = geom_rect.yMinimum();
double ya2 = geom_rect.yMaximum();
QgsRectangle new_extent = geom_rect;
QgsRectangle mOrigExtent = mComposerMap->extent();
if ( mFixedScale )
{
// only translate, keep the original scale (i.e. width x height)
double geom_center_x = ( xa1 + xa2 ) / 2.0;
double geom_center_y = ( ya1 + ya2 ) / 2.0;
double xx = geom_center_x - mOrigExtent.width() / 2.0;
double yy = geom_center_y - mOrigExtent.height() / 2.0;
new_extent = QgsRectangle( xx,
yy,
xx + mOrigExtent.width(),
yy + mOrigExtent.height() );
}
else
{
// auto scale
double geom_ratio = geom_rect.width() / geom_rect.height();
double map_ratio = mOrigExtent.width() / mOrigExtent.height();
// geometry height is too big
if ( geom_ratio < map_ratio )
{
// extent the bbox's width
double adj_width = ( map_ratio * geom_rect.height() - geom_rect.width() ) / 2.0;
xa1 -= adj_width;
xa2 += adj_width;
}
// geometry width is too big
else if ( geom_ratio > map_ratio )
{
// extent the bbox's height
double adj_height = ( geom_rect.width() / map_ratio - geom_rect.height() ) / 2.0;
ya1 -= adj_height;
ya2 += adj_height;
}
new_extent = QgsRectangle( xa1, ya1, xa2, ya2 );
if ( mMargin > 0.0 )
{
new_extent.scale( 1 + mMargin );
}
}
// evaluate label expressions
QList<QgsComposerLabel*> labels;
mComposition->composerItems( labels );
@ -392,10 +419,118 @@ void QgsAtlasComposition::prepareForFeature( int featureI )
( *pageIt )->update();
}
// set the new extent (and render)
mComposerMap->setNewAtlasFeatureExtent( new_extent );
emit statusMsgChanged( QString( tr( "Atlas feature %1 of %2" ) ).arg( featureI + 1 ).arg( mFeatureIds.size() ) );
//update composer maps
//build a list of atlas-enabled composer maps
QList<QgsComposerMap*> maps;
QList<QgsComposerMap*> atlasMaps;
mComposition->composerItems( maps );
for ( QList<QgsComposerMap*>::iterator mit = maps.begin(); mit != maps.end(); ++mit )
{
QgsComposerMap* currentMap = ( *mit );
if ( !currentMap->atlasDriven() )
{
continue;
}
atlasMaps << currentMap;
}
if ( atlasMaps.isEmpty() )
{
//no atlas enabled maps
return;
}
//
// compute the new extent
// keep the original aspect ratio
// and apply a margin
const QgsCoordinateReferenceSystem& coverage_crs = mCoverageLayer->crs();
// transformation needed for feature geometries. This should be set on a per-atlas map basis,
// but given that it's not currently possible to have maps with different CRSes we can just
// calculate it once based on the first atlas maps' CRS.
const QgsCoordinateReferenceSystem& destination_crs = atlasMaps[0]->mapRenderer()->destinationCrs();
mTransform.setSourceCrs( coverage_crs );
mTransform.setDestCRS( destination_crs );
// QgsGeometry::boundingBox is expressed in the geometry"s native CRS
// We have to transform the grometry to the destination CRS and ask for the bounding box
// Note: we cannot directly take the transformation of the bounding box, since transformations are not linear
QgsGeometry tgeom( *mCurrentFeature.geometry() );
tgeom.transform( mTransform );
mTransformedFeatureBounds = tgeom.boundingBox();
//update atlas bounds of every atlas enabled composer map
for ( QList<QgsComposerMap*>::iterator mit = atlasMaps.begin(); mit != atlasMaps.end(); ++mit )
{
prepareMap( *mit );
}
}
void QgsAtlasComposition::prepareMap( QgsComposerMap* map )
{
if ( !map->atlasDriven() )
{
return;
}
double xa1 = mTransformedFeatureBounds.xMinimum();
double xa2 = mTransformedFeatureBounds.xMaximum();
double ya1 = mTransformedFeatureBounds.yMinimum();
double ya2 = mTransformedFeatureBounds.yMaximum();
QgsRectangle new_extent = mTransformedFeatureBounds;
QgsRectangle mOrigExtent = map->extent();
if ( map->atlasFixedScale() )
{
// only translate, keep the original scale (i.e. width x height)
double geom_center_x = ( xa1 + xa2 ) / 2.0;
double geom_center_y = ( ya1 + ya2 ) / 2.0;
double xx = geom_center_x - mOrigExtent.width() / 2.0;
double yy = geom_center_y - mOrigExtent.height() / 2.0;
new_extent = QgsRectangle( xx,
yy,
xx + mOrigExtent.width(),
yy + mOrigExtent.height() );
}
else
{
// auto scale
double geom_ratio = mTransformedFeatureBounds.width() / mTransformedFeatureBounds.height();
double map_ratio = mOrigExtent.width() / mOrigExtent.height();
// geometry height is too big
if ( geom_ratio < map_ratio )
{
// extent the bbox's width
double adj_width = ( map_ratio * mTransformedFeatureBounds.height() - mTransformedFeatureBounds.width() ) / 2.0;
xa1 -= adj_width;
xa2 += adj_width;
}
// geometry width is too big
else if ( geom_ratio > map_ratio )
{
// extent the bbox's height
double adj_height = ( mTransformedFeatureBounds.width() / map_ratio - mTransformedFeatureBounds.height() ) / 2.0;
ya1 -= adj_height;
ya2 += adj_height;
}
new_extent = QgsRectangle( xa1, ya1, xa2, ya2 );
if ( map->atlasMargin() > 0.0 )
{
new_extent.scale( 1 + map->atlasMargin() );
}
}
// set the new extent (and render)
map->setNewAtlasFeatureExtent( new_extent );
}
const QString& QgsAtlasComposition::currentFilename() const
@ -420,18 +555,9 @@ void QgsAtlasComposition::writeXML( QDomElement& elem, QDomDocument& doc ) const
{
atlasElem.setAttribute( "coverageLayer", "" );
}
if ( mComposerMap )
{
atlasElem.setAttribute( "composerMap", mComposerMap->id() );
}
else
{
atlasElem.setAttribute( "composerMap", "" );
}
atlasElem.setAttribute( "hideCoverage", mHideCoverage ? "true" : "false" );
atlasElem.setAttribute( "fixedScale", mFixedScale ? "true" : "false" );
atlasElem.setAttribute( "singleFile", mSingleFile ? "true" : "false" );
atlasElem.setAttribute( "margin", QString::number( mMargin ) );
atlasElem.setAttribute( "filenamePattern", mFilenamePattern );
atlasElem.setAttribute( "sortFeatures", mSortFeatures ? "true" : "false" );
@ -470,20 +596,36 @@ void QgsAtlasComposition::readXML( const QDomElement& atlasElem, const QDomDocum
break;
}
}
// look for stored composer map
mComposerMap = 0;
QList<const QgsComposerMap*> maps = mComposition->composerMapItems();
for ( QList<const QgsComposerMap*>::const_iterator it = maps.begin(); it != maps.end(); ++it )
//look for stored composer map, to upgrade pre 2.1 projects
int composerMapNo = atlasElem.attribute( "composerMap", "0" ).toInt();
QgsComposerMap * composerMap = 0;
if ( composerMapNo != 0 )
{
if (( *it )->id() == atlasElem.attribute( "composerMap" ).toInt() )
QList<QgsComposerMap*> maps;
mComposition->composerItems( maps );
for ( QList<QgsComposerMap*>::iterator it = maps.begin(); it != maps.end(); ++it )
{
mComposerMap = const_cast<QgsComposerMap*>( *it );
break;
if (( *it )->id() == composerMapNo )
{
( *it )->setAtlasDriven( true );
break;
}
}
}
mMargin = atlasElem.attribute( "margin", "0.0" ).toDouble();
mHideCoverage = atlasElem.attribute( "hideCoverage", "false" ) == "true" ? true : false;
mFixedScale = atlasElem.attribute( "fixedScale", "false" ) == "true" ? true : false;
//upgrade pre 2.1 projects
double margin = atlasElem.attribute( "margin", "0.0" ).toDouble();
if ( composerMap && margin != 0 )
{
composerMap->setAtlasMargin( margin );
}
bool fixedScale = atlasElem.attribute( "fixedScale", "false" ) == "true" ? true : false;
if ( composerMap && fixedScale )
{
composerMap->setAtlasFixedScale( true );
}
mSingleFile = atlasElem.attribute( "singleFile", "false" ) == "true" ? true : false;
mFilenamePattern = atlasElem.attribute( "filenamePattern", "" );
@ -528,7 +670,7 @@ void QgsAtlasComposition::setHideCoverage( bool hide )
mRestoreLayer = false;
}
}
mComposerMap->cache();
updateAtlasMaps();
mComposition->update();
}

View File

@ -45,17 +45,35 @@ class CORE_EXPORT QgsAtlasComposition : public QObject
bool enabled() const { return mEnabled; }
void setEnabled( bool e );
QgsComposerMap* composerMap() const { return mComposerMap; }
void setComposerMap( QgsComposerMap* map ) { mComposerMap = map; }
/**Returns the map used by the atlas
* @deprecated Use QgsComposerMap::atlasDriven() instead
*/
QgsComposerMap* composerMap() const;
/**Sets the map used by the atlas
* @deprecated Use QgsComposerMap::setAtlasDriven( true ) instead
*/
void setComposerMap( QgsComposerMap* map );
bool hideCoverage() const { return mHideCoverage; }
void setHideCoverage( bool hide );
bool fixedScale() const { return mFixedScale; }
void setFixedScale( bool fixed ) { mFixedScale = fixed; }
/**Returns whether the atlas map uses a fixed scale
* @deprecated Use QgsComposerMap::atlasFixedScale() instead
*/
bool fixedScale() const;
/**Sets whether the atlas map should use a fixed scale
* @deprecated Use QgsComposerMap::setAtlasFixedScale( bool ) instead
*/
void setFixedScale( bool fixed );
float margin() const { return mMargin; }
void setMargin( float margin ) { mMargin = margin; }
/**Returns the margin for the atlas map
* @deprecated Use QgsComposerMap::atlasMargin() instead
*/
float margin() const;
/**Sets the margin for the atlas map
* @deprecated Use QgsComposerMap::setAtlasMargin( double ) instead
*/
void setMargin( float margin );
QString filenamePattern() const { return mFilenamePattern; }
void setFilenamePattern( const QString& pattern );
@ -113,6 +131,9 @@ class CORE_EXPORT QgsAtlasComposition : public QObject
/** Returns the current atlas feature. Must be called after prepareForFeature( i ). */
QgsFeature* currentFeature() { return &mCurrentFeature; }
/** Recalculates the bounds of an atlas driven map */
void prepareMap( QgsComposerMap* map );
signals:
/** emitted when one of the parameters changes */
void parameterChanged();
@ -123,6 +144,9 @@ class CORE_EXPORT QgsAtlasComposition : public QObject
/**Is emitted when the atlas has an updated status bar message for the composer window*/
void statusMsgChanged( QString message );
/**Is emitted when the coverage layer for an atlas changes*/
void coverageLayerChanged( QgsVectorLayer* layer );
private:
/**Updates the filename expression*/
void updateFilenameExpression();
@ -133,10 +157,7 @@ class CORE_EXPORT QgsAtlasComposition : public QObject
QgsComposition* mComposition;
bool mEnabled;
QgsComposerMap* mComposerMap;
bool mHideCoverage;
bool mFixedScale;
double mMargin;
QString mFilenamePattern;
QgsVectorLayer* mCoverageLayer;
bool mSingleFile;
@ -170,6 +191,12 @@ class CORE_EXPORT QgsAtlasComposition : public QObject
QgsFeature mCurrentFeature;
bool mRestoreLayer;
std::auto_ptr<QgsExpression> mFilenameExpr;
// bounding box of the current feature transformed into map crs
QgsRectangle mTransformedFeatureBounds;
//forces all atlas enabled maps to redraw
void updateAtlasMaps();
};
#endif

View File

@ -51,7 +51,7 @@ QgsComposerMap::QgsComposerMap( QgsComposition *composition, int x, int y, int w
mLeftGridAnnotationDirection( Horizontal ), mRightGridAnnotationDirection( Horizontal ), mTopGridAnnotationDirection( Horizontal ),
mBottomGridAnnotationDirection( Horizontal ), mGridFrameStyle( NoGridFrame ), mGridFrameWidth( 2.0 ),
mGridFramePenThickness( 0.5 ), mGridFramePenColor( QColor( 0, 0, 0 ) ), mGridFrameFillColor1( Qt::white ), mGridFrameFillColor2( Qt::black ),
mCrossLength( 3 ), mMapCanvas( 0 ), mDrawCanvasItems( true )
mCrossLength( 3 ), mMapCanvas( 0 ), mDrawCanvasItems( true ), mAtlasDriven( false ), mAtlasFixedScale( false ), mAtlasMargin( 0.10 )
{
mComposition = composition;
mOverviewFrameMapSymbol = 0;
@ -106,7 +106,7 @@ QgsComposerMap::QgsComposerMap( QgsComposition *composition )
mLeftGridAnnotationDirection( Horizontal ), mRightGridAnnotationDirection( Horizontal ), mTopGridAnnotationDirection( Horizontal ),
mBottomGridAnnotationDirection( Horizontal ), mGridFrameStyle( NoGridFrame ), mGridFrameWidth( 2.0 ), mGridFramePenThickness( 0.5 ),
mGridFramePenColor( QColor( 0, 0, 0 ) ), mGridFrameFillColor1( Qt::white ), mGridFrameFillColor2( Qt::black ),
mCrossLength( 3 ), mMapCanvas( 0 ), mDrawCanvasItems( true )
mCrossLength( 3 ), mMapCanvas( 0 ), mDrawCanvasItems( true ), mAtlasDriven( false ), mAtlasFixedScale( false ), mAtlasMargin( 0.10 )
{
mOverviewFrameMapSymbol = 0;
mGridLineSymbol = 0;
@ -651,10 +651,7 @@ void QgsComposerMap::toggleAtlasPreview()
QgsRectangle* QgsComposerMap::currentMapExtent()
{
//non-const version
QgsAtlasComposition* atlasMap = &mComposition->atlasComposition();
if ( atlasMap->composerMap() == this && mComposition->atlasMode() != QgsComposition::AtlasOff )
if ( mAtlasDriven && mComposition->atlasMode() != QgsComposition::AtlasOff )
{
//if atlas is enabled, and we are either exporting the composition or previewing the atlas, then
//return the current temporary atlas feature extent
@ -670,9 +667,7 @@ QgsRectangle* QgsComposerMap::currentMapExtent()
const QgsRectangle* QgsComposerMap::currentMapExtent() const
{
//const version
QgsAtlasComposition* atlasMap = &mComposition->atlasComposition();
if ( atlasMap->composerMap() == this && mComposition->atlasMode() != QgsComposition::AtlasOff )
if ( mAtlasDriven && mComposition->atlasMode() != QgsComposition::AtlasOff )
{
//if atlas is enabled, and we are either exporting the composition or previewing the atlas, then
//return the current temporary atlas feature extent
@ -991,6 +986,13 @@ bool QgsComposerMap::writeXML( QDomElement& elem, QDomDocument & doc ) const
gridElem.appendChild( annotationElem );
composerMapElem.appendChild( gridElem );
//atlas
QDomElement atlasElem = doc.createElement( "AtlasMap" );
atlasElem.setAttribute( "atlasDriven", mAtlasDriven );
atlasElem.setAttribute( "fixedScale", mAtlasFixedScale );
atlasElem.setAttribute( "margin", qgsDoubleToString( mAtlasMargin ) );
composerMapElem.appendChild( atlasElem );
elem.appendChild( composerMapElem );
return _writeXML( composerMapElem, doc );
}
@ -1233,6 +1235,16 @@ bool QgsComposerMap::readXML( const QDomElement& itemElem, const QDomDocument& d
}
}
//atlas
QDomNodeList atlasNodeList = itemElem.elementsByTagName( "AtlasMap" );
if ( atlasNodeList.size() > 0 )
{
QDomElement atlasElem = atlasNodeList.at( 0 ).toElement();
mAtlasDriven = ( atlasElem.attribute( "atlasDriven", "0" ) != "0" );
mAtlasFixedScale = ( atlasElem.attribute( "fixedScale", "0" ) != "0" );
mAtlasMargin = atlasElem.attribute( "margin", "0.1" ).toDouble();
}
//restore general composer item properties
QDomNodeList composerItemList = itemElem.elementsByTagName( "ComposerItem" );
if ( composerItemList.size() > 0 )

View File

@ -420,6 +420,21 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem
*/
void sizeChangedByRotation( double& width, double& height );
/** Returns true if the map extent is set to follow the current atlas feature */
bool atlasDriven() const { return mAtlasDriven; }
/** Set to true if the map extents should be set by the current atlas feature */
void setAtlasDriven( bool enabled ) { mAtlasDriven = enabled; }
/** Returns true if the map uses a fixed scale when in atlas mode */
bool atlasFixedScale() const { return mAtlasFixedScale; }
/** Set to true if the map should use a fixed scale when in atlas mode */
void setAtlasFixedScale( bool fixed ) { mAtlasFixedScale = fixed; }
/** Returns the margin size (percentage) used when the map is in atlas mode */
double atlasMargin() const { return mAtlasMargin; }
/** Sets the margin size (percentage) used when the map is in atlas mode */
void setAtlasMargin( double margin ) { mAtlasMargin = margin; }
signals:
void extentChanged();
@ -571,6 +586,13 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem
* center of extent remains the same */
void adjustExtentToItemShape( double itemWidth, double itemHeight, QgsRectangle& extent ) const;
/**True if map is being controlled by an atlas*/
bool mAtlasDriven;
/**True if map uses a fixed scale when controlled by an atlas*/
bool mAtlasFixedScale;
/**Margin size for atlas driven extents (percentage of feature size)*/
double mAtlasMargin;
/**Draws the map grid*/
void drawGrid( QPainter* p );
void drawGridFrame( QPainter* p, const QList< QPair< double, QLineF > >& hLines, const QList< QPair< double, QLineF > >& vLines );

View File

@ -2347,9 +2347,16 @@ bool QgsComposition::setAtlasMode( QgsComposition::AtlasMode mode )
}
}
if ( mAtlasComposition.composerMap() )
QList<QgsComposerMap*> maps;
composerItems( maps );
for ( QList<QgsComposerMap*>::iterator mit = maps.begin(); mit != maps.end(); ++mit )
{
mAtlasComposition.composerMap()->toggleAtlasPreview();
QgsComposerMap* currentMap = ( *mit );
if ( !currentMap->atlasDriven() )
{
continue;
}
currentMap->toggleAtlasPreview();
}
update();

View File

@ -23,7 +23,16 @@
<property name="spacing">
<number>0</number>
</property>
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
@ -32,15 +41,24 @@
<enum>QFrame::StyledPanel</enum>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="horizontalSpacing">
<number>0</number>
</property>
<property name="verticalSpacing">
<number>3</number>
</property>
<property name="margin">
<number>0</number>
</property>
<item row="0" column="1">
<widget class="QCheckBox" name="mUseAtlasCheckBox">
<property name="text">
@ -91,7 +109,7 @@
<x>0</x>
<y>0</y>
<width>431</width>
<height>568</height>
<height>567</height>
</rect>
</property>
<layout class="QVBoxLayout" name="mainLayout">
@ -123,27 +141,13 @@
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<item row="0" column="0">
<widget class="QLabel" name="mVerticalAlignementLabel">
<property name="text">
<string>Composer map</string>
</property>
</widget>
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QComboBox" name="mComposerMapComboBox"/>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QLabel" name="mHorizontalAlignementLabel">
<property name="text">
<string>Coverage layer</string>
</property>
</widget>
</item>
<item row="1" column="1">
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QComboBox" name="mAtlasCoverageLayerComboBox"/>
@ -280,60 +284,6 @@
</layout>
</widget>
</item>
<item>
<widget class="QgsCollapsibleGroupBoxBasic" name="mScalingGroup">
<property name="enabled">
<bool>false</bool>
</property>
<property name="title">
<string>Scaling</string>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<property name="syncGroup" stdset="0">
<string notr="true">composeritem</string>
</property>
<property name="collapsed" stdset="0">
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QRadioButton" name="mAtlasMarginRadio">
<property name="text">
<string>Margin around feature</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="mAtlasMarginSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="suffix">
<string>%</string>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="value">
<number>10</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QRadioButton" name="mAtlasFixedScaleRadio">
<property name="text">
<string>Fixed scale</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QgsCollapsibleGroupBoxBasic" name="mOutputGroup">
<property name="enabled">

View File

@ -23,7 +23,16 @@
<property name="spacing">
<number>0</number>
</property>
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
@ -54,9 +63,9 @@
<property name="geometry">
<rect>
<x>0</x>
<y>-420</y>
<y>0</y>
<width>439</width>
<height>1509</height>
<height>1638</height>
</rect>
</property>
<property name="sizePolicy">
@ -251,6 +260,66 @@
</layout>
</widget>
</item>
<item>
<widget class="QgsCollapsibleGroupBoxBasic" name="mAtlasCheckBox">
<property name="title">
<string>Controlled by atlas</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<property name="collapsed" stdset="0">
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QRadioButton" name="mAtlasMarginRadio">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Margin around feature</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="mAtlasMarginSpinBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="suffix">
<string>%</string>
</property>
<property name="maximum">
<number>9999</number>
</property>
<property name="value">
<number>10</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QRadioButton" name="mAtlasFixedScaleRadio">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Fixed scale</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QgsCollapsibleGroupBoxBasic" name="mGridCheckBox">
<property name="title">

View File

@ -36,7 +36,7 @@ QgsCompositionChecker::~QgsCompositionChecker()
{
}
bool QgsCompositionChecker::testComposition( QString &report, int page )
bool QgsCompositionChecker::testComposition( QString &report, int page, int pixelDiff )
{
if ( !mComposition )
{
@ -82,7 +82,7 @@ bool QgsCompositionChecker::testComposition( QString &report, int page )
QString diffFilePath = QDir::tempPath() + QDir::separator() + QFileInfo( mTestName ).baseName() + "_result_diff.png";
bool testResult = compareImages( mTestName, 0, renderedFilePath );
bool testResult = compareImages( mTestName, pixelDiff, renderedFilePath );
QString myDashMessage = "<DartMeasurementFile name=\"Rendered Image " + mTestName + "\""
" type=\"image/png\">" + renderedFilePath +

View File

@ -29,7 +29,7 @@ class QgsCompositionChecker : public QgsRenderChecker
QgsCompositionChecker( const QString& testName, QgsComposition* composition );
~QgsCompositionChecker();
bool testComposition( QString &report, int page = 0 );
bool testComposition( QString &report, int page = 0, int pixelDiff = 0 );
private:
QgsCompositionChecker(); //forbidden

View File

@ -43,8 +43,14 @@ class TestQgsAtlasComposition: public QObject
void filename();
// test rendering with an autoscale atlas
void autoscale_render();
// test rendering with an autoscale atlas using the old api
void autoscale_render_2_0_api();
// test rendering with a fixed scale atlas
void fixedscale_render();
// test rendering with a fixed scale atlas using the old api
void fixedscale_render_2_0_api();
// test rendering with two atlas-driven maps
void two_map_autoscale_render();
// test rendering with a hidden coverage
void hiding_render();
// test rendering with feature sorting
@ -104,7 +110,6 @@ void TestQgsAtlasComposition::initTestCase()
mAtlas = &mComposition->atlasComposition();
mAtlas->setCoverageLayer( mVectorLayer );
mAtlas->setComposerMap( mAtlasMap );
mComposition->setAtlasMode( QgsComposition::ExportAtlas );
// an overview
@ -180,6 +185,29 @@ void TestQgsAtlasComposition::filename()
void TestQgsAtlasComposition::autoscale_render()
{
mAtlasMap->setAtlasDriven( true );
mAtlasMap->setAtlasFixedScale( false );
mAtlasMap->setAtlasMargin( 0.10 );
mAtlas->beginRender();
for ( int fit = 0; fit < 2; ++fit )
{
mAtlas->prepareForFeature( fit );
mLabel1->adjustSizeToText();
QgsCompositionChecker checker( QString( "atlas_autoscale%1" ).arg((( int )fit ) + 1 ), mComposition );
QVERIFY( checker.testComposition( mReport, 0, 10 ) );
}
mAtlas->endRender();
mAtlasMap->setAtlasDriven( false );
mAtlasMap->setAtlasFixedScale( false );
mAtlasMap->setAtlasMargin( 0 );
}
void TestQgsAtlasComposition::autoscale_render_2_0_api()
{
mAtlas->setComposerMap( mAtlasMap );
mAtlas->setFixedScale( false );
mAtlas->setMargin( 0.10f );
@ -190,16 +218,20 @@ void TestQgsAtlasComposition::autoscale_render()
mAtlas->prepareForFeature( fit );
mLabel1->adjustSizeToText();
QgsCompositionChecker checker( QString( "atlas_autoscale%1" ).arg((( int )fit ) + 1 ), mComposition );
QgsCompositionChecker checker( QString( "atlas_autoscale_old_api%1" ).arg((( int )fit ) + 1 ), mComposition );
QVERIFY( checker.testComposition( mReport, 0 ) );
}
mAtlas->endRender();
mAtlas->setComposerMap( 0 );
mAtlas->setFixedScale( false );
mAtlas->setMargin( 0 );
}
void TestQgsAtlasComposition::fixedscale_render()
{
mAtlasMap->setAtlasDriven( true );
mAtlasMap->setNewExtent( QgsRectangle( 209838.166, 6528781.020, 610491.166, 6920530.620 ) );
mAtlas->setFixedScale( true );
mAtlasMap->setAtlasFixedScale( true );
mAtlas->beginRender();
@ -213,12 +245,61 @@ void TestQgsAtlasComposition::fixedscale_render()
}
mAtlas->endRender();
mAtlasMap->setAtlasDriven( false );
mAtlasMap->setAtlasFixedScale( false );
}
void TestQgsAtlasComposition::fixedscale_render_2_0_api()
{
mAtlasMap->setNewExtent( QgsRectangle( 209838.166, 6528781.020, 610491.166, 6920530.620 ) );
mAtlas->setComposerMap( mAtlasMap );
mAtlas->setFixedScale( true );
mAtlas->beginRender();
for ( int fit = 0; fit < 2; ++fit )
{
mAtlas->prepareForFeature( fit );
mLabel1->adjustSizeToText();
QgsCompositionChecker checker( QString( "atlas_fixedscale_old_api%1" ).arg((( int )fit ) + 1 ), mComposition );
QVERIFY( checker.testComposition( mReport, 0 ) );
}
mAtlas->endRender();
mAtlas->setComposerMap( 0 );
mAtlas->setFixedScale( false );
}
void TestQgsAtlasComposition::two_map_autoscale_render()
{
mAtlasMap->setAtlasDriven( true );
mAtlasMap->setAtlasFixedScale( false );
mAtlasMap->setAtlasMargin( 0.10 );
mOverview->setAtlasDriven( true );
mOverview->setAtlasFixedScale( false );
mOverview->setAtlasMargin( 2.0 );
mAtlas->beginRender();
for ( int fit = 0; fit < 2; ++fit )
{
mAtlas->prepareForFeature( fit );
mLabel1->adjustSizeToText();
QgsCompositionChecker checker( QString( "atlas_two_maps%1" ).arg((( int )fit ) + 1 ), mComposition );
QVERIFY( checker.testComposition( mReport, 0, 10 ) );
}
mAtlas->endRender();
mAtlasMap->setAtlasDriven( false );
mAtlasMap->setAtlasFixedScale( false );
mAtlasMap->setAtlasMargin( 0 );
mOverview->setAtlasDriven( false );
}
void TestQgsAtlasComposition::hiding_render()
{
mAtlasMap->setNewExtent( QgsRectangle( 209838.166, 6528781.020, 610491.166, 6920530.620 ) );
mAtlas->setFixedScale( true );
mAtlasMap->setAtlasDriven( true );
mAtlasMap->setAtlasFixedScale( true );
mAtlas->setHideCoverage( true );
mAtlas->beginRender();
@ -237,7 +318,8 @@ void TestQgsAtlasComposition::hiding_render()
void TestQgsAtlasComposition::sorting_render()
{
mAtlasMap->setNewExtent( QgsRectangle( 209838.166, 6528781.020, 610491.166, 6920530.620 ) );
mAtlas->setFixedScale( true );
mAtlasMap->setAtlasDriven( true );
mAtlasMap->setAtlasFixedScale( true );
mAtlas->setHideCoverage( false );
mAtlas->setSortFeatures( true );
@ -260,7 +342,8 @@ void TestQgsAtlasComposition::sorting_render()
void TestQgsAtlasComposition::filtering_render()
{
mAtlasMap->setNewExtent( QgsRectangle( 209838.166, 6528781.020, 610491.166, 6920530.620 ) );
mAtlas->setFixedScale( true );
mAtlasMap->setAtlasDriven( true );
mAtlasMap->setAtlasFixedScale( true );
mAtlas->setHideCoverage( false );
mAtlas->setSortFeatures( false );

View File

@ -27,7 +27,7 @@ class QgsCompositionChecker(QgsRenderChecker):
self.mTestName = mTestName
super(QgsCompositionChecker, self).__init__()
def testComposition(self, page=0 ):
def testComposition(self, page=0, pixelDiff=0 ):
if ( self.mComposition == None):
myMessage = "Composition not valid"
return False, myMessage
@ -53,7 +53,7 @@ class QgsCompositionChecker(QgsRenderChecker):
outputImage.save( renderedFilePath, "PNG" )
diffFilePath = QDir.tempPath() + QDir.separator() + QFileInfo(self.mTestName).baseName() + "_result_diff.png"
testResult = self.compareImages( self.mTestName, 0, renderedFilePath )
testResult = self.compareImages( self.mTestName, pixelDiff, renderedFilePath )
myDashMessage = (('<DartMeasurementFile name="Rendered Image '
'%s" type="image/png">'

View File

@ -63,7 +63,6 @@ class TestQgsAtlasComposition(unittest.TestCase):
# the atlas
self.mAtlas = self.mComposition.atlasComposition()
self.mAtlas.setCoverageLayer( mVectorLayer )
self.mAtlas.setComposerMap( self.mAtlasMap )
self.mComposition.setAtlasMode( QgsComposition.ExportAtlas )
# an overview
@ -99,6 +98,7 @@ class TestQgsAtlasComposition(unittest.TestCase):
self.filename_test()
self.autoscale_render_test()
self.autoscale_render_test_old_api()
self.fixedscale_render_test()
self.hidden_render_test()
@ -113,6 +113,28 @@ class TestQgsAtlasComposition(unittest.TestCase):
self.mAtlas.endRender()
def autoscale_render_test( self ):
self.mAtlasMap.setAtlasDriven( True )
self.mAtlasMap.setAtlasFixedScale( False )
self.mAtlasMap.setAtlasMargin( 0.10 )
self.mAtlas.beginRender()
for i in range(0, 2):
self.mAtlas.prepareForFeature( i )
self.mLabel1.adjustSizeToText()
checker = QgsCompositionChecker('atlas_autoscale%d' % (i + 1), self.mComposition)
myTestResult, myMessage = checker.testComposition(0, 10)
assert myTestResult == True
self.mAtlas.endRender()
self.mAtlasMap.setAtlasDriven( False )
self.mAtlasMap.setAtlasFixedScale( True )
self.mAtlasMap.setAtlasMargin( 0 )
def autoscale_render_test_old_api( self ):
self.mAtlas.setComposerMap( self.mAtlasMap )
self.mAtlas.setFixedScale( False )
self.mAtlas.setMargin( 0.10 )
@ -122,15 +144,20 @@ class TestQgsAtlasComposition(unittest.TestCase):
self.mAtlas.prepareForFeature( i )
self.mLabel1.adjustSizeToText()
checker = QgsCompositionChecker('atlas_autoscale%d' % (i + 1), self.mComposition)
checker = QgsCompositionChecker('atlas_autoscale_old_api%d' % (i + 1), self.mComposition)
myTestResult, myMessage = checker.testComposition()
assert myTestResult == True
self.mAtlas.endRender()
def fixedscale_render_test( self ):
self.mAtlasMap.setNewExtent( QgsRectangle( 209838.166, 6528781.020, 610491.166, 6920530.620 ) );
self.mAtlas.setFixedScale( True )
self.mAtlas.setMargin( 0 )
self.mAtlas.setComposerMap( None )
def fixedscale_render_test( self ):
self.mAtlasMap.setAtlasDriven( True )
self.mAtlasMap.setAtlasFixedScale( True )
self.mAtlasMap.setNewExtent( QgsRectangle( 209838.166, 6528781.020, 610491.166, 6920530.620 ) );
self.mAtlas.beginRender()
@ -146,7 +173,7 @@ class TestQgsAtlasComposition(unittest.TestCase):
def hidden_render_test( self ):
self.mAtlasMap.setNewExtent( QgsRectangle( 209838.166, 6528781.020, 610491.166, 6920530.620 ) );
self.mAtlas.setFixedScale( True )
self.mAtlasMap.setAtlasFixedScale( True )
self.mAtlas.setHideCoverage( True )
self.mAtlas.beginRender()
@ -163,7 +190,7 @@ class TestQgsAtlasComposition(unittest.TestCase):
def sorting_render_test( self ):
self.mAtlasMap.setNewExtent( QgsRectangle( 209838.166, 6528781.020, 610491.166, 6920530.620 ) );
self.mAtlas.setFixedScale( True )
self.mAtlasMap.setAtlasFixedScale( True )
self.mAtlas.setHideCoverage( False )
self.mAtlas.setSortFeatures( True )
@ -184,7 +211,7 @@ class TestQgsAtlasComposition(unittest.TestCase):
def filtering_render_test( self ):
self.mAtlasMap.setNewExtent( QgsRectangle( 209838.166, 6528781.020, 610491.166, 6920530.620 ) );
self.mAtlas.setFixedScale( True )
self.mAtlasMap.setAtlasFixedScale( True )
self.mAtlas.setHideCoverage( False )
self.mAtlas.setSortFeatures( False )

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB