Last active
May 22, 2025 00:20
-
-
Save ivanlonel/c9cc2b17421a774b36410f217ea22ec8 to your computer and use it in GitHub Desktop.
Given a geometry and a plus code length (2, 4, 6, 8, 10, 11, 12, 13, 14, or 15), returns a grid of all rectangles represented by plus codes of that length that intersect the 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
-- https://dbfiddle.uk/3CgLervE | |
-- This uses function pluscode_decode, implemented here: | |
-- https://github.com/google/open-location-code/blob/main/plpgsql/pluscode_functions.sql | |
CREATE OR REPLACE FUNCTION pluscode_grid(original_geometry geometry, pluscode_length integer) | |
-- Given a geometry and a plus code length (2, 4, 6, 8, 10, 11, 12, 13, 14, or 15), returns a | |
-- grid of all rectangles represented by plus codes of that length that intersect the geometry. | |
RETURNS TABLE (pluscode text, geom geometry) | |
LANGUAGE SQL | |
IMMUTABLE | |
RETURNS NULL ON NULL INPUT | |
PARALLEL SAFE | |
BEGIN ATOMIC | |
WITH RECURSIVE constants AS ( | |
SELECT | |
'23456789CFGHJMPQRVWX' AS code_alphabet, | |
ST_Transform($1, 4326) AS wgs84_geom | |
), grid0 AS ( | |
-- Base case: Generate the 2-character plus codes | |
SELECT | |
geom, | |
pluscode, | |
2 AS code_length | |
FROM constants AS c, | |
generate_series(1, 9) AS i, | |
generate_series(1, 18) AS j, | |
concat( | |
substr(c.code_alphabet, i, 1), | |
substr(c.code_alphabet, j, 1), | |
'000000+' | |
) AS pluscode, | |
pluscode_decode(pluscode), | |
ST_MakeEnvelope(lng_lo, lat_lo, lng_hi, lat_hi, 4326) AS geom | |
WHERE ST_Intersects(wgs84_geom, geom) | |
UNION ALL | |
-- Recursive step for lengths 4, 6, 8, 10: Add two characters at a time | |
SELECT | |
pluscode_geom, | |
code, | |
g.code_length + 2 | |
FROM grid0 AS g, | |
constants AS c, | |
generate_series(1, 20) AS i, | |
generate_series(1, 20) AS j, | |
concat( | |
CASE g.code_length WHEN 8 THEN g.pluscode ELSE left(g.pluscode, g.code_length) END, | |
substr(c.code_alphabet, i, 1), | |
substr(c.code_alphabet, j, 1), | |
right('0000+', greatest(7 - g.code_length, 0)) | |
) AS code, | |
pluscode_decode(code), | |
ST_MakeEnvelope(lng_lo, lat_lo, lng_hi, lat_hi, 4326) AS pluscode_geom | |
WHERE g.code_length < 10 | |
AND g.code_length < $2 | |
AND ST_Intersects(wgs84_geom, pluscode_geom) | |
), grid AS ( | |
SELECT * FROM grid0 | |
UNION ALL | |
-- Recursive step for lengths 11 to 15: Add one character at a time | |
SELECT | |
pluscode_geom, | |
code, | |
g.code_length + 1 | |
FROM grid AS g, | |
constants AS c, | |
generate_series(1, 20) AS i, | |
concat( | |
g.pluscode, | |
substr(c.code_alphabet, i, 1) | |
) AS code, | |
pluscode_decode(code), | |
ST_MakeEnvelope(lng_lo, lat_lo, lng_hi, lat_hi, 4326) AS pluscode_geom | |
WHERE g.code_length >= 10 | |
AND g.code_length < $2 | |
AND ST_Intersects(wgs84_geom, pluscode_geom) | |
) | |
SELECT | |
pluscode, | |
ST_Transform(geom, ST_SRID($1)) AS geom | |
FROM grid | |
WHERE code_length = $2; | |
END; |
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
-- https://dbfiddle.uk/3CgLervE | |
-- This uses function pluscode_decode, implemented here: | |
-- https://github.com/google/open-location-code/blob/main/plpgsql/pluscode_functions.sql | |
CREATE OR REPLACE FUNCTION pluscode_grid_compact(original_geometry geometry, pluscode_length integer) | |
-- Given a geometry and a plus code length, returns a set of non-overlapping rectangles represented | |
-- by plus codes of that length or lower which, together, contain the geometry, aiming to minimize | |
-- both the number of rectangles inside the geometry and the area outside it. | |
RETURNS TABLE (pluscode text, geom geometry) | |
LANGUAGE SQL | |
IMMUTABLE | |
RETURNS NULL ON NULL INPUT | |
PARALLEL SAFE | |
BEGIN ATOMIC | |
WITH RECURSIVE constants AS ( | |
SELECT | |
'23456789CFGHJMPQRVWX' AS code_alphabet, | |
ST_Transform($1, 4326) AS wgs84_geom | |
), grid0 AS ( | |
-- Base case: Generate the 2-character plus codes | |
SELECT | |
geom, | |
pluscode, | |
2 AS code_length, | |
FALSE AS contained | |
FROM constants AS c, | |
generate_series(1, 9) AS i, | |
generate_series(1, 18) AS j, | |
concat( | |
substr(c.code_alphabet, i, 1), | |
substr(c.code_alphabet, j, 1), | |
'000000+' | |
) AS pluscode, | |
pluscode_decode(pluscode), | |
ST_MakeEnvelope(lng_lo, lat_lo, lng_hi, lat_hi, 4326) AS geom | |
WHERE ST_Intersects(wgs84_geom, geom) | |
UNION ALL | |
-- Recursive step for lengths 4, 6, 8, 10: Add two characters at a time | |
SELECT | |
pluscode_geom, | |
code, | |
g.code_length + 2, | |
ST_Contains(wgs84_geom, pluscode_geom) | |
FROM grid0 AS g, | |
constants AS c, | |
generate_series(1, 20) AS i, | |
generate_series(1, 20) AS j, | |
concat( | |
CASE g.code_length WHEN 8 THEN g.pluscode ELSE left(g.pluscode, g.code_length) END, | |
substr(c.code_alphabet, i, 1), | |
substr(c.code_alphabet, j, 1), | |
right('0000+', greatest(7 - g.code_length, 0)) | |
) AS code, | |
pluscode_decode(code), | |
ST_MakeEnvelope(lng_lo, lat_lo, lng_hi, lat_hi, 4326) AS pluscode_geom | |
WHERE g.code_length < 10 | |
AND g.code_length < $2 | |
AND NOT g.contained | |
AND ST_Intersects(wgs84_geom, pluscode_geom) | |
), grid AS ( | |
SELECT * FROM grid0 | |
UNION ALL | |
-- Recursive step for lengths 11 to 15: Add one character at a time | |
SELECT | |
pluscode_geom, | |
code, | |
g.code_length + 1, | |
ST_Contains(wgs84_geom, pluscode_geom) | |
FROM grid AS g, | |
constants AS c, | |
generate_series(1, 20) AS i, | |
concat( | |
g.pluscode, | |
substr(c.code_alphabet, i, 1) | |
) AS code, | |
pluscode_decode(code), | |
ST_MakeEnvelope(lng_lo, lat_lo, lng_hi, lat_hi, 4326) AS pluscode_geom | |
WHERE g.code_length >= 10 | |
AND g.code_length < $2 | |
AND NOT g.contained | |
AND ST_Intersects(wgs84_geom, pluscode_geom) | |
) | |
SELECT | |
pluscode, | |
ST_Transform(geom, ST_SRID($1)) AS geom | |
FROM grid | |
WHERE contained OR code_length = $2; | |
END; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment