Viktigt

Översättning är en gemenskapsinsats du kan gå med i. Den här sidan är för närvarande översatt till 100.00%.

7. Geometrihantering

Råd

Kodsnuttarna på den här sidan behöver följande import om du befinner dig utanför pyqgis-konsolen:

 1from qgis.core import (
 2  QgsGeometry,
 3  QgsGeometryCollection,
 4  QgsPoint,
 5  QgsPointXY,
 6  QgsWkbTypes,
 7  QgsProject,
 8  QgsFeatureRequest,
 9  QgsVectorLayer,
10  QgsDistanceArea,
11  QgsUnitTypes,
12  QgsCoordinateTransform,
13  QgsCoordinateReferenceSystem
14)

Punkter, linjestrengar och polygoner som representerar en rumslig egenskap kallas vanligen geometrier. I QGIS representeras de med klassen QgsGeometry.

Ibland är en geometri i själva verket en samling enkla (endelade) geometrier. En sådan geometri kallas en flerdelsgeometri. Om den bara innehåller en typ av enkel geometri kallar vi den multipunkt, multilinjestring eller multipolygon. Till exempel kan ett land som består av flera öar representeras som en multipolygon.

Geometriernas koordinater kan vara i valfritt koordinatreferenssystem (CRS). När funktioner hämtas från ett skikt kommer associerade geometrier att ha koordinater i skiktets CRS.

Beskrivning och specifikationer av alla möjliga geometrier, konstruktioner och relationer finns tillgängliga i OGC Simple Feature Access Standards för avancerade detaljer.

7.1. Geometri Konstruktion

PyQGIS erbjuder flera alternativ för att skapa en geometri:

  • från koordinater

    1gPnt = QgsGeometry.fromPointXY(QgsPointXY(1,1))
    2print(gPnt)
    3gLine = QgsGeometry.fromPolyline([QgsPoint(1, 1), QgsPoint(2, 2)])
    4print(gLine)
    5gPolygon = QgsGeometry.fromPolygonXY([[QgsPointXY(1, 1),
    6    QgsPointXY(2, 2), QgsPointXY(2, 1)]])
    7print(gPolygon)
    

    Koordinater anges med hjälp av klassen QgsPoint eller QgsPointXY. Skillnaden mellan dessa klasser är att QgsPoint stöder M- och Z-dimensioner.

    En Polyline (Linjestring) representeras av en lista med punkter.

    En polygon representeras av en lista med linjära ringar (dvs. slutna linjestringar). Den första ringen är den yttre ringen (gränsen), valfria efterföljande ringar är hål i polygonen. Observera att till skillnad från vissa program kommer QGIS att stänga ringen åt dig så att du inte behöver duplicera den första punkten som den sista.

    Geometrier med flera delar går en nivå längre: multi-point är en lista med punkter, multi-linestring är en lista med linestrings och multi-polygon är en lista med polygoner.

  • från välkänd text (WKT)

    geom = QgsGeometry.fromWkt("POINT(3 4)")
    print(geom)
    
  • från välkänd binär (WKB)

    1g = QgsGeometry()
    2wkb = bytes.fromhex("010100000000000000000045400000000000001440")
    3g.fromWkb(wkb)
    4
    5# print WKT representation of the geometry
    6print(g.asWkt())
    

7.2. Tillgång till geometri

Först bör du ta reda på geometritypen. Metoden wkbType() är den som ska användas. Den returnerar ett värde från QgsWkbTypes.Type uppräkning.

1print(gPnt.wkbType())
2# output: 1
3print(gLine.wkbType())
4# output: 2
5print(gPolygon.wkbType())
6# output: 3

Som ett alternativ kan man använda metoden type() som returnerar ett värde från uppräkningen QgsWkbTypes.GeometryType.

print(gLine.type())
# output: 1

Du kan använda funktionen displayString() för att få en geometrityp som är läsbar för människor.

1print(QgsWkbTypes.displayString(gPnt.wkbType()))
2# output: 'Point'
3print(QgsWkbTypes.displayString(gLine.wkbType()))
4# output: 'LineString'
5print(QgsWkbTypes.displayString(gPolygon.wkbType()))
6# output: 'Polygon'

Det finns också en hjälpfunktion isMultipart() för att ta reda på om en geometri är multipart eller inte.

För att extrahera information från en geometri finns det accessorfunktioner för varje vektortyp. Här är ett exempel på hur man använder dessa accessorer:

1print(gPnt.asPoint())
2# output: <QgsPointXY: POINT(1 1)>
3print(gLine.asPolyline())
4# output: [<QgsPointXY: POINT(1 1)>, <QgsPointXY: POINT(2 2)>]
5print(gPolygon.asPolygon())
6# output: [[<QgsPointXY: POINT(1 1)>, <QgsPointXY: POINT(2 2)>, <QgsPointXY: POINT(2 1)>, <QgsPointXY: POINT(1 1)>]]

Observera

Tuplerna (x,y) är inte riktiga tupler, de är QgsPoint-objekt, värdena är tillgängliga med x() och y()-metoder.

För geometrier med flera delar finns liknande accessorfunktioner: asMultiPoint(), asMultiPolyline() och asMultiPolygon().

Det är möjligt att iterera över alla delar av en geometri, oavsett geometrins typ. T.ex.

geom = QgsGeometry.fromWkt( 'MultiPoint( 0 0, 1 1, 2 2)' )
for part in geom.parts():
  print(part.asWkt())
Point (0 0)
Point (1 1)
Point (2 2)
geom = QgsGeometry.fromWkt( 'LineString( 0 0, 10 10 )' )
for part in geom.parts():
  print(part.asWkt())
LineString (0 0, 10 10)
gc = QgsGeometryCollection()
gc.fromWkt('GeometryCollection( Point(1 2), Point(11 12), LineString(33 34, 44 45))')
print(gc[1].asWkt())
Point (11 12)

Det är också möjligt att modifiera varje del av geometrin med QgsGeometry.parts()-metoden.

1geom = QgsGeometry.fromWkt( 'MultiPoint( 0 0, 1 1, 2 2)' )
2for part in geom.parts():
3  part.transform(QgsCoordinateTransform(
4    QgsCoordinateReferenceSystem("EPSG:4326"),
5    QgsCoordinateReferenceSystem("EPSG:3111"),
6    QgsProject.instance())
7  )
8
9print(geom.asWkt())
MultiPoint ((-10334726.79314758814871311 -5360105.10101194866001606),(-10462133.82917747274041176 -5217484.34365733992308378),(-10589398.51346861757338047 -5072020.35880533326417208))

7.3. Geometri Predikat och operationer

QGIS använder GEOS-biblioteket för avancerade geometrioperationer som geometripredikater (contains(), intersects(), …) och set-operationer (combine(), difference(), …). Den kan också beräkna geometriska egenskaper för geometrier, t.ex. area (för polygoner) eller längder (för polygoner och linjer).

Låt oss se ett exempel som kombinerar iterering över funktionerna i ett visst skikt och utförande av några geometriska beräkningar baserat på deras geometrier. Nedanstående kod kommer att beräkna och skriva ut arean och omkretsen för varje land i skiktet countries i vårt QGIS-projekt för handledning.

Följande kod förutsätter att layer är ett QgsVectorLayer-objekt som har funktionstypen Polygon.

 1# let's access the 'countries' layer
 2layer = QgsProject.instance().mapLayersByName('countries')[0]
 3
 4# let's filter for countries that begin with Z, then get their features
 5query = '"name" LIKE \'Z%\''
 6features = layer.getFeatures(QgsFeatureRequest().setFilterExpression(query))
 7
 8# now loop through the features, perform geometry computation and print the results
 9for f in features:
10  geom = f.geometry()
11  name = f.attribute('NAME')
12  print(name)
13  print('Area: ', geom.area())
14  print('Perimeter: ', geom.length())
1Zambia
2Area:  62.82279065343119
3Perimeter:  50.65232014052552
4Zimbabwe
5Area:  33.41113559136517
6Perimeter:  26.608288555013935

Nu har du beräknat och skrivit ut geometriernas area och omkrets. Du kanske dock snabbt märker att värdena är konstiga. Det beror på att areor och omkretsar inte tar hänsyn till CRS när de beräknas med hjälp av metoderna area() och length() från klassen QgsGeometry. För en mer kraftfull beräkning av yta och avstånd kan klassen QgsDistanceArea användas, som kan utföra ellipsoidbaserade beräkningar:

Följande kod förutsätter att layer är ett QgsVectorLayer-objekt som har funktionstypen Polygon.

 1d = QgsDistanceArea()
 2d.setEllipsoid('WGS84')
 3
 4layer = QgsProject.instance().mapLayersByName('countries')[0]
 5
 6# let's filter for countries that begin with Z, then get their features
 7query = '"name" LIKE \'Z%\''
 8features = layer.getFeatures(QgsFeatureRequest().setFilterExpression(query))
 9
10for f in features:
11  geom = f.geometry()
12  name = f.attribute('NAME')
13  print(name)
14  print("Perimeter (m):", d.measurePerimeter(geom))
15  print("Area (m2):", d.measureArea(geom))
16
17  # let's calculate and print the area again, but this time in square kilometers
18  print("Area (km2):", d.convertAreaMeasurement(d.measureArea(geom), QgsUnitTypes.AreaSquareKilometers))
1Zambia
2Perimeter (m): 5539361.250294601
3Area (m2): 751989035032.9031
4Area (km2): 751989.0350329031
5Zimbabwe
6Perimeter (m): 2865021.3325076113
7Area (m2): 389267821381.6008
8Area (km2): 389267.8213816008

Alternativt kanske du vill veta avståndet mellan två punkter.

 1d = QgsDistanceArea()
 2d.setEllipsoid('WGS84')
 3
 4# Let's create two points.
 5# Santa claus is a workaholic and needs a summer break,
 6# lets see how far is Tenerife from his home
 7santa = QgsPointXY(25.847899, 66.543456)
 8tenerife = QgsPointXY(-16.5735, 28.0443)
 9
10print("Distance in meters: ", d.measureLine(santa, tenerife))

Du kan hitta många exempel på algoritmer som ingår i QGIS och använda dessa metoder för att analysera och omvandla vektordata. Här är några länkar till koden för några av dem.