mirror of
https://github.com/qgis/QGIS.git
synced 2025-03-03 00:02:25 -05:00
[layouts][api] Add API to allow map items to be clipped (take their shape from)
other layout items which provide clipping paths Opens the door for non-rectangular layout maps
This commit is contained in:
parent
77badc0097
commit
915615aec4
@ -113,6 +113,137 @@ Emitted when the atlas clipping settings are changed.
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class QgsLayoutItemMapItemClipPathSettings : QObject
|
||||||
|
{
|
||||||
|
%Docstring
|
||||||
|
Contains settings relating to clipping a layout map by another layout item.
|
||||||
|
|
||||||
|
.. versionadded:: 3.16
|
||||||
|
%End
|
||||||
|
|
||||||
|
%TypeHeaderCode
|
||||||
|
#include "qgslayoutitemmap.h"
|
||||||
|
%End
|
||||||
|
public:
|
||||||
|
|
||||||
|
QgsLayoutItemMapItemClipPathSettings( QgsLayoutItemMap *map /TransferThis/ = 0 );
|
||||||
|
%Docstring
|
||||||
|
Constructor for QgsLayoutItemMapItemClipPathSettings, with the specified ``map`` parent.
|
||||||
|
%End
|
||||||
|
|
||||||
|
bool isActive() const;
|
||||||
|
%Docstring
|
||||||
|
Returns ``True`` if the item clipping is enabled and set to a valid source item.
|
||||||
|
|
||||||
|
.. seealso:: :py:func:`enabled`
|
||||||
|
|
||||||
|
.. seealso:: :py:func:`sourceItem`
|
||||||
|
%End
|
||||||
|
|
||||||
|
bool enabled() const;
|
||||||
|
%Docstring
|
||||||
|
Returns ``True`` if the map content should be clipped to the associated item.
|
||||||
|
|
||||||
|
.. seealso:: :py:func:`setEnabled`
|
||||||
|
%End
|
||||||
|
|
||||||
|
void setEnabled( bool enabled );
|
||||||
|
%Docstring
|
||||||
|
Sets whether the map content should be clipped to the associated item.
|
||||||
|
|
||||||
|
.. seealso:: :py:func:`enabled`
|
||||||
|
%End
|
||||||
|
|
||||||
|
QgsGeometry clippedMapExtent() const;
|
||||||
|
%Docstring
|
||||||
|
Returns the geometry to use for clipping the parent map, in the map item's CRS.
|
||||||
|
%End
|
||||||
|
|
||||||
|
QgsMapClippingRegion toMapClippingRegion() const;
|
||||||
|
%Docstring
|
||||||
|
Returns the clip path as a map clipping region.
|
||||||
|
%End
|
||||||
|
|
||||||
|
void setSourceItem( QgsLayoutItem *item );
|
||||||
|
%Docstring
|
||||||
|
Sets the source ``item`` which will provide the clipping path for the map.
|
||||||
|
|
||||||
|
The specified ``item`` must return the QgsLayoutItem.FlagProvidesClipPath flag.
|
||||||
|
|
||||||
|
.. seealso:: :py:func:`sourceItem`
|
||||||
|
%End
|
||||||
|
|
||||||
|
QgsLayoutItem *sourceItem();
|
||||||
|
%Docstring
|
||||||
|
Returns the source item which will provide the clipping path for the map, or ``None``
|
||||||
|
if no item is set.
|
||||||
|
|
||||||
|
.. seealso:: :py:func:`setSourceItem`
|
||||||
|
%End
|
||||||
|
|
||||||
|
QgsMapClippingRegion::FeatureClippingType featureClippingType() const;
|
||||||
|
%Docstring
|
||||||
|
Returns the feature clipping type to apply when clipping to the associated item.
|
||||||
|
|
||||||
|
.. seealso:: :py:func:`setFeatureClippingType`
|
||||||
|
%End
|
||||||
|
|
||||||
|
void setFeatureClippingType( QgsMapClippingRegion::FeatureClippingType type );
|
||||||
|
%Docstring
|
||||||
|
Sets the feature clipping ``type`` to apply when clipping to the associated item.
|
||||||
|
|
||||||
|
.. seealso:: :py:func:`featureClippingType`
|
||||||
|
%End
|
||||||
|
|
||||||
|
bool forceLabelsInsideFeature() const;
|
||||||
|
%Docstring
|
||||||
|
Returns ``True`` if labels should only be placed inside the clip path geometry.
|
||||||
|
|
||||||
|
.. seealso:: :py:func:`setForceLabelsInsideFeature`
|
||||||
|
%End
|
||||||
|
|
||||||
|
void setForceLabelsInsideFeature( bool forceInside );
|
||||||
|
%Docstring
|
||||||
|
Sets whether labels should only be placed inside the clip path geometry.
|
||||||
|
|
||||||
|
.. seealso:: :py:func:`forceLabelsInsideFeature`
|
||||||
|
%End
|
||||||
|
|
||||||
|
bool writeXml( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context ) const;
|
||||||
|
%Docstring
|
||||||
|
Stores settings in a DOM element, where ``element`` is the DOM element
|
||||||
|
corresponding to a 'LayoutMap' tag.
|
||||||
|
|
||||||
|
.. seealso:: :py:func:`readXml`
|
||||||
|
%End
|
||||||
|
|
||||||
|
bool readXml( const QDomElement &element, const QDomDocument &doc, const QgsReadWriteContext &context );
|
||||||
|
%Docstring
|
||||||
|
Sets the setting's state from a DOM document, where ``element`` is the DOM
|
||||||
|
node corresponding to a 'LayoutMap' tag.
|
||||||
|
|
||||||
|
.. seealso:: :py:func:`writeXml`
|
||||||
|
|
||||||
|
.. seealso:: :py:func:`finalizeRestoreFromXml`
|
||||||
|
%End
|
||||||
|
|
||||||
|
void finalizeRestoreFromXml();
|
||||||
|
%Docstring
|
||||||
|
To be called after all pending items have been restored from XML.
|
||||||
|
|
||||||
|
.. seealso:: :py:func:`readXml`
|
||||||
|
%End
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
void changed();
|
||||||
|
%Docstring
|
||||||
|
Emitted when the item clipping settings are changed.
|
||||||
|
%End
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class QgsLayoutItemMap : QgsLayoutItem, QgsTemporalRangeObject
|
class QgsLayoutItemMap : QgsLayoutItem, QgsTemporalRangeObject
|
||||||
{
|
{
|
||||||
%Docstring
|
%Docstring
|
||||||
@ -731,6 +862,13 @@ Creates a transform from layout coordinates to map coordinates.
|
|||||||
%Docstring
|
%Docstring
|
||||||
Returns the map's atlas clipping settings.
|
Returns the map's atlas clipping settings.
|
||||||
|
|
||||||
|
.. versionadded:: 3.16
|
||||||
|
%End
|
||||||
|
|
||||||
|
QgsLayoutItemMapItemClipPathSettings *itemClippingSettings();
|
||||||
|
%Docstring
|
||||||
|
Returns the map's item based clip path settings.
|
||||||
|
|
||||||
.. versionadded:: 3.16
|
.. versionadded:: 3.16
|
||||||
%End
|
%End
|
||||||
|
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
QgsLayoutItemMap::QgsLayoutItemMap( QgsLayout *layout )
|
QgsLayoutItemMap::QgsLayoutItemMap( QgsLayout *layout )
|
||||||
: QgsLayoutItem( layout )
|
: QgsLayoutItem( layout )
|
||||||
, mAtlasClippingSettings( new QgsLayoutItemMapAtlasClippingSettings( this ) )
|
, mAtlasClippingSettings( new QgsLayoutItemMapAtlasClippingSettings( this ) )
|
||||||
|
, mItemClippingSettings( new QgsLayoutItemMapItemClipPathSettings( this ) )
|
||||||
{
|
{
|
||||||
mBackgroundUpdateTimer = new QTimer( this );
|
mBackgroundUpdateTimer = new QTimer( this );
|
||||||
mBackgroundUpdateTimer->setSingleShot( true );
|
mBackgroundUpdateTimer->setSingleShot( true );
|
||||||
@ -62,6 +63,11 @@ QgsLayoutItemMap::QgsLayoutItemMap( QgsLayout *layout )
|
|||||||
refresh();
|
refresh();
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
connect( mItemClippingSettings, &QgsLayoutItemMapItemClipPathSettings::changed, this, [ = ]
|
||||||
|
{
|
||||||
|
refresh();
|
||||||
|
} );
|
||||||
|
|
||||||
if ( layout )
|
if ( layout )
|
||||||
connectUpdateSlot();
|
connectUpdateSlot();
|
||||||
}
|
}
|
||||||
@ -260,13 +266,28 @@ QgsRectangle QgsLayoutItemMap::extent() const
|
|||||||
return mExtent;
|
return mExtent;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPolygonF QgsLayoutItemMap::visibleExtentPolygon() const
|
QPolygonF QgsLayoutItemMap::calculateVisibleExtentPolygon( bool includeClipping ) const
|
||||||
{
|
{
|
||||||
QPolygonF poly;
|
QPolygonF poly;
|
||||||
mapPolygon( mExtent, poly );
|
mapPolygon( mExtent, poly );
|
||||||
|
|
||||||
|
if ( includeClipping && mItemClippingSettings->isActive() )
|
||||||
|
{
|
||||||
|
const QgsGeometry geom = mItemClippingSettings->clippedMapExtent();
|
||||||
|
if ( !geom.isEmpty() )
|
||||||
|
{
|
||||||
|
poly = poly.intersected( geom.asQPolygonF() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return poly;
|
return poly;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPolygonF QgsLayoutItemMap::visibleExtentPolygon() const
|
||||||
|
{
|
||||||
|
return calculateVisibleExtentPolygon( true );
|
||||||
|
}
|
||||||
|
|
||||||
QgsCoordinateReferenceSystem QgsLayoutItemMap::crs() const
|
QgsCoordinateReferenceSystem QgsLayoutItemMap::crs() const
|
||||||
{
|
{
|
||||||
if ( mCrs.isValid() )
|
if ( mCrs.isValid() )
|
||||||
@ -664,6 +685,7 @@ bool QgsLayoutItemMap::writePropertiesToElement( QDomElement &mapElem, QDomDocum
|
|||||||
}
|
}
|
||||||
|
|
||||||
mAtlasClippingSettings->writeXml( mapElem, doc, context );
|
mAtlasClippingSettings->writeXml( mapElem, doc, context );
|
||||||
|
mItemClippingSettings->writeXml( mapElem, doc, context );
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -820,6 +842,7 @@ bool QgsLayoutItemMap::readPropertiesFromElement( const QDomElement &itemElem, c
|
|||||||
}
|
}
|
||||||
|
|
||||||
mAtlasClippingSettings->readXml( itemElem, doc, context );
|
mAtlasClippingSettings->readXml( itemElem, doc, context );
|
||||||
|
mItemClippingSettings->readXml( itemElem, doc, context );
|
||||||
|
|
||||||
updateBoundingRect();
|
updateBoundingRect();
|
||||||
|
|
||||||
@ -1463,6 +1486,7 @@ QgsMapSettings QgsLayoutItemMap::mapSettings( const QgsRectangle &extent, QSizeF
|
|||||||
// override the default text render format inherited from the labeling engine settings using the layout's render context setting
|
// override the default text render format inherited from the labeling engine settings using the layout's render context setting
|
||||||
jobMapSettings.setTextRenderFormat( mLayout->renderContext().textRenderFormat() );
|
jobMapSettings.setTextRenderFormat( mLayout->renderContext().textRenderFormat() );
|
||||||
|
|
||||||
|
QgsGeometry labelBoundary;
|
||||||
if ( mEvaluatedLabelMargin.length() > 0 )
|
if ( mEvaluatedLabelMargin.length() > 0 )
|
||||||
{
|
{
|
||||||
QPolygonF visiblePoly = jobMapSettings.visiblePolygon();
|
QPolygonF visiblePoly = jobMapSettings.visiblePolygon();
|
||||||
@ -1471,7 +1495,7 @@ QgsMapSettings QgsLayoutItemMap::mapSettings( const QgsRectangle &extent, QSizeF
|
|||||||
const double layoutLabelMarginInMapUnits = layoutLabelMargin / rect().width() * jobMapSettings.extent().width();
|
const double layoutLabelMarginInMapUnits = layoutLabelMargin / rect().width() * jobMapSettings.extent().width();
|
||||||
QgsGeometry mapBoundaryGeom = QgsGeometry::fromQPolygonF( visiblePoly );
|
QgsGeometry mapBoundaryGeom = QgsGeometry::fromQPolygonF( visiblePoly );
|
||||||
mapBoundaryGeom = mapBoundaryGeom.buffer( -layoutLabelMarginInMapUnits, 0 );
|
mapBoundaryGeom = mapBoundaryGeom.buffer( -layoutLabelMarginInMapUnits, 0 );
|
||||||
jobMapSettings.setLabelBoundaryGeometry( mapBoundaryGeom );
|
labelBoundary = mapBoundaryGeom;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !mBlockingLabelItems.isEmpty() )
|
if ( !mBlockingLabelItems.isEmpty() )
|
||||||
@ -1497,14 +1521,45 @@ QgsMapSettings QgsLayoutItemMap::mapSettings( const QgsRectangle &extent, QSizeF
|
|||||||
|
|
||||||
if ( mAtlasClippingSettings->forceLabelsInsideFeature() )
|
if ( mAtlasClippingSettings->forceLabelsInsideFeature() )
|
||||||
{
|
{
|
||||||
if ( !jobMapSettings.labelBoundaryGeometry().isEmpty() )
|
if ( !labelBoundary.isEmpty() )
|
||||||
{
|
{
|
||||||
clipGeom = clipGeom.intersection( jobMapSettings.labelBoundaryGeometry() );
|
labelBoundary = clipGeom.intersection( labelBoundary );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
labelBoundary = clipGeom;
|
||||||
}
|
}
|
||||||
jobMapSettings.setLabelBoundaryGeometry( clipGeom );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( mItemClippingSettings->isActive() )
|
||||||
|
{
|
||||||
|
const QgsGeometry clipGeom = mItemClippingSettings->clippedMapExtent();
|
||||||
|
if ( !clipGeom.isEmpty() )
|
||||||
|
{
|
||||||
|
jobMapSettings.addClippingRegion( mItemClippingSettings->toMapClippingRegion() );
|
||||||
|
|
||||||
|
if ( mItemClippingSettings->forceLabelsInsideFeature() )
|
||||||
|
{
|
||||||
|
const double layoutLabelMargin = mLayout->convertToLayoutUnits( mEvaluatedLabelMargin );
|
||||||
|
const double layoutLabelMarginInMapUnits = layoutLabelMargin / rect().width() * jobMapSettings.extent().width();
|
||||||
|
QgsGeometry mapBoundaryGeom = clipGeom;
|
||||||
|
mapBoundaryGeom = mapBoundaryGeom.buffer( -layoutLabelMarginInMapUnits, 0 );
|
||||||
|
if ( !labelBoundary.isEmpty() )
|
||||||
|
{
|
||||||
|
labelBoundary = mapBoundaryGeom.intersection( labelBoundary );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
labelBoundary = mapBoundaryGeom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !labelBoundary.isNull() )
|
||||||
|
jobMapSettings.setLabelBoundaryGeometry( labelBoundary );
|
||||||
|
|
||||||
return jobMapSettings;
|
return jobMapSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1524,6 +1579,7 @@ void QgsLayoutItemMap::finalizeRestoreFromXml()
|
|||||||
|
|
||||||
mOverviewStack->finalizeRestoreFromXml();
|
mOverviewStack->finalizeRestoreFromXml();
|
||||||
mGridStack->finalizeRestoreFromXml();
|
mGridStack->finalizeRestoreFromXml();
|
||||||
|
mItemClippingSettings->finalizeRestoreFromXml();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QgsLayoutItemMap::setMoveContentPreviewOffset( double xOffset, double yOffset )
|
void QgsLayoutItemMap::setMoveContentPreviewOffset( double xOffset, double yOffset )
|
||||||
@ -1613,7 +1669,7 @@ QPolygonF QgsLayoutItemMap::transformedMapPolygon() const
|
|||||||
double dx = mXOffset;
|
double dx = mXOffset;
|
||||||
double dy = mYOffset;
|
double dy = mYOffset;
|
||||||
transformShift( dx, dy );
|
transformShift( dx, dy );
|
||||||
QPolygonF poly = visibleExtentPolygon();
|
QPolygonF poly = calculateVisibleExtentPolygon( false );
|
||||||
poly.translate( -dx, -dy );
|
poly.translate( -dx, -dy );
|
||||||
return poly;
|
return poly;
|
||||||
}
|
}
|
||||||
@ -1922,7 +1978,7 @@ void QgsLayoutItemMap::connectUpdateSlot()
|
|||||||
|
|
||||||
QTransform QgsLayoutItemMap::layoutToMapCoordsTransform() const
|
QTransform QgsLayoutItemMap::layoutToMapCoordsTransform() const
|
||||||
{
|
{
|
||||||
QPolygonF thisExtent = visibleExtentPolygon();
|
QPolygonF thisExtent = calculateVisibleExtentPolygon( false );
|
||||||
QTransform mapTransform;
|
QTransform mapTransform;
|
||||||
QPolygonF thisRectPoly = QPolygonF( QRectF( 0, 0, rect().width(), rect().height() ) );
|
QPolygonF thisRectPoly = QPolygonF( QRectF( 0, 0, rect().width(), rect().height() ) );
|
||||||
//workaround QT Bug #21329
|
//workaround QT Bug #21329
|
||||||
@ -2633,6 +2689,7 @@ void QgsLayoutItemMap::createStagedRenderJob( const QgsRectangle &extent, const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// QgsLayoutItemMapAtlasClippingSettings
|
// QgsLayoutItemMapAtlasClippingSettings
|
||||||
//
|
//
|
||||||
@ -2770,3 +2827,148 @@ void QgsLayoutItemMapAtlasClippingSettings::layersAboutToBeRemoved( const QList<
|
|||||||
_qgis_removeLayers( mLayersToClip, layers );
|
_qgis_removeLayers( mLayersToClip, layers );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// QgsLayoutItemMapItemClipPathSettings
|
||||||
|
//
|
||||||
|
QgsLayoutItemMapItemClipPathSettings::QgsLayoutItemMapItemClipPathSettings( QgsLayoutItemMap *map )
|
||||||
|
: QObject( map )
|
||||||
|
, mMap( map )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QgsLayoutItemMapItemClipPathSettings::isActive() const
|
||||||
|
{
|
||||||
|
return mEnabled && mClipPathSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QgsLayoutItemMapItemClipPathSettings::enabled() const
|
||||||
|
{
|
||||||
|
return mEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QgsLayoutItemMapItemClipPathSettings::setEnabled( bool enabled )
|
||||||
|
{
|
||||||
|
if ( enabled == mEnabled )
|
||||||
|
return;
|
||||||
|
|
||||||
|
mEnabled = enabled;
|
||||||
|
emit changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
QgsGeometry QgsLayoutItemMapItemClipPathSettings::clippedMapExtent() const
|
||||||
|
{
|
||||||
|
if ( isActive() )
|
||||||
|
{
|
||||||
|
QgsGeometry clipGeom( mClipPathSource->clipPath() );
|
||||||
|
clipGeom.transform( mMap->layoutToMapCoordsTransform() );
|
||||||
|
return clipGeom;
|
||||||
|
}
|
||||||
|
return QgsGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
|
QgsMapClippingRegion QgsLayoutItemMapItemClipPathSettings::toMapClippingRegion() const
|
||||||
|
{
|
||||||
|
QgsMapClippingRegion region( clippedMapExtent() );
|
||||||
|
region.setFeatureClip( mFeatureClippingType );
|
||||||
|
return region;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QgsLayoutItemMapItemClipPathSettings::setSourceItem( QgsLayoutItem *item )
|
||||||
|
{
|
||||||
|
if ( mClipPathSource == item )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( mClipPathSource )
|
||||||
|
{
|
||||||
|
disconnect( mClipPathSource, &QgsLayoutItem::sizePositionChanged, mMap, &QgsLayoutItemMap::refresh );
|
||||||
|
disconnect( mClipPathSource, &QgsLayoutItem::rotationChanged, mMap, &QgsLayoutItemMap::refresh );
|
||||||
|
disconnect( mClipPathSource, &QgsLayoutItem::sizePositionChanged, mMap, &QgsLayoutItemMap::extentChanged );
|
||||||
|
disconnect( mClipPathSource, &QgsLayoutItem::rotationChanged, mMap, &QgsLayoutItemMap::extentChanged );
|
||||||
|
}
|
||||||
|
|
||||||
|
mClipPathSource = item;
|
||||||
|
|
||||||
|
if ( mClipPathSource )
|
||||||
|
{
|
||||||
|
// if item size or rotation changes, we need to redraw this map
|
||||||
|
connect( mClipPathSource, &QgsLayoutItem::sizePositionChanged, mMap, &QgsLayoutItemMap::refresh );
|
||||||
|
connect( mClipPathSource, &QgsLayoutItem::rotationChanged, mMap, &QgsLayoutItemMap::refresh );
|
||||||
|
// and if clip item size or rotation changes, then effectively we've changed the visible extent of the map
|
||||||
|
connect( mClipPathSource, &QgsLayoutItem::sizePositionChanged, mMap, &QgsLayoutItemMap::extentChanged );
|
||||||
|
connect( mClipPathSource, &QgsLayoutItem::rotationChanged, mMap, &QgsLayoutItemMap::extentChanged );
|
||||||
|
}
|
||||||
|
|
||||||
|
emit changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
QgsLayoutItem *QgsLayoutItemMapItemClipPathSettings::sourceItem()
|
||||||
|
{
|
||||||
|
return mClipPathSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
QgsMapClippingRegion::FeatureClippingType QgsLayoutItemMapItemClipPathSettings::featureClippingType() const
|
||||||
|
{
|
||||||
|
return mFeatureClippingType;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QgsLayoutItemMapItemClipPathSettings::setFeatureClippingType( QgsMapClippingRegion::FeatureClippingType type )
|
||||||
|
{
|
||||||
|
if ( mFeatureClippingType == type )
|
||||||
|
return;
|
||||||
|
|
||||||
|
mFeatureClippingType = type;
|
||||||
|
emit changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QgsLayoutItemMapItemClipPathSettings::forceLabelsInsideFeature() const
|
||||||
|
{
|
||||||
|
return mForceLabelsInsideClipPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QgsLayoutItemMapItemClipPathSettings::setForceLabelsInsideFeature( bool forceInside )
|
||||||
|
{
|
||||||
|
if ( forceInside == mForceLabelsInsideClipPath )
|
||||||
|
return;
|
||||||
|
|
||||||
|
mForceLabelsInsideClipPath = forceInside;
|
||||||
|
emit changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QgsLayoutItemMapItemClipPathSettings::writeXml( QDomElement &element, QDomDocument &document, const QgsReadWriteContext & ) const
|
||||||
|
{
|
||||||
|
QDomElement settingsElem = document.createElement( QStringLiteral( "itemClippingSettings" ) );
|
||||||
|
settingsElem.setAttribute( QStringLiteral( "enabled" ), mEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
|
||||||
|
settingsElem.setAttribute( QStringLiteral( "forceLabelsInside" ), mForceLabelsInsideClipPath ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
|
||||||
|
settingsElem.setAttribute( QStringLiteral( "clippingType" ), QString::number( static_cast<int>( mFeatureClippingType ) ) );
|
||||||
|
if ( mClipPathSource )
|
||||||
|
settingsElem.setAttribute( QStringLiteral( "clipSource" ), mClipPathSource->uuid() );
|
||||||
|
else
|
||||||
|
settingsElem.setAttribute( QStringLiteral( "clipSource" ), QString() );
|
||||||
|
|
||||||
|
element.appendChild( settingsElem );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QgsLayoutItemMapItemClipPathSettings::readXml( const QDomElement &element, const QDomDocument &, const QgsReadWriteContext & )
|
||||||
|
{
|
||||||
|
const QDomElement settingsElem = element.firstChildElement( QStringLiteral( "itemClippingSettings" ) );
|
||||||
|
|
||||||
|
mEnabled = settingsElem.attribute( QStringLiteral( "enabled" ), QStringLiteral( "0" ) ).toInt();
|
||||||
|
mForceLabelsInsideClipPath = settingsElem.attribute( QStringLiteral( "forceLabelsInside" ), QStringLiteral( "0" ) ).toInt();
|
||||||
|
mFeatureClippingType = static_cast< QgsMapClippingRegion::FeatureClippingType >( settingsElem.attribute( QStringLiteral( "clippingType" ), QStringLiteral( "0" ) ).toInt() );
|
||||||
|
mClipPathUuid = settingsElem.attribute( QStringLiteral( "clipSource" ) );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QgsLayoutItemMapItemClipPathSettings::finalizeRestoreFromXml()
|
||||||
|
{
|
||||||
|
if ( !mClipPathUuid.isEmpty() )
|
||||||
|
{
|
||||||
|
if ( QgsLayoutItem *item = mMap->layout()->itemByUuid( mClipPathUuid, true ) )
|
||||||
|
{
|
||||||
|
setSourceItem( item );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -141,6 +141,141 @@ class CORE_EXPORT QgsLayoutItemMapAtlasClippingSettings : public QObject
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \ingroup core
|
||||||
|
* \class QgsLayoutItemMapItemClipPathSettings
|
||||||
|
* \brief Contains settings relating to clipping a layout map by another layout item.
|
||||||
|
* \since QGIS 3.16
|
||||||
|
*/
|
||||||
|
class CORE_EXPORT QgsLayoutItemMapItemClipPathSettings : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for QgsLayoutItemMapItemClipPathSettings, with the specified \a map parent.
|
||||||
|
*/
|
||||||
|
QgsLayoutItemMapItemClipPathSettings( QgsLayoutItemMap *map SIP_TRANSFERTHIS = nullptr );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns TRUE if the item clipping is enabled and set to a valid source item.
|
||||||
|
*
|
||||||
|
* \see enabled()
|
||||||
|
* \see sourceItem()
|
||||||
|
*/
|
||||||
|
bool isActive() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns TRUE if the map content should be clipped to the associated item.
|
||||||
|
*
|
||||||
|
* \see setEnabled()
|
||||||
|
*/
|
||||||
|
bool enabled() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether the map content should be clipped to the associated item.
|
||||||
|
*
|
||||||
|
* \see enabled()
|
||||||
|
*/
|
||||||
|
void setEnabled( bool enabled );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the geometry to use for clipping the parent map, in the map item's CRS.
|
||||||
|
*/
|
||||||
|
QgsGeometry clippedMapExtent() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the clip path as a map clipping region.
|
||||||
|
*/
|
||||||
|
QgsMapClippingRegion toMapClippingRegion() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the source \a item which will provide the clipping path for the map.
|
||||||
|
*
|
||||||
|
* The specified \a item must return the QgsLayoutItem::FlagProvidesClipPath flag.
|
||||||
|
*
|
||||||
|
* \see sourceItem()
|
||||||
|
*/
|
||||||
|
void setSourceItem( QgsLayoutItem *item );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the source item which will provide the clipping path for the map, or NULLPTR
|
||||||
|
* if no item is set.
|
||||||
|
*
|
||||||
|
* \see setSourceItem()
|
||||||
|
*/
|
||||||
|
QgsLayoutItem *sourceItem();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the feature clipping type to apply when clipping to the associated item.
|
||||||
|
*
|
||||||
|
* \see setFeatureClippingType()
|
||||||
|
*/
|
||||||
|
QgsMapClippingRegion::FeatureClippingType featureClippingType() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the feature clipping \a type to apply when clipping to the associated item.
|
||||||
|
*
|
||||||
|
* \see featureClippingType()
|
||||||
|
*/
|
||||||
|
void setFeatureClippingType( QgsMapClippingRegion::FeatureClippingType type );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns TRUE if labels should only be placed inside the clip path geometry.
|
||||||
|
*
|
||||||
|
* \see setForceLabelsInsideFeature()
|
||||||
|
*/
|
||||||
|
bool forceLabelsInsideFeature() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether labels should only be placed inside the clip path geometry.
|
||||||
|
*
|
||||||
|
* \see forceLabelsInsideFeature()
|
||||||
|
*/
|
||||||
|
void setForceLabelsInsideFeature( bool forceInside );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores settings in a DOM element, where \a element is the DOM element
|
||||||
|
* corresponding to a 'LayoutMap' tag.
|
||||||
|
* \see readXml()
|
||||||
|
*/
|
||||||
|
bool writeXml( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context ) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the setting's state from a DOM document, where \a element is the DOM
|
||||||
|
* node corresponding to a 'LayoutMap' tag.
|
||||||
|
* \see writeXml()
|
||||||
|
* \see finalizeRestoreFromXml()
|
||||||
|
*/
|
||||||
|
bool readXml( const QDomElement &element, const QDomDocument &doc, const QgsReadWriteContext &context );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To be called after all pending items have been restored from XML.
|
||||||
|
* \see readXml()
|
||||||
|
*/
|
||||||
|
void finalizeRestoreFromXml();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emitted when the item clipping settings are changed.
|
||||||
|
*/
|
||||||
|
void changed();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
QgsLayoutItemMap *mMap = nullptr;
|
||||||
|
bool mEnabled = false;
|
||||||
|
QgsMapClippingRegion::FeatureClippingType mFeatureClippingType = QgsMapClippingRegion::FeatureClippingType::ClipPainterOnly;
|
||||||
|
bool mForceLabelsInsideClipPath = false;
|
||||||
|
|
||||||
|
QPointer< QgsLayoutItem > mClipPathSource;
|
||||||
|
QString mClipPathUuid;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \ingroup core
|
* \ingroup core
|
||||||
* \class QgsLayoutItemMap
|
* \class QgsLayoutItemMap
|
||||||
@ -677,6 +812,13 @@ class CORE_EXPORT QgsLayoutItemMap : public QgsLayoutItem, public QgsTemporalRan
|
|||||||
*/
|
*/
|
||||||
QgsLayoutItemMapAtlasClippingSettings *atlasClippingSettings() { return mAtlasClippingSettings; }
|
QgsLayoutItemMapAtlasClippingSettings *atlasClippingSettings() { return mAtlasClippingSettings; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the map's item based clip path settings.
|
||||||
|
*
|
||||||
|
* \since QGIS 3.16
|
||||||
|
*/
|
||||||
|
QgsLayoutItemMapItemClipPathSettings *itemClippingSettings() { return mItemClippingSettings; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
void draw( QgsLayoutItemRenderContext &context ) override;
|
void draw( QgsLayoutItemRenderContext &context ) override;
|
||||||
@ -962,6 +1104,7 @@ class CORE_EXPORT QgsLayoutItemMap : public QgsLayoutItem, public QgsTemporalRan
|
|||||||
QStringList::iterator mExportThemeIt;
|
QStringList::iterator mExportThemeIt;
|
||||||
|
|
||||||
QgsLayoutItemMapAtlasClippingSettings *mAtlasClippingSettings = nullptr;
|
QgsLayoutItemMapAtlasClippingSettings *mAtlasClippingSettings = nullptr;
|
||||||
|
QgsLayoutItemMapItemClipPathSettings *mItemClippingSettings = nullptr;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refresh the map's extents, considering data defined extent, scale and rotation
|
* Refresh the map's extents, considering data defined extent, scale and rotation
|
||||||
@ -975,6 +1118,8 @@ class CORE_EXPORT QgsLayoutItemMap : public QgsLayoutItem, public QgsTemporalRan
|
|||||||
|
|
||||||
void createStagedRenderJob( const QgsRectangle &extent, const QSizeF size, double dpi );
|
void createStagedRenderJob( const QgsRectangle &extent, const QSizeF size, double dpi );
|
||||||
|
|
||||||
|
QPolygonF calculateVisibleExtentPolygon( bool includeClipping ) const;
|
||||||
|
|
||||||
friend class QgsLayoutItemMapGrid;
|
friend class QgsLayoutItemMapGrid;
|
||||||
friend class QgsLayoutItemMapOverview;
|
friend class QgsLayoutItemMapOverview;
|
||||||
friend class QgsLayoutItemLegend;
|
friend class QgsLayoutItemLegend;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user