Last active
August 29, 2015 14:04
-
-
Save andrewxhill/57b5bfc3e254a8409a8b to your computer and use it in GitHub Desktop.
PlpgSQL to cross dateline when drawing two points
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| -- See it on a map: | |
| -- | |
| -- with a as ( | |
| -- SELECT | |
| -- axh_crossdateline(the_geom_webmercator ORDER BY cartodb_id DESC) geom | |
| -- FROM | |
| -- deletetest | |
| -- ) | |
| -- SELECT geom AS the_geom_webmercator from a | |
| -- | |
| -- OR, write it back to a new table: | |
| -- | |
| -- with a as ( | |
| -- SELECT | |
| -- axh_crossdateline(the_geom_webmercator ORDER BY cartodb_id DESC) geom | |
| -- FROM | |
| -- deletetest | |
| -- ) | |
| -- SELECT ST_Transform(geom,4326) AS the_geom from a | |
| CREATE AGGREGATE axh_crossdateline (geometry) | |
| ( | |
| sfunc = axh_crossdateline_fn, | |
| stype = geometry | |
| ); | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| CREATE OR REPLACE FUNCTION AXH_CrossDateLine_fn (oldg GEOMETRY, newg GEOMETRY) | |
| RETURNS geometry as $$ | |
| DECLARE | |
| westmost GEOMETRY; | |
| eastmost GEOMETRY; | |
| curstr GEOMETRY; | |
| endpoint GEOMETRY; | |
| newseg GEOMETRY := NULL; | |
| h FLOAT8; | |
| p FLOAT8; | |
| zy FLOAT8; | |
| i INT; | |
| dir INT := 1; | |
| BEGIN | |
| IF newg IS NULL THEN | |
| RETURN oldg; | |
| END IF; | |
| IF oldg IS NULL THEN | |
| IF newg IS NULL THEN | |
| RETURN NULL; | |
| END IF; | |
| RETURN newg; | |
| END IF; | |
| IF ST_SRID(newg) != 3857 THEN | |
| RAISE EXCEPTION 'Expects the_geom_webmercator (SRID:3857) as input geometry'; | |
| END IF; | |
| IF ST_GeometryType(oldg) = 'ST_MultiLineString' THEN | |
| curstr := ST_GeometryN(oldg, ST_NumGeometries(oldg)); | |
| ELSE | |
| curstr := oldg; | |
| END IF; | |
| endpoint := ST_PointN(curstr, ST_NumPoints(curstr)); | |
| IF ABS(ST_X(ST_Transform(newg,4326)) - ST_X(ST_Transform(endpoint,4326))) > 180 THEN | |
| IF ST_X(endpoint) < ST_X(newg) THEN | |
| westmost := endpoint; | |
| eastmost := newg; | |
| ELSE | |
| westmost := newg; | |
| eastmost := endpoint; | |
| dir := 2; | |
| END IF; | |
| h := GREATEST(ST_Y(eastmost), ST_Y(westmost)) - LEAST(ST_Y(eastmost), ST_Y(westmost)); | |
| p := (h / (20037508.34 - ST_X(eastmost) + ST_X(westmost) + 20037508.34 )) * (20037508.34 - ST_X(eastmost)); | |
| zy := LEAST(ST_Y(eastmost), ST_Y(westmost)) + p; | |
| IF dir = 2 THEN | |
| curstr := ST_MakeLine( | |
| curstr, | |
| ST_MakeLine(eastmost, ST_SetSRID(ST_MakePoint(20037508.34, zy),3857)) | |
| ); | |
| newseg := ST_MakeLine(ST_SetSRID(ST_MakePoint(-20037508.34, zy),3857), westmost); | |
| ELSE | |
| curstr := ST_MakeLine( | |
| curstr, | |
| ST_MakeLine(westmost, ST_SetSRID(ST_MakePoint(-20037508.34, zy),3857)) | |
| ); | |
| newseg := ST_MakeLine(ST_SetSRID(ST_MakePoint(20037508.34, zy),3857), eastmost); | |
| END IF; | |
| ELSE | |
| curstr := ST_MakeLine(curstr, newg); | |
| END IF; | |
| IF ST_GeometryType(oldg) = 'ST_MultiLineString' THEN | |
| --put the multi back together | |
| IF ST_NumGeometries(oldg) > 1 THEN | |
| i := 2; | |
| eastmost := ST_GeometryN(oldg, 1); | |
| WHILE i < ST_NumGeometries(oldg) LOOP | |
| eastmost := ST_Collect(eastmost, ST_GeometryN(oldg, i)); | |
| i := i+1; | |
| END LOOP; | |
| curstr := ST_Collect(eastmost, curstr); | |
| END IF; | |
| END IF; | |
| -- Add the latest segment if there was one | |
| IF newseg IS NOT NULL THEN | |
| curstr := ST_Collect(curstr, newseg); | |
| END IF; | |
| RETURN curstr; | |
| END; | |
| $$ language plpgsql IMMUTABLE; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment