From 2ce42ac2a2a93b0e59f7d5ec8c84bfeb064992ba Mon Sep 17 00:00:00 2001 From: Zacharias Knudsen Date: Wed, 24 Aug 2022 13:37:05 +0200 Subject: [PATCH] Upgrade H3 core to `v4` (#54) Update `h3` core library to `v4.0.0`. Almost all functions have been renamed to align with `h3` core `v4`. Please take care when updating. --- .github/docker/Dockerfile | 16 +- .github/docker/tools.sh | 6 +- .github/documentation/generate.py | 3 + .github/documentation/sql.lark | 30 +- .github/workflows/test.yml | 16 +- .gitignore | 2 +- CHANGELOG.md | 22 +- META.json | 6 +- Makefile | 45 +- README.md | 22 +- docs/api.md | 415 ++++++++++-------- h3.control | 3 +- h3/sql/install/00-type.sql | 30 +- h3/sql/install/01-indexing.sql | 35 +- h3/sql/install/02-inspection.sql | 60 +-- h3/sql/install/03-traversal.sql | 77 ++-- h3/sql/install/04-hierarchy.sql | 113 +++-- h3/sql/install/05-regions.sql | 26 +- h3/sql/install/06-edge.sql | 76 ++++ h3/sql/install/06-uniedge.sql | 68 --- h3/sql/install/07-miscellaneous.sql | 67 --- h3/sql/install/07-vertex.sql | 47 ++ h3/sql/install/08-miscellaneous.sql | 75 ++++ h3/sql/install/10-operators.sql | 4 +- h3/sql/install/20-casts.sql | 37 ++ h3/sql/install/30-deprecated.sql | 25 -- .../{20-extension.sql => 30-extension.sql} | 2 +- h3/sql/install/99-postgis.sql | 78 ---- h3/sql/updates/h3--0.1.0--0.2.0.sql | 56 +-- h3/sql/updates/h3--0.2.0--0.3.0.sql | 4 +- h3/sql/updates/h3--0.3.0--0.3.1.sql | 4 +- h3/sql/updates/h3--0.3.2--0.4.0.sql | 4 +- h3/sql/updates/h3--3.4.1--3.5.0.sql | 6 +- h3/sql/updates/h3--3.5.0--3.6.0.sql | 6 +- h3/sql/updates/h3--3.6.5--3.7.0.sql | 8 +- h3/sql/updates/h3--3.7.2--4.0.0.sql | 253 +++++++++++ h3/src/include/extension.in.h | 18 +- h3/src/lib/{uniedges.c => edge.c} | 125 +++--- h3/src/lib/hierarchy.c | 155 +++---- h3/src/lib/indexing.c | 78 ++-- h3/src/lib/inspection.c | 52 ++- h3/src/lib/miscellaneous.c | 172 +++++--- h3/src/lib/opclass_btree.c | 2 +- h3/src/lib/opclass_hash.c | 4 +- h3/src/lib/operators.c | 18 +- h3/src/lib/regions.c | 121 ++--- h3/src/lib/traversal.c | 114 +++-- h3/src/lib/type.c | 25 +- h3/src/lib/vertex.c | 115 +++++ h3/test/expected/clustering.out | 2 +- h3/test/expected/edge.out | 63 +++ h3/test/expected/hierarchy.out | 44 +- h3/test/expected/indexing.out | 46 +- h3/test/expected/inspection.out | 20 +- h3/test/expected/miscellaneous.out | 60 +-- h3/test/expected/opclass_btree.out | 2 +- h3/test/expected/opclass_hash.out | 4 +- h3/test/expected/postgis.out | 30 +- h3/test/expected/regions.out | 28 +- h3/test/expected/traversal.out | 47 +- h3/test/expected/type.out | 4 +- h3/test/expected/uniedges.out | 63 --- h3/test/expected/vertex.out | 40 ++ h3/test/sql/clustering.sql | 2 +- h3/test/sql/edge.sql | 58 +++ h3/test/sql/hierarchy.sql | 44 +- h3/test/sql/indexing.sql | 45 +- h3/test/sql/inspection.sql | 20 +- h3/test/sql/miscellaneous.sql | 60 +-- h3/test/sql/opclass_btree.sql | 2 +- h3/test/sql/opclass_hash.sql | 4 +- h3/test/sql/postgis.sql | 30 +- h3/test/sql/regions.sql | 29 +- h3/test/sql/traversal.sql | 47 +- h3/test/sql/type.sql | 4 +- h3/test/sql/uniedges.sql | 58 --- h3/test/sql/vertex.sql | 37 ++ h3_postgis.control | 4 + h3_postgis/sql/install/01-indexing.sql | 41 ++ h3_postgis/sql/install/05-regions.sql | 42 ++ .../sql/install/20-casts.sql | 12 +- h3_postgis/sql/updates/.keep | 0 82 files changed, 2277 insertions(+), 1461 deletions(-) create mode 100644 h3/sql/install/06-edge.sql delete mode 100644 h3/sql/install/06-uniedge.sql delete mode 100644 h3/sql/install/07-miscellaneous.sql create mode 100644 h3/sql/install/07-vertex.sql create mode 100644 h3/sql/install/08-miscellaneous.sql create mode 100644 h3/sql/install/20-casts.sql delete mode 100644 h3/sql/install/30-deprecated.sql rename h3/sql/install/{20-extension.sql => 30-extension.sql} (95%) delete mode 100644 h3/sql/install/99-postgis.sql create mode 100644 h3/sql/updates/h3--3.7.2--4.0.0.sql rename h3/src/lib/{uniedges.c => edge.c} (50%) create mode 100644 h3/src/lib/vertex.c create mode 100644 h3/test/expected/edge.out delete mode 100644 h3/test/expected/uniedges.out create mode 100644 h3/test/expected/vertex.out create mode 100644 h3/test/sql/edge.sql delete mode 100644 h3/test/sql/uniedges.sql create mode 100644 h3/test/sql/vertex.sql create mode 100644 h3_postgis.control create mode 100644 h3_postgis/sql/install/01-indexing.sql create mode 100644 h3_postgis/sql/install/05-regions.sql rename h3/sql/updates/h3--3.7.2--unreleased.sql => h3_postgis/sql/install/20-casts.sql (61%) create mode 100644 h3_postgis/sql/updates/.keep diff --git a/.github/docker/Dockerfile b/.github/docker/Dockerfile index 8c4b1690..0ec2a0aa 100644 --- a/.github/docker/Dockerfile +++ b/.github/docker/Dockerfile @@ -1,18 +1,22 @@ -ARG ARCH=amd64 -ARG UBUNTU=latest -FROM $ARCH/ubuntu:$UBUNTU +ARG UBUNTU=focal +FROM ubuntu:$UBUNTU -ARG ARCH ARG UBUNTU ENV DEBIAN_FRONTEND=noninteractive -ENV ARCH=$ARCH RUN apt-get update && apt-get install -y \ build-essential \ - cmake \ + # cmake \ # see following comments git \ pgxnclient +# H3 requires CMake 3.20, which has not landed in ubuntu +# as of writing. So we setup cmake apt repository +RUN if [ "$UBUNTU" != "impish" ] ; then apt-key adv --fetch-keys https://apt.kitware.com/keys/kitware-archive-latest.asc ; fi +RUN if [ "$UBUNTU" != "impish" ] ; then echo "deb https://apt.kitware.com/ubuntu/ ${UBUNTU} main" >> /etc/apt/sources.list.d/pgdg.list ; fi +RUN apt-get update && apt-get install -y cmake +# we can remove the block above when 3.20 lands + # Setup PostgreSQL apt repository RUN apt-key adv --fetch-keys https://www.postgresql.org/media/keys/ACCC4CF8.asc RUN echo "deb http://apt.postgresql.org/pub/repos/apt/ ${UBUNTU}-pgdg main" >> /etc/apt/sources.list.d/pgdg.list diff --git a/.github/docker/tools.sh b/.github/docker/tools.sh index 9789bc07..6422e10b 100755 --- a/.github/docker/tools.sh +++ b/.github/docker/tools.sh @@ -2,12 +2,12 @@ set -e BASEDIR=$(dirname $(realpath "$0")) -REPOSITORY="docker.pkg.github.com/bytesandbrains/h3-pg" +REPOSITORY="ghcr.io/bytesandbrains/h3-pg" # i386 being phased out from postgres apt :-( #ARCHS=(amd64 i386) ARCHS=(amd64) -UBUNTUS=(impish focal) # latest and LTS +UBUNTUS=(jammy focal) # latest and LTS POSTGRESQLS=(14 13) # two latest cd $BASEDIR @@ -49,6 +49,7 @@ case "${o}" in echo "$postgresql-$ubuntu-$arch" docker build \ --tag $REPOSITORY/test:$postgresql-$ubuntu-$arch \ + --platform linux/$arch \ --build-arg POSTGRESQL=$postgresql \ --build-arg UBUNTU=$ubuntu \ --build-arg ARCH=$arch \ @@ -81,6 +82,7 @@ case "${o}" in echo "$postgresql-$ubuntu-$arch" docker run \ --rm \ + --platform linux/$arch \ -v "$PWD"/../..:/github/workspace \ $REPOSITORY/test:$postgresql-$ubuntu-$arch done diff --git a/.github/documentation/generate.py b/.github/documentation/generate.py index 62ab25a2..e68eae36 100644 --- a/.github/documentation/generate.py +++ b/.github/documentation/generate.py @@ -136,6 +136,9 @@ def string(self, s): def fun_name(self, children): return children[1] + def datatype(self, children): + return children[0] + @v_args(inline=True) def argument(self, name, argtype, default=None): out = "" diff --git a/.github/documentation/sql.lark b/.github/documentation/sql.lark index 74bff98e..18445f16 100644 --- a/.github/documentation/sql.lark +++ b/.github/documentation/sql.lark @@ -29,7 +29,7 @@ create_type_stmt: "CREATE" "TYPE" CNAME ("(" /([^\)])+/ ")")? // ----------------------------------------------------------------------------- // CREATE CAST ... -create_cast_stmt: "CREATE" "CAST" "(" CNAME "AS" CNAME ")" "WITH" "FUNCTION" CNAME "(" /([^\)])+/ ")" +create_cast_stmt: "CREATE" "CAST" "(" datatype "AS" datatype ")" "WITH" "FUNCTION" CNAME "(" /([^\)])+/ ")" // ----------------------------------------------------------------------------- // CREATE OPERATOR CLASS name [ DEFAULT ] FOR TYPE data_type @@ -53,8 +53,8 @@ create_opcl_list: create_opcl_opts ("," create_opcl_opts)* // ) create_oper_stmt: "CREATE" "OPERATOR" OPERATOR "(" create_oper_opts ")" create_oper_opt: /PROCEDURE/ "=" CNAME - | /LEFTARG/ "=" CNAME - | /RIGHTARG/ "=" CNAME + | /LEFTARG/ "=" datatype + | /RIGHTARG/ "=" datatype | /COMMUTATOR/ "=" OPERATOR | /NEGATOR/ "=" OPERATOR | /RESTRICT/ "=" CNAME @@ -82,7 +82,7 @@ create_oper_opts: create_oper_opt ("," create_oper_opt)* // } ... // [ WITH ( attribute [, ...] ) ] create_func_stmt: "CREATE" ("OR" "REPLACE")? "FUNCTION" fun_name "(" [argument_list] ")" [create_fun_rets] create_fun_opts* -?create_fun_rets: "RETURNS" ("SETOF")? CNAME "[]"? +?create_fun_rets: "RETURNS" ("SETOF")? datatype "[]"? create_fun_opts: "LANGUAGE" CNAME | ("IMMUTABLE" | "STABLE" | "VOLATILE" | ("NOT"? "LEAKPROOF")) | (("CALLED" "ON" "NULL" "INPUT") | ("RETURNS" "NULL" "ON" "NULL" "INPUT") | "STRICT") @@ -102,13 +102,31 @@ argument_list: argument ("," argument)* // ... // } IS 'text' comment_on_stmt: "COMMENT" "ON" comment_on_type "IS" string -comment_on_type: "CAST" "(" CNAME "AS" CNAME ")" -> comment_on_cast +comment_on_type: "CAST" "(" datatype "AS" datatype ")" -> comment_on_cast | "FUNCTION" fun_name "(" [argument_list] ")" -> comment_on_function | "OPERATOR" OPERATOR "(" argument "," argument ")" -> comment_on_operator // ----------------------------------------------------------------------------- // SIMPLE RULES -argument: "OUT"? [CNAME] CNAME "[]"? ("DEFAULT" expr)? +argument: "OUT"? [CNAME] datatype "[]"? ("DEFAULT" expr)? +!datatype: "h3index" + | "bigint" + | "boolean" + | "cstring" + | "double" "precision" + | "float" + | "geography" + | "geometry" + | "int" + | "int32" + | "int8" + | "integer" + | "internal" + | "point" + | "polygon" + | "record" + | "text" + | "void" fun_name: [CNAME "."] CNAME ?expr: atom | string atom: SIGNED_NUMBER -> number diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ff7c7d22..21ee017a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -4,7 +4,7 @@ on: [push, pull_request] jobs: docs: - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 - uses: actions/setup-python@v2 @@ -14,21 +14,21 @@ jobs: - run: git diff --exit-code docs installcheck: - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 strategy: matrix: postgresql: [14, 13] - ubuntu: [impish, focal] + ubuntu: [jammy, focal] arch: [amd64] steps: - uses: actions/checkout@v2 - name: Login to repository - run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login docker.pkg.github.com -u "$GITHUB_ACTOR" --password-stdin + run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u "$GITHUB_ACTOR" --password-stdin - name: Test - run: docker run -v ${PWD}:/github/workspace docker.pkg.github.com/bytesandbrains/h3-pg/test:${{ matrix.postgresql }}-${{ matrix.ubuntu }}-${{ matrix.arch }} + run: docker run -v ${PWD}:/github/workspace ghcr.io/bytesandbrains/h3-pg/test:${{ matrix.postgresql }}-${{ matrix.ubuntu }}-${{ matrix.arch }} i386: - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 strategy: matrix: postgresql: [12] @@ -37,6 +37,6 @@ jobs: steps: - uses: actions/checkout@v2 - name: Login to repository - run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login docker.pkg.github.com -u "$GITHUB_ACTOR" --password-stdin + run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u "$GITHUB_ACTOR" --password-stdin - name: Test - run: docker run -v ${PWD}:/github/workspace docker.pkg.github.com/bytesandbrains/h3-pg/test:${{ matrix.postgresql }}-${{ matrix.ubuntu }}-${{ matrix.arch }} + run: docker run -v ${PWD}:/github/workspace ghcr.io/bytesandbrains/h3-pg/test:${{ matrix.postgresql }}-${{ matrix.ubuntu }}-${{ matrix.arch }} diff --git a/.gitignore b/.gitignore index 5d98dc16..f684e408 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,7 @@ h3/test/regression.* h3/test/results # Generated -/h3--*.sql +/h3*.sql /h3/src/include/extension.h /h3/test/expected/ci-*.out /h3/test/sql/ci-*.sql diff --git a/CHANGELOG.md b/CHANGELOG.md index d7219b04..a88c880c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,10 +26,16 @@ avoid adding features or APIs which do not map onto the Click to see more. -- Handle non-polygons for `h3_polyfill` (see [#55], thanks [@Lokks]) - +## [4.0.0] - 2022-08-24 + +- ⚠️ Update `h3` core library to `v4.0.0`. Almost all functions have been renamed to align with `h3` core `v4`. Please take care when updating. You can see a [list of changed function names](https://h3geo.org/docs/library/migration-3.x/functions) in the core library documentation. +- ⚠️ The PostGIS functions has been extracted into a separate extension `h3_postgis`. Install using `CREATE EXTENSION h3_postgis;`. +- Enable link time optimization (see [#75], thanks [@mngr777]) +- Handle non-polygons for `h3_polyfill` (see [#55], thanks [@Lokks]) +- Take advantage of the new v4 error codes (fixes [#71], thanks [@kalenikaliaksandr]) + ## [3.7.2] - 2022-04-13 - Allow `NULL` in `holes` array for `h3_polyfill` (see [#64], thanks [@mngr777]) @@ -153,7 +159,8 @@ avoid adding features or APIs which do not map onto the - Initial public release -[unreleased]: https://github.com/bytesandbrains/h3-pg/compare/v3.7.2...HEAD +[unreleased]: https://github.com/bytesandbrains/h3-pg/compare/v4.0.0...HEAD +[4.0.0]: https://github.com/bytesandbrains/h3-pg/compare/v3.7.2...v4.0.0 [3.7.2]: https://github.com/bytesandbrains/h3-pg/compare/v3.7.1...v3.7.2 [3.7.1]: https://github.com/bytesandbrains/h3-pg/compare/v3.7.0...v3.7.1 [3.7.0]: https://github.com/bytesandbrains/h3-pg/compare/v3.6.5...v3.7.0 @@ -191,9 +198,12 @@ avoid adding features or APIs which do not map onto the [#55]: https://github.com/bytesandbrains/h3-pg/issues/55 [#64]: https://github.com/bytesandbrains/h3-pg/issues/64 [#65]: https://github.com/bytesandbrains/h3-pg/pull/65 +[#71]: https://github.com/bytesandbrains/h3-pg/issues/71 +[#75]: https://github.com/bytesandbrains/h3-pg/pull/75 [@abelvm]: https://github.com/AbelVM -[@komzpa]: https://github.com/Komzpa +[@kalenikaliaksandr]: https://github.com/kalenikaliaksandr [@kmacdough]: https://github.com/kmacdough -[@trylinka]: https://github.com/trylinka -[@mngr777]: https://github.com/mngr777 +[@komzpa]: https://github.com/Komzpa [@lokks]: https://github.com/Lokks +[@mngr777]: https://github.com/mngr777 +[@trylinka]: https://github.com/trylinka diff --git a/META.json b/META.json index 6cf928b2..5e7e1f2f 100644 --- a/META.json +++ b/META.json @@ -2,15 +2,15 @@ "name": "h3", "abstract": "PostgreSQL bindings for H3", "description": "PostgreSQL bindings for H3, a hierarchical hexagonal geospatial indexing system.", - "version": "unreleased", + "version": "4.0.0", "maintainer": "Bytes & Brains ", "license": "apache_2_0", "provides": { "h3": { "abstract": "PostgreSQL bindings for H3", - "file": "sql/h3--unreleased.sql", + "file": "sql/h3--4.0.0.sql", "docfile": "README.md", - "version": "unreleased" + "version": "4.0.0" } }, "resources": { diff --git a/Makefile b/Makefile index fb4c7b81..d41f94e4 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -# Copyright 2018-2019 Bytes & Brains +# Copyright 2018-2022 Bytes & Brains # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,14 +12,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -EXTENSION = h3 +EXTENSION = h3 h3_postgis # extract extension version from .control file -EXTVERSION = $(shell grep default_version $(EXTENSION).control | \ +EXTVERSION = $(shell grep default_version h3.control | \ sed -e "s/default_version[[:space:]]*=[[:space:]]*'\([^']*\)'/\1/") # h3 core library version to clone and statically link -LIBH3_VERSION = v3.7.1 +LIBH3_VERSION = v4.0.0-rc5 # directory that h3 core repository is cloned into LIBH3_SOURCE = libh3-$(LIBH3_VERSION) # h3 static library location @@ -28,15 +28,19 @@ LIBH3_BUILD = $(LIBH3_SOURCE)/build SQL_INSTALLS = $(wildcard h3/sql/install/*.sql) SQL_UPDATES = $(wildcard h3/sql/updates/*.sql) SQL_TESTS = $(wildcard h3/test/sql/*.sql) -SQL_FULLINSTALL = $(EXTENSION)--$(EXTVERSION).sql +SQL_FULLINSTALL = h3--$(EXTVERSION).sql + +# postgis extension +SQL_INSTALLS_H3_POSTGIS = $(wildcard h3_postgis/sql/install/*.sql) +SQL_FULLINSTALL_H3_POSTGIS = h3_postgis--$(EXTVERSION).sql # a shared library to build from multiple source files -MODULE_big = $(EXTENSION) +MODULE_big = h3 # object files to be linked together OBJS = $(patsubst %.c,%.o,$(wildcard h3/src/lib/*.c)) # random files to install into $PREFIX/share/$MODULEDIR DATA = $(SQL_UPDATES) -DATA_built = $(SQL_FULLINSTALL) +DATA_built = $(SQL_FULLINSTALL) $(SQL_FULLINSTALL_H3_POSTGIS) # will be added to MODULE_big link line SHLIB_LINK += -lh3 -L$(LIBH3_BUILD)/lib # will be added to CPPFLAGS @@ -47,13 +51,12 @@ REGRESS = $(basename $(notdir $(SQL_TESTS))) REGRESS_OPTS = \ --inputdir=h3/test \ --outputdir=h3/test \ - --load-extension=postgis \ --load-extension=h3 # extra files to remove in make clean EXTRA_CLEAN += \ $(LIBH3_SOURCE) \ $(DATA_built) \ - src/include/extension.h \ + h3/src/include/extension.h \ $(wildcard h3/test/sql/ci-*.sql) \ $(wildcard h3/test/expected/ci-*.out) \ $(wildcard *.BAK) \ @@ -100,10 +103,16 @@ h3/src/include/extension.h: h3/src/include/extension.in.h # generate full installation sql (from uninstalled to latest) $(SQL_FULLINSTALL): $(sort $(SQL_INSTALLS)) cat $^ > $@ +$(SQL_FULLINSTALL_H3_POSTGIS): $(sort $(SQL_INSTALLS_H3_POSTGIS)) + cat $^ > $@ # package for distribution -dist: $(SQL_FULLINSTALL) - git archive --prefix=h3-$(EXTVERSION)/ --output h3-${EXTVERSION}.zip --add-file=$(SQL_FULLINSTALL) HEAD +dist: $(SQL_FULLINSTALL) $(SQL_FULLINSTALL_H3_POSTGIS) + git archive --prefix=h3-$(EXTVERSION)/ \ + --output h3-${EXTVERSION}.zip \ + --add-file=$(SQL_FULLINSTALL) \ + --add-file=$(SQL_FULLINSTALL_H3_POSTGIS) \ + HEAD ########################################################################### # Extra CI testing targets @@ -112,6 +121,8 @@ dist: $(SQL_FULLINSTALL) format: clean pgindent +# Run on dev using: +# PIPENV_PIPFILE=.github/documentation/Pipfile pipenv run make docs/api.md docs/api.md: $(SQL_INSTALLS) python .github/documentation/generate.py "h3/sql/install/*" > $@ npx doctoc $@ @@ -126,11 +137,11 @@ EXCLUDED_BINDING_FUNCTIONS = \ # functions provided that are not part of expected binding functions EXTRA_BINDING_FUNCTIONS = \ get_extension_version \ - to_children_slow \ - to_geo_boundary_geography \ - to_geo_boundary_geometry \ - to_geography \ - to_geometry + cell_to_children_slow \ + cell_to_geo_boundary_geography \ + cell_to_geo_boundary_geometry \ + cell_to_geography \ + cell_to_geometry /tmp/excluded-functions: echo "$(EXCLUDED_BINDING_FUNCTIONS)" | tr " " "\n" > $@ @@ -141,7 +152,7 @@ EXTRA_BINDING_FUNCTIONS = \ PRINT_TYPES_SQL = "SELECT typname, typlen, typbyval, typalign FROM pg_type WHERE typname LIKE '%h3index' ORDER BY typname;" PRINT_FUNCTIONS_SQL = "\df *h3*" PRINT_FUNCFLAGS_SQL = "SELECT proname, proisstrict, provolatile, proparallel, prosrc FROM pg_proc WHERE proname LIKE '%h3%' ORDER BY proname, prosrc;" -PRINT_OPERATORS_SQL = "\do" +PRINT_OPERATORS_SQL = "\do *h3*" # rules for testing the update path against full install h3/test/sql/ci-install.sql: $(SQL_FULLINSTALL) diff --git a/README.md b/README.md index f553d231..123152fd 100644 --- a/README.md +++ b/README.md @@ -6,21 +6,21 @@ Developed in collaboration with [Scandinavian Highlands](http://www.scandinavian ## Prerequisites -* PostgreSQL 9.6 or higher (*including server headers*). It might work with earlier versions, we have not tested earlier than 9.6. -* C compiler (e.g., gcc) -* GNU Make -* Git & CMake (for libh3) +- PostgreSQL 9.6 or higher (_including server headers_). It might work with earlier versions, we have not tested earlier than 9.6. +- C compiler (e.g., gcc) +- GNU Make +- Git & CMake (for libh3) ## Quick Overview If the prerequisites are met you can use the PGXN Client to download, build, and install, e.g.: -``` +```shell $ pgxn install h3 $ pgxn load h3 $ psql =# SELECT h3_geo_to_h3(POINT('37.3615593,-122.0553238'), 5); - h3_geo_to_h3 + h3_geo_to_h3 ----------------- 85e35e73fffffff (1 row) @@ -28,16 +28,20 @@ $ psql #### On macOS with the Postgres.app Universal Binary -``` +```shell brew install pgxnclient make cmake export CMAKE_OSX_ARCHITECTURES="arm64;x86_64" pgxn install h3 ``` - ## Usage -Generally, all functions have been renamed from camelCase in H3 to snake_case in SQL with an added `h3_` prefix (except when that would result in a double `h3_` prefix). For example `geoToH3` becomes `h3_geo_to_h3` and `h3ToChildren` becomes `h3_to_children`. +> :tada: **Note:** The following usage docs apply to **H3 v4**, which was released on August 23, 2022. +> +> - For v3 docs, [see the latest v3.x.x release](https://github.com/bytesandbrains/h3-pg/blob/v3.7.2/README.md). +> - For breaking changes in v4, [see the CHANGELOG](./CHANGELOG.md). In particular, most [function names have changed](https://h3geo.org/docs/library/migration-3.x/functions). + +Generally, all functions have been renamed from camelCase in H3 to snake*case in SQL with an added `h3*` prefix. See [API reference](docs/api.md) for all provided functions. diff --git a/docs/api.md b/docs/api.md index ebb07bb5..0036e020 100644 --- a/docs/api.md +++ b/docs/api.md @@ -4,55 +4,63 @@ - [API Reference](#api-reference) - [Base type](#base-type) - - [`h3index` :: `bigint`](#h3index--bigint) - - [`bigint` :: `h3index`](#bigint--h3index) - [Indexing functions](#indexing-functions) - - [h3_geo_to_h3(`point`, resolution `integer`) ⇒ `h3index`](#h3_geo_to_h3point-resolution-integer-%E2%87%92-h3index) - - [h3_to_geo(`h3index`) ⇒ `point`](#h3_to_geoh3index-%E2%87%92-point) - - [h3_to_geo_boundary(`h3index`, [extend_at_meridian `BOOLEAN` = `false`]) ⇒ `polygon`](#h3_to_geo_boundaryh3index-extend_at_meridian-boolean--false-%E2%87%92-polygon) + - [h3_lat_lng_to_cell(latlng `point`, resolution `integer`) ⇒ `h3index`](#h3_lat_lng_to_celllatlng-point-resolution-integer-%E2%87%92-h3index) + - [h3_cell_to_lat_lng(cell `h3index`) ⇒ `point`](#h3_cell_to_lat_lngcell-h3index-%E2%87%92-point) + - [h3_cell_to_boundary(cell `h3index`, [extend_at_meridian `boolean` = `false`]) ⇒ `polygon`](#h3_cell_to_boundarycell-h3index-extend_at_meridian-boolean--false-%E2%87%92-polygon) - [Index inspection functions](#index-inspection-functions) - [h3_get_resolution(`h3index`) ⇒ `integer`](#h3_get_resolutionh3index-%E2%87%92-integer) - - [h3_get_base_cell(`h3index`) ⇒ `integer`](#h3_get_base_cellh3index-%E2%87%92-integer) - - [h3_is_valid(`h3index`) ⇒ `bool`](#h3_is_validh3index-%E2%87%92-bool) - - [h3_is_res_class_iii(`h3index`) ⇒ `bool`](#h3_is_res_class_iiih3index-%E2%87%92-bool) - - [h3_is_pentagon(`h3index`) ⇒ `bool`](#h3_is_pentagonh3index-%E2%87%92-bool) - - [h3_get_faces(`h3index`) ⇒ `integer`](#h3_get_facesh3index-%E2%87%92-integer) + - [h3_get_base_cell_number(`h3index`) ⇒ `integer`](#h3_get_base_cell_numberh3index-%E2%87%92-integer) + - [h3_is_valid_cell(`h3index`) ⇒ `boolean`](#h3_is_valid_cellh3index-%E2%87%92-boolean) + - [h3_is_res_class_iii(`h3index`) ⇒ `boolean`](#h3_is_res_class_iiih3index-%E2%87%92-boolean) + - [h3_is_pentagon(`h3index`) ⇒ `boolean`](#h3_is_pentagonh3index-%E2%87%92-boolean) + - [h3_get_icosahedron_faces(`h3index`) ⇒ `integer`](#h3_get_icosahedron_facesh3index-%E2%87%92-integer) - [Grid traversal functions](#grid-traversal-functions) - - [h3_k_ring(`h3index`, [k `integer` = 1]) ⇒ `h3index`](#h3_k_ringh3index-k-integer--1-%E2%87%92-h3index) - - [h3_k_ring_distances(`h3index`, [k `integer` = 1], index `h3index`, distance `int`) ⇒ `record`](#h3_k_ring_distancesh3index-k-integer--1-index-h3index-distance-int-%E2%87%92-record) - - [h3_hex_ring(`h3index`, [k `integer` = 1]) ⇒ `h3index`](#h3_hex_ringh3index-k-integer--1-%E2%87%92-h3index) - - [h3_line(`h3index`, `h3index`) ⇒ `h3index`](#h3_lineh3index-h3index-%E2%87%92-h3index) - - [h3_distance(`h3index`, `h3index`) ⇒ `integer`](#h3_distanceh3index-h3index-%E2%87%92-integer) - - [h3_experimental_h3_to_local_ij(origin `h3index`, index `h3index`) ⇒ `POINT`](#h3_experimental_h3_to_local_ijorigin-h3index-index-h3index-%E2%87%92-point) - - [h3_experimental_local_ij_to_h3(origin `h3index`, coord `POINT`) ⇒ `h3index`](#h3_experimental_local_ij_to_h3origin-h3index-coord-point-%E2%87%92-h3index) + - [h3_grid_disk(origin `h3index`, [k `integer` = 1]) ⇒ `h3index`](#h3_grid_diskorigin-h3index-k-integer--1-%E2%87%92-h3index) + - [h3_grid_disk_distances(origin `h3index`, [k `integer` = 1], index `h3index`, distance `int`) ⇒ `record`](#h3_grid_disk_distancesorigin-h3index-k-integer--1-index-h3index-distance-int-%E2%87%92-record) + - [h3_grid_ring_unsafe(origin `h3index`, [k `integer` = 1]) ⇒ `h3index`](#h3_grid_ring_unsafeorigin-h3index-k-integer--1-%E2%87%92-h3index) + - [h3_grid_path_cells(origin `h3index`, destination `h3index`) ⇒ `h3index`](#h3_grid_path_cellsorigin-h3index-destination-h3index-%E2%87%92-h3index) + - [h3_grid_distance(origin `h3index`, destination `h3index`) ⇒ `bigint`](#h3_grid_distanceorigin-h3index-destination-h3index-%E2%87%92-bigint) + - [h3_cell_to_local_ij(origin `h3index`, index `h3index`) ⇒ `point`](#h3_cell_to_local_ijorigin-h3index-index-h3index-%E2%87%92-point) + - [h3_local_ij_to_cell(origin `h3index`, coord `point`) ⇒ `h3index`](#h3_local_ij_to_cellorigin-h3index-coord-point-%E2%87%92-h3index) - [Hierarchical grid functions](#hierarchical-grid-functions) - - [h3_to_parent(`h3index`, [resolution `integer` = -1]) ⇒ `h3index`](#h3_to_parenth3index-resolution-integer---1-%E2%87%92-h3index) - - [h3_to_children(`h3index`, [resolution `integer` = -1]) ⇒ `h3index`](#h3_to_childrenh3index-resolution-integer---1-%E2%87%92-h3index) - - [h3_to_center_child(`h3index`, [resolution `integer` = -1]) ⇒ `h3index`](#h3_to_center_childh3index-resolution-integer---1-%E2%87%92-h3index) - - [h3_compact(`h3index`) ⇒ `h3index`](#h3_compacth3index-%E2%87%92-h3index) - - [h3_uncompact(`h3index`, [resolution `integer` = -1]) ⇒ `h3index`](#h3_uncompacth3index-resolution-integer---1-%E2%87%92-h3index) - - [h3_to_children_slow(index `h3index`, [resolution `integer` = -1]) ⇒ `h3index`](#h3_to_children_slowindex-h3index-resolution-integer---1-%E2%87%92-h3index) + - [h3_cell_to_parent(cell `h3index`, resolution `integer`) ⇒ `h3index`](#h3_cell_to_parentcell-h3index-resolution-integer-%E2%87%92-h3index) + - [h3_cell_to_children(cell `h3index`, resolution `integer`) ⇒ `h3index`](#h3_cell_to_childrencell-h3index-resolution-integer-%E2%87%92-h3index) + - [h3_cell_to_center_child(cell `h3index`, resolution `integer`) ⇒ `h3index`](#h3_cell_to_center_childcell-h3index-resolution-integer-%E2%87%92-h3index) + - [h3_compact_cells(cells `h3index`) ⇒ `h3index`](#h3_compact_cellscells-h3index-%E2%87%92-h3index) + - [h3_uncompact_cells(cells `h3index`, resolution `integer`) ⇒ `h3index`](#h3_uncompact_cellscells-h3index-resolution-integer-%E2%87%92-h3index) + - [h3_cell_to_parent(cell `h3index`) ⇒ `h3index`](#h3_cell_to_parentcell-h3index-%E2%87%92-h3index) + - [h3_cell_to_children(cell `h3index`) ⇒ `h3index`](#h3_cell_to_childrencell-h3index-%E2%87%92-h3index) + - [h3_cell_to_center_child(cell `h3index`) ⇒ `h3index`](#h3_cell_to_center_childcell-h3index-%E2%87%92-h3index) + - [h3_uncompact_cells(cells `h3index`) ⇒ `h3index`](#h3_uncompact_cellscells-h3index-%E2%87%92-h3index) + - [h3_cell_to_children_slow(index `h3index`, resolution `integer`) ⇒ `h3index`](#h3_cell_to_children_slowindex-h3index-resolution-integer-%E2%87%92-h3index) + - [h3_cell_to_children_slow(index `h3index`) ⇒ `h3index`](#h3_cell_to_children_slowindex-h3index-%E2%87%92-h3index) - [Region functions](#region-functions) - - [h3_polyfill(exterior `polygon`, holes `polygon`, [resolution `integer` = 1]) ⇒ `h3index`](#h3_polyfillexterior-polygon-holes-polygon-resolution-integer--1-%E2%87%92-h3index) - - [h3_set_to_multi_polygon(`h3index`, exterior `polygon`, holes `polygon`) ⇒ `record`](#h3_set_to_multi_polygonh3index-exterior-polygon-holes-polygon-%E2%87%92-record) + - [h3_polygon_to_cells(exterior `polygon`, holes `polygon`, [resolution `integer` = 1]) ⇒ `h3index`](#h3_polygon_to_cellsexterior-polygon-holes-polygon-resolution-integer--1-%E2%87%92-h3index) + - [h3_cells_to_multi_polygon(`h3index`, exterior `polygon`, holes `polygon`) ⇒ `record`](#h3_cells_to_multi_polygonh3index-exterior-polygon-holes-polygon-%E2%87%92-record) - [Unidirectional edge functions](#unidirectional-edge-functions) - - [h3_indexes_are_neighbors(`h3index`, `h3index`) ⇒ `boolean`](#h3_indexes_are_neighborsh3index-h3index-%E2%87%92-boolean) - - [h3_get_h3_unidirectional_edge(origin `h3index`, destination `h3index`) ⇒ `h3index`](#h3_get_h3_unidirectional_edgeorigin-h3index-destination-h3index-%E2%87%92-h3index) - - [h3_unidirectional_edge_is_valid(edge `h3index`) ⇒ `boolean`](#h3_unidirectional_edge_is_validedge-h3index-%E2%87%92-boolean) - - [h3_get_origin_h3_index_from_unidirectional_edge(edge `h3index`) ⇒ `h3index`](#h3_get_origin_h3_index_from_unidirectional_edgeedge-h3index-%E2%87%92-h3index) - - [h3_get_destination_h3_index_from_unidirectional_edge(edge `h3index`) ⇒ `h3index`](#h3_get_destination_h3_index_from_unidirectional_edgeedge-h3index-%E2%87%92-h3index) - - [h3_get_h3_indexes_from_unidirectional_edge(edge `h3index`, origin `h3index`, destination `h3index`) ⇒ `record`](#h3_get_h3_indexes_from_unidirectional_edgeedge-h3index-origin-h3index-destination-h3index-%E2%87%92-record) - - [h3_get_h3_unidirectional_edges_from_hexagon(`h3index`) ⇒ `h3index`](#h3_get_h3_unidirectional_edges_from_hexagonh3index-%E2%87%92-h3index) - - [h3_get_h3_unidirectional_edge_boundary(edge `h3index`) ⇒ `polygon`](#h3_get_h3_unidirectional_edge_boundaryedge-h3index-%E2%87%92-polygon) + - [h3_are_neighbor_cells(origin `h3index`, destination `h3index`) ⇒ `boolean`](#h3_are_neighbor_cellsorigin-h3index-destination-h3index-%E2%87%92-boolean) + - [h3_cells_to_directed_edge(origin `h3index`, destination `h3index`) ⇒ `h3index`](#h3_cells_to_directed_edgeorigin-h3index-destination-h3index-%E2%87%92-h3index) + - [h3_is_valid_directed_edge(edge `h3index`) ⇒ `boolean`](#h3_is_valid_directed_edgeedge-h3index-%E2%87%92-boolean) + - [h3_get_directed_edge_origin(edge `h3index`) ⇒ `h3index`](#h3_get_directed_edge_originedge-h3index-%E2%87%92-h3index) + - [h3_get_directed_edge_destination(edge `h3index`) ⇒ `h3index`](#h3_get_directed_edge_destinationedge-h3index-%E2%87%92-h3index) + - [h3_directed_edge_to_cells(edge `h3index`, origin `h3index`, destination `h3index`) ⇒ `record`](#h3_directed_edge_to_cellsedge-h3index-origin-h3index-destination-h3index-%E2%87%92-record) + - [h3_origin_to_directed_edges(`h3index`) ⇒ `h3index`](#h3_origin_to_directed_edgesh3index-%E2%87%92-h3index) + - [h3_directed_edge_to_boundary(edge `h3index`) ⇒ `polygon`](#h3_directed_edge_to_boundaryedge-h3index-%E2%87%92-polygon) +- [H3 Vertex functions](#h3-vertex-functions) + - [h3_cell_to_vertex(cell `h3index`, vertexNum `integer`) ⇒ `h3index`](#h3_cell_to_vertexcell-h3index-vertexnum-integer-%E2%87%92-h3index) + - [h3_cell_to_vertexes(cell `h3index`) ⇒ `h3index`](#h3_cell_to_vertexescell-h3index-%E2%87%92-h3index) + - [h3_vertex_to_lat_lng(vertex `h3index`) ⇒ `point`](#h3_vertex_to_lat_lngvertex-h3index-%E2%87%92-point) + - [h3_is_valid_vertex(vertex `h3index`) ⇒ `boolean`](#h3_is_valid_vertexvertex-h3index-%E2%87%92-boolean) - [Miscellaneous H3 functions](#miscellaneous-h3-functions) - - [h3_point_dist(a `point`, b `point`, [unit `text` = km]) ⇒ `float`](#h3_point_dista-point-b-point-unit-text--km-%E2%87%92-float) - - [h3_hex_area(resolution `integer`, [unit `text` = km]) ⇒ `float`](#h3_hex_arearesolution-integer-unit-text--km-%E2%87%92-float) - - [h3_cell_area(cell `h3index`, [unit `text` = km^2]) ⇒ `float`](#h3_cell_areacell-h3index-unit-text--km%5E2-%E2%87%92-float) - - [h3_edge_length(resolution `integer`, [unit `text` = km]) ⇒ `float`](#h3_edge_lengthresolution-integer-unit-text--km-%E2%87%92-float) - - [h3_exact_edge_length(edge `h3index`, [unit `text` = km]) ⇒ `float`](#h3_exact_edge_lengthedge-h3index-unit-text--km-%E2%87%92-float) - - [h3_num_hexagons(resolution `integer`) ⇒ `bigint`](#h3_num_hexagonsresolution-integer-%E2%87%92-bigint) - - [h3_get_res_0_indexes() ⇒ `h3index`](#h3_get_res_0_indexes-%E2%87%92-h3index) - - [h3_get_pentagon_indexes(resolution `integer`) ⇒ `h3index`](#h3_get_pentagon_indexesresolution-integer-%E2%87%92-h3index) + - [h3_great_circle_distance(a `point`, b `point`, [unit `text` = km]) ⇒ `double`](#h3_great_circle_distancea-point-b-point-unit-text--km-%E2%87%92-double) + - [h3_get_hexagon_area_avg(resolution `integer`, [unit `text` = km]) ⇒ `double`](#h3_get_hexagon_area_avgresolution-integer-unit-text--km-%E2%87%92-double) + - [h3_cell_area(cell `h3index`, [unit `text` = km^2]) ⇒ `double`](#h3_cell_areacell-h3index-unit-text--km%5E2-%E2%87%92-double) + - [h3_get_hexagon_edge_length_avg(resolution `integer`, [unit `text` = km]) ⇒ `double`](#h3_get_hexagon_edge_length_avgresolution-integer-unit-text--km-%E2%87%92-double) + - [h3_edge_length(edge `h3index`, [unit `text` = km]) ⇒ `double`](#h3_edge_lengthedge-h3index-unit-text--km-%E2%87%92-double) + - [h3_get_num_cells(resolution `integer`) ⇒ `bigint`](#h3_get_num_cellsresolution-integer-%E2%87%92-bigint) + - [h3_get_res_0_cells() ⇒ `h3index`](#h3_get_res_0_cells-%E2%87%92-h3index) + - [h3_get_pentagons(resolution `integer`) ⇒ `h3index`](#h3_get_pentagonsresolution-integer-%E2%87%92-h3index) - [Operators](#operators) - [B-tree operators](#b-tree-operators) - [Operator: `h3index` = `h3index`](#operator-h3index--h3index) @@ -62,21 +70,12 @@ - [Operator: `h3index` @> `h3index`](#operator-h3index--h3index) - [Operator: `h3index` <@ `h3index`](#operator-h3index--h3index) - [Operator: `h3index` <-> `h3index`](#operator-h3index---h3index) +- [Type casts](#type-casts) + - [`h3index` :: `bigint`](#h3index--bigint) + - [`bigint` :: `h3index`](#bigint--h3index) + - [`h3index` :: `point`](#h3index--point) - [Extension specific functions](#extension-specific-functions) - [h3_get_extension_version() ⇒ `text`](#h3_get_extension_version-%E2%87%92-text) -- [PostGIS Functions](#postgis-functions) - - [h3_geo_to_h3(`geometry`, resolution `integer`) ⇒ `h3index`](#h3_geo_to_h3geometry-resolution-integer-%E2%87%92-h3index) - - [h3_geo_to_h3(`geography`, resolution `integer`) ⇒ `h3index`](#h3_geo_to_h3geography-resolution-integer-%E2%87%92-h3index) - - [h3_to_geometry(`h3index`) ⇒ `geometry`](#h3_to_geometryh3index-%E2%87%92-geometry) - - [h3_to_geography(`h3index`) ⇒ `geography`](#h3_to_geographyh3index-%E2%87%92-geography) - - [h3_to_geo_boundary_geometry(`h3index`, [extend `BOOLEAN` = `false`]) ⇒ `geometry`](#h3_to_geo_boundary_geometryh3index-extend-boolean--false-%E2%87%92-geometry) - - [h3_to_geo_boundary_geography(`h3index`, [extend `BOOLEAN` = `false`]) ⇒ `geography`](#h3_to_geo_boundary_geographyh3index-extend-boolean--false-%E2%87%92-geography) - - [h3_polyfill(multi `geometry`, resolution `integer`) ⇒ `h3index`](#h3_polyfillmulti-geometry-resolution-integer-%E2%87%92-h3index) - - [h3_polyfill(multi `geography`, resolution `integer`) ⇒ `h3index`](#h3_polyfillmulti-geography-resolution-integer-%E2%87%92-h3index) - - [PostGIS casts](#postgis-casts) - - [`h3index` :: `point`](#h3index--point) - - [`h3index` :: `geometry`](#h3index--geometry) - - [`h3index` :: `geography`](#h3index--geography) @@ -84,6 +83,8 @@ # Base type +An unsigned 64-bit integer representing any H3 object (hexagon, pentagon, directed edge ...) +represented as a (or 16-character) hexadecimal string, like '8928308280fffff'. @@ -91,42 +92,29 @@ - -### `h3index` :: `bigint` - - -Convert H3 index to bigint, which is useful when you need a decimal representation - - - -### `bigint` :: `h3index` - - -Convert bigint to H3 index - # Indexing functions These function are used for finding the H3 index containing coordinates, and for finding the center and boundary of H3 indexes. -### h3_geo_to_h3(`point`, resolution `integer`) ⇒ `h3index` -*Since v0.2.0* +### h3_lat_lng_to_cell(latlng `point`, resolution `integer`) ⇒ `h3index` +*Since v4.0.0* Indexes the location at the specified resolution -### h3_to_geo(`h3index`) ⇒ `point` -*Since v1.0.0* +### h3_cell_to_lat_lng(cell `h3index`) ⇒ `point` +*Since v4.0.0* Finds the centroid of the index -### h3_to_geo_boundary(`h3index`, [extend_at_meridian `BOOLEAN` = `false`]) ⇒ `polygon` -*Since v1.0.0* +### h3_cell_to_boundary(cell `h3index`, [extend_at_meridian `boolean` = `false`]) ⇒ `polygon` +*Since v4.0.0* Finds the boundary of the index, second argument extends coordinates when crossing 180th meridian to help visualization @@ -145,15 +133,15 @@ Returns the resolution of the index -### h3_get_base_cell(`h3index`) ⇒ `integer` -*Since v1.0.0* +### h3_get_base_cell_number(`h3index`) ⇒ `integer` +*Since v4.0.0* Returns the base cell number of the index -### h3_is_valid(`h3index`) ⇒ `bool` +### h3_is_valid_cell(`h3index`) ⇒ `boolean` *Since v1.0.0* @@ -161,7 +149,7 @@ Returns true if the given H3Index is valid -### h3_is_res_class_iii(`h3index`) ⇒ `bool` +### h3_is_res_class_iii(`h3index`) ⇒ `boolean` *Since v1.0.0* @@ -169,7 +157,7 @@ Returns true if this index has a resolution with Class III orientation -### h3_is_pentagon(`h3index`) ⇒ `bool` +### h3_is_pentagon(`h3index`) ⇒ `boolean` *Since v1.0.0* @@ -177,8 +165,8 @@ Returns true if this index represents a pentagonal cell -### h3_get_faces(`h3index`) ⇒ `integer` -*Since v3.5.0* +### h3_get_icosahedron_faces(`h3index`) ⇒ `integer` +*Since v4.0.0* Find all icosahedron faces intersected by a given H3 index @@ -188,32 +176,32 @@ Find all icosahedron faces intersected by a given H3 index Grid traversal allows finding cells in the vicinity of an origin cell, and determining how to traverse the grid from one cell to another. -### h3_k_ring(`h3index`, [k `integer` = 1]) ⇒ `h3index` -*Since v0.2.0* +### h3_grid_disk(origin `h3index`, [k `integer` = 1]) ⇒ `h3index` +*Since v4.0.0* Produces indices within "k" distance of the origin index -### h3_k_ring_distances(`h3index`, [k `integer` = 1], index `h3index`, distance `int`) ⇒ `record` -*Since v0.2.0* +### h3_grid_disk_distances(origin `h3index`, [k `integer` = 1], index `h3index`, distance `int`) ⇒ `record` +*Since v4.0.0* Produces indices within "k" distance of the origin index paired with their distance to the origin -### h3_hex_ring(`h3index`, [k `integer` = 1]) ⇒ `h3index` -*Since v0.2.0* +### h3_grid_ring_unsafe(origin `h3index`, [k `integer` = 1]) ⇒ `h3index` +*Since v4.0.0* Returns the hollow hexagonal ring centered at origin with distance "k" -### h3_line(`h3index`, `h3index`) ⇒ `h3index` -*Since v0.4.0* +### h3_grid_path_cells(origin `h3index`, destination `h3index`) ⇒ `h3index` +*Since v4.0.0* Given two H3 indexes, return the line of indexes between them (inclusive). @@ -224,78 +212,115 @@ distances for indexes on opposite sides of a pentagon. -### h3_distance(`h3index`, `h3index`) ⇒ `integer` -*Since v0.2.0* +### h3_grid_distance(origin `h3index`, destination `h3index`) ⇒ `bigint` +*Since v4.0.0* Returns the distance in grid cells between the two indices -### h3_experimental_h3_to_local_ij(origin `h3index`, index `h3index`) ⇒ `POINT` +### h3_cell_to_local_ij(origin `h3index`, index `h3index`) ⇒ `point` *Since v0.2.0* Produces local IJ coordinates for an H3 index anchored by an origin. -This function is experimental, and its output is not guaranteed to be compatible across different versions of H3. -### h3_experimental_local_ij_to_h3(origin `h3index`, coord `POINT`) ⇒ `h3index` +### h3_local_ij_to_cell(origin `h3index`, coord `point`) ⇒ `h3index` *Since v0.2.0* Produces an H3 index from local IJ coordinates anchored by an origin. -This function is experimental, and its output is not guaranteed to be compatible across different versions of H3. # Hierarchical grid functions These functions permit moving between resolutions in the H3 grid system. The functions produce parent (coarser) or children (finer) cells. -### h3_to_parent(`h3index`, [resolution `integer` = -1]) ⇒ `h3index` -*Since v1.0.0* +### h3_cell_to_parent(cell `h3index`, resolution `integer`) ⇒ `h3index` +*Since v4.0.0* Returns the parent of the given index -### h3_to_children(`h3index`, [resolution `integer` = -1]) ⇒ `h3index` -*Since v1.0.0* +### h3_cell_to_children(cell `h3index`, resolution `integer`) ⇒ `h3index` +*Since v4.0.0* Returns the set of children of the given index -### h3_to_center_child(`h3index`, [resolution `integer` = -1]) ⇒ `h3index` -*Since v3.6.0* +### h3_cell_to_center_child(cell `h3index`, resolution `integer`) ⇒ `h3index` +*Since v4.0.0* Returns the center child (finer) index contained by input index at given resolution -### h3_compact(`h3index`) ⇒ `h3index` -*Since v0.2.0* +### h3_compact_cells(cells `h3index`) ⇒ `h3index` +*Since v4.0.0* Compacts the given array as best as possible -### h3_uncompact(`h3index`, [resolution `integer` = -1]) ⇒ `h3index` -*Since v0.2.0* +### h3_uncompact_cells(cells `h3index`, resolution `integer`) ⇒ `h3index` +*Since v4.0.0* -Uncompacts the given array at the given resolution. If no resolution is given, then it is chosen as one higher than the highest resolution in the set +Uncompacts the given array at the given resolution. +### h3_cell_to_parent(cell `h3index`) ⇒ `h3index` +*Since v4.0.0* -### h3_to_children_slow(index `h3index`, [resolution `integer` = -1]) ⇒ `h3index` -*Since v1.0.0* + +Returns the parent of the given index + + + +### h3_cell_to_children(cell `h3index`) ⇒ `h3index` +*Since v4.0.0* + + +Returns the set of children of the given index + + + +### h3_cell_to_center_child(cell `h3index`) ⇒ `h3index` +*Since v4.0.0* + + +Returns the center child (finer) index contained by input index at next resolution + + + +### h3_uncompact_cells(cells `h3index`) ⇒ `h3index` +*Since v4.0.0* + + +Uncompacts the given array at the resolution one higher than the highest resolution in the set + + + + +### h3_cell_to_children_slow(index `h3index`, resolution `integer`) ⇒ `h3index` +*Since v4.0.0* + + +Slower version of H3ToChildren but allocates less memory + + + +### h3_cell_to_children_slow(index `h3index`) ⇒ `h3index` Slower version of H3ToChildren but allocates less memory @@ -304,16 +329,16 @@ Slower version of H3ToChildren but allocates less memory These functions convert H3 indexes to and from polygonal areas. -### h3_polyfill(exterior `polygon`, holes `polygon`, [resolution `integer` = 1]) ⇒ `h3index` -*Since v0.2.0* +### h3_polygon_to_cells(exterior `polygon`, holes `polygon`, [resolution `integer` = 1]) ⇒ `h3index` +*Since v4.0.0* Takes an exterior polygon [and a set of hole polygon] and returns the set of hexagons that best fit the structure -### h3_set_to_multi_polygon(`h3index`, exterior `polygon`, holes `polygon`) ⇒ `record` -*Since v3.5.0* +### h3_cells_to_multi_polygon(`h3index`, exterior `polygon`, holes `polygon`) ⇒ `record` +*Since v4.0.0* Create a LinkedGeoPolygon describing the outline(s) of a set of hexagons. Polygon outlines will follow GeoJSON MultiPolygon order: Each polygon will have one outer loop, which is first in the list, followed by any holes @@ -323,133 +348,167 @@ Create a LinkedGeoPolygon describing the outline(s) of a set of hexagons. Polygo Unidirectional edges allow encoding the directed edge from one cell to a neighboring cell. -### h3_indexes_are_neighbors(`h3index`, `h3index`) ⇒ `boolean` -*Since v1.0.0* +### h3_are_neighbor_cells(origin `h3index`, destination `h3index`) ⇒ `boolean` +*Since v4.0.0* Returns true if the given indices are neighbors -### h3_get_h3_unidirectional_edge(origin `h3index`, destination `h3index`) ⇒ `h3index` -*Since v0.2.0* +### h3_cells_to_directed_edge(origin `h3index`, destination `h3index`) ⇒ `h3index` +*Since v4.0.0* Returns a unidirectional edge H3 index based on the provided origin and destination. -### h3_unidirectional_edge_is_valid(edge `h3index`) ⇒ `boolean` -*Since v1.0.0* +### h3_is_valid_directed_edge(edge `h3index`) ⇒ `boolean` +*Since v4.0.0* Returns true if the given edge is valid. -### h3_get_origin_h3_index_from_unidirectional_edge(edge `h3index`) ⇒ `h3index` -*Since v0.2.0* +### h3_get_directed_edge_origin(edge `h3index`) ⇒ `h3index` +*Since v4.0.0* Returns the origin index from the given edge. -### h3_get_destination_h3_index_from_unidirectional_edge(edge `h3index`) ⇒ `h3index` -*Since v0.2.0* +### h3_get_directed_edge_destination(edge `h3index`) ⇒ `h3index` +*Since v4.0.0* Returns the destination index from the given edge. -### h3_get_h3_indexes_from_unidirectional_edge(edge `h3index`, origin `h3index`, destination `h3index`) ⇒ `record` -*Since v0.2.0* +### h3_directed_edge_to_cells(edge `h3index`, origin `h3index`, destination `h3index`) ⇒ `record` +*Since v4.0.0* Returns the pair of indices from the given edge. -### h3_get_h3_unidirectional_edges_from_hexagon(`h3index`) ⇒ `h3index` -*Since v0.2.0* +### h3_origin_to_directed_edges(`h3index`) ⇒ `h3index` +*Since v4.0.0* Returns all unidirectional edges with the given index as origin -### h3_get_h3_unidirectional_edge_boundary(edge `h3index`) ⇒ `polygon` -*Since v0.2.0* +### h3_directed_edge_to_boundary(edge `h3index`) ⇒ `polygon` +*Since v4.0.0* Provides the coordinates defining the unidirectional edge. +# H3 Vertex functions + +Functions for working with cell vertexes. + +### h3_cell_to_vertex(cell `h3index`, vertexNum `integer`) ⇒ `h3index` +*Since v4.0.0* + + +Returns a single vertex for a given cell, as an H3 index + + + +### h3_cell_to_vertexes(cell `h3index`) ⇒ `h3index` +*Since v4.0.0* + + +Returns all vertexes for a given cell, as H3 indexes + + + +### h3_vertex_to_lat_lng(vertex `h3index`) ⇒ `point` +*Since v4.0.0* + + +Get the geocoordinates of an H3 vertex + + + +### h3_is_valid_vertex(vertex `h3index`) ⇒ `boolean` +*Since v4.0.0* + + +Whether the input is a valid H3 vertex + # Miscellaneous H3 functions These functions include descriptions of the H3 grid system. -### h3_point_dist(a `point`, b `point`, [unit `text` = km]) ⇒ `float` -*Since v3.7.0* +### h3_great_circle_distance(a `point`, b `point`, [unit `text` = km]) ⇒ `double` +*Since v4.0.0* -The great circle distance in radians between two spherical coordinates. +The great circle distance in radians between two spherical coordinates -### h3_hex_area(resolution `integer`, [unit `text` = km]) ⇒ `float` -*Since v3.5.0* +### h3_get_hexagon_area_avg(resolution `integer`, [unit `text` = km]) ⇒ `double` +*Since v4.0.0* -Average hexagon area in square (kilo)meters at the given resolution. +Average hexagon area in square (kilo)meters at the given resolution -### h3_cell_area(cell `h3index`, [unit `text` = km^2]) ⇒ `float` -*Since v3.7.0* +### h3_cell_area(cell `h3index`, [unit `text` = km^2]) ⇒ `double` +*Since v4.0.0* -Exact area for a specific cell (hexagon or pentagon). +Exact area for a specific cell (hexagon or pentagon) -### h3_edge_length(resolution `integer`, [unit `text` = km]) ⇒ `float` -*Since v3.5.0* +### h3_get_hexagon_edge_length_avg(resolution `integer`, [unit `text` = km]) ⇒ `double` +*Since v4.0.0* -Average hexagon edge length in (kilo)meters at the given resolution. +Average hexagon edge length in (kilo)meters at the given resolution -### h3_exact_edge_length(edge `h3index`, [unit `text` = km]) ⇒ `float` -*Since v3.7.0* +### h3_edge_length(edge `h3index`, [unit `text` = km]) ⇒ `double` +*Since v4.0.0* -Exact length for a specific unidirectional edge. +Exact length for a specific unidirectional edge -### h3_num_hexagons(resolution `integer`) ⇒ `bigint` -*Since v0.2.0* +### h3_get_num_cells(resolution `integer`) ⇒ `bigint` +*Since v4.0.0* -Number of unique H3 indexes at the given resolution. +Number of unique H3 indexes at the given resolution -### h3_get_res_0_indexes() ⇒ `h3index` -*Since v1.0.0* +### h3_get_res_0_cells() ⇒ `h3index` +*Since v4.0.0* -Returns all 122 resolution 0 indexes. +Returns all 122 resolution 0 indexes -### h3_get_pentagon_indexes(resolution `integer`) ⇒ `h3index` -*Since v3.6.0* +### h3_get_pentagons(resolution `integer`) ⇒ `h3index` +*Since v4.0.0* -All the pentagon H3 indexes at the specified resolution. +All the pentagon H3 indexes at the specified resolution # Operators ## B-tree operators @@ -509,66 +568,32 @@ Returns the distance in grid cells between the two indices -# Extension specific functions - -### h3_get_extension_version() ⇒ `text` -*Since v1.0.0* - - -Get the currently installed version of the extension. - - -# PostGIS Functions - -### h3_geo_to_h3(`geometry`, resolution `integer`) ⇒ `h3index` -*Since v0.3.0* +# Type casts +### `h3index` :: `bigint` -### h3_geo_to_h3(`geography`, resolution `integer`) ⇒ `h3index` -*Since v0.3.0* +Convert H3 index to bigint, which is useful when you need a decimal representation -### h3_to_geometry(`h3index`) ⇒ `geometry` -*Since v1.0.0* +### `bigint` :: `h3index` +Convert bigint to H3 index -### h3_to_geography(`h3index`) ⇒ `geography` -*Since v1.0.0* +### `h3index` :: `point` -### h3_to_geo_boundary_geometry(`h3index`, [extend `BOOLEAN` = `false`]) ⇒ `geometry` -*Since v1.0.0* - +Convert H3 index to point +# Extension specific functions -### h3_to_geo_boundary_geography(`h3index`, [extend `BOOLEAN` = `false`]) ⇒ `geography` +### h3_get_extension_version() ⇒ `text` *Since v1.0.0* - -### h3_polyfill(multi `geometry`, resolution `integer`) ⇒ `h3index` -*Since v0.3.0* - - - -### h3_polyfill(multi `geography`, resolution `integer`) ⇒ `h3index` -*Since v0.3.0* - - -## PostGIS casts -### `h3index` :: `point` -*Since v0.3.0* - - -### `h3index` :: `geometry` -*Since v0.3.0* - - -### `h3index` :: `geography` -*Since v0.3.0* +Get the currently installed version of the extension. diff --git a/h3.control b/h3.control index 83012507..1962b8ba 100644 --- a/h3.control +++ b/h3.control @@ -1,4 +1,3 @@ comment = 'H3 bindings for PostgreSQL' -default_version = 'unreleased' +default_version = '4.0.0' relocatable = true -requires = 'postgis' diff --git a/h3/sql/install/00-type.sql b/h3/sql/install/00-type.sql index 18fd6fb6..858dcce5 100644 --- a/h3/sql/install/00-type.sql +++ b/h3/sql/install/00-type.sql @@ -1,5 +1,5 @@ /* - * Copyright 2018-2019 Bytes & Brains + * Copyright 2018-2022 Bytes & Brains * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,9 @@ -- ---------- ---------- ---------- ---------- ---------- ---------- ---------- --| # Base type +--| +--| An unsigned 64-bit integer representing any H3 object (hexagon, pentagon, directed edge ...) +--| represented as a (or 16-character) hexadecimal string, like '8928308280fffff'. -- ---------- ---------- ---------- ---------- ---------- ---------- ---------- -- declare shell type, allowing us to reference while defining functions @@ -26,30 +29,17 @@ CREATE TYPE h3index; --@ internal -CREATE OR REPLACE FUNCTION h3index_in(cstring) RETURNS h3index - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +CREATE OR REPLACE FUNCTION + h3index_in(cstring) RETURNS h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; --@ internal -CREATE OR REPLACE FUNCTION h3index_out(h3index) RETURNS cstring - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +CREATE OR REPLACE FUNCTION + h3index_out(h3index) RETURNS cstring +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; CREATE TYPE h3index ( INPUT = h3index_in, OUTPUT = h3index_out, LIKE = int8 ); - ---@ internal -CREATE OR REPLACE FUNCTION h3index_to_bigint(h3index) RETURNS bigint - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; -CREATE CAST (h3index AS bigint) WITH FUNCTION h3index_to_bigint(h3index); -COMMENT ON CAST (h3index AS bigint) IS - 'Convert H3 index to bigint, which is useful when you need a decimal representation'; - ---@ internal -CREATE OR REPLACE FUNCTION bigint_to_h3index(bigint) RETURNS h3index - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; -CREATE CAST (bigint AS h3index) WITH FUNCTION bigint_to_h3index(bigint); -COMMENT ON CAST (h3index AS bigint) IS - 'Convert bigint to H3 index'; - diff --git a/h3/sql/install/01-indexing.sql b/h3/sql/install/01-indexing.sql index fccdbb45..ffd13f89 100644 --- a/h3/sql/install/01-indexing.sql +++ b/h3/sql/install/01-indexing.sql @@ -1,5 +1,5 @@ /* - * Copyright 2018-2019 Bytes & Brains + * Copyright 2018-2022 Bytes & Brains * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,20 +19,23 @@ --| These function are used for finding the H3 index containing coordinates, --| and for finding the center and boundary of H3 indexes. ---@ availability: 0.2.0 -CREATE OR REPLACE FUNCTION h3_geo_to_h3(point, resolution integer) RETURNS h3index - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; - COMMENT ON FUNCTION h3_geo_to_h3(point, integer) IS -'Indexes the location at the specified resolution'; +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_lat_lng_to_cell(latlng point, resolution integer) RETURNS h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_lat_lng_to_cell(point, integer) +IS 'Indexes the location at the specified resolution'; ---@ availability: 1.0.0 -CREATE OR REPLACE FUNCTION h3_to_geo(h3index) RETURNS point - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; - COMMENT ON FUNCTION h3_to_geo(h3index) IS -'Finds the centroid of the index'; +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_cell_to_lat_lng(cell h3index) RETURNS point +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_cell_to_lat_lng(h3index) +IS 'Finds the centroid of the index'; ---@ availability: 1.0.0 -CREATE OR REPLACE FUNCTION h3_to_geo_boundary(h3index, extend_at_meridian BOOLEAN DEFAULT FALSE) RETURNS polygon - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; - COMMENT ON FUNCTION h3_to_geo_boundary(h3index, boolean) IS -'Finds the boundary of the index, second argument extends coordinates when crossing 180th meridian to help visualization'; \ No newline at end of file +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_cell_to_boundary(cell h3index, extend_at_meridian boolean DEFAULT FALSE) RETURNS polygon +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_cell_to_boundary(h3index, boolean) +IS 'Finds the boundary of the index, second argument extends coordinates when crossing 180th meridian to help visualization'; \ No newline at end of file diff --git a/h3/sql/install/02-inspection.sql b/h3/sql/install/02-inspection.sql index c96673c3..b5c47d68 100644 --- a/h3/sql/install/02-inspection.sql +++ b/h3/sql/install/02-inspection.sql @@ -1,5 +1,5 @@ /* - * Copyright 2018-2019 Bytes & Brains + * Copyright 2018-2022 Bytes & Brains * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,37 +21,43 @@ --| 64-bit representation of an H3 index. --@ availability: 1.0.0 -CREATE OR REPLACE FUNCTION h3_get_resolution(h3index) RETURNS integer - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; - COMMENT ON FUNCTION h3_get_resolution(h3index) IS -'Returns the resolution of the index'; +CREATE OR REPLACE FUNCTION + h3_get_resolution(h3index) RETURNS integer +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_get_resolution(h3index) +IS 'Returns the resolution of the index'; ---@ availability: 1.0.0 -CREATE OR REPLACE FUNCTION h3_get_base_cell(h3index) RETURNS integer - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; - COMMENT ON FUNCTION h3_get_base_cell(h3index) IS -'Returns the base cell number of the index'; +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_get_base_cell_number(h3index) RETURNS integer +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_get_base_cell_number(h3index) +IS 'Returns the base cell number of the index'; --@ availability: 1.0.0 -CREATE OR REPLACE FUNCTION h3_is_valid(h3index) RETURNS bool - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; - COMMENT ON FUNCTION h3_is_valid(h3index) IS -'Returns true if the given H3Index is valid'; +CREATE OR REPLACE FUNCTION + h3_is_valid_cell(h3index) RETURNS boolean +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_is_valid_cell(h3index) +IS 'Returns true if the given H3Index is valid'; --@ availability: 1.0.0 -CREATE OR REPLACE FUNCTION h3_is_res_class_iii(h3index) RETURNS bool - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; - COMMENT ON FUNCTION h3_is_res_class_iii(h3index) IS -'Returns true if this index has a resolution with Class III orientation'; +CREATE OR REPLACE FUNCTION + h3_is_res_class_iii(h3index) RETURNS boolean +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_is_res_class_iii(h3index) +IS 'Returns true if this index has a resolution with Class III orientation'; --@ availability: 1.0.0 -CREATE OR REPLACE FUNCTION h3_is_pentagon(h3index) RETURNS bool - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; - COMMENT ON FUNCTION h3_is_pentagon(h3index) IS -'Returns true if this index represents a pentagonal cell'; +CREATE OR REPLACE FUNCTION + h3_is_pentagon(h3index) RETURNS boolean +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_is_pentagon(h3index) +IS 'Returns true if this index represents a pentagonal cell'; ---@ availability: 3.5.0 -CREATE OR REPLACE FUNCTION h3_get_faces(h3index) RETURNS integer[] - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; - COMMENT ON FUNCTION h3_get_faces(h3index) IS -'Find all icosahedron faces intersected by a given H3 index'; +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_get_icosahedron_faces(h3index) RETURNS integer[] +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_get_icosahedron_faces(h3index) +IS 'Find all icosahedron faces intersected by a given H3 index'; diff --git a/h3/sql/install/03-traversal.sql b/h3/sql/install/03-traversal.sql index 4eac2007..5f6aa654 100644 --- a/h3/sql/install/03-traversal.sql +++ b/h3/sql/install/03-traversal.sql @@ -1,5 +1,5 @@ /* - * Copyright 2018-2019 Bytes & Brains + * Copyright 2018-2022 Bytes & Brains * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,50 +19,55 @@ --| Grid traversal allows finding cells in the vicinity of an origin cell, and --| determining how to traverse the grid from one cell to another. ---@ availability: 0.2.0 -CREATE OR REPLACE FUNCTION h3_k_ring(h3index, k integer DEFAULT 1) RETURNS SETOF h3index - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; - COMMENT ON FUNCTION h3_k_ring(h3index, k integer) IS -'Produces indices within "k" distance of the origin index'; +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_grid_disk(origin h3index, k integer DEFAULT 1) RETURNS SETOF h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_grid_disk(h3index, integer) +IS 'Produces indices within "k" distance of the origin index'; ---@ availability: 0.2.0 -CREATE OR REPLACE FUNCTION h3_k_ring_distances(h3index, k integer DEFAULT 1, OUT index h3index, OUT distance int) RETURNS SETOF record - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; - COMMENT ON FUNCTION h3_k_ring_distances(h3index, k integer) IS -'Produces indices within "k" distance of the origin index paired with their distance to the origin'; +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_grid_disk_distances(origin h3index, k integer DEFAULT 1, OUT index h3index, OUT distance int) RETURNS SETOF record +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_grid_disk_distances(h3index, integer) +IS 'Produces indices within "k" distance of the origin index paired with their distance to the origin'; ---@ availability: 0.2.0 -CREATE OR REPLACE FUNCTION h3_hex_ring(h3index, k integer DEFAULT 1) RETURNS SETOF h3index - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; - COMMENT ON FUNCTION h3_hex_ring(h3index, k integer) IS -'Returns the hollow hexagonal ring centered at origin with distance "k"'; +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_grid_ring_unsafe(origin h3index, k integer DEFAULT 1) RETURNS SETOF h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_grid_ring_unsafe(h3index, integer) +IS 'Returns the hollow hexagonal ring centered at origin with distance "k"'; ---@ availability: 0.4.0 -CREATE OR REPLACE FUNCTION h3_line(h3index, h3index) RETURNS SETOF h3index - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; - COMMENT ON FUNCTION h3_line(h3index, h3index) IS -'Given two H3 indexes, return the line of indexes between them (inclusive). +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_grid_path_cells(origin h3index, destination h3index) RETURNS SETOF h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_grid_path_cells(h3index, h3index) +IS 'Given two H3 indexes, return the line of indexes between them (inclusive). This function may fail to find the line between two indexes, for example if they are very far apart. It may also fail when finding distances for indexes on opposite sides of a pentagon.'; ---@ availability: 0.2.0 -CREATE OR REPLACE FUNCTION h3_distance(h3index, h3index) RETURNS integer - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; - COMMENT ON FUNCTION h3_distance(h3index, h3index) IS -'Returns the distance in grid cells between the two indices'; +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_grid_distance(origin h3index, destination h3index) RETURNS bigint +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_grid_distance(h3index, h3index) +IS 'Returns the distance in grid cells between the two indices'; --@ availability: 0.2.0 -CREATE OR REPLACE FUNCTION h3_experimental_h3_to_local_ij(origin h3index, index h3index) RETURNS POINT - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; - COMMENT ON FUNCTION h3_experimental_h3_to_local_ij(origin h3index, index h3index) IS -'Produces local IJ coordinates for an H3 index anchored by an origin. -This function is experimental, and its output is not guaranteed to be compatible across different versions of H3.'; +CREATE OR REPLACE FUNCTION + h3_cell_to_local_ij(origin h3index, index h3index) RETURNS point +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_cell_to_local_ij(h3index, h3index) +IS 'Produces local IJ coordinates for an H3 index anchored by an origin.'; --@ availability: 0.2.0 -CREATE OR REPLACE FUNCTION h3_experimental_local_ij_to_h3(origin h3index, coord POINT) RETURNS h3index - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; - COMMENT ON FUNCTION h3_experimental_local_ij_to_h3(origin h3index, coord POINT) IS -'Produces an H3 index from local IJ coordinates anchored by an origin. -This function is experimental, and its output is not guaranteed to be compatible across different versions of H3.'; +CREATE OR REPLACE FUNCTION + h3_local_ij_to_cell(origin h3index, coord point) RETURNS h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_local_ij_to_cell(h3index, point) +IS 'Produces an H3 index from local IJ coordinates anchored by an origin.'; diff --git a/h3/sql/install/04-hierarchy.sql b/h3/sql/install/04-hierarchy.sql index e6d2a490..127dfeb2 100644 --- a/h3/sql/install/04-hierarchy.sql +++ b/h3/sql/install/04-hierarchy.sql @@ -1,5 +1,5 @@ /* - * Copyright 2018-2019 Bytes & Brains + * Copyright 2018-2022 Bytes & Brains * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,41 +19,75 @@ --| These functions permit moving between resolutions in the H3 grid system. --| The functions produce parent (coarser) or children (finer) cells. ---@ availability: 1.0.0 -CREATE OR REPLACE FUNCTION h3_to_parent(h3index, resolution integer DEFAULT -1) RETURNS h3index - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; - COMMENT ON FUNCTION h3_to_parent(h3index, resolution integer) IS -'Returns the parent of the given index'; - ---@ availability: 1.0.0 -CREATE OR REPLACE FUNCTION h3_to_children(h3index, resolution integer DEFAULT -1) RETURNS SETOF h3index - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; - COMMENT ON FUNCTION h3_to_children(index h3index, resolution integer) IS -'Returns the set of children of the given index'; - ---@ availability: 3.6.0 -CREATE OR REPLACE FUNCTION h3_to_center_child(h3index, resolution integer DEFAULT -1) RETURNS h3index - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; - COMMENT ON FUNCTION h3_to_parent(h3index, resolution integer) IS -'Returns the center child (finer) index contained by input index at given resolution'; - ---@ availability: 0.2.0 -CREATE OR REPLACE FUNCTION h3_compact(h3index[]) RETURNS SETOF h3index - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; - COMMENT ON FUNCTION h3_compact(h3index[]) IS -'Compacts the given array as best as possible'; - ---@ availability: 0.2.0 -CREATE OR REPLACE FUNCTION h3_uncompact(h3index[], resolution integer DEFAULT -1) RETURNS SETOF h3index - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; - COMMENT ON FUNCTION h3_uncompact(h3index[], resolution integer) IS -'Uncompacts the given array at the given resolution. If no resolution is given, then it is chosen as one higher than the highest resolution in the set'; +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_cell_to_parent(cell h3index, resolution integer) RETURNS h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_cell_to_parent(cell h3index, resolution integer) +IS 'Returns the parent of the given index'; + +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_cell_to_children(cell h3index, resolution integer) RETURNS SETOF h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_cell_to_children(cell h3index, resolution integer) +IS 'Returns the set of children of the given index'; + +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_cell_to_center_child(cell h3index, resolution integer) RETURNS h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_cell_to_center_child(cell h3index, resolution integer) +IS 'Returns the center child (finer) index contained by input index at given resolution'; + +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_compact_cells(cells h3index[]) RETURNS SETOF h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_compact_cells(cells h3index[]) +IS 'Compacts the given array as best as possible'; + +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_uncompact_cells(cells h3index[], resolution integer) RETURNS SETOF h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_uncompact_cells(cells h3index[], resolution integer) +IS 'Uncompacts the given array at the given resolution.'; -- ---------- ---------- ---------- ---------- ---------- ---------- ---------- -- Custom Funtions +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_cell_to_parent(cell h3index) RETURNS h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_cell_to_parent(cell h3index) +IS 'Returns the parent of the given index'; + +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_cell_to_children(cell h3index) RETURNS SETOF h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_cell_to_children(cell h3index) +IS 'Returns the set of children of the given index'; + +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_cell_to_center_child(cell h3index) RETURNS h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_cell_to_center_child(cell h3index) +IS 'Returns the center child (finer) index contained by input index at next resolution'; + +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_uncompact_cells(cells h3index[]) RETURNS SETOF h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_uncompact_cells(cells h3index[]) +IS 'Uncompacts the given array at the resolution one higher than the highest resolution in the set'; + + --@ internal -CREATE OR REPLACE FUNCTION __h3_to_children_aux(index h3index, resolution integer, current INTEGER) +CREATE OR REPLACE FUNCTION __h3_cell_to_children_aux(index h3index, resolution integer, current integer) RETURNS SETOF h3index AS $$ DECLARE retSet h3index[]; @@ -68,18 +102,23 @@ CREATE OR REPLACE FUNCTION __h3_to_children_aux(index h3index, resolution intege END IF; IF current < resolution THEN - SELECT ARRAY(SELECT h3_to_children(index)) into retSet; + SELECT ARRAY(SELECT h3_cell_to_children(index)) into retSet; FOREACH r in ARRAY retSet LOOP - RETURN QUERY SELECT __h3_to_children_aux(r, resolution, current + 1); + RETURN QUERY SELECT __h3_cell_to_children_aux(r, resolution, current + 1); END LOOP; ELSE RETURN NEXT index; END IF; END;$$ LANGUAGE plpgsql; ---@ availability: 1.0.0 -CREATE OR REPLACE FUNCTION h3_to_children_slow(index h3index, resolution integer DEFAULT -1) RETURNS SETOF h3index - AS $$ SELECT __h3_to_children_aux($1, $2, -1) $$ LANGUAGE SQL; - COMMENT ON FUNCTION h3_to_children_slow(index h3index, resolution integer) IS +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION h3_cell_to_children_slow(index h3index, resolution integer) RETURNS SETOF h3index + AS $$ SELECT __h3_cell_to_children_aux($1, $2, -1) $$ LANGUAGE SQL; + COMMENT ON FUNCTION h3_cell_to_children_slow(index h3index, resolution integer) IS +'Slower version of H3ToChildren but allocates less memory'; + +CREATE OR REPLACE FUNCTION h3_cell_to_children_slow(index h3index) RETURNS SETOF h3index + AS $$ SELECT __h3_cell_to_children_aux($1, -1, -1) $$ LANGUAGE SQL; + COMMENT ON FUNCTION h3_cell_to_children_slow(index h3index) IS 'Slower version of H3ToChildren but allocates less memory'; diff --git a/h3/sql/install/05-regions.sql b/h3/sql/install/05-regions.sql index c30d91de..2be1c0eb 100644 --- a/h3/sql/install/05-regions.sql +++ b/h3/sql/install/05-regions.sql @@ -1,5 +1,5 @@ /* - * Copyright 2018-2019 Bytes & Brains + * Copyright 2018-2022 Bytes & Brains * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,14 +18,18 @@ --| --| These functions convert H3 indexes to and from polygonal areas. ---@ availability: 0.2.0 -CREATE OR REPLACE FUNCTION h3_polyfill(exterior polygon, holes polygon[], resolution integer DEFAULT 1) RETURNS SETOF h3index - AS 'h3' LANGUAGE C IMMUTABLE CALLED ON NULL INPUT PARALLEL SAFE; -- NOT STRICT - COMMENT ON FUNCTION h3_polyfill(exterior polygon, holes polygon[], resolution integer) IS -'Takes an exterior polygon [and a set of hole polygon] and returns the set of hexagons that best fit the structure'; +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_polygon_to_cells(exterior polygon, holes polygon[], resolution integer DEFAULT 1) RETURNS SETOF h3index +AS 'h3' LANGUAGE C IMMUTABLE +-- intentionally NOT STRICT +CALLED ON NULL INPUT PARALLEL SAFE; COMMENT ON FUNCTION + h3_polygon_to_cells(polygon, polygon[], integer) +IS 'Takes an exterior polygon [and a set of hole polygon] and returns the set of hexagons that best fit the structure'; ---@ availability: 3.5.0 -CREATE OR REPLACE FUNCTION h3_set_to_multi_polygon(h3index[], OUT exterior polygon, OUT holes polygon[]) RETURNS SETOF record - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; - COMMENT ON FUNCTION h3_set_to_multi_polygon(h3index[]) IS -'Create a LinkedGeoPolygon describing the outline(s) of a set of hexagons. Polygon outlines will follow GeoJSON MultiPolygon order: Each polygon will have one outer loop, which is first in the list, followed by any holes'; +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_cells_to_multi_polygon(h3index[], OUT exterior polygon, OUT holes polygon[]) RETURNS SETOF record +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_cells_to_multi_polygon(h3index[]) +IS 'Create a LinkedGeoPolygon describing the outline(s) of a set of hexagons. Polygon outlines will follow GeoJSON MultiPolygon order: Each polygon will have one outer loop, which is first in the list, followed by any holes'; diff --git a/h3/sql/install/06-edge.sql b/h3/sql/install/06-edge.sql new file mode 100644 index 00000000..70f72739 --- /dev/null +++ b/h3/sql/install/06-edge.sql @@ -0,0 +1,76 @@ +/* + * Copyright 2018-2022 Bytes & Brains + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +--| # Unidirectional edge functions +--| +--| Unidirectional edges allow encoding the directed edge from one cell to a +--| neighboring cell. + +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_are_neighbor_cells(origin h3index, destination h3index) RETURNS boolean +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_are_neighbor_cells(origin h3index, destination h3index) +IS 'Returns true if the given indices are neighbors'; + +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_cells_to_directed_edge(origin h3index, destination h3index) RETURNS h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_cells_to_directed_edge(origin h3index, destination h3index) +IS 'Returns a unidirectional edge H3 index based on the provided origin and destination.'; + +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_is_valid_directed_edge(edge h3index) RETURNS boolean +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_is_valid_directed_edge(edge h3index) +IS 'Returns true if the given edge is valid.'; + +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_get_directed_edge_origin(edge h3index) RETURNS h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_get_directed_edge_origin(edge h3index) +IS 'Returns the origin index from the given edge.'; + +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_get_directed_edge_destination(edge h3index) RETURNS h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_get_directed_edge_destination(edge h3index) +IS 'Returns the destination index from the given edge.'; + +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_directed_edge_to_cells(edge h3index, OUT origin h3index, OUT destination h3index) RETURNS record +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_directed_edge_to_cells(edge h3index) +IS 'Returns the pair of indices from the given edge.'; + +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_origin_to_directed_edges(h3index) RETURNS SETOF h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_origin_to_directed_edges(h3index) +IS 'Returns all unidirectional edges with the given index as origin'; + +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_directed_edge_to_boundary(edge h3index) RETURNS polygon +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_directed_edge_to_boundary(edge h3index) +IS 'Provides the coordinates defining the unidirectional edge.'; diff --git a/h3/sql/install/06-uniedge.sql b/h3/sql/install/06-uniedge.sql deleted file mode 100644 index 0b02900b..00000000 --- a/h3/sql/install/06-uniedge.sql +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2018-2019 Bytes & Brains - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - ---| # Unidirectional edge functions ---| ---| Unidirectional edges allow encoding the directed edge from one cell to a ---| neighboring cell. - ---@ availability: 1.0.0 -CREATE OR REPLACE FUNCTION h3_indexes_are_neighbors(h3index, h3index) RETURNS boolean - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; - COMMENT ON FUNCTION h3_indexes_are_neighbors(h3index, h3index) IS -'Returns true if the given indices are neighbors'; - ---@ availability: 0.2.0 -CREATE OR REPLACE FUNCTION h3_get_h3_unidirectional_edge(origin h3index, destination h3index) RETURNS h3index - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; - COMMENT ON FUNCTION h3_get_h3_unidirectional_edge(origin h3index, destination h3index) IS -'Returns a unidirectional edge H3 index based on the provided origin and destination.'; - ---@ availability: 1.0.0 -CREATE OR REPLACE FUNCTION h3_unidirectional_edge_is_valid(edge h3index) RETURNS boolean - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; - COMMENT ON FUNCTION h3_unidirectional_edge_is_valid(edge h3index) IS -'Returns true if the given edge is valid.'; - ---@ availability: 0.2.0 -CREATE OR REPLACE FUNCTION h3_get_origin_h3_index_from_unidirectional_edge(edge h3index) RETURNS h3index - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; - COMMENT ON FUNCTION h3_get_origin_h3_index_from_unidirectional_edge(edge h3index) IS -'Returns the origin index from the given edge.'; - ---@ availability: 0.2.0 -CREATE OR REPLACE FUNCTION h3_get_destination_h3_index_from_unidirectional_edge(edge h3index) RETURNS h3index - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; - COMMENT ON FUNCTION h3_get_destination_h3_index_from_unidirectional_edge(edge h3index) IS -'Returns the destination index from the given edge.'; - ---@ availability: 0.2.0 -CREATE OR REPLACE FUNCTION h3_get_h3_indexes_from_unidirectional_edge(edge h3index, OUT origin h3index, OUT destination h3index) RETURNS record - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; - COMMENT ON FUNCTION h3_get_h3_indexes_from_unidirectional_edge(edge h3index) IS -'Returns the pair of indices from the given edge.'; - ---@ availability: 0.2.0 -CREATE OR REPLACE FUNCTION h3_get_h3_unidirectional_edges_from_hexagon(h3index) RETURNS SETOF h3index - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; - COMMENT ON FUNCTION h3_get_h3_unidirectional_edges_from_hexagon(h3index) IS -'Returns all unidirectional edges with the given index as origin'; - ---@ availability: 0.2.0 -CREATE OR REPLACE FUNCTION h3_get_h3_unidirectional_edge_boundary(edge h3index) RETURNS polygon - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; - COMMENT ON FUNCTION h3_get_h3_unidirectional_edge_boundary(edge h3index) IS -'Provides the coordinates defining the unidirectional edge.'; diff --git a/h3/sql/install/07-miscellaneous.sql b/h3/sql/install/07-miscellaneous.sql deleted file mode 100644 index 0e5f0cdf..00000000 --- a/h3/sql/install/07-miscellaneous.sql +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2018-2019 Bytes & Brains - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - ---| # Miscellaneous H3 functions ---| ---| These functions include descriptions of the H3 grid system. - ---@ availability: 3.7.0 -CREATE OR REPLACE FUNCTION h3_point_dist(a point, b point, unit text DEFAULT 'km') RETURNS float - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; - COMMENT ON FUNCTION h3_point_dist(point, point, text) IS -'The great circle distance in radians between two spherical coordinates.'; - ---@ availability: 3.5.0 -CREATE OR REPLACE FUNCTION h3_hex_area(resolution integer, unit text DEFAULT 'km') RETURNS float - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; - COMMENT ON FUNCTION h3_hex_area(integer, text) IS -'Average hexagon area in square (kilo)meters at the given resolution.'; - ---@ availability: 3.7.0 -CREATE OR REPLACE FUNCTION h3_cell_area(cell h3index, unit text DEFAULT 'km^2') RETURNS float - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; - COMMENT ON FUNCTION h3_cell_area(h3index, text) IS -'Exact area for a specific cell (hexagon or pentagon).'; - ---@ availability: 3.5.0 -CREATE OR REPLACE FUNCTION h3_edge_length(resolution integer, unit text DEFAULT 'km') RETURNS float - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; - COMMENT ON FUNCTION h3_edge_length(integer, text) IS -'Average hexagon edge length in (kilo)meters at the given resolution.'; - ---@ availability: 3.7.0 -CREATE OR REPLACE FUNCTION h3_exact_edge_length(edge h3index, unit text DEFAULT 'km') RETURNS float - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; - COMMENT ON FUNCTION h3_exact_edge_length(h3index, text) IS -'Exact length for a specific unidirectional edge.'; - ---@ availability: 0.2.0 -CREATE OR REPLACE FUNCTION h3_num_hexagons(resolution integer) RETURNS bigint - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; - COMMENT ON FUNCTION h3_num_hexagons(integer) IS -'Number of unique H3 indexes at the given resolution.'; - ---@ availability: 1.0.0 -CREATE OR REPLACE FUNCTION h3_get_res_0_indexes() RETURNS SETOF h3index - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; - COMMENT ON FUNCTION h3_get_res_0_indexes() IS -'Returns all 122 resolution 0 indexes.'; - ---@ availability: 3.6.0 -CREATE OR REPLACE FUNCTION h3_get_pentagon_indexes(resolution integer) RETURNS SETOF h3index - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; - COMMENT ON FUNCTION h3_get_res_0_indexes() IS -'All the pentagon H3 indexes at the specified resolution.'; \ No newline at end of file diff --git a/h3/sql/install/07-vertex.sql b/h3/sql/install/07-vertex.sql new file mode 100644 index 00000000..3aa15b6e --- /dev/null +++ b/h3/sql/install/07-vertex.sql @@ -0,0 +1,47 @@ +/* + * Copyright 2022 Bytes & Brains + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +--| # H3 Vertex functions +--| +--| Functions for working with cell vertexes. + +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_cell_to_vertex(cell h3index, vertexNum integer) RETURNS h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_cell_to_vertex(cell h3index, vertexNum integer) +IS 'Returns a single vertex for a given cell, as an H3 index'; + +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_cell_to_vertexes(cell h3index) RETURNS SETOF h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_cell_to_vertexes(cell h3index) +IS 'Returns all vertexes for a given cell, as H3 indexes'; + +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_vertex_to_lat_lng(vertex h3index) RETURNS point +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_vertex_to_lat_lng(vertex h3index) +IS 'Get the geocoordinates of an H3 vertex'; + +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_is_valid_vertex(vertex h3index) RETURNS boolean +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_is_valid_vertex(vertex h3index) +IS 'Whether the input is a valid H3 vertex'; diff --git a/h3/sql/install/08-miscellaneous.sql b/h3/sql/install/08-miscellaneous.sql new file mode 100644 index 00000000..30b046c9 --- /dev/null +++ b/h3/sql/install/08-miscellaneous.sql @@ -0,0 +1,75 @@ +/* + * Copyright 2018-2022 Bytes & Brains + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +--| # Miscellaneous H3 functions +--| +--| These functions include descriptions of the H3 grid system. + +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_great_circle_distance(a point, b point, unit text DEFAULT 'km') RETURNS double precision +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_great_circle_distance(point, point, text) +IS 'The great circle distance in radians between two spherical coordinates'; + +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_get_hexagon_area_avg(resolution integer, unit text DEFAULT 'km') RETURNS double precision +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_get_hexagon_area_avg(integer, text) +IS 'Average hexagon area in square (kilo)meters at the given resolution'; + +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_cell_area(cell h3index, unit text DEFAULT 'km^2') RETURNS double precision +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_cell_area(h3index, text) +IS 'Exact area for a specific cell (hexagon or pentagon)'; + +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_get_hexagon_edge_length_avg(resolution integer, unit text DEFAULT 'km') RETURNS double precision +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_get_hexagon_edge_length_avg(integer, text) +IS 'Average hexagon edge length in (kilo)meters at the given resolution'; + +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_edge_length(edge h3index, unit text DEFAULT 'km') RETURNS double precision +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_edge_length(h3index, text) +IS 'Exact length for a specific unidirectional edge'; + +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_get_num_cells(resolution integer) RETURNS bigint +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_get_num_cells(integer) IS +'Number of unique H3 indexes at the given resolution'; + +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_get_res_0_cells() RETURNS SETOF h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_get_res_0_cells() +IS 'Returns all 122 resolution 0 indexes'; + +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION + h3_get_pentagons(resolution integer) RETURNS SETOF h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_get_pentagons(resolution integer) +IS 'All the pentagon H3 indexes at the specified resolution'; \ No newline at end of file diff --git a/h3/sql/install/10-operators.sql b/h3/sql/install/10-operators.sql index bc1b41df..6705106e 100644 --- a/h3/sql/install/10-operators.sql +++ b/h3/sql/install/10-operators.sql @@ -1,5 +1,5 @@ /* - * Copyright 2018-2019 Bytes & Brains + * Copyright 2018-2022 Bytes & Brains * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -153,7 +153,7 @@ COMMENT ON OPERATOR <@ (h3index, h3index) IS CREATE OPERATOR <-> ( LEFTARG = h3index, RIGHTARG = h3index, - PROCEDURE = h3_distance, + PROCEDURE = h3_grid_distance, COMMUTATOR = <-> ); COMMENT ON OPERATOR <-> (h3index, h3index) IS diff --git a/h3/sql/install/20-casts.sql b/h3/sql/install/20-casts.sql new file mode 100644 index 00000000..8f1ecbdf --- /dev/null +++ b/h3/sql/install/20-casts.sql @@ -0,0 +1,37 @@ +/* + * Copyright 2022 Bytes & Brains + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +--| # Type casts + +--@ internal +CREATE OR REPLACE FUNCTION + h3index_to_bigint(h3index) RETURNS bigint +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +CREATE CAST (h3index AS bigint) WITH FUNCTION h3index_to_bigint(h3index); +COMMENT ON CAST (h3index AS bigint) IS + 'Convert H3 index to bigint, which is useful when you need a decimal representation'; + +--@ internal +CREATE OR REPLACE FUNCTION + bigint_to_h3index(bigint) RETURNS h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +CREATE CAST (bigint AS h3index) WITH FUNCTION bigint_to_h3index(bigint); +COMMENT ON CAST (h3index AS bigint) IS + 'Convert bigint to H3 index'; + +CREATE CAST (h3index AS point) WITH FUNCTION h3_cell_to_lat_lng(h3index); +COMMENT ON CAST (h3index AS point) IS + 'Convert H3 index to point'; \ No newline at end of file diff --git a/h3/sql/install/30-deprecated.sql b/h3/sql/install/30-deprecated.sql deleted file mode 100644 index f4d910db..00000000 --- a/h3/sql/install/30-deprecated.sql +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2020 Bytes & Brains - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - ---@ deprecated: 3.7.0 -CREATE OR REPLACE FUNCTION h3_hex_area(resolution integer, km boolean) RETURNS float - AS $$ SELECT h3_hex_area($1, CASE WHEN $2 THEN 'km' ELSE 'm' END) $$ - IMMUTABLE STRICT PARALLEL SAFE LANGUAGE SQL; - ---@ deprecated: 3.7.0 -CREATE OR REPLACE FUNCTION h3_edge_length(resolution integer, km boolean) RETURNS float - AS $$ SELECT h3_edge_length($1, CASE WHEN $2 THEN 'km' ELSE 'm' END) $$ - IMMUTABLE STRICT PARALLEL SAFE LANGUAGE SQL; diff --git a/h3/sql/install/20-extension.sql b/h3/sql/install/30-extension.sql similarity index 95% rename from h3/sql/install/20-extension.sql rename to h3/sql/install/30-extension.sql index ae0bec99..e61048e6 100644 --- a/h3/sql/install/20-extension.sql +++ b/h3/sql/install/30-extension.sql @@ -1,5 +1,5 @@ /* - * Copyright 2018-2019 Bytes & Brains + * Copyright 2018-2022 Bytes & Brains * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/h3/sql/install/99-postgis.sql b/h3/sql/install/99-postgis.sql deleted file mode 100644 index e414d2fe..00000000 --- a/h3/sql/install/99-postgis.sql +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2019 Bytes & Brains - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - ---| # PostGIS Functions - ---@ availability: 0.3.0 -CREATE OR REPLACE FUNCTION h3_geo_to_h3(geometry, resolution integer) RETURNS h3index - AS $$ SELECT h3_geo_to_h3($1::point, $2); $$ IMMUTABLE STRICT PARALLEL SAFE LANGUAGE SQL; - ---@ availability: 0.3.0 -CREATE OR REPLACE FUNCTION h3_geo_to_h3(geography, resolution integer) RETURNS h3index - AS $$ SELECT h3_geo_to_h3($1::geometry, $2); $$ IMMUTABLE STRICT PARALLEL SAFE LANGUAGE SQL; - ---@ availability: 1.0.0 -CREATE OR REPLACE FUNCTION h3_to_geometry(h3index) RETURNS geometry - AS $$ SELECT ST_SetSRID(h3_to_geo($1)::geometry, 4326) $$ IMMUTABLE STRICT PARALLEL SAFE LANGUAGE SQL; - ---@ availability: 1.0.0 -CREATE OR REPLACE FUNCTION h3_to_geography(h3index) RETURNS geography - AS $$ SELECT h3_to_geometry($1)::geography $$ IMMUTABLE STRICT PARALLEL SAFE LANGUAGE SQL; - ---@ availability: 1.0.0 -CREATE OR REPLACE FUNCTION h3_to_geo_boundary_geometry(h3index, extend BOOLEAN DEFAULT FALSE) RETURNS geometry - AS $$ SELECT ST_SetSRID(h3_to_geo_boundary($1, $2)::geometry, 4326) $$ IMMUTABLE STRICT PARALLEL SAFE LANGUAGE SQL; - ---@ availability: 1.0.0 -CREATE OR REPLACE FUNCTION h3_to_geo_boundary_geography(h3index, extend BOOLEAN DEFAULT FALSE) RETURNS geography - AS $$ SELECT h3_to_geo_boundary_geometry($1, $2)::geography $$ IMMUTABLE STRICT PARALLEL SAFE LANGUAGE SQL; - ---@ availability: 0.3.0 -CREATE OR REPLACE FUNCTION h3_polyfill(multi geometry, resolution integer) RETURNS SETOF h3index - AS $$ SELECT h3_polyfill(exterior, holes, resolution) FROM ( - SELECT - -- extract exterior ring of each polygon - ST_MakePolygon(ST_ExteriorRing(poly))::polygon exterior, - -- extract holes of each polygon - (SELECT array_agg(hole) - FROM ( - SELECT ST_MakePolygon(ST_InteriorRingN( - poly, - generate_series(1, ST_NumInteriorRings(poly)) - ))::polygon AS hole - ) q_hole - ) holes - -- extract single polygons from multipolygon - FROM ( - select (st_dump(multi)).geom as poly - ) q_poly GROUP BY poly - ) h3_polyfill; $$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE CALLED ON NULL INPUT; -- NOT STRICT - ---@ availability: 0.3.0 -CREATE OR REPLACE FUNCTION h3_polyfill(multi geography, resolution integer) RETURNS SETOF h3index -AS $$ SELECT h3_polyfill($1::geometry, $2) $$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE CALLED ON NULL INPUT; -- NOT STRICT - --- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---| ## PostGIS casts - ---@ availability: 0.3.0 -CREATE CAST (h3index AS point) WITH FUNCTION h3_to_geo(h3index); - ---@ availability: 0.3.0 -CREATE CAST (h3index AS geometry) WITH FUNCTION h3_to_geometry(h3index); - ---@ availability: 0.3.0 -CREATE CAST (h3index AS geography) WITH FUNCTION h3_to_geography(h3index); diff --git a/h3/sql/updates/h3--0.1.0--0.2.0.sql b/h3/sql/updates/h3--0.1.0--0.2.0.sql index 1b4793b6..7723884e 100644 --- a/h3/sql/updates/h3--0.1.0--0.2.0.sql +++ b/h3/sql/updates/h3--0.1.0--0.2.0.sql @@ -1,5 +1,5 @@ /* - * Copyright 2018 Bytes & Brains + * Copyright 2018-2022 Bytes & Brains * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,15 +19,15 @@ -- Indexing functions (indexing.c) CREATE OR REPLACE FUNCTION h3_geo_to_h3(point, resolution integer) RETURNS h3index - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + AS 'h3', 'h3_lat_lng_to_cell' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION h3_geo_to_h3(point, resolution integer) IS 'Indexes the location at the specified resolution'; CREATE OR REPLACE FUNCTION h3_h3_to_geo(h3index) RETURNS point - AS 'h3', 'h3_to_geo' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + AS 'h3', 'h3_cell_to_lat_lng' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION h3_h3_to_geo(h3index) IS 'Finds the centroid of the index'; CREATE OR REPLACE FUNCTION h3_h3_to_geo_boundary(h3index) RETURNS polygon - AS 'h3', 'h3_to_geo_boundary' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + AS 'h3', 'h3_cell_to_boundary' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION h3_h3_to_geo_boundary(h3index) IS 'Finds the boundary of the index'; @@ -37,11 +37,11 @@ CREATE OR REPLACE FUNCTION h3_h3_get_resolution(h3index) RETURNS integer COMMENT ON FUNCTION h3_h3_get_resolution(h3index) IS 'Returns the resolution of the index'; CREATE OR REPLACE FUNCTION h3_h3_get_base_cell(h3index) RETURNS integer - AS 'h3', 'h3_get_base_cell' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + AS 'h3', 'h3_get_base_cell_number' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION h3_h3_get_base_cell(h3index) IS 'Returns the base cell number of the index'; CREATE OR REPLACE FUNCTION h3_h3_is_valid(h3index) RETURNS bool - AS 'h3', 'h3_is_valid' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + AS 'h3', 'h3_is_valid_cell' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION h3_h3_is_valid(h3index) IS 'Returns true if the given H3Index is valid'; CREATE OR REPLACE FUNCTION h3_h3_is_res_class_iii(h3index) RETURNS bool @@ -55,97 +55,97 @@ CREATE OR REPLACE FUNCTION h3_h3_is_pentagon(h3index) RETURNS bool -- Grid traversal functions (traversal.c) CREATE OR REPLACE FUNCTION h3_k_ring(h3index, k integer DEFAULT 1) RETURNS SETOF h3index - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + AS 'h3', 'h3_grid_disk' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION h3_k_ring(h3index, k integer) IS 'Produces indices within "k" distance of the origin index'; CREATE OR REPLACE FUNCTION h3_k_ring_distances(h3index, k integer DEFAULT 1, OUT index h3index, OUT distance int) RETURNS SETOF record - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + AS 'h3', 'h3_grid_disk_distances' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION h3_k_ring_distances(h3index, k integer) IS 'Produces indices within "k" distance of the origin index paired with their distance to the origin'; CREATE OR REPLACE FUNCTION h3_hex_ring(h3index, k integer DEFAULT 1) RETURNS SETOF h3index - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + AS 'h3', 'h3_grid_ring_unsafe' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION h3_hex_ring(h3index, k integer) IS 'Returns the hollow hexagonal ring centered at origin with distance "k"'; CREATE OR REPLACE FUNCTION h3_distance(h3index, h3index) RETURNS integer - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + AS 'h3', 'h3_grid_distance' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION h3_distance(h3index, h3index) IS 'Returns the distance in grid cells between the two indices'; CREATE OR REPLACE FUNCTION h3_experimental_h3_to_local_ij(origin h3index, index h3index) RETURNS POINT - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + AS 'h3', 'h3_cell_to_local_ij' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION h3_experimental_h3_to_local_ij(origin h3index, index h3index) IS 'Produces local IJ coordinates for an H3 index anchored by an origin. This function is experimental, and its output is not guaranteed to be compatible across different versions of H3.'; CREATE OR REPLACE FUNCTION h3_experimental_local_ij_to_h3(origin h3index, coord POINT) RETURNS h3index - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + AS 'h3', 'h3_local_ij_to_cell' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION h3_experimental_local_ij_to_h3(origin h3index, coord POINT) IS 'Produces an H3 index from local IJ coordinates anchored by an origin. This function is experimental, and its output is not guaranteed to be compatible across different versions of H3.'; -- Hierarchical grid functions (hierarchy.c) CREATE OR REPLACE FUNCTION h3_h3_to_parent(h3index, resolution integer DEFAULT -1) RETURNS h3index - AS 'h3', 'h3_to_parent' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + AS 'h3', 'h3_cell_to_parent' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION h3_h3_to_parent(h3index, resolution integer) IS 'Returns the parent of the given index'; CREATE OR REPLACE FUNCTION h3_h3_to_children(h3index, resolution integer DEFAULT -1) RETURNS SETOF h3index - AS 'h3', 'h3_to_children' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + AS 'h3', 'h3_cell_to_children' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION h3_h3_to_children(index h3index, resolution integer) IS 'Returns the set of children of the given index'; CREATE OR REPLACE FUNCTION h3_compact(h3index[]) RETURNS SETOF h3index - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + AS 'h3', 'h3_compact_cells' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION h3_compact(h3index[]) IS 'Compacts the given array as best as possible'; CREATE OR REPLACE FUNCTION h3_uncompact(h3index[], resolution integer DEFAULT -1) RETURNS SETOF h3index - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + AS 'h3', 'h3_uncompact_cells' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION h3_uncompact(h3index[], resolution integer) IS 'Uncompacts the given array at the given resolution. If no resolution is given, then it is chosen as one higher than the highest resolution in the set'; - + -- Region functions (regions.c) CREATE OR REPLACE FUNCTION h3_polyfill(exterior polygon, holes polygon[], resolution integer DEFAULT 1) RETURNS SETOF h3index - AS 'h3' LANGUAGE C IMMUTABLE PARALLEL SAFE; -- NOT STRICT + AS 'h3', 'h3_polygon_to_cells' LANGUAGE C IMMUTABLE PARALLEL SAFE; -- NOT STRICT COMMENT ON FUNCTION h3_polyfill(exterior polygon, holes polygon[], resolution integer) IS 'Takes an exterior polygon [and a set of hole polygon] and returns the set of hexagons that best fit the structure'; CREATE OR REPLACE FUNCTION h3_h3_set_to_linked_geo(h3index[], OUT exterior polygon, OUT holes polygon[]) RETURNS SETOF record - AS 'h3', 'h3_set_to_multi_polygon' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + AS 'h3', 'h3_cells_to_multi_polygon' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION h3_h3_set_to_linked_geo(h3index[]) IS 'Create a LinkedGeoPolygon describing the outline(s) of a set of hexagons. Polygon outlines will follow GeoJSON MultiPolygon order: Each polygon will have one outer loop, which is first in the list, followed by any holes'; -- Unidirectional edge functions (uniedges.c) CREATE OR REPLACE FUNCTION h3_h3_indexes_are_neighbors(h3index, h3index) RETURNS boolean - AS 'h3', 'h3_indexes_are_neighbors' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + AS 'h3', 'h3_are_neighbor_cells' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION h3_h3_indexes_are_neighbors(h3index, h3index) IS 'Returns true if the given indices are neighbors'; CREATE OR REPLACE FUNCTION h3_get_h3_unidirectional_edge(origin h3index, destination h3index) RETURNS h3index - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + AS 'h3', 'h3_cells_to_directed_edge' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION h3_get_h3_unidirectional_edge(origin h3index, destination h3index) IS 'Returns a unidirectional edge H3 index based on the provided origin and destination.'; CREATE OR REPLACE FUNCTION h3_h3_unidirectional_edge_is_valid(edge h3index) RETURNS boolean - AS 'h3', 'h3_unidirectional_edge_is_valid' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + AS 'h3', 'h3_is_valid_directed_edge' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION h3_h3_unidirectional_edge_is_valid(edge h3index) IS 'Returns true if the given edge is valid.'; CREATE OR REPLACE FUNCTION h3_get_origin_h3_index_from_unidirectional_edge(edge h3index) RETURNS h3index - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + AS 'h3', 'h3_get_directed_edge_origin' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION h3_get_origin_h3_index_from_unidirectional_edge(edge h3index) IS 'Returns the origin index from the given edge.'; CREATE OR REPLACE FUNCTION h3_get_destination_h3_index_from_unidirectional_edge(edge h3index) RETURNS h3index - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + AS 'h3', 'h3_get_directed_edge_destination' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION h3_get_destination_h3_index_from_unidirectional_edge(edge h3index) IS 'Returns the destination index from the given edge.'; CREATE OR REPLACE FUNCTION h3_get_h3_indexes_from_unidirectional_edge(edge h3index, OUT origin h3index, OUT destination h3index) RETURNS record - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + AS 'h3', 'h3_directed_edge_to_cells' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION h3_get_h3_indexes_from_unidirectional_edge(edge h3index) IS 'Returns the pair of indices from the given edge.'; CREATE OR REPLACE FUNCTION h3_get_h3_unidirectional_edges_from_hexagon(h3index) RETURNS SETOF h3index - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + AS 'h3', 'h3_origin_to_directed_edges' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION h3_get_h3_unidirectional_edges_from_hexagon(h3index) IS 'Returns all unidirectional edges with the given index as origin'; CREATE OR REPLACE FUNCTION h3_get_unidirectional_edge_boundary(edge h3index) RETURNS polygon - AS 'h3', 'h3_get_h3_unidirectional_edge_boundary' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + AS 'h3', 'h3_directed_edge_to_boundary' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION h3_get_unidirectional_edge_boundary(edge h3index) IS 'Provides the coordinates defining the unidirectional edge.'; -- Miscellaneous H3 functions (miscellaneous.c) CREATE OR REPLACE FUNCTION h3_num_hexagons(resolution integer) RETURNS bigint - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + AS 'h3', 'h3_get_num_cells' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION h3_num_hexagons(resolution integer) IS 'Number of unique H3 indexes at the given resolution.'; diff --git a/h3/sql/updates/h3--0.2.0--0.3.0.sql b/h3/sql/updates/h3--0.2.0--0.3.0.sql index 76161f85..d7dc6d69 100644 --- a/h3/sql/updates/h3--0.2.0--0.3.0.sql +++ b/h3/sql/updates/h3--0.2.0--0.3.0.sql @@ -1,5 +1,5 @@ /* - * Copyright 2018-2019 Bytes & Brains + * Copyright 2018-2022 Bytes & Brains * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ -- Custom helper functions CREATE OR REPLACE FUNCTION h3_basecells() RETURNS SETOF h3index - AS 'h3', 'h3_get_res_0_indexes' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + AS 'h3', 'h3_get_res_0_cells' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION h3_basecells() IS 'Returns all 122 basecells.'; diff --git a/h3/sql/updates/h3--0.3.0--0.3.1.sql b/h3/sql/updates/h3--0.3.0--0.3.1.sql index 77456c73..28745e8a 100644 --- a/h3/sql/updates/h3--0.3.0--0.3.1.sql +++ b/h3/sql/updates/h3--0.3.0--0.3.1.sql @@ -1,5 +1,5 @@ /* - * Copyright 2018 Bytes & Brains + * Copyright 2018-2022 Bytes & Brains * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,7 +22,7 @@ DROP FUNCTION IF EXISTS h3_h3_to_geo_boundary_geometry(h3index); DROP FUNCTION IF EXISTS h3_h3_to_geo_boundary_geography(h3index); CREATE OR REPLACE FUNCTION h3_h3_to_geo_boundary(h3index, extend_at_meridian BOOLEAN DEFAULT FALSE) RETURNS polygon - AS 'h3', 'h3_to_geo_boundary' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + AS 'h3', 'h3_cell_to_boundary' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION h3_h3_to_geo_boundary(h3index, boolean) IS 'Finds the boundary of the index, second argument extends coordinates when crossing 180th meridian to help visualization'; CREATE OR REPLACE FUNCTION h3_h3_to_geo_boundary_geometry(h3index, extend BOOLEAN DEFAULT FALSE) RETURNS geometry diff --git a/h3/sql/updates/h3--0.3.2--0.4.0.sql b/h3/sql/updates/h3--0.3.2--0.4.0.sql index b0398ff3..27018b76 100644 --- a/h3/sql/updates/h3--0.3.2--0.4.0.sql +++ b/h3/sql/updates/h3--0.3.2--0.4.0.sql @@ -1,5 +1,5 @@ /* - * Copyright 2018 Bytes & Brains + * Copyright 2018-2022 Bytes & Brains * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,7 @@ \echo Use "ALTER EXTENSION h3 UPDATE TO '0.4.0'" to load this file. \quit CREATE OR REPLACE FUNCTION h3_line(h3index, h3index) RETURNS SETOF h3index - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + AS 'h3', 'h3_grid_path_cells' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION h3_line(h3index, h3index) IS 'Given two H3 indexes, return the line of indexes between them (inclusive). diff --git a/h3/sql/updates/h3--3.4.1--3.5.0.sql b/h3/sql/updates/h3--3.4.1--3.5.0.sql index 29e55040..b42866c1 100644 --- a/h3/sql/updates/h3--3.4.1--3.5.0.sql +++ b/h3/sql/updates/h3--3.4.1--3.5.0.sql @@ -1,5 +1,5 @@ /* - * Copyright 2019 Bytes & Brains + * Copyright 2019-2022 Bytes & Brains * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,7 @@ \echo Use "ALTER EXTENSION h3 UPDATE TO '3.5.0'" to load this file. \quit CREATE OR REPLACE FUNCTION h3_get_faces(h3index) RETURNS integer[] - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + AS 'h3', 'h3_get_icosahedron_faces' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION h3_get_faces(h3index) IS 'Find all icosahedron faces intersected by a given H3 index'; @@ -35,7 +35,7 @@ CREATE OR REPLACE FUNCTION h3_edge_length(resolution integer, km boolean DEFAULT DROP FUNCTION IF EXISTS h3_hex_area_km2(integer); DROP FUNCTION IF EXISTS h3_hex_area_m2(integer); CREATE OR REPLACE FUNCTION h3_hex_area(resolution integer, km boolean DEFAULT FALSE) RETURNS float - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + AS 'h3', 'h3_get_hexagon_area_avg' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION h3_hex_area(integer, boolean) IS 'Average hexagon area in square (kilo)meters at the given resolution.'; diff --git a/h3/sql/updates/h3--3.5.0--3.6.0.sql b/h3/sql/updates/h3--3.5.0--3.6.0.sql index d4cf70db..819a809a 100644 --- a/h3/sql/updates/h3--3.5.0--3.6.0.sql +++ b/h3/sql/updates/h3--3.5.0--3.6.0.sql @@ -1,5 +1,5 @@ /* - * Copyright 2019 Bytes & Brains + * Copyright 2019-2022 Bytes & Brains * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,13 +19,13 @@ -- Hierarchical grid functions (hierarchy.c) CREATE OR REPLACE FUNCTION h3_to_center_child(h3index, resolution integer DEFAULT -1) RETURNS h3index - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + AS 'h3', 'h3_cell_to_center_child' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION h3_to_parent(h3index, resolution integer) IS 'Returns the center child (finer) index contained by input index at given resolution'; -- Miscellaneous H3 functions (miscellaneous.c) CREATE OR REPLACE FUNCTION h3_get_pentagon_indexes(resolution integer) RETURNS SETOF h3index - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + AS 'h3', 'h3_get_pentagons' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION h3_get_res_0_indexes() IS 'All the pentagon H3 indexes at the specified resolution.'; diff --git a/h3/sql/updates/h3--3.6.5--3.7.0.sql b/h3/sql/updates/h3--3.6.5--3.7.0.sql index 53e20344..19e4d902 100644 --- a/h3/sql/updates/h3--3.6.5--3.7.0.sql +++ b/h3/sql/updates/h3--3.6.5--3.7.0.sql @@ -1,5 +1,5 @@ /* - * Copyright 2020 Bytes & Brains + * Copyright 2020-2022 Bytes & Brains * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,7 +32,7 @@ CREATE OR REPLACE FUNCTION h3_to_geography(h3index) RETURNS geography -- New functions in core v3.7.0 CREATE OR REPLACE FUNCTION h3_point_dist(a point, b point, unit text DEFAULT 'km') RETURNS float - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + AS 'h3', 'h3_great_circle_distance' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION h3_point_dist(point, point, text) IS 'The great circle distance in radians between two spherical coordinates.'; @@ -42,13 +42,13 @@ CREATE OR REPLACE FUNCTION h3_cell_area(cell h3index, unit text DEFAULT 'km^2') 'Exact area for a specific cell (hexagon or pentagon).'; CREATE OR REPLACE FUNCTION h3_exact_edge_length(edge h3index, unit text DEFAULT 'km') RETURNS float - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + AS 'h3', 'h3_edge_length' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION h3_exact_edge_length(h3index, text) IS 'Exact length for a specific unidirectional edge.'; -- New call signatures for hexarea and edgelength, using string instead of boolean CREATE OR REPLACE FUNCTION h3_hex_area(resolution integer, unit text DEFAULT 'km') RETURNS float - AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + AS 'h3', 'h3_get_hexagon_area_avg' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION h3_hex_area(integer, text) IS 'Average hexagon area in square (kilo)meters at the given resolution.'; diff --git a/h3/sql/updates/h3--3.7.2--4.0.0.sql b/h3/sql/updates/h3--3.7.2--4.0.0.sql new file mode 100644 index 00000000..03b36c43 --- /dev/null +++ b/h3/sql/updates/h3--3.7.2--4.0.0.sql @@ -0,0 +1,253 @@ +/* + * Copyright 2022 Bytes & Brains + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "ALTER EXTENSION h3 UPDATE TO '4.0.0'" to load this file. \quit + +-- Move postgis integration to its own extension +DROP FUNCTION IF EXISTS h3_geo_to_h3(geometry, resolution integer); +DROP FUNCTION IF EXISTS h3_geo_to_h3(geography, resolution integer); +DROP FUNCTION IF EXISTS h3_to_geo_boundary_geometry(h3index); +DROP FUNCTION IF EXISTS h3_to_geo_boundary_geography(h3index); +DROP FUNCTION IF EXISTS h3_to_geo_boundary_geometry(h3index, extend boolean); +DROP FUNCTION IF EXISTS h3_to_geo_boundary_geography(h3index, extend boolean); +DROP FUNCTION IF EXISTS h3_polyfill(multi geometry, resolution integer); +DROP FUNCTION IF EXISTS h3_polyfill(multi geography, resolution integer); +DROP CAST (h3index AS geometry); +DROP CAST (h3index AS geography); +DROP FUNCTION IF EXISTS h3_to_geometry(h3index); +DROP FUNCTION IF EXISTS h3_to_geography(h3index); + +-- H3 Core v4 renames + +-- indexing +ALTER FUNCTION h3_geo_to_h3(point, resolution integer) RENAME TO h3_lat_lng_to_cell; +CREATE OR REPLACE FUNCTION + h3_lat_lng_to_cell(latlng point, resolution integer) RETURNS h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +ALTER FUNCTION h3_to_geo(h3index) RENAME TO h3_cell_to_lat_lng; +CREATE OR REPLACE FUNCTION + h3_cell_to_lat_lng(cell h3index) RETURNS point +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +ALTER FUNCTION h3_to_geo_boundary(h3index, extend_at_meridian BOOLEAN) RENAME TO h3_cell_to_boundary; +CREATE OR REPLACE FUNCTION + h3_cell_to_boundary(cell h3index, extend_at_meridian boolean DEFAULT FALSE) RETURNS polygon +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; + +-- inspection + +ALTER FUNCTION h3_get_base_cell(h3index) RENAME TO h3_get_base_cell_number; +ALTER FUNCTION h3_is_valid(h3index) RENAME TO h3_is_valid_cell; +ALTER FUNCTION h3_get_faces(h3index) RENAME TO h3_get_icosahedron_faces; + +-- traversal +ALTER FUNCTION h3_k_ring(h3index, k integer) RENAME TO h3_grid_disk; +CREATE OR REPLACE FUNCTION + h3_grid_disk(origin h3index, k integer DEFAULT 1) RETURNS SETOF h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +ALTER FUNCTION h3_k_ring_distances(h3index, k integer, OUT index h3index, OUT distance int) RENAME TO h3_grid_disk_distances; +CREATE OR REPLACE FUNCTION + h3_grid_disk_distances(origin h3index, k integer DEFAULT 1, OUT index h3index, OUT distance int) RETURNS SETOF record +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +DROP FUNCTION h3_hex_ring(h3index, k integer); +CREATE OR REPLACE FUNCTION + h3_grid_ring_unsafe(origin h3index, k integer DEFAULT 1) RETURNS SETOF h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_grid_ring_unsafe(h3index, integer) +IS 'Returns the hollow hexagonal ring centered at origin with distance "k"'; + +DROP FUNCTION h3_line(h3index, h3index); +CREATE OR REPLACE FUNCTION + h3_grid_path_cells(origin h3index, destination h3index) RETURNS SETOF h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_grid_path_cells(h3index, h3index) +IS 'Given two H3 indexes, return the line of indexes between them (inclusive). + +This function may fail to find the line between two indexes, for +example if they are very far apart. It may also fail when finding +distances for indexes on opposite sides of a pentagon.'; +DROP OPERATOR <-> (h3index, h3index); +DROP FUNCTION h3_distance(h3index, h3index); +CREATE OR REPLACE FUNCTION + h3_grid_distance(origin h3index, destination h3index) RETURNS bigint +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +ALTER FUNCTION h3_experimental_h3_to_local_ij(origin h3index, index h3index) RENAME TO h3_cell_to_local_ij; +ALTER FUNCTION h3_experimental_local_ij_to_h3(origin h3index, coord POINT) RENAME TO h3_local_ij_to_cell; + +CREATE OPERATOR <-> ( + LEFTARG = h3index, + RIGHTARG = h3index, + PROCEDURE = h3_grid_distance, + COMMUTATOR = <-> +); +COMMENT ON OPERATOR <-> (h3index, h3index) IS + 'Returns the distance in grid cells between the two indices'; + + +-- hierarchy +DROP FUNCTION h3_to_parent(h3index, resolution integer); +CREATE OR REPLACE FUNCTION + h3_cell_to_parent(cell h3index, resolution integer) RETURNS h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_cell_to_parent(cell h3index, resolution integer) +IS 'Returns the parent of the given index'; + +DROP FUNCTION h3_to_children(h3index, resolution integer); +CREATE OR REPLACE FUNCTION + h3_cell_to_children(cell h3index, resolution integer) RETURNS SETOF h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_cell_to_children(cell h3index, resolution integer) +IS 'Returns the set of children of the given index'; + +DROP FUNCTION h3_to_center_child(h3index, resolution integer); + +CREATE OR REPLACE FUNCTION + h3_cell_to_center_child(cell h3index, resolution integer) RETURNS h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_cell_to_center_child(cell h3index, resolution integer) +IS 'Returns the center child (finer) index contained by input index at given resolution'; + +DROP FUNCTION h3_compact(h3index[]); +CREATE OR REPLACE FUNCTION + h3_compact_cells(cells h3index[]) RETURNS SETOF h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_compact_cells(cells h3index[]) +IS 'Compacts the given array as best as possible'; +DROP FUNCTION h3_uncompact(h3index[], resolution integer); +CREATE OR REPLACE FUNCTION + h3_uncompact_cells(cells h3index[], resolution integer) RETURNS SETOF h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_uncompact_cells(cells h3index[], resolution integer) +IS 'Uncompacts the given array at the given resolution.'; + +DROP FUNCTION IF EXISTS h3_to_children_slow(index h3index); +DROP FUNCTION IF EXISTS h3_to_children_slow(index h3index, resolution integer); +DROP FUNCTION IF EXISTS __h3_to_children_aux(index h3index, resolution integer, current integer); +--copied new +CREATE OR REPLACE FUNCTION + h3_cell_to_parent(cell h3index) RETURNS h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_cell_to_parent(cell h3index) +IS 'Returns the parent of the given index'; +CREATE OR REPLACE FUNCTION + h3_cell_to_children(cell h3index) RETURNS SETOF h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_cell_to_children(cell h3index) +IS 'Returns the set of children of the given index'; +CREATE OR REPLACE FUNCTION + h3_cell_to_center_child(cell h3index) RETURNS h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_cell_to_center_child(cell h3index) +IS 'Returns the center child (finer) index contained by input index at next resolution'; +CREATE OR REPLACE FUNCTION + h3_uncompact_cells(cells h3index[]) RETURNS SETOF h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_uncompact_cells(cells h3index[]) +IS 'Uncompacts the given array at the resolution one higher than the highest resolution in the set'; +CREATE OR REPLACE FUNCTION __h3_cell_to_children_aux(index h3index, resolution integer, current integer) + RETURNS SETOF h3index AS $$ + DECLARE + retSet h3index[]; + r h3index; + BEGIN + IF current = -1 THEN + SELECT h3_get_resolution(index) into current; + END IF; + + IF resolution = -1 THEN + SELECT h3_get_resolution(index)+1 into resolution; + END IF; + + IF current < resolution THEN + SELECT ARRAY(SELECT h3_cell_to_children(index)) into retSet; + FOREACH r in ARRAY retSet LOOP + RETURN QUERY SELECT __h3_cell_to_children_aux(r, resolution, current + 1); + END LOOP; + ELSE + RETURN NEXT index; + END IF; + END;$$ LANGUAGE plpgsql; +CREATE OR REPLACE FUNCTION h3_cell_to_children_slow(index h3index, resolution integer) RETURNS SETOF h3index + AS $$ SELECT __h3_cell_to_children_aux($1, $2, -1) $$ LANGUAGE SQL; + COMMENT ON FUNCTION h3_cell_to_children_slow(index h3index, resolution integer) IS +'Slower version of H3ToChildren but allocates less memory'; +CREATE OR REPLACE FUNCTION h3_cell_to_children_slow(index h3index) RETURNS SETOF h3index + AS $$ SELECT __h3_cell_to_children_aux($1, -1, -1) $$ LANGUAGE SQL; + COMMENT ON FUNCTION h3_cell_to_children_slow(index h3index) IS +'Slower version of H3ToChildren but allocates less memory'; + + + +-- regions +ALTER FUNCTION h3_polyfill(exterior polygon, holes polygon[], resolution integer) RENAME TO h3_polygon_to_cells; +ALTER FUNCTION h3_set_to_multi_polygon(h3index[], OUT exterior polygon, OUT holes polygon[]) RENAME TO h3_cells_to_multi_polygon; + +-- edge +ALTER FUNCTION h3_indexes_are_neighbors(h3index, h3index) RENAME TO h3_are_neighbor_cells; +CREATE OR REPLACE FUNCTION + h3_are_neighbor_cells(origin h3index, destination h3index) RETURNS boolean +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; +ALTER FUNCTION h3_get_h3_unidirectional_edge(origin h3index, destination h3index) RENAME TO h3_cells_to_directed_edge; +ALTER FUNCTION h3_unidirectional_edge_is_valid(edge h3index) RENAME TO h3_is_valid_directed_edge; +ALTER FUNCTION h3_get_origin_h3_index_from_unidirectional_edge(edge h3index) RENAME TO h3_get_directed_edge_origin; +ALTER FUNCTION h3_get_destination_h3_index_from_unidirectional_edge(edge h3index) RENAME TO h3_get_directed_edge_destination; +ALTER FUNCTION h3_get_h3_indexes_from_unidirectional_edge(edge h3index, OUT origin h3index, OUT destination h3index) RENAME TO h3_directed_edge_to_cells; +ALTER FUNCTION h3_get_h3_unidirectional_edges_from_hexagon(h3index) RENAME TO h3_origin_to_directed_edges; +ALTER FUNCTION h3_get_h3_unidirectional_edge_boundary(edge h3index) RENAME TO h3_directed_edge_to_boundary; + +-- miscellaneous +ALTER FUNCTION h3_point_dist(a point, b point, unit text) RENAME TO h3_great_circle_distance; +ALTER FUNCTION h3_hex_area(resolution integer, unit text) RENAME TO h3_get_hexagon_area_avg; +DROP FUNCTION IF EXISTS h3_edge_length(resolution integer, unit text); +CREATE OR REPLACE FUNCTION + h3_get_hexagon_edge_length_avg(resolution integer, unit text DEFAULT 'km') RETURNS double precision +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_get_hexagon_edge_length_avg(integer, text) +IS 'Average hexagon edge length in (kilo)meters at the given resolution'; +ALTER FUNCTION h3_exact_edge_length(edge h3index, unit text) RENAME TO h3_edge_length; +ALTER FUNCTION h3_num_hexagons(resolution integer) RENAME TO h3_get_num_cells; +ALTER FUNCTION h3_get_res_0_indexes() RENAME TO h3_get_res_0_cells; +ALTER FUNCTION h3_get_pentagon_indexes(resolution integer) RENAME TO h3_get_pentagons; + +-- deprecated +DROP FUNCTION IF EXISTS h3_hex_area(integer, boolean); +DROP FUNCTION IF EXISTS h3_edge_length(integer, boolean); + + +-- copied from 07-vertex.sql +CREATE OR REPLACE FUNCTION + h3_cell_to_vertex(cell h3index, vertexNum integer) RETURNS h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_cell_to_vertex(cell h3index, vertexNum integer) +IS 'Returns a single vertex for a given cell, as an H3 index'; + +CREATE OR REPLACE FUNCTION + h3_cell_to_vertexes(cell h3index) RETURNS SETOF h3index +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_cell_to_vertexes(cell h3index) +IS 'Returns all vertexes for a given cell, as H3 indexes'; + +CREATE OR REPLACE FUNCTION + h3_vertex_to_lat_lng(vertex h3index) RETURNS point +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_vertex_to_lat_lng(vertex h3index) +IS 'Get the geocoordinates of an H3 vertex'; + +CREATE OR REPLACE FUNCTION + h3_is_valid_vertex(vertex h3index) RETURNS boolean +AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION + h3_is_valid_vertex(vertex h3index) +IS 'Whether the input is a valid H3 vertex'; diff --git a/h3/src/include/extension.in.h b/h3/src/include/extension.in.h index 30d851d8..fe577fa1 100644 --- a/h3/src/include/extension.in.h +++ b/h3/src/include/extension.in.h @@ -1,5 +1,5 @@ /* - * Copyright 2018-2020 Bytes & Brains + * Copyright 2018-2022 Bytes & Brains * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -75,15 +75,25 @@ Datum srf_return_h3_index_distances_from_user_fctx(PG_FUNCTION_ARGS); #define SRF_RETURN_H3_INDEX_DISTANCES_FROM_USER_FCTX() \ return srf_return_h3_index_distances_from_user_fctx(fcinfo) +/* use origin resolution minus one when no resolution is given */ +#define PG_GETARG_OPTIONAL_RES(n, cell, offset) \ + PG_NARGS() == (n + 1) ? PG_GETARG_INT32(1) : getResolution(cell) + offset + +/*error reporting*/ + +#define H3_ERROR(error, func) \ + if (error) ereport(ERROR, ( \ + errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION), \ + errmsg("%s error code: %i", func, error), \ + errhint("https://h3geo.org/docs/next/library/errors/#table-of-error-codes") \ + )) + #define ASSERT(condition, code, msg, ...) \ if (0 == (condition)) ereport(ERROR, ( \ errcode(code), \ errmsg(msg, ##__VA_ARGS__) \ )) -#define ASSERT_EXTERNAL(condition, msg, ...) \ - ASSERT(condition, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION, msg, ##__VA_ARGS__) - #define ENSURE_TYPEFUNC_COMPOSITE(x) \ ASSERT( \ x == TYPEFUNC_COMPOSITE, \ diff --git a/h3/src/lib/uniedges.c b/h3/src/lib/edge.c similarity index 50% rename from h3/src/lib/uniedges.c rename to h3/src/lib/edge.c index 3756bcd6..c1b0fbf7 100644 --- a/h3/src/lib/uniedges.c +++ b/h3/src/lib/edge.c @@ -1,5 +1,5 @@ /* - * Copyright 2018-2020 Bytes & Brains + * Copyright 2018-2022 Bytes & Brains * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,74 +23,86 @@ #include // Main H3 include #include "extension.h" -PG_FUNCTION_INFO_V1(h3_indexes_are_neighbors); -PG_FUNCTION_INFO_V1(h3_get_h3_unidirectional_edge); -PG_FUNCTION_INFO_V1(h3_unidirectional_edge_is_valid); -PG_FUNCTION_INFO_V1(h3_get_origin_h3_index_from_unidirectional_edge); -PG_FUNCTION_INFO_V1(h3_get_destination_h3_index_from_unidirectional_edge); -PG_FUNCTION_INFO_V1(h3_get_h3_indexes_from_unidirectional_edge); -PG_FUNCTION_INFO_V1(h3_get_h3_unidirectional_edges_from_hexagon); -PG_FUNCTION_INFO_V1(h3_get_h3_unidirectional_edge_boundary); +PG_FUNCTION_INFO_V1(h3_are_neighbor_cells); +PG_FUNCTION_INFO_V1(h3_cells_to_directed_edge); +PG_FUNCTION_INFO_V1(h3_is_valid_directed_edge); +PG_FUNCTION_INFO_V1(h3_get_directed_edge_origin); +PG_FUNCTION_INFO_V1(h3_get_directed_edge_destination); +PG_FUNCTION_INFO_V1(h3_directed_edge_to_cells); +PG_FUNCTION_INFO_V1(h3_origin_to_directed_edges); +PG_FUNCTION_INFO_V1(h3_directed_edge_to_boundary); -/* Returns whether or not the provided H3Indexes are neighbors */ +/* Returns whether or not the provided H3 cell indexes are neighbors. */ Datum -h3_indexes_are_neighbors(PG_FUNCTION_ARGS) +h3_are_neighbor_cells(PG_FUNCTION_ARGS) { + int neighboring; + H3Error error; H3Index origin = PG_GETARG_H3INDEX(0); H3Index destination = PG_GETARG_H3INDEX(1); - bool areNeighbors = h3IndexesAreNeighbors(origin, destination); - PG_RETURN_BOOL(areNeighbors); + error = areNeighborCells(origin, destination, &neighboring); + H3_ERROR(error, "areNeighborCells"); + + PG_RETURN_BOOL(neighboring); } -/* - * Returns a unidirectional edge H3 index based on the provided origin and - * destination - */ +/* Returns a unidirectional edge H3 index based on the provided origin and destination. */ Datum -h3_get_h3_unidirectional_edge(PG_FUNCTION_ARGS) +h3_cells_to_directed_edge(PG_FUNCTION_ARGS) { + H3Index edge; + H3Error error; H3Index origin = PG_GETARG_H3INDEX(0); H3Index destination = PG_GETARG_H3INDEX(1); - H3Index edge = getH3UnidirectionalEdge(origin, destination); - ASSERT_EXTERNAL(edge, "Can only create edges between neighbouring indexes"); + error = cellsToDirectedEdge(origin, destination, &edge); + H3_ERROR(error, "cellsToDirectedEdge"); + PG_RETURN_H3INDEX(edge); } -/* Determines if the provided H3Index is a valid unidirectional edge index */ +/* Determines if the provided H3Index is a valid unidirectional edge index. */ Datum -h3_unidirectional_edge_is_valid(PG_FUNCTION_ARGS) +h3_is_valid_directed_edge(PG_FUNCTION_ARGS) { H3Index edge = PG_GETARG_H3INDEX(0); - bool isValid = h3UnidirectionalEdgeIsValid(edge); + int valid = isValidDirectedEdge(edge); - PG_RETURN_BOOL(isValid); + PG_RETURN_BOOL(valid); } -/* Returns the origin hexagon from the unidirectional edge H3Index */ +/* Returns the origin hexagon from the unidirectional edge H3Index. */ Datum -h3_get_origin_h3_index_from_unidirectional_edge(PG_FUNCTION_ARGS) +h3_get_directed_edge_origin(PG_FUNCTION_ARGS) { + H3Index origin; + H3Error error; H3Index edge = PG_GETARG_H3INDEX(0); - H3Index origin = getOriginH3IndexFromUnidirectionalEdge(edge); + + error = getDirectedEdgeOrigin(edge, &origin); + H3_ERROR(error, "getDirectedEdgeOrigin"); PG_RETURN_H3INDEX(origin); } -/* Returns the destination hexagon from the unidirectional edge H3Index */ +/* Returns the destination hexagon from the unidirectional edge H3Index. */ Datum -h3_get_destination_h3_index_from_unidirectional_edge(PG_FUNCTION_ARGS) +h3_get_directed_edge_destination(PG_FUNCTION_ARGS) { + H3Index destination; + H3Error error; H3Index edge = PG_GETARG_H3INDEX(0); - H3Index destination = getDestinationH3IndexFromUnidirectionalEdge(edge); + + error = getDirectedEdgeDestination(edge, &destination); + H3_ERROR(error, "getDirectedEdgeDestination"); PG_RETURN_H3INDEX(destination); } -/* Returns the origin, destination pair of hexagon IDs for the given edge ID */ +/* Returns the origin, destination pair of hexagon IDs for the given edge ID. */ Datum -h3_get_h3_indexes_from_unidirectional_edge(PG_FUNCTION_ARGS) +h3_directed_edge_to_cells(PG_FUNCTION_ARGS) { TupleDesc tuple_desc; Datum values[2]; @@ -98,25 +110,27 @@ h3_get_h3_indexes_from_unidirectional_edge(PG_FUNCTION_ARGS) HeapTuple tuple; Datum result; + H3Error error; H3Index edge = PG_GETARG_H3INDEX(0); - H3Index *indexes = palloc(sizeof(H3Index) * 2); + H3Index *cells = palloc(2 * sizeof(H3Index)); - getH3IndexesFromUnidirectionalEdge(edge, indexes); + error = directedEdgeToCells(edge, cells); + H3_ERROR(error, "directedEdgeToCells"); ENSURE_TYPEFUNC_COMPOSITE(get_call_result_type(fcinfo, NULL, &tuple_desc)); - tuple_desc = BlessTupleDesc(tuple_desc); - values[0] = H3IndexGetDatum(indexes[0]); - values[1] = H3IndexGetDatum(indexes[1]); + values[0] = H3IndexGetDatum(cells[0]); + values[1] = H3IndexGetDatum(cells[1]); + tuple_desc = BlessTupleDesc(tuple_desc); tuple = heap_form_tuple(tuple_desc, values, nulls); result = HeapTupleGetDatum(tuple); PG_RETURN_DATUM(result); } -/* Provides all of the unidirectional edges from the current H3Index */ +/* Provides all of the unidirectional edges from the current H3Index. */ Datum -h3_get_h3_unidirectional_edges_from_hexagon(PG_FUNCTION_ARGS) +h3_origin_to_directed_edges(PG_FUNCTION_ARGS) { if (SRF_IS_FIRSTCALL()) { @@ -124,41 +138,44 @@ h3_get_h3_unidirectional_edges_from_hexagon(PG_FUNCTION_ARGS) MemoryContext oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); + int max = 6; + H3Error error; H3Index origin = PG_GETARG_H3INDEX(0); - int maxSize = 6; - H3Index *edges = palloc(sizeof(H3Index) * maxSize); + H3Index *edges = palloc(max * sizeof(H3Index)); - getH3UnidirectionalEdgesFromHexagon(origin, edges); + error = originToDirectedEdges(origin, edges); + H3_ERROR(error, "originToDirectedEdges"); funcctx->user_fctx = edges; - funcctx->max_calls = maxSize; + funcctx->max_calls = max; MemoryContextSwitchTo(oldcontext); } SRF_RETURN_H3_INDEXES_FROM_USER_FCTX(); } -/* Provides the coordinates defining the unidirectional edge */ +/* Provides the coordinates defining the unidirectional edge. */ Datum -h3_get_h3_unidirectional_edge_boundary(PG_FUNCTION_ARGS) +h3_directed_edge_to_boundary(PG_FUNCTION_ARGS) { - H3Index edge = PG_GETARG_H3INDEX(0); - - GeoBoundary geoBoundary; + CellBoundary boundary; POLYGON *polygon; int size; + H3Error error; + H3Index edge = PG_GETARG_H3INDEX(0); - getH3UnidirectionalEdgeBoundary(edge, &geoBoundary); + error = directedEdgeToBoundary(edge, &boundary); + H3_ERROR(error, "directedEdgeToBoundary"); - size = offsetof(POLYGON, p[0]) +sizeof(polygon->p[0]) * geoBoundary.numVerts; + size = offsetof(POLYGON, p[0]) +sizeof(polygon->p[0]) * boundary.numVerts; polygon = (POLYGON *) palloc(size); SET_VARSIZE(polygon, size); - polygon->npts = geoBoundary.numVerts; + polygon->npts = boundary.numVerts; - for (int v = 0; v < geoBoundary.numVerts; v++) + for (int v = 0; v < boundary.numVerts; v++) { - polygon->p[v].x = radsToDegs(geoBoundary.verts[v].lat); - polygon->p[v].y = radsToDegs(geoBoundary.verts[v].lon); + polygon->p[v].x = radsToDegs(boundary.verts[v].lat); + polygon->p[v].y = radsToDegs(boundary.verts[v].lng); } PG_RETURN_POLYGON_P(polygon); } diff --git a/h3/src/lib/hierarchy.c b/h3/src/lib/hierarchy.c index 5fde642d..0efd3ba0 100644 --- a/h3/src/lib/hierarchy.c +++ b/h3/src/lib/hierarchy.c @@ -1,5 +1,5 @@ /* - * Copyright 2018-2020 Bytes & Brains + * Copyright 2018-2022 Bytes & Brains * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,52 +23,38 @@ #include // Main H3 include #include "extension.h" -PG_FUNCTION_INFO_V1(h3_to_parent); -PG_FUNCTION_INFO_V1(h3_to_children); -PG_FUNCTION_INFO_V1(h3_to_center_child); -PG_FUNCTION_INFO_V1(h3_compact); -PG_FUNCTION_INFO_V1(h3_uncompact); +PG_FUNCTION_INFO_V1(h3_cell_to_parent); +PG_FUNCTION_INFO_V1(h3_cell_to_children); +PG_FUNCTION_INFO_V1(h3_cell_to_center_child); +PG_FUNCTION_INFO_V1(h3_compact_cells); +PG_FUNCTION_INFO_V1(h3_uncompact_cells); /* Returns the parent (coarser) index containing given index */ Datum -h3_to_parent(PG_FUNCTION_ARGS) +h3_cell_to_parent(PG_FUNCTION_ARGS) { H3Index parent; - - /* get function arguments */ + H3Error error; H3Index origin = PG_GETARG_H3INDEX(0); - int parentRes = PG_GETARG_INT32(1); - int childRes = h3GetResolution(origin); - - if (parentRes == -1) - { - /* resolution parameter not set */ - parentRes = childRes - 1; - } - ASSERT( - parentRes <= childRes, - ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE, - "Requested parent resolution %d is finer than input index resolution %d", - parentRes, childRes - ); + int resolution = PG_GETARG_OPTIONAL_RES(1, origin, -1); - /* get parent */ - parent = h3ToParent(origin, parentRes); - ASSERT_EXTERNAL(parent, "Could not generate parent"); + error = cellToParent(origin, resolution, &parent); + H3_ERROR(error, "cellToParent"); PG_RETURN_H3INDEX(parent); } /* Returns children indexes at given resolution (or next resolution if none given) */ Datum -h3_to_children(PG_FUNCTION_ARGS) +h3_cell_to_children(PG_FUNCTION_ARGS) { /* stuff done only on the first call of the function */ if (SRF_IS_FIRSTCALL()) { - int maxSize; - int size; + int64_t max; + int64_t size; H3Index *children; + H3Error error; /* create a function context for cross-call persistence */ FuncCallContext *funcctx = SRF_FIRSTCALL_INIT(); @@ -81,33 +67,24 @@ h3_to_children(PG_FUNCTION_ARGS) /* ensure valid resolution target */ H3Index origin = PG_GETARG_H3INDEX(0); - int resolution = PG_GETARG_INT32(1); + int resolution = PG_GETARG_OPTIONAL_RES(1, origin, 1); - if (resolution == -1) - { - /* resolution parameter not set */ - resolution = h3GetResolution(origin) + 1; - } - ASSERT( - resolution <= MAX_H3_RES, - ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE, - "Maximum resolution exceeded" - ); + error = cellToChildrenSize(origin, resolution, &max); + H3_ERROR(error, "cellToChildrenSize"); - maxSize = maxH3ToChildrenSize(origin, resolution); - size = maxSize * sizeof(H3Index); + size = max * sizeof(H3Index); ASSERT( AllocSizeIsValid(size), ERRCODE_OUT_OF_MEMORY, - "Cannot allocate necessary amount memory, try using h3_to_children_slow()" + "Cannot allocate necessary amount memory, try using h3_cell_to_children_slow()" ); - children = palloc(size); - h3ToChildren(origin, resolution, children); - ASSERT_EXTERNAL(*children, "Could not generate children"); + + error = cellToChildren(origin, resolution, children); + H3_ERROR(error, "cellToChildren"); funcctx->user_fctx = children; - funcctx->max_calls = maxSize; + funcctx->max_calls = max; /* END One-time setup code */ @@ -119,40 +96,25 @@ h3_to_children(PG_FUNCTION_ARGS) /* Returns the center child (finer) index contained by input index at given resolution */ Datum -h3_to_center_child(PG_FUNCTION_ARGS) +h3_cell_to_center_child(PG_FUNCTION_ARGS) { H3Index child; - - /* get function arguments */ + H3Error error; H3Index origin = PG_GETARG_H3INDEX(0); - int childRes = PG_GETARG_INT32(1); - int parentRes = h3GetResolution(origin); + int resolution = PG_GETARG_OPTIONAL_RES(1, origin, 1); - if (childRes == -1) - { - /* resolution parameter not set */ - childRes = parentRes + 1; - } - ASSERT( - childRes >= parentRes, - ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE, - "Requested child resolution %d is coarser than input index resolution %d", - childRes, parentRes - ); - - /* get child */ - child = h3ToCenterChild(origin, childRes); - ASSERT_EXTERNAL(child, "Could not generate center child"); + error = cellToCenterChild(origin, resolution, &child); + H3_ERROR(error, "cellToCenterChild"); PG_RETURN_H3INDEX(child); } Datum -h3_compact(PG_FUNCTION_ARGS) +h3_compact_cells(PG_FUNCTION_ARGS) { if (SRF_IS_FIRSTCALL()) { - int result; + H3Error error; Datum value; bool isnull; int i = 0; @@ -162,10 +124,10 @@ h3_compact(PG_FUNCTION_ARGS) MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); ArrayType *array = PG_GETARG_ARRAYTYPE_P(0); - int maxSize = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array)); + int max = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array)); ArrayIterator iterator = array_create_iterator(array, 0, NULL); - H3Index *h3set = palloc(sizeof(H3Index) * maxSize); - H3Index *compactedSet = palloc0(maxSize * sizeof(H3Index)); + H3Index *h3set = palloc(max * sizeof(H3Index)); + H3Index *compactedSet = palloc0(max * sizeof(H3Index)); /* Extract data from array into h3set, and wipe compactedSet memory */ while (array_iterate(iterator, &value, &isnull)) @@ -173,11 +135,11 @@ h3_compact(PG_FUNCTION_ARGS) h3set[i++] = DatumGetH3Index(value); } - result = compact(h3set, compactedSet, maxSize); - ASSERT_EXTERNAL(result == 0, "Could not compact input array"); + error = compactCells(h3set, compactedSet, max); + H3_ERROR(error, "compactCells"); funcctx->user_fctx = compactedSet; - funcctx->max_calls = maxSize; + funcctx->max_calls = max; MemoryContextSwitchTo(oldcontext); } @@ -185,15 +147,16 @@ h3_compact(PG_FUNCTION_ARGS) } Datum -h3_uncompact(PG_FUNCTION_ARGS) +h3_uncompact_cells(PG_FUNCTION_ARGS) { if (SRF_IS_FIRSTCALL()) { - int result; + H3Error error; + int resolution; Datum value; bool isnull; int i = 0; - int maxSize; + int64_t max; H3Index *uncompactedSet; FuncCallContext *funcctx = SRF_FIRSTCALL_INIT(); @@ -201,27 +164,33 @@ h3_uncompact(PG_FUNCTION_ARGS) MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); ArrayType *array = PG_GETARG_ARRAYTYPE_P(0); - int resolution = PG_GETARG_INT32(1); - int arrayLength = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array)); + int numCompacted = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array)); ArrayIterator iterator = array_create_iterator(array, 0, NULL); - H3Index *h3set = palloc(sizeof(H3Index) * arrayLength); + H3Index *compactedSet = palloc(numCompacted * sizeof(H3Index)); - /* Extract data from array into h3set, and wipe compactedSet memory */ + /* + * Extract data from array into compactedSet, and wipe compactedSet + * memory + */ while (array_iterate(iterator, &value, &isnull)) { - h3set[i++] = DatumGetH3Index(value); + compactedSet[i++] = DatumGetH3Index(value); } - if (resolution == -1) + if (PG_NARGS() == 2) + { + resolution = PG_GETARG_INT32(1); + } + else { /* resolution parameter not set */ int highRes = 0; /* Find highest resolution in the given set */ - for (int i = 0; i < arrayLength; i++) + for (int i = 0; i < numCompacted; i++) { - int curRes = h3GetResolution(h3set[i]); + int curRes = getResolution(compactedSet[i]); if (curRes > highRes) highRes = curRes; @@ -235,16 +204,16 @@ h3_uncompact(PG_FUNCTION_ARGS) resolution = (highRes == 15 ? highRes : highRes + 1); } - maxSize = maxUncompactSize(h3set, arrayLength, resolution); - uncompactedSet = palloc0(maxSize * sizeof(H3Index)); + error = uncompactCellsSize(compactedSet, numCompacted, resolution, &max); + H3_ERROR(error, "uncompactCellsSize"); - result = uncompact(h3set, arrayLength, uncompactedSet, maxSize, resolution); - ASSERT_EXTERNAL(result == 0, - "Could not uncompact input array. This may be caused by choosing a lower resolution than some of the indexes" - ); + uncompactedSet = palloc0(max * sizeof(H3Index)); + + error = uncompactCells(compactedSet, numCompacted, uncompactedSet, max, resolution); + H3_ERROR(error, "uncompactCells"); funcctx->user_fctx = uncompactedSet; - funcctx->max_calls = maxSize; + funcctx->max_calls = max; MemoryContextSwitchTo(oldcontext); } diff --git a/h3/src/lib/indexing.c b/h3/src/lib/indexing.c index adfd1c40..dde0e374 100644 --- a/h3/src/lib/indexing.c +++ b/h3/src/lib/indexing.c @@ -1,5 +1,5 @@ /* - * Copyright 2018-2020 Bytes & Brains + * Copyright 2018-2022 Bytes & Brains * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,77 +22,89 @@ #include "extension.h" #include -PG_FUNCTION_INFO_V1(h3_geo_to_h3); -PG_FUNCTION_INFO_V1(h3_to_geo); -PG_FUNCTION_INFO_V1(h3_to_geo_boundary); +PG_FUNCTION_INFO_V1(h3_lat_lng_to_cell); +PG_FUNCTION_INFO_V1(h3_cell_to_lat_lng); +PG_FUNCTION_INFO_V1(h3_cell_to_boundary); /* Indexes the location at the specified resolution */ Datum -h3_geo_to_h3(PG_FUNCTION_ARGS) +h3_lat_lng_to_cell(PG_FUNCTION_ARGS) { - Point *geo = PG_GETARG_POINT_P(0); + H3Index cell; + H3Error error; + LatLng location; + Point *point = PG_GETARG_POINT_P(0); int resolution = PG_GETARG_INT32(1); - H3Index idx; - GeoCoord location; - if (h3_guc_strict) { - ASSERT_EXTERNAL(geo->x >= -180 && geo->x <= 180, "Longitude must be between -180 and 180 degrees inclusive, but got %f.", geo->x); - ASSERT_EXTERNAL(geo->y >= -90 && geo->y <= 90, "Latitude must be between -90 and 90 degrees inclusive, but got %f.", geo->y); + ASSERT( + point->x >= -180 && point->x <= 180, + ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE, + "Longitude must be between -180 and 180 degrees inclusive, but got %f.", + point->x + ); + ASSERT( + point->y >= -90 && point->y <= 90, + ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE, + "Latitude must be between -90 and 90 degrees inclusive, but got %f.", + point->y + ); } - location.lon = degsToRads(geo->x); - location.lat = degsToRads(geo->y); + location.lng = degsToRads(point->x); + location.lat = degsToRads(point->y); - idx = geoToH3(&location, resolution); - ASSERT_EXTERNAL(idx, "Indexing failed at specified resolution."); + error = latLngToCell(&location, resolution, &cell); + H3_ERROR(error, "latLngToCell"); - PG_FREE_IF_COPY(geo, 0); - PG_RETURN_H3INDEX(idx); + PG_FREE_IF_COPY(point, 0); + PG_RETURN_H3INDEX(cell); } /* Finds the centroid of the index */ Datum -h3_to_geo(PG_FUNCTION_ARGS) +h3_cell_to_lat_lng(PG_FUNCTION_ARGS) { - H3Index idx = PG_GETARG_H3INDEX(0); - - Point *geo = palloc(sizeof(Point)); - GeoCoord center; + LatLng center; + H3Error error; + Point *point = palloc(sizeof(Point)); + H3Index cell = PG_GETARG_H3INDEX(0); - h3ToGeo(idx, ¢er); + error = cellToLatLng(cell, ¢er); + H3_ERROR(error, "cellToLatLng"); - geo->x = radsToDegs(center.lon); - geo->y = radsToDegs(center.lat); + point->x = radsToDegs(center.lng); + point->y = radsToDegs(center.lat); - PG_RETURN_POINT_P(geo); + PG_RETURN_POINT_P(point); } /* Finds the boundary of the index */ Datum -h3_to_geo_boundary(PG_FUNCTION_ARGS) +h3_cell_to_boundary(PG_FUNCTION_ARGS) { - H3Index idx = PG_GETARG_H3INDEX(0); + H3Index cell = PG_GETARG_H3INDEX(0); bool extend = PG_GETARG_BOOL(1); double delta, firstLon, lon, lat; - + H3Error error; int size; POLYGON *polygon; - GeoBoundary boundary; + CellBoundary boundary; - h3ToGeoBoundary(idx, &boundary); + error = cellToBoundary(cell, &boundary); + H3_ERROR(error, "cellToBoundary"); size = offsetof(POLYGON, p) +sizeof(polygon->p[0]) * boundary.numVerts; polygon = (POLYGON *) palloc(size); SET_VARSIZE(polygon, size); polygon->npts = boundary.numVerts; - firstLon = boundary.verts[0].lon; + firstLon = boundary.verts[0].lng; if (firstLon < 0) { delta = -2 * M_PI; @@ -104,7 +116,7 @@ h3_to_geo_boundary(PG_FUNCTION_ARGS) for (int v = 0; v < boundary.numVerts; v++) { - lon = boundary.verts[v].lon; + lon = boundary.verts[v].lng; lat = boundary.verts[v].lat; /* check if different sign */ diff --git a/h3/src/lib/inspection.c b/h3/src/lib/inspection.c index 3bc14ed9..39811ccc 100644 --- a/h3/src/lib/inspection.c +++ b/h3/src/lib/inspection.c @@ -1,5 +1,5 @@ /* - * Copyright 2018-2020 Bytes & Brains + * Copyright 2018-2022 Bytes & Brains * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,40 +24,40 @@ #include "extension.h" PG_FUNCTION_INFO_V1(h3_get_resolution); -PG_FUNCTION_INFO_V1(h3_get_base_cell); -PG_FUNCTION_INFO_V1(h3_is_valid); +PG_FUNCTION_INFO_V1(h3_get_base_cell_number); +PG_FUNCTION_INFO_V1(h3_is_valid_cell); PG_FUNCTION_INFO_V1(h3_is_res_class_iii); PG_FUNCTION_INFO_V1(h3_is_pentagon); -PG_FUNCTION_INFO_V1(h3_get_faces); +PG_FUNCTION_INFO_V1(h3_get_icosahedron_faces); /* Returns the resolution of the index */ Datum h3_get_resolution(PG_FUNCTION_ARGS) { H3Index hex = PG_GETARG_H3INDEX(0); - int resolution = h3GetResolution(hex); + int32_t resolution = getResolution(hex); PG_RETURN_INT32(resolution); } /* Returns the base cell number of the index */ Datum -h3_get_base_cell(PG_FUNCTION_ARGS) +h3_get_base_cell_number(PG_FUNCTION_ARGS) { H3Index hex = PG_GETARG_H3INDEX(0); - int base_cell_number = h3GetBaseCell(hex); + int32_t result = getBaseCellNumber(hex); - PG_RETURN_INT32(base_cell_number); + PG_RETURN_INT32(result); } /* Returns true if this is a valid H3 index */ Datum -h3_is_valid(PG_FUNCTION_ARGS) +h3_is_valid_cell(PG_FUNCTION_ARGS) { H3Index hex = PG_GETARG_H3INDEX(0); - bool isValid = h3IsValid(hex); + bool result = isValidCell(hex); - PG_RETURN_BOOL(isValid); + PG_RETURN_BOOL(result); } /* Returns true if this index has a resolution with Class III orientation */ @@ -65,9 +65,9 @@ Datum h3_is_res_class_iii(PG_FUNCTION_ARGS) { H3Index hex = PG_GETARG_H3INDEX(0); - bool isResClassIII = h3IsResClassIII(hex); + bool result = isResClassIII(hex); - PG_RETURN_BOOL(isResClassIII); + PG_RETURN_BOOL(result); } /* Returns true if this hex represents a pentagonal cell */ @@ -75,32 +75,38 @@ Datum h3_is_pentagon(PG_FUNCTION_ARGS) { H3Index hex = PG_GETARG_H3INDEX(0); - bool isPentagon = h3IsPentagon(hex); + bool result = isPentagon(hex); - PG_RETURN_BOOL(isPentagon); + PG_RETURN_BOOL(result); } /* Find all icosahedron faces intersected by a given H3 index */ Datum -h3_get_faces(PG_FUNCTION_ARGS) +h3_get_icosahedron_faces(PG_FUNCTION_ARGS) { Oid elmtype = INT4OID; int16 elmlen; bool elmbyval; char elmalign; - H3Index hex = PG_GETARG_H3INDEX(0); - int maxFaces = maxFaceCount(hex); - + int *faces; + Datum *elements; + int maxFaces; ArrayType *result; - int nelems = 0; + H3Error error; + H3Index hex = PG_GETARG_H3INDEX(0); + + error = maxFaceCount(hex, &maxFaces); + H3_ERROR(error, "maxFaceCount"); + /* get the faces */ - int *faces = palloc(maxFaces * sizeof(int)); - Datum *elements = palloc(maxFaces * sizeof(Datum)); + faces = palloc(maxFaces * sizeof(int)); + elements = palloc(maxFaces * sizeof(Datum)); - h3GetFaces(hex, faces); + error = getIcosahedronFaces(hex, faces); + H3_ERROR(error, "getIcosahedronFaces"); for (int i = 0; i < maxFaces; i++) { diff --git a/h3/src/lib/miscellaneous.c b/h3/src/lib/miscellaneous.c index d0456316..b5eaba58 100644 --- a/h3/src/lib/miscellaneous.c +++ b/h3/src/lib/miscellaneous.c @@ -1,5 +1,5 @@ /* - * Copyright 2018-2019 Bytes & Brains + * Copyright 2018-2022 Bytes & Brains * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,58 +23,32 @@ #include // Main H3 include #include "extension.h" -PG_FUNCTION_INFO_V1(h3_point_dist); -PG_FUNCTION_INFO_V1(h3_hex_area); +PG_FUNCTION_INFO_V1(h3_get_hexagon_area_avg); PG_FUNCTION_INFO_V1(h3_cell_area); +PG_FUNCTION_INFO_V1(h3_get_hexagon_edge_length_avg); PG_FUNCTION_INFO_V1(h3_edge_length); -PG_FUNCTION_INFO_V1(h3_exact_edge_length); -PG_FUNCTION_INFO_V1(h3_num_hexagons); -PG_FUNCTION_INFO_V1(h3_get_res_0_indexes); -PG_FUNCTION_INFO_V1(h3_get_pentagon_indexes); - -/* The great circle distance in radians between two spherical coordinates */ -Datum -h3_point_dist(PG_FUNCTION_ARGS) -{ - Point *aPoint = PG_GETARG_POINT_P(0); - Point *bPoint = PG_GETARG_POINT_P(1); - char *unit = text_to_cstring(PG_GETARG_TEXT_PP(2)); - - GeoCoord a; - GeoCoord b; - double distance; - - a.lon = degsToRads(aPoint->x); - a.lat = degsToRads(aPoint->y); - b.lon = degsToRads(bPoint->x); - b.lat = degsToRads(bPoint->y); - - if (strcmp(unit, "rads") == 0) - distance = pointDistRads(&a, &b); - else if (strcmp(unit, "km") == 0) - distance = pointDistKm(&a, &b); - else if (strcmp(unit, "m") == 0) - distance = pointDistM(&a, &b); - else - ASSERT_EXTERNAL(0, "Unit must be m, km or rads."); - - PG_RETURN_FLOAT8(distance); -} +PG_FUNCTION_INFO_V1(h3_get_num_cells); +PG_FUNCTION_INFO_V1(h3_get_res_0_cells); +PG_FUNCTION_INFO_V1(h3_get_pentagons); +PG_FUNCTION_INFO_V1(h3_great_circle_distance); /* Average hexagon area in square (kilo)meters at the given resolution */ Datum -h3_hex_area(PG_FUNCTION_ARGS) +h3_get_hexagon_area_avg(PG_FUNCTION_ARGS) { int resolution = PG_GETARG_INT32(0); char *unit = text_to_cstring(PG_GETARG_TEXT_PP(1)); double area; + H3Error error; if (strcmp(unit, "km") == 0) - area = hexAreaKm2(resolution); + error = getHexagonAreaAvgKm2(resolution, &area); else if (strcmp(unit, "m") == 0) - area = hexAreaM2(resolution); + error = getHexagonAreaAvgM2(resolution, &area); else - ASSERT_EXTERNAL(0, "Unit must be m or km."); + ASSERT(0, ERRCODE_INVALID_PARAMETER_VALUE, "Unit must be m or km."); + + H3_ERROR(error, "getHexagonAreaAvgM2"); PG_RETURN_FLOAT8(area); } @@ -86,70 +60,107 @@ h3_cell_area(PG_FUNCTION_ARGS) H3Index cell = PG_GETARG_H3INDEX(0); char *unit = text_to_cstring(PG_GETARG_TEXT_PP(1)); double area; + H3Error error; if (strcmp(unit, "rads^2") == 0) - area = cellAreaRads2(cell); + { + error = cellAreaRads2(cell, &area); + H3_ERROR(error, "cellAreaRads2"); + } else if (strcmp(unit, "km^2") == 0) - area = cellAreaKm2(cell); + { + error = cellAreaKm2(cell, &area); + H3_ERROR(error, "cellAreaKm2"); + } else if (strcmp(unit, "m^2") == 0) - area = cellAreaM2(cell); + { + error = cellAreaM2(cell, &area); + H3_ERROR(error, "cellAreaM2"); + } else - ASSERT_EXTERNAL(0, "Unit must be m^2, km^2 or rads^2."); + { + ASSERT(0, ERRCODE_INVALID_PARAMETER_VALUE, "Unit must be m^2, km^2 or rads^2."); + } PG_RETURN_FLOAT8(area); } /* Average hexagon edge length in (kilo)meters at the given resolution */ Datum -h3_edge_length(PG_FUNCTION_ARGS) +h3_get_hexagon_edge_length_avg(PG_FUNCTION_ARGS) { int resolution = PG_GETARG_INT32(0); char *unit = text_to_cstring(PG_GETARG_TEXT_PP(1)); double length; + H3Error error; if (strcmp(unit, "km") == 0) - length = edgeLengthKm(resolution); + { + error = getHexagonEdgeLengthAvgKm(resolution, &length); + H3_ERROR(error, "getHexagonEdgeLengthAvgKm"); + } else if (strcmp(unit, "m") == 0) - length = edgeLengthM(resolution); + { + error = getHexagonEdgeLengthAvgM(resolution, &length); + H3_ERROR(error, "getHexagonEdgeLengthAvgM"); + } else - ASSERT_EXTERNAL(0, "Unit must be m or km."); + { + ASSERT(0, ERRCODE_INVALID_PARAMETER_VALUE, "Unit must be m or km."); + } + PG_RETURN_FLOAT8(length); } /* Exact length for a specific unidirectional edge */ Datum -h3_exact_edge_length(PG_FUNCTION_ARGS) +h3_edge_length(PG_FUNCTION_ARGS) { H3Index edge = PG_GETARG_H3INDEX(0); char *unit = text_to_cstring(PG_GETARG_TEXT_PP(1)); double length; + H3Error error; if (strcmp(unit, "rads") == 0) - length = exactEdgeLengthRads(edge); + { + error = edgeLengthRads(edge, &length); + H3_ERROR(error, "edgeLengthRads"); + } else if (strcmp(unit, "km") == 0) - length = exactEdgeLengthKm(edge); + { + error = edgeLengthKm(edge, &length); + H3_ERROR(error, "edgeLengthKm"); + } else if (strcmp(unit, "m") == 0) - length = exactEdgeLengthM(edge); + { + error = edgeLengthM(edge, &length); + H3_ERROR(error, "edgeLengthM"); + } else - ASSERT_EXTERNAL(0, "Unit must be m, km or rads."); + { + ASSERT(0, ERRCODE_INVALID_PARAMETER_VALUE, "Unit must be m, km or rads."); + } PG_RETURN_FLOAT8(length); } /* Number of unique H3 indexes at the given resolution */ Datum -h3_num_hexagons(PG_FUNCTION_ARGS) +h3_get_num_cells(PG_FUNCTION_ARGS) { + int64_t cells; int resolution = PG_GETARG_INT32(0); - unsigned long long retVal = numHexagons(resolution); + H3Error error = getNumCells(resolution, &cells); + + H3_ERROR(error, "getNumCells"); - PG_RETURN_INT64(retVal); + PG_RETURN_INT64(cells); } /* Provides all resolution 0 indexes */ Datum -h3_get_res_0_indexes(PG_FUNCTION_ARGS) +h3_get_res_0_cells(PG_FUNCTION_ARGS) { if (SRF_IS_FIRSTCALL()) { @@ -157,10 +168,12 @@ h3_get_res_0_indexes(PG_FUNCTION_ARGS) MemoryContext oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); - int count = res0IndexCount(); - H3Index *indexes = palloc(sizeof(H3Index) * count); + H3Error error; + int count = res0CellCount(); + H3Index *indexes = palloc(count * sizeof(H3Index)); - getRes0Indexes(indexes); + error = getRes0Cells(indexes); + H3_ERROR(error, "getRes0Cells"); funcctx->user_fctx = indexes; funcctx->max_calls = count; @@ -172,7 +185,7 @@ h3_get_res_0_indexes(PG_FUNCTION_ARGS) /* All the pentagon H3 indexes at the specified resolution */ Datum -h3_get_pentagon_indexes(PG_FUNCTION_ARGS) +h3_get_pentagons(PG_FUNCTION_ARGS) { if (SRF_IS_FIRSTCALL()) { @@ -180,11 +193,13 @@ h3_get_pentagon_indexes(PG_FUNCTION_ARGS) MemoryContext oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); + H3Error error; int resolution = PG_GETARG_INT32(0); - int count = pentagonIndexCount(); - H3Index *indexes = palloc(sizeof(H3Index) * count); + int count = pentagonCount(); + H3Index *indexes = palloc(count * sizeof(H3Index)); - getPentagonIndexes(resolution, indexes); + error = getPentagons(resolution, indexes); + H3_ERROR(error, "getPentagons"); funcctx->user_fctx = indexes; funcctx->max_calls = count; @@ -193,3 +208,32 @@ h3_get_pentagon_indexes(PG_FUNCTION_ARGS) SRF_RETURN_H3_INDEXES_FROM_USER_FCTX(); } + +/* The great circle distance in radians between two spherical coordinates */ +Datum +h3_great_circle_distance(PG_FUNCTION_ARGS) +{ + Point *aPoint = PG_GETARG_POINT_P(0); + Point *bPoint = PG_GETARG_POINT_P(1); + char *unit = text_to_cstring(PG_GETARG_TEXT_PP(2)); + + LatLng a; + LatLng b; + double distance; + + a.lng = degsToRads(aPoint->x); + a.lat = degsToRads(aPoint->y); + b.lng = degsToRads(bPoint->x); + b.lat = degsToRads(bPoint->y); + + if (strcmp(unit, "rads") == 0) + distance = greatCircleDistanceRads(&a, &b); + else if (strcmp(unit, "km") == 0) + distance = greatCircleDistanceKm(&a, &b); + else if (strcmp(unit, "m") == 0) + distance = greatCircleDistanceM(&a, &b); + else + ASSERT(0, ERRCODE_INVALID_PARAMETER_VALUE, "Unit must be m, km or rads."); + + PG_RETURN_FLOAT8(distance); +} diff --git a/h3/src/lib/opclass_btree.c b/h3/src/lib/opclass_btree.c index 378e3843..e16d2ba6 100644 --- a/h3/src/lib/opclass_btree.c +++ b/h3/src/lib/opclass_btree.c @@ -1,5 +1,5 @@ /* - * Copyright 2018-2020 Bytes & Brains + * Copyright 2018-2022 Bytes & Brains * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/h3/src/lib/opclass_hash.c b/h3/src/lib/opclass_hash.c index 0d4580b5..51588aed 100644 --- a/h3/src/lib/opclass_hash.c +++ b/h3/src/lib/opclass_hash.c @@ -1,5 +1,5 @@ /* - * Copyright 2018-2020 Bytes & Brains + * Copyright 2018-2022 Bytes & Brains * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,7 +37,7 @@ Datum h3index_hash_extended(PG_FUNCTION_ARGS) { H3Index index = PG_GETARG_H3INDEX(0); - uint64 seed = PG_GETARG_INT64(1); + int64_t seed = PG_GETARG_INT64(1); Datum hash = hash_any_extended((unsigned char *) &index, sizeof(index), seed); PG_RETURN_DATUM(hash); diff --git a/h3/src/lib/operators.c b/h3/src/lib/operators.c index aea6cd49..50b50cef 100644 --- a/h3/src/lib/operators.c +++ b/h3/src/lib/operators.c @@ -1,5 +1,5 @@ /* - * Copyright 2020 Bytes & Brains + * Copyright 2020-2022 Bytes & Brains * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,10 +37,18 @@ PG_FUNCTION_INFO_V1(h3index_contained_by); static int containment(H3Index a, H3Index b) { - int aRes = h3GetResolution(a); - int bRes = h3GetResolution(b); - H3Index aParent = h3ToParent(a, bRes); - H3Index bParent = h3ToParent(b, aRes); + H3Error error = 0; + H3Index aParent = a; + H3Index bParent = b; + int aRes = getResolution(a); + int bRes = getResolution(b); + + if (aRes > bRes) + error = cellToParent(a, bRes, &aParent); + else if (aRes < bRes) + error = cellToParent(b, aRes, &bParent); + + H3_ERROR(error, "cellToParent"); /* a contains b */ if (a == bParent) diff --git a/h3/src/lib/regions.c b/h3/src/lib/regions.c index abc069e4..7caf0f65 100644 --- a/h3/src/lib/regions.c +++ b/h3/src/lib/regions.c @@ -1,5 +1,5 @@ /* - * Copyright 2018-2019 Bytes & Brains + * Copyright 2018-2022 Bytes & Brains * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,19 +27,19 @@ #include // Main H3 include #include "extension.h" -PG_FUNCTION_INFO_V1(h3_polyfill); -PG_FUNCTION_INFO_V1(h3_set_to_multi_polygon); +PG_FUNCTION_INFO_V1(h3_polygon_to_cells); +PG_FUNCTION_INFO_V1(h3_cells_to_multi_polygon); static void -polygonToGeofence(POLYGON *polygon, Geofence * geofence) +polygonToGeoLoop(POLYGON *polygon, GeoLoop * geoloop) { - geofence->numVerts = polygon->npts; - geofence->verts = (GeoCoord *) palloc(geofence->numVerts * sizeof(GeoCoord)); + geoloop->numVerts = polygon->npts; + geoloop->verts = (LatLng *) palloc(geoloop->numVerts * sizeof(LatLng)); - for (int i = 0; i < geofence->numVerts; i++) + for (int i = 0; i < geoloop->numVerts; i++) { - geofence->verts[i].lon = degsToRads(polygon->p[i].x); - geofence->verts[i].lat = degsToRads(polygon->p[i].y); + geoloop->verts[i].lng = degsToRads(polygon->p[i].x); + geoloop->verts[i].lat = degsToRads(polygon->p[i].y); } } @@ -47,7 +47,7 @@ static int linkedGeoLoopToNativePolygonSize(LinkedGeoLoop * linkedLoop) { int count = 0; - LinkedGeoCoord *linkedCoord = linkedLoop->first; + LinkedLatLng *linkedCoord = linkedLoop->first; while (linkedCoord != NULL) { @@ -61,12 +61,12 @@ static void linkedGeoLoopToNativePolygon(LinkedGeoLoop * linkedLoop, POLYGON *polygon) { int count; - LinkedGeoCoord *linkedCoord = linkedLoop->first; + LinkedLatLng *linkedCoord = linkedLoop->first; count = 0; while (linkedCoord != NULL) { - (polygon->p[count]).x = radsToDegs(linkedCoord->vertex.lon); + (polygon->p[count]).x = radsToDegs(linkedCoord->vertex.lng); (polygon->p[count]).y = radsToDegs(linkedCoord->vertex.lat); linkedCoord = linkedCoord->next; count++; @@ -77,7 +77,7 @@ linkedGeoLoopToNativePolygon(LinkedGeoLoop * linkedLoop, POLYGON *polygon) * void polyfill(const GeoPolygon* geoPolygon, int res, H3Index* out); */ Datum -h3_polyfill(PG_FUNCTION_ARGS) +h3_polygon_to_cells(PG_FUNCTION_ARGS) { if (SRF_IS_FIRSTCALL()) { @@ -85,20 +85,22 @@ h3_polyfill(PG_FUNCTION_ARGS) MemoryContext oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); - int maxSize; + int64_t maxSize; H3Index *indices; + H3Error error; ArrayType *holes; int nelems = 0; int resolution; GeoPolygon polygon; Datum value; bool isnull; + POLYGON *exterior; if (PG_ARGISNULL(0)) - ASSERT_EXTERNAL(0, "No polygon given to polyfill"); + ASSERT(0, ERRCODE_INVALID_PARAMETER_VALUE, "No polygon given to polyfill"); /* get function arguments */ - POLYGON *exterior = PG_GETARG_POLYGON_P(0); + exterior = PG_GETARG_POLYGON_P(0); if (!PG_ARGISNULL(1)) { @@ -108,7 +110,7 @@ h3_polyfill(PG_FUNCTION_ARGS) resolution = PG_GETARG_INT32(2); /* build polygon */ - polygonToGeofence(exterior, &(polygon.geofence)); + polygonToGeoLoop(exterior, &(polygon.geoloop)); if (nelems) { @@ -116,15 +118,19 @@ h3_polyfill(PG_FUNCTION_ARGS) ArrayIterator iterator = array_create_iterator(holes, 0, NULL); polygon.numHoles = nelems; - polygon.holes = (Geofence *) palloc(polygon.numHoles * sizeof(Geofence)); + polygon.holes = (GeoLoop *) palloc(polygon.numHoles * sizeof(GeoLoop)); while (array_iterate(iterator, &value, &isnull)) { - if (isnull) { + if (isnull) + { polygon.numHoles--; - } else { + } + else + { POLYGON *hole = DatumGetPolygonP(value); - polygonToGeofence(hole, &(polygon.holes[i])); + + polygonToGeoLoop(hole, &(polygon.holes[i])); i++; } } @@ -135,10 +141,12 @@ h3_polyfill(PG_FUNCTION_ARGS) } /* produce hexagons into allocated memory */ - maxSize = maxPolyfillSize(&polygon, resolution); + error = maxPolygonToCellsSize(&polygon, resolution, 0, &maxSize); + H3_ERROR(error, "maxPolygonToCellsSize"); indices = palloc_extended(maxSize * sizeof(H3Index), MCXT_ALLOC_HUGE | MCXT_ALLOC_ZERO); - polyfill(&polygon, resolution, indices); + error = polygonToCells(&polygon, resolution, 0, indices); + H3_ERROR(error, "polygonToCells"); funcctx->user_fctx = indices; funcctx->max_calls = maxSize; @@ -154,7 +162,7 @@ h3_polyfill(PG_FUNCTION_ARGS) * https://stackoverflow.com/questions/51127189/how-to-return-array-into-array-with-custom-type-in-postgres-c-function */ Datum -h3_set_to_multi_polygon(PG_FUNCTION_ARGS) +h3_cells_to_multi_polygon(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; TupleDesc tuple_desc; @@ -164,33 +172,32 @@ h3_set_to_multi_polygon(PG_FUNCTION_ARGS) if (SRF_IS_FIRSTCALL()) { - MemoryContext oldcontext; - ArrayType *array; - int numHexes; - H3Index *h3Set; - H3Index *idx; - - funcctx = SRF_FIRSTCALL_INIT(); - oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); - - ENSURE_TYPEFUNC_COMPOSITE(get_call_result_type(fcinfo, NULL, &tuple_desc)); + H3Error error; + Datum value; + bool isnull; + int i = 0; - /* get function arguments */ - array = PG_GETARG_ARRAYTYPE_P(0); + FuncCallContext *funcctx = SRF_FIRSTCALL_INIT(); + MemoryContext oldcontext = + MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); - numHexes = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array)); - h3Set = palloc(sizeof(H3Index) * numHexes); - idx = (H3Index *) ARR_DATA_PTR(array); + ArrayType *array = PG_GETARG_ARRAYTYPE_P(0); + int numHexes = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array)); + ArrayIterator iterator = array_create_iterator(array, 0, NULL); + H3Index *h3set = palloc(numHexes * sizeof(H3Index)); - for (int i = 0; i < numHexes; i++) + /* Extract data from array into h3set, and wipe compactedSet memory */ + while (array_iterate(iterator, &value, &isnull)) { - h3Set[i] = fetch_att(idx, true, sizeof(H3Index)); - idx++; + h3set[i++] = DatumGetH3Index(value); } /* produce hexagons into allocated memory */ linkedPolygon = palloc(sizeof(LinkedGeoPolygon)); - h3SetToLinkedGeo(h3Set, numHexes, linkedPolygon); + error = cellsToLinkedMultiPolygon(h3set, numHexes, linkedPolygon); + H3_ERROR(error, "cellsToLinkedMultiPolygon"); + + ENSURE_TYPEFUNC_COMPOSITE(get_call_result_type(fcinfo, NULL, &tuple_desc)); funcctx->user_fctx = linkedPolygon; funcctx->tuple_desc = BlessTupleDesc(tuple_desc); @@ -271,13 +278,13 @@ h3_set_to_multi_polygon(PG_FUNCTION_ARGS) } else { - destroyLinkedPolygon(linkedPolygon); + destroyLinkedMultiPolygon(linkedPolygon); SRF_RETURN_DONE(funcctx); } } /* --------------------------------------------------------------------------- - * The GeoPolygon, LinkedGeoCoord, LinkedGeoCoord, + * The GeoPolygon, LinkedLatLng, LinkedLatLng, * LinkedGeoLoop, and LinkedGeoPolygon * * copied from H3 core for reference @@ -290,28 +297,28 @@ h3_set_to_multi_polygon(PG_FUNCTION_ARGS) typedef struct { double lat; ///< latitude in radians double lon; ///< longitude in radians -} GeoCoord; +} LatLng; typedef struct { int numVerts; - GeoCoord *verts; -} Geofence; + LatLng *verts; +} GeoLoop; typedef struct { - Geofence geofence; ///< exterior boundary of the polygon + GeoLoop geoloop; ///< exterior boundary of the polygon int numHoles; ///< number of elements in the array pointed to by holes - Geofence *holes; ///< interior boundaries (holes) in the polygon + GeoLoop *holes; ///< interior boundaries (holes) in the polygon } GeoPolygon; */ -/** @struct LinkedGeoCoord +/** @struct LinkedLatLng * @brief A coordinate node in a linked geo structure, part of a linked list * -typedef struct LinkedGeoCoord LinkedGeoCoord; -struct LinkedGeoCoord +typedef struct LinkedLatLng LinkedLatLng; +struct LinkedLatLng { - GeoCoord vertex; - LinkedGeoCoord *next; + LatLng vertex; + LinkedLatLng *next; }; ** @struct LinkedGeoLoop @@ -320,8 +327,8 @@ struct LinkedGeoCoord typedef struct LinkedGeoLoop LinkedGeoLoop; struct LinkedGeoLoop { - LinkedGeoCoord *first; - LinkedGeoCoord *last; + LinkedLatLng *first; + LinkedLatLng *last; LinkedGeoLoop *next; }; diff --git a/h3/src/lib/traversal.c b/h3/src/lib/traversal.c index 322a4ad8..c022e88b 100644 --- a/h3/src/lib/traversal.c +++ b/h3/src/lib/traversal.c @@ -1,5 +1,5 @@ /* - * Copyright 2018-2020 Bytes & Brains + * Copyright 2018-2022 Bytes & Brains * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,13 +24,13 @@ #include // Main H3 include #include "extension.h" -PG_FUNCTION_INFO_V1(h3_k_ring); -PG_FUNCTION_INFO_V1(h3_k_ring_distances); -PG_FUNCTION_INFO_V1(h3_hex_ring); -PG_FUNCTION_INFO_V1(h3_distance); -PG_FUNCTION_INFO_V1(h3_line); -PG_FUNCTION_INFO_V1(h3_experimental_h3_to_local_ij); -PG_FUNCTION_INFO_V1(h3_experimental_local_ij_to_h3); +PG_FUNCTION_INFO_V1(h3_grid_disk); +PG_FUNCTION_INFO_V1(h3_grid_disk_distances); +PG_FUNCTION_INFO_V1(h3_grid_ring_unsafe); +PG_FUNCTION_INFO_V1(h3_grid_distance); +PG_FUNCTION_INFO_V1(h3_grid_path_cells); +PG_FUNCTION_INFO_V1(h3_cell_to_local_ij); +PG_FUNCTION_INFO_V1(h3_local_ij_to_cell); /* * k-rings produces indices within k distance of the origin index. @@ -43,7 +43,7 @@ PG_FUNCTION_INFO_V1(h3_experimental_local_ij_to_h3); * pentagon. */ Datum -h3_k_ring(PG_FUNCTION_ARGS) +h3_grid_disk(PG_FUNCTION_ARGS) { if (SRF_IS_FIRSTCALL()) { @@ -51,18 +51,24 @@ h3_k_ring(PG_FUNCTION_ARGS) MemoryContext oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); + int64_t max; + H3Index *indices; + H3Error error; + /* get function arguments */ H3Index origin = PG_GETARG_H3INDEX(0); int k = PG_GETARG_INT32(1); - /* produce indices into allocated memory */ - int maxSize = maxKringSize(k); - H3Index *indices = palloc(maxSize * sizeof(H3Index)); + error = maxGridDiskSize(k, &max); + H3_ERROR(error, "maxGridDiskSize"); - kRing(origin, k, indices); + indices = palloc(max * sizeof(H3Index)); + + error = gridDisk(origin, k, indices); + H3_ERROR(error, "gridDisk"); funcctx->user_fctx = indices; - funcctx->max_calls = maxSize; + funcctx->max_calls = max; MemoryContextSwitchTo(oldcontext); } @@ -80,7 +86,7 @@ h3_k_ring(PG_FUNCTION_ARGS) * pentagon. */ Datum -h3_k_ring_distances(PG_FUNCTION_ARGS) +h3_grid_disk_distances(PG_FUNCTION_ARGS) { if (SRF_IS_FIRSTCALL()) { @@ -98,13 +104,20 @@ h3_k_ring_distances(PG_FUNCTION_ARGS) * for */ /* returning */ - int maxSize = maxKringSize(k); - hexDistanceTuple *user_fctx = palloc(sizeof(hexDistanceTuple)); + int64_t maxSize; + H3Error error; + hexDistanceTuple *user_fctx; + + error = maxGridDiskSize(k, &maxSize); + H3_ERROR(error, "maxGridDiskSize"); + + user_fctx = palloc(sizeof(hexDistanceTuple)); user_fctx->indices = palloc(maxSize * sizeof(H3Index)); user_fctx->distances = palloc(maxSize * sizeof(int)); - kRingDistances(origin, k, user_fctx->indices, user_fctx->distances); + error = gridDiskDistances(origin, k, user_fctx->indices, user_fctx->distances); + H3_ERROR(error, "gridDiskDistances"); ENSURE_TYPEFUNC_COMPOSITE(get_call_result_type(fcinfo, NULL, &tuple_desc)); @@ -124,11 +137,10 @@ h3_k_ring_distances(PG_FUNCTION_ARGS) * Throws if pentagonal distortion was encountered. */ Datum -h3_hex_ring(PG_FUNCTION_ARGS) +h3_grid_ring_unsafe(PG_FUNCTION_ARGS) { if (SRF_IS_FIRSTCALL()) { - int result; FuncCallContext *funcctx = SRF_FIRSTCALL_INIT(); MemoryContext oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); @@ -145,14 +157,23 @@ h3_hex_ring(PG_FUNCTION_ARGS) * If k is larger than 0, the ring is the size of the circle with k, * minus the circle with k-1 */ - int maxSize = maxKringSize(k); + int64_t maxSize; + int64_t innerSize; + H3Error error; + + error = maxGridDiskSize(k, &maxSize); + H3_ERROR(error, "maxGridDiskSize"); if (k > 0) - maxSize -= maxKringSize(k - 1); + { + error = maxGridDiskSize(k - 1, &innerSize); + H3_ERROR(error, "maxGridDiskSize"); + maxSize -= innerSize; + } indices = palloc(maxSize * sizeof(H3Index)); - result = hexRing(origin, k, indices); - ASSERT_EXTERNAL(result == 0, "Pentagonal distortion encountered, this method is undefined when it encounters pentagons"); + error = gridRingUnsafe(origin, k, indices); + H3_ERROR(error, "gridRingUnsafe"); funcctx->user_fctx = indices; funcctx->max_calls = maxSize; @@ -172,14 +193,17 @@ h3_hex_ring(PG_FUNCTION_ARGS) * space functions. */ Datum -h3_distance(PG_FUNCTION_ARGS) +h3_grid_distance(PG_FUNCTION_ARGS) { H3Index originIndex = PG_GETARG_H3INDEX(0); H3Index h3Index = PG_GETARG_H3INDEX(1); - int distance; + H3Error error; + int64_t distance; - distance = h3Distance(originIndex, h3Index); - PG_RETURN_INT32(distance); + error = gridDistance(originIndex, h3Index, &distance); + H3_ERROR(error, "gridDistance"); + + PG_RETURN_INT64(distance); } /* @@ -190,7 +214,7 @@ h3_distance(PG_FUNCTION_ARGS) * distances for indexes on opposite sides of a pentagon. */ Datum -h3_line(PG_FUNCTION_ARGS) +h3_grid_path_cells(PG_FUNCTION_ARGS) { if (SRF_IS_FIRSTCALL()) { @@ -199,14 +223,19 @@ h3_line(PG_FUNCTION_ARGS) MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); /* get function arguments */ + int64_t size; + H3Error error; + H3Index *indices; H3Index start = PG_GETARG_H3INDEX(0); H3Index end = PG_GETARG_H3INDEX(1); - int size = h3LineSize(start, end); - H3Index *indices = palloc(size * sizeof(H3Index)); - int result = h3Line(start, end, indices); + error = gridPathCellsSize(start, end, &size); + H3_ERROR(error, "gridPathCellsSize"); + + indices = palloc(size * sizeof(H3Index)); - ASSERT_EXTERNAL(result == 0, "Failed to generate line"); + error = gridPathCells(start, end, indices); + H3_ERROR(error, "gridPathCells"); funcctx->user_fctx = indices; funcctx->max_calls = size; @@ -218,20 +247,19 @@ h3_line(PG_FUNCTION_ARGS) /* * Produces local IJ coordinates for an H3 index anchored by an origin. - * - * This function is experimental, and its output is not guaranteed to be - * compatible across different versions of H3. */ Datum -h3_experimental_h3_to_local_ij(PG_FUNCTION_ARGS) +h3_cell_to_local_ij(PG_FUNCTION_ARGS) { H3Index origin = PG_GETARG_H3INDEX(0); H3Index index = PG_GETARG_H3INDEX(1); Point *point = (Point *) palloc(sizeof(Point)); CoordIJ coord; + H3Error error; - experimentalH3ToLocalIj(origin, index, &coord); + error = cellToLocalIj(origin, index, 0, &coord); + H3_ERROR(error, "cellToLocalIj"); point->x = coord.i; point->y = coord.j; @@ -240,12 +268,9 @@ h3_experimental_h3_to_local_ij(PG_FUNCTION_ARGS) /* * Produces an H3 index from local IJ coordinates anchored by an origin. - * - * This function is experimental, and its output is not guaranteed to be - * compatible across different versions of H3. */ Datum -h3_experimental_local_ij_to_h3(PG_FUNCTION_ARGS) +h3_local_ij_to_cell(PG_FUNCTION_ARGS) { H3Index origin = PG_GETARG_H3INDEX(0); Point *point = PG_GETARG_POINT_P(1); @@ -253,11 +278,14 @@ h3_experimental_local_ij_to_h3(PG_FUNCTION_ARGS) H3Index *index = (H3Index *) palloc(sizeof(H3Index)); CoordIJ coord; + H3Error error; coord.i = point->x; coord.j = point->y; - experimentalLocalIjToH3(origin, &coord, index); + error = localIjToCell(origin, &coord, 0, index); + H3_ERROR(error, "localIjToCell"); + PG_FREE_IF_COPY(point, 1); PG_RETURN_H3INDEX(*index); } diff --git a/h3/src/lib/type.c b/h3/src/lib/type.c index d77a13cd..cb2fb0d5 100644 --- a/h3/src/lib/type.c +++ b/h3/src/lib/type.c @@ -1,5 +1,5 @@ /* - * Copyright 2018-2020 Bytes & Brains + * Copyright 2018-2022 Bytes & Brains * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,20 +30,27 @@ PG_FUNCTION_INFO_V1(bigint_to_h3index); Datum h3index_in(PG_FUNCTION_ARGS) { - char *str = PG_GETARG_CSTRING(0); - H3Index hex = stringToH3(str); + H3Error error; + H3Index h3; + char *string = PG_GETARG_CSTRING(0); - PG_RETURN_H3INDEX(hex); + error = stringToH3(string, &h3); + H3_ERROR(error, "stringToH3"); + + PG_RETURN_H3INDEX(h3); } Datum h3index_out(PG_FUNCTION_ARGS) { - H3Index hex = PG_GETARG_H3INDEX(0); - char *str = palloc(17 * sizeof(char)); + H3Error error; + H3Index h3 = PG_GETARG_H3INDEX(0); + char *string = palloc(17 * sizeof(char)); + + error = h3ToString(h3, string, 17); + H3_ERROR(error, "h3ToString"); - h3ToString(hex, str, 17); - PG_RETURN_CSTRING(str); + PG_RETURN_CSTRING(string); } /* bigint conversion functions */ @@ -58,7 +65,7 @@ h3index_to_bigint(PG_FUNCTION_ARGS) Datum bigint_to_h3index(PG_FUNCTION_ARGS) { - int64 bigint = PG_GETARG_INT64(0); + int64_t bigint = PG_GETARG_INT64(0); PG_RETURN_H3INDEX(bigint); } diff --git a/h3/src/lib/vertex.c b/h3/src/lib/vertex.c new file mode 100644 index 00000000..af265169 --- /dev/null +++ b/h3/src/lib/vertex.c @@ -0,0 +1,115 @@ +/* + * Copyright 2022 Bytes & Brains + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include // Datum, etc. +#include // PG_FUNCTION_ARGS, etc. +#include // Needed to return HeapTuple +#include // Needed to return HeapTuple +#include // making native points + +#include // Main H3 include +#include "extension.h" + +PG_FUNCTION_INFO_V1(h3_cell_to_vertex); +PG_FUNCTION_INFO_V1(h3_cell_to_vertexes); +PG_FUNCTION_INFO_V1(h3_vertex_to_lat_lng); +PG_FUNCTION_INFO_V1(h3_is_valid_vertex); + +/* Returns a single vertex for a given cell, as an H3 index */ +Datum +h3_cell_to_vertex(PG_FUNCTION_ARGS) +{ + H3Index vertex; + H3Error error; + H3Index cell = PG_GETARG_H3INDEX(0); + int vertexNum = PG_GETARG_INT32(1); + + error = cellToVertex(cell, vertexNum, &vertex); + H3_ERROR(error, "cellToVertex"); + + PG_RETURN_H3INDEX(vertex); +} + +/* Returns all vertexes for a given cell, as H3 indexes */ +Datum +h3_cell_to_vertexes(PG_FUNCTION_ARGS) +{ + /* stuff done only on the first call of the function */ + if (SRF_IS_FIRSTCALL()) + { + int maxSize; + int size; + H3Index *vertexes; + H3Error error; + + /* create a function context for cross-call persistence */ + FuncCallContext *funcctx = SRF_FIRSTCALL_INIT(); + + /* switch to memory context appropriate for multiple function calls */ + MemoryContext oldcontext = + MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); + + /* BEGIN One-time setup code */ + + H3Index cell = PG_GETARG_H3INDEX(0); + + maxSize = 6; + size = maxSize * sizeof(H3Index); + + vertexes = palloc(size); + error = cellToVertexes(cell, vertexes); + H3_ERROR(error, "cellToVertexes"); + + funcctx->user_fctx = vertexes; + funcctx->max_calls = maxSize; + + /* END One-time setup code */ + + MemoryContextSwitchTo(oldcontext); + } + + SRF_RETURN_H3_INDEXES_FROM_USER_FCTX(); +} + +/* Get the geocoordinates of an H3 vertex */ +Datum +h3_vertex_to_lat_lng(PG_FUNCTION_ARGS) +{ + H3Index vertex = PG_GETARG_H3INDEX(0); + + H3Error error; + Point *point = palloc(sizeof(Point)); + LatLng latlng; + + error = vertexToLatLng(vertex, &latlng); + H3_ERROR(error, "vertexToLatLng"); + + point->x = radsToDegs(latlng.lng); + point->y = radsToDegs(latlng.lat); + + PG_RETURN_POINT_P(point); +} + + +/* Whether the input is a valid H3 vertex */ +Datum +h3_is_valid_vertex(PG_FUNCTION_ARGS) +{ + H3Index vertex = PG_GETARG_H3INDEX(0); + bool is_valid = isValidVertex(vertex); + + PG_RETURN_BOOL(is_valid); +} diff --git a/h3/test/expected/clustering.out b/h3/test/expected/clustering.out index 49f83c1d..b462b725 100644 --- a/h3/test/expected/clustering.out +++ b/h3/test/expected/clustering.out @@ -2,7 +2,7 @@ \set string '\'801dfffffffffff\'' \set hexagon ':string::h3index' CREATE TABLE h3_test_clustering (hex h3index PRIMARY KEY); -INSERT INTO h3_test_clustering (hex) SELECT * from h3_get_res_0_indexes(); +INSERT INTO h3_test_clustering (hex) SELECT * from h3_get_res_0_cells(); CREATE INDEX h3_test_clustering_index ON h3_test_clustering USING btree (hex); CLUSTER h3_test_clustering_index ON h3_test_clustering; -- diff --git a/h3/test/expected/edge.out b/h3/test/expected/edge.out new file mode 100644 index 00000000..01336970 --- /dev/null +++ b/h3/test/expected/edge.out @@ -0,0 +1,63 @@ +\pset tuples_only on +\set hexagon '\'880326b885fffff\'::h3index' +\set neighbor '\'880326b887fffff\'::h3index' +\set pentagon '\'831c00fffffffff\'::h3index' +\set edge '\'1180326b885fffff\'::h3index' +-- +-- TEST h3_are_neighbor_cells +-- +SELECT h3_are_neighbor_cells(:hexagon, :neighbor); + t + +SELECT NOT h3_are_neighbor_cells(:hexagon, :hexagon); + t + +-- +-- TEST h3_cells_to_directed_edge +-- +SELECT h3_cells_to_directed_edge(:hexagon, :neighbor) = :edge; + t + +-- +-- TEST h3_is_valid_directed_edge +-- +SELECT h3_is_valid_directed_edge(:edge); + t + +SELECT NOT h3_is_valid_directed_edge(:hexagon); + t + +-- +-- TEST h3_get_directed_edge_origin and +-- h3_get_directed_edge_destination +-- +SELECT h3_get_directed_edge_origin(:edge) = :hexagon +AND h3_get_directed_edge_destination(:edge) = :neighbor; + t + +-- +-- TEST h3_directed_edge_to_cells +-- +SELECT h3_directed_edge_to_cells(:edge) = (:hexagon, :neighbor); + t + +-- +-- TEST h3_origin_to_directed_edges +-- +SELECT array_length(array_agg(edge), 1) = 6 FROM ( + SELECT h3_origin_to_directed_edges(:hexagon) edge +) q; + t + +SELECT array_length(array_agg(edge), 1) = 5 expected FROM ( + SELECT h3_origin_to_directed_edges(:pentagon) edge +) q; + t + +-- +-- TEST h3_directed_edge_to_boundary +-- +SELECT h3_directed_edge_to_boundary(:edge) + ~= polygon '((89.5830164946548,64.7146398954916),(89.5790678021742,64.2872231517217))' + t + diff --git a/h3/test/expected/hierarchy.out b/h3/test/expected/hierarchy.out index e7c7f15d..27af2520 100644 --- a/h3/test/expected/hierarchy.out +++ b/h3/test/expected/hierarchy.out @@ -4,93 +4,93 @@ \set pentagon '\'831c00fffffffff\'::h3index' \set resolution 3 -- --- TEST h3_to_children, h3_to_parent and h3_to_center_chil +-- TEST h3_cell_to_children, h3_cell_to_parent and h3_to_center_chil -- -- all parents of one the children of a hexagon, must be the original hexagon SELECT bool_and(i = :hexagon) FROM ( - SELECT h3_to_parent(h3_to_children(:hexagon)) i + SELECT h3_cell_to_parent(h3_cell_to_children(:hexagon)) i ) q; t -- one child of the parent of a hexagon, must be the original hexagon SELECT bool_or(i = :hexagon) FROM ( - SELECT h3_to_children(h3_to_parent(:hexagon)) i + SELECT h3_cell_to_children(h3_cell_to_parent(:hexagon)) i ) q; t -- all parents of one the children of a pentagon, must be the original pentagon SELECT bool_and(i = :pentagon) FROM ( - SELECT h3_to_parent(h3_to_children(:pentagon)) i + SELECT h3_cell_to_parent(h3_cell_to_children(:pentagon)) i ) q; t -- one child of the parent of a pentagon, must be the original pentagon SELECT bool_or(i = :pentagon) FROM ( - SELECT h3_to_children(h3_to_parent(:pentagon)) i + SELECT h3_cell_to_children(h3_cell_to_parent(:pentagon)) i ) q; t -- hexagon has 7 children SELECT array_length(array_agg(hex), 1) = 7 FROM ( - SELECT h3_to_children(:hexagon) hex + SELECT h3_cell_to_children(:hexagon) hex ) q; t -- pentagon has 6 children SELECT array_length(array_agg(hex), 1) = 6 FROM ( - SELECT h3_to_children(:pentagon) hex + SELECT h3_cell_to_children(:pentagon) hex ) q; t -- parent is one lower resolution -SELECT h3_get_resolution(h3_to_parent(:hexagon)) = :resolution -1; +SELECT h3_get_resolution(h3_cell_to_parent(:hexagon)) = :resolution -1; t -- all children is one higher resolution SELECT bool_and(r = :resolution +1) FROM ( - SELECT h3_get_resolution(h3_to_children(:hexagon)) r + SELECT h3_get_resolution(h3_cell_to_children(:hexagon)) r ) q; t -- parent of center child should be original index -SELECT :hexagon = h3_to_parent(h3_to_center_child(:hexagon, 15), :resolution); +SELECT :hexagon = h3_cell_to_parent(h3_cell_to_center_child(:hexagon, 15), :resolution); t -- --- TEST h3_compact and h3_uncompact +-- TEST h3_compact_cells and h3_uncompact_cells -- -- compacts the children of two hexes into the original two hexes SELECT array_agg(result) is null FROM ( - SELECT h3_compact( - ARRAY(SELECT h3_to_children(:hexagon) UNION SELECT h3_to_children(:pentagon)) + SELECT h3_compact_cells( + ARRAY(SELECT h3_cell_to_children(:hexagon) UNION SELECT h3_cell_to_children(:pentagon)) ) result EXCEPT SELECT unnest(ARRAY[:hexagon, :pentagon]) result ) q; t -- compact is inverse of uncompact -SELECT h3_compact(ARRAY(SELECT h3_uncompact(ARRAY[:hexagon], :resolution))) = :hexagon; +SELECT h3_compact_cells(ARRAY(SELECT h3_uncompact_cells(ARRAY[:hexagon], :resolution))) = :hexagon; t -- uncompacts all to same resolution, gives same result as getting children SELECT array_agg(result) is null FROM ( - SELECT h3_uncompact(ARRAY( - SELECT h3_to_children(:hexagon) UNION SELECT :pentagon + SELECT h3_uncompact_cells(ARRAY( + SELECT h3_cell_to_children(:hexagon) UNION SELECT :pentagon ), :resolution +2) result EXCEPT ( - SELECT h3_to_children(:hexagon, :resolution +2) result - UNION SELECT h3_to_children(:pentagon, :resolution +2) result + SELECT h3_cell_to_children(:hexagon, :resolution +2) result + UNION SELECT h3_cell_to_children(:pentagon, :resolution +2) result ) ) q; t -- --- TEST h3_to_children_slow +-- TEST h3_cell_to_children_slow -- --- h3_to_children_slow and h3_to_children have same result +-- h3_cell_to_children_slow and h3_cell_to_children have same result SELECT array_agg(result) is null FROM ( - SELECT h3_to_children_slow(:hexagon, :resolution + 3) result - EXCEPT SELECT h3_to_children(:hexagon, :resolution + 3) result + SELECT h3_cell_to_children_slow(:hexagon, :resolution + 3) result + EXCEPT SELECT h3_cell_to_children(:hexagon, :resolution + 3) result ) q; t diff --git a/h3/test/expected/indexing.out b/h3/test/expected/indexing.out index 43ca79fc..2bfcc62e 100644 --- a/h3/test/expected/indexing.out +++ b/h3/test/expected/indexing.out @@ -6,47 +6,61 @@ \set edgecross '\'8003fffffffffff\'::h3index' \set resolution 3 -- --- TEST h3_to_geo and h3_geo_to_h3 +-- TEST h3_cell_to_lat_lng and h3_lat_lng_to_cell -- -- convertion to geo works -SELECT h3_to_geo(:hexagon) ~= :geo; +SELECT h3_cell_to_lat_lng(:hexagon) ~= :geo; t -- convertion to h3 index works -SELECT h3_geo_to_h3(:geo, :resolution) = :hexagon; +SELECT h3_lat_lng_to_cell(:geo, :resolution) = :hexagon; t --- h3_to_geo is inverse of h3_geo_to_h3 -SELECT h3_to_geo(i) ~= :geo AND h3_get_resolution(i) = :resolution FROM ( - SELECT h3_geo_to_h3(:geo, :resolution) AS i +-- h3_cell_to_lat_lng is inverse of h3_lat_lng_to_cell +SELECT h3_cell_to_lat_lng(i) ~= :geo AND h3_get_resolution(i) = :resolution FROM ( + SELECT h3_lat_lng_to_cell(:geo, :resolution) AS i ) AS q; t --- h3_geo_to_h3 is inverse of h3_to_geo -SELECT h3_geo_to_h3(g, r) = :hexagon FROM ( - SELECT h3_to_geo(:hexagon) AS g, h3_get_resolution(:hexagon) AS r +-- h3_lat_lng_to_cell is inverse of h3_cell_to_lat_lng +SELECT h3_lat_lng_to_cell(g, r) = :hexagon FROM ( + SELECT h3_cell_to_lat_lng(:hexagon) AS g, h3_get_resolution(:hexagon) AS r ) AS q; t -- same for pentagon -SELECT h3_geo_to_h3(g, r) = :pentagon FROM ( - SELECT h3_to_geo(:pentagon) AS g, h3_get_resolution(:pentagon) AS r +SELECT h3_lat_lng_to_cell(g, r) = :pentagon FROM ( + SELECT h3_cell_to_lat_lng(:pentagon) AS g, h3_get_resolution(:pentagon) AS r ) AS q; t -- --- TEST h3_to_geo_boundary +-- TEST h3_cell_to_boundary -- -- polyfill of geo boundary returns original index -SELECT h3_polyfill(h3_to_geo_boundary(:hexagon), null, :resolution) = :hexagon; +SELECT h3_polygon_to_cells(h3_cell_to_boundary(:hexagon), null, :resolution) = :hexagon; t -- same for pentagon -SELECT h3_polyfill(h3_to_geo_boundary(:pentagon), null, :resolution) = :pentagon; +SELECT h3_polygon_to_cells(h3_cell_to_boundary(:pentagon), null, :resolution) = :pentagon; t -- the boundary of an edgecrossing index is different with flag set to true -SELECT h3_to_geo_boundary(:hexagon) ~= h3_to_geo_boundary(:hexagon, true) -AND NOT h3_to_geo_boundary(:edgecross) ~= h3_to_geo_boundary(:edgecross, true); +SELECT h3_cell_to_boundary(:hexagon) ~= h3_cell_to_boundary(:hexagon, true) +AND NOT h3_cell_to_boundary(:edgecross) ~= h3_cell_to_boundary(:edgecross, true); t +-- cell to parent RES_MISMATCH +CREATE FUNCTION h3_fail_indexing_cell_to_parent() RETURNS boolean LANGUAGE PLPGSQL + AS $$ + BEGIN + PERFORM h3_cell_to_parent('831c02fffffffff', 10); + RETURN false; + EXCEPTION WHEN OTHERS THEN + RETURN true; + END; + $$; +SELECT h3_fail_indexing_cell_to_parent(); + t + +DROP FUNCTION h3_fail_indexing_cell_to_parent; diff --git a/h3/test/expected/inspection.out b/h3/test/expected/inspection.out index 430b83ee..3cb4bd50 100644 --- a/h3/test/expected/inspection.out +++ b/h3/test/expected/inspection.out @@ -11,29 +11,29 @@ SELECT h3_get_resolution(:hexagon) = :resolution AND h3_get_resolution(:pentagon t -- --- TEST h3_get_base_cell +-- TEST h3_get_base_cell_number -- -- base cell is same for parents -SELECT h3_get_base_cell(:hexagon) = h3_get_base_cell(h3_to_parent(:hexagon)); +SELECT h3_get_base_cell_number(:hexagon) = h3_get_base_cell_number(h3_cell_to_parent(:hexagon)); t -SELECT h3_get_base_cell(:pentagon) = h3_get_base_cell(h3_to_parent(:pentagon)); +SELECT h3_get_base_cell_number(:pentagon) = h3_get_base_cell_number(h3_cell_to_parent(:pentagon)); t -- --- TEST h3_is_valid +-- TEST h3_is_valid_cell -- -SELECT h3_is_valid(:hexagon) AND h3_is_valid(:pentagon) AND NOT h3_is_valid(:invalid); +SELECT h3_is_valid_cell(:hexagon) AND h3_is_valid_cell(:pentagon) AND NOT h3_is_valid_cell(:invalid); t -- -- TEST h3_is_res_class_iii -- -- if index is Class III then parent is not -SELECT h3_is_res_class_iii(:hexagon) AND NOT h3_is_res_class_iii(h3_to_parent(:hexagon)); +SELECT h3_is_res_class_iii(:hexagon) AND NOT h3_is_res_class_iii(h3_cell_to_parent(:hexagon)); t -SELECT h3_is_res_class_iii(:pentagon) AND NOT h3_is_res_class_iii(h3_to_parent(:pentagon)); +SELECT h3_is_res_class_iii(:pentagon) AND NOT h3_is_res_class_iii(h3_cell_to_parent(:pentagon)); t -- @@ -43,11 +43,11 @@ SELECT h3_is_pentagon(:pentagon) AND NOT h3_is_pentagon(:hexagon); t -- --- TEST h3_get_faces +-- TEST h3_get_icosahedron_faces -- -SELECT h3_get_faces('851c0047fffffff') = ARRAY[11,6]; +SELECT h3_get_icosahedron_faces('851c0047fffffff') = ARRAY[11,6]; t -SELECT h3_get_faces('851c004bfffffff') = ARRAY[6]; +SELECT h3_get_icosahedron_faces('851c004bfffffff') = ARRAY[6]; t diff --git a/h3/test/expected/miscellaneous.out b/h3/test/expected/miscellaneous.out index 7d802ce4..646bdda1 100644 --- a/h3/test/expected/miscellaneous.out +++ b/h3/test/expected/miscellaneous.out @@ -2,99 +2,99 @@ \set degs 90.45 \set rads 1.57865030842887 \set epsilon 0.0000000000001 -\set uniedge '\'1180326b885fffff\'::h3index' +\set edge '\'1180326b885fffff\'::h3index' -- --- TEST h3_point_dist +-- TEST h3_great_circle_distance -- \set lyon POINT(4.8422, 45.7597) \set paris POINT(2.3508, 48.8567) -SELECT h3_point_dist(:lyon, :paris, 'rads') - 0.0615628186794217 < :epsilon; +SELECT h3_great_circle_distance(:lyon, :paris, 'rads') - 0.0615628186794217 < :epsilon; t -SELECT h3_point_dist(:lyon, :paris, 'm') - 392217.1598841777 < :epsilon; +SELECT h3_great_circle_distance(:lyon, :paris, 'm') - 392217.1598841777 < :epsilon; t -SELECT h3_point_dist(:lyon, :paris, 'km') - 392.21715988417765 < :epsilon; +SELECT h3_great_circle_distance(:lyon, :paris, 'km') - 392.21715988417765 < :epsilon; t -- test that 'km' is the default unit -SELECT h3_point_dist(:lyon, :paris, 'km') = h3_point_dist(:lyon, :paris); +SELECT h3_great_circle_distance(:lyon, :paris, 'km') = h3_great_circle_distance(:lyon, :paris); t -- --- TEST h3_hex_area +-- TEST h3_get_hexagon_area_avg -- -SELECT h3_hex_area(10, 'm') = 15047.5; +SELECT abs(h3_get_hexagon_area_avg(10, 'm') - 15047.50190766437) < :epsilon; t -SELECT h3_hex_area(10, 'km') = 0.0150475; +SELECT abs(h3_get_hexagon_area_avg(10, 'km') - 0.01504750190766435) < :epsilon; t -SELECT h3_hex_area(10, 'km') = h3_hex_area(10); +SELECT h3_get_hexagon_area_avg(10, 'km') = h3_get_hexagon_area_avg(10); t -- -- TEST h3_cell_area -- \set expected_km2 0.01119834221989390 -SELECT abs((h3_cell_area(h3_geo_to_h3(POINT(0, 0), 10), 'm^2') / 1000000) - :expected_km2) < :epsilon; +SELECT abs((h3_cell_area(h3_lat_lng_to_cell(POINT(0, 0), 10), 'm^2') / 1000000) - :expected_km2) < :epsilon; t -SELECT abs(h3_cell_area(h3_geo_to_h3(POINT(0, 0), 10), 'km^2') - :expected_km2) < :epsilon; +SELECT abs(h3_cell_area(h3_lat_lng_to_cell(POINT(0, 0), 10), 'km^2') - :expected_km2) < :epsilon; t -SELECT h3_cell_area(h3_geo_to_h3(POINT(0, 0), 10), 'rads^2') > 0; +SELECT h3_cell_area(h3_lat_lng_to_cell(POINT(0, 0), 10), 'rads^2') > 0; t -- default is km^2 -SELECT h3_cell_area(h3_geo_to_h3(POINT(0, 0), 10), 'km^2') = h3_cell_area(h3_geo_to_h3(POINT(0, 0), 10)); +SELECT h3_cell_area(h3_lat_lng_to_cell(POINT(0, 0), 10), 'km^2') = h3_cell_area(h3_lat_lng_to_cell(POINT(0, 0), 10)); t -- --- TEST h3_edge_length +-- TEST h3_get_hexagon_edge_length_avg -- -SELECT h3_edge_length(10, 'm') = 65.90780749; +SELECT h3_get_hexagon_edge_length_avg(10, 'm') = 65.90780749; t -SELECT h3_edge_length(10, 'km') = 0.065907807; +SELECT h3_get_hexagon_edge_length_avg(10, 'km') = 0.065907807; t -SELECT h3_edge_length(10, 'km') = h3_edge_length(10); +SELECT h3_get_hexagon_edge_length_avg(10, 'km') = h3_get_hexagon_edge_length_avg(10); t -- --- TEST h3_exact_edge_length +-- TEST h3_edge_length -- -SELECT h3_exact_edge_length(:uniedge, 'rads') > 0; +SELECT h3_edge_length(:edge, 'rads') > 0; t -SELECT h3_exact_edge_length(:uniedge, 'km') > h3_exact_edge_length(:uniedge, 'rads'); +SELECT h3_edge_length(:edge, 'km') > h3_edge_length(:edge, 'rads'); t -SELECT h3_exact_edge_length(:uniedge, 'm') > h3_exact_edge_length(:uniedge, 'km'); +SELECT h3_edge_length(:edge, 'm') > h3_edge_length(:edge, 'km'); t -SELECT h3_exact_edge_length(:uniedge) = h3_exact_edge_length(:uniedge, 'km'); +SELECT h3_edge_length(:edge) = h3_edge_length(:edge, 'km'); t -- --- TEST h3_num_hexagons +-- TEST h3_get_num_cells -- -SELECT h3_num_hexagons(0) = 122; +SELECT h3_get_num_cells(0) = 122; t -SELECT h3_num_hexagons(15) = 569707381193162; +SELECT h3_get_num_cells(15) = 569707381193162; t -- --- TEST h3_get_res_0_indexes +-- TEST h3_get_res_0_cells -- -SELECT COUNT(*) = 122 FROM (SELECT h3_get_res_0_indexes()) q; +SELECT COUNT(*) = 122 FROM (SELECT h3_get_res_0_cells()) q; t -- --- TEST h3_get_pentagon_indexes +-- TEST h3_get_pentagons -- -SELECT COUNT(*) = 12 FROM (SELECT h3_get_pentagon_indexes(6)) q; +SELECT COUNT(*) = 12 FROM (SELECT h3_get_pentagons(6)) q; t diff --git a/h3/test/expected/opclass_btree.out b/h3/test/expected/opclass_btree.out index ce90d793..6bd16ad1 100644 --- a/h3/test/expected/opclass_btree.out +++ b/h3/test/expected/opclass_btree.out @@ -2,7 +2,7 @@ \set string '\'801dfffffffffff\'' \set hexagon ':string::h3index' CREATE TABLE h3_test_btree (hex h3index PRIMARY KEY); -INSERT INTO h3_test_btree (hex) SELECT * from h3_get_res_0_indexes(); +INSERT INTO h3_test_btree (hex) SELECT * from h3_get_res_0_cells(); CREATE INDEX h3_btree ON h3_test_btree USING btree (hex); -- -- TEST b-tree operator class diff --git a/h3/test/expected/opclass_hash.out b/h3/test/expected/opclass_hash.out index 6d0fdddb..15f25606 100644 --- a/h3/test/expected/opclass_hash.out +++ b/h3/test/expected/opclass_hash.out @@ -1,13 +1,13 @@ \pset tuples_only on CREATE TABLE h3_test_hash (hex h3index PRIMARY KEY); -INSERT INTO h3_test_hash (hex) SELECT * from h3_get_res_0_indexes(); +INSERT INTO h3_test_hash (hex) SELECT * from h3_get_res_0_cells(); CREATE INDEX h3_btree ON h3_test_hash USING hash (hex); ERROR: relation "h3_btree" already exists -- -- TEST hash operator class -- SELECT COUNT(hex) = 122 FROM ( - SELECT hex FROM h3_test_hash WHERE hex IN (SELECT h3_get_res_0_indexes()) + SELECT hex FROM h3_test_hash WHERE hex IN (SELECT h3_get_res_0_cells()) ) q; t diff --git a/h3/test/expected/postgis.out b/h3/test/expected/postgis.out index 65dd1722..04131967 100644 --- a/h3/test/expected/postgis.out +++ b/h3/test/expected/postgis.out @@ -4,26 +4,30 @@ \set hexagon '\'8a63a9a99047fff\'' \set meter ST_SetSRID(ST_Point(6196902.235389061,1413172.0833316022), 3857) \set degree ST_SetSRID(ST_Point(55.6677199224442,12.592131261648213), 4326) -SELECT h3_geo_to_h3(:degree, :resolution) = '8a63a9a99047fff'; +-- polygon with 2 holes +\set with2holes '\'POLYGON((31.6520834 68.9912098,31.6521263 68.9910944,31.6530919 68.9912021,31.6540789 68.9912944,31.6550016 68.991279,31.6553449 68.9910175,31.6554737 68.9907713,31.6559458 68.990402,31.6563535 68.9900789,31.6568684 68.9897404,31.6569543 68.9895711,31.6567182 68.988671,31.6569114 68.9881786,31.6571045 68.9879401,31.6567611 68.9875708,31.6570401 68.9873015,31.6576195 68.986986,31.6581774 68.9868398,31.6584992 68.9870553,31.6586065 68.9872707,31.6590786 68.9873246,31.6594219 68.9872091,31.6596579 68.9870091,31.6596579 68.9867706,31.6601515 68.9866167,31.6607308 68.9864551,31.660409 68.986232,31.6601729 68.9860627,31.6605806 68.9859319,31.6614818 68.9859011,31.6620183 68.9857087,31.6622972 68.9854471,31.6628337 68.9852932,31.6633701 68.9852855,31.663928 68.9855702,31.6640782 68.9859088,31.6636705 68.9862166,31.6639924 68.9864859,31.664443 68.9868629,31.664679 68.9872091,31.6642928 68.9873784,31.6641426 68.9876939,31.6650009 68.9879016,31.6652155 68.9881555,31.6653657 68.9883709,31.6659665 68.9886941,31.6662884 68.9889941,31.666739 68.989248,31.6669321 68.9891095,31.6670394 68.9888787,31.6681123 68.9889326,31.6687345 68.989325,31.6692495 68.9895865,31.6701937 68.9897635,31.6710949 68.9897404,31.6725325 68.9897558,31.6733479 68.9898558,31.6743135 68.9904097,31.674571 68.990702,31.6747641 68.9909328,31.6745066 68.9911405,31.6738844 68.9912636,31.6731977 68.9914175,31.6734981 68.9916098,31.6739487 68.9915713,31.6744852 68.9915175,31.6750431 68.9914021,31.6751718 68.9911944,31.6752147 68.9910405,31.6756439 68.9910636,31.6765451 68.9912021,31.6777253 68.9912944,31.6784119 68.9912482,31.6790771 68.9911559,31.6793346 68.9913021,31.6787553 68.9916713,31.678133 68.9920867,31.6780472 68.9924483,31.6782617 68.9927098,31.6792702 68.9941098,31.6794419 68.9943636,31.6801715 68.9945328,31.6817808 68.9946328,31.6825533 68.9948174,31.6827249 68.995202,31.683712 68.9957404,31.6840124 68.9962634,31.684699 68.9965556,31.6848492 68.9968171,31.6841197 68.9969632,31.6831326 68.9969479,31.6827464 68.9969171,31.6824031 68.9968556,31.6821456 68.9967248,31.6813302 68.9968248,31.6810083 68.9971094,31.6806865 68.9971863,31.6802358 68.9971401,31.6792702 68.9967018,31.6787553 68.9963864,31.6780901 68.9958327,31.6777038 68.9956788,31.6766095 68.9955635,31.6762233 68.9954943,31.6759658 68.9952943,31.6753649 68.9951481,31.6746354 68.9952712,31.6735625 68.9951866,31.6728329 68.9951866,31.6726398 68.9953943,31.6719746 68.9955173,31.6709661 68.9954173,31.6704941 68.9951558,31.6700434 68.9948251,31.669743 68.9944867,31.6695285 68.994179,31.6693783 68.9939329,31.6690779 68.993756,31.6680479 68.9935867,31.663692 68.9929329,31.6628551 68.9927637,31.661675 68.9927637,31.6610527 68.9929637,31.6605377 68.9929714,31.6599583 68.9929406,31.6588855 68.9928175,31.658349 68.992656,31.657598 68.9923714,31.6567826 68.9922329,31.6552162 68.9920714,31.6541648 68.9919175,31.6531348 68.9916483,31.6523838 68.9914175,31.6520834 68.9912098),(31.657185 68.990202,31.657244 68.9903482,31.6574585 68.9903809,31.6578555 68.9903597,31.6581452 68.9902539,31.6583651 68.9900924,31.6582364 68.9899366,31.6578716 68.9898616,31.6575766 68.9898731,31.6573083 68.9899808,31.6572332 68.9900731,31.657185 68.990202),(31.6590196 68.9886094,31.6591644 68.9887229,31.6594058 68.9888537,31.6595936 68.9889557,31.6596794 68.9890441,31.6597116 68.9891345,31.659776 68.9892519,31.6599476 68.9891903,31.660012 68.9890614,31.6601139 68.9889383,31.6602641 68.9888326,31.6602749 68.988721,31.6601998 68.988596,31.6600603 68.988369,31.6601676 68.9882709,31.6604251 68.9882844,31.6607255 68.9882728,31.6609454 68.9881767,31.6605592 68.9880901,31.6604841 68.9879689,31.6603607 68.9878497,31.660071 68.9878843,31.6597867 68.9879959,31.6593575 68.9880305,31.6592127 68.9881132,31.6592234 68.9882421,31.6592127 68.9883786,31.6590196 68.9886094))\''::geometry(POLYGON) +CREATE EXTENSION postgis; +CREATE EXTENSION h3_postgis; +SELECT h3_lat_lng_to_cell(:degree, :resolution) = '8a63a9a99047fff'; t -- meters are NOT reprojected -SELECT h3_geo_to_h3(:meter, :resolution) <> '8a63a9a99047fff'; +SELECT h3_lat_lng_to_cell(:meter, :resolution) <> '8a63a9a99047fff'; t -- check back/forth conversion return same hex -SELECT h3_geo_to_h3(h3_to_geometry(:hexagon), :resolution) = '8a63a9a99047fff'; +SELECT h3_lat_lng_to_cell(h3_cell_to_geometry(:hexagon), :resolution) = '8a63a9a99047fff'; t -- check num points in boundary -SELECT ST_NPoints( h3_to_geo_boundary_geometry(:hexagon)) = 7; +SELECT ST_NPoints(h3_cell_to_boundary_geometry(:hexagon)) = 7; t --- test strict h3_geo_to_h3 throws for bad latlon +-- test strict h3_lat_lng_to_cell throws for bad latlon CREATE FUNCTION h3_test_postgis_nounit() RETURNS boolean LANGUAGE PLPGSQL AS $$ BEGIN - PERFORM h3_geo_to_h3(POINT(360, 2.592131261648213), 1); + PERFORM h3_lat_lng_to_cell(POINT(360, 2.592131261648213), 1); RETURN false; EXCEPTION WHEN OTHERS THEN RETURN true; @@ -38,11 +42,17 @@ DROP FUNCTION h3_test_postgis_nounit; -- Test wraparound \set lon 55.6677199224442 \set lat 12.592131261648213 -SELECT h3_geo_to_h3(POINT(:lon, :lat), 7) - = h3_geo_to_h3(POINT(:lon + 360, :lat), 7); +SELECT h3_lat_lng_to_cell(POINT(:lon, :lat), 7) + = h3_lat_lng_to_cell(POINT(:lon + 360, :lat), 7); t -SELECT h3_geo_to_h3(POINT(:lon, :lat ), 7) - = h3_geo_to_h3(POINT(:lon, :lat + 360), 7); +SELECT h3_lat_lng_to_cell(POINT(:lon, :lat ), 7) + = h3_lat_lng_to_cell(POINT(:lon, :lat + 360), 7); + t + +-- h3_polygon_to_cells works for polygon with two holes +SELECT COUNT(*) = 48 FROM ( + SELECT h3_polygon_to_cells(:with2holes, 10) +) q; t diff --git a/h3/test/expected/regions.out b/h3/test/expected/regions.out index 11e0d7bb..579c1bce 100644 --- a/h3/test/expected/regions.out +++ b/h3/test/expected/regions.out @@ -4,44 +4,36 @@ -- center hex \set center '\'81583ffffffffff\'' -- 7 child hexes in res 0 index -\set solid 'ARRAY(SELECT h3_to_children(:res0index, 1))' +\set solid 'ARRAY(SELECT h3_cell_to_children(:res0index, 1))' -- 6 child hexes in rim of res 0 index \set hollow 'array_remove(:solid, :center)' --- polygon with 2 holes -\set with2holes '\'POLYGON((31.6520834 68.9912098,31.6521263 68.9910944,31.6530919 68.9912021,31.6540789 68.9912944,31.6550016 68.991279,31.6553449 68.9910175,31.6554737 68.9907713,31.6559458 68.990402,31.6563535 68.9900789,31.6568684 68.9897404,31.6569543 68.9895711,31.6567182 68.988671,31.6569114 68.9881786,31.6571045 68.9879401,31.6567611 68.9875708,31.6570401 68.9873015,31.6576195 68.986986,31.6581774 68.9868398,31.6584992 68.9870553,31.6586065 68.9872707,31.6590786 68.9873246,31.6594219 68.9872091,31.6596579 68.9870091,31.6596579 68.9867706,31.6601515 68.9866167,31.6607308 68.9864551,31.660409 68.986232,31.6601729 68.9860627,31.6605806 68.9859319,31.6614818 68.9859011,31.6620183 68.9857087,31.6622972 68.9854471,31.6628337 68.9852932,31.6633701 68.9852855,31.663928 68.9855702,31.6640782 68.9859088,31.6636705 68.9862166,31.6639924 68.9864859,31.664443 68.9868629,31.664679 68.9872091,31.6642928 68.9873784,31.6641426 68.9876939,31.6650009 68.9879016,31.6652155 68.9881555,31.6653657 68.9883709,31.6659665 68.9886941,31.6662884 68.9889941,31.666739 68.989248,31.6669321 68.9891095,31.6670394 68.9888787,31.6681123 68.9889326,31.6687345 68.989325,31.6692495 68.9895865,31.6701937 68.9897635,31.6710949 68.9897404,31.6725325 68.9897558,31.6733479 68.9898558,31.6743135 68.9904097,31.674571 68.990702,31.6747641 68.9909328,31.6745066 68.9911405,31.6738844 68.9912636,31.6731977 68.9914175,31.6734981 68.9916098,31.6739487 68.9915713,31.6744852 68.9915175,31.6750431 68.9914021,31.6751718 68.9911944,31.6752147 68.9910405,31.6756439 68.9910636,31.6765451 68.9912021,31.6777253 68.9912944,31.6784119 68.9912482,31.6790771 68.9911559,31.6793346 68.9913021,31.6787553 68.9916713,31.678133 68.9920867,31.6780472 68.9924483,31.6782617 68.9927098,31.6792702 68.9941098,31.6794419 68.9943636,31.6801715 68.9945328,31.6817808 68.9946328,31.6825533 68.9948174,31.6827249 68.995202,31.683712 68.9957404,31.6840124 68.9962634,31.684699 68.9965556,31.6848492 68.9968171,31.6841197 68.9969632,31.6831326 68.9969479,31.6827464 68.9969171,31.6824031 68.9968556,31.6821456 68.9967248,31.6813302 68.9968248,31.6810083 68.9971094,31.6806865 68.9971863,31.6802358 68.9971401,31.6792702 68.9967018,31.6787553 68.9963864,31.6780901 68.9958327,31.6777038 68.9956788,31.6766095 68.9955635,31.6762233 68.9954943,31.6759658 68.9952943,31.6753649 68.9951481,31.6746354 68.9952712,31.6735625 68.9951866,31.6728329 68.9951866,31.6726398 68.9953943,31.6719746 68.9955173,31.6709661 68.9954173,31.6704941 68.9951558,31.6700434 68.9948251,31.669743 68.9944867,31.6695285 68.994179,31.6693783 68.9939329,31.6690779 68.993756,31.6680479 68.9935867,31.663692 68.9929329,31.6628551 68.9927637,31.661675 68.9927637,31.6610527 68.9929637,31.6605377 68.9929714,31.6599583 68.9929406,31.6588855 68.9928175,31.658349 68.992656,31.657598 68.9923714,31.6567826 68.9922329,31.6552162 68.9920714,31.6541648 68.9919175,31.6531348 68.9916483,31.6523838 68.9914175,31.6520834 68.9912098),(31.657185 68.990202,31.657244 68.9903482,31.6574585 68.9903809,31.6578555 68.9903597,31.6581452 68.9902539,31.6583651 68.9900924,31.6582364 68.9899366,31.6578716 68.9898616,31.6575766 68.9898731,31.6573083 68.9899808,31.6572332 68.9900731,31.657185 68.990202),(31.6590196 68.9886094,31.6591644 68.9887229,31.6594058 68.9888537,31.6595936 68.9889557,31.6596794 68.9890441,31.6597116 68.9891345,31.659776 68.9892519,31.6599476 68.9891903,31.660012 68.9890614,31.6601139 68.9889383,31.6602641 68.9888326,31.6602749 68.988721,31.6601998 68.988596,31.6600603 68.988369,31.6601676 68.9882709,31.6604251 68.9882844,31.6607255 68.9882728,31.6609454 68.9881767,31.6605592 68.9880901,31.6604841 68.9879689,31.6603607 68.9878497,31.660071 68.9878843,31.6597867 68.9879959,31.6593575 68.9880305,31.6592127 68.9881132,31.6592234 68.9882421,31.6592127 68.9883786,31.6590196 68.9886094))\''::geometry(POLYGON) -- pentagon \set pentagon '\'831c00fffffffff\'::h3index' -- --- TEST h3_polyfill and h3_set_to_multi_polygon +-- TEST h3_polygon_to_cells and h3_cells_to_multi_polygon -- --- h3_polyfill is inverse of h3_set_to_multi_polygon for set without holes +-- h3_polygon_to_cells is inverse of h3_cells_to_multi_polygon for set without holes SELECT array_agg(result) is null FROM ( - SELECT h3_polyfill(exterior, holes, 1) result FROM ( - SELECT exterior, holes FROM h3_set_to_multi_polygon(:solid) + SELECT h3_polygon_to_cells(exterior, holes, 1) result FROM ( + SELECT exterior, holes FROM h3_cells_to_multi_polygon(:solid) ) qq EXCEPT SELECT unnest(:solid) result ) q; t --- h3_polyfill is inverse of h3_set_to_multi_polygon for set with a hole +-- h3_polygon_to_cells is inverse of h3_cells_to_multi_polygon for set with a hole SELECT array_agg(result) is null FROM ( - SELECT h3_polyfill(exterior, holes, 1) result FROM ( - SELECT exterior, holes FROM h3_set_to_multi_polygon(:hollow) + SELECT h3_polygon_to_cells(exterior, holes, 1) result FROM ( + SELECT exterior, holes FROM h3_cells_to_multi_polygon(:hollow) ) qq EXCEPT SELECT unnest(:hollow) result ) q; t --- h3_polyfill works for polygon with two holes -SELECT COUNT(*) = 48 FROM ( - SELECT h3_polyfill(:with2holes, 10) -) q; - t - -- h3_polyfill doesn't segfault on NULL value in holes SELECT TRUE FROM ( - SELECT h3_polyfill(exterior, ARRAY[NULL::POLYGON], 1) result FROM ( - SELECT exterior, holes FROM h3_set_to_multi_polygon( + SELECT h3_polygon_to_cells(exterior, ARRAY[NULL::POLYGON], 1) result FROM ( + SELECT exterior, holes FROM h3_cells_to_multi_polygon( ARRAY[:pentagon]::H3Index[] ) ) qq diff --git a/h3/test/expected/traversal.out b/h3/test/expected/traversal.out index 90a8763c..fe6df032 100644 --- a/h3/test/expected/traversal.out +++ b/h3/test/expected/traversal.out @@ -3,32 +3,32 @@ \set origin '\'880326b887fffff\'' \set pentagon '\'831c00fffffffff\'' -- --- TEST h3_k_ring and h3_hex_ring +-- TEST h3_grid_disk and h3_grid_ring_unsafe -- --- kRing 0 is input index -SELECT h3_k_ring(:hexagon, 0) = :hexagon; +-- gridDisk 0 is input index +SELECT h3_grid_disk(:hexagon, 0) = :hexagon; t --- kRing 2 is same as sum of hexRing 0, 1 and 2 +-- gridDisk 2 is same as sum of gridRing 0, 1 and 2 SELECT array_agg(r) is null FROM ( - SELECT h3_k_ring(:hexagon, 2) r + SELECT h3_grid_disk(:hexagon, 2) r EXCEPT ( - SELECT h3_hex_ring(:hexagon, 0) r - UNION SELECT h3_hex_ring(:hexagon, 1) r - UNION SELECT h3_hex_ring(:hexagon, 2) r + SELECT h3_grid_ring_unsafe(:hexagon, 0) r + UNION SELECT h3_grid_ring_unsafe(:hexagon, 1) r + UNION SELECT h3_grid_ring_unsafe(:hexagon, 2) r ) ) q; t -- --- TEST h3_k_ring_distances +-- TEST h3_grid_disk_distances -- -- correct number of indexes at distances 0, 1 and 2 for k=2 SELECT COUNT(index) filter (WHERE distance = 0) = 1 AND COUNT(index) filter (WHERE distance = 1) = 6 AND COUNT(index) filter (WHERE distance = 2) = 12 FROM ( - SELECT index, distance FROM h3_k_ring_distances(:hexagon, 2) + SELECT index, distance FROM h3_grid_disk_distances(:hexagon, 2) ) q; t @@ -37,32 +37,41 @@ SELECT COUNT(index) filter (WHERE distance = 0) = 1 AND COUNT(index) filter (WHERE distance = 1) = 5 AND COUNT(index) filter (WHERE distance = 2) = 10 FROM ( - SELECT index, distance FROM h3_k_ring_distances(:pentagon, 2) + SELECT index, distance FROM h3_grid_disk_distances(:pentagon, 2) ) q; t -- --- TEST h3_line +-- TEST h3_grid_path_cells -- -SELECT ARRAY(SELECT h3_line('841c023ffffffff', '841c025ffffffff')) +SELECT ARRAY(SELECT h3_grid_path_cells('841c023ffffffff', '841c025ffffffff')) = ARRAY['841c023ffffffff','841c027ffffffff','841c025ffffffff']::h3index[]; t -- --- TEST h3_distance +-- TEST h3_grid_distance -- -- returns 1 for indexes with one index between them -SELECT h3_distance('880326b881fffff', '880326b885fffff') = 1; +SELECT h3_grid_distance('880326b881fffff', '880326b885fffff') = 1; t --- returns -1 for invalid inputs -SELECT h3_distance('880326b881fffff', h3_to_parent('880326b885fffff')) = -1; +-- throws for invalid inputs +CREATE FUNCTION h3_test_grid_distance_invalid() RETURNS boolean LANGUAGE PLPGSQL + AS $$ + BEGIN + PERFORM h3_grid_distance('880326b881fffff', h3_cell_to_parent('880326b885fffff')) = -1; + RETURN false; + EXCEPTION WHEN OTHERS THEN + RETURN true; + END; + $$; +SELECT h3_test_grid_distance_invalid(); t -- --- TEST h3_experimental_h3_to_local_ij and h3_experimental_local_ij_to_h3 +-- TEST h3_cell_to_local_ij and h3_local_ij_to_cell -- -- they are inverse of each others -SELECT :hexagon = h3_experimental_local_ij_to_h3(:origin, h3_experimental_h3_to_local_ij(:origin, :hexagon)); +SELECT :hexagon = h3_local_ij_to_cell(:origin, h3_cell_to_local_ij(:origin, :hexagon)); t diff --git a/h3/test/expected/type.out b/h3/test/expected/type.out index d90f53ed..2a8308f5 100644 --- a/h3/test/expected/type.out +++ b/h3/test/expected/type.out @@ -18,11 +18,11 @@ SELECT NOT :hexagon <> :hexagon; SELECT :hexagon <> :pentagon; t -SELECT :pentagon <@ h3_to_parent(:pentagon); +SELECT :pentagon <@ h3_cell_to_parent(:pentagon); t SELECT bool_and(:pentagon @> c) FROM ( - SELECT h3_to_children(:pentagon) c + SELECT h3_cell_to_children(:pentagon) c ) q; t diff --git a/h3/test/expected/uniedges.out b/h3/test/expected/uniedges.out deleted file mode 100644 index 04411b1e..00000000 --- a/h3/test/expected/uniedges.out +++ /dev/null @@ -1,63 +0,0 @@ -\pset tuples_only on -\set hexagon '\'880326b885fffff\'::h3index' -\set neighbor '\'880326b887fffff\'::h3index' -\set pentagon '\'831c00fffffffff\'::h3index' -\set uniedge '\'1180326b885fffff\'::h3index' --- --- TEST h3_indexes_are_neighbors --- -SELECT h3_indexes_are_neighbors(:hexagon, :neighbor); - t - -SELECT NOT h3_indexes_are_neighbors(:hexagon, :hexagon); - t - --- --- TEST h3_get_h3_unidirectional_edge --- -SELECT h3_get_h3_unidirectional_edge(:hexagon, :neighbor) = :uniedge; - t - --- --- TEST h3_unidirectional_edge_is_valid --- -SELECT h3_unidirectional_edge_is_valid(:uniedge); - t - -SELECT NOT h3_unidirectional_edge_is_valid(:hexagon); - t - --- --- TEST h3_get_origin_h3_index_from_unidirectional_edge and --- h3_get_destination_h3_index_from_unidirectional_edge --- -SELECT h3_get_origin_h3_index_from_unidirectional_edge(:uniedge) = :hexagon -AND h3_get_destination_h3_index_from_unidirectional_edge(:uniedge) = :neighbor; - t - --- --- TEST h3_get_h3_indexes_from_unidirectional_edge --- -SELECT h3_get_h3_indexes_from_unidirectional_edge(:uniedge) = (:hexagon, :neighbor); - t - --- --- TEST h3_get_h3_unidirectional_edges_from_hexagon --- -SELECT array_length(array_agg(edge), 1) = 6 FROM ( - SELECT h3_get_h3_unidirectional_edges_from_hexagon(:hexagon) edge -) q; - t - -SELECT array_length(array_agg(edge), 1) = 5 expected FROM ( - SELECT h3_get_h3_unidirectional_edges_from_hexagon(:pentagon) edge -) q; - t - --- --- TEST h3_get_h3_unidirectional_edge_boundary --- -SELECT h3_get_h3_unidirectional_edge_boundary(:uniedge) - ~= polygon '((89.5830164946548,64.7146398954916),(89.5790678021742,64.2872231517217))' - t - diff --git a/h3/test/expected/vertex.out b/h3/test/expected/vertex.out new file mode 100644 index 00000000..d013a0a6 --- /dev/null +++ b/h3/test/expected/vertex.out @@ -0,0 +1,40 @@ +\pset tuples_only on +\set hexagon '\'880326b885fffff\'::h3index' +\set pentagon '\'831c00fffffffff\'::h3index' +\set vertex2 '\'2280326b885fffff\'::h3index' +\set geo POINT(65.60200108645547,89.57740563247555) +-- +-- TEST h3_cell_to_vertex +-- +SELECT h3_cell_to_vertex(:hexagon, 2) = :vertex2; + t + +-- +-- TEST h3_cell_to_vertexes +-- +SELECT COUNT(*) = 6 FROM ( + SELECT h3_cell_to_vertexes(:hexagon) +) q; + t + +SELECT COUNT(*) = 5 FROM ( + SELECT h3_cell_to_vertexes(:pentagon) +) q; + t + +-- +-- TEST h3_vertex_to_lat_lng +-- + +SELECT h3_vertex_to_lat_lng(:vertex2) ~= :geo; + t + +-- +-- TEST h3_is_valid_vertex and +-- +SELECT h3_is_valid_vertex(:vertex2); + t + +SELECT NOT h3_is_valid_vertex(:hexagon); + t + diff --git a/h3/test/sql/clustering.sql b/h3/test/sql/clustering.sql index ec70fb38..2bd729b4 100644 --- a/h3/test/sql/clustering.sql +++ b/h3/test/sql/clustering.sql @@ -3,7 +3,7 @@ \set hexagon ':string::h3index' CREATE TABLE h3_test_clustering (hex h3index PRIMARY KEY); -INSERT INTO h3_test_clustering (hex) SELECT * from h3_get_res_0_indexes(); +INSERT INTO h3_test_clustering (hex) SELECT * from h3_get_res_0_cells(); CREATE INDEX h3_test_clustering_index ON h3_test_clustering USING btree (hex); CLUSTER h3_test_clustering_index ON h3_test_clustering; -- diff --git a/h3/test/sql/edge.sql b/h3/test/sql/edge.sql new file mode 100644 index 00000000..0b4b6a17 --- /dev/null +++ b/h3/test/sql/edge.sql @@ -0,0 +1,58 @@ +\pset tuples_only on + +\set hexagon '\'880326b885fffff\'::h3index' +\set neighbor '\'880326b887fffff\'::h3index' +\set pentagon '\'831c00fffffffff\'::h3index' +\set edge '\'1180326b885fffff\'::h3index' + +-- +-- TEST h3_are_neighbor_cells +-- + +SELECT h3_are_neighbor_cells(:hexagon, :neighbor); +SELECT NOT h3_are_neighbor_cells(:hexagon, :hexagon); + +-- +-- TEST h3_cells_to_directed_edge +-- + +SELECT h3_cells_to_directed_edge(:hexagon, :neighbor) = :edge; + +-- +-- TEST h3_is_valid_directed_edge +-- + +SELECT h3_is_valid_directed_edge(:edge); +SELECT NOT h3_is_valid_directed_edge(:hexagon); + +-- +-- TEST h3_get_directed_edge_origin and +-- h3_get_directed_edge_destination +-- + +SELECT h3_get_directed_edge_origin(:edge) = :hexagon +AND h3_get_directed_edge_destination(:edge) = :neighbor; + +-- +-- TEST h3_directed_edge_to_cells +-- + +SELECT h3_directed_edge_to_cells(:edge) = (:hexagon, :neighbor); + +-- +-- TEST h3_origin_to_directed_edges +-- + +SELECT array_length(array_agg(edge), 1) = 6 FROM ( + SELECT h3_origin_to_directed_edges(:hexagon) edge +) q; +SELECT array_length(array_agg(edge), 1) = 5 expected FROM ( + SELECT h3_origin_to_directed_edges(:pentagon) edge +) q; + +-- +-- TEST h3_directed_edge_to_boundary +-- + +SELECT h3_directed_edge_to_boundary(:edge) + ~= polygon '((89.5830164946548,64.7146398954916),(89.5790678021742,64.2872231517217))' \ No newline at end of file diff --git a/h3/test/sql/hierarchy.sql b/h3/test/sql/hierarchy.sql index fe83721c..336439e3 100644 --- a/h3/test/sql/hierarchy.sql +++ b/h3/test/sql/hierarchy.sql @@ -6,81 +6,81 @@ \set resolution 3 -- --- TEST h3_to_children, h3_to_parent and h3_to_center_chil +-- TEST h3_cell_to_children, h3_cell_to_parent and h3_to_center_chil -- -- all parents of one the children of a hexagon, must be the original hexagon SELECT bool_and(i = :hexagon) FROM ( - SELECT h3_to_parent(h3_to_children(:hexagon)) i + SELECT h3_cell_to_parent(h3_cell_to_children(:hexagon)) i ) q; -- one child of the parent of a hexagon, must be the original hexagon SELECT bool_or(i = :hexagon) FROM ( - SELECT h3_to_children(h3_to_parent(:hexagon)) i + SELECT h3_cell_to_children(h3_cell_to_parent(:hexagon)) i ) q; -- all parents of one the children of a pentagon, must be the original pentagon SELECT bool_and(i = :pentagon) FROM ( - SELECT h3_to_parent(h3_to_children(:pentagon)) i + SELECT h3_cell_to_parent(h3_cell_to_children(:pentagon)) i ) q; -- one child of the parent of a pentagon, must be the original pentagon SELECT bool_or(i = :pentagon) FROM ( - SELECT h3_to_children(h3_to_parent(:pentagon)) i + SELECT h3_cell_to_children(h3_cell_to_parent(:pentagon)) i ) q; -- hexagon has 7 children SELECT array_length(array_agg(hex), 1) = 7 FROM ( - SELECT h3_to_children(:hexagon) hex + SELECT h3_cell_to_children(:hexagon) hex ) q; -- pentagon has 6 children SELECT array_length(array_agg(hex), 1) = 6 FROM ( - SELECT h3_to_children(:pentagon) hex + SELECT h3_cell_to_children(:pentagon) hex ) q; -- parent is one lower resolution -SELECT h3_get_resolution(h3_to_parent(:hexagon)) = :resolution -1; +SELECT h3_get_resolution(h3_cell_to_parent(:hexagon)) = :resolution -1; -- all children is one higher resolution SELECT bool_and(r = :resolution +1) FROM ( - SELECT h3_get_resolution(h3_to_children(:hexagon)) r + SELECT h3_get_resolution(h3_cell_to_children(:hexagon)) r ) q; -- parent of center child should be original index -SELECT :hexagon = h3_to_parent(h3_to_center_child(:hexagon, 15), :resolution); +SELECT :hexagon = h3_cell_to_parent(h3_cell_to_center_child(:hexagon, 15), :resolution); -- --- TEST h3_compact and h3_uncompact +-- TEST h3_compact_cells and h3_uncompact_cells -- -- compacts the children of two hexes into the original two hexes SELECT array_agg(result) is null FROM ( - SELECT h3_compact( - ARRAY(SELECT h3_to_children(:hexagon) UNION SELECT h3_to_children(:pentagon)) + SELECT h3_compact_cells( + ARRAY(SELECT h3_cell_to_children(:hexagon) UNION SELECT h3_cell_to_children(:pentagon)) ) result EXCEPT SELECT unnest(ARRAY[:hexagon, :pentagon]) result ) q; -- compact is inverse of uncompact -SELECT h3_compact(ARRAY(SELECT h3_uncompact(ARRAY[:hexagon], :resolution))) = :hexagon; +SELECT h3_compact_cells(ARRAY(SELECT h3_uncompact_cells(ARRAY[:hexagon], :resolution))) = :hexagon; -- uncompacts all to same resolution, gives same result as getting children SELECT array_agg(result) is null FROM ( - SELECT h3_uncompact(ARRAY( - SELECT h3_to_children(:hexagon) UNION SELECT :pentagon + SELECT h3_uncompact_cells(ARRAY( + SELECT h3_cell_to_children(:hexagon) UNION SELECT :pentagon ), :resolution +2) result EXCEPT ( - SELECT h3_to_children(:hexagon, :resolution +2) result - UNION SELECT h3_to_children(:pentagon, :resolution +2) result + SELECT h3_cell_to_children(:hexagon, :resolution +2) result + UNION SELECT h3_cell_to_children(:pentagon, :resolution +2) result ) ) q; -- --- TEST h3_to_children_slow +-- TEST h3_cell_to_children_slow -- --- h3_to_children_slow and h3_to_children have same result +-- h3_cell_to_children_slow and h3_cell_to_children have same result SELECT array_agg(result) is null FROM ( - SELECT h3_to_children_slow(:hexagon, :resolution + 3) result - EXCEPT SELECT h3_to_children(:hexagon, :resolution + 3) result + SELECT h3_cell_to_children_slow(:hexagon, :resolution + 3) result + EXCEPT SELECT h3_cell_to_children(:hexagon, :resolution + 3) result ) q; \ No newline at end of file diff --git a/h3/test/sql/indexing.sql b/h3/test/sql/indexing.sql index ad42e9e1..d8c07633 100644 --- a/h3/test/sql/indexing.sql +++ b/h3/test/sql/indexing.sql @@ -8,38 +8,51 @@ \set resolution 3 -- --- TEST h3_to_geo and h3_geo_to_h3 +-- TEST h3_cell_to_lat_lng and h3_lat_lng_to_cell -- -- convertion to geo works -SELECT h3_to_geo(:hexagon) ~= :geo; +SELECT h3_cell_to_lat_lng(:hexagon) ~= :geo; -- convertion to h3 index works -SELECT h3_geo_to_h3(:geo, :resolution) = :hexagon; +SELECT h3_lat_lng_to_cell(:geo, :resolution) = :hexagon; --- h3_to_geo is inverse of h3_geo_to_h3 -SELECT h3_to_geo(i) ~= :geo AND h3_get_resolution(i) = :resolution FROM ( - SELECT h3_geo_to_h3(:geo, :resolution) AS i +-- h3_cell_to_lat_lng is inverse of h3_lat_lng_to_cell +SELECT h3_cell_to_lat_lng(i) ~= :geo AND h3_get_resolution(i) = :resolution FROM ( + SELECT h3_lat_lng_to_cell(:geo, :resolution) AS i ) AS q; --- h3_geo_to_h3 is inverse of h3_to_geo -SELECT h3_geo_to_h3(g, r) = :hexagon FROM ( - SELECT h3_to_geo(:hexagon) AS g, h3_get_resolution(:hexagon) AS r +-- h3_lat_lng_to_cell is inverse of h3_cell_to_lat_lng +SELECT h3_lat_lng_to_cell(g, r) = :hexagon FROM ( + SELECT h3_cell_to_lat_lng(:hexagon) AS g, h3_get_resolution(:hexagon) AS r ) AS q; -- same for pentagon -SELECT h3_geo_to_h3(g, r) = :pentagon FROM ( - SELECT h3_to_geo(:pentagon) AS g, h3_get_resolution(:pentagon) AS r +SELECT h3_lat_lng_to_cell(g, r) = :pentagon FROM ( + SELECT h3_cell_to_lat_lng(:pentagon) AS g, h3_get_resolution(:pentagon) AS r ) AS q; -- --- TEST h3_to_geo_boundary +-- TEST h3_cell_to_boundary -- -- polyfill of geo boundary returns original index -SELECT h3_polyfill(h3_to_geo_boundary(:hexagon), null, :resolution) = :hexagon; +SELECT h3_polygon_to_cells(h3_cell_to_boundary(:hexagon), null, :resolution) = :hexagon; -- same for pentagon -SELECT h3_polyfill(h3_to_geo_boundary(:pentagon), null, :resolution) = :pentagon; +SELECT h3_polygon_to_cells(h3_cell_to_boundary(:pentagon), null, :resolution) = :pentagon; -- the boundary of an edgecrossing index is different with flag set to true -SELECT h3_to_geo_boundary(:hexagon) ~= h3_to_geo_boundary(:hexagon, true) -AND NOT h3_to_geo_boundary(:edgecross) ~= h3_to_geo_boundary(:edgecross, true); +SELECT h3_cell_to_boundary(:hexagon) ~= h3_cell_to_boundary(:hexagon, true) +AND NOT h3_cell_to_boundary(:edgecross) ~= h3_cell_to_boundary(:edgecross, true); + +-- cell to parent RES_MISMATCH +CREATE FUNCTION h3_fail_indexing_cell_to_parent() RETURNS boolean LANGUAGE PLPGSQL + AS $$ + BEGIN + PERFORM h3_cell_to_parent('831c02fffffffff', 10); + RETURN false; + EXCEPTION WHEN OTHERS THEN + RETURN true; + END; + $$; +SELECT h3_fail_indexing_cell_to_parent(); +DROP FUNCTION h3_fail_indexing_cell_to_parent; \ No newline at end of file diff --git a/h3/test/sql/inspection.sql b/h3/test/sql/inspection.sql index 164e442f..bb017713 100644 --- a/h3/test/sql/inspection.sql +++ b/h3/test/sql/inspection.sql @@ -13,26 +13,26 @@ SELECT h3_get_resolution(:hexagon) = :resolution AND h3_get_resolution(:pentagon) = :resolution; -- --- TEST h3_get_base_cell +-- TEST h3_get_base_cell_number -- -- base cell is same for parents -SELECT h3_get_base_cell(:hexagon) = h3_get_base_cell(h3_to_parent(:hexagon)); -SELECT h3_get_base_cell(:pentagon) = h3_get_base_cell(h3_to_parent(:pentagon)); +SELECT h3_get_base_cell_number(:hexagon) = h3_get_base_cell_number(h3_cell_to_parent(:hexagon)); +SELECT h3_get_base_cell_number(:pentagon) = h3_get_base_cell_number(h3_cell_to_parent(:pentagon)); -- --- TEST h3_is_valid +-- TEST h3_is_valid_cell -- -SELECT h3_is_valid(:hexagon) AND h3_is_valid(:pentagon) AND NOT h3_is_valid(:invalid); +SELECT h3_is_valid_cell(:hexagon) AND h3_is_valid_cell(:pentagon) AND NOT h3_is_valid_cell(:invalid); -- -- TEST h3_is_res_class_iii -- -- if index is Class III then parent is not -SELECT h3_is_res_class_iii(:hexagon) AND NOT h3_is_res_class_iii(h3_to_parent(:hexagon)); -SELECT h3_is_res_class_iii(:pentagon) AND NOT h3_is_res_class_iii(h3_to_parent(:pentagon)); +SELECT h3_is_res_class_iii(:hexagon) AND NOT h3_is_res_class_iii(h3_cell_to_parent(:hexagon)); +SELECT h3_is_res_class_iii(:pentagon) AND NOT h3_is_res_class_iii(h3_cell_to_parent(:pentagon)); -- -- TEST h3_is_pentagon @@ -41,7 +41,7 @@ SELECT h3_is_res_class_iii(:pentagon) AND NOT h3_is_res_class_iii(h3_to_parent(: SELECT h3_is_pentagon(:pentagon) AND NOT h3_is_pentagon(:hexagon); -- --- TEST h3_get_faces +-- TEST h3_get_icosahedron_faces -- -SELECT h3_get_faces('851c0047fffffff') = ARRAY[11,6]; -SELECT h3_get_faces('851c004bfffffff') = ARRAY[6]; +SELECT h3_get_icosahedron_faces('851c0047fffffff') = ARRAY[11,6]; +SELECT h3_get_icosahedron_faces('851c004bfffffff') = ARRAY[6]; diff --git a/h3/test/sql/miscellaneous.sql b/h3/test/sql/miscellaneous.sql index 64f08fee..6074c656 100644 --- a/h3/test/sql/miscellaneous.sql +++ b/h3/test/sql/miscellaneous.sql @@ -2,75 +2,75 @@ \set degs 90.45 \set rads 1.57865030842887 \set epsilon 0.0000000000001 -\set uniedge '\'1180326b885fffff\'::h3index' +\set edge '\'1180326b885fffff\'::h3index' -- --- TEST h3_point_dist +-- TEST h3_great_circle_distance -- \set lyon POINT(4.8422, 45.7597) \set paris POINT(2.3508, 48.8567) -SELECT h3_point_dist(:lyon, :paris, 'rads') - 0.0615628186794217 < :epsilon; -SELECT h3_point_dist(:lyon, :paris, 'm') - 392217.1598841777 < :epsilon; -SELECT h3_point_dist(:lyon, :paris, 'km') - 392.21715988417765 < :epsilon; +SELECT h3_great_circle_distance(:lyon, :paris, 'rads') - 0.0615628186794217 < :epsilon; +SELECT h3_great_circle_distance(:lyon, :paris, 'm') - 392217.1598841777 < :epsilon; +SELECT h3_great_circle_distance(:lyon, :paris, 'km') - 392.21715988417765 < :epsilon; -- test that 'km' is the default unit -SELECT h3_point_dist(:lyon, :paris, 'km') = h3_point_dist(:lyon, :paris); +SELECT h3_great_circle_distance(:lyon, :paris, 'km') = h3_great_circle_distance(:lyon, :paris); -- --- TEST h3_hex_area +-- TEST h3_get_hexagon_area_avg -- -SELECT h3_hex_area(10, 'm') = 15047.5; -SELECT h3_hex_area(10, 'km') = 0.0150475; -SELECT h3_hex_area(10, 'km') = h3_hex_area(10); +SELECT abs(h3_get_hexagon_area_avg(10, 'm') - 15047.50190766437) < :epsilon; +SELECT abs(h3_get_hexagon_area_avg(10, 'km') - 0.01504750190766435) < :epsilon; +SELECT h3_get_hexagon_area_avg(10, 'km') = h3_get_hexagon_area_avg(10); -- -- TEST h3_cell_area -- \set expected_km2 0.01119834221989390 -SELECT abs((h3_cell_area(h3_geo_to_h3(POINT(0, 0), 10), 'm^2') / 1000000) - :expected_km2) < :epsilon; -SELECT abs(h3_cell_area(h3_geo_to_h3(POINT(0, 0), 10), 'km^2') - :expected_km2) < :epsilon; -SELECT h3_cell_area(h3_geo_to_h3(POINT(0, 0), 10), 'rads^2') > 0; +SELECT abs((h3_cell_area(h3_lat_lng_to_cell(POINT(0, 0), 10), 'm^2') / 1000000) - :expected_km2) < :epsilon; +SELECT abs(h3_cell_area(h3_lat_lng_to_cell(POINT(0, 0), 10), 'km^2') - :expected_km2) < :epsilon; +SELECT h3_cell_area(h3_lat_lng_to_cell(POINT(0, 0), 10), 'rads^2') > 0; -- default is km^2 -SELECT h3_cell_area(h3_geo_to_h3(POINT(0, 0), 10), 'km^2') = h3_cell_area(h3_geo_to_h3(POINT(0, 0), 10)); +SELECT h3_cell_area(h3_lat_lng_to_cell(POINT(0, 0), 10), 'km^2') = h3_cell_area(h3_lat_lng_to_cell(POINT(0, 0), 10)); -- --- TEST h3_edge_length +-- TEST h3_get_hexagon_edge_length_avg -- -SELECT h3_edge_length(10, 'm') = 65.90780749; -SELECT h3_edge_length(10, 'km') = 0.065907807; -SELECT h3_edge_length(10, 'km') = h3_edge_length(10); +SELECT h3_get_hexagon_edge_length_avg(10, 'm') = 65.90780749; +SELECT h3_get_hexagon_edge_length_avg(10, 'km') = 0.065907807; +SELECT h3_get_hexagon_edge_length_avg(10, 'km') = h3_get_hexagon_edge_length_avg(10); -- --- TEST h3_exact_edge_length +-- TEST h3_edge_length -- -SELECT h3_exact_edge_length(:uniedge, 'rads') > 0; -SELECT h3_exact_edge_length(:uniedge, 'km') > h3_exact_edge_length(:uniedge, 'rads'); -SELECT h3_exact_edge_length(:uniedge, 'm') > h3_exact_edge_length(:uniedge, 'km'); +SELECT h3_edge_length(:edge, 'rads') > 0; +SELECT h3_edge_length(:edge, 'km') > h3_edge_length(:edge, 'rads'); +SELECT h3_edge_length(:edge, 'm') > h3_edge_length(:edge, 'km'); -SELECT h3_exact_edge_length(:uniedge) = h3_exact_edge_length(:uniedge, 'km'); +SELECT h3_edge_length(:edge) = h3_edge_length(:edge, 'km'); -- --- TEST h3_num_hexagons +-- TEST h3_get_num_cells -- -SELECT h3_num_hexagons(0) = 122; -SELECT h3_num_hexagons(15) = 569707381193162; +SELECT h3_get_num_cells(0) = 122; +SELECT h3_get_num_cells(15) = 569707381193162; -- --- TEST h3_get_res_0_indexes +-- TEST h3_get_res_0_cells -- -SELECT COUNT(*) = 122 FROM (SELECT h3_get_res_0_indexes()) q; +SELECT COUNT(*) = 122 FROM (SELECT h3_get_res_0_cells()) q; -- --- TEST h3_get_pentagon_indexes +-- TEST h3_get_pentagons -- -SELECT COUNT(*) = 12 FROM (SELECT h3_get_pentagon_indexes(6)) q; \ No newline at end of file +SELECT COUNT(*) = 12 FROM (SELECT h3_get_pentagons(6)) q; \ No newline at end of file diff --git a/h3/test/sql/opclass_btree.sql b/h3/test/sql/opclass_btree.sql index 8c4d7608..b92c434e 100644 --- a/h3/test/sql/opclass_btree.sql +++ b/h3/test/sql/opclass_btree.sql @@ -3,7 +3,7 @@ \set hexagon ':string::h3index' CREATE TABLE h3_test_btree (hex h3index PRIMARY KEY); -INSERT INTO h3_test_btree (hex) SELECT * from h3_get_res_0_indexes(); +INSERT INTO h3_test_btree (hex) SELECT * from h3_get_res_0_cells(); CREATE INDEX h3_btree ON h3_test_btree USING btree (hex); -- -- TEST b-tree operator class diff --git a/h3/test/sql/opclass_hash.sql b/h3/test/sql/opclass_hash.sql index 62f7bd91..751c840a 100644 --- a/h3/test/sql/opclass_hash.sql +++ b/h3/test/sql/opclass_hash.sql @@ -1,14 +1,14 @@ \pset tuples_only on CREATE TABLE h3_test_hash (hex h3index PRIMARY KEY); -INSERT INTO h3_test_hash (hex) SELECT * from h3_get_res_0_indexes(); +INSERT INTO h3_test_hash (hex) SELECT * from h3_get_res_0_cells(); CREATE INDEX h3_btree ON h3_test_hash USING hash (hex); -- -- TEST hash operator class -- SELECT COUNT(hex) = 122 FROM ( - SELECT hex FROM h3_test_hash WHERE hex IN (SELECT h3_get_res_0_indexes()) + SELECT hex FROM h3_test_hash WHERE hex IN (SELECT h3_get_res_0_cells()) ) q; CREATE TABLE h3_test_hash_part (hex h3index PRIMARY KEY) PARTITION BY HASH (hex); \ No newline at end of file diff --git a/h3/test/sql/postgis.sql b/h3/test/sql/postgis.sql index 7ca25572..a430e389 100644 --- a/h3/test/sql/postgis.sql +++ b/h3/test/sql/postgis.sql @@ -4,23 +4,28 @@ \set hexagon '\'8a63a9a99047fff\'' \set meter ST_SetSRID(ST_Point(6196902.235389061,1413172.0833316022), 3857) \set degree ST_SetSRID(ST_Point(55.6677199224442,12.592131261648213), 4326) +-- polygon with 2 holes +\set with2holes '\'POLYGON((31.6520834 68.9912098,31.6521263 68.9910944,31.6530919 68.9912021,31.6540789 68.9912944,31.6550016 68.991279,31.6553449 68.9910175,31.6554737 68.9907713,31.6559458 68.990402,31.6563535 68.9900789,31.6568684 68.9897404,31.6569543 68.9895711,31.6567182 68.988671,31.6569114 68.9881786,31.6571045 68.9879401,31.6567611 68.9875708,31.6570401 68.9873015,31.6576195 68.986986,31.6581774 68.9868398,31.6584992 68.9870553,31.6586065 68.9872707,31.6590786 68.9873246,31.6594219 68.9872091,31.6596579 68.9870091,31.6596579 68.9867706,31.6601515 68.9866167,31.6607308 68.9864551,31.660409 68.986232,31.6601729 68.9860627,31.6605806 68.9859319,31.6614818 68.9859011,31.6620183 68.9857087,31.6622972 68.9854471,31.6628337 68.9852932,31.6633701 68.9852855,31.663928 68.9855702,31.6640782 68.9859088,31.6636705 68.9862166,31.6639924 68.9864859,31.664443 68.9868629,31.664679 68.9872091,31.6642928 68.9873784,31.6641426 68.9876939,31.6650009 68.9879016,31.6652155 68.9881555,31.6653657 68.9883709,31.6659665 68.9886941,31.6662884 68.9889941,31.666739 68.989248,31.6669321 68.9891095,31.6670394 68.9888787,31.6681123 68.9889326,31.6687345 68.989325,31.6692495 68.9895865,31.6701937 68.9897635,31.6710949 68.9897404,31.6725325 68.9897558,31.6733479 68.9898558,31.6743135 68.9904097,31.674571 68.990702,31.6747641 68.9909328,31.6745066 68.9911405,31.6738844 68.9912636,31.6731977 68.9914175,31.6734981 68.9916098,31.6739487 68.9915713,31.6744852 68.9915175,31.6750431 68.9914021,31.6751718 68.9911944,31.6752147 68.9910405,31.6756439 68.9910636,31.6765451 68.9912021,31.6777253 68.9912944,31.6784119 68.9912482,31.6790771 68.9911559,31.6793346 68.9913021,31.6787553 68.9916713,31.678133 68.9920867,31.6780472 68.9924483,31.6782617 68.9927098,31.6792702 68.9941098,31.6794419 68.9943636,31.6801715 68.9945328,31.6817808 68.9946328,31.6825533 68.9948174,31.6827249 68.995202,31.683712 68.9957404,31.6840124 68.9962634,31.684699 68.9965556,31.6848492 68.9968171,31.6841197 68.9969632,31.6831326 68.9969479,31.6827464 68.9969171,31.6824031 68.9968556,31.6821456 68.9967248,31.6813302 68.9968248,31.6810083 68.9971094,31.6806865 68.9971863,31.6802358 68.9971401,31.6792702 68.9967018,31.6787553 68.9963864,31.6780901 68.9958327,31.6777038 68.9956788,31.6766095 68.9955635,31.6762233 68.9954943,31.6759658 68.9952943,31.6753649 68.9951481,31.6746354 68.9952712,31.6735625 68.9951866,31.6728329 68.9951866,31.6726398 68.9953943,31.6719746 68.9955173,31.6709661 68.9954173,31.6704941 68.9951558,31.6700434 68.9948251,31.669743 68.9944867,31.6695285 68.994179,31.6693783 68.9939329,31.6690779 68.993756,31.6680479 68.9935867,31.663692 68.9929329,31.6628551 68.9927637,31.661675 68.9927637,31.6610527 68.9929637,31.6605377 68.9929714,31.6599583 68.9929406,31.6588855 68.9928175,31.658349 68.992656,31.657598 68.9923714,31.6567826 68.9922329,31.6552162 68.9920714,31.6541648 68.9919175,31.6531348 68.9916483,31.6523838 68.9914175,31.6520834 68.9912098),(31.657185 68.990202,31.657244 68.9903482,31.6574585 68.9903809,31.6578555 68.9903597,31.6581452 68.9902539,31.6583651 68.9900924,31.6582364 68.9899366,31.6578716 68.9898616,31.6575766 68.9898731,31.6573083 68.9899808,31.6572332 68.9900731,31.657185 68.990202),(31.6590196 68.9886094,31.6591644 68.9887229,31.6594058 68.9888537,31.6595936 68.9889557,31.6596794 68.9890441,31.6597116 68.9891345,31.659776 68.9892519,31.6599476 68.9891903,31.660012 68.9890614,31.6601139 68.9889383,31.6602641 68.9888326,31.6602749 68.988721,31.6601998 68.988596,31.6600603 68.988369,31.6601676 68.9882709,31.6604251 68.9882844,31.6607255 68.9882728,31.6609454 68.9881767,31.6605592 68.9880901,31.6604841 68.9879689,31.6603607 68.9878497,31.660071 68.9878843,31.6597867 68.9879959,31.6593575 68.9880305,31.6592127 68.9881132,31.6592234 68.9882421,31.6592127 68.9883786,31.6590196 68.9886094))\''::geometry(POLYGON) -SELECT h3_geo_to_h3(:degree, :resolution) = '8a63a9a99047fff'; +CREATE EXTENSION postgis; +CREATE EXTENSION h3_postgis; + +SELECT h3_lat_lng_to_cell(:degree, :resolution) = '8a63a9a99047fff'; -- meters are NOT reprojected -SELECT h3_geo_to_h3(:meter, :resolution) <> '8a63a9a99047fff'; +SELECT h3_lat_lng_to_cell(:meter, :resolution) <> '8a63a9a99047fff'; -- check back/forth conversion return same hex -SELECT h3_geo_to_h3(h3_to_geometry(:hexagon), :resolution) = '8a63a9a99047fff'; +SELECT h3_lat_lng_to_cell(h3_cell_to_geometry(:hexagon), :resolution) = '8a63a9a99047fff'; -- check num points in boundary -SELECT ST_NPoints( h3_to_geo_boundary_geometry(:hexagon)) = 7; +SELECT ST_NPoints(h3_cell_to_boundary_geometry(:hexagon)) = 7; --- test strict h3_geo_to_h3 throws for bad latlon +-- test strict h3_lat_lng_to_cell throws for bad latlon CREATE FUNCTION h3_test_postgis_nounit() RETURNS boolean LANGUAGE PLPGSQL AS $$ BEGIN - PERFORM h3_geo_to_h3(POINT(360, 2.592131261648213), 1); + PERFORM h3_lat_lng_to_cell(POINT(360, 2.592131261648213), 1); RETURN false; EXCEPTION WHEN OTHERS THEN RETURN true; @@ -34,8 +39,13 @@ DROP FUNCTION h3_test_postgis_nounit; -- Test wraparound \set lon 55.6677199224442 \set lat 12.592131261648213 -SELECT h3_geo_to_h3(POINT(:lon, :lat), 7) - = h3_geo_to_h3(POINT(:lon + 360, :lat), 7); +SELECT h3_lat_lng_to_cell(POINT(:lon, :lat), 7) + = h3_lat_lng_to_cell(POINT(:lon + 360, :lat), 7); + +SELECT h3_lat_lng_to_cell(POINT(:lon, :lat ), 7) + = h3_lat_lng_to_cell(POINT(:lon, :lat + 360), 7); -SELECT h3_geo_to_h3(POINT(:lon, :lat ), 7) - = h3_geo_to_h3(POINT(:lon, :lat + 360), 7); \ No newline at end of file +-- h3_polygon_to_cells works for polygon with two holes +SELECT COUNT(*) = 48 FROM ( + SELECT h3_polygon_to_cells(:with2holes, 10) +) q; \ No newline at end of file diff --git a/h3/test/sql/regions.sql b/h3/test/sql/regions.sql index ccb8ad3e..5133caeb 100644 --- a/h3/test/sql/regions.sql +++ b/h3/test/sql/regions.sql @@ -4,43 +4,36 @@ -- center hex \set center '\'81583ffffffffff\'' -- 7 child hexes in res 0 index -\set solid 'ARRAY(SELECT h3_to_children(:res0index, 1))' +\set solid 'ARRAY(SELECT h3_cell_to_children(:res0index, 1))' -- 6 child hexes in rim of res 0 index \set hollow 'array_remove(:solid, :center)' --- polygon with 2 holes -\set with2holes '\'POLYGON((31.6520834 68.9912098,31.6521263 68.9910944,31.6530919 68.9912021,31.6540789 68.9912944,31.6550016 68.991279,31.6553449 68.9910175,31.6554737 68.9907713,31.6559458 68.990402,31.6563535 68.9900789,31.6568684 68.9897404,31.6569543 68.9895711,31.6567182 68.988671,31.6569114 68.9881786,31.6571045 68.9879401,31.6567611 68.9875708,31.6570401 68.9873015,31.6576195 68.986986,31.6581774 68.9868398,31.6584992 68.9870553,31.6586065 68.9872707,31.6590786 68.9873246,31.6594219 68.9872091,31.6596579 68.9870091,31.6596579 68.9867706,31.6601515 68.9866167,31.6607308 68.9864551,31.660409 68.986232,31.6601729 68.9860627,31.6605806 68.9859319,31.6614818 68.9859011,31.6620183 68.9857087,31.6622972 68.9854471,31.6628337 68.9852932,31.6633701 68.9852855,31.663928 68.9855702,31.6640782 68.9859088,31.6636705 68.9862166,31.6639924 68.9864859,31.664443 68.9868629,31.664679 68.9872091,31.6642928 68.9873784,31.6641426 68.9876939,31.6650009 68.9879016,31.6652155 68.9881555,31.6653657 68.9883709,31.6659665 68.9886941,31.6662884 68.9889941,31.666739 68.989248,31.6669321 68.9891095,31.6670394 68.9888787,31.6681123 68.9889326,31.6687345 68.989325,31.6692495 68.9895865,31.6701937 68.9897635,31.6710949 68.9897404,31.6725325 68.9897558,31.6733479 68.9898558,31.6743135 68.9904097,31.674571 68.990702,31.6747641 68.9909328,31.6745066 68.9911405,31.6738844 68.9912636,31.6731977 68.9914175,31.6734981 68.9916098,31.6739487 68.9915713,31.6744852 68.9915175,31.6750431 68.9914021,31.6751718 68.9911944,31.6752147 68.9910405,31.6756439 68.9910636,31.6765451 68.9912021,31.6777253 68.9912944,31.6784119 68.9912482,31.6790771 68.9911559,31.6793346 68.9913021,31.6787553 68.9916713,31.678133 68.9920867,31.6780472 68.9924483,31.6782617 68.9927098,31.6792702 68.9941098,31.6794419 68.9943636,31.6801715 68.9945328,31.6817808 68.9946328,31.6825533 68.9948174,31.6827249 68.995202,31.683712 68.9957404,31.6840124 68.9962634,31.684699 68.9965556,31.6848492 68.9968171,31.6841197 68.9969632,31.6831326 68.9969479,31.6827464 68.9969171,31.6824031 68.9968556,31.6821456 68.9967248,31.6813302 68.9968248,31.6810083 68.9971094,31.6806865 68.9971863,31.6802358 68.9971401,31.6792702 68.9967018,31.6787553 68.9963864,31.6780901 68.9958327,31.6777038 68.9956788,31.6766095 68.9955635,31.6762233 68.9954943,31.6759658 68.9952943,31.6753649 68.9951481,31.6746354 68.9952712,31.6735625 68.9951866,31.6728329 68.9951866,31.6726398 68.9953943,31.6719746 68.9955173,31.6709661 68.9954173,31.6704941 68.9951558,31.6700434 68.9948251,31.669743 68.9944867,31.6695285 68.994179,31.6693783 68.9939329,31.6690779 68.993756,31.6680479 68.9935867,31.663692 68.9929329,31.6628551 68.9927637,31.661675 68.9927637,31.6610527 68.9929637,31.6605377 68.9929714,31.6599583 68.9929406,31.6588855 68.9928175,31.658349 68.992656,31.657598 68.9923714,31.6567826 68.9922329,31.6552162 68.9920714,31.6541648 68.9919175,31.6531348 68.9916483,31.6523838 68.9914175,31.6520834 68.9912098),(31.657185 68.990202,31.657244 68.9903482,31.6574585 68.9903809,31.6578555 68.9903597,31.6581452 68.9902539,31.6583651 68.9900924,31.6582364 68.9899366,31.6578716 68.9898616,31.6575766 68.9898731,31.6573083 68.9899808,31.6572332 68.9900731,31.657185 68.990202),(31.6590196 68.9886094,31.6591644 68.9887229,31.6594058 68.9888537,31.6595936 68.9889557,31.6596794 68.9890441,31.6597116 68.9891345,31.659776 68.9892519,31.6599476 68.9891903,31.660012 68.9890614,31.6601139 68.9889383,31.6602641 68.9888326,31.6602749 68.988721,31.6601998 68.988596,31.6600603 68.988369,31.6601676 68.9882709,31.6604251 68.9882844,31.6607255 68.9882728,31.6609454 68.9881767,31.6605592 68.9880901,31.6604841 68.9879689,31.6603607 68.9878497,31.660071 68.9878843,31.6597867 68.9879959,31.6593575 68.9880305,31.6592127 68.9881132,31.6592234 68.9882421,31.6592127 68.9883786,31.6590196 68.9886094))\''::geometry(POLYGON) -- pentagon \set pentagon '\'831c00fffffffff\'::h3index' -- --- TEST h3_polyfill and h3_set_to_multi_polygon +-- TEST h3_polygon_to_cells and h3_cells_to_multi_polygon -- --- h3_polyfill is inverse of h3_set_to_multi_polygon for set without holes +-- h3_polygon_to_cells is inverse of h3_cells_to_multi_polygon for set without holes SELECT array_agg(result) is null FROM ( - SELECT h3_polyfill(exterior, holes, 1) result FROM ( - SELECT exterior, holes FROM h3_set_to_multi_polygon(:solid) + SELECT h3_polygon_to_cells(exterior, holes, 1) result FROM ( + SELECT exterior, holes FROM h3_cells_to_multi_polygon(:solid) ) qq EXCEPT SELECT unnest(:solid) result ) q; --- h3_polyfill is inverse of h3_set_to_multi_polygon for set with a hole +-- h3_polygon_to_cells is inverse of h3_cells_to_multi_polygon for set with a hole SELECT array_agg(result) is null FROM ( - SELECT h3_polyfill(exterior, holes, 1) result FROM ( - SELECT exterior, holes FROM h3_set_to_multi_polygon(:hollow) + SELECT h3_polygon_to_cells(exterior, holes, 1) result FROM ( + SELECT exterior, holes FROM h3_cells_to_multi_polygon(:hollow) ) qq EXCEPT SELECT unnest(:hollow) result ) q; --- h3_polyfill works for polygon with two holes -SELECT COUNT(*) = 48 FROM ( - SELECT h3_polyfill(:with2holes, 10) -) q; - -- h3_polyfill doesn't segfault on NULL value in holes SELECT TRUE FROM ( - SELECT h3_polyfill(exterior, ARRAY[NULL::POLYGON], 1) result FROM ( - SELECT exterior, holes FROM h3_set_to_multi_polygon( + SELECT h3_polygon_to_cells(exterior, ARRAY[NULL::POLYGON], 1) result FROM ( + SELECT exterior, holes FROM h3_cells_to_multi_polygon( ARRAY[:pentagon]::H3Index[] ) ) qq @@ -68,4 +61,4 @@ CREATE FUNCTION h3_test_polyfill_bad2() RETURNS boolean LANGUAGE PLPGSQL SELECT h3_test_polyfill_bad1(); SELECT h3_test_polyfill_bad2(); DROP FUNCTION h3_test_polyfill_bad1; -DROP FUNCTION h3_test_polyfill_bad2; \ No newline at end of file +DROP FUNCTION h3_test_polyfill_bad2; diff --git a/h3/test/sql/traversal.sql b/h3/test/sql/traversal.sql index 83c0d651..17d2ac1f 100644 --- a/h3/test/sql/traversal.sql +++ b/h3/test/sql/traversal.sql @@ -4,26 +4,26 @@ \set pentagon '\'831c00fffffffff\'' -- --- TEST h3_k_ring and h3_hex_ring +-- TEST h3_grid_disk and h3_grid_ring_unsafe -- --- kRing 0 is input index +-- gridDisk 0 is input index -SELECT h3_k_ring(:hexagon, 0) = :hexagon; +SELECT h3_grid_disk(:hexagon, 0) = :hexagon; --- kRing 2 is same as sum of hexRing 0, 1 and 2 +-- gridDisk 2 is same as sum of gridRing 0, 1 and 2 SELECT array_agg(r) is null FROM ( - SELECT h3_k_ring(:hexagon, 2) r + SELECT h3_grid_disk(:hexagon, 2) r EXCEPT ( - SELECT h3_hex_ring(:hexagon, 0) r - UNION SELECT h3_hex_ring(:hexagon, 1) r - UNION SELECT h3_hex_ring(:hexagon, 2) r + SELECT h3_grid_ring_unsafe(:hexagon, 0) r + UNION SELECT h3_grid_ring_unsafe(:hexagon, 1) r + UNION SELECT h3_grid_ring_unsafe(:hexagon, 2) r ) ) q; -- --- TEST h3_k_ring_distances +-- TEST h3_grid_disk_distances -- -- correct number of indexes at distances 0, 1 and 2 for k=2 @@ -31,7 +31,7 @@ SELECT COUNT(index) filter (WHERE distance = 0) = 1 AND COUNT(index) filter (WHERE distance = 1) = 6 AND COUNT(index) filter (WHERE distance = 2) = 12 FROM ( - SELECT index, distance FROM h3_k_ring_distances(:hexagon, 2) + SELECT index, distance FROM h3_grid_disk_distances(:hexagon, 2) ) q; -- same for pentagon @@ -39,29 +39,38 @@ SELECT COUNT(index) filter (WHERE distance = 0) = 1 AND COUNT(index) filter (WHERE distance = 1) = 5 AND COUNT(index) filter (WHERE distance = 2) = 10 FROM ( - SELECT index, distance FROM h3_k_ring_distances(:pentagon, 2) + SELECT index, distance FROM h3_grid_disk_distances(:pentagon, 2) ) q; -- --- TEST h3_line +-- TEST h3_grid_path_cells -- -SELECT ARRAY(SELECT h3_line('841c023ffffffff', '841c025ffffffff')) +SELECT ARRAY(SELECT h3_grid_path_cells('841c023ffffffff', '841c025ffffffff')) = ARRAY['841c023ffffffff','841c027ffffffff','841c025ffffffff']::h3index[]; -- --- TEST h3_distance +-- TEST h3_grid_distance -- -- returns 1 for indexes with one index between them -SELECT h3_distance('880326b881fffff', '880326b885fffff') = 1; +SELECT h3_grid_distance('880326b881fffff', '880326b885fffff') = 1; --- returns -1 for invalid inputs -SELECT h3_distance('880326b881fffff', h3_to_parent('880326b885fffff')) = -1; +-- throws for invalid inputs +CREATE FUNCTION h3_test_grid_distance_invalid() RETURNS boolean LANGUAGE PLPGSQL + AS $$ + BEGIN + PERFORM h3_grid_distance('880326b881fffff', h3_cell_to_parent('880326b885fffff')) = -1; + RETURN false; + EXCEPTION WHEN OTHERS THEN + RETURN true; + END; + $$; +SELECT h3_test_grid_distance_invalid(); -- --- TEST h3_experimental_h3_to_local_ij and h3_experimental_local_ij_to_h3 +-- TEST h3_cell_to_local_ij and h3_local_ij_to_cell -- -- they are inverse of each others -SELECT :hexagon = h3_experimental_local_ij_to_h3(:origin, h3_experimental_h3_to_local_ij(:origin, :hexagon)); \ No newline at end of file +SELECT :hexagon = h3_local_ij_to_cell(:origin, h3_cell_to_local_ij(:origin, :hexagon)); \ No newline at end of file diff --git a/h3/test/sql/type.sql b/h3/test/sql/type.sql index d6cccfb5..0ee50859 100644 --- a/h3/test/sql/type.sql +++ b/h3/test/sql/type.sql @@ -11,9 +11,9 @@ SELECT :hexagon = :hexagon; SELECT NOT :hexagon = :pentagon; SELECT NOT :hexagon <> :hexagon; SELECT :hexagon <> :pentagon; -SELECT :pentagon <@ h3_to_parent(:pentagon); +SELECT :pentagon <@ h3_cell_to_parent(:pentagon); SELECT bool_and(:pentagon @> c) FROM ( - SELECT h3_to_children(:pentagon) c + SELECT h3_cell_to_children(:pentagon) c ) q; -- diff --git a/h3/test/sql/uniedges.sql b/h3/test/sql/uniedges.sql deleted file mode 100644 index 4177f25e..00000000 --- a/h3/test/sql/uniedges.sql +++ /dev/null @@ -1,58 +0,0 @@ -\pset tuples_only on - -\set hexagon '\'880326b885fffff\'::h3index' -\set neighbor '\'880326b887fffff\'::h3index' -\set pentagon '\'831c00fffffffff\'::h3index' -\set uniedge '\'1180326b885fffff\'::h3index' - --- --- TEST h3_indexes_are_neighbors --- - -SELECT h3_indexes_are_neighbors(:hexagon, :neighbor); -SELECT NOT h3_indexes_are_neighbors(:hexagon, :hexagon); - --- --- TEST h3_get_h3_unidirectional_edge --- - -SELECT h3_get_h3_unidirectional_edge(:hexagon, :neighbor) = :uniedge; - --- --- TEST h3_unidirectional_edge_is_valid --- - -SELECT h3_unidirectional_edge_is_valid(:uniedge); -SELECT NOT h3_unidirectional_edge_is_valid(:hexagon); - --- --- TEST h3_get_origin_h3_index_from_unidirectional_edge and --- h3_get_destination_h3_index_from_unidirectional_edge --- - -SELECT h3_get_origin_h3_index_from_unidirectional_edge(:uniedge) = :hexagon -AND h3_get_destination_h3_index_from_unidirectional_edge(:uniedge) = :neighbor; - --- --- TEST h3_get_h3_indexes_from_unidirectional_edge --- - -SELECT h3_get_h3_indexes_from_unidirectional_edge(:uniedge) = (:hexagon, :neighbor); - --- --- TEST h3_get_h3_unidirectional_edges_from_hexagon --- - -SELECT array_length(array_agg(edge), 1) = 6 FROM ( - SELECT h3_get_h3_unidirectional_edges_from_hexagon(:hexagon) edge -) q; -SELECT array_length(array_agg(edge), 1) = 5 expected FROM ( - SELECT h3_get_h3_unidirectional_edges_from_hexagon(:pentagon) edge -) q; - --- --- TEST h3_get_h3_unidirectional_edge_boundary --- - -SELECT h3_get_h3_unidirectional_edge_boundary(:uniedge) - ~= polygon '((89.5830164946548,64.7146398954916),(89.5790678021742,64.2872231517217))' \ No newline at end of file diff --git a/h3/test/sql/vertex.sql b/h3/test/sql/vertex.sql new file mode 100644 index 00000000..d7d294be --- /dev/null +++ b/h3/test/sql/vertex.sql @@ -0,0 +1,37 @@ +\pset tuples_only on + +\set hexagon '\'880326b885fffff\'::h3index' +\set pentagon '\'831c00fffffffff\'::h3index' +\set vertex2 '\'2280326b885fffff\'::h3index' +\set geo POINT(65.60200108645547,89.57740563247555) + +-- +-- TEST h3_cell_to_vertex +-- + +SELECT h3_cell_to_vertex(:hexagon, 2) = :vertex2; + +-- +-- TEST h3_cell_to_vertexes +-- + +SELECT COUNT(*) = 6 FROM ( + SELECT h3_cell_to_vertexes(:hexagon) +) q; + +SELECT COUNT(*) = 5 FROM ( + SELECT h3_cell_to_vertexes(:pentagon) +) q; + +-- +-- TEST h3_vertex_to_lat_lng +-- + +SELECT h3_vertex_to_lat_lng(:vertex2) ~= :geo; + +-- +-- TEST h3_is_valid_vertex and +-- + +SELECT h3_is_valid_vertex(:vertex2); +SELECT NOT h3_is_valid_vertex(:hexagon); \ No newline at end of file diff --git a/h3_postgis.control b/h3_postgis.control new file mode 100644 index 00000000..094cca7a --- /dev/null +++ b/h3_postgis.control @@ -0,0 +1,4 @@ +comment = 'H3 PostGIS integration' +default_version = '4.0.0' +relocatable = true +requires = 'h3, postgis' diff --git a/h3_postgis/sql/install/01-indexing.sql b/h3_postgis/sql/install/01-indexing.sql new file mode 100644 index 00000000..eb76f41d --- /dev/null +++ b/h3_postgis/sql/install/01-indexing.sql @@ -0,0 +1,41 @@ +/* + * Copyright 2019-2022 Bytes & Brains + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +--| # PostGIS Indexing Functions + +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION h3_lat_lng_to_cell(geometry, resolution integer) RETURNS h3index + AS $$ SELECT h3_lat_lng_to_cell($1::point, $2); $$ IMMUTABLE STRICT PARALLEL SAFE LANGUAGE SQL; + +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION h3_lat_lng_to_cell(geography, resolution integer) RETURNS h3index + AS $$ SELECT h3_lat_lng_to_cell($1::geometry, $2); $$ IMMUTABLE STRICT PARALLEL SAFE LANGUAGE SQL; + +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION h3_cell_to_geometry(h3index) RETURNS geometry + AS $$ SELECT ST_SetSRID(h3_cell_to_lat_lng($1)::geometry, 4326) $$ IMMUTABLE STRICT PARALLEL SAFE LANGUAGE SQL; + +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION h3_cell_to_geography(h3index) RETURNS geography + AS $$ SELECT h3_cell_to_geometry($1)::geography $$ IMMUTABLE STRICT PARALLEL SAFE LANGUAGE SQL; + +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION h3_cell_to_boundary_geometry(h3index, extend boolean DEFAULT FALSE) RETURNS geometry + AS $$ SELECT ST_SetSRID(h3_cell_to_boundary($1, $2)::geometry, 4326) $$ IMMUTABLE STRICT PARALLEL SAFE LANGUAGE SQL; + +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION h3_cell_to_boundary_geography(h3index, extend boolean DEFAULT FALSE) RETURNS geography + AS $$ SELECT h3_cell_to_boundary_geometry($1, $2)::geography $$ IMMUTABLE STRICT PARALLEL SAFE LANGUAGE SQL; diff --git a/h3_postgis/sql/install/05-regions.sql b/h3_postgis/sql/install/05-regions.sql new file mode 100644 index 00000000..310cefa7 --- /dev/null +++ b/h3_postgis/sql/install/05-regions.sql @@ -0,0 +1,42 @@ +/* + * Copyright 2019-2022 Bytes & Brains + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +--| # PostGIS Region Functions + +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION h3_polygon_to_cells(multi geometry, resolution integer) RETURNS SETOF h3index + AS $$ SELECT h3_polygon_to_cells(exterior, holes, resolution) FROM ( + SELECT + -- extract exterior ring of each polygon + ST_MakePolygon(ST_ExteriorRing(poly))::polygon exterior, + -- extract holes of each polygon + (SELECT array_agg(hole) + FROM ( + SELECT ST_MakePolygon(ST_InteriorRingN( + poly, + generate_series(1, ST_NumInteriorRings(poly)) + ))::polygon AS hole + ) q_hole + ) holes + -- extract single polygons from multipolygon + FROM ( + select (st_dump(multi)).geom as poly + ) q_poly GROUP BY poly + ) h3_polygon_to_cells; $$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE CALLED ON NULL INPUT; -- NOT STRICT + +--@ availability: 4.0.0 +CREATE OR REPLACE FUNCTION h3_polygon_to_cells(multi geography, resolution integer) RETURNS SETOF h3index +AS $$ SELECT h3_polygon_to_cells($1::geometry, $2) $$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE CALLED ON NULL INPUT; -- NOT STRICT diff --git a/h3/sql/updates/h3--3.7.2--unreleased.sql b/h3_postgis/sql/install/20-casts.sql similarity index 61% rename from h3/sql/updates/h3--3.7.2--unreleased.sql rename to h3_postgis/sql/install/20-casts.sql index b7d1285d..417deddb 100644 --- a/h3/sql/updates/h3--3.7.2--unreleased.sql +++ b/h3_postgis/sql/install/20-casts.sql @@ -1,5 +1,5 @@ /* - * Copyright 2022 Bytes & Brains + * Copyright 2019-2022 Bytes & Brains * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,5 +14,11 @@ * limitations under the License. */ --- complain if script is sourced in psql, rather than via CREATE EXTENSION -\echo Use "ALTER EXTENSION h3 UPDATE TO 'unreleased'" to load this file. \quit +-- ---------- ---------- ---------- ---------- ---------- ---------- ---------- +--| ## PostGIS casts + +--@ availability: 0.3.0 +CREATE CAST (h3index AS geometry) WITH FUNCTION h3_cell_to_geometry(h3index); + +--@ availability: 0.3.0 +CREATE CAST (h3index AS geography) WITH FUNCTION h3_cell_to_geography(h3index); diff --git a/h3_postgis/sql/updates/.keep b/h3_postgis/sql/updates/.keep new file mode 100644 index 00000000..e69de29b