Skip to content

Commit

Permalink
Add projection keyword to from_geoarrow + update type hints (#78)
Browse files Browse the repository at this point in the history
  • Loading branch information
jorisvandenbossche authored Nov 25, 2024
1 parent acf3641 commit a650b7a
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 0 deletions.
7 changes: 7 additions & 0 deletions src/geoarrow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ py::array_t<PyObjectGeography> from_geoarrow(py::object input,
bool oriented,
bool planar,
float tessellate_tolerance,
Projection projection,
py::object geometry_encoding) {
if (!py::hasattr(input, "__arrow_c_array__")) {
throw std::invalid_argument(
Expand All @@ -33,6 +34,7 @@ py::array_t<PyObjectGeography> from_geoarrow(py::object input,

s2geog::geoarrow::ImportOptions options;
options.set_oriented(oriented);
options.set_projection(projection.s2_projection());
if (planar) {
auto tol = S1Angle::Radians(tessellate_tolerance / EARTH_RADIUS_METERS);
options.set_tessellate_tolerance(tol);
Expand Down Expand Up @@ -264,6 +266,7 @@ void init_geoarrow(py::module& m) {
py::arg("oriented") = false,
py::arg("planar") = false,
py::arg("tessellate_tolerance") = 100.0,
py::arg("projection") = Projection::lnglat(),
py::arg("geometry_encoding") = py::none(),
R"pbdoc(
Create an array of geographies from an Arrow array object with a GeoArrow
Expand Down Expand Up @@ -301,6 +304,10 @@ void init_geoarrow(py::module& m) {
The maximum distance in meters that a point must be moved to
satisfy the planar edge constraint. This is only used if `planar`
is set to True.
projection : spherely.Projection, default Projection.lnglat()
The projection of the input coordinates. By default, it assumes
longitude/latitude coordinates, but this option allows to convert
from coordinates in pseudo-mercator or orthographic projection as well.
geometry_encoding : str, default None
By default, the encoding is inferred from the GeoArrow extension
type of the input array.
Expand Down
24 changes: 24 additions & 0 deletions src/spherely.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,16 @@ MultiLineStringGeography = Annotated[Geography, GeographyType.MULTILINESTRING]
MultiPolygonGeography = Annotated[Geography, GeographyType.MULTIPOLYGON]
GeometryCollection = Annotated[Geography, GeographyType.GEOMETRYCOLLECTION]

# Projection class

class Projection:
@staticmethod
def lnglat() -> Projection: ...
@staticmethod
def speudo_mercator() -> Projection: ...
@staticmethod
def orthographic(longitude: float, latitude: float) -> Projection: ...

# Numpy-like vectorized (universal) functions

_NameType = TypeVar("_NameType", bound=str)
Expand Down Expand Up @@ -222,17 +232,31 @@ def from_wkb(
tessellate_tolerance: float = 100.0,
) -> npt.NDArray[Any]: ...

class ArrowSchemaExportable(Protocol):
def __arrow_c_schema__(self) -> object: ...

class ArrowArrayExportable(Protocol):
def __arrow_c_array__(
self, requested_schema: object | None = None
) -> Tuple[object, object]: ...

def to_geoarrow(
input: npt.ArrayLike,
/,
*,
output_schema: ArrowSchemaExportable | None = None,
projection: Projection = Projection.lnglat(),
planar: bool = False,
tessellate_tolerance: float = 100.0,
precision: int = 6,
) -> ArrowArrayExportable: ...
def from_geoarrow(
input: ArrowArrayExportable,
/,
*,
oriented: bool = False,
planar: bool = False,
tessellate_tolerance: float = 100.0,
projection: Projection = Projection.lnglat(),
geometry_encoding: str | None = None,
) -> npt.NDArray[Any]: ...
12 changes: 12 additions & 0 deletions tests/test_geoarrow.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,18 @@ def test_from_wkt_planar():
assert spherely.distance(result, spherely.point(-30.1, 45)) < 10


def test_from_geoarrow_projection():
arr = ga.as_wkt(["POINT (1 0)", "POINT(0 1)"])

result = spherely.from_geoarrow(
arr, projection=spherely.Projection.orthographic(0, 0)
)
expected = spherely.points([90, 0], [0, 90])
# TODO use equality when we support precision / snapping
# assert spherely.equals(result, expected).all()
assert (spherely.to_wkt(result) == spherely.to_wkt(expected)).all()


def test_from_geoarrow_no_extension_type():
arr = pa.array(["POINT (1 1)", "POINT(2 2)", "POINT(3 3)"])

Expand Down

0 comments on commit a650b7a

Please sign in to comment.