pax_global_header 0000666 0000000 0000000 00000000064 14460144644 0014521 g ustar 00root root 0000000 0000000 52 comment=a6d98a41ebf9cb3b0c91dedfa6e248e72b27aed3
h3-pg-4.1.3/ 0000775 0000000 0000000 00000000000 14460144644 0012444 5 ustar 00root root 0000000 0000000 h3-pg-4.1.3/.github/ 0000775 0000000 0000000 00000000000 14460144644 0014004 5 ustar 00root root 0000000 0000000 h3-pg-4.1.3/.github/FUNDING.yml 0000664 0000000 0000000 00000001340 14460144644 0015617 0 ustar 00root root 0000000 0000000 # These are supported funding model platforms
github: [zachasme]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
h3-pg-4.1.3/.github/workflows/ 0000775 0000000 0000000 00000000000 14460144644 0016041 5 ustar 00root root 0000000 0000000 h3-pg-4.1.3/.github/workflows/documentation.yml 0000664 0000000 0000000 00000000572 14460144644 0021441 0 ustar 00root root 0000000 0000000 name: documentation
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
documentation:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: "3.10"
- run: pipx install poetry
- run: scripts/documentation
- run: git diff --exit-code docs
h3-pg-4.1.3/.github/workflows/pgxn.yml 0000664 0000000 0000000 00000001605 14460144644 0017542 0 ustar 00root root 0000000 0000000 name: pgxn
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
pgxn:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- name: Install PGXN Client
run: sudo pip install pgxnclient
- name: Install PostgreSQL server dependencies
run: |
sudo apt-get update
sudo apt-get install postgresql-server-dev-14 postgis
- name: Prepare PostgreSQL
run: |
sudo systemctl start postgresql.service
sudo -u postgres -i createuser --superuser runner
sudo -u postgres -i createdb runner
psql -c "CREATE EXTENSION postgis; CREATE EXTENSION postgis_raster;"
- name: Bundle
run: scripts/bundle
- name: Install
run: sudo pgxn install ./h3-*.zip
- name: Load
run: pgxn load h3
- name: Check
run: pgxn check h3
h3-pg-4.1.3/.github/workflows/test-linux.yml 0000664 0000000 0000000 00000002776 14460144644 0020714 0 ustar 00root root 0000000 0000000 name: test-linux
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
linux:
strategy:
matrix:
config: [Release, Debug]
pg: [15, 14, 13, 12, 11]
runs-on: ubuntu-22.04
name: linux 🐘${{ matrix.pg }} (${{ matrix.config }})
steps:
- uses: actions/checkout@v3
- name: Cache Cargo
uses: actions/cache@v3
with:
path: ~/.cargo
key: ${{ runner.os }}-cargo-2023
- name: Install pg_validate_extupgrade
run: cargo install --locked --git https://github.com/rjuju/pg_validate_extupgrade.git
- name: Setup PostgreSQL ${{ matrix.pg }}
run: |
sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh -p -i -v ${{ matrix.pg }}
sudo apt-get -y install postgresql-${{ matrix.pg }}-postgis-3
sudo -u postgres -i createuser --superuser runner
sudo -u postgres -i createdb runner
psql -c "CREATE EXTENSION postgis; CREATE EXTENSION postgis_raster;"
- name: Generate
run: cmake -B build -DCMAKE_BUILD_TYPE=${{ matrix.config }}
- name: Build
run: cmake --build build
- name: Install
run: sudo cmake --install build --component h3-pg
- name: Test
env:
PGHOST: /var/run/postgresql
run: ctest --test-dir build --output-on-failure --build-config ${{ matrix.config }}
- name: Print regression diffs
if: ${{ failure() }}
run: cat build/*/test/regression.diffs
h3-pg-4.1.3/.github/workflows/test-macos.yml 0000664 0000000 0000000 00000002337 14460144644 0020650 0 ustar 00root root 0000000 0000000 name: test-macos
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
macos:
strategy:
matrix:
config: [Release, Debug]
runs-on: macos-12
steps:
- uses: actions/checkout@v3
- name: Cache Cargo
uses: actions/cache@v3
with:
path: ~/.cargo
key: ${{ runner.os }}-cargo-2023
- name: Install pg_validate_extupgrade
run: cargo install --locked --git https://github.com/rjuju/pg_validate_extupgrade.git
- name: Install PostgreSQL server dependencies
run: brew install postgis
- name: Generate
run: cmake -B build -DCMAKE_BUILD_TYPE=${{ matrix.config }}
- name: Build
run: cmake --build build --config ${{ matrix.config }}
- name: Install
run: sudo cmake --install build --component h3-pg --config ${{ matrix.config }}
- name: Prepare PostgreSQL
run: |
pg_ctl start -D /usr/local/var/postgresql@14 --wait
createdb runner
- name: Test
run: ctest --test-dir build --output-on-failure --build-config ${{ matrix.config }}
- name: Print regression diffs
if: ${{ failure() }}
run: cat build/*/regression.diffs
h3-pg-4.1.3/.github/workflows/test-windows.yml 0000664 0000000 0000000 00000001532 14460144644 0021234 0 ustar 00root root 0000000 0000000 name: test-windows
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
windows:
strategy:
matrix:
config: [Release, Debug]
runs-on: windows-2022
steps:
- uses: actions/checkout@v3
- name: Fix default PostgreSQL version on Windows Runner
run: $env:PGBIN >> $env:GITHUB_PATH
- name: Generate
run: cmake -B build -DCMAKE_BUILD_TYPE=${{ matrix.config }}
- name: Build
run: cmake --build build --config ${{ matrix.config }}
- name: Install
run: cmake --install build --component h3-pg --config ${{ matrix.config }}
- name: Test
run: ctest --test-dir build --output-on-failure --build-config ${{ matrix.config }}
- name: Print regression diffs
if: ${{ failure() }}
run: cat build/*/test/regression.diffs
h3-pg-4.1.3/.gitignore 0000664 0000000 0000000 00000000301 14460144644 0014426 0 ustar 00root root 0000000 0000000 build*/
# C
*.o
*.bc
*.so
# Test results
h3/test/regression.*
h3/test/results
# Generated
/h3*.sql
/h3/test/expected/ci-*.out
/h3/test/sql/ci-*.sql
/libh3-*/
/h3-*.zip
*.BAK
# IDEs
.vscode
h3-pg-4.1.3/CHANGELOG.md 0000664 0000000 0000000 00000025117 14460144644 0014263 0 ustar 00root root 0000000 0000000 # Changelog
All notable changes to this project will be documented in this file.
Critical bugfixes or breaking changes are marked using a warning symbol: ⚠️
_The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)._
## Versioning
The H3 core library adheres to [Semantic Versioning](http://semver.org/).
H3-pg has a `major.minor.patch` version scheme. The major and minor version
numbers of H3-pg are the major and minor version of the bound core library,
respectively. The patch version is incremented independently of the core
library.
Because H3-pg is versioned in lockstep with the H3 core library, please
avoid adding features or APIs which do not map onto the
[H3 core API](https://uber.github.io/h3/#/documentation/api-reference/).
## [Unreleased]
Changes that have landed in master but are not yet released.
Click to see more.
## [4.1.3] - 2023-07-26
- Add `geometry @ int` and `geography @ int` operators, as shortcuts for `h3_lat_lng_to_cell`.
- Explain PostGIS SRID expectations (see [#131], thanks [@rustprooflabs])
## [4.1.2] - 2023-02-08
- *Actually* fix `h3_postgis` upgrade path (see [#117], thanks [@mngr777])
## [4.1.1] - 2023-02-07
- Add `postgis_raster` integration (see [#112], thanks [@mngr777])
- Fix `h3_postgis` upgrade path (see [#117], thanks [@mngr777])
## [4.1.0] - 2023-01-18
- Bump `h3` to `v4.1.0`
- Add bindings for `h3_cell_to_child_pos` and `h3_child_pos_to_cell`.
- Use CMake for entire build (see [#70])
- Add helper to fix pass-by-value migration (see [#111])
- Allow distance operator `<->` to work for cells at different resolutions (using center child).
## [4.0.3] - 2022-11-04
- Add BRIN operator class (see [#97], thanks [@mngr777])
- Split PostGIS multipolygons by 180th meridian (see [#90], thanks [@mngr777])
- Add aggregate functions for `h3_postgis` (see [#91], thanks [@mngr777])
- Add recursive `h3_grid_path_cells` (see [#93], thanks [@mngr777])
## [4.0.2] - 2022-09-19
- Fix broken function renames (see [#87], thanks [@Kompza], [@mngr777])
## [4.0.1] - 2022-09-19
- Bump `h3` to `v4.0.1` (was locked on `rc5` for the previous release)
- Add compile flag support check (see [#78], thanks [@mngr777])
- Split polygons by 180th meridian (see [#76], thanks [@mngr777])
## [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])
- Allow >1Gb memory allocations for `h3_polyfill` (see [#65], thanks [@mngr777])
## [3.7.1] - 2021-06-23
- Update `h3` core library to `v3.7.1`
## [3.7.0] - 2020-09-30
- ⚠️ Default unit for `h3_hex_area` and `h3_edge_length` changed to kilometers
- Update `h3` core library to `v3.7.0`
- Add `h3_point_dist` and `h3_exact_edge_length` bindings
- Add distance operator `<->`
- Fix `h3_to_geography` and `h3_to_geometry` refering to removed functions if extension was upgraded from pre-1.0
- Add optional input validation in geoToH3 (see [#41], thanks [@trylinka])
- Support unit as string argument in `h3_hex_area` and `h3_edge_length` (and flag previous version for deprecation)
## [3.6.5] - 2020-08-14
- Add support for partitioning by hash (see [#37], thanks [@abelvm])
- Fix difference in function flags between fresh install and upgrades (see [#38], thanks [@abelvm])
## [3.6.4] - 2020-06-29
- Update `h3` core library to `v3.6.4`
## [3.6.3] - 2020-04-08
- Build `h3` core using release flag for 2x/3x performance (see [#23], thanks [@komzpa])
## [3.6.2] - 2020-04-07
**This update will corrupt your h3indexes unless your are using a 32-bit build of PostgreSQL (see [#31]). If you upgrade to `4.0.4` you can use the function `h3_pg_migrate_pass_by_reference(h3index)` to retrieve your old h3 cells. See [#111].**
- Add parallel safety flags to PostGIS functions (see [#19], thanks [@komzpa])
- Add B-Tree sort support (see [#24], thanks [@komzpa])
- ⚠️ Make type `h3index` pass-by-value on supported systems (see [#22], [#26], thanks [@komzpa])
- Update `h3` core library to `v3.6.3`
## [3.6.1] - 2019-12-09
- Add `&&`, `@>` and `<@` operators for overlaps, contains and contained by respectively
- Fix PostgreSQL 12 build (see [#18], thanks [@komzpa])
- Update `h3` core library to `v3.6.1`
## [3.6.0] - 2019-10-07
- Add support for `bigint` cast (see [#9], thanks [@kmacdough])
- Add `h3_to_center_child` binding
- Add `h3_get_pentagon_indexes` binding
- Update `h3` core library to `v3.6.0`
## [3.5.0] - 2019-08-01
- Add `h3_get_faces` binding
- ⚠️ Replace `h3_hex_area_m2` and `h3_hex_area_km2` with `h3_hex_area`
- ⚠️ Replace `h3_edge_length_m` and `h3_edge_length_km` with `h3_edge_length`
- ⚠️ Remove `hex_range`, `hex_ranges` and `hex_range_distances`
- Remove `h3` core library version check, since we know which version we are linking
- Fix PostgreSQL 12 build (see [#4], thanks [@komzpa])
- Update `h3` core library to `v3.5.0`
## [3.4.1] - 2019-06-14
- Fix `abs` warning
## [3.4.0] - 2019-06-13
- ⚠️ Remove degree/radian conversion helpers (in favor of built-in RADIANS/DEGREES)
## [1.0.6] - 2019-06-03
- Update `h3` core library to `v3.4.4`
## [1.0.5] - 2019-02-15
- Fix update path
## [1.0.4] - 2019-02-15
- Fix `polyfill` for polygon with multiple holes
## [1.0.3] - 2019-01-27
- Fix update path
## [1.0.2] - 2019-01-27
- Remove git tag check in `distribute` makefile target, since it causes error on pgxn install
## [1.0.1] - 2019-01-27
- Remove usage of `FALSE` instead of 0 in conditional in `ASSERT` macro
## [1.0.0] - 2019-01-27
- Add `h3_get_extension_version()`
- Add hash operator class, now `WHERE IN` works
- ⚠️ Replace `h3_basecells` with `h3_get_res_0_indexes`
- ⚠️ Rename all functions with double `h3_h3_` prefix to use single `h3_` prefix
- ⚠️ Remove `h3_haversine_distance` function
- ⚠️ Change Makefile such that the `h3` core library is cloned, built and statically linked
- Test that upgrade path has same result as fresh install
## [0.4.0] - 2019-01-12
- Add `h3_line` binding
- Fix `h3_h3_to_children_slow`
## [0.3.2] - 2019-01-08
- ⚠️ Fix `btree` operator class indexing
## [0.3.1] - 2018-12-17
- Add `extend` flag to `h3_h3_to_geo_boundary` such that polygons are not wrapped at antimeridian
## 0.3.0 - 2018-12-11
- Initial public release
[unreleased]: https://github.com/zachasme/h3-pg/compare/v4.1.3...HEAD
[4.1.3]: https://github.com/zachasme/h3-pg/compare/v4.1.2...v4.1.3
[4.1.2]: https://github.com/zachasme/h3-pg/compare/v4.1.1...v4.1.2
[4.1.1]: https://github.com/zachasme/h3-pg/compare/v4.1.0...v4.1.1
[4.1.0]: https://github.com/zachasme/h3-pg/compare/v4.0.3...v4.1.0
[4.0.3]: https://github.com/zachasme/h3-pg/compare/v4.0.2...v4.0.3
[4.0.2]: https://github.com/zachasme/h3-pg/compare/v4.0.1...v4.0.2
[4.0.1]: https://github.com/zachasme/h3-pg/compare/v4.0.0...v4.0.1
[4.0.0]: https://github.com/zachasme/h3-pg/compare/v3.7.2...v4.0.0
[3.7.2]: https://github.com/zachasme/h3-pg/compare/v3.7.1...v3.7.2
[3.7.1]: https://github.com/zachasme/h3-pg/compare/v3.7.0...v3.7.1
[3.7.0]: https://github.com/zachasme/h3-pg/compare/v3.6.5...v3.7.0
[3.6.5]: https://github.com/zachasme/h3-pg/compare/v3.6.4...v3.6.5
[3.6.4]: https://github.com/zachasme/h3-pg/compare/v3.6.3...v3.6.4
[3.6.3]: https://github.com/zachasme/h3-pg/compare/v3.6.2...v3.6.3
[3.6.2]: https://github.com/zachasme/h3-pg/compare/v3.6.1...v3.6.2
[3.6.1]: https://github.com/zachasme/h3-pg/compare/v3.6.0...v3.6.1
[3.6.0]: https://github.com/zachasme/h3-pg/compare/v3.5.0...v3.6.0
[3.5.0]: https://github.com/zachasme/h3-pg/compare/v3.4.1...v3.5.0
[3.4.1]: https://github.com/zachasme/h3-pg/compare/v3.4.0...v3.4.1
[3.4.0]: https://github.com/zachasme/h3-pg/compare/v1.0.6...v3.4.0
[1.0.6]: https://github.com/zachasme/h3-pg/compare/v1.0.5...v1.0.6
[1.0.5]: https://github.com/zachasme/h3-pg/compare/v1.0.4...v1.0.5
[1.0.4]: https://github.com/zachasme/h3-pg/compare/v1.0.3...v1.0.4
[1.0.3]: https://github.com/zachasme/h3-pg/compare/v1.0.2...v1.0.3
[1.0.2]: https://github.com/zachasme/h3-pg/compare/v1.0.1...v1.0.2
[1.0.1]: https://github.com/zachasme/h3-pg/compare/v1.0.0...v1.0.1
[1.0.0]: https://github.com/zachasme/h3-pg/compare/v0.4.0...v1.0.0
[0.4.0]: https://github.com/zachasme/h3-pg/compare/v0.3.2...v0.4.0
[0.3.2]: https://github.com/zachasme/h3-pg/compare/v0.3.1...v0.3.2
[0.3.1]: https://github.com/zachasme/h3-pg/compare/v0.3.0...v0.3.1
[#4]: https://github.com/zachasme/h3-pg/pull/4
[#9]: https://github.com/zachasme/h3-pg/pull/9
[#18]: https://github.com/zachasme/h3-pg/pull/18
[#19]: https://github.com/zachasme/h3-pg/pull/19
[#22]: https://github.com/zachasme/h3-pg/pull/22
[#23]: https://github.com/zachasme/h3-pg/issues/23
[#24]: https://github.com/zachasme/h3-pg/pull/24
[#26]: https://github.com/zachasme/h3-pg/pull/26
[#31]: https://github.com/zachasme/h3-pg/pull/31
[#37]: https://github.com/zachasme/h3-pg/issues/37
[#38]: https://github.com/zachasme/h3-pg/issues/38
[#41]: https://github.com/zachasme/h3-pg/issues/41
[#55]: https://github.com/zachasme/h3-pg/issues/55
[#64]: https://github.com/zachasme/h3-pg/issues/64
[#65]: https://github.com/zachasme/h3-pg/pull/65
[#70]: https://github.com/zachasme/h3-pg/pull/70
[#71]: https://github.com/zachasme/h3-pg/issues/71
[#75]: https://github.com/zachasme/h3-pg/pull/75
[#76]: https://github.com/zachasme/h3-pg/pull/76
[#78]: https://github.com/zachasme/h3-pg/pull/78
[#87]: https://github.com/zachasme/h3-pg/pull/87
[#90]: https://github.com/zachasme/h3-pg/pull/90
[#91]: https://github.com/zachasme/h3-pg/pull/91
[#93]: https://github.com/zachasme/h3-pg/pull/93
[#97]: https://github.com/zachasme/h3-pg/pull/97
[#111]: https://github.com/zachasme/h3-pg/pull/111
[#112]: https://github.com/zachasme/h3-pg/pull/112
[#117]: https://github.com/zachasme/h3-pg/issues/117
[#131]: https://github.com/zachasme/h3-pg/pull/131
[@abelvm]: https://github.com/AbelVM
[@kalenikaliaksandr]: https://github.com/kalenikaliaksandr
[@kmacdough]: https://github.com/kmacdough
[@komzpa]: https://github.com/Komzpa
[@lokks]: https://github.com/Lokks
[@mngr777]: https://github.com/mngr777
[@trylinka]: https://github.com/trylinka
[@rustprooflabs]: https://github.com/rustprooflabs
h3-pg-4.1.3/CITATION.cff 0000664 0000000 0000000 00000000474 14460144644 0014343 0 ustar 00root root 0000000 0000000 cff-version: 1.2.0
message: "If you use this software, please cite it as below."
authors:
- family-names: "Knudsen"
given-names: "Zacharias"
orcid: https://orcid.org/0000-0003-3662-8396
title: "h3-pg"
version: v3.7.2
doi: 10.5281/zenodo.6856596
date-released: 2022-04-13
url: "https://github.com/zachasme/h3-pg" h3-pg-4.1.3/CMakeLists.txt 0000664 0000000 0000000 00000005147 14460144644 0015213 0 ustar 00root root 0000000 0000000 # 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.
# Almost all CMake files should start with this
# You should always specify a range with the newest
# and oldest tested versions of CMake. This will ensure
# you pick up the best policies.
# Keep minimum version in sync with:
# https://github.com/uber/h3/blob/master/CMakeLists.txt
cmake_minimum_required(VERSION 3.20..3.24)
if(POLICY CMP0135)
# Set the timestamps of all extracted contents to the time of the extraction
cmake_policy(SET CMP0135 NEW)
endif()
# This is your project statement. You should always list languages;
# Listing the version is nice here since it sets lots of useful variables
project(
h3-pg
VERSION 4.1.3
LANGUAGES C
)
# set this to "${PROJECT_VERSION}" on release
set(INSTALL_VERSION "${PROJECT_VERSION}")
#set(INSTALL_VERSION "unreleased")
set(H3_CORE_VERSION 4.1.0)
set(H3_CORE_SHA256 ec99f1f5974846bde64f4513cf8d2ea1b8d172d2218ab41803bf6a63532272bc)
# If you set any CMAKE_ variables, that can go here.
# (But usually don't do this, except maybe for C++ standard)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
# Allow forcing PostgreSQL version
set(POSTGRESQL_VERSION $ENV{POSTGRESQL_VERSION} CACHE STRING "PostgreSQL version major")
# Find packages go here.
find_package(PostgreSQL ${POSTGRESQL_VERSION} REQUIRED
OPTIONAL_COMPONENTS PostGIS
)
include(AddPostgreSQLExtension)
add_definitions(-DPOSTGRESQL_VERSION_MAJOR=${PostgreSQL_VERSION_MAJOR})
# https://cliutils.gitlab.io/modern-cmake/chapters/testing.html
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
include(CTest)
endif()
# Include core library
add_subdirectory(cmake/h3)
# Include extensions and their shared code
add_subdirectory(include)
add_subdirectory(h3)
add_subdirectory(h3_postgis)
# Add target that bundles for pgxn
configure_file(META.json.in META.json)
add_custom_target(pgxn
COMMAND git archive --format zip
--prefix="h3-${INSTALL_VERSION}/"
--add-file ${CMAKE_BINARY_DIR}/META.json
-o h3-${INSTALL_VERSION}.zip HEAD
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
h3-pg-4.1.3/LICENSE 0000775 0000000 0000000 00000023675 14460144644 0013471 0 ustar 00root root 0000000 0000000 Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
h3-pg-4.1.3/META.json.in 0000664 0000000 0000000 00000002042 14460144644 0014470 0 ustar 00root root 0000000 0000000 {
"name": "h3",
"abstract": "PostgreSQL bindings for H3",
"description": "PostgreSQL bindings for H3, a hierarchical hexagonal geospatial indexing system.",
"version": "@PROJECT_VERSION@",
"maintainer": "Zacharias Knudsen ",
"license": "apache_2_0",
"provides": {
"h3": {
"abstract": "PostgreSQL bindings for H3",
"file": "h3--@PROJECT_VERSION@.sql",
"docfile": "README.md",
"version": "@PROJECT_VERSION@"
},
"h3_postgis": {
"abstract": "H3 PostGIS integration",
"file": "h3_postgis--@PROJECT_VERSION@.sql",
"docfile": "README.md",
"version": "@PROJECT_VERSION@"
}
},
"resources": {
"homepage": "https://github.com/zachasme/h3-pg",
"bugtracker": {
"web": "https://github.com/zachasme/h3-pg/issues"
},
"repository": {
"url": "https://github.com/zachasme/h3-pg.git",
"web": "https://github.com/zachasme/h3-pg",
"type": "git"
}
},
"meta-spec": {
"version": "1.0.0",
"url": "http://pgxn.org/meta/spec.txt"
}
}
h3-pg-4.1.3/Makefile 0000664 0000000 0000000 00000001525 14460144644 0014107 0 ustar 00root root 0000000 0000000 # 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.
# this file only exists to support pgxnclient
.PHONY: all install installcheck
all:
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
install:
cmake --install build --component h3-pg
installcheck:
ctest --output-on-failure --build-config Release
h3-pg-4.1.3/README.md 0000664 0000000 0000000 00000005617 14460144644 0013734 0 ustar 00root root 0000000 0000000 # h3-pg: Uber's H3 Hexagonal Hierarchical Geospatial Indexing System in PostgreSQL
[](https://github.com/zachasme/postgresql-extensions-cmake/actions)
[](https://github.com/zachasme/postgresql-extensions-cmake/actions/workflows/test-macos.yml)
[](https://github.com/zachasme/postgresql-extensions-cmake/actions/workflows/test-windows.yml)
[](LICENSE)
This library provides PostgreSQL bindings for the [H3 Core Library](https://github.com/uber/h3). For API reference, please see the [H3 Documentation](https://uber.github.io/h3).
Developed in collaboration with [Scandinavian Highlands](http://www.scandinavian-highlands.com).
## Prerequisites
- PostgreSQL 11+ (_including server headers_, e.g. `postgresql-server-dev-14`)
- C compiler (e.g., `gcc`)
- [CMake](https://cmake.org/) 3.20+
- GNU Make
## Quick Overview
If the prerequisites are met you can use the [PGXN Client](docs/pgxnclient.md) to download, build, and install, e.g.:
```shell
$ pgxn install h3
$ pgxn load h3
$ psql
=# SELECT h3_lat_lng_to_cell(POINT('37.3615593,-122.0553238'), 5);
h3_lat_lng_to_cell
-----------------
85e35e73fffffff
(1 row)
```
(You can install a specific version using `pgxn install 'h3=3.7.2'` and `pgxn load 'h3=3.7.2'` for example)
See [Building](#building) for other installation methods.
## Usage
> :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/zachasme/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.
See [API reference](https://pgxn.org/dist/h3/docs/api.html) for all provided functions.
## Building
```bash
# Generate native build system
cmake -B build -DCMAKE_BUILD_TYPE=Release
# Build extension(s)
cmake --build build
# Install extensions (might require sudo)
cmake --install build --component h3-pg
```
## Contributing
Pull requests and GitHub issues are welcome. Please include tests for new work. Please note that the purpose of this extension is to expose the API of the H3 Core library, so we will rarely accept new features that are not part of that API. New proposed feature work is more appropriate in the core C library or in a new extension that depends on h3-pg.
See [Development](docs/development.md).
## License
This project is released under the [Apache 2.0 License](LICENSE.md).
h3-pg-4.1.3/cmake/ 0000775 0000000 0000000 00000000000 14460144644 0013524 5 ustar 00root root 0000000 0000000 h3-pg-4.1.3/cmake/AddPostgreSQLExtension.cmake 0000664 0000000 0000000 00000005521 14460144644 0021042 0 ustar 00root root 0000000 0000000 # Add pg_regress binary
find_program(PostgreSQL_REGRESS pg_regress
HINTS
"${PostgreSQL_PKG_LIBRARY_DIR}/pgxs/src/test/regress/"
"${PostgreSQL_BIN_DIR}"
)
# Add pg_validate_extupgrade binary
find_program(PostgreSQL_VALIDATE_EXTUPGRADE pg_validate_extupgrade)
# Add pgindent binary
find_program(PostgreSQL_INDENT pgindent)
# Helper command to add extensions
function(PostgreSQL_add_extension LIBRARY_NAME)
set(options RELOCATABLE)
set(oneValueArgs NAME COMMENT VERSION COMPONENT)
set(multiValueArgs REQUIRES SOURCES INSTALLS UPDATES)
cmake_parse_arguments(EXTENSION "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
# Default extension name to same as library name
if(NOT EXTENSION_NAME)
set(EXTENSION_NAME ${LIBRARY_NAME})
endif()
# Allow extensions without sources
if(EXTENSION_SOURCES)
# Add extension as a dynamically linked library
add_library(${LIBRARY_NAME} MODULE ${EXTENSION_SOURCES})
# Link extension to PostgreSQL
target_link_libraries(${LIBRARY_NAME} PRIVATE PostgreSQL::PostgreSQL)
# Fix apple missing symbols
if(APPLE)
set_target_properties(${LIBRARY_NAME} PROPERTIES LINK_FLAGS ${PostgreSQL_LINK_FLAGS})
endif()
# Final touches on output file
set_target_properties(${LIBRARY_NAME} PROPERTIES
OUTPUT_NAME ${EXTENSION_NAME}
INTERPROCEDURAL_OPTIMIZATION TRUE
#C_VISIBILITY_PRESET hidden # @TODO: how to get this working?
PREFIX "" # Avoid lib* prefix on output file
)
# Install .so/.dll to pkglib-dir
install(
TARGETS ${LIBRARY_NAME}
LIBRARY DESTINATION "${PostgreSQL_PKG_LIBRARY_DIR}"
COMPONENT ${EXTENSION_COMPONENT}
)
endif()
# Generate .control file
string(REPLACE ";" ", " EXTENSION_REQUIRES "${EXTENSION_REQUIRES}")
configure_file(
${CMAKE_SOURCE_DIR}/cmake/control.in
${EXTENSION_NAME}.control
)
# Generate .sql install file
set(EXTENSION_INSTALL ${CMAKE_CURRENT_BINARY_DIR}/${EXTENSION_NAME}--${EXTENSION_VERSION}.sql)
file(WRITE "${EXTENSION_INSTALL}.in" "")
foreach(file ${EXTENSION_INSTALLS})
file(READ ${file} CONTENTS)
file(APPEND "${EXTENSION_INSTALL}.in" "${CONTENTS}")
endforeach()
configure_file("${EXTENSION_INSTALL}.in" "${EXTENSION_INSTALL}" COPYONLY)
# Install everything else into share-dir
install(
FILES
${CMAKE_CURRENT_BINARY_DIR}/${EXTENSION_NAME}.control
${EXTENSION_INSTALL}
${EXTENSION_UPDATES}
DESTINATION "${PostgreSQL_SHARE_DIR}/extension"
COMPONENT ${EXTENSION_COMPONENT}
)
# Setup auto-format
if(PostgreSQL_INDENT)
add_custom_target("format_${EXTENSION_NAME}"
COMMAND ${PostgreSQL_INDENT} ${EXTENSION_SOURCES}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Formatting ${EXTENSION_NAME} sources"
)
add_dependencies(${LIBRARY_NAME} "format_${EXTENSION_NAME}")
endif()
endfunction()
h3-pg-4.1.3/cmake/FindPostgreSQL.cmake 0000664 0000000 0000000 00000020231 14460144644 0017330 0 ustar 00root root 0000000 0000000 # Based on:
# https://cmake.org/cmake/help/latest/manual/cmake-developer.7.html#find-modules
# ----------------------------------------------------------------------------
# https://www.postgresql.org/support/versioning/
set(PostgreSQL_SUPPORTED_VERSIONS ${PostgreSQL_ADDITIONAL_VERSIONS}
"15" "14" "13" "12" "11")
# Use `FIND_VERSION` to locate specific version of pg_config, or fallback to known versions
if(PostgreSQL_FIND_VERSION)
list(PREPEND PostgreSQL_SUPPORTED_VERSIONS "${PostgreSQL_FIND_VERSION_MAJOR}")
endif()
foreach(suffix ${PostgreSQL_SUPPORTED_VERSIONS})
if(WIN32)
list(APPEND PostgreSQL_CONFIG_PATH_SUFFIXES
"PostgreSQL/${suffix}/bin")
endif()
if(UNIX)
list(APPEND PostgreSQL_CONFIG_HINTS
"/usr/lib/postgresql/${suffix}/bin")
endif()
endforeach()
# Configuration will be based on values gathered from `pg_config`
find_program(PostgreSQL_CONFIG pg_config REQUIRED
HINTS ${PostgreSQL_CONFIG_HINTS}
PATH_SUFFIXES ${PostgreSQL_CONFIG_PATH_SUFFIXES}
)
# Grab information about the installed version of PostgreSQL
execute_process(COMMAND ${PostgreSQL_CONFIG} --version OUTPUT_VARIABLE PostgreSQL_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(COMMAND ${PostgreSQL_CONFIG} --bindir OUTPUT_VARIABLE PostgreSQL_BIN_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(COMMAND ${PostgreSQL_CONFIG} --sharedir OUTPUT_VARIABLE PostgreSQL_SHARE_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(COMMAND ${PostgreSQL_CONFIG} --includedir OUTPUT_VARIABLE PostgreSQL_INCLUDE_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(COMMAND ${PostgreSQL_CONFIG} --pkgincludedir OUTPUT_VARIABLE PostgreSQL_PKG_INCLUDE_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(COMMAND ${PostgreSQL_CONFIG} --includedir-server OUTPUT_VARIABLE PostgreSQL_SERVER_INCLUDE_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(COMMAND ${PostgreSQL_CONFIG} --libdir OUTPUT_VARIABLE PostgreSQL_LIBRARY_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(COMMAND ${PostgreSQL_CONFIG} --pkglibdir OUTPUT_VARIABLE PostgreSQL_PKG_LIBRARY_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)
# @TODO: Figure out if we need _INCLUDE_DIR and/or _PKG_INCLUDE_DIR
# Create include dirs list
list(APPEND PostgreSQL_INCLUDE_DIRS "${PostgreSQL_INCLUDE_DIR}" "${PostgreSQL_PKG_INCLUDE_DIR}" "${PostgreSQL_SERVER_INCLUDE_DIR}")
list(APPEND PostgreSQL_LIBRARY_DIRS "${PostgreSQL_LIBRARY_DIR}")
# Set library to search for (which is different on WIN32)
set(FIND_LIBRARY pq)
# Platform fixes: Windows
# https://wiki.postgresql.org/wiki/Building_and_Installing_PostgreSQL_Extension_Modules
if(WIN32)
set(FIND_LIBRARY postgres)
list(APPEND PostgreSQL_INCLUDE_DIRS "${PostgreSQL_SERVER_INCLUDE_DIR}/port/win32")
if(MSVC)
list(APPEND PostgreSQL_INCLUDE_DIRS "${PostgreSQL_SERVER_INCLUDE_DIR}/port/win32_msvc")
endif(MSVC)
endif(WIN32)
# Platform fixes: MacOS
# https://github.com/postgres/postgres/blob/master/src/makefiles/Makefile.darwin
set(PostgreSQL_LINK_FLAGS "")
# @TODO: Find out if the cannot be done in a more cmakey way
if(APPLE)
find_program(PostgreSQL_EXECUTABLE postgres REQUIRED NO_DEFAULT_PATH PATHS ${PostgreSQL_BIN_DIR})
set(PostgreSQL_LINK_FLAGS "-bundle_loader ${PostgreSQL_EXECUTABLE}")
endif()
# ----------------------------------------------------------------------------
# Now we need to find the libraries and include files
# if the library is available with multiple configurations, you can use SelectLibraryConfigurations
# to automatically set the _LIBRARY variable:
# @TODO: Find out if we can actually find any debug libraries on each platform
find_library(PostgreSQL_LIBRARY_RELEASE
NAMES ${FIND_LIBRARY}
PATHS ${PostgreSQL_LIBRARY_DIRS}
)
find_library(PostgreSQL_LIBRARY_DEBUG
NAMES ${FIND_LIBRARY}d # <-- debug
PATHS ${PostgreSQL_LIBRARY_DIRS}
)
include(SelectLibraryConfigurations)
select_library_configurations(PostgreSQL)
# ----------------------------------------------------------------------------
# If you have a good way of getting the version (from a header file, for example),
# you can use that information to set Foo_VERSION (although note that find modules have
# traditionally used Foo_VERSION_STRING, so you may want to set both).
string(REGEX MATCHALL "[0-9]+" PostgreSQL_VERSION_LIST "${PostgreSQL_VERSION}")
list(GET PostgreSQL_VERSION_LIST 0 PostgreSQL_VERSION_MAJOR)
list(GET PostgreSQL_VERSION_LIST 1 PostgreSQL_VERSION_MINOR)
set(PostgreSQL_VERSION "${PostgreSQL_VERSION_MAJOR}.${PostgreSQL_VERSION_MINOR}")
# ----------------------------------------------------------------------------
# Handle additional components
if("PostGIS" IN_LIST PostgreSQL_FIND_COMPONENTS)
find_library(
POSTGIS
NAMES postgis postgis-3 postgis-3.so
PATHS ${PostgreSQL_PKG_LIBRARY_DIR}
)
set(PostgreSQL_PostGIS_FOUND TRUE)
if(NOT POSTGIS)
set(PostgreSQL_PostGIS_FOUND FALSE)
endif()
endif()
# ----------------------------------------------------------------------------
# Now we can use FindPackageHandleStandardArgs to do
# most of the rest of the work for us
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(PostgreSQL
REQUIRED_VARS
PostgreSQL_LIBRARY
PostgreSQL_INCLUDE_DIRS
HANDLE_COMPONENTS
VERSION_VAR PostgreSQL_VERSION
)
# ----------------------------------------------------------------------------
# At this point, we have to provide a way for users of the find module to link to the library or libraries that were found.
#
# If the library is available with multiple configurations, the IMPORTED_CONFIGURATIONS target property should also be populated:
if(PostgreSQL_FOUND)
# When providing imported targets, these should be namespaced (hence the Foo:: prefix);
# CMake will recognize that values passed to target_link_libraries() that contain :: in their name
# are supposed to be imported targets (rather than just library names),
if (NOT TARGET PostgreSQL::PostgreSQL)
add_library(PostgreSQL::PostgreSQL UNKNOWN IMPORTED)
endif()
# The RELEASE variant should be listed first in the property so that the variant is chosen
# if the user uses a configuration which is not an exact match for any listed IMPORTED_CONFIGURATIONS.
if (PostgreSQL_LIBRARY_RELEASE)
set_property(TARGET PostgreSQL::PostgreSQL APPEND PROPERTY
IMPORTED_CONFIGURATIONS RELEASE
)
set_target_properties(PostgreSQL::PostgreSQL PROPERTIES
IMPORTED_LOCATION_RELEASE "${PostgreSQL_LIBRARY_RELEASE}"
)
endif()
if (PostgreSQL_LIBRARY_DEBUG)
set_property(TARGET PostgreSQL::PostgreSQL APPEND PROPERTY
IMPORTED_CONFIGURATIONS DEBUG
)
set_target_properties(PostgreSQL::PostgreSQL PROPERTIES
IMPORTED_LOCATION_DEBUG "${PostgreSQL_LIBRARY_DEBUG}"
)
endif()
set_target_properties(PostgreSQL::PostgreSQL PROPERTIES
#INTERFACE_COMPILE_OPTIONS "${PostgreSQL_CFLAGS_OTHER}"
INTERFACE_INCLUDE_DIRECTORIES "${PostgreSQL_INCLUDE_DIRS}"
)
endif()
# Most of the cache variables should be hidden in the `ccmake` interface unless the user explicitly asks to edit them.
mark_as_advanced(
PostgreSQL_INCLUDE_DIRS
PostgreSQL_LIBRARY
)
# ----------------------------------------------------------------------------
# Traditional variables (from pkg-config):
#
# _FOUND has the package been found
# _LIBRARIES ?
# _LINK_LIBRARIES ?
# _LIBRARY_DIRS ?
# _LDFLAGS ?
# _LDFLAGS_OTHER ?
# _INCLUDE_DIRS ?
# _CFLAGS ?
# _CFLAGS_OTHER required non-include-dir CFLAGS to stdout
#
# _VERSION full version of found package
# _PREFIX ?
# _INCLUDEDIR ?
# _LIBDIR ?
# debug
message(STATUS "Find version: ${PostgreSQL_FIND_VERSION}")
message(STATUS "Find major: ${PostgreSQL_FIND_VERSION_MAJOR}")
message(STATUS "Find minor: ${PostgreSQL_FIND_VERSION_MINOR}")
message(STATUS "Found version: ${PostgreSQL_VERSION}")
message(STATUS "Found major: ${PostgreSQL_VERSION_MAJOR}")
message(STATUS "Found minor: ${PostgreSQL_VERSION_MINOR}")
# Get all variables
GET_CMAKE_PROPERTY(vars VARIABLES)
FOREACH(var ${vars})
STRING(REGEX MATCH "^PostgreSQL_" item ${var})
IF(item)
message(STATUS "${var} = ${${var}}")
ENDIF(item)
ENDFOREACH(var)
h3-pg-4.1.3/cmake/control.in 0000664 0000000 0000000 00000000220 14460144644 0015526 0 ustar 00root root 0000000 0000000 comment = '@EXTENSION_COMMENT@'
default_version = '@EXTENSION_VERSION@'
relocatable = @EXTENSION_RELOCATABLE@
requires = '@EXTENSION_REQUIRES@'
h3-pg-4.1.3/cmake/h3/ 0000775 0000000 0000000 00000000000 14460144644 0014036 5 ustar 00root root 0000000 0000000 h3-pg-4.1.3/cmake/h3/CMakeLists.txt 0000664 0000000 0000000 00000001174 14460144644 0016601 0 ustar 00root root 0000000 0000000 include(FetchContent)
# Skip core tooling we won't need for extension
set(ENABLE_COVERAGE OFF)
set(BUILD_BENCHMARKS OFF)
set(BUILD_FUZZERS OFF)
set(BUILD_FILTERS OFF)
set(BUILD_GENERATORS OFF)
set(ENABLE_FORMAT OFF)
set(ENABLE_LINTING OFF)
set(ENABLE_DOCS OFF)
FetchContent_Declare(
h3
URL https://github.com/uber/h3/archive/refs/tags/v${H3_CORE_VERSION}.tar.gz
URL_HASH SHA256=${H3_CORE_SHA256}
)
FetchContent_MakeAvailable(h3)
set_target_properties(h3 PROPERTIES
INTERPROCEDURAL_OPTIMIZATION TRUE
C_VISIBILITY_PRESET hidden
)
set(H3_INCLUDE_DIR ${h3_BINARY_DIR}/src/h3lib/include)
h3-pg-4.1.3/docs/ 0000775 0000000 0000000 00000000000 14460144644 0013374 5 ustar 00root root 0000000 0000000 h3-pg-4.1.3/docs/api.md 0000664 0000000 0000000 00000054325 14460144644 0014500 0 ustar 00root root 0000000 0000000 # API Reference
The `h3` extension wraps the [H3 Core Library](https://github.com/uber/h3).
The detailed API reference is in the core [H3 Documentation](https://uber.github.io/h3) under the API Reference section.
The `h3` core functions have been renamed from camelCase in H3 core to snake\_case in SQL.
The SQL function name is prefixed with `h3_`.
# 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'.
# Indexing functions
These function are used for finding the H3 index containing coordinates,
and for finding the center and boundary of H3 indexes.
### h3_lat_lng_to_cell(latlng `point`, resolution `integer`) ⇒ `h3index`
*Since v4.0.0*
See also: h3_lat_lng_to_cell(`geometry`, `integer`), h3_lat_lng_to_cell(`geography`, `integer`)
Indexes the location at the specified resolution.
### h3_cell_to_lat_lng(cell `h3index`) ⇒ `point`
*Since v4.0.0*
See also: h3_cell_to_geometry(`h3index`), h3_cell_to_geography(`h3index`)
Finds the centroid of the index.
### h3_cell_to_boundary(cell `h3index`) ⇒ `polygon`
*Since v4.0.0*
See also: h3_cell_to_boundary_geometry(`h3index`), h3_cell_to_boundary_geography(`h3index`)
Finds the boundary of the index.
Use `SET h3.extend_antimeridian TO true` to extend coordinates when crossing 180th meridian.
# Index inspection functions
These functions provide metadata about an H3 index, such as its resolution
or base cell, and provide utilities for converting into and out of the
64-bit representation of an H3 index.
### h3_get_resolution(`h3index`) ⇒ `integer`
*Since v1.0.0*
Returns the resolution of the index.
### h3_get_base_cell_number(`h3index`) ⇒ `integer`
*Since v4.0.0*
Returns the base cell number of the index.
### h3_is_valid_cell(`h3index`) ⇒ `boolean`
*Since v1.0.0*
Returns true if the given H3Index is valid.
### h3_is_res_class_iii(`h3index`) ⇒ `boolean`
*Since v1.0.0*
Returns true if this index has a resolution with Class III orientation.
### h3_is_pentagon(`h3index`) ⇒ `boolean`
*Since v1.0.0*
Returns true if this index represents a pentagonal cell.
### h3_get_icosahedron_faces(`h3index`) ⇒ `integer[]`
*Since v4.0.0*
Find all icosahedron faces intersected by a given H3 index.
# Grid traversal functions
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_grid_disk(origin `h3index`, [k `integer` = 1]) ⇒ SETOF `h3index`
*Since v4.0.0*
Produces indices within "k" distance of the origin index.
### h3_grid_disk_distances(origin `h3index`, [k `integer` = 1], OUT index `h3index`, OUT distance `int`) ⇒ SETOF `record`
*Since v4.0.0*
Produces indices within "k" distance of the origin index paired with their distance to the origin.
### h3_grid_ring_unsafe(origin `h3index`, [k `integer` = 1]) ⇒ SETOF `h3index`
*Since v4.0.0*
Returns the hollow hexagonal ring centered at origin with distance "k".
### h3_grid_path_cells(origin `h3index`, destination `h3index`) ⇒ SETOF `h3index`
*Since v4.0.0*
See also: h3_grid_path_cells_recursive(`h3index`, `h3index`)
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.
### h3_grid_distance(origin `h3index`, destination `h3index`) ⇒ `bigint`
*Since v4.0.0*
Returns the distance in grid cells between the two indices.
### 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.
### 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.
# Hierarchical grid functions
These functions permit moving between resolutions in the H3 grid system.
The functions produce parent (coarser) or children (finer) cells.
### h3_cell_to_parent(cell `h3index`, resolution `integer`) ⇒ `h3index`
*Since v4.0.0*
Returns the parent of the given index.
### h3_cell_to_children(cell `h3index`, resolution `integer`) ⇒ SETOF `h3index`
*Since v4.0.0*
Returns the set of children of the given index.
### 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_cells(cells `h3index[]`) ⇒ SETOF `h3index`
*Since v4.0.0*
Compacts the given array as best as possible.
### h3_cell_to_child_pos(child `h3index`, parentRes `integer`) ⇒ `int8`
*Since v4.1.0*
Returns the position of the child cell within an ordered list of all children of the cells parent at the specified resolution parentRes. The order of the ordered list is the same as that returned by cellToChildren. This is the complement of childPosToCell.
### h3_child_pos_to_cell(childPos `int8`, parent `h3index`, childRes `int`) ⇒ `h3index`
*Since v4.1.0*
Returns the child cell at a given position within an ordered list of all children of parent at the specified resolution childRes. The order of the ordered list is the same as that returned by cellToChildren. This is the complement of cellToChildPos.
### h3_uncompact_cells(cells `h3index[]`, resolution `integer`) ⇒ SETOF `h3index`
*Since v4.0.0*
Uncompacts the given array at the given resolution.
### h3_cell_to_parent(cell `h3index`) ⇒ `h3index`
*Since v4.0.0*
Returns the parent of the given index.
### h3_cell_to_children(cell `h3index`) ⇒ SETOF `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[]`) ⇒ SETOF `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`) ⇒ SETOF `h3index`
*Since v4.0.0*
Slower version of H3ToChildren but allocates less memory.
### h3_cell_to_children_slow(index `h3index`) ⇒ SETOF `h3index`
Slower version of H3ToChildren but allocates less memory.
# Region functions
These functions convert H3 indexes to and from polygonal areas.
### h3_polygon_to_cells(exterior `polygon`, holes `polygon[]`, [resolution `integer` = 1]) ⇒ SETOF `h3index`
*Since v4.0.0*
See also: h3_polygon_to_cells(`geometry`, `integer`), h3_polygon_to_cells(`geography`, `integer`)
Takes an exterior polygon [and a set of hole polygon] and returns the set of hexagons that best fit the structure.
### h3_cells_to_multi_polygon(`h3index[]`, OUT exterior `polygon`, OUT holes `polygon[]`) ⇒ SETOF `record`
*Since v4.0.0*
See also: h3_cells_to_multi_polygon_geometry(`h3index[]`), h3_cells_to_multi_polygon_geography(`h3index[]`), h3_cells_to_multi_polygon_geometry(setof `h3index`), h3_cells_to_multi_polygon_geography(setof `h3index`)
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
Unidirectional edges allow encoding the directed edge from one cell to a
neighboring cell.
### h3_are_neighbor_cells(origin `h3index`, destination `h3index`) ⇒ `boolean`
*Since v4.0.0*
Returns true if the given indices are neighbors.
### 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_is_valid_directed_edge(edge `h3index`) ⇒ `boolean`
*Since v4.0.0*
Returns true if the given edge is valid.
### h3_get_directed_edge_origin(edge `h3index`) ⇒ `h3index`
*Since v4.0.0*
Returns the origin index from the given edge.
### h3_get_directed_edge_destination(edge `h3index`) ⇒ `h3index`
*Since v4.0.0*
Returns the destination index from the given edge.
### h3_directed_edge_to_cells(edge `h3index`, OUT origin `h3index`, OUT destination `h3index`) ⇒ `record`
*Since v4.0.0*
Returns the pair of indices from the given edge.
### h3_origin_to_directed_edges(`h3index`) ⇒ SETOF `h3index`
*Since v4.0.0*
Returns all unidirectional edges with the given index as origin.
### 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`) ⇒ SETOF `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_great_circle_distance(a `point`, b `point`, [unit `text` = km]) ⇒ `double precision`
*Since v4.0.0*
The great circle distance in radians between two spherical coordinates.
### h3_get_hexagon_area_avg(resolution `integer`, [unit `text` = km]) ⇒ `double precision`
*Since v4.0.0*
Average hexagon area in square (kilo)meters at the given resolution.
### h3_cell_area(cell `h3index`, [unit `text` = km^2]) ⇒ `double precision`
*Since v4.0.0*
Exact area for a specific cell (hexagon or pentagon).
### h3_get_hexagon_edge_length_avg(resolution `integer`, [unit `text` = km]) ⇒ `double precision`
*Since v4.0.0*
Average hexagon edge length in (kilo)meters at the given resolution.
### h3_edge_length(edge `h3index`, [unit `text` = km]) ⇒ `double precision`
*Since v4.0.0*
Exact length for a specific unidirectional edge.
### h3_get_num_cells(resolution `integer`) ⇒ `bigint`
*Since v4.0.0*
Number of unique H3 indexes at the given resolution.
### h3_get_res_0_cells() ⇒ SETOF `h3index`
*Since v4.0.0*
Returns all 122 resolution 0 indexes.
### h3_get_pentagons(resolution `integer`) ⇒ SETOF `h3index`
*Since v4.0.0*
All the pentagon H3 indexes at the specified resolution.
# Operators
### Operator: `h3index` <-> `h3index`
*Since v3.7.0*
Returns the distance in grid cells between the two indices (at the lowest resolution of the two).
## B-tree operators
### Operator: `h3index` = `h3index`
*Since v0.1.0*
Returns true if two indexes are the same.
### Operator: `h3index` <> `h3index`
*Since v0.1.0*
## R-tree Operators
### Operator: `h3index` && `h3index`
*Since v3.6.1*
Returns true if the two H3 indexes intersect.
### Operator: `h3index` @> `h3index`
*Since v3.6.1*
Returns true if A contains B.
### Operator: `h3index` <@ `h3index`
*Since v3.6.1*
Returns true if A is contained by B.
# Type casts
### `h3index` :: `bigint`
Convert H3 index to bigint, which is useful when you need a decimal representation.
### `bigint` :: `h3index`
Convert bigint to H3 index.
### `h3index` :: `point`
Convert H3 index to point.
# Extension specific functions
### h3_get_extension_version() ⇒ `text`
*Since v1.0.0*
Get the currently installed version of the extension.
### h3_pg_migrate_pass_by_reference(`h3index`) ⇒ `h3index`
*Since v4.1.0*
Migrate h3index from pass-by-reference to pass-by-value.
# Deprecated functions
### h3_cell_to_boundary(cell `h3index`, extend_antimeridian `boolean`) ⇒ `polygon`
DEPRECATED: Use `SET h3.extend_antimeridian TO true` instead.
# PostGIS Integration
The `GEOMETRY` data passed to `h3-pg` PostGIS functions should
be in SRID 4326. This is an expectation of the core H3 library.
Using other SRIDs, such as 3857, can result in either errors or
invalid data depending on the function.
For example, the `h3_polygon_to_cells()` function will fail with
an error in this scenario while the `h3_lat_lng_to_cell()` function
will return an invalid geometry.
# PostGIS Indexing Functions
### h3_lat_lng_to_cell(`geometry`, resolution `integer`) ⇒ `h3index`
*Since v4.0.0*
Indexes the location at the specified resolution.
### h3_lat_lng_to_cell(`geography`, resolution `integer`) ⇒ `h3index`
*Since v4.0.0*
Indexes the location at the specified resolution.
### h3_cell_to_geometry(`h3index`) ⇒ `geometry`
*Since v4.0.0*
Finds the centroid of the index.
### h3_cell_to_geography(`h3index`) ⇒ `geography`
*Since v4.0.0*
Finds the centroid of the index.
### h3_cell_to_boundary_geometry(`h3index`) ⇒ `geometry`
*Since v4.0.0*
Finds the boundary of the index.
Splits polygons when crossing 180th meridian.
### h3_cell_to_boundary_geography(`h3index`) ⇒ `geography`
*Since v4.0.0*
Finds the boundary of the index.
Splits polygons when crossing 180th meridian.
# PostGIS Grid Traversal Functions
### h3_grid_path_cells_recursive(origin `h3index`, destination `h3index`) ⇒ SETOF `h3index`
*Since v4.1.0*
# PostGIS Region Functions
### h3_polygon_to_cells(multi `geometry`, resolution `integer`) ⇒ SETOF `h3index`
*Since v4.0.0*
### h3_polygon_to_cells(multi `geography`, resolution `integer`) ⇒ SETOF `h3index`
*Since v4.0.0*
### h3_cells_to_multi_polygon_geometry(`h3index[]`) ⇒ `geometry`
*Since v4.1.0*
### h3_cells_to_multi_polygon_geography(`h3index[]`) ⇒ `geography`
*Since v4.1.0*
### h3_cells_to_multi_polygon_geometry(setof `h3index`)
*Since v4.1.0*
### h3_cells_to_multi_polygon_geography(setof `h3index`)
*Since v4.1.0*
# PostGIS Operators
### Operator: `geometry` @ `integer`
*Since v4.1.3*
Index geometry at specified resolution.
### Operator: `geography` @ `integer`
*Since v4.1.3*
Index geography at specified resolution.
# PostGIS casts
### `h3index` :: `geometry`
*Since v0.3.0*
### `h3index` :: `geography`
*Since v0.3.0*
# WKB indexing functions
### h3_cell_to_boundary_wkb(cell `h3index`) ⇒ `bytea`
*Since v4.1.0*
Finds the boundary of the index, converts to EWKB.
Splits polygons when crossing 180th meridian.
This function has to return WKB since Postgres does not provide multipolygon type.
# WKB regions functions
### h3_cells_to_multi_polygon_wkb(`h3index[]`) ⇒ `bytea`
*Since v4.1.0*
Create a LinkedGeoPolygon describing the outline(s) of a set of hexagons, converts to EWKB.
Splits polygons when crossing 180th meridian.
# Raster processing functions
## Continuous raster data
For rasters with pixel values representing continuous data (temperature, humidity,
elevation), the data inside H3 cells can be summarized by calculating number of
pixels, sum, mean, standard deviation, min and max for each cell inside a raster
and grouping these stats across multiple rasters by H3 index.
```
SELECT
(summary).h3 AS h3,
(h3_raster_summary_stats_agg((summary).stats)).*
FROM (
SELECT h3_raster_summary(rast, 8) AS summary
FROM rasters
) t
GROUP BY 1;
h3 | count | sum | mean | stddev | min | max
-----------------+-------+--------------------+---------------------+--------------------+-------+------------------
882d638189fffff | 10 | 4.607657432556152 | 0.46076574325561526 | 1.3822972297668457 | 0 | 4.607657432556152
882d64c4d1fffff | 10 | 3.6940908953547478 | 0.3694090895354748 | 1.099336879464068 | 0 | 3.667332887649536
882d607431fffff | 11 | 6.219290263950825 | 0.5653900239955295 | 1.7624673707119065 | 0 | 6.13831996917724
<...>
```
*Since v4.1.1*
### h3_raster_summary_stats_agg(setof `h3_raster_summary_stats`)
*Since v4.1.1*
### h3_raster_summary_clip(rast `raster`, resolution `integer`, [nband `integer` = 1]) ⇒ TABLE (h3 `h3index`, stats `h3_raster_summary_stats`)
*Since v4.1.1*
Returns `h3_raster_summary_stats` for each H3 cell in raster for a given band. Clips the raster by H3 cell geometries and processes each part separately.
### h3_raster_summary_centroids(rast `raster`, resolution `integer`, [nband `integer` = 1]) ⇒ TABLE (h3 `h3index`, stats `h3_raster_summary_stats`)
*Since v4.1.1*
Returns `h3_raster_summary_stats` for each H3 cell in raster for a given band. Finds corresponding H3 cell for each pixel, then groups values by H3 index.
### h3_raster_summary_subpixel(rast `raster`, resolution `integer`, [nband `integer` = 1]) ⇒ TABLE (h3 `h3index`, stats `h3_raster_summary_stats`)
*Since v4.1.1*
Returns `h3_raster_summary_stats` for each H3 cell in raster for a given band. Assumes H3 cell is smaller than a pixel. Finds corresponding pixel for each H3 cell in raster.
### h3_raster_summary(rast `raster`, resolution `integer`, [nband `integer` = 1]) ⇒ TABLE (h3 `h3index`, stats `h3_raster_summary_stats`)
*Since v4.1.1*
Returns `h3_raster_summary_stats` for each H3 cell in raster for a given band. Attempts to select an appropriate method based on number of pixels per H3 cell.
## Discrete raster data
For rasters where pixels have discrete values corresponding to different classes
of land cover or land use, H3 cell data summary can be represented by a JSON object
with separate fields for each class. First, value, number of pixels and approximate
area are calculated for each H3 cell and value in a raster, then the stats are
grouped across multiple rasters by H3 index and value, and after that stats for
different values in a cell are combined into a single JSON object.
The following example query additionally calculates a fraction of H3 cell pixels
for each value, using a window function to get a total number of pixels:
```
WITH
summary AS (
-- get aggregated summary for each H3 index/value pair
SELECT h3, val, h3_raster_class_summary_item_agg(summary) AS item
FROM
rasters,
h3_raster_class_summary(rast, 8)
GROUP BY 1, 2),
summary_total AS (
-- add total number of pixels per H3 cell
SELECT h3, val, item, sum((item).count) OVER (PARTITION BY h3) AS total
FROM summary)
SELECT
h3,
jsonb_object_agg(
concat('class_', val::text),
h3_raster_class_summary_item_to_jsonb(item) -- val, count, area
|| jsonb_build_object('fraction', (item).count / total) -- add fraction value
ORDER BY val
) AS summary
FROM summary_total
GROUP BY 1;
h3 | summary
----------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------
88194e6f3bfffff | {"class_1": {"area": 75855.5748, "count": 46, "value": 1, "fraction": 0.4509}, "class_2": {"area": 92345.9171, "count": 56, "value": 2, "fraction": 0.5490}}
88194e6f37fffff | {"class_1": {"area": 255600.3064, "count": 155, "value": 1, "fraction": 0.5}, "class_2": {"area": 255600.3064, "count": 155, "value": 2, "fraction": 0.5}}
88194e6f33fffff | {"class_1": {"area": 336402.9840, "count": 204, "value": 1, "fraction": 0.5125}, "class_2": {"area": 319912.6416, "count": 194, "value": 2, "fraction": 0.4874}}
<...>
```
Area covered by pixels with the most frequent value in each cell:
```
SELECT DISTINCT ON (h3)
h3, val, (item).area
FROM (
SELECT
h3, val, h3_raster_class_summary_item_agg(summary) AS item
FROM
rasters,
h3_raster_class_summary(rast, 8)
GROUP BY 1, 2
) t
ORDER BY h3, (item).count DESC;
h3 | val | area
-----------------+-----+--------------------
88194e6f3bfffff | 5 | 23238.699360251427
88194e6f37fffff | 9 | 60863.26022922993
88194e6f33fffff | 8 | 76355.72646939754
<...>
```
*Since v4.1.1*
### h3_raster_class_summary_item_to_jsonb(item `h3_raster_class_summary_item`) ⇒ `jsonb`
*Since v4.1.1*
Convert raster summary to JSONB, example: `{"count": 10, "value": 2, "area": 16490.3423}`
### h3_raster_class_summary_item_agg(setof `h3_raster_class_summary_item`)
*Since v4.1.1*
### h3_raster_class_summary_clip(rast `raster`, resolution `integer`, [nband `integer` = 1]) ⇒ TABLE (h3 `h3index`, val `integer`, summary `h3_raster_class_summary_item`)
*Since v4.1.1*
Returns `h3_raster_class_summary_item` for each H3 cell and value for a given band. Clips the raster by H3 cell geometries and processes each part separately.
### h3_raster_class_summary_centroids(rast `raster`, resolution `integer`, [nband `integer` = 1]) ⇒ TABLE (h3 `h3index`, val `integer`, summary `h3_raster_class_summary_item`)
*Since v4.1.1*
Returns `h3_raster_class_summary_item` for each H3 cell and value for a given band. Finds corresponding H3 cell for each pixel, then groups by H3 and value.
### h3_raster_class_summary_subpixel(rast `raster`, resolution `integer`, [nband `integer` = 1]) ⇒ TABLE (h3 `h3index`, val `integer`, summary `h3_raster_class_summary_item`)
*Since v4.1.1*
Returns `h3_raster_class_summary_item` for each H3 cell and value for a given band. Assumes H3 cell is smaller than a pixel. Finds corresponding pixel for each H3 cell in raster.
### h3_raster_class_summary(rast `raster`, resolution `integer`, [nband `integer` = 1]) ⇒ TABLE (h3 `h3index`, val `integer`, summary `h3_raster_class_summary_item`)
*Since v4.1.1*
Returns `h3_raster_class_summary_item` for each H3 cell and value for a given band. Attempts to select an appropriate method based on number of pixels per H3 cell.
h3-pg-4.1.3/docs/development.md 0000664 0000000 0000000 00000002321 14460144644 0016236 0 ustar 00root root 0000000 0000000 ## Development
In order to build and test your changes, simply run `./scripts/develop`.
Documentation is generated from the sql files, using the script `scripts/documentaion` (requires poetry).
## Release Process
1. Update version number
- Don't follow semver, simply use major and minor from H3 core and increment patch.
- Version number should be changed in root `CMakeLists.txt`.
- Set `INSTALL_VERSION` to "${PROJECT_VERSION}".
- Update files (and cmake references) suffixed `--unreleased` should be renamed.
- Installer `.sql` files should have `@ availability` comments updated.
- Update changelog by moving from `Unreleased` to a new section
- Push and merge changes in `release-x.y.z` branch.
2. Create a release on GitHub
- Draft new release "vX.Y.Z"
- Copy CHANGELOG.md entry into release description
3. Distribute the extension on PGXN
- Run `scripts/bundle` to package the release
- Upload the distribution on [PGXN Manager](https://manager.pgxn.org/) (username: `bytesandbrains`)
4. Prepare for development
- Set `INSTALL_VERSION` to `unreleased` in root `CMakeLists.txt`.
- Create new update files with `--unreleased` suffix.
- Add them to relevant `CMakeLists.txt` files.
h3-pg-4.1.3/docs/pgxnclient.md 0000664 0000000 0000000 00000001041 14460144644 0016065 0 ustar 00root root 0000000 0000000 # PGXN Client
> `pgxnclient` does not normally ship with PostgreSQL, so you will probably have to install it manually.
The [PGXN Client](https://pgxn.github.io/pgxnclient/) is a command line tool designed to interact with the [PostgreSQL Extension Network](https://pgxn.org/) allowing searching, compiling, installing, and removing extensions in PostgreSQL databases.
## Ubuntu
On Ubuntu you can install using `apt`
```bash
apt-get install pgxnclient
```
## MacOS
On MacOs you can install using `brew`
```bash
brew install pgxnclient
``` h3-pg-4.1.3/h3/ 0000775 0000000 0000000 00000000000 14460144644 0012756 5 ustar 00root root 0000000 0000000 h3-pg-4.1.3/h3/CMakeLists.txt 0000664 0000000 0000000 00000005067 14460144644 0015526 0 ustar 00root root 0000000 0000000 PostgreSQL_add_extension(postgresql_h3
RELOCATABLE
NAME h3
COMMENT "H3 bindings for PostgreSQL"
VERSION ${INSTALL_VERSION}
COMPONENT ${PROJECT_NAME}
SOURCES
src/binding/edge.c
src/binding/hierarchy.c
src/binding/indexing.c
src/binding/inspection.c
src/binding/miscellaneous.c
src/binding/regions.c
src/binding/traversal.c
src/binding/vertex.c
src/deprecated.c
src/extension.c
src/guc.c
src/init.c
src/opclass_btree.c
src/opclass_hash.c
src/operators.c
src/srf.c
src/type.c
INSTALLS
sql/install/00-type.sql
sql/install/01-indexing.sql
sql/install/02-inspection.sql
sql/install/03-traversal.sql
sql/install/04-hierarchy.sql
sql/install/05-regions.sql
sql/install/06-edge.sql
sql/install/07-vertex.sql
sql/install/08-miscellaneous.sql
sql/install/10-operators.sql
sql/install/11-opclass_btree.sql
sql/install/12-opclass_hash.sql
sql/install/13-opclass_brin.sql
sql/install/20-casts.sql
sql/install/30-extension.sql
sql/install/99-deprecated.sql
UPDATES
sql/updates/h3--0.1.0.sql
sql/updates/h3--0.1.0--0.2.0.sql
sql/updates/h3--0.2.0--0.3.0.sql
sql/updates/h3--0.3.0--0.3.1.sql
sql/updates/h3--0.3.1--0.3.2.sql
sql/updates/h3--0.3.2--0.4.0.sql
sql/updates/h3--0.4.0--1.0.0.sql
sql/updates/h3--1.0.0--1.0.1.sql
sql/updates/h3--1.0.1--1.0.2.sql
sql/updates/h3--1.0.2--1.0.3.sql
sql/updates/h3--1.0.3--1.0.4.sql
sql/updates/h3--1.0.4--1.0.5.sql
sql/updates/h3--1.0.5--1.0.6.sql
sql/updates/h3--1.0.6--3.4.0.sql
sql/updates/h3--3.4.0--3.4.1.sql
sql/updates/h3--3.4.1--3.5.0.sql
sql/updates/h3--3.5.0--3.6.0.sql
sql/updates/h3--3.6.0--3.6.1.sql
sql/updates/h3--3.6.1--3.6.2.sql
sql/updates/h3--3.6.2--3.6.3.sql
sql/updates/h3--3.6.3--3.6.4.sql
sql/updates/h3--3.6.4--3.6.5.sql
sql/updates/h3--3.6.5--3.7.0.sql
sql/updates/h3--3.7.0--3.7.1.sql
sql/updates/h3--3.7.1--3.7.2.sql
sql/updates/h3--3.7.2--4.0.0.sql
sql/updates/h3--4.0.0--4.0.1.sql
sql/updates/h3--4.0.1--4.0.2.sql
sql/updates/h3--4.0.2--4.0.3.sql
sql/updates/h3--4.0.3--4.1.0.sql
sql/updates/h3--4.1.0--4.1.1.sql
sql/updates/h3--4.1.1--4.1.2.sql
sql/updates/h3--4.1.2--4.1.3.sql
)
# configure
configure_file(src/config.h.in src/config.h)
# include
target_include_directories(postgresql_h3 PRIVATE
${CMAKE_CURRENT_BINARY_DIR}/src
src
)
# link
target_link_libraries(postgresql_h3 PRIVATE
postgresql_h3_shared
h3
)
# test
if(BUILD_TESTING)
add_subdirectory(test)
endif()
h3-pg-4.1.3/h3/sql/ 0000775 0000000 0000000 00000000000 14460144644 0013555 5 ustar 00root root 0000000 0000000 h3-pg-4.1.3/h3/sql/install/ 0000775 0000000 0000000 00000000000 14460144644 0015223 5 ustar 00root root 0000000 0000000 h3-pg-4.1.3/h3/sql/install/00-type.sql 0000664 0000000 0000000 00000003711 14460144644 0017144 0 ustar 00root root 0000000 0000000 /*
* 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.
*/
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "CREATE EXTENSION h3" to load this file. \quit
-- ---------- ---------- ---------- ---------- ---------- ---------- ----------
--| The `h3` extension wraps the [H3 Core Library](https://github.com/uber/h3).
--| The detailed API reference is in the core [H3 Documentation](https://uber.github.io/h3) under the API Reference section.
--|
--| The `h3` core functions have been renamed from camelCase in H3 core to snake\_case in SQL.
--| The SQL function name is prefixed with `h3_`.
--|
--| # 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
-- before finally providing the full definition of the data type
CREATE TYPE h3index;
--@ internal
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 TYPE h3index (
INPUT = h3index_in,
OUTPUT = h3index_out,
LIKE = int8
);
h3-pg-4.1.3/h3/sql/install/01-indexing.sql 0000664 0000000 0000000 00000003453 14460144644 0017774 0 ustar 00root root 0000000 0000000 /*
* 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.
*/
--| # Indexing functions
--|
--| These function are used for finding the H3 index containing coordinates,
--| and for finding the center and boundary of H3 indexes.
--@ availability: 4.0.0
--@ ref: h3_lat_lng_to_cell_geometry, h3_lat_lng_to_cell_geography
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: 4.0.0
--@ ref: h3_cell_to_geometry, h3_cell_to_geography
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: 4.0.0
--@ ref: h3_cell_to_boundary_geometry, h3_cell_to_boundary_geography
CREATE OR REPLACE FUNCTION
h3_cell_to_boundary(cell h3index) RETURNS polygon
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION
h3_cell_to_boundary(h3index)
IS 'Finds the boundary of the index.
Use `SET h3.extend_antimeridian TO true` to extend coordinates when crossing 180th meridian.';
h3-pg-4.1.3/h3/sql/install/02-inspection.sql 0000664 0000000 0000000 00000004562 14460144644 0020345 0 ustar 00root root 0000000 0000000 /*
* 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.
*/
--| # Index inspection functions
--|
--| These functions provide metadata about an H3 index, such as its resolution
--| or base cell, and provide utilities for converting into and out of the
--| 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.';
--@ 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_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 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 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: 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.';
h3-pg-4.1.3/h3/sql/install/03-traversal.sql 0000664 0000000 0000000 00000006316 14460144644 0020175 0 ustar 00root root 0000000 0000000 /*
* 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.
*/
--| # Grid traversal functions
--|
--| 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: 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: 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: 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: 4.0.0
--@ ref: h3_grid_path_cells_recursive
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: 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_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_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.';
h3-pg-4.1.3/h3/sql/install/04-hierarchy.sql 0000664 0000000 0000000 00000013737 14460144644 0020156 0 ustar 00root root 0000000 0000000 /*
* 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.
*/
--| # Hierarchical grid functions
--|
--| These functions permit moving between resolutions in the H3 grid system.
--| The functions produce parent (coarser) or children (finer) cells.
--@ 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.1.0
CREATE OR REPLACE FUNCTION
h3_cell_to_child_pos(child h3index, parentRes integer) RETURNS int8
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION
h3_cell_to_child_pos(child h3index, parentRes integer)
IS 'Returns the position of the child cell within an ordered list of all children of the cells parent at the specified resolution parentRes. The order of the ordered list is the same as that returned by cellToChildren. This is the complement of childPosToCell.';
--@ availability: 4.1.0
CREATE OR REPLACE FUNCTION
h3_child_pos_to_cell(childPos int8, parent h3index, childRes int) RETURNS h3index
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION
h3_child_pos_to_cell(childPos int8, parent h3index, childRes int)
IS 'Returns the child cell at a given position within an ordered list of all children of parent at the specified resolution childRes. The order of the ordered list is the same as that returned by cellToChildren. This is the complement of cellToChildPos.';
--@ 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_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;
--@ 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.';
h3-pg-4.1.3/h3/sql/install/05-regions.sql 0000664 0000000 0000000 00000003524 14460144644 0017640 0 ustar 00root root 0000000 0000000 /*
* 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.
*/
--| # Region functions
--|
--| These functions convert H3 indexes to and from polygonal areas.
--@ availability: 4.0.0
--@ ref: h3_polygon_to_cells_geometry, h3_polygon_to_cells_geography
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: 4.0.0
--@ ref: h3_cells_to_multi_polygon_geometry, h3_cells_to_multi_polygon_geography, h3_cells_to_multi_polygon_geometry_agg, h3_cells_to_multi_polygon_geography_agg
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.';
h3-pg-4.1.3/h3/sql/install/06-edge.sql 0000664 0000000 0000000 00000006204 14460144644 0017075 0 ustar 00root root 0000000 0000000 /*
* 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.';
h3-pg-4.1.3/h3/sql/install/07-vertex.sql 0000664 0000000 0000000 00000003405 14460144644 0017507 0 ustar 00root root 0000000 0000000 /*
* 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.';
h3-pg-4.1.3/h3/sql/install/08-miscellaneous.sql 0000664 0000000 0000000 00000006070 14460144644 0021037 0 ustar 00root root 0000000 0000000 /*
* 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.'; h3-pg-4.1.3/h3/sql/install/10-operators.sql 0000664 0000000 0000000 00000011045 14460144644 0020201 0 ustar 00root root 0000000 0000000 /*
* 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.
*/
--| # Operators
--@ internal
CREATE OR REPLACE FUNCTION h3index_distance(h3index, h3index) RETURNS bigint
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
--@ availability: 3.7.0
CREATE OPERATOR <-> (
LEFTARG = h3index,
RIGHTARG = h3index,
PROCEDURE = h3index_distance,
COMMUTATOR = <->
);
COMMENT ON OPERATOR <-> (h3index, h3index) IS
'Returns the distance in grid cells between the two indices (at the lowest resolution of the two).';
-- ---------- ---------- ---------- ---------- ---------- ---------- ----------
--| ## B-tree operators
--@ internal
CREATE OR REPLACE FUNCTION h3index_eq(h3index, h3index) RETURNS boolean
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
--@ availability: 0.1.0
CREATE OPERATOR = (
LEFTARG = h3index,
RIGHTARG = h3index,
PROCEDURE = h3index_eq,
COMMUTATOR = =,
NEGATOR = <>,
RESTRICT = eqsel,
JOIN = eqjoinsel,
HASHES, MERGES
);
COMMENT ON OPERATOR = (h3index, h3index) IS
'Returns true if two indexes are the same.';
--@ internal
CREATE OR REPLACE FUNCTION h3index_ne(h3index, h3index) RETURNS boolean
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
--@ availability: 0.1.0
CREATE OPERATOR <> (
LEFTARG = h3index,
RIGHTARG = h3index,
PROCEDURE = h3index_ne,
COMMUTATOR = <>,
NEGATOR = =,
RESTRICT = neqsel,
JOIN = neqjoinsel
);
--@ internal
CREATE OR REPLACE FUNCTION h3index_lt(h3index, h3index) RETURNS boolean
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
--@ internal
CREATE OPERATOR < (
LEFTARG = h3index,
RIGHTARG = h3index,
PROCEDURE = h3index_lt,
COMMUTATOR = > ,
NEGATOR = >= ,
RESTRICT = scalarltsel,
JOIN = scalarltjoinsel
);
--@ internal
CREATE OR REPLACE FUNCTION h3index_le(h3index, h3index) RETURNS boolean
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
--@ internal
CREATE OPERATOR <= (
LEFTARG = h3index,
RIGHTARG = h3index,
PROCEDURE = h3index_le,
COMMUTATOR = >= ,
NEGATOR = > ,
RESTRICT = scalarltsel,
JOIN = scalarltjoinsel
);
--@ internal
CREATE OR REPLACE FUNCTION h3index_gt(h3index, h3index) RETURNS boolean
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
--@ internal
CREATE OPERATOR > (
LEFTARG = h3index,
RIGHTARG = h3index,
PROCEDURE = h3index_gt,
COMMUTATOR = < ,
NEGATOR = <= ,
RESTRICT = scalargtsel,
JOIN = scalargtjoinsel
);
--@ internal
CREATE OR REPLACE FUNCTION h3index_ge(h3index, h3index) RETURNS boolean
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
--@ internal
CREATE OPERATOR >= (
LEFTARG = h3index,
RIGHTARG = h3index,
PROCEDURE = h3index_ge,
COMMUTATOR = <= ,
NEGATOR = < ,
RESTRICT = scalargtsel,
JOIN = scalargtjoinsel
);
-- ---------- ---------- ---------- ---------- ---------- ---------- ----------
--| ## R-tree Operators
--@ internal
CREATE OR REPLACE FUNCTION h3index_overlaps(h3index, h3index) RETURNS boolean
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
--@ availability: 3.6.1
CREATE OPERATOR && (
PROCEDURE = h3index_overlaps,
LEFTARG = h3index, RIGHTARG = h3index,
COMMUTATOR = &&,
RESTRICT = contsel, JOIN = contjoinsel
);
COMMENT ON OPERATOR && (h3index, h3index) IS
'Returns true if the two H3 indexes intersect.';
--@ internal
CREATE OR REPLACE FUNCTION h3index_contains(h3index, h3index) RETURNS boolean
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
--@ availability: 3.6.1
CREATE OPERATOR @> (
PROCEDURE = h3index_contains,
LEFTARG = h3index, RIGHTARG = h3index,
COMMUTATOR = <@,
RESTRICT = contsel, JOIN = contjoinsel
);
COMMENT ON OPERATOR @> (h3index, h3index) IS
'Returns true if A contains B.';
--@ internal
CREATE OR REPLACE FUNCTION h3index_contained_by(h3index, h3index) RETURNS boolean
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
--@ availability: 3.6.1
CREATE OPERATOR <@ (
PROCEDURE = h3index_contained_by,
LEFTARG = h3index, RIGHTARG = h3index,
COMMUTATOR = @>,
RESTRICT = contsel, JOIN = contjoinsel
);
COMMENT ON OPERATOR <@ (h3index, h3index) IS
'Returns true if A is contained by B.';
h3-pg-4.1.3/h3/sql/install/11-opclass_btree.sql 0000664 0000000 0000000 00000002305 14460144644 0021010 0 ustar 00root root 0000000 0000000 /*
* 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.
*/
-- B-tree operator class
--@ internal
CREATE OR REPLACE FUNCTION h3index_cmp(h3index, h3index) RETURNS integer
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
--@ internal
CREATE OR REPLACE FUNCTION h3index_sortsupport(internal)
RETURNS void
AS 'h3', 'h3index_sortsupport'
LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
--@ internal
CREATE OPERATOR CLASS h3index_ops DEFAULT FOR TYPE h3index USING btree AS
OPERATOR 1 < ,
OPERATOR 2 <= ,
OPERATOR 3 = ,
OPERATOR 4 >= ,
OPERATOR 5 > ,
FUNCTION 1 h3index_cmp(h3index, h3index),
FUNCTION 2 h3index_sortsupport(internal);
h3-pg-4.1.3/h3/sql/install/12-opclass_hash.sql 0000664 0000000 0000000 00000002121 14460144644 0020627 0 ustar 00root root 0000000 0000000 /*
* 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.
*/
-- Hash operator class
--@ internal
CREATE OR REPLACE FUNCTION h3index_hash(h3index) RETURNS integer
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
--@ internal
CREATE OR REPLACE FUNCTION h3index_hash_extended(h3index, int8) RETURNS int8
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
--@ internal
CREATE OPERATOR CLASS h3index_ops DEFAULT FOR TYPE h3index USING hash AS
OPERATOR 1 = ,
FUNCTION 1 h3index_hash(h3index),
FUNCTION 2 h3index_hash_extended(h3index, int8);
h3-pg-4.1.3/h3/sql/install/13-opclass_brin.sql 0000664 0000000 0000000 00000002103 14460144644 0020637 0 ustar 00root root 0000000 0000000 /*
* 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.
*/
-- BRIN operator class
--@ internal
CREATE OPERATOR CLASS h3index_minmax_ops DEFAULT FOR TYPE h3index USING brin AS
OPERATOR 1 < ,
OPERATOR 2 <= ,
OPERATOR 3 = ,
OPERATOR 4 >= ,
OPERATOR 5 > ,
FUNCTION 1 brin_minmax_opcinfo(internal),
FUNCTION 2 brin_minmax_add_value(internal, internal, internal, internal),
FUNCTION 3 brin_minmax_consistent(internal, internal, internal),
FUNCTION 4 brin_minmax_union(internal, internal, internal);
h3-pg-4.1.3/h3/sql/install/20-casts.sql 0000664 0000000 0000000 00000002555 14460144644 0017307 0 ustar 00root root 0000000 0000000 /*
* 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.'; h3-pg-4.1.3/h3/sql/install/30-extension.sql 0000664 0000000 0000000 00000002245 14460144644 0020203 0 ustar 00root root 0000000 0000000 /*
* 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.
*/
--| # Extension specific functions
--@ availability: 1.0.0
CREATE OR REPLACE FUNCTION h3_get_extension_version() RETURNS text
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION h3_get_extension_version() IS
'Get the currently installed version of the extension.';
--@ availability: 4.1.0
CREATE OR REPLACE FUNCTION h3_pg_migrate_pass_by_reference(h3index) RETURNS h3index
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION h3_pg_migrate_pass_by_reference(h3index) IS
'Migrate h3index from pass-by-reference to pass-by-value.';
h3-pg-4.1.3/h3/sql/install/99-deprecated.sql 0000664 0000000 0000000 00000001626 14460144644 0020310 0 ustar 00root root 0000000 0000000 /*
* 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.
*/
--| # Deprecated functions
CREATE OR REPLACE FUNCTION
h3_cell_to_boundary(cell h3index, extend_antimeridian boolean) RETURNS polygon
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION
h3_cell_to_boundary(h3index, boolean)
IS 'DEPRECATED: Use `SET h3.extend_antimeridian TO true` instead.';
h3-pg-4.1.3/h3/sql/updates/ 0000775 0000000 0000000 00000000000 14460144644 0015222 5 ustar 00root root 0000000 0000000 h3-pg-4.1.3/h3/sql/updates/h3--0.1.0--0.2.0.sql 0000664 0000000 0000000 00000025742 14460144644 0017506 0 ustar 00root root 0000000 0000000 /*
* 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.
*/
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "ALTER EXTENSION h3 UPDATE TO '0.2.0'" to load this file. \quit
-- 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;
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' 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' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION h3_h3_to_geo_boundary(h3index) IS
'Finds the boundary of the index';
-- Index inspection functions (inspection.c)
CREATE OR REPLACE FUNCTION h3_h3_get_resolution(h3index) RETURNS integer
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
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' 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' 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
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION h3_h3_is_res_class_iii(h3index) IS
'Returns true if this index has a resolution with Class III orientation';
CREATE OR REPLACE FUNCTION h3_h3_is_pentagon(h3index) RETURNS bool
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION h3_h3_is_pentagon(h3index) IS
'Returns true if this index represents a pentagonal cell';
-- 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;
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;
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;
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;
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;
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;
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' 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' 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;
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;
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
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' 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' 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;
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' 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;
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;
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;
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;
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' 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;
COMMENT ON FUNCTION h3_num_hexagons(resolution integer) IS
'Number of unique H3 indexes at the given resolution.';
-- DEPRECATED in v3.4.0
CREATE OR REPLACE FUNCTION h3_degs_to_rads(float) RETURNS float
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE OR REPLACE FUNCTION h3_rads_to_degs(float) RETURNS float
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
-- DEPRECATED in v3.5.0
CREATE OR REPLACE FUNCTION h3_hex_area_km2(integer) RETURNS float
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE OR REPLACE FUNCTION h3_hex_area_m2(integer) RETURNS float
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE OR REPLACE FUNCTION h3_edge_length_km(integer) RETURNS float
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE OR REPLACE FUNCTION h3_edge_length_m(integer) RETURNS float
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE OR REPLACE FUNCTION h3_hex_range(h3index, k integer) RETURNS SETOF h3index
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE OR REPLACE FUNCTION h3_hex_range_distances(h3index, k integer, OUT h3index, OUT int) RETURNS SETOF record
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE OR REPLACE FUNCTION h3_hex_ranges(h3index[], k integer) RETURNS SETOF h3index
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
-- DEPRECATED in v3.6.0
CREATE OR REPLACE FUNCTION h3_string_to_h3(cstring) RETURNS h3index
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE OR REPLACE FUNCTION h3_h3_to_string(h3index) RETURNS cstring
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
h3-pg-4.1.3/h3/sql/updates/h3--0.1.0.sql 0000664 0000000 0000000 00000007005 14460144644 0016766 0 ustar 00root root 0000000 0000000 /*
* Copyright 2018 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 "CREATE EXTENSION h3" to load this file. \quit
-- Declare shell type, allowing us to reference while defining functions
CREATE TYPE h3index;
CREATE OR REPLACE FUNCTION h3index_in(cstring) RETURNS h3index
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 OR REPLACE FUNCTION h3index_eq(h3index, h3index) RETURNS boolean
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE OR REPLACE FUNCTION h3index_ne(h3index, h3index) RETURNS boolean
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE OR REPLACE FUNCTION h3index_lt(h3index, h3index) RETURNS boolean
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE OR REPLACE FUNCTION h3index_le(h3index, h3index) RETURNS boolean
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE OR REPLACE FUNCTION h3index_gt(h3index, h3index) RETURNS boolean
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE OR REPLACE FUNCTION h3index_ge(h3index, h3index) RETURNS boolean
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE OR REPLACE FUNCTION h3index_cmp(h3index, h3index) RETURNS integer
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
-- Finally, we can provide the full definition of the data type
CREATE TYPE h3index (
INTERNALLENGTH = 8,
INPUT = h3index_in,
OUTPUT = h3index_out,
ALIGNMENT = double
);
-- Operators
CREATE OPERATOR = (
LEFTARG = h3index,
RIGHTARG = h3index,
PROCEDURE = h3index_eq,
COMMUTATOR = =,
NEGATOR = <>,
RESTRICT = eqsel,
JOIN = eqjoinsel,
HASHES, MERGES
);
CREATE OPERATOR <> (
LEFTARG = h3index,
RIGHTARG = h3index,
PROCEDURE = h3index_ne,
COMMUTATOR = <>,
NEGATOR = =,
RESTRICT = neqsel,
JOIN = neqjoinsel
);
CREATE OPERATOR < (
LEFTARG = h3index,
RIGHTARG = h3index,
PROCEDURE = h3index_lt,
COMMUTATOR = > ,
NEGATOR = >= ,
RESTRICT = scalarltsel,
JOIN = scalarltjoinsel
);
CREATE OPERATOR <= (
LEFTARG = h3index,
RIGHTARG = h3index,
PROCEDURE = h3index_le,
COMMUTATOR = >= ,
NEGATOR = > ,
RESTRICT = scalarltsel,
JOIN = scalarltjoinsel
);
CREATE OPERATOR > (
LEFTARG = h3index,
RIGHTARG = h3index,
PROCEDURE = h3index_gt,
COMMUTATOR = < ,
NEGATOR = <= ,
RESTRICT = scalargtsel,
JOIN = scalargtjoinsel
);
CREATE OPERATOR >= (
LEFTARG = h3index,
RIGHTARG = h3index,
PROCEDURE = h3index_ge,
COMMUTATOR = <= ,
NEGATOR = < ,
RESTRICT = scalargtsel,
JOIN = scalargtjoinsel
);
-- Operator class
CREATE OPERATOR CLASS btree_h3index_ops DEFAULT FOR TYPE h3index
USING btree AS
OPERATOR 1 < ,
OPERATOR 2 <= ,
OPERATOR 3 = ,
OPERATOR 4 >= ,
OPERATOR 5 > ,
FUNCTION 1 h3index_cmp(h3index, h3index);
h3-pg-4.1.3/h3/sql/updates/h3--0.2.0--0.3.0.sql 0000664 0000000 0000000 00000010653 14460144644 0017503 0 ustar 00root root 0000000 0000000 /*
* 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.
*/
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "ALTER EXTENSION h3 UPDATE TO '0.3.0'" to load this file. \quit
-- Custom helper functions
CREATE OR REPLACE FUNCTION h3_basecells() RETURNS SETOF h3index
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION h3_basecells() IS
'Returns all 122 basecells.';
CREATE OR REPLACE FUNCTION __h3_h3_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_h3_get_resolution(index) into current;
END IF;
IF resolution = -1 THEN
SELECT h3_h3_get_resolution(index)+1 into resolution;
END IF;
IF current < resolution THEN
SELECT ARRAY(SELECT h3_h3_to_children_fast(index)) into retSet;
FOREACH r in ARRAY retSet LOOP
RETURN QUERY SELECT __h3_h3_to_children_aux(r, resolution, current + 1);
END LOOP;
ELSE
RETURN NEXT index;
END IF;
END;$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION h3_h3_to_children_slow(index h3index, resolution integer DEFAULT -1) RETURNS SETOF h3index
AS $$ SELECT __h3_h3_to_children_aux($1, $2, -1) $$ LANGUAGE SQL;
COMMENT ON FUNCTION h3_h3_to_children_slow(index h3index, resolution integer) IS
'Slower version of H3ToChildren but allocates less memory';
-- PostGIS
--CREATE OR REPLACE FUNCTION h3_geo_to_h3(geometry, resolution integer) RETURNS h3index
-- AS $$ SELECT h3_geo_to_h3($1::point, $2); $$ LANGUAGE SQL;
--CREATE OR REPLACE FUNCTION h3_geo_to_h3(geography, resolution integer) RETURNS h3index
-- AS $$ SELECT h3_geo_to_h3($1::geometry, $2); $$ LANGUAGE SQL;
--CREATE OR REPLACE FUNCTION h3_h3_to_geometry(h3index) RETURNS geometry
-- AS $$ SELECT ST_SetSRID(h3_h3_to_geo($1)::geometry, 4326) $$ LANGUAGE SQL;
--CREATE OR REPLACE FUNCTION h3_h3_to_geography(h3index) RETURNS geography
-- AS $$ SELECT h3_h3_to_geometry($1)::geography $$ LANGUAGE SQL;
--CREATE OR REPLACE FUNCTION h3_h3_to_geo_boundary_geometry(h3index) RETURNS geometry
-- AS $$ SELECT ST_SetSRID(h3_h3_to_geo_boundary($1)::geometry, 4326) $$ LANGUAGE SQL;
--CREATE OR REPLACE FUNCTION h3_h3_to_geo_boundary_geography(h3index) RETURNS geography
-- AS $$ SELECT h3_h3_to_geo_boundary_geometry($1)::geography $$ LANGUAGE SQL;
--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 STRICT;
--CREATE OR REPLACE FUNCTION h3_polyfill(multi geography, resolution integer) RETURNS SETOF h3index
--AS $$ SELECT h3_polyfill($1::geometry, $2) $$ LANGUAGE SQL;
-- Type casts
CREATE CAST (h3index AS point) WITH FUNCTION h3_h3_to_geo(h3index);
--CREATE CAST (h3index AS geometry) WITH FUNCTION h3_h3_to_geometry(h3index);
--CREATE CAST (h3index AS geography) WITH FUNCTION h3_h3_to_geography(h3index);
-- DEPRECATED in v1.0.0
CREATE OR REPLACE FUNCTION h3_haversine_distance(h3index, h3index) RETURNS double precision
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
h3-pg-4.1.3/h3/sql/updates/h3--0.3.0--0.3.1.sql 0000664 0000000 0000000 00000003264 14460144644 0017505 0 ustar 00root root 0000000 0000000 /*
* 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.
*/
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "ALTER EXTENSION h3 UPDATE TO '0.3.1'" to load this file. \quit
DROP FUNCTION IF EXISTS h3_h3_to_geo_boundary(h3index);
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' 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
-- AS $$ SELECT ST_SetSRID(h3_h3_to_geo_boundary($1, $2)::geometry, 4326) $$ LANGUAGE SQL;
--CREATE OR REPLACE FUNCTION h3_h3_to_geo_boundary_geography(h3index, extend BOOLEAN DEFAULT FALSE) RETURNS geography
-- AS $$ SELECT h3_h3_to_geo_boundary_geometry($1, $2)::geography $$ LANGUAGE SQL; h3-pg-4.1.3/h3/sql/updates/h3--0.3.1--0.3.2.sql 0000664 0000000 0000000 00000001421 14460144644 0017500 0 ustar 00root root 0000000 0000000 /*
* Copyright 2018 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 '0.3.2'" to load this file. \quit
-- NO CHANGES HERE, ONLY IN C FILES
h3-pg-4.1.3/h3/sql/updates/h3--0.3.2--0.4.0.sql 0000664 0000000 0000000 00000003675 14460144644 0017515 0 ustar 00root root 0000000 0000000 /*
* 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.
*/
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
\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;
COMMENT ON FUNCTION h3_line(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.';
CREATE OR REPLACE FUNCTION __h3_h3_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_h3_get_resolution(index) into current;
END IF;
IF resolution = -1 THEN
SELECT h3_h3_get_resolution(index)+1 into resolution;
END IF;
IF current < resolution THEN
SELECT ARRAY(SELECT h3_h3_to_children(index)) into retSet;
FOREACH r in ARRAY retSet LOOP
RETURN QUERY SELECT __h3_h3_to_children_aux(r, resolution, current + 1);
END LOOP;
ELSE
RETURN NEXT index;
END IF;
END;$$ LANGUAGE plpgsql; h3-pg-4.1.3/h3/sql/updates/h3--0.4.0--1.0.0.sql 0000664 0000000 0000000 00000010724 14460144644 0017502 0 ustar 00root root 0000000 0000000 /*
* 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.
*/
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "CREATE EXTENSION h3" to load this file. \quit
DROP FUNCTION IF EXISTS h3_haversine_distance(h3index, h3index);
ALTER FUNCTION h3_basecells() RENAME TO h3_get_res_0_indexes;
COMMENT ON FUNCTION h3_get_res_0_indexes() IS
'Get all resolution 0 indexes.';
-- rename functions with double (h3_h3_) prefix
ALTER FUNCTION h3_h3_get_base_cell(h3index) RENAME TO h3_get_base_cell;
ALTER FUNCTION h3_h3_get_resolution(h3index) RENAME TO h3_get_resolution;
ALTER FUNCTION h3_h3_is_pentagon(h3index) RENAME TO h3_is_pentagon;
ALTER FUNCTION h3_h3_is_res_class_iii(h3index) RENAME TO h3_is_res_class_iii;
ALTER FUNCTION h3_h3_is_valid(h3index) RENAME TO h3_is_valid;
ALTER FUNCTION h3_h3_indexes_are_neighbors(h3index,h3index) RENAME TO h3_indexes_are_neighbors;
ALTER FUNCTION h3_h3_set_to_linked_geo(h3index[]) RENAME TO h3_set_to_linked_geo;
ALTER FUNCTION __h3_h3_to_children_aux(h3index,integer,integer) RENAME TO __h3_to_children_aux;
ALTER FUNCTION h3_h3_to_children(h3index,integer) RENAME TO h3_to_children;
ALTER FUNCTION h3_h3_to_children_slow(h3index,integer) RENAME TO h3_to_children_slow;
--ALTER FUNCTION h3_h3_to_geo_boundary_geography(h3index,boolean) RENAME TO h3_to_geo_boundary_geography;
--ALTER FUNCTION h3_h3_to_geo_boundary_geometry(h3index,boolean) RENAME TO h3_to_geo_boundary_geometry;
ALTER FUNCTION h3_h3_to_geo_boundary(h3index,boolean) RENAME TO h3_to_geo_boundary;
--ALTER FUNCTION h3_h3_to_geography(h3index) RENAME TO h3_to_geography;
ALTER FUNCTION h3_h3_to_geo(h3index) RENAME TO h3_to_geo;
--ALTER FUNCTION h3_h3_to_geometry(h3index) RENAME TO h3_to_geometry;
ALTER FUNCTION h3_h3_to_parent(h3index,integer) RENAME TO h3_to_parent;
ALTER FUNCTION h3_h3_to_string(h3index) RENAME TO h3_to_string;
ALTER FUNCTION h3_h3_unidirectional_edge_is_valid(h3index) RENAME TO h3_unidirectional_edge_is_valid;
--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) $$ LANGUAGE SQL;
--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 $$ LANGUAGE SQL;
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
'Slower version of H3ToChildren but allocates less memory';
CREATE OR REPLACE FUNCTION __h3_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_to_children(index)) into retSet;
FOREACH r in ARRAY retSet LOOP
RETURN QUERY SELECT __h3_to_children_aux(r, resolution, current + 1);
END LOOP;
ELSE
RETURN NEXT index;
END IF;
END;$$ LANGUAGE plpgsql;
-- version
CREATE OR REPLACE FUNCTION h3_get_extension_version() RETURNS text
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION h3_get_extension_version() IS
'Get the currently installed version of the extension.';
-- hash operators
CREATE OR REPLACE FUNCTION h3index_hash(h3index) RETURNS integer
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE OPERATOR CLASS hash_h3index_ops DEFAULT FOR TYPE h3index
USING hash AS
OPERATOR 1 = ,
FUNCTION 1 h3index_hash(h3index);
h3-pg-4.1.3/h3/sql/updates/h3--1.0.0--1.0.1.sql 0000664 0000000 0000000 00000001145 14460144644 0017475 0 ustar 00root root 0000000 0000000 /*
* Copyright 2018 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.
*/
-- no changes
h3-pg-4.1.3/h3/sql/updates/h3--1.0.1--1.0.2.sql 0000664 0000000 0000000 00000001145 14460144644 0017477 0 ustar 00root root 0000000 0000000 /*
* Copyright 2018 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.
*/
-- no changes
h3-pg-4.1.3/h3/sql/updates/h3--1.0.2--1.0.3.sql 0000664 0000000 0000000 00000001145 14460144644 0017501 0 ustar 00root root 0000000 0000000 /*
* Copyright 2018 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.
*/
-- no changes
h3-pg-4.1.3/h3/sql/updates/h3--1.0.3--1.0.4.sql 0000664 0000000 0000000 00000001421 14460144644 0017500 0 ustar 00root root 0000000 0000000 /*
* Copyright 2018 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 '1.0.4'" to load this file. \quit
-- NO CHANGES HERE, ONLY IN C FILES
h3-pg-4.1.3/h3/sql/updates/h3--1.0.4--1.0.5.sql 0000664 0000000 0000000 00000001421 14460144644 0017502 0 ustar 00root root 0000000 0000000 /*
* Copyright 2018 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 '1.0.5'" to load this file. \quit
-- NO CHANGES HERE, ONLY IN C FILES
h3-pg-4.1.3/h3/sql/updates/h3--1.0.5--1.0.6.sql 0000664 0000000 0000000 00000001421 14460144644 0017504 0 ustar 00root root 0000000 0000000 /*
* Copyright 2018 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 '1.0.6'" to load this file. \quit
-- NO CHANGES HERE, ONLY IN C FILES
h3-pg-4.1.3/h3/sql/updates/h3--1.0.6--3.4.0.sql 0000664 0000000 0000000 00000001515 14460144644 0017511 0 ustar 00root root 0000000 0000000 /*
* Copyright 2018 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 '3.4.0'" to load this file. \quit
DROP FUNCTION IF EXISTS h3_degs_to_rads(float);
DROP FUNCTION IF EXISTS h3_rads_to_degs(float);
h3-pg-4.1.3/h3/sql/updates/h3--3.4.0--3.4.1.sql 0000664 0000000 0000000 00000001354 14460144644 0017513 0 ustar 00root root 0000000 0000000 /*
* 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.
*/
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "ALTER EXTENSION h3 UPDATE TO '3.4.1'" to load this file. \quit
h3-pg-4.1.3/h3/sql/updates/h3--3.4.1--3.5.0.sql 0000664 0000000 0000000 00000004313 14460144644 0017512 0 ustar 00root root 0000000 0000000 /*
* 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.
*/
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
\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;
COMMENT ON FUNCTION h3_get_faces(h3index) IS
'Find all icosahedron faces intersected by a given H3 index';
ALTER FUNCTION h3_get_unidirectional_edge_boundary(h3index) RENAME TO h3_get_h3_unidirectional_edge_boundary;
-- replace separate length functions with single function
DROP FUNCTION IF EXISTS h3_edge_length_km(integer);
DROP FUNCTION IF EXISTS h3_edge_length_m(integer);
CREATE OR REPLACE FUNCTION h3_edge_length(resolution integer, km boolean DEFAULT FALSE) RETURNS float
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION h3_edge_length(integer, boolean) IS
'Average hexagon edge length in (kilo)meters at the given resolution.';
-- replace separate area functions with single function
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;
COMMENT ON FUNCTION h3_hex_area(integer, boolean) IS
'Average hexagon area in square (kilo)meters at the given resolution.';
DROP FUNCTION IF EXISTS h3_hex_range(h3index, integer);
DROP FUNCTION IF EXISTS h3_hex_range_distances(h3index, integer);
DROP FUNCTION IF EXISTS h3_hex_ranges(h3index[], integer);
ALTER FUNCTION h3_set_to_linked_geo(h3index[]) RENAME TO h3_set_to_multi_polygon; h3-pg-4.1.3/h3/sql/updates/h3--3.5.0--3.6.0.sql 0000664 0000000 0000000 00000003674 14460144644 0017524 0 ustar 00root root 0000000 0000000 /*
* 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.
*/
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "ALTER EXTENSION h3 UPDATE TO '3.6.0'" to load this file. \quit
-- 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;
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;
COMMENT ON FUNCTION h3_get_res_0_indexes() IS
'All the pentagon H3 indexes at the specified resolution.';
-- type casts
CREATE OR REPLACE FUNCTION h3index_to_bigint(h3index) RETURNS bigint
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE OR REPLACE FUNCTION bigint_to_h3index(bigint) RETURNS h3index
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE CAST (h3index AS bigint) WITH FUNCTION h3index_to_bigint(h3index);
CREATE CAST (bigint AS h3index) WITH FUNCTION bigint_to_h3index(bigint);
-- string conversion already provided by type itself
DROP FUNCTION IF EXISTS h3_to_string(h3index);
DROP FUNCTION IF EXISTS h3_string_to_h3(cstring); h3-pg-4.1.3/h3/sql/updates/h3--3.6.0--3.6.1.sql 0000664 0000000 0000000 00000003230 14460144644 0017512 0 ustar 00root root 0000000 0000000 /*
* 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.
*/
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "ALTER EXTENSION h3 UPDATE TO '3.6.1'" to load this file. \quit
-- add R-tree operators
CREATE OR REPLACE FUNCTION h3index_overlaps(h3index, h3index) RETURNS boolean
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE OR REPLACE FUNCTION h3index_contains(h3index, h3index) RETURNS boolean
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE OR REPLACE FUNCTION h3index_contained_by(h3index, h3index) RETURNS boolean
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE OPERATOR && (
PROCEDURE = h3index_overlaps,
LEFTARG = h3index,
RIGHTARG = h3index,
COMMUTATOR = &&,
RESTRICT = contsel,
JOIN = contjoinsel
);
CREATE OPERATOR @> (
PROCEDURE = h3index_contains,
LEFTARG = h3index,
RIGHTARG = h3index,
COMMUTATOR = <@,
RESTRICT = contsel,
JOIN = contjoinsel
);
CREATE OPERATOR <@ (
PROCEDURE = h3index_contained_by,
LEFTARG = h3index,
RIGHTARG = h3index,
COMMUTATOR = @>,
RESTRICT = contsel,
JOIN = contjoinsel
);
h3-pg-4.1.3/h3/sql/updates/h3--3.6.1--3.6.2.sql 0000664 0000000 0000000 00000002321 14460144644 0017514 0 ustar 00root root 0000000 0000000 /*
* 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.
*/
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "ALTER EXTENSION h3 UPDATE TO '3.6.2'" to load this file. \quit
-- add sort support (see #24)
CREATE OR REPLACE FUNCTION h3index_sortsupport(internal)
RETURNS void
AS 'h3', 'h3index_sortsupport'
LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
ALTER OPERATOR family btree_h3index_ops USING btree ADD FUNCTION 2 (h3index) h3index_sortsupport(internal);
-- pass-by-value on supported systems (see #26)
UPDATE pg_type AS sink
SET typbyval = source.typbyval FROM (
SELECT typbyval FROM pg_type WHERE typname = 'int8'
) source
WHERE typname = 'h3index';
h3-pg-4.1.3/h3/sql/updates/h3--3.6.2--3.6.3.sql 0000664 0000000 0000000 00000001372 14460144644 0017523 0 ustar 00root root 0000000 0000000 /*
* 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.
*/
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "ALTER EXTENSION h3 UPDATE TO '3.6.3'" to load this file. \quit
-- no changes h3-pg-4.1.3/h3/sql/updates/h3--3.6.3--3.6.4.sql 0000664 0000000 0000000 00000001372 14460144644 0017525 0 ustar 00root root 0000000 0000000 /*
* 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.
*/
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "ALTER EXTENSION h3 UPDATE TO '3.6.4'" to load this file. \quit
-- no changes h3-pg-4.1.3/h3/sql/updates/h3--3.6.4--3.6.5.sql 0000664 0000000 0000000 00000003677 14460144644 0017541 0 ustar 00root root 0000000 0000000 /*
* 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.
* 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 '3.6.5'" to load this file. \quit
-- Fix function flags which were previously only changed in install files
ALTER FUNCTION h3_get_h3_unidirectional_edge_boundary(h3index)
IMMUTABLE STRICT PARALLEL SAFE;
--ALTER FUNCTION h3_geo_to_h3(geometry, integer)
-- IMMUTABLE STRICT PARALLEL SAFE;
--ALTER FUNCTION h3_geo_to_h3(geography, integer)
-- IMMUTABLE STRICT PARALLEL SAFE;
--ALTER FUNCTION h3_to_geometry(h3index)
-- IMMUTABLE STRICT PARALLEL SAFE;
--ALTER FUNCTION h3_to_geography(h3index)
-- IMMUTABLE STRICT PARALLEL SAFE;
--ALTER FUNCTION h3_to_geo_boundary_geometry(h3index, boolean)
-- IMMUTABLE STRICT PARALLEL SAFE;
--ALTER FUNCTION h3_to_geo_boundary_geography(h3index, boolean)
-- IMMUTABLE STRICT PARALLEL SAFE;
--ALTER FUNCTION h3_polyfill(geometry, integer)
-- IMMUTABLE PARALLEL SAFE CALLED ON NULL INPUT; -- NOT STRICT
--ALTER FUNCTION h3_polyfill(geography, integer)
-- IMMUTABLE PARALLEL SAFE CALLED ON NULL INPUT; -- NOT STRICT
-- Add second support function for hash opclass
CREATE OR REPLACE FUNCTION h3index_hash_extended(h3index, int8) RETURNS int8
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
ALTER OPERATOR FAMILY hash_h3index_ops USING hash ADD
FUNCTION 2 h3index_hash_extended(h3index, int8); h3-pg-4.1.3/h3/sql/updates/h3--3.6.5--3.7.0.sql 0000664 0000000 0000000 00000006621 14460144644 0017526 0 ustar 00root root 0000000 0000000 /*
* 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.
* 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 '3.7.0'" to load this file. \quit
CREATE OPERATOR <-> (
LEFTARG = h3index,
RIGHTARG = h3index,
PROCEDURE = h3_distance,
COMMUTATOR = <->
);
-- Broken since 1.0.0 on update path
--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;
--CREATE OR REPLACE FUNCTION h3_to_geography(h3index) RETURNS geography
-- AS $$ SELECT h3_to_geometry($1)::geography $$ IMMUTABLE STRICT PARALLEL SAFE LANGUAGE SQL;
-- 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;
COMMENT ON FUNCTION h3_point_dist(point, point, text) IS
'The great circle distance in radians between two spherical coordinates.';
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).';
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.';
-- 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;
COMMENT ON FUNCTION h3_hex_area(integer, text) IS
'Average hexagon area in square (kilo)meters at the given resolution.';
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.';
DROP FUNCTION IF EXISTS h3_hex_area(integer, boolean);
DROP FUNCTION IF EXISTS h3_edge_length(integer, boolean);
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;
COMMENT ON FUNCTION h3_hex_area(integer, boolean) IS
'Deprecated: use string for unit';
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;
COMMENT ON FUNCTION h3_edge_length(integer, boolean) IS
'Deprecated: use string for unit';
h3-pg-4.1.3/h3/sql/updates/h3--3.7.0--3.7.1.sql 0000664 0000000 0000000 00000002315 14460144644 0017517 0 ustar 00root root 0000000 0000000 /*
* Copyright 2021 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 '3.7.1'" to load this file. \quit
COMMENT ON OPERATOR && (h3index, h3index) IS
'Returns true if the two H3 indexes intersect';
COMMENT ON OPERATOR @> (h3index, h3index) IS
'Returns true if A containts B';
COMMENT ON OPERATOR <@ (h3index, h3index) IS
'Returns true if A is contained by B';
COMMENT ON OPERATOR = (h3index, h3index) IS
'Returns true if two indexes are the same';
COMMENT ON FUNCTION h3_hex_area(integer, boolean) IS
NULL;
COMMENT ON FUNCTION h3_edge_length(integer, boolean) IS
NULL; h3-pg-4.1.3/h3/sql/updates/h3--3.7.1--3.7.2.sql 0000664 0000000 0000000 00000001372 14460144644 0017523 0 ustar 00root root 0000000 0000000 /*
* 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 '3.7.2'" to load this file. \quit
-- no changes h3-pg-4.1.3/h3/sql/updates/h3--3.7.2--4.0.0.sql 0000664 0000000 0000000 00000030356 14460144644 0017520 0 ustar 00root root 0000000 0000000 /*
* 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 IF EXISTS (h3index AS geometry);
DROP CAST IF EXISTS (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';
h3-pg-4.1.3/h3/sql/updates/h3--4.0.0--4.0.1.sql 0000664 0000000 0000000 00000017441 14460144644 0017511 0 ustar 00root root 0000000 0000000 /*
* 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.1'" to load this file. \quit
CREATE OR REPLACE FUNCTION
h3_cell_to_boundary_wkb(cell h3index) RETURNS bytea
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION
h3_cell_to_boundary_wkb(h3index)
IS 'Finds the boundary of the index, converts to EWKB.
Splits polygons when crossing 180th meridian.
This function has to return WKB since Postgres does not provide multipolygon type.';
-- deprecate extend flag
DROP FUNCTION IF EXISTS h3_cell_to_boundary(cell h3index, extend_at_meridian boolean);
CREATE OR REPLACE FUNCTION
h3_cell_to_boundary(cell h3index, extend_antimeridian boolean) RETURNS polygon
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION
h3_cell_to_boundary(h3index, boolean)
IS 'DEPRECATED: Use `SET h3.extend_antimeridian TO true` instead.';
CREATE OR REPLACE FUNCTION
h3_cell_to_boundary(cell h3index) RETURNS polygon
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION
h3_cell_to_boundary(h3index)
IS 'Finds the boundary of the index.
Use `SET h3.extend_antimeridian TO true` to extend coordinates when crossing 180th meridian.';
-- fix comments
-- indexing
COMMENT ON FUNCTION
h3_lat_lng_to_cell(point, integer)
IS 'Indexes the location at the specified resolution.';
COMMENT ON FUNCTION
h3_cell_to_lat_lng(h3index)
IS 'Finds the centroid of the index.';
-- inspection
COMMENT ON FUNCTION
h3_get_resolution(h3index)
IS 'Returns the resolution of the index.';
COMMENT ON FUNCTION
h3_get_base_cell_number(h3index)
IS 'Returns the base cell number of the index.';
COMMENT ON FUNCTION
h3_is_valid_cell(h3index)
IS 'Returns true if the given H3Index is valid.';
COMMENT ON FUNCTION
h3_is_res_class_iii(h3index)
IS 'Returns true if this index has a resolution with Class III orientation.';
COMMENT ON FUNCTION
h3_is_pentagon(h3index)
IS 'Returns true if this index represents a pentagonal cell.';
COMMENT ON FUNCTION
h3_get_icosahedron_faces(h3index)
IS 'Find all icosahedron faces intersected by a given H3 index.';
-- traversal
COMMENT ON FUNCTION
h3_grid_disk(h3index, integer)
IS 'Produces indices within "k" distance of the origin index.';
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.';
COMMENT ON FUNCTION
h3_grid_ring_unsafe(h3index, integer)
IS 'Returns the hollow hexagonal ring centered at origin with distance "k".';
COMMENT ON FUNCTION
h3_grid_distance(h3index, h3index)
IS 'Returns the distance in grid cells between the two indices.';
COMMENT ON FUNCTION
h3_cell_to_local_ij(h3index, h3index)
IS 'Produces local IJ coordinates for an H3 index anchored by an origin.';
COMMENT ON FUNCTION
h3_local_ij_to_cell(h3index, point)
IS 'Produces an H3 index from local IJ coordinates anchored by an origin.';
-- hierarchy
COMMENT ON FUNCTION
h3_cell_to_parent(cell h3index, resolution integer)
IS 'Returns the parent of the given index.';
COMMENT ON FUNCTION
h3_cell_to_children(cell h3index, resolution integer)
IS 'Returns the set of children of the given index.';
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.';
COMMENT ON FUNCTION
h3_compact_cells(cells h3index[])
IS 'Compacts the given array as best as possible.';
COMMENT ON FUNCTION
h3_cell_to_parent(cell h3index)
IS 'Returns the parent of the given index.';
COMMENT ON FUNCTION
h3_cell_to_children(cell h3index)
IS 'Returns the set of children of the given index.';
COMMENT ON FUNCTION
h3_cell_to_center_child(cell h3index)
IS 'Returns the center child (finer) index contained by input index at next resolution.';
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.';
COMMENT ON FUNCTION
h3_cell_to_children_slow(index h3index, resolution integer)
IS 'Slower version of H3ToChildren but allocates less memory.';
COMMENT ON FUNCTION
h3_cell_to_children_slow(index h3index)
IS 'Slower version of H3ToChildren but allocates less memory.';
-- regions
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.';
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.';
-- edge
COMMENT ON FUNCTION
h3_are_neighbor_cells(origin h3index, destination h3index)
IS 'Returns true if the given indices are neighbors.';
COMMENT ON FUNCTION
h3_origin_to_directed_edges(h3index)
IS 'Returns all unidirectional edges with the given index as origin.';
-- vertex
COMMENT ON FUNCTION
h3_cell_to_vertex(cell h3index, vertexNum integer)
IS 'Returns a single vertex for a given cell, as an H3 index.';
COMMENT ON FUNCTION
h3_cell_to_vertexes(cell h3index)
IS 'Returns all vertexes for a given cell, as H3 indexes.';
COMMENT ON FUNCTION
h3_vertex_to_lat_lng(vertex h3index)
IS 'Get the geocoordinates of an H3 vertex.';
COMMENT ON FUNCTION
h3_is_valid_vertex(vertex h3index)
IS 'Whether the input is a valid H3 vertex.';
-- miscellaneous
COMMENT ON FUNCTION
h3_great_circle_distance(point, point, text)
IS 'The great circle distance in radians between two spherical coordinates.';
COMMENT ON FUNCTION
h3_get_hexagon_area_avg(integer, text)
IS 'Average hexagon area in square (kilo)meters at the given resolution.';
COMMENT ON FUNCTION
h3_cell_area(h3index, text)
IS 'Exact area for a specific cell (hexagon or pentagon).';
COMMENT ON FUNCTION
h3_get_hexagon_edge_length_avg(integer, text)
IS 'Average hexagon edge length in (kilo)meters at the given resolution.';
COMMENT ON FUNCTION
h3_edge_length(h3index, text)
IS 'Exact length for a specific unidirectional edge.';
COMMENT ON FUNCTION
h3_get_num_cells(integer) IS
'Number of unique H3 indexes at the given resolution.';
COMMENT ON FUNCTION
h3_get_res_0_cells()
IS 'Returns all 122 resolution 0 indexes.';
COMMENT ON FUNCTION
h3_get_pentagons(resolution integer)
IS 'All the pentagon H3 indexes at the specified resolution.';
-- operators
COMMENT ON OPERATOR = (h3index, h3index) IS
'Returns true if two indexes are the same.';
COMMENT ON OPERATOR && (h3index, h3index) IS
'Returns true if the two H3 indexes intersect.';
COMMENT ON OPERATOR @> (h3index, h3index) IS
'Returns true if A containts B.';
COMMENT ON OPERATOR <@ (h3index, h3index) IS
'Returns true if A is contained by B.';
COMMENT ON OPERATOR <-> (h3index, h3index) IS
'Returns the distance in grid cells between the two indices.';
-- casts
COMMENT ON CAST (h3index AS bigint) IS
'Convert H3 index to bigint, which is useful when you need a decimal representation.';
COMMENT ON CAST (h3index AS bigint) IS
'Convert bigint to H3 index.';
COMMENT ON CAST (h3index AS point) IS
'Convert H3 index to point.';
h3-pg-4.1.3/h3/sql/updates/h3--4.0.1--4.0.2.sql 0000664 0000000 0000000 00000046271 14460144644 0017516 0 ustar 00root root 0000000 0000000 /*
* 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.2'" to load this file. \quit
-- Due to mishandling of C-level renames in previous releases,
-- this upgrade attempts to align user-installations as much as possible
-- by copying the full-install script in its entirety
-- (except casts/operators/etc)
--
-- For more information see PR #87
CREATE OR REPLACE FUNCTION
h3index_in(cstring) RETURNS h3index
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 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.';
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.';
CREATE OR REPLACE FUNCTION
h3_cell_to_boundary(cell h3index) RETURNS polygon
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION
h3_cell_to_boundary(h3index)
IS 'Finds the boundary of the index.
Use `SET h3.extend_antimeridian TO true` to extend coordinates when crossing 180th meridian.';
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_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.';
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.';
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.';
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.';
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.';
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.';
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.';
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".';
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.';
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.';
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.';
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.';
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.';
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.';
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.';
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.';
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.';
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.';
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.';
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.';
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.';
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.';
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.';
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.';
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.';
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.';
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.';
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.';
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.';
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.';
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.';
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).';
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.';
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.';
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.';
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.';
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.';
CREATE OR REPLACE FUNCTION h3index_eq(h3index, h3index) RETURNS boolean
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE OR REPLACE FUNCTION h3index_ne(h3index, h3index) RETURNS boolean
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE OR REPLACE FUNCTION h3index_lt(h3index, h3index) RETURNS boolean
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE OR REPLACE FUNCTION h3index_le(h3index, h3index) RETURNS boolean
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE OR REPLACE FUNCTION h3index_gt(h3index, h3index) RETURNS boolean
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE OR REPLACE FUNCTION h3index_ge(h3index, h3index) RETURNS boolean
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE OR REPLACE FUNCTION h3index_overlaps(h3index, h3index) RETURNS boolean
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON OPERATOR && (h3index, h3index) IS
'Returns true if the two H3 indexes intersect.';
CREATE OR REPLACE FUNCTION h3index_contains(h3index, h3index) RETURNS boolean
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON OPERATOR @> (h3index, h3index) IS
'Returns true if A containts B.';
CREATE OR REPLACE FUNCTION h3index_contained_by(h3index, h3index) RETURNS boolean
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON OPERATOR <@ (h3index, h3index) IS
'Returns true if A is contained by B.';
COMMENT ON OPERATOR <-> (h3index, h3index) IS
'Returns the distance in grid cells between the two indices.';
CREATE OR REPLACE FUNCTION h3index_cmp(h3index, h3index) RETURNS integer
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE OR REPLACE FUNCTION h3index_sortsupport(internal)
RETURNS void
AS 'h3', 'h3index_sortsupport'
LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE OR REPLACE FUNCTION h3index_hash(h3index) RETURNS integer
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE OR REPLACE FUNCTION h3index_hash_extended(h3index, int8) RETURNS int8
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
CREATE OR REPLACE FUNCTION
h3index_to_bigint(h3index) RETURNS bigint
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON CAST (h3index AS bigint) IS
'Convert H3 index to bigint, which is useful when you need a decimal representation.';
CREATE OR REPLACE FUNCTION
bigint_to_h3index(bigint) RETURNS h3index
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON CAST (h3index AS bigint) IS
'Convert bigint to H3 index.';
COMMENT ON CAST (h3index AS point) IS
'Convert H3 index to point.';
CREATE OR REPLACE FUNCTION h3_get_extension_version() RETURNS text
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION h3_get_extension_version() IS
'Get the currently installed version of the extension.';
CREATE OR REPLACE FUNCTION
h3_cell_to_boundary_wkb(cell h3index) RETURNS bytea
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION
h3_cell_to_boundary_wkb(h3index)
IS 'Finds the boundary of the index, converts to EWKB.
Splits polygons when crossing 180th meridian.
This function has to return WKB since Postgres does not provide multipolygon type.';
CREATE OR REPLACE FUNCTION
h3_cell_to_boundary(cell h3index, extend_antimeridian boolean) RETURNS polygon
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION
h3_cell_to_boundary(h3index, boolean)
IS 'DEPRECATED: Use `SET h3.extend_antimeridian TO true` instead.';
h3-pg-4.1.3/h3/sql/updates/h3--4.0.2--4.0.3.sql 0000664 0000000 0000000 00000003050 14460144644 0017504 0 ustar 00root root 0000000 0000000 /*
* 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.3'" to load this file. \quit
CREATE OR REPLACE FUNCTION
h3_cells_to_multi_polygon_wkb(h3index[]) RETURNS bytea
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION
h3_cells_to_multi_polygon_wkb(h3index[])
IS 'Create a LinkedGeoPolygon describing the outline(s) of a set of hexagons, converts to EWKB.
Splits polygons when crossing 180th meridian.';
-- BRIN operator class
CREATE OPERATOR CLASS h3index_minmax_ops DEFAULT FOR TYPE h3index USING brin AS
OPERATOR 1 < ,
OPERATOR 2 <= ,
OPERATOR 3 = ,
OPERATOR 4 >= ,
OPERATOR 5 > ,
FUNCTION 1 brin_minmax_opcinfo(internal),
FUNCTION 2 brin_minmax_add_value(internal, internal, internal, internal),
FUNCTION 3 brin_minmax_consistent(internal, internal, internal),
FUNCTION 4 brin_minmax_union(internal, internal, internal);
h3-pg-4.1.3/h3/sql/updates/h3--4.0.3--4.1.0.sql 0000664 0000000 0000000 00000005715 14460144644 0017515 0 ustar 00root root 0000000 0000000 /*
* Copyright 2022-2023 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.1.0'" to load this file. \quit
DROP FUNCTION IF EXISTS h3_cell_to_boundary_wkb(h3index);
DROP FUNCTION IF EXISTS h3_cells_to_multi_polygon_wkb(h3index[]);
ALTER OPERATOR FAMILY btree_h3index_ops USING btree RENAME TO h3index_ops;
ALTER OPERATOR CLASS btree_h3index_ops USING btree RENAME TO h3index_ops;
ALTER OPERATOR FAMILY hash_h3index_ops USING hash RENAME TO h3index_ops;
ALTER OPERATOR CLASS hash_h3index_ops USING hash RENAME TO h3index_ops;
CREATE OR REPLACE FUNCTION h3_pg_migrate_pass_by_reference(h3index) RETURNS h3index
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION h3_pg_migrate_pass_by_reference(h3index) IS
'Migrate h3index from pass-by-reference to pass-by-value.';
-- make distance operator allow different resolutions
CREATE OR REPLACE FUNCTION h3index_distance(h3index, h3index) RETURNS bigint
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
DROP OPERATOR IF EXISTS <-> (h3index, h3index);
CREATE OPERATOR <-> (
LEFTARG = h3index,
RIGHTARG = h3index,
PROCEDURE = h3index_distance,
COMMUTATOR = <->
);
COMMENT ON OPERATOR <-> (h3index, h3index) IS
'Returns the distance in grid cells between the two indices (at the lowest resolution of the two).';
-- new child pos functions
-- see https://github.com/uber/h3/pull/719
CREATE OR REPLACE FUNCTION
h3_cell_to_child_pos(child h3index, parentRes integer) RETURNS int8
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION
h3_cell_to_child_pos(child h3index, parentRes integer)
IS 'Returns the position of the child cell within an ordered list of all children of the cells parent at the specified resolution parentRes. The order of the ordered list is the same as that returned by cellToChildren. This is the complement of childPosToCell.';
CREATE OR REPLACE FUNCTION
h3_child_pos_to_cell(childPos int8, parent h3index, childRes int) RETURNS h3index
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION
h3_child_pos_to_cell(childPos int8, parent h3index, childRes int)
IS 'Returns the child cell at a given position within an ordered list of all children of parent at the specified resolution childRes. The order of the ordered list is the same as that returned by cellToChildren. This is the complement of cellToChildPos.';
h3-pg-4.1.3/h3/sql/updates/h3--4.1.0--4.1.1.sql 0000664 0000000 0000000 00000001354 14460144644 0017507 0 ustar 00root root 0000000 0000000 /*
* Copyright 2023 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.1.1'" to load this file. \quit
h3-pg-4.1.3/h3/sql/updates/h3--4.1.1--4.1.2.sql 0000664 0000000 0000000 00000001354 14460144644 0017511 0 ustar 00root root 0000000 0000000 /*
* Copyright 2023 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.1.2'" to load this file. \quit
h3-pg-4.1.3/h3/sql/updates/h3--4.1.2--4.1.3.sql 0000664 0000000 0000000 00000001474 14460144644 0017516 0 ustar 00root root 0000000 0000000 /*
* Copyright 2023 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.1.3'" to load this file. \quit
COMMENT ON OPERATOR @> (h3index, h3index) IS
'Returns true if A contains B.'; h3-pg-4.1.3/h3/src/ 0000775 0000000 0000000 00000000000 14460144644 0013545 5 ustar 00root root 0000000 0000000 h3-pg-4.1.3/h3/src/binding/ 0000775 0000000 0000000 00000000000 14460144644 0015157 5 ustar 00root root 0000000 0000000 h3-pg-4.1.3/h3/src/binding/edge.c 0000664 0000000 0000000 00000011446 14460144644 0016235 0 ustar 00root root 0000000 0000000 /*
* Copyright 2018-2023 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
#include
#include // PG_FUNCTION_INFO_V1
#include // SRF_IS_FIRSTCALL
#include // HeapTuple
#include // PG_RETURN_POLYGON_P
#include "error.h"
#include "type.h"
#include "srf.h"
#if POSTGRESQL_VERSION_MAJOR >= 16
#include "varatt.h" //VAR_SIZE and friends moved to here from postgres.h
#endif
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_are_neighbor_cells);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_cells_to_directed_edge);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_is_valid_directed_edge);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_get_directed_edge_origin);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_get_directed_edge_destination);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_directed_edge_to_cells);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_origin_to_directed_edges);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_directed_edge_to_boundary);
/* Returns whether or not the provided H3 cell indexes are neighbors. */
Datum
h3_are_neighbor_cells(PG_FUNCTION_ARGS)
{
int neighboring;
H3Index origin = PG_GETARG_H3INDEX(0);
H3Index destination = PG_GETARG_H3INDEX(1);
h3_assert(areNeighborCells(origin, destination, &neighboring));
PG_RETURN_BOOL(neighboring);
}
/* Returns a unidirectional edge H3 index based on the provided origin and destination. */
Datum
h3_cells_to_directed_edge(PG_FUNCTION_ARGS)
{
H3Index edge;
H3Index origin = PG_GETARG_H3INDEX(0);
H3Index destination = PG_GETARG_H3INDEX(1);
h3_assert(cellsToDirectedEdge(origin, destination, &edge));
PG_RETURN_H3INDEX(edge);
}
/* Determines if the provided H3Index is a valid unidirectional edge index. */
Datum
h3_is_valid_directed_edge(PG_FUNCTION_ARGS)
{
H3Index edge = PG_GETARG_H3INDEX(0);
int valid = isValidDirectedEdge(edge);
PG_RETURN_BOOL(valid);
}
/* Returns the origin hexagon from the unidirectional edge H3Index. */
Datum
h3_get_directed_edge_origin(PG_FUNCTION_ARGS)
{
H3Index origin;
H3Index edge = PG_GETARG_H3INDEX(0);
h3_assert(getDirectedEdgeOrigin(edge, &origin));
PG_RETURN_H3INDEX(origin);
}
/* Returns the destination hexagon from the unidirectional edge H3Index. */
Datum
h3_get_directed_edge_destination(PG_FUNCTION_ARGS)
{
H3Index destination;
H3Index edge = PG_GETARG_H3INDEX(0);
h3_assert(getDirectedEdgeDestination(edge, &destination));
PG_RETURN_H3INDEX(destination);
}
/* Returns the origin, destination pair of hexagon IDs for the given edge ID. */
Datum
h3_directed_edge_to_cells(PG_FUNCTION_ARGS)
{
TupleDesc tuple_desc;
Datum values[2];
bool nulls[2] = {false};
HeapTuple tuple;
Datum result;
H3Index edge = PG_GETARG_H3INDEX(0);
H3Index *cells = palloc(2 * sizeof(H3Index));
h3_assert(directedEdgeToCells(edge, cells));
ENSURE_TYPEFUNC_COMPOSITE(get_call_result_type(fcinfo, NULL, &tuple_desc));
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. */
Datum
h3_origin_to_directed_edges(PG_FUNCTION_ARGS)
{
if (SRF_IS_FIRSTCALL())
{
FuncCallContext *funcctx = SRF_FIRSTCALL_INIT();
MemoryContext oldcontext =
MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
int max = 6;
H3Index origin = PG_GETARG_H3INDEX(0);
H3Index *edges = palloc(max * sizeof(H3Index));
h3_assert(originToDirectedEdges(origin, edges));
funcctx->user_fctx = edges;
funcctx->max_calls = max;
MemoryContextSwitchTo(oldcontext);
}
SRF_RETURN_H3_INDEXES_FROM_USER_FCTX();
}
/* Provides the coordinates defining the unidirectional edge. */
Datum
h3_directed_edge_to_boundary(PG_FUNCTION_ARGS)
{
CellBoundary boundary;
POLYGON *polygon;
int size;
H3Index edge = PG_GETARG_H3INDEX(0);
h3_assert(directedEdgeToBoundary(edge, &boundary));
size = offsetof(POLYGON, p[0]) +sizeof(polygon->p[0]) * boundary.numVerts;
polygon = (POLYGON *) palloc(size);
SET_VARSIZE(polygon, size);
polygon->npts = boundary.numVerts;
for (int v = 0; v < boundary.numVerts; v++)
{
polygon->p[v].x = radsToDegs(boundary.verts[v].lat);
polygon->p[v].y = radsToDegs(boundary.verts[v].lng);
}
PG_RETURN_POLYGON_P(polygon);
}
h3-pg-4.1.3/h3/src/binding/hierarchy.c 0000664 0000000 0000000 00000014204 14460144644 0017302 0 ustar 00root root 0000000 0000000 /*
* Copyright 2018-2023 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
#include
#include // PG_FUNCTION_INFO_V1
#include // SRF_IS_FIRSTCALL
#include // ArrayType
#include "error.h"
#include "type.h"
#include "srf.h"
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_cell_to_parent);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_cell_to_children);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_cell_to_center_child);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_cell_to_child_pos);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_child_pos_to_cell);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_compact_cells);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_uncompact_cells);
/* Returns the parent (coarser) index containing given index */
Datum
h3_cell_to_parent(PG_FUNCTION_ARGS)
{
H3Index parent;
H3Index origin = PG_GETARG_H3INDEX(0);
int resolution = PG_GETARG_OPTIONAL_RES(1, origin, -1);
h3_assert(cellToParent(origin, resolution, &parent));
PG_RETURN_H3INDEX(parent);
}
/* Returns children indexes at given resolution (or next resolution if none given) */
Datum
h3_cell_to_children(PG_FUNCTION_ARGS)
{
/* stuff done only on the first call of the function */
if (SRF_IS_FIRSTCALL())
{
int64_t max;
int64_t size;
H3Index *children;
/* 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 */
/* ensure valid resolution target */
H3Index origin = PG_GETARG_H3INDEX(0);
int resolution = PG_GETARG_OPTIONAL_RES(1, origin, 1);
h3_assert(cellToChildrenSize(origin, resolution, &max));
size = max * sizeof(H3Index);
ASSERT(
AllocSizeIsValid(size),
ERRCODE_OUT_OF_MEMORY,
"Cannot allocate necessary amount memory, try using h3_cell_to_children_slow()"
);
children = palloc(size);
h3_assert(cellToChildren(origin, resolution, children));
funcctx->user_fctx = children;
funcctx->max_calls = max;
/* END One-time setup code */
MemoryContextSwitchTo(oldcontext);
}
SRF_RETURN_H3_INDEXES_FROM_USER_FCTX();
}
/* Returns the center child (finer) index contained by input index at given resolution */
Datum
h3_cell_to_center_child(PG_FUNCTION_ARGS)
{
H3Index child;
H3Index origin = PG_GETARG_H3INDEX(0);
int resolution = PG_GETARG_OPTIONAL_RES(1, origin, 1);
h3_assert(cellToCenterChild(origin, resolution, &child));
PG_RETURN_H3INDEX(child);
}
Datum
h3_cell_to_child_pos(PG_FUNCTION_ARGS)
{
H3Index child = PG_GETARG_H3INDEX(0);
int parentRes = PG_GETARG_INT32(1);
int64_t childPos;
h3_assert(cellToChildPos(child, parentRes, &childPos));
PG_RETURN_INT64(childPos);
}
Datum
h3_child_pos_to_cell(PG_FUNCTION_ARGS)
{
int64_t childPos = PG_GETARG_INT64(0);
H3Index parent = PG_GETARG_H3INDEX(1);
int childRes = PG_GETARG_INT32(2);
H3Index child;
h3_assert(childPosToCell(childPos, parent, childRes, &child));
PG_RETURN_H3INDEX(child);
}
Datum
h3_compact_cells(PG_FUNCTION_ARGS)
{
if (SRF_IS_FIRSTCALL())
{
Datum value;
bool isnull;
int i = 0;
FuncCallContext *funcctx = SRF_FIRSTCALL_INIT();
MemoryContext oldcontext =
MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
ArrayType *array = PG_GETARG_ARRAYTYPE_P(0);
int max = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
ArrayIterator iterator = array_create_iterator(array, 0, NULL);
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))
{
h3set[i++] = DatumGetH3Index(value);
}
h3_assert(compactCells(h3set, compactedSet, max));
funcctx->user_fctx = compactedSet;
funcctx->max_calls = max;
MemoryContextSwitchTo(oldcontext);
}
SRF_RETURN_H3_INDEXES_FROM_USER_FCTX();
}
Datum
h3_uncompact_cells(PG_FUNCTION_ARGS)
{
if (SRF_IS_FIRSTCALL())
{
int resolution;
Datum value;
bool isnull;
int i = 0;
int64_t max;
H3Index *uncompactedSet;
FuncCallContext *funcctx = SRF_FIRSTCALL_INIT();
MemoryContext oldcontext =
MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
ArrayType *array = PG_GETARG_ARRAYTYPE_P(0);
int numCompacted = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
ArrayIterator iterator = array_create_iterator(array, 0, NULL);
H3Index *compactedSet = palloc(numCompacted * sizeof(H3Index));
/*
* Extract data from array into compactedSet, and wipe compactedSet
* memory
*/
while (array_iterate(iterator, &value, &isnull))
{
compactedSet[i++] = DatumGetH3Index(value);
}
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 < numCompacted; i++)
{
int curRes = getResolution(compactedSet[i]);
if (curRes > highRes)
highRes = curRes;
}
/*
* If the highest resolution is the maximun allowed, uncompact to
* that
*/
/* Else uncompact one step further than the highest resolution */
resolution = (highRes == 15 ? highRes : highRes + 1);
}
h3_assert(uncompactCellsSize(compactedSet, numCompacted, resolution, &max));
uncompactedSet = palloc0(max * sizeof(H3Index));
h3_assert(uncompactCells(compactedSet, numCompacted, uncompactedSet, max, resolution));
funcctx->user_fctx = uncompactedSet;
funcctx->max_calls = max;
MemoryContextSwitchTo(oldcontext);
}
SRF_RETURN_H3_INDEXES_FROM_USER_FCTX();
}
h3-pg-4.1.3/h3/src/binding/indexing.c 0000664 0000000 0000000 00000006527 14460144644 0017142 0 ustar 00root root 0000000 0000000 /*
* Copyright 2018-2023 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
#if POSTGRESQL_VERSION_MAJOR >= 16
#include "varatt.h" //VAR_SIZE and friends moved to here from postgres.h
#endif
#include
#include // PG_FUNCTION_INFO_V1
#include // PG_GETARG_POINT_P
#include "constants.h"
#include "error.h"
#include "type.h"
#include "guc.h"
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_lat_lng_to_cell);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_cell_to_lat_lng);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_cell_to_boundary);
/* Indexes the location at the specified resolution */
Datum
h3_lat_lng_to_cell(PG_FUNCTION_ARGS)
{
H3Index cell;
LatLng location;
Point *point = PG_GETARG_POINT_P(0);
int resolution = PG_GETARG_INT32(1);
if (h3_guc_strict)
{
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.lng = degsToRads(point->x);
location.lat = degsToRads(point->y);
h3_assert(latLngToCell(&location, resolution, &cell));
PG_FREE_IF_COPY(point, 0);
PG_RETURN_H3INDEX(cell);
}
/* Finds the centroid of the index */
Datum
h3_cell_to_lat_lng(PG_FUNCTION_ARGS)
{
LatLng center;
Point *point = palloc(sizeof(Point));
H3Index cell = PG_GETARG_H3INDEX(0);
h3_assert(cellToLatLng(cell, ¢er));
point->x = radsToDegs(center.lng);
point->y = radsToDegs(center.lat);
PG_RETURN_POINT_P(point);
}
/* Finds the boundary of the index */
Datum
h3_cell_to_boundary(PG_FUNCTION_ARGS)
{
H3Index cell = PG_GETARG_H3INDEX(0);
double delta,
firstLon,
lon,
lat;
int size;
POLYGON *polygon;
CellBoundary boundary;
/* DEPRECATION BEGIN: Remove next major */
bool extend;
if (PG_NARGS() == 1)
{
extend = h3_guc_extend_antimeridian;
}
else
{
extend = PG_GETARG_BOOL(1);
H3_DEPRECATION("Please use `SET h3.extend_antimeridian TO true` instead of extend flag");
}
/* DEPRECATION END */
h3_assert(cellToBoundary(cell, &boundary));
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].lng;
if (firstLon < 0)
{
delta = -2 * M_PI;
}
else
{
delta = +2 * M_PI;
}
for (int v = 0; v < boundary.numVerts; v++)
{
lon = boundary.verts[v].lng;
lat = boundary.verts[v].lat;
/* check if different sign */
if (extend && fabs(lon - firstLon) > M_PI)
lon = lon + delta;
polygon->p[v].x = radsToDegs(lon);
polygon->p[v].y = radsToDegs(lat);
}
PG_RETURN_POLYGON_P(polygon);
}
h3-pg-4.1.3/h3/src/binding/inspection.c 0000664 0000000 0000000 00000006047 14460144644 0017505 0 ustar 00root root 0000000 0000000 /*
* Copyright 2018-2023 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
#include
#include // PG_FUNCTION_ARGS
#include // ArrayType
#include // get_typlenbyvalalign
#include // INT4OID
#include "error.h"
#include "type.h"
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_get_resolution);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_get_base_cell_number);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_is_valid_cell);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_is_res_class_iii);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_is_pentagon);
PGDLLEXPORT 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);
int32_t resolution = getResolution(hex);
PG_RETURN_INT32(resolution);
}
/* Returns the base cell number of the index */
Datum
h3_get_base_cell_number(PG_FUNCTION_ARGS)
{
H3Index hex = PG_GETARG_H3INDEX(0);
int32_t result = getBaseCellNumber(hex);
PG_RETURN_INT32(result);
}
/* Returns true if this is a valid H3 index */
Datum
h3_is_valid_cell(PG_FUNCTION_ARGS)
{
H3Index hex = PG_GETARG_H3INDEX(0);
bool result = isValidCell(hex);
PG_RETURN_BOOL(result);
}
/* Returns true if this index has a resolution with Class III orientation */
Datum
h3_is_res_class_iii(PG_FUNCTION_ARGS)
{
H3Index hex = PG_GETARG_H3INDEX(0);
bool result = isResClassIII(hex);
PG_RETURN_BOOL(result);
}
/* Returns true if this hex represents a pentagonal cell */
Datum
h3_is_pentagon(PG_FUNCTION_ARGS)
{
H3Index hex = PG_GETARG_H3INDEX(0);
bool result = isPentagon(hex);
PG_RETURN_BOOL(result);
}
/* Find all icosahedron faces intersected by a given H3 index */
Datum
h3_get_icosahedron_faces(PG_FUNCTION_ARGS)
{
Oid elmtype = INT4OID;
int16 elmlen;
bool elmbyval;
char elmalign;
int *faces;
Datum *elements;
int maxFaces;
ArrayType *result;
int nelems = 0;
H3Index hex = PG_GETARG_H3INDEX(0);
h3_assert(maxFaceCount(hex, &maxFaces));
/* get the faces */
faces = palloc(maxFaces * sizeof(int));
elements = palloc(maxFaces * sizeof(Datum));
h3_assert(getIcosahedronFaces(hex, faces));
for (int i = 0; i < maxFaces; i++)
{
int face = faces[i];
/* add any valid face to result array */
if (face > -1)
elements[nelems++] = Int32GetDatum(face);
}
/* build the array */
get_typlenbyvalalign(elmtype, &elmlen, &elmbyval, &elmalign);
result = construct_array(elements, nelems, elmtype, elmlen, elmbyval, elmalign);
PG_RETURN_ARRAYTYPE_P(result);
}
h3-pg-4.1.3/h3/src/binding/miscellaneous.c 0000664 0000000 0000000 00000012763 14460144644 0020177 0 ustar 00root root 0000000 0000000 /*
* Copyright 2018-2023 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
#include
#include // PG_FUNCTION_ARGS
#include // SRF_IS_FIRSTCALL
#include // PG_GETARG_POINT_P
#include // text_to_cstring
#include "error.h"
#include "type.h"
#include "srf.h"
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_get_hexagon_area_avg);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_cell_area);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_get_hexagon_edge_length_avg);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_edge_length);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_get_num_cells);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_get_res_0_cells);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_get_pentagons);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_great_circle_distance);
/* Average hexagon area in square (kilo)meters at the given resolution */
Datum
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;
if (strcmp(unit, "km") == 0)
h3_assert(getHexagonAreaAvgKm2(resolution, &area));
else if (strcmp(unit, "m") == 0)
h3_assert(getHexagonAreaAvgM2(resolution, &area));
else
ASSERT(0, ERRCODE_INVALID_PARAMETER_VALUE, "Unit must be m or km.");
PG_RETURN_FLOAT8(area);
}
/* Exact area for a specific cell (hexagon or pentagon) */
Datum
h3_cell_area(PG_FUNCTION_ARGS)
{
H3Index cell = PG_GETARG_H3INDEX(0);
char *unit = text_to_cstring(PG_GETARG_TEXT_PP(1));
double area;
if (strcmp(unit, "rads^2") == 0)
h3_assert(cellAreaRads2(cell, &area));
else if (strcmp(unit, "km^2") == 0)
h3_assert(cellAreaKm2(cell, &area));
else if (strcmp(unit, "m^2") == 0)
h3_assert(cellAreaM2(cell, &area));
else
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_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;
if (strcmp(unit, "km") == 0)
h3_assert(getHexagonEdgeLengthAvgKm(resolution, &length));
else if (strcmp(unit, "m") == 0)
h3_assert(getHexagonEdgeLengthAvgM(resolution, &length));
else
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_edge_length(PG_FUNCTION_ARGS)
{
H3Index edge = PG_GETARG_H3INDEX(0);
char *unit = text_to_cstring(PG_GETARG_TEXT_PP(1));
double length;
if (strcmp(unit, "rads") == 0)
h3_assert(edgeLengthRads(edge, &length));
else if (strcmp(unit, "km") == 0)
h3_assert(edgeLengthKm(edge, &length));
else if (strcmp(unit, "m") == 0)
h3_assert(edgeLengthM(edge, &length));
else
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_get_num_cells(PG_FUNCTION_ARGS)
{
int64_t cells;
int resolution = PG_GETARG_INT32(0);
h3_assert(getNumCells(resolution, &cells));
PG_RETURN_INT64(cells);
}
/* Provides all resolution 0 indexes */
Datum
h3_get_res_0_cells(PG_FUNCTION_ARGS)
{
if (SRF_IS_FIRSTCALL())
{
FuncCallContext *funcctx = SRF_FIRSTCALL_INIT();
MemoryContext oldcontext =
MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
int count = res0CellCount();
H3Index *indexes = palloc(count * sizeof(H3Index));
h3_assert(getRes0Cells(indexes));
funcctx->user_fctx = indexes;
funcctx->max_calls = count;
MemoryContextSwitchTo(oldcontext);
}
SRF_RETURN_H3_INDEXES_FROM_USER_FCTX();
}
/* All the pentagon H3 indexes at the specified resolution */
Datum
h3_get_pentagons(PG_FUNCTION_ARGS)
{
if (SRF_IS_FIRSTCALL())
{
FuncCallContext *funcctx = SRF_FIRSTCALL_INIT();
MemoryContext oldcontext =
MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
int resolution = PG_GETARG_INT32(0);
int count = pentagonCount();
H3Index *indexes = palloc(count * sizeof(H3Index));
h3_assert(getPentagons(resolution, indexes));
funcctx->user_fctx = indexes;
funcctx->max_calls = count;
MemoryContextSwitchTo(oldcontext);
}
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);
}
h3-pg-4.1.3/h3/src/binding/regions.c 0000664 0000000 0000000 00000020642 14460144644 0016775 0 ustar 00root root 0000000 0000000 /*
* Copyright 2018-2023 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
#include
#include // PG_FUNCTION_ARGS
#include // SRF_IS_FIRSTCALL
#include // HeapTuple
#include // ArrayType
#include // PG_GETARG_POLYGON_P
#include // get_typlenbyvalalign
#include // POLYGONOID
#include "error.h"
#include "type.h"
#include "srf.h"
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_polygon_to_cells);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_cells_to_multi_polygon);
static void
polygonToGeoLoop(POLYGON *polygon, GeoLoop * geoloop)
{
geoloop->numVerts = polygon->npts;
geoloop->verts = (LatLng *) palloc(geoloop->numVerts * sizeof(LatLng));
for (int i = 0; i < geoloop->numVerts; i++)
{
geoloop->verts[i].lng = degsToRads(polygon->p[i].x);
geoloop->verts[i].lat = degsToRads(polygon->p[i].y);
}
}
static int
linkedGeoLoopToNativePolygonSize(LinkedGeoLoop * linkedLoop)
{
int count = 0;
LinkedLatLng *linkedCoord = linkedLoop->first;
while (linkedCoord != NULL)
{
count++;
linkedCoord = linkedCoord->next;
}
return count;
}
static void
linkedGeoLoopToNativePolygon(LinkedGeoLoop * linkedLoop, POLYGON *polygon)
{
int count;
LinkedLatLng *linkedCoord = linkedLoop->first;
count = 0;
while (linkedCoord != NULL)
{
(polygon->p[count]).x = radsToDegs(linkedCoord->vertex.lng);
(polygon->p[count]).y = radsToDegs(linkedCoord->vertex.lat);
linkedCoord = linkedCoord->next;
count++;
}
}
/*
* void polyfill(const GeoPolygon* geoPolygon, int res, H3Index* out);
*/
Datum
h3_polygon_to_cells(PG_FUNCTION_ARGS)
{
if (SRF_IS_FIRSTCALL())
{
FuncCallContext *funcctx = SRF_FIRSTCALL_INIT();
MemoryContext oldcontext =
MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
int64_t maxSize;
H3Index *indices;
ArrayType *holes;
int nelems = 0;
int resolution;
GeoPolygon polygon;
Datum value;
bool isnull;
POLYGON *exterior;
if (PG_ARGISNULL(0))
ASSERT(0, ERRCODE_INVALID_PARAMETER_VALUE, "No polygon given to polyfill");
/* get function arguments */
exterior = PG_GETARG_POLYGON_P(0);
if (!PG_ARGISNULL(1))
{
holes = PG_GETARG_ARRAYTYPE_P(1);
nelems = ArrayGetNItems(ARR_NDIM(holes), ARR_DIMS(holes));
}
resolution = PG_GETARG_INT32(2);
/* build polygon */
polygonToGeoLoop(exterior, &(polygon.geoloop));
if (nelems)
{
int i = 0;
ArrayIterator iterator = array_create_iterator(holes, 0, NULL);
polygon.numHoles = nelems;
polygon.holes = (GeoLoop *) palloc(polygon.numHoles * sizeof(GeoLoop));
while (array_iterate(iterator, &value, &isnull))
{
if (isnull)
{
polygon.numHoles--;
}
else
{
POLYGON *hole = DatumGetPolygonP(value);
polygonToGeoLoop(hole, &(polygon.holes[i]));
i++;
}
}
}
else
{
polygon.numHoles = 0;
}
/* produce hexagons into allocated memory */
h3_assert(maxPolygonToCellsSize(&polygon, resolution, 0, &maxSize));
indices = palloc_extended(maxSize * sizeof(H3Index),
MCXT_ALLOC_HUGE | MCXT_ALLOC_ZERO);
h3_assert(polygonToCells(&polygon, resolution, 0, indices));
funcctx->user_fctx = indices;
funcctx->max_calls = maxSize;
MemoryContextSwitchTo(oldcontext);
}
SRF_RETURN_H3_INDEXES_FROM_USER_FCTX();
}
/*
* void polyfill(const GeoPolygon* geoPolygon, int res, H3Index* out);
*
* https://stackoverflow.com/questions/51127189/how-to-return-array-into-array-with-custom-type-in-postgres-c-function
*/
Datum
h3_cells_to_multi_polygon(PG_FUNCTION_ARGS)
{
FuncCallContext *funcctx;
TupleDesc tuple_desc;
LinkedGeoPolygon *linkedPolygon;
LinkedGeoLoop *linkedLoop;
if (SRF_IS_FIRSTCALL())
{
Datum value;
bool isnull;
int i = 0;
FuncCallContext *funcctx = SRF_FIRSTCALL_INIT();
MemoryContext oldcontext =
MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
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));
/* Extract data from array into h3set, and wipe compactedSet memory */
while (array_iterate(iterator, &value, &isnull))
{
h3set[i++] = DatumGetH3Index(value);
}
/* produce hexagons into allocated memory */
linkedPolygon = palloc(sizeof(LinkedGeoPolygon));
h3_assert(cellsToLinkedMultiPolygon(h3set, numHexes, linkedPolygon));
ENSURE_TYPEFUNC_COMPOSITE(get_call_result_type(fcinfo, NULL, &tuple_desc));
funcctx->user_fctx = linkedPolygon;
funcctx->tuple_desc = BlessTupleDesc(tuple_desc);
MemoryContextSwitchTo(oldcontext);
}
funcctx = SRF_PERCALL_SETUP();
linkedPolygon = (LinkedGeoPolygon *) funcctx->user_fctx;
if (linkedPolygon)
{
HeapTuple tuple;
Datum result;
int count;
int size;
POLYGON *polygon;
Datum *elems;
Datum values[2];
bool nulls[2];
int16 typlen;
bool typbyval;
char typalign;
ArrayType *retarr;
tuple_desc = funcctx->tuple_desc;
linkedLoop = linkedPolygon->first;
count = linkedGeoLoopToNativePolygonSize(linkedLoop);
size = offsetof(POLYGON, p) +sizeof(polygon->p[0]) * count;
polygon = palloc0(size);
SET_VARSIZE(polygon, size);
polygon->npts = count;
linkedGeoLoopToNativePolygon(linkedLoop, polygon);
values[0] = PolygonPGetDatum(polygon);
nulls[0] = false;
/* construct array */
count = 0;
linkedLoop = linkedPolygon->first->next;
while (linkedLoop != NULL)
{
count++;
linkedLoop = linkedLoop->next;
}
elems = (Datum *) palloc(count * sizeof(Datum));
if (count)
{
linkedLoop = linkedPolygon->first->next;
for (int i = 0; i < count; i++)
{
int subcount = linkedGeoLoopToNativePolygonSize(linkedLoop);
POLYGON *polygon;
int size = offsetof(POLYGON, p) +sizeof(polygon->p[0]) * subcount;
polygon = palloc0(size);
SET_VARSIZE(polygon, size);
polygon->npts = subcount;
linkedGeoLoopToNativePolygon(linkedLoop, polygon);
elems[i] = PolygonPGetDatum(polygon);
linkedLoop = linkedLoop->next;
}
}
get_typlenbyvalalign(POLYGONOID, &typlen, &typbyval, &typalign);
retarr =
construct_array(elems, count, POLYGONOID, typlen, typbyval, typalign);
values[1] = PointerGetDatum(retarr);
nulls[1] = false;
tuple = heap_form_tuple(tuple_desc, values, nulls);
result = HeapTupleGetDatum(tuple);
funcctx->user_fctx = linkedPolygon->next;
SRF_RETURN_NEXT(funcctx, result);
}
else
{
destroyLinkedMultiPolygon(linkedPolygon);
SRF_RETURN_DONE(funcctx);
}
}
/* ---------------------------------------------------------------------------
* The GeoPolygon, LinkedLatLng, LinkedLatLng,
* LinkedGeoLoop, and LinkedGeoPolygon
*
* copied from H3 core for reference
*/
/** @struct GeoPolygon
* @brief Simplified core of GeoJSON Polygon coordinates definition
*/
/*
typedef struct {
double lat; ///< latitude in radians
double lon; ///< longitude in radians
} LatLng;
typedef struct {
int numVerts;
LatLng *verts;
} GeoLoop;
typedef struct {
GeoLoop geoloop; ///< exterior boundary of the polygon
int numHoles; ///< number of elements in the array pointed to by holes
GeoLoop *holes; ///< interior boundaries (holes) in the polygon
} GeoPolygon;
*/
/** @struct LinkedLatLng
* @brief A coordinate node in a linked geo structure, part of a linked list
*
typedef struct LinkedLatLng LinkedLatLng;
struct LinkedLatLng
{
LatLng vertex;
LinkedLatLng *next;
};
** @struct LinkedGeoLoop
* @brief A loop node in a linked geo structure, part of a linked list
*
typedef struct LinkedGeoLoop LinkedGeoLoop;
struct LinkedGeoLoop
{
LinkedLatLng *first;
LinkedLatLng *last;
LinkedGeoLoop *next;
};
** @struct LinkedGeoPolygon
* @brief A polygon node in a linked geo structure, part of a linked list.
*
typedef struct LinkedGeoPolygon LinkedGeoPolygon;
struct LinkedGeoPolygon
{
LinkedGeoLoop *first;
LinkedGeoLoop *last;
LinkedGeoPolygon *next;
};
*/
h3-pg-4.1.3/h3/src/binding/traversal.c 0000664 0000000 0000000 00000015744 14460144644 0017341 0 ustar 00root root 0000000 0000000 /*
* Copyright 2018-2023 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
#include
#include // PG_FUNCTION_ARGS
#include // SRF_IS_FIRSTCALL
#include // PG_GETARG_POINT_P
#include "error.h"
#include "type.h"
#include "srf.h"
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_grid_disk);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_grid_disk_distances);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_grid_ring_unsafe);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_grid_distance);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_grid_path_cells);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_cell_to_local_ij);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_local_ij_to_cell);
/*
* k-rings produces indices within k distance of the origin index.
*
* k-ring 0 is defined as the origin index, k-ring 1 is defined as k-ring 0 and
* all neighboring indices, and so on.
*
* Output is placed in the provided array in no particular order.
* There may be fewer elements in output, as can happen when crossing a
* pentagon.
*/
Datum
h3_grid_disk(PG_FUNCTION_ARGS)
{
if (SRF_IS_FIRSTCALL())
{
FuncCallContext *funcctx = SRF_FIRSTCALL_INIT();
MemoryContext oldcontext =
MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
int64_t max;
H3Index *indices;
/* get function arguments */
H3Index origin = PG_GETARG_H3INDEX(0);
int k = PG_GETARG_INT32(1);
h3_assert(maxGridDiskSize(k, &max));
indices = palloc(max * sizeof(H3Index));
h3_assert(gridDisk(origin, k, indices));
funcctx->user_fctx = indices;
funcctx->max_calls = max;
MemoryContextSwitchTo(oldcontext);
}
SRF_RETURN_H3_INDEXES_FROM_USER_FCTX();
}
/*
* k-rings produces indices within k distance of the origin index.
*
* k-ring 0 is defined as the origin index, k-ring 1 is defined as k-ring 0 and
* all neighboring indices, and so on.
*
* Output is placed in the provided array in no particular order.
* There may be fewer elements in output, as can happen when crossing a
* pentagon.
*/
Datum
h3_grid_disk_distances(PG_FUNCTION_ARGS)
{
if (SRF_IS_FIRSTCALL())
{
FuncCallContext *funcctx = SRF_FIRSTCALL_INIT();
MemoryContext oldcontext =
MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
TupleDesc tuple_desc;
/* get function arguments */
H3Index origin = PG_GETARG_H3INDEX(0);
int k = PG_GETARG_INT32(1);
/*
* Allocate memory for the indices, the distances and the tuple used
* for
*/
/* returning */
int64_t maxSize;
hexDistanceTuple *user_fctx;
h3_assert(maxGridDiskSize(k, &maxSize));
user_fctx = palloc(sizeof(hexDistanceTuple));
user_fctx->indices = palloc(maxSize * sizeof(H3Index));
user_fctx->distances = palloc(maxSize * sizeof(int));
h3_assert(gridDiskDistances(origin, k, user_fctx->indices, user_fctx->distances));
ENSURE_TYPEFUNC_COMPOSITE(get_call_result_type(fcinfo, NULL, &tuple_desc));
funcctx->tuple_desc = BlessTupleDesc(tuple_desc);
funcctx->max_calls = maxSize;
funcctx->user_fctx = user_fctx;
MemoryContextSwitchTo(oldcontext);
}
SRF_RETURN_H3_INDEX_DISTANCES_FROM_USER_FCTX();
}
/*
* Produces the hollow hexagonal ring centered at origin with sides of length k.
*
* Throws if pentagonal distortion was encountered.
*/
Datum
h3_grid_ring_unsafe(PG_FUNCTION_ARGS)
{
if (SRF_IS_FIRSTCALL())
{
FuncCallContext *funcctx = SRF_FIRSTCALL_INIT();
MemoryContext oldcontext =
MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
/* get function arguments */
H3Index *indices;
H3Index origin = PG_GETARG_H3INDEX(0);
int k = PG_GETARG_INT32(1);
/*
* Find the size of the ring. If k is 0, then it is the same as
* k_ring.
*
* If k is larger than 0, the ring is the size of the circle with k,
* minus the circle with k-1
*/
int64_t maxSize;
int64_t innerSize;
h3_assert(maxGridDiskSize(k, &maxSize));
if (k > 0)
{
h3_assert(maxGridDiskSize(k - 1, &innerSize));
maxSize -= innerSize;
}
indices = palloc(maxSize * sizeof(H3Index));
h3_assert(gridRingUnsafe(origin, k, indices));
funcctx->user_fctx = indices;
funcctx->max_calls = maxSize;
MemoryContextSwitchTo(oldcontext);
}
SRF_RETURN_H3_INDEXES_FROM_USER_FCTX();
}
/*
* Returns the distance in grid cells between the two indexes.
*
* Returns a negative number if finding the distance failed.
* Finding the distance can fail because the two indexes are not comparable
* (different resolutions), too far apart, or are separated by pentagonal
* distortion. This is the same set of limitations as the local IJ coordinate
* space functions.
*/
Datum
h3_grid_distance(PG_FUNCTION_ARGS)
{
H3Index originIndex = PG_GETARG_H3INDEX(0);
H3Index h3Index = PG_GETARG_H3INDEX(1);
int64_t distance;
h3_assert(gridDistance(originIndex, h3Index, &distance));
PG_RETURN_INT64(distance);
}
/*
* 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.
*/
Datum
h3_grid_path_cells(PG_FUNCTION_ARGS)
{
if (SRF_IS_FIRSTCALL())
{
FuncCallContext *funcctx = SRF_FIRSTCALL_INIT();
MemoryContext oldcontext =
MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
/* get function arguments */
int64_t size;
H3Index *indices;
H3Index start = PG_GETARG_H3INDEX(0);
H3Index end = PG_GETARG_H3INDEX(1);
h3_assert(gridPathCellsSize(start, end, &size));
indices = palloc(size * sizeof(H3Index));
h3_assert(gridPathCells(start, end, indices));
funcctx->user_fctx = indices;
funcctx->max_calls = size;
MemoryContextSwitchTo(oldcontext);
}
SRF_RETURN_H3_INDEXES_FROM_USER_FCTX();
}
/*
* Produces local IJ coordinates for an H3 index anchored by an origin.
*/
Datum
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;
h3_assert(cellToLocalIj(origin, index, 0, &coord));
point->x = coord.i;
point->y = coord.j;
PG_RETURN_POINT_P(point);
}
/*
* Produces an H3 index from local IJ coordinates anchored by an origin.
*/
Datum
h3_local_ij_to_cell(PG_FUNCTION_ARGS)
{
H3Index origin = PG_GETARG_H3INDEX(0);
Point *point = PG_GETARG_POINT_P(1);
H3Index *index = (H3Index *) palloc(sizeof(H3Index));
CoordIJ coord;
coord.i = point->x;
coord.j = point->y;
h3_assert(localIjToCell(origin, &coord, 0, index));
PG_FREE_IF_COPY(point, 1);
PG_RETURN_H3INDEX(*index);
}
h3-pg-4.1.3/h3/src/binding/vertex.c 0000664 0000000 0000000 00000005344 14460144644 0016646 0 ustar 00root root 0000000 0000000 /*
* Copyright 2022-2023 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
#include
#include // PG_FUNCTION_ARGS
#include // SRF_IS_FIRSTCALL
#include // PG_RETURN_POINT_P
#include "error.h"
#include "type.h"
#include "srf.h"
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_cell_to_vertex);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_cell_to_vertexes);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_vertex_to_lat_lng);
PGDLLEXPORT 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;
H3Index cell = PG_GETARG_H3INDEX(0);
int vertexNum = PG_GETARG_INT32(1);
h3_assert(cellToVertex(cell, vertexNum, &vertex));
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;
/* 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);
h3_assert(cellToVertexes(cell, vertexes));
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);
Point *point = palloc(sizeof(Point));
LatLng latlng;
h3_assert(vertexToLatLng(vertex, &latlng));
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);
}
h3-pg-4.1.3/h3/src/config.h.in 0000664 0000000 0000000 00000001313 14460144644 0015566 0 ustar 00root root 0000000 0000000 /*
* Copyright 2023 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.
*/
#ifndef H3_CONFIG_H
#define H3_CONFIG_H
#define POSTGRESQL_H3_VERSION "@INSTALL_VERSION@"
#endif /* H3_CONFIG_H */
h3-pg-4.1.3/h3/src/deprecated.c 0000664 0000000 0000000 00000006406 14460144644 0016017 0 ustar 00root root 0000000 0000000 /*
* Copyright 2022-2023 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 "deprecate.h"
H3_DEPRECATE("1.0.0", h3_basecells);
H3_DEPRECATE("1.0.0", h3_h3_get_base_cell);
H3_DEPRECATE("1.0.0", h3_h3_get_resolution);
H3_DEPRECATE("1.0.0", h3_h3_indexes_are_neighbors);
H3_DEPRECATE("1.0.0", h3_h3_is_pentagon);
H3_DEPRECATE("1.0.0", h3_h3_is_res_class_iii);
H3_DEPRECATE("1.0.0", h3_h3_is_valid);
H3_DEPRECATE("1.0.0", h3_h3_set_to_linked_geo);
H3_DEPRECATE("1.0.0", h3_h3_to_children);
H3_DEPRECATE("1.0.0", h3_h3_to_geo_boundary);
H3_DEPRECATE("1.0.0", h3_h3_to_geo);
H3_DEPRECATE("1.0.0", h3_h3_to_parent);
H3_DEPRECATE("1.0.0", h3_h3_unidirectional_edge_is_valid);
H3_DEPRECATE("1.0.0", h3_haversine_distance);
H3_DEPRECATE("3.4.0", h3_degs_to_rads);
H3_DEPRECATE("3.4.0", h3_rads_to_degs);
H3_DEPRECATE("3.5.0", h3_edge_length_km);
H3_DEPRECATE("3.5.0", h3_edge_length_m);
H3_DEPRECATE("3.5.0", h3_get_unidirectional_edge_boundary);
H3_DEPRECATE("3.5.0", h3_hex_area_km2);
H3_DEPRECATE("3.5.0", h3_hex_area_m2);
H3_DEPRECATE("3.5.0", h3_hex_range_distances);
H3_DEPRECATE("3.5.0", h3_hex_range);
H3_DEPRECATE("3.5.0", h3_hex_ranges);
H3_DEPRECATE("3.6.0", h3_h3_to_string);
H3_DEPRECATE("3.6.0", h3_string_to_h3);
H3_DEPRECATE("4.0.0", h3_compact);
H3_DEPRECATE("4.0.0", h3_distance);
H3_DEPRECATE("4.0.0", h3_exact_edge_length);
H3_DEPRECATE("4.0.0", h3_experimental_h3_to_local_ij);
H3_DEPRECATE("4.0.0", h3_experimental_local_ij_to_h3);
H3_DEPRECATE("4.0.0", h3_geo_to_h3);
H3_DEPRECATE("4.0.0", h3_get_base_cell);
H3_DEPRECATE("4.0.0", h3_get_destination_h3_index_from_unidirectional_edge);
H3_DEPRECATE("4.0.0", h3_get_faces);
H3_DEPRECATE("4.0.0", h3_get_h3_indexes_from_unidirectional_edge);
H3_DEPRECATE("4.0.0", h3_get_h3_unidirectional_edge_boundary);
H3_DEPRECATE("4.0.0", h3_get_h3_unidirectional_edge);
H3_DEPRECATE("4.0.0", h3_get_h3_unidirectional_edges_from_hexagon);
H3_DEPRECATE("4.0.0", h3_get_origin_h3_index_from_unidirectional_edge);
H3_DEPRECATE("4.0.0", h3_get_pentagon_indexes);
H3_DEPRECATE("4.0.0", h3_get_res_0_indexes);
H3_DEPRECATE("4.0.0", h3_hex_area);
H3_DEPRECATE("4.0.0", h3_hex_ring);
H3_DEPRECATE("4.0.0", h3_indexes_are_neighbors);
H3_DEPRECATE("4.0.0", h3_is_valid);
H3_DEPRECATE("4.0.0", h3_k_ring_distances);
H3_DEPRECATE("4.0.0", h3_k_ring);
H3_DEPRECATE("4.0.0", h3_line);
H3_DEPRECATE("4.0.0", h3_num_hexagons);
H3_DEPRECATE("4.0.0", h3_point_dist);
H3_DEPRECATE("4.0.0", h3_polyfill);
H3_DEPRECATE("4.0.0", h3_set_to_multi_polygon);
H3_DEPRECATE("4.0.0", h3_to_center_child);
H3_DEPRECATE("4.0.0", h3_to_geo_boundary);
H3_DEPRECATE("4.0.0", h3_to_geo);
H3_DEPRECATE("4.0.0", h3_uncompact);
H3_DEPRECATE("4.0.0", h3_unidirectional_edge_is_valid);
H3_DEPRECATE("4.1.0", h3_cell_to_boundary_wkb);
H3_DEPRECATE("4.1.0", h3_cells_to_multi_polygon_wkb);
h3-pg-4.1.3/h3/src/extension.c 0000664 0000000 0000000 00000002500 14460144644 0015722 0 ustar 00root root 0000000 0000000 /*
* Copyright 2018-2023 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
#include
#include // PG_FUNCTION_INFO_V1
#include // cstring_to_text
#include "type.h"
#include "config.h"
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_get_extension_version);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_pg_migrate_pass_by_reference);
/* Return version number for this extension (not main h3 lib) */
Datum
h3_get_extension_version(PG_FUNCTION_ARGS)
{
PG_RETURN_TEXT_P(cstring_to_text(POSTGRESQL_H3_VERSION));
}
/*
* Migration from pass-by-reference to pass-by-value
* https://github.com/zachasme/h3-pg/issues/31
*/
Datum
h3_pg_migrate_pass_by_reference(PG_FUNCTION_ARGS)
{
H3Index cell = (*((H3Index *) DatumGetPointer(PG_GETARG_DATUM(0))));
PG_RETURN_H3INDEX(cell);
}
h3-pg-4.1.3/h3/src/guc.c 0000664 0000000 0000000 00000002343 14460144644 0014471 0 ustar 00root root 0000000 0000000 /*
* Copyright 2023 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
#include // DefineCustom*Variable
bool h3_guc_strict = false;
bool h3_guc_extend_antimeridian = false;
void
_guc_init(void)
{
DefineCustomBoolVariable("h3.strict",
"Enable strict indexing (fail on invalid lng/lat).",
NULL,
&h3_guc_strict,
false,
PGC_USERSET,
0,
NULL,
NULL,
NULL);
DefineCustomBoolVariable("h3.extend_antimeridian",
"Extend boundaries by 180th meridian, when possible.",
NULL,
&h3_guc_extend_antimeridian,
false,
PGC_USERSET,
0,
NULL,
NULL,
NULL);
}
h3-pg-4.1.3/h3/src/guc.h 0000664 0000000 0000000 00000001352 14460144644 0014475 0 ustar 00root root 0000000 0000000 /*
* Copyright 2023 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.
*/
#ifndef H3_GUC_H
#define H3_GUC_H
extern bool h3_guc_strict;
extern bool h3_guc_extend_antimeridian;
void _guc_init(void);
#endif /* H3_GUC_H */
h3-pg-4.1.3/h3/src/init.c 0000664 0000000 0000000 00000001704 14460144644 0014656 0 ustar 00root root 0000000 0000000 /*
* Copyright 2023 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.
*/
/* required for MSVC */
#define _USE_MATH_DEFINES
#include
#include // PG_MODULE_MAGIC
#include "guc.h"
/* see https://www.postgresql.org/docs/current/xfunc-c.html#XFUNC-C-DYNLOAD */
PG_MODULE_MAGIC;
void
_PG_init(void)
{
/* In case we allow using shared library h3, */
/* we could make version number assertion here */
_guc_init();
}
h3-pg-4.1.3/h3/src/opclass_btree.c 0000664 0000000 0000000 00000004135 14460144644 0016541 0 ustar 00root root 0000000 0000000 /*
* Copyright 2018-2023 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
#include
#include // PG_FUNCTION_ARGS
#include // SortSupport
#include "type.h"
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3index_cmp);
Datum
h3index_cmp(PG_FUNCTION_ARGS)
{
H3Index a = PG_GETARG_H3INDEX(0);
H3Index b = PG_GETARG_H3INDEX(1);
uint32_t ret = 0;
if (a < b)
ret = 1;
else if (a > b)
ret = -1;
PG_RETURN_INT32(ret);
}
static int
h3index_cmp_abbrev(Datum x, Datum y, SortSupport ssup)
{
if (x == y)
return 0;
else if (x < y)
return 1;
else
return -1;
}
static int
h3index_cmp_full(Datum x, Datum y, SortSupport ssup)
{
H3Index a = DatumGetH3Index(x);
H3Index b = DatumGetH3Index(y);
if (a == b)
return 0;
else if (a < b)
return 1;
return -1;
}
static bool
h3index_abbrev_abort(int memtupcount, SortSupport ssup)
{
return 0;
}
static Datum
h3index_abbrev_convert(Datum original, SortSupport ssup)
{
H3Index a = DatumGetH3Index(original);
return a;
}
/*
* Sort support strategy routine
*/
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3index_sortsupport);
Datum
h3index_sortsupport(PG_FUNCTION_ARGS)
{
SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
ssup->comparator = h3index_cmp_full;
ssup->ssup_extra = NULL;
/* Enable sortsupport only on 64 bit Datum */
if (ssup->abbreviate && sizeof(Datum) == 8)
{
ssup->comparator = h3index_cmp_abbrev;
ssup->abbrev_converter = h3index_abbrev_convert;
ssup->abbrev_abort = h3index_abbrev_abort;
ssup->abbrev_full_comparator = h3index_cmp_full;
}
PG_RETURN_VOID();
}
h3-pg-4.1.3/h3/src/opclass_hash.c 0000664 0000000 0000000 00000002344 14460144644 0016363 0 ustar 00root root 0000000 0000000 /*
* Copyright 2018-2023 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
#include
#include // PG_FUNCTION_ARGS
#include // hash_any
#include "type.h"
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3index_hash);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3index_hash_extended);
Datum
h3index_hash(PG_FUNCTION_ARGS)
{
H3Index index = PG_GETARG_H3INDEX(0);
Datum hash = hash_any((unsigned char *) &index, sizeof(index));
PG_RETURN_DATUM(hash);
}
Datum
h3index_hash_extended(PG_FUNCTION_ARGS)
{
H3Index index = PG_GETARG_H3INDEX(0);
int64_t seed = PG_GETARG_INT64(1);
Datum hash = hash_any_extended((unsigned char *) &index, sizeof(index), seed);
PG_RETURN_DATUM(hash);
}
h3-pg-4.1.3/h3/src/operators.c 0000664 0000000 0000000 00000007224 14460144644 0015734 0 ustar 00root root 0000000 0000000 /*
* Copyright 2020-2023 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
#include
#include // PG_FUNCTION_ARGS
#include "error.h"
#include "type.h"
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3index_distance);
/* b-tree */
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3index_eq);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3index_ne);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3index_lt);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3index_le);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3index_gt);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3index_ge);
/* r-tree */
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3index_overlaps);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3index_contains);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3index_contained_by);
/* static helpers */
static int
containment(H3Index a, H3Index b)
{
H3Index aParent = a;
H3Index bParent = b;
int aRes = getResolution(a);
int bRes = getResolution(b);
if (aRes > bRes)
h3_assert(cellToParent(a, bRes, &aParent));
else if (aRes < bRes)
h3_assert(cellToParent(b, aRes, &bParent));
/* a contains b */
if (a == bParent)
return 1;
/* a contained by b */
if (b == aParent)
return -1;
/* no overlap */
return 0;
}
/* distance operator allowing for different resolutions */
Datum
h3index_distance(PG_FUNCTION_ARGS)
{
H3Index a = PG_GETARG_H3INDEX(0);
H3Index b = PG_GETARG_H3INDEX(1);
int resA = getResolution(a);
int resB = getResolution(b);
H3Error error;
int64_t distance;
if (resA < resB)
h3_assert(cellToCenterChild(a, resB, &a));
else if (resB < resA)
h3_assert(cellToCenterChild(b, resA, &b));
error = gridDistance(a, b, &distance);
/* h3_assert(error); */
if (error)
distance = -1;
PG_RETURN_INT64(distance);
}
/* b-tree operators */
Datum
h3index_eq(PG_FUNCTION_ARGS)
{
H3Index a = PG_GETARG_H3INDEX(0);
H3Index b = PG_GETARG_H3INDEX(1);
bool ret = a == b;
PG_RETURN_BOOL(ret);
}
Datum
h3index_ne(PG_FUNCTION_ARGS)
{
H3Index a = PG_GETARG_H3INDEX(0);
H3Index b = PG_GETARG_H3INDEX(1);
bool ret = a != b;
PG_RETURN_BOOL(ret);
}
Datum
h3index_lt(PG_FUNCTION_ARGS)
{
H3Index a = PG_GETARG_H3INDEX(0);
H3Index b = PG_GETARG_H3INDEX(1);
bool ret = a < b;
PG_RETURN_BOOL(ret);
}
Datum
h3index_le(PG_FUNCTION_ARGS)
{
H3Index a = PG_GETARG_H3INDEX(0);
H3Index b = PG_GETARG_H3INDEX(1);
bool ret = a <= b;
PG_RETURN_BOOL(ret);
}
Datum
h3index_gt(PG_FUNCTION_ARGS)
{
H3Index a = PG_GETARG_H3INDEX(0);
H3Index b = PG_GETARG_H3INDEX(1);
bool ret = a > b;
PG_RETURN_BOOL(ret);
}
Datum
h3index_ge(PG_FUNCTION_ARGS)
{
H3Index a = PG_GETARG_H3INDEX(0);
H3Index b = PG_GETARG_H3INDEX(1);
bool ret = a >= b;
PG_RETURN_BOOL(ret);
}
/* r-tree operators */
Datum
h3index_overlaps(PG_FUNCTION_ARGS)
{
H3Index a = PG_GETARG_H3INDEX(0);
H3Index b = PG_GETARG_H3INDEX(1);
bool ret = containment(a, b) != 0;
PG_RETURN_BOOL(ret);
}
Datum
h3index_contains(PG_FUNCTION_ARGS)
{
H3Index a = PG_GETARG_H3INDEX(0);
H3Index b = PG_GETARG_H3INDEX(1);
bool ret = containment(a, b) > 0;
PG_RETURN_BOOL(ret);
}
Datum
h3index_contained_by(PG_FUNCTION_ARGS)
{
H3Index a = PG_GETARG_H3INDEX(0);
H3Index b = PG_GETARG_H3INDEX(1);
bool ret = containment(a, b) < 0;
PG_RETURN_BOOL(ret);
}
h3-pg-4.1.3/h3/src/srf.c 0000664 0000000 0000000 00000004554 14460144644 0014513 0 ustar 00root root 0000000 0000000 /*
* Copyright 2023 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
#include
#include // SRF_IS_FIRSTCALL
#include // HeapTuple
#include "type.h"
#include "srf.h"
/*
* Set-Returning-Function assume user fctx contains indices
* will skip missing (all zeros) indices
*/
Datum
srf_return_h3_indexes_from_user_fctx(PG_FUNCTION_ARGS)
{
FuncCallContext *funcctx = SRF_PERCALL_SETUP();
int call_cntr = funcctx->call_cntr;
int max_calls = funcctx->max_calls;
H3Index *indices = (H3Index *) funcctx->user_fctx;
/* skip missing indices (all zeros) */
while (call_cntr < max_calls && !indices[call_cntr])
{
funcctx->call_cntr = ++call_cntr;
};
if (call_cntr < max_calls)
{
Datum result = H3IndexGetDatum(indices[call_cntr]);
SRF_RETURN_NEXT(funcctx, result);
}
else
{
SRF_RETURN_DONE(funcctx);
}
}
/*
* Returns hex/distance tuples from user_fctx
* will skip missing (all zeros) indices
*/
Datum
srf_return_h3_index_distances_from_user_fctx(PG_FUNCTION_ARGS)
{
FuncCallContext *funcctx = SRF_PERCALL_SETUP();
int call_cntr = funcctx->call_cntr;
int max_calls = funcctx->max_calls;
hexDistanceTuple *user_fctx = funcctx->user_fctx;
H3Index *indices = user_fctx->indices;
int *distances = user_fctx->distances;
/* skip missing indices (all zeros) */
while (!indices[call_cntr])
{
funcctx->call_cntr = ++call_cntr;
};
if (call_cntr < max_calls)
{
TupleDesc tuple_desc = funcctx->tuple_desc;
Datum values[2];
bool nulls[2] = {false};
HeapTuple tuple;
Datum result;
values[0] = H3IndexGetDatum(indices[call_cntr]);
values[1] = Int32GetDatum(distances[call_cntr]);
tuple = heap_form_tuple(tuple_desc, values, nulls);
result = HeapTupleGetDatum(tuple);
SRF_RETURN_NEXT(funcctx, result);
}
else
{
SRF_RETURN_DONE(funcctx);
}
}
h3-pg-4.1.3/h3/src/srf.h 0000664 0000000 0000000 00000002275 14460144644 0014516 0 ustar 00root root 0000000 0000000 /*
* Copyright 2023 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.
*/
#ifndef H3_SRF_H
#define H3_SRF_H
#include
typedef struct
{
H3Index *indices;
int *distances;
} hexDistanceTuple;
/* helper functions to return sets from user fctx */
Datum srf_return_h3_indexes_from_user_fctx(PG_FUNCTION_ARGS);
Datum srf_return_h3_index_distances_from_user_fctx(PG_FUNCTION_ARGS);
/* macros to pass on fcinfo to above helpers */
#define SRF_RETURN_H3_INDEXES_FROM_USER_FCTX() \
return srf_return_h3_indexes_from_user_fctx(fcinfo)
#define SRF_RETURN_H3_INDEX_DISTANCES_FROM_USER_FCTX() \
return srf_return_h3_index_distances_from_user_fctx(fcinfo)
#endif /* H3_SRF_H */
h3-pg-4.1.3/h3/src/type.c 0000664 0000000 0000000 00000003065 14460144644 0014676 0 ustar 00root root 0000000 0000000 /*
* Copyright 2018-2023 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
#include
#include // PG_FUNCTION_ARGS
#include "error.h"
#include "type.h"
/* conversion */
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3index_in);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3index_out);
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3index_to_bigint);
PGDLLEXPORT PG_FUNCTION_INFO_V1(bigint_to_h3index);
/* textual input/output functions */
Datum
h3index_in(PG_FUNCTION_ARGS)
{
char *string = PG_GETARG_CSTRING(0);
H3Index h3;
h3_assert(stringToH3(string, &h3));
PG_RETURN_H3INDEX(h3);
}
Datum
h3index_out(PG_FUNCTION_ARGS)
{
H3Index h3 = PG_GETARG_H3INDEX(0);
char *string = palloc(17 * sizeof(char));
h3_assert(h3ToString(h3, string, 17));
PG_RETURN_CSTRING(string);
}
/* bigint conversion functions */
Datum
h3index_to_bigint(PG_FUNCTION_ARGS)
{
H3Index h3index = PG_GETARG_H3INDEX(0);
PG_RETURN_INT64(h3index);
}
Datum
bigint_to_h3index(PG_FUNCTION_ARGS)
{
int64_t bigint = PG_GETARG_INT64(0);
PG_RETURN_H3INDEX(bigint);
}
h3-pg-4.1.3/h3/test/ 0000775 0000000 0000000 00000000000 14460144644 0013735 5 ustar 00root root 0000000 0000000 h3-pg-4.1.3/h3/test/CMakeLists.txt 0000664 0000000 0000000 00000001567 14460144644 0016506 0 ustar 00root root 0000000 0000000 set(TESTS
extension
hierarchy
indexing
inspection
miscellaneous
opclass_brin
opclass_btree
opclass_hash
regions
traversal
type
edge
)
if(PostgreSQL_REGRESS)
add_test(
NAME h3_regress
COMMAND ${PostgreSQL_REGRESS}
--temp-instance=${CMAKE_BINARY_DIR}/tmp
--bindir=${PostgreSQL_BIN_DIR}
--inputdir=${CMAKE_CURRENT_SOURCE_DIR}
--outputdir=${CMAKE_CURRENT_BINARY_DIR}
--load-extension h3
${TESTS}
)
endif()
if(PostgreSQL_VALIDATE_EXTUPGRADE)
add_test(
NAME h3_validate_extrupgrade
COMMAND pg_validate_extupgrade
--extname h3
--from 0.1.0
--to ${INSTALL_VERSION}
)
endif()
# @TODO: Figure out how to inline on MacOS
if(NOT APPLE)
add_test(
NAME h3_inlined
COMMAND sh -c "! objdump -D ${PostgreSQL_PKG_LIBRARY_DIR}/h3.so | grep radsToDegs"
CONFIGURATIONS Release
)
endif()
h3-pg-4.1.3/h3/test/expected/ 0000775 0000000 0000000 00000000000 14460144644 0015536 5 ustar 00root root 0000000 0000000 h3-pg-4.1.3/h3/test/expected/clustering.out 0000664 0000000 0000000 00000000747 14460144644 0020456 0 ustar 00root root 0000000 0000000 \pset tuples_only on
\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_cells();
CREATE INDEX h3_test_clustering_index ON h3_test_clustering USING btree (hex);
CLUSTER h3_test_clustering_index ON h3_test_clustering;
--
-- TEST clustering on B-tree
--
SELECT hex = :hexagon FROM (
SELECT hex FROM h3_test_clustering WHERE hex = :hexagon
) q;
t
h3-pg-4.1.3/h3/test/expected/edge.out 0000664 0000000 0000000 00000002510 14460144644 0017171 0 ustar 00root root 0000000 0000000 \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
h3-pg-4.1.3/h3/test/expected/extension.out 0000664 0000000 0000000 00000000514 14460144644 0020303 0 ustar 00root root 0000000 0000000 \pset tuples_only on
--
-- TEST h3_get_extension_version
--
SELECT h3_get_extension_version() ~ '^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$'
OR h3_get_extension_version() = 'unreleased';
t
h3-pg-4.1.3/h3/test/expected/hierarchy.out 0000664 0000000 0000000 00000006115 14460144644 0020250 0 ustar 00root root 0000000 0000000 \pset tuples_only on
-- neighbouring indexes (one hexagon, one pentagon) at resolution 3
\set hexagon '\'831c02fffffffff\'::h3index'
\set pentagon '\'831c00fffffffff\'::h3index'
\set resolution 3
--
-- 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_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_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_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_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_cell_to_children(:hexagon) hex
) q;
t
-- pentagon has 6 children
SELECT array_length(array_agg(hex), 1) = 6 FROM (
SELECT h3_cell_to_children(:pentagon) hex
) q;
t
-- parent is one lower resolution
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_cell_to_children(:hexagon)) r
) q;
t
-- parent of center child should be original index
SELECT :hexagon = h3_cell_to_parent(h3_cell_to_center_child(:hexagon, 15), :resolution);
t
--
-- TEST h3_cell_to_child_pos and h3_child_pos_to_cell
--
SELECT :hexagon = h3_child_pos_to_cell(
h3_cell_to_child_pos(:hexagon, :resolution - 1),
h3_cell_to_parent(:hexagon),
:resolution
);
t
SELECT COUNT(*) = 7 FROM (
SELECT h3_cell_to_child_pos(
h3_cell_to_children(:hexagon), :resolution - 1
)
) q;
t
--
-- 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_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_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_cells(ARRAY(
SELECT h3_cell_to_children(:hexagon) UNION SELECT :pentagon
), :resolution +2) result
EXCEPT (
SELECT h3_cell_to_children(:hexagon, :resolution +2) result
UNION SELECT h3_cell_to_children(:pentagon, :resolution +2) result
)
) q;
t
--
-- TEST h3_cell_to_children_slow
--
-- h3_cell_to_children_slow and h3_cell_to_children have same result
SELECT array_agg(result) is null FROM (
SELECT h3_cell_to_children_slow(:hexagon, :resolution + 3) result
EXCEPT SELECT h3_cell_to_children(:hexagon, :resolution + 3) result
) q;
t
h3-pg-4.1.3/h3/test/expected/indexing.out 0000664 0000000 0000000 00000004231 14460144644 0020074 0 ustar 00root root 0000000 0000000 \pset tuples_only on
-- neighbouring indexes (one hexagon, one pentagon) at resolution 3
\set geo POINT(-144.52399108028, 49.7165031828995)
\set hexagon '\'831c02fffffffff\'::h3index'
\set pentagon '\'831c00fffffffff\'::h3index'
\set edgecross '\'8003fffffffffff\'::h3index'
\set resolution 3
--
-- TEST h3_cell_to_lat_lng and h3_lat_lng_to_cell
--
-- convertion to geo works
SELECT h3_cell_to_lat_lng(:hexagon) ~= :geo;
t
-- convertion to h3 index works
SELECT h3_lat_lng_to_cell(:geo, :resolution) = :hexagon;
t
-- 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_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_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_cell_to_boundary
--
-- polyfill of geo boundary returns original index
SELECT h3_polygon_to_cells(h3_cell_to_boundary(:hexagon), null, :resolution) = :hexagon;
t
-- same for 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_cell_to_boundary(:hexagon) ~= h3_cell_to_boundary(:hexagon, true)
AND NOT h3_cell_to_boundary(:edgecross) ~= h3_cell_to_boundary(:edgecross, true);
WARNING: Deprecated: Please use `SET h3.extend_antimeridian TO true` instead of extend flag
WARNING: Deprecated: Please use `SET h3.extend_antimeridian TO true` instead of extend flag
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;
h3-pg-4.1.3/h3/test/expected/inspection.out 0000664 0000000 0000000 00000002444 14460144644 0020446 0 ustar 00root root 0000000 0000000 \pset tuples_only on
-- neighbouring indexes (one hexagon, one pentagon) at resolution 3
\set invalid '\'0\''
\set hexagon '\'831c02fffffffff\'::h3index'
\set pentagon '\'831c00fffffffff\'::h3index'
\set resolution 3
--
-- TEST h3_get_resolution
--
SELECT h3_get_resolution(:hexagon) = :resolution AND h3_get_resolution(:pentagon) = :resolution;
t
--
-- TEST h3_get_base_cell_number
--
-- base cell is same for parents
SELECT h3_get_base_cell_number(:hexagon) = h3_get_base_cell_number(h3_cell_to_parent(:hexagon));
t
SELECT h3_get_base_cell_number(:pentagon) = h3_get_base_cell_number(h3_cell_to_parent(:pentagon));
t
--
-- TEST h3_is_valid_cell
--
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_cell_to_parent(:hexagon));
t
SELECT h3_is_res_class_iii(:pentagon) AND NOT h3_is_res_class_iii(h3_cell_to_parent(:pentagon));
t
--
-- TEST h3_is_pentagon
--
SELECT h3_is_pentagon(:pentagon) AND NOT h3_is_pentagon(:hexagon);
t
--
-- TEST h3_get_icosahedron_faces
--
SELECT h3_get_icosahedron_faces('851c0047fffffff') = ARRAY[11,6];
t
SELECT h3_get_icosahedron_faces('851c004bfffffff') = ARRAY[6];
t
h3-pg-4.1.3/h3/test/expected/miscellaneous.out 0000664 0000000 0000000 00000004350 14460144644 0021134 0 ustar 00root root 0000000 0000000 \pset tuples_only on
\set degs 90.45
\set rads 1.57865030842887
\set epsilon 0.000000001
\set edge '\'1180326b885fffff\'::h3index'
--
-- TEST h3_great_circle_distance
--
\set lyon POINT(4.8422, 45.7597)
\set paris POINT(2.3508, 48.8567)
SELECT h3_great_circle_distance(:lyon, :paris, 'rads') - 0.0615628186794217 < :epsilon;
t
SELECT h3_great_circle_distance(:lyon, :paris, 'm') - 392217.1598841777 < :epsilon;
t
SELECT h3_great_circle_distance(:lyon, :paris, 'km') - 392.21715988417765 < :epsilon;
t
-- test that 'km' is the default unit
SELECT h3_great_circle_distance(:lyon, :paris, 'km') = h3_great_circle_distance(:lyon, :paris);
t
--
-- TEST h3_get_hexagon_area_avg
--
SELECT abs(h3_get_hexagon_area_avg(10, 'm') - 15047.50190766437) < :epsilon;
t
SELECT abs(h3_get_hexagon_area_avg(10, 'km') - 0.01504750190766435) < :epsilon;
t
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_lat_lng_to_cell(POINT(0, 0), 10), 'm^2') / 1000000) - :expected_km2) < :epsilon;
t
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_lat_lng_to_cell(POINT(0, 0), 10), 'rads^2') > 0;
t
-- default is km^2
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_get_hexagon_edge_length_avg
--
SELECT h3_get_hexagon_edge_length_avg(10, 'm') = 65.90780749;
t
SELECT h3_get_hexagon_edge_length_avg(10, 'km') = 0.065907807;
t
SELECT h3_get_hexagon_edge_length_avg(10, 'km') = h3_get_hexagon_edge_length_avg(10);
t
--
-- TEST h3_edge_length
--
SELECT h3_edge_length(:edge, 'rads') > 0;
t
SELECT h3_edge_length(:edge, 'km') > h3_edge_length(:edge, 'rads');
t
SELECT h3_edge_length(:edge, 'm') > h3_edge_length(:edge, 'km');
t
SELECT h3_edge_length(:edge) = h3_edge_length(:edge, 'km');
t
--
-- TEST h3_get_num_cells
--
SELECT h3_get_num_cells(0) = 122;
t
SELECT h3_get_num_cells(15) = 569707381193162;
t
--
-- TEST h3_get_res_0_cells
--
SELECT COUNT(*) = 122 FROM (SELECT h3_get_res_0_cells()) q;
t
--
-- TEST h3_get_pentagons
--
SELECT COUNT(*) = 12 FROM (SELECT h3_get_pentagons(6)) q;
t
h3-pg-4.1.3/h3/test/expected/opclass_brin.out 0000664 0000000 0000000 00000000602 14460144644 0020743 0 ustar 00root root 0000000 0000000 \pset tuples_only on
\set string '\'801dfffffffffff\''
\set hexagon ':string::h3index'
CREATE TABLE h3_test_brin (hex h3index PRIMARY KEY);
INSERT INTO h3_test_brin (hex) SELECT * FROM h3_get_res_0_cells();
CREATE INDEX h3_brin ON h3_test_brin USING brin (hex);
--
-- Test BRIN operator class
--
SELECT hex = :hexagon FROM (
SELECT hex FROM h3_test_brin WHERE hex = :hexagon
) q;
t
h3-pg-4.1.3/h3/test/expected/opclass_btree.out 0000664 0000000 0000000 00000000614 14460144644 0021115 0 ustar 00root root 0000000 0000000 \pset tuples_only on
\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_cells();
CREATE INDEX h3_btree ON h3_test_btree USING btree (hex);
--
-- TEST b-tree operator class
--
SELECT hex = :hexagon FROM (
SELECT hex FROM h3_test_btree WHERE hex = :hexagon
) q;
t
h3-pg-4.1.3/h3/test/expected/opclass_hash.out 0000664 0000000 0000000 00000000730 14460144644 0020736 0 ustar 00root root 0000000 0000000 \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_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_cells())
) q;
t
CREATE TABLE h3_test_hash_part (hex h3index PRIMARY KEY) PARTITION BY HASH (hex);
h3-pg-4.1.3/h3/test/expected/regions.out 0000664 0000000 0000000 00000004164 14460144644 0017742 0 ustar 00root root 0000000 0000000 \pset tuples_only on
-- res 0 index
\set res0index '\'8059fffffffffff\''
-- center hex
\set center '\'81583ffffffffff\''
-- 7 child hexes in res 0 index
\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)'
-- pentagon
\set pentagon '\'831c00fffffffff\'::h3index'
--
-- TEST h3_polygon_to_cells and h3_cells_to_multi_polygon
--
-- 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_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_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_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 doesn't segfault on NULL value in holes
SELECT TRUE FROM (
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
) q LIMIT 1;
t
-- h3_polyfill throws on non-polygons
CREATE FUNCTION h3_test_polyfill_bad1() RETURNS boolean LANGUAGE PLPGSQL
AS $$
BEGIN
PERFORM h3_polyfill(ST_GeomFromText('POINT(-71.160281 42.258729)',4326), 8);
RETURN false;
EXCEPTION WHEN OTHERS THEN
RETURN true;
END;
$$;
CREATE FUNCTION h3_test_polyfill_bad2() RETURNS boolean LANGUAGE PLPGSQL
AS $$
BEGIN
PERFORM h3_polyfill(ST_GeomFromText('LINESTRING(-71.160281 42.258729,-71.160837 42.259113,-71.161144 42.25932)',4326), 8);
RETURN false;
EXCEPTION WHEN OTHERS THEN
RETURN true;
END;
$$;
SELECT h3_test_polyfill_bad1();
t
SELECT h3_test_polyfill_bad2();
t
DROP FUNCTION h3_test_polyfill_bad1;
DROP FUNCTION h3_test_polyfill_bad2;
h3-pg-4.1.3/h3/test/expected/traversal.out 0000664 0000000 0000000 00000004040 14460144644 0020270 0 ustar 00root root 0000000 0000000 \pset tuples_only on
\set hexagon '\'880326b88dfffff\''
\set origin '\'880326b887fffff\''
\set pentagon '\'831c00fffffffff\''
--
-- TEST h3_grid_disk and h3_grid_ring_unsafe
--
-- gridDisk 0 is input index
SELECT h3_grid_disk(:hexagon, 0) = :hexagon;
t
-- gridDisk 2 is same as sum of gridRing 0, 1 and 2
SELECT array_agg(r) is null FROM (
SELECT h3_grid_disk(:hexagon, 2) r
EXCEPT (
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_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_grid_disk_distances(:hexagon, 2)
) q;
t
-- same for pentagon
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_grid_disk_distances(:pentagon, 2)
) q;
t
--
-- TEST h3_grid_path_cells
--
SELECT ARRAY(SELECT h3_grid_path_cells('841c023ffffffff', '841c025ffffffff'))
= ARRAY['841c023ffffffff','841c027ffffffff','841c025ffffffff']::h3index[];
t
--
-- TEST h3_grid_distance
--
-- returns 1 for indexes with one index between them
SELECT h3_grid_distance('880326b881fffff', '880326b885fffff') = 1;
t
-- 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_cell_to_local_ij and h3_local_ij_to_cell
--
-- they are inverse of each others
SELECT :hexagon = h3_local_ij_to_cell(:origin, h3_cell_to_local_ij(:origin, :hexagon));
t
h3-pg-4.1.3/h3/test/expected/type.out 0000664 0000000 0000000 00000001113 14460144644 0017244 0 ustar 00root root 0000000 0000000 \pset tuples_only on
\set string '\'801dfffffffffff\''
\set asbigint 576988517884755967
\set hexagon ':string::h3index'
\set pentagon '\'844c001ffffffff\'::h3index'
--
-- TEST operators
--
SELECT :hexagon = :hexagon;
t
SELECT NOT :hexagon = :pentagon;
t
SELECT NOT :hexagon <> :hexagon;
t
SELECT :hexagon <> :pentagon;
t
SELECT :pentagon <@ h3_cell_to_parent(:pentagon);
t
SELECT bool_and(:pentagon @> c) FROM (
SELECT h3_cell_to_children(:pentagon) c
) q;
t
--
-- TEST bigint casting
--
SELECT :asbigint = :hexagon::bigint;
t
SELECT :hexagon = :asbigint::h3index;
t
h3-pg-4.1.3/h3/test/expected/vertex.out 0000664 0000000 0000000 00000001265 14460144644 0017610 0 ustar 00root root 0000000 0000000 \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
h3-pg-4.1.3/h3/test/sql/ 0000775 0000000 0000000 00000000000 14460144644 0014534 5 ustar 00root root 0000000 0000000 h3-pg-4.1.3/h3/test/sql/clustering.sql 0000664 0000000 0000000 00000000744 14460144644 0017441 0 ustar 00root root 0000000 0000000 \pset tuples_only on
\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_cells();
CREATE INDEX h3_test_clustering_index ON h3_test_clustering USING btree (hex);
CLUSTER h3_test_clustering_index ON h3_test_clustering;
--
-- TEST clustering on B-tree
--
SELECT hex = :hexagon FROM (
SELECT hex FROM h3_test_clustering WHERE hex = :hexagon
) q;
h3-pg-4.1.3/h3/test/sql/edge.sql 0000664 0000000 0000000 00000002456 14460144644 0016170 0 ustar 00root root 0000000 0000000 \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))' h3-pg-4.1.3/h3/test/sql/extension.sql 0000664 0000000 0000000 00000000512 14460144644 0017267 0 ustar 00root root 0000000 0000000 \pset tuples_only on
--
-- TEST h3_get_extension_version
--
SELECT h3_get_extension_version() ~ '^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$'
OR h3_get_extension_version() = 'unreleased';
h3-pg-4.1.3/h3/test/sql/hierarchy.sql 0000664 0000000 0000000 00000006044 14460144644 0017237 0 ustar 00root root 0000000 0000000 \pset tuples_only on
-- neighbouring indexes (one hexagon, one pentagon) at resolution 3
\set hexagon '\'831c02fffffffff\'::h3index'
\set pentagon '\'831c00fffffffff\'::h3index'
\set resolution 3
--
-- 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_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_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_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_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_cell_to_children(:hexagon) hex
) q;
-- pentagon has 6 children
SELECT array_length(array_agg(hex), 1) = 6 FROM (
SELECT h3_cell_to_children(:pentagon) hex
) q;
-- parent is one lower resolution
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_cell_to_children(:hexagon)) r
) q;
-- parent of center child should be original index
SELECT :hexagon = h3_cell_to_parent(h3_cell_to_center_child(:hexagon, 15), :resolution);
--
-- TEST h3_cell_to_child_pos and h3_child_pos_to_cell
--
SELECT :hexagon = h3_child_pos_to_cell(
h3_cell_to_child_pos(:hexagon, :resolution - 1),
h3_cell_to_parent(:hexagon),
:resolution
);
SELECT COUNT(*) = 7 FROM (
SELECT h3_cell_to_child_pos(
h3_cell_to_children(:hexagon), :resolution - 1
)
) q;
--
-- 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_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_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_cells(ARRAY(
SELECT h3_cell_to_children(:hexagon) UNION SELECT :pentagon
), :resolution +2) result
EXCEPT (
SELECT h3_cell_to_children(:hexagon, :resolution +2) result
UNION SELECT h3_cell_to_children(:pentagon, :resolution +2) result
)
) q;
--
-- TEST h3_cell_to_children_slow
--
-- h3_cell_to_children_slow and h3_cell_to_children have same result
SELECT array_agg(result) is null FROM (
SELECT h3_cell_to_children_slow(:hexagon, :resolution + 3) result
EXCEPT SELECT h3_cell_to_children(:hexagon, :resolution + 3) result
) q;
h3-pg-4.1.3/h3/test/sql/indexing.sql 0000664 0000000 0000000 00000003704 14460144644 0017066 0 ustar 00root root 0000000 0000000 \pset tuples_only on
-- neighbouring indexes (one hexagon, one pentagon) at resolution 3
\set geo POINT(-144.52399108028, 49.7165031828995)
\set hexagon '\'831c02fffffffff\'::h3index'
\set pentagon '\'831c00fffffffff\'::h3index'
\set edgecross '\'8003fffffffffff\'::h3index'
\set resolution 3
--
-- TEST h3_cell_to_lat_lng and h3_lat_lng_to_cell
--
-- convertion to geo works
SELECT h3_cell_to_lat_lng(:hexagon) ~= :geo;
-- convertion to h3 index works
SELECT h3_lat_lng_to_cell(:geo, :resolution) = :hexagon;
-- 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_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_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_cell_to_boundary
--
-- polyfill of geo boundary returns original index
SELECT h3_polygon_to_cells(h3_cell_to_boundary(:hexagon), null, :resolution) = :hexagon;
-- same for 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_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; h3-pg-4.1.3/h3/test/sql/inspection.sql 0000664 0000000 0000000 00000002414 14460144644 0017431 0 ustar 00root root 0000000 0000000 \pset tuples_only on
-- neighbouring indexes (one hexagon, one pentagon) at resolution 3
\set invalid '\'0\''
\set hexagon '\'831c02fffffffff\'::h3index'
\set pentagon '\'831c00fffffffff\'::h3index'
\set resolution 3
--
-- TEST h3_get_resolution
--
SELECT h3_get_resolution(:hexagon) = :resolution AND h3_get_resolution(:pentagon) = :resolution;
--
-- TEST h3_get_base_cell_number
--
-- base cell is same for parents
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_cell
--
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_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
--
SELECT h3_is_pentagon(:pentagon) AND NOT h3_is_pentagon(:hexagon);
--
-- TEST h3_get_icosahedron_faces
--
SELECT h3_get_icosahedron_faces('851c0047fffffff') = ARRAY[11,6];
SELECT h3_get_icosahedron_faces('851c004bfffffff') = ARRAY[6];
h3-pg-4.1.3/h3/test/sql/miscellaneous.sql 0000664 0000000 0000000 00000004244 14460144644 0020124 0 ustar 00root root 0000000 0000000 \pset tuples_only on
\set degs 90.45
\set rads 1.57865030842887
\set epsilon 0.000000001
\set edge '\'1180326b885fffff\'::h3index'
--
-- TEST h3_great_circle_distance
--
\set lyon POINT(4.8422, 45.7597)
\set paris POINT(2.3508, 48.8567)
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_great_circle_distance(:lyon, :paris, 'km') = h3_great_circle_distance(:lyon, :paris);
--
-- TEST h3_get_hexagon_area_avg
--
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_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_lat_lng_to_cell(POINT(0, 0), 10), 'km^2') = h3_cell_area(h3_lat_lng_to_cell(POINT(0, 0), 10));
--
-- TEST h3_get_hexagon_edge_length_avg
--
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_edge_length
--
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_edge_length(:edge) = h3_edge_length(:edge, 'km');
--
-- TEST h3_get_num_cells
--
SELECT h3_get_num_cells(0) = 122;
SELECT h3_get_num_cells(15) = 569707381193162;
--
-- TEST h3_get_res_0_cells
--
SELECT COUNT(*) = 122 FROM (SELECT h3_get_res_0_cells()) q;
--
-- TEST h3_get_pentagons
--
SELECT COUNT(*) = 12 FROM (SELECT h3_get_pentagons(6)) q;
h3-pg-4.1.3/h3/test/sql/opclass_brin.sql 0000664 0000000 0000000 00000000577 14460144644 0017744 0 ustar 00root root 0000000 0000000 \pset tuples_only on
\set string '\'801dfffffffffff\''
\set hexagon ':string::h3index'
CREATE TABLE h3_test_brin (hex h3index PRIMARY KEY);
INSERT INTO h3_test_brin (hex) SELECT * FROM h3_get_res_0_cells();
CREATE INDEX h3_brin ON h3_test_brin USING brin (hex);
--
-- Test BRIN operator class
--
SELECT hex = :hexagon FROM (
SELECT hex FROM h3_test_brin WHERE hex = :hexagon
) q;
h3-pg-4.1.3/h3/test/sql/opclass_btree.sql 0000664 0000000 0000000 00000000611 14460144644 0020100 0 ustar 00root root 0000000 0000000 \pset tuples_only on
\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_cells();
CREATE INDEX h3_btree ON h3_test_btree USING btree (hex);
--
-- TEST b-tree operator class
--
SELECT hex = :hexagon FROM (
SELECT hex FROM h3_test_btree WHERE hex = :hexagon
) q;
h3-pg-4.1.3/h3/test/sql/opclass_hash.sql 0000664 0000000 0000000 00000000653 14460144644 0017730 0 ustar 00root root 0000000 0000000 \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_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_cells())
) q;
CREATE TABLE h3_test_hash_part (hex h3index PRIMARY KEY) PARTITION BY HASH (hex); h3-pg-4.1.3/h3/test/sql/regions.sql 0000664 0000000 0000000 00000004145 14460144644 0016727 0 ustar 00root root 0000000 0000000 \pset tuples_only on
-- res 0 index
\set res0index '\'8059fffffffffff\''
-- center hex
\set center '\'81583ffffffffff\''
-- 7 child hexes in res 0 index
\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)'
-- pentagon
\set pentagon '\'831c00fffffffff\'::h3index'
--
-- TEST h3_polygon_to_cells and h3_cells_to_multi_polygon
--
-- 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_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_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_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 doesn't segfault on NULL value in holes
SELECT TRUE FROM (
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
) q LIMIT 1;
-- h3_polyfill throws on non-polygons
CREATE FUNCTION h3_test_polyfill_bad1() RETURNS boolean LANGUAGE PLPGSQL
AS $$
BEGIN
PERFORM h3_polyfill(ST_GeomFromText('POINT(-71.160281 42.258729)',4326), 8);
RETURN false;
EXCEPTION WHEN OTHERS THEN
RETURN true;
END;
$$;
CREATE FUNCTION h3_test_polyfill_bad2() RETURNS boolean LANGUAGE PLPGSQL
AS $$
BEGIN
PERFORM h3_polyfill(ST_GeomFromText('LINESTRING(-71.160281 42.258729,-71.160837 42.259113,-71.161144 42.25932)',4326), 8);
RETURN false;
EXCEPTION WHEN OTHERS THEN
RETURN true;
END;
$$;
SELECT h3_test_polyfill_bad1();
SELECT h3_test_polyfill_bad2();
DROP FUNCTION h3_test_polyfill_bad1;
DROP FUNCTION h3_test_polyfill_bad2;
h3-pg-4.1.3/h3/test/sql/traversal.sql 0000664 0000000 0000000 00000004016 14460144644 0017261 0 ustar 00root root 0000000 0000000 \pset tuples_only on
\set hexagon '\'880326b88dfffff\''
\set origin '\'880326b887fffff\''
\set pentagon '\'831c00fffffffff\''
--
-- TEST h3_grid_disk and h3_grid_ring_unsafe
--
-- gridDisk 0 is input index
SELECT h3_grid_disk(:hexagon, 0) = :hexagon;
-- gridDisk 2 is same as sum of gridRing 0, 1 and 2
SELECT array_agg(r) is null FROM (
SELECT h3_grid_disk(:hexagon, 2) r
EXCEPT (
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_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_grid_disk_distances(:hexagon, 2)
) q;
-- same for pentagon
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_grid_disk_distances(:pentagon, 2)
) q;
--
-- TEST h3_grid_path_cells
--
SELECT ARRAY(SELECT h3_grid_path_cells('841c023ffffffff', '841c025ffffffff'))
= ARRAY['841c023ffffffff','841c027ffffffff','841c025ffffffff']::h3index[];
--
-- TEST h3_grid_distance
--
-- returns 1 for indexes with one index between them
SELECT h3_grid_distance('880326b881fffff', '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_cell_to_local_ij and h3_local_ij_to_cell
--
-- they are inverse of each others
SELECT :hexagon = h3_local_ij_to_cell(:origin, h3_cell_to_local_ij(:origin, :hexagon)); h3-pg-4.1.3/h3/test/sql/type.sql 0000664 0000000 0000000 00000001056 14460144644 0016240 0 ustar 00root root 0000000 0000000 \pset tuples_only on
\set string '\'801dfffffffffff\''
\set asbigint 576988517884755967
\set hexagon ':string::h3index'
\set pentagon '\'844c001ffffffff\'::h3index'
--
-- TEST operators
--
SELECT :hexagon = :hexagon;
SELECT NOT :hexagon = :pentagon;
SELECT NOT :hexagon <> :hexagon;
SELECT :hexagon <> :pentagon;
SELECT :pentagon <@ h3_cell_to_parent(:pentagon);
SELECT bool_and(:pentagon @> c) FROM (
SELECT h3_cell_to_children(:pentagon) c
) q;
--
-- TEST bigint casting
--
SELECT :asbigint = :hexagon::bigint;
SELECT :hexagon = :asbigint::h3index;
h3-pg-4.1.3/h3/test/sql/vertex.sql 0000664 0000000 0000000 00000001245 14460144644 0016574 0 ustar 00root root 0000000 0000000 \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); h3-pg-4.1.3/h3_postgis/ 0000775 0000000 0000000 00000000000 14460144644 0014526 5 ustar 00root root 0000000 0000000 h3-pg-4.1.3/h3_postgis/CMakeLists.txt 0000664 0000000 0000000 00000002244 14460144644 0017270 0 ustar 00root root 0000000 0000000 PostgreSQL_add_extension(postgresql_h3_postgis
RELOCATABLE
NAME h3_postgis
COMMENT "H3 PostGIS integration"
VERSION ${INSTALL_VERSION}
COMPONENT ${PROJECT_NAME}
REQUIRES
h3
postgis
postgis_raster
SOURCES
src/init.c
src/wkb_bbox3.c
src/wkb_indexing.c
src/wkb_linked_geo.c
src/wkb_regions.c
src/wkb_split.c
src/wkb_vect3.c
src/wkb.c
INSTALLS
sql/install/01-indexing.sql
sql/install/03-traversal.sql
sql/install/05-regions.sql
sql/install/10-operators.sql
sql/install/20-casts.sql
sql/install/30-wkb.sql
sql/install/40-rasters.sql
sql/install/99-deprecated.sql
UPDATES
sql/updates/h3_postgis--4.0.0.sql
sql/updates/h3_postgis--4.0.0--4.0.1.sql
sql/updates/h3_postgis--4.0.1--4.0.2.sql
sql/updates/h3_postgis--4.0.2--4.0.3.sql
sql/updates/h3_postgis--4.0.3--4.1.0.sql
sql/updates/h3_postgis--4.1.0--4.1.1.sql
sql/updates/h3_postgis--4.1.1--4.1.2.sql
sql/updates/h3_postgis--4.1.2--4.1.3.sql
)
# link
target_link_libraries(postgresql_h3_postgis PRIVATE postgresql_h3_shared h3)
# test
if(BUILD_TESTING AND PostgreSQL_PostGIS_FOUND)
add_subdirectory(test)
endif()
h3-pg-4.1.3/h3_postgis/sql/ 0000775 0000000 0000000 00000000000 14460144644 0015325 5 ustar 00root root 0000000 0000000 h3-pg-4.1.3/h3_postgis/sql/install/ 0000775 0000000 0000000 00000000000 14460144644 0016773 5 ustar 00root root 0000000 0000000 h3-pg-4.1.3/h3_postgis/sql/install/01-indexing.sql 0000664 0000000 0000000 00000006335 14460144644 0021546 0 ustar 00root root 0000000 0000000 /*
* 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.
*/
--| The `GEOMETRY` data passed to `h3-pg` PostGIS functions should
--| be in SRID 4326. This is an expectation of the core H3 library.
--| Using other SRIDs, such as 3857, can result in either errors or
--| invalid data depending on the function.
--| For example, the `h3_polygon_to_cells()` function will fail with
--| an error in this scenario while the `h3_lat_lng_to_cell()` function
--| will return an invalid geometry.
--| # PostGIS Indexing Functions
--@ availability: 4.0.0
--@ refid: h3_lat_lng_to_cell_geometry
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;
COMMENT ON FUNCTION
h3_lat_lng_to_cell(geometry, resolution integer)
IS 'Indexes the location at the specified resolution.';
--@ availability: 4.0.0
--@ refid: h3_lat_lng_to_cell_geography
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;
COMMENT ON FUNCTION
h3_lat_lng_to_cell(geometry, resolution integer)
IS 'Indexes the location at the specified resolution.';
--@ availability: 4.0.0
--@ refid: h3_cell_to_geometry
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;
COMMENT ON FUNCTION
h3_cell_to_geometry(h3index)
IS 'Finds the centroid of the index.';
--@ availability: 4.0.0
--@ refid: h3_cell_to_geography
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;
COMMENT ON FUNCTION
h3_cell_to_geography(h3index)
IS 'Finds the centroid of the index.';
--@ availability: 4.0.0
--@ refid: h3_cell_to_boundary_geometry
CREATE OR REPLACE FUNCTION h3_cell_to_boundary_geometry(h3index) RETURNS geometry
AS $$ SELECT h3_cell_to_boundary_wkb($1)::geometry $$ IMMUTABLE STRICT PARALLEL SAFE LANGUAGE SQL;
COMMENT ON FUNCTION
h3_cell_to_boundary_geometry(h3index)
IS 'Finds the boundary of the index.
Splits polygons when crossing 180th meridian.';
--@ availability: 4.0.0
--@ refid: h3_cell_to_boundary_geography
CREATE OR REPLACE FUNCTION h3_cell_to_boundary_geography(h3index) RETURNS geography
AS $$ SELECT h3_cell_to_boundary_wkb($1)::geography $$ IMMUTABLE STRICT PARALLEL SAFE LANGUAGE SQL;
COMMENT ON FUNCTION
h3_cell_to_boundary_geography(h3index)
IS 'Finds the boundary of the index.
Splits polygons when crossing 180th meridian.';
h3-pg-4.1.3/h3_postgis/sql/install/03-traversal.sql 0000664 0000000 0000000 00000004176 14460144644 0021747 0 ustar 00root root 0000000 0000000 /*
* 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.
*/
--| # PostGIS Grid Traversal Functions
--@ availability: 4.1.0
--@ refid: h3_grid_path_cells_recursive
CREATE OR REPLACE FUNCTION
h3_grid_path_cells_recursive(origin h3index, destination h3index) RETURNS SETOF h3index
AS $$
BEGIN
IF (SELECT
origin != destination
AND NOT h3_are_neighbor_cells(origin, destination)
AND ((base1 != base2 AND NOT h3_are_neighbor_cells(base1, base2))
OR ((h3_is_pentagon(base1) OR h3_is_pentagon(base2))
AND NOT (
h3_get_icosahedron_faces(origin)
&& h3_get_icosahedron_faces(destination))))
FROM (
SELECT
h3_cell_to_parent(origin, 0) AS base1,
h3_cell_to_parent(destination, 0) AS base2) AS t)
THEN
RETURN QUERY WITH
points AS (
SELECT
h3_cell_to_geometry(origin) AS g1,
h3_cell_to_geometry(destination) AS g2),
cells AS (
SELECT
h3_lat_lng_to_cell(
ST_Centroid(ST_MakeLine(g1, g2)::geography),
h3_get_resolution(origin)) AS middle
FROM points)
SELECT h3_grid_path_cells_recursive(origin, middle) FROM cells
UNION
SELECT h3_grid_path_cells_recursive(middle, destination) FROM cells;
ELSE
RETURN QUERY SELECT h3_grid_path_cells(origin, destination);
END IF;
END;
$$ LANGUAGE 'plpgsql' IMMUTABLE STRICT PARALLEL SAFE;
h3-pg-4.1.3/h3_postgis/sql/install/05-regions.sql 0000664 0000000 0000000 00000005652 14460144644 0021414 0 ustar 00root root 0000000 0000000 /*
* 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
--@ refid: h3_polygon_to_cells_geometry
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
--@ refid: h3_polygon_to_cells_geography
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
--@ availability: 4.1.0
--@ refid: h3_cells_to_multi_polygon_geometry
CREATE OR REPLACE FUNCTION
h3_cells_to_multi_polygon_geometry(h3index[]) RETURNS geometry
AS $$ SELECT h3_cells_to_multi_polygon_wkb($1)::geometry $$ IMMUTABLE STRICT PARALLEL SAFE LANGUAGE SQL;
--@ availability: 4.1.0
--@ refid: h3_cells_to_multi_polygon_geography
CREATE OR REPLACE FUNCTION
h3_cells_to_multi_polygon_geography(h3index[]) RETURNS geography
AS $$ SELECT h3_cells_to_multi_polygon_wkb($1)::geography $$ IMMUTABLE STRICT PARALLEL SAFE LANGUAGE SQL;
--@ availability: 4.1.0
--@ refid: h3_cells_to_multi_polygon_geometry_agg
CREATE AGGREGATE h3_cells_to_multi_polygon_geometry(h3index) (
sfunc = array_append,
stype = h3index[],
finalfunc = h3_cells_to_multi_polygon_geometry,
parallel = safe
);
--@ availability: 4.1.0
--@ refid: h3_cells_to_multi_polygon_geography_agg
CREATE AGGREGATE h3_cells_to_multi_polygon_geography(h3index) (
sfunc = array_append,
stype = h3index[],
finalfunc = h3_cells_to_multi_polygon_geography,
parallel = safe
);
h3-pg-4.1.3/h3_postgis/sql/install/10-operators.sql 0000664 0000000 0000000 00000002045 14460144644 0021751 0 ustar 00root root 0000000 0000000 /*
* Copyright 2023 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 Operators
--@ availability: 4.1.3
CREATE OPERATOR @ (
PROCEDURE = h3_lat_lng_to_cell,
LEFTARG = geometry, RIGHTARG = integer
);
COMMENT ON OPERATOR @ (geometry, integer) IS
'Index geometry at specified resolution.';
--@ availability: 4.1.3
CREATE OPERATOR @ (
PROCEDURE = h3_lat_lng_to_cell,
LEFTARG = geography, RIGHTARG = integer
);
COMMENT ON OPERATOR @ (geography, integer) IS
'Index geography at specified resolution.';
h3-pg-4.1.3/h3_postgis/sql/install/20-casts.sql 0000664 0000000 0000000 00000001620 14460144644 0021047 0 ustar 00root root 0000000 0000000 /*
* 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 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);
h3-pg-4.1.3/h3_postgis/sql/install/30-wkb.sql 0000664 0000000 0000000 00000002651 14460144644 0020523 0 ustar 00root root 0000000 0000000 /*
* 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.
*/
--| # WKB indexing functions
--@ availability: 4.1.0
CREATE OR REPLACE FUNCTION
h3_cell_to_boundary_wkb(cell h3index) RETURNS bytea
AS 'h3_postgis' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION
h3_cell_to_boundary_wkb(h3index)
IS 'Finds the boundary of the index, converts to EWKB.
Splits polygons when crossing 180th meridian.
This function has to return WKB since Postgres does not provide multipolygon type.';
--| # WKB regions functions
--@ availability: 4.1.0
CREATE OR REPLACE FUNCTION
h3_cells_to_multi_polygon_wkb(h3index[]) RETURNS bytea
AS 'h3_postgis' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION
h3_cells_to_multi_polygon_wkb(h3index[])
IS 'Create a LinkedGeoPolygon describing the outline(s) of a set of hexagons, converts to EWKB.
Splits polygons when crossing 180th meridian.';
h3-pg-4.1.3/h3_postgis/sql/install/40-rasters.sql 0000664 0000000 0000000 00000060530 14460144644 0021424 0 ustar 00root root 0000000 0000000 /*
* Copyright 2022-2023 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.
*/
--| # Raster processing functions
-- Get nodata value for ST_Clip function
-- ST_Clip sets nodata pixel values to minimum value by default, but it won't
-- set band nodata value in this case, which we need later for filtering dumped
-- values.
CREATE OR REPLACE FUNCTION __h3_raster_band_nodata(
rast raster,
nband integer)
RETURNS double precision
AS $$
SELECT coalesce(
ST_BandNoDataValue(rast, nband),
ST_MinPossibleValue(ST_BandPixelType(rast, nband)));
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
CREATE OR REPLACE FUNCTION __h3_raster_to_polygon(
rast raster,
nband integer)
RETURNS geometry
AS $$
SELECT ST_MinConvexHull(rast, nband);
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
-- Area of a pixel close to the center of raster polygon, in meters
CREATE OR REPLACE FUNCTION __h3_raster_polygon_pixel_area(
rast raster,
poly geometry)
RETURNS double precision
AS $$
SELECT ST_Area(
ST_Transform(
ST_PixelAsPolygon(
rast,
ST_WorldToRasterCoordX(rast, c),
ST_WorldToRasterCoordY(rast, c)),
4326)::geography)
FROM ST_Centroid(poly) AS c
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
CREATE OR REPLACE FUNCTION __h3_raster_polygon_centroid_cell(
poly geometry,
resolution integer)
RETURNS h3index
AS $$
DECLARE
cell h3index := h3_lat_lng_to_cell(ST_Transform(ST_Centroid(poly), 4326), resolution);
BEGIN
IF h3_is_pentagon(cell) THEN
SELECT h3 INTO cell FROM h3_grid_disk(cell) AS h3 WHERE h3 != cell LIMIT 1;
END IF;
RETURN cell;
END;
$$ LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
-- Area of a cell close to the center of raster polygon, in meters
CREATE OR REPLACE FUNCTION __h3_raster_polygon_centroid_cell_area(
poly geometry,
resolution integer)
RETURNS double precision
AS $$
SELECT ST_Area(
h3_cell_to_boundary_geography(
__h3_raster_polygon_centroid_cell(poly, resolution)));
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
-- Get list of cells inside of the raster polygon,
-- buffered by `buffer` value (in meters).
-- If SRID != 4326 then additionally buffer by 1 pixel to account for transformation.
CREATE OR REPLACE FUNCTION __h3_raster_polygon_to_cells(
rast raster,
poly geometry,
resolution integer,
buffer double precision)
RETURNS SETOF h3index
AS $$
DECLARE
buffered geometry := poly;
BEGIN
IF ST_SRID(rast) != 4326 THEN
buffered := ST_Transform(
ST_Buffer(
poly,
greatest(ST_PixelWidth(rast), ST_PixelHeight(rast)),
'join=mitre'),
4326);
END IF;
IF buffer > 0.0 THEN
RETURN QUERY
SELECT h3_polygon_to_cells(
ST_Buffer(
buffered::geography,
buffer,
'join=mitre'),
resolution);
ELSE
RETURN QUERY
SELECT h3_polygon_to_cells(buffered, resolution);
END IF;
END
$$ LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
-- Get geometries of H3 cells interesecting raster polygon.
CREATE OR REPLACE FUNCTION __h3_raster_polygon_to_cell_boundaries_intersects(
rast raster,
poly geometry,
resolution integer)
RETURNS TABLE (h3 h3index, geom geometry)
AS $$
SELECT h3, geom
FROM
__h3_raster_polygon_to_cells(
rast,
poly,
resolution,
h3_get_hexagon_edge_length_avg(resolution, 'm') * 1.3
) AS h3,
ST_Transform(h3_cell_to_boundary_geometry(h3), ST_SRID(rast)) AS geom
WHERE ST_Intersects(geom, poly);
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
-- Get raster coordinates of H3 cells with centroids inside the raster polygon
CREATE OR REPLACE FUNCTION __h3_raster_polygon_to_cell_coords_centroid(
rast raster,
poly geometry,
resolution integer)
RETURNS TABLE (h3 h3index, x integer, y integer)
AS $$
WITH
geoms AS (
SELECT
h3,
ST_Transform(
h3_cell_to_geometry(h3),
ST_SRID(poly)
) AS geom
FROM (
SELECT __h3_raster_polygon_to_cells(rast, poly, resolution, 0.0) AS h3
) t),
coords AS (
SELECT
h3,
ST_WorldToRasterCoordX(rast, geom) AS x,
ST_WorldToRasterCoordY(rast, geom) AS y
FROM geoms)
SELECT h3, x, y
FROM coords
WHERE
x BETWEEN 1 AND ST_Width(rast)
AND y BETWEEN 1 AND ST_Height(rast);
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
CREATE OR REPLACE FUNCTION __h3_raster_polygon_to_cell_parts(
rast raster,
poly geometry,
resolution integer,
nband integer)
RETURNS TABLE (h3 h3index, part raster)
AS $$
DECLARE
nodata CONSTANT double precision := __h3_raster_band_nodata(rast, nband);
BEGIN
RETURN QUERY
SELECT c.h3, p AS part
FROM
__h3_raster_polygon_to_cell_boundaries_intersects(rast, poly, resolution) AS c,
ST_Clip(rast, nband, c.geom, nodata, TRUE) AS p
WHERE NOT ST_BandIsNoData(p, nband);
END;
$$ LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
-- Get values corresponding to all H3 cells with centroids inside the
-- raster polygon. Assumes cell area is less than pixel area.
CREATE OR REPLACE FUNCTION __h3_raster_polygon_subpixel_cell_values(
rast raster,
poly geometry,
resolution integer,
nband integer)
RETURNS TABLE (h3 h3index, val double precision)
AS $$
SELECT
h3,
ST_Value(rast, nband, x, y) AS val
FROM __h3_raster_polygon_to_cell_coords_centroid(rast, poly, resolution);
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
--| ## Continuous raster data
--|
--| For rasters with pixel values representing continuous data (temperature, humidity,
--| elevation), the data inside H3 cells can be summarized by calculating number of
--| pixels, sum, mean, standard deviation, min and max for each cell inside a raster
--| and grouping these stats across multiple rasters by H3 index.
--|
--| ```
--| SELECT
--| (summary).h3 AS h3,
--| (h3_raster_summary_stats_agg((summary).stats)).*
--| FROM (
--| SELECT h3_raster_summary(rast, 8) AS summary
--| FROM rasters
--| ) t
--| GROUP BY 1;
--|
--| h3 | count | sum | mean | stddev | min | max
--| -----------------+-------+--------------------+---------------------+--------------------+-------+------------------
--| 882d638189fffff | 10 | 4.607657432556152 | 0.46076574325561526 | 1.3822972297668457 | 0 | 4.607657432556152
--| 882d64c4d1fffff | 10 | 3.6940908953547478 | 0.3694090895354748 | 1.099336879464068 | 0 | 3.667332887649536
--| 882d607431fffff | 11 | 6.219290263950825 | 0.5653900239955295 | 1.7624673707119065 | 0 | 6.13831996917724
--| <...>
--| ```
-- NOTE: `count` can be < 1 when cell area is less than pixel area
--@ availability: 4.1.1
CREATE TYPE h3_raster_summary_stats AS (
count double precision,
sum double precision,
mean double precision,
stddev double precision,
min double precision,
max double precision
);
-- ST_SummaryStats result type to h3_raster_summary_stats
CREATE OR REPLACE FUNCTION __h3_raster_to_summary_stats(stats summarystats)
RETURNS h3_raster_summary_stats
AS $$
SELECT ROW(
(stats).count,
(stats).sum,
(stats).mean,
(stats).stddev,
(stats).min,
(stats).max
)::h3_raster_summary_stats
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
CREATE OR REPLACE FUNCTION __h3_raster_summary_stats_agg_transfn(
s1 h3_raster_summary_stats,
s2 h3_raster_summary_stats)
RETURNS h3_raster_summary_stats
AS $$
WITH total AS (
SELECT
(s1).count + (s2).count AS count,
(s1).sum + (s2).sum AS sum)
SELECT ROW(
t.count,
t.sum,
t.sum / t.count,
sqrt(
(
-- sum of squared values: (variance + mean squared) * count
(((s1).stddev * (s1).stddev + (s1).mean * (s1).mean)) * (s1).count
+ (((s2).stddev * (s2).stddev + (s2).mean * (s2).mean)) * (s2).count
)
/ t.count
- ((t.sum * t.sum) / (t.count * t.count)) -- mean squared
),
least((s1).min, (s2).min),
greatest((s1).max, (s2).max)
)::h3_raster_summary_stats
FROM total AS t
$$ LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE;
--@ availability: 4.1.1
CREATE AGGREGATE h3_raster_summary_stats_agg(h3_raster_summary_stats) (
sfunc = __h3_raster_summary_stats_agg_transfn,
stype = h3_raster_summary_stats,
parallel = safe
);
CREATE OR REPLACE FUNCTION __h3_raster_polygon_summary_clip(
rast raster,
poly geometry,
resolution integer,
nband integer)
RETURNS TABLE (h3 h3index, stats h3_raster_summary_stats)
AS $$
SELECT
h3,
__h3_raster_to_summary_stats(ST_SummaryStats(part, nband, TRUE)) AS stats
FROM __h3_raster_polygon_to_cell_parts(rast, poly, resolution, nband);
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
--@ availability: 4.1.1
CREATE OR REPLACE FUNCTION h3_raster_summary_clip(
rast raster,
resolution integer,
nband integer DEFAULT 1)
RETURNS TABLE (h3 h3index, stats h3_raster_summary_stats)
AS $$
SELECT __h3_raster_polygon_summary_clip(
rast,
__h3_raster_to_polygon(rast, nband),
resolution,
nband);
$$ LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION
h3_raster_summary_clip(raster, integer, integer)
IS 'Returns `h3_raster_summary_stats` for each H3 cell in raster for a given band. Clips the raster by H3 cell geometries and processes each part separately.';
--@ availability: 4.1.1
CREATE OR REPLACE FUNCTION h3_raster_summary_centroids(
rast raster,
resolution integer,
nband integer DEFAULT 1)
RETURNS TABLE (h3 h3index, stats h3_raster_summary_stats)
AS $$
SELECT
h3_lat_lng_to_cell(ST_Transform(geom, 4326), resolution) AS h3,
ROW(
count(val),
sum(val),
avg(val),
stddev_pop(val),
min(val),
max(val)
)::h3_raster_summary_stats AS stats
FROM ST_PixelAsCentroids(rast, nband)
GROUP BY 1;
$$ LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION
h3_raster_summary_centroids(raster, integer, integer)
IS 'Returns `h3_raster_summary_stats` for each H3 cell in raster for a given band. Finds corresponding H3 cell for each pixel, then groups values by H3 index.';
CREATE OR REPLACE FUNCTION __h3_raster_polygon_summary_subpixel(
rast raster,
poly geometry,
resolution integer,
nband integer,
pixels_per_cell double precision)
RETURNS TABLE (h3 h3index, stats h3_raster_summary_stats)
AS $$
SELECT
h3,
ROW(
pixels_per_cell, -- count
val, -- sum
val, -- mean
0.0, -- stddev
val, -- min
val -- max
)::h3_raster_summary_stats AS stats
FROM __h3_raster_polygon_subpixel_cell_values(rast, poly, resolution, nband) t;
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
--@ availability: 4.1.1
CREATE OR REPLACE FUNCTION h3_raster_summary_subpixel(
rast raster,
resolution integer,
nband integer DEFAULT 1)
RETURNS TABLE (h3 h3index, stats h3_raster_summary_stats)
AS $$
DECLARE
poly CONSTANT geometry := __h3_raster_to_polygon(rast, nband);
pixel_area CONSTANT double precision := __h3_raster_polygon_pixel_area(rast, poly);
cell_area CONSTANT double precision := __h3_raster_polygon_centroid_cell_area(poly, resolution);
BEGIN
RETURN QUERY SELECT (__h3_raster_polygon_summary_subpixel(
rast,
poly,
resolution,
nband,
cell_area / pixel_area)).*;
END;
$$ LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION
h3_raster_summary_subpixel(raster, integer, integer)
IS 'Returns `h3_raster_summary_stats` for each H3 cell in raster for a given band. Assumes H3 cell is smaller than a pixel. Finds corresponding pixel for each H3 cell in raster.';
--@ availability: 4.1.1
CREATE OR REPLACE FUNCTION h3_raster_summary(
rast raster,
resolution integer,
nband integer DEFAULT 1)
RETURNS TABLE (h3 h3index, stats h3_raster_summary_stats)
AS $$
DECLARE
poly CONSTANT geometry := __h3_raster_to_polygon(rast, nband);
cell_area CONSTANT double precision := __h3_raster_polygon_centroid_cell_area(poly, resolution);
pixel_area CONSTANT double precision := __h3_raster_polygon_pixel_area(rast, poly);
pixels_per_cell CONSTANT double precision := cell_area / pixel_area;
BEGIN
IF pixels_per_cell > 70
AND (ST_Area(ST_Transform(poly, 4326)::geography) / cell_area) > 10000 / (pixels_per_cell - 70)
THEN
RETURN QUERY SELECT (__h3_raster_polygon_summary_clip(
rast,
poly,
resolution,
nband
)).*;
ELSIF pixels_per_cell > 1 THEN
RETURN QUERY SELECT (h3_raster_summary_centroids(
rast,
resolution,
nband
)).*;
ELSE
RETURN QUERY SELECT (__h3_raster_polygon_summary_subpixel(
rast,
poly,
resolution,
nband,
pixels_per_cell
)).*;
END IF;
END;
$$ LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION
h3_raster_summary(raster, integer, integer)
IS 'Returns `h3_raster_summary_stats` for each H3 cell in raster for a given band. Attempts to select an appropriate method based on number of pixels per H3 cell.';
--| ## Discrete raster data
--|
--| For rasters where pixels have discrete values corresponding to different classes
--| of land cover or land use, H3 cell data summary can be represented by a JSON object
--| with separate fields for each class. First, value, number of pixels and approximate
--| area are calculated for each H3 cell and value in a raster, then the stats are
--| grouped across multiple rasters by H3 index and value, and after that stats for
--| different values in a cell are combined into a single JSON object.
--|
--| The following example query additionally calculates a fraction of H3 cell pixels
--| for each value, using a window function to get a total number of pixels:
--| ```
--| WITH
--| summary AS (
--| -- get aggregated summary for each H3 index/value pair
--| SELECT h3, val, h3_raster_class_summary_item_agg(summary) AS item
--| FROM
--| rasters,
--| h3_raster_class_summary(rast, 8)
--| GROUP BY 1, 2),
--| summary_total AS (
--| -- add total number of pixels per H3 cell
--| SELECT h3, val, item, sum((item).count) OVER (PARTITION BY h3) AS total
--| FROM summary)
--| SELECT
--| h3,
--| jsonb_object_agg(
--| concat('class_', val::text),
--| h3_raster_class_summary_item_to_jsonb(item) -- val, count, area
--| || jsonb_build_object('fraction', (item).count / total) -- add fraction value
--| ORDER BY val
--| ) AS summary
--| FROM summary_total
--| GROUP BY 1;
--|
--| h3 | summary
--| ----------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------
--| 88194e6f3bfffff | {"class_1": {"area": 75855.5748, "count": 46, "value": 1, "fraction": 0.4509}, "class_2": {"area": 92345.9171, "count": 56, "value": 2, "fraction": 0.5490}}
--| 88194e6f37fffff | {"class_1": {"area": 255600.3064, "count": 155, "value": 1, "fraction": 0.5}, "class_2": {"area": 255600.3064, "count": 155, "value": 2, "fraction": 0.5}}
--| 88194e6f33fffff | {"class_1": {"area": 336402.9840, "count": 204, "value": 1, "fraction": 0.5125}, "class_2": {"area": 319912.6416, "count": 194, "value": 2, "fraction": 0.4874}}
--| <...>
--| ```
--|
--| Area covered by pixels with the most frequent value in each cell:
--| ```
--| SELECT DISTINCT ON (h3)
--| h3, val, (item).area
--| FROM (
--| SELECT
--| h3, val, h3_raster_class_summary_item_agg(summary) AS item
--| FROM
--| rasters,
--| h3_raster_class_summary(rast, 8)
--| GROUP BY 1, 2
--| ) t
--| ORDER BY h3, (item).count DESC;
--|
--| h3 | val | area
--| -----------------+-----+--------------------
--| 88194e6f3bfffff | 5 | 23238.699360251427
--| 88194e6f37fffff | 9 | 60863.26022922993
--| 88194e6f33fffff | 8 | 76355.72646939754
--| <...>
--| ```
-- NOTE: `count` can be < 1 when cell area is less than pixel area
--@ availability: 4.1.1
CREATE TYPE h3_raster_class_summary_item AS (
val integer,
count double precision,
area double precision
);
--@ availability: 4.1.1
CREATE OR REPLACE FUNCTION h3_raster_class_summary_item_to_jsonb(
item h3_raster_class_summary_item)
RETURNS jsonb
AS $$
SELECT jsonb_build_object(
'value', (item).val,
'count', (item).count,
'area', (item).area
);
$$ LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION
h3_raster_class_summary_item_to_jsonb(h3_raster_class_summary_item)
IS 'Convert raster summary to JSONB, example: `{"count": 10, "value": 2, "area": 16490.3423}`';
CREATE OR REPLACE FUNCTION __h3_raster_class_summary_item_agg_transfn(
s1 h3_raster_class_summary_item,
s2 h3_raster_class_summary_item)
RETURNS h3_raster_class_summary_item
AS $$
SELECT
s1.val,
s1.count + s2.count,
s1.area + s2.area;
$$ LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE;
--@ availability: 4.1.1
CREATE AGGREGATE h3_raster_class_summary_item_agg(h3_raster_class_summary_item) (
stype = h3_raster_class_summary_item,
sfunc = __h3_raster_class_summary_item_agg_transfn,
parallel = safe
);
CREATE OR REPLACE FUNCTION __h3_raster_class_summary_part(
rast raster,
nband integer,
pixel_area double precision)
RETURNS SETOF h3_raster_class_summary_item
AS $$
SELECT ROW(
value::integer,
count::double precision,
count * pixel_area
)::h3_raster_class_summary_item
FROM ST_ValueCount(rast, nband) t;
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
CREATE OR REPLACE FUNCTION __h3_raster_class_polygon_summary_clip(
rast raster,
poly geometry,
resolution integer,
nband integer,
pixel_area double precision)
RETURNS TABLE (h3 h3index, val integer, summary h3_raster_class_summary_item)
AS $$
WITH
summary AS (
SELECT
h3,
__h3_raster_class_summary_part(part, nband, pixel_area) AS summary
FROM __h3_raster_polygon_to_cell_parts(rast, poly, resolution, nband) t)
SELECT h3, (summary).val, summary
FROM summary;
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
--@ availability: 4.1.1
CREATE OR REPLACE FUNCTION h3_raster_class_summary_clip(
rast raster,
resolution integer,
nband integer DEFAULT 1)
RETURNS TABLE (h3 h3index, val integer, summary h3_raster_class_summary_item)
AS $$
DECLARE
poly CONSTANT geometry := __h3_raster_to_polygon(rast, nband);
BEGIN
RETURN QUERY SELECT (__h3_raster_class_polygon_summary_clip(
rast,
poly,
resolution,
nband,
__h3_raster_polygon_pixel_area(rast, poly)
)).*;
END;
$$ LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION
h3_raster_class_summary_clip(raster, integer, integer)
IS 'Returns `h3_raster_class_summary_item` for each H3 cell and value for a given band. Clips the raster by H3 cell geometries and processes each part separately.';
CREATE OR REPLACE FUNCTION __h3_raster_class_summary_centroids(
rast raster,
resolution integer,
nband integer,
pixel_area double precision)
RETURNS TABLE (h3 h3index, val integer, summary h3_raster_class_summary_item)
AS $$
SELECT
h3_lat_lng_to_cell(ST_Transform(geom, 4326), resolution) AS h3,
val::integer AS val,
ROW(
val::integer,
count(*)::double precision,
count(*) * pixel_area
)::h3_raster_class_summary_item AS summary
FROM ST_PixelAsCentroids(rast, nband)
GROUP BY 1, 2;
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
--@ availability: 4.1.1
CREATE OR REPLACE FUNCTION h3_raster_class_summary_centroids(
rast raster,
resolution integer,
nband integer DEFAULT 1)
RETURNS TABLE (h3 h3index, val integer, summary h3_raster_class_summary_item)
AS $$
SELECT __h3_raster_class_summary_centroids(
rast,
resolution,
nband,
__h3_raster_polygon_pixel_area(rast, __h3_raster_to_polygon(rast, nband))
);
$$ LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION
h3_raster_class_summary_centroids(raster, integer, integer)
IS 'Returns `h3_raster_class_summary_item` for each H3 cell and value for a given band. Finds corresponding H3 cell for each pixel, then groups by H3 and value.';
CREATE OR REPLACE FUNCTION __h3_raster_class_polygon_summary_subpixel(
rast raster,
poly geometry,
resolution integer,
nband integer,
cell_area double precision,
pixel_area double precision)
RETURNS TABLE (h3 h3index, val integer, summary h3_raster_class_summary_item)
AS $$
SELECT
h3,
val::integer AS val,
ROW(
val::integer,
cell_area / pixel_area,
cell_area
)::h3_raster_class_summary_item AS summary
FROM __h3_raster_polygon_subpixel_cell_values(rast, poly, resolution, nband);
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
--@ availability: 4.1.1
CREATE OR REPLACE FUNCTION h3_raster_class_summary_subpixel(
rast raster,
resolution integer,
nband integer DEFAULT 1)
RETURNS TABLE (h3 h3index, val integer, summary h3_raster_class_summary_item)
AS $$
DECLARE
poly CONSTANT geometry := __h3_raster_to_polygon(rast, nband);
BEGIN
RETURN QUERY SELECT (__h3_raster_class_polygon_summary_subpixel(
rast,
poly,
resolution,
nband,
__h3_raster_polygon_centroid_cell_area(poly, resolution),
__h3_raster_polygon_pixel_area(rast, poly)
)).*;
END;
$$ LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION
h3_raster_class_summary_subpixel(raster, integer, integer)
IS 'Returns `h3_raster_class_summary_item` for each H3 cell and value for a given band. Assumes H3 cell is smaller than a pixel. Finds corresponding pixel for each H3 cell in raster.';
--@ availability: 4.1.1
CREATE OR REPLACE FUNCTION h3_raster_class_summary(
rast raster,
resolution integer,
nband integer DEFAULT 1)
RETURNS TABLE (h3 h3index, val integer, summary h3_raster_class_summary_item)
AS $$
DECLARE
poly CONSTANT geometry := __h3_raster_to_polygon(rast, nband);
cell_area CONSTANT double precision := __h3_raster_polygon_centroid_cell_area(poly, resolution);
pixel_area CONSTANT double precision := __h3_raster_polygon_pixel_area(rast, poly);
pixels_per_cell CONSTANT double precision := cell_area / pixel_area;
BEGIN
IF pixels_per_cell > 70
AND (ST_Area(ST_Transform(poly, 4326)::geography) / cell_area) > 10000 / (pixels_per_cell - 70)
THEN
RETURN QUERY SELECT (__h3_raster_class_polygon_summary_clip(
rast,
poly,
resolution,
nband,
pixel_area
)).*;
ELSIF pixels_per_cell > 1 THEN
RETURN QUERY SELECT (__h3_raster_class_summary_centroids(
rast,
resolution,
nband,
pixel_area
)).*;
ELSE
RETURN QUERY SELECT (__h3_raster_class_polygon_summary_subpixel(
rast,
poly,
resolution,
nband,
cell_area,
pixel_area
)).*;
END IF;
END;
$$ LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION h3_raster_class_summary(raster, integer, integer)
IS 'Returns `h3_raster_class_summary_item` for each H3 cell and value for a given band. Attempts to select an appropriate method based on number of pixels per H3 cell.';
h3-pg-4.1.3/h3_postgis/sql/install/99-deprecated.sql 0000664 0000000 0000000 00000002226 14460144644 0022055 0 ustar 00root root 0000000 0000000 /*
* 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.
*/
--@ availability: 4.0.0
--@ deprecated
CREATE OR REPLACE FUNCTION h3_cell_to_boundary_geometry(h3index, extend_antimeridian boolean) RETURNS geometry
AS $$ SELECT ST_SetSRID(h3_cell_to_boundary($1, extend_antimeridian)::geometry, 4326) $$ IMMUTABLE STRICT PARALLEL SAFE LANGUAGE SQL;
--@ availability: 4.0.0
--@ deprecated
CREATE OR REPLACE FUNCTION h3_cell_to_boundary_geography(h3index, extend_antimeridian boolean) RETURNS geography
AS $$ SELECT ST_SetSRID(h3_cell_to_boundary($1, extend_antimeridian)::geometry, 4326) $$ IMMUTABLE STRICT PARALLEL SAFE LANGUAGE SQL;
h3-pg-4.1.3/h3_postgis/sql/updates/ 0000775 0000000 0000000 00000000000 14460144644 0016772 5 ustar 00root root 0000000 0000000 h3-pg-4.1.3/h3_postgis/sql/updates/h3_postgis--4.0.0--4.0.1.sql 0000664 0000000 0000000 00000005005 14460144644 0023022 0 ustar 00root root 0000000 0000000 /*
* 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.
*/
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "ALTER EXTENSION h3_postgis UPDATE TO '4.0.1'" to load this file. \quit
-- deprecated
DROP FUNCTION IF EXISTS h3_cell_to_boundary_geometry(h3index, boolean);
CREATE OR REPLACE FUNCTION h3_cell_to_boundary_geometry(h3index, extend_antimeridian boolean) RETURNS geometry
AS $$ SELECT ST_SetSRID(h3_cell_to_boundary($1, extend_antimeridian)::geometry, 4326) $$ IMMUTABLE STRICT PARALLEL SAFE LANGUAGE SQL;
DROP FUNCTION IF EXISTS h3_cell_to_boundary_geography(h3index, boolean);
CREATE OR REPLACE FUNCTION h3_cell_to_boundary_geography(h3index, extend_antimeridian boolean) RETURNS geography
AS $$ SELECT ST_SetSRID(h3_cell_to_boundary($1, extend_antimeridian)::geometry, 4326) $$ IMMUTABLE STRICT PARALLEL SAFE LANGUAGE SQL;
-- new splitted version
CREATE OR REPLACE FUNCTION h3_cell_to_boundary_geometry(h3index) RETURNS geometry
AS $$ SELECT h3_cell_to_boundary_wkb($1)::geometry $$ IMMUTABLE STRICT PARALLEL SAFE LANGUAGE SQL;
CREATE OR REPLACE FUNCTION h3_cell_to_boundary_geography(h3index) RETURNS geography
AS $$ SELECT h3_cell_to_boundary_wkb($1)::geography $$ IMMUTABLE STRICT PARALLEL SAFE LANGUAGE SQL;
-- comments
COMMENT ON FUNCTION
h3_lat_lng_to_cell(geometry, resolution integer)
IS 'Indexes the location at the specified resolution.';
COMMENT ON FUNCTION
h3_lat_lng_to_cell(geometry, resolution integer)
IS 'Indexes the location at the specified resolution.';
COMMENT ON FUNCTION
h3_cell_to_geometry(h3index)
IS 'Finds the centroid of the index.';
COMMENT ON FUNCTION
h3_cell_to_geography(h3index)
IS 'Finds the centroid of the index.';
COMMENT ON FUNCTION
h3_cell_to_boundary_geometry(h3index)
IS 'Finds the boundary of the index.
Splits polygons when crossing 180th meridian.';
COMMENT ON FUNCTION
h3_cell_to_boundary_geography(h3index)
IS 'Finds the boundary of the index.
Splits polygons when crossing 180th meridian.';
h3-pg-4.1.3/h3_postgis/sql/updates/h3_postgis--4.0.0.sql 0000664 0000000 0000000 00000006274 14460144644 0022320 0 ustar 00root root 0000000 0000000 /*
* 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 "CREATE EXTENSION h3_postgis" to load this file. \quit
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;
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;
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;
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;
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;
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;
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
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
CREATE CAST (h3index AS geometry) WITH FUNCTION h3_cell_to_geometry(h3index);
CREATE CAST (h3index AS geography) WITH FUNCTION h3_cell_to_geography(h3index);
h3-pg-4.1.3/h3_postgis/sql/updates/h3_postgis--4.0.1--4.0.2.sql 0000664 0000000 0000000 00000001403 14460144644 0023022 0 ustar 00root root 0000000 0000000 /*
* 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_postgis UPDATE TO '4.0.2'" to load this file. \quit
-- no changes
h3-pg-4.1.3/h3_postgis/sql/updates/h3_postgis--4.0.2--4.0.3.sql 0000664 0000000 0000000 00000005674 14460144644 0023042 0 ustar 00root root 0000000 0000000 /*
* 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_postgis UPDATE TO '4.0.3'" to load this file. \quit
CREATE OR REPLACE FUNCTION
h3_cells_to_multi_polygon_geometry(h3index[]) RETURNS geometry
AS $$ SELECT h3_cells_to_multi_polygon_wkb($1)::geometry $$ IMMUTABLE STRICT PARALLEL SAFE LANGUAGE SQL;
CREATE OR REPLACE FUNCTION
h3_cells_to_multi_polygon_geography(h3index[]) RETURNS geography
AS $$ SELECT h3_cells_to_multi_polygon_wkb($1)::geography $$ IMMUTABLE STRICT PARALLEL SAFE LANGUAGE SQL;
CREATE AGGREGATE h3_cells_to_multi_polygon_geometry(h3index) (
sfunc = array_append,
stype = h3index[],
finalfunc = h3_cells_to_multi_polygon_geometry,
parallel = safe
);
CREATE AGGREGATE h3_cells_to_multi_polygon_geography(h3index) (
sfunc = array_append,
stype = h3index[],
finalfunc = h3_cells_to_multi_polygon_geography,
parallel = safe
);
CREATE OR REPLACE FUNCTION
h3_grid_path_cells_recursive(origin h3index, destination h3index) RETURNS SETOF h3index
AS $$
BEGIN
IF (SELECT
origin != destination
AND NOT h3_are_neighbor_cells(origin, destination)
AND ((base1 != base2 AND NOT h3_are_neighbor_cells(base1, base2))
OR ((h3_is_pentagon(base1) OR h3_is_pentagon(base2))
AND NOT (
h3_get_icosahedron_faces(origin)
&& h3_get_icosahedron_faces(destination))))
FROM (
SELECT
h3_cell_to_parent(origin, 0) AS base1,
h3_cell_to_parent(destination, 0) AS base2) AS t)
THEN
RETURN QUERY WITH
points AS (
SELECT
h3_cell_to_geometry(origin) AS g1,
h3_cell_to_geometry(destination) AS g2),
cells AS (
SELECT
h3_lat_lng_to_cell(
ST_Centroid(ST_MakeLine(g1, g2)::geography),
h3_get_resolution(origin)) AS middle
FROM points)
SELECT h3_grid_path_cells_recursive(origin, middle) FROM cells
UNION
SELECT h3_grid_path_cells_recursive(middle, destination) FROM cells;
ELSE
RETURN QUERY SELECT h3_grid_path_cells(origin, destination);
END IF;
END;
$$ LANGUAGE 'plpgsql' IMMUTABLE STRICT PARALLEL SAFE;
h3-pg-4.1.3/h3_postgis/sql/updates/h3_postgis--4.0.3--4.1.0.sql 0000664 0000000 0000000 00000001371 14460144644 0023027 0 ustar 00root root 0000000 0000000 /*
* Copyright 2022-2023 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_postgis UPDATE TO '4.1.0'" to load this file. \quit
h3-pg-4.1.3/h3_postgis/sql/updates/h3_postgis--4.1.0--4.1.1.sql 0000664 0000000 0000000 00000047572 14460144644 0023043 0 ustar 00root root 0000000 0000000 /*
* Copyright 2023 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_postgis UPDATE TO '4.1.1'" to load this file. \quit
-- raster
CREATE OR REPLACE FUNCTION
h3_cell_to_boundary_wkb(cell h3index) RETURNS bytea
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION
h3_cell_to_boundary_wkb(h3index)
IS 'Finds the boundary of the index, converts to EWKB.
Splits polygons when crossing 180th meridian.
This function has to return WKB since Postgres does not provide multipolygon type.';
CREATE OR REPLACE FUNCTION
h3_cells_to_multi_polygon_wkb(h3index[]) RETURNS bytea
AS 'h3' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION
h3_cells_to_multi_polygon_wkb(h3index[])
IS 'Create a LinkedGeoPolygon describing the outline(s) of a set of hexagons, converts to EWKB.
Splits polygons when crossing 180th meridian.';
-- Raster processing
CREATE OR REPLACE FUNCTION __h3_raster_band_nodata(
rast raster,
nband integer)
RETURNS double precision
AS $$
SELECT coalesce(
ST_BandNoDataValue(rast, nband),
ST_MinPossibleValue(ST_BandPixelType(rast, nband)));
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
CREATE OR REPLACE FUNCTION __h3_raster_to_polygon(
rast raster,
nband integer)
RETURNS geometry
AS $$
SELECT ST_MinConvexHull(rast, nband);
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
CREATE OR REPLACE FUNCTION __h3_raster_polygon_pixel_area(
rast raster,
poly geometry)
RETURNS double precision
AS $$
SELECT ST_Area(
ST_Transform(
ST_PixelAsPolygon(
rast,
ST_WorldToRasterCoordX(rast, c),
ST_WorldToRasterCoordY(rast, c)),
4326)::geography)
FROM ST_Centroid(poly) AS c
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
CREATE OR REPLACE FUNCTION __h3_raster_polygon_centroid_cell(
poly geometry,
resolution integer)
RETURNS h3index
AS $$
DECLARE
cell h3index := h3_lat_lng_to_cell(ST_Transform(ST_Centroid(poly), 4326), resolution);
BEGIN
IF h3_is_pentagon(cell) THEN
SELECT h3 INTO cell FROM h3_grid_disk(cell) AS h3 WHERE h3 != cell LIMIT 1;
END IF;
RETURN cell;
END;
$$ LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
CREATE OR REPLACE FUNCTION __h3_raster_polygon_centroid_cell_area(
poly geometry,
resolution integer)
RETURNS double precision
AS $$
SELECT ST_Area(
h3_cell_to_boundary_geography(
__h3_raster_polygon_centroid_cell(poly, resolution)));
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
CREATE OR REPLACE FUNCTION __h3_raster_polygon_to_cells(
rast raster,
poly geometry,
resolution integer,
buffer double precision)
RETURNS SETOF h3index
AS $$
DECLARE
buffered geometry := poly;
BEGIN
IF ST_SRID(rast) != 4326 THEN
buffered := ST_Transform(
ST_Buffer(
poly,
greatest(ST_PixelWidth(rast), ST_PixelHeight(rast)),
'join=mitre'),
4326);
END IF;
IF buffer > 0.0 THEN
RETURN QUERY
SELECT h3_polygon_to_cells(
ST_Buffer(
buffered::geography,
buffer,
'join=mitre'),
resolution);
ELSE
RETURN QUERY
SELECT h3_polygon_to_cells(buffered, resolution);
END IF;
END
$$ LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
CREATE OR REPLACE FUNCTION __h3_raster_polygon_to_cell_boundaries_intersects(
rast raster,
poly geometry,
resolution integer)
RETURNS TABLE (h3 h3index, geom geometry)
AS $$
SELECT h3, geom
FROM
__h3_raster_polygon_to_cells(
rast,
poly,
resolution,
h3_get_hexagon_edge_length_avg(resolution, 'm') * 1.3
) AS h3,
ST_Transform(h3_cell_to_boundary_geometry(h3), ST_SRID(rast)) AS geom
WHERE ST_Intersects(geom, poly);
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
CREATE OR REPLACE FUNCTION __h3_raster_polygon_to_cell_coords_centroid(
rast raster,
poly geometry,
resolution integer)
RETURNS TABLE (h3 h3index, x integer, y integer)
AS $$
WITH
geoms AS (
SELECT
h3,
ST_Transform(
h3_cell_to_geometry(h3),
ST_SRID(poly)
) AS geom
FROM (
SELECT __h3_raster_polygon_to_cells(rast, poly, resolution, 0.0) AS h3
) t),
coords AS (
SELECT
h3,
ST_WorldToRasterCoordX(rast, geom) AS x,
ST_WorldToRasterCoordY(rast, geom) AS y
FROM geoms)
SELECT h3, x, y
FROM coords
WHERE
x BETWEEN 1 AND ST_Width(rast)
AND y BETWEEN 1 AND ST_Height(rast);
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
CREATE OR REPLACE FUNCTION __h3_raster_polygon_to_cell_parts(
rast raster,
poly geometry,
resolution integer,
nband integer)
RETURNS TABLE (h3 h3index, part raster)
AS $$
DECLARE
nodata CONSTANT double precision := __h3_raster_band_nodata(rast, nband);
BEGIN
RETURN QUERY
SELECT c.h3, p AS part
FROM
__h3_raster_polygon_to_cell_boundaries_intersects(rast, poly, resolution) AS c,
ST_Clip(rast, nband, c.geom, nodata, TRUE) AS p
WHERE NOT ST_BandIsNoData(p, nband);
END;
$$ LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
CREATE OR REPLACE FUNCTION __h3_raster_polygon_subpixel_cell_values(
rast raster,
poly geometry,
resolution integer,
nband integer)
RETURNS TABLE (h3 h3index, val double precision)
AS $$
SELECT
h3,
ST_Value(rast, nband, x, y) AS val
FROM __h3_raster_polygon_to_cell_coords_centroid(rast, poly, resolution);
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
-- Raster processing: continuous data
CREATE TYPE h3_raster_summary_stats AS (
count double precision,
sum double precision,
mean double precision,
stddev double precision,
min double precision,
max double precision
);
CREATE OR REPLACE FUNCTION __h3_raster_to_summary_stats(stats summarystats)
RETURNS h3_raster_summary_stats
AS $$
SELECT ROW(
(stats).count,
(stats).sum,
(stats).mean,
(stats).stddev,
(stats).min,
(stats).max
)::h3_raster_summary_stats
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
CREATE OR REPLACE FUNCTION __h3_raster_summary_stats_agg_transfn(
s1 h3_raster_summary_stats,
s2 h3_raster_summary_stats)
RETURNS h3_raster_summary_stats
AS $$
WITH total AS (
SELECT
(s1).count + (s2).count AS count,
(s1).sum + (s2).sum AS sum)
SELECT ROW(
t.count,
t.sum,
t.sum / t.count,
sqrt(
(
-- sum of squared values: (variance + mean squared) * count
(((s1).stddev * (s1).stddev + (s1).mean * (s1).mean)) * (s1).count
+ (((s2).stddev * (s2).stddev + (s2).mean * (s2).mean)) * (s2).count
)
/ t.count
- ((t.sum * t.sum) / (t.count * t.count)) -- mean squared
),
least((s1).min, (s2).min),
greatest((s1).max, (s2).max)
)::h3_raster_summary_stats
FROM total AS t
$$ LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE;
CREATE AGGREGATE h3_raster_summary_stats_agg(h3_raster_summary_stats) (
sfunc = __h3_raster_summary_stats_agg_transfn,
stype = h3_raster_summary_stats,
parallel = safe
);
CREATE OR REPLACE FUNCTION __h3_raster_polygon_summary_clip(
rast raster,
poly geometry,
resolution integer,
nband integer)
RETURNS TABLE (h3 h3index, stats h3_raster_summary_stats)
AS $$
SELECT
h3,
__h3_raster_to_summary_stats(ST_SummaryStats(part, nband, TRUE)) AS stats
FROM __h3_raster_polygon_to_cell_parts(rast, poly, resolution, nband);
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
CREATE OR REPLACE FUNCTION h3_raster_summary_clip(
rast raster,
resolution integer,
nband integer DEFAULT 1)
RETURNS TABLE (h3 h3index, stats h3_raster_summary_stats)
AS $$
SELECT __h3_raster_polygon_summary_clip(
rast,
__h3_raster_to_polygon(rast, nband),
resolution,
nband);
$$ LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION
h3_raster_summary_clip(raster, integer, integer)
IS 'Returns `h3_raster_summary_stats` for each H3 cell in raster for a given band. Clips the raster by H3 cell geometries and processes each part separately.';
CREATE OR REPLACE FUNCTION h3_raster_summary_centroids(
rast raster,
resolution integer,
nband integer DEFAULT 1)
RETURNS TABLE (h3 h3index, stats h3_raster_summary_stats)
AS $$
SELECT
h3_lat_lng_to_cell(ST_Transform(geom, 4326), resolution) AS h3,
ROW(
count(val),
sum(val),
avg(val),
stddev_pop(val),
min(val),
max(val)
)::h3_raster_summary_stats AS stats
FROM ST_PixelAsCentroids(rast, nband)
GROUP BY 1;
$$ LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION
h3_raster_summary_centroids(raster, integer, integer)
IS 'Returns `h3_raster_summary_stats` for each H3 cell in raster for a given band. Finds corresponding H3 cell for each pixel, then groups values by H3 index.';
CREATE OR REPLACE FUNCTION __h3_raster_polygon_summary_subpixel(
rast raster,
poly geometry,
resolution integer,
nband integer,
pixels_per_cell double precision)
RETURNS TABLE (h3 h3index, stats h3_raster_summary_stats)
AS $$
SELECT
h3,
ROW(
pixels_per_cell, -- count
val, -- sum
val, -- mean
0.0, -- stddev
val, -- min
val -- max
)::h3_raster_summary_stats AS stats
FROM __h3_raster_polygon_subpixel_cell_values(rast, poly, resolution, nband) t;
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
CREATE OR REPLACE FUNCTION h3_raster_summary_subpixel(
rast raster,
resolution integer,
nband integer DEFAULT 1)
RETURNS TABLE (h3 h3index, stats h3_raster_summary_stats)
AS $$
DECLARE
poly CONSTANT geometry := __h3_raster_to_polygon(rast, nband);
pixel_area CONSTANT double precision := __h3_raster_polygon_pixel_area(rast, poly);
cell_area CONSTANT double precision := __h3_raster_polygon_centroid_cell_area(poly, resolution);
BEGIN
RETURN QUERY SELECT (__h3_raster_polygon_summary_subpixel(
rast,
poly,
resolution,
nband,
cell_area / pixel_area)).*;
END;
$$ LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION
h3_raster_summary_subpixel(raster, integer, integer)
IS 'Returns `h3_raster_summary_stats` for each H3 cell in raster for a given band. Assumes H3 cell is smaller than a pixel. Finds corresponding pixel for each H3 cell in raster.';
CREATE OR REPLACE FUNCTION h3_raster_summary(
rast raster,
resolution integer,
nband integer DEFAULT 1)
RETURNS TABLE (h3 h3index, stats h3_raster_summary_stats)
AS $$
DECLARE
poly CONSTANT geometry := __h3_raster_to_polygon(rast, nband);
cell_area CONSTANT double precision := __h3_raster_polygon_centroid_cell_area(poly, resolution);
pixel_area CONSTANT double precision := __h3_raster_polygon_pixel_area(rast, poly);
pixels_per_cell CONSTANT double precision := cell_area / pixel_area;
BEGIN
IF pixels_per_cell > 70
AND (ST_Area(ST_Transform(poly, 4326)::geography) / cell_area) > 10000 / (pixels_per_cell - 70)
THEN
RETURN QUERY SELECT (__h3_raster_polygon_summary_clip(
rast,
poly,
resolution,
nband
)).*;
ELSIF pixels_per_cell > 1 THEN
RETURN QUERY SELECT (h3_raster_summary_centroids(
rast,
resolution,
nband
)).*;
ELSE
RETURN QUERY SELECT (__h3_raster_polygon_summary_subpixel(
rast,
poly,
resolution,
nband,
pixels_per_cell
)).*;
END IF;
END;
$$ LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION
h3_raster_summary(raster, integer, integer)
IS 'Returns `h3_raster_summary_stats` for each H3 cell in raster for a given band. Attempts to select an appropriate method based on number of pixels per H3 cell.';
-- Raster processing: discrete data
CREATE TYPE h3_raster_class_summary_item AS (
val integer,
count double precision,
area double precision
);
CREATE OR REPLACE FUNCTION h3_raster_class_summary_item_to_jsonb(
item h3_raster_class_summary_item)
RETURNS jsonb
AS $$
SELECT jsonb_build_object(
'value', (item).val,
'count', (item).count,
'area', (item).area
);
$$ LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION
h3_raster_class_summary_item_to_jsonb(h3_raster_class_summary_item)
IS 'Convert raster summary to JSONB, example: `{"count": 10, "value": 2, "area": 16490.3423}`';
CREATE OR REPLACE FUNCTION __h3_raster_class_summary_item_agg_transfn(
s1 h3_raster_class_summary_item,
s2 h3_raster_class_summary_item)
RETURNS h3_raster_class_summary_item
AS $$
SELECT
s1.val,
s1.count + s2.count,
s1.area + s2.area;
$$ LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE;
CREATE AGGREGATE h3_raster_class_summary_item_agg(h3_raster_class_summary_item) (
stype = h3_raster_class_summary_item,
sfunc = __h3_raster_class_summary_item_agg_transfn,
parallel = safe
);
CREATE OR REPLACE FUNCTION __h3_raster_class_summary_part(
rast raster,
nband integer,
pixel_area double precision)
RETURNS SETOF h3_raster_class_summary_item
AS $$
SELECT ROW(
value::integer,
count::double precision,
count * pixel_area
)::h3_raster_class_summary_item
FROM ST_ValueCount(rast, nband) t;
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
CREATE OR REPLACE FUNCTION __h3_raster_class_polygon_summary_clip(
rast raster,
poly geometry,
resolution integer,
nband integer,
pixel_area double precision)
RETURNS TABLE (h3 h3index, val integer, summary h3_raster_class_summary_item)
AS $$
WITH
summary AS (
SELECT
h3,
__h3_raster_class_summary_part(part, nband, pixel_area) AS summary
FROM __h3_raster_polygon_to_cell_parts(rast, poly, resolution, nband) t)
SELECT h3, (summary).val, summary
FROM summary;
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
CREATE OR REPLACE FUNCTION h3_raster_class_summary_clip(
rast raster,
resolution integer,
nband integer DEFAULT 1)
RETURNS TABLE (h3 h3index, val integer, summary h3_raster_class_summary_item)
AS $$
DECLARE
poly CONSTANT geometry := __h3_raster_to_polygon(rast, nband);
BEGIN
RETURN QUERY SELECT (__h3_raster_class_polygon_summary_clip(
rast,
poly,
resolution,
nband,
__h3_raster_polygon_pixel_area(rast, poly)
)).*;
END;
$$ LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION
h3_raster_class_summary_clip(raster, integer, integer)
IS 'Returns `h3_raster_class_summary_item` for each H3 cell and value for a given band. Clips the raster by H3 cell geometries and processes each part separately.';
CREATE OR REPLACE FUNCTION __h3_raster_class_summary_centroids(
rast raster,
resolution integer,
nband integer,
pixel_area double precision)
RETURNS TABLE (h3 h3index, val integer, summary h3_raster_class_summary_item)
AS $$
SELECT
h3_lat_lng_to_cell(ST_Transform(geom, 4326), resolution) AS h3,
val::integer AS val,
ROW(
val::integer,
count(*)::double precision,
count(*) * pixel_area
)::h3_raster_class_summary_item AS summary
FROM ST_PixelAsCentroids(rast, nband)
GROUP BY 1, 2;
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
CREATE OR REPLACE FUNCTION h3_raster_class_summary_centroids(
rast raster,
resolution integer,
nband integer DEFAULT 1)
RETURNS TABLE (h3 h3index, val integer, summary h3_raster_class_summary_item)
AS $$
SELECT __h3_raster_class_summary_centroids(
rast,
resolution,
nband,
__h3_raster_polygon_pixel_area(rast, __h3_raster_to_polygon(rast, nband))
);
$$ LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION
h3_raster_class_summary_centroids(raster, integer, integer)
IS 'Returns `h3_raster_class_summary_item` for each H3 cell and value for a given band. Finds corresponding H3 cell for each pixel, then groups by H3 and value.';
CREATE OR REPLACE FUNCTION __h3_raster_class_polygon_summary_subpixel(
rast raster,
poly geometry,
resolution integer,
nband integer,
cell_area double precision,
pixel_area double precision)
RETURNS TABLE (h3 h3index, val integer, summary h3_raster_class_summary_item)
AS $$
SELECT
h3,
val::integer AS val,
ROW(
val::integer,
cell_area / pixel_area,
cell_area
)::h3_raster_class_summary_item AS summary
FROM __h3_raster_polygon_subpixel_cell_values(rast, poly, resolution, nband);
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
CREATE OR REPLACE FUNCTION h3_raster_class_summary_subpixel(
rast raster,
resolution integer,
nband integer DEFAULT 1)
RETURNS TABLE (h3 h3index, val integer, summary h3_raster_class_summary_item)
AS $$
DECLARE
poly CONSTANT geometry := __h3_raster_to_polygon(rast, nband);
BEGIN
RETURN QUERY SELECT (__h3_raster_class_polygon_summary_subpixel(
rast,
poly,
resolution,
nband,
__h3_raster_polygon_centroid_cell_area(poly, resolution),
__h3_raster_polygon_pixel_area(rast, poly)
)).*;
END;
$$ LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION
h3_raster_class_summary_subpixel(raster, integer, integer)
IS 'Returns `h3_raster_class_summary_item` for each H3 cell and value for a given band. Assumes H3 cell is smaller than a pixel. Finds corresponding pixel for each H3 cell in raster.';
CREATE OR REPLACE FUNCTION h3_raster_class_summary(
rast raster,
resolution integer,
nband integer DEFAULT 1)
RETURNS TABLE (h3 h3index, val integer, summary h3_raster_class_summary_item)
AS $$
DECLARE
poly CONSTANT geometry := __h3_raster_to_polygon(rast, nband);
cell_area CONSTANT double precision := __h3_raster_polygon_centroid_cell_area(poly, resolution);
pixel_area CONSTANT double precision := __h3_raster_polygon_pixel_area(rast, poly);
pixels_per_cell CONSTANT double precision := cell_area / pixel_area;
BEGIN
IF pixels_per_cell > 70
AND (ST_Area(ST_Transform(poly, 4326)::geography) / cell_area) > 10000 / (pixels_per_cell - 70)
THEN
RETURN QUERY SELECT (__h3_raster_class_polygon_summary_clip(
rast,
poly,
resolution,
nband,
pixel_area
)).*;
ELSIF pixels_per_cell > 1 THEN
RETURN QUERY SELECT (__h3_raster_class_summary_centroids(
rast,
resolution,
nband,
pixel_area
)).*;
ELSE
RETURN QUERY SELECT (__h3_raster_class_polygon_summary_subpixel(
rast,
poly,
resolution,
nband,
cell_area,
pixel_area
)).*;
END IF;
END;
$$ LANGUAGE plpgsql IMMUTABLE STRICT PARALLEL SAFE;
COMMENT ON FUNCTION h3_raster_class_summary(raster, integer, integer)
IS 'Returns `h3_raster_class_summary_item` for each H3 cell and value for a given band. Attempts to select an appropriate method based on number of pixels per H3 cell.';
h3-pg-4.1.3/h3_postgis/sql/updates/h3_postgis--4.1.1--4.1.2.sql 0000664 0000000 0000000 00000002772 14460144644 0023036 0 ustar 00root root 0000000 0000000 /*
* Copyright 2023 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_postgis UPDATE TO '4.1.2'" to load this file. \quit
-- fix wrong shared lib #117
CREATE OR REPLACE FUNCTION
h3_cell_to_boundary_wkb(cell h3index) RETURNS bytea
AS 'h3_postgis' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION
h3_cell_to_boundary_wkb(h3index)
IS 'Finds the boundary of the index, converts to EWKB.
Splits polygons when crossing 180th meridian.
This function has to return WKB since Postgres does not provide multipolygon type.';
CREATE OR REPLACE FUNCTION
h3_cells_to_multi_polygon_wkb(h3index[]) RETURNS bytea
AS 'h3_postgis' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE; COMMENT ON FUNCTION
h3_cells_to_multi_polygon_wkb(h3index[])
IS 'Create a LinkedGeoPolygon describing the outline(s) of a set of hexagons, converts to EWKB.
Splits polygons when crossing 180th meridian.';
h3-pg-4.1.3/h3_postgis/sql/updates/h3_postgis--4.1.2--4.1.3.sql 0000664 0000000 0000000 00000002242 14460144644 0023030 0 ustar 00root root 0000000 0000000 /*
* Copyright 2023 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.1.3'" to load this file. \quit
--@ availability: 4.1.3
CREATE OPERATOR @ (
PROCEDURE = h3_lat_lng_to_cell,
LEFTARG = geometry, RIGHTARG = integer
);
COMMENT ON OPERATOR @ (geometry, integer) IS
'Index geometry at specified resolution.';
--@ availability: 4.1.3
CREATE OPERATOR @ (
PROCEDURE = h3_lat_lng_to_cell,
LEFTARG = geography, RIGHTARG = integer
);
COMMENT ON OPERATOR @ (geography, integer) IS
'Index geography at specified resolution.';
h3-pg-4.1.3/h3_postgis/src/ 0000775 0000000 0000000 00000000000 14460144644 0015315 5 ustar 00root root 0000000 0000000 h3-pg-4.1.3/h3_postgis/src/init.c 0000664 0000000 0000000 00000001363 14460144644 0016427 0 ustar 00root root 0000000 0000000 /*
* Copyright 2023 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
#include // PG_MODULE_MAGIC
/* see https://www.postgresql.org/docs/current/xfunc-c.html#XFUNC-C-DYNLOAD */
PG_MODULE_MAGIC;
h3-pg-4.1.3/h3_postgis/src/wkb.c 0000664 0000000 0000000 00000021040 14460144644 0016241 0 ustar 00root root 0000000 0000000 /*
* Copyright 2022-2023 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
#include
#include "error.h"
#include "wkb.h"
#include "wkb_linked_geo.h"
#define WKB_BYTE_SIZE 1
#define WKB_INT_SIZE 4
#define WKB_DOUBLE_SIZE 8
#define WKB_NDR 1
#define WKB_XDR 0
#define WKB_POLYGON_TYPE 3
#define WKB_MULTIPOLYGON_TYPE 6
#define WKB_SRID_FLAG 0x20000000
#define WKB_SRID_DEFAULT 4326
#define ASSERT_WKB_DATA_WRITTEN(wkb, data) \
ASSERT( \
(uint8 *)wkb + VARSIZE(wkb) == data, \
ERRCODE_EXTERNAL_ROUTINE_EXCEPTION, \
"# of written bytes (%d) must match allocation size (%d)", \
(int)(data - (uint8 *)wkb), VARSIZE(wkb))
static bool
boundary_is_empty(const CellBoundary * boundary);
static bool
boundary_is_closed(const CellBoundary * boundary);
static size_t
boundary_array_data_size(const CellBoundary * boundaries, int num);
static size_t
boundary_data_size(const CellBoundary * boundary);
static size_t
linked_geo_polygon_data_size(const LinkedGeoPolygon * multiPolygon);
static size_t
linked_geo_loop_data_size(const LinkedGeoLoop * loop);
static uint8 *
wkb_write_boundary_array_data(uint8 *data, const CellBoundary * boundaries, int num);
static uint8 *
wkb_write_boundary_data(uint8 *data, const CellBoundary * boundary);
static uint8 *
wkb_write_linked_geo_polygon_data(uint8 *data, const LinkedGeoPolygon * multiPolygon);
static uint8 *
wkb_write_lat_lng_array(uint8 *data, const LatLng * coord, int num);
static uint8 *
wkb_write_linked_geo_loop_data(uint8 *data, const LinkedGeoLoop * loop);
static uint8 *
wkb_write_lat_lng(uint8 *data, const LatLng * coord);
static uint8 *
wkb_write_endian(uint8 *data);
static uint8 *
wkb_write_int(uint8 *data, uint32 value);
static uint8 *
wkb_write(uint8 *data, const void *value, size_t size);
bytea *
boundary_array_to_wkb(const CellBoundary * boundaries, size_t num)
{
uint8 *data;
bytea *wkb;
size_t size = boundary_array_data_size(boundaries, num);
wkb = palloc(VARHDRSZ + size);
SET_VARSIZE(wkb, VARHDRSZ + size);
data = (uint8 *) VARDATA(wkb);
data = wkb_write_boundary_array_data(data, boundaries, num);
ASSERT_WKB_DATA_WRITTEN(wkb, data);
return wkb;
}
bytea *
boundary_to_wkb(const CellBoundary * boundary)
{
bytea *wkb;
uint8 *data;
size_t size = boundary_data_size(boundary);
wkb = palloc(VARHDRSZ + size);
SET_VARSIZE(wkb, VARHDRSZ + size);
data = (uint8 *) VARDATA(wkb);
data = wkb_write_boundary_data(data, boundary);
ASSERT_WKB_DATA_WRITTEN(wkb, data);
return wkb;
}
bytea *
linked_geo_polygon_to_wkb(const LinkedGeoPolygon * multiPolygon)
{
bytea *wkb;
uint8 *data;
size_t size = linked_geo_polygon_data_size(multiPolygon);
wkb = palloc(VARHDRSZ + size);
SET_VARSIZE(wkb, VARHDRSZ + size);
data = (uint8 *) VARDATA(wkb);
data = wkb_write_linked_geo_polygon_data(data, multiPolygon);
ASSERT_WKB_DATA_WRITTEN(wkb, data);
return wkb;
}
bool
boundary_is_empty(const CellBoundary * boundary)
{
return boundary->numVerts < 1;
}
bool
boundary_is_closed(const CellBoundary * boundary)
{
const LatLng *verts;
int numVerts;
if (boundary_is_empty(boundary))
return true;
verts = boundary->verts;
numVerts = boundary->numVerts;
return verts[0].lng == verts[numVerts - 1].lng
&& verts[1].lat == verts[numVerts - 1].lat;
}
size_t
boundary_array_data_size(const CellBoundary * boundaries, int num)
{
/* byte order + type + srid + # of polygons */
size_t size = WKB_BYTE_SIZE + WKB_INT_SIZE * 3;
/* boundaries */
for (int i = 0; i < num; i++)
size += boundary_data_size(&boundaries[i]);
return size;
}
size_t
boundary_data_size(const CellBoundary * boundary)
{
/* byte order + type + srid + # of rings */
size_t size = WKB_BYTE_SIZE + WKB_INT_SIZE * 3;
/* points */
if (!boundary_is_empty(boundary))
{
int numVerts = boundary->numVerts;
if (!boundary_is_closed(boundary))
numVerts++;
/* # of points, point data */
size += WKB_INT_SIZE + numVerts * WKB_DOUBLE_SIZE * 2;
}
return size;
}
size_t
linked_geo_polygon_data_size(const LinkedGeoPolygon * multiPolygon)
{
size_t size = 0;
int isMulti = (multiPolygon->next != NULL);
/* byte order + type + srid */
size = WKB_BYTE_SIZE + WKB_INT_SIZE * 2;
if (isMulti)
{
/* # of polygons */
size += WKB_INT_SIZE;
}
FOREACH_LINKED_POLYGON(multiPolygon, polygon)
{
if (isMulti)
{
/* byte order + type + srid */
size += WKB_BYTE_SIZE + WKB_INT_SIZE * 2;
}
/* # of rings */
size += WKB_INT_SIZE;
FOREACH_LINKED_LOOP(polygon, loop)
{
size += linked_geo_loop_data_size(loop);
}
}
return size;
}
size_t
linked_geo_loop_data_size(const LinkedGeoLoop * loop)
{
/* ring size */
size_t size = WKB_INT_SIZE;
/* point data (including closing point) */
size += WKB_DOUBLE_SIZE * (count_linked_lat_lng(loop) + 1) * 2;
return size;
}
uint8 *
wkb_write_boundary_array_data(uint8 *data, const CellBoundary * boundaries, int num)
{
/* byte order */
data = wkb_write_endian(data);
/* type */
data = wkb_write_int(data, WKB_MULTIPOLYGON_TYPE | WKB_SRID_FLAG);
/* SRID */
data = wkb_write_int(data, WKB_SRID_DEFAULT);
/* # of polygons */
data = wkb_write_int(data, num);
/* polygons */
for (int i = 0; i < num; i++)
data = wkb_write_boundary_data(data, &boundaries[i]);
return data;
}
uint8 *
wkb_write_boundary_data(uint8 *data, const CellBoundary * boundary)
{
/* byte order */
data = wkb_write_endian(data);
/* type */
data = wkb_write_int(data, WKB_POLYGON_TYPE | WKB_SRID_FLAG);
/* SRID */
data = wkb_write_int(data, WKB_SRID_DEFAULT);
/* # of rings */
data = wkb_write_int(data, boundary_is_empty(boundary) ? 0 : 1);
/* exterior ring */
if (!boundary_is_empty(boundary))
{
bool is_closed = boundary_is_closed(boundary);
data = wkb_write_int(data, boundary->numVerts + (is_closed ? 0 : 1));
data = wkb_write_lat_lng_array(data, boundary->verts, boundary->numVerts);
/* close the ring */
if (!is_closed)
data = wkb_write_lat_lng(data, &boundary->verts[0]);
}
return data;
}
uint8 *
wkb_write_linked_geo_polygon_data(uint8 *data, const LinkedGeoPolygon * multiPolygon)
{
int isMulti = (multiPolygon->next != NULL);
int type = isMulti ? WKB_MULTIPOLYGON_TYPE : WKB_POLYGON_TYPE;
/* byte order */
data = wkb_write_endian(data);
/* type */
data = wkb_write_int(data, type | WKB_SRID_FLAG);
/* SRID */
data = wkb_write_int(data, WKB_SRID_DEFAULT);
if (isMulti)
{
/* # of polygons */
data = wkb_write_int(data, count_linked_polygons(multiPolygon));
}
FOREACH_LINKED_POLYGON(multiPolygon, polygon)
{
if (isMulti)
{
/* byte order */
data = wkb_write_endian(data);
/* type */
data = wkb_write_int(data, WKB_POLYGON_TYPE | WKB_SRID_FLAG);
/* SRID */
data = wkb_write_int(data, WKB_SRID_DEFAULT);
}
/* # of rings */
data = wkb_write_int(data, count_linked_geo_loops(polygon));
/* rings */
FOREACH_LINKED_LOOP(polygon, loop)
{
data = wkb_write_linked_geo_loop_data(data, loop);
}
}
return data;
}
uint8 *
wkb_write_lat_lng_array(uint8 *data, const LatLng * coords, int num)
{
for (int i = 0; i < num; i++)
data = wkb_write_lat_lng(data, &coords[i]);
return data;
}
uint8 *
wkb_write_linked_geo_loop_data(uint8 *data, const LinkedGeoLoop * loop)
{
/* # of points (including closing point) */
data = wkb_write_int(data, count_linked_lat_lng(loop) + 1);
/* point data */
FOREACH_LINKED_LAT_LNG(loop, latlng)
{
data = wkb_write_lat_lng(data, &latlng->vertex);
}
/* closing point data */
data = wkb_write_lat_lng(data, &loop->first->vertex);
return data;
}
uint8 *
wkb_write_lat_lng(uint8 *data, const LatLng * coord)
{
data = wkb_write(data, &coord->lng, sizeof(coord->lng));
data = wkb_write(data, &coord->lat, sizeof(coord->lat));
return data;
}
uint8 *
wkb_write_endian(uint8 *data)
{
/* Always use native order */
uint32 order = 0x00000001;
data[0] = ((uint8 *) &order)[0] ? WKB_NDR : WKB_XDR;
return data + 1;
}
uint8 *
wkb_write_int(uint8 *data, uint32 value)
{
return wkb_write(data, &value, sizeof(value));
}
uint8 *
wkb_write(uint8 *data, const void *value, size_t size)
{
memcpy(data, value, size);
return data + size;
}
h3-pg-4.1.3/h3_postgis/src/wkb.h 0000664 0000000 0000000 00000002024 14460144644 0016247 0 ustar 00root root 0000000 0000000 /*
* Copyright 2022-2023 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.
*/
#ifndef PGH3_WKB_H
#define PGH3_WKB_H
#include
#include
#include
#if POSTGRESQL_VERSION_MAJOR >= 16
#include "varatt.h" //VAR_SIZE and friends moved to here from postgres.h
#endif
bytea *
boundary_array_to_wkb(const CellBoundary * boundaries, size_t num);
bytea *
boundary_to_wkb(const CellBoundary * boundary);
bytea *
linked_geo_polygon_to_wkb(const LinkedGeoPolygon * multiPolygon);
#endif
h3-pg-4.1.3/h3_postgis/src/wkb_bbox3.c 0000664 0000000 0000000 00000011436 14460144644 0017346 0 ustar 00root root 0000000 0000000 /*
* Copyright 2022-2023 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
#include
#include "wkb_bbox3.h"
#include "wkb_linked_geo.h"
typedef struct
{
double x;
double y;
} Vect2;
static void
vect2_normalize(Vect2 * vect);
static short
vect2_segment_side(const Vect2 * start, const Vect2 * end, const Vect2 * point);
static void
bbox3_merge_vect3(const Vect3 * vect, Bbox3 * bbox);
void
bbox3_from_vect3(const Vect3 * vect, Bbox3 * bbox)
{
bbox->xmin = bbox->xmax = vect->x;
bbox->ymin = bbox->ymax = vect->y;
bbox->zmin = bbox->zmax = vect->z;
}
void
bbox3_merge(const Bbox3 * other, Bbox3 * bbox)
{
if (other->xmin < bbox->xmin)
bbox->xmin = other->xmin;
if (other->xmax > bbox->xmax)
bbox->xmax = other->xmax;
if (other->ymin < bbox->ymin)
bbox->ymin = other->ymin;
if (other->ymax > bbox->ymax)
bbox->ymax = other->ymax;
if (other->zmin < bbox->zmin)
bbox->zmin = other->zmin;
if (other->zmax > bbox->zmax)
bbox->zmax = other->zmax;
}
void
bbox3_from_linked_loop(const LinkedGeoLoop * loop, Bbox3 * bbox)
{
Vect3 vect,
nextVect;
vect3_from_lat_lng(&loop->first->vertex, &vect);
bbox3_from_vect3(&vect, bbox);
if (!loop->first->next)
return;
FOREACH_LINKED_LAT_LNG_PAIR(loop, cur, next)
{
Bbox3 segmentBbox;
vect3_from_lat_lng(&next->vertex, &nextVect);
if (!vect3_eq(&vect, &nextVect))
{
bbox3_from_segment_vect3(&vect, &nextVect, &segmentBbox);
bbox3_merge(&segmentBbox, bbox);
}
vect = nextVect;
}
}
int
bbox3_contains_vect3(const Bbox3 * bbox, const Vect3 * vect)
{
return bbox->xmin <= vect->x && vect->x <= bbox->xmax
&& bbox->ymin <= vect->y && vect->y <= bbox->ymax
&& bbox->zmin <= vect->z && vect->z <= bbox->zmax;
}
int
bbox3_contains_lat_lng(const Bbox3 * bbox, const LatLng * coord)
{
Vect3 vect;
vect3_from_lat_lng(coord, &vect);
return bbox3_contains_vect3(bbox, &vect);
}
void
bbox3_from_segment_vect3(const Vect3 * vect1, const Vect3 * vect2, Bbox3 * bbox)
{
Vect3 vn,
vect3;
Vect3 axes[6];
Vect2 r1,
r2,
orig;
short orig_side;
/* Init bbox */
bbox3_from_vect3(vect1, bbox);
bbox3_merge_vect3(vect2, bbox);
/* Check if end points are the same */
if (vect3_eq(vect1, vect2))
return;
/* Normal of plain containing endpoint vectors */
vect3_cross(vect1, vect2, &vn);
vect3_normalize(&vn);
/* Vector orthogonal to first endpoint vector */
vect3_cross(&vn, vect1, &vect3);
/* Project endpoint vectors onto the plane, using vect1/vect3 as basis */
r1.x = 1.0;
r1.y = 0.0;
r2.x = vect3_dot(vect2, vect1);
r2.y = vect3_dot(vect2, &vect3);
/* Origin side relative to the projected segment (r1, r2) */
orig.x = 0.0;
orig.y = 0.0;
orig_side = vect2_segment_side(&r1, &r2, &orig);
/* Axis points: (1, 0, 0), (-1, 0, 0), (0, 1, 0), ... */
memset(axes, 0, 6 * sizeof(Vect3));
axes[0].x = axes[2].y = axes[4].z = 1.0;
axes[1].x = axes[3].y = axes[5].z = -1.0;
for (int i = 0; i < 6; ++i)
{
/* Project axis onto the plane, normalize */
Vect2 rx;
rx.x = vect3_dot(&axes[i], vect1);
rx.y = vect3_dot(&axes[i], &vect3);
vect2_normalize(&rx);
/* Is projected axis vector between r1 and r2 */
/* (is origin on the opposite side of segment (r1, r2))? */
if (vect2_segment_side(&r1, &r2, &rx) != orig_side)
{
Vect3 vx;
vx.x = rx.x * vect1->x + rx.y * vect3.x;
vx.y = rx.x * vect1->y + rx.y * vect3.y;
vx.z = rx.x * vect1->z + rx.y * vect3.z;
bbox3_merge_vect3(&vx, bbox);
}
}
}
void
bbox3_from_segment_lat_lng(const LatLng * coord1, const LatLng * coord2, Bbox3 * bbox)
{
Vect3 vect1,
vect2;
vect3_from_lat_lng(coord1, &vect1);
vect3_from_lat_lng(coord2, &vect2);
bbox3_from_segment_vect3(&vect1, &vect2, bbox);
}
static void
vect2_normalize(Vect2 * vect)
{
double len = sqrt(vect->x * vect->x + vect->y * vect->y);
if (len > 0.0)
{
vect->x /= len;
vect->y /= len;
}
else
{
vect->x = 0.0;
vect->y = 0.0;
}
}
static short
vect2_segment_side(const Vect2 * start, const Vect2 * end, const Vect2 * point)
{
double side = (point->x - start->x) * (end->y - start->y)
- (end->x - start->x) * (point->y - start->y);
return (side == 0) ? 0 : (side < 0) ? -1 : 1;
}
static void
bbox3_merge_vect3(const Vect3 * vect, Bbox3 * bbox)
{
Bbox3 vect_bbox;
bbox3_from_vect3(vect, &vect_bbox);
bbox3_merge(&vect_bbox, bbox);
}
h3-pg-4.1.3/h3_postgis/src/wkb_bbox3.h 0000664 0000000 0000000 00000002503 14460144644 0017346 0 ustar 00root root 0000000 0000000 /*
* Copyright 2022-2023 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.
*/
#ifndef PGH3_WKB_BBOX3_H
#define PGH3_WKB_BBOX3_H
#include
#include "wkb_vect3.h"
typedef struct
{
double xmin;
double xmax;
double ymin;
double ymax;
double zmin;
double zmax;
} Bbox3;
void
bbox3_from_vect3(const Vect3 * vect, Bbox3 * bbox);
void
bbox3_merge(const Bbox3 * other, Bbox3 * bbox);
void
bbox3_from_linked_loop(const LinkedGeoLoop * loop, Bbox3 * bbox);
int
bbox3_contains_vect3(const Bbox3 * bbox, const Vect3 * vect);
int
bbox3_contains_lat_lng(const Bbox3 * bbox, const LatLng * coord);
void
bbox3_from_segment_vect3(const Vect3 * vect1, const Vect3 * vect2, Bbox3 * bbox);
void
bbox3_from_segment_lat_lng(const LatLng * coord1, const LatLng * coord2, Bbox3 * bbox);
#endif
h3-pg-4.1.3/h3_postgis/src/wkb_indexing.c 0000664 0000000 0000000 00000013240 14460144644 0020131 0 ustar 00root root 0000000 0000000 /*
* Copyright 2022-2023 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
#include
#include // PG_FUNCTION_ARGS
#include
#include "constants.h"
#include "error.h"
#include "type.h"
#include "wkb_split.h"
#include "wkb_vect3.h"
#include "wkb.h"
#define SIGN(x) ((x < 0) ? -1 : (x > 0) ? 1 \
: 0)
#define ABS_LAT_MAX (degsToRads(89.9999))
#define SPLIT_ASSERT(condition, message) \
ASSERT( \
condition, \
ERRCODE_EXTERNAL_ROUTINE_EXCEPTION, \
message)
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_cell_to_boundary_wkb);
/* Converts CellBoundary coordinates to degrees in place */
static void
boundary_to_degs(CellBoundary * boundary);
/* Checks if CellBoundary is crossed by antimeridian */
static int
boundary_crosses_180_num(const CellBoundary * boundary);
/* Splits CellBoundary by antimeridian (and 0 meridian around poles) */
static void
boundary_split_180(const CellBoundary * boundary, CellBoundary * left, CellBoundary * right);
/*
Creates a boundary for polar cells with additional points on an antimeridian.
The functions adds 2 points (with lon. 180 and -180) for intersection with
antimeridian and 2 points on antimeridian close to the pole.
This allows to better display polar cells in e.g. Mercator projection.
*/
static void
boundary_split_180_polar(const CellBoundary * boundary, CellBoundary * res);
/* Finds the boundary of the index, converts to EWKB, splits the boundary by 180 meridian */
Datum
h3_cell_to_boundary_wkb(PG_FUNCTION_ARGS)
{
H3Index cell = PG_GETARG_H3INDEX(0);
bytea *wkb;
CellBoundary boundary;
int crossNum;
h3_assert(cellToBoundary(cell, &boundary));
crossNum = boundary_crosses_180_num(&boundary);
if (crossNum == 0)
{
/* Cell is not crossed by antimeridian */
boundary_to_degs(&boundary);
wkb = boundary_to_wkb(&boundary);
}
else if (crossNum == 1)
{
/* Cell boundary is crossed by antimeridian once */
CellBoundary split;
boundary_split_180_polar(&boundary, &split);
boundary_to_degs(&split);
wkb = boundary_to_wkb(&split);
}
else
{
/* Crossed by antimeridian */
CellBoundary parts[2];
boundary_split_180(&boundary, &parts[0], &parts[1]);
boundary_to_degs(&parts[0]);
boundary_to_degs(&parts[1]);
wkb = boundary_array_to_wkb(parts, 2);
}
PG_RETURN_BYTEA_P(wkb);
}
void
boundary_to_degs(CellBoundary * boundary)
{
LatLng *verts = boundary->verts;
const int numVerts = boundary->numVerts;
for (int v = 0; v < numVerts; v++)
{
verts[v].lng = radsToDegs(verts[v].lng);
verts[v].lat = radsToDegs(verts[v].lat);
}
}
int
boundary_crosses_180_num(const CellBoundary * boundary)
{
const int numVerts = boundary->numVerts;
const LatLng *verts = boundary->verts;
int num = 0;
for (int v = 0; v < numVerts; v++)
{
double lon = verts[v].lng;
double nextLon = verts[(v + 1) % numVerts].lng;
if (SIGN(lon) != SIGN(nextLon)
&& fabs(lon - nextLon) > M_PI)
{
++num;
}
}
return num;
}
void
boundary_split_180(const CellBoundary * boundary, CellBoundary * part1, CellBoundary * part2)
{
const int numVerts = boundary->numVerts;
const LatLng *verts = boundary->verts;
part1->numVerts = 0;
part2->numVerts = 0;
for (int v = 0; v < numVerts; v++)
{
int next = (v + 1) % numVerts;
double lon;
double nextLon;
CellBoundary *part;
lon = verts[v].lng;
nextLon = verts[next].lng;
part = (lon < 0) ? part1 : part2;
/* Add current vertex */
part->verts[part->numVerts++] = verts[v];
if (SIGN(lon) != SIGN(nextLon))
{
LatLng vert;
SPLIT_ASSERT(
fabs(lon - nextLon) > M_PI,
"Cell boundaries crossed by the Prime meridian "
"must be handled in `boundary_split_180_polar`");
vert.lat = split_180_lat(&verts[v], &verts[next]);
vert.lng = (lon < 0) ? -M_PI : M_PI;
/* Add split point */
/* current part */
part->verts[part->numVerts++] = vert;
/* next part */
vert.lng = -vert.lng;
part = (part == part1) ? part2 : part1;
part->verts[part->numVerts++] = vert;
}
}
}
void
boundary_split_180_polar(const CellBoundary * boundary, CellBoundary * res)
{
const int numVerts = boundary->numVerts;
const LatLng *verts = boundary->verts;
res->numVerts = 0;
for (int v = 0; v < numVerts; v++)
{
int next = (v + 1) % numVerts;
double lon;
double nextLon;
/* Add current vertex */
res->verts[res->numVerts++] = verts[v];
lon = verts[v].lng;
nextLon = verts[next].lng;
if (SIGN(lon) != SIGN(nextLon)
&& fabs(lon - nextLon) > M_PI)
{
LatLng vert;
double splitLat;
SPLIT_ASSERT(
v + 1 == res->numVerts,
"Cell boundaries crossed by antimeridian more than once "
"must be handled in `boundary_split_180`");
splitLat = split_180_lat(&verts[v], &verts[next]);
/* Add intersection point */
vert.lat = splitLat;
vert.lng = (lon < 0) ? -M_PI : M_PI;
res->verts[res->numVerts++] = vert;
/* Add points on antimeridian near the pole */
vert.lat = SIGN(vert.lat) * ABS_LAT_MAX;
res->verts[res->numVerts++] = vert;
vert.lng = -vert.lng;
res->verts[res->numVerts++] = vert;
/* Add intersection point */
vert.lat = splitLat;
res->verts[res->numVerts++] = vert;
}
}
}
h3-pg-4.1.3/h3_postgis/src/wkb_linked_geo.c 0000664 0000000 0000000 00000005512 14460144644 0020427 0 ustar 00root root 0000000 0000000 /*
* Copyright 2022-2023 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
#include "wkb_linked_geo.h"
static void
free_linked_geo_loop(LinkedGeoLoop * loop);
int
count_linked_polygons(const LinkedGeoPolygon * multiPolygon)
{
int num = 0;
FOREACH_LINKED_POLYGON(multiPolygon, _)
++ num;
return num;
}
int
count_linked_geo_loops(const LinkedGeoPolygon * polygon)
{
int num = 0;
FOREACH_LINKED_LOOP(polygon, _)
++ num;
return num;
}
int
count_linked_lat_lng(const LinkedGeoLoop * loop)
{
int num = 0;
FOREACH_LINKED_LAT_LNG(loop, _)
++ num;
return num;
}
LinkedGeoPolygon *
copy_linked_geo_polygon(const LinkedGeoPolygon * polygon)
{
LinkedGeoPolygon *copy = palloc0(sizeof(LinkedGeoPolygon));
FOREACH_LINKED_LOOP(polygon, loop)
{
LinkedGeoLoop *loopCopy = copy_linked_geo_loop(loop);
add_linked_geo_loop(copy, loopCopy);
}
return copy;
}
LinkedGeoLoop *
copy_linked_geo_loop(const LinkedGeoLoop * loop)
{
LinkedGeoLoop *copy = palloc0(sizeof(LinkedGeoLoop));
FOREACH_LINKED_LAT_LNG(loop, latlng)
{
LinkedLatLng *latlng_copy = copy_linked_lat_lng(latlng);
add_linked_lat_lng(copy, latlng_copy);
}
return copy;
}
LinkedLatLng *
copy_linked_lat_lng(const LinkedLatLng * latlng)
{
LinkedLatLng *copy = palloc0(sizeof(LinkedLatLng));
copy->vertex = latlng->vertex;
return copy;
}
void
add_linked_geo_loop(LinkedGeoPolygon * polygon, LinkedGeoLoop * loop)
{
LinkedGeoLoop *last = polygon->last;
if (!last)
polygon->first = loop;
else
last->next = loop;
polygon->last = loop;
}
void
add_linked_lat_lng(LinkedGeoLoop * loop, LinkedLatLng * latlng)
{
LinkedLatLng *last = loop->last;
if (!last)
loop->first = latlng;
else
last->next = latlng;
loop->last = latlng;
}
void
free_linked_geo_polygon(LinkedGeoPolygon * multiPolygon)
{
LinkedGeoPolygon *polygon = multiPolygon;
while (polygon)
{
LinkedGeoPolygon *nextPolygon = polygon->next;
/* Free loops */
LinkedGeoLoop *loop = polygon->first;
while (loop)
{
LinkedGeoLoop *nextLoop = loop->next;
free_linked_geo_loop(loop);
loop = nextLoop;
}
pfree(polygon);
polygon = nextPolygon;
}
}
void
free_linked_geo_loop(LinkedGeoLoop * loop)
{
LinkedLatLng *latlng = loop->first;
while (latlng)
{
LinkedLatLng *next = latlng->next;
pfree(latlng);
latlng = next;
}
pfree(loop);
}
h3-pg-4.1.3/h3_postgis/src/wkb_linked_geo.h 0000664 0000000 0000000 00000004627 14460144644 0020442 0 ustar 00root root 0000000 0000000 /*
* Copyright 2022-2023 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.
*/
#ifndef PGH3_WKB_LINKED_GEO_H
#define PGH3_WKB_LINKED_GEO_H
#include
#define _FOREACH_LINKED_ITEM(first, item, Type) \
for (Type *item = (first); \
item != NULL; \
item = item->next)
#define FOREACH_LINKED_POLYGON(multiPolygon, polygon) \
_FOREACH_LINKED_ITEM(multiPolygon, polygon, const LinkedGeoPolygon)
#define FOREACH_LINKED_POLYGON_NOCONST(multiPolygon, polygon) \
_FOREACH_LINKED_ITEM(multiPolygon, polygon, LinkedGeoPolygon)
#define FOREACH_LINKED_LOOP(polygon, loop) \
_FOREACH_LINKED_ITEM(polygon->first, loop, const LinkedGeoLoop)
#define FOREACH_LINKED_LOOP_NOCONST(polygon, loop) \
_FOREACH_LINKED_ITEM(polygon->first, loop, LinkedGeoLoop)
#define FOREACH_LINKED_LAT_LNG(loop, latlng) \
_FOREACH_LINKED_ITEM(loop->first, latlng, const LinkedLatLng)
#define FOREACH_LINKED_LAT_LNG_NOCONST(loop, latlng) \
_FOREACH_LINKED_ITEM(loop->first, latlng, LinkedLatLng)
/* NOTE: loop must contain at least 2 points */
#define FOREACH_LINKED_LAT_LNG_PAIR(loop, cur, next) \
for (const LinkedLatLng *cur = loop->first, *next = cur->next; \
cur != NULL; \
cur = cur->next, next = next->next ? next->next : loop->first)
int
count_linked_polygons(const LinkedGeoPolygon * multiPolygon);
int
count_linked_geo_loops(const LinkedGeoPolygon * polygon);
int
count_linked_lat_lng(const LinkedGeoLoop * loop);
LinkedGeoPolygon *
copy_linked_geo_polygon(const LinkedGeoPolygon * polygon);
LinkedGeoLoop *
copy_linked_geo_loop(const LinkedGeoLoop * loop);
LinkedLatLng *
copy_linked_lat_lng(const LinkedLatLng * latlng);
void
add_linked_geo_loop(LinkedGeoPolygon * polygon, LinkedGeoLoop * loop);
void
add_linked_lat_lng(LinkedGeoLoop * loop, LinkedLatLng * latlng);
void
free_linked_geo_polygon(LinkedGeoPolygon * multiPolygon);
#endif
h3-pg-4.1.3/h3_postgis/src/wkb_regions.c 0000664 0000000 0000000 00000005164 14460144644 0020000 0 ustar 00root root 0000000 0000000 /*
* Copyright 2022-2023 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
#include
#include // PG_FUNCTION_ARGS
#include // using arrays
#include "error.h"
#include "type.h"
#include "wkb_linked_geo.h"
#include "wkb_split.h"
#include "wkb.h"
PGDLLEXPORT PG_FUNCTION_INFO_V1(h3_cells_to_multi_polygon_wkb);
/* Converts LinkedGeoPolygon vertex coordinates to degrees in place */
static void
linked_geo_polygon_to_degs(LinkedGeoPolygon * multiPolygon);
Datum
h3_cells_to_multi_polygon_wkb(PG_FUNCTION_ARGS)
{
ArrayType *array = PG_GETARG_ARRAYTYPE_P(0);
LinkedGeoPolygon *linkedPolygon;
H3Error error;
int numHexes;
ArrayIterator iterator;
Datum value;
bool isnull;
H3Index *h3set;
bytea *wkb;
numHexes = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
h3set = palloc(numHexes * sizeof(H3Index));
/* Extract data from array into h3set */
iterator = array_create_iterator(array, 0, NULL);
numHexes = 0;
while (array_iterate(iterator, &value, &isnull))
{
h3set[numHexes++] = DatumGetH3Index(value);
}
/* produce hexagons into allocated memory */
linkedPolygon = palloc(sizeof(LinkedGeoPolygon));
h3_assert(cellsToLinkedMultiPolygon(h3set, numHexes, linkedPolygon));
if (is_linked_polygon_crossed_by_180(linkedPolygon))
{
/* Split by 180th meridian */
LinkedGeoPolygon *splitPolygon = split_linked_polygon_by_180(linkedPolygon);
linked_geo_polygon_to_degs(splitPolygon);
wkb = linked_geo_polygon_to_wkb(splitPolygon);
free_linked_geo_polygon(splitPolygon);
}
else
{
linked_geo_polygon_to_degs(linkedPolygon);
wkb = linked_geo_polygon_to_wkb(linkedPolygon);
}
destroyLinkedMultiPolygon(linkedPolygon);
pfree(linkedPolygon);
PG_RETURN_BYTEA_P(wkb);
}
void
linked_geo_polygon_to_degs(LinkedGeoPolygon * multiPolygon)
{
FOREACH_LINKED_POLYGON_NOCONST(multiPolygon, polygon)
{
FOREACH_LINKED_LOOP_NOCONST(polygon, loop)
{
FOREACH_LINKED_LAT_LNG_NOCONST(loop, latlng)
{
LatLng *vertex = &latlng->vertex;
vertex->lat = radsToDegs(vertex->lat);
vertex->lng = radsToDegs(vertex->lng);
}
}
}
}
h3-pg-4.1.3/h3_postgis/src/wkb_split.c 0000664 0000000 0000000 00000054650 14460144644 0017471 0 ustar 00root root 0000000 0000000 /*
* Copyright 2022-2023 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
#include
#include
#include
#include "constants.h"
#include "wkb_split.h"
#include "wkb_bbox3.h"
#include "wkb_linked_geo.h"
/*
Example: O-shaped polygon crossed by antimeridian.
After intersections are found and sorted by latitude,
intersection pairs 0-1 and 2-3 become segments in
exterior rings of the polygons in result.
|
+------(0)------+
| | |
| +---(1)---+ |
| | | | |
| | | | |
| +---(2)---+ |
| | |
+------(3)------+
|
Algorithm overview:
1. Initialization:
- empty array of vertices
- empty array of intersections
- empty array of interior rings not split by antimeridian
2. Processing polygon rings:
for each ring in the polygon:
if ring is crossed by prime or antimeridian:
for each segment in the ring:
- add first endpoint to array of vertices
if segment crosses antimeridian:
- add an intersection, link to first endpoint
else:
- add ring to array of non-split holes
3. Preparing data:
- sort intersections by latitude
- set sort order value for each intersection
4. Building multipolygon:
while there are unused vertices:
- create empty exterior ring
- start traversing vertex array forward starting from next unused vertex
while current vertex is unused:
- add current vertex to exterior ring
- get next vertex (depends on traversal direction)
if there is an intersection between vertices:
- add intersection point to exterior ring
- get adjacent intersection from sorted array
- add next intersection point to exterior ring
- update traversal direction based on intersection direction value
- get next vertex
- move to text vertex
- check which non-split holes are inside the exterior ring and add them to polygon
- add polygon to result
*/
#define SIGN(x) ((x < 0) ? -1 : (x > 0) ? 1 \
: 0)
#define FP_EQUAL(v1, v2) ((v1) == (v2) || fabs((v1) - (v2)) < DBL_EPSILON)
#define SPLIT_ASSERT(condition, message) \
ASSERT( \
condition, \
ERRCODE_EXTERNAL_ROUTINE_EXCEPTION, \
message)
#define SPLIT_ASSERT_VALID_VERTEX_IDX(split, idx) \
SPLIT_ASSERT(0 <= idx && idx < split->vertexNum, "vertex index out of bounds")
#define INTERSECT_ARRAY_SIZE_INIT (4)
/* Direction of segment intersecting antimeridian: */
/* West-to-East or East-to-West */
typedef enum
{
SplitIntersectDir_None = 0,
SplitIntersectDir_WE,
SplitIntersectDir_EW
} SplitIntersectDir;
typedef struct
{
SplitIntersectDir dir;
bool isPrime;
double lat;
int vertexIdx;
int sortOrder;
} SplitIntersect;
typedef struct
{
const LatLng *latlngPtr;
int intersectIdx;
short sign; /* longitude sign is set explicitly in case
* longitude of the vertex itself is zero */
int link; /* links first and last vertices in a ring */
} SplitVertex;
typedef struct
{
/* Vertices */
int vertexNum;
SplitVertex *vertices;
/* Intersections */
int maxIntersectNum;
int intersectNum;
SplitIntersect *intersects;
SplitIntersect **sortedIntersects;
/* Non-split holes */
int holeNum;
const LinkedGeoLoop **holes;
} Split;
static bool
is_polygon_crossed(const LinkedGeoPolygon * polygon);
static LinkedGeoPolygon *
split_polygon(const LinkedGeoPolygon * polygon);
static bool
is_ring_crossed(const LinkedGeoLoop * ring);
static void
split_init(Split * split, int ringNum, int vertexNum);
static void
split_cleanup(Split * split);
static void
split_process_ring(Split * split, const LinkedGeoLoop * ring);
static void
split_prepare(Split * split);
static LinkedGeoPolygon *
split_create_multi_polygon(Split * split);
static int
split_add_vertex(Split * split, const LatLng * latlng);
static void
split_add_intersect_after(Split * split, int vertexIdx, SplitIntersectDir dir, bool isPrime, double lat);
static int
split_add_intersect(Split * split, SplitIntersectDir dir, bool isPrime, double lat);
static void
split_link_vertices(Split * split, int idx1, int idx2);
static void
split_add_hole(Split * split, const LinkedGeoLoop * hole);
static
void split_sort_intersects(Split * split);
static int
split_intersect_ptr_cmp(const void *a, const void *b);
static int
split_find_next_vertex(Split * split, int *start);
static LinkedGeoPolygon *
split_create_polygon_vertex(Split * split, int vertexIdx);
static void
split_polygon_assign_holes(Split * split, short sign, LinkedGeoPolygon * polygon);
static const SplitIntersect *
split_get_intersect_after(Split * split, int vertexIdx);
static void
split_intersect_get_lat_lng(const SplitIntersect * intersect, short sign, LatLng * latlng);
static int
count_polygon_vertices(const LinkedGeoPolygon * polygon, int *ringNum);
static short
lat_lng_ring_pos(const LinkedGeoLoop * ring, short sign, const Bbox3 * bbox, const LatLng * latlng);
static short
segment_intersect(const Vect3 * v1, const Vect3 * v2, const Vect3 * u1, const Vect3 * u2);
static short
point_segment_pos(const Vect3 * v1, const Vect3 * v2, const Vect3 * p);
static void
add_lat_lng(LinkedGeoLoop * loop, const LatLng * latlng);
bool
is_linked_polygon_crossed_by_180(const LinkedGeoPolygon * multiPolygon)
{
FOREACH_LINKED_POLYGON(multiPolygon, polygon)
{
if (is_polygon_crossed(polygon))
return true;
}
return false;
}
LinkedGeoPolygon *
split_linked_polygon_by_180(const LinkedGeoPolygon * multiPolygon)
{
LinkedGeoPolygon *result = NULL;
LinkedGeoPolygon *last = NULL;
FOREACH_LINKED_POLYGON(multiPolygon, polygon)
{
/* Split or copy next polygon */
LinkedGeoPolygon *nextResult = is_polygon_crossed(polygon)
? split_polygon(polygon)
: copy_linked_geo_polygon(polygon);
/* Add to result */
if (!result)
{
result = nextResult;
last = nextResult;
}
else
{
last->next = nextResult;
}
while (last->next)
last = last->next;
}
return result;
}
double
split_180_lat(const LatLng * coord1, const LatLng * coord2)
{
Vect3 p1,
p2,
normal,
s;
double y;
/* Normal of circle containing points: normal = p1 x p2 */
vect3_from_lat_lng(coord1, &p1);
vect3_from_lat_lng(coord2, &p2);
vect3_cross(&p1, &p2, &normal);
/* y coordinate of 0/180 meridian circle normal */
y = (coord1->lng < 0 || coord2->lng > 0) ? -1 : 1;
/* Circle plane intersection vector: s = (p1 x p2) x {0, y, 0} */
s.x = -(normal.z * y);
s.y = 0;
s.z = normal.x * y;
vect3_normalize(&s); /* intersection point coordinates on unit
* sphere */
return asin(s.z); /* latitude */
}
bool
is_polygon_crossed(const LinkedGeoPolygon * polygon)
{
return polygon->first
? is_ring_crossed(polygon->first)
: false;
}
LinkedGeoPolygon *
split_polygon(const LinkedGeoPolygon * polygon)
{
int ringNum,
vertexNum;
Split split;
LinkedGeoPolygon *result;
/* Init data */
vertexNum = count_polygon_vertices(polygon, &ringNum);
split_init(&split, ringNum, vertexNum);
/* Process rings */
FOREACH_LINKED_LOOP(polygon, ring)
{
if (ring == polygon->first || is_ring_crossed(ring))
split_process_ring(&split, ring);
else
split_add_hole(&split, ring);
}
/* Prepare data */
split_prepare(&split);
/* Build result */
result = split_create_multi_polygon(&split);
/* Cleanup */
split_cleanup(&split);
return result;
}
bool
is_ring_crossed(const LinkedGeoLoop * ring)
{
if (!ring->first || !ring->first->next)
return false;
FOREACH_LINKED_LAT_LNG_PAIR(ring, cur, next)
{
double lng = cur->vertex.lng;
double nextLng = next->vertex.lng;
if (SIGN(lng) != SIGN(nextLng)
&& fabs(lng - nextLng) > M_PI)
{
return true;
}
}
return false;
}
void
split_init(Split * split, int ringNum, int vertexNum)
{
*split = (Split)
{
0
};
split->vertices = palloc0(vertexNum * sizeof(SplitVertex));
split->maxIntersectNum = INTERSECT_ARRAY_SIZE_INIT;
split->intersects = palloc0(split->maxIntersectNum * sizeof(SplitIntersect));
if (ringNum > 1)
split->holes = palloc0((ringNum - 1) * sizeof(LinkedGeoLoop *));
}
void
split_cleanup(Split * split)
{
if (split->vertices)
pfree(split->vertices);
if (split->intersects)
pfree(split->intersects);
if (split->sortedIntersects)
pfree(split->sortedIntersects);
if (split->holes)
pfree(split->holes);
*split = (Split)
{
0
};
}
void
split_process_ring(Split * split, const LinkedGeoLoop * ring)
{
short sign = 0;
int vertexIdx = -1;
int firstVertexIdx = -1;
SPLIT_ASSERT(ring->first && ring->first->next, "polygon ring must have at least 2 vertices");
FOREACH_LINKED_LAT_LNG_PAIR(ring, cur, next)
{
double lng,
nextLng;
short nextSign;
/* Add vertex */
vertexIdx = split_add_vertex(split, &cur->vertex);
if (firstVertexIdx < 0)
firstVertexIdx = vertexIdx;
lng = cur->vertex.lng;
nextLng = next->vertex.lng;
nextSign = SIGN(nextLng);
if (sign == 0)
{
sign = SIGN(lng);
if (sign != 0)
{
/* Set sign for vertices traversed so far */
for (int i = firstVertexIdx; i <= vertexIdx; ++i)
split->vertices[i].sign = sign;
}
}
else
{
/* Set vertex sign */
split->vertices[vertexIdx].sign = sign;
}
if (sign != 0 && nextSign != 0 && nextSign != sign)
{
/* Prime or antimeridian crossed */
/* Add intersection after current vertex */
SplitIntersectDir dir = (sign < 0) ? SplitIntersectDir_WE : SplitIntersectDir_EW;
int isPrime = (fabs(lng - nextLng) < M_PI);
double lat = split_180_lat(&cur->vertex, &next->vertex);
split_add_intersect_after(split, vertexIdx, dir, isPrime, lat);
sign = nextSign;
}
}
/* Link first and last vertices */
split_link_vertices(split, firstVertexIdx, vertexIdx);
}
void
split_prepare(Split * split)
{
split_sort_intersects(split);
}
LinkedGeoPolygon *
split_create_multi_polygon(Split * split)
{
LinkedGeoPolygon *multiPolygon = NULL;
LinkedGeoPolygon *lastPolygon = NULL;
int vertexIdxStart = 0;
while (true)
{
LinkedGeoPolygon *polygon;
/* Get next unused vertex */
int vertexIdx = split_find_next_vertex(split, &vertexIdxStart);
if (vertexIdx < 0)
break; /* done */
/* Create next polygon */
polygon = split_create_polygon_vertex(split, vertexIdx);
/* Add to result */
if (!multiPolygon)
multiPolygon = polygon;
else
lastPolygon->next = polygon;
lastPolygon = polygon;
}
return multiPolygon;
}
int
split_add_vertex(Split * split, const LatLng * latlng)
{
int idx = split->vertexNum++;
SplitVertex *vertex = &split->vertices[idx];
vertex->latlngPtr = latlng;
vertex->intersectIdx = -1;
vertex->sign = 0;
vertex->link = -1;
return idx;
}
void
split_add_intersect_after(Split * split, int vertexIdx, SplitIntersectDir dir, bool isPrime, double lat)
{
int idx = split_add_intersect(split, dir, isPrime, lat);
SplitIntersect *intersect = &split->intersects[idx];
intersect->vertexIdx = vertexIdx;
split->vertices[vertexIdx].intersectIdx = idx;
}
int
split_add_intersect(Split * split, SplitIntersectDir dir, bool isPrime, double lat)
{
int idx;
SplitIntersect *intersect;
if (split->intersectNum == split->maxIntersectNum)
{
/* Reallocate memory for intersections */
int maxNum = split->maxIntersectNum * 2;
if (maxNum > split->vertexNum)
maxNum = split->vertexNum;
split->intersects = repalloc(split->intersects, maxNum * sizeof(SplitIntersect));
split->maxIntersectNum = maxNum;
}
idx = split->intersectNum++;
intersect = &split->intersects[idx];
intersect->dir = dir;
intersect->isPrime = isPrime;
intersect->lat = lat;
intersect->vertexIdx = -1;
intersect->sortOrder = -1;
return idx;
}
void
split_link_vertices(Split * split, int idx1, int idx2)
{
SPLIT_ASSERT_VALID_VERTEX_IDX(split, idx1);
SPLIT_ASSERT_VALID_VERTEX_IDX(split, idx2);
split->vertices[idx1].link = idx2;
split->vertices[idx2].link = idx1;
}
void
split_add_hole(Split * split, const LinkedGeoLoop * hole)
{
split->holes[split->holeNum++] = hole;
}
void
split_sort_intersects(Split * split)
{
SPLIT_ASSERT(split->intersectNum % 2 == 0, "intersection number must be even");
/* Collect intesection pointers */
split->sortedIntersects = palloc(split->intersectNum * sizeof(SplitIntersect *));
for (int i = 0; i < split->intersectNum; ++i)
{
SplitIntersect *intersect = &split->intersects[i];
split->sortedIntersects[i] = intersect;
}
/* Sort intersection pointers */
qsort(
split->sortedIntersects,
split->intersectNum,
sizeof(SplitIntersect *),
&split_intersect_ptr_cmp);
/* Assign sort order values to intersections */
for (int i = 0; i < split->intersectNum; ++i)
split->sortedIntersects[i]->sortOrder = i;
}
/**
Sort intersections by latitude
Sort value for points on prime meridian:
* 180 - lat, if lat >= 0
* -180 - lat, if lat < 0
-90 0 90
------*----------+----------*------>
meridian: prime antimeridian prime
value: -180-lat lat 180-lat
*/
int
split_intersect_ptr_cmp(const void *a, const void *b)
{
const SplitIntersect *i1 = *((const SplitIntersect **) a);
const SplitIntersect *i2 = *((const SplitIntersect **) b);
double v1,
v2;
v1 = i1->lat;
if (i1->isPrime)
v1 = ((v1 < 0) ? -M_PI : M_PI) - v1;
v2 = i2->lat;
if (i2->isPrime)
v2 = ((v2 < 0) ? -M_PI : M_PI) - v2;
return (v1 == v2)
? 0
: (v1 < v2) ? -1 : 1;
}
int
split_find_next_vertex(Split * split, int *start)
{
for (int i = *start; i < split->vertexNum; ++i)
{
if (split->vertices[i].latlngPtr)
{
*start = i + 1;
return i;
}
}
return -1;
}
LinkedGeoPolygon *
split_create_polygon_vertex(Split * split, int vertexIdx)
{
LinkedGeoPolygon *polygon;
LinkedGeoLoop *loop;
int idx,
nextIdx,
intersectIdx;
SplitVertex *vertex;
const SplitIntersect *intersect;
short sign,
step;
polygon = palloc0(sizeof(LinkedGeoPolygon));
loop = palloc0(sizeof(LinkedGeoLoop));
add_linked_geo_loop(polygon, loop);
idx = vertexIdx;
vertex = &split->vertices[idx];
sign = vertex->sign;
step = 1; /* vertex array traversal direction */
while (vertex->latlngPtr)
{
/* Add vertex */
add_lat_lng(loop, vertex->latlngPtr);
vertex->latlngPtr = NULL;
/*
* Get indices of the other segment endpoint and potential
* intersection
*/
if (vertex->link > -1 && ((step > 0) == (idx > vertex->link)))
{
nextIdx = vertex->link;
/* Potential intersection is after last ring vertex */
intersectIdx = (nextIdx > idx) ? nextIdx : idx;
}
else
{
nextIdx = idx + step;
/* Potential intersection is after first vertex */
intersectIdx = (nextIdx > idx) ? idx : nextIdx;
}
/* Is there an intersection after the vertex? */
SPLIT_ASSERT_VALID_VERTEX_IDX(split, intersectIdx);
intersect = split_get_intersect_after(split, intersectIdx);
if (intersect)
{
LatLng latlng;
int intersectSortOrder;
/* Add intersection vertex */
split_intersect_get_lat_lng(intersect, sign, &latlng);
add_lat_lng(loop, &latlng);
/* Find next intersection */
intersectSortOrder = (intersect->sortOrder % 2 == 0)
? intersect->sortOrder + 1
: intersect->sortOrder - 1;
intersect = split->sortedIntersects[intersectSortOrder];
intersectIdx = intersect->vertexIdx;
/* Add next intersection vertex */
split_intersect_get_lat_lng(intersect, sign, &latlng);
add_lat_lng(loop, &latlng);
/*
* Does intersecting segment end in the same hemisphere where the
* polygon is located?
*/
step = ((sign > 0) == (intersect->dir == SplitIntersectDir_WE)) ? 1 : -1;
if (step > 0)
{
/* Next vertex is the second endpoint of a segment */
const SplitVertex *segmentStart = &split->vertices[intersectIdx];
if (segmentStart->link > -1 && intersectIdx > segmentStart->link)
nextIdx = segmentStart->link;
else
nextIdx = intersectIdx + 1;
}
else
{
/* Next vertex is the first endpoint of a segment */
nextIdx = intersectIdx;
}
}
idx = nextIdx;
vertex = &split->vertices[idx];
}
/* Assign holes */
split_polygon_assign_holes(split, sign, polygon);
return polygon;
}
void
split_polygon_assign_holes(Split * split, short sign, LinkedGeoPolygon * polygon)
{
const LinkedGeoLoop *outerLoop;
Bbox3 bbox;
outerLoop = polygon->first;
bbox3_from_linked_loop(outerLoop, &bbox);
for (int i = 0; i < split->holeNum; ++i)
{
const LinkedGeoLoop *hole;
short pos = 0;
hole = split->holes[i];
if (!hole)
continue;
/* Check if hole vertices are inside the outher shell of the polygon */
FOREACH_LINKED_LAT_LNG(hole, cur)
{
pos = lat_lng_ring_pos(outerLoop, sign, &bbox, &cur->vertex);
if (pos != 0)
break; /* vertex is either inside or outside */
}
if (pos != -1)
{
/* Add hole loop copy to polygon */
LinkedGeoLoop *hole_copy = copy_linked_geo_loop(hole);
add_linked_geo_loop(polygon, hole_copy);
/* Remove hole from the list */
split->holes[i] = NULL;
}
}
}
const SplitIntersect *
split_get_intersect_after(Split * split, int vertexIdx)
{
int idx;
SPLIT_ASSERT_VALID_VERTEX_IDX(split, vertexIdx);
idx = split->vertices[vertexIdx].intersectIdx;
return (idx > -1)
? &split->intersects[idx]
: NULL;
}
void
split_intersect_get_lat_lng(const SplitIntersect * intersect, short sign, LatLng * latlng)
{
latlng->lat = intersect->lat;
if (intersect->isPrime)
latlng->lng = 0.0;
else
latlng->lng = (sign > 0) ? M_PI : -M_PI;
}
int
count_polygon_vertices(const LinkedGeoPolygon * polygon, int *ringNum)
{
int num = 0;
if (ringNum)
*ringNum = 0;
FOREACH_LINKED_LOOP(polygon, ring)
{
if (ringNum)
++(*ringNum);
num += count_linked_lat_lng(ring);
}
return num;
}
short
lat_lng_ring_pos(const LinkedGeoLoop * ring, short sign, const Bbox3 * bbox, const LatLng * latlng)
{
short signLatlng;
Vect3 vect,
outVect;
LatLng out;
int intersectNum = 0;
Vect3 curVect,
nextVect;
/* Check longitude sign */
signLatlng = SIGN(latlng->lng);
if (signLatlng != 0 && signLatlng != sign)
return -1;
vect3_from_lat_lng(latlng, &vect);
/* Check bbox */
if (!bbox3_contains_vect3(bbox, &vect))
return -1;
/* Create a point that's guaranteed to be outside the polygon */
out.lng = (latlng->lng == 0) ? -sign * 1e-10 : -latlng->lng;
out.lat = latlng->lat;
vect3_from_lat_lng(&out, &outVect);
/* Check if ring is a single vertex exactly matching the point */
if (!ring->first->next)
return true;
/*
* Count a number of intersections between the ring and (latlng, out)
* segment
*/
intersectNum = 0;
vect3_from_lat_lng(&ring->first->vertex, &curVect);
FOREACH_LINKED_LAT_LNG_PAIR(ring, cur, next)
{
short intersect;
/* Check if point matches ring vertex */
if (vect3_eq(&vect, &curVect))
return 0;
/* Next vertex */
vect3_from_lat_lng(&next->vertex, &nextVect);
if (!vect3_eq(&curVect, &nextVect))
{
intersect = segment_intersect(&curVect, &nextVect, &vect, &outVect);
if (intersect == 0)
return 0; /* point on ring segment */
if (intersect > 0)
++intersectNum;
}
curVect = nextVect;
}
return (intersectNum % 2 == 0) ? -1 : 1;
}
short
segment_intersect(const Vect3 * v1, const Vect3 * v2, const Vect3 * u1, const Vect3 * u2)
{
Vect3 vn,
un;
short v1Side,
v2Side,
u1Side,
u2Side;
double normalDot;
/* Normals of V and U planes */
vect3_cross(v1, v2, &vn);
vect3_normalize(&vn);
vect3_cross(u1, u2, &un);
vect3_normalize(&un);
/* Are the planes the same? */
normalDot = vect3_dot(&vn, &un);
if (FP_EQUAL(fabs(normalDot), 1.0))
{
short ret = point_segment_pos(v1, v2, u1);
if (ret == -1)
ret = point_segment_pos(v1, v2, u2);
if (ret == -1)
ret = point_segment_pos(u1, u2, v1);
if (ret == -1)
ret = point_segment_pos(u1, u2, v2);
return ret;
}
/* Which side of other segment are segment endpoints? */
v1Side = SIGN(vect3_dot(&un, v1));
v2Side = SIGN(vect3_dot(&un, v2));
u1Side = SIGN(vect3_dot(&vn, u1));
u2Side = SIGN(vect3_dot(&vn, u2));
/* v1 and v2 are on the same side of U plane */
if (v1Side == v2Side && v1Side != 0)
return -1;
/* u1 and u2 are on the same side of V plane */
if (u1Side == u2Side && u2Side != 0)
return -1;
if (v1Side != v2Side && (v1Side + v2Side) == 0
&& u1Side != u2Side && (u1Side + u2Side) == 0)
{
/* Intersection point */
Vect3 intersect;
vect3_cross(&vn, &un, &intersect);
vect3_normalize(&intersect);
/* Is intersection point inside both arcs? */
if (point_segment_pos(v1, v2, &intersect) != -1
&& point_segment_pos(u1, u2, &intersect) != -1)
{
return 1;
}
/* Try antipodal intersection point */
vect3_scale(&intersect, -1.0);
if (point_segment_pos(v1, v2, &intersect) != -1
&& point_segment_pos(u1, u2, &intersect) != -1)
{
return 1;
}
return -1;
}
return 0;
}
short
point_segment_pos(const Vect3 * v1, const Vect3 * v2, const Vect3 * p)
{
Vect3 middle;
double minSimilarity;
/* Check if point is same as one of segment endpoints */
if (vect3_eq(p, v1) || vect3_eq(p, v2))
return 0;
/* Find vector bisecting anble between segment endpoint vectors */
vect3_sum(v1, v2, &middle);
vect3_normalize(&middle);
/* How similar are endpoint vectors to bisecting vector? */
minSimilarity = vect3_dot(v1, &middle);
if (fabs(1.0 - minSimilarity) > 1e-10)
{
/* Segment is long enough to use dot product test. */
/* If point vector is more similar to bisecting vector, */
/*
* then it must be closer to center, so the point is inside the
* segment.
*/
return (vect3_dot(p, &middle) > minSimilarity) ? 1 : -1;
}
else
{
/* Segment is too short to use dot product test. */
/*
* Check if vectors from segment endpoints to the point are in
* opposite directions.
*/
Vect3 d1,
d2;
vect3_diff(p, v1, &d1);
vect3_normalize(&d1);
vect3_diff(p, v2, &d2);
vect3_normalize(&d2);
return (vect3_dot(&d1, &d2) < 0.0) ? 1 : -1;
}
}
void
add_lat_lng(LinkedGeoLoop * loop, const LatLng * latlng)
{
LinkedLatLng *linked;
if (loop->last)
{
/* Does new vertex exactly match the last one? */
const LatLng *last = &loop->last->vertex;
if (last->lat == latlng->lat && last->lng == latlng->lng)
return;
}
linked = palloc0(sizeof(LinkedLatLng));
linked->vertex.lat = latlng->lat;
linked->vertex.lng = latlng->lng;
add_linked_lat_lng(loop, linked);
}
h3-pg-4.1.3/h3_postgis/src/wkb_split.h 0000664 0000000 0000000 00000001710 14460144644 0017463 0 ustar 00root root 0000000 0000000 /*
* Copyright 2022-2023 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.
*/
#ifndef PGH3_WKB_SPLIT_H
#define PGH3_WKB_SPLIT_H
#include
#include
#include "error.h"
bool
is_linked_polygon_crossed_by_180(const LinkedGeoPolygon * multiPolygon);
LinkedGeoPolygon *
split_linked_polygon_by_180(const LinkedGeoPolygon * multiPolygon);
double
split_180_lat(const LatLng * coord1, const LatLng * coord2);
#endif
h3-pg-4.1.3/h3_postgis/src/wkb_vect3.c 0000664 0000000 0000000 00000004440 14460144644 0017352 0 ustar 00root root 0000000 0000000 /*
* Copyright 2022-2023 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
#include
#include "wkb_vect3.h"
#define FP_EQUAL(v1, v2) ((v1) == (v2) || fabs((v1) - (v2)) < DBL_EPSILON)
void
vect3_from_lat_lng(const LatLng * coord, Vect3 * vect)
{
vect->x = cos(coord->lat) * cos(coord->lng);
vect->y = cos(coord->lat) * sin(coord->lng);
vect->z = sin(coord->lat);
}
void
vect3_to_lat_lng(const Vect3 * vect, LatLng * coord)
{
coord->lng = atan2(vect->y, vect->x);
coord->lat = asin(vect->z);
}
int
vect3_eq(const Vect3 * vect1, const Vect3 * vect2)
{
return FP_EQUAL(vect1->x, vect2->x)
&& FP_EQUAL(vect1->y, vect2->y)
&& FP_EQUAL(vect1->z, vect2->z);
}
void
vect3_normalize(Vect3 * vect)
{
double len = sqrt(vect->x * vect->x + vect->y * vect->y + vect->z * vect->z);
if (len > 0)
{
vect->x = vect->x / len;
vect->y = vect->y / len;
vect->z = vect->z / len;
}
else
{
vect->x = 0;
vect->y = 0;
vect->z = 0;
}
}
void
vect3_sum(const Vect3 * vect1, const Vect3 * vect2, Vect3 * sum)
{
sum->x = vect1->x + vect2->x;
sum->y = vect1->y + vect2->y;
sum->z = vect1->z + vect2->z;
}
void
vect3_diff(const Vect3 * vect1, const Vect3 * vect2, Vect3 * diff)
{
diff->x = vect1->x - vect2->x;
diff->y = vect1->y - vect2->y;
diff->z = vect1->z - vect2->z;
}
void
vect3_scale(Vect3 * vect, double factor)
{
vect->x *= factor;
vect->y *= factor;
vect->z *= factor;
}
void
vect3_cross(const Vect3 * vect1, const Vect3 * vect2, Vect3 * prod)
{
prod->x = vect1->y * vect2->z - vect1->z * vect2->y;
prod->y = vect1->z * vect2->x - vect1->x * vect2->z;
prod->z = vect1->x * vect2->y - vect1->y * vect2->x;
}
double
vect3_dot(const Vect3 * vect1, const Vect3 * vect2)
{
return (vect1->x * vect2->x) + (vect1->y * vect2->y) + (vect1->z * vect2->z);
}
h3-pg-4.1.3/h3_postgis/src/wkb_vect3.h 0000664 0000000 0000000 00000002506 14460144644 0017360 0 ustar 00root root 0000000 0000000 /*
* Copyright 2022-2023 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.
*/
#ifndef PGH3_VECT3_H
#define PGH3_VECT3_H
#include
#include
#include
typedef struct
{
double x;
double y;
double z;
} Vect3;
void
vect3_from_lat_lng(const LatLng * coord, Vect3 * vect);
void
vect3_to_lat_lng(const Vect3 * vect, LatLng * coord);
int
vect3_eq(const Vect3 * vect1, const Vect3 * vect2);
void
vect3_normalize(Vect3 * vect);
void
vect3_sum(const Vect3 * vect1, const Vect3 * vect2, Vect3 * sum);
void
vect3_diff(const Vect3 * vect1, const Vect3 * vect2, Vect3 * diff);
void
vect3_scale(Vect3 * vect, double factor);
void
vect3_cross(const Vect3 * vect1, const Vect3 * vect2, Vect3 * prod);
double
vect3_dot(const Vect3 * vect1, const Vect3 * vect2);
#endif
h3-pg-4.1.3/h3_postgis/test/ 0000775 0000000 0000000 00000000000 14460144644 0015505 5 ustar 00root root 0000000 0000000 h3-pg-4.1.3/h3_postgis/test/CMakeLists.txt 0000664 0000000 0000000 00000001251 14460144644 0020244 0 ustar 00root root 0000000 0000000 set(TESTS
postgis
rasters
)
if(PostgreSQL_REGRESS)
add_test(
NAME "h3_postgis_regress"
COMMAND ${PostgreSQL_REGRESS}
--temp-instance=${CMAKE_BINARY_DIR}/tmp
--bindir=${PostgreSQL_BIN_DIR}
--inputdir=${CMAKE_CURRENT_SOURCE_DIR}
--outputdir=${CMAKE_CURRENT_BINARY_DIR}
--load-extension h3
--load-extension postgis
--load-extension postgis_raster
--load-extension h3_postgis
${TESTS}
)
endif()
if(PostgreSQL_VALIDATE_EXTUPGRADE)
add_test(
NAME "h3_postgis_validate_extupgrade"
COMMAND pg_validate_extupgrade
--extname h3_postgis
--from 4.0.0
--to ${INSTALL_VERSION}
)
endif()
h3-pg-4.1.3/h3_postgis/test/expected/ 0000775 0000000 0000000 00000000000 14460144644 0017306 5 ustar 00root root 0000000 0000000 h3-pg-4.1.3/h3_postgis/test/expected/postgis.out 0000664 0000000 0000000 00000020407 14460144644 0021532 0 ustar 00root root 0000000 0000000 \pset tuples_only on
-- Variables for testing
\set resolution 10
\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)
\set edgecross '\'8003fffffffffff\'::h3index'
\set polar '\'81f2bffffffffff\'::h3index'
\set lat1 84.76455330449812
\set lat2 89.980298101841
\set epsilon 0.0000000000001
\set longPathEndpoint1 '\'842ca2bffffffff\'::h3index'
\set longPathEndpoint2 '\'842e611ffffffff\'::h3index'
-- 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)
-- S-shaped polygon with 4 holes crossing antimeridian
\set transmeridianWithHoles '\'POLYGON((-170 12.5, 170 12.5, 170 7.5, -175 7.5, -175 2.5, 170 2.5, 170 -12.5, -170 -12.5, -170 -7.5, 175 -7.5, 175 -2.5, -170 -2.5, -170 12.5), (-176 11.5, -179 11.5, -179 8.5, -176 8.5, -176 11.5), (174 11.5, 171 11.5, 171 8.5, 174 8.5, 174 11.5), (174 -3.5, 171 -3.5, 171 -6.5, 174 -6.5, 174 -3.5),(-176 -8.5, -179 -8.5, -179 -11.5, -176 -11.5, -176 -8.5))\''::geometry(POLYGON)
-- multipolygon with 2 polygons: one crossing and one not crossing antimeridian
\set transmeridianMulti '\'MULTIPOLYGON(((-175 50, -175 55, 175 55, 175 50, -175 50)), ((170 50, 170 55, 165 55, 165 50, 170 50)))\''::geometry(MULTIPOLYGON)
SELECT h3_lat_lng_to_cell(:degree, :resolution) = '8a63a9a99047fff';
t
-- meters are NOT reprojected
SELECT h3_lat_lng_to_cell(:meter, :resolution) <> '8a63a9a99047fff';
t
-- check back/forth conversion return same hex
SELECT h3_lat_lng_to_cell(h3_cell_to_geometry(:hexagon), :resolution) = '8a63a9a99047fff';
t
-- check num points in boundary
SELECT ST_NPoints(h3_cell_to_boundary_geometry(:hexagon)) = 7;
t
-- 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_lat_lng_to_cell(POINT(360, 2.592131261648213), 1);
RETURN false;
EXCEPTION WHEN OTHERS THEN
RETURN true;
END;
$$;
SET h3.strict TO true;
SELECT h3_test_postgis_nounit();
t
SET h3.strict TO false;
DROP FUNCTION h3_test_postgis_nounit;
-- Test wraparound
\set lon 55.6677199224442
\set lat 12.592131261648213
SELECT h3_lat_lng_to_cell(POINT(:lon, :lat), 7)
= h3_lat_lng_to_cell(POINT(:lon + 360, :lat), 7);
t
SELECT h3_lat_lng_to_cell(POINT(:lon, :lat ), 7)
= h3_lat_lng_to_cell(POINT(:lon, :lat + 360), 7);
t
-- test h3_grid_path_cells_recursive works for long path
SELECT COUNT(*) > 0 FROM (
SELECT h3_grid_path_cells_recursive(:longPathEndpoint1, :longPathEndpoint1)
) q;
t
-- h3_polygon_to_cells works for polygon with two holes
SELECT COUNT(*) = 48 FROM (
SELECT h3_polygon_to_cells(:with2holes, 10)
) q;
t
--
-- Test h3_cell_to_boundary_wkb
--
-- polyfill of geo boundary returns original index
SELECT h3_polygon_to_cells(h3_cell_to_boundary(:hexagon)::geometry::polygon, null, :resolution) = :hexagon;
t
-- the boundary of a non-edgecrossing index is a polygon
SELECT GeometryType(h3_cell_to_boundary_wkb(:hexagon)::geometry) LIKE 'POLYGON';
t
-- the boundary of an edgecrossing index is a multipolygon when split
SELECT GeometryType(h3_cell_to_boundary_wkb(:edgecross)::geometry) LIKE 'MULTIPOLYGON';
t
-- the boundary of a polar cell is a polygon
SELECT GeometryType(h3_cell_to_boundary_wkb(:polar)::geometry) LIKE 'POLYGON';
t
-- check num points in polar cell boundary
SELECT ST_NPoints(h3_cell_to_boundary_geometry(:polar)) = 11;
t
-- check latitude of antimeridian crossing points
SET h3.split_antimeridian TO true;
SELECT every(ABS(ST_Y(p) - :lat1) < :epsilon OR ABS(ST_Y(p) - :lat2) < :epsilon)
FROM (
SELECT (dp).geom AS p FROM (
(SELECT ST_DumpPoints(h3_cell_to_boundary_wkb(:edgecross)::geometry) AS dp)
) AS q1
) AS q2
WHERE ABS(ABS(ST_X(p)) - 180) < :epsilon;
t
--
-- Test h3_cells_to_multi_polygon_wkb
--
-- polygon is split in 4 polygons with 1 hole each
WITH split AS (
SELECT h3_cells_to_multi_polygon_wkb(
array(SELECT h3_polygon_to_cells(:transmeridianWithHoles, 4)))::geometry AS multi),
dp AS (SELECT ST_Dump(multi) AS dp FROM split),
polygons AS (SELECT (dp).geom AS geom FROM dp)
SELECT GeometryType(geom) LIKE 'POLYGON' AND ST_NumInteriorRings(geom) = 1
FROM polygons;
t
t
t
t
-- multipolygon with 2 polygons becomes multipolygon with 3
WITH split AS (
SELECT h3_cells_to_multi_polygon_wkb(
array(SELECT h3_polygon_to_cells(:transmeridianMulti, 3)))::geometry AS multi),
dp AS (SELECT ST_Dump(multi) AS dp FROM split)
SELECT COUNT(*) = 3 FROM dp;
t
h3-pg-4.1.3/h3_postgis/test/expected/rasters.out 0000664 0000000 0000000 00000013016 14460144644 0021523 0 ustar 00root root 0000000 0000000 \pset tuples_only on
\set resolution 9
\set coverage_size 2
\set raster_size 25
\set pixel_size 0.0005
\set value_num 5
\set lat 51.5
\set lng -0.025
CREATE TABLE h3_test_rasters (id SERIAL, rast raster);
INSERT INTO h3_test_rasters (rast) (
WITH
vals AS (
SELECT array_agg(row) AS vals
FROM (
SELECT array_agg((x + y) % :value_num + 1) AS row
FROM
generate_series(1, :raster_size) AS x,
generate_series(1, :raster_size) AS y
GROUP BY y
) t),
rasts AS (
SELECT
ST_AddBand(
ST_MakeEmptyCoverage(
:raster_size, :raster_size,
:raster_size * :coverage_size, :raster_size * :coverage_size,
:lng, :lat,
:pixel_size, -(:pixel_size),
0, 0,
4326),
ARRAY[ROW(1, '8BUI', 1, 0)]::addbandarg[]
) AS rast)
SELECT ST_SetValues(r.rast, 1, 1, 1, v.vals)
FROM rasts r, vals v
);
CREATE FUNCTION h3_test_equal(
v1 double precision,
v2 double precision)
RETURNS boolean
AS $$
SELECT ABS(v1 - v2) < 1e-12;
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
CREATE FUNCTION h3_test_raster_summary_stats_equal(
s1 h3_raster_summary_stats,
s2 h3_raster_summary_stats)
RETURNS boolean
AS $$
SELECT s1 IS NOT NULL AND s2 IS NOT NULL
AND h3_test_equal((s1).count, (s2).count)
AND h3_test_equal((s1).sum, (s2).sum)
AND h3_test_equal((s1).mean, (s2).mean)
AND h3_test_equal((s1).stddev, (s2).stddev)
AND h3_test_equal((s1).min, (s2).min)
AND h3_test_equal((s1).max, (s2).max);
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
CREATE FUNCTION h3_test_raster_class_summary_item_equal(
i1 h3_raster_class_summary_item,
i2 h3_raster_class_summary_item)
RETURNS boolean
AS $$
SELECT i1 IS NOT NULL AND i2 IS NOT NULL
AND h3_test_equal((i1).val, (i2).val)
AND h3_test_equal((i1).count, (i2).count)
AND h3_test_equal((i1).area, (i2).area);
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
-- Results of `h3_raster_summary_clip` and `h3_raster_summary_centroids`
-- should be identical
WITH
clip AS (
SELECT
h3,
h3_raster_summary_stats_agg(stats) AS stats
FROM (
-- h3, stats
SELECT (h3_raster_summary_clip(rast, :resolution)).*
FROM h3_test_rasters
) t
GROUP BY 1),
centroids AS (
SELECT
h3,
h3_raster_summary_stats_agg(stats) AS stats
FROM (
-- h3, stats
SELECT (h3_raster_summary_centroids(rast, :resolution)).*
FROM h3_test_rasters
) t
GROUP BY 1)
SELECT COUNT(*)
FROM clip a FULL OUTER JOIN centroids b ON a.h3 = b.h3
WHERE NOT h3_test_raster_summary_stats_equal(a.stats, b.stats);
0
-- Results of `h3_raster_class_summary_clip` and `h3_raster_class_summary_clip`
-- should be identical
WITH
clip AS (
SELECT
h3,
val,
h3_raster_class_summary_item_agg(summary) AS summary
FROM (
-- h3, val, summary
SELECT (h3_raster_class_summary_clip(rast, :resolution)).*
FROM h3_test_rasters
) t
GROUP BY 1, 2),
centroids AS (
SELECT
h3,
val,
h3_raster_class_summary_item_agg(summary) AS summary
FROM (
-- h3, val, summary
SELECT (h3_raster_class_summary_centroids(rast, :resolution)).*
FROM h3_test_rasters
) t
GROUP BY 1, 2)
SELECT COUNT(*)
FROM clip a FULL OUTER JOIN centroids b ON a.h3 = b.h3 AND a.val = b.val
WHERE NOT h3_test_raster_class_summary_item_equal(a.summary, b.summary);
0
-- Stats aggregation check:
-- stats for a cell intersecting multiple rasters (with aggregation) should be
-- the same when calculated on a union of rasters (without aggregation).
WITH
rast AS (
-- Union all test rasters
SELECT ST_Union(rast) AS rast FROM h3_test_rasters),
middle AS (
-- Find an H3 cell in a bottom-right corner of a first raster
-- (intersecting 4 rasters)
SELECT
h3_lat_lng_to_cell(
ST_MakePoint(
ST_RasterToWorldCoordX(rast, :raster_size),
ST_RasterToWorldCoordY(rast, :raster_size)),
:resolution
) AS h3
FROM rast),
summary1 AS (
-- Get summary from combined raster
SELECT t.stats
FROM (
-- h3, stats
SELECT (h3_raster_summary_clip(rast, :resolution)).*
FROM rast
) t, middle m
WHERE t.h3 = m.h3),
summary2 AS (
-- Get aggregates summary from separate rasters
SELECT h3_raster_summary_stats_agg(t.stats) AS stats
FROM (
-- h3, stats
SELECT (h3_raster_summary_clip(rast, :resolution)).*
FROM h3_test_rasters
) t, middle m
WHERE t.h3 = m.h3
GROUP BY t.h3)
SELECT h3_test_raster_summary_stats_equal(s1.stats, s2.stats)
FROM summary1 s1, summary2 s2;
t
DROP FUNCTION h3_test_raster_class_summary_item_equal(
h3_raster_class_summary_item,
h3_raster_class_summary_item);
DROP FUNCTION h3_test_raster_summary_stats_equal(
h3_raster_summary_stats,
h3_raster_summary_stats);
DROP FUNCTION h3_test_equal(double precision, double precision);
DROP TABLE h3_test_rasters;
h3-pg-4.1.3/h3_postgis/test/sql/ 0000775 0000000 0000000 00000000000 14460144644 0016304 5 ustar 00root root 0000000 0000000 h3-pg-4.1.3/h3_postgis/test/sql/postgis.sql 0000664 0000000 0000000 00000020316 14460144644 0020517 0 ustar 00root root 0000000 0000000 \pset tuples_only on
-- Variables for testing
\set resolution 10
\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)
\set edgecross '\'8003fffffffffff\'::h3index'
\set polar '\'81f2bffffffffff\'::h3index'
\set lat1 84.76455330449812
\set lat2 89.980298101841
\set epsilon 0.0000000000001
\set longPathEndpoint1 '\'842ca2bffffffff\'::h3index'
\set longPathEndpoint2 '\'842e611ffffffff\'::h3index'
-- 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)
-- S-shaped polygon with 4 holes crossing antimeridian
\set transmeridianWithHoles '\'POLYGON((-170 12.5, 170 12.5, 170 7.5, -175 7.5, -175 2.5, 170 2.5, 170 -12.5, -170 -12.5, -170 -7.5, 175 -7.5, 175 -2.5, -170 -2.5, -170 12.5), (-176 11.5, -179 11.5, -179 8.5, -176 8.5, -176 11.5), (174 11.5, 171 11.5, 171 8.5, 174 8.5, 174 11.5), (174 -3.5, 171 -3.5, 171 -6.5, 174 -6.5, 174 -3.5),(-176 -8.5, -179 -8.5, -179 -11.5, -176 -11.5, -176 -8.5))\''::geometry(POLYGON)
-- multipolygon with 2 polygons: one crossing and one not crossing antimeridian
\set transmeridianMulti '\'MULTIPOLYGON(((-175 50, -175 55, 175 55, 175 50, -175 50)), ((170 50, 170 55, 165 55, 165 50, 170 50)))\''::geometry(MULTIPOLYGON)
SELECT h3_lat_lng_to_cell(:degree, :resolution) = '8a63a9a99047fff';
-- meters are NOT reprojected
SELECT h3_lat_lng_to_cell(:meter, :resolution) <> '8a63a9a99047fff';
-- check back/forth conversion return same hex
SELECT h3_lat_lng_to_cell(h3_cell_to_geometry(:hexagon), :resolution) = '8a63a9a99047fff';
-- check num points in boundary
SELECT ST_NPoints(h3_cell_to_boundary_geometry(:hexagon)) = 7;
-- 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_lat_lng_to_cell(POINT(360, 2.592131261648213), 1);
RETURN false;
EXCEPTION WHEN OTHERS THEN
RETURN true;
END;
$$;
SET h3.strict TO true;
SELECT h3_test_postgis_nounit();
SET h3.strict TO false;
DROP FUNCTION h3_test_postgis_nounit;
-- Test wraparound
\set lon 55.6677199224442
\set lat 12.592131261648213
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);
-- test h3_grid_path_cells_recursive works for long path
SELECT COUNT(*) > 0 FROM (
SELECT h3_grid_path_cells_recursive(:longPathEndpoint1, :longPathEndpoint1)
) q;
-- h3_polygon_to_cells works for polygon with two holes
SELECT COUNT(*) = 48 FROM (
SELECT h3_polygon_to_cells(:with2holes, 10)
) q;
--
-- Test h3_cell_to_boundary_wkb
--
-- polyfill of geo boundary returns original index
SELECT h3_polygon_to_cells(h3_cell_to_boundary(:hexagon)::geometry::polygon, null, :resolution) = :hexagon;
-- the boundary of a non-edgecrossing index is a polygon
SELECT GeometryType(h3_cell_to_boundary_wkb(:hexagon)::geometry) LIKE 'POLYGON';
-- the boundary of an edgecrossing index is a multipolygon when split
SELECT GeometryType(h3_cell_to_boundary_wkb(:edgecross)::geometry) LIKE 'MULTIPOLYGON';
-- the boundary of a polar cell is a polygon
SELECT GeometryType(h3_cell_to_boundary_wkb(:polar)::geometry) LIKE 'POLYGON';
-- check num points in polar cell boundary
SELECT ST_NPoints(h3_cell_to_boundary_geometry(:polar)) = 11;
-- check latitude of antimeridian crossing points
SET h3.split_antimeridian TO true;
SELECT every(ABS(ST_Y(p) - :lat1) < :epsilon OR ABS(ST_Y(p) - :lat2) < :epsilon)
FROM (
SELECT (dp).geom AS p FROM (
(SELECT ST_DumpPoints(h3_cell_to_boundary_wkb(:edgecross)::geometry) AS dp)
) AS q1
) AS q2
WHERE ABS(ABS(ST_X(p)) - 180) < :epsilon;
--
-- Test h3_cells_to_multi_polygon_wkb
--
-- polygon is split in 4 polygons with 1 hole each
WITH split AS (
SELECT h3_cells_to_multi_polygon_wkb(
array(SELECT h3_polygon_to_cells(:transmeridianWithHoles, 4)))::geometry AS multi),
dp AS (SELECT ST_Dump(multi) AS dp FROM split),
polygons AS (SELECT (dp).geom AS geom FROM dp)
SELECT GeometryType(geom) LIKE 'POLYGON' AND ST_NumInteriorRings(geom) = 1
FROM polygons;
-- multipolygon with 2 polygons becomes multipolygon with 3
WITH split AS (
SELECT h3_cells_to_multi_polygon_wkb(
array(SELECT h3_polygon_to_cells(:transmeridianMulti, 3)))::geometry AS multi),
dp AS (SELECT ST_Dump(multi) AS dp FROM split)
SELECT COUNT(*) = 3 FROM dp;
h3-pg-4.1.3/h3_postgis/test/sql/rasters.sql 0000664 0000000 0000000 00000013004 14460144644 0020506 0 ustar 00root root 0000000 0000000 \pset tuples_only on
\set resolution 9
\set coverage_size 2
\set raster_size 25
\set pixel_size 0.0005
\set value_num 5
\set lat 51.5
\set lng -0.025
CREATE TABLE h3_test_rasters (id SERIAL, rast raster);
INSERT INTO h3_test_rasters (rast) (
WITH
vals AS (
SELECT array_agg(row) AS vals
FROM (
SELECT array_agg((x + y) % :value_num + 1) AS row
FROM
generate_series(1, :raster_size) AS x,
generate_series(1, :raster_size) AS y
GROUP BY y
) t),
rasts AS (
SELECT
ST_AddBand(
ST_MakeEmptyCoverage(
:raster_size, :raster_size,
:raster_size * :coverage_size, :raster_size * :coverage_size,
:lng, :lat,
:pixel_size, -(:pixel_size),
0, 0,
4326),
ARRAY[ROW(1, '8BUI', 1, 0)]::addbandarg[]
) AS rast)
SELECT ST_SetValues(r.rast, 1, 1, 1, v.vals)
FROM rasts r, vals v
);
CREATE FUNCTION h3_test_equal(
v1 double precision,
v2 double precision)
RETURNS boolean
AS $$
SELECT ABS(v1 - v2) < 1e-12;
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
CREATE FUNCTION h3_test_raster_summary_stats_equal(
s1 h3_raster_summary_stats,
s2 h3_raster_summary_stats)
RETURNS boolean
AS $$
SELECT s1 IS NOT NULL AND s2 IS NOT NULL
AND h3_test_equal((s1).count, (s2).count)
AND h3_test_equal((s1).sum, (s2).sum)
AND h3_test_equal((s1).mean, (s2).mean)
AND h3_test_equal((s1).stddev, (s2).stddev)
AND h3_test_equal((s1).min, (s2).min)
AND h3_test_equal((s1).max, (s2).max);
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
CREATE FUNCTION h3_test_raster_class_summary_item_equal(
i1 h3_raster_class_summary_item,
i2 h3_raster_class_summary_item)
RETURNS boolean
AS $$
SELECT i1 IS NOT NULL AND i2 IS NOT NULL
AND h3_test_equal((i1).val, (i2).val)
AND h3_test_equal((i1).count, (i2).count)
AND h3_test_equal((i1).area, (i2).area);
$$ LANGUAGE SQL IMMUTABLE PARALLEL SAFE;
-- Results of `h3_raster_summary_clip` and `h3_raster_summary_centroids`
-- should be identical
WITH
clip AS (
SELECT
h3,
h3_raster_summary_stats_agg(stats) AS stats
FROM (
-- h3, stats
SELECT (h3_raster_summary_clip(rast, :resolution)).*
FROM h3_test_rasters
) t
GROUP BY 1),
centroids AS (
SELECT
h3,
h3_raster_summary_stats_agg(stats) AS stats
FROM (
-- h3, stats
SELECT (h3_raster_summary_centroids(rast, :resolution)).*
FROM h3_test_rasters
) t
GROUP BY 1)
SELECT COUNT(*)
FROM clip a FULL OUTER JOIN centroids b ON a.h3 = b.h3
WHERE NOT h3_test_raster_summary_stats_equal(a.stats, b.stats);
-- Results of `h3_raster_class_summary_clip` and `h3_raster_class_summary_clip`
-- should be identical
WITH
clip AS (
SELECT
h3,
val,
h3_raster_class_summary_item_agg(summary) AS summary
FROM (
-- h3, val, summary
SELECT (h3_raster_class_summary_clip(rast, :resolution)).*
FROM h3_test_rasters
) t
GROUP BY 1, 2),
centroids AS (
SELECT
h3,
val,
h3_raster_class_summary_item_agg(summary) AS summary
FROM (
-- h3, val, summary
SELECT (h3_raster_class_summary_centroids(rast, :resolution)).*
FROM h3_test_rasters
) t
GROUP BY 1, 2)
SELECT COUNT(*)
FROM clip a FULL OUTER JOIN centroids b ON a.h3 = b.h3 AND a.val = b.val
WHERE NOT h3_test_raster_class_summary_item_equal(a.summary, b.summary);
-- Stats aggregation check:
-- stats for a cell intersecting multiple rasters (with aggregation) should be
-- the same when calculated on a union of rasters (without aggregation).
WITH
rast AS (
-- Union all test rasters
SELECT ST_Union(rast) AS rast FROM h3_test_rasters),
middle AS (
-- Find an H3 cell in a bottom-right corner of a first raster
-- (intersecting 4 rasters)
SELECT
h3_lat_lng_to_cell(
ST_MakePoint(
ST_RasterToWorldCoordX(rast, :raster_size),
ST_RasterToWorldCoordY(rast, :raster_size)),
:resolution
) AS h3
FROM rast),
summary1 AS (
-- Get summary from combined raster
SELECT t.stats
FROM (
-- h3, stats
SELECT (h3_raster_summary_clip(rast, :resolution)).*
FROM rast
) t, middle m
WHERE t.h3 = m.h3),
summary2 AS (
-- Get aggregates summary from separate rasters
SELECT h3_raster_summary_stats_agg(t.stats) AS stats
FROM (
-- h3, stats
SELECT (h3_raster_summary_clip(rast, :resolution)).*
FROM h3_test_rasters
) t, middle m
WHERE t.h3 = m.h3
GROUP BY t.h3)
SELECT h3_test_raster_summary_stats_equal(s1.stats, s2.stats)
FROM summary1 s1, summary2 s2;
DROP FUNCTION h3_test_raster_class_summary_item_equal(
h3_raster_class_summary_item,
h3_raster_class_summary_item);
DROP FUNCTION h3_test_raster_summary_stats_equal(
h3_raster_summary_stats,
h3_raster_summary_stats);
DROP FUNCTION h3_test_equal(double precision, double precision);
DROP TABLE h3_test_rasters;
h3-pg-4.1.3/include/ 0000775 0000000 0000000 00000000000 14460144644 0014067 5 ustar 00root root 0000000 0000000 h3-pg-4.1.3/include/CMakeLists.txt 0000664 0000000 0000000 00000000431 14460144644 0016625 0 ustar 00root root 0000000 0000000 add_library(postgresql_h3_shared
OBJECT error.c
)
target_link_libraries(postgresql_h3_shared
PRIVATE PostgreSQL::PostgreSQL
)
target_include_directories(postgresql_h3_shared
INTERFACE ./
)
set_target_properties(postgresql_h3_shared PROPERTIES POSITION_INDEPENDENT_CODE True)
h3-pg-4.1.3/include/constants.h 0000664 0000000 0000000 00000000204 14460144644 0016250 0 ustar 00root root 0000000 0000000 #ifndef H3_CONSTANTS_H
#define H3_CONSTANTS_H
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#endif /* H3_CONSTANTS_H */
h3-pg-4.1.3/include/deprecate.h 0000664 0000000 0000000 00000002372 14460144644 0016200 0 ustar 00root root 0000000 0000000 /*
* Copyright 2023 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
#include // PG_FUNCTION_INFO_V1
/* Inspired by PostGIS legacy function handling */
/* https://github.com/postgis/postgis/blob/master/postgis/postgis_legacy.c */
#define H3_DEPRECATE(version, funcname) \
PGDLLEXPORT PG_FUNCTION_INFO_V1(funcname); \
Datum funcname(PG_FUNCTION_ARGS) \
{ \
ereport(ERROR, (\
errcode(ERRCODE_FEATURE_NOT_SUPPORTED), \
errmsg("A stored procedure tried to use deprecated C function '%s'", \
__func__), \
errdetail("Library function '%s' was deprecated in h3 %s", \
__func__, version), \
errhint("Consider running: ALTER EXTENSION h3 UPDATE") \
)); \
PG_RETURN_POINTER(NULL); \
}
h3-pg-4.1.3/include/error.c 0000664 0000000 0000000 00000000375 14460144644 0015371 0 ustar 00root root 0000000 0000000 #include
void
h3_assert(int error)
{
if (error)
ereport(ERROR, (
errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
errmsg("error code: %i", error),
errhint("https://h3geo.org/docs/library/errors#table-of-error-codes")));
}
h3-pg-4.1.3/include/error.h 0000664 0000000 0000000 00000002474 14460144644 0015400 0 ustar 00root root 0000000 0000000 /*
* Copyright 2023 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.
*/
#ifndef H3_ERROR_H
#define H3_ERROR_H
void h3_assert(int error);
#define ASSERT(condition, code, msg, ...) \
if (0 == (condition)) ereport(ERROR, ( \
errcode(code), \
errmsg(msg, ##__VA_ARGS__) \
))
#define ENSURE_TYPEFUNC_COMPOSITE(x) \
ASSERT( \
x == TYPEFUNC_COMPOSITE, \
ERRCODE_INVALID_PARAMETER_VALUE, \
"Function returning record called in context " \
"that cannot accept type record" \
)
#define H3_DEPRECATION(msg) \
ereport(WARNING, ( \
errmsg("Deprecated: %s", msg) \
))
#define DEBUG(msg, ...) \
ereport(NOTICE, ( \
errmsg(msg, ##__VA_ARGS__) \
))
#define DEBUG_H3INDEX(h3index) DEBUG("index: %lx", h3index)
#endif /* H3_ERROR_H */
h3-pg-4.1.3/include/type.h 0000664 0000000 0000000 00000003206 14460144644 0015222 0 ustar 00root root 0000000 0000000 /*
* Copyright 2023 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.
*/
#ifndef H3_TYPE_H
#define H3_TYPE_H
#include
/*
* DatumGetH3Index
* Returns H3 index value of a datum.
*
* Note: this macro hides whether h3 index is pass by value or by reference.
*/
#ifdef USE_FLOAT8_BYVAL
#define DatumGetH3Index(X) ((H3Index) (X))
#else
#define DatumGetH3Index(X) (* ((H3Index *) DatumGetPointer(X)))
#endif
/*
* H3IndexGetDatum
* Returns datum representation for an H3 index.
*
* Note: if H3 index is pass by reference, this function returns a reference
* to palloc'd space.
*/
#ifdef USE_FLOAT8_BYVAL
#define H3IndexGetDatum(X) ((Datum) (X))
#else
#define H3IndexGetDatum(X) Int64GetDatum((int64) (X))
#endif
/* Macros for fetching arguments and returning results of h3 index type */
#define PG_GETARG_H3INDEX(n) DatumGetH3Index(PG_GETARG_DATUM(n))
#define PG_RETURN_H3INDEX(x) return H3IndexGetDatum(x)
/* 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
#endif /* H3_TYPE_H */
h3-pg-4.1.3/scripts/ 0000775 0000000 0000000 00000000000 14460144644 0014133 5 ustar 00root root 0000000 0000000 h3-pg-4.1.3/scripts/bundle 0000775 0000000 0000000 00000000160 14460144644 0015327 0 ustar 00root root 0000000 0000000 #!/usr/bin/env bash
git clean -xdf
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --target=pgxn
h3-pg-4.1.3/scripts/develop 0000775 0000000 0000000 00000000302 14460144644 0015512 0 ustar 00root root 0000000 0000000 #!/usr/bin/env bash
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
sudo cmake --install build --component h3-pg
ctest --test-dir build --output-on-failure --build-config Release
h3-pg-4.1.3/scripts/documentation 0000775 0000000 0000000 00000000610 14460144644 0016727 0 ustar 00root root 0000000 0000000 #!/usr/bin/env bash
# ensure we are in script dir
cd "$(dirname "$0")"
# go to python project dir
cd sql2doc
# ensure dependencies are present
poetry install
# generate markdown from sql files
poetry run -q -- python generate.py \
-g "API Reference" "../../h3/sql/install/*.sql" \
-g "PostGIS Integration" "../../h3_postgis/sql/install/*.sql" \
> "../../docs/api.md"
h3-pg-4.1.3/scripts/sql2doc/ 0000775 0000000 0000000 00000000000 14460144644 0015502 5 ustar 00root root 0000000 0000000 h3-pg-4.1.3/scripts/sql2doc/Pipfile 0000664 0000000 0000000 00000000171 14460144644 0017014 0 ustar 00root root 0000000 0000000 [[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true
[dev-packages]
[packages]
lark-parser = "*"
h3-pg-4.1.3/scripts/sql2doc/generate.py 0000664 0000000 0000000 00000031753 14460144644 0017657 0 ustar 00root root 0000000 0000000 """
The concept:
We don't want to manually keep API docs in sync with SQL files.
So instead we should generate the docs from the sql/install/*.sql files.
We have the following things to document:
* Type
* Cast (put in same section as the type)
* Operator
* Function
* Aggregate function
Some functions do not need docs, we can signal this by not applying a comment.
This is internal operator functions for example.
We should parse the sql files, extract the above, and then document all things that
have comments applied.
We should probably hardcode a list of things that should not be documented, so we can
fail if new function are undocumented.
"""
import argparse
import glob
import re
from pathlib import Path
from lark import Lark, Transformer, v_args, visitors
import sys #TEST
# see PGXN::API::Indexer::_clean_html_body
def to_anchor(text):
text = re.sub(r"[^\w\s\(\)-]", "", text) # approximating processing done in Text::Markdown
text = re.sub(r"^([^a-zA-Z])", r"L\1", text)
text = re.sub(r"[^a-zA-Z0-9_:.-]+", ".", text)
return "#" + text
def md_heading(text, level=0):
return "#" * (level + 1) + " " + text
class Context:
level = 0
def __init__(self, statements_by_refid={}):
self.statements_by_refid = statements_by_refid
self.level = 0
class StmtBase:
level = 0
newline_before = True
newline_after = True
decorators = {}
def __init__(self, level=-1):
self.level = level
def set_decorators(self, decorators):
self.decorators = decorators
def get_decorator(self, key):
return self.decorators[key] if self.has_decorator(key) else None
def has_decorator(self, key):
return key in self.decorators
def is_internal(self):
return self.has_decorator("internal")
def is_deprecated(self):
return self.has_decorator("deprecated")
def is_visible(self):
return not self.is_internal() and not self.is_deprecated()
def get_refid(self):
return self.get_decorator("refid")
def get_ref_text(self):
return str(self)
def get_anchor(self):
if not self.is_visible() or self.level < 0:
return None
return to_anchor(str(self))
def get_refs(self, statements_by_refid):
ids = self.get_decorator("ref") or []
return [statements_by_refid[refid] for refid in ids if refid in statements_by_refid]
def to_ref(self):
return '{}'.format(self.get_anchor(), self.get_ref_text())
def to_md(self, context):
if not self.is_visible():
return ""
md = str(self)
if self.level > -1:
md = md_heading(md, self.level)
if self.newline_before:
md = "\n" + md
# availability
availability = self.get_decorator("availability")
if availability:
md += f"\n*Since v{availability}*"
# references
refs = self.get_refs(context.statements_by_refid)
if len(refs) > 0:
md += "\n\nSee also: "
md += ", ".join([ref.to_ref() for ref in refs])
if self.newline_after:
md += "\n"
return md
def __str__(self):
raise Execepion("Not implemented")
class Argument:
def __init__(self, argmode, name, argtype, default):
self.argmode = argmode
self.name = name
self.argtype = argtype
self.default = default
def get_typestr(self):
s = "`{}`".format(self.argtype)
if self.default:
s = "[{} = {}]".format(s, self.default)
return s
def __str__(self):
s = ""
if self.argmode:
s += self.argmode + " "
if self.name:
s += self.name + " "
s += "`{}`".format(self.argtype)
if self.default:
s = "[{} = {}]".format(s, self.default)
return s
class Column:
def __init__(self, name, coltype):
self.name = name;
self.coltype = coltype;
def __str__(self):
return "{} `{}`".format(self.name, self.coltype)
class FunctionReturnsBase:
pass
class FunctionReturns(FunctionReturnsBase):
def __init__(self, rettype):
self.rettype = rettype
def __str__(self):
return "`{}`".format(self.rettype)
class FunctionReturnsSet(FunctionReturns):
def __str__(self):
return "SETOF " + super().__str__()
class FunctionReturnsTable(FunctionReturnsBase):
def __init__(self, columns):
self.columns = columns
def __str__(self):
return "TABLE (" + ", ".join([str(col) for col in self.columns]) + ")";
class CustomMd(StmtBase):
def __init__(self, line):
super().__init__()
self.newline_after = False
match = re.match(r"(#+)\s*(.*)", line)
if match:
self.newline_before = True
self.level = max(0, len(match[1]) - 1)
self.line = match[2]
else:
self.newline_before = False
self.level = -1
self.line = line
def update_level(self, context):
if self.level > -1:
context.level = max(0, self.level)
def __str__(self):
return self.line
class CreateFunctionStmt(StmtBase):
def __init__(self, name: str, arguments, returns: FunctionReturnsBase):
super().__init__(2)
self.name = name
self.arguments = arguments or []
self.returns = returns
def get_ref_text(self):
return "{}({})".format(
self.name,
", ".join([arg.get_typestr() for arg in self.arguments]))
def __str__(self):
return "{}({}) ⇒ {}".format(
self.name,
", ".join([str(arg) for arg in self.arguments]),
self.returns)
class CreateAggregateStmt(StmtBase):
def __init__(self, name: str, arguments):
super().__init__(2)
self.name = name
self.arguments = arguments or []
def get_ref_text(self):
return "{}(setof {})".format(
self.name,
", ".join([arg.get_typestr() for arg in self.arguments]))
def __str__(self):
return "{}(setof {})".format(
self.name,
", ".join([str(arg) for arg in self.arguments]))
class CreateTypeStmt(StmtBase):
def __str__(self):
return ""
class CreateCastStmt(StmtBase):
def __init__(self, source, target):
super().__init__(2)
self.source = source
self.target = target
def __str__(self):
return "`{}` :: `{}`".format(self.source, self.target)
class CreateOperatorStmt(StmtBase):
def __init__(self, name, left, right):
super().__init__(2)
self.name = name
self.left = left
self.right = right
def __str__(self):
return "Operator: `{}` {} `{}`".format(self.left, self.name, self.right)
class CreateCommentStmt(StmtBase):
def __init__(self, text):
super().__init__()
self.text = text
def __str__(self):
return self.text
class SQLTransformer(Transformer):
def start(self, statements):
# flatten
flat = [item for sublist in statements for item in sublist]
return flat
@v_args(inline=True)
def custom_decorated_statement(self, decorators, statement = None):
if not statement:
raise visitors.Discard()
if decorators:
statement.set_decorators(decorators)
return statement
def custom_decorators(self, lines):
decorators = {}
for line in lines:
try:
key, value = line.split(":")
key = str(key).lower()
if key in ["ref"]:
decorators[key] = [v.strip() for v in value.split(",")]
else:
decorators[key] = value.strip()
except:
decorators[str(line).lower()] = True
return decorators
def custom_md_statement(self, children):
return children
# -- MARKDOWN --------------------------------------------------------------
@v_args(inline=True)
def custom_markdown(self, line=""):
line = re.sub(r"^--\|[ \t]?", '', line)
return CustomMd(line)
# -- CREATE TYPE -----------------------------------------------------------
def create_type_stmt(self, children):
return CreateTypeStmt()
# -- CREATE CAST -----------------------------------------------------------
@v_args(inline=True)
def create_cast_stmt(self, source, target, *children):
return CreateCastStmt(source, target)
# -- CREATE OPERATOR -------------------------------------------------------
@v_args(inline=True)
def create_oper_stmt(self, name, options):
return CreateOperatorStmt(name, options['LEFTARG'], options['RIGHTARG'])
def create_oper_opts(self, opts):
return {key: value for [key, value] in opts}
@v_args(inline=True)
def create_oper_opt(self, option, value=None):
return [str(option), value]
# -- CREATE FUNCTION -------------------------------------------------------
@v_args(inline=True)
def create_fun_ret_table_columns(self, columns):
return FunctionReturnsTable(columns)
def create_fun_rettype(self, children):
rettype = children[1]
if children[0] is not None:
return FunctionReturnsSet(rettype)
return FunctionReturns(rettype)
def column_list(self, children):
return children
@v_args(inline=True)
def column(self, name: str, coltype: str):
return Column(name, coltype)
@v_args(inline=True)
def create_func_stmt(self, name: str, arguments, returns, *opts):
# skip internal functions
if name.startswith("__"):
raise visitors.Discard()
return CreateFunctionStmt(name, arguments, returns)
# -- CREATE AGGREGATE ------------------------------------------------------
@v_args(inline=True)
def create_agg_stmt(self, name: str, arguments, *params):
return CreateAggregateStmt(name, arguments)
# -- CREATE COMMENT --------------------------------------------------------
@v_args(inline=True)
def comment_on_stmt(self, child, text):
return CreateCommentStmt(text)
# -- FUNCTION OR AGGREGATE ARGUMENTS ---------------------------------------
def argument_list(self, children):
return children
@v_args(inline=True)
def argument(self, argmode, name, argtype, default=None):
return Argument(argmode, name, argtype, default)
# -- CREATE OPERATOR CLASS -------------------------------------------------
def create_opcl_stmt(self, children):
raise visitors.Discard()
# -- SIMPLE RULES ----------------------------------------------------------
true = lambda self, _: "`true`"
false = lambda self, _: "`false`"
number = v_args(inline=True)(int)
def fun_name(self, children):
return children[1]
@v_args(inline=True)
def string(self, s):
return s[1:-1].replace('\\"', '"')
# -- TERMINALS -------------------------------------------------------------
def SIGNED_NUMBER(self, children):
return int(children)
def CNAME(self, cname):
return str(cname)
def OPERATOR(self, name):
return str(name)
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument(
'--group', '-g',
nargs=2, metavar=('header', 'glob'),
action='append',
help='Globs for each group of SQL install files')
return parser.parse_args()
def create_parser():
here = Path(__file__).parent
parser = Lark.open(
here / "sql.lark",
parser="lalr",
maybe_placeholders=True)
return parser
def process_group(parser, group, statements_by_refid):
[header, files_glob] = group
statements = []
paths = glob.glob(files_glob)
for path in sorted(paths):
group_statements = parse_file(parser, path)
# Add referenced statements to map
for statement in group_statements:
refid = statement.get_refid()
if refid:
statements_by_refid[refid] = statement
statements += group_statements
return (header, statements)
# return flat list of statements in file
def parse_file(parser, path):
with open(path) as fd:
sql = fd.read()
tree = parser.parse(sql)
statements = SQLTransformer(visit_tokens=True).transform(tree)
return statements
def statements_to_md(statements, context):
items = [stmt.to_md(context) for stmt in statements]
return [item for item in items if len(item) > 0]
def main():
args = parse_args()
parser = create_parser()
groups = []
statements_by_refid = {}
# Process groups
for item in args.group:
group = process_group(parser, item, statements_by_refid)
groups.append(group)
# Output
md = ""
for group in groups:
[header, statements] = group
md += md_heading(header) + "\n"
md += "\n".join(statements_to_md(statements, Context(statements_by_refid))) + "\n"
print(md)
if __name__ == "__main__":
main()
h3-pg-4.1.3/scripts/sql2doc/poetry.lock 0000664 0000000 0000000 00000001245 14460144644 0017700 0 ustar 00root root 0000000 0000000 [[package]]
name = "lark-parser"
version = "0.12.0"
description = "a modern parsing library"
category = "main"
optional = false
python-versions = "*"
[package.extras]
atomic-cache = ["atomicwrites"]
nearley = ["js2py"]
regex = ["regex"]
[metadata]
lock-version = "1.1"
python-versions = "^3.10"
content-hash = "13b79c3b8dcbda6768897ce2de93db42bde7daba97ed35e49cc12468f26e873d"
[metadata.files]
lark-parser = [
{file = "lark-parser-0.12.0.tar.gz", hash = "sha256:15967db1f1214013dca65b1180745047b9be457d73da224fcda3d9dd4e96a138"},
{file = "lark_parser-0.12.0-py2.py3-none-any.whl", hash = "sha256:0eaf30cb5ba787fe404d73a7d6e61df97b21d5a63ac26c5008c78a494373c675"},
]
h3-pg-4.1.3/scripts/sql2doc/pyproject.toml 0000664 0000000 0000000 00000000513 14460144644 0020415 0 ustar 00root root 0000000 0000000 [tool.poetry]
name = "documentation"
version = "1.0.0"
description = "Autogenerate postgres extension documentation from sql files"
authors = ["Zacharias Knudsen "]
[tool.poetry.dependencies]
python = "^3.10"
lark-parser = "^0.12.0"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
h3-pg-4.1.3/scripts/sql2doc/sql.lark 0000664 0000000 0000000 00000017742 14460144644 0017167 0 ustar 00root root 0000000 0000000 // statement list
start: custom_md_statement (";" custom_md_statement)* ";"?
// markdown or statement
custom_md_statement: (custom_markdown)* custom_decorated_statement
custom_decorated_statement: [custom_decorators] statement
// statement
?statement: create_type_stmt
| create_cast_stmt
| create_opcl_stmt
| create_oper_stmt
| create_func_stmt
| create_agg_stmt
| comment_on_stmt
custom_decorators: ("--@" /([^\n])+/)+
custom_markdown: /--\|[ \t]?([^\n])+/
| "--|\n"
// -----------------------------------------------------------------------------
// --------------- Basic SQL below ---------------------------------------------
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// CREATE TYPE name ...
create_type_stmt: "CREATE" "TYPE" CNAME "AS"? ("(" /([^\)])+/ ")")?
// -----------------------------------------------------------------------------
// CREATE CAST ...
create_cast_stmt: "CREATE" "CAST" "(" DATATYPE "AS" DATATYPE ")" "WITH" "FUNCTION" CNAME "(" /([^\)])+/ ")"
// -----------------------------------------------------------------------------
// CREATE OPERATOR CLASS name [ DEFAULT ] FOR TYPE data_type
// USING index_method [ FAMILY family_name ] AS
// { OPERATOR strategy_number operator_name [ ( op_type, op_type ) ] [ FOR SEARCH | FOR ORDER BY sort_family_name ]
// | FUNCTION support_number [ ( op_type [ , op_type ] ) ] function_name ( argument_type [, ...] )
// | STORAGE storage_type
// } [, ... ]
create_opcl_stmt: "CREATE" "OPERATOR" "CLASS" CNAME "DEFAULT"? "FOR" "TYPE" CNAME "USING" CNAME "AS" create_opcl_list
create_opcl_opts: "OPERATOR" SIGNED_NUMBER OPERATOR
| "FUNCTION" SIGNED_NUMBER fun_name "(" [argument_list] ")"
create_opcl_list: create_opcl_opts ("," create_opcl_opts)*
// -----------------------------------------------------------------------------
// CREATE OPERATOR name (
// PROCEDURE = function_name
// [, LEFTARG = left_type ] [, RIGHTARG = right_type ]
// [, COMMUTATOR = com_op ] [, NEGATOR = neg_op ]
// [, RESTRICT = res_proc ] [, JOIN = join_proc ]
// [, HASHES ] [, MERGES ]
// )
create_oper_stmt: "CREATE" "OPERATOR" OPERATOR "(" create_oper_opts ")"
create_oper_opt: /PROCEDURE/ "=" CNAME
| /LEFTARG/ "=" DATATYPE
| /RIGHTARG/ "=" DATATYPE
| /COMMUTATOR/ "=" OPERATOR
| /NEGATOR/ "=" OPERATOR
| /RESTRICT/ "=" CNAME
| /JOIN/ "=" CNAME
| /HASHES/
| /MERGES/
create_oper_opts: create_oper_opt ("," create_oper_opt)*
// -----------------------------------------------------------------------------
// CREATE [ OR REPLACE ] FUNCTION
// name ( [ [ argmode ] [ argname ] argtype [ { DEFAULT | = } default_expr ] [, ...] ] )
// [ RETURNS rettype
// | RETURNS TABLE ( column_name column_type [, ...] ) ]
// { LANGUAGE lang_name
// | TRANSFORM { FOR TYPE type_name } [, ... ]
// | WINDOW
// | IMMUTABLE | STABLE | VOLATILE | [ NOT ] LEAKPROOF
// | CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT
// | [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER
// | COST execution_cost
// | ROWS result_rows
// | SET configuration_parameter { TO value | = value | FROM CURRENT }
// | AS 'definition'
// | AS 'obj_file', 'link_symbol'
// } ...
// [ WITH ( attribute [, ...] ) ]
create_func_stmt: "CREATE" ("OR" "REPLACE")? "FUNCTION" fun_name "(" [argument_list] ")" [create_fun_rets] create_fun_opts*
?create_fun_rets: ("RETURNS" "TABLE" "(" create_fun_ret_table_columns ")")
| ("RETURNS" create_fun_rettype)
create_fun_opts: "LANGUAGE" (CNAME|"'" CNAME "'")
| ("IMMUTABLE" | "STABLE" | "VOLATILE" | ("NOT"? "LEAKPROOF"))
| (("CALLED" "ON" "NULL" "INPUT") | ("RETURNS" "NULL" "ON" "NULL" "INPUT") | "STRICT")
| ("PARALLEL" ("UNSAFE" | "RESTRICTED" | "SAFE"))
| "AS" string ("," string)?
create_fun_ret_table_columns: column_list
column_list: column ("," column)*
argument_list: argument ("," argument)*
!create_fun_rettype: ["SETOF"] DATATYPE
// -----------------------------------------------------------------------------
// CREATE [ OR REPLACE ] AGGREGATE name ( [ argmode ] [ argname ] arg_data_type [ , ... ] ) (
// SFUNC = sfunc,
// STYPE = state_data_type
// [ , SSPACE = state_data_size ]
// [ , FINALFUNC = ffunc ]
// [ , FINALFUNC_EXTRA ]
// [ , FINALFUNC_MODIFY = { READ_ONLY | SHAREABLE | READ_WRITE } ]
// [ , COMBINEFUNC = combinefunc ]
// [ , SERIALFUNC = serialfunc ]
// [ , DESERIALFUNC = deserialfunc ]
// [ , INITCOND = initial_condition ]
// [ , MSFUNC = msfunc ]
// [ , MINVFUNC = minvfunc ]
// [ , MSTYPE = mstate_data_type ]
// [ , MSSPACE = mstate_data_size ]
// [ , MFINALFUNC = mffunc ]
// [ , MFINALFUNC_EXTRA ]
// [ , MFINALFUNC_MODIFY = { READ_ONLY | SHAREABLE | READ_WRITE } ]
// [ , MINITCOND = minitial_condition ]
// [ , SORTOP = sort_operator ]
// [ , PARALLEL = { SAFE | RESTRICTED | UNSAFE } ]
// )
// create_agg_stmt: "CREATE" ("OR" "REPLACE")? "AGGREGATE" fun_name "(" [argument_list] ")" "(" agg_param_list ")"
create_agg_stmt: "CREATE" ("OR" "REPLACE")? "AGGREGATE" fun_name "(" [argument_list] ")" "(" agg_param_list ")"
agg_param_list: agg_param ("," agg_param)*
agg_param: "sfunc" "=" fun_name
| "stype" "=" DATATYPE
| "finalfunc" "=" fun_name
| "parallel" "=" ("safe"|"restricted"|"unsafe")
// -----------------------------------------------------------------------------
// COMMENT ON
// {
// ...
// CAST (source_type AS target_type) |
// ...
// FUNCTION function_name ( [ [ argmode ] [ argname ] argtype [, ...] ] ) |
// ...
// OPERATOR operator_name (left_type, right_type) |
// ...
// } IS 'text'
comment_on_stmt: "COMMENT" "ON" comment_on_type "IS" string
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
column: CNAME DATATYPE
argument: [ARGMODE] [CNAME] DATATYPE ("DEFAULT" expr)?
ARGMODE.2: "IN" | "OUT" | "INOUT"
DATATYPE_SCALAR: "h3index"
| "raster"
| "summarystats"
| "h3_raster_summary_stats"
| "h3_raster_class_summary_item"
| "jsonb"
| "bigint"
| "boolean"
| "cstring"
| "double" WS "precision"
| "float"
| "geography"
| "geometry"
| "bytea"
| "int32"
| "int8"
| "integer"
| "internal"
| "int"
| "point"
| "polygon"
| "record"
| "text"
| "void"
DATATYPE: DATATYPE_SCALAR "[]"?
fun_name: [CNAME "."] CNAME
?expr: atom | string
atom: SIGNED_NUMBER -> number
| "TRUE" -> true
| "FALSE" -> false
string: STRING
// -----------------------------------------------------------------------------
// TERMINALS
// Terminals are used to match text into symbols.
// They can be defined as a combination of literals and other terminals.
LITERAL: SIGNED_NUMBER | ESCAPED_STRING
OPERATOR: ("+"|"-"|"*"|"/"|"<"|">"|"="|"~"|"!"|"@"|"#"|"%"|"^"|"&"|"|"|"`"|"?")+
STRING: "'" /([^'])+/ "'"
| "$$" /(.|\n)*?/ "$$"
MULTI_COMMENT : "/*" /(.|\n)+/ "*/"
SINGLE_COMMENT: "--" /[^\|@]/ /([^\n])*/
COMMAND: "\\" /([^\n])+/
// -----------------------------------------------------------------------------
%import common (CNAME, INT, ESCAPED_STRING, _STRING_ESC_INNER, SIGNED_NUMBER, WS, NEWLINE)
%ignore COMMAND
%ignore MULTI_COMMENT
%ignore SINGLE_COMMENT
%ignore WS