18 #include <QtAlgorithms> 32 mComposition( composition ),
34 mHideCoverage( false ), mFilenamePattern(
"'output_'||$feature" ),
35 mCoverageLayer( 0 ), mSingleFile( false ),
36 mSortFeatures( false ), mSortAscending( true ), mCurrentFeatureNo( 0 ),
37 mFilterFeatures( false ), mFeatureFilter(
"" ),
38 mFilenameParserError( QString() ),
39 mFilterParserError( QString() )
61 if ( enabled == mEnabled )
72 void QgsAtlasComposition::removeLayers( QStringList layers )
74 if ( !mCoverageLayer )
79 foreach ( QString layerId, layers )
81 if ( layerId == mCoverageLayer->
id() )
93 if ( layer == mCoverageLayer )
98 mCoverageLayer = layer;
121 QList<QgsComposerMap*> maps;
123 for ( QList<QgsComposerMap*>::iterator mit = maps.begin(); mit != maps.end(); ++mit )
150 if ( !mCoverageLayer )
159 if ( mCoverageLayer )
162 if ( idx >= 0 && idx < fields.
count() )
164 mSortKeyAttributeName = fields[idx].name();
168 mSortKeyAttributeName =
"";
182 if ( mKeys[ id1 ].type() == QVariant::Int )
184 result = mKeys[ id1 ].toInt() < mKeys[ id2 ].toInt();
186 else if ( mKeys[ id1 ].type() == QVariant::Double )
188 result = mKeys[ id1 ].toDouble() < mKeys[ id2 ].toDouble();
190 else if ( mKeys[ id1 ].type() == QVariant::String )
192 result = ( QString::localeAwareCompare( mKeys[ id1 ].toString(), mKeys[ id2 ].toString() ) < 0 );
195 return mAscending ? result : !result;
206 if ( !mCoverageLayer )
211 updateFilenameExpression();
216 QScopedPointer<QgsExpression> filterExpression;
217 if ( mFilterFeatures && !mFeatureFilter.isEmpty() )
219 filterExpression.reset(
new QgsExpression( mFeatureFilter ) );
220 if ( filterExpression->hasParserError() )
222 mFilterParserError = filterExpression->parserErrorString();
226 mFilterParserError = QString();
232 mFeatureKeys.clear();
233 int sortIdx = mCoverageLayer->
fieldNameIndex( mSortKeyAttributeName );
236 if ( !filterExpression.isNull() )
238 QVariant result = filterExpression->evaluate( &feat, mCoverageLayer->pendingFields() );
239 if ( filterExpression->hasEvalError() )
245 if ( !result.toBool() )
250 mFeatureIds.push_back( feat.
id() );
252 if ( mSortFeatures && sortIdx != -1 )
254 mFeatureKeys.insert( feat.
id(), feat.
attributes()[ sortIdx ] );
259 if ( mFeatureKeys.count() )
261 FieldSorter sorter( mFeatureKeys, mSortAscending );
262 qSort( mFeatureIds.begin(), mFeatureIds.end(), sorter );
274 return mFeatureIds.size();
280 if ( !mCoverageLayer )
288 if ( !featuresUpdated )
303 if ( !mCoverageLayer )
315 void QgsAtlasComposition::updateAtlasMaps()
318 QList<QgsComposerMap*> maps;
319 mComposition->composerItems( maps );
320 for ( QList<QgsComposerMap*>::iterator mit = maps.begin(); mit != maps.end(); ++mit )
334 return mFeatureIds.size();
339 int newFeatureNo = mCurrentFeatureNo + 1;
340 if ( newFeatureNo >= mFeatureIds.size() )
342 newFeatureNo = mFeatureIds.size() - 1;
350 int newFeatureNo = mCurrentFeatureNo - 1;
351 if ( newFeatureNo < 0 )
371 int featureI = mFeatureIds.indexOf( feat->
id() );
388 if ( !mCoverageLayer )
393 if ( mFeatureIds.size() == 0 )
399 mCurrentFeatureNo = featureI;
402 mCoverageLayer->getFeatures(
QgsFeatureRequest().setFilterFid( mFeatureIds[ featureI ] ) ).nextFeature( mCurrentFeature );
410 if ( !evalFeatureFilename() )
417 emit
statusMsgChanged( QString(
tr(
"Atlas feature %1 of %2" ) ).arg( featureI + 1 ).arg( mFeatureIds.size() ) );
419 if ( !mCurrentFeature.isValid() )
434 QList<QgsComposerMap*> maps;
435 QList<QgsComposerMap*> atlasMaps;
436 mComposition->composerItems( maps );
437 if ( maps.isEmpty() )
441 for ( QList<QgsComposerMap*>::iterator mit = maps.begin(); mit != maps.end(); ++mit )
448 atlasMaps << currentMap;
451 if ( atlasMaps.count() > 0 )
459 computeExtent( atlasMaps[0] );
462 for ( QList<QgsComposerMap*>::iterator mit = maps.begin(); mit != maps.end(); ++mit )
464 if (( *mit )->atlasDriven() )
487 mTransform.setSourceCrs( coverage_crs );
488 mTransform.setDestCRS( destination_crs );
495 mTransformedFeatureBounds = tgeom.boundingBox();
505 if ( mTransformedFeatureBounds.isEmpty() )
509 computeExtent( map );
512 double xa1 = mTransformedFeatureBounds.xMinimum();
513 double xa2 = mTransformedFeatureBounds.xMaximum();
514 double ya1 = mTransformedFeatureBounds.yMinimum();
515 double ya2 = mTransformedFeatureBounds.yMaximum();
520 bool isPointLayer =
false;
521 switch ( mCoverageLayer->wkbType() )
530 isPointLayer =
false;
539 double originalScale = calc.
calculate( mOrigExtent, map->rect().width() );
540 double geomCenterX = ( xa1 + xa2 ) / 2.0;
541 double geomCenterY = ( ya1 + ya2 ) / 2.0;
546 double xMin = geomCenterX - mOrigExtent.width() / 2.0;
547 double yMin = geomCenterY - mOrigExtent.height() / 2.0;
550 xMin + mOrigExtent.width(),
551 yMin + mOrigExtent.height() );
555 double newScale = calc.
calculate( newExtent, map->rect().width() );
556 newExtent.
scale( originalScale / newScale );
561 double newWidth = mOrigExtent.width();
562 double newHeight = mOrigExtent.height();
563 const QVector<qreal>& scales = mPredefinedScales;
564 for (
int i = 0; i < scales.size(); i++ )
566 double ratio = scales[i] / originalScale;
567 newWidth = mOrigExtent.width() * ratio;
568 newHeight = mOrigExtent.height() * ratio;
571 double xMin = geomCenterX - newWidth / 2.0;
572 double yMin = geomCenterY - newHeight / 2.0;
580 double newScale = calc.
calculate( newExtent, map->rect().width() );
581 newExtent.
scale( scales[i] / newScale );
583 if (( newExtent.
width() >= mTransformedFeatureBounds.width() ) && ( newExtent.
height() >= mTransformedFeatureBounds.height() ) )
595 double geomRatio = mTransformedFeatureBounds.width() / mTransformedFeatureBounds.height();
596 double mapRatio = mOrigExtent.width() / mOrigExtent.height();
599 if ( geomRatio < mapRatio )
602 double adjWidth = ( mapRatio * mTransformedFeatureBounds.height() - mTransformedFeatureBounds.width() ) / 2.0;
607 else if ( geomRatio > mapRatio )
610 double adjHeight = ( mTransformedFeatureBounds.width() / mapRatio - mTransformedFeatureBounds.height() ) / 2.0;
628 return mCurrentFilename;
633 QDomElement atlasElem = doc.createElement(
"Atlas" );
634 atlasElem.setAttribute(
"enabled", mEnabled ?
"true" :
"false" );
640 if ( mCoverageLayer )
642 atlasElem.setAttribute(
"coverageLayer", mCoverageLayer->id() );
646 atlasElem.setAttribute(
"coverageLayer",
"" );
649 atlasElem.setAttribute(
"hideCoverage", mHideCoverage ?
"true" :
"false" );
650 atlasElem.setAttribute(
"singleFile", mSingleFile ?
"true" :
"false" );
651 atlasElem.setAttribute(
"filenamePattern", mFilenamePattern );
653 atlasElem.setAttribute(
"sortFeatures", mSortFeatures ?
"true" :
"false" );
656 atlasElem.setAttribute(
"sortKey", mSortKeyAttributeName );
657 atlasElem.setAttribute(
"sortAscending", mSortAscending ?
"true" :
"false" );
659 atlasElem.setAttribute(
"filterFeatures", mFilterFeatures ?
"true" :
"false" );
660 if ( mFilterFeatures )
662 atlasElem.setAttribute(
"featureFilter", mFeatureFilter );
665 elem.appendChild( atlasElem );
670 mEnabled = atlasElem.attribute(
"enabled",
"false" ) ==
"true" ?
true :
false;
681 for ( QMap<QString, QgsMapLayer*>::const_iterator it = layers.begin(); it != layers.end(); ++it )
683 if ( it.key() == atlasElem.attribute(
"coverageLayer" ) )
690 mSingleFile = atlasElem.attribute(
"singleFile",
"false" ) ==
"true" ?
true :
false;
691 mFilenamePattern = atlasElem.attribute(
"filenamePattern",
"" );
693 mSortFeatures = atlasElem.attribute(
"sortFeatures",
"false" ) ==
"true" ?
true :
false;
696 mSortKeyAttributeName = atlasElem.attribute(
"sortKey",
"" );
701 int idx = mSortKeyAttributeName.toInt( &isIndex );
702 if ( isIndex && mCoverageLayer )
704 const QgsFields fields = mCoverageLayer->pendingFields();
705 if ( idx >= 0 && idx < fields.
count() )
707 mSortKeyAttributeName = fields[idx].name();
710 mSortAscending = atlasElem.attribute(
"sortAscending",
"true" ) ==
"true" ?
true :
false;
712 mFilterFeatures = atlasElem.attribute(
"filterFeatures",
"false" ) ==
"true" ?
true :
false;
713 if ( mFilterFeatures )
715 mFeatureFilter = atlasElem.attribute(
"featureFilter",
"" );
718 mHideCoverage = atlasElem.attribute(
"hideCoverage",
"false" ) ==
"true" ?
true :
false;
727 int composerMapNo = elem.attribute(
"composerMap",
"-1" ).toInt();
729 if ( composerMapNo != -1 )
731 QList<QgsComposerMap*> maps;
732 mComposition->composerItems( maps );
733 for ( QList<QgsComposerMap*>::iterator it = maps.begin(); it != maps.end(); ++it )
735 if (( *it )->id() == composerMapNo )
737 composerMap = ( *it );
745 double margin = elem.attribute(
"margin",
"0.0" ).toDouble();
746 if ( composerMap && margin != 0 )
750 bool fixedScale = elem.attribute(
"fixedScale",
"false" ) ==
"true" ?
true :
false;
751 if ( composerMap && fixedScale )
759 mHideCoverage = hide;
765 mComposition->update();
772 mFilenamePattern = pattern;
773 return updateFilenameExpression();
776 bool QgsAtlasComposition::updateFilenameExpression()
778 if ( !mCoverageLayer )
783 const QgsFields& fields = mCoverageLayer->pendingFields();
785 if ( mFilenamePattern.size() > 0 )
787 mFilenameExpr.reset(
new QgsExpression( mFilenamePattern ) );
790 if ( mFilenameExpr->hasParserError() )
792 mFilenameParserError = mFilenameExpr->parserErrorString();
797 mFilenameExpr->prepare( fields );
803 evalFeatureFilename();
808 bool QgsAtlasComposition::evalFeatureFilename()
811 if ( mFilenamePattern.size() > 0 && !mFilenameExpr.isNull() )
813 QVariant filenameRes = mFilenameExpr->evaluate( &mCurrentFeature, mCoverageLayer->pendingFields() );
814 if ( mFilenameExpr->hasEvalError() )
820 mCurrentFilename = filenameRes.toString();
827 mPredefinedScales = scales;
829 qSort( mPredefinedScales.begin(), mPredefinedScales.end() );
bool prepareForFeature(const int i, const bool updateMaps=true)
Prepare the atlas map for the given feature.
QgsFeatureId id() const
Get the feature id for this feature.
Class for parsing and evaluation of expressions (formerly called "search strings").
void setMapUnits(QGis::UnitType mapUnits)
Set the map units.
QMap< QgsFeatureId, QVariant > SorterKeys
Wrapper for iterator of features from vector data provider or vector layer.
A rectangle specified with double values.
void renderEnded()
Is emitted when atlas rendering has ended.
double atlasMargin(const QgsComposerObject::PropertyValueType valueType=QgsComposerObject::EvaluatedValue)
Returns the margin size (percentage) used when the map is in atlas mode.
Q_DECL_DEPRECATED int sortKeyAttributeIndex() const
int fieldNameIndex(const QString &fieldName) const
Utility method to get attribute index from name.
void setNewAtlasFeatureExtent(const QgsRectangle &extent)
Sets new Extent for the current atlas preview and changes width, height (and implicitely also scale)...
QgsAtlasComposition(QgsComposition *composition)
Q_DECL_DEPRECATED bool fixedScale() const
Returns whether the atlas map uses a fixed scale.
const QgsMapSettings & mapSettings() const
Return setting of QGIS map canvas.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())
Query the provider for features specified in request.
QgsGeometry * geometry() const
Get the geometry object associated with this feature.
void cache()
Create cache image.
static QgsMapLayerRegistry * instance()
#define Q_NOWARN_DEPRECATED_PUSH
void setDpi(double dpi)
Set the dpi to be used in scale calculations.
QgsComposition * composition()
bool enabled() const
Returns whether the atlas generation is enabled.
Container of fields for a vector layer.
void toggled(bool)
emitted when atlas is enabled or disabled
void setHideCoverage(bool hide)
Sets whether the coverage layer should be hidden in map items in the composition. ...
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
void endRender()
Ends the rendering.
static void logMessage(QString message, QString tag=QString::null, MessageLevel level=WARNING)
add a message to the instance (and create it if necessary)
void readXML(const QDomElement &elem, const QDomDocument &doc)
Reads general atlas settings from xml.
Q_DECL_DEPRECATED void setFixedScale(bool fixed)
Sets whether the atlas map should use a fixed scale.
Q_DECL_DEPRECATED float margin() const
Returns the margin for the atlas map.
void setAtlasMargin(double margin)
Sets the margin size (percentage) used when the map is in atlas mode.
bool setFilenamePattern(const QString &pattern)
Sets the filename expression used for generating output filenames for each atlas page.
Q_DECL_DEPRECATED void setSortKeyAttributeIndex(int idx)
void setCoverageLayer(QgsVectorLayer *layer)
Sets the coverage layer to use for the atlas features.
void setAtlasScalingMode(AtlasScalingMode mode)
Sets the current atlas scaling mode.
bool beginRender()
Begins the rendering.
Q_DECL_DEPRECATED void setComposerMap(QgsComposerMap *map)
Sets the map used by the atlas.
double calculate(const QgsRectangle &mapExtent, int canvasWidth)
Calculate the scale denominator.
void prepareMap(QgsComposerMap *map)
Recalculates the bounds of an atlas driven map.
void statusMsgChanged(QString message)
Is emitted when the atlas has an updated status bar message for the composer window.
void refreshFeature()
Refreshes the current atlas feature, by refetching its attributes from the vector layer provider...
const QgsComposition * composition() const
Returns the composition the item is attached to.
const QgsCoordinateReferenceSystem & destinationCrs() const
returns CRS of destination coordinate reference system
This class wraps a request for features to a vector layer (or directly its vector data provider)...
int numFeatures() const
Returns the number of features in the coverage layer.
const QgsAttributes & attributes() const
QString id() const
Get this layer's unique ID, this ID is used to access this layer from map layer registry.
int count() const
Return number of items.
Q_DECL_DEPRECATED bool atlasFixedScale() const
Returns true if the map uses a fixed scale when in atlas mode.
void setEnabled(bool enabled)
Sets whether the atlas is enabled.
int updateFeatures()
Requeries the current atlas coverage layer and applies filtering and sorting.
void writeXML(QDomElement &elem, QDomDocument &doc) const
Graphics scene for map printing.
Object representing map window.
void featureChanged(QgsFeature *feature)
Is emitted when the current atlas feature changes.
void coverageLayerChanged(QgsVectorLayer *layer)
Is emitted when the coverage layer for an atlas changes.
Calculates scale for a given combination of canvas size, map extent, and monitor dpi.
bool setAtlasMode(const QgsComposition::AtlasMode mode)
Sets the current atlas mode of the composition.
bool operator()(const QgsFeatureId &id1, const QgsFeatureId &id2)
#define Q_NOWARN_DEPRECATED_POP
void renderBegun()
Is emitted when atlas rendering has begun.
QgsRectangle extent() const
FieldSorter(QgsAtlasComposition::SorterKeys &keys, bool ascending=true)
Q_DECL_DEPRECATED QgsComposerMap * composerMap() const
Returns the map used by the atlas.
void readXMLMapSettings(const QDomElement &elem, const QDomDocument &doc)
Reads old (pre 2.2) map related atlas settings from xml.
Q_DECL_DEPRECATED void setMargin(float margin)
Sets the margin for the atlas map.
AtlasScalingMode atlasScalingMode() const
Returns the current atlas scaling mode.
Class for storing a coordinate reference system (CRS)
const QMap< QString, QgsMapLayer * > & mapLayers()
Retrieve the mapLayers collection (mainly intended for use by projection)
void parameterChanged()
emitted when one of the parameters changes
int transform(const QgsCoordinateTransform &ct)
Transform this geometry as described by CoordinateTransform ct.
const QString & currentFilename() const
Returns the current filename.
bool atlasDriven() const
Returns whether the map extent is set to follow the current atlas feature.
const QgsFields & pendingFields() const
returns field list in the to-be-committed state
static void setSpecialColumn(const QString &name, QVariant value)
Assign a special column.
void setAtlasDriven(bool enabled)
Sets whether the map extent will follow the current atlas feature.
bool nextFeature(QgsFeature &f)
void composerItems(QList< T * > &itemList)
Return composer items of a specific type.
double width() const
Width of the rectangle.
Represents a vector layer which manages a vector based data sets.
int fieldNameIndex(const QString &fieldName) const
Returns the index of a field name or -1 if the field does not exist.
void setPredefinedScales(const QVector< qreal > &scales)
Sets the list of predefined scales for the atlas.
double height() const
Height of the rectangle.
void scale(double scaleFactor, const QgsPoint *c=0)
Scale the rectangle around its center point.