Skip to content

Commit

Permalink
Restore atlas map handling
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Jan 5, 2018
1 parent 3ffdda3 commit 69ddc32
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 47 deletions.
3 changes: 3 additions & 0 deletions python/core/layout/qgslayoutitemmap.sip
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,9 @@ associated legend items know they should update

public slots:

virtual void refresh();


virtual void invalidateCache();


Expand Down
49 changes: 12 additions & 37 deletions src/app/layout/qgslayoutmapwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "qgslayoutmapgridwidget.h"
#include "qgsstyle.h"
#include "qgslayoutundostack.h"
#include "qgslayoutatlas.h"
#include <QMenu>
#include <QMessageBox>

Expand Down Expand Up @@ -111,17 +112,14 @@ QgsLayoutMapWidget::QgsLayoutMapWidget( QgsLayoutItemMap *item )

connect( item, &QgsLayoutObject::changed, this, &QgsLayoutMapWidget::updateGuiElements );

#if 0 //TODO
QgsAtlasComposition *atlas = atlasComposition();
if ( atlas )
connect( &item->layout()->context(), &QgsLayoutContext::layerChanged,
this, &QgsLayoutMapWidget::atlasLayerChanged );
if ( QgsLayoutAtlas *atlas = layoutAtlas() )
{
connect( atlas, &QgsAtlasComposition::coverageLayerChanged,
this, &QgsLayoutMapWidget::atlasLayerChanged );
connect( atlas, &QgsAtlasComposition::toggled, this, &QgsLayoutMapWidget::compositionAtlasToggled );

connect( atlas, &QgsLayoutAtlas::toggled, this, &QgsLayoutMapWidget::compositionAtlasToggled );
compositionAtlasToggled( atlas->enabled() );
}
#endif

mOverviewFrameMapComboBox->setCurrentLayout( item->layout() );
mOverviewFrameMapComboBox->setItemType( QgsLayoutItemRegistry::LayoutMap );
mOverviewFrameStyleButton->registerExpressionContextGenerator( item );
Expand Down Expand Up @@ -196,11 +194,9 @@ void QgsLayoutMapWidget::populateDataDefinedButtons()

void QgsLayoutMapWidget::compositionAtlasToggled( bool atlasEnabled )
{
Q_UNUSED( atlasEnabled );
#if 0 //TODO
if ( atlasEnabled &&
mMapItem && mMapItem->composition() && mMapItem->composition()->atlasComposition().coverageLayer()
&& mMapItem->composition()->atlasComposition().coverageLayer()->wkbType() != QgsWkbTypes::NoGeometry )
mMapItem && mMapItem->layout() && mMapItem->layout()->context().layer()
&& mMapItem->layout()->context().layer()->wkbType() != QgsWkbTypes::NoGeometry )
{
mAtlasCheckBox->setEnabled( true );
}
Expand All @@ -209,7 +205,6 @@ void QgsLayoutMapWidget::compositionAtlasToggled( bool atlasEnabled )
mAtlasCheckBox->setEnabled( false );
mAtlasCheckBox->setChecked( false );
}
#endif
}

void QgsLayoutMapWidget::aboutToShowKeepLayersVisibilityPresetsMenu()
Expand Down Expand Up @@ -387,31 +382,16 @@ void QgsLayoutMapWidget::mAtlasCheckBox_toggled( bool checked )

void QgsLayoutMapWidget::updateMapForAtlas()
{
#if 0 //TODO
//update map if in atlas preview mode
QgsComposition *composition = mMapItem->composition();
if ( !composition )
{
return;
}
if ( composition->atlasMode() == QgsComposition::AtlasOff )
{
return;
}

if ( mMapItem->atlasDriven() )
{
//update atlas based extent for map
QgsAtlasComposition *atlas = &composition->atlasComposition();
//prepareMap causes a redraw
atlas->prepareMap( mMapItem );
mMapItem->refresh();
}
else
{
//redraw map
mMapItem->invalidateCache();
}
#endif
}

void QgsLayoutMapWidget::mAtlasMarginRadio_toggled( bool checked )
Expand Down Expand Up @@ -708,15 +688,14 @@ void QgsLayoutMapWidget::toggleAtlasScalingOptionsByLayerType()
return;
}

#if 0 //TODO
//get atlas coverage layer
QgsVectorLayer *coverageLayer = atlasCoverageLayer();
if ( !coverageLayer )
QgsVectorLayer *layer = coverageLayer();
if ( !layer )
{
return;
}

switch ( coverageLayer->wkbType() )
switch ( layer->wkbType() )
{
case QgsWkbTypes::Point:
case QgsWkbTypes::Point25D:
Expand All @@ -732,7 +711,6 @@ void QgsLayoutMapWidget::toggleAtlasScalingOptionsByLayerType()
mAtlasMarginRadio->setEnabled( true );
mAtlasPredefinedScaleRadio->setEnabled( true );
}
#endif
}

void QgsLayoutMapWidget::updateComposerExtentFromGui()
Expand Down Expand Up @@ -1066,8 +1044,6 @@ void QgsLayoutMapWidget::initAnnotationDirectionBox( QComboBox *c, QgsLayoutItem

void QgsLayoutMapWidget::atlasLayerChanged( QgsVectorLayer *layer )
{
Q_UNUSED( layer );
#if 0 //TODO
if ( !layer || layer->wkbType() == QgsWkbTypes::NoGeometry )
{
//geometryless layer, disable atlas control
Expand All @@ -1083,7 +1059,6 @@ void QgsLayoutMapWidget::atlasLayerChanged( QgsVectorLayer *layer )
// enable or disable fixed scale control based on layer type
if ( mAtlasCheckBox->isChecked() )
toggleAtlasScalingOptionsByLayerType();
#endif
}

bool QgsLayoutMapWidget::hasPredefinedScales() const
Expand Down
162 changes: 162 additions & 0 deletions src/core/layout/qgslayoutitemmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,14 @@ QgsLayoutItemMap *QgsLayoutItemMap::create( QgsLayout *layout )
return new QgsLayoutItemMap( layout );
}

void QgsLayoutItemMap::refresh()
{
QgsLayoutItem::refresh();
invalidateCache();

updateAtlasFeature();
}

double QgsLayoutItemMap::scale() const
{
QgsScaleCalculator calculator;
Expand Down Expand Up @@ -1799,3 +1807,157 @@ void QgsLayoutItemMap::refreshMapExtents( const QgsExpressionContext *context )
emit mapRotationChanged( mapRotation );
}
}

void QgsLayoutItemMap::updateAtlasFeature()
{
if ( !atlasDriven() || !mLayout->context().layer() )
return; // nothing to do

QgsRectangle bounds = computeAtlasRectangle();
if ( bounds.isNull() )
return;

double xa1 = bounds.xMinimum();
double xa2 = bounds.xMaximum();
double ya1 = bounds.yMinimum();
double ya2 = bounds.yMaximum();
QgsRectangle newExtent = bounds;
QgsRectangle originalExtent = mExtent;

//sanity check - only allow fixed scale mode for point layers
bool isPointLayer = false;
switch ( mLayout->context().layer()->wkbType() )
{
case QgsWkbTypes::Point:
case QgsWkbTypes::Point25D:
case QgsWkbTypes::MultiPoint:
case QgsWkbTypes::MultiPoint25D:
isPointLayer = true;
break;
default:
isPointLayer = false;
break;
}

if ( mAtlasScalingMode == Fixed || mAtlasScalingMode == Predefined || isPointLayer )
{
QgsScaleCalculator calc;
calc.setMapUnits( crs().mapUnits() );
calc.setDpi( 25.4 );
double originalScale = calc.calculate( originalExtent, rect().width() );
double geomCenterX = ( xa1 + xa2 ) / 2.0;
double geomCenterY = ( ya1 + ya2 ) / 2.0;

if ( mAtlasScalingMode == Fixed || isPointLayer )
{
// only translate, keep the original scale (i.e. width x height)
double xMin = geomCenterX - originalExtent.width() / 2.0;
double yMin = geomCenterY - originalExtent.height() / 2.0;
newExtent = QgsRectangle( xMin,
yMin,
xMin + originalExtent.width(),
yMin + originalExtent.height() );

//scale newExtent to match original scale of map
//this is required for geographic coordinate systems, where the scale varies by extent
double newScale = calc.calculate( newExtent, rect().width() );
newExtent.scale( originalScale / newScale );
}
else if ( mAtlasScalingMode == Predefined )
{
// choose one of the predefined scales
double newWidth = originalExtent.width();
double newHeight = originalExtent.height();
QVector<qreal> scales = mLayout->context().predefinedScales();
for ( int i = 0; i < scales.size(); i++ )
{
double ratio = scales[i] / originalScale;
newWidth = originalExtent.width() * ratio;
newHeight = originalExtent.height() * ratio;

// compute new extent, centered on feature
double xMin = geomCenterX - newWidth / 2.0;
double yMin = geomCenterY - newHeight / 2.0;
newExtent = QgsRectangle( xMin,
yMin,
xMin + newWidth,
yMin + newHeight );

//scale newExtent to match desired map scale
//this is required for geographic coordinate systems, where the scale varies by extent
double newScale = calc.calculate( newExtent, rect().width() );
newExtent.scale( scales[i] / newScale );

if ( ( newExtent.width() >= bounds.width() ) && ( newExtent.height() >= bounds.height() ) )
{
// this is the smallest extent that embeds the feature, stop here
break;
}
}
}
}
else if ( mAtlasScalingMode == Auto )
{
// auto scale

double geomRatio = bounds.width() / bounds.height();
double mapRatio = originalExtent.width() / originalExtent.height();

// geometry height is too big
if ( geomRatio < mapRatio )
{
// extent the bbox's width
double adjWidth = ( mapRatio * bounds.height() - bounds.width() ) / 2.0;
xa1 -= adjWidth;
xa2 += adjWidth;
}
// geometry width is too big
else if ( geomRatio > mapRatio )
{
// extent the bbox's height
double adjHeight = ( bounds.width() / mapRatio - bounds.height() ) / 2.0;
ya1 -= adjHeight;
ya2 += adjHeight;
}
newExtent = QgsRectangle( xa1, ya1, xa2, ya2 );

if ( mAtlasMargin > 0.0 )
{
newExtent.scale( 1 + mAtlasMargin );
}
}

// set the new extent (and render)
setExtent( newExtent );
}

QgsRectangle QgsLayoutItemMap::computeAtlasRectangle()
{
// QgsGeometry::boundingBox is expressed in the geometry"s native CRS
// We have to transform the geometry 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 g = mLayout->context().currentGeometry( crs() );
// Rotating the geometry, so the bounding box is correct wrt map rotation
if ( mEvaluatedMapRotation != 0.0 )
{
QgsPointXY prevCenter = g.boundingBox().center();
g.rotate( mEvaluatedMapRotation, g.boundingBox().center() );
// Rotation center will be still the bounding box center of an unrotated geometry.
// Which means, if the center of bbox moves after rotation, the viewport will
// also be offset, and part of the geometry will fall out of bounds.
// Here we compensate for that roughly: by extending the rotated bounds
// so that its center is the same as the original.
QgsRectangle bounds = g.boundingBox();
double dx = std::max( std::abs( prevCenter.x() - bounds.xMinimum() ),
std::abs( prevCenter.x() - bounds.xMaximum() ) );
double dy = std::max( std::abs( prevCenter.y() - bounds.yMinimum() ),
std::abs( prevCenter.y() - bounds.yMaximum() ) );
QgsPointXY center = g.boundingBox().center();
return QgsRectangle( center.x() - dx, center.y() - dy,
center.x() + dx, center.y() + dy );
}
else
{
return g.boundingBox();
}
}
15 changes: 6 additions & 9 deletions src/core/layout/qgslayoutitemmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -422,15 +422,6 @@ class CORE_EXPORT QgsLayoutItemMap : public QgsLayoutItem
//! True if a draw is already in progress
bool isDrawing() const {return mDrawing;}

#if 0 //TODO

/**
* Sets new Extent for the current atlas preview and changes width, height (and implicitly also scale).
Atlas preview extents are only temporary, and are regenerated whenever the atlas feature changes
*/
void setNewAtlasFeatureExtent( const QgsRectangle &extent );
#endif

// In case of annotations, the bounding rectangle can be larger than the map item rectangle
QRectF boundingRect() const override;

Expand Down Expand Up @@ -472,6 +463,8 @@ class CORE_EXPORT QgsLayoutItemMap : public QgsLayoutItem

public slots:

void refresh() override;

void invalidateCache() override;

//! Updates the bounding rect of this item. Call this function before doing any changes related to annotation out of the map rectangle
Expand Down Expand Up @@ -656,6 +649,10 @@ class CORE_EXPORT QgsLayoutItemMap : public QgsLayoutItem
*/
void refreshMapExtents( const QgsExpressionContext *context = nullptr );

void updateAtlasFeature();

QgsRectangle computeAtlasRectangle();

friend class QgsLayoutItemMapGrid;
friend class QgsLayoutItemMapOverview;
friend class QgsLayoutItemLegend;
Expand Down
1 change: 0 additions & 1 deletion tests/src/core/testqgslayoutcontext.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

/***************************************************************************
testqgslayoutcontext.cpp
------------------------
Expand Down

0 comments on commit 69ddc32

Please sign in to comment.