Skip to content

Commit

Permalink
upgrade to h3 v4.2.0
Browse files Browse the repository at this point in the history
  • Loading branch information
isaacbrodsky committed Dec 15, 2024
1 parent e9506ff commit 2571e3c
Show file tree
Hide file tree
Showing 9 changed files with 142 additions and 13 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ avoid adding features or APIs which do not map onto the

## Unreleased

None.
- Update to v4.2.0.

## [4.1.2] - 2024-10-26

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = 'scikit_build_core.build'

[project]
name = 'h3'
version = '4.1.2'
version = '4.2.0'
description = "Uber's hierarchical hexagonal geospatial indexing system"
readme = 'readme.md'
license = {file = 'LICENSE'}
Expand Down
2 changes: 2 additions & 0 deletions src/h3/_cy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@
cell_to_latlng,
polygon_to_cells,
polygons_to_cells,
polygon_to_cells_experimental,
polygons_to_cells_experimental,
cell_to_boundary,
directed_edge_to_boundary,
great_circle_distance,
Expand Down
3 changes: 3 additions & 0 deletions src/h3/_cy/h3lib.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,9 @@ cdef extern from 'h3api.h':
H3Error maxPolygonToCellsSize(const GeoPolygon *geoPolygon, int res, uint32_t flags, uint64_t *count)
H3Error polygonToCells(const GeoPolygon *geoPolygon, int res, uint32_t flags, H3int *out)

H3Error maxPolygonToCellsSizeExperimental(const GeoPolygon *geoPolygon, int res, uint32_t flags, uint64_t *count)
H3Error polygonToCellsExperimental(const GeoPolygon *geoPolygon, int res, uint32_t flags, uint64_t sz, H3int *out)

# ctypedef struct GeoMultiPolygon:
# int numPolygons
# GeoPolygon *polygons
Expand Down
74 changes: 74 additions & 0 deletions src/h3/_cy/latlng.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,80 @@ def polygons_to_cells(polygons, int res):
return hmm.to_mv()


def polygon_to_cells_experimental(outer, int res, int flags, holes=None):
""" Get the set of cells whose center is contained in a polygon.
The polygon is defined similarity to the GeoJson standard, with an exterior
`outer` ring of lat/lng points, and a list of `holes`, each of which are also
rings of lat/lng points.
Each ring may be in clockwise or counter-clockwise order
(right-hand rule or not), and may or may not be a closed loop (where the last
element is equal to the first).
The GeoJSON spec requires the right-hand rule and a closed loop, but
this function relaxes those constraints.
Unlike the GeoJson standard, the elements of the lat/lng pairs of each
ring are in lat/lng order, instead of lng/lat order.
We'll handle translation to different formats in the Python code,
rather than the Cython code.
Parameters
----------
outer : list or tuple
A ring given by a sequence of lat/lng pairs.
res : int
The resolution of the output hexagons
flags : int
Polygon to cells flags, such as containment mode.
holes : list or tuple
A collection of rings, each given by a sequence of lat/lng pairs.
These describe any the "holes" in the polygon.
"""
cdef:
uint64_t n

check_res(res)

if not outer:
return H3MemoryManager(0).to_mv()

gp = GeoPolygon(outer, holes=holes)

check_for_error(
h3lib.maxPolygonToCellsSizeExperimental(&gp.gp, res, flags, &n)
)

hmm = H3MemoryManager(n)
check_for_error(
h3lib.polygonToCellsExperimental(&gp.gp, res, flags, n, hmm.ptr)
)
mv = hmm.to_mv()

return mv


def polygons_to_cells_experimental(polygons, int res, int flags):
mvs = [
polygon_to_cells_experimental(outer=poly.outer, res=res, holes=poly.holes, flags=flags)
for poly in polygons
]

n = sum(map(len, mvs))
hmm = H3MemoryManager(n)

# probably super inefficient, but it is working!
# tood: move this to C
k = 0
for mv in mvs:
for v in mv:
hmm.ptr[k] = v
k += 1

return hmm.to_mv()


def cell_to_boundary(H3int h):
"""Compose an array of geo-coordinates that outlines a hexagonal cell"""
cdef:
Expand Down
20 changes: 15 additions & 5 deletions src/h3/api/basic_int/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ def uncompact_cells(cells, res):
return _out_collection(hu)


def h3shape_to_cells(h3shape, res):
def h3shape_to_cells(h3shape, res, flags=0, experimental=False):
"""
Return the collection of H3 cells at a given resolution whose center points
are contained within an ``LatLngPoly`` or ``LatLngMultiPoly``.
Expand All @@ -477,6 +477,10 @@ def h3shape_to_cells(h3shape, res):
h3shape : ``H3Shape``
res : int
Resolution of the output cells
flags : int
Containment mode flags
experimental : bool
Whether to use experimental algorithm.
Returns
-------
Expand Down Expand Up @@ -506,10 +510,16 @@ def h3shape_to_cells(h3shape, res):
# todo: not sure if i want this dispatch logic here. maybe in the objects?
if isinstance(h3shape, LatLngPoly):
poly = h3shape
mv = _cy.polygon_to_cells(poly.outer, res, holes=poly.holes)
if experimental:
mv = _cy.polygon_to_cells_experimental(poly.outer, res=res, holes=poly.holes, flags=flags)

Check failure on line 514 in src/h3/api/basic_int/__init__.py

View workflow job for this annotation

GitHub Actions / Coverage and Lint

Ruff (E501)

src/h3/api/basic_int/__init__.py:514:89: E501 Line too long (102 > 88)
else:
mv = _cy.polygon_to_cells(poly.outer, res=res, holes=poly.holes)
elif isinstance(h3shape, LatLngMultiPoly):
mpoly = h3shape
mv = _cy.polygons_to_cells(mpoly.polys, res)
if experimental:
mv = _cy.polygons_to_cells_experimental(mpoly.polys, res=res, flags=flags)
else:
mv = _cy.polygons_to_cells(mpoly.polys, res=res)
elif isinstance(h3shape, H3Shape):
raise ValueError('Unrecognized H3Shape: ' + str(h3shape))
else:
Expand All @@ -518,11 +528,11 @@ def h3shape_to_cells(h3shape, res):
return _out_collection(mv)


def polygon_to_cells(h3shape, res):
def polygon_to_cells(h3shape, res, flags=0, experimental=False):
"""
Alias for ``h3shape_to_cells``.
"""
return h3shape_to_cells(h3shape, res)
return h3shape_to_cells(h3shape, res, flags=flags, experimental=experimental)


def cells_to_h3shape(cells, *, tight=True):
Expand Down
2 changes: 1 addition & 1 deletion src/h3lib
Submodule h3lib updated 186 files
40 changes: 40 additions & 0 deletions tests/polyfill/test_h3.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,46 @@ def test_polygon_to_cells():
assert '89283080527ffff' in out
assert '89283095edbffff' in out

def test_polygon_to_cells_experimental():

Check failure on line 119 in tests/polyfill/test_h3.py

View workflow job for this annotation

GitHub Actions / Coverage and Lint

Ruff (E302)

tests/polyfill/test_h3.py:119:1: E302 Expected 2 blank lines, found 1
poly = h3.LatLngPoly(sf_7x7)
# Note that `polygon_to_cells` is an alias for `h3shape_to_cells`
out = h3.polygon_to_cells(poly, res=9, flags=0, experimental=True)

assert len(out) == 1253
assert '89283080527ffff' in out
assert '89283095edbffff' in out


def test_polygon_to_cells_experimental_full():
poly = h3.LatLngPoly(sf_7x7)
# Note that `polygon_to_cells` is an alias for `h3shape_to_cells`
out = h3.polygon_to_cells(poly, res=9, flags=1, experimental=True)

assert len(out) == 1175
assert '89283082a1bffff' in out
assert '89283080527ffff' not in out
assert '89283095edbffff' in out


def test_polygon_to_cells_experimental_overlapping():
poly = h3.LatLngPoly(sf_7x7)
# Note that `polygon_to_cells` is an alias for `h3shape_to_cells`
out = h3.polygon_to_cells(poly, res=9, flags=2, experimental=True)

assert len(out) == 1334
assert '89283080527ffff' in out
assert '89283095edbffff' in out


def test_polygon_to_cells_experimental_overlapping_bbox():
poly = h3.LatLngPoly(sf_7x7)
# Note that `polygon_to_cells` is an alias for `h3shape_to_cells`
out = h3.polygon_to_cells(poly, res=9, flags=3, experimental=True)

assert len(out) == 1416
assert '89283080527ffff' in out
assert '89283095edbffff' in out


def test_polyfill_with_hole():
poly = h3.LatLngPoly(sf_7x7, sf_hole1)
Expand Down
10 changes: 5 additions & 5 deletions tests/test_cells_and_edges.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,11 +289,11 @@ def test_average_hexagon_area():

def test_average_hexagon_edge_length():
expected_in_km = {
0: 1107.712591000,
1: 418.676005500,
2: 158.244655800,
9: 0.174375668,
15: 0.000509713,
0: 1281.256011,
1: 483.0568391,
2: 182.5129565,
9: 0.200786148,
15: 0.000584169,
}

out = {
Expand Down

0 comments on commit 2571e3c

Please sign in to comment.