def testTrueNorth(self): """Test syncing picture to true north""" mapSettings = QgsMapSettings() mapSettings.setDestinationCrs(QgsCoordinateReferenceSystem.fromEpsgId(3575)) composition = QgsComposition(mapSettings) composerMap = QgsComposerMap(composition) composerMap.setNewExtent(QgsRectangle(-2126029.962, -2200807.749, -119078.102, -757031.156)) composition.addComposerMap(composerMap) composerPicture = QgsComposerPicture(composition) composition.addComposerPicture(composerPicture) composerPicture.setRotationMap(composerMap.id()) self.assertTrue(composerPicture.rotationMap() >= 0) composerPicture.setNorthMode(QgsComposerPicture.TrueNorth) self.assertAlmostEqual(composerPicture.pictureRotation(), 37.20, 1) # shift map composerMap.setNewExtent(QgsRectangle(2120672.293, -3056394.691, 2481640.226, -2796718.780)) self.assertAlmostEqual(composerPicture.pictureRotation(), -38.18, 1) # rotate map composerMap.setMapRotation(45) self.assertAlmostEqual(composerPicture.pictureRotation(), -38.18 + 45, 1) # add an offset composerPicture.setNorthOffset(-10) self.assertAlmostEqual(composerPicture.pictureRotation(), -38.18 + 35, 1)
def testRenderMetersInMapUnits(self): crs_wsg84 = QgsCoordinateReferenceSystem.fromOgcWmsCrs('EPSG:4326') rt_extent = QgsRectangle(13.37768985634235, 52.51625705830762, 13.37771931686235, 52.51628651882762) point_berlin_wsg84 = QgsPointXY(13.37770458660236, 52.51627178856762) length_wsg84_mapunits = 0.00001473026350140572 meters_test = 2.40 da_wsg84 = QgsDistanceArea() da_wsg84.setSourceCrs(crs_wsg84, QgsProject.instance().transformContext()) if (da_wsg84.sourceCrs().isGeographic()): da_wsg84.setEllipsoid(da_wsg84.sourceCrs().ellipsoidAcronym()) length_meter_mapunits = da_wsg84.measureLineProjected(point_berlin_wsg84, 1.0, (math.pi / 2)) meters_test_mapunits = meters_test * length_wsg84_mapunits meters_test_pixel = meters_test * length_wsg84_mapunits ms = QgsMapSettings() ms.setDestinationCrs(crs_wsg84) ms.setExtent(rt_extent) r = QgsRenderContext.fromMapSettings(ms) r.setExtent(rt_extent) self.assertEqual(r.extent().center().toString(7), point_berlin_wsg84.toString(7)) c = QgsMapUnitScale() r.setDistanceArea(da_wsg84) result_test_painterunits = r.convertToPainterUnits(meters_test, QgsUnitTypes.RenderMetersInMapUnits, c) self.assertEqual(QgsDistanceArea.formatDistance(result_test_painterunits, 7, QgsUnitTypes.DistanceUnknownUnit, True), QgsDistanceArea.formatDistance(meters_test_mapunits, 7, QgsUnitTypes.DistanceUnknownUnit, True)) result_test_mapunits = r.convertToMapUnits(meters_test, QgsUnitTypes.RenderMetersInMapUnits, c) self.assertEqual(QgsDistanceArea.formatDistance(result_test_mapunits, 7, QgsUnitTypes.DistanceDegrees, True), QgsDistanceArea.formatDistance(meters_test_mapunits, 7, QgsUnitTypes.DistanceDegrees, True)) result_test_meters = r.convertFromMapUnits(meters_test_mapunits, QgsUnitTypes.RenderMetersInMapUnits) self.assertEqual(QgsDistanceArea.formatDistance(result_test_meters, 1, QgsUnitTypes.DistanceMeters, True), QgsDistanceArea.formatDistance(meters_test, 1, QgsUnitTypes.DistanceMeters, True))
def render_layers(layer_paths): """ :param layer_paths: A list of layer paths. :return: Buffer containing output. Note caller is responsible for closing the buffer with buffer.close() :rtype: QBuffer """ layers = [] extent = None crs = QgsCoordinateReferenceSystem() crs.createFromSrid(3857) for layer_path in layer_paths: map_layer = QgsVectorLayer(layer_path, None, 'ogr') QgsMapLayerRegistry.instance().addMapLayer(map_layer) transform = QgsCoordinateTransform(map_layer.crs(), crs) print map_layer.extent().toString() layer_extent = transform.transform(map_layer.extent()) if extent is None: extent = layer_extent else: extent.combineExtentWith(layer_extent) print extent.toString() # set layer set layers.append(map_layer.id()) # add ID of every layer map_settings = QgsMapSettings() map_settings.setDestinationCrs(crs) map_settings.setCrsTransformEnabled(True) map_settings.setExtent(extent) map_settings.setOutputSize(QSize(1000, 1000)) map_settings.setLayers(layers) # job = QgsMapRendererParallelJob(settings) job = QgsMapRendererSequentialJob(map_settings) job.start() job.waitForFinished() image = job.renderedImage() # Save teh image to a buffer map_buffer = QBuffer() map_buffer.open(QIODevice.ReadWrite) image.save(map_buffer, "PNG") image.save('/tmp/test.png', 'png') # clean up QgsMapLayerRegistry.instance().removeAllMapLayers() return map_buffer
def getBaseMapSettings(cls): """ :rtype: QgsMapSettings """ ms = QgsMapSettings() crs = QgsCoordinateReferenceSystem() """:type: QgsCoordinateReferenceSystem""" crs.createFromSrid(4326) ms.setBackgroundColor(QColor(152, 219, 249)) ms.setOutputSize(QSize(420, 280)) ms.setOutputDpi(72) ms.setFlag(QgsMapSettings.Antialiasing, True) ms.setFlag(QgsMapSettings.UseAdvancedEffects, False) ms.setFlag(QgsMapSettings.ForceVectorOutput, False) # no caching? ms.setDestinationCrs(crs) return ms
def cloneMapSettings(self, oms): """ :param oms: QgsMapSettings :rtype: QgsMapSettings """ ms = QgsMapSettings() ms.setBackgroundColor(oms.backgroundColor()) ms.setOutputSize(oms.outputSize()) ms.setOutputDpi(oms.outputDpi()) ms.setFlags(oms.flags()) ms.setDestinationCrs(oms.destinationCrs()) ms.setCrsTransformEnabled(oms.hasCrsTransformEnabled()) ms.setMapUnits(oms.mapUnits()) ms.setExtent(oms.extent()) ms.setLayers(oms.layers()) return ms
def test01_export_empty(self): """test exporting with empty export settings""" # map settings canvasSize = QSize(600, 600) width = 1000. height = width * canvasSize.height() / canvasSize.width() crs = QgsCoordinateReferenceSystem(3099, QgsCoordinateReferenceSystem.EpsgCrsId) # JGD2000 / UTM zone 53N mapSettings = QgsMapSettings() mapSettings.setOutputSize(canvasSize) mapSettings.setExtent(QgsRectangle(0, 0, width, height)) mapSettings.setDestinationCrs(crs) exporter = Exporter() exporter.setMapSettings(mapSettings) err = exporter.export(outputPath(os.path.join("empty", "empty.html"))) assert err == Exporter.NO_ERROR, err
def cloneMapSettings(self, oms): """ :param QgsMapSettings oms: Other QgsMapSettings :rtype: QgsMapSettings """ ms = QgsMapSettings() ms.setBackgroundColor(oms.backgroundColor()) ms.setOutputSize(oms.outputSize()) ms.setOutputDpi(oms.outputDpi()) ms.setFlags(oms.flags()) ms.setDestinationCrs(oms.destinationCrs()) ms.setExtent(oms.extent()) ms.setOutputImageFormat(oms.outputImageFormat()) ms.setLabelingEngineSettings(oms.labelingEngineSettings()) ms.setLayers(oms.layers()) return ms
def getBaseMapSettings(cls): """ :rtype: QgsMapSettings """ ms = QgsMapSettings() crs = QgsCoordinateReferenceSystem() """:type: QgsCoordinateReferenceSystem""" # default for labeling test data: WGS 84 / UTM zone 13N crs.createFromSrid(32613) ms.setBackgroundColor(QColor(152, 219, 249)) ms.setOutputSize(QSize(420, 280)) ms.setOutputDpi(72) ms.setFlag(QgsMapSettings.Antialiasing) ms.setDestinationCrs(crs) ms.setCrsTransformEnabled(False) ms.setMapUnits(crs.mapUnits()) # meters ms.setExtent(cls.aoiExtent()) return ms
def getBaseMapSettings(cls): """ :rtype: QgsMapSettings """ ms = QgsMapSettings() crs = QgsCoordinateReferenceSystem() """:type: QgsCoordinateReferenceSystem""" # default for labeling test data: WGS 84 / UTM zone 13N crs.createFromSrid(32613) ms.setBackgroundColor(QColor(152, 219, 249)) ms.setOutputSize(QSize(420, 280)) ms.setOutputDpi(72) ms.setFlag(QgsMapSettings.Antialiasing, True) ms.setFlag(QgsMapSettings.UseAdvancedEffects, False) ms.setFlag(QgsMapSettings.ForceVectorOutput, False) # no caching? ms.setDestinationCrs(crs) ms.setExtent(cls.aoiExtent()) return ms
def testFromMapSettings(self): """ test QgsRenderContext.fromMapSettings() """ ms = QgsMapSettings() ms.setOutputSize(QSize(1000, 1000)) ms.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3111')) ms.setExtent(QgsRectangle(10000, 20000, 30000, 40000)) ms.setTextRenderFormat(QgsRenderContext.TextFormatAlwaysText) rc = QgsRenderContext.fromMapSettings(ms) self.assertEqual(rc.textRenderFormat(), QgsRenderContext.TextFormatAlwaysText) ms.setTextRenderFormat(QgsRenderContext.TextFormatAlwaysOutlines) rc = QgsRenderContext.fromMapSettings(ms) self.assertEqual(rc.textRenderFormat(), QgsRenderContext.TextFormatAlwaysOutlines) self.assertEqual(rc.mapExtent(), QgsRectangle(10000, 20000, 30000, 40000))
def renderAnnotation(self, annotation, offset): image = QImage(600, 400, QImage.Format_RGB32) image.fill(QColor(0, 0, 0, 0)) QgsRenderChecker.drawBackground(image) painter = QPainter() ms = QgsMapSettings() ms.setDestinationCrs(QgsCoordinateReferenceSystem(4326)) extent = QgsRectangle(0, 5, 40, 30) ms.setExtent(extent) ms.setOutputSize(image.size()) context = QgsRenderContext.fromMapSettings(ms) context.setPainter(painter) context.setScaleFactor(96 / 25.4) # 96 DPI painter.begin(image) painter.translate(offset.x(), offset.y()) annotation.render(context) painter.end() return image
def testIntersectionRuleBased(self): """ Test that rule based renderer using intersection clip paths correctly uses original feature area for rule evaluation, not clipped area """ poly_layer = QgsVectorLayer(os.path.join(TEST_DATA_DIR, 'polys.shp')) self.assertTrue(poly_layer.isValid()) sym1 = QgsFillSymbol.createSimple({ 'color': '#ff00ff', 'outline_color': '#000000', 'outline_width': '1' }) sym2 = QgsFillSymbol.createSimple({ 'color': '#00ffff', 'outline_color': '#000000', 'outline_width': '1' }) r1 = QgsRuleBasedRenderer.Rule(sym1, 0, 0, 'area($geometry)>25') r2 = QgsRuleBasedRenderer.Rule(sym2, 0, 0, 'ELSE') rootrule = QgsRuleBasedRenderer.Rule(None) rootrule.appendChild(r1) rootrule.appendChild(r2) renderer = QgsRuleBasedRenderer(rootrule) poly_layer.setRenderer(renderer) mapsettings = QgsMapSettings() mapsettings.setOutputSize(QSize(400, 400)) mapsettings.setOutputDpi(96) mapsettings.setDestinationCrs( QgsCoordinateReferenceSystem('EPSG:3857')) mapsettings.setExtent( QgsRectangle(-13875783.2, 2266009.4, -8690110.7, 6673344.5)) mapsettings.setLayers([poly_layer]) mapsettings.setEllipsoid('') region = QgsMapClippingRegion( QgsGeometry.fromWkt( 'Polygon ((-11725957 5368254, -12222900 4807501, -12246014 3834025, -12014878 3496059, -11259833 3518307, -10751333 3621153, -10574129 4516741, -10847640 5194995, -11105742 5325957, -11725957 5368254))' )) region.setFeatureClip( QgsMapClippingRegion.FeatureClippingType.ClipToIntersection) region2 = QgsMapClippingRegion( QgsGeometry.fromWkt( 'Polygon ((-11032549 5421399, -11533344 4693167, -11086481 4229112, -11167378 3742984, -10616504 3553984, -10161936 3925771, -9618766 4668482, -9472380 5620753, -10115709 5965063, -11032549 5421399))' )) region2.setFeatureClip( QgsMapClippingRegion.FeatureClippingType.ClipToIntersection) mapsettings.addClippingRegion(region) mapsettings.addClippingRegion(region2) renderchecker = QgsMultiRenderChecker() renderchecker.setMapSettings(mapsettings) renderchecker.setControlPathPrefix('vectorlayerrenderer') renderchecker.setControlName('expected_intersection_rule_based') result = renderchecker.runTest('expected_intersection_rule_based') self.report += renderchecker.report() self.assertTrue(result) # also try with symbol levels renderer.setUsingSymbolLevels(True) poly_layer.setRenderer(renderer) renderchecker = QgsMultiRenderChecker() renderchecker.setMapSettings(mapsettings) renderchecker.setControlPathPrefix('vectorlayerrenderer') renderchecker.setControlName('expected_intersection_rule_based') result = renderchecker.runTest('expected_intersection_rule_based') self.report += renderchecker.report() self.assertTrue(result)
def test_render_via_job_with_transform(self): """ Test rendering an annotation layer via a map render job """ layer = QgsAnnotationLayer( 'test', QgsAnnotationLayer.LayerOptions( QgsProject.instance().transformContext())) self.assertTrue(layer.isValid()) item = QgsAnnotationPolygonItem( QgsPolygon( QgsLineString([ QgsPoint(11.5, 13), QgsPoint(12, 13), QgsPoint(12, 13.5), QgsPoint(11.5, 13) ]))) item.setSymbol( QgsFillSymbol.createSimple({ 'color': '200,100,100', 'outline_color': 'black', 'outline_width': '2' })) item.setZIndex(1) i1_id = layer.addItem(item) item = QgsAnnotationLineItem( QgsLineString( [QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)])) item.setSymbol( QgsLineSymbol.createSimple({ 'color': '#ffff00', 'line_width': '3' })) item.setZIndex(2) i2_id = layer.addItem(item) item = QgsAnnotationMarkerItem(QgsPoint(12, 13)) item.setSymbol( QgsMarkerSymbol.createSimple({ 'color': '100,200,200', 'size': '6', 'outline_color': 'black' })) item.setZIndex(3) i3_id = layer.addItem(item) layer.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) settings = QgsMapSettings() settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) settings.setExtent(QgsRectangle(1250958, 1386945, 1420709, 1532518)) settings.setOutputSize(QSize(200, 200)) settings.setLayers([layer]) job = QgsMapRendererSequentialJob(settings) job.start() job.waitForFinished() # check rendered item results item_results = job.takeRenderedItemResults() item_details = item_results.renderedItems() self.assertEqual(len(item_details), 3) self.assertEqual([i.layerId() for i in item_details], [layer.id()] * 3) self.assertCountEqual([i.itemId() for i in item_details], [i1_id, i2_id, i3_id]) # bounds should be in map crs self.assertEqual( [ QgsGeometry.fromRect(i.boundingBox()).asWkt(0) for i in item_details if i.itemId() == i1_id ][0], 'Polygon ((1280174 1459732, 1335834 1459732, 1335834 1516914, 1280174 1516914, 1280174 1459732))' ) self.assertEqual( [ QgsGeometry.fromRect(i.boundingBox()).asWkt(0) for i in item_details if i.itemId() == i2_id ][0], 'Polygon ((1224514 1459732, 1335834 1459732, 1335834 1689200, 1224514 1689200, 1224514 1459732))' ) expected = 'Polygon ((1325786 1449684, 1345882 1449684, 1345882 1469780, 1325786 1469780, 1325786 1449684))' result = [ QgsGeometry.fromRect(i.boundingBox()).asWkt(0) for i in item_details if i.itemId() == i3_id ][0] self.assertTrue( compareWkt(result, expected, tol=1000), "mismatch Expected:\n{}\nGot:\n{}\n".format(expected, result))
def generate(self, writer, parameters, context, feedback): feedback.setProgress(1) extent = self.parameterAsExtent(parameters, self.EXTENT, context) self.min_zoom = self.parameterAsInt(parameters, self.ZOOM_MIN, context) self.max_zoom = self.parameterAsInt(parameters, self.ZOOM_MAX, context) dpi = self.parameterAsInt(parameters, self.DPI, context) self.tile_format = self.formats[self.parameterAsEnum(parameters, self.TILE_FORMAT, context)] tile_width = 256 tile_height = 256 wgs_crs = QgsCoordinateReferenceSystem('EPSG:4326') dest_crs = QgsCoordinateReferenceSystem('EPSG:3857') project = context.project() src_to_wgs = QgsCoordinateTransform(project.crs(), wgs_crs, context.transformContext()) wgs_to_dest = QgsCoordinateTransform(wgs_crs, dest_crs, context.transformContext()) settings = QgsMapSettings() settings.setOutputImageFormat(QImage.Format_ARGB32_Premultiplied) settings.setDestinationCrs(dest_crs) settings.setLayers(self.layers) settings.setOutputDpi(dpi) if self.tile_format == 'PNG': settings.setBackgroundColor(QColor(Qt.transparent)) self.wgs_extent = src_to_wgs.transformBoundingBox(extent) self.wgs_extent = [self.wgs_extent.xMinimum(), self.wgs_extent.yMinimum(), self.wgs_extent.xMaximum(), self.wgs_extent.yMaximum()] metatiles_by_zoom = {} metatiles_count = 0 for zoom in range(self.min_zoom, self.max_zoom + 1): metatiles = get_metatiles(self.wgs_extent, zoom, 4) metatiles_by_zoom[zoom] = metatiles metatiles_count += len(metatiles) lab_buffer_px = 100 progress = 0 tile_params = { 'format': self.tile_format, 'quality': 75, 'width': tile_width, 'height': tile_height, 'min_zoom': self.min_zoom, 'max_zoom': self.max_zoom, 'extent': self.wgs_extent, } writer.set_parameters(tile_params) for zoom in range(self.min_zoom, self.max_zoom + 1): feedback.pushConsoleInfo('Generating tiles for zoom level: %s' % zoom) for i, metatile in enumerate(metatiles_by_zoom[zoom]): if feedback.isCanceled(): break size = QSize(tile_width * metatile.rows(), tile_height * metatile.columns()) extent = QgsRectangle(*metatile.extent()) settings.setExtent(wgs_to_dest.transformBoundingBox(extent)) settings.setOutputSize(size) if hasattr(settings, 'setLabelBoundaryGeometry'): label_area = QgsRectangle(settings.extent()) lab_buffer = label_area.width() * (lab_buffer_px / size.width()) label_area.set( label_area.xMinimum() + lab_buffer, label_area.yMinimum() + lab_buffer, label_area.xMaximum() - lab_buffer, label_area.yMaximum() - lab_buffer ) settings.setLabelBoundaryGeometry(QgsGeometry.fromRect(label_area)) image = QImage(size, QImage.Format_ARGB32_Premultiplied) image.fill(Qt.transparent) dpm = settings.outputDpi() / 25.4 * 1000 image.setDotsPerMeterX(dpm) image.setDotsPerMeterY(dpm) painter = QPainter(image) job = QgsMapRendererCustomPainterJob(settings, painter) job.renderSynchronously() painter.end() # For analysing metatiles (labels, etc.) # metatile_dir = os.path.join(output_dir, str(zoom)) # os.makedirs(metatile_dir, exist_ok=True) # image.save(os.path.join(metatile_dir, 'metatile_%s.png' % i)) for r, c, tile in metatile.tiles: tile_img = image.copy(tile_width * r, tile_height * c, tile_width, tile_height) writer.write_tile(tile, tile_img) progress += 1 feedback.setProgress(100 * (progress / metatiles_count)) writer.close()
def render(self, params): self.check_required_params(params) with change_directory(self.project_root): crs = QgsCoordinateReferenceSystem() crs.createFromSrid(params.get('srs')) img = QImage( QSize(*params.get('image_size')), QImage.Format_ARGB32_Premultiplied ) dpm = 1 / 0.00028 img.setDotsPerMeterX(dpm) img.setDotsPerMeterY(dpm) # set background color bgcolor = params.get('bgcolor') if params.get('transparent'): # fully transparent bgcolor.append(0) else: # fully opaque bgcolor.append(255) color = QColor(*bgcolor) img.fill(color) map_settings = QgsMapSettings() map_settings.setBackgroundColor(color) map_settings.setDestinationCrs(crs) map_settings.setCrsTransformEnabled(True) map_settings.setExtent(QgsRectangle(*params.get('bbox'))) map_settings.setOutputDpi(img.logicalDpiX()) map_settings.setOutputSize(img.size()) map_settings.setMapUnits(crs.mapUnits()) layers = params.get('layers') self.setTransparencies(layers, params.get('transparencies')) map_settings.setLayers(layers) p = QPainter() p.begin(img) job = QgsMapRendererCustomPainterJob(map_settings, p) job.start() job.waitForFinished() map_buffer = QBuffer() map_buffer.open(QIODevice.ReadWrite) if params.get('image_format') == 'jpeg': img.save(map_buffer, 'JPEG') elif params.get('image_format') == 'png8': png8 = img.convertToFormat(QImage.Format_Indexed8) png8.save(map_buffer, "PNG") else: img.save(map_buffer, 'PNG') # clean up p.end() map_buffer.close() return map_buffer.data()
class TileSet(): """ A set of tiles """ def __init__(self, map_theme, layer, extent, tile_size, mupp, output, map_settings): """ :param map_theme: :param extent: :param layer: :param tile_size: :param mupp: :param output: :param map_settings: Map canvas map settings used for some fallback values and CRS """ self.extent = extent self.mupp = mupp self.tile_size = tile_size # TODO: Check if file exists and update instead? driver = self.getDriverForFile(output) if not driver: raise GeoAlgorithmExecutionException( u'Could not load GDAL driver for file {}'.format(output)) crs = map_settings.destinationCrs() self.x_tile_count = math.ceil(extent.width() / mupp / tile_size) self.y_tile_count = math.ceil(extent.height() / mupp / tile_size) xsize = self.x_tile_count * tile_size ysize = self.y_tile_count * tile_size self.dataset = driver.Create(output, xsize, ysize, 3) # 3 bands self.dataset.SetProjection(str(crs.toWkt())) self.dataset.SetGeoTransform( [extent.xMinimum(), mupp, 0, extent.yMaximum(), 0, -mupp]) self.image = QImage(QSize(tile_size, tile_size), QImage.Format_RGB32) self.settings = QgsMapSettings() self.settings.setCrsTransformEnabled(True) self.settings.setOutputDpi(self.image.logicalDpiX()) self.settings.setOutputImageFormat(QImage.Format_RGB32) self.settings.setDestinationCrs(crs) self.settings.setOutputSize(self.image.size()) self.settings.setMapUnits(crs.mapUnits()) self.settings.setFlag(QgsMapSettings.Antialiasing, True) self.settings.setFlag(QgsMapSettings.RenderMapTile, True) if QgsProject.instance().mapThemeCollection().hasMapTheme(map_theme): self.settings.setLayers(QgsProject.instance().mapThemeCollection(). mapThemeVisibleLayers(map_theme)) self.settings.setLayerStyleOverrides(QgsProject.instance( ).mapThemeCollection().mapThemeStyleOverrides(map_theme)) elif layer: self.settings.setLayers([layer]) else: self.settings.setLayers(map_settings.layers()) def render(self, progress): for x in range(self.x_tile_count): for y in range(self.y_tile_count): cur_tile = x * self.y_tile_count + y num_tiles = self.x_tile_count * self.y_tile_count progress.setPercentage(cur_tile * 100 / num_tiles) self.renderTile(x, y) def renderTile(self, x, y): """ Render one tile :param x: The x index of the current tile :param y: The y index of the current tile """ painter = QPainter(self.image) self.settings.setExtent( QgsRectangle( self.extent.xMinimum() + x * self.mupp * self.tile_size, self.extent.yMaximum() - (y + 1) * self.mupp * self.tile_size, self.extent.xMinimum() + (x + 1) * self.mupp * self.tile_size, self.extent.yMaximum() - y * self.mupp * self.tile_size)) job = QgsMapRendererCustomPainterJob(self.settings, painter) job.renderSynchronously() painter.end() # Needs not to be deleted or Windows will kill it too early... tmpfile = tempfile.NamedTemporaryFile(suffix='.png', delete=False) try: self.image.save(tmpfile.name) src_ds = osgeo.gdal.Open(tmpfile.name) self.dataset.WriteRaster( x * self.tile_size, y * self.tile_size, self.tile_size, self.tile_size, src_ds.ReadRaster(0, 0, self.tile_size, self.tile_size)) finally: del src_ds tmpfile.close() os.unlink(tmpfile.name) def getDriverForFile(self, filename): """ Get the GDAL driver for a filename, based on its extension. (.gpkg, .mbtiles...) """ _, extension = os.path.splitext(filename) for i in range(osgeo.gdal.GetDriverCount()): driver = osgeo.gdal.GetDriver(i) if driver.GetMetadataItem('DMD_EXTENSION') == extension[1:]: return driver
def renderer(self): qgis = QgsApplication([], False) qgis.setPrefixPath(self.settings.get('path'), True) qgis.setMaxThreads(1) qgis.initQgis() while True: try: fndata, srs, render_size, extended, \ target_box, result = self.queue.get() layer = QgsVectorLayer(fndata, 'layer', 'ogr') crs = QgsCoordinateReferenceSystem(srs.id) layer.setCrs(crs) settings = QgsMapSettings() settings.setLayers([layer.id()]) settings.setFlag(QgsMapSettings.DrawLabeling) settings.setFlag(QgsMapSettings.Antialiasing) settings.setCrsTransformEnabled(True) settings.setDestinationCrs(crs) settings.setMapUnits(crs.mapUnits()) settings.setOutputSize(QSize(*render_size)) settings.setExtent(QgsRectangle(*extended)) settings.setOutputImageFormat(QImage.Format_ARGB32) bgcolor = QColor.fromRgba(qRgba(255, 255, 255, 0)) settings.setBackgroundColor(bgcolor) settings.setOutputDpi(96) QgsMapLayerRegistry.instance().addMapLayer(layer) settings.setLayers([layer.id()]) # Создаем QImage руками чтобы можно было использовать # QgsMapRendererCustomPainterJob. Остальные не позволяют # обойти баг с рисованием поверх старого. img = QImage(settings.outputSize(), QImage.Format_ARGB32) # Эти костыли нужны для того, чтобы корректно рисовались # слои на прозрачном фоне, без этого получается каша. img.fill(QColor.fromRgba(qRgba(255, 255, 255, 255))) img.fill(QColor.fromRgba(qRgba(255, 255, 255, 0))) # DPI должно быть таким же как в settings, иначе ошибка. В QImage # разрешение указывается в точках на метр по каждой оси. dpm = settings.outputDpi() / 25.4 * 1000 img.setDotsPerMeterX(dpm) img.setDotsPerMeterY(dpm) painter = QPainter(img) job = QgsMapRendererCustomPainterJob(settings, painter) job.renderSynchronously() painter.end() QgsMapLayerRegistry.instance().removeAllMapLayers() # Преобразование QImage в PIL ba = QByteArray() bf = QBuffer(ba) bf.open(QIODevice.WriteOnly) img.save(bf, 'PNG') bf.close() buf = StringIO() buf.write(bf.data()) buf.seek(0) img = PIL.Image.open(buf) # Вырезаем нужный нам кусок изображения result.put(img.crop(target_box)) except Exception as e: self.logger.error(e.message) qgis.exitQgis()
def testRenderLayerWithReferenceScale(self): layer = QgsAnnotationLayer( 'test', QgsAnnotationLayer.LayerOptions( QgsProject.instance().transformContext())) layer.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) self.assertTrue(layer.isValid()) item = QgsAnnotationPolygonItem( QgsPolygon( QgsLineString([ QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15), QgsPoint(12, 13) ]))) item.setSymbol( QgsFillSymbol.createSimple({ 'color': '200,100,100', 'outline_color': 'black', 'outline_width': '2' })) item.setZIndex(3) i1_id = layer.addItem(item) item = QgsAnnotationLineItem( QgsLineString( [QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)])) item.setSymbol( QgsLineSymbol.createSimple({ 'color': '#ffff00', 'line_width': '3' })) item.setZIndex(2) i2_id = layer.addItem(item) item = QgsAnnotationMarkerItem(QgsPoint(12, 13)) item.setSymbol( QgsMarkerSymbol.createSimple({ 'color': '100,200,200', 'size': '6', 'outline_color': 'black' })) item.setZIndex(1) i3_id = layer.addItem(item) settings = QgsMapSettings() settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) settings.setExtent(QgsRectangle(10, 10, 18, 18)) settings.setOutputSize(QSize(300, 300)) settings.setFlag(QgsMapSettings.Antialiasing, False) rc = QgsRenderContext.fromMapSettings(settings) layer.item(i1_id).setUseSymbologyReferenceScale(True) layer.item(i1_id).setSymbologyReferenceScale(rc.rendererScale() * 2) # note item 3 has use symbology reference scale set to false, so should be ignored layer.item(i2_id).setUseSymbologyReferenceScale(False) layer.item(i2_id).setSymbologyReferenceScale(rc.rendererScale() * 2) layer.item(i3_id).setUseSymbologyReferenceScale(True) layer.item(i3_id).setSymbologyReferenceScale(rc.rendererScale() * 2) image = QImage(200, 200, QImage.Format_ARGB32) image.setDotsPerMeterX(int(96 / 25.4 * 1000)) image.setDotsPerMeterY(int(96 / 25.4 * 1000)) image.fill(QColor(255, 255, 255)) painter = QPainter(image) rc.setPainter(painter) try: renderer = layer.createMapRenderer(rc) renderer.render() finally: painter.end() self.assertTrue( self.imageCheck('layer_render_reference_scale', 'layer_render_reference_scale', image)) # also check details of rendered items item_details = renderer.takeRenderedItemDetails() self.assertEqual([i.layerId() for i in item_details], [layer.id()] * 3) self.assertCountEqual([i.itemId() for i in item_details], [i1_id, i2_id, i3_id]) self.assertEqual( [i.boundingBox() for i in item_details if i.itemId() == i1_id][0], QgsRectangle(12, 13, 14, 15)) self.assertEqual( [i.boundingBox() for i in item_details if i.itemId() == i2_id][0], QgsRectangle(11, 13, 12, 15)) self.assertEqual([ i.boundingBox().toString(1) for i in item_details if i.itemId() == i3_id ][0], '11.4,12.4 : 12.6,13.6')
def testRenderMultipleRenderersAboveAndBelow(self): poly_layer = QgsVectorLayer(os.path.join(TEST_DATA_DIR, 'polys.shp')) self.assertTrue(poly_layer.isValid()) sym1 = QgsFillSymbol.createSimple({'color': '#ffaaff', 'outline_color': '#000000', 'outline_width': '1'}) renderer = QgsSingleSymbolRenderer(sym1) poly_layer.setRenderer(renderer) # add secondary renderer, for rendering below class Gen1(QgsFeatureRendererGenerator): def id(self): return 'Gen1' def level(self): return 3 def createRenderer(self): renderer = QgsCategorizedSymbolRenderer() renderer.setClassAttribute('Name') cf1 = QgsCentroidFillSymbolLayer() cf1.setSubSymbol(QgsMarkerSymbol.createSimple( {'color': '#33aa33', 'outline_style': 'no', 'size': '5'})) sym1 = QgsFillSymbol([cf1]) cf2 = QgsCentroidFillSymbolLayer() cf2.setSubSymbol(QgsMarkerSymbol.createSimple( {'color': '#aa33aa', 'outline_style': 'no', 'size': '5'})) sym2 = QgsFillSymbol([cf2]) renderer.addCategory(QgsRendererCategory('Dam', sym1, 'Dam')) renderer.addCategory(QgsRendererCategory('Lake', sym2, 'Lake')) return renderer # add secondary renderer, for rendering below class Gen2(QgsFeatureRendererGenerator): def id(self): return 'Gen2' def level(self): return 2 def createRenderer(self): renderer = QgsCategorizedSymbolRenderer() renderer.setClassAttribute('Value < 12') cf1 = QgsCentroidFillSymbolLayer() cf1.setSubSymbol(QgsMarkerSymbol.createSimple( {'color': '#aa1111', 'outline_style': 'no', 'size': '8'})) sym1 = QgsFillSymbol([cf1]) cf2 = QgsCentroidFillSymbolLayer() cf2.setSubSymbol(QgsMarkerSymbol.createSimple( {'color': '#1111dd', 'outline_style': 'no', 'size': '8'})) sym2 = QgsFillSymbol([cf2]) renderer.addCategory(QgsRendererCategory('1', sym1, '1')) renderer.addCategory(QgsRendererCategory('0', sym2, '0')) return renderer # add secondary renderer, for rendering below class Gen1b(QgsFeatureRendererGenerator): def id(self): return 'Gen1b' def level(self): return -2 def createRenderer(self): renderer = QgsCategorizedSymbolRenderer() renderer.setClassAttribute('Name') sym1 = QgsFillSymbol.createSimple( {'color': '#ffaaff', 'outline_color': '#33aa33', 'outline_width': '3'}) sym2 = QgsFillSymbol.createSimple( {'color': '#ffaaff', 'outline_color': '#aa33aa', 'outline_width': '3'}) renderer.addCategory(QgsRendererCategory('Dam', sym1, 'Dam')) renderer.addCategory(QgsRendererCategory('Lake', sym2, 'Lake')) return renderer # add secondary renderer, for rendering below class Gen2b(QgsFeatureRendererGenerator): def id(self): return 'Gen2b' def level(self): return -3 def createRenderer(self): renderer = QgsCategorizedSymbolRenderer() renderer.setClassAttribute('Value < 12') sym1 = QgsFillSymbol.createSimple( {'color': '#ffaaff', 'outline_color': '#aa1111', 'outline_width': '5'}) sym2 = QgsFillSymbol.createSimple( {'color': '#ffaaff', 'outline_color': '#1111dd', 'outline_width': '5'}) renderer.addCategory(QgsRendererCategory('1', sym1, '1')) renderer.addCategory(QgsRendererCategory('0', sym2, '0')) return renderer poly_layer.addFeatureRendererGenerator(Gen1()) poly_layer.addFeatureRendererGenerator(Gen2()) poly_layer.addFeatureRendererGenerator(Gen1b()) poly_layer.addFeatureRendererGenerator(Gen2b()) mapsettings = QgsMapSettings() mapsettings.setOutputSize(QSize(400, 400)) mapsettings.setOutputDpi(96) mapsettings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) mapsettings.setExtent(QgsRectangle(-13875783.2, 2266009.4, -8690110.7, 6673344.5)) mapsettings.setLayers([poly_layer]) renderchecker = QgsMultiRenderChecker() renderchecker.setMapSettings(mapsettings) renderchecker.setControlPathPrefix('vectorlayerrenderer') renderchecker.setControlName('expected_multiple_renderers_both_above_below') result = renderchecker.runTest('expected_multiple_renderers_both_above_below') self.report += renderchecker.report() self.assertTrue(result) # also try with symbol levels renderer.setUsingSymbolLevels(True) poly_layer.setRenderer(renderer) renderchecker = QgsMultiRenderChecker() renderchecker.setMapSettings(mapsettings) renderchecker.setControlPathPrefix('vectorlayerrenderer') renderchecker.setControlName('expected_multiple_renderers_both_above_below') result = renderchecker.runTest('expected_multiple_renderers_both_above_below') self.report += renderchecker.report() self.assertTrue(result)
class TestQgsComposerMap(unittest.TestCase): def __init__(self, methodName): """Run once on class initialization.""" unittest.TestCase.__init__(self, methodName) # create composition with composer map self.mMapSettings = QgsMapSettings() crs = QgsCoordinateReferenceSystem(32633) self.mMapSettings.setDestinationCrs(crs) self.mComposition = QgsComposition(QgsProject.instance()) self.mComposition.setPaperSize(297, 210) self.mComposerMap = QgsComposerMap(self.mComposition, 20, 20, 200, 100) self.mComposerMap.setFrameEnabled(True) self.mComposerMap.setBackgroundColor(QColor(150, 100, 100)) self.mComposition.addComposerMap(self.mComposerMap) def testGrid(self): """Test that we can create a grid for a map.""" myRectangle = QgsRectangle(781662.375, 3339523.125, 793062.375, 3345223.125) self.mComposerMap.setNewExtent(myRectangle) self.mComposerMap.grid().setEnabled(True) self.mComposerMap.grid().setIntervalX(2000) self.mComposerMap.grid().setIntervalY(2000) self.mComposerMap.grid().setAnnotationEnabled(True) self.mComposerMap.grid().setGridLineColor(QColor(0, 255, 0)) self.mComposerMap.grid().setGridLineWidth(0.5) self.mComposerMap.grid().setAnnotationFont(QgsFontUtils.getStandardTestFont()) self.mComposerMap.grid().setAnnotationPrecision(0) self.mComposerMap.grid().setAnnotationDisplay(QgsComposerMapGrid.HideAll, QgsComposerMapGrid.Left) self.mComposerMap.grid().setAnnotationPosition(QgsComposerMapGrid.OutsideMapFrame, QgsComposerMapGrid.Right) self.mComposerMap.grid().setAnnotationDisplay(QgsComposerMapGrid.HideAll, QgsComposerMapGrid.Top) self.mComposerMap.grid().setAnnotationPosition(QgsComposerMapGrid.OutsideMapFrame, QgsComposerMapGrid.Bottom) self.mComposerMap.grid().setAnnotationDirection(QgsComposerMapGrid.Horizontal, QgsComposerMapGrid.Right) self.mComposerMap.grid().setAnnotationDirection(QgsComposerMapGrid.Horizontal, QgsComposerMapGrid.Bottom) self.mComposerMap.grid().setAnnotationFontColor(QColor(255, 0, 0, 150)) self.mComposerMap.grid().setBlendMode(QPainter.CompositionMode_Overlay) self.mComposerMap.updateBoundingRect() checker = QgsCompositionChecker('composermap_grid', self.mComposition) checker.setControlPathPrefix("composer_mapgrid") myTestResult, myMessage = checker.testComposition() self.mComposerMap.grid().setEnabled(False) self.mComposerMap.grid().setAnnotationEnabled(False) assert myTestResult, myMessage def testCrossGrid(self): myRectangle = QgsRectangle(781662.375, 3339523.125, 793062.375, 3345223.125) self.mComposerMap.setNewExtent(myRectangle) self.mComposerMap.grid().setEnabled(True) self.mComposerMap.grid().setStyle(QgsComposerMapGrid.Cross) self.mComposerMap.grid().setCrossLength(2.0) self.mComposerMap.grid().setIntervalX(2000) self.mComposerMap.grid().setIntervalY(2000) self.mComposerMap.grid().setAnnotationEnabled(False) self.mComposerMap.grid().setGridLineColor(QColor(0, 255, 0)) self.mComposerMap.grid().setGridLineWidth(0.5) self.mComposerMap.grid().setBlendMode(QPainter.CompositionMode_SourceOver) self.mComposerMap.updateBoundingRect() checker = QgsCompositionChecker('composermap_crossgrid', self.mComposition) checker.setControlPathPrefix("composer_mapgrid") myTestResult, myMessage = checker.testComposition() self.mComposerMap.grid().setStyle(QgsComposerMapGrid.Solid) self.mComposerMap.grid().setEnabled(False) self.mComposerMap.grid().setAnnotationEnabled(False) assert myTestResult, myMessage def testMarkerGrid(self): myRectangle = QgsRectangle(781662.375, 3339523.125, 793062.375, 3345223.125) self.mComposerMap.setNewExtent(myRectangle) self.mComposerMap.grid().setEnabled(True) self.mComposerMap.grid().setStyle(QgsComposerMapGrid.Markers) self.mComposerMap.grid().setCrossLength(2.0) self.mComposerMap.grid().setIntervalX(2000) self.mComposerMap.grid().setIntervalY(2000) self.mComposerMap.grid().setAnnotationEnabled(False) self.mComposerMap.grid().setBlendMode(QPainter.CompositionMode_SourceOver) self.mComposerMap.updateBoundingRect() checker = QgsCompositionChecker('composermap_markergrid', self.mComposition) checker.setControlPathPrefix("composer_mapgrid") myTestResult, myMessage = checker.testComposition() self.mComposerMap.grid().setStyle(QgsComposerMapGrid.Solid) self.mComposerMap.grid().setEnabled(False) self.mComposerMap.grid().setAnnotationEnabled(False) assert myTestResult, myMessage def testFrameOnly(self): myRectangle = QgsRectangle(781662.375, 3339523.125, 793062.375, 3345223.125) self.mComposerMap.setNewExtent(myRectangle) self.mComposerMap.grid().setEnabled(True) self.mComposerMap.grid().setStyle(QgsComposerMapGrid.FrameAnnotationsOnly) self.mComposerMap.grid().setIntervalX(2000) self.mComposerMap.grid().setIntervalY(2000) self.mComposerMap.grid().setAnnotationEnabled(False) self.mComposerMap.grid().setFrameStyle(QgsComposerMapGrid.Zebra) self.mComposerMap.grid().setFramePenSize(0.5) self.mComposerMap.grid().setBlendMode(QPainter.CompositionMode_SourceOver) self.mComposerMap.updateBoundingRect() checker = QgsCompositionChecker('composermap_gridframeonly', self.mComposition) checker.setControlPathPrefix("composer_mapgrid") myTestResult, myMessage = checker.testComposition() self.mComposerMap.grid().setStyle(QgsComposerMapGrid.Solid) self.mComposerMap.grid().setEnabled(False) self.mComposerMap.grid().setAnnotationEnabled(False) self.mComposerMap.grid().setFrameStyle(QgsComposerMapGrid.NoFrame) assert myTestResult, myMessage def testZebraStyle(self): self.mComposerMap.grid().setFrameStyle(QgsComposerMapGrid.Zebra) myRectangle = QgsRectangle(785462.375, 3341423.125, 789262.375, 3343323.125) self.mComposerMap.setNewExtent(myRectangle) self.mComposerMap.grid().setIntervalX(2000) self.mComposerMap.grid().setIntervalY(2000) self.mComposerMap.grid().setGridLineColor(QColor(0, 0, 0)) self.mComposerMap.grid().setAnnotationFontColor(QColor(0, 0, 0)) self.mComposerMap.grid().setBlendMode(QPainter.CompositionMode_SourceOver) self.mComposerMap.grid().setFrameStyle(QgsComposerMapGrid.Zebra) self.mComposerMap.grid().setFrameWidth(10) self.mComposerMap.grid().setFramePenSize(1) self.mComposerMap.grid().setGridLineWidth(0.5) self.mComposerMap.grid().setFramePenColor(QColor(255, 100, 0, 200)) self.mComposerMap.grid().setFrameFillColor1(QColor(50, 90, 50, 100)) self.mComposerMap.grid().setFrameFillColor2(QColor(200, 220, 100, 60)) self.mComposerMap.grid().setEnabled(True) self.mComposerMap.updateBoundingRect() checker = QgsCompositionChecker('composermap_zebrastyle', self.mComposition) checker.setControlPathPrefix("composer_mapgrid") myTestResult, myMessage = checker.testComposition(0, 100) assert myTestResult, myMessage def testZebraStyleSides(self): self.mComposerMap.grid().setFrameStyle(QgsComposerMapGrid.Zebra) myRectangle = QgsRectangle(781662.375, 3339523.125, 793062.375, 3345223.125) self.mComposerMap.setNewExtent(myRectangle) self.mComposerMap.grid().setIntervalX(2000) self.mComposerMap.grid().setIntervalY(2000) self.mComposerMap.grid().setGridLineColor(QColor(0, 0, 0)) self.mComposerMap.grid().setAnnotationFontColor(QColor(0, 0, 0)) self.mComposerMap.grid().setBlendMode(QPainter.CompositionMode_SourceOver) self.mComposerMap.grid().setFrameStyle(QgsComposerMapGrid.Zebra) self.mComposerMap.grid().setFrameWidth(10) self.mComposerMap.grid().setFramePenSize(1) self.mComposerMap.grid().setGridLineWidth(0.5) self.mComposerMap.grid().setFramePenColor(QColor(0, 0, 0)) self.mComposerMap.grid().setFrameFillColor1(QColor(0, 0, 0)) self.mComposerMap.grid().setFrameFillColor2(QColor(255, 255, 255)) self.mComposerMap.grid().setEnabled(True) self.mComposerMap.grid().setFrameSideFlag(QgsComposerMapGrid.FrameLeft, True) self.mComposerMap.grid().setFrameSideFlag(QgsComposerMapGrid.FrameRight, False) self.mComposerMap.grid().setFrameSideFlag(QgsComposerMapGrid.FrameTop, False) self.mComposerMap.grid().setFrameSideFlag(QgsComposerMapGrid.FrameBottom, False) self.mComposerMap.updateBoundingRect() checker = QgsCompositionChecker('composermap_zebrastyle_left', self.mComposition) checker.setControlPathPrefix("composer_mapgrid") myTestResult, myMessage = checker.testComposition(0, 100) assert myTestResult, myMessage self.mComposerMap.grid().setFrameSideFlag(QgsComposerMapGrid.FrameTop, True) self.mComposerMap.updateBoundingRect() checker = QgsCompositionChecker('composermap_zebrastyle_lefttop', self.mComposition) checker.setControlPathPrefix("composer_mapgrid") myTestResult, myMessage = checker.testComposition(0, 100) assert myTestResult, myMessage self.mComposerMap.grid().setFrameSideFlag(QgsComposerMapGrid.FrameRight, True) self.mComposerMap.updateBoundingRect() checker = QgsCompositionChecker('composermap_zebrastyle_lefttopright', self.mComposition) checker.setControlPathPrefix("composer_mapgrid") myTestResult, myMessage = checker.testComposition(0, 100) assert myTestResult, myMessage self.mComposerMap.grid().setFrameSideFlag(QgsComposerMapGrid.FrameBottom, True) self.mComposerMap.grid().setFrameStyle(QgsComposerMapGrid.NoFrame) def testInteriorTicks(self): self.mComposerMap.grid().setFrameStyle(QgsComposerMapGrid.Zebra) myRectangle = QgsRectangle(781662.375, 3339523.125, 793062.375, 3345223.125) self.mComposerMap.setNewExtent(myRectangle) self.mComposerMap.grid().setIntervalX(2000) self.mComposerMap.grid().setIntervalY(2000) self.mComposerMap.grid().setAnnotationFontColor(QColor(0, 0, 0)) self.mComposerMap.grid().setBlendMode(QPainter.CompositionMode_SourceOver) self.mComposerMap.grid().setFrameStyle(QgsComposerMapGrid.InteriorTicks) self.mComposerMap.grid().setFrameWidth(10) self.mComposerMap.grid().setFramePenSize(1) self.mComposerMap.grid().setFramePenColor(QColor(0, 0, 0)) self.mComposerMap.grid().setEnabled(True) self.mComposerMap.grid().setStyle(QgsComposerMapGrid.FrameAnnotationsOnly) self.mComposerMap.updateBoundingRect() checker = QgsCompositionChecker('composermap_interiorticks', self.mComposition) checker.setControlPathPrefix("composer_mapgrid") myTestResult, myMessage = checker.testComposition(0, 100) assert myTestResult, myMessage
def testFromMapSettings(self): """ test QgsRenderContext.fromMapSettings() """ ms = QgsMapSettings() ms.setOutputSize(QSize(1000, 1000)) ms.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3111')) ms.setExtent(QgsRectangle(10000, 20000, 30000, 40000)) ms.setFlag(QgsMapSettings.Antialiasing, True) ms.setFlag(QgsMapSettings.LosslessImageRendering, True) ms.setFlag(QgsMapSettings.Render3DMap, True) ms.setZRange(QgsDoubleRange(1, 10)) ms.setOutputSize(QSize(100, 100)) ms.setDevicePixelRatio(2) ms.setOutputImageFormat(QImage.Format_Alpha8) ms.setFrameRate(30) ms.setCurrentFrame(6) ms.setTextRenderFormat(QgsRenderContext.TextFormatAlwaysText) rc = QgsRenderContext.fromMapSettings(ms) self.assertEqual(rc.textRenderFormat(), QgsRenderContext.TextFormatAlwaysText) self.assertTrue(rc.testFlag(QgsRenderContext.Antialiasing)) self.assertTrue(rc.testFlag(QgsRenderContext.LosslessImageRendering)) self.assertTrue(rc.testFlag(QgsRenderContext.Render3DMap)) self.assertEqual(ms.zRange(), QgsDoubleRange(1, 10)) self.assertEqual(rc.symbologyReferenceScale(), -1) self.assertEqual(rc.outputSize(), QSize(100, 100)) self.assertEqual(rc.devicePixelRatio(), 2) self.assertEqual(rc.deviceOutputSize(), QSize(200, 200)) self.assertEqual(rc.imageFormat(), QImage.Format_Alpha8) self.assertEqual(rc.frameRate(), 30) self.assertEqual(rc.currentFrame(), 6) # should have an valid mapToPixel self.assertTrue(rc.mapToPixel().isValid()) ms.setTextRenderFormat(QgsRenderContext.TextFormatAlwaysOutlines) ms.setZRange(QgsDoubleRange()) rc = QgsRenderContext.fromMapSettings(ms) self.assertEqual(rc.textRenderFormat(), QgsRenderContext.TextFormatAlwaysOutlines) self.assertTrue(ms.zRange().isInfinite()) self.assertEqual(rc.mapExtent(), QgsRectangle(10000, 20000, 30000, 40000)) ms.setIsTemporal(True) rc = QgsRenderContext.fromMapSettings(ms) self.assertEqual(rc.isTemporal(), True) ms.setTemporalRange( QgsDateTimeRange(QDateTime(2020, 1, 1, 0, 0), QDateTime(2010, 12, 31, 23, 59))) rc = QgsRenderContext.fromMapSettings(ms) self.assertEqual( rc.temporalRange(), QgsDateTimeRange(QDateTime(2020, 1, 1, 0, 0), QDateTime(2010, 12, 31, 23, 59))) ms.setDpiTarget(111.1) rc = QgsRenderContext.fromMapSettings(ms) self.assertEqual(rc.dpiTarget(), 111.1)
def testReprojectionErrorsWhileRendering(self): # WKT of a polygon which causes reprojection errors while rendering # (apologies for the ridiculously complex wkt, but I can't find a way to reproduce with simplifiction) wkt = 'MultiPolygon (((16.93392988400009358 42.77094147300012139, 16.88493899800005238 42.72939687700012712, ' \ '16.80298912900011032 42.76349518400014915, 16.85816491000014139 42.78400299700011544, ' \ '16.93392988400009358 42.77094147300012139)),((17.38200931100010393 42.79783763200002511, ' \ '17.65894616000011297 42.74298737200008702, 17.74887129000009622 42.69456614800010641, ' \ '17.32374108200008322 42.79083893400003547, 17.38200931100010393 42.79783763200002511)),' \ '((16.768565300000148 42.97223541900014254, 17.03207441500009622 42.98261139500014849, ' \ '17.13184655000009116 42.96954987200014386, 17.20020592500009116 42.92177969000012183, ' \ '16.85141035200010151 42.90070221600008438, 16.65544681100004709 42.92625560099999404, ' \ '16.70679772200014668 42.96954987200014386, 16.63168379000003938 42.98261139500014849, ' \ '16.768565300000148 42.97223541900014254)),((17.05567467500011958 43.02895742400001211, ' \ '17.24024498800011429 43.02277252800014651, 17.74146569100011561 42.83926015800001608, ' \ '17.70736738400009358 42.88703034100014122, 17.65334906206413734 42.8909283361407887, ' \ '17.70158573400010482 42.91950022500007833, 17.81175988700005064 42.909862570000044, ' \ '17.85847538200005147 42.81697418200012351, 18.22413781700009849 42.62807098500009317, ' \ '18.43735477700010961 42.55921213800017711, 18.4371480710000526 42.4934022020000981, ' \ '18.49642988400009358 42.41632721600008438, 18.23894290500010129 42.55906810100005089, ' \ '18.21753991000014139 42.6201032570001388, 18.07601972700010151 42.65131256700003348, ' \ '18.0432235040000819 42.70205312700007028, 17.90162194100014403 42.75189850500014188, ' \ '17.8928328790000819 42.79083893400003547, 17.72095787900005348 42.8262393250000315, ' \ '17.7618921230000808 42.77871328300012976, 17.74870853000004445 42.77204010600017625, ' \ '17.21387780000011958 42.98261139500014849, 17.04615319100011561 42.9950625670000619, ' \ '17.00163821700004974 43.05149974200010377, 17.05567467500011958 43.02895742400001211)),' \ '((16.19467207100007045 43.07440827000000638, 16.254893425000148 43.06854889500006323, ' \ '16.08716881600014403 43.01146067900008063, 16.04883873800011429 43.06517161700004692, ' \ '16.19467207100007045 43.07440827000000638)),((16.56275475400011032 43.22898997600010773, ' \ '16.65951582100009887 43.21596914300012315, 16.72771243600001867 43.16461823100003414, ' \ '17.19336998800014271 43.12726471600016964, 16.67017662900013875 43.12547435099999404, ' \ '16.37159264400014536 43.19550202000006323, 16.49642988400006516 43.21808502800014651, ' \ '16.58326256600014403 43.18866608300005794, 16.52051842500006273 43.22898997600010773, ' \ '16.56275475400011032 43.22898997600010773)),((16.80681399800010922 43.34247467700005529, ' \ '16.89234459700011826 43.31220123900006058, 16.84620201900008851 43.27338288000005662, ' \ '16.62826582100012729 43.26373932500008834, 16.50074303500014139 43.28424713700003679, ' \ '16.42188561300008587 43.31757233300011478, 16.40577233200011165 43.33270905200011214, ' \ '16.45346113400009358 43.35317617400009738, 16.42628014400008851 43.39411041900011412, ' \ '16.44703209700008983 43.39484284100014122, 16.80681399800010922 43.34247467700005529)),' \ '((16.29818769600012729 43.40363190300011809, 16.30274498800008587 43.38727448100009099, ' \ '16.39144941500012465 43.34638092700005529, 16.348643425000148 43.33869049700003018, ' \ '16.20045006600014403 43.40704987200003018, 16.29818769600012729 43.40363190300011809)),' \ '((16.33415774800010922 43.50153229400014254, 16.3752547540000819 43.49017975500008504, ' \ '16.21143639400008851 43.49005768400009231, 16.26441491000014139 43.51288483300011478, ' \ '16.33415774800010922 43.50153229400014254)),((15.67888431100004709 43.64801666900014254, ' \ '15.74040774800010922 43.62750885600009099, 15.67204837300002396 43.63743724200010377, ' \ '15.60377037900013875 43.67470937700007028, 15.67888431100004709 43.64801666900014254)),' \ '((15.36736087300005238 43.79010651200015047, 15.39568118600007551 43.7724063170000619, ' \ '15.22779381600014403 43.87445709800014981, 15.24073326900014536 43.88076406500009341, ' \ '15.36736087300005238 43.79010651200015047)),((15.44271894600009887 43.89907461100013109, ' \ '15.35865319100014403 43.91937897300014981, 15.26124108200011165 44.01105377800003282, ' \ '15.38404381600008719 43.9701602230000077, 15.44271894600009887 43.89907461100013109)),' \ '((15.22575931100010393 44.06622955900014915, 15.25440514400008851 44.01788971600014122, ' \ '15.12183678500014139 44.09223053600005926, 15.06251061300008587 44.16193268400012073, ' \ '15.22575931100010393 44.06622955900014915)),((14.83545983200014007 44.15102773600013109, ' \ '14.85726972700010151 44.15204498900000374, 14.86915123800014271 44.14052969000006499, ' \ '14.83521569100008719 44.14166901200009363, 14.81983483200014007 44.15302155199999845, ' \ '14.82243899800005238 44.16868724200004692, 14.83545983200014007 44.15102773600013109)),' \ '((14.98511803500011297 44.09096914300012315, 15.21680748800008587 43.91278717700008372, ' \ '15.13331139400011693 43.92121002800003282, 15.19450931100004709 43.87262604400017096, ' \ '15.10661868600007551 43.92544179900015422, 14.84961998800014271 44.17560455900014915, ' \ '14.98511803500011297 44.09096914300012315)),((14.765961134000122 44.26504140800015819, ' \ '14.74854576900014536 44.26166413000014188, 14.73959394600012729 44.28017812700015554, ' \ '14.79167728000007287 44.27252838700003679, 14.765961134000122 44.26504140800015819)),' \ '((14.66138756600011561 44.30866120000014519, 14.6407983730000808 44.31183502800003282, ' \ '14.59506269600007045 44.34711334800006455, 14.643565300000148 44.32575104400011412, ' \ '14.66138756600011561 44.30866120000014519)),((14.81120853000004445 44.35004303600000242, ' \ '14.75619550900009358 44.36399974200004692, 14.76343834700008983 44.41535065300017493, ' \ '14.80323326900008851 44.40550364800004957, 14.81120853000004445 44.35004303600000242)),' \ '((14.27116946700002131 44.61253489800004957, 14.23259524800005238 44.62604401200012205, ' \ '14.2657983730000808 44.67951080900003547, 14.28044681100007551 44.67755768400009231, ' \ '14.27116946700002131 44.61253489800004957)),((14.84522545700008322 44.60053131700011875, ' \ '14.93824303500014139 44.59414297100001079, 15.07553144600007045 44.48407623900006058, ' \ '14.91114342500011958 44.54547760600014783, 15.04802493600004709 44.43943919500001982, ' \ '15.09669030000009116 44.41518789300000947, 15.04151451900014536 44.47662995000008834, ' \ '15.25440514400008851 44.34003327000000638, 15.165049675000148 44.36737702000006323, ' \ '15.22022545700008322 44.3127302100001117, 15.13086998800008587 44.33258698100003414, ' \ '15.17237389400014536 44.29913971600016964, 15.12875410200007309 44.31199778900018771, ' \ '15.08920332100009887 44.37421295800000109, 15.11719811300014271 44.38719310099999404, ' \ '15.04900149800010922 44.39468008000015686, 14.89747155000009116 44.49091217699999845, ' \ '14.91863040500010129 44.50454336100013109, 14.87696373800011429 44.55975983300005794, ' \ '14.73365319100008719 44.70319245000014519, 14.84522545700008322 44.60053131700011875)),' \ '((14.41000410200010151 44.60097890800001608, 14.52662194100011561 44.50372955900012073, ' \ '14.53435306100010393 44.48407623900006058, 14.42261803500008455 44.57387929900009738, ' \ '14.36304772200014668 44.57343170800000109, 14.38257897200014668 44.60325755399999537, ' \ '14.33578535200007309 44.71678294500010509, 14.39747155000009116 44.6856143250000315, ' \ '14.41000410200010151 44.60097890800001608)),((14.75326582100007045 44.84585195500012844, ' \ '14.74048912900011032 44.82050202000000638, 14.82243899800005238 44.77142975500005662, ' \ '14.84961998800014271 44.70319245000014519, 14.65788821700004974 44.79877350500014188, ' \ '14.7268172540000819 44.79877350500014188, 14.6858016290000819 44.8471540390000456, ' \ '14.75326582100007045 44.84585195500012844)),((14.47103925900006516 44.95392487200003018, ' \ '14.45191491000008455 44.79877350500014188, 14.47217858200011165 44.7079531920000619, ' \ '14.53435306100010393 44.63426341400010244, 14.51335696700007816 44.618841864000089, ' \ '14.42790774800005238 44.65656159100014122, 14.29420006600008719 44.9086367860001161, ' \ '14.30152428500011297 44.94342682500014519, 14.38738040500004445 44.90900299700003018, ' \ '14.39031009200004974 44.96039459800012139, 14.41138756600008719 44.95636627800014651, ' \ '14.27849368600004709 45.1133487000000315, 14.29957116000014139 45.16233958499999801, ' \ '14.35621178500014139 45.16925690300008966, 14.387705925000148 45.03904857000013351, ' \ '14.47103925900006516 44.95392487200003018)),((14.56332441500012465 45.24974192900008063, ' \ '14.62378991000011297 45.17548248900006058, 14.59742272200011826 45.16644928600005926, ' \ '14.66529381600011561 45.16181061400011743, 14.66529381600011561 45.08734772300006455, ' \ '14.74048912900011032 45.07306549700014386, 14.81495201900008851 44.97748444200009033, ' \ '14.70639082100009887 44.9467227230000077, 14.62891686300014271 44.97817617400004053, ' \ '14.62086022200008983 45.04559967700011214, 14.61695397200008983 45.02464427300007799, ' \ '14.51050866000014139 45.03217194200011875, 14.43873131600014403 45.07050202000006323, ' \ '14.4670516290000819 45.12409088700015047, 14.53012129000009622 45.13483307500014519, ' \ '14.53435306100010393 45.23753489800002114, 14.56332441500012465 45.24974192900008063)),' \ '((16.36947066200013978 46.54057118800012915, 16.63767134600004738 46.47447703100009164, ' \ '16.75508020000012266 46.38187286400001597, 16.83765913900006694 46.38187286400001597, ' \ '16.88923221800007468 46.29216257800014489, 17.05294315600005461 46.15346303300005104, ' \ '17.20859257000006437 46.11656606000003933, 17.27587528500004055 46.01202463800002818, ' \ '17.31680301900004793 45.99765859000002877, 17.29013798000011093 45.98463612900009423, ' \ '17.40620324700006449 45.94365671800015605, 17.59110152100009827 45.93621531200012953, ' \ '17.65652388500006964 45.84541982000014571, 17.80917606600013414 45.81441396100005647, ' \ '17.85806197100004056 45.77172922800004073, 18.21121870900006456 45.78537180600012846, ' \ '18.40438521300006869 45.74180857400001798, 18.57347049900010916 45.81668772400014689, ' \ '18.6556360270001278 45.90758656800015558, 18.7755253500000947 45.88283355700004051, ' \ '18.90130578600007993 45.93120269800006383, 18.87288374800004931 45.89523590100002082, ' \ '18.90699019400011593 45.86795074500018643, 18.85531376100007606 45.85735707600009903, ' \ '18.84497847500006174 45.8157058720000947, 18.96848514800012708 45.66873809800016204, ' \ '18.90357954900008508 45.57308502200005762, 18.94171675700005153 45.53892689999999277, ' \ '19.01809452300011571 45.56740061400002162, 19.10625451700005328 45.51164174500017623, ' \ '19.00961958800010621 45.49867095900005154, 19.00300500400010151 45.45536611000007099, ' \ '19.03742150900006891 45.42229319300010104, 18.97592655400006834 45.39495636000008005, ' \ '19.09199182100007874 45.34999786400005917, 19.12475467900009107 45.29811472600006539, ' \ '19.36308638500014467 45.24824696900010679, 19.40783817500010855 45.20313344400013023, ' \ '19.39068160000005037 45.16933705700016333, 19.22593713300008744 45.16194732700016345, ' \ '19.12186079900010327 45.195795390000157, 19.13767378700009658 45.14603098600004216, ' \ '19.04486291500009543 45.13724599300006446, 19.08227665200013234 45.08494944300004192, ' \ '19.0872375890000967 44.97710072800013847, 19.13167932100006396 44.95317454000003465, ' \ '19.06667036900009293 44.90568389900012392, 18.99142948400006503 44.9149339800001286, ' \ '19.01582076000008215 44.86563466400004074, 18.88962691200009658 44.86119049100013001, ' \ '18.78338016700013213 44.91374542300012251, 18.79175174900009893 45.00154368100008639, ' \ '18.73831831900008638 45.0159097290000858, 18.68405806500004473 45.08479441400000098, ' \ '18.64871138500012648 45.06267689999999959, 18.61667199700013953 45.09766184500010411, ' \ '18.54959598800010667 45.09476796500011631, 18.51703983500007666 45.05585561200003042, ' \ '18.23788374800011525 45.15745147700012296, 18.15365116400005263 45.0975584930001645, ' \ '18.00347945100011771 45.1493382780000303, 17.83573775200005684 45.0644338990000648, ' \ '17.68473921700012852 45.1639627080000281, 17.48185754400009273 45.11440500900012296, ' \ '17.49622359200009214 45.1416901650001563, 17.44775109900012922 45.13430043600014585, ' \ '17.44330692500011537 45.16205068000009248, 17.38243208800008688 45.1396231090000839, ' \ '17.26895064300006766 45.18954254200015441, 17.24548954300007608 45.15538442000017483, ' \ '17.18709517400012032 45.14856313100001728, 17.0363033440001459 45.23047027600007652, ' \ '17.00829471800011561 45.21615590500009318, 17.00829471800011561 45.24416453100009505, ' \ '16.94731652900014751 45.23568959600000028, 16.9243721930001243 45.28452382500016427, ' \ '16.81171757000004163 45.18122263700009, 16.52894413300009546 45.22225372400005483, ' \ '16.38921106000003647 45.11683380099999852, 16.31624393700010955 45.00123362300008978, ' \ '16.12152714000009723 45.09616322900008356, 16.02044803900011516 45.213933818000001, ' \ '15.79234826700013627 45.18980092400012438, 15.76361617000014803 44.97555043600003444, ' \ '15.7308533120001357 44.92723297200008403, 15.77343469200010873 44.84501576800015243, ' \ '15.71607385200013596 44.80320953400008932, 15.72847619600008784 44.76910308800002269, ' \ '15.80568078600006743 44.69665273000013883, 15.88877648900006534 44.72424794500012979, ' \ '15.96897831200004703 44.63924021400013942, 16.02830285600006732 44.62471913700009907, ' \ '16.04473596200011798 44.58937245700018082, 16.00608199000004106 44.54100331600012908, ' \ '16.11646285000011858 44.52146962500013672, 16.15966434700004584 44.41610138000002905, ' \ '16.13827030500004867 44.37760243800015303, 16.20286584400008678 44.35977406800010669, ' \ '16.18756962000011868 44.28241444999999032, 16.21578495300011014 44.20815541600011045, ' \ '16.32688928200008149 44.08237498000012522, 16.50103885900011846 43.99271637000008184, ' \ '16.67859908100004418 43.8406843060001421, 16.71260217300007866 43.77151540100005889, ' \ '17.03051558500007445 43.54847991900005866, 17.27050093600007585 43.46321380700000248, ' \ '17.28993127500007176 43.3034302780000786, 17.44206669100009321 43.15243174300015028, ' \ '17.6284119050001209 43.04657257100008394, 17.66272505700004558 42.96569895500012137, ' \ '17.63450972400008254 42.950402731000068, 17.51563561300008587 42.95888906500012183, ' \ '17.47087649800005238 43.01341380400010905, 17.50196373800014271 43.03099192900005221, ' \ '17.43360436300014271 43.01740143400009231, 17.46021569100011561 43.03099192900005221, ' \ '17.42611738400009358 43.06517161700004692, 17.4045516290000819 43.05149974200010377, ' \ '17.31625410200012993 43.12726471600016964, 17.11394290500004445 43.21320221600008438, ' \ '16.88062584700011826 43.40595123900006058, 16.62582441500009622 43.44904205900009231, ' \ '16.52466881600011561 43.51080963700009363, 16.39144941500012465 43.51080963700009363, ' \ '16.47339928500008455 43.5381533870001789, 16.43384850400013875 43.54975006700000506, ' \ '16.11768639400008851 43.52448151200003679, 16.17237389400014536 43.4896914730000077, ' \ '16.11312910200004467 43.47890859600009605, 15.95948326900011693 43.50397370000008834, ' \ '15.987315300000148 43.54490794500010509, 15.92530358200011165 43.55857982000004824, ' \ '15.91895592500009116 43.62872955900012073, 15.96631920700011165 43.64118073100003414, ' \ '15.90479576900014536 43.64801666900014254, 15.95297285200010151 43.65086497599999404, ' \ '15.95045006600008719 43.68854401200015047, 15.70630944100008719 43.76341380400005221, ' \ '15.6174422540000819 43.82550690300017493, 15.66309655000009116 43.81297435099999404, ' \ '15.67888431100004709 43.81928131700011875, 15.45508873800014271 43.92804596600014122, ' \ '15.14454186300011429 44.19546133000015686, 15.15219160200012993 44.23529694200014717, ' \ '15.11036217500011958 44.26434967700011214, 15.14063561300011429 44.28245677300013483, ' \ '15.17660566500009622 44.24994538000005662, 15.20777428500008455 44.27277252800014651, ' \ '15.19809004000012465 44.30166250200007028, 15.295258009000122 44.25067780199999845, ' \ '15.30274498800008587 44.29913971600016964, 15.26124108200011165 44.33258698100003414, ' \ '15.42448978000001603 44.26797109600006763, 15.52865644600009887 44.27179596600008438, ' \ '15.30795332100009887 44.35439687700007028, 15.00733483200014007 44.56972890800012976, ' \ '14.883799675000148 44.7236188820001388, 14.883799675000148 44.86147695500012844, 14.92164147200008983 ' \ '44.95880768400009231, 14.85279381600011561 45.09365469000000815, 14.65788821700004974 ' \ '45.19660065300017493, 14.57081139400008851 45.29364655200011214, 14.31153405000009116 ' \ '45.34398021000005485, 14.23259524800005238 45.14935944200000506, 14.17937259200007816 ' \ '45.13450755400005221, 14.19312584700008983 45.10561758000012844, 14.14389082100007045 ' \ '45.05939362200003018, 14.151377800000148 44.97748444200009033, 14.06885826900014536 ' \ '44.94953034100014122, 14.08383222700007309 44.9863955750000315, 14.04029381600014403 ' \ '45.03896719000015025, 14.0756942070000548 44.98371002800003282, 14.02051842500011958 ' \ '44.90110911700004692, 13.97266686300011429 44.90110911700004692, 13.99301191500009622 ' \ '44.88129303600014453, 13.97266686300011429 44.82664622599999404, 14.00001061300008587 ' \ '44.81305573100003414, 13.89014733200011165 44.83348216400010244, 13.91797936300014271 ' \ '44.77826569200009033, 13.90316816500009622 44.77240631700014717, 13.89698326900011693 ' \ '44.81305573100003414, 13.78711998800014271 44.87506745000008834, 13.84229576900008851 ' \ '44.88812897300006455, 13.79460696700010658 44.89496491100008768, 13.77409915500007287 ' \ '44.96381256700014717, 13.6232202480000808 45.07306549700014386, 13.61255944100014403 ' \ '45.11786530199999845, 13.72624759200004974 45.13450755400005221, 13.5959578790000819 ' \ '45.14541250200001343, 13.57545006600011561 45.26487864800007799, 13.60271243600001867 ' \ '45.28534577000012007, 13.57545006600011561 45.30646393400006389, 13.60954837300005238 ' \ '45.32013580900017757, 13.54127037900013875 45.34613678600005926, 13.50709069100014403 ' \ '45.51190827000000638, 13.62901778100007277 45.45898346000016943, 13.75929406800014476 ' \ '45.46316925100011019, 13.88900191200011136 45.42363678000005223, 13.98263960800005634 ' \ '45.47531321200001742, 13.97189091000012695 45.5142255660000643, 14.09291711400010172 ' \ '45.47391794800002174, 14.21869755100007637 45.49717234400004884, 14.37279667100006009 ' \ '45.47784535800009564, 14.4689148350000778 45.52559438100014688, 14.49857710800012001 ' \ '45.59618438800005435, 14.58094934100009255 45.66780792200010808, 14.66848921700008646 ' \ '45.53396596300005683, 14.79716353300005949 45.46518463200006011, 14.88160282300009385 ' \ '45.46978383400001178, 14.9226339110000481 45.51494903600017494, 15.13926151500010064 ' \ '45.43004465799999991, 15.32519331800011742 45.45283396399999276, 15.36136682100004691 ' \ '45.48203114900003641, 15.29666792800006192 45.52295888300012905, 15.2685559480001416 ' \ '45.60166208900012919, 15.37376916500011248 45.64021270800010655, 15.25501672300006817 ' \ '45.72346344000011698, 15.42906294700014769 45.77529490200011253, 15.45128381300008868 ' \ '45.81513743100013869, 15.67607629400006886 45.84169911700014666, 15.65943648300003588 ' \ '45.88882802400014782, 15.69798710100010908 46.0362092080000167, 15.58988000500005455 ' \ '46.11351715100001059, 15.62284956800010605 46.19170359400006021, 16.01920780400010358 ' \ '46.29882883700007312, 16.05961877400008575 46.33231516600015709, 16.0579651280001201 ' \ '46.37753204400003426, 16.2756262620000598 46.37316538500006402, 16.23490523300009158 ' \ '46.4933389280001137, 16.36947066200013978 46.54057118800012915))) ' geom = QgsGeometry.fromWkt(wkt) f = QgsFeature() f.setGeometry(geom) image = QImage(200, 200, QImage.Format_RGB32) painter = QPainter() ms = QgsMapSettings() crs = QgsCoordinateReferenceSystem.fromProj4('+proj=ortho +lat_0=36.5 +lon_0=-118.8 +x_0=0 +y_0=0 +a=6371000 +b=6371000 +units=m +no_defs') self.assertTrue(crs.isValid()) ms.setDestinationCrs(crs) ms.setExtent(QgsRectangle(1374999.8, 3912610.7, 4724462.5, 6505499.6)) ms.setOutputSize(image.size()) context = QgsRenderContext.fromMapSettings(ms) context.setPainter(painter) context.setScaleFactor(96 / 25.4) # 96 DPI ct = QgsCoordinateTransform(QgsCoordinateReferenceSystem('epsg:4326'), crs, QgsProject.instance()) self.assertTrue(ct.isValid()) context.setCoordinateTransform(ct) context.setExtent(ct.transformBoundingBox(ms.extent(), QgsCoordinateTransform.ReverseTransform)) fill_symbol = QgsFillSymbol.createSimple({'color': '#ffffff', 'outline_color': '#ffffff', 'outline_width': '10'}) painter.begin(image) try: image.fill(QColor(0, 0, 0)) fill_symbol.startRender(context) fill_symbol.renderFeature(f, context) fill_symbol.stopRender(context) finally: painter.end() assert self.imageCheck('Reprojection errors polygon', 'reprojection_errors_polygon', image) #also test linestring linestring = QgsGeometry(geom.constGet().boundary()) f.setGeometry(linestring) line_symbol = QgsLineSymbol.createSimple({'color': '#ffffff', 'outline_width': '10'}) image = QImage(200, 200, QImage.Format_RGB32) painter.begin(image) try: image.fill(QColor(0, 0, 0)) line_symbol.startRender(context) line_symbol.renderFeature(f, context) line_symbol.stopRender(context) finally: painter.end() assert self.imageCheck('Reprojection errors linestring', 'reprojection_errors_linestring', image)
def processAlgorithm(self, parameters, context, feedback): feedback.setProgress(1) extent = self.parameterAsExtent(parameters, self.EXTENT, context) min_zoom = self.parameterAsInt(parameters, self.ZOOM_MIN, context) max_zoom = self.parameterAsInt(parameters, self.ZOOM_MAX, context) dpi = self.parameterAsInt(parameters, self.DPI, context) tile_format = self.formats[self.parameterAsEnum( parameters, self.TILE_FORMAT, context)] output_format = self.outputs[self.parameterAsEnum( parameters, self.OUTPUT_FORMAT, context)] if output_format == 'Directory': output_dir = self.parameterAsString(parameters, self.OUTPUT_DIRECTORY, context) if not output_dir: raise QgsProcessingException( self.tr('You need to specify output directory.')) else: # MBTiles output_file = self.parameterAsString(parameters, self.OUTPUT_FILE, context) if not output_file: raise QgsProcessingException( self.tr('You need to specify output filename.')) tile_width = 256 tile_height = 256 wgs_crs = QgsCoordinateReferenceSystem('EPSG:4326') dest_crs = QgsCoordinateReferenceSystem('EPSG:3857') project = context.project() src_to_wgs = QgsCoordinateTransform(project.crs(), wgs_crs, context.transformContext()) wgs_to_dest = QgsCoordinateTransform(wgs_crs, dest_crs, context.transformContext()) settings = QgsMapSettings() settings.setOutputImageFormat(QImage.Format_ARGB32_Premultiplied) settings.setDestinationCrs(dest_crs) settings.setLayers(self.layers) settings.setOutputDpi(dpi) wgs_extent = src_to_wgs.transformBoundingBox(extent) wgs_extent = [ wgs_extent.xMinimum(), wgs_extent.yMinimum(), wgs_extent.xMaximum(), wgs_extent.yMaximum() ] metatiles_by_zoom = {} metatiles_count = 0 for zoom in range(min_zoom, max_zoom + 1): metatiles = get_metatiles(wgs_extent, zoom, 4) metatiles_by_zoom[zoom] = metatiles metatiles_count += len(metatiles) lab_buffer_px = 100 progress = 0 tile_params = { 'format': tile_format, 'quality': 75, 'width': tile_width, 'height': tile_height } if output_format == 'Directory': writer = DirectoryWriter(output_dir, tile_params) else: writer = MBTilesWriter(output_file, tile_params, wgs_extent, min_zoom, max_zoom) for zoom in range(min_zoom, max_zoom + 1): feedback.pushConsoleInfo('Generating tiles for zoom level: %s' % zoom) for i, metatile in enumerate(metatiles_by_zoom[zoom]): size = QSize(tile_width * metatile.rows(), tile_height * metatile.columns()) extent = QgsRectangle(*metatile.extent()) settings.setExtent(wgs_to_dest.transformBoundingBox(extent)) settings.setOutputSize(size) label_area = QgsRectangle(settings.extent()) lab_buffer = label_area.width() * (lab_buffer_px / size.width()) label_area.set(label_area.xMinimum() + lab_buffer, label_area.yMinimum() + lab_buffer, label_area.xMaximum() - lab_buffer, label_area.yMaximum() - lab_buffer) settings.setLabelBoundaryGeometry( QgsGeometry.fromRect(label_area)) image = QImage(size, QImage.Format_ARGB32_Premultiplied) image.fill(Qt.transparent) dpm = settings.outputDpi() / 25.4 * 1000 image.setDotsPerMeterX(dpm) image.setDotsPerMeterY(dpm) painter = QPainter(image) job = QgsMapRendererCustomPainterJob(settings, painter) job.renderSynchronously() painter.end() # For analysing metatiles (labels, etc.) # metatile_dir = os.path.join(output_dir, str(zoom)) # os.makedirs(metatile_dir, exist_ok=True) # image.save(os.path.join(metatile_dir, 'metatile_%s.png' % i)) for r, c, tile in metatile.tiles: tile_img = image.copy(tile_width * r, tile_height * c, tile_width, tile_height) writer.writeTile(tile, tile_img) progress += 1 feedback.setProgress(100 * (progress / metatiles_count)) writer.close() results = {} if output_format == 'Directory': results['OUTPUT_DIRECTORY'] = output_dir else: # MBTiles results['OUTPUT_FILE'] = output_file return results
def testRenderMultipleRenderersSelection(self): """ Test that selection colors only apply to main renderer :return: """ poly_layer = QgsVectorLayer(os.path.join(TEST_DATA_DIR, 'polys.shp')) self.assertTrue(poly_layer.isValid()) poly_layer.selectAll() sym1 = QgsFillSymbol.createSimple({'color': '#ffaaff', 'outline_color': '#000000', 'outline_style': 'no'}) renderer = QgsSingleSymbolRenderer(sym1) poly_layer.setRenderer(renderer) # add secondary renderer, for rendering below class Gen1(QgsFeatureRendererGenerator): def id(self): return 'Gen1' def level(self): return -2 def createRenderer(self): renderer = QgsCategorizedSymbolRenderer() renderer.setClassAttribute('Name') sym1 = QgsFillSymbol.createSimple( {'color': '#ffaaff', 'outline_color': '#33aa33', 'outline_width': '3'}) sym2 = QgsFillSymbol.createSimple( {'color': '#ffaaff', 'outline_color': '#aa33aa', 'outline_width': '3'}) renderer.addCategory(QgsRendererCategory('Dam', sym1, 'Dam')) renderer.addCategory(QgsRendererCategory('Lake', sym2, 'Lake')) return renderer poly_layer.addFeatureRendererGenerator(Gen1()) mapsettings = QgsMapSettings() mapsettings.setOutputSize(QSize(400, 400)) mapsettings.setOutputDpi(96) mapsettings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) mapsettings.setExtent(QgsRectangle(-13875783.2, 2266009.4, -8690110.7, 6673344.5)) mapsettings.setLayers([poly_layer]) renderchecker = QgsMultiRenderChecker() renderchecker.setMapSettings(mapsettings) renderchecker.setControlPathPrefix('vectorlayerrenderer') renderchecker.setControlName('expected_multiple_renderers_selection') result = renderchecker.runTest('expected_multiple_renderers_selection') self.report += renderchecker.report() self.assertTrue(result) # also try with symbol levels renderer.setUsingSymbolLevels(True) poly_layer.setRenderer(renderer) renderchecker = QgsMultiRenderChecker() renderchecker.setMapSettings(mapsettings) renderchecker.setControlPathPrefix('vectorlayerrenderer') renderchecker.setControlName('expected_multiple_renderers_selection') result = renderchecker.runTest('expected_multiple_renderers_selection') self.report += renderchecker.report() self.assertTrue(result)
def test_render_via_job(self): """ Test rendering an annotation layer via a map render job """ layer = QgsAnnotationLayer( 'test', QgsAnnotationLayer.LayerOptions( QgsProject.instance().transformContext())) self.assertTrue(layer.isValid()) item = QgsAnnotationPolygonItem( QgsPolygon( QgsLineString([ QgsPoint(11.5, 13), QgsPoint(12, 13), QgsPoint(12, 13.5), QgsPoint(11.5, 13) ]))) item.setSymbol( QgsFillSymbol.createSimple({ 'color': '200,100,100', 'outline_color': 'black', 'outline_width': '2' })) item.setZIndex(1) i1_id = layer.addItem(item) item = QgsAnnotationLineItem( QgsLineString( [QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)])) item.setSymbol( QgsLineSymbol.createSimple({ 'color': '#ffff00', 'line_width': '3' })) item.setZIndex(2) i2_id = layer.addItem(item) item = QgsAnnotationMarkerItem(QgsPoint(12, 13)) item.setSymbol( QgsMarkerSymbol.createSimple({ 'color': '100,200,200', 'size': '6', 'outline_color': 'black' })) item.setZIndex(3) i3_id = layer.addItem(item) layer.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) settings = QgsMapSettings() settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) settings.setExtent(QgsRectangle(10, 10, 18, 18)) settings.setOutputSize(QSize(200, 200)) settings.setLayers([layer]) job = QgsMapRendererParallelJob(settings) job.start() job.waitForFinished() # check rendered item results item_results = job.takeRenderedItemResults() item_details = item_results.renderedItems() self.assertEqual(len(item_details), 3) self.assertEqual([i.layerId() for i in item_details], [layer.id()] * 3) self.assertCountEqual([i.itemId() for i in item_details], [i1_id, i2_id, i3_id]) self.assertCountEqual([ i.itemId() for i in item_results.renderedAnnotationItemsInBounds( QgsRectangle(0, 0, 1, 1)) ], []) self.assertCountEqual([ i.itemId() for i in item_results.renderedAnnotationItemsInBounds( QgsRectangle(10, 10, 11, 18)) ], [i2_id]) self.assertCountEqual([ i.itemId() for i in item_results.renderedAnnotationItemsInBounds( QgsRectangle(10, 10, 12, 18)) ], [i1_id, i2_id, i3_id]) # bounds should be in map crs self.assertEqual( [i.boundingBox() for i in item_details if i.itemId() == i1_id][0], QgsRectangle(11.5, 13, 12, 13.5)) self.assertEqual( [i.boundingBox() for i in item_details if i.itemId() == i2_id][0], QgsRectangle(11, 13, 12, 15)) self.assertEqual([ i.boundingBox().toString(1) for i in item_details if i.itemId() == i3_id ][0], '11.5,12.5 : 12.5,13.5')
class TestQgsComposerMap(unittest.TestCase): def __init__(self, methodName): """Run once on class initialization.""" unittest.TestCase.__init__(self, methodName) # create composition with composer map self.mMapSettings = QgsMapSettings() crs = QgsCoordinateReferenceSystem(32633) self.mMapSettings.setDestinationCrs(crs) self.mMapSettings.setCrsTransformEnabled(False) self.mComposition = QgsComposition(QgsProject.instance()) self.mComposition.setPaperSize(297, 210) self.mComposerMap = QgsComposerMap(self.mComposition, 20, 20, 200, 100) self.mComposerMap.setFrameEnabled(True) self.mComposerMap.setBackgroundColor(QColor(150, 100, 100)) self.mComposition.addComposerMap(self.mComposerMap) def testGrid(self): """Test that we can create a grid for a map.""" myRectangle = QgsRectangle(781662.375, 3339523.125, 793062.375, 3345223.125) self.mComposerMap.setNewExtent(myRectangle) self.mComposerMap.grid().setEnabled(True) self.mComposerMap.grid().setIntervalX(2000) self.mComposerMap.grid().setIntervalY(2000) self.mComposerMap.grid().setAnnotationEnabled(True) self.mComposerMap.grid().setGridLineColor(QColor(0, 255, 0)) self.mComposerMap.grid().setGridLineWidth(0.5) self.mComposerMap.grid().setAnnotationFont( QgsFontUtils.getStandardTestFont()) self.mComposerMap.grid().setAnnotationPrecision(0) self.mComposerMap.grid().setAnnotationDisplay( QgsComposerMapGrid.HideAll, QgsComposerMapGrid.Left) self.mComposerMap.grid().setAnnotationPosition( QgsComposerMapGrid.OutsideMapFrame, QgsComposerMapGrid.Right) self.mComposerMap.grid().setAnnotationDisplay( QgsComposerMapGrid.HideAll, QgsComposerMapGrid.Top) self.mComposerMap.grid().setAnnotationPosition( QgsComposerMapGrid.OutsideMapFrame, QgsComposerMapGrid.Bottom) self.mComposerMap.grid().setAnnotationDirection( QgsComposerMapGrid.Horizontal, QgsComposerMapGrid.Right) self.mComposerMap.grid().setAnnotationDirection( QgsComposerMapGrid.Horizontal, QgsComposerMapGrid.Bottom) self.mComposerMap.grid().setAnnotationFontColor(QColor(255, 0, 0, 150)) self.mComposerMap.grid().setBlendMode(QPainter.CompositionMode_Overlay) self.mComposerMap.updateBoundingRect() checker = QgsCompositionChecker('composermap_grid', self.mComposition) checker.setControlPathPrefix("composer_mapgrid") myTestResult, myMessage = checker.testComposition() self.mComposerMap.grid().setEnabled(False) self.mComposerMap.grid().setAnnotationEnabled(False) assert myTestResult, myMessage def testCrossGrid(self): myRectangle = QgsRectangle(781662.375, 3339523.125, 793062.375, 3345223.125) self.mComposerMap.setNewExtent(myRectangle) self.mComposerMap.grid().setEnabled(True) self.mComposerMap.grid().setStyle(QgsComposerMapGrid.Cross) self.mComposerMap.grid().setCrossLength(2.0) self.mComposerMap.grid().setIntervalX(2000) self.mComposerMap.grid().setIntervalY(2000) self.mComposerMap.grid().setAnnotationEnabled(False) self.mComposerMap.grid().setGridLineColor(QColor(0, 255, 0)) self.mComposerMap.grid().setGridLineWidth(0.5) self.mComposerMap.grid().setBlendMode( QPainter.CompositionMode_SourceOver) self.mComposerMap.updateBoundingRect() checker = QgsCompositionChecker('composermap_crossgrid', self.mComposition) checker.setControlPathPrefix("composer_mapgrid") myTestResult, myMessage = checker.testComposition() self.mComposerMap.grid().setStyle(QgsComposerMapGrid.Solid) self.mComposerMap.grid().setEnabled(False) self.mComposerMap.grid().setAnnotationEnabled(False) assert myTestResult, myMessage def testMarkerGrid(self): myRectangle = QgsRectangle(781662.375, 3339523.125, 793062.375, 3345223.125) self.mComposerMap.setNewExtent(myRectangle) self.mComposerMap.grid().setEnabled(True) self.mComposerMap.grid().setStyle(QgsComposerMapGrid.Markers) self.mComposerMap.grid().setCrossLength(2.0) self.mComposerMap.grid().setIntervalX(2000) self.mComposerMap.grid().setIntervalY(2000) self.mComposerMap.grid().setAnnotationEnabled(False) self.mComposerMap.grid().setBlendMode( QPainter.CompositionMode_SourceOver) self.mComposerMap.updateBoundingRect() checker = QgsCompositionChecker('composermap_markergrid', self.mComposition) checker.setControlPathPrefix("composer_mapgrid") myTestResult, myMessage = checker.testComposition() self.mComposerMap.grid().setStyle(QgsComposerMapGrid.Solid) self.mComposerMap.grid().setEnabled(False) self.mComposerMap.grid().setAnnotationEnabled(False) assert myTestResult, myMessage def testFrameOnly(self): myRectangle = QgsRectangle(781662.375, 3339523.125, 793062.375, 3345223.125) self.mComposerMap.setNewExtent(myRectangle) self.mComposerMap.grid().setEnabled(True) self.mComposerMap.grid().setStyle( QgsComposerMapGrid.FrameAnnotationsOnly) self.mComposerMap.grid().setIntervalX(2000) self.mComposerMap.grid().setIntervalY(2000) self.mComposerMap.grid().setAnnotationEnabled(False) self.mComposerMap.grid().setFrameStyle(QgsComposerMapGrid.Zebra) self.mComposerMap.grid().setFramePenSize(0.5) self.mComposerMap.grid().setBlendMode( QPainter.CompositionMode_SourceOver) self.mComposerMap.updateBoundingRect() checker = QgsCompositionChecker('composermap_gridframeonly', self.mComposition) checker.setControlPathPrefix("composer_mapgrid") myTestResult, myMessage = checker.testComposition() self.mComposerMap.grid().setStyle(QgsComposerMapGrid.Solid) self.mComposerMap.grid().setEnabled(False) self.mComposerMap.grid().setAnnotationEnabled(False) self.mComposerMap.grid().setFrameStyle(QgsComposerMapGrid.NoFrame) assert myTestResult, myMessage def testZebraStyle(self): self.mComposerMap.grid().setFrameStyle(QgsComposerMapGrid.Zebra) myRectangle = QgsRectangle(785462.375, 3341423.125, 789262.375, 3343323.125) self.mComposerMap.setNewExtent(myRectangle) self.mComposerMap.grid().setIntervalX(2000) self.mComposerMap.grid().setIntervalY(2000) self.mComposerMap.grid().setGridLineColor(QColor(0, 0, 0)) self.mComposerMap.grid().setAnnotationFontColor(QColor(0, 0, 0)) self.mComposerMap.grid().setBlendMode( QPainter.CompositionMode_SourceOver) self.mComposerMap.grid().setFrameStyle(QgsComposerMapGrid.Zebra) self.mComposerMap.grid().setFrameWidth(10) self.mComposerMap.grid().setFramePenSize(1) self.mComposerMap.grid().setGridLineWidth(0.5) self.mComposerMap.grid().setFramePenColor(QColor(255, 100, 0, 200)) self.mComposerMap.grid().setFrameFillColor1(QColor(50, 90, 50, 100)) self.mComposerMap.grid().setFrameFillColor2(QColor(200, 220, 100, 60)) self.mComposerMap.grid().setEnabled(True) self.mComposerMap.updateBoundingRect() checker = QgsCompositionChecker('composermap_zebrastyle', self.mComposition) checker.setControlPathPrefix("composer_mapgrid") myTestResult, myMessage = checker.testComposition(0, 100) assert myTestResult, myMessage def testZebraStyleSides(self): self.mComposerMap.grid().setFrameStyle(QgsComposerMapGrid.Zebra) myRectangle = QgsRectangle(781662.375, 3339523.125, 793062.375, 3345223.125) self.mComposerMap.setNewExtent(myRectangle) self.mComposerMap.grid().setIntervalX(2000) self.mComposerMap.grid().setIntervalY(2000) self.mComposerMap.grid().setGridLineColor(QColor(0, 0, 0)) self.mComposerMap.grid().setAnnotationFontColor(QColor(0, 0, 0)) self.mComposerMap.grid().setBlendMode( QPainter.CompositionMode_SourceOver) self.mComposerMap.grid().setFrameStyle(QgsComposerMapGrid.Zebra) self.mComposerMap.grid().setFrameWidth(10) self.mComposerMap.grid().setFramePenSize(1) self.mComposerMap.grid().setGridLineWidth(0.5) self.mComposerMap.grid().setFramePenColor(QColor(0, 0, 0)) self.mComposerMap.grid().setFrameFillColor1(QColor(0, 0, 0)) self.mComposerMap.grid().setFrameFillColor2(QColor(255, 255, 255)) self.mComposerMap.grid().setEnabled(True) self.mComposerMap.grid().setFrameSideFlag(QgsComposerMapGrid.FrameLeft, True) self.mComposerMap.grid().setFrameSideFlag( QgsComposerMapGrid.FrameRight, False) self.mComposerMap.grid().setFrameSideFlag(QgsComposerMapGrid.FrameTop, False) self.mComposerMap.grid().setFrameSideFlag( QgsComposerMapGrid.FrameBottom, False) self.mComposerMap.updateBoundingRect() checker = QgsCompositionChecker('composermap_zebrastyle_left', self.mComposition) checker.setControlPathPrefix("composer_mapgrid") myTestResult, myMessage = checker.testComposition(0, 100) assert myTestResult, myMessage self.mComposerMap.grid().setFrameSideFlag(QgsComposerMapGrid.FrameTop, True) self.mComposerMap.updateBoundingRect() checker = QgsCompositionChecker('composermap_zebrastyle_lefttop', self.mComposition) checker.setControlPathPrefix("composer_mapgrid") myTestResult, myMessage = checker.testComposition(0, 100) assert myTestResult, myMessage self.mComposerMap.grid().setFrameSideFlag( QgsComposerMapGrid.FrameRight, True) self.mComposerMap.updateBoundingRect() checker = QgsCompositionChecker('composermap_zebrastyle_lefttopright', self.mComposition) checker.setControlPathPrefix("composer_mapgrid") myTestResult, myMessage = checker.testComposition(0, 100) assert myTestResult, myMessage self.mComposerMap.grid().setFrameSideFlag( QgsComposerMapGrid.FrameBottom, True) self.mComposerMap.grid().setFrameStyle(QgsComposerMapGrid.NoFrame) def testInteriorTicks(self): self.mComposerMap.grid().setFrameStyle(QgsComposerMapGrid.Zebra) myRectangle = QgsRectangle(781662.375, 3339523.125, 793062.375, 3345223.125) self.mComposerMap.setNewExtent(myRectangle) self.mComposerMap.grid().setIntervalX(2000) self.mComposerMap.grid().setIntervalY(2000) self.mComposerMap.grid().setAnnotationFontColor(QColor(0, 0, 0)) self.mComposerMap.grid().setBlendMode( QPainter.CompositionMode_SourceOver) self.mComposerMap.grid().setFrameStyle( QgsComposerMapGrid.InteriorTicks) self.mComposerMap.grid().setFrameWidth(10) self.mComposerMap.grid().setFramePenSize(1) self.mComposerMap.grid().setFramePenColor(QColor(0, 0, 0)) self.mComposerMap.grid().setEnabled(True) self.mComposerMap.grid().setStyle( QgsComposerMapGrid.FrameAnnotationsOnly) self.mComposerMap.updateBoundingRect() checker = QgsCompositionChecker('composermap_interiorticks', self.mComposition) checker.setControlPathPrefix("composer_mapgrid") myTestResult, myMessage = checker.testComposition(0, 100) assert myTestResult, myMessage
def generate(self, writer, parameters, context, feedback): feedback.setProgress(1) extent = self.parameterAsExtent(parameters, self.EXTENT, context) self.min_zoom = self.parameterAsInt(parameters, self.ZOOM_MIN, context) self.max_zoom = self.parameterAsInt(parameters, self.ZOOM_MAX, context) dpi = self.parameterAsInt(parameters, self.DPI, context) self.tile_format = self.formats[self.parameterAsEnum( parameters, self.TILE_FORMAT, context)] transparent = self.parameterAsBool(parameters, self.TRANSPARENT, context) quality = self.parameterAsInt(parameters, self.QUALITY, context) self.metatilesize = self.parameterAsInt(parameters, self.METATILESIZE, context) try: tile_width = self.parameterAsInt(parameters, self.TILE_WIDTH, context) tile_height = self.parameterAsInt(parameters, self.TILE_HEIGHT, context) except AttributeError: # for mbtiles we don't have such settings tile_width = 256 tile_height = 256 wgs_crs = QgsCoordinateReferenceSystem('EPSG:4326') dest_crs = QgsCoordinateReferenceSystem('EPSG:3857') project = context.project() src_to_wgs = QgsCoordinateTransform(project.crs(), wgs_crs, context.transformContext()) wgs_to_dest = QgsCoordinateTransform(wgs_crs, dest_crs, context.transformContext()) settings = QgsMapSettings() settings.setOutputImageFormat(QImage.Format_ARGB32_Premultiplied) settings.setDestinationCrs(dest_crs) settings.setLayers(self.layers) settings.setOutputDpi(dpi) canvas_red = QgsProject.instance().readNumEntry( 'Gui', '/CanvasColorRedPart', 255)[0] canvas_green = QgsProject.instance().readNumEntry( 'Gui', '/CanvasColorGreenPart', 255)[0] canvas_blue = QgsProject.instance().readNumEntry( 'Gui', '/CanvasColorBluePart', 255)[0] color = QColor(canvas_red, canvas_green, canvas_blue, 255) if self.tile_format == 'PNG' and transparent: color.setAlpha(0) settings.setBackgroundColor(color) # disable partial labels (they would be cut at the edge of tiles) labeling_engine_settings = settings.labelingEngineSettings() labeling_engine_settings.setFlag( QgsLabelingEngineSettings.UsePartialCandidates, False) settings.setLabelingEngineSettings(labeling_engine_settings) self.wgs_extent = src_to_wgs.transformBoundingBox(extent) self.wgs_extent = [ self.wgs_extent.xMinimum(), self.wgs_extent.yMinimum(), self.wgs_extent.xMaximum(), self.wgs_extent.yMaximum() ] metatiles_by_zoom = {} metatiles_count = 0 for zoom in range(self.min_zoom, self.max_zoom + 1): metatiles = get_metatiles(self.wgs_extent, zoom, self.metatilesize) metatiles_by_zoom[zoom] = metatiles metatiles_count += len(metatiles) lab_buffer_px = 100 progress = 0 tile_params = { 'format': self.tile_format, 'quality': quality, 'width': tile_width, 'height': tile_height, 'min_zoom': self.min_zoom, 'max_zoom': self.max_zoom, 'extent': self.wgs_extent, } writer.set_parameters(tile_params) for zoom in range(self.min_zoom, self.max_zoom + 1): feedback.pushConsoleInfo('Generating tiles for zoom level: %s' % zoom) for i, metatile in enumerate(metatiles_by_zoom[zoom]): if feedback.isCanceled(): break size = QSize(tile_width * metatile.rows(), tile_height * metatile.columns()) extent = QgsRectangle(*metatile.extent()) settings.setExtent(wgs_to_dest.transformBoundingBox(extent)) settings.setOutputSize(size) image = QImage(size, QImage.Format_ARGB32_Premultiplied) image.fill(Qt.transparent) dpm = settings.outputDpi() / 25.4 * 1000 image.setDotsPerMeterX(dpm) image.setDotsPerMeterY(dpm) painter = QPainter(image) job = QgsMapRendererCustomPainterJob(settings, painter) job.renderSynchronously() painter.end() # For analysing metatiles (labels, etc.) # metatile_dir = os.path.join(output_dir, str(zoom)) # os.makedirs(metatile_dir, exist_ok=True) # image.save(os.path.join(metatile_dir, 'metatile_%s.png' % i)) for r, c, tile in metatile.tiles: tile_img = image.copy(tile_width * r, tile_height * c, tile_width, tile_height) writer.write_tile(tile, tile_img) progress += 1 feedback.setProgress(100 * (progress / metatiles_count)) writer.close()
def testRenderWithTransform(self): layer = QgsAnnotationLayer( 'test', QgsAnnotationLayer.LayerOptions( QgsProject.instance().transformContext())) self.assertTrue(layer.isValid()) item = QgsAnnotationPolygonItem( QgsPolygon( QgsLineString([ QgsPoint(11.5, 13), QgsPoint(12, 13), QgsPoint(12, 13.5), QgsPoint(11.5, 13) ]))) item.setSymbol( QgsFillSymbol.createSimple({ 'color': '200,100,100', 'outline_color': 'black', 'outline_width': '2' })) item.setZIndex(1) layer.addItem(item) item = QgsAnnotationLineStringItem( QgsLineString( [QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)])) item.setSymbol( QgsLineSymbol.createSimple({ 'color': '#ffff00', 'line_width': '3' })) item.setZIndex(2) layer.addItem(item) item = QgsAnnotationMarkerItem(QgsPointXY(12, 13)) item.setSymbol( QgsMarkerSymbol.createSimple({ 'color': '100,200,200', 'size': '6', 'outline_color': 'black' })) item.setZIndex(3) layer.addItem(item) layer.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) settings = QgsMapSettings() settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) settings.setExtent(QgsRectangle(1250958, 1386945, 1420709, 1532518)) settings.setOutputSize(QSize(300, 300)) settings.setFlag(QgsMapSettings.Antialiasing, False) rc = QgsRenderContext.fromMapSettings(settings) rc.setCoordinateTransform( QgsCoordinateTransform(layer.crs(), settings.destinationCrs(), QgsProject.instance())) image = QImage(200, 200, QImage.Format_ARGB32) image.setDotsPerMeterX(96 / 25.4 * 1000) image.setDotsPerMeterY(96 / 25.4 * 1000) image.fill(QColor(255, 255, 255)) painter = QPainter(image) rc.setPainter(painter) try: renderer = layer.createMapRenderer(rc) renderer.render() finally: painter.end() self.assertTrue( self.imageCheck('layer_render_transform', 'layer_render_transform', image))
def processAlgorithm(self, parameters, context, feedback): feedback.setProgress(1) extent = self.parameterAsExtent(parameters, self.EXTENT, context) min_zoom = self.parameterAsInt(parameters, self.ZOOM_MIN, context) max_zoom = self.parameterAsInt(parameters, self.ZOOM_MAX, context) dpi = self.parameterAsInt(parameters, self.DPI, context) tile_format = self.formats[self.parameterAsEnum(parameters, self.TILE_FORMAT, context)] output_format = self.outputs[self.parameterAsEnum(parameters, self.OUTPUT_FORMAT, context)] if output_format == 'Directory': output_dir = self.parameterAsString(parameters, self.OUTPUT_DIRECTORY, context) if not output_dir: raise QgsProcessingException(self.tr('You need to specify output directory.')) else: # MBTiles output_file = self.parameterAsString(parameters, self.OUTPUT_FILE, context) if not output_file: raise QgsProcessingException(self.tr('You need to specify output filename.')) tile_width = 256 tile_height = 256 wgs_crs = QgsCoordinateReferenceSystem('EPSG:4326') dest_crs = QgsCoordinateReferenceSystem('EPSG:3857') project = context.project() src_to_wgs = QgsCoordinateTransform(project.crs(), wgs_crs, context.transformContext()) wgs_to_dest = QgsCoordinateTransform(wgs_crs, dest_crs, context.transformContext()) settings = QgsMapSettings() settings.setOutputImageFormat(QImage.Format_ARGB32_Premultiplied) settings.setDestinationCrs(dest_crs) settings.setLayers(self.layers) settings.setOutputDpi(dpi) wgs_extent = src_to_wgs.transformBoundingBox(extent) wgs_extent = [wgs_extent.xMinimum(), wgs_extent.yMinimum(), wgs_extent.xMaximum(), wgs_extent.yMaximum()] metatiles_by_zoom = {} metatiles_count = 0 for zoom in range(min_zoom, max_zoom + 1): metatiles = get_metatiles(wgs_extent, zoom, 4) metatiles_by_zoom[zoom] = metatiles metatiles_count += len(metatiles) lab_buffer_px = 100 progress = 0 tile_params = { 'format': tile_format, 'quality': 75, 'width': tile_width, 'height': tile_height } if output_format == 'Directory': writer = DirectoryWriter(output_dir, tile_params) else: writer = MBTilesWriter(output_file, tile_params, wgs_extent, min_zoom, max_zoom) for zoom in range(min_zoom, max_zoom + 1): feedback.pushConsoleInfo('Generating tiles for zoom level: %s' % zoom) for i, metatile in enumerate(metatiles_by_zoom[zoom]): size = QSize(tile_width * metatile.rows(), tile_height * metatile.columns()) extent = QgsRectangle(*metatile.extent()) settings.setExtent(wgs_to_dest.transformBoundingBox(extent)) settings.setOutputSize(size) label_area = QgsRectangle(settings.extent()) lab_buffer = label_area.width() * (lab_buffer_px / size.width()) label_area.set( label_area.xMinimum() + lab_buffer, label_area.yMinimum() + lab_buffer, label_area.xMaximum() - lab_buffer, label_area.yMaximum() - lab_buffer ) settings.setLabelBoundaryGeometry(QgsGeometry.fromRect(label_area)) image = QImage(size, QImage.Format_ARGB32_Premultiplied) image.fill(Qt.transparent) dpm = settings.outputDpi() / 25.4 * 1000 image.setDotsPerMeterX(dpm) image.setDotsPerMeterY(dpm) painter = QPainter(image) job = QgsMapRendererCustomPainterJob(settings, painter) job.renderSynchronously() painter.end() # For analysing metatiles (labels, etc.) # metatile_dir = os.path.join(output_dir, str(zoom)) # os.makedirs(metatile_dir, exist_ok=True) # image.save(os.path.join(metatile_dir, 'metatile_%s.png' % i)) for r, c, tile in metatile.tiles: tile_img = image.copy(tile_width * r, tile_height * c, tile_width, tile_height) writer.writeTile(tile, tile_img) progress += 1 feedback.setProgress(100 * (progress / metatiles_count)) writer.close() results = {} if output_format == 'Directory': results['OUTPUT_DIRECTORY'] = output_dir else: # MBTiles results['OUTPUT_FILE'] = output_file return results
class TestSelectiveMasking(unittest.TestCase): def setUp(self): self.checker = QgsRenderChecker() self.checker.setControlPathPrefix("selective_masking") self.report = "<h1>Python Selective Masking Tests</h1>\n" self.map_settings = QgsMapSettings() crs = QgsCoordinateReferenceSystem('epsg:4326') extent = QgsRectangle(-123.0, 22.7, -76.4, 46.9) self.map_settings.setBackgroundColor(QColor(152, 219, 249)) self.map_settings.setOutputSize(QSize(420, 280)) self.map_settings.setOutputDpi(72) self.map_settings.setFlag(QgsMapSettings.Antialiasing, True) self.map_settings.setFlag(QgsMapSettings.UseAdvancedEffects, False) self.map_settings.setDestinationCrs(crs) self.map_settings.setExtent(extent) # load a predefined QGIS project self.assertTrue(QgsProject.instance().read(os.path.join(unitTestDataPath(), "selective_masking.qgs"))) self.points_layer = QgsProject.instance().mapLayersByName('points')[0] self.lines_layer = QgsProject.instance().mapLayersByName('lines')[0] # line layer with subsymbols self.lines_layer2 = QgsProject.instance().mapLayersByName('lines2')[0] # line layer with labels self.lines_with_labels = QgsProject.instance().mapLayersByName('lines_with_labels')[0] self.polys_layer = QgsProject.instance().mapLayersByName('polys')[0] # polygon layer with a rule based labeling self.polys_layer2 = QgsProject.instance().mapLayersByName('polys2')[0] self.raster_layer = QgsProject.instance().mapLayersByName('raster_layer')[0] # try to fix the font for where labels are defined # in order to have more stable image comparison tests for layer in [self.polys_layer, self.lines_with_labels, self.polys_layer2]: for provider in layer.labeling().subProviders(): settings = layer.labeling().settings(provider) font = getTestFont() font.setPointSize(32) fmt = settings.format() fmt.setFont(font) fmt.setNamedStyle('Roman') fmt.setSize(32) fmt.setSizeUnit(QgsUnitTypes.RenderPoints) settings.setFormat(fmt) if (layer.geometryType == QgsWkbTypes.PolygonGeometry): settings.placement = QgsPalLayerSettings.OverPoint layer.labeling().setSettings(settings, provider) # order layers for rendering self.map_settings.setLayers([self.points_layer, self.lines_layer, self.polys_layer]) def tearDown(self): report_file_path = "%s/qgistest.html" % QDir.tempPath() with open(report_file_path, 'a') as report_file: report_file.write(self.report) def check_renderings(self, map_settings, control_name): """Test a rendering with different configurations: - parallel rendering, no cache - sequential rendering, no cache - parallel rendering, with cache (rendered two times) - sequential rendering, with cache (rendered two times) """ for do_parallel in [False, True]: for use_cache in [False, True]: print("=== parallel", do_parallel, "cache", use_cache) tmp = getTempfilePath('png') cache = None if use_cache: cache = QgsMapRendererCache() # render a first time to fill the cache renderMapToImageWithTime(self.map_settings, parallel=do_parallel, cache=cache) img, t = renderMapToImageWithTime(self.map_settings, parallel=do_parallel, cache=cache) img.save(tmp) print("Image rendered in {}".format(tmp)) self.checker.setControlName(control_name) self.checker.setRenderedImage(tmp) suffix = "_parallel" if do_parallel else "_sequential" res = self.checker.compareImages(control_name + suffix) self.report += self.checker.report() self.assertTrue(res) print("=== Rendering took {}s".format(float(t) / 1000.0)) def test_save_restore_references(self): """ Test saving and restoring symbol layer references """ # simple ids mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setMasks([ QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), QgsSymbolLayerReference(self.lines_layer2.id(), QgsSymbolLayerId("some_id", [1, 3, 5, 19])), QgsSymbolLayerReference(self.polys_layer.id(), QgsSymbolLayerId("some_other_id", [4, 5])), ]) props = mask_layer.properties() mask_layer2 = QgsMaskMarkerSymbolLayer.create(props) self.assertEqual(mask_layer2.masks(), [ QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), QgsSymbolLayerReference(self.lines_layer2.id(), QgsSymbolLayerId("some_id", [1, 3, 5, 19])), QgsSymbolLayerReference(self.polys_layer.id(), QgsSymbolLayerId("some_other_id", [4, 5])), ]) # complex ids mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setMasks([ QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), QgsSymbolLayerReference(self.lines_layer2.id(), QgsSymbolLayerId("some id, #1", [1, 3, 5, 19])), QgsSymbolLayerReference(self.polys_layer.id(), QgsSymbolLayerId("some other id, like, this", [4, 5])), ]) props = mask_layer.properties() mask_layer2 = QgsMaskMarkerSymbolLayer.create(props) self.assertEqual(mask_layer2.masks(), [ QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), QgsSymbolLayerReference(self.lines_layer2.id(), QgsSymbolLayerId("some id, #1", [1, 3, 5, 19])), QgsSymbolLayerReference(self.polys_layer.id(), QgsSymbolLayerId("some other id, like, this", [4, 5])), ]) # complex ids, v2 mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setMasks([ QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("a string; with bits", 0)), QgsSymbolLayerReference(self.lines_layer2.id(), QgsSymbolLayerId("some; id, #1", [1, 3, 5, 19])), QgsSymbolLayerReference(self.polys_layer.id(), QgsSymbolLayerId("some other; id, lik;e, this", [4, 5])), ]) props = mask_layer.properties() mask_layer2 = QgsMaskMarkerSymbolLayer.create(props) self.assertEqual(mask_layer2.masks(), [ QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("a string; with bits", 0)), QgsSymbolLayerReference(self.lines_layer2.id(), QgsSymbolLayerId("some; id, #1", [1, 3, 5, 19])), QgsSymbolLayerReference(self.polys_layer.id(), QgsSymbolLayerId("some other; id, lik;e, this", [4, 5])), ]) def test_label_mask(self): # modify labeling settings label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), # the black jets QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("B52", 0)), QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("Jet", 0))]) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) format = self.polys_layer.labeling().settings().format() self.assertTrue(format.mask().enabled()) self.check_renderings(self.map_settings, "label_mask") def test_multiple_label_masks_different_sets(self): # modify labeling settings of the polys layer label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_with_labels.id(), QgsSymbolLayerId("", 0)), # the black jets QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("B52", 0)), QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("Jet", 0))]) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) format = self.polys_layer.labeling().settings().format() self.assertTrue(format.mask().enabled()) # modify labeling settings of the lines layer label_settings = self.lines_with_labels.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # polygons QgsSymbolLayerReference(self.polys_layer.id(), QgsSymbolLayerId("", 0)), ]) label_settings.setFormat(fmt) self.lines_with_labels.labeling().setSettings(label_settings) # new map settings with a line symbology that has labels self.map_settings.setLayers([self.points_layer, self.lines_with_labels, self.polys_layer]) self.check_renderings(self.map_settings, "multiple_label_masks_different_sets") # restore map settings self.map_settings.setLayers([self.points_layer, self.lines_layer, self.polys_layer]) def test_multiple_label_masks_same_set(self): # modify labeling settings of the polys layer label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_with_labels.id(), QgsSymbolLayerId("", 0)), ]) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) format = self.polys_layer.labeling().settings().format() self.assertTrue(format.mask().enabled()) # modify labeling settings of the lines layer label_settings = self.lines_with_labels.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_with_labels.id(), QgsSymbolLayerId("", 0)), ]) label_settings.setFormat(fmt) self.lines_with_labels.labeling().setSettings(label_settings) # new map settings with a line symbology that has labels self.map_settings.setLayers([self.points_layer, self.lines_with_labels, self.polys_layer]) self.check_renderings(self.map_settings, "multiple_label_masks_same_set") # restore map settings self.map_settings.setLayers([self.points_layer, self.lines_layer, self.polys_layer]) def test_label_mask_subsymbol(self): # new map settings with a line symbology that has sub symbols self.map_settings.setLayers([self.points_layer, self.lines_layer2, self.polys_layer]) # modify labeling settings label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # mask only vertical segments of "roads" QgsSymbolLayerReference(self.lines_layer2.id(), QgsSymbolLayerId("", [1, 0])), # the black jets QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("B52", 0)), QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("Jet", 0))]) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) format = self.polys_layer.labeling().settings().format() self.assertTrue(format.mask().enabled()) self.check_renderings(self.map_settings, "label_mask_subsymbol") # restore original map settings self.map_settings.setLayers([self.points_layer, self.lines_layer, self.polys_layer]) def test_label_mask_dd(self): """ test label mask with data defined properties """ label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() fmt.mask().setEnabled(False) fmt.mask().setSize(1.0) fmt.mask().setOpacity(0.42) # mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), # the black jets QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("B52", 0)), QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("Jet", 0))]) # overwrite with data-defined properties fmt.dataDefinedProperties().setProperty(QgsPalLayerSettings.MaskEnabled, QgsProperty.fromExpression('1')) fmt.dataDefinedProperties().setProperty(QgsPalLayerSettings.MaskBufferSize, QgsProperty.fromExpression('4.0')) fmt.dataDefinedProperties().setProperty(QgsPalLayerSettings.MaskOpacity, QgsProperty.fromExpression('100.0')) context = QgsRenderContext() fmt.updateDataDefinedProperties(context) self.assertEqual(fmt.mask().enabled(), True) self.assertEqual(fmt.mask().size(), 4.0) self.assertEqual(fmt.mask().opacity(), 1.0) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) self.check_renderings(self.map_settings, "label_mask") def test_label_mask_rule_labeling(self): # new map settings with a rule based labeling self.map_settings.setLayers([self.points_layer, self.lines_layer, self.polys_layer2]) # modify labeling settings of one rule for child in self.polys_layer2.labeling().rootRule().children(): if child.description() == 'Tadam': break label_settings = child.settings() label_settings.priority = 3 fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), # the black jets QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("B52", 0)), QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("Jet", 0))]) label_settings.setFormat(fmt) child.setSettings(label_settings) # modify labeling settings of another rule for child in self.polys_layer2.labeling().rootRule().children(): if child.description() != 'Tadam': break label_settings = child.settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the polygons QgsSymbolLayerReference(self.polys_layer2.id(), QgsSymbolLayerId("", 0)), ]) label_settings.setFormat(fmt) child.setSettings(label_settings) self.check_renderings(self.map_settings, "rule_label_mask") # restore map settings self.map_settings.setLayers([self.points_layer, self.lines_layer, self.polys_layer]) def test_label_mask_symbol_levels(self): # modify labeling settings label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), # the black jets QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("B52", 0)), QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("Jet", 0))]) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) format = self.polys_layer.labeling().settings().format() self.assertTrue(format.mask().enabled()) # enable symbol levels self.lines_layer.renderer().setUsingSymbolLevels(True) self.check_renderings(self.map_settings, "label_mask_symbol_levels") def test_symbol_layer_mask(self): p = QgsMarkerSymbol.createSimple({'color': '#fdbf6f', 'size': "7"}) self.points_layer.setRenderer(QgsSingleSymbolRenderer(p)) circle_symbol = QgsMarkerSymbol.createSimple({'size': '10'}) mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setSubSymbol(circle_symbol) mask_layer.setMasks([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), ]) # add this mask layer to the point layer self.points_layer.renderer().symbol().appendSymbolLayer(mask_layer) self.check_renderings(self.map_settings, "sl_mask") def test_multiple_masks_same_symbol_layer(self): """Test multiple masks that occlude the same symbol layer""" # # 1. a symbol layer mask # p = QgsMarkerSymbol.createSimple({'color': '#fdbf6f', 'size': "7"}) self.points_layer.setRenderer(QgsSingleSymbolRenderer(p)) circle_symbol = QgsMarkerSymbol.createSimple({'size': '10'}) mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setSubSymbol(circle_symbol) mask_layer.setMasks([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), ]) # add this mask layer to the point layer self.points_layer.renderer().symbol().appendSymbolLayer(mask_layer) # # 2. a label mask # # modify labeling settings label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)) ]) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) self.check_renderings(self.map_settings, "multiple_masks_same_sl") def test_multiple_masks_different_symbol_layers_same_layer(self): """Test multiple masks that occlude different symbol layers of the same layer. The UI should disallow this settings. We test here that only one mask is retained""" # # 1. a symbol layer mask # p = QgsMarkerSymbol.createSimple({'color': '#fdbf6f', 'size': "7"}) self.points_layer.setRenderer(QgsSingleSymbolRenderer(p)) circle_symbol = QgsMarkerSymbol.createSimple({'size': '10'}) mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setSubSymbol(circle_symbol) mask_layer.setMasks([ # the yellow part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 1)), ]) # add this mask layer to the point layer self.points_layer.renderer().symbol().appendSymbolLayer(mask_layer) # # 2. a label mask # # modify labeling settings label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)) ]) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) self.check_renderings(self.map_settings, "multiple_masks_different_sl") def test_multiple_masks_different_symbol_layers_same_layer2(self): """Test multiple masks that occlude different symbol layers of the same layer - 2nd possible order The UI should disallow this settings. We test here that only one mask is retained""" # # 1. a symbol layer mask # p = QgsMarkerSymbol.createSimple({'color': '#fdbf6f', 'size': "7"}) self.points_layer.setRenderer(QgsSingleSymbolRenderer(p)) circle_symbol = QgsMarkerSymbol.createSimple({'size': '10'}) mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setSubSymbol(circle_symbol) mask_layer.setMasks([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), ]) # add this mask layer to the point layer self.points_layer.renderer().symbol().appendSymbolLayer(mask_layer) # # 2. a label mask # # modify labeling settings label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the yellow part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 1)) ]) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) self.check_renderings(self.map_settings, "multiple_masks_different_sl2") def test_mask_symbollayer_preview(self): # # Masks should be visible in previews # p = QgsMarkerSymbol.createSimple({'color': '#fdbf6f', 'size': "7"}) circle_symbol = QgsMarkerSymbol.createSimple({'size': '10'}) mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setSubSymbol(circle_symbol) p.insertSymbolLayer(0, mask_layer) for control_name, render_function in [ ("as_image", lambda: p.asImage(QSize(64, 64)).save(tmp)), ("as_big_preview", lambda: p.bigSymbolPreviewImage().save(tmp)), ("sl_preview", lambda: QgsSymbolLayerUtils.symbolLayerPreviewIcon(mask_layer, QgsUnitTypes.RenderPixels, QSize(64, 64)).pixmap(QSize(64, 64)).save(tmp)) ]: tmp = getTempfilePath('png') render_function() self.checker.setControlName(control_name) self.checker.setRenderedImage(tmp) res = self.checker.compareImages(control_name, 90) self.report += self.checker.report() self.assertTrue(res) def test_mask_with_effect(self): p = QgsMarkerSymbol.createSimple({'color': '#fdbf6f', 'size': "7"}) self.points_layer.setRenderer(QgsSingleSymbolRenderer(p)) circle_symbol = QgsMarkerSymbol.createSimple({'size': '12'}) mask_layer = QgsMaskMarkerSymbolLayer() mask_layer.setSubSymbol(circle_symbol) mask_layer.setMasks([ # the yellow part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 1)), ]) # add an outer glow effect to the mask layer blur = QgsOuterGlowEffect.create({"enabled": "1", "blur_level": "6.445", "blur_unit": "MM", "opacity": "1", "spread": "0.6", "spread_unit": "MM", "color1": "0,0,255,255", "draw_mode": "2" }) mask_layer.setPaintEffect(blur) # add this mask layer to the point layer self.points_layer.renderer().symbol().appendSymbolLayer(mask_layer) self.check_renderings(self.map_settings, "mask_with_effect") def test_label_mask_with_effect(self): # modify labeling settings label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), # the black jets QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("B52", 0)), QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("Jet", 0))]) # add an outer glow effect to the mask blur = QgsOuterGlowEffect.create({"enabled": "1", "blur_level": "6.445", "blur_unit": "MM", "opacity": "1", "spread": "0.6", "spread_unit": "MM", "color1": "0,0,255,255", "draw_mode": "2" }) fmt.mask().setPaintEffect(blur) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) format = self.polys_layer.labeling().settings().format() self.assertTrue(format.mask().enabled()) self.check_renderings(self.map_settings, "label_mask_with_effect") def test_layout_exports(self): """Test mask effects in a layout export at 300 dpi""" # modify labeling settings label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0)), # the black jets QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("B52", 0)), QgsSymbolLayerReference(self.points_layer.id(), QgsSymbolLayerId("Jet", 0))]) # add an outer glow effect to the mask blur = QgsOuterGlowEffect.create({"enabled": "1", "blur_level": "6.445", "blur_unit": "MM", "opacity": "1", "spread": "0.6", "spread_unit": "MM", "color1": "0,0,255,255", "draw_mode": "2" }) fmt.mask().setPaintEffect(blur) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) layout = QgsLayout(QgsProject.instance()) page = QgsLayoutItemPage(layout) page.setPageSize(QgsLayoutSize(50, 33)) layout.pageCollection().addPage(page) map = QgsLayoutItemMap(layout) map.attemptSetSceneRect(QRectF(1, 1, 48, 32)) map.setFrameEnabled(True) layout.addLayoutItem(map) map.setExtent(self.lines_layer.extent()) map.setLayers([self.points_layer, self.lines_layer, self.polys_layer]) image = QImage(591, 591, QImage.Format_RGB32) image.setDotsPerMeterX(int(300 / 25.3 * 1000)) image.setDotsPerMeterY(int(300 / 25.3 * 1000)) image.fill(0) p = QPainter(image) exporter = QgsLayoutExporter(layout) exporter.renderPage(p, 0) p.end() tmp = getTempfilePath('png') image.save(tmp) control_name = "layout_export" self.checker.setControlName(control_name) self.checker.setRenderedImage(tmp) res = self.checker.compareImages(control_name) self.report += self.checker.report() self.assertTrue(res) def test_different_dpi_target(self): """Test with raster layer and a target dpi""" # modify labeling settings label_settings = self.polys_layer.labeling().settings() fmt = label_settings.format() # enable a mask fmt.mask().setEnabled(True) fmt.mask().setSize(4.0) # and mask other symbol layers underneath fmt.mask().setMaskedSymbolLayers([ # the black part of roads QgsSymbolLayerReference(self.lines_layer.id(), QgsSymbolLayerId("", 0))]) label_settings.setFormat(fmt) self.polys_layer.labeling().setSettings(label_settings) self.map_settings.setLayers([self.lines_layer, self.polys_layer, self.raster_layer]) self.map_settings.setDpiTarget(300) self.check_renderings(self.map_settings, "different_dpi_target")
class TestQgsAtlasComposition(unittest.TestCase): def testCase(self): self.TEST_DATA_DIR = unitTestDataPath() tmppath = tempfile.mkdtemp() for file in glob.glob( os.path.join(self.TEST_DATA_DIR, 'france_parts.*')): shutil.copy(os.path.join(self.TEST_DATA_DIR, file), tmppath) vectorFileInfo = QFileInfo(tmppath + "/france_parts.shp") mVectorLayer = QgsVectorLayer(vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr") QgsMapLayerRegistry.instance().addMapLayers([mVectorLayer]) # create composition with composer map self.mapSettings = QgsMapSettings() layerStringList = [] layerStringList.append(mVectorLayer.id()) self.mapSettings.setLayers(layerStringList) self.mapSettings.setCrsTransformEnabled(True) self.mapSettings.setMapUnits(QGis.Meters) # select epsg:2154 crs = QgsCoordinateReferenceSystem() crs.createFromSrid(2154) self.mapSettings.setDestinationCrs(crs) self.mComposition = QgsComposition(self.mapSettings) self.mComposition.setPaperSize(297, 210) # fix the renderer, fill with green props = {"color": "0,127,0"} fillSymbol = QgsFillSymbolV2.createSimple(props) renderer = QgsSingleSymbolRendererV2(fillSymbol) mVectorLayer.setRendererV2(renderer) # the atlas map self.mAtlasMap = QgsComposerMap(self.mComposition, 20, 20, 130, 130) self.mAtlasMap.setFrameEnabled(True) self.mComposition.addComposerMap(self.mAtlasMap) # the atlas self.mAtlas = self.mComposition.atlasComposition() self.mAtlas.setCoverageLayer(mVectorLayer) self.mAtlas.setEnabled(True) self.mComposition.setAtlasMode(QgsComposition.ExportAtlas) # an overview mOverview = QgsComposerMap(self.mComposition, 180, 20, 50, 50) mOverview.setFrameEnabled(True) mOverview.setOverviewFrameMap(self.mAtlasMap.id()) self.mComposition.addComposerMap(mOverview) nextent = QgsRectangle(49670.718, 6415139.086, 699672.519, 7065140.887) mOverview.setNewExtent(nextent) # set the fill symbol of the overview map props2 = {"color": "127,0,0,127"} fillSymbol2 = QgsFillSymbolV2.createSimple(props2) mOverview.setOverviewFrameMapSymbol(fillSymbol2) # header label self.mLabel1 = QgsComposerLabel(self.mComposition) self.mComposition.addComposerLabel(self.mLabel1) self.mLabel1.setText("[% \"NAME_1\" %] area") self.mLabel1.setFont(QgsFontUtils.getStandardTestFont()) self.mLabel1.adjustSizeToText() self.mLabel1.setSceneRect(QRectF(150, 5, 60, 15)) qWarning( "header label font: %s exactMatch:%s" % (self.mLabel1.font().toString(), self.mLabel1.font().exactMatch())) # feature number label self.mLabel2 = QgsComposerLabel(self.mComposition) self.mComposition.addComposerLabel(self.mLabel2) self.mLabel2.setText("# [%$feature || ' / ' || $numfeatures%]") self.mLabel2.setFont(QgsFontUtils.getStandardTestFont()) self.mLabel2.adjustSizeToText() self.mLabel2.setSceneRect(QRectF(150, 200, 60, 15)) qWarning( "feature number label font: %s exactMatch:%s" % (self.mLabel2.font().toString(), self.mLabel2.font().exactMatch())) self.filename_test() self.autoscale_render_test() self.autoscale_render_test_old_api() self.fixedscale_render_test() self.predefinedscales_render_test() self.hidden_render_test() self.legend_test() shutil.rmtree(tmppath, True) def filename_test(self): self.mAtlas.setFilenamePattern("'output_' || $feature") self.mAtlas.beginRender() for i in range(0, self.mAtlas.numFeatures()): self.mAtlas.prepareForFeature(i) expected = "output_%d" % (i + 1) assert self.mAtlas.currentFilename() == expected self.mAtlas.endRender() def autoscale_render_test(self): self.mAtlasMap.setAtlasDriven(True) self.mAtlasMap.setAtlasScalingMode(QgsComposerMap.Auto) self.mAtlasMap.setAtlasMargin(0.10) self.mAtlas.beginRender() for i in range(0, 2): self.mAtlas.prepareForFeature(i) self.mLabel1.adjustSizeToText() checker = QgsCompositionChecker('atlas_autoscale%d' % (i + 1), self.mComposition) checker.setControlPathPrefix("atlas") myTestResult, myMessage = checker.testComposition(0, 200) assert myTestResult self.mAtlas.endRender() self.mAtlasMap.setAtlasDriven(False) self.mAtlasMap.setAtlasScalingMode(QgsComposerMap.Fixed) self.mAtlasMap.setAtlasMargin(0) def autoscale_render_test_old_api(self): self.mAtlas.setComposerMap(self.mAtlasMap) self.mAtlas.setFixedScale(False) self.mAtlas.setMargin(0.10) self.mAtlas.beginRender() for i in range(0, 2): self.mAtlas.prepareForFeature(i) self.mLabel1.adjustSizeToText() checker = QgsCompositionChecker( 'atlas_autoscale_old_api%d' % (i + 1), self.mComposition) checker.setControlPathPrefix("atlas") myTestResult, myMessage = checker.testComposition(0, 200) assert myTestResult self.mAtlas.endRender() self.mAtlas.setFixedScale(True) self.mAtlas.setMargin(0) self.mAtlas.setComposerMap(None) self.mAtlasMap.setAtlasDriven(False) def fixedscale_render_test(self): self.mAtlasMap.setNewExtent( QgsRectangle(209838.166, 6528781.020, 610491.166, 6920530.620)) self.mAtlasMap.setAtlasDriven(True) self.mAtlasMap.setAtlasScalingMode(QgsComposerMap.Fixed) self.mAtlas.beginRender() for i in range(0, 2): self.mAtlas.prepareForFeature(i) self.mLabel1.adjustSizeToText() checker = QgsCompositionChecker('atlas_fixedscale%d' % (i + 1), self.mComposition) checker.setControlPathPrefix("atlas") myTestResult, myMessage = checker.testComposition(0, 200) assert myTestResult self.mAtlas.endRender() def predefinedscales_render_test(self): self.mAtlasMap.setNewExtent( QgsRectangle(209838.166, 6528781.020, 610491.166, 6920530.620)) self.mAtlasMap.setAtlasDriven(True) self.mAtlasMap.setAtlasScalingMode(QgsComposerMap.Predefined) scales = [1800000, 5000000] self.mAtlas.setPredefinedScales(scales) for i, s in enumerate(self.mAtlas.predefinedScales()): assert s == scales[i] self.mAtlas.beginRender() for i in range(0, 2): self.mAtlas.prepareForFeature(i) self.mLabel1.adjustSizeToText() checker = QgsCompositionChecker( 'atlas_predefinedscales%d' % (i + 1), self.mComposition) checker.setControlPathPrefix("atlas") myTestResult, myMessage = checker.testComposition(0, 200) assert myTestResult self.mAtlas.endRender() def hidden_render_test(self): self.mAtlasMap.setNewExtent( QgsRectangle(209838.166, 6528781.020, 610491.166, 6920530.620)) self.mAtlasMap.setAtlasScalingMode(QgsComposerMap.Fixed) self.mAtlas.setHideCoverage(True) self.mAtlas.beginRender() for i in range(0, 2): self.mAtlas.prepareForFeature(i) self.mLabel1.adjustSizeToText() checker = QgsCompositionChecker('atlas_hiding%d' % (i + 1), self.mComposition) checker.setControlPathPrefix("atlas") myTestResult, myMessage = checker.testComposition(0, 200) assert myTestResult self.mAtlas.endRender() self.mAtlas.setHideCoverage(False) def sorting_render_test(self): self.mAtlasMap.setNewExtent( QgsRectangle(209838.166, 6528781.020, 610491.166, 6920530.620)) self.mAtlasMap.setAtlasScalingMode(QgsComposerMap.Fixed) self.mAtlas.setHideCoverage(False) self.mAtlas.setSortFeatures(True) self.mAtlas.setSortKeyAttributeIndex(4) # departement name self.mAtlas.setSortAscending(False) self.mAtlas.beginRender() for i in range(0, 2): self.mAtlas.prepareForFeature(i) self.mLabel1.adjustSizeToText() checker = QgsCompositionChecker('atlas_sorting%d' % (i + 1), self.mComposition) checker.setControlPathPrefix("atlas") myTestResult, myMessage = checker.testComposition(0, 200) assert myTestResult self.mAtlas.endRender() def filtering_render_test(self): self.mAtlasMap.setNewExtent( QgsRectangle(209838.166, 6528781.020, 610491.166, 6920530.620)) self.mAtlasMap.setAtlasScalingMode(QgsComposerMap.Fixed) self.mAtlas.setHideCoverage(False) self.mAtlas.setSortFeatures(False) self.mAtlas.setFilterFeatures(True) self.mAtlas.setFeatureFilter( "substr(NAME_1,1,1)='P'") # select only 'Pays de la loire' self.mAtlas.beginRender() for i in range(0, 1): self.mAtlas.prepareForFeature(i) self.mLabel1.adjustSizeToText() checker = QgsCompositionChecker('atlas_filtering%d' % (i + 1), self.mComposition) checker.setControlPathPrefix("atlas") myTestResult, myMessage = checker.testComposition(0, 200) assert myTestResult self.mAtlas.endRender() def legend_test(self): self.mAtlasMap.setAtlasDriven(True) self.mAtlasMap.setAtlasScalingMode(QgsComposerMap.Auto) self.mAtlasMap.setAtlasMargin(0.10) # add a point layer ptLayer = QgsVectorLayer( "Point?crs=epsg:4326&field=attr:int(1)&field=label:string(20)", "points", "memory") pr = ptLayer.dataProvider() f1 = QgsFeature(1) f1.initAttributes(2) f1.setAttribute(0, 1) f1.setAttribute(1, "Test label 1") f1.setGeometry(QgsGeometry.fromPoint(QgsPoint(-0.638, 48.954))) f2 = QgsFeature(2) f2.initAttributes(2) f2.setAttribute(0, 2) f2.setAttribute(1, "Test label 2") f2.setGeometry(QgsGeometry.fromPoint(QgsPoint(-1.682, 48.550))) pr.addFeatures([f1, f2]) # categorized symbology r = QgsCategorizedSymbolRendererV2("attr", [ QgsRendererCategoryV2( 1, QgsMarkerSymbolV2.createSimple({"color": "255,0,0"}), "red"), QgsRendererCategoryV2( 2, QgsMarkerSymbolV2.createSimple({"color": "0,0,255"}), "blue") ]) ptLayer.setRendererV2(r) QgsMapLayerRegistry.instance().addMapLayer(ptLayer) # add the point layer to the map settings layers = self.mapSettings.layers() layers = [ptLayer.id()] + layers self.mapSettings.setLayers(layers) # add a legend legend = QgsComposerLegend(self.mComposition) legend.moveBy(200, 100) # sets the legend filter parameter legend.setComposerMap(self.mAtlasMap) legend.setLegendFilterOutAtlas(True) self.mComposition.addComposerLegend(legend) self.mAtlas.beginRender() self.mAtlas.prepareForFeature(0) self.mLabel1.adjustSizeToText() checker = QgsCompositionChecker('atlas_legend', self.mComposition) myTestResult, myMessage = checker.testComposition() assert myTestResult self.mAtlas.endRender() # restore state self.mapSettings.setLayers([layers[1]]) self.mComposition.removeComposerItem(legend) QgsMapLayerRegistry.instance().removeMapLayer(ptLayer.id())
class TileSet(): """ A set of tiles """ def __init__(self, map_theme, layer, extent, tile_size, mupp, output, make_trans, map_settings): """ :param map_theme: :param extent: :param layer: :param tile_size: :param mupp: :param output: :param map_settings: Map canvas map settings used for some fallback values and CRS """ self.extent = extent self.mupp = mupp self.tile_size = tile_size driver = self.getDriverForFile(output) if not driver: raise QgsProcessingException( u'Could not load GDAL driver for file {}'.format(output)) crs = map_settings.destinationCrs() self.x_tile_count = math.ceil(extent.width() / mupp / tile_size) self.y_tile_count = math.ceil(extent.height() / mupp / tile_size) xsize = self.x_tile_count * tile_size ysize = self.y_tile_count * tile_size if make_trans: no_bands = 4 else: no_bands = 3 self.dataset = driver.Create(output, xsize, ysize, no_bands) self.dataset.SetProjection(str(crs.toWkt())) self.dataset.SetGeoTransform( [extent.xMinimum(), mupp, 0, extent.yMaximum(), 0, -mupp]) self.image = QImage(QSize(tile_size, tile_size), QImage.Format_ARGB32) self.settings = QgsMapSettings() self.settings.setOutputDpi(self.image.logicalDpiX()) self.settings.setOutputImageFormat(QImage.Format_ARGB32) self.settings.setDestinationCrs(crs) self.settings.setOutputSize(self.image.size()) self.settings.setFlag(QgsMapSettings.Antialiasing, True) self.settings.setFlag(QgsMapSettings.RenderMapTile, True) self.settings.setFlag(QgsMapSettings.UseAdvancedEffects, True) if make_trans: self.settings.setBackgroundColor(QColor(255, 255, 255, 0)) else: self.settings.setBackgroundColor(QColor(255, 255, 255)) if QgsProject.instance().mapThemeCollection().hasMapTheme(map_theme): self.settings.setLayers(QgsProject.instance().mapThemeCollection(). mapThemeVisibleLayers(map_theme)) self.settings.setLayerStyleOverrides(QgsProject.instance( ).mapThemeCollection().mapThemeStyleOverrides(map_theme)) elif layer: self.settings.setLayers([layer]) else: self.settings.setLayers(map_settings.layers()) def render(self, feedback, make_trans): for x in range(self.x_tile_count): for y in range(self.y_tile_count): if feedback.isCanceled(): return cur_tile = x * self.y_tile_count + y num_tiles = self.x_tile_count * self.y_tile_count self.renderTile(x, y, feedback, make_trans) feedback.setProgress(int((cur_tile / num_tiles) * 100)) def renderTile(self, x, y, feedback, make_trans): """ Render one tile :param x: The x index of the current tile :param y: The y index of the current tile """ if make_trans: background_color = QColor(255, 255, 255, 0) self.image.fill(background_color.rgba()) else: background_color = QColor(255, 255, 255) self.image.fill(background_color.rgb()) painter = QPainter(self.image) self.settings.setExtent( QgsRectangle( self.extent.xMinimum() + x * self.mupp * self.tile_size, self.extent.yMaximum() - (y + 1) * self.mupp * self.tile_size, self.extent.xMinimum() + (x + 1) * self.mupp * self.tile_size, self.extent.yMaximum() - y * self.mupp * self.tile_size)) job = QgsMapRendererCustomPainterJob(self.settings, painter) job.renderSynchronously() painter.end() # Needs not to be deleted or Windows will kill it too early... tmpfile = tempfile.NamedTemporaryFile(suffix='.png', delete=False) try: self.image.save(tmpfile.name) src_ds = osgeo.gdal.Open(tmpfile.name) self.dataset.WriteRaster( x * self.tile_size, y * self.tile_size, self.tile_size, self.tile_size, src_ds.ReadRaster(0, 0, self.tile_size, self.tile_size)) except Exception as e: feedback.reportError(str(e)) finally: del src_ds tmpfile.close() os.unlink(tmpfile.name) def getDriverForFile(self, filename): """ Get the GDAL driver for a filename, based on its extension. (.gpkg, .mbtiles...) """ _, extension = os.path.splitext(filename) # If no extension is set, use .tif as default if extension == '': extension = '.tif' driver_name = QgsRasterFileWriter.driverForExtension(extension[1:]) return osgeo.gdal.GetDriverByName(driver_name)
class TestQgsAtlasComposition(unittest.TestCase): def testCase(self): self.TEST_DATA_DIR = unitTestDataPath() tmppath = tempfile.mkdtemp() for file in glob.glob(os.path.join(self.TEST_DATA_DIR, 'france_parts.*')): shutil.copy(os.path.join(self.TEST_DATA_DIR, file), tmppath) vectorFileInfo = QFileInfo(tmppath + "/france_parts.shp") mVectorLayer = QgsVectorLayer(vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr") QgsMapLayerRegistry.instance().addMapLayers([mVectorLayer]) # create composition with composer map self.mapSettings = QgsMapSettings() layerStringList = [] layerStringList.append(mVectorLayer.id()) self.mapSettings.setLayers(layerStringList) self.mapSettings.setCrsTransformEnabled(True) self.mapSettings.setMapUnits(QGis.Meters) # select epsg:2154 crs = QgsCoordinateReferenceSystem() crs.createFromSrid(2154) self.mapSettings.setDestinationCrs(crs) self.mComposition = QgsComposition(self.mapSettings) self.mComposition.setPaperSize(297, 210) # fix the renderer, fill with green props = {"color": "0,127,0"} fillSymbol = QgsFillSymbolV2.createSimple(props) renderer = QgsSingleSymbolRendererV2(fillSymbol) mVectorLayer.setRendererV2(renderer) # the atlas map self.mAtlasMap = QgsComposerMap(self.mComposition, 20, 20, 130, 130) self.mAtlasMap.setFrameEnabled(True) self.mComposition.addComposerMap(self.mAtlasMap) # the atlas self.mAtlas = self.mComposition.atlasComposition() self.mAtlas.setCoverageLayer(mVectorLayer) self.mAtlas.setEnabled(True) self.mComposition.setAtlasMode(QgsComposition.ExportAtlas) # an overview mOverview = QgsComposerMap(self.mComposition, 180, 20, 50, 50) mOverview.setFrameEnabled(True) mOverview.setOverviewFrameMap(self.mAtlasMap.id()) self.mComposition.addComposerMap(mOverview) nextent = QgsRectangle(49670.718, 6415139.086, 699672.519, 7065140.887) mOverview.setNewExtent(nextent) # set the fill symbol of the overview map props2 = {"color": "127,0,0,127"} fillSymbol2 = QgsFillSymbolV2.createSimple(props2) mOverview.setOverviewFrameMapSymbol(fillSymbol2) # header label self.mLabel1 = QgsComposerLabel(self.mComposition) self.mComposition.addComposerLabel(self.mLabel1) self.mLabel1.setText("[% \"NAME_1\" %] area") self.mLabel1.setFont(QgsFontUtils.getStandardTestFont()) self.mLabel1.adjustSizeToText() self.mLabel1.setSceneRect(QRectF(150, 5, 60, 15)) qWarning( "header label font: %s exactMatch:%s" % (self.mLabel1.font().toString(), self.mLabel1.font().exactMatch())) # feature number label self.mLabel2 = QgsComposerLabel(self.mComposition) self.mComposition.addComposerLabel(self.mLabel2) self.mLabel2.setText("# [%$feature || ' / ' || $numfeatures%]") self.mLabel2.setFont(QgsFontUtils.getStandardTestFont()) self.mLabel2.adjustSizeToText() self.mLabel2.setSceneRect(QRectF(150, 200, 60, 15)) qWarning("feature number label font: %s exactMatch:%s" % ( self.mLabel2.font().toString(), self.mLabel2.font().exactMatch())) self.filename_test() self.autoscale_render_test() self.autoscale_render_test_old_api() self.fixedscale_render_test() self.predefinedscales_render_test() self.hidden_render_test() self.legend_test() shutil.rmtree(tmppath, True) def filename_test(self): self.mAtlas.setFilenamePattern("'output_' || $feature") self.mAtlas.beginRender() for i in range(0, self.mAtlas.numFeatures()): self.mAtlas.prepareForFeature(i) expected = "output_%d" % (i + 1) assert self.mAtlas.currentFilename() == expected self.mAtlas.endRender() def autoscale_render_test(self): self.mAtlasMap.setAtlasDriven(True) self.mAtlasMap.setAtlasScalingMode(QgsComposerMap.Auto) self.mAtlasMap.setAtlasMargin(0.10) self.mAtlas.beginRender() for i in range(0, 2): self.mAtlas.prepareForFeature(i) self.mLabel1.adjustSizeToText() checker = QgsCompositionChecker('atlas_autoscale%d' % (i + 1), self.mComposition) checker.setControlPathPrefix("atlas") myTestResult, myMessage = checker.testComposition(0, 200) assert myTestResult self.mAtlas.endRender() self.mAtlasMap.setAtlasDriven(False) self.mAtlasMap.setAtlasScalingMode(QgsComposerMap.Fixed) self.mAtlasMap.setAtlasMargin(0) def autoscale_render_test_old_api(self): self.mAtlas.setComposerMap(self.mAtlasMap) self.mAtlas.setFixedScale(False) self.mAtlas.setMargin(0.10) self.mAtlas.beginRender() for i in range(0, 2): self.mAtlas.prepareForFeature(i) self.mLabel1.adjustSizeToText() checker = QgsCompositionChecker('atlas_autoscale_old_api%d' % (i + 1), self.mComposition) checker.setControlPathPrefix("atlas") myTestResult, myMessage = checker.testComposition(0, 200) assert myTestResult self.mAtlas.endRender() self.mAtlas.setFixedScale(True) self.mAtlas.setMargin(0) self.mAtlas.setComposerMap(None) self.mAtlasMap.setAtlasDriven(False) def fixedscale_render_test(self): self.mAtlasMap.setNewExtent(QgsRectangle(209838.166, 6528781.020, 610491.166, 6920530.620)) self.mAtlasMap.setAtlasDriven(True) self.mAtlasMap.setAtlasScalingMode(QgsComposerMap.Fixed) self.mAtlas.beginRender() for i in range(0, 2): self.mAtlas.prepareForFeature(i) self.mLabel1.adjustSizeToText() checker = QgsCompositionChecker('atlas_fixedscale%d' % (i + 1), self.mComposition) checker.setControlPathPrefix("atlas") myTestResult, myMessage = checker.testComposition(0, 200) assert myTestResult self.mAtlas.endRender() def predefinedscales_render_test(self): self.mAtlasMap.setNewExtent(QgsRectangle(209838.166, 6528781.020, 610491.166, 6920530.620)) self.mAtlasMap.setAtlasDriven(True) self.mAtlasMap.setAtlasScalingMode(QgsComposerMap.Predefined) scales = [1800000, 5000000] self.mAtlas.setPredefinedScales(scales) for i, s in enumerate(self.mAtlas.predefinedScales()): assert s == scales[i] self.mAtlas.beginRender() for i in range(0, 2): self.mAtlas.prepareForFeature(i) self.mLabel1.adjustSizeToText() checker = QgsCompositionChecker('atlas_predefinedscales%d' % (i + 1), self.mComposition) checker.setControlPathPrefix("atlas") myTestResult, myMessage = checker.testComposition(0, 200) assert myTestResult self.mAtlas.endRender() def hidden_render_test(self): self.mAtlasMap.setNewExtent(QgsRectangle(209838.166, 6528781.020, 610491.166, 6920530.620)) self.mAtlasMap.setAtlasScalingMode(QgsComposerMap.Fixed) self.mAtlas.setHideCoverage(True) self.mAtlas.beginRender() for i in range(0, 2): self.mAtlas.prepareForFeature(i) self.mLabel1.adjustSizeToText() checker = QgsCompositionChecker('atlas_hiding%d' % (i + 1), self.mComposition) checker.setControlPathPrefix("atlas") myTestResult, myMessage = checker.testComposition(0, 200) assert myTestResult self.mAtlas.endRender() self.mAtlas.setHideCoverage(False) def sorting_render_test(self): self.mAtlasMap.setNewExtent(QgsRectangle(209838.166, 6528781.020, 610491.166, 6920530.620)) self.mAtlasMap.setAtlasScalingMode(QgsComposerMap.Fixed) self.mAtlas.setHideCoverage(False) self.mAtlas.setSortFeatures(True) self.mAtlas.setSortKeyAttributeIndex(4) # departement name self.mAtlas.setSortAscending(False) self.mAtlas.beginRender() for i in range(0, 2): self.mAtlas.prepareForFeature(i) self.mLabel1.adjustSizeToText() checker = QgsCompositionChecker('atlas_sorting%d' % (i + 1), self.mComposition) checker.setControlPathPrefix("atlas") myTestResult, myMessage = checker.testComposition(0, 200) assert myTestResult self.mAtlas.endRender() def filtering_render_test(self): self.mAtlasMap.setNewExtent(QgsRectangle(209838.166, 6528781.020, 610491.166, 6920530.620)) self.mAtlasMap.setAtlasScalingMode(QgsComposerMap.Fixed) self.mAtlas.setHideCoverage(False) self.mAtlas.setSortFeatures(False) self.mAtlas.setFilterFeatures(True) self.mAtlas.setFeatureFilter("substr(NAME_1,1,1)='P'") # select only 'Pays de la loire' self.mAtlas.beginRender() for i in range(0, 1): self.mAtlas.prepareForFeature(i) self.mLabel1.adjustSizeToText() checker = QgsCompositionChecker('atlas_filtering%d' % (i + 1), self.mComposition) checker.setControlPathPrefix("atlas") myTestResult, myMessage = checker.testComposition(0, 200) assert myTestResult self.mAtlas.endRender() def legend_test(self): self.mAtlasMap.setAtlasDriven(True) self.mAtlasMap.setAtlasScalingMode(QgsComposerMap.Auto) self.mAtlasMap.setAtlasMargin(0.10) # add a point layer ptLayer = QgsVectorLayer("Point?crs=epsg:4326&field=attr:int(1)&field=label:string(20)", "points", "memory") pr = ptLayer.dataProvider() f1 = QgsFeature(1) f1.initAttributes(2) f1.setAttribute(0, 1) f1.setAttribute(1, "Test label 1") f1.setGeometry(QgsGeometry.fromPoint(QgsPoint(-0.638, 48.954))) f2 = QgsFeature(2) f2.initAttributes(2) f2.setAttribute(0, 2) f2.setAttribute(1, "Test label 2") f2.setGeometry(QgsGeometry.fromPoint(QgsPoint(-1.682, 48.550))) pr.addFeatures([f1, f2]) # categorized symbology r = QgsCategorizedSymbolRendererV2("attr", [QgsRendererCategoryV2(1, QgsMarkerSymbolV2.createSimple({"color": "255,0,0"}), "red"), QgsRendererCategoryV2(2, QgsMarkerSymbolV2.createSimple({"color": "0,0,255"}), "blue")]) ptLayer.setRendererV2(r) QgsMapLayerRegistry.instance().addMapLayer(ptLayer) # add the point layer to the map settings layers = self.mapSettings.layers() layers = [ptLayer.id()] + layers self.mapSettings.setLayers(layers) # add a legend legend = QgsComposerLegend(self.mComposition) legend.moveBy(200, 100) # sets the legend filter parameter legend.setComposerMap(self.mAtlasMap) legend.setLegendFilterOutAtlas(True) self.mComposition.addComposerLegend(legend) self.mAtlas.beginRender() self.mAtlas.prepareForFeature(0) self.mLabel1.adjustSizeToText() checker = QgsCompositionChecker('atlas_legend', self.mComposition) myTestResult, myMessage = checker.testComposition() assert myTestResult self.mAtlas.endRender() # restore state self.mapSettings.setLayers([layers[1]]) self.mComposition.removeComposerItem(legend) QgsMapLayerRegistry.instance().removeMapLayer(ptLayer.id())
def testReprojectionErrorsWhileRendering(self): # WKT of a polygon which causes reprojection errors while rendering # (apologies for the ridiculously complex wkt, but I can't find a way to reproduce with simplifiction) wkt = 'MultiPolygon (((16.93392988400009358 42.77094147300012139, 16.88493899800005238 42.72939687700012712, ' \ '16.80298912900011032 42.76349518400014915, 16.85816491000014139 42.78400299700011544, ' \ '16.93392988400009358 42.77094147300012139)),((17.38200931100010393 42.79783763200002511, ' \ '17.65894616000011297 42.74298737200008702, 17.74887129000009622 42.69456614800010641, ' \ '17.32374108200008322 42.79083893400003547, 17.38200931100010393 42.79783763200002511)),' \ '((16.768565300000148 42.97223541900014254, 17.03207441500009622 42.98261139500014849, ' \ '17.13184655000009116 42.96954987200014386, 17.20020592500009116 42.92177969000012183, ' \ '16.85141035200010151 42.90070221600008438, 16.65544681100004709 42.92625560099999404, ' \ '16.70679772200014668 42.96954987200014386, 16.63168379000003938 42.98261139500014849, ' \ '16.768565300000148 42.97223541900014254)),((17.05567467500011958 43.02895742400001211, ' \ '17.24024498800011429 43.02277252800014651, 17.74146569100011561 42.83926015800001608, ' \ '17.70736738400009358 42.88703034100014122, 17.65334906206413734 42.8909283361407887, ' \ '17.70158573400010482 42.91950022500007833, 17.81175988700005064 42.909862570000044, ' \ '17.85847538200005147 42.81697418200012351, 18.22413781700009849 42.62807098500009317, ' \ '18.43735477700010961 42.55921213800017711, 18.4371480710000526 42.4934022020000981, ' \ '18.49642988400009358 42.41632721600008438, 18.23894290500010129 42.55906810100005089, ' \ '18.21753991000014139 42.6201032570001388, 18.07601972700010151 42.65131256700003348, ' \ '18.0432235040000819 42.70205312700007028, 17.90162194100014403 42.75189850500014188, ' \ '17.8928328790000819 42.79083893400003547, 17.72095787900005348 42.8262393250000315, ' \ '17.7618921230000808 42.77871328300012976, 17.74870853000004445 42.77204010600017625, ' \ '17.21387780000011958 42.98261139500014849, 17.04615319100011561 42.9950625670000619, ' \ '17.00163821700004974 43.05149974200010377, 17.05567467500011958 43.02895742400001211)),' \ '((16.19467207100007045 43.07440827000000638, 16.254893425000148 43.06854889500006323, ' \ '16.08716881600014403 43.01146067900008063, 16.04883873800011429 43.06517161700004692, ' \ '16.19467207100007045 43.07440827000000638)),((16.56275475400011032 43.22898997600010773, ' \ '16.65951582100009887 43.21596914300012315, 16.72771243600001867 43.16461823100003414, ' \ '17.19336998800014271 43.12726471600016964, 16.67017662900013875 43.12547435099999404, ' \ '16.37159264400014536 43.19550202000006323, 16.49642988400006516 43.21808502800014651, ' \ '16.58326256600014403 43.18866608300005794, 16.52051842500006273 43.22898997600010773, ' \ '16.56275475400011032 43.22898997600010773)),((16.80681399800010922 43.34247467700005529, ' \ '16.89234459700011826 43.31220123900006058, 16.84620201900008851 43.27338288000005662, ' \ '16.62826582100012729 43.26373932500008834, 16.50074303500014139 43.28424713700003679, ' \ '16.42188561300008587 43.31757233300011478, 16.40577233200011165 43.33270905200011214, ' \ '16.45346113400009358 43.35317617400009738, 16.42628014400008851 43.39411041900011412, ' \ '16.44703209700008983 43.39484284100014122, 16.80681399800010922 43.34247467700005529)),' \ '((16.29818769600012729 43.40363190300011809, 16.30274498800008587 43.38727448100009099, ' \ '16.39144941500012465 43.34638092700005529, 16.348643425000148 43.33869049700003018, ' \ '16.20045006600014403 43.40704987200003018, 16.29818769600012729 43.40363190300011809)),' \ '((16.33415774800010922 43.50153229400014254, 16.3752547540000819 43.49017975500008504, ' \ '16.21143639400008851 43.49005768400009231, 16.26441491000014139 43.51288483300011478, ' \ '16.33415774800010922 43.50153229400014254)),((15.67888431100004709 43.64801666900014254, ' \ '15.74040774800010922 43.62750885600009099, 15.67204837300002396 43.63743724200010377, ' \ '15.60377037900013875 43.67470937700007028, 15.67888431100004709 43.64801666900014254)),' \ '((15.36736087300005238 43.79010651200015047, 15.39568118600007551 43.7724063170000619, ' \ '15.22779381600014403 43.87445709800014981, 15.24073326900014536 43.88076406500009341, ' \ '15.36736087300005238 43.79010651200015047)),((15.44271894600009887 43.89907461100013109, ' \ '15.35865319100014403 43.91937897300014981, 15.26124108200011165 44.01105377800003282, ' \ '15.38404381600008719 43.9701602230000077, 15.44271894600009887 43.89907461100013109)),' \ '((15.22575931100010393 44.06622955900014915, 15.25440514400008851 44.01788971600014122, ' \ '15.12183678500014139 44.09223053600005926, 15.06251061300008587 44.16193268400012073, ' \ '15.22575931100010393 44.06622955900014915)),((14.83545983200014007 44.15102773600013109, ' \ '14.85726972700010151 44.15204498900000374, 14.86915123800014271 44.14052969000006499, ' \ '14.83521569100008719 44.14166901200009363, 14.81983483200014007 44.15302155199999845, ' \ '14.82243899800005238 44.16868724200004692, 14.83545983200014007 44.15102773600013109)),' \ '((14.98511803500011297 44.09096914300012315, 15.21680748800008587 43.91278717700008372, ' \ '15.13331139400011693 43.92121002800003282, 15.19450931100004709 43.87262604400017096, ' \ '15.10661868600007551 43.92544179900015422, 14.84961998800014271 44.17560455900014915, ' \ '14.98511803500011297 44.09096914300012315)),((14.765961134000122 44.26504140800015819, ' \ '14.74854576900014536 44.26166413000014188, 14.73959394600012729 44.28017812700015554, ' \ '14.79167728000007287 44.27252838700003679, 14.765961134000122 44.26504140800015819)),' \ '((14.66138756600011561 44.30866120000014519, 14.6407983730000808 44.31183502800003282, ' \ '14.59506269600007045 44.34711334800006455, 14.643565300000148 44.32575104400011412, ' \ '14.66138756600011561 44.30866120000014519)),((14.81120853000004445 44.35004303600000242, ' \ '14.75619550900009358 44.36399974200004692, 14.76343834700008983 44.41535065300017493, ' \ '14.80323326900008851 44.40550364800004957, 14.81120853000004445 44.35004303600000242)),' \ '((14.27116946700002131 44.61253489800004957, 14.23259524800005238 44.62604401200012205, ' \ '14.2657983730000808 44.67951080900003547, 14.28044681100007551 44.67755768400009231, ' \ '14.27116946700002131 44.61253489800004957)),((14.84522545700008322 44.60053131700011875, ' \ '14.93824303500014139 44.59414297100001079, 15.07553144600007045 44.48407623900006058, ' \ '14.91114342500011958 44.54547760600014783, 15.04802493600004709 44.43943919500001982, ' \ '15.09669030000009116 44.41518789300000947, 15.04151451900014536 44.47662995000008834, ' \ '15.25440514400008851 44.34003327000000638, 15.165049675000148 44.36737702000006323, ' \ '15.22022545700008322 44.3127302100001117, 15.13086998800008587 44.33258698100003414, ' \ '15.17237389400014536 44.29913971600016964, 15.12875410200007309 44.31199778900018771, ' \ '15.08920332100009887 44.37421295800000109, 15.11719811300014271 44.38719310099999404, ' \ '15.04900149800010922 44.39468008000015686, 14.89747155000009116 44.49091217699999845, ' \ '14.91863040500010129 44.50454336100013109, 14.87696373800011429 44.55975983300005794, ' \ '14.73365319100008719 44.70319245000014519, 14.84522545700008322 44.60053131700011875)),' \ '((14.41000410200010151 44.60097890800001608, 14.52662194100011561 44.50372955900012073, ' \ '14.53435306100010393 44.48407623900006058, 14.42261803500008455 44.57387929900009738, ' \ '14.36304772200014668 44.57343170800000109, 14.38257897200014668 44.60325755399999537, ' \ '14.33578535200007309 44.71678294500010509, 14.39747155000009116 44.6856143250000315, ' \ '14.41000410200010151 44.60097890800001608)),((14.75326582100007045 44.84585195500012844, ' \ '14.74048912900011032 44.82050202000000638, 14.82243899800005238 44.77142975500005662, ' \ '14.84961998800014271 44.70319245000014519, 14.65788821700004974 44.79877350500014188, ' \ '14.7268172540000819 44.79877350500014188, 14.6858016290000819 44.8471540390000456, ' \ '14.75326582100007045 44.84585195500012844)),((14.47103925900006516 44.95392487200003018, ' \ '14.45191491000008455 44.79877350500014188, 14.47217858200011165 44.7079531920000619, ' \ '14.53435306100010393 44.63426341400010244, 14.51335696700007816 44.618841864000089, ' \ '14.42790774800005238 44.65656159100014122, 14.29420006600008719 44.9086367860001161, ' \ '14.30152428500011297 44.94342682500014519, 14.38738040500004445 44.90900299700003018, ' \ '14.39031009200004974 44.96039459800012139, 14.41138756600008719 44.95636627800014651, ' \ '14.27849368600004709 45.1133487000000315, 14.29957116000014139 45.16233958499999801, ' \ '14.35621178500014139 45.16925690300008966, 14.387705925000148 45.03904857000013351, ' \ '14.47103925900006516 44.95392487200003018)),((14.56332441500012465 45.24974192900008063, ' \ '14.62378991000011297 45.17548248900006058, 14.59742272200011826 45.16644928600005926, ' \ '14.66529381600011561 45.16181061400011743, 14.66529381600011561 45.08734772300006455, ' \ '14.74048912900011032 45.07306549700014386, 14.81495201900008851 44.97748444200009033, ' \ '14.70639082100009887 44.9467227230000077, 14.62891686300014271 44.97817617400004053, ' \ '14.62086022200008983 45.04559967700011214, 14.61695397200008983 45.02464427300007799, ' \ '14.51050866000014139 45.03217194200011875, 14.43873131600014403 45.07050202000006323, ' \ '14.4670516290000819 45.12409088700015047, 14.53012129000009622 45.13483307500014519, ' \ '14.53435306100010393 45.23753489800002114, 14.56332441500012465 45.24974192900008063)),' \ '((16.36947066200013978 46.54057118800012915, 16.63767134600004738 46.47447703100009164, ' \ '16.75508020000012266 46.38187286400001597, 16.83765913900006694 46.38187286400001597, ' \ '16.88923221800007468 46.29216257800014489, 17.05294315600005461 46.15346303300005104, ' \ '17.20859257000006437 46.11656606000003933, 17.27587528500004055 46.01202463800002818, ' \ '17.31680301900004793 45.99765859000002877, 17.29013798000011093 45.98463612900009423, ' \ '17.40620324700006449 45.94365671800015605, 17.59110152100009827 45.93621531200012953, ' \ '17.65652388500006964 45.84541982000014571, 17.80917606600013414 45.81441396100005647, ' \ '17.85806197100004056 45.77172922800004073, 18.21121870900006456 45.78537180600012846, ' \ '18.40438521300006869 45.74180857400001798, 18.57347049900010916 45.81668772400014689, ' \ '18.6556360270001278 45.90758656800015558, 18.7755253500000947 45.88283355700004051, ' \ '18.90130578600007993 45.93120269800006383, 18.87288374800004931 45.89523590100002082, ' \ '18.90699019400011593 45.86795074500018643, 18.85531376100007606 45.85735707600009903, ' \ '18.84497847500006174 45.8157058720000947, 18.96848514800012708 45.66873809800016204, ' \ '18.90357954900008508 45.57308502200005762, 18.94171675700005153 45.53892689999999277, ' \ '19.01809452300011571 45.56740061400002162, 19.10625451700005328 45.51164174500017623, ' \ '19.00961958800010621 45.49867095900005154, 19.00300500400010151 45.45536611000007099, ' \ '19.03742150900006891 45.42229319300010104, 18.97592655400006834 45.39495636000008005, ' \ '19.09199182100007874 45.34999786400005917, 19.12475467900009107 45.29811472600006539, ' \ '19.36308638500014467 45.24824696900010679, 19.40783817500010855 45.20313344400013023, ' \ '19.39068160000005037 45.16933705700016333, 19.22593713300008744 45.16194732700016345, ' \ '19.12186079900010327 45.195795390000157, 19.13767378700009658 45.14603098600004216, ' \ '19.04486291500009543 45.13724599300006446, 19.08227665200013234 45.08494944300004192, ' \ '19.0872375890000967 44.97710072800013847, 19.13167932100006396 44.95317454000003465, ' \ '19.06667036900009293 44.90568389900012392, 18.99142948400006503 44.9149339800001286, ' \ '19.01582076000008215 44.86563466400004074, 18.88962691200009658 44.86119049100013001, ' \ '18.78338016700013213 44.91374542300012251, 18.79175174900009893 45.00154368100008639, ' \ '18.73831831900008638 45.0159097290000858, 18.68405806500004473 45.08479441400000098, ' \ '18.64871138500012648 45.06267689999999959, 18.61667199700013953 45.09766184500010411, ' \ '18.54959598800010667 45.09476796500011631, 18.51703983500007666 45.05585561200003042, ' \ '18.23788374800011525 45.15745147700012296, 18.15365116400005263 45.0975584930001645, ' \ '18.00347945100011771 45.1493382780000303, 17.83573775200005684 45.0644338990000648, ' \ '17.68473921700012852 45.1639627080000281, 17.48185754400009273 45.11440500900012296, ' \ '17.49622359200009214 45.1416901650001563, 17.44775109900012922 45.13430043600014585, ' \ '17.44330692500011537 45.16205068000009248, 17.38243208800008688 45.1396231090000839, ' \ '17.26895064300006766 45.18954254200015441, 17.24548954300007608 45.15538442000017483, ' \ '17.18709517400012032 45.14856313100001728, 17.0363033440001459 45.23047027600007652, ' \ '17.00829471800011561 45.21615590500009318, 17.00829471800011561 45.24416453100009505, ' \ '16.94731652900014751 45.23568959600000028, 16.9243721930001243 45.28452382500016427, ' \ '16.81171757000004163 45.18122263700009, 16.52894413300009546 45.22225372400005483, ' \ '16.38921106000003647 45.11683380099999852, 16.31624393700010955 45.00123362300008978, ' \ '16.12152714000009723 45.09616322900008356, 16.02044803900011516 45.213933818000001, ' \ '15.79234826700013627 45.18980092400012438, 15.76361617000014803 44.97555043600003444, ' \ '15.7308533120001357 44.92723297200008403, 15.77343469200010873 44.84501576800015243, ' \ '15.71607385200013596 44.80320953400008932, 15.72847619600008784 44.76910308800002269, ' \ '15.80568078600006743 44.69665273000013883, 15.88877648900006534 44.72424794500012979, ' \ '15.96897831200004703 44.63924021400013942, 16.02830285600006732 44.62471913700009907, ' \ '16.04473596200011798 44.58937245700018082, 16.00608199000004106 44.54100331600012908, ' \ '16.11646285000011858 44.52146962500013672, 16.15966434700004584 44.41610138000002905, ' \ '16.13827030500004867 44.37760243800015303, 16.20286584400008678 44.35977406800010669, ' \ '16.18756962000011868 44.28241444999999032, 16.21578495300011014 44.20815541600011045, ' \ '16.32688928200008149 44.08237498000012522, 16.50103885900011846 43.99271637000008184, ' \ '16.67859908100004418 43.8406843060001421, 16.71260217300007866 43.77151540100005889, ' \ '17.03051558500007445 43.54847991900005866, 17.27050093600007585 43.46321380700000248, ' \ '17.28993127500007176 43.3034302780000786, 17.44206669100009321 43.15243174300015028, ' \ '17.6284119050001209 43.04657257100008394, 17.66272505700004558 42.96569895500012137, ' \ '17.63450972400008254 42.950402731000068, 17.51563561300008587 42.95888906500012183, ' \ '17.47087649800005238 43.01341380400010905, 17.50196373800014271 43.03099192900005221, ' \ '17.43360436300014271 43.01740143400009231, 17.46021569100011561 43.03099192900005221, ' \ '17.42611738400009358 43.06517161700004692, 17.4045516290000819 43.05149974200010377, ' \ '17.31625410200012993 43.12726471600016964, 17.11394290500004445 43.21320221600008438, ' \ '16.88062584700011826 43.40595123900006058, 16.62582441500009622 43.44904205900009231, ' \ '16.52466881600011561 43.51080963700009363, 16.39144941500012465 43.51080963700009363, ' \ '16.47339928500008455 43.5381533870001789, 16.43384850400013875 43.54975006700000506, ' \ '16.11768639400008851 43.52448151200003679, 16.17237389400014536 43.4896914730000077, ' \ '16.11312910200004467 43.47890859600009605, 15.95948326900011693 43.50397370000008834, ' \ '15.987315300000148 43.54490794500010509, 15.92530358200011165 43.55857982000004824, ' \ '15.91895592500009116 43.62872955900012073, 15.96631920700011165 43.64118073100003414, ' \ '15.90479576900014536 43.64801666900014254, 15.95297285200010151 43.65086497599999404, ' \ '15.95045006600008719 43.68854401200015047, 15.70630944100008719 43.76341380400005221, ' \ '15.6174422540000819 43.82550690300017493, 15.66309655000009116 43.81297435099999404, ' \ '15.67888431100004709 43.81928131700011875, 15.45508873800014271 43.92804596600014122, ' \ '15.14454186300011429 44.19546133000015686, 15.15219160200012993 44.23529694200014717, ' \ '15.11036217500011958 44.26434967700011214, 15.14063561300011429 44.28245677300013483, ' \ '15.17660566500009622 44.24994538000005662, 15.20777428500008455 44.27277252800014651, ' \ '15.19809004000012465 44.30166250200007028, 15.295258009000122 44.25067780199999845, ' \ '15.30274498800008587 44.29913971600016964, 15.26124108200011165 44.33258698100003414, ' \ '15.42448978000001603 44.26797109600006763, 15.52865644600009887 44.27179596600008438, ' \ '15.30795332100009887 44.35439687700007028, 15.00733483200014007 44.56972890800012976, ' \ '14.883799675000148 44.7236188820001388, 14.883799675000148 44.86147695500012844, 14.92164147200008983 ' \ '44.95880768400009231, 14.85279381600011561 45.09365469000000815, 14.65788821700004974 ' \ '45.19660065300017493, 14.57081139400008851 45.29364655200011214, 14.31153405000009116 ' \ '45.34398021000005485, 14.23259524800005238 45.14935944200000506, 14.17937259200007816 ' \ '45.13450755400005221, 14.19312584700008983 45.10561758000012844, 14.14389082100007045 ' \ '45.05939362200003018, 14.151377800000148 44.97748444200009033, 14.06885826900014536 ' \ '44.94953034100014122, 14.08383222700007309 44.9863955750000315, 14.04029381600014403 ' \ '45.03896719000015025, 14.0756942070000548 44.98371002800003282, 14.02051842500011958 ' \ '44.90110911700004692, 13.97266686300011429 44.90110911700004692, 13.99301191500009622 ' \ '44.88129303600014453, 13.97266686300011429 44.82664622599999404, 14.00001061300008587 ' \ '44.81305573100003414, 13.89014733200011165 44.83348216400010244, 13.91797936300014271 ' \ '44.77826569200009033, 13.90316816500009622 44.77240631700014717, 13.89698326900011693 ' \ '44.81305573100003414, 13.78711998800014271 44.87506745000008834, 13.84229576900008851 ' \ '44.88812897300006455, 13.79460696700010658 44.89496491100008768, 13.77409915500007287 ' \ '44.96381256700014717, 13.6232202480000808 45.07306549700014386, 13.61255944100014403 ' \ '45.11786530199999845, 13.72624759200004974 45.13450755400005221, 13.5959578790000819 ' \ '45.14541250200001343, 13.57545006600011561 45.26487864800007799, 13.60271243600001867 ' \ '45.28534577000012007, 13.57545006600011561 45.30646393400006389, 13.60954837300005238 ' \ '45.32013580900017757, 13.54127037900013875 45.34613678600005926, 13.50709069100014403 ' \ '45.51190827000000638, 13.62901778100007277 45.45898346000016943, 13.75929406800014476 ' \ '45.46316925100011019, 13.88900191200011136 45.42363678000005223, 13.98263960800005634 ' \ '45.47531321200001742, 13.97189091000012695 45.5142255660000643, 14.09291711400010172 ' \ '45.47391794800002174, 14.21869755100007637 45.49717234400004884, 14.37279667100006009 ' \ '45.47784535800009564, 14.4689148350000778 45.52559438100014688, 14.49857710800012001 ' \ '45.59618438800005435, 14.58094934100009255 45.66780792200010808, 14.66848921700008646 ' \ '45.53396596300005683, 14.79716353300005949 45.46518463200006011, 14.88160282300009385 ' \ '45.46978383400001178, 14.9226339110000481 45.51494903600017494, 15.13926151500010064 ' \ '45.43004465799999991, 15.32519331800011742 45.45283396399999276, 15.36136682100004691 ' \ '45.48203114900003641, 15.29666792800006192 45.52295888300012905, 15.2685559480001416 ' \ '45.60166208900012919, 15.37376916500011248 45.64021270800010655, 15.25501672300006817 ' \ '45.72346344000011698, 15.42906294700014769 45.77529490200011253, 15.45128381300008868 ' \ '45.81513743100013869, 15.67607629400006886 45.84169911700014666, 15.65943648300003588 ' \ '45.88882802400014782, 15.69798710100010908 46.0362092080000167, 15.58988000500005455 ' \ '46.11351715100001059, 15.62284956800010605 46.19170359400006021, 16.01920780400010358 ' \ '46.29882883700007312, 16.05961877400008575 46.33231516600015709, 16.0579651280001201 ' \ '46.37753204400003426, 16.2756262620000598 46.37316538500006402, 16.23490523300009158 ' \ '46.4933389280001137, 16.36947066200013978 46.54057118800012915))) ' geom = QgsGeometry.fromWkt(wkt) f = QgsFeature() f.setGeometry(geom) image = QImage(200, 200, QImage.Format_RGB32) painter = QPainter() ms = QgsMapSettings() crs = QgsCoordinateReferenceSystem.fromProj4( '+proj=ortho +lat_0=36.5 +lon_0=-118.8 +x_0=0 +y_0=0 +a=6371000 +b=6371000 +units=m +no_defs' ) self.assertTrue(crs.isValid()) ms.setDestinationCrs(crs) ms.setExtent(QgsRectangle(1374999.8, 3912610.7, 4724462.5, 6505499.6)) ms.setOutputSize(image.size()) context = QgsRenderContext.fromMapSettings(ms) context.setPainter(painter) context.setScaleFactor(96 / 25.4) # 96 DPI ct = QgsCoordinateTransform(QgsCoordinateReferenceSystem('epsg:4326'), crs, QgsProject.instance()) self.assertTrue(ct.isValid()) context.setCoordinateTransform(ct) context.setExtent( ct.transformBoundingBox(ms.extent(), QgsCoordinateTransform.ReverseTransform)) fill_symbol = QgsFillSymbol.createSimple({ 'color': '#ffffff', 'outline_color': '#ffffff', 'outline_width': '10' }) painter.begin(image) try: image.fill(QColor(0, 0, 0)) fill_symbol.startRender(context) fill_symbol.renderFeature(f, context) fill_symbol.stopRender(context) finally: painter.end() assert self.imageCheck('Reprojection errors polygon', 'reprojection_errors_polygon', image) #also test linestring linestring = QgsGeometry(geom.constGet().boundary()) f.setGeometry(linestring) line_symbol = QgsLineSymbol.createSimple({ 'color': '#ffffff', 'outline_width': '10' }) image = QImage(200, 200, QImage.Format_RGB32) painter.begin(image) try: image.fill(QColor(0, 0, 0)) line_symbol.startRender(context) line_symbol.renderFeature(f, context) line_symbol.stopRender(context) finally: painter.end() assert self.imageCheck('Reprojection errors linestring', 'reprojection_errors_linestring', image)
class TileSet(): """ A set of tiles """ def __init__(self, map_theme, layer, extent, tile_size, mupp, output, make_trans, map_settings): """ :param map_theme: :param extent: :param layer: :param tile_size: :param mupp: :param output: :param map_settings: Map canvas map settings used for some fallback values and CRS """ self.extent = extent self.mupp = mupp self.tile_size = tile_size driver = self.getDriverForFile(output) if not driver: raise QgsProcessingException( u'Could not load GDAL driver for file {}'.format(output)) crs = map_settings.destinationCrs() self.x_tile_count = math.ceil(extent.width() / mupp / tile_size) self.y_tile_count = math.ceil(extent.height() / mupp / tile_size) xsize = self.x_tile_count * tile_size ysize = self.y_tile_count * tile_size if make_trans: no_bands = 4 else: no_bands = 3 self.dataset = driver.Create(output, xsize, ysize, no_bands) self.dataset.SetProjection(str(crs.toWkt())) self.dataset.SetGeoTransform( [extent.xMinimum(), mupp, 0, extent.yMaximum(), 0, -mupp]) self.image = QImage(QSize(tile_size, tile_size), QImage.Format_ARGB32) self.settings = QgsMapSettings() self.settings.setOutputDpi(self.image.logicalDpiX()) self.settings.setOutputImageFormat(QImage.Format_ARGB32) self.settings.setDestinationCrs(crs) self.settings.setOutputSize(self.image.size()) self.settings.setFlag(QgsMapSettings.Antialiasing, True) self.settings.setFlag(QgsMapSettings.RenderMapTile, True) self.settings.setFlag(QgsMapSettings.UseAdvancedEffects, True) if make_trans: self.settings.setBackgroundColor(QColor(255, 255, 255, 0)) else: self.settings.setBackgroundColor(QColor(255, 255, 255)) if QgsProject.instance().mapThemeCollection().hasMapTheme(map_theme): self.settings.setLayers( QgsProject.instance().mapThemeCollection( ).mapThemeVisibleLayers( map_theme)) self.settings.setLayerStyleOverrides( QgsProject.instance().mapThemeCollection( ).mapThemeStyleOverrides( map_theme)) elif layer: self.settings.setLayers([layer]) else: self.settings.setLayers(map_settings.layers()) def render(self, feedback, make_trans): for x in range(self.x_tile_count): for y in range(self.y_tile_count): if feedback.isCanceled(): return cur_tile = x * self.y_tile_count + y num_tiles = self.x_tile_count * self.y_tile_count self.renderTile(x, y, feedback, make_trans) feedback.setProgress(int((cur_tile / num_tiles) * 100)) def renderTile(self, x, y, feedback, make_trans): """ Render one tile :param x: The x index of the current tile :param y: The y index of the current tile """ if make_trans: background_color = QColor(255, 255, 255, 0) self.image.fill(background_color.rgba()) else: background_color = QColor(255, 255, 255) self.image.fill(background_color.rgb()) painter = QPainter(self.image) self.settings.setExtent(QgsRectangle( self.extent.xMinimum() + x * self.mupp * self.tile_size, self.extent.yMaximum() - (y + 1) * self.mupp * self.tile_size, self.extent.xMinimum() + (x + 1) * self.mupp * self.tile_size, self.extent.yMaximum() - y * self.mupp * self.tile_size)) job = QgsMapRendererCustomPainterJob(self.settings, painter) job.renderSynchronously() painter.end() # Needs not to be deleted or Windows will kill it too early... tmpfile = tempfile.NamedTemporaryFile(suffix='.png', delete=False) try: self.image.save(tmpfile.name) src_ds = osgeo.gdal.Open(tmpfile.name) self.dataset.WriteRaster(x * self.tile_size, y * self.tile_size, self.tile_size, self.tile_size, src_ds.ReadRaster(0, 0, self.tile_size, self.tile_size)) except Exception as e: feedback.reportError(str(e)) finally: del src_ds tmpfile.close() os.unlink(tmpfile.name) def getDriverForFile(self, filename): """ Get the GDAL driver for a filename, based on its extension. (.gpkg, .mbtiles...) """ _, extension = os.path.splitext(filename) # If no extension is set, use .tif as default if extension == '': extension = '.tif' driver_name = QgsRasterFileWriter.driverForExtension(extension[1:]) return osgeo.gdal.GetDriverByName(driver_name)
def testRenderWithTransform(self): layer = QgsAnnotationLayer( 'test', QgsAnnotationLayer.LayerOptions( QgsProject.instance().transformContext())) self.assertTrue(layer.isValid()) item = QgsAnnotationPolygonItem( QgsPolygon( QgsLineString([ QgsPoint(11.5, 13), QgsPoint(12, 13), QgsPoint(12, 13.5), QgsPoint(11.5, 13) ]))) item.setSymbol( QgsFillSymbol.createSimple({ 'color': '200,100,100', 'outline_color': 'black', 'outline_width': '2' })) item.setZIndex(1) i1_id = layer.addItem(item) item = QgsAnnotationLineItem( QgsLineString( [QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)])) item.setSymbol( QgsLineSymbol.createSimple({ 'color': '#ffff00', 'line_width': '3' })) item.setZIndex(2) i2_id = layer.addItem(item) item = QgsAnnotationMarkerItem(QgsPoint(12, 13)) item.setSymbol( QgsMarkerSymbol.createSimple({ 'color': '100,200,200', 'size': '6', 'outline_color': 'black' })) item.setZIndex(3) i3_id = layer.addItem(item) layer.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) settings = QgsMapSettings() settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) settings.setExtent(QgsRectangle(1250958, 1386945, 1420709, 1532518)) settings.setOutputSize(QSize(300, 300)) settings.setFlag(QgsMapSettings.Antialiasing, False) rc = QgsRenderContext.fromMapSettings(settings) rc.setCoordinateTransform( QgsCoordinateTransform(layer.crs(), settings.destinationCrs(), QgsProject.instance())) rc.setExtent(rc.coordinateTransform().transformBoundingBox( settings.extent(), QgsCoordinateTransform.ReverseTransform)) image = QImage(200, 200, QImage.Format_ARGB32) image.setDotsPerMeterX(int(96 / 25.4 * 1000)) image.setDotsPerMeterY(int(96 / 25.4 * 1000)) image.fill(QColor(255, 255, 255)) painter = QPainter(image) rc.setPainter(painter) try: renderer = layer.createMapRenderer(rc) renderer.render() finally: painter.end() self.assertTrue( self.imageCheck('layer_render_transform', 'layer_render_transform', image)) # also check details of rendered items item_details = renderer.takeRenderedItemDetails() self.assertEqual([i.layerId() for i in item_details], [layer.id()] * 3) self.assertCountEqual([i.itemId() for i in item_details], [i1_id, i2_id, i3_id]) self.assertEqual( [i.boundingBox() for i in item_details if i.itemId() == i1_id][0], QgsRectangle(11.5, 13, 12, 13.5)) self.assertEqual( [i.boundingBox() for i in item_details if i.itemId() == i2_id][0], QgsRectangle(11, 13, 12, 15)) self.assertEqual([ i.boundingBox().toString(2) for i in item_details if i.itemId() == i3_id ][0], '11.94,12.94 : 12.06,13.06')