Skip to content

Instantly share code, notes, and snippets.

@LtGlahn
Created November 11, 2020 10:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save LtGlahn/9f5a5658c538d6c25a467e69c76cb1c1 to your computer and use it in GitHub Desktop.
Save LtGlahn/9f5a5658c538d6c25a467e69c76cb1c1 to your computer and use it in GitHub Desktop.
Stedsnavn i SSR versus navn på tunneller i NVDB
"""
Script som sammenligner navn på tunneller i NVDB med stedsnavn i SSR
Logikken er som følger:
- Søk i SSR skjer innafor boundingbox laget fra 500 meter buffer rundt tunnelløpene
(de forekomstene av objekttype 67 Tunnelløp som er datterobjekter av denne forekomsten av 581 Tunnel)
- Hvis nødvendig, søker vi flere ganger i SSR:
1. Først på eksakt match på NVDB navnet
2. Deretter wildcard-søk etter *tunnel* (innafor boundingbox)
3. Deretter fjerner vi tallord fra NVDB navnet (1, I, IV og så videre)
4. Deretter fjerner vi frasen "tunnel" (og feilstavinger av "tunnel", "tunellen" osv) fra 3)
5. Hvis ikke dette går så gir vi opp...
Resultatene lagres som geopackage og excel-regneark.
"""
import requests
import xmltodict
import pdb
import collections
import geopandas as gpd
from shapely import wkt
from shapely.geometry import LineString
from shapely.ops import unary_union
from pyproj import Transformer
import STARTHER # Kun nødvendig om du bruker https://github.com/LtGlahn/workinprogress, en omvei til nvdbapi-V3
import nvdbapiv3 # https://github.com/LtGlahn/nvdbapi-V3
def finnssrtunnel( nvdbnavn, geom, omkrets=500, rekursjon=False):
"""
Finner tunnelnavn i SSR innafor bbox rundt geom
Prøver primitiv "fuzzy search" om vi ikke får eksakt treff
se SSR api https://www.kartverket.no/en/api-and-data/stedsnavndata/brukarrettleiing-stadnamn-api
ARGUMENTS:
nvdbnavn: String, navn på tunnel i NVDB
geom: shapely geometrisk objekt.
KEYWORDS:
omkrets: Størrelse på boundingbox vi søker innafor
rekursjon: Boolean, hvis True og søket returnerer null treff så prøver vi ut ymse wildcard-pertubasjoner
RETURNS:
Tuple med følgende elementer:
ssrNavn: Liste med en oppføring per SSR-treff
ssrKvalitet: Angir om det er eksakt eller fuzzy treff
antallSsrTreff: Antall søketreff
ssrId: Liste med SSR ID for alle søketreffene
ssrSkrivemaateStatus: Liste med en oppføring per skrivestatus på treffene fra SSR
sokefrase: Søkefrasen som ga treff
ssrKommune: Liste med en oppføring per kommune som treffene befinner seg i
ssrNavnetype: Liste med en oppføring per SSR navnetype blant treffene
"""
(ostLL,nordLL,ostUR,nordUR) = geom.buffer(omkrets).bounds
ssrUrl = 'https://ws.geonorge.no/SKWS3Index/ssr/sok'
params= { 'navn' : nvdbnavn, 'ostLL' : ostLL, 'nordLL' : nordLL, 'ostUR': ostUR, 'nordUR' : nordUR, 'eksakteForst' : 'true' }
r = requests.get( ssrUrl, params=params)
ssrNavn = []
ssrKvalitet = 'INGEN'
antallSsrTreff = 0
ssrId = []
ssrSkrivemaateStatus = []
ssrKommune = []
ssrNavnetype = []
sokefrase = nvdbnavn
ssrNavnetype = []
if r.ok and '<?xml' in r.text[0:5] and not '<totaltAntallTreff>0</totaltAntallTreff>' in r.text:
r.encoding = 'utf-8'
myDict = xmltodict.parse( r.text )
ssrKvalitet = 'EKSAKT'
antallSsrTreff = int( myDict['sokRes']['totaltAntallTreff'] )
if isinstance( myDict['sokRes']['stedsnavn'], collections.OrderedDict ):
ssrNavn.append( myDict['sokRes']['stedsnavn']['stedsnavn'] )
ssrId.append( myDict['sokRes']['stedsnavn']['ssrId'] )
ssrSkrivemaateStatus.append( myDict['sokRes']['stedsnavn']['skrivemaatestatus'] )
ssrKommune.append( myDict['sokRes']['stedsnavn']['kommunenavn'] )
ssrNavnetype.append( myDict['sokRes']['stedsnavn']['navnetype'] )
elif isinstance( myDict['sokRes']['stedsnavn'], list):
ssrNavn.extend( [ x['stedsnavn'] for x in myDict['sokRes']['stedsnavn'] ] )
ssrId.extend( [ x['ssrId'] for x in myDict['sokRes']['stedsnavn'] ] )
ssrSkrivemaateStatus.extend( [ x['skrivemaatestatus'] for x in myDict['sokRes']['stedsnavn'] ] )
ssrKommune.extend( [ x['kommunenavn'] for x in myDict['sokRes']['stedsnavn'] ] )
ssrNavnetype.extend( [ x['navnetype'] for x in myDict['sokRes']['stedsnavn'] ] )
else:
print( 'Null treff??? This should not happen... ')
elif rekursjon:
# Får vi treff når vi søker på *tunnel* innafor bbox?
if antallSsrTreff == 0:
( ssrNavn, ssrKvalitet, antallSsrTreff, ssrId, ssrSkrivemaateStatus, sokefrase, ssrKommune, ssrNavnetype ) = \
finnssrtunnel( '*tunnel*', geom, omkrets=omkrets, rekursjon=False)
ssrKvalitet = 'Søkeord *tunnel*'
# Har vi telleord?
nysokefrase = fjerntelling( nvdbnavn )
if antallSsrTreff == 0 and nysokefrase != nvdbnavn:
print( 'Fjernet telling fra tunnelnavn', nvdbnavn, '=>', nysokefrase)
( ssrNavn, ssrKvalitet, antallSsrTreff, ssrId, ssrSkrivemaateStatus, sokefrase, ssrKommune, ssrNavnetype ) = \
finnssrtunnel( nysokefrase, geom, omkrets=omkrets, rekursjon=False)
ssrKvalitet = 'Fjernet tallord'
# Fjerner ordet "tunnel" fra søketermen, prøver igjen...
if antallSsrTreff == 0:
sokefrase2 = nysokefrase.lower()
sokefrase2 = sokefrase2.replace( 'tunnelen' , '')
sokefrase2 = sokefrase2.replace( 'tunelen' , '')
sokefrase2 = sokefrase2.replace( 'tunellen' , '')
sokefrase2 = sokefrase2.replace( 'tunell' , '')
sokefrase2 = sokefrase2.replace( 'tunnellen' , '')
sokefrase2 = sokefrase2.replace( 'tunnel' , '')
sokefrase2 = sokefrase2.replace( 'tunel' , '')
sokefrase2 = sokefrase2.strip()
( ssrNavn, ssrKvalitet, antallSsrTreff, ssrId, ssrSkrivemaateStatus, sokefrase, ssrKommune, ssrNavnetype ) = \
finnssrtunnel( sokefrase2, geom, omkrets=omkrets, rekursjon=False)
ssrKvalitet = 'Fjernet tallord og "tunnel"'
if antallSsrTreff == 0:
ssrKvalitet = 'INGEN'
print( 'Ingen søketreff', nvdbnavn, 'eller', sokefrase2 )
ssrSkrivemaateStatus = list( set( ssrSkrivemaateStatus ) )
ssrNavn = list( set( ssrNavn ) )
ssrKommune = list( set( ssrKommune ))
ssrNavnetype = list( set( ssrNavnetype ))
return( ssrNavn, ssrKvalitet, antallSsrTreff, ssrId, ssrSkrivemaateStatus, sokefrase, ssrKommune, ssrNavnetype )
def fjerntelling( tunnellnavn):
"""
Fjerner telling av typen Diggbartunnellen 1, Diggbartunnelen 2 og så videre
ARGUMENTS:
tunnelnavn - string
KEYWORDS:
None
RETURNS:
tunnelnavn
"""
navnebiter = tunnellnavn.split( )
godebiter = []
for bit in navnebiter:
try:
x = int( bit )
except ValueError:
if bit.upper() not in [ 'I', 'II', 'III', 'IV', 'V', 'VI' ]:
godebiter.append(bit)
else:
godebiter.append(bit)
nyttnavn = ' '.join( godebiter )
return nyttnavn
if __name__ == "__main__":
trans = Transformer.from_crs('EPSG:5973', 'EPSG:5972')
data = []
# For debugging
# miliste = [ 92204012, 237272463, 237272458, 275871985, 92204576, 92204147, 272037773, 440826971, 228222589, 83669781, 83645662 ]
# for objid in miliste:
# r = nvdbapiv3.finnid( objid, kunfagdata=True )
tunsok = nvdbapiv3.nvdbFagdata(581)
tun = tunsok.nesteNvdbFagObjekt()
while tun:
# Geometrihåndtering
geom = wkt.loads( tun.geometri['wkt'] )
(x, y) = trans.transform( geom.x, geom.y)
vref = tun.lokasjon['vegsystemreferanser'][0]['kortform']
mydict = { 'NVDB-id' : tun.id,
'vegkategori' : vref[0],
'vegsystemreferanse' : vref,
'Tunnelforvalterområde' : tun.egenskapverdi( 12087),
'Tunnel kommune' : tun.lokasjon['kommuner'][0],
'Navn i NVDB' : tun.egenskapverdi( 5225 ),
'Tunnelnummer' : tun.egenskapverdi( 9306 ),
'Brutus Id' : tun.egenskapverdi( 9329 ),
'Åpningsår' : tun.egenskapverdi( 'Åpningsår'),
'Offisiell lengde' : tun.egenskapverdi( 8945),
'Antall parallelle hovedløp' : tun.egenskapverdi( 3947 ),
'UTM32 Øst' : x,
'UTM32 Nord' : y
}
# Inspiserer datterobjekter av typen tunnelløp
tunfam = tun.relasjon( 67 )
kommuner = set( )
tlopgeom = LineString( )
if tunfam and 'vegobjekter' in tunfam.keys():
for datterId in tunfam['vegobjekter']:
datter = nvdbapiv3.finnid( datterId, kunfagdata=True )
if datter and 'geometri' in datter.keys():
kommuner = kommuner.union( set( [ str(x) for x in datter['lokasjon']['kommuner'] ] ) )
tlopgeom = unary_union([ tlopgeom, wkt.loads( datter['geometri']['wkt'] ) ])
elif datter:
print( tun.id, tun.egenskapverdi(5225), 'har datter uten geometri:', datter['id'])
else:
print( tun.id, tun.egenskapverdi(5225), 'har ugyldig tunnelløp-datterobjekt:', datterId )
mydict['Kommuner tunnelløp'] = ','.join( list( kommuner ) )
if len( list( kommuner )) == 0:
print( 'Fant ingen gyldige døtre for tunnel', tun.id, tun.egenskapverdi( 5225 ))
tlopgeom = geom
# Søker etter stedsnavn
if mydict['Navn i NVDB']:
( ssrNavn, ssrKvalitet, antallSsrTreff, ssrId, ssrSkrivemaateStatus, sokefrase, ssrKommune, ssrNavnetype ) = \
finnssrtunnel( mydict['Navn i NVDB'], tlopgeom, omkrets=500, rekursjon=True )
mydict['Navn i SSR'] = ','.join( ssrNavn )
# mydict['Kvalitet navnesøk'] = ssrKvalitet
mydict['Antall SSR-treff'] = antallSsrTreff
mydict['ssrId'] = ','.join( ssrId )
mydict['SSR Skrivemåtestatus'] = ','.join( ssrSkrivemaateStatus )
mydict['Søkefrase'] = sokefrase
mydict['SSR kommuner'] = ','.join( ssrKommune )
mydict['SSR navnetype'] = ','.join( ssrNavnetype )
mydict['geometry'] = geom
data.append( mydict )
tun = tunsok.nesteNvdbFagObjekt()
myGdf = gpd.GeoDataFrame( data )
myGdf.to_file( 'tunnelnavn.gpkg', driver='GPKG' )
myGdf.to_excel( 'tunnelnavn.xlsx', index=False)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment