I detta inlägg försöker jag dokumentera enklast möjliga sättet att lägga till punkter i ett geopackage. Heter det förresten en eller ett geopackage(-fil)?
På sikt så vill jag använda detta för att spara data till en fil direkt från en Raspberry Pi med ansluten GPS.
Hur GPS ansluts och hur man läser data från denna har jag skrivit om tidigare, men nu vill jag kunna spara till något annat än en textfil.
Detta innebär lite fler utmaningar, men det är inte oöverkomligt.
För det första behöver man ha GDAL/OGR installerat med python-bindningar. För geopackage behöver GDAL även ”libsqlite3”.
from osgeo import ogr, osr # Skapa koordinatsystem för lagrets koordinater srs = osr.SpatialReference() srs.ImportFromEPSG(4326) # Skapa "driver" för geopackage gpkgDrv = ogr.GetDriverByName("GPKG") # Skapa en datakälla dS = gpkgDrv.CreateDataSource("filnamn.gpkg") # Skapa själva lagret med en geometri lr = dS.CreateLayer("filnamn.gpkg", srs, ogr.wkbPoint) # Skapa eventuella attribut, upprepa för flera fält fD = ogr.FieldDefn("textfält", ogr.OFTString) lr.CreateField(fD) # Hämta lagerdefinition lD = lr.GetLayerDefn() # Objektet... ft = ogr.Feature(lD) # Nästa rad skapar en enskild punkt punkt = ogr.Geometry(ogr.wkbPoint) # och lägger till en position i X, Y punkt.AddPoint(15,55) # Tilldela objektet positionen ft.SetGeometry(punkt) # Tilldela objektet attribut, upprepa för alla attribut ft.SetField("textfält", "attributvärde") # Skapa objektet i lagret lr.CreateFeature(ft) # Stäng filen och frigör resurser dS.Destroy()
Koden ovan skapar ett geopackage med en punkt, men vill man ha flera så behöver man göra lite anpassningar.
För att det skall gå att upprepa så skall ”ft” objektet skapas på nytt, för varje gång ett nytt objekt skall läggas till. Det block som inleds med # Objektet… skall därför upprepas för varje punkt som skall läggas till.
Nu har jag lagt till kommentarer vid varje rad i koden ovan så det ser mer ut än vad det är. Nu kan jag använda detta för att skapa en ”skrivare” för geopackage i mina pythonskript.
Vill man använda andra attributtyper än ”text” så kan man använda OFTInteger, OFTReal, OFTDate, med flera typer. Vissa av dessa har ytterligare egenskaper som kan eller bör sättas.
För att skapa funktioner så börjar jag med att ”bryta ut” det som jag vill kunna ändra i variabler.
EPSG = 4326 filnamn = "filnamn.gpkg" attrNamn = ["namn1", "namn2"] attrTyp = [ogr.OFTString, ogr.OFTString] lon = 15.2 # nytt värde för varje punkt lat = 55.3 # nytt värde för varje punkt attrVarde = ["Värde1", "Värde2"] # ny lista för varje punkt
Sedan kan man skicka dessa variabler med anrop av funktioner som skapar lagret, lägger till punkter och sedan avslutar.
skapaLager(EPSG, filnamn, attrNamn, attrTyp) # Upprepa för varje punkt nyPunkt(lon, lat, attrVarde) avslutaLager()
Själva funktionerna kan du nog själv lista ut hur de kan skrivas… eller?
Tänk bara på att deklarera eventuella ”globala” variabler om du inte är fruktansvärt kreativ med anropen.
Ja, ja! Okej då! Här kommer mina funktioner.
def skapaLager(EPSG, filnamn, attrNamn, attrTyp): gpkgDrv = ogr.GetDriverByName("GPKG") global dS dS = gpkgDrv.CreateDataSource(filnamn) global lr srs = osr.SpatialReference() srs.ImportFromEPSG(EPSG) lr = dS.CreateLayer(filnamn, srs, ogr.wkbPoint) for namn, typ in zip(attrNamn, attrTyp): fD = ogr.FieldDefn(namn, typ) lr.CreateField(fD) def nyPunkt(lon, lat, attrNamn, attrVarde): global lr lD = lr.GetLayerDefn() ft = ogr.Feature(lD) punkt = ogr.Geometry(ogr.wkbPoint) punkt.AddPoint(lon, lat) ft.SetGeometry(punkt) for namn, varde in zip(attrNamn, attrVarde): ft.SetField(namn, varde) lr.CreateFeature(ft) def avslutaLager(): global dS dS.Destroy()