Ejemplo n.º 1
0
void QgsAtlasComposition::updateFilenameExpression()
{
  const QgsFields& fields = mCoverageLayer->pendingFields();

  if ( !mSingleFile && mFilenamePattern.size() > 0 )
  {
    mFilenameExpr = std::auto_ptr<QgsExpression>( new QgsExpression( mFilenamePattern ) );
    // expression used to evaluate each filename
    // test for evaluation errors
    if ( mFilenameExpr->hasParserError() )
    {
      throw std::runtime_error( tr( "Filename parsing error: %1" ).arg( mFilenameExpr->parserErrorString() ).toLocal8Bit().data() );
    }

    // prepare the filename expression
    mFilenameExpr->prepare( fields );
  }

  //if atlas preview is currently enabled, regenerate filename for current feature
  if ( mComposition->atlasMode() == QgsComposition::PreviewAtlas )
  {
    evalFeatureFilename();
  }

}
Ejemplo n.º 2
0
bool QgsAtlasComposition::updateFilenameExpression()
{
  if ( !mCoverageLayer )
  {
    return false;
  }

  QgsExpressionContext expressionContext = createExpressionContext();

  if ( !mFilenamePattern.isEmpty() )
  {
    mFilenameExpr.reset( new QgsExpression( mFilenamePattern ) );
    // expression used to evaluate each filename
    // test for evaluation errors
    if ( mFilenameExpr->hasParserError() )
    {
      mFilenameParserError = mFilenameExpr->parserErrorString();
      return false;
    }

    // prepare the filename expression
    mFilenameExpr->prepare( &expressionContext );
  }

  //if atlas preview is currently enabled, regenerate filename for current feature
  if ( mComposition->atlasMode() == QgsComposition::PreviewAtlas )
  {
    evalFeatureFilename( expressionContext );
  }
  return true;
}
Ejemplo n.º 3
0
bool QgsLayoutAtlas::updateFilenameExpression( QString &error )
{
  if ( !mCoverageLayer )
  {
    return false;
  }

  QgsExpressionContext expressionContext = createExpressionContext();

  if ( !mFilenameExpressionString.isEmpty() )
  {
    mFilenameExpression = QgsExpression( mFilenameExpressionString );
    // expression used to evaluate each filename
    // test for evaluation errors
    if ( mFilenameExpression.hasParserError() )
    {
      error = mFilenameExpression.parserErrorString();
      return false;
    }

    // prepare the filename expression
    mFilenameExpression.prepare( &expressionContext );
  }

  // regenerate current filename
  evalFeatureFilename( expressionContext );
  return true;
}
Ejemplo n.º 4
0
bool QgsAtlasComposition::updateFilenameExpression()
{
  if ( !mCoverageLayer )
  {
    return false;
  }

  const QgsFields& fields = mCoverageLayer->pendingFields();

  if ( mFilenamePattern.size() > 0 )
  {
    mFilenameExpr = std::auto_ptr<QgsExpression>( new QgsExpression( mFilenamePattern ) );
    // expression used to evaluate each filename
    // test for evaluation errors
    if ( mFilenameExpr->hasParserError() )
    {
      mFilenameParserError = mFilenameExpr->parserErrorString();
      return false;
    }

    // prepare the filename expression
    mFilenameExpr->prepare( fields );
  }

  //if atlas preview is currently enabled, regenerate filename for current feature
  if ( mComposition->atlasMode() == QgsComposition::PreviewAtlas )
  {
    evalFeatureFilename();
  }
  return true;
}
Ejemplo n.º 5
0
bool QgsLayoutAtlas::prepareForFeature( const int featureI )
{
  if ( !mCoverageLayer )
  {
    return false;
  }

  if ( mFeatureIds.isEmpty() )
  {
    emit messagePushed( tr( "No matching atlas features" ) );
    return false;
  }

  if ( featureI >= mFeatureIds.size() )
  {
    return false;
  }

  mCurrentFeatureNo = featureI;

  // retrieve the next feature, based on its id
  if ( !mCoverageLayer->getFeatures( QgsFeatureRequest().setFilterFid( mFeatureIds[ featureI ].first ) ).nextFeature( mCurrentFeature ) )
    return false;

  mLayout->reportContext().blockSignals( true ); // setFeature emits changed, we don't want 2 signals
  mLayout->reportContext().setLayer( mCoverageLayer.get() );
  mLayout->reportContext().blockSignals( false );
  mLayout->reportContext().setFeature( mCurrentFeature );

  // must come after we've set the report context feature, or the expression context will have an outdated atlas feature
  QgsExpressionContext expressionContext = createExpressionContext();

  // generate filename for current feature
  if ( !evalFeatureFilename( expressionContext ) )
  {
    //error evaluating filename
    return false;
  }

  emit featureChanged( mCurrentFeature );
  emit messagePushed( QString( tr( "Atlas feature %1 of %2" ) ).arg( featureI + 1 ).arg( mFeatureIds.size() ) );

  return mCurrentFeature.isValid();
}
Ejemplo n.º 6
0
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;
  }

  //clear the transformed bounds of the previous feature
  mTransformedFeatureBounds = QgsRectangle();

  if ( atlasMaps.isEmpty() )
  {
    //no atlas enabled maps
    return;
  }

  // compute extent of current feature in the map CRS. 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.
  computeExtent( atlasMaps[0] );

  //update atlas bounds of every atlas enabled composer map
  for ( QList<QgsComposerMap*>::iterator mit = atlasMaps.begin(); mit != atlasMaps.end(); ++mit )
  {
    prepareMap( *mit );
  }
}
Ejemplo n.º 7
0
bool QgsAtlasComposition::prepareForFeature( const int featureI, const bool updateMaps )
{
  if ( !mCoverageLayer )
  {
    return false;
  }

  if ( mFeatureIds.isEmpty() )
  {
    emit statusMsgChanged( tr( "No matching atlas features" ) );
    return false;
  }

  if ( featureI >= mFeatureIds.size() )
  {
    return false;
  }

  mCurrentFeatureNo = featureI;

  // retrieve the next feature, based on its id
  mCoverageLayer->getFeatures( QgsFeatureRequest().setFilterFid( mFeatureIds[ featureI ].first ) ).nextFeature( mCurrentFeature );

  QgsExpressionContext expressionContext = createExpressionContext();

  // generate filename for current feature
  if ( !evalFeatureFilename( expressionContext ) )
  {
    //error evaluating filename
    return false;
  }

  mGeometryCache.clear();
  emit featureChanged( &mCurrentFeature );
  emit statusMsgChanged( QString( tr( "Atlas feature %1 of %2" ) ).arg( featureI + 1 ).arg( mFeatureIds.size() ) );

  if ( !mCurrentFeature.isValid() )
  {
    //bad feature
    return true;
  }

  if ( !updateMaps )
  {
    //nothing more to do
    return true;
  }

  //update composer maps

  //build a list of atlas-enabled composer maps
  QList<QgsComposerMap*> maps;
  QList<QgsComposerMap*> atlasMaps;
  mComposition->composerItems( maps );
  if ( maps.isEmpty() )
  {
    return true;
  }
  for ( QList<QgsComposerMap*>::iterator mit = maps.begin(); mit != maps.end(); ++mit )
  {
    QgsComposerMap* currentMap = ( *mit );
    if ( !currentMap->atlasDriven() )
    {
      continue;
    }
    atlasMaps << currentMap;
  }

  if ( !atlasMaps.isEmpty() )
  {
    //clear the transformed bounds of the previous feature
    mTransformedFeatureBounds = QgsRectangle();

    // compute extent of current feature in the map CRS. 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.
    computeExtent( atlasMaps[0] );
  }

  for ( QList<QgsComposerMap*>::iterator mit = maps.begin(); mit != maps.end(); ++mit )
  {
    if (( *mit )->atlasDriven() )
    {
      // map is atlas driven, so update it's bounds (causes a redraw)
      prepareMap( *mit );
    }
    else
    {
      // map is not atlas driven, so manually force a redraw (to reflect possibly atlas
      // dependent symbology)
      ( *mit )->cache();
    }
  }

  return true;
}
Ejemplo n.º 8
0
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() ) );
}
Ejemplo n.º 9
0
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 );
  }
}
Ejemplo n.º 10
0
bool QgsAtlasComposition::prepareForFeature( int featureI )
{
  if ( !mCoverageLayer )
  {
    return false;
  }

  if ( mFeatureIds.size() == 0 )
  {
    emit statusMsgChanged( tr( "No matching atlas features" ) );
    return false;
  }

  mCurrentFeatureNo = featureI;

  // 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( "$atlasfeature", QVariant::fromValue( mCurrentFeature ) );
  QgsExpression::setSpecialColumn( "$feature", QVariant(( int )featureI + 1 ) );

  // generate filename for current feature
  if ( !evalFeatureFilename() )
  {
    //error evaluating filename
    return false;
  }

  emit featureChanged( &mCurrentFeature );
  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;
  }

  //clear the transformed bounds of the previous feature
  mTransformedFeatureBounds = QgsRectangle();

  if ( atlasMaps.isEmpty() )
  {
    //no atlas enabled maps
    return true;
  }

  // compute extent of current feature in the map CRS. 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.
  computeExtent( atlasMaps[0] );

  //update atlas bounds of every atlas enabled composer map
  for ( QList<QgsComposerMap*>::iterator mit = atlasMaps.begin(); mit != atlasMaps.end(); ++mit )
  {
    prepareMap( *mit );
  }

  return true;
}