void QgsAtlasComposition::computeExtent( QgsComposerMap* map ) { // compute the extent of the current feature, in the crs of the specified map const QgsCoordinateReferenceSystem& coverage_crs = mCoverageLayer->crs(); // transformation needed for feature geometries const QgsCoordinateReferenceSystem& destination_crs = map->composition()->mapSettings().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(); }
void QgsAtlasComposition::prepareForFeature( int featureI ) { if ( !mComposerMap || !mCoverageLayer ) { return; } if ( mFeatureIds.size() == 0 ) { emit statusMsgChanged( tr( "No matching atlas features" ) ); return; } // retrieve the next feature, based on its id mCoverageLayer->getFeatures( QgsFeatureRequest().setFilterFid( mFeatureIds[ featureI ] ) ).nextFeature( mCurrentFeature ); QgsExpression::setSpecialColumn( "$atlasfeatureid", mCurrentFeature.id() ); QgsExpression::setSpecialColumn( "$atlasgeometry", QVariant::fromValue( *mCurrentFeature.geometry() ) ); QgsExpression::setSpecialColumn( "$feature", QVariant(( int )featureI + 1 ) ); // 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 ); for ( QList<QgsComposerLabel*>::iterator lit = labels.begin(); lit != labels.end(); ++lit ) { ( *lit )->setExpressionContext( &mCurrentFeature, mCoverageLayer ); } // 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() ) ); }
void QgsAtlasComposition::prepareForFeature( size_t featureI ) { if ( !mComposerMap || !mCoverageLayer ) { return; } // retrieve the next feature, based on its id mCoverageLayer->getFeatures( QgsFeatureRequest().setFilterFid( mFeatureIds[ featureI ] ) ).nextFeature( mCurrentFeature ); if ( !mSingleFile && mFilenamePattern.size() > 0 ) { QgsExpression::setSpecialColumn( "$feature", QVariant(( int )featureI + 1 ) ); QVariant filenameRes = mFilenameExpr->evaluate( &mCurrentFeature ); if ( mFilenameExpr->hasEvalError() ) { throw std::runtime_error( tr( "Filename eval error: %1" ).arg( mFilenameExpr->evalErrorString() ).toLocal8Bit().data() ); } mCurrentFilename = filenameRes.toString(); } // // 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; // restore the original extent // (successive calls to setNewExtent tend to deform the original rectangle) mComposerMap->setNewExtent( mOrigExtent ); 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 ); QgsExpression::setSpecialColumn( "$feature", QVariant(( int )featureI + 1 ) ); for ( QList<QgsComposerLabel*>::iterator lit = labels.begin(); lit != labels.end(); ++lit ) { ( *lit )->setExpressionContext( &mCurrentFeature, mCoverageLayer ); } // set the new extent (and render) mComposerMap->setNewExtent( new_extent ); }
void QgsAtlasComposition::prepareForFeature( int featureI ) { if ( !mCoverageLayer ) { return; } if ( mFeatureIds.size() == 0 ) { emit statusMsgChanged( tr( "No matching atlas features" ) ); return; } // retrieve the next feature, based on its id mCoverageLayer->getFeatures( QgsFeatureRequest().setFilterFid( mFeatureIds[ featureI ] ) ).nextFeature( mCurrentFeature ); QgsExpression::setSpecialColumn( "$atlasfeatureid", mCurrentFeature.id() ); QgsExpression::setSpecialColumn( "$atlasgeometry", QVariant::fromValue( *mCurrentFeature.geometry() ) ); QgsExpression::setSpecialColumn( "$feature", QVariant(( int )featureI + 1 ) ); // generate filename for current feature evalFeatureFilename(); // evaluate label expressions QList<QgsComposerLabel*> labels; mComposition->composerItems( labels ); for ( QList<QgsComposerLabel*>::iterator lit = labels.begin(); lit != labels.end(); ++lit ) { ( *lit )->setExpressionContext( &mCurrentFeature, mCoverageLayer ); } // update shapes (in case they use data defined symbology with atlas properties) QList<QgsComposerShape*> shapes; mComposition->composerItems( shapes ); for ( QList<QgsComposerShape*>::iterator lit = shapes.begin(); lit != shapes.end(); ++lit ) { ( *lit )->update(); } // update page background (in case it uses data defined symbology with atlas properties) QList<QgsPaperItem*> pages; mComposition->composerItems( pages ); for ( QList<QgsPaperItem*>::iterator pageIt = pages.begin(); pageIt != pages.end(); ++pageIt ) { ( *pageIt )->update(); } 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 ); } }