def getGeomPolygonRing(rings, idRing): # rings = [ QgsPointXY ] ringPoints = [ QgsPoint( p ) for p in rings[ idRing ] ] # [ QgsPoint ] line = QgsLineString( ringPoints ) del ringPoints[:] polygon = QgsPolygon() polygon.setExteriorRing( line ) del line return QgsGeometry( polygon )
def getSurfaces(self, geometry): surfaces = [] if isinstance(geometry, QgsGeometryCollection): # collection for i in range(geometry.numGeometries()): surfaces.extend(self.getSurfaces(geometry.geometryN(i))) else: # not collection if geometry.vertexCount() > 2: surface = QgsPolygon() surface.setExteriorRing(geometry.clone()) surfaces.append(surface) return surfaces
def convertToPolygon(self, geom): if QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.PointGeometry and geom.constGet().nCoordinates() < 3: raise QgsProcessingException( self.tr('Cannot convert from Point to Polygon').format(QgsWkbTypes.displayString(geom.wkbType()))) elif QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.PointGeometry: # multipoint with at least 3 points # TODO: mega inefficient - needs rework when geometry iterators land # (but at least it doesn't lose Z/M values) points = [] for g in geom.constGet().coordinateSequence(): for r in g: for p in r: points.append(p) linestring = QgsLineString(points) linestring.close() p = QgsPolygon() p.setExteriorRing(linestring) return [QgsGeometry(p)] elif QgsWkbTypes.geometryType(geom.wkbType()) == QgsWkbTypes.LineGeometry: if QgsWkbTypes.isMultiType(geom): parts = [] for i in range(geom.constGet().numGeometries()): p = QgsPolygon() linestring = geom.constGet().geometryN(i).clone() linestring.close() p.setExteriorRing(linestring) parts.append(QgsGeometry(p)) return QgsGeometry.collectGeometry(parts) else: # linestring to polygon p = QgsPolygon() linestring = geom.constGet().clone() linestring.close() p.setExteriorRing(linestring) return [QgsGeometry(p)] else: #polygon if QgsWkbTypes.isMultiType(geom): return geom.asGeometryCollection() else: return [geom]
def get_mesh_geometry(self, mesh, index): face = mesh.face(index) points = [mesh.vertex(v) for v in face] polygon = QgsPolygon() polygon.setExteriorRing(QgsLineString(points)) return QgsGeometry(polygon)
def testGeometryRendering(self): '''Tests rendering a bunch of different geometries, including bad/odd geometries.''' empty_multipolygon = QgsMultiPolygon() empty_multipolygon.addGeometry(QgsPolygon()) empty_polygon = QgsPolygon() empty_linestring = QgsLineString() tests = [ { 'name': 'Point', 'wkt': 'Point (1 2)', 'reference_image': 'point' }, { 'name': 'MultiPoint', 'wkt': 'MultiPoint ((10 30),(40 20),(30 10),(20 10))', 'reference_image': 'multipoint' }, { 'name': 'LineString', 'wkt': 'LineString (0 0,3 4,4 3)', 'reference_image': 'linestring' }, { 'name': 'Empty LineString', 'geom': QgsGeometry(empty_linestring), 'reference_image': 'empty' }, { 'name': 'MultiLineString', 'wkt': 'MultiLineString ((0 0, 1 0, 1 1, 2 1, 2 0), (3 1, 5 1, 5 0, 6 0))', 'reference_image': 'multilinestring' }, { 'name': 'Polygon', 'wkt': 'Polygon ((0 0, 10 0, 10 10, 0 10, 0 0),(5 5, 7 5, 7 7 , 5 7, 5 5))', 'reference_image': 'polygon' }, { 'name': 'Empty Polygon', 'geom': QgsGeometry(empty_polygon), 'reference_image': 'empty' }, { 'name': 'MultiPolygon', 'wkt': 'MultiPolygon (((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)),((4 0, 5 0, 5 2, 3 2, 3 1, 4 1, 4 0)))', 'reference_image': 'multipolygon' }, { 'name': 'Empty MultiPolygon', 'geom': QgsGeometry(empty_multipolygon), 'reference_image': 'empty' }, { 'name': 'CircularString', 'wkt': 'CIRCULARSTRING(268 415,227 505,227 406)', 'reference_image': 'circular_string' }, { 'name': 'CompoundCurve', 'wkt': 'COMPOUNDCURVE((5 3, 5 13), CIRCULARSTRING(5 13, 7 15, 9 13), (9 13, 9 3), CIRCULARSTRING(9 3, 7 1, 5 3))', 'reference_image': 'compound_curve' }, { 'name': 'CurvePolygon', 'wkt': 'CURVEPOLYGON(CIRCULARSTRING(1 3, 3 5, 4 7, 7 3, 1 3))', 'reference_image': 'curve_polygon' }, { 'name': 'MultiCurve', 'wkt': 'MultiCurve((5 5,3 5,3 3,0 3),CIRCULARSTRING(0 0, 2 1,2 2))', 'reference_image': 'multicurve' }, { 'name': 'CurvePolygon_no_arc', # refs #14028 'wkt': 'CURVEPOLYGON(LINESTRING(1 3, 3 5, 4 7, 7 3, 1 3))', 'reference_image': 'curve_polygon_no_arc' } ] for test in tests: def get_geom(): if 'geom' not in test: geom = QgsGeometry.fromWkt(test['wkt']) assert geom and not geom.isNull( ), 'Could not create geometry {}'.format(test['wkt']) else: geom = test['geom'] return geom geom = get_geom() rendered_image = self.renderGeometry(geom) assert self.imageCheck(test['name'], test['reference_image'], rendered_image) #Note - each test is repeated with the same geometry and reference image, but with added #z and m dimensions. This tests that presence of the dimensions does not affect rendering #test with Z geom_z = get_geom() geom_z.get().addZValue(5) rendered_image = self.renderGeometry(geom_z) assert self.imageCheck(test['name'] + 'Z', test['reference_image'], rendered_image) #test with ZM geom_z.get().addMValue(15) rendered_image = self.renderGeometry(geom_z) assert self.imageCheck(test['name'] + 'ZM', test['reference_image'], rendered_image) #test with M geom_m = get_geom() geom_m.get().addMValue(15) rendered_image = self.renderGeometry(geom_m) assert self.imageCheck(test['name'] + 'M', test['reference_image'], rendered_image)
def get_inner_rings_layer(self, names, plot_layer, id_field, use_selection=False): id_field_idx = plot_layer.fields().indexFromName(id_field) request = QgsFeatureRequest().setSubsetOfAttributes([id_field_idx]) polygons = plot_layer.getSelectedFeatures( request) if use_selection else plot_layer.getFeatures(request) layer = QgsVectorLayer( "LineString?crs={}".format(plot_layer.sourceCrs().authid()), "rings", "memory") data_provider = layer.dataProvider() data_provider.addAttributes([QgsField(names.T_ID_F, QVariant.Int)]) layer.updateFields() features = [] for polygon in polygons: polygon_geom = polygon.geometry() is_multipart = polygon_geom.isMultipart() # Does the current multipolygon have inner rings? has_inner_rings = False multi_polygon = None single_polygon = None if is_multipart: multi_polygon = polygon_geom.constGet() # TODO: remove when the error is resolved if type(multi_polygon) != QgsMultiPolygon: geom = QgsMultiPolygon() geom.fromWkt(polygon_geom.asWkt()) multi_polygon = geom for part in range(multi_polygon.numGeometries()): if multi_polygon.ringCount(part) > 1: has_inner_rings = True break else: single_polygon = polygon_geom.constGet() # TODO: remove when the error is resolved if type(single_polygon) != QgsPolygon: geom = QgsPolygon() geom.fromWkt(polygon_geom.asWkt()) single_polygon = geom if single_polygon.numInteriorRings() > 0: has_inner_rings = True if has_inner_rings: if is_multipart and multi_polygon: for i in range(multi_polygon.numGeometries()): temp_polygon = multi_polygon.geometryN(i) # TODO: remove when the error is resolved if type(temp_polygon) != QgsPolygon: geom = QgsPolygon() geom.fromWkt(temp_polygon.asWkt()) temp_polygon = geom for j in range(temp_polygon.numInteriorRings()): new_feature = QgsVectorLayerUtils().createFeature( layer, QgsGeometry( temp_polygon.interiorRing(j).clone()), {0: polygon[id_field]}) features.append(new_feature) elif not is_multipart and single_polygon: for j in range(single_polygon.numInteriorRings()): new_feature = QgsVectorLayerUtils().createFeature( layer, QgsGeometry( single_polygon.interiorRing(j).clone()), {0: polygon[id_field]}) features.append(new_feature) layer.dataProvider().addFeatures(features) layer.updateExtents() layer.reload() return layer
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 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')
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 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')
def testItems(self): layer = QgsAnnotationLayer( 'test', QgsAnnotationLayer.LayerOptions( QgsProject.instance().transformContext())) self.assertTrue(layer.isValid()) self.assertTrue(layer.isEmpty()) self.assertIsNone(layer.item('xxxx')) self.assertIsNone(layer.item('')) polygon_item_id = layer.addItem( QgsAnnotationPolygonItem( QgsPolygon( QgsLineString([ QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15), QgsPoint(12, 13) ])))) linestring_item_id = layer.addItem( QgsAnnotationLineItem( QgsLineString( [QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)]))) marker_item_id = layer.addItem( QgsAnnotationMarkerItem(QgsPoint(12, 13))) self.assertEqual(len(layer.items()), 3) self.assertFalse(layer.isEmpty()) self.assertIsInstance(layer.items()[polygon_item_id], QgsAnnotationPolygonItem) self.assertIsInstance(layer.items()[linestring_item_id], QgsAnnotationLineItem) self.assertIsInstance(layer.items()[marker_item_id], QgsAnnotationMarkerItem) self.assertIsInstance(layer.item(polygon_item_id), QgsAnnotationPolygonItem) self.assertIsInstance(layer.item(linestring_item_id), QgsAnnotationLineItem) self.assertIsInstance(layer.item(marker_item_id), QgsAnnotationMarkerItem) self.assertIsNone(layer.item('xxxx')) self.assertIsNone(layer.item('')) self.assertFalse(layer.removeItem('xxxx')) self.assertEqual(len(layer.items()), 3) self.assertTrue(layer.removeItem(linestring_item_id)) self.assertEqual(len(layer.items()), 2) self.assertIsInstance(layer.items()[polygon_item_id], QgsAnnotationPolygonItem) self.assertIsInstance(layer.items()[marker_item_id], QgsAnnotationMarkerItem) self.assertFalse(layer.removeItem(linestring_item_id)) self.assertTrue(layer.removeItem(polygon_item_id)) self.assertEqual(len(layer.items()), 1) self.assertIsInstance(layer.items()[marker_item_id], QgsAnnotationMarkerItem) self.assertTrue(layer.removeItem(marker_item_id)) self.assertEqual(len(layer.items()), 0) self.assertTrue(layer.isEmpty()) layer.addItem( QgsAnnotationPolygonItem( QgsPolygon( QgsLineString([ QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15), QgsPoint(12, 13) ])))) layer.addItem( QgsAnnotationLineItem( QgsLineString( [QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)]))) layer.addItem(QgsAnnotationMarkerItem(QgsPoint(12, 13))) self.assertEqual(len(layer.items()), 3) layer.clear() self.assertEqual(len(layer.items()), 0)