Skip to content

Commit

Permalink
add cells_to_localij and localij_to_cells functions
Browse files Browse the repository at this point in the history
  • Loading branch information
nmandery committed Jun 23, 2024
1 parent d418e30 commit 6403537
Show file tree
Hide file tree
Showing 10 changed files with 121 additions and 5 deletions.
14 changes: 11 additions & 3 deletions crates/h3arrow/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,32 @@ All notable changes to this project will be documented in this file.
The format is loosely based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres
to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).


## Unreleased (YYYY-MM-DD TBD)

* Added H3ArrayBuilder type.
* Added LocalIj coordinate support.

## v0.4.0 (2024-03-01)

* Update h3o to 0.6.
* Upgrade geo to 0.28
* Upgrade rstar to 0.12
* Upgrade geozero to 0.12

## v0.3.0 (2024-02-06)

* Extend documentation on ParseUtf8Array::parse_utf8array.
* Add ChangeResolutionOp::change_resolution_list.
* Update geozero to 0.11.
* Update h3o to 0.5.
* Migrate from arrow2 to the official apache arrow implementation and aligned naming. This comes along with many API changes. `geoarrow::ToWKBLines` has been removed.
* Migrate from arrow2 to the official apache arrow implementation and aligned naming. This comes along with many API
changes. `geoarrow::ToWKBLines` has been removed.

## v0.2.0 (2023-08-31)
* Upgrade h3o from v0.3 to v0.4. Due to the new polyfill modes this lead to API breakages in the `ToCellsOptions` struct.

* Upgrade h3o from v0.3 to v0.4. Due to the new polyfill modes this lead to API breakages in the `ToCellsOptions`
struct.

## v0.1.0 (2023-07-24)

* Initial release
1 change: 1 addition & 0 deletions crates/h3arrow/src/algorithm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub mod concave_hull;
pub mod convex_hull;
pub mod coordinates;
pub mod grid;
pub mod localij;
pub mod string;

#[allow(unused_imports)]
Expand Down
48 changes: 47 additions & 1 deletion crates/h3arrow/src/array/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::marker::PhantomData;
use std::mem::transmute;

use arrow::array::{Array, ArrayIter, PrimitiveArray, UInt64Array};
use arrow::array::{Array, ArrayIter, PrimitiveArray, UInt64Array, UInt64Builder};
use h3o::{CellIndex, DirectedEdgeIndex, VertexIndex};

#[allow(unused_imports)]
Expand Down Expand Up @@ -87,6 +87,10 @@ where
}
}

pub fn builder(capacity: usize) -> H3ArrayBuilder<IX> {
H3ArrayBuilder::with_capacity(capacity)
}

pub fn primitive_array(&self) -> &UInt64Array {
&self.primitive_array
}
Expand Down Expand Up @@ -132,6 +136,48 @@ pub type CellIndexArray = H3Array<CellIndex>;
pub type VertexIndexArray = H3Array<VertexIndex>;
pub type DirectedEdgeIndexArray = H3Array<DirectedEdgeIndex>;

pub struct H3ArrayBuilder<IX> {
h3index_phantom: PhantomData<IX>,
builder: UInt64Builder,
}

impl<IX> H3ArrayBuilder<IX>
where
IX: H3IndexArrayValue,
{
pub fn with_capacity(capacity: usize) -> Self {
Self {
h3index_phantom: Default::default(),
builder: UInt64Builder::with_capacity(capacity),
}
}

/// Returns the capacity of this builder measured in slots of type `T`
pub fn capacity(&self) -> usize {
self.builder.capacity()
}

/// Appends a value of type `T` into the builder
#[inline]
pub fn append_value(&mut self, v: IX) {
self.builder.append_value(v.into());
}

/// Appends a null slot into the builder
#[inline]
pub fn append_null(&mut self) {
self.builder.append_null();
}

/// Builds the [`H3Array`] and reset this builder.
pub fn finish(&mut self) -> H3Array<IX> {
H3Array {
h3index_phantom: Default::default(),
primitive_array: self.builder.finish(),
}
}
}

/// Conversion corresponding to `From` with the difference that the validity mask
/// is set accordingly to the validity to the contained values.
pub trait FromWithValidity<T> {
Expand Down
6 changes: 6 additions & 0 deletions crates/h3arrow/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ pub enum Error {
#[error(transparent)]
OutlinerError(#[from] h3o::error::OutlinerError),

#[error(transparent)]
LocalIJError(#[from] h3o::error::LocalIjError),

#[error(transparent)]
Arrow2(#[from] arrow::error::ArrowError),

Expand All @@ -42,6 +45,9 @@ pub enum Error {
#[error("Invalid WKB encountered")]
InvalidWKB,

#[error("array length mismatch")]
LengthMismatch,

#[error(transparent)]
IO(#[from] std::io::Error),
}
1 change: 1 addition & 0 deletions h3ronpy/CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Unreleased
----------

- Restrict numpy version to <2 until incompatibilities of rust-numpy with version 2 are resolved
- Add `cells_to_localij` and `localij_to_cells` functions.

0.20.2 - 2024-04-16
-------------------
Expand Down
41 changes: 41 additions & 0 deletions h3ronpy/python/h3ronpy/arrow/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,45 @@ def directededges_to_string(directededgearray) -> pa.Array:
return op.directededges_to_string(_to_uint64_array(directededgearray))


def cells_to_localij(cellarray, anchor, set_failing_to_invalid: bool = False) -> pa.Table:
"""
Produces IJ coordinates for an index anchored by an origin `anchor`.
The coordinate space used by this function may have deleted regions or warping due to pentagonal distortion.
Coordinates are only comparable if they come from the same origin index.
The parameter `anchor` can be a single cell or an array of cells which serve as anchor for the
cells of `cellarray`. In case it is an array, the length must match the length of the cell
array.
The default behavior is for this function to fail when a single transformation can not be completed
successfully. When `set_failing_to_invalid` is set to True, only the failing positions
of the output arrays will be set to null.
"""
if type(anchor) is not int:
anchor = _to_uint64_array(anchor)
return op.cells_to_localij(_to_uint64_array(cellarray), anchor, set_failing_to_invalid=set_failing_to_invalid)


def localij_to_cells(anchor, i, j, set_failing_to_invalid: bool = False) -> pa.Array:
"""
Produces cells from `i` and `j` coordinates and an `anchor` cell.
The default behavior is for this function to fail when a single transformation can not be completed
successfully. When `set_failing_to_invalid` is set to True, only the failing positions
of the output arrays will be set to null.
"""
if type(anchor) is not int:
anchor = _to_uint64_array(anchor)
return op.localij_to_cells(
anchor,
_to_arrow_array(i, pa.int32()),
_to_arrow_array(j, pa.int32()),
set_failing_to_invalid=set_failing_to_invalid,
)


__all__ = [
change_resolution.__name__,
change_resolution_list.__name__,
Expand All @@ -220,4 +259,6 @@ def directededges_to_string(directededgearray) -> pa.Array:
cells_to_string.__name__,
vertexes_to_string.__name__,
directededges_to_string.__name__,
cells_to_localij.__name__,
localij_to_cells.__name__,
]
5 changes: 4 additions & 1 deletion h3ronpy/python/h3ronpy/pandas/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ def wrapper(*args, **kw):
cells_to_string = _wrap(_arrow.cells_to_string, ret_type=pd.Series)
vertexes_to_string = _wrap(_arrow.vertexes_to_string, ret_type=pd.Series)
directededges_to_string = _wrap(_arrow.directededges_to_string, ret_type=pd.Series)

cells_to_localij = _wrap(_arrow.cells_to_localij, ret_type=pd.DataFrame)
localij_to_cells = _wrap(_arrow.localij_to_cells, ret_type=pd.Series)

__all__ = [
change_resolution.__name__,
Expand All @@ -79,4 +80,6 @@ def wrapper(*args, **kw):
cells_to_string.__name__,
vertexes_to_string.__name__,
directededges_to_string.__name__,
cells_to_localij.__name__,
localij_to_cells.__name__,
]
4 changes: 4 additions & 0 deletions h3ronpy/python/h3ronpy/polars/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ def wrapper(*args, **kw):
cells_to_string = _wrap(_arrow.cells_to_string, ret_type=pl.Series)
vertexes_to_string = _wrap(_arrow.vertexes_to_string, ret_type=pl.Series)
directededges_to_string = _wrap(_arrow.directededges_to_string, ret_type=pl.Series)
cells_to_localij = _wrap(_arrow.cells_to_localij, ret_type=pl.DataFrame)
localij_to_cells = _wrap(_arrow.localij_to_cells, ret_type=pl.Series)


@pl.api.register_expr_namespace("h3")
Expand Down Expand Up @@ -214,6 +216,8 @@ def directededges_to_string(self) -> pl.Series:
cells_to_string.__name__,
vertexes_to_string.__name__,
directededges_to_string.__name__,
cells_to_localij.__name__,
localij_to_cells.__name__,
H3Expr.__name__,
H3SeriesShortcuts.__name__,
]
3 changes: 3 additions & 0 deletions h3ronpy/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,13 @@ impl IntoPyErr for A3Error {
A3Error::InvalidGeometry(e) => e.into_pyerr(),
A3Error::CompactionError(e) => e.into_pyerr(),
A3Error::OutlinerError(e) => e.into_pyerr(),
A3Error::LocalIJError(e) => e.into_pyerr(),
A3Error::Arrow2(e) => e.into_pyerr(),
A3Error::NotAUint64Array
| A3Error::NonParsableCellIndex
| A3Error::NonParsableDirectedEdgeIndex
| A3Error::NonParsableVertexIndex
| A3Error::LengthMismatch
| A3Error::InvalidWKB => PyValueError::new_err(self.to_string()),
A3Error::IO(e) => e.into_pyerr(),
}
Expand Down Expand Up @@ -62,6 +64,7 @@ impl_h3o_value_err!(
h3arrow::export::h3o::error::InvalidResolution,
h3arrow::export::h3o::error::InvalidVertexIndex,
h3arrow::export::h3o::error::OutlinerError,
h3arrow::export::h3o::error::LocalIjError,
);

impl IntoPyErr for rasterh3::Error {
Expand Down
3 changes: 3 additions & 0 deletions h3ronpy/src/op/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use pyo3::prelude::*;

mod compact;
mod localij;
mod measure;
mod neighbor;
mod resolution;
Expand Down Expand Up @@ -30,6 +31,8 @@ pub fn init_op_submodule(m: &PyModule) -> PyResult<()> {
m.add_function(wrap_pyfunction!(measure::cells_area_m2, m)?)?;
m.add_function(wrap_pyfunction!(measure::cells_area_km2, m)?)?;
m.add_function(wrap_pyfunction!(measure::cells_area_rads2, m)?)?;
m.add_function(wrap_pyfunction!(localij::cells_to_localij, m)?)?;
m.add_function(wrap_pyfunction!(localij::localij_to_cells, m)?)?;

Ok(())
}

0 comments on commit 6403537

Please sign in to comment.