Skip to content

Commit

Permalink
BIGINT input (#102)
Browse files Browse the repository at this point in the history
* begin BIGINT support

* variants

* rest of tests

* README update

* update readme

* align
  • Loading branch information
isaacbrodsky committed May 13, 2024
1 parent fb7f446 commit b01652a
Show file tree
Hide file tree
Showing 17 changed files with 709 additions and 160 deletions.
127 changes: 70 additions & 57 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,62 +43,75 @@ SELECT h3_cell_to_latlng(cast(586265647244115967 as ubigint));

# Implemented functions

This extension implements the entire [H3 API](https://h3geo.org/docs/api/indexing). The full list of functions is below:

| Function |
| --- |
| `h3_latlng_to_cell`
| `h3_cell_to_lat`
| `h3_cell_to_lng`
| `h3_cell_to_latlng`
| `h3_cell_to_boundary_wkt`
| `h3_get_resolution`
| `h3_get_base_cell_number`
| `h3_string_to_h3`
| `h3_h3_to_string`
| `h3_is_valid_cell`
| `h3_is_res_class_iii`
| `h3_is_pentagon`
| `h3_get_icosahedron_faces`
| `h3_cell_to_parent`
| `h3_cell_to_children`
| `h3_cell_to_center_child`
| `h3_cell_to_child_pos`
| `h3_child_pos_to_cell`
| `h3_compact_cells`
| `h3_uncompact_cells`
| `h3_grid_disk`
| `h3_grid_disk_distances`
| `h3_grid_disk_unsafe`
| `h3_grid_disk_distances_unsafe`
| `h3_grid_ring_unsafe`
| `h3_grid_path_cells`
| `h3_grid_distance`
| `h3_cell_to_local_ij`
| `h3_local_ij_to_cell`
| `h3_cell_to_vertex`
| `h3_cell_to_vertexes`
| `h3_vertex_to_lat`
| `h3_vertex_to_lng`
| `h3_vertex_to_latlng`
| `h3_is_valid_vertex`
| `h3_is_valid_directed_edge`
| `h3_origin_to_directed_edges`
| `h3_directed_edge_to_cells`
| `h3_get_directed_edge_origin`
| `h3_get_directed_edge_destination`
| `h3_cells_to_directed_edge`
| `h3_are_neighbor_cells`
| `h3_directed_edge_to_boundary_wkt`
| `h3_get_hexagon_area_avg`
| `h3_cell_area`
| `h3_edge_length`
| `h3_get_num_cells`
| `h3_get_res0_cells`
| `h3_get_pentagons`
| `h3_great_circle_distance`
| `h3_cells_to_multi_polygon_wkt`
| `h3_polygon_wkt_to_cells`
This extension implements the entire [H3 API](https://h3geo.org/docs/api/indexing). The full list of functions is below.

All functions support H3 indexes specified as `UBIGINT` (`uint64`) or `BIGINT` (`int64`),
but the unsigned one is preferred and is returned when the extension can't detect which
one to use. The unsigned and signed APIs are identical. Many functions also support
`VARCHAR` H3 index input and output.

### Full list of functions

| Function | Notes | Description
| --: | --- | ---
| `h3_latlng_to_cell` | [u](#fu) | Convert latitude/longitude coordinate to cell ID
| `h3_cell_to_lat` | [v](#fv) | Convert cell ID to latitude
| `h3_cell_to_lng` | [v](#fv) | Convert cell ID to longitude
| `h3_cell_to_latlng` | [v](#fv) | Convert cell ID to latitude/longitude
| `h3_cell_to_boundary_wkt` | [v](#fv) | Convert cell ID to cell boundary
| `h3_get_resolution` | [i](#fi) | Get resolution number of cell ID
| `h3_get_base_cell_number` | [i](#fi) | Get base cell number of cell ID
| `h3_string_to_h3` | [u](#fu) | Convert VARCHAR cell ID to UBIGINT
| `h3_h3_to_string` | [i](#fi) | Convert BIGINT or UBIGINT cell ID to VARCHAR
| `h3_is_valid_cell` | [v](#fv) | True if this is a valid cell ID
| `h3_is_res_class_iii` | [i](#fi) | True if the cell's resolution is class III
| `h3_is_pentagon` | [i](#fi) | True if the cell is a pentagon
| `h3_get_icosahedron_faces` | [i](#fi) | List of icosahedron face IDs the cell is on
| `h3_cell_to_parent` | [i](#fi) | Get coarser cell for a cell
| `h3_cell_to_children` | [i](#fi) | Get finer cells for a cell
| `h3_cell_to_center_child` | [i](#fi) | Get the center finer cell for a cell
| `h3_cell_to_child_pos` | [i](#fi) | Get a sub-indexing number for a cell inside a parent
| `h3_child_pos_to_cell` | [i](#fi) | Convert parent and sub-indexing number to a cell ID
| `h3_compact_cells` | [i](#fi) | Convert a set of single-resolution cells to the minimal mixed-resolution set
| `h3_uncompact_cells` | [i](#fi) | Convert a mixed-resolution set to a single-resolution set of cells
| `h3_grid_disk` | [i](#fi) | Find cells within a grid distance
| `h3_grid_disk_distances` | [i](#fi) | Find cells within a grid distance, sorted by distance
| `h3_grid_disk_unsafe` | [i](#fi) | Find cells within a grid distance, with no pentagon distortion
| `h3_grid_disk_distances_unsafe` | [i](#fi) | Find cells within a grid distance, sorted by distance, with no pentagon distortion
| `h3_grid_ring_unsafe` | [i](#fi) | Find cells exactly a grid distance away, with no pentagon distortion
| `h3_grid_path_cells` | [i](#fi) | Find a grid path to connect two cells
| `h3_grid_distance` | [i](#fi) | Find the grid distance between two cells
| `h3_cell_to_local_ij` | [i](#fi) | Convert a cell ID to a local I,J coordinate space
| `h3_local_ij_to_cell` | [i](#fi) | Convert a local I,J coordinate to a cell ID
| `h3_cell_to_vertex` | [i](#fi) | Get the vertex ID for a cell ID and vertex number
| `h3_cell_to_vertexes` | [i](#fi) | Get all vertex IDs for a cell ID
| `h3_vertex_to_lat` | [i](#fi) | Convert a vertex ID to latitude
| `h3_vertex_to_lng` | [i](#fi) | Convert a vertex ID to longitude
| `h3_vertex_to_latlng` | [i](#fi) | Convert a vertex ID to latitude/longitude coordinate
| `h3_is_valid_vertex` | [v](#fv) | True if passed a valid vertex ID
| `h3_is_valid_directed_edge` | [v](#fv) | True if passed a valid directed edge ID
| `h3_origin_to_directed_edges` | [i](#fi) | Get all directed edge IDs for a cell ID
| `h3_directed_edge_to_cells` | [i](#fi) | Convert a directed edge ID to origin/destination cell IDs
| `h3_get_directed_edge_origin` | [i](#fi) | Convert a directed edge ID to origin cell ID
| `h3_get_directed_edge_destination` | [i](#fi) | Convert a directed edge ID to destination cell ID
| `h3_cells_to_directed_edge` | [i](#fi) | Convert an origin/destination pair to directed edge ID
| `h3_are_neighbor_cells` | [i](#fi) | True if the two cell IDs are directly adjacent
| `h3_directed_edge_to_boundary_wkt` | [v](#fv) | Convert directed edge ID to linestring WKT
| `h3_get_hexagon_area_avg` | | Get average area of a hexagon cell at resolution
| `h3_cell_area` | [v](#fv) | Get the area of a cell ID
| `h3_edge_length` | [v](#fv) | Get the length of a directed edge ID
| `h3_get_num_cells` | | Get the number of cells at a resolution
| `h3_get_res0_cells` | [u](#fu) | Get all resolution 0 cells
| `h3_get_pentagons` | [u](#fu) | Get all pentagons at a resolution
| `h3_great_circle_distance` | | Compute the great circle distance between two points (haversine)
| `h3_cells_to_multi_polygon_wkt` | [v](#fv) | Convert a set of cells to multipolygon WKT
| `h3_polygon_wkt_to_cells` | [u](#fu) | Convert polygon WKT to a set of cells

### Notes

* <i id="fv">v</i>: Supports VARCHAR, UBIGINT, and BIGINT input and output.
* <i id="fi">i</i>: Supports UBIGINT and BIGINT input and output. (TODO for these to support VARCHAR too.)
* <i id="fu">u</i>: Supports UBIGINT output only.

# Development

Expand Down Expand Up @@ -152,4 +165,4 @@ DGGRID Copyright (c) 2015 Southern Oregon University

[DuckDB](https://github.com/duckdb/duckdb) Copyright 2018-2022 Stichting DuckDB Foundation (MIT License)

Build system adapted from [sqlitescanner](https://github.com/duckdblabs/sqlitescanner) Copyright 2018-2022 DuckDB Labs BV (MIT License)
[DuckDB extension-template](https://github.com/duckdb/extension-template) Copyright 2018-2022 DuckDB Labs BV (MIT License)
72 changes: 54 additions & 18 deletions src/h3_directededge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,39 +209,71 @@ static void DirectedEdgeToBoundaryWktVarcharFunction(DataChunk &args,
}

CreateScalarFunctionInfo H3Functions::GetDirectedEdgeToCellsFunction() {
return CreateScalarFunctionInfo(ScalarFunction(
"h3_directed_edge_to_cells", {LogicalType::UBIGINT},
LogicalType::LIST(LogicalType::UBIGINT), DirectedEdgeToCellsFunction));
ScalarFunctionSet funcs("h3_directed_edge_to_cells");
// TODO: VARCHAR variant of this function
funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT},
LogicalType::LIST(LogicalType::UBIGINT),
DirectedEdgeToCellsFunction));
funcs.AddFunction(ScalarFunction({LogicalType::BIGINT},
LogicalType::LIST(LogicalType::UBIGINT),
DirectedEdgeToCellsFunction));
return CreateScalarFunctionInfo(funcs);
}

CreateScalarFunctionInfo H3Functions::GetOriginToDirectedEdgesFunction() {
return CreateScalarFunctionInfo(ScalarFunction(
"h3_origin_to_directed_edges", {LogicalType::UBIGINT},
LogicalType::LIST(LogicalType::UBIGINT), OriginToDirectedEdgesFunction));
ScalarFunctionSet funcs("h3_origin_to_directed_edges");
// TODO: VARCHAR variant of this function
funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT},
LogicalType::LIST(LogicalType::UBIGINT),
OriginToDirectedEdgesFunction));
funcs.AddFunction(ScalarFunction({LogicalType::BIGINT},
LogicalType::LIST(LogicalType::UBIGINT),
OriginToDirectedEdgesFunction));
return CreateScalarFunctionInfo(funcs);
}

CreateScalarFunctionInfo H3Functions::GetGetDirectedEdgeOriginFunction() {
return CreateScalarFunctionInfo(
ScalarFunction("h3_get_directed_edge_origin", {LogicalType::UBIGINT},
LogicalType::UBIGINT, GetDirectedEdgeOriginFunction));
ScalarFunctionSet funcs("h3_get_directed_edge_origin");
// TODO: VARCHAR variant of this function
funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT}, LogicalType::UBIGINT,
GetDirectedEdgeOriginFunction));
funcs.AddFunction(ScalarFunction({LogicalType::BIGINT}, LogicalType::BIGINT,
GetDirectedEdgeOriginFunction));
return CreateScalarFunctionInfo(funcs);
}

CreateScalarFunctionInfo H3Functions::GetGetDirectedEdgeDestinationFunction() {
return CreateScalarFunctionInfo(
ScalarFunction("h3_get_directed_edge_destination", {LogicalType::UBIGINT},
LogicalType::UBIGINT, GetDirectedEdgeDestinationFunction));
ScalarFunctionSet funcs("h3_get_directed_edge_destination");
// TODO: VARCHAR variant of this function
funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT}, LogicalType::UBIGINT,
GetDirectedEdgeDestinationFunction));
funcs.AddFunction(ScalarFunction({LogicalType::BIGINT}, LogicalType::BIGINT,
GetDirectedEdgeDestinationFunction));
return CreateScalarFunctionInfo(funcs);
}

CreateScalarFunctionInfo H3Functions::GetCellsToDirectedEdgeFunction() {
return CreateScalarFunctionInfo(ScalarFunction(
"h3_cells_to_directed_edge", {LogicalType::UBIGINT, LogicalType::UBIGINT},
LogicalType::UBIGINT, CellsToDirectedEdgeFunction));
ScalarFunctionSet funcs("h3_cells_to_directed_edge");
// TODO: VARCHAR variant of this function
funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT, LogicalType::UBIGINT},
LogicalType::UBIGINT,
CellsToDirectedEdgeFunction));
funcs.AddFunction(ScalarFunction({LogicalType::BIGINT, LogicalType::BIGINT},
LogicalType::BIGINT,
CellsToDirectedEdgeFunction));
return CreateScalarFunctionInfo(funcs);
}

CreateScalarFunctionInfo H3Functions::GetAreNeighborCellsFunction() {
return CreateScalarFunctionInfo(ScalarFunction(
"h3_are_neighbor_cells", {LogicalType::UBIGINT, LogicalType::UBIGINT},
LogicalType::BOOLEAN, AreNeighborCellsFunction));
ScalarFunctionSet funcs("h3_are_neighbor_cells");
// TODO: VARCHAR variant of this function
funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT, LogicalType::UBIGINT},
LogicalType::BOOLEAN,
AreNeighborCellsFunction));
funcs.AddFunction(ScalarFunction({LogicalType::BIGINT, LogicalType::BIGINT},
LogicalType::BOOLEAN,
AreNeighborCellsFunction));
return CreateScalarFunctionInfo(funcs);
}

CreateScalarFunctionInfo H3Functions::GetIsValidDirectedEdgeFunctions() {
Expand All @@ -250,6 +282,8 @@ CreateScalarFunctionInfo H3Functions::GetIsValidDirectedEdgeFunctions() {
IsValidDirectedEdgeVarcharFunction));
funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT}, LogicalType::BOOLEAN,
IsValidDirectedEdgeFunction));
funcs.AddFunction(ScalarFunction({LogicalType::BIGINT}, LogicalType::BOOLEAN,
IsValidDirectedEdgeFunction));
return CreateScalarFunctionInfo(funcs);
}

Expand All @@ -259,6 +293,8 @@ CreateScalarFunctionInfo H3Functions::GetDirectedEdgeToBoundaryWktFunction() {
DirectedEdgeToBoundaryWktVarcharFunction));
funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT}, LogicalType::VARCHAR,
DirectedEdgeToBoundaryWktFunction));
funcs.AddFunction(ScalarFunction({LogicalType::BIGINT}, LogicalType::VARCHAR,
DirectedEdgeToBoundaryWktFunction));
return CreateScalarFunctionInfo(funcs);
}

Expand Down
77 changes: 58 additions & 19 deletions src/h3_hierarchy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,47 +274,86 @@ static void UncompactCellsFunction(DataChunk &args, ExpressionState &state,
}

CreateScalarFunctionInfo H3Functions::GetCellToParentFunction() {
return CreateScalarFunctionInfo(ScalarFunction(
"h3_cell_to_parent", {LogicalType::UBIGINT, LogicalType::INTEGER},
LogicalType::UBIGINT, CellToParentFunction));
ScalarFunctionSet funcs("h3_cell_to_parent");
// TODO: VARCHAR variant of this function
funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT, LogicalType::INTEGER},
LogicalType::UBIGINT, CellToParentFunction));
funcs.AddFunction(ScalarFunction({LogicalType::BIGINT, LogicalType::INTEGER},
LogicalType::BIGINT, CellToParentFunction));
return CreateScalarFunctionInfo(funcs);
}

CreateScalarFunctionInfo H3Functions::GetCellToChildrenFunction() {
return CreateScalarFunctionInfo(ScalarFunction(
"h3_cell_to_children", {LogicalType::UBIGINT, LogicalType::INTEGER},
LogicalType::LIST(LogicalType::UBIGINT), CellToChildrenFunction));
ScalarFunctionSet funcs("h3_cell_to_children");
// TODO: VARCHAR variant of this function
funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT, LogicalType::INTEGER},
LogicalType::LIST(LogicalType::UBIGINT),
CellToChildrenFunction));
funcs.AddFunction(ScalarFunction({LogicalType::BIGINT, LogicalType::INTEGER},
LogicalType::LIST(LogicalType::BIGINT),
CellToChildrenFunction));
return CreateScalarFunctionInfo(funcs);
}

CreateScalarFunctionInfo H3Functions::GetCellToCenterChildFunction() {
return CreateScalarFunctionInfo(ScalarFunction(
"h3_cell_to_center_child", {LogicalType::UBIGINT, LogicalType::INTEGER},
LogicalType::UBIGINT, CellToCenterChildFunction));
ScalarFunctionSet funcs("h3_cell_to_center_child");
// TODO: VARCHAR variant of this function
funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT, LogicalType::INTEGER},
LogicalType::UBIGINT,
CellToCenterChildFunction));
funcs.AddFunction(ScalarFunction({LogicalType::BIGINT, LogicalType::INTEGER},
LogicalType::BIGINT,
CellToCenterChildFunction));
return CreateScalarFunctionInfo(funcs);
}

CreateScalarFunctionInfo H3Functions::GetCellToChildPosFunction() {
return CreateScalarFunctionInfo(ScalarFunction(
"h3_cell_to_child_pos", {LogicalType::UBIGINT, LogicalType::INTEGER},
LogicalType::BIGINT, CellToChildPosFunction));
ScalarFunctionSet funcs("h3_cell_to_child_pos");
// TODO: VARCHAR variant of this function
// Note this does not return an index, rather it returns a position ID
funcs.AddFunction(ScalarFunction({LogicalType::UBIGINT, LogicalType::INTEGER},
LogicalType::BIGINT,
CellToChildPosFunction));
funcs.AddFunction(ScalarFunction({LogicalType::BIGINT, LogicalType::INTEGER},
LogicalType::BIGINT,
CellToChildPosFunction));
return CreateScalarFunctionInfo(funcs);
}

CreateScalarFunctionInfo H3Functions::GetChildPosToCellFunction() {
return CreateScalarFunctionInfo(ScalarFunction(
"h3_child_pos_to_cell",
ScalarFunctionSet funcs("h3_child_pos_to_cell");
// TODO: VARCHAR variant of this function
funcs.AddFunction(ScalarFunction(
{LogicalType::BIGINT, LogicalType::UBIGINT, LogicalType::INTEGER},
LogicalType::UBIGINT, ChildPosToCellFunction));
funcs.AddFunction(ScalarFunction(
{LogicalType::BIGINT, LogicalType::BIGINT, LogicalType::INTEGER},
LogicalType::BIGINT, ChildPosToCellFunction));
return CreateScalarFunctionInfo(funcs);
}

CreateScalarFunctionInfo H3Functions::GetCompactCellsFunction() {
return CreateScalarFunctionInfo(ScalarFunction(
"h3_compact_cells", {LogicalType::LIST(LogicalType::UBIGINT)},
LogicalType::LIST(LogicalType::UBIGINT), CompactCellsFunction));
ScalarFunctionSet funcs("h3_compact_cells");
// TODO: VARCHAR variant of this function
funcs.AddFunction(ScalarFunction({LogicalType::LIST(LogicalType::UBIGINT)},
LogicalType::LIST(LogicalType::UBIGINT),
CompactCellsFunction));
funcs.AddFunction(ScalarFunction({LogicalType::LIST(LogicalType::BIGINT)},
LogicalType::LIST(LogicalType::BIGINT),
CompactCellsFunction));
return CreateScalarFunctionInfo(funcs);
}

CreateScalarFunctionInfo H3Functions::GetUncompactCellsFunction() {
return CreateScalarFunctionInfo(ScalarFunction(
"h3_uncompact_cells",
ScalarFunctionSet funcs("h3_uncompact_cells");
// TODO: VARCHAR variant of this function
funcs.AddFunction(ScalarFunction(
{LogicalType::LIST(LogicalType::UBIGINT), LogicalType::INTEGER},
LogicalType::LIST(LogicalType::UBIGINT), UncompactCellsFunction));
funcs.AddFunction(ScalarFunction(
{LogicalType::LIST(LogicalType::BIGINT), LogicalType::INTEGER},
LogicalType::LIST(LogicalType::BIGINT), UncompactCellsFunction));
return CreateScalarFunctionInfo(funcs);
}

} // namespace duckdb
Loading

0 comments on commit b01652a

Please sign in to comment.