def testClippingBackgroundFrame(self): """ Make sure frame/background are also clipped """ vl = QgsVectorLayer("Polygon?crs=epsg:4326&field=id:integer", "vl", "memory") props = { "color": "127,255,127", 'outline_style': 'solid', 'outline_width': '1', 'outline_color': '0,0,255' } fillSymbol = QgsFillSymbol.createSimple(props) renderer = QgsSingleSymbolRenderer(fillSymbol) vl.setRenderer(renderer) f = QgsFeature(vl.fields(), 1) for x in range(0, 15, 3): for y in range(0, 15, 3): f.setGeometry(QgsGeometry(QgsPoint(x, y)).buffer(1, 3)) vl.dataProvider().addFeature(f) p = QgsProject() p.addMapLayer(vl) layout = QgsLayout(p) layout.initializeDefaults() p.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) map = QgsLayoutItemMap(layout) map.attemptSetSceneRect(QRectF(10, 10, 180, 180)) map.setFrameEnabled(True) map.setFrameStrokeWidth( QgsLayoutMeasurement(2, QgsUnitTypes.LayoutMillimeters)) map.setBackgroundEnabled(True) map.setBackgroundColor(QColor(200, 255, 200)) map.zoomToExtent(vl.extent()) map.setLayers([vl]) layout.addLayoutItem(map) shape = QgsLayoutItemShape(layout) layout.addLayoutItem(shape) shape.setShapeType(QgsLayoutItemShape.Ellipse) shape.attemptSetSceneRect(QRectF(10, 10, 180, 180)) map.itemClippingSettings().setEnabled(True) map.itemClippingSettings().setSourceItem(shape) map.itemClippingSettings().setFeatureClippingType( QgsMapClippingRegion.FeatureClippingType.ClipPainterOnly) checker = QgsLayoutChecker('composermap_itemclip_background', layout) checker.setControlPathPrefix("composer_map") result, message = checker.testLayout() TestQgsLayoutMap.report += checker.report() self.assertTrue(result, message)
def testClippedMapExtent(self): p = QgsProject() l = QgsPrintLayout(p) map = QgsLayoutItemMap(l) shape = QgsLayoutItemShape(l) l.addLayoutItem(map) map.attemptSetSceneRect(QRectF(10, 20, 100, 80)) map.zoomToExtent(QgsRectangle(100, 200, 50, 40)) l.addLayoutItem(shape) shape.setShapeType(QgsLayoutItemShape.Triangle) shape.attemptSetSceneRect(QRectF(20, 30, 70, 50)) settings = map.itemClippingSettings() settings.setEnabled(True) settings.setSourceItem(shape) geom = settings.clippedMapExtent() self.assertEqual(geom.asWkt(), 'Polygon ((-5 80, 135 80, 65 180, -5 80))')
def testBoundingRectForStrokeSizeOnRestore(self): """ Test that item bounding rect correctly accounts for stroke size on item restore """ pr = QgsProject() l = QgsLayout(pr) shape = QgsLayoutItemShape(l) shape.setShapeType(QgsLayoutItemShape.Rectangle) shape.attemptSetSceneRect(QRectF(30, 10, 100, 200)) self.assertEqual(shape.boundingRect(), QRectF(-0.15, -0.15, 100.3, 200.3)) # set a symbol with very wide stroke s = QgsFillSymbol.createSimple({ 'outline_color': '#ff0000', 'outline_width': '40', 'color': '#ff5588' }) shape.setSymbol(s) # bounding rect for item should include stroke self.assertEqual(shape.boundingRect(), QRectF(-20.0, -20.0, 140.0, 240.0)) # save the shape and restore doc = QDomDocument("testdoc") parent_elem = doc.createElement("test") doc.appendChild(parent_elem) self.assertTrue(shape.writeXml(parent_elem, doc, QgsReadWriteContext())) item_elem = parent_elem.firstChildElement("LayoutItem") self.assertFalse(item_elem.isNull()) # restore shape2 = QgsLayoutItemShape(l) self.assertTrue(shape2.readXml(item_elem, doc, QgsReadWriteContext())) # bounding rect for item should include stroke self.assertEqual(shape2.boundingRect(), QRectF(-20.0, -20.0, 140.0, 240.0))
def testClipPath(self): pr = QgsProject() l = QgsLayout(pr) shape = QgsLayoutItemShape(l) shape.setShapeType(QgsLayoutItemShape.Rectangle) shape.attemptSetSceneRect(QRectF(30, 10, 100, 200)) # must be a closed polygon, in scene coordinates! self.assertEqual(shape.clipPath().asWkt(), 'Polygon ((30 10, 130 10, 130 210, 30 210, 30 10))') self.assertTrue( int(shape.itemFlags() & QgsLayoutItem.FlagProvidesClipPath)) spy = QSignalSpy(shape.clipPathChanged) shape.setCornerRadius( QgsLayoutMeasurement(10, QgsUnitTypes.LayoutMillimeters)) self.assertTrue(shape.clipPath().asWkt(0).startswith( 'Polygon ((30 20, 30 20, 30 19, 30 19, 30 19, 30 19')) self.assertEqual(len(spy), 1) shape.setShapeType(QgsLayoutItemShape.Ellipse) self.assertEqual(len(spy), 2) self.assertTrue(shape.clipPath().asWkt(0).startswith( 'Polygon ((130 110, 130 111, 130 113, 130 114')) shape.setShapeType(QgsLayoutItemShape.Triangle) self.assertEqual(len(spy), 3) self.assertEqual(shape.clipPath().asWkt(), 'Polygon ((30 210, 130 210, 80 10, 30 210))') shape.attemptSetSceneRect(QRectF(50, 20, 80, 120)) self.assertEqual(len(spy), 4) self.assertEqual(shape.clipPath().asWkt(), 'Polygon ((50 140, 130 140, 90 20, 50 140))')
def testToMapClippingRegion(self): p = QgsProject() l = QgsPrintLayout(p) p.layoutManager().addLayout(l) map = QgsLayoutItemMap(l) shape = QgsLayoutItemShape(l) l.addLayoutItem(map) map.attemptSetSceneRect(QRectF(10, 20, 100, 80)) map.zoomToExtent(QgsRectangle(100, 200, 50, 40)) l.addLayoutItem(shape) shape.setShapeType(QgsLayoutItemShape.Triangle) shape.attemptSetSceneRect(QRectF(20, 30, 70, 50)) settings = map.itemClippingSettings() settings.setEnabled(True) settings.setFeatureClippingType( QgsMapClippingRegion.FeatureClippingType.NoClipping) settings.setSourceItem(shape) region = settings.toMapClippingRegion() self.assertEqual(region.geometry().asWkt(), 'Polygon ((-5 80, 135 80, 65 180, -5 80))') self.assertEqual(region.featureClip(), QgsMapClippingRegion.FeatureClippingType.NoClipping)
def testClippingHideClipSource(self): """ When an item is set to be the clip source, it shouldn't render anything itself """ format = QgsTextFormat() format.setFont(QgsFontUtils.getStandardTestFont("Bold")) format.setSize(30) format.setNamedStyle("Bold") format.setColor(QColor(0, 0, 0)) settings = QgsPalLayerSettings() settings.setFormat(format) settings.fieldName = "'XXXX'" settings.isExpression = True settings.placement = QgsPalLayerSettings.OverPoint vl = QgsVectorLayer("Polygon?crs=epsg:4326&field=id:integer", "vl", "memory") props = { "color": "127,255,127", 'outline_style': 'solid', 'outline_width': '1', 'outline_color': '0,0,255' } fillSymbol = QgsFillSymbol.createSimple(props) renderer = QgsSingleSymbolRenderer(fillSymbol) vl.setRenderer(renderer) f = QgsFeature(vl.fields(), 1) for x in range(0, 15, 3): for y in range(0, 15, 3): f.setGeometry(QgsGeometry(QgsPoint(x, y)).buffer(1, 3)) vl.dataProvider().addFeature(f) vl.setLabeling(QgsVectorLayerSimpleLabeling(settings)) vl.setLabelsEnabled(True) p = QgsProject() p.addMapLayer(vl) layout = QgsLayout(p) layout.initializeDefaults() p.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) map = QgsLayoutItemMap(layout) map.attemptSetSceneRect(QRectF(10, 10, 180, 180)) map.setFrameEnabled(False) map.zoomToExtent(vl.extent()) map.setLayers([vl]) layout.addLayoutItem(map) shape = QgsLayoutItemShape(layout) layout.addLayoutItem(shape) shape.setShapeType(QgsLayoutItemShape.Ellipse) shape.attemptSetSceneRect(QRectF(10, 10, 180, 180)) map.itemClippingSettings().setEnabled(True) map.itemClippingSettings().setSourceItem(shape) map.itemClippingSettings().setForceLabelsInsideClipPath(False) map.itemClippingSettings().setFeatureClippingType( QgsMapClippingRegion.FeatureClippingType.ClipToIntersection) checker = QgsLayoutChecker('composermap_itemclip_nodrawsource', layout) checker.setControlPathPrefix("composer_map") result, message = checker.testLayout() TestQgsLayoutMap.report += checker.report() self.assertTrue(result, message)