Skip to content

Commit c5b3443

Browse files
committedJul 28, 2020
Don't draw items which are a clip source for a map
1 parent 2f3258c commit c5b3443

File tree

5 files changed

+93
-0
lines changed

5 files changed

+93
-0
lines changed
 

‎python/core/auto_generated/layout/qgslayoututils.sip.in

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,13 @@ This method will return an optimal round number which falls within the given ran
244244
the largest "pretty" number possible.
245245

246246
.. versionadded:: 3.10
247+
%End
248+
249+
static bool itemIsAClippingSource( const QgsLayoutItem *item );
250+
%Docstring
251+
Returns ``True`` if an ``item`` is a clipping item for another layout item.
252+
253+
.. versionadded:: 3.16
247254
%End
248255

249256
};

‎src/core/layout/qgslayoutitem.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,9 @@ bool QgsLayoutItem::shouldBlockUndoCommands() const
589589

590590
bool QgsLayoutItem::shouldDrawItem() const
591591
{
592+
if ( mLayout && QgsLayoutUtils::itemIsAClippingSource( this ) )
593+
return false;
594+
592595
if ( !mLayout || mLayout->renderContext().isPreviewRender() )
593596
{
594597
//preview mode so OK to draw item

‎src/core/layout/qgslayoututils.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,22 @@ double QgsLayoutUtils::calculatePrettySize( const double minimumSize, const doub
461461
}
462462
}
463463

464+
bool QgsLayoutUtils::itemIsAClippingSource( const QgsLayoutItem *item )
465+
{
466+
if ( !( item->itemFlags() & QgsLayoutItem::FlagProvidesClipPath ) )
467+
return false; // not a clipping provider, so shortcut out
468+
469+
// current only maps can be clipped
470+
QList< QgsLayoutItemMap * > maps;
471+
item->layout()->layoutItems( maps );
472+
for ( QgsLayoutItemMap *map : qgis::as_const( maps ) )
473+
{
474+
if ( map->itemClippingSettings()->isActive() && map->itemClippingSettings()->sourceItem() == item )
475+
return true;
476+
}
477+
return false;
478+
}
479+
464480
double QgsLayoutUtils::pointsToMM( const double pointSize )
465481
{
466482
//conversion to mm based on 1 point = 1/72 inch

‎src/core/layout/qgslayoututils.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,13 @@ class CORE_EXPORT QgsLayoutUtils
232232
*/
233233
static double calculatePrettySize( double minimumSize, double maximumSize );
234234

235+
/**
236+
* Returns TRUE if an \a item is a clipping item for another layout item.
237+
*
238+
* \since QGIS 3.16
239+
*/
240+
static bool itemIsAClippingSource( const QgsLayoutItem *item );
241+
235242
private:
236243

237244
//! Scale factor for upscaling fontsize and downscaling painter

‎tests/src/python/test_qgslayoutmap.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,66 @@ def testClippingOverview(self):
662662
self.report += checker.report()
663663
self.assertTrue(result, message)
664664

665+
def testClippingHideClipSource(self):
666+
"""
667+
When an item is set to be the clip source, it shouldn't render anything itself
668+
"""
669+
format = QgsTextFormat()
670+
format.setFont(QgsFontUtils.getStandardTestFont("Bold"))
671+
format.setSize(30)
672+
format.setNamedStyle("Bold")
673+
format.setColor(QColor(0, 0, 0))
674+
settings = QgsPalLayerSettings()
675+
settings.setFormat(format)
676+
settings.fieldName = "'XXXX'"
677+
settings.isExpression = True
678+
settings.placement = QgsPalLayerSettings.OverPoint
679+
680+
vl = QgsVectorLayer("Polygon?crs=epsg:4326&field=id:integer", "vl", "memory")
681+
682+
props = {"color": "127,255,127", 'outline_style': 'solid', 'outline_width': '1', 'outline_color': '0,0,255'}
683+
fillSymbol = QgsFillSymbol.createSimple(props)
684+
renderer = QgsSingleSymbolRenderer(fillSymbol)
685+
vl.setRenderer(renderer)
686+
687+
f = QgsFeature(vl.fields(), 1)
688+
for x in range(0, 15, 3):
689+
for y in range(0, 15, 3):
690+
f.setGeometry(QgsGeometry(QgsPoint(x, y)).buffer(1, 3))
691+
vl.dataProvider().addFeature(f)
692+
693+
vl.setLabeling(QgsVectorLayerSimpleLabeling(settings))
694+
vl.setLabelsEnabled(True)
695+
696+
p = QgsProject()
697+
698+
p.addMapLayer(vl)
699+
layout = QgsLayout(p)
700+
layout.initializeDefaults()
701+
p.setCrs(QgsCoordinateReferenceSystem('EPSG:4326'))
702+
map = QgsLayoutItemMap(layout)
703+
map.attemptSetSceneRect(QRectF(10, 10, 180, 180))
704+
map.setFrameEnabled(True)
705+
map.zoomToExtent(vl.extent())
706+
map.setLayers([vl])
707+
layout.addLayoutItem(map)
708+
709+
shape = QgsLayoutItemShape(layout)
710+
layout.addLayoutItem(shape)
711+
shape.setShapeType(QgsLayoutItemShape.Ellipse)
712+
shape.attemptSetSceneRect(QRectF(10, 10, 180, 180))
713+
714+
map.itemClippingSettings().setEnabled(True)
715+
map.itemClippingSettings().setSourceItem(shape)
716+
map.itemClippingSettings().setForceLabelsInsideClipPath(False)
717+
map.itemClippingSettings().setFeatureClippingType(QgsMapClippingRegion.FeatureClippingType.ClipToIntersection)
718+
719+
checker = QgsLayoutChecker('composermap_itemclip_nodrawsource', layout)
720+
checker.setControlPathPrefix("composer_map")
721+
result, message = checker.testLayout()
722+
self.report += checker.report()
723+
self.assertTrue(result, message)
724+
665725

666726
if __name__ == '__main__':
667727
unittest.main()

0 commit comments

Comments
 (0)
Please sign in to comment.