1

I have knowledge graph with sf:Point (for example "POINT(51.95656412820512 5.880331774358974)"^^<http://www.opengis.net/ont/geosparql#wktLiteral>). I want to know which country or administrative region this point is located in (by way of checking wdt:P3896).

I know I can get the map data of a country using a federated query to wikidata:

PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX wdt: <http://www.wikidata.org/prop/direct/>
PREFIX wd: <http://www.wikidata.org/entity/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT * WHERE {
    SERVICE <https://query.wikidata.org/sparql> {
        ?country wdt:P31 wd:Q6256.
        ?country wdt:P3896 ?boundary .
        FILTER(?country = wd:Q55) .
        ?country rdfs:label  ?label .
        FILTER(lang(?label)="en") .
    }
}

This returns

country boundary label
wd:Q55 http://commons.wikimedia.org/data/main/Data:Nederland.map "Netherlands"@en

Is it possible to find out using a sparql query whether the given point is within the Netherlands?

There does not seem to be a sparql function to determine whether a point is within a geoshape (wdt:P3896). I could not find any other workable methods for answering such a question with sparql. Could anyone offer me advice?

1 Answers1

0

Depending on the level of aproximation you need, you could try the following SPARQL query as subquery:

SELECT ?country
WHERE {
  BIND(51.95656412820512 as ?lat)
  BIND(5.880331774358974 as ?lon)
  
  ?country wdt:P31 wd:Q6256 ;
           wdt:P1332 ?n ;
           wdt:P1333 ?s ;
           wdt:P1334 ?e ;
           wdt:P1335 ?w .
  bind( "^.* (-?[0-9\\.]+)[^0-9\\.]*$" as  ?latRegex )
  bind( "^[^0-9\\.]*?(-?[0-9\\.]+) .*$" as ?lonRegex )
  bind( xsd:float(replace( str(?n), ?latRegex, "$1" )) as ?nLat )
  bind( xsd:float(replace( str(?s), ?latRegex, "$1" )) as ?sLat )
  bind( xsd:float(replace( str(?e), ?lonRegex, "$1" )) as ?eLon )
  bind( xsd:float(replace( str(?w), ?lonRegex, "$1" )) as ?wLon )
  
  FILTER  (?lat <= ?nLat && ?lat >= ?sLat)
  FILTER ((?lon <= ?eLon && ?lon >= ?wLon) ||
         ((?lon <= ?eLon || ?lon >= ?wLon) && ?wLon > ?eLon))
}

You can try it here.

This basically aproximates countries as squares, so it could potentially return multiple countries. In general it seems to work quite good.

If you have multiple countries, you can also return the geoshape and verify the point containment offline.

P.S. Note that country (Q6256) is a quite generic class (the above query returns both Netherlands (Q55) and Kingdom of the Netherlands (Q29999)), you may want to replace it with something more precise.

logi-kal
  • 7,107
  • 6
  • 31
  • 43
  • Thank you for your answer. Sadly this does not completely for fill my requirements as I am interested into the borders of countries. I do think this may be usefull for other people though. – Sibbe Bakker Aug 14 '23 at 13:30