Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recursive h3_grid_path_cells #93

Merged
merged 1 commit into from
Oct 21, 2022

Conversation

mngr777
Copy link
Contributor

@mngr777 mngr777 commented Oct 17, 2022

h3_grid_path_cells_recursive allows creating a path between arbitrary h3 indexes.

h3_grid_path_cells function fails if base cells of origin and destination are not neighbors or the same base cell (this is what happens in the case from #71, see cellToLocalIjk, and _getBaseCellDirection definitions). Additionally, it's not always possible to create a path across a base pentagon: the indexes must be on the same icosahedron face or faces sharing an edge (see this comment in the library).

Recursive function checks for this conditions before calling h3_grid_path_cells and uses ST_Centroid to find a middle point on the path and call itself on each half. It is possible that this middle point index is outside of path that h3 would have generated, especially for lower resolutions, but this doesn't seem to be a problem as h3_grid_path_cells output itself is not strictly defined.

There's no convenient way to check if indexes are on edge sharing faces, so the function just checks if they have a common face.

Example: res. 4 indexes from Baghdad to Osaka:

\set baghdad '\'POINT(44.366111 33.315278)\'::geometry::point'
\set osaka '\'POINT(135.502222 34.693889)\'::geometry::point'

-- path polygons WKT
SELECT ST_AsText(h3_cell_to_boundary_geometry(
    h3_grid_path_cells_recursive(
        h3_lat_lng_to_cell(:baghdad, 4),
        h3_lat_lng_to_cell(:osaka, 4))));

-- base cell polygons WKT
SELECT ST_AsText(h3_cell_to_boundary_geometry(h3)) FROM (
   SELECT DISTINCT h3_cell_to_parent(
       h3_grid_path_cells_recursive(
           h3_lat_lng_to_cell(:baghdad, 4),
           h3_lat_lng_to_cell(:osaka, 4)),
       0) as h3) as t;

-- path endpoints used in recursive calls, WKT (see function definition below)
SELECT ST_AsText(h3_cell_to_boundary_geometry(
    h3_grid_path_cells_recursive_endpoints(
        h3_lat_lng_to_cell(:baghdad, 4),
        h3_lat_lng_to_cell(:osaka, 4))));

baghdad-to-osaka-h3-res-4

CREATE OR REPLACE FUNCTION
    h3_grid_path_cells_recursive_endpoints(origin h3index, destination h3index) RETURNS SETOF h3index
AS $$
BEGIN
    IF (SELECT origin != destination
               AND NOT h3_are_neighbor_cells(origin, destination)
               AND ((base1 != base2 AND NOT h3_are_neighbor_cells(base1, base2))
                   OR ((h3_is_pentagon(base1) OR h3_is_pentagon(base2))
                       AND NOT (
                           h3_get_icosahedron_faces(origin)
                           && h3_get_icosahedron_faces(destination))))
        FROM (SELECT h3_cell_to_parent(origin, 0) AS base1,
                     h3_cell_to_parent(destination, 0) AS base2) AS t)
    THEN
        RETURN QUERY WITH
            points AS (
                SELECT
                    h3_cell_to_geometry(origin) AS g1,
                    h3_cell_to_geometry(destination) AS g2),
            cells AS (
                SELECT h3_lat_lng_to_cell(
                    ST_Centroid(ST_MakeLine(g1, g2)::geography),
                    h3_get_resolution(origin)) AS middle
                FROM points)
            SELECT h3_grid_path_cells_recursive_endpoints(origin, middle) FROM cells
            UNION
            SELECT h3_grid_path_cells_recursive_endpoints(middle, destination) FROM cells;
    ELSE
        RETURN QUERY SELECT origin UNION SELECT destination;
    END IF;
END;
$$ LANGUAGE 'plpgsql' IMMUTABLE STRICT PARALLEL SAFE;

@zachasme zachasme merged commit a9aca90 into zachasme:main Oct 21, 2022
@zachasme
Copy link
Owner

Thanks, this is super cool!

zachasme added a commit that referenced this pull request Oct 26, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants