Dane przestrzenne w PHP

38
Systemy Informacji Przestrzennej Dane przestrzenne czyli Jak nauczyć PHP geografii? Michał Mackiewicz Szczyrk, 25- 27.10.2013 www.gis-support.pl

Transcript of Dane przestrzenne w PHP

Page 1: Dane przestrzenne w PHP

SystemyInformacji Przestrzennej

Dane przestrzenne

czyli

Jak nauczyć PHP geografii?

Michał Mackiewicz

Szczyrk, 25- 27.10.2013

www.gis-support.pl

Page 2: Dane przestrzenne w PHP

SystemyInformacji Przestrzennej

fot. monokini / sxc.hu

Page 3: Dane przestrzenne w PHP

SystemyInformacji Przestrzennej Tymczasem w internetach

Page 4: Dane przestrzenne w PHP

SystemyInformacji Przestrzennej

Podnosimy poprzeczkę

Page 5: Dane przestrzenne w PHP

SystemyInformacji Przestrzennej

Podnosimy poprzeczkę

„Znajdź wszystkie czynne sklepy monopolowe czynne w piątek po godzinie 19 nie dalej niż 5 km od hotelu Orle Gniazdo w Szczyrku”

Page 6: Dane przestrzenne w PHP

SystemyInformacji Przestrzennej Grzechy główne

SpatialIsNotSpecial

Page 7: Dane przestrzenne w PHP

SystemyInformacji Przestrzennej Ale co konkretnie jest „specjalne”?

●Typy danych●Relacje przestrzenne●Układy współrzędnych●Formaty przechowywania●Formaty wymiany

Page 8: Dane przestrzenne w PHP

SystemyInformacji Przestrzennej Typy danych

Punkt (POINT)

Linia (LINESTRING)

Poligon (POLYGON)

Fot.gimnick /sxc/hu

Fot. linder6580 / sxc.hu

Fot. ColinBroug / sxc.hu

Page 9: Dane przestrzenne w PHP

SystemyInformacji Przestrzennej Geometrie złożone

Poligon złożony (MULTIPOLYGON)

Linia złożona (MULTILINESTRING)

Rys. rybnik.eu

Rys. rzyjontko / Wikimedia Commons

Page 10: Dane przestrzenne w PHP

SystemyInformacji Przestrzennej Geometrie non-simple albo invalid

Poligon z bagnetem

Samoprzecinająca się linia

Page 11: Dane przestrzenne w PHP

SystemyInformacji Przestrzennej Relacje przestrzenne

rys. Krauss/Wikimedia Commons, CC-BY-SA

Page 12: Dane przestrzenne w PHP

SystemyInformacji Przestrzennej Układy współrzędnych

● Współrzędne mogą być geograficzne albo płaskie● Istnieje bardzo wiele układów współrzędnych● Układy identyfikowane są przez kod EPSG, tzw. SRID● Układy można przeliczać (transformować) z użyciem

odpowiednich bibliotek

Page 13: Dane przestrzenne w PHP

SystemyInformacji Przestrzennej Współrzędne geograficzne

South Pole

North Pole

Equator

Prime Meridian0

30

60-60

-30

90-90

0

30

-60

6090

-90

-30

180

-120

-150 150

120

o

o

oo

o

o

o

● Współrzędne sferyczne, jednostki - stopnie● Zakres od -90 do 90 (szerokość), -180 do 180 (długość)● Jednolite dla całego świata● Bardziej złożone obliczeniowo – uwzględnienie krzywizny Ziemi

Page 14: Dane przestrzenne w PHP

SystemyInformacji Przestrzennej Współrzędne płaskie

● Współrzędne kartezjańskie, jednostki – metry / stopy● Liczby 6-9 cyfrowe, najczęściej wyłącznie dodatnie● (bardzo) wiele lokalnych układów● Proste obliczenia – bez uwzględnienia krzywizny

Page 15: Dane przestrzenne w PHP

SystemyInformacji Przestrzennej Układ współrzędnych Google

● Współrzędne rysunku mapy w odwzorowaniu Merkatora● Ogromne zniekształcenia długości i powierzchni● Nadają się do renderowania map, ale nie do obliczeń

EPSG:900913EPSG:3785EPSG:3875

Page 16: Dane przestrzenne w PHP

SystemyInformacji Przestrzennej PHP a dane przestrzenne

ZŁA WIADOMOŚĆ

Większość bibliotek przeznaczonych do pracy z danymi przestrzennymi ma bardzo słabe wsparcie dla PHP

DOBRA WIADOMOŚĆ

Większość potrzebnych operacji na danych przestrzennych można wykonać po stronie bazy danych

Page 17: Dane przestrzenne w PHP

SystemyInformacji Przestrzennej Bazy danych dla geoinformacji

SQL

PostgreSQL + PostGISMS SQL Server (natywnie)SQLite + SpatiaLiteOracle (natywnie ograniczony zestaw funkcji, +Spatial)MySQL(natywnie)

NoSQL

MongoDB (2.4+ natywnie)CouchDB + GeoCouch

Page 18: Dane przestrzenne w PHP

SystemyInformacji Przestrzennej Bazy danych dla geoinformacji

Typy przestrzenne

Funkcje przestrzenne

Indeksy przestrzenne

Specjalne typy kolumn dedykowane przechowywaniu geometrii

Specjalne funkcje np. do obliczania długości, powierzchni, wyszukiwania wg kryteriów przestrzennych, testowania relacji przestrzennych

Ułatwiają wyszukiwanie wg kryteriów przestrzennych

Page 19: Dane przestrzenne w PHP

SystemyInformacji Przestrzennej Typy przestrzenne

Typ GEOMETRY

Typ GEOGRAPHY

Umożliwia przechowywanie geometrii w dowolnym układzie współrzędnych.Dane do obliczeń (np. maksymalna odległość) muszą być zadane w tych samych jednostkach, co układ współrzędnych.Dostępny w każdej bazie oferującej rozszerzenia przestrzenne

Umożliwia przechowywanie geometrii tylko w układzie współrzędnych geograficznych.Dane do obliczeń (np. maksymalna odległość) są zadawane w metrach.Dostępny w PostgreSQL + PostGIS, MS SQL Server

Wada: wolniejsze działanie, ograniczona liczba funkcji przestrzennych

Page 20: Dane przestrzenne w PHP

SystemyInformacji Przestrzennej Funkcje przestrzenne

Przykłady:

Służą do operacji na typach GEOMETRY i GEOGRAPHYPodstawą jest specyfikacja OpenGIS SQL/MMNazwy funkcji są częściowo zunifikowane między różnymi DBMS i mają przedrostek ST_

● Funkcje pomiarów – ST_Length (zwraca długość), ST_Area (zwraca powierzchnię), ST_Extent (zwraca zasięg), ST_Distance (zwraca odległość między 2 geometriami)

● Funkcje testujące relacje przestrzenne – ST_Equals (czy geometrie są identyczne?), ST_Intersects (czy geometrie się przecinają?), ST_Disjoint (czy geometrie nie mają punktów wspólnych?)

● Funkcje tworzące nowe geometrie – ST_Buffer (strefa buforowa o zadanym promieniu), ST_Intersection (część wspólna z przecięcia 2 geometrii)

● Funkcje eksportu – ST_AsText (zwraca geometrię w postaci tekstowej), ST_AsKML (zwraca geometrię w formie zgodnej z Google Earth)

● Funkcje importu – ST_GeomFromText (tworzy geometrię na podstawie tekstu w formacie WKT), ST_MakePoint (tworzy geometrię punktu na podstawie pary współrzędnych x i y)

Page 21: Dane przestrzenne w PHP

SystemyInformacji Przestrzennej Indeksy przestrzenne

PostGIS:

CREATE INDEX tabela1_gist ON tabela1(geom) USING gist;

SpatiaLite:

SELECT CreateSpatialIndex('tabela1','geom');

Służą do przyspieszenia wyszukiwania według kryteriów przestrzennych, np. w promieniu od zadanego punktu

Page 22: Dane przestrzenne w PHP

SystemyInformacji Przestrzennej Forma zapisu w bazie

ATRYBUTY GEOMETRIA

Dane opisoweDowolne typy dopuszczone przez DBMS

Kształt obiektuTyp GEOMETRY/GEOGRAPHYDane binarne

Dodatkowe ograniczenia dot. typu geometrii i układu współrzędnychNieobowiązkowe w aplikacjach WEB, przydatne dla DesktopGIS

Page 23: Dane przestrzenne w PHP

SystemyInformacji Przestrzennej Format wymiany: GeoJSON

● Prosty w użyciu i implementacji● Zgodny z bibliotekami WebGIS

(OpenLayers,Leaflet, Geo5)● Zgodny z aplikacjami DesktopGIS (np. QGIS)

i biblioteką GDAL/OGR● Opublikowany na GitHub automagicznie

zmienia się w mapę

Page 24: Dane przestrzenne w PHP

SystemyInformacji Przestrzennej GeoJSON - struktura

{'type' : 'FeatureCollection','features' : [

{'type' : Feature,'properties' : {

'atrybut1' : 'wartość1','atrybut2' : 2,'atrybut3' : false},'geometry': {

'type' : 'Point', //LineString, Polygon, MultiPolygon etc.'coordinates' : []

}},// etc, etc...

]}

Page 25: Dane przestrzenne w PHP

SystemyInformacji Przestrzennej GeoJSON – budowa w PHP

Haczyk:

Geometria musi być zapisana oddzielnie od atrybutów

Problemy z nim związane:

Trzeba znać nazwę kolumny z geometrią

Trzeba przekształcić geometrię z bazy na format zgodny z specyfikacją GeoJSON

Page 26: Dane przestrzenne w PHP

SystemyInformacji Przestrzennej Rozpoznanie kolumny z geometrią

Rozwiązanie 1. Zawsze trzymać się konwencji

Kolumnę geometrii zwykło się nazywać „geom” albo „the_geom” (stara konwencja)

Rozwiązanie 2. Uczynić nazwę kolumny geometrii definiowalną

Podanie nazwy kolumny geometrii jako jednego z parametrów zapytania do serwera i odczytanie z $_GET / $_POST

Rozwiązanie 3. Skorzystać z systemowej tabeli/widoku geometry_columns

Wymaga dodatkowego zapytania do bazy. Nie należy korzystać z information_schema ponieważ rozpoznaje geometrię jako typ USER_DEFINED – możliwa kolizja

Page 27: Dane przestrzenne w PHP

SystemyInformacji Przestrzennej

Przetworzenie geometrii z bazy na GeoJSON

Rozwiązanie 1. Skorzystanie z funkcji ST_AsGeoJSON (tylko PostGIS)

Rozwiązanie 2. Konwersja po stronie PHP

● Eksport funkcją ST_AsText (dostępna w PostGIS, MySQL, SQL Server, SpatiaLite) i własna funkcja parsowania

● Eksport funkcją ST_AsBinary (PostGIS, MySQL, SQL Server, SpatiaLite) i konwersja biblioteką geoPHP

● Użycie geoPHP bez funkcji eksportu (tylko PostGIS)

Page 28: Dane przestrzenne w PHP

SystemyInformacji Przestrzennej

Co zrobić z wynikiem ST_AsGeoJSON?

Rozwiązanie 1.

Rozwiązanie 2.

Page 29: Dane przestrzenne w PHP

SystemyInformacji Przestrzennej geoPHP

●Biblioteka na podwójnej licencji (Modified BSD albo GPL)●Nie ma dodatkowych zależności●Może wykorzystać moduł GEOS – wówczas dysponuje rozszerzonym zestawem funkcji●Możliwa integracja z Drupalem●Umożliwia:

● Odczyt i zapis geometrii w formatach tekstowych i WKB/EWKB (wewnętrzny PostGIS)

● Obliczanie długości i powierzchni● Obliczanie centroidu i zasięgu (bounding box)● Sprawdzenie układu współrzędnych● Rozbijanie geometrii złożonych na proste● Rozbijanie geometrii poligonowych i liniowych na punkty

http://github.com/phayes/geoPHP

Page 30: Dane przestrzenne w PHP

SystemyInformacji Przestrzennej GeoPHP – użycie z PostGIS

$sql = 'SELECT * FROM poi LIMIT 1';$row = $pdo->query($sql)->fetch();

//geometria pobrana bezpośrednio z bazy jest zakodowana w postaci HEX

$wkb = hex2bin($row['geom']);

$geophpGeom = geoPHP::load($wkb,'ewkb');$exporter = new GeoJSON();$geojsonArray = $exporter->getArray($geophpGeom);

Założenia:Instancja PDO o nazwie $pdo, tryb pobierania danych FETCH_ASSOCKolumna geometrii o nazwie geom

Page 31: Dane przestrzenne w PHP

SystemyInformacji Przestrzennej

GeoPHP – użycie z funkcją ST_AsBinary()

$sql = 'SELECT nazwa,adres,ST_AsBinary(geom) AS geom FROM poi LIMIT 1';$row = $pdo->query($sql)->fetch();

//geometria pobrana bezpośrednio z bazy jest zakodowana w postaci HEX

$wkb = hex2bin($row['geom']);

$geophpGeom = geoPHP::load($wkb,'wkb');$exporter = new GeoJSON();$geojsonArray = $exporter->getArray($geophpGeom);

Założenia:Instancja PDO o nazwie $pdo, tryb pobierania danych FETCH_ASSOCKolumna geometrii o nazwie geom

Page 32: Dane przestrzenne w PHP

SystemyInformacji Przestrzennej Kompletny skrypt (prawie DBMS-agnostic)

require_once('geoPHP/geoPHP.inc');$pdo = new PDO('pgsql:host=localhost;port=5432;dbname=gis;user=geo;password=***');$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);

$sql = 'SELECT nazwa,adres,ST_AsBinary(geom) AS geom FROM poi';$rs = $pdo->query($sql)->fetchAll();

$geojson = ['type'=>'FeatureCollection','features'=>[]];

foreach($rs as $row) {$wkb = hex2bin($row['geom']); $geophpGeom = geoPHP::load($wkb,'wkb');$exporter = new GeoJSON();$geojsonArray = $exporter->getArray($geophpGeom);unset($row['geom']);$feature = ['type'=>'Feature','geometry'=>$geojsonArray,'properties'=>[]];foreach($row as $key=>$value) {

$feature['properties'][$key] = $value;}array_push($geojson,$feature);

}

header('Content-type: application/json');echo json_encode($geojson);

Page 33: Dane przestrzenne w PHP

SystemyInformacji Przestrzennej Zapis geometrii z GeoJSON

$geojson = json_decode($_POST['geojson'],true);foreach($geojson['features'] as $feature) {

$geojsonGeom = $feature['geometry'];$attributes = $feature['properties'];$geophpGeom = geoPHP::load($geojsonGeom,'json');$wkbGeom = geoPHP::out($geophpGeom,'wkb');$hexHeom = bin2hex($wkbGeom);$columns = implode(',',array_keys($attributes));$values = array_values($attributes);$str = str_repeat('?,',count($values)).”ST_GeomFromWKB('$hexGeom',4326)”;$sql = „INSERT INTO tabela($columns,geom) VALUES($valueString)”;$stmt = $pdo->prepare($sql);$result = $stmt->execute($values);

}

Page 34: Dane przestrzenne w PHP

SystemyInformacji Przestrzennej

Zapis geometrii z pary współrzędnych

$x = $_POST['x'];$y = $_POST['y'];$info = $_POST['info'];

//dla PostGIS

$sql = INSERT INTO poi(info,geom) VALUES('$info',ST_SetSRID(ST_MakePoint($x,$y),4326));

//dla pozostałych

$sql = INSERT INTO poi(info,geom) VALUES('$info',ST_GeomFromText('POINT($x $y)',4326);

Page 35: Dane przestrzenne w PHP

SystemyInformacji Przestrzennej Format KML

Do użycia w Google Maps / Earth

Najważniejsze różnice:● Zapis atrybutów w postaci HTML● Opcjonalne dołączenie stylu

Pozyskiwanie z bazy danych:

PostGIS – funkcja ST_AsKML(geom)

Pozostałe – metoda geoPHP::out($geophpGeom,'kml')

Włączenie fragmentu surowego XML do DOM

Więcej informacji - https://developers.google.com/kml/articles/phpmysqlkml

Page 36: Dane przestrzenne w PHP

SystemyInformacji Przestrzennej

…no dobrze, ale gdzie jest ten sklep monopolowy?

Poszukiwanie w promieniu – ST_DWithin(geometria,promień) – tylko PostGIS

SELECT * FROM poi WHERE type='alcohol' AND open_till > 19 AND ST_DWithin(

geom,ST_GeomFromText('POINT(19.02456,49.72074)',4326),5000);

Page 37: Dane przestrzenne w PHP

SystemyInformacji Przestrzennej Więcej zasobów

●http://www.postgis.org●http://geophp.net●http://gis.stackexchange.com●http://www.bostongis.com

Page 38: Dane przestrzenne w PHP

SystemyInformacji Przestrzennej

Dziękuję za uwagę.