43 #include <QStyleOptionGraphicsItem>
51 mBackgroundUpdateTimer =
new QTimer(
this );
52 mBackgroundUpdateTimer->setSingleShot(
true );
53 connect( mBackgroundUpdateTimer, &QTimer::timeout,
this, &QgsLayoutItemMap::recreateCachedImageInBackground );
57 setCacheMode( QGraphicsItem::NoCache );
64 mGridStack = std::make_unique< QgsLayoutItemMapGridStack >(
this );
65 mOverviewStack = std::make_unique< QgsLayoutItemMapOverviewStack >(
this );
98 mPainterJob->cancel();
123 QList<QgsLayoutItemMap *> mapsList;
124 mLayout->layoutItems( mapsList );
133 if ( map->mMapId == mMapId )
136 maxId = std::max( maxId, map->mMapId );
141 mLayout->itemsModel()->updateItemDisplayName(
this );
153 return tr(
"Map %1" ).arg( mMapId );
165 mCachedLayerStyleOverridesPresetName.clear();
169 updateAtlasFeature();
174 if ( rect().isEmpty() )
179 calculator.
setDpi( 25.4 );
186 double currentScaleDenominator =
scale();
193 double scaleRatio = scaleDenominator / currentScaleDenominator;
194 mExtent.
scale( scaleRatio );
196 if ( mAtlasDriven && mAtlasScalingMode ==
Fixed )
203 calculator.
setDpi( 25.4 );
204 scaleRatio = scaleDenominator / calculator.
calculate( mExtent, rect().width() );
205 mExtent.
scale( scaleRatio );
229 QRectF currentRect = rect();
231 double newHeight = currentRect.width() * mExtent.
height() / mExtent.
width();
243 double currentWidthHeightRatio = 1.0;
244 if ( !currentExtent.
isNull() )
245 currentWidthHeightRatio = currentExtent.
width() / currentExtent.
height();
247 currentWidthHeightRatio = rect().width() / rect().height();
248 double newWidthHeightRatio = newExtent.
width() / newExtent.
height();
250 if ( currentWidthHeightRatio < newWidthHeightRatio )
253 double newHeight = newExtent.
width() / currentWidthHeightRatio;
254 double deltaHeight = newHeight - newExtent.
height();
261 double newWidth = currentWidthHeightRatio * newExtent.
height();
262 double deltaWidth = newWidth - newExtent.
width();
267 if ( mExtent == newExtent )
286 QPolygonF QgsLayoutItemMap::calculateVisibleExtentPolygon(
bool includeClipping )
const
289 mapPolygon( mExtent, poly );
291 if ( includeClipping && mItemClippingSettings->
isActive() )
305 return calculateVisibleExtentPolygon(
true );
313 return mLayout->project()->crs();
328 return _qgis_listRefToRaw( mLayers );
333 mLayers = _qgis_listRawToRef(
layers );
338 if ( overrides == mLayerStyleOverrides )
341 mLayerStyleOverrides = overrides;
348 mLayerStyleOverrides.clear();
355 mLayerStyleOverrides.insert( layer->id(), style.
xmlData() );
362 if ( mFollowVisibilityPreset == follow )
365 mFollowVisibilityPreset = follow;
367 if ( !mFollowVisibilityPresetName.isEmpty() )
368 emit
themeChanged( mFollowVisibilityPreset ? mFollowVisibilityPresetName : QString() );
373 if ( name == mFollowVisibilityPresetName )
376 mFollowVisibilityPresetName = name;
377 if ( mFollowVisibilityPreset )
383 mLastRenderedImageOffsetX -= dx;
384 mLastRenderedImageOffsetY -= dy;
387 transformShift( dx, dy );
411 double mapY = mExtent.
yMinimum() + ( 1 - ( point.y() / rect().height() ) ) * ( mExtent.
yMaximum() - mExtent.
yMinimum() );
417 centerX = mapX + ( centerX - mapX ) * ( 1.0 / factor );
418 centerY = mapY + ( centerY - mapY ) * ( 1.0 / factor );
420 double newIntervalX, newIntervalY;
437 if ( mAtlasDriven && mAtlasScalingMode ==
Fixed )
444 calculator.
setDpi( 25.4 );
445 double scaleRatio =
scale() / calculator.
calculate( mExtent, rect().width() );
446 mExtent.
scale( scaleRatio );
462 if ( layer->dataProvider() && layer->providerType() == QLatin1String(
"wms" ) )
496 if ( mOverviewStack->containsAdvancedEffects() )
502 if ( mGridStack->containsAdvancedEffects() )
514 mMapRotation = rotation;
515 mEvaluatedMapRotation = mMapRotation;
529 mAtlasDriven = enabled;
546 double margin = mAtlasMargin;
554 margin = ddMargin / 100;
566 if ( mGridStack->size() < 1 )
569 mGridStack->addGrid(
grid );
571 return mGridStack->grid( 0 );
576 if ( mOverviewStack->size() < 1 )
579 mOverviewStack->addOverview(
overview );
581 return mOverviewStack->overview( 0 );
592 mapElem.setAttribute( QStringLiteral(
"keepLayerSet" ), QStringLiteral(
"true" ) );
596 mapElem.setAttribute( QStringLiteral(
"keepLayerSet" ), QStringLiteral(
"false" ) );
599 if ( mDrawAnnotations )
601 mapElem.setAttribute( QStringLiteral(
"drawCanvasItems" ), QStringLiteral(
"true" ) );
605 mapElem.setAttribute( QStringLiteral(
"drawCanvasItems" ), QStringLiteral(
"false" ) );
609 QDomElement extentElem = doc.createElement( QStringLiteral(
"Extent" ) );
614 mapElem.appendChild( extentElem );
618 QDomElement crsElem = doc.createElement( QStringLiteral(
"crs" ) );
620 mapElem.appendChild( crsElem );
624 mapElem.setAttribute( QStringLiteral(
"followPreset" ), mFollowVisibilityPreset ? QStringLiteral(
"true" ) : QStringLiteral(
"false" ) );
625 mapElem.setAttribute( QStringLiteral(
"followPresetName" ), mFollowVisibilityPresetName );
628 mapElem.setAttribute( QStringLiteral(
"mapRotation" ), QString::number( mMapRotation ) );
631 QDomElement layerSetElem = doc.createElement( QStringLiteral(
"LayerSet" ) );
636 QDomElement layerElem = doc.createElement( QStringLiteral(
"Layer" ) );
637 QDomText layerIdText = doc.createTextNode( layerRef.layerId );
638 layerElem.appendChild( layerIdText );
640 layerElem.setAttribute( QStringLiteral(
"name" ), layerRef.name );
641 layerElem.setAttribute( QStringLiteral(
"source" ), layerRef.source );
642 layerElem.setAttribute( QStringLiteral(
"provider" ), layerRef.provider );
644 layerSetElem.appendChild( layerElem );
646 mapElem.appendChild( layerSetElem );
649 if ( mKeepLayerStyles )
651 QDomElement stylesElem = doc.createElement( QStringLiteral(
"LayerStyles" ) );
652 for (
auto styleIt = mLayerStyleOverrides.constBegin(); styleIt != mLayerStyleOverrides.constEnd(); ++styleIt )
654 QDomElement styleElem = doc.createElement( QStringLiteral(
"LayerStyle" ) );
659 styleElem.setAttribute( QStringLiteral(
"layerid" ), ref.
layerId );
660 styleElem.setAttribute( QStringLiteral(
"name" ), ref.
name );
661 styleElem.setAttribute( QStringLiteral(
"source" ), ref.
source );
662 styleElem.setAttribute( QStringLiteral(
"provider" ), ref.
provider );
666 stylesElem.appendChild( styleElem );
668 mapElem.appendChild( stylesElem );
672 mGridStack->writeXml( mapElem, doc, context );
675 mOverviewStack->writeXml( mapElem, doc, context );
678 QDomElement atlasElem = doc.createElement( QStringLiteral(
"AtlasMap" ) );
679 atlasElem.setAttribute( QStringLiteral(
"atlasDriven" ), mAtlasDriven );
680 atlasElem.setAttribute( QStringLiteral(
"scalingMode" ), mAtlasScalingMode );
681 atlasElem.setAttribute( QStringLiteral(
"margin" ),
qgsDoubleToString( mAtlasMargin ) );
682 mapElem.appendChild( atlasElem );
684 mapElem.setAttribute( QStringLiteral(
"labelMargin" ), mLabelMargin.
encodeMeasurement() );
685 mapElem.setAttribute( QStringLiteral(
"mapFlags" ),
static_cast< int>( mMapFlags ) );
687 QDomElement labelBlockingItemsElem = doc.createElement( QStringLiteral(
"labelBlockingItems" ) );
688 for (
const auto &item : std::as_const( mBlockingLabelItems ) )
693 QDomElement blockingItemElem = doc.createElement( QStringLiteral(
"item" ) );
694 blockingItemElem.setAttribute( QStringLiteral(
"uuid" ), item->uuid() );
695 labelBlockingItemsElem.appendChild( blockingItemElem );
697 mapElem.appendChild( labelBlockingItemsElem );
700 mapElem.setAttribute( QStringLiteral(
"isTemporal" ),
isTemporal() ? 1 : 0 );
703 mapElem.setAttribute( QStringLiteral(
"temporalRangeBegin" ),
temporalRange().begin().toString( Qt::ISODate ) );
704 mapElem.setAttribute( QStringLiteral(
"temporalRangeEnd" ),
temporalRange().end().toString( Qt::ISODate ) );
707 mAtlasClippingSettings->
writeXml( mapElem, doc, context );
708 mItemClippingSettings->
writeXml( mapElem, doc, context );
715 mUpdatesEnabled =
false;
718 QDomNodeList extentNodeList = itemElem.elementsByTagName( QStringLiteral(
"Extent" ) );
719 if ( !extentNodeList.isEmpty() )
721 QDomElement extentElem = extentNodeList.at( 0 ).toElement();
722 double xmin, xmax, ymin, ymax;
723 xmin = extentElem.attribute( QStringLiteral(
"xmin" ) ).toDouble();
724 xmax = extentElem.attribute( QStringLiteral(
"xmax" ) ).toDouble();
725 ymin = extentElem.attribute( QStringLiteral(
"ymin" ) ).toDouble();
726 ymax = extentElem.attribute( QStringLiteral(
"ymax" ) ).toDouble();
730 QDomNodeList crsNodeList = itemElem.elementsByTagName( QStringLiteral(
"crs" ) );
732 if ( !crsNodeList.isEmpty() )
734 QDomElement crsElem = crsNodeList.at( 0 ).toElement();
740 mMapRotation = itemElem.attribute( QStringLiteral(
"mapRotation" ), QStringLiteral(
"0" ) ).toDouble();
741 mEvaluatedMapRotation = mMapRotation;
744 mFollowVisibilityPreset = itemElem.attribute( QStringLiteral(
"followPreset" ) ).compare( QLatin1String(
"true" ) ) == 0;
745 mFollowVisibilityPresetName = itemElem.attribute( QStringLiteral(
"followPresetName" ) );
748 QString keepLayerSetFlag = itemElem.attribute( QStringLiteral(
"keepLayerSet" ) );
749 if ( keepLayerSetFlag.compare( QLatin1String(
"true" ), Qt::CaseInsensitive ) == 0 )
751 mKeepLayerSet =
true;
755 mKeepLayerSet =
false;
758 QString drawCanvasItemsFlag = itemElem.attribute( QStringLiteral(
"drawCanvasItems" ), QStringLiteral(
"true" ) );
759 if ( drawCanvasItemsFlag.compare( QLatin1String(
"true" ), Qt::CaseInsensitive ) == 0 )
761 mDrawAnnotations =
true;
765 mDrawAnnotations =
false;
768 mLayerStyleOverrides.clear();
772 QDomNodeList layerSetNodeList = itemElem.elementsByTagName( QStringLiteral(
"LayerSet" ) );
773 if ( !layerSetNodeList.isEmpty() )
775 QDomElement layerSetElem = layerSetNodeList.at( 0 ).toElement();
776 QDomNodeList layerIdNodeList = layerSetElem.elementsByTagName( QStringLiteral(
"Layer" ) );
777 mLayers.reserve( layerIdNodeList.size() );
778 for (
int i = 0; i < layerIdNodeList.size(); ++i )
780 QDomElement layerElem = layerIdNodeList.at( i ).toElement();
781 QString layerId = layerElem.text();
782 QString layerName = layerElem.attribute( QStringLiteral(
"name" ) );
783 QString layerSource = layerElem.attribute( QStringLiteral(
"source" ) );
784 QString layerProvider = layerElem.attribute( QStringLiteral(
"provider" ) );
786 QgsMapLayerRef ref( layerId, layerName, layerSource, layerProvider );
793 QDomNodeList layerStylesNodeList = itemElem.elementsByTagName( QStringLiteral(
"LayerStyles" ) );
794 mKeepLayerStyles = !layerStylesNodeList.isEmpty();
795 if ( mKeepLayerStyles )
797 QDomElement layerStylesElem = layerStylesNodeList.at( 0 ).toElement();
798 QDomNodeList layerStyleNodeList = layerStylesElem.elementsByTagName( QStringLiteral(
"LayerStyle" ) );
799 for (
int i = 0; i < layerStyleNodeList.size(); ++i )
801 const QDomElement &layerStyleElement = layerStyleNodeList.at( i ).toElement();
802 QString layerId = layerStyleElement.attribute( QStringLiteral(
"layerid" ) );
803 QString layerName = layerStyleElement.attribute( QStringLiteral(
"name" ) );
804 QString layerSource = layerStyleElement.attribute( QStringLiteral(
"source" ) );
805 QString layerProvider = layerStyleElement.attribute( QStringLiteral(
"provider" ) );
806 QgsMapLayerRef ref( layerId, layerName, layerSource, layerProvider );
810 style.
readXml( layerStyleElement );
816 mNumCachedLayers = 0;
817 mCacheInvalidated =
true;
820 mOverviewStack->readXml( itemElem, doc, context );
823 mGridStack->readXml( itemElem, doc, context );
826 QDomNodeList atlasNodeList = itemElem.elementsByTagName( QStringLiteral(
"AtlasMap" ) );
827 if ( !atlasNodeList.isEmpty() )
829 QDomElement atlasElem = atlasNodeList.at( 0 ).toElement();
830 mAtlasDriven = ( atlasElem.attribute( QStringLiteral(
"atlasDriven" ), QStringLiteral(
"0" ) ) != QLatin1String(
"0" ) );
831 if ( atlasElem.hasAttribute( QStringLiteral(
"fixedScale" ) ) )
833 mAtlasScalingMode = ( atlasElem.attribute( QStringLiteral(
"fixedScale" ), QStringLiteral(
"0" ) ) != QLatin1String(
"0" ) ) ?
Fixed :
Auto;
835 else if ( atlasElem.hasAttribute( QStringLiteral(
"scalingMode" ) ) )
837 mAtlasScalingMode =
static_cast<AtlasScalingMode>( atlasElem.attribute( QStringLiteral(
"scalingMode" ) ).toInt() );
839 mAtlasMargin = atlasElem.attribute( QStringLiteral(
"margin" ), QStringLiteral(
"0.1" ) ).toDouble();
844 mMapFlags =
static_cast< MapItemFlags
>( itemElem.attribute( QStringLiteral(
"mapFlags" ),
nullptr ).toInt() );
847 mBlockingLabelItems.clear();
848 mBlockingLabelItemUuids.clear();
849 QDomNodeList labelBlockingNodeList = itemElem.elementsByTagName( QStringLiteral(
"labelBlockingItems" ) );
850 if ( !labelBlockingNodeList.isEmpty() )
852 QDomElement blockingItems = labelBlockingNodeList.at( 0 ).toElement();
853 QDomNodeList labelBlockingNodeList = blockingItems.childNodes();
854 for (
int i = 0; i < labelBlockingNodeList.size(); ++i )
856 const QDomElement &itemBlockingElement = labelBlockingNodeList.at( i ).toElement();
857 const QString itemUuid = itemBlockingElement.attribute( QStringLiteral(
"uuid" ) );
858 mBlockingLabelItemUuids << itemUuid;
862 mAtlasClippingSettings->
readXml( itemElem, doc, context );
863 mItemClippingSettings->
readXml( itemElem, doc, context );
868 setIsTemporal( itemElem.attribute( QStringLiteral(
"isTemporal" ) ).toInt() );
871 const QDateTime begin = QDateTime::fromString( itemElem.attribute( QStringLiteral(
"temporalRangeBegin" ) ), Qt::ISODate );
872 const QDateTime end = QDateTime::fromString( itemElem.attribute( QStringLiteral(
"temporalRangeEnd" ) ), Qt::ISODate );
876 mUpdatesEnabled =
true;
882 if ( mItemClippingSettings->
isActive() )
893 if ( !
mLayout || !painter || !painter->device() || !mUpdatesEnabled )
902 QRectF thisPaintRect = rect();
908 if (
mLayout->renderContext().isPreviewRender() )
911 painter->setClipRect( thisPaintRect );
912 if ( !mCacheFinalImage || mCacheFinalImage->isNull() )
915 painter->setBrush( QBrush( QColor( 125, 125, 125, 125 ) ) );
916 painter->drawRect( thisPaintRect );
917 painter->setBrush( Qt::NoBrush );
919 messageFont.setPointSize( 12 );
920 painter->setFont( messageFont );
921 painter->setPen( QColor( 255, 255, 255, 255 ) );
922 painter->drawText( thisPaintRect, Qt::AlignCenter | Qt::AlignHCenter, tr(
"Rendering map" ) );
923 if ( mPainterJob && mCacheInvalidated && !mDrawingPreview )
927 mBackgroundUpdateTimer->start( 1 );
929 else if ( !mPainterJob && !mDrawingPreview )
933 mBackgroundUpdateTimer->start( 1 );
938 if ( mCacheInvalidated && !mDrawingPreview )
942 mBackgroundUpdateTimer->start( 1 );
947 double imagePixelWidth = mCacheFinalImage->width();
948 double scale = rect().width() / imagePixelWidth;
952 painter->translate( mLastRenderedImageOffsetX + mXOffset, mLastRenderedImageOffsetY + mYOffset );
954 painter->drawImage( 0, 0, *mCacheFinalImage );
959 painter->setClipRect( thisPaintRect, Qt::NoClip );
961 mOverviewStack->drawItems( painter,
false );
962 mGridStack->drawItems( painter );
964 drawMapFrame( painter );
972 QPaintDevice *paintDevice = painter->device();
979 #if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
981 painter->setRenderHint( QPainter::LosslessImageRendering,
true );
989 int widthInPixels =
static_cast< int >( std::round(
boundingRect().width() * layoutUnitsInInches * destinationDpi ) );
990 int heightInPixels =
static_cast< int >( std::round(
boundingRect().height() * layoutUnitsInInches * destinationDpi ) );
991 QImage image = QImage( widthInPixels, heightInPixels, QImage::Format_ARGB32 );
993 image.fill( Qt::transparent );
994 image.setDotsPerMeterX(
static_cast< int >( std::round( 1000 * destinationDpi / 25.4 ) ) );
995 image.setDotsPerMeterY(
static_cast< int >( std::round( 1000 * destinationDpi / 25.4 ) ) );
996 double dotsPerMM = destinationDpi / 25.4;
997 QPainter p( &image );
1000 QRect imagePaintRect(
static_cast< int >( std::round( tl.x() * dotsPerMM ) ),
1001 static_cast< int >( std::round( tl.y() * dotsPerMM ) ),
1002 static_cast< int >( std::round( thisPaintRect.width() * dotsPerMM ) ),
1003 static_cast< int >( std::round( thisPaintRect.height() * dotsPerMM ) ) );
1004 p.setClipRect( imagePaintRect );
1006 p.translate( imagePaintRect.topLeft() );
1010 if ( shouldDrawPart( Background ) )
1012 p.scale( dotsPerMM, dotsPerMM );
1013 drawMapBackground( &p );
1014 p.scale( 1.0 / dotsPerMM, 1.0 / dotsPerMM );
1017 drawMap( &p, cExtent, imagePaintRect.size(), image.logicalDpiX() );
1022 p.scale( dotsPerMM, dotsPerMM );
1024 if ( shouldDrawPart( OverviewMapExtent ) )
1026 mOverviewStack->drawItems( &p,
false );
1028 if ( shouldDrawPart( Grid ) )
1030 mGridStack->drawItems( &p );
1035 painter->scale( 1 / dotsPerMM, 1 / dotsPerMM );
1036 painter->drawImage( QPointF( -tl.x()* dotsPerMM, -tl.y() * dotsPerMM ), image );
1037 painter->scale( dotsPerMM, dotsPerMM );
1042 if ( shouldDrawPart( Background ) )
1044 drawMapBackground( painter );
1048 painter->setClipRect( thisPaintRect );
1053 painter->translate( mXOffset, mYOffset );
1055 double dotsPerMM = paintDevice->logicalDpiX() / 25.4;
1057 painter->scale( 1 / dotsPerMM, 1 / dotsPerMM );
1059 if ( mCurrentExportPart != NotLayered )
1061 if ( !mStagedRendererJob )
1063 createStagedRenderJob( cExtent, size, paintDevice->logicalDpiX() );
1066 mStagedRendererJob->renderCurrentPart( painter );
1070 drawMap( painter, cExtent, size, paintDevice->logicalDpiX() );
1074 painter->setClipRect( thisPaintRect, Qt::NoClip );
1076 if ( shouldDrawPart( OverviewMapExtent ) )
1078 mOverviewStack->drawItems( painter,
false );
1080 if ( shouldDrawPart( Grid ) )
1082 mGridStack->drawItems( painter );
1087 if ( shouldDrawPart( Frame ) )
1089 drawMapFrame( painter );
1100 + ( layerCount + ( layerCount ? 1 : 0 ) )
1101 + ( mGridStack->hasEnabledItems() ? 1 : 0 )
1102 + ( mOverviewStack->hasEnabledItems() ? 1 : 0 )
1108 mCurrentExportPart = Start;
1110 mExportThemes = !mFollowVisibilityPreset ?
mLayout->renderContext().exportThemes() : QStringList();
1111 mExportThemeIt = mExportThemes.begin();
1116 mCurrentExportPart = NotLayered;
1117 mExportThemes.clear();
1118 mExportThemeIt = mExportThemes.begin();
1123 switch ( mCurrentExportPart )
1128 mCurrentExportPart = Background;
1134 mCurrentExportPart = Layer;
1138 if ( mStagedRendererJob )
1140 if ( mStagedRendererJob->nextPart() )
1144 mExportLabelingResults.reset( mStagedRendererJob->takeLabelingResults() );
1145 mStagedRendererJob.reset();
1149 if ( mExportThemeIt != mExportThemes.end() && ++mExportThemeIt != mExportThemes.end() )
1155 if ( mGridStack->hasEnabledItems() )
1157 mCurrentExportPart = Grid;
1163 for (
int i = 0; i < mOverviewStack->size(); ++i )
1168 mCurrentExportPart = OverviewMapExtent;
1174 case OverviewMapExtent:
1177 mCurrentExportPart = Frame;
1184 if ( isSelected() && !
mLayout->renderContext().isPreviewRender() )
1186 mCurrentExportPart = SelectionBoxes;
1191 case SelectionBoxes:
1192 mCurrentExportPart = End;
1213 switch ( mCurrentExportPart )
1223 if ( !mExportThemes.empty() && mExportThemeIt != mExportThemes.end() )
1226 if ( mStagedRendererJob )
1228 switch ( mStagedRendererJob->currentStage() )
1232 detail.
mapLayerId = mStagedRendererJob->currentLayerId();
1233 detail.
compositionMode = mStagedRendererJob->currentLayerCompositionMode();
1234 detail.
opacity = mStagedRendererJob->currentLayerOpacity();
1240 detail.
name = QStringLiteral(
"%1: %2" ).arg(
displayName(), layer->name() );
1242 else if (
mLayout->project()->mainAnnotationLayer()->id() == detail.
mapLayerId )
1248 detail.
name = QStringLiteral(
"%1: %2" ).arg(
displayName(), tr(
"Annotations" ) );
1253 const QList<QgsLayoutItemMapOverview *> res = mOverviewStack->asList();
1259 if ( item->mapLayer() && detail.
mapLayerId == item->mapLayer()->id() )
1262 detail.
name = QStringLiteral(
"%1 (%2): %3" ).arg(
displayName(), detail.
mapTheme, item->mapLayer()->name() );
1264 detail.
name = QStringLiteral(
"%1: %2" ).arg(
displayName(), item->mapLayer()->name() );
1273 detail.
mapLayerId = mStagedRendererJob->currentLayerId();
1279 detail.
name = tr(
"%1: %2 (Labels)" ).arg(
displayName(), layer->name() );
1314 case OverviewMapExtent:
1322 case SelectionBoxes:
1337 void QgsLayoutItemMap::drawMap( QPainter *painter,
const QgsRectangle &extent, QSizeF size,
double dpi )
1351 if ( shouldDrawPart( OverviewMapExtent ) )
1353 ms.setLayers( mOverviewStack->modifyMapLayerList( ms.layers() ) );
1357 #ifdef HAVE_SERVER_PYTHON_PLUGINS
1358 job.setFeatureFilterProvider(
mLayout->renderContext().featureFilterProvider() );
1364 job.renderSynchronously();
1366 mExportLabelingResults.reset( job.takeLabelingResults() );
1368 mRenderingErrors = job.errors();
1371 void QgsLayoutItemMap::recreateCachedImageInBackground()
1377 QPainter *oldPainter = mPainter.release();
1378 QImage *oldImage = mCacheRenderingImage.release();
1381 oldJob->deleteLater();
1389 mCacheRenderingImage.reset(
nullptr );
1393 Q_ASSERT( !mPainterJob );
1394 Q_ASSERT( !mPainter );
1395 Q_ASSERT( !mCacheRenderingImage );
1401 int w =
static_cast< int >( std::round( widthLayoutUnits * mPreviewScaleFactor ) );
1402 int h =
static_cast< int >( std::round( heightLayoutUnits * mPreviewScaleFactor ) );
1405 if ( w > 5000 || h > 5000 )
1410 h =
static_cast< int>( std::round( w * heightLayoutUnits / widthLayoutUnits ) );
1415 w =
static_cast< int >( std::round( h * widthLayoutUnits / heightLayoutUnits ) );
1419 if ( w <= 0 || h <= 0 )
1422 mCacheRenderingImage.reset(
new QImage( w, h, QImage::Format_ARGB32 ) );
1425 mCacheRenderingImage->setDotsPerMeterX(
static_cast< int >( std::round( 1000 * w / widthLayoutUnits ) ) );
1426 mCacheRenderingImage->setDotsPerMeterY(
static_cast< int >( std::round( 1000 * h / heightLayoutUnits ) ) );
1429 mCacheRenderingImage->fill( QColor( 255, 255, 255, 0 ).rgba() );
1434 if ( mItemClippingSettings->
isActive() )
1436 QPainter p( mCacheRenderingImage.get() );
1438 p.setPen( Qt::NoPen );
1440 p.scale( mCacheRenderingImage->width() / widthLayoutUnits, mCacheRenderingImage->height() / heightLayoutUnits );
1450 mCacheInvalidated =
false;
1451 mPainter.reset(
new QPainter( mCacheRenderingImage.get() ) );
1454 if ( shouldDrawPart( OverviewMapExtent ) )
1456 settings.setLayers( mOverviewStack->modifyMapLayerList( settings.layers() ) );
1461 mPainterJob->start();
1473 mDrawingPreview =
false;
1496 if (
layout()->renderContext().isPreviewRender() )
1499 jobMapSettings.
setRotation( mEvaluatedMapRotation );
1503 if ( includeLayerSettings )
1508 if ( !
mLayout->project()->mainAnnotationLayer()->isEmpty() )
1511 layers.insert( 0,
mLayout->project()->mainAnnotationLayer() );
1518 if ( !
mLayout->renderContext().isPreviewRender() )
1561 if ( mEvaluatedLabelMargin.
length() > 0 )
1564 visiblePoly.append( visiblePoly.at( 0 ) );
1565 const double layoutLabelMargin =
mLayout->convertToLayoutUnits( mEvaluatedLabelMargin );
1566 const double layoutLabelMarginInMapUnits = layoutLabelMargin / rect().width() * jobMapSettings.
extent().
width();
1568 mapBoundaryGeom = mapBoundaryGeom.
buffer( -layoutLabelMarginInMapUnits, 0 );
1569 labelBoundary = mapBoundaryGeom;
1572 if ( !mBlockingLabelItems.isEmpty() )
1585 if ( mAtlasClippingSettings->
enabled() &&
mLayout->reportContext().feature().isValid() )
1596 if ( !labelBoundary.
isEmpty() )
1598 labelBoundary = clipGeom.
intersection( labelBoundary );
1602 labelBoundary = clipGeom;
1607 if ( mItemClippingSettings->
isActive() )
1616 const double layoutLabelMargin =
mLayout->convertToLayoutUnits( mEvaluatedLabelMargin );
1617 const double layoutLabelMarginInMapUnits = layoutLabelMargin / rect().width() * jobMapSettings.
extent().
width();
1619 mapBoundaryGeom = mapBoundaryGeom.
buffer( -layoutLabelMarginInMapUnits, 0 );
1620 if ( !labelBoundary.
isEmpty() )
1622 labelBoundary = mapBoundaryGeom.
intersection( labelBoundary );
1626 labelBoundary = mapBoundaryGeom;
1632 if ( !labelBoundary.
isNull() )
1635 return jobMapSettings;
1642 mBlockingLabelItems.clear();
1643 for (
const QString &
uuid : std::as_const( mBlockingLabelItemUuids ) )
1652 mOverviewStack->finalizeRestoreFromXml();
1653 mGridStack->finalizeRestoreFromXml();
1665 return mCurrentRectangle;
1679 const double mapScale =
scale();
1703 QVariantList layersIds;
1713 const QList<QgsMapLayer *> layersInMap =
layersToRender( &context );
1715 layersIds.reserve( layersInMap.count() );
1716 layers.reserve( layersInMap.count() );
1719 layersIds << layer->id();
1725 scope->
addFunction( QStringLiteral(
"is_layer_visible" ),
new QgsExpressionContextUtils::GetLayerVisibility( layersInMap,
scale() ) );
1731 #if 0 // not relevant here! (but left so as to respect all the dangerous warnings in QgsExpressionContextUtils::mapSettingsScope)
1744 if ( extentWidth <= 0 )
1748 return rect().width() / extentWidth;
1753 double dx = mXOffset;
1754 double dy = mYOffset;
1755 transformShift( dx, dy );
1756 QPolygonF poly = calculateVisibleExtentPolygon(
false );
1757 poly.translate( -dx, -dy );
1763 if ( !mBlockingLabelItems.contains( item ) )
1764 mBlockingLabelItems.append( item );
1771 mBlockingLabelItems.removeAll( item );
1778 return mBlockingLabelItems.contains( item );
1783 return mPreviewLabelingResults.get();
1792 if ( mOverviewStack )
1794 for (
int i = 0; i < mOverviewStack->size(); ++i )
1796 if ( mOverviewStack->item( i )->accept( visitor ) )
1803 for (
int i = 0; i < mGridStack->size(); ++i )
1805 if ( mGridStack->item( i )->accept( visitor ) )
1818 mRenderedFeatureHandlers.append( handler );
1823 mRenderedFeatureHandlers.removeAll( handler );
1829 if ( mapPoly.empty() )
1831 return QPointF( 0, 0 );
1836 double dx = mapCoords.x() - rotationPoint.
x();
1837 double dy = mapCoords.y() - rotationPoint.
y();
1839 QgsPointXY backRotatedCoords( rotationPoint.
x() + dx, rotationPoint.
y() + dy );
1842 double xItem = rect().width() * ( backRotatedCoords.
x() - unrotatedExtent.
xMinimum() ) / unrotatedExtent.
width();
1843 double yItem = rect().height() * ( 1 - ( backRotatedCoords.
y() - unrotatedExtent.
yMinimum() ) / unrotatedExtent.
height() );
1844 return QPointF( xItem, yItem );
1858 mapPolygon( newExtent, poly );
1859 QRectF bRect = poly.boundingRect();
1873 mCacheInvalidated =
true;
1879 QRectF rectangle = rect();
1880 double frameExtension =
frameEnabled() ? pen().widthF() / 2.0 : 0.0;
1882 double topExtension = 0.0;
1883 double rightExtension = 0.0;
1884 double bottomExtension = 0.0;
1885 double leftExtension = 0.0;
1888 mGridStack->calculateMaxGridExtension( topExtension, rightExtension, bottomExtension, leftExtension );
1890 topExtension = std::max( topExtension, frameExtension );
1891 rightExtension = std::max( rightExtension, frameExtension );
1892 bottomExtension = std::max( bottomExtension, frameExtension );
1893 leftExtension = std::max( leftExtension, frameExtension );
1895 rectangle.setLeft( rectangle.left() - leftExtension );
1896 rectangle.setRight( rectangle.right() + rightExtension );
1897 rectangle.setTop( rectangle.top() - topExtension );
1898 rectangle.setBottom( rectangle.bottom() + bottomExtension );
1899 if ( rectangle != mCurrentRectangle )
1901 prepareGeometryChange();
1902 mCurrentRectangle = rectangle;
1930 refreshMapExtents( &context );
1932 if ( mExtent != beforeExtent )
1939 refreshLabelMargin(
false );
1943 const QString previousTheme = mLastEvaluatedThemeName.isEmpty() ? mFollowVisibilityPresetName : mLastEvaluatedThemeName;
1945 if ( mLastEvaluatedThemeName != previousTheme )
1963 mCacheInvalidated =
true;
1968 void QgsLayoutItemMap::layersAboutToBeRemoved(
const QList<QgsMapLayer *> &layers )
1970 if ( !mLayers.isEmpty() || mLayerStyleOverrides.isEmpty() )
1974 mLayerStyleOverrides.remove( layer->id() );
1976 _qgis_removeLayers( mLayers,
layers );
1980 void QgsLayoutItemMap::painterJobFinished()
1983 mPreviewLabelingResults.reset( mPainterJob->takeLabelingResults() );
1984 mPainterJob.reset(
nullptr );
1985 mPainter.reset(
nullptr );
1986 mCacheFinalImage = std::move( mCacheRenderingImage );
1987 mLastRenderedImageOffsetX = 0;
1988 mLastRenderedImageOffsetY = 0;
1994 void QgsLayoutItemMap::shapeChanged()
1999 double w = rect().width();
2000 double h = rect().height();
2003 double newWidth = mExtent.
width();
2005 double newHeight = newWidth * h / w;
2010 refreshMapExtents();
2017 void QgsLayoutItemMap::mapThemeChanged(
const QString &theme )
2019 if ( theme == mCachedLayerStyleOverridesPresetName )
2020 mCachedLayerStyleOverridesPresetName.clear();
2023 void QgsLayoutItemMap::currentMapThemeRenamed(
const QString &theme,
const QString &newTheme )
2025 if ( theme == mFollowVisibilityPresetName )
2027 mFollowVisibilityPresetName = newTheme;
2031 void QgsLayoutItemMap::connectUpdateSlot()
2039 this, &QgsLayoutItemMap::layersAboutToBeRemoved );
2043 if ( layers().isEmpty() )
2072 if ( mAtlasScalingMode == Predefined )
2073 updateAtlasFeature();
2079 QPolygonF thisExtent = calculateVisibleExtentPolygon(
false );
2080 QTransform mapTransform;
2081 QPolygonF thisRectPoly = QPolygonF( QRectF( 0, 0, rect().width(), rect().height() ) );
2083 thisRectPoly.pop_back();
2084 thisExtent.pop_back();
2086 QPolygonF thisItemPolyInLayout = mapToScene( thisRectPoly );
2089 QTransform::quadToQuad( thisItemPolyInLayout, thisExtent, mapTransform );
2090 return mapTransform;
2093 QList<QgsLabelBlockingRegion> QgsLayoutItemMap::createLabelBlockingRegions(
const QgsMapSettings & )
const
2096 QList< QgsLabelBlockingRegion > blockers;
2097 blockers.reserve( mBlockingLabelItems.count() );
2098 for (
const auto &item : std::as_const( mBlockingLabelItems ) )
2105 if ( item->property(
"wasVisible" ).isValid() )
2107 if ( !item->property(
"wasVisible" ).toBool() )
2110 else if ( !item->isVisible() )
2113 QPolygonF itemRectInMapCoordinates = mapTransform.map( item->mapToScene( item->rect() ) );
2114 itemRectInMapCoordinates.append( itemRectInMapCoordinates.at( 0 ) );
2123 return mLabelMargin;
2128 mLabelMargin = margin;
2129 refreshLabelMargin(
false );
2132 void QgsLayoutItemMap::updateToolTip()
2141 if ( mFollowVisibilityPreset )
2143 presetName = mFollowVisibilityPresetName;
2147 else if ( !mExportThemes.empty() && mExportThemeIt != mExportThemes.end() )
2148 presetName = *mExportThemeIt;
2159 QList<QgsMapLayer *> renderLayers;
2161 QString presetName = themeToRender( *evalContext );
2162 if ( !presetName.isEmpty() )
2164 if (
mLayout->project()->mapThemeCollection()->hasMapTheme( presetName ) )
2165 renderLayers =
mLayout->project()->mapThemeCollection()->mapThemeVisibleLayers( presetName );
2167 renderLayers =
mLayout->project()->mapThemeCollection()->masterVisibleLayers();
2169 else if ( !
layers().isEmpty() )
2175 renderLayers =
mLayout->project()->mapThemeCollection()->masterVisibleLayers();
2182 renderLayers.clear();
2184 const QStringList layerNames = ddLayers.split(
'|' );
2186 for (
const QString &name : layerNames )
2188 const QList< QgsMapLayer * > matchingLayers =
mLayout->project()->mapLayersByName( name );
2191 renderLayers << layer;
2200 int removeAt = renderLayers.indexOf(
mLayout->reportContext().layer() );
2201 if ( removeAt != -1 )
2203 renderLayers.removeAt( removeAt );
2208 renderLayers.erase( std::remove_if( renderLayers.begin(), renderLayers.end(), [](
QgsMapLayer * layer )
2210 return !layer || !layer->isValid();
2211 } ), renderLayers.end() );
2213 return renderLayers;
2216 QMap<QString, QString> QgsLayoutItemMap::layerStyleOverridesToRender(
const QgsExpressionContext &context )
const
2218 QString presetName = themeToRender( context );
2219 if ( !presetName.isEmpty() )
2221 if (
mLayout->project()->mapThemeCollection()->hasMapTheme( presetName ) )
2223 if ( presetName != mCachedLayerStyleOverridesPresetName )
2226 mCachedPresetLayerStyleOverrides =
mLayout->project()->mapThemeCollection()->mapThemeStyleOverrides( presetName );
2227 mCachedLayerStyleOverridesPresetName = presetName;
2230 return mCachedPresetLayerStyleOverrides;
2233 return QMap<QString, QString>();
2235 else if ( mFollowVisibilityPreset )
2237 QString presetName = mFollowVisibilityPresetName;
2240 if (
mLayout->project()->mapThemeCollection()->hasMapTheme( presetName ) )
2242 if ( presetName.isEmpty() || presetName != mCachedLayerStyleOverridesPresetName )
2245 mCachedPresetLayerStyleOverrides =
mLayout->project()->mapThemeCollection()->mapThemeStyleOverrides( presetName );
2246 mCachedLayerStyleOverridesPresetName = presetName;
2249 return mCachedPresetLayerStyleOverrides;
2252 return QMap<QString, QString>();
2254 else if ( mKeepLayerStyles )
2256 return mLayerStyleOverrides;
2260 return QMap<QString, QString>();
2264 QgsRectangle QgsLayoutItemMap::transformedExtent()
const
2266 double dx = mXOffset;
2267 double dy = mYOffset;
2268 transformShift( dx, dy );
2272 void QgsLayoutItemMap::mapPolygon(
const QgsRectangle &extent, QPolygonF &poly )
const
2282 poly << QPointF( poly.at( 0 ) );
2294 poly << QPointF( rotationPoint.x() - dx, rotationPoint.y() - dy );
2300 poly << QPointF( rotationPoint.x() - dx, rotationPoint.y() - dy );
2306 poly << QPointF( rotationPoint.x() - dx, rotationPoint.y() - dy );
2312 poly << QPointF( rotationPoint.x() - dx, rotationPoint.y() - dy );
2315 poly << QPointF( poly.at( 0 ) );
2318 void QgsLayoutItemMap::transformShift(
double &xShift,
double &yShift )
const
2321 double dxScaled = xShift * mmToMapUnits;
2322 double dyScaled = - yShift * mmToMapUnits;
2337 const QList< QgsAnnotation * > annotations =
mLayout->project()->annotationManager()->annotations();
2338 if ( annotations.isEmpty() )
2348 if ( !annotation || !annotation->isVisible() )
2352 if ( annotation->mapLayer() && !
layers.contains( annotation->mapLayer() ) )
2355 drawAnnotation( annotation, rc );
2369 double itemX, itemY;
2372 QPointF mapPos = layoutMapPosForItem( annotation );
2381 context.
painter()->translate( itemX, itemY );
2384 double dotsPerMM = context.
painter()->device()->logicalDpiX() / 25.4;
2385 context.
painter()->scale( 1 / dotsPerMM, 1 / dotsPerMM );
2387 annotation->
render( context );
2390 QPointF QgsLayoutItemMap::layoutMapPosForItem(
const QgsAnnotation *annotation )
const
2393 return QPointF( 0, 0 );
2402 if ( annotationCrs !=
crs() )
2409 t.transformInPlace( mapX, mapY, z );
2419 void QgsLayoutItemMap::drawMapFrame( QPainter *p )
2430 void QgsLayoutItemMap::drawMapBackground( QPainter *p )
2441 bool QgsLayoutItemMap::shouldDrawPart( QgsLayoutItemMap::PartType part )
const
2443 if ( mCurrentExportPart == NotLayered )
2461 return mCurrentExportPart == Layer;
2464 return mCurrentExportPart == Grid && mGridStack->hasEnabledItems();
2466 case OverviewMapExtent:
2467 return mCurrentExportPart == OverviewMapExtent && mOverviewStack->hasEnabledItems();
2472 case SelectionBoxes:
2473 return mCurrentExportPart == SelectionBoxes && isSelected();
2494 bool useDdXMin =
false;
2495 bool useDdXMax =
false;
2496 bool useDdYMin =
false;
2497 bool useDdYMax =
false;
2528 if ( newExtent != mExtent )
2534 double currentWidthHeightRatio = mExtent.
width() / mExtent.
height();
2535 double newWidthHeightRatio = newExtent.
width() / newExtent.
height();
2537 if ( currentWidthHeightRatio < newWidthHeightRatio )
2540 double newHeight = newExtent.
width() / currentWidthHeightRatio;
2541 double deltaHeight = newHeight - newExtent.
height();
2548 double newWidth = currentWidthHeightRatio * newExtent.
height();
2549 double deltaWidth = newWidth - newExtent.
width();
2554 mExtent = newExtent;
2564 newExtent = mExtent;
2567 if ( useDdXMax || useDdXMin || useDdYMax || useDdYMin )
2571 if ( useDdXMin && !useDdXMax )
2577 else if ( !useDdXMin && useDdXMax )
2583 if ( useDdYMin && !useDdYMax )
2589 else if ( !useDdYMin && useDdYMax )
2596 if ( newExtent != mExtent )
2598 mExtent = newExtent;
2615 void QgsLayoutItemMap::refreshLabelMargin(
bool updateItem )
2628 void QgsLayoutItemMap::updateAtlasFeature()
2647 if ( mAtlasScalingMode ==
Fixed || mAtlasScalingMode ==
Predefined || isPointLayer )
2652 double originalScale = calc.
calculate( originalExtent, rect().width() );
2653 double geomCenterX = ( xa1 + xa2 ) / 2.0;
2654 double geomCenterY = ( ya1 + ya2 ) / 2.0;
2655 QVector<qreal> scales;
2657 if ( !
mLayout->reportContext().predefinedScales().empty() )
2658 scales =
mLayout->reportContext().predefinedScales();
2660 scales =
mLayout->renderContext().predefinedScales();
2662 if ( mAtlasScalingMode ==
Fixed || scales.isEmpty() || ( isPointLayer && mAtlasScalingMode !=
Predefined ) )
2665 double xMin = geomCenterX - originalExtent.
width() / 2.0;
2666 double yMin = geomCenterY - originalExtent.
height() / 2.0;
2669 xMin + originalExtent.
width(),
2670 yMin + originalExtent.
height() );
2674 double newScale = calc.
calculate( newExtent, rect().width() );
2675 newExtent.
scale( originalScale / newScale );
2680 double newWidth = originalExtent.
width();
2681 double newHeight = originalExtent.
height();
2682 for (
int i = 0; i < scales.size(); i++ )
2684 double ratio = scales[i] / originalScale;
2685 newWidth = originalExtent.
width() * ratio;
2686 newHeight = originalExtent.
height() * ratio;
2689 double xMin = geomCenterX - newWidth / 2.0;
2690 double yMin = geomCenterY - newHeight / 2.0;
2698 double newScale = calc.
calculate( newExtent, rect().width() );
2699 newExtent.
scale( scales[i] / newScale );
2709 else if ( mAtlasScalingMode ==
Auto )
2713 double geomRatio = bounds.
width() / bounds.
height();
2714 double mapRatio = originalExtent.
width() / originalExtent.
height();
2717 if ( geomRatio < mapRatio )
2720 double adjWidth = ( mapRatio * bounds.
height() - bounds.
width() ) / 2.0;
2725 else if ( geomRatio > mapRatio )
2728 double adjHeight = ( bounds.
width() / mapRatio - bounds.
height() ) / 2.0;
2734 const double evaluatedAtlasMargin =
atlasMargin();
2735 if ( evaluatedAtlasMargin > 0.0 )
2737 newExtent.
scale( 1 + evaluatedAtlasMargin );
2753 if ( mEvaluatedMapRotation != 0.0 )
2763 double dx = std::max( std::abs( prevCenter.
x() - bounds.
xMinimum() ),
2764 std::abs( prevCenter.
x() - bounds.
xMaximum() ) );
2765 double dy = std::max( std::abs( prevCenter.
y() - bounds.
yMinimum() ),
2766 std::abs( prevCenter.
y() - bounds.
yMaximum() ) );
2769 center.
x() + dx, center.
y() + dy );
2777 void QgsLayoutItemMap::createStagedRenderJob(
const QgsRectangle &extent,
const QSizeF size,
double dpi )
2780 settings.
setLayers( mOverviewStack->modifyMapLayerList( settings.
layers() ) );
2782 mStagedRendererJob = std::make_unique< QgsMapRendererStagedRenderJob >( settings,
2785 : QgsMapRendererStagedRenderJob::Flags() );
2786 mStagedRendererJob->start();
2802 this, &QgsLayoutItemMapAtlasClippingSettings::layersAboutToBeRemoved );
2808 return mClipToAtlasFeature;
2813 if (
enabled == mClipToAtlasFeature )
2816 mClipToAtlasFeature =
enabled;
2822 return mFeatureClippingType;
2827 if ( mFeatureClippingType == type )
2830 mFeatureClippingType = type;
2836 return mForceLabelsInsideFeature;
2841 if ( forceInside == mForceLabelsInsideFeature )
2844 mForceLabelsInsideFeature = forceInside;
2850 return mRestrictToLayers;
2855 if ( mRestrictToLayers ==
enabled )
2864 return _qgis_listRefToRaw( mLayersToClip );
2875 QDomElement settingsElem = document.createElement( QStringLiteral(
"atlasClippingSettings" ) );
2876 settingsElem.setAttribute( QStringLiteral(
"enabled" ), mClipToAtlasFeature ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
2877 settingsElem.setAttribute( QStringLiteral(
"forceLabelsInside" ), mForceLabelsInsideFeature ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
2878 settingsElem.setAttribute( QStringLiteral(
"clippingType" ), QString::number(
static_cast<int>( mFeatureClippingType ) ) );
2879 settingsElem.setAttribute( QStringLiteral(
"restrictLayers" ), mRestrictToLayers ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
2882 QDomElement layerSetElem = document.createElement( QStringLiteral(
"layersToClip" ) );
2887 QDomElement layerElem = document.createElement( QStringLiteral(
"Layer" ) );
2888 QDomText layerIdText = document.createTextNode( layerRef.layerId );
2889 layerElem.appendChild( layerIdText );
2891 layerElem.setAttribute( QStringLiteral(
"name" ), layerRef.name );
2892 layerElem.setAttribute( QStringLiteral(
"source" ), layerRef.source );
2893 layerElem.setAttribute( QStringLiteral(
"provider" ), layerRef.provider );
2895 layerSetElem.appendChild( layerElem );
2897 settingsElem.appendChild( layerSetElem );
2899 element.appendChild( settingsElem );
2905 const QDomElement settingsElem = element.firstChildElement( QStringLiteral(
"atlasClippingSettings" ) );
2907 mClipToAtlasFeature = settingsElem.attribute( QStringLiteral(
"enabled" ), QStringLiteral(
"0" ) ).toInt();
2908 mForceLabelsInsideFeature = settingsElem.attribute( QStringLiteral(
"forceLabelsInside" ), QStringLiteral(
"0" ) ).toInt();
2910 mRestrictToLayers = settingsElem.attribute( QStringLiteral(
"restrictLayers" ), QStringLiteral(
"0" ) ).toInt();
2912 mLayersToClip.clear();
2913 QDomNodeList layerSetNodeList = settingsElem.elementsByTagName( QStringLiteral(
"layersToClip" ) );
2914 if ( !layerSetNodeList.isEmpty() )
2916 QDomElement layerSetElem = layerSetNodeList.at( 0 ).toElement();
2917 QDomNodeList layerIdNodeList = layerSetElem.elementsByTagName( QStringLiteral(
"Layer" ) );
2918 mLayersToClip.reserve( layerIdNodeList.size() );
2919 for (
int i = 0; i < layerIdNodeList.size(); ++i )
2921 QDomElement layerElem = layerIdNodeList.at( i ).toElement();
2922 QString layerId = layerElem.text();
2923 QString layerName = layerElem.attribute( QStringLiteral(
"name" ) );
2924 QString layerSource = layerElem.attribute( QStringLiteral(
"source" ) );
2925 QString layerProvider = layerElem.attribute( QStringLiteral(
"provider" ) );
2927 QgsMapLayerRef ref( layerId, layerName, layerSource, layerProvider );
2930 mLayersToClip << ref;
2937 void QgsLayoutItemMapAtlasClippingSettings::layersAboutToBeRemoved(
const QList<QgsMapLayer *> &layers )
2939 if ( !mLayersToClip.isEmpty() )
2941 _qgis_removeLayers( mLayersToClip, layers );
2956 return mEnabled && mClipPathSource;
2971 if ( mClipPathSource )
2974 mClipPathSource->refresh();
2983 QgsGeometry clipGeom( mClipPathSource->clipPath() );
2994 QgsGeometry clipGeom( mClipPathSource->clipPath() );
2995 clipGeom.
transform( mMap->sceneTransform().inverted() );
3010 if ( mClipPathSource == item )
3013 if ( mClipPathSource )
3022 mClipPathSource = item;
3024 if ( mClipPathSource )
3033 mClipPathSource->refresh();
3047 return mClipPathSource;
3052 return mFeatureClippingType;
3057 if ( mFeatureClippingType == type )
3060 mFeatureClippingType = type;
3066 return mForceLabelsInsideClipPath;
3071 if ( forceInside == mForceLabelsInsideClipPath )
3074 mForceLabelsInsideClipPath = forceInside;
3080 QDomElement settingsElem = document.createElement( QStringLiteral(
"itemClippingSettings" ) );
3081 settingsElem.setAttribute( QStringLiteral(
"enabled" ), mEnabled ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
3082 settingsElem.setAttribute( QStringLiteral(
"forceLabelsInside" ), mForceLabelsInsideClipPath ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
3083 settingsElem.setAttribute( QStringLiteral(
"clippingType" ), QString::number(
static_cast<int>( mFeatureClippingType ) ) );
3084 if ( mClipPathSource )
3085 settingsElem.setAttribute( QStringLiteral(
"clipSource" ), mClipPathSource->uuid() );
3087 settingsElem.setAttribute( QStringLiteral(
"clipSource" ), QString() );
3089 element.appendChild( settingsElem );
3095 const QDomElement settingsElem = element.firstChildElement( QStringLiteral(
"itemClippingSettings" ) );
3097 mEnabled = settingsElem.attribute( QStringLiteral(
"enabled" ), QStringLiteral(
"0" ) ).toInt();
3098 mForceLabelsInsideClipPath = settingsElem.attribute( QStringLiteral(
"forceLabelsInside" ), QStringLiteral(
"0" ) ).toInt();
3100 mClipPathUuid = settingsElem.attribute( QStringLiteral(
"clipSource" ) );
3107 if ( !mClipPathUuid.isEmpty() )