postgis gotchasinfo.citusdata.com/rs/235-cne-301/images/postgis_gotchas... · 2015. 11. 24. ·...

Post on 20-Jul-2021

3 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

PostGIS GotchasThe Things You Didn't Know That Lead to Confusion and Dismay

Paul Ramsey <pramsey@cartodb.com>

Wednesday, November 18, 15

Happy GIS day!What do you callthe day afterGIS day?

PostGIS Dayis tomorrow

Wednesday, November 18, 15

PostGIS GotchasThe Things You Didn't Know That Lead to Confusion and Dismay

Paul Ramsey <pramsey@cartodb.com>

Wednesday, November 18, 15

Honestly, I have no idea why it works like that...

Wednesday, November 18, 15

Projections

Wednesday, November 18, 15

Map projectionsare easy to

misunderstand, and is not obvious

how the database handles

them

Wednesday, November 18, 15

I’m a web developer,I don’t have to care aboutprojections.

Latitude, longitude, and leave me alone.

Wednesday, November 18, 15

POLYGON((1280119.03221134 500217.455871584, 1280261.61218257 499632.634256804, 1280190.99588308 499213.124106239, 1280099.24061359 499105.746442104, 1279651.62405538 498726.116394963, 1279257.64664648 498533.057113174, 1279171.59744916 498501.346411505, 1278841.58918754 498091.419596675, 1278713.36740315 497949.513489055, 1278527.51646549 497719.477195373... ))

Wednesday, November 18, 15

everygeometry

has an“srid”

spatial_ref_sys- srid- srtext

Wednesday, November 18, 15

POLYGON((1280119.03221134 500217.455871584, 1280261.61218257 499632.634256804, 1280190.99588308 499213.124106239, 1280099.24061359 499105.746442104, 1279651.62405538 498726.116394963, 1279257.64664648 498533.057113174, 1279171.59744916 498501.346411505, 1278841.58918754 498091.419596675, 1278713.36740315 497949.513489055, 1278527.51646549 497719.477195373... ))

srid = 3005

Wednesday, November 18, 15

srid = 3005SELECT  proj4text  FROM  spatial_ref_sys  WHERE  srid  =  3005

Wednesday, November 18, 15

srid = 3005

+proj=aea +lat_1=50 +lat_2=58.5 +lat_0=45 +lon_0=-126 +x_0=1000000 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_def

Wednesday, November 18, 15

Screwing UpProjections

Wednesday, November 18, 15

I’m a web developer,so I loaded the county data in latitude, longitude...

shp2pgsql  -­‐s  4326  parcels.shp

Wednesday, November 18, 15

POLYGON((1280119.03221134 500217.455871584, 1280261.61218257 499632.634256804, 1280190.99588308 499213.124106239, 1280099.24061359 499105.746442104, 1279651.62405538 498726.116394963, 1279257.64664648 498533.057113174, 1279171.59744916 498501.346411505, 1278841.58918754 498091.419596675, 1278713.36740315 497949.513489055, 1278527.51646549 497719.477195373... ))

srid = 4326

Wednesday, November 18, 15

srid = 4326

ALTER  TABLE  parcelsALTER  COLUMN  geomTYPE      Geometry(POLYGON,  3005)USING    ST_SetSRID(geom,  3005)

Wednesday, November 18, 15

POLYGON((1280119.03221134 500217.455871584, 1280261.61218257 499632.634256804, 1280190.99588308 499213.124106239, 1280099.24061359 499105.746442104, 1279651.62405538 498726.116394963, 1279257.64664648 498533.057113174, 1279171.59744916 498501.346411505, 1278841.58918754 498091.419596675, 1278713.36740315 497949.513489055, 1278527.51646549 497719.477195373... ))

srid = 3005

Wednesday, November 18, 15

ST_SetSRID(geometry, integer)vs

ST_Transform(geometry, integer)

Wednesday, November 18, 15

srid = 3005

ALTER  TABLE  parcelsALTER  COLUMN  geomTYPE      Geometry(POLYGON,  4326)USING    ST_Transform(geom,  4326)

Wednesday, November 18, 15

POLYGON((-122.137589562995 49.4494831202169, -122.136067204134 49.4441590695153, -122.137354118353 49.4404247925302, -122.138697187897 49.4395051093253, -122.1451402904 49.436313812165, -122.150704929813 49.434772105515, -122.15191243534 49.4345292778163, -122.156758770153 49.4310075640806, -122.158628595554 49.4297952058489, -122.161356817931 49.4278191153391... ))

srid = 4326

Wednesday, November 18, 15

ST_Distance(a,b)

Wednesday, November 18, 15

Lack ofProjections

Wednesday, November 18, 15

POINT(2.3508 48.8567)Paris

Los AngelesPOINT(-118.25 34.05)

Wednesday, November 18, 15

POINT(2.3508 48.8567)Paris

Los AngelesPOINT(-118.25 34.05)

ST_Distance()121.506

Actual Distance: 9107kmWednesday, November 18, 15

POINT(6050592 6877419)Paris

Los AngelesPOINT(1744760 -1146504)

ST_Transform(..., 3857)ST_Distance()

13606727

Actual Distance: 9107kmWednesday, November 18, 15

POINT(6050592 6877419)Paris

Los AngelesPOINT(1744760 -1146504)

ST_Transform(..., 3857)ST_Distance() * cos(radians(lat))

9621409

Actual Distance: 9107kmWednesday, November 18, 15

ST_Distance(a::geography, b::geography) 9107543

Actual Distance: 9107km

POINT(2.3508 48.8567)Paris

Los AngelesPOINT(-118.25 34.05)

Wednesday, November 18, 15

Dude, why didn’t you just tell me that right away?

Wednesday, November 18, 15

Geography

Wednesday, November 18, 15

Pythagoras (Plane)

double dx = x2 - x1double dy = y2 - y1;double d2 = dx * dx + dy * dy;double d = sqrt(d2);

Wednesday, November 18, 15

double R = 6371000; /* meters */double d_lat = lat2-lat1; /* radians */double d_lon = lon2-lon1; /* radians */double sin_lat = sin(d_lat/2);double sin_lon = sin(d_lon/2);double a = sin_lat * sin_lat +        cos(lat1) * cos(lat2) *         sin_lon * sin_lon; double c = 2 * atan2(sqrt(a), sqrt(1-a)); double d = R * c;

Haversine (Sphere)

Wednesday, November 18, 15

• ST_Area(g1)

• ST_Distance(g1, g2)

• ST_DWithin(g1, g2, d)

• ST_Intersects(g1, g2)

• ST_Covers(gpoly1, gpt2)

GEOGRAPHY Functions

Wednesday, November 18, 15

ST_Buffer(geography)

Wednesday, November 18, 15

                       geometry($1),          

ST_Buffer(geography)

               ST_Transform(                                _ST_BestSRID($1)                ),      

           ST_Buffer(                    $2),    

     ST_Transform(                    4326)  

SELECT  geography(                                            )

Wednesday, November 18, 15

_ST_BestSRID(geog)

Wednesday, November 18, 15

_ST_BestSRID(geog)

_ST_BestSRID(geog1, geog2)

Wednesday, November 18, 15

SELECT  geography(    ST_StartPoint(        geometry($1)    ))

ST_StartPoint(geography)

Wednesday, November 18, 15

GeodeticReasoning

Wednesday, November 18, 15

https://trac.osgeo.org/postgis/ticket/3357Wednesday, November 18, 15

https://trac.osgeo.org/postgis/ticket/3357Wednesday, November 18, 15

ST_Segmentize(geography, 100000)

Wednesday, November 18, 15

ST_Segmentize(geometry, 0.01)

Wednesday, November 18, 15

Why does ST_Extent(ST_Transform(geom))

not equalST_Transform(ST_Extent(geom))?

Wednesday, November 18, 15

ST_Transform()

Wednesday, November 18, 15

Dude, stop talking about projections.

Wednesday, November 18, 15

UnpredictablePerformance

Wednesday, November 18, 15

start-up nerd says....

Wednesday, November 18, 15

“I want to reverse-geocode 1000 points per second...”

Given a point, tell me what polygon(s) it is in.

(a) I have a real-time stream of 1000 points per second

(b) I have 1M points I need to process in 1000 seconds

Wednesday, November 18, 15

(a) I have a real-time stream of 1000 points per second

(b) I have 1M points I need to process in 1000 seconds

• Lots of small queries

• Find the candidate polygon(s) using r-tree index

• Test each candidate for point-in-polygon edge by edge: O(N)

SELECT * FROM polys WHERE ST_Intersects( geom, ST_SetSRID( ST_MakePoint({x},{y}), {srid}));

Wednesday, November 18, 15

(b) I have 1M points I need to process in 1000 seconds

• One big query

• Nested loop, tends to send the same polygons into the query, over and over

• PostGIS holds a cache of most recent polygon, with edge index built on it: O(log(N))

SELECT pt.id, poly.idFROM poly, ptWHERE ST_Intersects( poly.geom, pt.geom);

Wednesday, November 18, 15

“I want to reverse-geocode 1000 points per second...”

Given a point, tell me what polygon(s) it is in.

(a) I have a real-time stream of 1000 points per second

(b) I have 1M points I need to process in 1000 seconds

Wednesday, November 18, 15

Mysterious Operators

Wednesday, November 18, 15

Database nerd says,“So you mentioned indexes and r-trees,

but I haven’t seen any operators yet...”

Wednesday, November 18, 15

CREATE OR REPLACE FUNCTION ST_Intersects(geometry, geometry)RETURNS booleanAS 'SELECT $1 && $2 AND _ST_Intersects($1,$2)'LANGUAGE 'sql' IMMUTABLE;

Simple FeaturesFor SQL

Wednesday, November 18, 15

&&

Wednesday, November 18, 15

CREATE OPERATOR CLASS gist_geometry_ops_2d DEFAULT FOR TYPE geometry USING GIST AS STORAGE box2df, OPERATOR 1 << , OPERATOR 2 &< , OPERATOR 3 && , OPERATOR 4 &> , OPERATOR 5 >> , OPERATOR 6 ~= , OPERATOR 7 ~ , OPERATOR 8 @ , OPERATOR 9 &<| , OPERATOR 10 <<| , OPERATOR 11 |>> , OPERATOR 12 |&> , OPERATOR 13 <-> FOR ORDER BY pg_catalog.float_ops, OPERATOR 14 <#> FOR ORDER BY pg_catalog.float_ops, FUNCTION 8 geometry_gist_distance_2d (internal, geometry, int4), FUNCTION 1 geometry_gist_consistent_2d (internal, geometry, int4), FUNCTION 2 geometry_gist_union_2d (bytea, internal), FUNCTION 3 geometry_gist_compress_2d (internal), FUNCTION 4 geometry_gist_decompress_2d (internal), FUNCTION 5 geometry_gist_penalty_2d (internal, internal, internal), FUNCTION 6 geometry_gist_picksplit_2d (internal, internal), FUNCTION 7 geometry_gist_same_2d (geom1 geometry, geom2 geometry, internal);

Wednesday, November 18, 15

CREATE OPERATOR CLASS gist_geometry_ops_2d DEFAULT FOR TYPE geometry USING GIST AS ...

CREATE OPERATOR CLASS btree_geometry_ops DEFAULT FOR TYPE geometry USING btree AS OPERATOR 1 < , OPERATOR 2 <= , OPERATOR 3 = , OPERATOR 4 >= , OPERATOR 5 > , FUNCTION 1 geometry_cmp (geom1 geometry, geom2 geometry);

Wednesday, November 18, 15

CREATE INDEX myindex ON mytable (geom);

CREATE INDEX myindex USING GIST ON mytable (geom);

Wednesday, November 18, 15

SELECT * FROM mytable ORDER BY geom;

• Sort on xmin of bounding box unless they are equal...

• Sort on ymin of bounding box unless they are equal...

• Sort on xmax of bounding box unless they are equal...

• Sort on ymax of bounding box unless they are equal...

• Return “equality”

SELECT * FROM mytable GROUP BY geom;

Wednesday, November 18, 15

CREATE INDEX myindex USING GIST ON mytable (geom);

CREATE INDEX myindex USING GIST ON mytable (geom gist_geometry_ops_nd);

CREATE INDEX myindex USING GIST ON mytable (geog);

&&&

Wednesday, November 18, 15

MysteriousEmptiness

Wednesday, November 18, 15

philosophy nerd says“life is emptiness”

Wednesday, November 18, 15

A B

ST_Intersection(A, B)

Wednesday, November 18, 15

ST_Intersection(A, B)

POLYGON EMPTY

is not NULL

Wednesday, November 18, 15

A B

ST_Union(C,ST_Intersection(A, B))

C

Wednesday, November 18, 15

ST_Union(C, POLYGON EMPTY)

C

Wednesday, November 18, 15

GEOMETRY EMPTY

• Intersection of disjoint objects

• Simplification using tolerance larger than the object

• Negative buffering using radius larger than the object

• Differencing larger object from smaller

Wednesday, November 18, 15

More UnpredictablePerformance

Wednesday, November 18, 15

GIS nerd says

Wednesday, November 18, 15

“Overlay”

Wednesday, November 18, 15

SELECT a.id, b.id, ST_Intersection(a.geom, b.geom)FROM a, bWHERE ST_Intersects(a.geom, b.geom);

Wednesday, November 18, 15

Wednesday, November 18, 15

SELECT a.id, b.id, CASE WHEN ST_Contains(a.geom, b.geom) THEN b.geom ELSE ST_Intersection(a.geom, b.geom) END AS geomFROM a, bWHERE ST_Intersects(a.geom, b.geom);

Wednesday, November 18, 15

Prepared Geometry

•ST_Contains

• ST_ContainsProperly

•ST_Within

•ST_Covers

•ST_Intersects

Wednesday, November 18, 15

1 ProblemMany Solutions

Wednesday, November 18, 15

philosophy nerd says“when is a buffer

not a buffer?”

Wednesday, November 18, 15

SELECT a.id, b.id FROM a, bWHERE ST_Intersects( a.geom, ST_Buffer(b.geom, 500));

SELECT a.id, b.id FROM a, bWHERE ST_Distance(a.geom, b.geom) < 500;

SELECT a.id, b.id FROM a, bWHERE ST_DWithin(a.geom, b.geom, 500);

Wednesday, November 18, 15

CREATE OR REPLACE FUNCTION ST_DWithin(geom1 geometry, geom2 geometry, float8) RETURNS boolean AS 'SELECT $1 && ST_Expand($2,$3) AND $2 && ST_Expand($1,$3) AND _ST_DWithin($1, $2, $3)' LANGUAGE 'sql' IMMUTABLE;

Wednesday, November 18, 15

RasterDisaster

Wednesday, November 18, 15

Wednesday, November 18, 15

Wednesday, November 18, 15

Wednesday, November 18, 15

HiddenFeatures

Wednesday, November 18, 15

SET  postgis.backend  =  ‘geos’;SET  postgis.backend  =  ‘sfcgal’;

Wednesday, November 18, 15

• ST_3DIntersection

• ST_Tesselate

• ST_3DArea

• ST_Extrude

• ST_ForceLHR

• ST_Orientation

• ST_Minkowski

• ST_StraightSkeleton

Wednesday, November 18, 15

New to 2.2!

ST_ApproximateMedialAxis()

Wednesday, November 18, 15

CREATE  EXTENSION  postgis_sfcgal;

CREATE  EXTENSION  postgis_tiger_geocoder;

CREATE  EXTENSION  postgis_topology;

CREATE  EXTENSION  postgis_raster;

Wednesday, November 18, 15

Even MoreHidden Features

Wednesday, November 18, 15

github.com/pgpointcloud

Wednesday, November 18, 15

pgRouting: A Practical Guidehttp://

.com/pgrouting

pgrouting.org

Wednesday, November 18, 15

Honestly, I have no idea why it works like that...

Wednesday, November 18, 15

PostGIS GotchasThe Things You Didn't Know That Lead to Confusion and Dismay

Paul Ramsey <pramsey@cartodb.com>

Wednesday, November 18, 15

top related